rpy2-2.3.9/0000755000175000017500000000000012271276522013575 5ustar laurentlaurent00000000000000rpy2-2.3.9/MPL_LICENSE0000644000175000017500000006223311550074767015326 0ustar laurentlaurent00000000000000 MOZILLA PUBLIC LICENSE Version 1.1 --------------- 1. Definitions. 1.0.1. "Commercial Use" means distribution or otherwise making the Covered Code available to a third party. 1.1. "Contributor" means each entity that creates or contributes to the creation of Modifications. 1.2. "Contributor Version" means the combination of the Original Code, prior Modifications used by a Contributor, and the Modifications made by that particular Contributor. 1.3. "Covered Code" means the Original Code or Modifications or the combination of the Original Code and Modifications, in each case including portions thereof. 1.4. "Electronic Distribution Mechanism" means a mechanism generally accepted in the software development community for the electronic transfer of data. 1.5. "Executable" means Covered Code in any form other than Source Code. 1.6. "Initial Developer" means the individual or entity identified as the Initial Developer in the Source Code notice required by Exhibit A. 1.7. "Larger Work" means a work which combines Covered Code or portions thereof with code not governed by the terms of this License. 1.8. "License" means this document. 1.8.1. "Licensable" means having the right to grant, to the maximum extent possible, whether at the time of the initial grant or subsequently acquired, any and all of the rights conveyed herein. 1.9. "Modifications" means any addition to or deletion from the substance or structure of either the Original Code or any previous Modifications. When Covered Code is released as a series of files, a Modification is: A. Any addition to or deletion from the contents of a file containing Original Code or previous Modifications. B. Any new file that contains any part of the Original Code or previous Modifications. 1.10. "Original Code" means Source Code of computer software code which is described in the Source Code notice required by Exhibit A as Original Code, and which, at the time of its release under this License is not already Covered Code governed by this License. 1.10.1. "Patent Claims" means any patent claim(s), now owned or hereafter acquired, including without limitation, method, process, and apparatus claims, in any patent Licensable by grantor. 1.11. "Source Code" means the preferred form of the Covered Code for making modifications to it, including all modules it contains, plus any associated interface definition files, scripts used to control compilation and installation of an Executable, or source code differential comparisons against either the Original Code or another well known, available Covered Code of the Contributor's choice. The Source Code can be in a compressed or archival form, provided the appropriate decompression or de-archiving software is widely available for no charge. 1.12. "You" (or "Your") means an individual or a legal entity exercising rights under, and complying with all of the terms of, this License or a future version of this License issued under Section 6.1. For legal entities, "You" includes any entity which controls, is controlled by, or is under common control with You. For purposes of this definition, "control" means (a) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (b) ownership of more than fifty percent (50%) of the outstanding shares or beneficial ownership of such entity. 2. Source Code License. 2.1. The Initial Developer Grant. The Initial Developer hereby grants You a world-wide, royalty-free, non-exclusive license, subject to third party intellectual property claims: (a) under intellectual property rights (other than patent or trademark) Licensable by Initial Developer to use, reproduce, modify, display, perform, sublicense and distribute the Original Code (or portions thereof) with or without Modifications, and/or as part of a Larger Work; and (b) under Patents Claims infringed by the making, using or selling of Original Code, to make, have made, use, practice, sell, and offer for sale, and/or otherwise dispose of the Original Code (or portions thereof). (c) the licenses granted in this Section 2.1(a) and (b) are effective on the date Initial Developer first distributes Original Code under the terms of this License. (d) Notwithstanding Section 2.1(b) above, no patent license is granted: 1) for code that You delete from the Original Code; 2) separate from the Original Code; or 3) for infringements caused by: i) the modification of the Original Code or ii) the combination of the Original Code with other software or devices. 2.2. Contributor Grant. Subject to third party intellectual property claims, each Contributor hereby grants You a world-wide, royalty-free, non-exclusive license (a) under intellectual property rights (other than patent or trademark) Licensable by Contributor, to use, reproduce, modify, display, perform, sublicense and distribute the Modifications created by such Contributor (or portions thereof) either on an unmodified basis, with other Modifications, as Covered Code and/or as part of a Larger Work; and (b) under Patent Claims infringed by the making, using, or selling of Modifications made by that Contributor either alone and/or in combination with its Contributor Version (or portions of such combination), to make, use, sell, offer for sale, have made, and/or otherwise dispose of: 1) Modifications made by that Contributor (or portions thereof); and 2) the combination of Modifications made by that Contributor with its Contributor Version (or portions of such combination). (c) the licenses granted in Sections 2.2(a) and 2.2(b) are effective on the date Contributor first makes Commercial Use of the Covered Code. (d) Notwithstanding Section 2.2(b) above, no patent license is granted: 1) for any code that Contributor has deleted from the Contributor Version; 2) separate from the Contributor Version; 3) for infringements caused by: i) third party modifications of Contributor Version or ii) the combination of Modifications made by that Contributor with other software (except as part of the Contributor Version) or other devices; or 4) under Patent Claims infringed by Covered Code in the absence of Modifications made by that Contributor. 3. Distribution Obligations. 3.1. Application of License. The Modifications which You create or to which You contribute are governed by the terms of this License, including without limitation Section 2.2. The Source Code version of Covered Code may be distributed only under the terms of this License or a future version of this License released under Section 6.1, and You must include a copy of this License with every copy of the Source Code You distribute. You may not offer or impose any terms on any Source Code version that alters or restricts the applicable version of this License or the recipients' rights hereunder. However, You may include an additional document offering the additional rights described in Section 3.5. 3.2. Availability of Source Code. Any Modification which You create or to which You contribute must be made available in Source Code form under the terms of this License either on the same media as an Executable version or via an accepted Electronic Distribution Mechanism to anyone to whom you made an Executable version available; and if made available via Electronic Distribution Mechanism, must remain available for at least twelve (12) months after the date it initially became available, or at least six (6) months after a subsequent version of that particular Modification has been made available to such recipients. You are responsible for ensuring that the Source Code version remains available even if the Electronic Distribution Mechanism is maintained by a third party. 3.3. Description of Modifications. You must cause all Covered Code to which You contribute to contain a file documenting the changes You made to create that Covered Code and the date of any change. You must include a prominent statement that the Modification is derived, directly or indirectly, from Original Code provided by the Initial Developer and including the name of the Initial Developer in (a) the Source Code, and (b) in any notice in an Executable version or related documentation in which You describe the origin or ownership of the Covered Code. 3.4. Intellectual Property Matters (a) Third Party Claims. If Contributor has knowledge that a license under a third party's intellectual property rights is required to exercise the rights granted by such Contributor under Sections 2.1 or 2.2, Contributor must include a text file with the Source Code distribution titled "LEGAL" which describes the claim and the party making the claim in sufficient detail that a recipient will know whom to contact. If Contributor obtains such knowledge after the Modification is made available as described in Section 3.2, Contributor shall promptly modify the LEGAL file in all copies Contributor makes available thereafter and shall take other steps (such as notifying appropriate mailing lists or newsgroups) reasonably calculated to inform those who received the Covered Code that new knowledge has been obtained. (b) Contributor APIs. If Contributor's Modifications include an application programming interface and Contributor has knowledge of patent licenses which are reasonably necessary to implement that API, Contributor must also include this information in the LEGAL file. (c) Representations. Contributor represents that, except as disclosed pursuant to Section 3.4(a) above, Contributor believes that Contributor's Modifications are Contributor's original creation(s) and/or Contributor has sufficient rights to grant the rights conveyed by this License. 3.5. Required Notices. You must duplicate the notice in Exhibit A in each file of the Source Code. If it is not possible to put such notice in a particular Source Code file due to its structure, then You must include such notice in a location (such as a relevant directory) where a user would be likely to look for such a notice. If You created one or more Modification(s) You may add your name as a Contributor to the notice described in Exhibit A. You must also duplicate this License in any documentation for the Source Code where You describe recipients' rights or ownership rights relating to Covered Code. You may choose to offer, and to charge a fee for, warranty, support, indemnity or liability obligations to one or more recipients of Covered Code. However, You may do so only on Your own behalf, and not on behalf of the Initial Developer or any Contributor. You must make it absolutely clear than any such warranty, support, indemnity or liability obligation is offered by You alone, and You hereby agree to indemnify the Initial Developer and every Contributor for any liability incurred by the Initial Developer or such Contributor as a result of warranty, support, indemnity or liability terms You offer. 3.6. Distribution of Executable Versions. You may distribute Covered Code in Executable form only if the requirements of Section 3.1-3.5 have been met for that Covered Code, and if You include a notice stating that the Source Code version of the Covered Code is available under the terms of this License, including a description of how and where You have fulfilled the obligations of Section 3.2. The notice must be conspicuously included in any notice in an Executable version, related documentation or collateral in which You describe recipients' rights relating to the Covered Code. You may distribute the Executable version of Covered Code or ownership rights under a license of Your choice, which may contain terms different from this License, provided that You are in compliance with the terms of this License and that the license for the Executable version does not attempt to limit or alter the recipient's rights in the Source Code version from the rights set forth in this License. If You distribute the Executable version under a different license You must make it absolutely clear that any terms which differ from this License are offered by You alone, not by the Initial Developer or any Contributor. You hereby agree to indemnify the Initial Developer and every Contributor for any liability incurred by the Initial Developer or such Contributor as a result of any such terms You offer. 3.7. Larger Works. You may create a Larger Work by combining Covered Code with other code not governed by the terms of this License and distribute the Larger Work as a single product. In such a case, You must make sure the requirements of this License are fulfilled for the Covered Code. 4. Inability to Comply Due to Statute or Regulation. If it is impossible for You to comply with any of the terms of this License with respect to some or all of the Covered Code due to statute, judicial order, or regulation then You must: (a) comply with the terms of this License to the maximum extent possible; and (b) describe the limitations and the code they affect. Such description must be included in the LEGAL file described in Section 3.4 and must be included with all distributions of the Source Code. Except to the extent prohibited by statute or regulation, such description must be sufficiently detailed for a recipient of ordinary skill to be able to understand it. 5. Application of this License. This License applies to code to which the Initial Developer has attached the notice in Exhibit A and to related Covered Code. 6. Versions of the License. 6.1. New Versions. Netscape Communications Corporation ("Netscape") may publish revised and/or new versions of the License from time to time. Each version will be given a distinguishing version number. 6.2. Effect of New Versions. Once Covered Code has been published under a particular version of the License, You may always continue to use it under the terms of that version. You may also choose to use such Covered Code under the terms of any subsequent version of the License published by Netscape. No one other than Netscape has the right to modify the terms applicable to Covered Code created under this License. 6.3. Derivative Works. If You create or use a modified version of this License (which you may only do in order to apply it to code which is not already Covered Code governed by this License), You must (a) rename Your license so that the phrases "Mozilla", "MOZILLAPL", "MOZPL", "Netscape", "MPL", "NPL" or any confusingly similar phrase do not appear in your license (except to note that your license differs from this License) and (b) otherwise make it clear that Your version of the license contains terms which differ from the Mozilla Public License and Netscape Public License. (Filling in the name of the Initial Developer, Original Code or Contributor in the notice described in Exhibit A shall not of themselves be deemed to be modifications of this License.) 7. DISCLAIMER OF WARRANTY. COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER. 8. TERMINATION. 8.1. This License and the rights granted hereunder will terminate automatically if You fail to comply with terms herein and fail to cure such breach within 30 days of becoming aware of the breach. All sublicenses to the Covered Code which are properly granted shall survive any termination of this License. Provisions which, by their nature, must remain in effect beyond the termination of this License shall survive. 8.2. If You initiate litigation by asserting a patent infringement claim (excluding declatory judgment actions) against Initial Developer or a Contributor (the Initial Developer or Contributor against whom You file such action is referred to as "Participant") alleging that: (a) such Participant's Contributor Version directly or indirectly infringes any patent, then any and all rights granted by such Participant to You under Sections 2.1 and/or 2.2 of this License shall, upon 60 days notice from Participant terminate prospectively, unless if within 60 days after receipt of notice You either: (i) agree in writing to pay Participant a mutually agreeable reasonable royalty for Your past and future use of Modifications made by such Participant, or (ii) withdraw Your litigation claim with respect to the Contributor Version against such Participant. If within 60 days of notice, a reasonable royalty and payment arrangement are not mutually agreed upon in writing by the parties or the litigation claim is not withdrawn, the rights granted by Participant to You under Sections 2.1 and/or 2.2 automatically terminate at the expiration of the 60 day notice period specified above. (b) any software, hardware, or device, other than such Participant's Contributor Version, directly or indirectly infringes any patent, then any rights granted to You by such Participant under Sections 2.1(b) and 2.2(b) are revoked effective as of the date You first made, used, sold, distributed, or had made, Modifications made by that Participant. 8.3. If You assert a patent infringement claim against Participant alleging that such Participant's Contributor Version directly or indirectly infringes any patent where such claim is resolved (such as by license or settlement) prior to the initiation of patent infringement litigation, then the reasonable value of the licenses granted by such Participant under Sections 2.1 or 2.2 shall be taken into account in determining the amount or value of any payment or license. 8.4. In the event of termination under Sections 8.1 or 8.2 above, all end user license agreements (excluding distributors and resellers) which have been validly granted by You or any distributor hereunder prior to termination shall survive termination. 9. LIMITATION OF LIABILITY. UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE INITIAL DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF COVERED CODE, OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE TO ANY PERSON FOR ANY INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF GOODWILL, WORK STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY RESULTING FROM SUCH PARTY'S NEGLIGENCE TO THE EXTENT APPLICABLE LAW PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO THIS EXCLUSION AND LIMITATION MAY NOT APPLY TO YOU. 10. U.S. GOVERNMENT END USERS. The Covered Code is a "commercial item," as that term is defined in 48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial computer software" and "commercial computer software documentation," as such terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48 C.F.R. 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (June 1995), all U.S. Government End Users acquire Covered Code with only those rights set forth herein. 11. MISCELLANEOUS. This License represents the complete agreement concerning subject matter hereof. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. This License shall be governed by California law provisions (except to the extent applicable law, if any, provides otherwise), excluding its conflict-of-law provisions. With respect to disputes in which at least one party is a citizen of, or an entity chartered or registered to do business in the United States of America, any litigation relating to this License shall be subject to the jurisdiction of the Federal Courts of the Northern District of California, with venue lying in Santa Clara County, California, with the losing party responsible for costs, including without limitation, court costs and reasonable attorneys' fees and expenses. The application of the United Nations Convention on Contracts for the International Sale of Goods is expressly excluded. Any law or regulation which provides that the language of a contract shall be construed against the drafter shall not apply to this License. 12. RESPONSIBILITY FOR CLAIMS. As between Initial Developer and the Contributors, each party is responsible for claims and damages arising, directly or indirectly, out of its utilization of rights under this License and You agree to work with Initial Developer and Contributors to distribute such responsibility on an equitable basis. Nothing herein is intended or shall be deemed to constitute any admission of liability. 13. MULTIPLE-LICENSED CODE. Initial Developer may designate portions of the Covered Code as "Multiple-Licensed". "Multiple-Licensed" means that the Initial Developer permits you to utilize portions of the Covered Code under Your choice of the NPL or the alternative licenses, if any, specified by the Initial Developer in the file described in Exhibit A. EXHIBIT A -Mozilla Public License. ``The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.mozilla.org/MPL/ Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the specific language governing rights and limitations under the License. The Original Code is ______________________________________. The Initial Developer of the Original Code is ________________________. Portions created by ______________________ are Copyright (C) ______ _______________________. All Rights Reserved. Contributor(s): ______________________________________. Alternatively, the contents of this file may be used under the terms of the _____ license (the "[___] License"), in which case the provisions of [______] License are applicable instead of those above. If you wish to allow use of your version of this file only under the terms of the [____] License and not to allow others to use your version of this file under the MPL, indicate your decision by deleting the provisions above and replace them with the notice and other provisions required by the [___] License. If you do not delete the provisions above, a recipient may use your version of this file under either the MPL or the [___] License." [NOTE: The text of this Exhibit A may differ slightly from the text of the notices in the Source Code files of the Original Code. You should use the text of this Exhibit A rather than the text found in the Original Code Source Code for Your Modifications.] rpy2-2.3.9/LGPL_LICENSE0000644000175000017500000006350011550074767015432 0ustar laurentlaurent00000000000000 GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! rpy2-2.3.9/MANIFEST0000644000175000017500000001111212271276522014722 0ustar laurentlaurent00000000000000# file GENERATED by distutils, do NOT edit AUTHORS GPL_LICENSE LGPL_LICENSE MANIFEST MANIFEST.in MPL_LICENSE NEWS README setup.py ./rpy/__init__.py ./rpy/rpy_classic.py ./rpy/tests.py ./rpy/tests_rpy_classic.py ./rpy/interactive/__init__.py ./rpy/interactive/ipython.py ./rpy/interactive/packages.py ./rpy/interactive/process_revents.py ./rpy/interactive/tests/__init__.py ./rpy/rinterface/__init__.py ./rpy/rinterface/_rinterface.c ./rpy/rinterface/_rpy_device.c ./rpy/rinterface/tests/__init__.py ./rpy/rinterface/tests/test_Device.py ./rpy/rinterface/tests/test_EmbeddedR.py ./rpy/rinterface/tests/test_Sexp.py ./rpy/rinterface/tests/test_SexpClosure.py ./rpy/rinterface/tests/test_SexpEnvironment.py ./rpy/rinterface/tests/test_SexpExtPtr.py ./rpy/rinterface/tests/test_SexpVector.py ./rpy/rinterface/tests/test_SexpVectorNumeric.py ./rpy/rlike/__init__.py ./rpy/rlike/container.py ./rpy/rlike/functional.py ./rpy/rlike/indexing.py ./rpy/rlike/tests/__init__.py ./rpy/rlike/tests/test_container.py ./rpy/rlike/tests/test_functional.py ./rpy/rlike/tests/test_indexing.py ./rpy/robjects/__init__.py ./rpy/robjects/constants.py ./rpy/robjects/conversion.py ./rpy/robjects/environments.py ./rpy/robjects/functions.py ./rpy/robjects/help.py ./rpy/robjects/language.py ./rpy/robjects/methods.py ./rpy/robjects/numpy2ri.py ./rpy/robjects/packages.py ./rpy/robjects/pandas2ri.py ./rpy/robjects/robject.py ./rpy/robjects/vectors.py ./rpy/robjects/lib/__init__.py ./rpy/robjects/lib/ggplot2.py ./rpy/robjects/lib/grid.py ./rpy/robjects/lib/tests/__init__.py ./rpy/robjects/lib/tests/test_ggplot2.py ./rpy/robjects/tests/__init__.py ./rpy/robjects/tests/testArray.py ./rpy/robjects/tests/testDataFrame.py ./rpy/robjects/tests/testEnvironment.py ./rpy/robjects/tests/testFormula.py ./rpy/robjects/tests/testFunction.py ./rpy/robjects/tests/testHelp.py ./rpy/robjects/tests/testLanguage.py ./rpy/robjects/tests/testMethods.py ./rpy/robjects/tests/testNumpyConversions.py ./rpy/robjects/tests/testPackages.py ./rpy/robjects/tests/testPandasConversions.py ./rpy/robjects/tests/testRObject.py ./rpy/robjects/tests/testRobjects.py ./rpy/robjects/tests/testVector.py doc/Makefile doc/source/rpy2_logo.png rpy/__init__.py rpy/rpy_classic.py rpy/tests.py rpy/tests_rpy_classic.py rpy/interactive/__init__.py rpy/interactive/ipython.py rpy/interactive/packages.py rpy/interactive/process_revents.py rpy/interactive/tests/__init__.py rpy/rinterface/__init__.py rpy/rinterface/_rinterface.c rpy/rinterface/_rinterface.h rpy/rinterface/_rpy_device.c rpy/rinterface/array.c rpy/rinterface/array.h rpy/rinterface/buffer.c rpy/rinterface/buffer.h rpy/rinterface/embeddedr.c rpy/rinterface/embeddedr.h rpy/rinterface/na_values.c rpy/rinterface/na_values.h rpy/rinterface/null_value.c rpy/rinterface/null_value.h rpy/rinterface/r_utils.c rpy/rinterface/r_utils.h rpy/rinterface/rexternalptr.c rpy/rinterface/rexternalptr.h rpy/rinterface/rpy_device.h rpy/rinterface/sequence.c rpy/rinterface/sequence.h rpy/rinterface/sexp.c rpy/rinterface/sexp.h rpy/rinterface/tests/__init__.py rpy/rinterface/tests/test_Device.py rpy/rinterface/tests/test_EmbeddedR.py rpy/rinterface/tests/test_Sexp.py rpy/rinterface/tests/test_SexpClosure.py rpy/rinterface/tests/test_SexpEnvironment.py rpy/rinterface/tests/test_SexpExtPtr.py rpy/rinterface/tests/test_SexpVector.py rpy/rinterface/tests/test_SexpVectorNumeric.py rpy/rlike/__init__.py rpy/rlike/container.py rpy/rlike/functional.py rpy/rlike/indexing.py rpy/rlike/tests/__init__.py rpy/rlike/tests/test_container.py rpy/rlike/tests/test_functional.py rpy/rlike/tests/test_indexing.py rpy/robjects/__init__.py rpy/robjects/constants.py rpy/robjects/conversion.py rpy/robjects/environments.py rpy/robjects/functions.py rpy/robjects/help.py rpy/robjects/language.py rpy/robjects/methods.py rpy/robjects/numpy2ri.py rpy/robjects/packages.py rpy/robjects/pandas2ri.py rpy/robjects/robject.py rpy/robjects/vectors.py rpy/robjects/lib/__init__.py rpy/robjects/lib/ggplot2.py rpy/robjects/lib/grid.py rpy/robjects/lib/ggplot2/__init__.py rpy/robjects/lib/ggplot2/theme.py rpy/robjects/lib/tests/__init__.py rpy/robjects/lib/tests/test_ggplot2.py rpy/robjects/tests/__init__.py rpy/robjects/tests/testArray.py rpy/robjects/tests/testDataFrame.py rpy/robjects/tests/testEnvironment.py rpy/robjects/tests/testFormula.py rpy/robjects/tests/testFunction.py rpy/robjects/tests/testHelp.py rpy/robjects/tests/testLanguage.py rpy/robjects/tests/testMethods.py rpy/robjects/tests/testNumpyConversions.py rpy/robjects/tests/testPackages.py rpy/robjects/tests/testPandasConversions.py rpy/robjects/tests/testRObject.py rpy/robjects/tests/testRobjects.py rpy/robjects/tests/testVector.py rpy2-2.3.9/AUTHORS0000644000175000017500000000112011550106172014627 0ustar laurentlaurent00000000000000 Author ------ Laurent Gautier Copyright Laurent Gautier 2008-2010 People have contributed suggestions or patches; they are thanked here, rpy2 is much better because of them. rpy2 is making a limited use (if much left) of code from: RPy - http://rpy.sourceforge.net -------------------------------- (in rinteface/rinterface.c) Copyright Walter Moreira 2002-2003 Copyright Gregory Warnes 2003-2008 Parseltongue project - http://serpent.speak.googlepages.com/ ------------------------------------------------------------ (in rinterface/rinterface.c) Copyright Alexander Belopolsky - 2006 rpy2-2.3.9/MANIFEST.in0000664000175000017500000000237012040503773015332 0ustar laurentlaurent00000000000000global-include README global-exclude *patch* *diff* .hg include MANIFEST MANIFEST.in include NEWS README AUTHORS include MPL_LICENSE GPL_LICENSE LGPL_LICENSE include rpy/rinterface/_rinterface.h include rpy/rinterface/_rinterface.c include rpy/rinterface/sexp.c include rpy/rinterface/sexp.h include rpy/rinterface/array.c include rpy/rinterface/array.h include rpy/rinterface/buffer.c include rpy/rinterface/buffer.h include rpy/rinterface/sequence.c include rpy/rinterface/sequence.h include rpy/rinterface/na_values.c include rpy/rinterface/na_values.h include rpy/rinterface/null_value.c include rpy/rinterface/null_value.h include rpy/rinterface/embeddedr.c include rpy/rinterface/embeddedr.h include rpy/rinterface/r_utils.c include rpy/rinterface/r_utils.h include rpy/rinterface/_rpy_device.c include rpy/rinterface/rpy_device.h include rpy/rinterface/rexternalptr.c include rpy/rinterface/rexternalptr.h include rpy/rinterface/*.py include rpy/rinterface/tests/*.py include rpy/__init__.py include rpy/tests.py include rpy/rpy_classic.py include rpy/tests_rpy_classic.py recursive-include rpy/robjects *.py recursive-include rpy/interactive *.py recursive-include rpy/rlike *.py prune dist include doc/Makefile include doc/source/rpy2_logo.png rpy2-2.3.9/setup.py0000755000175000017500000004526012271276146015323 0ustar laurentlaurent00000000000000 import os, os.path, sys, shutil, re, itertools, warnings from collections import namedtuple from distutils.command.build_ext import build_ext as _build_ext from distutils.command.build import build as _build from distutils.core import setup from distutils.core import Extension pack_name = 'rpy2' pack_version = __import__('rpy').__version__ default_lib_directory = 'bin' if sys.platform=='win32' else 'lib' package_prefix='.' if sys.version_info >= (3,): print("Using 2to3 to translate Python2-only idioms into Python3 code. Please wait...") # Python 3 and we need to translate code package_prefix = os.path.join('build', 'python3_rpy') from distutils import filelist, dir_util, file_util, util#, log #log.set_verbosity(1) fl = filelist.FileList() tmp = open("MANIFEST.in") for line in tmp: line = line.rstrip() if line != '': fl.process_template_line(line) tmp.close() dir_util.create_tree(package_prefix, fl.files) outfiles_2to3 = [] #dist_script = os.path.join("build", "src", "distribute_setup.py") for f in fl.files: outf, copied = file_util.copy_file(f, os.path.join(package_prefix, f), update=1) if copied and outf.endswith(".py"): #and outf != dist_script: outfiles_2to3.append(outf) if copied and outf.endswith('api_tests.txt'): # XXX support this in distutils as well from lib2to3.main import main main('lib2to3.fixes', ['-wd', os.path.join(package_prefix, 'tests', 'api_tests.txt')]) util.run_2to3(outfiles_2to3) # arrange setup to use the copy sys.path.insert(0, package_prefix) src_root = package_prefix print('done.') else: from distutils.core import setup from distutils.core import Extension class build(_build): user_options = _build.user_options + \ [ #('r-autoconfig', None, # "guess all configuration paths from " +\ # "the R executable found in the PATH " +\ # "(this overrides r-home)"), ('r-home=', None, "full path for the R home to compile against " +\ "(see r-autoconfig for an automatic configuration)"), ('r-home-lib=', None, "full path for the R shared lib/ directory " +\ "(/%s otherwise)" % default_lib_directory), ('r-home-modules=', None, "full path for the R shared modules/ directory " +\ "(/modules otherwise)"), ('ignore-check-rversion', None, 'ignore checks for supported R versions')] boolean_options = _build.boolean_options + \ ['ignore_check_rversion', ] def initialize_options(self): _build.initialize_options(self) self.r_autoconfig = None self.r_home = None self.r_home_lib = None self.r_home_modules = None self.ignore_check_rversion = False class build_ext(_build_ext): """ -DRPY_STRNDUP : definition of strndup() -DRPY_VERBOSE -DRPY_DEBUG_PRESERV -DRPY_DEBUG_PROMISE : evaluation of promises -DRPY_DEBUG_OBJECTINIT : initialization of PySexpObject -DRPY_DEBUG_CONSOLE : console I/O -DRPY_DEBUG_COBJECT : SexpObject passed as a CObject -DRPY_DEBUG_GRDEV """ user_options = _build_ext.user_options + \ [ #('r-autoconfig', None, # "guess all configuration paths from " +\ # "the R executable found in the PATH " +\ # "(this overrides r-home)"), ('r-home=', None, "full path for the R home to compile against " +\ "(see r-autoconfig for an automatic configuration)"), ('r-home-lib=', None, "full path for the R shared lib/ directory" +\ "(/%s otherwise)" % default_lib_directory), ('r-home-modules=', None, "full path for the R shared modules/ directory" +\ "(/modules otherwise)"), ('ignore-check-rversion', None, 'ignore checks for supported R versions')] boolean_options = _build_ext.boolean_options + \ ['ignore-check-rversion', ] #+ \ #['r-autoconfig', ] def initialize_options(self): _build_ext.initialize_options(self) self.r_autoconfig = None self.r_home = None self.r_home_lib = None self.r_home_modules = None self.ignore_check_rversion = False def finalize_options(self): self.set_undefined_options('build', #('r_autoconfig', 'r_autoconfig'), ('r_home', 'r_home')) _build_ext.finalize_options(self) if self.r_home is None: tmp = os.popen("R RHOME") self.r_home = tmp.readlines() tmp.close() if len(self.r_home) == 0: raise SystemExit("Error: Tried to guess R's HOME but no R command in the PATH.") #Twist if 'R RHOME' spits out a warning if self.r_home[0].startswith("WARNING"): self.r_home = self.r_home[1] else: self.r_home = self.r_home[0] #self.r_home = [self.r_home, ] if self.r_home is None: raise SystemExit("Error: --r-home not specified.") else: self.r_home = self.r_home.split(os.pathsep) rversions = [] for r_home in self.r_home: r_home = r_home.strip() rversion = get_rversion(r_home) if rversion[0] == 'development' or \ cmp_version(rversion[:2], [2, 8]) == -1: if self.ignore_check_rversion: warnings.warn("R did not seem to have the minimum required version number") else: raise SystemExit("Error: R >= 2.8 required (and R told '%s')." %'.'.join(rversion)) rversions.append(rversion) config = RConfig() for about in ('--ldflags', '--cppflags'): config += get_rconfig(r_home, about) for about in ('LAPACK_LIBS', 'BLAS_LIBS'): config += get_rconfig(r_home, about, True) print(config.__repr__()) self.include_dirs.extend(config._include_dirs) self.libraries.extend(config._libraries) self.library_dirs.extend(config._library_dirs) if self.r_home_modules is None: self.library_dirs.extend([os.path.join(r_home, 'modules'), ]) else: self.library_dirs.extend([self.r_home_modules, ]) #for e in self.extensions: # self.extra_link_args.extra_link_args(config.extra_link_args) # e.extra_compile_args.extend(extra_link_args) def run(self): _build_ext.run(self) def get_rversion(r_home): r_exec = os.path.join(r_home, 'bin', 'R') # Twist if Win32 if sys.platform == "win32": if "64 bit" in sys.version: r_exec = os.path.join(r_home, 'bin', 'x64', 'R') if sys.version_info >= (3,): import subprocess p = subprocess.Popen('"'+r_exec+'" --version', shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, close_fds=sys.platform!="win32") rp = p.stdout else: rp = os.popen3('"'+r_exec+'" --version')[2] else: rp = os.popen('"'+r_exec+'" --version') rversion = rp.readline() #Twist if 'R RHOME' spits out a warning if rversion.startswith("WARNING"): rversion = rp.readline() m = re.match('^R ([^ ]+) ([^ ]+) .+$', rversion) if m is None: rp.close() # return dummy version 0.0 rversion = [0, 0] else: rversion = m.groups()[1] if m.groups()[0] == 'version': rversion = rversion.split('.') rversion[0] = int(rversion[0]) rversion[1] = int(rversion[1]) else: rversion = ['development', ''] rp.close() return rversion def cmp_version(x, y): if (x[0] < y[0]): return -1 if (x[0] > y[0]): return 1 if (x[0] == y[0]): if len(x) == 1 or len(y) == 1: return 0 return cmp_version(x[1:], y[1:]) class RConfig(object): _include_dirs = None _libraries = None _library_dirs = None _extra_link_args = None _frameworks = None _framework_dirs = None def __init__(self, include_dirs = tuple(), libraries = tuple(), library_dirs = tuple(), extra_link_args = tuple(), frameworks = tuple(), framework_dirs = tuple()): for k in ('include_dirs', 'libraries', 'library_dirs', 'extra_link_args'): v = locals()[k] if not isinstance(v, tuple): if isinstance(v, str): v = [v, ] v = tuple(set(v)) self.__dict__['_'+k] = v # frameworks are specific to OSX for k in ('framework_dirs', 'frameworks'): v = locals()[k] if not isinstance(v, tuple): if isinstance(v, str): v = [v, ] v = tuple(set(v)) self.__dict__['_'+k] = v self.__dict__['_'+'extra_link_args'] = tuple(set(v + self.__dict__['_'+'extra_link_args'])) @staticmethod def from_string(string, allow_empty = False): possible_patterns = ('^-L(?P[^ ]+)$', '^-l(?P[^ ]+)$', '^-I(?P[^ ]+)$', '^(?P-F[^ ]+?)$', '^(?P-framework [^ ]+)$', '^(?P-Wl[^ ]+)$') pp = [re.compile(x) for x in possible_patterns] # sanity check of what is returned into rconfig rconfig_m = None span = (0, 0) rc = RConfig() for substring in re.split('(? Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. rpy2-2.3.9/doc/0000755000175000017500000000000012271276522014342 5ustar laurentlaurent00000000000000rpy2-2.3.9/doc/Makefile0000644000175000017500000000611211550106172015772 0ustar laurentlaurent00000000000000# Makefile for Sphinx documentation # # You can set these variables from the command line. SPHINXOPTS = SPHINXBUILD = sphinx-build PAPER = # Internal variables. PAPEROPT_a4 = -D latex_paper_size=a4 PAPEROPT_letter = -D latex_paper_size=letter ALLSPHINXOPTS = -d build/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source .PHONY: help clean html dirhtml pickle json htmlhelp qthelp latex changes linkcheck doctest help: @echo "Please use \`make ' where is one of" @echo " html to make standalone HTML files" @echo " dirhtml to make HTML files named index.html in directories" @echo " pickle to make pickle files" @echo " json to make JSON files" @echo " htmlhelp to make HTML files and a HTML help project" @echo " qthelp to make HTML files and a qthelp project" @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" @echo " changes to make an overview of all changed/added/deprecated items" @echo " linkcheck to check all external links for integrity" @echo " doctest to run all doctests embedded in the documentation (if enabled)" clean: -rm -rf build/* demo_benchmark: @cd source/_static/demos && python benchmarks.py demo_graphics: @cd source/_static/demos && python benchmarks.py demo_all: demo_graphics demo_benchmark html: $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) build/html @echo @echo "Build finished. The HTML pages are in build/html." dirhtml: $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) build/dirhtml @echo @echo "Build finished. The HTML pages are in build/dirhtml." pickle: $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) build/pickle @echo @echo "Build finished; now you can process the pickle files." json: $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) build/json @echo @echo "Build finished; now you can process the JSON files." htmlhelp: $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) build/htmlhelp @echo @echo "Build finished; now you can run HTML Help Workshop with the" \ ".hhp project file in build/htmlhelp." qthelp: $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) build/qthelp @echo @echo "Build finished; now you can run "qcollectiongenerator" with the" \ ".qhcp project file in build/qthelp, like this:" @echo "# qcollectiongenerator build/qthelp/rpy2.qhcp" @echo "To view the help file:" @echo "# assistant -collectionFile build/qthelp/rpy2.qhc" latex: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) build/latex @echo @echo "Build finished; the LaTeX files are in build/latex." @echo "Run \`make all-pdf' or \`make all-ps' in that directory to" \ "run these through (pdf)latex." changes: $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) build/changes @echo @echo "The overview file is in build/changes." linkcheck: $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) build/linkcheck @echo @echo "Link check complete; look for any errors in the above output " \ "or in build/linkcheck/output.txt." doctest: $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) build/doctest @echo "Testing of doctests in the sources finished, look at the " \ "results in build/doctest/output.txt." rpy2-2.3.9/doc/source/0000755000175000017500000000000012271276522015642 5ustar laurentlaurent00000000000000rpy2-2.3.9/doc/source/rpy2_logo.png0000664000175000017500000004146612040503773020274 0ustar laurentlaurent00000000000000‰PNG  IHDRÀ^RdðsRGB®ÎébKGDÿÿÿ ½§“ pHYs¯¯^‘tIMEÛ 2o7 IDATxÚí½w|uþ?þœÙ^²»ÙM6¤BGŠ  ´ÔC½³Ö³á¡¢g¹ó,gã(rx'Ê¡âùñk;…£¨ ‚ˆ@$@z/»Ù¾;3¿?²ï÷ov³ ) l ¯ÇcÛf§¼çÕ+ƒ‹‹/Æßÿþw|öÙgÌîÝ»5‡C'“Ét,ËʆQÐø7µ“ ‚ A*‚@¨W™èUæÿ\¹ÿ³\ü›ÿwò^‚KBðÆ0Œ€÷æƒ~çC¼Bü™a˜Pÿåý¿Ñ÷þïYÑÚI¬ ù^âÿžõoŒhc0‚ 0­ýü½  Ã0 €a˜F™L¶S&“àyþ{¹\^6eÊû 7Ü \̇Á\ȃ/]ºo¼ñ`É’%Yuuu·rw=Çqׂñ à}\9 “É •J”H$» Ãÿ­X±"ž|òI¼þúëݓ׀|ð‹År?Çq1­ ¸ ¾–fFÑWˆñeY°,[­Õj¿š0aÂçÍ›çãQ·!€Ç{ +W®Ä’%KzÕÖÖ~i·ÛÇøEý—:=ÐÝéAF¥RYbcc¯_¾|y<÷ÜsxñÅÃ~°ëÂO<ñV¬XeË–%VUUms8#ü\éAþ8Cöƒàõz•‡ã®«¯¾ÚòóÏ?p:¸÷Þ{±gÏž°žP΃-Y²o¾ù&>øàƒ¨;wþÏåre·Åùyž§[îeD"Ã0`Y6”ÊË€×ë•Y,–•?üpìÚµkŸëÝ»wä«@Ë—/W=zt§Óéë÷@0Á:¹á¸¸8˜Íf$%%Áh4ö`Å^¯EEE¨­­Eqq1¼^o ÜR‹˜ØØØgÖ®]ûJÄÀ²eËðꫯâþû朗©i_™cĈÏqbbb0bÄ\wÝuÈÈÈèÁ†+, rrr°k×.€a˜D ‚ •Jëcbbf¼õÖ[9+žxâ cUUÕI·Û|>ŸÇÇwÜ´´´¡®8‹—>{›Í†={ö`Æ ,Ëì €Q«Õ»A˜f6›9â^ï*°á8ÈSO=hjjZåv»cCÝè°aðdÉŠüDçïAþ+Ú⥱­V‹3f`ñâÅP©T-v.—kŠÁ`.ä›hïÞ½xõÕWcJKK7r€ÔÇ!99Ï?ÿ< ¥úÄïB†ARR¼^/Nœ8À †xžgd>|øÝp¿ËàÉ'Ÿœ={v‰Çãßð¥\^"‘à‰'ž@þ+Yä÷Àù×çÖ[oEÿþýÁq\°º.8ÎQo¼ñ†9\çì²ôõ×_ÇúõëÕß~ûí b»Bø|>Ìž= Wò‡º_†aÀó<òòòPRR‚’’TWWÃétÂét‚ã8Èår ÄÅÅ!==„Ùl>ï±/'•ˆaÜÿýX´hQ‹{å86›-@uD>|x¨×ë v{*•JŒ=ú²FüP¶ŒËåBcc#, òóóñÃ?ààÁƒøõ×_ÑÐÐЩóŒ5 ×^{-fΜ‰ŒŒ ÄÄÄP]ùr²§$&&"++ ùùùH$ä7ÆÏXÕ#Àn·÷  ö*™ÍfÄÆÆ^Öž ÕjÅÞ½{)¢?~ùùùa;ßÁƒqðàA¼þú눋‹ÃèÑ£1iÒ$Ì™3‡º“/É@ˆàª«®B^^^‹`™×ëUD |ñÅ̦M›úùÓ”@­VC­V_Öˆ¿yóf¼óÎ;ÈÉÉASSÇ¿†ªª*lÚ´ _ý5^zé%LŸ>«V­‚Édº¬¤Abb"åþbà8.lÀ†3)xžïÊÀS*•Ëå—•áj·Û‘ŸŸ'Ÿ|*• sæÌÁ–-[PUUuQ?PWW‡>ú111xê©§ÐÐÐ@‘¿;Ý Ã@£Ñ@*mÉ£yžp»Ý,š‹YZÜ€T* yÝQ·?qâV¬XY³f!++ o¼ñ\.WD]ók¯½†!C†àí·ßP%º3Äá«#†|>+‚º½´»yp:„3f`âĉX¼x1vïÞÑ×^ZZŠ… âꫯFyyùeé€ðù|¦H" €¨ËÅ›ã¿'>|&LÀÈ‘#±mÛ6ÔÖÖv›{áy?ýôŒýû÷TÜ]&`Žàyžñטv{UÇápàóÏ?ÇìÙ³1|øpüðÃÝQêêê0aÂlذá²P‰D*Pä€B¡ð2 SÚ=:ðÁ`̘1¸í¶Ûð¿ÿýïrRpß}÷Ñ|­ËD%2„ë@]¶PÕjµ¯±±ÑÒ‘ž·wÞy'>ŒËxžÇk¯½†ØØX<þøã`Y¶»Ç ”#Ìf³a˜êî°˜â‡~äÈÌŸ?ÙÙÙ—5ò‹aÉ’%øè£.‚Ž7èã?Î1 SÛ€a444àø&OžŒ7âJƒ»ï¾[¶léîö@ä@wàúäAoذ‰‰‰X·n]§sr.=ôJJJº³ $4ˆXVÂ0 Ž?Ž9sæàî»ï†Óé ÿÓJ!“ÉBm"JKKñòË/ƒã¸î§‘D% ¶@`6› Ï?ÿ<Þ{ï=X­Ö°[¥RaĈ4húô郸¸8h40 ŸÏ‡Ãššœ;w'Nœ@NN,–Èóüë_ÿÂ<€aÆ]Ñ Ëb ,"ñÉ5:t7ÝtJK»î¡ŽŽÆwÞ‰Ûo¿ €\.‡T*¥­=B]Çqðù|ày'OžÄºuë°aƈJŸxä‘G°oß¾nçò÷.èR/Ñ󉑻dÉŒ9²ÓÈ…Þ½{ãÀÏ?ÿŒúúz¬^½cÆŒN§ƒR©„T*mõ¾I”R©„J¥ÂðáÃñöÛoÃétbÆ 2dH¨º×‹û÷ïÇO?ýÔí bžçÖaÙíU 1÷Ú¼y3ž{î9=z´SÇ1b¦OŸŽI“&aܸqP*•acä:,X€ `ëÖ­X¿~=>ûì³KŠLÏ=÷vìØÑÝ$€ÜßmZ¸¢ € Ïó¸ï¾ûðñÇwJŸí¶Û°lÙ2¤¥¥!**гáT ‚ aÆŒ˜4i-Z„Ûo¿%%%—™>Œ’’$''w#ü$[¶l‘pGŠè’éú1bþýï·ùår9ðôÓO£©© ÿùÏ0dÈètºOÎ…àŠâc* \sÍ5ÈËËìY³B\h°ÙlØ·o_wzüŒ lqqqXÔ nç%ÔçóaÍš56lŽ9Ò®ÿjµZÜ|óÍX¿~= ðÊ+¯@«Õ^²**¢{k4lÞ¼o¾ùæE¯ s»Ýí^¿b€‡Ã–`X·«Va•••¸çž{°mÛ¶voÏ<ó æÏŸÔÔT(Šˆ1âÅ{ì1ôîÝ¿ÿýï/juÙ¹sçàñxºMõž ¬Ïç Kr· „åææbëÖ­m"¿D"ALL žþyð<—^z }ûöȇ,¶fÏž 6\Tu¨ªªê‚/àZ1þ:”+Sš2e zè¡V÷;v,–/_Ž3gÎà…^póE²·ƒ\ç-·Ü‚þóŸí¼‹…vhî.Àq1p1‘ŠaH$¼òÊ+-<3fÌÀ®]»°uëV,Z´QQQ1‚îdäßwß}xæ™g.Êù\.Wp¶ˆE[ƒ›6mŒ3ÇŽÃ7ß|ƒÉ“'#***€`ºò‹¯÷ñÇLj#Ð!=ALÄÀÅŽ"UaèС8qâöïßìììˆRsºº&‚ Àd2á¯ýë¿¥RyI\°]\ŸÈ!\‚@!‚þýûS„i QÚBÈà‘­‚ бMçÛZÛ¯µki/aÿÏœ93f̸ kÝíû7uºu$XŒd!¦Š´ø=¸;B[¯íY,î]#nóê5ø}{ˆ–a¼óÎ;HJJº`똘˜xÙuð»¨p)UŽ`$#m0Bs×ÂàãyN§.—+ íáùlñ±ÅR@&“A¥RÑX9†\.‡B¡hÑì)”Ú&¾Ò(öºë®ÃÎ;/ÈfffvÛfW´ ˆŒôä;ŸÏ‡ºº:¸\.ê=R*•´Ù*ÉÚ4›ÍaSAy<žâ°Z­ðx<à8,ËÂl6C©T†ÌÄ Î€ \P©T2dH·CÜpÙÒp!â¥R‚uoŽãPQQ«Õ …Bøøø€þú­Œål»MMVxÜx¼xÜð<¹\¹B¹\µZ ½!:ШbYh4h4š„AÖÉëõ¢¬¬ N§r¹)))”·–‹” …B·ÛÖ5T«Õ3fÌëN — tQaâW¢Öx½^TUUA"‘ >>>`·Ë‡Ã—Ó›ÝâòJ””W¢´¢¥U(¯¬Aƒµ V7AV©#‘‚‘È©¬™à8Î Áç…àuApX f}0Dic4 )¾’{!%1©‰ñ0ôP)UP©UPk´š£Ôdæ­ÇãAII <bcc!“É T*!“É$@tt4qæÌ™°®çðáÃa6›»[¬$lC×#^ñ Vs§÷ù|¨¬¬¤jŒ\.§!1œ-8…Óù'Qp®%V•Õ ÖÍ€Wê!Ñ Ñ ‚$}<Øì(ÈdJÄ0 @¥š¨ä1AÏa p{=(qÛqÎÞ®¼\A5û)è$^˜U âÔ@’†AF| 2ûe¡ÿ€lÈÍݳ 1444ÀétÂb±@$$$P‰¥V«öõ]ºti·äÜB˜ÔŽp¡_¬æ5¢®®uuuÈÈÈ ¨ÅÜëä‰ãØúõüpè(ì¦~àz =‚A&FF"ƒ–•†4_Ÿ»ùƒ¹¡ @`0~¤÷‹> ù0 XU¤ª( &‰Zà9TrTø¼8Ây!)®…ôÐ^HËþA‰LŸ9®–•P÷ù|ðx<ÈË˃ÑhDll,µ_ ñññ¸þú뻫öryJ±(#>Çqp:(..FLL ²³³é×ܺã[|ºy*¥fhN†|öíÍÈÌs`lb ­ŸÛØ>/Ày!p^0œŒ³¬×x`=0^'xR%¹ºy“©š_UÑ$ÊfJ®‚ î _|ø†ß‚ýu¥øöÓÝüý]L;·þv’¡Ñj¡V«1xð`ÔÕÕáìÙ³°Z­Ðét0™Lðx<ðz½vE{^‚œ2;¸¸,¨§=‹h¥ðù ø<`üHÏPŽ–œò`$Íz·§¶îòSP{§a«d`V3ˆS³ˆK‹F£JÝ *•*µ *•‰.— N‡N§.§‡uu'Piq¢Æ" Ú) Æ) Æ#46ФþÐM\»ÛKN`ÓŠÿ"KÇcbŸ\sõh 4&“ &Ss7ðÏ?ÿ (**Bee%¬V+]#qÌ¡­B}ǃššœ8q'N„Åb H‰÷v·’á0‚ÅÈ/æTEEEP«ÕHHH ®JŸÏ‹UËßÀÞ³4&;Ê4}óžf·g«HpNŒLom1œy{ ­8†ñÃúãú™cÑ?3 a»R¥‚T*ëìÍùc ÍÓ ëñýþüoçßPìQC3p2”½GB™˜…2§­Õøê½mH÷½ƒ'é½3©ËR¥R!!!¡ËÏÌívCÔÖÖ¢´´iiiP(.â+A*„‹˜®">©í%œßår¡¢¢111T7æ8[¾þç}p£î„bìP°<FÈlÖv©ŒßpçßTæÐÿat/æÜ~Æ’ ¹±+³#.ZúÊ0P©ÕP©Õˆ˜„báýw£¤¤_}ñ¾ùâc¸úÏ›>¬)¾^½qÖÙ€ùËþ†ß^3 y2YøºÐ“¹ÍIIIHLLĉ'`4 ™LÖ®`à¥V•#Ibº@<7Ãó<ÑÐг٠½^È9°ï|ú Žzb¡½ù HYà}ÕB³m+‘‚s6ÁS˜ƒL¦£zÉðÛ×–!!)….ì×[¶ ¾¾¾Kk"‘H¨KS«ÕB¯×Ãd2!>>> "-99 -ÆÃrøfÓWØyà²ëñ›×aJ/Çô¿ïqâ“O>i[hÓ+Áóày,ËB&“A.—C«ÕÂd2!11:.€H³³³QUU…²²2ÄÅÅÑ€a7Q‡.¹Ìt•ЉÊÓÐЛ͆ÔÔTªò¼úâ_ðm­®ÌÙˆÒÅ6œ×Á‡Â€U¨à(8ˆèü­xþÞßcÈ Y0Åš[ Η_~Ùª^ÜÑX1TÉ+ÇqHJJ 7Ü€¡C‡ÒýXV‚Y7þ×OŸ‰Â‚Ó¨µØ`·s8¸÷{ü´rýL ë|Àq%¶ºº:TTT€aèõzh4 ôíÛ¿ûÝïð»ßýŽ^C\\¢¢¢PXXHÓ#$I¤¶S(/Û$«=>Ÿv»uuuèÛ·/$ , žzêiœˆ›éˆQr^€çšÚŽp}†Àyáøî?˜ëÂK¾Ðú¤¡¡UUU4Ž “É`4ÃêÑsR‹Å‚çŸf³Ï<ó ÒÓÓéþr…œ>}#G–ýRkfÏ™ƒ‚‚‚6Ï)“ÉðÖ[oTÌÕÕÕaéÒ¥ø÷¿ÿÆÆF”••áøñãøòË/ñè£bãÆÔªV«‘••…ÜÜ\ 0€^ÿ…h *{)¨1ØÛÃqšššPVV†>}ú@"‘ ¶¦OýõuIœ iÆÈf7$ôiÔ†°=ÁHeðÖ—CŸóoüõ·ÃðÊ+/ƒeYð<ÒÒRlÞ¼«W¯FaaaøYTˆkåyz½cÆŒ^¯Ç¢E‹ðþûïÃç󵨷OŸ>;f ÞúÛ_ð¯ïObñÒeçMZ»çž{ðÐCH!“É„õë×cõêÕ-øÖÔÔ`Ú´ixúé§áñx(¥¤¤ ¬¬ >Ÿ¯]iÞÝØKq±·‡ã8ØívTWW£oß¾J¥°Z,X´ìYäÆL„:y`³¿ƒ /© γG‘rês¼õôC¸~Æ,Í5°_ý5¾úê+Ád2µèqÁä¶_êy½^èõzŒ1;wîÄÚµk©ÑÙÐЀcÇŽzgfbíªå˜ž¡Ë2mv –Ëå¸é¦›Zá~xôÑG1}úôÿ}íµ×p÷ÝwÓÏ$øf±X(\nêÏ%“b$õz½¨®®FJJ är9AÀ³Ï>ƒò!wA™ káÍ0 ¼ueH.Ù‰÷V½†¤Ô4Í-@Ö¯_êêjÄÆÆ"%%½zõº¨!â7Ã0èׯvî܉]»vhÎûÙ»w/>úè#x½^H$L›6 ©¤MO”\.ÇĉéÚþøãøþûïj^zé¥Vÿÿé§Ÿ Ñëõhjj‚×ëÄI“UÉvñI>ÍfƒT*…Z­† ØôÕW8¢Ö!(ÈÓ±sðÐlÇ«O>B]~GÅæÍ›Ñ«W/$%%!%%III0›Í·o"œoB<ÏcĈX½z5UCƇ¼¼¼€¿ùùùm¯>J¥’JÖÅ‹còäÉÃ0Új‡îõzñá‡Ò{Z­n·›F[«½¸ÒU ¦£ˆ#<ìv;Ôj5†ÛíÆ‡Û€M¿ Ïwñ€•‚+<€[‡'!½O?ÍÃð8€ÄÄD$''#99ñññ0™LˆŠŠêpM,Ã0ðx<°X,hll¤›ÅbÝn§ºôùîD"ÙlƶmÛ}ûöE||< uäå嵉t·ß~;=f~~><½^ï¿ÿ>`íããã[=ÆñãÇQZZÚlËåô‘ZqúE¨*¼p0†nG ðA¡¼^/jjjعë;É“!Qj;ml‘ —üðg˜Ï}«ÕŠÝ»wÃl6£W¯^0›ÍˆŽŽ†V«¥©Ç=˲(..†ÍfƒZ­†R©¤mÓ- öîÝ‹ü‘æhë¡»Àl6Ó6…r¹wÞy' VVVâÔ©Sm^qi FýÃ?L¥ ÓJ€O hll¤ŸI ‚ÇãÏ磉zâïÄÒ!TFkõÒ‘@]vƒ ‚€{î¹§ÃØêóùàv»Á‹8ý›6C5ø>@èBr)+ýÄn<úûßÒ¯¶oß“É„ØØXÄÆÆB¯×C¥RQÄë,±y<<üð픜}ú`ÕªUp»Ý8wî$ ¤R) ^}õÕV‰à믿@Vñ½¥¦¦R5.”Ó@,õHG¬½ˆ1‚Ng»Œ`±~çóùÀ0 d2Ôj5Ù¿›3?½ú6šÌ·Ð½yŸ>§ >— ¼×Óªïšar5NÊû`Ûöí¸aΚtäÈ >¼…;¯3 “ÉðÏþ6l6› ÃÀd2!)) R©´Uä'HPRR‚+VP±OR->Üæ5Lœ8´ZL|–eQRR‚;ï¼UUU!ÿ?räH¼õÖ[T=$Ž ¯× ‡Ã¤¤$Œ;¶ÕI’[·n¥Ý«ÅàÅ_ÄìÙ³[쟑‘p^¯—Ú>íu~D” à×)Ùöx|‡"*B¡€F£Ayy9 0dȤ÷ÎÄÃ7NÄK_nsÕ­x/8—œÛ óôâÁyKòôaø(gÔÊí˜:m*Ôêæî GŽArr2L&]üŽÏóHNNnÁ¹ˆd#*øžƒ_"‘ ©© 555X²d Ôju¡ÀZ[0jÔ(0 C<l6ª««±ÿ~¼ûî»-_ …ÙÙÙ¸í¶ÛpË-·ÀápÐkªªªÂáÇ1qâD¨T*¸Ýn<ðÀ­À矎3f´Hq˜5kÖ®]‹gŸ}6 ¼têÔ©ô}ii)”Je§¦Ó„«a— €ã¸6§u› F2R3«Ñhƒ£G"&&:C®»*«±zójÈG܆•øoZÒns›<íˆÙøàè>œ;ó6î¹ï>(JÄÆÆ¢¾¾UUUÐjµNº#¡ÿP¿)ìÛ'ˆïóùPPPFƒx-¤Dyyy›^xþùç¡T6w˜cY^¯MMM¨®®n±æÃ† Ãĉ1räHôë×QQQ°ÙlÔ;vìÎ;—Ë…œœL™2^¯W]ut:ÍkÃöíÛQ\\ žç›{¥êõ´¶â¡‡ÂàÁƒ1~üx‚µZÐÏéìÙ³´ApGmÈpÅrºL~ȶÅùƒS"Vâƒ&“ [·nÅUW]¹\ŽÑc®ÆÁ`í¦Ï ý;@`üRi÷"Ñóô‹½U8ñÌ_ðÔâ?">!f Z­V”••u†uèw± XRR‚ºº:ÜtÓM*ÁktüøñQa·Ýv¦NŠââbÔÔÔÀf³Ñi …111HLLDVV§&~^os•ÝnÇ¡C‡ÀqM¾s8hjj¢:uêÔ1«ÕŠüü|$%%Ááp //jµ©©©07næÍ›‡>øÓ¦M£ÄÁqêêꨳ #Hío‹(D0A©T ¥R N£Ñ§Ó‰ÜÜ\ 8J¥ã'L€R&Á†¯6¢6mdÆ$0hò”xiBtqxôåàŽ©£1iü8DM0 0 T ¸P@]eeehllÄÈ‘#1tèPZž)–¶¦&0,{Þ îsçÎÅàÁƒ1nܸyMâˆspÎçóÁáp ´´%%%Ðét0 Ðh4ày‹…"¨ ?~|Hp»Ý8}ú4’““!l6~üñGÜpà ¨®®F\\íÎ=cÆ '(..¦3HúHG…pĨ@‰S=].‡F£Ñh„ÛíFii)~ýõWdgg#** #¯‡„ä|µu;¾;ròÁÓÁÊT8íJ› ]%=´×=ˆOÏÁyŸ`X/%&M¹™}ÄÄ|A€¨L©©©HIIAUUV®\‰I“&QcÑëõàÛí[±ûp>ÿÃìß¿¿ÕãÅÆÆ">>> Õ™Øâ´ ‚ô¤§é«J$†L&C||<ŒF# T*<X–¥ÃºA@ZZMyƒËåBaa!¦L™´›!l—Ë…o¿ýƒéééhjj‚V«EMM är9T*U§ÒS"Fò/x‡+ÂÈ \NGƒP•••8xð 222––s\/Ü7ÿN\—‡UkWÁ‘1Š>W7wˆ:@~[ž2µ|6v4Õbçš1(FŠ;ç-@Bbb‡<¡ÒzÏ÷ÀˆžOšPíÚµ ÇAÊ2ølóV¸2'¡Ïð›püøñ6Ã!C†ÐÂÑKJJhiQ¶Z­p¹\¨««£Æ(Q=Íf3åüƒZ­–¶xt¹\TbÑÑÑHIIA^^^‹k9wî¼^/X–…\.ǨQ£(ÁWWW#77Æ CJJ JKKáõzQYY ³Ù Äjk;l!b 3*Ø$•J¡Ñh¨Í@ãôéÓ°X,ÈÌÌ„Z­ÆÁƒñïýŸþß°ëàû°¥ŒVÆßÌ–iƒ ¨ @`X0ú^ÀØ»ñKÍ9ìyq-Òt,®¾j(lv;Ìç‹ ²,jkkát:)w{·Ä=þ[ó•@ZZþûå°$Œ„fúŸÀsÜ|óÍôšHJµF£¡í[áìBÄÛ~P‡å‘8™t/#¾lâ!’Ë娮®FNNÒÒÒ’’†apëmwàÚÉ•È9ðü„ãu>0ñYP&ôm^Îw^ÉмÐÀy!3%#zÚèwZñeÙÈ›<ÈhÇõ744`Ú´i:t(­–jjjBQÑ9ü|è¤29åÆmd¿~ýp¢²>k TdÎ@¹àsƒQ¨ÀH`˜æ…åËqæ—ÿCvou›^A’šŠÜÜ\ôÍìõë×·yÞøøx¤¤¤ä6ÅÅÅ!66†¦yµ$Av’x&ö‰m’£¥V«áp8`0Àó<²²²hc0TVVÒ±TDB|ùå—4ÃÔívC"‘ ¨¨ˆ–Q*ж\ L·„ù/<,R€NÄ("¢X¥RA«ÕR³¡¡?ýôt:}ðÍe ®›: 3~3 Uå8yâ8Μ;ŽŠ&vNF i” ’($Úh°r ÀÍ*“МoÔÞjSÁa•j@PˆžÞç'Q¢†FIi)ÒÓÒ\‘¡â%©©©øî»ï““Óæy'OžL d¡£££a0ZH±Êªãs¨t±]&®'NOO‡V« ™œ÷믿bìØ±4îS]]O>ù>ø ½·Û ‹Å‚´´4¨T*ÈåòÎædEN.P¸$€˜ˆè&¯Dh4èt:•´Z­(,,Ä™3g “É––F3 õÑFŒ7£ÇoîËïpÀét¢¶¾g‹ËPXtŨ¬k€ƒUAjè‰ÆV¡…Üãl÷u{« ðGÀ9Á;¬à,U` ˆÕ«‘ÔËŒ¬ ƒ°÷»]°Ûí¥†¡îŸë¤k ®¿þzÄjll„N§£)‚m€ó¹ƒ»9ˆ%°x*%aNC† Y “——–eÁq´Z-^}õUhµZL:•¿¢¢QQQÍFTªÕ«£®t舙œ_/æbD" !|«ÕЦ¦&Øív…ÒÞ ®Ÿ6W_}u@+1Gõx<4hRRR`µZ[m».ŒF#ÊÊÊÚìÚð›ßü†žËëõÂf³!--"kk*NGן¬µ^¯GEE’““)„‚¢¢"êÂ^½z5àþûï§ç·Ûíà8Ž6&_ogJ`#ɾ`ùâ…{5ˆm V«·Û §Ó°9ú½ÛíFqqq€d‘ÉdˆŠŠ¢öƒ^¯§yé‰{½^Úæ£±±gÏžEnn.jjj@+¦fΜ‰?þ¸Õä;žç‘žžŽuëÖµy¾Y³fQw"1(‰7¥é­÷ÄÉŠ¥¥¥HMMÇqèÛ·o«ÿ'ÃüöìÙƒ™3gbĈ4Kµªª :Ž6#·¢ì,‘Føý‚ä{(Ä®:1!#™ô¼!½uÄéM#îjV[[K9n¯^½¨×™5¨¬¬ÄìÙ³[dLº\.,X°½{÷†^¯oŽúõ!%îÌÔÔT8p Õó(•JdddÐcÔÖÖ"55µ…;1ëMÔ ¥R`ô²,‹ÌÌÌs Ž9‚ãÇÃívãÏþ3ýŸÃá€ÅbA||< ¸Û¥ÕHsƒ^4N£ A"FCƒR¤ŸéÝn7Ý<}8Úóøêϧ:t(dºð_|Ûo¿:#FŒÀîÝ»‘””à‰‰‰8wîM?ÄOj˜IJƒØ.Gu:jjj`2™Àó<’¾ýö[ìÚµ ?ü0t:8ŽƒD"Á‰'èôÂý[‹Œw;#Ø/.ZS—`®Qšûjг É&î^F¤éíÙ•D8žç©< ‘——‡áÇcÊ”)øæ›oàñx¤€ÏçÃðáÃñöÛo·yžÔÔTj8䯯¯‡D"V«íÐÌàv!‡ß¤Õja³Ù(dggã¿ÿýo‹ýwìØ„„üö·¿¥*** ‘Hèx¦Öl•Kl8 \⨳ú_°›{‚i$ñ‹ô 5›Í0›Í0™L]šÀó<úöíÛêX¥·ß~›&}ÝrË-(((ÈÜÔëõÐjµØºuk›çÑëõŸ™™‰¤¤$0 ƒÜÜÜ€áÙí|ÊP(´í"ÏóèÝ»w«ÿ¿ñÆ‘œœLkjjj`0ÂÝ’2l*&dŒˆ~×b½28JÄ9IT# a†ÇtE-Ójµ2dHÈß÷íÛ‡ÂÂBð<‰'B£ÑÀb±ÐÁu£FÂòåËÏ{žS§NÑ·`Û@£ÑàÔ©S´ÃBg›þ{àˆ ’DCA||<î½÷^ZÔ_WWžçi¦i_-”eY>R$@ÄMIh-Ð#N çÈ„Ž!NhmŸÇëõ¶:|‚ã8|þùç4fþüù:t(fÍš…ÄÄDlܸß|óÍyïkÿþýxë­·PTTD»G ¤V«Q__ߢãvWב¤¤ˆƒkr¹< }"W^y…×3 ƒ¢¢"èõzZg ž?ÜÅâ#!\‘q€ ©.Gœ Qˆó[|>òóóÏ{Üššú e2<Øêþr¹MMMP(èß¿?JJJpóÍ7Ãf³uˆû½ûî»X¿~=5NüñGÒŸ‚ Àáp´ìÊ`;±*$v±J¥RÚ—ÀwމѣGÃãñ@"‘ ??r¹F£‘öK ‡ñq^ ‹m‡› ˆ4p¹\Ôkq×]wÑj¨ó!dFF†ÁO?ý„½{÷¶ØG­VãÕW_E¿~ýÐÐЀ^½zAŒ;Ÿ}öY—8!1èÉ}‘ŽÛçk3ÒÞ¢“`B3=q¿Ñ””<øàƒÔðmjjBUUz÷îMó“Â9å@§Rð/˜ºé°(±žk4qòäI 4ýúõ &ðä æŽÇŽßÿüçÇOHHÀºuë3gÎP_8ÏóÐjµ]Æ-Fz–ea·Ûáv»ÏKP1ɸ$q£`­f‹/†Ñh¤Uh§OŸF\\¾“Ú‚pz~Â5 £Ëà÷žt[ !ÿ¨¨(Ô××ãçŸFVVEÎÆÆFZw+¶¬V+, >þøcìÚµ«E㩘˜|÷ÝwHHH€Õj…N§Cmm-Ž?ŽÁƒt›6>C©mÁïÅIƒùùùˆ‹‹k5ÜÚ# 9Xçõzi4™4#3ÁHù"9†ÍfCII €æ±L3gΤ=^KJJÀó<ŒF#Mîç(… ÂÅsÕÝ­ TMrTTŒF#ªªª°gÏäææbÇŽ¨¬¬¤)Çb}¸­&³ÙÙÙØ·oÔj5¼^/ M»(--Åÿþ÷?ôêÕ‹va ͬH¤š$ø1 µZM HrnÒHÀívÃn·£®®111ÔÓBtm1§#>™Í@:I“d7¢:EEE!-- ,ËÂf³çyÚæ]*•bË–-€Áƒãå—_¦é‡eeeHKK£9ÿâìÔpò®ˆ‘ …B`†ïnœ_¬Â) ¹_}õ>ýôÓ„ÓVŸ 9Wç½÷ÞƒJ¥¢Þ¹\­V “ÉŸÏ™L†††”——S—¥¸XE"‘ **ŠúÝív{@g=ò*•J¡R©èì3âmG…ƒnp§Ó‰‚‚Ú¦¦OŸŽ£Gvêx/¼ðžþùCT”#vɰ$I{¤²‹x£Ä«Åƒ´ƒG&‘ÿh·xL«¸G‘"Dí9wî\@6¦ÛíÆÞ½{qöìY >¤þzqt\¼ð ÈÏÏÇ;#aÆQCøôéÓ±±±nÏP’(LÒ;r¼@avo]tÉdØ·oæÍ›‡³gÏvJ¾ùæ›x衇hC©Öl q†%á¶Á^¥Pe‹ÁsvCy±ÄÅí¡¼<ÇÁår¡¢¢iiiT=[¶lYÀÜ€¤¤$Ì›7×]w222hDwݺuزe V¯^)S¦Àáp@*•âìÙ³¨­­ERRRÀÎ Éýà ]&™_·’9är96n܈… Âb±t ù·lÙ‚I“&Q„ •¨œ½JT”Ö¦Õ#q(/P°›6¸8˜x|>jkkzöìØ±£ÅÐŒÒÒRüíoÃÆ1räH ìÝ»%%%X¹r%&L˜@ƒm(--E||<ÕýÅÈ¡%~)Ø£uE÷—J¥xê©§ðÚk¯uê8‰‰‰øþûï‘Tì*Q/¹Å@'HÒVàËçó¡¡¡ß&ÑÚÖ ¤¤„º:•J%>øà <˜v½&mjHBa°×§­_‘áʺ òËd2ÔÕÕaþüùFþÑ£Gc×®]![šwÄ],®P ²´vâæ¸Ä½êóùƧ¶ãÆÃöíÛió/2tãܹsˆ‰‰¡]9H®ÿ…Ðû[³ß"‚üÃß„î€ür¹999˜:u*6nÜØ©ãÌŸ?ÿýïѯ_¿€]EØ ­#“û¯®®¦+LJ›o¾9äþýúõÛo¾‰5kÖ &&^¯—·œ9sqqqˆ§%¥dèuW§ît;7h||<†á/å¸ûö<|©TŠ 6àÁl³è¼-Xºt)þò—¿@&“Áw©ƒnjj‚Ûí†L&Ïóxî¹ç0bÄ|òÉ'ýúõÃܹsÑ¿ŠÐÄ uìØ1466">>žr~íÏùíN–Hð]wÝå‰TC—V®\‰_|±SÇR(X¶l^xá…€ä³îäò%)&“ ¹¹¹2dMë˜;w.n»í6ê-òxú(zàÂÏó˜0au½^*5(,Åš~#X¸ÐÈ/“Éàt:ñâ‹/ÒÀTt_xúé§;ëhµt @TžÓ§OcÁ‚¶'¨÷@÷€n¸iii]1‚#Ò¸`*Ïþýûqà 7t:ªÛ‘r¹·Þz+mp)!\*ïB€D"ÛíÆ;#±cÇö ÿeééé˜9sfWŸñù|aÁÝpÂÜ8a)&¹<µµµxðÁCö¢ïî ÷Þ{/ C§£ì‚ HGTÄ˲N†a¸p¸¦òŸ;w'NìRT·" –.]ÚU†Ön·§ÈˆeY‡ ¾®">Ðìûøã‘™™Ùƒü—!üíokaßu†Ž8Ž‹‰@"‘8ü*P§‘_*•Âçóá‘GÁ¼yóz0å2„ØØXÌ›7/9VŒ aÑ^Âr™LÖiˆø÷KKKqíµ×âÌ™3=˜r™Âý÷ß0@£‹À…ãšÂcIK¥^t0!NL,[¶lAVVVò_Æ`41{öìpÕ ‡­I¸Ü \k!Z»Y’Kþì³ÏbîܹíHÑÝF…‘#G†ëp<Ã0Þˆ!©TÊ׈ûË·r¹o¼ñFOJË/¦Y¶ÕD`S*•g"†$ J$9ÎV[3™L=Øq™ÃÀqýõ×wÈï/\.W‹vô‚  Ã8 CEÄ™ÒÞ–j4hР ¹Ìá­·ÞêTúrUUU¨y ŒT*m7n\yÄ€L& iTWW£¶¶¶Íÿ¶6[·.7nÆŒÓ!×'A¥_ý5d3¹\~zæÌ™îp\_XÜ  …ÂŲ,çóùFtµ‡ÇŽ£“ŃoÄãñ`ÅŠX¹re¦\ÆÐ¸H­V+Ž;0X›FttôÛẶ°åUÏŸ?ÿ°Óé*Fr2 qùòåÐétaàÜ—'ä—ÉdX¹r%vïÞÝbH‡R©t~øá‡êp³Ë*©£Õjµd¨U…X–…ÕjÅÚµkÃÚ¹._Édøá‡°ÿþàá+‚ P«Õÿã]—í×®àÇÜ{ソ”••=ÉqœÄ?Å›!DPUU»ÝNõýàbóèáüD×/,,ÄÛo¿M‡ï‰öa”J¥O­VÏÊÉÉq¼»ä4wMþÓŸþä7nœÏårMiöT¶þ>}ú4l6ÒÓÓ¡Õj{$A +áy¿þú+Ö¬YƒúúúàѪÃ0ŒJ¥zÃl6o?~¼ðÃ?D– òýžIDATK–,ÑÖÔÔìt8£C {æy¸öÚk1iÒ$¨TªVGõÀå bïN^^¶mÛ†_~ùN§3Àð%ºL&«Š½vÕªUùa½ŽpèÉ'ŸÄë¯¿Ž… Ž­««ÛÂqœ!øøbÕG£Ñ ;;LJV«íöÃöz ýÀó<\.Š‹‹±ÿ~TUUQFB-A`ÌfóÒüão†Ãy°Ûn» ü1.\8¿®®n•Ïç3øÅBi¾Ô#®L @ºÏµÒxX ª´^¯ÿpݺuóˆcÇŽ…õ:¤áŸÿ•Gsù!Ùx†aÈ{·¿-Ž €ƒeY Ã0V†aš†q3 ãó¯ø†ñú7;« VAœ^¯·A£Ñ4¬\¹ÒÎ0LÎ\HøÿB£ô-_œIEND®B`‚rpy2-2.3.9/README0000664000175000017500000000404712040503773014457 0ustar laurentlaurent00000000000000 This is the source tree or distribution for the rpy2 package. Installation ============ The distutils mechanism can be used: python setup.py install The package is known to compile on Linux, WinXp and MacOSX (provided that developper tools are installed). In case you find yourself with this source without any idea of what it takes to compile anything on your platform, do consider looking for pre-compiled binaries. Documentation ============= Documentation is available either in the source tree (to be built), or online (see the rpy home page on sourceforge). License ======= RPy2 is subject to the Mozilla Public License Version 1.1 (the "License"); you may not use RPy2 except in compliance with the License. You may obtain a copy of the License at http://www.mozilla.org/MPL/ (or see the file MPL_LICENSE) Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the specific language governing rights and limitations under the License. The Original Code is the RPy2 python package, itself subdivived into subpackages and modules. All code is Copyright of the respective author(s). See the file AUTHORS for further details regarding authorship. Alternatively, RPy2 may be used under the terms of either the GNU General Public License Version 2 or later (the "GPL", see the file GPL_LICENSE), or the GNU Lesser General Public License Version 2.1 or later (the "LGPL", see the file LGPL_LICENSE), in which case the provisions of the GPL or the LGPL are applicable instead of those above. If you wish to allow use of your version of this file only under the terms of either the GPL or the LGPL, and not to allow others to use your version of this file under the terms of the MPL, indicate your decision by deleting the provisions above and replace them with the notice and other provisions required by the GPL or the LGPL. If you do not delete the provisions above, a recipient may use your version of this file under the terms of any one of the MPL, the GPL or the LGPL. rpy2-2.3.9/rpy/0000755000175000017500000000000012271276522014407 5ustar laurentlaurent00000000000000rpy2-2.3.9/rpy/robjects/0000755000175000017500000000000012271276522016222 5ustar laurentlaurent00000000000000rpy2-2.3.9/rpy/robjects/vectors.py0000644000175000017500000011200112271276146020256 0ustar laurentlaurent00000000000000from rpy2.robjects.robject import RObjectMixin, RObject import rpy2.rinterface as rinterface #import rpy2.robjects.conversion as conversion import conversion import rpy2.rlike.container as rlc import sys, copy, os, itertools, math import time from datetime import datetime from time import struct_time, mktime, tzname from operator import attrgetter from rpy2.rinterface import Sexp, SexpVector, ListSexpVector, StrSexpVector, \ IntSexpVector, BoolSexpVector, ComplexSexpVector, FloatSexpVector, \ R_NilValue, NA_Real, NA_Integer, NA_Character, NA_Logical, NULL, MissingArg globalenv_ri = rinterface.globalenv baseenv_ri = rinterface.baseenv utils_ri = rinterface.baseenv['as.environment'](rinterface.StrSexpVector(("package:utils", ))) class ExtractDelegator(object): """ Delegate the R 'extraction' ("[") and 'replacement' ("[<-") of items in a vector or vector-like object. This can help making syntactic niceties possible.""" _extractfunction = rinterface.baseenv['['] _replacefunction = rinterface.baseenv['[<-'] def __init__(self, parent): self._parent = parent def __call__(self, *args, **kwargs): """ Subset the "R-way.", using R's "[" function. In a nutshell, R indexing differs from Python indexing on: - indexing can be done with integers or strings (that are 'names') - an index equal to TRUE will mean everything selected (because of the recycling rule) - integer indexing starts at one - negative integer indexing means exclusion of the given integers - an index is itself a vector of elements to select """ conv_args = list(None for x in xrange(len(args))) for i, x in enumerate(args): if x is MissingArg: conv_args[i] = x else: conv_args[i] = conversion.py2ro(x) kwargs = copy.copy(kwargs) for k, v in kwargs.itervalues(): kwargs[k] = conversion.py2ro(v) fun = self._extractfunction conv_args.insert(0, self._parent) res = fun(*conv_args, **kwargs) res = conversion.py2ro(res) return res def __getitem__(self, item): fun = self._extractfunction args = rlc.TaggedList(item) for i, (k, v) in enumerate(args.iteritems()): if v is MissingArg: continue args[i] = conversion.py2ro(v) args.insert(0, self._parent) res = fun.rcall(args.items(), globalenv_ri) res = conversion.py2ro(res) return res def __setitem__(self, item, value): """ Assign a given value to a given index position in the vector. The index position can either be: - an int: x[1] = y - a tuple of ints: x[1, 2, 3] = y - an iteritem-able object (such as a dict): x[{'i': 1}] = y """ fun = self._replacefunction if type(item) is tuple: args = list([None, ] * (len(item)+2)) for i, v in enumerate(item): if v is MissingArg: continue args[i+1] = conversion.py2ro(v) args[-1] = conversion.py2ro(value) args[0] = self._parent res = fun(*args) elif (type(item) is dict) or (type(item) is rlc.TaggedList): args = rlc.TaggedList.from_iteritems(item) for i, (k, v) in enumerate(args.iteritems()): args[i] = conversion.py2ro(v) args.append(conversion.py2ro(value), tag = None) args.insert(0, self._parent, tag = None) res = fun.rcall(tuple(args.iteritems()), globalenv_ri) else: args = [self._parent, conversion.py2ro(item), conversion.py2ro(value)] res = fun(*args) #FIXME: check refcount and copying self._parent.__sexp__ = res.__sexp__ class DoubleExtractDelegator(ExtractDelegator): """ Delegate the R 'extraction' ("[[") and "replacement" ("[[<-") of items in a vector or vector-like object. This can help making syntactic niceties possible.""" _extractfunction = rinterface.baseenv['[['] _replacefunction = rinterface.baseenv['[[<-'] class VectorOperationsDelegator(object): """ Delegate operations such as __getitem__, __add__, etc... to the corresponding R function. This permits a convenient coexistence between operators on Python sequence object with their R conterparts. """ def __init__(self, parent): """ The parent in expected to inherit from Vector. """ self._parent = parent def __add__(self, x): res = globalenv_ri.get("+")(self._parent, conversion.py2ri(x)) return conversion.ri2py(res) def __sub__(self, x): res = globalenv_ri.get("-")(self._parent, conversion.py2ri(x)) return conversion.ri2py(res) def __mul__(self, x): res = globalenv_ri.get("*")(self._parent, conversion.py2ri(x)) return conversion.ri2py(res) def __pow__(self, x): res = globalenv_ri.get("^")(self._parent, conversion.py2ri(x)) return conversion.ri2py(res) def __div__(self, x): res = globalenv_ri.get("/")(self._parent, conversion.py2ri(x)) return conversion.ri2py(res) def __divmod__(self, x): res = globalenv_ri.get("%%")(self._parent, conversion.py2ri(x)) return conversion.ri2py(res) def __or__(self, x): res = globalenv_ri.get("|")(self._parent, conversion.py2ri(x)) return conversion.ri2py(res) def __and__(self, x): res = globalenv_ri.get("&")(self._parent, conversion.py2ri(x)) return conversion.ri2py(res) # Comparisons def __lt__(self, x): res = globalenv_ri.get("<")(self._parent, conversion.py2ri(x)) return conversion.ri2py(res) def __le__(self, x): res = globalenv_ri.get("<=")(self._parent, conversion.py2ri(x)) return conversion.ri2py(res) def __eq__(self, x): res = globalenv_ri.get("==")(self._parent, conversion.py2ri(x)) return conversion.ri2py(res) def __ne__(self, x): res = globalenv_ri.get("!=")(self._parent, conversion.py2ri(x)) return conversion.ri2py(res) def __gt__(self, x): res = globalenv_ri.get(">")(self._parent, conversion.py2ri(x)) return conversion.ri2py(res) def __ge__(self, x): res = globalenv_ri.get(">=")(self._parent, conversion.py2ri(x)) return conversion.ri2py(res) # def __neg__(self): res = globalenv_ri.get("-")(self._parent) return res def __contains__(self, what): res = globalenv_ri.get("%in%")(self._parent, what) return res class Vector(RObjectMixin, SexpVector): """ Vector(seq) -> Vector. The parameter 'seq' can be an instance inheriting from rinterface.SexpVector, or an arbitrary Python object. In the later case, a conversion will be attempted using conversion.py2ri(). R vector-like object. Items can be accessed with: - the method "__getitem__" ("[" operator) - the delegators rx or rx2 """ _sample = rinterface.baseenv['sample'] def __init__(self, o): if not isinstance(o, SexpVector): o = conversion.py2ri(o) super(Vector, self).__init__(o) self.ro = VectorOperationsDelegator(self) self.rx = ExtractDelegator(self) self.rx2 = DoubleExtractDelegator(self) def __add__(self, x): res = baseenv_ri.get("c")(self, conversion.py2ri(x)) res = conversion.ri2py(res) return res def __getitem__(self, i): res = super(Vector, self).__getitem__(i) if isinstance(res, Sexp): res = conversion.ri2py(res) return res def __setitem__(self, i, value): value = conversion.py2ri(value) res = super(Vector, self).__setitem__(i, value) def __getslice__(self, i, j): res = super(Vector, self).__getslice__(i, j) if isinstance(res, Sexp): res = conversion.ri2py(res) return res def _names_get(self): res = baseenv_ri.get('names')(self) res = conversion.ri2py(res) return res def _names_set(self, value): res = globalenv_ri.get("names<-")(self, conversion.py2ro(value)) self.__sexp__ = res.__sexp__ names = property(_names_get, _names_set, "Names for the items in the vector.") def iteritems(self): """ iterate over names and values """ if self.names.rsame(R_NilValue): it_names = itertools.cycle((None, )) else: it_names = iter(self.names) it_self = iter(self) for v, k in zip(it_self, it_names): yield (k, v) def sample(self, n, replace = False, probabilities = None): """ Draw a sample of size n from the vector. If 'replace' is True, the sampling is done with replacement. The optional argument 'probabilities' can indicate sampling probabilities. """ assert isinstance(n, int) assert isinstance(replace, bool) if probabilities is not None: probabilities = FloatVector(probabilities) res = self._sample(self, IntVector((n,)), replace = BoolVector((replace, )), prob = probabilities) res = conversion.ri2py(res) return res def __repr_content__(self): def p_str(x, max_width = 8): max_width = int(max_width) if x is NA_Real or x is NA_Integer or x is NA_Character or x is NA_Logical: res = repr(x) elif isinstance(x, long) or isinstance(x, int): res = '%8i' %x elif isinstance(x, float): res = '%8f' %x else: if isinstance(x, str): x = x.__repr__() else: x = type(x).__name__ if len(x) < max_width: res = x else: res = "%s..." % (str(x[ : (max_width - 3)])) return res l = len(self) if l < 7: s = '[' + \ ', '.join((p_str(elt, max_width = math.floor(52 / l)) for elt in self[ : 8])) +\ ']' else: s = '[' + \ ', '.join((p_str(elt) for elt in self[ : 3])) + ', ..., ' + \ ', '.join((p_str(elt) for elt in self[-3 : ])) + \ ']' return s def __repr__(self): return super(Vector, self).__repr__() + os.linesep + \ self.__repr_content__() #name alias if Python 3 (iteritems no longer existing for dict objects) if sys.version_info[0] == 3: Vector.items = Vector.iteritems class StrVector(Vector, StrSexpVector): """ Vector of string elements StrVector(seq) -> StrVector. The parameter 'seq' can be an instance inheriting from rinterface.SexpVector, or an arbitrary Python sequence. In the later case, all elements in the sequence should be either strings, or have a str() representation. """ _factorconstructor = rinterface.baseenv['factor'] def __init__(self, obj): obj = StrSexpVector(obj) super(StrVector, self).__init__(obj) def factor(self): """ factor() -> FactorVector Construct a factor vector from a vector of strings. """ res = self._factorconstructor(self) return conversion.ri2py(res) class IntVector(Vector, IntSexpVector): """ Vector of integer elements IntVector(seq) -> IntVector. The parameter 'seq' can be an instance inheriting from rinterface.SexpVector, or an arbitrary Python sequence. In the later case, all elements in the sequence should be either integers, or have an int() representation. """ _tabulate = rinterface.baseenv['tabulate'] def __init__(self, obj): obj = IntSexpVector(obj) super(IntVector, self).__init__(obj) def tabulate(self, nbins = None): """ Like the R function tabulate, count the number of times integer values are found """ if nbins is None: nbins = max(1, max(self)) res = self._tabulate(self) return conversion.ri2py(res) class BoolVector(Vector, BoolSexpVector): """ Vector of boolean (logical) elements BoolVector(seq) -> BoolVector. The parameter 'seq' can be an instance inheriting from rinterface.SexpVector, or an arbitrary Python sequence. In the later case, all elements in the sequence should be either booleans, or have a bool() representation. """ def __init__(self, obj): obj = BoolSexpVector(obj) super(BoolVector, self).__init__(obj) class ComplexVector(Vector, ComplexSexpVector): """ Vector of complex elements ComplexVector(seq) -> ComplexVector The parameter 'seq' can be an instance inheriting from rinterface.SexpVector, or an arbitrary Python sequence. In the later case, all elements in the sequence should be either complex, or have a complex() representation. """ def __init__(self, obj): obj = ComplexSexpVector(obj) super(ComplexVector, self).__init__(obj) class FloatVector(Vector, FloatSexpVector): """ Vector of float (double) elements FloatVector(seq) -> FloatVector. The parameter 'seq' can be an instance inheriting from rinterface.SexpVector, or an arbitrary Python sequence. In the later case, all elements in the sequence should be either float, or have a float() representation. """ def __init__(self, obj): obj = FloatSexpVector(obj) super(FloatVector, self).__init__(obj) class FactorVector(IntVector): """ Vector of 'factors' FactorVector(obj, levels = rinterface.MissingArg, labels = rinterface.MissingArg, exclude = rinterface.MissingArg, ordered = rinterface.MissingArg) -> FactorVector obj: StrVector or StrSexpVector levels: StrVector or StrSexpVector labels: StrVector or StrSexpVector (of same length as levels) exclude: StrVector or StrSexpVector ordered: boolean """ _factor = baseenv_ri['factor'] _levels = baseenv_ri['levels'] _levels_set = baseenv_ri['levels<-'] _nlevels = baseenv_ri['nlevels'] _isordered = baseenv_ri['is.ordered'] def __init__(self, obj, levels = rinterface.MissingArg, labels = rinterface.MissingArg, exclude = rinterface.MissingArg, ordered = rinterface.MissingArg): if not isinstance(obj, Sexp): obj = StrSexpVector(obj) res = self._factor(obj, levels = levels, labels = labels, exclude = exclude, ordered = ordered) self.__sexp__ = res.__sexp__ self.ro = VectorOperationsDelegator(self) self.rx = ExtractDelegator(self) self.rx2 = DoubleExtractDelegator(self) def __levels_get(self): res = self._levels(self) return conversion.ri2py(res) def __levels_set(self, value): res = self._levels_set(self, conversion.py2ro(value)) self.__sexp__ = res.__sexp__ levels = property(__levels_get, __levels_set) def __nlevels_get(self): res = self._nlevels(self) return res[0] nlevels = property(__nlevels_get, None, None, "number of levels ") def __isordered_get(self): res = self._isordered(self) return res[0] isordered = property(__isordered_get, None, None, "are the levels in the factor ordered ?") def iter_labels(self): """ Iterate the over the labels, that is iterate over the items returning associated label for each item """ levels = self.levels for x in self: yield levels[x-1] class ListVector(Vector, ListSexpVector): """ R list (vector of arbitray elements) ListVector(iteritemable) -> ListVector. The parameter 'iteritemable' can be any object inheriting from rpy2.rlike.container.TaggedList, rpy2.rinterface.SexpVector of type VECSXP, or dict. """ _vector = rinterface.baseenv['vector'] def __init__(self, tlist): if isinstance(tlist, rinterface.SexpVector): if tlist.typeof != rinterface.VECSXP: raise ValueError("tlist should of typeof VECSXP") super(ListVector, self).__init__(tlist) elif isinstance(tlist, rlc.TaggedList): kv = [(k, conversion.py2ri(v)) for k,v in tlist.iteritems()] kv = tuple(kv) df = baseenv_ri.get("list").rcall(kv, globalenv_ri) super(ListVector, self).__init__(df) elif hasattr(tlist, "__iter__"): if not callable(tlist.__iter__): raise ValueError("tlist should have a /method/ __iter__ (not an attribute)") kv = [(str(k), conversion.py2ri(tlist[k])) for k in tlist] kv = tuple(kv) df = baseenv_ri.get("list").rcall(kv, globalenv_ri) super(ListVector, self).__init__(df) else: raise ValueError("tlist can be either "+ "an iter-able " + " or an instance of rpy2.rinterface.SexpVector" + " of type VECSXP, or a Python dict.") def __repr__(self): res = [] if len(self) < 7: for i, x in enumerate(self): if isinstance(x, ListVector): res.append(super(ListVector, self).__repr__()) else: try: name = self.names[i] except TypeError, te: name = '' res.append(" %s: %s%s %s" %(name, type(x), os.linesep, x.__repr__())) else: for i, x in enumerate(self[:3]): if isinstance(x, ListVector): res.append(super(ListVector, self).__repr__()) else: try: name = self.names[i] except TypeError, te: name = '' res.append(" %s: %s%s %s" %(name, type(x), os.linesep, x.__repr__())) res.append(' ...') for i, x in enumerate(self[-3:]): if isinstance(x, ListVector): res.append(super(ListVector, self).__repr__()) else: try: name = self.names[i] except TypeError, te: name = '' res.append(" %s: %s%s %s" %(name, type(x), os.linesep, x.__repr__())) res = super(ListVector, self).__repr__() + os.linesep + \ os.linesep.join(res) return res @staticmethod def from_length(length): """ Create a list of given length """ res = ListVector._vector(StrSexpVector(("list", )), length) res = conversion.ri2py(res) return res class DateVector(FloatVector): """ Vector of dates """ pass class POSIXt(object): """ POSIX time vector. This is an abstract class. """ pass class POSIXlt(POSIXt, Vector): """ Representation of dates with a 9-component structure (similar to Python's time.struct_time). POSIXlt(seq) -> POSIXlt. The constructor accepts either an R vector or a sequence (an object with the Python sequence interface) of time.struct_time objects. """ def __init__(self, seq): """ """ if isinstance(seq, Sexp): super(self, Vector)(seq) else: for elt in seq: if not isinstance(elt, struct_time): raise ValueError('All elements must inherit from time.struct_time') as_posixlt = baseenv_ri['as.POSIXlt'] origin = StrSexpVector([time.strftime("%Y-%m-%d", time.gmtime(0)),]) rvec = FloatSexpVector([mktime(x) for x in seq]) sexp = as_posixlt(rvec, origin = origin) self.__sexp__ = sexp.__sexp__ def __getitem__(self, i): # "[[" operator returns the components of a time object # (and yes, this is confusing) tmp = self.rx2(i-1) return struct_time(*tuple(tmp)) class POSIXct(POSIXt, FloatVector): """ Representation of dates as seconds since Epoch. This form is preferred to POSIXlt for inclusion in a DataFrame. POSIXlt(seq) -> POSIXlt. The constructor accepts either an R vector floats or a sequence (an object with the Python sequence interface) of time.struct_time objects. """ _as_posixct = baseenv_ri['as.POSIXct'] _ISOdatetime = baseenv_ri['ISOdatetime'] def __init__(self, seq): """ Create a POSIXct from either an R vector or a sequence of Python dates. """ if isinstance(seq, Sexp): super(FloatVector, self).__init__(seq) elif isinstance(seq[0], struct_time): sexp = POSIXct.sexp_from_struct_time(seq) self.__sexp__ = sexp.__sexp__ elif isinstance(seq[0], datetime): sexp = POSIXct.sexp_from_datetime(seq) self.__sexp__ = sexp.__sexp__ else: raise ValueError('All elements must inherit from time.struct_time or datetime.datetime.') @staticmethod def _sexp_from_seq(seq, tz_info_getter, isodatetime_columns): """ return a POSIXct vector from a sequence of time.struct_time elements. """ tz_count = 0 tz_info = None for elt in seq: tmp = tz_info_getter(elt) if tz_info is None: tz_info = tmp tz_count = 1 elif tz_info == tmp: tz_count += 1 else: # different time zones #FIXME: create a list of time zones with tz_count times # tz_info, add the current tz_info and append further. raise ValueError("Sequences of dates with different time zones not yet allowed.") if tz_info is None: tz_info = tzname[0] # We could use R's as.POSIXct instead of ISOdatetime # since as.POSIXct is used by it anyway, but the overall # interface for dates and conversion between formats # is not exactly straightforward. Someone with more # time should look into this. d = isodatetime_columns(seq) sexp = POSIXct._ISOdatetime(*d, tz = StrSexpVector((tz_info, ))) return sexp @staticmethod def sexp_from_struct_time(seq): def f(seq): return [IntVector([x.tm_year for x in seq]), IntVector([x.tm_mon for x in seq]), IntVector([x.tm_mday for x in seq]), IntVector([x.tm_hour for x in seq]), IntVector([x.tm_min for x in seq]), IntVector([x.tm_sec for x in seq])] return POSIXct._sexp_from_seq(seq, lambda elt: time.tzname[0], f) @staticmethod def sexp_from_datetime(seq): """ return a POSIXct vector from a sequence of datetime.datetime elements. """ def f(seq): return [IntVector([x.year for x in seq]), IntVector([x.month for x in seq]), IntVector([x.day for x in seq]), IntVector([x.hour for x in seq]), IntVector([x.minute for x in seq]), IntVector([x.second for x in seq])] return POSIXct._sexp_from_seq(seq, attrgetter('tzinfo'), f) class Array(Vector): """ An R array """ _dimnames_get = baseenv_ri['dimnames'] _dimnames_set = baseenv_ri['dimnames<-'] _dim_get = baseenv_ri['dim'] _dim_set = baseenv_ri['dim<-'] _isarray = baseenv_ri['is.array'] def __init__(self, obj): super(Array, self).__init__(obj) #import pdb; pdb.set_trace() if not self._isarray(self)[0]: raise(TypeError("The object must be representing an R array")) def __dim_get(self): res = self._dim_get(self) res = conversion.ri2py(res) return res def __dim_set(self, value): value = conversion.py2ro(value) res = self._dim_set(self, value) #FIXME: not properly done raise(Exception("Not yet implemented")) dim = property(__dim_get, __dim_set, "Get or set the dimension of the array.") def __dimnames_get(self): """ Return a list of name vectors (like the R function 'dimnames' does).""" res = self._dimnames_get(self) res = conversion.ri2py(res) return res def __dimnames_set(self, value): """ Set list of name vectors (like the R function 'dimnames' does).""" value = conversion.ri2py(value) res = self._dimnames_set(self, value) self.__sexp__ = res.__sexp__ names = property(__dimnames_get, __dimnames_set, None, "names associated with the dimension.") dimnames = names class Matrix(Array): """ An R matrix """ _transpose = baseenv_ri['t'] _rownames = baseenv_ri['rownames'] _colnames = baseenv_ri['colnames'] _dot = baseenv_ri['%*%'] _crossprod = baseenv_ri['crossprod'] _tcrossprod = baseenv_ri['tcrossprod'] _svd = baseenv_ri['svd'] _eigen = baseenv_ri['eigen'] def __nrow_get(self): """ Number of rows. :rtype: integer """ return self.dim[0] nrow = property(__nrow_get, None, None, "Number of rows") def __ncol_get(self): """ Number of columns. :rtype: integer """ return self.dim[1] ncol = property(__ncol_get, None, None, "Number of columns") def __rownames_get(self): """ Row names :rtype: SexpVector """ res = self._rownames(self) return conversion.ri2py(res) def __rownames_set(self, rn): if isinstance(rn, StrSexpVector): if len(rn) != self.nrow: raise ValueError('Invalid length.') if self.dimnames is NULL: dn = ListVector.from_length(2) dn[0] = rn self.do_slot_assign('dimnames', dn) else: dn = self.dimnames dn[0] = rn else: raise ValueError('The rownames attribute can only be an R string vector.') rownames = property(__rownames_get, __rownames_set, None, "Row names") def __colnames_get(self): """ Column names :rtype: SexpVector """ res = self._colnames(self) return conversion.ri2py(res) def __colnames_set(self, cn): if isinstance(cn, StrSexpVector): if len(cn) != self.ncol: raise ValueError('Invalid length.') if self.dimnames is NULL: dn = ListVector.from_length(2) dn[1] = cn self.do_slot_assign('dimnames', dn) else: dn = self.dimnames dn[1] = cn else: raise ValueError('The colnames attribute can only be an R string vector.') colnames = property(__colnames_get, __colnames_set, None, "Column names") def transpose(self): """ transpose the matrix """ res = self._transpose(self) return conversion.ri2py(res) def crossprod(self, m): """ crossproduct X'.Y""" res = self._crossprod(self, conversion.ri2py(m)) return conversion.ri2py(res) def tcrossprod(self, m): """ crossproduct X.Y'""" res = self._tcrossprod(self, m) return conversion.ri2py(res) def svd(self, nu = None, nv = None, linpack = False): """ SVD decomposition. If nu is None, it is given the default value min(tuple(self.dim)). If nv is None, it is given the default value min(tuple(self.dim)). """ if nu is None: nu = min(tuple(self.dim)) if nv is None: nv = min(tuple(self.dim)) res = self._svd(self, nu = nu, nv = nv, LINPACK = False) return conversion.ri2py(res) def dot(self, m): """ Matrix multiplication """ res = self._dot(self, m) return conversion.ri2py(res) def eigen(self): """ Eigen values """ res = self._eigen(self) return conversion.ri2py(res) class DataFrame(ListVector): """ R 'data.frame'. """ _dataframe_name = rinterface.StrSexpVector(('data.frame',)) _read_csv = utils_ri['read.csv'] _write_table = utils_ri['write.table'] _cbind = rinterface.baseenv['cbind.data.frame'] _rbind = rinterface.baseenv['rbind.data.frame'] _is_list = rinterface.baseenv['is.list'] def __init__(self, obj): """ Create a new data frame. :param obj: object inheriting from rpy2.rinterface.SexpVector, or inheriting from TaggedList or a mapping name -> value """ if isinstance(obj, rinterface.SexpVector): if obj.typeof != rinterface.VECSXP: raise ValueError("obj should of typeof VECSXP"+\ " (and we get %s)" % rinterface.str_typeint(obj.typeof)) if self._is_list(obj)[0] or \ globalenv_ri.get('inherits')(obj, self._dataframe_name)[0]: #FIXME: is it really a good idea to pass R lists # to the constructor ? super(DataFrame, self).__init__(obj) else: raise ValueError( "When passing R objects to build a DataFrame," +\ " the R object must be a list or inherit from" +\ " the R class 'data.frame'") elif isinstance(obj, rlc.TaggedList): kv = [(k, conversion.py2ri(v)) for k,v in obj.items()] kv = tuple(kv) df = baseenv_ri.get("data.frame").rcall(kv, globalenv_ri) super(DataFrame, self).__init__(df) else: try: kv = [(str(k), conversion.py2ri(obj[k])) for k in obj] except TypeError: raise ValueError("obj can be either "+ "an instance of an iter-able class" + "(such a Python dict, rpy2.rlike.container OrdDict" + " or an instance of rpy2.rinterface.SexpVector" + " of type VECSXP") df = baseenv_ri.get("data.frame").rcall(tuple(kv), globalenv_ri) super(DataFrame, self).__init__(df) def _get_nrow(self): """ Number of rows. :rtype: integer """ return baseenv_ri["nrow"](self)[0] nrow = property(_get_nrow, None, None) def _get_ncol(self): """ Number of columns. :rtype: integer """ return baseenv_ri["ncol"](self)[0] ncol = property(_get_ncol, None, None) def _get_rownames(self): res = baseenv_ri["rownames"](self) return conversion.ri2py(res) def _set_rownames(self, rownames): res = baseenv_ri["rownames<-"](self, conversion.py2ri(rownames)) self.__sexp__ = res.__sexp__ rownames = property(_get_rownames, _set_rownames, None, "Row names") def _get_colnames(self): res = baseenv_ri["colnames"](self) return conversion.ri2py(res) def _set_colnames(self, colnames): res = baseenv_ri["colnames<-"](self, conversion.py2ri(colnames)) self.__sexp__ = res.__sexp__ colnames = property(_get_colnames, _set_colnames, None) def __getitem__(self, i): # Make sure this is not a List returned # FIXME: should this be optimzed ? tmp = super(DataFrame, self).__getitem__(i) if tmp.typeof == rinterface.VECSXP: return DataFrame(tmp) else: return conversion.ri2py(tmp) def cbind(self, *args, **kwargs): """ bind objects as supplementary columns """ new_args = [self, ] + [conversion.ri2py(x) for x in args] new_kwargs = dict([(k, conversion.ri2py(v)) for k,v in kwargs.iteritems()]) res = self._cbind(*new_args, **new_kwargs) return conversion.ri2py(res) def rbind(self, *args, **kwargs): """ bind objects as supplementary rows """ new_args = [conversion.ri2py(x) for x in args] new_kwargs = dict([(k, conversion.ri2py(v)) for k,v in kwargs.iteritems()]) res = self._rbind(self, *new_args, **new_kwargs) return conversion.ri2py(res) @staticmethod def from_csvfile(path, header = True, sep = ",", quote = "\"", dec = ".", row_names = rinterface.MissingArg, col_names = rinterface.MissingArg, fill = True, comment_char = "", as_is = False): """ Create an instance from data in a .csv file. path : string with a path header : boolean (heading line with column names or not) sep : separator character quote : quote character row_names : column name, or column index for column names (warning: indexing starts at one in R) fill : boolean (fill the lines when less entries than columns) comment_char : comment character as_is : boolean (keep the columns of strings as such, or turn them into factors) """ path = conversion.py2ro(path) header = conversion.py2ro(header) sep = conversion.py2ro(sep) quote = conversion.py2ro(quote) dec = conversion.py2ro(dec) if row_names is not rinterface.MissingArg: row_names = conversion.py2ro(row_names) if col_names is not rinterface.MissingArg: col_names = conversion.py2ro(col_names) fill = conversion.py2ro(fill) comment_char = conversion.py2ro(comment_char) as_is = conversion.py2ro(as_is) res = DataFrame._read_csv(path, **{'header': header, 'sep': sep, 'quote': quote, 'dec': dec, 'row.names': row_names, 'col.names': col_names, 'fill': fill, 'comment.char': comment_char, 'as.is': as_is}) res = conversion.ri2py(res) return res def to_csvfile(self, path, quote = True, sep = ",", eol = os.linesep, na = "NA", dec = ".", row_names = True, col_names = True, qmethod = "escape", append = False): """ Save the data into a .csv file. path : string with a path quote : quote character sep : separator character eol : end-of-line character(s) na : string for missing values dec : string for decimal separator row_names : boolean (save row names, or not) col_names : boolean (save column names, or not) comment_char : method to 'escape' special characters append : boolean (append if the file in the path is already existing, or not) """ path = conversion.py2ro(path) append = conversion.py2ro(append) sep = conversion.py2ro(sep) eol = conversion.py2ro(eol) na = conversion.py2ro(na) dec = conversion.py2ro(dec) row_names = conversion.py2ro(row_names) col_names = conversion.py2ro(col_names) qmethod = conversion.py2ro(qmethod) res = self._write_table(self, **{'file': path, 'quote': quote, 'sep': sep, 'eol': eol, 'na': na, 'dec': dec, 'row.names': row_names, 'col.names': col_names, 'qmethod': qmethod, 'append': append}) return res def iter_row(self): """ iterator across rows """ for i in xrange(self.nrow): yield self.rx(i+1, rinterface.MissingArg) def iter_column(self): """ iterator across columns """ for i in xrange(self.ncol): yield self.rx(rinterface.MissingArg, i+1) # end of definition for DataFrame __all__ = ['Vector', 'StrVector', 'IntVector', 'BoolVector', 'ComplexVector', 'FloatVector', 'FactorVector', 'ListVector', 'POSIXlt', 'POSIXct', 'Array', 'Matrix', 'DataFrame'] rpy2-2.3.9/rpy/robjects/conversion.py0000644000175000017500000000105412271276146020763 0ustar laurentlaurent00000000000000""" The module contains the conversion functions to be used by the rpy2.robjects functions and methods. These functions are by default empty place-holders, raising a NotImplementedError exception. """ def ri2py(obj): """ Dummy function for ri2py """ raise NotImplementedError("Conversion function undefined") def py2ri(obj): """ Dummy function for py2ri """ raise NotImplementedError("Conversion function undefined") def py2ro(obj): """ Dummy function for py2ro """ raise NotImplementedError("Conversion function undefined") rpy2-2.3.9/rpy/robjects/constants.py0000644000175000017500000000033112271276146020607 0ustar laurentlaurent00000000000000import rpy2.rinterface as rinterface _reval = rinterface.baseenv['eval'] # NULL NULL = _reval(rinterface.parse("NULL")) # TRUE/FALSE TRUE = _reval(rinterface.parse("TRUE")) FALSE = _reval(rinterface.parse("FALSE")) rpy2-2.3.9/rpy/robjects/language.py0000644000175000017500000000125612271276146020365 0ustar laurentlaurent00000000000000""" Utilities for manipulating or evaluating the R language """ import rpy2.robjects.conversion as conversion import rpy2.rinterface as ri _reval = ri.baseenv['eval'] _parse = ri.parse def eval(x, envir = ri.globalenv): """ Evaluate R code. If the input object is an R expression it evaluates it directly, if it is a string it parses it before evaluating it. By default the evaluation is performed in R's global environment but a specific environment can be specified.""" if isinstance(x, str) or isinstance(x, unicode): p = _parse(x) else: p = x res = _reval(p, envir = envir) res = conversion.ri2py(res) return res del(ri) rpy2-2.3.9/rpy/robjects/robject.py0000644000175000017500000000625412271276146020235 0ustar laurentlaurent00000000000000import os, sys import tempfile import rpy2.rinterface rpy2.rinterface.initr() import conversion class RObjectMixin(object): """ Class to provide methods common to all RObject instances """ __rname__ = None __tempfile = rpy2.rinterface.baseenv.get("tempfile") __file = rpy2.rinterface.baseenv.get("file") __fifo = rpy2.rinterface.baseenv.get("fifo") __sink = rpy2.rinterface.baseenv.get("sink") __close = rpy2.rinterface.baseenv.get("close") __readlines = rpy2.rinterface.baseenv.get("readLines") __unlink = rpy2.rinterface.baseenv.get("unlink") __rclass = rpy2.rinterface.baseenv.get("class") __rclass_set = rpy2.rinterface.baseenv.get("class<-") __show = rpy2.rinterface.baseenv.get("show") def __str__(self): if sys.platform == 'win32': tmpf = tempfile.NamedTemporaryFile(delete=False) tfname = tmpf.name tmp = self.__file(rpy2.rinterface.StrSexpVector([tfname,]), open=rpy2.rinterface.StrSexpVector(["r+", ])) self.__sink(tmp) else: writeconsole = rpy2.rinterface.get_writeconsole() s = [] def f(x): s.append(x) rpy2.rinterface.set_writeconsole(f) self.__show(self) if sys.platform == 'win32': self.__sink() s = tmpf.readlines() tmpf.close() try: del tmpf os.unlink(tfname) except WindowsError: if os.path.exists(tfname): print 'Unable to unlink tempfile %s' % tfname s = str.join(os.linesep, s) else: rpy2.rinterface.set_writeconsole(writeconsole) s = str.join('', s) return s def r_repr(self): """ String representation for an object that can be directly evaluated as R code. """ return repr_robject(self, linesep='\n') def _rclass_get(self): try: res = self.__rclass(self) #res = conversion.ri2py(res) return res except rpy2.rinterface.RRuntimeError, rre: if self.typeof == rpy2.rinterface.SYMSXP: #unevaluated expression: has no class return (None, ) else: raise rre def _rclass_set(self, value): res = self.__rclass_set(self, value) self.__sexp__ = res.__sexp__ rclass = property(_rclass_get, _rclass_set, None, "R class for the object, stored as an R string vector.") def repr_robject(o, linesep=os.linesep): s = rpy2.rinterface.baseenv.get("deparse")(o) s = str.join(linesep, s) return s class RObject(RObjectMixin, rpy2.rinterface.Sexp): """ Base class for all R objects. """ def __setattr__(self, name, value): if name == '_sexp': if not isinstance(value, rpy2.rinterface.Sexp): raise ValueError("_attr must contain an object " +\ "that inherits from rpy2.rinterface.Sexp" +\ "(not from %s)" %type(value)) super(RObject, self).__setattr__(name, value) rpy2-2.3.9/rpy/robjects/pandas2ri.py0000644000175000017500000000475512271276146020474 0ustar laurentlaurent00000000000000import rpy2.robjects as ro import rpy2.robjects.conversion as conversion import rpy2.rinterface as rinterface from rpy2.rinterface import SexpVector, INTSXP from pandas.core.frame import DataFrame as PandasDataFrame from pandas.core.series import Series as PandasSeries from pandas.core.index import Index as PandasIndex from collections import OrderedDict from rpy2.robjects.vectors import DataFrame, Vector, ListVector, StrVector, IntVector, POSIXct # pandas is requiring numpy. We add the numpy conversion as implicit import rpy2.robjects.numpy2ri as numpy2ri numpy2ri.activate() original_conversion = conversion.py2ri ISOdatetime = rinterface.baseenv['ISOdatetime'] def pandas2ri(obj): if isinstance(obj, PandasDataFrame): od = OrderedDict() for name, values in obj.iteritems(): if values.dtype.kind == 'O': od[name] = StrVector(values) else: od[name] = ro.conversion.py2ri(values) return DataFrame(od) elif isinstance(obj, PandasIndex): if obj.dtype.kind == 'O': return StrVector(obj) else: # only other alternative to 'O' is integer, I think return original_conversion(obj) elif isinstance(obj, PandasSeries): if obj.dtype == ' not really supported by numpy "b": rinterface.LGLSXP, "i": rinterface.INTSXP, # "u" -> special-cased below "f": rinterface.REALSXP, "c": rinterface.CPLXSXP, # "O" -> special-cased below "S": rinterface.STRSXP, "U": rinterface.STRSXP, # "V" -> special-cased below } def numpy2ri(o): """ Augmented conversion function, converting numpy arrays into rpy2.rinterface-level R structures. """ # allow array-likes to also function with this module. if not isinstance(o, numpy.ndarray) and hasattr(o, '__array__'): o = o.__array__() if isinstance(o, numpy.ndarray): if not o.dtype.isnative: raise(ValueError("Cannot pass numpy arrays with non-native byte orders at the moment.")) # Most types map onto R arrays: if o.dtype.kind in _kinds: # "F" means "use column-major order" vec = SexpVector(o.ravel("F"), _kinds[o.dtype.kind]) dim = SexpVector(o.shape, INTSXP) res = ro.r.array(vec, dim=dim) # R does not support unsigned types: elif o.dtype.kind == "u": raise(ValueError("Cannot convert numpy array of unsigned values -- R does not have unsigned integers.")) # Array-of-PyObject is treated like a Python list: elif o.dtype.kind == "O": res = conversion.py2ri(list(o)) # Record arrays map onto R data frames: elif o.dtype.kind == "V": if o.dtype.names is None: raise(ValueError("Nothing can be done for this numpy array type %s at the moment." % (o.dtype,))) df_args = [] for field_name in o.dtype.names: df_args.append((field_name, conversion.py2ri(o[field_name]))) res = ro.baseenv["data.frame"].rcall(tuple(df_args), ro.globalenv) # It should be impossible to get here: else: raise(ValueError("Unknown numpy array type.")) else: res = ro.default_py2ri(o) return res def ri2numpy(o): if isinstance(o, ListVector): res = numpy.rec.fromarrays(o, names=tuple(o.names)) elif isinstance(o, Vector) and (type(o) != Vector): res = numpy.asarray(o) else: res = ro.default_ri2py(o) return res def activate(): conversion.py2ri = numpy2ri conversion.ri2numpy = ri2numpy rpy2-2.3.9/rpy/robjects/functions.py0000644000175000017500000000626312271276146020615 0ustar laurentlaurent00000000000000from collections import OrderedDict from rpy2.robjects.robject import RObjectMixin, RObject import rpy2.rinterface as rinterface #import rpy2.robjects.conversion as conversion import conversion baseenv_ri = rinterface.baseenv #needed to avoid circular imports _reval = rinterface.baseenv['eval'] NULL = _reval(rinterface.parse("NULL")) class Function(RObjectMixin, rinterface.SexpClosure): """ Python representation of an R function. """ __formals = baseenv_ri.get('formals') __local = baseenv_ri.get('local') __call = baseenv_ri.get('call') __assymbol = baseenv_ri.get('as.symbol') __newenv = baseenv_ri.get('new.env') _local_env = None def __init__(self, *args, **kwargs): super(Function, self).__init__(*args, **kwargs) self._local_env = self.__newenv(hash=rinterface.BoolSexpVector((True, ))) def __call__(self, *args, **kwargs): new_args = [conversion.py2ri(a) for a in args] new_kwargs = {} for k, v in kwargs.iteritems(): new_kwargs[k] = conversion.py2ri(v) res = super(Function, self).__call__(*new_args, **new_kwargs) res = conversion.ri2py(res) return res def formals(self): """ Return the signature of the underlying R function (as the R function 'formals()' would). """ res = self.__formals(self) res = conversion.ri2py(res) return res def rcall(self, *args): """ Wrapper around the parent method rpy2.rinterface.SexpClosure.rcall(). """ res = super(Function, self).rcall(*args) res = conversion.ri2py(res) return res class SignatureTranslatedFunction(Function): """ Python representation of an R function, where the character '.' is replaced with '_' in the R arguments names. """ _prm_translate = None def __init__(self, sexp, init_prm_translate = None): super(SignatureTranslatedFunction, self).__init__(sexp) if init_prm_translate is None: prm_translate = OrderedDict() else: assert isinstance(init_prm_translate, dict) prm_translate = init_prm_translate if not self.formals().rsame(NULL): for r_param in self.formals().names: py_param = r_param.replace('.', '_') if py_param in prm_translate: raise ValueError("Error: '%s' already in the transalation table" %r_param) #FIXME: systematically add the parameter to the translation, as it makes it faster for generating # dynamically the pydoc string from the R help. #if py_param != r_param: # prm_translate[py_param] = r_param prm_translate[py_param] = r_param self._prm_translate = prm_translate if hasattr(sexp, '__rname__'): self.__rname__ = sexp.__rname__ def __call__(self, *args, **kwargs): prm_translate = self._prm_translate for k in tuple(kwargs.keys()): r_k = prm_translate.get(k, None) if r_k is not None: v = kwargs.pop(k) kwargs[r_k] = v return super(SignatureTranslatedFunction, self).__call__(*args, **kwargs) rpy2-2.3.9/rpy/robjects/packages.py0000644000175000017500000003013412271276146020355 0ustar laurentlaurent00000000000000from types import ModuleType from warnings import warn import rpy2.rinterface as rinterface import rpy2.robjects.lib import conversion as conversion from rpy2.robjects.functions import SignatureTranslatedFunction from rpy2.robjects.constants import NULL from rpy2.robjects import Environment _require = rinterface.baseenv['require'] _as_env = rinterface.baseenv['as.environment'] _package_has_namespace = rinterface.baseenv['packageHasNamespace'] _system_file = rinterface.baseenv['system.file'] _get_namespace = rinterface.baseenv['getNamespace'] _get_namespace_version = rinterface.baseenv['getNamespaceVersion'] _get_namespace_exports = rinterface.baseenv['getNamespaceExports'] try: _find_package = rinterface.baseenv['find.package'] except LookupError: _find_package = rinterface.baseenv['.find.package'] _packages = rinterface.baseenv['.packages'] _libpaths = rinterface.baseenv['.libPaths'] _loaded_namespaces = rinterface.baseenv['loadedNamespaces'] _globalenv = rinterface.globalenv _new_env = rinterface.baseenv["new.env"] StrSexpVector = rinterface.StrSexpVector _data = rinterface.baseenv['::'](StrSexpVector(('utils', )), StrSexpVector(('data', ))) _reval = rinterface.baseenv['eval'] _options = rinterface.baseenv['options'] def no_warnings(func): def run_withoutwarnings(*args, **kwargs): warn_i = _options().do_slot('names').index('warn') oldwarn = _options()[warn_i][0] _options(warn = -1) try: res = func(*args, **kwargs) except Exception, e: # restore the old warn setting before propagating # the exception up _options(warn = oldwarn) raise e _options(warn = oldwarn) return res return run_withoutwarnings @no_warnings def _eval_quiet(expr): return _reval(expr) def reval(string, envir = _globalenv): """ Evaluate a string as R code - string: a string - envir: an environment in which the environment should take place (default: R's global environment) """ p = rinterface.parse(string) res = _reval(p, envir = envir) return res def quiet_require(name, lib_loc = None): """ Load an R package /quietly/ (suppressing messages to the console). """ if lib_loc == None: lib_loc = "NULL" else: lib_loc = "\"%s\"" % (lib_loc.replace('"', '\\"')) expr_txt = "suppressPackageStartupMessages(base::require(%s, lib.loc=%s))" \ %(name, lib_loc) expr = rinterface.parse(expr_txt) ok = _eval_quiet(expr) return ok def get_packagepath(package): """ return the path to an R package installed """ res = _find_package(rinterface.StrSexpVector((package, ))) return res[0] class PackageData(object): """ Datasets in an R package. In R datasets can be distributed with a package. Datasets can be: - serialized R objects - R code (that produces the dataset) For a given R packages, datasets are stored separately from the rest of the code and are evaluated/loaded lazily. The lazy aspect has been conserved and the dataset are only loaded or generated when called through the method 'fetch()'. """ _packagename = None _lib_loc = None _datasets = None def __init__(self, packagename, lib_loc = rinterface.NULL): self._packagename = packagename self._lib_loc def _init_setlist(self): _datasets = dict() # 2D array of information about datatsets tmp_m = _data(**{'package':StrSexpVector((self._packagename, )), 'lib.loc': self._lib_loc})[2] nrows, ncols = tmp_m.do_slot('dim') c_i = 2 for r_i in range(nrows): _datasets[tmp_m[r_i + c_i * nrows]] = None # FIXME: check if instance methods are overriden self._datasets = _datasets def names(self): """ Names of the datasets""" if self._datasets is None: self._init_setlist() return self._datasets.keys() def fetch(self, name): """ Fetch the dataset (loads it or evaluates the R associated with it. In R, datasets are loaded into the global environment by default but this function returns an environment that contains the dataset(s). """ #tmp_env = rinterface.SexpEnvironment() if self._datasets is None: self._init_setlist() if name not in self._datasets: raise ValueError('Data set "%s" cannot be found' % name) env = _new_env() _data(StrSexpVector((name, )), **{'package': StrSexpVector((self._packagename, )), 'lib.loc': self._lib_loc, 'envir': env}) return Environment(env) class Package(ModuleType): """ Models an R package (and can do so from an arbitrary environment - with the caution that locked environments should mostly be considered). """ _env = None __rname__ = None _translation = None _rpy2r = None __fill_rpy2r__ = None __update_dict__ = None _exported_names = None __version__ = None __rdata__ = None def __init__(self, env, name, translation = {}, exported_names = None, on_conflict = 'fail', version = None): """ Create a Python module-like object from an R environment, using the specified translation if defined. - on_conflict: 'fail' or 'warn' (default: 'fail') """ super(Package, self).__init__(name) self._env = env self.__rname__ = name self._translation = translation mynames = tuple(self.__dict__) self._rpy2r = {} if exported_names is None: exported_names = set(self._env.keys()) self._exported_names = exported_names self.__fill_rpy2r__(on_conflict = on_conflict) self._exported_names = self._exported_names.difference(mynames) self.__version__ = version def __update_dict__(self, on_conflict = 'fail'): """ Update the __dict__ according to what is in the R environment """ for elt in self._rpy2r: del(self.__dict__[elt]) self._rpy2r.clear() self.__fill_rpy2r__(on_conflict = on_conflict) def __fill_rpy2r__(self, on_conflict = 'fail'): """ Fill the attribute _rpy2r. - on_conflict: 'fail' or 'warn' (default: 'fail') """ assert(on_conflict in ('fail', 'warn')) name = self.__rname__ for rname in self._env: if rname in self._translation: rpyname = self._translation[rname] else: dot_i = rname.find('.') if dot_i > -1: rpyname = rname.replace('.', '_') if rpyname in self._rpy2r: msg = ('Conflict when converting R symbol'+\ ' in the package "%s"' +\ ' to a Python symbol ' +\ '(%s -> %s while there is already'+\ ' %s)') %(self.__rname__, rname, rpyname, rpyname) if on_conflict == 'fail': raise LibraryError(msg) else: warn(msg) continue else: rpyname = rname if rpyname in self.__dict__ or rpyname == '__dict__': raise LibraryError('The symbol ' + rname +\ ' in the package "' + name + '"' +\ ' is conflicting with ' +\ 'a Python object attribute') self._rpy2r[rpyname] = rname if (rpyname != rname) and (rname in self._exported_names): self._exported_names.remove(rname) self._exported_names.add(rpyname) rpyobj = conversion.ri2py(self._env[rname]) if hasattr(rpyobj, '__rname__'): rpyobj.__rname__ = rname #FIXME: shouldn't the original R name be also in the __dict__ ? self.__dict__[rpyname] = rpyobj def __repr__(self): s = super(Package, self).__repr__() return 'rpy2.robjecs.packages.Package as a ' + s class SignatureTranslatedPackage(Package): def __fill_rpy2r__(self, on_conflict = 'fail'): super(SignatureTranslatedPackage, self).__fill_rpy2r__(on_conflict = on_conflict) for name, robj in self.__dict__.iteritems(): if isinstance(robj, rinterface.Sexp) and robj.typeof == rinterface.CLOSXP: self.__dict__[name] = SignatureTranslatedFunction(self.__dict__[name]) class SignatureTranslatedAnonymousPackage(SignatureTranslatedPackage): def __init__(self, string, name): env = Environment() reval(string, env) super(SignatureTranslatedAnonymousPackage, self).__init__(env, name) class LibraryError(ImportError): """ Error occuring when importing an R library """ pass def importr(name, lib_loc = None, robject_translations = {}, signature_translation = True, suppress_messages = True, on_conflict = 'fail', data = True): """ Import an R package. Arguments: - name: name of the R package - lib_loc: specific location for the R library (default: None) - robject_translations: dict (default: {}) - signature_translation: dict (default: {}) - suppress_message: Suppress messages R usually writes on the console (defaut: True) - on_conflict: 'fail' or 'warn' (default: 'fail') - data: embed a PackageData objects under the attribute name __rdata__ (default: True) Return: - an instance of class SignatureTranslatedPackage, or of class Package """ rname = rinterface.StrSexpVector((name, )) if suppress_messages: ok = quiet_require(name, lib_loc = lib_loc) else: ok = _require(rinterface.StrSexpVector(rname), **{'lib.loc': rinterface.StrSexpVector((lib_loc, ))})[0] if not ok: raise LibraryError("The R package %s could not be imported" %name) if _package_has_namespace(rname, _system_file(package = rname)): env = _get_namespace(rname) version = _get_namespace_version(rname)[0] exported_names = set(_get_namespace_exports(rname)) else: env = _as_env(rinterface.StrSexpVector(['package:'+name, ])) exported_names = None version = None if signature_translation: pack = SignatureTranslatedPackage(env, name, translation = robject_translations, exported_names = exported_names, on_conflict = on_conflict, version = version) else: pack = Package(env, name, translation = robject_translations, exported_names = exported_names, on_conflict = on_conflict, version = version) if data: if pack.__rdata__ is not None: warn('While importing the R package "%s", the rpy2 Package object is masking a translated R symbol "__rdata__" already present' % name) pack.__rdata__ = PackageData(name, lib_loc = lib_loc) return pack def wherefrom(symbol, startenv = rinterface.globalenv): """ For a given symbol, return the environment this symbol is first found in, starting from 'startenv' """ env = startenv obj = None tryagain = True while tryagain: try: obj = env[symbol] tryagain = False except LookupError, knf: env = env.enclos() if env.rsame(rinterface.emptyenv): tryagain = False else: tryagain = True return conversion.ri2py(env) rpy2-2.3.9/rpy/robjects/help.py0000644000175000017500000003113412271276146017530 0ustar laurentlaurent00000000000000""" R help system. """ import os, itertools import sqlite3 import rpy2.rinterface as rinterface from rpy2.rinterface import StrSexpVector import packages import rpy2.rlike.container as rlc tmp = rinterface.baseenv['R.Version']() tmp_major = int(tmp[tmp.do_slot('names').index('major')][0]) tmp_minor = float(tmp[tmp.do_slot('names').index('minor')][0]) if (tmp_major > 2) or (tmp_major == 2 and tmp_minor >= 13): readRDS = rinterface.baseenv['readRDS'] else: readRDS = rinterface.baseenv['.readRDS'] del(tmp) del(tmp_major) del(tmp_minor) _eval = rinterface.baseenv['eval'] def quiet_require(name, lib_loc = None): """ Load an R package /quietly/ (suppressing messages to the console). """ if lib_loc == None: lib_loc = "NULL" expr_txt = "suppressPackageStartupMessages(base::require(%s, lib.loc=%s))" \ %(name, lib_loc) expr = rinterface.parse(expr_txt) ok = _eval(expr) return ok quiet_require('tools') _get_namespace = rinterface.baseenv['getNamespace'] _lazyload_dbfetch = rinterface.baseenv['lazyLoadDBfetch'] tools_ns = _get_namespace(StrSexpVector(('tools',))) #_Rd_get_argument_table = tools_ns['.Rd_get_argument_table'] _Rd_db = tools_ns['Rd_db'] _Rd_deparse = tools_ns['.Rd_deparse'] __rd_meta = os.path.join('Meta', 'Rd.rds') __package_meta = os.path.join('Meta', 'package.rds') def create_metaRd_db(dbcon): """ Create an database to store R help pages. dbcon: database connection (assumed to be SQLite - may or may not work with other databases) """ dbcon.execute(''' CREATE TABLE package ( name TEXT UNIQUE, title TEXT, version TEXT, description TEXT ); ''') dbcon.execute(''' CREATE TABLE rd_meta ( id INTEGER, file TEXT UNIQUE, name TEXT, type TEXT, title TEXT, encoding TEXT, package_rowid INTEGER ); ''') dbcon.execute(''' CREATE INDEX type_idx ON rd_meta (type); ''') dbcon.execute(''' CREATE TABLE rd_alias_meta ( rd_meta_rowid INTEGER, alias TEXT ); ''') dbcon.execute(''' CREATE INDEX alias_idx ON rd_alias_meta (alias); ''') dbcon.commit() def populate_metaRd_db(package_name, dbcon, package_path = None): """ Populate a database with the meta-information associated with an R package: version, description, title, and aliases (those are what the R help system is organised around). - package_name: a string - dbcon: a database connection - package_path: path the R package installation (default: None) """ if package_path is None: package_path = packages.get_packagepath(package_name) rpath = StrSexpVector((os.path.join(package_path, __package_meta),)) rds = readRDS(rpath) desc = rds[rds.do_slot('names').index('DESCRIPTION')] db_res = dbcon.execute('insert into package values (?,?,?,?)', (desc[desc.do_slot('names').index('Package')], desc[desc.do_slot('names').index('Title')], desc[desc.do_slot('names').index('Version')], desc[desc.do_slot('names').index('Description')], )) package_rowid = db_res.lastrowid rpath = StrSexpVector((os.path.join(package_path, __rd_meta),)) rds = readRDS(rpath) FILE_I = rds.do_slot("names").index('File') NAME_I = rds.do_slot("names").index('Name') TYPE_I = rds.do_slot("names").index('Type') TITLE_I = rds.do_slot("names").index('Title') ENCODING_I = rds.do_slot("names").index('Encoding') ALIAS_I = rds.do_slot("names").index('Aliases') for row_i in xrange(len(rds[0])): db_res = dbcon.execute('insert into rd_meta values (?,?,?,?,?,?,?)', (row_i, rds[FILE_I][row_i], rds[NAME_I][row_i], rds[TYPE_I][row_i], rds[TITLE_I][row_i], rds[ENCODING_I][row_i], package_rowid)) rd_rowid = db_res.lastrowid for alias in rds[ALIAS_I][row_i]: dbcon.execute('insert into rd_alias_meta values (?,?)', (rd_rowid, alias)) class Page(object): """ An R documentation page. The original R structure is a nested sequence of components, corresponding to the latex-like .Rd file An help page is divided into sections, the names for the sections are the keys for the dict attribute 'sections', and a given section can be extracted with the square-bracket operator. In R, the S3 class 'Rd' is the closest entity to this class. """ def __init__(self, struct_rdb, _type = ''): sections = rlc.OrdDict() for elt in struct_rdb: rd_tag = elt.do_slot("Rd_tag")[0][1:] if rd_tag == 'section': rd_section = rd_tag[0] lst = sections.get(rd_tag) if lst is None: lst = [] sections[rd_tag] = lst for sub_elt in elt: lst.append(sub_elt) self._sections = sections self._type = _type def _section_get(self): return self._sections sections = property(_section_get, None, "Sections in the in help page, as a dict.") def __getitem__(self, item): """ Get a section """ return self.sections[item] def arguments(self): """ Get the arguments and their description as a list of 2-tuples. """ section = self._sections['arguments'] res = list() for item in section: if item.do_slot("Rd_tag")[0] == '\\item': if len(item) != 2: continue arg_name = _Rd_deparse(item[0])[0] arg_desc = _Rd_deparse(item[1])[0] for x in arg_name.split(','): x = x.lstrip() if x.endswith('\\dots'): x = '...' res.append((x, arg_desc)) else: continue return res def description(self): """ Get the description of the entry """ section = self._sections.get('description', None) if section is None: return '' else: res = ''.join(_Rd_deparse(x)[0] for x in section) return res def title(self): """ Get the title """ section = self._sections['title'] res = ''.join(_Rd_deparse(x)[0] for x in section) return res def value(self): """ Get the value returned """ section = self._sections.get('value', None) if section is None: return '' else: res = ''.join(_Rd_deparse(x)[0] for x in section) return res def seealso(self): """ Get the other documentation entries recommended """ section = self._sections.get('seealso', None) if section is None: return '' else: res = ''.join(_Rd_deparse(x)[0] for x in section) return res def usage(self): """ Get the usage for the object """ section = self._sections.get('usage', None) if section is None: res = '' else: res = (_Rd_deparse(x)[0] for x in section) res = ''.join(res) return res def iteritems(self): """ iterator through the sections names and content in the documentation Page. """ return self.sections.iteritems def to_docstring(self, section_names = None): """ section_names: list of section names to consider. If None all sections are used. Returns a string that can be used as a Python docstring. """ s = [] if section_names is None: section_names = self.sections.keys() def walk(tree): if not isinstance(tree, str): for elt in tree: walk(elt) else: s.append(tree) s.append(' ') for name in section_names: s.append(name) s.append(os.linesep) s.append('-' * len(name)) s.append(os.linesep) s.append(os.linesep) walk(self.sections[name]) s.append(os.linesep) s.append(os.linesep) return ''.join(s) class Package(object): """ The R documentation page (aka help) for a package. """ __package_path = None __package_name = None __aliases_info = 'aliases.rds' __hsearch_meta = os.path.join('Meta', 'hsearch.rds') __paths_info = 'paths.rds' __anindex_info = 'AnIndex' def __package_name_get(self): return self.__package_name name = property(__package_name_get, None, None, 'Name of the package as known by R') def __init__(self, package_name, package_path = None): self.__package_name = package_name if package_path is None: package_path = packages.get_packagepath(package_name) self.__package_path = package_path rd_meta_dbcon = sqlite3.connect(':memory:') create_metaRd_db(rd_meta_dbcon) populate_metaRd_db(package_name, rd_meta_dbcon, package_path = package_path) self._dbcon = rd_meta_dbcon path = os.path.join(package_path, 'help', package_name + '.rdx') self._rdx = readRDS(StrSexpVector((path, ))) def fetch(self, alias): """ Fetch the documentation page associated with a given alias. For S4 classes, the class name is *often* suffixed with '-class'. For example, the alias to the documentation for the class AnnotatedDataFrame in the package Biobase is 'AnnotatedDataFrame-class'. """ c = self._dbcon.execute('SELECT rd_meta_rowid, alias FROM rd_alias_meta WHERE alias=?', (alias, )) res_alias = c.fetchall() if len(res_alias) == 0: raise HelpNotFoundError("No help could be fetched", topic = alias, package = self.__package_name) c = self._dbcon.execute('SELECT file, name, type FROM rd_meta WHERE rowid=?', (res_alias[0][0], )) # since the selection is on a verified rowid we are sure to exactly get one row res = c.fetchall() rkey = StrSexpVector((res[0][0][:-3], )) _type = res[0][2] rpath = StrSexpVector((os.path.join(self.package_path, 'help', self.__package_name + '.rdb'),)) rdx_variables = self._rdx[self._rdx.do_slot('names').index('variables')] _eval = rinterface.baseenv['eval'] devnull_func = rinterface.parse('function(x) {}') devnull_func = _eval(devnull_func) res = _lazyload_dbfetch(rdx_variables[rdx_variables.do_slot('names').index(rkey[0])], rpath, self._rdx[self._rdx.do_slot('names').index("compressed")], devnull_func) p_res = Page(res, _type = _type) return p_res package_path = property(lambda self: str(self.__package_path), None, None, "Path to the installed R package") def __repr__(self): r = 'R package %s %s' %(self.__package_name, super(Package, self).__repr__()) return r class HelpNotFoundError(KeyError): """ Exception raised when an help topic cannot be found. """ def __init__(self, msg, topic=None, package=None): super(HelpNotFoundError, self).__init__(msg) self.topic = topic self.package = package def pages(topic): """ Get help pages corresponding to a given topic. """ res = list() for path in packages._libpaths(): for name in packages._packages(**{'all.available': True, 'lib.loc': StrSexpVector((path,))}): #FIXME: what if the same package is installed # at different locations ? pack = Package(name) try: page = pack.fetch(topic) res.append(page) except HelpNotFoundError, hnfe: pass return tuple(res) def docstring(package, alias): if not isinstance(package, Package): package = Package(package) page = package.fetch(alias) usage = page.section_docstring('usage') arguments = page.section_docstring('arguments') rpy2-2.3.9/rpy/robjects/lib/0000755000175000017500000000000012271276522016770 5ustar laurentlaurent00000000000000rpy2-2.3.9/rpy/robjects/lib/tests/0000755000175000017500000000000012271276522020132 5ustar laurentlaurent00000000000000rpy2-2.3.9/rpy/robjects/lib/tests/__init__.py0000644000175000017500000000104212271276146022242 0ustar laurentlaurent00000000000000import unittest from rpy2.rinterface import RRuntimeError try: import test_ggplot2 except RRuntimeError: test_ggplot2 = None def suite(): if test_ggplot2: suite_ggplot2 = test_ggplot2.suite() alltests = unittest.TestSuite([suite_ggplot2, ]) else: alltests = unittest.TestSuite([]) return alltests #pass def main(): r = unittest.TestResult() suite().run(r) return r if __name__ == '__main__': tr = unittest.TextTestRunner(verbosity = 2) suite = suite() tr.run(suite) rpy2-2.3.9/rpy/robjects/lib/tests/test_ggplot2.py0000644000175000017500000000143312271276146023124 0ustar laurentlaurent00000000000000import unittest from rpy2.robjects.lib import ggplot2 from rpy2.robjects.packages import importr datasets = importr('datasets') mtcars = datasets.__rdata__.fetch('mtcars')['mtcars'] class GGPlot2TestCase(unittest.TestCase): def testSetup(self): pass def tearDown(self): pass def testGGPlot(self): gp = ggplot2.ggplot(mtcars) self.assertTrue(isinstance(gp, ggplot2.GGPlot)) def testAdd(self): gp = ggplot2.ggplot(mtcars) pp = gp + \ ggplot2.aes_string(x='wt', y='mpg') + \ ggplot2.geom_point() self.assertTrue(isinstance(pp, ggplot2.GGPlot)) def suite(): suite = unittest.TestLoader().loadTestsFromTestCase(GGPlot2TestCase) return suite if __name__ == '__main__': unittest.main() rpy2-2.3.9/rpy/robjects/lib/grid.py0000644000175000017500000001507712271276146020303 0ustar laurentlaurent00000000000000""" Mapping of the R library "grid" for graphics. The R library provides a low-level coordinate system and graphic primitives to built visualizations. """ import rpy2.robjects.methods import rpy2.robjects as robjects import rpy2.robjects.conversion as conversion from rpy2.rlike.container import OrdDict from rpy2.robjects.packages import importr NULL = robjects.NULL #getmethod = robjects.baseenv.get("getMethod") grid = importr('grid') grid_env = robjects.baseenv['as.environment']('package:grid') layout = grid.grid_layout newpage = grid.grid_newpage grill = grid.grid_grill edit = grid.grid_edit get = grid.grid_get remove = grid.grid_remove add = grid.grid_add xaxis = grid.grid_xaxis yaxis = grid.grid_yaxis class Unit(robjects.RObject): """ Vector of unit values (as in R's grid package) """ _unit = grid_env['unit'] def __init__(self, *args, **kwargs): od = OrdDict() for item in args: od[None] = conversion.py2ro(item) for k, v in kwargs.iteritems(): od[k] = conversion.py2ro(v) res = self._constructor.rcall(tuple(od.items()), robjects.globalenv) self.__sexp__ = res.__sexp__ @classmethod def unit(cls, *args, **kwargs): """ Constructor (uses the R function grid::unit())""" res = cls._unit(*args, **kwargs) return res unit = Unit.unit class Gpar(robjects.RObject): """ Graphical parameters """ _gpar = grid_env['gpar'] _get_gpar = grid_env['get.gpar'] def __init__(self, *args, **kwargs): od = OrdDict() for item in args: od[None] = conversion.py2ro(item) for k, v in kwargs.iteritems(): od[k] = conversion.py2ro(v) res = self._constructor.rcall(tuple(od.items()), robjects.globalenv) self.__sexp__ = res.__sexp__ @classmethod def gpar(cls, *args, **kwargs): """ Constructor (uses the R function grid::gpar())""" res = cls._gpar(*args, **kwargs) return res def get(self, names = None): return self._get_gpar(names) gpar = Gpar.gpar class Grob(robjects.RObject): """ Graphical object """ _grob = grid_env['grob'] _draw = grid_env['grid.draw'] def __init__(self, *args, **kwargs): od = OrdDict() for item in args: od[None] = conversion.py2ro(item) for k, v in kwargs.iteritems(): od[k] = conversion.py2ro(v) res = self._constructor.rcall(tuple(od.items()), robjects.globalenv) self.__sexp__ = res.__sexp__ @classmethod def grob(cls, **kwargs): """ Constructor (uses the R function grid::grob())""" res = cls._grob(**kwargs) return res def draw(self, recording = True): """ Draw a graphical object (calling the R function grid::grid.raw())""" self._draw(self, recording = recording) grob = Grob.grob class Rect(Grob): _constructor = grid_env['rectGrob'] rect = Rect class Lines(Grob): _constructor = grid_env['linesGrob'] lines = Lines class Circle(Grob): _constructor = grid_env['circleGrob'] circle = Circle class Points(Grob): _constructor = grid_env['pointsGrob'] points = Points class Text(Grob): _constructor = grid_env['textGrob'] text = Text class GTree(Grob): """ gTree """ _gtree = grid_env['gTree'] _grobtree = grid_env['grobTree'] @classmethod def gtree(cls, **kwargs): """ Constructor (uses the R function grid::gTree())""" res = cls._gtree(**kwargs) return res @classmethod def grobtree(cls, **kwargs): """ Constructor (uses the R function grid::grobTree())""" res = cls._grobtree(**kwargs) return res class Axis(GTree): pass class XAxis(Axis): _xaxis = xaxis _xaxisgrob = grid.xaxisGrob @classmethod def xaxis(cls, **kwargs): """ Constructor (uses the R function grid::xaxis())""" res = cls._xaxis(**kwargs) return res @classmethod def xaxisgrob(cls, **kwargs): """ Constructor (uses the R function grid::xaxisgrob())""" res = cls._xaxisgrob(**kwargs) return res class YAxis(Axis): _yaxis = yaxis _yaxisgrob = grid.yaxisGrob @classmethod def yaxis(cls, **kwargs): """ Constructor (uses the R function grid::yaxis())""" res = cls._yaxis(**kwargs) return res @classmethod def yaxisgrob(cls, **kwargs): """ Constructor (uses the R function grid::yaxisgrob())""" res = cls._yaxisgrob(**kwargs) return res class Viewport(robjects.RObject): """ Drawing context. Viewports can be thought of as nodes in a scene graph. """ _pushviewport = grid_env['pushViewport'] _popviewport = grid_env['popViewport'] _current = grid_env['current.viewport'] _plotviewport = grid_env['plotViewport'] _downviewport = grid_env['downViewport'] _seek = grid_env['seekViewport'] _upviewport = grid_env['upViewport'] _viewport = grid_env['viewport'] def push(self, recording = True): self._pushviewport(self, recording = recording) @classmethod def pop(cls, n): """ Pop n viewports from the stack. """ cls._popviewport(n) @classmethod def current(cls): """ Return the current viewport in the stack. """ cls._current() @classmethod def default(cls, **kwargs): cls._plotviewport(**kwargs) @classmethod def down(cls, name, strict = False, recording = True): """ Return the number of Viewports it went down """ cls._downviewport(name, strict = strict, recording = recording) @classmethod def seek(cls, name, recording = True): """ Seek and return a Viewport given its name """ cls._seek(name, recording = recording) @classmethod def up(cls, n, recording = True): """ Go up n viewports """ cls._downviewport(n, recording = recording) @classmethod def viewport(cls, **kwargs): """ Constructor: create a Viewport """ res = cls._viewport(**kwargs) return res viewport = Viewport.viewport _grid_dict = { 'grob': Grob, 'gTree': GTree, 'xaxis': XAxis, 'yaxis': YAxis, 'viewport': Viewport } original_conversion = conversion.ri2py def grid_conversion(robj): pyobj = original_conversion(robj) if not isinstance(pyobj, robjects.RS4): rcls = pyobj.rclass if rcls is NULL: rcls = (None, ) try: cls = _grid_dict[rcls[0]] pyobj = cls(pyobj) except KeyError, ke: pass return pyobj conversion.ri2py = grid_conversion rpy2-2.3.9/rpy/robjects/lib/__init__.py0000644000175000017500000000000012271276146021071 0ustar laurentlaurent00000000000000rpy2-2.3.9/rpy/robjects/lib/ggplot2.py0000644000175000017500000005565612271276146020743 0ustar laurentlaurent00000000000000""" Wrapper for the popular R library ggplot2. With rpy2, the most convenient general way to import packages is to use `importr()`, for example with ggplot2:: from rpy2.robjects.packages import importr ggplot2 = importr('ggplot2') This module is an supplementary layer in which an attempt at modelling the package as it was really developed as Python package is made. Behind the scene, `importr()` is used and can be accessed with: from robjects.robjects.lib import ggplot2 ggplot2.ggplot2 GGplot2 is designed using a prototype-based approach to Object-Oriented Programming, and this module is trying to define class-hierachies so the nature of a given instance can be identified more easily. The main families of classes are: - GGplot - Aes and AesString - Layer - Stat A downside of the approach is that the code in the module is 'hand-made'. In hindsight, this can be tedious to maintain and document but this is a good showcase of "manual" mapping of R code into Python classes. The codebase in R for ggplot2 has evolved since this was initially written, and many functions have signature-defined parameters (used to be ellipsis about everywhere). Metaprogramming will hopefully be added to shorten the Python code in the module, and provide a more dynamic mapping. """ import rpy2.robjects as robjects import rpy2.robjects.conversion as conversion import rpy2.rinterface as rinterface from rpy2.robjects.packages import importr import copy import warnings NULL = robjects.NULL ggplot2 = importr('ggplot2') TARGET_VERSION = '0.9.3.1' if ggplot2.__version__ != TARGET_VERSION: warnings.warn('This was designed againt ggplot2 version %s but you have %s' % (TARGET_VERSION, ggplot2.__version__)) ggplot2_env = robjects.baseenv['as.environment']('package:ggplot2') StrVector = robjects.StrVector def as_symbol(x): res = rinterface.parse(x) return res class GGPlot(robjects.RObject): """ A Grammar of Graphics Plot. GGPlot instances can be added to one an other in order to construct the final plot (the method `__add__()` is implemented). """ _constructor = ggplot2._env['ggplot'] _rprint = ggplot2._env['print.ggplot'] _add = ggplot2._env['%+%'] @classmethod def new(cls, data): """ Constructor for the class GGplot. """ data = conversion.py2ri(data) res = cls(cls._constructor(data)) return res def plot(self, vp = robjects.constants.NULL): self._rprint(self, vp = vp) def __add__(self, obj): res = self._add(self, obj) if res.rclass[0] != 'gg': raise ValueError("Added object did not give a ggplot result (get class '%s')." % res.rclass[0]) return self.__class__(res) ggplot = GGPlot.new class Aes(robjects.Vector): """ Aesthetics mapping, using expressions rather than string (this is the most common form when using the package in R - it might be easier to use AesString when working in Python using rpy2 - see class AesString in this Python module). """ _constructor = ggplot2_env['aes'] @classmethod def new(cls, **kwargs): """Constructor for the class Aes.""" new_kwargs = copy.copy(kwargs) for k,v in kwargs.iteritems(): new_kwargs[k] = as_symbol(v) res = cls(cls._constructor(**new_kwargs)) return res aes = Aes.new class AesString(robjects.Vector): """ Aesthetics mapping, using strings rather than expressions (the later being most common form when using the package in R - see class Aes in this Python module). This associates dimensions in the data sets (columns in the DataFrame), possibly with a transformation applied on-the-fly (e.g., "log(value)", or "cost / benefits") to graphical "dimensions" in a chosen graphical representation (e.g., x-axis, color of points, size, etc...). Not all graphical representations have all dimensions. Refer to the documentation of ggplot2, online tutorials, or Hadley's book for more details. """ _constructor = ggplot2_env['aes_string'] @classmethod def new(cls, **kwargs): """Constructor for the class AesString.""" new_kwargs = copy.copy(kwargs) for k,v in kwargs.iteritems(): new_kwargs[k] = as_symbol(v) res = cls(cls._constructor(**new_kwargs)) return res aes_string = AesString.new class Layer(robjects.RObject): """ At this level, aesthetics mapping can (should ?) be specified (see Aes and AesString). """ _constructor = ggplot2_env['layer'] #_dollar = proto_env["$.proto"] @classmethod def new(cls, *args, **kwargs): """ Constructor for the class Layer. """ for i, elt in enumerate(args): args[i] = conversion.py2ro(elt) for k in kwargs: kwargs[k] = conversion.py2ro(kwargs[k]) res = cls(cls.contructor)(*args, **kwargs) return res layer = Layer.new class GBaseObject(robjects.RObject): @classmethod def new(*args, **kwargs): args_list = list(args) cls = args_list.pop(0) res = cls(cls._constructor(*args_list, **kwargs)) return res class Stat(GBaseObject): """ A "statistical" processing of the data in order to make a plot, or a plot element. This is an abstract class; material classes are called Stat* (e.g., StatAbline, StatBin, etc...). """ pass class StatAbline(Stat): """ Line from slope and intercept. """ _constructor = ggplot2_env['stat_abline'] stat_abline = StatAbline.new class StatBin(Stat): """ Bin data. """ _constructor = ggplot2_env['stat_bin'] stat_bin = StatBin.new class StatBin2D(Stat): """ 2D binning of data into squares/rectangles. """ _constructor = ggplot2_env['stat_bin2d'] stat_bin2d = StatBin2D.new class StatBinhex(Stat): """ 2D binning of data into hexagons. """ _constructor = ggplot2_env['stat_binhex'] stat_binhex = StatBinhex.new class StatBoxplot(Stat): """ Components of box and whisker plot. """ _constructor = ggplot2_env['stat_boxplot'] stat_boxplot = StatBoxplot.new class StatContour(Stat): """ Contours of 3D data. """ _constructor = ggplot2_env['stat_contour'] stat_contour = StatContour.new class StatDensity(Stat): """ 1D density estimate """ _constructor = ggplot2_env['stat_density'] stat_density = StatDensity.new class StatDensity2D(Stat): """ 2D density estimate """ _constructor = ggplot2_env['stat_density2d'] stat_density2d = StatDensity2D.new class StatFunction(Stat): """ Superimpose a function """ _constructor = ggplot2_env['stat_function'] stat_function = StatFunction.new class StatHline(Stat): """ Horizontal line """ _constructor = ggplot2_env['stat_hline'] stat_hline = StatHline.new class StatIdentity(Stat): """ Identity function """ _constructor = ggplot2_env['stat_identity'] stat_identity = StatIdentity.new class StatQQ(Stat): """ Calculation for quantile-quantile plot. """ _constructor = ggplot2_env['stat_qq'] stat_qq = StatQQ.new class StatQuantile(Stat): """ Continuous quantiles """ _constructor = ggplot2_env['stat_quantile'] stat_quantile = StatQuantile.new class StatSmooth(Stat): """ Smoothing function """ _constructor = ggplot2_env['stat_smooth'] stat_smooth = StatSmooth.new class StatSpoke(Stat): """ Convert angle and radius to xend and yend """ _constructor = ggplot2_env['stat_spoke'] stat_spoke = StatSpoke.new class StatSum(Stat): """ Sum unique values. Useful when overplotting. """ _constructor = ggplot2_env['stat_sum'] stat_sum = StatSum.new class StatSummary(Stat): """ Summarize values for y at every unique value for x""" _constructor = ggplot2_env['stat_summary'] stat_summary = StatSummary.new class StatUnique(Stat): """ Remove duplicates. """ _constructor = ggplot2_env['stat_unique'] stat_unique = StatUnique.new class StatVline(Stat): """ Vertival line. """ _constructor = ggplot2_env['stat_vline'] stat_vline = StatVline.new class Coord(GBaseObject): """ Coordinates """ pass class CoordFixed(Coord): """ Cartesian coordinates with fixed relationship (that is fixed ratio between units in axes). CoordEquel seems to be identical to this class.""" _constructor = ggplot2_env['coord_fixed'] coord_fixed = CoordFixed.new class CoordCartesian(Coord): """ Cartesian coordinates. """ _constructor = ggplot2_env['coord_cartesian'] coord_cartesian = CoordCartesian.new class CoordEqual(Coord): """ This class seems to be identical to CoordFixed. """ _constructor = ggplot2_env['coord_equal'] coord_equal = CoordEqual.new class CoordFlip(Coord): """ Flip horizontal and vertical coordinates. """ _constructor = ggplot2_env['coord_flip'] coord_flip = CoordFlip.new class CoordMap(Coord): """ Map projections. """ _constructor = ggplot2_env['coord_map'] coord_map = CoordMap.new class CoordPolar(Coord): """ Polar coordinates. """ _constructor = ggplot2_env['coord_polar'] coord_polar = CoordPolar.new class CoordTrans(Coord): """ Apply transformations (functions) to a cartesian coordinate system. """ _constructor = ggplot2_env['coord_trans'] coord_trans = CoordTrans.new class Facet(GBaseObject): """ Panels """ pass class FacetGrid(Facet): """ Panels in a grid. """ _constructor = ggplot2_env['facet_grid'] facet_grid = FacetGrid.new class FacetWrap(Facet): """ Sequence of panels in a 2D layout """ _constructor = ggplot2_env['facet_wrap'] facet_wrap = FacetWrap.new class Geom(GBaseObject): pass class GeomAbline(Geom): _constructor = ggplot2_env['geom_abline'] geom_abline = GeomAbline.new class GeomArea(Geom): _constructor = ggplot2_env['geom_area'] geom_area = GeomArea.new class GeomBar(Geom): _constructor = ggplot2_env['geom_bar'] geom_bar = GeomBar.new class GeomBin2D(Geom): _constructor = ggplot2_env['geom_bin2d'] geom_bin2d = GeomBin2D.new class GeomBlank(Geom): _constructor = ggplot2_env['geom_blank'] geom_blank = GeomBlank.new class GeomBoxplot(Geom): _constructor = ggplot2_env['geom_boxplot'] geom_boxplot = GeomBoxplot.new class GeomContour(Geom): _constructor = ggplot2_env['geom_contour'] geom_contour = GeomContour.new class GeomCrossBar(Geom): _constructor = ggplot2_env['geom_crossbar'] geom_crossbar = GeomCrossBar.new class GeomDensity(Geom): _constructor = ggplot2_env['geom_density'] geom_density = GeomDensity.new class GeomDensity2D(Geom): _constructor = ggplot2_env['geom_density2d'] geom_density2d = GeomDensity2D.new class GeomDotplot(Geom): _constructor = ggplot2_env['geom_dotplot'] geom_dotplot = GeomDotplot.new class GeomErrorBar(Geom): _constructor = ggplot2_env['geom_errorbar'] geom_errorbar = GeomErrorBar.new class GeomErrorBarH(Geom): _constructor = ggplot2_env['geom_errorbarh'] geom_errorbarh = GeomErrorBarH.new class GeomFreqPoly(Geom): _constructor = ggplot2_env['geom_freqpoly'] geom_freqpoly = GeomFreqPoly.new class GeomHex(Geom): _constructor = ggplot2_env['geom_hex'] geom_hex = GeomHex.new class GeomHistogram(Geom): _constructor = ggplot2_env['geom_histogram'] geom_histogram = GeomHistogram.new class GeomHLine(Geom): _constructor = ggplot2_env['geom_hline'] geom_hline = GeomHLine.new class GeomJitter(Geom): _constructor = ggplot2_env['geom_jitter'] geom_jitter = GeomJitter.new class GeomLine(Geom): _constructor = ggplot2_env['geom_line'] geom_line = GeomLine.new class GeomLineRange(Geom): _constructor = ggplot2_env['geom_linerange'] geom_linerange = GeomLineRange.new class GeomPath(Geom): _constructor = ggplot2_env['geom_path'] geom_path = GeomPath.new class GeomPoint(Geom): _constructor = ggplot2_env['geom_point'] geom_point = GeomPoint.new class GeomPointRange(Geom): _constructor = ggplot2_env['geom_pointrange'] geom_pointrange = GeomPointRange.new class GeomPolygon(Geom): _constructor = ggplot2_env['geom_polygon'] geom_polygon = GeomPolygon.new class GeomQuantile(Geom): _constructor = ggplot2_env['geom_quantile'] geom_quantile = GeomQuantile.new class GeomRect(Geom): _constructor = ggplot2_env['geom_rect'] geom_rect = GeomRect.new class GeomRibbon(Geom): _constructor = ggplot2_env['geom_ribbon'] geom_ribbon = GeomRibbon.new class GeomRug(Geom): _constructor = ggplot2_env['geom_rug'] geom_rug = GeomRug.new class GeomSegment(Geom): _constructor = ggplot2_env['geom_segment'] geom_segment = GeomSegment.new class GeomSmooth(Geom): _constructor = ggplot2_env['geom_smooth'] geom_smooth = GeomSmooth.new class GeomStep(Geom): _constructor = ggplot2_env['geom_step'] geom_step = GeomStep.new class GeomText(Geom): _constructor = ggplot2_env['geom_text'] geom_text = GeomText.new class GeomTile(Geom): _constructor = ggplot2_env['geom_tile'] geom_tile = GeomTile.new class GeomVLine(Geom): _constructor = ggplot2_env['geom_vline'] geom_vline = GeomVLine.new class Position(GBaseObject): pass class PositionDodge(Position): _constructor = ggplot2_env['position_dodge'] position_dodge = PositionDodge.new class PositionFill(Position): _constructor = ggplot2_env['position_fill'] position_fill = PositionFill.new class PositionJitter(Position): _constructor = ggplot2_env['position_jitter'] position_jitter = PositionJitter.new class PositionStack(Position): _constructor = ggplot2_env['position_stack'] position_stack = PositionStack.new class Scale(GBaseObject): pass class ScaleAlpha(Scale): _constructor = ggplot2_env['scale_alpha'] scale_alpha = ScaleAlpha.new class ScaleColour(Scale): pass class ScaleDiscrete(Scale): pass class ScaleLinetype(Scale): _constructor = ggplot2_env['scale_linetype'] scale_linetype = ScaleLinetype.new class ScaleShape(Scale): _constructor = ggplot2_env['scale_shape'] scale_shape = ScaleShape.new class ScaleSize(Scale): _constructor = ggplot2_env['scale_size'] scale_size = ScaleSize.new class ScaleShapeDiscrete(Scale): _constructor = ggplot2_env['scale_shape_discrete'] scale_shape_discrete = ScaleShapeDiscrete.new class ScaleFill(Scale): pass class ScaleX(Scale): pass class ScaleY(Scale): pass # class Limits(Scale): # _constructor = ggplot2_env['limits'] # limits = Limits.new class XLim(Scale): _constructor = ggplot2_env['xlim'] xlim = XLim.new class YLim(Scale): _constructor = ggplot2_env['ylim'] ylim = YLim.new class ScaleXContinuous(ScaleX): _constructor = ggplot2_env['scale_x_continuous'] scale_x_continuous = ScaleXContinuous.new class ScaleYContinuous(ScaleY): _constructor = ggplot2_env['scale_y_continuous'] scale_y_continuous = ScaleYContinuous.new class ScaleXDiscrete(ScaleX): _constructor = ggplot2_env['scale_x_discrete'] scale_x_discrete = ScaleXDiscrete.new class ScaleYDiscrete(ScaleY): _constructor = ggplot2_env['scale_y_discrete'] scale_y_discrete = ScaleYDiscrete.new class ScaleXDate(ScaleX): _constructor = ggplot2_env['scale_x_date'] scale_x_date = ScaleXDate.new class ScaleYDate(ScaleY): _constructor = ggplot2_env['scale_y_date'] scale_y_date = ScaleYDate.new class ScaleXDatetime(ScaleX): _constructor = ggplot2_env['scale_x_datetime'] scale_x_datetime = ScaleXDatetime.new class ScaleYDatetime(ScaleY): _constructor = ggplot2_env['scale_y_datetime'] scale_y_datetime = ScaleYDatetime.new class ScaleXLog10(ScaleX): _constructor = ggplot2_env['scale_x_log10'] scale_x_log10 = ScaleXLog10.new class ScaleYLog10(ScaleY): _constructor = ggplot2_env['scale_y_log10'] scale_y_log10 = ScaleYLog10.new class ScaleXReverse(ScaleX): _constructor = ggplot2_env['scale_x_reverse'] scale_x_reverse = ScaleXReverse.new class ScaleYReverse(ScaleY): _constructor = ggplot2_env['scale_y_reverse'] scale_y_reverse = ScaleYReverse.new class ScaleXSqrt(ScaleX): _constructor = ggplot2_env['scale_x_sqrt'] scale_x_sqrt = ScaleXSqrt.new class ScaleYSqrt(ScaleY): _constructor = ggplot2_env['scale_y_sqrt'] scale_y_sqrt = ScaleYSqrt.new class ScaleColourBrewer(ScaleColour): _constructor = ggplot2_env['scale_colour_brewer'] scale_colour_brewer = ScaleColourBrewer.new class ScaleColourContinuous(ScaleColour): _constructor = ggplot2_env['scale_colour_continuous'] scale_colour_continuous = ScaleColourContinuous.new class ScaleColourDiscrete(ScaleColour): _constructor = ggplot2_env['scale_colour_discrete'] scale_colour_discrete = ScaleColourDiscrete.new class ScaleColourGradient(ScaleColour): _constructor = ggplot2_env['scale_colour_gradient'] scale_colour_gradient = ScaleColourGradient.new class ScaleColourGradient2(ScaleColour): _constructor = ggplot2_env['scale_colour_gradient2'] scale_colour_gradient2 = ScaleColourGradient2.new class ScaleColourGradientN(ScaleColour): _constructor = ggplot2_env['scale_colour_gradientn'] scale_colour_gradientn = ScaleColourGradientN.new class ScaleColourGrey(ScaleColour): _constructor = ggplot2_env['scale_colour_grey'] scale_colour_grey = ScaleColourGrey.new class ScaleColourHue(ScaleColour): _constructor = ggplot2_env['scale_colour_hue'] scale_colour_hue = ScaleColourHue.new class ScaleColourIdentity(ScaleColour): _constructor = ggplot2_env['scale_colour_identity'] scale_colour_identity = ScaleColourIdentity.new class ScaleColourManual(ScaleColour): _constructor = ggplot2_env['scale_colour_manual'] scale_colour_manual = ScaleColourManual.new class ScaleFillBrewer(ScaleFill): _constructor = ggplot2_env['scale_fill_brewer'] scale_fill_brewer = ScaleFillBrewer.new class ScaleFillContinuous(ScaleFill): _constructor = ggplot2_env['scale_fill_continuous'] scale_fill_continuous = ScaleFillContinuous.new class ScaleFillDiscrete(ScaleFill): _constructor = ggplot2_env['scale_fill_discrete'] scale_fill_discrete = ScaleFillDiscrete.new class ScaleFillGradient(ScaleFill): _constructor = ggplot2_env['scale_fill_gradient'] scale_fill_gradient = ScaleFillGradient.new class ScaleFillGradient2(ScaleFill): _constructor = ggplot2_env['scale_fill_gradient2'] scale_fill_gradient2 = ScaleFillGradient2.new class ScaleFillGradientN(ScaleFill): _constructor = ggplot2_env['scale_fill_gradientn'] scale_fill_gradientn = ScaleFillGradientN.new class ScaleFillGrey(ScaleFill): _constructor = ggplot2_env['scale_fill_grey'] scale_fill_grey = ScaleFillGrey.new class ScaleFillHue(ScaleFill): _constructor = ggplot2_env['scale_fill_hue'] scale_fill_hue = ScaleFillHue.new class ScaleFillIdentity(ScaleFill): _constructor = ggplot2_env['scale_fill_identity'] scale_fill_identity = ScaleFillIdentity.new class ScaleFillManual(ScaleFill): _constructor = ggplot2_env['scale_fill_manual'] scale_fill_manual = ScaleFillManual.new class ScaleLinetypeManual(ScaleLinetype): _constructor = ggplot2_env['scale_linetype_manual'] scale_linetype_manual = ScaleLinetypeManual.new class ScaleShapeManual(ScaleShape): _constructor = ggplot2_env['scale_shape_manual'] scale_shape_manual = ScaleShapeManual.new guides = ggplot2.guides guide_colorbar = ggplot2.guide_colorbar guide_colourbar = ggplot2.guide_colourbar guide_legend = ggplot2.guide_legend class Options(robjects.Vector): def __init__(self, obj): self.__sexp__ = obj.__sexp__ def __repr__(self): s = '' %(type(self), id(self)) return s class Element(Options): pass class ElementText(Element): _constructor = ggplot2.element_text @classmethod def new(cls, family = "", face = "plain", colour = "black", size = 10, hjust = 0.5, vjust = 0.5, angle = 0, lineheight = 1.1, color = NULL): res = cls(cls._constructor(family = family, face = face, colour = colour, size = size, hjust = hjust, vjust = vjust, angle = angle, lineheight = lineheight)) return res element_text = ElementText.new class ElementRect(Element): _constructor = ggplot2.element_rect @classmethod def new(cls, fill = NULL, colour = NULL, size = NULL, linetype = NULL, color = NULL): res = cls(cls._constructor(fill = fill, colour = colour, size = size, linetype = linetype, color = color)) return res element_rect = ElementRect.new class Theme(Options): pass class ElementBlank(Theme): _constructor = ggplot2.element_blank @classmethod def new(cls): res = cls(cls._constructor()) return res element_blank = ElementBlank.new class ThemeBlank(Theme): _constructor = ggplot2.theme_blank @classmethod def new(cls): res = cls(cls._constructor()) return res theme_blank = ThemeBlank.new theme_get = ggplot2.theme_get class ThemeGrey(Theme): _constructor = ggplot2.theme_grey @classmethod def new(cls, base_size = 12): res = cls(cls._constructor(base_size = base_size)) return res theme_grey = ThemeGrey.new class ThemeClassic(Theme): _constructor = ggplot2.theme_classic @classmethod def new(cls, base_size = 12, base_family = ""): res = cls(cls._constructor(base_size = base_size, base_family = base_family)) return res theme_classic = ThemeClassic.new class ThemeRect(Theme): _constructor = ggplot2.theme_rect @classmethod def new(cls, fill = robjects.NA_Logical, colour = "black", size = 0.5, linetype = 1): res = cls(cls._constructor(fill = fill, colour = colour, size = size, linetype = linetype)) return res theme_rect = ThemeRect.new class ThemeSegment(Theme): _constructor = ggplot2.theme_rect @classmethod def new(cls, colour = 'black', size = 0.5, linetype = 1): res = cls(cls._constructor(colour = colour, size = size, linetype = linetype)) return res theme_segment = ThemeSegment.new class ThemeBW(Theme): _constructor = ggplot2.theme_bw @classmethod def new(cls, base_size = 12): res = cls(cls._constructor(base_size = base_size)) return res theme_bw = ThemeBW.new class ThemeGray(Theme): _constructor = ggplot2.theme_gray @classmethod def new(cls, base_size = 12): res = cls(cls._constructor(base_size = base_size)) return res theme_gray = ThemeGray.new class ThemeLine(Theme): _constructor = ggplot2.theme_line @classmethod def new(cls, colour = 'black', size = 0.5, linetype = 1): res = cls(cls._constructor(colour = colour, size = size, linetype = linetype)) return res theme_line = ThemeLine.new #theme_render theme_set = ggplot2.theme_set theme_update = ggplot2.theme_update gplot = ggplot2.qplot map_data = ggplot2.map_data opts = ggplot2_env['opts'] theme = ggplot2_env['theme'] ggtitle = ggplot2.ggtitle original_conversion = conversion.ri2py def ggplot2_conversion(robj): pyobj = original_conversion(robj) rcls = pyobj.rclass if rcls is NULL: rcls = (None, ) if 'gg' in rcls: pyobj = GGPlot(pyobj) return pyobj conversion.ri2py = ggplot2_conversion rpy2-2.3.9/rpy/robjects/lib/ggplot2/0000755000175000017500000000000012271276522020346 5ustar laurentlaurent00000000000000rpy2-2.3.9/rpy/robjects/lib/ggplot2/__init__.py0000644000175000017500000004206012104173561022453 0ustar laurentlaurent00000000000000import rpy2.robjects.methods import rpy2.robjects as robjects import rpy2.robjects.conversion as conversion import rpy2.rinterface as rinterface from rpy2.robjects.packages import importr import copy import rpy2.robjects.lib.ggplot2.theme as theme NULL = robjects.NULL #getmethod = robjects.baseenv.get("getMethod") rimport = robjects.baseenv.get('library') ggplot2 = importr('ggplot2') ggplot2_env = robjects.baseenv['as.environment']('package:ggplot2') StrVector = robjects.StrVector def as_symbol(x): res = rinterface.parse(x) return res class GGPlot(robjects.RObject): _constructor = ggplot2_env['ggplot'] _rprint = robjects.baseenv[':::']('ggplot2', 'print.ggplot') _add = ggplot2_env['+.ggplot'] @classmethod def new(cls, data): res = cls(cls._constructor(data)) return res def plot(self, vp = robjects.constants.NULL): self._rprint(self, vp = vp) def __add__(self, obj): res = self._add(self, obj) return res ggplot = GGPlot.new class Aes(robjects.Vector): _constructor = ggplot2_env['aes'] @classmethod def new(cls, **kwargs): new_kwargs = copy.copy(kwargs) for k,v in kwargs.items(): new_kwargs[k] = as_symbol(v) res = cls(cls._constructor(**new_kwargs)) return res aes = Aes.new class AesString(robjects.Vector): _constructor = ggplot2_env['aes_string'] @classmethod def new(cls, **kwargs): new_kwargs = copy.copy(kwargs) for k,v in kwargs.items(): new_kwargs[k] = as_symbol(v) res = cls(cls._constructor(**new_kwargs)) return res aes_string = AesString.new class Layer(robjects.RObject): _constructor = ggplot2_env['layer'] #_dollar = proto_env["$.proto"] @classmethod def new(cls, geom, geom_params, stat, stat_params, data, aesthetics, position, params): args = [conversion.py2ro(x) for x in (geom, geom_params, stat, stat_params, data, aesthetics, position, params)] res = cls(cls.contructor)(*args) return res layer = Layer.new class GBaseObject(robjects.RObject): @classmethod def new(*args, **kwargs): args_list = list(args) cls = args_list.pop(0) res = cls(cls._constructor(*args_list, **kwargs)) return res class Stat(GBaseObject): pass class StatAbline(Stat): _constructor = ggplot2_env['stat_abline'] stat_abline = StatAbline.new class StatBin(Stat): _constructor = ggplot2_env['stat_bin'] stat_bin = StatBin.new class StatBin2D(Stat): _constructor = ggplot2_env['stat_bin2d'] stat_bin2d = StatBin2D.new class StatBinhex(Stat): _constructor = ggplot2_env['stat_binhex'] stat_binhex = StatBinhex.new class StatBoxplot(Stat): _constructor = ggplot2_env['stat_boxplot'] stat_boxplot = StatBoxplot.new class StatContour(Stat): _constructor = ggplot2_env['stat_contour'] stat_contour = StatContour.new class StatDensity(Stat): _constructor = ggplot2_env['stat_density'] stat_density = StatDensity.new class StatDensity2D(Stat): _constructor = ggplot2_env['stat_density2d'] stat_density2d = StatDensity2D.new class StatFunction(Stat): _constructor = ggplot2_env['stat_function'] stat_function = StatFunction.new class StatHline(Stat): _constructor = ggplot2_env['stat_hline'] stat_hline = StatHline.new class StatIdentity(Stat): _constructor = ggplot2_env['stat_identity'] stat_identity = StatIdentity.new class StatQQ(Stat): _constructor = ggplot2_env['stat_qq'] stat_qq = StatQQ.new class StatQuantile(Stat): _constructor = ggplot2_env['stat_quantile'] stat_quantile = StatQuantile.new class StatSmooth(Stat): _constructor = ggplot2_env['stat_smooth'] stat_smooth = StatSmooth.new class StatSpoke(Stat): _constructor = ggplot2_env['stat_spoke'] stat_spoke = StatSpoke.new class StatSum(Stat): _constructor = ggplot2_env['stat_sum'] stat_sum = StatSum.new class StatSummary(Stat): _constructor = ggplot2_env['stat_summary'] stat_summary = StatSummary.new class StatUnique(Stat): _constructor = ggplot2_env['stat_unique'] stat_unique = StatUnique.new class StatVline(Stat): _constructor = ggplot2_env['stat_vline'] stat_vline = StatVline.new class Coord(GBaseObject): pass class CoordCartesian(Coord): _constructor = ggplot2_env['coord_cartesian'] coord_cartesian = CoordCartesian.new class CoordEqual(Coord): _constructor = ggplot2_env['coord_equal'] coord_equal = CoordEqual.new class CoordFlip(Coord): _constructor = ggplot2_env['coord_flip'] coord_flip = CoordFlip.new class CoordMap(Coord): _constructor = ggplot2_env['coord_map'] coord_map = CoordMap.new class CoordPolar(Coord): _constructor = ggplot2_env['coord_polar'] coord_polar = CoordPolar.new class CoordTrans(Coord): _constructor = ggplot2_env['coord_trans'] coord_trans = CoordTrans.new class Facet(GBaseObject): pass class FacetGrid(Facet): _constructor = ggplot2_env['facet_grid'] facet_grid = FacetGrid.new class FacetWrap(Facet): _constructor = ggplot2_env['facet_wrap'] facet_wrap = FacetWrap.new class Geom(GBaseObject): pass class GeomAbline(Geom): _constructor = ggplot2_env['geom_abline'] geom_abline = GeomAbline.new class GeomArea(Geom): _constructor = ggplot2_env['geom_area'] geom_area = GeomArea.new class GeomBar(Geom): _constructor = ggplot2_env['geom_bar'] geom_bar = GeomBar.new class GeomBin2D(Geom): _constructor = ggplot2_env['geom_bin2d'] geom_bin2d = GeomBin2D.new class GeomBlank(Geom): _constructor = ggplot2_env['geom_blank'] geom_blank = GeomBlank.new class GeomBoxplot(Geom): _constructor = ggplot2_env['geom_boxplot'] geom_boxplot = GeomBoxplot.new class GeomContour(Geom): _constructor = ggplot2_env['geom_contour'] geom_contour = GeomContour.new class GeomCrossBar(Geom): _constructor = ggplot2_env['geom_crossbar'] geom_crossbar = GeomCrossBar.new class GeomDensity(Geom): _constructor = ggplot2_env['geom_density'] geom_density = GeomDensity.new class GeomDensity2D(Geom): _constructor = ggplot2_env['geom_density2d'] geom_density2d = GeomDensity2D.new class GeomErrorBar(Geom): _constructor = ggplot2_env['geom_errorbar'] geom_errorbar = GeomErrorBar.new class GeomErrorBarH(Geom): _constructor = ggplot2_env['geom_errorbarh'] geom_errorbarh = GeomErrorBarH.new class GeomFreqPoly(Geom): _constructor = ggplot2_env['geom_freqpoly'] geom_freqpoly = GeomFreqPoly.new class GeomHex(Geom): _constructor = ggplot2_env['geom_hex'] geom_hex = GeomHex.new class GeomHistogram(Geom): _constructor = ggplot2_env['geom_histogram'] geom_histogram = GeomHistogram.new class GeomHLine(Geom): _constructor = ggplot2_env['geom_hline'] geom_hline = GeomHLine.new class GeomJitter(Geom): _constructor = ggplot2_env['geom_jitter'] geom_jitter = GeomJitter.new class GeomLine(Geom): _constructor = ggplot2_env['geom_line'] geom_line = GeomLine.new class GeomLineRange(Geom): _constructor = ggplot2_env['geom_linerange'] geom_linerange = GeomLineRange.new class GeomPath(Geom): _constructor = ggplot2_env['geom_path'] geom_path = GeomPath.new class GeomPoint(Geom): _constructor = ggplot2_env['geom_point'] geom_point = GeomPoint.new class GeomPointRange(Geom): _constructor = ggplot2_env['geom_pointrange'] geom_pointrange = GeomPointRange.new class GeomPolygon(Geom): _constructor = ggplot2_env['geom_polygon'] geom_polygon = GeomPolygon.new class GeomQuantile(Geom): _constructor = ggplot2_env['geom_quantile'] geom_quantile = GeomQuantile.new class GeomRect(Geom): _constructor = ggplot2_env['geom_rect'] geom_rect = GeomRect.new class GeomRibbon(Geom): _constructor = ggplot2_env['geom_ribbon'] geom_ribbon = GeomRibbon.new class GeomRug(Geom): _constructor = ggplot2_env['geom_rug'] geom_rug = GeomRug.new class GeomSegment(Geom): _constructor = ggplot2_env['geom_segment'] geom_segment = GeomSegment.new class GeomSmooth(Geom): _constructor = ggplot2_env['geom_smooth'] geom_smooth = GeomSmooth.new class GeomStep(Geom): _constructor = ggplot2_env['geom_step'] geom_step = GeomStep.new class GeomText(Geom): _constructor = ggplot2_env['geom_text'] geom_text = GeomText.new class GeomTile(Geom): _constructor = ggplot2_env['geom_tile'] geom_tile = GeomTile.new class GeomVLine(Geom): _constructor = ggplot2_env['geom_vline'] geom_vline = GeomVLine.new class Position(GBaseObject): pass class PositionDodge(Position): _constructor = ggplot2_env['position_dodge'] position_dodge = PositionDodge.new class PositionFill(Position): _constructor = ggplot2_env['position_fill'] position_fill = PositionFill.new class PositionIdentify(Position): _constructor = ggplot2_env['position_identity'] position_identity = PositionIdentify.new class PositionJitter(Position): _constructor = ggplot2_env['position_jitter'] position_jitter = PositionJitter.new class PositionStack(Position): _constructor = ggplot2_env['position_stack'] position_stack = PositionStack.new class Scale(GBaseObject): pass class ScaleAlpha(Scale): _constructor = ggplot2_env['scale_alpha'] scale_alpha = ScaleAlpha.new class ScaleColour(Scale): _constructor = ggplot2_env['scale_colour'] scale_colour = ScaleColour.new class ScaleDiscrete(Scale): _constructor = ggplot2_env['scale_discrete'] scale_discrete = ScaleDiscrete.new class ScaleLinetype(Scale): _constructor = ggplot2_env['scale_linetype'] scale_linetype = ScaleLinetype.new class ScaleShape(Scale): _constructor = ggplot2_env['scale_shape'] scale_shape = ScaleShape.new class ScaleSize(Scale): _constructor = ggplot2_env['scale_size'] scale_size = ScaleSize.new class ScaleFill(Scale): pass class ScaleX(Scale): pass class ScaleY(Scale): pass class Limits(Scale): _constructor = ggplot2_env['limits'] limits = Limits.new class XLim(Scale): _constructor = ggplot2_env['xlim'] xlim = XLim.new class YLim(Scale): _constructor = ggplot2_env['ylim'] ylim = YLim.new class ScaleXContinuous(ScaleX): _constructor = ggplot2_env['scale_x_continuous'] scale_x_continuous = ScaleXContinuous.new class ScaleYContinuous(ScaleY): _constructor = ggplot2_env['scale_y_continuous'] scale_y_continuous = ScaleYContinuous.new class ScaleXDiscrete(ScaleX): _constructor = ggplot2_env['scale_x_discrete'] scale_x_discrete = ScaleXDiscrete.new class ScaleYDiscrete(ScaleY): _constructor = ggplot2_env['scale_y_discrete'] scale_y_discrete = ScaleYDiscrete.new class ScaleXDate(ScaleX): _constructor = ggplot2_env['scale_x_date'] scale_x_date = ScaleXDate.new class ScaleYDate(ScaleY): _constructor = ggplot2_env['scale_y_date'] scale_y_date = ScaleYDate.new class ScaleXDatetime(ScaleX): _constructor = ggplot2_env['scale_x_datetime'] scale_x_datetime = ScaleXDatetime.new class ScaleYDatetime(ScaleY): _constructor = ggplot2_env['scale_y_datetime'] scale_y_datetime = ScaleYDatetime.new class ScaleXExp(ScaleX): _constructor = ggplot2_env['scale_x_exp'] scale_x_exp = ScaleXExp.new class ScaleYExp(ScaleY): _constructor = ggplot2_env['scale_y_exp'] scale_y_exp = ScaleYExp.new class ScaleXInverse(ScaleX): _constructor = ggplot2_env['scale_x_inverse'] scale_x_inverse = ScaleXInverse.new class ScaleYInverse(ScaleY): _constructor = ggplot2_env['scale_y_inverse'] scale_y_inverse = ScaleYInverse.new class ScaleXLog(ScaleX): _constructor = ggplot2_env['scale_x_log'] scale_x_log = ScaleXLog.new class ScaleYLog(ScaleY): _constructor = ggplot2_env['scale_y_log'] scale_y_log = ScaleYLog.new class ScaleXLog10(ScaleX): _constructor = ggplot2_env['scale_x_log10'] scale_x_log10 = ScaleXLog10.new class ScaleYLog10(ScaleY): _constructor = ggplot2_env['scale_y_log10'] scale_y_log10 = ScaleYLog10.new class ScaleXLog2(ScaleX): _constructor = ggplot2_env['scale_x_log2'] scale_x_log2 = ScaleXLog2.new class ScaleYLog2(ScaleY): _constructor = ggplot2_env['scale_y_log2'] scale_y_log2 = ScaleYLog2.new class ScaleXLogit(ScaleX): _constructor = ggplot2_env['scale_x_logit'] scale_x_logit = ScaleXLogit.new class ScaleYLogit(ScaleY): _constructor = ggplot2_env['scale_y_logit'] scale_y_logit = ScaleYLogit.new class ScaleXPow(ScaleX): _constructor = ggplot2_env['scale_x_pow'] scale_x_pow = ScaleXPow.new class ScaleYPow(ScaleY): _constructor = ggplot2_env['scale_y_pow'] scale_y_pow = ScaleYPow.new class ScaleXPow10(ScaleX): _constructor = ggplot2_env['scale_x_pow10'] scale_x_pow10 = ScaleXPow10.new class ScaleYPow10(ScaleY): _constructor = ggplot2_env['scale_y_pow10'] scale_y_pow10 = ScaleYPow10.new class ScaleXProb(ScaleX): _constructor = ggplot2_env['scale_x_prob'] scale_x_prob = ScaleXProb.new class ScaleYProb(ScaleY): _constructor = ggplot2_env['scale_y_prob'] scale_y_prob = ScaleYProb.new class ScaleXProbit(ScaleX): _constructor = ggplot2_env['scale_x_probit'] scale_x_probit = ScaleXProbit.new class ScaleYProbit(ScaleY): _constructor = ggplot2_env['scale_y_probit'] scale_y_probit = ScaleYProbit.new class ScaleXReverse(ScaleX): _constructor = ggplot2_env['scale_x_reverse'] scale_x_reverse = ScaleXReverse.new class ScaleYReverse(ScaleY): _constructor = ggplot2_env['scale_y_reverse'] scale_y_reverse = ScaleYReverse.new class ScaleXSqrt(ScaleX): _constructor = ggplot2_env['scale_x_sqrt'] scale_x_sqrt = ScaleXSqrt.new class ScaleYSqrt(ScaleY): _constructor = ggplot2_env['scale_y_sqrt'] scale_y_sqrt = ScaleYSqrt.new class ScaleColourBrewer(ScaleColour): _constructor = ggplot2_env['scale_colour_brewer'] scale_colour_brewer = ScaleColourBrewer.new class ScaleColourContinuous(ScaleColour): _constructor = ggplot2_env['scale_colour_continuous'] scale_colour_continuous = ScaleColourContinuous.new class ScaleColourDiscrete(ScaleColour): _constructor = ggplot2_env['scale_colour_discrete'] scale_colour_discrete = ScaleColourDiscrete.new class ScaleColourGradient(ScaleColour): _constructor = ggplot2_env['scale_colour_gradient'] scale_colour_gradient = ScaleColourGradient.new class ScaleColourGradient2(ScaleColour): _constructor = ggplot2_env['scale_colour_gradient2'] scale_colour_gradient2 = ScaleColourGradient2.new class ScaleColourGradientN(ScaleColour): _constructor = ggplot2_env['scale_colour_gradientn'] scale_colour_gradientn = ScaleColourGradientN.new class ScaleColourGrey(ScaleColour): _constructor = ggplot2_env['scale_colour_grey'] scale_colour_grey = ScaleColourGrey.new class ScaleColourHue(ScaleColour): _constructor = ggplot2_env['scale_colour_hue'] scale_colour_hue = ScaleColourHue.new class ScaleColourIdentity(ScaleColour): _constructor = ggplot2_env['scale_colour_identity'] scale_colour_identity = ScaleColourIdentity.new class ScaleColourManual(ScaleColour): _constructor = ggplot2_env['scale_colour_manual'] scale_colour_manual = ScaleColourManual.new class ScaleFillBrewer(ScaleFill): _constructor = ggplot2_env['scale_fill_brewer'] scale_fill_brewer = ScaleFillBrewer.new class ScaleFillContinuous(ScaleFill): _constructor = ggplot2_env['scale_fill_continuous'] scale_fill_continuous = ScaleFillContinuous.new class ScaleFillDiscrete(ScaleFill): _constructor = ggplot2_env['scale_fill_discrete'] scale_fill_discrete = ScaleFillDiscrete.new class ScaleFillGradient(ScaleFill): _constructor = ggplot2_env['scale_fill_gradient'] scale_fill_gradient = ScaleFillGradient.new class ScaleFillGradient2(ScaleFill): _constructor = ggplot2_env['scale_fill_gradient2'] scale_fill_gradient2 = ScaleFillGradient2.new class ScaleFillGradientN(ScaleFill): _constructor = ggplot2_env['scale_fill_gradientn'] scale_fill_gradientn = ScaleFillGradientN.new class ScaleFillGrey(ScaleFill): _constructor = ggplot2_env['scale_fill_grey'] scale_fill_grey = ScaleFillGrey.new class ScaleFillHue(ScaleFill): _constructor = ggplot2_env['scale_fill_hue'] scale_fill_hue = ScaleFillHue.new class ScaleFillIdentity(ScaleFill): _constructor = ggplot2_env['scale_fill_identity'] scale_fill_identity = ScaleFillIdentity.new class ScaleFillManual(ScaleFill): _constructor = ggplot2_env['scale_fill_manual'] scale_fill_manual = ScaleFillManual.new class ScaleLinetypeManual(ScaleLinetype): _constructor = ggplot2_env['scale_linetype_manual'] scale_linetype_manual = ScaleLinetypeManual.new class ScaleShapeManual(ScaleShape): _constructor = ggplot2_env['scale_shape_manual'] scale_shape_manual = ScaleShapeManual.new # --- themes theme_blank = theme.Blank.new theme_grey = theme.Grey.new theme_rect = theme.Rect.new theme_segment = theme.Segment.new theme_text = theme.Text.new theme_bw = theme.BW.new theme_gray = theme.Gray.new theme_line = theme.Line.new # theme_render theme_get = ggplot2.theme_get theme_set = ggplot2.theme_set theme_update = ggplot2.theme_update gplot = ggplot2.qplot map_data = ggplot2.map_data opts = ggplot2_env['opts'] original_conversion = conversion.ri2py def ggplot2_conversion(robj): pyobj = original_conversion(robj) rcls = pyobj.rclass if rcls is NULL: rcls = (None, ) if 'ggplot' in rcls: pyobj = GGPlot(pyobj) return pyobj conversion.ri2py = ggplot2_conversion rpy2-2.3.9/rpy/robjects/lib/ggplot2/theme.py0000644000175000017500000000466711610010213022012 0ustar laurentlaurent00000000000000from rpy2.robjects.packages import importr ggplot2_pack = importr('ggplot2') class Options(robjects.Vector): def __init__(self, obj): self.__sexp__ = obj.__sexp__ def __repr__(self): s = '' %(type(self), id(self)) return s class Theme(Options): pass class Blank(Theme): _constructor = ggplot2_pack.theme_blank @classmethod def new(cls): res = cls(cls._constructor()) return res class Grey(Theme): _constructor = ggplot2_pack.theme_grey @classmethod def new(cls, base_size = 12): res = cls(cls._constructor(base_size = base_size)) return res class Rect(Theme): _constructor = ggplot2_pack.theme_rect @classmethod def new(cls, fill = robjects.NA_Logical, colour = "black", size = 0.5, linetype = 1): res = cls(cls._constructor(fill = fill, colour = colour, size = size, linetype = linetype)) return res class Segment(Theme): _constructor = ggplot2_pack.theme_rect @classmethod def new(cls, colour = 'black', size = 0.5, linetype = 1): res = cls(cls._constructor(colour = colour, size = size, linetype = linetype)) return res # Theme text is not a vector :/ class Text(robjects.Function): _constructor = ggplot2_pack.theme_text @classmethod def new(cls, family = "", face = "plain", colour = "black", size = 10, hjust = 0.5, vjust = 0.5, angle = 0, lineheight = 1.1): res = cls(cls._constructor(family = family, face = face, colour = colour, size = size, hjust = hjust, vjust = vjust, angle = angle, lineheight = lineheight)) return res class BW(Theme): _constructor = ggplot2_pack.theme_bw @classmethod def new(cls, base_size = 12): res = cls(cls._constructor(base_size = base_size)) return res class Gray(Theme): _constructor = ggplot2_pack.theme_gray @classmethod def new(cls, base_size = 12): res = cls(cls._constructor(base_size = base_size)) return res class Line(Theme): _constructor = ggplot2_pack.theme_line @classmethod def new(cls, colour = 'black', size = 0.5, linetype = 1): res = cls(cls._constructor(colour = colour, size = size, linetype = linetype)) return res rpy2-2.3.9/rpy/interactive/0000755000175000017500000000000012271276522016724 5ustar laurentlaurent00000000000000rpy2-2.3.9/rpy/interactive/process_revents.py0000644000175000017500000000332412271276146022526 0ustar laurentlaurent00000000000000"""This module runs continuous updates for R, such as redrawing graphs when the plot window is resized. Use the start() and stop() functions to turn updates on and off. """ from rpy2.rinterface import process_revents import time import threading class _EventProcessorThread(threading.Thread): """ Call rinterface.process_revents(), pausing for at least EventProcessor.interval between calls. """ _continue = True def run(self): while self._continue: process_revents() time.sleep(EventProcessor.interval) class EventProcessor(object): """ Processor for R events (Singleton class) """ interval = 0.2 daemon_thread = True name_thread = 'rpy2_process_revents' _thread = None _instance = None def __new__(cls): if cls._instance is None: cls._instance = object.__new__(cls) return cls._instance def start(self): """ start the event processor """ if (self._thread is not None) and (self._thread.is_alive()): raise RuntimeError("Processing of R events already started.") else: self._thread = _EventProcessorThread(name = self.name_thread) self._thread.setDaemon(self.daemon_thread) self._thread.start() def stop(self): """ stop the event processor """ self._thread._continue = False self._thread.join() thread = property(lambda self: self._thread, None, None, "Thread that processes the events.") def start(): """ Start the threaded processing of R events. """ EventProcessor().start() def stop(): """ Stop the threaded processing of R events. """ EventProcessor().stop() rpy2-2.3.9/rpy/interactive/tests/0000755000175000017500000000000012271276522020066 5ustar laurentlaurent00000000000000rpy2-2.3.9/rpy/interactive/tests/__init__.py0000644000175000017500000000060712271276146022204 0ustar laurentlaurent00000000000000import unittest import testRevents def suite(): suite_Revents = testRevents.suite() alltests = unittest.TestSuite([suite_Revents, ]) return alltests def main(): r = unittest.TestResult() suite().run(r) return r if __name__ == '__main__': tr = unittest.TextTestRunner(verbosity = 2) suite = suite() tr.run(suite) rpy2-2.3.9/rpy/interactive/ipython.py0000644000175000017500000000370312271276146020775 0ustar laurentlaurent00000000000000""" Goodies for ipython """ from rpy2 import robjects from rpy2.robjects.packages import importr from rpy2.robjects.lib import ggplot2 from IPython.core.display import Image import tempfile grdevices = importr('grDevices') # automatic plotting of ggplot2 figures in the notebook class GGPlot(ggplot2.GGPlot): # special representation for ipython def _repr_png_(self, width = 700, height = 500): # Hack with a temp file (use buffer later ?) fn = tempfile.NamedTemporaryFile(mode = 'wb', suffix = '.png', delete = False) fn.close() grdevices.png(fn.name, width = width, height = height) self.plot() grdevices.dev_off() import io with io.OpenWrapper(fn.name, mode='rb') as data: res = data.read() return res def png(self, width = 700, height = 500): """ Build an Ipython "Image" (requires iPython). """ return Image(self._repr_png_(width = width, height = height), embed=True) ggplot = GGPlot.new class GGPlotSVG(ggplot2.GGPlot): """ The embedding of several SVG figures into one ipython notebook is giving garbled figures. The SVG functionality is taken out to a child class. """ def _repr_svg_(self, width = 6, height = 4): # Hack with a temp file (use buffer later ?) fn = tempfile.NamedTemporaryFile(mode = 'wb', suffix = '.svg', delete = False) fn.close() grdevices.svg(fn.name, width = width, height = height) self.plot() grdevices.dev_off() import io with io.OpenWrapper(fn.name, mode='rb') as data: res = data.read().decode('utf-8') return res def svg(self, width = 6, height = 4): """ Build an Ipython "Image" (requires iPython). """ return Image(self._repr_svg_(width = width, height = height), embed=True) rpy2-2.3.9/rpy/interactive/__init__.py0000644000175000017500000000267412271276146021050 0ustar laurentlaurent00000000000000""" Package to interface with R, with a focus on interactive usage (REPL approach to code-writing), although the package will work in non-interactive settings. The package aims at being simple rather than exhaustively complete (rpy2.robjects, or rpy2.rinterface, can be used if needed), providing a comfortable experience with autocompletion-capable python consoles. """ from collections import OrderedDict from rpy2.robjects.packages import _loaded_namespaces from rpy2.robjects.vectors import IntVector, FloatVector, ComplexVector from rpy2.robjects.vectors import Array, Matrix from rpy2.robjects.vectors import StrVector from rpy2.robjects.vectors import ListVector, DataFrame from rpy2.robjects.environments import Environment from rpy2.rinterface import NULL from rpy2.robjects import Formula, RS4 from rpy2.robjects import methods from rpy2.robjects import conversion from rpy2.robjects import help as rhelp from rpy2.robjects.language import eval from . import process_revents as revents from os import linesep import re class S4Classes(object): """ *Very* experimental attempt at getting the S4 classes dynamically mirrored. """ __instance = None def __new__(cls): if cls.__instance is None: cls.__instance = object.__new__(cls) return cls.__instance def __setattr__(self, name, value): raise AttributeError("Attributes cannot be set. Use 'importr'") #classes = S4Classes() #revents.start() rpy2-2.3.9/rpy/interactive/packages.py0000664000175000017500000001420212217361501021045 0ustar laurentlaurent00000000000000from rpy2.robjects.packages import importr as _importr import rpy2.robjects.help as rhelp from rpy2.rinterface import baseenv from os import linesep from collections import OrderedDict import re class Packages(object): __instance = None def __new__(cls): if cls.__instance is None: cls.__instance = object.__new__(cls) return cls.__instance def __setattr__(self, name, value): raise AttributeError("Attributes cannot be set. Use 'importr'") packages = Packages() _loaded_namespaces = baseenv['loadedNamespaces'] def importr(packname, newname = None, verbose = False): """ Wrapper around rpy2.robjects.packages.importr, adding the following features: - package instance added to the pseudo-module 'packages' - automatic pydoc generation from the R help pages """ assert isinstance(packname, str) packinstance = _importr(packname, on_conflict = 'warn') # fix the package name (dots possible in R package names) if newname is None: newname = packname.replace('.', '_') Packages().__dict__[newname] = packinstance ## Currently too slow for a serious usage: R's introspection ## of S4 classes is not fast enough # d = {} # for cn in methods.get_classnames(packname): # class AutoS4(RS4): # __metaclass__ = methods.RS4Auto_Type # __rpackagename__ = packname # __rname__ = cn # newcn = cn.replace('.', '_') # d[newcn] = AutoS4 # S4Classes().__dict__[newname] = d p_latex_code = re.compile('\\\\code{([^}]+)}') p_latex_link = re.compile('\\\\link{([^}]+)}') p_latex_any_curly = re.compile('\\\\[^ ]+{([^}]+)}') p_latex_any = re.compile('\\\\([^ ]+)') p_latex_usage = re.compile('\\\\method{(?P[^}]+)}{(?P[^}]+)}(?P.+)') doc = rhelp.Package(packname) for obj_name in packinstance.__dict__: obj = packinstance.__dict__[obj_name] # ignore class-defined attributes to only consider # the ones defined dynamically if hasattr(type(packinstance), obj_name): continue try: p = doc.fetch(obj.__rname__) except rhelp.HelpNotFoundError as hnfe: # No R documentation could be found for the object if verbose: print('Pydoc generator: no help for "%s"' %(obj_name, )) continue except AttributeError as ae: # No __rname__ for the object print('Pydoc generator: oddity with "%s"' %(obj_name, )) continue except: print('Pydoc generator: oddity with "%s" ("%s")' %(obj_name, obj.__rname__)) continue if obj_name in packinstance._exported_names: exported = True else: exported = False #if verbose: # print('Pydoc generator: "%s" not exported' %(obj_name, )) #continue docstring = [p.title(), '[ %s - %s exported ]' %(p._type, 'not' if not exported else ''), '** Experimental dynamic conversion of the associated R documentation **'] tmp = p.description() tmp = re.sub(p_latex_any_curly, "'\\1'", tmp) docstring.append(tmp) docstring.append('') tmp_usage = p.usage().split(linesep) for i, row in enumerate(tmp_usage): tmp_m = p_latex_usage.match(row) if tmp_m is not None: tmp_usage[i] = '%s_%s%s' %(tmp_m.group('method'), tmp_m.group('class'), tmp_m.group('signature')) tmp_usage = linesep.join(tmp_usage) docstring.extend([tmp_usage, '']) if obj_name not in packinstance._exported_names: tmp = p.seealso() tmp = re.sub(p_latex_code, "'\\1'", tmp) tmp = re.sub(p_latex_any_curly, '\\1', tmp) tmp = re.sub(p_latex_any, "'\\1'", tmp) docstring.extend(['', 'See Also:', tmp]) docstring = linesep.join(docstring) obj.__doc__ = docstring continue try: arguments = p.arguments() except KeyError as ke: #FIXME: no arguments - should the handling differ a bit ? arguments = tuple() # Assume uniqueness of values in the dict. This is making sense since # parameters to the function should have unique names ans... this appears to be enforced # by R when declaring a function arguments = OrderedDict(arguments) if hasattr(obj, '_prm_translate'): docstring.extend(['', 'Parameters:', '']) for k, v in obj._prm_translate.items(): try: tmp = arguments[v] tmp = re.sub(p_latex_code, "'\\1'", tmp) tmp = re.sub(p_latex_any_curly, '\\1', tmp) tmp = re.sub(p_latex_any, "'\\1'", tmp) docstring.append('%s -- %s' %(k, tmp)) except KeyError: # This is an inconsistency in the R documentation # (the parameter in the function's signature does # not have an entry in the R documentation). # Do nothing. # if verbose: print('Pydoc generator: no help for parameter "%s" in %s' %(k, obj_name)) docstring.append('%s -- [error fetching the documentation]' %(k)) #print('Pydoc generator: oddity with R\'s "%s" over the parameter "%s"' %(obj_name, v)) tmp = p.value() tmp = re.sub(p_latex_code, "'\\1'", tmp) tmp = re.sub(p_latex_any, '\\1', tmp) docstring.extend(['', 'Returns:', tmp]) tmp = p.seealso() tmp = re.sub(p_latex_code, "'\\1'", tmp) tmp = re.sub(p_latex_any_curly, '\\1', tmp) tmp = re.sub(p_latex_any, "'\\1'", tmp) docstring.extend(['', 'See Also:', tmp]) docstring = linesep.join(docstring) obj.__doc__ = docstring return packinstance for packname in _loaded_namespaces(): importr(packname) rpy2-2.3.9/rpy/tests.py0000644000175000017500000000206712271276146016132 0ustar laurentlaurent00000000000000if __name__ == "__main__": import sys, rpy2.rinterface sys.stdout.write("rpy2 version: %s\n" % rpy2.__version__) sys.stdout.write("built against R version: %s\n" % '-'.join(str(x) for x in rpy2.rinterface.R_VERSION_BUILD)) sys.stdout.flush() import unittest import rpy2.robjects.tests import rpy2.rinterface.tests import rpy2.rlike.tests #import rpy2.interactive.tests import rpy2.tests_rpy_classic def suite(): suite_robjects = rpy2.robjects.tests.suite() suite_rinterface = rpy2.rinterface.tests.suite() suite_rlike = rpy2.rlike.tests.suite() #suite_interactive = rpy2.interactive.tests.suite() suite_rpy_classic = rpy2.tests_rpy_classic.suite() alltests = unittest.TestSuite([suite_rinterface, suite_robjects, suite_rlike, #suite_interactive, suite_rpy_classic ]) return alltests if __name__ == "__main__": unittest.main(defaultTest = "suite") rpy2-2.3.9/rpy/rlike/0000755000175000017500000000000012271276522015515 5ustar laurentlaurent00000000000000rpy2-2.3.9/rpy/rlike/tests/0000755000175000017500000000000012271276522016657 5ustar laurentlaurent00000000000000rpy2-2.3.9/rpy/rlike/tests/test_container.py0000644000175000017500000001731712271276146022265 0ustar laurentlaurent00000000000000import unittest import itertools import rpy2.rlike.container as rlc class OrdDictTestCase(unittest.TestCase): def testNew(self): nl = rlc.OrdDict() x = (('a', 123), ('b', 456), ('c', 789)) nl = rlc.OrdDict(x) def testLen(self): x = rlc.OrdDict() self.assertEqual(0, len(x)) x['a'] = 2 x['b'] = 1 self.assertEqual(2, len(x)) def testGetSetitem(self): x = rlc.OrdDict() x['a'] = 1 self.assertEqual(1, len(x)) self.assertEqual(1, x['a']) self.assertEqual(0, x.index('a')) x['a'] = 2 self.assertEqual(1, len(x)) self.assertEqual(2, x['a']) self.assertEqual(0, x.index('a')) x['b'] = 1 self.assertEqual(2, len(x)) self.assertEqual(1, x['b']) self.assertEqual(1, x.index('b')) def testGet(self): x = rlc.OrdDict() x['a'] = 1 self.assertEqual(1, x.get('a')) self.assertEqual(None, x.get('b')) self.assertEqual(2, x.get('b', 2)) def testKeys(self): x = rlc.OrdDict() for i,k in enumerate('abcdef'): x[k] = i for i,k in enumerate(x.keys()): self.assertEqual('abcdef'[i], k) def testGetSetitemWithNone(self): x = rlc.OrdDict() x['a'] = 1 x[None] = 2 self.assertEqual(2, len(x)) x['b'] = 5 self.assertEqual(3, len(x)) self.assertEqual(1, x['a']) self.assertEqual(5, x['b']) self.assertEqual(0, x.index('a')) self.assertEqual(2, x.index('b')) def testReverse(self): x = rlc.OrdDict() x['a'] = 3 x['b'] = 2 x['c'] = 1 x.reverse() self.assertEqual(1, x['c']) self.assertEqual(0, x.index('c')) self.assertEqual(2, x['b']) self.assertEqual(1, x.index('b')) self.assertEqual(3, x['a']) self.assertEqual(2, x.index('a')) def testItems(self): args = (('a', 5), ('b', 4), ('c', 3), ('d', 2), ('e', 1)) x = rlc.OrdDict(args) it = x.items() for ki, ko in itertools.izip(args, it): self.assertEqual(ki[0], ko[0]) self.assertEqual(ki[1], ko[1]) class TaggedListTestCase(unittest.TestCase): def test__add__(self): tl = rlc.TaggedList((1,2,3), tags=('a', 'b', 'c')) tl = tl + tl self.assertEqual(6, len(tl)) self.assertEqual(('a', 'b', 'c', 'a', 'b', 'c'), tl.tags) self.assertEqual((1,2,3,1,2,3), tuple(tl)) def test__delitem__(self): tl = rlc.TaggedList((1,2,3), tags=('a', 'b', 'c')) self.assertEqual(3, len(tl)) del tl[1] self.assertEqual(2, len(tl)) self.assertEqual(tl.tags, ('a', 'c')) self.assertEqual(tuple(tl), (1, 3)) def test__delslice__(self): tl = rlc.TaggedList((1,2,3,4), tags=('a', 'b', 'c', 'd')) del tl[1:3] self.assertEqual(2, len(tl)) self.assertEqual(tl.tags, ('a', 'd')) self.assertEqual(tuple(tl), (1, 4)) def test__iadd__(self): tl = rlc.TaggedList((1,2,3), tags=('a', 'b', 'c')) tl += tl self.assertEqual(6, len(tl)) self.assertEqual(('a', 'b', 'c', 'a', 'b', 'c'), tl.tags) self.assertEqual((1,2,3,1,2,3), tuple(tl)) def test__imul__(self): tl = rlc.TaggedList((1,2), tags=('a', 'b')) tl *= 3 self.assertEqual(6, len(tl)) self.assertEqual(('a', 'b', 'a', 'b', 'a', 'b'), tl.tags) self.assertEqual((1,2,1,2,1,2), tuple(tl)) def test__init__(self): tl = rlc.TaggedList((1,2,3), tags=('a', 'b', 'c')) self.assertRaises(ValueError, rlc.TaggedList, (1,2,3), tags = ('b', 'c')) def test__setslice__(self): tl = rlc.TaggedList((1,2,3,4), tags=('a', 'b', 'c', 'd')) tl[1:3] = [5, 6] self.assertEqual(4, len(tl)) self.assertEqual(tl.tags, ('a', 'b', 'c', 'd')) self.assertEqual(tuple(tl), (1, 5, 6, 4)) def testappend(self): tl = rlc.TaggedList((1,2,3), tags=('a', 'b', 'c')) self.assertEqual(3, len(tl)) tl.append(4, tag='a') self.assertEqual(4, len(tl)) self.assertEqual(4, tl[3]) self.assertEqual(('a', 'b', 'c', 'a'), tl.tags) def testextend(self): tl = rlc.TaggedList((1,2,3), tags=('a', 'b', 'c')) tl.extend([4, 5]) self.assertEqual(('a', 'b', 'c', None, None), tuple(tl.itertags())) self.assertEqual((1, 2, 3, 4, 5), tuple(tl)) def testinsert(self): tl = rlc.TaggedList((1,2,3), tags=('a', 'b', 'c')) tl.insert(1, 4, tag = 'd') self.assertEqual(('a', 'd', 'b', 'c'), tuple(tl.itertags())) self.assertEqual((1, 4, 2, 3), tuple(tl)) def testitems(self): tl = rlc.TaggedList((1,2,3), tags=('a', 'b', 'c')) self.assertEqual((('a', 1), ('b', 2), ('c', 3)), tuple(tl.items())) def testiterontag(self): tl = rlc.TaggedList((1,2,3), tags=('a', 'b', 'a')) self.assertEqual((1, 3), tuple(tl.iterontag('a'))) def testitertags(self): tl = rlc.TaggedList((1,2,3), tags=('a', 'b', 'c')) self.assertEqual(('a', 'b', 'c'), tuple(tl.itertags())) def testpop(self): tl = rlc.TaggedList((1,2,3), tags=('a', 'b', 'c')) self.assertEqual(3, len(tl)) elt = tl.pop() self.assertEqual(3, elt) self.assertEqual(2, len(tl)) self.assertEqual(tl.tags, ('a', 'b')) self.assertEqual(tuple(tl), (1, 2)) elt = tl.pop(0) self.assertEqual(1, elt) self.assertEqual(1, len(tl)) self.assertEqual(tl.tags, ('b', )) def testremove(self): tl = rlc.TaggedList((1,2,3), tags=('a', 'b', 'c')) self.assertEqual(3, len(tl)) tl.remove(2) self.assertEqual(2, len(tl)) self.assertEqual(tl.tags, ('a', 'c')) self.assertEqual(tuple(tl), (1, 3)) def testreverse(self): tn = ['a', 'b', 'c'] tv = [1,2,3] tl = rlc.TaggedList(tv, tags = tn) tl.reverse() self.assertEqual(3, len(tl)) self.assertEqual(tl.tags, ('c', 'b', 'a')) self.assertEqual(tuple(tl), (3, 2, 1)) def testsort(self): tn = ['a', 'c', 'b'] tv = [1,3,2] tl = rlc.TaggedList(tv, tags = tn) tl.sort() self.assertEqual(tl.tags, ('a', 'b', 'c')) self.assertEqual(tuple(tl), (1, 2, 3)) def testtags(self): tn = ['a', 'b', 'c'] tv = [1,2,3] tl = rlc.TaggedList(tv, tags = tn) tags = tl.tags self.assertTrue(isinstance(tags, tuple)) self.assertEqual(tags, ('a', 'b', 'c')) tn = ['d', 'e', 'f'] tl.tags = tn self.assertTrue(isinstance(tags, tuple)) self.assertEqual(tuple(tn), tl.tags) def testsettag(self): tn = ['a', 'b', 'c'] tv = [1,2,3] tl = rlc.TaggedList(tv, tags = tn) tl.settag(1, 'z') self.assertEqual(tl.tags, ('a', 'z', 'c')) def testfrom_iteritems(self): od = rlc.OrdDict( (('a', 1), ('b', 2), ('c', 3)) ) tl = rlc.TaggedList.from_iteritems(od) self.assertEqual(('a', 'b', 'c'), tl.tags) self.assertEqual((1, 2, 3), tuple(tl)) tl = rlc.TaggedList.from_iteritems({'a':1, 'b':2, 'c':3}) self.assertEqual(set(('a', 'b', 'c')), set(tl.tags)) self.assertEqual(set((1, 2, 3)), set(tuple(tl))) def suite(): suite = unittest.TestLoader().loadTestsFromTestCase(OrdDictTestCase) suite.addTest(unittest.TestLoader().loadTestsFromTestCase(TaggedListTestCase)) return suite if __name__ == '__main__': unittest.main() rpy2-2.3.9/rpy/rlike/tests/__init__.py0000644000175000017500000000074412271276146020777 0ustar laurentlaurent00000000000000import unittest import test_container import test_functional import test_indexing def suite(): suite_container = test_container.suite() suite_functional = test_functional.suite() suite_indexing = test_indexing.suite() alltests = unittest.TestSuite([suite_container, suite_functional, suite_indexing]) return alltests def main(): r = unittest.TestResult() suite().run(r) return r rpy2-2.3.9/rpy/rlike/tests/test_functional.py0000644000175000017500000000213512271276146022435 0ustar laurentlaurent00000000000000import unittest import itertools import rpy2.rlike.functional as rlf class TapplyTestCase(unittest.TestCase): def testSumByString(self): seq = ( 1, 2, 3, 4, 5, 6) tags = ('a', 'b', 'a', 'c', 'b', 'a') expected = {'a': 1+3+6, 'b': 2+5, 'c': 4} res = rlf.tapply(seq, tags, sum) for k, v in res: self.assertEqual(expected[k], v) class VectorizeTestCase(unittest.TestCase): def simpleFunction(self, subject_fun): def f(x): return x ** 2 f_iter = subject_fun(f) seq = (1, 2, 3) res = f_iter(seq) for va, vb in itertools.izip(seq, res): self.assertEqual(va ** 2, vb) def testIterify(self): self.simpleFunction(rlf.iterify) def testListify(self): self.simpleFunction(rlf.listify) def suite(): suite = unittest.TestLoader().loadTestsFromTestCase(TapplyTestCase) suite.addTest(unittest.TestLoader().loadTestsFromTestCase(VectorizeTestCase)) return suite if __name__ == '__main__': unittest.main() rpy2-2.3.9/rpy/rlike/tests/test_indexing.py0000644000175000017500000000107112271276146022076 0ustar laurentlaurent00000000000000import unittest import itertools import rpy2.rlike.indexing as rfi class OrderTestCase(unittest.TestCase): def testOrder(self): seq = ( 2, 1, 5, 3, 4) expected = (1, 2, 3, 4, 5) res = rfi.order(seq) for va, vb in itertools.izip(expected, res): self.assertEqual(va, seq[vb]) def suite(): suite = unittest.TestLoader().loadTestsFromTestCase(OrderTestCase) #suite.addTest(unittest.TestLoader().loadTestsFromTestCase(VectorizeTestCase)) return suite if __name__ == '__main__': unittest.main() rpy2-2.3.9/rpy/rlike/indexing.py0000644000175000017500000000056712271276146017706 0ustar laurentlaurent00000000000000 def default_key(x): """ Default comparison function """ return x def order(seq, key = default_key, reverse = False): """ Return the order in which to take the items to obtained a sorted sequence.""" o = range(len(seq)) def wrap_key(x): x = seq[x] return key(x) o.sort(key = wrap_key, reverse = reverse) return o rpy2-2.3.9/rpy/rlike/__init__.py0000644000175000017500000000000012271276146017616 0ustar laurentlaurent00000000000000rpy2-2.3.9/rpy/rlike/container.py0000644000175000017500000002221712271276146020057 0ustar laurentlaurent00000000000000import itertools import rpy2.rlike.indexing as rli class OrdDict(dict): """ Implements the Ordered Dict API defined in PEP 372. When `odict` becomes part of collections, this class should inherit from it rather than from `dict`. This class differs a little from the Ordered Dict proposed in PEP 372 by the fact that: not all elements have to be named. None as a key value means an absence of name for the element. """ def __init__(self, c=[]): if isinstance(c, TaggedList) or isinstance(c, OrdDict): c = c.iteritems() elif isinstance(c, dict): #FIXME: allow instance from OrdDict ? raise ValueError('A regular dictionnary does not ' +\ 'conserve the order of its keys.') super(OrdDict, self).__init__() self.__l = [] l = self.__l for k,v in c: self[k] = v def __copy__(self): cp = OrdDict(c = tuple(self.iteritems())) return cp def __cmp__(self, o): raise(Exception("Not yet implemented.")) def __eq__(self): raise(Exception("Not yet implemented.")) def __getitem__(self, key): if key is None: raise ValueError("Unnamed items cannot be retrieved by key.") i = super(OrdDict, self).__getitem__(key) return self.__l[i][1] def __iter__(self): l = self.__l for e in l: k = e[0] if k is None: continue else: yield k def __len__(self): return len(self.__l) def __ne__(self): raise(Exception("Not yet implemented.")) def __repr__(self): s = 'o{' for k,v in self.iteritems(): s += "'" + str(k) + "': " + str(v) + ", " s += '}' return s def __reversed__(self): raise(Exception("Not yet implemented.")) def __setitem__(self, key, value): """ Replace the element if the key is known, and conserve its rank in the list, or append it if unknown. """ if key is None: self.__l.append((key, value)) return if self.has_key(key): i = self.index(key) self.__l[i] = (key, value) else: self.__l.append((key, value)) super(OrdDict, self).__setitem__(key, len(self.__l)-1) def byindex(self, i): """ Fetch a value by index (rank), rather than by key.""" return self.__l[i] def index(self, k): """ Return the index (rank) for the key 'k' """ return super(OrdDict, self).__getitem__(k) def items(self): """ Return an ordered list of all key/value pairs """ res = [self.byindex(i) for i in xrange(len(self.__l))] return tuple(res) def get(self, k, d = None): """ OD.get(k[,d]) -> OD[k] if k in OD, else d. d defaults to None """ try: res = self[k] except KeyError, ke: res = d return res def iteritems(self): """ OD.iteritems() -> an iterator over the (key, value) items of D """ return iter(self.__l) def keys(self): """ """ return tuple([x[0] for x in self.__l]) def reverse(self): """ Reverse the order of the elements in-place (no copy).""" l = self.__l n = len(self.__l) for i in xrange(n//2): tmp = l[i] l[i] = l[n-i-1] kv = l[i] if kv is not None: super(OrdDict, self).__setitem__(kv[0], i) l[n-i-1] = tmp kv = tmp if kv is not None: super(OrdDict, self).__setitem__(kv[0], n-i-1) def sort(self, cmp=None, key=None, reverse=False): raise(Exception("Not yet implemented.")) class TaggedList(list): """ A list for which each item has a 'tag'. :param l: list :param tag: optional sequence of tags """ def __add__(self, tl): try: tags = tl.tags except AttributeError, ae: raise ValueError('Can only concatenate TaggedLists.') res = TaggedList(list(self) + list(tl), tags = self.tags + tl.tags) return res def __delitem__(self, y): super(TaggedList, self).__delitem__(y) self.__tags.__delitem__(y) def __delslice__(self, i, j): super(TaggedList, self).__delslice__(i, j) self.__tags.__delslice__(i, j) def __iadd__(self, y): super(TaggedList, self).__iadd__(y) if isinstance(y, TaggedList): self.__tags.__iadd__(y.tags) else: self.__tags.__iadd__([None, ] * len(y)) return self def __imul__(self, y): restags = self.__tags.__imul__(y) resitems = super(TaggedList, self).__imul__(y) return self @staticmethod def from_iteritems(tagval): res = TaggedList([]) for k,v in tagval.iteritems(): res.append(v, tag=k) return res def __init__(self, seq, tags = None): super(TaggedList, self).__init__(seq) if tags is None: tags = [None, ] * len(seq) if len(tags) != len(seq): raise ValueError("There must be as many tags as seq") self.__tags = list(tags) def __setslice__(self, i, j, y): super(TaggedList, self).__setslice__(i, j, y) #FIXME: handle TaggedList ? #self.__tags.__setslice__(i, j, [None, ]) def append(self, obj, tag = None): """ Append an object to the list :param obj: object :param tag: object """ super(TaggedList, self).append(obj) self.__tags.append(tag) def extend(self, iterable): """ Extend the list with an iterable object. :param iterable: iterable object """ if isinstance(iterable, TaggedList): itertags = iterable.itertags() else: itertags = [None, ] * len(iterable) for tag, item in itertools.izip(itertags, iterable): self.append(item, tag=tag) def insert(self, index, obj, tag=None): """ Insert an object in the list :param index: integer :param obj: object :param tag: object """ super(TaggedList, self).insert(index, obj) self.__tags.insert(index, tag) def items(self): """ Return a tuple of all pairs (tag, item). :rtype: tuple of 2-element tuples (tag, item) """ res = [(tag, item) for tag, item in itertools.izip(self.__tags, self)] return tuple(res) def iterontag(self, tag): """ iterate on items marked with one given tag. :param tag: object """ i = 0 for onetag in self.__tags: if tag == onetag: yield self[i] i += 1 def iteritems(self): """ OD.iteritems() -> an iterator over the (key, value) items of D """ for tag, item in itertools.izip(self.__tags, self): yield (tag, item) def itertags(self): """ iterate on tags. :rtype: iterator """ for tag in self.__tags: yield tag def pop(self, index=None): """ Pop the item at a given index out of the list :param index: integer """ if index is None: index = len(self) - 1 res = super(TaggedList, self).pop(index) self.__tags.pop(index) return res def remove(self, value): """ Remove a given value from the list. :param value: object """ found = False for i in xrange(len(self)): if self[i] == value: found = True break if found: self.pop(i) def reverse(self): """ Reverse the order of the elements in the list. """ super(TaggedList, self).reverse() self.__tags.reverse() def sort(self, reverse = False): """ Sort in place """ o = rli.order(self, reverse = reverse) super(TaggedList, self).sort(reverse = reverse) self.__tags = [self.__tags[i] for i in o] def __get_tags(self): return tuple(self.__tags) def __set_tags(self, tags): if len(tags) == len(self.__tags): self.__tags = tuple(tags) else: raise ValueError("The new list of tags should have the same length as the old one") tags = property(__get_tags, __set_tags) def settag(self, i, t): """ Set tag 't' for item 'i'. :param i: integer (index) :param t: object (tag) """ self.__tags[i] = t # class DataFrame(ArgsDict): # def __init__(self, s): # super(ArgsDict, self).__init__(s) # if len(self) > 0: # nrows = len(self[0]) # for i, v in enumerate(self): # if len(v) != nrows: # raise ValueError("Expected length %i for element %i" # %(nrows, i)) rpy2-2.3.9/rpy/rlike/functional.py0000644000175000017500000000176412271276146020243 0ustar laurentlaurent00000000000000import itertools def tapply(seq, tag, fun): """ Apply the function `fun` to the items in `seq`, grouped by the tags defined in `tag`. :param seq: sequence :param tag: any sequence of tags :param fun: function :rtype: list """ if len(seq) != len(tag): raise ValueError("seq and tag should have the same length.") tag_grp = {} for i, t in enumerate(tag): try: tag_grp[t].append(i) except LookupError, le: tag_grp[t] = [i, ] res = [(tag, fun([seq[i] for i in ti])) for tag, ti in tag_grp.items()] return res def listify(fun): """ Decorator to make a function apply to each item in a sequence, and return a list. """ def f(seq): res = [fun(x) for x in seq] return res return f def iterify(fun): """ Decorator to make a function apply to each item in a sequence, and return an iterator. """ def f(seq): for x in seq: yield fun(x) return f rpy2-2.3.9/rpy/__init__.py0000644000175000017500000000022312271276145016516 0ustar laurentlaurent00000000000000 __version_vector__ = ((2,3,9), '') __version__ = '.'.join([str(x) for x in __version_vector__[0]]) + \ '' + __version_vector__[1] rpy2-2.3.9/rpy/tests_rpy_classic.py0000644000175000017500000000305212271276146020520 0ustar laurentlaurent00000000000000import unittest import rpy2.rpy_classic as rpy import rpy2.rinterface class RpyClassicTestCase(unittest.TestCase): def testAttributeExpansion(self): rpy.set_default_mode(rpy.BASIC_CONVERSION) wtest = rpy.r.wilcox_test self.assertTrue(isinstance(wtest, rpy.Robj)) def testFunctionCall(self): rpy.set_default_mode(rpy.BASIC_CONVERSION) # positional only three = rpy.r.sum(1,2) three = three[0] # is this what is happening w/ rpy, or the list is # ...automatically dropped ? self.assertEqual(3, three) # positional + keywords onetwothree = rpy.r.seq(1, 3, by=0.5) self.assertEqual([1.0, 1.5, 2.0, 2.5, 3.0], onetwothree) def testFunctionCallWithRObj(self): rpy.set_default_mode(rpy.NO_CONVERSION) onetwo = rpy.r.seq(1, 2) three = rpy.r.sum(onetwo) rpy.set_default_mode(rpy.BASIC_CONVERSION) self.assertEqual(3, three.sexp[0]) def testCallable(self): rpy.set_default_mode(rpy.NO_CONVERSION) #in rpy-1.x, everything is callable self.assertTrue(callable(rpy.r.seq)) self.assertTrue(callable(rpy.r.pi)) def testSexp(self): rpy.set_default_mode(rpy.NO_CONVERSION) pi = rpy.r.pi self.assertTrue(isinstance(pi.sexp, rpy2.rinterface.Sexp)) self.assertRaises(AttributeError, setattr, pi, 'sexp', None) def suite(): suite = unittest.TestLoader().loadTestsFromTestCase(RpyClassicTestCase) return suite if __name__ == '__main__': unittest.main() rpy2-2.3.9/rpy/rinterface/0000755000175000017500000000000012271276522016531 5ustar laurentlaurent00000000000000rpy2-2.3.9/rpy/rinterface/_rpy_device.c0000644000175000017500000012375512271276146021204 0ustar laurentlaurent00000000000000/* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * Copyright (C) 2008-2012 Laurent Gautier * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ #include #include #include #include #include #include #include "_rinterface.h" #include "rpy_device.h" PyDoc_STRVAR(module_doc, "Graphical devices for R. They can be interactive " "(e.g., the X11 window that open during an interactive R session)," " or not (e.g., PDF or PNG files)."); static inline void rpy_printandclear_error(void) { PyObject* pythonerror = PyErr_Occurred(); if (pythonerror != NULL) { /* All R actions should be stopped since the Python callback failed, and the Python exception raised up.*/ /* FIXME: Print the exception in the meanwhile */ PyErr_Print(); PyErr_Clear(); } } SEXP rpy_devoff(SEXP devnum, SEXP rho) { SEXP c_R, call_R, res, fun_R; #ifdef RPY_DEBUG_GRDEV printf("rpy_devoff(): checking 'rho'.\n"); #endif if(!isEnvironment(rho)) { #ifdef RPY_DEBUG_GRDEV printf("rpy_devoff(): invalid 'rho'.\n"); #endif error("'rho' should be an environment\n"); } #ifdef RPY_DEBUG_GRDEV printf("rpy_devoff(): Looking for dev.off()...\n"); #endif PROTECT(fun_R = PyRinterface_FindFun(install("dev.off"), rho)); if (fun_R == R_UnboundValue) printf("dev.off() could not be found.\n"); #ifdef RPY_DEBUG_GRDEV printf("rpy_devoff(): found.\n"); #endif /* incantation to summon R */ PROTECT(c_R = call_R = allocList(2)); SET_TYPEOF(c_R, LANGSXP); SETCAR(c_R, fun_R); c_R = CDR(c_R); /* first argument is the device number to be closed */ SETCAR(c_R, devnum); SET_TAG(c_R, install("which")); c_R = CDR(c_R); int error = 0; #ifdef RPY_DEBUG_GRDEV printf("rpy_devoff(): R_tryEval()\n"); #endif PROTECT(res = R_tryEval(call_R, rho, &error)); #ifdef RPY_DEBUG_GRDEV printf("rpy_devoff(): unprotecting.\n"); #endif UNPROTECT(3); return res; } /* evaluate a call to a Python callback for the device */ static inline void rpy_GrDev_CallBack(pDevDesc dd, PyObject *name) { PyObject *result; /* Restore the Python handler */ /* FIXME */ /* PyOS_setsig(SIGINT, python_sighandler); */ PyObject *self = (PyObject *)dd->deviceSpecific; result = PyObject_CallMethodObjArgs(self, name, NULL); rpy_printandclear_error(); Py_XDECREF(result); } static PyObject *GrDev_close_name; int _GrDev_close(PyObject *self) { PyObject *res; PyObject *tp, *v, *tb; int closed = 1; int is_zombie; /* if _GrDev_close() is called from a destructor (quite likely because of R's GEkillDevice()), we need to resurrect the object as calling close() can invoke arbitrary code (see Python's own iobase.c) */ is_zombie = (Py_REFCNT(self) == 0); if (is_zombie) { ++Py_REFCNT(self); } PyErr_Fetch(&tp, &v, &tb); res = PyObject_GetAttrString(self, "closed"); /* if the attribute "closed" does not exist, ignore */ if (res == NULL) PyErr_Clear(); else { closed = PyObject_IsTrue(res); Py_DECREF(res); if (closed == -1) PyErr_Clear(); } if (closed == 0) { pDevDesc devdesc = ((PyGrDevObject *)self)->grdev; rpy_GrDev_CallBack(devdesc, GrDev_close_name); /* FIXME: Shouldn't the result be checked ? */ } PyErr_Restore(tp, v, tb); if (is_zombie) { if (--Py_REFCNT(self) != 0) { /* The object lives again. The following code is taken from slot_tp_del in typeobject.c. */ Py_ssize_t refcnt = Py_REFCNT(self); _Py_NewReference(self); Py_REFCNT(self) = refcnt; /* If Py_REF_DEBUG, _Py_NewReference bumped _Py_RefTotal, so * we need to undo that. */ _Py_DEC_REFTOTAL; /* If Py_TRACE_REFS, _Py_NewReference re-added self to the object * chain, so no more to do there. * If COUNT_ALLOCS, the original decref bumped tp_frees, and * _Py_NewReference bumped tp_allocs: both of those need to be * undone. */ #ifdef COUNT_ALLOCS --Py_TYPE(self)->tp_frees; --Py_TYPE(self)->tp_allocs; #endif return -1; } } return 0; } static void rpy_Close(pDevDesc dd) { printf("Closing device.\n"); /* this callback is special because it can be called from a code path going through a Python destructor for the device */ _GrDev_close(dd->deviceSpecific); } PyDoc_STRVAR(GrDev_close_doc, "Callback to implement: close the device." ""); static PyObject* GrDev_close(PyObject *self) { PyErr_Format(PyExc_NotImplementedError, "Device closing not implemented."); return NULL; Py_INCREF(Py_None); return Py_None; } static PyObject* GrDev_activate_name; static void rpy_Activate(pDevDesc dd) { rpy_GrDev_CallBack(dd, GrDev_activate_name); } PyDoc_STRVAR(GrDev_activate_doc, "Callback to implement: activation of the graphical device."); static PyObject* GrDev_activate(PyObject *self) { /* error("Not implemented."); */ PyErr_Format(PyExc_NotImplementedError, "Device activation not implemented."); /* printf("done.\n"); */ Py_INCREF(Py_None); return Py_None; } static PyObject* GrDev_deactivate_name; static void rpy_Deactivate(pDevDesc dd) { rpy_GrDev_CallBack(dd, GrDev_deactivate_name); } PyDoc_STRVAR(GrDev_deactivate_doc, "Callback to implement: deactivate the graphical device."); static PyObject* GrDev_deactivate(PyObject *self) { PyErr_Format(PyExc_NotImplementedError, "Device deactivation not implemented."); Py_INCREF(Py_None); return Py_None; } static PyObject* GrDev_size_name; static void rpy_Size(double *left, double *right, double *bottom, double *top, pDevDesc dd) { PyObject *result; /* Restore the Python handler */ /* FIXME */ /* PyOS_setsig(SIGINT, python_sighandler); */ printf("FIXME: size(left=%f, right=%f, bottom=%f, top=%f)\n", *left, *right, *bottom, *top); PyObject *self = (PyObject *)dd->deviceSpecific; //PyObject *lrbt = Py_BuildValue("(dddd)", *left, *right, *bottom, *top); //result = PyObject_CallMethodObjArgs(self, GrDev_size_name, // lrbt, NULL); result = PyObject_CallMethodObjArgs(self, GrDev_size_name, NULL, NULL); rpy_printandclear_error(); if (! PyTuple_Check(result) ) { PyErr_Format(PyExc_ValueError, "Callback 'size' should return a tuple."); rpy_printandclear_error(); } else if (PyTuple_Size(result) != 4) { PyErr_Format(PyExc_ValueError, "Callback 'size' should return a tuple of length 4."); rpy_printandclear_error(); } else { *left = PyFloat_AsDouble(PyTuple_GetItem(result, 0)); *right = PyFloat_AsDouble(PyTuple_GetItem(result, 1)); *bottom = PyFloat_AsDouble(PyTuple_GetItem(result, 2)); *top = PyFloat_AsDouble(PyTuple_GetItem(result, 3)); } //Py_DECREF(lrbt); Py_XDECREF(result); } PyDoc_STRVAR(GrDev_size_doc, "Callback to implement: set the size of the graphical device.\n" "The callback must return a tuple of 4 Python float (C double).\n" "These could be:\n" "left = 0\nright= \nbottom = \ntop=0\n" ); static PyObject* GrDev_size(PyObject *self, PyObject *args) { PyErr_Format(PyExc_NotImplementedError, "Device size not implemented.\n" "[ expected signature is ((left, right, bottom, top)) \n]" "[ should return a tuple of length 4]"); Py_INCREF(Py_None); return Py_None; } static PyObject* GrDev_newpage_name; static void rpy_NewPage(const pGEcontext gc, pDevDesc dd) { PyObject *result; /* Restore the Python handler */ /* FIXME */ /* PyOS_setsig(SIGINT, python_sighandler); */ /* FIXME give the callback access to gc */ PyObject *self = (PyObject *)dd->deviceSpecific; result = PyObject_CallMethodObjArgs(self, GrDev_newpage_name, NULL); rpy_printandclear_error(); Py_XDECREF(result); } PyDoc_STRVAR(GrDev_newpage_doc, "Callback to implement: create a new page for the graphical device.\n" "If the device can only handle one page, " "the callback will have to eventually terminate clean an existing page."); static PyObject* GrDev_newpage(PyObject *self, PyObject *args) { printf("FIXME: newpage.\n"); /* PyErr_Format(PyExc_NotImplementedError, "Not implemented."); */ Py_INCREF(Py_None); printf(" done.\n"); return Py_None; } static PyObject* GrDev_clip_name; static void rpy_Clip(double x0, double x1, double y0, double y1, pDevDesc dd) { PyObject *result; /* Restore the Python handler */ /* FIXME */ /* PyOS_setsig(SIGINT, python_sighandler); */ PyObject *self = (PyObject *)dd->deviceSpecific; /* FIXME optimize ? (may be an array ?) */ PyObject *py_x0 = PyFloat_FromDouble(x0); PyObject *py_x1 = PyFloat_FromDouble(x1); PyObject *py_y0 = PyFloat_FromDouble(y0); PyObject *py_y1 = PyFloat_FromDouble(y1); result = PyObject_CallMethodObjArgs(self, GrDev_clip_name, py_x0, py_x1, py_y0, py_y1, NULL); rpy_printandclear_error(); Py_DECREF(py_x0); Py_DECREF(py_x1); Py_DECREF(py_y0); Py_DECREF(py_y1); Py_XDECREF(result); } PyDoc_STRVAR(GrDev_clip_doc, "Callback to implement: clip the graphical device.\n" "The callback method will receive 4 arguments (Python floats) corresponding " "to the x0, x1, y0, y1 respectively."); static PyObject* GrDev_clip(PyObject *self, PyObject *args) { PyErr_Format(PyExc_NotImplementedError, "Device clip not implemented."); Py_INCREF(Py_None); return Py_None; } static PyObject* GrDev_strwidth_name; static double rpy_StrWidth(const char *str, const pGEcontext gc, pDevDesc dd) { PyObject *result; /* Restore the Python handler */ /* FIXME */ /* PyOS_setsig(SIGINT, python_sighandler); */ /* FIXME give the callback access to gc */ PyObject *self = (PyObject *)dd->deviceSpecific; #if (PY_VERSION_HEX < 0x03010000) PyObject *py_str = PyString_FromString(str); #else PyObject *py_str = PyUnicode_FromString(str); #endif result = PyObject_CallMethodObjArgs(self, GrDev_strwidth_name, py_str, NULL); rpy_printandclear_error(); /*FIXME: only one of the two error should be printed. */ if (!PyFloat_Check(result)) { PyErr_SetString(PyExc_TypeError, "The value returned by strwidth must be a float"); } rpy_printandclear_error(); double r_res = PyFloat_AsDouble(result); Py_DECREF(py_str); Py_DECREF(result); return r_res; } PyDoc_STRVAR(GrDev_strwidth_doc, "Callback to implement: strwidth(text) -> width\n\n" "Width (in pixels) of a text when represented on the graphical device.\n" "The callback will return a Python float (C double)."); static PyObject* GrDev_strwidth(PyObject *self, PyObject *args) { PyErr_Format(PyExc_NotImplementedError, "Device strwidth not implemented."); Py_INCREF(Py_None); return Py_None; } static PyObject* GrDev_text_name; static void rpy_Text(double x, double y, const char *str, double rot, double hadj, const pGEcontext gc, pDevDesc dd) { PyObject *result; /* Restore the Python handler */ /* FIXME */ /* PyOS_setsig(SIGINT, python_sighandler); */ PyObject *self = (PyObject *)dd->deviceSpecific; /* FIXME optimize ? */ PyObject *py_x = PyFloat_FromDouble(x); PyObject *py_y = PyFloat_FromDouble(y); #if (PY_VERSION_HEX < 0x03010000) PyObject *py_str = PyString_FromString(str); #else PyObject *py_str = PyUnicode_FromString(str); #endif PyObject *py_rot = PyFloat_FromDouble(rot); PyObject *py_hadj = PyFloat_FromDouble(hadj); /* FIXME pass gc ? */ result = PyObject_CallMethodObjArgs(self, GrDev_text_name, py_x, py_y, py_str, py_rot, py_hadj, NULL); rpy_printandclear_error(); Py_DECREF(py_x); Py_DECREF(py_y); Py_DECREF(py_str); Py_DECREF(py_rot); Py_DECREF(py_hadj); Py_XDECREF(result); } PyDoc_STRVAR(GrDev_text_doc, "Callback to implement: display text on the device.\n" "The callback will receive the parameters:\n" "x, y (position), string, rot (angle in degrees), hadj (some horizontal spacing parameter ?)"); static PyObject* GrDev_text(PyObject *self, PyObject *args) { PyErr_Format(PyExc_NotImplementedError, "Device text not implemented."); Py_INCREF(Py_None); return Py_None; } static PyObject* GrDev_rect_name; static void rpy_Rect(double x0, double x1, double y0, double y1, const pGEcontext gc, pDevDesc dd) { PyObject *result; /* Restore the Python handler */ /* FIXME */ /* PyOS_setsig(SIGINT, python_sighandler); */ PyObject *self = (PyObject *)dd->deviceSpecific; /* FIXME optimize ? */ PyObject *py_x0 = PyFloat_FromDouble(x0); PyObject *py_x1 = PyFloat_FromDouble(x1); PyObject *py_y0 = PyFloat_FromDouble(y0); PyObject *py_y1 = PyFloat_FromDouble(y1); /* FIXME pass gc ? */ result = PyObject_CallMethodObjArgs(self, GrDev_rect_name, py_x0, py_x1, py_y0, py_y1, NULL); rpy_printandclear_error(); Py_DECREF(py_x0); Py_DECREF(py_x1); Py_DECREF(py_y0); Py_DECREF(py_y1); Py_XDECREF(result); } PyDoc_STRVAR(GrDev_rect_doc, "Callback to implement: draw a rectangle on the graphical device.\n" "The callback will receive 4 parameters x0, x1, y0, y1."); static PyObject* GrDev_rect(PyObject *self, PyObject *args) { PyErr_Format(PyExc_NotImplementedError, "Device rect not implemented."); Py_INCREF(Py_None); return Py_None; } static PyObject* GrDev_circle_name; static void rpy_Circle(double x, double y, double r, const pGEcontext gc, pDevDesc dd) { PyObject *result; /* Restore the Python handler */ /* FIXME */ /* PyOS_setsig(SIGINT, python_sighandler); */ PyObject *self = (PyObject *)dd->deviceSpecific; /* FIXME optimize ? */ PyObject *py_x = PyFloat_FromDouble(x); PyObject *py_y = PyFloat_FromDouble(y); PyObject *py_r = PyFloat_FromDouble(r); /* FIXME pass gc ? */ result = PyObject_CallMethodObjArgs(self, GrDev_circle_name, py_x, py_y, py_r, NULL); rpy_printandclear_error(); Py_DECREF(py_x); Py_DECREF(py_y); Py_DECREF(py_r); Py_XDECREF(result); } PyDoc_STRVAR(GrDev_circle_doc, "Callback to implement: draw a circle on the graphical device.\n" "The callback will receive the parameters x, y, radius"); static PyObject* GrDev_circle(PyObject *self, PyObject *args) { PyErr_Format(PyExc_NotImplementedError, "Device circle not implemented."); Py_INCREF(Py_None); return Py_None; } static PyObject* GrDev_line_name; static void rpy_Line(double x1, double y1, double x2, double y2, const pGEcontext gc, pDevDesc dd) { PyObject *result; /* Restore the Python handler */ /* FIXME */ /* PyOS_setsig(SIGINT, python_sighandler); */ PyObject *self = (PyObject *)dd->deviceSpecific; /* FIXME optimize ? */ PyObject *py_x1 = PyFloat_FromDouble(x1); PyObject *py_y1 = PyFloat_FromDouble(y1); PyObject *py_x2 = PyFloat_FromDouble(x2); PyObject *py_y2 = PyFloat_FromDouble(y2); /* FIXME pass gc ? */ result = PyObject_CallMethodObjArgs(self, GrDev_line_name, py_x1, py_y1, py_x2, py_y2, NULL); rpy_printandclear_error(); Py_DECREF(py_x1); Py_DECREF(py_y1); Py_DECREF(py_x2); Py_DECREF(py_y2); Py_DECREF(result); } PyDoc_STRVAR(GrDev_line_doc, "Callback to implement: draw a line on the graphical device.\n" "The callback will receive the arguments x1, y1, x2, y2."); static PyObject* GrDev_line(PyObject *self, PyObject *args) { PyErr_Format(PyExc_NotImplementedError, "Device line not implemented.\n" "[expected signature is (x1, y1, x2, y2)]"); Py_INCREF(Py_None); return Py_None; } static PyObject* GrDev_polyline_name; static void rpy_PolyLine(int n, double *x, double *y, const pGEcontext gc, pDevDesc dd) { PyObject *result; /* Restore the Python handler */ /* FIXME */ /* PyOS_setsig(SIGINT, python_sighandler); */ PyObject *self = (PyObject *)dd->deviceSpecific; #ifdef RPY_DEBUG_GRDEV printf("FIXME: PolyLine.\n"); #endif /* FIXME optimize ? Yes ! MemoryViews.*/ PyObject *py_x = PyTuple_New((Py_ssize_t)n); PyObject *py_y = PyTuple_New((Py_ssize_t)n); int i; for (i = 0; i < n; i++) { PyTuple_SET_ITEM(py_x, (Py_ssize_t)i, PyFloat_FromDouble(x[i])); PyTuple_SET_ITEM(py_y, (Py_ssize_t)i, PyFloat_FromDouble(y[i])); } /* FIXME pass gc ? */ result = PyObject_CallMethodObjArgs(self, GrDev_polyline_name, py_x, py_y, NULL); rpy_printandclear_error(); Py_DECREF(py_x); Py_DECREF(py_y); Py_DECREF(result); } PyDoc_STRVAR(GrDev_polyline_doc, "Callback to implement: draw a polyline on the graphical device."); static PyObject* GrDev_polyline(PyObject *self, PyObject *args) { PyErr_Format(PyExc_NotImplementedError, "Device polyline not implemented."); Py_INCREF(Py_None); return Py_None; } static PyObject* GrDev_polygon_name; static void rpy_Polygon(int n, double *x, double *y, const pGEcontext gc, pDevDesc dd) { PyObject *result; /* Restore the Python handler */ /* FIXME */ /* PyOS_setsig(SIGINT, python_sighandler); */ PyObject *self = (PyObject *)dd->deviceSpecific; /* FIXME optimize ? */ #ifdef RPY_DEBUG_GRDEV printf("FIXME: Polygon.\n"); #endif PyObject *py_n = PyLong_FromLong(n); /* FIXME: optimize by moving py_x and py_y to Python buffers */ PyObject *py_x = PyTuple_New((Py_ssize_t)n); PyObject *py_y = PyTuple_New((Py_ssize_t)n); int i; for (i = 0; i < n; i++) { PyTuple_SET_ITEM(py_x, (Py_ssize_t)i, PyFloat_FromDouble(x[i])); PyTuple_SET_ITEM(py_y, (Py_ssize_t)i, PyFloat_FromDouble(y[i])); } /* FIXME pass gc ? */ result = PyObject_CallMethodObjArgs(self, GrDev_polygon_name, py_n, py_x, py_y, NULL); rpy_printandclear_error(); Py_DECREF(py_x); Py_DECREF(py_y); Py_DECREF(py_n); Py_DECREF(result); } PyDoc_STRVAR(GrDev_polygon_doc, "Callback to implement: draw a polygon on the graphical device."); static PyObject* GrDev_polygon(PyObject *self, PyObject *args) { PyErr_Format(PyExc_NotImplementedError, "Device polygon not implemented."); Py_INCREF(Py_None); return Py_None; } static PyObject* GrDev_locator_name; static Rboolean rpy_Locator(double *x, double *y, pDevDesc dd) { PyObject *result; /* Restore the Python handler */ /* FIXME */ /* PyOS_setsig(SIGINT, python_sighandler); */ PyObject *self = (PyObject *)dd->deviceSpecific; /* FIXME optimize ? */ #ifdef RPY_DEBUG_GRDEV printf("FIXME: Locator.\n"); #endif //PyObject *py_x = PyList_New(0); //PyObject *py_y = PyList_New(0); /* FIXME: pass gc ? */ /* FIXME: test !dd->dev->locator before proceed ? */ result = PyObject_CallMethodObjArgs(self, GrDev_locator_name, //py_x, py_y, NULL); rpy_printandclear_error(); if (! PyTuple_Check(result) ) { PyErr_Format(PyExc_ValueError, "Callback 'size' should return a tuple."); rpy_printandclear_error(); } else if (PyTuple_Size(result) != 2) { PyErr_Format(PyExc_ValueError, "Callback 'size' should return a tuple of length 2."); rpy_printandclear_error(); } else { x[0] = PyFloat_AsDouble(PyTuple_GET_ITEM(result, 0)); y[0] = PyFloat_AsDouble(PyTuple_GET_ITEM(result, 1)); //int i; //for (i = 0; i < n; i++) { //x[i] = PyFloat_AsDouble(PyList_GET_ITEM(py_x, (Py_ssize_t)i)); //y[i] = PyFloat_AsDouble(PyList_GET_ITEM(py_y, (Py_ssize_t)i)); //} } Rboolean res_r = TRUE; printf("FIXME: return TRUE or FALSE"); //Py_DECREF(py_x); //Py_DECREF(py_y); Py_DECREF(result); return res_r; } PyDoc_STRVAR(GrDev_locator_doc, "Callback to implement: locator on the graphical device."); static PyObject* GrDev_locator(PyObject *self, PyObject *args) { PyErr_Format(PyExc_NotImplementedError, "Device locator not implemented."); Py_INCREF(Py_None); return Py_None; } static PyObject* GrDev_mode_name; static void rpy_Mode(int mode, pDevDesc dd) { PyObject *result; /* Restore the Python handler */ /* FIXME */ /* PyOS_setsig(SIGINT, python_sighandler); */ PyObject *self = (PyObject *)dd->deviceSpecific; #if (PY_VERSION_HEX < 0x03010000) PyObject *py_mode = PyInt_FromLong((long)mode); #else PyObject *py_mode = PyLong_FromLong((long)mode); #endif result = PyObject_CallMethodObjArgs(self, GrDev_mode_name, py_mode, NULL); rpy_printandclear_error(); Py_DECREF(py_mode); Py_DECREF(result); } PyDoc_STRVAR(GrDev_mode_doc, "Callback to implement: mode of the graphical device."); static PyObject* GrDev_mode(PyObject *self) { PyErr_Format(PyExc_NotImplementedError, "Device mode not implemented."); Py_INCREF(Py_None); return Py_None; } static PyObject* GrDev_metricinfo_name; static void rpy_MetricInfo(int c, const pGEcontext gc, double* ascent, double* descent, double *width, pDevDesc dd) { PyObject *result; /* Restore the Python handler */ /* FIXME */ /* PyOS_setsig(SIGINT, python_sighandler); */ PyObject *self = (PyObject *)dd->deviceSpecific; /* FIXME optimize ? */ #ifdef RPY_DEBUG_GRDEV printf("FIXME: MetricInfo.\n"); #endif #if (PY_VERSION_HEX < 0x03010000) PyObject *py_c = PyInt_FromLong((long)c); #else PyObject *py_c = PyLong_FromLong((long)c); #endif //PyObject *py_ascent = PyFloat_FromDouble(*ascent); //PyObject *py_descent = PyFloat_FromDouble(*descent); //PyObject *py_width = PyFloat_FromDouble(*width); /* FIXME pass gc ? */ result = PyObject_CallMethodObjArgs(self, GrDev_metricinfo_name, py_c, //py_ascent, py_descent, py_width, NULL); rpy_printandclear_error(); if (! PyTuple_Check(result) ) { PyErr_Format(PyExc_ValueError, "Callback 'size' should return a tuple."); rpy_printandclear_error(); } else if (PyTuple_Size(result) != 3) { PyErr_Format(PyExc_ValueError, "Callback 'metricinfo' should return a tuple of length 3."); rpy_printandclear_error(); } else { *ascent = PyFloat_AsDouble(PyTuple_GetItem(result, 0)); *descent = PyFloat_AsDouble(PyTuple_GetItem(result, 1)); *width = PyFloat_AsDouble(PyTuple_GetItem(result, 2)); } Py_DECREF(py_c); //Py_DECREF(py_ascent); //Py_DECREF(py_descent); //Py_DECREF(py_width); Py_DECREF(result); } PyDoc_STRVAR(GrDev_metricinfo_doc, "Callback to implement: MetricInfo on the graphical device."); static PyObject* GrDev_metricinfo(PyObject *self, PyObject *args) { PyErr_Format(PyExc_NotImplementedError, "Device metricinfo not implemented."); Py_INCREF(Py_None); return Py_None; } static PyObject* GrDev_getevent_name; static SEXP rpy_GetEvent(SEXP rho, const char *prompt) { SEXP r_res = R_NilValue; PyObject *result; pGEDevDesc dd = GEcurrentDevice(); /* Restore the Python handler */ /* FIXME */ /* PyOS_setsig(SIGINT, python_sighandler); */ PyObject *self = (PyObject *)dd->dev->deviceSpecific; /* FIXME optimize ? */ #ifdef RPY_DEBUG_GRDEV printf("FIXME: MetricInfo.\n"); #endif #if (PY_VERSION_HEX < 0x03010000) PyObject *py_prompt = PyString_FromString(prompt); #else PyObject *py_prompt = PyUnicode_FromString(prompt); #endif /* FIXME pass gc ? */ result = PyObject_CallMethodObjArgs(self, GrDev_getevent_name, py_prompt, NULL); rpy_printandclear_error(); /* FIXME: check that the method only returns PySexp ? */ printf("FIXME: check that only PySexp returned.\n"); r_res = RPY_SEXP((PySexpObject *)result); /* FIXME: handle refcount and protection of the resulting r_res */ printf("FIXME: handle refcount and protection of the resulting r_res"); Py_DECREF(result); Py_DECREF(py_prompt); return r_res; } PyDoc_STRVAR(GrDev_getevent_doc, "Callback to implement: get event on the graphical device."); static PyObject* GrDev_getevent(PyObject *self, PyObject *args) { PyErr_Format(PyExc_NotImplementedError, "Device getevent not implemented."); Py_INCREF(Py_None); return Py_None; } void configureDevice(pDevDesc dd, PyObject *self) { /* setup structure */ dd->deviceSpecific = (void *) self; dd->close = rpy_Close; dd->activate = rpy_Activate; dd->deactivate = rpy_Deactivate; dd->size = rpy_Size; dd->newPage = rpy_NewPage; dd->clip = rpy_Clip; /* Next two are unused */ dd->strWidth = rpy_StrWidth; dd->text = rpy_Text; dd->rect = rpy_Rect; dd->circle = rpy_Circle; dd->line = rpy_Line; dd->polyline = rpy_PolyLine; dd->polygon = rpy_Polygon; dd->locator = rpy_Locator; dd->mode = rpy_Mode; dd->metricInfo = rpy_MetricInfo; dd->getEvent = rpy_GetEvent; /* FIXME: initialization from self.attribute */ dd->hasTextUTF8 = TRUE; /*PyObject_GetAttrString(self, ); */ dd->wantSymbolUTF8 = TRUE; /* FIXME: initialization from self.attribute */ dd->strWidthUTF8 = rpy_StrWidth; dd->textUTF8 = rpy_Text; dd->left = 0; /* FIXME: initialization from self.attribute */ dd->right = 100; /* FIXME: initialization from self.attribute */ dd->bottom = 100; /* FIXME: initialization from self.attribute */ dd->top = 0; /* FIXME: initialization from self.attribute */ /* starting parameters */ dd->startfont = 1; dd->startps = 12.0; /* ps * */ dd->startcol = R_RGB(0, 0, 0); dd->startfill = R_TRANWHITE; dd->startlty = LTY_SOLID; dd->startgamma = 1; /* dd->cra[0] = 0.9 * 12; */ /* dd->cra[1] = 1.2 * 12; */ /* character addressing offsets */ dd->xCharOffset = 0.4900; dd->yCharOffset = 0.3333; dd->yLineBias = 0.1; /* inches per raster unit */ dd->ipr[0] = 1; dd->ipr[1] = 1; /* device capabilities */ dd->canClip = FALSE; dd->canHAdj = 0; /* text adjustment 0, 1, or 2 */ dd->canChangeGamma = FALSE; /* FIXME: what is this ? */ dd->canGenMouseDown = TRUE; /* can the device generate mousedown events */ dd->canGenMouseMove = TRUE; /* can the device generate mousemove events */ dd->canGenMouseUp = TRUE; /* can the device generate mouseup events */ dd->canGenKeybd = TRUE; /* can the device generate keyboard events */ dd->displayListOn = TRUE; /* finish */ } static void GrDev_clear(PyGrDevObject *self) { /* FIXME */ printf("FIXME: Clearing GrDev.\n"); printf(" done.\n"); } static void GrDev_dealloc(PyGrDevObject *self) { #ifdef RPY_DEBUG_GRDEV printf("FIXME: Deallocating GrDev (device number %i).\n", RPY_DEV_NUM(self)); #endif pGEDevDesc dd = GEgetDevice(RPY_DEV_NUM(self)-1); /* Caution: GEkillDevice will call the method "close()" for the the device. */ /* (See GrDev_close for details) */ if (dd) GEkillDevice(dd); #ifdef RPY_DEBUG_GRDEV printf("GrDevDealloc: PyMem_Free()\n"); #endif printf("--> skipping PyMem_Free(((PyGrDevObject *)self)->grdev) \n"); //PyMem_Free(((PyGrDevObject *)self)->grdev); #if (PY_VERSION_HEX < 0x03010000) self->ob_type->tp_free((PyObject*)self); #else Py_TYPE(self)->tp_free((PyObject*)self); #endif #ifdef RPY_DEBUG_GRDEV printf(" done.\n"); #endif } static PyObject* GrDev_repr(PyObject *self) { pDevDesc devdesc = ((PyGrDevObject *)self)->grdev; #if (PY_VERSION_HEX < 0x03010000) return PyString_FromFormat("<%s - Python:\%p / R graphical device:\%p>", self->ob_type->tp_name, self, devdesc); #else return PyUnicode_FromFormat("<%s - Python:\%p / R graphical device:\%p>", Py_TYPE(self)->tp_name, self, devdesc); #endif } static PyMethodDef GrDev_methods[] = { {"close", (PyCFunction)GrDev_close, METH_NOARGS, GrDev_close_doc}, {"activate", (PyCFunction)GrDev_activate, METH_NOARGS, GrDev_activate_doc}, {"deactivate", (PyCFunction)GrDev_deactivate, METH_NOARGS, GrDev_deactivate_doc}, {"size", (PyCFunction)GrDev_size, METH_VARARGS, GrDev_size_doc}, {"newpage", (PyCFunction)GrDev_newpage, METH_VARARGS, GrDev_newpage_doc}, {"clip", (PyCFunction)GrDev_clip, METH_VARARGS, GrDev_clip_doc}, {"strwidth", (PyCFunction)GrDev_strwidth, METH_VARARGS, GrDev_strwidth_doc}, {"text", (PyCFunction)GrDev_text, METH_VARARGS, GrDev_text_doc}, {"rect", (PyCFunction)GrDev_rect, METH_VARARGS, GrDev_rect_doc}, {"circle", (PyCFunction)GrDev_circle, METH_VARARGS, GrDev_circle_doc}, {"line", (PyCFunction)GrDev_line, METH_VARARGS, GrDev_line_doc}, {"polyline", (PyCFunction)GrDev_polyline, METH_VARARGS, GrDev_polyline_doc}, {"polygon", (PyCFunction)GrDev_polygon, METH_VARARGS, GrDev_polygon_doc}, {"locator", (PyCFunction)GrDev_locator, METH_VARARGS, GrDev_locator_doc}, {"mode", (PyCFunction)GrDev_mode, METH_VARARGS, GrDev_mode_doc}, {"metricinfo", (PyCFunction)GrDev_metricinfo, METH_VARARGS, GrDev_metricinfo_doc}, {"getevent", (PyCFunction)GrDev_getevent, METH_VARARGS, GrDev_getevent_doc}, /* */ {NULL, NULL} /* sentinel */ }; RPY_GRDEV_BOOL_GETSET(hasTextUTF8, "UTF8 capabilities of the device.") RPY_GRDEV_BOOL_GETSET(wantSymbolUTF8, "UTF8 capabilities of the device.") PyDoc_STRVAR(GrDev_left_doc, "Left coordinate."); static PyObject* GrDev_left_get(PyObject *self) { PyObject *res; res = PyFloat_FromDouble(((PyGrDevObject *)self)->grdev->left); return res; } static int GrDev_left_set(PyObject *self, PyObject *value) { RPY_GRDEV_FLOAT_SET(self, value, left); } PyDoc_STRVAR(GrDev_right_doc, "Right coordinate."); static PyObject* GrDev_right_get(PyObject *self) { PyObject *res; res = PyFloat_FromDouble(((PyGrDevObject *)self)->grdev->right); return res; } static int GrDev_right_set(PyObject *self, PyObject *value) { RPY_GRDEV_FLOAT_SET(self, value, right); } PyDoc_STRVAR(GrDev_top_doc, "Top coordinate."); static PyObject* GrDev_top_get(PyObject *self) { PyObject *res; res = PyFloat_FromDouble(((PyGrDevObject *)self)->grdev->top); return res; } static int GrDev_top_set(PyObject *self, PyObject *value) { RPY_GRDEV_FLOAT_SET(self, value, top); } PyDoc_STRVAR(GrDev_bottom_doc, "Bottom coordinate."); static PyObject* GrDev_bottom_get(PyObject *self) { PyObject *res; res = PyFloat_FromDouble(((PyGrDevObject *)self)->grdev->bottom); return res; } static int GrDev_bottom_set(PyObject *self, PyObject *value) { RPY_GRDEV_FLOAT_SET(self, value, bottom); } RPY_GRDEV_BOOL_GETSET(canGenMouseDown, "Ability to generate mouse down events.") RPY_GRDEV_BOOL_GETSET(canGenMouseMove, "Ability to generate mouse move events.") RPY_GRDEV_BOOL_GETSET(canGenMouseUp, "Ability to generate mouse up events.") RPY_GRDEV_BOOL_GETSET(canGenKeybd, "Ability to generate keyboard events.") RPY_GRDEV_BOOL_GETSET(displayListOn, "Status of the display list.") PyDoc_STRVAR(GrDev_devnum_doc, "Device number."); static PyObject* GrDev_devnum_get(PyObject* self) { PyObject* res; if ( RPY_DEV_NUM(self) == 0) { Py_INCREF(Py_None); res = Py_None; } else { #if (PY_VERSION_HEX < 0x03010000) res = PyInt_FromLong((long)RPY_DEV_NUM(self)); #else res = PyLong_FromLong((long)RPY_DEV_NUM(self)); #endif } return res; } static PyObject * rpydev_closed_get(PyObject *self, void *context) { return PyBool_FromLong(PyObject_HasAttrString(self, "__GrDev_closed")); } static PyGetSetDef GrDev_getsets[] = { {"hasTextUTF8", (getter)GrDev_hasTextUTF8_get, (setter)GrDev_hasTextUTF8_set, GrDev_hasTextUTF8_doc}, {"wantSymbolUTF8", (getter)GrDev_wantSymbolUTF8_get, (setter)GrDev_wantSymbolUTF8_set, GrDev_wantSymbolUTF8_doc}, {"left", (getter)GrDev_left_get, (setter)GrDev_left_set, GrDev_left_doc}, {"right", (getter)GrDev_right_get, (setter)GrDev_right_set, GrDev_right_doc}, {"top", (getter)GrDev_top_get, (setter)GrDev_top_set, GrDev_top_doc}, {"bottom", (getter)GrDev_bottom_get, (setter)GrDev_bottom_set, GrDev_bottom_doc}, {"canGenMouseDown", (getter)GrDev_canGenMouseDown_get, (setter)GrDev_canGenMouseDown_set, GrDev_canGenMouseDown_doc}, {"canGenMouseMove", (getter)GrDev_canGenMouseMove_get, (setter)GrDev_canGenMouseMove_set, GrDev_canGenMouseMove_doc}, {"canGenMouseUp", (getter)GrDev_canGenMouseUp_get, (setter)GrDev_canGenMouseUp_set, GrDev_canGenMouseUp_doc}, {"canGenKeybd", (getter)GrDev_canGenKeybd_get, (setter)GrDev_canGenKeybd_set, GrDev_canGenKeybd_doc}, {"displayListOn", (getter)GrDev_displayListOn_get, (setter)GrDev_displayListOn_set, GrDev_displayListOn_doc}, /* */ {"devnum", (getter)GrDev_devnum_get, NULL, GrDev_devnum_doc}, {"closed", (getter)rpydev_closed_get, NULL, NULL}, /* */ {NULL, NULL, NULL, NULL} /* sentinel */ }; static PyObject* GrDev_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { #ifdef RPY_DEBUG_GRDEV printf("FIXME: New GrDev\n"); #endif assert(type != NULL && type->tp_alloc != NULL); if (!PyRinterface_IsInitialized()) { PyErr_Format(PyExc_RuntimeError, "R must be initialized before instances of GraphicalDevice can be created."); return NULL; } PyGrDevObject *self; self = (PyGrDevObject *)type->tp_alloc(type, 0); if (! self) { PyErr_NoMemory(); } self->grdev = (pDevDesc)PyMem_Malloc(1 * sizeof(DevDesc)); if (self->grdev == NULL) { PyErr_Format(PyExc_RuntimeError, "Could not allocate memory for an R device description."); return NULL; } #ifdef RPY_DEBUG_GRDEV printf(" done.\n"); #endif return(PyObject *)self; } static int GrDev_init(PyObject *self, PyObject *args, PyObject *kwds) { #ifdef RPY_DEBUG_GRDEV printf("FIXME: Initializing GrDev\n"); #endif if (!PyRinterface_IsInitialized()) { PyErr_Format(PyExc_RuntimeError, "R must be initialized before instances of GraphicalDevice can be created."); return -1; } if (R_CheckDeviceAvailableBool() != TRUE) { PyErr_Format(PyExc_RuntimeError, "Too many open R devices."); return -1; } pDevDesc dev = ((PyGrDevObject *)self)->grdev; configureDevice(dev, self); pGEDevDesc gdd = GEcreateDevDesc(dev); #if (PY_VERSION_HEX < 0x03010000) GEaddDevice2(gdd, self->ob_type->tp_name); #else GEaddDevice2(gdd, Py_TYPE(self)->tp_name); #endif GEinitDisplayList(gdd); /* FIXME: protect device number ? */ /* allocate memory for the pDevDesc structure ? */ /* pDevDesc grdev = malloc(); */ /* FIXME: handle allocation error */ /* self->grdev = grdev; */ return 0; } /* * Generic graphical device. */ PyDoc_STRVAR(GrDev_doc, "Python-defined graphical device for R."); static PyTypeObject GrDev_Type = { /* The ob_type field must be initialized in the module init function * to be portable to Windows without using C++. */ #if (PY_VERSION_HEX < 0x03010000) PyObject_HEAD_INIT(NULL) 0, /*ob_size*/ #else PyVarObject_HEAD_INIT(NULL, 0) #endif "rpy2.rinterface.GraphicalDevice", /*tp_name*/ sizeof(PyGrDevObject), /*tp_basicsize*/ 0, /*tp_itemsize*/ /* methods */ (destructor)GrDev_dealloc, /*tp_dealloc*/ 0, /*tp_print*/ 0, /*tp_getattr*/ 0, /*tp_setattr*/ #if (PY_VERSION_HEX < 0x03010000) 0, /*tp_compare*/ #else 0, /*tp_reserved*/ #endif GrDev_repr, /*tp_repr*/ 0, /*tp_as_number*/ 0, /*tp_as_sequence*/ 0, /*tp_as_mapping*/ 0, /*tp_hash*/ 0, /*tp_call*/ 0, /*tp_str*/ 0, /*tp_getattro*/ 0, /*tp_setattro*/ 0, /*tp_as_buffer*/ Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /*tp_flags*/ GrDev_doc, /*tp_doc*/ 0, /*tp_traverse*/ 0,/*(inquiry)Sexp_clear, tp_clear*/ 0, /*tp_richcompare*/ 0, /*tp_weaklistoffset*/ 0, /*tp_iter*/ 0, /*tp_iternext*/ GrDev_methods, /*tp_methods*/ 0, /*tp_members*/ GrDev_getsets, /*tp_getset*/ 0, /*tp_base*/ 0, /*tp_dict*/ 0, /*tp_descr_get*/ 0, /*tp_descr_set*/ 0, /*tp_dictoffset*/ (initproc)GrDev_init, /*tp_init*/ 0, /*tp_alloc*/ GrDev_new, /*tp_new*/ 0, /*tp_free*/ 0, /*tp_is_gc*/ #if (PY_VERSION_HEX < 0x03010000) #else 0, /*tp_bases*/ 0, /*tp_mro*/ 0, /*tp_cache*/ 0, /*tp_subclasses*/ 0 /*tp_weaklist*/ #endif }; /* Additional methods for RpyDevice */ static PyMethodDef rpydevice_methods[] = { {NULL, NULL} /* sentinel */ }; #ifndef PyMODINIT_FUNC /* declarations for DLL import/export */ #define PyMODINIT_FUNC void #endif #if (PY_VERSION_HEX < 0x03010000) #else static struct PyModuleDef rpydevicemodule = { PyModuleDef_HEAD_INIT, "_rpy_device", /* name of module */ module_doc, /* module documentation, may be NULL */ -1, /* size of per-interpreter state of the module */ NULL, NULL, NULL, NULL, NULL }; #endif PyMODINIT_FUNC #if (PY_VERSION_HEX < 0x03010000) init_rpy_device(void) #else PyInit__rpy_device(void) #endif { #if (PY_VERSION_HEX < 0x03010000) GrDev_close_name = PyString_FromString("close"); GrDev_activate_name = PyString_FromString("activate"); GrDev_deactivate_name = PyString_FromString("deactivate"); GrDev_size_name = PyString_FromString("size"); GrDev_newpage_name = PyString_FromString("newpage"); GrDev_clip_name = PyString_FromString("clip"); GrDev_strwidth_name = PyString_FromString("strwidth"); GrDev_text_name = PyString_FromString("text"); GrDev_rect_name = PyString_FromString("rect"); GrDev_circle_name = PyString_FromString("circle"); GrDev_line_name = PyString_FromString("line"); GrDev_polyline_name = PyString_FromString("polyline"); GrDev_polygon_name = PyString_FromString("polygon"); GrDev_locator_name = PyString_FromString("locator"); GrDev_mode_name = PyString_FromString("mode"); GrDev_metricinfo_name = PyString_FromString("metricinfo"); GrDev_getevent_name = PyString_FromString("getevent"); #else GrDev_close_name = PyUnicode_FromString("close"); GrDev_activate_name = PyUnicode_FromString("activate"); GrDev_deactivate_name = PyUnicode_FromString("deactivate"); GrDev_size_name = PyUnicode_FromString("size"); GrDev_newpage_name = PyUnicode_FromString("newpage"); GrDev_clip_name = PyUnicode_FromString("clip"); GrDev_strwidth_name = PyUnicode_FromString("strwidth"); GrDev_text_name = PyUnicode_FromString("text"); GrDev_rect_name = PyUnicode_FromString("rect"); GrDev_circle_name = PyUnicode_FromString("circle"); GrDev_line_name = PyUnicode_FromString("line"); GrDev_polyline_name = PyUnicode_FromString("polyline"); GrDev_polygon_name = PyUnicode_FromString("polygon"); GrDev_locator_name = PyUnicode_FromString("locator"); GrDev_mode_name = PyUnicode_FromString("mode"); GrDev_metricinfo_name = PyUnicode_FromString("metricinfo"); GrDev_getevent_name = PyUnicode_FromString("getevent"); #endif if (PyType_Ready(&GrDev_Type) < 0) { #if (PY_VERSION_HEX < 0x03010000) return; #else return NULL; #endif } PyObject *m, *d; #if (PY_VERSION_HEX < 0x03010000) m = Py_InitModule3("_rpy_device", rpydevice_methods, module_doc); #else m = PyModule_Create(&rpydevicemodule); #endif if (m == NULL) { #if (PY_VERSION_HEX < 0x03010000) return; #else return NULL; #endif } if (import_rinterface() < 0) #if (PY_VERSION_HEX < 0x03010000) return; #else return NULL; #endif d = PyModule_GetDict(m); PyModule_AddObject(m, "GraphicalDevice", (PyObject *)&GrDev_Type); #if (PY_VERSION_HEX < 0x03010000) #else return m; #endif } rpy2-2.3.9/rpy/rinterface/rexternalptr.c0000644000175000017500000002004112271276146021426 0ustar laurentlaurent00000000000000/* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * Copyright (C) 2008-2012 Laurent Gautier * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ /* * As usual with rpy2, we have a Python objects that exposes an R object. * In this file the type is ExtPtrSexp and the R object is an * "external pointer" object that points to a * Python object. This allows us to pass around a Python object within * the R side of rpy2. * * */ /* Finalizer for R external pointers that are arbitrary Python objects */ static void R_PyObject_decref(SEXP s) { PyObject* pyo = (PyObject*)R_ExternalPtrAddr(s); if (pyo) { Py_DECREF(pyo); R_ClearExternalPtr(s); } } PyDoc_STRVAR(ExtPtrSexp_Type_doc, "R object that is an 'external pointer'," " a pointer to a data structure implemented at the C level.\n" "SexpExtPtr(extref, tag = None, protected = None)"); /* PyDoc_STRVAR(ExtPtrSexp___init___doc, */ /* "Construct an external pointer. " */ /* ); */ static int ExtPtrSexp_init(PySexpObject *self, PyObject *args, PyObject *kwds) { #ifdef RPY_VERBOSE printf("Python:%p / R:%p - ExtPtrSexp initializing...\n", self, RPY_SEXP((PySexpObject *)self)); #endif if (! RPY_SEXP(self)) { PyErr_Format(PyExc_ValueError, "NULL SEXP."); return -1; } PyObject *pyextptr = Py_None; PyObject *pytag = Py_None; PyObject *pyprotected = Py_None; static char *kwlist[] = {"extptr", "tag", "protected", NULL}; if (! PyArg_ParseTupleAndKeywords(args, kwds, "O|O!O!", kwlist, &pyextptr, &Sexp_Type, &pytag, &Sexp_Type, &pyprotected)) { return -1; } if (rpy_has_status(RPY_R_BUSY)) { PyErr_Format(PyExc_RuntimeError, "Concurrent access to R is not allowed."); return -1; } embeddedR_setlock(); /*FIXME: twist here - MakeExternalPtr will "preserve" the tag */ /* but the tag is already preserved (when exposed as a Python object) */ /* R_ReleaseObject(pytag->sObj->sexp); */ SEXP rtag, rprotected, rres; if (pytag == Py_None) { rtag = R_NilValue; } else { rtag = RPY_SEXP((PySexpObject *)pytag); } if (pyprotected == Py_None) { rprotected = R_NilValue; } else { rprotected = RPY_SEXP((PySexpObject *)pyprotected); } /* FIXME: is the INCREF needed ? */ Py_INCREF(pyextptr); rres = R_MakeExternalPtr(pyextptr, rtag, rprotected); PROTECT(rres); R_RegisterCFinalizerEx(rres, (R_CFinalizer_t)R_PyObject_decref, TRUE); UNPROTECT(1); if (Rpy_ReplaceSexp((PySexpObject *)self, rres) == -1) { embeddedR_freelock(); return -1; } #ifdef RPY_VERBOSE printf("done.\n"); #endif embeddedR_freelock(); return 0; } PyDoc_STRVAR(ExtPtrSexp___address___doc, "The C handle to external data as a PyCObject." ); static PyObject* ExtPtrSexp_address(PySexpObject *self) { if (! RPY_SEXP(self)) { PyErr_Format(PyExc_ValueError, "NULL SEXP."); return NULL; } embeddedR_setlock(); #if (PY_VERSION_HEX < 0x02070000) PyObject *res = PyCObject_FromVoidPtr(R_ExternalPtrAddr(self->sObj->sexp), NULL); #else PyObject *res = PyCapsule_New(R_ExternalPtrAddr(self->sObj->sexp), "rpy2.rinterface._C_API_SEXP_", NULL); #endif embeddedR_freelock(); return res; } PyDoc_STRVAR(ExtPtrSexp___tag___doc, "The R tag associated with the external pointer" ); static PySexpObject* ExtPtrSexp_tag(PySexpObject *self) { if (! RPY_SEXP(self)) { PyErr_Format(PyExc_ValueError, "NULL SEXP."); return NULL; } embeddedR_setlock(); SEXP rtag = R_ExternalPtrTag(self->sObj->sexp); PySexpObject *res = newPySexpObject(rtag); embeddedR_freelock(); return res; } PyDoc_STRVAR(ExtPtrSexp___protected___doc, "The R 'protected' object associated with the external pointer" ); static PySexpObject* ExtPtrSexp_protected(PySexpObject *self) { if (! RPY_SEXP(self)) { PyErr_Format(PyExc_ValueError, "NULL SEXP."); return NULL; } embeddedR_setlock(); SEXP rtag = R_ExternalPtrProtected(self->sObj->sexp); PySexpObject *res = newPySexpObject(rtag); embeddedR_freelock(); return res; } static PyGetSetDef ExtPtrSexp_getsets[] = { {"__address__", (getter)ExtPtrSexp_address, (setter)0, ExtPtrSexp___address___doc}, {"__tag__", (getter)ExtPtrSexp_tag, (setter)0, ExtPtrSexp___tag___doc}, {"__protected__", (getter)ExtPtrSexp_protected, (setter)0, ExtPtrSexp___protected___doc}, {NULL, NULL, NULL, NULL} /* sentinel */ }; static PyTypeObject ExtPtrSexp_Type = { /* The ob_type field must be initialized in the module init function * to be portable to Windows without using C++. */ #if (PY_VERSION_HEX < 0x03010000) PyObject_HEAD_INIT(NULL) 0, /*ob_size*/ #else PyVarObject_HEAD_INIT(NULL, 0) #endif "rpy2.rinterface.SexpExtPtr", /*tp_name*/ sizeof(PySexpObject), /*tp_basicsize*/ 0, /*tp_itemsize*/ /* methods */ 0, /*tp_dealloc*/ 0, /*tp_print*/ 0, /*tp_getattr*/ 0, /*tp_setattr*/ 0, /*tp_compare*/ 0, /*tp_repr*/ 0, /*tp_as_number*/ 0, /*tp_as_sequence*/ 0, /*tp_as_mapping*/ 0, /*tp_hash*/ 0, /*tp_call*/ 0, /*tp_str*/ 0, /*tp_getattro*/ 0, /*tp_setattro*/ 0, /*tp_as_buffer*/ Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /*tp_flags*/ ExtPtrSexp_Type_doc, /*tp_doc*/ 0, /*tp_traverse*/ 0, /*tp_clear*/ 0, /*tp_richcompare*/ 0, /*tp_weaklistoffset*/ 0, /*tp_iter*/ 0, /*tp_iternext*/ 0, /*tp_methods*/ 0, /*tp_members*/ ExtPtrSexp_getsets, /*tp_getset*/ &Sexp_Type, /*tp_base*/ 0, /*tp_dict*/ 0, /*tp_descr_get*/ 0, /*tp_descr_set*/ 0, /*tp_dictoffset*/ (initproc)ExtPtrSexp_init, /*tp_init*/ 0, /*tp_alloc*/ /*FIXME: add new method */ 0, /*tp_new*/ 0, /*tp_free*/ 0 /*tp_is_gc*/ }; rpy2-2.3.9/rpy/rinterface/null_value.h0000644000175000017500000000035112271276146021051 0ustar laurentlaurent00000000000000#ifndef _RPY_PRIVATE_NULLVALUE_H_ #define _RPY_PRIVATE_NULLVALUE_H_ #ifndef _RPY_RINTERFACE_MODULE_ #error null_value.h should not be included #endif static PyTypeObject RNULL_Type; static PyTypeObject UnboundValue_Type; #endif rpy2-2.3.9/rpy/rinterface/embeddedr.h0000644000175000017500000000143012271276146020615 0ustar laurentlaurent00000000000000#ifndef _RPY_PRIVATE_EMBEDDEDR_H_ #define _RPY_PRIVATE_EMBEDDEDR_H_ #include extern const unsigned int const RPY_R_INITIALIZED; extern const unsigned int const RPY_R_BUSY; /* Representation of R objects (instances) as instances in Python. */ static PyObject* Rpy_R_Precious; static void embeddedR_setlock(void); static void embeddedR_freelock(void); static unsigned int rpy_has_status(unsigned int); static void SexpObject_clear(SexpObject *sexpobj); static void SexpObject_CObject_destroy(PyObject *rpycapsule); static unsigned int embeddedR_status; static SexpObject* Rpy_PreserveObject(SEXP object); static SexpObject* _Rpy_PreserveObject(SEXP object); static int Rpy_ReleaseObject(SEXP object); static inline int Rpy_ReplaceSexp(PySexpObject *pso, SEXP rObj); #endif rpy2-2.3.9/rpy/rinterface/buffer.c0000644000175000017500000001554612271276146020163 0ustar laurentlaurent00000000000000/* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * Copyright (C) 2008-2012 Laurent Gautier * * Portions created by Alexander Belopolsky are * Copyright (C) 2006 Alexander Belopolsky. * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ #include #include #include "_rinterface.h" #include "buffer.h" static int sexp_rank(SEXP sexp) { /* Return the number of dimensions for the buffer * (e.g., a vector will return 1, a matrix 2, ...) */ SEXP dim = getAttrib(sexp, R_DimSymbol); if (dim == R_NilValue) return 1; return GET_LENGTH(dim); } static void sexp_shape(SEXP sexp, Py_intptr_t *shape, int nd) { /* Set the buffer 'shape', that is a vector of Py_intptr_t * containing the size of each dimension (see sexp_rank). */ int i; SEXP dim = getAttrib(sexp, R_DimSymbol); if (dim == R_NilValue) shape[0] = LENGTH(sexp); else for (i = 0; i < nd; i++) { shape[i] = INTEGER(dim)[i]; } } static void sexp_strides(SEXP sexp, Py_intptr_t *strides, Py_ssize_t itemsize, Py_intptr_t *shape, int nd) { /* Set the buffer 'strides', that is a vector or Py_intptr_t * containing the offset (in bytes) when progressing along * each dimension. */ int i; strides[0] = itemsize; for (i = 1; i < nd; i++) { strides[i] = shape[i-1] * strides[i-1]; } } #if PY_VERSION_HEX >= 0x02060000 static int VectorSexp_getbuffer(PyObject *obj, Py_buffer *view, int flags) { if (view == NULL) { return 0; } if ((flags & PyBUF_F_CONTIGUOUS) == PyBUF_F_CONTIGUOUS) { PyErr_SetString(PyExc_ValueError, "Only FORTRAN-style contiguous arrays allowed."); return -1; } view->obj = obj; if (obj) { Py_INCREF(obj); } view->readonly = 0; PySexpObject *self = (PySexpObject *)obj; SEXP sexp = RPY_SEXP(self); switch (TYPEOF(sexp)) { case REALSXP: view->buf = NUMERIC_POINTER(sexp); view->len = GET_LENGTH(sexp) * sizeof(double); view->itemsize = sizeof(double); view->format = "d"; break; case INTSXP: view->buf = INTEGER_POINTER(sexp); view->len = GET_LENGTH(sexp) * sizeof(int); view->itemsize = sizeof(int); view->format = "i"; break; case LGLSXP: view->buf = LOGICAL_POINTER(sexp); view->len = GET_LENGTH(sexp) * sizeof(int); view->itemsize = sizeof(int); view->format = "i"; break; case CPLXSXP: view->buf = COMPLEX_POINTER(sexp); view->len = GET_LENGTH(sexp) * sizeof(Rcomplex); view->itemsize = sizeof(Rcomplex); view->format = "B"; /* FIXME: correct format for complex ? */ break; case RAWSXP: view->buf = RAW_POINTER(sexp); view->len = GET_LENGTH(sexp); view->itemsize = 1; view->format = "B"; break; default: PyErr_Format(PyExc_ValueError, "Buffer for this type not yet supported."); return -1; } view->ndim = sexp_rank(sexp); view->shape = NULL; if ((flags & PyBUF_ND) == PyBUF_ND) { view->shape = (Py_intptr_t*)PyMem_Malloc(sizeof(Py_intptr_t) * view->ndim); sexp_shape(sexp, view->shape, view->ndim); } view->strides = NULL; if ((flags & PyBUF_STRIDES) == PyBUF_STRIDES) { view->strides = (Py_intptr_t*)PyMem_Malloc(sizeof(Py_intptr_t) * view->ndim); sexp_strides(sexp, view->strides, view->itemsize, view->shape, view->ndim); } /* view->suboffsets = (Py_intptr_t*)PyMem_Malloc(sizeof(Py_intptr_t) * view->ndim); */ /* int i; */ /* for (i = 0; i < view->ndim; i++) { */ /* view->suboffsets[i] = 0; */ /* } */ view->suboffsets = NULL; view->internal = NULL; return 0; } #endif #if (PY_VERSION_HEX < 0x03010000) static Py_ssize_t VectorSexp_getsegcount(PySexpObject *self, Py_ssize_t *lenp) { if (lenp == NULL) { return 1; } else { printf("--->\n"); return 0; } } static Py_ssize_t VectorSexp_getreadbuf(PySexpObject *self, Py_ssize_t segment, const void **ptrptr) { if (segment != 0) { PyErr_SetString(PyExc_ValueError, "accessing non-existing data segment"); return -1; } SEXP sexp = RPY_SEXP(self); Py_ssize_t len; switch (TYPEOF(sexp)) { case REALSXP: *ptrptr = (void *)NUMERIC_POINTER(sexp); len = GET_LENGTH(sexp) * sizeof(double); break; case INTSXP: *ptrptr = (void *)INTEGER_POINTER(sexp); len = GET_LENGTH(sexp) * sizeof(int); break; case LGLSXP: *ptrptr = (void *)LOGICAL_POINTER(sexp); len = GET_LENGTH(sexp) * sizeof(int); break; case CPLXSXP: *ptrptr = (void *)COMPLEX_POINTER(sexp); len = GET_LENGTH(sexp) * sizeof(Rcomplex); break; case RAWSXP: *ptrptr = (void *)RAW_POINTER(sexp); len = GET_LENGTH(sexp) * 1; break; default: PyErr_Format(PyExc_ValueError, "Buffer for this type not yet supported."); *ptrptr = NULL; return -1; } return len; } static Py_ssize_t VectorSexp_getwritebuf(PySexpObject *self, Py_ssize_t segment, const void **ptrptr) { printf("getwritebuf\n"); /*FIXME: introduce a "writeable" flag for SexpVector objects ? */ return VectorSexp_getreadbuf(self, segment, ptrptr); } static Py_ssize_t VectorSexp_getcharbuf(PySexpObject *self, Py_ssize_t segment, const char **ptrptr) { /*FIXME: introduce a "writeable" flag for SexpVector objects ? */ return VectorSexp_getreadbuf(self, segment, (const void **)ptrptr); } #endif static PyBufferProcs VectorSexp_as_buffer = { #if (PY_VERSION_HEX < 0x03010000) (readbufferproc)VectorSexp_getreadbuf, (writebufferproc)VectorSexp_getwritebuf, (segcountproc)VectorSexp_getsegcount, (charbufferproc)VectorSexp_getcharbuf, #endif #if PY_VERSION_HEX >= 0x02060000 (getbufferproc)VectorSexp_getbuffer, (releasebufferproc)0, #endif }; rpy2-2.3.9/rpy/rinterface/array.c0000644000175000017500000001475212271276146020026 0ustar laurentlaurent00000000000000/* A. Belopolsky's Array interface, modified as seen fit * to accommodate changes in numpy and in Python 3. * This will be phased out * as Numpy is now using memoryviews. * Laurent Gautier - 2010 */ /* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * Copyright (C) 2008-2012 Laurent Gautier * * Portions created by Alexander Belopolsky are * Copyright (C) 2006 Alexander Belopolsky. * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ #include #include #include #include "_rinterface.h" #define ARRAY_INTERFACE_VERSION 2 /* Array Interface flags */ #define NPY_CONTIGUOUS 0x0001 #define NPY_FORTRAN 0x0002 #define NPY_ENSURECOPY 0x0020 #define NPY_ALIGNED 0x0100 #define NPY_NOTSWAPPED 0x0200 #define NPY_WRITEABLE 0x0400 #define NPY_BEHAVED (NPY_ALIGNED | NPY_WRITEABLE) #define NPY_FARRAY (NPY_FORTRAN | NPY_BEHAVED) typedef struct { int version; int nd; char typekind; int itemsize; int flags; Py_intptr_t *shape; Py_intptr_t *strides; void *data; } PyArrayInterface; static char sexp_typekind(SEXP sexp) { /* Given an SEXP object, this returns the corresponding * Type in the numpy world. */ switch (TYPEOF(sexp)) { case REALSXP: return 'f'; case INTSXP: return 'i'; /* FIXME: handle strings ? */ /* case STRSXP: return 'S'; */ /* FIXME: handle 'O' (as R list ?) */ case CPLXSXP: return 'c'; /* It would be more logical (hah) to return 'b' here, but 1) R booleans are * full integer width, and Numpy for example can only handle 8-bit booleans, * not 32-bit, 2) R actually uses this width; NA_LOGICAL is the same as * NA_INTEGER, i.e. INT_MIN, i.e. 0x80000000. So this also lets us preserve * NA's: */ case LGLSXP: return 'i'; } return 0; } static void* sexp_typepointer(SEXP sexp) { switch (TYPEOF(sexp)) { case REALSXP: return (void *)NUMERIC_POINTER(sexp); case INTSXP: return (void *)INTEGER_POINTER(sexp); /* case STRSXP: return (void *)CHARACTER_POINTER(; */ case CPLXSXP: return (void *)COMPLEX_POINTER(sexp); case LGLSXP: return (void *)LOGICAL_POINTER(sexp); } return NULL; } static int sexp_itemsize(SEXP sexp) { switch (TYPEOF(sexp)) { case REALSXP: return sizeof(*REAL(sexp)); case INTSXP: return sizeof(*INTEGER(sexp)); case STRSXP: return sizeof(*CHAR(sexp)); case CPLXSXP: return sizeof(*COMPLEX(sexp)); case LGLSXP: return sizeof(*LOGICAL(sexp)); } return 0; } /* static int */ /* sexp_rank(SEXP sexp) */ /* { */ /* /\* Return the number of dimensions for the array */ /* * (e.g., a vector will return 1, a matrix 2, ...) */ /* *\/ */ /* SEXP dim = getAttrib(sexp, R_DimSymbol); */ /* if (dim == R_NilValue) */ /* return 1; */ /* return GET_LENGTH(dim); */ /* } */ /* static void */ /* sexp_shape(SEXP sexp, Py_intptr_t* shape, int nd) */ /* { */ /* /\* Set the numpy 'shape', that is a vector of Py_intptr_t */ /* * containing the size of each dimension (see sexp_rank). */ /* *\/ */ /* int i; */ /* SEXP dim = getAttrib(sexp, R_DimSymbol); */ /* if (dim == R_NilValue) */ /* shape[0] = LENGTH(sexp); */ /* else for (i = 0; i < nd; ++i) { */ /* shape[i] = INTEGER(dim)[i]; */ /* } */ /* } */ #if (PY_VERSION_HEX < 0x02070000) static void array_struct_free(void *ptr, void *arr) { PyArrayInterface *inter = (PyArrayInterface *)ptr; PyMem_Free(inter->shape); Py_DECREF((PyObject *)arr); PyMem_Free(inter); } #else static void array_struct_free(PyObject *rpynumpycapsule) { PyArrayInterface *inter = (PyArrayInterface *)(PyCapsule_GetPointer(rpynumpycapsule, NULL)); PyMem_Free(inter->shape); PyMem_Free(inter); } #endif static PyObject* array_struct_get(PySexpObject *self) { /* Get an array structure as understood by the numpy package from 'self' (a SexpVector). */ SEXP sexp = RPY_SEXP(self); if (!sexp) { PyErr_SetString(PyExc_AttributeError, "Null sexp"); return NULL; } char typekind = sexp_typekind(sexp); if (!typekind) { PyErr_SetString(PyExc_AttributeError, "Unsupported SEXP type"); return NULL; } /* allocate memory for the array description (this is what will be returned) */ PyArrayInterface *inter; inter = (PyArrayInterface *)PyMem_Malloc(sizeof(PyArrayInterface)); if (!inter) { return PyErr_NoMemory(); } inter->version = ARRAY_INTERFACE_VERSION; int nd = sexp_rank(sexp); inter->nd = nd; inter->typekind = typekind; inter->itemsize = sexp_itemsize(sexp); inter->flags = (NPY_FARRAY | NPY_NOTSWAPPED); inter->shape = (Py_intptr_t*)PyMem_Malloc(sizeof(Py_intptr_t)*nd); sexp_shape(sexp, inter->shape, nd); inter->strides = (Py_intptr_t*)PyMem_Malloc(sizeof(Py_intptr_t)*nd); sexp_strides(sexp, inter->strides, inter->itemsize, inter->shape, nd); inter->data = sexp_typepointer(sexp); if (inter->data == NULL) { PyErr_SetString(PyExc_RuntimeError, "Error while mapping type."); return NULL; } Py_INCREF(self); #if (PY_VERSION_HEX < 0x02070000) return PyCObject_FromVoidPtrAndDesc(inter, self, array_struct_free); #else return PyCapsule_New(inter, NULL, /* Numpy does not seem to give a name */ (PyCapsule_Destructor) array_struct_free); #endif } rpy2-2.3.9/rpy/rinterface/r_utils.h0000644000175000017500000000045412271276146020370 0ustar laurentlaurent00000000000000#ifndef RPY_RU_H #define RPY_RU_H #include #include SEXP rpy_serialize(SEXP object, SEXP rho); SEXP rpy_unserialize(SEXP connection, SEXP rho); SEXP rpy_list_attr(SEXP sexp); SEXP rpy_lang2str(SEXP sexp, SEXPTYPE t); #define __RPY_RSVN_SWITCH_VERSION__ 134914 #endif rpy2-2.3.9/rpy/rinterface/tests/0000755000175000017500000000000012271276522017673 5ustar laurentlaurent00000000000000rpy2-2.3.9/rpy/rinterface/tests/test_SexpVectorNumeric.py0000644000175000017500000000570412271276146024741 0ustar laurentlaurent00000000000000import unittest import itertools import rpy2.rinterface as rinterface try: import numpy has_numpy = True except ImportError: has_numpy = False def only_numpy(function): def res(self): if has_numpy: return function(self) else: return None rinterface.initr() def floatEqual(x, y, epsilon = 0.00000001): return abs(x - y) < epsilon def testArrayStructInt(self, numericModule): px = [1, -2, 3] x = rinterface.SexpVector(px, rinterface.INTSXP) nx = numericModule.asarray(x) self.assertEqual(nx.dtype.kind, 'i') for orig, new in itertools.izip(px, nx): self.assertEqual(orig, new) # change value in the Python array... makes it change in the R vector nx[1] = 12 self.assertEqual(x[1], 12) def testArrayStructDouble(self, numericModule): px = [1.0, -2.0, 3.0] x = rinterface.SexpVector(px, rinterface.REALSXP) nx = numericModule.asarray(x) self.assertEqual(nx.dtype.kind, 'f') for orig, new in itertools.izip(px, nx): self.assertEqual(orig, new) # change value in the Python array... makes it change in the R vector nx[1] = 333.2 self.assertEqual(x[1], 333.2) def testArrayStructComplex(self, numericModule): px = [1+2j, 2+5j, -1+0j] x = rinterface.SexpVector(px, rinterface.CPLXSXP) nx = numericModule.asarray(x) self.assertEqual(nx.dtype.kind, 'c') for orig, new in itertools.izip(px, nx): self.assertEqual(orig, new) def testArrayStructBoolean(self, numericModule): px = [True, False, True] x = rinterface.SexpVector(px, rinterface.LGLSXP) nx = numericModule.asarray(x) self.assertEqual('i', nx.dtype.kind) # not 'b', see comments in array.c for orig, new in itertools.izip(px, nx): self.assertEqual(orig, new) class SexpVectorNumericTestCase(unittest.TestCase): @only_numpy def testArrayStructNumpyInt(self): testArrayStructInt(self, numpy) @only_numpy def testArrayStructNumpyDouble(self): testArrayStructDouble(self, numpy) @only_numpy def testArrayStructNumpyComplex(self): testArrayStructComplex(self, numpy) @only_numpy def testArrayStructNumpyBoolean(self): testArrayStructBoolean(self, numpy) @only_numpy def testArrayShapeLen3(self): extract = rinterface.baseenv['['] rarray = rinterface.baseenv['array'](rinterface.IntSexpVector(range(30)), dim = rinterface.IntSexpVector([5,2,3])) npyarray = numpy.array(rarray) for i in range(5): for j in range(2): for k in range(3): self.assertEqual(extract(rarray, i+1, j+1, k+1)[0], npyarray[i, j, k]) def suite(): suite = unittest.TestLoader().loadTestsFromTestCase(SexpVectorNumericTestCase) return suite if __name__ == '__main__': tr = unittest.TextTestRunner(verbosity = 2) tr.run(suite()) rpy2-2.3.9/rpy/rinterface/tests/test_SexpExtPtr.py0000644000175000017500000000332512271276146023377 0ustar laurentlaurent00000000000000import unittest import rpy2.rinterface as rinterface rinterface.initr() class SexpExtPtrTestCase(unittest.TestCase): def setUp(self): self.console = rinterface.get_writeconsole() def noconsole(x): pass rinterface.set_writeconsole(noconsole) def tearDown(self): rinterface.set_writeconsole(self.console) def testNewDefault(self): pyobject = "ahaha" sexp_new = rinterface.SexpExtPtr(pyobject) # R External pointer are never copied self.assertEqual(rinterface.EXTPTRSXP, sexp_new.typeof) def testNewTag(self): pyobject = "ahaha" sexp_new = rinterface.SexpExtPtr(pyobject, tag = rinterface.StrSexpVector("b")) self.assertEqual(rinterface.EXTPTRSXP, sexp_new.typeof) self.assertEqual('b', sexp_new.__tag__[0]) def testNewInvalidTag(self): pyobject = "ahaha" self.assertRaises(TypeError, rinterface.SexpExtPtr, pyobject, tag = True) def testNewProtected(self): pyobject = "ahaha" sexp_new = rinterface.SexpExtPtr(pyobject, protected = rinterface.StrSexpVector("c")) self.assertEqual(rinterface.EXTPTRSXP, sexp_new.typeof) self.assertEqual('c', sexp_new.__protected__[0]) def testNewInvalidProtected(self): pyobject = "ahaha" self.assertRaises(TypeError, rinterface.SexpExtPtr, pyobject, protected = True) def suite(): suite = unittest.TestLoader().loadTestsFromTestCase(SexpExtPtrTestCase) return suite if __name__ == '__main__': tr = unittest.TextTestRunner(verbosity = 2) tr.run(suite()) rpy2-2.3.9/rpy/rinterface/tests/test_Sexp.py0000644000175000017500000001706412271276146022235 0ustar laurentlaurent00000000000000import unittest import copy import gc from rpy2 import rinterface rinterface.initr() class SexpTestCase(unittest.TestCase): def testNew_invalid(self): x = "a" self.assertRaises(ValueError, rinterface.Sexp, x) def testNew(self): sexp = rinterface.baseenv.get("letters") sexp_new = rinterface.Sexp(sexp) idem = rinterface.baseenv.get("identical") self.assertTrue(idem(sexp, sexp_new)[0]) sexp_new2 = rinterface.Sexp(sexp) self.assertTrue(idem(sexp, sexp_new2)[0]) del(sexp) self.assertTrue(idem(sexp_new, sexp_new2)[0]) def testTypeof_get(self): sexp = rinterface.baseenv.get("letters") self.assertEqual(sexp.typeof, rinterface.STRSXP) sexp = rinterface.baseenv.get("pi") self.assertEqual(sexp.typeof, rinterface.REALSXP) sexp = rinterface.baseenv.get("plot") self.assertEqual(sexp.typeof, rinterface.CLOSXP) def testList_attrs(self): x = rinterface.IntSexpVector((1,2,3)) self.assertEqual(0, len(x.list_attrs())) x.do_slot_assign('a', rinterface.IntSexpVector((33,))) self.assertEqual(1, len(x.list_attrs())) self.assertTrue('a' in x.list_attrs()) def testDo_slot(self): data_func = rinterface.baseenv.get("data") data_func(rinterface.SexpVector(["iris", ], rinterface.STRSXP)) sexp = rinterface.globalenv.get("iris") names = sexp.do_slot("names") iris_names = ("Sepal.Length", "Sepal.Width", "Petal.Length", "Petal.Width", "Species") self.assertEqual(len(iris_names), len(names)) for i, n in enumerate(iris_names): self.assertEqual(iris_names[i], names[i]) self.assertRaises(LookupError, sexp.do_slot, "foo") def testDo_slot_assign(self): data_func = rinterface.baseenv.get("data") data_func(rinterface.SexpVector(["iris", ], rinterface.STRSXP)) sexp = rinterface.globalenv.get("iris") iris_names = rinterface.StrSexpVector(['a', 'b', 'c', 'd', 'e']) sexp.do_slot_assign("names", iris_names) names = [x for x in sexp.do_slot("names")] self.assertEqual(['a', 'b', 'c', 'd', 'e'], names) def testDo_slot_assign_create(self): #test that assigning slots is also creating the slot x = rinterface.IntSexpVector([1,2,3]) x.do_slot_assign("foo", rinterface.StrSexpVector(["bar", ])) slot = x.do_slot("foo") self.assertEqual(1, len(slot)) self.assertEqual("bar", slot[0]) def testSexp_rsame_true(self): sexp_a = rinterface.baseenv.get("letters") sexp_b = rinterface.baseenv.get("letters") self.assertTrue(sexp_a.rsame(sexp_b)) def testSexp_rsame_false(self): sexp_a = rinterface.baseenv.get("letters") sexp_b = rinterface.baseenv.get("pi") self.assertFalse(sexp_a.rsame(sexp_b)) def testSexp_rsame_wrongType(self): sexp_a = rinterface.baseenv.get("letters") self.assertRaises(ValueError, sexp_a.rsame, 'foo') def testSexp_sexp(self): sexp = rinterface.IntSexpVector([1,2,3]) sexp_count = sexp.__sexp_refcount__ sexp_cobj = sexp.__sexp__ d = dict(rinterface._rinterface.protected_rids()) self.assertEqual(sexp_count, d[sexp.rid]) self.assertEqual(sexp_count, sexp.__sexp_refcount__) sexp2 = rinterface.IntSexpVector([4,5,6,7]) sexp2_rid = sexp2.rid sexp2.__sexp__ = sexp_cobj del(sexp) gc.collect() d = dict(rinterface._rinterface.protected_rids()) self.assertEqual(None, d.get(sexp2_rid)) def testSexp_rclass_get(self): sexp = rinterface.baseenv.get("letters") self.assertEqual(len(sexp.rclass), 1) self.assertEqual(sexp.rclass[0], "character") sexp = rinterface.baseenv.get("matrix")(0) self.assertEqual(len(sexp.rclass), 1) self.assertEqual(sexp.rclass[0], "matrix") def testSexp_rclass_set(self): sexp = rinterface.IntSexpVector([1,2,3]) sexp.rclass = rinterface.StrSexpVector(['foo']) self.assertEqual(len(sexp.rclass), 1) self.assertEqual(sexp.rclass[0], "foo") def testSexp_sexp_wrongtypeof(self): sexp = rinterface.IntSexpVector([1,2,3]) cobj = sexp.__sexp__ sexp = rinterface.StrSexpVector(['a', 'b']) self.assertEqual(2, len(sexp)) self.assertRaises(ValueError, sexp.__setattr__, '__sexp__', cobj) def testSexp_sexp_UniqueCapsule(self): sexp = rinterface.IntSexpVector([1,2,3]) sexp_count = sexp.__sexp_refcount__ cobj = sexp.__sexp__ # check that no increase in the refcount: the capsule is unique self.assertEqual(sexp_count, sexp.__sexp_refcount__) self.assertEqual(sexp_count, dict(rinterface.protected_rids())[sexp.rid]) del(cobj) gc.collect() self.assertEqual(sexp_count, sexp.__sexp_refcount__) self.assertEqual(sexp_count, dict(rinterface.protected_rids())[sexp.rid]) sexp_rid = sexp.rid del(sexp) gc.collect() self.assertFalse(sexp_rid in dict(rinterface.protected_rids())) def testSexp_sexp_set(self): x = rinterface.IntSexpVector([1,2,3]) x_s = x.__sexp__ x_rid = x.rid # The Python reference count of the capsule is incremented, # not the rpy2 reference count self.assertEqual(1, x.__sexp_refcount__) y = rinterface.IntSexpVector([4,5,6]) y_count = y.__sexp_refcount__ y_rid = y.rid self.assertEqual(1, y_count) self.assertTrue(x_rid in [elt[0] for elt in rinterface.protected_rids()]) x.__sexp__ = y.__sexp__ self.assertFalse(x_rid in [elt[0] for elt in rinterface.protected_rids()]) self.assertEqual(x.rid, y.rid) self.assertEqual(y_rid, y.rid) # now both x and y point to the same capsule, making # the rpy2 reference count to 2 self.assertEqual(x.__sexp_refcount__, y.__sexp_refcount__) self.assertEqual(y_count+1, x.__sexp_refcount__) del(x) self.assertTrue(y_rid in [elt[0] for elt in rinterface.protected_rids()]) del(y) self.assertFalse(y_rid in [elt[0] for elt in rinterface.protected_rids()]) def testSexp_deepcopy(self): sexp = rinterface.IntSexpVector([1,2,3]) self.assertEqual(0, sexp.named) rinterface.baseenv.get("identity")(sexp) self.assertEqual(2, sexp.named) sexp2 = sexp.__deepcopy__() self.assertEqual(sexp.typeof, sexp2.typeof) self.assertEqual(list(sexp), list(sexp2)) self.assertFalse(sexp.rsame(sexp2)) self.assertEqual(0, sexp2.named) # should be the same as above, but just in case: sexp3 = copy.deepcopy(sexp) self.assertEqual(sexp.typeof, sexp3.typeof) self.assertEqual(list(sexp), list(sexp3)) self.assertFalse(sexp.rsame(sexp3)) self.assertEqual(0, sexp3.named) def testRID(self): globalenv_id = rinterface.baseenv.get('.GlobalEnv').rid self.assertEqual(globalenv_id, rinterface.globalenv.rid) class RNULLTestCase(unittest.TestCase): def testRNULLType_nonzero(self): NULL = rinterface.RNULLType() self.assertFalse(NULL) def suite(): suite = unittest.TestLoader().loadTestsFromTestCase(SexpTestCase) suite.addTest(unittest.TestLoader().loadTestsFromTestCase(RNULLTestCase)) return suite if __name__ == '__main__': tr = unittest.TextTestRunner(verbosity = 2) tr.run(suite()) rpy2-2.3.9/rpy/rinterface/tests/test_Device.py0000644000175000017500000001004112271276146022501 0ustar laurentlaurent00000000000000import unittest import rpy2.rinterface as rinterface import rpy2.rinterface._rpy_device as rdevice import sys, os, subprocess, time, tempfile, signal import tempfile rinterface.initr() class AbstractDevice(rdevice.GraphicalDevice): def __init__(self): super(AbstractDevice, self).__init__() def activate(self): self._activated = True def deactivate(self): self._activated = False def close(self): pass class AbstractDeviceTestCase(unittest.TestCase): def setUp(self): self.gd = AbstractDevice() def tearDown(self): self.gd = None def _testGetSetBooleanAttr(self, name): gd = self.gd setattr(gd, name, True) self.assertTrue(getattr(gd, name)) setattr(gd, name, False) self.assertFalse(getattr(gd, name)) self.assertRaises(TypeError, setattr, gd, name, None) def _testGetSetDoubleAttr(self, name): gd = self.gd gd = rdevice.GraphicalDevice() setattr(gd, name, 100.0) self.assertTrue(getattr(gd, name)) setattr(gd, name, 0.0) self.assertFalse(getattr(gd, name)) self.assertRaises(TypeError, setattr, gd, name, None) def testHasTextUTF8(self): self._testGetSetBooleanAttr("hasTextUTF8") def testWantSymbolUTF8(self): self._testGetSetBooleanAttr("wantSymbolUTF8") def testLeft(self): self._testGetSetDoubleAttr("left") def testRight(self): self._testGetSetDoubleAttr("right") def testTop(self): self._testGetSetDoubleAttr("top") def testBottom(self): self._testGetSetDoubleAttr("bottom") def testCanGenMouseDown(self): self._testGetSetBooleanAttr("canGenMouseDown") def testCanGenMouseMove(self): self._testGetSetBooleanAttr("canGenMouseMove") def testCanGenKeybd(self): self._testGetSetBooleanAttr("canGenKeybd") def testDisplayListOn(self): self._testGetSetBooleanAttr("displayListOn") class CodeDevice(rdevice.GraphicalDevice): def __init__(self, filehandle): super(CodeDevice, self).__init__() self._activated = None self._open = True self._pagecount = 0 self._file = filehandle def activate(self): self._activated = True def deactivate(self): self._activated = False def close(self): self._activated = None self._open = False self._file.close() def size(self, lrbt): return (1,2,3,4) def newpage(self): self._file.write('#--- new page\n') self._pagecount = self._pagecount + 1 def line(self, x1, y1, x2, y2): self._file.write('line(%f, %f, %f, %f)' %(x1, y1, x2, y2)) def polyline(self, x, y): for xx, yy in zip(x, y): self._file.write('polyline(%f, %f)' %(xx, yy)) def clip(self, x1, y1, x2, y2): self._file.write('clip(%f, %f, %f, %f)' %(x1, y1, x2, y2)) class ConcreteDeviceTestCase(unittest.TestCase): def setUp(self): #f = tempfile.NamedTemporaryFile() f = file('/tmp/foo', mode='w') self.gd = CodeDevice(f) def tearDown(self): self.gd.close() def testActivate(self): self.assertTrue(self.gd._activated) #other_gd = ConcreteDeviceTestCase.CodeDevice() #self.assertFalse(self.gd._activated) def testClose(self): self.gd.close() self.assertFalse(self.gd._open) def testSize(self): size = self.gd.size() self.assertEqual(size, [1,2,3,4]) def testLine(self): res = rinterface.globalenv.get('plot.new')() res = rinterface.globalenv.get('lines')(rinterface.IntSexpVector((0, 0)), rinterface.IntSexpVector((1, 2))) def suite(): suite = unittest.TestLoader().loadTestsFromTestCase(AbstractDeviceTestCase) suite.addTest(unittest.TestLoader().loadTestsFromTestCase(ConcreteDeviceTestCase)) return suite if __name__ == '__main__': tr = unittest.TextTestRunner(verbosity = 2) tr.run(suite()) rpy2-2.3.9/rpy/rinterface/tests/test_SexpVector.py0000644000175000017500000005171712271276146023423 0ustar laurentlaurent00000000000000import unittest import sys, struct import rpy2.rinterface as ri ri.initr() def evalr(string): res = ri.parse(string) res = ri.baseenv["eval"](res) return res def floatEqual(x, y, epsilon = 0.00000001): return abs(x - y) < epsilon IS_PYTHON3 = sys.version_info[0] == 3 class WrapperSexpVectorTestCase(unittest.TestCase): def testInt(self): sexp = ri.IntSexpVector([1, ]) isInteger = ri.globalenv.get("is.integer") ok = isInteger(sexp)[0] self.assertTrue(ok) def testFloat(self): sexp = ri.IntSexpVector([1.0, ]) isNumeric = ri.globalenv.get("is.numeric") ok = isNumeric(sexp)[0] self.assertTrue(ok) def testStr(self): sexp = ri.StrSexpVector(["a", ]) isStr = ri.globalenv.get("is.character") ok = isStr(sexp)[0] self.assertTrue(ok) def testBool(self): sexp = ri.BoolSexpVector([True, ]) isBool = ri.globalenv.get("is.logical") ok = isBool(sexp)[0] self.assertTrue(ok) def testComplex(self): sexp = ri.ComplexSexpVector([1+2j, ]) is_complex = ri.globalenv.get("is.complex") ok = is_complex(sexp)[0] self.assertTrue(ok) def testByte(self): if IS_PYTHON3: seq = (b'a', b'b') else: seq = ('a', 'b') sexp = ri.ByteSexpVector(seq) is_raw = ri.globalenv.get("is.raw") ok = is_raw(sexp)[0] self.assertTrue(ok) class NAValuesTestCase(unittest.TestCase): def testRtoNAInteger(self): na_int = ri.NAIntegerType() r_na_int = evalr("NA_integer_")[0] self.assertTrue(r_na_int is na_int) def testNAIntegertoR(self): na_int = ri.NAIntegerType() self.assertEqual(True, ri.baseenv["is.na"](na_int)[0]) def testNAIntegerBinaryfunc(self): na_int = ri.NAIntegerType() self.assertTrue((na_int + 2) is na_int) def testNAIntegerInVector(self): na_int = ri.NAIntegerType() x = ri.IntSexpVector((1, na_int, 2)) self.assertTrue(x[1] is na_int) self.assertEqual(1, x[0]) self.assertEqual(2, x[2]) def testNAIntegerRepr(self): na_int = ri.NAIntegerType() self.assertEqual("NA_integer_", repr(na_int)) def testRtoNALogical(self): na_lgl = ri.NALogicalType() r_na_lgl = evalr("NA")[0] self.assertTrue(r_na_lgl is na_lgl) def testNALogicaltoR(self): na_lgl = ri.NALogicalType() self.assertEqual(True, ri.baseenv["is.na"](na_lgl)[0]) def testNALogicalInVector(self): na_bool = ri.NALogicalType() x = ri.BoolSexpVector((True, na_bool, False)) self.assertTrue(x[1] is na_bool) self.assertEqual(True, x[0]) self.assertEqual(False, x[2]) def testNAIntegerRepr(self): na_bool = ri.NALogicalType() self.assertEqual("NA", repr(na_bool)) def testRtoNAReal(self): na_real = ri.NARealType() r_na_real = evalr("NA_real_")[0] self.assertTrue(r_na_real is na_real) def testNARealtoR(self): na_real = ri.NARealType() self.assertEqual(True, ri.baseenv["is.na"](na_real)[0]) def testNARealBinaryfunc(self): na_real = ri.NARealType() self.assertTrue((na_real + 2.0) is na_real) def testNARealInVector(self): na_float = ri.NARealType() x = ri.FloatSexpVector((1.1, na_float, 2.2)) self.assertTrue(x[1] is na_float) self.assertEqual(1.1, x[0]) self.assertEqual(2.2, x[2]) def testNARealRepr(self): na_float = ri.NARealType() self.assertEqual("NA_real_", repr(na_float)) def testRtoNACharacter(self): na_character = ri.NACharacterType() r_na_character = evalr("NA_character_")[0] self.assertTrue(r_na_character is na_character) def testNACharactertoR(self): na_character = ri.NACharacterType() self.assertEqual(True, ri.baseenv["is.na"](ri.StrSexpVector((na_character, )))[0]) def testNACharacterInVector(self): na_str = ri.NACharacterType() x = ri.StrSexpVector(("ab", na_str, "cd")) self.assertTrue(x[1] is na_str) self.assertEqual("ab", x[0]) self.assertEqual("cd", x[2]) def testNACharacterRepr(self): na_str = ri.NACharacterType() self.assertEqual("NA_character_", repr(na_str)) class IntSexpVectorTestCase(unittest.TestCase): def testInitFromSeq(self): seq = range(3) v = ri.IntSexpVector(seq) self.assertEqual(3, len(v)) for x,y in zip(seq, v): self.assertEqual(x, y) def testInitFromIter(self): it = xrange(3) v = ri.IntSexpVector(it) self.assertEqual(3, len(v)) for x,y in zip(xrange(3), v): self.assertEqual(x, y) def testInitFromSeqInvalidInt(self): seq = (1, 'b', 3) self.assertRaises(ValueError, ri.IntSexpVector, seq) def testInitFromSeqInvalidOverflow(self): v = ri.IntSexpVector((ri.R_LEN_T_MAX-1, ri.R_LEN_T_MAX)) self.assertEqual(ri.R_LEN_T_MAX-1, v[0]) self.assertEqual(ri.R_LEN_T_MAX, v[1]) # check 64-bit architecture if struct.calcsize("P") >= 8: self.assertRaises(OverflowError, ri.IntSexpVector, (ri.R_LEN_T_MAX+1, )) class FloatSexpVectorTestCase(unittest.TestCase): def testInitFromSeq(self): seq = (1.0, 2.0, 3.0) v = ri.FloatSexpVector(seq) self.assertEqual(3, len(v)) for x,y in zip(seq, v): self.assertEqual(x, y) def testInitFromIter(self): it = xrange(10) v = ri.FloatSexpVector(it) self.assertEqual(10, len(v)) for x,y in zip(xrange(10), v): self.assertEqual(x, y) def testInitFromSeqInvalidFloat(self): seq = (1.0, 'b', 3.0) self.assertRaises(ValueError, ri.FloatSexpVector, seq) class ByteSexpVectorTestCase(unittest.TestCase): def testInitFromBytes(self): if IS_PYTHON3: seq = (b'a', b'b', b'c') else: seq = 'abc' v = ri.ByteSexpVector(seq) self.assertEqual(3, len(v)) for x,y in zip(seq, v): self.assertEqual(x, y) def testInitFromSeqOfBytes(self): if IS_PYTHON3: seq = (b'a', b'b', b'c') else: seq = ('a', 'b', 'c') v = ri.ByteSexpVector(seq) self.assertEqual(3, len(v)) for x,y in zip(seq, v): self.assertEqual(x, y) def testInitFromSeqInvalidByte(self): if IS_PYTHON3: seq = (b'a', 2, b'c') else: seq = ('a', 2, 'c') self.assertRaises(ValueError, ri.ByteSexpVector, seq) class SexpVectorTestCase(unittest.TestCase): def testMissinfType(self): self.assertRaises(ValueError, ri.SexpVector, [2, ]) def testDel(self): v = ri.IntSexpVector(range(10)) self.assertRaises(TypeError, v.__delitem__, 3) #FIXME: end and initializing again causes currently a lot a trouble... def testNewWithoutInit(self): if sys.version_info[0] == 2 and sys.version_info[1] < 6: self.assertTrue(False) # cannot be tested with Python < 2.6 return None import multiprocessing def foo(queue): import rpy2.rinterface as rinterface rinterface.endr(1) try: tmp = ri.SexpVector([1,2], ri.INTSXP) res = (False, None) except RuntimeError, re: res = (True, re) except Exception, e: res = (False, e) queue.put(res) q = multiprocessing.Queue() p = multiprocessing.Process(target = foo, args = (q,)) p.start() res = q.get() p.join() self.assertTrue(res[0]) def testNewBool(self): sexp = ri.SexpVector([True, ], ri.LGLSXP) isLogical = ri.globalenv.get("is.logical") ok = isLogical(sexp)[0] self.assertTrue(ok) self.assertTrue(sexp[0]) sexp = ri.SexpVector(["a", ], ri.LGLSXP) isLogical = ri.globalenv.get("is.logical") ok = isLogical(sexp)[0] self.assertTrue(ok) self.assertTrue(sexp[0]) def testNewInt(self): sexp = ri.SexpVector([1, ], ri.INTSXP) isInteger = ri.globalenv.get("is.integer") ok = isInteger(sexp)[0] self.assertTrue(ok) sexp = ri.SexpVector(["a", ], ri.INTSXP) isNA = ri.globalenv.get("is.na") ok = isNA(sexp)[0] self.assertTrue(ok) def testNewReal(self): sexp = ri.SexpVector([1.0, ], ri.REALSXP) isNumeric = ri.globalenv.get("is.numeric") ok = isNumeric(sexp)[0] self.assertTrue(ok) sexp = ri.SexpVector(["a", ], ri.REALSXP) isNA = ri.globalenv.get("is.na") ok = isNA(sexp)[0] self.assertTrue(ok) def testNewComplex(self): sexp = ri.SexpVector([1.0 + 1.0j, ], ri.CPLXSXP) isComplex = ri.globalenv.get("is.complex") ok = isComplex(sexp)[0] self.assertTrue(ok) def testNewString(self): sexp = ri.SexpVector(["abc", ], ri.STRSXP) isCharacter = ri.globalenv.get("is.character") ok = isCharacter(sexp)[0] self.assertTrue(ok) sexp = ri.SexpVector([1, ], ri.STRSXP) isCharacter = ri.globalenv.get("is.character") ok = isCharacter(sexp)[0] self.assertTrue(ok) def testNewUnicode(self): sexp = ri.SexpVector([u'abc', ], ri.STRSXP) isCharacter = ri.globalenv.get("is.character") ok = isCharacter(sexp)[0] self.assertTrue(ok) self.assertEqual('abc', sexp[0]) def testNewUnicodeSymbol(self): sexp = ri.SexpVector((u'\u21a7', ), ri.STRSXP) isCharacter = ri.globalenv.get("is.character") ok = isCharacter(sexp)[0] self.assertTrue(ok) self.assertEqual(u'\u21a7', sexp[0]) def testNewList(self): vec = ri.ListSexpVector([1,'b',3,'d',5]) ok = ri.baseenv["is.list"](vec)[0] self.assertTrue(ok) self.assertEqual(5, len(vec)) self.assertEqual(1, vec[0][0]) self.assertEqual('b', vec[1][0]) def testNewVector(self): sexp_char = ri.SexpVector(["abc", ], ri.STRSXP) sexp_int = ri.SexpVector([1, ], ri.INTSXP) sexp = ri.SexpVector([sexp_char, sexp_int], ri.VECSXP) isList = ri.globalenv.get("is.list") ok = isList(sexp)[0] self.assertTrue(ok) self.assertEqual(2, len(sexp)) def testNew_InvalidType_NotAType(self): self.assertRaises(ValueError, ri.SexpVector, [1, ], -1) self.assertRaises(ValueError, ri.SexpVector, [1, ], 250) def testNew_InvalidType_NotAVectorType(self): self.assertRaises(ValueError, ri.SexpVector, [1, ], ri.ENVSXP) def testNew_InvalidType_NotASequence(self): self.assertRaises(ValueError, ri.SexpVector, 1, ri.INTSXP) def testGetItem(self): letters_R = ri.globalenv.get("letters") self.assertTrue(isinstance(letters_R, ri.SexpVector)) letters = (('a', 0), ('b', 1), ('c', 2), ('x', 23), ('y', 24), ('z', 25)) for l, i in letters: self.assertTrue(letters_R[i] == l) Rlist = ri.globalenv.get("list") seq_R = ri.globalenv.get("seq") mySeq = seq_R(ri.SexpVector([0, ], ri.INTSXP), ri.SexpVector([10, ], ri.INTSXP)) myList = Rlist(s=mySeq, l=letters_R) idem = ri.globalenv.get("identical") self.assertTrue(idem(mySeq, myList[0])) self.assertTrue(idem(letters_R, myList[1])) letters_R = ri.globalenv.get("letters") self.assertEqual('z', letters_R[-1]) def testGetItemLang(self): formula = ri.baseenv.get('formula') f = formula(ri.StrSexpVector(['y ~ x', ])) y = f[0] self.assertEqual(ri.SYMSXP, y.typeof) def testGetItemExpression(self): expression = ri.baseenv.get('expression') e = expression(ri.StrSexpVector(['a', ]), ri.StrSexpVector(['b', ])) y = e[0] self.assertEqual(ri.STRSXP, y.typeof) def testGetItemPairList(self): pairlist = ri.baseenv.get('pairlist') pl = pairlist(a = ri.StrSexpVector([1, ])) y = pl[0] self.assertEqual(ri.LISTSXP, y.typeof) def testGetItemNegativeOutOfBound(self): letters_R = ri.globalenv.get("letters") self.assertRaises(IndexError, letters_R.__getitem__, -100) def testGetItemOutOfBound(self): myVec = ri.SexpVector([0, 1, 2, 3, 4, 5], ri.INTSXP) self.assertRaises(IndexError, myVec.__getitem__, 10) if (sys.maxint > ri.R_LEN_T_MAX): self.assertRaises(IndexError, myVec.__getitem__, ri.R_LEN_T_MAX+1) def testGetSliceFloat(self): vec = ri.FloatSexpVector([1.0,2.0,3.0]) vec = vec[0:2] self.assertEqual(2, len(vec)) self.assertEqual(1.0, vec[0]) self.assertEqual(2.0, vec[1]) def testGetSliceInt(self): vec = ri.IntSexpVector([1,2,3]) vec = vec[0:2] self.assertEqual(2, len(vec)) self.assertEqual(1, vec[0]) self.assertEqual(2, vec[1]) def testGetSliceIntNegative(self): vec = ri.IntSexpVector([1,2,3]) vec = vec[-2:-1] self.assertEqual(1, len(vec)) self.assertEqual(2, vec[0]) def testGetSliceMissingBoundary(self): vec = ri.IntSexpVector(range(10)) vec_slice = vec[:2] self.assertEqual(2, len(vec_slice)) self.assertEqual(0, vec_slice[0]) self.assertEqual(1, vec_slice[1]) vec_slice = vec[8:] self.assertEqual(2, len(vec_slice)) self.assertEqual(8, vec_slice[0]) self.assertEqual(9, vec_slice[1]) vec_slice = vec[-2:] self.assertEqual(2, len(vec_slice)) self.assertEqual(8, vec_slice[0]) self.assertEqual(9, vec_slice[1]) def testGetSliceBool(self): vec = ri.BoolSexpVector([True,False,True]) vec = vec[0:2] self.assertEqual(2, len(vec)) self.assertEqual(True, vec[0]) self.assertEqual(False, vec[1]) def testGetSliceStr(self): vec = ri.StrSexpVector(['a','b','c']) vec = vec[0:2] self.assertEqual(2, len(vec)) self.assertEqual('a', vec[0]) self.assertEqual('b', vec[1]) def testGetSliceComplex(self): vec = ri.ComplexSexpVector([1+2j,2+3j,3+4j]) vec = vec[0:2] self.assertEqual(2, len(vec)) self.assertEqual(1+2j, vec[0]) self.assertEqual(2+3j, vec[1]) def testGetSliceList(self): vec = ri.ListSexpVector([1,'b',True]) vec = vec[0:2] self.assertEqual(2, len(vec)) self.assertEqual(1, vec[0][0]) self.assertEqual('b', vec[1][0]) def testAssignItemDifferentType(self): c_R = ri.globalenv.get("c") myVec = c_R(ri.SexpVector([0, 1, 2, 3, 4, 5], ri.INTSXP)) self.assertRaises(ValueError, myVec.__setitem__, 0, ri.SexpVector(["a", ], ri.STRSXP)) def testAssignItemOutOfBound(self): c_R = ri.globalenv.get("c") myVec = c_R(ri.SexpVector([0, 1, 2, 3, 4, 5], ri.INTSXP)) self.assertRaises(IndexError, myVec.__setitem__, 10, ri.SexpVector([1, ], ri.INTSXP)) def testAssignItemInt(self): c_R = ri.globalenv.get("c") myVec = c_R(ri.SexpVector([0, 1, 2, 3, 4, 5], ri.INTSXP)) myVec[0] = ri.SexpVector([100, ], ri.INTSXP) self.assertTrue(myVec[0] == 100) myVec[3] = ri.SexpVector([100, ], ri.INTSXP) self.assertTrue(myVec[3] == 100) myVec[-1] = ri.SexpVector([200, ], ri.INTSXP) self.assertTrue(myVec[5] == 200) def testAssignItemReal(self): c_R = ri.globalenv.get("c") myVec = c_R(ri.SexpVector([0.0, 1.0, 2.0, 3.0, 4.0, 5.0], ri.REALSXP)) myVec[0] = ri.SexpVector([100.0, ], ri.REALSXP) self.assertTrue(floatEqual(myVec[0], 100.0)) myVec[3] = ri.SexpVector([100.0, ], ri.REALSXP) self.assertTrue(floatEqual(myVec[3], 100.0)) def testAssignItemLogical(self): c_R = ri.globalenv.get("c") myVec = c_R(ri.SexpVector([True, False, True, True, False], ri.LGLSXP)) myVec[0] = ri.SexpVector([False, ], ri.LGLSXP) self.assertFalse(myVec[0]) myVec[3] = ri.SexpVector([False, ], ri.LGLSXP) self.assertFalse(myVec[3]) def testAssignItemComplex(self): c_R = ri.globalenv.get("c") myVec = c_R(ri.SexpVector([1.0+2.0j, 2.0+2.0j, 3.0+2.0j, 4.0+2.0j, 5.0+2.0j], ri.CPLXSXP)) myVec[0] = ri.SexpVector([100.0+200.0j, ], ri.CPLXSXP) self.assertTrue(floatEqual(myVec[0].real, 100.0)) self.assertTrue(floatEqual(myVec[0].imag, 200.0)) myVec[3] = ri.SexpVector([100.0+200.0j, ], ri.CPLXSXP) self.assertTrue(floatEqual(myVec[3].real, 100.0)) self.assertTrue(floatEqual(myVec[3].imag, 200.0)) def testAssignItemList(self): myVec = ri.SexpVector([ri.StrSexpVector(["a", ]), ri.IntSexpVector([1, ]), ri.IntSexpVector([3, ])], ri.VECSXP) myVec[0] = ri.SexpVector([ri.FloatSexpVector([100.0, ]), ], ri.VECSXP) self.assertTrue(floatEqual(myVec[0][0][0], 100.0)) myVec[2] = ri.SexpVector([ri.StrSexpVector(["a", ]), ], ri.VECSXP) self.assertTrue(myVec[2][0][0] == "a") def testAssignItemString(self): letters_R = ri.SexpVector("abcdefghij", ri.STRSXP) self.assertRaises(ValueError, letters_R.__setitem__, 0, ri.SexpVector([1, ], ri.INTSXP)) letters_R[0] = ri.SexpVector(["z", ], ri.STRSXP) self.assertTrue(letters_R[0] == "z") def testSetSliceFloat(self): vec = ri.FloatSexpVector([1.0,2.0,3.0]) vec[0:2] = ri.FloatSexpVector([11.0, 12.0]) self.assertEqual(3, len(vec)) self.assertEqual(11.0, vec[0]) self.assertEqual(12.0, vec[1]) self.assertEqual(3.0, vec[2]) def testSetSliceInt(self): vec = ri.IntSexpVector([1,2,3]) vec[0:2] = ri.IntSexpVector([11,12]) self.assertEqual(3, len(vec)) self.assertEqual(11, vec[0]) self.assertEqual(12, vec[1]) def testSetSliceIntNegative(self): vec = ri.IntSexpVector([1,2,3]) vec[-2:-1] = ri.IntSexpVector([33,]) self.assertEqual(3, len(vec)) self.assertEqual(33, vec[1]) def testSetSliceBool(self): vec = ri.BoolSexpVector([True,False,True]) vec[0:2] = ri.BoolSexpVector([False, False]) self.assertEqual(3, len(vec)) self.assertEqual(False, vec[0]) self.assertEqual(False, vec[1]) def testSetSliceStr(self): vec = ri.StrSexpVector(['a','b','c']) vec[0:2] = ri.StrSexpVector(['d','e']) self.assertEqual(3, len(vec)) self.assertEqual('d', vec[0]) self.assertEqual('e', vec[1]) def testSetSliceComplex(self): vec = ri.ComplexSexpVector([1+2j,2+3j,3+4j]) vec[0:2] = ri.ComplexSexpVector([11+2j,12+3j]) self.assertEqual(3, len(vec)) self.assertEqual(11+2j, vec[0]) self.assertEqual(12+3j, vec[1]) def testSetSliceList(self): vec = ri.ListSexpVector([1,'b',True]) vec[0:2] = ri.ListSexpVector([False, 2]) self.assertEqual(3, len(vec)) self.assertEqual(False, vec[0][0]) self.assertEqual(2, vec[1][0]) def testMissingRPreserveObjectBug(self): rgc = ri.baseenv['gc'] xx = range(100000) x = ri.SexpVector(xx, ri.INTSXP) rgc() self.assertEqual(0, x[0]) def testIndexInteger(self): x = ri.IntSexpVector((1,2,3)) self.assertEqual(0, x.index(1)) self.assertEqual(2, x.index(3)) def testIndexStr(self): x = ri.StrSexpVector(('a','b','c')) self.assertEqual(0, x.index('a')) self.assertEqual(2, x.index('c')) def suite(): suite = unittest.TestLoader().loadTestsFromTestCase(SexpVectorTestCase) suite.addTest(unittest.TestLoader().\ loadTestsFromTestCase(WrapperSexpVectorTestCase)) suite.addTest(unittest.TestLoader().\ loadTestsFromTestCase(IntSexpVectorTestCase)) suite.addTest(unittest.TestLoader().\ loadTestsFromTestCase(FloatSexpVectorTestCase)) suite.addTest(unittest.TestLoader().\ loadTestsFromTestCase(ByteSexpVectorTestCase)) suite.addTest(unittest.TestLoader().loadTestsFromTestCase(NAValuesTestCase)) return suite if __name__ == '__main__': tr = unittest.TextTestRunner(verbosity = 2) tr.run(suite()) rpy2-2.3.9/rpy/rinterface/tests/test_SexpEnvironment.py0000644000175000017500000001053512271276146024456 0ustar laurentlaurent00000000000000import unittest import rpy2.rinterface as rinterface rinterface.initr() class SexpEnvironmentTestCase(unittest.TestCase): def setUp(self): self.console = rinterface.get_writeconsole() def noconsole(x): pass rinterface.set_writeconsole(noconsole) def tearDown(self): rinterface.set_writeconsole(self.console) def testNew(self): sexp = rinterface.globalenv sexp_new = rinterface.SexpEnvironment(sexp) idem = rinterface.globalenv.get("identical") self.assertTrue(idem(sexp, sexp_new)[0]) sexp_new2 = rinterface.Sexp(sexp) self.assertTrue(idem(sexp, sexp_new2)[0]) del(sexp) self.assertTrue(idem(sexp_new, sexp_new2)[0]) self.assertRaises(ValueError, rinterface.SexpEnvironment, '2') def testGlobalEnv(self): ok = isinstance(rinterface.globalenv, rinterface.SexpEnvironment) self.assertTrue(ok) def testGetClosure(self): help_R = rinterface.globalenv.get("help") ok = isinstance(help_R, rinterface.SexpClosure) self.assertTrue(ok) def testGetVector(self): pi_R = rinterface.globalenv.get("pi") ok = isinstance(pi_R, rinterface.SexpVector) self.assertTrue(ok) def testGetEnvironment(self): ge_R = rinterface.globalenv.get(".GlobalEnv") ok = isinstance(ge_R, rinterface.SexpEnvironment) self.assertTrue(ok) def testGetOnlyFromLoadedLibrary(self): self.assertRaises(LookupError, rinterface.globalenv.get, "survfit") rinterface.globalenv.get("library")(rinterface.StrSexpVector(["survival", ])) sfit_R = rinterface.globalenv.get("survfit") ok = isinstance(sfit_R, rinterface.SexpClosure) self.assertTrue(ok) def testGet_functionOnly_lookupError(self): # now with the function-only option self.assertRaises(LookupError, rinterface.globalenv.get, "pi", wantfun = True) def testGet_functionOnly(self): hist = rinterface.globalenv.get("hist", wantfun = False) self.assertEqual(rinterface.CLOSXP, hist.typeof) rinterface.globalenv["hist"] = rinterface.SexpVector(["foo", ], rinterface.STRSXP) hist = rinterface.globalenv.get("hist", wantfun = True) self.assertEqual(rinterface.CLOSXP, hist.typeof) def testGet_emptyString(self): self.assertRaises(ValueError, rinterface.globalenv.get, "") def testSubscript(self): ge = rinterface.globalenv obj = rinterface.globalenv.get("letters") ge["a"] = obj a = rinterface.globalenv["a"] ok = ge.get("identical")(obj, a) self.assertTrue(ok[0]) def testSubscript_emptyString(self): ge = rinterface.globalenv self.assertRaises(KeyError, ge.__getitem__, "") def testLength(self): newEnv = rinterface.globalenv.get("new.env") env = newEnv() self.assertEqual(0, len(env)) env["a"] = rinterface.SexpVector([123, ], rinterface.INTSXP) self.assertEqual(1, len(env)) env["b"] = rinterface.SexpVector([123, ], rinterface.INTSXP) self.assertEqual(2, len(env)) def testIter(self): newEnv = rinterface.globalenv.get("new.env") env = newEnv() env["a"] = rinterface.SexpVector([123, ], rinterface.INTSXP) env["b"] = rinterface.SexpVector([456, ], rinterface.INTSXP) symbols = [x for x in env] self.assertEqual(2, len(symbols)) for s in ["a", "b"]: self.assertTrue(s in symbols) def testDel(self): env = rinterface.globalenv.get("new.env")() env["a"] = rinterface.SexpVector([123, ], rinterface.INTSXP) env["b"] = rinterface.SexpVector([456, ], rinterface.INTSXP) self.assertEqual(2, len(env)) del(env['a']) self.assertEqual(1, len(env)) self.assertTrue('b' in env) def testDelKeyError(self): self.assertRaises(KeyError, rinterface.globalenv.__delitem__, 'foo') def testDelBaseError(self): self.assertRaises(ValueError, rinterface.baseenv.__delitem__, 'letters') def suite(): suite = unittest.TestLoader().loadTestsFromTestCase(SexpEnvironmentTestCase) return suite if __name__ == '__main__': tr = unittest.TextTestRunner(verbosity = 2) tr.run(suite()) rpy2-2.3.9/rpy/rinterface/tests/__init__.py0000644000175000017500000000217412271276146022012 0ustar laurentlaurent00000000000000import unittest import test_SexpVector import test_SexpEnvironment import test_Sexp import test_SexpClosure import test_SexpVectorNumeric import test_Device import test_SexpExtPtr import test_EmbeddedR #import test_EmbeddedR_multithreaded def suite(): suite_SexpVector = test_SexpVector.suite() suite_SexpEnvironment = test_SexpEnvironment.suite() suite_Sexp = test_Sexp.suite() suite_SexpClosure = test_SexpClosure.suite() suite_SexpVectorNumeric = test_SexpVectorNumeric.suite() suite_EmbeddedR = test_EmbeddedR.suite() suite_Device = test_Device.suite() suite_SexpExtPtr = test_SexpExtPtr.suite() #suite_EmbeddedR_multithreaded = test_EmbeddedR_multithreaded.suite() alltests = unittest.TestSuite([ suite_EmbeddedR ,suite_Sexp ,suite_SexpVector ,suite_SexpEnvironment ,suite_SexpClosure ,suite_SexpVectorNumeric #,suite_Device #,suite_EmbeddedR_multithreaded ,suite_SexpExtPtr ]) return alltests if __name__ == '__main__': tr = unittest.TextTestRunner(verbosity = 2) suite = suite() tr.run(suite) rpy2-2.3.9/rpy/rinterface/tests/test_EmbeddedR.py0000644000175000017500000003753512271276146023136 0ustar laurentlaurent00000000000000import unittest import itertools import pickle import rpy2 import rpy2.rinterface as rinterface import sys, os, subprocess, time, tempfile, io, signal, gc IS_PYTHON3 = sys.version_info[0] == 3 rinterface.initr() def onlyAQUAorWindows(function): def res(self): platform = rinterface.baseenv.get('.Platform') platform_gui = [e for i, e in enumerate(platform.do_slot('names')) if e == 'GUI'][0] platform_ostype = [e for i, e in enumerate(platform.do_slot('names')) if e == 'OS.type'][0] if (platform_gui != 'AQUA') and (platform_ostype != 'windows'): self.assertTrue(False) # cannot be tested outside GUI==AQUA or OS.type==windows return None else: return function(self) class CustomException(Exception): pass class EmbeddedRTestCase(unittest.TestCase): def testConsolePrint(self): if sys.version_info[0] == 3: tmp_file = io.StringIO() stdout = sys.stdout sys.stdout = tmp_file try: rinterface.consolePrint('haha') except Exception, e: sys.stdout = stdout raise e sys.stdout = stdout tmp_file.flush() tmp_file.seek(0) self.assertEqual('haha', ''.join(s for s in tmp_file).rstrip()) tmp_file.close() else: # no need to test which Python 2, only 2.7 supported tmp_file = tempfile.NamedTemporaryFile() stdout = sys.stdout sys.stdout = tmp_file try: rinterface.consolePrint('haha') except Exception, e: sys.stdout = stdout raise e sys.stdout = stdout tmp_file.flush() tmp_file.seek(0) self.assertEqual('haha', ''.join(s.decode() for s in tmp_file)) tmp_file.close() def testCallErrorWhenEndedR(self): if sys.version_info[0] == 2 and sys.version_info[1] < 6: self.assertTrue(False) # cannot be tested with Python < 2.6 return None import multiprocessing def foo(queue): import rpy2.rinterface as rinterface rdate = rinterface.baseenv['date'] rinterface.endr(1) try: tmp = rdate() res = (False, None) except RuntimeError, re: res = (True, re) except Exception, e: res = (False, e) queue.put(res) q = multiprocessing.Queue() p = multiprocessing.Process(target = foo, args = (q,)) p.start() res = q.get() p.join() self.assertTrue(res[0]) def testStr_typeint(self): t = rinterface.baseenv['letters'] self.assertEqual('STRSXP', rinterface.str_typeint(t.typeof)) t = rinterface.baseenv['pi'] self.assertEqual('REALSXP', rinterface.str_typeint(t.typeof)) def testStr_typeint_invalid(self): self.assertRaises(LookupError, rinterface.str_typeint, 99) def testGet_initoptions(self): options = rinterface.get_initoptions() self.assertEqual(len(rinterface.initoptions), len(options)) for o1, o2 in itertools.izip(rinterface.initoptions, options): self.assertEqual(o1, o2) def testSet_initoptions(self): self.assertRaises(RuntimeError, rinterface.set_initoptions, ('aa', '--verbose', '--no-save')) def testParse(self): xp = rinterface.parse("2 + 3") self.assertEqual(rinterface.EXPRSXP, xp.typeof) self.assertEqual(2.0, xp[0][1][0]) self.assertEqual(3.0, xp[0][2][0]) def testParseUnicode(self): xp = rinterface.parse(u'"\u21a7"') self.assertEqual(1, len(xp)) self.assertEqual(1, len(xp[0])) def testRternalize(self): def f(x, y): return x[0]+y[0] rfun = rinterface.rternalize(f) res = rfun(1, 2) self.assertEqual(3, res[0]) def testRternalizeNamedArgs(self): def f(x, y, z=None): if z is None: return x[0]+y[0] else: return z rfun = rinterface.rternalize(f) res = rfun(1, 2) self.assertEqual(3, res[0]) res = rfun(1, 2, z=8) self.assertEqual(8, res[0]) def testExternalPython(self): def f(x): return 3 rpy_fun = rinterface.SexpExtPtr(f, tag = rinterface.python_type_tag) _python = rinterface.StrSexpVector(('.Python', )) res = rinterface.baseenv['.External'](_python, rpy_fun, 1) self.assertEqual(3, res[0]) self.assertEqual(1, len(res)) def testExternalPythonFromExpression(self): xp_name = rinterface.StrSexpVector(('expression',)) xp = rinterface.baseenv['vector'](xp_name, 3) def testParseInvalidString(self): self.assertRaises(ValueError, rinterface.parse, 3) def testInterruptR(self): if sys.version_info[0] == 2 and sys.version_info[1] < 6: self.assertTrue(False) # Test unit currently requires Python >= 2.6 rpy_code = tempfile.NamedTemporaryFile(mode = 'w', suffix = '.py', delete = False) rpy2_path = os.path.dirname(rpy2.__path__[0]) if IS_PYTHON3: pyexception_as = ' as' else: pyexception_as = ',' rpy_code_str = """ import sys sys.path.insert(0, '%s') import rpy2.rinterface as ri ri.initr() def f(x): pass ri.set_writeconsole(f) rcode = "i <- 0; " rcode += "while(TRUE) { " rcode += "i <- i+1; " rcode += "Sys.sleep(0.01); " rcode += "}" try: ri.baseenv['eval'](ri.parse(rcode)) except Exception%s e: sys.exit(0) """ %(rpy2_path, pyexception_as) rpy_code.write(rpy_code_str) rpy_code.close() child_proc = subprocess.Popen((sys.executable, rpy_code.name)) time.sleep(1) # required for the SIGINT to function # (appears like a bug w/ subprocess) # (the exact sleep time migth be machine dependent :( ) child_proc.send_signal(signal.SIGINT) time.sleep(1) # required for the SIGINT to function ret_code = child_proc.poll() self.assertFalse(ret_code is None) # Interruption failed def testRpyMemory(self): x = rinterface.SexpVector(xrange(10), rinterface.INTSXP) y = rinterface.SexpVector(xrange(10), rinterface.INTSXP) x_rid = x.rid self.assertTrue(x_rid in set(z[0] for z in rinterface.protected_rids())) del(x) gc.collect(); gc.collect() self.assertFalse(x_rid in set(z[0] for z in rinterface.protected_rids())) class CallbacksTestCase(unittest.TestCase): def tearDown(self): rinterface.set_writeconsole(rinterface.consolePrint) rinterface.set_readconsole(rinterface.consoleRead) rinterface.set_readconsole(rinterface.consoleFlush) rinterface.set_choosefile(rinterface.chooseFile) sys.last_value = None def testSetWriteConsole(self): buf = [] def f(x): buf.append(x) rinterface.set_writeconsole(f) self.assertEqual(rinterface.get_writeconsole(), f) code = rinterface.SexpVector(["3", ], rinterface.STRSXP) rinterface.baseenv["print"](code) self.assertEqual('[1] "3"\n', str.join('', buf)) def testWriteConsoleWithError(self): def f(x): raise CustomException("Doesn't work.") rinterface.set_writeconsole(f) tmp_file = tempfile.NamedTemporaryFile() stderr = sys.stderr sys.stderr = tmp_file try: code = rinterface.SexpVector(["3", ], rinterface.STRSXP) rinterface.baseenv["print"](code) except Exception, e: sys.stderr = stderr raise e sys.stderr = stderr tmp_file.flush() tmp_file.seek(0) self.assertEqual("Doesn't work.", str(sys.last_value)) #errorstring = ''.join(tmp_file.readlines()) #self.assertTrue(errorstring.startswith('Traceback')) #tmp_file.close() @onlyAQUAorWindows def testSetFlushConsole(self): flush = {'count': 0} def f(): flush['count'] = flush['count'] + 1 rinterface.set_flushconsole(f) self.assertEqual(rinterface.get_flushconsole(), f) rinterface.baseenv.get("flush.console")() self.assertEqual(1, flush['count']) rinterface.set_writeconsole(rinterface.consoleFlush) @onlyAQUAorWindows def testFlushConsoleWithError(self): def f(prompt): raise Exception("Doesn't work.") rinterface.set_flushconsole(f) tmp_file = tempfile.NamedTemporaryFile() stderr = sys.stderr sys.stderr = tmp_file try: res = rinterface.baseenv.get("flush.console")() except Exception, e: sys.stderr = stderr raise e sys.stderr = stderr tmp_file.flush() tmp_file.seek(0) self.assertEqual("Doesn't work.", str(sys.last_value)) #errorstring = ''.join(tmp_file.readlines()) #self.assertTrue(errorstring.startswith('Traceback')) #tmp_file.close() def testSetReadConsole(self): yes = "yes\n" def sayyes(prompt): return yes rinterface.set_readconsole(sayyes) self.assertEqual(rinterface.get_readconsole(), sayyes) res = rinterface.baseenv["readline"]() self.assertEqual(yes.strip(), res[0]) rinterface.set_readconsole(rinterface.consoleRead) def testReadConsoleWithError(self): def f(prompt): raise Exception("Doesn't work.") rinterface.set_readconsole(f) tmp_file = tempfile.NamedTemporaryFile() stderr = sys.stderr sys.stderr = tmp_file try: res = rinterface.baseenv["readline"]() except Exception, e: sys.stderr = stderr raise e sys.stderr = stderr tmp_file.flush() tmp_file.seek(0) self.assertEqual("Doesn't work.", str(sys.last_value)) #errorstring = ''.join(tmp_file.readlines()) #self.assertTrue(errorstring.startswith('Traceback')) #tmp_file.close() def testSetShowMessage(self): def f(message): return "foo" rinterface.set_showmessage(f) #FIXME: incomplete test def testShowMessageWithError(self): def f(prompt): raise Exception("Doesn't work.") rinterface.set_showmessage(f) #FIXME: incomplete test def testSetChooseFile(self): me = "me" def chooseMe(prompt): return me rinterface.set_choosefile(chooseMe) self.assertEqual(rinterface.get_choosefile(), chooseMe) res = rinterface.baseenv["file.choose"]() self.assertEqual(me, res[0]) rinterface.set_choosefile(rinterface.chooseFile) def testChooseFileWithError(self): def noconsole(x): pass rinterface.set_writeconsole(noconsole) # reverted by the tearDown method def f(prompt): raise Exception("Doesn't work.") rinterface.set_choosefile(f) tmp_file = tempfile.NamedTemporaryFile() stderr = sys.stderr sys.stderr = tmp_file try: res = rinterface.baseenv["file.choose"]() except rinterface.RRuntimeError: pass except Exception, e: sys.stderr = stderr raise e sys.stderr = stderr tmp_file.flush() tmp_file.seek(0) self.assertEqual("Doesn't work.", str(sys.last_value)) #errorstring = ''.join(tmp_file.readlines()) #self.assertTrue(errorstring.startswith('Traceback')) #tmp_file.close() def testSetShowFiles(self): sf = [] def f(fileheaders, wtitle, fdel, pager): sf.append(wtitle) for tf in fileheaders: sf.append(tf) rinterface.set_showfiles(f) file_path = rinterface.baseenv["file.path"] r_home = rinterface.baseenv["R.home"] filename = file_path(r_home(rinterface.StrSexpVector(("doc", ))), rinterface.StrSexpVector(("COPYRIGHTS", ))) res = rinterface.baseenv["file.show"](filename) self.assertEqual(filename[0], sf[1][1]) self.assertEqual('R Information', sf[0]) def testShowFilesWithError(self): def f(fileheaders, wtitle, fdel, pager): raise Exception("Doesn't work.") rinterface.set_showfiles(f) file_path = rinterface.baseenv["file.path"] r_home = rinterface.baseenv["R.home"] filename = file_path(r_home(rinterface.StrSexpVector(("doc", ))), rinterface.StrSexpVector(("COPYRIGHTS", ))) tmp_file = tempfile.NamedTemporaryFile() stderr = sys.stderr sys.stderr = tmp_file try: res = rinterface.baseenv["file.show"](filename) except rinterface.RRuntimeError: pass except Exception, e: sys.stderr = stderr raise e sys.stderr = stderr tmp_file.flush() tmp_file.seek(0) self.assertEqual("Doesn't work.", str(sys.last_value)) #errorstring = ''.join(tmp_file.readlines()) #self.assertTrue(errorstring.startswith('Traceback')) #tmp_file.close() def testSetCleanUp(self): orig_cleanup = rinterface.get_cleanup() def f(saveact, status, runlast): return False rinterface.set_cleanup(f) rinterface.set_cleanup(orig_cleanup) def testCleanUp(self): orig_cleanup = rinterface.get_cleanup() def f(saveact, status, runlast): return None r_quit = rinterface.baseenv['q'] rinterface.set_cleanup(f) self.assertRaises(rinterface.RRuntimeError, r_quit) rinterface.set_cleanup(orig_cleanup) class ObjectDispatchTestCase(unittest.TestCase): def testObjectDispatchLang(self): formula = rinterface.globalenv.get('formula') obj = formula(rinterface.StrSexpVector(['y ~ x', ])) self.assertTrue(isinstance(obj, rinterface.SexpVector)) self.assertEqual(rinterface.LANGSXP, obj.typeof) def testObjectDispatchVector(self): letters = rinterface.globalenv.get('letters') self.assertTrue(isinstance(letters, rinterface.SexpVector)) def testObjectDispatchClosure(self): #import pdb; pdb.set_trace() help = rinterface.globalenv.get('sum') self.assertTrue(isinstance(help, rinterface.SexpClosure)) def testObjectDispatchRawVector(self): raw = rinterface.baseenv.get('raw') #rawvec = raw(rinterface.IntSexpVector((10, ))) #self.assertEqual(rinterface.RAWSXP, rawvec.typeof) class SerializeTestCase(unittest.TestCase): def testUnserialize(self): x = rinterface.IntSexpVector([1,2,3]) x_serialized = x.__getstate__() x_again = rinterface.unserialize(x_serialized, x.typeof) identical = rinterface.baseenv["identical"] self.assertFalse(x.rsame(x_again)) self.assertTrue(identical(x, x_again)[0]) def testPickle(self): x = rinterface.IntSexpVector([1,2,3]) f = tempfile.NamedTemporaryFile() pickle.dump(x, f) f.flush() f.seek(0) x_again = pickle.load(f) f.close() identical = rinterface.baseenv["identical"] self.assertTrue(identical(x, x_again)[0]) def suite(): suite = unittest.TestLoader().loadTestsFromTestCase(EmbeddedRTestCase) suite.addTest(unittest.TestLoader().loadTestsFromTestCase(CallbacksTestCase)) suite.addTest(unittest.TestLoader().loadTestsFromTestCase(ObjectDispatchTestCase)) return suite if __name__ == '__main__': tr = unittest.TextTestRunner(verbosity = 2) tr.run(suite()) rpy2-2.3.9/rpy/rinterface/tests/test_SexpClosure.py0000644000175000017500000001133412271276146023564 0ustar laurentlaurent00000000000000import unittest import rpy2.rinterface as rinterface import rpy2.rlike.container as rlc rinterface.initr() class SexpClosureTestCase(unittest.TestCase): def setUp(self): self.console = rinterface.get_writeconsole() def noconsole(x): pass rinterface.set_writeconsole(noconsole) def tearDown(self): rinterface.set_writeconsole(self.console) def testNew(self): x = "a" self.assertRaises(ValueError, rinterface.SexpClosure, x) def testTypeof(self): sexp = rinterface.globalenv.get("plot") self.assertEqual(sexp.typeof, rinterface.CLOSXP) def testRError(self): sum = rinterface.baseenv["sum"] letters = rinterface.baseenv["letters"] self.assertRaises(rinterface.RRuntimeError, sum, letters) def testClosureenv(self): exp = rinterface.parse("function(x) { x[y] }") fun = rinterface.baseenv["eval"](exp) vec = rinterface.baseenv["letters"] self.assertRaises(rinterface.RRuntimeError, fun, vec) fun.closureenv["y"] = rinterface.SexpVector([1, ], rinterface.INTSXP) self.assertEqual('a', fun(vec)[0]) fun.closureenv["y"] = rinterface.SexpVector([2, ], rinterface.INTSXP) self.assertEqual('b', fun(vec)[0]) def testCallS4SetClass(self): # R's package "methods" can perform uncommon operations r_setClass = rinterface.globalenv.get('setClass') r_representation = rinterface.globalenv.get('representation') attrnumeric = rinterface.SexpVector(["numeric", ], rinterface.STRSXP) classname = rinterface.SexpVector(['Track', ], rinterface.STRSXP) classrepr = r_representation(x = attrnumeric, y = attrnumeric) r_setClass(classname, classrepr) def testRcallOrdDict(self): ad = rlc.OrdDict((('a', rinterface.SexpVector([2, ], rinterface.INTSXP)), ('b', rinterface.SexpVector([1, ], rinterface.INTSXP)), (None, rinterface.SexpVector([5, ], rinterface.INTSXP)), ('c', rinterface.SexpVector([0, ], rinterface.INTSXP)))) mylist = rinterface.baseenv['list'].rcall(tuple(ad.items()), rinterface.globalenv) names = [x for x in mylist.do_slot("names")] for i in range(4): self.assertEqual(('a', 'b', '', 'c')[i], names[i]) def testRcallOrdDictEnv(self): ad = rlc.OrdDict( ((None, rinterface.parse('sum(x)')),) ) env_a = rinterface.baseenv['new.env']() env_a['x'] = rinterface.IntSexpVector([1,2,3]) sum_a = rinterface.baseenv['eval'].rcall(tuple(ad.items()), env_a) self.assertEqual(6, sum_a[0]) env_b = rinterface.baseenv['new.env']() env_b['x'] = rinterface.IntSexpVector([4,5,6]) sum_b = rinterface.baseenv['eval'].rcall(tuple(ad.items()), env_b) self.assertEqual(15, sum_b[0]) def testErrorInCall(self): mylist = rinterface.baseenv['list'] self.assertRaises(ValueError, mylist, 'foo') def testMissingArg(self): exp = rinterface.parse("function(x) { missing(x) }") fun = rinterface.baseenv["eval"](exp) nonmissing = rinterface.SexpVector([0, ], rinterface.INTSXP) missing = rinterface.MissingArg self.assertEqual(False, fun(nonmissing)[0]) self.assertEqual(True, fun(missing)[0]) def testScalarConvertInteger(self): self.assertEqual('integer', rinterface.baseenv["typeof"](1)[0]) def testScalarConvertLong(self): self.assertEqual('integer', rinterface.baseenv["typeof"](long(1))[0]) def testScalarConvertDouble(self): self.assertEqual('double', rinterface.baseenv["typeof"](1.0)[0]) def testScalarConvertBoolean(self): self.assertEqual('logical', rinterface.baseenv["typeof"](True)[0]) def suite(): suite = unittest.TestLoader().loadTestsFromTestCase(SexpClosureTestCase) return suite if __name__ == '__main__': tr = unittest.TextTestRunner(verbosity = 2) tr.run(suite()) rpy2-2.3.9/rpy/rinterface/_rinterface.c0000755000175000017500000032163012271276146021170 0ustar laurentlaurent00000000000000/* A python-R interface*/ /* * The authors for the original RPy code, as well as * belopolsky for his contributed code, are listed here as authors; * although the design is largely new, parts of this code is * derived from their contributions. * * Laurent Gautier - 2008 */ /* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * Copyright (C) 2008-2012 Laurent Gautier * * Portions created by Alexander Belopolsky are * Copyright (C) 2006 Alexander Belopolsky. * * Portions created by Gregory R. Warnes are * Copyright (C) 2003-2008 Gregory Warnes. * * Portions created by Walter Moreira are * Copyright (C) 2002-2003 Walter Moreira * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ #include #include #define PY_SSIZE_T_CLEAN #include "Python.h" #define _RINTERFACE_MODULE #include "_rinterface.h" #if defined(Win32) || defined(Win64) #include #endif #include #include #include #include #if !(defined(Win32) || defined(Win64)) #include #endif #include #include #include #include #include #include /*FIXME: required to fix the R issue with setting static char* values for readline variable (making Python's readline crash when trying to free them) */ #ifdef HAS_READLINE #include #endif /* From Defn.h */ #ifdef HAVE_POSIX_SETJMP #define SIGJMP_BUF sigjmp_buf #else #define SIGJMP_BUF jmp_buf #endif #define _RPY_RINTERFACE_MODULE_ #if (PY_VERSION_HEX < 0x03010000) staticforward PyObject* EmbeddedR_unserialize(PyObject* self, PyObject* args); #else static PyObject* EmbeddedR_unserialize(PyObject* self, PyObject* args); #endif #include "embeddedr.h" #include "na_values.h" #include "sexp.h" #include "r_utils.h" #include "buffer.h" #include "array.h" #include "sequence.h" #include "rexternalptr.h" static PySexpObject* newPySexpObject(const SEXP sexp); /* Helper variable to quickly resolve SEXP types. * An array of strings giving either * the SEXP name (INTSXP, REALSXP, etc...), or a NULL * if there is no such valid SEXP. */ static char **validSexpType; static SEXP newSEXP(PyObject *object, const int rType); #include "embeddedr.c" #include "null_value.c" #include "na_values.c" #include "sexp.c" #include "r_utils.c" #include "buffer.c" #include "array.c" #include "sequence.c" #include "rexternalptr.c" static PyObject *embeddedR_isInitialized; /* A tuple that holds options to initialize R */ static PyObject *initOptions; static SEXP errMessage_SEXP; static PyObject *RPyExc_RuntimeError = NULL; #if (defined(Win32) || defined(Win64)) /* R instance as a global */ Rstart Rp; #endif /* FIXME: see the details of interruption */ /* Indicates whether the R interpreter was interrupted by a SIGINT */ int interrupted = 0; /* Abort the current R computation due to a SIGINT */ static void interrupt_R(int signum) { printf("-->interrupted.\n"); interrupted = 1; error("Interrupted"); } SIGJMP_BUF env_sigjmp; /* Python's signal handler */ static PyOS_sighandler_t python_sighandler, last_sighandler; /* In SAGE, explicit defintions */ /* /\* Python handler (definition varies across platforms) *\/ */ /* #if defined(__CYGWIN32__) /\* Windows XP *\/ */ /* _sig_func_ptr python_sighandler; */ /* #elif defined(__FreeBSD__) /\* FreeBSD *\/ */ /* sig_t python_sighandler; */ /* #elif defined(__APPLE__) /\* OSX *\/ */ /* sig_t python_sighandler; */ /* #elif defined (__sun__) || defined (__sun) /\* Solaris *\/ */ /* __sighandler_t python_sighandler; */ /* #else /\* Other, e.g., Linux *\/ */ /* __sighandler_t python_sighandler; */ /* #endif */ #if defined(_RPY_STRNDUP_) /* OSX 10.5 and 10.6, and older BSD */ inline char* strndup (const char *s, size_t n) { size_t len = strlen (s); char *ret; if (len <= n) return strdup (s); ret = malloc(n + 1); strncpy(ret, s, n); ret[n] = '\0'; return ret; } #endif static int PyRinterface_IsInitialized(void) { int res = (embeddedR_isInitialized == Py_True) ? 1 : 0; return res; } /* Return R_UnboundValue when not found. */ static SEXP PyRinterface_FindFun(SEXP symbol, SEXP rho) { SEXP vl; while (rho != R_EmptyEnv) { /* This is not really right. Any variable can mask a function */ vl = findVarInFrame3(rho, symbol, TRUE); if (vl != R_UnboundValue) { if (TYPEOF(vl) == PROMSXP) { PROTECT(vl); vl = eval(vl, rho); UNPROTECT(1); } if (TYPEOF(vl) == CLOSXP || TYPEOF(vl) == BUILTINSXP || TYPEOF(vl) == SPECIALSXP) return (vl); if (vl == R_MissingArg) { printf("R_MissingArg in rpy_FindFun.\n"); return R_UnboundValue; } } rho = ENCLOS(rho); } return R_UnboundValue; } PyDoc_STRVAR(module_doc, "Low-level functions to interface with R.\n\ One should mostly consider calling the functions defined here when\ writing a higher level interface between python and R.\ Check the documentation for the module this is bundled into if\ you only wish to have an off-the-shelf interface with R.\ \n\ "); static PyObject *RPY_R_VERSION_BUILD; static PySexpObject *globalEnv; static PySexpObject *baseNameSpaceEnv; static PySexpObject *emptyEnv; static PySexpObject *rpy_R_NilValue; #ifdef RPY_DEBUG_PRESERVE static int preserved_robjects = 0; #endif /* NAs */ static PyObject* NAInteger_New(int new); static PyTypeObject NAInteger_Type; static PyObject* NALogical_New(int new); static PyTypeObject NALogical_Type; static PyObject* NAReal_New(int new); static PyTypeObject NAReal_Type; static PyObject* NAComplex_New(int new); static PyTypeObject NAComplex_Type; static PyObject* NACharacter_New(int new); static PyTypeObject NACharacter_Type; /* type tag for Python external methods */ static PySexpObject *R_PyObject_type_tag; static void RegisterExternalSymbols(void); /* --- set output from the R console ---*/ static inline PyObject* EmbeddedR_setAnyCallback(PyObject *self, PyObject *args, PyObject **target) { PyObject *result; PyObject *function; if ( PyArg_ParseTuple(args, "O:console", &function)) { if (function != Py_None && !PyCallable_Check(function)) { PyErr_SetString(PyExc_TypeError, "parameter must be callable"); return NULL; } Py_XDECREF(*target); if (function == Py_None) { *target = NULL; } else { Py_XINCREF(function); *target = function; } Py_INCREF(Py_None); result = Py_None; } else { PyErr_SetString(PyExc_TypeError, "The parameter should be a callable."); return NULL; } return result; } static PyObject* EmbeddedR_getAnyCallback(PyObject *self, PyObject *args, PyObject *target) { PyObject *result = NULL; if (PyArg_ParseTuple(args, "")) { if (target == NULL) { result = Py_None; } else { result = target; } } else { } Py_XINCREF(result); return result; } static PyObject* writeConsoleCallback = NULL; static PyObject* EmbeddedR_setWriteConsole(PyObject *self, PyObject *args) { PyObject *res = EmbeddedR_setAnyCallback(self, args, &writeConsoleCallback); return res; } PyDoc_STRVAR(EmbeddedR_setWriteConsole_doc, "set_writeconsole(f)\n\n" "Set how to handle output from the R console with either None" " or a function f such as f(output) returns None" " (f only has side effects)."); static PyObject * EmbeddedR_getWriteConsole(PyObject *self, PyObject *args) { return EmbeddedR_getAnyCallback(self, args, writeConsoleCallback); } PyDoc_STRVAR(EmbeddedR_getWriteConsole_doc, "get_writeconsole()\n\n" "Retrieve the current R console output handler" " (see set_writeconsole)"); static void EmbeddedR_WriteConsole(const char *buf, int len) { PyObject *arglist; PyObject *result; const int is_threaded = PyEval_ThreadsInitialized(); PyGILState_STATE gstate; RPY_GIL_ENSURE(is_threaded, gstate); /* It is necessary to restore the Python handler when using a Python function for I/O. */ PyOS_setsig(SIGINT, python_sighandler); #if (PY_VERSION_HEX < 0x03010000) arglist = Py_BuildValue("(s)", buf); #else arglist = Py_BuildValue("(s)", buf); #endif if (! arglist) { PyErr_NoMemory(); /* signal(SIGINT, old_int); */ /* return NULL; */ } if (writeConsoleCallback == NULL) { return; } result = PyEval_CallObject(writeConsoleCallback, arglist); PyObject* pythonerror = PyErr_Occurred(); if (pythonerror != NULL) { /* All R actions should be stopped since the Python callback failed, and the Python exception raised up.*/ /* FIXME: Print the exception in the meanwhile */ PyErr_Print(); PyErr_Clear(); } Py_DECREF(arglist); /* signal(SIGINT, old_int); */ Py_XDECREF(result); RPY_GIL_RELEASE(is_threaded, gstate); } static PyObject* showMessageCallback = NULL; static PyObject* EmbeddedR_setShowMessage(PyObject *self, PyObject *args) { return EmbeddedR_setAnyCallback(self, args, &showMessageCallback); } PyDoc_STRVAR(EmbeddedR_setShowMessage_doc, "set_showmessage(f)\n\n" "Set how to handle alert message from R with either None" " or a function f such as f(message) returns None" " (f only has side effects)."); static PyObject * EmbeddedR_getShowMessage(PyObject *self, PyObject *args) { return EmbeddedR_getAnyCallback(self, args, showMessageCallback); } PyDoc_STRVAR(EmbeddedR_getShowMessage_doc, "get_showmessage()\n\n" "Retrieve the current R alert message handler" " (see set_showmessage)"); static void EmbeddedR_ShowMessage(const char *buf) { PyOS_sighandler_t old_int; PyObject *arglist; PyObject *result; const int is_threaded = PyEval_ThreadsInitialized(); PyGILState_STATE gstate; RPY_GIL_ENSURE(is_threaded, gstate); /* It is necessary to restore the Python handler when using a Python function for I/O. */ old_int = PyOS_getsig(SIGINT); PyOS_setsig(SIGINT, python_sighandler); arglist = Py_BuildValue("(s)", buf); if (! arglist) { //PyErr_NoMemory(); printf("Ouch. Likely a out of memory.\n"); signal(SIGINT, old_int); return; } if (showMessageCallback == NULL) { return; } result = PyEval_CallObject(showMessageCallback, arglist); PyObject* pythonerror = PyErr_Occurred(); if (pythonerror != NULL) { /* All R actions should be stopped since the Python callback failed, and the Python exception raised up.*/ /* FIXME: Print the exception in the meanwhile */ PyErr_Print(); PyErr_Clear(); } Py_DECREF(arglist); /* signal(SIGINT, old_int); */ Py_XDECREF(result); RPY_GIL_RELEASE(is_threaded, gstate); } static PyObject* readConsoleCallback = NULL; static PyObject* EmbeddedR_setReadConsole(PyObject *self, PyObject *args) { return EmbeddedR_setAnyCallback(self, args, &readConsoleCallback); } PyDoc_STRVAR(EmbeddedR_setReadConsole_doc, "set_readconsole(f)\n\n" "Set how to handle input to R with either None" " or a function f such as f(prompt) returns the string" " message to be passed to R"); static PyObject * EmbeddedR_getReadConsole(PyObject *self, PyObject *args) { return EmbeddedR_getAnyCallback(self, args, readConsoleCallback); } PyDoc_STRVAR(EmbeddedR_getReadConsole_doc, "get_readconsole()\n\n" "Retrieve the current R alert message handler" " (see set_readconsole)"); static int EmbeddedR_ReadConsole(const char *prompt, unsigned char *buf, int len, int addtohistory) { PyObject *arglist; PyObject *result; const int is_threaded = PyEval_ThreadsInitialized(); PyGILState_STATE gstate; RPY_GIL_ENSURE(is_threaded, gstate); /* It is necessary to restore the Python handler when using a Python function for I/O. */ /* old_int = PyOS_getsig(SIGINT); */ /* PyOS_setsig(SIGINT, python_sighandler); */ arglist = Py_BuildValue("(s)", prompt); if (! arglist) { PyErr_NoMemory(); /* signal(SIGINT, old_int); */ /* return NULL; */ } if (readConsoleCallback == NULL) { Py_DECREF(arglist); RPY_GIL_RELEASE(is_threaded, gstate); return -1; } #ifdef RPY_DEBUG_CONSOLE printf("Callback for console input..."); #endif result = PyEval_CallObject(readConsoleCallback, arglist); #ifdef RPY_DEBUG_CONSOLE printf("done.(%p)\n", result); #endif Py_XDECREF(arglist); PyObject* pythonerror = PyErr_Occurred(); if (pythonerror != NULL) { /* All R actions should be stopped since the Python callback failed, and the Python exception raised up.*/ /* FIXME: Print the exception in the meanwhile */ PyErr_Print(); PyErr_Clear(); RPY_GIL_RELEASE(is_threaded, gstate); return 0; } if (result == NULL) { /* FIXME: can this be reached ? result == NULL while no error ? */ /* signal(SIGINT, old_int); */ RPY_GIL_RELEASE(is_threaded, gstate); return 0; } const char *input_str = NULL; #if (PY_VERSION_HEX < 0x03010000) input_str = PyString_AsString(result); #else int is_unicode = PyUnicode_Check(result); PyObject *pybytes = NULL; if (is_unicode) { pybytes = PyUnicode_AsLatin1String(result); input_str = PyBytes_AsString(pybytes); } else if (PyBytes_Check(result)) { input_str = PyBytes_AsString(result); } else { PyErr_Format(PyExc_ValueError, \ "The R console callback must return a unicode string or bytes."); PyErr_Print(); PyErr_Clear(); RPY_GIL_RELEASE(is_threaded, gstate); return 0; } //const char *input_str = PyBytes_AsString(result); #endif if (! input_str) { #if (PY_VERSION_HEX >= 0x03010000) if (is_unicode) Py_XDECREF(pybytes); #endif PyErr_Print(); PyErr_Clear(); RPY_GIL_RELEASE(is_threaded, gstate); return 0; } /* Snatched from Rcallbacks.c in JRI */ int l=strlen(input_str); strncpy((char *)buf, input_str, (l>len-1)?len-1:l); buf[(l>len-1)?len-1:l]=0; /* --- */ #if (PY_VERSION_HEX >= 0x03010000) if (is_unicode) Py_XDECREF(pybytes); #endif Py_XDECREF(result); /* signal(SIGINT, old_int); */ RPY_GIL_RELEASE(is_threaded, gstate); return 1; } static PyObject* flushConsoleCallback = NULL; static PyObject* EmbeddedR_setFlushConsole(PyObject *self, PyObject *args) { return EmbeddedR_setAnyCallback(self, args, &flushConsoleCallback); } PyDoc_STRVAR(EmbeddedR_setFlushConsole_doc, "set_flushconsole(f)\n\n" "Set how to handle the flushing to the R conso with either None" " or a function f such as f() returns None" " (f only has side effects)."); static PyObject * EmbeddedR_getFlushConsole(PyObject *self, PyObject *args) { return EmbeddedR_getAnyCallback(self, args, flushConsoleCallback); } PyDoc_STRVAR(EmbeddedR_getFlushConsole_doc, "get_flushconsole()\n\n" "Retrieve the current R handler to flush the console" " (see set_flushconsole)"); static void EmbeddedR_FlushConsole(void) { const int is_threaded = PyEval_ThreadsInitialized(); PyGILState_STATE gstate; RPY_GIL_ENSURE(is_threaded, gstate); //PyObject *result (returned by call below); PyEval_CallObject(flushConsoleCallback, NULL); PyObject* pythonerror = PyErr_Occurred(); if (pythonerror != NULL) { /* All R actions should be stopped since the Python callback failed, and the Python exception raised up.*/ /* FIXME: Print the exception in the meanwhile */ PyErr_Print(); PyErr_Clear(); } RPY_GIL_RELEASE(is_threaded, gstate); return; } static PyObject* chooseFileCallback = NULL; static PyObject* EmbeddedR_setChooseFile(PyObject *self, PyObject *args) { return EmbeddedR_setAnyCallback(self, args, &chooseFileCallback); } PyDoc_STRVAR(EmbeddedR_setChooseFile_doc, "Use the function to handle R's requests for choosing a file."); static PyObject * EmbeddedR_getChooseFile(PyObject *self, PyObject *args) { return EmbeddedR_getAnyCallback(self, args, chooseFileCallback); } PyDoc_STRVAR(EmbeddedR_getChooseFile_doc, "Retrieve current R console output handler (see setChooseFile)."); /* Callback to replace R's default function for choosing a file This return 1 on success, 0 on failure. In the case of failure the calling function will fail as */ static int EmbeddedR_ChooseFile(int new, char *buf, int len) { PyObject *arglist; PyObject *result; const int is_threaded = PyEval_ThreadsInitialized(); PyGILState_STATE gstate; RPY_GIL_ENSURE(is_threaded, gstate); #if (PY_VERSION_HEX < 0x03010000) arglist = Py_BuildValue("(s)", buf); #else arglist = Py_BuildValue("(y)", buf); #endif if (! arglist) { PyErr_NoMemory(); } if (chooseFileCallback == NULL) { Py_DECREF(arglist); RPY_GIL_RELEASE(is_threaded, gstate); return 0; } result = PyEval_CallObject(chooseFileCallback, arglist); PyObject* pythonerror = PyErr_Occurred(); if (pythonerror != NULL) { /* All R actions should be stopped since the Python callback failed, and the Python exception raised up.*/ /* FIXME: Print the exception in the meanwhile */ PyErr_Print(); PyErr_Clear(); Py_XDECREF(arglist); RPY_GIL_RELEASE(is_threaded, gstate); return 0; } if (result == NULL) { /* FIXME: can this be reached ? result == NULL while no error ? */ printf("Error: trouble with chooseFileCallback, we should not be here.\n"); Py_XDECREF(arglist); RPY_GIL_RELEASE(is_threaded, gstate); return 0; } #if (PY_VERSION_HEX < 0x03010000) char *path_str = PyString_AsString(result); #else PyObject *pybytes = PyUnicode_AsLatin1String(result); char *path_str = PyBytes_AsString(pybytes); #endif if (! path_str) { #if (PY_VERSION_HEX >= 0x03010000) Py_DECREF(pybytes); #endif Py_DECREF(result); PyErr_SetString(PyExc_TypeError, "Returned value should have a string representation"); PyErr_Print(); PyErr_Clear(); Py_DECREF(arglist); RPY_GIL_RELEASE(is_threaded, gstate); return 0; } /* As shown in gnomeGUI */ int l=strlen(path_str); strncpy((char *)buf, path_str, (l>len-1)?len-1:l); buf[(l>len-1)?len-1:l] = '\0'; /* --- */ #if (PY_VERSION_HEX >= 0x03010000) Py_DECREF(pybytes); #endif Py_DECREF(arglist); Py_DECREF(result); RPY_GIL_RELEASE(is_threaded, gstate); return l; } static PyObject* showFilesCallback = NULL; static PyObject* EmbeddedR_setShowFiles(PyObject *self, PyObject *args) { return EmbeddedR_setAnyCallback(self, args, &showFilesCallback); } PyDoc_STRVAR(EmbeddedR_setShowFiles_doc, "Use the function to display files."); static PyObject * EmbeddedR_getShowFiles(PyObject *self, PyObject *args) { return EmbeddedR_getAnyCallback(self, args, showFilesCallback); } PyDoc_STRVAR(EmbeddedR_getShowFiles_doc, "Retrieve current R console output handler (see setShowFiles)."); static int EmbeddedR_ShowFiles(int nfile, const char **file, const char **headers, const char *wtitle, Rboolean del, const char *pager) { const int is_threaded = PyEval_ThreadsInitialized(); PyGILState_STATE gstate; RPY_GIL_ENSURE(is_threaded, gstate); if (showFilesCallback == NULL) { RPY_GIL_RELEASE(is_threaded, gstate); return 0; } if (nfile < 1) { RPY_GIL_RELEASE(is_threaded, gstate); return 0; } PyObject *arglist; PyObject *result; PyObject *py_del; RPY_PY_FROM_RBOOL(py_del, del); #if (PY_VERSION_HEX < 0x03010000) PyObject *py_wtitle = PyString_FromString(wtitle); PyObject *py_pager = PyString_FromString(pager); #else PyObject *py_wtitle = PyUnicode_FromString(wtitle); PyObject *py_pager = PyUnicode_FromString(pager); #endif PyObject *py_fileheaders_tuple = PyTuple_New(nfile); PyObject *py_fileheader; int f_i; for (f_i = 0; f_i < nfile; f_i++) { py_fileheader = PyTuple_New(2); #if (PY_VERSION_HEX < 0x03010000) if (PyTuple_SetItem(py_fileheader, 0, PyString_FromString(headers[f_i])) != 0) { #else if (PyTuple_SetItem(py_fileheader, 0, PyUnicode_FromString(headers[f_i])) != 0) { #endif Py_DECREF(py_fileheaders_tuple); /*FIXME: decref other PyObject arguments */ RPY_GIL_RELEASE(is_threaded, gstate); return 0; } #if (PY_VERSION_HEX < 0x03010000) if (PyTuple_SetItem(py_fileheader, 1, PyString_FromString(file[f_i])) != 0) { #else if (PyTuple_SetItem(py_fileheader, 1, PyUnicode_FromString(file[f_i])) != 0) { #endif Py_DECREF(py_fileheaders_tuple); /*FIXME: decref other PyObject arguments */ RPY_GIL_RELEASE(is_threaded, gstate); return 0; } if (PyTuple_SetItem(py_fileheaders_tuple, f_i, py_fileheader) != 0) { Py_DECREF(py_fileheaders_tuple); /*FIXME: decref other PyObject arguments */ RPY_GIL_RELEASE(is_threaded, gstate); return 0; } } arglist = Py_BuildValue("OOOO", py_fileheaders_tuple, py_wtitle, py_del, py_pager); if (! arglist) { PyErr_Print(); PyErr_NoMemory(); /* FIXME: decref PyObject arguments ? */ RPY_GIL_RELEASE(is_threaded, gstate); return 0; } result = PyEval_CallObject(showFilesCallback, arglist); if (PyErr_Occurred()) { /* All R actions should be stopped since the Python callback failed, and the Python exception raised up.*/ /* FIXME: Print the exception in the meanwhile */ PyErr_Print(); PyErr_Clear(); Py_XDECREF(arglist); RPY_GIL_RELEASE(is_threaded, gstate); return 0; } if (result == NULL) { /* FIXME: can this be reached ? result == NULL while no error ? */ printf("Error: trouble with chooseFileCallback, we should not be here.\n"); Py_XDECREF(arglist); RPY_GIL_RELEASE(is_threaded, gstate); return 0; } /*FIXME: check that nothing is returned ? */ if (! 1) { Py_DECREF(result); PyErr_SetString(PyExc_TypeError, "Returned value should be None"); PyErr_Print(); PyErr_Clear(); Py_DECREF(arglist); RPY_GIL_RELEASE(is_threaded, gstate); return 0; } Py_DECREF(arglist); Py_DECREF(result); RPY_GIL_RELEASE(is_threaded, gstate); return 1; } static PyObject* cleanUpCallback = NULL; static PyObject* EmbeddedR_setCleanUp(PyObject *self, PyObject *args) { return EmbeddedR_setAnyCallback(self, args, &cleanUpCallback); } PyDoc_STRVAR(EmbeddedR_setCleanUp_doc, "Set the function called to clean up when exiting R."); static PyObject * EmbeddedR_getCleanUp(PyObject *self, PyObject *args) { PyObject* res = EmbeddedR_getAnyCallback(self, args, cleanUpCallback); return res; } PyDoc_STRVAR(EmbeddedR_getCleanUp_doc, "Get the function called to clean up when exiting R."); extern SA_TYPE SaveAction; static void EmbeddedR_CleanUp(SA_TYPE saveact, int status, int runLast) { /* R_CleanUp is invoked at the end of the session to give the user the option of saving their data. If ask == SA_SAVEASK the user should be asked if possible (and this option should not occur in non-interactive use). If ask = SA_SAVE or SA_NOSAVE the decision is known. If ask = SA_DEFAULT use the SaveAction set at startup. In all these cases run .Last() unless quitting is cancelled. If ask = SA_SUICIDE, no save, no .Last, possibly other things. */ const int is_threaded = PyEval_ThreadsInitialized(); PyGILState_STATE gstate; if(saveact == SA_DEFAULT) { /* The normal case apart from R_Suicide */ saveact = SaveAction; } RPY_GIL_ENSURE(is_threaded, gstate); PyObject *arglist = Py_BuildValue("iii", saveact, status, runLast); PyObject *result = PyEval_CallObject(cleanUpCallback, arglist); PyObject* pythonerror = PyErr_Occurred(); if (pythonerror != NULL) { /* All R actions should be stopped since the Python callback failed, and the Python exception raised up.*/ /* FIXME: Print the exception in the meanwhile */ PyErr_Print(); PyErr_Clear(); } else { if (result == Py_None) jump_to_toplevel(); int res_true = PyObject_IsTrue(result); switch(res_true) { case -1: printf("*** error while testing of the value returned from the cleanup callback is true.\n"); jump_to_toplevel(); break; case 1: saveact = SA_SAVE; break; case 0: saveact = SA_NOSAVE; break; } Py_XDECREF(arglist); RPY_GIL_RELEASE(is_threaded, gstate); } if (saveact == SA_SAVEASK) { #if ! (defined(Win32) || defined(Win64)) if (R_Interactive) { #endif /* if (cleanUpCallback != NULL) { */ /* } */ /* } else { */ saveact = SaveAction; /* } */ #if ! (defined(Win32) || defined(Win64)) } else { saveact = SaveAction; } #endif } switch (saveact) { case SA_SAVE: if(runLast) R_dot_Last(); if(R_DirtyImage) R_SaveGlobalEnv(); /* if (CharacterMode == RGui) { */ /* R_setupHistory(); /\* re-read the history size and filename *\/ */ /* wgl_savehistory(R_HistoryFile, R_HistorySize); */ /* } else if(R_Interactive && CharacterMode == RTerm) { */ /* R_setupHistory(); /\* re-read the history size and filename *\/ */ /* gl_savehistory(R_HistoryFile, R_HistorySize); */ /* } */ break; case SA_NOSAVE: if(runLast) R_dot_Last(); break; case SA_SUICIDE: default: break; } R_RunExitFinalizers(); /* editorcleanall(); */ /* CleanEd(); */ R_CleanTempDir(); Rf_KillAllDevices(); /* AllDevicesKilled = TRUE; */ /* if (R_Interactive && CharacterMode == RTerm) */ /* SetConsoleTitle(oldtitle); */ /* if (R_CollectWarnings && saveact != SA_SUICIDE */ /* && CharacterMode == RTerm) */ /* PrintWarnings(); */ /* app_cleanup(); */ /* RConsole = NULL; */ /* if(ifp) fclose(ifp); */ /* if(ifile[0]) unlink(ifile); */ /* exit(status); */ } /* --- Initialize and terminate an embedded R --- */ static PyObject* EmbeddedR_getinitoptions(PyObject *self) { return initOptions; } PyDoc_STRVAR(EmbeddedR_get_initoptions_doc, "\ Get the options used to initialize R.\ "); static PyObject* EmbeddedR_setinitoptions(PyObject *self, PyObject *tuple) { if (rpy_has_status(RPY_R_INITIALIZED)) { PyErr_Format(PyExc_RuntimeError, "Options cannot be set once R has been initialized."); return NULL; } int istuple = PyTuple_Check(tuple); if (! istuple) { PyErr_Format(PyExc_ValueError, "Parameter should be a tuple."); return NULL; } /* now test that all elements of the tuple are strings (Python2) * or bytes (Python3). */ Py_ssize_t ii; for (ii = 0; ii < PyTuple_GET_SIZE(tuple); ii++) { #if (PY_VERSION_HEX < 0x03010000) if (! PyString_Check(PyTuple_GET_ITEM(tuple, ii))) { PyErr_Format(PyExc_ValueError, "All options should be strings."); return NULL; } #else if (! PyBytes_Check(PyTuple_GET_ITEM(tuple, ii))) { PyErr_Format(PyExc_ValueError, "All options should be bytes."); return NULL; } #endif } Py_DECREF(initOptions); Py_INCREF(tuple); initOptions = tuple; Py_INCREF(Py_None); return Py_None; } PyDoc_STRVAR(EmbeddedR_set_initoptions_doc, "\ Set the options used to initialize R.\ "); /* --- R_ProcessEvents ---*/ static PyObject* EmbeddedR_ProcessEvents(PyObject *self) { if (! (rpy_has_status(RPY_R_INITIALIZED))) { PyErr_Format(PyExc_RuntimeError, "R should not process events before being initialized."); return NULL; } if (rpy_has_status(RPY_R_BUSY)) { PyErr_Format(PyExc_RuntimeError, "Concurrent access to R is not allowed."); return NULL; } embeddedR_setlock(); #if defined(HAVE_AQUA) || (defined(Win32) || defined(Win64)) /* Can the call to R_ProcessEvents somehow fail ? */ R_ProcessEvents(); #endif #if ! (defined(Win32) || defined(Win64)) R_runHandlers(R_InputHandlers, R_checkActivity(0, 1)); #endif embeddedR_freelock(); Py_INCREF(Py_None); return Py_None; } PyDoc_STRVAR(EmbeddedR_ProcessEvents_doc, "Process R events. This function is a simple wrapper around\n" "R_ProcessEvents (on win32 and MacOS X-Aqua)\n" "and R_runHandlers (on other platforms)."); #if defined(Win32) || defined(Win64) void win32CallBack() { /* called during i/o, eval, graphics in ProcessEvents */ } void Re_Busy(int which) { } #endif static void end_r(void) { /* taken from the tests/Embedded/shutdown.c in the R source tree */ R_dot_Last(); R_RunExitFinalizers(); /* CleanEd(); */ Rf_KillAllDevices(); R_CleanTempDir(); /* PrintWarnings(); */ R_gc(); /* */ /*NOTE: This is only part of the procedure to terminate R - more in EmbeddedR_end()*/ } static PyObject* EmbeddedR_init(PyObject *self) { static int status; if (rpy_has_status(RPY_R_INITIALIZED)) { #if (PY_VERSION_HEX < 0x03010000) return PyInt_FromLong(status); #else return PyLong_FromLong(status); #endif /* PyErr_Format(PyExc_RuntimeError, "R can only be initialized once."); */ /* return NULL; */ } const Py_ssize_t n_args = PySequence_Size(initOptions); char *options[n_args]; PyObject *opt_string; Py_ssize_t ii; for (ii = 0; ii < n_args; ii++) { opt_string = PyTuple_GetItem(initOptions, ii); #if (PY_VERSION_HEX < 0x03010000) options[ii] = PyString_AsString(opt_string); #else options[ii] = PyBytes_AsString(opt_string); #endif } #if ! (defined(Win32) || defined(Win64)) #else /* --- Win32 --- */ structRstart rp; Rp = &rp; char RHome[260]; char RUser[260]; R_setStartTime(); R_DefParams(Rp); if (getenv("R_HOME")) { strcpy(RHome, getenv("R_HOME")); } else { PyErr_Format(PyExc_RuntimeError, "R_HOME not defined."); return NULL; } Rp->rhome = RHome; if (getenv("R_USER")) { strcpy(RUser, getenv("R_USER")); } else if (getenv("HOME")) { strcpy(RUser, getenv("HOME")); } else if (getenv("HOMEDIR")) { strcpy(RUser, getenv("HOMEDIR")); strcat(RUser, getenv("HOMEPATH")); } else { PyErr_Format(PyExc_RuntimeError, "R_USER not defined."); return NULL; } Rp->home = RUser; /* Rp->CharacterMode = LinkDLL; */ Rp->ReadConsole = EmbeddedR_ReadConsole; Rp->WriteConsole = NULL; Rp->WriteConsoleEx = EmbeddedR_WriteConsole; Rp->Busy = Re_Busy; Rp->ShowMessage = EmbeddedR_ShowMessage; /* Rp->FlushConsole = EmbeddedR_FlushConsole; */ Rp->CallBack = win32CallBack; Rp->R_Quiet = FALSE; Rp->R_Interactive = TRUE; Rp->RestoreAction = SA_RESTORE; Rp->SaveAction = SA_SAVEASK; /* hocus-pocus for R-win32 - just don't ask why*/ R_SetParams(Rp); R_SizeFromEnv(Rp); R_SetParams(Rp); setup_term_ui(); #endif #ifdef RIF_HAS_RSIGHAND R_SignalHandlers = 0; #endif /* int status = Rf_initEmbeddedR(n_args, options);*/ status = Rf_initialize_R(n_args, options); if (status < 0) { PyErr_SetString(PyExc_RuntimeError, "Error while initializing R."); return NULL; } #if ! (defined(Win32) | defined(Win64)) R_Interactive = TRUE; #endif #ifdef RIF_HAS_RSIGHAND R_SignalHandlers = 0; #endif #ifdef R_INTERFACE_PTRS ptr_R_CleanUp = EmbeddedR_CleanUp; /* Redirect R console output */ ptr_R_ShowMessage = EmbeddedR_ShowMessage; ptr_R_WriteConsole = EmbeddedR_WriteConsole; ptr_R_FlushConsole = EmbeddedR_FlushConsole; R_Outputfile = NULL; R_Consolefile = NULL; /* Redirect R console input */ ptr_R_ReadConsole = EmbeddedR_ReadConsole; ptr_R_ChooseFile = EmbeddedR_ChooseFile; ptr_R_ShowFiles = EmbeddedR_ShowFiles; #endif #ifdef CSTACK_DEFNS /* Taken from JRI: * disable stack checking, because threads will thow it off */ R_CStackLimit = (uintptr_t) -1; /* --- */ #endif setup_Rmainloop(); Py_XDECREF(embeddedR_isInitialized); embeddedR_status = RPY_R_INITIALIZED; embeddedR_isInitialized = Py_True; Py_INCREF(embeddedR_isInitialized); /* FIXME: Attempt at using a container distinct from R's PreciousList */ /* (currently replaced by a Python dict and R's PreciousList) */ //PROTECT(RPY_R_Precious = allocVector(LISTSXP, 0)); //UNPROTECT(1); //R_PreserveObject(RPY_R_Precious); SexpObject *sexpobj_ptr = Rpy_PreserveObject(R_GlobalEnv); Rpy_ReleaseObject(globalEnv->sObj->sexp); globalEnv->sObj = sexpobj_ptr; sexpobj_ptr = Rpy_PreserveObject(R_BaseNamespace); Rpy_ReleaseObject(baseNameSpaceEnv->sObj->sexp); baseNameSpaceEnv->sObj = sexpobj_ptr; sexpobj_ptr = Rpy_PreserveObject(R_EmptyEnv); Rpy_ReleaseObject(emptyEnv->sObj->sexp); emptyEnv->sObj = sexpobj_ptr; sexpobj_ptr = Rpy_PreserveObject(R_MissingArg); Rpy_ReleaseObject(((PySexpObject *)MissingArg_Type_New(0))->sObj->sexp); ((PySexpObject *)MissingArg_Type_New(0))->sObj = sexpobj_ptr; sexpobj_ptr = Rpy_PreserveObject(R_NilValue); Rpy_ReleaseObject(((PySexpObject *)RNULL_Type_New(0))->sObj->sexp); ((PySexpObject *)RNULL_Type_New(0))->sObj = sexpobj_ptr; sexpobj_ptr = Rpy_PreserveObject(R_UnboundValue); Rpy_ReleaseObject(((PySexpObject *)UnboundValue_Type_New(0))->sObj->sexp); ((PySexpObject *)UnboundValue_Type_New(0))->sObj = sexpobj_ptr; sexpobj_ptr = Rpy_PreserveObject(R_NilValue); Rpy_ReleaseObject(rpy_R_NilValue->sObj->sexp); rpy_R_NilValue->sObj = sexpobj_ptr; errMessage_SEXP = findVar(install("geterrmessage"), R_BaseNamespace); #if (PY_VERSION_HEX < 0x03010000) PyObject *res = PyInt_FromLong(status); #else PyObject *res = PyLong_FromLong(status); #endif /* type tag for Python external methods */ SEXP type_tag; PROTECT(type_tag = allocVector(STRSXP, 1)); SET_STRING_ELT(type_tag, 0, mkChar("Python")); //R_PreserveObject(type_tag); sexpobj_ptr = Rpy_PreserveObject(type_tag); UNPROTECT(1); Rpy_ReleaseObject(R_PyObject_type_tag->sObj->sexp); R_PyObject_type_tag->sObj = sexpobj_ptr; /* register the symbols */ RegisterExternalSymbols(); /*FIXME: setting readline variables so R's oddly static declarations become harmless*/ #ifdef HAS_READLINE char *rl_completer, *rl_basic; rl_completer = strndup(rl_completer_word_break_characters, 200); rl_completer_word_break_characters = rl_completer; rl_basic = strndup(rl_basic_word_break_characters, 200); rl_basic_word_break_characters = rl_basic; #endif /* --- */ #ifdef RPY_VERBOSE printf("R initialized - status: %i\n", status); #endif int register_endr = Py_AtExit( end_r ); if (register_endr != 0) { register_endr = PyErr_WarnEx(PyExc_RuntimeWarning, "'rpy2.rinterface.endr' could not be " "registered as a cleanup function " "(limit exceed).", 1); /*FIXME: what if -1 returned ? calling end_r will leave the process unable to try to initialize R anyway. */ } return res; } PyDoc_STRVAR(EmbeddedR_init_doc, "\ Initialize an embedded R.\ "); static PyObject* EmbeddedR_end(PyObject *self, Py_ssize_t fatal) { /* FIXME: Have a reference count for R objects known to Python. * ending R will not be possible until all such objects are already * deallocated in Python ? *other possibility would be to have a fallback for "unreachable" objects ? */ end_r(); Rf_endEmbeddedR((int)fatal); embeddedR_status = embeddedR_status & (! RPY_R_INITIALIZED); SexpObject *sexpobj_ptr = Rpy_PreserveObject(R_EmptyEnv); Rpy_ReleaseObject(globalEnv->sObj->sexp); globalEnv->sObj = sexpobj_ptr; sexpobj_ptr = Rpy_PreserveObject(R_EmptyEnv); Rpy_ReleaseObject(baseNameSpaceEnv->sObj->sexp); baseNameSpaceEnv->sObj = sexpobj_ptr; sexpobj_ptr = Rpy_PreserveObject(R_EmptyEnv); Rpy_ReleaseObject(emptyEnv->sObj->sexp); emptyEnv->sObj = sexpobj_ptr; errMessage_SEXP = R_NilValue; /* FIXME: Is it possible to reinitialize R later ? * Py_XDECREF(embeddedR_isInitialized); * embeddedR_isInitialized = Py_False; *Py_INCREF(embeddedR_isInitialized); */ Py_RETURN_NONE; } PyDoc_STRVAR(EmbeddedR_end_doc, "endEmbeddedR()\n\ \n\ Terminate an embedded R."); static PyObject* EmbeddedR_setinteractive(PyObject *self, PyObject *status) { if (! PyBool_Check(status)) { PyErr_SetString(PyExc_ValueError, "The status must be a boolean"); return NULL; } int rtruefalse; if (PyObject_IsTrue(status)) { rtruefalse = TRUE; } else { rtruefalse = FALSE; } #if defined(Win32) || defined(Win64) Rp->R_Interactive = rtruefalse; #else R_Interactive = rtruefalse; #endif Py_RETURN_NONE; } PyDoc_STRVAR(EmbeddedR_setinteractive_doc, "set_interactive(status)\n\ \n\ Set the interactivity status for R.\n\ (This function exists for experimentation purposes,\n\ and could lead to an unpredictable outcome.)"); /* Create a Python exception from an R error */ static void EmbeddedR_exception_from_errmessage(void) { SEXP expr, res; /* PROTECT(errMessage_SEXP) */ PROTECT(expr = allocVector(LANGSXP, 1)); SETCAR(expr, errMessage_SEXP); PROTECT(res = Rf_eval(expr, R_GlobalEnv)); const char *message = CHARACTER_VALUE(res); PyErr_SetString(RPyExc_RuntimeError, message); UNPROTECT(2); } PyDoc_STRVAR(EmbeddedR_parse_doc, "parse(string)\n\ \n\ Parse a string as R code.\n"); static PySexpObject* EmbeddedR_parse(PyObject *self, PyObject *pystring) { SEXP cmdSexp, cmdexpr; PySexpObject *cmdpy; ParseStatus status; if (! (rpy_has_status(RPY_R_INITIALIZED))) { PyErr_Format(PyExc_RuntimeError, "R must be initialized before any call to R functions is possible."); return NULL; } PyObject *pybytes; char *string; #if (PY_VERSION_HEX < 0x03010000) if (PyUnicode_Check(pystring)) { pybytes = PyUnicode_AsUTF8String(pystring); string = PyBytes_AsString(pybytes); } else if (PyString_Check(pystring)) { string = PyString_AsString(pystring); } else { PyErr_Format(PyExc_ValueError, "The object to parse must be a string."); return NULL; } #else if (! PyUnicode_Check(pystring)) { PyErr_Format(PyExc_ValueError, "The object to parse must be a unicode string"); return NULL; } pybytes = PyUnicode_AsUTF8String(pystring); string = PyBytes_AsString(pybytes); #endif embeddedR_setlock(); PROTECT(cmdSexp = allocVector(STRSXP, 1)); SET_STRING_ELT(cmdSexp, 0, mkChar(string)); #if (PY_VERSION_HEX >= 0x03010000) Py_DECREF(pybytes); #endif cmdexpr = PROTECT(R_ParseVector(cmdSexp, -1, &status, R_NilValue)); if (status != PARSE_OK) { UNPROTECT(2); embeddedR_freelock(); PyErr_Format(PyExc_ValueError, "Error while parsing the string."); /*FIXME: Fetch parsing error details*/ return NULL; } cmdpy = newPySexpObject(cmdexpr); UNPROTECT(2); embeddedR_freelock(); return cmdpy; } /* * Access to R objects through Python objects */ /* * Closure-type Sexp. */ /* Evaluate a SEXP. It must be constructed by hand. It raises a Python exception if an error ocurred during the evaluation */ SEXP do_eval_expr(SEXP expr_R, SEXP env_R) { SEXP res_R = R_NilValue; int errorOccurred = 0; /* FIXME: if env_R is null, use R_BaseEnv * shouldn't it be R_GlobalContext (but then it throws a NULL error) ? */ if (isNull(env_R)) { /* env_R = R_BaseEnv; */ env_R = R_GlobalEnv; /* env_R = R_GlobalContext; */ } /* Py_BEGIN_ALLOW_THREADS */ #ifdef _WIN32 last_sighandler = PyOS_setsig(SIGBREAK, interrupt_R); #else last_sighandler = PyOS_setsig(SIGINT, interrupt_R); #endif python_sighandler = last_sighandler; /* FIXME: evaluate expression in the given environment */ interrupted = 0; res_R = R_tryEval(expr_R, env_R, &errorOccurred); /* Py_END_ALLOW_THREADS */ #ifdef _WIN32 PyOS_setsig(SIGBREAK, python_sighandler); #else PyOS_setsig(SIGINT, python_sighandler); #endif if (errorOccurred) { res_R = R_NilValue; if (interrupted) { printf("Keyboard interrupt.\n"); PyErr_SetNone(PyExc_KeyboardInterrupt); /* FIXME: handling of interruptions */ } else { EmbeddedR_exception_from_errmessage(); } } return res_R; } static PyTypeObject EnvironmentSexp_Type; /* This is the method to call when invoking a 'Sexp' */ static PyObject * Sexp_rcall(PyObject *self, PyObject *args) { if (! (rpy_has_status(RPY_R_INITIALIZED))) { PyErr_Format(PyExc_RuntimeError, "R must be initialized before any call to R functions is possible."); return NULL; } PyObject *params, *env; if (! PyArg_ParseTuple(args, "OO", ¶ms, &env)) { return NULL; } if (! PyTuple_Check(params)) { PyErr_Format(PyExc_ValueError, "The first parameter must be a tuple."); return NULL; } if (! PyObject_IsInstance(env, (PyObject*)&EnvironmentSexp_Type)) { PyErr_Format(PyExc_ValueError, "The second parameter must be an EnvironmentSexp_Type."); return NULL; } if (rpy_has_status(RPY_R_BUSY)) { PyErr_Format(PyExc_RuntimeError, "Concurrent access to R is not allowed."); return NULL; } embeddedR_setlock(); SEXP call_R, c_R, res_R; int nparams; SEXP tmp_R, fun_R; int protect_count = 0; if (! PySequence_Check(args)) { PyErr_Format(PyExc_ValueError, "The one argument to the function must implement the sequence protocol."); embeddedR_freelock(); return NULL; } nparams = PySequence_Length(params); /* A SEXP with the function to call and the arguments and keywords. */ PROTECT(c_R = call_R = allocList(nparams+1)); protect_count++; SET_TYPEOF(call_R, LANGSXP); fun_R = RPY_SEXP((PySexpObject *)self); if (! fun_R) { PyErr_Format(PyExc_ValueError, "Underlying R function is a NULL SEXP."); goto fail; } SETCAR(c_R, fun_R); c_R = CDR(c_R); int arg_i; int on_the_fly; /* boolean flag to tell whether a given parameter is * converted on the fly */ PyObject *tmp_obj; /* temp object to iterate through the args tuple*/ /* named args */ PyObject *argValue, *argName; #if (PY_VERSION_HEX < 0x03010000) #else PyObject *pybytes; #endif const char *argNameString; unsigned int addArgName; Py_ssize_t item_length; /* Loop through the elements in the sequence "args" * and build the R call. * Each element in the sequence is expected to be a tuple * of length 2 (name, value). */ for (arg_i=0; arg_i= 0x03010000) Py_DECREF(pybytes); #endif } c_R = CDR(c_R); /* if on-the-fly conversion, UNPROTECT the newly created * tmp_R in order to avoid overflowing the protection stack. */ if (on_the_fly) { UNPROTECT(1); protect_count--; } } /* Py_BEGIN_ALLOW_THREADS */ /* FIXME: R_GlobalContext ? */ PROTECT(res_R = do_eval_expr(call_R, RPY_SEXP((PySexpObject *)env))); protect_count += 1; if (PyErr_Occurred()) { /* Python exception set during the call to do_eval_expr() */ if (res_R == R_NilValue) { UNPROTECT(protect_count); embeddedR_freelock(); return NULL; } else { printf("Warning: Exception while result not R_NilValue.\n"); } } /* Unexplained hidding of the function R_PrintWarnings() * in the codebase (and inquiries about alternative options * on the R-dev list completely ignored). */ /* FIXME: standardize R outputs */ /* extern void Rf_PrintWarnings(void); */ /* Rf_PrintWarnings(); /\* show any warning messages *\/ */ PyObject *res = (PyObject *)newPySexpObject(res_R); UNPROTECT(protect_count); embeddedR_freelock(); return res; fail: UNPROTECT(protect_count); embeddedR_freelock(); return NULL; } PyDoc_STRVAR(SexpClosure_rcall_doc, "S.rcall(args, env) -> Sexp\n\n" "Return the result of evaluating the underlying R function" " as an instance of type rpy2.rinterface.Sexp," " args being a sequence of two-elements items" " and env a instance of type rpy2.rinterface.SexpEnvironment."); /* This is merely a wrapper around Sexp_rcall, * putting named and unnamed arguments into a tuple of name, value pairs. */ static PyObject * Sexp_call(PyObject *self, PyObject *args, PyObject *kwds) { Py_ssize_t n_unnamedparams, n_namedparams, n_params, p_i, ppos; PyObject *tmp_pair, *tmp_key, *tmp_value, *params, *new_args, *res; n_unnamedparams = PySequence_Length(args); /* test present in Objects/funcobject.c in the Python source * Missing keywords do not translate to an empty dict. */ if (kwds != NULL && PyDict_Check(kwds)) { n_namedparams = PyDict_Size(kwds); } else { n_namedparams = 0; } n_params = n_unnamedparams + n_namedparams; /* Tuple to hold (name, value) pairs for Sexp_rcall(). * This must be DECREFed when exiting. */ params = PyTuple_New(n_params); /* Populate with unnamed parameters first */ for (p_i = 0; p_i < n_unnamedparams; p_i++) { tmp_pair = PyTuple_New(2); /* key/name is None */ /* PyTuple_SET_ITEM() "steals" a reference, so INCREF necessary */ Py_INCREF(Py_None); PyTuple_SET_ITEM(tmp_pair, 0, Py_None); /* value */ tmp_value = PyTuple_GET_ITEM(args, p_i); Py_INCREF(tmp_value); PyTuple_SET_ITEM(tmp_pair, 1, tmp_value); PyTuple_SET_ITEM(params, p_i, tmp_pair); /* PyTuple_SET_ITEM() "steals" a reference, so no DECREF necessary */ } if (n_namedparams > 0) { ppos = 0; p_i = 0; while(PyDict_Next(kwds, &ppos, &tmp_key, &tmp_value)) { tmp_pair = PyTuple_New(2); /* PyTuple_SET_ITEM() "steals" a reference, so no DECREF necessary */ Py_INCREF(tmp_key); PyTuple_SET_ITEM(tmp_pair, 0, tmp_key); Py_INCREF(tmp_value); PyTuple_SET_ITEM(tmp_pair, 1, tmp_value); PyTuple_SET_ITEM(params, p_i + n_unnamedparams, tmp_pair); p_i++; /* PyTuple_SET_ITEM() "steals" a reference, so no DECREF necessary */ } } /* Build a tuple with the parameters for Sexp_rcall(): - params built above - an R environment */ new_args = PyTuple_New(2); PyTuple_SET_ITEM(new_args, 0, params); /* reference to params stolen, no need to change refcount for params */ Py_INCREF(globalEnv); PyTuple_SET_ITEM(new_args, 1, (PyObject *)globalEnv); res = Sexp_rcall(self, new_args); Py_DECREF(new_args); return res; } static PySexpObject* SexpClosure_env_get(PyObject *self) { SEXP closureEnv, sexp; sexp = RPY_SEXP((PySexpObject*)self); if (! sexp) { PyErr_Format(PyExc_ValueError, "NULL SEXP."); return NULL; } if (rpy_has_status(RPY_R_BUSY)) { PyErr_Format(PyExc_RuntimeError, "Concurrent access to R is not allowed."); return NULL; } embeddedR_setlock(); PROTECT(closureEnv = CLOENV(sexp)); embeddedR_freelock(); PySexpObject *res = newPySexpObject(closureEnv); UNPROTECT(1); return res; } PyDoc_STRVAR(SexpClosure_env_doc, "\n\ Environment the object is defined in.\n\ This corresponds to the C-level function CLOENV(SEXP).\n\ \n\ :rtype: :class:`rpy2.rinterface.SexpEnvironment`\n"); static PyMethodDef ClosureSexp_methods[] = { {"rcall", (PyCFunction)Sexp_rcall, METH_VARARGS, SexpClosure_rcall_doc}, {NULL, NULL} /* sentinel */ }; static PyGetSetDef ClosureSexp_getsets[] = { {"closureenv", (getter)SexpClosure_env_get, (setter)0, SexpClosure_env_doc}, {NULL, NULL, NULL, NULL} }; PyDoc_STRVAR(ClosureSexp_Type_doc, "A R object that is a closure, that is a function. \ In R a function is defined within an enclosing \ environment, thus the name closure. \ In Python, 'nested scopes' could be the closest similar thing.\ "); static int ClosureSexp_init(PyObject *self, PyObject *args, PyObject *kwds); static PyTypeObject ClosureSexp_Type = { /* The ob_type field must be initialized in the module init function * to be portable to Windows without using C++. */ #if (PY_VERSION_HEX < 0x03010000) PyObject_HEAD_INIT(NULL) 0, /*ob_size*/ #else PyVarObject_HEAD_INIT(NULL, 0) #endif "rpy2.rinterface.SexpClosure", /*tp_name*/ sizeof(PySexpObject), /*tp_basicsize*/ 0, /*tp_itemsize*/ /* methods */ 0, /*tp_dealloc*/ 0, /*tp_print*/ 0, /*tp_getattr*/ 0, /*tp_setattr*/ 0, /*tp_compare*/ 0, /*tp_repr*/ 0, /*tp_as_number*/ 0, /*tp_as_sequence*/ 0, /*tp_as_mapping*/ 0, /*tp_hash*/ Sexp_call, /*tp_call*/ 0, /*tp_str*/ 0, /*tp_getattro*/ 0, /*tp_setattro*/ 0, /*tp_as_buffer*/ Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /*tp_flags*/ ClosureSexp_Type_doc, /*tp_doc*/ 0, /*tp_traverse*/ 0, /*tp_clear*/ 0, /*tp_richcompare*/ 0, /*tp_weaklistoffset*/ 0, /*tp_iter*/ 0, /*tp_iternext*/ ClosureSexp_methods, /*tp_methods*/ 0, /*tp_members*/ ClosureSexp_getsets, /*tp_getset*/ &Sexp_Type, /*tp_base*/ 0, /*tp_dict*/ 0, /*tp_descr_get*/ 0, /*tp_descr_set*/ 0, /*tp_dictoffset*/ (initproc)ClosureSexp_init, /*tp_init*/ 0, /*tp_alloc*/ 0, /*tp_new*/ 0, /*tp_free*/ 0 /*tp_is_gc*/ }; static int ClosureSexp_init(PyObject *self, PyObject *args, PyObject *kwds) { PyObject *object; PyObject *copy; static char *kwlist[] = {"sexpclos", "copy", NULL}; /* FIXME: handle the copy argument */ if (! PyArg_ParseTupleAndKeywords(args, kwds, "O|O!", kwlist, &object, &PyBool_Type, ©)) { return -1; } if (PyObject_IsInstance(object, (PyObject*)&ClosureSexp_Type)) { /* call parent's constructor */ if (Sexp_init(self, args, NULL) == -1) { PyErr_Format(PyExc_RuntimeError, "Error initializing instance."); return -1; } } else { PyErr_Format(PyExc_ValueError, "Cannot instantiate from this type."); return -1; } return 0; } /* --- */ static PyObject* EnvironmentSexp_findVar(PyObject *self, PyObject *args, PyObject *kwds) { char *name; SEXP res_R = NULL; PySexpObject *res = NULL; PyObject *wantFun = Py_False; static char *kwlist[] = {"name", "wantfun", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|O!", kwlist, &name, &PyBool_Type, &wantFun)) { return NULL; } if (rpy_has_status(RPY_R_BUSY)) { PyErr_Format(PyExc_RuntimeError, "Concurrent access to R is not allowed."); return NULL; } embeddedR_setlock(); const SEXP rho_R = RPY_SEXP((PySexpObject *)self); if (! rho_R) { PyErr_Format(PyExc_ValueError, "C-NULL SEXP."); embeddedR_freelock(); return NULL; } if (!isEnvironment(rho_R)) { PyErr_Format(PyExc_ValueError, "Trying to apply to a non-environment (typeof is %i).", TYPEOF(rho_R)); embeddedR_freelock(); return NULL; } if (strlen(name) == 0) { PyErr_Format(PyExc_ValueError, "Invalid name."); embeddedR_freelock(); return NULL; } if (rho_R == R_EmptyEnv) { PyErr_Format(PyExc_LookupError, "Fatal error: R_EmptyEnv."); return NULL; } if (PyObject_IsTrue(wantFun)) { res_R = PyRinterface_FindFun(install(name), rho_R); } else { res_R = findVar(install(name), rho_R); } if (res_R != R_UnboundValue) { /* FIXME rpy_only */ res = newPySexpObject(res_R); } else { PyErr_Format(PyExc_LookupError, "'%s' not found", name); res = NULL; } embeddedR_freelock(); return (PyObject *)res; } PyDoc_STRVAR(EnvironmentSexp_findVar_doc, "Find a name/symbol in the environment, following the chain of enclosing\n" "environments until either the topmost environment is reached or the name\n" "is found, and returned the associated object. \n" "The optional parameter `wantfun` indicates whether functions should be\n" "returned or not.\n" ":rtype: instance of type of subtype :class:`rpy2.rinterface.Sexp`"); static PyObject* EnvironmentSexp_frame(PyObject *self) { if (! (rpy_has_status(RPY_R_INITIALIZED))) { PyErr_Format(PyExc_RuntimeError, "R must be initialized before environments can be accessed."); return NULL; } SEXP res_R = NULL; PySexpObject *res; if (rpy_has_status(RPY_R_BUSY)) { PyErr_Format(PyExc_RuntimeError, "Concurrent access to R is not allowed."); return NULL; } embeddedR_setlock(); res_R = FRAME(RPY_SEXP((PySexpObject *)self)); res = newPySexpObject(res_R); return (PyObject *)res; } PyDoc_STRVAR(EnvironmentSexp_frame_doc, "Return the frame the environment is in."); static PyObject* EnvironmentSexp_enclos(PyObject *self) { if (! (rpy_has_status(RPY_R_INITIALIZED))) { PyErr_Format(PyExc_RuntimeError, "R must be initialized before environments can be accessed."); return NULL; } if (rpy_has_status(RPY_R_BUSY)) { PyErr_Format(PyExc_RuntimeError, "Concurrent access to R is not allowed."); return NULL; } embeddedR_setlock(); SEXP res_R = NULL; PySexpObject *res; res_R = ENCLOS(RPY_SEXP((PySexpObject *)self)); res = newPySexpObject(res_R); embeddedR_freelock(); return (PyObject *)res; } PyDoc_STRVAR(EnvironmentSexp_enclos_doc, "Return the enclosure the environment is in."); static PyMethodDef EnvironmentSexp_methods[] = { {"get", (PyCFunction)EnvironmentSexp_findVar, METH_VARARGS | METH_KEYWORDS, EnvironmentSexp_findVar_doc}, {"frame", (PyCFunction)EnvironmentSexp_frame, METH_NOARGS, EnvironmentSexp_frame_doc}, {"enclos", (PyCFunction)EnvironmentSexp_enclos, METH_NOARGS, EnvironmentSexp_enclos_doc}, {NULL, NULL} /* sentinel */ }; static PySexpObject* EnvironmentSexp_subscript(PyObject *self, PyObject *key) { const char *name; SEXP res_R = NULL; #if (PY_VERSION_HEX < 0x03010000) if (!PyString_Check(key)) { PyErr_Format(PyExc_ValueError, "Keys must be string objects."); return NULL; } #else if (!PyUnicode_Check(key)) { PyErr_Format(PyExc_ValueError, "Keys must be unicode string objects."); return NULL; } #endif #if (PY_VERSION_HEX < 0x03010000) name = PyString_AsString(key); #else PyObject *pybytes = PyUnicode_AsLatin1String(key); if (pybytes == NULL) { return NULL; } name = PyBytes_AsString(pybytes); #endif if (strlen(name) == 0) { PyErr_Format(PyExc_KeyError, "%s", name); #if (PY_VERSION_HEX >= 0x03010000) Py_DECREF(pybytes); #endif return NULL; } if (rpy_has_status(RPY_R_BUSY)) { PyErr_Format(PyExc_RuntimeError, "Concurrent access to R is not allowed."); #if (PY_VERSION_HEX >= 0x03010000) Py_DECREF(pybytes); #endif return NULL; } embeddedR_setlock(); SEXP rho_R = RPY_SEXP((PySexpObject *)self); if (! rho_R) { PyErr_Format(PyExc_ValueError, "C-NULL SEXP."); embeddedR_freelock(); #if (PY_VERSION_HEX >= 0x03010000) Py_DECREF(pybytes); #endif return NULL; } res_R = findVarInFrame(rho_R, install(name)); if (res_R != R_UnboundValue) { #if (PY_VERSION_HEX >= 0x03010000) Py_DECREF(pybytes); #endif embeddedR_freelock(); return newPySexpObject(res_R); } PyErr_Format(PyExc_LookupError, "'%s' not found", name); #if (PY_VERSION_HEX >= 0x03010000) Py_DECREF(pybytes); #endif embeddedR_freelock(); return NULL; } static int EnvironmentSexp_ass_subscript(PyObject *self, PyObject *key, PyObject *value) { const char *name; #if (PY_VERSION_HEX < 0x03010000) if (!PyString_Check(key)) { PyErr_Format(PyExc_ValueError, "Keys must be string objects."); return -1; } #else if (!PyUnicode_Check(key)) { PyErr_Format(PyExc_ValueError, "Keys must be unicode string objects."); return -1; } #endif #if (PY_VERSION_HEX < 0x03010000) name = PyString_AsString(key); #else PyObject *pybytes = PyUnicode_AsLatin1String(key); name = PyBytes_AsString(pybytes); #endif if (rpy_has_status(RPY_R_BUSY)) { PyErr_Format(PyExc_RuntimeError, "Concurrent access to R is not allowed."); #if (PY_VERSION_HEX >= 0x03010000) Py_DECREF(pybytes); #endif return -1; } embeddedR_setlock(); SEXP rho_R = RPY_SEXP((PySexpObject *)self); if (! rho_R) { PyErr_Format(PyExc_ValueError, "The environment has NULL SEXP."); embeddedR_freelock(); #if (PY_VERSION_HEX >= 0x03010000) Py_DECREF(pybytes); #endif return -1; } SEXP sym; if (value == NULL) { /* deletion of the item 'key' */ if (rho_R == R_BaseNamespace) { PyErr_Format(PyExc_ValueError, "Variables from the R base namespace cannot be removed."); embeddedR_freelock(); #if (PY_VERSION_HEX >= 0x03010000) Py_DECREF(pybytes); #endif return -1; } if (rho_R == R_BaseEnv) { PyErr_Format(PyExc_ValueError, "Variables from the R base environment cannot be removed."); embeddedR_freelock(); #if (PY_VERSION_HEX >= 0x03010000) Py_DECREF(pybytes); #endif return -1; } if (rho_R == R_EmptyEnv) { PyErr_Format(PyExc_ValueError, "Cannot remove variables from the empty environment."); embeddedR_freelock(); #if (PY_VERSION_HEX >= 0x03010000) Py_DECREF(pybytes); #endif return -1; } if (R_EnvironmentIsLocked(rho_R)) { PyErr_Format(PyExc_ValueError, "Cannot remove bindings from a locked environment."); embeddedR_freelock(); #if (PY_VERSION_HEX >= 0x03010000) Py_DECREF(pybytes); #endif return -1; } sym = Rf_install(name); SEXP res_rm; res_rm = findVarInFrame(rho_R, sym); if (res_rm == R_UnboundValue) { PyErr_Format(PyExc_KeyError, "'%s' not found", name); #if (PY_VERSION_HEX >= 0x03010000) Py_DECREF(pybytes); #endif embeddedR_freelock(); return -1; } res_rm = rpy_remove(sym, rho_R, R_BaseEnv); if (! res_rm) { embeddedR_freelock(); #if (PY_VERSION_HEX >= 0x03010000) Py_DECREF(pybytes); #endif PyErr_Format(PyExc_RuntimeError, "Could not remove variable from environment."); return -1; } else { embeddedR_freelock(); #if (PY_VERSION_HEX >= 0x03010000) Py_DECREF(pybytes); #endif return 0; } } int is_PySexpObject = PyObject_TypeCheck(value, &Sexp_Type); if (! is_PySexpObject) { #if (PY_VERSION_HEX >= 0x03010000) Py_DECREF(pybytes); #endif embeddedR_freelock(); PyErr_Format(PyExc_ValueError, "All parameters must be of type Sexp_Type."); return -1; } SEXP sexp_copy; SEXP sexp = RPY_SEXP((PySexpObject *)value); if (! sexp) { PyErr_Format(PyExc_ValueError, "The value has NULL SEXP."); embeddedR_freelock(); #if (PY_VERSION_HEX >= 0x03010000) Py_DECREF(pybytes); #endif return -1; } #if (PY_VERSION_HEX >= 0x03010000) Py_DECREF(pybytes); #endif sym = Rf_install(name); PROTECT(sexp_copy = Rf_duplicate(sexp)); Rf_defineVar(sym, sexp_copy, rho_R); UNPROTECT(1); embeddedR_freelock(); return 0; } static Py_ssize_t EnvironmentSexp_length(PyObject *self) { if (rpy_has_status(RPY_R_BUSY)) { PyErr_Format(PyExc_RuntimeError, "Concurrent access to R is not allowed."); return -1; } embeddedR_setlock(); SEXP rho_R = RPY_SEXP((PySexpObject *)self); if (! rho_R) { PyErr_Format(PyExc_ValueError, "The environment has NULL SEXP."); embeddedR_freelock(); return -1; } SEXP symbols; PROTECT(symbols = R_lsInternal(rho_R, TRUE)); Py_ssize_t len = (Py_ssize_t)GET_LENGTH(symbols); UNPROTECT(1); embeddedR_freelock(); return len; } static PyMappingMethods EnvironmentSexp_mappingMethods = { (lenfunc)EnvironmentSexp_length, /* mp_length */ (binaryfunc)EnvironmentSexp_subscript, /* mp_subscript */ (objobjargproc)EnvironmentSexp_ass_subscript /* mp_ass_subscript */ }; static PyObject* EnvironmentSexp_iter(PyObject *sexpEnvironment) { if (rpy_has_status(RPY_R_BUSY)) { PyErr_Format(PyExc_RuntimeError, "Concurrent access to R is not allowed."); return NULL; } embeddedR_setlock(); SEXP rho_R = RPY_SEXP((PySexpObject *)sexpEnvironment); if (! rho_R) { PyErr_Format(PyExc_ValueError, "The environment has NULL SEXP."); embeddedR_freelock(); return NULL; } SEXP symbols; PROTECT(symbols = R_lsInternal(rho_R, TRUE)); PySexpObject *seq = newPySexpObject(symbols); Py_INCREF(seq); UNPROTECT(1); PyObject *it = PyObject_GetIter((PyObject *)seq); Py_DECREF(seq); embeddedR_freelock(); return it; } PyDoc_STRVAR(EnvironmentSexp_Type_doc, "R object that is an environment.\n" "R environments can be seen as similar to Python\n" "dictionnaries, with the following twists:\n" "\n" "- an environment can be a list of frames to sequentially\n" "search into\n" "\n" "- the search can be recursively propagated to the enclosing\n" "environment whenever the key is not found (in that respect\n" "they can be seen as scopings).\n" "\n" "The subsetting operator \"[\" is made to match Python's\n" "behavior, that is the enclosing environments are not\n" "inspected upon absence of a given key.\n"); static int EnvironmentSexp_init(PyObject *self, PyObject *args, PyObject *kwds); static PyTypeObject EnvironmentSexp_Type = { /* The ob_type field must be initialized in the module init function * to be portable to Windows without using C++. */ #if (PY_VERSION_HEX < 0x03010000) PyObject_HEAD_INIT(NULL) 0, /*ob_size*/ #else PyVarObject_HEAD_INIT(NULL, 0) #endif "rpy2.rinterface.SexpEnvironment", /*tp_name*/ sizeof(PySexpObject), /*tp_basicsize*/ 0, /*tp_itemsize*/ /* methods */ 0, /*tp_dealloc*/ 0, /*tp_print*/ 0, /*tp_getattr*/ 0, /*tp_setattr*/ 0, /*tp_compare*/ 0, /*tp_repr*/ 0, /*tp_as_number*/ 0, /*tp_as_sequence*/ &EnvironmentSexp_mappingMethods,/*tp_as_mapping*/ 0, /*tp_hash*/ 0, /*tp_call*/ 0, /*tp_str*/ 0, /*tp_getattro*/ 0, /*tp_setattro*/ 0, /*tp_as_buffer*/ Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /*tp_flags*/ EnvironmentSexp_Type_doc, /*tp_doc*/ 0, /*tp_traverse*/ 0, /*tp_clear*/ 0, /*tp_richcompare*/ 0, /*tp_weaklistoffset*/ EnvironmentSexp_iter, /*tp_iter*/ 0, /*tp_iternext*/ EnvironmentSexp_methods, /*tp_methods*/ 0, /*tp_members*/ 0, /*tp_getset*/ &Sexp_Type, /*tp_base*/ 0, /*tp_dict*/ 0, /*tp_descr_get*/ 0, /*tp_descr_set*/ 0, /*tp_dictoffset*/ (initproc)EnvironmentSexp_init, /*tp_init*/ 0, /*tp_alloc*/ /* FIXME: add new method */ 0, /*tp_new*/ 0, /*tp_free*/ 0 /*tp_is_gc*/ }; static int EnvironmentSexp_init(PyObject *self, PyObject *args, PyObject *kwds) { PyObject *object; PyObject *copy = Py_False; static char *kwlist[] = {"sexpenv", "copy", NULL}; /* FIXME: handle the copy argument */ if (! PyArg_ParseTupleAndKeywords(args, kwds, "O|O!", kwlist, &object, &PyBool_Type, ©)) { return -1; } if (rpy_has_status(RPY_R_BUSY)) { PyErr_Format(PyExc_RuntimeError, "Concurrent access to R is not allowed."); return -1; } embeddedR_setlock(); if (PyObject_IsInstance(object, (PyObject*)&EnvironmentSexp_Type)) { /* call parent's constructor */ if (Sexp_init(self, args, NULL) == -1) { PyErr_Format(PyExc_RuntimeError, "Error initializing instance."); embeddedR_freelock(); return -1; } } else { PyErr_Format(PyExc_ValueError, "Cannot instantiate from this type."); embeddedR_freelock(); return -1; } embeddedR_freelock(); return 0; } /* FIXME: write more doc */ PyDoc_STRVAR(S4Sexp_Type_doc, "R object that is an 'S4 object'.\ Attributes can be accessed using the method 'do_slot'.\ "); static PyTypeObject S4Sexp_Type = { /* The ob_type field must be initialized in the module init function * to be portable to Windows without using C++. */ #if (PY_VERSION_HEX < 0x03010000) PyObject_HEAD_INIT(NULL) 0, /*ob_size*/ #else PyVarObject_HEAD_INIT(NULL, 0) #endif "rpy2.rinterface.SexpS4", /*tp_name*/ sizeof(PySexpObject), /*tp_basicsize*/ 0, /*tp_itemsize*/ /* methods */ 0, /*tp_dealloc*/ 0, /*tp_print*/ 0, /*tp_getattr*/ 0, /*tp_setattr*/ 0, /*tp_compare*/ 0, /*tp_repr*/ 0, /*tp_as_number*/ 0, /*tp_as_sequence*/ 0, /*tp_as_mapping*/ 0, /*tp_hash*/ 0, /*tp_call*/ 0, /*tp_str*/ 0, /*tp_getattro*/ 0, /*tp_setattro*/ 0, /*tp_as_buffer*/ Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /*tp_flags*/ S4Sexp_Type_doc, /*tp_doc*/ 0, /*tp_traverse*/ 0, /*tp_clear*/ 0, /*tp_richcompare*/ 0, /*tp_weaklistoffset*/ 0, /*tp_iter*/ 0, /*tp_iternext*/ 0, /*tp_methods*/ 0, /*tp_members*/ 0, /*tp_getset*/ &Sexp_Type, /*tp_base*/ 0, /*tp_dict*/ 0, /*tp_descr_get*/ 0, /*tp_descr_set*/ 0, /*tp_dictoffset*/ 0, /*tp_init*/ 0, /*tp_alloc*/ /*FIXME: add new method */ 0, /*tp_new*/ 0, /*tp_free*/ 0 /*tp_is_gc*/ }; /* FIXME: write more doc */ PyDoc_STRVAR(LangSexp_Type_doc, "Language object."); static PyTypeObject LangSexp_Type = { /* The ob_type field must be initialized in the module init function * to be portable to Windows without using C++. */ #if (PY_VERSION_HEX < 0x03010000) PyObject_HEAD_INIT(NULL) 0, /*ob_size*/ #else PyVarObject_HEAD_INIT(NULL, 0) #endif "rpy2.rinterface.SexpLang", /*tp_name*/ sizeof(PySexpObject), /*tp_basicsize*/ 0, /*tp_itemsize*/ /* methods */ 0, /*tp_dealloc*/ 0, /*tp_print*/ 0, /*tp_getattr*/ 0, /*tp_setattr*/ 0, /*tp_compare*/ 0, /*tp_repr*/ 0, /*tp_as_number*/ 0, /*tp_as_sequence*/ 0, /*tp_as_mapping*/ 0, /*tp_hash*/ 0, /*tp_call*/ 0, /*tp_str*/ 0, /*tp_getattro*/ 0, /*tp_setattro*/ 0, /*tp_as_buffer*/ Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /*tp_flags*/ LangSexp_Type_doc, /*tp_doc*/ 0, /*tp_traverse*/ 0, /*tp_clear*/ 0, /*tp_richcompare*/ 0, /*tp_weaklistoffset*/ 0, /*tp_iter*/ 0, /*tp_iternext*/ 0, /*tp_methods*/ 0, /*tp_members*/ 0, /*tp_getset*/ &Sexp_Type, /*tp_base*/ 0, /*tp_dict*/ 0, /*tp_descr_get*/ 0, /*tp_descr_set*/ 0, /*tp_dictoffset*/ 0, /*tp_init*/ 0, /*tp_alloc*/ /* FIXME: add new method */ 0, /*tp_new*/ 0, /*tp_free*/ 0 /*tp_is_gc*/ }; /* --- Create a SEXP object --- * Given an R SEXP object, it creates a * PySexpObject that is an rpy2 Python representation * of an R object. * * In case of error, this returns NULL. */ static PySexpObject* newPySexpObject(const SEXP sexp) { PySexpObject *object; SEXP sexp_ok, env_R; if (! sexp) { PyErr_Format(PyExc_ValueError, "NULL SEXP."); return NULL; } /* FIXME: let the possibility to manipulate un-evaluated promises ? */ if (TYPEOF(sexp) == PROMSXP) { PROTECT(env_R = PRENV(sexp)); if (env_R == R_NilValue) { env_R = R_BaseEnv; } PROTECT(sexp_ok = eval(sexp, env_R)); #ifdef RPY_DEBUG_PROMISE printf(" evaluating promise %p into %p.\n", sexp, sexp_ok); #endif UNPROTECT(2); } else { sexp_ok = sexp; } switch (TYPEOF(sexp_ok)) { case NILSXP: object = (PySexpObject *)RNULL_Type_New(1); break; case CLOSXP: case BUILTINSXP: case SPECIALSXP: object = (PySexpObject *)Sexp_new(&ClosureSexp_Type, Py_None, Py_None); break; /*FIXME: BUILTINSXP and SPECIALSXP really like CLOSXP ? */ case REALSXP: case INTSXP: case LGLSXP: case CPLXSXP: case VECSXP: case LISTSXP: case LANGSXP: case EXPRSXP: case STRSXP: case RAWSXP: object = (PySexpObject *)Sexp_new(&VectorSexp_Type, Py_None, Py_None); break; case ENVSXP: object = (PySexpObject *)Sexp_new(&EnvironmentSexp_Type, Py_None, Py_None); break; case S4SXP: object = (PySexpObject *)Sexp_new(&S4Sexp_Type, Py_None, Py_None); break; case EXTPTRSXP: object = (PySexpObject *)Sexp_new(&ExtPtrSexp_Type, Py_None, Py_None); break; default: object = (PySexpObject *)Sexp_new(&Sexp_Type, Py_None, Py_None); break; } if (!object) { #ifdef RPY_DEBUG_PRESERVE printf(" PRESERVE -- Sexp_clear: R_ReleaseObject -- %p ", sexp_ok); preserved_robjects -= 1; printf("-- %i\n", preserved_robjects); #endif /* FIXME: Override possible error message from Rpy_ReleaseObject (should an aggregated error message be made ? */ PyErr_NoMemory(); return NULL; } /* PyObject_Init(&object, &ClosureSexp_Type); */ if (Rpy_ReplaceSexp(object, sexp_ok) == -1) { return NULL; } /* FIXME: Increment reference ? */ /* Py_INCREF(object); */ return object; } /* This function is only able to create a R-Python object for an R vector-like 'rType', and from an 'object' that is a sequence. */ static SEXP newSEXP(PyObject *object, int rType) { SEXP sexp; SEXP str_R; /* used whenever there a string / unicode */ PyObject *seq_object, *item, *item_tmp, *na, *pybytes; #ifdef RPY_VERBOSE printf(" new SEXP for Python:%p.\n", object); #endif seq_object = PySequence_Fast(object, "Cannot create R object from non-sequence Python object."); if (! seq_object) { return NULL; } const Py_ssize_t length = PySequence_Fast_GET_SIZE(seq_object); Py_ssize_t i; double *numeric_ptr; int *integer_ptr; int *logical_ptr; char *raw_ptr; switch(rType) { case REALSXP: PROTECT(sexp = NEW_NUMERIC(length)); numeric_ptr = REAL(sexp); for (i = 0; i < length; ++i) { item = PySequence_Fast_GET_ITEM(seq_object, i); item_tmp = PyNumber_Float(item); if (item_tmp && (item != NAReal_New(0))) { numeric_ptr[i] = PyFloat_AS_DOUBLE(item_tmp); } else { PyErr_Clear(); numeric_ptr[i] = NA_REAL; } Py_XDECREF(item_tmp); } UNPROTECT(1); break; case INTSXP: PROTECT(sexp = NEW_INTEGER(length)); integer_ptr = INTEGER(sexp); for (i = 0; i < length; ++i) { item = PySequence_Fast_GET_ITEM(seq_object, i); #if (PY_VERSION_HEX < 0x03010000) item_tmp = PyNumber_Int(item); #else item_tmp = PyNumber_Long(item); #endif if (item_tmp && (item != NAInteger_New(0))) { #if (PY_VERSION_HEX < 0x03010000) long l = PyInt_AS_LONG(item_tmp); #else long l = PyLong_AS_LONG(item_tmp); #endif integer_ptr[i] = RPY_RINT_FROM_LONG(l); } else { PyErr_Clear(); integer_ptr[i] = NA_INTEGER; } Py_XDECREF(item_tmp); } UNPROTECT(1); break; case LGLSXP: PROTECT(sexp = NEW_LOGICAL(length)); logical_ptr = LOGICAL(sexp); for (i = 0; i < length; ++i) { item = PySequence_Fast_GET_ITEM(seq_object, i); if (item == NALogical_New(0)) { logical_ptr[i] = NA_LOGICAL; } else { int q = PyObject_IsTrue(item); if (q != -1) logical_ptr[i] = q; else { PyErr_Clear(); logical_ptr[i] = NA_LOGICAL; } } } UNPROTECT(1); break; case RAWSXP: PROTECT(sexp = NEW_RAW(length)); raw_ptr = (char *)RAW_POINTER(sexp); char *buffer; Py_ssize_t size_tmp; int ok; for (i = 0; i < length; ++i) { item = PySequence_Fast_GET_ITEM(seq_object, i); #if (PY_VERSION_HEX < 0x03010000) ok = PyString_AsStringAndSize(item, &buffer, &size_tmp); #else ok = PyBytes_AsStringAndSize(item, &buffer, &size_tmp); #endif if (ok == -1) { PyErr_Clear(); printf("Error while converting to Bytes element %zd.\n", i); continue; } if (size_tmp > 1) { /*FIXME: raise an error */ printf("Invalid input for RAW. Truncating...\n"); } raw_ptr[i] = buffer[0]; } UNPROTECT(1); break; case STRSXP: PROTECT(sexp = NEW_CHARACTER(length)); na = NACharacter_New(1); for (i = 0; i < length; ++i) { /* item is a borrowed reference */ item = PySequence_Fast_GET_ITEM(seq_object, i); if (item == na) { str_R = NA_STRING; #if (PY_VERSION_HEX < 0x03010000) } else if(PyString_Check(item)) { /* PyObject_Str in Python >= 3 is a unicode string */ str_R = mkChar(PyString_AS_STRING(item)); if (!str_R) { PyErr_NoMemory(); UNPROTECT(1); sexp = NULL; Py_DECREF(na); break; } #endif } else if (PyUnicode_Check(item)) { pybytes = PyUnicode_AsUTF8String(item); if (pybytes == NULL) { sexp = NULL; break; } #if (PY_VERSION_HEX < 0x03010000) const char *string = PyString_AsString(pybytes); #else const char *string = PyBytes_AsString(pybytes); #endif if (string == NULL) { Py_DECREF(pybytes); sexp = NULL; break; } str_R = mkCharCE(string, CE_UTF8); Py_DECREF(pybytes); if (!str_R) { PyErr_NoMemory(); UNPROTECT(1); sexp = NULL; Py_DECREF(na); break; } } else { PyErr_Clear(); str_R = NA_STRING; } SET_STRING_ELT(sexp, i, str_R); } UNPROTECT(1); Py_XDECREF(na); break; case VECSXP: PROTECT(sexp = NEW_LIST(length)); SEXP tmp, tmp2; for (i = 0; i < length; ++i) { if((item = PySequence_Fast_GET_ITEM(seq_object, i))) { if (PyObject_TypeCheck(item, &Sexp_Type)) { SET_ELEMENT(sexp, i, RPY_SEXP((PySexpObject *)item)); } else if (PyFloat_Check(item)) { tmp = allocVector(REALSXP, 1); REAL(tmp)[0] = PyFloat_AS_DOUBLE(item); SET_ELEMENT(sexp, i, tmp); #if (PY_VERSION_HEX < 0x03010000) } else if (PyInt_Check(item)) { #else } else if (PyLong_Check(item)) { #endif tmp = allocVector(INTSXP, 1); #if (PY_VERSION_HEX < 0x03010000) INTEGER_POINTER(tmp)[0] = (int)PyInt_AS_LONG(item); #else INTEGER_POINTER(tmp)[0] = (int)PyLong_AS_LONG(item); #endif SET_ELEMENT(sexp, i, tmp); } else if (PyLong_Check(item)) { tmp = allocVector(INTSXP, 1); INTEGER_POINTER(tmp)[0] = RPY_RINT_FROM_LONG(PyLong_AsLong(item)); if ((INTEGER_POINTER(tmp)[0] == -1) && PyErr_Occurred() ) { INTEGER_POINTER(tmp)[0] = NA_INTEGER; PyErr_Clear(); } SET_ELEMENT(sexp, i, tmp); } else if (PyBool_Check(item)) { tmp = allocVector(LGLSXP, 1); #if (PY_VERSION_HEX < 0x03010000) LOGICAL_POINTER(tmp)[0] = (int)PyInt_AS_LONG(item); #else LOGICAL_POINTER(tmp)[0] = (int)PyLong_AS_LONG(item); #endif SET_ELEMENT(sexp, i, tmp); #if (PY_VERSION_HEX < 0x03010000) } else if (PyString_Check(item)) { #else } else if (PyUnicode_Check(item)) { #endif PROTECT(tmp = NEW_CHARACTER(1)); #if (PY_VERSION_HEX < 0x03010000) tmp2 = mkChar(PyString_AsString(item)); #else pybytes = PyUnicode_AsUTF8String(item); if (pybytes == NULL) { sexp = NULL; break; } tmp2 = mkCharCE(PyBytes_AsString(pybytes), CE_UTF8); Py_DECREF(pybytes); #endif if (!tmp2) { PyErr_NoMemory(); sexp = NULL; break; } SET_STRING_ELT(tmp, 0, tmp2); SET_ELEMENT(sexp, i, tmp); UNPROTECT(1); } else { PyErr_Format(PyExc_ValueError, "All elements of the list must be of " "type 'Sexp_Type' or of Python types float, int, bool, or str."); sexp = NULL; break; } } } UNPROTECT(1); break; case CPLXSXP: PROTECT(sexp = NEW_COMPLEX(length)); for (i = 0; i < length; ++i) { item = PySequence_Fast_GET_ITEM(seq_object, i); if (PyComplex_Check(item)) { Py_complex cplx = PyComplex_AsCComplex(item); COMPLEX(sexp)[i].r = cplx.real; COMPLEX(sexp)[i].i = cplx.imag; } else { PyErr_Clear(); COMPLEX(sexp)[i].r = NA_REAL; COMPLEX(sexp)[i].i = NA_REAL; } } UNPROTECT(1); break; default: PyErr_Format(PyExc_ValueError, "Cannot handle type %d", rType); sexp = NULL; } Py_DECREF(seq_object); /* if (sexp != NULL) { */ /* //R_PreserveObject(sexp); */ /* SexpObject *sexpobjet_ptr = Rpy_PreserveObject(sexp); */ /* #ifdef RPY_DEBUG_PRESERVE */ /* preserved_robjects += 1; */ /* printf(" PRESERVE -- R_PreserveObject -- %p -- %i\n", */ /* sexp, preserved_robjects); */ /* #endif */ /* } */ #ifdef RPY_VERBOSE printf(" new SEXP for Python:%p is %p.\n", object, sexp); #endif return sexp; } /* --- Find a variable in an environment --- */ static PyObject* EmbeddedR_sexpType(PyObject *self, PyObject *args) { /* Return the C-defined name for R types */ int sexp_i; if (! PyArg_ParseTuple(args, "i", &sexp_i)) { /* PyErr_Format(PyExc_LookupError, "Value should be an integer"); */ return NULL; } const char *sexp_type = validSexpType[sexp_i]; if ((sexp_i < 0) || (sexp_i >= RPY_MAX_VALIDSEXTYPE) || (! sexp_type)) { PyErr_Format(PyExc_LookupError, "'%i' is not a valid SEXP value.", sexp_i); return NULL; } /* FIXME: store python strings when initializing validSexpType instead */ #if (PY_VERSION_HEX < 0x03010000) PyObject *res = PyString_FromString(sexp_type); #else PyObject *res = PyUnicode_FromString(sexp_type); #endif return res; } /* --- List of functions defined in the module --- */ static PyMethodDef EmbeddedR_methods[] = { {"get_initoptions", (PyCFunction)EmbeddedR_getinitoptions, METH_NOARGS, EmbeddedR_get_initoptions_doc}, {"set_initoptions", (PyCFunction)EmbeddedR_setinitoptions, METH_O, EmbeddedR_set_initoptions_doc}, {"initr", (PyCFunction)EmbeddedR_init, METH_NOARGS, EmbeddedR_init_doc}, {"endr", (PyCFunction)EmbeddedR_end, METH_O, EmbeddedR_end_doc}, {"set_interactive", (PyCFunction)EmbeddedR_setinteractive, METH_O, EmbeddedR_setinteractive_doc}, {"set_writeconsole", (PyCFunction)EmbeddedR_setWriteConsole, METH_VARARGS, EmbeddedR_setWriteConsole_doc}, {"get_writeconsole", (PyCFunction)EmbeddedR_getWriteConsole, METH_VARARGS, EmbeddedR_getWriteConsole_doc}, {"set_readconsole", (PyCFunction)EmbeddedR_setReadConsole, METH_VARARGS, EmbeddedR_setReadConsole_doc}, {"get_readconsole", (PyCFunction)EmbeddedR_getReadConsole, METH_VARARGS, EmbeddedR_getReadConsole_doc}, {"set_flushconsole", (PyCFunction)EmbeddedR_setFlushConsole, METH_VARARGS, EmbeddedR_setFlushConsole_doc}, {"get_flushconsole", (PyCFunction)EmbeddedR_getFlushConsole, METH_VARARGS, EmbeddedR_getFlushConsole_doc}, {"set_showmessage", (PyCFunction)EmbeddedR_setShowMessage, METH_VARARGS, EmbeddedR_setShowMessage_doc}, {"get_showmessage", (PyCFunction)EmbeddedR_getShowMessage, METH_VARARGS, EmbeddedR_getShowMessage_doc}, {"set_choosefile", (PyCFunction)EmbeddedR_setChooseFile, METH_VARARGS, EmbeddedR_setChooseFile_doc}, {"get_choosefile", (PyCFunction)EmbeddedR_getChooseFile, METH_VARARGS, EmbeddedR_getChooseFile_doc}, {"set_showfiles", (PyCFunction)EmbeddedR_setShowFiles, METH_VARARGS, EmbeddedR_setShowFiles_doc}, {"get_showfiles", (PyCFunction)EmbeddedR_getShowFiles, METH_VARARGS, EmbeddedR_getShowFiles_doc}, {"set_cleanup", (PyCFunction)EmbeddedR_setCleanUp, METH_VARARGS, EmbeddedR_setCleanUp_doc}, {"get_cleanup", (PyCFunction)EmbeddedR_getCleanUp, METH_VARARGS, EmbeddedR_getCleanUp_doc}, {"parse", (PyCFunction)EmbeddedR_parse, METH_O, EmbeddedR_parse_doc}, {"process_revents", (PyCFunction)EmbeddedR_ProcessEvents, METH_NOARGS, EmbeddedR_ProcessEvents_doc}, {"str_typeint", (PyCFunction)EmbeddedR_sexpType, METH_VARARGS, "Return the SEXP name tag (string) corresponding to an integer."}, {"unserialize", (PyCFunction)EmbeddedR_unserialize, METH_VARARGS, "unserialize(str, rtype)\n" "Unserialize an R object from its string representation."}, {"protected_rids", (PyCFunction)Rpy_ProtectedIDs, METH_NOARGS, Rpy_ProtectedIDs_doc}, {NULL, NULL} /* sentinel */ }; /* A. Belopolsky's callback */ /* R representation of a PyObject */ static SEXP mkPyObject(PyObject* pyo) { SEXP res; Py_INCREF(pyo); res = R_MakeExternalPtr(pyo, RPY_SEXP(R_PyObject_type_tag), R_NilValue); R_RegisterCFinalizer(res, (R_CFinalizer_t)R_PyObject_decref); return res; } #define R_PyObject_TYPE_CHECK(s) \ (TYPEOF(s) == EXTPTRSXP && R_ExternalPtrTag(s) == RPY_SEXP(R_PyObject_type_tag)) static SEXP do_Python(SEXP args) { args = CDR(args); SEXP sexp = CAR(args); SEXP res; int protect_count; if (!R_PyObject_TYPE_CHECK(sexp)) { error(".Python: The first argument must be an external pointer tagged as of Python type."); return R_NilValue; } PyObject *pyf = R_ExternalPtrAddr(sexp); /* Result for the evaluation of the Python function */ PyObject *pyres; /* create argument list */ PyObject *pyargs = PyList_New(0); /* named arguments */ PyObject *pynargs = PyDict_New(); const char *tag; int ok_setnamedarg; for (args = CDR(args); args != R_NilValue; args = CDR(args)) { sexp = CAR(args); if (isNull(TAG(args))) { /* unnamed argument */ if (R_PyObject_TYPE_CHECK(sexp)) { PyList_Append(pyargs, (PyObject *)R_ExternalPtrAddr(sexp)); } else { PyList_Append(pyargs, (PyObject *)newPySexpObject(sexp)); } } else { tag = CHAR(PRINTNAME(TAG(args))); /* named argument */ if (R_PyObject_TYPE_CHECK(sexp)) { ok_setnamedarg = PyDict_SetItemString(pynargs, tag, (PyObject *)R_ExternalPtrAddr(sexp)); } else { ok_setnamedarg = PyDict_SetItemString(pynargs, tag, (PyObject *)newPySexpObject(sexp)); } if (ok_setnamedarg == -1) { error("rpy2: Error while setting a named argument"); } } } PyObject *pyargstup = PyList_AsTuple(pyargs); /* free the R lock as we are leaving the R side back to Python */ embeddedR_freelock(); pyres = PyObject_Call(pyf, pyargstup, pynargs); embeddedR_setlock(); if (!pyres) { PyObject *exctype; PyObject *excvalue; PyObject *exctraceback; PyObject *excstr; PyErr_Fetch(&exctype, &excvalue, &exctraceback); excstr = PyObject_Str(excvalue); if (excstr) { #if (PY_VERSION_HEX < 0x03010000) error(PyString_AS_STRING(excstr)); #else PyObject *pybytes = PyUnicode_AsLatin1String(excstr); error(PyBytes_AsString(pybytes)); Py_DECREF(pybytes); #endif Py_DECREF(excstr); } else { error("rpy2: Python error."); } PyErr_Clear(); } Py_DECREF(pyargs); Py_DECREF(pyargstup); if (PyObject_IsInstance((PyObject*)pyres, (PyObject*)&Sexp_Type)) { res = RPY_SEXP((PySexpObject*)pyres); } else { protect_count = 0; RPY_PYSCALAR_RVECTOR(pyres, res); if (res == NULL) { res = mkPyObject(pyres); } UNPROTECT(protect_count); } Py_DECREF(pyres); return res; } static void RegisterExternalSymbols() { R_ExternalMethodDef externalMethods[] = { {".Python", (DL_FUNC)&do_Python, -1}, {NULL, NULL, 0} }; R_registerRoutines(R_getEmbeddingDllInfo(), NULL, NULL, NULL, externalMethods); } /* --- Initialize the module ---*/ static char **validSexpType; #define ADD_INT_CONSTANT(module, name) \ PyModule_AddIntConstant(module, #name, name); \ #define ADD_SEXP_CONSTANT(module, name) \ PyModule_AddIntConstant(module, #name, name); \ validSexpType[name] = #name ; \ #define PYASSERT_ZERO(code) \ if ((code) != 0) {return ; } \ #if (PY_VERSION_HEX < 0x03010000) #else static struct PyModuleDef rinterfacemodule = { PyModuleDef_HEAD_INIT, "_rinterface", /* name of module */ module_doc, /* module documentation, may be NULL */ -1, /* size of per-interpreter state */ EmbeddedR_methods /* method table */ }; #endif /* GS: Necessary? */ /* LG: might be for win32/win64 (I can't remember)*/ #ifndef PyMODINIT_FUNC /* declarations for DLL import/export */ #define PyMODINIT_FUNC void #endif PyMODINIT_FUNC #if (PY_VERSION_HEX < 0x03010000) init_rinterface(void) #else PyInit__rinterface(void) #endif { /* PyMODINIT_FUNC */ /* RPY_RINTERFACE_INIT(void) */ /* { */ /* Finalize the type object including setting type of the new type * object; doing it here is required for portability to Windows * without requiring C++. */ if (PyType_Ready(&Sexp_Type) < 0) { #if (PY_VERSION_HEX < 0x03010000) return; #else return NULL; #endif } if (PyType_Ready(&ClosureSexp_Type) < 0) { #if (PY_VERSION_HEX < 0x03010000) return; #else return NULL; #endif } if (PyType_Ready(&VectorSexp_Type) < 0) { #if (PY_VERSION_HEX < 0x03010000) return; #else return NULL; #endif } if (PyType_Ready(&IntVectorSexp_Type) < 0) { #if (PY_VERSION_HEX < 0x03010000) return; #else return NULL; #endif } if (PyType_Ready(&FloatVectorSexp_Type) < 0) { #if (PY_VERSION_HEX < 0x03010000) return; #else return NULL; #endif } if (PyType_Ready(&StrVectorSexp_Type) < 0) { #if (PY_VERSION_HEX < 0x03010000) return; #else return NULL; #endif } if (PyType_Ready(&BoolVectorSexp_Type) < 0) { #if (PY_VERSION_HEX < 0x03010000) return; #else return NULL; #endif } if (PyType_Ready(&ByteVectorSexp_Type) < 0) { #if (PY_VERSION_HEX < 0x03010000) return; #else return NULL; #endif } if (PyType_Ready(&ComplexVectorSexp_Type) < 0) { #if (PY_VERSION_HEX < 0x03010000) return; #else return NULL; #endif } if (PyType_Ready(&ListVectorSexp_Type) < 0) { #if (PY_VERSION_HEX < 0x03010000) return; #else return NULL; #endif } if (PyType_Ready(&EnvironmentSexp_Type) < 0) { #if (PY_VERSION_HEX < 0x03010000) return; #else return NULL; #endif } if (PyType_Ready(&S4Sexp_Type) < 0) { #if (PY_VERSION_HEX < 0x03010000) return; #else return NULL; #endif } if (PyType_Ready(&LangSexp_Type) < 0) { #if (PY_VERSION_HEX < 0x03010000) return; #else return NULL; #endif } if (PyType_Ready(&ExtPtrSexp_Type) < 0) { #if (PY_VERSION_HEX < 0x03010000) return; #else return NULL; #endif } /* Required because NA types inherit from basic Python types */ if (PyType_Ready(&PyBool_Type) < 0) { #if (PY_VERSION_HEX < 0x03010000) return; #else return NULL; #endif } if (PyType_Ready(&PyLong_Type) < 0) { #if (PY_VERSION_HEX < 0x03010000) return; #else return NULL; #endif } /* NA types */ #if defined(Win32) || defined(Win64) NAInteger_Type.tp_base=&PyLong_Type; #endif if (PyType_Ready(&NAInteger_Type) < 0) { #if (PY_VERSION_HEX < 0x03010000) return; #else return NULL; #endif } #if defined(Win32) || defined(Win64) NALogical_Type.tp_base=&PyLong_Type; #endif if (PyType_Ready(&NALogical_Type) < 0) { #if (PY_VERSION_HEX < 0x03010000) return; #else return NULL; #endif } #if defined(Win32) || defined(Win64) NAReal_Type.tp_base=&PyFloat_Type; #endif if (PyType_Ready(&NAReal_Type) < 0) { #if (PY_VERSION_HEX < 0x03010000) return; #else return NULL; #endif } #if defined(Win32) || defined(Win64) NAComplex_Type.tp_base=&PyComplex_Type; #endif if (PyType_Ready(&NAComplex_Type) < 0) { #if (PY_VERSION_HEX < 0x03010000) return; #else return NULL; #endif } #if (defined(Win32) || defined(Win64)) & PY_VERSION_HEX < 0x03010000 NACharacter_Type.tp_base=&PyString_Type; #elif defined(Win32) NACharacter_Type.tp_base=&PyUnicode_Type; #endif if (PyType_Ready(&NACharacter_Type) < 0) { #if (PY_VERSION_HEX < 0x03010000) return; #else return NULL; #endif } PyObject *m, *d; static void *PyRinterface_API[PyRinterface_API_pointers]; PyObject *c_api_object; #if (PY_VERSION_HEX < 0x03010000) m = Py_InitModule3("_rinterface", EmbeddedR_methods, module_doc); #else m = PyModule_Create(&rinterfacemodule); #endif if (m == NULL) { #if (PY_VERSION_HEX < 0x03010000) return; #else return NULL; #endif } /* Initialize the C API pointer array */ PyRinterface_API[ PyRinterface_IsInitialized_NUM ] = \ (void *)PyRinterface_IsInitialized; PyRinterface_API[ PyRinterface_FindFun_NUM ] = \ (void *)PyRinterface_FindFun; /* Create a Capsule containing the API pointer array's address */ c_api_object = PyCapsule_New((void *)PyRinterface_API, PyRinterface_API_NAME, NULL); if (c_api_object == NULL) { #if (PY_VERSION_HEX < 0x03010000) return; #else return NULL; #endif } else { PyModule_AddObject(m, "_C_API", c_api_object); } d = PyModule_GetDict(m); /* Add SXP types */ validSexpType = calloc(RPY_MAX_VALIDSEXTYPE, sizeof(char *)); if (! validSexpType) { PyErr_NoMemory(); #if (PY_VERSION_HEX < 0x03010000) return; #else return NULL; #endif } ADD_SEXP_CONSTANT(m, NILSXP); ADD_SEXP_CONSTANT(m, SYMSXP); ADD_SEXP_CONSTANT(m, LISTSXP); ADD_SEXP_CONSTANT(m, CLOSXP); ADD_SEXP_CONSTANT(m, ENVSXP); ADD_SEXP_CONSTANT(m, PROMSXP); ADD_SEXP_CONSTANT(m, LANGSXP); ADD_SEXP_CONSTANT(m, SPECIALSXP); ADD_SEXP_CONSTANT(m, BUILTINSXP); ADD_SEXP_CONSTANT(m, CHARSXP); ADD_SEXP_CONSTANT(m, STRSXP); ADD_SEXP_CONSTANT(m, LGLSXP); ADD_SEXP_CONSTANT(m, INTSXP); ADD_SEXP_CONSTANT(m, REALSXP); ADD_SEXP_CONSTANT(m, CPLXSXP); ADD_SEXP_CONSTANT(m, DOTSXP); ADD_SEXP_CONSTANT(m, ANYSXP); ADD_SEXP_CONSTANT(m, VECSXP); ADD_SEXP_CONSTANT(m, EXPRSXP); ADD_SEXP_CONSTANT(m, BCODESXP); ADD_SEXP_CONSTANT(m, EXTPTRSXP); ADD_SEXP_CONSTANT(m, RAWSXP); ADD_SEXP_CONSTANT(m, S4SXP); /* longuest integer for R indexes */ ADD_INT_CONSTANT(m, R_LEN_T_MAX); /* "Logical" (boolean) values */ ADD_INT_CONSTANT(m, TRUE); ADD_INT_CONSTANT(m, FALSE); /* R_ext/Arith.h */ /* ADD_INT_CONSTANT(m, NA_LOGICAL); */ /* ADD_INT_CONSTANT(m, NA_INTEGER); */ RPY_R_VERSION_BUILD = PyTuple_New(4); #if (PY_VERSION_HEX < 0x03010000) PYASSERT_ZERO( PyTuple_SetItem(RPY_R_VERSION_BUILD, 0, PyString_FromString(R_MAJOR)) ); PYASSERT_ZERO( PyTuple_SetItem(RPY_R_VERSION_BUILD, 1, PyString_FromString(R_MINOR)) ); PYASSERT_ZERO( PyTuple_SetItem(RPY_R_VERSION_BUILD, 2, PyString_FromString(R_STATUS)) ); # else if (PyTuple_SetItem(RPY_R_VERSION_BUILD, 0, PyUnicode_FromString(R_MAJOR)) < 0) return NULL; if (PyTuple_SetItem(RPY_R_VERSION_BUILD, 1, PyUnicode_FromString(R_MINOR)) < 0) return NULL; if (PyTuple_SetItem(RPY_R_VERSION_BUILD, 2, PyUnicode_FromString(R_STATUS)) < 0) return NULL; #endif #if (PY_VERSION_HEX < 0x03010000) && (R_VERSION < __RPY_RSVN_SWITCH_VERSION__) PYASSERT_ZERO( PyTuple_SetItem(RPY_R_VERSION_BUILD, 3, PyString_FromString(R_SVN_REVISION)) ); #elif (PY_VERSION_HEX < 0x03010000) PYASSERT_ZERO( PyTuple_SetItem(RPY_R_VERSION_BUILD, 3, PyLong_FromLong(R_SVN_REVISION)) ); #elif (R_VERSION < __RPY_RSVN_SWITCH_VERSION__) if (PyTuple_SetItem(RPY_R_VERSION_BUILD, 3, PyLong_FromLong(R_SVN_REVISION)) < 0) return NULL; #else if (PyTuple_SetItem(RPY_R_VERSION_BUILD, 3, PyLong_FromLong(R_SVN_REVISION)) < 0) return NULL; #endif initOptions = PyTuple_New(4); #if (PY_VERSION_HEX < 0x03010000) PYASSERT_ZERO( PyTuple_SetItem(initOptions, 0, PyString_FromString("rpy2")) ); PYASSERT_ZERO( PyTuple_SetItem(initOptions, 1, PyString_FromString("--quiet")) ); PYASSERT_ZERO( PyTuple_SetItem(initOptions, 2, PyString_FromString("--vanilla")) ); PYASSERT_ZERO( PyTuple_SetItem(initOptions, 3, PyString_FromString("--no-save")) ); #else if (PyTuple_SetItem(initOptions, 0, PyBytes_FromString("rpy2")) < 0) return NULL; if (PyTuple_SetItem(initOptions, 1, PyBytes_FromString("--quiet")) < 0) return NULL; if (PyTuple_SetItem(initOptions, 2, PyBytes_FromString("--vanilla")) < 0) return NULL; if (PyTuple_SetItem(initOptions, 3, PyBytes_FromString("--no-save")) < 0) return NULL; #endif /* Add an extra ref. It should remain impossible to delete it */ Py_INCREF(initOptions); Rpy_R_Precious = PyDict_New(); PyModule_AddObject(m, "_Rpy_R_Precious", Rpy_R_Precious); /* Add an extra ref. It should remain impossible to delete it */ Py_INCREF(Rpy_R_Precious); PyModule_AddObject(m, "R_VERSION_BUILD", RPY_R_VERSION_BUILD); PyModule_AddObject(m, "initoptions", initOptions); PyModule_AddObject(m, "Sexp", (PyObject *)&Sexp_Type); PyModule_AddObject(m, "SexpClosure", (PyObject *)&ClosureSexp_Type); PyModule_AddObject(m, "SexpVector", (PyObject *)&VectorSexp_Type); PyModule_AddObject(m, "IntSexpVector", (PyObject *)&IntVectorSexp_Type); PyModule_AddObject(m, "FloatSexpVector", (PyObject *)&FloatVectorSexp_Type); PyModule_AddObject(m, "StrSexpVector", (PyObject *)&StrVectorSexp_Type); PyModule_AddObject(m, "BoolSexpVector", (PyObject *)&BoolVectorSexp_Type); PyModule_AddObject(m, "ByteSexpVector", (PyObject *)&ByteVectorSexp_Type); PyModule_AddObject(m, "ComplexSexpVector", (PyObject *)&ComplexVectorSexp_Type); PyModule_AddObject(m, "ListSexpVector", (PyObject *)&ListVectorSexp_Type); PyModule_AddObject(m, "SexpEnvironment", (PyObject *)&EnvironmentSexp_Type); PyModule_AddObject(m, "SexpS4", (PyObject *)&S4Sexp_Type); PyModule_AddObject(m, "SexpLang", (PyObject *)&LangSexp_Type); PyModule_AddObject(m, "SexpExtPtr", (PyObject *)&ExtPtrSexp_Type); /* NA types */ PyModule_AddObject(m, "NAIntegerType", (PyObject *)&NAInteger_Type); PyModule_AddObject(m, "NA_Integer", NAInteger_New(1)); PyModule_AddObject(m, "NALogicalType", (PyObject *)&NALogical_Type); PyModule_AddObject(m, "NA_Logical", NALogical_New(1)); PyModule_AddObject(m, "NARealType", (PyObject *)&NAReal_Type); PyModule_AddObject(m, "NA_Real", NAReal_New(1)); PyModule_AddObject(m, "NAComplexType", (PyObject *)&NAComplex_Type); PyModule_AddObject(m, "NA_Complex", NAComplex_New(1)); PyModule_AddObject(m, "NACharacterType", (PyObject *)&NACharacter_Type); PyModule_AddObject(m, "NA_Character", NACharacter_New(1)); /* Missing */ if (PyType_Ready(&MissingArg_Type) < 0) { #if (PY_VERSION_HEX < 0x03010000) return; #else return NULL; #endif } PyModule_AddObject(m, "MissingArgType", (PyObject *)&MissingArg_Type); PyModule_AddObject(m, "MissingArg", MissingArg_Type_New(1)); /* Unbound */ if (PyType_Ready(&UnboundValue_Type) < 0) { #if (PY_VERSION_HEX < 0x03010000) return; #else return NULL; #endif } PyModule_AddObject(m, "UnboundValueType", (PyObject *)&UnboundValue_Type); PyModule_AddObject(m, "UnboundValue", UnboundValue_Type_New(1)); /* NULL */ if (PyType_Ready(&RNULL_Type) < 0) { #if (PY_VERSION_HEX < 0x03010000) return; #else return NULL; #endif } PyModule_AddObject(m, "RNULLType", (PyObject *)&RNULL_Type); /*FIXME: shouldn't RNULLArg disappear ? */ PyModule_AddObject(m, "RNULLArg", RNULL_Type_New(1)); PyModule_AddObject(m, "NULL", RNULL_Type_New(1)); if (RPyExc_RuntimeError == NULL) { RPyExc_RuntimeError = PyErr_NewException("rpy2.rinterface.RRuntimeError", NULL, NULL); if (RPyExc_RuntimeError == NULL) { #if (PY_VERSION_HEX < 0x03010000) return; #else return NULL; #endif } } Py_INCREF(RPyExc_RuntimeError); PyModule_AddObject(m, "RRuntimeError", RPyExc_RuntimeError); embeddedR_isInitialized = Py_False; Py_INCREF(Py_False); if (PyModule_AddObject(m, "is_initialized", embeddedR_isInitialized) < 0) { #if (PY_VERSION_HEX < 0x03010000) return; #else return NULL; #endif } emptyEnv = (PySexpObject*)Sexp_new(&EnvironmentSexp_Type, Py_None, Py_None); SexpObject *sexpobj_ptr = Rpy_PreserveObject(R_EmptyEnv); Rpy_ReleaseObject(emptyEnv->sObj->sexp); emptyEnv->sObj = sexpobj_ptr; if (PyDict_SetItemString(d, "emptyenv", (PyObject *)emptyEnv) < 0) { Py_DECREF(emptyEnv); #if (PY_VERSION_HEX < 0x03010000) return; #else return NULL; #endif } Py_DECREF(emptyEnv); globalEnv = (PySexpObject *)Sexp_new(&EnvironmentSexp_Type, Py_None, Py_None); sexpobj_ptr = Rpy_PreserveObject(R_EmptyEnv); Rpy_ReleaseObject(globalEnv->sObj->sexp); globalEnv->sObj = sexpobj_ptr; if (PyDict_SetItemString(d, "globalenv", (PyObject *)globalEnv) < 0) { Py_DECREF(globalEnv); #if (PY_VERSION_HEX < 0x03010000) return; #else return NULL; #endif } Py_DECREF(globalEnv); baseNameSpaceEnv = (PySexpObject*)Sexp_new(&EnvironmentSexp_Type, Py_None, Py_None); sexpobj_ptr = Rpy_PreserveObject(R_EmptyEnv); Rpy_ReleaseObject(baseNameSpaceEnv->sObj->sexp); baseNameSpaceEnv->sObj = sexpobj_ptr; if (PyDict_SetItemString(d, "baseenv", (PyObject *)baseNameSpaceEnv) < 0) { Py_DECREF(baseNameSpaceEnv); #if (PY_VERSION_HEX < 0x03010000) return; #else return NULL; #endif } Py_DECREF(baseNameSpaceEnv); rpy_R_NilValue = (PySexpObject*)Sexp_new(&Sexp_Type, Py_None, Py_None); if (PyDict_SetItemString(d, "R_NilValue", (PyObject *)rpy_R_NilValue) < 0) { Py_DECREF(rpy_R_NilValue); #if (PY_VERSION_HEX < 0x03010000) return; #else return NULL; #endif } Py_DECREF(rpy_R_NilValue); R_PyObject_type_tag = (PySexpObject*)Sexp_new(&VectorSexp_Type, Py_None, Py_None); if (PyDict_SetItemString(d, "python_type_tag", (PyObject *)R_PyObject_type_tag) < 0) { Py_DECREF(R_PyObject_type_tag); #if (PY_VERSION_HEX < 0x03010000) return; #else return NULL; #endif } Py_DECREF(R_PyObject_type_tag); rinterface_unserialize = PyDict_GetItemString(d, "unserialize"); #if (PY_VERSION_HEX < 0x03010000) #else return m; #endif } rpy2-2.3.9/rpy/rinterface/na_values.c0000644000175000017500000007613412271276146020667 0ustar laurentlaurent00000000000000/* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * Copyright (C) 2008-2012 Laurent Gautier * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ /* --- NA values --- */ #include PyDoc_STRVAR(NAInteger_Type_doc, "Missing value for an integer in R." ); static PyObject* NAInteger_repr(PyObject *self) { static PyObject* repr = NULL; if (repr == NULL) { #if (PY_VERSION_HEX < 0x03010000) repr = PyString_FromString("NA_integer_"); #else repr = PyUnicode_FromString("NA_integer_"); #endif } Py_XINCREF(repr); return repr; } static PyObject* NA_str(PyObject *self) { static PyObject* repr = NULL; if (repr == NULL) { #if (PY_VERSION_HEX < 0x03010000) repr = PyString_FromString("NA"); #else repr = PyUnicode_FromString("NA"); #endif } Py_XINCREF(repr); return repr; } /* Whenever an NA object is used for arithmetic or logic, * the results is NA. */ static PyObject* NA_unaryfunc(PyObject *self) { Py_XINCREF(self); return self; } static PyObject* NA_binaryfunc(PyObject *self, PyObject *obj) { Py_XINCREF(self); return self; } static PyObject* NA_ternaryfunc(PyObject *self, PyObject *obj1, PyObject *obj2) { Py_XINCREF(self); return self; } static int NA_nonzero(PyObject *self) { PyErr_Format(PyExc_ValueError, "NA values cannot be evaluated as booleans."); return 0; } static PyNumberMethods NAInteger_NumberMethods = { (binaryfunc)NA_binaryfunc, /* nb_add */ (binaryfunc)NA_binaryfunc, /* nb_subtract; */ (binaryfunc)NA_binaryfunc, /* nb_multiply; */ #if (PY_VERSION_HEX < 0x03010000) (binaryfunc)NA_binaryfunc, /* nb_divide; */ #endif (binaryfunc)NA_binaryfunc, /* nb_remainder; */ (binaryfunc)NA_binaryfunc, /* nb_divmod; */ (ternaryfunc)NA_ternaryfunc, /* nb_power; */ (unaryfunc) NA_unaryfunc, /* nb_negative; */ (unaryfunc) NA_unaryfunc, /* nb_positive; */ (unaryfunc) NA_unaryfunc, /* nb_absolute; */ (inquiry) NA_nonzero, /* nb_nonzero; -- Used by PyObject_IsTrue */ (unaryfunc) NA_unaryfunc, /* nb_invert; */ (binaryfunc) NA_binaryfunc, /* nb_lshift; */ (binaryfunc) NA_binaryfunc, /* nb_rshift; */ (binaryfunc) NA_binaryfunc, /* nb_and; */ (binaryfunc) NA_binaryfunc, /* nb_xor; */ (binaryfunc) NA_binaryfunc, /* nb_or; */ #if (PY_VERSION_HEX < 0x03010000) 0, //(coerce) NA_coerce, /* coercion nb_coerce; -- Used by the coerce() function */ #endif (unaryfunc) NA_unaryfunc, /* nb_int; */ #if (PY_VERSION_HEX < 0x03010000) (unaryfunc) NA_unaryfunc, /* nb_long; */ #else NULL, /* reserved */ #endif (unaryfunc) NA_unaryfunc, /* nb_float; */ #if (PY_VERSION_HEX < 0x03010000) (unaryfunc) NA_unaryfunc, /* nb_oct; */ (unaryfunc) NA_unaryfunc, /* nb_hex; */ #endif /* Added in release 2.0 */ (binaryfunc)NA_binaryfunc, /* nb_inplace_add; */ (binaryfunc)NA_binaryfunc, /* nb_inplace_subtract; */ (binaryfunc)NA_binaryfunc, /* nb_inplace_multiply; */ #if (PY_VERSION_HEX < 0x03010000) (binaryfunc)NA_binaryfunc, /* nb_inplace_divide; */ #endif (binaryfunc)NA_binaryfunc, /* nb_inplace_remainder; */ (ternaryfunc)NA_ternaryfunc, /* nb_inplace_power; */ 0, /* nb_inplace_lshift; */ 0, /* nb_inplace_rshift; */ 0, /* nb_inplace_and; */ 0, /* nb_inplace_xor; */ 0, /* nb_inplace_or; */ /* Added in release 2.2 */ (binaryfunc) NA_binaryfunc, /* nb_floor_divide; */ (binaryfunc) NA_binaryfunc, /* nb_true_divide; */ (binaryfunc)NA_binaryfunc, /* nb_inplace_floor_divide; */ (binaryfunc)NA_binaryfunc, /* nb_inplace_true_divide; */ /* Added in release 2.5 */ #if PY_VERSION_HEX >= 0x02050000 (unaryfunc) NA_unaryfunc /* nb_index; */ #endif }; static PyObject* NAInteger_tp_new(PyTypeObject *type, PyObject *args, PyObject *kwds); static PyTypeObject NAInteger_Type = { /* The ob_type field must be initialized in the module init function * to be portable to Windows without using C++. */ #if (PY_VERSION_HEX < 0x03010000) PyObject_HEAD_INIT(NULL) 0, /*ob_size*/ #else PyVarObject_HEAD_INIT(NULL, 0) #endif "rpy2.rinterface.NAIntegerType", /*tp_name*/ sizeof(PyLongObject), /*tp_basicsize*/ 0, /*tp_itemsize*/ /* methods */ 0, /*tp_dealloc*/ 0, /*tp_print*/ 0, /*tp_getattr*/ 0, /*tp_setattr*/ 0, /*tp_compare*/ NAInteger_repr, /*tp_repr*/ &NAInteger_NumberMethods, /*tp_as_number*/ 0, /*tp_as_sequence*/ 0, /*tp_as_mapping*/ 0, /*tp_hash*/ 0, /*tp_call*/ NA_str, /*tp_str*/ 0, /*tp_getattro*/ 0, /*tp_setattro*/ 0, /*tp_as_buffer*/ #if (PY_VERSION_HEX < 0x03010000) Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_CHECKTYPES, /*tp_flags*/ #else Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /*tp_flags*/ #endif NAInteger_Type_doc, /*tp_doc*/ 0, /*tp_traverse*/ 0, /*tp_clear*/ 0, /*tp_richcompare*/ 0, /*tp_weaklistoffset*/ 0, /*tp_iter*/ 0, /*tp_iternext*/ 0, /*tp_methods*/ 0, /*tp_members*/ 0, /*tp_getset*/ #if defined(Win32) || defined(Win64) NULL, #else &PyLong_Type, /*tp_base*/ #endif 0, /*tp_dict*/ 0, /*tp_descr_get*/ 0, /*tp_descr_set*/ 0, /*tp_dictoffset*/ 0, //(initproc)ClosureSexp_init, /*tp_init*/ 0, /*tp_alloc*/ NAInteger_tp_new, /*tp_new*/ 0, /*tp_free*/ 0 /*tp_is_gc*/ }; static PyObject* NAInteger_tp_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { static PyLongObject *self = NULL; static char *kwlist[] = {0}; PyObject *py_value; Py_ssize_t i, n; assert(PyType_IsSubtype(type, &PyLong_Type)); if (! PyArg_ParseTupleAndKeywords(args, kwds, "", kwlist)) { return NULL; } if (self == NULL) { py_value = PyLong_FromLong((long)(NA_INTEGER)); if (py_value == NULL) { return NULL; } assert(PyLong_CheckExact(py_value)); n = Py_SIZE(py_value); if (n < 0) n = -n; self = (PyLongObject *)(PyLong_Type.tp_alloc(type, n)); if (self == NULL) { Py_DECREF(py_value); return NULL; } assert(PyLong_Check(self)); Py_SIZE(self) = Py_SIZE(py_value); for (i = 0; i < n; i++) { self->ob_digit[i] = ((PyLongObject *)py_value)->ob_digit[i]; } Py_DECREF(py_value); } Py_XINCREF(self); return (PyObject *)self; } static PyObject* NAInteger_New(int new) { RPY_NA_NEW(NAInteger_Type, NAInteger_tp_new) } /* NA Boolean / Logical */ PyDoc_STRVAR(NALogical_Type_doc, "Missing value for a boolean in R." ); static PyObject* NALogical_tp_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { RPY_NA_TP_NEW("NALogicalType", PyLong_Type, PyLong_FromLong, (long)NA_LOGICAL) } static PyObject* NALogical_New(int new) { RPY_NA_NEW(NALogical_Type, NALogical_tp_new) } static PyObject* NALogical_repr(PyObject *self) { static PyObject* repr = NULL; if (repr == NULL) { #if (PY_VERSION_HEX < 0x03010000) repr = PyString_FromString("NA"); #else repr = PyUnicode_FromString("NA"); #endif } Py_XINCREF(repr); return repr; } static PyNumberMethods NALogical_NumberMethods = { 0, /* nb_add */ 0, /* nb_subtract; */ 0, /* nb_multiply; */ #if (PY_VERSION_HEX < 0x03010000) 0, /* nb_divide; */ #endif 0, /* nb_remainder; */ 0, /* nb_divmod; */ 0, /* nb_power; */ 0, /* nb_negative; */ 0, /* nb_positive; */ 0, /* nb_absolute; */ 0, /* nb_nonzero; -- Used by PyObject_IsTrue */ 0, /* nb_invert; */ 0, /* nb_lshift; */ 0, /* nb_rshift; */ (binaryfunc) NA_binaryfunc, /* nb_and; */ (binaryfunc) NA_binaryfunc, /* nb_xor; */ (binaryfunc) NA_binaryfunc, /* nb_or; */ #if (PY_VERSION_HEX < 0x03010000) 0, //(coerce) NA_coerce, /* coercion nb_coerce; -- Used by the coerce() function */ #endif 0, /* nb_int; */ #if (PY_VERSION_HEX < 0x03010000) 0, /* nb_long; */ #else NULL, /* reserved */ #endif 0, /* nb_float; */ #if (PY_VERSION_HEX < 0x03010000) 0, /* nb_oct; */ 0, /* nb_hex; */ #endif /* Added in release 2.0 */ 0, /* nb_inplace_add; */ 0, /* nb_inplace_subtract; */ 0, /* nb_inplace_multiply; */ #if (PY_VERSION_HEX < 0x03010000) 0, /* nb_inplace_divide; */ #endif 0, /* nb_inplace_remainder; */ 0, /* nb_inplace_power; */ 0, /* nb_inplace_lshift; */ 0, /* nb_inplace_rshift; */ 0, /* nb_inplace_and; */ 0, /* nb_inplace_xor; */ 0, /* nb_inplace_or; */ /* Added in release 2.2 */ 0, /* nb_floor_divide; */ 0, /* nb_true_divide; */ 0, /* nb_inplace_floor_divide; */ 0, /* nb_inplace_true_divide; */ /* Added in release 2.5 */ #if PY_VERSION_HEX >= 0x02050000 0 /* nb_index; */ #endif }; static PyTypeObject NALogical_Type = { /* The ob_type field must be initialized in the module init function * to be portable to Windows without using C++. */ #if (PY_VERSION_HEX < 0x03010000) PyObject_HEAD_INIT(NULL) 0, /*ob_size*/ #else PyVarObject_HEAD_INIT(NULL, 0) #endif "rpy2.rinterface.NALogicalType", /*tp_name*/ sizeof(PyLongObject), /*tp_basicsize*/ 0, /*tp_itemsize*/ /* methods */ 0, /*tp_dealloc*/ 0, /*tp_print*/ 0, /*tp_getattr*/ 0, /*tp_setattr*/ 0, /*tp_compare*/ NALogical_repr, /*tp_repr*/ &NALogical_NumberMethods, /*tp_as_number*/ 0, /*tp_as_sequence*/ 0, /*tp_as_mapping*/ 0, /*tp_hash*/ 0, /*tp_call*/ NA_str, /*tp_str*/ 0, /*tp_getattro*/ 0, /*tp_setattro*/ 0, /*tp_as_buffer*/ #if (PY_VERSION_HEX < 0x03010000) Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_CHECKTYPES, /*tp_flags*/ #else Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /*tp_flags*/ #endif NALogical_Type_doc, /*tp_doc*/ 0, /*tp_traverse*/ 0, /*tp_clear*/ 0, /*tp_richcompare*/ 0, /*tp_weaklistoffset*/ 0, /*tp_iter*/ 0, /*tp_iternext*/ 0, //NAInteger_methods, /*tp_methods*/ 0, /*tp_members*/ 0, /*tp_getset*/ #if defined(Win32) || defined(Win64) NULL, #else &PyLong_Type, /*tp_base*/ #endif 0, /*tp_dict*/ 0, /*tp_descr_get*/ 0, /*tp_descr_set*/ 0, /*tp_dictoffset*/ 0, //(initproc)ClosureSexp_init, /*tp_init*/ 0, /*tp_alloc*/ NALogical_tp_new, /*tp_new*/ 0, /*tp_free*/ 0 /*tp_is_gc*/ }; /* NA Float / Real */ PyDoc_STRVAR(NAReal_Type_doc, "Missing value for a float in R." ); static PyObject* NAReal_tp_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { //printf("--->0x%llx\n", *(unsigned long long *)&(NAREAL_IEEE.value)); static PyObject *self = NULL; static char *kwlist[] = {0}; PyObject *py_value; assert(PyType_IsSubtype(type, &PyFloat_Type)); if (! PyArg_ParseTupleAndKeywords(args, kwds, "", kwlist)) { return NULL; } if (self == NULL) { py_value = PyFloat_FromDouble((double)(NAREAL_IEEE.value)); //(double)0x7ff00000000007a2 //NA_REAL //py_value = PyFloat_FromDouble(NA_REAL); if (py_value == NULL) { return NULL; } assert(PyFloat_CheckExact(py_value)); self = type->tp_alloc(type, 0); if (self == NULL) { //printf("--->\n"); Py_DECREF(py_value); return NULL; } ((PyFloatObject *)self)->ob_fval = ((PyFloatObject *)py_value)->ob_fval; //((PyFloatObject *)self)->ob_fval = (double)(NAREAL_IEEE.value); Py_DECREF(py_value); } Py_INCREF(self); return self; /* RPY_NA_TP_NEW("NARealType", PyFloat_Type, PyFloat_FromDouble, */ /* NA_REAL); */ } static PyObject* NAReal_New(int new) { RPY_NA_NEW(NAReal_Type, NAReal_tp_new) } static PyObject* NAReal_repr(PyObject *self) { static PyObject* repr = NULL; if (repr == NULL) { #if (PY_VERSION_HEX < 0x03010000) repr = PyString_FromString("NA_real_"); #else repr = PyUnicode_FromString("NA_real_"); #endif } Py_XINCREF(repr); return repr; } static PyNumberMethods NAReal_NumberMethods = { (binaryfunc)NA_binaryfunc, /* nb_add */ (binaryfunc)NA_binaryfunc, /* nb_subtract; */ (binaryfunc)NA_binaryfunc, /* nb_multiply; */ #if (PY_VERSION_HEX < 0x03010000) (binaryfunc)NA_binaryfunc, /* nb_divide; */ #endif (binaryfunc)NA_binaryfunc, /* nb_remainder; */ (binaryfunc)NA_binaryfunc, /* nb_divmod; */ (ternaryfunc)NA_ternaryfunc, /* nb_power; */ (unaryfunc) NA_unaryfunc, /* nb_negative; */ (unaryfunc) NA_unaryfunc, /* nb_positive; */ (unaryfunc) NA_unaryfunc, /* nb_absolute; */ (inquiry) NA_nonzero, /* nb_nonzero; -- Used by PyObject_IsTrue */ 0, /* nb_invert; */ 0, /* nb_lshift; */ 0, /* nb_rshift; */ 0, /* nb_and; */ 0, /* nb_xor; */ 0, /* nb_or; */ #if (PY_VERSION_HEX < 0x03010000) 0, //(coerce) NA_coerce, /* coercion nb_coerce; -- Used by the coerce() function */ #endif (unaryfunc) NA_unaryfunc, /* nb_int; */ #if (PY_VERSION_HEX < 0x03010000) (unaryfunc) NA_unaryfunc, /* nb_long; */ #else NULL, /* reserved */ #endif (unaryfunc) NA_unaryfunc, /* nb_float; */ #if (PY_VERSION_HEX < 0x03010000) 0, /* nb_oct; */ 0, /* nb_hex; */ #endif /* Added in release 2.0 */ 0, /* nb_inplace_add; */ 0, /* nb_inplace_subtract; */ 0, /* nb_inplace_multiply; */ #if (PY_VERSION_HEX < 0x03010000) 0, /* nb_inplace_divide; */ #endif 0, /* nb_inplace_remainder; */ 0, /* nb_inplace_power; */ 0, /* nb_inplace_lshift; */ 0, /* nb_inplace_rshift; */ 0, /* nb_inplace_and; */ 0, /* nb_inplace_xor; */ 0, /* nb_inplace_or; */ /* Added in release 2.2 */ (binaryfunc) NA_binaryfunc, /* nb_floor_divide; */ (binaryfunc) NA_binaryfunc, /* nb_true_divide; */ 0, /* nb_inplace_floor_divide; */ 0, /* nb_inplace_true_divide; */ /* Added in release 2.5 */ #if PY_VERSION_HEX >= 0x02050000 0 /* nb_index; */ #endif }; static PyTypeObject NAReal_Type = { /* The ob_type field must be initialized in the module init function * to be portable to Windows without using C++. */ #if (PY_VERSION_HEX < 0x03010000) PyObject_HEAD_INIT(NULL) 0, /*ob_size*/ #else PyVarObject_HEAD_INIT(NULL, 0) #endif "rpy2.rinterface.NARealType", /*tp_name*/ sizeof(PyFloatObject), /*tp_basicsize*/ 0, /*tp_itemsize*/ /* methods */ 0, /*tp_dealloc*/ 0, /*tp_print*/ 0, /*tp_getattr*/ 0, /*tp_setattr*/ 0, /*tp_compare*/ NAReal_repr, /*tp_repr*/ &NAReal_NumberMethods, /*tp_as_number*/ 0, /*tp_as_sequence*/ 0, /*tp_as_mapping*/ 0, /*tp_hash*/ 0, /*tp_call*/ NA_str, /*tp_str*/ 0, /*tp_getattro*/ 0, /*tp_setattro*/ 0, /*tp_as_buffer*/ #if (PY_VERSION_HEX < 0x03010000) Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_CHECKTYPES, /*tp_flags*/ #else Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /*tp_flags*/ #endif NAReal_Type_doc, /*tp_doc*/ 0, /*tp_traverse*/ 0, /*tp_clear*/ 0, /*tp_richcompare*/ 0, /*tp_weaklistoffset*/ 0, /*tp_iter*/ 0, /*tp_iternext*/ 0, //NAInteger_methods, /*tp_methods*/ 0, /*tp_members*/ 0, /*tp_getset*/ #if defined(Win32) || defined(Win64) NULL, #else &PyFloat_Type, /*tp_base*/ #endif 0, /*tp_dict*/ 0, /*tp_descr_get*/ 0, /*tp_descr_set*/ 0, /*tp_dictoffset*/ 0, //(initproc)ClosureSexp_init, /*tp_init*/ 0, /*tp_alloc*/ NAReal_tp_new, /*tp_new*/ 0, /*tp_free*/ 0 /*tp_is_gc*/ }; /* NA Character */ PyDoc_STRVAR(NACharacter_Type_doc, "Missing value for a string." ); static PyObject* NACharacter_tp_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { #if (PY_VERSION_HEX < 0x03010000) RPY_NA_TP_NEW("NACharacterType", PyString_Type, PyString_FromString, "") #else RPY_NA_TP_NEW("NACharacterType", PyUnicode_Type, PyUnicode_FromString, "") #endif } static PyObject* NACharacter_New(int new) { RPY_NA_NEW(NACharacter_Type, NACharacter_tp_new) } static PyObject* NACharacter_repr(PyObject *self) { static PyObject* repr = NULL; if (repr == NULL) { #if (PY_VERSION_HEX < 0x03010000) repr = PyString_FromString("NA_character_"); #else repr = PyUnicode_FromString("NA_character_"); #endif } Py_XINCREF(repr); return repr; } static PyTypeObject NACharacter_Type = { /* The ob_type field must be initialized in the module init function * to be portable to Windows without using C++. */ #if (PY_VERSION_HEX < 0x03010000) PyObject_HEAD_INIT(NULL) 0, /*ob_size*/ #else PyVarObject_HEAD_INIT(NULL, 0) #endif "rpy2.rinterface.NACharacterType", /*tp_name*/ #if (PY_VERSION_HEX < 0x03010000) sizeof(PyStringObject), /*tp_basicsize*/ #else sizeof(PyUnicodeObject), /*tp_basicsize*/ #endif 0, /*tp_itemsize*/ /* methods */ 0, /*tp_dealloc*/ 0, /*tp_print*/ 0, /*tp_getattr*/ 0, /*tp_setattr*/ 0, /*tp_compare*/ NACharacter_repr, /*tp_repr*/ 0, /*tp_as_number*/ 0, /*tp_as_sequence*/ 0, /*tp_as_mapping*/ 0, /*tp_hash*/ 0, /*tp_call*/ NA_str, /*tp_str*/ 0, /*tp_getattro*/ 0, /*tp_setattro*/ 0, /*tp_as_buffer*/ #if (PY_VERSION_HEX < 0x03010000) Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_CHECKTYPES, /*tp_flags*/ #else Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /*tp_flags*/ #endif NACharacter_Type_doc, /*tp_doc*/ 0, /*tp_traverse*/ 0, /*tp_clear*/ 0, /*tp_richcompare*/ 0, /*tp_weaklistoffset*/ 0, /*tp_iter*/ 0, /*tp_iternext*/ 0, //NAInteger_methods, /*tp_methods*/ 0, /*tp_members*/ 0, /*tp_getset*/ #if defined(Win32) || defined(Win64) NULL, #elif (PY_VERSION_HEX < 0x03010000) &PyString_Type, /*tp_base*/ #else &PyUnicode_Type, #endif 0, /*tp_dict*/ 0, /*tp_descr_get*/ 0, /*tp_descr_set*/ 0, /*tp_dictoffset*/ 0, //(initproc)ClosureSexp_init, /*tp_init*/ 0, /*tp_alloc*/ NACharacter_tp_new, /*tp_new*/ 0, /*tp_free*/ 0 /*tp_is_gc*/ }; /* NA Complex */ PyDoc_STRVAR(NAComplex_Type_doc, "Missing value for a complex in R." ); static PyObject* NAComplex_tp_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { //static PyObject *self = NULL; //static char *kwlist[] = {0}; Py_complex pyvalue = {(double)NAREAL_IEEE.value, (double)NAREAL_IEEE.value}; assert(PyType_IsSubtype(type, &PyComplex_Type)); RPY_NA_TP_NEW('Complex', PyComplex_Type, PyComplex_FromCComplex, pyvalue); } static PyObject* NAComplex_New(int new) { RPY_NA_NEW(NAComplex_Type, NAComplex_tp_new) } static PyObject* NAComplex_repr(PyObject *self) { static PyObject* repr = NULL; if (repr == NULL) { #if (PY_VERSION_HEX < 0x03010000) repr = PyString_FromString("NA_complex_"); #else repr = PyUnicode_FromString("NA_complex_"); #endif } Py_XINCREF(repr); return repr; } static PyNumberMethods NAComplex_NumberMethods = { (binaryfunc)NA_binaryfunc, /* nb_add */ (binaryfunc)NA_binaryfunc, /* nb_subtract; */ (binaryfunc)NA_binaryfunc, /* nb_multiply; */ #if (PY_VERSION_HEX < 0x03010000) (binaryfunc)NA_binaryfunc, /* nb_divide; */ #endif (binaryfunc)NA_binaryfunc, /* nb_remainder; */ (binaryfunc)NA_binaryfunc, /* nb_divmod; */ (ternaryfunc)NA_ternaryfunc, /* nb_power; */ (unaryfunc) NA_unaryfunc, /* nb_negative; */ (unaryfunc) NA_unaryfunc, /* nb_positive; */ (unaryfunc) NA_unaryfunc, /* nb_absolute; */ (inquiry) NA_nonzero, /* nb_nonzero; -- Used by PyObject_IsTrue */ 0, /* nb_invert; */ 0, /* nb_lshift; */ 0, /* nb_rshift; */ 0, /* nb_and; */ 0, /* nb_xor; */ 0, /* nb_or; */ #if (PY_VERSION_HEX < 0x03010000) 0, //(coerce) NA_coerce, /* coercion nb_coerce; -- Used by the coerce() function */ #endif (unaryfunc) NA_unaryfunc, /* nb_int; */ #if (PY_VERSION_HEX < 0x03010000) (unaryfunc) NA_unaryfunc, /* nb_long; */ #else NULL, /* reserved */ #endif (unaryfunc) NA_unaryfunc, /* nb_float; */ #if (PY_VERSION_HEX < 0x03010000) 0, /* nb_oct; */ 0, /* nb_hex; */ #endif /* Added in release 2.0 */ 0, /* nb_inplace_add; */ 0, /* nb_inplace_subtract; */ 0, /* nb_inplace_multiply; */ #if (PY_VERSION_HEX < 0x03010000) 0, /* nb_inplace_divide; */ #endif 0, /* nb_inplace_remainder; */ 0, /* nb_inplace_power; */ 0, /* nb_inplace_lshift; */ 0, /* nb_inplace_rshift; */ 0, /* nb_inplace_and; */ 0, /* nb_inplace_xor; */ 0, /* nb_inplace_or; */ /* Added in release 2.2 */ (binaryfunc) NA_binaryfunc, /* nb_floor_divide; */ (binaryfunc) NA_binaryfunc, /* nb_true_divide; */ 0, /* nb_inplace_floor_divide; */ 0, /* nb_inplace_true_divide; */ /* Added in release 2.5 */ #if PY_VERSION_HEX >= 0x02050000 0 /* nb_index; */ #endif }; static PyTypeObject NAComplex_Type = { /* The ob_type field must be initialized in the module init function * to be portable to Windows without using C++. */ #if (PY_VERSION_HEX < 0x03010000) PyObject_HEAD_INIT(NULL) 0, /*ob_size*/ #else PyVarObject_HEAD_INIT(NULL, 0) #endif "rpy2.rinterface.NAComplexType", /*tp_name*/ sizeof(PyComplexObject), /*tp_basicsize*/ 0, /*tp_itemsize*/ /* methods */ 0, /*tp_dealloc*/ 0, /*tp_print*/ 0, /*tp_getattr*/ 0, /*tp_setattr*/ 0, /*tp_compare*/ NAComplex_repr, /*tp_repr*/ &NAComplex_NumberMethods, /*tp_as_number*/ 0, /*tp_as_sequence*/ 0, /*tp_as_mapping*/ 0, /*tp_hash*/ 0, /*tp_call*/ NA_str, /*tp_str*/ 0, /*tp_getattro*/ 0, /*tp_setattro*/ 0, /*tp_as_buffer*/ #if (PY_VERSION_HEX < 0x03010000) Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_CHECKTYPES, /*tp_flags*/ #else Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /*tp_flags*/ #endif NAComplex_Type_doc, /*tp_doc*/ 0, /*tp_traverse*/ 0, /*tp_clear*/ 0, /*tp_richcompare*/ 0, /*tp_weaklistoffset*/ 0, /*tp_iter*/ 0, /*tp_iternext*/ 0, //NAInteger_methods, /*tp_methods*/ 0, /*tp_members*/ 0, /*tp_getset*/ #if defined(Win32) || defined(Win64) NULL, #else &PyComplex_Type, /*tp_base*/ #endif 0, /*tp_dict*/ 0, /*tp_descr_get*/ 0, /*tp_descr_set*/ 0, /*tp_dictoffset*/ 0, //(initproc)ClosureSexp_init, /*tp_init*/ 0, /*tp_alloc*/ NAComplex_tp_new, /*tp_new*/ 0, /*tp_free*/ 0 /*tp_is_gc*/ }; /* Missing parameter value (not an NA in the usual sense) */ PyDoc_STRVAR(MissingArg_Type_doc, "Missing argument (in a function call)." ); #if (PY_VERSION_HEX < 0x03010000) staticforward PyTypeObject MissingArg_Type; #else static PyTypeObject MissingArg_Type; #endif static PyObject* MissingArgType_tp_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { static PySexpObject *self = NULL; static char *kwlist[] = {0}; if (! PyArg_ParseTupleAndKeywords(args, kwds, "", kwlist)) { return NULL; } if (self == NULL) { self = (PySexpObject*)(Sexp_Type.tp_new(&MissingArg_Type, Py_None, Py_None)); if (self == NULL) { return NULL; } } Py_XINCREF(self); return (PyObject *)self; } static PyObject* MissingArgType_tp_init(PyObject *self, PyObject *args, PyObject *kwds) { static char *kwlist[] = {0}; if (! PyArg_ParseTupleAndKeywords(args, kwds, "", kwlist)) { return NULL; } return 0; } static PyObject* MissingArgType_repr(PyObject *self) { static PyObject* repr = NULL; if (repr == NULL) { #if (PY_VERSION_HEX < 0x03010000) repr = PyString_FromString("rpy2.rinterface.MissingArg"); #else repr = PyUnicode_FromString("rpy2.rinterface.MissingArg"); #endif } Py_XINCREF(repr); return repr; } static PyObject* MissingArgType_str(PyObject *self) { static PyObject* repr = NULL; if (repr == NULL) { #if (PY_VERSION_HEX < 0x03010000) repr = PyString_FromString("MissingArg"); #else repr = PyUnicode_FromString("MissingArg"); #endif } Py_XINCREF(repr); return repr; } static PyTypeObject MissingArg_Type = { /* The ob_type field must be initialized in the module init function * to be portable to Windows without using C++. */ #if (PY_VERSION_HEX < 0x03010000) PyObject_HEAD_INIT(NULL) 0, /*ob_size*/ #else PyVarObject_HEAD_INIT(NULL, 0) #endif "rpy2.rinterface.MissingArgType", /*tp_name*/ sizeof(PySexpObject), /*tp_basicsize*/ 0, /*tp_itemsize*/ /* methods */ 0, /*tp_dealloc*/ 0, /*tp_print*/ 0, /*tp_getattr*/ 0, /*tp_setattr*/ 0, /*tp_compare*/ MissingArgType_repr, /*tp_repr*/ 0, /*tp_as_number*/ 0, /*tp_as_sequence*/ 0, /*tp_as_mapping*/ 0, /*tp_hash*/ 0, /*tp_call*/ MissingArgType_str, /*tp_str*/ 0, /*tp_getattro*/ 0, /*tp_setattro*/ 0, /*tp_as_buffer*/ #if (PY_VERSION_HEX < 0x03010000) Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_CHECKTYPES, /*tp_flags*/ #else Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /*tp_flags*/ #endif MissingArg_Type_doc, /*tp_doc*/ 0, /*tp_traverse*/ 0, /*tp_clear*/ 0, /*tp_richcompare*/ 0, /*tp_weaklistoffset*/ 0, /*tp_iter*/ 0, /*tp_iternext*/ 0, //NAInteger_methods, /*tp_methods*/ 0, /*tp_members*/ 0, /*tp_getset*/ &Sexp_Type, /*tp_base*/ 0, /*tp_dict*/ 0, /*tp_descr_get*/ 0, /*tp_descr_set*/ 0, /*tp_dictoffset*/ (initproc)MissingArgType_tp_init, /*tp_init*/ 0, /*tp_alloc*/ MissingArgType_tp_new, /*tp_new*/ 0, /*tp_free*/ 0 /*tp_is_gc*/ }; static PyObject* MissingArg_Type_New(int new) { RPY_NA_NEW(MissingArg_Type, MissingArgType_tp_new) } rpy2-2.3.9/rpy/rinterface/rexternalptr.h0000644000175000017500000000030512271276146021434 0ustar laurentlaurent00000000000000#ifndef _RPY_PRIVATE_REXTPTR_H_ #define _RPY_PRIVATE_REXTPTR_H_ #ifndef _RPY_RINTERFACE_MODULE_ #error rexternalptr.h should not be included #endif static void R_PyObject_decref(SEXP s); #endif rpy2-2.3.9/rpy/rinterface/__init__.py0000644000175000017500000001161712271276146020652 0ustar laurentlaurent00000000000000import os, sys try: if ((sys.version_info.major == 2) and (sys.version_info.minor < 7)) or \ ((sys.version_info.major == 3) and (sys.version_info.minor < 3)): raise RuntimeError("Python (>=2.7 and < 3.0) or >=3.3 are required to run rpy2") except AttributeError: # Python 2.6 and earlier do not represent version_info as # a namedtuple import warnings warnings.warn("Unsupported Python version. Python (>=2.7 and < 3.0) or >=3.3 are thought to be required to run rpy2.") try: R_HOME = (os.environ["R_HOME"], ) except KeyError: tmp = os.popen("R RHOME") R_HOME = tmp.readlines() tmp.close() del(tmp) if len(R_HOME) == 0: if sys.platform == 'win32': try: import win32api import win32con hkey = win32api.RegOpenKeyEx(win32con.HKEY_LOCAL_MACHINE, "Software\\R-core\\R", 0, win32con.KEY_QUERY_VALUE ) R_HOME = win32api.RegQueryValueEx(hkey, "InstallPath")[0] win32api.RegCloseKey( hkey ) except ImportError, ie: raise RuntimeError( "No environment variable R_HOME could be found, " "calling the command 'R RHOME' does not return anything, " +\ "and unable to import win32api or win32con, " +\ "both of which being needed to retrieve where is R "+\ "from the registry. You should either specify R_HOME " +\ "or install the win32 package.") except: raise RuntimeError( "No environment variable R_HOME could be found, " "calling the command 'R RHOME' does not return anything, " +\ "and unable to determine R version from the registery." +\ "This might be because R.exe is nowhere in your Path.") else: raise RuntimeError( "R_HOME not defined, and no R command in the PATH." ) else: #Twist if 'R RHOME' spits out a warning if R_HOME[0].startswith("WARNING"): R_HOME = R_HOME[1] else: R_HOME = R_HOME[0] R_HOME = R_HOME.strip() os.environ['R_HOME'] = R_HOME # MSWindows-specific code _win_ok = False if sys.platform == 'win32': import platform architecture = platform.architecture()[0] if architecture == '32bit': _win_bindir = 'i386' elif architecture == '64bit': _win_bindir = 'x64' else: raise ValueError("Unknown architecture %s" %architecture) import win32api os.environ['PATH'] += ';' + os.path.join(R_HOME, 'bin', _win_bindir) os.environ['PATH'] += ';' + os.path.join(R_HOME, 'modules', _win_bindir) os.environ['PATH'] += ';' + os.path.join(R_HOME, 'lib') # Load the R dll using the explicit path R_DLL_DIRS = ('bin', 'lib') # Try dirs from R_DLL_DIRS for r_dir in R_DLL_DIRS: Rlib = os.path.join(R_HOME, r_dir, _win_bindir, 'R.dll') if not os.path.exists(Rlib): continue win32api.LoadLibrary( Rlib ) _win_ok = True break # Otherwise fail out! if not _win_ok: raise RuntimeError("Unable to locate R.dll within %s" % R_HOME) # cleanup the namespace del(os) try: del(win32api) del(win32con) except: pass from rpy2.rinterface._rinterface import * # wrapper in case someone changes sys.stdout: if sys.version_info.major == 3: # Print became a regular function in Python 3, making # the workaround (mostly) unnecessary (python2to3 still needs it # wrapped in a function def consolePrint(x): print(x) else: def consolePrint(x): sys.stdout.write(x) set_writeconsole(consolePrint) def consoleFlush(): sys.stdout.flush() set_flushconsole(consoleFlush) def consoleRead(prompt): text = raw_input(prompt) text += "\n" return text set_readconsole(consoleRead) def consoleMessage(x): sys.stdout.write(x) set_showmessage(consoleMessage) def chooseFile(prompt): res = raw_input(prompt) return res set_choosefile(chooseFile) def showFiles(wtitle, titlefiles, rdel, pager): sys.stdout.write(titlefiles) for wt in wtitle: sys.stdout.write(wt[0]) f = open(wt[1]) for row in f: sys.stdout.write(row) f.close() return 0 set_showfiles(showFiles) def rternalize(function): """ Takes an arbitrary Python function and wrap it in such a way that it can be called from the R side. """ assert callable(function) #FIXME: move the test down to C rpy_fun = SexpExtPtr(function, tag = python_type_tag) #rpy_type = ri.StrSexpVector(('.Python', )) #FIXME: this is a hack. Find a better way. template = parse('function(...) { .External(".Python", foo, ...) }') template[0][2][1][2] = rpy_fun return baseenv['eval'](template) # def cleanUp(saveact, status, runlast): # return True # setCleanUp(cleanUp) rpy2-2.3.9/rpy/rinterface/rpy_device.h0000644000175000017500000000452212271276146021040 0ustar laurentlaurent00000000000000#ifndef RPY_RD_H #define RPY_RD_H #include #include #include typedef struct { PyObject_HEAD; pDevDesc grdev; } PyGrDevObject; #define RPY_DEV_NUM(obj) ( 1 + ndevNumber(((PyGrDevObject *)obj)->grdev) ) #define RPY_DEV_KILLED(obj) ( ((PyGrDevObject *)obj)->killed ) #define RPY_GRDEV_BOOL_GET(self, attrname) \ PyObject *res; \ if (((PyGrDevObject *)self)->grdev->attrname == TRUE) { \ res = Py_True; \ } else { \ res = Py_False; \ } \ Py_INCREF(res); \ return res \ #define RPY_GRDEV_BOOL_SET(self, value, attrname) \ int res = 0; \ if (value == NULL) { \ PyErr_SetString(PyExc_TypeError, \ "The attribute "#attrname"cannot be deleted"); \ res = -1; \ } else if (! PyBool_Check(value)) { \ PyErr_SetString(PyExc_TypeError, \ "The attribute "#attrname" must be a boolean"); \ res = -1; \ } else if (value == Py_True) { \ ((PyGrDevObject *)self)->grdev->attrname = TRUE; \ } else if (value == Py_False) { \ ((PyGrDevObject *)self)->grdev->attrname = FALSE; \ } else { \ PyErr_SetString(PyExc_TypeError, \ "Mysterious error when setting the attribute "#attrname"."); \ res = -1; \ } \ return res #define RPY_GRDEV_BOOL_GETSET(attrname, docstring) \ PyDoc_STRVAR(GrDev_##attrname##_doc, \ docstring); \ static PyObject* \ GrDev_##attrname##_get(PyObject *self) \ { \ RPY_GRDEV_BOOL_GET(self, attrname); \ } \ static int \ GrDev_##attrname##_set(PyObject *self, PyObject *value) \ { \ RPY_GRDEV_BOOL_SET(self, value, attrname); \ } #define RPY_GRDEV_FLOAT_SET(self, value, attrname) \ int res = 0; \ if (value == NULL) { \ PyErr_SetString(PyExc_TypeError, \ "The attribute '"#attrname"' cannot be deleted"); \ res = -1; \ } else if (! PyFloat_Check(value)) { \ PyErr_SetString(PyExc_TypeError, \ "The attribute '"#attrname"' must be a float"); \ res = -1; \ } else { \ ((PyGrDevObject *)self)->grdev->attrname = PyFloat_AsDouble(value); \ } \ return res SEXP rpy_devoff(SEXP devnum, SEXP rho); #endif /* !RPY_RD_H */ rpy2-2.3.9/rpy/rinterface/_rinterface.h0000644000175000017500000002253512271276146021174 0ustar laurentlaurent00000000000000#ifndef Py__RINTERFACE_H_ #define Py__RINTERFACE_H_ #ifdef __cplusplus extern "C" { #endif #include #include #include #if defined (__APPLE__) #define _RPY_STRNDUP_ #endif /* strndup is not available on solaris prior to Solaris 5.11 */ #if defined (sun) || defined (__sun) #if defined (__SunOS_5_11) #include #else #define _RPY_STRNDUP_ #endif #endif /* * Highest possible SEXP type (used for quick resolution of valid/invalid SEXP) */ #define RPY_MAX_VALIDSEXTYPE 99 typedef struct { Py_ssize_t count; SEXP sexp; } SexpObject; typedef struct { PyObject_HEAD SexpObject *sObj; /* SEXP sexp; */ } PySexpObject; #define RPY_COUNT(obj) (((obj)->sObj)->count) #define RPY_SEXP(obj) (((obj)->sObj)->sexp) /* #define RPY_SEXP(obj) ((obj)->sexp) */ /* #define RPY_RPYONLY(obj) (((obj)->sObj)->rpy_only) */ #define RPY_INCREF(obj) (((obj)->sObj)->count++) /* #define RPY_DECREF(obj) (((obj)->sObj)->count--) */ #define RPY_RINT_FROM_LONG(value) \ ((value<=(long)INT_MAX && value>=(long)INT_MIN)?(int)value:NA_INTEGER) #define RPY_PY_FROM_RBOOL(res, rbool) \ if (rbool == NA_LOGICAL) { \ Py_INCREF(Py_None); \ res = Py_None; \ } else { \ res = PyBool_FromLong((long)(rbool)); \ } #define RPY_GIL_ENSURE(is_threaded, gstate) \ if (is_threaded) { \ gstate = PyGILState_Ensure(); \ } #define RPY_GIL_RELEASE(is_threaded, gstate) \ if (is_threaded) { \ PyGILState_Release(gstate); \ } #if (PY_VERSION_HEX < 0x03010000) #define RPY_PYSCALAR_TESTINT PyInt_Check #else #define RPY_PYSCALAR_TESTINT PyLong_Check #endif #if (PY_VERSION_HEX < 0x03010000) #define RPY_PYSCALAR_SETINT(py_obj)\ ((int)(PyInt_AS_LONG(py_obj))); #else #define RPY_PYSCALAR_SETINT(py_obj)\ RPY_RINT_FROM_LONG(PyLong_AsLong(py_obj)); #endif #define RPY_PYSCALAR_RVECTOR(py_obj, sexp) \ sexp = NULL; \ /* The argument is not a PySexpObject, so we are going to check \ if conversion from a scalar type is possible */ \ if ((py_obj) == NACharacter_New(0)) { \ sexp = NA_STRING; \ } else if ((py_obj) == NAInteger_New(0)) { \ sexp = allocVector(INTSXP, 1); \ PROTECT(sexp); \ protect_count++; \ INTEGER_POINTER(sexp)[0] = NA_INTEGER; \ } else if ((py_obj) == NALogical_New(0)) { \ sexp = allocVector(LGLSXP, 1); \ PROTECT(sexp); \ protect_count++; \ LOGICAL_POINTER(sexp)[0] = NA_LOGICAL; \ } else if ((py_obj) == NAReal_New(0)) { \ sexp = allocVector(REALSXP, 1); \ PROTECT(sexp); \ protect_count++; \ NUMERIC_POINTER(sexp)[0] = NA_REAL; \ } else if (PyBool_Check(py_obj)) { \ sexp = allocVector(LGLSXP, 1); \ LOGICAL_POINTER(sexp)[0] = py_obj == Py_True ? TRUE : FALSE; \ PROTECT(sexp); \ protect_count++; \ } else if (RPY_PYSCALAR_TESTINT(py_obj)) { \ sexp = allocVector(INTSXP, 1); \ INTEGER_POINTER(sexp)[0] = RPY_PYSCALAR_SETINT(py_obj); \ PROTECT(sexp); \ protect_count++; \ } else if (PyLong_Check(py_obj)) { \ sexp = allocVector(INTSXP, 1); \ INTEGER_POINTER(sexp)[0] = RPY_RINT_FROM_LONG(PyLong_AsLong(py_obj)); \ if ((INTEGER_POINTER(sexp)[0] == -1) && PyErr_Occurred() ) { \ INTEGER_POINTER(sexp)[0] = NA_INTEGER; \ PyErr_Clear(); \ } \ PROTECT(sexp); \ protect_count++; \ } else if (PyFloat_Check(py_obj)) { \ sexp = allocVector(REALSXP, 1); \ NUMERIC_POINTER(sexp)[0] = PyFloat_AS_DOUBLE(py_obj); \ PROTECT(sexp); \ protect_count++; \ } else if (py_obj == Py_None) { \ sexp = R_NilValue; \ } #define RPY_NA_TP_NEW(type_name, parent_type, pyconstructor, value) \ static PyObject *self = NULL; \ static char *kwlist[] = {0}; \ PyObject *py_value, *new_args; \ \ if (! PyArg_ParseTupleAndKeywords(args, kwds, "", kwlist)) { \ return NULL; \ } \ \ if (self == NULL) { \ py_value = (pyconstructor)(value); \ if (py_value == NULL) { \ return NULL; \ } \ new_args = PyTuple_Pack(1, py_value); \ if (new_args == NULL) { \ return NULL; \ } \ self = (parent_type).tp_new(type, new_args, kwds); \ Py_DECREF(new_args); \ if (self == NULL) { \ return NULL; \ } \ } \ Py_XINCREF(self); \ return (PyObject *)self; \ #define RPY_NA_NEW(type, type_tp_new) \ static PyObject *args = NULL; \ static PyObject *kwds = NULL; \ PyObject *res; \ \ if (args == NULL) { \ args = PyTuple_Pack(0); \ } \ if (kwds == NULL) { \ kwds = PyDict_New(); \ } \ \ res = (type_tp_new)(&(type), args, kwds); \ if (! new) { \ Py_DECREF(res); \ } \ return res; \ /* C API functions */ #define PyRinterface_API_NAME "rpy2.rinterface._rinterface._C_API" /* -- check initialization */ #define PyRinterface_IsInitialized_NUM 0 #define PyRinterface_IsInitialized_RETURN int #define PyRinterface_IsInitialized_PROTO (void) /* -- check findfun */ #define PyRinterface_FindFun_NUM 1 #define PyRinterface_FindFun_RETURN SEXP #define PyRinterface_FindFun_PROTO (SEXP, SEXP) /* Total nmber of C API pointers */ #define PyRinterface_API_pointers 2 #ifdef _RINTERFACE_MODULE /* This section is used when compiling _rinterface.c */ static PyRinterface_IsInitialized_RETURN PyRinterface_IsInitialized PyRinterface_IsInitialized_PROTO; static PyRinterface_FindFun_RETURN PyRinterface_FindFun PyRinterface_FindFun_PROTO; static PyObject *embeddedR_isInitialized; #else /* This section is used in modules that use _rinterface's API */ static void **PyRinterface_API; #define PyRinterface_IsInitialized \ (*(PyRinterface_IsInitialized_RETURN (*)PyRinterface_IsInitialized_PROTO) PyRinterface_API[PyRinterface_IsInitialized_NUM]) #define PyRinterface_FindFun \ (*(PyRinterface_FindFun_RETURN (*)PyRinterface_FindFun_PROTO) PyRinterface_API[PyRinterface_FindFun_NUM]) /* Return -1 on error, 0 on success. * PyCapsule_Import will set an exception if there's an error. */ static int import_rinterface(void) { PyRinterface_API = (void **)PyCapsule_Import(PyRinterface_API_NAME, 0); return (PyRinterface_API != NULL) ? 0 : -1; } #endif #ifdef __cplusplus } #endif #endif /* !Py__RINTERFACE_H_ */ rpy2-2.3.9/rpy/rinterface/r_utils.c0000644000175000017500000001151212271276146020360 0ustar laurentlaurent00000000000000/* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * Copyright (C) 2008-2013 Laurent Gautier * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ #include SEXP rpy_serialize(SEXP object, SEXP rho) { SEXP c_R, call_R, res, fun_R; PROTECT(fun_R = PyRinterface_FindFun(install("serialize"), rho)); if(!isEnvironment(rho)) error("'rho' should be an environment"); /* obscure incatation to summon R */ PROTECT(c_R = call_R = allocList(3)); SET_TYPEOF(c_R, LANGSXP); SETCAR(c_R, fun_R); c_R = CDR(c_R); /* first argument is the SEXP object to serialize */ SETCAR(c_R, object); c_R = CDR(c_R); /* second argument is NULL */ SETCAR(c_R, R_NilValue); c_R = CDR(c_R); PROTECT(res = eval(call_R, rho)); UNPROTECT(3); return res; } SEXP rpy_unserialize(SEXP connection, SEXP rho) { SEXP c_R, call_R, res, fun_R; PROTECT(fun_R = PyRinterface_FindFun(install("unserialize"), rho)); if(!isEnvironment(rho)) error("'rho' should be an environment"); /* obscure incatation to summon R */ PROTECT(c_R = call_R = allocList(2)); SET_TYPEOF(c_R, LANGSXP); SETCAR(c_R, fun_R); c_R = CDR(c_R); /* first argument is a RAWSXP representation of the object to unserialize */ SETCAR(c_R, connection); c_R = CDR(c_R); PROTECT(res = eval(call_R, rho)); UNPROTECT(2); return res; } SEXP rpy_list_attr(SEXP sexp) { SEXP attrs, res; int nvalues, attr_i; attrs = ATTRIB(sexp); nvalues = GET_LENGTH(attrs); PROTECT(res = allocVector(STRSXP, nvalues)); attr_i = 0; while (attrs != R_NilValue) { if (TAG(attrs) == R_NilValue) SET_STRING_ELT(res, attr_i, R_BlankString); else SET_STRING_ELT(res, attr_i, PRINTNAME(TAG(attrs))); attrs = CDR(attrs); attr_i++; } UNPROTECT(1); return res; } SEXP rpy_remove(SEXP symbol, SEXP env, SEXP rho) { SEXP c_R, call_R, res; static SEXP fun_R = NULL; if (fun_R == NULL) { PROTECT(fun_R = PyRinterface_FindFun(install("rm"), rho)); /* FIXME: or use the rpy2 object tracking layer ?*/ R_PreserveObject(fun_R); UNPROTECT(1); } if(!isEnvironment(rho)) error("'rho' should be an environment"); /* incantation to summon R */ PROTECT(c_R = call_R = allocList(2+1)); SET_TYPEOF(c_R, LANGSXP); SETCAR(c_R, fun_R); c_R = CDR(c_R); /* first argument is the name of the variable to be removed */ SETCAR(c_R, symbol); //SET_TAG(c_R, install("list")); c_R = CDR(c_R); /* second argument is the environment in which the variable should be removed */ SETCAR(c_R, env); SET_TAG(c_R, install("envir")); c_R = CDR(c_R); int error = 0; PROTECT(res = R_tryEval(call_R, rho, &error)); UNPROTECT(2); return res; } SEXP rpy_lang2str(SEXP sexp, SEXPTYPE t) { SEXP symbol = CAR(sexp); static struct{ SEXP if_sym; SEXP while_sym; SEXP for_sym; SEXP eq_sym; SEXP gets_sym; SEXP lpar_sym; SEXP lbrace_sym; SEXP call_sym; } s_str = {0, 0, 0, 0, 0, 0, 0, 0}; if(!s_str.if_sym) { s_str.if_sym = install("if"); s_str.while_sym = install("while"); s_str.for_sym = install("for"); s_str.eq_sym = install("="); s_str.gets_sym = install("<-"); s_str.lpar_sym = install("("); s_str.lbrace_sym = install("{"); s_str.call_sym = install("call"); } if(Rf_isSymbol(symbol)) { if(symbol == s_str.if_sym || symbol == s_str.for_sym || symbol == s_str.while_sym || symbol == s_str.lpar_sym || symbol == s_str.lbrace_sym || symbol == s_str.eq_sym || symbol == s_str.gets_sym) return PRINTNAME(symbol); } return PRINTNAME(s_str.call_sym); } rpy2-2.3.9/rpy/rinterface/sexp.h0000644000175000017500000000060012271276146017657 0ustar laurentlaurent00000000000000#ifndef _RPY_PRIVATE_SEXP_H_ #define _RPY_PRIVATE_SEXP_H_ #ifndef _RPY_RINTERFACE_MODULE_ #error sexp.h should not be included directly #endif #include #include #include #include static PyObject* EmbeddedR_unserialize(PyObject* self, PyObject* args); static PyObject *rinterface_unserialize; static PyTypeObject Sexp_Type; #endif rpy2-2.3.9/rpy/rinterface/sexp.c0000644000175000017500000005434612271276146017672 0ustar laurentlaurent00000000000000/* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * Copyright (C) 2008-2012 Laurent Gautier * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ #include #include "r_utils.h" #include "embeddedr.h" #include "sexp.h" static void Sexp_clear(PySexpObject *self) { Rpy_ReleaseObject(self->sObj->sexp); } static void Sexp_dealloc(PySexpObject *self) { Sexp_clear(self); #if (PY_VERSION_HEX < 0x03010000) (self->ob_type->tp_free)((PyObject*)self); #else (Py_TYPE(self)->tp_free)((PyObject *)self); #endif /* PyObject_Del(self); */ } static PyObject* Sexp_repr(PyObject *self) { /* FIXME: make sure this is making any sense */ SEXP sexp = RPY_SEXP((PySexpObject *)self); /* if (! sexp) { * PyErr_Format(PyExc_ValueError, "NULL SEXP."); * return NULL; *} */ #if (PY_VERSION_HEX < 0x03010000) return PyString_FromFormat("<%s - Python:\%p / R:\%p>", self->ob_type->tp_name, self, sexp); #else return PyUnicode_FromFormat("<%s - Python:\%p / R:\%p>", self->ob_type->tp_name, self, sexp); #endif } static PyObject* Sexp_typeof_get(PyObject *self) { PySexpObject *pso = (PySexpObject*)self; SEXP sexp = RPY_SEXP(pso); if (! sexp) { PyErr_Format(PyExc_ValueError, "NULL SEXP."); return NULL; } #if (PY_VERSION_HEX < 0x03010000) return PyInt_FromLong((long)TYPEOF(sexp)); #else return PyLong_FromLong((long)TYPEOF(sexp)); #endif } PyDoc_STRVAR(Sexp_typeof_doc, "R internal SEXPREC type."); PyDoc_STRVAR(Sexp_list_attr_doc, "Returns the list of attribute names."); PyObject* Sexp_list_attr(PyObject *self) { SEXP sexp = RPY_SEXP(((PySexpObject*)self)); if (! sexp) { PyErr_Format(PyExc_ValueError, "NULL SEXP."); return NULL; } SEXP res_R; PROTECT(res_R = rpy_list_attr(sexp)); PyObject *res = (PyObject *)newPySexpObject(res_R); UNPROTECT(1); return res; } static PyObject* Sexp_do_slot(PyObject *self, PyObject *name) { SEXP sexp = RPY_SEXP(((PySexpObject*)self)); if (! sexp) { PyErr_Format(PyExc_ValueError, "NULL SEXP."); return NULL; } #if (PY_VERSION_HEX < 0x03010000) if (! PyString_Check(name)) { #else if (! PyUnicode_Check(name)) { #endif PyErr_SetString(PyExc_TypeError, "The name must be a string."); return NULL; } #if (PY_VERSION_HEX < 0x03010000) char *name_str = PyString_AS_STRING(name); #else PyObject *pybytes = PyUnicode_AsLatin1String(name); char *name_str = PyBytes_AsString(pybytes); #endif if (! R_has_slot(sexp, install(name_str))) { PyErr_SetString(PyExc_LookupError, "The object has no such attribute."); #if (PY_VERSION_HEX >= 0x03010000) Py_DECREF(pybytes); #endif return NULL; } SEXP res_R = GET_SLOT(sexp, install(name_str)); #if (PY_VERSION_HEX >= 0x03010000) Py_DECREF(pybytes); #endif PyObject *res = (PyObject *)newPySexpObject(res_R); return res; } PyDoc_STRVAR(Sexp_do_slot_doc, "Returns the attribute/slot for an R object.\n" " The name of the slot (a string) is the only parameter for\n" "the method.\n" ":param name: string\n" ":rtype: instance of type or subtype :class:`rpy2.rinterface.Sexp`"); static PyObject* Sexp_do_slot_assign(PyObject *self, PyObject *args) { SEXP sexp = RPY_SEXP(((PySexpObject*)self)); if (! sexp) { PyErr_Format(PyExc_ValueError, "NULL SEXP."); return NULL;; } char *name_str; PyObject *value; if (! PyArg_ParseTuple(args, "sO", &name_str, &value)) { return NULL; } if (! PyObject_IsInstance(value, (PyObject*)&Sexp_Type)) { PyErr_Format(PyExc_ValueError, "Value must be an instance of Sexp."); return NULL; } SEXP value_sexp = RPY_SEXP((PySexpObject *)value); if (! value_sexp) { PyErr_Format(PyExc_ValueError, "NULL SEXP."); return NULL;; } SET_SLOT(sexp, install(name_str), value_sexp); Py_INCREF(Py_None); return Py_None; } PyDoc_STRVAR(Sexp_do_slot_assign_doc, "Set the attribute/slot for an R object.\n" "\n" ":param name: string\n" ":param value: instance of :class:`rpy2.rinterface.Sexp`"); static PyObject* Sexp_named_get(PyObject *self) { SEXP sexp = RPY_SEXP(((PySexpObject*)self)); if (! sexp) { PyErr_Format(PyExc_ValueError, "NULL SEXP."); return NULL;; } unsigned int res = NAMED(sexp); #if (PY_VERSION_HEX < 0x03010000) return PyInt_FromLong((long)res); #else return PyLong_FromLong((long)res); #endif } PyDoc_STRVAR(Sexp_named_doc, "Integer code for the R object reference-pseudo counting.\n\ This method corresponds to the macro NAMED.\n\ See the R-extensions manual for further details."); /* Get the underlying R object exposed by rpy2 as a Python capsule. This is needed to overcome the pass-by-value (pass-by-need) paradigm in R and provide the appearance of pass-by-reference from the Python side. */ static PyObject* Sexp_sexp_get(PyObject *self, void *closure) { PySexpObject* rpyobj = (PySexpObject*)self; if (! RPY_SEXP(rpyobj)) { PyErr_Format(PyExc_ValueError, "NULL SEXP."); return NULL;; } PyObject *key = PyLong_FromVoidPtr((void *)rpyobj->sObj->sexp); PyObject *capsule = PyDict_GetItem(Rpy_R_Precious, key); if (capsule == NULL) { printf("Error: Could not get the capsule for the SEXP. This means trouble.\n"); return NULL; } Py_DECREF(key); /* capsule is a borrowed reference: INCREF */ Py_INCREF(capsule); return capsule; } /* Assign a new underlying R object to the Python representation */ static int Sexp_sexp_set(PyObject *self, PyObject *obj, void *closure) { if (! PyCapsule_CheckExact(obj)) { PyErr_SetString(PyExc_TypeError, "The value must be a Capsule"); return -1; } SexpObject *sexpobj_new = (SexpObject *)(PyCapsule_GetPointer(obj, "rpy2.rinterface._C_API_")); if (sexpobj_new == NULL) { PyErr_SetString(PyExc_TypeError, "The value must be a CObject or a Capsule of name 'rpy2.rinterface._C_API_'."); return -1; } SexpObject *sexpobj_orig = ((PySexpObject*)self)->sObj; #ifdef RPY_DEBUG_COBJECT printf("Setting %p (count: %i) to %p (count: %i)\n", sexpobj_orig, (int)sexpobj_orig->count, sexpobj_new, (int)sexpobj_new->count); #endif if ( (sexpobj_orig->sexp != R_NilValue) & (TYPEOF(sexpobj_orig->sexp) != TYPEOF(sexpobj_new->sexp)) ) { PyErr_Format(PyExc_ValueError, "Mismatch in SEXP type (as returned by typeof)"); return -1; } SEXP sexp = sexpobj_new->sexp; if (! sexp) { PyErr_Format(PyExc_ValueError, "NULL SEXP."); return -1; } return Rpy_ReplaceSexp((PySexpObject *)self, sexp); } PyDoc_STRVAR(Sexp_sexp_doc, "Opaque C pointer to the underlying R object"); static PyObject* Sexp_rclass_get(PyObject *self, void *closure) { SEXP sexp = RPY_SEXP(((PySexpObject*)self)); if (! sexp) { PyErr_Format(PyExc_ValueError, "NULL SEXP."); return NULL;; } /* SEXP res_R = R_data_class(sexp, TRUE);*/ /* R_data_class is not exported, although R's own package "methods" needs it as part of the API. We are getting the R class by ourselves. This is problematic since we are now exposed to changes in the behaviour of R_data_class. */ SEXP res_R = getAttrib(sexp, R_ClassSymbol); int nclasses = length(res_R); if (nclasses == 0) { /* if no explicit class, R will still consider the presence of dimensions, then the "TYPEOF" */ SEXP sexp_dim = getAttrib(sexp, R_DimSymbol); int nd = length(sexp_dim); if(nd > 0) { if(nd == 2) res_R = mkChar("matrix"); else res_R = mkChar("array"); } else { SEXPTYPE t = TYPEOF(sexp); switch(t) { case CLOSXP: case SPECIALSXP: case BUILTINSXP: res_R = mkChar("function"); break; case REALSXP: res_R = mkChar("numeric"); break; case SYMSXP: res_R = mkChar("name"); break; case LANGSXP: /* res_R = lang2str(sexp, t);*/ /* lang2str is not part of the R API, yadayadayada....*/ res_R = rpy_lang2str(sexp, t); break; default: res_R = Rf_type2str(t); } } } else { res_R = asChar(res_R); } PROTECT(res_R); SEXP class_Rstring = ScalarString(res_R); UNPROTECT(1); PyObject *res = (PyObject *)newPySexpObject(class_Rstring); return res; } /* Return -1 on failure, with an exception set. */ static int Sexp_rclass_set(PyObject *self, PyObject *value, void *closure) { SEXP sexp = RPY_SEXP(((PySexpObject*)self)); if (! sexp) { PyErr_Format(PyExc_ValueError, "NULL SEXP."); return -1; } if (! PyObject_IsInstance(value, (PyObject*)&Sexp_Type)) { PyErr_Format(PyExc_ValueError, "Value must be a Sexp."); return NULL; } SEXP sexp_class = RPY_SEXP((PySexpObject*)value); SET_CLASS(sexp, sexp_class); return 0; } PyDoc_STRVAR(Sexp_rclass_doc, "R class name (and in R the class is an attribute and can be set)."); static PyObject* Sexp_rid_get(PyObject *self) { SEXP sexp = RPY_SEXP(((PySexpObject*)self)); if (! sexp) { PyErr_Format(PyExc_ValueError, "NULL SEXP."); return NULL;; } PyObject *res = PyLong_FromVoidPtr((void *)sexp); return res; } PyDoc_STRVAR(Sexp_rid_doc, "ID for the associated R object (Hint: that's a memory address)"); static PyObject* Sexp_refcount_get(PyObject *self) { PySexpObject* rpyobj = (PySexpObject*)self; if (! RPY_SEXP(rpyobj)) { PyErr_Format(PyExc_ValueError, "NULL SEXP."); return NULL; } #if (PY_VERSION_HEX < 0x03010000) PyObject *res = PyInt_FromLong((long)(rpyobj->sObj->count)); #else PyObject *res = PyLong_FromLong((long)(rpyobj->sObj->count)); #endif return res; } PyDoc_STRVAR(Sexp_refcount_doc, "Reference counter for the underlying R object"); static PyObject* Sexp_rsame(PyObject *self, PyObject *other) { if (! PyObject_IsInstance(other, (PyObject*)&Sexp_Type)) { PyErr_Format(PyExc_ValueError, "Can only compare Sexp objects."); return NULL; } SEXP sexp_self = RPY_SEXP(((PySexpObject*)self)); if (! sexp_self) { PyErr_Format(PyExc_ValueError, "NULL SEXP."); return NULL;; } SEXP sexp_other = RPY_SEXP(((PySexpObject*)other)); if (! sexp_other) { PyErr_Format(PyExc_ValueError, "NULL SEXP."); return NULL;; } long same = (sexp_self == sexp_other); return PyBool_FromLong(same); } PyDoc_STRVAR(Sexp_rsame_doc, "Is the given object representing the same underlying R object as the instance."); static PyObject* Sexp_duplicate(PyObject *self, PyObject *kwargs) { SEXP sexp_self, sexp_copy; PyObject *res; sexp_self = RPY_SEXP((PySexpObject*)self); if (! sexp_self) { PyErr_Format(PyExc_ValueError, "NULL SEXP."); return NULL;; } PROTECT(sexp_copy = Rf_duplicate(sexp_self)); res = (PyObject *) newPySexpObject(sexp_copy); UNPROTECT(1); return res; } PyDoc_STRVAR(Sexp_duplicate_doc, "Makes a copy of the underlying Sexp object, and returns it."); static PyObject* Sexp___getstate__(PyObject *self) { PyObject *res_string; SEXP sexp = RPY_SEXP((PySexpObject *)self); if (! sexp) { PyErr_Format(PyExc_ValueError, "NULL SEXP."); return NULL; } SEXP sexp_ser; PROTECT(sexp_ser = rpy_serialize(sexp, R_GlobalEnv)); if (TYPEOF(sexp_ser) != RAWSXP) { UNPROTECT(1); PyErr_Format(PyExc_RuntimeError, "R's serialize did not return a raw vector."); return NULL; } /* PyByteArray is only available with Python >= 2.6 */ /* res = PyByteArray_FromStringAndSize(sexp_ser, len); */ /*FIXME: is this working on 64bit archs ? */ #if (PY_VERSION_HEX < 0x03010000) res_string = PyString_FromStringAndSize((void *)RAW_POINTER(sexp_ser), (Py_ssize_t)LENGTH(sexp_ser)); #else res_string = PyBytes_FromStringAndSize((void *)RAW_POINTER(sexp_ser), (Py_ssize_t)LENGTH(sexp_ser)); #endif UNPROTECT(1); return res_string; } PyDoc_STRVAR(Sexp___getstate___doc, "Returns a serialized object for the underlying R object"); static PyObject* Sexp___setstate__(PyObject *self, PyObject *state) { Py_INCREF(Py_None); return Py_None; } PyDoc_STRVAR(Sexp___setstate___doc, "set the state of an instance (dummy)."); static PyObject* EmbeddedR_unserialize(PyObject* self, PyObject* args) { PyObject *res; if (! (rpy_has_status(RPY_R_INITIALIZED))) { PyErr_Format(PyExc_RuntimeError, "R cannot evaluate code before being initialized."); return NULL; } char *raw; Py_ssize_t raw_size; int rtype; if (! PyArg_ParseTuple(args, "s#i", &raw, &raw_size, &rtype)) { return NULL; } if (rpy_has_status(RPY_R_BUSY)) { PyErr_Format(PyExc_RuntimeError, "Concurrent access to R is not allowed."); return NULL; } embeddedR_setlock(); /* Not the most memory-efficient; an other option would * be to create a dummy RAW and rebind "raw" as its content * (wich seems clearly off the charts). */ SEXP raw_sexp, sexp_ser; PROTECT(raw_sexp = NEW_RAW((int)raw_size)); /*FIXME: use of the memcpy seems to point in the direction of * using the option mentioned above anyway. */ Py_ssize_t raw_i; for (raw_i = 0; raw_i < raw_size; raw_i++) { RAW_POINTER(raw_sexp)[raw_i] = raw[raw_i]; } PROTECT(sexp_ser = rpy_unserialize(raw_sexp, R_GlobalEnv)); if (TYPEOF(sexp_ser) != rtype) { UNPROTECT(2); PyErr_Format(PyExc_ValueError, "Mismatch between the serialized object" " and the expected R type" " (expected %i but got %i)", rtype, TYPEOF(raw_sexp)); return NULL; } res = (PyObject*)newPySexpObject(sexp_ser); UNPROTECT(2); embeddedR_freelock(); return res; } static PyObject* Sexp___reduce__(PyObject* self) { PyObject *dict, *result; if (! (rpy_has_status(RPY_R_INITIALIZED))) { PyErr_Format(PyExc_RuntimeError, "R cannot evaluate code before being initialized."); return NULL; } dict = PyObject_GetAttrString((PyObject *)self, "__dict__"); if (dict == NULL) { PyErr_Clear(); dict = Py_None; Py_INCREF(dict); } if (rpy_has_status(RPY_R_BUSY)) { PyErr_Format(PyExc_RuntimeError, "Concurrent access to R is not allowed."); return NULL; } embeddedR_setlock(); result = Py_BuildValue("O(Oi)O", rinterface_unserialize, /* constructor */ Sexp___getstate__(self), TYPEOF(RPY_SEXP((PySexpObject *)self)), dict); embeddedR_freelock(); Py_DECREF(dict); return result; } PyDoc_STRVAR(Sexp___reduce___doc, "Prepare an instance for serialization."); static PyMethodDef Sexp_methods[] = { {"list_attrs", (PyCFunction)Sexp_list_attr, METH_NOARGS, Sexp_list_attr_doc}, {"do_slot", (PyCFunction)Sexp_do_slot, METH_O, Sexp_do_slot_doc}, {"do_slot_assign", (PyCFunction)Sexp_do_slot_assign, METH_VARARGS, Sexp_do_slot_assign_doc}, {"rsame", (PyCFunction)Sexp_rsame, METH_O, Sexp_rsame_doc}, #if (PY_VERSION_HEX < 0x03010000) {"__deepcopy__", (PyCFunction)Sexp_duplicate, METH_KEYWORDS, Sexp_duplicate_doc}, #else {"__deepcopy__", (PyCFunction)Sexp_duplicate, METH_VARARGS | METH_KEYWORDS, Sexp_duplicate_doc}, #endif {"__getstate__", (PyCFunction)Sexp___getstate__, METH_NOARGS, Sexp___getstate___doc}, {"__setstate__", (PyCFunction)Sexp___setstate__, METH_O, Sexp___setstate___doc}, {"__reduce__", (PyCFunction)Sexp___reduce__, METH_NOARGS, Sexp___reduce___doc}, {NULL, NULL} /* sentinel */ }; static PyGetSetDef Sexp_getsets[] = { {"named", (getter)Sexp_named_get, (setter)0, Sexp_named_doc}, {"typeof", (getter)Sexp_typeof_get, (setter)0, Sexp_typeof_doc}, {"rclass", (getter)Sexp_rclass_get, (setter)Sexp_rclass_set, Sexp_rclass_doc}, {"rid", (getter)Sexp_rid_get, (setter)0, Sexp_rid_doc}, {"__sexp__", (getter)Sexp_sexp_get, (setter)Sexp_sexp_set, Sexp_sexp_doc}, {"__sexp_refcount__", (getter)Sexp_refcount_get, (setter)0, Sexp_refcount_doc}, {NULL, NULL, NULL, NULL} /* sentinel */ }; static PyObject* Sexp_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { PySexpObject *self = NULL; /* unsigned short int rpy_only = 1; */ #ifdef RPY_VERBOSE printf("new '%s' object @...\n", type->tp_name); #endif /* self = (PySexpObject *)PyObject_New(PySexpObject, type); */ self = (PySexpObject *)type->tp_alloc(type, 0); #ifdef RPY_VERBOSE printf(" Python:%p / R:%p (R_NilValue) ...\n", self, R_NilValue); #endif if (! self) PyErr_NoMemory(); self->sObj = Rpy_PreserveObject(R_NilValue); if (self->sObj == NULL) { printf("Error in Sexp_new. This is not looking good...\n"); } #ifdef RPY_VERBOSE printf("done.\n"); #endif return (PyObject *)self; } static int Sexp_init(PyObject *self, PyObject *args, PyObject *kwds) { #ifdef RPY_VERBOSE printf("Python:%p / R:%p - Sexp initializing...\n", self, RPY_SEXP((PySexpObject *)self)); #endif PyObject *sourceObject; PyObject *copy = Py_True; int sexptype = -1; static char *kwlist[] = {"sexp", "sexptype", NULL}; /* FIXME: handle the copy argument */ /* the "sexptype" is as a quick hack to make calls from the constructor of SexpVector */ if (! PyArg_ParseTupleAndKeywords(args, kwds, "O|i", kwlist, &sourceObject, &sexptype)) { return -1; } if (! PyObject_IsInstance(sourceObject, (PyObject*)&Sexp_Type)) { PyErr_Format(PyExc_ValueError, "Can only instanciate from Sexp objects."); return -1; } /* Since sourceObject is a Sexp_Type, the R object is already tracked. */ /* int swap = Rpy_ReplaceSexp(((PySexpObject *)self)->sObj, */ /* ((PySexpObject *)sourceObject)->sObj->sexp); */ /* if (swap == -1) { */ /* return -1; */ /* } */ SexpObject *oldSexpObject = ((PySexpObject *)self)->sObj; SexpObject *newSexpObject = Rpy_PreserveObject(((PySexpObject *)sourceObject)->sObj->sexp); if (newSexpObject == NULL) { return -1; } ((PySexpObject *)self)->sObj = newSexpObject; if (Rpy_ReleaseObject(oldSexpObject->sexp) == -1) { return -1; } //RPY_INCREF((PySexpObject *)self); #ifdef RPY_VERBOSE printf("Python: %p / R: %p - sexp count is now %i.\n", (PySexpObject *)self, RPY_SEXP((PySexpObject *)self), RPY_COUNT((PySexpObject *)self)); #endif #ifdef RPY_VERBOSE printf("done.\n"); #endif /* SET_NAMED(RPY_SEXP((PySexpObject *)self), (unsigned int)2); */ return 0; } /* * Generic Sexp_Type. It represents SEXP objects at large. */ static PyTypeObject Sexp_Type = { /* The ob_type field must be initialized in the module init function * to be portable to Windows without using C++. */ #if (PY_VERSION_HEX < 0x03010000) PyObject_HEAD_INIT(NULL) 0, /*ob_size*/ #else PyVarObject_HEAD_INIT(NULL, 0) #endif "rpy2.rinterface.Sexp", /*tp_name*/ sizeof(PySexpObject), /*tp_basicsize*/ 0, /*tp_itemsize*/ /* methods */ (destructor)Sexp_dealloc, /*tp_dealloc*/ 0, /*tp_print*/ 0, /*tp_getattr*/ 0, /*tp_setattr*/ 0, /*tp_compare*/ Sexp_repr, /*tp_repr*/ 0, /*tp_as_number*/ 0, /*tp_as_sequence*/ 0, /*tp_as_mapping*/ 0, /*tp_hash*/ 0, /*tp_call*/ 0, /*tp_str*/ 0, /*tp_getattro*/ 0, /*tp_setattro*/ 0, /*tp_as_buffer*/ Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /*tp_flags*/ 0, /*tp_doc*/ 0, /*tp_traverse*/ (inquiry)Sexp_clear, /*tp_clear*/ 0, /*tp_richcompare*/ 0, /*tp_weaklistoffset*/ 0, /*tp_iter*/ 0, /*tp_iternext*/ Sexp_methods, /*tp_methods*/ 0, /*tp_members*/ Sexp_getsets, /*tp_getset*/ 0, /*tp_base*/ 0, /*tp_dict*/ 0, /*tp_descr_get*/ 0, /*tp_descr_set*/ 0, /*tp_dictoffset*/ (initproc)Sexp_init, /*tp_init*/ 0, /*tp_alloc*/ Sexp_new, /*tp_new*/ 0, /*tp_free*/ 0, /*tp_is_gc*/ }; rpy2-2.3.9/rpy/rinterface/na_values.h0000644000175000017500000000111012271276146020652 0ustar laurentlaurent00000000000000#ifndef _RPY_PRIVATE_NAVALUES_H_ #define _RPY_PRIVATE_NAVALUES_H_ #ifndef _RPY_RINTERFACE_MODULE_ #error na_values.h should not be included #endif static PyTypeObject NAInteger_Type; static PyTypeObject NAReal_Type; static PyTypeObject NAComplex_Type; static PyTypeObject NALogical_Type; static PyTypeObject NACharacter_Type; typedef union { double value; unsigned int word[2]; } ieee_double; #ifdef RPY_BIGENDIAN static const ieee_double NAREAL_IEEE = {.word = {0x7ff00000, 1954}}; #else static const ieee_double NAREAL_IEEE = {.word = {1954, 0x7ff00000}}; #endif #endif rpy2-2.3.9/rpy/rinterface/embeddedr.c0000644000175000017500000002313512271276146020616 0ustar laurentlaurent00000000000000#include "embeddedr.h" /* Helper variable to store R's status */ const unsigned int const RPY_R_INITIALIZED = 0x01; const unsigned int const RPY_R_BUSY = 0x02; /* Initial status is 0 */ static unsigned int embeddedR_status = 0; /* R's precious list-like*/ //static SEXP RPY_R_Precious = NULL; static PyObject *Rpy_R_Precious; static inline void embeddedR_setlock(void) { embeddedR_status = embeddedR_status | RPY_R_BUSY; } static inline void embeddedR_freelock(void) { embeddedR_status = embeddedR_status ^ RPY_R_BUSY; } static inline unsigned int rpy_has_status(unsigned int status) { return (embeddedR_status & status) == status; } static void SexpObject_clear(SexpObject *sexpobj) { if (sexpobj->count <= 0) { printf("Warning: clearing an R object with a refcount <= zero.\n"); } if (sexpobj->sexp != R_NilValue) { R_ReleaseObject(sexpobj->sexp); PyMem_Free(sexpobj); } /* sexpobj->count--; */ /* #ifdef RPY_VERBOSE */ /* printf("R:%p -- sexp count is %i...", */ /* sexpobj->sexp, sexpobj->count); */ /* #endif */ /* if (((*sexpobj).count == 0) && (*sexpobj).sexp) { */ /* #ifdef RPY_VERBOSE */ /* printf("freeing SEXP resources..."); */ /* #endif */ /* /\* if (sexpobj->sexp != R_NilValue) { *\/ */ /* /\* #ifdef RPY_DEBUG_PRESERVE *\/ */ /* /\* printf(" PRESERVE -- Sexp_clear: R_ReleaseObject -- %p ", *\/ */ /* /\* sexpobj->sexp); *\/ */ /* /\* preserved_robjects -= 1; *\/ */ /* /\* printf("-- %i\n", preserved_robjects); *\/ */ /* /\* #endif *\/ */ /* /\* int preserve_status = Rpy_ReleaseObject(sexpobj->sexp); *\/ */ /* /\* if (preserve_status == -1) { *\/ */ /* /\* PyErr_Print(); *\/ */ /* /\* PyErr_Clear(); *\/ */ /* /\* } *\/ */ /* /\* } *\/ */ /* /\* self->ob_type->tp_free((PyObject*)self); *\/ */ /* #ifdef RPY_VERBOSE */ /* printf("done.\n"); */ /* #endif */ /* } */ } static void SexpObject_CObject_destroy(PyObject *rpycapsule) { SexpObject *sexpobj_ptr = (SexpObject *)(PyCapsule_GetPointer(rpycapsule, "rpy2.rinterface._C_API_")); SexpObject_clear(sexpobj_ptr); } /* Keep track of R objects preserved by rpy2 Return NULL on failure (a Python exception being set) */ static SexpObject* Rpy_PreserveObject(SEXP object) { /* PyDict can be confused if an error has been raised. We put aside the exception if the case, to restore it at the end. FIXME: this situation can occur because of presumed shortcomings in the overall design of rpy2. */ int reset_error_state = 0; PyObject *ptype, *pvalue, *ptraceback; if (PyErr_Occurred()) { reset_error_state = 1; PyErr_Fetch(&ptype, &pvalue, &ptraceback); } PyObject *key = PyLong_FromVoidPtr((void *)object); PyObject *capsule = PyDict_GetItem(Rpy_R_Precious, key); SexpObject *sexpobj_ptr; /* capsule is a borrowed reference */ if (capsule == NULL) { /* The R object is not yet tracked by rpy2 so we: - create a new SexpObject. - create a capsule for it - put the capsule in the tracking dictionary */ sexpobj_ptr = (SexpObject *)PyMem_Malloc(1 * sizeof(SexpObject)); if (! sexpobj_ptr) { PyErr_NoMemory(); return NULL; } sexpobj_ptr->count = 1; sexpobj_ptr->sexp = object; capsule = PyCapsule_New((void *)(sexpobj_ptr), "rpy2.rinterface._C_API_", SexpObject_CObject_destroy); if (PyDict_SetItem(Rpy_R_Precious, key, capsule) == -1) { Py_DECREF(key); Py_DECREF(capsule); return NULL; } Py_DECREF(capsule); if (object != R_NilValue) { R_PreserveObject(object); } } else { /* Reminder: capsule is a borrowed reference */ sexpobj_ptr = (SexpObject *)(PyCapsule_GetPointer(capsule, "rpy2.rinterface._C_API_")); if (sexpobj_ptr != NULL) { sexpobj_ptr->count++; } } Py_DECREF(key); if (reset_error_state) { if (PyErr_Occurred()) { PyErr_Print(); PyErr_Clear(); } PyErr_Restore(ptype, pvalue, ptraceback); } return sexpobj_ptr; } /* static int Rpy_PreserveObject(SEXP object) { */ /* R_ReleaseObject(RPY_R_Precious); */ /* PROTECT(RPY_R_Precious); */ /* RPY_R_Precious = CONS(object, RPY_R_Precious); */ /* UNPROTECT(1); */ /* R_PreserveObject(RPY_R_Precious); */ /* } */ static int Rpy_ReleaseObject(SEXP object) { /* PyDict can be confused if an error has been raised. We put aside the exception if the case, to restore it at the end. FIXME: this situation can occur because of presumed shortcomings in the overall design of rpy2. */ int reset_error_state = 0; PyObject *ptype, *pvalue, *ptraceback; if (PyErr_Occurred()) { reset_error_state = 1; PyErr_Fetch(&ptype, &pvalue, &ptraceback); } PyObject *key = PyLong_FromVoidPtr((void *)object); PyObject *capsule = PyDict_GetItem(Rpy_R_Precious, key); /* capsule is a borrowed reference */ if (capsule == NULL) { if (reset_error_state) { PyErr_Restore(ptype, pvalue, ptraceback); printf("Error:Trying to release object ID %ld while not preserved\n", PyLong_AsLong(key)); } else { PyErr_Format(PyExc_KeyError, "Trying to release object ID %ld while not preserved\n", PyLong_AsLong(key)); } Py_DECREF(key); return -1; } SexpObject *sexpobj_ptr = (SexpObject *)(PyCapsule_GetPointer(capsule, "rpy2.rinterface._C_API_")); if (sexpobj_ptr == NULL) { if (reset_error_state) { if (PyErr_Occurred()) { PyErr_Print(); } PyErr_Restore(ptype, pvalue, ptraceback); } Py_DECREF(key); return -1; } int res = 0; switch (sexpobj_ptr->count) { case 0: if (object != R_NilValue) { res = -1; PyErr_Format(PyExc_ValueError, "Preserved object ID %ld with a count of zero\n", PyLong_AsLong(key)); Py_DECREF(key); return res; } break; case 1: /* By deleting the capsule from the dictionary, the count of the SexpObject will go down by one, reach zero, and the release of the R object will be performed. */ if (object == R_NilValue) { sexpobj_ptr->count--; } else { res = PyDict_DelItem(Rpy_R_Precious, key); if (res == -1) PyErr_Format(PyExc_ValueError, "Occured while deleting preserved object ID %ld\n", PyLong_AsLong(key)); } break; case 2: /* When the refcount is exactly 2, we could have the following possible * situations: * A- 1 PySexpObject, 1 SexpObject in a capsule * B- 2 SexpObject in a capsule * C- 2 PySexObject * Only A is effectively possible because each PySexpObject has * an associated capsule (rules out C) and each capsule is unique * for a given SEXP (rules out B). * In addition to that, the reference counting in rpy2 is independent * from Python's reference counting. This is means that in the situation A/ * above we can have n pointers to the PySexpObject and m pointers * to the SexpObject. */ // ob_refcnt; /* if (PyLong_AsLong(key) == 0) { */ /* printf("Count 2 for: 0\n"); */ /* break; */ /* } */ sexpobj_ptr->count--; /* if (object == R_NilValue) { */ /* sexpobj_ptr->count--; */ /* } else { */ /* //printf("-->use to delete %ld here\n", PyLong_AsLong(key)); */ /* res = PyDict_DelItem(Rpy_R_Precious, key); */ /* if (res == -1) */ /* PyErr_Format(PyExc_ValueError, */ /* "Occured while deleting preserved object ID %ld\n", */ /* PyLong_AsLong(key)); */ /* } */ break; default: sexpobj_ptr->count--; break; } Py_DECREF(key); if (reset_error_state) { if (PyErr_Occurred()) { PyErr_Print(); } PyErr_Restore(ptype, pvalue, ptraceback); } return res; } /* SEXP parentnode, node; */ /* Py_ssize_t res = -1; */ /* if (isNull(RPY_R_Precious)) { */ /* return res; */ /* } */ /* res++; */ /* if (object == CAR(RPY_R_Precious)) { */ /* RPY_R_Precious = CDR(RPY_R_Precious); */ /* return res; */ /* } */ /* parentnode = RPY_R_Precious; */ /* node = CDR(RPY_R_Precious); */ /* while (!isNull(node)) { */ /* res++; */ /* if (object == CAR(node)) { */ /* SETCDR(parentnode, CDR(node)); */ /* return res; */ /* } */ /* parentnode = node; */ /* node = CDR(node); */ /* } */ PyDoc_STRVAR(Rpy_ProtectedIDs_doc, "Return a tuple with the R IDs for the objects protected\ from R's garbage collection by rpy2, along with the number of rpy2 objects\ protecting them from collection.\n"); /* Return a tuple with IDs of R objects protected by rpy2 and counts */ static PyObject* Rpy_ProtectedIDs(PyObject *self) { PyObject *key, *capsule; Py_ssize_t pos = 0; PyObject *ids = PyTuple_New(PyDict_Size(Rpy_R_Precious)); Py_ssize_t pos_ids = 0; PyObject *id_count; SexpObject *sexpobject_ptr; while (PyDict_Next(Rpy_R_Precious, &pos, &key, &capsule)) { id_count = PyTuple_New(2); Py_INCREF(key); PyTuple_SET_ITEM(id_count, 0, key); sexpobject_ptr = (SexpObject *)(PyCapsule_GetPointer(capsule, "rpy2.rinterface._C_API_")); PyTuple_SET_ITEM(id_count, 1, PyLong_FromLong(sexpobject_ptr->count)); PyTuple_SET_ITEM(ids, pos_ids, id_count); pos_ids++; } return ids; } /* return 0 on success, -1 on failure (and set an exception) */ static inline int Rpy_ReplaceSexp(PySexpObject *pso, SEXP rObj) { SexpObject *sexpobj_ptr = Rpy_PreserveObject(rObj); //printf("target: %zd\n", sexpobj_ptr->count); if (sexpobj_ptr == NULL) { return -1; } //printf("orig: %zd\n", pso->sObj->count); SEXP sexp = pso->sObj->sexp; pso->sObj = sexpobj_ptr; int res = Rpy_ReleaseObject(sexp); return res; } rpy2-2.3.9/rpy/rinterface/sequence.c0000644000175000017500000021364412271276146020521 0ustar laurentlaurent00000000000000/* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * Copyright (C) 2008-2012 Laurent Gautier * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ #include #include #include #include "_rinterface.h" #include "embeddedr.h" #include "sexp.h" #include "sequence.h" /* len(x) or object.__len__() */ static Py_ssize_t VectorSexp_len(PySexpObject* object) { if (rpy_has_status(RPY_R_BUSY)) { PyErr_Format(PyExc_RuntimeError, "Concurrent access to R is not allowed."); return -1; } embeddedR_setlock(); Py_ssize_t len; /* FIXME: sanity checks. */ SEXP sexp = RPY_SEXP(object); if (! sexp) { PyErr_Format(PyExc_ValueError, "NULL SEXP."); return -1; } len = (Py_ssize_t)GET_LENGTH(sexp); embeddedR_freelock(); return len; } /* a[i] or object.__getitem__(i). This only considers the case where 'i' is an integer. R can also get item on names, but that's currently exposed at a higher level in rpy2. */ static PyObject * VectorSexp_item(PySexpObject* object, Py_ssize_t i) { PyObject* res; R_len_t i_R, len_R; if (rpy_has_status(RPY_R_BUSY)) { PyErr_Format(PyExc_RuntimeError, "Concurrent access to R is not allowed."); return NULL; } embeddedR_setlock(); SEXP *sexp = &(RPY_SEXP(object)); if (! sexp) { PyErr_Format(PyExc_ValueError, "NULL SEXP."); embeddedR_freelock(); return NULL; } len_R = GET_LENGTH(*sexp); if (i < 0) { /*FIXME: check that unit tests are covering this properly */ /*FIXME: is this valid for Python < 3 ? */ #if (PY_VERSION_HEX < 0x03010000) i = len_R - i; #else i += len_R; #endif } /* On 64bits platforms, Python is apparently able to use larger integer * than R for indexing. */ if (i >= R_LEN_T_MAX) { PyErr_Format(PyExc_IndexError, "Index value exceeds what R can handle."); embeddedR_freelock(); res = NULL; return res; } if (i < 0) { PyErr_Format(PyExc_IndexError, "Mysterious error: likely an integer overflow."); res = NULL; embeddedR_freelock(); return res; } if ((i >= GET_LENGTH(*sexp))) { PyErr_Format(PyExc_IndexError, "Index out of range."); res = NULL; } else { double vd; int vi; Rcomplex vc; /* Rbyte vr; */ char *vr; const char *vs; SEXP tmp, sexp_item; /* needed by LANGSXP */ i_R = (R_len_t)i; switch (TYPEOF(*sexp)) { case REALSXP: vd = (NUMERIC_POINTER(*sexp))[i_R]; if (R_IsNA(vd)) { res = NAReal_New(1); } else { res = PyFloat_FromDouble(vd); } break; case INTSXP: vi = INTEGER_POINTER(*sexp)[i_R]; if (vi == NA_INTEGER) { res = NAInteger_New(1); } else { #if (PY_VERSION_HEX < 0x03010000) res = PyInt_FromLong((long)vi); #else res = PyLong_FromLong((long)vi); #endif } break; case LGLSXP: vi = LOGICAL_POINTER(*sexp)[i_R]; if (vi == NA_LOGICAL) { res = NALogical_New(1); } else { RPY_PY_FROM_RBOOL(res, vi); } break; case CPLXSXP: vc = COMPLEX_POINTER(*sexp)[i_R]; if (vc.r == NAREAL_IEEE.value && vc.i == NAREAL_IEEE.value) { res = NAComplex_New(1); } else { res = PyComplex_FromDoubles(vc.r, vc.i); } break; case RAWSXP: vr = ((char *)RAW_POINTER(*sexp)) + i_R; #if (PY_VERSION_HEX < 0x03010000) res = PyString_FromStringAndSize(vr, 1); #else res = PyBytes_FromStringAndSize(vr, 1); #endif break; case STRSXP: sexp_item = STRING_ELT(*sexp, i_R); if (sexp_item == NA_STRING) { res = NACharacter_New(1); } else { cetype_t encoding = Rf_getCharCE(sexp_item); switch (encoding) { case CE_UTF8: vs = translateCharUTF8(sexp_item); res = PyUnicode_FromString(vs); break; default: vs = CHAR(sexp_item); #if (PY_VERSION_HEX < 0x03010000) res = PyString_FromString(vs); #else res = PyUnicode_FromString(vs); #endif break; } } break; /* case CHARSXP: */ /* FIXME: implement handling of single char (if possible ?) */ /* vs = (CHAR(*sexp)[i_R]); */ /* res = PyString_FromStringAndSize(vs, 1); */ case VECSXP: case EXPRSXP: sexp_item = VECTOR_ELT(*sexp, i_R); res = (PyObject *)newPySexpObject(sexp_item); break; case LISTSXP: tmp = nthcdr(*sexp, i_R); sexp_item = allocVector(LISTSXP, 1); SETCAR(sexp_item, CAR(tmp)); SET_TAG(sexp_item, TAG(tmp)); res = (PyObject *)newPySexpObject(sexp_item); break; case LANGSXP: sexp_item = CAR(nthcdr(*sexp, i_R)); res = (PyObject *)newPySexpObject(sexp_item); break; default: PyErr_Format(PyExc_ValueError, "Cannot handle type %d", TYPEOF(*sexp)); res = NULL; break; } } embeddedR_freelock(); return res; } /* a[i1:i2] */ static PyObject * VectorSexp_slice(PySexpObject* object, Py_ssize_t ilow, Py_ssize_t ihigh) { R_len_t len_R; if (rpy_has_status(RPY_R_BUSY)) { PyErr_Format(PyExc_RuntimeError, "Concurrent access to R is not allowed."); return NULL; } embeddedR_setlock(); SEXP *sexp = &(RPY_SEXP(object)); SEXP res_sexp, tmp, tmp2; if (! sexp) { PyErr_Format(PyExc_ValueError, "NULL SEXP."); embeddedR_freelock(); return NULL; } len_R = GET_LENGTH(*sexp); if (ilow < 0) ilow = 0; else if (ilow > (Py_ssize_t)len_R) ilow = (Py_ssize_t)len_R; if (ihigh < ilow) ihigh = ilow; else if (ihigh > (Py_ssize_t)len_R) ihigh = (Py_ssize_t)len_R; /* On 64bits, Python is apparently able to use larger integer * than R for indexing. */ if ((ilow >= (Py_ssize_t)R_LEN_T_MAX) | (ihigh >= (Py_ssize_t)R_LEN_T_MAX)) { PyErr_Format(PyExc_IndexError, "Index values in the slice exceed what R can handle."); embeddedR_freelock(); return NULL; } if ((ilow < 0) | (ihigh < 0)) { PyErr_Format(PyExc_IndexError, "Mysterious error: likely an integer overflow."); embeddedR_freelock(); return NULL; } if ((ilow > GET_LENGTH(*sexp)) | (ihigh > GET_LENGTH(*sexp))) { PyErr_Format(PyExc_IndexError, "Index out of range."); return NULL; } else { if ( ilow > ihigh ) { /* Whenever this occurs for regular Python lists, * a sequence of length 0 is returned. Setting ilow:=ilow * causes the same whithout writing "special case" code. */ ihigh = ilow; } R_len_t slice_len = ihigh-ilow; R_len_t slice_i; //const char *vs; //SEXP tmp, sexp_item; /* tmp and sexp_item needed for case LANGSXP */ switch (TYPEOF(*sexp)) { case REALSXP: res_sexp = allocVector(REALSXP, slice_len); memcpy(NUMERIC_POINTER(res_sexp), NUMERIC_POINTER(*sexp) + ilow, (ihigh-ilow) * sizeof(double)); break; case INTSXP: res_sexp = allocVector(INTSXP, slice_len); memcpy(INTEGER_POINTER(res_sexp), INTEGER_POINTER(*sexp) + ilow, (ihigh-ilow) * sizeof(int)); break; case LGLSXP: res_sexp = allocVector(LGLSXP, slice_len); memcpy(LOGICAL_POINTER(res_sexp), LOGICAL_POINTER(*sexp) + ilow, (ihigh-ilow) * sizeof(int)); break; case CPLXSXP: res_sexp = allocVector(CPLXSXP, slice_len); for (slice_i = 0; slice_i < slice_len; slice_i++) { COMPLEX_POINTER(res_sexp)[slice_i] = (COMPLEX_POINTER(*sexp))[slice_i + ilow]; } break; case RAWSXP: res_sexp = allocVector(RAWSXP, slice_len); memcpy(RAW_POINTER(res_sexp), RAW_POINTER(*sexp) + ilow, (ihigh - ilow) * sizeof(char)); break; case STRSXP: res_sexp = allocVector(STRSXP, slice_len); for (slice_i = 0; slice_i < slice_len; slice_i++) { SET_STRING_ELT(res_sexp, slice_i, STRING_ELT(*sexp, slice_i + ilow)); } break; /* case CHARSXP: */ /* FIXME: implement handling of single char (if possible ?) */ /* vs = (CHAR(*sexp)[i_R]); */ /* res = PyString_FromStringAndSize(vs, 1); */ case VECSXP: case EXPRSXP: res_sexp = allocVector(VECSXP, slice_len); for (slice_i = 0; slice_i < slice_len; slice_i++) { SET_VECTOR_ELT(res_sexp, slice_i, VECTOR_ELT(*sexp, slice_i + ilow)); } break; case LANGSXP: PROTECT(res_sexp = allocList(slice_len)); if ( slice_len > 0 ) { SET_TYPEOF(res_sexp, LANGSXP); } for (tmp = *sexp, tmp2 = res_sexp, slice_i = 0; slice_i < slice_len + ilow; tmp = CDR(tmp)) { if (slice_i - ilow > 0) { tmp2 = CDR(tmp2); SETCAR(tmp2, tmp); } slice_i++; } UNPROTECT(1); break; case LISTSXP: default: PyErr_Format(PyExc_ValueError, "Cannot handle type %d", TYPEOF(*sexp)); res_sexp = NULL; break; } } embeddedR_freelock(); if (res_sexp == NULL) { return NULL; } return (PyObject*)newPySexpObject(res_sexp); } /* a[i] = val */ static int VectorSexp_ass_item(PySexpObject* object, Py_ssize_t i, PyObject* val) { R_len_t i_R, len_R; int self_typeof; if (val == NULL) { PyErr_Format(PyExc_TypeError, "Object does not support item deletion."); return -1; } /* Check for 64 bits platforms */ if (i >= R_LEN_T_MAX) { PyErr_Format(PyExc_IndexError, "Index value exceeds what R can handle."); return -1; } SEXP *sexp = &(RPY_SEXP(object)); len_R = GET_LENGTH(*sexp); if (i < 0) { /* FIXME: Is this valid for Python < 3 ?*/ #if (PY_VERSION_HEX < 0x03010000) i = len_R - i; #else i = len_R + i; #endif } if (i >= len_R) { PyErr_Format(PyExc_IndexError, "Index out of range."); return -1; } if (! sexp) { PyErr_Format(PyExc_ValueError, "NULL SEXP."); return -1; } int is_PySexpObject = PyObject_TypeCheck(val, &Sexp_Type); if (! is_PySexpObject) { PyErr_Format(PyExc_ValueError, "Any new value must be of " "type 'Sexp_Type'."); return -1; } SEXP *sexp_val = &(RPY_SEXP((PySexpObject *)val)); if (! sexp_val) { PyErr_Format(PyExc_ValueError, "NULL SEXP."); return -1; } self_typeof = TYPEOF(*sexp); if ( (self_typeof != VECSXP) && self_typeof != LANGSXP ) { if (TYPEOF(*sexp_val) != self_typeof) { PyErr_Format(PyExc_ValueError, "The new value cannot be of 'typeof' other than %i ('%i' given)", self_typeof, TYPEOF(*sexp_val)); return -1; } if (LENGTH(*sexp_val) != 1) { PyErr_Format(PyExc_ValueError, "The new value must be of length 1."); return -1; } } SEXP sexp_copy; i_R = (R_len_t)i; switch (self_typeof) { case REALSXP: (NUMERIC_POINTER(*sexp))[i_R] = (NUMERIC_POINTER(*sexp_val))[0]; break; case INTSXP: (INTEGER_POINTER(*sexp))[i_R] = (INTEGER_POINTER(*sexp_val))[0]; break; case LGLSXP: (LOGICAL_POINTER(*sexp))[i_R] = (LOGICAL_POINTER(*sexp_val))[0]; break; case CPLXSXP: (COMPLEX_POINTER(*sexp))[i_R] = (COMPLEX_POINTER(*sexp_val))[0]; break; case RAWSXP: (RAW_POINTER(*sexp))[i_R] = (RAW_POINTER(*sexp_val))[0]; break; case STRSXP: SET_STRING_ELT(*sexp, i_R, STRING_ELT(*sexp_val, 0)); break; case VECSXP: PROTECT(sexp_copy = Rf_duplicate(*sexp_val)); SET_VECTOR_ELT(*sexp, i_R, sexp_copy); UNPROTECT(1); break; case LANGSXP: SETCAR(nthcdr(*sexp, i_R), *sexp_val); break; default: PyErr_Format(PyExc_ValueError, "Cannot handle typeof '%d'", self_typeof); return -1; break; } return 0; } /* a[i:j] = val */ static int VectorSexp_ass_slice(PySexpObject* object, Py_ssize_t ilow, Py_ssize_t ihigh, PyObject *val) { R_len_t len_R; if (rpy_has_status(RPY_R_BUSY)) { PyErr_Format(PyExc_RuntimeError, "Concurrent access to R is not allowed."); return -1; } embeddedR_setlock(); if (! PyObject_TypeCheck(val, &Sexp_Type)) { PyErr_Format(PyExc_ValueError, "Any new value must be of " "type 'Sexp_Type'."); embeddedR_freelock(); return -1; } SEXP *sexp = &(RPY_SEXP(object)); len_R = GET_LENGTH(*sexp); /* FIXME: Is this valid for Python < 3 ? */ #if (PY_VERSION_HEX < 0x03010000) if (ilow < 0) { ilow = (R_len_t)(len_R - ilow) + 1; } if (ihigh < 0) { ihigh = (R_len_t)(len_R - ihigh) + 1; } #endif if (! sexp) { PyErr_Format(PyExc_ValueError, "NULL SEXP."); embeddedR_freelock(); return -1; } /* On 64bits, Python is apparently able to use larger integer * than R for indexing. */ if ((ilow >= R_LEN_T_MAX) | (ihigh >= R_LEN_T_MAX)) { PyErr_Format(PyExc_IndexError, "Index values in the slice exceed what R can handle."); embeddedR_freelock(); return -1; } if ((ilow < 0) | (ihigh < 0)) { PyErr_Format(PyExc_IndexError, "Mysterious error: likely an integer overflow."); embeddedR_freelock(); return -1; } if ((ilow > GET_LENGTH(*sexp)) | (ihigh > GET_LENGTH(*sexp))) { PyErr_Format(PyExc_IndexError, "Index out of range."); return -1; } else { if ( ilow > ihigh ) { /* Whenever this occurs for regular Python lists, * a sequence of length 0 is returned. Setting ilow:=ilow * causes the same whithout writing "special case" code. */ ihigh = ilow; } R_len_t slice_len = ihigh-ilow; R_len_t slice_i; SEXP sexp_val = RPY_SEXP((PySexpObject *)val); if (! sexp_val) { PyErr_Format(PyExc_ValueError, "NULL SEXP."); embeddedR_freelock(); return -1; } if (slice_len != GET_LENGTH(sexp_val)) { PyErr_Format(PyExc_ValueError, "The length of the replacement value differs from the length of the slice."); embeddedR_freelock(); return -1; } switch (TYPEOF(*sexp)) { case REALSXP: memcpy(NUMERIC_POINTER(*sexp) + ilow, NUMERIC_POINTER(sexp_val), (ihigh-ilow) * sizeof(double)); break; case INTSXP: memcpy(INTEGER_POINTER(*sexp) + ilow, INTEGER_POINTER(sexp_val), (ihigh-ilow) * sizeof(int)); break; case LGLSXP: memcpy(LOGICAL_POINTER(*sexp) + ilow, LOGICAL_POINTER(sexp_val), (ihigh-ilow) * sizeof(int)); break; case CPLXSXP: for (slice_i = 0; slice_i < slice_len; slice_i++) { (COMPLEX_POINTER(*sexp))[slice_i + ilow] = COMPLEX_POINTER(sexp_val)[slice_i]; } break; case RAWSXP: memcpy(RAW_POINTER(*sexp) + ilow, RAW_POINTER(sexp_val), (ihigh-ilow) * sizeof(char)); break; case STRSXP: for (slice_i = 0; slice_i < slice_len; slice_i++) { SET_STRING_ELT(*sexp, slice_i + ilow, STRING_ELT(sexp_val, slice_i)); } break; case VECSXP: case EXPRSXP: for (slice_i = 0; slice_i < slice_len; slice_i++) { SET_VECTOR_ELT(*sexp, slice_i + ilow, VECTOR_ELT(sexp_val, slice_i)); } break; case CHARSXP: case LISTSXP: case LANGSXP: default: PyErr_Format(PyExc_ValueError, "Cannot handle type %d", TYPEOF(*sexp)); embeddedR_freelock(); return -1; break; } } embeddedR_freelock(); return 0; } static PySequenceMethods VectorSexp_sequenceMethods = { (lenfunc)VectorSexp_len, /* sq_length */ 0, /* sq_concat */ 0, /* sq_repeat */ (ssizeargfunc)VectorSexp_item, /* sq_item */ #if (PY_VERSION_HEX < 0x03010000) (ssizessizeargfunc)VectorSexp_slice, /* sq_slice */ #else 0, /* sq_slice */ #endif (ssizeobjargproc)VectorSexp_ass_item, /* sq_ass_item */ #if (PY_VERSION_HEX < 0x03010000) (ssizessizeobjargproc)VectorSexp_ass_slice, /* sq_ass_slice */ #else 0, #endif 0, /* sq_contains */ 0, /* sq_inplace_concat */ 0 /* sq_inplace_repeat */ }; #if (PY_VERSION_HEX < 0x03010000) #else /* generic a[i] for Python3 */ static PyObject* VectorSexp_subscript(PySexpObject *object, PyObject* item) { Py_ssize_t i; if (PyIndex_Check(item)) { i = PyNumber_AsSsize_t(item, PyExc_IndexError); if (i == -1 && PyErr_Occurred()) { return NULL; } /* currently checked in VectorSexp_item */ /* (but have it here nevertheless) */ if (i < 0) i += VectorSexp_len(object); return VectorSexp_item(object, i); } else if (PySlice_Check(item)) { Py_ssize_t start, stop, step, slicelength; Py_ssize_t vec_len = VectorSexp_len(object); if (vec_len == -1) /* propagate the error */ return NULL; #if (PY_VERSION_HEX >= 0x03020000) if (PySlice_GetIndicesEx((PyObject*)item, vec_len, &start, &stop, &step, &slicelength) < 0) { return NULL; } #else if (PySlice_GetIndicesEx((PySliceObject*)item, vec_len, &start, &stop, &step, &slicelength) < 0) { return NULL; } #endif if (slicelength <= 0) { PyErr_Format(PyExc_IndexError, "The slice's length can't be < 0."); return NULL; /* return VectorSexp_New(0); */ } else { if (step == 1) { PyObject *result = VectorSexp_slice(object, start, stop); return result; } else { PyErr_Format(PyExc_IndexError, "Only slicing with step==1 is supported for the moment."); return NULL; } } } else { PyErr_Format(PyExc_TypeError, "SexpVector indices must be integers, not %.200s", Py_TYPE(item)->tp_name); return NULL; } } /* genericc a[i] = foo for Python 3 */ static int VectorSexp_ass_subscript(PySexpObject* self, PyObject* item, PyObject* value) { if (PyIndex_Check(item)) { Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError); if (i == -1 && PyErr_Occurred()) return -1; if (i < 0) i += VectorSexp_len(self); return VectorSexp_ass_item(self, i, value); } else if (PySlice_Check(item)) { Py_ssize_t start, stop, step, slicelength; Py_ssize_t vec_len = VectorSexp_len(self); if (vec_len == -1) /* propagate the error */ return -1; #if (PY_VERSION_HEX >= 0x03020000) if (PySlice_GetIndicesEx((PyObject*)item, vec_len, &start, &stop, &step, &slicelength) < 0) { return -1; } #else if (PySlice_GetIndicesEx((PySliceObject*)item, vec_len, &start, &stop, &step, &slicelength) < 0) { return -1; } #endif if (step == 1) { return VectorSexp_ass_slice(self, start, stop, value); } else { PyErr_Format(PyExc_IndexError, "Only slicing with step==1 is supported for the moment."); return -1; } } else { PyErr_Format(PyExc_TypeError, "VectorSexp indices must be integers, not %.200s", item->ob_type->tp_name); return -1; } } static PyMappingMethods VectorSexp_as_mapping = { (lenfunc)VectorSexp_len, (binaryfunc)VectorSexp_subscript, (objobjargproc)VectorSexp_ass_subscript }; #endif static PyObject * VectorSexp_index(PySexpObject *self, PyObject *args) { Py_ssize_t i, start, stop; PyObject *v; PyObject *item; SEXP sexp = RPY_SEXP(self); if (! sexp) { PyErr_Format(PyExc_ValueError, "NULL SEXP."); return NULL; } start = 0; stop = (Py_ssize_t)(GET_LENGTH(sexp)); if (!PyArg_ParseTuple(args, "O|O&O&:index", &v, _PyEval_SliceIndex, &start, _PyEval_SliceIndex, &stop)) return NULL; if (start < 0) { start += (Py_ssize_t)(GET_LENGTH(sexp)); if (start < 0) start = 0; } if (stop < 0) { stop += (Py_ssize_t)(GET_LENGTH(sexp)); if (stop < 0) stop = 0; } for (i = start; i < stop && i < (Py_ssize_t)(GET_LENGTH(sexp)); i++) { item = VectorSexp_item(self, i); int cmp = PyObject_RichCompareBool(item, v, Py_EQ); Py_DECREF(item); if (cmp > 0) #if (PY_VERSION_HEX < 0x03010000) return PyInt_FromSsize_t(i); #else return PyLong_FromSsize_t(i); #endif else if (cmp < 0) return NULL; } PyErr_SetString(PyExc_ValueError, "list.index(x): x not in list"); return NULL; } PyDoc_STRVAR(VectorSexp_index_doc, "V.index(value, [start, [stop]]) -> integer -- return first index of value." "Raises ValueError if the value is not present."); static PyMethodDef VectorSexp_methods[] = { {"index", (PyCFunction)VectorSexp_index, METH_VARARGS, VectorSexp_index_doc}, {NULL, NULL} }; static PyGetSetDef VectorSexp_getsets[] = { {"__array_struct__", (getter)array_struct_get, (setter)0, "Array protocol: struct"}, {NULL, NULL, NULL, NULL} /* sentinel */ }; PyDoc_STRVAR(VectorSexp_Type_doc, "R object that is a vector." " R vectors start their indexing at one," " while Python lists or arrays start indexing" " at zero.\n" "In the hope to avoid confusion, the indexing" " in Python (e.g., :meth:`__getitem__` / :meth:`__setitem__`)" " starts at zero."); static int VectorSexp_init(PyObject *self, PyObject *args, PyObject *kwds); static PyTypeObject VectorSexp_Type = { /* The ob_type field must be initialized in the module init function * to be portable to Windows without using C++. */ #if (PY_VERSION_HEX < 0x03010000) PyObject_HEAD_INIT(NULL) 0, /*ob_size*/ #else PyVarObject_HEAD_INIT(NULL, 0) #endif "rpy2.rinterface.SexpVector", /*tp_name*/ sizeof(PySexpObject), /*tp_basicsize*/ 0, /*tp_itemsize*/ /* methods */ 0, /*tp_dealloc*/ 0, /*tp_print*/ 0, /*tp_getattr*/ 0, /*tp_setattr*/ 0, /*tp_compare*/ 0, /*tp_repr*/ 0, /*tp_as_number*/ &VectorSexp_sequenceMethods, /*tp_as_sequence*/ #if (PY_VERSION_HEX < 0x03010000) 0, /*tp_as_mapping*/ #else &VectorSexp_as_mapping, #endif 0, /*tp_hash*/ 0, /*tp_call*/ 0, /*tp_str*/ 0, /*tp_getattro*/ 0, /*tp_setattro*/ #if PY_VERSION_HEX >= 0x02060000 &VectorSexp_as_buffer, /*tp_as_buffer*/ #else 0, /*tp_as_buffer*/ #endif #if PY_VERSION_HEX >= 0x02060000 & PY_VERSION_HEX < 0x03010000 Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_HAVE_NEWBUFFER, /*tp_flags*/ #else Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /*tp_flags*/ #endif VectorSexp_Type_doc, /*tp_doc*/ 0, /*tp_traverse*/ 0, /*tp_clear*/ 0, /*tp_richcompare*/ 0, /*tp_weaklistoffset*/ 0, /*tp_iter*/ 0, /*tp_iternext*/ VectorSexp_methods, /*tp_methods*/ 0, /*tp_members*/ VectorSexp_getsets, /*tp_getset*/ &Sexp_Type, /*tp_base*/ 0, /*tp_dict*/ 0, /*tp_descr_get*/ 0, /*tp_descr_set*/ 0, /*tp_dictoffset*/ (initproc)VectorSexp_init, /*tp_init*/ 0, /*tp_alloc*/ 0, /*tp_new*/ 0, /*tp_free*/ 0 /*tp_is_gc*/ }; static int VectorSexp_init(PyObject *self, PyObject *args, PyObject *kwds) { #ifdef RPY_VERBOSE printf("%p: VectorSexp initializing...\n", self); #endif if (! (rpy_has_status(RPY_R_INITIALIZED))) { PyErr_Format(PyExc_RuntimeError, "R must be initialized before any instance can be created."); return -1; } PyObject *object; int sexptype = -1; static char *kwlist[] = {"sexpvector", "sexptype", NULL}; /* FIXME: handle the copy argument */ if (! PyArg_ParseTupleAndKeywords(args, kwds, "O|i", kwlist, &object, &sexptype)) { return -1; } if (rpy_has_status(RPY_R_BUSY)) { PyErr_Format(PyExc_RuntimeError, "Concurrent access to R is not allowed."); return -1; } embeddedR_setlock(); if (PyObject_IsInstance(object, (PyObject*)&VectorSexp_Type)) { /* call parent's constructor */ if (Sexp_init(self, args, NULL) == -1) { /* PyErr_Format(PyExc_RuntimeError, "Error initializing instance."); */ embeddedR_freelock(); return -1; } } else if (PySequence_Check(object)) { if ((sexptype < 0) || (sexptype > RPY_MAX_VALIDSEXTYPE) || (! validSexpType[sexptype])) { PyErr_Format(PyExc_ValueError, "Invalid SEXP type '%i'.", sexptype); embeddedR_freelock(); return -1; } /* FIXME: implemement automagic type ? *(RPy has something)... or leave it to extensions ? */ SEXP sexp = newSEXP(object, sexptype); PROTECT(sexp); /* sexp is not preserved*/ if (sexp == NULL) { /* newSEXP returning NULL will also have raised an exception * (not-so-clear design :/ ) */ UNPROTECT(1); embeddedR_freelock(); return -1; } if (Rpy_ReplaceSexp((PySexpObject *)self, sexp) == -1) { embeddedR_freelock(); UNPROTECT(1); return -1; } UNPROTECT(1); #ifdef RPY_DEBUG_OBJECTINIT printf(" SEXP vector is %p.\n", RPY_SEXP((PySexpObject *)self)); #endif /* SET_NAMED(RPY_SEXP((PySexpObject *)self), 2); */ } else { PyErr_Format(PyExc_ValueError, "Invalid sexpvector."); embeddedR_freelock(); return -1; } #ifdef RPY_VERBOSE printf("done (VectorSexp_init).\n"); #endif embeddedR_freelock(); return 0; } /* transition to replace the current VectorSexp_init() and make VectorSexp_init() an abstract class */ static int VectorSexp_init_private(PyObject *self, PyObject *args, PyObject *kwds, RPy_seqobjtosexpproc seq_to_R, RPy_iterobjtosexpproc iter_to_R, int sexptype) { if (! (rpy_has_status(RPY_R_INITIALIZED))) { PyErr_Format(PyExc_RuntimeError, "R must be initialized before any instance can be created."); return -1; } PyObject *object; PySexpObject *rpyobject; static char *kwlist[] = {"sexpvector", NULL}; if (! PyArg_ParseTupleAndKeywords(args, kwds, "O", kwlist, &object)) { return -1; } if (rpy_has_status(RPY_R_BUSY)) { PyErr_Format(PyExc_RuntimeError, "Concurrent access to R is not allowed."); return -1; } embeddedR_setlock(); SEXP sexp = R_NilValue; if (PyObject_IsInstance(object, (PyObject*)&VectorSexp_Type)) { #ifdef RPY_VERBOSE printf(" object already a VectorSexp_Type\n"); #endif rpyobject = (PySexpObject *)object; if (sexptype != TYPEOF(RPY_SEXP(rpyobject))) { PyErr_Format(PyExc_ValueError, "Invalid SEXP type '%i' (should be %i).", TYPEOF(RPY_SEXP(rpyobject)), sexptype); embeddedR_freelock(); return -1; } /* call parent's constructor */ if (Sexp_init(self, args, NULL) == -1) { /* PyErr_Format(PyExc_RuntimeError, "Error initializing instance."); */ embeddedR_freelock(); return -1; } } else { /* The parameter is not already a PySexpObject. Create the necessary PySexpObjects. */ int is_sequence = PySequence_Check(object); if ( !is_sequence ) { Py_ssize_t length = PyObject_Length(object); if (length == -1) { PyErr_Format(PyExc_ValueError, "The object does not have a length."); embeddedR_freelock(); return -1; } else if (iter_to_R == NULL) { /*FIXME: temporary, while the different implementations are written */ } else if (iter_to_R(object, length, &sexp) == -1) { /* RPy_SeqTo*SXP returns already raises an exception in case of problem */ embeddedR_freelock(); return -1; } else { PyErr_Format(PyExc_ValueError, "Unexpected problem when building R vector from non-sequence."); embeddedR_freelock(); return -1; } } else { #ifdef RPY_VERBOSE printf(" object a sequence\n"); #endif if (seq_to_R(object, &sexp) == -1) { /* RPy_SeqTo*SXP returns already raises an exception in case of problem */ embeddedR_freelock(); return -1; } //R_PreserveObject(sexp); #ifdef RPY_DEBUG_PRESERVE preserved_robjects += 1; printf(" PRESERVE -- R_PreserveObject -- %p -- %i\n", sexp, preserved_robjects); #endif if (Rpy_ReplaceSexp((PySexpObject *)self, sexp) == -1) { embeddedR_freelock(); return -1; } #ifdef RPY_DEBUG_OBJECTINIT printf(" SEXP vector is %p.\n", RPY_SEXP((PySexpObject *)self)); #endif /* SET_NAMED(RPY_SEXP((PySexpObject *)self), 2); */ } } embeddedR_freelock(); return 0; } PyDoc_STRVAR(IntVectorSexp_Type_doc, "R vector of integers (note: integers in R are C-int, not C-long)"); static int IntVectorSexp_init(PyObject *self, PyObject *args, PyObject *kwds); static PyTypeObject IntVectorSexp_Type = { /* The ob_type field must be initialized in the module init function * to be portable to Windows without using C++. */ #if (PY_VERSION_HEX < 0x03010000) PyObject_HEAD_INIT(NULL) 0, /*ob_size*/ #else PyVarObject_HEAD_INIT(NULL, 0) #endif "rpy2.rinterface.IntSexpVector", /*tp_name*/ sizeof(PySexpObject), /*tp_basicsize*/ 0, /*tp_itemsize*/ /* methods */ 0, /*tp_dealloc*/ 0, /*tp_print*/ 0, /*tp_getattr*/ 0, /*tp_setattr*/ 0, /*tp_compare*/ 0, /*tp_repr*/ 0, /*tp_as_number*/ 0, /*tp_as_sequence*/ #if (PY_VERSION_HEX < 0x03010000) 0, /*tp_as_mapping*/ #else 0, #endif 0, /*tp_hash*/ 0, /*tp_call*/ 0, /*tp_str*/ 0, /*tp_getattro*/ 0, /*tp_setattro*/ #if PY_VERSION_HEX >= 0x02060000 & PY_VERSION_HEX < 0x03010000 0, /*tp_as_buffer*/ Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_HAVE_NEWBUFFER, /*tp_flags*/ #else 0, /*tp_as_buffer*/ 0, /*tp_flags*/ #endif IntVectorSexp_Type_doc, /*tp_doc*/ 0, /*tp_traverse*/ 0, /*tp_clear*/ 0, /*tp_richcompare*/ 0, /*tp_weaklistoffset*/ 0, /*tp_iter*/ 0, /*tp_iternext*/ 0, /*tp_methods*/ 0, /*tp_members*/ 0, /*tp_getset*/ &VectorSexp_Type, /*tp_base*/ 0, /*tp_dict*/ 0, /*tp_descr_get*/ 0, /*tp_descr_set*/ 0, /*tp_dictoffset*/ (initproc)IntVectorSexp_init, /*tp_init*/ 0, /*tp_alloc*/ 0, /*tp_new*/ 0, /*tp_free*/ 0 /*tp_is_gc*/ }; /* Take an arbitray Python sequence and a target pointer SEXP and build an R vector of integers. The function returns 0 on success, -1 on failure. In the case of a failure, it will also create an exception with an informative message that can be propagated up. */ static int RPy_SeqToINTSXP(PyObject *object, SEXP *sexpp) { Py_ssize_t ii; PyObject *seq_object, *item, *item_tmp; SEXP new_sexp; seq_object = PySequence_Fast(object, "Cannot create R object from non-sequence object."); if (! seq_object) { return -1; } const Py_ssize_t length = PySequence_Fast_GET_SIZE(seq_object); if (length > R_LEN_T_MAX) { PyErr_Format(PyExc_ValueError, "The Python sequence is longer than the longuest possible vector in R"); Py_XDECREF(seq_object); return -1; } PROTECT(new_sexp = NEW_INTEGER(length)); int *integer_ptr = INTEGER(new_sexp); /*FIXME: Optimization possible for array.array by using memcpy(). * With Python >= 2.7, this could be extended to memoryviews. */ for (ii = 0; ii < length; ++ii) { item = PySequence_Fast_GET_ITEM(seq_object, ii); #if (PY_VERSION_HEX < 0x03010000) item_tmp = PyNumber_Int(item); #else item_tmp = PyNumber_Long(item); #endif if (item == NAInteger_New(0)) { integer_ptr[ii] = NA_INTEGER; } else if (item_tmp) { #if (PY_VERSION_HEX < 0x03010000) long l = PyInt_AS_LONG(item_tmp); #else long l = PyLong_AS_LONG(item_tmp); #endif if ((l > (long)INT_MAX) || (l < (long)INT_MIN)) { UNPROTECT(1); PyErr_Format(PyExc_OverflowError, "Integer overflow with element %zd.", ii); Py_XDECREF(seq_object); return -1; } else { integer_ptr[ii] = (int)l; } } else { UNPROTECT(1); PyErr_Format(PyExc_ValueError, "Error while trying to convert element %zd to an integer.", ii); Py_XDECREF(seq_object); return -1; } Py_XDECREF(item_tmp); } UNPROTECT(1); *sexpp = new_sexp; Py_XDECREF(seq_object); return 0; } /* Take an arbitray Python iterable, a length, and a target pointer SEXP and build an R vector of integers. The function returns 0 on success, -1 on failure. In the case of a failure, it will also create an exception with an informative message that can be propagated up. */ static int RPy_IterToINTSXP(PyObject *object, const Py_ssize_t length, SEXP *sexpp) { PyObject *item, *item_tmp; SEXP new_sexp; if (length > R_LEN_T_MAX) { PyErr_Format(PyExc_ValueError, "The length exceeds what the longuest possible R vector can be."); } PROTECT(new_sexp = NEW_INTEGER(length)); int *integer_ptr = INTEGER(new_sexp); Py_ssize_t ii = 0; while (ii < length) { item = PyIter_Next(object); if (item == NULL) { UNPROTECT(1); PyErr_Format(PyExc_ValueError, "Error while trying to retrive element %zd in the iterator.", ii); return -1; } #if (PY_VERSION_HEX < 0x03010000) item_tmp = PyNumber_Int(item); #else item_tmp = PyNumber_Long(item); #endif if (item == NAInteger_New(0)) { integer_ptr[ii] = NA_INTEGER; } else if (item_tmp) { #if (PY_VERSION_HEX < 0x03010000) long l = PyInt_AS_LONG(item_tmp); #else long l = PyLong_AS_LONG(item_tmp); #endif if ((l > (long)INT_MAX) || (l < (long)INT_MIN)) { UNPROTECT(1); PyErr_Format(PyExc_OverflowError, "Integer overflow with element %zd.", ii); return -1; } else { integer_ptr[ii] = (int)l; } } else { UNPROTECT(1); PyErr_Format(PyExc_ValueError, "Error while trying to convert element %zd to an integer.", ii); return -1; } Py_XDECREF(item_tmp); ii++; } UNPROTECT(1); *sexpp = new_sexp; return 0; } /* Make an R INTSEXP from a Python int or long scalar */ static SEXP IntVectorSexp_AsSexp(PyObject *pyfloat) { int status; SEXP sexp; PyObject *seq_tmp = PyTuple_New(1); PyTuple_SetItem(seq_tmp, 0, pyfloat); status = RPy_SeqToINTSXP(seq_tmp, &sexp); if (status == -1) { return NULL; } Py_DECREF(seq_tmp); return sexp; } static int IntVectorSexp_init(PyObject *self, PyObject *args, PyObject *kwds) { #ifdef RPY_VERBOSE printf("%p: IntVectorSexp initializing...\n", self); #endif int res; res = VectorSexp_init_private(self, args, kwds, (RPy_seqobjtosexpproc)RPy_SeqToINTSXP, (RPy_iterobjtosexpproc)RPy_IterToINTSXP, INTSXP); #ifdef RPY_VERBOSE printf("done (IntVectorSexp_init).\n"); #endif return res; } PyDoc_STRVAR(FloatVectorSexp_Type_doc, "R vector of Python floats (note: double in C)"); static int FloatVectorSexp_init(PyObject *self, PyObject *args, PyObject *kwds); static PyTypeObject FloatVectorSexp_Type = { /* The ob_type field must be initialized in the module init function * to be portable to Windows without using C++. */ #if (PY_VERSION_HEX < 0x03010000) PyObject_HEAD_INIT(NULL) 0, /*ob_size*/ #else PyVarObject_HEAD_INIT(NULL, 0) #endif "rpy2.rinterface.FloatSexpVector", /*tp_name*/ sizeof(PySexpObject), /*tp_basicsize*/ 0, /*tp_itemsize*/ /* methods */ 0, /*tp_dealloc*/ 0, /*tp_print*/ 0, /*tp_getattr*/ 0, /*tp_setattr*/ 0, /*tp_compare*/ 0, /*tp_repr*/ 0, /*tp_as_number*/ 0, /*tp_as_sequence*/ #if (PY_VERSION_HEX < 0x03010000) 0, /*tp_as_mapping*/ #else 0, #endif 0, /*tp_hash*/ 0, /*tp_call*/ 0, /*tp_str*/ 0, /*tp_getattro*/ 0, /*tp_setattro*/ #if PY_VERSION_HEX >= 0x02060000 & PY_VERSION_HEX < 0x03010000 0, /*tp_as_buffer*/ Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_HAVE_NEWBUFFER, /*tp_flags*/ #else 0, /*tp_as_buffer*/ 0, /*tp_flags*/ #endif FloatVectorSexp_Type_doc, /*tp_doc*/ 0, /*tp_traverse*/ 0, /*tp_clear*/ 0, /*tp_richcompare*/ 0, /*tp_weaklistoffset*/ 0, /*tp_iter*/ 0, /*tp_iternext*/ 0, /*tp_methods*/ 0, /*tp_members*/ 0, /*tp_getset*/ &VectorSexp_Type, /*tp_base*/ 0, /*tp_dict*/ 0, /*tp_descr_get*/ 0, /*tp_descr_set*/ 0, /*tp_dictoffset*/ (initproc)FloatVectorSexp_init, /*tp_init*/ 0, /*tp_alloc*/ 0, /*tp_new*/ 0, /*tp_free*/ 0 /*tp_is_gc*/ }; /* Take an arbitray Python sequence and a target pointer SEXP and build an R vector of "numeric" values (double* in C, float in Python). The function returns 0 on success, -1 on failure. In the case of a failure, it will also create an exception with an informative message that can be propagated up. */ static int RPy_SeqToREALSXP(PyObject *object, SEXP *sexpp) { Py_ssize_t ii; PyObject *seq_object, *item, *item_tmp; SEXP new_sexp; seq_object = PySequence_Fast(object, "Cannot create R object from non-sequence object."); if (! seq_object) { return -1; } const Py_ssize_t length = PySequence_Fast_GET_SIZE(seq_object); if (length > R_LEN_T_MAX) { PyErr_Format(PyExc_ValueError, "The Python sequence is longer than the longuest possible vector in R"); Py_XDECREF(seq_object); return -1; } PROTECT(new_sexp = NEW_NUMERIC(length)); double *double_ptr = NUMERIC_POINTER(new_sexp); /*FIXME: Optimization possible for array.array by using memcpy(). * With Python >= 2.7, this could be extended to memoryviews. */ for (ii = 0; ii < length; ++ii) { item = PySequence_Fast_GET_ITEM(seq_object, ii); item_tmp = PyNumber_Float(item); if (item == NAReal_New(0)) { double_ptr[ii] = NA_REAL; } else if (item_tmp) { double value = PyFloat_AS_DOUBLE(item_tmp); double_ptr[ii] = value; } else { UNPROTECT(1); PyErr_Format(PyExc_ValueError, "Error while trying to convert element %zd to a double.", ii); Py_XDECREF(seq_object); return -1; } Py_XDECREF(item_tmp); } UNPROTECT(1); *sexpp = new_sexp; Py_XDECREF(seq_object); return 0; } /* Take an arbitray Python iterator, length, and a target pointer SEXP and build an R vector of "numeric" values (double* in C, float in Python). The function returns 0 on success, -1 on failure. In the case of a failure, it will also create an exception with an informative message that can be propagated up. */ static int RPy_IterToREALSXP(PyObject *object, Py_ssize_t length, SEXP *sexpp) { PyObject *item, *item_tmp; SEXP new_sexp; if (length > R_LEN_T_MAX) { PyErr_Format(PyExc_ValueError, "The Python sequence is longer than the longuest possible vector in R"); } PROTECT(new_sexp = NEW_NUMERIC(length)); double *double_ptr = NUMERIC_POINTER(new_sexp); Py_ssize_t ii = 0; while (ii < length) { item = PyIter_Next(object); if (item == NULL) { UNPROTECT(1); PyErr_Format(PyExc_ValueError, "Error while trying to retrive element %zd in the iterator.", ii); return -1; } item_tmp = PyNumber_Float(item); if (item == NAReal_New(0)) { double_ptr[ii] = NA_REAL; } else if (item_tmp) { double value = PyFloat_AS_DOUBLE(item_tmp); double_ptr[ii] = value; } else { UNPROTECT(1); PyErr_Format(PyExc_ValueError, "Error while trying to convert element %zd to a double.", ii); return -1; } Py_XDECREF(item_tmp); ii++; } UNPROTECT(1); *sexpp = new_sexp; return 0; } /* Make an R NUMERIC SEXP from a Python float scalar */ static SEXP FloatVectorSexp_AsSexp(PyObject *pyfloat) { int status; SEXP sexp; PyObject *seq_tmp = PyTuple_New(1); PyTuple_SetItem(seq_tmp, 0, pyfloat); status = RPy_SeqToREALSXP(seq_tmp, &sexp); if (status == -1) { return NULL; } Py_DECREF(seq_tmp); return sexp; } static int FloatVectorSexp_init(PyObject *self, PyObject *args, PyObject *kwds) { #ifdef RPY_VERBOSE printf("%p: FloatVectorSexp initializing...\n", self); #endif int res = VectorSexp_init_private(self, args, kwds, (RPy_seqobjtosexpproc)RPy_SeqToREALSXP, (RPy_iterobjtosexpproc)RPy_IterToREALSXP, REALSXP); #ifdef RPY_VERBOSE printf("done (FloatVectorSexp_init).\n"); #endif return res; } PyDoc_STRVAR(StrVectorSexp_Type_doc, "R vector of Python strings"); static int StrVectorSexp_init(PyObject *self, PyObject *args, PyObject *kwds); static PyTypeObject StrVectorSexp_Type = { /* The ob_type field must be initialized in the module init function * to be portable to Windows without using C++. */ #if (PY_VERSION_HEX < 0x03010000) PyObject_HEAD_INIT(NULL) 0, /*ob_size*/ #else PyVarObject_HEAD_INIT(NULL, 0) #endif "rpy2.rinterface.StrSexpVector", /*tp_name*/ sizeof(PySexpObject), /*tp_basicsize*/ 0, /*tp_itemsize*/ /* methods */ 0, /*tp_dealloc*/ 0, /*tp_print*/ 0, /*tp_getattr*/ 0, /*tp_setattr*/ 0, /*tp_compare*/ 0, /*tp_repr*/ 0, /*tp_as_number*/ 0, /*tp_as_sequence*/ #if (PY_VERSION_HEX < 0x03010000) 0, /*tp_as_mapping*/ #else 0, #endif 0, /*tp_hash*/ 0, /*tp_call*/ 0, /*tp_str*/ 0, /*tp_getattro*/ 0, /*tp_setattro*/ #if PY_VERSION_HEX >= 0x02060000 & PY_VERSION_HEX < 0x03010000 0, /*tp_as_buffer*/ Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_HAVE_NEWBUFFER, /*tp_flags*/ #else 0, /*tp_as_buffer*/ 0, /*tp_flags*/ #endif StrVectorSexp_Type_doc, /*tp_doc*/ 0, /*tp_traverse*/ 0, /*tp_clear*/ 0, /*tp_richcompare*/ 0, /*tp_weaklistoffset*/ 0, /*tp_iter*/ 0, /*tp_iternext*/ 0, /*tp_methods*/ 0, /*tp_members*/ 0, /*tp_getset*/ &VectorSexp_Type, /*tp_base*/ 0, /*tp_dict*/ 0, /*tp_descr_get*/ 0, /*tp_descr_set*/ 0, /*tp_dictoffset*/ (initproc)StrVectorSexp_init, /*tp_init*/ 0, /*tp_alloc*/ 0, /*tp_new*/ 0, /*tp_free*/ 0 /*tp_is_gc*/ }; /* Take an arbitray Python sequence and a target pointer SEXP and build an R vector of strings (character in R, char* in C). The function returns 0 on success, -1 on failure. In the case of a failure, it will also create an exception with an informative message that can be propagated up. */ static int RPy_SeqToSTRSXP(PyObject *object, SEXP *sexpp) { Py_ssize_t ii; PyObject *seq_object, *item, *item_tmp; SEXP new_sexp, str_R; seq_object = PySequence_Fast(object, "Cannot create R object from non-sequence object."); if (! seq_object) { return -1; } const Py_ssize_t length = PySequence_Fast_GET_SIZE(seq_object); if (length > R_LEN_T_MAX) { PyErr_Format(PyExc_ValueError, "The Python sequence is longer than the longuest possible vector in R"); Py_XDECREF(seq_object); return -1; } PROTECT(new_sexp = NEW_CHARACTER(length)); for (ii = 0; ii < length; ++ii) { item = PySequence_Fast_GET_ITEM(seq_object, ii); if (item == NACharacter_New(0)) { SET_STRING_ELT(new_sexp, ii, NA_STRING); continue; } #if (PY_VERSION_HEX < 0x03010000) if (PyString_Check(item)) { /* INCREF since item_tmp is DECREFed later */ item_tmp = item; Py_INCREF(item_tmp); str_R = mkChar(PyString_AS_STRING(item_tmp)); } else if (PyUnicode_Check(item)) { item_tmp = PyUnicode_AsUTF8String(item); if (item_tmp == NULL) { UNPROTECT(1); PyErr_Format(PyExc_ValueError, "Error raised by codec for element %zd.", ii); Py_XDECREF(seq_object); return -1; } const char *string = PyString_AsString(item_tmp); str_R = mkCharCE(string, CE_UTF8); } #else /* Only difference with Python < 3.1 is that PyString case is dropped. Technically a macro would avoid code duplication. */ if (PyUnicode_Check(item)) { item_tmp = PyUnicode_AsUTF8String(item); if (item_tmp == NULL) { UNPROTECT(1); PyErr_Format(PyExc_ValueError, "Error raised by codec for element %zd.", ii); Py_XDECREF(seq_object); return -1; } const char *string = PyBytes_AsString(item_tmp); str_R = mkCharCE(string, CE_UTF8); } #endif else { /* Last option: try to call str() on the object. */ item_tmp = PyObject_Str(item); if (item_tmp == NULL) { UNPROTECT(1); PyErr_Format(PyExc_ValueError, "Error raised when calling str() for element %zd.", ii); Py_XDECREF(seq_object); return -1; } #if (PY_VERSION_HEX < 0x03010000) str_R = mkChar(PyString_AS_STRING(item_tmp)); #else PyObject *item_tmp2 = PyUnicode_AsUTF8String(item_tmp); if (item_tmp2 == NULL) { UNPROTECT(1); PyErr_Format(PyExc_ValueError, "Error raised by codec for str(element %zd).", ii); Py_XDECREF(seq_object); return -1; } const char *string = PyBytes_AsString(item_tmp2); str_R = mkCharCE(string, CE_UTF8); Py_DECREF(item_tmp2); #endif } SET_STRING_ELT(new_sexp, ii, str_R); Py_XDECREF(item_tmp); } UNPROTECT(1); *sexpp = new_sexp; Py_XDECREF(seq_object); return 0; } /* Make an R STRSEXP from a Python string scalar */ static SEXP StrVectorSexp_AsSexp(PyObject *pyfloat) { int status; SEXP sexp; PyObject *seq_tmp = PyTuple_New(1); PyTuple_SetItem(seq_tmp, 0, pyfloat); status = RPy_SeqToSTRSXP(seq_tmp, &sexp); if (status == -1) { return NULL; } Py_DECREF(seq_tmp); return sexp; } static int StrVectorSexp_init(PyObject *self, PyObject *args, PyObject *kwds) { #ifdef RPY_VERBOSE printf("%p: StrVectorSexp initializing...\n", self); #endif int res = VectorSexp_init_private(self, args, kwds, (RPy_seqobjtosexpproc)RPy_SeqToSTRSXP, NULL, STRSXP); #ifdef RPY_VERBOSE printf("done (StrVectorSexp_init).\n"); #endif return res; } PyDoc_STRVAR(BoolVectorSexp_Type_doc, "R vector of booleans"); static int BoolVectorSexp_init(PyObject *self, PyObject *args, PyObject *kwds); static PyTypeObject BoolVectorSexp_Type = { /* The ob_type field must be initialized in the module init function * to be portable to Windows without using C++. */ #if (PY_VERSION_HEX < 0x03010000) PyObject_HEAD_INIT(NULL) 0, /*ob_size*/ #else PyVarObject_HEAD_INIT(NULL, 0) #endif "rpy2.rinterface.BoolSexpVector", /*tp_name*/ sizeof(PySexpObject), /*tp_basicsize*/ 0, /*tp_itemsize*/ /* methods */ 0, /*tp_dealloc*/ 0, /*tp_print*/ 0, /*tp_getattr*/ 0, /*tp_setattr*/ 0, /*tp_compare*/ 0, /*tp_repr*/ 0, /*tp_as_number*/ 0, /*tp_as_sequence*/ #if (PY_VERSION_HEX < 0x03010000) 0, /*tp_as_mapping*/ #else 0, #endif 0, /*tp_hash*/ 0, /*tp_call*/ 0, /*tp_str*/ 0, /*tp_getattro*/ 0, /*tp_setattro*/ #if PY_VERSION_HEX >= 0x02060000 & PY_VERSION_HEX < 0x03010000 0, /*tp_as_buffer*/ Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_HAVE_NEWBUFFER, /*tp_flags*/ #else 0, /*tp_as_buffer*/ 0, /*tp_flags*/ #endif BoolVectorSexp_Type_doc,/*tp_doc*/ 0, /*tp_traverse*/ 0, /*tp_clear*/ 0, /*tp_richcompare*/ 0, /*tp_weaklistoffset*/ 0, /*tp_iter*/ 0, /*tp_iternext*/ 0, /*tp_methods*/ 0, /*tp_members*/ 0, /*tp_getset*/ &VectorSexp_Type, /*tp_base*/ 0, /*tp_dict*/ 0, /*tp_descr_get*/ 0, /*tp_descr_set*/ 0, /*tp_dictoffset*/ (initproc)BoolVectorSexp_init, /*tp_init*/ 0, /*tp_alloc*/ 0, /*tp_new*/ 0, /*tp_free*/ 0 /*tp_is_gc*/ }; /* Take an arbitray Python sequence and a target pointer SEXP and build an R vector of "logical" values (booleans). The function returns 0 on success, -1 on failure. In the case of a failure, it will also create an exception with an informative message that can be propagated up. */ static int RPy_SeqToLGLSXP(PyObject *object, SEXP *sexpp) { Py_ssize_t ii; PyObject *seq_object, *item; SEXP new_sexp; seq_object = PySequence_Fast(object, "Cannot create R object from non-sequence object."); if (! seq_object) { return -1; } const Py_ssize_t length = PySequence_Fast_GET_SIZE(seq_object); if (length > R_LEN_T_MAX) { PyErr_Format(PyExc_ValueError, "The Python sequence is longer than the longuest possible vector in R"); Py_XDECREF(seq_object); return -1; } PROTECT(new_sexp = NEW_LOGICAL(length)); int *int_ptr = LOGICAL_POINTER(new_sexp); /*FIXME: Optimization possible for array.array by using memcpy(). * With Python >= 2.7, this could be extended to memoryviews. */ for (ii = 0; ii < length; ++ii) { item = PySequence_Fast_GET_ITEM(seq_object, ii); if (item == NALogical_New(0)) { /* Special case: NA value from R */ int_ptr[ii] = NA_LOGICAL; } else { int isnot = PyObject_Not(item); switch(isnot) { case 0: int_ptr[ii] = TRUE; break; case 1: int_ptr[ii] = FALSE; break; case -1: UNPROTECT(1); /* FIXME: PyObject_Not() will have raised an exception, * may be the text for the exception should be reported ?*/ PyErr_Format(PyExc_ValueError, "Error while evaluating 'not '.", ii); Py_XDECREF(seq_object); return -1; break; } } } UNPROTECT(1); *sexpp = new_sexp; Py_XDECREF(seq_object); return 0; } /* Make an R LGLSEXP from a Python bool scalar */ static SEXP BoolVectorSexp_AsSexp(PyObject *pyfloat) { int status; SEXP sexp; PyObject *seq_tmp = PyTuple_New(1); PyTuple_SetItem(seq_tmp, 0, pyfloat); status = RPy_SeqToLGLSXP(seq_tmp, &sexp); if (status == -1) { return NULL; } Py_DECREF(seq_tmp); return sexp; } static int BoolVectorSexp_init(PyObject *self, PyObject *args, PyObject *kwds) { #ifdef RPY_VERBOSE printf("%p: BoolVectorSexp initializing...\n", self); #endif int res = VectorSexp_init_private(self, args, kwds, (RPy_seqobjtosexpproc)RPy_SeqToLGLSXP, NULL, LGLSXP); #ifdef RPY_VERBOSE printf("done (BoolVectorSexp_init).\n"); #endif return res; } PyDoc_STRVAR(ByteVectorSexp_Type_doc, "R vector of bytes"); static int ByteVectorSexp_init(PyObject *self, PyObject *args, PyObject *kwds); static PyTypeObject ByteVectorSexp_Type = { /* The ob_type field must be initialized in the module init function * to be portable to Windows without using C++. */ #if (PY_VERSION_HEX < 0x03010000) PyObject_HEAD_INIT(NULL) 0, /*ob_size*/ #else PyVarObject_HEAD_INIT(NULL, 0) #endif "rpy2.rinterface.ByteSexpVector", /*tp_name*/ sizeof(PySexpObject), /*tp_basicsize*/ 0, /*tp_itemsize*/ /* methods */ 0, /*tp_dealloc*/ 0, /*tp_print*/ 0, /*tp_getattr*/ 0, /*tp_setattr*/ 0, /*tp_compare*/ 0, /*tp_repr*/ 0, /*tp_as_number*/ 0, /*tp_as_sequence*/ #if (PY_VERSION_HEX < 0x03010000) 0, /*tp_as_mapping*/ #else 0, #endif 0, /*tp_hash*/ 0, /*tp_call*/ 0, /*tp_str*/ 0, /*tp_getattro*/ 0, /*tp_setattro*/ #if PY_VERSION_HEX >= 0x02060000 & PY_VERSION_HEX < 0x03010000 0, /*tp_as_buffer*/ Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_HAVE_NEWBUFFER, /*tp_flags*/ #else 0, /*tp_as_buffer*/ 0, /*tp_flags*/ #endif ByteVectorSexp_Type_doc,/*tp_doc*/ 0, /*tp_traverse*/ 0, /*tp_clear*/ 0, /*tp_richcompare*/ 0, /*tp_weaklistoffset*/ 0, /*tp_iter*/ 0, /*tp_iternext*/ 0, /*tp_methods*/ 0, /*tp_members*/ 0, /*tp_getset*/ &VectorSexp_Type, /*tp_base*/ 0, /*tp_dict*/ 0, /*tp_descr_get*/ 0, /*tp_descr_set*/ 0, /*tp_dictoffset*/ (initproc)ByteVectorSexp_init, /*tp_init*/ 0, /*tp_alloc*/ 0, /*tp_new*/ 0, /*tp_free*/ 0 /*tp_is_gc*/ }; /* Take an arbitray Python sequence and a target pointer SEXP and build an R vector of "raw" values (bytes). The function returns 0 on success, -1 on failure. In the case of a failure, it will also create an exception with an informative message that can be propagated up. */ static int RPy_SeqToRAWSXP(PyObject *object, SEXP *sexpp) { Py_ssize_t ii; PyObject *seq_object, *item; SEXP new_sexp; seq_object = PySequence_Fast(object, "Cannot create R object from non-sequence object."); if (! seq_object) { return -1; } const Py_ssize_t length = PySequence_Fast_GET_SIZE(seq_object); if (length > R_LEN_T_MAX) { PyErr_Format(PyExc_ValueError, "The Python sequence is longer than the longuest possible vector in R"); Py_XDECREF(seq_object); return -1; } PROTECT(new_sexp = NEW_RAW(length)); char *raw_ptr = (char *)RAW_POINTER(new_sexp); /*FIXME: Optimization possible for array.array by using memcpy(). * With Python >= 2.7, this could be extended to memoryviews. */ for (ii = 0; ii < length; ++ii) { item = PySequence_Fast_GET_ITEM(seq_object, ii); Py_ssize_t size_tmp; char *buffer; int ok; #if (PY_VERSION_HEX < 0x03010000) ok = PyString_AsStringAndSize(item, &buffer, &size_tmp); #else ok = PyBytes_AsStringAndSize(item, &buffer, &size_tmp); #endif if (ok == -1) { UNPROTECT(1); PyErr_Format(PyExc_ValueError, "Element %zd is not a byte.", ii); Py_XDECREF(seq_object); return -1; } else if (size_tmp > 1) { UNPROTECT(1); PyErr_Format(PyExc_ValueError, "Element %zd contains more than one byte.", ii); Py_XDECREF(seq_object); return -1; } raw_ptr[ii] = buffer[0]; } UNPROTECT(1); *sexpp = new_sexp; Py_XDECREF(seq_object); return 0; } static int ByteVectorSexp_init(PyObject *self, PyObject *args, PyObject *kwds) { #ifdef RPY_VERBOSE printf("%p: ByteVectorSexp initializing...\n", self); #endif int res = VectorSexp_init_private(self, args, kwds, (RPy_seqobjtosexpproc)RPy_SeqToRAWSXP, NULL, RAWSXP); #ifdef RPY_VERBOSE printf("done (ByteVectorSexp_init).\n"); #endif return res; } PyDoc_STRVAR(ComplexVectorSexp_Type_doc, "R vector of complex values."); static int ComplexVectorSexp_init(PyObject *self, PyObject *args, PyObject *kwds); static PyTypeObject ComplexVectorSexp_Type = { /* The ob_type field must be initialized in the module init function * to be portable to Windows without using C++. */ #if (PY_VERSION_HEX < 0x03010000) PyObject_HEAD_INIT(NULL) 0, /*ob_size*/ #else PyVarObject_HEAD_INIT(NULL, 0) #endif "rpy2.rinterface.ComplexSexpVector", /*tp_name*/ sizeof(PySexpObject), /*tp_basicsize*/ 0, /*tp_itemsize*/ /* methods */ 0, /*tp_dealloc*/ 0, /*tp_print*/ 0, /*tp_getattr*/ 0, /*tp_setattr*/ 0, /*tp_compare*/ 0, /*tp_repr*/ 0, /*tp_as_number*/ 0, /*tp_as_sequence*/ #if (PY_VERSION_HEX < 0x03010000) 0, /*tp_as_mapping*/ #else 0, #endif 0, /*tp_hash*/ 0, /*tp_call*/ 0, /*tp_str*/ 0, /*tp_getattro*/ 0, /*tp_setattro*/ #if PY_VERSION_HEX >= 0x02060000 & PY_VERSION_HEX < 0x03010000 0, /*tp_as_buffer*/ Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_HAVE_NEWBUFFER, /*tp_flags*/ #else 0, /*tp_as_buffer*/ 0, /*tp_flags*/ #endif ComplexVectorSexp_Type_doc, /*tp_doc*/ 0, /*tp_traverse*/ 0, /*tp_clear*/ 0, /*tp_richcompare*/ 0, /*tp_weaklistoffset*/ 0, /*tp_iter*/ 0, /*tp_iternext*/ 0, /*tp_methods*/ 0, /*tp_members*/ 0, /*tp_getset*/ &VectorSexp_Type, /*tp_base*/ 0, /*tp_dict*/ 0, /*tp_descr_get*/ 0, /*tp_descr_set*/ 0, /*tp_dictoffset*/ (initproc)ComplexVectorSexp_init, /*tp_init*/ 0, /*tp_alloc*/ 0, /*tp_new*/ 0, /*tp_free*/ 0 /*tp_is_gc*/ }; /* Take an arbitray Python sequence and a target pointer SEXP and build an R vector of "complex" values. The function returns 0 on success, -1 on failure. In the case of a failure, it will also create an exception with an informative message that can be propagated up. */ static int RPy_SeqToCPLXSXP(PyObject *object, SEXP *sexpp) { Py_ssize_t ii; PyObject *seq_object, *item; SEXP new_sexp; seq_object = PySequence_Fast(object, "Cannot create R object from non-sequence object."); if (! seq_object) { return -1; } const Py_ssize_t length = PySequence_Fast_GET_SIZE(seq_object); if (length > R_LEN_T_MAX) { PyErr_Format(PyExc_ValueError, "The Python sequence is longer than the longuest possible vector in R"); Py_XDECREF(seq_object); return -1; } PROTECT(new_sexp = NEW_COMPLEX(length)); /*FIXME: Optimization possible for array.array by using memcpy(). * With Python >= 2.7, this could be extended to memoryviews. */ for (ii = 0; ii < length; ++ii) { item = PySequence_Fast_GET_ITEM(seq_object, ii); if (item == NAComplex_New(0)) { COMPLEX(new_sexp)[ii].r = NA_REAL; COMPLEX(new_sexp)[ii].i = NA_REAL; } else if (PyComplex_Check(item)) { Py_complex cplx = PyComplex_AsCComplex(item); COMPLEX(new_sexp)[ii].r = cplx.real; COMPLEX(new_sexp)[ii].i = cplx.imag; } else { UNPROTECT(1); PyErr_Format(PyExc_ValueError, "Element %zd is not a complex", ii); Py_XDECREF(seq_object); return -1; } } UNPROTECT(1); *sexpp = new_sexp; Py_XDECREF(seq_object); return 0; } /* Make an R LGLSEXP from a Python complex scalar */ static SEXP ComplexVectorSexp_AsSexp(PyObject *pyfloat) { int status; SEXP sexp; PyObject *seq_tmp = PyTuple_New(1); PyTuple_SetItem(seq_tmp, 0, pyfloat); status = RPy_SeqToCPLXSXP(seq_tmp, &sexp); if (status == -1) { return NULL; } Py_DECREF(seq_tmp); return sexp; } static int ComplexVectorSexp_init(PyObject *self, PyObject *args, PyObject *kwds) { #ifdef RPY_VERBOSE printf("%p: ComplexVectorSexp initializing...\n", self); #endif int res = VectorSexp_init_private(self, args, kwds, (RPy_seqobjtosexpproc)RPy_SeqToCPLXSXP, NULL, CPLXSXP); #ifdef RPY_VERBOSE printf("done (ComplexVectorSexp_init).\n"); #endif return res; } PyDoc_STRVAR(ListVectorSexp_Type_doc, "R list."); static int ListVectorSexp_init(PyObject *self, PyObject *args, PyObject *kwds); static PyTypeObject ListVectorSexp_Type = { /* The ob_type field must be initialized in the module init function * to be portable to Windows without using C++. */ #if (PY_VERSION_HEX < 0x03010000) PyObject_HEAD_INIT(NULL) 0, /*ob_size*/ #else PyVarObject_HEAD_INIT(NULL, 0) #endif "rpy2.rinterface.ListSexpVector", /*tp_name*/ sizeof(PySexpObject), /*tp_basicsize*/ 0, /*tp_itemsize*/ /* methods */ 0, /*tp_dealloc*/ 0, /*tp_print*/ 0, /*tp_getattr*/ 0, /*tp_setattr*/ 0, /*tp_compare*/ 0, /*tp_repr*/ 0, /*tp_as_number*/ 0, /*tp_as_sequence*/ #if (PY_VERSION_HEX < 0x03010000) 0, /*tp_as_mapping*/ #else 0, #endif 0, /*tp_hash*/ 0, /*tp_call*/ 0, /*tp_str*/ 0, /*tp_getattro*/ 0, /*tp_setattro*/ #if PY_VERSION_HEX >= 0x02060000 & PY_VERSION_HEX < 0x03010000 0, /*tp_as_buffer*/ Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_HAVE_NEWBUFFER, /*tp_flags*/ #else 0, /*tp_as_buffer*/ 0, /*tp_flags*/ #endif ListVectorSexp_Type_doc, /*tp_doc*/ 0, /*tp_traverse*/ 0, /*tp_clear*/ 0, /*tp_richcompare*/ 0, /*tp_weaklistoffset*/ 0, /*tp_iter*/ 0, /*tp_iternext*/ 0, /*tp_methods*/ 0, /*tp_members*/ 0, /*tp_getset*/ &VectorSexp_Type, /*tp_base*/ 0, /*tp_dict*/ 0, /*tp_descr_get*/ 0, /*tp_descr_set*/ 0, /*tp_dictoffset*/ (initproc)ListVectorSexp_init, /*tp_init*/ 0, /*tp_alloc*/ 0, /*tp_new*/ 0, /*tp_free*/ 0 /*tp_is_gc*/ }; /* Take an arbitray Python sequence and a target pointer SEXP and build an R list. The function returns 0 on success, -1 on failure. In the case of a failure, it will also create an exception with an informative message that can be propagated up. */ static int RPy_SeqToVECSXP(PyObject *object, SEXP *sexpp) { Py_ssize_t ii; PyObject *seq_object, *item; SEXP new_sexp, new_sexp_item; seq_object = PySequence_Fast(object, "Cannot create R object from non-sequence object."); if (! seq_object) { return -1; } const Py_ssize_t length = PySequence_Fast_GET_SIZE(seq_object); if (length > R_LEN_T_MAX) { PyErr_Format(PyExc_ValueError, "The Python sequence is longer than the longuest possible vector in R"); Py_XDECREF(seq_object); return -1; } PROTECT(new_sexp = NEW_LIST(length)); for (ii = 0; ii < length; ++ii) { item = PySequence_Fast_GET_ITEM(seq_object, ii); if (PyObject_TypeCheck(item, &Sexp_Type)) { /* if element in the list already represents an R object, * add it as is */ SET_ELEMENT(new_sexp, ii, RPY_SEXP((PySexpObject *)item)); } else if (PyFloat_Check(item)) { /* if element is a float, put it silently into a vector of length 1 */ /* FIXME: PROTECT ? */ new_sexp_item = FloatVectorSexp_AsSexp(item); if (new_sexp_item) { SET_ELEMENT(new_sexp, ii, new_sexp_item); } else { UNPROTECT(1); Py_XDECREF(seq_object); return -1; } } else if (PyBool_Check(item)) { new_sexp_item = BoolVectorSexp_AsSexp(item); if (new_sexp_item) { SET_ELEMENT(new_sexp, ii, new_sexp_item); } else { UNPROTECT(1); Py_XDECREF(seq_object); return -1; } } else if (PyLong_Check(item) #if (PY_VERSION_HEX < 0x03010000) || PyInt_Check(item)) { #else ) { #endif new_sexp_item = IntVectorSexp_AsSexp(item); if (new_sexp_item) { SET_ELEMENT(new_sexp, ii, new_sexp_item); } else { UNPROTECT(1); Py_XDECREF(seq_object); return -1; } } else if (PyUnicode_Check(item) #if (PY_VERSION_HEX < 0x03010000) || PyString_Check(item)) { #else ) { #endif new_sexp_item = StrVectorSexp_AsSexp(item); if (new_sexp_item) { SET_ELEMENT(new_sexp, ii, new_sexp_item); } else { UNPROTECT(1); Py_XDECREF(seq_object); return -1; } } else if (PyComplex_Check(item)) { new_sexp_item = FloatVectorSexp_AsSexp(item); if (new_sexp_item) { SET_ELEMENT(new_sexp, ii, new_sexp_item); } else { UNPROTECT(1); Py_XDECREF(seq_object); return -1; } } else { UNPROTECT(1); PyErr_Format(PyExc_ValueError, "Element %zd cannot be implicitly cast to an R object.", ii); Py_XDECREF(seq_object); return -1; } } UNPROTECT(1); *sexpp = new_sexp; Py_XDECREF(seq_object); return 0; } static int ListVectorSexp_init(PyObject *self, PyObject *args, PyObject *kwds) { #ifdef RPY_VERBOSE printf("%p: ListVectorSexp initializing...\n", self); #endif int res = VectorSexp_init_private(self, args, kwds, (RPy_seqobjtosexpproc)RPy_SeqToVECSXP, NULL, VECSXP); #ifdef RPY_VERBOSE printf("done (ListVectorSexp_init).\n"); #endif return res; } rpy2-2.3.9/rpy/rinterface/array.h0000644000175000017500000000023012271276146020015 0ustar laurentlaurent00000000000000 #ifndef RPY_AR_H #define RPY_AR_H #include #include static PyObject* array_struct_get(PySexpObject *self); #endif /* !RPY_AR_H */ rpy2-2.3.9/rpy/rinterface/sequence.h0000644000175000017500000000053612271276146020520 0ustar laurentlaurent00000000000000#ifndef _RPY_PRIVATE_SEQUENCE_H_ #define _RPY_PRIVATE_SEQUENCE_H_ #ifndef _RPY_RINTERFACE_MODULE_ #error sequence.h should not be included directly #endif static PySequenceMethods VectorSexp_sequenceMethods; typedef int (* RPy_seqobjtosexpproc)(PyObject *, SEXP *); typedef int (* RPy_iterobjtosexpproc)(PyObject *, Py_ssize_t, SEXP *); #endif rpy2-2.3.9/rpy/rinterface/buffer.h0000644000175000017500000000030312271276146020151 0ustar laurentlaurent00000000000000#ifndef _RPY_PRIVATE_BUFFER_H_ #define _RPY_PRIVATE_BUFFER_H_ #ifndef _RPY_RINTERFACE_MODULE_ #error buffer.h should not be included #endif static PyBufferProcs VectorSexp_as_buffer; #endif rpy2-2.3.9/rpy/rinterface/null_value.c0000644000175000017500000002656012271276146021056 0ustar laurentlaurent00000000000000/* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * Copyright (C) 2008-2010 Laurent Gautier * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ /* --- NULL value --- */ PyDoc_STRVAR(RNULL_Type_doc, "R NULL (singleton)." ); #if (PY_VERSION_HEX < 0x03010000) staticforward PyTypeObject RNULL_Type; #else static PyTypeObject RNULL_Type; #endif static PyObject* RNULLType_tp_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { static PySexpObject *self = NULL; static char *kwlist[] = {0}; if (! PyArg_ParseTupleAndKeywords(args, kwds, "", kwlist)) { return NULL; } if (self == NULL) { self = (PySexpObject*)(Sexp_Type.tp_new(&RNULL_Type, Py_None, Py_None)); if (self == NULL) { return NULL; } } Py_XINCREF(self); return (PyObject *)self; } static PyObject* RNULLType_tp_init(PyObject *self, PyObject *args, PyObject *kwds) { static char *kwlist[] = {0}; if (! PyArg_ParseTupleAndKeywords(args, kwds, "", kwlist)) { return NULL; } return 0; } static PyObject* RNULLType_repr(PyObject *self) { static PyObject* repr = NULL; if (repr == NULL) { #if (PY_VERSION_HEX < 0x03010000) repr = PyString_FromString("rpy2.rinterface.NULL"); #else repr = PyUnicode_FromString("rpy2.rinterface.NULL"); #endif } Py_XINCREF(repr); return repr; } static PyObject* RNULLType_str(PyObject *self) { static PyObject* repr = NULL; if (repr == NULL) { #if (PY_VERSION_HEX < 0x03010000) repr = PyString_FromString("NULL"); #else repr = PyUnicode_FromString("NULL"); #endif } Py_XINCREF(repr); return repr; } static int RNULLType_nonzero(PyObject *self) { return 0; } static PyNumberMethods RNULLType_as_number = { 0, /* nb_add */ 0, /* nb_subtract */ 0, /* nb_multiply */ #if (PY_VERSION_HEX < 0x03010000) 0, /* nb_divide */ #endif 0, /* nb_remainder */ 0, /* nb_divmod */ 0, /* nb_power */ 0, /* nb_negative */ 0, /* nb_positive */ 0, /* nb_absolute */ (inquiry)RNULLType_nonzero, /* nb_nonzero */ 0, /* nb_invert */ 0, /* nb_lshift */ 0, /* nb_rshift */ 0, /* nb_and */ 0, /* nb_xor */ 0, /* nb_or */ #if (PY_VERSION_HEX < 0x03010000) 0, /* nb_coerce */ #endif 0, /* nb_int */ #if (PY_VERSION_HEX < 0x03010000) 0, /* nb_long */ #else NULL, /* reserved */ #endif 0, /* nb_float */ #if (PY_VERSION_HEX < 0x03010000) 0, /* nb_oct */ 0, /* nb_hex */ #endif /* added in release 2.0 */ 0, /* nb_inplace_add */ 0, /* nb_inplace_subtract */ 0, /* nb_inplace_multiply */ #if (PY_VERSION_HEX < 0x03010000) 0, /* nb_inplace_divide */ #endif 0, /* nb_inplace_remainder */ 0, /* nb_inplace_power */ 0, /* nb_inplace_lshift */ 0, /* nb_inplace_rshift */ 0, /* nb_inplace_and */ 0, /* nb_inplace_xor */ 0, /* nb_inplace_or */ /* added in release 2.2 */ 0, /* nb_floor_divide */ 0, /* nb_true_divide */ 0, /* nb_inplace_floor_divide */ 0, /* nb_inplace_true_divide */ /* added in version 2.5 */ #if (PY_VERSION_HEX >= 0x02050000) 0, /* nb_index */ #endif }; static PyTypeObject RNULL_Type = { /* The ob_type field must be initialized in the module init function * to be portable to Windows without using C++. */ #if (PY_VERSION_HEX < 0x03010000) PyObject_HEAD_INIT(NULL) 0, /*ob_size*/ #else PyVarObject_HEAD_INIT(NULL, 0) #endif "rpy2.rinterface.RNULLType", /*tp_name*/ sizeof(PySexpObject), /*tp_basicsize*/ 0, /*tp_itemsize*/ /* methods */ 0, /*tp_dealloc*/ 0, /*tp_print*/ 0, /*tp_getattr*/ 0, /*tp_setattr*/ 0, /*tp_compare*/ RNULLType_repr, /*tp_repr*/ &RNULLType_as_number, /*tp_as_number*/ 0, /*tp_as_sequence*/ 0, /*tp_as_mapping*/ 0, /*tp_hash*/ 0, /*tp_call*/ RNULLType_str, /*tp_str*/ 0, /*tp_getattro*/ 0, /*tp_setattro*/ 0, /*tp_as_buffer*/ #if (PY_VERSION_HEX < 0x03010000) Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_CHECKTYPES, /*tp_flags*/ #else Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /*tp_flags*/ #endif RNULL_Type_doc, /*tp_doc*/ 0, /*tp_traverse*/ 0, /*tp_clear*/ 0, /*tp_richcompare*/ 0, /*tp_weaklistoffset*/ 0, /*tp_iter*/ 0, /*tp_iternext*/ 0, /*tp_methods*/ 0, /*tp_members*/ 0, /*tp_getset*/ &Sexp_Type, /*tp_base*/ 0, /*tp_dict*/ 0, /*tp_descr_get*/ 0, /*tp_descr_set*/ 0, /*tp_dictoffset*/ (initproc)RNULLType_tp_init, /*tp_init*/ 0, /*tp_alloc*/ RNULLType_tp_new, /*tp_new*/ 0, /*tp_free*/ 0 /*tp_is_gc*/ }; static PyObject* RNULL_Type_New(int new) { RPY_NA_NEW(RNULL_Type, RNULLType_tp_new) } /* Unbound marker value */ PyDoc_STRVAR(UnboundValue_Type_doc, "Unbound marker (R_UnboundValue in R's C API)." ); #if (PY_VERSION_HEX < 0x03010000) staticforward PyTypeObject UnboundValue_Type; #else static PyTypeObject UnboundValue_Type; #endif static PyObject* UnboundValueType_tp_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { static PySexpObject *self = NULL; static char *kwlist[] = {0}; if (! PyArg_ParseTupleAndKeywords(args, kwds, "", kwlist)) { return NULL; } if (self == NULL) { self = (PySexpObject*)(Sexp_Type.tp_new(&UnboundValue_Type, Py_None, Py_None)); if (self == NULL) { return NULL; } } Py_XINCREF(self); return (PyObject *)self; } static PyObject* UnboundValueType_tp_init(PyObject *self, PyObject *args, PyObject *kwds) { static char *kwlist[] = {0}; if (! PyArg_ParseTupleAndKeywords(args, kwds, "", kwlist)) { return NULL; } return 0; } static PyObject* UnboundValueType_repr(PyObject *self) { static PyObject* repr = NULL; if (repr == NULL) { #if (PY_VERSION_HEX < 0x03010000) repr = PyString_FromString("rpy2.rinterface.UnboundValue"); #else repr = PyUnicode_FromString("rpy2.rinterface.UnboundValue"); #endif } Py_XINCREF(repr); return repr; } static PyObject* UnboundValueType_str(PyObject *self) { static PyObject* repr = NULL; if (repr == NULL) { #if (PY_VERSION_HEX < 0x03010000) repr = PyString_FromString("UnboundValue"); #else repr = PyUnicode_FromString("UnboundValue"); #endif } Py_XINCREF(repr); return repr; } static PyTypeObject UnboundValue_Type = { /* The ob_type field must be initialized in the module init function * to be portable to Windows without using C++. */ #if (PY_VERSION_HEX < 0x03010000) PyObject_HEAD_INIT(NULL) 0, /*ob_size*/ #else PyVarObject_HEAD_INIT(NULL, 0) #endif "rpy2.rinterface.UnboundValueType", /*tp_name*/ sizeof(PySexpObject), /*tp_basicsize*/ 0, /*tp_itemsize*/ /* methods */ 0, /*tp_dealloc*/ 0, /*tp_print*/ 0, /*tp_getattr*/ 0, /*tp_setattr*/ 0, /*tp_compare*/ UnboundValueType_repr, /*tp_repr*/ 0, /*tp_as_number*/ 0, /*tp_as_sequence*/ 0, /*tp_as_mapping*/ 0, /*tp_hash*/ 0, /*tp_call*/ UnboundValueType_str, /*tp_str*/ 0, /*tp_getattro*/ 0, /*tp_setattro*/ 0, /*tp_as_buffer*/ #if (PY_VERSION_HEX < 0x03010000) Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_CHECKTYPES, /*tp_flags*/ #else Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /*tp_flags*/ #endif UnboundValue_Type_doc, /*tp_doc*/ 0, /*tp_traverse*/ 0, /*tp_clear*/ 0, /*tp_richcompare*/ 0, /*tp_weaklistoffset*/ 0, /*tp_iter*/ 0, /*tp_iternext*/ 0, //NAInteger_methods, /*tp_methods*/ 0, /*tp_members*/ 0, /*tp_getset*/ &Sexp_Type, /*tp_base*/ 0, /*tp_dict*/ 0, /*tp_descr_get*/ 0, /*tp_descr_set*/ 0, /*tp_dictoffset*/ (initproc)UnboundValueType_tp_init, /*tp_init*/ 0, /*tp_alloc*/ UnboundValueType_tp_new, /*tp_new*/ 0, /*tp_free*/ 0 /*tp_is_gc*/ }; static PyObject* UnboundValue_Type_New(int new) { RPY_NA_NEW(UnboundValue_Type, UnboundValueType_tp_new) } rpy2-2.3.9/rpy/rpy_classic.py0000644000175000017500000002002012271276146017270 0ustar laurentlaurent00000000000000""" Implementation of RPy 1.x (for compatibility) """ import rpy2.rinterface as ri import array # RPY_VERSION = '1.x' # --- options in 'rpy_options.py' rpy_options = { 'RHOME':None, # R Installation Directory 'RVERSION':None, # R Version *string* 'RVER':None, # R Version *number* 'RUSER':None, # R User's Home Directory 'USE_NUMERIC':None, # Is Numeric module available 'VERBOSE':False, # Should status messages be displated. 'SETUP_READ_CONSOLE': True, # False for no standard console read config 'SETUP_WRITE_CONSOLE': True, # False for no standard console write config 'SETUP_SHOWFILES': True # False for no standard console file viewerd config } # --- more options VERBOSE = True RVERSION = None RHOME = None TOP_CONVERSION = 4 PROC_CONVERSION = 4 CLASS_CONVERSION = 3 BASIC_CONVERSION = 2 VECTOR_CONVERSION = 1 NO_CONVERSION = 0 NO_DEFAULT = -1 # from RPy.h TOP_MODE = 4 # --- init R ri.initr() class RPyException(Exception): """ Generic exeception for RPy """ pass class RPyTypeConversionException(RPyException): pass class RPyRException(RuntimeError): """ Runtime error while running R code. """ pass # for backwards compatibility RException = RPyException # I/O setters # FIXME: sort out the details of what RPy is doing with that # and what is the amount that is user-defined (and/or used). set_rpy_output = None set_rpy_input = None get_rpy_output = None get_rpy_input = None # --- "CONVERSION" system # same default as in "rpymodule.c" default_mode = -1 # Wrap a function in safe modes to avoid infinite recursion when # called from within the conversion system def with_mode(i, fun): def f(*args, **kwds): try: e = get_default_mode() set_default_mode(i) return fun(*args, **kwds) finally: set_default_mode(e) return f # Manage the global mode def set_default_mode(mode): if not isinstance(mode, int): raise ValueError("mode should be an int.") if (mode < -1) or (mode > TOP_MODE): raise ValueError("wrong mode.") global default_mode default_mode = mode def get_default_mode(): global default_mode return default_mode # note: inherits from dict: not considering pre-2.2 versions of Python class Dict_With_Mode(dict): def __setitem__(self, key, value): v = with_mode(BASIC_CONVERSION, value) if type(key) not in [str, tuple]: k = with_mode(BASIC_CONVERSION, key) super(Dict_With_Mode, self).__setitem__(k, v) proc_table = Dict_With_Mode({}) class_table = Dict_With_Mode({}) def seq2vec(seq): types = [bool, int, float, str] has_type = [False, False, False, False] for tp_i, tp in enumerate(types): for elt in seq: if isinstance(elt, tp): has_type[tp_i] = True r_type = None if has_type[3]: r_type = ri.STRSXP elif has_type[2]: r_type = ri.REALSXP elif has_type[1]: r_type = ri.INTSXP elif has_type[0]: r_type = ri.LGLSXP if r_type is not None: vec = ri.SexpVector(seq, r_type) return vec def py2rpy(obj): if isinstance(obj, int): robj = ri.SexpVector([obj, ], ri.INTSXP) return robj if isinstance(obj, float): robj = ri.SexpVector([obj, ], ri.REALSXP) return robj if isinstance(obj, str): robj = ri.SexpVector([obj, ], ri.STRSXP) return robj if isinstance(obj, complex): robj = ri.SexpVector([obj, ], ri.CPLSXP) return robj if isinstance(obj, list) or isinstance(obj, tuple): robj = seq2vec(obj) return robj raise ValueError("Don't know what to do with 'obj'.") def rpy2py_basic(obj): if hasattr(obj, '__len__'): if obj.typeof in [ri.INTSXP, ri.REALSXP, ri.CPLXSXP, ri.LGLSXP,ri.STRSXP]: res = [x for x in obj] elif obj.typeof in [ri.VECSXP]: try: # if the returned objects is a list with names, return a dict obj_names = obj.do_slot("names") # caution: throw an exception if duplicated names if (len(set(obj_names)) != len(obj_names)): raise ValueError("Duplicated names in the R named list.") res = dict([(obj_names[i], rpy2py(x)) for i,x in enumerate(obj)]) except LookupError: res = [rpy2py(x) for x in obj] elif obj.typeof == [ri.LANGSXP]: res = Robj(obj) else: raise ValueError("Invalid type for 'obj'.") else: res = Robj(obj) return res #raise ValueError("Invalid type for 'obj'.") def rpy2py(obj, mode=None): """ Transform RPy objects into pure python objects. """ if mode is None: mode = default_mode if mode == NO_CONVERSION: res = Robj(obj) return res if mode == BASIC_CONVERSION: res = rpy2py_basic(obj) return res raise ValueError("Invalid default mode.") class Robj(object): """ Class to model any R object. As in the 'classic' RPy (that is versions 1.x), Whether an object is callable or a vector, or else, is resolved at runtime in R and it only exposed as an "R something" to Python. """ __local_mode = NO_DEFAULT def __init__(self, sexp): if not isinstance(sexp, ri.Sexp): raise ValueError('"sexp" must inherit from rinterface.Sexp (not %s)' %str(type(sexp))) self.__sexp = sexp def __call__(self, *args, **kwargs): args_r = [] for a in args: if isinstance(a, ri.Sexp): a = a elif isinstance(a, Robj): a = a.get_sexp() else: a = py2rpy(a) args_r.append(a) kwargs_r = {} for a_n in kwargs: a = kwargs[a_n] if isinstance(a, ri.Sexp): a = a elif isinstance(a, Robj): a = a.get_sexp() else: a = py2rpy(a) kwargs_r[a_n] = a res = self.__sexp(*args_r, **kwargs_r) res = rpy2py(res) return res def __getitem__(self, item): if not isinstance(item, Robj): item = py2rpy(item) res = r["["](self.__sexp, item) mode = self.__local_mode if mode == BASIC_CONVERSION: res = rpy2py(res) return res ##FIXME: not part of RPy-1.x. def get_sexp(self): return self.__sexp sexp = property(fget = get_sexp) #def __repr__(self): # res = rpy2py(self) # return res def as_py(self, mode = None): if mode is None: mode = default_mode res = rpy2py(self.__sexp, mode = mode) return res def __local_mode(self, mode = default_mode): self.__local_mode = mode class R(object): def __init__(self): self.get = ri.globalenv.get self.TRUE = ri.TRUE self.FALSE = ri.FALSE def __getattr__(self, name): if name.startswith('__') and name.endswith('__'): return super(R, self).__getattr__(name) if len(name) > 1 and name[-1] == '_' and name[-2] != '_': name = name[:-1] name = name.replace('__', '<-') name = name.replace('_', '.') res = self.__getitem__(name) return res def __getitem__(self, name): #FIXME: "get function only" vs "get anything" # wantfun = True ? res = ri.globalenv.get(name) res = rpy2py(res) return res def __call__(self, s): return self.eval(self.parse(text=s)) def __help__(self, *args, **kwargs): helpobj.helpfun(*arg, **kw) def __repr__(self): r_version = ri.baseenv['R.version.string'][0] res = 'RPy version %s with %s' %(RPY_VERSION, r_version) return res def __str__(self): return repr(self) def __cleanup__(self): ri.endEmbeddedR() del(self) r = R() rpy2-2.3.9/NEWS0000644000175000017500000007734512271276145014315 0ustar laurentlaurent00000000000000Release 2.3.9 ============= Bugs fixed ---------- - Changes in pandas 0.13.0 broke the rpy2 conversion layer (Issue #173) Release 2.3.8 ============= Bugs fixed ---------- - Crash with R-3.0.2. Changes in R-3.0.2's C API coupled to a strange behaviour with R promises caused the problem. (PR #150) Release 2.3.7 ============= Bugs fixed ---------- - ggplot2's "guides" were missing - ggplot2's "theme_classic" was missing (PR #143) - ggplot2's "element_rect" was missing (PR #144) - :func:`rpy2.interactive.packages` was broken (PR #142) Release 2.3.6 ============= Bugs fixed ---------- - Several reports of segfault on OS X (since rpy2-2.3.1 - PR #109) - More fixes in converting `DataFrames` with dates from `pandas` Relase 2.3.5 ============ Bugs fixed ---------- - Missing mapping to ggplot2's `scale_shape_discrete` function - Better handling of dates in Pandas - Constructor for POSIXct improved (and fixed) Changes ------- - The attribute :attr:`rclass` is no longer read-only and can be set (since R allows it) - Importing the module :mod:`rpy2.interactive` no longer activates event processing by default (triggering concurrency errors when used with ipython). New features ------------ - New module :mod:`rpy2.interactive.ipython` (so far plotting automatically a ggplot2 figure in the iPython's console) - It is now possible to set the :attr:`rclass`. Relase 2.3.4 ============ Bugs fixed ---------- - Spurious error when running unit tests with Python 3 and numpy installed - Missing mapping to ggplot2's `geom_dotplot` function - Warnings are not longer printed (see Changes below) Changes ------- - Bumped target version of ggplot2 to 0.9.3.1 - Warnings are not longer printed. The C-level function in R became hidden in R-3.0, and the cost of an R-level check/print is relatively high if the R code called is very short. This might evolve into printing warnings only if interactive mode in Python (if this can be checked reliably). Release 2.3.3 ============= Bugs fixed ---------- - Some of the data.frames converted from :mod:`pandas` were triggering a :class:`TypeError` when calling :func:`repr` - In :mod:`rpy2.robjects.lib.ggplot2`, a mapping to `coord_fixed` was missing (PR #120) - Using the parameter `lib_loc` in a call to :func:`rpy2.robjects.packages.importr` was resulting in an error (PR #119) - Creating a `layer` through the `rpy2.robjects.lib.ggplot2` interface did not accept parameters (PR #122) - Testing the Python version was crashing of a number of unsupported Python versions (<= 2.6) (PR #117) New features ------------ - New module pandas2ri to convert from mod:`pandas` `DataFrame` objects - New classes :class:`rpy2.robjects.lib.grid.Unit` and :class:`rpy2.robjects.lib.grid.Gpar` to model their counterparts in R's `grid` package as they were previously missing from rpy2. Release 2.3.2 ============= Bug fixed --------- - Building on Win64 (pull request #6) - Fetching data from an R package through `importr` was masking any R object called `data` in that package. The data are now under the attribute name `__rdata__`. This is not completely safe either, although much less likely, a warning will be issued if still masking anything. Changes ------- - More informative error message when failing to build because `R CMD config` does not return what is expected Release 2.3.1 ============= Bugs fixed ---------- - default console print callback with Python (issue #112 linked to it) - deprecation warnings with ggplot2 (issue #111 and contributed patch) Release 2.3.0 ============= New Features ------------ :mod:`rpy2.rinterface`: - C-level API, allowing other C-level modules to make use of utilities without going through the Python level. The exact definition of the API is not yet fixed. For now there is PyRinteractive_IsInitialized() to assess whether R was initialized (through :mod:`rpy2.rinterface` or not). - C-module _rpy_device, allowing one to implement R graphical devices in Python [(very) experimental] - Tracking of R objects kept protected from garbage collection by rpy2 is now possible. - New method :meth:`Sexp.rid` to return the identifier of the R object represented by a Python/rpy2 object :mod:`rpy2.rinteractive`: - Dynamic build of Python docstrings out of the R manual pages :mod:`rpy2.robjects.help`: - Build dynamic help :mod:`rpy2.robjects.packages: - Build anonymous R packages from strings - When using :func:`importr`, the datasets are added as an attribute :attr:`data`, itself an instance of a new class :class:`PackageData`. It no longer possible to access datasets are regular objects from a code package (because of changes in R), and the new system is more robust against quirks. Changes ------- :mod:`rpy2.rinterface`: - :attr:`SexpClosure.env` to replace the method `closureenv`. Release 2.2.6 ============= Bugs fixed ---------- - Newest R-2.15 and ggplot2 0.9 broke the ggplot2 interaface in :mod:`rpy2.robjects.lib.ggplot2` Release 2.2.5 ============= Bugs fixed ---------- - install process: Library location for some of the R installations - should compile on win32 (thanks to a patch from Evgeny Cherkashin), a work to a limited extend Release 2.2.4 ============= Bugs fixed ---------- - Memory leak when creating R vectors from Python (issue #82) Release 2.2.3 ============= Bugs fixed ---------- - Dynamic construction of S4 classes was looking for R help as 'class.' rather than '-class' - The cleanup of temporary directories created by R was not happening if the Python process terminated without calline :func:`rpy2.rinterface.endr()` (issue #68, and proof-of-principle fix by chrish42) Release 2.2.2 ============= Bugs fixed ---------- - With the robjects layer, repr() on a list containing non-vector elements was failing Release 2.2.1 ============= Bugs fixed ---------- - MANIFEST.in was missing from MANIFEST.in, required with Python 3 Release 2.2.0 ============= New Features ------------ - Support for Python 3, and for some of its features ported to Python 2.7 :mod:`rpy2.robjects`: - :meth:`Environment.keys` to list the keys - classes :class:`robjects.vectors.POSIXlt` and :class:`robjects.vectors.POSIXlt` to represent vectors of R dates/time - :func:`packages.get_packagepath` to get the path to an R package - module :mod:`rpy2.robjects.help` to expose the R help system to Python - Metaclass utilities in :mod:`rpy2.robjects.methods`, allowing to reflect automatically R S4 classes as Python classes. - :meth:`rpy2.robjects.vectors.FactorVector.iter_labels` to iterate over the labels - :class:`rpy2.robjects.vectors.ListVector` to represent R lists. - Constructor for :class:`rpy2.robjects.vectors.ListVector` and :class:`rpy2.robjects.vectors.DataFrame` accept any iterable at the condition that the elements iterated through also valid subscripts for it (e.g., given an iterable v, the following is valid: .. code-block:: python x[k] for x in v :mod:`rpy2.rinterface`: - :data:`NA_Complex` and :class:`NAComplexType` for missing complex values. - :class:`SexpExtPtr` to represent R objects of type EXTPTR (external pointers). - :func:`rpy2.rinterface.parse` to parse a string a R code - :func:`rpy2.rinterface.rternalise` to wrap Python function as :class:`SexpClosure` that can be called by R just as it was a function of its own. - :class:`rpy2.rinterface.RNULLType` for R's C-level NULL value and :class:`rpy2.rinterface.UnboundValueType` for R's C-level R_UnboundValue (both singletons). - :meth:`rinterface.SexpVector.index`, of similar behaviour to :meth:`list.index`. - :meth:`rpy2.rinterface.Sexp.list_attrs` to list the names of all R attributes for a given object. - :class:`rpy2.rinterface.ByteSexpVector` to represent R 'raw' vectors. - constant `R_LEN_T_MAX` to store what is the maximum length for a vector in R. - tuple `R_VERSION_BUILD` to store the version of R rpy2 was built against - getter :attr:`Sexp.rclass` to return the R class associated with an object :mod:`rpy2.rlike`: - :class:`container.OrdDict` get proper methods :meth:`keys` and `get` :mod:`rpy2.interactive`: - A new sub-package to provide utilities for interactive work, either for handling R interactive events or use Python for interactive programming (as often done with the R console) Changes ------- :mod:`rpy2.robjects`: - NA_bool, NA_real, NA_integer, NA_character and NA_complex are now deprecated (and removed). NA_Logical, NA_Real, NA_Integer, NA_Character, NA_Complex should be used. - :class:`rpy2.robjects.packages.Package` now inherits from :class:`types.ModuleType` - classes representing R vector also inherit their type-specific rinterface-level counterpart. - Importing the :class:`rpy2.robjects.numpy2ri` is no longer sufficient to active the conversion. Explicit activation is now needed; the function `activate` can do that. :mod:`rpy2.rinterface`: - :class:`IntSexpVector`, :class:`FloatSexpVector`, :class:`StrSexpVector`, :class:`BoolSexpVector`, :class:`ComplexSexpVector` are now defined at the C level, improving performances and memory footprint whenever a lot of instances are created. Bugs fixed ---------- - Better and more explicit detection system for needed libraries when compiling rpy2 (ported to release 2.1.6) - Long-standing issue with readline fixed (issue #10) Release 2.1.9 ============= Bugs fixed ---------- - The R class in rpy2.robjects is now truly a singleton - When using numpy 1.5 and Python >= 2.7, the exposed buffer for R numerical (double) vectors or arrays was wrong. Release 2.1.8 ============= Bugs fixed ---------- - Fixed issue with R arrays with more than 2 dimensions and numpy arrays (issue #47 - backported from the branch 2.2.x). Release 2.1.7 ============= Bugs fixed ---------- - More fixes for the automated detection of include and libraries at build time. Release 2.1.6 ============= Bugs fixed ---------- - Further fixes in the automatic detection of includes and libraries needed to compile rpy2 against R. The detection code has been refactored (backport from the 2.2.x branch) Release 2.1.5 ============= Bugs fixed ---------- - fixes the automatic detection of R_HOME/lib during building/compiling when R_HOME/lib is not in lib/ (issue #54) Release 2.1.4 ============= New features ------------ - :mod:`rpy2.robjects.lib.ggplot2` now has the functions :func:`limits`, :func:`xlim`, :func:`ylim` exposed (patch contributed anonymously) Bugs fixed ---------- - Install script when the BLAS library used by R is specified as a library file (patch by Michael Kuhn) Release 2.1.3 ============= Bugs fixed ---------- - Spurious error message when using DataFrame.from_csvfile() without specifying col_names or row_names - Patch to finally compile with Python < 2.6 (contribDuted by Denis Barbier) Release 2.1.2 ============= New Features ------------ :mod:`rpy2.robjects`: - NA_Logical, NA_Real, NA_Integer, NA_Character from :mod:`rpy2.rinterface` are imported by robjects. Changes ------- :mod:`rpy2.robjects`: - NA_bool, NA_real, NA_integer, NA_character and NA_complex are now robjects-level vectors (they were rinterface-level vectors). Consider using the rinterface-defined NAs instead of them. Bugs fixed ---------- - Missing conditional C definition to compile with Python 2.4 # issue 38 - Fixed error when calling robjects.vectors.Vector.iteritems() on an R vector without names - Fixed automatic conversion issues (issue #41) Release 2.1.1 ============= Bugs fixed ---------- - Issues with NA values # issue 37 - Missing manual scale functions in :mod:`rpy2.robjects.lib.ggplot2` # issue 39 Release 2.1.0 ============= New Features ------------ :mod:`rpy2.robjects`: - Method :meth:`formals` for :class:`Function` (formerly *RFunction*) - Methods :meth:`slotnames`, :meth:`isclass`, and :meth:`validobject` for :class:`RS4` - Vector-like objects now in a module :mod:`rpy2.robjects.vectors` - :func:`set_accessors` for adding simply accessors to a class inheriting from :class:`RS4` - :class:`RS4_Type` for metaclass-declared accessors - Delegating classes :class:`ExtractDelegator` and :class:`DoubleExtractDelegator` for extracting the R-way - :class:`DataFrame` (formerly *RDataFrame*) can now be created from :`rlike.container.OrdDict` instances, or any other object inheriting from dict. - :class:`FactorVector` to represent R factors - the conversion is now returning subclasses of :class:`robjects.vectors.Vector` -formerly *RVector*- (such as :class:`IntVector`, :class:`FloatVector`, etc...) rather than only return :class:`Vector` - :class:`StrVector` has a method :meth:`factor` to turn a vector of strings into an R factor - :class:`Matrix` was added the methods: :meth:`dot`, :meth:`svd`, :meth:`crossprod`, :meth:`tcrossprod`, :meth:`transpose`. - :meth:`IntVector.tabulate` to count the number of times a value is found in the vector - :meth:`Vector.sample` to draw a (random) sample of arbitrary size from a vector - :data:`NA_Bool`, :data:`NA_Real`, :data:`NA_Integer`, :data:`NA_Character`, :data:`NA_Complex` as aliases for R's missing values. - :data:`ComplexVector` for vectors of complex (real + imaginary) elements - :mod:`packages` to provide utility functions to handle R packages (import of R packages) - :mod:`functions` to provide classes related to R functions, with the new class :class:`SignatureTranslatedFunction` - :meth:`DataFrame.iter_row` and :meth:`DataFrame.iter_column`, iterating through rows and columns respectively. - :meth:`DataFrame.cbind` and :meth:`DataFrame.rbind` for binding columns or rows to a DataFrame. - :meth:`Vector.iteritems` to iterate on pairs of names and values. - :attr:`Robject.__rname__` to store the "R name" :mod:`rpy2.rinterface`: - New functions for specifying callback functions for R's front-ends: :func:`set_showmessage`, :func:`set_flushconsole`, :func:`set_choosefile`, :func:`set_showfiles` - New object :data:`MissingArg`, exposing R's special object for representing a "missing" parameter in a function call. (#this was first a patch by Nathaniel Smith with a function getMissingArgSexp) - Initial commit of a callback-based implementation of an R graphical device (this is for the moment very experimental - and not fully working) - :meth:`SexpClosure.rcall` is now taking 2 parameters, a tuple with the parameters and an :class:`SexpEnvironment` in which the call is to be evaluated. - :attr:`Sexp.__sexp__` now has a setter method. This permits the rebinding of the underlying R SEXP, and allows to expose `foo<-` type of R methods as Python function/methods with side effects. - Objects of R type RAWSXP are now exposed as instances of class :class:`SexpVector`. - Factory function :func:`unserialize` to build Sexp* instances from byte string serialized with R's own 'serialize'. - Method :meth:`Sexp.__reduce__` for pickling/unpickling - Ability to specify a callback function for R_CleanUp (called upon exiting R) through :func:`get_cleanup` and :func:`set_cleanup` [very experimental] - Class :class:`ListSexpVector` for creating R lists easily (complementing :class:`IntSexpVector`, :class:`StrSexpVector`, and friends) - :meth:`colnames`, :meth:`rownames` for :class:`Array` (formerly *RArray*) are now property-style getters - Pairlists (LISTSXP) now handled - Experimental function :func:`set_interactive` to set whether R is in interactive mode or not (#following an issue reported by Yaroslav Halchenko) - New object :data:`R_NilValue`, exposing R's special object for representing a "NULL". - :data:`ComplexSexpVector` for vectors of complex (real + imaginary) elements - Scalar Python parameters of type :class:`int`, :class:`long`, :class:`double`, :class:`bool`, and :class:`None` in a call (using :class:`SexpClosure`) are now automatically converted to length-one R vectors (at the exception of None, converted to R_NilValue). - Python slices can now be used on R vector-like objects - Better handling of R's missing values NA, `NA_integer_`, `NA_real_`, and `NA_character_`. :mod:`rpy2.rlike`: - :meth:`iteritems` for :class:`OrdDict` (formerly:class:`ArgDict`) and :class:`TaggedList` - static method :meth:`from_iteritems` for :class:`TaggedList`, for creating a TaggedList from any object having a method :meth:`iteritems` Changes ------- - The setup.py script is now taking command-line arguments when specifying R library-related paths are wished. python setup.py --help build_ext will list them :mod:`rpy2.robjects`: - RS4 no longer makes R's slots as Python attributes through :meth:`__attr__` - The package is split into modules - The broken variables NA_STRING, NA_INTEGER, NA_LOGICAL, and NA_REAL are removed. The documentation on missing values was revised. - :data:`globalEnv` and :data:`baseNameSpaceEnv` were renamed to :data:`globalenv` and :data:`baseenv` respectively - The parameter *wantFun* in :meth:`Environment.get` (formerly *REnvironment.get()*) is now *wantfun* - :attr:`Vector.r` does not have a __getitem__ method any longer (see in `.rx` and `.rx2` in the new features) - :meth:`colnames`, :meth:`rownames`, :meth:`nrow`, :meth:`ncol` for :class:`DataFrame` are now property-style getters - :meth:`nrow`, :meth:`ncol` for :class:`Array` are now property-style getters - static method :meth:`from_csvfile` and instance method :meth:`to_csvfile` for :class:`DataFrame` - module :mod:`lib` to store modules representing R packages - module :mod:`lib.ggplot2` for the CRAN package ggplot2. - renaming of few classes, the *R* prefix: :class:`Formula` (from *RFormula*), :class:`DataFrame` (from *RDataFrame*), :class:`Array` (from *RArray*), :class:`Matrix` (from *RMatrix*), :class:`Environment` (from *REnvironment*), :class:`Function` (from *RFunction*), :class:`Vector` (from *RVector*). - :class:`robjects.vectors.Vector` lost the (now redundant) methods `subset` and `assign`. Those operations were just aliases to the :class:`ExtractDelegator` :mod:`rpy2.rinterface`: - :data:`globalEnv`, :data:`baseNameSpaceEnv`, and :data:`emptyEnv` were renamed to :data:`globalenv`, :data:`baseenv` and :data:`emptyenv` respectively - The parameter *wantFun* in :meth:`SexpEnvironment.get` is now *wantfun* - The call-back getters and setters are now :func:`get_readconsole`, :func:`set_readconsole`, :func:`get_writeconsole`, :func:`set_writeconsole`, :func:`get_flushconsole`, and :func:`set_flushconsole`. - Functions also accept named parameters equal to Py_None, and transform them to R NULL (previously only accepted parameters inheriting from Sexp). :mod:`rpy2.rlike`: - :class:`ArgDict` becomes :class:`OrdDict`. - :meth:`tags` of :class:`TaggedList` is now a property (with a getter and a setter) :mod:`rpy2.rpy_classic`: - R named lists are returned as Python :class:`dict`, like rpy-1.x does it, with the notable difference that duplicate names are not silently overwritten: an exception of class :class:`ValueError` is thrown whenever happening Bugs fixed ---------- - :meth:`REnvironment.get` now accepts a named parameter *wantFun* (like :meth:`rinterface.SexpEnvironment` does) - :class:`rinterface.SexpVector` will now properly raise an exception when trying to create vector-like object of impossible type - Crash when trying to create a SexpVector of a non-vector type - R objects of class *matrix* are now properly converted into :class:`RMatrix` (instead of :class:`Array`) - :meth:`Robj.as_py` was not working at all (and now it does to some extent) Release 2.0.7 ============= Bugs fixed ---------- - On win32, printing an object was leaving an open file handle behind each time, leading to an error and the impossibility to print (# bug report and fix by Christopher Gutierrez) Release 2.0.6 ============= No user-visible change. Win32-specific additions to the C module were made to compile it. Release 2.0.5 ============= Bugs fixed ---------- - Crash when calling :meth:`SexpEnvironment.get` with an empty string #bug report by Walter Moreira - :meth:`SexpEnvironment.__getitem__` called with an empty string caused unpredictable (and bad) things Release 2.0.4 ============= Bugs fixed ---------- - Added missing named parameter *wantfun* to method :meth:`REnvironment.get` (making it similar to :meth:`SexpEnvironment.get`) - Leak in reference counting when creating SexpVector objects fixed (the symptom was a process growing in size when creating R vector from Python list or numpy arrays) - `R CMD config LAPACK_LIBS` could return an empty string when R was compiled with the veclib framework, causing the setup.py script to raise an exception. setup.py now only print a message about an empty string returned from R CMD config - Numpy arrays with complex elements are no longer causing segfaults - Calls to :meth:`SexpClosure.rcall` with something else that the expected kind of tuple could cause a segfault Release 2.0.3 ============= New Features ------------ :mod:`rpy2.rinterface`: - :meth:`process_revents`, a Wrapper for R_ProcessEvents (# suggested by June Kim to help with issues related to interactive display on win32), and for R_RunHandlers on UNIX-like systems (# patch by Nathaniel Smith). - All callbacks are getting a get to complement the set. (# Patch by Nathaniel Smith) - :meth:`Sexp.__deepcopy__` to copy an object (calling Rf_Duplicate) (# from a patch by Nathaniel Smith) Changes ------- - the default for reading and writing the console are now using sys.stdin and sys.stdout (# patch submitted by Nathaniel Smith) - console IO callbacks (reading and writing) are complemented by one to flush the console - :meth:`Sexp.do_slot_assign` now creates the slot if missing (design-fix - # patch by Nathaniel Smith) Bugs fixed ---------- - fixed problem of numpy interface with R boolean vectors. They are now presented as 'i' rather than 'b' to numpy (# patch submitted by Nathaniel Smith) - The mechanism for setting arbitrary callaback functions for console I/O now ensures that a traceback is printed to stderr whenever an error occurs during the evalutation of the callback (the raised exception used to be silently propagated to the next python call, leading to problems). Release 2.0.2 ============= Bugs fixed ---------- - Fix installation bug when the include directories contain either '-' or 'I' #spotted by James Yoo - Failing to initialize R now throws a RuntimeError - Copying an R "NA" into Python returns a None (and no longer a True) (#fixes a bug reported by Jeff Gentry) Release 2.0.1 ============= New features ------------ :mod:`rpy2.robjects`: - Property `names` for the :class:`RVector` methods :meth:`getnames` and :meth:`setnames` (this was likely forgotten for Release 2.0.0). - Property `rclass` for :class:`RObjectMixin` Changes ------- :mod:`rpy2.robjects`: - :meth:`rclass` becomes :meth:`getrclass` Bugs fixed ---------- - Having the environment variable R_HOME specified resulted in an error when importing :mod:`rpy2.rinterface` # root of the problem spotted by Peter - Setup.py has no longer a (possibly outdated) static hardcoded version number for rpy2 - Testing no longer stops with an error in the absence of the third-party module :mod:`numpy` - :meth:`rpy2.rlike.container.TaggedList.pop` is now returning the element matching the given index Release 2.0.0 ============= New features ------------ - New module :mod:`rpy2.robjects.conversion`. - New module :mod:`rpy2.robjects.numpy2ri` to convert :mod:`numpy` objects into :mod:`rpy2` objects. # adapted from a patch contributed by Nathaniel Smith Changes ------- - :meth:`RObject.__repr__` moved to :meth:`RObject.r_repr` Bugs fixed ---------- - Informative message returned as RuntimeError when failing to find R's HOME - Use the registry to find the R's HOME on win32 # snatched from Peter's earlier contribution to rpy-1.x Release 2.0.0rc1 ================ :mod:`rpy2.rpy_classic`: - :meth:`rpy_classic.RObj.getSexp` moved to a property :attr:`rpy_classic.Robj.sexp`. :mod:`rpy2.robjects`: - :meth:`RObject.__repr__` moved to :meth:`RObject.r_repr` - :meth:`ri2py`, :meth:`ro2py`, and :meth:`py2ri` moved to the new module :mod:`conversion`. Adding the prefix `conversion.` to calls to those functions will be enough to update existing code Bugs fixed ---------- - Informative message returned as RuntimeError when failing to find R's HOME - Use the registry to find the R's HOME on win32 # snatched from Peter's earlier contribution to rpy-1.x Release 2.0.0rc1 ================ New features ------------ - added :data:`__version__` to rpy2/__init__.py :mod:`rpy2.robjects`: - added classes :class:`StrVector`, :class:`IntVector`, :class:`FloatVector`, :class:`BoolVector` :mod:`rpy2.rinterface`: - added missing class :class:`BoolSexpVector`. Changes ------- :mod:`rpy2.robjects`: - does not alias :class:`rinterface.StrSexpVector`, :class:`rinterface.IntSexpVector`, :class:`rinterface.FloatSexpVector` anymore - Constructor for :class:`rpy2.robjects.RDataFrame` checks that R lists are data.frames (not all lists are data.frame) - Formerly new attribute :attr:`_dotter` for :class:`R` is now gone. The documentaion now points to :mod:`rpy2.rpy_classic` for this sort of things. Bugs fixed ---------- - conditional typedef in rinterface.c to compile under win32 # reported and initial proposed fix from Paul Harrington - __pow__ was missing from the delegator object for robjects.RVector (while the documentation was claiming it was there) # bug report by Robert Nuske - Earlier change from Sexp.typeof() to getter Sexp.typeof was not reflected in :mod:`rpy2.rpy_classic` # bug report by Robert Denham Release 2.0.0b1 =============== New features ------------ :mod:`rpy2.robjects`: - added :meth:`setenvironment` for :class:`RFormula`, and defined `environment` as a property - defined `names` as a property for :class:`RVector` :mod:`rpy2.rinterface`: - added functions :func:`get_initoptions` and :func:`set_initoptions`. - new attribute :attr:`_dotter` for :class:`R` singleton. Setting it to True will translate '_' into '.' if the attribute is not found Changes ------- :mod:`rpy2.robjects`: - constructor for RDataFrame now now accepts either :class:`rlike.container.TaggedList` or :class:`rinterface.SexpVector` :mod:`rpy2.rinterface`: - :func:`sexpTypeEmbeddedR` is now called :func:`str_typeint`. - :attr:`initOptions` is now called :attr:`initoptions`. Changes of options can only be done through :func:`set_initoptions`. Bugs fixed ---------- - crash of :meth:`Sexp.enclos` when R not yet initialized (bug report #2078176) - potential crash of :meth:`Sexp.frame` when R not yet initialized - proper reference counting when handling, and deleting, :attr:`Sexp.__sexp__` generated CObjects - setup.py: get properly the include directories (no matter where they are) #bug report and fix adapted from Robert Nuske - setup.py: link to external lapack or blas library when relevant - added a MANIFEST.in ensuring that headers get included in the source distribution #missing headers reported by Nicholas Lewin-Koh - :func:`rinterface.str_typeint` was causing segfault when called with 99 - fixed subsetting for LANGSXP objects Release 2.0.0a3 =============== New features ------------ :mod:`rpy2.rinterface`: - :func:`setReadConsole`: specify Python callback for console input - `R` string vectors can now be built from Python unicode objects - getter :attr:`__sexp__` to return an opaque C pointer to the underlying R object - method :meth:`rsame` to test if the underlying R objects for two :class:`Sexp` are the same. - added `emptyEnv` (R's C-level `R_EmptyEnv`) - added method :meth:`Sexp.do_slot_assign` :mod:`rpy2.robjects`: - R string vectors can now be built from Python unicode objects :mod:`rpy2.rlike`: - module :mod:`functional` with the functions :func:`tapply`, :func:`listify`, :func:`iterify`. - module :mod:`indexing` with the function :func:`order` - method :meth:`TaggedList.sort` now implemented Changes ------- :mod:`rpy2.rinterface`: - :func:`initEmbeddedR` is only initializing if R is not started (no effect otherwise, and no exception thrown anymore) - the method :meth:`Sexp.typeof` was replaced by a Python `getter` :attr:`typeof`. - the method :meth:`Sexp.named` was replaced by a Python `getter` :attr:`named`. - R objects of type LANGSXP are now one kind of vector (... but this may change again) - R objects of type EXPRSXP are now handled as vectors (... but this may change again) - :func:`initEmbeddedR` renamed to :func:`initr` - :func:`endEmbeddedR` renamed to :func:`endr` :mod:`rpy2.robjects`: - :class:`R` remains a singleton, but does not throw an exception when multiple instances are requested Bugs fixed ---------- - unable to compile on Python2.4 (definition of aliases to Python2.5-specific were not where they should be). - overflow issues on Python 2.4/64 bits when indexing R vector with very large integers. - handling of negative indexes for :class:`SexpVector`'s :meth:`__getitem__` and :meth:`__setitem__` was missing - trying to create an instance of :class:`SexpVector` before initializing R raises a RuntimeException (used to segfault) - experimental method :meth:`enclos` was not properly exported - setup.py was exiting prematurely when R was compiled against an existing BLAS library - complex vectors should now be handled properly by :mod:`rpy2.rinterface.robjects`. - methods :meth:`rownames` and :meth:`colnames` for :class:`RDataFrame` were incorrect. Release 2.0.0a2 =============== New features ------------ :mod:`rpy2.rlike`: - package for R-like features in Python - module :mod:`rpy2.rlike.container` - class :class:`ArgsDict` in :mod:`rpy2.rlike.container` - class :class:`TaggedList` in :mod:`rpy2.rlike.container` :mod:`rpy2.rinterface`: - method :meth:`named`, corresponding to R's C-level NAMED - experimental methods :meth:`frame` and :meth:`enclos` for SexpEnvironment corresponding to R's C-level FRAME and ENCLOS - method :meth:`rcall` for :class:`ClosureSexp` - new experimental class :class:`SexpLang` for R language objects. Bugs fixed ---------- - R stack checking is disabled (no longer crashes when multithreading) - fixed missing R_PreserveObject for vectors (causing R part of the object to sometimes vanish during garbage collection) - prevents calling an R function when R has been ended (raise :class:`RuntimeException`). Release 2.0.0a1 =============== New features ------------ :mod:`rpy2.robjects`: - method :meth:`getnames` for :class:`RVector` - experimental methods :meth:`__setitem__` and :meth:`setnames` for :class:`RVector` - method 'getnames' for :class:`RArray` - new class :class:`RFormula` - new helper class :class:`RVectorDelegator` (see below) - indexing RVector the "R way" with subset is now possible through a delegating attribute (e.g., myvec.r[True] rather than myvec.subset(True)). #suggested by Michael Sorich - new class :class:`RDataFrame`. The constructor :meth:`__init__` is still experimental (need for an ordered dictionnary, that will be in before the beta - filled documentation about mapping between objects Changes ------- - many fixes and additions to the documentation - improved GTK console in the demos - changed the major version number to 2 in order to avoid confusion with rpy 1.x # Suggested by Peter and Gregory Warnes - moved test.py to demos/example01.py :mod:`rpy2.robjects`: - changed method name `getNames` to `getnames` where available (all lower-case names for methods seems to be the accepted norm in Python). Bugs fixed ---------- :mod:`rpy2.robjects`: - fixed string representation of R object on Microsoft Windows (using fifo, not available on win32) - :meth:`__getattr__` for :class:`RS4` is now using :meth:`ri2py` :mod:`rpy2.rinterface`: - fixed context of evaluation for R functions (now R_GlobalEnv) Release 1.0a0 ============= - first public release