Author: Ronan Lamy <ronan.l...@gmail.com> Branch: install-rpython Changeset: r92089:a1f3fe63fa46 Date: 2017-08-05 14:02 +0100 http://bitbucket.org/pypy/pypy/changeset/a1f3fe63fa46/
Log: hg merge default diff too long, truncating to 2000 out of 3400 lines diff --git a/Makefile b/Makefile --- a/Makefile +++ b/Makefile @@ -10,7 +10,7 @@ RUNINTERP = $(PYPY_EXECUTABLE) endif -.PHONY: cffi_imports +.PHONY: pypy-c cffi_imports pypy-c: @echo @@ -32,7 +32,7 @@ @echo "====================================================================" @echo @sleep 5 - $(RUNINTERP) rpython/bin/rpython -Ojit pypy/goal/targetpypystandalone.py + cd pypy/goal && $(RUNINTERP) ../../rpython/bin/rpython -Ojit targetpypystandalone.py # Note: the -jN option, or MAKEFLAGS=-jN, are not usable. They are # replaced with an opaque --jobserver option by the time this Makefile @@ -40,4 +40,4 @@ # http://lists.gnu.org/archive/html/help-make/2010-08/msg00106.html cffi_imports: pypy-c - PYTHONPATH=. ./pypy-c pypy/tool/build_cffi_imports.py || /bin/true + PYTHONPATH=. pypy/goal/pypy-c pypy/tool/build_cffi_imports.py || /bin/true diff --git a/lib-python/2.7/distutils/unixccompiler.py b/lib-python/2.7/distutils/unixccompiler.py --- a/lib-python/2.7/distutils/unixccompiler.py +++ b/lib-python/2.7/distutils/unixccompiler.py @@ -226,7 +226,19 @@ return "-L" + dir def _is_gcc(self, compiler_name): - return "gcc" in compiler_name or "g++" in compiler_name + # XXX PyPy workaround, look at the big comment below for more + # context. On CPython, the hack below works fine because + # `compiler_name` contains the name of the actual compiler which was + # used at compile time (e.g. 'x86_64-linux-gnu-gcc' on my machine). + # PyPy hardcodes it to 'cc', so the hack doesn't work, and the end + # result is that we pass the wrong option to the compiler. + # + # The workaround is to *always* pretend to be GCC if we are on Linux: + # this should cover the vast majority of real systems, including the + # ones which use clang (which understands the '-Wl,-rpath' syntax as + # well) + return (sys.platform == "linux2" or + "gcc" in compiler_name or "g++" in compiler_name) def runtime_library_dir_option(self, dir): # XXX Hackish, at the very least. See Python bug #445902: diff --git a/lib_pypy/cffi/api.py b/lib_pypy/cffi/api.py --- a/lib_pypy/cffi/api.py +++ b/lib_pypy/cffi/api.py @@ -394,12 +394,17 @@ replace_with = ' ' + replace_with return self._backend.getcname(cdecl, replace_with) - def gc(self, cdata, destructor): + def gc(self, cdata, destructor, size=0): """Return a new cdata object that points to the same data. Later, when this new cdata object is garbage-collected, 'destructor(old_cdata_object)' will be called. + + The optional 'size' gives an estimate of the size, used to + trigger the garbage collection more eagerly. So far only used + on PyPy. It tells the GC that the returned object keeps alive + roughly 'size' bytes of external memory. """ - return self._backend.gcp(cdata, destructor) + return self._backend.gcp(cdata, destructor, size) def _get_cached_btype(self, type): assert self._lock.acquire(False) is False diff --git a/lib_pypy/cffi/backend_ctypes.py b/lib_pypy/cffi/backend_ctypes.py --- a/lib_pypy/cffi/backend_ctypes.py +++ b/lib_pypy/cffi/backend_ctypes.py @@ -1002,7 +1002,7 @@ _weakref_cache_ref = None - def gcp(self, cdata, destructor): + def gcp(self, cdata, destructor, size=0): if self._weakref_cache_ref is None: import weakref class MyRef(weakref.ref): diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py --- a/pypy/config/pypyoption.py +++ b/pypy/config/pypyoption.py @@ -224,11 +224,6 @@ "use specialised tuples", default=False), - BoolOption("withcelldict", - "use dictionaries that are optimized for being used as module dicts", - default=False, - requires=[("objspace.honor__builtins__", False)]), - BoolOption("withliststrategies", "enable optimized ways to store lists of primitives ", default=True), @@ -288,7 +283,7 @@ # extra optimizations with the JIT if level == 'jit': - config.objspace.std.suggest(withcelldict=True) + pass # none at the moment def enable_allworkingmodules(config): diff --git a/pypy/doc/build.rst b/pypy/doc/build.rst --- a/pypy/doc/build.rst +++ b/pypy/doc/build.rst @@ -10,6 +10,18 @@ minutes on a fast machine -- and RAM-hungry. You will need **at least** 2 GB of memory on a 32-bit machine and 4GB on a 64-bit machine. +Before you start +---------------- + +Our normal development workflow avoids a full translation by using test-driven +development. You can read more about how to develop PyPy here_, and latest +translated (hopefully functional) binary packages are available on our +buildbot's `nightly builds`_ + +.. _here: getting-started-dev.html +.. _`nightly builds`: http://buildbot.pypy.org/nightly + +You will need the build dependencies below to run the tests. Clone the repository -------------------- @@ -140,22 +152,61 @@ Run the translation ------------------- +We usually translate in the ``pypy/goal`` directory, so all the following +commands assume your ``$pwd`` is there. + Translate with JIT:: - cd pypy/goal pypy ../../rpython/bin/rpython --opt=jit Translate without JIT:: - cd pypy/goal pypy ../../rpython/bin/rpython --opt=2 +Note this translates pypy via the ``targetpypystandalone.py`` file, so these +are shorthand for:: + + pypy ../../rpython/bin/rpython <rpython options> targetpypystandalone.py <pypy options> + +More help is availabe via ``--help`` at either option position, and more info +can be found in the :doc:`config/index` section. + (You can use ``python`` instead of ``pypy`` here, which will take longer but works too.) -If everything works correctly this will create an executable ``pypy-c`` in the -current directory. The executable behaves mostly like a normal Python -interpreter (see :doc:`cpython_differences`). +If everything works correctly this will: + +1. Run the rpython `translation chain`_, producing a database of the + entire pypy interpreter. This step is currently singe threaded, and RAM + hungry. As part of this step, the chain creates a large number of C code + files and a Makefile to compile them in a + directory controlled by the ``PYPY_USESSION_DIR`` environment variable. +2. Create an executable ``pypy-c`` by running the Makefile. This step can + utilize all possible cores on the machine. +3. Copy the needed binaries to the current directory. +4. Generate c-extension modules for any cffi-based stdlib modules. + + +The resulting executable behaves mostly like a normal Python +interpreter (see :doc:`cpython_differences`), and is ready for testing, for +use as a base interpreter for a new virtualenv, or for packaging into a binary +suitable for installation on another machine running the same OS as the build +machine. + +Note that step 4 is merely done as a convenience, any of the steps may be rerun +without rerunning the previous steps. + +.. _`translation chain`: https://rpython.readthedocs.io/en/latest/translation.html + + +Making a debug build of PyPy +---------------------------- + +If the Makefile is rerun with the lldebug or lldebug0 target, appropriate +compilation flags are added to add debug info and reduce compiler optimizations +to ``-O0`` respectively. If you stop in a debugger, you will see the +very wordy machine-generated C code from the rpython translation step, which +takes a little bit of reading to relate back to the rpython code. Build cffi import libraries for the stdlib ------------------------------------------ @@ -169,14 +220,6 @@ .. _`out-of-line API mode`: http://cffi.readthedocs.org/en/latest/overview.html#real-example-api-level-out-of-line -Translating with non-standard options -------------------------------------- - -It is possible to have non-standard features enabled for translation, -but they are not really tested any more. Look, for example, at the -:doc:`objspace proxies <objspace-proxies>` document. - - Packaging (preparing for installation) -------------------------------------- @@ -205,14 +248,16 @@ * PyPy 2.5.1 or earlier: normal users would see permission errors. Installers need to run ``pypy -c "import gdbm"`` and other similar - commands at install time; the exact list is in `package.py`_. Users + commands at install time; the exact list is in + :source:`pypy/tool/release/package.py <package.py>`. Users seeing a broken installation of PyPy can fix it after-the-fact if they have sudo rights, by running once e.g. ``sudo pypy -c "import gdbm``. * PyPy 2.6 and later: anyone would get ``ImportError: no module named _gdbm_cffi``. Installers need to run ``pypy _gdbm_build.py`` in the ``lib_pypy`` directory during the installation process (plus others; - see the exact list in `package.py`_). Users seeing a broken + see the exact list in :source:`pypy/tool/release/package.py <package.py>`). + Users seeing a broken installation of PyPy can fix it after-the-fact, by running ``pypy /path/to/lib_pypy/_gdbm_build.py``. This command produces a file called ``_gdbm_cffi.pypy-41.so`` locally, which is a C extension diff --git a/pypy/doc/config/objspace.std.withcelldict.txt b/pypy/doc/config/objspace.std.withcelldict.txt deleted file mode 100644 --- a/pypy/doc/config/objspace.std.withcelldict.txt +++ /dev/null @@ -1,2 +0,0 @@ -Enable cell-dicts. This optimization is not helpful without the JIT. In the -presence of the JIT, it greatly helps looking up globals. diff --git a/pypy/doc/configuration.rst b/pypy/doc/configuration.rst --- a/pypy/doc/configuration.rst +++ b/pypy/doc/configuration.rst @@ -188,4 +188,6 @@ can be found on the ``config`` attribute of all ``TranslationContext`` instances and are described in :source:`rpython/config/translationoption.py`. The interpreter options are attached to the object space, also under the name ``config`` and are -described in :source:`pypy/config/pypyoption.py`. +described in :source:`pypy/config/pypyoption.py`. Both set of options are +documented in the :doc:`config/index` section. + diff --git a/pypy/doc/cppyy_example.rst b/pypy/doc/cppyy_example.rst deleted file mode 100644 --- a/pypy/doc/cppyy_example.rst +++ /dev/null @@ -1,59 +0,0 @@ -File example.h -============== - -:: - - #include <iostream> - #include <vector> - - class AbstractClass { - public: - virtual ~AbstractClass() {} - virtual void abstract_method() = 0; - }; - - class ConcreteClass : AbstractClass { - public: - ConcreteClass(int n=42) : m_int(n) {} - ~ConcreteClass() {} - - virtual void abstract_method() { - std::cout << "called concrete method" << std::endl; - } - - void array_method(int* ad, int size) { - for (int i=0; i < size; ++i) - std::cout << ad[i] << ' '; - std::cout << std::endl; - } - - void array_method(double* ad, int size) { - for (int i=0; i < size; ++i) - std::cout << ad[i] << ' '; - std::cout << std::endl; - } - - AbstractClass* show_autocast() { - return this; - } - - operator const char*() { - return "Hello operator const char*!"; - } - - public: - int m_int; - }; - - namespace Namespace { - - class ConcreteClass { - public: - class NestedClass { - public: - std::vector<int> m_v; - }; - - }; - - } // namespace Namespace diff --git a/pypy/doc/cpython_differences.rst b/pypy/doc/cpython_differences.rst --- a/pypy/doc/cpython_differences.rst +++ b/pypy/doc/cpython_differences.rst @@ -330,6 +330,8 @@ - ``frozenset`` (empty frozenset only) + - unbound method objects (for Python 2 only) + This change requires some changes to ``id`` as well. ``id`` fulfills the following condition: ``x is y <=> id(x) == id(y)``. Therefore ``id`` of the above types will return a value that is computed from the argument, and can diff --git a/pypy/doc/extending.rst b/pypy/doc/extending.rst --- a/pypy/doc/extending.rst +++ b/pypy/doc/extending.rst @@ -12,7 +12,7 @@ * Write them in pure Python and use ctypes_. -* Write them in C++ and bind them through :doc:`cppyy <cppyy>` using Cling. +* Write them in C++ and bind them through cppyy_ using Cling. * Write them as `RPython mixed modules`_. @@ -64,9 +64,9 @@ cppyy ----- -For C++, `cppyy`_ is an automated bindings generator available for both +For C++, _cppyy_ is an automated bindings generator available for both PyPy and CPython. -``cppyy`` relies on declarations from C++ header files to dynamically +_cppyy_ relies on declarations from C++ header files to dynamically construct Python equivalent classes, functions, variables, etc. It is designed for use by large scale programs and supports modern C++. With PyPy, it leverages the built-in ``_cppyy`` module, allowing the JIT to @@ -75,8 +75,7 @@ To install, run ``pip install cppyy``. Further details are available in the `full documentation`_. -.. _cppyy: http://cppyy.readthedocs.org/ -.. _`full documentation`: http://cppyy.readthedocs.org/ +.. _`full documentation`: https://cppyy.readthedocs.org/ RPython Mixed Modules diff --git a/pypy/doc/getting-started-dev.rst b/pypy/doc/getting-started-dev.rst --- a/pypy/doc/getting-started-dev.rst +++ b/pypy/doc/getting-started-dev.rst @@ -35,8 +35,8 @@ * Edit things. Use ``hg diff`` to see what you changed. Use ``hg add`` to make Mercurial aware of new files you added, e.g. new test files. - Use ``hg status`` to see if there are such files. Run tests! (See - the rest of this page.) + Use ``hg status`` to see if there are such files. Write and run tests! + (See the rest of this page.) * Commit regularly with ``hg commit``. A one-line commit message is fine. We love to have tons of commits; make one as soon as you have @@ -113,6 +113,10 @@ make sure you have the correct version installed which you can find out with the ``--version`` switch. +You will need the `build requirements`_ to run tests successfully, since many of +them compile little pieces of PyPy and then run the tests inside that minimal +interpreter + Now on to running some tests. PyPy has many different test directories and you can use shell completion to point at directories or files:: @@ -141,7 +145,7 @@ .. _py.test testing tool: http://pytest.org .. _py.test usage and invocations: http://pytest.org/latest/usage.html#usage - +.. _`build requirements`: build.html#install-build-time-dependencies Special Introspection Features of the Untranslated Python Interpreter --------------------------------------------------------------------- diff --git a/pypy/doc/whatsnew-head.rst b/pypy/doc/whatsnew-head.rst --- a/pypy/doc/whatsnew-head.rst +++ b/pypy/doc/whatsnew-head.rst @@ -5,6 +5,14 @@ .. this is a revision shortly after release-pypy2.7-v5.8.0 .. startrev: 558bd00b3dd8 +In previous versions of PyPy, ``instance.method`` would return always +the same bound method object, when gotten out of the same instance (as +far as ``is`` and ``id()`` can tell). CPython doesn't do that. Now +PyPy, like CPython, returns a different bound method object every time. +For ``type.method``, PyPy2 still returns always the same *unbound* +method object; CPython does it for built-in types but not for +user-defined types. + .. branch: cffi-complex .. branch: cffi-char16-char32 @@ -30,3 +38,25 @@ Renaming of ``cppyy`` to ``_cppyy``. The former is now an external package installable with ``pip install cppyy``. + +.. branch: Enable_PGO_for_clang + +.. branch: nopax + +At the end of translation, run ``attr -q -s pax.flags -V m`` on +PAX-enabled systems on the produced binary. This seems necessary +because PyPy uses a JIT. + +.. branch: pypy_bytearray + +Improve ``bytearray`` performance (backported from py3.5) + +.. branch: gc-del-limit-growth + +Fix the bounds in the GC when allocating a lot of objects with finalizers, +fixes issue #2590 + +.. branch: arrays-force-less + +Small improvement to optimize list accesses with constant indexes better by +throwing away information about them less eagerly. diff --git a/pypy/interpreter/argument.py b/pypy/interpreter/argument.py --- a/pypy/interpreter/argument.py +++ b/pypy/interpreter/argument.py @@ -2,6 +2,7 @@ Arguments objects. """ from rpython.rlib.debug import make_sure_not_resized +from rpython.rlib.objectmodel import not_rpython from rpython.rlib import jit from pypy.interpreter.error import OperationError, oefmt @@ -46,8 +47,8 @@ # behaviour but produces better error messages self.methodcall = methodcall + @not_rpython def __repr__(self): - """ NOT_RPYTHON """ name = self.__class__.__name__ if not self.keywords: return '%s(%s)' % (name, self.arguments_w,) diff --git a/pypy/interpreter/error.py b/pypy/interpreter/error.py --- a/pypy/interpreter/error.py +++ b/pypy/interpreter/error.py @@ -7,6 +7,7 @@ from rpython.rlib import jit from rpython.rlib.objectmodel import we_are_translated, specialize +from rpython.rlib.objectmodel import not_rpython from rpython.rlib import rstack, rstackovf from pypy.interpreter import debug @@ -57,8 +58,9 @@ self.match(space, space.w_KeyboardInterrupt)) # note: an extra case is added in OpErrFmtNoArgs + @not_rpython def __str__(self): - "NOT_RPYTHON: Convenience for tracebacks." + "Convenience for tracebacks." s = self._w_value space = getattr(self.w_type, 'space', None) if space is not None: @@ -107,15 +109,16 @@ if RECORD_INTERPLEVEL_TRACEBACK: self.debug_excs.append(sys.exc_info()) + @not_rpython def print_application_traceback(self, space, file=None): - "NOT_RPYTHON: Dump a standard application-level traceback." + "Dump a standard application-level traceback." if file is None: file = sys.stderr self.print_app_tb_only(file) print >> file, self.errorstr(space) + @not_rpython def print_app_tb_only(self, file): - "NOT_RPYTHON" tb = self._application_traceback if tb: import linecache @@ -142,8 +145,9 @@ print >> file, l tb = tb.next + @not_rpython def print_detailed_traceback(self, space=None, file=None): - """NOT_RPYTHON: Dump a nice detailed interpreter- and + """Dump a nice detailed interpreter- and application-level traceback, useful to debug the interpreter.""" if file is None: file = sys.stderr diff --git a/pypy/interpreter/executioncontext.py b/pypy/interpreter/executioncontext.py --- a/pypy/interpreter/executioncontext.py +++ b/pypy/interpreter/executioncontext.py @@ -1,7 +1,7 @@ import sys from pypy.interpreter.error import OperationError, get_cleared_operation_error from rpython.rlib.unroll import unrolling_iterable -from rpython.rlib.objectmodel import specialize +from rpython.rlib.objectmodel import specialize, not_rpython from rpython.rlib import jit, rgc, objectmodel TICK_COUNTER_STEP = 100 @@ -423,8 +423,9 @@ # to run at the next possible bytecode self.reset_ticker(-1) + @not_rpython def register_periodic_action(self, action, use_bytecode_counter): - """NOT_RPYTHON: + """ Register the PeriodicAsyncAction action to be called whenever the tick counter becomes smaller than 0. If 'use_bytecode_counter' is True, make sure that we decrease the tick counter at every bytecode. diff --git a/pypy/interpreter/function.py b/pypy/interpreter/function.py --- a/pypy/interpreter/function.py +++ b/pypy/interpreter/function.py @@ -559,21 +559,29 @@ return space.newbool(space.eq_w(self.w_function, w_other.w_function)) def is_w(self, space, other): + if self.w_instance is not None: + return W_Root.is_w(self, space, other) + # The following special-case is only for *unbound* method objects. + # Motivation: in CPython, it seems that no strange internal type + # exists where the equivalent of ``x.method is x.method`` would + # return True. This is unlike unbound methods, where e.g. + # ``list.append is list.append`` returns True. The following code + # is here to emulate that behaviour. Unlike CPython, we return + # True for all equal unbound methods, not just for built-in types. if not isinstance(other, Method): return False - return (self.w_instance is other.w_instance and + return (other.w_instance is None and self.w_function is other.w_function and self.w_class is other.w_class) def immutable_unique_id(self, space): - from pypy.objspace.std.util import IDTAG_METHOD as tag + if self.w_instance is not None: + return W_Root.immutable_unique_id(self, space) + # the special-case is only for *unbound* method objects + # + from pypy.objspace.std.util import IDTAG_UNBOUND_METHOD as tag from pypy.objspace.std.util import IDTAG_SHIFT - if self.w_instance is not None: - id = space.bigint_w(space.id(self.w_instance)) - id = id.lshift(LONG_BIT) - else: - id = rbigint.fromint(0) - id = id.or_(space.bigint_w(space.id(self.w_function))) + id = space.bigint_w(space.id(self.w_function)) id = id.lshift(LONG_BIT).or_(space.bigint_w(space.id(self.w_class))) id = id.lshift(IDTAG_SHIFT).int_or_(tag) return space.newlong_from_rbigint(id) diff --git a/pypy/interpreter/gateway.py b/pypy/interpreter/gateway.py --- a/pypy/interpreter/gateway.py +++ b/pypy/interpreter/gateway.py @@ -23,7 +23,7 @@ DescrMismatch) from pypy.interpreter.error import OperationError, oefmt from pypy.interpreter.function import ClassMethod, FunctionWithFixedCode -from rpython.rlib.objectmodel import we_are_translated +from rpython.rlib.objectmodel import we_are_translated, not_rpython from rpython.rlib.rarithmetic import r_longlong, r_int, r_ulonglong, r_uint from rpython.tool.sourcetools import func_with_new_name, compile2 @@ -64,8 +64,8 @@ def _freeze_(self): return True + @not_rpython def unwrap(self, space, w_value): - """NOT_RPYTHON""" raise NotImplementedError @@ -380,8 +380,8 @@ class BuiltinActivation(object): _immutable_ = True + @not_rpython def __init__(self, behavior): - """NOT_RPYTHON""" self.behavior = behavior def _run(self, space, scope_w): @@ -621,9 +621,9 @@ # When a BuiltinCode is stored in a Function object, # you get the functionality of CPython's built-in function type. + @not_rpython def __init__(self, func, unwrap_spec=None, self_type=None, descrmismatch=None, doc=None): - "NOT_RPYTHON" # 'implfunc' is the interpreter-level function. # Note that this uses a lot of (construction-time) introspection. Code.__init__(self, func.__name__) @@ -969,10 +969,10 @@ instancecache = {} + @not_rpython def __new__(cls, f, app_name=None, unwrap_spec=None, descrmismatch=None, as_classmethod=False, doc=None): - "NOT_RPYTHON" # f must be a function whose name does NOT start with 'app_' self_type = None if hasattr(f, 'im_func'): @@ -1013,8 +1013,8 @@ self._staticdefs = zip(argnames[-len(defaults):], defaults) return self + @not_rpython def _getdefaults(self, space): - "NOT_RPYTHON" defs_w = [] for name, defaultval in self._staticdefs: if name.startswith('w_'): @@ -1070,8 +1070,8 @@ class GatewayCache(SpaceCache): + @not_rpython def build(cache, gateway): - "NOT_RPYTHON" space = cache.space defs = gateway._getdefaults(space) # needs to be implemented by subclass code = gateway._code @@ -1141,8 +1141,8 @@ w_globals = self.getwdict(space) return space.getitem(w_globals, space.newtext(name)) + @not_rpython def interphook(self, name): - "NOT_RPYTHON" def appcaller(space, *args_w): if not isinstance(space, ObjSpace): raise TypeError("first argument must be a space instance.") @@ -1179,15 +1179,16 @@ """NOT_RPYTHON The cache mapping each applevel instance to its lazily built w_dict""" + @not_rpython def build(self, app): - "NOT_RPYTHON. Called indirectly by Applevel.getwdict()." + "Called indirectly by Applevel.getwdict()." return build_applevel_dict(app, self.space) # __________ pure applevel version __________ +@not_rpython def build_applevel_dict(self, space): - "NOT_RPYTHON" w_glob = space.newdict(module=True) space.setitem(w_glob, space.newtext('__name__'), space.newtext(self.modname)) space.exec_(self.source, w_glob, w_glob, @@ -1198,8 +1199,9 @@ # ____________________________________________________________ +@not_rpython def appdef(source, applevel=ApplevelClass, filename=None): - """ NOT_RPYTHON: build an app-level helper function, like for example: + """ build an app-level helper function, like for example: myfunc = appdef('''myfunc(x, y): return x+y ''') @@ -1245,6 +1247,6 @@ # app2interp_temp is used for testing mainly +@not_rpython def app2interp_temp(func, applevel_temp=applevel_temp, filename=None): - """ NOT_RPYTHON """ return appdef(func, applevel_temp, filename=filename) diff --git a/pypy/interpreter/miscutils.py b/pypy/interpreter/miscutils.py --- a/pypy/interpreter/miscutils.py +++ b/pypy/interpreter/miscutils.py @@ -3,6 +3,7 @@ """ from rpython.rlib.listsort import make_timsort_class +from rpython.rlib.objectmodel import not_rpython class ThreadLocals: @@ -41,9 +42,8 @@ # but in some corner cases it is not... unsure why self._value = None - +@not_rpython def make_weak_value_dictionary(space, keytype, valuetype): - "NOT_RPYTHON" if space.config.translation.rweakref: from rpython.rlib.rweakref import RWeakValueDictionary return RWeakValueDictionary(keytype, valuetype) diff --git a/pypy/interpreter/mixedmodule.py b/pypy/interpreter/mixedmodule.py --- a/pypy/interpreter/mixedmodule.py +++ b/pypy/interpreter/mixedmodule.py @@ -3,6 +3,9 @@ from pypy.interpreter import gateway from pypy.interpreter.error import OperationError from pypy.interpreter.baseobjspace import W_Root + +from rpython.rlib.objectmodel import not_rpython + import sys class MixedModule(Module): @@ -15,16 +18,17 @@ lazy = False submodule_name = None + @not_rpython def __init__(self, space, w_name): - """ NOT_RPYTHON """ Module.__init__(self, space, w_name) self.lazy = True self.__class__.buildloaders() self.loaders = self.loaders.copy() # copy from the class to the inst self.submodules_w = [] + @not_rpython def install(self): - """NOT_RPYTHON: install this module, and it's submodules into + """install this module, and it's submodules into space.builtin_modules""" Module.install(self) if hasattr(self, "submodules"): @@ -61,8 +65,8 @@ self.w_initialdict = self.space.call_method(self.w_dict, 'items') @classmethod + @not_rpython def get_applevel_name(cls): - """ NOT_RPYTHON """ if cls.applevel_name is not None: return cls.applevel_name else: @@ -130,8 +134,8 @@ self._frozen = True @classmethod + @not_rpython def buildloaders(cls): - """ NOT_RPYTHON """ if not hasattr(cls, 'loaders'): # build a constant dictionary out of # applevel/interplevel definitions @@ -161,8 +165,8 @@ return space.newtext_or_none(cls.__doc__) +@not_rpython def getinterpevalloader(pkgroot, spec): - """ NOT_RPYTHON """ def ifileloader(space): d = {'space':space} # EVIL HACK (but it works, and this is not RPython :-) @@ -202,8 +206,8 @@ return ifileloader applevelcache = {} +@not_rpython def getappfileloader(pkgroot, appname, spec): - """ NOT_RPYTHON """ # hum, it's a bit more involved, because we usually # want the import at applevel modname, attrname = spec.split('.') diff --git a/pypy/interpreter/module.py b/pypy/interpreter/module.py --- a/pypy/interpreter/module.py +++ b/pypy/interpreter/module.py @@ -4,7 +4,7 @@ from pypy.interpreter.baseobjspace import W_Root from pypy.interpreter.error import OperationError -from rpython.rlib.objectmodel import we_are_translated +from rpython.rlib.objectmodel import we_are_translated, not_rpython class Module(W_Root): @@ -40,13 +40,15 @@ except OperationError: pass + @not_rpython def install(self): - """NOT_RPYTHON: installs this module into space.builtin_modules""" + """installs this module into space.builtin_modules""" modulename = self.space.text0_w(self.w_name) self.space.builtin_modules[modulename] = self + @not_rpython def setup_after_space_initialization(self): - """NOT_RPYTHON: to allow built-in modules to do some more setup + """to allow built-in modules to do some more setup after the space is fully initialized.""" def init(self, space): diff --git a/pypy/interpreter/pyframe.py b/pypy/interpreter/pyframe.py --- a/pypy/interpreter/pyframe.py +++ b/pypy/interpreter/pyframe.py @@ -7,6 +7,7 @@ from rpython.rlib.debug import ll_assert_not_none from rpython.rlib.jit import hint from rpython.rlib.objectmodel import instantiate, specialize, we_are_translated +from rpython.rlib.objectmodel import not_rpython from rpython.rlib.rarithmetic import intmask, r_uint from rpython.tool.pairtype import extendabletype @@ -144,8 +145,9 @@ return None return d.w_locals + @not_rpython def __repr__(self): - # NOT_RPYTHON: useful in tracebacks + # useful in tracebacks return "<%s.%s executing %s at line %s" % ( self.__class__.__module__, self.__class__.__name__, self.pycode, self.get_last_lineno()) diff --git a/pypy/interpreter/pyopcode.py b/pypy/interpreter/pyopcode.py --- a/pypy/interpreter/pyopcode.py +++ b/pypy/interpreter/pyopcode.py @@ -7,7 +7,7 @@ from rpython.rlib import jit, rstackovf from rpython.rlib.debug import check_nonneg from rpython.rlib.objectmodel import (we_are_translated, always_inline, - dont_inline) + dont_inline, not_rpython) from rpython.rlib.rarithmetic import r_uint, intmask from rpython.tool.sourcetools import func_with_new_name @@ -20,8 +20,8 @@ from pypy.interpreter.pycode import PyCode, BytecodeCorruption from pypy.tool.stdlib_opcode import bytecode_spec +@not_rpython def unaryoperation(operationname): - """NOT_RPYTHON""" def opimpl(self, *ignored): operation = getattr(self.space, operationname) w_1 = self.popvalue() @@ -31,8 +31,8 @@ return func_with_new_name(opimpl, "opcode_impl_for_%s" % operationname) +@not_rpython def binaryoperation(operationname): - """NOT_RPYTHON""" def opimpl(self, *ignored): operation = getattr(self.space, operationname) w_2 = self.popvalue() diff --git a/pypy/interpreter/test/test_function.py b/pypy/interpreter/test/test_function.py --- a/pypy/interpreter/test/test_function.py +++ b/pypy/interpreter/test/test_function.py @@ -1,4 +1,4 @@ -import pytest +import pytest, sys from pypy.interpreter import eval from pypy.interpreter.function import Function, Method, descr_function_get from pypy.interpreter.pycode import PyCode @@ -342,6 +342,11 @@ raises(ValueError, type(f).__setstate__, f, (1, 2, 3)) class AppTestMethod: + def setup_class(cls): + cls.w_runappdirect_on_cpython = cls.space.wrap( + cls.runappdirect and + '__pypy__' not in sys.builtin_module_names) + def test_simple_call(self): class A(object): def func(self, arg2): @@ -572,7 +577,6 @@ assert meth == meth assert meth == MethodType(func, object) - @pytest.mark.skipif("config.option.runappdirect") def test_method_identity(self): class A(object): def m(self): @@ -589,19 +593,24 @@ a = A() a2 = A() - assert a.m is a.m - assert id(a.m) == id(a.m) - assert a.m is not a.n - assert id(a.m) != id(a.n) - assert a.m is not a2.m - assert id(a.m) != id(a2.m) + x = a.m; y = a.m + assert x is not y + assert id(x) != id(y) + assert x == y + assert x is not a.n + assert id(x) != id(a.n) + assert x is not a2.m + assert id(x) != id(a2.m) - assert A.m is A.m - assert id(A.m) == id(A.m) - assert A.m is not A.n - assert id(A.m) != id(A.n) - assert A.m is not B.m - assert id(A.m) != id(B.m) + if not self.runappdirect_on_cpython: + assert A.m is A.m + assert id(A.m) == id(A.m) + assert A.m == A.m + x = A.m + assert x is not A.n + assert id(x) != id(A.n) + assert x is not B.m + assert id(x) != id(B.m) class TestMethod: diff --git a/pypy/interpreter/typedef.py b/pypy/interpreter/typedef.py --- a/pypy/interpreter/typedef.py +++ b/pypy/interpreter/typedef.py @@ -8,14 +8,15 @@ from rpython.rlib.jit import promote from rpython.rlib.objectmodel import compute_identity_hash, specialize -from rpython.rlib.objectmodel import instantiate +from rpython.rlib.objectmodel import instantiate, not_rpython from rpython.tool.sourcetools import compile2, func_with_new_name class TypeDef(object): + @not_rpython def __init__(self, __name, __base=None, __total_ordering__=None, __buffer=None, **rawdict): - "NOT_RPYTHON: initialization-time only" + "initialization-time only" self.name = __name if __base is None: bases = [] @@ -113,8 +114,9 @@ # register_finalizer() or not. @specialize.memo() +@not_rpython def get_unique_interplevel_subclass(space, cls): - "NOT_RPYTHON: initialization-time only" + "initialization-time only" assert cls.typedef.acceptable_as_base_class try: return _unique_subclass_cache[cls] @@ -349,15 +351,17 @@ return self +@not_rpython def interp_attrproperty(name, cls, doc=None, wrapfn=None): - "NOT_RPYTHON: initialization-time only" + "initialization-time only" assert wrapfn is not None def fget(space, obj): return getattr(space, wrapfn)(getattr(obj, name)) return GetSetProperty(fget, cls=cls, doc=doc) +@not_rpython def interp_attrproperty_w(name, cls, doc=None): - "NOT_RPYTHON: initialization-time only" + "initialization-time only" def fget(space, obj): w_value = getattr(obj, name) if w_value is None: diff --git a/pypy/module/__builtin__/test/test_classobj.py b/pypy/module/__builtin__/test/test_classobj.py --- a/pypy/module/__builtin__/test/test_classobj.py +++ b/pypy/module/__builtin__/test/test_classobj.py @@ -1090,18 +1090,18 @@ def setup_class(cls): if cls.runappdirect: py.test.skip("can only be run on py.py") - def is_strdict(space, w_class): - from pypy.objspace.std.dictmultiobject import BytesDictStrategy + def is_moduledict(space, w_class): + from pypy.objspace.std.celldict import ModuleDictStrategy w_d = w_class.getdict(space) - return space.wrap(isinstance(w_d.get_strategy(), BytesDictStrategy)) + return space.wrap(isinstance(w_d.get_strategy(), ModuleDictStrategy)) - cls.w_is_strdict = cls.space.wrap(gateway.interp2app(is_strdict)) + cls.w_is_moduledict = cls.space.wrap(gateway.interp2app(is_moduledict)) - def test_strdict(self): + def test_moduledict(self): class A: a = 1 b = 2 - assert self.is_strdict(A) + assert self.is_moduledict(A) def test_attr_slots(self): class C: diff --git a/pypy/module/_cffi_backend/cdataobj.py b/pypy/module/_cffi_backend/cdataobj.py --- a/pypy/module/_cffi_backend/cdataobj.py +++ b/pypy/module/_cffi_backend/cdataobj.py @@ -433,17 +433,22 @@ def _sizeof(self): return self.ctype.size - def with_gc(self, w_destructor): + def with_gc(self, w_destructor, size=0): space = self.space if space.is_none(w_destructor): if isinstance(self, W_CDataGCP): self.detach_destructor() - return space.w_None - raise oefmt(space.w_TypeError, - "Can remove destructor only on a object " - "previously returned by ffi.gc()") - with self as ptr: - return W_CDataGCP(space, ptr, self.ctype, self, w_destructor) + w_res = space.w_None + else: + raise oefmt(space.w_TypeError, + "Can remove destructor only on a object " + "previously returned by ffi.gc()") + else: + with self as ptr: + w_res = W_CDataGCP(space, ptr, self.ctype, self, w_destructor) + if size != 0: + rgc.add_memory_pressure(size) + return w_res def unpack(self, length): from pypy.module._cffi_backend.ctypeptr import W_CTypePtrOrArray diff --git a/pypy/module/_cffi_backend/ffi_obj.py b/pypy/module/_cffi_backend/ffi_obj.py --- a/pypy/module/_cffi_backend/ffi_obj.py +++ b/pypy/module/_cffi_backend/ffi_obj.py @@ -351,14 +351,14 @@ return handle.from_handle(self.space, w_arg) - @unwrap_spec(w_cdata=W_CData) - def descr_gc(self, w_cdata, w_destructor): + @unwrap_spec(w_cdata=W_CData, size=int) + def descr_gc(self, w_cdata, w_destructor, size=0): """\ Return a new cdata object that points to the same data. Later, when this new cdata object is garbage-collected, 'destructor(old_cdata_object)' will be called.""" # - return w_cdata.with_gc(w_destructor) + return w_cdata.with_gc(w_destructor, size) @unwrap_spec(replace_with='text') diff --git a/pypy/module/_cffi_backend/func.py b/pypy/module/_cffi_backend/func.py --- a/pypy/module/_cffi_backend/func.py +++ b/pypy/module/_cffi_backend/func.py @@ -257,6 +257,6 @@ # ____________________________________________________________ -@unwrap_spec(w_cdata=cdataobj.W_CData) -def gcp(space, w_cdata, w_destructor): - return w_cdata.with_gc(w_destructor) +@unwrap_spec(w_cdata=cdataobj.W_CData, size=int) +def gcp(space, w_cdata, w_destructor, size=0): + return w_cdata.with_gc(w_destructor, size) diff --git a/pypy/module/_cffi_backend/test/test_ffi_obj.py b/pypy/module/_cffi_backend/test/test_ffi_obj.py --- a/pypy/module/_cffi_backend/test/test_ffi_obj.py +++ b/pypy/module/_cffi_backend/test/test_ffi_obj.py @@ -377,7 +377,7 @@ raises(TypeError, ffi.gc, p, None) seen = [] q1 = ffi.gc(p, lambda p: seen.append(1)) - q2 = ffi.gc(q1, lambda p: seen.append(2)) + q2 = ffi.gc(q1, lambda p: seen.append(2), size=123) import gc; gc.collect() assert seen == [] assert ffi.gc(q1, None) is None diff --git a/pypy/module/_codecs/__init__.py b/pypy/module/_codecs/__init__.py --- a/pypy/module/_codecs/__init__.py +++ b/pypy/module/_codecs/__init__.py @@ -1,5 +1,6 @@ from pypy.interpreter.mixedmodule import MixedModule from rpython.rlib import runicode +from rpython.rlib.objectmodel import not_rpython from pypy.module._codecs import interp_codecs class Module(MixedModule): @@ -86,9 +87,8 @@ 'unicode_internal_encode' : 'interp_codecs.unicode_internal_encode', } + @not_rpython def __init__(self, space, *args): - "NOT_RPYTHON" - # mbcs codec is Windows specific, and based on rffi. if (hasattr(runicode, 'str_decode_mbcs')): self.interpleveldefs['mbcs_encode'] = 'interp_codecs.mbcs_encode' diff --git a/pypy/module/_codecs/interp_codecs.py b/pypy/module/_codecs/interp_codecs.py --- a/pypy/module/_codecs/interp_codecs.py +++ b/pypy/module/_codecs/interp_codecs.py @@ -1,5 +1,5 @@ from rpython.rlib import jit -from rpython.rlib.objectmodel import we_are_translated +from rpython.rlib.objectmodel import we_are_translated, not_rpython from rpython.rlib.rstring import UnicodeBuilder from rpython.rlib.runicode import code_to_unichr, MAXUNICODE @@ -268,8 +268,8 @@ raise oefmt(space.w_TypeError, "don't know how to handle %T in error callback", w_exc) +@not_rpython def register_builtin_error_handlers(space): - "NOT_RPYTHON" state = space.fromcache(CodecState) for error in ("strict", "ignore", "replace", "xmlcharrefreplace", "backslashreplace"): diff --git a/pypy/module/_vmprof/test/test__vmprof.py b/pypy/module/_vmprof/test/test__vmprof.py --- a/pypy/module/_vmprof/test/test__vmprof.py +++ b/pypy/module/_vmprof/test/test__vmprof.py @@ -1,3 +1,4 @@ +import sys from rpython.tool.udir import udir from pypy.tool.pytest.objspace import gettestobjspace @@ -7,6 +8,8 @@ def setup_class(cls): cls.w_tmpfilename = cls.space.wrap(str(udir.join('test__vmprof.1'))) cls.w_tmpfilename2 = cls.space.wrap(str(udir.join('test__vmprof.2'))) + cls.w_plain = cls.space.wrap(not cls.runappdirect and + '__pypy__' not in sys.builtin_module_names) def test_import_vmprof(self): tmpfile = open(self.tmpfilename, 'wb') @@ -117,6 +120,8 @@ assert _vmprof.get_profile_path() is None def test_stop_sampling(self): + if not self.plain: + skip("unreliable test except on CPython without -A") import os import _vmprof tmpfile = open(self.tmpfilename, 'wb') diff --git a/pypy/module/array/interp_array.py b/pypy/module/array/interp_array.py --- a/pypy/module/array/interp_array.py +++ b/pypy/module/array/interp_array.py @@ -118,6 +118,29 @@ return space.w_True return space.w_False +index_count_jd = jit.JitDriver( + greens = ['count', 'arrclass', 'tp_item'], + reds = 'auto', name = 'array.index_or_count') + +def index_count_array(arr, w_val, count=False): + space = arr.space + tp_item = space.type(w_val) + arrclass = arr.__class__ + cnt = 0 + for i in range(arr.len): + index_count_jd.jit_merge_point( + tp_item=tp_item, count=count, + arrclass=arrclass) + w_item = arr.w_getitem(space, i) + if space.eq_w(w_item, w_val): + if count: + cnt += 1 + else: + return i + if count: + return cnt + return -1 + UNICODE_ARRAY = lltype.Ptr(lltype.Array(lltype.UniChar, hints={'nolength': True})) @@ -257,17 +280,12 @@ """ self.extend(w_x) - def descr_count(self, space, w_val): + def descr_count(self, space, w_x): """ count(x) Return number of occurrences of x in the array. """ - cnt = 0 - for i in range(self.len): - # XXX jitdriver - w_item = self.w_getitem(space, i) - if space.eq_w(w_item, w_val): - cnt += 1 + cnt = index_count_array(self, w_x, count=True) return space.newint(cnt) def descr_index(self, space, w_x): @@ -275,10 +293,9 @@ Return index of first occurrence of x in the array. """ - for i in range(self.len): - w_item = self.w_getitem(space, i) - if space.eq_w(w_item, w_x): - return space.newint(i) + res = index_count_array(self, w_x, count=False) + if res >= 0: + return space.newint(res) raise oefmt(space.w_ValueError, "array.index(x): x not in list") def descr_reverse(self, space): @@ -752,7 +769,9 @@ class TypeCode(object): def __init__(self, itemtype, unwrap, canoverflow=False, signed=False, - method='__int__'): + method='__int__', errorname=None): + if errorname is None: + errorname = unwrap[:-2] self.itemtype = itemtype self.bytes = rffi.sizeof(itemtype) self.arraytype = lltype.Array(itemtype, hints={'nolength': True}) @@ -762,6 +781,7 @@ self.canoverflow = canoverflow self.w_class = None self.method = method + self.errorname = errorname def _freeze_(self): # hint for the annotator: track individual constant instances @@ -785,8 +805,8 @@ 'i': TypeCode(rffi.INT, 'int_w', True, True), 'I': _UINTTypeCode, 'l': TypeCode(rffi.LONG, 'int_w', True, True), - 'L': TypeCode(rffi.ULONG, 'bigint_w'), # Overflow handled by - # rbigint.touint() which + 'L': TypeCode(rffi.ULONG, 'bigint_w', # Overflow handled by + errorname="integer"), # rbigint.touint() which # corresponds to the # C-type unsigned long 'f': TypeCode(lltype.SingleFloat, 'float_w', method='__float__'), @@ -864,7 +884,7 @@ item = unwrap(space.call_method(w_item, mytype.method)) except OperationError: raise oefmt(space.w_TypeError, - "array item must be " + mytype.unwrap[:-2]) + "array item must be " + mytype.errorname) else: raise if mytype.unwrap == 'bigint_w': diff --git a/pypy/module/array/test/test_array.py b/pypy/module/array/test/test_array.py --- a/pypy/module/array/test/test_array.py +++ b/pypy/module/array/test/test_array.py @@ -162,6 +162,11 @@ raises(OverflowError, a.append, -1) raises(OverflowError, a.append, 2 ** (8 * b)) + def test_errormessage(self): + a = self.array("L", [1, 2, 3]) + excinfo = raises(TypeError, "a[0] = 'abc'") + assert str(excinfo.value) == "array item must be integer" + def test_fromstring(self): import sys diff --git a/pypy/module/cppyy/test/test_cint.py b/pypy/module/cppyy/test/test_cint.py deleted file mode 100644 --- a/pypy/module/cppyy/test/test_cint.py +++ /dev/null @@ -1,710 +0,0 @@ -import py, os, sys - -# These tests are for the CINT backend only (they exercise ROOT features -# and classes that are not loaded/available with the Reflex backend). At -# some point, these tests are likely covered by the CLang/LLVM backend. -from pypy.module.cppyy import capi -if capi.identify() != 'CINT': - py.test.skip("backend-specific: CINT-only tests") - -# load _cffi_backend early, or its global vars are counted as leaks in the -# test (note that the module is not otherwise used in the test itself) -from pypy.module._cffi_backend import newtype - -currpath = py.path.local(__file__).dirpath() -iotypes_dct = str(currpath.join("iotypesDict.so")) - -def setup_module(mod): - if sys.platform == 'win32': - py.test.skip("win32 not supported so far") - err = os.system("cd '%s' && make CINT=t iotypesDict.so" % currpath) - if err: - raise OSError("'make' failed (see stderr)") - -class AppTestCINT: - spaceconfig = dict(usemodules=['cppyy', '_rawffi', 'itertools']) - - def test01_globals(self): - """Test the availability of ROOT globals""" - - import cppyy - - assert cppyy.gbl.gROOT - assert cppyy.gbl.gApplication - assert cppyy.gbl.gSystem - assert cppyy.gbl.TInterpreter.Instance() # compiled - assert cppyy.gbl.TInterpreter # interpreted - assert cppyy.gbl.TDirectory.CurrentDirectory() # compiled - assert cppyy.gbl.TDirectory # interpreted - - def test02_write_access_to_globals(self): - """Test overwritability of ROOT globals""" - - import cppyy - - oldval = cppyy.gbl.gDebug - assert oldval != 3 - - proxy = cppyy.gbl.__class__.__dict__['gDebug'] - cppyy.gbl.gDebug = 3 - assert proxy.__get__(proxy, None) == 3 - - # this is where this test differs from test03_write_access_to_globals - # in test_pythonify.py - cppyy.gbl.gROOT.ProcessLine('int gDebugCopy = gDebug;') - assert cppyy.gbl.gDebugCopy == 3 - - cppyy.gbl.gDebug = oldval - - def test03_create_access_to_globals(self): - """Test creation and access of new ROOT globals""" - - import cppyy - - cppyy.gbl.gROOT.ProcessLine('double gMyOwnGlobal = 3.1415') - assert cppyy.gbl.gMyOwnGlobal == 3.1415 - - proxy = cppyy.gbl.__class__.__dict__['gMyOwnGlobal'] - assert proxy.__get__(proxy, None) == 3.1415 - - def test04_auto_loading(self): - """Test auto-loading by retrieving a non-preloaded class""" - - import cppyy - - l = cppyy.gbl.TLorentzVector() - assert isinstance(l, cppyy.gbl.TLorentzVector) - - def test05_macro_loading(self): - """Test accessibility to macro classes""" - - import cppyy - - loadres = cppyy.gbl.gROOT.LoadMacro('simple_class.C') - assert loadres == 0 - - base = cppyy.gbl.MySimpleBase - simple = cppyy.gbl.MySimpleDerived - simple_t = cppyy.gbl.MySimpleDerived_t - - assert issubclass(simple, base) - assert simple is simple_t - - c = simple() - assert isinstance(c, simple) - assert c.m_data == c.get_data() - - c.set_data(13) - assert c.m_data == 13 - assert c.get_data() == 13 - - -class AppTestCINTPYTHONIZATIONS: - spaceconfig = dict(usemodules=['cppyy', '_rawffi', 'itertools']) - - def test01_strings(self): - """Test TString/TObjString compatibility""" - - import cppyy - - pyteststr = "aap noot mies" - def test_string(s1, s2): - assert len(s1) == len(s2) - assert s1 == s1 - assert s1 == s2 - assert s1 == str(s1) - assert s1 == pyteststr - assert s1 != "aap" - assert s1 != "" - assert s1 < "noot" - assert repr(s1) == repr(s2) - - s1 = cppyy.gbl.TString(pyteststr) - test_string(s1, pyteststr) - - s3 = cppyy.gbl.TObjString(pyteststr) - test_string(s3, pyteststr) - - def test03_TVector(self): - """Test TVector2/3/T behavior""" - - import cppyy, math - - N = 51 - - # TVectorF is a typedef of floats - v = cppyy.gbl.TVectorF(N) - for i in range(N): - v[i] = i*i - - assert len(v) == N - for j in v: - assert round(v[int(math.sqrt(j)+0.5)]-j, 5) == 0. - - def test04_TStringTObjString(self): - """Test string/TString interchangebility""" - - import cppyy - - test = "aap noot mies" - - s1 = cppyy.gbl.TString(test ) - s2 = str(s1) - - assert s1 == test - assert test == s2 - assert s1 == s2 - - s3 = cppyy.gbl.TObjString(s2) - assert s3 == test - assert s2 == s3 - - # force use of: TNamed(const TString &name, const TString &title) - n = cppyy.gbl.TNamed(test, cppyy.gbl.TString("title")) - assert n.GetTitle() == "title" - assert n.GetName() == test - - -class AppTestCINTTTREE: - spaceconfig = dict(usemodules=['cppyy', '_rawffi', 'itertools']) - - def setup_class(cls): - cls.w_N = cls.space.newint(5) - cls.w_M = cls.space.newint(10) - cls.w_fname = cls.space.newtext("test.root") - cls.w_tname = cls.space.newtext("test") - cls.w_title = cls.space.newtext("test tree") - cls.w_iotypes = cls.space.appexec([], """(): - import cppyy - return cppyy.load_reflection_info(%r)""" % (iotypes_dct,)) - - def test01_write_stdvector(self): - """Test writing of a single branched TTree with an std::vector<double>""" - - from cppyy import gbl # bootstraps, only needed for tests - from cppyy.gbl import TFile, TTree - from cppyy.gbl.std import vector - - f = TFile(self.fname, "RECREATE") - mytree = TTree(self.tname, self.title) - mytree._python_owns = False - - v = vector("double")() - raises(TypeError, TTree.Branch, None, "mydata", v.__class__.__name__, v) - raises(TypeError, TTree.Branch, v, "mydata", v.__class__.__name__, v) - - mytree.Branch("mydata", v.__class__.__name__, v) - - for i in range(self.N): - for j in range(self.M): - v.push_back(i*self.M+j) - mytree.Fill() - v.clear() - f.Write() - f.Close() - - def test02_file_open(self): - - from cppyy import gbl - - f = gbl.TFile.Open(self.fname) - s = str(f) # should not raise - r = repr(f) - - f.Close() - - def test03_read_stdvector(self): - """Test reading of a single branched TTree with an std::vector<double>""" - - from cppyy import gbl - from cppyy.gbl import TFile - - f = TFile(self.fname) - mytree = f.Get(self.tname) - - i = 0 - for event in mytree: - assert len(event.mydata) == self.M - for entry in event.mydata: - assert i == int(entry) - i += 1 - assert i == self.N * self.M - - f.Close() - - def test04_write_some_data_object(self): - """Test writing of a complex data object""" - - from cppyy import gbl - from cppyy.gbl import TFile, TTree, IO - from cppyy.gbl.IO import SomeDataObject - - f = TFile(self.fname, "RECREATE") - mytree = TTree(self.tname, self.title) - - d = SomeDataObject() - b = mytree.Branch("data", d) - mytree._python_owns = False - assert b - - for i in range(self.N): - for j in range(self.M): - d.add_float(i*self.M+j) - d.add_tuple(d.get_floats()) - - mytree.Fill() - - f.Write() - f.Close() - - def test05_read_some_data_object(self): - """Test reading of a complex data object""" - - from cppyy import gbl - from cppyy.gbl import TFile - - f = TFile(self.fname) - mytree = f.Get(self.tname) - - j = 1 - for event in mytree: - i = 0 - assert len(event.data.get_floats()) == j*self.M - for entry in event.data.get_floats(): - assert i == int(entry) - i += 1 - - k = 1 - assert len(event.data.get_tuples()) == j - for mytuple in event.data.get_tuples(): - i = 0 - assert len(mytuple) == k*self.M - for entry in mytuple: - assert i == int(entry) - i += 1 - k += 1 - j += 1 - assert j-1 == self.N - # - f.Close() - - def test06_branch_activation(self): - """Test of automatic branch activation""" - - from cppyy import gbl - from cppyy.gbl import TFile, TTree - from cppyy.gbl.std import vector - - L = 5 - - # writing - f = TFile(self.fname, "RECREATE") - mytree = TTree(self.tname, self.title) - mytree._python_owns = False - - for i in range(L): - v = vector("double")() - mytree.Branch("mydata_%d"%i, v.__class__.__name__, v) - mytree.__dict__["v_%d"%i] = v - - for i in range(self.N): - for k in range(L): - v = mytree.__dict__["v_%d"%k] - for j in range(self.M): - mytree.__dict__["v_%d"%k].push_back(i*self.M+j*L+k) - mytree.Fill() - for k in range(L): - v = mytree.__dict__["v_%d"%k] - v.clear() - f.Write() - f.Close() - - del mytree, f - import gc - gc.collect() - - # reading - f = TFile(self.fname) - mytree = f.Get(self.tname) - - # force (initial) disabling of all branches - mytree.SetBranchStatus("*",0); - - i = 0 - for event in mytree: - for k in range(L): - j = 0 - data = getattr(mytree, "mydata_%d"%k) - assert len(data) == self.M - for entry in data: - assert entry == i*self.M+j*L+k - j += 1 - assert j == self.M - i += 1 - assert i == self.N - - f.Close() - - def test07_write_builtin(self): - """Test writing of builtins""" - - from cppyy import gbl # bootstraps, only needed for tests - from cppyy.gbl import TFile, TTree - from cppyy.gbl.std import vector - - f = TFile(self.fname, "RECREATE") - mytree = TTree(self.tname, self.title) - mytree._python_owns = False - - import array - mytree.ba = array.array('c', [chr(0)]) - mytree.ia = array.array('i', [0]) - mytree.da = array.array('d', [0.]) - - mytree.Branch("my_bool", mytree.ba, "my_bool/O") - mytree.Branch("my_int", mytree.ia, "my_int/I") - mytree.Branch("my_int2", mytree.ia, "my_int2/I") - mytree.Branch("my_double", mytree.da, "my_double/D") - - for i in range(self.N): - # make sure value is different from default (0) - mytree.ba[0] = i%2 and chr(0) or chr(1) - mytree.ia[0] = i+1 - mytree.da[0] = (i+1)/2. - mytree.Fill() - f.Write() - f.Close() - - def test08_read_builtin(self): - """Test reading of builtins""" - - from cppyy import gbl - from cppyy.gbl import TFile - - f = TFile(self.fname) - mytree = f.Get(self.tname) - - raises(AttributeError, getattr, mytree, "does_not_exist") - - i = 1 - for event in mytree: - assert event.my_bool == (i-1)%2 and 0 or 1 - assert event.my_int == i - assert event.my_double == i/2. - i += 1 - assert (i-1) == self.N - - f.Close() - - def test09_user_read_builtin(self): - """Test user-directed reading of builtins""" - - from cppyy import gbl - from cppyy.gbl import TFile - - f = TFile(self.fname) - mytree = f.Get(self.tname) - - # note, this is an old, annoted tree from test08 - for i in range(3, mytree.GetEntriesFast()): - mytree.GetEntry(i) - assert mytree.my_int == i+1 - assert mytree.my_int2 == i+1 - - f.Close() - -class AppTestCINTREGRESSION: - spaceconfig = dict(usemodules=['cppyy', '_rawffi', 'itertools']) - - # these are tests that at some point in the past resulted in failures on - # PyROOT; kept here to confirm no regression from PyROOT - - def test01_regression(self): - """TPaveText::AddText() used to result in KeyError""" - - # This is where the original problem was discovered, and the test is - # left in. However, the detailed underlying problem, as well as the - # solution to it, is tested in test_fragile.py - - from cppyy import gbl - from cppyy.gbl import TPaveText - - hello = TPaveText( .1, .8, .9, .97 ) - hello.AddText( 'Hello, World!' ) - - -class AppTestCINTFUNCTION: - spaceconfig = dict(usemodules=['cppyy', '_rawffi', 'itertools']) - _pypytest_leaks = None # TODO: figure out the false positives - - # test the function callbacks; this does not work with Reflex, as it can - # not generate functions on the fly (it might with cffi?) - - @py.test.mark.dont_track_allocations("TODO: understand; initialization left-over?") - def test01_global_function_callback(self): - """Test callback of a python global function""" - - import cppyy, gc - TF1 = cppyy.gbl.TF1 - - def identity(x): - return x[0] - - f = TF1("pyf1", identity, -1., 1., 0) - - assert f.Eval(0.5) == 0.5 - assert f.Eval(-10.) == -10. - assert f.Eval(1.0) == 1.0 - - # check proper propagation of default value - f = TF1("pyf1d", identity, -1., 1.) - - assert f.Eval(0.5) == 0.5 - - del f # force here, to prevent leak-check complaints - gc.collect() - - def test02_callable_object_callback(self): - """Test callback of a python callable object""" - - import cppyy, gc - TF1 = cppyy.gbl.TF1 - - class Linear: - def __call__(self, x, par): - return par[0] + x[0]*par[1] - - f = TF1("pyf2", Linear(), -1., 1., 2) - f.SetParameters(5., 2.) - - assert f.Eval(-0.1) == 4.8 - assert f.Eval(1.3) == 7.6 - - del f # force here, to prevent leak-check complaints - gc.collect() - - def test03_fit_with_python_gaussian(self): - """Test fitting with a python global function""" - - # note: this function is dread-fully slow when running testing un-translated - - import cppyy, gc, math - TF1, TH1F = cppyy.gbl.TF1, cppyy.gbl.TH1F - - def pygaus(x, par): - arg1 = 0 - scale1 = 0 - ddx = 0.01 - - if (par[2] != 0.0): - arg1 = (x[0]-par[1])/par[2] - scale1 = (ddx*0.39894228)/par[2] - h1 = par[0]/(1+par[3]) - - gauss = h1*scale1*math.exp(-0.5*arg1*arg1) - else: - gauss = 0. - return gauss - - f = TF1("pygaus", pygaus, -4, 4, 4) - f.SetParameters(600, 0.43, 0.35, 600) - - h = TH1F("h", "test", 100, -4, 4) - h.FillRandom("gaus", 200000) - h.Fit(f, "0Q") - - assert f.GetNDF() == 96 - result = f.GetParameters() - assert round(result[1] - 0., 1) == 0 # mean - assert round(result[2] - 1., 1) == 0 # s.d. - - del f # force here, to prevent leak-check complaints - gc.collect() - - -class AppTestSURPLUS: - spaceconfig = dict(usemodules=['cppyy', '_rawffi', 'itertools']) - - # these are tests that were historically exercised on ROOT classes and - # have twins on custom classes; kept here just in case differences crop - # up between the ROOT classes and the custom ones - - def test01_class_enum(self): - """Test class enum access and values""" - - import cppyy - TObject = cppyy.gbl.TObject - gROOT = cppyy.gbl.gROOT - - assert TObject.kBitMask == gROOT.ProcessLine("return TObject::kBitMask;") - assert TObject.kIsOnHeap == gROOT.ProcessLine("return TObject::kIsOnHeap;") - assert TObject.kNotDeleted == gROOT.ProcessLine("return TObject::kNotDeleted;") - assert TObject.kZombie == gROOT.ProcessLine("return TObject::kZombie;") - - t = TObject() - - assert TObject.kBitMask == t.kBitMask - assert TObject.kIsOnHeap == t.kIsOnHeap - assert TObject.kNotDeleted == t.kNotDeleted - assert TObject.kZombie == t.kZombie - - def test02_global_enum(self): - """Test global enums access and values""" - - import cppyy - from cppyy import gbl - - assert gbl.kRed == gbl.gROOT.ProcessLine("return kRed;") - assert gbl.kGreen == gbl.gROOT.ProcessLine("return kGreen;") - assert gbl.kBlue == gbl.gROOT.ProcessLine("return kBlue;") - - def test03_copy_contructor(self): - """Test copy constructor""" - - import cppyy - TLorentzVector = cppyy.gbl.TLorentzVector - - t1 = TLorentzVector(1., 2., 3., -4.) - t2 = TLorentzVector(0., 0., 0., 0.) - t3 = TLorentzVector(t1) - - assert t1 == t3 - assert t1 != t2 - - for i in range(4): - assert t1[i] == t3[i] - - def test04_object_validity(self): - """Test object validity checking""" - - import cppyy - - t1 = cppyy.gbl.TObject() - - assert t1 - assert not not t1 - - t2 = cppyy.gbl.gROOT.FindObject("Nah, I don't exist") - - assert not t2 - - def test05_element_access(self): - """Test access to elements in matrix and array objects.""" - - from cppyy import gbl - - N = 3 - v = gbl.TVectorF(N) - m = gbl.TMatrixD(N, N) - - for i in range(N): - assert v[i] == 0.0 - - for j in range(N): - assert m[i][j] == 0.0 - - def test06_static_function_call( self ): - """Test call to static function.""" - - import cppyy - TROOT, gROOT = cppyy.gbl.TROOT, cppyy.gbl.gROOT - - c1 = TROOT.Class() - assert not not c1 - - c2 = gROOT.Class() - - assert c1 == c2 - - old = gROOT.GetDirLevel() - TROOT.SetDirLevel(2) - assert 2 == gROOT.GetDirLevel() - gROOT.SetDirLevel(old) - - old = TROOT.GetDirLevel() - gROOT.SetDirLevel(3) - assert 3 == TROOT.GetDirLevel() - TROOT.SetDirLevel(old) - - def test07_macro(self): - """Test access to cpp macro's""" - - from cppyy import gbl - - assert gbl.NULL == 0 - - gbl.gROOT.ProcessLine('#define aap "aap"') - gbl.gROOT.ProcessLine('#define noot 1') - gbl.gROOT.ProcessLine('#define mies 2.0') - - # TODO: macro's assumed to always be of long type ... - #assert gbl.aap == "aap" - assert gbl.noot == 1 - #assert gbl.mies == 2.0 - - def test08_opaque_pointer_passing(self): - """Test passing around of opaque pointers""" - - import cppyy - - # TODO: figure out CObject (see also test_advanced.py) - - s = cppyy.gbl.TString("Hello World!") - #cobj = cppyy.as_cobject(s) - addr = cppyy.addressof(s) - - #assert s == cppyy.bind_object(cobj, s.__class__) - #assert s == cppyy.bind_object(cobj, "TString") - assert s == cppyy.bind_object(addr, s.__class__) - assert s == cppyy.bind_object(addr, "TString") - - def test09_object_and_pointer_comparisons(self): - """Verify object and pointer comparisons""" - - import cppyy - gbl = cppyy.gbl - - c1 = cppyy.bind_object(0, gbl.TCanvas) - assert c1 == None - assert None == c1 - - c2 = cppyy.bind_object(0, gbl.TCanvas) - assert c1 == c2 - assert c2 == c1 - - # TLorentzVector overrides operator== - l1 = cppyy.bind_object(0, gbl.TLorentzVector) - assert l1 == None - assert None == l1 - - assert c1 != l1 - assert l1 != c1 - - l2 = cppyy.bind_object(0, gbl.TLorentzVector) - assert l1 == l2 - assert l2 == l1 - - l3 = gbl.TLorentzVector(1, 2, 3, 4) - l4 = gbl.TLorentzVector(1, 2, 3, 4) - l5 = gbl.TLorentzVector(4, 3, 2, 1) - assert l3 == l4 - assert l4 == l3 - - assert l3 != None # like this to ensure __ne__ is called - assert None != l3 # id. - assert l3 != l5 - assert l5 != l3 - - def test10_recursive_remove(self): - """Verify that objects are recursively removed when destroyed""" - - import cppyy - - c = cppyy.gbl.TClass.GetClass("TObject") - _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit