New upstream version 7.3.4~rc2+dfsg
Stefano Rivera
3 years ago
98 | 98 | Alex Martelli |
99 | 99 | Spenser Bauman |
100 | 100 | Michal Bendowski |
101 | nulano | |
101 | Ondrej Baranovič | |
102 | 102 | Jan de Mooij |
103 | 103 | Stefan Beyer |
104 | 104 | Tyler Wade |
114 | 114 | Devin Jeanpierre |
115 | 115 | Bob Ippolito |
116 | 116 | Bruno Gola |
117 | nulano | |
118 | 117 | David Malcolm |
119 | 118 | Yannick Jadoul |
120 | 119 | Squeaky |
37 | 37 | def close(self): |
38 | 38 | with _lock: |
39 | 39 | if self.__ll_dbm: |
40 | lib.gdbm_close(self.__ll_dbm) | |
40 | lib.pygdbm_close(self.__ll_dbm) | |
41 | 41 | self.__ll_dbm = None |
42 | 42 | |
43 | 43 | def __raise_from_errno(self): |
10 | 10 | #define GDBM_NOLOCK ... |
11 | 11 | #define GDBM_REPLACE ... |
12 | 12 | |
13 | void* gdbm_open(char *, int, int, int, void (*)()); | |
14 | void gdbm_close(void*); | |
13 | typedef struct gdbm_file_info *GDBM_FILE; | |
14 | ||
15 | GDBM_FILE gdbm_open(const char *, int, int, int, void (*)(const char *)); | |
15 | 16 | |
16 | 17 | typedef struct { |
17 | 18 | char *dptr; |
18 | 19 | int dsize; |
19 | 20 | } datum; |
20 | 21 | |
21 | datum gdbm_fetch(void*, datum); | |
22 | datum gdbm_fetch(GDBM_FILE, datum); | |
22 | 23 | datum pygdbm_fetch(void*, char*, int); |
23 | int gdbm_delete(void*, datum); | |
24 | int gdbm_store(void*, datum, datum, int); | |
25 | int gdbm_exists(void*, datum); | |
26 | int pygdbm_exists(void*, char*, int); | |
24 | int gdbm_delete(GDBM_FILE, datum); | |
25 | int gdbm_store(GDBM_FILE, datum, datum, int); | |
26 | int gdbm_exists(GDBM_FILE, datum); | |
27 | int pygdbm_exists(GDBM_FILE, char*, int); | |
28 | void pygdbm_close(GDBM_FILE); | |
27 | 29 | |
28 | int gdbm_reorganize(void*); | |
30 | int gdbm_reorganize(GDBM_FILE); | |
29 | 31 | |
30 | datum gdbm_firstkey(void*); | |
31 | datum gdbm_nextkey(void*, datum); | |
32 | void gdbm_sync(void*); | |
32 | datum gdbm_firstkey(GDBM_FILE); | |
33 | datum gdbm_nextkey(GDBM_FILE, datum); | |
34 | void gdbm_sync(GDBM_FILE); | |
33 | 35 | |
34 | char* gdbm_strerror(int); | |
35 | int gdbm_errno; | |
36 | const char* gdbm_strerror(int); | |
37 | extern int gdbm_errno; | |
36 | 38 | |
39 | /* Needed to release returned values */ | |
37 | 40 | void free(void*); |
38 | 41 | ''') |
39 | 42 | |
57 | 60 | datum key = {dptr, dsize}; |
58 | 61 | return gdbm_exists(gdbm_file, key); |
59 | 62 | } |
63 | ||
64 | static void pygdbm_close(GDBM_FILE gdbm_file) { | |
65 | /* | |
66 | * In verison 17, void gdbm_close() became int gdbm_close() | |
67 | * Work around that by wrapping the function | |
68 | */ | |
69 | gdbm_close(gdbm_file); | |
70 | } | |
60 | 71 | ''', libraries=['gdbm'], **kwds) |
61 | 72 | |
62 | 73 |
0 | 0 | from __future__ import print_function |
1 | import sys, shutil, os, tempfile, hashlib, collections | |
1 | import collections | |
2 | import hashlib | |
3 | import os | |
4 | import platform | |
5 | import shutil | |
6 | import sys | |
2 | 7 | import sysconfig |
8 | import tempfile | |
3 | 9 | from os.path import join |
4 | 10 | |
5 | 11 | try: |
54 | 60 | # without an _ssl module, but the OpenSSL download site redirect HTTP |
55 | 61 | # to HTTPS |
56 | 62 | cffi_dependencies = { |
57 | 'lzma': ('http://distfiles.macports.org/xz/xz-5.2.5.tar.bz2', | |
63 | '_ssl': ('http://distfiles.macports.org/openssl/openssl-1.1.1k.tar.gz', | |
64 | '892a0875b9872acd04a9fde79b1f943075d5ea162415de3047c327df33fbaee5', | |
65 | [['./config', '--prefix=/usr', 'no-shared'], | |
66 | ['make', '-s', '-j', str(multiprocessing.cpu_count())], | |
67 | ['make', 'install', 'DESTDIR={}/'.format(deps_destdir)], | |
68 | ]), | |
69 | } | |
70 | if sys.platform == 'darwin' or platform.machine() == 'aarch64': | |
71 | # TODO: use these on x86 after upgrading Docker images to manylinux2014 | |
72 | cffi_dependencies['_gdbm'] = ( | |
73 | # this does not compile on the x86 buildbot, linker is missing '_history_list' | |
74 | 'http://distfiles.macports.org/gdbm/gdbm-1.18.1.tar.gz', | |
75 | '86e613527e5dba544e73208f42b78b7c022d4fa5a6d5498bf18c8d6f745b91dc', | |
76 | [configure_args + ['--without-readline'], | |
77 | ['make', '-s', '-j', str(multiprocessing.cpu_count())], | |
78 | ['make', 'install', 'DESTDIR={}/'.format(deps_destdir)], | |
79 | ]) | |
80 | cffi_dependencies['lzma'] = ( | |
81 | # this does not compile on the linux64 buildbot, needs -fPIC | |
82 | 'http://distfiles.macports.org/xz/xz-5.2.5.tar.bz2', | |
58 | 83 | '5117f930900b341493827d63aa910ff5e011e0b994197c3b71c08a20228a42df', |
59 | 84 | [configure_args, |
60 | 85 | ['make', '-s', '-j', str(multiprocessing.cpu_count())], |
61 | 86 | ['make', 'install', 'DESTDIR={}/'.format(deps_destdir)], |
62 | ]), | |
63 | '_ssl': ('http://distfiles.macports.org/openssl/openssl-1.1.1f.tar.gz', | |
64 | '186c6bfe6ecfba7a5b48c47f8a1673d0f3b0e5ba2e25602dd23b629975da3f35', | |
65 | [['./config', '--prefix=/usr', 'no-shared'], | |
66 | ['make', '-s', '-j', str(multiprocessing.cpu_count())], | |
67 | ['make', 'install', 'DESTDIR={}/'.format(deps_destdir)], | |
68 | ]), | |
69 | # this does not compile on the buildbot, linker is missing '_history_list' | |
70 | 'gdbm': ('http://distfiles.macports.org/gdbm/gdbm-1.18.1.tar.gz', | |
71 | '86e613527e5dba544e73208f42b78b7c022d4fa5a6d5498bf18c8d6f745b91dc', | |
72 | [configure_args + ['--without-readline'], | |
73 | ['make', '-s', '-j', str(multiprocessing.cpu_count())], | |
74 | ['make', 'install', 'DESTDIR={}/'.format(deps_destdir)], | |
75 | ]), | |
76 | } | |
77 | ||
87 | ]) | |
78 | 88 | |
79 | 89 | def _unpack_tarfile(filename, extract_dir): |
80 | 90 | """Unpack tar/tar.gz/tar.bz2/tar.xz `filename` to `extract_dir` |
170 | 180 | def create_cffi_import_libraries(pypy_c, options, basedir, only=None, |
171 | 181 | embed_dependencies=False, rebuild=False): |
172 | 182 | from rpython.tool.runsubprocess import run_subprocess |
183 | print('calling create_cffi_import_libraries with "embed_dependencies"', embed_dependencies) | |
173 | 184 | |
174 | 185 | shutil.rmtree(str(join(basedir,'lib_pypy','__pycache__')), |
175 | 186 | ignore_errors=True) |
183 | 194 | env['INCLUDE'] = externals_path + r'\include;' + env.get('INCLUDE', '') |
184 | 195 | env['LIB'] = externals_path + r'\lib;' + env.get('LIB', '') |
185 | 196 | env['PATH'] = externals_path + r'\bin;' + env.get('PATH', '') |
197 | else: | |
198 | env['CFLAGS'] = '-fPIC ' + env.get('CFLAGS', '') | |
186 | 199 | status, stdout, stderr = run_subprocess(str(pypy_c), ['-c', 'import setuptools']) |
187 | 200 | if status != 0: |
188 | 201 | status, stdout, stderr = run_subprocess(str(pypy_c), ['-m', 'ensurepip']) |
87 | 87 | |
88 | 88 | # not ported yet |
89 | 89 | if IS_64_BITS: |
90 | for name in ["_cppyy", "micronumpy"]: | |
90 | for name in ["_cppyy", "micronumpy", "_hpy_universal"]: | |
91 | 91 | if name in working_modules: |
92 | 92 | working_modules.remove(name) |
93 | 93 | |
98 | 98 | if "_cppyy" in working_modules: |
99 | 99 | working_modules.remove("_cppyy") # depends on ctypes |
100 | 100 | |
101 | if 1 or sys.platform.startswith('linux') and sys.maxsize <= 2**31: | |
101 | if sys.platform.startswith('linux') and sys.maxsize <= 2**31: | |
102 | 102 | # _hpy_universal needs tweaking to work on 32-bit linux |
103 | 103 | working_modules.remove('_hpy_universal') |
104 | 104 |
96 | 96 | - ``strategy(dict or list or set)``: Return the underlying strategy currently |
97 | 97 | used by the object |
98 | 98 | |
99 | - ``list_get_physical_size(obj)``: Return the physical (ie overallocated | |
100 | size) of the underlying list | |
101 | ||
99 | 102 | - ``specialized_zip_2_lists`` |
100 | 103 | - ``locals_to_fast`` |
101 | 104 | - ``set_code_callback`` |
48 | 48 | 'sphinx.ext.ifconfig', |
49 | 49 | 'sphinx.ext.graphviz', |
50 | 50 | 'pypyconfig', |
51 | 'sphinx_affiliates'] | |
51 | # 'sphinx_affiliates', | |
52 | ] | |
52 | 53 | |
53 | 54 | # Canonical URL (including the '/') so searching from rpython docs finds these |
54 | 55 | affiliate_options = { |
64 | 64 | Alex Martelli |
65 | 65 | Spenser Bauman |
66 | 66 | Michal Bendowski |
67 | nulano | |
67 | Ondrej Baranovič | |
68 | 68 | Jan de Mooij |
69 | 69 | Stefan Beyer |
70 | 70 | Tyler Wade |
5 | 5 | |
6 | 6 | .. toctree:: |
7 | 7 | |
8 | release-v7.3.4.rst | |
8 | 9 | release-v7.3.3.rst |
9 | 10 | release-v7.3.2.rst |
10 | 11 | release-v7.3.1.rst |
6 | 6 | .. toctree:: |
7 | 7 | |
8 | 8 | whatsnew-head.rst |
9 | whatsnew-pypy2-7.3.4.rst | |
9 | 10 | whatsnew-pypy2-7.3.3.rst |
10 | 11 | whatsnew-pypy2-7.3.2.rst |
11 | 12 | whatsnew-pypy2-7.3.1.rst |
41 | 42 | whatsnew-1.9.rst |
42 | 43 | |
43 | 44 | |
45 | CPython 3.7 compatible versions | |
46 | ------------------------------- | |
47 | ||
48 | .. toctree:: | |
49 | whatsnew-pypy3-head.rst | |
50 | whatsnew-pypy3-7.3.4.rst | |
51 | ||
44 | 52 | CPython 3.6 compatible versions |
45 | 53 | ------------------------------- |
46 | 54 |
8 | 8 | .. _`PyPy blog`: https://pypy.org/blog |
9 | 9 | |
10 | 10 | .. |
11 | Changelog up to commit d414fb8186a7 | |
12 | ||
13 | ||
14 | -The PyPy team is proud to release the version 7.3.4 of PyPy, which includes | |
11 | Changelog up to commit 9c11d242d78c | |
12 | ||
13 | ||
14 | The PyPy team is proud to release the version 7.3.4 of PyPy, which includes | |
15 | 15 | two different interpreters: |
16 | 16 | |
17 | 17 | - PyPy2.7, which is an interpreter supporting the syntax and the features of |
20 | 20 | |
21 | 21 | - PyPy3.7, which is an interpreter supporting the syntax and the features of |
22 | 22 | Python 3.7, including the stdlib for CPython 3.7.10. We no longer refer to |
23 | this as beta-quality | |
23 | this as beta-quality as the last incompatibilities with CPython (in the | |
24 | ``re`` module) have been fixed. | |
25 | ||
26 | We are no longer releasing a Python3.6 version, as we focus on updating to | |
27 | Python 3.8. We have begun streaming the advances towards this goal on Saturday | |
28 | evenings European time on https://www.twitch.tv/pypyproject. If Python3.6 is | |
29 | important to you, please reach out as we could offer sponsored longer term | |
30 | support. | |
24 | 31 | |
25 | 32 | The interpreters are based on much the same codebase, thus the multiple |
26 | 33 | release. This is a micro release, all APIs are compatible with the 7.3 |
27 | releases, but read on to find out what is new. | |
28 | ||
29 | .. | |
30 | The major new feature is prelminary support for the Universal mode of HPy: a | |
31 | new way of writing c-extension modules to totally encapsulate the `PyObject*`. | |
32 | The goal, as laid out in the `HPy blog post`_, is to enable a migration path | |
33 | for c-extension authors who wish their code to be performant on alternative | |
34 | interpreters like GraalPython_ (written on top of the Java virtual machine), | |
35 | RustPython_, and PyPy. Thanks to Oracle for sponsoring work on HPy. | |
34 | releases. Highlights of the release include binary **Windows 64** support, | |
35 | faster numerical instance fields, and a preliminary HPy backend. | |
36 | ||
37 | A new contributor (Ondrej Baranovič - thanks!) took us up on the challenge to get | |
38 | `windows 64-bit`_ support. The work has been merged and for the first time we | |
39 | are releasing a 64-bit Windows binary package. | |
40 | ||
41 | The release contains the biggest change to `PyPy's implementation of the | |
42 | instances of user-defined classes`_ in many years. The optimization was | |
43 | motivated by the report of performance problems running a `numerical particle | |
44 | emulation`_. We implemented an optimization that stores ``int`` and ``float`` | |
45 | instance fields in an unboxed way, as long as these fields are type-stable | |
46 | (meaning that the same field always stores the same type, using the principle | |
47 | of `type freezing`_). This gives significant performance improvements on | |
48 | numerical pure-Python code, and other code where instances store many integers | |
49 | or floating point numbers. | |
50 | ||
51 | .. _`PyPy's implementation of the instances of user-defined classes`: | |
52 | https://www.pypy.org/posts/2010/11/efficiently-implementing-python-objects-3838329944323946932.html | |
53 | .. _`numerical particle emulation`: https://github.com/paugier/nbabel | |
54 | .. _`type freezing`: https://www.csl.cornell.edu/~cbatten/pdfs/cheng-type-freezing-cgo2020.pdf | |
55 | ||
56 | There were also a number of optimizations for methods around strings and bytes, | |
57 | following user reported performance problems. If you are unhappy with PyPy's | |
58 | performance on some code of yours, please report `an issue`_! | |
59 | ||
60 | .. _`an issue`: https://foss.heptapod.net/pypy/pypy/-/issues/ | |
61 | ||
62 | A major new feature is prelminary support for the Universal mode of HPy: a | |
63 | new way of writing c-extension modules to totally encapsulate ``PyObject*``. | |
64 | The goal, as laid out in the `HPy documentation`_ and recent `HPy blog post`_, | |
65 | is to enable a migration path | |
66 | for c-extension authors who wish their code to be performant on alternative | |
67 | interpreters like GraalPython_ (written on top of the Java virtual machine), | |
68 | RustPython_, and PyPy. Thanks to Oracle and IBM for sponsoring work on HPy. | |
36 | 69 | |
37 | 70 | Several issues exposed in the 7.3.3 release were fixed. Many of them came from the |
38 | 71 | great work ongoing to ship PyPy-compatible binary packages in `conda-forge`_. |
39 | 72 | A big shout out to them for taking this on. |
40 | 73 | |
41 | There are also some significant performance improvements around maps | |
42 | (dictionaries), ints, strings, btyes and more. These were done as users | |
43 | reported reproducible performance problems. | |
44 | ||
45 | 74 | Development of PyPy takes place on https://foss.heptapod.net/pypy/pypy. |
46 | 75 | We have seen an increase in the number of drive-by contributors who are able to |
47 | 76 | use gitlab + mercurial to create merge requests. |
48 | 77 | |
49 | We also have begun streaming the advances towards PyPy3.8 on Saturday evenings | |
50 | European time on https://www.twitch.tv/pypyproject. | |
51 | ||
52 | 78 | The `CFFI`_ backend has been updated to version 1.14.5 and the cppyy_ backend |
53 | to 1.14.2. We recommend using CFFI rather than c-extensions to interact with C, | |
79 | to 1.14.2. We recommend using CFFI rather than C-extensions to interact with C, | |
54 | 80 | and using cppyy for performant wrapping of C++ code for Python. |
55 | 81 | |
56 | A new contributor took us up on the challenge to get `windows 64-bit`_ support. | |
57 | The work has been merged and for the first time we are releasing a 64-bit | |
58 | windows binary package. | |
59 | ||
60 | As always, this release fixed several issues and bugs. We strongly recommend | |
61 | updating. Many of the fixes are the direct result of end-user bug reports, so | |
62 | please continue reporting issues as they crop up. | |
82 | As always, we strongly recommend updating to the latest versions. Many fixes | |
83 | are the direct result of end-user bug reports, so please continue reporting | |
84 | issues as they crop up. | |
63 | 85 | |
64 | 86 | You can find links to download the v7.3.4 releases here: |
65 | 87 | |
69 | 91 | project. If PyPy is not quite good enough for your needs, we are available for |
70 | 92 | direct consulting work. If PyPy is helping you out, we would love to hear about |
71 | 93 | it and encourage submissions to our `renovated blog site`_ via a pull request |
72 | to www.github.com://pypy/pypy.org | |
94 | to https://github.com/pypy/pypy.org | |
73 | 95 | |
74 | 96 | We would also like to thank our contributors and encourage new people to join |
75 | 97 | the project. PyPy has many layers and we need help with all of them: `PyPy`_ |
76 | 98 | and `RPython`_ documentation improvements, tweaking popular modules to run |
77 | on pypy, or general `help`_ with making RPython's JIT even better. Since the | |
99 | on PyPy, or general `help`_ with making RPython's JIT even better. Since the | |
78 | 100 | previous release, we have accepted contributions from 10 new contributors, |
79 | thanks for pitching in. | |
80 | ||
81 | If you are a python library maintainer and use c-extensions, please consider | |
101 | thanks for pitching in, and welcome to the project! | |
102 | ||
103 | If you are a python library maintainer and use C-extensions, please consider | |
82 | 104 | making a cffi / cppyy version of your library that would be performant on PyPy. |
83 | 105 | In any case both `cibuildwheel`_ and the `multibuild system`_ support |
84 | 106 | building wheels for PyPy. |
90 | 112 | .. _`cppyy`: https://cppyy.readthedocs.io |
91 | 113 | .. _`multibuild system`: https://github.com/matthew-brett/multibuild |
92 | 114 | .. _`cibuildwheel`: https://github.com/joerick/cibuildwheel |
93 | .. _`blog post`: https://morepypy.blogspot.com/2020/02/pypy-and-cffi-have-moved-to-heptapod.html | |
115 | .. _`blog post`: https://pypy.org/blog/2020/02/pypy-and-cffi-have-moved-to-heptapod.html | |
94 | 116 | .. _`conda-forge`: https://conda-forge.org/blog//2020/03/10/pypy |
95 | 117 | .. _`documented changes`: https://docs.python.org/3/whatsnew/3.7.html#re |
96 | 118 | .. _`PyPy 3.7 wiki`: https://foss.heptapod.net/pypy/pypy/-/wikis/py3.7%20status |
97 | 119 | .. _`wheels on PyPI`: https://pypi.org/project/numpy/#files |
98 | 120 | .. _`windows 64-bit`: https://foss.heptapod.net/pypy/pypy/-/issues/2073#note_141389 |
99 | .. _`HPy blog post`: https://morepypy.blogspot.com/2019/12/hpy-kick-off-sprint-report.html | |
121 | .. _`HPy documentation`: https://hpy.readthedocs.io/en/latest/ | |
122 | .. _`HPy blog post`: https://hpyproject.org/blog/posts/2021/03/hello-hpy/ | |
100 | 123 | .. _`GraalPython`: https://github.com/graalvm/graalpython |
101 | 124 | .. _`RustPython`: https://github.com/RustPython/RustPython |
102 | 125 | .. _`renovated blog site`: https://pypy.org/blog |
132 | 155 | ========= |
133 | 156 | |
134 | 157 | Bugfixes shared across versions |
135 | ------------------------------ | |
158 | ------------------------------- | |
136 | 159 | - Test, fix xml default attribute values (issue 3333_, `bpo 42151`_) |
137 | - Update the ``re`` module to the Python3.7 implementation | |
138 | - Truncate ``REG_SZ`` at first ``NULL`` in ``winreg`` to match ``reg.exe`` | |
139 | behaviour (`bpo 25778`_) | |
140 | - Rename ``_hashlib.Hash`` to ``HASH`` to match cpython | |
160 | - Rename ``_hashlib.Hash`` to ``HASH`` to match CPython | |
141 | 161 | - Fix loading system libraries with ctypes on macOS Big Sur (issue 3314) |
142 | 162 | - Fix ``__thread_id`` in greenlets (issue 3381_) |
143 | 163 | - Reject XML entity declarations in plist files (`bpo 42051`_) |
144 | - Make compare_digest more constant-time (`bpo-40791`_) | |
164 | - Make compare_digest more constant-time (`bpo 40791`_) | |
145 | 165 | - Only use '&' as a query string separator in url parsing (`bpo 42967`_) |
146 | 166 | - Fix `__r*__` reverse methods on weakref proxies |
167 | - Restore pickle of dict iterators on default (python2.7) | |
147 | 168 | |
148 | 169 | Speedups and enhancements shared across versions |
149 | 170 | ------------------------------------------------ |
151 | 172 | officializes the fact that you can raise RPython exceptions from llhelpers, |
152 | 173 | and makes it possible to specify what is the C value to return in case of |
153 | 174 | errors. Useful for HPY_ |
154 | - Introduce a new RPython decorator ``@never_allocates`` which ensures a class | |
175 | - Introduce a new RPython decorator ``@never_allocate`` which ensures a class | |
155 | 176 | is **never** instantiated at runtime. Useful for objects that are required to |
156 | 177 | be constant-folded away |
157 | 178 | - Upstream internal ``cparser`` tool from ``pypy/`` to ``rpython/`` |
169 | 190 | - Copy manifest from CPython and link it into ``pypy.exe`` (issue 3363) |
170 | 191 | - Preserve ``None`` passed as ``REG_BINARY`` instead of crashing or changing it |
171 | 192 | to an empty string in ``winreg`` (`bpo 21151`_) |
193 | - Add ``REG_QWORD*`` and ``Reg{Dis,En}ableReflectionKey``, and | |
194 | ``RegDeleteKeyEx`` to ``winreg`` | |
172 | 195 | - Backport msvc detection from python3, which probably breaks using Visual |
173 | 196 | Studio 2008 (MSVC9, or the version that used to be used to build CPython2.7 |
174 | 197 | on Windows) |
188 | 211 | - Fast path for ``unicode.upper/lower``, ``unicodedb.toupper/lower`` for ascii, |
189 | 212 | latin-1 |
190 | 213 | - Add a JIT driver for ``re.split`` |
191 | - Expose ``os.memfd_create`` on linux for glibc>2.27 (not on portable builds) | |
214 | - Expose ``os.memfd_create`` on Linux for glibc>2.27 (not on portable builds) | |
192 | 215 | - Add a shortcut for ``re.sub`` doing zero replacements |
193 | for things like escaping characters) | |
194 | ||
195 | C-API (cpyext) and c-extensions | |
216 | for things like escaping characters) | |
217 | - Expose the physical size of a list in ``__pypy__.list_get_physical_size`` | |
218 | - Clean up the icon bundled with the exe in windows | |
219 | - Add a fast path for ``list[:] = l2`` | |
220 | - Update packaged OpenSSL to 1.1.1k | |
221 | - Make ARM builds portable | |
222 | ||
223 | C-API (cpyext) and C-extensions | |
196 | 224 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
197 | 225 | - make order of arguments of ``PyDescr_NewGetSet`` consistent with CPython, |
198 | 226 | related to issue 2267_ |
204 | 232 | - Fix ``PyObject_Format`` for type objects (issue 3404_) |
205 | 233 | - Move ``inttypes.h`` into ``pyport.h`` (issue 3407_) |
206 | 234 | - Sync ``Py_.*Flags`` values with ``sys.flags`` (issue 3409_) |
235 | - Make ``PyUnicode_Check`` a macro, but still export the function from | |
236 | the shared library for backwards compatibility | |
207 | 237 | |
208 | 238 | |
209 | 239 | Python 3.7+ |
210 | 240 | ----------- |
241 | - Update the ``re`` module to the Python 3.7 implementation | |
211 | 242 | - Fix the ``crypt`` thread lock (issue 3395_) and fix input encoding (issue |
212 | 243 | 3378_) |
213 | 244 | - Fixes ``utf_8_decode`` for ``final=False`` (issue 3348_) |
214 | 245 | - Test, fix for ``time.strftime(u'%y\ud800%m', time.localtime(192039127))`` |
215 | - ``CALL_FUNCTION_KW`` pops a constant tuple from the stack, and uses | |
216 | fixedview, which loses the constness | |
246 | - ``CALL_FUNCTION_KW`` with keyword arguments is now much faster, because the | |
247 | data structure storing the arguments can be removed by the JIT | |
217 | 248 | - Fix the ``repr`` of subclasses |
218 | 249 | - Better error message for ``object.__init__`` with too many parameters |
219 | 250 | - Fix bug in ``codecs`` where using a function from the parser turns warnings |
228 | 259 | - Hang on to ``servername_callback`` handle in ``_ssl`` so it will not be |
229 | 260 | deleted until the context is deleted (issue 3396) |
230 | 261 | - Implement ``set_wakeup_fd(warn_on_full_buffer)`` (issue 3227_) |
231 | - Add ``REG_QWORD*`` and ``Reg{Dis,En}ableReflectionKey``, and | |
232 | ``RegDeleteKeyEx`` to ``winreg`` | |
233 | 262 | - Round-trip invalid UTF-16 data in ``winreg`` without a ``UnicodeDecodeError`` |
234 | 263 | (issue 3342_) |
264 | - Truncate ``REG_SZ`` at first ``NULL`` in ``winreg`` to match ``reg.exe`` | |
265 | behaviour (`bpo 25778`_) | |
235 | 266 | - Fix for surrogates in ``winreg`` input value (issue 3345_) |
236 | 267 | - In ``sysconfig``, ``INCLUDEPY`` and ``INCLUDEDIR`` should point to the |
237 | 268 | original directory even in a virtualenv (issue 3364_) |
245 | 276 | - Generalize venv to copy all ``*.exe`` and ``*.dll`` for windows |
246 | 277 | - The evaluation order of keys and values of *large* dict literals was wrong in |
247 | 278 | 3.7 (in lower versions it was the same way, but in 3.7 the evaluation order |
248 | of *small* dicts changed (issue 3380_) | |
249 | - Cache the imported ``re`` module (going through ``__import__`` is | |
279 | of *small* dicts changed), issue 3380_ | |
280 | - Cache the imported ``re`` module in ``_sre`` (going through ``__import__`` is | |
250 | 281 | unfortunately quite expensive on 3.x) |
251 | 282 | - Mention a repeated keyword argument in the error message |
252 | 283 | - Stop emitting the ``STORE_ANNOTATION`` and ``BINARY_DIVIDE`` bytecodes, |
255 | 286 | ``pip install --local`` |
256 | 287 | - No longer call ``eval()`` on content received via HTTP in CJK codec tests (`bpo 41944`_) |
257 | 288 | - Add missing `c_/f_/contiguous` flags on memoryview |
258 | - Fix ``xml.ElementTree.extend`` not working on iterators (issue 3181_, `bpo-43399`_) | |
289 | - Fix ``xml.ElementTree.extend`` not working on iterators (issue 3181_, `bpo 43399`_) | |
259 | 290 | - `Python -m` now adds *starting* directory to `sys.path` (`bpo 33053`_) |
260 | - Reimplement ``heapq.merge()`` using a linked tournamet tree (`bpo 38938`_) | |
291 | - Reimplement ``heapq.merge()`` using a linked tournament tree (`bpo 38938`_) | |
292 | - Fix shring of cursors in ``sqllite3`` (issues 3351_ and 3403_) | |
293 | - Fix remaining ``sqllite3`` incompatibilities | |
294 | - Fix ``CALL_METHOD_KW`` to not lose the immutability of the keyword name tuple | |
261 | 295 | |
262 | 296 | Python 3.7 C-API |
263 | 297 | ~~~~~~~~~~~~~~~~ |
268 | 302 | - Clean up some ``char *`` -> ``const char *`` misnaming (issue 3362) |
269 | 303 | - Accept ``NULL`` input to ``PyLong_AsUnsignedLongLongMask`` |
270 | 304 | - Add ``PyImport_GetModule`` (issue 3385_) |
271 | - Converting utf-8 to 1-byte buffers must consider latin-1 encoding (`issue 3413`_) | |
305 | - Converting utf-8 to 1-byte buffers must consider latin-1 encoding (issue `3413`_) | |
272 | 306 | - Fix value of ``.__module__`` and ``.__name__`` on the result of |
273 | 307 | ``PyType_FromSpec`` |
308 | - Add missing ``PyFile_FromFd`` | |
274 | 309 | |
275 | 310 | .. _2267: https://foss.heptapod.net/pypy/pypy/-/issues/2267 |
311 | .. _2371: https://foss.heptapod.net/pypy/pypy/-/issues/2371 | |
276 | 312 | .. _3172: https://foss.heptapod.net/pypy/pypy/-/issues/3172 |
277 | 313 | .. _3181: https://foss.heptapod.net/pypy/pypy/-/issues/3181 |
278 | 314 | .. _3227: https://foss.heptapod.net/pypy/pypy/-/issues/3227 |
281 | 317 | .. _3342: https://foss.heptapod.net/pypy/pypy/-/issues/3342 |
282 | 318 | .. _3345: https://foss.heptapod.net/pypy/pypy/-/issues/3345 |
283 | 319 | .. _3348: https://foss.heptapod.net/pypy/pypy/-/issues/3348 |
320 | .. _3351: https://foss.heptapod.net/pypy/pypy/-/issues/3351 | |
284 | 321 | .. _3355: https://foss.heptapod.net/pypy/pypy/-/issues/3355 |
285 | 322 | .. _3357: https://foss.heptapod.net/pypy/pypy/-/issues/3357 |
286 | 323 | .. _3359: https://foss.heptapod.net/pypy/pypy/-/issues/3359 |
296 | 333 | .. _3395: https://foss.heptapod.net/pypy/pypy/-/issues/3395 |
297 | 334 | .. _3396: https://foss.heptapod.net/pypy/pypy/-/issues/3396 |
298 | 335 | .. _3400: https://foss.heptapod.net/pypy/pypy/-/issues/3400 |
336 | .. _3403: https://foss.heptapod.net/pypy/pypy/-/issues/3403 | |
299 | 337 | .. _3404: https://foss.heptapod.net/pypy/pypy/-/issues/3404 |
300 | 338 | .. _3407: https://foss.heptapod.net/pypy/pypy/-/issues/3407 |
301 | 339 | .. _3409: https://foss.heptapod.net/pypy/pypy/-/issues/3409 |
340 | .. _3413: https://foss.heptapod.net/pypy/pypy/-/issues/3413 | |
302 | 341 | |
303 | 342 | .. _`merge request 723`: https://foss.heptapod.net/pypy/pypy/-/merge_request/723 |
304 | 343 | |
305 | 344 | .. _`bpo 21151`: https://bugs.python.org/issue21151 |
345 | .. _`bpo 25778`: https://bugs.python.org/issue25778 | |
306 | 346 | .. _`bpo 28732`: https://bugs.python.org/issue28732 |
307 | 347 | .. _`bpo 30024`: https://bugs.python.org/issue30024 |
308 | 348 | .. _`bpo 31286`: https://bugs.python.org/issue31286 |
32 | 32 | |
33 | 33 | .. _SECCOMP: https://code.google.com/p/seccompsandbox/wiki/overview |
34 | 34 | .. _pysandbox: https://mail.python.org/pipermail/python-dev/2013-November/130132.html |
35 | .. _sandbloxlib: https://foss.heptapod.net/pypy/sandboxlib | |
35 | .. _sandboxlib: https://foss.heptapod.net/pypy/sandboxlib | |
36 | 36 | |
37 | 37 | Another point of comparison: if we were instead to try to plug CPython |
38 | 38 | into a special virtualizing C library, we would get a result |
92 | 92 | 'John Witulski': ['witulski'], |
93 | 93 | 'Andrew Lawrence': ['andrew.lawrence@siemens.com', 'andrewjlawrence'], |
94 | 94 | 'Batuhan Taskaya': ['isidentical'], |
95 | 'Ondrej Baranovič': ['nulano'], | |
95 | 96 | } |
96 | 97 | |
97 | 98 | alias_map = {} |
0 | 0 | ============================ |
1 | What's new in PyPy2.7 7.3.3+ | |
1 | What's new in PyPy2.7 7.3.4+ | |
2 | 2 | ============================ |
3 | 3 | |
4 | .. this is a revision shortly after release-pypy-7.3.3 | |
5 | .. startrev: de512cf13506 | |
6 | ||
7 | .. branch: rpython-error_value | |
8 | .. branch: hpy-error-value | |
9 | ||
10 | Introduce @rlib.objectmodel.llhelper_error_value, will is used by HPy | |
11 | ||
12 | .. branch: new-ci-image | |
13 | ||
14 | CI: Add a Dockerfile for CI to prevent hitting pull limits on docker hub | |
15 | ||
16 | .. branch: issue-3333 | |
17 | ||
18 | Fix xml.etree.ElementTree assigning default attribute values: issue 3333 | |
19 | ||
20 | .. branch: rpython-rsre-for-37 | |
21 | ||
22 | Support for the new format of regular expressions in Python 3.7 | |
23 | ||
24 | .. branch: rpy-cparser | |
25 | ||
26 | Upstream internal cparser tool from pypy/ to rpython/ | |
4 | .. this is a revision shortly after release-pypy-7.3.4 | |
5 | .. startrev: 9c11d242d78c | |
27 | 6 | |
28 | 7 | |
29 | .. branch: win64 | |
30 | ||
31 | Change rpython and pypy to enable translating 64-bit windows | |
32 | ||
33 | ||
34 | .. branch: rpython-error_value | |
35 | ||
36 | Introduce @rlib.objectmodel.llhelper_error_value, will be used by HPy | |
37 | ||
38 | .. branch: add-rffi-constcharpsize2str | |
39 | ||
40 | Add ``rffi.constcharpsize2str`` | |
41 | ||
42 | .. branch: document-win64 | |
43 | ||
44 | Refactor documentation of win64 from future plans to what was executed | |
45 | ||
46 | .. branch: sync-distutils | |
47 | ||
48 | Backport msvc detection from python3, which probably breaks using Visual Studio | |
49 | 2008 (MSVC9, or the version that used to be used to build CPython2.7 on | |
50 | Windows) | |
51 | ||
52 | .. branch: py2.7-winreg | |
53 | ||
54 | Backport fixes to winreg adding reflection and fix for passing None (bpo | |
55 | 21151). | |
56 | ||
57 | .. branch: pymodule_new-const-charp | |
58 | ||
59 | Change parameter type of ``PyModule_New`` to ``const char*``, add | |
60 | ``PyModule_Check`` and ``PyModule_CheckExact`` | |
61 | ||
62 | .. branch: rpython-never-allocate | |
63 | ||
64 | Introduce a ``@never_allocate`` class decorator, which ensure that a certain | |
65 | RPython class is never actually instantiated at runtime. Useful to ensure that | |
66 | e.g. it's always constant-folded away | |
67 | ||
68 | .. branch: map-improvements | |
69 | ||
70 | Optimize instances with integer or float fields to have more efficent field | |
71 | reads and writes. They also use less memory if they have at least two such | |
72 | fields. | |
73 | ||
74 | .. branch: win-tcl8.6 | |
75 | ||
76 | Update the version of Tk/Tcl on windows to 8.6 | |
77 | ||
78 | .. branch: big-sur-dyld-cache | |
79 | ||
80 | Backport changes to ``_ctypes`` needed for maxos BigSur from py3.7 | |
81 | ||
82 | .. branch: cppyy-packaging | |
83 | ||
84 | Updated the API to the latest cppyy_backend (1.14.2), made all types used | |
85 | consistent to avoid void*/long casting problems on Win64, and added several | |
86 | new "builtin" types (wide chars, complex, etc.). | |
87 | ||
88 | ||
89 | .. branch: intbound-improvements-3 | |
90 | ||
91 | Refactor the intbound analysis in the JIT | |
92 | ||
93 | .. branch: issue-3404 | |
94 | ||
95 | Fix ``PyObject_Format`` for type objects | |
96 | ||
97 | ||
98 | .. branch: string-algorithmic-optimizations | |
99 | ||
100 | Faster str.replace and bytes.replace implementations. | |
101 | ||
102 | .. branch: vmprof-aarch64 | |
103 | ||
104 | Enable vmprof on arm64 |
0 | =========================== | |
1 | What's new in PyPy2.7 7.3.4 | |
2 | =========================== | |
3 | ||
4 | .. this is a revision shortly after release-pypy-7.3.3 | |
5 | .. startrev: de512cf13506 | |
6 | ||
7 | .. branch: rpython-error_value | |
8 | .. branch: hpy-error-value | |
9 | ||
10 | Introduce @rlib.objectmodel.llhelper_error_value, will is used by HPy | |
11 | ||
12 | .. branch: new-ci-image | |
13 | ||
14 | CI: Add a Dockerfile for CI to prevent hitting pull limits on docker hub | |
15 | ||
16 | .. branch: issue-3333 | |
17 | ||
18 | Fix xml.etree.ElementTree assigning default attribute values: issue 3333 | |
19 | ||
20 | .. branch: rpython-rsre-for-37 | |
21 | ||
22 | Support for the new format of regular expressions in Python 3.7 | |
23 | ||
24 | .. branch: rpy-cparser | |
25 | ||
26 | Upstream internal cparser tool from pypy/ to rpython/ | |
27 | ||
28 | ||
29 | .. branch: win64 | |
30 | ||
31 | Change rpython and pypy to enable translating 64-bit windows | |
32 | ||
33 | ||
34 | .. branch: rpython-error_value | |
35 | ||
36 | Introduce @rlib.objectmodel.llhelper_error_value, will be used by HPy | |
37 | ||
38 | .. branch: add-rffi-constcharpsize2str | |
39 | ||
40 | Add ``rffi.constcharpsize2str`` | |
41 | ||
42 | .. branch: document-win64 | |
43 | ||
44 | Refactor documentation of win64 from future plans to what was executed | |
45 | ||
46 | .. branch: sync-distutils | |
47 | ||
48 | Backport msvc detection from python3, which probably breaks using Visual Studio | |
49 | 2008 (MSVC9, or the version that used to be used to build CPython2.7 on | |
50 | Windows) | |
51 | ||
52 | .. branch: py2.7-winreg | |
53 | ||
54 | Backport fixes to winreg adding reflection and fix for passing None (bpo | |
55 | 21151). | |
56 | ||
57 | .. branch: pymodule_new-const-charp | |
58 | ||
59 | Change parameter type of ``PyModule_New`` to ``const char*``, add | |
60 | ``PyModule_Check`` and ``PyModule_CheckExact`` | |
61 | ||
62 | .. branch: rpython-never-allocate | |
63 | ||
64 | Introduce a ``@never_allocate`` class decorator, which ensure that a certain | |
65 | RPython class is never actually instantiated at runtime. Useful to ensure that | |
66 | e.g. it's always constant-folded away | |
67 | ||
68 | .. branch: map-improvements | |
69 | ||
70 | Optimize instances with integer or float fields to have more efficent field | |
71 | reads and writes. They also use less memory if they have at least two such | |
72 | fields. | |
73 | ||
74 | .. branch: win-tcl8.6 | |
75 | ||
76 | Update the version of Tk/Tcl on windows to 8.6 | |
77 | ||
78 | .. branch: big-sur-dyld-cache | |
79 | ||
80 | Backport changes to ``_ctypes`` needed for maxos BigSur from py3.7 | |
81 | ||
82 | .. branch: cppyy-packaging | |
83 | ||
84 | Updated the API to the latest cppyy_backend (1.14.2), made all types used | |
85 | consistent to avoid void*/long casting problems on Win64, and added several | |
86 | new "builtin" types (wide chars, complex, etc.). | |
87 | ||
88 | ||
89 | .. branch: intbound-improvements-3 | |
90 | ||
91 | Refactor the intbound analysis in the JIT | |
92 | ||
93 | .. branch: issue-3404 | |
94 | ||
95 | Fix ``PyObject_Format`` for type objects | |
96 | ||
97 | ||
98 | .. branch: string-algorithmic-optimizations | |
99 | ||
100 | Faster str.replace and bytes.replace implementations. | |
101 | ||
102 | .. branch: vmprof-aarch64 | |
103 | ||
104 | Enable vmprof on arm64 | |
105 | ||
106 | .. branch: icon-aliasing | |
107 | ||
108 | Improve pypy.ico |
0 | ========================= | |
1 | What's new in PyPy3 7.3.4 | |
2 | ========================= | |
3 | ||
4 | .. this is the revision after release-pypy3.6-v7.3.3 | |
5 | .. startrev: a57ea1224248 | |
6 | ||
7 | .. branches merged to py3.6 and are not reported in the test. Re-enable | |
8 | these lines for the release or when fixing the test | |
9 | .. branch: py3.6-resync | |
10 | ||
11 | .. branch: fix-crypt-py3-import | |
12 | ||
13 | Fix bad merge of crypt cffi module | |
14 | ||
15 | .. branch: issue3348 | |
16 | ||
17 | Fix utf_8_decode for final=False, error=ignore | |
18 | ||
19 | .. branch: py3.7-rsre | |
20 | ||
21 | Fix rsre module for python 3.7 | |
22 | ||
23 | .. branch: incremental_decoder | |
24 | ||
25 | Fix utf_8_decode for final=False | |
26 | ||
27 | ||
28 | .. branch: refactor-posonly | |
29 | ||
30 | Refactor how positional-only arguments are represented in signature objects, | |
31 | which brings it more in line with Python 3.8, and simplifies the code. | |
32 | ||
33 | .. branch: const | |
34 | ||
35 | Change `char *`` to ``const char *`` in ``PyStructSequence_Field``, | |
36 | ``PyStructSequence_Desc``, ``PyGetSetDef``, ``wrapperbase`` | |
37 | ||
38 | .. branch: win64-py3.7 | |
39 | ||
40 | Merge win64 into this branch | |
41 | ||
42 | .. branch: win64-cpyext | |
43 | ||
44 | Fix the cpyext module for win64 | |
45 | ||
46 | .. branch: py3.7-winreg | |
47 | ||
48 | Fix various problems with ``winreg``: add ``REG_QWORD``, implement reflection | |
49 | on win64, (bpo-21151) preserve None passed as ``REG_BINARY``, (bpo-25778), | |
50 | truncate ``REG_SZ`` at first ``NULL``, use surrogatepass in ``UTF-16`` decoding | |
51 | (issue 3342). | |
52 | ||
53 | .. branch: py3.7-win64-hash | |
54 | ||
55 | Prevent overflow in ``_hash_long`` on win64 using method from CPython, and | |
56 | speed it up. | |
57 | ||
58 | .. branch: issue-3371 | |
59 | ||
60 | Allow compiler to inherit flags from ``__future__.annotations``. Fixes | |
61 | ``>>> x : X`` | |
62 | ||
63 | .. branch: win32consoleio2 | |
64 | ||
65 | Re-enable ``_io.win32console`` on windows | |
66 | ||
67 | .. branch: meth-fastcall | |
68 | ||
69 | Implement METH_FASTCALL | |
70 | ||
71 | .. branch: py3.7-win64-cpyext-longobject | |
72 | ||
73 | Fix ``cpyext.longobject`` for win64 | |
74 | ||
75 | .. branch: py3.7-big-sur-dyld-cache | |
76 | ||
77 | Fix loading system libraries with ctypes on macOS Big Sur. (issue 3314) | |
78 | ||
79 | .. branch: map-improvements-3.7 | |
80 | ||
81 | Port map-improvements to py3.7 | |
82 | ||
83 | .. branch: win64-hpy | |
84 | ||
85 | Enable _hpy_universal on win64 | |
86 | ||
87 | .. branch: vendor/stdlib-3.7 | |
88 | ||
89 | Update stdlib to 3.7.10 | |
90 | ||
91 | .. branch: fix-issue-3181 | |
92 | ||
93 | Fix ElementTree.extend not working on iterators (issue 3181 and bpo43399) |
0 | ========================== | |
1 | What's new in PyPy3 7.3.3+ | |
2 | ========================== | |
0 | ============================ | |
1 | What's new in PyPy3.7 7.3.4+ | |
2 | ============================ | |
3 | 3 | |
4 | .. this is the revision after release-pypy3.6-v7.3.3 | |
5 | .. startrev: a57ea1224248 | |
4 | .. this is a revision shortly after release-pypy-7.3.4 | |
5 | .. startrev: 9c11d242d78c | |
6 | 6 | |
7 | .. branches merged to py3.6 and are not reported in the test. Re-enable | |
8 | these lines for the release or when fixing the test | |
9 | .. branch: py3.6-resync | |
7 | .. branch: hpy | |
10 | 8 | |
11 | .. branch: fix-crypt-py3-import | |
12 | ||
13 | Fix bad merge of crypt cffi module | |
14 | ||
15 | .. branch: issue3348 | |
16 | ||
17 | Fix utf_8_decode for final=False, error=ignore | |
18 | ||
19 | .. branch: py3.7-rsre | |
20 | ||
21 | Fix rsre module for python 3.7 | |
22 | ||
23 | .. branch: incremental_decoder | |
24 | ||
25 | Fix utf_8_decode for final=False | |
26 | ||
27 | ||
28 | .. branch: refactor-posonly | |
29 | ||
30 | Refactor how positional-only arguments are represented in signature objects, | |
31 | which brings it more in line with Python 3.8, and simplifies the code. | |
32 | ||
33 | .. branch: const | |
34 | ||
35 | Change `char *`` to ``const char *`` in ``PyStructSequence_Field``, | |
36 | ``PyStructSequence_Desc``, ``PyGetSetDef``, ``wrapperbase`` | |
37 | ||
38 | .. branch: win64-py3.7 | |
39 | ||
40 | Merge win64 into this branch | |
41 | ||
42 | .. branch: win64-cpyext | |
43 | ||
44 | Fix the cpyext module for win64 | |
45 | ||
46 | .. branch: py3.7-winreg | |
47 | ||
48 | Fix various problems with ``winreg``: add ``REG_QWORD``, implement reflection | |
49 | on win64, (bpo-21151) preserve None passed as ``REG_BINARY``, (bpo-25778), | |
50 | truncate ``REG_SZ`` at first ``NULL``, use surrogatepass in ``UTF-16`` decoding | |
51 | (issue 3342). | |
52 | ||
53 | .. branch: py3.7-win64-hash | |
54 | ||
55 | Prevent overflow in ``_hash_long`` on win64 using method from CPython, and | |
56 | speed it up. | |
57 | ||
58 | .. branch: issue-3371 | |
59 | ||
60 | Allow compiler to inherit flags from ``__future__.annotations``. Fixes | |
61 | ``>>> x : X`` | |
62 | ||
63 | .. branch: win32consoleio2 | |
64 | ||
65 | Re-enable ``_io.win32console`` on windows | |
66 | ||
67 | .. branch: meth-fastcall | |
68 | ||
69 | Implement METH_FASTCALL | |
70 | ||
71 | .. branch: py3.7-win64-cpyext-longobject | |
72 | ||
73 | Fix ``cpyext.longobject`` for win64 | |
74 | ||
75 | .. branch: py3.7-big-sur-dyld-cache | |
76 | ||
77 | Fix loading system libraries with ctypes on macOS Big Sur. (issue 3314) | |
78 | ||
79 | .. branch: map-improvements-3.7 | |
80 | ||
81 | Port map-improvements to py3.7 | |
82 | ||
83 | .. branch: win64-hpy | |
84 | ||
85 | Enable _hpy_universal on win64 | |
86 | ||
87 | .. branch: vendor/stdlib-3.7 | |
88 | ||
89 | Update stdlib to 3.7.10 | |
90 | ||
91 | .. branch: fix-issue-3181 | |
92 | ||
93 | Fix ElementTree.extend not working on iterators (issue 3181 and bpo43399) | |
9 | Merge latest hpy |
Binary diff not shown
381 | 381 | ''' Use cffi to compile cffi interfaces to modules''' |
382 | 382 | filename = join(pypydir, '..', 'lib_pypy', 'pypy_tools', |
383 | 383 | 'build_cffi_imports.py') |
384 | if sys.platform == 'darwin': | |
384 | if sys.platform in ('darwin', 'linux', 'linux2'): | |
385 | 385 | argv = [filename, '--embed-dependencies'] |
386 | 386 | else: |
387 | 387 | argv = [filename,] |
295 | 295 | def test_pickle_dictiter(self): |
296 | 296 | import pickle |
297 | 297 | tdict = {'2':2, '3':3, '5':5} |
298 | diter = iter(tdict) | |
299 | seen = next(diter) | |
300 | pckl = pickle.dumps(diter) | |
301 | result = pickle.loads(pckl) | |
302 | assert set(result) == (set('235') - set([seen])) | |
298 | diter = iter(tdict) | |
299 | res1 = next(diter) | |
300 | s = pickle.dumps(diter) | |
301 | res2 = next(diter) | |
302 | res3 = next(diter) | |
303 | assert {res1, res2, res3} == set(tdict) | |
304 | ||
305 | diter2 = pickle.loads(s) | |
306 | assert set(diter2) == set(tdict) - {res1} | |
303 | 307 | |
304 | 308 | def test_pickle_reversed(self): |
305 | 309 | import pickle |
109 | 109 | raise oefmt(space.w_TypeError, "expecting dict or list or set object, or instance of some kind") |
110 | 110 | return space.newtext(name) |
111 | 111 | |
112 | def list_get_physical_size(space, w_obj): | |
113 | if not isinstance(w_obj, W_ListObject): | |
114 | raise oefmt(space.w_TypeError, "expected list") | |
115 | return space.newint(w_obj.physical_size()) | |
116 | ||
117 | ||
112 | 118 | def get_console_cp(space): |
113 | 119 | """get_console_cp() |
114 | 120 |
119 | 119 | 'newmemoryview' : 'interp_buffer.newmemoryview', |
120 | 120 | 'set_exc_info' : 'interp_magic.set_exc_info', |
121 | 121 | 'utf8content' : 'interp_magic.utf8content', |
122 | 'list_get_physical_size' : 'interp_magic.list_get_physical_size', | |
122 | 123 | |
123 | 124 | 'get_contextvar_context' : 'interp_magic.get_contextvar_context', |
124 | 125 | 'set_contextvar_context' : 'interp_magic.set_contextvar_context', |
122 | 122 | finally: |
123 | 123 | set_contextvar_context(context) |
124 | 124 | |
125 | def test_list_get_physical_size(self): | |
126 | from __pypy__ import list_get_physical_size | |
127 | l = [1, 2] | |
128 | l.append(3) | |
129 | assert list_get_physical_size(l) >= 3 # should be 6, but untranslated 3⏎ |
0 | 0 | import os.path |
1 | import functools | |
1 | 2 | from pathlib import Path |
2 | from setuptools import Extension | |
3 | from distutils.errors import DistutilsError, DistutilsSetupError | |
3 | from distutils import log | |
4 | from distutils.command.build import build | |
5 | from distutils.errors import DistutilsError | |
6 | from setuptools.command import bdist_egg as bdist_egg_mod | |
7 | from setuptools.command.build_ext import build_ext | |
4 | 8 | |
5 | 9 | # NOTE: this file is also imported by PyPy tests, so it must be compatible |
6 | 10 | # with both Python 2.7 and Python 3.x |
7 | 11 | |
8 | _BASE_DIR = Path(__file__).parent | |
9 | 12 | |
10 | 13 | class HPyDevel: |
11 | def __init__(self, base_dir=_BASE_DIR): | |
14 | """ Extra sources for building HPy extensions with hpy.devel. """ | |
15 | ||
16 | _DEFAULT_BASE_DIR = Path(__file__).parent | |
17 | ||
18 | def __init__(self, base_dir=_DEFAULT_BASE_DIR): | |
12 | 19 | self.base_dir = Path(base_dir) |
13 | 20 | self.include_dir = self.base_dir.joinpath('include') |
14 | 21 | self.src_dir = self.base_dir.joinpath('src', 'runtime') |
15 | # extra_sources are needed both in CPython and Universal mode | |
16 | self._extra_sources = [ | |
22 | ||
23 | def get_extra_include_dirs(self): | |
24 | """ Extra include directories needed by extensions in both CPython and | |
25 | Universal modes. | |
26 | """ | |
27 | return list(map(str, [ | |
28 | self.include_dir, | |
29 | ])) | |
30 | ||
31 | def get_extra_sources(self): | |
32 | """ Extra sources needed by extensions in both CPython and Universal | |
33 | modes. | |
34 | """ | |
35 | return list(map(str, [ | |
17 | 36 | self.src_dir.joinpath('argparse.c'), |
18 | ] | |
19 | # ctx_sources are needed only in Universal mode | |
20 | self._ctx_sources = list(self.src_dir.glob('ctx_*.c')) | |
21 | ||
22 | def get_extra_sources(self): | |
23 | return list(map(str, self._extra_sources)) | |
37 | ])) | |
24 | 38 | |
25 | 39 | def get_ctx_sources(self): |
26 | return list(map(str, self._ctx_sources)) | |
27 | ||
28 | def fix_extension(self, ext, hpy_abi): | |
29 | """ | |
30 | Modify an existing setuptools.Extension to generate an HPy module. | |
31 | """ | |
32 | if hasattr(ext, 'hpy_abi'): | |
40 | """ Extra sources needed only in the CPython ABI mode. | |
41 | """ | |
42 | return list(map(str, self.src_dir.glob('ctx_*.c'))) | |
43 | ||
44 | def fix_distribution(self, dist): | |
45 | """ Override build_ext to support hpy modules. | |
46 | ||
47 | Used from both setup.py and hpy/test. | |
48 | """ | |
49 | dist.hpydevel = self | |
50 | ||
51 | base_build = dist.cmdclass.get("build", build) | |
52 | base_build_ext = dist.cmdclass.get("build_ext", build_ext) | |
53 | orig_bdist_egg_write_stub = bdist_egg_mod.write_stub | |
54 | ||
55 | class build_hpy_ext(build_hpy_ext_mixin, base_build_ext, object): | |
56 | _base_build_ext = base_build_ext | |
57 | ||
58 | def dist_has_ext_modules(self): | |
59 | if self.ext_modules or self.hpy_ext_modules: | |
60 | return True | |
61 | return False | |
62 | ||
63 | def build_has_ext_modules(self): | |
64 | return self.distribution.has_ext_modules() | |
65 | ||
66 | def bdist_egg_write_stub(resource, pyfile): | |
67 | if resource.endswith(".hpy.so"): | |
68 | log.info("stub file already created for %s", resource) | |
69 | return | |
70 | orig_bdist_egg_write_stub(resource, pyfile) | |
71 | ||
72 | # replace build_ext subcommand | |
73 | dist.cmdclass['build_ext'] = build_hpy_ext | |
74 | dist.__class__.has_ext_modules = dist_has_ext_modules | |
75 | base_build.has_ext_modules = build_has_ext_modules | |
76 | # setuptools / distutils store subcommands in .subcommands which | |
77 | # is a list of tuples of (extension_name, extension_needs_to_run_func). | |
78 | # The two lines below replace .subcommand entry for build_ext. | |
79 | idx = [sub[0] for sub in base_build.sub_commands].index("build_ext") | |
80 | base_build.sub_commands[idx] = ("build_ext", build_has_ext_modules) | |
81 | bdist_egg_mod.write_stub = bdist_egg_write_stub | |
82 | ||
83 | ||
84 | def handle_hpy_ext_modules(dist, attr, hpy_ext_modules): | |
85 | """ Distuils hpy_ext_module setup(...) argument and --hpy-abi option. | |
86 | ||
87 | See hpy's setup.py where this function is registered as an entry | |
88 | point. | |
89 | """ | |
90 | assert attr == 'hpy_ext_modules' | |
91 | ||
92 | # add a global option --hpy-abi to setup.py | |
93 | dist.__class__.hpy_abi = 'cpython' | |
94 | dist.__class__.global_options += [ | |
95 | ('hpy-abi=', None, 'Specify the HPy ABI mode (default: cpython)') | |
96 | ] | |
97 | hpydevel = HPyDevel() | |
98 | hpydevel.fix_distribution(dist) | |
99 | ||
100 | ||
101 | _HPY_UNIVERSAL_MODULE_STUB_TEMPLATE = """ | |
102 | class Spec: | |
103 | def __init__(self, name, origin): | |
104 | self.name = name | |
105 | self.origin = origin | |
106 | ||
107 | ||
108 | def __bootstrap__(): | |
109 | import sys, pkg_resources | |
110 | from hpy.universal import load_from_spec | |
111 | ext_filepath = pkg_resources.resource_filename(__name__, {ext_file!r}) | |
112 | m = load_from_spec(Spec({module_name!r}, ext_filepath)) | |
113 | m.__file__ = ext_filepath | |
114 | m.__loader__ = __loader__ | |
115 | m.__package__ = __package__ | |
116 | m.__spec__ = __spec__ | |
117 | sys.modules[__name__] = m | |
118 | ||
119 | __bootstrap__() | |
120 | """ | |
121 | ||
122 | ||
123 | class HPyExtensionName(str): | |
124 | """ Wrapper around str to allow HPy extension modules to be identified. | |
125 | ||
126 | The following build_ext command methods are passed only the *name* | |
127 | of the extension and not the full extension object. The | |
128 | build_hpy_ext_mixin class needs to detect when HPy are extensions | |
129 | passed to these methods and override the default behaviour. | |
130 | ||
131 | This str sub-class allows HPy extensions to be detected, while | |
132 | still allowing the extension name to be used as an ordinary string. | |
133 | """ | |
134 | ||
135 | def split(self, *args, **kw): | |
136 | result = str.split(self, *args, **kw) | |
137 | return [self.__class__(s) for s in result] | |
138 | ||
139 | def translate(self, *args, **kw): | |
140 | result = str.translate(self, *args, **kw) | |
141 | return self.__class__(result) | |
142 | ||
143 | ||
144 | def is_hpy_extension(ext_name): | |
145 | """ Return True if the extension name is for an HPy extension. """ | |
146 | return isinstance(ext_name, HPyExtensionName) | |
147 | ||
148 | ||
149 | def remember_hpy_extension(f): | |
150 | """ Decorator for remembering whether an extension name belongs to an | |
151 | HPy extension. | |
152 | """ | |
153 | @functools.wraps(f) | |
154 | def wrapper(self, ext_name): | |
155 | if self._only_hpy_extensions: | |
156 | assert is_hpy_extension(ext_name), ( | |
157 | "Extension name %r is not marked as an HPyExtensionName" | |
158 | " but only HPy extensions are present. This is almost" | |
159 | " certainly a bug in HPy's overriding of setuptools" | |
160 | " build_ext. Please report this error the HPy maintainers." | |
161 | % (ext_name,) | |
162 | ) | |
163 | result = f(self, ext_name) | |
164 | if is_hpy_extension(ext_name): | |
165 | result = HPyExtensionName(result) | |
166 | return result | |
167 | return wrapper | |
168 | ||
169 | ||
170 | class build_hpy_ext_mixin: | |
171 | """ A mixin class for setuptools build_ext to add support for buidling | |
172 | HPy extensions. | |
173 | """ | |
174 | ||
175 | # Ideally we would have simply added the HPy extensions to .extensions | |
176 | # at the end of .initialize_options() but the setuptools build_ext | |
177 | # .finalize_options both iterate over and needless overwrite the | |
178 | # .extensions attribute, so we hide the full extension list in | |
179 | # ._extensions and expose it as a settable property that ignores attempts | |
180 | # to overwrite it: | |
181 | ||
182 | _extensions = None | |
183 | ||
184 | @property | |
185 | def extensions(self): | |
186 | return self._extensions | |
187 | ||
188 | @extensions.setter | |
189 | def extensions(self, value): | |
190 | pass # ignore any attempts to change the list of extensions directly | |
191 | ||
192 | def initialize_options(self): | |
193 | self._base_build_ext.initialize_options(self) | |
194 | self.hpydevel = self.distribution.hpydevel | |
195 | ||
196 | def _finalize_hpy_ext(self, ext): | |
197 | if hasattr(ext, "hpy_abi"): | |
33 | 198 | return |
34 | ext.hpy_abi = hpy_abi | |
35 | ext.include_dirs.append(str(self.include_dir)) | |
36 | ext.sources += self.get_extra_sources() | |
37 | if hpy_abi == 'cpython': | |
38 | ext.sources += self.get_ctx_sources() | |
39 | if hpy_abi == 'universal': | |
199 | ext.name = HPyExtensionName(ext.name) | |
200 | ext.hpy_abi = self.distribution.hpy_abi | |
201 | ext.include_dirs += self.hpydevel.get_extra_include_dirs() | |
202 | ext.sources += self.hpydevel.get_extra_sources() | |
203 | if ext.hpy_abi == 'cpython': | |
204 | ext.sources += self.hpydevel.get_ctx_sources() | |
205 | ext._hpy_needs_stub = False | |
206 | if ext.hpy_abi == 'universal': | |
40 | 207 | ext.define_macros.append(('HPY_UNIVERSAL_ABI', None)) |
41 | ||
42 | def collect_hpy_ext_names(self, dist, hpy_ext_modules): | |
43 | """ | |
44 | This is sub-optimal but it should work in 99% of the cases, and complain | |
45 | clearly in the others. | |
46 | ||
47 | In order to implement build_hpy_ext, we need to know whether an | |
48 | Extension was put inside hpy_ext_modules or ext_modules, and we need | |
49 | to know it ONLY by looking at its name (because that's all we get when | |
50 | distutils calls build_hpy_ext.get_ext_filename). So here we collect | |
51 | and return all hpy_ext_names. | |
52 | ||
53 | However, there is a problem: if the module is inside a package, | |
54 | distutils' build_ext.get_ext_fullpath calls get_ext_filename with ONLY | |
55 | the last part of the dotted name (see distutils/commands/build_ext.py). | |
56 | ||
57 | This means that there is a risk of conflicts if we have two ext | |
58 | modules with the same name in two different packages, of which one is | |
59 | HPy and the other is legacy; e.g.:: | |
60 | ||
61 | setup(ext_modules = [Extension(name='foo.mymod', ...)], | |
62 | hpy_ext_modules = [Extension(name='bar.mymod', ...)],) | |
63 | ||
64 | In that case, we cannot know whether ``mymod`` is an HPy ext module or | |
65 | not. If we detect such a problem, we exit early, and the only solution | |
66 | is to rename one of them :( | |
67 | """ | |
68 | def collect_ext_names(exts): | |
69 | if exts is None: | |
70 | return set() | |
71 | names = set() | |
72 | for ext in exts: | |
73 | names.add(ext.name) # full name, e.g. 'foo.bar.baz' | |
74 | names.add(ext.name.split('.')[-1]) # modname, e.g. 'baz' | |
75 | return names | |
76 | ||
77 | hpy_ext_names = collect_ext_names(hpy_ext_modules) | |
78 | ext_names = collect_ext_names(dist.ext_modules) | |
79 | conflicts = hpy_ext_names.intersection(ext_names) | |
80 | if conflicts: | |
81 | lines = ['\n'] | |
82 | lines.append('Name conflict between ext_modules and hpy_ext_modules:') | |
83 | for name in conflicts: | |
84 | lines.append(' - %s' % name) | |
85 | lines.append('You can not have modules ending with the same name in both') | |
86 | lines.append('ext_modules and hpy_ext_modules: this is a limitation of ') | |
87 | lines.append('hpy.devel, please rename one of them.') | |
88 | raise DistutilsSetupError('\n'.join(lines)) | |
89 | return hpy_ext_names | |
90 | ||
91 | def fix_distribution(self, dist, hpy_ext_modules): | |
92 | from setuptools.command.build_ext import build_ext | |
93 | from setuptools.command.install import install | |
94 | ||
95 | def is_hpy_extension(ext_name): | |
96 | return ext_name in is_hpy_extension._ext_names | |
97 | is_hpy_extension._ext_names = self.collect_hpy_ext_names(dist, hpy_ext_modules) | |
98 | ||
99 | # add the hpy_extension modules to the normal ext_modules | |
100 | if dist.ext_modules is None: | |
101 | dist.ext_modules = [] | |
102 | dist.ext_modules += hpy_ext_modules | |
103 | ||
104 | hpy_devel = self | |
105 | base_build_ext = dist.cmdclass.get('build_ext', build_ext) | |
106 | base_install = dist.cmdclass.get('install', install) | |
107 | ||
108 | class build_hpy_ext(base_build_ext): | |
109 | """ | |
110 | Custom distutils command which properly recognizes and handle hpy | |
111 | extensions: | |
112 | ||
113 | - modify 'include_dirs', 'sources' and 'define_macros' depending on | |
114 | the selected hpy_abi | |
115 | ||
116 | - modify the filename extension if we are targeting the universal | |
117 | ABI. | |
118 | """ | |
119 | ||
120 | def build_extension(self, ext): | |
121 | if is_hpy_extension(ext.name): | |
122 | # add the required include_dirs, sources and macros | |
123 | hpy_devel.fix_extension(ext, hpy_abi=self.distribution.hpy_abi) | |
124 | return base_build_ext.build_extension(self, ext) | |
125 | ||
126 | def get_ext_filename(self, ext_name): | |
127 | # this is needed to give the .hpy.so extension to universal extensions | |
128 | if is_hpy_extension(ext_name) and self.distribution.hpy_abi == 'universal': | |
129 | ext_path = ext_name.split('.') | |
130 | ext_suffix = '.hpy.so' # XXX Windows? | |
131 | return os.path.join(*ext_path) + ext_suffix | |
132 | return base_build_ext.get_ext_filename(self, ext_name) | |
133 | ||
134 | class install_hpy(base_install): | |
135 | ||
136 | def run(self): | |
137 | if self.distribution.hpy_abi == 'universal': | |
138 | raise DistutilsError( | |
139 | 'setup.py install is not supported for HPy universal modules.\n' | |
140 | ' At the moment, the only supported method is: \n' | |
141 | ' setup.py --hpy-abi-universal build_ext --inplace') | |
142 | return base_install.run(self) | |
143 | ||
144 | dist.cmdclass['build_ext'] = build_hpy_ext | |
145 | dist.cmdclass['install'] = install_hpy | |
146 | ||
147 | ||
148 | ||
149 | def handle_hpy_ext_modules(dist, attr, hpy_ext_modules): | |
150 | """ | |
151 | setuptools entry point, see setup.py | |
152 | """ | |
153 | assert attr == 'hpy_ext_modules' | |
154 | ||
155 | # Add a global option --hpy-abi to setup.py | |
156 | if not hasattr(dist.__class__, 'hpy_abi'): | |
157 | dist.__class__.hpy_abi = 'cpython' | |
158 | dist.__class__.global_options += [ | |
159 | ('hpy-abi=', None, 'Specify the HPy ABI mode (default: cpython)') | |
160 | ] | |
161 | ||
162 | hpy_devel = HPyDevel() | |
163 | hpy_devel.fix_distribution(dist, hpy_ext_modules) | |
208 | ext._hpy_needs_stub = True | |
209 | ||
210 | def finalize_options(self): | |
211 | self._extensions = self.distribution.ext_modules or [] | |
212 | # _only_hpy_extensions is used only as a sanity check that no | |
213 | # hpy extensions are misidentified as legacy C API extensions in the | |
214 | # case where only hpy extensions are present. | |
215 | self._only_hpy_extensions = not bool(self._extensions) | |
216 | hpy_ext_modules = self.distribution.hpy_ext_modules or [] | |
217 | for ext in hpy_ext_modules: | |
218 | self._finalize_hpy_ext(ext) | |
219 | self._extensions.extend(hpy_ext_modules) | |
220 | self._base_build_ext.finalize_options(self) | |
221 | for ext in hpy_ext_modules: | |
222 | ext._needs_stub = ext._hpy_needs_stub | |
223 | ||
224 | @remember_hpy_extension | |
225 | def get_ext_fullname(self, ext_name): | |
226 | return self._base_build_ext.get_ext_fullname(self, ext_name) | |
227 | ||
228 | @remember_hpy_extension | |
229 | def get_ext_fullpath(self, ext_name): | |
230 | return self._base_build_ext.get_ext_fullpath(self, ext_name) | |
231 | ||
232 | @remember_hpy_extension | |
233 | def get_ext_filename(self, ext_name): | |
234 | if not is_hpy_extension(ext_name): | |
235 | return self._base_build_ext.get_ext_filename(self, ext_name) | |
236 | if self.distribution.hpy_abi == 'universal': | |
237 | ext_path = ext_name.split('.') | |
238 | ext_suffix = '.hpy.so' # XXX Windows? | |
239 | ext_filename = os.path.join(*ext_path) + ext_suffix | |
240 | else: | |
241 | ext_filename = self._base_build_ext.get_ext_filename( | |
242 | self, ext_name) | |
243 | return ext_filename | |
244 | ||
245 | def write_stub(self, output_dir, ext, compile=False): | |
246 | if (not hasattr(ext, "hpy_abi") or | |
247 | self.distribution.hpy_abi != 'universal'): | |
248 | return self._base_build_ext.write_stub( | |
249 | self, output_dir, ext, compile=compile) | |
250 | pkgs = ext._full_name.split('.') | |
251 | if compile: | |
252 | # compile is true when .write_stub is called while copying | |
253 | # extensions to the source folder as part of build_ext --inplace. | |
254 | # In this situation, output_dir includes the folders that make up | |
255 | # the packages containing the module. When compile is false, | |
256 | # output_dir does not include those folders (and is just the | |
257 | # build_lib folder). | |
258 | pkgs = [pkgs[-1]] | |
259 | stub_file = os.path.join(output_dir, *pkgs) + '.py' | |
260 | log.info( | |
261 | "writing hpy universal stub loader for %s to %s", | |
262 | ext._full_name, stub_file) | |
263 | if compile and os.path.exists(stub_file): | |
264 | raise DistutilsError(stub_file + " already exists! Please delete.") | |
265 | ext_file = os.path.basename(ext._file_name) | |
266 | module_name = ext_file.split(".")[0] | |
267 | if not self.dry_run: | |
268 | with open(stub_file, 'w') as f: | |
269 | f.write(_HPY_UNIVERSAL_MODULE_STUB_TEMPLATE.format( | |
270 | ext_file=ext_file, module_name=module_name) | |
271 | ) |
+3
-1
1 | 1 | /* |
2 | 2 | DO NOT EDIT THIS FILE! |
3 | 3 | |
4 | This file is automatically generated by tools/autogen.py from tools/public_api.h. | |
4 | This file is automatically generated by hpy.tools.autogen.hpyfunc.autogen_hpyfunc_declare_h | |
5 | See also hpy.tools.autogen and hpy/tools/public_api.h | |
6 | ||
5 | 7 | Run this to regenerate: |
6 | 8 | make autogen |
7 | 9 |
1 | 1 | /* |
2 | 2 | DO NOT EDIT THIS FILE! |
3 | 3 | |
4 | This file is automatically generated by tools/autogen.py from tools/public_api.h. | |
4 | This file is automatically generated by hpy.tools.autogen.hpyslot.autogen_hpyslot_h | |
5 | See also hpy.tools.autogen and hpy/tools/public_api.h | |
6 | ||
5 | 7 | Run this to regenerate: |
6 | 8 | make autogen |
7 | 9 |
1 | 1 | /* |
2 | 2 | DO NOT EDIT THIS FILE! |
3 | 3 | |
4 | This file is automatically generated by tools/autogen.py from tools/public_api.h. | |
4 | This file is automatically generated by hpy.tools.autogen.trampolines.autogen_impl_h | |
5 | See also hpy.tools.autogen and hpy/tools/public_api.h | |
6 | ||
5 | 7 | Run this to regenerate: |
6 | 8 | make autogen |
7 | 9 | |
267 | 269 | return _py2h(PyNumber_InPlaceOr(_h2py(h1), _h2py(h2))); |
268 | 270 | } |
269 | 271 | |
272 | HPyAPI_STORAGE int _HPy_IMPL_NAME(Callable_Check)(HPyContext ctx, HPy h) | |
273 | { | |
274 | return PyCallable_Check(_h2py(h)); | |
275 | } | |
276 | ||
270 | 277 | HPyAPI_STORAGE void _HPy_IMPL_NAME(Err_SetString)(HPyContext ctx, HPy h_type, const char *message) |
271 | 278 | { |
272 | 279 | PyErr_SetString(_h2py(h_type), message); |
447 | 454 | return _py2h(PyDict_New()); |
448 | 455 | } |
449 | 456 | |
457 | HPyAPI_STORAGE int _HPy_IMPL_NAME(Tuple_Check)(HPyContext ctx, HPy h) | |
458 | { | |
459 | return PyTuple_Check(_h2py(h)); | |
460 | } | |
461 |
0 | #ifndef HPY_COMMON_RUNTIME_CALL_H | |
1 | #define HPY_COMMON_RUNTIME_CALL_H | |
2 | ||
3 | #include <Python.h> | |
4 | #include "hpy.h" | |
5 | ||
6 | _HPy_HIDDEN HPy | |
7 | ctx_CallTupleDict(HPyContext ctx, HPy callable, HPy args, HPy kw); | |
8 | ||
9 | #endif /* HPY_COMMON_RUNTIME_CALL_H */ |
0 | 0 | |
1 | 1 | // automatically generated by setup.py:get_scm_config() |
2 | #define HPY_VERSION "0.1.dev875+g7c832a2" | |
3 | #define HPY_GIT_REVISION "7c832a2" | |
2 | #define HPY_VERSION "0.1.dev959+geb07982" | |
3 | #define HPY_GIT_REVISION "eb07982" |
+3
-1
1 | 1 | /* |
2 | 2 | DO NOT EDIT THIS FILE! |
3 | 3 | |
4 | This file is automatically generated by tools/autogen.py from tools/public_api.h. | |
4 | This file is automatically generated by hpy.tools.autogen.hpyfunc.autogen_cpython_hpyfunc_trampoline_h | |
5 | See also hpy.tools.autogen and hpy/tools/public_api.h | |
6 | ||
5 | 7 | Run this to regenerate: |
6 | 8 | make autogen |
7 | 9 |
271 | 271 | #include "../common/hpydef.h" |
272 | 272 | #include "../common/hpytype.h" |
273 | 273 | #include "../common/hpymodule.h" |
274 | #include "../common/runtime/ctx_call.h" | |
274 | 275 | #include "../common/runtime/ctx_module.h" |
275 | 276 | #include "../common/runtime/ctx_type.h" |
276 | 277 | #include "../common/runtime/ctx_listbuilder.h" |
314 | 315 | return ctx_Cast(ctx, h); |
315 | 316 | } |
316 | 317 | |
318 | HPyAPI_FUNC(HPy) | |
319 | HPy_CallTupleDict(HPyContext ctx, HPy callable, HPy args, HPy kw) | |
320 | { | |
321 | return ctx_CallTupleDict(ctx, callable, args, kw); | |
322 | } | |
323 | ||
317 | 324 | HPyAPI_FUNC(HPyListBuilder) |
318 | 325 | HPyListBuilder_New(HPyContext ctx, HPy_ssize_t initial_size) |
319 | 326 | { |
1 | 1 | /* |
2 | 2 | DO NOT EDIT THIS FILE! |
3 | 3 | |
4 | This file is automatically generated by tools/autogen.py from tools/public_api.h. | |
4 | This file is automatically generated by hpy.tools.autogen.ctx.autogen_ctx_h | |
5 | See also hpy.tools.autogen and hpy/tools/public_api.h | |
6 | ||
5 | 7 | Run this to regenerate: |
6 | 8 | make autogen |
7 | 9 | |
137 | 139 | HPy (*ctx_InPlaceAnd)(HPyContext ctx, HPy h1, HPy h2); |
138 | 140 | HPy (*ctx_InPlaceXor)(HPyContext ctx, HPy h1, HPy h2); |
139 | 141 | HPy (*ctx_InPlaceOr)(HPyContext ctx, HPy h1, HPy h2); |
142 | int (*ctx_Callable_Check)(HPyContext ctx, HPy h); | |
143 | HPy (*ctx_CallTupleDict)(HPyContext ctx, HPy callable, HPy args, HPy kw); | |
144 | void (*ctx_FatalError)(HPyContext ctx, const char *message); | |
140 | 145 | void (*ctx_Err_SetString)(HPyContext ctx, HPy h_type, const char *message); |
141 | 146 | void (*ctx_Err_SetObject)(HPyContext ctx, HPy h_type, HPy h_value); |
142 | 147 | int (*ctx_Err_Occurred)(HPyContext ctx); |
182 | 187 | int (*ctx_List_Append)(HPyContext ctx, HPy h_list, HPy h_item); |
183 | 188 | int (*ctx_Dict_Check)(HPyContext ctx, HPy h); |
184 | 189 | HPy (*ctx_Dict_New)(HPyContext ctx); |
185 | void (*ctx_FatalError)(HPyContext ctx, const char *message); | |
190 | int (*ctx_Tuple_Check)(HPyContext ctx, HPy h); | |
186 | 191 | HPy (*ctx_Tuple_FromArray)(HPyContext ctx, HPy items[], HPy_ssize_t n); |
187 | 192 | HPy (*ctx_FromPyObject)(HPyContext ctx, cpy_PyObject *obj); |
188 | 193 | cpy_PyObject *(*ctx_AsPyObject)(HPyContext ctx, HPy h); |
+3
-1
1 | 1 | /* |
2 | 2 | DO NOT EDIT THIS FILE! |
3 | 3 | |
4 | This file is automatically generated by tools/autogen.py from tools/public_api.h. | |
4 | This file is automatically generated by hpy.tools.autogen.hpyfunc.autogen_hpyfunc_trampoline_h | |
5 | See also hpy.tools.autogen and hpy/tools/public_api.h | |
6 | ||
5 | 7 | Run this to regenerate: |
6 | 8 | make autogen |
7 | 9 |
+15
-1
1 | 1 | /* |
2 | 2 | DO NOT EDIT THIS FILE! |
3 | 3 | |
4 | This file is automatically generated by tools/autogen.py from tools/public_api.h. | |
4 | This file is automatically generated by hpy.tools.autogen.trampolines.autogen_trampolines_h | |
5 | See also hpy.tools.autogen and hpy/tools/public_api.h | |
6 | ||
5 | 7 | Run this to regenerate: |
6 | 8 | make autogen |
7 | 9 | |
227 | 229 | return ctx->ctx_InPlaceOr ( ctx, h1, h2 ); |
228 | 230 | } |
229 | 231 | |
232 | static inline int HPyCallable_Check(HPyContext ctx, HPy h) { | |
233 | return ctx->ctx_Callable_Check ( ctx, h ); | |
234 | } | |
235 | ||
236 | static inline HPy HPy_CallTupleDict(HPyContext ctx, HPy callable, HPy args, HPy kw) { | |
237 | return ctx->ctx_CallTupleDict ( ctx, callable, args, kw ); | |
238 | } | |
239 | ||
230 | 240 | static inline void HPyErr_SetString(HPyContext ctx, HPy h_type, const char *message) { |
231 | 241 | ctx->ctx_Err_SetString ( ctx, h_type, message ); |
232 | 242 | } |
403 | 413 | return ctx->ctx_Dict_New ( ctx ); |
404 | 414 | } |
405 | 415 | |
416 | static inline int HPyTuple_Check(HPyContext ctx, HPy h) { | |
417 | return ctx->ctx_Tuple_Check ( ctx, h ); | |
418 | } | |
419 | ||
406 | 420 | static inline HPy HPyTuple_FromArray(HPyContext ctx, HPy items[], HPy_ssize_t n) { |
407 | 421 | return ctx->ctx_Tuple_FromArray ( ctx, items, n ); |
408 | 422 | } |
0 | #include <Python.h> | |
1 | #include "hpy.h" | |
2 | ||
3 | #ifdef HPY_UNIVERSAL_ABI | |
4 | // for _h2py and _py2h | |
5 | # include "handles.h" | |
6 | #endif | |
7 | ||
8 | _HPy_HIDDEN HPy | |
9 | ctx_CallTupleDict(HPyContext ctx, HPy callable, HPy args, HPy kw) | |
10 | { | |
11 | PyObject *obj; | |
12 | if (!HPy_IsNull(args) && !HPyTuple_Check(ctx, args)) { | |
13 | HPyErr_SetString(ctx, ctx->h_TypeError, | |
14 | "HPy_CallTupleDict requires args to be a tuple or null handle"); | |
15 | return HPy_NULL; | |
16 | } | |
17 | if (!HPy_IsNull(kw) && !HPyDict_Check(ctx, kw)) { | |
18 | HPyErr_SetString(ctx, ctx->h_TypeError, | |
19 | "HPy_CallTupleDict requires kw to be a dict or null handle"); | |
20 | return HPy_NULL; | |
21 | } | |
22 | if (HPy_IsNull(kw)) { | |
23 | obj = PyObject_CallObject(_h2py(callable), _h2py(args)); | |
24 | } | |
25 | else if (!HPy_IsNull(args)){ | |
26 | obj = PyObject_Call(_h2py(callable), _h2py(args), _h2py(kw)); | |
27 | } | |
28 | else { | |
29 | // args is null, but kw is not, so we need to create an empty args tuple | |
30 | // for CPython's PyObject_Call | |
31 | HPy items[] = {}; | |
32 | HPy empty_tuple = HPyTuple_FromArray(ctx, items, 0); | |
33 | obj = PyObject_Call(_h2py(callable), _h2py(empty_tuple), _h2py(kw)); | |
34 | HPy_Close(ctx, empty_tuple); | |
35 | } | |
36 | return _py2h(obj); | |
37 | } |
0 | 0 | |
1 | 1 | # automatically generated by setup.py:get_scm_config() |
2 | __version__ = "0.1.dev875+g7c832a2" | |
3 | __git_revision__ = "7c832a2" | |
2 | __version__ = "0.1.dev959+geb07982" | |
3 | __git_revision__ = "eb07982" |
0 | from pypy.interpreter.error import oefmt | |
1 | from .apiset import API | |
2 | from . import handles | |
3 | ||
4 | @API.func("HPy HPy_CallTupleDict(HPyContext ctx, HPy callable, HPy args, HPy kw)") | |
5 | def HPy_CallTupleDict(space, ctx, h_callable, h_args, h_kw): | |
6 | w_callable = handles.deref(space, h_callable) | |
7 | w_args = handles.deref(space, h_args) if h_args else None | |
8 | w_kw = handles.deref(space, h_kw) if h_kw else None | |
9 | ||
10 | # Check the types here, as space.call would allow any iterable/mapping | |
11 | if w_args and not space.isinstance_w(w_args, space.w_tuple): | |
12 | raise oefmt(space.w_TypeError, | |
13 | "HPy_CallTupleDict requires args to be a tuple or null handle") | |
14 | if w_kw and not space.isinstance_w(w_kw, space.w_dict): | |
15 | raise oefmt(space.w_TypeError, | |
16 | "HPy_CallTupleDict requires kw to be a dict or null handle") | |
17 | ||
18 | # Note: both w_args and w_kw are allowed to be None | |
19 | w_result = space.call(w_callable, w_args, w_kw) | |
20 | return handles.new(space, w_result) |
18 | 18 | interp_unicode, |
19 | 19 | interp_float, |
20 | 20 | interp_bytes, |
21 | interp_call, | |
21 | 22 | interp_dict, |
22 | 23 | interp_list, |
23 | 24 | interp_tuple, |
42 | 43 | state = space.fromcache(State) |
43 | 44 | initfunc_ptr = rffi.cast(llapi.HPyInitFunc, initfunc_ptr) |
44 | 45 | h_module = initfunc_ptr(state.ctx) |
46 | if not h_module: | |
47 | raise oefmt(space.w_SystemError, | |
48 | "initialization of %s failed without raising an exception", | |
49 | name) | |
45 | 50 | return handles.consume(space, h_module) |
46 | 51 | |
47 | 52 | def descr_load_from_spec(space, w_spec): |
97 | 97 | def HPyLong_AsUnsignedLongLong(space, ctx, h): |
98 | 98 | w_long = handles.deref(space, h) |
99 | 99 | try: |
100 | return rffi.cast(rffi.ULONGLONG, space.r_ulonglong_w(w_long)) | |
100 | return rffi.cast(rffi.ULONGLONG, space.r_ulonglong_w( | |
101 | w_long, allow_conversion=False)) | |
101 | 102 | except OperationError as e: |
102 | 103 | if e.match(space, space.w_ValueError): |
103 | 104 | e.w_type = space.w_OverflowError |
125 | 126 | error_value=API.cast("ssize_t", -1)) |
126 | 127 | def HPyLong_AsSsize_t(space, ctx, h): |
127 | 128 | w_long = handles.deref(space, h) |
128 | return space.int_w(w_long) | |
129 | return space.int_w(w_long, allow_conversion=False) |
0 | 0 | from rpython.rtyper.lltypesystem import lltype, rffi |
1 | from rpython.rlib.rarithmetic import widen | |
2 | 1 | from pypy.interpreter.error import OperationError, oefmt |
3 | from pypy.interpreter.module import Module | |
2 | from pypy.interpreter.module import Module, init_extra_module_attrs | |
4 | 3 | from pypy.module._hpy_universal.apiset import API |
5 | 4 | from pypy.module._hpy_universal import llapi |
6 | 5 | from pypy.module._hpy_universal import handles |
20 | 19 | attach_legacy_methods(space, pymethods, w_mod, modname) |
21 | 20 | else: |
22 | 21 | raise oefmt(space.w_RuntimeError, |
23 | "Module %s contains legacy methods, but _hpy_universal " | |
24 | "was compiled without cpyext support", modname) | |
22 | "Module %s contains legacy methods, but _hpy_universal " | |
23 | "was compiled without cpyext support", modname) | |
25 | 24 | # |
26 | 25 | # add the native HPy defines |
27 | 26 | if hpydef.c_defines: |
37 | 36 | space, name, sig, doc, hpymeth.c_impl, w_mod) |
38 | 37 | space.setattr(w_mod, space.newtext(w_extfunc.name), w_extfunc) |
39 | 38 | i += 1 |
39 | if hpydef.c_m_doc: | |
40 | w_doc = space.newtext(rffi.constcharp2str(hpydef.c_m_doc)) | |
41 | else: | |
42 | w_doc = space.w_None | |
43 | space.setattr(w_mod, space.newtext('__doc__'), w_doc) | |
44 | init_extra_module_attrs(space, w_mod) | |
40 | 45 | return handles.new(space, w_mod) |
41 | 46 | |
42 | 47 |
64 | 64 | w_value = handles.deref(space, h_value) |
65 | 65 | operation.setattr(space, w_obj, w_name, w_value) |
66 | 66 | return API.int(0) |
67 | ||
68 | ||
69 | @API.func("int HPyCallable_Check(HPyContext ctx, HPy h)", error_value='CANNOT_FAIL') | |
70 | def HPyCallable_Check(space, ctx, h_obj): | |
71 | w_obj = handles.deref(space, h_obj) | |
72 | return API.int(space.is_true(space.callable(w_obj))) | |
67 | 73 | |
68 | 74 | |
69 | 75 | @API.func("HPy HPy_GetItem(HPyContext ctx, HPy h_obj, HPy h_key)") |
7 | 7 | items_w[i] = handles.deref(space, items[i]) |
8 | 8 | w_result = space.newtuple(items_w) |
9 | 9 | return handles.new(space, w_result) |
10 | ||
11 | @API.func("int HPyTuple_Check(HPyContext ctx, HPy h)", error_value='CANNOT_FAIL') | |
12 | def HPyTuple_Check(space, ctx, h): | |
13 | w_obj = handles.deref(space, h) | |
14 | w_obj_type = space.type(w_obj) | |
15 | res = (space.is_w(w_obj_type, space.w_tuple) or | |
16 | space.issubtype_w(w_obj_type, space.w_tuple)) | |
17 | return API.int(res) |
190 | 190 | void * ctx_InPlaceAnd; |
191 | 191 | void * ctx_InPlaceXor; |
192 | 192 | void * ctx_InPlaceOr; |
193 | void * ctx_Callable_Check; | |
194 | void * ctx_CallTupleDict; | |
195 | void * ctx_FatalError; | |
193 | 196 | void * ctx_Err_SetString; |
194 | 197 | void * ctx_Err_SetObject; |
195 | 198 | void * ctx_Err_Occurred; |
235 | 238 | void * ctx_List_Append; |
236 | 239 | void * ctx_Dict_Check; |
237 | 240 | void * ctx_Dict_New; |
238 | void * ctx_FatalError; | |
241 | void * ctx_Tuple_Check; | |
239 | 242 | void * ctx_Tuple_FromArray; |
240 | 243 | void * ctx_FromPyObject; |
241 | 244 | void * ctx_AsPyObject; |
496 | 499 | SIZEOF_HPyObject_HEAD = rffi.sizeof(cts.gettype('struct _HPyObject_head_s')) |
497 | 500 | |
498 | 501 | # HPy API functions which are implemented directly in C |
502 | pypy_HPy_FatalError = rffi.llexternal('pypy_HPy_FatalError', | |
503 | [HPyContext, rffi.CCHARP], | |
504 | lltype.Void, | |
505 | compilation_info=eci, _nowrapper=True) | |
506 | ||
499 | 507 | pypy_HPyErr_Occurred = rffi.llexternal('pypy_HPyErr_Occurred', [HPyContext], |
500 | 508 | rffi.INT_real, |
501 | 509 | compilation_info=eci, _nowrapper=True) |
5 | 5 | # include "src/exception.h" |
6 | 6 | #endif |
7 | 7 | |
8 | #include <stdio.h> | |
8 | 9 | #include "universal/hpy.h" |
9 | 10 | #include "hpyerr.h" |
10 | 11 | #include "bridge.h" |
11 | 12 | |
12 | 13 | |
14 | void pypy_HPy_FatalError(HPyContext ctx, const char *message) | |
15 | { | |
16 | fprintf(stderr, "Fatal Python error: %s\n", message); | |
17 | abort(); | |
18 | } | |
13 | 19 | |
14 | 20 | int pypy_HPyErr_Occurred(HPyContext ctx) |
15 | 21 | { |
0 | 0 | #include "src/precommondefs.h" |
1 | 1 | #include "universal/hpy.h" |
2 | 2 | |
3 | RPY_EXTERN void pypy_HPy_FatalError(HPyContext ctx, const char *message); | |
3 | 4 | RPY_EXTERN int pypy_HPyErr_Occurred(HPyContext ctx); |
4 | 5 | RPY_EXTERN void pypy_HPyErr_SetString(HPyContext ctx, HPy type, const char *message); |
5 | 6 | RPY_EXTERN void pypy_HPyErr_SetObject(HPyContext ctx, HPy type, HPy value); |
65 | 65 | ctx_field = 'c_ctx_' + func.basename |
66 | 66 | setattr(self.ctx, ctx_field, funcptr) |
67 | 67 | |
68 | self.ctx.c_ctx_FatalError = rffi.cast(rffi.VOIDP, llapi.pypy_HPy_FatalError) | |
68 | 69 | self.ctx.c_ctx_Err_Occurred = rffi.cast(rffi.VOIDP, llapi.pypy_HPyErr_Occurred) |
69 | 70 | self.ctx.c_ctx_Err_SetString = rffi.cast(rffi.VOIDP, llapi.pypy_HPyErr_SetString) |
70 | 71 | self.ctx.c_ctx_Err_SetObject = rffi.cast(rffi.VOIDP, llapi.pypy_HPyErr_SetObject) |
0 | 0 | import pytest |
1 | import sys | |
2 | 1 | from .support import ExtensionCompiler |
3 | ||
4 | disable = False | |
5 | ||
6 | if sys.platform == 'win32': | |
7 | # skip all tests on windows, see issue hpyproject/hpy#61 | |
8 | disable = True | |
9 | ||
10 | def pytest_ignore_collect(path, config): | |
11 | if disable: | |
12 | return True | |
13 | ||
14 | def pytest_collect_file(path, parent): | |
15 | if disable: | |
16 | # We end up here when calling py.test .../test_foo.py directly | |
17 | # It's OK to kill the whole session with the following line | |
18 | pytest.skip("skipping on windows") | |
19 | 2 | |
20 | 3 | def pytest_addoption(parser): |
21 | 4 | parser.addoption( |
197 | 197 | |
198 | 198 | def make_module(self, ExtensionTemplate, main_src, name, extra_sources): |
199 | 199 | """ |
200 | Compile&load a modulo into memory. This is NOT a proper import: e.g. the module | |
201 | is not put into sys.modules | |
202 | """ | |
203 | so_filename = self.compile_module(ExtensionTemplate, main_src, name, | |
204 | extra_sources) | |
205 | if self.hpy_abi == 'universal': | |
206 | return self.load_universal_module(name, so_filename) | |
207 | else: | |
208 | return self.load_cython_module(name, so_filename) | |
209 | ||
210 | def load_universal_module(self, name, so_filename): | |
211 | assert self.hpy_abi == 'universal' | |
212 | import hpy.universal | |
213 | spec = Spec(name, so_filename) | |
214 | return hpy.universal.load_from_spec(spec) | |
215 | ||
216 | def load_cython_module(self, name, so_filename): | |
217 | assert self.hpy_abi == 'cpython' | |
218 | # we've got a normal CPython module compiled with the CPython API/ABI, | |
219 | # let's load it normally. It is important to do the imports only here, | |
220 | # because this file will be imported also by PyPy tests which runs on | |
221 | # Python2 | |
222 | import importlib.util | |
223 | from importlib.machinery import ExtensionFileLoader | |
224 | spec = importlib.util.spec_from_file_location(name, so_filename) | |
225 | module = importlib.util.module_from_spec(spec) | |
226 | spec.loader.exec_module(module) | |
200 | Compile & load a module. This is NOT a proper import: e.g. | |
201 | the module is not put into sys.modules | |
202 | """ | |
203 | mod_filename = self.compile_module( | |
204 | ExtensionTemplate, main_src, name, extra_sources) | |
205 | return self.load_module(name, mod_filename) | |
206 | ||
207 | def load_module(self, name, mod_filename): | |
208 | # It is important to do the imports only here, because this file will | |
209 | # be imported also by PyPy tests which runs on Python2 | |
210 | import importlib | |
211 | import sys | |
212 | import os | |
213 | if name in sys.modules: | |
214 | raise ValueError( | |
215 | "Test module {!r} already present in sys.modules".format(name)) | |
216 | importlib.invalidate_caches() | |
217 | mod_dir = os.path.dirname(mod_filename) | |
218 | sys.path.insert(0, mod_dir) | |
219 | try: | |
220 | module = importlib.import_module(name) | |
221 | assert sys.modules[name] is module | |
222 | finally: | |
223 | # assert that the module import didn't change the sys.path entry | |
224 | # that was added above, then remove the entry. | |
225 | assert sys.path[0] == mod_dir | |
226 | del sys.path[0] | |
227 | if name in sys.modules: | |
228 | del sys.modules[name] | |
227 | 229 | return module |
228 | 230 | |
229 | 231 | |
241 | 243 | return self.compiler.make_module(ExtensionTemplate, main_src, name, |
242 | 244 | extra_sources) |
243 | 245 | |
244 | def should_check_refcount(self): | |
245 | # defaults to True on CPython, but is set to False by e.g. PyPy | |
246 | return sys.implementation.name == 'cpython' | |
246 | def supports_refcounts(self): | |
247 | """ Returns True if the underlying Python implementation supports | |
248 | reference counts. | |
249 | ||
250 | By default returns True on CPython and False on other | |
251 | implementations. | |
252 | """ | |
253 | return sys.implementation.name == "cpython" | |
254 | ||
255 | def supports_ordinary_make_module_imports(self): | |
256 | """ Returns True if `.make_module(...)` loads modules using a | |
257 | standard Python import mechanism (e.g. `importlib.import_module`). | |
258 | ||
259 | By default returns True because the base implementation of | |
260 | `.make_module(...)` uses an ordinary import. Sub-classes that | |
261 | override `.make_module(...)` may also want to override this | |
262 | method. | |
263 | """ | |
264 | return True | |
265 | ||
266 | def supports_sys_executable(self): | |
267 | """ Returns True is `sys.executable` is set to a value that allows | |
268 | a Python equivalent to the current Python to be launched via, e.g., | |
269 | `subprocess.run(...)`. | |
270 | ||
271 | By default returns `True` if sys.executable is set to a true value. | |
272 | """ | |
273 | return bool(getattr(sys, "executable", None)) | |
247 | 274 | |
248 | 275 | |
249 | 276 | # the few functions below are copied and adapted from cffi/ffiplatform.py |
262 | 289 | os.environ[key] = value |
263 | 290 | return outputfilename |
264 | 291 | |
292 | ||
265 | 293 | def _build(tmpdir, ext, hpy_devel, hpy_abi, compiler_verbose=0, debug=None): |
266 | 294 | # XXX compact but horrible :-( |
267 | 295 | from distutils.core import Distribution |
268 | import distutils.errors, distutils.log | |
296 | import distutils.errors | |
297 | import distutils.log | |
269 | 298 | # |
270 | 299 | dist = Distribution() |
271 | 300 | dist.parse_config_files() |
272 | options = dist.get_option_dict('build_ext') | |
273 | 301 | if debug is None: |
274 | 302 | debug = sys.flags.debug |
275 | options['debug'] = ('ffiplatform', debug) | |
276 | options['force'] = ('ffiplatform', True) | |
277 | options['build_lib'] = ('ffiplatform', tmpdir) | |
278 | options['build_temp'] = ('ffiplatform', tmpdir) | |
279 | # | |
303 | options_build_ext = dist.get_option_dict('build_ext') | |
304 | options_build_ext['debug'] = ('ffiplatform', debug) | |
305 | options_build_ext['force'] = ('ffiplatform', True) | |
306 | options_build_ext['build_lib'] = ('ffiplatform', tmpdir) | |
307 | options_build_ext['build_temp'] = ('ffiplatform', tmpdir) | |
308 | options_build_py = dist.get_option_dict('build_py') | |
309 | options_build_py['build_lib'] = ('ffiplatform', tmpdir) | |
310 | ||
280 | 311 | # this is the equivalent of passing --hpy-abi from setup.py's command line |
281 | 312 | dist.hpy_abi = hpy_abi |
282 | hpy_devel.fix_distribution(dist, hpy_ext_modules=[ext]) | |
283 | # | |
313 | dist.hpy_ext_modules = [ext] | |
314 | hpy_devel.fix_distribution(dist) | |
315 | ||
284 | 316 | old_level = distutils.log.set_threshold(0) or 0 |
285 | 317 | try: |
286 | 318 | distutils.log.set_verbosity(compiler_verbose) |
287 | 319 | dist.run_command('build_ext') |
288 | 320 | cmd_obj = dist.get_command_obj('build_ext') |
289 | [soname] = cmd_obj.get_outputs() | |
321 | outputs = cmd_obj.get_outputs() | |
322 | if hpy_abi == "cpython": | |
323 | [mod_filename] = [x for x in outputs if not x.endswith(".py")] | |
324 | else: | |
325 | [mod_filename] = [x for x in outputs if x.endswith(".py")] | |
290 | 326 | finally: |
291 | 327 | distutils.log.set_threshold(old_level) |
292 | # | |
293 | return soname | |
328 | ||
329 | return mod_filename |
0 | """ | |
1 | NOTE: this tests are also meant to be run as PyPy "applevel" tests. | |
2 | ||
3 | This means that global imports will NOT be visible inside the test | |
4 | functions. In particular, you have to "import pytest" inside the test in order | |
5 | to be able to use e.g. pytest.raises (which on PyPy will be implemented by a | |
6 | "fake pytest module") | |
7 | """ | |
8 | from .support import HPyTest | |
9 | ||
10 | ||
11 | class TestBasic(HPyTest): | |
12 | ||
13 | def test_get_version(self): | |
14 | if self.compiler.hpy_abi != 'universal': | |
15 | return | |
16 | import hpy.universal | |
17 | version, gitrev = hpy.universal.get_version() | |
18 | # it's a bit hard to test the CONTENT of these values. Let's just | |
19 | # check that they are strings... | |
20 | assert isinstance(version, str) | |
21 | assert isinstance(gitrev, str) | |
22 | ||
23 | def test_empty_module(self): | |
24 | import sys | |
25 | mod = self.make_module(""" | |
26 | @INIT | |
27 | """) | |
28 | assert type(mod) is type(sys) | |
29 | ||
30 | def test_different_name(self): | |
31 | mod = self.make_module(""" | |
32 | @INIT | |
33 | """, name="foo") | |
34 | assert mod.__name__ == "foo" | |
35 | ||
36 | def test_noop_function(self): | |
37 | mod = self.make_module(""" | |
38 | HPyDef_METH(f, "f", f_impl, HPyFunc_NOARGS, .doc="hello world") | |
39 | static HPy f_impl(HPyContext ctx, HPy self) | |
40 | { | |
41 | return HPy_Dup(ctx, ctx->h_None); | |
42 | } | |
43 | ||
44 | @EXPORT(f) | |
45 | @INIT | |
46 | """) | |
47 | assert mod.f() is None | |
48 | assert mod.f.__doc__ == 'hello world' | |
49 | ||
50 | def test_self_is_module(self): | |
51 | mod = self.make_module(""" | |
52 | HPyDef_METH(f, "f", f_impl, HPyFunc_NOARGS) | |
53 | static HPy f_impl(HPyContext ctx, HPy self) | |
54 | { | |
55 | return HPy_Dup(ctx, self); | |
56 | } | |
57 | @EXPORT(f) | |
58 | @INIT | |
59 | """) | |
60 | assert mod.f() is mod | |
61 | ||
62 | def test_identity_function(self): | |
63 | mod = self.make_module(""" | |
64 | HPyDef_METH(f, "f", f_impl, HPyFunc_O) | |
65 | static HPy f_impl(HPyContext ctx, HPy self, HPy arg) | |
66 | { | |
67 | return HPy_Dup(ctx, arg); | |
68 | } | |
69 | @EXPORT(f) | |
70 | @INIT | |
71 | """) | |
72 | x = object() | |
73 | assert mod.f(x) is x | |
74 | ||
75 | def test_float_asdouble(self): | |
76 | mod = self.make_module(""" | |
77 | HPyDef_METH(f, "f", f_impl, HPyFunc_O) | |
78 | static HPy f_impl(HPyContext ctx, HPy self, HPy arg) | |
79 | { | |
80 | double a = HPyFloat_AsDouble(ctx, arg); | |
81 | return HPyFloat_FromDouble(ctx, a * 2.); | |
82 | } | |
83 | @EXPORT(f) | |
84 | @INIT | |
85 | """) | |
86 | assert mod.f(1.) == 2. | |
87 | ||
88 | def test_wrong_number_of_arguments(self): | |
89 | import pytest | |
90 | mod = self.make_module(""" | |
91 | HPyDef_METH(f_noargs, "f_noargs", f_noargs_impl, HPyFunc_NOARGS) | |
92 | static HPy f_noargs_impl(HPyContext ctx, HPy self) | |
93 | { | |
94 | return HPy_Dup(ctx, ctx->h_None); | |
95 | } | |
96 | HPyDef_METH(f_o, "f_o", f_o_impl, HPyFunc_O) | |
97 | static HPy f_o_impl(HPyContext ctx, HPy self, HPy arg) | |
98 | { | |
99 | return HPy_Dup(ctx, ctx->h_None); | |
100 | } | |
101 | @EXPORT(f_noargs) | |
102 | @EXPORT(f_o) | |
103 | @INIT | |
104 | """) | |
105 | with pytest.raises(TypeError): | |
106 | mod.f_noargs(1) | |
107 | with pytest.raises(TypeError): | |
108 | mod.f_o() | |
109 | with pytest.raises(TypeError): | |
110 | mod.f_o(1, 2) | |
111 | ||
112 | def test_close(self): | |
113 | mod = self.make_module(""" | |
114 | HPyDef_METH(f, "f", f_impl, HPyFunc_O) | |
115 | static HPy f_impl(HPyContext ctx, HPy self, HPy arg) | |
116 | { | |
117 | HPy one = HPyLong_FromLong(ctx, 1); | |
118 | if (HPy_IsNull(one)) | |
119 | return HPy_NULL; | |
120 | HPy res = HPy_Add(ctx, arg, one); | |
121 | HPy_Close(ctx, one); | |
122 | return res; | |
123 | } | |
124 | @EXPORT(f) | |
125 | @INIT | |
126 | """) | |
127 | assert mod.f(41.5) == 42.5 | |
128 | ||
129 | def test_bool(self): | |
130 | mod = self.make_module(""" | |
131 | HPyDef_METH(f, "f", f_impl, HPyFunc_O) | |
132 | static HPy f_impl(HPyContext ctx, HPy self, HPy arg) | |
133 | { | |
134 | int cond = HPyLong_AsLong(ctx, arg) > 5; | |
135 | return HPy_Dup(ctx, cond ? ctx->h_True : ctx->h_False); | |
136 | } | |
137 | @EXPORT(f) | |
138 | @INIT | |
139 | """) | |
140 | assert mod.f(4) is False | |
141 | assert mod.f(6) is True | |
142 | ||
143 | def test_exception(self): | |
144 | import pytest | |
145 | mod = self.make_module(""" | |
146 | HPyDef_METH(f, "f", f_impl, HPyFunc_O) | |
147 | static HPy f_impl(HPyContext ctx, HPy self, HPy arg) | |
148 | { | |
149 | long x = HPyLong_AsLong(ctx, arg); | |
150 | if (x < 5) { | |
151 | return HPyLong_FromLong(ctx, -x); | |
152 | } | |
153 | else { | |
154 | HPyErr_SetString(ctx, ctx->h_ValueError, "hello world"); | |
155 | return HPy_NULL; | |
156 | } | |
157 | } | |
158 | @EXPORT(f) | |
159 | @INIT | |
160 | """) | |
161 | assert mod.f(-10) == 10 | |
162 | with pytest.raises(ValueError) as exc: | |
163 | mod.f(20) | |
164 | assert str(exc.value) == 'hello world' | |
165 | ||
166 | def test_builtin_handles(self): | |
167 | mod = self.make_module(""" | |
168 | HPyDef_METH(f, "f", f_impl, HPyFunc_O) | |
169 | static HPy f_impl(HPyContext ctx, HPy self, HPy arg) | |
170 | { | |
171 | long i = HPyLong_AsLong(ctx, arg); | |
172 | HPy h; | |
173 | switch(i) { | |
174 | case 1: h = ctx->h_None; break; | |
175 | case 2: h = ctx->h_False; break; | |
176 | case 3: h = ctx->h_True; break; | |
177 | case 4: h = ctx->h_ValueError; break; | |
178 | case 5: h = ctx->h_TypeError; break; | |
179 | case 6: h = ctx->h_IndexError; break; | |
180 | case 7: h = ctx->h_SystemError; break; | |
181 | case 8: h = ctx->h_BaseObjectType; break; | |
182 | case 9: h = ctx->h_TypeType; break; | |
183 | case 10: h = ctx->h_LongType; break; | |
184 | case 11: h = ctx->h_UnicodeType; break; | |
185 | case 12: h = ctx->h_TupleType; break; | |
186 | case 13: h = ctx->h_ListType; break; | |
187 | default: | |
188 | HPyErr_SetString(ctx, ctx->h_ValueError, "invalid choice"); | |
189 | return HPy_NULL; | |
190 | } | |
191 | return HPy_Dup(ctx, h); | |
192 | } | |
193 | @EXPORT(f) | |
194 | @INIT | |
195 | """) | |
196 | builtin_objs = ( | |
197 | '<NULL>', None, False, True, ValueError, TypeError, IndexError, | |
198 | SystemError, object, type, int, str, tuple, list, | |
199 | ) | |
200 | for i, obj in enumerate(builtin_objs): | |
201 | if i == 0: | |
202 | continue | |
203 | assert mod.f(i) is obj | |
204 | ||
205 | def test_extern_def(self): | |
206 | import pytest | |
207 | main = """ | |
208 | extern HPyDef f; | |
209 | extern HPyDef g; | |
210 | extern HPyDef h; | |
211 | extern HPyDef i; | |
212 | ||
213 | @EXPORT(f) | |
214 | @EXPORT(g) | |
215 | @EXPORT(h) | |
216 | @EXPORT(i) | |
217 | @INIT | |
218 | """ | |
219 | extra = """ | |
220 | HPyDef_METH(f, "f", f_impl, HPyFunc_NOARGS) | |
221 | static HPy f_impl(HPyContext ctx, HPy self) | |
222 | { | |
223 | return HPyLong_FromLong(ctx, 12345); | |
224 | } | |
225 | HPyDef_METH(g, "g", g_impl, HPyFunc_O) | |
226 | static HPy g_impl(HPyContext ctx, HPy self, HPy arg) | |
227 | { | |
228 | return HPy_Dup(ctx, arg); | |
229 | } | |
230 | HPyDef_METH(h, "h", h_impl, HPyFunc_VARARGS) | |
231 | static HPy h_impl(HPyContext ctx, HPy self, HPy *args, HPy_ssize_t nargs) | |
232 | { | |
233 | long a, b; | |
234 | if (!HPyArg_Parse(ctx, NULL, args, nargs, "ll", &a, &b)) | |
235 | return HPy_NULL; | |
236 | return HPyLong_FromLong(ctx, 10*a + b); | |
237 | } | |
238 | HPyDef_METH(i, "i", i_impl, HPyFunc_KEYWORDS) | |
239 | static HPy i_impl(HPyContext ctx, HPy self, HPy *args, HPy_ssize_t nargs, | |
240 | HPy kw) | |
241 | { | |
242 | long a, b; | |
243 | static const char *kwlist[] = { "a", "b", NULL }; | |
244 | if (!HPyArg_ParseKeywords(ctx, NULL, args, nargs, kw, "ll", kwlist, &a, &b)) | |
245 | return HPy_NULL; | |
246 | return HPyLong_FromLong(ctx, 10*a + b); | |
247 | } | |
248 | """ | |
249 | mod = self.make_module(main, extra_sources=[extra]) | |
250 | assert mod.f() == 12345 | |
251 | assert mod.g(42) == 42 | |
252 | assert mod.h(5, 6) == 56 | |
253 | assert mod.i(4, 3) == 43 | |
254 | assert mod.i(a=2, b=5) == 25 | |
255 | with pytest.raises(TypeError): | |
256 | mod.h("not an integer", "not an integer either") | |
257 | ||
258 | def test_Float_FromDouble(self): | |
259 | mod = self.make_module(""" | |
260 | HPyDef_METH(f, "f", f_impl, HPyFunc_NOARGS) | |
261 | static HPy f_impl(HPyContext ctx, HPy self) | |
262 | { | |
263 | return HPyFloat_FromDouble(ctx, 123.45); | |
264 | } | |
265 | @EXPORT(f) | |
266 | @INIT | |
267 | """) | |
268 | assert mod.f() == 123.45 | |
269 | ||
270 | def test_unsupported_signature(self): | |
271 | import pytest | |
272 | with pytest.raises(ValueError) as exc: | |
273 | self.make_module(""" | |
274 | HPyDef f = { | |
275 | .kind = HPyDef_Kind_Meth, | |
276 | .meth = { | |
277 | .name = "f", | |
278 | .signature = 1234, | |
279 | } | |
280 | }; | |
281 | @EXPORT(f) | |
282 | @INIT | |
283 | """) | |
284 | assert str(exc.value) == 'Unsupported HPyMeth signature' | |
285 | ||
286 | def test_repr_str_ascii_bytes(self): | |
287 | mod = self.make_module(""" | |
288 | HPyDef_METH(f1, "f1", f1_impl, HPyFunc_O) | |
289 | static HPy f1_impl(HPyContext ctx, HPy self, HPy arg) | |
290 | { | |
291 | return HPy_Repr(ctx, arg); | |
292 | } | |
293 | HPyDef_METH(f2, "f2", f2_impl, HPyFunc_O) | |
294 | static HPy f2_impl(HPyContext ctx, HPy self, HPy arg) | |
295 | { | |
296 | return HPy_Str(ctx, arg); | |
297 | } | |
298 | HPyDef_METH(f3, "f3", f3_impl, HPyFunc_O) | |
299 | static HPy f3_impl(HPyContext ctx, HPy self, HPy arg) | |
300 | { | |
301 | return HPy_ASCII(ctx, arg); | |
302 | } | |
303 | HPyDef_METH(f4, "f4", f4_impl, HPyFunc_O) | |
304 | static HPy f4_impl(HPyContext ctx, HPy self, HPy arg) | |
305 | { | |
306 | return HPy_Bytes(ctx, arg); | |
307 | } | |
308 | @EXPORT(f1) | |
309 | @EXPORT(f2) | |
310 | @EXPORT(f3) | |
311 | @EXPORT(f4) | |
312 | @INIT | |
313 | """) | |
314 | assert mod.f1("\u1234") == "'\u1234'" | |
315 | assert mod.f2(42) == "42" | |
316 | assert mod.f3("\u1234") == "'\\u1234'" | |
317 | assert mod.f4(bytearray(b"foo")) == b"foo" | |
318 | ||
319 | def test_is_true(self): | |
320 | mod = self.make_module(""" | |
321 | HPyDef_METH(f, "f", f_impl, HPyFunc_O) | |
322 | static HPy f_impl(HPyContext ctx, HPy self, HPy arg) | |
323 | { | |
324 | int cond = HPy_IsTrue(ctx, arg); | |
325 | return HPy_Dup(ctx, cond ? ctx->h_True : ctx->h_False); | |
326 | } | |
327 | @EXPORT(f) | |
328 | @INIT | |
329 | """) | |
330 | assert mod.f("1234") is True | |
331 | assert mod.f("") is False | |
332 | ||
333 | def test_richcompare(self): | |
334 | mod = self.make_module(""" | |
335 | HPyDef_METH(f, "f", f_impl, HPyFunc_O) | |
336 | static HPy f_impl(HPyContext ctx, HPy self, HPy arg) | |
337 | { | |
338 | HPy arg2 = HPyLong_FromLong(ctx, 100); | |
339 | HPy result = HPy_RichCompare(ctx, arg, arg2, HPy_GT); | |
340 | HPy_Close(ctx, arg2); | |
341 | return result; | |
342 | } | |
343 | @EXPORT(f) | |
344 | @INIT | |
345 | """) | |
346 | assert mod.f(100) is False | |
347 | assert mod.f(150) is True | |
348 | ||
349 | def test_richcomparebool(self): | |
350 | mod = self.make_module(""" | |
351 | HPyDef_METH(f, "f", f_impl, HPyFunc_O) | |
352 | static HPy f_impl(HPyContext ctx, HPy self, HPy arg) | |
353 | { | |
354 | HPy arg2 = HPyLong_FromLong(ctx, 100); | |
355 | int result = HPy_RichCompareBool(ctx, arg, arg2, HPy_GE); | |
356 | HPy_Close(ctx, arg2); | |
357 | return HPyLong_FromLong(ctx, -result); | |
358 | } | |
359 | @EXPORT(f) | |
360 | @INIT | |
361 | """) | |
362 | assert mod.f(50) == 0 | |
363 | assert mod.f(100) == -1 | |
364 | ||
365 | def test_hash(self): | |
366 | mod = self.make_module(""" | |
367 | HPyDef_METH(f, "f", f_impl, HPyFunc_O) | |
368 | static HPy f_impl(HPyContext ctx, HPy self, HPy arg) | |
369 | { | |
370 | HPy_hash_t hash = HPy_Hash(ctx, arg); | |
371 | return HPyLong_FromSsize_t(ctx, hash); | |
372 | } | |
373 | @EXPORT(f) | |
374 | @INIT | |
375 | """) | |
376 | x = object() | |
377 | assert mod.f(x) == hash(x) |
0 | """ | |
1 | NOTE: this tests are also meant to be run as PyPy "applevel" tests. | |
2 | ||
3 | This means that global imports will NOT be visible inside the test | |
4 | functions. In particular, you have to "import pytest" inside the test in order | |
5 | to be able to use e.g. pytest.raises (which on PyPy will be implemented by a | |
6 | "fake pytest module") | |
7 | """ | |
8 | from .support import HPyTest | |
9 | ||
10 | ||
11 | class TestBasic(HPyTest): | |
12 | ||
13 | def test_get_version(self): | |
14 | if self.compiler.hpy_abi != 'universal': | |
15 | return | |
16 | import hpy.universal | |
17 | version, gitrev = hpy.universal.get_version() | |
18 | # it's a bit hard to test the CONTENT of these values. Let's just | |
19 | # check that they are strings... | |
20 | assert isinstance(version, str) | |
21 | assert isinstance(gitrev, str) | |
22 | ||
23 | def test_empty_module(self): | |
24 | import sys | |
25 | mod = self.make_module(""" | |
26 | @INIT | |
27 | """) | |
28 | assert type(mod) is type(sys) | |
29 | ||
30 | def test_different_name(self): | |
31 | mod = self.make_module(""" | |
32 | @INIT | |
33 | """, name="foo") | |
34 | assert mod.__name__ == "foo" | |
35 | ||
36 | def test_noop_function(self): | |
37 | mod = self.make_module(""" | |
38 | HPyDef_METH(f, "f", f_impl, HPyFunc_NOARGS, .doc="hello world") | |
39 | static HPy f_impl(HPyContext ctx, HPy self) | |
40 | { | |
41 | return HPy_Dup(ctx, ctx->h_None); | |
42 | } | |
43 | ||
44 | @EXPORT(f) | |
45 | @INIT | |
46 | """) | |
47 | assert mod.f() is None | |
48 | assert mod.f.__doc__ == 'hello world' | |
49 | ||
50 | def test_self_is_module(self): | |
51 | mod = self.make_module(""" | |
52 | HPyDef_METH(f, "f", f_impl, HPyFunc_NOARGS) | |
53 | static HPy f_impl(HPyContext ctx, HPy self) | |
54 | { | |
55 | return HPy_Dup(ctx, self); | |
56 | } | |
57 | @EXPORT(f) | |
58 | @INIT | |
59 | """) | |
60 | assert mod.f() is mod | |
61 | ||
62 | def test_identity_function(self): | |
63 | mod = self.make_module(""" | |
64 | HPyDef_METH(f, "f", f_impl, HPyFunc_O) | |
65 | static HPy f_impl(HPyContext ctx, HPy self, HPy arg) | |
66 | { | |
67 | return HPy_Dup(ctx, arg); | |
68 | } | |
69 | @EXPORT(f) | |
70 | @INIT | |
71 | """) | |
72 | x = object() | |
73 | assert mod.f(x) is x | |
74 | ||
75 | def test_float_asdouble(self): | |
76 | mod = self.make_module(""" | |
77 | HPyDef_METH(f, "f", f_impl, HPyFunc_O) | |
78 | static HPy f_impl(HPyContext ctx, HPy self, HPy arg) | |
79 | { | |
80 | double a = HPyFloat_AsDouble(ctx, arg); | |
81 | return HPyFloat_FromDouble(ctx, a * 2.); | |
82 | } | |
83 | @EXPORT(f) | |
84 | @INIT | |
85 | """) | |
86 | assert mod.f(1.) == 2. | |
87 | ||
88 | def test_wrong_number_of_arguments(self): | |
89 | import pytest | |
90 | mod = self.make_module(""" | |
91 | HPyDef_METH(f_noargs, "f_noargs", f_noargs_impl, HPyFunc_NOARGS) | |
92 | static HPy f_noargs_impl(HPyContext ctx, HPy self) | |
93 | { | |
94 | return HPy_Dup(ctx, ctx->h_None); | |
95 | } | |
96 | HPyDef_METH(f_o, "f_o", f_o_impl, HPyFunc_O) | |
97 | static HPy f_o_impl(HPyContext ctx, HPy self, HPy arg) | |
98 | { | |
99 | return HPy_Dup(ctx, ctx->h_None); | |
100 | } | |
101 | @EXPORT(f_noargs) | |
102 | @EXPORT(f_o) | |
103 | @INIT | |
104 | """) | |
105 | with pytest.raises(TypeError): | |
106 | mod.f_noargs(1) | |
107 | with pytest.raises(TypeError): | |
108 | mod.f_o() | |
109 | with pytest.raises(TypeError): | |
110 | mod.f_o(1, 2) | |
111 | ||
112 | def test_close(self): | |
113 | mod = self.make_module(""" | |
114 | HPyDef_METH(f, "f", f_impl, HPyFunc_O) | |
115 | static HPy f_impl(HPyContext ctx, HPy self, HPy arg) | |
116 | { | |
117 | HPy one = HPyLong_FromLong(ctx, 1); | |
118 | if (HPy_IsNull(one)) | |
119 | return HPy_NULL; | |
120 | HPy res = HPy_Add(ctx, arg, one); | |
121 | HPy_Close(ctx, one); | |
122 | return res; | |
123 | } | |
124 | @EXPORT(f) | |
125 | @INIT | |
126 | """) | |
127 | assert mod.f(41.5) == 42.5 | |
128 | ||
129 | def test_bool(self): | |
130 | mod = self.make_module(""" | |
131 | HPyDef_METH(f, "f", f_impl, HPyFunc_O) | |
132 | static HPy f_impl(HPyContext ctx, HPy self, HPy arg) | |
133 | { | |
134 | int cond = HPyLong_AsLong(ctx, arg) > 5; | |
135 | return HPy_Dup(ctx, cond ? ctx->h_True : ctx->h_False); | |
136 | } | |
137 | @EXPORT(f) | |
138 | @INIT | |
139 | """) | |
140 | assert mod.f(4) is False | |
141 | assert mod.f(6) is True | |
142 | ||
143 | def test_exception(self): | |
144 | import pytest | |
145 | mod = self.make_module(""" | |
146 | HPyDef_METH(f, "f", f_impl, HPyFunc_O) | |
147 | static HPy f_impl(HPyContext ctx, HPy self, HPy arg) | |
148 | { | |
149 | long x = HPyLong_AsLong(ctx, arg); | |
150 | if (x < 5) { | |
151 | return HPyLong_FromLong(ctx, -x); | |
152 | } | |
153 | else { | |
154 | HPyErr_SetString(ctx, ctx->h_ValueError, "hello world"); | |
155 | return HPy_NULL; | |
156 | } | |
157 | } | |
158 | @EXPORT(f) | |
159 | @INIT | |
160 | """) | |
161 | assert mod.f(-10) == 10 | |
162 | with pytest.raises(ValueError) as exc: | |
163 | mod.f(20) | |
164 | assert str(exc.value) == 'hello world' | |
165 | ||
166 | def test_builtin_handles(self): | |
167 | mod = self.make_module(""" | |
168 | HPyDef_METH(f, "f", f_impl, HPyFunc_O) | |
169 | static HPy f_impl(HPyContext ctx, HPy self, HPy arg) | |
170 | { | |
171 | long i = HPyLong_AsLong(ctx, arg); | |
172 | HPy h; | |
173 | switch(i) { | |
174 | case 1: h = ctx->h_None; break; | |
175 | case 2: h = ctx->h_False; break; | |
176 | case 3: h = ctx->h_True; break; | |
177 | case 4: h = ctx->h_ValueError; break; | |
178 | case 5: h = ctx->h_TypeError; break; | |
179 | case 6: h = ctx->h_IndexError; break; | |
180 | case 7: h = ctx->h_SystemError; break; | |
181 | case 8: h = ctx->h_BaseObjectType; break; | |
182 | case 9: h = ctx->h_TypeType; break; | |
183 | case 10: h = ctx->h_LongType; break; | |
184 | case 11: h = ctx->h_UnicodeType; break; | |
185 | case 12: h = ctx->h_TupleType; break; | |
186 | case 13: h = ctx->h_ListType; break; | |
187 | default: | |
188 | HPyErr_SetString(ctx, ctx->h_ValueError, "invalid choice"); | |
189 | return HPy_NULL; | |
190 | } | |
191 | return HPy_Dup(ctx, h); | |
192 | } | |
193 | @EXPORT(f) | |
194 | @INIT | |
195 | """) | |
196 | builtin_objs = ( | |
197 | '<NULL>', None, False, True, ValueError, TypeError, IndexError, | |
198 | SystemError, object, type, int, str, tuple, list, | |
199 | ) | |
200 | for i, obj in enumerate(builtin_objs): | |
201 | if i == 0: | |
202 | continue | |
203 | assert mod.f(i) is obj | |
204 | ||
205 | def test_extern_def(self): | |
206 | import pytest | |
207 | main = """ | |
208 | extern HPyDef f; | |
209 | extern HPyDef g; | |
210 | extern HPyDef h; | |
211 | extern HPyDef i; | |
212 | ||
213 | @EXPORT(f) | |
214 | @EXPORT(g) | |
215 | @EXPORT(h) | |
216 | @EXPORT(i) | |
217 | @INIT | |
218 | """ | |
219 | extra = """ | |
220 | HPyDef_METH(f, "f", f_impl, HPyFunc_NOARGS) | |
221 | static HPy f_impl(HPyContext ctx, HPy self) | |
222 | { | |
223 | return HPyLong_FromLong(ctx, 12345); | |
224 | } | |
225 | HPyDef_METH(g, "g", g_impl, HPyFunc_O) | |
226 | static HPy g_impl(HPyContext ctx, HPy self, HPy arg) | |
227 | { | |
228 | return HPy_Dup(ctx, arg); | |
229 | } | |
230 | HPyDef_METH(h, "h", h_impl, HPyFunc_VARARGS) | |
231 | static HPy h_impl(HPyContext ctx, HPy self, HPy *args, HPy_ssize_t nargs) | |
232 | { | |
233 | long a, b; | |
234 | if (!HPyArg_Parse(ctx, NULL, args, nargs, "ll", &a, &b)) | |
235 | return HPy_NULL; | |
236 | return HPyLong_FromLong(ctx, 10*a + b); | |
237 | } | |
238 | HPyDef_METH(i, "i", i_impl, HPyFunc_KEYWORDS) | |
239 | static HPy i_impl(HPyContext ctx, HPy self, HPy *args, HPy_ssize_t nargs, | |
240 | HPy kw) | |
241 | { | |
242 | long a, b; | |
243 | static const char *kwlist[] = { "a", "b", NULL }; | |
244 | if (!HPyArg_ParseKeywords(ctx, NULL, args, nargs, kw, "ll", kwlist, &a, &b)) | |
245 | return HPy_NULL; | |
246 | return HPyLong_FromLong(ctx, 10*a + b); | |
247 | } | |
248 | """ | |
249 | mod = self.make_module(main, extra_sources=[extra]) | |
250 | assert mod.f() == 12345 | |
251 | assert mod.g(42) == 42 | |
252 | assert mod.h(5, 6) == 56 | |
253 | assert mod.i(4, 3) == 43 | |
254 | assert mod.i(a=2, b=5) == 25 | |
255 | with pytest.raises(TypeError): | |
256 | mod.h("not an integer", "not an integer either") | |
257 | ||
258 | def test_Float_FromDouble(self): | |
259 | mod = self.make_module(""" | |
260 | HPyDef_METH(f, "f", f_impl, HPyFunc_NOARGS) | |
261 | static HPy f_impl(HPyContext ctx, HPy self) | |
262 | { | |
263 | return HPyFloat_FromDouble(ctx, 123.45); | |
264 | } | |
265 | @EXPORT(f) | |
266 | @INIT | |
267 | """) | |
268 | assert mod.f() == 123.45 | |
269 | ||
270 | def test_unsupported_signature(self): | |
271 | import pytest | |
272 | with pytest.raises(ValueError) as exc: | |
273 | self.make_module(""" | |
274 | HPyDef f = { | |
275 | .kind = HPyDef_Kind_Meth, | |
276 | .meth = { | |
277 | .name = "f", | |
278 | .signature = 1234, | |
279 | } | |
280 | }; | |
281 | @EXPORT(f) | |
282 | @INIT | |
283 | """) | |
284 | assert str(exc.value) == 'Unsupported HPyMeth signature' | |
285 | ||
286 | def test_repr_str_ascii_bytes(self): | |
287 | mod = self.make_module(""" | |
288 | HPyDef_METH(f1, "f1", f1_impl, HPyFunc_O) | |
289 | static HPy f1_impl(HPyContext ctx, HPy self, HPy arg) | |
290 | { | |
291 | return HPy_Repr(ctx, arg); | |
292 | } | |
293 | HPyDef_METH(f2, "f2", f2_impl, HPyFunc_O) | |
294 | static HPy f2_impl(HPyContext ctx, HPy self, HPy arg) | |
295 | { | |
296 | return HPy_Str(ctx, arg); | |
297 | } | |
298 | HPyDef_METH(f3, "f3", f3_impl, HPyFunc_O) | |
299 | static HPy f3_impl(HPyContext ctx, HPy self, HPy arg) | |
300 | { | |
301 | return HPy_ASCII(ctx, arg); | |
302 | } | |
303 | HPyDef_METH(f4, "f4", f4_impl, HPyFunc_O) | |
304 | static HPy f4_impl(HPyContext ctx, HPy self, HPy arg) | |
305 | { | |
306 | return HPy_Bytes(ctx, arg); | |
307 | } | |
308 | @EXPORT(f1) | |
309 | @EXPORT(f2) | |
310 | @EXPORT(f3) | |
311 | @EXPORT(f4) | |
312 | @INIT | |
313 | """) | |
314 | assert mod.f1("\u1234") == "'\u1234'" | |
315 | assert mod.f2(42) == "42" | |
316 | assert mod.f3("\u1234") == "'\\u1234'" | |
317 | assert mod.f4(bytearray(b"foo")) == b"foo" | |
318 | ||
319 | def test_is_true(self): | |
320 | mod = self.make_module(""" | |
321 | HPyDef_METH(f, "f", f_impl, HPyFunc_O) | |
322 | static HPy f_impl(HPyContext ctx, HPy self, HPy arg) | |
323 | { | |
324 | int cond = HPy_IsTrue(ctx, arg); | |
325 | return HPy_Dup(ctx, cond ? ctx->h_True : ctx->h_False); | |
326 | } | |
327 | @EXPORT(f) | |
328 | @INIT | |
329 | """) | |
330 | assert mod.f("1234") is True | |
331 | assert mod.f("") is False | |
332 | ||
333 | def test_richcompare(self): | |
334 | mod = self.make_module(""" | |
335 | HPyDef_METH(f, "f", f_impl, HPyFunc_O) | |
336 | static HPy f_impl(HPyContext ctx, HPy self, HPy arg) | |
337 | { | |
338 | HPy arg2 = HPyLong_FromLong(ctx, 100); | |
339 | HPy result = HPy_RichCompare(ctx, arg, arg2, HPy_GT); | |
340 | HPy_Close(ctx, arg2); | |
341 | return result; | |
342 | } | |
343 | @EXPORT(f) | |
344 | @INIT | |
345 | """) | |
346 | assert mod.f(100) is False | |
347 | assert mod.f(150) is True | |
348 | ||
349 | def test_richcomparebool(self): | |
350 | mod = self.make_module(""" | |
351 | HPyDef_METH(f, "f", f_impl, HPyFunc_O) | |
352 | static HPy f_impl(HPyContext ctx, HPy self, HPy arg) | |
353 | { | |
354 | HPy arg2 = HPyLong_FromLong(ctx, 100); | |
355 | int result = HPy_RichCompareBool(ctx, arg, arg2, HPy_GE); | |
356 | HPy_Close(ctx, arg2); | |
357 | return HPyLong_FromLong(ctx, -result); | |
358 | } | |
359 | @EXPORT(f) | |
360 | @INIT | |
361 | """) | |
362 | assert mod.f(50) == 0 | |
363 | assert mod.f(100) == -1 | |
364 | ||
365 | def test_hash(self): | |
366 | mod = self.make_module(""" | |
367 | HPyDef_METH(f, "f", f_impl, HPyFunc_O) | |
368 | static HPy f_impl(HPyContext ctx, HPy self, HPy arg) | |
369 | { | |
370 | HPy_hash_t hash = HPy_Hash(ctx, arg); | |
371 | return HPyLong_FromSsize_t(ctx, hash); | |
372 | } | |
373 | @EXPORT(f) | |
374 | @INIT | |
375 | """) | |
376 | x = object() | |
377 | assert mod.f(x) == hash(x) |
0 | from .support import HPyTest | |
1 | ||
2 | ||
3 | class TestCall(HPyTest): | |
4 | def argument_combinations(self, **items): | |
5 | """ Returns all possible ways of expressing the given items as | |
6 | arguments to a function. | |
7 | """ | |
8 | items = list(items.items()) | |
9 | for i in range(len(items) + 1): | |
10 | args = tuple(item[1] for item in items[:i]) | |
11 | kw = dict(items[i:]) | |
12 | yield {"args": args, "kw": kw} | |
13 | if not args: | |
14 | yield {"kw": kw} | |
15 | if not kw: | |
16 | yield {"args": args} | |
17 | if not args and not kw: | |
18 | yield {} | |
19 | ||
20 | def test_hpy_calltupledict(self): | |
21 | import pytest | |
22 | mod = self.make_module(""" | |
23 | HPyDef_METH(call, "call", call_impl, HPyFunc_KEYWORDS) | |
24 | static HPy call_impl(HPyContext ctx, HPy self, | |
25 | HPy *args, HPy_ssize_t nargs, HPy kw) | |
26 | { | |
27 | ||
28 | HPy f, result; | |
29 | HPy f_args = HPy_NULL; | |
30 | HPy f_kw = HPy_NULL; | |
31 | HPyTracker ht; | |
32 | static const char *kwlist[] = { "f", "args", "kw", NULL }; | |
33 | if (!HPyArg_ParseKeywords(ctx, &ht, args, nargs, kw, "O|OO", | |
34 | kwlist, &f, &f_args, &f_kw)) { | |
35 | return HPy_NULL; | |
36 | } | |
37 | result = HPy_CallTupleDict(ctx, f, f_args, f_kw); | |
38 | HPyTracker_Close(ctx, ht); | |
39 | return result; | |
40 | } | |
41 | @EXPORT(call) | |
42 | @INIT | |
43 | """) | |
44 | ||
45 | def f(a, b): | |
46 | return a + b | |
47 | ||
48 | def g(): | |
49 | return "this is g" | |
50 | ||
51 | # test passing arguments with handles of the correct type -- | |
52 | # i.e. args is a tuple or a null handle, kw is a dict or a null handle. | |
53 | for d in self.argument_combinations(a=1, b=2): | |
54 | assert mod.call(f, **d) == 3 | |
55 | for d in self.argument_combinations(a=1): | |
56 | with pytest.raises(TypeError): | |
57 | mod.call(f, **d) | |
58 | for d in self.argument_combinations(): | |
59 | with pytest.raises(TypeError): | |
60 | mod.call(f, **d) | |
61 | for d in self.argument_combinations(): | |
62 | assert mod.call(g, **d) == "this is g" | |
63 | for d in self.argument_combinations(object=2): | |
64 | assert mod.call(str, **d) == "2" | |
65 | for d in self.argument_combinations(): | |
66 | with pytest.raises(TypeError): | |
67 | mod.call("not callable", **d) | |
68 | for d in self.argument_combinations(unknown=2): | |
69 | with pytest.raises(TypeError): | |
70 | mod.call("not callable", **d) | |
71 | ||
72 | # test passing handles of the incorrect type as arguments | |
73 | with pytest.raises(TypeError): | |
74 | mod.call(f, args=[1, 2]) | |
75 | with pytest.raises(TypeError): | |
76 | mod.call(f, args="string") | |
77 | with pytest.raises(TypeError): | |
78 | mod.call(f, args=1) | |
79 | with pytest.raises(TypeError): | |
80 | mod.call(f, args=None) | |
81 | with pytest.raises(TypeError): | |
82 | mod.call(f, kw=[1, 2]) | |
83 | with pytest.raises(TypeError): | |
84 | mod.call(f, kw="string") | |
85 | with pytest.raises(TypeError): | |
86 | mod.call(f, kw=1) | |
87 | with pytest.raises(TypeError): | |
88 | mod.call(f, kw=None) | |
89 | ||
90 | def test_hpycallable_check(self): | |
91 | mod = self.make_module(""" | |
92 | HPyDef_METH(f, "f", f_impl, HPyFunc_O) | |
93 | static HPy f_impl(HPyContext ctx, HPy self, HPy arg) | |
94 | { | |
95 | if (HPyCallable_Check(ctx, arg)) | |
96 | return HPy_Dup(ctx, ctx->h_True); | |
97 | return HPy_Dup(ctx, ctx->h_False); | |
98 | } | |
99 | @EXPORT(f) | |
100 | @INIT | |
101 | """) | |
102 | ||
103 | def f(): | |
104 | return "this is f" | |
105 | ||
106 | assert mod.f(f) is True | |
107 | assert mod.f(str) is True | |
108 | assert mod.f("a") is False | |
109 | assert mod.f(3) is False |
2 | 2 | |
3 | 3 | class TestCPythonCompatibility(HPyTest): |
4 | 4 | |
5 | # One note about the should_check_refcount() in the tests below: on | |
5 | # One note about the supports_refcounts() in the tests below: on | |
6 | 6 | # CPython, handles are actually implemented as INCREF/DECREF, so we can |
7 | 7 | # check e.g. after an HPy_Dup the refcnt is += 1. However, on PyPy they |
8 | 8 | # are implemented in a completely different way which is unrelated to the |
34 | 34 | x = mod.f() |
35 | 35 | assert x[0] == 1234 |
36 | 36 | assert len(x) == 2 |
37 | if self.should_check_refcount(): | |
37 | if self.supports_refcounts(): | |
38 | 38 | assert x == [1234, +1] |
39 | 39 | |
40 | 40 | def test_aspyobject(self): |
96 | 96 | @INIT |
97 | 97 | """) |
98 | 98 | x = mod.f() |
99 | if self.should_check_refcount(): | |
99 | if self.supports_refcounts(): | |
100 | 100 | assert x == -1 |
101 | 101 | |
102 | 102 | def test_hpy_dup(self): |
122 | 122 | @INIT |
123 | 123 | """) |
124 | 124 | x = mod.f() |
125 | if self.should_check_refcount(): | |
125 | if self.supports_refcounts(): | |
126 | 126 | assert x == +1 |
127 | 127 | |
128 | 128 | def test_many_handles(self): |
19 | 19 | mod.f() |
20 | 20 | |
21 | 21 | def test_FatalError(self): |
22 | import os | |
23 | import sys | |
22 | 24 | mod = self.make_module(""" |
23 | 25 | HPyDef_METH(f, "f", f_impl, HPyFunc_NOARGS) |
24 | 26 | static HPy f_impl(HPyContext ctx, HPy self) |
32 | 34 | @EXPORT(f) |
33 | 35 | @INIT |
34 | 36 | """) |
35 | # Calling mod.f() gives a fatal error, ending in abort(). | |
36 | # How to check that? For now we just check that the above compiles | |
37 | if not self.supports_sys_executable(): | |
38 | # if sys.executable is not available (e.g. inside pypy app-level) | |
39 | # tests, then skip the rest of this test | |
40 | return | |
41 | # subprocess is not importable in pypy app-level tests | |
42 | import subprocess | |
43 | env = os.environ.copy() | |
44 | env["PYTHONPATH"] = os.path.dirname(mod.__file__) | |
45 | result = subprocess.run([ | |
46 | sys.executable, | |
47 | "-c", "import {} as mod; mod.f()".format(mod.__name__) | |
48 | ], env=env, stdout=subprocess.PIPE, stderr=subprocess.PIPE) | |
49 | assert result.returncode == -6 | |
50 | assert result.stdout == b"" | |
51 | assert result.stderr.startswith(b"Fatal Python error: boom!\n") | |
37 | 52 | |
38 | 53 | def test_HPyErr_Occurred(self): |
39 | 54 | import pytest |
232 | 247 | check_exception(EnvironmentError) |
233 | 248 | check_exception(IOError) |
234 | 249 | |
235 | @pytest_collecting.mark.xfail(True, reason=( | |
236 | "Creating the unicode exceptions requires something like HPyCall" | |
237 | " and that isn't implemented yet." | |
238 | )) | |
239 | 250 | def test_h_unicode_exceptions(self): |
240 | 251 | import pytest |
241 | 252 | mod = self.make_module(""" |
263 | 274 | HPy_Close(ctx, h_dict); |
264 | 275 | return HPy_NULL; |
265 | 276 | } |
266 | h_err_value = HPy_Call(ctx, h_err, h_args, h_kw); | |
277 | h_err_value = HPy_CallTupleDict(ctx, h_err, h_args, h_kw); | |
267 | 278 | if (HPy_IsNull(h_err_value)) { |
268 | 279 | HPy_Close(ctx, h_dict); |
269 | 280 | HPy_Close(ctx, h_err); |
1 | 1 | |
2 | 2 | |
3 | 3 | class TestLong(HPyTest): |
4 | ||
5 | def magic_int(self, v): | |
6 | """ Return an instance of a class that implements __int__ | |
7 | and returns value v. | |
8 | """ | |
9 | class MagicInt(object): | |
10 | def __int__(self): | |
11 | return v | |
12 | return MagicInt() | |
13 | ||
14 | def magic_index(self, v): | |
15 | """ Return an instance of a class that implements __index__ | |
16 | and returns value v. | |
17 | """ | |
18 | class MagicIndex(object): | |
19 | def __index__(self): | |
20 | return v | |
21 | return MagicIndex() | |
22 | ||
23 | def python_supports_magic_index(self): | |
24 | """ Return True if the Python version is 3.8 or later and thus | |
25 | should support calling __index__ in the various HPyLong_As... | |
26 | methods. | |
27 | """ | |
28 | import sys | |
29 | vi = sys.version_info | |
30 | return (vi.major > 3 or (vi.major == 3 and vi.minor >= 8)) | |
4 | 31 | |
5 | 32 | def test_Long_FromLong(self): |
6 | 33 | mod = self.make_module(""" |
32 | 59 | assert mod.f(45) == 90 |
33 | 60 | with pytest.raises(TypeError): |
34 | 61 | mod.f("this is not a number") |
62 | assert mod.f(self.magic_int(2)) == 4 | |
63 | if self.python_supports_magic_index(): | |
64 | assert mod.f(self.magic_index(2)) == 4 | |
35 | 65 | |
36 | 66 | def test_Long_FromUnsignedLong(self): |
37 | 67 | mod = self.make_module(""" |
65 | 95 | mod.f(-91) |
66 | 96 | with pytest.raises(TypeError): |
67 | 97 | mod.f("this is not a number") |
98 | with pytest.raises(TypeError): | |
99 | mod.f(self.magic_int(2)) | |
100 | with pytest.raises(TypeError): | |
101 | mod.f(self.magic_index(2)) | |
68 | 102 | |
69 | 103 | def test_Long_AsUnsignedLongMask(self): |
70 | 104 | import pytest |
84 | 118 | assert mod.f(-1) == 2**64 - 1 |
85 | 119 | with pytest.raises(TypeError): |
86 | 120 | mod.f("this is not a number") |
121 | assert mod.f(self.magic_int(2)) == 2 | |
122 | if self.python_supports_magic_index(): | |
123 | assert mod.f(self.magic_index(2)) == 2 | |
87 | 124 | |
88 | 125 | def test_Long_FromLongLong(self): |
89 | 126 | mod = self.make_module(""" |
117 | 154 | assert mod.f(-2147483648) == -2147483648 |
118 | 155 | with pytest.raises(TypeError): |
119 | 156 | mod.f("this is not a number") |
157 | assert mod.f(self.magic_int(2)) == 2 | |
158 | if self.python_supports_magic_index(): | |
159 | assert mod.f(self.magic_index(2)) == 2 | |
120 | 160 | |
121 | 161 | def test_Long_FromUnsignedLongLong(self): |
122 | 162 | mod = self.make_module(""" |
151 | 191 | mod.f(-4294967296) |
152 | 192 | with pytest.raises(TypeError): |
153 | 193 | mod.f("this is not a number") |
194 | with pytest.raises(TypeError): | |
195 | mod.f(self.magic_int(2)) | |
196 | with pytest.raises(TypeError): | |
197 | mod.f(self.magic_index(2)) | |
154 | 198 | |
155 | 199 | def test_Long_AsUnsignedLongLongMask(self): |
156 | 200 | import pytest |
170 | 214 | assert mod.f(-1) == 2**64 - 1 |
171 | 215 | with pytest.raises(TypeError): |
172 | 216 | mod.f("this is not a number") |
217 | assert mod.f(self.magic_int(2)) == 2 | |
218 | if self.python_supports_magic_index(): | |
219 | assert mod.f(self.magic_index(2)) == 2 | |
173 | 220 | |
174 | 221 | def test_Long_FromSize_t(self): |
175 | 222 | mod = self.make_module(""" |
204 | 251 | mod.f(-2147483648) |
205 | 252 | with pytest.raises(TypeError): |
206 | 253 | mod.f("this is not a number") |
254 | with pytest.raises(TypeError): | |
255 | mod.f(self.magic_int(2)) | |
256 | with pytest.raises(TypeError): | |
257 | mod.f(self.magic_index(2)) | |
207 | 258 | |
208 | 259 | def test_Long_FromSsize_t(self): |
209 | 260 | mod = self.make_module(""" |
240 | 291 | assert mod.f(-41) == -41 |
241 | 292 | with pytest.raises(TypeError): |
242 | 293 | mod.f("this is not a number") |
294 | with pytest.raises(TypeError): | |
295 | mod.f(self.magic_int(2)) | |
296 | with pytest.raises(TypeError): | |
297 | mod.f(self.magic_index(2)) |
0 | 0 | from .support import HPyTest |
1 | 1 | |
2 | 2 | class TestTuple(HPyTest): |
3 | ||
4 | def test_Check(self): | |
5 | mod = self.make_module(""" | |
6 | HPyDef_METH(f, "f", f_impl, HPyFunc_O) | |
7 | static HPy f_impl(HPyContext ctx, HPy self, HPy arg) | |
8 | { | |
9 | if (HPyTuple_Check(ctx, arg)) | |
10 | return HPy_Dup(ctx, ctx->h_True); | |
11 | return HPy_Dup(ctx, ctx->h_False); | |
12 | } | |
13 | @EXPORT(f) | |
14 | @INIT | |
15 | """) | |
16 | class MyTuple(tuple): | |
17 | pass | |
18 | ||
19 | assert mod.f(()) is True | |
20 | assert mod.f([]) is False | |
21 | assert mod.f(MyTuple()) is True | |
3 | 22 | |
4 | 23 | def test_FromArray(self): |
5 | 24 | mod = self.make_module(""" |
191 | 191 | def test_refcount(self): |
192 | 192 | import pytest |
193 | 193 | import sys |
194 | if not self.should_check_refcount(): | |
194 | if not self.supports_refcounts(): | |
195 | 195 | pytest.skip() |
196 | 196 | mod = self.make_module(""" |
197 | 197 | @DEFINE_PointObject |
0 | import pytest as pytest_collecting | |
1 | ||
2 | 0 | from .support import HPyTest |
3 | ||
4 | # this function should probably goes somewhere into hpy.universal and/or and | |
5 | # hpy package and/or an import hook, or whatever. I do not want to think about | |
6 | # this now. | |
7 | def import_module_properly(mod): | |
8 | raise NotImplementedError("fix me eventually") | |
9 | ||
10 | # this was moved from support.py, where it did not belong | |
11 | ## class HPyLoader(ExtensionFileLoader): | |
12 | ## def create_module(self, spec): | |
13 | ## import hpy.universal | |
14 | ## return hpy.universal.load_from_spec(spec) | |
15 | 1 | |
16 | 2 | |
17 | 3 | class TestImporting(HPyTest): |
18 | 4 | |
19 | @pytest_collecting.mark.xfail | |
20 | 5 | def test_importing_attributes(self): |
21 | import sys | |
22 | modname = 'mytest' | |
23 | so_filename = self.compile_module(""" | |
6 | import pytest | |
7 | if not self.supports_ordinary_make_module_imports(): | |
8 | pytest.skip() | |
9 | mod = self.make_module(""" | |
24 | 10 | @INIT |
25 | """, name=modname) | |
26 | mod = import_module_properly(so_filename, modname) | |
27 | assert mod in sys.modules | |
11 | """, name='mytest') | |
12 | assert mod.__name__ == 'mytest' | |
13 | assert mod.__package__ == '' | |
14 | assert mod.__doc__ == 'some test for hpy' | |
28 | 15 | assert mod.__loader__.name == 'mytest' |
29 | 16 | assert mod.__spec__.loader is mod.__loader__ |
17 | assert mod.__spec__.name == 'mytest' | |
30 | 18 | assert mod.__file__ |
7 | 7 | from pypy.module._hpy_universal._vendored.hpy.devel import HPyDevel |
8 | 8 | |
9 | 9 | COMPILER_VERBOSE = False |
10 | ||
11 | 10 | |
12 | 11 | |
13 | 12 | class HPyAppTest(object): |
54 | 53 | else: |
55 | 54 | items_w = space.unpackiterable(w_extra_sources) |
56 | 55 | extra_sources = [space.text_w(item) for item in items_w] |
57 | so_filename = compiler.compile_module(ExtensionTemplate, | |
56 | py_filename = compiler.compile_module(ExtensionTemplate, | |
58 | 57 | source_template, name, extra_sources) |
58 | so_filename = py_filename.replace(".py", ".hpy.so") | |
59 | 59 | w_mod = space.appexec([space.newtext(so_filename), space.newtext(name)], |
60 | 60 | """(path, modname): |
61 | 61 | import _hpy_universal |
65 | 65 | return w_mod |
66 | 66 | self.w_make_module = self.space.wrap(interp2app(descr_make_module)) |
67 | 67 | |
68 | def should_check_refcount(space): | |
68 | def supports_refcounts(space): | |
69 | 69 | return space.w_False |
70 | self.w_should_check_refcount = self.space.wrap(interp2app(should_check_refcount)) | |
70 | self.w_supports_refcounts = self.space.wrap(interp2app(supports_refcounts)) | |
71 | ||
72 | def supports_ordinary_make_module_imports(space): | |
73 | return space.w_False | |
74 | self.w_supports_ordinary_make_module_imports = self.space.wrap( | |
75 | interp2app(supports_ordinary_make_module_imports)) | |
76 | ||
77 | def supports_sys_executable(space): | |
78 | return space.w_False | |
79 | self.w_supports_sys_executable = self.space.wrap( | |
80 | interp2app(supports_sys_executable)) | |
71 | 81 | |
72 | 82 | self.w_compiler = self.space.appexec([], """(): |
73 | 83 | class compiler: |
29 | 29 | - ListBuilder_Cancel is not tested |
30 | 30 | |
31 | 31 | """ |
32 | def test_import_failure(self): | |
33 | import pytest | |
34 | with pytest.raises(RuntimeError): | |
35 | self.make_module(""" | |
36 | HPy_MODINIT(test) | |
37 | static HPy init_test_impl(HPyContext ctx) | |
38 | { | |
39 | HPyErr_SetString(ctx, ctx->h_RuntimeError, "foo"); | |
40 | return HPyLong_FromLong(ctx, 42); | |
41 | } | |
42 | """, name='test') | |
43 | ||
44 | def test_import_bad_module(self): | |
45 | import pytest | |
46 | with pytest.raises(SystemError): | |
47 | self.make_module(""" | |
48 | HPy_MODINIT(test) | |
49 | static HPy init_test_impl(HPyContext ctx) | |
50 | { | |
51 | return HPy_NULL; | |
52 | } | |
53 | """, name='test') | |
54 | ||
55 | def test_HPyModule_Create(self): | |
56 | mod = self.make_module(""" | |
57 | HPyDef_METH(f, "f", f_impl, HPyFunc_NOARGS) | |
58 | static HPy f_impl(HPyContext ctx, HPy self) | |
59 | { | |
60 | HPyModuleDef def = { | |
61 | .m_name = "foo", | |
62 | .m_doc = "Some doc", | |
63 | .m_size = -1, | |
64 | }; | |
65 | return HPyModule_Create(ctx, &def); | |
66 | } | |
67 | @EXPORT(f) | |
68 | @INIT | |
69 | """) | |
70 | m = mod.f() | |
71 | assert m.__name__ == "foo" | |
72 | assert m.__doc__ == "Some doc" | |
73 | assert m.__package__ is None | |
74 | assert m.__loader__ is None | |
75 | assert m.__spec__ is None | |
76 | assert set(vars(m).keys()) == { | |
77 | '__name__', '__doc__', '__package__', '__loader__', '__spec__'} | |
32 | 78 | |
33 | 79 | |
34 | 80 | class TestExtraCPythonCompatibility(HPyTest): |
0 | 0 | """ The ffi for rpython |
1 | 1 | """ |
2 | 2 | |
3 | from rpython.rtyper.lltypesystem import rffi | |
3 | from rpython.rtyper.lltypesystem import rffi, lltype | |
4 | 4 | from rpython.rtyper.tool import rffi_platform |
5 | 5 | from rpython.translator.tool.cbuild import ExternalCompilationInfo |
6 | 6 | |
74 | 74 | |
75 | 75 | eci = eci.merge(ExternalCompilationInfo( |
76 | 76 | post_include_bits=[ |
77 | "RPY_EXTERN char *rpy_curses_setupterm(char *, int);\n" | |
77 | "RPY_EXTERN int rpy_curses_setupterm(char *, int, int *);\n" | |
78 | 78 | "RPY_EXTERN char *rpy_curses_tigetstr(char *);\n" |
79 | 79 | "RPY_EXTERN char *rpy_curses_tparm(char *, int, int, int, int," |
80 | 80 | " int, int, int, int, int);" |
84 | 84 | %(include_lines)s |
85 | 85 | |
86 | 86 | RPY_EXTERN |
87 | char *rpy_curses_setupterm(char *term, int fd) | |
88 | { | |
89 | int errret = -42; | |
90 | if (setupterm(term, fd, &errret) == ERR) { | |
91 | switch (errret) { | |
92 | case 0: | |
93 | return "setupterm: could not find terminal"; | |
94 | case -1: | |
95 | return "setupterm: could not find terminfo database"; | |
96 | default: | |
97 | return "setupterm: unknown error"; | |
98 | } | |
99 | } | |
100 | return NULL; | |
87 | int rpy_curses_setupterm(char *t, int fd, int *errret) { | |
88 | return setupterm(t, fd, errret); | |
101 | 89 | } |
102 | 90 | |
103 | 91 | RPY_EXTERN |
119 | 107 | """ % globals()])) |
120 | 108 | |
121 | 109 | |
122 | rpy_curses_setupterm = rffi.llexternal( | |
123 | "rpy_curses_setupterm", [rffi.CCHARP, rffi.INT], rffi.CCHARP, | |
124 | compilation_info=eci) | |
110 | setupterm = rffi.llexternal( | |
111 | "rpy_curses_setupterm", [rffi.CCHARP, rffi.INT, rffi.INTP], | |
112 | rffi.INT, compilation_info=eci) | |
125 | 113 | |
126 | 114 | rpy_curses_tigetstr = rffi.llexternal( |
127 | 115 | "rpy_curses_tigetstr", [rffi.CCHARP], rffi.CCHARP, |
1 | 1 | from pypy.interpreter.error import OperationError |
2 | 2 | from pypy.module._minimal_curses import fficurses |
3 | 3 | from rpython.rtyper.lltypesystem import lltype, rffi |
4 | from rpython.rlib.rarithmetic import r_uint, intmask, widen | |
4 | 5 | |
5 | 6 | |
6 | 7 | class ModuleInfo: |
21 | 22 | |
22 | 23 | @unwrap_spec(fd=int) |
23 | 24 | def setupterm(space, w_termname=None, fd=-1): |
25 | _fd = fd | |
24 | 26 | if fd == -1: |
25 | 27 | w_stdout = space.getattr(space.getbuiltinmodule('sys'), |
26 | 28 | space.newtext('stdout')) |
27 | fd = space.int_w(space.call_function(space.getattr(w_stdout, | |
29 | _fd = space.int_w(space.call_function(space.getattr(w_stdout, | |
28 | 30 | space.newtext('fileno')))) |
29 | 31 | if space.is_none(w_termname): |
30 | 32 | termname = None |
33 | termname_err = 'None' | |
31 | 34 | else: |
32 | 35 | termname = space.text_w(w_termname) |
36 | termname_err = "'%s'" % termname | |
33 | 37 | |
34 | with rffi.scoped_str2charp(termname) as ll_term: | |
35 | fd = rffi.cast(rffi.INT, fd) | |
36 | ll_errmsg = fficurses.rpy_curses_setupterm(ll_term, fd) | |
37 | if ll_errmsg: | |
38 | raise curses_error(space, rffi.charp2str(ll_errmsg)) | |
39 | ||
38 | p_errret = lltype.malloc(rffi.INTP.TO, 1, flavor='raw') | |
39 | try: | |
40 | with rffi.scoped_str2charp(termname) as ll_term: | |
41 | _fd = rffi.cast(rffi.INT, _fd) | |
42 | errval = fficurses.setupterm(ll_term, _fd, p_errret) | |
43 | ||
44 | if errval == -1: | |
45 | errret = widen(p_errret[0]) | |
46 | if errret == 0: | |
47 | msg_ext = 'could not find terminal' | |
48 | elif errret == -1: | |
49 | msg_ext = 'could not find termininfo database' | |
50 | else: | |
51 | msg_ext = 'unknown error' | |
52 | msg = ("setupterm(%s, %d) failed (err=%d): %s" % | |
53 | (termname_err, fd, errret, msg_ext)) | |
54 | raise curses_error(space, msg) | |
55 | finally: | |
56 | lltype.free(p_errret, flavor='raw') | |
40 | 57 | space.fromcache(ModuleInfo).setupterm_called = True |
41 | 58 | |
42 | 59 | @unwrap_spec(capname='text') |
80 | 80 | |
81 | 81 | def runs_setupterm(): |
82 | 82 | null = lltype.nullptr(rffi.CCHARP.TO) |
83 | fficurses.rpy_curses_setupterm(null, 1) | |
83 | p_errret = lltype.malloc(rffi.INTP.TO, 1, flavor='raw') | |
84 | errval = fficurses.setupterm(null, 1, p_errret) | |
84 | 85 | |
85 | 86 | fn = compile(runs_setupterm, []) |
86 | 87 | fn() |
91 | 92 | from pypy.module._minimal_curses import fficurses |
92 | 93 | |
93 | 94 | def runs_ctgetstr(): |
95 | p_errret = lltype.malloc(rffi.INTP.TO, 1, flavor='raw') | |
94 | 96 | with rffi.scoped_str2charp("xterm") as ll_term: |
95 | fficurses.rpy_curses_setupterm(ll_term, 1) | |
97 | errval = fficurses.setupterm(ll_term, 1, p_errret) | |
96 | 98 | with rffi.scoped_str2charp("cup") as ll_capname: |
97 | 99 | ll = fficurses.rpy_curses_tigetstr(ll_capname) |
98 | 100 | return rffi.charp2str(ll) |
107 | 109 | from pypy.module._minimal_curses import fficurses |
108 | 110 | |
109 | 111 | def runs_tparm(): |
112 | p_errret = lltype.malloc(rffi.INTP.TO, 1, flavor='raw') | |
110 | 113 | with rffi.scoped_str2charp("xterm") as ll_term: |
111 | fficurses.rpy_curses_setupterm(ll_term, 1) | |
114 | errval = fficurses.setupterm(ll_term, 1, p_errret) | |
112 | 115 | with rffi.scoped_str2charp("cup") as ll_capname: |
113 | 116 | cup = fficurses.rpy_curses_tigetstr(ll_capname) |
114 | 117 | res = fficurses.rpy_curses_tparm(cup, 5, 3, 0, 0, 0, 0, 0, 0, 0) |
533 | 533 | return w_item, n |
534 | 534 | |
535 | 535 | def sub_get_printable_location(filter_is_callable, use_builder, filter_type, pattern): |
536 | s = str(pattern) | |
536 | s = str(pattern.pattern) | |
537 | 537 | if len(s) > 120: |
538 | 538 | s = s[:110] + '...' |
539 | 539 | if use_builder == '\x00': |
551 | 551 | |
552 | 552 | |
553 | 553 | def split_get_printable_location(num_groups, ctx_type, pattern): |
554 | s = str(pattern) | |
554 | s = str(pattern.pattern) | |
555 | 555 | if len(s) > 120: |
556 | 556 | s = s[:110] + '...' |
557 | 557 |
1433 | 1433 | |
1434 | 1434 | |
1435 | 1435 | def mangle_name(prefix, name): |
1436 | if name.startswith('Py'): | |
1436 | if name.startswith('PyPyUnicode'): | |
1437 | # for PyPyUnicode_Check, PyPyUnicode_CheckExact | |
1438 | return name | |
1439 | elif name.startswith('Py'): | |
1437 | 1440 | return prefix + name[2:] |
1438 | 1441 | elif name.startswith('_Py'): |
1439 | 1442 | return '_' + prefix + name[3:] |
10 | 10 | utf8_encode_utf_32_helper, str_decode_latin_1, utf8_encode_latin_1) |
11 | 11 | from pypy.objspace.std.unicodeobject import unicodedb |
12 | 12 | from pypy.module.cpyext.api import ( |
13 | CANNOT_FAIL, Py_ssize_t, Py_TPFLAGS_UNICODE_SUBCLASS, cpython_api, | |
14 | bootstrap_function, CONST_STRING, INTP_real, | |
13 | CANNOT_FAIL, Py_ssize_t, cpython_api, | |
14 | bootstrap_function, CONST_STRING, INTP_real, Py_TPFLAGS_UNICODE_SUBCLASS, | |
15 | 15 | CONST_WSTRING, Py_CLEANUP_SUPPORTED, slot_function, cts, parse_dir, |
16 | 16 | PyTypeObjectPtr) |
17 | 17 | from pypy.module.cpyext.pyerrors import PyErr_BadArgument |
46 | 46 | default_encoding = lltype.malloc(rffi.CCHARP.TO, DEFAULT_ENCODING_SIZE, |
47 | 47 | flavor='raw', zero=True) |
48 | 48 | |
49 | ||
50 | 49 | WCHAR_KIND = 0 |
51 | 50 | _1BYTE_KIND = 1 |
52 | 51 | _2BYTE_KIND = 2 |
59 | 58 | 4: '_4BYTE_KIND', |
60 | 59 | } |
61 | 60 | |
62 | def PyUnicode_Check(ref): | |
61 | # Backward compatibility: in PyPy7.3.4 this function became a C macro. But | |
62 | # since we do not change the API, we need to export this function from the | |
63 | # dll/so. This requires giving the mangled name here and special casing it in | |
64 | # mangle_name from api.py | |
65 | @cts.decl("int PyPyUnicode_Check(void * obj)", error=CANNOT_FAIL) | |
66 | def PyUnicode_Check(space, ref): | |
63 | 67 | if not ref: |
64 | 68 | return False |
69 | ref = rffi.cast(PyObject, ref) | |
65 | 70 | return (widen(ref.c_ob_type.c_tp_flags) & Py_TPFLAGS_UNICODE_SUBCLASS) != 0 |
71 | ||
72 | # Backward compatibility: in PyPy7.3.4 this function became a C macro. But | |
73 | # since we do not change the API, we need to also export this function from the | |
74 | # dll/so. This requires giving the mangled name here and special casing it in | |
75 | # mangle_name from api.py | |
76 | @cts.decl("int PyPyUnicode_CheckExact(void * obj)", error=CANNOT_FAIL) | |
77 | def PyUnicode_CheckExact(space, ref): | |
78 | if not ref: | |
79 | return False | |
80 | w_obj = from_ref(space, rffi.cast(PyObject, ref)) | |
81 | w_obj_type = space.type(w_obj) | |
82 | return space.is_w(w_obj_type, space.w_unicode) | |
83 | ||
66 | 84 | |
67 | 85 | def new_empty_unicode(space, length): |
68 | 86 | """ |
446 | 464 | def PyUnicode_AsUnicodeAndSize(space, ref, psize): |
447 | 465 | """Return a read-only pointer to the Unicode object's internal Py_UNICODE |
448 | 466 | buffer, NULL if unicode is not a Unicode object.""" |
449 | if not PyUnicode_Check(ref): | |
467 | if not PyUnicode_Check(space, ref): | |
450 | 468 | raise oefmt(space.w_TypeError, "expected unicode object") |
451 | 469 | if not get_wbuffer(ref): |
452 | 470 | w_unicode = from_ref(space, rffi.cast(PyObject, ref)) |
497 | 515 | |
498 | 516 | @cts.decl("char * PyUnicode_AsUTF8AndSize(PyObject *unicode, Py_ssize_t *psize)") |
499 | 517 | def PyUnicode_AsUTF8AndSize(space, ref, psize): |
500 | if not PyUnicode_Check(ref): | |
518 | if not PyUnicode_Check(space, ref): | |
501 | 519 | PyErr_BadArgument(space) |
502 | 520 | if not get_ready(ref): |
503 | 521 | res = _PyUnicode_Ready(space, ref) |
556 | 574 | return default_encoding |
557 | 575 | |
558 | 576 | def _unicode_as_encoded_object(space, pyobj, llencoding, llerrors): |
559 | if not PyUnicode_Check(pyobj): | |
577 | if not PyUnicode_Check(space, pyobj): | |
560 | 578 | PyErr_BadArgument(space) |
561 | 579 | |
562 | 580 | encoding = errors = None |
594 | 612 | """Encode a Unicode object using Unicode-Escape and return the result as Python |
595 | 613 | string object. Error handling is "strict". Return NULL if an exception was |
596 | 614 | raised by the codec.""" |
597 | if not PyUnicode_Check(pyobj): | |
615 | if not PyUnicode_Check(space, pyobj): | |
598 | 616 | PyErr_BadArgument(space) |
599 | 617 | |
600 | 618 | w_unicode = from_ref(space, pyobj) |
885 | 903 | """Encode a Unicode object and return the result as Python |
886 | 904 | string object. Error handling is "strict". Return NULL if an |
887 | 905 | exception was raised by the codec.""" |
888 | if not PyUnicode_Check(pyobj): | |
906 | if not PyUnicode_Check(space, pyobj): | |
889 | 907 | PyErr_BadArgument(space) |
890 | 908 | w_unicode = from_ref(space, pyobj) |
891 | 909 | return unicodeobject.encode_object(space, w_unicode, encoding, "strict") |
1334 | 1352 | @cts.decl("""Py_ssize_t PyUnicode_FindChar(PyObject *str, Py_UCS4 ch, |
1335 | 1353 | Py_ssize_t start, Py_ssize_t end, int direction)""", error=-1) |
1336 | 1354 | def PyUnicode_FindChar(space, ref, ch, start, end, direction): |
1337 | if not PyUnicode_Check(ref): | |
1355 | if not PyUnicode_Check(space, ref): | |
1338 | 1356 | PyErr_BadArgument(space) |
1339 | 1357 | w_str = from_ref(space, ref) |
1340 | 1358 | ch = widen(ch) |
1351 | 1369 | |
1352 | 1370 | @cts.decl("Py_UCS4 PyUnicode_ReadChar(PyObject *unicode, Py_ssize_t index)", error=-1) |
1353 | 1371 | def PyUnicode_ReadChar(space, ref, index): |
1354 | if not PyUnicode_Check(ref): | |
1372 | if not PyUnicode_Check(space, ref): | |
1355 | 1373 | PyErr_BadArgument(space) |
1356 | 1374 | if not get_ready(ref): |
1357 | 1375 | PyErr_BadArgument(space) |
1369 | 1387 | - ref must not have a RPython object |
1370 | 1388 | - ref must not have been processed by _PyUnicode_Ready |
1371 | 1389 | """ |
1372 | if not PyUnicode_Check(ref): | |
1390 | if not PyUnicode_Check(space, ref): | |
1373 | 1391 | PyErr_BadArgument(space) |
1374 | 1392 | if index < 0 or index > get_len(ref): |
1375 | 1393 | raise oefmt(space.w_IndexError, "string index out of range") |
27 | 27 | '_fix_co_filename': 'interp_imp.fix_co_filename', |
28 | 28 | |
29 | 29 | 'source_hash': 'interp_imp.source_hash', |
30 | 'check_hash_based_pycs': 'space.newtext("default")' | |
30 | 'check_hash_based_pycs': 'space.newtext("default")', | |
31 | 31 | } |
32 | 32 | |
33 | 33 | appleveldefs = { |
644 | 644 | return res |
645 | 645 | """, []) |
646 | 646 | assert len([l for l in log.loops if l.chunks[1].bytecode_name.startswith("DescrOperation.contains")]) == 2 |
647 | ||
648 | def test_methodcall_kwargs_regression(self): | |
649 | log = self.run(""" | |
650 | class A: | |
651 | def f(self, x, y, z): | |
652 | return x + y + z | |
653 | def main(): | |
654 | a = A() | |
655 | res = 0 | |
656 | for i in range(10000): | |
657 | a.f(x=i, y=i+1, z=i*2) # ID: meth | |
658 | res += i | |
659 | """, []) | |
660 | ||
661 | loop, = log.loops_by_id('meth') | |
662 | ||
663 | assert loop.match_by_id("meth", """ | |
664 | setfield_gc(p15, i65, descr=...) | |
665 | guard_not_invalidated(descr=...) | |
666 | i68 = int_mul_ovf(i62, 2) | |
667 | guard_no_overflow(descr=...) | |
668 | p69 = force_token() | |
669 | """) | |
670 |
195 | 195 | exc = raises(TypeError, 'sys.flags.optimize = 3') |
196 | 196 | assert 'readonly' in str(exc.value) |
197 | 197 | raises(AttributeError, 'sys.flags.not_a_sys_flag = 2') |
198 | ||
198 | ||
199 | 199 | def test_sys_exit(self): |
200 | 200 | import sys |
201 | 201 | exc = raises(SystemExit, sys.exit) |
220 | 220 | def test_sys_flags_dev_mode_is_bool(self): |
221 | 221 | import sys |
222 | 222 | assert type(sys.flags.dev_mode) is bool |
223 | ||
224 | 223 | |
225 | 224 | class AppTestSysModulePortedFromCPython: |
226 | 225 | spaceconfig = { |
402 | 402 | |
403 | 403 | assert (d1 + from_copy) == (d1 + from_compressor) |
404 | 404 | |
405 | @py.test.mark.skipif(rzlib.ZLIB_VERSION in ('1.2.8', '1.2.3'), reason='does not error check') | |
405 | @py.test.mark.skipif(rzlib.ZLIB_VERSION in ('1.2.7', '1.2.8', '1.2.3'), reason='does not error check') | |
406 | 406 | def test_cannot_copy_compressor_with_stream_in_inconsistent_state(self): |
407 | 407 | if self.runappdirect: skip("can't run with -A") |
408 | 408 | compressor = self.zlib.compressobj() |
98 | 98 | |
99 | 99 | @jit.unroll_safe |
100 | 100 | def CALL_METHOD_KW(f, n_arguments, *ignored): |
101 | from pypy.objspace.std.tupleobject import W_AbstractTupleObject | |
101 | 102 | # opargs contains the arg + kwarg count, excluding the implicit 'self' |
102 | 103 | w_self = f.peekvalue_maybe_none(n_arguments + 1) |
103 | w_tup_varnames = f.popvalue() | |
104 | keywords_w = f.space.fixedview(w_tup_varnames) | |
105 | n_keywords = len(keywords_w) | |
104 | ||
105 | space = f.space | |
106 | # like in BUILD_CONST_KEY_MAP we can't use space.fixedview because then | |
107 | # the immutability of the tuple is lost | |
108 | w_tup_varnames = space.interp_w(W_AbstractTupleObject, f.popvalue()) | |
109 | n_keywords = space.len_w(w_tup_varnames) | |
110 | keywords = [None] * n_keywords | |
111 | keywords_w = [None] * n_keywords | |
112 | for i in range(n_keywords): | |
113 | keywords[i] = space.text_w(w_tup_varnames.getitem(space, i)) | |
114 | w_value = f.peekvalue(n_keywords - 1 - i) | |
115 | keywords_w[i] = w_value | |
116 | f.dropvalues(n_keywords) | |
106 | 117 | n_arguments -= n_keywords |
107 | 118 | n = n_arguments + (w_self is not None) |
108 | keywords = [f.space.text_w(w_keyword) for w_keyword in keywords_w] | |
109 | keywords_w = [None] * n_keywords | |
110 | while True: | |
111 | n_keywords -= 1 | |
112 | if n_keywords < 0: | |
113 | break | |
114 | w_value = f.popvalue() | |
115 | keywords_w[n_keywords] = w_value | |
116 | ||
117 | 119 | arguments = f.popvalues(n) # includes w_self if it is not None |
118 | 120 | if w_self is None: |
119 | 121 | f.popvalue_maybe_none() # removes w_self, which is None |
404 | 404 | argument reverse. Argument must be unwrapped.""" |
405 | 405 | self.strategy.sort(self, reverse) |
406 | 406 | |
407 | def physical_size(self): | |
408 | """ return the physical (ie overallocated size) of the underlying list. | |
409 | """ | |
410 | # exposed in __pypy__ | |
411 | return self.strategy.physical_size(self) | |
412 | ||
407 | 413 | # exposed to app-level |
408 | 414 | |
409 | 415 | @staticmethod |
551 | 557 | |
552 | 558 | def descr_setitem(self, space, w_index, w_any): |
553 | 559 | if isinstance(w_index, W_SliceObject): |
560 | # special case for l[:] = l2 | |
561 | if (space.is_w(w_index.w_start, space.w_None) and | |
562 | space.is_w(w_index.w_stop, space.w_None) and | |
563 | space.is_w(w_index.w_step, space.w_None)): | |
564 | if space.is_w(self, w_any): | |
565 | return | |
566 | # use the extend logic | |
567 | self.clear(space) | |
568 | self.extend(w_any) | |
569 | return | |
570 | ||
554 | 571 | oldsize = self.length() |
555 | 572 | start, stop, step, slicelength = w_index.indices4(space, oldsize) |
556 | 573 | if isinstance(w_any, W_ListObject): |
557 | self.setslice(start, step, slicelength, w_any) | |
574 | w_other = w_any | |
558 | 575 | else: |
559 | 576 | sequence_w = space.listview(w_any) |
560 | 577 | w_other = W_ListObject(space, sequence_w) |
561 | self.setslice(start, step, slicelength, w_other) | |
578 | self.setslice(start, step, slicelength, w_other) | |
562 | 579 | return |
563 | 580 | |
564 | 581 | idx = space.getindex_w(w_index, space.w_IndexError, "list") |
860 | 877 | def is_empty_strategy(self): |
861 | 878 | return False |
862 | 879 | |
880 | def physical_size(self, w_list): | |
881 | raise oefmt(self.space.w_ValueError, "can't get physical size of list") | |
882 | ||
863 | 883 | |
864 | 884 | class EmptyListStrategy(ListStrategy): |
865 | 885 | """EmptyListStrategy is used when a W_List withouth elements is created. |
1019 | 1039 | |
1020 | 1040 | def is_empty_strategy(self): |
1021 | 1041 | return True |
1042 | ||
1043 | def physical_size(self, w_list): | |
1044 | return 0 | |
1022 | 1045 | |
1023 | 1046 | |
1024 | 1047 | class SizeListStrategy(EmptyListStrategy): |
1516 | 1539 | i -= 1 |
1517 | 1540 | return |
1518 | 1541 | else: |
1519 | # Make a shallow copy to more easily handle the reversal case | |
1520 | w_list.reverse() | |
1542 | # other_items is items and step is < 0, therefore: | |
1543 | assert step == -1 | |
1544 | items.reverse() | |
1521 | 1545 | return |
1522 | 1546 | #other_items = list(other_items) |
1523 | 1547 | for i in range(len2): |
1585 | 1609 | |
1586 | 1610 | def reverse(self, w_list): |
1587 | 1611 | self.unerase(w_list.lstorage).reverse() |
1612 | ||
1613 | def physical_size(self, w_list): | |
1614 | from rpython.rlib.objectmodel import list_get_physical_size | |
1615 | l = self.unerase(w_list.lstorage) | |
1616 | return list_get_physical_size(l) | |
1588 | 1617 | |
1589 | 1618 | |
1590 | 1619 | class ObjectListStrategy(ListStrategy): |
1172 | 1172 | logger_copy = set(logger[:]) # prevent re-evaluation during pytest error print |
1173 | 1173 | assert (foo2, foo2_bis) in logger_copy |
1174 | 1174 | assert logger_copy.issubset({(foo1, foo2_bis), (foo2, foo2_bis), (foo3, foo2_bis)}) |
1175 | ||
1176 | def test_pickle(self): | |
1177 | d = {1: 1, 2: 2, 3: 3} | |
1178 | it = iter(d) | |
1179 | first = next(it) | |
1180 | reduced = it.__reduce__() | |
1181 | rebuild, args = reduced | |
1182 | new = rebuild(*args) | |
1183 | items = set(new) | |
1184 | assert len(items) == 2 | |
1185 | items.add(first) | |
1186 | assert items == set(d) | |
1175 | 1187 | |
1176 | 1188 | |
1177 | 1189 | class AppTestStrategies(object): |
1128 | 1128 | for i in range(count): |
1129 | 1129 | b[i:i+1] = ['y'] |
1130 | 1130 | assert b == ['y'] * count |
1131 | ||
1132 | def test_setslice_full(self): | |
1133 | l = [1, 2, 3] | |
1134 | l[::] = "abc" | |
1135 | assert l == ['a', 'b', 'c'] | |
1136 | ||
1137 | l = [1, 2, 3] | |
1138 | l[::] = [] | |
1139 | assert l == [] | |
1140 | ||
1141 | l = [1, 2, 3] | |
1142 | l[::] = l | |
1143 | assert l == [1, 2, 3] | |
1131 | 1144 | |
1132 | 1145 | def test_recursive_repr(self): |
1133 | 1146 | l = [] |
304 | 304 | |
305 | 305 | def descr_hash(self, space): |
306 | 306 | if _unroll_condition(self): |
307 | return self._descr_hash_unroll(space) | |
307 | res = self._descr_hash_unroll(space) | |
308 | 308 | else: |
309 | return self._descr_hash_jitdriver(space) | |
309 | res = self._descr_hash_jitdriver(space) | |
310 | return space.newint(res) | |
310 | 311 | |
311 | 312 | @jit.unroll_safe |
312 | 313 | def _descr_hash_unroll(self, space): |
319 | 320 | z -= 1 |
320 | 321 | mult += 82520 + z + z |
321 | 322 | x += 97531 |
322 | return space.newint(intmask(x)) | |
323 | return intmask(x) | |
323 | 324 | |
324 | 325 | def _descr_hash_jitdriver(self, space): |
325 | 326 | mult = 1000003 |
337 | 338 | mult += 82520 + z + z |
338 | 339 | i += 1 |
339 | 340 | x += 97531 |
340 | return space.newint(intmask(x)) | |
341 | return intmask(x) | |
341 | 342 | |
342 | 343 | def descr_eq(self, space, w_other): |
343 | 344 | if not isinstance(w_other, W_AbstractTupleObject): |
30 | 30 | raise ValueError(f"'{a}' not in '{b}'") |
31 | 31 | |
32 | 32 | |
33 | ||
34 | ||
35 | pypy_versions = {'7.3.3': {'python_version': ['3.7.9', '3.6.12', '2.7.18'], | |
33 | pypy_versions = { | |
34 | '7.3.4rc1': {'python_version': ['3.7.10', '2.7.18'], | |
35 | 'date': '2021-03-19', | |
36 | }, | |
37 | '7.3.3': {'python_version': ['3.7.9', '3.6.12', '2.7.18'], | |
36 | 38 | 'date': '2020-11-21', |
37 | 39 | }, |
38 | 40 | '7.3.3rc1': {'python_version': ['3.6.12'], |
50 | 52 | pypy version for that cpython""" |
51 | 53 | ret = {} |
52 | 54 | for pypy_ver, vv in v.items(): |
55 | if 'rc' in pypy_ver: | |
56 | # skip release candidates | |
57 | continue | |
53 | 58 | for pv in vv['python_version']: |
54 | 59 | # for nightlies, we rely on python_version being major.minor while |
55 | 60 | # for releases python_version is major.minor.patch |
62 | 67 | latest_pypys = create_latest_versions(pypy_versions) |
63 | 68 | |
64 | 69 | arches = ['aarch64', 'i686', 'x64', 'x86', 'darwin', 's390x'] |
65 | platforms = ['linux', 'win32', 'darwin'] | |
70 | platforms = ['linux', 'win32', 'win64', 'darwin'] | |
66 | 71 | arch_map={('aarch64', 'linux'): 'aarch64', |
67 | 72 | ('i686', 'linux'): 'linux32', |
68 | 73 | ('x64', 'linux'): 'linux64', |
69 | 74 | ('s390x', 'linux'): 's390x', |
70 | 75 | ('x86', 'win32'): 'win32', |
76 | ('x64', 'win64'): 'win64', | |
71 | 77 | ('x64', 'darwin'): 'osx64', |
72 | 78 | } |
73 | 79 | |
86 | 92 | elif d['latest_pypy'] is True: |
87 | 93 | assert_equal(latest_pypys[d['python_version']], d['pypy_version']) |
88 | 94 | else: |
89 | assert_different(latest_pypys[d['python_version']], d['pypy_version']) | |
95 | try: | |
96 | assert_different(latest_pypys[d['python_version']], d['pypy_version']) | |
97 | except KeyError: | |
98 | assert 'rc' in d['pypy_version'] | |
90 | 99 | if 'date' in d: |
91 | 100 | assert_equal(d['date'], v['date']) |
92 | 101 | for f in d['files']: |
45 | 45 | RPYTHON_BUILDERS = [ |
46 | 46 | 'rpython-linux-x86-32', |
47 | 47 | 'rpython-linux-x86-64', |
48 | 'rpython-win-x86-32' | |
49 | # 'rpython-win-x86-64' | |
48 | # 'rpython-win-x86-32' | |
49 | 'rpython-win-x86-64' | |
50 | 50 | ] |
51 | 51 | |
52 | 52 | def get_user(): |
252 | 252 | os.symlink(POSIX_EXE, 'pypy{}'.format(python_ver)) |
253 | 253 | os.symlink(POSIX_EXE, 'python') |
254 | 254 | os.symlink(POSIX_EXE, 'python{}'.format(python_ver)) |
255 | os.symlink(POSIX_EXE, 'python{}'.format(python_ver[1])) | |
255 | os.symlink(POSIX_EXE, 'python{}'.format(python_ver[0])) | |
256 | 256 | finally: |
257 | 257 | os.chdir(old_dir) |
258 | 258 | fix_permissions(pypydir) |
354 | 354 | parser.add_argument('--embedded-dependencies', '--no-embedded-dependencies', |
355 | 355 | dest='embed_dependencies', |
356 | 356 | action=NegateAction, |
357 | default=(ARCH in ('darwin', 'aarch64')), | |
357 | default=(ARCH in ('darwin', 'aarch64', 'x86_64')), | |
358 | 358 | help='whether to embed dependencies in CFFI modules ' |
359 | 359 | '(default on OS X)') |
360 | 360 | parser.add_argument('--make-portable', |
1 | 1 | |
2 | 2 | # Edit these appropriately before running this script |
3 | 3 | pmaj=3 # python main version: 2 or 3 |
4 | pmin=6 # python minor version | |
4 | pmin=7 # python minor version | |
5 | 5 | maj=7 |
6 | 6 | min=3 |
7 | rev=3 | |
8 | #rc=rc2 # set to blank for actual release | |
7 | rev=4 | |
8 | rc=rc1 # comment this line for actual release | |
9 | 9 | |
10 | 10 | function maybe_exit { |
11 | 11 | if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then |
47 | 47 | function repackage_builds { |
48 | 48 | # Download latest builds from the buildmaster, rename the top |
49 | 49 | # level directory, and repackage ready to be uploaded |
50 | actual_ver=xxxxxxxxxxxxxxx | |
51 | 50 | for plat in linux linux64 osx64 aarch64 s390x # linux-armhf-raspbian linux-armel |
52 | 51 | do |
53 | 52 | echo downloading package for $plat |
69 | 68 | fi |
70 | 69 | tar -xf pypy-c-jit-latest-$plat.tar.bz2 |
71 | 70 | rm pypy-c-jit-latest-$plat.tar.bz2 |
71 | ||
72 | # Check that this is the correct version | |
73 | actual_ver=$(grep PYPY_VERSION pypy-c-jit-*-$plat/include/patchlevel.h |cut -f3 -d' ') | |
74 | if [ $actual_ver != "\"$maj.$min.$rev\"" ] | |
75 | then | |
76 | echo xxxxxxxxxxxxxxxxxxxxxx | |
77 | echo version mismatch, expected "\"$maj.$min.$rev\"", got $actual_ver for $plat | |
78 | echo xxxxxxxxxxxxxxxxxxxxxx | |
79 | exit -1 | |
80 | rm -rf pypy-c-jit-*-$plat | |
81 | continue | |
82 | fi | |
83 | ||
84 | # Move the files into the correct directory and create the tarball | |
72 | 85 | plat_final=$plat |
73 | 86 | if [ $plat = linux ]; then |
74 | 87 | plat_final=linux32 |
75 | 88 | fi |
76 | 89 | mv pypy-c-jit-*-$plat $rel-$plat_final |
77 | # TODO: automate the platform choice or move it to the head of the file | |
78 | if [ $plat_final == linux64 ] | |
79 | then | |
80 | actual_ver=`$rel-$plat_final/bin/$exe -c "import sys; print('.'.join([str(x) for x in sys.pypy_version_info[:2]]))"` | |
81 | fi | |
82 | 90 | echo packaging $plat_final |
83 | 91 | tar --owner=root --group=root --numeric-owner -cjf $rel-$plat_final.tar.bz2 $rel-$plat_final |
84 | 92 | rm -rf $rel-$plat_final |
85 | 93 | done |
86 | if [ "$actual_ver" != "$maj.$min" ] | |
87 | then | |
88 | echo xxxxxxxxxxxxxxxxxxxxxx | |
89 | echo version mismatch, expected $maj.$min, got $actual_ver | |
90 | echo xxxxxxxxxxxxxxxxxxxxxx | |
91 | exit -1 | |
92 | rm -rf $rel-$plat_final | |
93 | continue | |
94 | fi | |
95 | plat=win32 | |
96 | if wget http://buildbot.pypy.org/nightly/$branchname/pypy-c-jit-latest-$plat.zip | |
97 | then | |
94 | # end of "for" loop | |
95 | for plat in win64 win32 | |
96 | do | |
97 | if wget -q --show-progress http://buildbot.pypy.org/nightly/$branchname/pypy-c-jit-latest-$plat.zip | |
98 | then | |
99 | echo $plat downloaded | |
100 | else | |
101 | echo $plat no download available | |
102 | continue | |
103 | fi | |
98 | 104 | unzip -q pypy-c-jit-latest-$plat.zip |
99 | 105 | rm pypy-c-jit-latest-$plat.zip |
106 | actual_ver=$(grep PYPY_VERSION pypy-c-jit-*-$plat/include/patchlevel.h |cut -f3 -d' ') | |
107 | if [ $actual_ver != "\"$maj.$min.$rev\"" ] | |
108 | then | |
109 | echo xxxxxxxxxxxxxxxxxxxxxx | |
110 | echo version mismatch, expected "\"$maj.$min.$rev\"", got $actual_ver for $plat | |
111 | echo xxxxxxxxxxxxxxxxxxxxxx | |
112 | rm -rf pypy-c-jit-*-$plat | |
113 | continue | |
114 | fi | |
100 | 115 | mv pypy-c-jit-*-$plat $rel-$plat |
101 | 116 | zip -rq $rel-$plat.zip $rel-$plat |
102 | 117 | rm -rf $rel-$plat |
103 | else | |
104 | echo no download for $plat | |
105 | fi | |
118 | done | |
119 | # end of "for" loop | |
106 | 120 | } |
107 | 121 | |
108 | 122 | function repackage_source { |
0 | 0 | [ |
1 | { | |
2 | "pypy_version": "7.3.4rc1", | |
3 | "python_version": "3.7.10", | |
4 | "stable": false, | |
5 | "latest_pypy": false, | |
6 | "date": "2021-03-19", | |
7 | "files": [ | |
8 | { | |
9 | "filename": "pypy3.7-v7.3.4rc1-aarch64.tar.bz2", | |
10 | "arch": "aarch64", | |
11 | "platform": "linux", | |
12 | "download_url": "https://downloads.python.org/pypy/pypy3.7-v7.3.4rc1-aarch64.tar.bz2" | |
13 | }, | |
14 | { | |
15 | "filename": "pypy3.7-v7.3.4rc1-linux32.tar.bz2", | |
16 | "arch": "i686", | |
17 | "platform": "linux", | |
18 | "download_url": "https://downloads.python.org/pypy/pypy3.7-v7.3.4rc1-linux32.tar.bz2" | |
19 | }, | |
20 | { | |
21 | "filename": "pypy3.7-v7.3.4rc1-linux64.tar.bz2", | |
22 | "arch": "x64", | |
23 | "platform": "linux", | |
24 | "download_url": "https://downloads.python.org/pypy/pypy3.7-v7.3.4rc1-linux64.tar.bz2" | |
25 | }, | |
26 | { | |
27 | "filename": "pypy3.7-v7.3.4rc1-osx64.tar.bz2", | |
28 | "arch": "x64", | |
29 | "platform": "darwin", | |
30 | "download_url": "https://downloads.python.org/pypy/pypy3.7-v7.3.4rc1-osx64.tar.bz2" | |
31 | }, | |
32 | { | |
33 | "filename": "pypy3.7-v7.3.4rc1-win64.zip", | |
34 | "arch": "x64", | |
35 | "platform": "win64", | |
36 | "download_url": "https://downloads.python.org/pypy/pypy3.7-v7.3.4rc1-win64.zip" | |
37 | } | |
38 | ] | |
39 | }, | |
40 | { | |
41 | "pypy_version": "7.3.4rc1", | |
42 | "python_version": "2.7.18", | |
43 | "stable": false, | |
44 | "latest_pypy": false, | |
45 | "date": "2021-03-19", | |
46 | "files": [ | |
47 | { | |
48 | "filename": "pypy2.7-v7.3.4rc1-aarch64.tar.bz2", | |
49 | "arch": "aarch64", | |
50 | "platform": "linux", | |
51 | "download_url": "https://downloads.python.org/pypy/pypy2.7-v7.3.4rc1-aarch64.tar.bz2" | |
52 | }, | |
53 | { | |
54 | "filename": "pypy2.7-v7.3.4rc1-linux32.tar.bz2", | |
55 | "arch": "i686", | |
56 | "platform": "linux", | |
57 | "download_url": "https://downloads.python.org/pypy/pypy2.7-v7.3.4rc1-linux32.tar.bz2" | |
58 | }, | |
59 | { | |
60 | "filename": "pypy2.7-v7.3.4rc1-linux64.tar.bz2", | |
61 | "arch": "x64", | |
62 | "platform": "linux", | |
63 | "download_url": "https://downloads.python.org/pypy/pypy2.7-v7.3.4rc1-linux64.tar.bz2" | |
64 | }, | |
65 | { | |
66 | "filename": "pypy2.7-v7.3.4rc1-osx64.tar.bz2", | |
67 | "arch": "x64", | |
68 | "platform": "darwin", | |
69 | "download_url": "https://downloads.python.org/pypy/pypy2.7-v7.3.4rc1-osx64.tar.bz2" | |
70 | }, | |
71 | { | |
72 | "filename": "pypy2.7-v7.3.4rc1-win64.zip", | |
73 | "arch": "x64", | |
74 | "platform": "win64", | |
75 | "download_url": "https://downloads.python.org/pypy/pypy2.7-v7.3.4rc1-win64.zip" | |
76 | } | |
77 | ] | |
78 | }, | |
1 | 79 | { |
2 | 80 | "pypy_version": "7.3.3", |
3 | 81 | "python_version": "3.6.12", |
703 | 703 | return self._optimize_oois_ooisnot(op, True, False) |
704 | 704 | |
705 | 705 | def optimize_INSTANCE_PTR_EQ(self, op): |
706 | arg0 = get_box_replacement(op.getarg(0)) | |
707 | arg1 = get_box_replacement(op.getarg(1)) | |
708 | self.pure_from_args(rop.INSTANCE_PTR_EQ, [arg1, arg0], op) | |
706 | 709 | return self._optimize_oois_ooisnot(op, False, True) |
707 | 710 | |
708 | 711 | def optimize_INSTANCE_PTR_NE(self, op): |
712 | arg0 = get_box_replacement(op.getarg(0)) | |
713 | arg1 = get_box_replacement(op.getarg(1)) | |
714 | self.pure_from_args(rop.INSTANCE_PTR_NE, [arg1, arg0], op) | |
709 | 715 | return self._optimize_oois_ooisnot(op, True, True) |
710 | 716 | |
711 | 717 | def optimize_CALL_N(self, op): |
404 | 404 | [p0] |
405 | 405 | guard_class(p0, ConstClass(node_vtable)) [] |
406 | 406 | jump(p0) |
407 | """ | |
408 | self.optimize_loop(ops, expected) | |
409 | ||
410 | def test_instance_ptr_eq_is_symmetric(self): | |
411 | ops = """ | |
412 | [p0, p1] | |
413 | i0 = instance_ptr_eq(p0, p1) | |
414 | guard_false(i0) [] | |
415 | i1 = instance_ptr_eq(p1, p0) | |
416 | guard_false(i1) [] | |
417 | jump(p0, p1) | |
418 | """ | |
419 | expected = """ | |
420 | [p0, p1] | |
421 | i0 = instance_ptr_eq(p0, p1) | |
422 | guard_false(i0) [] | |
423 | jump(p0, p1) | |
424 | """ | |
425 | self.optimize_loop(ops, expected) | |
426 | ||
427 | ops = """ | |
428 | [p0, p1] | |
429 | i0 = instance_ptr_ne(p0, p1) | |
430 | guard_true(i0) [] | |
431 | i1 = instance_ptr_ne(p1, p0) | |
432 | guard_true(i1) [] | |
433 | jump(p0, p1) | |
434 | """ | |
435 | expected = """ | |
436 | [p0, p1] | |
437 | i0 = instance_ptr_ne(p0, p1) | |
438 | guard_true(i0) [] | |
439 | jump(p0, p1) | |
407 | 440 | """ |
408 | 441 | self.optimize_loop(ops, expected) |
409 | 442 |
488 | 488 | hop.exception_is_here() |
489 | 489 | hop.gendirectcall(r_list.LIST._ll_resize_hint, v_list, v_sizehint) |
490 | 490 | |
491 | def list_get_physical_size(l): | |
492 | """ try to get the physical size of an overallocated RPython list. will | |
493 | return the regular length untranslated. """ | |
494 | return len(l) | |
495 | ||
496 | def ll_physical_size(l): | |
497 | return len(l.items) | |
498 | ||
499 | class Entry(ExtRegistryEntry): | |
500 | _about_ = list_get_physical_size | |
501 | ||
502 | def compute_result_annotation(self, s_l): | |
503 | from rpython.annotator import model as annmodel | |
504 | if annmodel.s_None.contains(s_l): | |
505 | pass # first argument is only None so far, but we | |
506 | # expect a generalization later | |
507 | elif not isinstance(s_l, annmodel.SomeList): | |
508 | raise annmodel.AnnotatorError("First argument must be a list") | |
509 | return annmodel.SomeInteger(nonneg=True) | |
510 | ||
511 | def specialize_call(self, hop): | |
512 | from rpython.rtyper.lltypesystem.rlist import FixedSizeListRepr, ListRepr | |
513 | v_list, = hop.inputargs(*hop.args_r) | |
514 | if isinstance(hop.args_r[0], ListRepr): | |
515 | ll_func = ll_physical_size | |
516 | else: | |
517 | ll_func = v_list.concretetype.TO.ll_length | |
518 | hop.exception_cannot_occur() | |
519 | return hop.gendirectcall(ll_func, v_list) | |
520 | ||
521 | ||
491 | 522 | # ____________________________________________________________ |
492 | 523 | # |
493 | 524 | # id-like functions. The idea is that calling hash() or id() is not |
10 | 10 | # we print based on indices in 'args'. We first print |
11 | 11 | # 'ctx.pattern' from the arg number debugprint[0]. |
12 | 12 | pattern = args[debugprint[0]] |
13 | s = str(pattern) | |
13 | s = str(pattern.pattern) | |
14 | 14 | if len(s) > 120: |
15 | 15 | s = s[:110] + '...' |
16 | 16 | if len(debugprint) > 1: |
7 | 7 | iterkeys_with_hash, iteritems_with_hash, contains_with_hash, |
8 | 8 | setitem_with_hash, getitem_with_hash, delitem_with_hash, import_from_mixin, |
9 | 9 | fetch_translated_config, try_inline, delitem_if_value_is, move_to_end, |
10 | never_allocate, dont_inline) | |
10 | never_allocate, dont_inline, list_get_physical_size) | |
11 | 11 | from rpython.translator.translator import TranslationContext, graphof |
12 | 12 | from rpython.rtyper.test.tool import BaseRtypingTest |
13 | 13 | from rpython.rtyper.test.test_llinterp import interpret |
589 | 589 | r = interpret(f, [29]) |
590 | 590 | assert r == 1 |
591 | 591 | |
592 | def test_list_get_physical_size(): | |
593 | def f(z): | |
594 | l = [z, z + 1] | |
595 | if z: | |
596 | l.append(z) | |
597 | return list_get_physical_size(l) | |
598 | ||
599 | r = interpret(f, [29]) | |
600 | assert r == 6 | |
601 | ||
602 | # now with fixed-sized list | |
603 | def f(z): | |
604 | l = [z, z + 1] | |
605 | return list_get_physical_size(l) | |
606 | ||
607 | r = interpret(f, [29]) | |
608 | assert r == 2 | |
609 | ||
592 | 610 | def test_iterkeys_with_hash(): |
593 | 611 | def f(i): |
594 | 612 | d = {i + .0: 5, i + .5: 6} |