rpy2-2.7.8/0000775000175000017500000000000012654242632013602 5ustar laurentlaurent00000000000000rpy2-2.7.8/PKG-INFO0000664000175000017500000000112512654242632014676 0ustar laurentlaurent00000000000000Metadata-Version: 1.1 Name: rpy2 Version: 2.7.8 Summary: Python interface to the R language (embedded R) Home-page: http://rpy.sourceforge.net Author: Laurent Gautier Author-email: lgautier@gmail.com License: GPLv2+ Description: UNKNOWN Platform: UNKNOWN Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 3 Classifier: License :: OSI Approved :: GNU General Public License v2 or later (GPLv2+) Classifier: Intended Audience :: Developers Classifier: Intended Audience :: Science/Research Classifier: Development Status :: 5 - Production/Stable Requires: six rpy2-2.7.8/MANIFEST.in0000664000175000017500000000243312610501355015332 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/ipython *.py recursive-include rpy/interactive *.py recursive-include rpy/rlike *.py prune dist include doc/Makefile include doc/source/rpy2_logo.png rpy2-2.7.8/setup.py0000775000175000017500000003206312610501355015313 0ustar laurentlaurent00000000000000#!/usr/bin/env python import os, os.path, sys, shutil, re, itertools, warnings import argparse, shlex, subprocess from collections import namedtuple from setuptools import setup, Extension from setuptools.command.build_ext import build_ext as _build_ext pack_name = 'rpy2' pack_version = __import__('rpy').__version__ package_prefix='.' def _get_r_home(r_bin = "R"): if (os.getenv('R_ENVIRON') is not None) or (os.getenv('R_ENVIRON_USER') is not None): warnings.warn("The environment variable R_ENVIRON or R_ENVIRON_USER is set. Differences between their settings during build time and run time may lead to issues when using rpy2.") try: r_home = subprocess.check_output((r_bin, "RHOME"), universal_newlines=True) except: raise SystemExit("Error: Tried to guess R's HOME but no command (%s) in the PATH." % r_bin) r_home = r_home.split(os.linesep) #Twist if 'R RHOME' spits out a warning if r_home[0].startswith("WARNING"): warnings.warn("R emitting a warning: %s" % r_home[0]) r_home = r_home[1].rstrip() else: r_home = r_home[0].rstrip() if os.path.exists(os.path.join(r_home, 'Renviron.site')): warnings.warn("The optional file '%s' is defined. Modifying it between build time and run time may lead to issues when using rpy2." % os.path.join(r_home, 'Renviron.site')) return r_home 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 + \ [ ('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): try: super(build_ext, self).initialize_options() except TypeError: # distutils parent class an old style Python class _build_ext.initialize_options(self) self.r_autoconfig = None self.r_home = None self.r_home_lib = None self.ignore_check_rversion = False def finalize_options(self): self.set_undefined_options('build') r_home = _get_r_home() rexec = RExec(r_home) if rexec.version[0] == 'development' or \ cmp_version(rexec.version[: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(rexec.version)) try: super(build_ext, self).finalize_options() except TypeError: # distutils parent class an old style Python class _build_ext.finalize_options(self) def run(self): try: super(build_ext, self).run() except TypeError: # distutils parent class an old style Python class _build_ext.run(self) 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 RExec(object): """ Compilation-related configuration parameters used by R. """ def __init__(self, r_home): if sys.platform == "win32" and "64 bit" in sys.version: r_exec = os.path.join(r_home, 'bin', 'x64', 'R') else: r_exec = os.path.join(r_home, 'bin', 'R') self._r_exec = r_exec self._version = None @property def version(self): if self._version is not None: return self._version output = subprocess.check_output((self._r_exec, '--version'), universal_newlines = True) if not output: # sometimes R output goes to stderr output = subprocess.check_output((self._r_exec, '--version'), stderr = subprocess.STDOUT, universal_newlines = True) output = iter(output.split('\n')) rversion = next(output) #Twist if 'R --version' spits out a warning if rversion.startswith("WARNING"): warnings.warn("R emitting a warning: %s" % rversion) rversion = next(output) print(rversion) m = re.match('^R ([^ ]+) ([^ ]+) .+$', rversion) if m is None: warnings.warn("Unable to extract R's version number from the string: '%s'" % rversion) # return dummy version 0.0 rversion = [0, 0] else: rversion = m.groups()[1] if m.groups()[0] == 'version': rversion = [int(x) for x in rversion.split('.')] else: rversion = ['development', ''] self._version = rversion return self._version def cmd_config(self, about, allow_empty=False): cmd = (self._r_exec, 'CMD', 'config', about) print(subprocess.list2cmdline(cmd)) output = subprocess.check_output(cmd, universal_newlines = True) output = output.split(os.linesep) #Twist if 'R RHOME' spits out a warning if output[0].startswith("WARNING"): warnings.warn("R emitting a warning: %s" % output[0]) output = output[1:] return output def getRinterface_ext(): extra_link_args = [] extra_compile_args = [] include_dirs = [] libraries = [] library_dirs = [] #FIXME: crude way (will break in many cases) #check how to get how to have a configure step define_macros = [] if sys.platform == 'win32': define_macros.append(('Win32', 1)) if "64 bit" in sys.version: define_macros.append(('Win64', 1)) extra_link_args.append('-m64') extra_compile_args.append('-m64') # MS_WIN64 only defined by pyconfig.h for MSVC. # See http://bugs.python.org/issue4709 define_macros.append(('MS_WIN64', 1)) else: define_macros.append(('R_INTERFACE_PTRS', 1)) define_macros.append(('HAVE_POSIX_SIGJMP', 1)) define_macros.append(('RIF_HAS_RSIGHAND', 1)) define_macros.append(('CSTACK_DEFNS', 1)) define_macros.append(('HAS_READLINE', 1)) if sys.byteorder == 'big': define_macros.append(('RPY_BIGENDIAN', 1)) else: pass r_home = _get_r_home() rexec = RExec(r_home) if rexec.version[0] == 'development' or \ cmp_version(rexec.version[:2], [3, 2]) == -1: warnings.warn("R did not seem to have the minimum required version number") ldf = shlex.split(' '.join(rexec.cmd_config('--ldflags'))) cppf = shlex.split(' '.join(rexec.cmd_config('--cppflags'))) #lapacklibs = rexec.cmd_config('LAPACK_LIBS', True) #blaslibs = rexec.cmd_config('BLAS_LIBS', True) parser = argparse.ArgumentParser() parser.add_argument('-I', action='append') parser.add_argument('-L', action='append') parser.add_argument('-l', action='append') # compile args, unknown = parser.parse_known_args(cppf) if args.I is None: warnings.warn('No include specified') else: include_dirs.extend(args.I) extra_compile_args.extend(unknown) # link args, unknown = parser.parse_known_args(ldf) # OS X's frameworks need special attention if args.L is None: # presumably OS X and framework: if args.l is None: # hmmm... no libraries at all warnings.warn('No libraries as -l arguments to the compiler.') else: libraries.extend([x for x in args.l if x != 'R']) else: library_dirs.extend(args.L) libraries.extend(args.l) extra_link_args.extend(unknown) print(""" Compilation parameters for rpy2's C components: include_dirs = %s library_dirs = %s libraries = %s extra_link_args = %s """ % (str(include_dirs), str(library_dirs), str(libraries), str(extra_link_args))) rinterface_ext = Extension( name = pack_name + '.rinterface._rinterface', sources = [os.path.join(package_prefix, 'rpy', 'rinterface', '_rinterface.c') ], depends = [os.path.join(package_prefix, 'rpy', 'rinterface', 'embeddedr.h'), os.path.join(package_prefix, 'rpy', 'rinterface', 'r_utils.h'), os.path.join(package_prefix, 'rpy', 'rinterface', 'buffer.h'), os.path.join(package_prefix, 'rpy', 'rinterface', 'sequence.h'), os.path.join(package_prefix, 'rpy', 'rinterface', 'sexp.h'), os.path.join(package_prefix, 'rpy', 'rinterface', '_rinterface.h'), os.path.join(package_prefix, 'rpy', 'rinterface', 'rpy_device.h') ], include_dirs = [os.path.join(package_prefix, 'rpy', 'rinterface'),] + include_dirs, libraries = libraries, library_dirs = library_dirs, define_macros = define_macros, runtime_library_dirs = library_dirs, extra_compile_args=extra_compile_args, extra_link_args = extra_link_args ) rpy_device_ext = Extension( pack_name + '.rinterface._rpy_device', [ os.path.join(package_prefix, 'rpy', 'rinterface', '_rpy_device.c'), ], include_dirs = include_dirs + [os.path.join('rpy', 'rinterface'), ], libraries = libraries, library_dirs = library_dirs, define_macros = define_macros, runtime_library_dirs = library_dirs, extra_compile_args=extra_compile_args, extra_link_args = extra_link_args ) return [rinterface_ext, rpy_device_ext] if __name__ == '__main__': rinterface_exts = [] ri_ext = getRinterface_ext() rinterface_exts.extend(ri_ext) pack_dir = {pack_name: os.path.join(package_prefix, 'rpy')} #import setuptools.command.install #for scheme in setuptools.command.install.INSTALL_SCHEMES.values(): # scheme['data'] = scheme['purelib'] requires=['six', ] if sys.version_info[0] < 3 or (sys.version_info[0] == 3 and sys.version_info[1] < 4): requires.append('singledispatch') # additional C library included in rpy2 libraries = list() libraries.append(('r_utils', dict(sources = [os.path.join(package_prefix, 'rpy', 'rinterface', 'r_utils.c')], include_dirs = ri_ext[0].include_dirs, language = 'c'))) setup( cmdclass = {'build_ext': build_ext}, name = pack_name, version = pack_version, description = "Python interface to the R language (embedded R)", url = "http://rpy.sourceforge.net", license = "GPLv2+", author = "Laurent Gautier", author_email = "lgautier@gmail.com", requires = requires, install_requires = requires, ext_modules = rinterface_exts, libraries = libraries, package_dir = pack_dir, packages = [pack_name, pack_name + '.rlike', pack_name + '.rlike.tests', pack_name + '.rinterface', pack_name + '.rinterface.tests', pack_name + '.robjects', pack_name + '.robjects.tests', pack_name + '.robjects.lib', pack_name + '.robjects.lib.tests', pack_name + '.interactive', pack_name + '.interactive.tests', pack_name + '.ipython', pack_name + '.ipython.tests' ], classifiers = ['Programming Language :: Python', 'Programming Language :: Python :: 3', 'License :: OSI Approved :: GNU General Public License v2 or later (GPLv2+)', 'Intended Audience :: Developers', 'Intended Audience :: Science/Research', 'Development Status :: 5 - Production/Stable' ], package_data = { 'rpy2': ['images/*.png', ], 'rpy2': ['doc/source/rpy2_logo.png', ]} ) rpy2-2.7.8/doc/0000775000175000017500000000000012654242632014347 5ustar laurentlaurent00000000000000rpy2-2.7.8/doc/Makefile0000664000175000017500000002001612617761637016020 0ustar laurentlaurent00000000000000# Makefile for Sphinx documentation # # You can set these variables from the command line. SPHINXOPTS = SPHINXBUILD = sphinx-build PAPER = BUILDDIR = _build # User-friendly check for sphinx-build ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) $(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) endif # Internal variables. PAPEROPT_a4 = -D latex_paper_size=a4 PAPEROPT_letter = -D latex_paper_size=letter ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . # the i18n builder cannot share the environment and doctrees with the others I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext 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 " singlehtml to make a single large HTML file" @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 " devhelp to make HTML files and a Devhelp project" @echo " epub to make an epub" @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" @echo " latexpdf to make LaTeX files and run them through pdflatex" @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" @echo " text to make text files" @echo " man to make manual pages" @echo " texinfo to make Texinfo files" @echo " info to make Texinfo files and run them through makeinfo" @echo " gettext to make PO message catalogs" @echo " changes to make an overview of all changed/added/deprecated items" @echo " xml to make Docutils-native XML files" @echo " pseudoxml to make pseudoxml-XML files for display purposes" @echo " linkcheck to check all external links for integrity" @echo " doctest to run all doctests embedded in the documentation (if enabled)" @echo " rpy2demo_graphics to build the figures used in the documentation about graphics" @echo " rpy2demo_benchmark to build the figure(s) used in the documentation about benchmarks" @echo " notebooks to build the ipython notebooks used in the documentation" clean: rm -rf $(BUILDDIR)/* rpy2demo_benchmark: @cd _static/demos && python benchmarks.py rpy2demo_graphics: @cd _static/demos && python graphics.py rpy2demo_all: rpy2demo_graphics rpy2demo_benchmark # rule to build ipython notebooks from markdown notebooks/%.ipynb : notebooks/%.md notedown \ --precode 'from functools import partial' \ 'from rpy2.ipython import html' \ 'html.html_rdataframe=partial(html.html_rdataframe, table_class="docutils")' \ --run \ -o $@ \ $< cp $@ _static/notebooks/ # rule to build sphinx-friendly ReST from ipython notebooks notebooks/%.rst : notebooks/%.ipynb @cd generated_rst && ipython nbconvert --to rst ../$< # rule to build HTML render of an ipython notebook _static/notebooks/%.html : notebooks/%.ipynb ipython nbconvert --to html $< --output $@ MD_NOTEBOOKS := $(basename $(notdir $(wildcard notebooks/*.md))) _notebooks: $(MD_NOTEBOOKS:%=notebooks/%.rst) _notebooks_html: $(MD_NOTEBOOKS:%=_static/notebooks/%.html) notebooks: @echo "Building IPython notebooks from markdown..." mkdir -p _static/notebooks _notebooks _notebooks_html html: $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." dirhtml: $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." singlehtml: $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml @echo @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." pickle: $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle @echo @echo "Build finished; now you can process the pickle files." json: $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json @echo @echo "Build finished; now you can process the JSON files." htmlhelp: $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp @echo @echo "Build finished; now you can run HTML Help Workshop with the" \ ".hhp project file in $(BUILDDIR)/htmlhelp." qthelp: $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp @echo @echo "Build finished; now you can run "qcollectiongenerator" with the" \ ".qhcp project file in $(BUILDDIR)/qthelp, like this:" @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/rpy2.qhcp" @echo "To view the help file:" @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/rpy2.qhc" devhelp: $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp @echo @echo "Build finished." @echo "To view the help file:" @echo "# mkdir -p $$HOME/.local/share/devhelp/rpy2" @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/rpy2" @echo "# devhelp" epub: $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub @echo @echo "Build finished. The epub file is in $(BUILDDIR)/epub." latex: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." @echo "Run \`make' in that directory to run these through (pdf)latex" \ "(use \`make latexpdf' here to do that automatically)." latexpdf: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo "Running LaTeX files through pdflatex..." $(MAKE) -C $(BUILDDIR)/latex all-pdf @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." latexpdfja: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo "Running LaTeX files through platex and dvipdfmx..." $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." text: $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text @echo @echo "Build finished. The text files are in $(BUILDDIR)/text." man: $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man @echo @echo "Build finished. The manual pages are in $(BUILDDIR)/man." texinfo: $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo @echo @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." @echo "Run \`make' in that directory to run these through makeinfo" \ "(use \`make info' here to do that automatically)." info: $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo @echo "Running Texinfo files through makeinfo..." make -C $(BUILDDIR)/texinfo info @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." gettext: $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale @echo @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." changes: $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes @echo @echo "The overview file is in $(BUILDDIR)/changes." linkcheck: $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck @echo @echo "Link check complete; look for any errors in the above output " \ "or in $(BUILDDIR)/linkcheck/output.txt." doctest: $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest @echo "Testing of doctests in the sources finished, look at the " \ "results in $(BUILDDIR)/doctest/output.txt." xml: $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml @echo @echo "Build finished. The XML files are in $(BUILDDIR)/xml." pseudoxml: $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml @echo @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." rpy2-2.7.8/doc/generated_rst/0000775000175000017500000000000012654242632017175 5ustar laurentlaurent00000000000000rpy2-2.7.8/doc/generated_rst/README0000664000175000017500000000007112602105320020034 0ustar laurentlaurent00000000000000This directory contains rst files dynamically generated.rpy2-2.7.8/README.rst0000664000175000017500000000372612610501355015271 0ustar laurentlaurent00000000000000This is the source tree or distribution for the rpy2 package. .. image:: https://drone.io/bitbucket.org/rpy2/rpy2/status.png :target: https://drone.io/bitbucket.org/rpy2/rpy2/latest .. image:: https://img.shields.io/pypi/v/rpy2.svg?style=flat-square :target: https://pypi.python.org/pypi/rpy2 Installation ============ `pip` should work out of the box: pip install rpy2 The package is known to compile on Linux, MacOSX, and Windows (provided that developper tools installed are you are ready figure out how yourself). In case you find yourself with this source without any idea of what it takes to compile anything on your platform, try first python setup.py install If this fails, consider looking for pre-compiled binaries (they are available on Linux Red Hat, CentOS, Debian, Ubuntu, etc...) or using the matching Docker container. Note that `python setup.py develop` will appear to work, but will result in an installation from the `rpy` directory here. The namespaces will be incorrect, so don't do that! Documentation ============= Documentation is available either in the source tree (to be built), or online (see the rpy home page on sourceforge). Testing ======= The testing machinery uses the new unittest functionality, requiring python 2.7+ (or potentially the backported unittest2 library for older python, but this is not supported). The test suite can be run (once rpy2 is installed) as follows: python -m rpy2.tests By providing an argument, like "-v", you'll get verbose output. Individual tests can be run as follows: python -m unittest rpy2.robjects.tests.testVector Test discovery can be attempted as follows (not that it may not work): python -m unittest discover rpy2.robjects Prefer `python -m rpy2.tests` to run all tests. License ======= RPy2 can be used under the terms of either the GNU General Public License Version 2 or later (see the file gpl-2.0.txt).rpy2-2.7.8/rpy/0000775000175000017500000000000012654242632014414 5ustar laurentlaurent00000000000000rpy2-2.7.8/rpy/rpy_classic.py0000664000175000017500000002002012610501355017263 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.7.8/rpy/__init__.py0000664000175000017500000000022312654236076016527 0ustar laurentlaurent00000000000000 __version_vector__ = ((2,7,8), '') __version__ = '.'.join([str(x) for x in __version_vector__[0]]) + \ '' + __version_vector__[1] rpy2-2.7.8/rpy/robjects/0000775000175000017500000000000012654242632016227 5ustar laurentlaurent00000000000000rpy2-2.7.8/rpy/robjects/pandas2ri.py0000664000175000017500000001267212646327734020504 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 import pandas from numpy import recarray import numpy from collections import OrderedDict from rpy2.robjects.vectors import (DataFrame, Vector, ListVector, StrVector, IntVector, POSIXct) from rpy2.rinterface import (IntSexpVector, ListSexpVector) original_converter = None # pandas is requiring numpy. We add the numpy conversion will be # activate in the function activate() below import rpy2.robjects.numpy2ri as numpy2ri ISOdatetime = rinterface.baseenv['ISOdatetime'] as_vector = rinterface.baseenv['as.vector'] converter = conversion.Converter('original pandas conversion') py2ri = converter.py2ri py2ro = converter.py2ro ri2py = converter.ri2py ri2ro = converter.ri2ro @py2ri.register(PandasDataFrame) def py2ri_pandasdataframe(obj): od = OrderedDict() for name, values in obj.iteritems(): if values.dtype.kind == 'O': od[name] = StrVector(values) else: od[name] = conversion.py2ri(values) return DataFrame(od) @py2ri.register(PandasIndex) def py2ri_pandasindex(obj): if obj.dtype.kind == 'O': return StrVector(obj) else: # pandas2ri should definitely not have to know which paths remain to be # converted by numpy2ri # Answer: the thing is that pandas2ri builds on the conversion # rules defined by numpy2ri - deferring to numpy2ri is allowing # us to reuse that code. return numpy2ri.numpy2ri(obj) @py2ri.register(PandasSeries) def py2ri_pandasseries(obj): if obj.dtype == ' 1: raise ValueError('Currently unable to handle more than one class per object') for rclsname in robj.rclass: rcls = _getclass(rclsname) return rcls(robj) if clslist is None: return robj methods_env = rinterface.baseenv.get('as.environment')(StrSexpVector(('package:methods', ))) rpy2-2.7.8/rpy/robjects/__init__.py0000664000175000017500000002340212654236076020346 0ustar laurentlaurent00000000000000""" R objects as Python objects. The module is structured around the singleton r of class R, that represents an embedded R. License: GPLv3.0 (although a dual license can be worked out) """ import os, sys import array import itertools from datetime import datetime import rpy2.rinterface as rinterface import rpy2.rlike.container as rlc from rpy2.robjects.robject import RObjectMixin, RObject from rpy2.robjects.vectors import (BoolVector, IntVector, FloatVector, ComplexVector, StrVector, FactorVector, Vector, ListVector, DateVector, POSIXct, POSIXlt, Array, Matrix, DataFrame) from rpy2.robjects.functions import Function, SignatureTranslatedFunction from rpy2.robjects.environments import Environment from rpy2.robjects.methods import RS4 from . import conversion from rpy2.rinterface import (Sexp, SexpVector, SexpClosure, SexpEnvironment, SexpS4, StrSexpVector, SexpExtPtr) _globalenv = rinterface.globalenv # missing values from rpy2.rinterface import (NA_Real, NA_Integer, NA_Logical, NA_Character, NA_Complex, NULL) if sys.version_info[0] == 2: py3str = unicode py3bytes = str import itertools zip = itertools.izip else: long = int py3str = str py3bytes = bytes _rparse = rinterface.baseenv['parse'] _reval = rinterface.baseenv['eval'] 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 default_converter = conversion.Converter('base empty converter') @default_converter.ri2ro.register(RObject) def _(obj): return obj def sexpvector_to_ro(obj): try: rcls = obj.do_slot("class") except LookupError as le: rcls = [None] if 'data.frame' in rcls: res = vectors.DataFrame(obj) return res try: dim = obj.do_slot("dim") if len(dim) == 2: res = vectors.Matrix(obj) else: res = vectors.Array(obj) except LookupError as le: if obj.typeof == rinterface.INTSXP: if 'factor' in rcls: res = vectors.FactorVector(obj) else: res = vectors.IntVector(obj) elif obj.typeof == rinterface.REALSXP: if obj.rclass[0] == 'POSIXct': res = vectors.POSIXct(obj) else: res = vectors.FloatVector(obj) elif obj.typeof == rinterface.LGLSXP: res = vectors.BoolVector(obj) elif obj.typeof == rinterface.STRSXP: res = vectors.StrVector(obj) elif obj.typeof == rinterface.VECSXP: res = vectors.ListVector(obj) elif obj.typeof == rinterface.LANGSXP and 'formula' in rcls: res = Formula(obj) else: res = vectors.Vector(obj) return res default_converter.ri2ro.register(SexpVector, sexpvector_to_ro) TYPEORDER = {bool: (0, BoolVector), int: (1, IntVector), float: (2, FloatVector), complex: (3, ComplexVector), str: (4, StrVector)} def sequence_to_vector(lst): curr_typeorder = -1 for i, elt in enumerate(lst): cls = type(elt) if cls in TYPEORDER: if TYPEORDER[cls][0] > curr_typeorder: curr_typeorder, curr_type = TYPEORDER[cls] else: raise ValueError('The element %i in the list has a type that cannot be handled.' % i) res = curr_type(lst) return res @default_converter.ri2ro.register(SexpClosure) def _(obj): return SignatureTranslatedFunction(obj) @default_converter.ri2ro.register(SexpEnvironment) def _(obj): return Environment(obj) @default_converter.ri2ro.register(SexpS4) def _(obj): return RS4(obj) @default_converter.ri2ro.register(SexpExtPtr) def _(obj): return obj @default_converter.ri2ro.register(object) def _(obj): return RObject(obj) @default_converter.ri2ro.register(type(NULL)) def _(obj): return obj def default_py2ri(o): """ Convert an arbitrary Python object to a :class:`rpy2.rinterface.Sexp` object. Creates an R object with the content of the Python object, wich means data copying. :param o: object :rtype: :class:`rpy2.rinterface.Sexp` (and subclasses) """ pass @default_converter.py2ri.register(RObject) def _(obj): return rinterface.Sexp(obj) @default_converter.py2ri.register(Sexp) def _(obj): return obj @default_converter.py2ri.register(array.array) def _(obj): if obj.typecode in ('h', 'H', 'i', 'I'): res = rinterface.SexpVector(obj, rinterface.INTSXP) elif obj.typecode in ('f', 'd'): res = rinterface.SexpVector(obj, rinterface.REALSXP) else: raise(ValueError("Nothing can be done for this array type at the moment.")) return res @default_converter.py2ri.register(bool) def _(obj): return rinterface.SexpVector([obj, ], rinterface.LGLSXP) def int2ri(obj): # special case for NA_Logical if obj is rinterface.NA_Logical: res = rinterface.SexpVector([obj, ], rinterface.LGLSXP) else: res = rinterface.SexpVector([obj, ], rinterface.INTSXP) return res default_converter.py2ri.register(int, int2ri) default_converter.py2ri.register(long, int2ri) @default_converter.py2ri.register(float) def _(obj): return rinterface.SexpVector([obj, ], rinterface.REALSXP) @default_converter.py2ri.register(py3bytes) def _(obj): return rinterface.SexpVector([obj, ], rinterface.STRSXP) @default_converter.py2ri.register(py3str) def _(obj): return rinterface.SexpVector([obj, ], rinterface.STRSXP) @default_converter.py2ri.register(list) def _(obj): return rinterface.ListSexpVector([conversion.py2ri(x) for x in obj]) @default_converter.py2ri.register(rlc.TaggedList) def _(obj): res = rinterface.ListSexpVector([conversion.py2ri(x) for x in obj]) res.do_slot_assign('names', rinterface.StrSexpVector(obj.tags)) return res @default_converter.py2ri.register(complex) def _(obj): return rinterface.SexpVector([obj, ], rinterface.CPLXSXP) @default_converter.py2ro.register(object) def _(obj): robj = conversion.py2ri(obj) return conversion.ri2ro(robj) @default_converter.ri2py.register(object) def _(obj): return conversion.ri2ro(obj) class Formula(RObjectMixin, rinterface.Sexp): def __init__(self, formula, environment = _globalenv): if isinstance(formula, str): inpackage = rinterface.baseenv["::"] asformula = inpackage(rinterface.StrSexpVector(['stats', ]), rinterface.StrSexpVector(['as.formula', ])) formula = rinterface.SexpVector(rinterface.StrSexpVector([formula, ])) robj = asformula(formula, env = environment) else: robj = formula super(Formula, self).__init__(robj) def getenvironment(self): """ Get the environment in which the formula is finding its symbols.""" res = self.do_slot(".Environment") res = conversion.ri2ro(res) return res def setenvironment(self, val): """ Set the environment in which a formula will find its symbols.""" if not isinstance(val, rinterface.SexpEnvironment): raise ValueError("The environment must be an instance of" + " rpy2.rinterface.Sexp.environment") self.do_slot_assign(".Environment", val) environment = property(getenvironment, setenvironment, "R environment in which the formula will look for" + " its variables.") class R(object): _instance = None def __new__(cls): if cls._instance is None: rinterface.initr() cls._instance = object.__new__(cls) return cls._instance def __getattribute__(self, attr): try: return super(R, self).__getattribute__(attr) except AttributeError as ae: orig_ae = str(ae) try: return self.__getitem__(attr) except LookupError as le: raise AttributeError(orig_ae) def __getitem__(self, item): res = _globalenv.get(item) res = conversion.ri2ro(res) if hasattr(res, '__rname__'): res.__rname__ = item return res #FIXME: check that this is properly working def __cleanup__(self): rinterface.endEmbeddedR() del(self) def __str__(self): s = super(R, self).__str__() s += os.linesep version = self["version"] tmp = [n+': '+val[0] for n, val in zip(version.names, version)] s += str.join(os.linesep, tmp) return s def __call__(self, string): p = _rparse(text=StrSexpVector((string,))) res = self.eval(p) return conversion.ri2py(res) r = R() conversion.set_conversion(default_converter) globalenv = conversion.converter.ri2ro(_globalenv) baseenv = conversion.converter.ri2ro(rinterface.baseenv) emptyenv = conversion.converter.ri2ro(rinterface.emptyenv) rpy2-2.7.8/rpy/robjects/robject.py0000664000175000017500000001357712654236076020253 0ustar laurentlaurent00000000000000import os, sys import tempfile import weakref import rpy2.rinterface rpy2.rinterface.initr() from . import conversion class RSlots(object): """ Attributes of an R object as a Python mapping. The parent proxy to the underlying R object is held as a weak reference. The attributes are therefore not protected from garbage collection unless bound to a Python symbol or in an other container. """ __slots__ = ['_robj', ] def __init__(self, robj): self._robj = weakref.proxy(robj) def __getitem__(self, key): value = self._robj.do_slot(key) return conversion.ri2ro(value) def __setitem__(self, key, value): rpy2_value = conversion.py2ri(value) self._robj.do_slot_assign(key, rpy2_value) def __len__(self): return len(self._robj.list_attrs()) def keys(self): for k in self._robj.list_attrs(): yield k def items(self): for k in self._robj.list_attrs(): v = self[key] yield (k, v) def values(self): for k in self._robj.list_attrs(): v = self[key] yield v def _reduce_robjectmixin(rdumps, rtypeof, rinterface_factory, rpy2type): rinterface_level=rinterface_factory(rdumps, rtypeof) return rpy2type(rinterface_level) 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") __slots = None @property def slots(self): """ Attributes of the underlying R object as a Python mapping. The attributes can accessed and assigned by name (as if they were in a Python `dict`).""" if self.__slots is None: self.__slots = RSlots(self) return self.__slots def __str__(self): if sys.platform == 'win32': tmpf = tempfile.NamedTemporaryFile(mode="w+", 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_regular() s = [] def f(x): s.append(x) rpy2.rinterface.set_writeconsole_regular(f) self.__show(self) if sys.platform == 'win32': self.__sink() s = tmpf.readlines() tmpf.close() self.__close(tmp) 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_regular(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 as 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.") # Python 3-only if sys.version_info[0] == 2: def __reduce__(self): """ robjects-level `__reduce__()`, calling the parent class' `__reduce__()` before substituting the current high-level class as a constructor. """ t = super(RObjectMixin, self).__reduce__() # fix the constructor and parameters l = list(t) l[1] = (l[1][0], l[1][1], l[0], type(self)) l[0] = _reduce_robjectmixin return tuple(l) elif sys.version_info[0] == 3: def __reduce__(self): """ robjects-level `__reduce__()`, calling the parent class' `__reduce__()` before substituting the current high-level class as a constructor. """ t = super().__reduce__() # fix the constructor and parameters l = list(t) l[1] = (l[1][0], l[1][1], l[0], type(self)) l[0] = _reduce_robjectmixin return tuple(l) 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.7.8/rpy/robjects/language.py0000664000175000017500000000125612610501355020360 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.ri2ro(res) return res del(ri) rpy2-2.7.8/rpy/robjects/functions.py0000664000175000017500000002025112610501355020601 0ustar laurentlaurent00000000000000import os, re from collections import OrderedDict from rpy2.robjects.robject import RObjectMixin, RObject import rpy2.rinterface as rinterface from rpy2.robjects import help #import rpy2.robjects.conversion conversion from . import conversion # XXX: I need to import default_ri2ro from rpy2.robjects.packages_utils import (default_symbol_r2python, default_symbol_check_after, _map_symbols, _fix_map_symbols) baseenv_ri = rinterface.baseenv #needed to avoid circular imports _reval = rinterface.baseenv['eval'] __formals = baseenv_ri.get('formals') __args = baseenv_ri.get('args') #_genericsargsenv = baseenv_ri['.GenericArgsEnv'] #_argsenv = baseenv_ri['.ArgsEnv'] def _formals_fixed(func): tmp = __args(func) return __formals(tmp) ## docstring_property and DocstringProperty ## from Bradley Froehle ## https://gist.github.com/bfroehle/4041015 def docstring_property(class_doc): def wrapper(fget): return DocstringProperty(class_doc, fget) return wrapper class DocstringProperty(object): def __init__(self, class_doc, fget): self.fget = fget self.class_doc = class_doc def __get__(self, obj, objtype=None): if obj is None: return self.class_doc else: return self.fget(obj) def __set__(self, obj, value): raise AttributeError("Cannot set the attribute") def __delete__(self, obj): raise AttributeError("Cannot delete the attribute") def _repr_argval(obj): """ Helper functions to display an R object in the docstring. This a hack and will be hopefully replaced the extraction of information from the R help system.""" try: l = len(obj) if l == 1: if obj[0].rid == rinterface.MissingArg.rid: # no default value s = None elif obj[0].rid == rinterface.NULL.rid: s = 'rinterface.NULL' else: s = str(obj[0][0]) elif l > 1: s = '(%s, ...)' % str(obj[0][0]) else: s = str(obj) except: s = str(obj) return s class Function(RObjectMixin, rinterface.SexpClosure): """ Python representation of an R function. """ __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, ))) @docstring_property(__doc__) def __doc__(self): fm = _formals_fixed(self) doc = list(['Python representation of an R function.', 'R arguments:', '']) if fm is rinterface.NULL: doc.append('') for key, val in zip(fm.do_slot('names'), fm): if key == '...': val = 'R ellipsis (any number of parameters)' doc.append('%s: %s' % (key, _repr_argval(val))) return os.linesep.join(doc) def __call__(self, *args, **kwargs): new_args = [conversion.py2ri(a) for a in args] new_kwargs = {} for k, v in kwargs.items(): new_kwargs[k] = conversion.py2ri(v) res = super(Function, self).__call__(*new_args, **new_kwargs) res = conversion.ri2ro(res) return res def formals(self): """ Return the signature of the underlying R function (as the R function 'formals()' would). """ res = _formals_fixed(self) res = conversion.ri2ro(res) return res def rcall(self, *args): """ Wrapper around the parent method rpy2.rinterface.SexpClosure.rcall(). """ res = super(Function, self).rcall(*args) # XXX: Now that ri2ro converts to python objects, we restrict to the # default now for a raw R call. I'm not sure there should be *any* # conversion. However, we need to get this out of __init__.py first! # res = ro.default_ri2ro(res) return res class SignatureTranslatedFunction(Function): """ Python representation of an R function, where the names in named argument are translated to valid argument names in Python. """ _prm_translate = None def __init__(self, sexp, init_prm_translate = None, on_conflict = 'warn', symbol_r2python = default_symbol_r2python, symbol_check_after = default_symbol_check_after): 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 formals = self.formals() if formals is not rinterface.NULL: (symbol_mapping, conflicts, resolutions) = _map_symbols(formals.names, translation = prm_translate, symbol_r2python = symbol_r2python, symbol_check_after = symbol_check_after) msg_prefix = 'Conflict when converting R symbols'+\ ' in the function\'s signature:\n- ' exception = ValueError _fix_map_symbols(symbol_mapping, conflicts, on_conflict, msg_prefix, exception) symbol_mapping.update(resolutions) reserved_pynames = set(dir(self)) prm_translate.update((k, v[0]) for k, v in symbol_mapping.items()) 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) pattern_link = re.compile(r'\\link\{(.+?)\}') pattern_code = re.compile(r'\\code\{(.+?)\}') pattern_samp = re.compile(r'\\samp\{(.+?)\}') class DocumentedSTFunction(SignatureTranslatedFunction): def __init__(self, sexp, init_prm_translate = None, packagename = None): super(DocumentedSTFunction, self).__init__(sexp, init_prm_translate = init_prm_translate) self.__rpackagename__ = packagename @docstring_property(__doc__) def __doc__(self): doc = ['Python representation of an R function.'] description = help.docstring(self.__rpackagename__, self.__rname__, sections=['description']) doc.append(description) fm = _formals_fixed(self) names = fm.do_slot('names') doc.append(self.__rname__+'(') for key, val in self._prm_translate.items(): if key == '___': description = '(was "..."). R ellipsis (any number of parameters)' else: description = _repr_argval(fm[names.index(val)]) if description is None: doc.append(' %s,' % key) else: doc.append(' %s = %s,' % (key, description)) doc.extend((')', '')) package = help.Package(self.__rpackagename__) page = package.fetch(self.__rname__) for item in page.arguments(): description = item.value description = description.replace('\n', '') description, count = pattern_link.subn(r'\1', description) description, count = pattern_code.subn(r'`\1`', description) description, count = pattern_samp.subn(r'`\1`', description) doc.append(' '.join((item.name, ': ', description, ','))) doc.append('') return os.linesep.join(doc) rpy2-2.7.8/rpy/robjects/packages_utils.py0000664000175000017500000001025412610501355021571 0ustar laurentlaurent00000000000000""" Utility module with functions related to R packages (having these in this utility module rather than in packages.py prevents circular imports). """ from rpy2 import rinterface from warnings import warn from collections import defaultdict _packages = rinterface.baseenv['.packages'] _libpaths = rinterface.baseenv['.libPaths'] _find_package = rinterface.baseenv['find.package'] def get_packagepath(package): """ return the path to an R package installed """ res = _find_package(rinterface.StrSexpVector((package, ))) return res[0] # Functions to translate R symbols to Python symbols. # The functions are in this module in order to facilitate # their access from other modules (without circular dependencies). # It not necessarily the absolute best place to have the functions though. def default_symbol_r2python(rname): return rname.replace('.', '_') def default_symbol_check_after(symbol_mapping): # dict to store the Python symbol -> R symbols mapping causing problems. conflicts = dict() resolutions = dict() for py_symbol, r_symbols in symbol_mapping.items(): n_r_symbols = len(r_symbols) if n_r_symbols == 1: continue elif n_r_symbols == 2: # more than one R symbol associated with this Python symbol try: idx = r_symbols.index(py_symbol) # there is an R symbol identical to the proposed Python symbol; # we keep that pair mapped, and change the Python symbol for the # other R symbol(s) according to PEP 0008 for i, s in enumerate(r_symbols): if i == idx: resolutions[py_symbol] = [s,] else: new_py_symbol = py_symbol + '_' resolutions[new_py_symbol] = [s,] except ValueError: # I am unsure about what to do at this point: # add it as a conflict conflicts[py_symbol] = r_symbols else: # no automatic resolution if more than 2 conflicts[py_symbol] = r_symbols return conflicts, resolutions def _map_symbols(rnames, translation = dict(), symbol_r2python = default_symbol_r2python, symbol_check_after = default_symbol_check_after): """ :param names: an iterable of rnames :param translation: a mapping for R name->python name :param symbol_r2python: a function to translate an R symbol into a (presumably valid) Python symbol :param symbol_check_after: a function to check a prospective set of translation and resolve conflicts if needed """ symbol_mapping = defaultdict(list) for rname in rnames: if rname in translation: rpyname = translation[rname] else: rpyname = symbol_r2python(rname) symbol_mapping[rpyname].append(rname) conflicts, resolutions = symbol_check_after(symbol_mapping) return (symbol_mapping, conflicts, resolutions) def _fix_map_symbols(symbol_mapping, conflicts, on_conflict, msg_prefix, exception): """ :param symbol_mapping: as returned by `_map_symbols` :param conflicts: as returned by `_map_symbols` :param on_conflict: action to take if conflict :param msg_prefix: prefix for error message :param exception: exception to raise """ if len(conflicts) > 0: msg = msg_prefix msg += '\n- '.join(('%s -> %s' %(k, ', '.join(v)) for k,v in conflicts.items())) if on_conflict == 'fail': msg += '\nTo turn this exception into a simple' +\ ' warning use the parameter' +\ ' `on_conflict="warn"\`' raise exception(msg) elif on_conflict == 'warn': for k, v in conflicts.items(): if k in v: symbol_mapping[k] = [k,] else: del(symbol_mapping[k]) warn(msg) else: raise ValueError('Invalid value for parameter "on_conflict"') rpy2-2.7.8/rpy/robjects/packages.py0000664000175000017500000004443212615506121020357 0ustar laurentlaurent00000000000000import os from types import ModuleType from collections import defaultdict from warnings import warn import rpy2.rinterface as rinterface import rpy2.robjects.lib from . import conversion from rpy2.robjects.functions import (SignatureTranslatedFunction, docstring_property, DocumentedSTFunction) from rpy2.robjects.constants import NULL from rpy2.robjects import Environment from rpy2.robjects.packages_utils import (_libpaths, get_packagepath, _packages, default_symbol_r2python, default_symbol_check_after, _map_symbols, _fix_map_symbols) import rpy2.robjects.help as rhelp _require = rinterface.baseenv['require'] _library = rinterface.baseenv['library'] _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'] _loaded_namespaces = rinterface.baseenv['loadedNamespaces'] _globalenv = rinterface.globalenv _new_env = rinterface.baseenv["new.env"] StrSexpVector = rinterface.StrSexpVector # Fetching symbols in the namespace "utils" assumes that "utils" is loaded # (currently the case by default in R). _data = rinterface.baseenv['::'](StrSexpVector(('utils', )), StrSexpVector(('data', ))) _reval = rinterface.baseenv['eval'] _options = rinterface.baseenv['options'] def no_warnings(func): """ Decorator to run R functions without warning. """ 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 as 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) # FIXME: should this be part of the API for rinterface ? # (may be it is already the case and there is code # duplicaton ?) def reval(string, envir = _globalenv): """ Evaluate a string as R code :param string: R code :type string: a :class:`str` :param 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 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 _symbol_r2python = None __version__ = None __rdata__ = None def __init__(self, env, name, translation = {}, exported_names = None, on_conflict = 'fail', version = None, symbol_r2python = default_symbol_r2python, symbol_check_after = default_symbol_check_after): """ Create a Python module-like object from an R environment, using the specified translation if defined. - env: R environment - name: package name - translation: `dict` with R names as keys and corresponding Python names as values - exported_names: `set` of names/symbols to expose to instance users - on_conflict: 'fail' or 'warn' (default: 'fail') - version: version string for the package - symbol_r2python: function to convert R symbols into Python symbols. The default translate `.` into `_`. - symbol_check_after: function to check the Python symbols obtained from `symbol_r2python`. """ 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._symbol_r2python = symbol_r2python self._symbol_check_after = symbol_check_after 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__ (symbol_mapping, conflicts, resolutions) = _map_symbols(self._env, translation = self._translation, symbol_r2python = self._symbol_r2python, symbol_check_after = self._symbol_check_after) msg_prefix = 'Conflict when converting R symbols'+\ ' in the package "%s"' % self.__rname__ +\ ' to Python symbols: \n-' exception = LibraryError _fix_map_symbols(symbol_mapping, conflicts, on_conflict, msg_prefix, exception) symbol_mapping.update(resolutions) reserved_pynames = set(dir(self)) for rpyname, rnames in symbol_mapping.items(): # last paranoid check if len(rnames) > 1: raise ValueError('Only one R name should be associated with %s (and we have %s)' % (rpyname, str(rnames))) rname = rnames[0] if rpyname in reserved_pynames: 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) try: riobj = self._env[rname] except rinterface.RRuntimeError as rre: warn(str(rre)) rpyobj = conversion.ri2ro(riobj) 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.robjects.packages.Package as a ' + s # alias STF = SignatureTranslatedFunction class SignatureTranslatedPackage(Package): """ R package in which the R functions had their signatures 'translated' (that this the named parameters were made to to conform Python's rules for vaiable names).""" def __fill_rpy2r__(self, on_conflict = 'fail'): super(SignatureTranslatedPackage, self).__fill_rpy2r__(on_conflict = on_conflict) for name, robj in self.__dict__.items(): if isinstance(robj, rinterface.Sexp) and robj.typeof == rinterface.CLOSXP: self.__dict__[name] = STF(self.__dict__[name], on_conflict = on_conflict, symbol_r2python = self._symbol_r2python, symbol_check_after = self._symbol_check_after) # alias STP = SignatureTranslatedPackage class SignatureTranslatedAnonymousPackage(SignatureTranslatedPackage): def __init__(self, string, name): env = Environment() reval(string, env) super(SignatureTranslatedAnonymousPackage, self).__init__(env, name) # alias STAP = SignatureTranslatedAnonymousPackage class InstalledSTPackage(SignatureTranslatedPackage): @docstring_property(__doc__) def __doc__(self): doc = list(['Python representation of an R package.']) if not self.__rname__: doc.append('') else: try: doc.append(rhelp.docstring(self.__rname__, self.__rname__ + '-package', sections=['description'])) except rhelp.HelpNotFoundError as hnf: doc.append('[R help was not found]') return os.linesep.join(doc) def __fill_rpy2r__(self, on_conflict = 'fail'): super(SignatureTranslatedPackage, self).__fill_rpy2r__(on_conflict = on_conflict) for name, robj in self.__dict__.items(): if isinstance(robj, rinterface.Sexp) and robj.typeof == rinterface.CLOSXP: self.__dict__[name] = DocumentedSTFunction(self.__dict__[name], packagename = self.__rname__) class InstalledPackage(Package): @docstring_property(__doc__) def __doc__(self): doc = list(['Python representation of an R package.', 'R arguments:', '']) if not self.__rname__: doc.append('') else: try: doc.append(rhelp.docstring(self.__rname__, self.__rname__ + '-package', sections=['description'])) except rhelp.HelpNotFoundError as hnf: doc.append('[R help was not found]') return os.linesep.join(doc) class LibraryError(ImportError): """ Error occuring when importing an R library """ pass class InstalledPackages(object): """ R packages installed. """ def __init__(self, lib_loc=None): libraryiqr = _library(**{'lib.loc': lib_loc}) lib_results_i = libraryiqr.do_slot('names').index('results') self.lib_results = libraryiqr[lib_results_i] self.nrows, self.ncols = self.lib_results.do_slot('dim') self.colnames = self.lib_results.do_slot('dimnames')[1] # column names self.lib_packname_i = self.colnames.index('Package') def isinstalled(self, packagename): if not isinstance(packagename, rinterface.StrSexpVector): rname = rinterface.StrSexpVector((packagename, )) else: if len(packagename) > 1: raise ValueError("Only specify one package name at a time.") rname = packagename nrows, ncols = self.nrows, self.ncols lib_results, lib_packname_i = self.lib_results, self.lib_packname_i for i in range(0+lib_packname_i*nrows, nrows*(lib_packname_i+1), 1): if lib_results[i] == packagename: return True return False def __iter__(self): """ Iterate through rows, yield tuples at each iteration """ lib_results = self.lib_results nrows, ncols = self.nrows, self.ncols colrg = range(0, ncols) for row_i in range(nrows): yield tuple(lib_results[x*nrows+row_i] for x in colrg) def isinstalled(name, lib_loc = None): """ Find whether an R package is installed :param name: name of an R package :param lib_loc: specific location for the R library (default: None) :rtype: a :class:`bool` """ instapack = InstalledPackages(lib_loc) return instapack.isinstalled(name) def importr(name, lib_loc = None, robject_translations = {}, signature_translation = True, suppress_messages = True, on_conflict = 'fail', symbol_r2python = default_symbol_r2python, symbol_check_after = default_symbol_check_after, 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: (True or False) - suppress_message: Suppress messages R usually writes on the console (defaut: True) - on_conflict: 'fail' or 'warn' (default: 'fail') - symbol_r2python: function to translate R symbols into Python symbols - symbol_check_after: function to check the Python symbol obtained from `symbol_r2python`. - 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 = InstalledSTPackage(env, name, translation = robject_translations, exported_names = exported_names, on_conflict = on_conflict, version = version, symbol_r2python = symbol_r2python, symbol_check_after = symbol_check_after) else: pack = InstalledPackage(env, name, translation = robject_translations, exported_names = exported_names, on_conflict = on_conflict, version = version, symbol_r2python = symbol_r2python, symbol_check_after = symbol_check_after) 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 data(package): """ Return the PackageData for the given package.""" return package.__rdata__ 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 as knf: env = env.enclos() if env.rsame(rinterface.emptyenv): tryagain = False else: tryagain = True return conversion.ri2ro(env) rpy2-2.7.8/rpy/robjects/vectors.py0000664000175000017500000011606712632133671020277 0ustar laurentlaurent00000000000000from rpy2.robjects.robject import RObjectMixin, RObject import rpy2.rinterface as rinterface #import rpy2.robjects.conversion as conversion from . 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) if sys.version_info[0] == 2: py3str = unicode py3bytes = str range = xrange else: long = int py3str = str py3bytes = bytes 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 range(len(args))) for i, x in enumerate(args): if x is MissingArg: conv_args[i] = x else: conv_args[i] = conversion.py2ri(x) kwargs = copy.copy(kwargs) for k, v in kwargs.values(): kwargs[k] = conversion.py2ri(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.items()): 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 item-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_items(item) for i, (k, v) in enumerate(args.items()): args[i] = conversion.py2ro(v) args.append(conversion.py2ro(value), tag = None) args.insert(0, self._parent, tag = None) res = fun.rcall(tuple(args.items()), 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.ri2ro(res) def __sub__(self, x): res = globalenv_ri.get("-")(self._parent, conversion.py2ri(x)) return conversion.ri2ro(res) def __mul__(self, x): res = globalenv_ri.get("*")(self._parent, conversion.py2ri(x)) return conversion.ri2ro(res) def __pow__(self, x): res = globalenv_ri.get("^")(self._parent, conversion.py2ri(x)) return conversion.ri2ro(res) if sys.version_info[0] == 2: def __div__(self, x): res = globalenv_ri.get("/")(self._parent, conversion.py2ri(x)) return conversion.ri2ro(res) else: def __floordiv__(self, x): res = globalenv_ri.get("%/%")(self._parent, conversion.py2ri(x)) return conversion.ri2ro(res) def __truediv__(self, x): res = globalenv_ri.get("/")(self._parent, conversion.py2ri(x)) return conversion.ri2ro(res) def __divmod__(self, x): res = globalenv_ri.get("%%")(self._parent, conversion.py2ri(x)) return conversion.ri2ro(res) def __or__(self, x): res = globalenv_ri.get("|")(self._parent, conversion.py2ri(x)) return conversion.ri2ro(res) def __and__(self, x): res = globalenv_ri.get("&")(self._parent, conversion.py2ri(x)) return conversion.ri2ro(res) # Comparisons def __lt__(self, x): res = globalenv_ri.get("<")(self._parent, conversion.py2ri(x)) return conversion.ri2ro(res) def __le__(self, x): res = globalenv_ri.get("<=")(self._parent, conversion.py2ri(x)) return conversion.ri2ro(res) def __eq__(self, x): res = globalenv_ri.get("==")(self._parent, conversion.py2ri(x)) return conversion.ri2ro(res) def __ne__(self, x): res = globalenv_ri.get("!=")(self._parent, conversion.py2ri(x)) return conversion.ri2ro(res) def __gt__(self, x): res = globalenv_ri.get(">")(self._parent, conversion.py2ri(x)) return conversion.ri2ro(res) def __ge__(self, x): res = globalenv_ri.get(">=")(self._parent, conversion.py2ri(x)) return conversion.ri2ro(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.ri2ro(res) return res def __getitem__(self, i): res = super(Vector, self).__getitem__(i) if isinstance(res, Sexp): res = conversion.ri2ro(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.ri2ro(res) return res def _names_get(self): res = baseenv_ri.get('names')(self) res = conversion.ri2ro(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 items(self): """ iterator on names and values """ #FIXME: should be a view ? 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.ri2ro(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, py3str): 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 == 0: s = '[]' elif 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__() 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'] @property def NAvalue(self): return rinterface.NA_Character 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.ri2ro(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'] @property def NAvalue(self): return rinterface.NA_Integer 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.ri2ro(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. """ @property def NAvalue(self): return rinterface.NA_Logical 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. """ @property def NAvalue(self): return rinterface.NA_Complex 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. """ @property def NAvalue(self): return rinterface.NA_Real 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'] @property def NAvalue(self): return rinterface.NA_Integer def __init__(self, obj, levels = rinterface.MissingArg, labels = rinterface.MissingArg, exclude = rinterface.MissingArg, ordered = rinterface.MissingArg): if not isinstance(obj, Sexp): obj = StrSexpVector(obj) if ('factor' in obj.rclass) and \ all(p is rinterface.MissingArg for p in (labels, exclude, ordered)): res = obj else: 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.ri2ro(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(itemable) -> ListVector. The parameter 'itemable' can be: - an object with a method `items()`, such for example a dict, a rpy2.rlike.container.TaggedList, an rpy2.rinterface.SexpVector of type VECSXP. - an iterable of (name, value) tuples """ _vector = rinterface.baseenv['vector'] def __init__(self, tlist): if isinstance(tlist, rinterface.SexpVector): if tlist.typeof != rinterface.VECSXP: raise ValueError("tlist should have " "tlist.typeof == rinterface.VECSXP") super(ListVector, self).__init__(tlist) elif hasattr(tlist, 'items') and callable(tlist.items): kv = [(k, conversion.py2ri(v)) for k,v in tlist.items()] 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(v)) for k,v 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 as 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 as 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 as 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.ri2ro(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.ri2ro(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.ri2ro(res) return res def __dimnames_set(self, value): """ Set list of name vectors (like the R function 'dimnames' does).""" value = conversion.ri2ro(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.ri2ro(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.ri2ro(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.ri2ro(res) def crossprod(self, m): """ crossproduct X'.Y""" res = self._crossprod(self, conversion.ri2ro(m)) return conversion.ri2ro(res) def tcrossprod(self, m): """ crossproduct X.Y'""" res = self._tcrossprod(self, m) return conversion.ri2ro(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.ri2ro(res) def dot(self, m): """ Matrix multiplication """ res = self._dot(self, m) return conversion.ri2ro(res) def eigen(self): """ Eigen values """ res = self._eigen(self) return conversion.ri2ro(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.ri2ro(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.ri2ro(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 # 3rd-party conversions could return objects # that no longer inherit from rpy2's R objects. # We need to use the low-level __getitem__ # to bypass the conversion mechanism. # R's data.frames have no representation at the C-API level # (they are lists) tmp = rinterface.ListSexpVector.__getitem__(self, i) if tmp.typeof == rinterface.VECSXP: return DataFrame(tmp) else: return conversion.ri2ro(tmp) def cbind(self, *args, **kwargs): """ bind objects as supplementary columns """ new_args = [self, ] + [conversion.ri2ro(x) for x in args] new_kwargs = dict([(k, conversion.ri2ro(v)) for k,v in kwargs.items()]) res = self._cbind(*new_args, **new_kwargs) return conversion.ri2ro(res) def rbind(self, *args, **kwargs): """ bind objects as supplementary rows """ new_args = [conversion.ri2ro(x) for x in args] new_kwargs = dict([(k, conversion.ri2ro(v)) for k,v in kwargs.items()]) res = self._rbind(self, *new_args, **new_kwargs) return conversion.ri2ro(res) @staticmethod def from_csvfile(path, header = True, sep = ",", quote = "\"", dec = ".", row_names = rinterface.MissingArg, col_names = rinterface.MissingArg, fill = True, comment_char = "", na_strings = [], 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 na_strings : a list of strings which are interpreted to be NA values 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) na_strings = conversion.py2ro(na_strings) 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, 'na.strings': na_strings, 'as.is': as_is}) res = conversion.ri2ro(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 range(self.nrow): yield self.rx(i+1, rinterface.MissingArg) def iter_column(self): """ iterator across columns """ for i in range(self.ncol): yield self.rx(rinterface.MissingArg, i+1) # end of definition for DataFrame rtypeof2rotype = { rinterface.INTSXP: IntVector, rinterface.REALSXP: FloatVector, rinterface.STRSXP: StrVector, rinterface.CPLXSXP: ComplexVector, rinterface.LGLSXP: BoolVector } __all__ = ['Vector', 'StrVector', 'IntVector', 'BoolVector', 'ComplexVector', 'FloatVector', 'FactorVector', 'Vector', 'ListVector', 'POSIXlt', 'POSIXct', 'Array', 'Matrix', 'DataFrame'] rpy2-2.7.8/rpy/robjects/lib/0000775000175000017500000000000012654242632016775 5ustar laurentlaurent00000000000000rpy2-2.7.8/rpy/robjects/lib/__init__.py0000664000175000017500000000000012610501355021064 0ustar laurentlaurent00000000000000rpy2-2.7.8/rpy/robjects/lib/ggplot2.py0000664000175000017500000006122512654236124020732 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 = '2.0.0' 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) def save(self, filename, **kwargs): """ Save the plot ( calls R's `ggplot2::ggsave()` ) """ ggplot2.ggsave(filename=filename, plot=self, **kwargs) 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.items(): 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.""" res = cls(cls._constructor(**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 StatBin(Stat): """ Bin data. """ _constructor = ggplot2_env['stat_bin'] stat_bin = StatBin.new class StatBin2D(Stat): """ 2D binning of data into squares/rectangles. """ try: _constructor = ggplot2_env['stat_bin_2d'] except: # fallback for versions of ggplot2 < 2.0 _constructor = ggplot2_env['stat_bin2d'] stat_bin2d = StatBin2D.new stat_bin_2d=StatBin2D.new class StatBinhex(Stat): """ 2D binning of data into hexagons. """ try: _constructor = ggplot2_env['stat_bin_hex'] except: # fallback for versions of ggplot2 < 2.0 _constructor = ggplot2_env['stat_binhex'] stat_binhex = StatBinhex.new stat_bin_hex=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 """ try: _constructor = ggplot2_env['stat_density_2d'] except: _constructor = ggplot2_env['stat_density2d'] stat_density2d = StatDensity2D.new stat_density_2d=StatDensity2D.new class StatFunction(Stat): """ Superimpose a function """ _constructor = ggplot2_env['stat_function'] stat_function = StatFunction.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 StatSummary2D(Stat): """ Summarize values for y at every unique value for x""" try: _constructor = ggplot2_env['stat_summary_2d'] except: _constructor = ggplot2_env['stat_summary2d'] stat_summary2d = StatSummary2D.new stat_summary_2d = StatSummary2D.new class StatUnique(Stat): """ Remove duplicates. """ _constructor = ggplot2_env['stat_unique'] stat_unique = StatUnique.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): try: _constructor = ggplot2_env['geom_density_2d'] except: _constructor = ggplot2_env['geom_density2d'] geom_density2d = GeomDensity2D.new geom_density_2d = 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 GeomRaster(Geom): _constructor = ggplot2_env['geom_raster'] geom_raster = GeomRaster.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 GeomSpoke(Geom): """ Convert angle and radius to xend and yend """ _constructor = ggplot2_env['geom_spoke'] geom_spoke = GeomSpoke.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 scale_color_brewer = scale_colour_brewer class ScaleColourContinuous(ScaleColour): _constructor = ggplot2_env['scale_colour_continuous'] scale_colour_continuous = ScaleColourContinuous.new scale_color_continuous = scale_colour_continuous class ScaleColourDiscrete(ScaleColour): _constructor = ggplot2_env['scale_colour_discrete'] scale_colour_discrete = ScaleColourDiscrete.new scale_color_discrete = scale_colour_discrete class ScaleColourGradient(ScaleColour): _constructor = ggplot2_env['scale_colour_gradient'] scale_colour_gradient = ScaleColourGradient.new scale_color_gradient = scale_colour_gradient class ScaleColourGradient2(ScaleColour): _constructor = ggplot2_env['scale_colour_gradient2'] scale_colour_gradient2 = ScaleColourGradient2.new scale_color_gradient2 = scale_colour_gradient2 class ScaleColourGradientN(ScaleColour): _constructor = ggplot2_env['scale_colour_gradientn'] scale_colour_gradientn = ScaleColourGradientN.new scale_color_gradientn = scale_colour_gradientn class ScaleColourGrey(ScaleColour): _constructor = ggplot2_env['scale_colour_grey'] scale_colour_grey = ScaleColourGrey.new scale_color_grey = scale_colour_grey class ScaleColourHue(ScaleColour): _constructor = ggplot2_env['scale_colour_hue'] scale_colour_hue = ScaleColourHue.new scale_color_hue = scale_colour_hue class ScaleColourIdentity(ScaleColour): _constructor = ggplot2_env['scale_colour_identity'] scale_colour_identity = ScaleColourIdentity.new scale_color_identity = scale_colour_identity class ScaleColourManual(ScaleColour): _constructor = ggplot2_env['scale_colour_manual'] scale_colour_manual = ScaleColourManual.new scale_color_manual = scale_colour_manual 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 Labs(Options): _constructor = ggplot2.labs @classmethod def new(cls, **kwargs): res = cls(cls._constructor(**kwargs)) return res labs = Labs.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 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 ThemeDark(Theme): _constructor = ggplot2.theme_dark @classmethod def new(cls, base_size = 12, base_family = ""): res = cls(cls._constructor(base_size = base_size, base_family = base_family)) return res theme_dark = ThemeDark.new class ThemeLight(Theme): _constructor = ggplot2.theme_light @classmethod def new(cls, base_size = 12, base_family = ""): res = cls(cls._constructor(base_size = base_size, base_family = base_family)) return res theme_light = ThemeLight.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 theme_grey = theme_gray class ThemeMinimal(Theme): _constructor = ggplot2.theme_minimal @classmethod def new(cls, base_size = 12, base_family = ""): res = cls(cls._constructor(base_size = base_size, base_family = base_family)) return res theme_minimal = ThemeMinimal.new class ThemeLinedraw(Theme): _constructor = ggplot2.theme_linedraw @classmethod def new(cls, base_size=12, base_family=""): res = cls(cls._constructor(base_size=base_size, base_family=base_family)) return res theme_linedraw = ThemeLinedraw.new class ThemeVoid(Theme): _constructor = ggplot2.theme_void @classmethod def new(cls, base_size = 12, base_family = ""): res = cls(cls._constructor(base_size = base_size, base_family = base_family)) return res theme_void = ThemeVoid.new #theme_render theme_set = ggplot2.theme_set theme_update = ggplot2.theme_update gplot = ggplot2.qplot map_data = ggplot2.map_data theme = ggplot2_env['theme'] ggtitle = ggplot2.ggtitle original_ri2ro = conversion.ri2ro def ggplot2_conversion(robj): pyobj = original_ri2ro(robj) try: rcls = pyobj.rclass except AttributeError: # conversion lead to something that is no # longer an R object return pyobj if (rcls is not None) and ('gg' in rcls): pyobj = GGPlot(pyobj) return pyobj conversion.ri2ro = ggplot2_conversion rpy2-2.7.8/rpy/robjects/lib/grid.py0000664000175000017500000001645512610501355020277 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.items(): 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.items(): 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.items(): 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_py2ri = None original_ri2ro = None original_py2ro = None def grid_ri2ro(robj): pyobj = original_ri2ro(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 as ke: pass return pyobj def activate(): global original_py2ri, original_ri2ro, original_py2ro # If module is already activated, there is nothing to do if original_py2ri: return original_py2ri = conversion.py2ri original_ri2ro = conversion.ri2ro original_py2ro = conversion.py2ro #conversion.py2ri = numpy2ri conversion.ri2ro = grid_ri2ro #conversion.py2ro = numpy2ro def deactivate(): global original_py2ri, original_ri2ro, original_py2ro # If module has never been activated or already deactivated, # there is nothing to do if not original_py2ri: return conversion.py2ri = original_py2ri conversion.ri2ro = original_ri2ro conversion.py2ro = original_py2ro original_py2ri = original_ri2ro = original_py2ro = None rpy2-2.7.8/rpy/robjects/lib/tests/0000775000175000017500000000000012654242632020137 5ustar laurentlaurent00000000000000rpy2-2.7.8/rpy/robjects/lib/tests/test_ggplot2.py0000664000175000017500000000201212610501355023111 0ustar laurentlaurent00000000000000import unittest # Try to load R ggplot package, and see if it works from rpy2.rinterface import RRuntimeError has_ggplot = True try: from rpy2.robjects.lib import ggplot2 except RRuntimeError: has_ggplot = False from rpy2.robjects.packages import importr datasets = importr('datasets') mtcars = datasets.__rdata__.fetch('mtcars')['mtcars'] @unittest.skipUnless(has_ggplot, 'ggplot2 package not available in R') 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.7.8/rpy/robjects/lib/tests/__init__.py0000664000175000017500000000034012610501355022235 0ustar laurentlaurent00000000000000import unittest from os.path import dirname def main(): tr = unittest.TextTestRunner(verbosity = 2) suite = unittest.TestLoader().discover(dirname(__file__)) tr.run(suite) if __name__ == '__main__': main() rpy2-2.7.8/rpy/robjects/lib/tests/test_dplyr.py0000664000175000017500000000441212611212261022667 0ustar laurentlaurent00000000000000import unittest # Try to load R dplyr package, and see if it works from rpy2.rinterface import RRuntimeError has_dplyr = None try: from rpy2.robjects.lib import dplyr has_dplyr = True except RRuntimeError: has_dplyr = False from rpy2.robjects.packages import importr, data datasets = importr('datasets') mtcars = data(datasets).fetch('mtcars')['mtcars'] @unittest.skipUnless(has_dplyr, 'dplyr package not available in R') class DplyrTestCase(unittest.TestCase): def testSetup(self): pass def tearDown(self): pass def testDataFrame(self): dataf = dplyr.DataFrame(mtcars) # FIXME: no testing much at the moment... self.assertTrue(isinstance(dataf, dplyr.DataFrame)) def testFilter_NoFilter(self): dataf = dplyr.DataFrame(mtcars) dataf_filter = dataf.filter() self.assertEqual(dataf.nrow, dataf_filter.nrow) def testFilter_OneFilter(self): dataf = dplyr.DataFrame(mtcars) ngear_gt_3 = len(tuple(x for x in dataf.rx2('gear') if x > 3)) dataf_filter = dataf.filter('gear > 3') self.assertEqual(ngear_gt_3, dataf_filter.nrow) def testSplitMergeFunction(self): dataf = dplyr.DataFrame(mtcars) dataf_by_gear = dataf.group_by('gear') dataf_sum_gear = dataf_by_gear.summarize(foo='sum(gear)') self.assertEquals(type(dataf_sum_gear), dplyr.DataFrame) def testJoin(self): dataf_a = dplyr.DataFrame(mtcars) dataf_b = dataf_a.mutate(foo=1) dataf_c = dataf_a.inner_join(dataf_b) all_names = list(dataf_a.colnames) all_names.append('foo') try: # Python 3 self.assertCountEqual(all_names, dataf_c.colnames) except AttributeError as ae: # Python 2.7 self.assertItemsEqual(all_names, dataf_c.colnames) def testCollect(self): dataf = dplyr.DataFrame(mtcars) dataf_collected = dataf.collect() # FIXME: no real test here. Just ensuring that it is returning # without error self.assertEquals(dplyr.DataFrame, type(dataf_collected)) def suite(): suite = unittest.TestLoader().loadTestsFromTestCase(DplyrTestCase) return suite if __name__ == '__main__': unittest.main() rpy2-2.7.8/rpy/robjects/lib/dplyr.py0000664000175000017500000001255612654236076020517 0ustar laurentlaurent00000000000000from collections import namedtuple from six import with_metaclass from rpy2.robjects.packages import importr, data import warnings with warnings.catch_warnings(): warnings.simplefilter("ignore") dplyr = importr('dplyr', on_conflict="warn") TARGET_VERSION = '0.4.3' if dplyr.__version__ != TARGET_VERSION: warnings.warn('This was designed againt dplyr version %s but you have %s' % (TARGET_VERSION, dplyr.__version__)) lazyeval = importr('lazyeval', on_conflict="warn") from rpy2 import robjects StringInEnv = namedtuple('StringInEnv', 'string env') def _fix_args_inenv(args, env): args_inenv = list() for v in args: if isinstance(v, StringInEnv): args_inenv.append(lazyeval.as_lazy(v.string, env=v.env)) else: args_inenv.append(lazyeval.as_lazy(v, env=env)) return args_inenv def _fix_kwargs_inenv(kwargs, env): kwargs_inenv = dict() for k,v in kwargs.items(): if isinstance(v, StringInEnv): kwargs_inenv[k] = lazyeval.as_lazy(v.string, env=v.env) else: kwargs_inenv[k] = lazyeval.as_lazy(v, env=env) return kwargs_inenv def _wrap(rfunc, cls, env=robjects.globalenv): def func(dataf, *args, **kwargs): args_inenv = _fix_args_inenv(args, env) kwargs_inenv = _fix_kwargs_inenv(kwargs, env) if cls is None: return type(dataf)(rfunc(dataf, *args_inenv, **kwargs_inenv)) else: return cls(rfunc(dataf, *args_inenv, **kwargs_inenv)) return func def _wrap2(rfunc, cls, env=robjects.globalenv): def func(dataf_a, dataf_b, *args, **kwargs): args_inenv = _fix_args_inenv(args, env) kwargs_inenv = _fix_kwargs_inenv(kwargs, env) if cls is None: return type(dataf_a)(rfunc(dataf_a, dataf_b, *args_inenv, **kwargs_inenv)) else: return cls(rfunc(dataf_a, dataf_b, *args_inenv, **kwargs_inenv)) return func def _make_pipe(rfunc, cls, env=robjects.globalenv): def func(*args, **kwargs): def func2(obj): args_inenv = _fix_args_inenv(args, env) kwargs_inenv = _fix_kwargs_inenv(kwargs, env) return cls(rfunc(obj, *args_inenv, **kwargs_inenv)) return func2 return func def _make_pipe2(rfunc, cls, env=robjects.globalenv): def func(*args, **kwargs): def func2(obj_a, obj_b): args_inenv = _fix_args_inenv(args, env) kwargs_inenv = _fix_kwargs_inenv(kwargs, env) return cls(rfunc(obj_a, obj_b, *args_inenv, **kwargs_inenv)) return func2 return func class DataFrame(robjects.DataFrame): def __rshift__(self, other): return other(self) def copy_to(self, destination, name, **kwargs): """ - destination: database - name: table name in the destination database """ res = dplyr.copy_to(destination, self, name=name) return type(self)(res) def collect(self, *args, **kwargs): cls = type(self) return cls(dplyr.collect(self, *args, **kwargs)) class GroupedDataFrame(robjects.DataFrame): pass DataFrame.arrange = _wrap(dplyr.arrange_, None) DataFrame.distinct = _wrap(dplyr.distinct_, None) DataFrame.mutate = _wrap(dplyr.mutate_, None) DataFrame.transmute = _wrap(dplyr.transmute_, None) DataFrame.filter = _wrap(dplyr.filter_, None) DataFrame.select = _wrap(dplyr.select_, None) DataFrame.group_by = _wrap(dplyr.group_by_, GroupedDataFrame) DataFrame.distinct = _wrap(dplyr.distinct_, None) DataFrame.inner_join = _wrap2(dplyr.inner_join, None) DataFrame.left_join = _wrap2(dplyr.left_join, None) DataFrame.right_join = _wrap2(dplyr.right_join, None) DataFrame.full_join = _wrap2(dplyr.full_join, None) DataFrame.semi_join = _wrap2(dplyr.semi_join, None) DataFrame.anti_join = _wrap2(dplyr.anti_join, None) DataFrame.union = _wrap2(dplyr.union, None) DataFrame.intersect = _wrap2(dplyr.intersect, None) DataFrame.setdiff = _wrap2(dplyr.setdiff, None) DataFrame.sample_n = _wrap(dplyr.sample_n, None) DataFrame.sample_frac = _wrap(dplyr.sample_frac, None) DataFrame.slice = _wrap(dplyr.slice_, None) GroupedDataFrame.summarize = _wrap(dplyr.summarize_, DataFrame) GroupedDataFrame.summarise = GroupedDataFrame.summarize GroupedDataFrame.ungroup = _wrap(dplyr.ungroup, DataFrame) arrange = _make_pipe(dplyr.arrange_, DataFrame) distinct = _make_pipe(dplyr.distinct_, DataFrame) mutate = _make_pipe(dplyr.mutate_, DataFrame) transmute = _make_pipe(dplyr.transmute_, DataFrame) filter = _make_pipe(dplyr.filter_, DataFrame) select = _make_pipe(dplyr.select_, DataFrame) group_by = _make_pipe(dplyr.group_by_, DataFrame) summarize = _make_pipe(dplyr.summarize_, DataFrame) summarise = summarize distinct = _make_pipe(dplyr.distinct_, DataFrame) inner_join = _make_pipe2(dplyr.inner_join, DataFrame) left_join = _make_pipe2(dplyr.left_join, DataFrame) right_join = _make_pipe2(dplyr.right_join, DataFrame) full_join = _make_pipe2(dplyr.full_join, DataFrame) semi_join = _make_pipe2(dplyr.semi_join, DataFrame) anti_join = _make_pipe2(dplyr.anti_join, DataFrame) union = _make_pipe2(dplyr.union, DataFrame) intersect = _make_pipe2(dplyr.intersect, DataFrame) setdiff = _make_pipe2(dplyr.setdiff, DataFrame) sample_n = _make_pipe(dplyr.sample_n, DataFrame) sample_frac = _make_pipe(dplyr.sample_frac, DataFrame) slice = _make_pipe(dplyr.slice_, DataFrame) rpy2-2.7.8/rpy/robjects/environments.py0000664000175000017500000000352312610501355021323 0ustar laurentlaurent00000000000000import rpy2.rinterface as rinterface from rpy2.robjects.robject import RObjectMixin, RObject from rpy2.robjects import conversion _new_env = rinterface.baseenv["new.env"] class Environment(RObjectMixin, rinterface.SexpEnvironment): """ An R environement. """ def __init__(self, o=None): if o is None: o = _new_env(hash=rinterface.SexpVector([True, ], rinterface.LGLSXP)) super(Environment, self).__init__(o) def __getitem__(self, item): res = super(Environment, self).__getitem__(item) res = conversion.converter.ri2ro(res) # objects in a R environment have an associated name / symbol try: res.__rname__ = item except AttributeError: # the 3rd-party conversion function can return objects # for which __rname__ cannot be set (because of fixed # __slots__ and no __rname__ in the original set # of attributes) pass return res def __setitem__(self, item, value): robj = conversion.converter.py2ri(value) super(Environment, self).__setitem__(item, robj) def get(self, item, wantfun = False): """ Get a object from its R name/symol :param item: string (name/symbol) :rtype: object (as returned by :func:`conversion.converter.ri2ro`) """ res = super(Environment, self).get(item, wantfun = wantfun) res = conversion.converter.ri2ro(res) res.__rname__ = item return res def keys(self): """ Return a tuple listing the keys in the object """ return tuple([x for x in self]) def items(self): """ Iterate through the symbols and associated objects in this R environment.""" for k in self: yield (k, self[k]) rpy2-2.7.8/rpy/robjects/constants.py0000664000175000017500000000033112610501355020602 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.7.8/rpy/robjects/tests/0000775000175000017500000000000012654242632017371 5ustar laurentlaurent00000000000000rpy2-2.7.8/rpy/robjects/tests/testPackages.py0000664000175000017500000001257512610501355022363 0ustar laurentlaurent00000000000000import unittest import sys, io, tempfile import rpy2.robjects as robjects import rpy2.robjects.packages as packages from rpy2.rinterface import RRuntimeError rinterface = robjects.rinterface class PackagesTestCase(unittest.TestCase): def testNew(self): env = robjects.Environment() env['a'] = robjects.StrVector('abcd') env['b'] = robjects.IntVector((1,2,3)) env['c'] = robjects.r(''' function(x) x^2''') pck = robjects.packages.Package(env, "dummy_package") self.assertTrue(isinstance(pck.a, robjects.Vector)) self.assertTrue(isinstance(pck.b, robjects.Vector)) self.assertTrue(isinstance(pck.c, robjects.Function)) def testNewWithDot(self): env = robjects.Environment() env['a.a'] = robjects.StrVector('abcd') env['b'] = robjects.IntVector((1,2,3)) env['c'] = robjects.r(''' function(x) x^2''') pck = robjects.packages.Package(env, "dummy_package") self.assertTrue(isinstance(pck.a_a, robjects.Vector)) self.assertTrue(isinstance(pck.b, robjects.Vector)) self.assertTrue(isinstance(pck.c, robjects.Function)) def testNewWithDotConflict(self): env = robjects.Environment() env['a.a_a'] = robjects.StrVector('abcd') env['a_a.a'] = robjects.IntVector((1,2,3)) env['c'] = robjects.r(''' function(x) x^2''') self.assertRaises(packages.LibraryError, robjects.packages.Package, env, "dummy_package") def testNewWithDotConflict2(self): env = robjects.Environment() name_in_use = dir(packages.Package(env, "foo"))[0] env[name_in_use] = robjects.StrVector('abcd') self.assertRaises(packages.LibraryError, robjects.packages.Package, env, "dummy_package") class SignatureTranslatedAnonymousPackagesTestCase(unittest.TestCase): string = """ square <- function(x) { return(x^2) } cube <- function(x) { return(x^3) } """ def testNew(self): powerpack = packages.STAP(self.string, "powerpack") self.assertTrue(hasattr(powerpack, 'square')) self.assertTrue(hasattr(powerpack, 'cube')) class ImportrTestCase(unittest.TestCase): def testImportStats(self): stats = robjects.packages.importr('stats', on_conflict='warn') self.assertTrue(isinstance(stats, robjects.packages.Package)) def testImportStatsWithLibLoc(self): path = robjects.packages.get_packagepath('stats') stats = robjects.packages.importr('stats', on_conflict='warn', lib_loc = path) self.assertTrue(isinstance(stats, robjects.packages.Package)) def testImportStatsWithLibLocAndSuppressMessages(self): path = robjects.packages.get_packagepath('stats') stats = robjects.packages.importr('stats', lib_loc=path, on_conflict='warn', suppress_messages=False) self.assertTrue(isinstance(stats, robjects.packages.Package)) def testImportStatsWithLibLocWithQuote(self): path = 'coin"coin' with self.assertRaises(RRuntimeError): if sys.version_info[0] == 3: Tmp_File = io.StringIO else: # no need to test which Python 2, only 2.7 supported Tmp_File = tempfile.NamedTemporaryFile tmp_file = Tmp_File() try: stdout = sys.stdout sys.stdout = tmp_file robjects.packages.importr('dummy_inexistant', lib_loc=path) finally: sys.stdout = stdout tmp_file.close() def testImportDatasets(self): datasets = robjects.packages.importr('datasets') self.assertTrue(isinstance(datasets, robjects.packages.Package)) self.assertTrue(isinstance(datasets.__rdata__, robjects.packages.PackageData)) self.assertTrue(isinstance(robjects.packages.data(datasets), robjects.packages.PackageData)) class WherefromTestCase(unittest.TestCase): def testWherefrom(self): stats = robjects.packages.importr('stats', on_conflict='warn') rnorm_pack = robjects.packages.wherefrom('rnorm') self.assertEqual('package:stats', rnorm_pack.do_slot('name')[0]) class InstalledPackagesTestCase(unittest.TestCase): def testNew(self): instapacks = robjects.packages.InstalledPackages() res = instapacks.isinstalled('foo') self.assertTrue(isinstance(res, bool)) ncols = len(instapacks.colnames) for row in instapacks: self.assertEqual(ncols, len(row)) def suite(): suite = unittest.TestLoader().loadTestsFromTestCase(PackagesTestCase) suite.addTest(unittest.TestLoader().loadTestsFromTestCase(ImportrTestCase)) suite.addTest(unittest.TestLoader().loadTestsFromTestCase(WherefromTestCase)) suite.addTest(unittest.TestLoader().loadTestsFromTestCase(InstalledPackagesTestCase)) suite.addTest(unittest.TestLoader().loadTestsFromTestCase(SignatureTranslatedAnonymousPackagesTestCase)) return suite if __name__ == '__main__': unittest.main() rpy2-2.7.8/rpy/robjects/tests/testNumpyConversions.py0000664000175000017500000001606012610501355024177 0ustar laurentlaurent00000000000000import unittest import sys import rpy2.robjects as robjects import rpy2.robjects.conversion as conversion r = robjects.r has_numpy = True try: import numpy import rpy2.robjects.numpy2ri as rpyn except: has_numpy = False @unittest.skipUnless(has_numpy, 'numpy is not available in python') class NumpyConversionsTestCase(unittest.TestCase): def setUp(self): #self._py2ri = robjects.conversion.py2ri #self._ri2py = robjects.conversion.ri2py rpyn.activate() def tearDown(self): rpyn.deactivate() def testActivate(self): rpyn.deactivate() #FIXME: is the following still making sense ? self.assertNotEqual(rpyn.py2ri, conversion.py2ri) l = len(conversion.py2ri.registry) k = set(conversion.py2ri.registry.keys()) rpyn.activate() self.assertTrue(len(conversion.py2ri.registry) > l) rpyn.deactivate() self.assertEqual(l, len(conversion.py2ri.registry)) self.assertEqual(k, set(conversion.py2ri.registry.keys())) def testActivateTwice(self): rpyn.deactivate() #FIXME: is the following still making sense ? self.assertNotEqual(rpyn.py2ri, conversion.py2ri) l = len(conversion.py2ri.registry) k = set(conversion.py2ri.registry.keys()) rpyn.activate() rpyn.deactivate() rpyn.activate() self.assertTrue(len(conversion.py2ri.registry) > l) rpyn.deactivate() self.assertEqual(l, len(conversion.py2ri.registry)) self.assertEqual(k, set(conversion.py2ri.registry.keys())) def checkHomogeneous(self, obj, mode, storage_mode): converted = conversion.py2ri(obj) self.assertEqual(r["mode"](converted)[0], mode) self.assertEqual(r["storage.mode"](converted)[0], storage_mode) self.assertEqual(list(obj), list(converted)) self.assertTrue(r["is.array"](converted)[0]) return converted def testVectorBoolean(self): l = [True, False, True] b = numpy.array(l, dtype=numpy.bool_) b_r = self.checkHomogeneous(b, "logical", "logical") self.assertTupleEqual(tuple(l), tuple(b_r)) def testVectorInteger(self): l = [1, 2, 3] i = numpy.array(l, dtype="i") i_r = self.checkHomogeneous(i, "numeric", "integer") self.assertTupleEqual(tuple(l), tuple(i_r)) def testVectorFloat(self): l = [1.0, 2.0, 3.0] f = numpy.array(l, dtype="f") f_r = self.checkHomogeneous(f, "numeric", "double") for orig, conv in zip(l, f_r): self.assertTrue(abs(orig-conv) < 0.000001) def testVectorComplex(self): l = [1j, 2j, 3j] c = numpy.array(l, dtype=numpy.complex_) c_r = self.checkHomogeneous(c, "complex", "complex") for orig, conv in zip(l, c_r): self.assertTrue(abs(orig.real-conv.real) < 0.000001) self.assertTrue(abs(orig.imag-conv.imag) < 0.000001) @unittest.skipUnless(sys.version_info[0] < 3, "Test only relevant if Python < 3.") def testVectorCharacter(self): l = ["a", "b", "c"] s = numpy.array(l, dtype="S") s_r = self.checkHomogeneous(s, "character", "character") self.assertTupleEqual(tuple(l), tuple(s_r)) def testVectorUnicodeCharacter(self): l = [u"a", u"b", u"c"] u = numpy.array(l, dtype="U") u_r = self.checkHomogeneous(u, "character", "character") self.assertTupleEqual(tuple(l), tuple(u_r)) def testArray(self): i2d = numpy.array([[1, 2, 3], [4, 5, 6]], dtype="i") i2d_r = conversion.py2ri(i2d) self.assertEqual(r["storage.mode"](i2d_r)[0], "integer") self.assertEqual(tuple(r["dim"](i2d_r)), (2, 3)) # Make sure we got the row/column swap right: self.assertEqual(r["["](i2d_r, 1, 2)[0], i2d[0, 1]) f3d = numpy.arange(24, dtype="f").reshape((2, 3, 4)) f3d_r = conversion.py2ri(f3d) self.assertEqual(r["storage.mode"](f3d_r)[0], "double") self.assertEqual(tuple(r["dim"](f3d_r)), (2, 3, 4)) # Make sure we got the row/column swap right: self.assertEqual(r["["](f3d_r, 1, 2, 3)[0], f3d[0, 1, 2]) def testScalar(self): i32 = numpy.int32(100) i32_r = conversion.py2ri(i32) i32_test = numpy.array(i32_r)[0] self.assertEqual(i32, i32_test) i64 = numpy.int64(100) i64_r = conversion.py2ri(i64) i64_test = numpy.array(i64_r)[0] self.assertEqual(i64, i64_test) f128 = numpy.float128(100.000000003) f128_r = conversion.py2ri(f128) f128_test = numpy.array(f128_r)[0] self.assertEqual(f128, f128_test) def testObjectArray(self): o = numpy.array([1, "a", 3.2], dtype=numpy.object_) o_r = conversion.py2ri(o) self.assertEqual(r["mode"](o_r)[0], "list") self.assertEqual(r["[["](o_r, 1)[0], 1) self.assertEqual(r["[["](o_r, 2)[0], "a") self.assertEqual(r["[["](o_r, 3)[0], 3.2) def testRecordArray(self): rec = numpy.array([(1, 2.3), (2, -0.7), (3, 12.1)], dtype=[("count", "i"), ("value", numpy.double)]) rec_r = conversion.py2ri(rec) self.assertTrue(r["is.data.frame"](rec_r)[0]) self.assertEqual(tuple(r["names"](rec_r)), ("count", "value")) count_r = r["$"](rec_r, "count") value_r = r["$"](rec_r, "value") self.assertEqual(r["storage.mode"](count_r)[0], "integer") self.assertEqual(r["storage.mode"](value_r)[0], "double") self.assertEqual(count_r[1], 2) self.assertEqual(value_r[2], 12.1) def testBadArray(self): u = numpy.array([1, 2, 3], dtype=numpy.uint32) self.assertRaises(ValueError, conversion.py2ri, u) def testAssignNumpyObject(self): x = numpy.arange(-10., 10., 1) env = robjects.Environment() env["x"] = x self.assertEqual(1, len(env)) # do have an R object of the right type ? x_r = env["x"] self.assertEqual(robjects.rinterface.REALSXP, x_r.typeof) # self.assertEqual((20,), tuple(x_r.dim)) def testDataFrameToNumpy(self): df = robjects.vectors.DataFrame(dict((('a', 1), ('b', 2)))) rec = conversion.ri2py(df) self.assertEqual(numpy.recarray, type(rec)) self.assertEqual(1, rec.a[0]) self.assertEqual(2, rec.b[0]) def testAtomicVectorToNumpy(self): v = robjects.vectors.IntVector((1,2,3)) a = rpyn.ri2py(v) self.assertTrue(isinstance(a, numpy.ndarray)) self.assertEqual(1, v[0]) def testRx2(self): df = robjects.vectors.DataFrame({ "A": robjects.vectors.IntVector([1,2,3]), "B": robjects.vectors.IntVector([1,2,3])}) b = df.rx2('B') self.assertEquals(tuple((1,2,3)), tuple(b)) def suite(): if has_numpy: return unittest.TestLoader().loadTestsFromTestCase(NumpyConversionsTestCase) else: return unittest.TestLoader().loadTestsFromTestCase(MissingNumpyDummyTestCase) if __name__ == '__main__': unittest.main() rpy2-2.7.8/rpy/robjects/tests/testVector.py0000664000175000017500000003265212632564573022124 0ustar laurentlaurent00000000000000import unittest import rpy2.robjects as robjects ri = robjects.rinterface import array, time, sys import time import datetime import rpy2.rlike.container as rlc from collections import OrderedDict if sys.version_info[0] == 2: range = xrange rlist = robjects.baseenv["list"] class VectorTestCase(unittest.TestCase): def testNew(self): identical = ri.baseenv["identical"] py_a = array.array('i', [1,2,3]) ro_v = robjects.Vector(py_a) self.assertEqual(ro_v.typeof, ri.INTSXP) ri_v = ri.SexpVector(py_a, ri.INTSXP) ro_v = robjects.Vector(ri_v) self.assertTrue(identical(ro_v, ri_v)[0]) del(ri_v) self.assertEqual(ri.INTSXP, ro_v.typeof) def testNewStrVector(self): vec = robjects.StrVector(['abc', 'def']) self.assertEqual('abc', vec[0]) self.assertEqual('def', vec[1]) self.assertEqual(2, len(vec)) def testNewIntVector(self): vec = robjects.IntVector([123, 456]) self.assertEqual(123, vec[0]) self.assertEqual(456, vec[1]) self.assertEqual(2, len(vec)) def testNewFloatVector(self): vec = robjects.FloatVector([123.0, 456.0]) self.assertEqual(123.0, vec[0]) self.assertEqual(456.0, vec[1]) self.assertEqual(2, len(vec)) def testNewBoolVector(self): vec = robjects.BoolVector([True, False]) self.assertEqual(True, vec[0]) self.assertEqual(False, vec[1]) self.assertEqual(2, len(vec)) def _testNewListVector(self, vec): self.assertTrue('a' in vec.names) self.assertTrue('b' in vec.names) self.assertEqual(2, len(vec)) self.assertEqual(2, len(vec.names)) def testNewListVector(self): vec = robjects.ListVector({'a': 1, 'b': 2}) self._testNewListVector(vec) s = (('a', 1), ('b', 2)) vec = robjects.ListVector(s) self._testNewListVector(vec) it = iter(s) vec = robjects.ListVector(s) self._testNewListVector(vec) def testAddOperators(self): seq_R = robjects.r["seq"] mySeqA = seq_R(0, 3) mySeqB = seq_R(5, 7) mySeqAdd = mySeqA + mySeqB self.assertEqual(len(mySeqA)+len(mySeqB), len(mySeqAdd)) for i, li in enumerate(mySeqA): self.assertEqual(li, mySeqAdd[i]) for j, li in enumerate(mySeqB): self.assertEqual(li, mySeqAdd[i+j+1]) def testRAddOperators(self): seq_R = robjects.r["seq"] mySeq = seq_R(0, 10) mySeqAdd = mySeq.ro + 2 for i, li in enumerate(mySeq): self.assertEqual(li + 2, mySeqAdd[i]) def testRMultOperators(self): seq_R = robjects.r["seq"] mySeq = seq_R(0, 10) mySeqAdd = mySeq.ro + mySeq for i, li in enumerate(mySeq): self.assertEqual(li * 2, mySeqAdd[i]) def testRPowerOperator(self): seq_R = robjects.r["seq"] mySeq = seq_R(0, 10) mySeqPow = mySeq.ro ** 2 for i, li in enumerate(mySeq): self.assertEqual(li ** 2, mySeqPow[i]) def testGetItem(self): letters = robjects.baseenv["letters"] self.assertEqual('a', letters[0]) self.assertEqual('z', letters[25]) def testGetItemOutOfBounds(self): letters = robjects.baseenv["letters"] self.assertRaises(IndexError, letters.__getitem__, 26) def testSetItem(self): vec = robjects.r.seq(1, 10) vec[0] = 20 self.assertEqual(20, vec[0]) def testSetItemOutOfBounds(self): vec = robjects.r.seq(1, 10) self.assertRaises(IndexError, vec.__setitem__, 20, 20) def getItemList(self): mylist = rlist(letters, "foo") idem = robjects.baseenv["identical"] self.assertTrue(idem(letters, mylist[0])) self.assertTrue(idem("foo", mylist[1])) def testGetNames(self): vec = robjects.Vector(array.array('i', [1,2,3])) v_names = [robjects.baseenv["letters"][x] for x in (0,1,2)] #FIXME: simplify this r_names = robjects.baseenv["c"](*v_names) vec = robjects.baseenv["names<-"](vec, r_names) for i in range(len(vec)): self.assertEqual(v_names[i], vec.names[i]) vec.names[0] = 'x' def testSetNames(self): vec = robjects.Vector(array.array('i', [1,2,3])) names = ['x', 'y', 'z'] vec.names = names for i in range(len(vec)): self.assertEqual(names[i], vec.names[i]) def testNAInteger(self): vec = robjects.IntVector(range(3)) vec[0] = robjects.NA_Integer self.assertTrue(robjects.baseenv['is.na'](vec)[0]) def testNAReal(self): vec = robjects.FloatVector((1.0, 2.0, 3.0)) vec[0] = robjects.NA_Real self.assertTrue(robjects.baseenv['is.na'](vec)[0]) def testNALogical(self): vec = robjects.BoolVector((True, False, True)) vec[0] = robjects.NA_Logical self.assertTrue(robjects.baseenv['is.na'](vec)[0]) def testNAComplex(self): vec = robjects.ComplexVector((1+1j, 2+2j, 3+3j)) vec[0] = robjects.NA_Complex self.assertTrue(robjects.baseenv['is.na'](vec)[0]) def testNACharacter(self): vec = robjects.StrVector('abc') vec[0] = robjects.NA_Character self.assertTrue(robjects.baseenv['is.na'](vec)[0]) def testRepr(self): vec = robjects.IntVector((1,2,3)) s = repr(vec).split('\n') self.assertEqual('[ 1, 2, 3]', s[1]) def testReprNonVectorInList(self): vec = robjects.ListVector(OrderedDict((('a', 1), ('b', robjects.Formula('y ~ x')), ))) s = repr(vec).split('\n') self.assertEqual('[IntVector, Formula]', s[1].strip()) def testItems(self): vec = robjects.IntVector(range(3)) vec.names = robjects.StrVector('abc') names = [k for k,v in vec.items()] self.assertEqual(['a', 'b', 'c'], names) values = [v for k,v in vec.items()] self.assertEqual([0, 1, 2], values) def testItemsNoNames(self): vec = robjects.IntVector(range(3)) names = [k for k,v in vec.items()] self.assertEqual([None, None, None], names) values = [v for k,v in vec.items()] self.assertEqual([0, 1, 2], values) class FactorVectorTestCase(unittest.TestCase): def testNew(self): vec = robjects.FactorVector(robjects.StrVector('abaabc')) self.assertEqual(6, len(vec)) def testIsordered(self): vec = robjects.FactorVector(robjects.StrVector('abaabc')) self.assertFalse(vec.isordered) def testNlevels(self): vec = robjects.FactorVector(robjects.StrVector('abaabc')) self.assertEqual(3, vec.nlevels) def testLevels(self): vec = robjects.FactorVector(robjects.StrVector('abaabc')) self.assertEqual(3, len(vec.levels)) self.assertEqual(set(('a','b','c')), set(tuple(vec.levels))) def testIter_labels(self): values = 'abaabc' vec = robjects.FactorVector(robjects.StrVector(values)) it = vec.iter_labels() for a, b in zip(values, it): self.assertEqual(a, b) def testFactorWithAttrs(self): # issue #299 r_src = """ x <- factor(c("a","b","a")) attr(x, "foo") <- "bar" x """ x = robjects.r(r_src) self.assertTrue('foo' in x.list_attrs()) _dateval_tuple = (1984, 1, 6, 6, 22, 0, 1, 6, 0) class DateTimeVectorTestCase(unittest.TestCase): def setUp(self): time.accept2dyear = False def tearDown(self): pass def testPOSIXlt_fromInvalidPythonTime(self): x = [time.struct_time(_dateval_tuple), time.struct_time(_dateval_tuple)] x.append('foo') self.assertRaises(ValueError, robjects.POSIXlt, x) def testPOSIXlt_fromPythonTime(self): x = [time.struct_time(_dateval_tuple), time.struct_time(_dateval_tuple)] res = robjects.POSIXlt(x) self.assertEqual(2, len(x)) def testPOSIXct_fromInvalidPythonTime(self): x = [time.struct_time(_dateval_tuple), time.struct_time(_dateval_tuple)] x.append('foo') # string 'foo' does not have attribute 'tm_zone' self.assertRaises(AttributeError, robjects.POSIXct, x) def testPOSIXct_fromPythonTime(self): x = [time.struct_time(_dateval_tuple), time.struct_time(_dateval_tuple)] res = robjects.POSIXct(x) self.assertEqual(2, len(x)) def testPOSIXct_fromPythonDatetime(self): x = [datetime.datetime(*_dateval_tuple[:-2]), datetime.datetime(*_dateval_tuple[:-2])] res = robjects.POSIXct(x) self.assertEqual(2, len(x)) def testPOSIXct_fromSexp(self): sexp = robjects.r('ISOdate(2013, 12, 11)') res = robjects.POSIXct(sexp) self.assertEqual(1, len(res)) class ExtractDelegatorTestCase(unittest.TestCase): def setUp(self): self.console = robjects.rinterface.get_writeconsole_regular() def tearDown(self): robjects.rinterface.set_writeconsole_regular(self.console) def testFloorDivision(self): v = robjects.vectors.IntVector((2,3,4)) if sys.version_info[0] == 2: res = v.ro / 2 else: res = v.ro // 2 self.assertEqual((1,1,2), tuple(int(x) for x in res)) def testExtractByIndex(self): seq_R = robjects.baseenv["seq"] mySeq = seq_R(0, 10) # R indexing starts at one myIndex = robjects.Vector(array.array('i', range(1, 11, 2))) mySubset = mySeq.rx(myIndex) for i, si in enumerate(myIndex): self.assertEqual(mySeq[si-1], mySubset[i]) def testExtractByName(self): seq_R = robjects.baseenv["seq"] mySeq = seq_R(0, 25) letters = robjects.baseenv["letters"] mySeq = robjects.baseenv["names<-"](mySeq, letters) # R indexing starts at one myIndex = robjects.Vector(letters[2]) mySubset = mySeq.rx(myIndex) for i, si in enumerate(myIndex): self.assertEqual(2, mySubset[i]) def testExtractIndexError(self): seq_R = robjects.baseenv["seq"] mySeq = seq_R(0, 10) # R indexing starts at one myIndex = robjects.Vector(['a', 'b', 'c']) def noconsole(x): pass robjects.rinterface.set_writeconsole_regular(noconsole) self.assertRaises(ri.RRuntimeError, mySeq.rx, myIndex) def testReplace(self): vec = robjects.IntVector(range(1, 6)) i = array.array('i', [1, 3]) vec.rx[rlc.TaggedList((i, ))] = 20 self.assertEqual(20, vec[0]) self.assertEqual(2, vec[1]) self.assertEqual(20, vec[2]) self.assertEqual(4, vec[3]) vec = robjects.IntVector(range(1, 6)) i = array.array('i', [1, 5]) vec.rx[rlc.TaggedList((i, ))] = 50 self.assertEqual(50, vec[0]) self.assertEqual(2, vec[1]) self.assertEqual(3, vec[2]) self.assertEqual(4, vec[3]) self.assertEqual(50, vec[4]) vec = robjects.IntVector(range(1, 6)) vec.rx[1] = 70 self.assertEqual(70, vec[0]) self.assertEqual(2, vec[1]) self.assertEqual(3, vec[2]) self.assertEqual(4, vec[3]) self.assertEqual(5, vec[4]) vec = robjects.IntVector(range(1, 6)) vec.rx[robjects.IntVector((1, 3))] = 70 self.assertEqual(70, vec[0]) self.assertEqual(2, vec[1]) self.assertEqual(70, vec[2]) self.assertEqual(4, vec[3]) self.assertEqual(5, vec[4]) m = robjects.r('matrix(1:10, ncol=2)') m.rx[1, 1] = 9 self.assertEqual(9, m[0]) m = robjects.r('matrix(1:10, ncol=2)') m.rx[2, robjects.IntVector((1,2))] = 9 self.assertEqual(9, m[1]) self.assertEqual(9, m[6]) def testExtractRecyclingRule(self): # recycling rule v = robjects.Vector(array.array('i', range(1, 23))) m = robjects.r.matrix(v, ncol = 2) col = m.rx(True, 1) self.assertEqual(11, len(col)) def testExtractList(self): # list letters = robjects.baseenv["letters"] myList = rlist(l=letters, f="foo") idem = robjects.baseenv["identical"] self.assertTrue(idem(letters, myList.rx("l")[0])) self.assertTrue(idem("foo", myList.rx("f")[0])) class ConversionHelperTestCase(unittest.TestCase): def testSequenceToVector(self): res = robjects.sequence_to_vector((1,2,3)) self.assertTrue(isinstance(res, robjects.IntVector)) res = robjects.sequence_to_vector((1,2,3.0)) self.assertTrue(isinstance(res, robjects.FloatVector)) res = robjects.sequence_to_vector((1,2,'a')) self.assertTrue(isinstance(res, robjects.StrVector)) def suite(): suite = unittest.TestLoader().loadTestsFromTestCase(VectorTestCase) suite.addTest(unittest.TestLoader().loadTestsFromTestCase(FactorVectorTestCase)) suite.addTest(unittest.TestLoader().loadTestsFromTestCase(DateTimeVectorTestCase)) suite.addTest(unittest.TestLoader().loadTestsFromTestCase(ExtractDelegatorTestCase)) suite.addTest(unittest.TestLoader().loadTestsFromTestCase(ConversionHelperTestCase)) return suite if __name__ == '__main__': unittest.main() rpy2-2.7.8/rpy/robjects/tests/__init__.py0000664000175000017500000000034512610501355021474 0ustar laurentlaurent00000000000000import unittest from os.path import dirname def main(): tr = unittest.TextTestRunner(verbosity = 2) suite = unittest.defaultTestLoader.discover(dirname(__file__)) tr.run(suite) if __name__ == '__main__': main() rpy2-2.7.8/rpy/robjects/tests/testArray.py0000664000175000017500000001067412610501355021721 0ustar laurentlaurent00000000000000import unittest import rpy2.robjects as robjects rinterface = robjects.rinterface import array def almost_equal(x, y, epsilon = 0.00001): return abs(y - x) <= epsilon class ArrayTestCase(unittest.TestCase): def testNew(self): letters = robjects.r.letters self.assertRaises(TypeError, robjects.Array, letters) m = robjects.r.matrix(1, nrow=5, ncol=3) a = robjects.Array(m) # only tests that it runs. def testDim(self): m = robjects.r.matrix(1, nrow=5, ncol=3) a = robjects.Array(m) d = a.dim self.assertEqual(2, len(d)) self.assertEqual(5, d[0]) self.assertEqual(3, d[1]) # rd = robjects.r.rev(d) # a.dim = rd def testNamesGet(self): dimnames = robjects.r.list(robjects.StrVector(['a', 'b', 'c']), robjects.StrVector(['d', 'e'])) m = robjects.r.matrix(1, nrow=3, ncol=2, dimnames = dimnames) a = robjects.Array(m) res = a.names r_identical = robjects.r.identical self.assertTrue(r_identical(dimnames[0], res[0])) self.assertTrue(r_identical(dimnames[1], res[1])) def testNamesSet(self): dimnames = robjects.r.list(robjects.StrVector(['a', 'b', 'c']), robjects.StrVector(['d', 'e'])) m = robjects.r.matrix(1, nrow=3, ncol=2) a = robjects.Array(m) a.names = dimnames res = a.names r_identical = robjects.r.identical self.assertTrue(r_identical(dimnames[0], res[0])) self.assertTrue(r_identical(dimnames[1], res[1])) class MatrixTestCase(unittest.TestCase): def testNrowGet(self): m = robjects.r.matrix(robjects.IntVector(range(6)), nrow=3, ncol=2) self.assertEqual(3, m.nrow) def testNcolGet(self): m = robjects.r.matrix(robjects.IntVector(range(6)), nrow=3, ncol=2) self.assertEqual(2, m.ncol) def testTranspose(self): m = robjects.r.matrix(robjects.IntVector(range(6)), nrow=3, ncol=2) mt = m.transpose() for i,val in enumerate((0,1,2,3,4,5,)): self.assertEqual(val, m[i]) for i,val in enumerate((0,3,1,4,2,5)): self.assertEqual(val, mt[i]) def testCrossprod(self): m = robjects.r.matrix(robjects.IntVector(range(4)), nrow=2) mcp = m.crossprod(m) for i,val in enumerate((1.0,3.0,3.0,13.0,)): self.assertEqual(val, mcp[i]) def testTCrossprod(self): m = robjects.r.matrix(robjects.IntVector(range(4)), nrow=2) mtcp = m.tcrossprod(m) for i,val in enumerate((4,6,6,10,)): self.assertEqual(val, mtcp[i]) def testSVD(self): m = robjects.r.matrix(robjects.IntVector((1, -1, -1, 1)), nrow=2) res = m.svd() for i,val in enumerate(res.rx2("d")): self.assertTrue(almost_equal((2, 0)[i], val)) def testEigen(self): m = robjects.r.matrix(robjects.IntVector((1, -1, -1, 1)), nrow=2) res = m.eigen() for i, val in enumerate(res.rx2("values")): self.assertEqual((2, 0)[i], val) def testDot(self): m = robjects.r.matrix(robjects.IntVector(range(4)), nrow=2, ncol=2) m2 = m.dot(m) self.assertEqual((2,3,6,11), tuple(m2)) def testColnames(self): m = robjects.r.matrix(robjects.IntVector(range(4)), nrow=2, ncol=2) self.assertEqual(rinterface.NULL, m.colnames) m.colnames = robjects.StrVector(('a', 'b')) self.assertEqual(2, len(m.colnames)) self.assertEqual('a', m.colnames[0]) self.assertEqual('b', m.colnames[1]) self.assertRaises(ValueError, m.__setattr__, 'colnames', robjects.StrVector(('a', 'b', 'c'))) def testRownames(self): m = robjects.r.matrix(robjects.IntVector(range(4)), nrow=2, ncol=2) self.assertEqual(rinterface.NULL, m.rownames) m.rownames = robjects.StrVector(('c', 'd')) self.assertEqual(2, len(m.rownames)) self.assertEqual('c', m.rownames[0]) self.assertEqual('d', m.rownames[1]) self.assertRaises(ValueError, m.__setattr__, 'rownames', robjects.StrVector(('a', 'b', 'c'))) def suite(): suite = unittest.TestLoader().loadTestsFromTestCase(ArrayTestCase) suite.addTest(unittest.TestLoader().loadTestsFromTestCase(MatrixTestCase)) return suite if __name__ == '__main__': unittest.main() rpy2-2.7.8/rpy/robjects/tests/testFormula.py0000664000175000017500000000156012610501355022242 0ustar laurentlaurent00000000000000import unittest import rpy2.robjects as robjects rinterface = robjects.rinterface class FormulaTestCase(unittest.TestCase): def testNew(self): fml = robjects.Formula("y ~ x") self.assertEqual("formula", fml.rclass[0]) def testGetenvironment(self): fml = robjects.Formula("y ~ x") env = fml.getenvironment() self.assertEqual("environment", env.rclass[0]) def testSetenvironment(self): fml = robjects.Formula("y ~ x") newenv = robjects.baseenv['new.env']() env = fml.getenvironment() self.assertFalse(newenv.rsame(env)) fml.setenvironment(newenv) env = fml.getenvironment() self.assertTrue(newenv.rsame(env)) def suite(): suite = unittest.TestLoader().loadTestsFromTestCase(FormulaTestCase) return suite if __name__ == '__main__': unittest.main() rpy2-2.7.8/rpy/robjects/tests/testFunction.py0000664000175000017500000000504412610501355022423 0ustar laurentlaurent00000000000000import unittest import rpy2.robjects as robjects rinterface = robjects.rinterface import array identical = rinterface.baseenv["identical"] Function = robjects.functions.Function SignatureTranslatedFunction = robjects.functions.SignatureTranslatedFunction class FunctionTestCase(unittest.TestCase): def testNewInvalid(self): self.assertRaises(ValueError, Function, 'a') def testNewInvalid(self): ri_f = rinterface.baseenv.get('help') ro_f = Function(ri_f) self.assertTrue(identical(ri_f, ro_f)) def testCall(self): ri_f = rinterface.baseenv.get('sum') ro_f = Function(ri_f) ro_v = robjects.Vector(array.array('i', [1,2,3])) s = ro_f(ro_v) def testCallWithSexp(self): ro_f = robjects.baseenv["sum"] ri_vec = robjects.rinterface.SexpVector([1,2,3], robjects.rinterface.INTSXP) res = ro_f(ri_vec) self.assertEqual(6, res[0]) def testCallClosureWithRObject(self): ri_f = rinterface.baseenv["sum"] ro_vec = robjects.Vector(array.array('i', [1,2,3])) res = ri_f(ro_vec) self.assertEqual(6, res[0]) def testFormals(self): ri_f = robjects.r('function(x, y) TRUE') res = ri_f.formals() #FIXME: no need for as.list when paired list are handled res = robjects.r['as.list'](res) self.assertEqual(2, len(res)) n = res.names self.assertEqual("x", n[0]) self.assertEqual("y", n[1]) class SignatureTranslatedFunctionTestCase(unittest.TestCase): def testNewInvalid(self): self.assertRaises(ValueError, SignatureTranslatedFunction, 'a') def testNew(self): ri_f = rinterface.baseenv.get('rank') ro_f = SignatureTranslatedFunction(ri_f) self.assertTrue(identical(ri_f, ro_f)) @unittest.expectedFailure def testNewWithTranslation(self): ri_f = rinterface.baseenv.get('rank') ro_f = SignatureTranslatedFunction(ri_f, prm_translate = {'foo_bar': 'na.last'}) self.assertTrue(identical(ri_f, ro_f)) def testCall(self): ri_f = rinterface.baseenv.get('sum') ro_f = robjects.Function(ri_f) ro_v = robjects.Vector(array.array('i', [1,2,3])) s = ro_f(ro_v) def suite(): suite = unittest.TestLoader().loadTestsFromTestCase(FunctionTestCase) return suite if __name__ == '__main__': unittest.main() rpy2-2.7.8/rpy/robjects/tests/testDataFrame.py0000644000175000017500000001070012466035613022463 0ustar laurentlaurent00000000000000import unittest import rpy2.robjects as robjects rinterface = robjects.rinterface import rpy2.rlike.container as rlc import array import csv, tempfile class DataFrameTestCase(unittest.TestCase): def testNewFromTaggedList(self): letters = robjects.r.letters numbers = robjects.r('1:26') df = robjects.DataFrame(rlc.TaggedList((letters, numbers), tags = ('letters', 'numbers'))) self.assertEqual("data.frame", df.rclass[0]) def testNewFromRObject(self): numbers = robjects.r('1:5') self.assertRaises(ValueError, robjects.DataFrame, numbers) rfunc = robjects.r('sum') self.assertRaises(ValueError, robjects.DataFrame, rfunc) rdataf = robjects.r('data.frame(a=1:2, b=c("a", "b"))') dataf = robjects.DataFrame(rdataf) def testNewFromOrdDict(self): od = rlc.OrdDict(c=(('a', robjects.IntVector((1,2))), ('b', robjects.StrVector(('c', 'd'))) )) dataf = robjects.DataFrame(od) self.assertEqual(1, dataf.rx2('a')[0]) def testDim(self): letters = robjects.r.letters numbers = robjects.r('1:26') df = robjects.DataFrame(rlc.TaggedList((letters, numbers), tags = ('letters', 'numbers'))) self.assertEqual(26, df.nrow) self.assertEqual(2, df.ncol) def testFrom_csvfile(self): column_names = ('letter', 'value') data = (column_names, ('a', 1), ('b', 2), ('c', 3)) fh = tempfile.NamedTemporaryFile(mode = "w", delete = False) csv_w = csv.writer(fh) csv_w.writerows(data) fh.close() dataf = robjects.DataFrame.from_csvfile(fh.name) self.assertEqual(column_names, tuple(dataf.names)) self.assertEqual(3, dataf.nrow) self.assertEqual(2, dataf.ncol) def testTo_csvfile(self): fh = tempfile.NamedTemporaryFile(mode = "w", delete = False) fh.close() d = {'letter': robjects.StrVector('abc'), 'value' : robjects.IntVector((1, 2, 3))} dataf = robjects.DataFrame(d) dataf.to_csvfile(fh.name) dataf = robjects.DataFrame.from_csvfile(fh.name) self.assertEqual(3, dataf.nrow) self.assertEqual(2, dataf.ncol) def testIter_col(self): dataf = robjects.r('data.frame(a=1:2, b=I(c("a", "b")))') col_types = [x.typeof for x in dataf.iter_column()] self.assertEqual(rinterface.INTSXP, col_types[0]) self.assertEqual(rinterface.STRSXP, col_types[1]) def testIter_row(self): dataf = robjects.r('data.frame(a=1:2, b=I(c("a", "b")))') rows = [x for x in dataf.iter_row()] self.assertEqual(1, rows[0][0][0]) self.assertEqual("b", rows[1][1][0]) def testColnames(self): dataf = robjects.r('data.frame(a=1:2, b=I(c("a", "b")))') self.assertEqual('1', dataf.rownames[0]) self.assertEqual('2', dataf.rownames[1]) def testColnames_set(self): dataf = robjects.r('data.frame(a=1:2, b=I(c("a", "b")))') dataf.colnames = robjects.StrVector('de') self.assertEqual('d', dataf.colnames[0]) self.assertEqual('e', dataf.colnames[1]) def testRownames(self): dataf = robjects.r('data.frame(a=1:2, b=I(c("a", "b")))') self.assertEqual('a', dataf.colnames[0]) self.assertEqual('b', dataf.colnames[1]) def testRownames_set(self): dataf = robjects.r('data.frame(a=1:2, b=I(c("a", "b")))') dataf.rownames = robjects.StrVector('de') self.assertEqual('d', dataf.rownames[0]) self.assertEqual('e', dataf.rownames[1]) def testCbind(self): dataf = robjects.r('data.frame(a=1:2, b=I(c("a", "b")))') dataf = dataf.cbind(robjects.r('data.frame(a=1:2, b=I(c("a", "b")))')) self.assertEqual(4, dataf.ncol) self.assertEqual(2, len([x for x in dataf.colnames if x == 'a'])) def testCbind(self): dataf = robjects.r('data.frame(a=1:2, b=I(c("a", "b")))') dataf = dataf.cbind(a = robjects.StrVector(("c", "d"))) self.assertEqual(3, dataf.ncol) self.assertEqual(2, len([x for x in dataf.colnames if x == 'a'])) def suite(): suite = unittest.TestLoader().loadTestsFromTestCase(DataFrameTestCase) return suite if __name__ == '__main__': unittest.main() rpy2-2.7.8/rpy/robjects/tests/testPandasConversions.py0000664000175000017500000001227512646330000024275 0ustar laurentlaurent00000000000000import unittest import rpy2.robjects as robjects from rpy2.robjects import conversion import rpy2.rinterface as rinterface from collections import OrderedDict from datetime import datetime has_pandas = True try: import pandas import numpy has_pandas = True except: has_pandas = False if has_pandas: import rpy2.robjects.pandas2ri as rpyp @unittest.skipUnless(has_pandas, "The Python package is not installed: functionalities associated with it cannot be tested.") class PandasConversionsTestCase(unittest.TestCase): def testActivate(self): #FIXME: is the following still making sense ? self.assertNotEqual(rpyp.py2ri, robjects.conversion.py2ri) l = len(robjects.conversion.py2ri.registry) k = set(robjects.conversion.py2ri.registry.keys()) rpyp.activate() self.assertTrue(len(conversion.py2ri.registry) > l) rpyp.deactivate() self.assertEqual(l, len(conversion.py2ri.registry)) self.assertEqual(k, set(conversion.py2ri.registry.keys())) def testActivateTwice(self): #FIXME: is the following still making sense ? self.assertNotEqual(rpyp.py2ri, robjects.conversion.py2ri) l = len(robjects.conversion.py2ri.registry) k = set(robjects.conversion.py2ri.registry.keys()) rpyp.activate() rpyp.deactivate() rpyp.activate() self.assertTrue(len(conversion.py2ri.registry) > l) rpyp.deactivate() self.assertEqual(l, len(conversion.py2ri.registry)) self.assertEqual(k, set(conversion.py2ri.registry.keys())) def testDataFrame(self): l = (('b', numpy.array([True, False, True], dtype=numpy.bool_)), ('i', numpy.array([1, 2, 3], dtype="i")), ('f', numpy.array([1, 2, 3], dtype="f")), ('s', numpy.array(["a", "b", "c"], dtype="S")), ('u', numpy.array([u"a", u"b", u"c"], dtype="U")), ('dates', [datetime(2012, 5, 2), datetime(2012, 6, 3), datetime(2012, 7, 1)])) od = OrderedDict(l) pd_df = pandas.core.frame.DataFrame(od) rpyp.activate() rp_df = robjects.conversion.py2ri(pd_df) rpyp.deactivate() self.assertEqual(pd_df.shape[0], rp_df.nrow) self.assertEqual(pd_df.shape[1], rp_df.ncol) def testSeries(self): Series = pandas.core.series.Series s = Series(numpy.random.randn(5), index=['a', 'b', 'c', 'd', 'e']) rpyp.activate() rp_s = robjects.conversion.py2ri(s) rpyp.deactivate() self.assertEqual(rinterface.FloatSexpVector, type(rp_s)) def testSeries_issue264(self): Series = pandas.core.series.Series s = Series(('a', 'b', 'c', 'd', 'e'), index=pandas.Int64Index([0,1,2,3,4])) rpyp.activate() rp_s = robjects.conversion.py2ri(s) rpyp.deactivate() # segfault before the fix str(rp_s) self.assertEqual(rinterface.ListSexpVector, type(rp_s)) def testCategorical(self): factor = robjects.vectors.FactorVector(('a', 'b', 'a')) rpyp.activate() rp_c = robjects.conversion.ri2py(factor) rpyp.deactivate() self.assertEqual(pandas.Categorical, type(rp_c)) def testRepr(self): # this should go to testVector, with other tests for repr() l = (('b', numpy.array([True, False, True], dtype=numpy.bool_)), ('i', numpy.array([1, 2, 3], dtype="i")), ('f', numpy.array([1, 2, 3], dtype="f")), ('s', numpy.array(["a", "b", "c"], dtype="S")), ('u', numpy.array([u"a", u"b", u"c"], dtype="U"))) od = OrderedDict(l) pd_df = pandas.core.frame.DataFrame(od) rpyp.activate() rp_df = robjects.conversion.py2ri(pd_df) rpyp.deactivate() s = repr(rp_df) # used to fail with a TypeError s = s.split('\n') self.assertEqual('[BoolVec..., IntVector, FloatVe..., FactorV..., FactorV...]', s[1].strip()) def testRi2pandas(self): rdataf = robjects.r('data.frame(a=1:2, b=I(c("a", "b")), c=c("a", "b"))') rpyp.activate() pandas_df = robjects.conversion.ri2py(rdataf) rpyp.deactivate() self.assertIsInstance(pandas_df, pandas.DataFrame) self.assertEquals(('a', 'b', 'c'), tuple(pandas_df.keys())) self.assertEquals(pandas_df['a'].dtype, numpy.dtype('int32')) self.assertEquals(pandas_df['b'].dtype, numpy.dtype('O')) self.assertEquals(pandas_df['c'].dtype, numpy.dtype('O')) def testRi2pandas_issue207(self): d = robjects.DataFrame({'x': 1}) rpyp.activate() try: ok = True robjects.globalenv['d'] = d except ValueError: ok = False finally: rpyp.deactivate() if 'd' in robjects.globalenv: del(robjects.globalenv['d']) self.assertTrue(ok) def suite(): if has_pandas: return unittest.TestLoader().loadTestsFromTestCase(PandasConversionsTestCase) else: return unittest.TestLoader().loadTestsFromTestCase(MissingPandasDummyTestCase) if __name__ == '__main__': unittest.main(defaultTest='suite') rpy2-2.7.8/rpy/robjects/tests/testMethods.py0000664000175000017500000001025312610501355022237 0ustar laurentlaurent00000000000000import unittest import sys import six import rpy2.robjects as robjects import rpy2.robjects.methods as methods rinterface = robjects.rinterface class MethodsTestCase(unittest.TestCase): def testSet_accessors(self): robjects.r['setClass']("A", robjects.r('list(foo="numeric")')) robjects.r['setMethod']("length", signature="A", definition = robjects.r("function(x) 123")) class A(methods.RS4): def __init__(self): obj = robjects.r['new']('A') self.__sexp__ = obj.__sexp__ acs = (('length', None, True, None), ) methods.set_accessors(A, "A", None, acs) a = A() self.assertEqual(123, a.length[0]) def testRS4_TypeNoAccessors(self): robjects.r['setClass']("Foo", robjects.r('list(foo="numeric")')) if sys.version_info[0] == 2: classdef = """ from rpy2 import robjects from rpy2.robjects import methods class Foo(methods.RS4): __metaclass__ = methods.RS4_Type def __init__(self): obj = robjects.r['new']('R_A') self.__sexp__ = obj.__sexp__ """ else: classdef = """ from rpy2 import robjects from rpy2.robjects import methods class Foo(methods.RS4, metaclass = methods.RS4_Type): def __init__(self): obj = robjects.r['new']('R_A') self.__sexp__ = obj.__sexp__ """ code = compile(classdef, '', 'exec') ns = dict() exec(code, ns) f = ns['Foo']() def testRS4instance_factory(self): rclassname = 'Foo' robjects.r['setClass'](rclassname, robjects.r('list(bar="numeric")')) obj = robjects.r['new'](rclassname) f_rs4i = methods.rs4instance_factory(obj) self.assertEqual(rclassname, type(f_rs4i).__name__) def testRS4_TypeAccessors(self): robjects.r['setClass']("R_A", robjects.r('list(foo="numeric")')) robjects.r['setMethod']("length", signature="R_A", definition = robjects.r("function(x) 123")) if sys.version_info[0] == 2: classdef = """ from rpy2 import robjects from rpy2.robjects import methods class R_A(methods.RS4): __metaclass__ = methods.RS4_Type __accessors__ = (('length', None, 'get_length', False, 'get the length'), ('length', None, None, True, 'length')) def __init__(self): obj = robjects.r['new']('R_A') self.__sexp__ = obj.__sexp__ """ else: classdef = """ from rpy2 import robjects from rpy2.robjects import methods class R_A(methods.RS4, metaclass=methods.RS4_Type): __accessors__ = (('length', None, 'get_length', False, 'get the length'), ('length', None, None, True, 'length')) def __init__(self): obj = robjects.r['new']('R_A') self.__sexp__ = obj.__sexp__ """ code = compile(classdef, '', 'exec') ns = dict() exec(code, ns) R_A = ns['R_A'] class A(R_A): __rname__ = 'R_A' ra = R_A() self.assertEqual(123, ra.get_length()[0]) self.assertEqual(123, ra.length[0]) a = A() self.assertEqual(123, a.get_length()[0]) self.assertEqual(123, a.length[0]) def testGetclassdef(self): robjects.r('library(stats4)') cr = methods.getclassdef('mle', 'stats4') self.assertFalse(cr.virtual) def testRS4Auto_Type(self): robjects.r('library(stats4)') class MLE(six.with_metaclass(robjects.methods.RS4Auto_Type, robjects.methods.RS4)): __rname__ = 'mle' __rpackagename__ = 'stats4' def testRS4Auto_Type_nopackname(self): robjects.r('library(stats4)') class MLE(six.with_metaclass(robjects.methods.RS4Auto_Type, robjects.methods.RS4)): __rname__ = 'mle' def suite(): suite = unittest.TestLoader().loadTestsFromTestCase(MethodsTestCase) return suite if __name__ == '__main__': unittest.main() rpy2-2.7.8/rpy/robjects/tests/testEnvironment.py0000664000175000017500000000246212610501355023143 0ustar laurentlaurent00000000000000import unittest import rpy2.robjects as robjects rinterface = robjects.rinterface import array class EnvironmentTestCase(unittest.TestCase): def testNew(self): env = robjects.Environment() self.assertEqual(rinterface.ENVSXP, env.typeof) def testNewValueError(self): self.assertRaises(ValueError, robjects.Environment, 'a') def testSetItem(self): env = robjects.Environment() env['a'] = 123 self.assertTrue('a' in env) def testKeys(self): env = robjects.Environment() env['a'] = 123 keys = list(env.keys()) self.assertEquals(1, len(keys)) keys.sort() for it_a, it_b in zip(keys, ('a',)): self.assertEquals(it_a, it_b) def testItems(self): env = robjects.Environment() env['a'] = 123 items = list(env.items()) self.assertEquals(1, len(items)) items.sort(key=lambda x: x[0]) for it_a, it_b in zip(items, (('a', 123),)): self.assertEquals(it_a[0], it_b[0]) self.assertEquals(it_a[1][0], it_b[1]) def suite(): suite = unittest.TestLoader().loadTestsFromTestCase(EnvironmentTestCase) return suite if __name__ == '__main__': unittest.main() rpy2-2.7.8/rpy/robjects/tests/testRobjects.py0000664000175000017500000001217712610501355022416 0ustar laurentlaurent00000000000000import unittest import rpy2.robjects as robjects rinterface = robjects.rinterface import array import sys if sys.version_info[0] == 2: py3str = unicode py3bytes = str else: py3str = str py3bytes = bytes class RInstanceTestCase(unittest.TestCase): def tearDow(self): robjects.r._dotter = False def testGetItem(self): letters_R = robjects.r["letters"] self.assertTrue(isinstance(letters_R, robjects.Vector)) letters = (('a', 0), ('b', 1), ('c', 2), ('x', 23), ('y', 24), ('z', 25)) for l, i in letters: self.assertTrue(letters_R[i] == l) as_list_R = robjects.r["as.list"] seq_R = robjects.r["seq"] mySeq = seq_R(0, 10) myList = as_list_R(mySeq) for i, li in enumerate(myList): self.assertEqual(i, myList[i][0]) def testEval(self): # vector long enough to span across more than one line x = robjects.baseenv['seq'](1, 50, 2) res = robjects.r('sum(%s)' %x.r_repr()) self.assertEqual(625, res[0]) class MappingTestCase(unittest.TestCase): def testMapperR2Python_string(self): sexp = rinterface.globalenv.get("letters") ob = robjects.default_converter.ri2ro(sexp) self.assertTrue(isinstance(ob, robjects.Vector)) def testMapperR2Python_boolean(self): sexp = rinterface.globalenv.get("T") ob = robjects.default_converter.ri2ro(sexp) self.assertTrue(isinstance(ob, robjects.Vector)) def testMapperR2Python_function(self): sexp = rinterface.globalenv.get("plot") ob = robjects.default_converter.ri2ro(sexp) self.assertTrue(isinstance(ob, robjects.Function)) def testMapperR2Python_environment(self): sexp = rinterface.globalenv.get(".GlobalEnv") self.assertTrue(isinstance(robjects.default_converter.ri2ro(sexp), robjects.Environment)) def testMapperR2Python_s4(self): robjects.r('setClass("A", representation(x="integer"))') classname = rinterface.StrSexpVector(["A", ]) one = rinterface.IntSexpVector([1, ]) sexp = rinterface.globalenv.get("new")(classname, x=one) self.assertTrue(isinstance(robjects.default_converter.ri2ro(sexp), robjects.RS4)) def testMapperPy2R_integer(self): py = 1 rob = robjects.default_converter.py2ro(py) self.assertTrue(isinstance(rob, robjects.Vector)) self.assertEqual(rinterface.INTSXP, rob.typeof) def testMapperPy2R_boolean(self): py = True rob = robjects.default_converter.py2ro(py) self.assertTrue(isinstance(rob, robjects.Vector)) self.assertEqual(rinterface.LGLSXP, rob.typeof) def testMapperPy2R_py3bytes(self): py = b'houba' rob = robjects.default_converter.py2ro(py) self.assertTrue(isinstance(rob, robjects.Vector)) self.assertEqual(rinterface.STRSXP, rob.typeof) def testMapperPy2R_py3str(self): py = u'houba' self.assertTrue(isinstance(py, py3str)) rob = robjects.default_converter.py2ro(py) self.assertTrue(isinstance(rob, robjects.Vector)) self.assertEqual(rinterface.STRSXP, rob.typeof) #FIXME: more tests def testMapperPy2R_float(self): py = 1.0 rob = robjects.default_converter.py2ro(py) self.assertTrue(isinstance(rob, robjects.Vector)) self.assertEqual(rinterface.REALSXP, rob.typeof) def testMapperPy2R_complex(self): py = 1.0 + 2j rob = robjects.default_converter.py2ro(py) self.assertTrue(isinstance(rob, robjects.Vector)) self.assertEqual(rinterface.CPLXSXP, rob.typeof) def testMapperPy2R_taggedlist(self): py = robjects.rlc.TaggedList(('a', 'b'), tags=('foo', 'bar')) robj = robjects.default_converter.py2ro(py) self.assertTrue(isinstance(robj, robjects.Vector)) self.assertEqual(2, len(robj)) self.assertEqual(('foo', 'bar'), tuple(robj.names)) def testOverride_ri2ro(self): class Density(object): def __init__(self, x): self._x = x def f(obj): pyobj = robjects.default_converter.ri2ro(obj) inherits = rinterface.baseenv["inherits"] classname = rinterface.SexpVector(["density", ], rinterface.STRSXP) if inherits(pyobj, classname)[0]: pyobj = Density(pyobj) return pyobj robjects.conversion.ri2ro = f x = robjects.r.rnorm(100) d = robjects.r.density(x) self.assertTrue(isinstance(d, Density)) def suite(): suite = unittest.TestLoader().loadTestsFromTestCase(RInstanceTestCase) suite.addTest(unittest.TestLoader().loadTestsFromTestCase(MappingTestCase)) return suite if __name__ == '__main__': unittest.main() rpy2-2.7.8/rpy/robjects/tests/testHelp.py0000664000175000017500000000207412610501355021526 0ustar laurentlaurent00000000000000import unittest import rpy2.robjects as robjects import rpy2.robjects.help as rh rinterface = robjects.rinterface class PackageTestCase(unittest.TestCase): def testInit(self): base_help = rh.Package('base') self.assertEqual('base', base_help.name) def testFetch(self): base_help = rh.Package('base') f = base_help.fetch('print') self.assertTrue('title' in f.sections.keys()) class PageTestCase(unittest.TestCase): def testInit(self): base_help = rh.Package('base') p = base_help.fetch('print') self.assertEqual('title', p.sections.keys()[0]) def testToDocstring(self): base_help = rh.Package('base') p = base_help.fetch('print') ds = p.to_docstring() self.assertEqual('title', ds[:5]) #self.assertEqual('-----', ds[2]) def suite(): suite = unittest.TestLoader().loadTestsFromTestCase(PackageTestCase) suite.addTest(unittest.TestLoader().loadTestsFromTestCase(PageTestCase)) return suite if __name__ == '__main__': unittest.main() rpy2-2.7.8/rpy/robjects/tests/testRObject.py0000664000175000017500000000673312610501355022174 0ustar laurentlaurent00000000000000import unittest import rpy2.robjects as robjects rinterface = robjects.rinterface import array import tempfile class RObjectTestCase(unittest.TestCase): def testNew(self): identical = rinterface.baseenv["identical"] py_a = array.array('i', [1,2,3]) self.assertRaises(ValueError, robjects.RObject, py_a) ri_v = rinterface.SexpVector(py_a, rinterface.INTSXP) ro_v = robjects.RObject(ri_v) self.assertTrue(identical(ro_v, ri_v)[0]) del(ri_v) self.assertEqual(rinterface.INTSXP, ro_v.typeof) def testR_repr(self): obj = robjects.baseenv["pi"] s = obj.r_repr() self.assertTrue(s.startswith('3.14')) def testStr(self): prt = robjects.baseenv["pi"] s = prt.__str__() self.assertTrue(s.startswith('[1] 3.14')) def testRclass(self): self.assertEqual("character", robjects.baseenv["letters"].rclass[0]) self.assertEqual("numeric", robjects.baseenv["pi"].rclass[0]) self.assertEqual("function", robjects.globalenv.get("help").rclass[0]) def testRclass_set(self): x = robjects.r("1:3") old_class = x.rclass x.rclass = robjects.StrVector(("Foo", )) + x.rclass self.assertEqual("Foo", x.rclass[0]) self.assertEqual(old_class[0], x.rclass[1]) def testDo_slot(self): self.assertEqual("A1.4, p. 270", robjects.globalenv.get("BOD").do_slot("reference")[0]) def testSlots(self): x = robjects.r('list(a=1,b=2,c=3)') s = x.slots self.assertEqual(1, len(s)) self.assertEqual(('names', ), tuple(s.keys())) self.assertEqual(('a', 'b', 'c'), tuple(s['names'])) s['names'] = 0 self.assertEqual(1, len(s)) self.assertEqual(('names', ), tuple(s.keys())) self.assertEqual((0, ), tuple(s['names'])) import pickle class RObjectPicklingTestCase(unittest.TestCase): def testPickle(self): tmp_file = tempfile.NamedTemporaryFile() robj = robjects.baseenv["pi"] pickle.dump(robj, tmp_file) tmp_file.flush() tmp_file.seek(0) robj_again = pickle.load(tmp_file) self.assertTrue(robjects.baseenv["identical"](robj, robj_again)[0]) tmp_file.close() import rpy2.robjects.methods class RS4TestCase(unittest.TestCase): def setUp(self): robjects.r('setClass("A", representation(a="numeric", b="character"))') def tearDown(self): robjects.r('setClass("A")') def testSlotNames(self): ainstance = robjects.r('new("A", a=1, b="c")') self.assertEqual(('a', 'b'), tuple(ainstance.slotnames())) def testIsClass(self): ainstance = robjects.r('new("A", a=1, b="c")') self.assertFalse(ainstance.isclass("B")) self.assertTrue(ainstance.isclass("A")) def testValidObject(self): ainstance = robjects.r('new("A", a=1, b="c")') self.assertTrue(ainstance.validobject()) #FIXME: test invalid objects ? def suite(): suite = unittest.TestLoader().loadTestsFromTestCase(RObjectTestCase) suite.addTest(unittest.TestLoader().loadTestsFromTestCase(RObjectPicklingTestCase)) suite.addTest(unittest.TestLoader().loadTestsFromTestCase(RS4TestCase)) return suite if __name__ == '__main__': unittest.main() rpy2-2.7.8/rpy/robjects/tests/testLanguage.py0000664000175000017500000000245312610501355022362 0ustar laurentlaurent00000000000000import unittest import rpy2.robjects as robjects import rpy2.robjects.language as lg rinterface = robjects.rinterface class LanguageTestCase(unittest.TestCase): def setUp(self): for var in ('x', 'y'): if var in robjects.globalenv.keys(): #del(ro.globalenv[var]) #segfault pass def tearDown(self): for var in ('x', 'y'): if var in robjects.globalenv.keys(): #del(ro.globalenv[var]) #segfault pass def testEval(self): code = """ x <- 1+2 y <- (x+1) / 2 """ res = lg.eval(code) self.assertTrue('x' in robjects.globalenv.keys()) self.assertEqual(3, robjects.globalenv['x'][0]) self.assertTrue('y' in robjects.globalenv.keys()) self.assertEqual(2, robjects.globalenv['y'][0]) def testEvalInEnvironment(self): code = """ x <- 1+2 y <- (x+1) / 2 """ env = robjects.Environment() res = lg.eval(code, envir=env) self.assertTrue('x' in env.keys()) self.assertEqual(3, env['x'][0]) self.assertTrue('y' in env.keys()) self.assertEqual(2, env['y'][0]) def suite(): suite = unittest.TestLoader().loadTestsFromTestCase(LanguageTestCase) return suite if __name__ == '__main__': unittest.main() rpy2-2.7.8/rpy/robjects/numpy2ri.py0000664000175000017500000001335212610501355020362 0ustar laurentlaurent00000000000000import rpy2.robjects as ro import rpy2.robjects.conversion as conversion import rpy2.rinterface as rinterface from rpy2.rinterface import Sexp, SexpVector, ListSexpVector, \ LGLSXP, INTSXP, REALSXP, CPLXSXP, STRSXP, VECSXP, NULL import numpy #from rpy2.robjects.vectors import DataFrame, Vector, ListVector original_converter = None # The possible kind codes are listed at # http://numpy.scipy.org/array_interface.shtml _kinds = { # "t" -> 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 #FIXME: datetime64 ? #"datetime64": } #FIXME: the following would need further thinking & testing on # 32bits architectures _kinds['float64'] = rinterface.REALSXP _vectortypes = (rinterface.LGLSXP, rinterface.INTSXP, rinterface.REALSXP, rinterface.CPLXSXP, rinterface.STRSXP) converter = conversion.Converter('original numpy conversion') py2ri = converter.py2ri py2ro = converter.py2ro ri2py = converter.ri2py ri2ro = converter.ri2ro @py2ri.register(numpy.ndarray) def numpy2ri(o): """ Augmented conversion function, converting numpy arrays into rpy2.rinterface-level R structures. """ 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) #FIXME: no dimnames ? #FIXME: optimize what is below needed/possible ? (other ways to create R arrays ?) res = rinterface.baseenv['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.")) return res @py2ri.register(numpy.integer) def npint_py2ri(obj): return ro.int2ri(obj) @py2ri.register(numpy.floating) def npfloat_py2ri(obj): return rinterface.SexpVector([obj, ], rinterface.REALSXP) @py2ri.register(object) def nonnumpy2ri(obj): # allow array-likes to also function with this module. if not isinstance(obj, numpy.ndarray) and hasattr(obj, '__array__'): obj = obj.__array__() return ro.default_converter.py2ri(obj) else: raise original_converter.py2ri(obj) @py2ro.register(numpy.ndarray) def numpy2ro(obj): res = numpy2ri(obj) return ro.vectors.rtypeof2rotype[res.typeof](res) @ri2py.register(ListSexpVector) def ri2py_list(obj): if 'data.frame' in obj.rclass: # R "factor" vectors will not convert well by default # (will become integers), so we build a temporary list o2 # with the factors as strings. o2 = list() # An added complication is that the conversion defined # in this module will make __getitem__ at the robjects # level return numpy arrays for column in rinterface.ListSexpVector(obj): if 'factor' in column.rclass: levels = tuple(column.do_slot("levels")) column = tuple(levels[x-1] for x in column) o2.append(column) names = obj.do_slot('names') if names is NULL: res = numpy.rec.fromarrays(o2) else: res = numpy.rec.fromarrays(o2, names=tuple(names)) else: # not a data.frame, yet is it still possible to convert it res = ro.default_converter.ri2py(obj) return res @ri2py.register(Sexp) def ri2py_sexp(obj): if (obj.typeof in _vectortypes) and (obj.typeof != VECSXP): res = numpy.asarray(obj) else: res = ro.default_converter.ri2py(obj) return res def activate(): global original_converter # If module is already activated, there is nothing to do if original_converter is not None: return original_converter = conversion.converter new_converter = conversion.Converter('numpy conversion', template=original_converter) for k,v in py2ri.registry.items(): if k is object: continue new_converter.py2ri.register(k, v) for k,v in ri2ro.registry.items(): if k is object: continue new_converter.ri2ro.register(k, v) for k,v in py2ro.registry.items(): if k is object: continue new_converter.py2ro.register(k, v) for k,v in ri2py.registry.items(): if k is object: continue new_converter.ri2py.register(k, v) conversion.set_conversion(new_converter) def deactivate(): global original_converter # If module has never been activated or already deactivated, # there is nothing to do if original_converter is None: return conversion.set_conversion(original_converter) original_converter = None rpy2-2.7.8/rpy/robjects/help.py0000664000175000017500000003132512610501355017525 0ustar laurentlaurent00000000000000""" R help system. """ import sys, os from collections import namedtuple import sqlite3 import rpy2.rinterface as rinterface from rpy2.rinterface import StrSexpVector from rpy2.robjects.packages_utils import get_packagepath, _libpaths, _packages import rpy2.rlike.container as rlc if sys.version_info[0] == 2: range = xrange 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 = 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 range(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)) Item = namedtuple('Item', 'name value') 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 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(Item(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 = 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 _libpaths(): for name in _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 as hnfe: pass return tuple(res) def docstring(package, alias, sections=['usage', 'arguments']): if not isinstance(package, Package): package = Package(package) page = package.fetch(alias) return page.to_docstring(sections) rpy2-2.7.8/rpy/rinterface/0000775000175000017500000000000012654242632016536 5ustar laurentlaurent00000000000000rpy2-2.7.8/rpy/rinterface/sequence.h0000664000175000017500000000053612610501355020513 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.7.8/rpy/rinterface/array.h0000664000175000017500000000023012610501355020010 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.7.8/rpy/rinterface/sexp.c0000664000175000017500000005576612654236076017711 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) { 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 = rpy2_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) if (PyString_Size(name) == 0) { #else if (PyUnicode_GET_LENGTH(name) == 0) { #endif PyErr_SetString(PyExc_ValueError, "The name cannot be an empty 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 *name, *value; #if (PY_VERSION_HEX < 0x03010000) if (! PyArg_ParseTuple(args, "SO", &name, &value)) { return NULL; } if (PyString_Size(name) == 0) { PyErr_SetString(PyExc_ValueError, "The name cannot be an empty string"); return NULL; } name_str = PyString_AS_STRING(name); #else if (! PyArg_ParseTuple(args, "UO", &name, &value)) { return NULL; } if (PyUnicode_GetLength(name) == 0) { PyErr_SetString(PyExc_ValueError, "The name cannot be an empty string"); return NULL; } PyObject *pybytes = PyUnicode_AsLatin1String(name); name_str = PyBytes_AsString(pybytes); Py_DECREF(pybytes); #endif 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->pycount, sexpobj_new, (int)sexpobj_new->pycount); #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 = rpy2_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 -1; } 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->pycount)); #else PyObject *res = PyLong_FromLong((long)(rpyobj->sObj->pycount)); #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 = rpy2_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 = rpy2_unserialize(raw_sexp, R_GlobalEnv)); if (TYPEOF(sexp_ser) != rtype) { UNPROTECT(3); 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(3); 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.7.8/rpy/rinterface/__init__.py0000664000175000017500000001311012654236076020650 0ustar laurentlaurent00000000000000import os, sys, warnings, subprocess 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 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 = subprocess.check_output(("R", "RHOME"), universal_newlines=True) R_HOME = tmp.split(os.linesep) 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) def set_writeconsole(func): DeprecationWarning("set_writeconsole is deprecated. Use set_writeconsole_regular or set_writeconsole_warnerror") set_writeconsole_regular(func) def get_writeconsole(): DeprecationWarning("get_writeconsole is deprecated. Use get_writeconsole_regular or get_writeconsole_warnerror") return get_writeconsole_regular() set_writeconsole_regular(consolePrint) set_writeconsole_warnerror(warnings.warn) def consoleFlush(): sys.stdout.flush() set_flushconsole(consoleFlush) # wrapper in case someone changes sys.stdout: if sys.version_info.major == 3: # 'raw_input()' became 'input()' in Python 3 def consoleRead(prompt): text = input(prompt) text += "\n" return text else: 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.7.8/rpy/rinterface/r_utils.h0000664000175000017500000000123412614110057020357 0ustar laurentlaurent00000000000000#ifndef RPY_RU_H #define RPY_RU_H #include #include SEXP rpy2_serialize(SEXP object, SEXP rho); SEXP rpy2_unserialize(SEXP connection, SEXP rho); SEXP rpy2_remove(SEXP symbol, SEXP environment, SEXP rho); SEXP rpy2_list_attr(SEXP sexp); SEXP rpy2_lang2str(SEXP sexp, SEXPTYPE t); SEXP externallymanaged_vector(SEXPTYPE rtype, void *array, int length); SEXP rpy2_newenv(SEXP hash, SEXP parent, SEXP size); int rpy2_isinitialized(void); int rpy2_setinitialized(void); typedef struct { int rfree; void *array; } ExternallyManagedVector; SEXP rpy2_findfun(SEXP symbol, SEXP rho); #define __RPY_RSVN_SWITCH_VERSION__ 134914 #endif rpy2-2.7.8/rpy/rinterface/null_value.h0000664000175000017500000000035112610501355021044 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.7.8/rpy/rinterface/na_values.c0000664000175000017500000007613412610501355020662 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.7.8/rpy/rinterface/_rpy_device.c0000664000175000017500000012374612610501355021177 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 "r_utils.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 = rpy2_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 (!rpy2_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 (!rpy2_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.7.8/rpy/rinterface/buffer.h0000664000175000017500000000030312610501355020144 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.7.8/rpy/rinterface/_rinterface.h0000664000175000017500000002243112654236076021177 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 /* -- SexpObject-begin -- */ typedef struct { Py_ssize_t pycount; int rcount; SEXP sexp; } SexpObject; /* -- SexpObject-end -- */ 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]) /* 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.7.8/rpy/rinterface/array.c0000664000175000017500000001475212610501355020021 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.7.8/rpy/rinterface/rpy_device.h0000664000175000017500000000452212610501355021033 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.7.8/rpy/rinterface/sexp.h0000664000175000017500000000060012610501355017652 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.7.8/rpy/rinterface/_rinterface.c0000775000175000017500000035271612654236076021211 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-2015 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 "buffer.c" #include "array.c" #include "sequence.c" #include "rexternalptr.c" /* A tuple that holds options to initialize R */ static PyObject *initOptions; static SEXP errMessage_SEXP; static PyObject *RPyExc_RuntimeError = NULL; static PyObject *RPyExc_ParsingError = NULL; static PyObject *RPyExc_ParsingIncompleteError = 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 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* writeConsoleRegularCallback = NULL; static PyObject* EmbeddedR_setWriteConsoleRegular(PyObject *self, PyObject *args) { PyObject *res = EmbeddedR_setAnyCallback(self, args, &writeConsoleRegularCallback); return res; } PyDoc_STRVAR(EmbeddedR_setWriteConsoleRegular_doc, "set_writeconsole_regular(f)\n\n" "Set how to handle regular 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* writeConsoleWarnErrorCallback = NULL; static PyObject* EmbeddedR_setWriteConsoleWarnError(PyObject *self, PyObject *args) { PyObject *res = EmbeddedR_setAnyCallback(self, args, &writeConsoleWarnErrorCallback); return res; } PyDoc_STRVAR(EmbeddedR_setWriteConsoleWarnError_doc, "set_writeconsole_warnerror(f)\n\n" "Set how to handle warning or error 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_getWriteConsoleRegular(PyObject *self, PyObject *args) { return EmbeddedR_getAnyCallback(self, args, writeConsoleRegularCallback); } PyDoc_STRVAR(EmbeddedR_getWriteConsoleRegular_doc, "get_writeconsole_regular()\n\n" "Retrieve the current R console output handler" " (see set_writeconsole_regular)"); static PyObject * EmbeddedR_getWriteConsoleWarnError(PyObject *self, PyObject *args) { return EmbeddedR_getAnyCallback(self, args, writeConsoleWarnErrorCallback); } PyDoc_STRVAR(EmbeddedR_getWriteConsoleWarnError_doc, "get_writeconsole_warnerror()\n\n" "Retrieve the current R console output handler for warnings and errors." " (see set_writeconsole_warnerror)"); static void EmbeddedR_WriteConsoleEx(const char *buf, int len, int otype) { /* otype can be 0: regular output or 1: error or warning */ void *consolecallback; switch(otype) { case 0: consolecallback = writeConsoleRegularCallback; break; case 1: consolecallback = writeConsoleWarnErrorCallback; break; default: printf("unknown otype in EmbeddedR_WriteConsoleEx.\n"); } 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 (consolecallback == NULL) { return; } result = PyEval_CallObject(consolecallback, 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); /* 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* resetConsoleCallback = 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 of the R console with either None" " or a function f such as f() returns None" " (f only has side effects)."); static PyObject* EmbeddedR_setResetConsole(PyObject *self, PyObject *args) { return EmbeddedR_setAnyCallback(self, args, &resetConsoleCallback); } PyDoc_STRVAR(EmbeddedR_setResetConsole_doc, "set_resetconsole(f)\n\n" "Set how to handle the reset R console 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 * EmbeddedR_getResetConsole(PyObject *self, PyObject *args) { return EmbeddedR_getAnyCallback(self, args, resetConsoleCallback); } PyDoc_STRVAR(EmbeddedR_getResetConsole_doc, "get_resetconsole()\n\n" "Retrieve the current R handler to reset the console" " (see set_resetconsole)"); static void EmbeddedR_ResetConsole(void) { const int is_threaded = PyEval_ThreadsInitialized(); PyGILState_STATE gstate; RPY_GIL_ENSURE(is_threaded, gstate); //PyObject *result (returned by call below); if (resetConsoleCallback != NULL) { PyEval_CallObject(resetConsoleCallback, 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); //char *path_str = PyBytes_AsString(result); #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()*/ } PyDoc_STRVAR(EmbeddedR_init_doc, "Initialize an embedded R.\n" "initr(r_preservehash=False) -> return code (an integer)\n" "\nThe optional argument r_preservehash is using an hash of " "the memory address as a key in an R environment to " "preserve R objects from garbage collection."); static PyObject* EmbeddedR_init(PyObject *self, PyObject *args, PyObject *kwds) { 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; */ } PyObject *preservehash = Py_False; static char *kwlist[] = {"r_preservehash", NULL}; if (! PyArg_ParseTupleAndKeywords(args, kwds, "|O!", kwlist, &PyBool_Type, &preservehash) ){ 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; /* Force use of WriteConsoleEx */ Rp->WriteConsoleEx = EmbeddedR_WriteConsoleEx; Rp->Busy = Re_Busy; Rp->ShowMessage = EmbeddedR_ShowMessage; /* Rp->FlushConsole = EmbeddedR_FlushConsole; */ Rp->ResetConsole = EmbeddedR_ResetConsole; 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 = NULL; /* Force use of WriteConsoleEx */ ptr_R_WriteConsoleEx = EmbeddedR_WriteConsoleEx; ptr_R_FlushConsole = EmbeddedR_FlushConsole; ptr_R_ResetConsole = EmbeddedR_ResetConsole; 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(); embeddedR_status = RPY_R_INITIALIZED; if (rpy2_setinitialized()) { printf("R is already initialized !"); } 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. */ } /* FIXME: Attempt at using an R container distinct from R's PreciousList */ /* (currently replaced by a Python dict and R's PreciousList) */ if (preservehash == Py_True) { PROTECT( RPY_R_PreciousEnv = rpy2_newenv(Rf_ScalarLogical(TRUE), R_GlobalEnv, Rf_ScalarInteger(29)) ); R_PreserveObject(RPY_R_PreciousEnv); UNPROTECT(1); } return res; } 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(PyObject *PythonException_Type) { 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); //RPyExc_RuntimeError //PyErr_SetString(RPyExc_RuntimeError, message); PyErr_SetString(PythonException_Type, 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)); switch(status) { case PARSE_OK: cmdpy = newPySexpObject(cmdexpr); break; case PARSE_INCOMPLETE: PyErr_SetString(RPyExc_ParsingIncompleteError, "Incomplete R code statement."); cmdpy = NULL; break; default: EmbeddedR_exception_from_errmessage(RPyExc_ParsingError); cmdpy = NULL; break; } 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(RPyExc_RuntimeError); } } 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 = rpy2_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 PyObject* EnvironmentSexp_keys(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, sexp_item; PROTECT(symbols = R_lsInternal(rho_R, TRUE)); int l = LENGTH(symbols); PyObject *keys = PyTuple_New(l); PyObject *val; int i; for (i=0; i= 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; } /* use R's "get" */ SEXP rsymb_internal = Rf_install(".Internal"); SEXP rsymb_get = Rf_install("get"); SEXP rlang_get = Rf_lang5(rsymb_get, Rf_mkString(name), // x rho_R, Rf_mkString("any"), Rf_ScalarLogical(FALSE)); SEXP rcall_get = Rf_lang2(rsymb_internal, rlang_get); int errorOccurred = 0; res_R = R_tryEval(rcall_get, R_GlobalEnv, &errorOccurred); if (errorOccurred) { /* /\* 2 options here: no such key, or the somewhat entertaining */ /* "error on retrieve" (see issue #251) *\/ */ SEXP rsymb_exists = Rf_install("exists"); SEXP rlang_exists = Rf_lang5(rsymb_exists, Rf_mkString(name), // x rho_R, Rf_mkString("any"), Rf_ScalarLogical(FALSE)); SEXP rcall_exists = Rf_lang2(rsymb_internal, rlang_exists); res_R = R_tryEvalSilent(rcall_exists, R_GlobalEnv, &errorOccurred); if (! asLogical(res_R)) { /* Error because of a missing key */ PyErr_Format(PyExc_LookupError, "'%s' not found", name); #if (PY_VERSION_HEX >= 0x03010000) Py_DECREF(pybytes); #endif embeddedR_freelock(); return NULL; } else { /* Retrieving the value associated with an existing key triggers an error in R. Don't ask. This is R. */ res_R = R_NilValue; EmbeddedR_exception_from_errmessage(RPyExc_RuntimeError); #if (PY_VERSION_HEX >= 0x03010000) Py_DECREF(pybytes); #endif embeddedR_freelock(); return NULL; } } else { /* No error */ #if (PY_VERSION_HEX >= 0x03010000) Py_DECREF(pybytes); #endif embeddedR_freelock(); return newPySexpObject(res_R); } } 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 = rpy2_remove(Rf_mkString(name), rho_R, Rf_ScalarLogical(FALSE)); 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(SymbolSexp_Type_doc, "R symbol"); static int SymbolSexp_init(PyObject *self, PyObject *args, PyObject *kwds); static PyObject* SymbolSexp_tp_str(PySexpObject *self) { SEXP sexp = RPY_SEXP(self); /* if (! sexp) { * PyErr_Format(PyExc_ValueError, "NULL SEXP."); * return NULL; *} */ const char* string = CHAR(PRINTNAME(sexp)); #if (PY_VERSION_HEX < 0x03010000) return PyString_FromString(string); #else return PyUnicode_FromString(string); #endif } static PyTypeObject SymbolSexp_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.SexpSymbol", /*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*/ (reprfunc)SymbolSexp_tp_str, /*tp_str*/ 0, /*tp_getattro*/ 0, /*tp_setattro*/ 0, /*tp_as_buffer*/ Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /*tp_flags*/ SymbolSexp_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)SymbolSexp_init, /*tp_init*/ 0, /*tp_alloc*/ /* FIXME: add new method */ 0, /*tp_new*/ 0, /*tp_free*/ 0 /*tp_is_gc*/ }; static int SymbolSexp_init(PyObject *self, PyObject *args, PyObject *kwds) { PyObject *pysymbol; PyObject *copy = Py_False; static char *kwlist[] = {"pysymbol", "copy", NULL}; /* FIXME: handle the copy argument */ if (! PyArg_ParseTupleAndKeywords(args, kwds, "O|O!", kwlist, &pysymbol, &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(); SEXP rres = R_NilValue; /* Allow initialization from SYMSXP or from a Python string */ int alreadySymbol = PyObject_IsInstance(pysymbol, (PyObject*)&SymbolSexp_Type); if (alreadySymbol) { /* call parent's constructor */ if (Sexp_init(self, args, NULL) == -1) { PyErr_Format(PyExc_RuntimeError, "Error initializing instance."); embeddedR_freelock(); return -1; } } #if (PY_VERSION_HEX < 0x03010000) else if (PyString_Check(pysymbol)) { rres = Rf_install(PyString_AS_STRING(pysymbol)); } else if (PyUnicode_Check(pysymbol)) { PyObject *utf8_str = PyUnicode_AsUTF8String(pysymbol); if (utf8_str == NULL) { //UNPROTECT(1); PyErr_Format(PyExc_ValueError, "Error raised by codec for symbol."); return -1; } PyErr_Format(PyExc_ValueError, "R symbol from UTF-8 is not yet implemented."); return -1; const char *string = PyString_AsString(utf8_str); rres = install(string); Py_XDECREF(utf8_str); } #else /* Only difference with Python < 3.1 is that PyString case is dropped. Technically a macro would avoid code duplication. */ else if (PyUnicode_Check(pysymbol)) { PyObject *utf8_str = PyUnicode_AsUTF8String(pysymbol); if (utf8_str == NULL) { //UNPROTECT(1); PyErr_Format(PyExc_ValueError, "Error raised by codec for symbol"); return -1; } const char *string = PyBytes_AsString(utf8_str); rres = install(string); Py_XDECREF(utf8_str); } #endif else { PyErr_Format(PyExc_ValueError, "Cannot instantiate from this type."); embeddedR_freelock(); return -1; } if (Rpy_ReplaceSexp((PySexpObject *)self, rres) == -1) { embeddedR_freelock(); return -1; } #ifdef RPY_VERBOSE printf("done.\n"); #endif embeddedR_freelock(); return 0; } /* 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 SYMSXP: object = (PySexpObject *)Sexp_new(&SymbolSexp_Type, Py_None, Py_None); 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: object = (PySexpObject *)Sexp_new(&FloatVectorSexp_Type, Py_None, Py_None); break; case INTSXP: object = (PySexpObject *)Sexp_new(&IntVectorSexp_Type, Py_None, Py_None); break; case LGLSXP: object = (PySexpObject *)Sexp_new(&BoolVectorSexp_Type, Py_None, Py_None); break; case STRSXP: object = (PySexpObject *)Sexp_new(&StrVectorSexp_Type, Py_None, Py_None); break; case VECSXP: object = (PySexpObject *)Sexp_new(&ListVectorSexp_Type, Py_None, Py_None); break; case CPLXSXP: object = (PySexpObject *)Sexp_new(&ComplexVectorSexp_Type, Py_None, Py_None); break; case LISTSXP: case LANGSXP: case EXPRSXP: 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(PyUnicode_AsUTF8(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_VARARGS | METH_KEYWORDS, EmbeddedR_init_doc}, {"is_initialized", (PyCFunction)EmbeddedR_isInitialized, METH_NOARGS, EmbeddedR_isInitialized_doc}, {"endr", (PyCFunction)EmbeddedR_end, METH_O, EmbeddedR_end_doc}, {"set_interactive", (PyCFunction)EmbeddedR_setinteractive, METH_O, EmbeddedR_setinteractive_doc}, {"set_writeconsole_regular", (PyCFunction)EmbeddedR_setWriteConsoleRegular, METH_VARARGS, EmbeddedR_setWriteConsoleRegular_doc}, {"get_writeconsole_regular", (PyCFunction)EmbeddedR_getWriteConsoleRegular, METH_VARARGS, EmbeddedR_getWriteConsoleRegular_doc}, {"set_writeconsole_warnerror", (PyCFunction)EmbeddedR_setWriteConsoleWarnError, METH_VARARGS, EmbeddedR_setWriteConsoleWarnError_doc}, {"get_writeconsole_warnerror", (PyCFunction)EmbeddedR_getWriteConsoleWarnError, METH_VARARGS, EmbeddedR_getWriteConsoleWarnError_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_resetconsole", (PyCFunction)EmbeddedR_setResetConsole, METH_VARARGS, EmbeddedR_setResetConsole_doc}, {"get_resetconsole", (PyCFunction)EmbeddedR_getResetConsole, METH_VARARGS, EmbeddedR_getResetConsole_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(&SymbolSexp_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 } /* 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(3); #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, 2, 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, 2, 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, "SexpSymbol", (PyObject *)&SymbolSexp_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); if (RPyExc_ParsingError == NULL) { RPyExc_ParsingError = \ PyErr_NewExceptionWithDoc("rpy2.rinterface.RParsingError", "Error when parsing a string as R code.", NULL, NULL); if (RPyExc_ParsingError == NULL) { #if (PY_VERSION_HEX < 0x03010000) return; #else return NULL; #endif } } Py_INCREF(RPyExc_ParsingError); PyModule_AddObject(m, "RParsingError", RPyExc_ParsingError); if (RPyExc_ParsingIncompleteError == NULL) { RPyExc_ParsingIncompleteError = \ PyErr_NewExceptionWithDoc("rpy2.rinterface.RParsingIncompleteError", "Exception raised when a string parsed as" "R code seems like an incomplete code block.", RPyExc_ParsingError, NULL); if (RPyExc_ParsingIncompleteError == NULL) { #if (PY_VERSION_HEX < 0x03010000) return; #else return NULL; #endif } } Py_INCREF(RPyExc_ParsingIncompleteError); PyModule_AddObject(m, "RParsingIncompleteError", RPyExc_ParsingIncompleteError); 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.7.8/rpy/rinterface/embeddedr.h0000664000175000017500000000140212610501355020607 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 SEXP RPY_R_PreciousEnv; 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 int Rpy_ReleaseObject(SEXP object); static inline int Rpy_ReplaceSexp(PySexpObject *pso, SEXP rObj); #endif rpy2-2.7.8/rpy/rinterface/r_utils.c0000664000175000017500000001464212654236076020377 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-2015 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 "r_utils.h" static int embeddedR_isinitialized; int rpy2_isinitialized(void) { int res = (embeddedR_isinitialized == 1) ? 1 : 0; return res; } int rpy2_setinitialized(void) { if (embeddedR_isinitialized == 1) { return 1; } else { embeddedR_isinitialized = 1; return 0; } } /* Return R_UnboundValue when not found. */ SEXP rpy2_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 rpy2_findfun.\n"); return R_UnboundValue; } } rho = ENCLOS(rho); } return R_UnboundValue; } SEXP rpy2_serialize(SEXP object, SEXP rho) { SEXP c_R, call_R, res, fun_R; PROTECT(fun_R = rpy2_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 rpy2_unserialize(SEXP connection, SEXP rho) { SEXP c_R, call_R, res, fun_R; PROTECT(fun_R = rpy2_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 rpy2_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 rpy2_remove(SEXP symbol, SEXP env, SEXP inherits) { SEXP internalSym = Rf_install(".Internal"); SEXP removeSym = Rf_install("remove"); SEXP call; PROTECT(call = Rf_lang2(internalSym, Rf_lang4(removeSym, symbol, env, inherits)) ); SEXP result = Rf_eval( call, R_GlobalEnv ) ; UNPROTECT(1); return result; } SEXP rpy2_newenv(SEXP hash, SEXP parent, SEXP size) { SEXP internalSym = Rf_install(".Internal"); SEXP newenvSym = Rf_install("new.env"); SEXP call; PROTECT(call = Rf_lang2(internalSym, Rf_lang4(newenvSym, hash, parent, size)) ); SEXP result = Rf_eval( call, R_GlobalEnv ) ; UNPROTECT(1); return result; } SEXP rpy2_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); } static void *externallymanaged_alloc(R_allocator_t *allocator, size_t length) { return ((ExternallyManagedVector *)allocator->data)->array; } static void externallymanaged_free(R_allocator_t *allocator, void *mem) { ((ExternallyManagedVector *)allocator->data)->rfree = 1; } SEXP externallymanaged_vector(SEXPTYPE rtype, void *array, int length) { R_allocator_t allocator = {externallymanaged_alloc, externallymanaged_free, 0, 0}; ExternallyManagedVector *extvector = malloc(sizeof(ExternallyManagedVector)); extvector->array = (void *) array; extvector->rfree = 0; allocator.data = extvector; return Rf_allocVector3(rtype, length, &allocator); } rpy2-2.7.8/rpy/rinterface/null_value.c0000664000175000017500000002656012610501355021051 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.7.8/rpy/rinterface/rexternalptr.h0000664000175000017500000000030512610501355021427 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.7.8/rpy/rinterface/na_values.h0000664000175000017500000000111012610501355020645 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.7.8/rpy/rinterface/sequence.c0000664000175000017500000021137212654236076020525 0ustar laurentlaurent00000000000000/* ***** BEGIN LICENSE BLOCK ***** * * GPLv2+ (see LICENSE file) * * Copyright (C) 2008-2014 Laurent Gautier * * ***** 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, sexp_name; /* needed by LANGSXP and LISTSXP*/ 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: /* R-exts says that it is converted to a VECSXP when subsetted */ //tmp = nthcdr(*sexp, i_R); tmp = nthcdr(*sexp, i_R); PROTECT(sexp_item = allocVector(VECSXP,1)); SET_VECTOR_ELT(sexp_item, 0, CAR(tmp)); PROTECT(sexp_name = allocVector(STRSXP,1)); SET_STRING_ELT(sexp_name, 0, PRINTNAME(TAG(tmp))); setAttrib(sexp_item, R_NamesSymbol, sexp_name); res = (PyObject *)newPySexpObject(sexp_item); UNPROTECT(2); 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*/ 0, /*tp_as_buffer*/ #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 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*/ 0, /*tp_as_buffer*/ #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 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*/ 0, /*tp_as_buffer*/ #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 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 = Rf_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 = Rf_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 = Rf_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 = Rf_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 = Rf_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*/ 0, /*tp_as_buffer*/ #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 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*/ 0, /*tp_as_buffer*/ #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 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*/ 0, /*tp_as_buffer*/ #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 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*/ 0, /*tp_as_buffer*/ #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 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.7.8/rpy/rinterface/tests/0000775000175000017500000000000012654242632017700 5ustar laurentlaurent00000000000000rpy2-2.7.8/rpy/rinterface/tests/test_SexpEnvironment.py0000664000175000017500000001136212610501355024450 0ustar laurentlaurent00000000000000import unittest import rpy2.rinterface as rinterface rinterface.initr() class SexpEnvironmentTestCase(unittest.TestCase): def setUp(self): self.console = rinterface.get_writeconsole_regular() def noconsole(x): pass rinterface.set_writeconsole_regular(noconsole) def tearDown(self): rinterface.set_writeconsole_regular(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 testKeys(self): newEnv = rinterface.globalenv.get("new.env") env = newEnv() env["a"] = rinterface.SexpVector([123, ], rinterface.INTSXP) env["b"] = rinterface.SexpVector([456, ], rinterface.INTSXP) symbols = env.keys() 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.7.8/rpy/rinterface/tests/test_Sexp.py0000664000175000017500000001775712610501355022241 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_emptyString(self): sexp = rinterface.baseenv.get('pi') self.assertRaises(ValueError, sexp.do_slot, "") 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 testDo_slot_assign_emptyString(self): #test that assigning slots is also creating the slot x = rinterface.IntSexpVector([1,2,3]) self.assertRaises(ValueError, x.do_slot_assign, "", rinterface.StrSexpVector(["bar", ])) 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.7.8/rpy/rinterface/tests/__init__.py0000664000175000017500000000314112637667232022020 0ustar laurentlaurent00000000000000import unittest import sys from . import test_SexpVector from . import test_SexpEnvironment from . import test_Sexp from . import test_SexpSymbol from . import test_SexpClosure from . import test_SexpVectorNumeric from . import test_Device from . import test_SexpExtPtr from . import test_EmbeddedR #import test_EmbeddedR_multithreaded def load_tests(loader, standard_tests, pattern): '''Ignore the test loader and return what we want Raw discovery here loads some stuff that results in a core dump, so we'll retain a load_tests() for now.''' suite_SexpVector = test_SexpVector.suite() suite_SexpEnvironment = test_SexpEnvironment.suite() suite_Sexp = test_Sexp.suite() suite_SexpSymbol = test_SexpSymbol.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_SexpSymbol ,suite_SexpVector ,suite_SexpEnvironment ,suite_SexpClosure ,suite_SexpVectorNumeric #,suite_Device #,suite_EmbeddedR_multithreaded ,suite_SexpExtPtr ]) return alltests def main(): tr = unittest.TextTestRunner(verbosity = 2) # We implement the load_tests() API, but ignore what we get suite = load_tests(None, None, None) tr.run(suite) if __name__ == '__main__': main() rpy2-2.7.8/rpy/rinterface/tests/test_SexpSymbol.py0000664000175000017500000000154512610501355023413 0ustar laurentlaurent00000000000000import unittest import copy import gc from rpy2 import rinterface rinterface.initr() class SexpSymbolTestCase(unittest.TestCase): def testNew_invalid(self): x = 1 self.assertRaises(ValueError, rinterface.SexpSymbol, x) def testNew_missing(self): self.assertRaises(TypeError, rinterface.SexpSymbol) def testNew_fromstring(self): symbol = rinterface.SexpSymbol("pi") evalsymbol = rinterface.baseenv['eval'](symbol) self.assertEqual(evalsymbol.rid, rinterface.baseenv['pi'].rid) def testNew_str(self): symbol = rinterface.SexpSymbol("pi") self.assertEqual("pi", str(symbol)) def suite(): suite = unittest.TestLoader().loadTestsFromTestCase(SexpSymbolTestCase) return suite if __name__ == '__main__': tr = unittest.TextTestRunner(verbosity = 2) tr.run(suite()) rpy2-2.7.8/rpy/rinterface/tests/test_Device.py0000664000175000017500000001004112610501355022474 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 = open('/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.7.8/rpy/rinterface/tests/test_SexpVector.py0000664000175000017500000005270512610501355023414 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 if sys.version_info[0] == 2: range = xrange IS_PYTHON3 = False else: IS_PYTHON3 = True 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 = range(3) v = ri.IntSexpVector(it) self.assertEqual(3, len(v)) for x,y in zip(range(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 = range(10) v = ri.FloatSexpVector(it) self.assertEqual(10, len(v)) for x,y in zip(range(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 as re: res = (True, re) except Exception as 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', ])) # R's behaviour is that subsetting returns an R list y = pl[0] self.assertEqual(ri.VECSXP, y.typeof) self.assertEqual('a', y.do_slot('names')[0]) self.assertEqual('1', y[0][0]) 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) #FIXME: R has introduced the use of larger integers # for vector sizes (and indexing). Is this relevant # any longer ? if IS_PYTHON3: haslargeint = (sys.maxsize > ri.R_LEN_T_MAX) else: haslargeint = (sys.maxint > ri.R_LEN_T_MAX) if haslargeint: 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.7.8/rpy/rinterface/tests/test_EmbeddedR.py0000664000175000017500000004111112654236076023127 0ustar laurentlaurent00000000000000import unittest import pickle import multiprocessing import rpy2 import rpy2.rinterface as rinterface import sys, os, subprocess, time, tempfile, io, signal, gc if sys.version_info[0] == 3: IS_PYTHON3 = True else: from itertools import izip as zip range = xrange IS_PYTHON3 = False 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 as 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 as 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 as re: res = (True, re) except Exception as 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 zip(rinterface.initoptions, options): self.assertEqual(o1, o2) def testSet_initoptions(self): self.assertRaises(RuntimeError, rinterface.set_initoptions, ('aa', '--verbose', '--no-save')) def testInitr(self): def init_r(preserve_hash): from rpy2 import rinterface rinterface.initr(r_preservehash=preserve_hash) preserve_hash = True proc = multiprocessing.Process(target=init_r, args=(preserve_hash,)) proc.start() proc.join() 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 testParseIncompleteError(self): self.assertRaises(rinterface.RParsingIncompleteError, rinterface.parse, "2 + 3 /") def testParseError(self): self.assertRaises(rinterface.RParsingError, rinterface.parse, "2 + 3 , 1") 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_regular(f) rcode = \"\"\" i <- 0; while(TRUE) { i <- i+1; Sys.sleep(0.01); }\"\"\" 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(range(10), rinterface.INTSXP) y = rinterface.SexpVector(range(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_regular(rinterface.consolePrint) rinterface.set_readconsole(rinterface.consoleRead) rinterface.set_readconsole(rinterface.consoleFlush) rinterface.set_choosefile(rinterface.chooseFile) sys.last_value = None def testSetWriteConsoleRegular(self): buf = [] def f(x): buf.append(x) rinterface.set_writeconsole_regular(f) self.assertEqual(rinterface.get_writeconsole_regular(), f) code = rinterface.SexpVector(["3", ], rinterface.STRSXP) rinterface.baseenv["print"](code) self.assertEqual('[1] "3"\n', str.join('', buf)) def testWriteConsoleRegularWithError(self): def f(x): raise CustomException("Doesn't work.") rinterface.set_writeconsole_regular(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 as 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 testSetResetConsole(self): reset = [0] def f(): reset[0] += 1 rinterface.set_resetconsole(f) self.assertEqual(rinterface.get_resetconsole(), f) try: rinterface.baseenv['eval'](rinterface.parse('1+"a"')) except rinterface.RRuntimeError: pass self.assertEqual(1, reset[0]) @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_regular(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 as 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 as 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_regular(noconsole) # reverted by the tearDown method def f(prompt): raise Exception("Doesn't work.") rinterface.set_choosefile(f) self.assertRaises(rinterface.RRuntimeError, rinterface.baseenv["file.choose"]) self.assertEqual("Doesn't work.", str(sys.last_value)) 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 as 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.7.8/rpy/rinterface/tests/test_SexpClosure.py0000664000175000017500000001145312610501355023561 0ustar laurentlaurent00000000000000import unittest import sys import rpy2.rinterface as rinterface import rpy2.rlike.container as rlc rinterface.initr() if sys.version_info[0] == 3: long = int class SexpClosureTestCase(unittest.TestCase): def setUp(self): self.console = rinterface.get_writeconsole_regular() def noconsole(x): pass rinterface.set_writeconsole_regular(noconsole) def tearDown(self): rinterface.set_writeconsole_regular(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.7.8/rpy/rinterface/tests/test_SexpExtPtr.py0000664000175000017500000000335512610501355023375 0ustar laurentlaurent00000000000000import unittest import rpy2.rinterface as rinterface rinterface.initr() class SexpExtPtrTestCase(unittest.TestCase): def setUp(self): self.console = rinterface.get_writeconsole_regular() def noconsole(x): pass rinterface.set_writeconsole_regular(noconsole) def tearDown(self): rinterface.set_writeconsole_regular(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.7.8/rpy/rinterface/tests/test_SexpVectorNumeric.py0000664000175000017500000000567112610501355024737 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 zip(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.7.8/rpy/rinterface/rexternalptr.c0000664000175000017500000002004112654236076021436 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.7.8/rpy/rinterface/buffer.c0000664000175000017500000001554612610501355020156 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.7.8/rpy/rinterface/embeddedr.c0000664000175000017500000002655612654236076020640 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; /* An environment to keep R objects preserved by rpy2 */ static SEXP RPY_R_PreciousEnv = 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; } /*FIXME: this is not thread safe (calls to R not using locking). Can this is be a source of errors ? */ static void SexpObject_clear(SexpObject *sexpobj) { if (sexpobj->pycount <= 0) { printf("Warning: clearing an R object with a refcount <= zero.\n"); } if ((sexpobj->sexp) != R_NilValue) { /* R objects that needs to be preserved from garbage collection */ if (RPY_R_PreciousEnv == NULL) { /* Use the R "precious list" */ R_ReleaseObject(sexpobj->sexp); } else { /* Use the environment */ static char *name_buf; if (name_buf == NULL) { /* Initialize with the number of characters required for an hexadecimal representation of a pointer*/ name_buf = (char *)calloc(sizeof(name_buf)*2+2+1, sizeof(char)) ; } sprintf(name_buf, "%p", (void *)(sexpobj->sexp)); SEXP res = rpy2_remove(Rf_mkString(name_buf), RPY_R_PreciousEnv, Rf_ScalarLogical(FALSE)); //Rf_defineVar(name_r, sexpobj->sexp, RPY_R_PreciousEnv); } 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->pycount = 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 objects that needs to be preserved from garbage collection */ if (RPY_R_PreciousEnv == NULL) { /* Use the R "precious list" */ R_PreserveObject(object); } else { /* Use an enclosing environment instead of R's "precious list" to protect the object from garbage collection */ static char *name_buf; if (name_buf == NULL) { /* Initialize with the number of characters required for an hexadecimal representation of a pointer*/ name_buf = (char *)calloc(sizeof(name_buf)*2+2+1, sizeof(char)) ; } sprintf(name_buf, "%p", (void *)object); SEXP name_r = Rf_install(name_buf); Rf_defineVar(name_r, object, RPY_R_PreciousEnv); } } } else { /* Reminder: capsule is a borrowed reference */ sexpobj_ptr = (SexpObject *)(PyCapsule_GetPointer(capsule, "rpy2.rinterface._C_API_")); if (sexpobj_ptr != NULL) { sexpobj_ptr->pycount++; } } 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->pycount) { 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->pycount--; } 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->pycount--; /* 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->pycount--; 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->pycount)); 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; } PyDoc_STRVAR(EmbeddedR_isInitialized_doc, "is_initialized() -> bool\n" "" "Return whether R is initialized."); static PyObject* EmbeddedR_isInitialized(void) { if (rpy2_isinitialized()) { Py_INCREF(Py_True); return Py_True; } else { Py_INCREF(Py_False); return Py_False; } } rpy2-2.7.8/rpy/tests.py0000775000175000017500000000706712654236076016152 0ustar laurentlaurent00000000000000#!/usr/bin/env python '''tests.py - run all the tests worth running The goal is that "ERRORS" and "FAILURES" are true failures, and expected problems sould be dealt with using decorators.''' from __future__ import print_function # if `singledispatch` is absent, the unit tests are failing with a rather # obscure / misleading error message. Test it now and report the problem. import sys if sys.version_info[0] < 3 or (sys.version_info[0] == 3 and sys.version_info[1] < 4): try: from singledispatch import singledispatch except ImportError as ie: print('The module "singledispatch is required for Python < 3.4') raise ie from os.path import dirname import unittest import rpy2 import rpy2.tests_rpy_classic def load_tests(loader, tests, pattern): '''Run tests a little faster than with TestLoader.discover() Note that we are using the unittest API here, but blithely ignore the values passed in for `tests` and `pattern`''' # For some reason, the commented code directly below is slow and loads some # things twice One specific message is regarding package_dependencies from # the tools package. # rpy_root = dirname(rpy2.__file__) # alltests = unittest.defaultTestLoader.discover(rpy_root, pattern='test*') rpy_root = dirname(rpy2.__file__) tests = unittest.TestSuite() pattern = 'test*' # This now catches some extra tests (bypassing the suite() functions), # at least in a virtualenv that lacks various packages, like numpy & # pandas suite_robjects = loader.discover('robjects', pattern, rpy_root) suite_rinterface = loader.discover('rinterface', pattern, rpy_root) suite_rlike = loader.discover('rlike', pattern, rpy_root) # This is once again testless suite_interactive = loader.discover('interactive', pattern, rpy_root) # ipython is a little trickier because it is an optional # dependency. try: import IPython has_ipython = True except ImportError as ie: has_ipython = False if has_ipython: suite_ipython= loader.discover('ipython', pattern, rpy_root) else: class MissingIpythonTestCase(unittest.TestCase): @unittest.skip("The optional dependency IPython is required in order to test features using it.") def testHasIpython(self): pass suite_ipython = unittest.TestLoader().loadTestsFromTestCase(MissingIpythonTestCase) suite_rpy_classic = rpy2.tests_rpy_classic.suite() tests.addTests([suite_rinterface, suite_robjects, suite_rlike, suite_interactive, suite_ipython, suite_rpy_classic ]) return tests if __name__ == "__main__": import sys, rpy2.rinterface print("rpy2 version: %s" % rpy2.__version__) print("- built against R version: %s" % '-'.join(str(x) for x in rpy2.rinterface.R_VERSION_BUILD)) try: import rpy2.rinterface except Exception as e: print("'rpy2.rinterface' could not be imported:") print(e) sys.exit(1) try: rpy2.rinterface.initr() except Exception as e: print("- The embedded R could not be initialized") print(e) sys.exit(1) try: rv = rpy2.rinterface.baseenv['R.version.string'] print("- running linked to R version: %s" % rv[0]) except KeyError as ke: print("The R version dynamically linked cannot be identified.") # This will sys.exit() with an appropriate error code unittest.main(buffer=True) rpy2-2.7.8/rpy/ipython/0000775000175000017500000000000012654242632016106 5ustar laurentlaurent00000000000000rpy2-2.7.8/rpy/ipython/__init__.py0000664000175000017500000000005312610501355020205 0ustar laurentlaurent00000000000000from .rmagic import load_ipython_extension rpy2-2.7.8/rpy/ipython/rmagic.py0000664000175000017500000006463712617667646017761 0ustar laurentlaurent00000000000000# -*- coding: utf-8 -*- """ ====== Rmagic ====== Magic command interface for interactive work with R in ipython. %R and %%R are the line and cell magics, respectively. .. note:: You will need a working copy of R. Usage ===== To enable the magics below, execute ``%load_ext rpy2.ipython``. ``%R`` {R_DOC} ``%Rpush`` {RPUSH_DOC} ``%Rpull`` {RPULL_DOC} ``%Rget`` {RGET_DOC} """ #----------------------------------------------------------------------------- # Copyright (C) 2012 The IPython Development Team # # Distributed under the terms of the BSD License. The full license is in # the file COPYING, distributed as part of this software. #----------------------------------------------------------------------------- import sys import tempfile from glob import glob from os import stat from shutil import rmtree # numpy and rpy2 imports import rpy2.rinterface as ri import rpy2.robjects as ro import rpy2.robjects.packages as rpacks Converter = ro.conversion.Converter import warnings template_converter = ro.conversion.converter try: from rpy2.robjects import pandas2ri as baseconversion template_converter = template_converter + baseconversion.converter except ImportError: try: from rpy2.robjects import numpy2ri as baseconversion template_converter = template_converter + baseconversion.converter warnings.warn(' '.join(("The Python package 'pandas' is strongly" "recommended when using `rpy2.ipython`.", "Unfortunately it could not be loaded,", "but at least we found 'numpy'."))) except ImportError: # Give up on numerics baseconversion = None warnings.warn(' '.join(("The Python package 'pandas' is strongly", "recommended when using `rpy2.ipython`.", "Unfortunately it could not be loaded,", "and we did not manage to load 'numpy'", "either."))) # IPython imports from IPython.core.displaypub import publish_display_data from IPython.core.magic import (Magics, magics_class, line_magic, line_cell_magic, needs_local_scope) from IPython.core.magic_arguments import ( argument, magic_arguments, parse_argstring, argument_group ) from IPython.utils.py3compat import str_to_unicode, unicode_to_str, PY3 try: from IPython.external.simplegeneric import generic except ImportError: # IPython 4.0 from simplegeneric import generic if sys.version_info[0] == 3: unicode = str class RInterpreterError(ri.RRuntimeError): """An error when running R code in a %%R magic cell.""" def __init__(self, line, err, stdout): self.line = line self.err = err.rstrip() self.stdout = stdout.rstrip() def __unicode__(self): s = 'Failed to parse and evaluate line %r.\nR error message: %r' % \ (self.line, self.err) if self.stdout and (self.stdout != self.err): s += '\nR stdout:\n' + self.stdout return s if PY3: __str__ = __unicode__ else: def __str__(self): return unicode_to_str(unicode(self), 'utf-8') @generic def pyconverter(pyobj): """Convert Python objects to R objects. Add types using the decorator: @pyconverter.when_type """ return pyobj converter = Converter('ipython conversion', template = template_converter) # The default conversion for lists is currently to make them an R list. That has # some advantages, but can be inconvenient (and, it's inconsistent with the way # python lists are automatically converted by numpy functions), so for # interactive use in the rmagic, we call unlist, which converts lists to vectors # **if the list was of uniform (atomic) type**. @pyconverter.when_type(list) def pyconverter_list(pyobj): # simplify2array is a utility function, but nice for us return ro.r.simplify2array(pyobj) @magics_class class RMagics(Magics): """A set of magics useful for interactive work with R via rpy2. """ def __init__(self, shell, pyconverter=pyconverter, cache_display_data=False, device='png'): """ Parameters ---------- shell : IPython shell pyconverter : callable To be called on values in ipython namespace before assigning to variables in rpy2. cache_display_data : bool If True, the published results of the final call to R are cached in the variable 'display_cache'. device : ['png', 'X11', 'svg'] Device to be used for plotting. Currently only 'png', 'X11' and 'svg' are supported, with 'png' and 'svg' being most useful in the notebook, and 'X11' allowing interactive plots in the terminal. """ super(RMagics, self).__init__(shell) self.cache_display_data = cache_display_data self.Rstdout_cache = [] self.pyconverter = pyconverter self.set_R_plotting_device(device) def set_R_plotting_device(self, device): """ Set which device R should use to produce plots. If device == 'svg' then the package 'Cairo' must be installed. Because Cairo forces "onefile=TRUE", it is not posible to include multiple plots per cell. Parameters ---------- device : ['png', 'X11', 'svg'] Device to be used for plotting. Currently only "png" and "X11" are supported, with 'png' and 'svg' being most useful in the notebook, and 'X11' allowing interactive plots in the terminal. """ device = device.strip() if device not in ['png', 'X11', 'svg']: raise ValueError("device must be one of ['png', 'X11' 'svg'], got '%s'", device) if device == 'svg': try: self.cairo = rpacks.importr('Cairo') except ri.RRuntimeError as rre: if rpacks.isinstalled('Cairo'): msg = "An error occurred when trying to load the R package Cairo'\n%s" % str(rre) else: msg = """ The R package 'Cairo' is required but it does not appear to be installed/available. Try: import rpy2.robjects.packages as rpacks utils = rpacks.importr('utils') utils.chooseCRANmirror(ind=1) utils.install_packages('Cairo') """ raise RInterpreterError(msg) self.device = device @line_magic def Rdevice(self, line): """ Change the plotting device R uses to one of ['png', 'X11', 'svg']. """ self.set_R_plotting_device(line.strip()) def eval(self, code): ''' Parse and evaluate a line of R code with rpy2. Returns the output to R's stdout() connection, the value generated by evaluating the code, and a boolean indicating whether the return value would be visible if the line of code were evaluated in an R REPL. R Code evaluation and visibility determination are done via an R call of the form withVisible(code_string), and this entire expression needs to be evaluated in R (we can't use rpy2 function proxies here, as withVisible is a LISPy R function). ''' old_writeconsole_regular = ri.get_writeconsole_regular() ri.set_writeconsole_regular(self.write_console_regular) try: # Need the newline in case the last line in code is a comment value, visible = ro.r("withVisible({%s\n})" % code) except (ri.RRuntimeError, ValueError) as exception: warning_or_other_msg = self.flush() # otherwise next return seems to have copy of error raise RInterpreterError(code, str_to_unicode(str(exception)), warning_or_other_msg) text_output = self.flush() ri.set_writeconsole_regular(old_writeconsole_regular) return text_output, value, visible[0] def write_console_regular(self, output): ''' A hook to capture R's stdout in a cache. ''' self.Rstdout_cache.append(output) def flush(self): ''' Flush R's stdout cache to a string, returning the string. ''' value = ''.join([str_to_unicode(s, 'utf-8') for s in self.Rstdout_cache]) self.Rstdout_cache = [] return value # @skip_doctest @needs_local_scope @line_magic def Rpush(self, line, local_ns=None): ''' A line-level magic for R that pushes variables from python to rpy2. The line should be made up of whitespace separated variable names in the IPython namespace:: In [7]: import numpy as np In [8]: X = np.array([4.5,6.3,7.9]) In [9]: X.mean() Out[9]: 6.2333333333333343 In [10]: %Rpush X In [11]: %R mean(X) Out[11]: array([ 6.23333333]) ''' if local_ns is None: local_ns = {} inputs = line.split(' ') for input in inputs: try: val = local_ns[input] except KeyError: try: val = self.shell.user_ns[input] except KeyError: # reraise the KeyError as a NameError so that it looks like # the standard python behavior when you use an unnamed # variable raise NameError("name '%s' is not defined" % input) robj = self.pyconverter(val) ro.r.assign(input, robj) # @skip_doctest @magic_arguments() @argument( 'outputs', nargs='*', ) @line_magic def Rpull(self, line): ''' A line-level magic for R that pulls variables from python to rpy2:: In [18]: _ = %R x = c(3,4,6.7); y = c(4,6,7); z = c('a',3,4) In [19]: %Rpull x y z In [20]: x Out[20]: array([ 3. , 4. , 6.7]) In [21]: y Out[21]: array([ 4., 6., 7.]) In [22]: z Out[22]: array(['a', '3', '4'], dtype='|S1') This is useful when a structured array is desired as output, or when the object in R has mixed data types. See the %%R docstring for more examples. Notes ----- Beware that R names can have '.' so this is not fool proof. To avoid this, don't name your R objects with '.'s... ''' args = parse_argstring(self.Rpull, line) outputs = args.outputs for output in outputs: robj = ri.globalenv.get(output) self.shell.push({output: converter.ri2py(robj) }) # @skip_doctest @magic_arguments() @argument( 'output', nargs=1, type=str, ) @line_magic def Rget(self, line): ''' Return an object from rpy2, possibly as a structured array (if possible). Similar to Rpull except only one argument is accepted and the value is returned rather than pushed to self.shell.user_ns:: In [3]: dtype=[('x', '= 1000: with open(imgfile, 'rb') as fh_img: images.append(fh_img.read()) else: # as onefile=TRUE, there is only one .svg file imgfile = "%s/Rplot.svg" % graph_dir # Cairo creates an SVG file every time R is called # -- empty ones are not published if stat(imgfile).st_size >= 1000: with open(imgfile, 'rb') as fh_img: images.append(fh_img.read()) mimetypes = { 'png' : 'image/png', 'svg' : 'image/svg+xml' } mime = mimetypes[self.device] # By default, isolate SVG images in the Notebook to avoid garbling if images and self.device == "svg" and isolate_svgs: md = {'image/svg+xml': dict(isolated=True)} # flush text streams before sending figures, helps a little with output for image in images: # synchronization in the console (though it's a bandaid, not a real sln) sys.stdout.flush(); sys.stderr.flush() display_data.append(('RMagic.R', {mime: image})) return display_data, md # @skip_doctest @magic_arguments() @argument( '-i', '--input', action='append', help='Names of input variable from shell.user_ns to be assigned to R variables of the same names after calling self.pyconverter. Multiple names can be passed separated only by commas with no whitespace.' ) @argument( '-o', '--output', action='append', help="Names of variables to be pushed from rpy2 to shell.user_ns after executing cell body (rpy2's internal facilities will apply ri2ro as appropriate). Multiple names can be passed separated only by commas with no whitespace." ) @argument( '-n', '--noreturn', help='Force the magic to not return anything.', action='store_true', default=False ) @argument_group("Plot", "Arguments to plotting device") @argument( '-w', '--width', type=int, help='Width of plotting device in R.' ) @argument( '-h', '--height', type=int, help='Height of plotting device in R.' ) @argument( '-p', '--pointsize', type=int, help='Pointsize of plotting device in R.' ) @argument( '-b', '--bg', help='Background of plotting device in R.' ) @argument_group("SVG", "SVG specific arguments") @argument( '--noisolation', help=('Disable SVG isolation in the Notebook. By default, SVGs are isolated to avoid namespace collisions between figures.' 'Disabling SVG isolation allows to reference previous figures or share CSS rules across a set of SVGs.'), action='store_false', default=True, dest='isolate_svgs' ) @argument_group("PNG", "PNG specific arguments") @argument( '-u', '--units', type=unicode, choices=["px", "in", "cm", "mm"], help='Units of png plotting device sent as an argument to *png* in R. One of ["px", "in", "cm", "mm"].' ) @argument( '-r', '--res', type=int, help='Resolution of png plotting device sent as an argument to *png* in R. Defaults to 72 if *units* is one of ["in", "cm", "mm"].' ) @argument( '-c', '--converter', default=None, help='Name of converter variable' ) @argument( 'code', nargs='*', ) @needs_local_scope @line_cell_magic def R(self, line, cell=None, local_ns=None): ''' Execute code in R, optionally returning results to the Python runtime. In line mode, this will evaluate an expression and convert the returned value to a Python object. The return value is determined by rpy2's behaviour of returning the result of evaluating the final expression. Multiple R expressions can be executed by joining them with semicolons:: In [9]: %R X=c(1,4,5,7); sd(X); mean(X) Out[9]: array([ 4.25]) In cell mode, this will run a block of R code. The resulting value is printed if it would be printed when evaluating the same code within a standard R REPL. Nothing is returned to python by default in cell mode:: In [10]: %%R ....: Y = c(2,4,3,9) ....: summary(lm(Y~X)) Call: lm(formula = Y ~ X) Residuals: 1 2 3 4 0.88 -0.24 -2.28 1.64 Coefficients: Estimate Std. Error t value Pr(>|t|) (Intercept) 0.0800 2.3000 0.035 0.975 X 1.0400 0.4822 2.157 0.164 Residual standard error: 2.088 on 2 degrees of freedom Multiple R-squared: 0.6993,Adjusted R-squared: 0.549 F-statistic: 4.651 on 1 and 2 DF, p-value: 0.1638 In the notebook, plots are published as the output of the cell:: %R plot(X, Y) will create a scatter plot of X bs Y. If cell is not None and line has some R code, it is prepended to the R code in cell. Objects can be passed back and forth between rpy2 and python via the -i -o flags in line:: In [14]: Z = np.array([1,4,5,10]) In [15]: %R -i Z mean(Z) Out[15]: array([ 5.]) In [16]: %R -o W W=Z*mean(Z) Out[16]: array([ 5., 20., 25., 50.]) In [17]: W Out[17]: array([ 5., 20., 25., 50.]) The return value is determined by these rules: * If the cell is not None (i.e., has contents), the magic returns None. * If the final line results in a NULL value when evaluated by rpy2, then None is returned. * No attempt is made to convert the final value to a structured array. Use %Rget to push a structured array. * If the -n flag is present, there is no return value. * A trailing ';' will also result in no return value as the last value in the line is an empty string. ''' args = parse_argstring(self.R, line) # arguments 'code' in line are prepended to # the cell lines if cell is None: code = '' return_output = True line_mode = True else: code = cell return_output = False line_mode = False code = ' '.join(args.code) + code # if there is no local namespace then default to an empty dict if local_ns is None: local_ns = {} if args.converter is None: pass else: try: localconverter = local_ns[args.converter] except KeyError: try: localconverter = self.shell.user_ns[args.converter] except KeyError: raise NameError("name '%s' is not defined" % args.converter) if not isinstance(localconverter, Converter): raise ValueError("'%s' must be a Converter object.") if args.input: for input in ','.join(args.input).split(','): try: val = local_ns[input] except KeyError: try: val = self.shell.user_ns[input] except KeyError: raise NameError("name '%s' is not defined" % input) if args.converter is None: ro.r.assign(input, self.pyconverter(val)) else: ro.r.assign(input, localconverter.py2ri(val)) tmpd = self.setup_graphics(args) text_output = '' try: if line_mode: for line in code.split(';'): text_result, result, visible = self.eval(line) text_output += text_result if text_result: # the last line printed something to the console so we won't return it return_output = False else: text_result, result, visible = self.eval(code) text_output += text_result if visible: old_writeconsole_regular = ri.get_writeconsole_regular() ri.set_writeconsole_regular(self.write_console_regular) ro.r.show(result) text_output += self.flush() ri.set_writeconsole_regular(old_writeconsole_regular) except RInterpreterError as e: # XXX - Maybe we should make this red or something? print(e.stdout) if not e.stdout.endswith(e.err): print(e.err) if tmpd: rmtree(tmpd) return finally: if self.device in ['png', 'svg']: ro.r('dev.off()') if text_output: # display_data.append(('RMagic.R', {'text/plain':text_output})) publish_display_data(data={'text/plain':text_output}, source='RMagic.R') # publish the R images if self.device in ['png', 'svg']: display_data, md = self.publish_graphics(tmpd, args.isolate_svgs) for tag, disp_d in display_data: publish_display_data(data=disp_d, source=tag, metadata=md) # kill the temporary directory - currently created only for "svg" # and "png" (else it's None) rmtree(tmpd) if args.output: for output in ','.join(args.output).split(','): if args.converter is None: output_ipy = converter.ri2py(ri.globalenv.get(output)) else: output_ipy = localconverter.ri2py(ri.globalenv.get(output)) self.shell.push({output: output_ipy }) # this will keep a reference to the display_data # which might be useful to other objects who happen to use # this method if self.cache_display_data: self.display_cache = display_data # We're in line mode and return_output is still True, # so return the converted result if return_output and not args.noreturn: if result is not ri.NULL: if args.converter is None: return converter.ri2py(result) else: return localconverter.ri2py(result) __doc__ = __doc__.format( R_DOC = ' '*8 + RMagics.R.__doc__, RPUSH_DOC = ' '*8 + RMagics.Rpush.__doc__, RPULL_DOC = ' '*8 + RMagics.Rpull.__doc__, RGET_DOC = ' '*8 + RMagics.Rget.__doc__ ) _switch_conversion_dataframe_doc = """ Switch the conversion of R data.frame / rpy2's DataFrame objects on or off. With rpy2 version 2.6.0, the conversion of R's data.frame objects (rpy2's DataFrame) to pandas' DataFrame is automatically activated when rmagic is loaded in ipython. This is trading convenience for performances since data are currently copied during the conversion. This function provides a simple way to to turn that automatic conversion off. """ def switchoff_conversion_dataframes(): __docstring__ = _switch_conversion_dataframe_doc import rpy2.robjects.vectors import rpy2.rinterface converter.ri2py.register(rpy2.robjects.vectors.DataFrame, lambda x: x) converter.ri2py.register(rpy2.rinterface.ListSexpVector, lambda x: x) def switchon_conversion_dataframes(): __docstring__ = _switch_conversion_dataframe_doc import rpy2.robjects.vectors import rpy2.rinterface cls = rpy2.rinterface.ListSexpVector converter.ri2py.register(rpy2.robjects.vectors.DataFrame, rpy2.robjects.pandas2ri.ri2py.registry[cls]) converter.ri2py.register(cls, rpy2.robjects.pandas2ri.ri2py.registry[cls]) def load_ipython_extension(ip): """Load the extension in IPython.""" if hasattr(baseconversion, 'activate'): # This is pandas2ri if pandas is installed, # or numpy2ri otherwise baseconversion.activate() ip.register_magics(RMagics) # Initialising rpy2 interferes with readline. Since, at this point, we've # probably just loaded rpy2, we reset the delimiters. See issue gh-2759. if ip.has_readline: ip.readline.set_completer_delims(ip.readline_delims) rpy2-2.7.8/rpy/ipython/ggplot.py0000664000175000017500000000370312610501355017747 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.7.8/rpy/ipython/html.py0000664000175000017500000002264212654236076017437 0ustar laurentlaurent00000000000000import jinja2 from IPython.display import HTML css = """ """ template_list = jinja2.Template("""

{{ clsname }} with {{ rlist | length }} elements:

{%- for elt_i in range(display_neltmax) %}
{{ rlist.names[elt_i] }}
{{ rlist[elt_i] }}
{%- endfor %} {%- if display_neltmax < (rlist | length) %}
...
{%- endif %}
""") template_vector_horizontal = jinja2.Template(""" {{ clsname }} with {{ vector | length }} elements: {%- for elt_i in range(display_ncolmax - size_tail) %} {%- endfor %} {%- if display_ncolmax < (vector | length) %} {%- endif %} {%- for elt_i in elt_i_tail %} {%- endfor %}
{{ vector[elt_i] }}...{{ vector[elt_i] }}
""") template_vector_vertical = jinja2.Template(""" {{ clsname }} with {{ vector | length }} elements: {%- for elt_i in range(display_nrowmax - size_tail) %} {%- if has_vector_names %} {%- endif %} {%- endfor %} {%- if display_nrowmax < (vector | length) %} {%- if has_vector_names %} {%- endif %} {%- endif %} {%- for elt_i in elt_i_tail %} {%- if has_vector_names %} {%- endif %} {%- endfor %}
{{ elt_i }}{{ vector.names[elt_i] }}{{ vector[elt_i]}}
.........
{{ elt_i }}{{ vector.names[elt_i] }}{{ vector[elt_i] }}
""") template_dataframe = jinja2.Template(""" {{ clsname }} with {{ dataf.nrow }} rows and {{ dataf | length }} columns: {%- if has_rownames %} {%- endif %} {%- for col_i in range(display_ncolmax - size_coltail) %} {%- endfor %} {%- if display_ncolmax < dataf.ncol %} {%- endif %} {%- for col_i in col_i_tail %} {%- endfor %} {%- for row_i in range(display_nrowmax - size_rowtail) %} {%- if has_rownames %} {%- endif %} {%- for col_i in range(display_ncolmax - size_coltail) %} {%- endfor %} {%- if display_ncolmax < dataf.ncol %} {%- endif %} {%- for col_i in col_i_tail %} {%- endfor %} {%- endfor %} {%- if dataf.nrow > display_nrowmax %} {%- if has_rownames %} {%- endif %} {%- for col_i in range(display_ncolmax - size_coltail) %} {%- endfor %} {%- if display_ncolmax < dataf.ncol %} {%- endif %} {%- for col_i in range(2) %} {%- endfor %} {%- endif %} {%- for row_i in row_i_tail %} {%- if has_rownames %} {%- endif %} {%- for col_i in range(display_ncolmax - size_coltail) %} {%- endfor %} {%- if display_ncolmax < dataf.ncol %} {%- endif %} {%- for col_i in col_i_tail %} {%- endfor %} {%- endfor %}
{{ dataf.names[col_i] }}...{{ dataf.names[col_i] }}
{{ row_i }}{{ dataf.rownames[row_i] }}{{ dataf[col_i][row_i] }}...{{ dataf[col_i][row_i] }}
...............
{{ row_i }}{{ dataf.rownames[row_i] }}{{ dataf[col_i][row_i] }}...{{ dataf[col_i][row_i] }}
""") template_ridentifiedobject = jinja2.Template("""
  • {{ clsname }} object
  • Origin in R: {{ origin }}
  • Class(es) in R:
      {%- for rclsname in obj.rclass %}
    • {{ rclsname }}
    • {%- endfor %}
""") template_rs4 = jinja2.Template("""
{{ clsname }} object
Origin in R: {{ origin }}
Class(es) in R:
    {%- for rclsname in obj.rclass %}
  • {{ rclsname }}
  • {%- endfor %}
Attributes:
    {%- for sln in obj.slotnames() %}
  • {{ sln }}
  • {%- endfor %}
""") from rpy2.robjects import (vectors, RObject, SignatureTranslatedFunction, RS4) class StrFactorVector(vectors.FactorVector): def __getitem__(self, item): integer = super(StrFactorVector, self).__getitem__(item) # R is one-offset, Python is zero-offset return self.levels[integer-1] class StrDataFrame(vectors.DataFrame): def __getitem__(self, item): obj = super(StrDataFrame, self).__getitem__(item) if isinstance(obj, vectors.FactorVector): obj = StrFactorVector(obj) return obj def html_vector_horizontal(vector, display_ncolmax=10, size_tail=2, table_class='rpy2_table'): if isinstance(vector, vectors.FactorVector): vector = StrFactorVector(vector) html = template_vector_horizontal.render({ 'table_class': table_class, 'clsname': type(vector).__name__, 'vector': vector, 'display_ncolmax': min(display_ncolmax, len(vector)), 'size_tail': size_tail, 'elt_i_tail': range(max(0, len(vector)-size_tail), len(vector))}) return html def html_rlist(vector, display_nrowmax=10, size_tail=2, table_class='rpy2_table'): html = template_vector_vertical.render({ 'table_class': table_class, 'clsname': type(vector).__name__, 'vector': vector, 'has_vector_names': vector.names is not rinterface.NULL, 'display_nrowmax': min(display_nrowmax, len(vector)), 'size_tail': size_tail, 'elt_i_tail': range(max(0, len(vector)-size_tail), len(vector))}) return html def html_rdataframe(dataf, display_nrowmax=10, display_ncolmax=6, size_coltail=2, size_rowtail=2, table_class='rpy2_table'): html = template_dataframe.render( {'dataf': StrDataFrame(dataf), 'table_class': table_class, 'has_rownames': dataf.rownames is not None, 'clsname': type(dataf).__name__, 'display_nrowmax': min(display_nrowmax, dataf.nrow), 'display_ncolmax': min(display_ncolmax, dataf.ncol), 'col_i_tail': range(max(0, dataf.ncol-size_coltail), dataf.ncol), 'row_i_tail': range(max(0, dataf.nrow-size_rowtail), dataf.nrow), 'size_coltail': size_coltail, 'size_rowtail': size_rowtail }) return html # FIXME: wherefrom() is taken from the rpy2 documentation # May be it should become part of the rpy2 API from rpy2 import rinterface def wherefrom(name, startenv=rinterface.globalenv): """ when calling 'get', where the R object is coming from. """ env = startenv obj = None retry = True while retry: try: obj = env[name] retry = False except LookupError: env = env.enclos() if env.rsame(rinterface.emptyenv): retry = False else: retry = True return env def _dict_ridentifiedobject(obj): if hasattr(obj, '__rname__') and obj.__rname__ is not None: env = wherefrom(obj.__rname__) try: origin = env.do_slot('name')[0] except LookupError: origin = 'package:base ?' else: origin = '???' d = {'clsname': type(obj).__name__, 'origin': origin, 'obj': obj} return d def html_ridentifiedobject(obj): d = _dict_ridentifiedobject(obj) html = template_ridentifiedobject.render(d) return html def html_rs4(obj, table_class='rpy2_table'): d = _dict_ridentifiedobject(obj) d['table_class']=table_class html = template_rs4.render(d) return html def init_printing(): ip = get_ipython() html_f = ip.display_formatter.formatters['text/html'] html_f.for_type(vectors.Vector, html_vector_horizontal) html_f.for_type(vectors.ListVector, html_rlist) html_f.for_type(vectors.DataFrame, html_rdataframe) html_f.for_type(RObject, html_ridentifiedobject) html_f.for_type(RS4, html_rs4) html_f.for_type(SignatureTranslatedFunction, html_ridentifiedobject) from IPython.display import HTML HTML(css) rpy2-2.7.8/rpy/ipython/tests/0000775000175000017500000000000012654242632017250 5ustar laurentlaurent00000000000000rpy2-2.7.8/rpy/ipython/tests/__init__.py0000664000175000017500000000044612610501355021355 0ustar laurentlaurent00000000000000import unittest from os.path import dirname def main(): tr = unittest.TextTestRunner(verbosity = 2) suite = unittest.defaultTestLoader.discover(dirname(__file__), pattern='test*') tr.run(suite) if __name__ == '__main__': main() rpy2-2.7.8/rpy/ipython/tests/test_rmagic.py0000664000175000017500000002450312617514232022124 0ustar laurentlaurent00000000000000import unittest from itertools import product # Currently numpy is a testing requirement, but rpy2 should work without numpy try: import numpy as np has_numpy = True except: has_numpy = False try: import pandas as pd has_pandas = True except: has_pandas = False from IPython.testing.globalipapp import get_ipython from IPython.utils.py3compat import PY3 if PY3: from io import StringIO np_string_type = 'U' else: from StringIO import StringIO np_string_type = 'S' from rpy2.ipython import rmagic # from IPython.core.getipython import get_ipython from rpy2 import rinterface from rpy2.robjects import r, vectors, globalenv import rpy2.robjects.packages as rpacks class TestRmagic(unittest.TestCase): @classmethod def setUpClass(cls): '''Set up an IPython session just once. It'd be safer to set it up for each test, but for now, I'm mimicking the IPython team's logic. ''' cls.ip = get_ipython() # This is just to get a minimally modified version of the changes # working cls.ip.magic('load_ext rpy2.ipython') def setUp(self): if hasattr(rmagic.template_converter, 'activate'): rmagic.template_converter.activate() def tearDown(self): # This seems like the safest thing to return to a safe state self.ip.run_line_magic('Rdevice', 'png') if hasattr(rmagic.template_converter, 'deactivate'): rmagic.template_converter.deactivate() @unittest.skipIf(not has_numpy, 'numpy not installed') def test_push(self): self.ip.push({'X':np.arange(5), 'Y':np.array([3,5,4,6,7])}) self.ip.run_line_magic('Rpush', 'X Y') np.testing.assert_almost_equal(np.asarray(r('X')), self.ip.user_ns['X']) np.testing.assert_almost_equal(np.asarray(r('Y')), self.ip.user_ns['Y']) @unittest.skipIf(not has_numpy, 'numpy not installed') def test_push_localscope(self): """Test that Rpush looks for variables in the local scope first.""" self.ip.run_cell(''' def rmagic_addone(u): %Rpush u %R result = u+1 %Rpull result return result[0] u = 0 result = rmagic_addone(12344) ''') result = self.ip.user_ns['result'] np.testing.assert_equal(result, 12345) @unittest.skipUnless(has_pandas, 'pandas is not available in python') @unittest.skipIf(not has_numpy, 'numpy not installed') def test_push_dataframe(self): df = pd.DataFrame([{'a': 1, 'b': 'bar'}, {'a': 5, 'b': 'foo', 'c': 20}]) self.ip.push({'df':df}) self.ip.run_line_magic('Rpush', 'df') # This is converted to factors, which are currently converted back to Python # as integers, so for now we test its representation in R. sio = StringIO() rinterface.set_writeconsole_regular(sio.write) try: r('print(df$b[1])') self.assertIn('[1] bar', sio.getvalue()) finally: rinterface.set_writeconsole_regular(None) # Values come packaged in arrays, so we unbox them to test. self.assertEqual(r('df$a[2]')[0], 5) missing = r('df$c[1]')[0] assert np.isnan(missing), missing @unittest.skipIf(not has_numpy, 'numpy not installed') def test_pull(self): r('Z=c(11:20)') self.ip.run_line_magic('Rpull', 'Z') np.testing.assert_almost_equal(np.asarray(r('Z')), self.ip.user_ns['Z']) np.testing.assert_almost_equal(self.ip.user_ns['Z'], np.arange(11,21)) @unittest.skipIf(not has_numpy, 'numpy not installed') def test_Rconverter(self): # If we get to dropping numpy requirement, we might use something # like the following: # self.assertSequenceEqual(buffer(a).buffer_info(), # buffer(b).buffer_info()) # numpy recarray (numpy's version of a data frame) dataf_np= np.array([(1, 2.9, 'a'), (2, 3.5, 'b'), (3, 2.1, 'c')], dtype=[('x', ' OD[k] if k in OD, else d. d defaults to None """ try: res = self[k] except KeyError as ke: res = d return res def items(self): """ OD.items() -> 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 range(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 as 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_items(tagval): res = TaggedList([]) for k,v in tagval.items(): 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 zip(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 zip(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 items(self): """ OD.items() -> an iterator over the (key, value) items of D """ for tag, item in zip(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 range(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.7.8/setup.cfg0000664000175000017500000000011312654242632015416 0ustar laurentlaurent00000000000000[easy_install] [egg_info] tag_date = 0 tag_build = tag_svn_revision = 0 rpy2-2.7.8/NEWS0000664000175000017500000013477412654236166014326 0ustar laurentlaurent00000000000000Release 2.7.8 ============= Bugs fixed ---------- - American English spelling was missing for some of the function names to specify colour (color) scales. - Fix for printing R objects on Windows (pull request #47) Release 2.7.7 ============= Bugs fixed ---------- - Pickling `robjects`-level objects resulted in `rinterface`-level objects when unpickled (issue #324). - Conversion of :mod:`pandas` data frames made the "columns" in the resulting R data frame R arrays rather than vector. This was sometimes confusing R functions (issue #323). Release 2.7.6 ============= Changes ------- - :mod:`rpy2.robjects.lib.ggplot2` was modified to match the newly released ggplot2-2.0.0. This is introducing API-breaking changes, which breaks the promise to keep the API stable through bugfix releases within series, but without it 2.7.x will not work with a new default installation of the R package ggplot2. Release 2.7.5 ============= Bugs fixed ---------- - Division and floordivision through the delegator `.ro` provided with R vectors wrapped by `robjects`. (issue #320) - Memory leak when unserializing (unpickling) R objects bundled in Python objects (issue #321) Release 2.7.4 ============= Bugs fixed ---------- - Python 3.5 highlighted slightly incorrect C-level flags in rpy2 objects declarations, and :mod:`rpy2.robjects` could not be imported. - Fixed unit tests for rmagic when :mod:`numpy` is not installed, and for :mod:`numpy` is installed by :mod:`pandas` in missing. Release 2.7.3 ============= Bugs fixed ---------- - method :meth:`DataFrame.collect` in :mod:`rpy2.robjects.lib.dplyr` was not functioning. - Applied patch by Matthias Klose to fix implict pointer conversions. - :mod:`pandas2ri.ri2py_dataframe` is now propagating the row names in the R data frame into an index in the pandas data frame (issue #285) - methods `union`, `intersect`, `setdiff`, `ungroup` defined in the R package `dplyr` were missing from the `DataFrame` definition in :mod:`rpy2.robjects.lib.dplyr` Release 2.7.2 ============= Bugs fixed ---------- - methods `distinct`, `sample_n`, and `sample_frac` defined in the R package `dplyr` were missing from the `DataFrame` definition in :mod:`rpy2.robjects.lib.dplyr` - The fix for the inheritance problem with :mod:`rpy2.robjects.lib.dplyr.DataFrame` introduced a regression whenever `group_by` is used. - The methods to perform joins on dplyr `DataFrame` objects where not working properly. Release 2.7.1 ============= Bugs fixed ---------- - The :meth:`__repr__` for :mod:`robjects`-level vectors was broken for vectors of length 1 (issue #306) - The ipython notebook-based sections of the documentation were not building - Classes inheriting from :mod:`dplyr.DataFrame` had dplyr methods returning objects of their parent class. Release 2.7.0 ============= New features ------------ - New exception :class:`rpy2.rinterface.RParsingError`. Errors occurring when parsing R code through :func:`rpy2.rinterface.parse` raise this exception (previously :class:`rpy2.rinterface.RRuntimeError`). - New class :class:`rpy2.robjects.conversion.Converter` to replace the `namedtuple` of the same name - New class :class:`rpy2.robjects.converter.ConversionContext`. This is a context manager allowing an easy setting of local conversion rules. The constructor has an alias called :meth:`rpy2.robjects.constructor.localconverter`. - New module :mod:`rpy2.robjects.lib.dplyr` providing a custom wrapper for the R library `dplyr` - Method :method:`Environment.items()` to iterate through the symbols and associated objects in an R environment. - Exception :class:`rpy2.rinterface.ParsingIncompleError`, a child class of :class:`rpy2.rinterface.ParsingError`, raised when calling :meth:`rpy2.rinteface.parse` results in R's C-level status to be `PARSE_INCOMPLETE`. This can make the Python implementation of an IDE for R easier. - Attribute :attr:`slots` for :mod:`rpy2.robjects`-level objects. The attribute is a :class:`rpy2.robjects.Rslots` which behaves like a Python mapping to provide access to R-attributes for the object (see issue #275). - The R "magic" for ipython `%%R` can be passed a local converter (see new features above) by using `-c`. Bugs fixed ---------- - Conversion rules were not applied when parsing and evaluating string as R with :class:`rpy2.robjects.R`. - Calling the constructor for :class:`rpy2.robjects.vectors.FactorVector` with an R factor is no longer making a copy, loosing the associated R attributes if any (fixes issue #299). - `rpy2` could crash when R was unable to dynamically load the C extension for one of its packages (noticed with issue #303). Changes ------- - :func:`rpy2.rinterface.is_initialized` is now a function. - :meth:`rpy2.robjects.R.__call__` is now calling R's `base::parse()` to parse the string rather the parser through R's C-API. The workaround let's us retrieve R's error message in case of failure (see issue #300) Release 2.6.3 ============= Bug fixed --------- - Metaclass `RS4Auto_Type` facilitating the creation of Python classes from R S4 classes was not handling classes without methods (issue #301) Release 2.6.2 ============= Bugs fixed ---------- - Check that R >= 3.2 is used at build time (issue #291) - Conversion rules were not applied when parsing and evaluating string as R code with :class:`rpy2.robjects.R`. Release 2.6.1 ============= New features ------------ - Because of their long names, the classes :class:`SignatureTranslatedAnonymousPackage`, :class:`SignatureTranslatedPackage`, and :class:`SignatureTranslatedFunction` in :mod:`rpy2.robjects.packages` have now the aliases :class:`STAP`, :class:`STP`, and :class:`STF` respectively. Bugs fixed ---------- - Typo in function name emitting warnings at build time (issue #283) - The conversion of `TaggedList` instances is now handling the names of items in the list (issue #286) Changes ------- - Loading the `ipython` extension in the absence of `pandas` or `numpy` is now issuing a warning (issue #279) Release 2.6.0 ============= New features ------------ - Report the existence during build time of a file `.Renviron`, or the definition of the environment variables `R_ENVIRON' or `R_ENVIRON_USER` with a warning. (issue #204) - Moved console writting callback to use `ptr_R_WriteConsoleEx` rather than `ptr_R_WriteConsole`. This allows callbacks for warnings and messages. `get/set_writeconsole` is now replaced by `get/set_writeconsole_regular` (regular output) and `get/set_writeconsole_warnerror` (warning and error). In order to conserve backward compatibility an alias for `get/set_writeconsole_regular` called `get/set_writeconsole` is provided. - Added callback for `ptr_R_ResetConsole`. - :mod:`pandas` :class:`Categorical` objects are automatically handled in the pandas converter. - The translation of R symbols into Python symbols used in `importr` and underlying classes and methods can be customized with a callback. The default translation turning `.` into `_` is `default_symbol_r2python`. - Translation of named arguments in R function is now sharing code with the translation of R symbols (see point above), providing a consistent way to perform translations. - Utility function `sequence_to_vector` in `robjects` to convert Python sequences (e.g., `list` or `tuple`) to R vector without having to specify the type (the type is inferred from the list). - :mod:`robjects.vectors` object have a property :attr:`NAvalue` that contains the `NA` value for the vector, allowing generic code on R vectors. For example, testing whether any vector contains `NA` can be written as `any(x is myvector.NAvalue for x in myvector)`. Making numpy /masked/ array is an other application. Changes ------- - The automatic name translation from R to Python used in `importr` is now slightly more complex. It will not only translate `.` to `_` but should a conflict arise from the existence in R of both the `.` and `_` versions the `.` version will be appended a `_` (in accordance with :pep:0008). The change was discussed in issue #274). - The ipython 'R magic' is now starting with a default conversion mode that is `pandas2ri` if it can find it, then `numpy2ri` if it can find it, and then the basic conversion. - R vectors are now typed at the C level (IntSexpVector, FloatSexpVector, ListSexpVector, etc...) whenever retrieving them from the embedded R with the low-level `rinterface`. This is facilitating dispatch on vector type (e.g., with `singledispatch` now used for the conversion system). Bugs fixed ---------- - The evaluation of R code through R's C-level function `tryEval` caused console output whenever an error occurred. Moving to the seemingly experimental `tryEvalSilent` makes evaluations less verbose. - Multiple plots in one ipython cell (pull request #44) Release 2.5.7 ============= - `simplegeneric` was moved of ipython 4.0.0 (pull request #43) Release 2.5.6 ============= Bugs fixed ---------- - Detection of the R version during setup on Win8 (issues #255 and #258) - Segmentation fault when converting :mod:`pandas` :class:`Series` with elements of type object (issue #264) - The default converter from Python (non-rpy2) objects to rinterface-level objects was producing robjects-level objects whenever the input was of type :class:`list` (discovered while fixing issue #264) - Implemented suggested fix for issue with unlinking files on Windows (issue #191) - Testing rpy2 in the absence of ipython no longer stops with an error (issue #266) Release 2.5.5 ============= Bugs fixed ---------- - Crash (segfault) when querying an R object in an R environment triggers an error (symbol exists, but associated values resolves to an error - issue #251) - Change in the signature of `rcall` was not updated in the documentation (issue #259) - Minor update to the documentation (issue #257) Release 2.5.4 ============= Bugs fixed ---------- - Filter PNG files on size, preventing empty files causing trouble to be ipython notebook rendering of graphics later on (slight modification of the pull request #39) - Fix installation left unresolved with rpy2-2.5.3 (issue #248) - Possible segfault with Python 3.4 (issue #249) Release 2.5.3 ============= Changes ------- - `setup.py` has `install_requires` in addition to `requires` in the hope to fix the missing dependency with Python 2 (:mod:`singledispatch` is required but not installed). Bugs fixed ---------- - Extracting configuration information from should now work when R is emitting a warning (issue #247) - On OS X the library discovery step can yield nothing (see issue #246). A tentative fix is to issue a warning and keep moving. Release 2.5.2 ============= Bugs fixed ---------- - String representation of :class:`robjects.R` (issue #238) - Check during `build_ext` if unsupported version of R (pull request #32) - HTMl display of columns of factors in a DataFrame (issue #236) - HTML display of factors (issue #242) Release 2.5.1 ============= Bugs fixed ---------- - Require singledispatch if Python 3.3 (issue #232) - Fixed bug when R spits out a warning when asked configuration information (issue #233) - Restored printing of compilation information when running `setup.py` - Fixed installation issue on some systems (issue #234) - Workaround obscure failure message from unittest if Python < 3.4 and :mod:`singledispatch` cannot be imported (issue #235) Release 2.5.0 ============= New features ------------ - Experimental alternative way to preserve R objects from garbage collection. This can be activated with `rinterface.initr(r_preservehash=True)` (default is `False`. - :class:`GGPlot` object getting a method :meth:`save` mirroring R's `ggplot2::ggsave()`. - The conversion system is now using generics/single dispatch. - New module :mod:`rpy2.ipython.html` with HTML display for rpy2 objects - [Experimental] New function :func:`robjects.methods.rs4instance_factory` to type RS4 objects with more specificity. Changes ------- - The script `setup.py` was rewritten for clarity and ease of maintenance. Now it only uses `setuptools`. Release 2.4.4 ============= Bugs fixed ---------- - Use `input` rather than `raw_input` in the default console callback with Python 3 (fixes issue #222) - Issues with conversions, pandas, and rmagic (fixes issue #218 and more) Release 2.4.3 ============= Bugs fixed ---------- - `geom_raster` was missing from `rpy2.robjects.lib.ggplot2` (pull request #30) - Fixed issue with SVG rendering in ipython notebook (issue #217) - Regression with `rx2()` introduced with new conversion (issue #219) - Fixed documentation (missing `import`) (issue #213) Release 2.4.2 ============= Bugs fixed ---------- - Assigning an R `DataFrame` into an environment was failing if the conversion for Pandas was activated. (Issue #207) Release 2.4.1 ============= Bugs fixed ---------- - :meth:`rpy2.ipython` fixed spurious output to notebook cells. Release 2.4.0 ============= Changes ------- - Conversion system slightly changed, with the optional conversions for :mod:`numpy` and :mod:`pandas` modified accordingly. The changes should only matter if using third-party conversion functions. - The Python 3 version is now a first class citizen. `2to3` is no longer used, and the code base is made directly compatible with Python. This lowers significantly the installation time with Python 3 (which matters when developping rpy2). - The default options to initialize R (`rpy2.rinterface.initoptions') are no longer `('rpy2', '--quiet', '--vanilla', '--no-save')` but now `('rpy2', '--quiet', '--no-save')`. - :class:`robjects.vectors.ListVector` can be instanciated from any objects with a method `items()` with the expectation that the method returns an iterable of (name, value) tuples, or even be an iterable of (name, value) tuples. New features ------------ - For instances of :class:`rpy2.robjects.Function`, the `__doc__` is now a property fetching information about the parameters in the R signature. - Convenience function :func:`rpy2.robjects.packages.data` to extract the datasets in an R pacakges - :mod:`ipython`'s `rmagic` is now part of :mod:`rpy`. To use, `%load_ext rpy2.ipython` from within IPython. - new method :meth:`rpy2.rinterface.SexpEnvironment.keys`, returnings the names in the environment as a tuple of Python strings. - convenience class :class:`robjects.packages.InstalledPackages`, with a companion function :func:`robjects.packages.isinstalled`. - new class :class:`rinterface.SexpSymbol` to represent R symbols Bugs fixed ---------- - :meth:`rpy2.rinterface.Sexp.do_slot` was crashing when the parameter was an empty string (PR #155) Release 2.3.10 ============== Bugs fixed ---------- - `setup.py build` was broken when new R compiled with OpenMP (Issue #183) Release 2.3.9 ============= - 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 rpy2-2.7.8/AUTHORS0000644000175000017500000000112012466035613014642 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.7.8/rpy2.egg-info/0000775000175000017500000000000012654242632016170 5ustar laurentlaurent00000000000000rpy2-2.7.8/rpy2.egg-info/SOURCES.txt0000644000175000017500000001216312654242632020055 0ustar laurentlaurent00000000000000AUTHORS MANIFEST.in NEWS README.rst setup.cfg setup.py ./rpy/__init__.py ./rpy/rpy_classic.py ./rpy/tests.py ./rpy/tests_rpy_classic.py ./rpy/interactive/__init__.py ./rpy/interactive/packages.py ./rpy/interactive/process_revents.py ./rpy/interactive/tests/__init__.py ./rpy/ipython/__init__.py ./rpy/ipython/ggplot.py ./rpy/ipython/html.py ./rpy/ipython/rmagic.py ./rpy/ipython/tests/__init__.py ./rpy/ipython/tests/test_rmagic.py ./rpy/rinterface/__init__.py ./rpy/rinterface/_rinterface.c ./rpy/rinterface/_rpy_device.c ./rpy/rinterface/r_utils.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_SexpSymbol.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/packages_utils.py ./rpy/robjects/pandas2ri.py ./rpy/robjects/robject.py ./rpy/robjects/vectors.py ./rpy/robjects/lib/__init__.py ./rpy/robjects/lib/dplyr.py ./rpy/robjects/lib/ggplot2.py ./rpy/robjects/lib/grid.py ./rpy/robjects/lib/tests/__init__.py ./rpy/robjects/lib/tests/test_dplyr.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/generated_rst/README rpy/__init__.py rpy/rpy_classic.py rpy/tests.py rpy/tests_rpy_classic.py rpy/interactive/__init__.py rpy/interactive/packages.py rpy/interactive/process_revents.py rpy/interactive/tests/__init__.py rpy/ipython/__init__.py rpy/ipython/ggplot.py rpy/ipython/html.py rpy/ipython/rmagic.py rpy/ipython/tests/__init__.py rpy/ipython/tests/test_rmagic.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_SexpSymbol.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/packages_utils.py rpy/robjects/pandas2ri.py rpy/robjects/robject.py rpy/robjects/vectors.py rpy/robjects/lib/__init__.py rpy/robjects/lib/dplyr.py rpy/robjects/lib/ggplot2.py rpy/robjects/lib/grid.py rpy/robjects/lib/tests/__init__.py rpy/robjects/lib/tests/test_dplyr.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.egg-info/PKG-INFO rpy2.egg-info/SOURCES.txt rpy2.egg-info/dependency_links.txt rpy2.egg-info/requires.txt rpy2.egg-info/top_level.txtrpy2-2.7.8/rpy2.egg-info/dependency_links.txt0000644000175000017500000000000112654242631022233 0ustar laurentlaurent00000000000000 rpy2-2.7.8/rpy2.egg-info/PKG-INFO0000644000175000017500000000112512654242631017261 0ustar laurentlaurent00000000000000Metadata-Version: 1.1 Name: rpy2 Version: 2.7.8 Summary: Python interface to the R language (embedded R) Home-page: http://rpy.sourceforge.net Author: Laurent Gautier Author-email: lgautier@gmail.com License: GPLv2+ Description: UNKNOWN Platform: UNKNOWN Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 3 Classifier: License :: OSI Approved :: GNU General Public License v2 or later (GPLv2+) Classifier: Intended Audience :: Developers Classifier: Intended Audience :: Science/Research Classifier: Development Status :: 5 - Production/Stable Requires: six rpy2-2.7.8/rpy2.egg-info/top_level.txt0000644000175000017500000000000512654242631020712 0ustar laurentlaurent00000000000000rpy2 rpy2-2.7.8/rpy2.egg-info/requires.txt0000664000175000017500000000000412654242631020561 0ustar laurentlaurent00000000000000six