Spaces:
Runtime error
Runtime error
Upload 9572 files
Browse filesThis view is limited to 50 files because it contains too many changes.
See raw diff
- .gitattributes +12 -0
- venv/Lib/site-packages/Cython-0.29.36.dist-info/COPYING.txt +19 -0
- venv/Lib/site-packages/Cython-0.29.36.dist-info/INSTALLER +1 -0
- venv/Lib/site-packages/Cython-0.29.36.dist-info/LICENSE.txt +176 -0
- venv/Lib/site-packages/Cython-0.29.36.dist-info/METADATA +63 -0
- venv/Lib/site-packages/Cython-0.29.36.dist-info/RECORD +424 -0
- venv/Lib/site-packages/Cython-0.29.36.dist-info/WHEEL +6 -0
- venv/Lib/site-packages/Cython-0.29.36.dist-info/entry_points.txt +4 -0
- venv/Lib/site-packages/Cython-0.29.36.dist-info/top_level.txt +3 -0
- venv/Lib/site-packages/Cython/Build/BuildExecutable.py +142 -0
- venv/Lib/site-packages/Cython/Build/Cythonize.py +229 -0
- venv/Lib/site-packages/Cython/Build/Dependencies.py +1296 -0
- venv/Lib/site-packages/Cython/Build/Distutils.py +1 -0
- venv/Lib/site-packages/Cython/Build/Inline.py +377 -0
- venv/Lib/site-packages/Cython/Build/IpythonMagic.py +564 -0
- venv/Lib/site-packages/Cython/Build/Tests/TestCyCache.py +106 -0
- venv/Lib/site-packages/Cython/Build/Tests/TestInline.py +96 -0
- venv/Lib/site-packages/Cython/Build/Tests/TestIpythonMagic.py +205 -0
- venv/Lib/site-packages/Cython/Build/Tests/TestStripLiterals.py +57 -0
- venv/Lib/site-packages/Cython/Build/Tests/__init__.py +1 -0
- venv/Lib/site-packages/Cython/Build/Tests/__pycache__/TestCyCache.cpython-311.pyc +0 -0
- venv/Lib/site-packages/Cython/Build/Tests/__pycache__/TestInline.cpython-311.pyc +0 -0
- venv/Lib/site-packages/Cython/Build/Tests/__pycache__/TestIpythonMagic.cpython-311.pyc +0 -0
- venv/Lib/site-packages/Cython/Build/Tests/__pycache__/TestStripLiterals.cpython-311.pyc +0 -0
- venv/Lib/site-packages/Cython/Build/Tests/__pycache__/__init__.cpython-311.pyc +0 -0
- venv/Lib/site-packages/Cython/Build/__init__.py +2 -0
- venv/Lib/site-packages/Cython/Build/__pycache__/BuildExecutable.cpython-311.pyc +0 -0
- venv/Lib/site-packages/Cython/Build/__pycache__/Cythonize.cpython-311.pyc +0 -0
- venv/Lib/site-packages/Cython/Build/__pycache__/Dependencies.cpython-311.pyc +0 -0
- venv/Lib/site-packages/Cython/Build/__pycache__/Distutils.cpython-311.pyc +0 -0
- venv/Lib/site-packages/Cython/Build/__pycache__/Inline.cpython-311.pyc +0 -0
- venv/Lib/site-packages/Cython/Build/__pycache__/IpythonMagic.cpython-311.pyc +0 -0
- venv/Lib/site-packages/Cython/Build/__pycache__/__init__.cpython-311.pyc +0 -0
- venv/Lib/site-packages/Cython/CodeWriter.py +819 -0
- venv/Lib/site-packages/Cython/Compiler/AnalysedTreeTransforms.py +99 -0
- venv/Lib/site-packages/Cython/Compiler/Annotate.py +317 -0
- venv/Lib/site-packages/Cython/Compiler/AutoDocTransforms.py +214 -0
- venv/Lib/site-packages/Cython/Compiler/Buffer.py +740 -0
- venv/Lib/site-packages/Cython/Compiler/Builtin.py +445 -0
- venv/Lib/site-packages/Cython/Compiler/CmdLine.py +240 -0
- venv/Lib/site-packages/Cython/Compiler/Code.pxd +124 -0
- venv/Lib/site-packages/Cython/Compiler/Code.py +2597 -0
- venv/Lib/site-packages/Cython/Compiler/CodeGeneration.py +35 -0
- venv/Lib/site-packages/Cython/Compiler/CythonScope.py +164 -0
- venv/Lib/site-packages/Cython/Compiler/DebugFlags.py +21 -0
- venv/Lib/site-packages/Cython/Compiler/Errors.py +265 -0
- venv/Lib/site-packages/Cython/Compiler/ExprNodes.py +0 -0
- venv/Lib/site-packages/Cython/Compiler/FlowControl.pxd +111 -0
- venv/Lib/site-packages/Cython/Compiler/FlowControl.py +1325 -0
- venv/Lib/site-packages/Cython/Compiler/FusedNode.py +901 -0
.gitattributes
CHANGED
@@ -33,3 +33,15 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
|
33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
36 |
+
venv/Lib/site-packages/altair/vegalite/v5/schema/__pycache__/core.cpython-311.pyc filter=lfs diff=lfs merge=lfs -text
|
37 |
+
venv/Lib/site-packages/fitz/_fitz.cp311-win_amd64.pyd filter=lfs diff=lfs merge=lfs -text
|
38 |
+
venv/Lib/site-packages/gradio/templates/frontend/assets/index-0eddd93f.js.map filter=lfs diff=lfs merge=lfs -text
|
39 |
+
venv/Lib/site-packages/numpy/.libs/libopenblas64__v0.3.23-gcc_10_3_0.dll filter=lfs diff=lfs merge=lfs -text
|
40 |
+
venv/Lib/site-packages/numpy/core/_multiarray_umath.cp311-win_amd64.pyd filter=lfs diff=lfs merge=lfs -text
|
41 |
+
venv/Lib/site-packages/numpy/core/_simd.cp311-win_amd64.pyd filter=lfs diff=lfs merge=lfs -text
|
42 |
+
venv/Lib/site-packages/pandas/_libs/algos.cp311-win_amd64.pyd filter=lfs diff=lfs merge=lfs -text
|
43 |
+
venv/Lib/site-packages/pandas/_libs/groupby.cp311-win_amd64.pyd filter=lfs diff=lfs merge=lfs -text
|
44 |
+
venv/Lib/site-packages/pandas/_libs/hashtable.cp311-win_amd64.pyd filter=lfs diff=lfs merge=lfs -text
|
45 |
+
venv/Lib/site-packages/pandas/_libs/join.cp311-win_amd64.pyd filter=lfs diff=lfs merge=lfs -text
|
46 |
+
venv/Lib/site-packages/PIL/_imaging.cp311-win_amd64.pyd filter=lfs diff=lfs merge=lfs -text
|
47 |
+
venv/Lib/site-packages/PIL/_imagingft.cp311-win_amd64.pyd filter=lfs diff=lfs merge=lfs -text
|
venv/Lib/site-packages/Cython-0.29.36.dist-info/COPYING.txt
ADDED
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
The original Pyrex code as of 2006-04 is licensed under the following
|
2 |
+
license: "Copyright stuff: Pyrex is free of restrictions. You may use,
|
3 |
+
redistribute, modify and distribute modified versions."
|
4 |
+
|
5 |
+
------------------
|
6 |
+
|
7 |
+
Cython, which derives from Pyrex, is licensed under the Apache 2.0
|
8 |
+
Software License. More precisely, all modifications and new code
|
9 |
+
made to go from Pyrex to Cython are so licensed.
|
10 |
+
|
11 |
+
See LICENSE.txt for more details.
|
12 |
+
|
13 |
+
------------------
|
14 |
+
|
15 |
+
The output of a Cython compilation is NOT considered a derivative
|
16 |
+
work of Cython. Specifically, though the compilation process may
|
17 |
+
embed snippets of varying lengths into the final output, these
|
18 |
+
snippets, as embedded in the output, do not encumber the resulting
|
19 |
+
output with any license restrictions.
|
venv/Lib/site-packages/Cython-0.29.36.dist-info/INSTALLER
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
pip
|
venv/Lib/site-packages/Cython-0.29.36.dist-info/LICENSE.txt
ADDED
@@ -0,0 +1,176 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
Apache License
|
2 |
+
Version 2.0, January 2004
|
3 |
+
http://www.apache.org/licenses/
|
4 |
+
|
5 |
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
6 |
+
|
7 |
+
1. Definitions.
|
8 |
+
|
9 |
+
"License" shall mean the terms and conditions for use, reproduction,
|
10 |
+
and distribution as defined by Sections 1 through 9 of this document.
|
11 |
+
|
12 |
+
"Licensor" shall mean the copyright owner or entity authorized by
|
13 |
+
the copyright owner that is granting the License.
|
14 |
+
|
15 |
+
"Legal Entity" shall mean the union of the acting entity and all
|
16 |
+
other entities that control, are controlled by, or are under common
|
17 |
+
control with that entity. For the purposes of this definition,
|
18 |
+
"control" means (i) the power, direct or indirect, to cause the
|
19 |
+
direction or management of such entity, whether by contract or
|
20 |
+
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
21 |
+
outstanding shares, or (iii) beneficial ownership of such entity.
|
22 |
+
|
23 |
+
"You" (or "Your") shall mean an individual or Legal Entity
|
24 |
+
exercising permissions granted by this License.
|
25 |
+
|
26 |
+
"Source" form shall mean the preferred form for making modifications,
|
27 |
+
including but not limited to software source code, documentation
|
28 |
+
source, and configuration files.
|
29 |
+
|
30 |
+
"Object" form shall mean any form resulting from mechanical
|
31 |
+
transformation or translation of a Source form, including but
|
32 |
+
not limited to compiled object code, generated documentation,
|
33 |
+
and conversions to other media types.
|
34 |
+
|
35 |
+
"Work" shall mean the work of authorship, whether in Source or
|
36 |
+
Object form, made available under the License, as indicated by a
|
37 |
+
copyright notice that is included in or attached to the work
|
38 |
+
(an example is provided in the Appendix below).
|
39 |
+
|
40 |
+
"Derivative Works" shall mean any work, whether in Source or Object
|
41 |
+
form, that is based on (or derived from) the Work and for which the
|
42 |
+
editorial revisions, annotations, elaborations, or other modifications
|
43 |
+
represent, as a whole, an original work of authorship. For the purposes
|
44 |
+
of this License, Derivative Works shall not include works that remain
|
45 |
+
separable from, or merely link (or bind by name) to the interfaces of,
|
46 |
+
the Work and Derivative Works thereof.
|
47 |
+
|
48 |
+
"Contribution" shall mean any work of authorship, including
|
49 |
+
the original version of the Work and any modifications or additions
|
50 |
+
to that Work or Derivative Works thereof, that is intentionally
|
51 |
+
submitted to Licensor for inclusion in the Work by the copyright owner
|
52 |
+
or by an individual or Legal Entity authorized to submit on behalf of
|
53 |
+
the copyright owner. For the purposes of this definition, "submitted"
|
54 |
+
means any form of electronic, verbal, or written communication sent
|
55 |
+
to the Licensor or its representatives, including but not limited to
|
56 |
+
communication on electronic mailing lists, source code control systems,
|
57 |
+
and issue tracking systems that are managed by, or on behalf of, the
|
58 |
+
Licensor for the purpose of discussing and improving the Work, but
|
59 |
+
excluding communication that is conspicuously marked or otherwise
|
60 |
+
designated in writing by the copyright owner as "Not a Contribution."
|
61 |
+
|
62 |
+
"Contributor" shall mean Licensor and any individual or Legal Entity
|
63 |
+
on behalf of whom a Contribution has been received by Licensor and
|
64 |
+
subsequently incorporated within the Work.
|
65 |
+
|
66 |
+
2. Grant of Copyright License. Subject to the terms and conditions of
|
67 |
+
this License, each Contributor hereby grants to You a perpetual,
|
68 |
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
69 |
+
copyright license to reproduce, prepare Derivative Works of,
|
70 |
+
publicly display, publicly perform, sublicense, and distribute the
|
71 |
+
Work and such Derivative Works in Source or Object form.
|
72 |
+
|
73 |
+
3. Grant of Patent License. Subject to the terms and conditions of
|
74 |
+
this License, each Contributor hereby grants to You a perpetual,
|
75 |
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
76 |
+
(except as stated in this section) patent license to make, have made,
|
77 |
+
use, offer to sell, sell, import, and otherwise transfer the Work,
|
78 |
+
where such license applies only to those patent claims licensable
|
79 |
+
by such Contributor that are necessarily infringed by their
|
80 |
+
Contribution(s) alone or by combination of their Contribution(s)
|
81 |
+
with the Work to which such Contribution(s) was submitted. If You
|
82 |
+
institute patent litigation against any entity (including a
|
83 |
+
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
84 |
+
or a Contribution incorporated within the Work constitutes direct
|
85 |
+
or contributory patent infringement, then any patent licenses
|
86 |
+
granted to You under this License for that Work shall terminate
|
87 |
+
as of the date such litigation is filed.
|
88 |
+
|
89 |
+
4. Redistribution. You may reproduce and distribute copies of the
|
90 |
+
Work or Derivative Works thereof in any medium, with or without
|
91 |
+
modifications, and in Source or Object form, provided that You
|
92 |
+
meet the following conditions:
|
93 |
+
|
94 |
+
(a) You must give any other recipients of the Work or
|
95 |
+
Derivative Works a copy of this License; and
|
96 |
+
|
97 |
+
(b) You must cause any modified files to carry prominent notices
|
98 |
+
stating that You changed the files; and
|
99 |
+
|
100 |
+
(c) You must retain, in the Source form of any Derivative Works
|
101 |
+
that You distribute, all copyright, patent, trademark, and
|
102 |
+
attribution notices from the Source form of the Work,
|
103 |
+
excluding those notices that do not pertain to any part of
|
104 |
+
the Derivative Works; and
|
105 |
+
|
106 |
+
(d) If the Work includes a "NOTICE" text file as part of its
|
107 |
+
distribution, then any Derivative Works that You distribute must
|
108 |
+
include a readable copy of the attribution notices contained
|
109 |
+
within such NOTICE file, excluding those notices that do not
|
110 |
+
pertain to any part of the Derivative Works, in at least one
|
111 |
+
of the following places: within a NOTICE text file distributed
|
112 |
+
as part of the Derivative Works; within the Source form or
|
113 |
+
documentation, if provided along with the Derivative Works; or,
|
114 |
+
within a display generated by the Derivative Works, if and
|
115 |
+
wherever such third-party notices normally appear. The contents
|
116 |
+
of the NOTICE file are for informational purposes only and
|
117 |
+
do not modify the License. You may add Your own attribution
|
118 |
+
notices within Derivative Works that You distribute, alongside
|
119 |
+
or as an addendum to the NOTICE text from the Work, provided
|
120 |
+
that such additional attribution notices cannot be construed
|
121 |
+
as modifying the License.
|
122 |
+
|
123 |
+
You may add Your own copyright statement to Your modifications and
|
124 |
+
may provide additional or different license terms and conditions
|
125 |
+
for use, reproduction, or distribution of Your modifications, or
|
126 |
+
for any such Derivative Works as a whole, provided Your use,
|
127 |
+
reproduction, and distribution of the Work otherwise complies with
|
128 |
+
the conditions stated in this License.
|
129 |
+
|
130 |
+
5. Submission of Contributions. Unless You explicitly state otherwise,
|
131 |
+
any Contribution intentionally submitted for inclusion in the Work
|
132 |
+
by You to the Licensor shall be under the terms and conditions of
|
133 |
+
this License, without any additional terms or conditions.
|
134 |
+
Notwithstanding the above, nothing herein shall supersede or modify
|
135 |
+
the terms of any separate license agreement you may have executed
|
136 |
+
with Licensor regarding such Contributions.
|
137 |
+
|
138 |
+
6. Trademarks. This License does not grant permission to use the trade
|
139 |
+
names, trademarks, service marks, or product names of the Licensor,
|
140 |
+
except as required for reasonable and customary use in describing the
|
141 |
+
origin of the Work and reproducing the content of the NOTICE file.
|
142 |
+
|
143 |
+
7. Disclaimer of Warranty. Unless required by applicable law or
|
144 |
+
agreed to in writing, Licensor provides the Work (and each
|
145 |
+
Contributor provides its Contributions) on an "AS IS" BASIS,
|
146 |
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
147 |
+
implied, including, without limitation, any warranties or conditions
|
148 |
+
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
149 |
+
PARTICULAR PURPOSE. You are solely responsible for determining the
|
150 |
+
appropriateness of using or redistributing the Work and assume any
|
151 |
+
risks associated with Your exercise of permissions under this License.
|
152 |
+
|
153 |
+
8. Limitation of Liability. In no event and under no legal theory,
|
154 |
+
whether in tort (including negligence), contract, or otherwise,
|
155 |
+
unless required by applicable law (such as deliberate and grossly
|
156 |
+
negligent acts) or agreed to in writing, shall any Contributor be
|
157 |
+
liable to You for damages, including any direct, indirect, special,
|
158 |
+
incidental, or consequential damages of any character arising as a
|
159 |
+
result of this License or out of the use or inability to use the
|
160 |
+
Work (including but not limited to damages for loss of goodwill,
|
161 |
+
work stoppage, computer failure or malfunction, or any and all
|
162 |
+
other commercial damages or losses), even if such Contributor
|
163 |
+
has been advised of the possibility of such damages.
|
164 |
+
|
165 |
+
9. Accepting Warranty or Additional Liability. While redistributing
|
166 |
+
the Work or Derivative Works thereof, You may choose to offer,
|
167 |
+
and charge a fee for, acceptance of support, warranty, indemnity,
|
168 |
+
or other liability obligations and/or rights consistent with this
|
169 |
+
License. However, in accepting such obligations, You may act only
|
170 |
+
on Your own behalf and on Your sole responsibility, not on behalf
|
171 |
+
of any other Contributor, and only if You agree to indemnify,
|
172 |
+
defend, and hold each Contributor harmless for any liability
|
173 |
+
incurred by, or claims asserted against, such Contributor by reason
|
174 |
+
of your accepting any such warranty or additional liability.
|
175 |
+
|
176 |
+
END OF TERMS AND CONDITIONS
|
venv/Lib/site-packages/Cython-0.29.36.dist-info/METADATA
ADDED
@@ -0,0 +1,63 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
Metadata-Version: 2.1
|
2 |
+
Name: Cython
|
3 |
+
Version: 0.29.36
|
4 |
+
Summary: The Cython compiler for writing C extensions for the Python language.
|
5 |
+
Home-page: http://cython.org/
|
6 |
+
Author: Robert Bradshaw, Stefan Behnel, Dag Seljebotn, Greg Ewing, et al.
|
7 |
+
Author-email: cython-devel@python.org
|
8 |
+
License: Apache
|
9 |
+
Project-URL: Documentation, https://cython.readthedocs.io/
|
10 |
+
Project-URL: Donate, https://cython.readthedocs.io/en/latest/src/donating.html
|
11 |
+
Project-URL: Source Code, https://github.com/cython/cython
|
12 |
+
Project-URL: Bug Tracker, https://github.com/cython/cython/issues
|
13 |
+
Project-URL: User Group, https://groups.google.com/g/cython-users
|
14 |
+
Classifier: Development Status :: 5 - Production/Stable
|
15 |
+
Classifier: Intended Audience :: Developers
|
16 |
+
Classifier: License :: OSI Approved :: Apache Software License
|
17 |
+
Classifier: Operating System :: OS Independent
|
18 |
+
Classifier: Programming Language :: Python
|
19 |
+
Classifier: Programming Language :: Python :: 2
|
20 |
+
Classifier: Programming Language :: Python :: 2.6
|
21 |
+
Classifier: Programming Language :: Python :: 2.7
|
22 |
+
Classifier: Programming Language :: Python :: 3
|
23 |
+
Classifier: Programming Language :: Python :: 3.4
|
24 |
+
Classifier: Programming Language :: Python :: 3.5
|
25 |
+
Classifier: Programming Language :: Python :: 3.6
|
26 |
+
Classifier: Programming Language :: Python :: 3.7
|
27 |
+
Classifier: Programming Language :: Python :: 3.8
|
28 |
+
Classifier: Programming Language :: Python :: 3.9
|
29 |
+
Classifier: Programming Language :: Python :: 3.10
|
30 |
+
Classifier: Programming Language :: Python :: 3.11
|
31 |
+
Classifier: Programming Language :: Python :: Implementation :: CPython
|
32 |
+
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
33 |
+
Classifier: Programming Language :: C
|
34 |
+
Classifier: Programming Language :: Cython
|
35 |
+
Classifier: Topic :: Software Development :: Code Generators
|
36 |
+
Classifier: Topic :: Software Development :: Compilers
|
37 |
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
38 |
+
Requires-Python: >=2.6, !=3.0.*, !=3.1.*, !=3.2.*
|
39 |
+
License-File: LICENSE.txt
|
40 |
+
License-File: COPYING.txt
|
41 |
+
|
42 |
+
The Cython language makes writing C extensions for the Python language as
|
43 |
+
easy as Python itself. Cython is a source code translator based on Pyrex_,
|
44 |
+
but supports more cutting edge functionality and optimizations.
|
45 |
+
|
46 |
+
The Cython language is a superset of the Python language (almost all Python
|
47 |
+
code is also valid Cython code), but Cython additionally supports optional
|
48 |
+
static typing to natively call C functions, operate with C++ classes and
|
49 |
+
declare fast C types on variables and class attributes. This allows the
|
50 |
+
compiler to generate very efficient C code from Cython code.
|
51 |
+
|
52 |
+
This makes Cython the ideal language for writing glue code for external
|
53 |
+
C/C++ libraries, and for fast C modules that speed up the execution of
|
54 |
+
Python code.
|
55 |
+
|
56 |
+
Note that for one-time builds, e.g. for CI/testing, on platforms that are not
|
57 |
+
covered by one of the wheel packages provided on PyPI *and* the pure Python wheel
|
58 |
+
that we provide is not used, it is substantially faster than a full source build
|
59 |
+
to install an uncompiled (slower) version of Cython with::
|
60 |
+
|
61 |
+
pip install Cython --install-option="--no-cython-compile"
|
62 |
+
|
63 |
+
.. _Pyrex: http://www.cosc.canterbury.ac.nz/greg.ewing/python/Pyrex/
|
venv/Lib/site-packages/Cython-0.29.36.dist-info/RECORD
ADDED
@@ -0,0 +1,424 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
../../Scripts/cygdb.exe,sha256=TtvCgNdaCjR_8FEK2YfdTeMPizjaD1vpyRpzxOrYbSE,108425
|
2 |
+
../../Scripts/cython.exe,sha256=hCVmdOApuN8hjUnpq3A1GpBqfr0CBtc9yymfhU9fPj0,108446
|
3 |
+
../../Scripts/cythonize.exe,sha256=Y9377oZV9hSTY7x5874VV5x53dk4tq00d3TIhqFebZE,108426
|
4 |
+
Cython-0.29.36.dist-info/COPYING.txt,sha256=4escSahQjoFz2sMBV-SmQ5pErYhGGUdGxCT7w_wrldc,756
|
5 |
+
Cython-0.29.36.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
|
6 |
+
Cython-0.29.36.dist-info/LICENSE.txt,sha256=psuoW8kuDP96RQsdhzwOqi6fyWv0ct8CR6Jr7He_P_k,10173
|
7 |
+
Cython-0.29.36.dist-info/METADATA,sha256=8M6LQI2NwyfVWTbrHtzm632MI8Q3CDEvvCz0dg-6abg,3147
|
8 |
+
Cython-0.29.36.dist-info/RECORD,,
|
9 |
+
Cython-0.29.36.dist-info/WHEEL,sha256=a-zpFRIJzOq5QfuhBzbhiA1eHTzNCJn8OdRvhdNX0Rk,110
|
10 |
+
Cython-0.29.36.dist-info/entry_points.txt,sha256=VU8NX8gnQyFbyqiWMzfh9BHvYMuoQRS3Nbm3kKcKQeY,139
|
11 |
+
Cython-0.29.36.dist-info/top_level.txt,sha256=jLV8tZV98iCbIfiJR4DVzTX5Ru1Y_pYMZ59wkMCe6SY,24
|
12 |
+
Cython/Build/BuildExecutable.py,sha256=9wjcOncQpbCT_Pu2Ljj5jufFLSY6T_oHOFt0uXYTdRk,4318
|
13 |
+
Cython/Build/Cythonize.py,sha256=OBSutgd93PXiRi5_6GRuhpfMZehw9YOfRgt1mxi6QLk,8359
|
14 |
+
Cython/Build/Dependencies.py,sha256=Ggsf_mtY-OjoOj1mVJtBkjUfjoTeUMAF9EkhTWgI_h0,49734
|
15 |
+
Cython/Build/Distutils.py,sha256=iO5tPX84Kc-ZWMocfuQbl_PqyC9HGGIRS-NiKI60-ZE,49
|
16 |
+
Cython/Build/Inline.py,sha256=3dSsczyUHASl8jzA9EOqVxLs92RumvcZfM8AlKFOtu4,13470
|
17 |
+
Cython/Build/IpythonMagic.py,sha256=0jwYS3BhztddJMDMMsxs8-fcL7U5EOaMXJJw6fnlKrc,21121
|
18 |
+
Cython/Build/Tests/TestCyCache.py,sha256=olOvphv4q1CLsNzMAhgmXnL77zhGGQKuKbYs_iSFFvA,4151
|
19 |
+
Cython/Build/Tests/TestInline.py,sha256=bp4XGXZYSyxY2zXI0q4bg58a0ARsclUzXSfWykn0dZw,2854
|
20 |
+
Cython/Build/Tests/TestIpythonMagic.py,sha256=H88J6_r3dP5V3-N7eSKZuE2l9G8BtkFF_o8wY7pifKU,6225
|
21 |
+
Cython/Build/Tests/TestStripLiterals.py,sha256=-QeUd22OnoL50rW2EgpfIA01UzRMutcBA5NrhkHiE7M,1550
|
22 |
+
Cython/Build/Tests/__init__.py,sha256=jOqtmPLCvMCq0xVMwGekuLpBmVgq0xtPFmUePySdOjs,13
|
23 |
+
Cython/Build/Tests/__pycache__/TestCyCache.cpython-311.pyc,,
|
24 |
+
Cython/Build/Tests/__pycache__/TestInline.cpython-311.pyc,,
|
25 |
+
Cython/Build/Tests/__pycache__/TestIpythonMagic.cpython-311.pyc,,
|
26 |
+
Cython/Build/Tests/__pycache__/TestStripLiterals.cpython-311.pyc,,
|
27 |
+
Cython/Build/Tests/__pycache__/__init__.cpython-311.pyc,,
|
28 |
+
Cython/Build/__init__.py,sha256=zBhW6hT9Mwk1ZybfuPi61iCa6A4srId1HJz9OiEd07o,69
|
29 |
+
Cython/Build/__pycache__/BuildExecutable.cpython-311.pyc,,
|
30 |
+
Cython/Build/__pycache__/Cythonize.cpython-311.pyc,,
|
31 |
+
Cython/Build/__pycache__/Dependencies.cpython-311.pyc,,
|
32 |
+
Cython/Build/__pycache__/Distutils.cpython-311.pyc,,
|
33 |
+
Cython/Build/__pycache__/Inline.cpython-311.pyc,,
|
34 |
+
Cython/Build/__pycache__/IpythonMagic.cpython-311.pyc,,
|
35 |
+
Cython/Build/__pycache__/__init__.cpython-311.pyc,,
|
36 |
+
Cython/CodeWriter.py,sha256=tNFcGTXXs7V90ukOORIZxyj1-1BW3bgmgV0gEBExcRM,23998
|
37 |
+
Cython/Compiler/AnalysedTreeTransforms.py,sha256=T2r1SLFeG7a4D9tt93hm8YRH_aGLwmK82PNpb1RsbnE,3826
|
38 |
+
Cython/Compiler/Annotate.py,sha256=bkVgdH3ItuIbaSpi9Qo5bKiIjOX3-J5sZORfcyk_eZY,12950
|
39 |
+
Cython/Compiler/AutoDocTransforms.py,sha256=le7k-xhGWDkvpRXRppZsqhJzkav6i41GmAOmDetxVmk,7517
|
40 |
+
Cython/Compiler/Buffer.py,sha256=6-YIUiLWtgpC2LRhs7116umzNiEbzA6cz1lnPkSEn30,29035
|
41 |
+
Cython/Compiler/Builtin.py,sha256=3ynoOxUd6AE8XOuEDWwcl7lnNZirdYYXgMQI_WD7XPM,22571
|
42 |
+
Cython/Compiler/CmdLine.py,sha256=mZIKTOwjX_K5lWdjHufuhqBHaeEaYpQVIzNiYx5VWKE,10819
|
43 |
+
Cython/Compiler/Code.pxd,sha256=XEZU44jXCOFoYTG15-R0X41krTrjpuo1wxRKjyzYwoY,3354
|
44 |
+
Cython/Compiler/Code.py,sha256=VqhIddTqD7JpJfGZnFR16CFq9KkaY48QFdu51omzjuo,97241
|
45 |
+
Cython/Compiler/CodeGeneration.py,sha256=jkcx2uX07nck0UZSgysIThRuJiPbdkSeXR4Z2uzbQU8,1108
|
46 |
+
Cython/Compiler/CythonScope.py,sha256=mNwmE509uePmR3S2djg3Dq6zOZ3hgK-U8NDeawys9WM,6027
|
47 |
+
Cython/Compiler/DebugFlags.py,sha256=5Zg9ETp0qPFEma6QMtrGUwu9Fn6NTYMBMWPI_GxFW0A,623
|
48 |
+
Cython/Compiler/Errors.py,sha256=GATz9x6onls09cM6TeDw3kdBgdCxUiKJBILwukBF6WI,7554
|
49 |
+
Cython/Compiler/ExprNodes.py,sha256=ZzkQzNrqSXdvpisV_BSqAXze3Z8-OjZQ76J8BS9knPQ,550360
|
50 |
+
Cython/Compiler/FlowControl.pxd,sha256=W8bqGCJLzvAhnL3d1OF8798ZDJg0QI0eA_ebnA4dkoQ,2918
|
51 |
+
Cython/Compiler/FlowControl.py,sha256=-I33Yd9sp1RCENjFkrufBM8Xrj3y5SI7KZ04Vz5Djiw,45981
|
52 |
+
Cython/Compiler/FusedNode.py,sha256=qmHVHylEPpllK_x-471xBG-zMzAt0RF52tLxt_-RZqs,37794
|
53 |
+
Cython/Compiler/Future.py,sha256=GwcWZ_Vti0atfbOARfS2kIvZOvRuPu38wbShIn4o4kA,587
|
54 |
+
Cython/Compiler/Interpreter.py,sha256=iNweexX2HDI5nZj2rzkW-lw9Rq3gzM__P7SBqH3uxbU,2106
|
55 |
+
Cython/Compiler/Lexicon.py,sha256=Cw_wIfQymcTEdkoo82V2xbV8kvCp30O-Pc7qF4hbfCI,4855
|
56 |
+
Cython/Compiler/Main.py,sha256=69AfwvXrHWoDo0MwWuEmeKIb_tH0ZgaKfnin0UvpvR0,37098
|
57 |
+
Cython/Compiler/MemoryView.py,sha256=c6J7PtQ6wccb9uBxvbLngia4jO-h2uea7viIzJNhDYU,30009
|
58 |
+
Cython/Compiler/ModuleNode.py,sha256=QttRKICtGBd8p_KS3WYk7jrlSxeCyKfuWpvIsj1s1sA,142306
|
59 |
+
Cython/Compiler/Naming.py,sha256=MpFzZ87EkODg_9SGj3pL8Y9WvvQwWgpc2Hg0vrlJg4k,6402
|
60 |
+
Cython/Compiler/Nodes.py,sha256=00MIN2ChPQt_eUJPkiOww0urLSVnT2LsKHYYpeMVS6Y,392028
|
61 |
+
Cython/Compiler/Optimize.py,sha256=MJ5w9bXi6qU-yvDaiiZdBMSnp8g-QhEhBhs1zpWVICQ,210296
|
62 |
+
Cython/Compiler/Options.py,sha256=MPnBwPqSHWTM1tf5c0VSI9RdSSFTmg4M4zlIbCIk_Zw,19742
|
63 |
+
Cython/Compiler/ParseTreeTransforms.pxd,sha256=oDSda3XYP79o8tCAxEm_epWWVPXSaPy8lYrprWYRyNk,2468
|
64 |
+
Cython/Compiler/ParseTreeTransforms.py,sha256=oLSgT3GwVZQ3wLE1mr0B5x-cJDyG-MpKLyPsYAbKnag,139345
|
65 |
+
Cython/Compiler/Parsing.pxd,sha256=pL_EQdVWaw7EZVTZrxzMcUvoSJeAoXXPRh8kCLudysk,8984
|
66 |
+
Cython/Compiler/Parsing.py,sha256=2xdvmTh6xjgX-TfbcsyvfsqBTegVwPzbgskVwNpWMAQ,130570
|
67 |
+
Cython/Compiler/Pipeline.py,sha256=6ravd0QCR5sCoKlz9HEz209A2UqgLp4Qp0VysoKa_mI,14061
|
68 |
+
Cython/Compiler/PyrexTypes.py,sha256=i46nr1fJazgCE47WDC5OFo1YEAdy9fZjOU3STi5mFnc,173999
|
69 |
+
Cython/Compiler/Pythran.py,sha256=NHIml0yx0jPLyTLRAHXZr0LHTyEyfYqspgYuV4vdNKI,7267
|
70 |
+
Cython/Compiler/Scanning.pxd,sha256=vjjPLZb5udPzMpk67DKojTTDUl31QU86oXyAMks7Hsw,2113
|
71 |
+
Cython/Compiler/Scanning.py,sha256=Gl7sU5rI-5H5v8z9QLZBh1hivS2cOGa9H878QdEpUU4,18438
|
72 |
+
Cython/Compiler/StringEncoding.py,sha256=dn3jVSL4JScbeYf1f56j5RJR9M58AnCDdJObC-cc3fg,10812
|
73 |
+
Cython/Compiler/Symtab.py,sha256=n0tdTnbPkSuU5EgPkr6nGBN98Lhbklbjt8o6NUFt264,111727
|
74 |
+
Cython/Compiler/Tests/TestBuffer.py,sha256=yw-KUu2pu4CnsqYaqxj5rpyYodmjJSEqUvQNxLwPL8I,4155
|
75 |
+
Cython/Compiler/Tests/TestCmdLine.py,sha256=mT673jQ9MekvTExZdnQLztNabCsAMRSuN__egQ7rZ9A,6658
|
76 |
+
Cython/Compiler/Tests/TestFlowControl.py,sha256=ge3iqBor6xe5MLaLbOtw7ETntJnAh8EequF1aetVzMw,1848
|
77 |
+
Cython/Compiler/Tests/TestGrammar.py,sha256=zWMvYG19nIH85Le8ragXt2vLBlWlGGNeMgrTdQO5JGM,3443
|
78 |
+
Cython/Compiler/Tests/TestMemView.py,sha256=yBAQ5tN8DVPTFRJ81dAzOepCt5Ly6fiaAssQve5ryy4,2515
|
79 |
+
Cython/Compiler/Tests/TestParseTreeTransforms.py,sha256=xiRKOWqHIMIT1bbYB1o5TefKJXC8oPpjt79tQFodMRc,8900
|
80 |
+
Cython/Compiler/Tests/TestSignatureMatching.py,sha256=qMiQZeg5_Eu8VfCY_lMawqpjpKNV0r6p6-9czKec1aY,3338
|
81 |
+
Cython/Compiler/Tests/TestStringEncoding.py,sha256=RL1YDXrOUe1sPLEbWmTJQ5VF-uEZ_KLz0jaeQoMx85k,2315
|
82 |
+
Cython/Compiler/Tests/TestTreeFragment.py,sha256=wHlnF0ApwxeITx9pzg46P9N_2lM-7mrPwhDeNlIQnXM,2206
|
83 |
+
Cython/Compiler/Tests/TestTreePath.py,sha256=x-2KBIhSE6-vT-2BPe2q-zaa1oHtc42ibKzVs_y8_So,4238
|
84 |
+
Cython/Compiler/Tests/TestTypes.py,sha256=YuFib5WCJfSPafrhy5yrCUdwajYw61yGPo4HveTyzUs,669
|
85 |
+
Cython/Compiler/Tests/TestUtilityLoad.py,sha256=Uzf4_bOjha-zwQaikNbsAOVQs3ZPX3YD7QQ5T4s66YY,3341
|
86 |
+
Cython/Compiler/Tests/TestVisitor.py,sha256=QAnBpUhnirSFKqXWiawo-OhXhxIRTQidWxEzGjJDz6M,2228
|
87 |
+
Cython/Compiler/Tests/__init__.py,sha256=jOqtmPLCvMCq0xVMwGekuLpBmVgq0xtPFmUePySdOjs,13
|
88 |
+
Cython/Compiler/Tests/__pycache__/TestBuffer.cpython-311.pyc,,
|
89 |
+
Cython/Compiler/Tests/__pycache__/TestCmdLine.cpython-311.pyc,,
|
90 |
+
Cython/Compiler/Tests/__pycache__/TestFlowControl.cpython-311.pyc,,
|
91 |
+
Cython/Compiler/Tests/__pycache__/TestGrammar.cpython-311.pyc,,
|
92 |
+
Cython/Compiler/Tests/__pycache__/TestMemView.cpython-311.pyc,,
|
93 |
+
Cython/Compiler/Tests/__pycache__/TestParseTreeTransforms.cpython-311.pyc,,
|
94 |
+
Cython/Compiler/Tests/__pycache__/TestSignatureMatching.cpython-311.pyc,,
|
95 |
+
Cython/Compiler/Tests/__pycache__/TestStringEncoding.cpython-311.pyc,,
|
96 |
+
Cython/Compiler/Tests/__pycache__/TestTreeFragment.cpython-311.pyc,,
|
97 |
+
Cython/Compiler/Tests/__pycache__/TestTreePath.cpython-311.pyc,,
|
98 |
+
Cython/Compiler/Tests/__pycache__/TestTypes.cpython-311.pyc,,
|
99 |
+
Cython/Compiler/Tests/__pycache__/TestUtilityLoad.cpython-311.pyc,,
|
100 |
+
Cython/Compiler/Tests/__pycache__/TestVisitor.cpython-311.pyc,,
|
101 |
+
Cython/Compiler/Tests/__pycache__/__init__.cpython-311.pyc,,
|
102 |
+
Cython/Compiler/TreeFragment.py,sha256=jQn4Lp2dNddJ-tjPquoFcyTcX9EIuTAbZKZAKs9-cGU,9408
|
103 |
+
Cython/Compiler/TreePath.py,sha256=3_lScMAd2Sly2ekZ8HO8dyZstGSruINl2MXXq9OYd2Q,7641
|
104 |
+
Cython/Compiler/TypeInference.py,sha256=s-GKZcq16KPPgY_OpF8cTlQmX1Cpu-qBMCtmAYDg8fc,22326
|
105 |
+
Cython/Compiler/TypeSlots.py,sha256=EEZNyJIQy50yiRcBRpAosN9DnsZ8_AiDJAHCcyU_3co,37868
|
106 |
+
Cython/Compiler/UtilNodes.py,sha256=mS6jlZ530p17WGU0ApbwvLecuByT18LFipVrKJg5jrM,11636
|
107 |
+
Cython/Compiler/UtilityCode.py,sha256=PbQtJt9fSwgm5xeXgYWQih6eUSmJL_RwTxOa5T9SrZU,9391
|
108 |
+
Cython/Compiler/Version.py,sha256=f2mS6aYYdu0DMRK3B4IuzMlCo-k-ffmehCao_vKlTdk,181
|
109 |
+
Cython/Compiler/Visitor.pxd,sha256=KvOZgHoEREMTVYXr1ZoAk9H4n__rpmhIwE2S11ajeYM,1792
|
110 |
+
Cython/Compiler/Visitor.py,sha256=iqtIsNaQwk8lSa6g_LnEU06CZtdnP7MDXbyodl4Ouwk,29984
|
111 |
+
Cython/Compiler/__init__.py,sha256=jOqtmPLCvMCq0xVMwGekuLpBmVgq0xtPFmUePySdOjs,13
|
112 |
+
Cython/Compiler/__pycache__/AnalysedTreeTransforms.cpython-311.pyc,,
|
113 |
+
Cython/Compiler/__pycache__/Annotate.cpython-311.pyc,,
|
114 |
+
Cython/Compiler/__pycache__/AutoDocTransforms.cpython-311.pyc,,
|
115 |
+
Cython/Compiler/__pycache__/Buffer.cpython-311.pyc,,
|
116 |
+
Cython/Compiler/__pycache__/Builtin.cpython-311.pyc,,
|
117 |
+
Cython/Compiler/__pycache__/CmdLine.cpython-311.pyc,,
|
118 |
+
Cython/Compiler/__pycache__/Code.cpython-311.pyc,,
|
119 |
+
Cython/Compiler/__pycache__/CodeGeneration.cpython-311.pyc,,
|
120 |
+
Cython/Compiler/__pycache__/CythonScope.cpython-311.pyc,,
|
121 |
+
Cython/Compiler/__pycache__/DebugFlags.cpython-311.pyc,,
|
122 |
+
Cython/Compiler/__pycache__/Errors.cpython-311.pyc,,
|
123 |
+
Cython/Compiler/__pycache__/ExprNodes.cpython-311.pyc,,
|
124 |
+
Cython/Compiler/__pycache__/FlowControl.cpython-311.pyc,,
|
125 |
+
Cython/Compiler/__pycache__/FusedNode.cpython-311.pyc,,
|
126 |
+
Cython/Compiler/__pycache__/Future.cpython-311.pyc,,
|
127 |
+
Cython/Compiler/__pycache__/Interpreter.cpython-311.pyc,,
|
128 |
+
Cython/Compiler/__pycache__/Lexicon.cpython-311.pyc,,
|
129 |
+
Cython/Compiler/__pycache__/Main.cpython-311.pyc,,
|
130 |
+
Cython/Compiler/__pycache__/MemoryView.cpython-311.pyc,,
|
131 |
+
Cython/Compiler/__pycache__/ModuleNode.cpython-311.pyc,,
|
132 |
+
Cython/Compiler/__pycache__/Naming.cpython-311.pyc,,
|
133 |
+
Cython/Compiler/__pycache__/Nodes.cpython-311.pyc,,
|
134 |
+
Cython/Compiler/__pycache__/Optimize.cpython-311.pyc,,
|
135 |
+
Cython/Compiler/__pycache__/Options.cpython-311.pyc,,
|
136 |
+
Cython/Compiler/__pycache__/ParseTreeTransforms.cpython-311.pyc,,
|
137 |
+
Cython/Compiler/__pycache__/Parsing.cpython-311.pyc,,
|
138 |
+
Cython/Compiler/__pycache__/Pipeline.cpython-311.pyc,,
|
139 |
+
Cython/Compiler/__pycache__/PyrexTypes.cpython-311.pyc,,
|
140 |
+
Cython/Compiler/__pycache__/Pythran.cpython-311.pyc,,
|
141 |
+
Cython/Compiler/__pycache__/Scanning.cpython-311.pyc,,
|
142 |
+
Cython/Compiler/__pycache__/StringEncoding.cpython-311.pyc,,
|
143 |
+
Cython/Compiler/__pycache__/Symtab.cpython-311.pyc,,
|
144 |
+
Cython/Compiler/__pycache__/TreeFragment.cpython-311.pyc,,
|
145 |
+
Cython/Compiler/__pycache__/TreePath.cpython-311.pyc,,
|
146 |
+
Cython/Compiler/__pycache__/TypeInference.cpython-311.pyc,,
|
147 |
+
Cython/Compiler/__pycache__/TypeSlots.cpython-311.pyc,,
|
148 |
+
Cython/Compiler/__pycache__/UtilNodes.cpython-311.pyc,,
|
149 |
+
Cython/Compiler/__pycache__/UtilityCode.cpython-311.pyc,,
|
150 |
+
Cython/Compiler/__pycache__/Version.cpython-311.pyc,,
|
151 |
+
Cython/Compiler/__pycache__/Visitor.cpython-311.pyc,,
|
152 |
+
Cython/Compiler/__pycache__/__init__.cpython-311.pyc,,
|
153 |
+
Cython/Coverage.py,sha256=FtCMjKLYWvtULxWIzN-y3RhbwQwL4GtLyIjj-B3-07E,13537
|
154 |
+
Cython/Debugger/Cygdb.py,sha256=CH_pXm0Jhl4SAe6sJXa5NS47vMmQ2KBbecyV56vLqFE,5751
|
155 |
+
Cython/Debugger/DebugWriter.py,sha256=Yzz28JR4qZepxvxeu_1rJxIjJ4JbNQm5vM5e_UtNuRo,1945
|
156 |
+
Cython/Debugger/Tests/TestLibCython.py,sha256=xrENLEahnp6WtOfokVtsALR6Ot2jFR6T5ZZRcaX0Vxk,8327
|
157 |
+
Cython/Debugger/Tests/__init__.py,sha256=jOqtmPLCvMCq0xVMwGekuLpBmVgq0xtPFmUePySdOjs,13
|
158 |
+
Cython/Debugger/Tests/__pycache__/TestLibCython.cpython-311.pyc,,
|
159 |
+
Cython/Debugger/Tests/__pycache__/__init__.cpython-311.pyc,,
|
160 |
+
Cython/Debugger/Tests/__pycache__/test_libcython_in_gdb.cpython-311.pyc,,
|
161 |
+
Cython/Debugger/Tests/__pycache__/test_libpython_in_gdb.cpython-311.pyc,,
|
162 |
+
Cython/Debugger/Tests/cfuncs.c,sha256=4SZurmnz5J1SiIs9N26Eu4zc2wvF_qMEKaN0eTcbDPo,71
|
163 |
+
Cython/Debugger/Tests/codefile,sha256=ugwpT9GPtYZIKe2Xco4PqikyA-poQAeYfE0icXmfb44,641
|
164 |
+
Cython/Debugger/Tests/test_libcython_in_gdb.py,sha256=EvPTYkd7nzR3JtFim-ASLI6wfcYhgWfI4BQrucLJbHY,15804
|
165 |
+
Cython/Debugger/Tests/test_libpython_in_gdb.py,sha256=1BD_FtMkmS4SoSQZq7MgAgDnvqIw3EcYZFVrtoCQmxo,4079
|
166 |
+
Cython/Debugger/__init__.py,sha256=jOqtmPLCvMCq0xVMwGekuLpBmVgq0xtPFmUePySdOjs,13
|
167 |
+
Cython/Debugger/__pycache__/Cygdb.cpython-311.pyc,,
|
168 |
+
Cython/Debugger/__pycache__/DebugWriter.cpython-311.pyc,,
|
169 |
+
Cython/Debugger/__pycache__/__init__.cpython-311.pyc,,
|
170 |
+
Cython/Debugger/__pycache__/libcython.cpython-311.pyc,,
|
171 |
+
Cython/Debugger/__pycache__/libpython.cpython-311.pyc,,
|
172 |
+
Cython/Debugger/libcython.py,sha256=Qs0qGzeUyeY___3jRDy_WWIDFGfSRH4al7On2XxkuNg,44949
|
173 |
+
Cython/Debugger/libpython.py,sha256=IyTEdtGLnpQmt2XPgZ7oskQ8qGWWV2_5TMgZ5NhTA0k,90489
|
174 |
+
Cython/Debugging.py,sha256=vFtJhn7QstMf5gnYru2qHIz5ZjPg1KSlZVGHr-pBCwM,552
|
175 |
+
Cython/Distutils/__init__.py,sha256=uyWaN2NJ_mKYLzVsDPi0qZCdIYoW5M_7YYEmAOIL3Ek,98
|
176 |
+
Cython/Distutils/__pycache__/__init__.cpython-311.pyc,,
|
177 |
+
Cython/Distutils/__pycache__/build_ext.cpython-311.pyc,,
|
178 |
+
Cython/Distutils/__pycache__/extension.cpython-311.pyc,,
|
179 |
+
Cython/Distutils/__pycache__/old_build_ext.cpython-311.pyc,,
|
180 |
+
Cython/Distutils/build_ext.py,sha256=Fc_cI5wN0fT1Mf2k5B5nH-PgZ8Gq2lL6OlzF_qzy3dA,1007
|
181 |
+
Cython/Distutils/extension.py,sha256=FHvtK3Tj9MqE17TuZ_jWg1Mh4X7e-CXIPUpJK7nqcQE,4706
|
182 |
+
Cython/Distutils/old_build_ext.py,sha256=Hy34A1HqhoDOyU-krN2gJUYXK2mYWc8E2EZB-stvmrE,13635
|
183 |
+
Cython/Includes/Deprecated/python.pxd,sha256=l7crg8H9cVRedMcjDf_9xDLdnUT57Vt1BxlZWom-h88,61
|
184 |
+
Cython/Includes/Deprecated/python_bool.pxd,sha256=qOaFbsP6_pKoB3HGTjQUkFhQqukXheCmcSnnBQLdKGQ,66
|
185 |
+
Cython/Includes/Deprecated/python_buffer.pxd,sha256=gv2a3ngcOnRKZZHSox_bW1WD8jGbxfH9NJm1-iUXf9U,68
|
186 |
+
Cython/Includes/Deprecated/python_bytes.pxd,sha256=07-Hk3YpN_i4mIlbWYbNgDkjEytQAYOepJLJTY1CrVk,67
|
187 |
+
Cython/Includes/Deprecated/python_cobject.pxd,sha256=V9F0DHQbFZPbJ8RRnN9mft2ipq4wubM8ghBCGHr6NwE,69
|
188 |
+
Cython/Includes/Deprecated/python_complex.pxd,sha256=ITmq55v0b1gibEpLSCTCz68ViljenSuGGjiWn_nvIvI,69
|
189 |
+
Cython/Includes/Deprecated/python_dict.pxd,sha256=gYhGkJhMmzWcrXoPnJHUcp-vdtcwUACbGlfv3wtGsKU,66
|
190 |
+
Cython/Includes/Deprecated/python_exc.pxd,sha256=irWdwDYRWU16-P54uGDNfUSUtkL5Sj_1zBDWext_80g,65
|
191 |
+
Cython/Includes/Deprecated/python_float.pxd,sha256=v1Hbpd4SF3hSF7ZL_olMaYJzmBNA9jWn0eO9ggLBlvc,67
|
192 |
+
Cython/Includes/Deprecated/python_function.pxd,sha256=lkYKySQy1W36hfyyAJsc3E-8d9bsx5k8OhIMFQ6k2jA,70
|
193 |
+
Cython/Includes/Deprecated/python_getargs.pxd,sha256=NEdeqPqu4di0YJm_7yLfvuS903CAe4K2Pzb13TRfBdE,69
|
194 |
+
Cython/Includes/Deprecated/python_instance.pxd,sha256=FX9UlYrSxDrzch7wUvh_Y5Ix-bsDYARkXzZJOg2FvEI,70
|
195 |
+
Cython/Includes/Deprecated/python_int.pxd,sha256=Cwd4J4KTKjxwEMz1BbCso0g0pOID9AnySKOC1g0kLqA,65
|
196 |
+
Cython/Includes/Deprecated/python_iterator.pxd,sha256=nPJ0nKSmnUVzI1SPrTSt9wSD7SQILyhONJdP0H_-FGc,70
|
197 |
+
Cython/Includes/Deprecated/python_list.pxd,sha256=VHpylsg46-5Ud8rwlPe63bb3zSToXm9R_fPorZrJsUE,66
|
198 |
+
Cython/Includes/Deprecated/python_long.pxd,sha256=pg8hOKNoKaW-Mslugzeq6NCeznJw939LT24AVQn_cqE,66
|
199 |
+
Cython/Includes/Deprecated/python_mapping.pxd,sha256=AZtJdYm37glDSNChduAsgavz-_DPDkxxQEAO9lDGy84,69
|
200 |
+
Cython/Includes/Deprecated/python_mem.pxd,sha256=Mxidel5P4yuJxJOvoYr0PN1FD78oCOIJUEMPYMYU7lE,65
|
201 |
+
Cython/Includes/Deprecated/python_method.pxd,sha256=x5ye5_8KqtsW2HrEon5NdFJmIkmVDV1KeVpFsuC2UZE,68
|
202 |
+
Cython/Includes/Deprecated/python_module.pxd,sha256=lKu5VYCgC6S7LSgFa22V2YTY9JfML0vABDZpChhxs60,68
|
203 |
+
Cython/Includes/Deprecated/python_number.pxd,sha256=X4MxGoITZuJNPtC2cFJ8lQwui8MOC6rQfEDbFIcWA9k,68
|
204 |
+
Cython/Includes/Deprecated/python_object.pxd,sha256=qr2OwYVot4ELK3_-mCfaktXgLJEaKWDyCEblQ2vXV-E,68
|
205 |
+
Cython/Includes/Deprecated/python_oldbuffer.pxd,sha256=QyY4Vn5-cFaOt0oZ27GuRXa3tLawgMZN8KMamn9F1yo,71
|
206 |
+
Cython/Includes/Deprecated/python_pycapsule.pxd,sha256=tHJfhgm1TrSwJQwQFdhwP7YE7oQFiegxhNhgCDmlB6A,71
|
207 |
+
Cython/Includes/Deprecated/python_ref.pxd,sha256=wv39G35V7tN5sIhcL1APpe5NuhCwYwVy6X5DPPm5g5A,65
|
208 |
+
Cython/Includes/Deprecated/python_sequence.pxd,sha256=9ycCua1ODfECKPd56_GBmeqzWrfdqmkjhbEmdt87NC0,70
|
209 |
+
Cython/Includes/Deprecated/python_set.pxd,sha256=_Z5KVXs0V_T8fpgLX-2LbDAZIY1HnuhO-eTUHHRYwu0,65
|
210 |
+
Cython/Includes/Deprecated/python_string.pxd,sha256=6VgAehwW9PcUC9Kp_HbRVMYPeF_Q-L8yr9o2ezuTzys,68
|
211 |
+
Cython/Includes/Deprecated/python_tuple.pxd,sha256=_ZTQh7dRBmrRs9mtmOFjP37d0IFItxs20kzFtKtkY-g,67
|
212 |
+
Cython/Includes/Deprecated/python_type.pxd,sha256=2OKmEdSqoyK8fXttlHG3NRguZ-ZikUUet-kjKLq-eEU,66
|
213 |
+
Cython/Includes/Deprecated/python_unicode.pxd,sha256=TF8-N0un1WdyccTDo9hZVABc53SYzKnC3MEKrGb3vV0,69
|
214 |
+
Cython/Includes/Deprecated/python_version.pxd,sha256=ZXrK0UGUt8vHbYPxm7PTdhMe1_h7Yj6Lo74oFxjnNns,69
|
215 |
+
Cython/Includes/Deprecated/python_weakref.pxd,sha256=CUWMSmClrWPoTnlClOFCSHa6Xd55qDgIlcDCD6tfEhM,69
|
216 |
+
Cython/Includes/Deprecated/stdio.pxd,sha256=lNc2YuvWJ-LNSSdN7adDo1lf-C2M0r10hH4bysha9Sg,64
|
217 |
+
Cython/Includes/Deprecated/stdlib.pxd,sha256=PbCbjT8MjDjVRjx5Rod79gi22-9YI35jTulePAKCPXE,65
|
218 |
+
Cython/Includes/Deprecated/stl.pxd,sha256=tHpByeYgNiclr3YtCdKKAeEs3CHJflqacC7YgV7YN8k,2187
|
219 |
+
Cython/Includes/cpython/__init__.pxd,sha256=8URNRvb7JkYhqDZv2J0bVsdeZBEJBu7u2QFYkDyXPG8,8254
|
220 |
+
Cython/Includes/cpython/array.pxd,sha256=g6apBiXJG_7a0mjGqkFaqlcQjsg64uKK1VlXFFyXVCk,6056
|
221 |
+
Cython/Includes/cpython/bool.pxd,sha256=FaNn8K-Toq8FAws8BguKMk0IPM7IJm9IiUUGARSrKYk,1359
|
222 |
+
Cython/Includes/cpython/buffer.pxd,sha256=wm7aHygGUof_H3-JyICOek_xiU6Oks178ark1Nfk-a0,4870
|
223 |
+
Cython/Includes/cpython/bytearray.pxd,sha256=m0VdoHgouF1T0VtRjFLXZ5fi22vaMdVwFWpF3IxB6m4,1443
|
224 |
+
Cython/Includes/cpython/bytes.pxd,sha256=tGLuiBMzQjurK_pq77CM7P0C-Hn0KUIDZCXW9QvlJAI,9906
|
225 |
+
Cython/Includes/cpython/cellobject.pxd,sha256=DXdTjSN1RP1m4CsaGuggyIA1nGiIO4Kr7-c0ZWfrpRo,1390
|
226 |
+
Cython/Includes/cpython/ceval.pxd,sha256=h6fBetZCUvWTcCn3bkXZg2kqnIuyC5ZSChyhOocxVus,236
|
227 |
+
Cython/Includes/cpython/cobject.pxd,sha256=ZeMdbpZLqpcTywdv2VoppMTWD4X_yghL6Qox7LVfOyg,1524
|
228 |
+
Cython/Includes/cpython/codecs.pxd,sha256=3fyudEljkNGQ7e3dJPst6udXGcAeNKvlMK9U8EB1gXc,5084
|
229 |
+
Cython/Includes/cpython/complex.pxd,sha256=-bu0Cq91tS_U5tTra18S0jqt1FgSJTHXJ5J8rk-MOAA,1777
|
230 |
+
Cython/Includes/cpython/conversion.pxd,sha256=dbbFuZJF0SscmcaNCUf0tlBQDRdKYf5tH8yzhTU_XYI,1696
|
231 |
+
Cython/Includes/cpython/datetime.pxd,sha256=wQqB8i3tMZOTw9qrLdbHJRkxgZqscGEqmq0tIDfkkqw,6776
|
232 |
+
Cython/Includes/cpython/dict.pxd,sha256=F-mrlcAfNmTSUkpJed63bp1IaO0cwG56t_DLk7f0xv0,6877
|
233 |
+
Cython/Includes/cpython/exc.pxd,sha256=29-bGESwfoMqx1XU3MMggkIr8pz_l0UPruzy6KIzHxg,13606
|
234 |
+
Cython/Includes/cpython/float.pxd,sha256=RD1qEAUocXG9qXrRiT8aCSSfGEyTzjTc9HQkv5xg1ZE,1424
|
235 |
+
Cython/Includes/cpython/function.pxd,sha256=IoJUprbz8F10DEKh-vSSpY6nWkCHw7SqG9p2f-4gHek,2671
|
236 |
+
Cython/Includes/cpython/genobject.pxd,sha256=emC1JPgkuvBbGC0rgeZapKDaXYEj48uWiDC-xF0Mx2I,1052
|
237 |
+
Cython/Includes/cpython/getargs.pxd,sha256=268twKzdiAkQMXMsetNiNlNqaqzlKtiBENKbhOHd8x4,775
|
238 |
+
Cython/Includes/cpython/instance.pxd,sha256=qCbxPeHKOJbuszDu3UEaI-KLX9lTopuaNCcpoHJ9ngU,985
|
239 |
+
Cython/Includes/cpython/int.pxd,sha256=d9a0zUw_M3pRycCESWIjtfXWRvdvFOWxjdOjkcbX2gs,4131
|
240 |
+
Cython/Includes/cpython/iterator.pxd,sha256=o52mLHbdm14Kqant2hR2zAdYzqK4fkSWZtBcRmpoP-I,1319
|
241 |
+
Cython/Includes/cpython/iterobject.pxd,sha256=5UEZZwG5zyzxoCpknoQuh91zPUV11Uxr6F1taJdTv8k,1036
|
242 |
+
Cython/Includes/cpython/list.pxd,sha256=t-xo7ROcewe6-0ztrNjsxMKV2KxD-ILUzemQ2tTuI7E,4084
|
243 |
+
Cython/Includes/cpython/long.pxd,sha256=d6jHN1XJj7WL5PPAUK8U93IPyjWtlTmyhrBEVmxmGF8,7051
|
244 |
+
Cython/Includes/cpython/longintrepr.pxd,sha256=czvKr3fQdYIwIRu3gojXssT9LFXH-nstM7f_lPt7lE4,480
|
245 |
+
Cython/Includes/cpython/mapping.pxd,sha256=OIdvNVUoIpVCSQnkbLceTicSN0D_jRw6wQmbtxtxKuQ,2693
|
246 |
+
Cython/Includes/cpython/mem.pxd,sha256=AWVinanXFBZXvU141we2dD8dkOqMJ8W3KAAzpBJqB5g,5386
|
247 |
+
Cython/Includes/cpython/memoryview.pxd,sha256=l97J5-hbH3hp9aMbdXp3n73hJFNNsng6uyh40pc8P7I,2504
|
248 |
+
Cython/Includes/cpython/method.pxd,sha256=UWXflhIlP4y7B5XDbH9rQ15iADciGW-iqV1-dlw2Wwg,2196
|
249 |
+
Cython/Includes/cpython/module.pxd,sha256=Vc0Up7q1Mir38bN293E8RMugxWfuzjLFHM4g2dviPBM,9226
|
250 |
+
Cython/Includes/cpython/number.pxd,sha256=tYJ0nn0k_llUx3ilniW9iXd2rKVejA-J5UUiIJ36Kww,11922
|
251 |
+
Cython/Includes/cpython/object.pxd,sha256=AK5D-LrDbvisO6wpkh29G6xjA71sBF_KfKUyn0k2hzg,18366
|
252 |
+
Cython/Includes/cpython/oldbuffer.pxd,sha256=v0-YZ_Iwwj3ZQdM8VE5NPTQcbBlJdWwJGtNO9DonGgw,2916
|
253 |
+
Cython/Includes/cpython/pycapsule.pxd,sha256=-l_Rx3jjHx2Ff5H1xyJKI6HyXEBMDisaD02u0U7_1d0,5701
|
254 |
+
Cython/Includes/cpython/pylifecycle.pxd,sha256=LziJZHclGdtsr3yT28fULHNZ_n67bs1DmI9s8YzrBGg,2000
|
255 |
+
Cython/Includes/cpython/pystate.pxd,sha256=xgf1BBkv36qvqMaR77zZWYOuonAwe4RfNKE2g91A6fk,3683
|
256 |
+
Cython/Includes/cpython/pythread.pxd,sha256=0375TaYmtNCDDkWBh9WY4oJ_jhoTxhu_RR5QiOsXmYg,1946
|
257 |
+
Cython/Includes/cpython/ref.pxd,sha256=2AmgyGDhwA4scts0jcBTdGTCG0b2P8-eYAKFJk44x0I,2557
|
258 |
+
Cython/Includes/cpython/sequence.pxd,sha256=iTp3C6wOvTdvjLmdj3k9GqQqCGDlQFpzWi07wVQqSS4,6008
|
259 |
+
Cython/Includes/cpython/set.pxd,sha256=ewHRPVMbHUGDInZ3NziisCq68LvtmEJ-SXFbzmuJxLc,5383
|
260 |
+
Cython/Includes/cpython/slice.pxd,sha256=Rzgn8diAsN7lS2xGTq4VZucV3ziFNra4oz4tKGEAkMo,3111
|
261 |
+
Cython/Includes/cpython/string.pxd,sha256=EKjDGFnPcjnkndwGMJqRrszDV390Mc6o7AADChnNCiA,9944
|
262 |
+
Cython/Includes/cpython/tuple.pxd,sha256=eOLfH75ftJeYszztGFWWZP7LnyFOgw8GNuE7PQ9hAvs,3206
|
263 |
+
Cython/Includes/cpython/type.pxd,sha256=FOypwX0ZYamPc4uO8bejzO-HzgiaSRaXEPsxxxPIneI,1831
|
264 |
+
Cython/Includes/cpython/unicode.pxd,sha256=ymXBenUGMeamRMv9bQ8_FbwIeId7Xi7Xjzs0Nhravyw,27009
|
265 |
+
Cython/Includes/cpython/version.pxd,sha256=l5KXt04isEv3qbGRJZ8fNlCYGO24HsA2l4EM3RxTEhE,847
|
266 |
+
Cython/Includes/cpython/weakref.pxd,sha256=UU9H_ovHG07FFgP_kY2xhGv3yJDr_8iujCZnxH2jnlo,1984
|
267 |
+
Cython/Includes/libc/__init__.pxd,sha256=jOqtmPLCvMCq0xVMwGekuLpBmVgq0xtPFmUePySdOjs,13
|
268 |
+
Cython/Includes/libc/errno.pxd,sha256=j5hcKx7zinivU2b6SFMy8LZ9sJIQY5XLrp9cQUKv5AQ,2050
|
269 |
+
Cython/Includes/libc/float.pxd,sha256=IhvZJljpTG0fZtcIp7EBO2Sqddozxoxwj4RFNVcKLpY,966
|
270 |
+
Cython/Includes/libc/limits.pxd,sha256=xHlIyuDIKpjqclvRRYzZIcfd5G1re5QtbmoDMqZR_Ec,621
|
271 |
+
Cython/Includes/libc/locale.pxd,sha256=sixG8EJ6wiVb0HIR1LWJ3lXTjTv463GJ9C_40HRovN4,1140
|
272 |
+
Cython/Includes/libc/math.pxd,sha256=51YUxSe01R96_rr3sj4n4MLW-eOmQbcwdNn8YthTxqg,2948
|
273 |
+
Cython/Includes/libc/setjmp.pxd,sha256=XRh-gSuhvFLl0nRvz5OhSWYe9eqX2attAck3JI7mwa4,297
|
274 |
+
Cython/Includes/libc/signal.pxd,sha256=XOScPDA5vzlfEmu4D7DFT1-5Eu3qMpYdUarjt-fqlbw,1170
|
275 |
+
Cython/Includes/libc/stddef.pxd,sha256=0rCyoocCfDL-1OQo3pxHQ-6fW20SAYktOLPoa4d97w8,164
|
276 |
+
Cython/Includes/libc/stdint.pxd,sha256=qHJXzpWCrbvJWSaHYZL27VJPupQreTZl9VGj0jgLdRU,3449
|
277 |
+
Cython/Includes/libc/stdio.pxd,sha256=qUaxEwNrQl1-4yHLorzzJZ-a-y5_-Rm_m7Z5meaRqH0,2476
|
278 |
+
Cython/Includes/libc/stdlib.pxd,sha256=p62xq2XfB24WfNCjRXgD6cOYoRuV47AnYijkjWv4ugE,2444
|
279 |
+
Cython/Includes/libc/string.pxd,sha256=tzYGbRrnccedFLes-KGgJqM0FEtwHF_q4f2fqltNvyE,2038
|
280 |
+
Cython/Includes/libc/time.pxd,sha256=-IRH7fTq3wKBKmQQnpZRhaLsnl7D_qXFz_4BLB9O3u0,1317
|
281 |
+
Cython/Includes/libcpp/__init__.pxd,sha256=PCx8ZRfOeoyMRu41PPlPY9uo2kZmt_7d0KR4Epzfe7c,94
|
282 |
+
Cython/Includes/libcpp/algorithm.pxd,sha256=-2V0oR_cFbHHzeWT9RcfLvi5Oy-s_V2lO3OI6ZtX6fM,1770
|
283 |
+
Cython/Includes/libcpp/cast.pxd,sha256=En4LBubdinfpm9Rel077tK_LGwg_3k4FAu9mlIbKjuw,501
|
284 |
+
Cython/Includes/libcpp/complex.pxd,sha256=IjL8y9sAglhGbTKhqsJbW0mgMTYEUbYM1ekr5VDhQgY,3012
|
285 |
+
Cython/Includes/libcpp/deque.pxd,sha256=aWqZ9j3OgQuqFLkqRO_U2FIwbSe2fKmmYDRAfD0vGqU,3106
|
286 |
+
Cython/Includes/libcpp/forward_list.pxd,sha256=-So1ExEOkoPfsSdMlJSlI5665-zyWLMoUxlmm2Dlokk,2392
|
287 |
+
Cython/Includes/libcpp/functional.pxd,sha256=BXPYkffEOlKO1erTLqlkBLex6Gb5byDMF4hq_MZ2aVI,381
|
288 |
+
Cython/Includes/libcpp/iterator.pxd,sha256=mVc1rsAYfn_ARrdQ4JG-Ut5il5ynIa1CRXLk8Be8Zks,1432
|
289 |
+
Cython/Includes/libcpp/limits.pxd,sha256=RKV3wPvk4tV_vX5CYQRJIK5m5xXav7SeBxltlLyk8es,1661
|
290 |
+
Cython/Includes/libcpp/list.pxd,sha256=rGQfB3_mDcRkGKtMBuvDQvAPmgzR5jxSf3eOSRgR4YA,2658
|
291 |
+
Cython/Includes/libcpp/map.pxd,sha256=GF2sDnFBHZoU3Rcuo1rn6yKh45nhkX0_iH29xj581ow,2551
|
292 |
+
Cython/Includes/libcpp/memory.pxd,sha256=Hj20aSnmUTPAhFCrlmF_aeHJKiMiZ2bDKhaYn2yybJo,3600
|
293 |
+
Cython/Includes/libcpp/pair.pxd,sha256=UBJXw43uHkDlNsr0Pu1aP5tZ-ILXhUAyOLam2qdWmZA,27
|
294 |
+
Cython/Includes/libcpp/queue.pxd,sha256=FbL4Q7C3lgtZ2YzictU1XBXzQ7G-6y9i_7l2eqzA3Xc,649
|
295 |
+
Cython/Includes/libcpp/set.pxd,sha256=3y5Ir2TjGD7g3VRvlkXV1a3V3ZYzJvwOAfeTv8ucOCw,2170
|
296 |
+
Cython/Includes/libcpp/stack.pxd,sha256=zM3SQOqMWONVqud13ag3bUupA-ozU_YMq4Ad2QkL6fI,292
|
297 |
+
Cython/Includes/libcpp/string.pxd,sha256=zsvzyW6IggIDFqcF-UuLjxiNAHPtToAoc9VhKKG2U5A,8731
|
298 |
+
Cython/Includes/libcpp/typeindex.pxd,sha256=mIHr5Mq6Lol0SlzqeK6w_giVERh3uAjZm78yPDLXzc4,524
|
299 |
+
Cython/Includes/libcpp/typeinfo.pxd,sha256=tITsqurrdaZjsEGFksem9xZtVhSxQRxHZxcoC-4Y-DY,304
|
300 |
+
Cython/Includes/libcpp/unordered_map.pxd,sha256=eNna4hRAucQLnliBfEMu7Unfd_lB18I42iwKmsCO0-M,2867
|
301 |
+
Cython/Includes/libcpp/unordered_set.pxd,sha256=eUYSOMT5Gt8kZWCUKezQGyXWzatEyNg6-nmAlmcBo-k,2622
|
302 |
+
Cython/Includes/libcpp/utility.pxd,sha256=hTbvp7c12pnU2yvzzMvflZB-MAc_--3xh3PXtD_VIwg,1040
|
303 |
+
Cython/Includes/libcpp/vector.pxd,sha256=GYqLb74owhMmNQHUCcZSxGcYPgNuw6qULsfWKr7g6OQ,3350
|
304 |
+
Cython/Includes/numpy/__init__.pxd,sha256=CbLwvA4u-xj7RHxbO9Hs2o6hXd7GaJJlGEn9XJVH4c4,38138
|
305 |
+
Cython/Includes/numpy/math.pxd,sha256=qZEdamaPgCFW4J7Itc6BWgOrQSKZdxDT6kbU_gqx2g4,5807
|
306 |
+
Cython/Includes/openmp.pxd,sha256=orCIBYFuVPtLdRdhhCm5uhGbeV_fgVCA2Jk2Bts1e2g,1713
|
307 |
+
Cython/Includes/posix/__init__.pxd,sha256=jOqtmPLCvMCq0xVMwGekuLpBmVgq0xtPFmUePySdOjs,13
|
308 |
+
Cython/Includes/posix/dlfcn.pxd,sha256=2IFcGBfZEmArdE0BxB71eT_Yb7n9STaVM11AtUcg_pE,355
|
309 |
+
Cython/Includes/posix/fcntl.pxd,sha256=oRL8-OsgcplHMGcYq5-W5twISvxK-vDfzAaEfuQHC-4,1194
|
310 |
+
Cython/Includes/posix/ioctl.pxd,sha256=2RC5zejPOCTkarDZM_6Vd2wc4oBuN7iaiL_C5MPBs90,99
|
311 |
+
Cython/Includes/posix/mman.pxd,sha256=juJcLi92N9Bc6L2p4zrUmYQIgNmrTsZ6hExbl1181pc,3362
|
312 |
+
Cython/Includes/posix/resource.pxd,sha256=MQe1bCTYQFVMsago3pgOvR6t6NElQElg7rhVANxYRcE,1254
|
313 |
+
Cython/Includes/posix/select.pxd,sha256=e4nhGHR8TRw6Xs9du5JoFtkd8U9sm3gX_BHq2FfmU6E,546
|
314 |
+
Cython/Includes/posix/signal.pxd,sha256=wFJI5UthdtU9mZWjEBeZ9IIfeX252JVwDk2tsbW_q3U,1876
|
315 |
+
Cython/Includes/posix/stat.pxd,sha256=ZOcPCpXnxlRRHcUkvg559hrFfB75uTbIYRWoQeyBCYs,1734
|
316 |
+
Cython/Includes/posix/stdio.pxd,sha256=K8DEH38hWMvy2A8zcKbHRrHSGsgwTIrQ9qCzU-0cWS0,1054
|
317 |
+
Cython/Includes/posix/stdlib.pxd,sha256=uGRPa00_HWZ6Chv5E13F96eut0xWHSfR7IioK9rKVLY,934
|
318 |
+
Cython/Includes/posix/strings.pxd,sha256=GNEteqND2wgXXSvkv6U9eKSC9oIom3C7o2zQ6W_J_S4,374
|
319 |
+
Cython/Includes/posix/time.pxd,sha256=wPUD7AjxpxmnUYmogTMFjroB2VzcPh8-b_8NEj-yG14,1980
|
320 |
+
Cython/Includes/posix/types.pxd,sha256=tWEWxST4EGHIgYS-Ce2SGjZ-KgmM2SVe1eggdcgv3JQ,1162
|
321 |
+
Cython/Includes/posix/unistd.pxd,sha256=w9B4d9NaXBsQ62XOr2xe9UFPGewmEk5BG6sqiRWdoM8,8061
|
322 |
+
Cython/Includes/posix/wait.pxd,sha256=WNogQvKu2hMfEQiCyaANfVWFnyJSk6TxBU0c6npeJrA,1244
|
323 |
+
Cython/Plex/Actions.pxd,sha256=FC-6ffzWR4i3rR6VSL2C64Xxs1qBhpBEzRsU7WpLn1Y,585
|
324 |
+
Cython/Plex/Actions.py,sha256=Caxkx8Kup9m4sx24ZcDTq-fAfPGG06TAHu2NI1D9zPs,2545
|
325 |
+
Cython/Plex/DFA.py,sha256=w4vl2ejXv6ptILtkTCbB8NcvF8ylwc6DaQ2gPFrWuo4,6012
|
326 |
+
Cython/Plex/Errors.py,sha256=As5uuGmqZe4w0B7Dm981lZTnDG-nlXSHYqiGUKnhrrY,1169
|
327 |
+
Cython/Plex/Lexicons.py,sha256=ay3yy9fqI5y5lfgpJ4ubBjYZQ53gFDVgNGbmoSl5DxI,6907
|
328 |
+
Cython/Plex/Machines.py,sha256=bIKg3-yxD_r7x-zEowJ7EsPBWlgXm_XhIozqsLQBeTk,7760
|
329 |
+
Cython/Plex/Regexps.py,sha256=qaP-Fr-GgKNmBVsMyXO3ltl2HH1JQcQiFmX2oyUyeOA,16208
|
330 |
+
Cython/Plex/Scanners.pxd,sha256=oSfcDUZ3syc2ag73udwU5xoaIGDxiNd8a2F_LLw5PzY,1481
|
331 |
+
Cython/Plex/Scanners.py,sha256=-TXAxKW43ZbQNCSEkMWEJ0SmqYVVCkSOT9UngOCRZnQ,12259
|
332 |
+
Cython/Plex/Timing.py,sha256=-VgQveS-Ip_2ErjrVxh4w7cXpyVBkUaSaiLadyD3bw0,472
|
333 |
+
Cython/Plex/Traditional.py,sha256=cAT-pZnqIwCJaqgSqgKODSznFZ5DunUw_MLWx8Y650c,4120
|
334 |
+
Cython/Plex/Transitions.py,sha256=Tvp7cFXR3ZBPPHm0TAhUMC_-uiRR9YdOkF4t0wtk-f0,7187
|
335 |
+
Cython/Plex/__init__.py,sha256=dvMeQpSyZE75W0gkf4Xo5LAxgQLNhkAXiQoIOtcOkZ0,1282
|
336 |
+
Cython/Plex/__pycache__/Actions.cpython-311.pyc,,
|
337 |
+
Cython/Plex/__pycache__/DFA.cpython-311.pyc,,
|
338 |
+
Cython/Plex/__pycache__/Errors.cpython-311.pyc,,
|
339 |
+
Cython/Plex/__pycache__/Lexicons.cpython-311.pyc,,
|
340 |
+
Cython/Plex/__pycache__/Machines.cpython-311.pyc,,
|
341 |
+
Cython/Plex/__pycache__/Regexps.cpython-311.pyc,,
|
342 |
+
Cython/Plex/__pycache__/Scanners.cpython-311.pyc,,
|
343 |
+
Cython/Plex/__pycache__/Timing.cpython-311.pyc,,
|
344 |
+
Cython/Plex/__pycache__/Traditional.cpython-311.pyc,,
|
345 |
+
Cython/Plex/__pycache__/Transitions.cpython-311.pyc,,
|
346 |
+
Cython/Plex/__pycache__/__init__.cpython-311.pyc,,
|
347 |
+
Cython/Runtime/__init__.py,sha256=jOqtmPLCvMCq0xVMwGekuLpBmVgq0xtPFmUePySdOjs,13
|
348 |
+
Cython/Runtime/__pycache__/__init__.cpython-311.pyc,,
|
349 |
+
Cython/Runtime/refnanny.pyx,sha256=f2p1_0YxK25lm8Qfsu2ytvl0Im7GYyix1Q9krEBwC6c,6279
|
350 |
+
Cython/Shadow.py,sha256=MVEHAbarZ56-h0-_TjoHyZJ6GBJbvDMs5x2dfqYZzrE,13007
|
351 |
+
Cython/StringIOTree.py,sha256=GX-TWn9XHwY5ecb4in8ovsTS5CtPTsSxZpanLWmQxgE,3336
|
352 |
+
Cython/Tempita/__init__.py,sha256=YHujYHiLoYUwFNNswJCgzSrDuie3sV08JsWT9Nbmp78,152
|
353 |
+
Cython/Tempita/__pycache__/__init__.cpython-311.pyc,,
|
354 |
+
Cython/Tempita/__pycache__/_looper.cpython-311.pyc,,
|
355 |
+
Cython/Tempita/__pycache__/_tempita.cpython-311.pyc,,
|
356 |
+
Cython/Tempita/__pycache__/compat3.cpython-311.pyc,,
|
357 |
+
Cython/Tempita/_looper.py,sha256=jlStYhz9Pgp6NatX86k-netBNBmvwaeWxCRS_S8vcIM,4168
|
358 |
+
Cython/Tempita/_tempita.py,sha256=ZUBoFcXHnLrzg_aOjd3N2JoRcNlZL9KGD97Sz-Rd4SM,37038
|
359 |
+
Cython/Tempita/compat3.py,sha256=cjW1y266vRF5Xvh8kAu7_qHGT8AGGu2kGSJRK6DI-0E,903
|
360 |
+
Cython/TestUtils.py,sha256=fzpic9xU-LP0wempXqwUQWZapBvXnFgbW_W9--IKpIA,7979
|
361 |
+
Cython/Tests/TestCodeWriter.py,sha256=qKad43J3hN7PLp7mVbEDESt96qsk8y3ELRwwIp9jnNw,2316
|
362 |
+
Cython/Tests/TestCythonUtils.py,sha256=XF4Fw4J5HZ4jUPLVv7ea8ZZcl2i9yXn5cx27WTtrcmU,474
|
363 |
+
Cython/Tests/TestJediTyper.py,sha256=F6MUG8SdzGXQwkbw6Wv1PqVlmlIT1z_7lH2buVOFT_I,6996
|
364 |
+
Cython/Tests/TestStringIOTree.py,sha256=vTuu3z32WTcmJaf0fBq62NMghYtaPL2rRnfdl2WM--4,1946
|
365 |
+
Cython/Tests/__init__.py,sha256=jOqtmPLCvMCq0xVMwGekuLpBmVgq0xtPFmUePySdOjs,13
|
366 |
+
Cython/Tests/__pycache__/TestCodeWriter.cpython-311.pyc,,
|
367 |
+
Cython/Tests/__pycache__/TestCythonUtils.cpython-311.pyc,,
|
368 |
+
Cython/Tests/__pycache__/TestJediTyper.cpython-311.pyc,,
|
369 |
+
Cython/Tests/__pycache__/TestStringIOTree.cpython-311.pyc,,
|
370 |
+
Cython/Tests/__pycache__/__init__.cpython-311.pyc,,
|
371 |
+
Cython/Tests/__pycache__/xmlrunner.cpython-311.pyc,,
|
372 |
+
Cython/Tests/xmlrunner.py,sha256=N1Z_C4Q_rSWFNQxm3L99qX-SaIWEksXbmfXOd_srg3s,14801
|
373 |
+
Cython/Utility/AsyncGen.c,sha256=vPzUFEDh8EYaFqWhXLJA-0PBM4Z5BpS-HOiQmDaKK5A,41775
|
374 |
+
Cython/Utility/Buffer.c,sha256=VUF4xHKJGX7QMTvpJO40aI1JUL-SERLEvlXXXEk2dHU,29654
|
375 |
+
Cython/Utility/Builtins.c,sha256=gYObNoiK_NVWRuzSFRePMb-dtw-XCp_Dx_Ztjmpq7as,16818
|
376 |
+
Cython/Utility/CConvert.pyx,sha256=fbZVHvm2vlWj2rgm8ajBt5jrbN30nY7dEmHlBCGomlU,4338
|
377 |
+
Cython/Utility/CMath.c,sha256=GIc7gd2WzaZryDJM3tefqXifLJpUJs6_T_c_mFrr-s8,2566
|
378 |
+
Cython/Utility/Capsule.c,sha256=SOeU7E7T7piQEx894T2QFH2RlSG-MmsiyuY4lVN1yso,505
|
379 |
+
Cython/Utility/CommonStructures.c,sha256=p65HHgTrf7h7Tj7JK7tIgkLrrCrjouL8HL90EHfoMoU,2558
|
380 |
+
Cython/Utility/Complex.c,sha256=6YPGWtZUNI2ig5LRn3KWURB7z3cfhSNasW1S1Ejl7ao,10062
|
381 |
+
Cython/Utility/Coroutine.c,sha256=6tGqnflttVUZatqW7SdFBAydrKb0gM8R0Xo7keTzrnY,90224
|
382 |
+
Cython/Utility/CpdefEnums.pyx,sha256=XMg8sdltQSNj2wGVfnHIWRvyHFCcLK8ZfpKznKi4lhY,1893
|
383 |
+
Cython/Utility/CppConvert.pyx,sha256=-e5i3_J1SS_GbctsflQwylx9cqdk_CJ2SfQSEDHa71k,6098
|
384 |
+
Cython/Utility/CppSupport.cpp,sha256=NTnSRCmi2PHuT3J6Qy15xMZGx0bf9l-MaxAbW6OVk6s,2234
|
385 |
+
Cython/Utility/CythonFunction.c,sha256=KpQykNHRfC6b6Jl2TGX1Ir9hLUNXC4SrtGgzVNEcSw0,46746
|
386 |
+
Cython/Utility/Embed.c,sha256=sMDv7XVJswaGRTQbQHtEDThZaAmvbn-6yeIqrUzboL4,6854
|
387 |
+
Cython/Utility/Exceptions.c,sha256=vULhDRn0lSdjDysXspvXmv8Bcu3BaxB07jUxmQ5s-jU,28348
|
388 |
+
Cython/Utility/ExtensionTypes.c,sha256=doPkCDEsyClYfDa1386DxwVj0D4jYvKQlnbXQo2REHM,11664
|
389 |
+
Cython/Utility/FunctionArguments.c,sha256=IH9Y5aV_tNrJLo_CWHskEnFai9fp9cKLvRkIZYl2UGQ,12040
|
390 |
+
Cython/Utility/ImportExport.c,sha256=VbB1KiTkt4WAVSZ-DZiYd-b3t_ESWOnSsP6IRYa_3r8,23448
|
391 |
+
Cython/Utility/MemoryView.pyx,sha256=5WnL5DJF0nuSQBN5oBeEHFYE8aYm4C0-hY9Azm-toY4,49749
|
392 |
+
Cython/Utility/MemoryView_C.c,sha256=wlIKZ6UxkH--BFA-ENr83FtUw0KtStkqjAvB24Q0y_s,29072
|
393 |
+
Cython/Utility/ModuleSetupCode.c,sha256=FwNj8IxvfOjuMuQngRRvp9xOp0GafLTINf6cwxU52L4,58901
|
394 |
+
Cython/Utility/ObjectHandling.c,sha256=ZNaN2UoxX7HGfJZQhVDuyZfhsrzJ2kijaRvoA-qR5qU,89084
|
395 |
+
Cython/Utility/Optimize.c,sha256=xtKZ8WhOe8l4UYONGVDilNFhzGMueJxA7nYJn8QIWmc,45184
|
396 |
+
Cython/Utility/Overflow.c,sha256=_KXlJsbMIi-jzdCotwxkN6mtqo6jHRNnPJ1ZKwXVhpE,12424
|
397 |
+
Cython/Utility/Printing.c,sha256=o8XnfjNIT8Ub5KY4FAp_FNw-OE3xqjy0MgmYWgDcWao,5103
|
398 |
+
Cython/Utility/Profile.c,sha256=3aq_eC7h_nUnZe-Np7td20ublCC4OowfHoV3FoW9UnU,17922
|
399 |
+
Cython/Utility/StringTools.c,sha256=UyWngTrFElFXl4NIi7n36QCM7HL3MCNGhvqpPYLLY6o,42215
|
400 |
+
Cython/Utility/TestCyUtilityLoader.pyx,sha256=91lWWJub7l_6xNn3ncrvQZZ94RpkQzEx2NtAaFpvrxY,152
|
401 |
+
Cython/Utility/TestCythonScope.pyx,sha256=HQm5E5Eehr3tkDDURURyVnDputKG3-Wn2k2aIAoru9g,1595
|
402 |
+
Cython/Utility/TestUtilityLoader.c,sha256=dGy6ZWL2kBqtmUY7kF75UEox5kadQZ__BmZKscwg2aY,279
|
403 |
+
Cython/Utility/TypeConversion.c,sha256=ydxFNzBNOWIKoDA_z_U8a1wcZxdyeieiac8KQDN6pok,36333
|
404 |
+
Cython/Utility/__init__.py,sha256=t2bpY-TYSX8lJdbKuBFJ1kBfpWVzgGw4xoZlCKfyj_s,1159
|
405 |
+
Cython/Utility/__pycache__/__init__.cpython-311.pyc,,
|
406 |
+
Cython/Utility/arrayarray.h,sha256=3Ll8Gd_S4rv8HaTfg5i6-aaoB9taI1vzwTp7NeA7Wy0,4089
|
407 |
+
Cython/Utils.py,sha256=gb4MDFuC2NidOkhLVpsOm0NE3opVgFLWPw6ydmo_Mq4,14300
|
408 |
+
Cython/__init__.py,sha256=GMnkoIas6hfN_meqZAJF9BEs1NuY4-4B2L0Uls7hXaA,358
|
409 |
+
Cython/__pycache__/CodeWriter.cpython-311.pyc,,
|
410 |
+
Cython/__pycache__/Coverage.cpython-311.pyc,,
|
411 |
+
Cython/__pycache__/Debugging.cpython-311.pyc,,
|
412 |
+
Cython/__pycache__/Shadow.cpython-311.pyc,,
|
413 |
+
Cython/__pycache__/StringIOTree.cpython-311.pyc,,
|
414 |
+
Cython/__pycache__/TestUtils.cpython-311.pyc,,
|
415 |
+
Cython/__pycache__/Utils.cpython-311.pyc,,
|
416 |
+
Cython/__pycache__/__init__.cpython-311.pyc,,
|
417 |
+
__pycache__/cython.cpython-311.pyc,,
|
418 |
+
cython.py,sha256=z2AtgHBGh0x0h0ZcGje7IhYlR6nGH_MmOh1fFMjqYn0,520
|
419 |
+
pyximport/__init__.py,sha256=9hOyKolFtOerPiVEyktKrT1VtzbGexq9UmORzo52iHI,79
|
420 |
+
pyximport/__pycache__/__init__.cpython-311.pyc,,
|
421 |
+
pyximport/__pycache__/pyxbuild.cpython-311.pyc,,
|
422 |
+
pyximport/__pycache__/pyximport.cpython-311.pyc,,
|
423 |
+
pyximport/pyxbuild.py,sha256=TiAkhtSxSbRW04JKtgO3FP3hfVzQ1mjjzCh5PqZDOrM,5702
|
424 |
+
pyximport/pyximport.py,sha256=Vjxp3kbmFRf9j0ya4f0m0Ahytkjjmv2UkFueasXxL5A,23578
|
venv/Lib/site-packages/Cython-0.29.36.dist-info/WHEEL
ADDED
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
Wheel-Version: 1.0
|
2 |
+
Generator: bdist_wheel (0.40.0)
|
3 |
+
Root-Is-Purelib: true
|
4 |
+
Tag: py2-none-any
|
5 |
+
Tag: py3-none-any
|
6 |
+
|
venv/Lib/site-packages/Cython-0.29.36.dist-info/entry_points.txt
ADDED
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
1 |
+
[console_scripts]
|
2 |
+
cygdb = Cython.Debugger.Cygdb:main
|
3 |
+
cython = Cython.Compiler.Main:setuptools_main
|
4 |
+
cythonize = Cython.Build.Cythonize:main
|
venv/Lib/site-packages/Cython-0.29.36.dist-info/top_level.txt
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
Cython
|
2 |
+
cython
|
3 |
+
pyximport
|
venv/Lib/site-packages/Cython/Build/BuildExecutable.py
ADDED
@@ -0,0 +1,142 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
"""
|
2 |
+
Compile a Python script into an executable that embeds CPython and run it.
|
3 |
+
Requires CPython to be built as a shared library ('libpythonX.Y').
|
4 |
+
|
5 |
+
Basic usage:
|
6 |
+
|
7 |
+
python cythonrun somefile.py [ARGS]
|
8 |
+
"""
|
9 |
+
|
10 |
+
from __future__ import absolute_import
|
11 |
+
|
12 |
+
DEBUG = True
|
13 |
+
|
14 |
+
import sys
|
15 |
+
import os
|
16 |
+
from distutils import sysconfig
|
17 |
+
|
18 |
+
|
19 |
+
def get_config_var(name, default=''):
|
20 |
+
return sysconfig.get_config_var(name) or default
|
21 |
+
|
22 |
+
INCDIR = sysconfig.get_python_inc()
|
23 |
+
LIBDIR1 = get_config_var('LIBDIR')
|
24 |
+
LIBDIR2 = get_config_var('LIBPL')
|
25 |
+
PYLIB = get_config_var('LIBRARY')
|
26 |
+
PYLIB_DYN = get_config_var('LDLIBRARY')
|
27 |
+
if PYLIB_DYN == PYLIB:
|
28 |
+
# no shared library
|
29 |
+
PYLIB_DYN = ''
|
30 |
+
else:
|
31 |
+
PYLIB_DYN = os.path.splitext(PYLIB_DYN[3:])[0] # 'lib(XYZ).so' -> XYZ
|
32 |
+
|
33 |
+
CC = get_config_var('CC', os.environ.get('CC', ''))
|
34 |
+
CFLAGS = get_config_var('CFLAGS') + ' ' + os.environ.get('CFLAGS', '')
|
35 |
+
LINKCC = get_config_var('LINKCC', os.environ.get('LINKCC', CC))
|
36 |
+
LINKFORSHARED = get_config_var('LINKFORSHARED')
|
37 |
+
LIBS = get_config_var('LIBS')
|
38 |
+
SYSLIBS = get_config_var('SYSLIBS')
|
39 |
+
EXE_EXT = sysconfig.get_config_var('EXE')
|
40 |
+
|
41 |
+
def _debug(msg, *args):
|
42 |
+
if DEBUG:
|
43 |
+
if args:
|
44 |
+
msg = msg % args
|
45 |
+
sys.stderr.write(msg + '\n')
|
46 |
+
|
47 |
+
def dump_config():
|
48 |
+
_debug('INCDIR: %s', INCDIR)
|
49 |
+
_debug('LIBDIR1: %s', LIBDIR1)
|
50 |
+
_debug('LIBDIR2: %s', LIBDIR2)
|
51 |
+
_debug('PYLIB: %s', PYLIB)
|
52 |
+
_debug('PYLIB_DYN: %s', PYLIB_DYN)
|
53 |
+
_debug('CC: %s', CC)
|
54 |
+
_debug('CFLAGS: %s', CFLAGS)
|
55 |
+
_debug('LINKCC: %s', LINKCC)
|
56 |
+
_debug('LINKFORSHARED: %s', LINKFORSHARED)
|
57 |
+
_debug('LIBS: %s', LIBS)
|
58 |
+
_debug('SYSLIBS: %s', SYSLIBS)
|
59 |
+
_debug('EXE_EXT: %s', EXE_EXT)
|
60 |
+
|
61 |
+
def runcmd(cmd, shell=True):
|
62 |
+
if shell:
|
63 |
+
cmd = ' '.join(cmd)
|
64 |
+
_debug(cmd)
|
65 |
+
else:
|
66 |
+
_debug(' '.join(cmd))
|
67 |
+
|
68 |
+
try:
|
69 |
+
import subprocess
|
70 |
+
except ImportError: # Python 2.3 ...
|
71 |
+
returncode = os.system(cmd)
|
72 |
+
else:
|
73 |
+
returncode = subprocess.call(cmd, shell=shell)
|
74 |
+
|
75 |
+
if returncode:
|
76 |
+
sys.exit(returncode)
|
77 |
+
|
78 |
+
def clink(basename):
|
79 |
+
runcmd([LINKCC, '-o', basename + EXE_EXT, basename+'.o', '-L'+LIBDIR1, '-L'+LIBDIR2]
|
80 |
+
+ [PYLIB_DYN and ('-l'+PYLIB_DYN) or os.path.join(LIBDIR1, PYLIB)]
|
81 |
+
+ LIBS.split() + SYSLIBS.split() + LINKFORSHARED.split())
|
82 |
+
|
83 |
+
def ccompile(basename):
|
84 |
+
runcmd([CC, '-c', '-o', basename+'.o', basename+'.c', '-I' + INCDIR] + CFLAGS.split())
|
85 |
+
|
86 |
+
def cycompile(input_file, options=()):
|
87 |
+
from ..Compiler import Version, CmdLine, Main
|
88 |
+
options, sources = CmdLine.parse_command_line(list(options or ()) + ['--embed', input_file])
|
89 |
+
_debug('Using Cython %s to compile %s', Version.version, input_file)
|
90 |
+
result = Main.compile(sources, options)
|
91 |
+
if result.num_errors > 0:
|
92 |
+
sys.exit(1)
|
93 |
+
|
94 |
+
def exec_file(program_name, args=()):
|
95 |
+
runcmd([os.path.abspath(program_name)] + list(args), shell=False)
|
96 |
+
|
97 |
+
def build(input_file, compiler_args=(), force=False):
|
98 |
+
"""
|
99 |
+
Build an executable program from a Cython module.
|
100 |
+
|
101 |
+
Returns the name of the executable file.
|
102 |
+
"""
|
103 |
+
basename = os.path.splitext(input_file)[0]
|
104 |
+
exe_file = basename + EXE_EXT
|
105 |
+
if not force and os.path.abspath(exe_file) == os.path.abspath(input_file):
|
106 |
+
raise ValueError("Input and output file names are the same, refusing to overwrite")
|
107 |
+
if (not force and os.path.exists(exe_file) and os.path.exists(input_file)
|
108 |
+
and os.path.getmtime(input_file) <= os.path.getmtime(exe_file)):
|
109 |
+
_debug("File is up to date, not regenerating %s", exe_file)
|
110 |
+
return exe_file
|
111 |
+
cycompile(input_file, compiler_args)
|
112 |
+
ccompile(basename)
|
113 |
+
clink(basename)
|
114 |
+
return exe_file
|
115 |
+
|
116 |
+
def build_and_run(args):
|
117 |
+
"""
|
118 |
+
Build an executable program from a Cython module and runs it.
|
119 |
+
|
120 |
+
Arguments after the module name will be passed verbatimely to the
|
121 |
+
program.
|
122 |
+
"""
|
123 |
+
cy_args = []
|
124 |
+
last_arg = None
|
125 |
+
for i, arg in enumerate(args):
|
126 |
+
if arg.startswith('-'):
|
127 |
+
cy_args.append(arg)
|
128 |
+
elif last_arg in ('-X', '--directive'):
|
129 |
+
cy_args.append(arg)
|
130 |
+
else:
|
131 |
+
input_file = arg
|
132 |
+
args = args[i+1:]
|
133 |
+
break
|
134 |
+
last_arg = arg
|
135 |
+
else:
|
136 |
+
raise ValueError('no input file provided')
|
137 |
+
|
138 |
+
program_name = build(input_file, cy_args)
|
139 |
+
exec_file(program_name, args)
|
140 |
+
|
141 |
+
if __name__ == '__main__':
|
142 |
+
build_and_run(sys.argv[1:])
|
venv/Lib/site-packages/Cython/Build/Cythonize.py
ADDED
@@ -0,0 +1,229 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#!/usr/bin/env python
|
2 |
+
|
3 |
+
from __future__ import absolute_import
|
4 |
+
|
5 |
+
import os
|
6 |
+
import shutil
|
7 |
+
import tempfile
|
8 |
+
from distutils.core import setup
|
9 |
+
|
10 |
+
from .Dependencies import cythonize, extended_iglob
|
11 |
+
from ..Utils import is_package_dir
|
12 |
+
from ..Compiler import Options
|
13 |
+
|
14 |
+
try:
|
15 |
+
import multiprocessing
|
16 |
+
parallel_compiles = int(multiprocessing.cpu_count() * 1.5)
|
17 |
+
except ImportError:
|
18 |
+
multiprocessing = None
|
19 |
+
parallel_compiles = 0
|
20 |
+
|
21 |
+
|
22 |
+
class _FakePool(object):
|
23 |
+
def map_async(self, func, args):
|
24 |
+
try:
|
25 |
+
from itertools import imap
|
26 |
+
except ImportError:
|
27 |
+
imap=map
|
28 |
+
for _ in imap(func, args):
|
29 |
+
pass
|
30 |
+
|
31 |
+
def close(self):
|
32 |
+
pass
|
33 |
+
|
34 |
+
def terminate(self):
|
35 |
+
pass
|
36 |
+
|
37 |
+
def join(self):
|
38 |
+
pass
|
39 |
+
|
40 |
+
|
41 |
+
def parse_directives(option, name, value, parser):
|
42 |
+
dest = option.dest
|
43 |
+
old_directives = dict(getattr(parser.values, dest,
|
44 |
+
Options.get_directive_defaults()))
|
45 |
+
directives = Options.parse_directive_list(
|
46 |
+
value, relaxed_bool=True, current_settings=old_directives)
|
47 |
+
setattr(parser.values, dest, directives)
|
48 |
+
|
49 |
+
|
50 |
+
def parse_options(option, name, value, parser):
|
51 |
+
dest = option.dest
|
52 |
+
options = dict(getattr(parser.values, dest, {}))
|
53 |
+
for opt in value.split(','):
|
54 |
+
if '=' in opt:
|
55 |
+
n, v = opt.split('=', 1)
|
56 |
+
v = v.lower() not in ('false', 'f', '0', 'no')
|
57 |
+
else:
|
58 |
+
n, v = opt, True
|
59 |
+
options[n] = v
|
60 |
+
setattr(parser.values, dest, options)
|
61 |
+
|
62 |
+
|
63 |
+
def parse_compile_time_env(option, name, value, parser):
|
64 |
+
dest = option.dest
|
65 |
+
old_env = dict(getattr(parser.values, dest, {}))
|
66 |
+
new_env = Options.parse_compile_time_env(value, current_settings=old_env)
|
67 |
+
setattr(parser.values, dest, new_env)
|
68 |
+
|
69 |
+
|
70 |
+
def find_package_base(path):
|
71 |
+
base_dir, package_path = os.path.split(path)
|
72 |
+
while os.path.isfile(os.path.join(base_dir, '__init__.py')):
|
73 |
+
base_dir, parent = os.path.split(base_dir)
|
74 |
+
package_path = '%s/%s' % (parent, package_path)
|
75 |
+
return base_dir, package_path
|
76 |
+
|
77 |
+
|
78 |
+
def cython_compile(path_pattern, options):
|
79 |
+
pool = None
|
80 |
+
all_paths = map(os.path.abspath, extended_iglob(path_pattern))
|
81 |
+
try:
|
82 |
+
for path in all_paths:
|
83 |
+
if options.build_inplace:
|
84 |
+
base_dir = path
|
85 |
+
while not os.path.isdir(base_dir) or is_package_dir(base_dir):
|
86 |
+
base_dir = os.path.dirname(base_dir)
|
87 |
+
else:
|
88 |
+
base_dir = None
|
89 |
+
|
90 |
+
if os.path.isdir(path):
|
91 |
+
# recursively compiling a package
|
92 |
+
paths = [os.path.join(path, '**', '*.{py,pyx}')]
|
93 |
+
else:
|
94 |
+
# assume it's a file(-like thing)
|
95 |
+
paths = [path]
|
96 |
+
|
97 |
+
ext_modules = cythonize(
|
98 |
+
paths,
|
99 |
+
nthreads=options.parallel,
|
100 |
+
exclude_failures=options.keep_going,
|
101 |
+
exclude=options.excludes,
|
102 |
+
compiler_directives=options.directives,
|
103 |
+
compile_time_env=options.compile_time_env,
|
104 |
+
force=options.force,
|
105 |
+
quiet=options.quiet,
|
106 |
+
depfile=options.depfile,
|
107 |
+
**options.options)
|
108 |
+
|
109 |
+
if ext_modules and options.build:
|
110 |
+
if len(ext_modules) > 1 and options.parallel > 1:
|
111 |
+
if pool is None:
|
112 |
+
try:
|
113 |
+
pool = multiprocessing.Pool(options.parallel)
|
114 |
+
except OSError:
|
115 |
+
pool = _FakePool()
|
116 |
+
pool.map_async(run_distutils, [
|
117 |
+
(base_dir, [ext]) for ext in ext_modules])
|
118 |
+
else:
|
119 |
+
run_distutils((base_dir, ext_modules))
|
120 |
+
except:
|
121 |
+
if pool is not None:
|
122 |
+
pool.terminate()
|
123 |
+
raise
|
124 |
+
else:
|
125 |
+
if pool is not None:
|
126 |
+
pool.close()
|
127 |
+
pool.join()
|
128 |
+
|
129 |
+
|
130 |
+
def run_distutils(args):
|
131 |
+
base_dir, ext_modules = args
|
132 |
+
script_args = ['build_ext', '-i']
|
133 |
+
cwd = os.getcwd()
|
134 |
+
temp_dir = None
|
135 |
+
try:
|
136 |
+
if base_dir:
|
137 |
+
os.chdir(base_dir)
|
138 |
+
temp_dir = tempfile.mkdtemp(dir=base_dir)
|
139 |
+
script_args.extend(['--build-temp', temp_dir])
|
140 |
+
setup(
|
141 |
+
script_name='setup.py',
|
142 |
+
script_args=script_args,
|
143 |
+
ext_modules=ext_modules,
|
144 |
+
)
|
145 |
+
finally:
|
146 |
+
if base_dir:
|
147 |
+
os.chdir(cwd)
|
148 |
+
if temp_dir and os.path.isdir(temp_dir):
|
149 |
+
shutil.rmtree(temp_dir)
|
150 |
+
|
151 |
+
|
152 |
+
def parse_args(args):
|
153 |
+
from optparse import OptionParser
|
154 |
+
parser = OptionParser(usage='%prog [options] [sources and packages]+')
|
155 |
+
|
156 |
+
parser.add_option('-X', '--directive', metavar='NAME=VALUE,...',
|
157 |
+
dest='directives', default={}, type="str",
|
158 |
+
action='callback', callback=parse_directives,
|
159 |
+
help='set a compiler directive')
|
160 |
+
parser.add_option('-E', '--compile-time-env', metavar='NAME=VALUE,...',
|
161 |
+
dest='compile_time_env', default={}, type="str",
|
162 |
+
action='callback', callback=parse_compile_time_env,
|
163 |
+
help='set a compile time environment variable')
|
164 |
+
parser.add_option('-s', '--option', metavar='NAME=VALUE',
|
165 |
+
dest='options', default={}, type="str",
|
166 |
+
action='callback', callback=parse_options,
|
167 |
+
help='set a cythonize option')
|
168 |
+
parser.add_option('-2', dest='language_level', action='store_const', const=2, default=None,
|
169 |
+
help='use Python 2 syntax mode by default')
|
170 |
+
parser.add_option('-3', dest='language_level', action='store_const', const=3,
|
171 |
+
help='use Python 3 syntax mode by default')
|
172 |
+
parser.add_option('--3str', dest='language_level', action='store_const', const='3str',
|
173 |
+
help='use Python 3 syntax mode by default')
|
174 |
+
parser.add_option('-a', '--annotate', dest='annotate', action='store_true',
|
175 |
+
help='generate annotated HTML page for source files')
|
176 |
+
|
177 |
+
parser.add_option('-x', '--exclude', metavar='PATTERN', dest='excludes',
|
178 |
+
action='append', default=[],
|
179 |
+
help='exclude certain file patterns from the compilation')
|
180 |
+
|
181 |
+
parser.add_option('-b', '--build', dest='build', action='store_true',
|
182 |
+
help='build extension modules using distutils')
|
183 |
+
parser.add_option('-i', '--inplace', dest='build_inplace', action='store_true',
|
184 |
+
help='build extension modules in place using distutils (implies -b)')
|
185 |
+
parser.add_option('-j', '--parallel', dest='parallel', metavar='N',
|
186 |
+
type=int, default=parallel_compiles,
|
187 |
+
help=('run builds in N parallel jobs (default: %d)' %
|
188 |
+
parallel_compiles or 1))
|
189 |
+
parser.add_option('-f', '--force', dest='force', action='store_true',
|
190 |
+
help='force recompilation')
|
191 |
+
parser.add_option('-q', '--quiet', dest='quiet', action='store_true',
|
192 |
+
help='be less verbose during compilation')
|
193 |
+
|
194 |
+
parser.add_option('--lenient', dest='lenient', action='store_true',
|
195 |
+
help='increase Python compatibility by ignoring some compile time errors')
|
196 |
+
parser.add_option('-k', '--keep-going', dest='keep_going', action='store_true',
|
197 |
+
help='compile as much as possible, ignore compilation failures')
|
198 |
+
parser.add_option('-M', '--depfile', action='store_true', help='produce depfiles for the sources')
|
199 |
+
|
200 |
+
options, args = parser.parse_args(args)
|
201 |
+
if not args:
|
202 |
+
parser.error("no source files provided")
|
203 |
+
if options.build_inplace:
|
204 |
+
options.build = True
|
205 |
+
if multiprocessing is None:
|
206 |
+
options.parallel = 0
|
207 |
+
if options.language_level:
|
208 |
+
assert options.language_level in (2, 3, '3str')
|
209 |
+
options.options['language_level'] = options.language_level
|
210 |
+
return options, args
|
211 |
+
|
212 |
+
|
213 |
+
def main(args=None):
|
214 |
+
options, paths = parse_args(args)
|
215 |
+
|
216 |
+
if options.lenient:
|
217 |
+
# increase Python compatibility by ignoring compile time errors
|
218 |
+
Options.error_on_unknown_names = False
|
219 |
+
Options.error_on_uninitialized = False
|
220 |
+
|
221 |
+
if options.annotate:
|
222 |
+
Options.annotate = True
|
223 |
+
|
224 |
+
for path in paths:
|
225 |
+
cython_compile(path, options)
|
226 |
+
|
227 |
+
|
228 |
+
if __name__ == '__main__':
|
229 |
+
main()
|
venv/Lib/site-packages/Cython/Build/Dependencies.py
ADDED
@@ -0,0 +1,1296 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from __future__ import absolute_import, print_function
|
2 |
+
|
3 |
+
import cython
|
4 |
+
from .. import __version__
|
5 |
+
|
6 |
+
import collections
|
7 |
+
import contextlib
|
8 |
+
import hashlib
|
9 |
+
import os
|
10 |
+
import shutil
|
11 |
+
import subprocess
|
12 |
+
import re, sys, time
|
13 |
+
import warnings
|
14 |
+
from glob import iglob
|
15 |
+
from io import open as io_open
|
16 |
+
from os.path import relpath as _relpath
|
17 |
+
from distutils.extension import Extension
|
18 |
+
from distutils.util import strtobool
|
19 |
+
import zipfile
|
20 |
+
|
21 |
+
try:
|
22 |
+
from collections.abc import Iterable
|
23 |
+
except ImportError:
|
24 |
+
from collections import Iterable
|
25 |
+
|
26 |
+
try:
|
27 |
+
import gzip
|
28 |
+
gzip_open = gzip.open
|
29 |
+
gzip_ext = '.gz'
|
30 |
+
except ImportError:
|
31 |
+
gzip_open = open
|
32 |
+
gzip_ext = ''
|
33 |
+
|
34 |
+
try:
|
35 |
+
import zlib
|
36 |
+
zipfile_compression_mode = zipfile.ZIP_DEFLATED
|
37 |
+
except ImportError:
|
38 |
+
zipfile_compression_mode = zipfile.ZIP_STORED
|
39 |
+
|
40 |
+
try:
|
41 |
+
import pythran
|
42 |
+
except:
|
43 |
+
pythran = None
|
44 |
+
|
45 |
+
from .. import Utils
|
46 |
+
from ..Utils import (cached_function, cached_method, path_exists, write_depfile,
|
47 |
+
safe_makedirs, copy_file_to_dir_if_newer, is_package_dir, replace_suffix)
|
48 |
+
from ..Compiler.Main import Context, CompilationOptions, default_options
|
49 |
+
|
50 |
+
join_path = cached_function(os.path.join)
|
51 |
+
copy_once_if_newer = cached_function(copy_file_to_dir_if_newer)
|
52 |
+
safe_makedirs_once = cached_function(safe_makedirs)
|
53 |
+
|
54 |
+
if sys.version_info[0] < 3:
|
55 |
+
# stupid Py2 distutils enforces str type in list of sources
|
56 |
+
_fs_encoding = sys.getfilesystemencoding()
|
57 |
+
if _fs_encoding is None:
|
58 |
+
_fs_encoding = sys.getdefaultencoding()
|
59 |
+
def encode_filename_in_py2(filename):
|
60 |
+
if not isinstance(filename, bytes):
|
61 |
+
return filename.encode(_fs_encoding)
|
62 |
+
return filename
|
63 |
+
else:
|
64 |
+
def encode_filename_in_py2(filename):
|
65 |
+
return filename
|
66 |
+
basestring = str
|
67 |
+
|
68 |
+
|
69 |
+
def _make_relative(file_paths, base=None):
|
70 |
+
if not base:
|
71 |
+
base = os.getcwd()
|
72 |
+
if base[-1] != os.path.sep:
|
73 |
+
base += os.path.sep
|
74 |
+
return [_relpath(path, base) if path.startswith(base) else path
|
75 |
+
for path in file_paths]
|
76 |
+
|
77 |
+
|
78 |
+
def extended_iglob(pattern):
|
79 |
+
if '{' in pattern:
|
80 |
+
m = re.match('(.*){([^}]+)}(.*)', pattern)
|
81 |
+
if m:
|
82 |
+
before, switch, after = m.groups()
|
83 |
+
for case in switch.split(','):
|
84 |
+
for path in extended_iglob(before + case + after):
|
85 |
+
yield path
|
86 |
+
return
|
87 |
+
if '**/' in pattern:
|
88 |
+
seen = set()
|
89 |
+
first, rest = pattern.split('**/', 1)
|
90 |
+
if first:
|
91 |
+
first = iglob(first+'/')
|
92 |
+
else:
|
93 |
+
first = ['']
|
94 |
+
for root in first:
|
95 |
+
for path in extended_iglob(join_path(root, rest)):
|
96 |
+
if path not in seen:
|
97 |
+
seen.add(path)
|
98 |
+
yield path
|
99 |
+
for path in extended_iglob(join_path(root, '*', '**/' + rest)):
|
100 |
+
if path not in seen:
|
101 |
+
seen.add(path)
|
102 |
+
yield path
|
103 |
+
else:
|
104 |
+
for path in iglob(pattern):
|
105 |
+
yield path
|
106 |
+
|
107 |
+
|
108 |
+
def nonempty(it, error_msg="expected non-empty iterator"):
|
109 |
+
empty = True
|
110 |
+
for value in it:
|
111 |
+
empty = False
|
112 |
+
yield value
|
113 |
+
if empty:
|
114 |
+
raise ValueError(error_msg)
|
115 |
+
|
116 |
+
|
117 |
+
@cached_function
|
118 |
+
def file_hash(filename):
|
119 |
+
path = os.path.normpath(filename)
|
120 |
+
prefix = ('%d:%s' % (len(path), path)).encode("UTF-8")
|
121 |
+
m = hashlib.md5(prefix)
|
122 |
+
with open(path, 'rb') as f:
|
123 |
+
data = f.read(65000)
|
124 |
+
while data:
|
125 |
+
m.update(data)
|
126 |
+
data = f.read(65000)
|
127 |
+
return m.hexdigest()
|
128 |
+
|
129 |
+
|
130 |
+
def update_pythran_extension(ext):
|
131 |
+
if pythran is None:
|
132 |
+
raise RuntimeError("You first need to install Pythran to use the np_pythran directive.")
|
133 |
+
try:
|
134 |
+
pythran_ext = pythran.config.make_extension(python=True)
|
135 |
+
except TypeError: # older pythran version only
|
136 |
+
pythran_ext = pythran.config.make_extension()
|
137 |
+
|
138 |
+
ext.include_dirs.extend(pythran_ext['include_dirs'])
|
139 |
+
ext.extra_compile_args.extend(pythran_ext['extra_compile_args'])
|
140 |
+
ext.extra_link_args.extend(pythran_ext['extra_link_args'])
|
141 |
+
ext.define_macros.extend(pythran_ext['define_macros'])
|
142 |
+
ext.undef_macros.extend(pythran_ext['undef_macros'])
|
143 |
+
ext.library_dirs.extend(pythran_ext['library_dirs'])
|
144 |
+
ext.libraries.extend(pythran_ext['libraries'])
|
145 |
+
ext.language = 'c++'
|
146 |
+
|
147 |
+
# These options are not compatible with the way normal Cython extensions work
|
148 |
+
for bad_option in ["-fwhole-program", "-fvisibility=hidden"]:
|
149 |
+
try:
|
150 |
+
ext.extra_compile_args.remove(bad_option)
|
151 |
+
except ValueError:
|
152 |
+
pass
|
153 |
+
|
154 |
+
|
155 |
+
def parse_list(s):
|
156 |
+
"""
|
157 |
+
>>> parse_list("")
|
158 |
+
[]
|
159 |
+
>>> parse_list("a")
|
160 |
+
['a']
|
161 |
+
>>> parse_list("a b c")
|
162 |
+
['a', 'b', 'c']
|
163 |
+
>>> parse_list("[a, b, c]")
|
164 |
+
['a', 'b', 'c']
|
165 |
+
>>> parse_list('a " " b')
|
166 |
+
['a', ' ', 'b']
|
167 |
+
>>> parse_list('[a, ",a", "a,", ",", ]')
|
168 |
+
['a', ',a', 'a,', ',']
|
169 |
+
"""
|
170 |
+
if len(s) >= 2 and s[0] == '[' and s[-1] == ']':
|
171 |
+
s = s[1:-1]
|
172 |
+
delimiter = ','
|
173 |
+
else:
|
174 |
+
delimiter = ' '
|
175 |
+
s, literals = strip_string_literals(s)
|
176 |
+
def unquote(literal):
|
177 |
+
literal = literal.strip()
|
178 |
+
if literal[0] in "'\"":
|
179 |
+
return literals[literal[1:-1]]
|
180 |
+
else:
|
181 |
+
return literal
|
182 |
+
return [unquote(item) for item in s.split(delimiter) if item.strip()]
|
183 |
+
|
184 |
+
|
185 |
+
transitive_str = object()
|
186 |
+
transitive_list = object()
|
187 |
+
bool_or = object()
|
188 |
+
|
189 |
+
distutils_settings = {
|
190 |
+
'name': str,
|
191 |
+
'sources': list,
|
192 |
+
'define_macros': list,
|
193 |
+
'undef_macros': list,
|
194 |
+
'libraries': transitive_list,
|
195 |
+
'library_dirs': transitive_list,
|
196 |
+
'runtime_library_dirs': transitive_list,
|
197 |
+
'include_dirs': transitive_list,
|
198 |
+
'extra_objects': list,
|
199 |
+
'extra_compile_args': transitive_list,
|
200 |
+
'extra_link_args': transitive_list,
|
201 |
+
'export_symbols': list,
|
202 |
+
'depends': transitive_list,
|
203 |
+
'language': transitive_str,
|
204 |
+
'np_pythran': bool_or
|
205 |
+
}
|
206 |
+
|
207 |
+
|
208 |
+
@cython.locals(start=cython.Py_ssize_t, end=cython.Py_ssize_t)
|
209 |
+
def line_iter(source):
|
210 |
+
if isinstance(source, basestring):
|
211 |
+
start = 0
|
212 |
+
while True:
|
213 |
+
end = source.find('\n', start)
|
214 |
+
if end == -1:
|
215 |
+
yield source[start:]
|
216 |
+
return
|
217 |
+
yield source[start:end]
|
218 |
+
start = end+1
|
219 |
+
else:
|
220 |
+
for line in source:
|
221 |
+
yield line
|
222 |
+
|
223 |
+
|
224 |
+
class DistutilsInfo(object):
|
225 |
+
|
226 |
+
def __init__(self, source=None, exn=None):
|
227 |
+
self.values = {}
|
228 |
+
if source is not None:
|
229 |
+
for line in line_iter(source):
|
230 |
+
line = line.lstrip()
|
231 |
+
if not line:
|
232 |
+
continue
|
233 |
+
if line[0] != '#':
|
234 |
+
break
|
235 |
+
line = line[1:].lstrip()
|
236 |
+
kind = next((k for k in ("distutils:","cython:") if line.startswith(k)), None)
|
237 |
+
if kind is not None:
|
238 |
+
key, _, value = [s.strip() for s in line[len(kind):].partition('=')]
|
239 |
+
type = distutils_settings.get(key, None)
|
240 |
+
if line.startswith("cython:") and type is None: continue
|
241 |
+
if type in (list, transitive_list):
|
242 |
+
value = parse_list(value)
|
243 |
+
if key == 'define_macros':
|
244 |
+
value = [tuple(macro.split('=', 1))
|
245 |
+
if '=' in macro else (macro, None)
|
246 |
+
for macro in value]
|
247 |
+
if type is bool_or:
|
248 |
+
value = strtobool(value)
|
249 |
+
self.values[key] = value
|
250 |
+
elif exn is not None:
|
251 |
+
for key in distutils_settings:
|
252 |
+
if key in ('name', 'sources','np_pythran'):
|
253 |
+
continue
|
254 |
+
value = getattr(exn, key, None)
|
255 |
+
if value:
|
256 |
+
self.values[key] = value
|
257 |
+
|
258 |
+
def merge(self, other):
|
259 |
+
if other is None:
|
260 |
+
return self
|
261 |
+
for key, value in other.values.items():
|
262 |
+
type = distutils_settings[key]
|
263 |
+
if type is transitive_str and key not in self.values:
|
264 |
+
self.values[key] = value
|
265 |
+
elif type is transitive_list:
|
266 |
+
if key in self.values:
|
267 |
+
# Change a *copy* of the list (Trac #845)
|
268 |
+
all = self.values[key][:]
|
269 |
+
for v in value:
|
270 |
+
if v not in all:
|
271 |
+
all.append(v)
|
272 |
+
value = all
|
273 |
+
self.values[key] = value
|
274 |
+
elif type is bool_or:
|
275 |
+
self.values[key] = self.values.get(key, False) | value
|
276 |
+
return self
|
277 |
+
|
278 |
+
def subs(self, aliases):
|
279 |
+
if aliases is None:
|
280 |
+
return self
|
281 |
+
resolved = DistutilsInfo()
|
282 |
+
for key, value in self.values.items():
|
283 |
+
type = distutils_settings[key]
|
284 |
+
if type in [list, transitive_list]:
|
285 |
+
new_value_list = []
|
286 |
+
for v in value:
|
287 |
+
if v in aliases:
|
288 |
+
v = aliases[v]
|
289 |
+
if isinstance(v, list):
|
290 |
+
new_value_list += v
|
291 |
+
else:
|
292 |
+
new_value_list.append(v)
|
293 |
+
value = new_value_list
|
294 |
+
else:
|
295 |
+
if value in aliases:
|
296 |
+
value = aliases[value]
|
297 |
+
resolved.values[key] = value
|
298 |
+
return resolved
|
299 |
+
|
300 |
+
def apply(self, extension):
|
301 |
+
for key, value in self.values.items():
|
302 |
+
type = distutils_settings[key]
|
303 |
+
if type in [list, transitive_list]:
|
304 |
+
value = getattr(extension, key) + list(value)
|
305 |
+
setattr(extension, key, value)
|
306 |
+
|
307 |
+
|
308 |
+
@cython.locals(start=cython.Py_ssize_t, q=cython.Py_ssize_t,
|
309 |
+
single_q=cython.Py_ssize_t, double_q=cython.Py_ssize_t,
|
310 |
+
hash_mark=cython.Py_ssize_t, end=cython.Py_ssize_t,
|
311 |
+
k=cython.Py_ssize_t, counter=cython.Py_ssize_t, quote_len=cython.Py_ssize_t)
|
312 |
+
def strip_string_literals(code, prefix='__Pyx_L'):
|
313 |
+
"""
|
314 |
+
Normalizes every string literal to be of the form '__Pyx_Lxxx',
|
315 |
+
returning the normalized code and a mapping of labels to
|
316 |
+
string literals.
|
317 |
+
"""
|
318 |
+
new_code = []
|
319 |
+
literals = {}
|
320 |
+
counter = 0
|
321 |
+
start = q = 0
|
322 |
+
in_quote = False
|
323 |
+
hash_mark = single_q = double_q = -1
|
324 |
+
code_len = len(code)
|
325 |
+
quote_type = None
|
326 |
+
quote_len = -1
|
327 |
+
|
328 |
+
while True:
|
329 |
+
if hash_mark < q:
|
330 |
+
hash_mark = code.find('#', q)
|
331 |
+
if single_q < q:
|
332 |
+
single_q = code.find("'", q)
|
333 |
+
if double_q < q:
|
334 |
+
double_q = code.find('"', q)
|
335 |
+
q = min(single_q, double_q)
|
336 |
+
if q == -1:
|
337 |
+
q = max(single_q, double_q)
|
338 |
+
|
339 |
+
# We're done.
|
340 |
+
if q == -1 and hash_mark == -1:
|
341 |
+
new_code.append(code[start:])
|
342 |
+
break
|
343 |
+
|
344 |
+
# Try to close the quote.
|
345 |
+
elif in_quote:
|
346 |
+
if code[q-1] == u'\\':
|
347 |
+
k = 2
|
348 |
+
while q >= k and code[q-k] == u'\\':
|
349 |
+
k += 1
|
350 |
+
if k % 2 == 0:
|
351 |
+
q += 1
|
352 |
+
continue
|
353 |
+
if code[q] == quote_type and (
|
354 |
+
quote_len == 1 or (code_len > q + 2 and quote_type == code[q+1] == code[q+2])):
|
355 |
+
counter += 1
|
356 |
+
label = "%s%s_" % (prefix, counter)
|
357 |
+
literals[label] = code[start+quote_len:q]
|
358 |
+
full_quote = code[q:q+quote_len]
|
359 |
+
new_code.append(full_quote)
|
360 |
+
new_code.append(label)
|
361 |
+
new_code.append(full_quote)
|
362 |
+
q += quote_len
|
363 |
+
in_quote = False
|
364 |
+
start = q
|
365 |
+
else:
|
366 |
+
q += 1
|
367 |
+
|
368 |
+
# Process comment.
|
369 |
+
elif -1 != hash_mark and (hash_mark < q or q == -1):
|
370 |
+
new_code.append(code[start:hash_mark+1])
|
371 |
+
end = code.find('\n', hash_mark)
|
372 |
+
counter += 1
|
373 |
+
label = "%s%s_" % (prefix, counter)
|
374 |
+
if end == -1:
|
375 |
+
end_or_none = None
|
376 |
+
else:
|
377 |
+
end_or_none = end
|
378 |
+
literals[label] = code[hash_mark+1:end_or_none]
|
379 |
+
new_code.append(label)
|
380 |
+
if end == -1:
|
381 |
+
break
|
382 |
+
start = q = end
|
383 |
+
|
384 |
+
# Open the quote.
|
385 |
+
else:
|
386 |
+
if code_len >= q+3 and (code[q] == code[q+1] == code[q+2]):
|
387 |
+
quote_len = 3
|
388 |
+
else:
|
389 |
+
quote_len = 1
|
390 |
+
in_quote = True
|
391 |
+
quote_type = code[q]
|
392 |
+
new_code.append(code[start:q])
|
393 |
+
start = q
|
394 |
+
q += quote_len
|
395 |
+
|
396 |
+
return "".join(new_code), literals
|
397 |
+
|
398 |
+
|
399 |
+
# We need to allow spaces to allow for conditional compilation like
|
400 |
+
# IF ...:
|
401 |
+
# cimport ...
|
402 |
+
dependency_regex = re.compile(r"(?:^\s*from +([0-9a-zA-Z_.]+) +cimport)|"
|
403 |
+
r"(?:^\s*cimport +([0-9a-zA-Z_.]+(?: *, *[0-9a-zA-Z_.]+)*))|"
|
404 |
+
r"(?:^\s*cdef +extern +from +['\"]([^'\"]+)['\"])|"
|
405 |
+
r"(?:^\s*include +['\"]([^'\"]+)['\"])", re.M)
|
406 |
+
dependency_after_from_regex = re.compile(
|
407 |
+
r"(?:^\s+\(([0-9a-zA-Z_., ]*)\)[#\n])|"
|
408 |
+
r"(?:^\s+([0-9a-zA-Z_., ]*)[#\n])",
|
409 |
+
re.M)
|
410 |
+
|
411 |
+
|
412 |
+
def normalize_existing(base_path, rel_paths):
|
413 |
+
return normalize_existing0(os.path.dirname(base_path), tuple(set(rel_paths)))
|
414 |
+
|
415 |
+
|
416 |
+
@cached_function
|
417 |
+
def normalize_existing0(base_dir, rel_paths):
|
418 |
+
"""
|
419 |
+
Given some base directory ``base_dir`` and a list of path names
|
420 |
+
``rel_paths``, normalize each relative path name ``rel`` by
|
421 |
+
replacing it by ``os.path.join(base, rel)`` if that file exists.
|
422 |
+
|
423 |
+
Return a couple ``(normalized, needed_base)`` where ``normalized``
|
424 |
+
if the list of normalized file names and ``needed_base`` is
|
425 |
+
``base_dir`` if we actually needed ``base_dir``. If no paths were
|
426 |
+
changed (for example, if all paths were already absolute), then
|
427 |
+
``needed_base`` is ``None``.
|
428 |
+
"""
|
429 |
+
normalized = []
|
430 |
+
needed_base = None
|
431 |
+
for rel in rel_paths:
|
432 |
+
if os.path.isabs(rel):
|
433 |
+
normalized.append(rel)
|
434 |
+
continue
|
435 |
+
path = join_path(base_dir, rel)
|
436 |
+
if path_exists(path):
|
437 |
+
normalized.append(os.path.normpath(path))
|
438 |
+
needed_base = base_dir
|
439 |
+
else:
|
440 |
+
normalized.append(rel)
|
441 |
+
return (normalized, needed_base)
|
442 |
+
|
443 |
+
|
444 |
+
def resolve_depends(depends, include_dirs):
|
445 |
+
include_dirs = tuple(include_dirs)
|
446 |
+
resolved = []
|
447 |
+
for depend in depends:
|
448 |
+
path = resolve_depend(depend, include_dirs)
|
449 |
+
if path is not None:
|
450 |
+
resolved.append(path)
|
451 |
+
return resolved
|
452 |
+
|
453 |
+
|
454 |
+
@cached_function
|
455 |
+
def resolve_depend(depend, include_dirs):
|
456 |
+
if depend[0] == '<' and depend[-1] == '>':
|
457 |
+
return None
|
458 |
+
for dir in include_dirs:
|
459 |
+
path = join_path(dir, depend)
|
460 |
+
if path_exists(path):
|
461 |
+
return os.path.normpath(path)
|
462 |
+
return None
|
463 |
+
|
464 |
+
|
465 |
+
@cached_function
|
466 |
+
def package(filename):
|
467 |
+
dir = os.path.dirname(os.path.abspath(str(filename)))
|
468 |
+
if dir != filename and is_package_dir(dir):
|
469 |
+
return package(dir) + (os.path.basename(dir),)
|
470 |
+
else:
|
471 |
+
return ()
|
472 |
+
|
473 |
+
|
474 |
+
@cached_function
|
475 |
+
def fully_qualified_name(filename):
|
476 |
+
module = os.path.splitext(os.path.basename(filename))[0]
|
477 |
+
return '.'.join(package(filename) + (module,))
|
478 |
+
|
479 |
+
|
480 |
+
@cached_function
|
481 |
+
def parse_dependencies(source_filename):
|
482 |
+
# Actual parsing is way too slow, so we use regular expressions.
|
483 |
+
# The only catch is that we must strip comments and string
|
484 |
+
# literals ahead of time.
|
485 |
+
with Utils.open_source_file(source_filename, error_handling='ignore') as fh:
|
486 |
+
source = fh.read()
|
487 |
+
distutils_info = DistutilsInfo(source)
|
488 |
+
source, literals = strip_string_literals(source)
|
489 |
+
source = source.replace('\\\n', ' ').replace('\t', ' ')
|
490 |
+
|
491 |
+
# TODO: pure mode
|
492 |
+
cimports = []
|
493 |
+
includes = []
|
494 |
+
externs = []
|
495 |
+
for m in dependency_regex.finditer(source):
|
496 |
+
cimport_from, cimport_list, extern, include = m.groups()
|
497 |
+
if cimport_from:
|
498 |
+
cimports.append(cimport_from)
|
499 |
+
m_after_from = dependency_after_from_regex.search(source, pos=m.end())
|
500 |
+
if m_after_from:
|
501 |
+
multiline, one_line = m_after_from.groups()
|
502 |
+
subimports = multiline or one_line
|
503 |
+
cimports.extend("{0}.{1}".format(cimport_from, s.strip())
|
504 |
+
for s in subimports.split(','))
|
505 |
+
|
506 |
+
elif cimport_list:
|
507 |
+
cimports.extend(x.strip() for x in cimport_list.split(","))
|
508 |
+
elif extern:
|
509 |
+
externs.append(literals[extern])
|
510 |
+
else:
|
511 |
+
includes.append(literals[include])
|
512 |
+
return cimports, includes, externs, distutils_info
|
513 |
+
|
514 |
+
|
515 |
+
class DependencyTree(object):
|
516 |
+
|
517 |
+
def __init__(self, context, quiet=False):
|
518 |
+
self.context = context
|
519 |
+
self.quiet = quiet
|
520 |
+
self._transitive_cache = {}
|
521 |
+
|
522 |
+
def parse_dependencies(self, source_filename):
|
523 |
+
if path_exists(source_filename):
|
524 |
+
source_filename = os.path.normpath(source_filename)
|
525 |
+
return parse_dependencies(source_filename)
|
526 |
+
|
527 |
+
@cached_method
|
528 |
+
def included_files(self, filename):
|
529 |
+
# This is messy because included files are textually included, resolving
|
530 |
+
# cimports (but not includes) relative to the including file.
|
531 |
+
all = set()
|
532 |
+
for include in self.parse_dependencies(filename)[1]:
|
533 |
+
include_path = join_path(os.path.dirname(filename), include)
|
534 |
+
if not path_exists(include_path):
|
535 |
+
include_path = self.context.find_include_file(include, None)
|
536 |
+
if include_path:
|
537 |
+
if '.' + os.path.sep in include_path:
|
538 |
+
include_path = os.path.normpath(include_path)
|
539 |
+
all.add(include_path)
|
540 |
+
all.update(self.included_files(include_path))
|
541 |
+
elif not self.quiet:
|
542 |
+
print("Unable to locate '%s' referenced from '%s'" % (filename, include))
|
543 |
+
return all
|
544 |
+
|
545 |
+
@cached_method
|
546 |
+
def cimports_externs_incdirs(self, filename):
|
547 |
+
# This is really ugly. Nested cimports are resolved with respect to the
|
548 |
+
# includer, but includes are resolved with respect to the includee.
|
549 |
+
cimports, includes, externs = self.parse_dependencies(filename)[:3]
|
550 |
+
cimports = set(cimports)
|
551 |
+
externs = set(externs)
|
552 |
+
incdirs = set()
|
553 |
+
for include in self.included_files(filename):
|
554 |
+
included_cimports, included_externs, included_incdirs = self.cimports_externs_incdirs(include)
|
555 |
+
cimports.update(included_cimports)
|
556 |
+
externs.update(included_externs)
|
557 |
+
incdirs.update(included_incdirs)
|
558 |
+
externs, incdir = normalize_existing(filename, externs)
|
559 |
+
if incdir:
|
560 |
+
incdirs.add(incdir)
|
561 |
+
return tuple(cimports), externs, incdirs
|
562 |
+
|
563 |
+
def cimports(self, filename):
|
564 |
+
return self.cimports_externs_incdirs(filename)[0]
|
565 |
+
|
566 |
+
def package(self, filename):
|
567 |
+
return package(filename)
|
568 |
+
|
569 |
+
def fully_qualified_name(self, filename):
|
570 |
+
return fully_qualified_name(filename)
|
571 |
+
|
572 |
+
@cached_method
|
573 |
+
def find_pxd(self, module, filename=None):
|
574 |
+
is_relative = module[0] == '.'
|
575 |
+
if is_relative and not filename:
|
576 |
+
raise NotImplementedError("New relative imports.")
|
577 |
+
if filename is not None:
|
578 |
+
module_path = module.split('.')
|
579 |
+
if is_relative:
|
580 |
+
module_path.pop(0) # just explicitly relative
|
581 |
+
package_path = list(self.package(filename))
|
582 |
+
while module_path and not module_path[0]:
|
583 |
+
try:
|
584 |
+
package_path.pop()
|
585 |
+
except IndexError:
|
586 |
+
return None # FIXME: error?
|
587 |
+
module_path.pop(0)
|
588 |
+
relative = '.'.join(package_path + module_path)
|
589 |
+
pxd = self.context.find_pxd_file(relative, None)
|
590 |
+
if pxd:
|
591 |
+
return pxd
|
592 |
+
if is_relative:
|
593 |
+
return None # FIXME: error?
|
594 |
+
return self.context.find_pxd_file(module, None)
|
595 |
+
|
596 |
+
@cached_method
|
597 |
+
def cimported_files(self, filename):
|
598 |
+
if filename[-4:] == '.pyx' and path_exists(filename[:-4] + '.pxd'):
|
599 |
+
pxd_list = [filename[:-4] + '.pxd']
|
600 |
+
else:
|
601 |
+
pxd_list = []
|
602 |
+
# Cimports generates all possible combinations package.module
|
603 |
+
# when imported as from package cimport module.
|
604 |
+
for module in self.cimports(filename):
|
605 |
+
if module[:7] == 'cython.' or module == 'cython':
|
606 |
+
continue
|
607 |
+
pxd_file = self.find_pxd(module, filename)
|
608 |
+
if pxd_file is not None:
|
609 |
+
pxd_list.append(pxd_file)
|
610 |
+
return tuple(pxd_list)
|
611 |
+
|
612 |
+
@cached_method
|
613 |
+
def immediate_dependencies(self, filename):
|
614 |
+
all = set([filename])
|
615 |
+
all.update(self.cimported_files(filename))
|
616 |
+
all.update(self.included_files(filename))
|
617 |
+
return all
|
618 |
+
|
619 |
+
def all_dependencies(self, filename):
|
620 |
+
return self.transitive_merge(filename, self.immediate_dependencies, set.union)
|
621 |
+
|
622 |
+
@cached_method
|
623 |
+
def timestamp(self, filename):
|
624 |
+
return os.path.getmtime(filename)
|
625 |
+
|
626 |
+
def extract_timestamp(self, filename):
|
627 |
+
return self.timestamp(filename), filename
|
628 |
+
|
629 |
+
def newest_dependency(self, filename):
|
630 |
+
return max([self.extract_timestamp(f) for f in self.all_dependencies(filename)])
|
631 |
+
|
632 |
+
def transitive_fingerprint(self, filename, module, compilation_options):
|
633 |
+
r"""
|
634 |
+
Return a fingerprint of a cython file that is about to be cythonized.
|
635 |
+
|
636 |
+
Fingerprints are looked up in future compilations. If the fingerprint
|
637 |
+
is found, the cythonization can be skipped. The fingerprint must
|
638 |
+
incorporate everything that has an influence on the generated code.
|
639 |
+
"""
|
640 |
+
try:
|
641 |
+
m = hashlib.md5(__version__.encode('UTF-8'))
|
642 |
+
m.update(file_hash(filename).encode('UTF-8'))
|
643 |
+
for x in sorted(self.all_dependencies(filename)):
|
644 |
+
if os.path.splitext(x)[1] not in ('.c', '.cpp', '.h'):
|
645 |
+
m.update(file_hash(x).encode('UTF-8'))
|
646 |
+
# Include the module attributes that change the compilation result
|
647 |
+
# in the fingerprint. We do not iterate over module.__dict__ and
|
648 |
+
# include almost everything here as users might extend Extension
|
649 |
+
# with arbitrary (random) attributes that would lead to cache
|
650 |
+
# misses.
|
651 |
+
m.update(str((
|
652 |
+
module.language,
|
653 |
+
getattr(module, 'py_limited_api', False),
|
654 |
+
getattr(module, 'np_pythran', False)
|
655 |
+
)).encode('UTF-8'))
|
656 |
+
|
657 |
+
m.update(compilation_options.get_fingerprint().encode('UTF-8'))
|
658 |
+
return m.hexdigest()
|
659 |
+
except IOError:
|
660 |
+
return None
|
661 |
+
|
662 |
+
def distutils_info0(self, filename):
|
663 |
+
info = self.parse_dependencies(filename)[3]
|
664 |
+
kwds = info.values
|
665 |
+
cimports, externs, incdirs = self.cimports_externs_incdirs(filename)
|
666 |
+
basedir = os.getcwd()
|
667 |
+
# Add dependencies on "cdef extern from ..." files
|
668 |
+
if externs:
|
669 |
+
externs = _make_relative(externs, basedir)
|
670 |
+
if 'depends' in kwds:
|
671 |
+
kwds['depends'] = list(set(kwds['depends']).union(externs))
|
672 |
+
else:
|
673 |
+
kwds['depends'] = list(externs)
|
674 |
+
# Add include_dirs to ensure that the C compiler will find the
|
675 |
+
# "cdef extern from ..." files
|
676 |
+
if incdirs:
|
677 |
+
include_dirs = list(kwds.get('include_dirs', []))
|
678 |
+
for inc in _make_relative(incdirs, basedir):
|
679 |
+
if inc not in include_dirs:
|
680 |
+
include_dirs.append(inc)
|
681 |
+
kwds['include_dirs'] = include_dirs
|
682 |
+
return info
|
683 |
+
|
684 |
+
def distutils_info(self, filename, aliases=None, base=None):
|
685 |
+
return (self.transitive_merge(filename, self.distutils_info0, DistutilsInfo.merge)
|
686 |
+
.subs(aliases)
|
687 |
+
.merge(base))
|
688 |
+
|
689 |
+
def transitive_merge(self, node, extract, merge):
|
690 |
+
try:
|
691 |
+
seen = self._transitive_cache[extract, merge]
|
692 |
+
except KeyError:
|
693 |
+
seen = self._transitive_cache[extract, merge] = {}
|
694 |
+
return self.transitive_merge_helper(
|
695 |
+
node, extract, merge, seen, {}, self.cimported_files)[0]
|
696 |
+
|
697 |
+
def transitive_merge_helper(self, node, extract, merge, seen, stack, outgoing):
|
698 |
+
if node in seen:
|
699 |
+
return seen[node], None
|
700 |
+
deps = extract(node)
|
701 |
+
if node in stack:
|
702 |
+
return deps, node
|
703 |
+
try:
|
704 |
+
stack[node] = len(stack)
|
705 |
+
loop = None
|
706 |
+
for next in outgoing(node):
|
707 |
+
sub_deps, sub_loop = self.transitive_merge_helper(next, extract, merge, seen, stack, outgoing)
|
708 |
+
if sub_loop is not None:
|
709 |
+
if loop is not None and stack[loop] < stack[sub_loop]:
|
710 |
+
pass
|
711 |
+
else:
|
712 |
+
loop = sub_loop
|
713 |
+
deps = merge(deps, sub_deps)
|
714 |
+
if loop == node:
|
715 |
+
loop = None
|
716 |
+
if loop is None:
|
717 |
+
seen[node] = deps
|
718 |
+
return deps, loop
|
719 |
+
finally:
|
720 |
+
del stack[node]
|
721 |
+
|
722 |
+
|
723 |
+
_dep_tree = None
|
724 |
+
|
725 |
+
def create_dependency_tree(ctx=None, quiet=False):
|
726 |
+
global _dep_tree
|
727 |
+
if _dep_tree is None:
|
728 |
+
if ctx is None:
|
729 |
+
ctx = Context(["."], CompilationOptions(default_options))
|
730 |
+
_dep_tree = DependencyTree(ctx, quiet=quiet)
|
731 |
+
return _dep_tree
|
732 |
+
|
733 |
+
|
734 |
+
# If this changes, change also docs/src/reference/compilation.rst
|
735 |
+
# which mentions this function
|
736 |
+
def default_create_extension(template, kwds):
|
737 |
+
if 'depends' in kwds:
|
738 |
+
include_dirs = kwds.get('include_dirs', []) + ["."]
|
739 |
+
depends = resolve_depends(kwds['depends'], include_dirs)
|
740 |
+
kwds['depends'] = sorted(set(depends + template.depends))
|
741 |
+
|
742 |
+
t = template.__class__
|
743 |
+
ext = t(**kwds)
|
744 |
+
metadata = dict(distutils=kwds, module_name=kwds['name'])
|
745 |
+
return (ext, metadata)
|
746 |
+
|
747 |
+
|
748 |
+
# This may be useful for advanced users?
|
749 |
+
def create_extension_list(patterns, exclude=None, ctx=None, aliases=None, quiet=False, language=None,
|
750 |
+
exclude_failures=False):
|
751 |
+
if language is not None:
|
752 |
+
print('Warning: passing language={0!r} to cythonize() is deprecated. '
|
753 |
+
'Instead, put "# distutils: language={0}" in your .pyx or .pxd file(s)'.format(language))
|
754 |
+
if exclude is None:
|
755 |
+
exclude = []
|
756 |
+
if patterns is None:
|
757 |
+
return [], {}
|
758 |
+
elif isinstance(patterns, basestring) or not isinstance(patterns, Iterable):
|
759 |
+
patterns = [patterns]
|
760 |
+
explicit_modules = set([m.name for m in patterns if isinstance(m, Extension)])
|
761 |
+
seen = set()
|
762 |
+
deps = create_dependency_tree(ctx, quiet=quiet)
|
763 |
+
to_exclude = set()
|
764 |
+
if not isinstance(exclude, list):
|
765 |
+
exclude = [exclude]
|
766 |
+
for pattern in exclude:
|
767 |
+
to_exclude.update(map(os.path.abspath, extended_iglob(pattern)))
|
768 |
+
|
769 |
+
module_list = []
|
770 |
+
module_metadata = {}
|
771 |
+
|
772 |
+
# workaround for setuptools
|
773 |
+
if 'setuptools' in sys.modules:
|
774 |
+
Extension_distutils = sys.modules['setuptools.extension']._Extension
|
775 |
+
Extension_setuptools = sys.modules['setuptools'].Extension
|
776 |
+
else:
|
777 |
+
# dummy class, in case we do not have setuptools
|
778 |
+
Extension_distutils = Extension
|
779 |
+
class Extension_setuptools(Extension): pass
|
780 |
+
|
781 |
+
# if no create_extension() function is defined, use a simple
|
782 |
+
# default function.
|
783 |
+
create_extension = ctx.options.create_extension or default_create_extension
|
784 |
+
|
785 |
+
for pattern in patterns:
|
786 |
+
if isinstance(pattern, str):
|
787 |
+
filepattern = pattern
|
788 |
+
template = Extension(pattern, []) # Fake Extension without sources
|
789 |
+
name = '*'
|
790 |
+
base = None
|
791 |
+
ext_language = language
|
792 |
+
elif isinstance(pattern, (Extension_distutils, Extension_setuptools)):
|
793 |
+
cython_sources = [s for s in pattern.sources
|
794 |
+
if os.path.splitext(s)[1] in ('.py', '.pyx')]
|
795 |
+
if cython_sources:
|
796 |
+
filepattern = cython_sources[0]
|
797 |
+
if len(cython_sources) > 1:
|
798 |
+
print("Warning: Multiple cython sources found for extension '%s': %s\n"
|
799 |
+
"See http://cython.readthedocs.io/en/latest/src/userguide/sharing_declarations.html "
|
800 |
+
"for sharing declarations among Cython files." % (pattern.name, cython_sources))
|
801 |
+
else:
|
802 |
+
# ignore non-cython modules
|
803 |
+
module_list.append(pattern)
|
804 |
+
continue
|
805 |
+
template = pattern
|
806 |
+
name = template.name
|
807 |
+
base = DistutilsInfo(exn=template)
|
808 |
+
ext_language = None # do not override whatever the Extension says
|
809 |
+
else:
|
810 |
+
msg = str("pattern is not of type str nor subclass of Extension (%s)"
|
811 |
+
" but of type %s and class %s" % (repr(Extension),
|
812 |
+
type(pattern),
|
813 |
+
pattern.__class__))
|
814 |
+
raise TypeError(msg)
|
815 |
+
|
816 |
+
for file in nonempty(sorted(extended_iglob(filepattern)), "'%s' doesn't match any files" % filepattern):
|
817 |
+
if os.path.abspath(file) in to_exclude:
|
818 |
+
continue
|
819 |
+
module_name = deps.fully_qualified_name(file)
|
820 |
+
if '*' in name:
|
821 |
+
if module_name in explicit_modules:
|
822 |
+
continue
|
823 |
+
elif name:
|
824 |
+
module_name = name
|
825 |
+
|
826 |
+
Utils.raise_error_if_module_name_forbidden(module_name)
|
827 |
+
|
828 |
+
if module_name not in seen:
|
829 |
+
try:
|
830 |
+
kwds = deps.distutils_info(file, aliases, base).values
|
831 |
+
except Exception:
|
832 |
+
if exclude_failures:
|
833 |
+
continue
|
834 |
+
raise
|
835 |
+
if base is not None:
|
836 |
+
for key, value in base.values.items():
|
837 |
+
if key not in kwds:
|
838 |
+
kwds[key] = value
|
839 |
+
|
840 |
+
kwds['name'] = module_name
|
841 |
+
|
842 |
+
sources = [file] + [m for m in template.sources if m != filepattern]
|
843 |
+
if 'sources' in kwds:
|
844 |
+
# allow users to add .c files etc.
|
845 |
+
for source in kwds['sources']:
|
846 |
+
source = encode_filename_in_py2(source)
|
847 |
+
if source not in sources:
|
848 |
+
sources.append(source)
|
849 |
+
kwds['sources'] = sources
|
850 |
+
|
851 |
+
if ext_language and 'language' not in kwds:
|
852 |
+
kwds['language'] = ext_language
|
853 |
+
|
854 |
+
np_pythran = kwds.pop('np_pythran', False)
|
855 |
+
|
856 |
+
# Create the new extension
|
857 |
+
m, metadata = create_extension(template, kwds)
|
858 |
+
m.np_pythran = np_pythran or getattr(m, 'np_pythran', False)
|
859 |
+
if m.np_pythran:
|
860 |
+
update_pythran_extension(m)
|
861 |
+
module_list.append(m)
|
862 |
+
|
863 |
+
# Store metadata (this will be written as JSON in the
|
864 |
+
# generated C file but otherwise has no purpose)
|
865 |
+
module_metadata[module_name] = metadata
|
866 |
+
|
867 |
+
if file not in m.sources:
|
868 |
+
# Old setuptools unconditionally replaces .pyx with .c/.cpp
|
869 |
+
target_file = os.path.splitext(file)[0] + ('.cpp' if m.language == 'c++' else '.c')
|
870 |
+
try:
|
871 |
+
m.sources.remove(target_file)
|
872 |
+
except ValueError:
|
873 |
+
# never seen this in the wild, but probably better to warn about this unexpected case
|
874 |
+
print("Warning: Cython source file not found in sources list, adding %s" % file)
|
875 |
+
m.sources.insert(0, file)
|
876 |
+
seen.add(name)
|
877 |
+
return module_list, module_metadata
|
878 |
+
|
879 |
+
|
880 |
+
# This is the user-exposed entry point.
|
881 |
+
def cythonize(module_list, exclude=None, nthreads=0, aliases=None, quiet=False, force=False, language=None,
|
882 |
+
exclude_failures=False, **options):
|
883 |
+
"""
|
884 |
+
Compile a set of source modules into C/C++ files and return a list of distutils
|
885 |
+
Extension objects for them.
|
886 |
+
|
887 |
+
:param module_list: As module list, pass either a glob pattern, a list of glob
|
888 |
+
patterns or a list of Extension objects. The latter
|
889 |
+
allows you to configure the extensions separately
|
890 |
+
through the normal distutils options.
|
891 |
+
You can also pass Extension objects that have
|
892 |
+
glob patterns as their sources. Then, cythonize
|
893 |
+
will resolve the pattern and create a
|
894 |
+
copy of the Extension for every matching file.
|
895 |
+
|
896 |
+
:param exclude: When passing glob patterns as ``module_list``, you can exclude certain
|
897 |
+
module names explicitly by passing them into the ``exclude`` option.
|
898 |
+
|
899 |
+
:param nthreads: The number of concurrent builds for parallel compilation
|
900 |
+
(requires the ``multiprocessing`` module).
|
901 |
+
|
902 |
+
:param aliases: If you want to use compiler directives like ``# distutils: ...`` but
|
903 |
+
can only know at compile time (when running the ``setup.py``) which values
|
904 |
+
to use, you can use aliases and pass a dictionary mapping those aliases
|
905 |
+
to Python strings when calling :func:`cythonize`. As an example, say you
|
906 |
+
want to use the compiler
|
907 |
+
directive ``# distutils: include_dirs = ../static_libs/include/``
|
908 |
+
but this path isn't always fixed and you want to find it when running
|
909 |
+
the ``setup.py``. You can then do ``# distutils: include_dirs = MY_HEADERS``,
|
910 |
+
find the value of ``MY_HEADERS`` in the ``setup.py``, put it in a python
|
911 |
+
variable called ``foo`` as a string, and then call
|
912 |
+
``cythonize(..., aliases={'MY_HEADERS': foo})``.
|
913 |
+
|
914 |
+
:param quiet: If True, Cython won't print error, warning, or status messages during the
|
915 |
+
compilation.
|
916 |
+
|
917 |
+
:param force: Forces the recompilation of the Cython modules, even if the timestamps
|
918 |
+
don't indicate that a recompilation is necessary.
|
919 |
+
|
920 |
+
:param language: To globally enable C++ mode, you can pass ``language='c++'``. Otherwise, this
|
921 |
+
will be determined at a per-file level based on compiler directives. This
|
922 |
+
affects only modules found based on file names. Extension instances passed
|
923 |
+
into :func:`cythonize` will not be changed. It is recommended to rather
|
924 |
+
use the compiler directive ``# distutils: language = c++`` than this option.
|
925 |
+
|
926 |
+
:param exclude_failures: For a broad 'try to compile' mode that ignores compilation
|
927 |
+
failures and simply excludes the failed extensions,
|
928 |
+
pass ``exclude_failures=True``. Note that this only
|
929 |
+
really makes sense for compiling ``.py`` files which can also
|
930 |
+
be used without compilation.
|
931 |
+
|
932 |
+
:param annotate: If ``True``, will produce a HTML file for each of the ``.pyx`` or ``.py``
|
933 |
+
files compiled. The HTML file gives an indication
|
934 |
+
of how much Python interaction there is in
|
935 |
+
each of the source code lines, compared to plain C code.
|
936 |
+
It also allows you to see the C/C++ code
|
937 |
+
generated for each line of Cython code. This report is invaluable when
|
938 |
+
optimizing a function for speed,
|
939 |
+
and for determining when to :ref:`release the GIL <nogil>`:
|
940 |
+
in general, a ``nogil`` block may contain only "white" code.
|
941 |
+
See examples in :ref:`determining_where_to_add_types` or
|
942 |
+
:ref:`primes`.
|
943 |
+
|
944 |
+
:param compiler_directives: Allow to set compiler directives in the ``setup.py`` like this:
|
945 |
+
``compiler_directives={'embedsignature': True}``.
|
946 |
+
See :ref:`compiler-directives`.
|
947 |
+
|
948 |
+
:param depfile: produce depfiles for the sources if True.
|
949 |
+
"""
|
950 |
+
if exclude is None:
|
951 |
+
exclude = []
|
952 |
+
if 'include_path' not in options:
|
953 |
+
options['include_path'] = ['.']
|
954 |
+
if 'common_utility_include_dir' in options:
|
955 |
+
safe_makedirs(options['common_utility_include_dir'])
|
956 |
+
|
957 |
+
depfile = options.pop('depfile', None)
|
958 |
+
|
959 |
+
if pythran is None:
|
960 |
+
pythran_options = None
|
961 |
+
else:
|
962 |
+
pythran_options = CompilationOptions(**options)
|
963 |
+
pythran_options.cplus = True
|
964 |
+
pythran_options.np_pythran = True
|
965 |
+
|
966 |
+
if force is None:
|
967 |
+
force = os.environ.get("CYTHON_FORCE_REGEN") == "1" # allow global overrides for build systems
|
968 |
+
|
969 |
+
c_options = CompilationOptions(**options)
|
970 |
+
cpp_options = CompilationOptions(**options); cpp_options.cplus = True
|
971 |
+
ctx = c_options.create_context()
|
972 |
+
options = c_options
|
973 |
+
module_list, module_metadata = create_extension_list(
|
974 |
+
module_list,
|
975 |
+
exclude=exclude,
|
976 |
+
ctx=ctx,
|
977 |
+
quiet=quiet,
|
978 |
+
exclude_failures=exclude_failures,
|
979 |
+
language=language,
|
980 |
+
aliases=aliases)
|
981 |
+
deps = create_dependency_tree(ctx, quiet=quiet)
|
982 |
+
build_dir = getattr(options, 'build_dir', None)
|
983 |
+
|
984 |
+
def copy_to_build_dir(filepath, root=os.getcwd()):
|
985 |
+
filepath_abs = os.path.abspath(filepath)
|
986 |
+
if os.path.isabs(filepath):
|
987 |
+
filepath = filepath_abs
|
988 |
+
if filepath_abs.startswith(root):
|
989 |
+
# distutil extension depends are relative to cwd
|
990 |
+
mod_dir = join_path(build_dir,
|
991 |
+
os.path.dirname(_relpath(filepath, root)))
|
992 |
+
copy_once_if_newer(filepath_abs, mod_dir)
|
993 |
+
|
994 |
+
modules_by_cfile = collections.defaultdict(list)
|
995 |
+
to_compile = []
|
996 |
+
for m in module_list:
|
997 |
+
if build_dir:
|
998 |
+
for dep in m.depends:
|
999 |
+
copy_to_build_dir(dep)
|
1000 |
+
|
1001 |
+
cy_sources = [
|
1002 |
+
source for source in m.sources
|
1003 |
+
if os.path.splitext(source)[1] in ('.pyx', '.py')]
|
1004 |
+
if len(cy_sources) == 1:
|
1005 |
+
# normal "special" case: believe the Extension module name to allow user overrides
|
1006 |
+
full_module_name = m.name
|
1007 |
+
else:
|
1008 |
+
# infer FQMN from source files
|
1009 |
+
full_module_name = None
|
1010 |
+
|
1011 |
+
new_sources = []
|
1012 |
+
for source in m.sources:
|
1013 |
+
base, ext = os.path.splitext(source)
|
1014 |
+
if ext in ('.pyx', '.py'):
|
1015 |
+
if m.np_pythran:
|
1016 |
+
c_file = base + '.cpp'
|
1017 |
+
options = pythran_options
|
1018 |
+
elif m.language == 'c++':
|
1019 |
+
c_file = base + '.cpp'
|
1020 |
+
options = cpp_options
|
1021 |
+
else:
|
1022 |
+
c_file = base + '.c'
|
1023 |
+
options = c_options
|
1024 |
+
|
1025 |
+
# setup for out of place build directory if enabled
|
1026 |
+
if build_dir:
|
1027 |
+
if os.path.isabs(c_file):
|
1028 |
+
warnings.warn("build_dir has no effect for absolute source paths")
|
1029 |
+
c_file = os.path.join(build_dir, c_file)
|
1030 |
+
dir = os.path.dirname(c_file)
|
1031 |
+
safe_makedirs_once(dir)
|
1032 |
+
|
1033 |
+
# write out the depfile, if requested
|
1034 |
+
if depfile:
|
1035 |
+
dependencies = deps.all_dependencies(source)
|
1036 |
+
write_depfile(c_file, source, dependencies)
|
1037 |
+
|
1038 |
+
if os.path.exists(c_file):
|
1039 |
+
c_timestamp = os.path.getmtime(c_file)
|
1040 |
+
else:
|
1041 |
+
c_timestamp = -1
|
1042 |
+
|
1043 |
+
# Priority goes first to modified files, second to direct
|
1044 |
+
# dependents, and finally to indirect dependents.
|
1045 |
+
if c_timestamp < deps.timestamp(source):
|
1046 |
+
dep_timestamp, dep = deps.timestamp(source), source
|
1047 |
+
priority = 0
|
1048 |
+
else:
|
1049 |
+
dep_timestamp, dep = deps.newest_dependency(source)
|
1050 |
+
priority = 2 - (dep in deps.immediate_dependencies(source))
|
1051 |
+
if force or c_timestamp < dep_timestamp:
|
1052 |
+
if not quiet and not force:
|
1053 |
+
if source == dep:
|
1054 |
+
print("Compiling %s because it changed." % source)
|
1055 |
+
else:
|
1056 |
+
print("Compiling %s because it depends on %s." % (source, dep))
|
1057 |
+
if not force and options.cache:
|
1058 |
+
fingerprint = deps.transitive_fingerprint(source, m, options)
|
1059 |
+
else:
|
1060 |
+
fingerprint = None
|
1061 |
+
to_compile.append((
|
1062 |
+
priority, source, c_file, fingerprint, quiet,
|
1063 |
+
options, not exclude_failures, module_metadata.get(m.name),
|
1064 |
+
full_module_name))
|
1065 |
+
new_sources.append(c_file)
|
1066 |
+
modules_by_cfile[c_file].append(m)
|
1067 |
+
else:
|
1068 |
+
new_sources.append(source)
|
1069 |
+
if build_dir:
|
1070 |
+
copy_to_build_dir(source)
|
1071 |
+
m.sources = new_sources
|
1072 |
+
|
1073 |
+
if options.cache:
|
1074 |
+
if not os.path.exists(options.cache):
|
1075 |
+
os.makedirs(options.cache)
|
1076 |
+
to_compile.sort()
|
1077 |
+
# Drop "priority" component of "to_compile" entries and add a
|
1078 |
+
# simple progress indicator.
|
1079 |
+
N = len(to_compile)
|
1080 |
+
progress_fmt = "[{0:%d}/{1}] " % len(str(N))
|
1081 |
+
for i in range(N):
|
1082 |
+
progress = progress_fmt.format(i+1, N)
|
1083 |
+
to_compile[i] = to_compile[i][1:] + (progress,)
|
1084 |
+
|
1085 |
+
if N <= 1:
|
1086 |
+
nthreads = 0
|
1087 |
+
if nthreads:
|
1088 |
+
# Requires multiprocessing (or Python >= 2.6)
|
1089 |
+
try:
|
1090 |
+
import multiprocessing
|
1091 |
+
pool = multiprocessing.Pool(
|
1092 |
+
nthreads, initializer=_init_multiprocessing_helper)
|
1093 |
+
except (ImportError, OSError):
|
1094 |
+
print("multiprocessing required for parallel cythonization")
|
1095 |
+
nthreads = 0
|
1096 |
+
else:
|
1097 |
+
# This is a bit more involved than it should be, because KeyboardInterrupts
|
1098 |
+
# break the multiprocessing workers when using a normal pool.map().
|
1099 |
+
# See, for example:
|
1100 |
+
# http://noswap.com/blog/python-multiprocessing-keyboardinterrupt
|
1101 |
+
try:
|
1102 |
+
result = pool.map_async(cythonize_one_helper, to_compile, chunksize=1)
|
1103 |
+
pool.close()
|
1104 |
+
while not result.ready():
|
1105 |
+
try:
|
1106 |
+
result.get(99999) # seconds
|
1107 |
+
except multiprocessing.TimeoutError:
|
1108 |
+
pass
|
1109 |
+
except KeyboardInterrupt:
|
1110 |
+
pool.terminate()
|
1111 |
+
raise
|
1112 |
+
pool.join()
|
1113 |
+
if not nthreads:
|
1114 |
+
for args in to_compile:
|
1115 |
+
cythonize_one(*args)
|
1116 |
+
|
1117 |
+
if exclude_failures:
|
1118 |
+
failed_modules = set()
|
1119 |
+
for c_file, modules in modules_by_cfile.items():
|
1120 |
+
if not os.path.exists(c_file):
|
1121 |
+
failed_modules.update(modules)
|
1122 |
+
elif os.path.getsize(c_file) < 200:
|
1123 |
+
f = io_open(c_file, 'r', encoding='iso8859-1')
|
1124 |
+
try:
|
1125 |
+
if f.read(len('#error ')) == '#error ':
|
1126 |
+
# dead compilation result
|
1127 |
+
failed_modules.update(modules)
|
1128 |
+
finally:
|
1129 |
+
f.close()
|
1130 |
+
if failed_modules:
|
1131 |
+
for module in failed_modules:
|
1132 |
+
module_list.remove(module)
|
1133 |
+
print("Failed compilations: %s" % ', '.join(sorted([
|
1134 |
+
module.name for module in failed_modules])))
|
1135 |
+
|
1136 |
+
if options.cache:
|
1137 |
+
cleanup_cache(options.cache, getattr(options, 'cache_size', 1024 * 1024 * 100))
|
1138 |
+
# cythonize() is often followed by the (non-Python-buffered)
|
1139 |
+
# compiler output, flush now to avoid interleaving output.
|
1140 |
+
sys.stdout.flush()
|
1141 |
+
return module_list
|
1142 |
+
|
1143 |
+
|
1144 |
+
if os.environ.get('XML_RESULTS'):
|
1145 |
+
compile_result_dir = os.environ['XML_RESULTS']
|
1146 |
+
def record_results(func):
|
1147 |
+
def with_record(*args):
|
1148 |
+
t = time.time()
|
1149 |
+
success = True
|
1150 |
+
try:
|
1151 |
+
try:
|
1152 |
+
func(*args)
|
1153 |
+
except:
|
1154 |
+
success = False
|
1155 |
+
finally:
|
1156 |
+
t = time.time() - t
|
1157 |
+
module = fully_qualified_name(args[0])
|
1158 |
+
name = "cythonize." + module
|
1159 |
+
failures = 1 - success
|
1160 |
+
if success:
|
1161 |
+
failure_item = ""
|
1162 |
+
else:
|
1163 |
+
failure_item = "failure"
|
1164 |
+
output = open(os.path.join(compile_result_dir, name + ".xml"), "w")
|
1165 |
+
output.write("""
|
1166 |
+
<?xml version="1.0" ?>
|
1167 |
+
<testsuite name="%(name)s" errors="0" failures="%(failures)s" tests="1" time="%(t)s">
|
1168 |
+
<testcase classname="%(name)s" name="cythonize">
|
1169 |
+
%(failure_item)s
|
1170 |
+
</testcase>
|
1171 |
+
</testsuite>
|
1172 |
+
""".strip() % locals())
|
1173 |
+
output.close()
|
1174 |
+
return with_record
|
1175 |
+
else:
|
1176 |
+
def record_results(func):
|
1177 |
+
return func
|
1178 |
+
|
1179 |
+
|
1180 |
+
# TODO: Share context? Issue: pyx processing leaks into pxd module
|
1181 |
+
@record_results
|
1182 |
+
def cythonize_one(pyx_file, c_file, fingerprint, quiet, options=None,
|
1183 |
+
raise_on_failure=True, embedded_metadata=None, full_module_name=None,
|
1184 |
+
progress=""):
|
1185 |
+
from ..Compiler.Main import compile_single, default_options
|
1186 |
+
from ..Compiler.Errors import CompileError, PyrexError
|
1187 |
+
|
1188 |
+
if fingerprint:
|
1189 |
+
if not os.path.exists(options.cache):
|
1190 |
+
safe_makedirs(options.cache)
|
1191 |
+
# Cython-generated c files are highly compressible.
|
1192 |
+
# (E.g. a compression ratio of about 10 for Sage).
|
1193 |
+
fingerprint_file_base = join_path(
|
1194 |
+
options.cache, "%s-%s" % (os.path.basename(c_file), fingerprint))
|
1195 |
+
gz_fingerprint_file = fingerprint_file_base + gzip_ext
|
1196 |
+
zip_fingerprint_file = fingerprint_file_base + '.zip'
|
1197 |
+
if os.path.exists(gz_fingerprint_file) or os.path.exists(zip_fingerprint_file):
|
1198 |
+
if not quiet:
|
1199 |
+
print("%sFound compiled %s in cache" % (progress, pyx_file))
|
1200 |
+
if os.path.exists(gz_fingerprint_file):
|
1201 |
+
os.utime(gz_fingerprint_file, None)
|
1202 |
+
with contextlib.closing(gzip_open(gz_fingerprint_file, 'rb')) as g:
|
1203 |
+
with contextlib.closing(open(c_file, 'wb')) as f:
|
1204 |
+
shutil.copyfileobj(g, f)
|
1205 |
+
else:
|
1206 |
+
os.utime(zip_fingerprint_file, None)
|
1207 |
+
dirname = os.path.dirname(c_file)
|
1208 |
+
with contextlib.closing(zipfile.ZipFile(zip_fingerprint_file)) as z:
|
1209 |
+
for artifact in z.namelist():
|
1210 |
+
z.extract(artifact, os.path.join(dirname, artifact))
|
1211 |
+
return
|
1212 |
+
if not quiet:
|
1213 |
+
print("%sCythonizing %s" % (progress, pyx_file))
|
1214 |
+
if options is None:
|
1215 |
+
options = CompilationOptions(default_options)
|
1216 |
+
options.output_file = c_file
|
1217 |
+
options.embedded_metadata = embedded_metadata
|
1218 |
+
|
1219 |
+
any_failures = 0
|
1220 |
+
try:
|
1221 |
+
result = compile_single(pyx_file, options, full_module_name=full_module_name)
|
1222 |
+
if result.num_errors > 0:
|
1223 |
+
any_failures = 1
|
1224 |
+
except (EnvironmentError, PyrexError) as e:
|
1225 |
+
sys.stderr.write('%s\n' % e)
|
1226 |
+
any_failures = 1
|
1227 |
+
# XXX
|
1228 |
+
import traceback
|
1229 |
+
traceback.print_exc()
|
1230 |
+
except Exception:
|
1231 |
+
if raise_on_failure:
|
1232 |
+
raise
|
1233 |
+
import traceback
|
1234 |
+
traceback.print_exc()
|
1235 |
+
any_failures = 1
|
1236 |
+
if any_failures:
|
1237 |
+
if raise_on_failure:
|
1238 |
+
raise CompileError(None, pyx_file)
|
1239 |
+
elif os.path.exists(c_file):
|
1240 |
+
os.remove(c_file)
|
1241 |
+
elif fingerprint:
|
1242 |
+
artifacts = list(filter(None, [
|
1243 |
+
getattr(result, attr, None)
|
1244 |
+
for attr in ('c_file', 'h_file', 'api_file', 'i_file')]))
|
1245 |
+
if len(artifacts) == 1:
|
1246 |
+
fingerprint_file = gz_fingerprint_file
|
1247 |
+
with contextlib.closing(open(c_file, 'rb')) as f:
|
1248 |
+
with contextlib.closing(gzip_open(fingerprint_file + '.tmp', 'wb')) as g:
|
1249 |
+
shutil.copyfileobj(f, g)
|
1250 |
+
else:
|
1251 |
+
fingerprint_file = zip_fingerprint_file
|
1252 |
+
with contextlib.closing(zipfile.ZipFile(
|
1253 |
+
fingerprint_file + '.tmp', 'w', zipfile_compression_mode)) as zip:
|
1254 |
+
for artifact in artifacts:
|
1255 |
+
zip.write(artifact, os.path.basename(artifact))
|
1256 |
+
os.rename(fingerprint_file + '.tmp', fingerprint_file)
|
1257 |
+
|
1258 |
+
|
1259 |
+
def cythonize_one_helper(m):
|
1260 |
+
import traceback
|
1261 |
+
try:
|
1262 |
+
return cythonize_one(*m)
|
1263 |
+
except Exception:
|
1264 |
+
traceback.print_exc()
|
1265 |
+
raise
|
1266 |
+
|
1267 |
+
|
1268 |
+
def _init_multiprocessing_helper():
|
1269 |
+
# KeyboardInterrupt kills workers, so don't let them get it
|
1270 |
+
import signal
|
1271 |
+
signal.signal(signal.SIGINT, signal.SIG_IGN)
|
1272 |
+
|
1273 |
+
|
1274 |
+
def cleanup_cache(cache, target_size, ratio=.85):
|
1275 |
+
try:
|
1276 |
+
p = subprocess.Popen(['du', '-s', '-k', os.path.abspath(cache)], stdout=subprocess.PIPE)
|
1277 |
+
res = p.wait()
|
1278 |
+
if res == 0:
|
1279 |
+
total_size = 1024 * int(p.stdout.read().strip().split()[0])
|
1280 |
+
if total_size < target_size:
|
1281 |
+
return
|
1282 |
+
except (OSError, ValueError):
|
1283 |
+
pass
|
1284 |
+
total_size = 0
|
1285 |
+
all = []
|
1286 |
+
for file in os.listdir(cache):
|
1287 |
+
path = join_path(cache, file)
|
1288 |
+
s = os.stat(path)
|
1289 |
+
total_size += s.st_size
|
1290 |
+
all.append((s.st_atime, s.st_size, path))
|
1291 |
+
if total_size > target_size:
|
1292 |
+
for time, size, file in reversed(sorted(all)):
|
1293 |
+
os.unlink(file)
|
1294 |
+
total_size -= size
|
1295 |
+
if total_size < target_size * ratio:
|
1296 |
+
break
|
venv/Lib/site-packages/Cython/Build/Distutils.py
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
from Cython.Distutils.build_ext import build_ext
|
venv/Lib/site-packages/Cython/Build/Inline.py
ADDED
@@ -0,0 +1,377 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from __future__ import absolute_import
|
2 |
+
|
3 |
+
import hashlib
|
4 |
+
import inspect
|
5 |
+
import os
|
6 |
+
import re
|
7 |
+
import sys
|
8 |
+
|
9 |
+
from distutils.core import Distribution, Extension
|
10 |
+
from distutils.command.build_ext import build_ext
|
11 |
+
|
12 |
+
import Cython
|
13 |
+
from ..Compiler.Main import Context, default_options
|
14 |
+
|
15 |
+
from ..Compiler.Visitor import CythonTransform, EnvTransform
|
16 |
+
from ..Compiler.ParseTreeTransforms import SkipDeclarations
|
17 |
+
from ..Compiler.TreeFragment import parse_from_strings
|
18 |
+
from ..Compiler.StringEncoding import _unicode
|
19 |
+
from .Dependencies import strip_string_literals, cythonize, cached_function
|
20 |
+
from ..Compiler import Pipeline
|
21 |
+
from ..Utils import get_cython_cache_dir
|
22 |
+
import cython as cython_module
|
23 |
+
|
24 |
+
|
25 |
+
IS_PY3 = sys.version_info >= (3,)
|
26 |
+
|
27 |
+
# A utility function to convert user-supplied ASCII strings to unicode.
|
28 |
+
if not IS_PY3:
|
29 |
+
def to_unicode(s):
|
30 |
+
if isinstance(s, bytes):
|
31 |
+
return s.decode('ascii')
|
32 |
+
else:
|
33 |
+
return s
|
34 |
+
else:
|
35 |
+
to_unicode = lambda x: x
|
36 |
+
|
37 |
+
if sys.version_info < (3, 5):
|
38 |
+
import imp
|
39 |
+
def load_dynamic(name, module_path):
|
40 |
+
return imp.load_dynamic(name, module_path)
|
41 |
+
else:
|
42 |
+
import importlib.util
|
43 |
+
from importlib.machinery import ExtensionFileLoader
|
44 |
+
|
45 |
+
def load_dynamic(name, path):
|
46 |
+
spec = importlib.util.spec_from_file_location(name, loader=ExtensionFileLoader(name, path))
|
47 |
+
module = importlib.util.module_from_spec(spec)
|
48 |
+
spec.loader.exec_module(module)
|
49 |
+
return module
|
50 |
+
|
51 |
+
class UnboundSymbols(EnvTransform, SkipDeclarations):
|
52 |
+
def __init__(self):
|
53 |
+
CythonTransform.__init__(self, None)
|
54 |
+
self.unbound = set()
|
55 |
+
def visit_NameNode(self, node):
|
56 |
+
if not self.current_env().lookup(node.name):
|
57 |
+
self.unbound.add(node.name)
|
58 |
+
return node
|
59 |
+
def __call__(self, node):
|
60 |
+
super(UnboundSymbols, self).__call__(node)
|
61 |
+
return self.unbound
|
62 |
+
|
63 |
+
|
64 |
+
@cached_function
|
65 |
+
def unbound_symbols(code, context=None):
|
66 |
+
code = to_unicode(code)
|
67 |
+
if context is None:
|
68 |
+
context = Context([], default_options)
|
69 |
+
from ..Compiler.ParseTreeTransforms import AnalyseDeclarationsTransform
|
70 |
+
tree = parse_from_strings('(tree fragment)', code)
|
71 |
+
for phase in Pipeline.create_pipeline(context, 'pyx'):
|
72 |
+
if phase is None:
|
73 |
+
continue
|
74 |
+
tree = phase(tree)
|
75 |
+
if isinstance(phase, AnalyseDeclarationsTransform):
|
76 |
+
break
|
77 |
+
try:
|
78 |
+
import builtins
|
79 |
+
except ImportError:
|
80 |
+
import __builtin__ as builtins
|
81 |
+
return tuple(UnboundSymbols()(tree) - set(dir(builtins)))
|
82 |
+
|
83 |
+
|
84 |
+
def unsafe_type(arg, context=None):
|
85 |
+
py_type = type(arg)
|
86 |
+
if py_type is int:
|
87 |
+
return 'long'
|
88 |
+
else:
|
89 |
+
return safe_type(arg, context)
|
90 |
+
|
91 |
+
|
92 |
+
def safe_type(arg, context=None):
|
93 |
+
py_type = type(arg)
|
94 |
+
if py_type in (list, tuple, dict, str):
|
95 |
+
return py_type.__name__
|
96 |
+
elif py_type is complex:
|
97 |
+
return 'double complex'
|
98 |
+
elif py_type is float:
|
99 |
+
return 'double'
|
100 |
+
elif py_type is bool:
|
101 |
+
return 'bint'
|
102 |
+
elif 'numpy' in sys.modules and isinstance(arg, sys.modules['numpy'].ndarray):
|
103 |
+
return 'numpy.ndarray[numpy.%s_t, ndim=%s]' % (arg.dtype.name, arg.ndim)
|
104 |
+
else:
|
105 |
+
for base_type in py_type.__mro__:
|
106 |
+
if base_type.__module__ in ('__builtin__', 'builtins'):
|
107 |
+
return 'object'
|
108 |
+
module = context.find_module(base_type.__module__, need_pxd=False)
|
109 |
+
if module:
|
110 |
+
entry = module.lookup(base_type.__name__)
|
111 |
+
if entry.is_type:
|
112 |
+
return '%s.%s' % (base_type.__module__, base_type.__name__)
|
113 |
+
return 'object'
|
114 |
+
|
115 |
+
|
116 |
+
def _get_build_extension():
|
117 |
+
dist = Distribution()
|
118 |
+
# Ensure the build respects distutils configuration by parsing
|
119 |
+
# the configuration files
|
120 |
+
config_files = dist.find_config_files()
|
121 |
+
dist.parse_config_files(config_files)
|
122 |
+
build_extension = build_ext(dist)
|
123 |
+
build_extension.finalize_options()
|
124 |
+
return build_extension
|
125 |
+
|
126 |
+
|
127 |
+
@cached_function
|
128 |
+
def _create_context(cython_include_dirs):
|
129 |
+
return Context(list(cython_include_dirs), default_options)
|
130 |
+
|
131 |
+
|
132 |
+
_cython_inline_cache = {}
|
133 |
+
_cython_inline_default_context = _create_context(('.',))
|
134 |
+
|
135 |
+
|
136 |
+
def _populate_unbound(kwds, unbound_symbols, locals=None, globals=None):
|
137 |
+
for symbol in unbound_symbols:
|
138 |
+
if symbol not in kwds:
|
139 |
+
if locals is None or globals is None:
|
140 |
+
calling_frame = inspect.currentframe().f_back.f_back.f_back
|
141 |
+
if locals is None:
|
142 |
+
locals = calling_frame.f_locals
|
143 |
+
if globals is None:
|
144 |
+
globals = calling_frame.f_globals
|
145 |
+
if symbol in locals:
|
146 |
+
kwds[symbol] = locals[symbol]
|
147 |
+
elif symbol in globals:
|
148 |
+
kwds[symbol] = globals[symbol]
|
149 |
+
else:
|
150 |
+
print("Couldn't find %r" % symbol)
|
151 |
+
|
152 |
+
|
153 |
+
def _inline_key(orig_code, arg_sigs, language_level):
|
154 |
+
key = orig_code, arg_sigs, sys.version_info, sys.executable, language_level, Cython.__version__
|
155 |
+
return hashlib.sha1(_unicode(key).encode('utf-8')).hexdigest()
|
156 |
+
|
157 |
+
|
158 |
+
def cython_inline(code, get_type=unsafe_type,
|
159 |
+
lib_dir=os.path.join(get_cython_cache_dir(), 'inline'),
|
160 |
+
cython_include_dirs=None, cython_compiler_directives=None,
|
161 |
+
force=False, quiet=False, locals=None, globals=None, language_level=None, **kwds):
|
162 |
+
|
163 |
+
if get_type is None:
|
164 |
+
get_type = lambda x: 'object'
|
165 |
+
ctx = _create_context(tuple(cython_include_dirs)) if cython_include_dirs else _cython_inline_default_context
|
166 |
+
|
167 |
+
cython_compiler_directives = dict(cython_compiler_directives) if cython_compiler_directives else {}
|
168 |
+
if language_level is None and 'language_level' not in cython_compiler_directives:
|
169 |
+
language_level = '3str'
|
170 |
+
if language_level is not None:
|
171 |
+
cython_compiler_directives['language_level'] = language_level
|
172 |
+
|
173 |
+
# Fast path if this has been called in this session.
|
174 |
+
_unbound_symbols = _cython_inline_cache.get(code)
|
175 |
+
if _unbound_symbols is not None:
|
176 |
+
_populate_unbound(kwds, _unbound_symbols, locals, globals)
|
177 |
+
args = sorted(kwds.items())
|
178 |
+
arg_sigs = tuple([(get_type(value, ctx), arg) for arg, value in args])
|
179 |
+
key_hash = _inline_key(code, arg_sigs, language_level)
|
180 |
+
invoke = _cython_inline_cache.get((code, arg_sigs, key_hash))
|
181 |
+
if invoke is not None:
|
182 |
+
arg_list = [arg[1] for arg in args]
|
183 |
+
return invoke(*arg_list)
|
184 |
+
|
185 |
+
orig_code = code
|
186 |
+
code = to_unicode(code)
|
187 |
+
code, literals = strip_string_literals(code)
|
188 |
+
code = strip_common_indent(code)
|
189 |
+
if locals is None:
|
190 |
+
locals = inspect.currentframe().f_back.f_back.f_locals
|
191 |
+
if globals is None:
|
192 |
+
globals = inspect.currentframe().f_back.f_back.f_globals
|
193 |
+
try:
|
194 |
+
_cython_inline_cache[orig_code] = _unbound_symbols = unbound_symbols(code)
|
195 |
+
_populate_unbound(kwds, _unbound_symbols, locals, globals)
|
196 |
+
except AssertionError:
|
197 |
+
if not quiet:
|
198 |
+
# Parsing from strings not fully supported (e.g. cimports).
|
199 |
+
print("Could not parse code as a string (to extract unbound symbols).")
|
200 |
+
|
201 |
+
cimports = []
|
202 |
+
for name, arg in list(kwds.items()):
|
203 |
+
if arg is cython_module:
|
204 |
+
cimports.append('\ncimport cython as %s' % name)
|
205 |
+
del kwds[name]
|
206 |
+
arg_names = sorted(kwds)
|
207 |
+
arg_sigs = tuple([(get_type(kwds[arg], ctx), arg) for arg in arg_names])
|
208 |
+
key_hash = _inline_key(orig_code, arg_sigs, language_level)
|
209 |
+
module_name = "_cython_inline_" + key_hash
|
210 |
+
|
211 |
+
if module_name in sys.modules:
|
212 |
+
module = sys.modules[module_name]
|
213 |
+
|
214 |
+
else:
|
215 |
+
build_extension = None
|
216 |
+
if cython_inline.so_ext is None:
|
217 |
+
# Figure out and cache current extension suffix
|
218 |
+
build_extension = _get_build_extension()
|
219 |
+
cython_inline.so_ext = build_extension.get_ext_filename('')
|
220 |
+
|
221 |
+
module_path = os.path.join(lib_dir, module_name + cython_inline.so_ext)
|
222 |
+
|
223 |
+
if not os.path.exists(lib_dir):
|
224 |
+
os.makedirs(lib_dir)
|
225 |
+
if force or not os.path.isfile(module_path):
|
226 |
+
cflags = []
|
227 |
+
c_include_dirs = []
|
228 |
+
qualified = re.compile(r'([.\w]+)[.]')
|
229 |
+
for type, _ in arg_sigs:
|
230 |
+
m = qualified.match(type)
|
231 |
+
if m:
|
232 |
+
cimports.append('\ncimport %s' % m.groups()[0])
|
233 |
+
# one special case
|
234 |
+
if m.groups()[0] == 'numpy':
|
235 |
+
import numpy
|
236 |
+
c_include_dirs.append(numpy.get_include())
|
237 |
+
# cflags.append('-Wno-unused')
|
238 |
+
module_body, func_body = extract_func_code(code)
|
239 |
+
params = ', '.join(['%s %s' % a for a in arg_sigs])
|
240 |
+
module_code = """
|
241 |
+
%(module_body)s
|
242 |
+
%(cimports)s
|
243 |
+
def __invoke(%(params)s):
|
244 |
+
%(func_body)s
|
245 |
+
return locals()
|
246 |
+
""" % {'cimports': '\n'.join(cimports),
|
247 |
+
'module_body': module_body,
|
248 |
+
'params': params,
|
249 |
+
'func_body': func_body }
|
250 |
+
for key, value in literals.items():
|
251 |
+
module_code = module_code.replace(key, value)
|
252 |
+
pyx_file = os.path.join(lib_dir, module_name + '.pyx')
|
253 |
+
fh = open(pyx_file, 'w')
|
254 |
+
try:
|
255 |
+
fh.write(module_code)
|
256 |
+
finally:
|
257 |
+
fh.close()
|
258 |
+
extension = Extension(
|
259 |
+
name = module_name,
|
260 |
+
sources = [pyx_file],
|
261 |
+
include_dirs = c_include_dirs,
|
262 |
+
extra_compile_args = cflags)
|
263 |
+
if build_extension is None:
|
264 |
+
build_extension = _get_build_extension()
|
265 |
+
build_extension.extensions = cythonize(
|
266 |
+
[extension],
|
267 |
+
include_path=cython_include_dirs or ['.'],
|
268 |
+
compiler_directives=cython_compiler_directives,
|
269 |
+
quiet=quiet)
|
270 |
+
build_extension.build_temp = os.path.dirname(pyx_file)
|
271 |
+
build_extension.build_lib = lib_dir
|
272 |
+
build_extension.run()
|
273 |
+
|
274 |
+
module = load_dynamic(module_name, module_path)
|
275 |
+
|
276 |
+
_cython_inline_cache[orig_code, arg_sigs, key_hash] = module.__invoke
|
277 |
+
arg_list = [kwds[arg] for arg in arg_names]
|
278 |
+
return module.__invoke(*arg_list)
|
279 |
+
|
280 |
+
|
281 |
+
# Cached suffix used by cython_inline above. None should get
|
282 |
+
# overridden with actual value upon the first cython_inline invocation
|
283 |
+
cython_inline.so_ext = None
|
284 |
+
|
285 |
+
_find_non_space = re.compile('[^ ]').search
|
286 |
+
|
287 |
+
|
288 |
+
def strip_common_indent(code):
|
289 |
+
min_indent = None
|
290 |
+
lines = code.splitlines()
|
291 |
+
for line in lines:
|
292 |
+
match = _find_non_space(line)
|
293 |
+
if not match:
|
294 |
+
continue # blank
|
295 |
+
indent = match.start()
|
296 |
+
if line[indent] == '#':
|
297 |
+
continue # comment
|
298 |
+
if min_indent is None or min_indent > indent:
|
299 |
+
min_indent = indent
|
300 |
+
for ix, line in enumerate(lines):
|
301 |
+
match = _find_non_space(line)
|
302 |
+
if not match or not line or line[indent:indent+1] == '#':
|
303 |
+
continue
|
304 |
+
lines[ix] = line[min_indent:]
|
305 |
+
return '\n'.join(lines)
|
306 |
+
|
307 |
+
|
308 |
+
module_statement = re.compile(r'^((cdef +(extern|class))|cimport|(from .+ cimport)|(from .+ import +[*]))')
|
309 |
+
def extract_func_code(code):
|
310 |
+
module = []
|
311 |
+
function = []
|
312 |
+
current = function
|
313 |
+
code = code.replace('\t', ' ')
|
314 |
+
lines = code.split('\n')
|
315 |
+
for line in lines:
|
316 |
+
if not line.startswith(' '):
|
317 |
+
if module_statement.match(line):
|
318 |
+
current = module
|
319 |
+
else:
|
320 |
+
current = function
|
321 |
+
current.append(line)
|
322 |
+
return '\n'.join(module), ' ' + '\n '.join(function)
|
323 |
+
|
324 |
+
|
325 |
+
try:
|
326 |
+
from inspect import getcallargs
|
327 |
+
except ImportError:
|
328 |
+
def getcallargs(func, *arg_values, **kwd_values):
|
329 |
+
all = {}
|
330 |
+
args, varargs, kwds, defaults = inspect.getargspec(func)
|
331 |
+
if varargs is not None:
|
332 |
+
all[varargs] = arg_values[len(args):]
|
333 |
+
for name, value in zip(args, arg_values):
|
334 |
+
all[name] = value
|
335 |
+
for name, value in list(kwd_values.items()):
|
336 |
+
if name in args:
|
337 |
+
if name in all:
|
338 |
+
raise TypeError("Duplicate argument %s" % name)
|
339 |
+
all[name] = kwd_values.pop(name)
|
340 |
+
if kwds is not None:
|
341 |
+
all[kwds] = kwd_values
|
342 |
+
elif kwd_values:
|
343 |
+
raise TypeError("Unexpected keyword arguments: %s" % list(kwd_values))
|
344 |
+
if defaults is None:
|
345 |
+
defaults = ()
|
346 |
+
first_default = len(args) - len(defaults)
|
347 |
+
for ix, name in enumerate(args):
|
348 |
+
if name not in all:
|
349 |
+
if ix >= first_default:
|
350 |
+
all[name] = defaults[ix - first_default]
|
351 |
+
else:
|
352 |
+
raise TypeError("Missing argument: %s" % name)
|
353 |
+
return all
|
354 |
+
|
355 |
+
|
356 |
+
def get_body(source):
|
357 |
+
ix = source.index(':')
|
358 |
+
if source[:5] == 'lambda':
|
359 |
+
return "return %s" % source[ix+1:]
|
360 |
+
else:
|
361 |
+
return source[ix+1:]
|
362 |
+
|
363 |
+
|
364 |
+
# Lots to be done here... It would be especially cool if compiled functions
|
365 |
+
# could invoke each other quickly.
|
366 |
+
class RuntimeCompiledFunction(object):
|
367 |
+
|
368 |
+
def __init__(self, f):
|
369 |
+
self._f = f
|
370 |
+
self._body = get_body(inspect.getsource(f))
|
371 |
+
|
372 |
+
def __call__(self, *args, **kwds):
|
373 |
+
all = getcallargs(self._f, *args, **kwds)
|
374 |
+
if IS_PY3:
|
375 |
+
return cython_inline(self._body, locals=self._f.__globals__, globals=self._f.__globals__, **all)
|
376 |
+
else:
|
377 |
+
return cython_inline(self._body, locals=self._f.func_globals, globals=self._f.func_globals, **all)
|
venv/Lib/site-packages/Cython/Build/IpythonMagic.py
ADDED
@@ -0,0 +1,564 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# -*- coding: utf-8 -*-
|
2 |
+
"""
|
3 |
+
=====================
|
4 |
+
Cython related magics
|
5 |
+
=====================
|
6 |
+
|
7 |
+
Magic command interface for interactive work with Cython
|
8 |
+
|
9 |
+
.. note::
|
10 |
+
|
11 |
+
The ``Cython`` package needs to be installed separately. It
|
12 |
+
can be obtained using ``easy_install`` or ``pip``.
|
13 |
+
|
14 |
+
Usage
|
15 |
+
=====
|
16 |
+
|
17 |
+
To enable the magics below, execute ``%load_ext cython``.
|
18 |
+
|
19 |
+
``%%cython``
|
20 |
+
|
21 |
+
{CYTHON_DOC}
|
22 |
+
|
23 |
+
``%%cython_inline``
|
24 |
+
|
25 |
+
{CYTHON_INLINE_DOC}
|
26 |
+
|
27 |
+
``%%cython_pyximport``
|
28 |
+
|
29 |
+
{CYTHON_PYXIMPORT_DOC}
|
30 |
+
|
31 |
+
Author:
|
32 |
+
* Brian Granger
|
33 |
+
|
34 |
+
Code moved from IPython and adapted by:
|
35 |
+
* Martín Gaitán
|
36 |
+
|
37 |
+
Parts of this code were taken from Cython.inline.
|
38 |
+
"""
|
39 |
+
#-----------------------------------------------------------------------------
|
40 |
+
# Copyright (C) 2010-2011, IPython Development Team.
|
41 |
+
#
|
42 |
+
# Distributed under the terms of the Modified BSD License.
|
43 |
+
#
|
44 |
+
# The full license is in the file ipython-COPYING.rst, distributed with this software.
|
45 |
+
#-----------------------------------------------------------------------------
|
46 |
+
|
47 |
+
from __future__ import absolute_import, print_function
|
48 |
+
|
49 |
+
import io
|
50 |
+
import os
|
51 |
+
import re
|
52 |
+
import sys
|
53 |
+
import time
|
54 |
+
import copy
|
55 |
+
import distutils.log
|
56 |
+
import textwrap
|
57 |
+
|
58 |
+
IO_ENCODING = sys.getfilesystemencoding()
|
59 |
+
IS_PY2 = sys.version_info[0] < 3
|
60 |
+
|
61 |
+
try:
|
62 |
+
reload
|
63 |
+
except NameError: # Python 3
|
64 |
+
from imp import reload
|
65 |
+
|
66 |
+
try:
|
67 |
+
import hashlib
|
68 |
+
except ImportError:
|
69 |
+
import md5 as hashlib
|
70 |
+
|
71 |
+
from distutils.core import Distribution, Extension
|
72 |
+
from distutils.command.build_ext import build_ext
|
73 |
+
|
74 |
+
from IPython.core import display
|
75 |
+
from IPython.core import magic_arguments
|
76 |
+
from IPython.core.magic import Magics, magics_class, cell_magic
|
77 |
+
try:
|
78 |
+
from IPython.paths import get_ipython_cache_dir
|
79 |
+
except ImportError:
|
80 |
+
# older IPython version
|
81 |
+
from IPython.utils.path import get_ipython_cache_dir
|
82 |
+
from IPython.utils.text import dedent
|
83 |
+
|
84 |
+
from ..Shadow import __version__ as cython_version
|
85 |
+
from ..Compiler.Errors import CompileError
|
86 |
+
from .Inline import cython_inline, load_dynamic
|
87 |
+
from .Dependencies import cythonize
|
88 |
+
|
89 |
+
|
90 |
+
PGO_CONFIG = {
|
91 |
+
'gcc': {
|
92 |
+
'gen': ['-fprofile-generate', '-fprofile-dir={TEMPDIR}'],
|
93 |
+
'use': ['-fprofile-use', '-fprofile-correction', '-fprofile-dir={TEMPDIR}'],
|
94 |
+
},
|
95 |
+
# blind copy from 'configure' script in CPython 3.7
|
96 |
+
'icc': {
|
97 |
+
'gen': ['-prof-gen'],
|
98 |
+
'use': ['-prof-use'],
|
99 |
+
}
|
100 |
+
}
|
101 |
+
PGO_CONFIG['mingw32'] = PGO_CONFIG['gcc']
|
102 |
+
|
103 |
+
|
104 |
+
if IS_PY2:
|
105 |
+
def encode_fs(name):
|
106 |
+
return name if isinstance(name, bytes) else name.encode(IO_ENCODING)
|
107 |
+
else:
|
108 |
+
def encode_fs(name):
|
109 |
+
return name
|
110 |
+
|
111 |
+
|
112 |
+
@magics_class
|
113 |
+
class CythonMagics(Magics):
|
114 |
+
|
115 |
+
def __init__(self, shell):
|
116 |
+
super(CythonMagics, self).__init__(shell)
|
117 |
+
self._reloads = {}
|
118 |
+
self._code_cache = {}
|
119 |
+
self._pyximport_installed = False
|
120 |
+
|
121 |
+
def _import_all(self, module):
|
122 |
+
mdict = module.__dict__
|
123 |
+
if '__all__' in mdict:
|
124 |
+
keys = mdict['__all__']
|
125 |
+
else:
|
126 |
+
keys = [k for k in mdict if not k.startswith('_')]
|
127 |
+
|
128 |
+
for k in keys:
|
129 |
+
try:
|
130 |
+
self.shell.push({k: mdict[k]})
|
131 |
+
except KeyError:
|
132 |
+
msg = "'module' object has no attribute '%s'" % k
|
133 |
+
raise AttributeError(msg)
|
134 |
+
|
135 |
+
@cell_magic
|
136 |
+
def cython_inline(self, line, cell):
|
137 |
+
"""Compile and run a Cython code cell using Cython.inline.
|
138 |
+
|
139 |
+
This magic simply passes the body of the cell to Cython.inline
|
140 |
+
and returns the result. If the variables `a` and `b` are defined
|
141 |
+
in the user's namespace, here is a simple example that returns
|
142 |
+
their sum::
|
143 |
+
|
144 |
+
%%cython_inline
|
145 |
+
return a+b
|
146 |
+
|
147 |
+
For most purposes, we recommend the usage of the `%%cython` magic.
|
148 |
+
"""
|
149 |
+
locs = self.shell.user_global_ns
|
150 |
+
globs = self.shell.user_ns
|
151 |
+
return cython_inline(cell, locals=locs, globals=globs)
|
152 |
+
|
153 |
+
@cell_magic
|
154 |
+
def cython_pyximport(self, line, cell):
|
155 |
+
"""Compile and import a Cython code cell using pyximport.
|
156 |
+
|
157 |
+
The contents of the cell are written to a `.pyx` file in the current
|
158 |
+
working directory, which is then imported using `pyximport`. This
|
159 |
+
magic requires a module name to be passed::
|
160 |
+
|
161 |
+
%%cython_pyximport modulename
|
162 |
+
def f(x):
|
163 |
+
return 2.0*x
|
164 |
+
|
165 |
+
The compiled module is then imported and all of its symbols are
|
166 |
+
injected into the user's namespace. For most purposes, we recommend
|
167 |
+
the usage of the `%%cython` magic.
|
168 |
+
"""
|
169 |
+
module_name = line.strip()
|
170 |
+
if not module_name:
|
171 |
+
raise ValueError('module name must be given')
|
172 |
+
fname = module_name + '.pyx'
|
173 |
+
with io.open(fname, 'w', encoding='utf-8') as f:
|
174 |
+
f.write(cell)
|
175 |
+
if 'pyximport' not in sys.modules or not self._pyximport_installed:
|
176 |
+
import pyximport
|
177 |
+
pyximport.install()
|
178 |
+
self._pyximport_installed = True
|
179 |
+
if module_name in self._reloads:
|
180 |
+
module = self._reloads[module_name]
|
181 |
+
# Note: reloading extension modules is not actually supported
|
182 |
+
# (requires PEP-489 reinitialisation support).
|
183 |
+
# Don't know why this should ever have worked as it reads here.
|
184 |
+
# All we really need to do is to update the globals below.
|
185 |
+
#reload(module)
|
186 |
+
else:
|
187 |
+
__import__(module_name)
|
188 |
+
module = sys.modules[module_name]
|
189 |
+
self._reloads[module_name] = module
|
190 |
+
self._import_all(module)
|
191 |
+
|
192 |
+
@magic_arguments.magic_arguments()
|
193 |
+
@magic_arguments.argument(
|
194 |
+
'-a', '--annotate', action='store_true', default=False,
|
195 |
+
help="Produce a colorized HTML version of the source."
|
196 |
+
)
|
197 |
+
@magic_arguments.argument(
|
198 |
+
'-+', '--cplus', action='store_true', default=False,
|
199 |
+
help="Output a C++ rather than C file."
|
200 |
+
)
|
201 |
+
@magic_arguments.argument(
|
202 |
+
'-3', dest='language_level', action='store_const', const=3, default=None,
|
203 |
+
help="Select Python 3 syntax."
|
204 |
+
)
|
205 |
+
@magic_arguments.argument(
|
206 |
+
'-2', dest='language_level', action='store_const', const=2, default=None,
|
207 |
+
help="Select Python 2 syntax."
|
208 |
+
)
|
209 |
+
@magic_arguments.argument(
|
210 |
+
'-f', '--force', action='store_true', default=False,
|
211 |
+
help="Force the compilation of a new module, even if the source has been "
|
212 |
+
"previously compiled."
|
213 |
+
)
|
214 |
+
@magic_arguments.argument(
|
215 |
+
'-c', '--compile-args', action='append', default=[],
|
216 |
+
help="Extra flags to pass to compiler via the `extra_compile_args` "
|
217 |
+
"Extension flag (can be specified multiple times)."
|
218 |
+
)
|
219 |
+
@magic_arguments.argument(
|
220 |
+
'--link-args', action='append', default=[],
|
221 |
+
help="Extra flags to pass to linker via the `extra_link_args` "
|
222 |
+
"Extension flag (can be specified multiple times)."
|
223 |
+
)
|
224 |
+
@magic_arguments.argument(
|
225 |
+
'-l', '--lib', action='append', default=[],
|
226 |
+
help="Add a library to link the extension against (can be specified "
|
227 |
+
"multiple times)."
|
228 |
+
)
|
229 |
+
@magic_arguments.argument(
|
230 |
+
'-n', '--name',
|
231 |
+
help="Specify a name for the Cython module."
|
232 |
+
)
|
233 |
+
@magic_arguments.argument(
|
234 |
+
'-L', dest='library_dirs', metavar='dir', action='append', default=[],
|
235 |
+
help="Add a path to the list of library directories (can be specified "
|
236 |
+
"multiple times)."
|
237 |
+
)
|
238 |
+
@magic_arguments.argument(
|
239 |
+
'-I', '--include', action='append', default=[],
|
240 |
+
help="Add a path to the list of include directories (can be specified "
|
241 |
+
"multiple times)."
|
242 |
+
)
|
243 |
+
@magic_arguments.argument(
|
244 |
+
'-S', '--src', action='append', default=[],
|
245 |
+
help="Add a path to the list of src files (can be specified "
|
246 |
+
"multiple times)."
|
247 |
+
)
|
248 |
+
@magic_arguments.argument(
|
249 |
+
'--pgo', dest='pgo', action='store_true', default=False,
|
250 |
+
help=("Enable profile guided optimisation in the C compiler. "
|
251 |
+
"Compiles the cell twice and executes it in between to generate a runtime profile.")
|
252 |
+
)
|
253 |
+
@magic_arguments.argument(
|
254 |
+
'--verbose', dest='quiet', action='store_false', default=True,
|
255 |
+
help=("Print debug information like generated .c/.cpp file location "
|
256 |
+
"and exact gcc/g++ command invoked.")
|
257 |
+
)
|
258 |
+
@cell_magic
|
259 |
+
def cython(self, line, cell):
|
260 |
+
"""Compile and import everything from a Cython code cell.
|
261 |
+
|
262 |
+
The contents of the cell are written to a `.pyx` file in the
|
263 |
+
directory `IPYTHONDIR/cython` using a filename with the hash of the
|
264 |
+
code. This file is then cythonized and compiled. The resulting module
|
265 |
+
is imported and all of its symbols are injected into the user's
|
266 |
+
namespace. The usage is similar to that of `%%cython_pyximport` but
|
267 |
+
you don't have to pass a module name::
|
268 |
+
|
269 |
+
%%cython
|
270 |
+
def f(x):
|
271 |
+
return 2.0*x
|
272 |
+
|
273 |
+
To compile OpenMP codes, pass the required `--compile-args`
|
274 |
+
and `--link-args`. For example with gcc::
|
275 |
+
|
276 |
+
%%cython --compile-args=-fopenmp --link-args=-fopenmp
|
277 |
+
...
|
278 |
+
|
279 |
+
To enable profile guided optimisation, pass the ``--pgo`` option.
|
280 |
+
Note that the cell itself needs to take care of establishing a suitable
|
281 |
+
profile when executed. This can be done by implementing the functions to
|
282 |
+
optimise, and then calling them directly in the same cell on some realistic
|
283 |
+
training data like this::
|
284 |
+
|
285 |
+
%%cython --pgo
|
286 |
+
def critical_function(data):
|
287 |
+
for item in data:
|
288 |
+
...
|
289 |
+
|
290 |
+
# execute function several times to build profile
|
291 |
+
from somewhere import some_typical_data
|
292 |
+
for _ in range(100):
|
293 |
+
critical_function(some_typical_data)
|
294 |
+
|
295 |
+
In Python 3.5 and later, you can distinguish between the profile and
|
296 |
+
non-profile runs as follows::
|
297 |
+
|
298 |
+
if "_pgo_" in __name__:
|
299 |
+
... # execute critical code here
|
300 |
+
"""
|
301 |
+
args = magic_arguments.parse_argstring(self.cython, line)
|
302 |
+
code = cell if cell.endswith('\n') else cell + '\n'
|
303 |
+
lib_dir = os.path.join(get_ipython_cache_dir(), 'cython')
|
304 |
+
key = (code, line, sys.version_info, sys.executable, cython_version)
|
305 |
+
|
306 |
+
if not os.path.exists(lib_dir):
|
307 |
+
os.makedirs(lib_dir)
|
308 |
+
|
309 |
+
if args.pgo:
|
310 |
+
key += ('pgo',)
|
311 |
+
if args.force:
|
312 |
+
# Force a new module name by adding the current time to the
|
313 |
+
# key which is hashed to determine the module name.
|
314 |
+
key += (time.time(),)
|
315 |
+
|
316 |
+
if args.name:
|
317 |
+
module_name = str(args.name) # no-op in Py3
|
318 |
+
else:
|
319 |
+
module_name = "_cython_magic_" + hashlib.md5(str(key).encode('utf-8')).hexdigest()
|
320 |
+
html_file = os.path.join(lib_dir, module_name + '.html')
|
321 |
+
module_path = os.path.join(lib_dir, module_name + self.so_ext)
|
322 |
+
|
323 |
+
have_module = os.path.isfile(module_path)
|
324 |
+
need_cythonize = args.pgo or not have_module
|
325 |
+
|
326 |
+
if args.annotate:
|
327 |
+
if not os.path.isfile(html_file):
|
328 |
+
need_cythonize = True
|
329 |
+
|
330 |
+
extension = None
|
331 |
+
if need_cythonize:
|
332 |
+
extensions = self._cythonize(module_name, code, lib_dir, args, quiet=args.quiet)
|
333 |
+
if extensions is None:
|
334 |
+
# Compilation failed and printed error message
|
335 |
+
return None
|
336 |
+
assert len(extensions) == 1
|
337 |
+
extension = extensions[0]
|
338 |
+
self._code_cache[key] = module_name
|
339 |
+
|
340 |
+
if args.pgo:
|
341 |
+
self._profile_pgo_wrapper(extension, lib_dir)
|
342 |
+
|
343 |
+
try:
|
344 |
+
self._build_extension(extension, lib_dir, pgo_step_name='use' if args.pgo else None,
|
345 |
+
quiet=args.quiet)
|
346 |
+
except distutils.errors.CompileError:
|
347 |
+
# Build failed and printed error message
|
348 |
+
return None
|
349 |
+
|
350 |
+
module = load_dynamic(module_name, module_path)
|
351 |
+
self._import_all(module)
|
352 |
+
|
353 |
+
if args.annotate:
|
354 |
+
try:
|
355 |
+
with io.open(html_file, encoding='utf-8') as f:
|
356 |
+
annotated_html = f.read()
|
357 |
+
except IOError as e:
|
358 |
+
# File could not be opened. Most likely the user has a version
|
359 |
+
# of Cython before 0.15.1 (when `cythonize` learned the
|
360 |
+
# `force` keyword argument) and has already compiled this
|
361 |
+
# exact source without annotation.
|
362 |
+
print('Cython completed successfully but the annotated '
|
363 |
+
'source could not be read.', file=sys.stderr)
|
364 |
+
print(e, file=sys.stderr)
|
365 |
+
else:
|
366 |
+
return display.HTML(self.clean_annotated_html(annotated_html))
|
367 |
+
|
368 |
+
def _profile_pgo_wrapper(self, extension, lib_dir):
|
369 |
+
"""
|
370 |
+
Generate a .c file for a separate extension module that calls the
|
371 |
+
module init function of the original module. This makes sure that the
|
372 |
+
PGO profiler sees the correct .o file of the final module, but it still
|
373 |
+
allows us to import the module under a different name for profiling,
|
374 |
+
before recompiling it into the PGO optimised module. Overwriting and
|
375 |
+
reimporting the same shared library is not portable.
|
376 |
+
"""
|
377 |
+
extension = copy.copy(extension) # shallow copy, do not modify sources in place!
|
378 |
+
module_name = extension.name
|
379 |
+
pgo_module_name = '_pgo_' + module_name
|
380 |
+
pgo_wrapper_c_file = os.path.join(lib_dir, pgo_module_name + '.c')
|
381 |
+
with io.open(pgo_wrapper_c_file, 'w', encoding='utf-8') as f:
|
382 |
+
f.write(textwrap.dedent(u"""
|
383 |
+
#include "Python.h"
|
384 |
+
#if PY_MAJOR_VERSION < 3
|
385 |
+
extern PyMODINIT_FUNC init%(module_name)s(void);
|
386 |
+
PyMODINIT_FUNC init%(pgo_module_name)s(void); /*proto*/
|
387 |
+
PyMODINIT_FUNC init%(pgo_module_name)s(void) {
|
388 |
+
PyObject *sys_modules;
|
389 |
+
init%(module_name)s(); if (PyErr_Occurred()) return;
|
390 |
+
sys_modules = PyImport_GetModuleDict(); /* borrowed, no exception, "never" fails */
|
391 |
+
if (sys_modules) {
|
392 |
+
PyObject *module = PyDict_GetItemString(sys_modules, "%(module_name)s"); if (!module) return;
|
393 |
+
PyDict_SetItemString(sys_modules, "%(pgo_module_name)s", module);
|
394 |
+
Py_DECREF(module);
|
395 |
+
}
|
396 |
+
}
|
397 |
+
#else
|
398 |
+
extern PyMODINIT_FUNC PyInit_%(module_name)s(void);
|
399 |
+
PyMODINIT_FUNC PyInit_%(pgo_module_name)s(void); /*proto*/
|
400 |
+
PyMODINIT_FUNC PyInit_%(pgo_module_name)s(void) {
|
401 |
+
return PyInit_%(module_name)s();
|
402 |
+
}
|
403 |
+
#endif
|
404 |
+
""" % {'module_name': module_name, 'pgo_module_name': pgo_module_name}))
|
405 |
+
|
406 |
+
extension.sources = extension.sources + [pgo_wrapper_c_file] # do not modify in place!
|
407 |
+
extension.name = pgo_module_name
|
408 |
+
|
409 |
+
self._build_extension(extension, lib_dir, pgo_step_name='gen')
|
410 |
+
|
411 |
+
# import and execute module code to generate profile
|
412 |
+
so_module_path = os.path.join(lib_dir, pgo_module_name + self.so_ext)
|
413 |
+
load_dynamic(pgo_module_name, so_module_path)
|
414 |
+
|
415 |
+
def _cythonize(self, module_name, code, lib_dir, args, quiet=True):
|
416 |
+
pyx_file = os.path.join(lib_dir, module_name + '.pyx')
|
417 |
+
pyx_file = encode_fs(pyx_file)
|
418 |
+
|
419 |
+
c_include_dirs = args.include
|
420 |
+
c_src_files = list(map(str, args.src))
|
421 |
+
if 'numpy' in code:
|
422 |
+
import numpy
|
423 |
+
c_include_dirs.append(numpy.get_include())
|
424 |
+
with io.open(pyx_file, 'w', encoding='utf-8') as f:
|
425 |
+
f.write(code)
|
426 |
+
extension = Extension(
|
427 |
+
name=module_name,
|
428 |
+
sources=[pyx_file] + c_src_files,
|
429 |
+
include_dirs=c_include_dirs,
|
430 |
+
library_dirs=args.library_dirs,
|
431 |
+
extra_compile_args=args.compile_args,
|
432 |
+
extra_link_args=args.link_args,
|
433 |
+
libraries=args.lib,
|
434 |
+
language='c++' if args.cplus else 'c',
|
435 |
+
)
|
436 |
+
try:
|
437 |
+
opts = dict(
|
438 |
+
quiet=quiet,
|
439 |
+
annotate=args.annotate,
|
440 |
+
force=True,
|
441 |
+
)
|
442 |
+
if args.language_level is not None:
|
443 |
+
assert args.language_level in (2, 3)
|
444 |
+
opts['language_level'] = args.language_level
|
445 |
+
elif sys.version_info[0] >= 3:
|
446 |
+
opts['language_level'] = 3
|
447 |
+
return cythonize([extension], **opts)
|
448 |
+
except CompileError:
|
449 |
+
return None
|
450 |
+
|
451 |
+
def _build_extension(self, extension, lib_dir, temp_dir=None, pgo_step_name=None, quiet=True):
|
452 |
+
build_extension = self._get_build_extension(
|
453 |
+
extension, lib_dir=lib_dir, temp_dir=temp_dir, pgo_step_name=pgo_step_name)
|
454 |
+
old_threshold = None
|
455 |
+
try:
|
456 |
+
if not quiet:
|
457 |
+
old_threshold = distutils.log.set_threshold(distutils.log.DEBUG)
|
458 |
+
build_extension.run()
|
459 |
+
finally:
|
460 |
+
if not quiet and old_threshold is not None:
|
461 |
+
distutils.log.set_threshold(old_threshold)
|
462 |
+
|
463 |
+
def _add_pgo_flags(self, build_extension, step_name, temp_dir):
|
464 |
+
compiler_type = build_extension.compiler.compiler_type
|
465 |
+
if compiler_type == 'unix':
|
466 |
+
compiler_cmd = build_extension.compiler.compiler_so
|
467 |
+
# TODO: we could try to call "[cmd] --version" for better insights
|
468 |
+
if not compiler_cmd:
|
469 |
+
pass
|
470 |
+
elif 'clang' in compiler_cmd or 'clang' in compiler_cmd[0]:
|
471 |
+
compiler_type = 'clang'
|
472 |
+
elif 'icc' in compiler_cmd or 'icc' in compiler_cmd[0]:
|
473 |
+
compiler_type = 'icc'
|
474 |
+
elif 'gcc' in compiler_cmd or 'gcc' in compiler_cmd[0]:
|
475 |
+
compiler_type = 'gcc'
|
476 |
+
elif 'g++' in compiler_cmd or 'g++' in compiler_cmd[0]:
|
477 |
+
compiler_type = 'gcc'
|
478 |
+
config = PGO_CONFIG.get(compiler_type)
|
479 |
+
orig_flags = []
|
480 |
+
if config and step_name in config:
|
481 |
+
flags = [f.format(TEMPDIR=temp_dir) for f in config[step_name]]
|
482 |
+
for extension in build_extension.extensions:
|
483 |
+
orig_flags.append((extension.extra_compile_args, extension.extra_link_args))
|
484 |
+
extension.extra_compile_args = extension.extra_compile_args + flags
|
485 |
+
extension.extra_link_args = extension.extra_link_args + flags
|
486 |
+
else:
|
487 |
+
print("No PGO %s configuration known for C compiler type '%s'" % (step_name, compiler_type),
|
488 |
+
file=sys.stderr)
|
489 |
+
return orig_flags
|
490 |
+
|
491 |
+
@property
|
492 |
+
def so_ext(self):
|
493 |
+
"""The extension suffix for compiled modules."""
|
494 |
+
try:
|
495 |
+
return self._so_ext
|
496 |
+
except AttributeError:
|
497 |
+
self._so_ext = self._get_build_extension().get_ext_filename('')
|
498 |
+
return self._so_ext
|
499 |
+
|
500 |
+
def _clear_distutils_mkpath_cache(self):
|
501 |
+
"""clear distutils mkpath cache
|
502 |
+
|
503 |
+
prevents distutils from skipping re-creation of dirs that have been removed
|
504 |
+
"""
|
505 |
+
try:
|
506 |
+
from distutils.dir_util import _path_created
|
507 |
+
except ImportError:
|
508 |
+
pass
|
509 |
+
else:
|
510 |
+
_path_created.clear()
|
511 |
+
|
512 |
+
def _get_build_extension(self, extension=None, lib_dir=None, temp_dir=None,
|
513 |
+
pgo_step_name=None, _build_ext=build_ext):
|
514 |
+
self._clear_distutils_mkpath_cache()
|
515 |
+
dist = Distribution()
|
516 |
+
config_files = dist.find_config_files()
|
517 |
+
try:
|
518 |
+
config_files.remove('setup.cfg')
|
519 |
+
except ValueError:
|
520 |
+
pass
|
521 |
+
dist.parse_config_files(config_files)
|
522 |
+
|
523 |
+
if not temp_dir:
|
524 |
+
temp_dir = lib_dir
|
525 |
+
add_pgo_flags = self._add_pgo_flags
|
526 |
+
|
527 |
+
if pgo_step_name:
|
528 |
+
base_build_ext = _build_ext
|
529 |
+
class _build_ext(_build_ext):
|
530 |
+
def build_extensions(self):
|
531 |
+
add_pgo_flags(self, pgo_step_name, temp_dir)
|
532 |
+
base_build_ext.build_extensions(self)
|
533 |
+
|
534 |
+
build_extension = _build_ext(dist)
|
535 |
+
build_extension.finalize_options()
|
536 |
+
if temp_dir:
|
537 |
+
temp_dir = encode_fs(temp_dir)
|
538 |
+
build_extension.build_temp = temp_dir
|
539 |
+
if lib_dir:
|
540 |
+
lib_dir = encode_fs(lib_dir)
|
541 |
+
build_extension.build_lib = lib_dir
|
542 |
+
if extension is not None:
|
543 |
+
build_extension.extensions = [extension]
|
544 |
+
return build_extension
|
545 |
+
|
546 |
+
@staticmethod
|
547 |
+
def clean_annotated_html(html):
|
548 |
+
"""Clean up the annotated HTML source.
|
549 |
+
|
550 |
+
Strips the link to the generated C or C++ file, which we do not
|
551 |
+
present to the user.
|
552 |
+
"""
|
553 |
+
r = re.compile('<p>Raw output: <a href="(.*)">(.*)</a>')
|
554 |
+
html = '\n'.join(l for l in html.splitlines() if not r.match(l))
|
555 |
+
return html
|
556 |
+
|
557 |
+
__doc__ = __doc__.format(
|
558 |
+
# rST doesn't see the -+ flag as part of an option list, so we
|
559 |
+
# hide it from the module-level docstring.
|
560 |
+
CYTHON_DOC=dedent(CythonMagics.cython.__doc__\
|
561 |
+
.replace('-+, --cplus', '--cplus ')),
|
562 |
+
CYTHON_INLINE_DOC=dedent(CythonMagics.cython_inline.__doc__),
|
563 |
+
CYTHON_PYXIMPORT_DOC=dedent(CythonMagics.cython_pyximport.__doc__),
|
564 |
+
)
|
venv/Lib/site-packages/Cython/Build/Tests/TestCyCache.py
ADDED
@@ -0,0 +1,106 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import difflib
|
2 |
+
import glob
|
3 |
+
import gzip
|
4 |
+
import os
|
5 |
+
import tempfile
|
6 |
+
|
7 |
+
import Cython.Build.Dependencies
|
8 |
+
import Cython.Utils
|
9 |
+
from Cython.TestUtils import CythonTest
|
10 |
+
|
11 |
+
|
12 |
+
class TestCyCache(CythonTest):
|
13 |
+
|
14 |
+
def setUp(self):
|
15 |
+
CythonTest.setUp(self)
|
16 |
+
self.temp_dir = tempfile.mkdtemp(
|
17 |
+
prefix='cycache-test',
|
18 |
+
dir='TEST_TMP' if os.path.isdir('TEST_TMP') else None)
|
19 |
+
self.src_dir = tempfile.mkdtemp(prefix='src', dir=self.temp_dir)
|
20 |
+
self.cache_dir = tempfile.mkdtemp(prefix='cache', dir=self.temp_dir)
|
21 |
+
|
22 |
+
def cache_files(self, file_glob):
|
23 |
+
return glob.glob(os.path.join(self.cache_dir, file_glob))
|
24 |
+
|
25 |
+
def fresh_cythonize(self, *args, **kwargs):
|
26 |
+
Cython.Utils.clear_function_caches()
|
27 |
+
Cython.Build.Dependencies._dep_tree = None # discard method caches
|
28 |
+
Cython.Build.Dependencies.cythonize(*args, **kwargs)
|
29 |
+
|
30 |
+
def test_cycache_switch(self):
|
31 |
+
content1 = 'value = 1\n'
|
32 |
+
content2 = 'value = 2\n'
|
33 |
+
a_pyx = os.path.join(self.src_dir, 'a.pyx')
|
34 |
+
a_c = a_pyx[:-4] + '.c'
|
35 |
+
|
36 |
+
open(a_pyx, 'w').write(content1)
|
37 |
+
self.fresh_cythonize(a_pyx, cache=self.cache_dir)
|
38 |
+
self.fresh_cythonize(a_pyx, cache=self.cache_dir)
|
39 |
+
self.assertEqual(1, len(self.cache_files('a.c*')))
|
40 |
+
a_contents1 = open(a_c).read()
|
41 |
+
os.unlink(a_c)
|
42 |
+
|
43 |
+
open(a_pyx, 'w').write(content2)
|
44 |
+
self.fresh_cythonize(a_pyx, cache=self.cache_dir)
|
45 |
+
a_contents2 = open(a_c).read()
|
46 |
+
os.unlink(a_c)
|
47 |
+
|
48 |
+
self.assertNotEqual(a_contents1, a_contents2, 'C file not changed!')
|
49 |
+
self.assertEqual(2, len(self.cache_files('a.c*')))
|
50 |
+
|
51 |
+
open(a_pyx, 'w').write(content1)
|
52 |
+
self.fresh_cythonize(a_pyx, cache=self.cache_dir)
|
53 |
+
self.assertEqual(2, len(self.cache_files('a.c*')))
|
54 |
+
a_contents = open(a_c).read()
|
55 |
+
self.assertEqual(
|
56 |
+
a_contents, a_contents1,
|
57 |
+
msg='\n'.join(list(difflib.unified_diff(
|
58 |
+
a_contents.split('\n'), a_contents1.split('\n')))[:10]))
|
59 |
+
|
60 |
+
def test_cycache_uses_cache(self):
|
61 |
+
a_pyx = os.path.join(self.src_dir, 'a.pyx')
|
62 |
+
a_c = a_pyx[:-4] + '.c'
|
63 |
+
open(a_pyx, 'w').write('pass')
|
64 |
+
self.fresh_cythonize(a_pyx, cache=self.cache_dir)
|
65 |
+
a_cache = os.path.join(self.cache_dir, os.listdir(self.cache_dir)[0])
|
66 |
+
gzip.GzipFile(a_cache, 'wb').write('fake stuff'.encode('ascii'))
|
67 |
+
os.unlink(a_c)
|
68 |
+
self.fresh_cythonize(a_pyx, cache=self.cache_dir)
|
69 |
+
a_contents = open(a_c).read()
|
70 |
+
self.assertEqual(a_contents, 'fake stuff',
|
71 |
+
'Unexpected contents: %s...' % a_contents[:100])
|
72 |
+
|
73 |
+
def test_multi_file_output(self):
|
74 |
+
a_pyx = os.path.join(self.src_dir, 'a.pyx')
|
75 |
+
a_c = a_pyx[:-4] + '.c'
|
76 |
+
a_h = a_pyx[:-4] + '.h'
|
77 |
+
a_api_h = a_pyx[:-4] + '_api.h'
|
78 |
+
open(a_pyx, 'w').write('cdef public api int foo(int x): return x\n')
|
79 |
+
self.fresh_cythonize(a_pyx, cache=self.cache_dir)
|
80 |
+
expected = [a_c, a_h, a_api_h]
|
81 |
+
for output in expected:
|
82 |
+
self.assertTrue(os.path.exists(output), output)
|
83 |
+
os.unlink(output)
|
84 |
+
self.fresh_cythonize(a_pyx, cache=self.cache_dir)
|
85 |
+
for output in expected:
|
86 |
+
self.assertTrue(os.path.exists(output), output)
|
87 |
+
|
88 |
+
def test_options_invalidation(self):
|
89 |
+
hash_pyx = os.path.join(self.src_dir, 'options.pyx')
|
90 |
+
hash_c = hash_pyx[:-len('.pyx')] + '.c'
|
91 |
+
|
92 |
+
open(hash_pyx, 'w').write('pass')
|
93 |
+
self.fresh_cythonize(hash_pyx, cache=self.cache_dir, cplus=False)
|
94 |
+
self.assertEqual(1, len(self.cache_files('options.c*')))
|
95 |
+
|
96 |
+
os.unlink(hash_c)
|
97 |
+
self.fresh_cythonize(hash_pyx, cache=self.cache_dir, cplus=True)
|
98 |
+
self.assertEqual(2, len(self.cache_files('options.c*')))
|
99 |
+
|
100 |
+
os.unlink(hash_c)
|
101 |
+
self.fresh_cythonize(hash_pyx, cache=self.cache_dir, cplus=False, show_version=False)
|
102 |
+
self.assertEqual(2, len(self.cache_files('options.c*')))
|
103 |
+
|
104 |
+
os.unlink(hash_c)
|
105 |
+
self.fresh_cythonize(hash_pyx, cache=self.cache_dir, cplus=False, show_version=True)
|
106 |
+
self.assertEqual(2, len(self.cache_files('options.c*')))
|
venv/Lib/site-packages/Cython/Build/Tests/TestInline.py
ADDED
@@ -0,0 +1,96 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os, tempfile
|
2 |
+
from Cython.Shadow import inline
|
3 |
+
from Cython.Build.Inline import safe_type
|
4 |
+
from Cython.TestUtils import CythonTest
|
5 |
+
|
6 |
+
try:
|
7 |
+
import numpy
|
8 |
+
has_numpy = True
|
9 |
+
except:
|
10 |
+
has_numpy = False
|
11 |
+
|
12 |
+
test_kwds = dict(force=True, quiet=True)
|
13 |
+
|
14 |
+
global_value = 100
|
15 |
+
|
16 |
+
class TestInline(CythonTest):
|
17 |
+
def setUp(self):
|
18 |
+
CythonTest.setUp(self)
|
19 |
+
self.test_kwds = dict(test_kwds)
|
20 |
+
if os.path.isdir('TEST_TMP'):
|
21 |
+
lib_dir = os.path.join('TEST_TMP','inline')
|
22 |
+
else:
|
23 |
+
lib_dir = tempfile.mkdtemp(prefix='cython_inline_')
|
24 |
+
self.test_kwds['lib_dir'] = lib_dir
|
25 |
+
|
26 |
+
def test_simple(self):
|
27 |
+
self.assertEqual(inline("return 1+2", **self.test_kwds), 3)
|
28 |
+
|
29 |
+
def test_types(self):
|
30 |
+
self.assertEqual(inline("""
|
31 |
+
cimport cython
|
32 |
+
return cython.typeof(a), cython.typeof(b)
|
33 |
+
""", a=1.0, b=[], **self.test_kwds), ('double', 'list object'))
|
34 |
+
|
35 |
+
def test_locals(self):
|
36 |
+
a = 1
|
37 |
+
b = 2
|
38 |
+
self.assertEqual(inline("return a+b", **self.test_kwds), 3)
|
39 |
+
|
40 |
+
def test_globals(self):
|
41 |
+
self.assertEqual(inline("return global_value + 1", **self.test_kwds), global_value + 1)
|
42 |
+
|
43 |
+
def test_no_return(self):
|
44 |
+
self.assertEqual(inline("""
|
45 |
+
a = 1
|
46 |
+
cdef double b = 2
|
47 |
+
cdef c = []
|
48 |
+
""", **self.test_kwds), dict(a=1, b=2.0, c=[]))
|
49 |
+
|
50 |
+
def test_def_node(self):
|
51 |
+
foo = inline("def foo(x): return x * x", **self.test_kwds)['foo']
|
52 |
+
self.assertEqual(foo(7), 49)
|
53 |
+
|
54 |
+
def test_class_ref(self):
|
55 |
+
class Type(object):
|
56 |
+
pass
|
57 |
+
tp = inline("Type")['Type']
|
58 |
+
self.assertEqual(tp, Type)
|
59 |
+
|
60 |
+
def test_pure(self):
|
61 |
+
import cython as cy
|
62 |
+
b = inline("""
|
63 |
+
b = cy.declare(float, a)
|
64 |
+
c = cy.declare(cy.pointer(cy.float), &b)
|
65 |
+
return b
|
66 |
+
""", a=3, **self.test_kwds)
|
67 |
+
self.assertEqual(type(b), float)
|
68 |
+
|
69 |
+
def test_compiler_directives(self):
|
70 |
+
self.assertEqual(
|
71 |
+
inline('return sum(x)',
|
72 |
+
x=[1, 2, 3],
|
73 |
+
cython_compiler_directives={'boundscheck': False}),
|
74 |
+
6
|
75 |
+
)
|
76 |
+
|
77 |
+
def test_lang_version(self):
|
78 |
+
# GH-3419. Caching for inline code didn't always respect compiler directives.
|
79 |
+
inline_divcode = "def f(int a, int b): return a/b"
|
80 |
+
self.assertEqual(
|
81 |
+
inline(inline_divcode, language_level=2)['f'](5,2),
|
82 |
+
2
|
83 |
+
)
|
84 |
+
self.assertEqual(
|
85 |
+
inline(inline_divcode, language_level=3)['f'](5,2),
|
86 |
+
2.5
|
87 |
+
)
|
88 |
+
|
89 |
+
if has_numpy:
|
90 |
+
|
91 |
+
def test_numpy(self):
|
92 |
+
import numpy
|
93 |
+
a = numpy.ndarray((10, 20))
|
94 |
+
a[0,0] = 10
|
95 |
+
self.assertEqual(safe_type(a), 'numpy.ndarray[numpy.float64_t, ndim=2]')
|
96 |
+
self.assertEqual(inline("return a[0,0]", a=a, **self.test_kwds), 10.0)
|
venv/Lib/site-packages/Cython/Build/Tests/TestIpythonMagic.py
ADDED
@@ -0,0 +1,205 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# -*- coding: utf-8 -*-
|
2 |
+
# tag: ipython
|
3 |
+
|
4 |
+
"""Tests for the Cython magics extension."""
|
5 |
+
|
6 |
+
from __future__ import absolute_import
|
7 |
+
|
8 |
+
import os
|
9 |
+
import sys
|
10 |
+
from contextlib import contextmanager
|
11 |
+
from Cython.Build import IpythonMagic
|
12 |
+
from Cython.TestUtils import CythonTest
|
13 |
+
|
14 |
+
try:
|
15 |
+
import IPython.testing.globalipapp
|
16 |
+
except ImportError:
|
17 |
+
# Disable tests and fake helpers for initialisation below.
|
18 |
+
def skip_if_not_installed(_):
|
19 |
+
return None
|
20 |
+
else:
|
21 |
+
def skip_if_not_installed(c):
|
22 |
+
return c
|
23 |
+
|
24 |
+
try:
|
25 |
+
# disable IPython history thread before it gets started to avoid having to clean it up
|
26 |
+
from IPython.core.history import HistoryManager
|
27 |
+
HistoryManager.enabled = False
|
28 |
+
except ImportError:
|
29 |
+
pass
|
30 |
+
|
31 |
+
code = u"""\
|
32 |
+
def f(x):
|
33 |
+
return 2*x
|
34 |
+
"""
|
35 |
+
|
36 |
+
cython3_code = u"""\
|
37 |
+
def f(int x):
|
38 |
+
return 2 / x
|
39 |
+
|
40 |
+
def call(x):
|
41 |
+
return f(*(x,))
|
42 |
+
"""
|
43 |
+
|
44 |
+
pgo_cython3_code = cython3_code + u"""\
|
45 |
+
def main():
|
46 |
+
for _ in range(100): call(5)
|
47 |
+
main()
|
48 |
+
"""
|
49 |
+
|
50 |
+
|
51 |
+
if sys.platform == 'win32':
|
52 |
+
# not using IPython's decorators here because they depend on "nose"
|
53 |
+
try:
|
54 |
+
from unittest import skip as skip_win32
|
55 |
+
except ImportError:
|
56 |
+
# poor dev's silent @unittest.skip()
|
57 |
+
def skip_win32(dummy):
|
58 |
+
def _skip_win32(func):
|
59 |
+
return None
|
60 |
+
return _skip_win32
|
61 |
+
else:
|
62 |
+
def skip_win32(dummy):
|
63 |
+
def _skip_win32(func):
|
64 |
+
def wrapper(*args, **kwargs):
|
65 |
+
func(*args, **kwargs)
|
66 |
+
return wrapper
|
67 |
+
return _skip_win32
|
68 |
+
|
69 |
+
|
70 |
+
@skip_if_not_installed
|
71 |
+
class TestIPythonMagic(CythonTest):
|
72 |
+
|
73 |
+
@classmethod
|
74 |
+
def setUpClass(cls):
|
75 |
+
CythonTest.setUpClass()
|
76 |
+
cls._ip = IPython.testing.globalipapp.get_ipython()
|
77 |
+
|
78 |
+
def setUp(self):
|
79 |
+
CythonTest.setUp(self)
|
80 |
+
self._ip.extension_manager.load_extension('cython')
|
81 |
+
|
82 |
+
def test_cython_inline(self):
|
83 |
+
ip = self._ip
|
84 |
+
ip.ex('a=10; b=20')
|
85 |
+
result = ip.run_cell_magic('cython_inline', '', 'return a+b')
|
86 |
+
self.assertEqual(result, 30)
|
87 |
+
|
88 |
+
@skip_win32('Skip on Windows')
|
89 |
+
def test_cython_pyximport(self):
|
90 |
+
ip = self._ip
|
91 |
+
module_name = '_test_cython_pyximport'
|
92 |
+
ip.run_cell_magic('cython_pyximport', module_name, code)
|
93 |
+
ip.ex('g = f(10)')
|
94 |
+
self.assertEqual(ip.user_ns['g'], 20.0)
|
95 |
+
ip.run_cell_magic('cython_pyximport', module_name, code)
|
96 |
+
ip.ex('h = f(-10)')
|
97 |
+
self.assertEqual(ip.user_ns['h'], -20.0)
|
98 |
+
try:
|
99 |
+
os.remove(module_name + '.pyx')
|
100 |
+
except OSError:
|
101 |
+
pass
|
102 |
+
|
103 |
+
def test_cython(self):
|
104 |
+
ip = self._ip
|
105 |
+
ip.run_cell_magic('cython', '', code)
|
106 |
+
ip.ex('g = f(10)')
|
107 |
+
self.assertEqual(ip.user_ns['g'], 20.0)
|
108 |
+
|
109 |
+
def test_cython_name(self):
|
110 |
+
# The Cython module named 'mymodule' defines the function f.
|
111 |
+
ip = self._ip
|
112 |
+
ip.run_cell_magic('cython', '--name=mymodule', code)
|
113 |
+
# This module can now be imported in the interactive namespace.
|
114 |
+
ip.ex('import mymodule; g = mymodule.f(10)')
|
115 |
+
self.assertEqual(ip.user_ns['g'], 20.0)
|
116 |
+
|
117 |
+
def test_cython_language_level(self):
|
118 |
+
# The Cython cell defines the functions f() and call().
|
119 |
+
ip = self._ip
|
120 |
+
ip.run_cell_magic('cython', '', cython3_code)
|
121 |
+
ip.ex('g = f(10); h = call(10)')
|
122 |
+
if sys.version_info[0] < 3:
|
123 |
+
self.assertEqual(ip.user_ns['g'], 2 // 10)
|
124 |
+
self.assertEqual(ip.user_ns['h'], 2 // 10)
|
125 |
+
else:
|
126 |
+
self.assertEqual(ip.user_ns['g'], 2.0 / 10.0)
|
127 |
+
self.assertEqual(ip.user_ns['h'], 2.0 / 10.0)
|
128 |
+
|
129 |
+
def test_cython3(self):
|
130 |
+
# The Cython cell defines the functions f() and call().
|
131 |
+
ip = self._ip
|
132 |
+
ip.run_cell_magic('cython', '-3', cython3_code)
|
133 |
+
ip.ex('g = f(10); h = call(10)')
|
134 |
+
self.assertEqual(ip.user_ns['g'], 2.0 / 10.0)
|
135 |
+
self.assertEqual(ip.user_ns['h'], 2.0 / 10.0)
|
136 |
+
|
137 |
+
def test_cython2(self):
|
138 |
+
# The Cython cell defines the functions f() and call().
|
139 |
+
ip = self._ip
|
140 |
+
ip.run_cell_magic('cython', '-2', cython3_code)
|
141 |
+
ip.ex('g = f(10); h = call(10)')
|
142 |
+
self.assertEqual(ip.user_ns['g'], 2 // 10)
|
143 |
+
self.assertEqual(ip.user_ns['h'], 2 // 10)
|
144 |
+
|
145 |
+
@skip_win32('Skip on Windows')
|
146 |
+
def test_cython3_pgo(self):
|
147 |
+
# The Cython cell defines the functions f() and call().
|
148 |
+
ip = self._ip
|
149 |
+
ip.run_cell_magic('cython', '-3 --pgo', pgo_cython3_code)
|
150 |
+
ip.ex('g = f(10); h = call(10); main()')
|
151 |
+
self.assertEqual(ip.user_ns['g'], 2.0 / 10.0)
|
152 |
+
self.assertEqual(ip.user_ns['h'], 2.0 / 10.0)
|
153 |
+
|
154 |
+
@skip_win32('Skip on Windows')
|
155 |
+
def test_extlibs(self):
|
156 |
+
ip = self._ip
|
157 |
+
code = u"""
|
158 |
+
from libc.math cimport sin
|
159 |
+
x = sin(0.0)
|
160 |
+
"""
|
161 |
+
ip.user_ns['x'] = 1
|
162 |
+
ip.run_cell_magic('cython', '-l m', code)
|
163 |
+
self.assertEqual(ip.user_ns['x'], 0)
|
164 |
+
|
165 |
+
|
166 |
+
def test_cython_verbose(self):
|
167 |
+
ip = self._ip
|
168 |
+
ip.run_cell_magic('cython', '--verbose', code)
|
169 |
+
ip.ex('g = f(10)')
|
170 |
+
self.assertEqual(ip.user_ns['g'], 20.0)
|
171 |
+
|
172 |
+
def test_cython_verbose_thresholds(self):
|
173 |
+
@contextmanager
|
174 |
+
def mock_distutils():
|
175 |
+
class MockLog:
|
176 |
+
DEBUG = 1
|
177 |
+
INFO = 2
|
178 |
+
thresholds = [INFO]
|
179 |
+
|
180 |
+
def set_threshold(self, val):
|
181 |
+
self.thresholds.append(val)
|
182 |
+
return self.thresholds[-2]
|
183 |
+
|
184 |
+
|
185 |
+
new_log = MockLog()
|
186 |
+
old_log = IpythonMagic.distutils.log
|
187 |
+
try:
|
188 |
+
IpythonMagic.distutils.log = new_log
|
189 |
+
yield new_log
|
190 |
+
finally:
|
191 |
+
IpythonMagic.distutils.log = old_log
|
192 |
+
|
193 |
+
ip = self._ip
|
194 |
+
with mock_distutils() as verbose_log:
|
195 |
+
ip.run_cell_magic('cython', '--verbose', code)
|
196 |
+
ip.ex('g = f(10)')
|
197 |
+
self.assertEqual(ip.user_ns['g'], 20.0)
|
198 |
+
self.assertEqual([verbose_log.INFO, verbose_log.DEBUG, verbose_log.INFO],
|
199 |
+
verbose_log.thresholds)
|
200 |
+
|
201 |
+
with mock_distutils() as normal_log:
|
202 |
+
ip.run_cell_magic('cython', '', code)
|
203 |
+
ip.ex('g = f(10)')
|
204 |
+
self.assertEqual(ip.user_ns['g'], 20.0)
|
205 |
+
self.assertEqual([normal_log.INFO], normal_log.thresholds)
|
venv/Lib/site-packages/Cython/Build/Tests/TestStripLiterals.py
ADDED
@@ -0,0 +1,57 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from Cython.Build.Dependencies import strip_string_literals
|
2 |
+
|
3 |
+
from Cython.TestUtils import CythonTest
|
4 |
+
|
5 |
+
class TestStripLiterals(CythonTest):
|
6 |
+
|
7 |
+
def t(self, before, expected):
|
8 |
+
actual, literals = strip_string_literals(before, prefix="_L")
|
9 |
+
self.assertEqual(expected, actual)
|
10 |
+
for key, value in literals.items():
|
11 |
+
actual = actual.replace(key, value)
|
12 |
+
self.assertEqual(before, actual)
|
13 |
+
|
14 |
+
def test_empty(self):
|
15 |
+
self.t("", "")
|
16 |
+
|
17 |
+
def test_single_quote(self):
|
18 |
+
self.t("'x'", "'_L1_'")
|
19 |
+
|
20 |
+
def test_double_quote(self):
|
21 |
+
self.t('"x"', '"_L1_"')
|
22 |
+
|
23 |
+
def test_nested_quotes(self):
|
24 |
+
self.t(""" '"' "'" """, """ '_L1_' "_L2_" """)
|
25 |
+
|
26 |
+
def test_triple_quote(self):
|
27 |
+
self.t(" '''a\n''' ", " '''_L1_''' ")
|
28 |
+
|
29 |
+
def test_backslash(self):
|
30 |
+
self.t(r"'a\'b'", "'_L1_'")
|
31 |
+
self.t(r"'a\\'", "'_L1_'")
|
32 |
+
self.t(r"'a\\\'b'", "'_L1_'")
|
33 |
+
|
34 |
+
def test_unicode(self):
|
35 |
+
self.t("u'abc'", "u'_L1_'")
|
36 |
+
|
37 |
+
def test_raw(self):
|
38 |
+
self.t(r"r'abc\\'", "r'_L1_'")
|
39 |
+
|
40 |
+
def test_raw_unicode(self):
|
41 |
+
self.t(r"ru'abc\\'", "ru'_L1_'")
|
42 |
+
|
43 |
+
def test_comment(self):
|
44 |
+
self.t("abc # foo", "abc #_L1_")
|
45 |
+
|
46 |
+
def test_comment_and_quote(self):
|
47 |
+
self.t("abc # 'x'", "abc #_L1_")
|
48 |
+
self.t("'abc#'", "'_L1_'")
|
49 |
+
|
50 |
+
def test_include(self):
|
51 |
+
self.t("include 'a.pxi' # something here",
|
52 |
+
"include '_L1_' #_L2_")
|
53 |
+
|
54 |
+
def test_extern(self):
|
55 |
+
self.t("cdef extern from 'a.h': # comment",
|
56 |
+
"cdef extern from '_L1_': #_L2_")
|
57 |
+
|
venv/Lib/site-packages/Cython/Build/Tests/__init__.py
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
# empty file
|
venv/Lib/site-packages/Cython/Build/Tests/__pycache__/TestCyCache.cpython-311.pyc
ADDED
Binary file (9.13 kB). View file
|
|
venv/Lib/site-packages/Cython/Build/Tests/__pycache__/TestInline.cpython-311.pyc
ADDED
Binary file (6.51 kB). View file
|
|
venv/Lib/site-packages/Cython/Build/Tests/__pycache__/TestIpythonMagic.cpython-311.pyc
ADDED
Binary file (12.2 kB). View file
|
|
venv/Lib/site-packages/Cython/Build/Tests/__pycache__/TestStripLiterals.cpython-311.pyc
ADDED
Binary file (4.55 kB). View file
|
|
venv/Lib/site-packages/Cython/Build/Tests/__pycache__/__init__.cpython-311.pyc
ADDED
Binary file (206 Bytes). View file
|
|
venv/Lib/site-packages/Cython/Build/__init__.py
ADDED
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
1 |
+
from .Dependencies import cythonize
|
2 |
+
from .Distutils import build_ext
|
venv/Lib/site-packages/Cython/Build/__pycache__/BuildExecutable.cpython-311.pyc
ADDED
Binary file (8.68 kB). View file
|
|
venv/Lib/site-packages/Cython/Build/__pycache__/Cythonize.cpython-311.pyc
ADDED
Binary file (12.4 kB). View file
|
|
venv/Lib/site-packages/Cython/Build/__pycache__/Dependencies.cpython-311.pyc
ADDED
Binary file (68.3 kB). View file
|
|
venv/Lib/site-packages/Cython/Build/__pycache__/Distutils.cpython-311.pyc
ADDED
Binary file (275 Bytes). View file
|
|
venv/Lib/site-packages/Cython/Build/__pycache__/Inline.cpython-311.pyc
ADDED
Binary file (20.3 kB). View file
|
|
venv/Lib/site-packages/Cython/Build/__pycache__/IpythonMagic.cpython-311.pyc
ADDED
Binary file (26.9 kB). View file
|
|
venv/Lib/site-packages/Cython/Build/__pycache__/__init__.cpython-311.pyc
ADDED
Binary file (319 Bytes). View file
|
|
venv/Lib/site-packages/Cython/CodeWriter.py
ADDED
@@ -0,0 +1,819 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
"""
|
2 |
+
Serializes a Cython code tree to Cython code. This is primarily useful for
|
3 |
+
debugging and testing purposes.
|
4 |
+
|
5 |
+
The output is in a strict format, no whitespace or comments from the input
|
6 |
+
is preserved (and it could not be as it is not present in the code tree).
|
7 |
+
"""
|
8 |
+
|
9 |
+
from __future__ import absolute_import, print_function
|
10 |
+
|
11 |
+
from .Compiler.Visitor import TreeVisitor
|
12 |
+
from .Compiler.ExprNodes import *
|
13 |
+
|
14 |
+
|
15 |
+
class LinesResult(object):
|
16 |
+
def __init__(self):
|
17 |
+
self.lines = []
|
18 |
+
self.s = u""
|
19 |
+
|
20 |
+
def put(self, s):
|
21 |
+
self.s += s
|
22 |
+
|
23 |
+
def newline(self):
|
24 |
+
self.lines.append(self.s)
|
25 |
+
self.s = u""
|
26 |
+
|
27 |
+
def putline(self, s):
|
28 |
+
self.put(s)
|
29 |
+
self.newline()
|
30 |
+
|
31 |
+
class DeclarationWriter(TreeVisitor):
|
32 |
+
|
33 |
+
indent_string = u" "
|
34 |
+
|
35 |
+
def __init__(self, result=None):
|
36 |
+
super(DeclarationWriter, self).__init__()
|
37 |
+
if result is None:
|
38 |
+
result = LinesResult()
|
39 |
+
self.result = result
|
40 |
+
self.numindents = 0
|
41 |
+
self.tempnames = {}
|
42 |
+
self.tempblockindex = 0
|
43 |
+
|
44 |
+
def write(self, tree):
|
45 |
+
self.visit(tree)
|
46 |
+
return self.result
|
47 |
+
|
48 |
+
def indent(self):
|
49 |
+
self.numindents += 1
|
50 |
+
|
51 |
+
def dedent(self):
|
52 |
+
self.numindents -= 1
|
53 |
+
|
54 |
+
def startline(self, s=u""):
|
55 |
+
self.result.put(self.indent_string * self.numindents + s)
|
56 |
+
|
57 |
+
def put(self, s):
|
58 |
+
self.result.put(s)
|
59 |
+
|
60 |
+
def putline(self, s):
|
61 |
+
self.result.putline(self.indent_string * self.numindents + s)
|
62 |
+
|
63 |
+
def endline(self, s=u""):
|
64 |
+
self.result.putline(s)
|
65 |
+
|
66 |
+
def line(self, s):
|
67 |
+
self.startline(s)
|
68 |
+
self.endline()
|
69 |
+
|
70 |
+
def comma_separated_list(self, items, output_rhs=False):
|
71 |
+
if len(items) > 0:
|
72 |
+
for item in items[:-1]:
|
73 |
+
self.visit(item)
|
74 |
+
if output_rhs and item.default is not None:
|
75 |
+
self.put(u" = ")
|
76 |
+
self.visit(item.default)
|
77 |
+
self.put(u", ")
|
78 |
+
self.visit(items[-1])
|
79 |
+
|
80 |
+
def visit_Node(self, node):
|
81 |
+
raise AssertionError("Node not handled by serializer: %r" % node)
|
82 |
+
|
83 |
+
def visit_ModuleNode(self, node):
|
84 |
+
self.visitchildren(node)
|
85 |
+
|
86 |
+
def visit_StatListNode(self, node):
|
87 |
+
self.visitchildren(node)
|
88 |
+
|
89 |
+
def visit_CDefExternNode(self, node):
|
90 |
+
if node.include_file is None:
|
91 |
+
file = u'*'
|
92 |
+
else:
|
93 |
+
file = u'"%s"' % node.include_file
|
94 |
+
self.putline(u"cdef extern from %s:" % file)
|
95 |
+
self.indent()
|
96 |
+
self.visit(node.body)
|
97 |
+
self.dedent()
|
98 |
+
|
99 |
+
def visit_CPtrDeclaratorNode(self, node):
|
100 |
+
self.put('*')
|
101 |
+
self.visit(node.base)
|
102 |
+
|
103 |
+
def visit_CReferenceDeclaratorNode(self, node):
|
104 |
+
self.put('&')
|
105 |
+
self.visit(node.base)
|
106 |
+
|
107 |
+
def visit_CArrayDeclaratorNode(self, node):
|
108 |
+
self.visit(node.base)
|
109 |
+
self.put(u'[')
|
110 |
+
if node.dimension is not None:
|
111 |
+
self.visit(node.dimension)
|
112 |
+
self.put(u']')
|
113 |
+
|
114 |
+
def visit_CArrayDeclaratorNode(self, node):
|
115 |
+
self.visit(node.base)
|
116 |
+
self.put(u'[')
|
117 |
+
if node.dimension is not None:
|
118 |
+
self.visit(node.dimension)
|
119 |
+
self.put(u']')
|
120 |
+
|
121 |
+
def visit_CFuncDeclaratorNode(self, node):
|
122 |
+
# TODO: except, gil, etc.
|
123 |
+
self.visit(node.base)
|
124 |
+
self.put(u'(')
|
125 |
+
self.comma_separated_list(node.args)
|
126 |
+
self.endline(u')')
|
127 |
+
|
128 |
+
def visit_CNameDeclaratorNode(self, node):
|
129 |
+
self.put(node.name)
|
130 |
+
|
131 |
+
def visit_CSimpleBaseTypeNode(self, node):
|
132 |
+
# See Parsing.p_sign_and_longness
|
133 |
+
if node.is_basic_c_type:
|
134 |
+
self.put(("unsigned ", "", "signed ")[node.signed])
|
135 |
+
if node.longness < 0:
|
136 |
+
self.put("short " * -node.longness)
|
137 |
+
elif node.longness > 0:
|
138 |
+
self.put("long " * node.longness)
|
139 |
+
self.put(node.name)
|
140 |
+
|
141 |
+
def visit_CComplexBaseTypeNode(self, node):
|
142 |
+
self.put(u'(')
|
143 |
+
self.visit(node.base_type)
|
144 |
+
self.visit(node.declarator)
|
145 |
+
self.put(u')')
|
146 |
+
|
147 |
+
def visit_CNestedBaseTypeNode(self, node):
|
148 |
+
self.visit(node.base_type)
|
149 |
+
self.put(u'.')
|
150 |
+
self.put(node.name)
|
151 |
+
|
152 |
+
def visit_TemplatedTypeNode(self, node):
|
153 |
+
self.visit(node.base_type_node)
|
154 |
+
self.put(u'[')
|
155 |
+
self.comma_separated_list(node.positional_args + node.keyword_args.key_value_pairs)
|
156 |
+
self.put(u']')
|
157 |
+
|
158 |
+
def visit_CVarDefNode(self, node):
|
159 |
+
self.startline(u"cdef ")
|
160 |
+
self.visit(node.base_type)
|
161 |
+
self.put(u" ")
|
162 |
+
self.comma_separated_list(node.declarators, output_rhs=True)
|
163 |
+
self.endline()
|
164 |
+
|
165 |
+
def visit_container_node(self, node, decl, extras, attributes):
|
166 |
+
# TODO: visibility
|
167 |
+
self.startline(decl)
|
168 |
+
if node.name:
|
169 |
+
self.put(u' ')
|
170 |
+
self.put(node.name)
|
171 |
+
if node.cname is not None:
|
172 |
+
self.put(u' "%s"' % node.cname)
|
173 |
+
if extras:
|
174 |
+
self.put(extras)
|
175 |
+
self.endline(':')
|
176 |
+
self.indent()
|
177 |
+
if not attributes:
|
178 |
+
self.putline('pass')
|
179 |
+
else:
|
180 |
+
for attribute in attributes:
|
181 |
+
self.visit(attribute)
|
182 |
+
self.dedent()
|
183 |
+
|
184 |
+
def visit_CStructOrUnionDefNode(self, node):
|
185 |
+
if node.typedef_flag:
|
186 |
+
decl = u'ctypedef '
|
187 |
+
else:
|
188 |
+
decl = u'cdef '
|
189 |
+
if node.visibility == 'public':
|
190 |
+
decl += u'public '
|
191 |
+
if node.packed:
|
192 |
+
decl += u'packed '
|
193 |
+
decl += node.kind
|
194 |
+
self.visit_container_node(node, decl, None, node.attributes)
|
195 |
+
|
196 |
+
def visit_CppClassNode(self, node):
|
197 |
+
extras = ""
|
198 |
+
if node.templates:
|
199 |
+
extras = u"[%s]" % ", ".join(node.templates)
|
200 |
+
if node.base_classes:
|
201 |
+
extras += "(%s)" % ", ".join(node.base_classes)
|
202 |
+
self.visit_container_node(node, u"cdef cppclass", extras, node.attributes)
|
203 |
+
|
204 |
+
def visit_CEnumDefNode(self, node):
|
205 |
+
self.visit_container_node(node, u"cdef enum", None, node.items)
|
206 |
+
|
207 |
+
def visit_CEnumDefItemNode(self, node):
|
208 |
+
self.startline(node.name)
|
209 |
+
if node.cname:
|
210 |
+
self.put(u' "%s"' % node.cname)
|
211 |
+
if node.value:
|
212 |
+
self.put(u" = ")
|
213 |
+
self.visit(node.value)
|
214 |
+
self.endline()
|
215 |
+
|
216 |
+
def visit_CClassDefNode(self, node):
|
217 |
+
assert not node.module_name
|
218 |
+
if node.decorators:
|
219 |
+
for decorator in node.decorators:
|
220 |
+
self.visit(decorator)
|
221 |
+
self.startline(u"cdef class ")
|
222 |
+
self.put(node.class_name)
|
223 |
+
if node.base_class_name:
|
224 |
+
self.put(u"(")
|
225 |
+
if node.base_class_module:
|
226 |
+
self.put(node.base_class_module)
|
227 |
+
self.put(u".")
|
228 |
+
self.put(node.base_class_name)
|
229 |
+
self.put(u")")
|
230 |
+
self.endline(u":")
|
231 |
+
self.indent()
|
232 |
+
self.visit(node.body)
|
233 |
+
self.dedent()
|
234 |
+
|
235 |
+
def visit_CTypeDefNode(self, node):
|
236 |
+
self.startline(u"ctypedef ")
|
237 |
+
self.visit(node.base_type)
|
238 |
+
self.put(u" ")
|
239 |
+
self.visit(node.declarator)
|
240 |
+
self.endline()
|
241 |
+
|
242 |
+
def visit_FuncDefNode(self, node):
|
243 |
+
self.startline(u"def %s(" % node.name)
|
244 |
+
self.comma_separated_list(node.args)
|
245 |
+
self.endline(u"):")
|
246 |
+
self.indent()
|
247 |
+
self.visit(node.body)
|
248 |
+
self.dedent()
|
249 |
+
|
250 |
+
def visit_CArgDeclNode(self, node):
|
251 |
+
if node.base_type.name is not None:
|
252 |
+
self.visit(node.base_type)
|
253 |
+
self.put(u" ")
|
254 |
+
self.visit(node.declarator)
|
255 |
+
if node.default is not None:
|
256 |
+
self.put(u" = ")
|
257 |
+
self.visit(node.default)
|
258 |
+
|
259 |
+
def visit_CImportStatNode(self, node):
|
260 |
+
self.startline(u"cimport ")
|
261 |
+
self.put(node.module_name)
|
262 |
+
if node.as_name:
|
263 |
+
self.put(u" as ")
|
264 |
+
self.put(node.as_name)
|
265 |
+
self.endline()
|
266 |
+
|
267 |
+
def visit_FromCImportStatNode(self, node):
|
268 |
+
self.startline(u"from ")
|
269 |
+
self.put(node.module_name)
|
270 |
+
self.put(u" cimport ")
|
271 |
+
first = True
|
272 |
+
for pos, name, as_name, kind in node.imported_names:
|
273 |
+
assert kind is None
|
274 |
+
if first:
|
275 |
+
first = False
|
276 |
+
else:
|
277 |
+
self.put(u", ")
|
278 |
+
self.put(name)
|
279 |
+
if as_name:
|
280 |
+
self.put(u" as ")
|
281 |
+
self.put(as_name)
|
282 |
+
self.endline()
|
283 |
+
|
284 |
+
def visit_NameNode(self, node):
|
285 |
+
self.put(node.name)
|
286 |
+
|
287 |
+
def visit_IntNode(self, node):
|
288 |
+
self.put(node.value)
|
289 |
+
|
290 |
+
def visit_NoneNode(self, node):
|
291 |
+
self.put(u"None")
|
292 |
+
|
293 |
+
def visit_NotNode(self, node):
|
294 |
+
self.put(u"(not ")
|
295 |
+
self.visit(node.operand)
|
296 |
+
self.put(u")")
|
297 |
+
|
298 |
+
def visit_DecoratorNode(self, node):
|
299 |
+
self.startline("@")
|
300 |
+
self.visit(node.decorator)
|
301 |
+
self.endline()
|
302 |
+
|
303 |
+
def visit_BinopNode(self, node):
|
304 |
+
self.visit(node.operand1)
|
305 |
+
self.put(u" %s " % node.operator)
|
306 |
+
self.visit(node.operand2)
|
307 |
+
|
308 |
+
def visit_AttributeNode(self, node):
|
309 |
+
self.visit(node.obj)
|
310 |
+
self.put(u".%s" % node.attribute)
|
311 |
+
|
312 |
+
def visit_BoolNode(self, node):
|
313 |
+
self.put(str(node.value))
|
314 |
+
|
315 |
+
# FIXME: represent string nodes correctly
|
316 |
+
def visit_StringNode(self, node):
|
317 |
+
value = node.value
|
318 |
+
if value.encoding is not None:
|
319 |
+
value = value.encode(value.encoding)
|
320 |
+
self.put(repr(value))
|
321 |
+
|
322 |
+
def visit_PassStatNode(self, node):
|
323 |
+
self.startline(u"pass")
|
324 |
+
self.endline()
|
325 |
+
|
326 |
+
class CodeWriter(DeclarationWriter):
|
327 |
+
|
328 |
+
def visit_SingleAssignmentNode(self, node):
|
329 |
+
self.startline()
|
330 |
+
self.visit(node.lhs)
|
331 |
+
self.put(u" = ")
|
332 |
+
self.visit(node.rhs)
|
333 |
+
self.endline()
|
334 |
+
|
335 |
+
def visit_CascadedAssignmentNode(self, node):
|
336 |
+
self.startline()
|
337 |
+
for lhs in node.lhs_list:
|
338 |
+
self.visit(lhs)
|
339 |
+
self.put(u" = ")
|
340 |
+
self.visit(node.rhs)
|
341 |
+
self.endline()
|
342 |
+
|
343 |
+
def visit_PrintStatNode(self, node):
|
344 |
+
self.startline(u"print ")
|
345 |
+
self.comma_separated_list(node.arg_tuple.args)
|
346 |
+
if not node.append_newline:
|
347 |
+
self.put(u",")
|
348 |
+
self.endline()
|
349 |
+
|
350 |
+
def visit_ForInStatNode(self, node):
|
351 |
+
self.startline(u"for ")
|
352 |
+
self.visit(node.target)
|
353 |
+
self.put(u" in ")
|
354 |
+
self.visit(node.iterator.sequence)
|
355 |
+
self.endline(u":")
|
356 |
+
self.indent()
|
357 |
+
self.visit(node.body)
|
358 |
+
self.dedent()
|
359 |
+
if node.else_clause is not None:
|
360 |
+
self.line(u"else:")
|
361 |
+
self.indent()
|
362 |
+
self.visit(node.else_clause)
|
363 |
+
self.dedent()
|
364 |
+
|
365 |
+
def visit_IfStatNode(self, node):
|
366 |
+
# The IfClauseNode is handled directly without a separate match
|
367 |
+
# for clariy.
|
368 |
+
self.startline(u"if ")
|
369 |
+
self.visit(node.if_clauses[0].condition)
|
370 |
+
self.endline(":")
|
371 |
+
self.indent()
|
372 |
+
self.visit(node.if_clauses[0].body)
|
373 |
+
self.dedent()
|
374 |
+
for clause in node.if_clauses[1:]:
|
375 |
+
self.startline("elif ")
|
376 |
+
self.visit(clause.condition)
|
377 |
+
self.endline(":")
|
378 |
+
self.indent()
|
379 |
+
self.visit(clause.body)
|
380 |
+
self.dedent()
|
381 |
+
if node.else_clause is not None:
|
382 |
+
self.line("else:")
|
383 |
+
self.indent()
|
384 |
+
self.visit(node.else_clause)
|
385 |
+
self.dedent()
|
386 |
+
|
387 |
+
def visit_SequenceNode(self, node):
|
388 |
+
self.comma_separated_list(node.args) # Might need to discover whether we need () around tuples...hmm...
|
389 |
+
|
390 |
+
def visit_SimpleCallNode(self, node):
|
391 |
+
self.visit(node.function)
|
392 |
+
self.put(u"(")
|
393 |
+
self.comma_separated_list(node.args)
|
394 |
+
self.put(")")
|
395 |
+
|
396 |
+
def visit_GeneralCallNode(self, node):
|
397 |
+
self.visit(node.function)
|
398 |
+
self.put(u"(")
|
399 |
+
posarg = node.positional_args
|
400 |
+
if isinstance(posarg, AsTupleNode):
|
401 |
+
self.visit(posarg.arg)
|
402 |
+
else:
|
403 |
+
self.comma_separated_list(posarg.args) # TupleNode.args
|
404 |
+
if node.keyword_args:
|
405 |
+
if isinstance(node.keyword_args, DictNode):
|
406 |
+
for i, (name, value) in enumerate(node.keyword_args.key_value_pairs):
|
407 |
+
if i > 0:
|
408 |
+
self.put(', ')
|
409 |
+
self.visit(name)
|
410 |
+
self.put('=')
|
411 |
+
self.visit(value)
|
412 |
+
else:
|
413 |
+
raise Exception("Not implemented yet")
|
414 |
+
self.put(u")")
|
415 |
+
|
416 |
+
def visit_ExprStatNode(self, node):
|
417 |
+
self.startline()
|
418 |
+
self.visit(node.expr)
|
419 |
+
self.endline()
|
420 |
+
|
421 |
+
def visit_InPlaceAssignmentNode(self, node):
|
422 |
+
self.startline()
|
423 |
+
self.visit(node.lhs)
|
424 |
+
self.put(u" %s= " % node.operator)
|
425 |
+
self.visit(node.rhs)
|
426 |
+
self.endline()
|
427 |
+
|
428 |
+
def visit_WithStatNode(self, node):
|
429 |
+
self.startline()
|
430 |
+
self.put(u"with ")
|
431 |
+
self.visit(node.manager)
|
432 |
+
if node.target is not None:
|
433 |
+
self.put(u" as ")
|
434 |
+
self.visit(node.target)
|
435 |
+
self.endline(u":")
|
436 |
+
self.indent()
|
437 |
+
self.visit(node.body)
|
438 |
+
self.dedent()
|
439 |
+
|
440 |
+
def visit_TryFinallyStatNode(self, node):
|
441 |
+
self.line(u"try:")
|
442 |
+
self.indent()
|
443 |
+
self.visit(node.body)
|
444 |
+
self.dedent()
|
445 |
+
self.line(u"finally:")
|
446 |
+
self.indent()
|
447 |
+
self.visit(node.finally_clause)
|
448 |
+
self.dedent()
|
449 |
+
|
450 |
+
def visit_TryExceptStatNode(self, node):
|
451 |
+
self.line(u"try:")
|
452 |
+
self.indent()
|
453 |
+
self.visit(node.body)
|
454 |
+
self.dedent()
|
455 |
+
for x in node.except_clauses:
|
456 |
+
self.visit(x)
|
457 |
+
if node.else_clause is not None:
|
458 |
+
self.visit(node.else_clause)
|
459 |
+
|
460 |
+
def visit_ExceptClauseNode(self, node):
|
461 |
+
self.startline(u"except")
|
462 |
+
if node.pattern is not None:
|
463 |
+
self.put(u" ")
|
464 |
+
self.visit(node.pattern)
|
465 |
+
if node.target is not None:
|
466 |
+
self.put(u", ")
|
467 |
+
self.visit(node.target)
|
468 |
+
self.endline(":")
|
469 |
+
self.indent()
|
470 |
+
self.visit(node.body)
|
471 |
+
self.dedent()
|
472 |
+
|
473 |
+
def visit_ReturnStatNode(self, node):
|
474 |
+
self.startline("return ")
|
475 |
+
self.visit(node.value)
|
476 |
+
self.endline()
|
477 |
+
|
478 |
+
def visit_ReraiseStatNode(self, node):
|
479 |
+
self.line("raise")
|
480 |
+
|
481 |
+
def visit_ImportNode(self, node):
|
482 |
+
self.put(u"(import %s)" % node.module_name.value)
|
483 |
+
|
484 |
+
def visit_TempsBlockNode(self, node):
|
485 |
+
"""
|
486 |
+
Temporaries are output like $1_1', where the first number is
|
487 |
+
an index of the TempsBlockNode and the second number is an index
|
488 |
+
of the temporary which that block allocates.
|
489 |
+
"""
|
490 |
+
idx = 0
|
491 |
+
for handle in node.temps:
|
492 |
+
self.tempnames[handle] = "$%d_%d" % (self.tempblockindex, idx)
|
493 |
+
idx += 1
|
494 |
+
self.tempblockindex += 1
|
495 |
+
self.visit(node.body)
|
496 |
+
|
497 |
+
def visit_TempRefNode(self, node):
|
498 |
+
self.put(self.tempnames[node.handle])
|
499 |
+
|
500 |
+
|
501 |
+
class PxdWriter(DeclarationWriter):
|
502 |
+
def __call__(self, node):
|
503 |
+
print(u'\n'.join(self.write(node).lines))
|
504 |
+
return node
|
505 |
+
|
506 |
+
def visit_CFuncDefNode(self, node):
|
507 |
+
if 'inline' in node.modifiers:
|
508 |
+
return
|
509 |
+
if node.overridable:
|
510 |
+
self.startline(u'cpdef ')
|
511 |
+
else:
|
512 |
+
self.startline(u'cdef ')
|
513 |
+
if node.visibility != 'private':
|
514 |
+
self.put(node.visibility)
|
515 |
+
self.put(u' ')
|
516 |
+
if node.api:
|
517 |
+
self.put(u'api ')
|
518 |
+
self.visit(node.declarator)
|
519 |
+
|
520 |
+
def visit_StatNode(self, node):
|
521 |
+
pass
|
522 |
+
|
523 |
+
|
524 |
+
class ExpressionWriter(TreeVisitor):
|
525 |
+
|
526 |
+
def __init__(self, result=None):
|
527 |
+
super(ExpressionWriter, self).__init__()
|
528 |
+
if result is None:
|
529 |
+
result = u""
|
530 |
+
self.result = result
|
531 |
+
self.precedence = [0]
|
532 |
+
|
533 |
+
def write(self, tree):
|
534 |
+
self.visit(tree)
|
535 |
+
return self.result
|
536 |
+
|
537 |
+
def put(self, s):
|
538 |
+
self.result += s
|
539 |
+
|
540 |
+
def remove(self, s):
|
541 |
+
if self.result.endswith(s):
|
542 |
+
self.result = self.result[:-len(s)]
|
543 |
+
|
544 |
+
def comma_separated_list(self, items):
|
545 |
+
if len(items) > 0:
|
546 |
+
for item in items[:-1]:
|
547 |
+
self.visit(item)
|
548 |
+
self.put(u", ")
|
549 |
+
self.visit(items[-1])
|
550 |
+
|
551 |
+
def visit_Node(self, node):
|
552 |
+
raise AssertionError("Node not handled by serializer: %r" % node)
|
553 |
+
|
554 |
+
def visit_NameNode(self, node):
|
555 |
+
self.put(node.name)
|
556 |
+
|
557 |
+
def visit_NoneNode(self, node):
|
558 |
+
self.put(u"None")
|
559 |
+
|
560 |
+
def visit_EllipsisNode(self, node):
|
561 |
+
self.put(u"...")
|
562 |
+
|
563 |
+
def visit_BoolNode(self, node):
|
564 |
+
self.put(str(node.value))
|
565 |
+
|
566 |
+
def visit_ConstNode(self, node):
|
567 |
+
self.put(str(node.value))
|
568 |
+
|
569 |
+
def visit_ImagNode(self, node):
|
570 |
+
self.put(node.value)
|
571 |
+
self.put(u"j")
|
572 |
+
|
573 |
+
def emit_string(self, node, prefix=u""):
|
574 |
+
repr_val = repr(node.value)
|
575 |
+
if repr_val[0] in 'ub':
|
576 |
+
repr_val = repr_val[1:]
|
577 |
+
self.put(u"%s%s" % (prefix, repr_val))
|
578 |
+
|
579 |
+
def visit_BytesNode(self, node):
|
580 |
+
self.emit_string(node, u"b")
|
581 |
+
|
582 |
+
def visit_StringNode(self, node):
|
583 |
+
self.emit_string(node)
|
584 |
+
|
585 |
+
def visit_UnicodeNode(self, node):
|
586 |
+
self.emit_string(node, u"u")
|
587 |
+
|
588 |
+
def emit_sequence(self, node, parens=(u"", u"")):
|
589 |
+
open_paren, close_paren = parens
|
590 |
+
items = node.subexpr_nodes()
|
591 |
+
self.put(open_paren)
|
592 |
+
self.comma_separated_list(items)
|
593 |
+
self.put(close_paren)
|
594 |
+
|
595 |
+
def visit_ListNode(self, node):
|
596 |
+
self.emit_sequence(node, u"[]")
|
597 |
+
|
598 |
+
def visit_TupleNode(self, node):
|
599 |
+
self.emit_sequence(node, u"()")
|
600 |
+
|
601 |
+
def visit_SetNode(self, node):
|
602 |
+
if len(node.subexpr_nodes()) > 0:
|
603 |
+
self.emit_sequence(node, u"{}")
|
604 |
+
else:
|
605 |
+
self.put(u"set()")
|
606 |
+
|
607 |
+
def visit_DictNode(self, node):
|
608 |
+
self.emit_sequence(node, u"{}")
|
609 |
+
|
610 |
+
def visit_DictItemNode(self, node):
|
611 |
+
self.visit(node.key)
|
612 |
+
self.put(u": ")
|
613 |
+
self.visit(node.value)
|
614 |
+
|
615 |
+
unop_precedence = {
|
616 |
+
'not': 3, '!': 3,
|
617 |
+
'+': 11, '-': 11, '~': 11,
|
618 |
+
}
|
619 |
+
binop_precedence = {
|
620 |
+
'or': 1,
|
621 |
+
'and': 2,
|
622 |
+
# unary: 'not': 3, '!': 3,
|
623 |
+
'in': 4, 'not_in': 4, 'is': 4, 'is_not': 4, '<': 4, '<=': 4, '>': 4, '>=': 4, '!=': 4, '==': 4,
|
624 |
+
'|': 5,
|
625 |
+
'^': 6,
|
626 |
+
'&': 7,
|
627 |
+
'<<': 8, '>>': 8,
|
628 |
+
'+': 9, '-': 9,
|
629 |
+
'*': 10, '@': 10, '/': 10, '//': 10, '%': 10,
|
630 |
+
# unary: '+': 11, '-': 11, '~': 11
|
631 |
+
'**': 12,
|
632 |
+
}
|
633 |
+
|
634 |
+
def operator_enter(self, new_prec):
|
635 |
+
old_prec = self.precedence[-1]
|
636 |
+
if old_prec > new_prec:
|
637 |
+
self.put(u"(")
|
638 |
+
self.precedence.append(new_prec)
|
639 |
+
|
640 |
+
def operator_exit(self):
|
641 |
+
old_prec, new_prec = self.precedence[-2:]
|
642 |
+
if old_prec > new_prec:
|
643 |
+
self.put(u")")
|
644 |
+
self.precedence.pop()
|
645 |
+
|
646 |
+
def visit_NotNode(self, node):
|
647 |
+
op = 'not'
|
648 |
+
prec = self.unop_precedence[op]
|
649 |
+
self.operator_enter(prec)
|
650 |
+
self.put(u"not ")
|
651 |
+
self.visit(node.operand)
|
652 |
+
self.operator_exit()
|
653 |
+
|
654 |
+
def visit_UnopNode(self, node):
|
655 |
+
op = node.operator
|
656 |
+
prec = self.unop_precedence[op]
|
657 |
+
self.operator_enter(prec)
|
658 |
+
self.put(u"%s" % node.operator)
|
659 |
+
self.visit(node.operand)
|
660 |
+
self.operator_exit()
|
661 |
+
|
662 |
+
def visit_BinopNode(self, node):
|
663 |
+
op = node.operator
|
664 |
+
prec = self.binop_precedence.get(op, 0)
|
665 |
+
self.operator_enter(prec)
|
666 |
+
self.visit(node.operand1)
|
667 |
+
self.put(u" %s " % op.replace('_', ' '))
|
668 |
+
self.visit(node.operand2)
|
669 |
+
self.operator_exit()
|
670 |
+
|
671 |
+
def visit_BoolBinopNode(self, node):
|
672 |
+
self.visit_BinopNode(node)
|
673 |
+
|
674 |
+
def visit_PrimaryCmpNode(self, node):
|
675 |
+
self.visit_BinopNode(node)
|
676 |
+
|
677 |
+
def visit_IndexNode(self, node):
|
678 |
+
self.visit(node.base)
|
679 |
+
self.put(u"[")
|
680 |
+
if isinstance(node.index, TupleNode):
|
681 |
+
if node.index.subexpr_nodes():
|
682 |
+
self.emit_sequence(node.index)
|
683 |
+
else:
|
684 |
+
self.put(u"()")
|
685 |
+
else:
|
686 |
+
self.visit(node.index)
|
687 |
+
self.put(u"]")
|
688 |
+
|
689 |
+
def visit_SliceIndexNode(self, node):
|
690 |
+
self.visit(node.base)
|
691 |
+
self.put(u"[")
|
692 |
+
if node.start:
|
693 |
+
self.visit(node.start)
|
694 |
+
self.put(u":")
|
695 |
+
if node.stop:
|
696 |
+
self.visit(node.stop)
|
697 |
+
if node.slice:
|
698 |
+
self.put(u":")
|
699 |
+
self.visit(node.slice)
|
700 |
+
self.put(u"]")
|
701 |
+
|
702 |
+
def visit_SliceNode(self, node):
|
703 |
+
if not node.start.is_none:
|
704 |
+
self.visit(node.start)
|
705 |
+
self.put(u":")
|
706 |
+
if not node.stop.is_none:
|
707 |
+
self.visit(node.stop)
|
708 |
+
if not node.step.is_none:
|
709 |
+
self.put(u":")
|
710 |
+
self.visit(node.step)
|
711 |
+
|
712 |
+
def visit_CondExprNode(self, node):
|
713 |
+
self.visit(node.true_val)
|
714 |
+
self.put(u" if ")
|
715 |
+
self.visit(node.test)
|
716 |
+
self.put(u" else ")
|
717 |
+
self.visit(node.false_val)
|
718 |
+
|
719 |
+
def visit_AttributeNode(self, node):
|
720 |
+
self.visit(node.obj)
|
721 |
+
self.put(u".%s" % node.attribute)
|
722 |
+
|
723 |
+
def visit_SimpleCallNode(self, node):
|
724 |
+
self.visit(node.function)
|
725 |
+
self.put(u"(")
|
726 |
+
self.comma_separated_list(node.args)
|
727 |
+
self.put(")")
|
728 |
+
|
729 |
+
def emit_pos_args(self, node):
|
730 |
+
if node is None:
|
731 |
+
return
|
732 |
+
if isinstance(node, AddNode):
|
733 |
+
self.emit_pos_args(node.operand1)
|
734 |
+
self.emit_pos_args(node.operand2)
|
735 |
+
elif isinstance(node, TupleNode):
|
736 |
+
for expr in node.subexpr_nodes():
|
737 |
+
self.visit(expr)
|
738 |
+
self.put(u", ")
|
739 |
+
elif isinstance(node, AsTupleNode):
|
740 |
+
self.put("*")
|
741 |
+
self.visit(node.arg)
|
742 |
+
self.put(u", ")
|
743 |
+
else:
|
744 |
+
self.visit(node)
|
745 |
+
self.put(u", ")
|
746 |
+
|
747 |
+
def emit_kwd_args(self, node):
|
748 |
+
if node is None:
|
749 |
+
return
|
750 |
+
if isinstance(node, MergedDictNode):
|
751 |
+
for expr in node.subexpr_nodes():
|
752 |
+
self.emit_kwd_args(expr)
|
753 |
+
elif isinstance(node, DictNode):
|
754 |
+
for expr in node.subexpr_nodes():
|
755 |
+
self.put(u"%s=" % expr.key.value)
|
756 |
+
self.visit(expr.value)
|
757 |
+
self.put(u", ")
|
758 |
+
else:
|
759 |
+
self.put(u"**")
|
760 |
+
self.visit(node)
|
761 |
+
self.put(u", ")
|
762 |
+
|
763 |
+
def visit_GeneralCallNode(self, node):
|
764 |
+
self.visit(node.function)
|
765 |
+
self.put(u"(")
|
766 |
+
self.emit_pos_args(node.positional_args)
|
767 |
+
self.emit_kwd_args(node.keyword_args)
|
768 |
+
self.remove(u", ")
|
769 |
+
self.put(")")
|
770 |
+
|
771 |
+
def emit_comprehension(self, body, target,
|
772 |
+
sequence, condition,
|
773 |
+
parens=(u"", u"")):
|
774 |
+
open_paren, close_paren = parens
|
775 |
+
self.put(open_paren)
|
776 |
+
self.visit(body)
|
777 |
+
self.put(u" for ")
|
778 |
+
self.visit(target)
|
779 |
+
self.put(u" in ")
|
780 |
+
self.visit(sequence)
|
781 |
+
if condition:
|
782 |
+
self.put(u" if ")
|
783 |
+
self.visit(condition)
|
784 |
+
self.put(close_paren)
|
785 |
+
|
786 |
+
def visit_ComprehensionAppendNode(self, node):
|
787 |
+
self.visit(node.expr)
|
788 |
+
|
789 |
+
def visit_DictComprehensionAppendNode(self, node):
|
790 |
+
self.visit(node.key_expr)
|
791 |
+
self.put(u": ")
|
792 |
+
self.visit(node.value_expr)
|
793 |
+
|
794 |
+
def visit_ComprehensionNode(self, node):
|
795 |
+
tpmap = {'list': u"[]", 'dict': u"{}", 'set': u"{}"}
|
796 |
+
parens = tpmap[node.type.py_type_name()]
|
797 |
+
body = node.loop.body
|
798 |
+
target = node.loop.target
|
799 |
+
sequence = node.loop.iterator.sequence
|
800 |
+
condition = None
|
801 |
+
if hasattr(body, 'if_clauses'):
|
802 |
+
# type(body) is Nodes.IfStatNode
|
803 |
+
condition = body.if_clauses[0].condition
|
804 |
+
body = body.if_clauses[0].body
|
805 |
+
self.emit_comprehension(body, target, sequence, condition, parens)
|
806 |
+
|
807 |
+
def visit_GeneratorExpressionNode(self, node):
|
808 |
+
body = node.loop.body
|
809 |
+
target = node.loop.target
|
810 |
+
sequence = node.loop.iterator.sequence
|
811 |
+
condition = None
|
812 |
+
if hasattr(body, 'if_clauses'):
|
813 |
+
# type(body) is Nodes.IfStatNode
|
814 |
+
condition = body.if_clauses[0].condition
|
815 |
+
body = body.if_clauses[0].body.expr.arg
|
816 |
+
elif hasattr(body, 'expr'):
|
817 |
+
# type(body) is Nodes.ExprStatNode
|
818 |
+
body = body.expr.arg
|
819 |
+
self.emit_comprehension(body, target, sequence, condition, u"()")
|
venv/Lib/site-packages/Cython/Compiler/AnalysedTreeTransforms.py
ADDED
@@ -0,0 +1,99 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from __future__ import absolute_import
|
2 |
+
|
3 |
+
from .Visitor import ScopeTrackingTransform
|
4 |
+
from .Nodes import StatListNode, SingleAssignmentNode, CFuncDefNode, DefNode
|
5 |
+
from .ExprNodes import DictNode, DictItemNode, NameNode, UnicodeNode
|
6 |
+
from .PyrexTypes import py_object_type
|
7 |
+
from .StringEncoding import EncodedString
|
8 |
+
from . import Symtab
|
9 |
+
|
10 |
+
class AutoTestDictTransform(ScopeTrackingTransform):
|
11 |
+
# Handles autotestdict directive
|
12 |
+
|
13 |
+
blacklist = ['__cinit__', '__dealloc__', '__richcmp__',
|
14 |
+
'__nonzero__', '__bool__',
|
15 |
+
'__len__', '__contains__']
|
16 |
+
|
17 |
+
def visit_ModuleNode(self, node):
|
18 |
+
if node.is_pxd:
|
19 |
+
return node
|
20 |
+
self.scope_type = 'module'
|
21 |
+
self.scope_node = node
|
22 |
+
|
23 |
+
if not self.current_directives['autotestdict']:
|
24 |
+
return node
|
25 |
+
self.all_docstrings = self.current_directives['autotestdict.all']
|
26 |
+
self.cdef_docstrings = self.all_docstrings or self.current_directives['autotestdict.cdef']
|
27 |
+
|
28 |
+
assert isinstance(node.body, StatListNode)
|
29 |
+
|
30 |
+
# First see if __test__ is already created
|
31 |
+
if u'__test__' in node.scope.entries:
|
32 |
+
# Do nothing
|
33 |
+
return node
|
34 |
+
|
35 |
+
pos = node.pos
|
36 |
+
|
37 |
+
self.tests = []
|
38 |
+
self.testspos = node.pos
|
39 |
+
|
40 |
+
test_dict_entry = node.scope.declare_var(EncodedString(u'__test__'),
|
41 |
+
py_object_type,
|
42 |
+
pos,
|
43 |
+
visibility='public')
|
44 |
+
create_test_dict_assignment = SingleAssignmentNode(pos,
|
45 |
+
lhs=NameNode(pos, name=EncodedString(u'__test__'),
|
46 |
+
entry=test_dict_entry),
|
47 |
+
rhs=DictNode(pos, key_value_pairs=self.tests))
|
48 |
+
self.visitchildren(node)
|
49 |
+
node.body.stats.append(create_test_dict_assignment)
|
50 |
+
return node
|
51 |
+
|
52 |
+
def add_test(self, testpos, path, doctest):
|
53 |
+
pos = self.testspos
|
54 |
+
keystr = u'%s (line %d)' % (path, testpos[1])
|
55 |
+
key = UnicodeNode(pos, value=EncodedString(keystr))
|
56 |
+
value = UnicodeNode(pos, value=doctest)
|
57 |
+
self.tests.append(DictItemNode(pos, key=key, value=value))
|
58 |
+
|
59 |
+
def visit_ExprNode(self, node):
|
60 |
+
# expressions cannot contain functions and lambda expressions
|
61 |
+
# do not have a docstring
|
62 |
+
return node
|
63 |
+
|
64 |
+
def visit_FuncDefNode(self, node):
|
65 |
+
if not node.doc or (isinstance(node, DefNode) and node.fused_py_func):
|
66 |
+
return node
|
67 |
+
if not self.cdef_docstrings:
|
68 |
+
if isinstance(node, CFuncDefNode) and not node.py_func:
|
69 |
+
return node
|
70 |
+
if not self.all_docstrings and '>>>' not in node.doc:
|
71 |
+
return node
|
72 |
+
|
73 |
+
pos = self.testspos
|
74 |
+
if self.scope_type == 'module':
|
75 |
+
path = node.entry.name
|
76 |
+
elif self.scope_type in ('pyclass', 'cclass'):
|
77 |
+
if isinstance(node, CFuncDefNode):
|
78 |
+
if node.py_func is not None:
|
79 |
+
name = node.py_func.name
|
80 |
+
else:
|
81 |
+
name = node.entry.name
|
82 |
+
else:
|
83 |
+
name = node.name
|
84 |
+
if self.scope_type == 'cclass' and name in self.blacklist:
|
85 |
+
return node
|
86 |
+
if self.scope_type == 'pyclass':
|
87 |
+
class_name = self.scope_node.name
|
88 |
+
else:
|
89 |
+
class_name = self.scope_node.class_name
|
90 |
+
if isinstance(node.entry.scope, Symtab.PropertyScope):
|
91 |
+
property_method_name = node.entry.scope.name
|
92 |
+
path = "%s.%s.%s" % (class_name, node.entry.scope.name,
|
93 |
+
node.entry.name)
|
94 |
+
else:
|
95 |
+
path = "%s.%s" % (class_name, node.entry.name)
|
96 |
+
else:
|
97 |
+
assert False
|
98 |
+
self.add_test(node.pos, path, node.doc)
|
99 |
+
return node
|
venv/Lib/site-packages/Cython/Compiler/Annotate.py
ADDED
@@ -0,0 +1,317 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Note: Work in progress
|
2 |
+
|
3 |
+
from __future__ import absolute_import
|
4 |
+
|
5 |
+
import os
|
6 |
+
import os.path
|
7 |
+
import re
|
8 |
+
import codecs
|
9 |
+
import textwrap
|
10 |
+
from datetime import datetime
|
11 |
+
from functools import partial
|
12 |
+
from collections import defaultdict
|
13 |
+
from xml.sax.saxutils import escape as html_escape
|
14 |
+
try:
|
15 |
+
from StringIO import StringIO
|
16 |
+
except ImportError:
|
17 |
+
from io import StringIO # does not support writing 'str' in Py2
|
18 |
+
|
19 |
+
from . import Version
|
20 |
+
from .Code import CCodeWriter
|
21 |
+
from .. import Utils
|
22 |
+
|
23 |
+
|
24 |
+
class AnnotationCCodeWriter(CCodeWriter):
|
25 |
+
|
26 |
+
def __init__(self, create_from=None, buffer=None, copy_formatting=True):
|
27 |
+
CCodeWriter.__init__(self, create_from, buffer, copy_formatting=copy_formatting)
|
28 |
+
if create_from is None:
|
29 |
+
self.annotation_buffer = StringIO()
|
30 |
+
self.last_annotated_pos = None
|
31 |
+
# annotations[filename][line] -> [(column, AnnotationItem)*]
|
32 |
+
self.annotations = defaultdict(partial(defaultdict, list))
|
33 |
+
# code[filename][line] -> str
|
34 |
+
self.code = defaultdict(partial(defaultdict, str))
|
35 |
+
# scopes[filename][line] -> set(scopes)
|
36 |
+
self.scopes = defaultdict(partial(defaultdict, set))
|
37 |
+
else:
|
38 |
+
# When creating an insertion point, keep references to the same database
|
39 |
+
self.annotation_buffer = create_from.annotation_buffer
|
40 |
+
self.annotations = create_from.annotations
|
41 |
+
self.code = create_from.code
|
42 |
+
self.scopes = create_from.scopes
|
43 |
+
self.last_annotated_pos = create_from.last_annotated_pos
|
44 |
+
|
45 |
+
def create_new(self, create_from, buffer, copy_formatting):
|
46 |
+
return AnnotationCCodeWriter(create_from, buffer, copy_formatting)
|
47 |
+
|
48 |
+
def write(self, s):
|
49 |
+
CCodeWriter.write(self, s)
|
50 |
+
self.annotation_buffer.write(s)
|
51 |
+
|
52 |
+
def mark_pos(self, pos, trace=True):
|
53 |
+
if pos is not None:
|
54 |
+
CCodeWriter.mark_pos(self, pos, trace)
|
55 |
+
if self.funcstate and self.funcstate.scope:
|
56 |
+
# lambdas and genexprs can result in multiple scopes per line => keep them in a set
|
57 |
+
self.scopes[pos[0].filename][pos[1]].add(self.funcstate.scope)
|
58 |
+
if self.last_annotated_pos:
|
59 |
+
source_desc, line, _ = self.last_annotated_pos
|
60 |
+
pos_code = self.code[source_desc.filename]
|
61 |
+
pos_code[line] += self.annotation_buffer.getvalue()
|
62 |
+
self.annotation_buffer = StringIO()
|
63 |
+
self.last_annotated_pos = pos
|
64 |
+
|
65 |
+
def annotate(self, pos, item):
|
66 |
+
self.annotations[pos[0].filename][pos[1]].append((pos[2], item))
|
67 |
+
|
68 |
+
def _css(self):
|
69 |
+
"""css template will later allow to choose a colormap"""
|
70 |
+
css = [self._css_template]
|
71 |
+
for i in range(255):
|
72 |
+
color = u"FFFF%02x" % int(255/(1+i/10.0))
|
73 |
+
css.append('.cython.score-%d {background-color: #%s;}' % (i, color))
|
74 |
+
try:
|
75 |
+
from pygments.formatters import HtmlFormatter
|
76 |
+
except ImportError:
|
77 |
+
pass
|
78 |
+
else:
|
79 |
+
css.append(HtmlFormatter().get_style_defs('.cython'))
|
80 |
+
return '\n'.join(css)
|
81 |
+
|
82 |
+
_css_template = textwrap.dedent("""
|
83 |
+
body.cython { font-family: courier; font-size: 12; }
|
84 |
+
|
85 |
+
.cython.tag { }
|
86 |
+
.cython.line { margin: 0em }
|
87 |
+
.cython.code { font-size: 9; color: #444444; display: none; margin: 0px 0px 0px 8px; border-left: 8px none; }
|
88 |
+
|
89 |
+
.cython.line .run { background-color: #B0FFB0; }
|
90 |
+
.cython.line .mis { background-color: #FFB0B0; }
|
91 |
+
.cython.code.run { border-left: 8px solid #B0FFB0; }
|
92 |
+
.cython.code.mis { border-left: 8px solid #FFB0B0; }
|
93 |
+
|
94 |
+
.cython.code .py_c_api { color: red; }
|
95 |
+
.cython.code .py_macro_api { color: #FF7000; }
|
96 |
+
.cython.code .pyx_c_api { color: #FF3000; }
|
97 |
+
.cython.code .pyx_macro_api { color: #FF7000; }
|
98 |
+
.cython.code .refnanny { color: #FFA000; }
|
99 |
+
.cython.code .trace { color: #FFA000; }
|
100 |
+
.cython.code .error_goto { color: #FFA000; }
|
101 |
+
|
102 |
+
.cython.code .coerce { color: #008000; border: 1px dotted #008000 }
|
103 |
+
.cython.code .py_attr { color: #FF0000; font-weight: bold; }
|
104 |
+
.cython.code .c_attr { color: #0000FF; }
|
105 |
+
.cython.code .py_call { color: #FF0000; font-weight: bold; }
|
106 |
+
.cython.code .c_call { color: #0000FF; }
|
107 |
+
""")
|
108 |
+
|
109 |
+
# on-click toggle function to show/hide C source code
|
110 |
+
_onclick_attr = ' onclick="{0}"'.format((
|
111 |
+
"(function(s){"
|
112 |
+
" s.display = s.display === 'block' ? 'none' : 'block'"
|
113 |
+
"})(this.nextElementSibling.style)"
|
114 |
+
).replace(' ', '') # poor dev's JS minification
|
115 |
+
)
|
116 |
+
|
117 |
+
def save_annotation(self, source_filename, target_filename, coverage_xml=None):
|
118 |
+
with Utils.open_source_file(source_filename) as f:
|
119 |
+
code = f.read()
|
120 |
+
generated_code = self.code.get(source_filename, {})
|
121 |
+
c_file = Utils.decode_filename(os.path.basename(target_filename))
|
122 |
+
html_filename = os.path.splitext(target_filename)[0] + ".html"
|
123 |
+
|
124 |
+
with codecs.open(html_filename, "w", encoding="UTF-8") as out_buffer:
|
125 |
+
out_buffer.write(self._save_annotation(code, generated_code, c_file, source_filename, coverage_xml))
|
126 |
+
|
127 |
+
def _save_annotation_header(self, c_file, source_filename, coverage_timestamp=None):
|
128 |
+
coverage_info = ''
|
129 |
+
if coverage_timestamp:
|
130 |
+
coverage_info = u' with coverage data from {timestamp}'.format(
|
131 |
+
timestamp=datetime.fromtimestamp(int(coverage_timestamp) // 1000))
|
132 |
+
|
133 |
+
outlist = [
|
134 |
+
textwrap.dedent(u'''\
|
135 |
+
<!DOCTYPE html>
|
136 |
+
<!-- Generated by Cython {watermark} -->
|
137 |
+
<html>
|
138 |
+
<head>
|
139 |
+
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
140 |
+
<title>Cython: {filename}</title>
|
141 |
+
<style type="text/css">
|
142 |
+
{css}
|
143 |
+
</style>
|
144 |
+
</head>
|
145 |
+
<body class="cython">
|
146 |
+
<p><span style="border-bottom: solid 1px grey;">Generated by Cython {watermark}</span>{more_info}</p>
|
147 |
+
<p>
|
148 |
+
<span style="background-color: #FFFF00">Yellow lines</span> hint at Python interaction.<br />
|
149 |
+
Click on a line that starts with a "<code>+</code>" to see the C code that Cython generated for it.
|
150 |
+
</p>
|
151 |
+
''').format(css=self._css(), watermark=Version.watermark,
|
152 |
+
filename=os.path.basename(source_filename) if source_filename else '',
|
153 |
+
more_info=coverage_info)
|
154 |
+
]
|
155 |
+
if c_file:
|
156 |
+
outlist.append(u'<p>Raw output: <a href="%s">%s</a></p>\n' % (c_file, c_file))
|
157 |
+
return outlist
|
158 |
+
|
159 |
+
def _save_annotation_footer(self):
|
160 |
+
return (u'</body></html>\n',)
|
161 |
+
|
162 |
+
def _save_annotation(self, code, generated_code, c_file=None, source_filename=None, coverage_xml=None):
|
163 |
+
"""
|
164 |
+
lines : original cython source code split by lines
|
165 |
+
generated_code : generated c code keyed by line number in original file
|
166 |
+
target filename : name of the file in which to store the generated html
|
167 |
+
c_file : filename in which the c_code has been written
|
168 |
+
"""
|
169 |
+
if coverage_xml is not None and source_filename:
|
170 |
+
coverage_timestamp = coverage_xml.get('timestamp', '').strip()
|
171 |
+
covered_lines = self._get_line_coverage(coverage_xml, source_filename)
|
172 |
+
else:
|
173 |
+
coverage_timestamp = covered_lines = None
|
174 |
+
annotation_items = dict(self.annotations[source_filename])
|
175 |
+
scopes = dict(self.scopes[source_filename])
|
176 |
+
|
177 |
+
outlist = []
|
178 |
+
outlist.extend(self._save_annotation_header(c_file, source_filename, coverage_timestamp))
|
179 |
+
outlist.extend(self._save_annotation_body(code, generated_code, annotation_items, scopes, covered_lines))
|
180 |
+
outlist.extend(self._save_annotation_footer())
|
181 |
+
return ''.join(outlist)
|
182 |
+
|
183 |
+
def _get_line_coverage(self, coverage_xml, source_filename):
|
184 |
+
coverage_data = None
|
185 |
+
for entry in coverage_xml.iterfind('.//class'):
|
186 |
+
if not entry.get('filename'):
|
187 |
+
continue
|
188 |
+
if (entry.get('filename') == source_filename or
|
189 |
+
os.path.abspath(entry.get('filename')) == source_filename):
|
190 |
+
coverage_data = entry
|
191 |
+
break
|
192 |
+
elif source_filename.endswith(entry.get('filename')):
|
193 |
+
coverage_data = entry # but we might still find a better match...
|
194 |
+
if coverage_data is None:
|
195 |
+
return None
|
196 |
+
return dict(
|
197 |
+
(int(line.get('number')), int(line.get('hits')))
|
198 |
+
for line in coverage_data.iterfind('lines/line')
|
199 |
+
)
|
200 |
+
|
201 |
+
def _htmlify_code(self, code):
|
202 |
+
try:
|
203 |
+
from pygments import highlight
|
204 |
+
from pygments.lexers import CythonLexer
|
205 |
+
from pygments.formatters import HtmlFormatter
|
206 |
+
except ImportError:
|
207 |
+
# no Pygments, just escape the code
|
208 |
+
return html_escape(code)
|
209 |
+
|
210 |
+
html_code = highlight(
|
211 |
+
code, CythonLexer(stripnl=False, stripall=False),
|
212 |
+
HtmlFormatter(nowrap=True))
|
213 |
+
return html_code
|
214 |
+
|
215 |
+
def _save_annotation_body(self, cython_code, generated_code, annotation_items, scopes, covered_lines=None):
|
216 |
+
outlist = [u'<div class="cython">']
|
217 |
+
pos_comment_marker = u'/* \N{HORIZONTAL ELLIPSIS} */\n'
|
218 |
+
new_calls_map = dict(
|
219 |
+
(name, 0) for name in
|
220 |
+
'refnanny trace py_macro_api py_c_api pyx_macro_api pyx_c_api error_goto'.split()
|
221 |
+
).copy
|
222 |
+
|
223 |
+
self.mark_pos(None)
|
224 |
+
|
225 |
+
def annotate(match):
|
226 |
+
group_name = match.lastgroup
|
227 |
+
calls[group_name] += 1
|
228 |
+
return u"<span class='%s'>%s</span>" % (
|
229 |
+
group_name, match.group(group_name))
|
230 |
+
|
231 |
+
lines = self._htmlify_code(cython_code).splitlines()
|
232 |
+
lineno_width = len(str(len(lines)))
|
233 |
+
if not covered_lines:
|
234 |
+
covered_lines = None
|
235 |
+
|
236 |
+
for k, line in enumerate(lines, 1):
|
237 |
+
try:
|
238 |
+
c_code = generated_code[k]
|
239 |
+
except KeyError:
|
240 |
+
c_code = ''
|
241 |
+
else:
|
242 |
+
c_code = _replace_pos_comment(pos_comment_marker, c_code)
|
243 |
+
if c_code.startswith(pos_comment_marker):
|
244 |
+
c_code = c_code[len(pos_comment_marker):]
|
245 |
+
c_code = html_escape(c_code)
|
246 |
+
|
247 |
+
calls = new_calls_map()
|
248 |
+
c_code = _parse_code(annotate, c_code)
|
249 |
+
score = (5 * calls['py_c_api'] + 2 * calls['pyx_c_api'] +
|
250 |
+
calls['py_macro_api'] + calls['pyx_macro_api'])
|
251 |
+
|
252 |
+
if c_code:
|
253 |
+
onclick = self._onclick_attr
|
254 |
+
expandsymbol = '+'
|
255 |
+
else:
|
256 |
+
onclick = ''
|
257 |
+
expandsymbol = ' '
|
258 |
+
|
259 |
+
covered = ''
|
260 |
+
if covered_lines is not None and k in covered_lines:
|
261 |
+
hits = covered_lines[k]
|
262 |
+
if hits is not None:
|
263 |
+
covered = 'run' if hits else 'mis'
|
264 |
+
|
265 |
+
outlist.append(
|
266 |
+
u'<pre class="cython line score-{score}"{onclick}>'
|
267 |
+
# generate line number with expand symbol in front,
|
268 |
+
# and the right number of digit
|
269 |
+
u'{expandsymbol}<span class="{covered}">{line:0{lineno_width}d}</span>: {code}</pre>\n'.format(
|
270 |
+
score=score,
|
271 |
+
expandsymbol=expandsymbol,
|
272 |
+
covered=covered,
|
273 |
+
lineno_width=lineno_width,
|
274 |
+
line=k,
|
275 |
+
code=line.rstrip(),
|
276 |
+
onclick=onclick,
|
277 |
+
))
|
278 |
+
if c_code:
|
279 |
+
outlist.append(u"<pre class='cython code score-{score} {covered}'>{code}</pre>".format(
|
280 |
+
score=score, covered=covered, code=c_code))
|
281 |
+
outlist.append(u"</div>")
|
282 |
+
return outlist
|
283 |
+
|
284 |
+
|
285 |
+
_parse_code = re.compile((
|
286 |
+
br'(?P<refnanny>__Pyx_X?(?:GOT|GIVE)REF|__Pyx_RefNanny[A-Za-z]+)|'
|
287 |
+
br'(?P<trace>__Pyx_Trace[A-Za-z]+)|'
|
288 |
+
br'(?:'
|
289 |
+
br'(?P<pyx_macro_api>__Pyx_[A-Z][A-Z_]+)|'
|
290 |
+
br'(?P<pyx_c_api>(?:__Pyx_[A-Z][a-z_][A-Za-z_]*)|__pyx_convert_[A-Za-z_]*)|'
|
291 |
+
br'(?P<py_macro_api>Py[A-Z][a-z]+_[A-Z][A-Z_]+)|'
|
292 |
+
br'(?P<py_c_api>Py[A-Z][a-z]+_[A-Z][a-z][A-Za-z_]*)'
|
293 |
+
br')(?=\()|' # look-ahead to exclude subsequent '(' from replacement
|
294 |
+
br'(?P<error_goto>(?:(?<=;) *if [^;]* +)?__PYX_ERR\([^)]+\))'
|
295 |
+
).decode('ascii')).sub
|
296 |
+
|
297 |
+
|
298 |
+
_replace_pos_comment = re.compile(
|
299 |
+
# this matches what Cython generates as code line marker comment
|
300 |
+
br'^\s*/\*(?:(?:[^*]|\*[^/])*\n)+\s*\*/\s*\n'.decode('ascii'),
|
301 |
+
re.M
|
302 |
+
).sub
|
303 |
+
|
304 |
+
|
305 |
+
class AnnotationItem(object):
|
306 |
+
|
307 |
+
def __init__(self, style, text, tag="", size=0):
|
308 |
+
self.style = style
|
309 |
+
self.text = text
|
310 |
+
self.tag = tag
|
311 |
+
self.size = size
|
312 |
+
|
313 |
+
def start(self):
|
314 |
+
return u"<span class='cython tag %s' title='%s'>%s" % (self.style, self.text, self.tag)
|
315 |
+
|
316 |
+
def end(self):
|
317 |
+
return self.size, u"</span>"
|
venv/Lib/site-packages/Cython/Compiler/AutoDocTransforms.py
ADDED
@@ -0,0 +1,214 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from __future__ import absolute_import, print_function
|
2 |
+
|
3 |
+
from .Visitor import CythonTransform
|
4 |
+
from .StringEncoding import EncodedString
|
5 |
+
from . import Options
|
6 |
+
from . import PyrexTypes, ExprNodes
|
7 |
+
from ..CodeWriter import ExpressionWriter
|
8 |
+
|
9 |
+
|
10 |
+
class AnnotationWriter(ExpressionWriter):
|
11 |
+
|
12 |
+
def visit_Node(self, node):
|
13 |
+
self.put(u"<???>")
|
14 |
+
|
15 |
+
def visit_LambdaNode(self, node):
|
16 |
+
# XXX Should we do better?
|
17 |
+
self.put("<lambda>")
|
18 |
+
|
19 |
+
|
20 |
+
class EmbedSignature(CythonTransform):
|
21 |
+
|
22 |
+
def __init__(self, context):
|
23 |
+
super(EmbedSignature, self).__init__(context)
|
24 |
+
self.class_name = None
|
25 |
+
self.class_node = None
|
26 |
+
|
27 |
+
def _fmt_expr(self, node):
|
28 |
+
writer = AnnotationWriter()
|
29 |
+
result = writer.write(node)
|
30 |
+
# print(type(node).__name__, '-->', result)
|
31 |
+
return result
|
32 |
+
|
33 |
+
def _fmt_arg(self, arg):
|
34 |
+
if arg.type is PyrexTypes.py_object_type or arg.is_self_arg:
|
35 |
+
doc = arg.name
|
36 |
+
else:
|
37 |
+
doc = arg.type.declaration_code(arg.name, for_display=1)
|
38 |
+
|
39 |
+
if arg.annotation:
|
40 |
+
annotation = self._fmt_expr(arg.annotation)
|
41 |
+
doc = doc + (': %s' % annotation)
|
42 |
+
if arg.default:
|
43 |
+
default = self._fmt_expr(arg.default)
|
44 |
+
doc = doc + (' = %s' % default)
|
45 |
+
elif arg.default:
|
46 |
+
default = self._fmt_expr(arg.default)
|
47 |
+
doc = doc + ('=%s' % default)
|
48 |
+
return doc
|
49 |
+
|
50 |
+
def _fmt_star_arg(self, arg):
|
51 |
+
arg_doc = arg.name
|
52 |
+
if arg.annotation:
|
53 |
+
annotation = self._fmt_expr(arg.annotation)
|
54 |
+
arg_doc = arg_doc + (': %s' % annotation)
|
55 |
+
return arg_doc
|
56 |
+
|
57 |
+
def _fmt_arglist(self, args,
|
58 |
+
npargs=0, pargs=None,
|
59 |
+
nkargs=0, kargs=None,
|
60 |
+
hide_self=False):
|
61 |
+
arglist = []
|
62 |
+
for arg in args:
|
63 |
+
if not hide_self or not arg.entry.is_self_arg:
|
64 |
+
arg_doc = self._fmt_arg(arg)
|
65 |
+
arglist.append(arg_doc)
|
66 |
+
if pargs:
|
67 |
+
arg_doc = self._fmt_star_arg(pargs)
|
68 |
+
arglist.insert(npargs, '*%s' % arg_doc)
|
69 |
+
elif nkargs:
|
70 |
+
arglist.insert(npargs, '*')
|
71 |
+
if kargs:
|
72 |
+
arg_doc = self._fmt_star_arg(kargs)
|
73 |
+
arglist.append('**%s' % arg_doc)
|
74 |
+
return arglist
|
75 |
+
|
76 |
+
def _fmt_ret_type(self, ret):
|
77 |
+
if ret is PyrexTypes.py_object_type:
|
78 |
+
return None
|
79 |
+
else:
|
80 |
+
return ret.declaration_code("", for_display=1)
|
81 |
+
|
82 |
+
def _fmt_signature(self, cls_name, func_name, args,
|
83 |
+
npargs=0, pargs=None,
|
84 |
+
nkargs=0, kargs=None,
|
85 |
+
return_expr=None,
|
86 |
+
return_type=None, hide_self=False):
|
87 |
+
arglist = self._fmt_arglist(args,
|
88 |
+
npargs, pargs,
|
89 |
+
nkargs, kargs,
|
90 |
+
hide_self=hide_self)
|
91 |
+
arglist_doc = ', '.join(arglist)
|
92 |
+
func_doc = '%s(%s)' % (func_name, arglist_doc)
|
93 |
+
if cls_name:
|
94 |
+
func_doc = '%s.%s' % (cls_name, func_doc)
|
95 |
+
ret_doc = None
|
96 |
+
if return_expr:
|
97 |
+
ret_doc = self._fmt_expr(return_expr)
|
98 |
+
elif return_type:
|
99 |
+
ret_doc = self._fmt_ret_type(return_type)
|
100 |
+
if ret_doc:
|
101 |
+
func_doc = '%s -> %s' % (func_doc, ret_doc)
|
102 |
+
return func_doc
|
103 |
+
|
104 |
+
def _embed_signature(self, signature, node_doc):
|
105 |
+
if node_doc:
|
106 |
+
return "%s\n%s" % (signature, node_doc)
|
107 |
+
else:
|
108 |
+
return signature
|
109 |
+
|
110 |
+
def __call__(self, node):
|
111 |
+
if not Options.docstrings:
|
112 |
+
return node
|
113 |
+
else:
|
114 |
+
return super(EmbedSignature, self).__call__(node)
|
115 |
+
|
116 |
+
def visit_ClassDefNode(self, node):
|
117 |
+
oldname = self.class_name
|
118 |
+
oldclass = self.class_node
|
119 |
+
self.class_node = node
|
120 |
+
try:
|
121 |
+
# PyClassDefNode
|
122 |
+
self.class_name = node.name
|
123 |
+
except AttributeError:
|
124 |
+
# CClassDefNode
|
125 |
+
self.class_name = node.class_name
|
126 |
+
self.visitchildren(node)
|
127 |
+
self.class_name = oldname
|
128 |
+
self.class_node = oldclass
|
129 |
+
return node
|
130 |
+
|
131 |
+
def visit_LambdaNode(self, node):
|
132 |
+
# lambda expressions so not have signature or inner functions
|
133 |
+
return node
|
134 |
+
|
135 |
+
def visit_DefNode(self, node):
|
136 |
+
if not self.current_directives['embedsignature']:
|
137 |
+
return node
|
138 |
+
|
139 |
+
is_constructor = False
|
140 |
+
hide_self = False
|
141 |
+
if node.entry.is_special:
|
142 |
+
is_constructor = self.class_node and node.name == '__init__'
|
143 |
+
if not is_constructor:
|
144 |
+
return node
|
145 |
+
class_name, func_name = None, self.class_name
|
146 |
+
hide_self = True
|
147 |
+
else:
|
148 |
+
class_name, func_name = self.class_name, node.name
|
149 |
+
|
150 |
+
nkargs = getattr(node, 'num_kwonly_args', 0)
|
151 |
+
npargs = len(node.args) - nkargs
|
152 |
+
signature = self._fmt_signature(
|
153 |
+
class_name, func_name, node.args,
|
154 |
+
npargs, node.star_arg,
|
155 |
+
nkargs, node.starstar_arg,
|
156 |
+
return_expr=node.return_type_annotation,
|
157 |
+
return_type=None, hide_self=hide_self)
|
158 |
+
if signature:
|
159 |
+
if is_constructor:
|
160 |
+
doc_holder = self.class_node.entry.type.scope
|
161 |
+
else:
|
162 |
+
doc_holder = node.entry
|
163 |
+
|
164 |
+
if doc_holder.doc is not None:
|
165 |
+
old_doc = doc_holder.doc
|
166 |
+
elif not is_constructor and getattr(node, 'py_func', None) is not None:
|
167 |
+
old_doc = node.py_func.entry.doc
|
168 |
+
else:
|
169 |
+
old_doc = None
|
170 |
+
new_doc = self._embed_signature(signature, old_doc)
|
171 |
+
doc_holder.doc = EncodedString(new_doc)
|
172 |
+
if not is_constructor and getattr(node, 'py_func', None) is not None:
|
173 |
+
node.py_func.entry.doc = EncodedString(new_doc)
|
174 |
+
return node
|
175 |
+
|
176 |
+
def visit_CFuncDefNode(self, node):
|
177 |
+
if not self.current_directives['embedsignature']:
|
178 |
+
return node
|
179 |
+
if not node.overridable: # not cpdef FOO(...):
|
180 |
+
return node
|
181 |
+
|
182 |
+
signature = self._fmt_signature(
|
183 |
+
self.class_name, node.declarator.base.name,
|
184 |
+
node.declarator.args,
|
185 |
+
return_type=node.return_type)
|
186 |
+
if signature:
|
187 |
+
if node.entry.doc is not None:
|
188 |
+
old_doc = node.entry.doc
|
189 |
+
elif getattr(node, 'py_func', None) is not None:
|
190 |
+
old_doc = node.py_func.entry.doc
|
191 |
+
else:
|
192 |
+
old_doc = None
|
193 |
+
new_doc = self._embed_signature(signature, old_doc)
|
194 |
+
node.entry.doc = EncodedString(new_doc)
|
195 |
+
if hasattr(node, 'py_func') and node.py_func is not None:
|
196 |
+
node.py_func.entry.doc = EncodedString(new_doc)
|
197 |
+
return node
|
198 |
+
|
199 |
+
def visit_PropertyNode(self, node):
|
200 |
+
if not self.current_directives['embedsignature']:
|
201 |
+
return node
|
202 |
+
|
203 |
+
entry = node.entry
|
204 |
+
if entry.visibility == 'public':
|
205 |
+
# property synthesised from a cdef public attribute
|
206 |
+
type_name = entry.type.declaration_code("", for_display=1)
|
207 |
+
if not entry.type.is_pyobject:
|
208 |
+
type_name = "'%s'" % type_name
|
209 |
+
elif entry.type.is_extension_type:
|
210 |
+
type_name = entry.type.module_name + '.' + type_name
|
211 |
+
signature = '%s: %s' % (entry.name, type_name)
|
212 |
+
new_doc = self._embed_signature(signature, entry.doc)
|
213 |
+
entry.doc = EncodedString(new_doc)
|
214 |
+
return node
|
venv/Lib/site-packages/Cython/Compiler/Buffer.py
ADDED
@@ -0,0 +1,740 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from __future__ import absolute_import
|
2 |
+
|
3 |
+
from .Visitor import CythonTransform
|
4 |
+
from .ModuleNode import ModuleNode
|
5 |
+
from .Errors import CompileError
|
6 |
+
from .UtilityCode import CythonUtilityCode
|
7 |
+
from .Code import UtilityCode, TempitaUtilityCode
|
8 |
+
|
9 |
+
from . import Options
|
10 |
+
from . import Interpreter
|
11 |
+
from . import PyrexTypes
|
12 |
+
from . import Naming
|
13 |
+
from . import Symtab
|
14 |
+
|
15 |
+
def dedent(text, reindent=0):
|
16 |
+
from textwrap import dedent
|
17 |
+
text = dedent(text)
|
18 |
+
if reindent > 0:
|
19 |
+
indent = " " * reindent
|
20 |
+
text = '\n'.join([indent + x for x in text.split('\n')])
|
21 |
+
return text
|
22 |
+
|
23 |
+
class IntroduceBufferAuxiliaryVars(CythonTransform):
|
24 |
+
|
25 |
+
#
|
26 |
+
# Entry point
|
27 |
+
#
|
28 |
+
|
29 |
+
buffers_exists = False
|
30 |
+
using_memoryview = False
|
31 |
+
|
32 |
+
def __call__(self, node):
|
33 |
+
assert isinstance(node, ModuleNode)
|
34 |
+
self.max_ndim = 0
|
35 |
+
result = super(IntroduceBufferAuxiliaryVars, self).__call__(node)
|
36 |
+
if self.buffers_exists:
|
37 |
+
use_bufstruct_declare_code(node.scope)
|
38 |
+
use_py2_buffer_functions(node.scope)
|
39 |
+
|
40 |
+
return result
|
41 |
+
|
42 |
+
|
43 |
+
#
|
44 |
+
# Basic operations for transforms
|
45 |
+
#
|
46 |
+
def handle_scope(self, node, scope):
|
47 |
+
# For all buffers, insert extra variables in the scope.
|
48 |
+
# The variables are also accessible from the buffer_info
|
49 |
+
# on the buffer entry
|
50 |
+
scope_items = scope.entries.items()
|
51 |
+
bufvars = [entry for name, entry in scope_items if entry.type.is_buffer]
|
52 |
+
if len(bufvars) > 0:
|
53 |
+
bufvars.sort(key=lambda entry: entry.name)
|
54 |
+
self.buffers_exists = True
|
55 |
+
|
56 |
+
memviewslicevars = [entry for name, entry in scope_items if entry.type.is_memoryviewslice]
|
57 |
+
if len(memviewslicevars) > 0:
|
58 |
+
self.buffers_exists = True
|
59 |
+
|
60 |
+
|
61 |
+
for (name, entry) in scope_items:
|
62 |
+
if name == 'memoryview' and isinstance(entry.utility_code_definition, CythonUtilityCode):
|
63 |
+
self.using_memoryview = True
|
64 |
+
break
|
65 |
+
del scope_items
|
66 |
+
|
67 |
+
if isinstance(node, ModuleNode) and len(bufvars) > 0:
|
68 |
+
# for now...note that pos is wrong
|
69 |
+
raise CompileError(node.pos, "Buffer vars not allowed in module scope")
|
70 |
+
for entry in bufvars:
|
71 |
+
if entry.type.dtype.is_ptr:
|
72 |
+
raise CompileError(node.pos, "Buffers with pointer types not yet supported.")
|
73 |
+
|
74 |
+
name = entry.name
|
75 |
+
buftype = entry.type
|
76 |
+
if buftype.ndim > Options.buffer_max_dims:
|
77 |
+
raise CompileError(node.pos,
|
78 |
+
"Buffer ndims exceeds Options.buffer_max_dims = %d" % Options.buffer_max_dims)
|
79 |
+
if buftype.ndim > self.max_ndim:
|
80 |
+
self.max_ndim = buftype.ndim
|
81 |
+
|
82 |
+
# Declare auxiliary vars
|
83 |
+
def decvar(type, prefix):
|
84 |
+
cname = scope.mangle(prefix, name)
|
85 |
+
aux_var = scope.declare_var(name=None, cname=cname,
|
86 |
+
type=type, pos=node.pos)
|
87 |
+
if entry.is_arg:
|
88 |
+
aux_var.used = True # otherwise, NameNode will mark whether it is used
|
89 |
+
|
90 |
+
return aux_var
|
91 |
+
|
92 |
+
auxvars = ((PyrexTypes.c_pyx_buffer_nd_type, Naming.pybuffernd_prefix),
|
93 |
+
(PyrexTypes.c_pyx_buffer_type, Naming.pybufferstruct_prefix))
|
94 |
+
pybuffernd, rcbuffer = [decvar(type, prefix) for (type, prefix) in auxvars]
|
95 |
+
|
96 |
+
entry.buffer_aux = Symtab.BufferAux(pybuffernd, rcbuffer)
|
97 |
+
|
98 |
+
scope.buffer_entries = bufvars
|
99 |
+
self.scope = scope
|
100 |
+
|
101 |
+
def visit_ModuleNode(self, node):
|
102 |
+
self.handle_scope(node, node.scope)
|
103 |
+
self.visitchildren(node)
|
104 |
+
return node
|
105 |
+
|
106 |
+
def visit_FuncDefNode(self, node):
|
107 |
+
self.handle_scope(node, node.local_scope)
|
108 |
+
self.visitchildren(node)
|
109 |
+
return node
|
110 |
+
|
111 |
+
#
|
112 |
+
# Analysis
|
113 |
+
#
|
114 |
+
buffer_options = ("dtype", "ndim", "mode", "negative_indices", "cast") # ordered!
|
115 |
+
buffer_defaults = {"ndim": 1, "mode": "full", "negative_indices": True, "cast": False}
|
116 |
+
buffer_positional_options_count = 1 # anything beyond this needs keyword argument
|
117 |
+
|
118 |
+
ERR_BUF_OPTION_UNKNOWN = '"%s" is not a buffer option'
|
119 |
+
ERR_BUF_TOO_MANY = 'Too many buffer options'
|
120 |
+
ERR_BUF_DUP = '"%s" buffer option already supplied'
|
121 |
+
ERR_BUF_MISSING = '"%s" missing'
|
122 |
+
ERR_BUF_MODE = 'Only allowed buffer modes are: "c", "fortran", "full", "strided" (as a compile-time string)'
|
123 |
+
ERR_BUF_NDIM = 'ndim must be a non-negative integer'
|
124 |
+
ERR_BUF_DTYPE = 'dtype must be "object", numeric type or a struct'
|
125 |
+
ERR_BUF_BOOL = '"%s" must be a boolean'
|
126 |
+
|
127 |
+
def analyse_buffer_options(globalpos, env, posargs, dictargs, defaults=None, need_complete=True):
|
128 |
+
"""
|
129 |
+
Must be called during type analysis, as analyse is called
|
130 |
+
on the dtype argument.
|
131 |
+
|
132 |
+
posargs and dictargs should consist of a list and a dict
|
133 |
+
of tuples (value, pos). Defaults should be a dict of values.
|
134 |
+
|
135 |
+
Returns a dict containing all the options a buffer can have and
|
136 |
+
its value (with the positions stripped).
|
137 |
+
"""
|
138 |
+
if defaults is None:
|
139 |
+
defaults = buffer_defaults
|
140 |
+
|
141 |
+
posargs, dictargs = Interpreter.interpret_compiletime_options(
|
142 |
+
posargs, dictargs, type_env=env, type_args=(0, 'dtype'))
|
143 |
+
|
144 |
+
if len(posargs) > buffer_positional_options_count:
|
145 |
+
raise CompileError(posargs[-1][1], ERR_BUF_TOO_MANY)
|
146 |
+
|
147 |
+
options = {}
|
148 |
+
for name, (value, pos) in dictargs.items():
|
149 |
+
if not name in buffer_options:
|
150 |
+
raise CompileError(pos, ERR_BUF_OPTION_UNKNOWN % name)
|
151 |
+
options[name] = value
|
152 |
+
|
153 |
+
for name, (value, pos) in zip(buffer_options, posargs):
|
154 |
+
if not name in buffer_options:
|
155 |
+
raise CompileError(pos, ERR_BUF_OPTION_UNKNOWN % name)
|
156 |
+
if name in options:
|
157 |
+
raise CompileError(pos, ERR_BUF_DUP % name)
|
158 |
+
options[name] = value
|
159 |
+
|
160 |
+
# Check that they are all there and copy defaults
|
161 |
+
for name in buffer_options:
|
162 |
+
if not name in options:
|
163 |
+
try:
|
164 |
+
options[name] = defaults[name]
|
165 |
+
except KeyError:
|
166 |
+
if need_complete:
|
167 |
+
raise CompileError(globalpos, ERR_BUF_MISSING % name)
|
168 |
+
|
169 |
+
dtype = options.get("dtype")
|
170 |
+
if dtype and dtype.is_extension_type:
|
171 |
+
raise CompileError(globalpos, ERR_BUF_DTYPE)
|
172 |
+
|
173 |
+
ndim = options.get("ndim")
|
174 |
+
if ndim and (not isinstance(ndim, int) or ndim < 0):
|
175 |
+
raise CompileError(globalpos, ERR_BUF_NDIM)
|
176 |
+
|
177 |
+
mode = options.get("mode")
|
178 |
+
if mode and not (mode in ('full', 'strided', 'c', 'fortran')):
|
179 |
+
raise CompileError(globalpos, ERR_BUF_MODE)
|
180 |
+
|
181 |
+
def assert_bool(name):
|
182 |
+
x = options.get(name)
|
183 |
+
if not isinstance(x, bool):
|
184 |
+
raise CompileError(globalpos, ERR_BUF_BOOL % name)
|
185 |
+
|
186 |
+
assert_bool('negative_indices')
|
187 |
+
assert_bool('cast')
|
188 |
+
|
189 |
+
return options
|
190 |
+
|
191 |
+
|
192 |
+
#
|
193 |
+
# Code generation
|
194 |
+
#
|
195 |
+
|
196 |
+
class BufferEntry(object):
|
197 |
+
def __init__(self, entry):
|
198 |
+
self.entry = entry
|
199 |
+
self.type = entry.type
|
200 |
+
self.cname = entry.buffer_aux.buflocal_nd_var.cname
|
201 |
+
self.buf_ptr = "%s.rcbuffer->pybuffer.buf" % self.cname
|
202 |
+
self.buf_ptr_type = entry.type.buffer_ptr_type
|
203 |
+
self.init_attributes()
|
204 |
+
|
205 |
+
def init_attributes(self):
|
206 |
+
self.shape = self.get_buf_shapevars()
|
207 |
+
self.strides = self.get_buf_stridevars()
|
208 |
+
self.suboffsets = self.get_buf_suboffsetvars()
|
209 |
+
|
210 |
+
def get_buf_suboffsetvars(self):
|
211 |
+
return self._for_all_ndim("%s.diminfo[%d].suboffsets")
|
212 |
+
|
213 |
+
def get_buf_stridevars(self):
|
214 |
+
return self._for_all_ndim("%s.diminfo[%d].strides")
|
215 |
+
|
216 |
+
def get_buf_shapevars(self):
|
217 |
+
return self._for_all_ndim("%s.diminfo[%d].shape")
|
218 |
+
|
219 |
+
def _for_all_ndim(self, s):
|
220 |
+
return [s % (self.cname, i) for i in range(self.type.ndim)]
|
221 |
+
|
222 |
+
def generate_buffer_lookup_code(self, code, index_cnames):
|
223 |
+
# Create buffer lookup and return it
|
224 |
+
# This is done via utility macros/inline functions, which vary
|
225 |
+
# according to the access mode used.
|
226 |
+
params = []
|
227 |
+
nd = self.type.ndim
|
228 |
+
mode = self.type.mode
|
229 |
+
if mode == 'full':
|
230 |
+
for i, s, o in zip(index_cnames,
|
231 |
+
self.get_buf_stridevars(),
|
232 |
+
self.get_buf_suboffsetvars()):
|
233 |
+
params.append(i)
|
234 |
+
params.append(s)
|
235 |
+
params.append(o)
|
236 |
+
funcname = "__Pyx_BufPtrFull%dd" % nd
|
237 |
+
funcgen = buf_lookup_full_code
|
238 |
+
else:
|
239 |
+
if mode == 'strided':
|
240 |
+
funcname = "__Pyx_BufPtrStrided%dd" % nd
|
241 |
+
funcgen = buf_lookup_strided_code
|
242 |
+
elif mode == 'c':
|
243 |
+
funcname = "__Pyx_BufPtrCContig%dd" % nd
|
244 |
+
funcgen = buf_lookup_c_code
|
245 |
+
elif mode == 'fortran':
|
246 |
+
funcname = "__Pyx_BufPtrFortranContig%dd" % nd
|
247 |
+
funcgen = buf_lookup_fortran_code
|
248 |
+
else:
|
249 |
+
assert False
|
250 |
+
for i, s in zip(index_cnames, self.get_buf_stridevars()):
|
251 |
+
params.append(i)
|
252 |
+
params.append(s)
|
253 |
+
|
254 |
+
# Make sure the utility code is available
|
255 |
+
if funcname not in code.globalstate.utility_codes:
|
256 |
+
code.globalstate.utility_codes.add(funcname)
|
257 |
+
protocode = code.globalstate['utility_code_proto']
|
258 |
+
defcode = code.globalstate['utility_code_def']
|
259 |
+
funcgen(protocode, defcode, name=funcname, nd=nd)
|
260 |
+
|
261 |
+
buf_ptr_type_code = self.buf_ptr_type.empty_declaration_code()
|
262 |
+
ptrcode = "%s(%s, %s, %s)" % (funcname, buf_ptr_type_code, self.buf_ptr,
|
263 |
+
", ".join(params))
|
264 |
+
return ptrcode
|
265 |
+
|
266 |
+
|
267 |
+
def get_flags(buffer_aux, buffer_type):
|
268 |
+
flags = 'PyBUF_FORMAT'
|
269 |
+
mode = buffer_type.mode
|
270 |
+
if mode == 'full':
|
271 |
+
flags += '| PyBUF_INDIRECT'
|
272 |
+
elif mode == 'strided':
|
273 |
+
flags += '| PyBUF_STRIDES'
|
274 |
+
elif mode == 'c':
|
275 |
+
flags += '| PyBUF_C_CONTIGUOUS'
|
276 |
+
elif mode == 'fortran':
|
277 |
+
flags += '| PyBUF_F_CONTIGUOUS'
|
278 |
+
else:
|
279 |
+
assert False
|
280 |
+
if buffer_aux.writable_needed: flags += "| PyBUF_WRITABLE"
|
281 |
+
return flags
|
282 |
+
|
283 |
+
def used_buffer_aux_vars(entry):
|
284 |
+
buffer_aux = entry.buffer_aux
|
285 |
+
buffer_aux.buflocal_nd_var.used = True
|
286 |
+
buffer_aux.rcbuf_var.used = True
|
287 |
+
|
288 |
+
def put_unpack_buffer_aux_into_scope(buf_entry, code):
|
289 |
+
# Generate code to copy the needed struct info into local
|
290 |
+
# variables.
|
291 |
+
buffer_aux, mode = buf_entry.buffer_aux, buf_entry.type.mode
|
292 |
+
pybuffernd_struct = buffer_aux.buflocal_nd_var.cname
|
293 |
+
|
294 |
+
fldnames = ['strides', 'shape']
|
295 |
+
if mode == 'full':
|
296 |
+
fldnames.append('suboffsets')
|
297 |
+
|
298 |
+
ln = []
|
299 |
+
for i in range(buf_entry.type.ndim):
|
300 |
+
for fldname in fldnames:
|
301 |
+
ln.append("%s.diminfo[%d].%s = %s.rcbuffer->pybuffer.%s[%d];" % \
|
302 |
+
(pybuffernd_struct, i, fldname,
|
303 |
+
pybuffernd_struct, fldname, i))
|
304 |
+
code.putln(' '.join(ln))
|
305 |
+
|
306 |
+
def put_init_vars(entry, code):
|
307 |
+
bufaux = entry.buffer_aux
|
308 |
+
pybuffernd_struct = bufaux.buflocal_nd_var.cname
|
309 |
+
pybuffer_struct = bufaux.rcbuf_var.cname
|
310 |
+
# init pybuffer_struct
|
311 |
+
code.putln("%s.pybuffer.buf = NULL;" % pybuffer_struct)
|
312 |
+
code.putln("%s.refcount = 0;" % pybuffer_struct)
|
313 |
+
# init the buffer object
|
314 |
+
# code.put_init_var_to_py_none(entry)
|
315 |
+
# init the pybuffernd_struct
|
316 |
+
code.putln("%s.data = NULL;" % pybuffernd_struct)
|
317 |
+
code.putln("%s.rcbuffer = &%s;" % (pybuffernd_struct, pybuffer_struct))
|
318 |
+
|
319 |
+
|
320 |
+
def put_acquire_arg_buffer(entry, code, pos):
|
321 |
+
buffer_aux = entry.buffer_aux
|
322 |
+
getbuffer = get_getbuffer_call(code, entry.cname, buffer_aux, entry.type)
|
323 |
+
|
324 |
+
# Acquire any new buffer
|
325 |
+
code.putln("{")
|
326 |
+
code.putln("__Pyx_BufFmt_StackElem __pyx_stack[%d];" % entry.type.dtype.struct_nesting_depth())
|
327 |
+
code.putln(code.error_goto_if("%s == -1" % getbuffer, pos))
|
328 |
+
code.putln("}")
|
329 |
+
# An exception raised in arg parsing cannot be caught, so no
|
330 |
+
# need to care about the buffer then.
|
331 |
+
put_unpack_buffer_aux_into_scope(entry, code)
|
332 |
+
|
333 |
+
|
334 |
+
def put_release_buffer_code(code, entry):
|
335 |
+
code.globalstate.use_utility_code(acquire_utility_code)
|
336 |
+
code.putln("__Pyx_SafeReleaseBuffer(&%s.rcbuffer->pybuffer);" % entry.buffer_aux.buflocal_nd_var.cname)
|
337 |
+
|
338 |
+
|
339 |
+
def get_getbuffer_call(code, obj_cname, buffer_aux, buffer_type):
|
340 |
+
ndim = buffer_type.ndim
|
341 |
+
cast = int(buffer_type.cast)
|
342 |
+
flags = get_flags(buffer_aux, buffer_type)
|
343 |
+
pybuffernd_struct = buffer_aux.buflocal_nd_var.cname
|
344 |
+
|
345 |
+
dtype_typeinfo = get_type_information_cname(code, buffer_type.dtype)
|
346 |
+
|
347 |
+
code.globalstate.use_utility_code(acquire_utility_code)
|
348 |
+
return ("__Pyx_GetBufferAndValidate(&%(pybuffernd_struct)s.rcbuffer->pybuffer, "
|
349 |
+
"(PyObject*)%(obj_cname)s, &%(dtype_typeinfo)s, %(flags)s, %(ndim)d, "
|
350 |
+
"%(cast)d, __pyx_stack)" % locals())
|
351 |
+
|
352 |
+
|
353 |
+
def put_assign_to_buffer(lhs_cname, rhs_cname, buf_entry,
|
354 |
+
is_initialized, pos, code):
|
355 |
+
"""
|
356 |
+
Generate code for reassigning a buffer variables. This only deals with getting
|
357 |
+
the buffer auxiliary structure and variables set up correctly, the assignment
|
358 |
+
itself and refcounting is the responsibility of the caller.
|
359 |
+
|
360 |
+
However, the assignment operation may throw an exception so that the reassignment
|
361 |
+
never happens.
|
362 |
+
|
363 |
+
Depending on the circumstances there are two possible outcomes:
|
364 |
+
- Old buffer released, new acquired, rhs assigned to lhs
|
365 |
+
- Old buffer released, new acquired which fails, reaqcuire old lhs buffer
|
366 |
+
(which may or may not succeed).
|
367 |
+
"""
|
368 |
+
|
369 |
+
buffer_aux, buffer_type = buf_entry.buffer_aux, buf_entry.type
|
370 |
+
pybuffernd_struct = buffer_aux.buflocal_nd_var.cname
|
371 |
+
flags = get_flags(buffer_aux, buffer_type)
|
372 |
+
|
373 |
+
code.putln("{") # Set up necessary stack for getbuffer
|
374 |
+
code.putln("__Pyx_BufFmt_StackElem __pyx_stack[%d];" % buffer_type.dtype.struct_nesting_depth())
|
375 |
+
|
376 |
+
getbuffer = get_getbuffer_call(code, "%s", buffer_aux, buffer_type) # fill in object below
|
377 |
+
|
378 |
+
if is_initialized:
|
379 |
+
# Release any existing buffer
|
380 |
+
code.putln('__Pyx_SafeReleaseBuffer(&%s.rcbuffer->pybuffer);' % pybuffernd_struct)
|
381 |
+
# Acquire
|
382 |
+
retcode_cname = code.funcstate.allocate_temp(PyrexTypes.c_int_type, manage_ref=False)
|
383 |
+
code.putln("%s = %s;" % (retcode_cname, getbuffer % rhs_cname))
|
384 |
+
code.putln('if (%s) {' % (code.unlikely("%s < 0" % retcode_cname)))
|
385 |
+
# If acquisition failed, attempt to reacquire the old buffer
|
386 |
+
# before raising the exception. A failure of reacquisition
|
387 |
+
# will cause the reacquisition exception to be reported, one
|
388 |
+
# can consider working around this later.
|
389 |
+
exc_temps = tuple(code.funcstate.allocate_temp(PyrexTypes.py_object_type, manage_ref=False)
|
390 |
+
for _ in range(3))
|
391 |
+
code.putln('PyErr_Fetch(&%s, &%s, &%s);' % exc_temps)
|
392 |
+
code.putln('if (%s) {' % code.unlikely("%s == -1" % (getbuffer % lhs_cname)))
|
393 |
+
code.putln('Py_XDECREF(%s); Py_XDECREF(%s); Py_XDECREF(%s);' % exc_temps) # Do not refnanny these!
|
394 |
+
code.globalstate.use_utility_code(raise_buffer_fallback_code)
|
395 |
+
code.putln('__Pyx_RaiseBufferFallbackError();')
|
396 |
+
code.putln('} else {')
|
397 |
+
code.putln('PyErr_Restore(%s, %s, %s);' % exc_temps)
|
398 |
+
code.putln('}')
|
399 |
+
code.putln('%s = %s = %s = 0;' % exc_temps)
|
400 |
+
for t in exc_temps:
|
401 |
+
code.funcstate.release_temp(t)
|
402 |
+
code.putln('}')
|
403 |
+
# Unpack indices
|
404 |
+
put_unpack_buffer_aux_into_scope(buf_entry, code)
|
405 |
+
code.putln(code.error_goto_if_neg(retcode_cname, pos))
|
406 |
+
code.funcstate.release_temp(retcode_cname)
|
407 |
+
else:
|
408 |
+
# Our entry had no previous value, so set to None when acquisition fails.
|
409 |
+
# In this case, auxiliary vars should be set up right in initialization to a zero-buffer,
|
410 |
+
# so it suffices to set the buf field to NULL.
|
411 |
+
code.putln('if (%s) {' % code.unlikely("%s == -1" % (getbuffer % rhs_cname)))
|
412 |
+
code.putln('%s = %s; __Pyx_INCREF(Py_None); %s.rcbuffer->pybuffer.buf = NULL;' %
|
413 |
+
(lhs_cname,
|
414 |
+
PyrexTypes.typecast(buffer_type, PyrexTypes.py_object_type, "Py_None"),
|
415 |
+
pybuffernd_struct))
|
416 |
+
code.putln(code.error_goto(pos))
|
417 |
+
code.put('} else {')
|
418 |
+
# Unpack indices
|
419 |
+
put_unpack_buffer_aux_into_scope(buf_entry, code)
|
420 |
+
code.putln('}')
|
421 |
+
|
422 |
+
code.putln("}") # Release stack
|
423 |
+
|
424 |
+
|
425 |
+
def put_buffer_lookup_code(entry, index_signeds, index_cnames, directives,
|
426 |
+
pos, code, negative_indices, in_nogil_context):
|
427 |
+
"""
|
428 |
+
Generates code to process indices and calculate an offset into
|
429 |
+
a buffer. Returns a C string which gives a pointer which can be
|
430 |
+
read from or written to at will (it is an expression so caller should
|
431 |
+
store it in a temporary if it is used more than once).
|
432 |
+
|
433 |
+
As the bounds checking can have any number of combinations of unsigned
|
434 |
+
arguments, smart optimizations etc. we insert it directly in the function
|
435 |
+
body. The lookup however is delegated to a inline function that is instantiated
|
436 |
+
once per ndim (lookup with suboffsets tend to get quite complicated).
|
437 |
+
|
438 |
+
entry is a BufferEntry
|
439 |
+
"""
|
440 |
+
negative_indices = directives['wraparound'] and negative_indices
|
441 |
+
|
442 |
+
if directives['boundscheck']:
|
443 |
+
# Check bounds and fix negative indices.
|
444 |
+
# We allocate a temporary which is initialized to -1, meaning OK (!).
|
445 |
+
# If an error occurs, the temp is set to the index dimension the
|
446 |
+
# error is occurring at.
|
447 |
+
failed_dim_temp = code.funcstate.allocate_temp(PyrexTypes.c_int_type, manage_ref=False)
|
448 |
+
code.putln("%s = -1;" % failed_dim_temp)
|
449 |
+
for dim, (signed, cname, shape) in enumerate(zip(index_signeds, index_cnames, entry.get_buf_shapevars())):
|
450 |
+
if signed != 0:
|
451 |
+
# not unsigned, deal with negative index
|
452 |
+
code.putln("if (%s < 0) {" % cname)
|
453 |
+
if negative_indices:
|
454 |
+
code.putln("%s += %s;" % (cname, shape))
|
455 |
+
code.putln("if (%s) %s = %d;" % (
|
456 |
+
code.unlikely("%s < 0" % cname),
|
457 |
+
failed_dim_temp, dim))
|
458 |
+
else:
|
459 |
+
code.putln("%s = %d;" % (failed_dim_temp, dim))
|
460 |
+
code.put("} else ")
|
461 |
+
# check bounds in positive direction
|
462 |
+
if signed != 0:
|
463 |
+
cast = ""
|
464 |
+
else:
|
465 |
+
cast = "(size_t)"
|
466 |
+
code.putln("if (%s) %s = %d;" % (
|
467 |
+
code.unlikely("%s >= %s%s" % (cname, cast, shape)),
|
468 |
+
failed_dim_temp, dim))
|
469 |
+
|
470 |
+
if in_nogil_context:
|
471 |
+
code.globalstate.use_utility_code(raise_indexerror_nogil)
|
472 |
+
func = '__Pyx_RaiseBufferIndexErrorNogil'
|
473 |
+
else:
|
474 |
+
code.globalstate.use_utility_code(raise_indexerror_code)
|
475 |
+
func = '__Pyx_RaiseBufferIndexError'
|
476 |
+
|
477 |
+
code.putln("if (%s) {" % code.unlikely("%s != -1" % failed_dim_temp))
|
478 |
+
code.putln('%s(%s);' % (func, failed_dim_temp))
|
479 |
+
code.putln(code.error_goto(pos))
|
480 |
+
code.putln('}')
|
481 |
+
code.funcstate.release_temp(failed_dim_temp)
|
482 |
+
elif negative_indices:
|
483 |
+
# Only fix negative indices.
|
484 |
+
for signed, cname, shape in zip(index_signeds, index_cnames, entry.get_buf_shapevars()):
|
485 |
+
if signed != 0:
|
486 |
+
code.putln("if (%s < 0) %s += %s;" % (cname, cname, shape))
|
487 |
+
|
488 |
+
return entry.generate_buffer_lookup_code(code, index_cnames)
|
489 |
+
|
490 |
+
|
491 |
+
def use_bufstruct_declare_code(env):
|
492 |
+
env.use_utility_code(buffer_struct_declare_code)
|
493 |
+
|
494 |
+
|
495 |
+
def buf_lookup_full_code(proto, defin, name, nd):
|
496 |
+
"""
|
497 |
+
Generates a buffer lookup function for the right number
|
498 |
+
of dimensions. The function gives back a void* at the right location.
|
499 |
+
"""
|
500 |
+
# _i_ndex, _s_tride, sub_o_ffset
|
501 |
+
macroargs = ", ".join(["i%d, s%d, o%d" % (i, i, i) for i in range(nd)])
|
502 |
+
proto.putln("#define %s(type, buf, %s) (type)(%s_imp(buf, %s))" % (name, macroargs, name, macroargs))
|
503 |
+
|
504 |
+
funcargs = ", ".join(["Py_ssize_t i%d, Py_ssize_t s%d, Py_ssize_t o%d" % (i, i, i) for i in range(nd)])
|
505 |
+
proto.putln("static CYTHON_INLINE void* %s_imp(void* buf, %s);" % (name, funcargs))
|
506 |
+
defin.putln(dedent("""
|
507 |
+
static CYTHON_INLINE void* %s_imp(void* buf, %s) {
|
508 |
+
char* ptr = (char*)buf;
|
509 |
+
""") % (name, funcargs) + "".join([dedent("""\
|
510 |
+
ptr += s%d * i%d;
|
511 |
+
if (o%d >= 0) ptr = *((char**)ptr) + o%d;
|
512 |
+
""") % (i, i, i, i) for i in range(nd)]
|
513 |
+
) + "\nreturn ptr;\n}")
|
514 |
+
|
515 |
+
|
516 |
+
def buf_lookup_strided_code(proto, defin, name, nd):
|
517 |
+
"""
|
518 |
+
Generates a buffer lookup function for the right number
|
519 |
+
of dimensions. The function gives back a void* at the right location.
|
520 |
+
"""
|
521 |
+
# _i_ndex, _s_tride
|
522 |
+
args = ", ".join(["i%d, s%d" % (i, i) for i in range(nd)])
|
523 |
+
offset = " + ".join(["i%d * s%d" % (i, i) for i in range(nd)])
|
524 |
+
proto.putln("#define %s(type, buf, %s) (type)((char*)buf + %s)" % (name, args, offset))
|
525 |
+
|
526 |
+
|
527 |
+
def buf_lookup_c_code(proto, defin, name, nd):
|
528 |
+
"""
|
529 |
+
Similar to strided lookup, but can assume that the last dimension
|
530 |
+
doesn't need a multiplication as long as.
|
531 |
+
Still we keep the same signature for now.
|
532 |
+
"""
|
533 |
+
if nd == 1:
|
534 |
+
proto.putln("#define %s(type, buf, i0, s0) ((type)buf + i0)" % name)
|
535 |
+
else:
|
536 |
+
args = ", ".join(["i%d, s%d" % (i, i) for i in range(nd)])
|
537 |
+
offset = " + ".join(["i%d * s%d" % (i, i) for i in range(nd - 1)])
|
538 |
+
proto.putln("#define %s(type, buf, %s) ((type)((char*)buf + %s) + i%d)" % (name, args, offset, nd - 1))
|
539 |
+
|
540 |
+
|
541 |
+
def buf_lookup_fortran_code(proto, defin, name, nd):
|
542 |
+
"""
|
543 |
+
Like C lookup, but the first index is optimized instead.
|
544 |
+
"""
|
545 |
+
if nd == 1:
|
546 |
+
proto.putln("#define %s(type, buf, i0, s0) ((type)buf + i0)" % name)
|
547 |
+
else:
|
548 |
+
args = ", ".join(["i%d, s%d" % (i, i) for i in range(nd)])
|
549 |
+
offset = " + ".join(["i%d * s%d" % (i, i) for i in range(1, nd)])
|
550 |
+
proto.putln("#define %s(type, buf, %s) ((type)((char*)buf + %s) + i%d)" % (name, args, offset, 0))
|
551 |
+
|
552 |
+
|
553 |
+
def use_py2_buffer_functions(env):
|
554 |
+
env.use_utility_code(GetAndReleaseBufferUtilityCode())
|
555 |
+
|
556 |
+
|
557 |
+
class GetAndReleaseBufferUtilityCode(object):
|
558 |
+
# Emulation of PyObject_GetBuffer and PyBuffer_Release for Python 2.
|
559 |
+
# For >= 2.6 we do double mode -- use the new buffer interface on objects
|
560 |
+
# which has the right tp_flags set, but emulation otherwise.
|
561 |
+
|
562 |
+
requires = None
|
563 |
+
is_cython_utility = False
|
564 |
+
|
565 |
+
def __init__(self):
|
566 |
+
pass
|
567 |
+
|
568 |
+
def __eq__(self, other):
|
569 |
+
return isinstance(other, GetAndReleaseBufferUtilityCode)
|
570 |
+
|
571 |
+
def __hash__(self):
|
572 |
+
return 24342342
|
573 |
+
|
574 |
+
def get_tree(self, **kwargs): pass
|
575 |
+
|
576 |
+
def put_code(self, output):
|
577 |
+
code = output['utility_code_def']
|
578 |
+
proto_code = output['utility_code_proto']
|
579 |
+
env = output.module_node.scope
|
580 |
+
cython_scope = env.context.cython_scope
|
581 |
+
|
582 |
+
# Search all types for __getbuffer__ overloads
|
583 |
+
types = []
|
584 |
+
visited_scopes = set()
|
585 |
+
def find_buffer_types(scope):
|
586 |
+
if scope in visited_scopes:
|
587 |
+
return
|
588 |
+
visited_scopes.add(scope)
|
589 |
+
for m in scope.cimported_modules:
|
590 |
+
find_buffer_types(m)
|
591 |
+
for e in scope.type_entries:
|
592 |
+
if isinstance(e.utility_code_definition, CythonUtilityCode):
|
593 |
+
continue
|
594 |
+
t = e.type
|
595 |
+
if t.is_extension_type:
|
596 |
+
if scope is cython_scope and not e.used:
|
597 |
+
continue
|
598 |
+
release = get = None
|
599 |
+
for x in t.scope.pyfunc_entries:
|
600 |
+
if x.name == u"__getbuffer__": get = x.func_cname
|
601 |
+
elif x.name == u"__releasebuffer__": release = x.func_cname
|
602 |
+
if get:
|
603 |
+
types.append((t.typeptr_cname, get, release))
|
604 |
+
|
605 |
+
find_buffer_types(env)
|
606 |
+
|
607 |
+
util_code = TempitaUtilityCode.load(
|
608 |
+
"GetAndReleaseBuffer", from_file="Buffer.c",
|
609 |
+
context=dict(types=types))
|
610 |
+
|
611 |
+
proto = util_code.format_code(util_code.proto)
|
612 |
+
impl = util_code.format_code(
|
613 |
+
util_code.inject_string_constants(util_code.impl, output)[1])
|
614 |
+
|
615 |
+
proto_code.putln(proto)
|
616 |
+
code.putln(impl)
|
617 |
+
|
618 |
+
|
619 |
+
def mangle_dtype_name(dtype):
|
620 |
+
# Use prefixes to separate user defined types from builtins
|
621 |
+
# (consider "typedef float unsigned_int")
|
622 |
+
if dtype.is_pyobject:
|
623 |
+
return "object"
|
624 |
+
elif dtype.is_ptr:
|
625 |
+
return "ptr"
|
626 |
+
else:
|
627 |
+
if dtype.is_typedef or dtype.is_struct_or_union:
|
628 |
+
prefix = "nn_"
|
629 |
+
else:
|
630 |
+
prefix = ""
|
631 |
+
return prefix + dtype.specialization_name()
|
632 |
+
|
633 |
+
def get_type_information_cname(code, dtype, maxdepth=None):
|
634 |
+
"""
|
635 |
+
Output the run-time type information (__Pyx_TypeInfo) for given dtype,
|
636 |
+
and return the name of the type info struct.
|
637 |
+
|
638 |
+
Structs with two floats of the same size are encoded as complex numbers.
|
639 |
+
One can separate between complex numbers declared as struct or with native
|
640 |
+
encoding by inspecting to see if the fields field of the type is
|
641 |
+
filled in.
|
642 |
+
"""
|
643 |
+
namesuffix = mangle_dtype_name(dtype)
|
644 |
+
name = "__Pyx_TypeInfo_%s" % namesuffix
|
645 |
+
structinfo_name = "__Pyx_StructFields_%s" % namesuffix
|
646 |
+
|
647 |
+
if dtype.is_error: return "<error>"
|
648 |
+
|
649 |
+
# It's critical that walking the type info doesn't use more stack
|
650 |
+
# depth than dtype.struct_nesting_depth() returns, so use an assertion for this
|
651 |
+
if maxdepth is None: maxdepth = dtype.struct_nesting_depth()
|
652 |
+
if maxdepth <= 0:
|
653 |
+
assert False
|
654 |
+
|
655 |
+
if name not in code.globalstate.utility_codes:
|
656 |
+
code.globalstate.utility_codes.add(name)
|
657 |
+
typecode = code.globalstate['typeinfo']
|
658 |
+
|
659 |
+
arraysizes = []
|
660 |
+
if dtype.is_array:
|
661 |
+
while dtype.is_array:
|
662 |
+
arraysizes.append(dtype.size)
|
663 |
+
dtype = dtype.base_type
|
664 |
+
|
665 |
+
complex_possible = dtype.is_struct_or_union and dtype.can_be_complex()
|
666 |
+
|
667 |
+
declcode = dtype.empty_declaration_code()
|
668 |
+
if dtype.is_simple_buffer_dtype():
|
669 |
+
structinfo_name = "NULL"
|
670 |
+
elif dtype.is_struct:
|
671 |
+
struct_scope = dtype.scope
|
672 |
+
if dtype.is_const:
|
673 |
+
struct_scope = struct_scope.const_base_type_scope
|
674 |
+
# Must pre-call all used types in order not to recurse during utility code writing.
|
675 |
+
fields = struct_scope.var_entries
|
676 |
+
assert len(fields) > 0
|
677 |
+
types = [get_type_information_cname(code, f.type, maxdepth - 1)
|
678 |
+
for f in fields]
|
679 |
+
typecode.putln("static __Pyx_StructField %s[] = {" % structinfo_name, safe=True)
|
680 |
+
for f, typeinfo in zip(fields, types):
|
681 |
+
typecode.putln(' {&%s, "%s", offsetof(%s, %s)},' %
|
682 |
+
(typeinfo, f.name, dtype.empty_declaration_code(), f.cname), safe=True)
|
683 |
+
typecode.putln(' {NULL, NULL, 0}', safe=True)
|
684 |
+
typecode.putln("};", safe=True)
|
685 |
+
else:
|
686 |
+
assert False
|
687 |
+
|
688 |
+
rep = str(dtype)
|
689 |
+
|
690 |
+
flags = "0"
|
691 |
+
is_unsigned = "0"
|
692 |
+
if dtype is PyrexTypes.c_char_type:
|
693 |
+
is_unsigned = "IS_UNSIGNED(%s)" % declcode
|
694 |
+
typegroup = "'H'"
|
695 |
+
elif dtype.is_int:
|
696 |
+
is_unsigned = "IS_UNSIGNED(%s)" % declcode
|
697 |
+
typegroup = "%s ? 'U' : 'I'" % is_unsigned
|
698 |
+
elif complex_possible or dtype.is_complex:
|
699 |
+
typegroup = "'C'"
|
700 |
+
elif dtype.is_float:
|
701 |
+
typegroup = "'R'"
|
702 |
+
elif dtype.is_struct:
|
703 |
+
typegroup = "'S'"
|
704 |
+
if dtype.packed:
|
705 |
+
flags = "__PYX_BUF_FLAGS_PACKED_STRUCT"
|
706 |
+
elif dtype.is_pyobject:
|
707 |
+
typegroup = "'O'"
|
708 |
+
else:
|
709 |
+
assert False, dtype
|
710 |
+
|
711 |
+
typeinfo = ('static __Pyx_TypeInfo %s = '
|
712 |
+
'{ "%s", %s, sizeof(%s), { %s }, %s, %s, %s, %s };')
|
713 |
+
tup = (name, rep, structinfo_name, declcode,
|
714 |
+
', '.join([str(x) for x in arraysizes]) or '0', len(arraysizes),
|
715 |
+
typegroup, is_unsigned, flags)
|
716 |
+
typecode.putln(typeinfo % tup, safe=True)
|
717 |
+
|
718 |
+
return name
|
719 |
+
|
720 |
+
def load_buffer_utility(util_code_name, context=None, **kwargs):
|
721 |
+
if context is None:
|
722 |
+
return UtilityCode.load(util_code_name, "Buffer.c", **kwargs)
|
723 |
+
else:
|
724 |
+
return TempitaUtilityCode.load(util_code_name, "Buffer.c", context=context, **kwargs)
|
725 |
+
|
726 |
+
context = dict(max_dims=Options.buffer_max_dims)
|
727 |
+
buffer_struct_declare_code = load_buffer_utility("BufferStructDeclare", context=context)
|
728 |
+
buffer_formats_declare_code = load_buffer_utility("BufferFormatStructs")
|
729 |
+
|
730 |
+
# Utility function to set the right exception
|
731 |
+
# The caller should immediately goto_error
|
732 |
+
raise_indexerror_code = load_buffer_utility("BufferIndexError")
|
733 |
+
raise_indexerror_nogil = load_buffer_utility("BufferIndexErrorNogil")
|
734 |
+
raise_buffer_fallback_code = load_buffer_utility("BufferFallbackError")
|
735 |
+
|
736 |
+
acquire_utility_code = load_buffer_utility("BufferGetAndValidate", context=context)
|
737 |
+
buffer_format_check_code = load_buffer_utility("BufferFormatCheck", context=context)
|
738 |
+
|
739 |
+
# See utility code BufferFormatFromTypeInfo
|
740 |
+
_typeinfo_to_format_code = load_buffer_utility("TypeInfoToFormat")
|
venv/Lib/site-packages/Cython/Compiler/Builtin.py
ADDED
@@ -0,0 +1,445 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#
|
2 |
+
# Builtin Definitions
|
3 |
+
#
|
4 |
+
|
5 |
+
from __future__ import absolute_import
|
6 |
+
|
7 |
+
from .Symtab import BuiltinScope, StructOrUnionScope
|
8 |
+
from .Code import UtilityCode
|
9 |
+
from .TypeSlots import Signature
|
10 |
+
from . import PyrexTypes
|
11 |
+
from . import Options
|
12 |
+
|
13 |
+
|
14 |
+
# C-level implementations of builtin types, functions and methods
|
15 |
+
|
16 |
+
iter_next_utility_code = UtilityCode.load("IterNext", "ObjectHandling.c")
|
17 |
+
getattr_utility_code = UtilityCode.load("GetAttr", "ObjectHandling.c")
|
18 |
+
getattr3_utility_code = UtilityCode.load("GetAttr3", "Builtins.c")
|
19 |
+
pyexec_utility_code = UtilityCode.load("PyExec", "Builtins.c")
|
20 |
+
pyexec_globals_utility_code = UtilityCode.load("PyExecGlobals", "Builtins.c")
|
21 |
+
globals_utility_code = UtilityCode.load("Globals", "Builtins.c")
|
22 |
+
|
23 |
+
builtin_utility_code = {
|
24 |
+
'StopAsyncIteration': UtilityCode.load_cached("StopAsyncIteration", "Coroutine.c"),
|
25 |
+
}
|
26 |
+
|
27 |
+
|
28 |
+
# mapping from builtins to their C-level equivalents
|
29 |
+
|
30 |
+
class _BuiltinOverride(object):
|
31 |
+
def __init__(self, py_name, args, ret_type, cname, py_equiv="*",
|
32 |
+
utility_code=None, sig=None, func_type=None,
|
33 |
+
is_strict_signature=False, builtin_return_type=None):
|
34 |
+
self.py_name, self.cname, self.py_equiv = py_name, cname, py_equiv
|
35 |
+
self.args, self.ret_type = args, ret_type
|
36 |
+
self.func_type, self.sig = func_type, sig
|
37 |
+
self.builtin_return_type = builtin_return_type
|
38 |
+
self.is_strict_signature = is_strict_signature
|
39 |
+
self.utility_code = utility_code
|
40 |
+
|
41 |
+
def build_func_type(self, sig=None, self_arg=None):
|
42 |
+
if sig is None:
|
43 |
+
sig = Signature(self.args, self.ret_type)
|
44 |
+
sig.exception_check = False # not needed for the current builtins
|
45 |
+
func_type = sig.function_type(self_arg)
|
46 |
+
if self.is_strict_signature:
|
47 |
+
func_type.is_strict_signature = True
|
48 |
+
if self.builtin_return_type:
|
49 |
+
func_type.return_type = builtin_types[self.builtin_return_type]
|
50 |
+
return func_type
|
51 |
+
|
52 |
+
|
53 |
+
class BuiltinAttribute(object):
|
54 |
+
def __init__(self, py_name, cname=None, field_type=None, field_type_name=None):
|
55 |
+
self.py_name = py_name
|
56 |
+
self.cname = cname or py_name
|
57 |
+
self.field_type_name = field_type_name # can't do the lookup before the type is declared!
|
58 |
+
self.field_type = field_type
|
59 |
+
|
60 |
+
def declare_in_type(self, self_type):
|
61 |
+
if self.field_type_name is not None:
|
62 |
+
# lazy type lookup
|
63 |
+
field_type = builtin_scope.lookup(self.field_type_name).type
|
64 |
+
else:
|
65 |
+
field_type = self.field_type or PyrexTypes.py_object_type
|
66 |
+
entry = self_type.scope.declare(self.py_name, self.cname, field_type, None, 'private')
|
67 |
+
entry.is_variable = True
|
68 |
+
|
69 |
+
|
70 |
+
class BuiltinFunction(_BuiltinOverride):
|
71 |
+
def declare_in_scope(self, scope):
|
72 |
+
func_type, sig = self.func_type, self.sig
|
73 |
+
if func_type is None:
|
74 |
+
func_type = self.build_func_type(sig)
|
75 |
+
scope.declare_builtin_cfunction(self.py_name, func_type, self.cname,
|
76 |
+
self.py_equiv, self.utility_code)
|
77 |
+
|
78 |
+
|
79 |
+
class BuiltinMethod(_BuiltinOverride):
|
80 |
+
def declare_in_type(self, self_type):
|
81 |
+
method_type, sig = self.func_type, self.sig
|
82 |
+
if method_type is None:
|
83 |
+
# override 'self' type (first argument)
|
84 |
+
self_arg = PyrexTypes.CFuncTypeArg("", self_type, None)
|
85 |
+
self_arg.not_none = True
|
86 |
+
self_arg.accept_builtin_subtypes = True
|
87 |
+
method_type = self.build_func_type(sig, self_arg)
|
88 |
+
self_type.scope.declare_builtin_cfunction(
|
89 |
+
self.py_name, method_type, self.cname, utility_code=self.utility_code)
|
90 |
+
|
91 |
+
|
92 |
+
builtin_function_table = [
|
93 |
+
# name, args, return, C API func, py equiv = "*"
|
94 |
+
BuiltinFunction('abs', "d", "d", "fabs",
|
95 |
+
is_strict_signature = True),
|
96 |
+
BuiltinFunction('abs', "f", "f", "fabsf",
|
97 |
+
is_strict_signature = True),
|
98 |
+
BuiltinFunction('abs', "i", "i", "abs",
|
99 |
+
is_strict_signature = True),
|
100 |
+
BuiltinFunction('abs', "l", "l", "labs",
|
101 |
+
is_strict_signature = True),
|
102 |
+
BuiltinFunction('abs', None, None, "__Pyx_abs_longlong",
|
103 |
+
utility_code = UtilityCode.load("abs_longlong", "Builtins.c"),
|
104 |
+
func_type = PyrexTypes.CFuncType(
|
105 |
+
PyrexTypes.c_longlong_type, [
|
106 |
+
PyrexTypes.CFuncTypeArg("arg", PyrexTypes.c_longlong_type, None)
|
107 |
+
],
|
108 |
+
is_strict_signature = True, nogil=True)),
|
109 |
+
] + list(
|
110 |
+
BuiltinFunction('abs', None, None, "/*abs_{0}*/".format(t.specialization_name()),
|
111 |
+
func_type = PyrexTypes.CFuncType(
|
112 |
+
t,
|
113 |
+
[PyrexTypes.CFuncTypeArg("arg", t, None)],
|
114 |
+
is_strict_signature = True, nogil=True))
|
115 |
+
for t in (PyrexTypes.c_uint_type, PyrexTypes.c_ulong_type, PyrexTypes.c_ulonglong_type)
|
116 |
+
) + list(
|
117 |
+
BuiltinFunction('abs', None, None, "__Pyx_c_abs{0}".format(t.funcsuffix),
|
118 |
+
func_type = PyrexTypes.CFuncType(
|
119 |
+
t.real_type, [
|
120 |
+
PyrexTypes.CFuncTypeArg("arg", t, None)
|
121 |
+
],
|
122 |
+
is_strict_signature = True, nogil=True))
|
123 |
+
for t in (PyrexTypes.c_float_complex_type,
|
124 |
+
PyrexTypes.c_double_complex_type,
|
125 |
+
PyrexTypes.c_longdouble_complex_type)
|
126 |
+
) + [
|
127 |
+
BuiltinFunction('abs', "O", "O", "__Pyx_PyNumber_Absolute",
|
128 |
+
utility_code=UtilityCode.load("py_abs", "Builtins.c")),
|
129 |
+
#('all', "", "", ""),
|
130 |
+
#('any', "", "", ""),
|
131 |
+
#('ascii', "", "", ""),
|
132 |
+
#('bin', "", "", ""),
|
133 |
+
BuiltinFunction('callable', "O", "b", "__Pyx_PyCallable_Check",
|
134 |
+
utility_code = UtilityCode.load("CallableCheck", "ObjectHandling.c")),
|
135 |
+
#('chr', "", "", ""),
|
136 |
+
#('cmp', "", "", "", ""), # int PyObject_Cmp(PyObject *o1, PyObject *o2, int *result)
|
137 |
+
#('compile', "", "", ""), # PyObject* Py_CompileString( char *str, char *filename, int start)
|
138 |
+
BuiltinFunction('delattr', "OO", "r", "PyObject_DelAttr"),
|
139 |
+
BuiltinFunction('dir', "O", "O", "PyObject_Dir"),
|
140 |
+
BuiltinFunction('divmod', "OO", "O", "PyNumber_Divmod"),
|
141 |
+
BuiltinFunction('exec', "O", "O", "__Pyx_PyExecGlobals",
|
142 |
+
utility_code = pyexec_globals_utility_code),
|
143 |
+
BuiltinFunction('exec', "OO", "O", "__Pyx_PyExec2",
|
144 |
+
utility_code = pyexec_utility_code),
|
145 |
+
BuiltinFunction('exec', "OOO", "O", "__Pyx_PyExec3",
|
146 |
+
utility_code = pyexec_utility_code),
|
147 |
+
#('eval', "", "", ""),
|
148 |
+
#('execfile', "", "", ""),
|
149 |
+
#('filter', "", "", ""),
|
150 |
+
BuiltinFunction('getattr3', "OOO", "O", "__Pyx_GetAttr3", "getattr",
|
151 |
+
utility_code=getattr3_utility_code), # Pyrex legacy
|
152 |
+
BuiltinFunction('getattr', "OOO", "O", "__Pyx_GetAttr3",
|
153 |
+
utility_code=getattr3_utility_code),
|
154 |
+
BuiltinFunction('getattr', "OO", "O", "__Pyx_GetAttr",
|
155 |
+
utility_code=getattr_utility_code),
|
156 |
+
BuiltinFunction('hasattr', "OO", "b", "__Pyx_HasAttr",
|
157 |
+
utility_code = UtilityCode.load("HasAttr", "Builtins.c")),
|
158 |
+
BuiltinFunction('hash', "O", "h", "PyObject_Hash"),
|
159 |
+
#('hex', "", "", ""),
|
160 |
+
#('id', "", "", ""),
|
161 |
+
#('input', "", "", ""),
|
162 |
+
BuiltinFunction('intern', "O", "O", "__Pyx_Intern",
|
163 |
+
utility_code = UtilityCode.load("Intern", "Builtins.c")),
|
164 |
+
BuiltinFunction('isinstance', "OO", "b", "PyObject_IsInstance"),
|
165 |
+
BuiltinFunction('issubclass', "OO", "b", "PyObject_IsSubclass"),
|
166 |
+
BuiltinFunction('iter', "OO", "O", "PyCallIter_New"),
|
167 |
+
BuiltinFunction('iter', "O", "O", "PyObject_GetIter"),
|
168 |
+
BuiltinFunction('len', "O", "z", "PyObject_Length"),
|
169 |
+
BuiltinFunction('locals', "", "O", "__pyx_locals"),
|
170 |
+
#('map', "", "", ""),
|
171 |
+
#('max', "", "", ""),
|
172 |
+
#('min', "", "", ""),
|
173 |
+
BuiltinFunction('next', "O", "O", "__Pyx_PyIter_Next",
|
174 |
+
utility_code = iter_next_utility_code), # not available in Py2 => implemented here
|
175 |
+
BuiltinFunction('next', "OO", "O", "__Pyx_PyIter_Next2",
|
176 |
+
utility_code = iter_next_utility_code), # not available in Py2 => implemented here
|
177 |
+
#('oct', "", "", ""),
|
178 |
+
#('open', "ss", "O", "PyFile_FromString"), # not in Py3
|
179 |
+
] + [
|
180 |
+
BuiltinFunction('ord', None, None, "__Pyx_long_cast",
|
181 |
+
func_type=PyrexTypes.CFuncType(
|
182 |
+
PyrexTypes.c_long_type, [PyrexTypes.CFuncTypeArg("c", c_type, None)],
|
183 |
+
is_strict_signature=True))
|
184 |
+
for c_type in [PyrexTypes.c_py_ucs4_type, PyrexTypes.c_py_unicode_type]
|
185 |
+
] + [
|
186 |
+
BuiltinFunction('ord', None, None, "__Pyx_uchar_cast",
|
187 |
+
func_type=PyrexTypes.CFuncType(
|
188 |
+
PyrexTypes.c_uchar_type, [PyrexTypes.CFuncTypeArg("c", c_type, None)],
|
189 |
+
is_strict_signature=True))
|
190 |
+
for c_type in [PyrexTypes.c_char_type, PyrexTypes.c_schar_type, PyrexTypes.c_uchar_type]
|
191 |
+
] + [
|
192 |
+
BuiltinFunction('ord', None, None, "__Pyx_PyObject_Ord",
|
193 |
+
utility_code=UtilityCode.load_cached("object_ord", "Builtins.c"),
|
194 |
+
func_type=PyrexTypes.CFuncType(
|
195 |
+
PyrexTypes.c_long_type, [
|
196 |
+
PyrexTypes.CFuncTypeArg("c", PyrexTypes.py_object_type, None)
|
197 |
+
],
|
198 |
+
exception_value="(long)(Py_UCS4)-1")),
|
199 |
+
BuiltinFunction('pow', "OOO", "O", "PyNumber_Power"),
|
200 |
+
BuiltinFunction('pow', "OO", "O", "__Pyx_PyNumber_Power2",
|
201 |
+
utility_code = UtilityCode.load("pow2", "Builtins.c")),
|
202 |
+
#('range', "", "", ""),
|
203 |
+
#('raw_input', "", "", ""),
|
204 |
+
#('reduce', "", "", ""),
|
205 |
+
BuiltinFunction('reload', "O", "O", "PyImport_ReloadModule"),
|
206 |
+
BuiltinFunction('repr', "O", "O", "PyObject_Repr"), # , builtin_return_type='str'), # add in Cython 3.1
|
207 |
+
#('round', "", "", ""),
|
208 |
+
BuiltinFunction('setattr', "OOO", "r", "PyObject_SetAttr"),
|
209 |
+
#('sum', "", "", ""),
|
210 |
+
#('sorted', "", "", ""),
|
211 |
+
#('type', "O", "O", "PyObject_Type"),
|
212 |
+
#('unichr', "", "", ""),
|
213 |
+
#('unicode', "", "", ""),
|
214 |
+
#('vars', "", "", ""),
|
215 |
+
#('zip', "", "", ""),
|
216 |
+
# Can't do these easily until we have builtin type entries.
|
217 |
+
#('typecheck', "OO", "i", "PyObject_TypeCheck", False),
|
218 |
+
#('issubtype', "OO", "i", "PyType_IsSubtype", False),
|
219 |
+
|
220 |
+
# Put in namespace append optimization.
|
221 |
+
BuiltinFunction('__Pyx_PyObject_Append', "OO", "O", "__Pyx_PyObject_Append"),
|
222 |
+
|
223 |
+
# This is conditionally looked up based on a compiler directive.
|
224 |
+
BuiltinFunction('__Pyx_Globals', "", "O", "__Pyx_Globals",
|
225 |
+
utility_code=globals_utility_code),
|
226 |
+
]
|
227 |
+
|
228 |
+
|
229 |
+
# Builtin types
|
230 |
+
# bool
|
231 |
+
# buffer
|
232 |
+
# classmethod
|
233 |
+
# dict
|
234 |
+
# enumerate
|
235 |
+
# file
|
236 |
+
# float
|
237 |
+
# int
|
238 |
+
# list
|
239 |
+
# long
|
240 |
+
# object
|
241 |
+
# property
|
242 |
+
# slice
|
243 |
+
# staticmethod
|
244 |
+
# super
|
245 |
+
# str
|
246 |
+
# tuple
|
247 |
+
# type
|
248 |
+
# xrange
|
249 |
+
|
250 |
+
builtin_types_table = [
|
251 |
+
|
252 |
+
("type", "PyType_Type", []),
|
253 |
+
|
254 |
+
# This conflicts with the C++ bool type, and unfortunately
|
255 |
+
# C++ is too liberal about PyObject* <-> bool conversions,
|
256 |
+
# resulting in unintuitive runtime behavior and segfaults.
|
257 |
+
# ("bool", "PyBool_Type", []),
|
258 |
+
|
259 |
+
("int", "PyInt_Type", []),
|
260 |
+
("long", "PyLong_Type", []),
|
261 |
+
("float", "PyFloat_Type", []),
|
262 |
+
|
263 |
+
("complex", "PyComplex_Type", [BuiltinAttribute('cval', field_type_name = 'Py_complex'),
|
264 |
+
BuiltinAttribute('real', 'cval.real', field_type = PyrexTypes.c_double_type),
|
265 |
+
BuiltinAttribute('imag', 'cval.imag', field_type = PyrexTypes.c_double_type),
|
266 |
+
]),
|
267 |
+
|
268 |
+
("basestring", "PyBaseString_Type", [
|
269 |
+
BuiltinMethod("join", "TO", "T", "__Pyx_PyBaseString_Join",
|
270 |
+
utility_code=UtilityCode.load("StringJoin", "StringTools.c")),
|
271 |
+
]),
|
272 |
+
("bytearray", "PyByteArray_Type", [
|
273 |
+
]),
|
274 |
+
("bytes", "PyBytes_Type", [BuiltinMethod("join", "TO", "O", "__Pyx_PyBytes_Join",
|
275 |
+
utility_code=UtilityCode.load("StringJoin", "StringTools.c")),
|
276 |
+
]),
|
277 |
+
("str", "PyString_Type", [BuiltinMethod("join", "TO", "O", "__Pyx_PyString_Join",
|
278 |
+
builtin_return_type='basestring',
|
279 |
+
utility_code=UtilityCode.load("StringJoin", "StringTools.c")),
|
280 |
+
]),
|
281 |
+
("unicode", "PyUnicode_Type", [BuiltinMethod("__contains__", "TO", "b", "PyUnicode_Contains"),
|
282 |
+
BuiltinMethod("join", "TO", "T", "PyUnicode_Join"),
|
283 |
+
]),
|
284 |
+
|
285 |
+
("tuple", "PyTuple_Type", []),
|
286 |
+
|
287 |
+
("list", "PyList_Type", [BuiltinMethod("insert", "TzO", "r", "PyList_Insert"),
|
288 |
+
BuiltinMethod("reverse", "T", "r", "PyList_Reverse"),
|
289 |
+
BuiltinMethod("append", "TO", "r", "__Pyx_PyList_Append",
|
290 |
+
utility_code=UtilityCode.load("ListAppend", "Optimize.c")),
|
291 |
+
BuiltinMethod("extend", "TO", "r", "__Pyx_PyList_Extend",
|
292 |
+
utility_code=UtilityCode.load("ListExtend", "Optimize.c")),
|
293 |
+
]),
|
294 |
+
|
295 |
+
("dict", "PyDict_Type", [BuiltinMethod("__contains__", "TO", "b", "PyDict_Contains"),
|
296 |
+
BuiltinMethod("has_key", "TO", "b", "PyDict_Contains"),
|
297 |
+
BuiltinMethod("items", "T", "O", "__Pyx_PyDict_Items",
|
298 |
+
utility_code=UtilityCode.load("py_dict_items", "Builtins.c")),
|
299 |
+
BuiltinMethod("keys", "T", "O", "__Pyx_PyDict_Keys",
|
300 |
+
utility_code=UtilityCode.load("py_dict_keys", "Builtins.c")),
|
301 |
+
BuiltinMethod("values", "T", "O", "__Pyx_PyDict_Values",
|
302 |
+
utility_code=UtilityCode.load("py_dict_values", "Builtins.c")),
|
303 |
+
BuiltinMethod("iteritems", "T", "O", "__Pyx_PyDict_IterItems",
|
304 |
+
utility_code=UtilityCode.load("py_dict_iteritems", "Builtins.c")),
|
305 |
+
BuiltinMethod("iterkeys", "T", "O", "__Pyx_PyDict_IterKeys",
|
306 |
+
utility_code=UtilityCode.load("py_dict_iterkeys", "Builtins.c")),
|
307 |
+
BuiltinMethod("itervalues", "T", "O", "__Pyx_PyDict_IterValues",
|
308 |
+
utility_code=UtilityCode.load("py_dict_itervalues", "Builtins.c")),
|
309 |
+
BuiltinMethod("viewitems", "T", "O", "__Pyx_PyDict_ViewItems",
|
310 |
+
utility_code=UtilityCode.load("py_dict_viewitems", "Builtins.c")),
|
311 |
+
BuiltinMethod("viewkeys", "T", "O", "__Pyx_PyDict_ViewKeys",
|
312 |
+
utility_code=UtilityCode.load("py_dict_viewkeys", "Builtins.c")),
|
313 |
+
BuiltinMethod("viewvalues", "T", "O", "__Pyx_PyDict_ViewValues",
|
314 |
+
utility_code=UtilityCode.load("py_dict_viewvalues", "Builtins.c")),
|
315 |
+
BuiltinMethod("clear", "T", "r", "__Pyx_PyDict_Clear",
|
316 |
+
utility_code=UtilityCode.load("py_dict_clear", "Optimize.c")),
|
317 |
+
BuiltinMethod("copy", "T", "T", "PyDict_Copy")]),
|
318 |
+
|
319 |
+
("slice", "PySlice_Type", [BuiltinAttribute('start'),
|
320 |
+
BuiltinAttribute('stop'),
|
321 |
+
BuiltinAttribute('step'),
|
322 |
+
]),
|
323 |
+
# ("file", "PyFile_Type", []), # not in Py3
|
324 |
+
|
325 |
+
("set", "PySet_Type", [BuiltinMethod("clear", "T", "r", "PySet_Clear"),
|
326 |
+
# discard() and remove() have a special treatment for unhashable values
|
327 |
+
BuiltinMethod("discard", "TO", "r", "__Pyx_PySet_Discard",
|
328 |
+
utility_code=UtilityCode.load("py_set_discard", "Optimize.c")),
|
329 |
+
BuiltinMethod("remove", "TO", "r", "__Pyx_PySet_Remove",
|
330 |
+
utility_code=UtilityCode.load("py_set_remove", "Optimize.c")),
|
331 |
+
# update is actually variadic (see Github issue #1645)
|
332 |
+
# BuiltinMethod("update", "TO", "r", "__Pyx_PySet_Update",
|
333 |
+
# utility_code=UtilityCode.load_cached("PySet_Update", "Builtins.c")),
|
334 |
+
BuiltinMethod("add", "TO", "r", "PySet_Add"),
|
335 |
+
BuiltinMethod("pop", "T", "O", "PySet_Pop")]),
|
336 |
+
("frozenset", "PyFrozenSet_Type", []),
|
337 |
+
("Exception", "((PyTypeObject*)PyExc_Exception)[0]", []),
|
338 |
+
("StopAsyncIteration", "((PyTypeObject*)__Pyx_PyExc_StopAsyncIteration)[0]", []),
|
339 |
+
]
|
340 |
+
|
341 |
+
|
342 |
+
types_that_construct_their_instance = set([
|
343 |
+
# some builtin types do not always return an instance of
|
344 |
+
# themselves - these do:
|
345 |
+
'type', 'bool', 'long', 'float', 'complex',
|
346 |
+
'bytes', 'unicode', 'bytearray',
|
347 |
+
'tuple', 'list', 'dict', 'set', 'frozenset'
|
348 |
+
# 'str', # only in Py3.x
|
349 |
+
# 'file', # only in Py2.x
|
350 |
+
])
|
351 |
+
|
352 |
+
|
353 |
+
builtin_structs_table = [
|
354 |
+
('Py_buffer', 'Py_buffer',
|
355 |
+
[("buf", PyrexTypes.c_void_ptr_type),
|
356 |
+
("obj", PyrexTypes.py_object_type),
|
357 |
+
("len", PyrexTypes.c_py_ssize_t_type),
|
358 |
+
("itemsize", PyrexTypes.c_py_ssize_t_type),
|
359 |
+
("readonly", PyrexTypes.c_bint_type),
|
360 |
+
("ndim", PyrexTypes.c_int_type),
|
361 |
+
("format", PyrexTypes.c_char_ptr_type),
|
362 |
+
("shape", PyrexTypes.c_py_ssize_t_ptr_type),
|
363 |
+
("strides", PyrexTypes.c_py_ssize_t_ptr_type),
|
364 |
+
("suboffsets", PyrexTypes.c_py_ssize_t_ptr_type),
|
365 |
+
("smalltable", PyrexTypes.CArrayType(PyrexTypes.c_py_ssize_t_type, 2)),
|
366 |
+
("internal", PyrexTypes.c_void_ptr_type),
|
367 |
+
]),
|
368 |
+
('Py_complex', 'Py_complex',
|
369 |
+
[('real', PyrexTypes.c_double_type),
|
370 |
+
('imag', PyrexTypes.c_double_type),
|
371 |
+
])
|
372 |
+
]
|
373 |
+
|
374 |
+
# set up builtin scope
|
375 |
+
|
376 |
+
builtin_scope = BuiltinScope()
|
377 |
+
|
378 |
+
def init_builtin_funcs():
|
379 |
+
for bf in builtin_function_table:
|
380 |
+
bf.declare_in_scope(builtin_scope)
|
381 |
+
|
382 |
+
builtin_types = {}
|
383 |
+
|
384 |
+
def init_builtin_types():
|
385 |
+
global builtin_types
|
386 |
+
for name, cname, methods in builtin_types_table:
|
387 |
+
utility = builtin_utility_code.get(name)
|
388 |
+
if name == 'frozenset':
|
389 |
+
objstruct_cname = 'PySetObject'
|
390 |
+
elif name == 'bytearray':
|
391 |
+
objstruct_cname = 'PyByteArrayObject'
|
392 |
+
elif name == 'bool':
|
393 |
+
objstruct_cname = None
|
394 |
+
elif name == 'Exception':
|
395 |
+
objstruct_cname = "PyBaseExceptionObject"
|
396 |
+
elif name == 'StopAsyncIteration':
|
397 |
+
objstruct_cname = "PyBaseExceptionObject"
|
398 |
+
else:
|
399 |
+
objstruct_cname = 'Py%sObject' % name.capitalize()
|
400 |
+
the_type = builtin_scope.declare_builtin_type(name, cname, utility, objstruct_cname)
|
401 |
+
builtin_types[name] = the_type
|
402 |
+
for method in methods:
|
403 |
+
method.declare_in_type(the_type)
|
404 |
+
|
405 |
+
def init_builtin_structs():
|
406 |
+
for name, cname, attribute_types in builtin_structs_table:
|
407 |
+
scope = StructOrUnionScope(name)
|
408 |
+
for attribute_name, attribute_type in attribute_types:
|
409 |
+
scope.declare_var(attribute_name, attribute_type, None,
|
410 |
+
attribute_name, allow_pyobject=True)
|
411 |
+
builtin_scope.declare_struct_or_union(
|
412 |
+
name, "struct", scope, 1, None, cname = cname)
|
413 |
+
|
414 |
+
|
415 |
+
def init_builtins():
|
416 |
+
init_builtin_structs()
|
417 |
+
init_builtin_types()
|
418 |
+
init_builtin_funcs()
|
419 |
+
|
420 |
+
entry = builtin_scope.declare_var(
|
421 |
+
'__debug__', PyrexTypes.c_const_type(PyrexTypes.c_bint_type),
|
422 |
+
pos=None, cname='__pyx_assertions_enabled()', is_cdef=True)
|
423 |
+
entry.utility_code = UtilityCode.load_cached("AssertionsEnabled", "Exceptions.c")
|
424 |
+
|
425 |
+
global list_type, tuple_type, dict_type, set_type, frozenset_type
|
426 |
+
global bytes_type, str_type, unicode_type, basestring_type, slice_type
|
427 |
+
global float_type, bool_type, type_type, complex_type, bytearray_type
|
428 |
+
type_type = builtin_scope.lookup('type').type
|
429 |
+
list_type = builtin_scope.lookup('list').type
|
430 |
+
tuple_type = builtin_scope.lookup('tuple').type
|
431 |
+
dict_type = builtin_scope.lookup('dict').type
|
432 |
+
set_type = builtin_scope.lookup('set').type
|
433 |
+
frozenset_type = builtin_scope.lookup('frozenset').type
|
434 |
+
slice_type = builtin_scope.lookup('slice').type
|
435 |
+
bytes_type = builtin_scope.lookup('bytes').type
|
436 |
+
str_type = builtin_scope.lookup('str').type
|
437 |
+
unicode_type = builtin_scope.lookup('unicode').type
|
438 |
+
basestring_type = builtin_scope.lookup('basestring').type
|
439 |
+
bytearray_type = builtin_scope.lookup('bytearray').type
|
440 |
+
float_type = builtin_scope.lookup('float').type
|
441 |
+
bool_type = builtin_scope.lookup('bool').type
|
442 |
+
complex_type = builtin_scope.lookup('complex').type
|
443 |
+
|
444 |
+
|
445 |
+
init_builtins()
|
venv/Lib/site-packages/Cython/Compiler/CmdLine.py
ADDED
@@ -0,0 +1,240 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#
|
2 |
+
# Cython - Command Line Parsing
|
3 |
+
#
|
4 |
+
|
5 |
+
from __future__ import absolute_import
|
6 |
+
|
7 |
+
import os
|
8 |
+
import sys
|
9 |
+
from . import Options
|
10 |
+
|
11 |
+
usage = """\
|
12 |
+
Cython (http://cython.org) is a compiler for code written in the
|
13 |
+
Cython language. Cython is based on Pyrex by Greg Ewing.
|
14 |
+
|
15 |
+
Usage: cython [options] sourcefile.{pyx,py} ...
|
16 |
+
|
17 |
+
Options:
|
18 |
+
-V, --version Display version number of cython compiler
|
19 |
+
-l, --create-listing Write error messages to a listing file
|
20 |
+
-I, --include-dir <directory> Search for include files in named directory
|
21 |
+
(multiple include directories are allowed).
|
22 |
+
-o, --output-file <filename> Specify name of generated C file
|
23 |
+
-t, --timestamps Only compile newer source files
|
24 |
+
-f, --force Compile all source files (overrides implied -t)
|
25 |
+
-v, --verbose Be verbose, print file names on multiple compilation
|
26 |
+
-p, --embed-positions If specified, the positions in Cython files of each
|
27 |
+
function definition is embedded in its docstring.
|
28 |
+
--cleanup <level> Release interned objects on python exit, for memory debugging.
|
29 |
+
Level indicates aggressiveness, default 0 releases nothing.
|
30 |
+
-w, --working <directory> Sets the working directory for Cython (the directory modules
|
31 |
+
are searched from)
|
32 |
+
--gdb Output debug information for cygdb
|
33 |
+
--gdb-outdir <directory> Specify gdb debug information output directory. Implies --gdb.
|
34 |
+
|
35 |
+
-D, --no-docstrings Strip docstrings from the compiled module.
|
36 |
+
-a, --annotate Produce a colorized HTML version of the source.
|
37 |
+
--annotate-coverage <cov.xml> Annotate and include coverage information from cov.xml.
|
38 |
+
--line-directives Produce #line directives pointing to the .pyx source
|
39 |
+
--cplus Output a C++ rather than C file.
|
40 |
+
--embed[=<method_name>] Generate a main() function that embeds the Python interpreter.
|
41 |
+
-2 Compile based on Python-2 syntax and code semantics.
|
42 |
+
-3 Compile based on Python-3 syntax and code semantics.
|
43 |
+
--3str Compile based on Python-3 syntax and code semantics without
|
44 |
+
assuming unicode by default for string literals under Python 2.
|
45 |
+
--lenient Change some compile time errors to runtime errors to
|
46 |
+
improve Python compatibility
|
47 |
+
--capi-reexport-cincludes Add cincluded headers to any auto-generated header files.
|
48 |
+
--fast-fail Abort the compilation on the first error
|
49 |
+
--warning-errors, -Werror Make all warnings into errors
|
50 |
+
--warning-extra, -Wextra Enable extra warnings
|
51 |
+
-X, --directive <name>=<value>[,<name=value,...] Overrides a compiler directive
|
52 |
+
-E, --compile-time-env name=value[,<name=value,...] Provides compile time env like DEF would do.
|
53 |
+
--module-name Fully qualified module name. If not given, it is deduced from the
|
54 |
+
import path if source file is in a package, or equals the
|
55 |
+
filename otherwise.
|
56 |
+
-M, --depfile Produce depfiles for the sources
|
57 |
+
"""
|
58 |
+
|
59 |
+
|
60 |
+
# The following experimental options are supported only on MacOSX:
|
61 |
+
# -C, --compile Compile generated .c file to .o file
|
62 |
+
# --link Link .o file to produce extension module (implies -C)
|
63 |
+
# -+, --cplus Use C++ compiler for compiling and linking
|
64 |
+
# Additional .o files to link may be supplied when using -X."""
|
65 |
+
|
66 |
+
def bad_usage():
|
67 |
+
sys.stderr.write(usage)
|
68 |
+
sys.exit(1)
|
69 |
+
|
70 |
+
def parse_command_line(args):
|
71 |
+
from .Main import CompilationOptions, default_options
|
72 |
+
|
73 |
+
pending_arg = []
|
74 |
+
|
75 |
+
def pop_arg():
|
76 |
+
if not args or pending_arg:
|
77 |
+
bad_usage()
|
78 |
+
if '=' in args[0] and args[0].startswith('--'): # allow "--long-option=xyz"
|
79 |
+
name, value = args.pop(0).split('=', 1)
|
80 |
+
pending_arg.append(value)
|
81 |
+
return name
|
82 |
+
return args.pop(0)
|
83 |
+
|
84 |
+
def pop_value(default=None):
|
85 |
+
if pending_arg:
|
86 |
+
return pending_arg.pop()
|
87 |
+
elif default is not None:
|
88 |
+
return default
|
89 |
+
elif not args:
|
90 |
+
bad_usage()
|
91 |
+
return args.pop(0)
|
92 |
+
|
93 |
+
def get_param(option):
|
94 |
+
tail = option[2:]
|
95 |
+
if tail:
|
96 |
+
return tail
|
97 |
+
else:
|
98 |
+
return pop_arg()
|
99 |
+
|
100 |
+
options = CompilationOptions(default_options)
|
101 |
+
sources = []
|
102 |
+
while args:
|
103 |
+
if args[0].startswith("-"):
|
104 |
+
option = pop_arg()
|
105 |
+
if option in ("-V", "--version"):
|
106 |
+
options.show_version = 1
|
107 |
+
elif option in ("-l", "--create-listing"):
|
108 |
+
options.use_listing_file = 1
|
109 |
+
elif option in ("-+", "--cplus"):
|
110 |
+
options.cplus = 1
|
111 |
+
elif option == "--embed":
|
112 |
+
Options.embed = pop_value("main")
|
113 |
+
elif option.startswith("-I"):
|
114 |
+
options.include_path.append(get_param(option))
|
115 |
+
elif option == "--include-dir":
|
116 |
+
options.include_path.append(pop_value())
|
117 |
+
elif option in ("-w", "--working"):
|
118 |
+
options.working_path = pop_value()
|
119 |
+
elif option in ("-o", "--output-file"):
|
120 |
+
options.output_file = pop_value()
|
121 |
+
elif option in ("-t", "--timestamps"):
|
122 |
+
options.timestamps = 1
|
123 |
+
elif option in ("-f", "--force"):
|
124 |
+
options.timestamps = 0
|
125 |
+
elif option in ("-v", "--verbose"):
|
126 |
+
options.verbose += 1
|
127 |
+
elif option in ("-p", "--embed-positions"):
|
128 |
+
Options.embed_pos_in_docstring = 1
|
129 |
+
elif option in ("-z", "--pre-import"):
|
130 |
+
Options.pre_import = pop_value()
|
131 |
+
elif option == "--cleanup":
|
132 |
+
Options.generate_cleanup_code = int(pop_value())
|
133 |
+
elif option in ("-D", "--no-docstrings"):
|
134 |
+
Options.docstrings = False
|
135 |
+
elif option in ("-a", "--annotate"):
|
136 |
+
Options.annotate = True
|
137 |
+
elif option == "--annotate-coverage":
|
138 |
+
Options.annotate = True
|
139 |
+
Options.annotate_coverage_xml = pop_value()
|
140 |
+
elif option == "--convert-range":
|
141 |
+
Options.convert_range = True
|
142 |
+
elif option == "--line-directives":
|
143 |
+
options.emit_linenums = True
|
144 |
+
elif option == "--no-c-in-traceback":
|
145 |
+
options.c_line_in_traceback = False
|
146 |
+
elif option == "--gdb":
|
147 |
+
options.gdb_debug = True
|
148 |
+
options.output_dir = os.curdir
|
149 |
+
elif option == "--gdb-outdir":
|
150 |
+
options.gdb_debug = True
|
151 |
+
options.output_dir = pop_value()
|
152 |
+
elif option == "--lenient":
|
153 |
+
Options.error_on_unknown_names = False
|
154 |
+
Options.error_on_uninitialized = False
|
155 |
+
elif option == '-2':
|
156 |
+
options.language_level = 2
|
157 |
+
elif option == '-3':
|
158 |
+
options.language_level = 3
|
159 |
+
elif option == '--3str':
|
160 |
+
options.language_level = '3str'
|
161 |
+
elif option == "--capi-reexport-cincludes":
|
162 |
+
options.capi_reexport_cincludes = True
|
163 |
+
elif option == "--fast-fail":
|
164 |
+
Options.fast_fail = True
|
165 |
+
elif option == "--cimport-from-pyx":
|
166 |
+
Options.cimport_from_pyx = True
|
167 |
+
elif option in ('-Werror', '--warning-errors'):
|
168 |
+
Options.warning_errors = True
|
169 |
+
elif option in ('-Wextra', '--warning-extra'):
|
170 |
+
options.compiler_directives.update(Options.extra_warnings)
|
171 |
+
elif option == "--old-style-globals":
|
172 |
+
Options.old_style_globals = True
|
173 |
+
elif option == "--directive" or option.startswith('-X'):
|
174 |
+
if option.startswith('-X') and option[2:].strip():
|
175 |
+
x_args = option[2:]
|
176 |
+
else:
|
177 |
+
x_args = pop_value()
|
178 |
+
try:
|
179 |
+
options.compiler_directives = Options.parse_directive_list(
|
180 |
+
x_args, relaxed_bool=True,
|
181 |
+
current_settings=options.compiler_directives)
|
182 |
+
except ValueError as e:
|
183 |
+
sys.stderr.write("Error in compiler directive: %s\n" % e.args[0])
|
184 |
+
sys.exit(1)
|
185 |
+
elif option == "--compile-time-env" or option.startswith('-E'):
|
186 |
+
if option.startswith('-E') and option[2:].strip():
|
187 |
+
x_args = option[2:]
|
188 |
+
else:
|
189 |
+
x_args = pop_value()
|
190 |
+
try:
|
191 |
+
options.compile_time_env = Options.parse_compile_time_env(
|
192 |
+
x_args, current_settings=options.compile_time_env)
|
193 |
+
except ValueError as e:
|
194 |
+
sys.stderr.write("Error in compile-time-env: %s\n" % e.args[0])
|
195 |
+
sys.exit(1)
|
196 |
+
elif option == "--module-name":
|
197 |
+
options.module_name = pop_value()
|
198 |
+
elif option in ('-M', '--depfile'):
|
199 |
+
options.depfile = True
|
200 |
+
elif option.startswith('--debug'):
|
201 |
+
option = option[2:].replace('-', '_')
|
202 |
+
from . import DebugFlags
|
203 |
+
if option in dir(DebugFlags):
|
204 |
+
setattr(DebugFlags, option, True)
|
205 |
+
else:
|
206 |
+
sys.stderr.write("Unknown debug flag: %s\n" % option)
|
207 |
+
bad_usage()
|
208 |
+
elif option in ('-h', '--help'):
|
209 |
+
sys.stdout.write(usage)
|
210 |
+
sys.exit(0)
|
211 |
+
else:
|
212 |
+
sys.stderr.write(usage)
|
213 |
+
sys.stderr.write("Unknown compiler flag: %s\n" % option)
|
214 |
+
sys.exit(1)
|
215 |
+
else:
|
216 |
+
sources.append(pop_arg())
|
217 |
+
|
218 |
+
if pending_arg:
|
219 |
+
bad_usage()
|
220 |
+
|
221 |
+
if options.use_listing_file and len(sources) > 1:
|
222 |
+
sys.stderr.write(
|
223 |
+
"cython: Only one source file allowed when using -o\n")
|
224 |
+
sys.exit(1)
|
225 |
+
if len(sources) == 0 and not options.show_version:
|
226 |
+
bad_usage()
|
227 |
+
if Options.embed and len(sources) > 1:
|
228 |
+
sys.stderr.write(
|
229 |
+
"cython: Only one source file allowed when using --embed\n")
|
230 |
+
sys.exit(1)
|
231 |
+
if options.module_name:
|
232 |
+
if options.timestamps:
|
233 |
+
sys.stderr.write(
|
234 |
+
"cython: Cannot use --module-name with --timestamps\n")
|
235 |
+
sys.exit(1)
|
236 |
+
if len(sources) > 1:
|
237 |
+
sys.stderr.write(
|
238 |
+
"cython: Only one source file allowed when using --module-name\n")
|
239 |
+
sys.exit(1)
|
240 |
+
return options, sources
|
venv/Lib/site-packages/Cython/Compiler/Code.pxd
ADDED
@@ -0,0 +1,124 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
|
2 |
+
from __future__ import absolute_import
|
3 |
+
|
4 |
+
cimport cython
|
5 |
+
from ..StringIOTree cimport StringIOTree
|
6 |
+
|
7 |
+
|
8 |
+
cdef class UtilityCodeBase(object):
|
9 |
+
cpdef format_code(self, code_string, replace_empty_lines=*)
|
10 |
+
|
11 |
+
|
12 |
+
cdef class UtilityCode(UtilityCodeBase):
|
13 |
+
cdef public object name
|
14 |
+
cdef public object proto
|
15 |
+
cdef public object impl
|
16 |
+
cdef public object init
|
17 |
+
cdef public object cleanup
|
18 |
+
cdef public object proto_block
|
19 |
+
cdef public object requires
|
20 |
+
cdef public dict _cache
|
21 |
+
cdef public list specialize_list
|
22 |
+
cdef public object file
|
23 |
+
|
24 |
+
cpdef none_or_sub(self, s, context)
|
25 |
+
|
26 |
+
|
27 |
+
cdef class FunctionState:
|
28 |
+
cdef public set names_taken
|
29 |
+
cdef public object owner
|
30 |
+
cdef public object scope
|
31 |
+
|
32 |
+
cdef public object error_label
|
33 |
+
cdef public size_t label_counter
|
34 |
+
cdef public set labels_used
|
35 |
+
cdef public object return_label
|
36 |
+
cdef public object continue_label
|
37 |
+
cdef public object break_label
|
38 |
+
cdef public list yield_labels
|
39 |
+
|
40 |
+
cdef public object return_from_error_cleanup_label # not used in __init__ ?
|
41 |
+
|
42 |
+
cdef public object exc_vars
|
43 |
+
cdef public object current_except
|
44 |
+
cdef public bint in_try_finally
|
45 |
+
cdef public bint can_trace
|
46 |
+
cdef public bint gil_owned
|
47 |
+
|
48 |
+
cdef public list temps_allocated
|
49 |
+
cdef public dict temps_free
|
50 |
+
cdef public dict temps_used_type
|
51 |
+
cdef public set zombie_temps
|
52 |
+
cdef public size_t temp_counter
|
53 |
+
cdef public list collect_temps_stack
|
54 |
+
|
55 |
+
cdef public object closure_temps
|
56 |
+
cdef public bint should_declare_error_indicator
|
57 |
+
cdef public bint uses_error_indicator
|
58 |
+
|
59 |
+
@cython.locals(n=size_t)
|
60 |
+
cpdef new_label(self, name=*)
|
61 |
+
cpdef tuple get_loop_labels(self)
|
62 |
+
cpdef set_loop_labels(self, labels)
|
63 |
+
cpdef tuple get_all_labels(self)
|
64 |
+
cpdef set_all_labels(self, labels)
|
65 |
+
cpdef start_collecting_temps(self)
|
66 |
+
cpdef stop_collecting_temps(self)
|
67 |
+
|
68 |
+
cpdef list temps_in_use(self)
|
69 |
+
|
70 |
+
cdef class IntConst:
|
71 |
+
cdef public object cname
|
72 |
+
cdef public object value
|
73 |
+
cdef public bint is_long
|
74 |
+
|
75 |
+
cdef class PyObjectConst:
|
76 |
+
cdef public object cname
|
77 |
+
cdef public object type
|
78 |
+
|
79 |
+
cdef class StringConst:
|
80 |
+
cdef public object cname
|
81 |
+
cdef public object text
|
82 |
+
cdef public object escaped_value
|
83 |
+
cdef public dict py_strings
|
84 |
+
cdef public list py_versions
|
85 |
+
|
86 |
+
@cython.locals(intern=bint, is_str=bint, is_unicode=bint)
|
87 |
+
cpdef get_py_string_const(self, encoding, identifier=*, is_str=*, py3str_cstring=*)
|
88 |
+
|
89 |
+
## cdef class PyStringConst:
|
90 |
+
## cdef public object cname
|
91 |
+
## cdef public object encoding
|
92 |
+
## cdef public bint is_str
|
93 |
+
## cdef public bint is_unicode
|
94 |
+
## cdef public bint intern
|
95 |
+
|
96 |
+
#class GlobalState(object):
|
97 |
+
|
98 |
+
#def funccontext_property(name):
|
99 |
+
|
100 |
+
cdef class CCodeWriter(object):
|
101 |
+
cdef readonly StringIOTree buffer
|
102 |
+
cdef readonly list pyclass_stack
|
103 |
+
cdef readonly object globalstate
|
104 |
+
cdef readonly object funcstate
|
105 |
+
cdef object code_config
|
106 |
+
cdef object last_pos
|
107 |
+
cdef object last_marked_pos
|
108 |
+
cdef Py_ssize_t level
|
109 |
+
cdef public Py_ssize_t call_level # debug-only, see Nodes.py
|
110 |
+
cdef bint bol
|
111 |
+
|
112 |
+
cpdef write(self, s)
|
113 |
+
cpdef put(self, code)
|
114 |
+
cpdef put_safe(self, code)
|
115 |
+
cpdef putln(self, code=*, bint safe=*)
|
116 |
+
@cython.final
|
117 |
+
cdef increase_indent(self)
|
118 |
+
@cython.final
|
119 |
+
cdef decrease_indent(self)
|
120 |
+
|
121 |
+
|
122 |
+
cdef class PyrexCodeWriter:
|
123 |
+
cdef public object f
|
124 |
+
cdef public Py_ssize_t level
|
venv/Lib/site-packages/Cython/Compiler/Code.py
ADDED
@@ -0,0 +1,2597 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# cython: language_level = 2
|
2 |
+
# cython: auto_pickle=False
|
3 |
+
#
|
4 |
+
# Code output module
|
5 |
+
#
|
6 |
+
|
7 |
+
from __future__ import absolute_import
|
8 |
+
|
9 |
+
import cython
|
10 |
+
cython.declare(os=object, re=object, operator=object, textwrap=object,
|
11 |
+
Template=object, Naming=object, Options=object, StringEncoding=object,
|
12 |
+
Utils=object, SourceDescriptor=object, StringIOTree=object,
|
13 |
+
DebugFlags=object, basestring=object, defaultdict=object,
|
14 |
+
closing=object, partial=object)
|
15 |
+
|
16 |
+
import os
|
17 |
+
import re
|
18 |
+
import shutil
|
19 |
+
import sys
|
20 |
+
import operator
|
21 |
+
import textwrap
|
22 |
+
from string import Template
|
23 |
+
from functools import partial
|
24 |
+
from contextlib import closing
|
25 |
+
from collections import defaultdict
|
26 |
+
|
27 |
+
try:
|
28 |
+
import hashlib
|
29 |
+
except ImportError:
|
30 |
+
import md5 as hashlib
|
31 |
+
|
32 |
+
from . import Naming
|
33 |
+
from . import Options
|
34 |
+
from . import DebugFlags
|
35 |
+
from . import StringEncoding
|
36 |
+
from . import Version
|
37 |
+
from .. import Utils
|
38 |
+
from .Scanning import SourceDescriptor
|
39 |
+
from ..StringIOTree import StringIOTree
|
40 |
+
|
41 |
+
try:
|
42 |
+
from __builtin__ import basestring
|
43 |
+
except ImportError:
|
44 |
+
from builtins import str as basestring
|
45 |
+
|
46 |
+
KEYWORDS_MUST_BE_BYTES = sys.version_info < (2, 7)
|
47 |
+
|
48 |
+
|
49 |
+
non_portable_builtins_map = {
|
50 |
+
# builtins that have different names in different Python versions
|
51 |
+
'bytes' : ('PY_MAJOR_VERSION < 3', 'str'),
|
52 |
+
'unicode' : ('PY_MAJOR_VERSION >= 3', 'str'),
|
53 |
+
'basestring' : ('PY_MAJOR_VERSION >= 3', 'str'),
|
54 |
+
'xrange' : ('PY_MAJOR_VERSION >= 3', 'range'),
|
55 |
+
'raw_input' : ('PY_MAJOR_VERSION >= 3', 'input'),
|
56 |
+
}
|
57 |
+
|
58 |
+
ctypedef_builtins_map = {
|
59 |
+
# types of builtins in "ctypedef class" statements which we don't
|
60 |
+
# import either because the names conflict with C types or because
|
61 |
+
# the type simply is not exposed.
|
62 |
+
'py_int' : '&PyInt_Type',
|
63 |
+
'py_long' : '&PyLong_Type',
|
64 |
+
'py_float' : '&PyFloat_Type',
|
65 |
+
'wrapper_descriptor' : '&PyWrapperDescr_Type',
|
66 |
+
}
|
67 |
+
|
68 |
+
basicsize_builtins_map = {
|
69 |
+
# builtins whose type has a different tp_basicsize than sizeof(...)
|
70 |
+
'PyTypeObject': 'PyHeapTypeObject',
|
71 |
+
}
|
72 |
+
|
73 |
+
uncachable_builtins = [
|
74 |
+
# Global/builtin names that cannot be cached because they may or may not
|
75 |
+
# be available at import time, for various reasons:
|
76 |
+
## - Py3.7+
|
77 |
+
'breakpoint', # might deserve an implementation in Cython
|
78 |
+
## - Py3.4+
|
79 |
+
'__loader__',
|
80 |
+
'__spec__',
|
81 |
+
## - Py3+
|
82 |
+
'BlockingIOError',
|
83 |
+
'BrokenPipeError',
|
84 |
+
'ChildProcessError',
|
85 |
+
'ConnectionAbortedError',
|
86 |
+
'ConnectionError',
|
87 |
+
'ConnectionRefusedError',
|
88 |
+
'ConnectionResetError',
|
89 |
+
'FileExistsError',
|
90 |
+
'FileNotFoundError',
|
91 |
+
'InterruptedError',
|
92 |
+
'IsADirectoryError',
|
93 |
+
'ModuleNotFoundError',
|
94 |
+
'NotADirectoryError',
|
95 |
+
'PermissionError',
|
96 |
+
'ProcessLookupError',
|
97 |
+
'RecursionError',
|
98 |
+
'ResourceWarning',
|
99 |
+
#'StopAsyncIteration', # backported
|
100 |
+
'TimeoutError',
|
101 |
+
'__build_class__',
|
102 |
+
'ascii', # might deserve an implementation in Cython
|
103 |
+
#'exec', # implemented in Cython
|
104 |
+
## - Py2.7+
|
105 |
+
'memoryview',
|
106 |
+
## - platform specific
|
107 |
+
'WindowsError',
|
108 |
+
## - others
|
109 |
+
'_', # e.g. used by gettext
|
110 |
+
]
|
111 |
+
|
112 |
+
special_py_methods = set([
|
113 |
+
'__cinit__', '__dealloc__', '__richcmp__', '__next__',
|
114 |
+
'__await__', '__aiter__', '__anext__',
|
115 |
+
'__getreadbuffer__', '__getwritebuffer__', '__getsegcount__',
|
116 |
+
'__getcharbuffer__', '__getbuffer__', '__releasebuffer__'
|
117 |
+
])
|
118 |
+
|
119 |
+
modifier_output_mapper = {
|
120 |
+
'inline': 'CYTHON_INLINE'
|
121 |
+
}.get
|
122 |
+
|
123 |
+
|
124 |
+
class IncludeCode(object):
|
125 |
+
"""
|
126 |
+
An include file and/or verbatim C code to be included in the
|
127 |
+
generated sources.
|
128 |
+
"""
|
129 |
+
# attributes:
|
130 |
+
#
|
131 |
+
# pieces {order: unicode}: pieces of C code to be generated.
|
132 |
+
# For the included file, the key "order" is zero.
|
133 |
+
# For verbatim include code, the "order" is the "order"
|
134 |
+
# attribute of the original IncludeCode where this piece
|
135 |
+
# of C code was first added. This is needed to prevent
|
136 |
+
# duplication if the same include code is found through
|
137 |
+
# multiple cimports.
|
138 |
+
# location int: where to put this include in the C sources, one
|
139 |
+
# of the constants INITIAL, EARLY, LATE
|
140 |
+
# order int: sorting order (automatically set by increasing counter)
|
141 |
+
|
142 |
+
# Constants for location. If the same include occurs with different
|
143 |
+
# locations, the earliest one takes precedense.
|
144 |
+
INITIAL = 0
|
145 |
+
EARLY = 1
|
146 |
+
LATE = 2
|
147 |
+
|
148 |
+
counter = 1 # Counter for "order"
|
149 |
+
|
150 |
+
def __init__(self, include=None, verbatim=None, late=True, initial=False):
|
151 |
+
self.order = self.counter
|
152 |
+
type(self).counter += 1
|
153 |
+
self.pieces = {}
|
154 |
+
|
155 |
+
if include:
|
156 |
+
if include[0] == '<' and include[-1] == '>':
|
157 |
+
self.pieces[0] = u'#include {0}'.format(include)
|
158 |
+
late = False # system include is never late
|
159 |
+
else:
|
160 |
+
self.pieces[0] = u'#include "{0}"'.format(include)
|
161 |
+
|
162 |
+
if verbatim:
|
163 |
+
self.pieces[self.order] = verbatim
|
164 |
+
|
165 |
+
if initial:
|
166 |
+
self.location = self.INITIAL
|
167 |
+
elif late:
|
168 |
+
self.location = self.LATE
|
169 |
+
else:
|
170 |
+
self.location = self.EARLY
|
171 |
+
|
172 |
+
def dict_update(self, d, key):
|
173 |
+
"""
|
174 |
+
Insert `self` in dict `d` with key `key`. If that key already
|
175 |
+
exists, update the attributes of the existing value with `self`.
|
176 |
+
"""
|
177 |
+
if key in d:
|
178 |
+
other = d[key]
|
179 |
+
other.location = min(self.location, other.location)
|
180 |
+
other.pieces.update(self.pieces)
|
181 |
+
else:
|
182 |
+
d[key] = self
|
183 |
+
|
184 |
+
def sortkey(self):
|
185 |
+
return self.order
|
186 |
+
|
187 |
+
def mainpiece(self):
|
188 |
+
"""
|
189 |
+
Return the main piece of C code, corresponding to the include
|
190 |
+
file. If there was no include file, return None.
|
191 |
+
"""
|
192 |
+
return self.pieces.get(0)
|
193 |
+
|
194 |
+
def write(self, code):
|
195 |
+
# Write values of self.pieces dict, sorted by the keys
|
196 |
+
for k in sorted(self.pieces):
|
197 |
+
code.putln(self.pieces[k])
|
198 |
+
|
199 |
+
|
200 |
+
def get_utility_dir():
|
201 |
+
# make this a function and not global variables:
|
202 |
+
# http://trac.cython.org/cython_trac/ticket/475
|
203 |
+
Cython_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
204 |
+
return os.path.join(Cython_dir, "Utility")
|
205 |
+
|
206 |
+
|
207 |
+
class UtilityCodeBase(object):
|
208 |
+
"""
|
209 |
+
Support for loading utility code from a file.
|
210 |
+
|
211 |
+
Code sections in the file can be specified as follows:
|
212 |
+
|
213 |
+
##### MyUtility.proto #####
|
214 |
+
|
215 |
+
[proto declarations]
|
216 |
+
|
217 |
+
##### MyUtility.init #####
|
218 |
+
|
219 |
+
[code run at module initialization]
|
220 |
+
|
221 |
+
##### MyUtility #####
|
222 |
+
#@requires: MyOtherUtility
|
223 |
+
#@substitute: naming
|
224 |
+
|
225 |
+
[definitions]
|
226 |
+
|
227 |
+
for prototypes and implementation respectively. For non-python or
|
228 |
+
-cython files backslashes should be used instead. 5 to 30 comment
|
229 |
+
characters may be used on either side.
|
230 |
+
|
231 |
+
If the @cname decorator is not used and this is a CythonUtilityCode,
|
232 |
+
one should pass in the 'name' keyword argument to be used for name
|
233 |
+
mangling of such entries.
|
234 |
+
"""
|
235 |
+
|
236 |
+
is_cython_utility = False
|
237 |
+
_utility_cache = {}
|
238 |
+
|
239 |
+
@classmethod
|
240 |
+
def _add_utility(cls, utility, type, lines, begin_lineno, tags=None):
|
241 |
+
if utility is None:
|
242 |
+
return
|
243 |
+
|
244 |
+
code = '\n'.join(lines)
|
245 |
+
if tags and 'substitute' in tags and tags['substitute'] == set(['naming']):
|
246 |
+
del tags['substitute']
|
247 |
+
try:
|
248 |
+
code = Template(code).substitute(vars(Naming))
|
249 |
+
except (KeyError, ValueError) as e:
|
250 |
+
raise RuntimeError("Error parsing templated utility code of type '%s' at line %d: %s" % (
|
251 |
+
type, begin_lineno, e))
|
252 |
+
|
253 |
+
# remember correct line numbers at least until after templating
|
254 |
+
code = '\n' * begin_lineno + code
|
255 |
+
|
256 |
+
if type == 'proto':
|
257 |
+
utility[0] = code
|
258 |
+
elif type == 'impl':
|
259 |
+
utility[1] = code
|
260 |
+
else:
|
261 |
+
all_tags = utility[2]
|
262 |
+
if KEYWORDS_MUST_BE_BYTES:
|
263 |
+
type = type.encode('ASCII')
|
264 |
+
all_tags[type] = code
|
265 |
+
|
266 |
+
if tags:
|
267 |
+
all_tags = utility[2]
|
268 |
+
for name, values in tags.items():
|
269 |
+
if KEYWORDS_MUST_BE_BYTES:
|
270 |
+
name = name.encode('ASCII')
|
271 |
+
all_tags.setdefault(name, set()).update(values)
|
272 |
+
|
273 |
+
@classmethod
|
274 |
+
def load_utilities_from_file(cls, path):
|
275 |
+
utilities = cls._utility_cache.get(path)
|
276 |
+
if utilities:
|
277 |
+
return utilities
|
278 |
+
|
279 |
+
filename = os.path.join(get_utility_dir(), path)
|
280 |
+
_, ext = os.path.splitext(path)
|
281 |
+
if ext in ('.pyx', '.py', '.pxd', '.pxi'):
|
282 |
+
comment = '#'
|
283 |
+
strip_comments = partial(re.compile(r'^\s*#(?!\s*cython\s*:).*').sub, '')
|
284 |
+
rstrip = StringEncoding._unicode.rstrip
|
285 |
+
else:
|
286 |
+
comment = '/'
|
287 |
+
strip_comments = partial(re.compile(r'^\s*//.*|/\*[^*]*\*/').sub, '')
|
288 |
+
rstrip = partial(re.compile(r'\s+(\\?)$').sub, r'\1')
|
289 |
+
match_special = re.compile(
|
290 |
+
(r'^%(C)s{5,30}\s*(?P<name>(?:\w|\.)+)\s*%(C)s{5,30}|'
|
291 |
+
r'^%(C)s+@(?P<tag>\w+)\s*:\s*(?P<value>(?:\w|[.:])+)') %
|
292 |
+
{'C': comment}).match
|
293 |
+
match_type = re.compile(r'(.+)[.](proto(?:[.]\S+)?|impl|init|cleanup)$').match
|
294 |
+
|
295 |
+
with closing(Utils.open_source_file(filename, encoding='UTF-8')) as f:
|
296 |
+
all_lines = f.readlines()
|
297 |
+
|
298 |
+
utilities = defaultdict(lambda: [None, None, {}])
|
299 |
+
lines = []
|
300 |
+
tags = defaultdict(set)
|
301 |
+
utility = type = None
|
302 |
+
begin_lineno = 0
|
303 |
+
|
304 |
+
for lineno, line in enumerate(all_lines):
|
305 |
+
m = match_special(line)
|
306 |
+
if m:
|
307 |
+
if m.group('name'):
|
308 |
+
cls._add_utility(utility, type, lines, begin_lineno, tags)
|
309 |
+
|
310 |
+
begin_lineno = lineno + 1
|
311 |
+
del lines[:]
|
312 |
+
tags.clear()
|
313 |
+
|
314 |
+
name = m.group('name')
|
315 |
+
mtype = match_type(name)
|
316 |
+
if mtype:
|
317 |
+
name, type = mtype.groups()
|
318 |
+
else:
|
319 |
+
type = 'impl'
|
320 |
+
utility = utilities[name]
|
321 |
+
else:
|
322 |
+
tags[m.group('tag')].add(m.group('value'))
|
323 |
+
lines.append('') # keep line number correct
|
324 |
+
else:
|
325 |
+
lines.append(rstrip(strip_comments(line)))
|
326 |
+
|
327 |
+
if utility is None:
|
328 |
+
raise ValueError("Empty utility code file")
|
329 |
+
|
330 |
+
# Don't forget to add the last utility code
|
331 |
+
cls._add_utility(utility, type, lines, begin_lineno, tags)
|
332 |
+
|
333 |
+
utilities = dict(utilities) # un-defaultdict-ify
|
334 |
+
cls._utility_cache[path] = utilities
|
335 |
+
return utilities
|
336 |
+
|
337 |
+
@classmethod
|
338 |
+
def load(cls, util_code_name, from_file=None, **kwargs):
|
339 |
+
"""
|
340 |
+
Load utility code from a file specified by from_file (relative to
|
341 |
+
Cython/Utility) and name util_code_name. If from_file is not given,
|
342 |
+
load it from the file util_code_name.*. There should be only one
|
343 |
+
file matched by this pattern.
|
344 |
+
"""
|
345 |
+
if '::' in util_code_name:
|
346 |
+
from_file, util_code_name = util_code_name.rsplit('::', 1)
|
347 |
+
if not from_file:
|
348 |
+
utility_dir = get_utility_dir()
|
349 |
+
prefix = util_code_name + '.'
|
350 |
+
try:
|
351 |
+
listing = os.listdir(utility_dir)
|
352 |
+
except OSError:
|
353 |
+
# XXX the code below assumes as 'zipimport.zipimporter' instance
|
354 |
+
# XXX should be easy to generalize, but too lazy right now to write it
|
355 |
+
import zipfile
|
356 |
+
global __loader__
|
357 |
+
loader = __loader__
|
358 |
+
archive = loader.archive
|
359 |
+
with closing(zipfile.ZipFile(archive)) as fileobj:
|
360 |
+
listing = [os.path.basename(name)
|
361 |
+
for name in fileobj.namelist()
|
362 |
+
if os.path.join(archive, name).startswith(utility_dir)]
|
363 |
+
files = [filename for filename in listing
|
364 |
+
if filename.startswith(prefix)]
|
365 |
+
if not files:
|
366 |
+
raise ValueError("No match found for utility code " + util_code_name)
|
367 |
+
if len(files) > 1:
|
368 |
+
raise ValueError("More than one filename match found for utility code " + util_code_name)
|
369 |
+
from_file = files[0]
|
370 |
+
|
371 |
+
utilities = cls.load_utilities_from_file(from_file)
|
372 |
+
proto, impl, tags = utilities[util_code_name]
|
373 |
+
|
374 |
+
if tags:
|
375 |
+
orig_kwargs = kwargs.copy()
|
376 |
+
for name, values in tags.items():
|
377 |
+
if name in kwargs:
|
378 |
+
continue
|
379 |
+
# only pass lists when we have to: most argument expect one value or None
|
380 |
+
if name == 'requires':
|
381 |
+
if orig_kwargs:
|
382 |
+
values = [cls.load(dep, from_file, **orig_kwargs)
|
383 |
+
for dep in sorted(values)]
|
384 |
+
else:
|
385 |
+
# dependencies are rarely unique, so use load_cached() when we can
|
386 |
+
values = [cls.load_cached(dep, from_file)
|
387 |
+
for dep in sorted(values)]
|
388 |
+
elif not values:
|
389 |
+
values = None
|
390 |
+
elif len(values) == 1:
|
391 |
+
values = list(values)[0]
|
392 |
+
kwargs[name] = values
|
393 |
+
|
394 |
+
if proto is not None:
|
395 |
+
kwargs['proto'] = proto
|
396 |
+
if impl is not None:
|
397 |
+
kwargs['impl'] = impl
|
398 |
+
|
399 |
+
if 'name' not in kwargs:
|
400 |
+
kwargs['name'] = util_code_name
|
401 |
+
|
402 |
+
if 'file' not in kwargs and from_file:
|
403 |
+
kwargs['file'] = from_file
|
404 |
+
return cls(**kwargs)
|
405 |
+
|
406 |
+
@classmethod
|
407 |
+
def load_cached(cls, utility_code_name, from_file=None, __cache={}):
|
408 |
+
"""
|
409 |
+
Calls .load(), but using a per-type cache based on utility name and file name.
|
410 |
+
"""
|
411 |
+
key = (cls, from_file, utility_code_name)
|
412 |
+
try:
|
413 |
+
return __cache[key]
|
414 |
+
except KeyError:
|
415 |
+
pass
|
416 |
+
code = __cache[key] = cls.load(utility_code_name, from_file)
|
417 |
+
return code
|
418 |
+
|
419 |
+
@classmethod
|
420 |
+
def load_as_string(cls, util_code_name, from_file=None, **kwargs):
|
421 |
+
"""
|
422 |
+
Load a utility code as a string. Returns (proto, implementation)
|
423 |
+
"""
|
424 |
+
util = cls.load(util_code_name, from_file, **kwargs)
|
425 |
+
proto, impl = util.proto, util.impl
|
426 |
+
return util.format_code(proto), util.format_code(impl)
|
427 |
+
|
428 |
+
def format_code(self, code_string, replace_empty_lines=re.compile(r'\n\n+').sub):
|
429 |
+
"""
|
430 |
+
Format a code section for output.
|
431 |
+
"""
|
432 |
+
if code_string:
|
433 |
+
code_string = replace_empty_lines('\n', code_string.strip()) + '\n\n'
|
434 |
+
return code_string
|
435 |
+
|
436 |
+
def __str__(self):
|
437 |
+
return "<%s(%s)>" % (type(self).__name__, self.name)
|
438 |
+
|
439 |
+
def get_tree(self, **kwargs):
|
440 |
+
pass
|
441 |
+
|
442 |
+
def __deepcopy__(self, memodict=None):
|
443 |
+
# No need to deep-copy utility code since it's essentially immutable.
|
444 |
+
return self
|
445 |
+
|
446 |
+
|
447 |
+
class UtilityCode(UtilityCodeBase):
|
448 |
+
"""
|
449 |
+
Stores utility code to add during code generation.
|
450 |
+
|
451 |
+
See GlobalState.put_utility_code.
|
452 |
+
|
453 |
+
hashes/equals by instance
|
454 |
+
|
455 |
+
proto C prototypes
|
456 |
+
impl implementation code
|
457 |
+
init code to call on module initialization
|
458 |
+
requires utility code dependencies
|
459 |
+
proto_block the place in the resulting file where the prototype should
|
460 |
+
end up
|
461 |
+
name name of the utility code (or None)
|
462 |
+
file filename of the utility code file this utility was loaded
|
463 |
+
from (or None)
|
464 |
+
"""
|
465 |
+
|
466 |
+
def __init__(self, proto=None, impl=None, init=None, cleanup=None, requires=None,
|
467 |
+
proto_block='utility_code_proto', name=None, file=None):
|
468 |
+
# proto_block: Which code block to dump prototype in. See GlobalState.
|
469 |
+
self.proto = proto
|
470 |
+
self.impl = impl
|
471 |
+
self.init = init
|
472 |
+
self.cleanup = cleanup
|
473 |
+
self.requires = requires
|
474 |
+
self._cache = {}
|
475 |
+
self.specialize_list = []
|
476 |
+
self.proto_block = proto_block
|
477 |
+
self.name = name
|
478 |
+
self.file = file
|
479 |
+
|
480 |
+
def __hash__(self):
|
481 |
+
return hash((self.proto, self.impl))
|
482 |
+
|
483 |
+
def __eq__(self, other):
|
484 |
+
if self is other:
|
485 |
+
return True
|
486 |
+
self_type, other_type = type(self), type(other)
|
487 |
+
if self_type is not other_type and not (isinstance(other, self_type) or isinstance(self, other_type)):
|
488 |
+
return False
|
489 |
+
|
490 |
+
self_proto = getattr(self, 'proto', None)
|
491 |
+
other_proto = getattr(other, 'proto', None)
|
492 |
+
return (self_proto, self.impl) == (other_proto, other.impl)
|
493 |
+
|
494 |
+
def none_or_sub(self, s, context):
|
495 |
+
"""
|
496 |
+
Format a string in this utility code with context. If None, do nothing.
|
497 |
+
"""
|
498 |
+
if s is None:
|
499 |
+
return None
|
500 |
+
return s % context
|
501 |
+
|
502 |
+
def specialize(self, pyrex_type=None, **data):
|
503 |
+
# Dicts aren't hashable...
|
504 |
+
name = self.name
|
505 |
+
if pyrex_type is not None:
|
506 |
+
data['type'] = pyrex_type.empty_declaration_code()
|
507 |
+
data['type_name'] = pyrex_type.specialization_name()
|
508 |
+
name = "%s[%s]" % (name, data['type_name'])
|
509 |
+
key = tuple(sorted(data.items()))
|
510 |
+
try:
|
511 |
+
return self._cache[key]
|
512 |
+
except KeyError:
|
513 |
+
if self.requires is None:
|
514 |
+
requires = None
|
515 |
+
else:
|
516 |
+
requires = [r.specialize(data) for r in self.requires]
|
517 |
+
|
518 |
+
s = self._cache[key] = UtilityCode(
|
519 |
+
self.none_or_sub(self.proto, data),
|
520 |
+
self.none_or_sub(self.impl, data),
|
521 |
+
self.none_or_sub(self.init, data),
|
522 |
+
self.none_or_sub(self.cleanup, data),
|
523 |
+
requires,
|
524 |
+
self.proto_block,
|
525 |
+
name,
|
526 |
+
)
|
527 |
+
|
528 |
+
self.specialize_list.append(s)
|
529 |
+
return s
|
530 |
+
|
531 |
+
def inject_string_constants(self, impl, output):
|
532 |
+
"""Replace 'PYIDENT("xyz")' by a constant Python identifier cname.
|
533 |
+
"""
|
534 |
+
if 'PYIDENT(' not in impl and 'PYUNICODE(' not in impl:
|
535 |
+
return False, impl
|
536 |
+
|
537 |
+
replacements = {}
|
538 |
+
def externalise(matchobj):
|
539 |
+
key = matchobj.groups()
|
540 |
+
try:
|
541 |
+
cname = replacements[key]
|
542 |
+
except KeyError:
|
543 |
+
str_type, name = key
|
544 |
+
cname = replacements[key] = output.get_py_string_const(
|
545 |
+
StringEncoding.EncodedString(name), identifier=str_type == 'IDENT').cname
|
546 |
+
return cname
|
547 |
+
|
548 |
+
impl = re.sub(r'PY(IDENT|UNICODE)\("([^"]+)"\)', externalise, impl)
|
549 |
+
assert 'PYIDENT(' not in impl and 'PYUNICODE(' not in impl
|
550 |
+
return True, impl
|
551 |
+
|
552 |
+
def inject_unbound_methods(self, impl, output):
|
553 |
+
"""Replace 'UNBOUND_METHOD(type, "name")' by a constant Python identifier cname.
|
554 |
+
"""
|
555 |
+
if 'CALL_UNBOUND_METHOD(' not in impl:
|
556 |
+
return False, impl
|
557 |
+
|
558 |
+
def externalise(matchobj):
|
559 |
+
type_cname, method_name, obj_cname, args = matchobj.groups()
|
560 |
+
args = [arg.strip() for arg in args[1:].split(',')] if args else []
|
561 |
+
assert len(args) < 3, "CALL_UNBOUND_METHOD() does not support %d call arguments" % len(args)
|
562 |
+
return output.cached_unbound_method_call_code(obj_cname, type_cname, method_name, args)
|
563 |
+
|
564 |
+
impl = re.sub(
|
565 |
+
r'CALL_UNBOUND_METHOD\('
|
566 |
+
r'([a-zA-Z_]+),' # type cname
|
567 |
+
r'\s*"([^"]+)",' # method name
|
568 |
+
r'\s*([^),]+)' # object cname
|
569 |
+
r'((?:,\s*[^),]+)*)' # args*
|
570 |
+
r'\)', externalise, impl)
|
571 |
+
assert 'CALL_UNBOUND_METHOD(' not in impl
|
572 |
+
|
573 |
+
return True, impl
|
574 |
+
|
575 |
+
def wrap_c_strings(self, impl):
|
576 |
+
"""Replace CSTRING('''xyz''') by a C compatible string
|
577 |
+
"""
|
578 |
+
if 'CSTRING(' not in impl:
|
579 |
+
return impl
|
580 |
+
|
581 |
+
def split_string(matchobj):
|
582 |
+
content = matchobj.group(1).replace('"', '\042')
|
583 |
+
return ''.join(
|
584 |
+
'"%s\\n"\n' % line if not line.endswith('\\') or line.endswith('\\\\') else '"%s"\n' % line[:-1]
|
585 |
+
for line in content.splitlines())
|
586 |
+
|
587 |
+
impl = re.sub(r'CSTRING\(\s*"""([^"]*(?:"[^"]+)*)"""\s*\)', split_string, impl)
|
588 |
+
assert 'CSTRING(' not in impl
|
589 |
+
return impl
|
590 |
+
|
591 |
+
def put_code(self, output):
|
592 |
+
if self.requires:
|
593 |
+
for dependency in self.requires:
|
594 |
+
output.use_utility_code(dependency)
|
595 |
+
if self.proto:
|
596 |
+
writer = output[self.proto_block]
|
597 |
+
writer.putln("/* %s.proto */" % self.name)
|
598 |
+
writer.put_or_include(
|
599 |
+
self.format_code(self.proto), '%s_proto' % self.name)
|
600 |
+
if self.impl:
|
601 |
+
impl = self.format_code(self.wrap_c_strings(self.impl))
|
602 |
+
is_specialised1, impl = self.inject_string_constants(impl, output)
|
603 |
+
is_specialised2, impl = self.inject_unbound_methods(impl, output)
|
604 |
+
writer = output['utility_code_def']
|
605 |
+
writer.putln("/* %s */" % self.name)
|
606 |
+
if not (is_specialised1 or is_specialised2):
|
607 |
+
# no module specific adaptations => can be reused
|
608 |
+
writer.put_or_include(impl, '%s_impl' % self.name)
|
609 |
+
else:
|
610 |
+
writer.put(impl)
|
611 |
+
if self.init:
|
612 |
+
writer = output['init_globals']
|
613 |
+
writer.putln("/* %s.init */" % self.name)
|
614 |
+
if isinstance(self.init, basestring):
|
615 |
+
writer.put(self.format_code(self.init))
|
616 |
+
else:
|
617 |
+
self.init(writer, output.module_pos)
|
618 |
+
writer.putln(writer.error_goto_if_PyErr(output.module_pos))
|
619 |
+
writer.putln()
|
620 |
+
if self.cleanup and Options.generate_cleanup_code:
|
621 |
+
writer = output['cleanup_globals']
|
622 |
+
writer.putln("/* %s.cleanup */" % self.name)
|
623 |
+
if isinstance(self.cleanup, basestring):
|
624 |
+
writer.put_or_include(
|
625 |
+
self.format_code(self.cleanup),
|
626 |
+
'%s_cleanup' % self.name)
|
627 |
+
else:
|
628 |
+
self.cleanup(writer, output.module_pos)
|
629 |
+
|
630 |
+
|
631 |
+
def sub_tempita(s, context, file=None, name=None):
|
632 |
+
"Run tempita on string s with given context."
|
633 |
+
if not s:
|
634 |
+
return None
|
635 |
+
|
636 |
+
if file:
|
637 |
+
context['__name'] = "%s:%s" % (file, name)
|
638 |
+
elif name:
|
639 |
+
context['__name'] = name
|
640 |
+
|
641 |
+
from ..Tempita import sub
|
642 |
+
return sub(s, **context)
|
643 |
+
|
644 |
+
|
645 |
+
class TempitaUtilityCode(UtilityCode):
|
646 |
+
def __init__(self, name=None, proto=None, impl=None, init=None, file=None, context=None, **kwargs):
|
647 |
+
if context is None:
|
648 |
+
context = {}
|
649 |
+
proto = sub_tempita(proto, context, file, name)
|
650 |
+
impl = sub_tempita(impl, context, file, name)
|
651 |
+
init = sub_tempita(init, context, file, name)
|
652 |
+
super(TempitaUtilityCode, self).__init__(
|
653 |
+
proto, impl, init=init, name=name, file=file, **kwargs)
|
654 |
+
|
655 |
+
@classmethod
|
656 |
+
def load_cached(cls, utility_code_name, from_file=None, context=None, __cache={}):
|
657 |
+
context_key = tuple(sorted(context.items())) if context else None
|
658 |
+
assert hash(context_key) is not None # raise TypeError if not hashable
|
659 |
+
key = (cls, from_file, utility_code_name, context_key)
|
660 |
+
try:
|
661 |
+
return __cache[key]
|
662 |
+
except KeyError:
|
663 |
+
pass
|
664 |
+
code = __cache[key] = cls.load(utility_code_name, from_file, context=context)
|
665 |
+
return code
|
666 |
+
|
667 |
+
def none_or_sub(self, s, context):
|
668 |
+
"""
|
669 |
+
Format a string in this utility code with context. If None, do nothing.
|
670 |
+
"""
|
671 |
+
if s is None:
|
672 |
+
return None
|
673 |
+
return sub_tempita(s, context, self.file, self.name)
|
674 |
+
|
675 |
+
|
676 |
+
class LazyUtilityCode(UtilityCodeBase):
|
677 |
+
"""
|
678 |
+
Utility code that calls a callback with the root code writer when
|
679 |
+
available. Useful when you only have 'env' but not 'code'.
|
680 |
+
"""
|
681 |
+
__name__ = '<lazy>'
|
682 |
+
requires = None
|
683 |
+
|
684 |
+
def __init__(self, callback):
|
685 |
+
self.callback = callback
|
686 |
+
|
687 |
+
def put_code(self, globalstate):
|
688 |
+
utility = self.callback(globalstate.rootwriter)
|
689 |
+
globalstate.use_utility_code(utility)
|
690 |
+
|
691 |
+
|
692 |
+
class FunctionState(object):
|
693 |
+
# return_label string function return point label
|
694 |
+
# error_label string error catch point label
|
695 |
+
# continue_label string loop continue point label
|
696 |
+
# break_label string loop break point label
|
697 |
+
# return_from_error_cleanup_label string
|
698 |
+
# label_counter integer counter for naming labels
|
699 |
+
# in_try_finally boolean inside try of try...finally
|
700 |
+
# exc_vars (string * 3) exception variables for reraise, or None
|
701 |
+
# can_trace boolean line tracing is supported in the current context
|
702 |
+
# scope Scope the scope object of the current function
|
703 |
+
|
704 |
+
# Not used for now, perhaps later
|
705 |
+
def __init__(self, owner, names_taken=set(), scope=None):
|
706 |
+
self.names_taken = names_taken
|
707 |
+
self.owner = owner
|
708 |
+
self.scope = scope
|
709 |
+
|
710 |
+
self.error_label = None
|
711 |
+
self.label_counter = 0
|
712 |
+
self.labels_used = set()
|
713 |
+
self.return_label = self.new_label()
|
714 |
+
self.new_error_label()
|
715 |
+
self.continue_label = None
|
716 |
+
self.break_label = None
|
717 |
+
self.yield_labels = []
|
718 |
+
|
719 |
+
self.in_try_finally = 0
|
720 |
+
self.exc_vars = None
|
721 |
+
self.current_except = None
|
722 |
+
self.can_trace = False
|
723 |
+
self.gil_owned = True
|
724 |
+
|
725 |
+
self.temps_allocated = [] # of (name, type, manage_ref, static)
|
726 |
+
self.temps_free = {} # (type, manage_ref) -> list of free vars with same type/managed status
|
727 |
+
self.temps_used_type = {} # name -> (type, manage_ref)
|
728 |
+
self.zombie_temps = set() # temps that must not be reused after release
|
729 |
+
self.temp_counter = 0
|
730 |
+
self.closure_temps = None
|
731 |
+
|
732 |
+
# This is used to collect temporaries, useful to find out which temps
|
733 |
+
# need to be privatized in parallel sections
|
734 |
+
self.collect_temps_stack = []
|
735 |
+
|
736 |
+
# This is used for the error indicator, which needs to be local to the
|
737 |
+
# function. It used to be global, which relies on the GIL being held.
|
738 |
+
# However, exceptions may need to be propagated through 'nogil'
|
739 |
+
# sections, in which case we introduce a race condition.
|
740 |
+
self.should_declare_error_indicator = False
|
741 |
+
self.uses_error_indicator = False
|
742 |
+
|
743 |
+
# safety checks
|
744 |
+
|
745 |
+
def validate_exit(self):
|
746 |
+
# validate that all allocated temps have been freed
|
747 |
+
if self.temps_allocated:
|
748 |
+
leftovers = self.temps_in_use()
|
749 |
+
if leftovers:
|
750 |
+
msg = "TEMPGUARD: Temps left over at end of '%s': %s" % (self.scope.name, ', '.join([
|
751 |
+
'%s [%s]' % (name, ctype)
|
752 |
+
for name, ctype, is_pytemp in sorted(leftovers)]),
|
753 |
+
)
|
754 |
+
#print(msg)
|
755 |
+
raise RuntimeError(msg)
|
756 |
+
|
757 |
+
# labels
|
758 |
+
|
759 |
+
def new_label(self, name=None):
|
760 |
+
n = self.label_counter
|
761 |
+
self.label_counter = n + 1
|
762 |
+
label = "%s%d" % (Naming.label_prefix, n)
|
763 |
+
if name is not None:
|
764 |
+
label += '_' + name
|
765 |
+
return label
|
766 |
+
|
767 |
+
def new_yield_label(self, expr_type='yield'):
|
768 |
+
label = self.new_label('resume_from_%s' % expr_type)
|
769 |
+
num_and_label = (len(self.yield_labels) + 1, label)
|
770 |
+
self.yield_labels.append(num_and_label)
|
771 |
+
return num_and_label
|
772 |
+
|
773 |
+
def new_error_label(self):
|
774 |
+
old_err_lbl = self.error_label
|
775 |
+
self.error_label = self.new_label('error')
|
776 |
+
return old_err_lbl
|
777 |
+
|
778 |
+
def get_loop_labels(self):
|
779 |
+
return (
|
780 |
+
self.continue_label,
|
781 |
+
self.break_label)
|
782 |
+
|
783 |
+
def set_loop_labels(self, labels):
|
784 |
+
(self.continue_label,
|
785 |
+
self.break_label) = labels
|
786 |
+
|
787 |
+
def new_loop_labels(self):
|
788 |
+
old_labels = self.get_loop_labels()
|
789 |
+
self.set_loop_labels(
|
790 |
+
(self.new_label("continue"),
|
791 |
+
self.new_label("break")))
|
792 |
+
return old_labels
|
793 |
+
|
794 |
+
def get_all_labels(self):
|
795 |
+
return (
|
796 |
+
self.continue_label,
|
797 |
+
self.break_label,
|
798 |
+
self.return_label,
|
799 |
+
self.error_label)
|
800 |
+
|
801 |
+
def set_all_labels(self, labels):
|
802 |
+
(self.continue_label,
|
803 |
+
self.break_label,
|
804 |
+
self.return_label,
|
805 |
+
self.error_label) = labels
|
806 |
+
|
807 |
+
def all_new_labels(self):
|
808 |
+
old_labels = self.get_all_labels()
|
809 |
+
new_labels = []
|
810 |
+
for old_label, name in zip(old_labels, ['continue', 'break', 'return', 'error']):
|
811 |
+
if old_label:
|
812 |
+
new_labels.append(self.new_label(name))
|
813 |
+
else:
|
814 |
+
new_labels.append(old_label)
|
815 |
+
self.set_all_labels(new_labels)
|
816 |
+
return old_labels
|
817 |
+
|
818 |
+
def use_label(self, lbl):
|
819 |
+
self.labels_used.add(lbl)
|
820 |
+
|
821 |
+
def label_used(self, lbl):
|
822 |
+
return lbl in self.labels_used
|
823 |
+
|
824 |
+
# temp handling
|
825 |
+
|
826 |
+
def allocate_temp(self, type, manage_ref, static=False, reusable=True):
|
827 |
+
"""
|
828 |
+
Allocates a temporary (which may create a new one or get a previously
|
829 |
+
allocated and released one of the same type). Type is simply registered
|
830 |
+
and handed back, but will usually be a PyrexType.
|
831 |
+
|
832 |
+
If type.is_pyobject, manage_ref comes into play. If manage_ref is set to
|
833 |
+
True, the temp will be decref-ed on return statements and in exception
|
834 |
+
handling clauses. Otherwise the caller has to deal with any reference
|
835 |
+
counting of the variable.
|
836 |
+
|
837 |
+
If not type.is_pyobject, then manage_ref will be ignored, but it
|
838 |
+
still has to be passed. It is recommended to pass False by convention
|
839 |
+
if it is known that type will never be a Python object.
|
840 |
+
|
841 |
+
static=True marks the temporary declaration with "static".
|
842 |
+
This is only used when allocating backing store for a module-level
|
843 |
+
C array literals.
|
844 |
+
|
845 |
+
if reusable=False, the temp will not be reused after release.
|
846 |
+
|
847 |
+
A C string referring to the variable is returned.
|
848 |
+
"""
|
849 |
+
if type.is_const and not type.is_reference:
|
850 |
+
type = type.const_base_type
|
851 |
+
elif type.is_reference and not type.is_fake_reference:
|
852 |
+
type = type.ref_base_type
|
853 |
+
elif type.is_cfunction:
|
854 |
+
from . import PyrexTypes
|
855 |
+
type = PyrexTypes.c_ptr_type(type) # A function itself isn't an l-value
|
856 |
+
if not type.is_pyobject and not type.is_memoryviewslice:
|
857 |
+
# Make manage_ref canonical, so that manage_ref will always mean
|
858 |
+
# a decref is needed.
|
859 |
+
manage_ref = False
|
860 |
+
|
861 |
+
freelist = self.temps_free.get((type, manage_ref))
|
862 |
+
if reusable and freelist is not None and freelist[0]:
|
863 |
+
result = freelist[0].pop()
|
864 |
+
freelist[1].remove(result)
|
865 |
+
else:
|
866 |
+
while True:
|
867 |
+
self.temp_counter += 1
|
868 |
+
result = "%s%d" % (Naming.codewriter_temp_prefix, self.temp_counter)
|
869 |
+
if result not in self.names_taken: break
|
870 |
+
self.temps_allocated.append((result, type, manage_ref, static))
|
871 |
+
if not reusable:
|
872 |
+
self.zombie_temps.add(result)
|
873 |
+
self.temps_used_type[result] = (type, manage_ref)
|
874 |
+
if DebugFlags.debug_temp_code_comments:
|
875 |
+
self.owner.putln("/* %s allocated (%s)%s */" % (result, type, "" if reusable else " - zombie"))
|
876 |
+
|
877 |
+
if self.collect_temps_stack:
|
878 |
+
self.collect_temps_stack[-1].add((result, type))
|
879 |
+
|
880 |
+
return result
|
881 |
+
|
882 |
+
def release_temp(self, name):
|
883 |
+
"""
|
884 |
+
Releases a temporary so that it can be reused by other code needing
|
885 |
+
a temp of the same type.
|
886 |
+
"""
|
887 |
+
type, manage_ref = self.temps_used_type[name]
|
888 |
+
freelist = self.temps_free.get((type, manage_ref))
|
889 |
+
if freelist is None:
|
890 |
+
freelist = ([], set()) # keep order in list and make lookups in set fast
|
891 |
+
self.temps_free[(type, manage_ref)] = freelist
|
892 |
+
if name in freelist[1]:
|
893 |
+
raise RuntimeError("Temp %s freed twice!" % name)
|
894 |
+
if name not in self.zombie_temps:
|
895 |
+
freelist[0].append(name)
|
896 |
+
freelist[1].add(name)
|
897 |
+
if DebugFlags.debug_temp_code_comments:
|
898 |
+
self.owner.putln("/* %s released %s*/" % (
|
899 |
+
name, " - zombie" if name in self.zombie_temps else ""))
|
900 |
+
|
901 |
+
def temps_in_use(self):
|
902 |
+
"""Return a list of (cname,type,manage_ref) tuples of temp names and their type
|
903 |
+
that are currently in use.
|
904 |
+
"""
|
905 |
+
used = []
|
906 |
+
for name, type, manage_ref, static in self.temps_allocated:
|
907 |
+
freelist = self.temps_free.get((type, manage_ref))
|
908 |
+
if freelist is None or name not in freelist[1]:
|
909 |
+
used.append((name, type, manage_ref and type.is_pyobject))
|
910 |
+
return used
|
911 |
+
|
912 |
+
def temps_holding_reference(self):
|
913 |
+
"""Return a list of (cname,type) tuples of temp names and their type
|
914 |
+
that are currently in use. This includes only temps of a
|
915 |
+
Python object type which owns its reference.
|
916 |
+
"""
|
917 |
+
return [(name, type)
|
918 |
+
for name, type, manage_ref in self.temps_in_use()
|
919 |
+
if manage_ref and type.is_pyobject]
|
920 |
+
|
921 |
+
def all_managed_temps(self):
|
922 |
+
"""Return a list of (cname, type) tuples of refcount-managed Python objects.
|
923 |
+
"""
|
924 |
+
return [(cname, type)
|
925 |
+
for cname, type, manage_ref, static in self.temps_allocated
|
926 |
+
if manage_ref]
|
927 |
+
|
928 |
+
def all_free_managed_temps(self):
|
929 |
+
"""Return a list of (cname, type) tuples of refcount-managed Python
|
930 |
+
objects that are not currently in use. This is used by
|
931 |
+
try-except and try-finally blocks to clean up temps in the
|
932 |
+
error case.
|
933 |
+
"""
|
934 |
+
return sorted([ # Enforce deterministic order.
|
935 |
+
(cname, type)
|
936 |
+
for (type, manage_ref), freelist in self.temps_free.items() if manage_ref
|
937 |
+
for cname in freelist[0]
|
938 |
+
])
|
939 |
+
|
940 |
+
def start_collecting_temps(self):
|
941 |
+
"""
|
942 |
+
Useful to find out which temps were used in a code block
|
943 |
+
"""
|
944 |
+
self.collect_temps_stack.append(set())
|
945 |
+
|
946 |
+
def stop_collecting_temps(self):
|
947 |
+
return self.collect_temps_stack.pop()
|
948 |
+
|
949 |
+
def init_closure_temps(self, scope):
|
950 |
+
self.closure_temps = ClosureTempAllocator(scope)
|
951 |
+
|
952 |
+
|
953 |
+
class NumConst(object):
|
954 |
+
"""Global info about a Python number constant held by GlobalState.
|
955 |
+
|
956 |
+
cname string
|
957 |
+
value string
|
958 |
+
py_type string int, long, float
|
959 |
+
value_code string evaluation code if different from value
|
960 |
+
"""
|
961 |
+
|
962 |
+
def __init__(self, cname, value, py_type, value_code=None):
|
963 |
+
self.cname = cname
|
964 |
+
self.value = value
|
965 |
+
self.py_type = py_type
|
966 |
+
self.value_code = value_code or value
|
967 |
+
|
968 |
+
|
969 |
+
class PyObjectConst(object):
|
970 |
+
"""Global info about a generic constant held by GlobalState.
|
971 |
+
"""
|
972 |
+
# cname string
|
973 |
+
# type PyrexType
|
974 |
+
|
975 |
+
def __init__(self, cname, type):
|
976 |
+
self.cname = cname
|
977 |
+
self.type = type
|
978 |
+
|
979 |
+
|
980 |
+
cython.declare(possible_unicode_identifier=object, possible_bytes_identifier=object,
|
981 |
+
replace_identifier=object, find_alphanums=object)
|
982 |
+
possible_unicode_identifier = re.compile(br"(?![0-9])\w+$".decode('ascii'), re.U).match
|
983 |
+
possible_bytes_identifier = re.compile(r"(?![0-9])\w+$".encode('ASCII')).match
|
984 |
+
replace_identifier = re.compile(r'[^a-zA-Z0-9_]+').sub
|
985 |
+
find_alphanums = re.compile('([a-zA-Z0-9]+)').findall
|
986 |
+
|
987 |
+
class StringConst(object):
|
988 |
+
"""Global info about a C string constant held by GlobalState.
|
989 |
+
"""
|
990 |
+
# cname string
|
991 |
+
# text EncodedString or BytesLiteral
|
992 |
+
# py_strings {(identifier, encoding) : PyStringConst}
|
993 |
+
|
994 |
+
def __init__(self, cname, text, byte_string):
|
995 |
+
self.cname = cname
|
996 |
+
self.text = text
|
997 |
+
self.escaped_value = StringEncoding.escape_byte_string(byte_string)
|
998 |
+
self.py_strings = None
|
999 |
+
self.py_versions = []
|
1000 |
+
|
1001 |
+
def add_py_version(self, version):
|
1002 |
+
if not version:
|
1003 |
+
self.py_versions = [2, 3]
|
1004 |
+
elif version not in self.py_versions:
|
1005 |
+
self.py_versions.append(version)
|
1006 |
+
|
1007 |
+
def get_py_string_const(self, encoding, identifier=None,
|
1008 |
+
is_str=False, py3str_cstring=None):
|
1009 |
+
py_strings = self.py_strings
|
1010 |
+
text = self.text
|
1011 |
+
|
1012 |
+
is_str = bool(identifier or is_str)
|
1013 |
+
is_unicode = encoding is None and not is_str
|
1014 |
+
|
1015 |
+
if encoding is None:
|
1016 |
+
# unicode string
|
1017 |
+
encoding_key = None
|
1018 |
+
else:
|
1019 |
+
# bytes or str
|
1020 |
+
encoding = encoding.lower()
|
1021 |
+
if encoding in ('utf8', 'utf-8', 'ascii', 'usascii', 'us-ascii'):
|
1022 |
+
encoding = None
|
1023 |
+
encoding_key = None
|
1024 |
+
else:
|
1025 |
+
encoding_key = ''.join(find_alphanums(encoding))
|
1026 |
+
|
1027 |
+
key = (is_str, is_unicode, encoding_key, py3str_cstring)
|
1028 |
+
if py_strings is not None:
|
1029 |
+
try:
|
1030 |
+
return py_strings[key]
|
1031 |
+
except KeyError:
|
1032 |
+
pass
|
1033 |
+
else:
|
1034 |
+
self.py_strings = {}
|
1035 |
+
|
1036 |
+
if identifier:
|
1037 |
+
intern = True
|
1038 |
+
elif identifier is None:
|
1039 |
+
if isinstance(text, bytes):
|
1040 |
+
intern = bool(possible_bytes_identifier(text))
|
1041 |
+
else:
|
1042 |
+
intern = bool(possible_unicode_identifier(text))
|
1043 |
+
else:
|
1044 |
+
intern = False
|
1045 |
+
if intern:
|
1046 |
+
prefix = Naming.interned_prefixes['str']
|
1047 |
+
else:
|
1048 |
+
prefix = Naming.py_const_prefix
|
1049 |
+
|
1050 |
+
if encoding_key:
|
1051 |
+
encoding_prefix = '_%s' % encoding_key
|
1052 |
+
else:
|
1053 |
+
encoding_prefix = ''
|
1054 |
+
|
1055 |
+
pystring_cname = "%s%s%s_%s" % (
|
1056 |
+
prefix,
|
1057 |
+
(is_str and 's') or (is_unicode and 'u') or 'b',
|
1058 |
+
encoding_prefix,
|
1059 |
+
self.cname[len(Naming.const_prefix):])
|
1060 |
+
|
1061 |
+
py_string = PyStringConst(
|
1062 |
+
pystring_cname, encoding, is_unicode, is_str, py3str_cstring, intern)
|
1063 |
+
self.py_strings[key] = py_string
|
1064 |
+
return py_string
|
1065 |
+
|
1066 |
+
class PyStringConst(object):
|
1067 |
+
"""Global info about a Python string constant held by GlobalState.
|
1068 |
+
"""
|
1069 |
+
# cname string
|
1070 |
+
# py3str_cstring string
|
1071 |
+
# encoding string
|
1072 |
+
# intern boolean
|
1073 |
+
# is_unicode boolean
|
1074 |
+
# is_str boolean
|
1075 |
+
|
1076 |
+
def __init__(self, cname, encoding, is_unicode, is_str=False,
|
1077 |
+
py3str_cstring=None, intern=False):
|
1078 |
+
self.cname = cname
|
1079 |
+
self.py3str_cstring = py3str_cstring
|
1080 |
+
self.encoding = encoding
|
1081 |
+
self.is_str = is_str
|
1082 |
+
self.is_unicode = is_unicode
|
1083 |
+
self.intern = intern
|
1084 |
+
|
1085 |
+
def __lt__(self, other):
|
1086 |
+
return self.cname < other.cname
|
1087 |
+
|
1088 |
+
|
1089 |
+
class GlobalState(object):
|
1090 |
+
# filename_table {string : int} for finding filename table indexes
|
1091 |
+
# filename_list [string] filenames in filename table order
|
1092 |
+
# input_file_contents dict contents (=list of lines) of any file that was used as input
|
1093 |
+
# to create this output C code. This is
|
1094 |
+
# used to annotate the comments.
|
1095 |
+
#
|
1096 |
+
# utility_codes set IDs of used utility code (to avoid reinsertion)
|
1097 |
+
#
|
1098 |
+
# declared_cnames {string:Entry} used in a transition phase to merge pxd-declared
|
1099 |
+
# constants etc. into the pyx-declared ones (i.e,
|
1100 |
+
# check if constants are already added).
|
1101 |
+
# In time, hopefully the literals etc. will be
|
1102 |
+
# supplied directly instead.
|
1103 |
+
#
|
1104 |
+
# const_cnames_used dict global counter for unique constant identifiers
|
1105 |
+
#
|
1106 |
+
|
1107 |
+
# parts {string:CCodeWriter}
|
1108 |
+
|
1109 |
+
|
1110 |
+
# interned_strings
|
1111 |
+
# consts
|
1112 |
+
# interned_nums
|
1113 |
+
|
1114 |
+
# directives set Temporary variable used to track
|
1115 |
+
# the current set of directives in the code generation
|
1116 |
+
# process.
|
1117 |
+
|
1118 |
+
directives = {}
|
1119 |
+
|
1120 |
+
code_layout = [
|
1121 |
+
'h_code',
|
1122 |
+
'filename_table',
|
1123 |
+
'utility_code_proto_before_types',
|
1124 |
+
'numeric_typedefs', # Let these detailed individual parts stay!,
|
1125 |
+
'complex_type_declarations', # as the proper solution is to make a full DAG...
|
1126 |
+
'type_declarations', # More coarse-grained blocks would simply hide
|
1127 |
+
'utility_code_proto', # the ugliness, not fix it
|
1128 |
+
'module_declarations',
|
1129 |
+
'typeinfo',
|
1130 |
+
'before_global_var',
|
1131 |
+
'global_var',
|
1132 |
+
'string_decls',
|
1133 |
+
'decls',
|
1134 |
+
'late_includes',
|
1135 |
+
'all_the_rest',
|
1136 |
+
'pystring_table',
|
1137 |
+
'cached_builtins',
|
1138 |
+
'cached_constants',
|
1139 |
+
'init_globals',
|
1140 |
+
'init_module',
|
1141 |
+
'cleanup_globals',
|
1142 |
+
'cleanup_module',
|
1143 |
+
'main_method',
|
1144 |
+
'utility_code_def',
|
1145 |
+
'end'
|
1146 |
+
]
|
1147 |
+
|
1148 |
+
|
1149 |
+
def __init__(self, writer, module_node, code_config, common_utility_include_dir=None):
|
1150 |
+
self.filename_table = {}
|
1151 |
+
self.filename_list = []
|
1152 |
+
self.input_file_contents = {}
|
1153 |
+
self.utility_codes = set()
|
1154 |
+
self.declared_cnames = {}
|
1155 |
+
self.in_utility_code_generation = False
|
1156 |
+
self.code_config = code_config
|
1157 |
+
self.common_utility_include_dir = common_utility_include_dir
|
1158 |
+
self.parts = {}
|
1159 |
+
self.module_node = module_node # because some utility code generation needs it
|
1160 |
+
# (generating backwards-compatible Get/ReleaseBuffer
|
1161 |
+
|
1162 |
+
self.const_cnames_used = {}
|
1163 |
+
self.string_const_index = {}
|
1164 |
+
self.dedup_const_index = {}
|
1165 |
+
self.pyunicode_ptr_const_index = {}
|
1166 |
+
self.num_const_index = {}
|
1167 |
+
self.py_constants = []
|
1168 |
+
self.cached_cmethods = {}
|
1169 |
+
self.initialised_constants = set()
|
1170 |
+
|
1171 |
+
writer.set_global_state(self)
|
1172 |
+
self.rootwriter = writer
|
1173 |
+
|
1174 |
+
def initialize_main_c_code(self):
|
1175 |
+
rootwriter = self.rootwriter
|
1176 |
+
for part in self.code_layout:
|
1177 |
+
self.parts[part] = rootwriter.insertion_point()
|
1178 |
+
|
1179 |
+
if not Options.cache_builtins:
|
1180 |
+
del self.parts['cached_builtins']
|
1181 |
+
else:
|
1182 |
+
w = self.parts['cached_builtins']
|
1183 |
+
w.enter_cfunc_scope()
|
1184 |
+
w.putln("static CYTHON_SMALL_CODE int __Pyx_InitCachedBuiltins(void) {")
|
1185 |
+
|
1186 |
+
w = self.parts['cached_constants']
|
1187 |
+
w.enter_cfunc_scope()
|
1188 |
+
w.putln("")
|
1189 |
+
w.putln("static CYTHON_SMALL_CODE int __Pyx_InitCachedConstants(void) {")
|
1190 |
+
w.put_declare_refcount_context()
|
1191 |
+
w.put_setup_refcount_context("__Pyx_InitCachedConstants")
|
1192 |
+
|
1193 |
+
w = self.parts['init_globals']
|
1194 |
+
w.enter_cfunc_scope()
|
1195 |
+
w.putln("")
|
1196 |
+
w.putln("static CYTHON_SMALL_CODE int __Pyx_InitGlobals(void) {")
|
1197 |
+
|
1198 |
+
if not Options.generate_cleanup_code:
|
1199 |
+
del self.parts['cleanup_globals']
|
1200 |
+
else:
|
1201 |
+
w = self.parts['cleanup_globals']
|
1202 |
+
w.enter_cfunc_scope()
|
1203 |
+
w.putln("")
|
1204 |
+
w.putln("static CYTHON_SMALL_CODE void __Pyx_CleanupGlobals(void) {")
|
1205 |
+
|
1206 |
+
code = self.parts['utility_code_proto']
|
1207 |
+
code.putln("")
|
1208 |
+
code.putln("/* --- Runtime support code (head) --- */")
|
1209 |
+
|
1210 |
+
code = self.parts['utility_code_def']
|
1211 |
+
if self.code_config.emit_linenums:
|
1212 |
+
code.write('\n#line 1 "cython_utility"\n')
|
1213 |
+
code.putln("")
|
1214 |
+
code.putln("/* --- Runtime support code --- */")
|
1215 |
+
|
1216 |
+
def finalize_main_c_code(self):
|
1217 |
+
self.close_global_decls()
|
1218 |
+
|
1219 |
+
#
|
1220 |
+
# utility_code_def
|
1221 |
+
#
|
1222 |
+
code = self.parts['utility_code_def']
|
1223 |
+
util = TempitaUtilityCode.load_cached("TypeConversions", "TypeConversion.c")
|
1224 |
+
code.put(util.format_code(util.impl))
|
1225 |
+
code.putln("")
|
1226 |
+
|
1227 |
+
def __getitem__(self, key):
|
1228 |
+
return self.parts[key]
|
1229 |
+
|
1230 |
+
#
|
1231 |
+
# Global constants, interned objects, etc.
|
1232 |
+
#
|
1233 |
+
def close_global_decls(self):
|
1234 |
+
# This is called when it is known that no more global declarations will
|
1235 |
+
# declared.
|
1236 |
+
self.generate_const_declarations()
|
1237 |
+
if Options.cache_builtins:
|
1238 |
+
w = self.parts['cached_builtins']
|
1239 |
+
w.putln("return 0;")
|
1240 |
+
if w.label_used(w.error_label):
|
1241 |
+
w.put_label(w.error_label)
|
1242 |
+
w.putln("return -1;")
|
1243 |
+
w.putln("}")
|
1244 |
+
w.exit_cfunc_scope()
|
1245 |
+
|
1246 |
+
w = self.parts['cached_constants']
|
1247 |
+
w.put_finish_refcount_context()
|
1248 |
+
w.putln("return 0;")
|
1249 |
+
if w.label_used(w.error_label):
|
1250 |
+
w.put_label(w.error_label)
|
1251 |
+
w.put_finish_refcount_context()
|
1252 |
+
w.putln("return -1;")
|
1253 |
+
w.putln("}")
|
1254 |
+
w.exit_cfunc_scope()
|
1255 |
+
|
1256 |
+
w = self.parts['init_globals']
|
1257 |
+
w.putln("return 0;")
|
1258 |
+
if w.label_used(w.error_label):
|
1259 |
+
w.put_label(w.error_label)
|
1260 |
+
w.putln("return -1;")
|
1261 |
+
w.putln("}")
|
1262 |
+
w.exit_cfunc_scope()
|
1263 |
+
|
1264 |
+
if Options.generate_cleanup_code:
|
1265 |
+
w = self.parts['cleanup_globals']
|
1266 |
+
w.putln("}")
|
1267 |
+
w.exit_cfunc_scope()
|
1268 |
+
|
1269 |
+
if Options.generate_cleanup_code:
|
1270 |
+
w = self.parts['cleanup_module']
|
1271 |
+
w.putln("}")
|
1272 |
+
w.exit_cfunc_scope()
|
1273 |
+
|
1274 |
+
def put_pyobject_decl(self, entry):
|
1275 |
+
self['global_var'].putln("static PyObject *%s;" % entry.cname)
|
1276 |
+
|
1277 |
+
# constant handling at code generation time
|
1278 |
+
|
1279 |
+
def get_cached_constants_writer(self, target=None):
|
1280 |
+
if target is not None:
|
1281 |
+
if target in self.initialised_constants:
|
1282 |
+
# Return None on second/later calls to prevent duplicate creation code.
|
1283 |
+
return None
|
1284 |
+
self.initialised_constants.add(target)
|
1285 |
+
return self.parts['cached_constants']
|
1286 |
+
|
1287 |
+
def get_int_const(self, str_value, longness=False):
|
1288 |
+
py_type = longness and 'long' or 'int'
|
1289 |
+
try:
|
1290 |
+
c = self.num_const_index[(str_value, py_type)]
|
1291 |
+
except KeyError:
|
1292 |
+
c = self.new_num_const(str_value, py_type)
|
1293 |
+
return c
|
1294 |
+
|
1295 |
+
def get_float_const(self, str_value, value_code):
|
1296 |
+
try:
|
1297 |
+
c = self.num_const_index[(str_value, 'float')]
|
1298 |
+
except KeyError:
|
1299 |
+
c = self.new_num_const(str_value, 'float', value_code)
|
1300 |
+
return c
|
1301 |
+
|
1302 |
+
def get_py_const(self, type, prefix='', cleanup_level=None, dedup_key=None):
|
1303 |
+
if dedup_key is not None:
|
1304 |
+
const = self.dedup_const_index.get(dedup_key)
|
1305 |
+
if const is not None:
|
1306 |
+
return const
|
1307 |
+
# create a new Python object constant
|
1308 |
+
const = self.new_py_const(type, prefix)
|
1309 |
+
if cleanup_level is not None \
|
1310 |
+
and cleanup_level <= Options.generate_cleanup_code:
|
1311 |
+
cleanup_writer = self.parts['cleanup_globals']
|
1312 |
+
cleanup_writer.putln('Py_CLEAR(%s);' % const.cname)
|
1313 |
+
if dedup_key is not None:
|
1314 |
+
self.dedup_const_index[dedup_key] = const
|
1315 |
+
return const
|
1316 |
+
|
1317 |
+
def get_string_const(self, text, py_version=None):
|
1318 |
+
# return a C string constant, creating a new one if necessary
|
1319 |
+
if text.is_unicode:
|
1320 |
+
byte_string = text.utf8encode()
|
1321 |
+
else:
|
1322 |
+
byte_string = text.byteencode()
|
1323 |
+
try:
|
1324 |
+
c = self.string_const_index[byte_string]
|
1325 |
+
except KeyError:
|
1326 |
+
c = self.new_string_const(text, byte_string)
|
1327 |
+
c.add_py_version(py_version)
|
1328 |
+
return c
|
1329 |
+
|
1330 |
+
def get_pyunicode_ptr_const(self, text):
|
1331 |
+
# return a Py_UNICODE[] constant, creating a new one if necessary
|
1332 |
+
assert text.is_unicode
|
1333 |
+
try:
|
1334 |
+
c = self.pyunicode_ptr_const_index[text]
|
1335 |
+
except KeyError:
|
1336 |
+
c = self.pyunicode_ptr_const_index[text] = self.new_const_cname()
|
1337 |
+
return c
|
1338 |
+
|
1339 |
+
def get_py_string_const(self, text, identifier=None,
|
1340 |
+
is_str=False, unicode_value=None):
|
1341 |
+
# return a Python string constant, creating a new one if necessary
|
1342 |
+
py3str_cstring = None
|
1343 |
+
if is_str and unicode_value is not None \
|
1344 |
+
and unicode_value.utf8encode() != text.byteencode():
|
1345 |
+
py3str_cstring = self.get_string_const(unicode_value, py_version=3)
|
1346 |
+
c_string = self.get_string_const(text, py_version=2)
|
1347 |
+
else:
|
1348 |
+
c_string = self.get_string_const(text)
|
1349 |
+
py_string = c_string.get_py_string_const(
|
1350 |
+
text.encoding, identifier, is_str, py3str_cstring)
|
1351 |
+
return py_string
|
1352 |
+
|
1353 |
+
def get_interned_identifier(self, text):
|
1354 |
+
return self.get_py_string_const(text, identifier=True)
|
1355 |
+
|
1356 |
+
def new_string_const(self, text, byte_string):
|
1357 |
+
cname = self.new_string_const_cname(byte_string)
|
1358 |
+
c = StringConst(cname, text, byte_string)
|
1359 |
+
self.string_const_index[byte_string] = c
|
1360 |
+
return c
|
1361 |
+
|
1362 |
+
def new_num_const(self, value, py_type, value_code=None):
|
1363 |
+
cname = self.new_num_const_cname(value, py_type)
|
1364 |
+
c = NumConst(cname, value, py_type, value_code)
|
1365 |
+
self.num_const_index[(value, py_type)] = c
|
1366 |
+
return c
|
1367 |
+
|
1368 |
+
def new_py_const(self, type, prefix=''):
|
1369 |
+
cname = self.new_const_cname(prefix)
|
1370 |
+
c = PyObjectConst(cname, type)
|
1371 |
+
self.py_constants.append(c)
|
1372 |
+
return c
|
1373 |
+
|
1374 |
+
def new_string_const_cname(self, bytes_value):
|
1375 |
+
# Create a new globally-unique nice name for a C string constant.
|
1376 |
+
value = bytes_value.decode('ASCII', 'ignore')
|
1377 |
+
return self.new_const_cname(value=value)
|
1378 |
+
|
1379 |
+
def new_num_const_cname(self, value, py_type):
|
1380 |
+
if py_type == 'long':
|
1381 |
+
value += 'L'
|
1382 |
+
py_type = 'int'
|
1383 |
+
prefix = Naming.interned_prefixes[py_type]
|
1384 |
+
cname = "%s%s" % (prefix, value)
|
1385 |
+
cname = cname.replace('+', '_').replace('-', 'neg_').replace('.', '_')
|
1386 |
+
return cname
|
1387 |
+
|
1388 |
+
def new_const_cname(self, prefix='', value=''):
|
1389 |
+
value = replace_identifier('_', value)[:32].strip('_')
|
1390 |
+
used = self.const_cnames_used
|
1391 |
+
name_suffix = value
|
1392 |
+
while name_suffix in used:
|
1393 |
+
counter = used[value] = used[value] + 1
|
1394 |
+
name_suffix = '%s_%d' % (value, counter)
|
1395 |
+
used[name_suffix] = 1
|
1396 |
+
if prefix:
|
1397 |
+
prefix = Naming.interned_prefixes[prefix]
|
1398 |
+
else:
|
1399 |
+
prefix = Naming.const_prefix
|
1400 |
+
return "%s%s" % (prefix, name_suffix)
|
1401 |
+
|
1402 |
+
def get_cached_unbound_method(self, type_cname, method_name):
|
1403 |
+
key = (type_cname, method_name)
|
1404 |
+
try:
|
1405 |
+
cname = self.cached_cmethods[key]
|
1406 |
+
except KeyError:
|
1407 |
+
cname = self.cached_cmethods[key] = self.new_const_cname(
|
1408 |
+
'umethod', '%s_%s' % (type_cname, method_name))
|
1409 |
+
return cname
|
1410 |
+
|
1411 |
+
def cached_unbound_method_call_code(self, obj_cname, type_cname, method_name, arg_cnames):
|
1412 |
+
# admittedly, not the best place to put this method, but it is reused by UtilityCode and ExprNodes ...
|
1413 |
+
utility_code_name = "CallUnboundCMethod%d" % len(arg_cnames)
|
1414 |
+
self.use_utility_code(UtilityCode.load_cached(utility_code_name, "ObjectHandling.c"))
|
1415 |
+
cache_cname = self.get_cached_unbound_method(type_cname, method_name)
|
1416 |
+
args = [obj_cname] + arg_cnames
|
1417 |
+
return "__Pyx_%s(&%s, %s)" % (
|
1418 |
+
utility_code_name,
|
1419 |
+
cache_cname,
|
1420 |
+
', '.join(args),
|
1421 |
+
)
|
1422 |
+
|
1423 |
+
def add_cached_builtin_decl(self, entry):
|
1424 |
+
if entry.is_builtin and entry.is_const:
|
1425 |
+
if self.should_declare(entry.cname, entry):
|
1426 |
+
self.put_pyobject_decl(entry)
|
1427 |
+
w = self.parts['cached_builtins']
|
1428 |
+
condition = None
|
1429 |
+
if entry.name in non_portable_builtins_map:
|
1430 |
+
condition, replacement = non_portable_builtins_map[entry.name]
|
1431 |
+
w.putln('#if %s' % condition)
|
1432 |
+
self.put_cached_builtin_init(
|
1433 |
+
entry.pos, StringEncoding.EncodedString(replacement),
|
1434 |
+
entry.cname)
|
1435 |
+
w.putln('#else')
|
1436 |
+
self.put_cached_builtin_init(
|
1437 |
+
entry.pos, StringEncoding.EncodedString(entry.name),
|
1438 |
+
entry.cname)
|
1439 |
+
if condition:
|
1440 |
+
w.putln('#endif')
|
1441 |
+
|
1442 |
+
def put_cached_builtin_init(self, pos, name, cname):
|
1443 |
+
w = self.parts['cached_builtins']
|
1444 |
+
interned_cname = self.get_interned_identifier(name).cname
|
1445 |
+
self.use_utility_code(
|
1446 |
+
UtilityCode.load_cached("GetBuiltinName", "ObjectHandling.c"))
|
1447 |
+
w.putln('%s = __Pyx_GetBuiltinName(%s); if (!%s) %s' % (
|
1448 |
+
cname,
|
1449 |
+
interned_cname,
|
1450 |
+
cname,
|
1451 |
+
w.error_goto(pos)))
|
1452 |
+
|
1453 |
+
def generate_const_declarations(self):
|
1454 |
+
self.generate_cached_methods_decls()
|
1455 |
+
self.generate_string_constants()
|
1456 |
+
self.generate_num_constants()
|
1457 |
+
self.generate_object_constant_decls()
|
1458 |
+
|
1459 |
+
def generate_object_constant_decls(self):
|
1460 |
+
consts = [(len(c.cname), c.cname, c)
|
1461 |
+
for c in self.py_constants]
|
1462 |
+
consts.sort()
|
1463 |
+
decls_writer = self.parts['decls']
|
1464 |
+
for _, cname, c in consts:
|
1465 |
+
decls_writer.putln(
|
1466 |
+
"static %s;" % c.type.declaration_code(cname))
|
1467 |
+
|
1468 |
+
def generate_cached_methods_decls(self):
|
1469 |
+
if not self.cached_cmethods:
|
1470 |
+
return
|
1471 |
+
|
1472 |
+
decl = self.parts['decls']
|
1473 |
+
init = self.parts['init_globals']
|
1474 |
+
cnames = []
|
1475 |
+
for (type_cname, method_name), cname in sorted(self.cached_cmethods.items()):
|
1476 |
+
cnames.append(cname)
|
1477 |
+
method_name_cname = self.get_interned_identifier(StringEncoding.EncodedString(method_name)).cname
|
1478 |
+
decl.putln('static __Pyx_CachedCFunction %s = {0, &%s, 0, 0, 0};' % (
|
1479 |
+
cname, method_name_cname))
|
1480 |
+
# split type reference storage as it might not be static
|
1481 |
+
init.putln('%s.type = (PyObject*)&%s;' % (
|
1482 |
+
cname, type_cname))
|
1483 |
+
|
1484 |
+
if Options.generate_cleanup_code:
|
1485 |
+
cleanup = self.parts['cleanup_globals']
|
1486 |
+
for cname in cnames:
|
1487 |
+
cleanup.putln("Py_CLEAR(%s.method);" % cname)
|
1488 |
+
|
1489 |
+
def generate_string_constants(self):
|
1490 |
+
c_consts = [(len(c.cname), c.cname, c) for c in self.string_const_index.values()]
|
1491 |
+
c_consts.sort()
|
1492 |
+
py_strings = []
|
1493 |
+
|
1494 |
+
decls_writer = self.parts['string_decls']
|
1495 |
+
for _, cname, c in c_consts:
|
1496 |
+
conditional = False
|
1497 |
+
if c.py_versions and (2 not in c.py_versions or 3 not in c.py_versions):
|
1498 |
+
conditional = True
|
1499 |
+
decls_writer.putln("#if PY_MAJOR_VERSION %s 3" % (
|
1500 |
+
(2 in c.py_versions) and '<' or '>='))
|
1501 |
+
decls_writer.putln('static const char %s[] = "%s";' % (
|
1502 |
+
cname, StringEncoding.split_string_literal(c.escaped_value)))
|
1503 |
+
if conditional:
|
1504 |
+
decls_writer.putln("#endif")
|
1505 |
+
if c.py_strings is not None:
|
1506 |
+
for py_string in c.py_strings.values():
|
1507 |
+
py_strings.append((c.cname, len(py_string.cname), py_string))
|
1508 |
+
|
1509 |
+
for c, cname in sorted(self.pyunicode_ptr_const_index.items()):
|
1510 |
+
utf16_array, utf32_array = StringEncoding.encode_pyunicode_string(c)
|
1511 |
+
if utf16_array:
|
1512 |
+
# Narrow and wide representations differ
|
1513 |
+
decls_writer.putln("#ifdef Py_UNICODE_WIDE")
|
1514 |
+
decls_writer.putln("static Py_UNICODE %s[] = { %s };" % (cname, utf32_array))
|
1515 |
+
if utf16_array:
|
1516 |
+
decls_writer.putln("#else")
|
1517 |
+
decls_writer.putln("static Py_UNICODE %s[] = { %s };" % (cname, utf16_array))
|
1518 |
+
decls_writer.putln("#endif")
|
1519 |
+
|
1520 |
+
if py_strings:
|
1521 |
+
self.use_utility_code(UtilityCode.load_cached("InitStrings", "StringTools.c"))
|
1522 |
+
py_strings.sort()
|
1523 |
+
w = self.parts['pystring_table']
|
1524 |
+
w.putln("")
|
1525 |
+
w.putln("static __Pyx_StringTabEntry %s[] = {" % Naming.stringtab_cname)
|
1526 |
+
for c_cname, _, py_string in py_strings:
|
1527 |
+
if not py_string.is_str or not py_string.encoding or \
|
1528 |
+
py_string.encoding in ('ASCII', 'USASCII', 'US-ASCII',
|
1529 |
+
'UTF8', 'UTF-8'):
|
1530 |
+
encoding = '0'
|
1531 |
+
else:
|
1532 |
+
encoding = '"%s"' % py_string.encoding.lower()
|
1533 |
+
|
1534 |
+
decls_writer.putln(
|
1535 |
+
"static PyObject *%s;" % py_string.cname)
|
1536 |
+
if py_string.py3str_cstring:
|
1537 |
+
w.putln("#if PY_MAJOR_VERSION >= 3")
|
1538 |
+
w.putln("{&%s, %s, sizeof(%s), %s, %d, %d, %d}," % (
|
1539 |
+
py_string.cname,
|
1540 |
+
py_string.py3str_cstring.cname,
|
1541 |
+
py_string.py3str_cstring.cname,
|
1542 |
+
'0', 1, 0,
|
1543 |
+
py_string.intern
|
1544 |
+
))
|
1545 |
+
w.putln("#else")
|
1546 |
+
w.putln("{&%s, %s, sizeof(%s), %s, %d, %d, %d}," % (
|
1547 |
+
py_string.cname,
|
1548 |
+
c_cname,
|
1549 |
+
c_cname,
|
1550 |
+
encoding,
|
1551 |
+
py_string.is_unicode,
|
1552 |
+
py_string.is_str,
|
1553 |
+
py_string.intern
|
1554 |
+
))
|
1555 |
+
if py_string.py3str_cstring:
|
1556 |
+
w.putln("#endif")
|
1557 |
+
w.putln("{0, 0, 0, 0, 0, 0, 0}")
|
1558 |
+
w.putln("};")
|
1559 |
+
|
1560 |
+
init_globals = self.parts['init_globals']
|
1561 |
+
init_globals.putln(
|
1562 |
+
"if (__Pyx_InitStrings(%s) < 0) %s" % (
|
1563 |
+
Naming.stringtab_cname,
|
1564 |
+
init_globals.error_goto(self.module_pos)))
|
1565 |
+
|
1566 |
+
def generate_num_constants(self):
|
1567 |
+
consts = [(c.py_type, c.value[0] == '-', len(c.value), c.value, c.value_code, c)
|
1568 |
+
for c in self.num_const_index.values()]
|
1569 |
+
consts.sort()
|
1570 |
+
decls_writer = self.parts['decls']
|
1571 |
+
init_globals = self.parts['init_globals']
|
1572 |
+
for py_type, _, _, value, value_code, c in consts:
|
1573 |
+
cname = c.cname
|
1574 |
+
decls_writer.putln("static PyObject *%s;" % cname)
|
1575 |
+
if py_type == 'float':
|
1576 |
+
function = 'PyFloat_FromDouble(%s)'
|
1577 |
+
elif py_type == 'long':
|
1578 |
+
function = 'PyLong_FromString((char *)"%s", 0, 0)'
|
1579 |
+
elif Utils.long_literal(value):
|
1580 |
+
function = 'PyInt_FromString((char *)"%s", 0, 0)'
|
1581 |
+
elif len(value.lstrip('-')) > 4:
|
1582 |
+
function = "PyInt_FromLong(%sL)"
|
1583 |
+
else:
|
1584 |
+
function = "PyInt_FromLong(%s)"
|
1585 |
+
init_globals.putln('%s = %s; %s' % (
|
1586 |
+
cname, function % value_code,
|
1587 |
+
init_globals.error_goto_if_null(cname, self.module_pos)))
|
1588 |
+
|
1589 |
+
# The functions below are there in a transition phase only
|
1590 |
+
# and will be deprecated. They are called from Nodes.BlockNode.
|
1591 |
+
# The copy&paste duplication is intentional in order to be able
|
1592 |
+
# to see quickly how BlockNode worked, until this is replaced.
|
1593 |
+
|
1594 |
+
def should_declare(self, cname, entry):
|
1595 |
+
if cname in self.declared_cnames:
|
1596 |
+
other = self.declared_cnames[cname]
|
1597 |
+
assert str(entry.type) == str(other.type)
|
1598 |
+
assert entry.init == other.init
|
1599 |
+
return False
|
1600 |
+
else:
|
1601 |
+
self.declared_cnames[cname] = entry
|
1602 |
+
return True
|
1603 |
+
|
1604 |
+
#
|
1605 |
+
# File name state
|
1606 |
+
#
|
1607 |
+
|
1608 |
+
def lookup_filename(self, source_desc):
|
1609 |
+
entry = source_desc.get_filenametable_entry()
|
1610 |
+
try:
|
1611 |
+
index = self.filename_table[entry]
|
1612 |
+
except KeyError:
|
1613 |
+
index = len(self.filename_list)
|
1614 |
+
self.filename_list.append(source_desc)
|
1615 |
+
self.filename_table[entry] = index
|
1616 |
+
return index
|
1617 |
+
|
1618 |
+
def commented_file_contents(self, source_desc):
|
1619 |
+
try:
|
1620 |
+
return self.input_file_contents[source_desc]
|
1621 |
+
except KeyError:
|
1622 |
+
pass
|
1623 |
+
source_file = source_desc.get_lines(encoding='ASCII',
|
1624 |
+
error_handling='ignore')
|
1625 |
+
try:
|
1626 |
+
F = [u' * ' + line.rstrip().replace(
|
1627 |
+
u'*/', u'*[inserted by cython to avoid comment closer]/'
|
1628 |
+
).replace(
|
1629 |
+
u'/*', u'/[inserted by cython to avoid comment start]*'
|
1630 |
+
)
|
1631 |
+
for line in source_file]
|
1632 |
+
finally:
|
1633 |
+
if hasattr(source_file, 'close'):
|
1634 |
+
source_file.close()
|
1635 |
+
if not F: F.append(u'')
|
1636 |
+
self.input_file_contents[source_desc] = F
|
1637 |
+
return F
|
1638 |
+
|
1639 |
+
#
|
1640 |
+
# Utility code state
|
1641 |
+
#
|
1642 |
+
|
1643 |
+
def use_utility_code(self, utility_code):
|
1644 |
+
"""
|
1645 |
+
Adds code to the C file. utility_code should
|
1646 |
+
a) implement __eq__/__hash__ for the purpose of knowing whether the same
|
1647 |
+
code has already been included
|
1648 |
+
b) implement put_code, which takes a globalstate instance
|
1649 |
+
|
1650 |
+
See UtilityCode.
|
1651 |
+
"""
|
1652 |
+
if utility_code and utility_code not in self.utility_codes:
|
1653 |
+
self.utility_codes.add(utility_code)
|
1654 |
+
utility_code.put_code(self)
|
1655 |
+
|
1656 |
+
def use_entry_utility_code(self, entry):
|
1657 |
+
if entry is None:
|
1658 |
+
return
|
1659 |
+
if entry.utility_code:
|
1660 |
+
self.use_utility_code(entry.utility_code)
|
1661 |
+
if entry.utility_code_definition:
|
1662 |
+
self.use_utility_code(entry.utility_code_definition)
|
1663 |
+
|
1664 |
+
|
1665 |
+
def funccontext_property(func):
|
1666 |
+
name = func.__name__
|
1667 |
+
attribute_of = operator.attrgetter(name)
|
1668 |
+
def get(self):
|
1669 |
+
return attribute_of(self.funcstate)
|
1670 |
+
def set(self, value):
|
1671 |
+
setattr(self.funcstate, name, value)
|
1672 |
+
return property(get, set)
|
1673 |
+
|
1674 |
+
|
1675 |
+
class CCodeConfig(object):
|
1676 |
+
# emit_linenums boolean write #line pragmas?
|
1677 |
+
# emit_code_comments boolean copy the original code into C comments?
|
1678 |
+
# c_line_in_traceback boolean append the c file and line number to the traceback for exceptions?
|
1679 |
+
|
1680 |
+
def __init__(self, emit_linenums=True, emit_code_comments=True, c_line_in_traceback=True):
|
1681 |
+
self.emit_code_comments = emit_code_comments
|
1682 |
+
self.emit_linenums = emit_linenums
|
1683 |
+
self.c_line_in_traceback = c_line_in_traceback
|
1684 |
+
|
1685 |
+
|
1686 |
+
class CCodeWriter(object):
|
1687 |
+
"""
|
1688 |
+
Utility class to output C code.
|
1689 |
+
|
1690 |
+
When creating an insertion point one must care about the state that is
|
1691 |
+
kept:
|
1692 |
+
- formatting state (level, bol) is cloned and used in insertion points
|
1693 |
+
as well
|
1694 |
+
- labels, temps, exc_vars: One must construct a scope in which these can
|
1695 |
+
exist by calling enter_cfunc_scope/exit_cfunc_scope (these are for
|
1696 |
+
sanity checking and forward compatibility). Created insertion points
|
1697 |
+
looses this scope and cannot access it.
|
1698 |
+
- marker: Not copied to insertion point
|
1699 |
+
- filename_table, filename_list, input_file_contents: All codewriters
|
1700 |
+
coming from the same root share the same instances simultaneously.
|
1701 |
+
"""
|
1702 |
+
|
1703 |
+
# f file output file
|
1704 |
+
# buffer StringIOTree
|
1705 |
+
|
1706 |
+
# level int indentation level
|
1707 |
+
# bol bool beginning of line?
|
1708 |
+
# marker string comment to emit before next line
|
1709 |
+
# funcstate FunctionState contains state local to a C function used for code
|
1710 |
+
# generation (labels and temps state etc.)
|
1711 |
+
# globalstate GlobalState contains state global for a C file (input file info,
|
1712 |
+
# utility code, declared constants etc.)
|
1713 |
+
# pyclass_stack list used during recursive code generation to pass information
|
1714 |
+
# about the current class one is in
|
1715 |
+
# code_config CCodeConfig configuration options for the C code writer
|
1716 |
+
|
1717 |
+
@cython.locals(create_from='CCodeWriter')
|
1718 |
+
def __init__(self, create_from=None, buffer=None, copy_formatting=False):
|
1719 |
+
if buffer is None: buffer = StringIOTree()
|
1720 |
+
self.buffer = buffer
|
1721 |
+
self.last_pos = None
|
1722 |
+
self.last_marked_pos = None
|
1723 |
+
self.pyclass_stack = []
|
1724 |
+
|
1725 |
+
self.funcstate = None
|
1726 |
+
self.globalstate = None
|
1727 |
+
self.code_config = None
|
1728 |
+
self.level = 0
|
1729 |
+
self.call_level = 0
|
1730 |
+
self.bol = 1
|
1731 |
+
|
1732 |
+
if create_from is not None:
|
1733 |
+
# Use same global state
|
1734 |
+
self.set_global_state(create_from.globalstate)
|
1735 |
+
self.funcstate = create_from.funcstate
|
1736 |
+
# Clone formatting state
|
1737 |
+
if copy_formatting:
|
1738 |
+
self.level = create_from.level
|
1739 |
+
self.bol = create_from.bol
|
1740 |
+
self.call_level = create_from.call_level
|
1741 |
+
self.last_pos = create_from.last_pos
|
1742 |
+
self.last_marked_pos = create_from.last_marked_pos
|
1743 |
+
|
1744 |
+
def create_new(self, create_from, buffer, copy_formatting):
|
1745 |
+
# polymorphic constructor -- very slightly more versatile
|
1746 |
+
# than using __class__
|
1747 |
+
result = CCodeWriter(create_from, buffer, copy_formatting)
|
1748 |
+
return result
|
1749 |
+
|
1750 |
+
def set_global_state(self, global_state):
|
1751 |
+
assert self.globalstate is None # prevent overwriting once it's set
|
1752 |
+
self.globalstate = global_state
|
1753 |
+
self.code_config = global_state.code_config
|
1754 |
+
|
1755 |
+
def copyto(self, f):
|
1756 |
+
self.buffer.copyto(f)
|
1757 |
+
|
1758 |
+
def getvalue(self):
|
1759 |
+
return self.buffer.getvalue()
|
1760 |
+
|
1761 |
+
def write(self, s):
|
1762 |
+
# also put invalid markers (lineno 0), to indicate that those lines
|
1763 |
+
# have no Cython source code correspondence
|
1764 |
+
cython_lineno = self.last_marked_pos[1] if self.last_marked_pos else 0
|
1765 |
+
self.buffer.markers.extend([cython_lineno] * s.count('\n'))
|
1766 |
+
self.buffer.write(s)
|
1767 |
+
|
1768 |
+
def insertion_point(self):
|
1769 |
+
other = self.create_new(create_from=self, buffer=self.buffer.insertion_point(), copy_formatting=True)
|
1770 |
+
return other
|
1771 |
+
|
1772 |
+
def new_writer(self):
|
1773 |
+
"""
|
1774 |
+
Creates a new CCodeWriter connected to the same global state, which
|
1775 |
+
can later be inserted using insert.
|
1776 |
+
"""
|
1777 |
+
return CCodeWriter(create_from=self)
|
1778 |
+
|
1779 |
+
def insert(self, writer):
|
1780 |
+
"""
|
1781 |
+
Inserts the contents of another code writer (created with
|
1782 |
+
the same global state) in the current location.
|
1783 |
+
|
1784 |
+
It is ok to write to the inserted writer also after insertion.
|
1785 |
+
"""
|
1786 |
+
assert writer.globalstate is self.globalstate
|
1787 |
+
self.buffer.insert(writer.buffer)
|
1788 |
+
|
1789 |
+
# Properties delegated to function scope
|
1790 |
+
@funccontext_property
|
1791 |
+
def label_counter(self): pass
|
1792 |
+
@funccontext_property
|
1793 |
+
def return_label(self): pass
|
1794 |
+
@funccontext_property
|
1795 |
+
def error_label(self): pass
|
1796 |
+
@funccontext_property
|
1797 |
+
def labels_used(self): pass
|
1798 |
+
@funccontext_property
|
1799 |
+
def continue_label(self): pass
|
1800 |
+
@funccontext_property
|
1801 |
+
def break_label(self): pass
|
1802 |
+
@funccontext_property
|
1803 |
+
def return_from_error_cleanup_label(self): pass
|
1804 |
+
@funccontext_property
|
1805 |
+
def yield_labels(self): pass
|
1806 |
+
|
1807 |
+
# Functions delegated to function scope
|
1808 |
+
def new_label(self, name=None): return self.funcstate.new_label(name)
|
1809 |
+
def new_error_label(self): return self.funcstate.new_error_label()
|
1810 |
+
def new_yield_label(self, *args): return self.funcstate.new_yield_label(*args)
|
1811 |
+
def get_loop_labels(self): return self.funcstate.get_loop_labels()
|
1812 |
+
def set_loop_labels(self, labels): return self.funcstate.set_loop_labels(labels)
|
1813 |
+
def new_loop_labels(self): return self.funcstate.new_loop_labels()
|
1814 |
+
def get_all_labels(self): return self.funcstate.get_all_labels()
|
1815 |
+
def set_all_labels(self, labels): return self.funcstate.set_all_labels(labels)
|
1816 |
+
def all_new_labels(self): return self.funcstate.all_new_labels()
|
1817 |
+
def use_label(self, lbl): return self.funcstate.use_label(lbl)
|
1818 |
+
def label_used(self, lbl): return self.funcstate.label_used(lbl)
|
1819 |
+
|
1820 |
+
|
1821 |
+
def enter_cfunc_scope(self, scope=None):
|
1822 |
+
self.funcstate = FunctionState(self, scope=scope)
|
1823 |
+
|
1824 |
+
def exit_cfunc_scope(self):
|
1825 |
+
self.funcstate = None
|
1826 |
+
|
1827 |
+
# constant handling
|
1828 |
+
|
1829 |
+
def get_py_int(self, str_value, longness):
|
1830 |
+
return self.globalstate.get_int_const(str_value, longness).cname
|
1831 |
+
|
1832 |
+
def get_py_float(self, str_value, value_code):
|
1833 |
+
return self.globalstate.get_float_const(str_value, value_code).cname
|
1834 |
+
|
1835 |
+
def get_py_const(self, type, prefix='', cleanup_level=None, dedup_key=None):
|
1836 |
+
return self.globalstate.get_py_const(type, prefix, cleanup_level, dedup_key).cname
|
1837 |
+
|
1838 |
+
def get_string_const(self, text):
|
1839 |
+
return self.globalstate.get_string_const(text).cname
|
1840 |
+
|
1841 |
+
def get_pyunicode_ptr_const(self, text):
|
1842 |
+
return self.globalstate.get_pyunicode_ptr_const(text)
|
1843 |
+
|
1844 |
+
def get_py_string_const(self, text, identifier=None,
|
1845 |
+
is_str=False, unicode_value=None):
|
1846 |
+
return self.globalstate.get_py_string_const(
|
1847 |
+
text, identifier, is_str, unicode_value).cname
|
1848 |
+
|
1849 |
+
def get_argument_default_const(self, type):
|
1850 |
+
return self.globalstate.get_py_const(type).cname
|
1851 |
+
|
1852 |
+
def intern(self, text):
|
1853 |
+
return self.get_py_string_const(text)
|
1854 |
+
|
1855 |
+
def intern_identifier(self, text):
|
1856 |
+
return self.get_py_string_const(text, identifier=True)
|
1857 |
+
|
1858 |
+
def get_cached_constants_writer(self, target=None):
|
1859 |
+
return self.globalstate.get_cached_constants_writer(target)
|
1860 |
+
|
1861 |
+
# code generation
|
1862 |
+
|
1863 |
+
def putln(self, code="", safe=False):
|
1864 |
+
if self.last_pos and self.bol:
|
1865 |
+
self.emit_marker()
|
1866 |
+
if self.code_config.emit_linenums and self.last_marked_pos:
|
1867 |
+
source_desc, line, _ = self.last_marked_pos
|
1868 |
+
self.write('\n#line %s "%s"\n' % (line, source_desc.get_escaped_description()))
|
1869 |
+
if code:
|
1870 |
+
if safe:
|
1871 |
+
self.put_safe(code)
|
1872 |
+
else:
|
1873 |
+
self.put(code)
|
1874 |
+
self.write("\n")
|
1875 |
+
self.bol = 1
|
1876 |
+
|
1877 |
+
def mark_pos(self, pos, trace=True):
|
1878 |
+
if pos is None:
|
1879 |
+
return
|
1880 |
+
if self.last_marked_pos and self.last_marked_pos[:2] == pos[:2]:
|
1881 |
+
return
|
1882 |
+
self.last_pos = (pos, trace)
|
1883 |
+
|
1884 |
+
def emit_marker(self):
|
1885 |
+
pos, trace = self.last_pos
|
1886 |
+
self.last_marked_pos = pos
|
1887 |
+
self.last_pos = None
|
1888 |
+
self.write("\n")
|
1889 |
+
if self.code_config.emit_code_comments:
|
1890 |
+
self.indent()
|
1891 |
+
self.write("/* %s */\n" % self._build_marker(pos))
|
1892 |
+
if trace and self.funcstate and self.funcstate.can_trace and self.globalstate.directives['linetrace']:
|
1893 |
+
self.indent()
|
1894 |
+
self.write('__Pyx_TraceLine(%d,%d,%s)\n' % (
|
1895 |
+
pos[1], not self.funcstate.gil_owned, self.error_goto(pos)))
|
1896 |
+
|
1897 |
+
def _build_marker(self, pos):
|
1898 |
+
source_desc, line, col = pos
|
1899 |
+
assert isinstance(source_desc, SourceDescriptor)
|
1900 |
+
contents = self.globalstate.commented_file_contents(source_desc)
|
1901 |
+
lines = contents[max(0, line-3):line] # line numbers start at 1
|
1902 |
+
lines[-1] += u' # <<<<<<<<<<<<<<'
|
1903 |
+
lines += contents[line:line+2]
|
1904 |
+
return u'"%s":%d\n%s\n' % (source_desc.get_escaped_description(), line, u'\n'.join(lines))
|
1905 |
+
|
1906 |
+
def put_safe(self, code):
|
1907 |
+
# put code, but ignore {}
|
1908 |
+
self.write(code)
|
1909 |
+
self.bol = 0
|
1910 |
+
|
1911 |
+
def put_or_include(self, code, name):
|
1912 |
+
include_dir = self.globalstate.common_utility_include_dir
|
1913 |
+
if include_dir and len(code) > 1024:
|
1914 |
+
include_file = "%s_%s.h" % (
|
1915 |
+
name, hashlib.md5(code.encode('utf8')).hexdigest())
|
1916 |
+
path = os.path.join(include_dir, include_file)
|
1917 |
+
if not os.path.exists(path):
|
1918 |
+
tmp_path = '%s.tmp%s' % (path, os.getpid())
|
1919 |
+
with closing(Utils.open_new_file(tmp_path)) as f:
|
1920 |
+
f.write(code)
|
1921 |
+
shutil.move(tmp_path, path)
|
1922 |
+
code = '#include "%s"\n' % path
|
1923 |
+
self.put(code)
|
1924 |
+
|
1925 |
+
def put(self, code):
|
1926 |
+
fix_indent = False
|
1927 |
+
if "{" in code:
|
1928 |
+
dl = code.count("{")
|
1929 |
+
else:
|
1930 |
+
dl = 0
|
1931 |
+
if "}" in code:
|
1932 |
+
dl -= code.count("}")
|
1933 |
+
if dl < 0:
|
1934 |
+
self.level += dl
|
1935 |
+
elif dl == 0 and code[0] == "}":
|
1936 |
+
# special cases like "} else {" need a temporary dedent
|
1937 |
+
fix_indent = True
|
1938 |
+
self.level -= 1
|
1939 |
+
if self.bol:
|
1940 |
+
self.indent()
|
1941 |
+
self.write(code)
|
1942 |
+
self.bol = 0
|
1943 |
+
if dl > 0:
|
1944 |
+
self.level += dl
|
1945 |
+
elif fix_indent:
|
1946 |
+
self.level += 1
|
1947 |
+
|
1948 |
+
def putln_tempita(self, code, **context):
|
1949 |
+
from ..Tempita import sub
|
1950 |
+
self.putln(sub(code, **context))
|
1951 |
+
|
1952 |
+
def put_tempita(self, code, **context):
|
1953 |
+
from ..Tempita import sub
|
1954 |
+
self.put(sub(code, **context))
|
1955 |
+
|
1956 |
+
def increase_indent(self):
|
1957 |
+
self.level += 1
|
1958 |
+
|
1959 |
+
def decrease_indent(self):
|
1960 |
+
self.level -= 1
|
1961 |
+
|
1962 |
+
def begin_block(self):
|
1963 |
+
self.putln("{")
|
1964 |
+
self.increase_indent()
|
1965 |
+
|
1966 |
+
def end_block(self):
|
1967 |
+
self.decrease_indent()
|
1968 |
+
self.putln("}")
|
1969 |
+
|
1970 |
+
def indent(self):
|
1971 |
+
self.write(" " * self.level)
|
1972 |
+
|
1973 |
+
def get_py_version_hex(self, pyversion):
|
1974 |
+
return "0x%02X%02X%02X%02X" % (tuple(pyversion) + (0,0,0,0))[:4]
|
1975 |
+
|
1976 |
+
def put_label(self, lbl):
|
1977 |
+
if lbl in self.funcstate.labels_used:
|
1978 |
+
self.putln("%s:;" % lbl)
|
1979 |
+
|
1980 |
+
def put_goto(self, lbl):
|
1981 |
+
self.funcstate.use_label(lbl)
|
1982 |
+
self.putln("goto %s;" % lbl)
|
1983 |
+
|
1984 |
+
def put_var_declaration(self, entry, storage_class="",
|
1985 |
+
dll_linkage=None, definition=True):
|
1986 |
+
#print "Code.put_var_declaration:", entry.name, "definition =", definition ###
|
1987 |
+
if entry.visibility == 'private' and not (definition or entry.defined_in_pxd):
|
1988 |
+
#print "...private and not definition, skipping", entry.cname ###
|
1989 |
+
return
|
1990 |
+
if entry.visibility == "private" and not entry.used:
|
1991 |
+
#print "...private and not used, skipping", entry.cname ###
|
1992 |
+
return
|
1993 |
+
if storage_class:
|
1994 |
+
self.put("%s " % storage_class)
|
1995 |
+
if not entry.cf_used:
|
1996 |
+
self.put('CYTHON_UNUSED ')
|
1997 |
+
self.put(entry.type.declaration_code(
|
1998 |
+
entry.cname, dll_linkage=dll_linkage))
|
1999 |
+
if entry.init is not None:
|
2000 |
+
self.put_safe(" = %s" % entry.type.literal_code(entry.init))
|
2001 |
+
elif entry.type.is_pyobject:
|
2002 |
+
self.put(" = NULL")
|
2003 |
+
self.putln(";")
|
2004 |
+
|
2005 |
+
def put_temp_declarations(self, func_context):
|
2006 |
+
for name, type, manage_ref, static in func_context.temps_allocated:
|
2007 |
+
decl = type.declaration_code(name)
|
2008 |
+
if type.is_pyobject:
|
2009 |
+
self.putln("%s = NULL;" % decl)
|
2010 |
+
elif type.is_memoryviewslice:
|
2011 |
+
from . import MemoryView
|
2012 |
+
self.putln("%s = %s;" % (decl, MemoryView.memslice_entry_init))
|
2013 |
+
else:
|
2014 |
+
self.putln("%s%s;" % (static and "static " or "", decl))
|
2015 |
+
|
2016 |
+
if func_context.should_declare_error_indicator:
|
2017 |
+
if self.funcstate.uses_error_indicator:
|
2018 |
+
unused = ''
|
2019 |
+
else:
|
2020 |
+
unused = 'CYTHON_UNUSED '
|
2021 |
+
# Initialize these variables to silence compiler warnings
|
2022 |
+
self.putln("%sint %s = 0;" % (unused, Naming.lineno_cname))
|
2023 |
+
self.putln("%sconst char *%s = NULL;" % (unused, Naming.filename_cname))
|
2024 |
+
self.putln("%sint %s = 0;" % (unused, Naming.clineno_cname))
|
2025 |
+
|
2026 |
+
def put_generated_by(self):
|
2027 |
+
self.putln("/* Generated by Cython %s */" % Version.watermark)
|
2028 |
+
self.putln("")
|
2029 |
+
|
2030 |
+
def put_h_guard(self, guard):
|
2031 |
+
self.putln("#ifndef %s" % guard)
|
2032 |
+
self.putln("#define %s" % guard)
|
2033 |
+
|
2034 |
+
def unlikely(self, cond):
|
2035 |
+
if Options.gcc_branch_hints:
|
2036 |
+
return 'unlikely(%s)' % cond
|
2037 |
+
else:
|
2038 |
+
return cond
|
2039 |
+
|
2040 |
+
def build_function_modifiers(self, modifiers, mapper=modifier_output_mapper):
|
2041 |
+
if not modifiers:
|
2042 |
+
return ''
|
2043 |
+
return '%s ' % ' '.join([mapper(m,m) for m in modifiers])
|
2044 |
+
|
2045 |
+
# Python objects and reference counting
|
2046 |
+
|
2047 |
+
def entry_as_pyobject(self, entry):
|
2048 |
+
type = entry.type
|
2049 |
+
if (not entry.is_self_arg and not entry.type.is_complete()
|
2050 |
+
or entry.type.is_extension_type):
|
2051 |
+
return "(PyObject *)" + entry.cname
|
2052 |
+
else:
|
2053 |
+
return entry.cname
|
2054 |
+
|
2055 |
+
def as_pyobject(self, cname, type):
|
2056 |
+
from .PyrexTypes import py_object_type, typecast
|
2057 |
+
return typecast(py_object_type, type, cname)
|
2058 |
+
|
2059 |
+
def put_gotref(self, cname):
|
2060 |
+
self.putln("__Pyx_GOTREF(%s);" % cname)
|
2061 |
+
|
2062 |
+
def put_giveref(self, cname):
|
2063 |
+
self.putln("__Pyx_GIVEREF(%s);" % cname)
|
2064 |
+
|
2065 |
+
def put_xgiveref(self, cname):
|
2066 |
+
self.putln("__Pyx_XGIVEREF(%s);" % cname)
|
2067 |
+
|
2068 |
+
def put_xgotref(self, cname):
|
2069 |
+
self.putln("__Pyx_XGOTREF(%s);" % cname)
|
2070 |
+
|
2071 |
+
def put_incref(self, cname, type, nanny=True):
|
2072 |
+
if nanny:
|
2073 |
+
self.putln("__Pyx_INCREF(%s);" % self.as_pyobject(cname, type))
|
2074 |
+
else:
|
2075 |
+
self.putln("Py_INCREF(%s);" % self.as_pyobject(cname, type))
|
2076 |
+
|
2077 |
+
def put_decref(self, cname, type, nanny=True):
|
2078 |
+
self._put_decref(cname, type, nanny, null_check=False, clear=False)
|
2079 |
+
|
2080 |
+
def put_var_gotref(self, entry):
|
2081 |
+
if entry.type.is_pyobject:
|
2082 |
+
self.putln("__Pyx_GOTREF(%s);" % self.entry_as_pyobject(entry))
|
2083 |
+
|
2084 |
+
def put_var_giveref(self, entry):
|
2085 |
+
if entry.type.is_pyobject:
|
2086 |
+
self.putln("__Pyx_GIVEREF(%s);" % self.entry_as_pyobject(entry))
|
2087 |
+
|
2088 |
+
def put_var_xgotref(self, entry):
|
2089 |
+
if entry.type.is_pyobject:
|
2090 |
+
self.putln("__Pyx_XGOTREF(%s);" % self.entry_as_pyobject(entry))
|
2091 |
+
|
2092 |
+
def put_var_xgiveref(self, entry):
|
2093 |
+
if entry.type.is_pyobject:
|
2094 |
+
self.putln("__Pyx_XGIVEREF(%s);" % self.entry_as_pyobject(entry))
|
2095 |
+
|
2096 |
+
def put_var_incref(self, entry, nanny=True):
|
2097 |
+
if entry.type.is_pyobject:
|
2098 |
+
if nanny:
|
2099 |
+
self.putln("__Pyx_INCREF(%s);" % self.entry_as_pyobject(entry))
|
2100 |
+
else:
|
2101 |
+
self.putln("Py_INCREF(%s);" % self.entry_as_pyobject(entry))
|
2102 |
+
|
2103 |
+
def put_var_xincref(self, entry):
|
2104 |
+
if entry.type.is_pyobject:
|
2105 |
+
self.putln("__Pyx_XINCREF(%s);" % self.entry_as_pyobject(entry))
|
2106 |
+
|
2107 |
+
def put_decref_clear(self, cname, type, nanny=True, clear_before_decref=False):
|
2108 |
+
self._put_decref(cname, type, nanny, null_check=False,
|
2109 |
+
clear=True, clear_before_decref=clear_before_decref)
|
2110 |
+
|
2111 |
+
def put_xdecref(self, cname, type, nanny=True, have_gil=True):
|
2112 |
+
self._put_decref(cname, type, nanny, null_check=True,
|
2113 |
+
have_gil=have_gil, clear=False)
|
2114 |
+
|
2115 |
+
def put_xdecref_clear(self, cname, type, nanny=True, clear_before_decref=False):
|
2116 |
+
self._put_decref(cname, type, nanny, null_check=True,
|
2117 |
+
clear=True, clear_before_decref=clear_before_decref)
|
2118 |
+
|
2119 |
+
def _put_decref(self, cname, type, nanny=True, null_check=False,
|
2120 |
+
have_gil=True, clear=False, clear_before_decref=False):
|
2121 |
+
if type.is_memoryviewslice:
|
2122 |
+
self.put_xdecref_memoryviewslice(cname, have_gil=have_gil)
|
2123 |
+
return
|
2124 |
+
|
2125 |
+
prefix = '__Pyx' if nanny else 'Py'
|
2126 |
+
X = 'X' if null_check else ''
|
2127 |
+
|
2128 |
+
if clear:
|
2129 |
+
if clear_before_decref:
|
2130 |
+
if not nanny:
|
2131 |
+
X = '' # CPython doesn't have a Py_XCLEAR()
|
2132 |
+
self.putln("%s_%sCLEAR(%s);" % (prefix, X, cname))
|
2133 |
+
else:
|
2134 |
+
self.putln("%s_%sDECREF(%s); %s = 0;" % (
|
2135 |
+
prefix, X, self.as_pyobject(cname, type), cname))
|
2136 |
+
else:
|
2137 |
+
self.putln("%s_%sDECREF(%s);" % (
|
2138 |
+
prefix, X, self.as_pyobject(cname, type)))
|
2139 |
+
|
2140 |
+
def put_decref_set(self, cname, rhs_cname):
|
2141 |
+
self.putln("__Pyx_DECREF_SET(%s, %s);" % (cname, rhs_cname))
|
2142 |
+
|
2143 |
+
def put_xdecref_set(self, cname, rhs_cname):
|
2144 |
+
self.putln("__Pyx_XDECREF_SET(%s, %s);" % (cname, rhs_cname))
|
2145 |
+
|
2146 |
+
def put_var_decref(self, entry):
|
2147 |
+
if entry.type.is_pyobject:
|
2148 |
+
self.putln("__Pyx_XDECREF(%s);" % self.entry_as_pyobject(entry))
|
2149 |
+
|
2150 |
+
def put_var_xdecref(self, entry, nanny=True):
|
2151 |
+
if entry.type.is_pyobject:
|
2152 |
+
if nanny:
|
2153 |
+
self.putln("__Pyx_XDECREF(%s);" % self.entry_as_pyobject(entry))
|
2154 |
+
else:
|
2155 |
+
self.putln("Py_XDECREF(%s);" % self.entry_as_pyobject(entry))
|
2156 |
+
|
2157 |
+
def put_var_decref_clear(self, entry):
|
2158 |
+
self._put_var_decref_clear(entry, null_check=False)
|
2159 |
+
|
2160 |
+
def put_var_xdecref_clear(self, entry):
|
2161 |
+
self._put_var_decref_clear(entry, null_check=True)
|
2162 |
+
|
2163 |
+
def _put_var_decref_clear(self, entry, null_check):
|
2164 |
+
if entry.type.is_pyobject:
|
2165 |
+
if entry.in_closure:
|
2166 |
+
# reset before DECREF to make sure closure state is
|
2167 |
+
# consistent during call to DECREF()
|
2168 |
+
self.putln("__Pyx_%sCLEAR(%s);" % (
|
2169 |
+
null_check and 'X' or '',
|
2170 |
+
entry.cname))
|
2171 |
+
else:
|
2172 |
+
self.putln("__Pyx_%sDECREF(%s); %s = 0;" % (
|
2173 |
+
null_check and 'X' or '',
|
2174 |
+
self.entry_as_pyobject(entry),
|
2175 |
+
entry.cname))
|
2176 |
+
|
2177 |
+
def put_var_decrefs(self, entries, used_only = 0):
|
2178 |
+
for entry in entries:
|
2179 |
+
if not used_only or entry.used:
|
2180 |
+
if entry.xdecref_cleanup:
|
2181 |
+
self.put_var_xdecref(entry)
|
2182 |
+
else:
|
2183 |
+
self.put_var_decref(entry)
|
2184 |
+
|
2185 |
+
def put_var_xdecrefs(self, entries):
|
2186 |
+
for entry in entries:
|
2187 |
+
self.put_var_xdecref(entry)
|
2188 |
+
|
2189 |
+
def put_var_xdecrefs_clear(self, entries):
|
2190 |
+
for entry in entries:
|
2191 |
+
self.put_var_xdecref_clear(entry)
|
2192 |
+
|
2193 |
+
def put_incref_memoryviewslice(self, slice_cname, have_gil=False):
|
2194 |
+
from . import MemoryView
|
2195 |
+
self.globalstate.use_utility_code(MemoryView.memviewslice_init_code)
|
2196 |
+
self.putln("__PYX_INC_MEMVIEW(&%s, %d);" % (slice_cname, int(have_gil)))
|
2197 |
+
|
2198 |
+
def put_xdecref_memoryviewslice(self, slice_cname, have_gil=False):
|
2199 |
+
from . import MemoryView
|
2200 |
+
self.globalstate.use_utility_code(MemoryView.memviewslice_init_code)
|
2201 |
+
self.putln("__PYX_XDEC_MEMVIEW(&%s, %d);" % (slice_cname, int(have_gil)))
|
2202 |
+
|
2203 |
+
def put_xgiveref_memoryviewslice(self, slice_cname):
|
2204 |
+
self.put_xgiveref("%s.memview" % slice_cname)
|
2205 |
+
|
2206 |
+
def put_init_to_py_none(self, cname, type, nanny=True):
|
2207 |
+
from .PyrexTypes import py_object_type, typecast
|
2208 |
+
py_none = typecast(type, py_object_type, "Py_None")
|
2209 |
+
if nanny:
|
2210 |
+
self.putln("%s = %s; __Pyx_INCREF(Py_None);" % (cname, py_none))
|
2211 |
+
else:
|
2212 |
+
self.putln("%s = %s; Py_INCREF(Py_None);" % (cname, py_none))
|
2213 |
+
|
2214 |
+
def put_init_var_to_py_none(self, entry, template = "%s", nanny=True):
|
2215 |
+
code = template % entry.cname
|
2216 |
+
#if entry.type.is_extension_type:
|
2217 |
+
# code = "((PyObject*)%s)" % code
|
2218 |
+
self.put_init_to_py_none(code, entry.type, nanny)
|
2219 |
+
if entry.in_closure:
|
2220 |
+
self.put_giveref('Py_None')
|
2221 |
+
|
2222 |
+
def put_pymethoddef(self, entry, term, allow_skip=True, wrapper_code_writer=None):
|
2223 |
+
if entry.is_special or entry.name == '__getattribute__':
|
2224 |
+
if entry.name not in special_py_methods:
|
2225 |
+
if entry.name == '__getattr__' and not self.globalstate.directives['fast_getattr']:
|
2226 |
+
pass
|
2227 |
+
# Python's typeobject.c will automatically fill in our slot
|
2228 |
+
# in add_operators() (called by PyType_Ready) with a value
|
2229 |
+
# that's better than ours.
|
2230 |
+
elif allow_skip:
|
2231 |
+
return
|
2232 |
+
|
2233 |
+
method_flags = entry.signature.method_flags()
|
2234 |
+
if not method_flags:
|
2235 |
+
return
|
2236 |
+
from . import TypeSlots
|
2237 |
+
if entry.is_special or TypeSlots.is_reverse_number_slot(entry.name):
|
2238 |
+
method_flags += [TypeSlots.method_coexist]
|
2239 |
+
func_ptr = wrapper_code_writer.put_pymethoddef_wrapper(entry) if wrapper_code_writer else entry.func_cname
|
2240 |
+
# Add required casts, but try not to shadow real warnings.
|
2241 |
+
cast = '__Pyx_PyCFunctionFast' if 'METH_FASTCALL' in method_flags else 'PyCFunction'
|
2242 |
+
if 'METH_KEYWORDS' in method_flags:
|
2243 |
+
cast += 'WithKeywords'
|
2244 |
+
if cast != 'PyCFunction':
|
2245 |
+
func_ptr = '(void*)(%s)%s' % (cast, func_ptr)
|
2246 |
+
self.putln(
|
2247 |
+
'{"%s", (PyCFunction)%s, %s, %s}%s' % (
|
2248 |
+
entry.name,
|
2249 |
+
func_ptr,
|
2250 |
+
"|".join(method_flags),
|
2251 |
+
entry.doc_cname if entry.doc else '0',
|
2252 |
+
term))
|
2253 |
+
|
2254 |
+
def put_pymethoddef_wrapper(self, entry):
|
2255 |
+
func_cname = entry.func_cname
|
2256 |
+
if entry.is_special:
|
2257 |
+
method_flags = entry.signature.method_flags()
|
2258 |
+
if method_flags and 'METH_NOARGS' in method_flags:
|
2259 |
+
# Special NOARGS methods really take no arguments besides 'self', but PyCFunction expects one.
|
2260 |
+
func_cname = Naming.method_wrapper_prefix + func_cname
|
2261 |
+
self.putln("static PyObject *%s(PyObject *self, CYTHON_UNUSED PyObject *arg) {return %s(self);}" % (
|
2262 |
+
func_cname, entry.func_cname))
|
2263 |
+
return func_cname
|
2264 |
+
|
2265 |
+
# GIL methods
|
2266 |
+
|
2267 |
+
def put_ensure_gil(self, declare_gilstate=True, variable=None):
|
2268 |
+
"""
|
2269 |
+
Acquire the GIL. The generated code is safe even when no PyThreadState
|
2270 |
+
has been allocated for this thread (for threads not initialized by
|
2271 |
+
using the Python API). Additionally, the code generated by this method
|
2272 |
+
may be called recursively.
|
2273 |
+
"""
|
2274 |
+
self.globalstate.use_utility_code(
|
2275 |
+
UtilityCode.load_cached("ForceInitThreads", "ModuleSetupCode.c"))
|
2276 |
+
if self.globalstate.directives['fast_gil']:
|
2277 |
+
self.globalstate.use_utility_code(UtilityCode.load_cached("FastGil", "ModuleSetupCode.c"))
|
2278 |
+
else:
|
2279 |
+
self.globalstate.use_utility_code(UtilityCode.load_cached("NoFastGil", "ModuleSetupCode.c"))
|
2280 |
+
self.putln("#ifdef WITH_THREAD")
|
2281 |
+
if not variable:
|
2282 |
+
variable = '__pyx_gilstate_save'
|
2283 |
+
if declare_gilstate:
|
2284 |
+
self.put("PyGILState_STATE ")
|
2285 |
+
self.putln("%s = __Pyx_PyGILState_Ensure();" % variable)
|
2286 |
+
self.putln("#endif")
|
2287 |
+
|
2288 |
+
def put_release_ensured_gil(self, variable=None):
|
2289 |
+
"""
|
2290 |
+
Releases the GIL, corresponds to `put_ensure_gil`.
|
2291 |
+
"""
|
2292 |
+
if self.globalstate.directives['fast_gil']:
|
2293 |
+
self.globalstate.use_utility_code(UtilityCode.load_cached("FastGil", "ModuleSetupCode.c"))
|
2294 |
+
else:
|
2295 |
+
self.globalstate.use_utility_code(UtilityCode.load_cached("NoFastGil", "ModuleSetupCode.c"))
|
2296 |
+
if not variable:
|
2297 |
+
variable = '__pyx_gilstate_save'
|
2298 |
+
self.putln("#ifdef WITH_THREAD")
|
2299 |
+
self.putln("__Pyx_PyGILState_Release(%s);" % variable)
|
2300 |
+
self.putln("#endif")
|
2301 |
+
|
2302 |
+
def put_acquire_gil(self, variable=None):
|
2303 |
+
"""
|
2304 |
+
Acquire the GIL. The thread's thread state must have been initialized
|
2305 |
+
by a previous `put_release_gil`
|
2306 |
+
"""
|
2307 |
+
if self.globalstate.directives['fast_gil']:
|
2308 |
+
self.globalstate.use_utility_code(UtilityCode.load_cached("FastGil", "ModuleSetupCode.c"))
|
2309 |
+
else:
|
2310 |
+
self.globalstate.use_utility_code(UtilityCode.load_cached("NoFastGil", "ModuleSetupCode.c"))
|
2311 |
+
self.putln("#ifdef WITH_THREAD")
|
2312 |
+
self.putln("__Pyx_FastGIL_Forget();")
|
2313 |
+
if variable:
|
2314 |
+
self.putln('_save = %s;' % variable)
|
2315 |
+
self.putln("Py_BLOCK_THREADS")
|
2316 |
+
self.putln("#endif")
|
2317 |
+
|
2318 |
+
def put_release_gil(self, variable=None):
|
2319 |
+
"Release the GIL, corresponds to `put_acquire_gil`."
|
2320 |
+
if self.globalstate.directives['fast_gil']:
|
2321 |
+
self.globalstate.use_utility_code(UtilityCode.load_cached("FastGil", "ModuleSetupCode.c"))
|
2322 |
+
else:
|
2323 |
+
self.globalstate.use_utility_code(UtilityCode.load_cached("NoFastGil", "ModuleSetupCode.c"))
|
2324 |
+
self.putln("#ifdef WITH_THREAD")
|
2325 |
+
self.putln("PyThreadState *_save;")
|
2326 |
+
self.putln("Py_UNBLOCK_THREADS")
|
2327 |
+
if variable:
|
2328 |
+
self.putln('%s = _save;' % variable)
|
2329 |
+
self.putln("__Pyx_FastGIL_Remember();")
|
2330 |
+
self.putln("#endif")
|
2331 |
+
|
2332 |
+
def declare_gilstate(self):
|
2333 |
+
self.putln("#ifdef WITH_THREAD")
|
2334 |
+
self.putln("PyGILState_STATE __pyx_gilstate_save;")
|
2335 |
+
self.putln("#endif")
|
2336 |
+
|
2337 |
+
# error handling
|
2338 |
+
|
2339 |
+
def put_error_if_neg(self, pos, value):
|
2340 |
+
# TODO this path is almost _never_ taken, yet this macro makes is slower!
|
2341 |
+
# return self.putln("if (unlikely(%s < 0)) %s" % (value, self.error_goto(pos)))
|
2342 |
+
return self.putln("if (%s < 0) %s" % (value, self.error_goto(pos)))
|
2343 |
+
|
2344 |
+
def put_error_if_unbound(self, pos, entry, in_nogil_context=False):
|
2345 |
+
from . import ExprNodes
|
2346 |
+
if entry.from_closure:
|
2347 |
+
func = '__Pyx_RaiseClosureNameError'
|
2348 |
+
self.globalstate.use_utility_code(
|
2349 |
+
ExprNodes.raise_closure_name_error_utility_code)
|
2350 |
+
elif entry.type.is_memoryviewslice and in_nogil_context:
|
2351 |
+
func = '__Pyx_RaiseUnboundMemoryviewSliceNogil'
|
2352 |
+
self.globalstate.use_utility_code(
|
2353 |
+
ExprNodes.raise_unbound_memoryview_utility_code_nogil)
|
2354 |
+
else:
|
2355 |
+
func = '__Pyx_RaiseUnboundLocalError'
|
2356 |
+
self.globalstate.use_utility_code(
|
2357 |
+
ExprNodes.raise_unbound_local_error_utility_code)
|
2358 |
+
|
2359 |
+
self.putln('if (unlikely(!%s)) { %s("%s"); %s }' % (
|
2360 |
+
entry.type.check_for_null_code(entry.cname),
|
2361 |
+
func,
|
2362 |
+
entry.name,
|
2363 |
+
self.error_goto(pos)))
|
2364 |
+
|
2365 |
+
def set_error_info(self, pos, used=False):
|
2366 |
+
self.funcstate.should_declare_error_indicator = True
|
2367 |
+
if used:
|
2368 |
+
self.funcstate.uses_error_indicator = True
|
2369 |
+
return "__PYX_MARK_ERR_POS(%s, %s)" % (
|
2370 |
+
self.lookup_filename(pos[0]),
|
2371 |
+
pos[1])
|
2372 |
+
|
2373 |
+
def error_goto(self, pos, used=True):
|
2374 |
+
lbl = self.funcstate.error_label
|
2375 |
+
self.funcstate.use_label(lbl)
|
2376 |
+
if pos is None:
|
2377 |
+
return 'goto %s;' % lbl
|
2378 |
+
self.funcstate.should_declare_error_indicator = True
|
2379 |
+
if used:
|
2380 |
+
self.funcstate.uses_error_indicator = True
|
2381 |
+
return "__PYX_ERR(%s, %s, %s)" % (
|
2382 |
+
self.lookup_filename(pos[0]),
|
2383 |
+
pos[1],
|
2384 |
+
lbl)
|
2385 |
+
|
2386 |
+
def error_goto_if(self, cond, pos):
|
2387 |
+
return "if (%s) %s" % (self.unlikely(cond), self.error_goto(pos))
|
2388 |
+
|
2389 |
+
def error_goto_if_null(self, cname, pos):
|
2390 |
+
return self.error_goto_if("!%s" % cname, pos)
|
2391 |
+
|
2392 |
+
def error_goto_if_neg(self, cname, pos):
|
2393 |
+
return self.error_goto_if("%s < 0" % cname, pos)
|
2394 |
+
|
2395 |
+
def error_goto_if_PyErr(self, pos):
|
2396 |
+
return self.error_goto_if("PyErr_Occurred()", pos)
|
2397 |
+
|
2398 |
+
def lookup_filename(self, filename):
|
2399 |
+
return self.globalstate.lookup_filename(filename)
|
2400 |
+
|
2401 |
+
def put_declare_refcount_context(self):
|
2402 |
+
self.putln('__Pyx_RefNannyDeclarations')
|
2403 |
+
|
2404 |
+
def put_setup_refcount_context(self, name, acquire_gil=False):
|
2405 |
+
if acquire_gil:
|
2406 |
+
self.globalstate.use_utility_code(
|
2407 |
+
UtilityCode.load_cached("ForceInitThreads", "ModuleSetupCode.c"))
|
2408 |
+
self.putln('__Pyx_RefNannySetupContext("%s", %d);' % (name, acquire_gil and 1 or 0))
|
2409 |
+
|
2410 |
+
def put_finish_refcount_context(self):
|
2411 |
+
self.putln("__Pyx_RefNannyFinishContext();")
|
2412 |
+
|
2413 |
+
def put_add_traceback(self, qualified_name, include_cline=True):
|
2414 |
+
"""
|
2415 |
+
Build a Python traceback for propagating exceptions.
|
2416 |
+
|
2417 |
+
qualified_name should be the qualified name of the function.
|
2418 |
+
"""
|
2419 |
+
format_tuple = (
|
2420 |
+
qualified_name,
|
2421 |
+
Naming.clineno_cname if include_cline else 0,
|
2422 |
+
Naming.lineno_cname,
|
2423 |
+
Naming.filename_cname,
|
2424 |
+
)
|
2425 |
+
self.funcstate.uses_error_indicator = True
|
2426 |
+
self.putln('__Pyx_AddTraceback("%s", %s, %s, %s);' % format_tuple)
|
2427 |
+
|
2428 |
+
def put_unraisable(self, qualified_name, nogil=False):
|
2429 |
+
"""
|
2430 |
+
Generate code to print a Python warning for an unraisable exception.
|
2431 |
+
|
2432 |
+
qualified_name should be the qualified name of the function.
|
2433 |
+
"""
|
2434 |
+
format_tuple = (
|
2435 |
+
qualified_name,
|
2436 |
+
Naming.clineno_cname,
|
2437 |
+
Naming.lineno_cname,
|
2438 |
+
Naming.filename_cname,
|
2439 |
+
self.globalstate.directives['unraisable_tracebacks'],
|
2440 |
+
nogil,
|
2441 |
+
)
|
2442 |
+
self.funcstate.uses_error_indicator = True
|
2443 |
+
self.putln('__Pyx_WriteUnraisable("%s", %s, %s, %s, %d, %d);' % format_tuple)
|
2444 |
+
self.globalstate.use_utility_code(
|
2445 |
+
UtilityCode.load_cached("WriteUnraisableException", "Exceptions.c"))
|
2446 |
+
|
2447 |
+
def put_trace_declarations(self):
|
2448 |
+
self.putln('__Pyx_TraceDeclarations')
|
2449 |
+
|
2450 |
+
def put_trace_frame_init(self, codeobj=None):
|
2451 |
+
if codeobj:
|
2452 |
+
self.putln('__Pyx_TraceFrameInit(%s)' % codeobj)
|
2453 |
+
|
2454 |
+
def put_trace_call(self, name, pos, nogil=False):
|
2455 |
+
self.putln('__Pyx_TraceCall("%s", %s[%s], %s, %d, %s);' % (
|
2456 |
+
name, Naming.filetable_cname, self.lookup_filename(pos[0]), pos[1], nogil, self.error_goto(pos)))
|
2457 |
+
|
2458 |
+
def put_trace_exception(self):
|
2459 |
+
self.putln("__Pyx_TraceException();")
|
2460 |
+
|
2461 |
+
def put_trace_return(self, retvalue_cname, nogil=False):
|
2462 |
+
self.putln("__Pyx_TraceReturn(%s, %d);" % (retvalue_cname, nogil))
|
2463 |
+
|
2464 |
+
def putln_openmp(self, string):
|
2465 |
+
self.putln("#ifdef _OPENMP")
|
2466 |
+
self.putln(string)
|
2467 |
+
self.putln("#endif /* _OPENMP */")
|
2468 |
+
|
2469 |
+
def undef_builtin_expect(self, cond):
|
2470 |
+
"""
|
2471 |
+
Redefine the macros likely() and unlikely to no-ops, depending on
|
2472 |
+
condition 'cond'
|
2473 |
+
"""
|
2474 |
+
self.putln("#if %s" % cond)
|
2475 |
+
self.putln(" #undef likely")
|
2476 |
+
self.putln(" #undef unlikely")
|
2477 |
+
self.putln(" #define likely(x) (x)")
|
2478 |
+
self.putln(" #define unlikely(x) (x)")
|
2479 |
+
self.putln("#endif")
|
2480 |
+
|
2481 |
+
def redef_builtin_expect(self, cond):
|
2482 |
+
self.putln("#if %s" % cond)
|
2483 |
+
self.putln(" #undef likely")
|
2484 |
+
self.putln(" #undef unlikely")
|
2485 |
+
self.putln(" #define likely(x) __builtin_expect(!!(x), 1)")
|
2486 |
+
self.putln(" #define unlikely(x) __builtin_expect(!!(x), 0)")
|
2487 |
+
self.putln("#endif")
|
2488 |
+
|
2489 |
+
|
2490 |
+
class PyrexCodeWriter(object):
|
2491 |
+
# f file output file
|
2492 |
+
# level int indentation level
|
2493 |
+
|
2494 |
+
def __init__(self, outfile_name):
|
2495 |
+
self.f = Utils.open_new_file(outfile_name)
|
2496 |
+
self.level = 0
|
2497 |
+
|
2498 |
+
def putln(self, code):
|
2499 |
+
self.f.write("%s%s\n" % (" " * self.level, code))
|
2500 |
+
|
2501 |
+
def indent(self):
|
2502 |
+
self.level += 1
|
2503 |
+
|
2504 |
+
def dedent(self):
|
2505 |
+
self.level -= 1
|
2506 |
+
|
2507 |
+
class PyxCodeWriter(object):
|
2508 |
+
"""
|
2509 |
+
Can be used for writing out some Cython code. To use the indenter
|
2510 |
+
functionality, the Cython.Compiler.Importer module will have to be used
|
2511 |
+
to load the code to support python 2.4
|
2512 |
+
"""
|
2513 |
+
|
2514 |
+
def __init__(self, buffer=None, indent_level=0, context=None, encoding='ascii'):
|
2515 |
+
self.buffer = buffer or StringIOTree()
|
2516 |
+
self.level = indent_level
|
2517 |
+
self.context = context
|
2518 |
+
self.encoding = encoding
|
2519 |
+
|
2520 |
+
def indent(self, levels=1):
|
2521 |
+
self.level += levels
|
2522 |
+
return True
|
2523 |
+
|
2524 |
+
def dedent(self, levels=1):
|
2525 |
+
self.level -= levels
|
2526 |
+
|
2527 |
+
def indenter(self, line):
|
2528 |
+
"""
|
2529 |
+
Instead of
|
2530 |
+
|
2531 |
+
with pyx_code.indenter("for i in range(10):"):
|
2532 |
+
pyx_code.putln("print i")
|
2533 |
+
|
2534 |
+
write
|
2535 |
+
|
2536 |
+
if pyx_code.indenter("for i in range(10);"):
|
2537 |
+
pyx_code.putln("print i")
|
2538 |
+
pyx_code.dedent()
|
2539 |
+
"""
|
2540 |
+
self.putln(line)
|
2541 |
+
self.indent()
|
2542 |
+
return True
|
2543 |
+
|
2544 |
+
def getvalue(self):
|
2545 |
+
result = self.buffer.getvalue()
|
2546 |
+
if isinstance(result, bytes):
|
2547 |
+
result = result.decode(self.encoding)
|
2548 |
+
return result
|
2549 |
+
|
2550 |
+
def putln(self, line, context=None):
|
2551 |
+
context = context or self.context
|
2552 |
+
if context:
|
2553 |
+
line = sub_tempita(line, context)
|
2554 |
+
self._putln(line)
|
2555 |
+
|
2556 |
+
def _putln(self, line):
|
2557 |
+
self.buffer.write("%s%s\n" % (self.level * " ", line))
|
2558 |
+
|
2559 |
+
def put_chunk(self, chunk, context=None):
|
2560 |
+
context = context or self.context
|
2561 |
+
if context:
|
2562 |
+
chunk = sub_tempita(chunk, context)
|
2563 |
+
|
2564 |
+
chunk = textwrap.dedent(chunk)
|
2565 |
+
for line in chunk.splitlines():
|
2566 |
+
self._putln(line)
|
2567 |
+
|
2568 |
+
def insertion_point(self):
|
2569 |
+
return PyxCodeWriter(self.buffer.insertion_point(), self.level,
|
2570 |
+
self.context)
|
2571 |
+
|
2572 |
+
def named_insertion_point(self, name):
|
2573 |
+
setattr(self, name, self.insertion_point())
|
2574 |
+
|
2575 |
+
|
2576 |
+
class ClosureTempAllocator(object):
|
2577 |
+
def __init__(self, klass):
|
2578 |
+
self.klass = klass
|
2579 |
+
self.temps_allocated = {}
|
2580 |
+
self.temps_free = {}
|
2581 |
+
self.temps_count = 0
|
2582 |
+
|
2583 |
+
def reset(self):
|
2584 |
+
for type, cnames in self.temps_allocated.items():
|
2585 |
+
self.temps_free[type] = list(cnames)
|
2586 |
+
|
2587 |
+
def allocate_temp(self, type):
|
2588 |
+
if type not in self.temps_allocated:
|
2589 |
+
self.temps_allocated[type] = []
|
2590 |
+
self.temps_free[type] = []
|
2591 |
+
elif self.temps_free[type]:
|
2592 |
+
return self.temps_free[type].pop(0)
|
2593 |
+
cname = '%s%d' % (Naming.codewriter_temp_prefix, self.temps_count)
|
2594 |
+
self.klass.declare_var(pos=None, name=cname, cname=cname, type=type, is_cdef=True)
|
2595 |
+
self.temps_allocated[type].append(cname)
|
2596 |
+
self.temps_count += 1
|
2597 |
+
return cname
|
venv/Lib/site-packages/Cython/Compiler/CodeGeneration.py
ADDED
@@ -0,0 +1,35 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from __future__ import absolute_import
|
2 |
+
|
3 |
+
from .Visitor import VisitorTransform
|
4 |
+
from .Nodes import StatListNode
|
5 |
+
|
6 |
+
|
7 |
+
class ExtractPxdCode(VisitorTransform):
|
8 |
+
"""
|
9 |
+
Finds nodes in a pxd file that should generate code, and
|
10 |
+
returns them in a StatListNode.
|
11 |
+
|
12 |
+
The result is a tuple (StatListNode, ModuleScope), i.e.
|
13 |
+
everything that is needed from the pxd after it is processed.
|
14 |
+
|
15 |
+
A purer approach would be to separately compile the pxd code,
|
16 |
+
but the result would have to be slightly more sophisticated
|
17 |
+
than pure strings (functions + wanted interned strings +
|
18 |
+
wanted utility code + wanted cached objects) so for now this
|
19 |
+
approach is taken.
|
20 |
+
"""
|
21 |
+
|
22 |
+
def __call__(self, root):
|
23 |
+
self.funcs = []
|
24 |
+
self.visitchildren(root)
|
25 |
+
return (StatListNode(root.pos, stats=self.funcs), root.scope)
|
26 |
+
|
27 |
+
def visit_FuncDefNode(self, node):
|
28 |
+
self.funcs.append(node)
|
29 |
+
# Do not visit children, nested funcdefnodes will
|
30 |
+
# also be moved by this action...
|
31 |
+
return node
|
32 |
+
|
33 |
+
def visit_Node(self, node):
|
34 |
+
self.visitchildren(node)
|
35 |
+
return node
|
venv/Lib/site-packages/Cython/Compiler/CythonScope.py
ADDED
@@ -0,0 +1,164 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from __future__ import absolute_import
|
2 |
+
|
3 |
+
from .Symtab import ModuleScope
|
4 |
+
from .PyrexTypes import *
|
5 |
+
from .UtilityCode import CythonUtilityCode
|
6 |
+
from .Errors import error
|
7 |
+
from .Scanning import StringSourceDescriptor
|
8 |
+
from . import MemoryView
|
9 |
+
|
10 |
+
|
11 |
+
class CythonScope(ModuleScope):
|
12 |
+
is_cython_builtin = 1
|
13 |
+
_cythonscope_initialized = False
|
14 |
+
|
15 |
+
def __init__(self, context):
|
16 |
+
ModuleScope.__init__(self, u'cython', None, None)
|
17 |
+
self.pxd_file_loaded = True
|
18 |
+
self.populate_cython_scope()
|
19 |
+
# The Main.Context object
|
20 |
+
self.context = context
|
21 |
+
|
22 |
+
for fused_type in (cy_integral_type, cy_floating_type, cy_numeric_type):
|
23 |
+
entry = self.declare_typedef(fused_type.name,
|
24 |
+
fused_type,
|
25 |
+
None,
|
26 |
+
cname='<error>')
|
27 |
+
entry.in_cinclude = True
|
28 |
+
|
29 |
+
def is_cpp(self):
|
30 |
+
# Allow C++ utility code in C++ contexts.
|
31 |
+
return self.context.cpp
|
32 |
+
|
33 |
+
def lookup_type(self, name):
|
34 |
+
# This function should go away when types are all first-level objects.
|
35 |
+
type = parse_basic_type(name)
|
36 |
+
if type:
|
37 |
+
return type
|
38 |
+
|
39 |
+
return super(CythonScope, self).lookup_type(name)
|
40 |
+
|
41 |
+
def lookup(self, name):
|
42 |
+
entry = super(CythonScope, self).lookup(name)
|
43 |
+
|
44 |
+
if entry is None and not self._cythonscope_initialized:
|
45 |
+
self.load_cythonscope()
|
46 |
+
entry = super(CythonScope, self).lookup(name)
|
47 |
+
|
48 |
+
return entry
|
49 |
+
|
50 |
+
def find_module(self, module_name, pos):
|
51 |
+
error("cython.%s is not available" % module_name, pos)
|
52 |
+
|
53 |
+
def find_submodule(self, module_name):
|
54 |
+
entry = self.entries.get(module_name, None)
|
55 |
+
if not entry:
|
56 |
+
self.load_cythonscope()
|
57 |
+
entry = self.entries.get(module_name, None)
|
58 |
+
|
59 |
+
if entry and entry.as_module:
|
60 |
+
return entry.as_module
|
61 |
+
else:
|
62 |
+
# TODO: fix find_submodule control flow so that we're not
|
63 |
+
# expected to create a submodule here (to protect CythonScope's
|
64 |
+
# possible immutability). Hack ourselves out of the situation
|
65 |
+
# for now.
|
66 |
+
raise error((StringSourceDescriptor(u"cython", u""), 0, 0),
|
67 |
+
"cython.%s is not available" % module_name)
|
68 |
+
|
69 |
+
def lookup_qualified_name(self, qname):
|
70 |
+
# ExprNode.as_cython_attribute generates qnames and we untangle it here...
|
71 |
+
name_path = qname.split(u'.')
|
72 |
+
scope = self
|
73 |
+
while len(name_path) > 1:
|
74 |
+
scope = scope.lookup_here(name_path[0])
|
75 |
+
if scope:
|
76 |
+
scope = scope.as_module
|
77 |
+
del name_path[0]
|
78 |
+
if scope is None:
|
79 |
+
return None
|
80 |
+
else:
|
81 |
+
return scope.lookup_here(name_path[0])
|
82 |
+
|
83 |
+
def populate_cython_scope(self):
|
84 |
+
# These are used to optimize isinstance in FinalOptimizePhase
|
85 |
+
type_object = self.declare_typedef(
|
86 |
+
'PyTypeObject',
|
87 |
+
base_type = c_void_type,
|
88 |
+
pos = None,
|
89 |
+
cname = 'PyTypeObject')
|
90 |
+
type_object.is_void = True
|
91 |
+
type_object_type = type_object.type
|
92 |
+
|
93 |
+
self.declare_cfunction(
|
94 |
+
'PyObject_TypeCheck',
|
95 |
+
CFuncType(c_bint_type, [CFuncTypeArg("o", py_object_type, None),
|
96 |
+
CFuncTypeArg("t", c_ptr_type(type_object_type), None)]),
|
97 |
+
pos = None,
|
98 |
+
defining = 1,
|
99 |
+
cname = 'PyObject_TypeCheck')
|
100 |
+
|
101 |
+
def load_cythonscope(self):
|
102 |
+
"""
|
103 |
+
Creates some entries for testing purposes and entries for
|
104 |
+
cython.array() and for cython.view.*.
|
105 |
+
"""
|
106 |
+
if self._cythonscope_initialized:
|
107 |
+
return
|
108 |
+
|
109 |
+
self._cythonscope_initialized = True
|
110 |
+
cython_testscope_utility_code.declare_in_scope(
|
111 |
+
self, cython_scope=self)
|
112 |
+
cython_test_extclass_utility_code.declare_in_scope(
|
113 |
+
self, cython_scope=self)
|
114 |
+
|
115 |
+
#
|
116 |
+
# The view sub-scope
|
117 |
+
#
|
118 |
+
self.viewscope = viewscope = ModuleScope(u'view', self, None)
|
119 |
+
self.declare_module('view', viewscope, None).as_module = viewscope
|
120 |
+
viewscope.is_cython_builtin = True
|
121 |
+
viewscope.pxd_file_loaded = True
|
122 |
+
|
123 |
+
cythonview_testscope_utility_code.declare_in_scope(
|
124 |
+
viewscope, cython_scope=self)
|
125 |
+
|
126 |
+
view_utility_scope = MemoryView.view_utility_code.declare_in_scope(
|
127 |
+
self.viewscope, cython_scope=self,
|
128 |
+
whitelist=MemoryView.view_utility_whitelist)
|
129 |
+
|
130 |
+
# self.entries["array"] = view_utility_scope.entries.pop("array")
|
131 |
+
|
132 |
+
|
133 |
+
def create_cython_scope(context):
|
134 |
+
# One could in fact probably make it a singleton,
|
135 |
+
# but not sure yet whether any code mutates it (which would kill reusing
|
136 |
+
# it across different contexts)
|
137 |
+
return CythonScope(context)
|
138 |
+
|
139 |
+
# Load test utilities for the cython scope
|
140 |
+
|
141 |
+
def load_testscope_utility(cy_util_name, **kwargs):
|
142 |
+
return CythonUtilityCode.load(cy_util_name, "TestCythonScope.pyx", **kwargs)
|
143 |
+
|
144 |
+
|
145 |
+
undecorated_methods_protos = UtilityCode(proto=u"""
|
146 |
+
/* These methods are undecorated and have therefore no prototype */
|
147 |
+
static PyObject *__pyx_TestClass_cdef_method(
|
148 |
+
struct __pyx_TestClass_obj *self, int value);
|
149 |
+
static PyObject *__pyx_TestClass_cpdef_method(
|
150 |
+
struct __pyx_TestClass_obj *self, int value, int skip_dispatch);
|
151 |
+
static PyObject *__pyx_TestClass_def_method(
|
152 |
+
PyObject *self, PyObject *value);
|
153 |
+
""")
|
154 |
+
|
155 |
+
cython_testscope_utility_code = load_testscope_utility("TestScope")
|
156 |
+
|
157 |
+
test_cython_utility_dep = load_testscope_utility("TestDep")
|
158 |
+
|
159 |
+
cython_test_extclass_utility_code = \
|
160 |
+
load_testscope_utility("TestClass", name="TestClass",
|
161 |
+
requires=[undecorated_methods_protos,
|
162 |
+
test_cython_utility_dep])
|
163 |
+
|
164 |
+
cythonview_testscope_utility_code = load_testscope_utility("View.TestScope")
|
venv/Lib/site-packages/Cython/Compiler/DebugFlags.py
ADDED
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Can be enabled at the command line with --debug-xxx.
|
2 |
+
|
3 |
+
debug_disposal_code = 0
|
4 |
+
debug_temp_alloc = 0
|
5 |
+
debug_coercion = 0
|
6 |
+
|
7 |
+
# Write comments into the C code that show where temporary variables
|
8 |
+
# are allocated and released.
|
9 |
+
debug_temp_code_comments = 0
|
10 |
+
|
11 |
+
# Write a call trace of the code generation phase into the C code.
|
12 |
+
debug_trace_code_generation = 0
|
13 |
+
|
14 |
+
# Do not replace exceptions with user-friendly error messages.
|
15 |
+
debug_no_exception_intercept = 0
|
16 |
+
|
17 |
+
# Print a message each time a new stage in the pipeline is entered.
|
18 |
+
debug_verbose_pipeline = 0
|
19 |
+
|
20 |
+
# Raise an exception when an error is encountered.
|
21 |
+
debug_exception_on_error = 0
|
venv/Lib/site-packages/Cython/Compiler/Errors.py
ADDED
@@ -0,0 +1,265 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#
|
2 |
+
# Errors
|
3 |
+
#
|
4 |
+
|
5 |
+
from __future__ import absolute_import
|
6 |
+
|
7 |
+
try:
|
8 |
+
from __builtin__ import basestring as any_string_type
|
9 |
+
except ImportError:
|
10 |
+
any_string_type = (bytes, str)
|
11 |
+
|
12 |
+
import sys
|
13 |
+
from contextlib import contextmanager
|
14 |
+
|
15 |
+
from ..Utils import open_new_file
|
16 |
+
from . import DebugFlags
|
17 |
+
from . import Options
|
18 |
+
|
19 |
+
|
20 |
+
class PyrexError(Exception):
|
21 |
+
pass
|
22 |
+
|
23 |
+
|
24 |
+
class PyrexWarning(Exception):
|
25 |
+
pass
|
26 |
+
|
27 |
+
|
28 |
+
def context(position):
|
29 |
+
source = position[0]
|
30 |
+
assert not (isinstance(source, any_string_type)), (
|
31 |
+
"Please replace filename strings with Scanning.FileSourceDescriptor instances %r" % source)
|
32 |
+
try:
|
33 |
+
F = source.get_lines()
|
34 |
+
except UnicodeDecodeError:
|
35 |
+
# file has an encoding problem
|
36 |
+
s = u"[unprintable code]\n"
|
37 |
+
else:
|
38 |
+
s = u''.join(F[max(0, position[1]-6):position[1]])
|
39 |
+
s = u'...\n%s%s^\n' % (s, u' '*(position[2]-1))
|
40 |
+
s = u'%s\n%s%s\n' % (u'-'*60, s, u'-'*60)
|
41 |
+
return s
|
42 |
+
|
43 |
+
def format_position(position):
|
44 |
+
if position:
|
45 |
+
return u"%s:%d:%d: " % (position[0].get_error_description(),
|
46 |
+
position[1], position[2])
|
47 |
+
return u''
|
48 |
+
|
49 |
+
def format_error(message, position):
|
50 |
+
if position:
|
51 |
+
pos_str = format_position(position)
|
52 |
+
cont = context(position)
|
53 |
+
message = u'\nError compiling Cython file:\n%s\n%s%s' % (cont, pos_str, message or u'')
|
54 |
+
return message
|
55 |
+
|
56 |
+
class CompileError(PyrexError):
|
57 |
+
|
58 |
+
def __init__(self, position = None, message = u""):
|
59 |
+
self.position = position
|
60 |
+
self.message_only = message
|
61 |
+
self.formatted_message = format_error(message, position)
|
62 |
+
self.reported = False
|
63 |
+
# Deprecated and withdrawn in 2.6:
|
64 |
+
# self.message = message
|
65 |
+
Exception.__init__(self, self.formatted_message)
|
66 |
+
# Python Exception subclass pickling is broken,
|
67 |
+
# see http://bugs.python.org/issue1692335
|
68 |
+
self.args = (position, message)
|
69 |
+
|
70 |
+
def __str__(self):
|
71 |
+
return self.formatted_message
|
72 |
+
|
73 |
+
class CompileWarning(PyrexWarning):
|
74 |
+
|
75 |
+
def __init__(self, position = None, message = ""):
|
76 |
+
self.position = position
|
77 |
+
# Deprecated and withdrawn in 2.6:
|
78 |
+
# self.message = message
|
79 |
+
Exception.__init__(self, format_position(position) + message)
|
80 |
+
|
81 |
+
class InternalError(Exception):
|
82 |
+
# If this is ever raised, there is a bug in the compiler.
|
83 |
+
|
84 |
+
def __init__(self, message):
|
85 |
+
self.message_only = message
|
86 |
+
Exception.__init__(self, u"Internal compiler error: %s"
|
87 |
+
% message)
|
88 |
+
|
89 |
+
class AbortError(Exception):
|
90 |
+
# Throw this to stop the compilation immediately.
|
91 |
+
|
92 |
+
def __init__(self, message):
|
93 |
+
self.message_only = message
|
94 |
+
Exception.__init__(self, u"Abort error: %s" % message)
|
95 |
+
|
96 |
+
class CompilerCrash(CompileError):
|
97 |
+
# raised when an unexpected exception occurs in a transform
|
98 |
+
def __init__(self, pos, context, message, cause, stacktrace=None):
|
99 |
+
if message:
|
100 |
+
message = u'\n' + message
|
101 |
+
else:
|
102 |
+
message = u'\n'
|
103 |
+
self.message_only = message
|
104 |
+
if context:
|
105 |
+
message = u"Compiler crash in %s%s" % (context, message)
|
106 |
+
if stacktrace:
|
107 |
+
import traceback
|
108 |
+
message += (
|
109 |
+
u'\n\nCompiler crash traceback from this point on:\n' +
|
110 |
+
u''.join(traceback.format_tb(stacktrace)))
|
111 |
+
if cause:
|
112 |
+
if not stacktrace:
|
113 |
+
message += u'\n'
|
114 |
+
message += u'%s: %s' % (cause.__class__.__name__, cause)
|
115 |
+
CompileError.__init__(self, pos, message)
|
116 |
+
# Python Exception subclass pickling is broken,
|
117 |
+
# see http://bugs.python.org/issue1692335
|
118 |
+
self.args = (pos, context, message, cause, stacktrace)
|
119 |
+
|
120 |
+
class NoElementTreeInstalledException(PyrexError):
|
121 |
+
"""raised when the user enabled options.gdb_debug but no ElementTree
|
122 |
+
implementation was found
|
123 |
+
"""
|
124 |
+
|
125 |
+
listing_file = None
|
126 |
+
num_errors = 0
|
127 |
+
echo_file = None
|
128 |
+
|
129 |
+
def open_listing_file(path, echo_to_stderr = 1):
|
130 |
+
# Begin a new error listing. If path is None, no file
|
131 |
+
# is opened, the error counter is just reset.
|
132 |
+
global listing_file, num_errors, echo_file
|
133 |
+
if path is not None:
|
134 |
+
listing_file = open_new_file(path)
|
135 |
+
else:
|
136 |
+
listing_file = None
|
137 |
+
if echo_to_stderr:
|
138 |
+
echo_file = sys.stderr
|
139 |
+
else:
|
140 |
+
echo_file = None
|
141 |
+
num_errors = 0
|
142 |
+
|
143 |
+
def close_listing_file():
|
144 |
+
global listing_file
|
145 |
+
if listing_file:
|
146 |
+
listing_file.close()
|
147 |
+
listing_file = None
|
148 |
+
|
149 |
+
def report_error(err, use_stack=True):
|
150 |
+
if error_stack and use_stack:
|
151 |
+
error_stack[-1].append(err)
|
152 |
+
else:
|
153 |
+
global num_errors
|
154 |
+
# See Main.py for why dual reporting occurs. Quick fix for now.
|
155 |
+
if err.reported: return
|
156 |
+
err.reported = True
|
157 |
+
try: line = u"%s\n" % err
|
158 |
+
except UnicodeEncodeError:
|
159 |
+
# Python <= 2.5 does this for non-ASCII Unicode exceptions
|
160 |
+
line = format_error(getattr(err, 'message_only', "[unprintable exception message]"),
|
161 |
+
getattr(err, 'position', None)) + u'\n'
|
162 |
+
if listing_file:
|
163 |
+
try: listing_file.write(line)
|
164 |
+
except UnicodeEncodeError:
|
165 |
+
listing_file.write(line.encode('ASCII', 'replace'))
|
166 |
+
if echo_file:
|
167 |
+
try: echo_file.write(line)
|
168 |
+
except UnicodeEncodeError:
|
169 |
+
echo_file.write(line.encode('ASCII', 'replace'))
|
170 |
+
num_errors += 1
|
171 |
+
if Options.fast_fail:
|
172 |
+
raise AbortError("fatal errors")
|
173 |
+
|
174 |
+
|
175 |
+
def error(position, message):
|
176 |
+
#print("Errors.error:", repr(position), repr(message)) ###
|
177 |
+
if position is None:
|
178 |
+
raise InternalError(message)
|
179 |
+
err = CompileError(position, message)
|
180 |
+
if DebugFlags.debug_exception_on_error: raise Exception(err) # debug
|
181 |
+
report_error(err)
|
182 |
+
return err
|
183 |
+
|
184 |
+
|
185 |
+
LEVEL = 1 # warn about all errors level 1 or higher
|
186 |
+
|
187 |
+
|
188 |
+
def message(position, message, level=1):
|
189 |
+
if level < LEVEL:
|
190 |
+
return
|
191 |
+
warn = CompileWarning(position, message)
|
192 |
+
line = "note: %s\n" % warn
|
193 |
+
if listing_file:
|
194 |
+
listing_file.write(line)
|
195 |
+
if echo_file:
|
196 |
+
echo_file.write(line)
|
197 |
+
return warn
|
198 |
+
|
199 |
+
|
200 |
+
def warning(position, message, level=0):
|
201 |
+
if level < LEVEL:
|
202 |
+
return
|
203 |
+
if Options.warning_errors and position:
|
204 |
+
return error(position, message)
|
205 |
+
warn = CompileWarning(position, message)
|
206 |
+
line = "warning: %s\n" % warn
|
207 |
+
if listing_file:
|
208 |
+
listing_file.write(line)
|
209 |
+
if echo_file:
|
210 |
+
echo_file.write(line)
|
211 |
+
return warn
|
212 |
+
|
213 |
+
|
214 |
+
_warn_once_seen = {}
|
215 |
+
def warn_once(position, message, level=0):
|
216 |
+
if level < LEVEL or message in _warn_once_seen:
|
217 |
+
return
|
218 |
+
warn = CompileWarning(position, message)
|
219 |
+
line = "warning: %s\n" % warn
|
220 |
+
if listing_file:
|
221 |
+
listing_file.write(line)
|
222 |
+
if echo_file:
|
223 |
+
echo_file.write(line)
|
224 |
+
_warn_once_seen[message] = True
|
225 |
+
return warn
|
226 |
+
|
227 |
+
|
228 |
+
# These functions can be used to momentarily suppress errors.
|
229 |
+
|
230 |
+
error_stack = []
|
231 |
+
|
232 |
+
|
233 |
+
def hold_errors():
|
234 |
+
error_stack.append([])
|
235 |
+
|
236 |
+
|
237 |
+
def release_errors(ignore=False):
|
238 |
+
held_errors = error_stack.pop()
|
239 |
+
if not ignore:
|
240 |
+
for err in held_errors:
|
241 |
+
report_error(err)
|
242 |
+
|
243 |
+
|
244 |
+
def held_errors():
|
245 |
+
return error_stack[-1]
|
246 |
+
|
247 |
+
|
248 |
+
# same as context manager:
|
249 |
+
|
250 |
+
@contextmanager
|
251 |
+
def local_errors(ignore=False):
|
252 |
+
errors = []
|
253 |
+
error_stack.append(errors)
|
254 |
+
try:
|
255 |
+
yield errors
|
256 |
+
finally:
|
257 |
+
release_errors(ignore=ignore)
|
258 |
+
|
259 |
+
|
260 |
+
# this module needs a redesign to support parallel cythonisation, but
|
261 |
+
# for now, the following works at least in sequential compiler runs
|
262 |
+
|
263 |
+
def reset():
|
264 |
+
_warn_once_seen.clear()
|
265 |
+
del error_stack[:]
|
venv/Lib/site-packages/Cython/Compiler/ExprNodes.py
ADDED
The diff for this file is too large to render.
See raw diff
|
|
venv/Lib/site-packages/Cython/Compiler/FlowControl.pxd
ADDED
@@ -0,0 +1,111 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from __future__ import absolute_import
|
2 |
+
|
3 |
+
cimport cython
|
4 |
+
|
5 |
+
from .Visitor cimport CythonTransform, TreeVisitor
|
6 |
+
|
7 |
+
cdef class ControlBlock:
|
8 |
+
cdef public set children
|
9 |
+
cdef public set parents
|
10 |
+
cdef public set positions
|
11 |
+
cdef public list stats
|
12 |
+
cdef public dict gen
|
13 |
+
cdef public set bounded
|
14 |
+
|
15 |
+
# Big integer bitsets
|
16 |
+
cdef public object i_input
|
17 |
+
cdef public object i_output
|
18 |
+
cdef public object i_gen
|
19 |
+
cdef public object i_kill
|
20 |
+
cdef public object i_state
|
21 |
+
|
22 |
+
cpdef bint empty(self)
|
23 |
+
cpdef detach(self)
|
24 |
+
cpdef add_child(self, block)
|
25 |
+
|
26 |
+
cdef class ExitBlock(ControlBlock):
|
27 |
+
cpdef bint empty(self)
|
28 |
+
|
29 |
+
cdef class NameAssignment:
|
30 |
+
cdef public bint is_arg
|
31 |
+
cdef public bint is_deletion
|
32 |
+
cdef public object lhs
|
33 |
+
cdef public object rhs
|
34 |
+
cdef public object entry
|
35 |
+
cdef public object pos
|
36 |
+
cdef public set refs
|
37 |
+
cdef public object bit
|
38 |
+
cdef public object inferred_type
|
39 |
+
|
40 |
+
cdef class AssignmentList:
|
41 |
+
cdef public object bit
|
42 |
+
cdef public object mask
|
43 |
+
cdef public list stats
|
44 |
+
|
45 |
+
cdef class AssignmentCollector(TreeVisitor):
|
46 |
+
cdef list assignments
|
47 |
+
|
48 |
+
@cython.final
|
49 |
+
cdef class ControlFlow:
|
50 |
+
cdef public set blocks
|
51 |
+
cdef public set entries
|
52 |
+
cdef public list loops
|
53 |
+
cdef public list exceptions
|
54 |
+
|
55 |
+
cdef public ControlBlock entry_point
|
56 |
+
cdef public ExitBlock exit_point
|
57 |
+
cdef public ControlBlock block
|
58 |
+
|
59 |
+
cdef public dict assmts
|
60 |
+
|
61 |
+
cpdef newblock(self, ControlBlock parent=*)
|
62 |
+
cpdef nextblock(self, ControlBlock parent=*)
|
63 |
+
cpdef bint is_tracked(self, entry)
|
64 |
+
cpdef bint is_statically_assigned(self, entry)
|
65 |
+
cpdef mark_position(self, node)
|
66 |
+
cpdef mark_assignment(self, lhs, rhs, entry)
|
67 |
+
cpdef mark_argument(self, lhs, rhs, entry)
|
68 |
+
cpdef mark_deletion(self, node, entry)
|
69 |
+
cpdef mark_reference(self, node, entry)
|
70 |
+
|
71 |
+
@cython.locals(block=ControlBlock, parent=ControlBlock, unreachable=set)
|
72 |
+
cpdef normalize(self)
|
73 |
+
|
74 |
+
@cython.locals(bit=object, assmts=AssignmentList,
|
75 |
+
block=ControlBlock)
|
76 |
+
cpdef initialize(self)
|
77 |
+
|
78 |
+
@cython.locals(assmts=AssignmentList, assmt=NameAssignment)
|
79 |
+
cpdef set map_one(self, istate, entry)
|
80 |
+
|
81 |
+
@cython.locals(block=ControlBlock, parent=ControlBlock)
|
82 |
+
cdef reaching_definitions(self)
|
83 |
+
|
84 |
+
cdef class Uninitialized:
|
85 |
+
pass
|
86 |
+
|
87 |
+
cdef class Unknown:
|
88 |
+
pass
|
89 |
+
|
90 |
+
|
91 |
+
cdef class MessageCollection:
|
92 |
+
cdef set messages
|
93 |
+
|
94 |
+
|
95 |
+
@cython.locals(dirty=bint, block=ControlBlock, parent=ControlBlock,
|
96 |
+
assmt=NameAssignment)
|
97 |
+
cdef check_definitions(ControlFlow flow, dict compiler_directives)
|
98 |
+
|
99 |
+
@cython.final
|
100 |
+
cdef class ControlFlowAnalysis(CythonTransform):
|
101 |
+
cdef object gv_ctx
|
102 |
+
cdef object constant_folder
|
103 |
+
cdef set reductions
|
104 |
+
cdef list env_stack
|
105 |
+
cdef list stack
|
106 |
+
cdef object env
|
107 |
+
cdef ControlFlow flow
|
108 |
+
cdef bint in_inplace_assignment
|
109 |
+
|
110 |
+
cpdef mark_assignment(self, lhs, rhs=*)
|
111 |
+
cpdef mark_position(self, node)
|
venv/Lib/site-packages/Cython/Compiler/FlowControl.py
ADDED
@@ -0,0 +1,1325 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from __future__ import absolute_import
|
2 |
+
|
3 |
+
import cython
|
4 |
+
cython.declare(PyrexTypes=object, ExprNodes=object, Nodes=object,
|
5 |
+
Builtin=object, InternalError=object, error=object, warning=object,
|
6 |
+
py_object_type=object, unspecified_type=object,
|
7 |
+
object_expr=object, fake_rhs_expr=object, TypedExprNode=object)
|
8 |
+
|
9 |
+
from . import Builtin
|
10 |
+
from . import ExprNodes
|
11 |
+
from . import Nodes
|
12 |
+
from . import Options
|
13 |
+
from .PyrexTypes import py_object_type, unspecified_type
|
14 |
+
from . import PyrexTypes
|
15 |
+
|
16 |
+
from .Visitor import TreeVisitor, CythonTransform
|
17 |
+
from .Errors import error, warning, InternalError
|
18 |
+
from .Optimize import ConstantFolding
|
19 |
+
|
20 |
+
|
21 |
+
class TypedExprNode(ExprNodes.ExprNode):
|
22 |
+
# Used for declaring assignments of a specified type without a known entry.
|
23 |
+
def __init__(self, type, may_be_none=None, pos=None):
|
24 |
+
super(TypedExprNode, self).__init__(pos)
|
25 |
+
self.type = type
|
26 |
+
self._may_be_none = may_be_none
|
27 |
+
|
28 |
+
def may_be_none(self):
|
29 |
+
return self._may_be_none != False
|
30 |
+
|
31 |
+
object_expr = TypedExprNode(py_object_type, may_be_none=True)
|
32 |
+
# Fake rhs to silence "unused variable" warning
|
33 |
+
fake_rhs_expr = TypedExprNode(unspecified_type)
|
34 |
+
|
35 |
+
|
36 |
+
class ControlBlock(object):
|
37 |
+
"""Control flow graph node. Sequence of assignments and name references.
|
38 |
+
|
39 |
+
children set of children nodes
|
40 |
+
parents set of parent nodes
|
41 |
+
positions set of position markers
|
42 |
+
|
43 |
+
stats list of block statements
|
44 |
+
gen dict of assignments generated by this block
|
45 |
+
bounded set of entries that are definitely bounded in this block
|
46 |
+
|
47 |
+
Example:
|
48 |
+
|
49 |
+
a = 1
|
50 |
+
b = a + c # 'c' is already bounded or exception here
|
51 |
+
|
52 |
+
stats = [Assignment(a), NameReference(a), NameReference(c),
|
53 |
+
Assignment(b)]
|
54 |
+
gen = {Entry(a): Assignment(a), Entry(b): Assignment(b)}
|
55 |
+
bounded = set([Entry(a), Entry(c)])
|
56 |
+
|
57 |
+
"""
|
58 |
+
|
59 |
+
def __init__(self):
|
60 |
+
self.children = set()
|
61 |
+
self.parents = set()
|
62 |
+
self.positions = set()
|
63 |
+
|
64 |
+
self.stats = []
|
65 |
+
self.gen = {}
|
66 |
+
self.bounded = set()
|
67 |
+
|
68 |
+
self.i_input = 0
|
69 |
+
self.i_output = 0
|
70 |
+
self.i_gen = 0
|
71 |
+
self.i_kill = 0
|
72 |
+
self.i_state = 0
|
73 |
+
|
74 |
+
def empty(self):
|
75 |
+
return (not self.stats and not self.positions)
|
76 |
+
|
77 |
+
def detach(self):
|
78 |
+
"""Detach block from parents and children."""
|
79 |
+
for child in self.children:
|
80 |
+
child.parents.remove(self)
|
81 |
+
for parent in self.parents:
|
82 |
+
parent.children.remove(self)
|
83 |
+
self.parents.clear()
|
84 |
+
self.children.clear()
|
85 |
+
|
86 |
+
def add_child(self, block):
|
87 |
+
self.children.add(block)
|
88 |
+
block.parents.add(self)
|
89 |
+
|
90 |
+
|
91 |
+
class ExitBlock(ControlBlock):
|
92 |
+
"""Non-empty exit point block."""
|
93 |
+
|
94 |
+
def empty(self):
|
95 |
+
return False
|
96 |
+
|
97 |
+
|
98 |
+
class AssignmentList(object):
|
99 |
+
def __init__(self):
|
100 |
+
self.stats = []
|
101 |
+
|
102 |
+
|
103 |
+
class ControlFlow(object):
|
104 |
+
"""Control-flow graph.
|
105 |
+
|
106 |
+
entry_point ControlBlock entry point for this graph
|
107 |
+
exit_point ControlBlock normal exit point
|
108 |
+
block ControlBlock current block
|
109 |
+
blocks set children nodes
|
110 |
+
entries set tracked entries
|
111 |
+
loops list stack for loop descriptors
|
112 |
+
exceptions list stack for exception descriptors
|
113 |
+
"""
|
114 |
+
|
115 |
+
def __init__(self):
|
116 |
+
self.blocks = set()
|
117 |
+
self.entries = set()
|
118 |
+
self.loops = []
|
119 |
+
self.exceptions = []
|
120 |
+
|
121 |
+
self.entry_point = ControlBlock()
|
122 |
+
self.exit_point = ExitBlock()
|
123 |
+
self.blocks.add(self.exit_point)
|
124 |
+
self.block = self.entry_point
|
125 |
+
|
126 |
+
def newblock(self, parent=None):
|
127 |
+
"""Create floating block linked to `parent` if given.
|
128 |
+
|
129 |
+
NOTE: Block is NOT added to self.blocks
|
130 |
+
"""
|
131 |
+
block = ControlBlock()
|
132 |
+
self.blocks.add(block)
|
133 |
+
if parent:
|
134 |
+
parent.add_child(block)
|
135 |
+
return block
|
136 |
+
|
137 |
+
def nextblock(self, parent=None):
|
138 |
+
"""Create block children block linked to current or `parent` if given.
|
139 |
+
|
140 |
+
NOTE: Block is added to self.blocks
|
141 |
+
"""
|
142 |
+
block = ControlBlock()
|
143 |
+
self.blocks.add(block)
|
144 |
+
if parent:
|
145 |
+
parent.add_child(block)
|
146 |
+
elif self.block:
|
147 |
+
self.block.add_child(block)
|
148 |
+
self.block = block
|
149 |
+
return self.block
|
150 |
+
|
151 |
+
def is_tracked(self, entry):
|
152 |
+
if entry.is_anonymous:
|
153 |
+
return False
|
154 |
+
return (entry.is_local or entry.is_pyclass_attr or entry.is_arg or
|
155 |
+
entry.from_closure or entry.in_closure or
|
156 |
+
entry.error_on_uninitialized)
|
157 |
+
|
158 |
+
def is_statically_assigned(self, entry):
|
159 |
+
if (entry.is_local and entry.is_variable and
|
160 |
+
(entry.type.is_struct_or_union or
|
161 |
+
entry.type.is_complex or
|
162 |
+
entry.type.is_array or
|
163 |
+
entry.type.is_cpp_class)):
|
164 |
+
# stack allocated structured variable => never uninitialised
|
165 |
+
return True
|
166 |
+
return False
|
167 |
+
|
168 |
+
def mark_position(self, node):
|
169 |
+
"""Mark position, will be used to draw graph nodes."""
|
170 |
+
if self.block:
|
171 |
+
self.block.positions.add(node.pos[:2])
|
172 |
+
|
173 |
+
def mark_assignment(self, lhs, rhs, entry):
|
174 |
+
if self.block and self.is_tracked(entry):
|
175 |
+
assignment = NameAssignment(lhs, rhs, entry)
|
176 |
+
self.block.stats.append(assignment)
|
177 |
+
self.block.gen[entry] = assignment
|
178 |
+
self.entries.add(entry)
|
179 |
+
|
180 |
+
def mark_argument(self, lhs, rhs, entry):
|
181 |
+
if self.block and self.is_tracked(entry):
|
182 |
+
assignment = Argument(lhs, rhs, entry)
|
183 |
+
self.block.stats.append(assignment)
|
184 |
+
self.block.gen[entry] = assignment
|
185 |
+
self.entries.add(entry)
|
186 |
+
|
187 |
+
def mark_deletion(self, node, entry):
|
188 |
+
if self.block and self.is_tracked(entry):
|
189 |
+
assignment = NameDeletion(node, entry)
|
190 |
+
self.block.stats.append(assignment)
|
191 |
+
self.block.gen[entry] = Uninitialized
|
192 |
+
self.entries.add(entry)
|
193 |
+
|
194 |
+
def mark_reference(self, node, entry):
|
195 |
+
if self.block and self.is_tracked(entry):
|
196 |
+
self.block.stats.append(NameReference(node, entry))
|
197 |
+
## XXX: We don't track expression evaluation order so we can't use
|
198 |
+
## XXX: successful reference as initialization sign.
|
199 |
+
## # Local variable is definitely bound after this reference
|
200 |
+
## if not node.allow_null:
|
201 |
+
## self.block.bounded.add(entry)
|
202 |
+
self.entries.add(entry)
|
203 |
+
|
204 |
+
def normalize(self):
|
205 |
+
"""Delete unreachable and orphan blocks."""
|
206 |
+
queue = set([self.entry_point])
|
207 |
+
visited = set()
|
208 |
+
while queue:
|
209 |
+
root = queue.pop()
|
210 |
+
visited.add(root)
|
211 |
+
for child in root.children:
|
212 |
+
if child not in visited:
|
213 |
+
queue.add(child)
|
214 |
+
unreachable = self.blocks - visited
|
215 |
+
for block in unreachable:
|
216 |
+
block.detach()
|
217 |
+
visited.remove(self.entry_point)
|
218 |
+
for block in visited:
|
219 |
+
if block.empty():
|
220 |
+
for parent in block.parents: # Re-parent
|
221 |
+
for child in block.children:
|
222 |
+
parent.add_child(child)
|
223 |
+
block.detach()
|
224 |
+
unreachable.add(block)
|
225 |
+
self.blocks -= unreachable
|
226 |
+
|
227 |
+
def initialize(self):
|
228 |
+
"""Set initial state, map assignments to bits."""
|
229 |
+
self.assmts = {}
|
230 |
+
|
231 |
+
bit = 1
|
232 |
+
for entry in self.entries:
|
233 |
+
assmts = AssignmentList()
|
234 |
+
assmts.mask = assmts.bit = bit
|
235 |
+
self.assmts[entry] = assmts
|
236 |
+
bit <<= 1
|
237 |
+
|
238 |
+
for block in self.blocks:
|
239 |
+
for stat in block.stats:
|
240 |
+
if isinstance(stat, NameAssignment):
|
241 |
+
stat.bit = bit
|
242 |
+
assmts = self.assmts[stat.entry]
|
243 |
+
assmts.stats.append(stat)
|
244 |
+
assmts.mask |= bit
|
245 |
+
bit <<= 1
|
246 |
+
|
247 |
+
for block in self.blocks:
|
248 |
+
for entry, stat in block.gen.items():
|
249 |
+
assmts = self.assmts[entry]
|
250 |
+
if stat is Uninitialized:
|
251 |
+
block.i_gen |= assmts.bit
|
252 |
+
else:
|
253 |
+
block.i_gen |= stat.bit
|
254 |
+
block.i_kill |= assmts.mask
|
255 |
+
block.i_output = block.i_gen
|
256 |
+
for entry in block.bounded:
|
257 |
+
block.i_kill |= self.assmts[entry].bit
|
258 |
+
|
259 |
+
for assmts in self.assmts.values():
|
260 |
+
self.entry_point.i_gen |= assmts.bit
|
261 |
+
self.entry_point.i_output = self.entry_point.i_gen
|
262 |
+
|
263 |
+
def map_one(self, istate, entry):
|
264 |
+
ret = set()
|
265 |
+
assmts = self.assmts[entry]
|
266 |
+
if istate & assmts.bit:
|
267 |
+
if self.is_statically_assigned(entry):
|
268 |
+
ret.add(StaticAssignment(entry))
|
269 |
+
elif entry.from_closure:
|
270 |
+
ret.add(Unknown)
|
271 |
+
else:
|
272 |
+
ret.add(Uninitialized)
|
273 |
+
for assmt in assmts.stats:
|
274 |
+
if istate & assmt.bit:
|
275 |
+
ret.add(assmt)
|
276 |
+
return ret
|
277 |
+
|
278 |
+
def reaching_definitions(self):
|
279 |
+
"""Per-block reaching definitions analysis."""
|
280 |
+
dirty = True
|
281 |
+
while dirty:
|
282 |
+
dirty = False
|
283 |
+
for block in self.blocks:
|
284 |
+
i_input = 0
|
285 |
+
for parent in block.parents:
|
286 |
+
i_input |= parent.i_output
|
287 |
+
i_output = (i_input & ~block.i_kill) | block.i_gen
|
288 |
+
if i_output != block.i_output:
|
289 |
+
dirty = True
|
290 |
+
block.i_input = i_input
|
291 |
+
block.i_output = i_output
|
292 |
+
|
293 |
+
|
294 |
+
class LoopDescr(object):
|
295 |
+
def __init__(self, next_block, loop_block):
|
296 |
+
self.next_block = next_block
|
297 |
+
self.loop_block = loop_block
|
298 |
+
self.exceptions = []
|
299 |
+
|
300 |
+
|
301 |
+
class ExceptionDescr(object):
|
302 |
+
"""Exception handling helper.
|
303 |
+
|
304 |
+
entry_point ControlBlock Exception handling entry point
|
305 |
+
finally_enter ControlBlock Normal finally clause entry point
|
306 |
+
finally_exit ControlBlock Normal finally clause exit point
|
307 |
+
"""
|
308 |
+
|
309 |
+
def __init__(self, entry_point, finally_enter=None, finally_exit=None):
|
310 |
+
self.entry_point = entry_point
|
311 |
+
self.finally_enter = finally_enter
|
312 |
+
self.finally_exit = finally_exit
|
313 |
+
|
314 |
+
|
315 |
+
class NameAssignment(object):
|
316 |
+
def __init__(self, lhs, rhs, entry):
|
317 |
+
if lhs.cf_state is None:
|
318 |
+
lhs.cf_state = set()
|
319 |
+
self.lhs = lhs
|
320 |
+
self.rhs = rhs
|
321 |
+
self.entry = entry
|
322 |
+
self.pos = lhs.pos
|
323 |
+
self.refs = set()
|
324 |
+
self.is_arg = False
|
325 |
+
self.is_deletion = False
|
326 |
+
self.inferred_type = None
|
327 |
+
|
328 |
+
def __repr__(self):
|
329 |
+
return '%s(entry=%r)' % (self.__class__.__name__, self.entry)
|
330 |
+
|
331 |
+
def infer_type(self):
|
332 |
+
self.inferred_type = self.rhs.infer_type(self.entry.scope)
|
333 |
+
return self.inferred_type
|
334 |
+
|
335 |
+
def type_dependencies(self):
|
336 |
+
return self.rhs.type_dependencies(self.entry.scope)
|
337 |
+
|
338 |
+
@property
|
339 |
+
def type(self):
|
340 |
+
if not self.entry.type.is_unspecified:
|
341 |
+
return self.entry.type
|
342 |
+
return self.inferred_type
|
343 |
+
|
344 |
+
|
345 |
+
class StaticAssignment(NameAssignment):
|
346 |
+
"""Initialised at declaration time, e.g. stack allocation."""
|
347 |
+
def __init__(self, entry):
|
348 |
+
if not entry.type.is_pyobject:
|
349 |
+
may_be_none = False
|
350 |
+
else:
|
351 |
+
may_be_none = None # unknown
|
352 |
+
lhs = TypedExprNode(
|
353 |
+
entry.type, may_be_none=may_be_none, pos=entry.pos)
|
354 |
+
super(StaticAssignment, self).__init__(lhs, lhs, entry)
|
355 |
+
|
356 |
+
def infer_type(self):
|
357 |
+
return self.entry.type
|
358 |
+
|
359 |
+
def type_dependencies(self):
|
360 |
+
return ()
|
361 |
+
|
362 |
+
|
363 |
+
class Argument(NameAssignment):
|
364 |
+
def __init__(self, lhs, rhs, entry):
|
365 |
+
NameAssignment.__init__(self, lhs, rhs, entry)
|
366 |
+
self.is_arg = True
|
367 |
+
|
368 |
+
|
369 |
+
class NameDeletion(NameAssignment):
|
370 |
+
def __init__(self, lhs, entry):
|
371 |
+
NameAssignment.__init__(self, lhs, lhs, entry)
|
372 |
+
self.is_deletion = True
|
373 |
+
|
374 |
+
def infer_type(self):
|
375 |
+
inferred_type = self.rhs.infer_type(self.entry.scope)
|
376 |
+
if (not inferred_type.is_pyobject and
|
377 |
+
inferred_type.can_coerce_to_pyobject(self.entry.scope)):
|
378 |
+
return py_object_type
|
379 |
+
self.inferred_type = inferred_type
|
380 |
+
return inferred_type
|
381 |
+
|
382 |
+
|
383 |
+
class Uninitialized(object):
|
384 |
+
"""Definitely not initialised yet."""
|
385 |
+
|
386 |
+
|
387 |
+
class Unknown(object):
|
388 |
+
"""Coming from outer closure, might be initialised or not."""
|
389 |
+
|
390 |
+
|
391 |
+
class NameReference(object):
|
392 |
+
def __init__(self, node, entry):
|
393 |
+
if node.cf_state is None:
|
394 |
+
node.cf_state = set()
|
395 |
+
self.node = node
|
396 |
+
self.entry = entry
|
397 |
+
self.pos = node.pos
|
398 |
+
|
399 |
+
def __repr__(self):
|
400 |
+
return '%s(entry=%r)' % (self.__class__.__name__, self.entry)
|
401 |
+
|
402 |
+
|
403 |
+
class ControlFlowState(list):
|
404 |
+
# Keeps track of Node's entry assignments
|
405 |
+
#
|
406 |
+
# cf_is_null [boolean] It is uninitialized
|
407 |
+
# cf_maybe_null [boolean] May be uninitialized
|
408 |
+
# is_single [boolean] Has only one assignment at this point
|
409 |
+
|
410 |
+
cf_maybe_null = False
|
411 |
+
cf_is_null = False
|
412 |
+
is_single = False
|
413 |
+
|
414 |
+
def __init__(self, state):
|
415 |
+
if Uninitialized in state:
|
416 |
+
state.discard(Uninitialized)
|
417 |
+
self.cf_maybe_null = True
|
418 |
+
if not state:
|
419 |
+
self.cf_is_null = True
|
420 |
+
elif Unknown in state:
|
421 |
+
state.discard(Unknown)
|
422 |
+
self.cf_maybe_null = True
|
423 |
+
else:
|
424 |
+
if len(state) == 1:
|
425 |
+
self.is_single = True
|
426 |
+
# XXX: Remove fake_rhs_expr
|
427 |
+
super(ControlFlowState, self).__init__(
|
428 |
+
[i for i in state if i.rhs is not fake_rhs_expr])
|
429 |
+
|
430 |
+
def one(self):
|
431 |
+
return self[0]
|
432 |
+
|
433 |
+
|
434 |
+
class GVContext(object):
|
435 |
+
"""Graphviz subgraph object."""
|
436 |
+
|
437 |
+
def __init__(self):
|
438 |
+
self.blockids = {}
|
439 |
+
self.nextid = 0
|
440 |
+
self.children = []
|
441 |
+
self.sources = {}
|
442 |
+
|
443 |
+
def add(self, child):
|
444 |
+
self.children.append(child)
|
445 |
+
|
446 |
+
def nodeid(self, block):
|
447 |
+
if block not in self.blockids:
|
448 |
+
self.blockids[block] = 'block%d' % self.nextid
|
449 |
+
self.nextid += 1
|
450 |
+
return self.blockids[block]
|
451 |
+
|
452 |
+
def extract_sources(self, block):
|
453 |
+
if not block.positions:
|
454 |
+
return ''
|
455 |
+
start = min(block.positions)
|
456 |
+
stop = max(block.positions)
|
457 |
+
srcdescr = start[0]
|
458 |
+
if not srcdescr in self.sources:
|
459 |
+
self.sources[srcdescr] = list(srcdescr.get_lines())
|
460 |
+
lines = self.sources[srcdescr]
|
461 |
+
return '\\n'.join([l.strip() for l in lines[start[1] - 1:stop[1]]])
|
462 |
+
|
463 |
+
def render(self, fp, name, annotate_defs=False):
|
464 |
+
"""Render graphviz dot graph"""
|
465 |
+
fp.write('digraph %s {\n' % name)
|
466 |
+
fp.write(' node [shape=box];\n')
|
467 |
+
for child in self.children:
|
468 |
+
child.render(fp, self, annotate_defs)
|
469 |
+
fp.write('}\n')
|
470 |
+
|
471 |
+
def escape(self, text):
|
472 |
+
return text.replace('"', '\\"').replace('\n', '\\n')
|
473 |
+
|
474 |
+
|
475 |
+
class GV(object):
|
476 |
+
"""Graphviz DOT renderer."""
|
477 |
+
|
478 |
+
def __init__(self, name, flow):
|
479 |
+
self.name = name
|
480 |
+
self.flow = flow
|
481 |
+
|
482 |
+
def render(self, fp, ctx, annotate_defs=False):
|
483 |
+
fp.write(' subgraph %s {\n' % self.name)
|
484 |
+
for block in self.flow.blocks:
|
485 |
+
label = ctx.extract_sources(block)
|
486 |
+
if annotate_defs:
|
487 |
+
for stat in block.stats:
|
488 |
+
if isinstance(stat, NameAssignment):
|
489 |
+
label += '\n %s [%s %s]' % (
|
490 |
+
stat.entry.name, 'deletion' if stat.is_deletion else 'definition', stat.pos[1])
|
491 |
+
elif isinstance(stat, NameReference):
|
492 |
+
if stat.entry:
|
493 |
+
label += '\n %s [reference %s]' % (stat.entry.name, stat.pos[1])
|
494 |
+
if not label:
|
495 |
+
label = 'empty'
|
496 |
+
pid = ctx.nodeid(block)
|
497 |
+
fp.write(' %s [label="%s"];\n' % (pid, ctx.escape(label)))
|
498 |
+
for block in self.flow.blocks:
|
499 |
+
pid = ctx.nodeid(block)
|
500 |
+
for child in block.children:
|
501 |
+
fp.write(' %s -> %s;\n' % (pid, ctx.nodeid(child)))
|
502 |
+
fp.write(' }\n')
|
503 |
+
|
504 |
+
|
505 |
+
class MessageCollection(object):
|
506 |
+
"""Collect error/warnings messages first then sort"""
|
507 |
+
def __init__(self):
|
508 |
+
self.messages = set()
|
509 |
+
|
510 |
+
def error(self, pos, message):
|
511 |
+
self.messages.add((pos, True, message))
|
512 |
+
|
513 |
+
def warning(self, pos, message):
|
514 |
+
self.messages.add((pos, False, message))
|
515 |
+
|
516 |
+
def report(self):
|
517 |
+
for pos, is_error, message in sorted(self.messages):
|
518 |
+
if is_error:
|
519 |
+
error(pos, message)
|
520 |
+
else:
|
521 |
+
warning(pos, message, 2)
|
522 |
+
|
523 |
+
|
524 |
+
def check_definitions(flow, compiler_directives):
|
525 |
+
flow.initialize()
|
526 |
+
flow.reaching_definitions()
|
527 |
+
|
528 |
+
# Track down state
|
529 |
+
assignments = set()
|
530 |
+
# Node to entry map
|
531 |
+
references = {}
|
532 |
+
assmt_nodes = set()
|
533 |
+
|
534 |
+
for block in flow.blocks:
|
535 |
+
i_state = block.i_input
|
536 |
+
for stat in block.stats:
|
537 |
+
i_assmts = flow.assmts[stat.entry]
|
538 |
+
state = flow.map_one(i_state, stat.entry)
|
539 |
+
if isinstance(stat, NameAssignment):
|
540 |
+
stat.lhs.cf_state.update(state)
|
541 |
+
assmt_nodes.add(stat.lhs)
|
542 |
+
i_state = i_state & ~i_assmts.mask
|
543 |
+
if stat.is_deletion:
|
544 |
+
i_state |= i_assmts.bit
|
545 |
+
else:
|
546 |
+
i_state |= stat.bit
|
547 |
+
assignments.add(stat)
|
548 |
+
if stat.rhs is not fake_rhs_expr:
|
549 |
+
stat.entry.cf_assignments.append(stat)
|
550 |
+
elif isinstance(stat, NameReference):
|
551 |
+
references[stat.node] = stat.entry
|
552 |
+
stat.entry.cf_references.append(stat)
|
553 |
+
stat.node.cf_state.update(state)
|
554 |
+
## if not stat.node.allow_null:
|
555 |
+
## i_state &= ~i_assmts.bit
|
556 |
+
## # after successful read, the state is known to be initialised
|
557 |
+
state.discard(Uninitialized)
|
558 |
+
state.discard(Unknown)
|
559 |
+
for assmt in state:
|
560 |
+
assmt.refs.add(stat)
|
561 |
+
|
562 |
+
# Check variable usage
|
563 |
+
warn_maybe_uninitialized = compiler_directives['warn.maybe_uninitialized']
|
564 |
+
warn_unused_result = compiler_directives['warn.unused_result']
|
565 |
+
warn_unused = compiler_directives['warn.unused']
|
566 |
+
warn_unused_arg = compiler_directives['warn.unused_arg']
|
567 |
+
|
568 |
+
messages = MessageCollection()
|
569 |
+
|
570 |
+
# assignment hints
|
571 |
+
for node in assmt_nodes:
|
572 |
+
if Uninitialized in node.cf_state:
|
573 |
+
node.cf_maybe_null = True
|
574 |
+
if len(node.cf_state) == 1:
|
575 |
+
node.cf_is_null = True
|
576 |
+
else:
|
577 |
+
node.cf_is_null = False
|
578 |
+
elif Unknown in node.cf_state:
|
579 |
+
node.cf_maybe_null = True
|
580 |
+
else:
|
581 |
+
node.cf_is_null = False
|
582 |
+
node.cf_maybe_null = False
|
583 |
+
|
584 |
+
# Find uninitialized references and cf-hints
|
585 |
+
for node, entry in references.items():
|
586 |
+
if Uninitialized in node.cf_state:
|
587 |
+
node.cf_maybe_null = True
|
588 |
+
if not entry.from_closure and len(node.cf_state) == 1:
|
589 |
+
node.cf_is_null = True
|
590 |
+
if (node.allow_null or entry.from_closure
|
591 |
+
or entry.is_pyclass_attr or entry.type.is_error):
|
592 |
+
pass # Can be uninitialized here
|
593 |
+
elif node.cf_is_null:
|
594 |
+
if entry.error_on_uninitialized or (
|
595 |
+
Options.error_on_uninitialized and (
|
596 |
+
entry.type.is_pyobject or entry.type.is_unspecified)):
|
597 |
+
messages.error(
|
598 |
+
node.pos,
|
599 |
+
"local variable '%s' referenced before assignment"
|
600 |
+
% entry.name)
|
601 |
+
else:
|
602 |
+
messages.warning(
|
603 |
+
node.pos,
|
604 |
+
"local variable '%s' referenced before assignment"
|
605 |
+
% entry.name)
|
606 |
+
elif warn_maybe_uninitialized:
|
607 |
+
messages.warning(
|
608 |
+
node.pos,
|
609 |
+
"local variable '%s' might be referenced before assignment"
|
610 |
+
% entry.name)
|
611 |
+
elif Unknown in node.cf_state:
|
612 |
+
# TODO: better cross-closure analysis to know when inner functions
|
613 |
+
# are being called before a variable is being set, and when
|
614 |
+
# a variable is known to be set before even defining the
|
615 |
+
# inner function, etc.
|
616 |
+
node.cf_maybe_null = True
|
617 |
+
else:
|
618 |
+
node.cf_is_null = False
|
619 |
+
node.cf_maybe_null = False
|
620 |
+
|
621 |
+
# Unused result
|
622 |
+
for assmt in assignments:
|
623 |
+
if (not assmt.refs and not assmt.entry.is_pyclass_attr
|
624 |
+
and not assmt.entry.in_closure):
|
625 |
+
if assmt.entry.cf_references and warn_unused_result:
|
626 |
+
if assmt.is_arg:
|
627 |
+
messages.warning(assmt.pos, "Unused argument value '%s'" %
|
628 |
+
assmt.entry.name)
|
629 |
+
else:
|
630 |
+
messages.warning(assmt.pos, "Unused result in '%s'" %
|
631 |
+
assmt.entry.name)
|
632 |
+
assmt.lhs.cf_used = False
|
633 |
+
|
634 |
+
# Unused entries
|
635 |
+
for entry in flow.entries:
|
636 |
+
if (not entry.cf_references
|
637 |
+
and not entry.is_pyclass_attr):
|
638 |
+
if entry.name != '_' and not entry.name.startswith('unused'):
|
639 |
+
# '_' is often used for unused variables, e.g. in loops
|
640 |
+
if entry.is_arg:
|
641 |
+
if warn_unused_arg:
|
642 |
+
messages.warning(entry.pos, "Unused argument '%s'" %
|
643 |
+
entry.name)
|
644 |
+
else:
|
645 |
+
if warn_unused:
|
646 |
+
messages.warning(entry.pos, "Unused entry '%s'" %
|
647 |
+
entry.name)
|
648 |
+
entry.cf_used = False
|
649 |
+
|
650 |
+
messages.report()
|
651 |
+
|
652 |
+
for node in assmt_nodes:
|
653 |
+
node.cf_state = ControlFlowState(node.cf_state)
|
654 |
+
for node in references:
|
655 |
+
node.cf_state = ControlFlowState(node.cf_state)
|
656 |
+
|
657 |
+
|
658 |
+
class AssignmentCollector(TreeVisitor):
|
659 |
+
def __init__(self):
|
660 |
+
super(AssignmentCollector, self).__init__()
|
661 |
+
self.assignments = []
|
662 |
+
|
663 |
+
def visit_Node(self):
|
664 |
+
self._visitchildren(self, None)
|
665 |
+
|
666 |
+
def visit_SingleAssignmentNode(self, node):
|
667 |
+
self.assignments.append((node.lhs, node.rhs))
|
668 |
+
|
669 |
+
def visit_CascadedAssignmentNode(self, node):
|
670 |
+
for lhs in node.lhs_list:
|
671 |
+
self.assignments.append((lhs, node.rhs))
|
672 |
+
|
673 |
+
|
674 |
+
class ControlFlowAnalysis(CythonTransform):
|
675 |
+
|
676 |
+
def visit_ModuleNode(self, node):
|
677 |
+
self.gv_ctx = GVContext()
|
678 |
+
self.constant_folder = ConstantFolding()
|
679 |
+
|
680 |
+
# Set of NameNode reductions
|
681 |
+
self.reductions = set()
|
682 |
+
|
683 |
+
self.in_inplace_assignment = False
|
684 |
+
self.env_stack = []
|
685 |
+
self.env = node.scope
|
686 |
+
self.stack = []
|
687 |
+
self.flow = ControlFlow()
|
688 |
+
self.visitchildren(node)
|
689 |
+
|
690 |
+
check_definitions(self.flow, self.current_directives)
|
691 |
+
|
692 |
+
dot_output = self.current_directives['control_flow.dot_output']
|
693 |
+
if dot_output:
|
694 |
+
annotate_defs = self.current_directives['control_flow.dot_annotate_defs']
|
695 |
+
fp = open(dot_output, 'wt')
|
696 |
+
try:
|
697 |
+
self.gv_ctx.render(fp, 'module', annotate_defs=annotate_defs)
|
698 |
+
finally:
|
699 |
+
fp.close()
|
700 |
+
return node
|
701 |
+
|
702 |
+
def visit_FuncDefNode(self, node):
|
703 |
+
for arg in node.args:
|
704 |
+
if arg.default:
|
705 |
+
self.visitchildren(arg)
|
706 |
+
self.visitchildren(node, ('decorators',))
|
707 |
+
self.env_stack.append(self.env)
|
708 |
+
self.env = node.local_scope
|
709 |
+
self.stack.append(self.flow)
|
710 |
+
self.flow = ControlFlow()
|
711 |
+
|
712 |
+
# Collect all entries
|
713 |
+
for entry in node.local_scope.entries.values():
|
714 |
+
if self.flow.is_tracked(entry):
|
715 |
+
self.flow.entries.add(entry)
|
716 |
+
|
717 |
+
self.mark_position(node)
|
718 |
+
# Function body block
|
719 |
+
self.flow.nextblock()
|
720 |
+
|
721 |
+
for arg in node.args:
|
722 |
+
self._visit(arg)
|
723 |
+
if node.star_arg:
|
724 |
+
self.flow.mark_argument(node.star_arg,
|
725 |
+
TypedExprNode(Builtin.tuple_type,
|
726 |
+
may_be_none=False),
|
727 |
+
node.star_arg.entry)
|
728 |
+
if node.starstar_arg:
|
729 |
+
self.flow.mark_argument(node.starstar_arg,
|
730 |
+
TypedExprNode(Builtin.dict_type,
|
731 |
+
may_be_none=False),
|
732 |
+
node.starstar_arg.entry)
|
733 |
+
self._visit(node.body)
|
734 |
+
# Workaround for generators
|
735 |
+
if node.is_generator:
|
736 |
+
self._visit(node.gbody.body)
|
737 |
+
|
738 |
+
# Exit point
|
739 |
+
if self.flow.block:
|
740 |
+
self.flow.block.add_child(self.flow.exit_point)
|
741 |
+
|
742 |
+
# Cleanup graph
|
743 |
+
self.flow.normalize()
|
744 |
+
check_definitions(self.flow, self.current_directives)
|
745 |
+
self.flow.blocks.add(self.flow.entry_point)
|
746 |
+
|
747 |
+
self.gv_ctx.add(GV(node.local_scope.name, self.flow))
|
748 |
+
|
749 |
+
self.flow = self.stack.pop()
|
750 |
+
self.env = self.env_stack.pop()
|
751 |
+
return node
|
752 |
+
|
753 |
+
def visit_DefNode(self, node):
|
754 |
+
node.used = True
|
755 |
+
return self.visit_FuncDefNode(node)
|
756 |
+
|
757 |
+
def visit_GeneratorBodyDefNode(self, node):
|
758 |
+
return node
|
759 |
+
|
760 |
+
def visit_CTypeDefNode(self, node):
|
761 |
+
return node
|
762 |
+
|
763 |
+
def mark_assignment(self, lhs, rhs=None):
|
764 |
+
if not self.flow.block:
|
765 |
+
return
|
766 |
+
if self.flow.exceptions:
|
767 |
+
exc_descr = self.flow.exceptions[-1]
|
768 |
+
self.flow.block.add_child(exc_descr.entry_point)
|
769 |
+
self.flow.nextblock()
|
770 |
+
|
771 |
+
if not rhs:
|
772 |
+
rhs = object_expr
|
773 |
+
if lhs.is_name:
|
774 |
+
if lhs.entry is not None:
|
775 |
+
entry = lhs.entry
|
776 |
+
else:
|
777 |
+
entry = self.env.lookup(lhs.name)
|
778 |
+
if entry is None: # TODO: This shouldn't happen...
|
779 |
+
return
|
780 |
+
self.flow.mark_assignment(lhs, rhs, entry)
|
781 |
+
elif lhs.is_sequence_constructor:
|
782 |
+
for i, arg in enumerate(lhs.args):
|
783 |
+
if not rhs or arg.is_starred:
|
784 |
+
item_node = None
|
785 |
+
else:
|
786 |
+
item_node = rhs.inferable_item_node(i)
|
787 |
+
self.mark_assignment(arg, item_node)
|
788 |
+
else:
|
789 |
+
self._visit(lhs)
|
790 |
+
|
791 |
+
if self.flow.exceptions:
|
792 |
+
exc_descr = self.flow.exceptions[-1]
|
793 |
+
self.flow.block.add_child(exc_descr.entry_point)
|
794 |
+
self.flow.nextblock()
|
795 |
+
|
796 |
+
def mark_position(self, node):
|
797 |
+
"""Mark position if DOT output is enabled."""
|
798 |
+
if self.current_directives['control_flow.dot_output']:
|
799 |
+
self.flow.mark_position(node)
|
800 |
+
|
801 |
+
def visit_FromImportStatNode(self, node):
|
802 |
+
for name, target in node.items:
|
803 |
+
if name != "*":
|
804 |
+
self.mark_assignment(target)
|
805 |
+
self.visitchildren(node)
|
806 |
+
return node
|
807 |
+
|
808 |
+
def visit_AssignmentNode(self, node):
|
809 |
+
raise InternalError("Unhandled assignment node")
|
810 |
+
|
811 |
+
def visit_SingleAssignmentNode(self, node):
|
812 |
+
self._visit(node.rhs)
|
813 |
+
self.mark_assignment(node.lhs, node.rhs)
|
814 |
+
return node
|
815 |
+
|
816 |
+
def visit_CascadedAssignmentNode(self, node):
|
817 |
+
self._visit(node.rhs)
|
818 |
+
for lhs in node.lhs_list:
|
819 |
+
self.mark_assignment(lhs, node.rhs)
|
820 |
+
return node
|
821 |
+
|
822 |
+
def visit_ParallelAssignmentNode(self, node):
|
823 |
+
collector = AssignmentCollector()
|
824 |
+
collector.visitchildren(node)
|
825 |
+
for lhs, rhs in collector.assignments:
|
826 |
+
self._visit(rhs)
|
827 |
+
for lhs, rhs in collector.assignments:
|
828 |
+
self.mark_assignment(lhs, rhs)
|
829 |
+
return node
|
830 |
+
|
831 |
+
def visit_InPlaceAssignmentNode(self, node):
|
832 |
+
self.in_inplace_assignment = True
|
833 |
+
self.visitchildren(node)
|
834 |
+
self.in_inplace_assignment = False
|
835 |
+
self.mark_assignment(node.lhs, self.constant_folder(node.create_binop_node()))
|
836 |
+
return node
|
837 |
+
|
838 |
+
def visit_DelStatNode(self, node):
|
839 |
+
for arg in node.args:
|
840 |
+
if arg.is_name:
|
841 |
+
entry = arg.entry or self.env.lookup(arg.name)
|
842 |
+
if entry.in_closure or entry.from_closure:
|
843 |
+
error(arg.pos,
|
844 |
+
"can not delete variable '%s' "
|
845 |
+
"referenced in nested scope" % entry.name)
|
846 |
+
if not node.ignore_nonexisting:
|
847 |
+
self._visit(arg) # mark reference
|
848 |
+
self.flow.mark_deletion(arg, entry)
|
849 |
+
else:
|
850 |
+
self._visit(arg)
|
851 |
+
return node
|
852 |
+
|
853 |
+
def visit_CArgDeclNode(self, node):
|
854 |
+
entry = self.env.lookup(node.name)
|
855 |
+
if entry:
|
856 |
+
may_be_none = not node.not_none
|
857 |
+
self.flow.mark_argument(
|
858 |
+
node, TypedExprNode(entry.type, may_be_none), entry)
|
859 |
+
return node
|
860 |
+
|
861 |
+
def visit_NameNode(self, node):
|
862 |
+
if self.flow.block:
|
863 |
+
entry = node.entry or self.env.lookup(node.name)
|
864 |
+
if entry:
|
865 |
+
self.flow.mark_reference(node, entry)
|
866 |
+
|
867 |
+
if entry in self.reductions and not self.in_inplace_assignment:
|
868 |
+
error(node.pos,
|
869 |
+
"Cannot read reduction variable in loop body")
|
870 |
+
|
871 |
+
return node
|
872 |
+
|
873 |
+
def visit_StatListNode(self, node):
|
874 |
+
if self.flow.block:
|
875 |
+
for stat in node.stats:
|
876 |
+
self._visit(stat)
|
877 |
+
if not self.flow.block:
|
878 |
+
stat.is_terminator = True
|
879 |
+
break
|
880 |
+
return node
|
881 |
+
|
882 |
+
def visit_Node(self, node):
|
883 |
+
self.visitchildren(node)
|
884 |
+
self.mark_position(node)
|
885 |
+
return node
|
886 |
+
|
887 |
+
def visit_SizeofVarNode(self, node):
|
888 |
+
return node
|
889 |
+
|
890 |
+
def visit_TypeidNode(self, node):
|
891 |
+
return node
|
892 |
+
|
893 |
+
def visit_IfStatNode(self, node):
|
894 |
+
next_block = self.flow.newblock()
|
895 |
+
parent = self.flow.block
|
896 |
+
# If clauses
|
897 |
+
for clause in node.if_clauses:
|
898 |
+
parent = self.flow.nextblock(parent)
|
899 |
+
self._visit(clause.condition)
|
900 |
+
self.flow.nextblock()
|
901 |
+
self._visit(clause.body)
|
902 |
+
if self.flow.block:
|
903 |
+
self.flow.block.add_child(next_block)
|
904 |
+
# Else clause
|
905 |
+
if node.else_clause:
|
906 |
+
self.flow.nextblock(parent=parent)
|
907 |
+
self._visit(node.else_clause)
|
908 |
+
if self.flow.block:
|
909 |
+
self.flow.block.add_child(next_block)
|
910 |
+
else:
|
911 |
+
parent.add_child(next_block)
|
912 |
+
|
913 |
+
if next_block.parents:
|
914 |
+
self.flow.block = next_block
|
915 |
+
else:
|
916 |
+
self.flow.block = None
|
917 |
+
return node
|
918 |
+
|
919 |
+
def visit_WhileStatNode(self, node):
|
920 |
+
condition_block = self.flow.nextblock()
|
921 |
+
next_block = self.flow.newblock()
|
922 |
+
# Condition block
|
923 |
+
self.flow.loops.append(LoopDescr(next_block, condition_block))
|
924 |
+
if node.condition:
|
925 |
+
self._visit(node.condition)
|
926 |
+
# Body block
|
927 |
+
self.flow.nextblock()
|
928 |
+
self._visit(node.body)
|
929 |
+
self.flow.loops.pop()
|
930 |
+
# Loop it
|
931 |
+
if self.flow.block:
|
932 |
+
self.flow.block.add_child(condition_block)
|
933 |
+
self.flow.block.add_child(next_block)
|
934 |
+
# Else clause
|
935 |
+
if node.else_clause:
|
936 |
+
self.flow.nextblock(parent=condition_block)
|
937 |
+
self._visit(node.else_clause)
|
938 |
+
if self.flow.block:
|
939 |
+
self.flow.block.add_child(next_block)
|
940 |
+
else:
|
941 |
+
condition_block.add_child(next_block)
|
942 |
+
|
943 |
+
if next_block.parents:
|
944 |
+
self.flow.block = next_block
|
945 |
+
else:
|
946 |
+
self.flow.block = None
|
947 |
+
return node
|
948 |
+
|
949 |
+
def mark_forloop_target(self, node):
|
950 |
+
# TODO: Remove redundancy with range optimization...
|
951 |
+
is_special = False
|
952 |
+
sequence = node.iterator.sequence
|
953 |
+
target = node.target
|
954 |
+
if isinstance(sequence, ExprNodes.SimpleCallNode):
|
955 |
+
function = sequence.function
|
956 |
+
if sequence.self is None and function.is_name:
|
957 |
+
entry = self.env.lookup(function.name)
|
958 |
+
if not entry or entry.is_builtin:
|
959 |
+
if function.name == 'reversed' and len(sequence.args) == 1:
|
960 |
+
sequence = sequence.args[0]
|
961 |
+
elif function.name == 'enumerate' and len(sequence.args) == 1:
|
962 |
+
if target.is_sequence_constructor and len(target.args) == 2:
|
963 |
+
iterator = sequence.args[0]
|
964 |
+
if iterator.is_name:
|
965 |
+
iterator_type = iterator.infer_type(self.env)
|
966 |
+
if iterator_type.is_builtin_type:
|
967 |
+
# assume that builtin types have a length within Py_ssize_t
|
968 |
+
self.mark_assignment(
|
969 |
+
target.args[0],
|
970 |
+
ExprNodes.IntNode(target.pos, value='PY_SSIZE_T_MAX',
|
971 |
+
type=PyrexTypes.c_py_ssize_t_type))
|
972 |
+
target = target.args[1]
|
973 |
+
sequence = sequence.args[0]
|
974 |
+
if isinstance(sequence, ExprNodes.SimpleCallNode):
|
975 |
+
function = sequence.function
|
976 |
+
if sequence.self is None and function.is_name:
|
977 |
+
entry = self.env.lookup(function.name)
|
978 |
+
if not entry or entry.is_builtin:
|
979 |
+
if function.name in ('range', 'xrange'):
|
980 |
+
is_special = True
|
981 |
+
for arg in sequence.args[:2]:
|
982 |
+
self.mark_assignment(target, arg)
|
983 |
+
if len(sequence.args) > 2:
|
984 |
+
self.mark_assignment(target, self.constant_folder(
|
985 |
+
ExprNodes.binop_node(node.pos,
|
986 |
+
'+',
|
987 |
+
sequence.args[0],
|
988 |
+
sequence.args[2])))
|
989 |
+
|
990 |
+
if not is_special:
|
991 |
+
# A for-loop basically translates to subsequent calls to
|
992 |
+
# __getitem__(), so using an IndexNode here allows us to
|
993 |
+
# naturally infer the base type of pointers, C arrays,
|
994 |
+
# Python strings, etc., while correctly falling back to an
|
995 |
+
# object type when the base type cannot be handled.
|
996 |
+
|
997 |
+
self.mark_assignment(target, node.item)
|
998 |
+
|
999 |
+
def visit_AsyncForStatNode(self, node):
|
1000 |
+
return self.visit_ForInStatNode(node)
|
1001 |
+
|
1002 |
+
def visit_ForInStatNode(self, node):
|
1003 |
+
condition_block = self.flow.nextblock()
|
1004 |
+
next_block = self.flow.newblock()
|
1005 |
+
# Condition with iterator
|
1006 |
+
self.flow.loops.append(LoopDescr(next_block, condition_block))
|
1007 |
+
self._visit(node.iterator)
|
1008 |
+
# Target assignment
|
1009 |
+
self.flow.nextblock()
|
1010 |
+
|
1011 |
+
if isinstance(node, Nodes.ForInStatNode):
|
1012 |
+
self.mark_forloop_target(node)
|
1013 |
+
elif isinstance(node, Nodes.AsyncForStatNode):
|
1014 |
+
# not entirely correct, but good enough for now
|
1015 |
+
self.mark_assignment(node.target, node.item)
|
1016 |
+
else: # Parallel
|
1017 |
+
self.mark_assignment(node.target)
|
1018 |
+
|
1019 |
+
# Body block
|
1020 |
+
if isinstance(node, Nodes.ParallelRangeNode):
|
1021 |
+
# In case of an invalid
|
1022 |
+
self._delete_privates(node, exclude=node.target.entry)
|
1023 |
+
|
1024 |
+
self.flow.nextblock()
|
1025 |
+
self._visit(node.body)
|
1026 |
+
self.flow.loops.pop()
|
1027 |
+
|
1028 |
+
# Loop it
|
1029 |
+
if self.flow.block:
|
1030 |
+
self.flow.block.add_child(condition_block)
|
1031 |
+
# Else clause
|
1032 |
+
if node.else_clause:
|
1033 |
+
self.flow.nextblock(parent=condition_block)
|
1034 |
+
self._visit(node.else_clause)
|
1035 |
+
if self.flow.block:
|
1036 |
+
self.flow.block.add_child(next_block)
|
1037 |
+
else:
|
1038 |
+
condition_block.add_child(next_block)
|
1039 |
+
|
1040 |
+
if next_block.parents:
|
1041 |
+
self.flow.block = next_block
|
1042 |
+
else:
|
1043 |
+
self.flow.block = None
|
1044 |
+
return node
|
1045 |
+
|
1046 |
+
def _delete_privates(self, node, exclude=None):
|
1047 |
+
for private_node in node.assigned_nodes:
|
1048 |
+
if not exclude or private_node.entry is not exclude:
|
1049 |
+
self.flow.mark_deletion(private_node, private_node.entry)
|
1050 |
+
|
1051 |
+
def visit_ParallelRangeNode(self, node):
|
1052 |
+
reductions = self.reductions
|
1053 |
+
|
1054 |
+
# if node.target is None or not a NameNode, an error will have
|
1055 |
+
# been previously issued
|
1056 |
+
if hasattr(node.target, 'entry'):
|
1057 |
+
self.reductions = set(reductions)
|
1058 |
+
|
1059 |
+
for private_node in node.assigned_nodes:
|
1060 |
+
private_node.entry.error_on_uninitialized = True
|
1061 |
+
pos, reduction = node.assignments[private_node.entry]
|
1062 |
+
if reduction:
|
1063 |
+
self.reductions.add(private_node.entry)
|
1064 |
+
|
1065 |
+
node = self.visit_ForInStatNode(node)
|
1066 |
+
|
1067 |
+
self.reductions = reductions
|
1068 |
+
return node
|
1069 |
+
|
1070 |
+
def visit_ParallelWithBlockNode(self, node):
|
1071 |
+
for private_node in node.assigned_nodes:
|
1072 |
+
private_node.entry.error_on_uninitialized = True
|
1073 |
+
|
1074 |
+
self._delete_privates(node)
|
1075 |
+
self.visitchildren(node)
|
1076 |
+
self._delete_privates(node)
|
1077 |
+
|
1078 |
+
return node
|
1079 |
+
|
1080 |
+
def visit_ForFromStatNode(self, node):
|
1081 |
+
condition_block = self.flow.nextblock()
|
1082 |
+
next_block = self.flow.newblock()
|
1083 |
+
# Condition with iterator
|
1084 |
+
self.flow.loops.append(LoopDescr(next_block, condition_block))
|
1085 |
+
self._visit(node.bound1)
|
1086 |
+
self._visit(node.bound2)
|
1087 |
+
if node.step is not None:
|
1088 |
+
self._visit(node.step)
|
1089 |
+
# Target assignment
|
1090 |
+
self.flow.nextblock()
|
1091 |
+
self.mark_assignment(node.target, node.bound1)
|
1092 |
+
if node.step is not None:
|
1093 |
+
self.mark_assignment(node.target, self.constant_folder(
|
1094 |
+
ExprNodes.binop_node(node.pos, '+', node.bound1, node.step)))
|
1095 |
+
# Body block
|
1096 |
+
self.flow.nextblock()
|
1097 |
+
self._visit(node.body)
|
1098 |
+
self.flow.loops.pop()
|
1099 |
+
# Loop it
|
1100 |
+
if self.flow.block:
|
1101 |
+
self.flow.block.add_child(condition_block)
|
1102 |
+
# Else clause
|
1103 |
+
if node.else_clause:
|
1104 |
+
self.flow.nextblock(parent=condition_block)
|
1105 |
+
self._visit(node.else_clause)
|
1106 |
+
if self.flow.block:
|
1107 |
+
self.flow.block.add_child(next_block)
|
1108 |
+
else:
|
1109 |
+
condition_block.add_child(next_block)
|
1110 |
+
|
1111 |
+
if next_block.parents:
|
1112 |
+
self.flow.block = next_block
|
1113 |
+
else:
|
1114 |
+
self.flow.block = None
|
1115 |
+
return node
|
1116 |
+
|
1117 |
+
def visit_LoopNode(self, node):
|
1118 |
+
raise InternalError("Generic loops are not supported")
|
1119 |
+
|
1120 |
+
def visit_WithTargetAssignmentStatNode(self, node):
|
1121 |
+
self.mark_assignment(node.lhs, node.with_node.enter_call)
|
1122 |
+
return node
|
1123 |
+
|
1124 |
+
def visit_WithStatNode(self, node):
|
1125 |
+
self._visit(node.manager)
|
1126 |
+
self._visit(node.enter_call)
|
1127 |
+
self._visit(node.body)
|
1128 |
+
return node
|
1129 |
+
|
1130 |
+
def visit_TryExceptStatNode(self, node):
|
1131 |
+
# After exception handling
|
1132 |
+
next_block = self.flow.newblock()
|
1133 |
+
# Body block
|
1134 |
+
self.flow.newblock()
|
1135 |
+
# Exception entry point
|
1136 |
+
entry_point = self.flow.newblock()
|
1137 |
+
self.flow.exceptions.append(ExceptionDescr(entry_point))
|
1138 |
+
self.flow.nextblock()
|
1139 |
+
## XXX: links to exception handling point should be added by
|
1140 |
+
## XXX: children nodes
|
1141 |
+
self.flow.block.add_child(entry_point)
|
1142 |
+
self.flow.nextblock()
|
1143 |
+
self._visit(node.body)
|
1144 |
+
self.flow.exceptions.pop()
|
1145 |
+
|
1146 |
+
# After exception
|
1147 |
+
if self.flow.block:
|
1148 |
+
if node.else_clause:
|
1149 |
+
self.flow.nextblock()
|
1150 |
+
self._visit(node.else_clause)
|
1151 |
+
if self.flow.block:
|
1152 |
+
self.flow.block.add_child(next_block)
|
1153 |
+
|
1154 |
+
for clause in node.except_clauses:
|
1155 |
+
self.flow.block = entry_point
|
1156 |
+
if clause.pattern:
|
1157 |
+
for pattern in clause.pattern:
|
1158 |
+
self._visit(pattern)
|
1159 |
+
else:
|
1160 |
+
# TODO: handle * pattern
|
1161 |
+
pass
|
1162 |
+
entry_point = self.flow.newblock(parent=self.flow.block)
|
1163 |
+
self.flow.nextblock()
|
1164 |
+
if clause.target:
|
1165 |
+
self.mark_assignment(clause.target)
|
1166 |
+
self._visit(clause.body)
|
1167 |
+
if self.flow.block:
|
1168 |
+
self.flow.block.add_child(next_block)
|
1169 |
+
|
1170 |
+
if self.flow.exceptions:
|
1171 |
+
entry_point.add_child(self.flow.exceptions[-1].entry_point)
|
1172 |
+
|
1173 |
+
if next_block.parents:
|
1174 |
+
self.flow.block = next_block
|
1175 |
+
else:
|
1176 |
+
self.flow.block = None
|
1177 |
+
return node
|
1178 |
+
|
1179 |
+
def visit_TryFinallyStatNode(self, node):
|
1180 |
+
body_block = self.flow.nextblock()
|
1181 |
+
|
1182 |
+
# Exception entry point
|
1183 |
+
entry_point = self.flow.newblock()
|
1184 |
+
self.flow.block = entry_point
|
1185 |
+
self._visit(node.finally_except_clause)
|
1186 |
+
|
1187 |
+
if self.flow.block and self.flow.exceptions:
|
1188 |
+
self.flow.block.add_child(self.flow.exceptions[-1].entry_point)
|
1189 |
+
|
1190 |
+
# Normal execution
|
1191 |
+
finally_enter = self.flow.newblock()
|
1192 |
+
self.flow.block = finally_enter
|
1193 |
+
self._visit(node.finally_clause)
|
1194 |
+
finally_exit = self.flow.block
|
1195 |
+
|
1196 |
+
descr = ExceptionDescr(entry_point, finally_enter, finally_exit)
|
1197 |
+
self.flow.exceptions.append(descr)
|
1198 |
+
if self.flow.loops:
|
1199 |
+
self.flow.loops[-1].exceptions.append(descr)
|
1200 |
+
self.flow.block = body_block
|
1201 |
+
body_block.add_child(entry_point)
|
1202 |
+
self.flow.nextblock()
|
1203 |
+
self._visit(node.body)
|
1204 |
+
self.flow.exceptions.pop()
|
1205 |
+
if self.flow.loops:
|
1206 |
+
self.flow.loops[-1].exceptions.pop()
|
1207 |
+
|
1208 |
+
if self.flow.block:
|
1209 |
+
self.flow.block.add_child(finally_enter)
|
1210 |
+
if finally_exit:
|
1211 |
+
self.flow.block = self.flow.nextblock(parent=finally_exit)
|
1212 |
+
else:
|
1213 |
+
self.flow.block = None
|
1214 |
+
return node
|
1215 |
+
|
1216 |
+
def visit_RaiseStatNode(self, node):
|
1217 |
+
self.mark_position(node)
|
1218 |
+
self.visitchildren(node)
|
1219 |
+
if self.flow.exceptions:
|
1220 |
+
self.flow.block.add_child(self.flow.exceptions[-1].entry_point)
|
1221 |
+
self.flow.block = None
|
1222 |
+
return node
|
1223 |
+
|
1224 |
+
def visit_ReraiseStatNode(self, node):
|
1225 |
+
self.mark_position(node)
|
1226 |
+
if self.flow.exceptions:
|
1227 |
+
self.flow.block.add_child(self.flow.exceptions[-1].entry_point)
|
1228 |
+
self.flow.block = None
|
1229 |
+
return node
|
1230 |
+
|
1231 |
+
def visit_ReturnStatNode(self, node):
|
1232 |
+
self.mark_position(node)
|
1233 |
+
self.visitchildren(node)
|
1234 |
+
|
1235 |
+
outer_exception_handlers = iter(self.flow.exceptions[::-1])
|
1236 |
+
for handler in outer_exception_handlers:
|
1237 |
+
if handler.finally_enter:
|
1238 |
+
self.flow.block.add_child(handler.finally_enter)
|
1239 |
+
if handler.finally_exit:
|
1240 |
+
# 'return' goes to function exit, or to the next outer 'finally' clause
|
1241 |
+
exit_point = self.flow.exit_point
|
1242 |
+
for next_handler in outer_exception_handlers:
|
1243 |
+
if next_handler.finally_enter:
|
1244 |
+
exit_point = next_handler.finally_enter
|
1245 |
+
break
|
1246 |
+
handler.finally_exit.add_child(exit_point)
|
1247 |
+
break
|
1248 |
+
else:
|
1249 |
+
if self.flow.block:
|
1250 |
+
self.flow.block.add_child(self.flow.exit_point)
|
1251 |
+
self.flow.block = None
|
1252 |
+
return node
|
1253 |
+
|
1254 |
+
def visit_BreakStatNode(self, node):
|
1255 |
+
if not self.flow.loops:
|
1256 |
+
#error(node.pos, "break statement not inside loop")
|
1257 |
+
return node
|
1258 |
+
loop = self.flow.loops[-1]
|
1259 |
+
self.mark_position(node)
|
1260 |
+
for exception in loop.exceptions[::-1]:
|
1261 |
+
if exception.finally_enter:
|
1262 |
+
self.flow.block.add_child(exception.finally_enter)
|
1263 |
+
if exception.finally_exit:
|
1264 |
+
exception.finally_exit.add_child(loop.next_block)
|
1265 |
+
break
|
1266 |
+
else:
|
1267 |
+
self.flow.block.add_child(loop.next_block)
|
1268 |
+
self.flow.block = None
|
1269 |
+
return node
|
1270 |
+
|
1271 |
+
def visit_ContinueStatNode(self, node):
|
1272 |
+
if not self.flow.loops:
|
1273 |
+
#error(node.pos, "continue statement not inside loop")
|
1274 |
+
return node
|
1275 |
+
loop = self.flow.loops[-1]
|
1276 |
+
self.mark_position(node)
|
1277 |
+
for exception in loop.exceptions[::-1]:
|
1278 |
+
if exception.finally_enter:
|
1279 |
+
self.flow.block.add_child(exception.finally_enter)
|
1280 |
+
if exception.finally_exit:
|
1281 |
+
exception.finally_exit.add_child(loop.loop_block)
|
1282 |
+
break
|
1283 |
+
else:
|
1284 |
+
self.flow.block.add_child(loop.loop_block)
|
1285 |
+
self.flow.block = None
|
1286 |
+
return node
|
1287 |
+
|
1288 |
+
def visit_ComprehensionNode(self, node):
|
1289 |
+
if node.expr_scope:
|
1290 |
+
self.env_stack.append(self.env)
|
1291 |
+
self.env = node.expr_scope
|
1292 |
+
# Skip append node here
|
1293 |
+
self._visit(node.loop)
|
1294 |
+
if node.expr_scope:
|
1295 |
+
self.env = self.env_stack.pop()
|
1296 |
+
return node
|
1297 |
+
|
1298 |
+
def visit_ScopedExprNode(self, node):
|
1299 |
+
if node.expr_scope:
|
1300 |
+
self.env_stack.append(self.env)
|
1301 |
+
self.env = node.expr_scope
|
1302 |
+
self.visitchildren(node)
|
1303 |
+
if node.expr_scope:
|
1304 |
+
self.env = self.env_stack.pop()
|
1305 |
+
return node
|
1306 |
+
|
1307 |
+
def visit_PyClassDefNode(self, node):
|
1308 |
+
self.visitchildren(node, ('dict', 'metaclass',
|
1309 |
+
'mkw', 'bases', 'class_result'))
|
1310 |
+
self.flow.mark_assignment(node.target, node.classobj,
|
1311 |
+
self.env.lookup(node.name))
|
1312 |
+
self.env_stack.append(self.env)
|
1313 |
+
self.env = node.scope
|
1314 |
+
self.flow.nextblock()
|
1315 |
+
self.visitchildren(node, ('body',))
|
1316 |
+
self.flow.nextblock()
|
1317 |
+
self.env = self.env_stack.pop()
|
1318 |
+
return node
|
1319 |
+
|
1320 |
+
def visit_AmpersandNode(self, node):
|
1321 |
+
if node.operand.is_name:
|
1322 |
+
# Fake assignment to silence warning
|
1323 |
+
self.mark_assignment(node.operand, fake_rhs_expr)
|
1324 |
+
self.visitchildren(node)
|
1325 |
+
return node
|
venv/Lib/site-packages/Cython/Compiler/FusedNode.py
ADDED
@@ -0,0 +1,901 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from __future__ import absolute_import
|
2 |
+
|
3 |
+
import copy
|
4 |
+
|
5 |
+
from . import (ExprNodes, PyrexTypes, MemoryView,
|
6 |
+
ParseTreeTransforms, StringEncoding, Errors)
|
7 |
+
from .ExprNodes import CloneNode, ProxyNode, TupleNode
|
8 |
+
from .Nodes import FuncDefNode, CFuncDefNode, StatListNode, DefNode
|
9 |
+
from ..Utils import OrderedSet
|
10 |
+
|
11 |
+
|
12 |
+
class FusedCFuncDefNode(StatListNode):
|
13 |
+
"""
|
14 |
+
This node replaces a function with fused arguments. It deep-copies the
|
15 |
+
function for every permutation of fused types, and allocates a new local
|
16 |
+
scope for it. It keeps track of the original function in self.node, and
|
17 |
+
the entry of the original function in the symbol table is given the
|
18 |
+
'fused_cfunction' attribute which points back to us.
|
19 |
+
Then when a function lookup occurs (to e.g. call it), the call can be
|
20 |
+
dispatched to the right function.
|
21 |
+
|
22 |
+
node FuncDefNode the original function
|
23 |
+
nodes [FuncDefNode] list of copies of node with different specific types
|
24 |
+
py_func DefNode the fused python function subscriptable from
|
25 |
+
Python space
|
26 |
+
__signatures__ A DictNode mapping signature specialization strings
|
27 |
+
to PyCFunction nodes
|
28 |
+
resulting_fused_function PyCFunction for the fused DefNode that delegates
|
29 |
+
to specializations
|
30 |
+
fused_func_assignment Assignment of the fused function to the function name
|
31 |
+
defaults_tuple TupleNode of defaults (letting PyCFunctionNode build
|
32 |
+
defaults would result in many different tuples)
|
33 |
+
specialized_pycfuncs List of synthesized pycfunction nodes for the
|
34 |
+
specializations
|
35 |
+
code_object CodeObjectNode shared by all specializations and the
|
36 |
+
fused function
|
37 |
+
|
38 |
+
fused_compound_types All fused (compound) types (e.g. floating[:])
|
39 |
+
"""
|
40 |
+
|
41 |
+
__signatures__ = None
|
42 |
+
resulting_fused_function = None
|
43 |
+
fused_func_assignment = None
|
44 |
+
defaults_tuple = None
|
45 |
+
decorators = None
|
46 |
+
|
47 |
+
child_attrs = StatListNode.child_attrs + [
|
48 |
+
'__signatures__', 'resulting_fused_function', 'fused_func_assignment']
|
49 |
+
|
50 |
+
def __init__(self, node, env):
|
51 |
+
super(FusedCFuncDefNode, self).__init__(node.pos)
|
52 |
+
|
53 |
+
self.nodes = []
|
54 |
+
self.node = node
|
55 |
+
|
56 |
+
is_def = isinstance(self.node, DefNode)
|
57 |
+
if is_def:
|
58 |
+
# self.node.decorators = []
|
59 |
+
self.copy_def(env)
|
60 |
+
else:
|
61 |
+
self.copy_cdef(env)
|
62 |
+
|
63 |
+
# Perform some sanity checks. If anything fails, it's a bug
|
64 |
+
for n in self.nodes:
|
65 |
+
assert not n.entry.type.is_fused
|
66 |
+
assert not n.local_scope.return_type.is_fused
|
67 |
+
if node.return_type.is_fused:
|
68 |
+
assert not n.return_type.is_fused
|
69 |
+
|
70 |
+
if not is_def and n.cfunc_declarator.optional_arg_count:
|
71 |
+
assert n.type.op_arg_struct
|
72 |
+
|
73 |
+
node.entry.fused_cfunction = self
|
74 |
+
# Copy the nodes as AnalyseDeclarationsTransform will prepend
|
75 |
+
# self.py_func to self.stats, as we only want specialized
|
76 |
+
# CFuncDefNodes in self.nodes
|
77 |
+
self.stats = self.nodes[:]
|
78 |
+
|
79 |
+
def copy_def(self, env):
|
80 |
+
"""
|
81 |
+
Create a copy of the original def or lambda function for specialized
|
82 |
+
versions.
|
83 |
+
"""
|
84 |
+
fused_compound_types = PyrexTypes.unique(
|
85 |
+
[arg.type for arg in self.node.args if arg.type.is_fused])
|
86 |
+
fused_types = self._get_fused_base_types(fused_compound_types)
|
87 |
+
permutations = PyrexTypes.get_all_specialized_permutations(fused_types)
|
88 |
+
|
89 |
+
self.fused_compound_types = fused_compound_types
|
90 |
+
|
91 |
+
if self.node.entry in env.pyfunc_entries:
|
92 |
+
env.pyfunc_entries.remove(self.node.entry)
|
93 |
+
|
94 |
+
for cname, fused_to_specific in permutations:
|
95 |
+
copied_node = copy.deepcopy(self.node)
|
96 |
+
# keep signature object identity for special casing in DefNode.analyse_declarations()
|
97 |
+
copied_node.entry.signature = self.node.entry.signature
|
98 |
+
|
99 |
+
self._specialize_function_args(copied_node.args, fused_to_specific)
|
100 |
+
copied_node.return_type = self.node.return_type.specialize(
|
101 |
+
fused_to_specific)
|
102 |
+
|
103 |
+
copied_node.analyse_declarations(env)
|
104 |
+
# copied_node.is_staticmethod = self.node.is_staticmethod
|
105 |
+
# copied_node.is_classmethod = self.node.is_classmethod
|
106 |
+
self.create_new_local_scope(copied_node, env, fused_to_specific)
|
107 |
+
self.specialize_copied_def(copied_node, cname, self.node.entry,
|
108 |
+
fused_to_specific, fused_compound_types)
|
109 |
+
|
110 |
+
PyrexTypes.specialize_entry(copied_node.entry, cname)
|
111 |
+
copied_node.entry.used = True
|
112 |
+
env.entries[copied_node.entry.name] = copied_node.entry
|
113 |
+
|
114 |
+
if not self.replace_fused_typechecks(copied_node):
|
115 |
+
break
|
116 |
+
|
117 |
+
self.orig_py_func = self.node
|
118 |
+
self.py_func = self.make_fused_cpdef(self.node, env, is_def=True)
|
119 |
+
|
120 |
+
def copy_cdef(self, env):
|
121 |
+
"""
|
122 |
+
Create a copy of the original c(p)def function for all specialized
|
123 |
+
versions.
|
124 |
+
"""
|
125 |
+
permutations = self.node.type.get_all_specialized_permutations()
|
126 |
+
# print 'Node %s has %d specializations:' % (self.node.entry.name,
|
127 |
+
# len(permutations))
|
128 |
+
# import pprint; pprint.pprint([d for cname, d in permutations])
|
129 |
+
|
130 |
+
# Prevent copying of the python function
|
131 |
+
self.orig_py_func = orig_py_func = self.node.py_func
|
132 |
+
self.node.py_func = None
|
133 |
+
if orig_py_func:
|
134 |
+
env.pyfunc_entries.remove(orig_py_func.entry)
|
135 |
+
|
136 |
+
fused_types = self.node.type.get_fused_types()
|
137 |
+
self.fused_compound_types = fused_types
|
138 |
+
|
139 |
+
new_cfunc_entries = []
|
140 |
+
for cname, fused_to_specific in permutations:
|
141 |
+
copied_node = copy.deepcopy(self.node)
|
142 |
+
|
143 |
+
# Make the types in our CFuncType specific.
|
144 |
+
type = copied_node.type.specialize(fused_to_specific)
|
145 |
+
entry = copied_node.entry
|
146 |
+
type.specialize_entry(entry, cname)
|
147 |
+
|
148 |
+
# Reuse existing Entries (e.g. from .pxd files).
|
149 |
+
for i, orig_entry in enumerate(env.cfunc_entries):
|
150 |
+
if entry.cname == orig_entry.cname and type.same_as_resolved_type(orig_entry.type):
|
151 |
+
copied_node.entry = env.cfunc_entries[i]
|
152 |
+
if not copied_node.entry.func_cname:
|
153 |
+
copied_node.entry.func_cname = entry.func_cname
|
154 |
+
entry = copied_node.entry
|
155 |
+
type = entry.type
|
156 |
+
break
|
157 |
+
else:
|
158 |
+
new_cfunc_entries.append(entry)
|
159 |
+
|
160 |
+
copied_node.type = type
|
161 |
+
entry.type, type.entry = type, entry
|
162 |
+
|
163 |
+
entry.used = (entry.used or
|
164 |
+
self.node.entry.defined_in_pxd or
|
165 |
+
env.is_c_class_scope or
|
166 |
+
entry.is_cmethod)
|
167 |
+
|
168 |
+
if self.node.cfunc_declarator.optional_arg_count:
|
169 |
+
self.node.cfunc_declarator.declare_optional_arg_struct(
|
170 |
+
type, env, fused_cname=cname)
|
171 |
+
|
172 |
+
copied_node.return_type = type.return_type
|
173 |
+
self.create_new_local_scope(copied_node, env, fused_to_specific)
|
174 |
+
|
175 |
+
# Make the argument types in the CFuncDeclarator specific
|
176 |
+
self._specialize_function_args(copied_node.cfunc_declarator.args,
|
177 |
+
fused_to_specific)
|
178 |
+
|
179 |
+
# If a cpdef, declare all specialized cpdefs (this
|
180 |
+
# also calls analyse_declarations)
|
181 |
+
copied_node.declare_cpdef_wrapper(env)
|
182 |
+
if copied_node.py_func:
|
183 |
+
env.pyfunc_entries.remove(copied_node.py_func.entry)
|
184 |
+
|
185 |
+
self.specialize_copied_def(
|
186 |
+
copied_node.py_func, cname, self.node.entry.as_variable,
|
187 |
+
fused_to_specific, fused_types)
|
188 |
+
|
189 |
+
if not self.replace_fused_typechecks(copied_node):
|
190 |
+
break
|
191 |
+
|
192 |
+
# replace old entry with new entries
|
193 |
+
try:
|
194 |
+
cindex = env.cfunc_entries.index(self.node.entry)
|
195 |
+
except ValueError:
|
196 |
+
env.cfunc_entries.extend(new_cfunc_entries)
|
197 |
+
else:
|
198 |
+
env.cfunc_entries[cindex:cindex+1] = new_cfunc_entries
|
199 |
+
|
200 |
+
if orig_py_func:
|
201 |
+
self.py_func = self.make_fused_cpdef(orig_py_func, env,
|
202 |
+
is_def=False)
|
203 |
+
else:
|
204 |
+
self.py_func = orig_py_func
|
205 |
+
|
206 |
+
def _get_fused_base_types(self, fused_compound_types):
|
207 |
+
"""
|
208 |
+
Get a list of unique basic fused types, from a list of
|
209 |
+
(possibly) compound fused types.
|
210 |
+
"""
|
211 |
+
base_types = []
|
212 |
+
seen = set()
|
213 |
+
for fused_type in fused_compound_types:
|
214 |
+
fused_type.get_fused_types(result=base_types, seen=seen)
|
215 |
+
return base_types
|
216 |
+
|
217 |
+
def _specialize_function_args(self, args, fused_to_specific):
|
218 |
+
for arg in args:
|
219 |
+
if arg.type.is_fused:
|
220 |
+
arg.type = arg.type.specialize(fused_to_specific)
|
221 |
+
if arg.type.is_memoryviewslice:
|
222 |
+
arg.type.validate_memslice_dtype(arg.pos)
|
223 |
+
|
224 |
+
def create_new_local_scope(self, node, env, f2s):
|
225 |
+
"""
|
226 |
+
Create a new local scope for the copied node and append it to
|
227 |
+
self.nodes. A new local scope is needed because the arguments with the
|
228 |
+
fused types are already in the local scope, and we need the specialized
|
229 |
+
entries created after analyse_declarations on each specialized version
|
230 |
+
of the (CFunc)DefNode.
|
231 |
+
f2s is a dict mapping each fused type to its specialized version
|
232 |
+
"""
|
233 |
+
node.create_local_scope(env)
|
234 |
+
node.local_scope.fused_to_specific = f2s
|
235 |
+
|
236 |
+
# This is copied from the original function, set it to false to
|
237 |
+
# stop recursion
|
238 |
+
node.has_fused_arguments = False
|
239 |
+
self.nodes.append(node)
|
240 |
+
|
241 |
+
def specialize_copied_def(self, node, cname, py_entry, f2s, fused_compound_types):
|
242 |
+
"""Specialize the copy of a DefNode given the copied node,
|
243 |
+
the specialization cname and the original DefNode entry"""
|
244 |
+
fused_types = self._get_fused_base_types(fused_compound_types)
|
245 |
+
type_strings = [
|
246 |
+
PyrexTypes.specialization_signature_string(fused_type, f2s)
|
247 |
+
for fused_type in fused_types
|
248 |
+
]
|
249 |
+
|
250 |
+
node.specialized_signature_string = '|'.join(type_strings)
|
251 |
+
|
252 |
+
node.entry.pymethdef_cname = PyrexTypes.get_fused_cname(
|
253 |
+
cname, node.entry.pymethdef_cname)
|
254 |
+
node.entry.doc = py_entry.doc
|
255 |
+
node.entry.doc_cname = py_entry.doc_cname
|
256 |
+
|
257 |
+
def replace_fused_typechecks(self, copied_node):
|
258 |
+
"""
|
259 |
+
Branch-prune fused type checks like
|
260 |
+
|
261 |
+
if fused_t is int:
|
262 |
+
...
|
263 |
+
|
264 |
+
Returns whether an error was issued and whether we should stop in
|
265 |
+
in order to prevent a flood of errors.
|
266 |
+
"""
|
267 |
+
num_errors = Errors.num_errors
|
268 |
+
transform = ParseTreeTransforms.ReplaceFusedTypeChecks(
|
269 |
+
copied_node.local_scope)
|
270 |
+
transform(copied_node)
|
271 |
+
|
272 |
+
if Errors.num_errors > num_errors:
|
273 |
+
return False
|
274 |
+
|
275 |
+
return True
|
276 |
+
|
277 |
+
def _fused_instance_checks(self, normal_types, pyx_code, env):
|
278 |
+
"""
|
279 |
+
Generate Cython code for instance checks, matching an object to
|
280 |
+
specialized types.
|
281 |
+
"""
|
282 |
+
for specialized_type in normal_types:
|
283 |
+
# all_numeric = all_numeric and specialized_type.is_numeric
|
284 |
+
pyx_code.context.update(
|
285 |
+
py_type_name=specialized_type.py_type_name(),
|
286 |
+
specialized_type_name=specialized_type.specialization_string,
|
287 |
+
)
|
288 |
+
pyx_code.put_chunk(
|
289 |
+
u"""
|
290 |
+
if isinstance(arg, {{py_type_name}}):
|
291 |
+
dest_sig[{{dest_sig_idx}}] = '{{specialized_type_name}}'; break
|
292 |
+
""")
|
293 |
+
|
294 |
+
def _dtype_name(self, dtype):
|
295 |
+
if dtype.is_typedef:
|
296 |
+
return '___pyx_%s' % dtype
|
297 |
+
return str(dtype).replace(' ', '_')
|
298 |
+
|
299 |
+
def _dtype_type(self, dtype):
|
300 |
+
if dtype.is_typedef:
|
301 |
+
return self._dtype_name(dtype)
|
302 |
+
return str(dtype)
|
303 |
+
|
304 |
+
def _sizeof_dtype(self, dtype):
|
305 |
+
if dtype.is_pyobject:
|
306 |
+
return 'sizeof(void *)'
|
307 |
+
else:
|
308 |
+
return "sizeof(%s)" % self._dtype_type(dtype)
|
309 |
+
|
310 |
+
def _buffer_check_numpy_dtype_setup_cases(self, pyx_code):
|
311 |
+
"Setup some common cases to match dtypes against specializations"
|
312 |
+
if pyx_code.indenter("if kind in b'iu':"):
|
313 |
+
pyx_code.putln("pass")
|
314 |
+
pyx_code.named_insertion_point("dtype_int")
|
315 |
+
pyx_code.dedent()
|
316 |
+
|
317 |
+
if pyx_code.indenter("elif kind == b'f':"):
|
318 |
+
pyx_code.putln("pass")
|
319 |
+
pyx_code.named_insertion_point("dtype_float")
|
320 |
+
pyx_code.dedent()
|
321 |
+
|
322 |
+
if pyx_code.indenter("elif kind == b'c':"):
|
323 |
+
pyx_code.putln("pass")
|
324 |
+
pyx_code.named_insertion_point("dtype_complex")
|
325 |
+
pyx_code.dedent()
|
326 |
+
|
327 |
+
if pyx_code.indenter("elif kind == b'O':"):
|
328 |
+
pyx_code.putln("pass")
|
329 |
+
pyx_code.named_insertion_point("dtype_object")
|
330 |
+
pyx_code.dedent()
|
331 |
+
|
332 |
+
match = "dest_sig[{{dest_sig_idx}}] = '{{specialized_type_name}}'"
|
333 |
+
no_match = "dest_sig[{{dest_sig_idx}}] = None"
|
334 |
+
def _buffer_check_numpy_dtype(self, pyx_code, specialized_buffer_types, pythran_types):
|
335 |
+
"""
|
336 |
+
Match a numpy dtype object to the individual specializations.
|
337 |
+
"""
|
338 |
+
self._buffer_check_numpy_dtype_setup_cases(pyx_code)
|
339 |
+
|
340 |
+
for specialized_type in pythran_types+specialized_buffer_types:
|
341 |
+
final_type = specialized_type
|
342 |
+
if specialized_type.is_pythran_expr:
|
343 |
+
specialized_type = specialized_type.org_buffer
|
344 |
+
dtype = specialized_type.dtype
|
345 |
+
pyx_code.context.update(
|
346 |
+
itemsize_match=self._sizeof_dtype(dtype) + " == itemsize",
|
347 |
+
signed_match="not (%s_is_signed ^ dtype_signed)" % self._dtype_name(dtype),
|
348 |
+
dtype=dtype,
|
349 |
+
specialized_type_name=final_type.specialization_string)
|
350 |
+
|
351 |
+
dtypes = [
|
352 |
+
(dtype.is_int, pyx_code.dtype_int),
|
353 |
+
(dtype.is_float, pyx_code.dtype_float),
|
354 |
+
(dtype.is_complex, pyx_code.dtype_complex)
|
355 |
+
]
|
356 |
+
|
357 |
+
for dtype_category, codewriter in dtypes:
|
358 |
+
if dtype_category:
|
359 |
+
cond = '{{itemsize_match}} and (<Py_ssize_t>arg.ndim) == %d' % (
|
360 |
+
specialized_type.ndim,)
|
361 |
+
if dtype.is_int:
|
362 |
+
cond += ' and {{signed_match}}'
|
363 |
+
|
364 |
+
if final_type.is_pythran_expr:
|
365 |
+
cond += ' and arg_is_pythran_compatible'
|
366 |
+
|
367 |
+
if codewriter.indenter("if %s:" % cond):
|
368 |
+
#codewriter.putln("print 'buffer match found based on numpy dtype'")
|
369 |
+
codewriter.putln(self.match)
|
370 |
+
codewriter.putln("break")
|
371 |
+
codewriter.dedent()
|
372 |
+
|
373 |
+
def _buffer_parse_format_string_check(self, pyx_code, decl_code,
|
374 |
+
specialized_type, env):
|
375 |
+
"""
|
376 |
+
For each specialized type, try to coerce the object to a memoryview
|
377 |
+
slice of that type. This means obtaining a buffer and parsing the
|
378 |
+
format string.
|
379 |
+
TODO: separate buffer acquisition from format parsing
|
380 |
+
"""
|
381 |
+
dtype = specialized_type.dtype
|
382 |
+
if specialized_type.is_buffer:
|
383 |
+
axes = [('direct', 'strided')] * specialized_type.ndim
|
384 |
+
else:
|
385 |
+
axes = specialized_type.axes
|
386 |
+
|
387 |
+
memslice_type = PyrexTypes.MemoryViewSliceType(dtype, axes)
|
388 |
+
memslice_type.create_from_py_utility_code(env)
|
389 |
+
pyx_code.context.update(
|
390 |
+
coerce_from_py_func=memslice_type.from_py_function,
|
391 |
+
dtype=dtype)
|
392 |
+
decl_code.putln(
|
393 |
+
"{{memviewslice_cname}} {{coerce_from_py_func}}(object, int)")
|
394 |
+
|
395 |
+
pyx_code.context.update(
|
396 |
+
specialized_type_name=specialized_type.specialization_string,
|
397 |
+
sizeof_dtype=self._sizeof_dtype(dtype))
|
398 |
+
|
399 |
+
pyx_code.put_chunk(
|
400 |
+
u"""
|
401 |
+
# try {{dtype}}
|
402 |
+
if itemsize == -1 or itemsize == {{sizeof_dtype}}:
|
403 |
+
memslice = {{coerce_from_py_func}}(arg, 0)
|
404 |
+
if memslice.memview:
|
405 |
+
__PYX_XDEC_MEMVIEW(&memslice, 1)
|
406 |
+
# print 'found a match for the buffer through format parsing'
|
407 |
+
%s
|
408 |
+
break
|
409 |
+
else:
|
410 |
+
__pyx_PyErr_Clear()
|
411 |
+
""" % self.match)
|
412 |
+
|
413 |
+
def _buffer_checks(self, buffer_types, pythran_types, pyx_code, decl_code, env):
|
414 |
+
"""
|
415 |
+
Generate Cython code to match objects to buffer specializations.
|
416 |
+
First try to get a numpy dtype object and match it against the individual
|
417 |
+
specializations. If that fails, try naively to coerce the object
|
418 |
+
to each specialization, which obtains the buffer each time and tries
|
419 |
+
to match the format string.
|
420 |
+
"""
|
421 |
+
# The first thing to find a match in this loop breaks out of the loop
|
422 |
+
pyx_code.put_chunk(
|
423 |
+
u"""
|
424 |
+
""" + (u"arg_is_pythran_compatible = False" if pythran_types else u"") + u"""
|
425 |
+
if ndarray is not None:
|
426 |
+
if isinstance(arg, ndarray):
|
427 |
+
dtype = arg.dtype
|
428 |
+
""" + (u"arg_is_pythran_compatible = True" if pythran_types else u"") + u"""
|
429 |
+
elif __pyx_memoryview_check(arg):
|
430 |
+
arg_base = arg.base
|
431 |
+
if isinstance(arg_base, ndarray):
|
432 |
+
dtype = arg_base.dtype
|
433 |
+
else:
|
434 |
+
dtype = None
|
435 |
+
else:
|
436 |
+
dtype = None
|
437 |
+
|
438 |
+
itemsize = -1
|
439 |
+
if dtype is not None:
|
440 |
+
itemsize = dtype.itemsize
|
441 |
+
kind = ord(dtype.kind)
|
442 |
+
dtype_signed = kind == 'i'
|
443 |
+
""")
|
444 |
+
pyx_code.indent(2)
|
445 |
+
if pythran_types:
|
446 |
+
pyx_code.put_chunk(
|
447 |
+
u"""
|
448 |
+
# Pythran only supports the endianness of the current compiler
|
449 |
+
byteorder = dtype.byteorder
|
450 |
+
if byteorder == "<" and not __Pyx_Is_Little_Endian():
|
451 |
+
arg_is_pythran_compatible = False
|
452 |
+
elif byteorder == ">" and __Pyx_Is_Little_Endian():
|
453 |
+
arg_is_pythran_compatible = False
|
454 |
+
if arg_is_pythran_compatible:
|
455 |
+
cur_stride = itemsize
|
456 |
+
shape = arg.shape
|
457 |
+
strides = arg.strides
|
458 |
+
for i in range(arg.ndim-1, -1, -1):
|
459 |
+
if (<Py_ssize_t>strides[i]) != cur_stride:
|
460 |
+
arg_is_pythran_compatible = False
|
461 |
+
break
|
462 |
+
cur_stride *= <Py_ssize_t> shape[i]
|
463 |
+
else:
|
464 |
+
arg_is_pythran_compatible = not (arg.flags.f_contiguous and (<Py_ssize_t>arg.ndim) > 1)
|
465 |
+
""")
|
466 |
+
pyx_code.named_insertion_point("numpy_dtype_checks")
|
467 |
+
self._buffer_check_numpy_dtype(pyx_code, buffer_types, pythran_types)
|
468 |
+
pyx_code.dedent(2)
|
469 |
+
|
470 |
+
for specialized_type in buffer_types:
|
471 |
+
self._buffer_parse_format_string_check(
|
472 |
+
pyx_code, decl_code, specialized_type, env)
|
473 |
+
|
474 |
+
def _buffer_declarations(self, pyx_code, decl_code, all_buffer_types, pythran_types):
|
475 |
+
"""
|
476 |
+
If we have any buffer specializations, write out some variable
|
477 |
+
declarations and imports.
|
478 |
+
"""
|
479 |
+
decl_code.put_chunk(
|
480 |
+
u"""
|
481 |
+
ctypedef struct {{memviewslice_cname}}:
|
482 |
+
void *memview
|
483 |
+
|
484 |
+
void __PYX_XDEC_MEMVIEW({{memviewslice_cname}} *, int have_gil)
|
485 |
+
bint __pyx_memoryview_check(object)
|
486 |
+
""")
|
487 |
+
|
488 |
+
pyx_code.local_variable_declarations.put_chunk(
|
489 |
+
u"""
|
490 |
+
cdef {{memviewslice_cname}} memslice
|
491 |
+
cdef Py_ssize_t itemsize
|
492 |
+
cdef bint dtype_signed
|
493 |
+
cdef char kind
|
494 |
+
|
495 |
+
itemsize = -1
|
496 |
+
""")
|
497 |
+
|
498 |
+
if pythran_types:
|
499 |
+
pyx_code.local_variable_declarations.put_chunk(u"""
|
500 |
+
cdef bint arg_is_pythran_compatible
|
501 |
+
cdef Py_ssize_t cur_stride
|
502 |
+
""")
|
503 |
+
|
504 |
+
pyx_code.imports.put_chunk(
|
505 |
+
u"""
|
506 |
+
cdef type ndarray
|
507 |
+
ndarray = __Pyx_ImportNumPyArrayTypeIfAvailable()
|
508 |
+
""")
|
509 |
+
|
510 |
+
seen_typedefs = set()
|
511 |
+
seen_int_dtypes = set()
|
512 |
+
for buffer_type in all_buffer_types:
|
513 |
+
dtype = buffer_type.dtype
|
514 |
+
dtype_name = self._dtype_name(dtype)
|
515 |
+
if dtype.is_typedef:
|
516 |
+
if dtype_name not in seen_typedefs:
|
517 |
+
seen_typedefs.add(dtype_name)
|
518 |
+
decl_code.putln(
|
519 |
+
'ctypedef %s %s "%s"' % (dtype.resolve(), dtype_name,
|
520 |
+
dtype.empty_declaration_code()))
|
521 |
+
|
522 |
+
if buffer_type.dtype.is_int:
|
523 |
+
if str(dtype) not in seen_int_dtypes:
|
524 |
+
seen_int_dtypes.add(str(dtype))
|
525 |
+
pyx_code.context.update(dtype_name=dtype_name,
|
526 |
+
dtype_type=self._dtype_type(dtype))
|
527 |
+
pyx_code.local_variable_declarations.put_chunk(
|
528 |
+
u"""
|
529 |
+
cdef bint {{dtype_name}}_is_signed
|
530 |
+
{{dtype_name}}_is_signed = not (<{{dtype_type}}> -1 > 0)
|
531 |
+
""")
|
532 |
+
|
533 |
+
def _split_fused_types(self, arg):
|
534 |
+
"""
|
535 |
+
Specialize fused types and split into normal types and buffer types.
|
536 |
+
"""
|
537 |
+
specialized_types = PyrexTypes.get_specialized_types(arg.type)
|
538 |
+
|
539 |
+
# Prefer long over int, etc by sorting (see type classes in PyrexTypes.py)
|
540 |
+
specialized_types.sort()
|
541 |
+
|
542 |
+
seen_py_type_names = set()
|
543 |
+
normal_types, buffer_types, pythran_types = [], [], []
|
544 |
+
has_object_fallback = False
|
545 |
+
for specialized_type in specialized_types:
|
546 |
+
py_type_name = specialized_type.py_type_name()
|
547 |
+
if py_type_name:
|
548 |
+
if py_type_name in seen_py_type_names:
|
549 |
+
continue
|
550 |
+
seen_py_type_names.add(py_type_name)
|
551 |
+
if py_type_name == 'object':
|
552 |
+
has_object_fallback = True
|
553 |
+
else:
|
554 |
+
normal_types.append(specialized_type)
|
555 |
+
elif specialized_type.is_pythran_expr:
|
556 |
+
pythran_types.append(specialized_type)
|
557 |
+
elif specialized_type.is_buffer or specialized_type.is_memoryviewslice:
|
558 |
+
buffer_types.append(specialized_type)
|
559 |
+
|
560 |
+
return normal_types, buffer_types, pythran_types, has_object_fallback
|
561 |
+
|
562 |
+
def _unpack_argument(self, pyx_code):
|
563 |
+
pyx_code.put_chunk(
|
564 |
+
u"""
|
565 |
+
# PROCESSING ARGUMENT {{arg_tuple_idx}}
|
566 |
+
if {{arg_tuple_idx}} < len(<tuple>args):
|
567 |
+
arg = (<tuple>args)[{{arg_tuple_idx}}]
|
568 |
+
elif kwargs is not None and '{{arg.name}}' in <dict>kwargs:
|
569 |
+
arg = (<dict>kwargs)['{{arg.name}}']
|
570 |
+
else:
|
571 |
+
{{if arg.default}}
|
572 |
+
arg = (<tuple>defaults)[{{default_idx}}]
|
573 |
+
{{else}}
|
574 |
+
{{if arg_tuple_idx < min_positional_args}}
|
575 |
+
raise TypeError("Expected at least %d argument%s, got %d" % (
|
576 |
+
{{min_positional_args}}, {{'"s"' if min_positional_args != 1 else '""'}}, len(<tuple>args)))
|
577 |
+
{{else}}
|
578 |
+
raise TypeError("Missing keyword-only argument: '%s'" % "{{arg.default}}")
|
579 |
+
{{endif}}
|
580 |
+
{{endif}}
|
581 |
+
""")
|
582 |
+
|
583 |
+
def make_fused_cpdef(self, orig_py_func, env, is_def):
|
584 |
+
"""
|
585 |
+
This creates the function that is indexable from Python and does
|
586 |
+
runtime dispatch based on the argument types. The function gets the
|
587 |
+
arg tuple and kwargs dict (or None) and the defaults tuple
|
588 |
+
as arguments from the Binding Fused Function's tp_call.
|
589 |
+
"""
|
590 |
+
from . import TreeFragment, Code, UtilityCode
|
591 |
+
|
592 |
+
fused_types = self._get_fused_base_types([
|
593 |
+
arg.type for arg in self.node.args if arg.type.is_fused])
|
594 |
+
|
595 |
+
context = {
|
596 |
+
'memviewslice_cname': MemoryView.memviewslice_cname,
|
597 |
+
'func_args': self.node.args,
|
598 |
+
'n_fused': len(fused_types),
|
599 |
+
'min_positional_args':
|
600 |
+
self.node.num_required_args - self.node.num_required_kw_args
|
601 |
+
if is_def else
|
602 |
+
sum(1 for arg in self.node.args if arg.default is None),
|
603 |
+
'name': orig_py_func.entry.name,
|
604 |
+
}
|
605 |
+
|
606 |
+
pyx_code = Code.PyxCodeWriter(context=context)
|
607 |
+
decl_code = Code.PyxCodeWriter(context=context)
|
608 |
+
decl_code.put_chunk(
|
609 |
+
u"""
|
610 |
+
cdef extern from *:
|
611 |
+
void __pyx_PyErr_Clear "PyErr_Clear" ()
|
612 |
+
type __Pyx_ImportNumPyArrayTypeIfAvailable()
|
613 |
+
int __Pyx_Is_Little_Endian()
|
614 |
+
""")
|
615 |
+
decl_code.indent()
|
616 |
+
|
617 |
+
pyx_code.put_chunk(
|
618 |
+
u"""
|
619 |
+
def __pyx_fused_cpdef(signatures, args, kwargs, defaults):
|
620 |
+
# FIXME: use a typed signature - currently fails badly because
|
621 |
+
# default arguments inherit the types we specify here!
|
622 |
+
|
623 |
+
dest_sig = [None] * {{n_fused}}
|
624 |
+
|
625 |
+
if kwargs is not None and not kwargs:
|
626 |
+
kwargs = None
|
627 |
+
|
628 |
+
cdef Py_ssize_t i
|
629 |
+
|
630 |
+
# instance check body
|
631 |
+
""")
|
632 |
+
|
633 |
+
pyx_code.indent() # indent following code to function body
|
634 |
+
pyx_code.named_insertion_point("imports")
|
635 |
+
pyx_code.named_insertion_point("func_defs")
|
636 |
+
pyx_code.named_insertion_point("local_variable_declarations")
|
637 |
+
|
638 |
+
fused_index = 0
|
639 |
+
default_idx = 0
|
640 |
+
all_buffer_types = OrderedSet()
|
641 |
+
seen_fused_types = set()
|
642 |
+
for i, arg in enumerate(self.node.args):
|
643 |
+
if arg.type.is_fused:
|
644 |
+
arg_fused_types = arg.type.get_fused_types()
|
645 |
+
if len(arg_fused_types) > 1:
|
646 |
+
raise NotImplementedError("Determination of more than one fused base "
|
647 |
+
"type per argument is not implemented.")
|
648 |
+
fused_type = arg_fused_types[0]
|
649 |
+
|
650 |
+
if arg.type.is_fused and fused_type not in seen_fused_types:
|
651 |
+
seen_fused_types.add(fused_type)
|
652 |
+
|
653 |
+
context.update(
|
654 |
+
arg_tuple_idx=i,
|
655 |
+
arg=arg,
|
656 |
+
dest_sig_idx=fused_index,
|
657 |
+
default_idx=default_idx,
|
658 |
+
)
|
659 |
+
|
660 |
+
normal_types, buffer_types, pythran_types, has_object_fallback = self._split_fused_types(arg)
|
661 |
+
self._unpack_argument(pyx_code)
|
662 |
+
|
663 |
+
# 'unrolled' loop, first match breaks out of it
|
664 |
+
if pyx_code.indenter("while 1:"):
|
665 |
+
if normal_types:
|
666 |
+
self._fused_instance_checks(normal_types, pyx_code, env)
|
667 |
+
if buffer_types or pythran_types:
|
668 |
+
env.use_utility_code(Code.UtilityCode.load_cached("IsLittleEndian", "ModuleSetupCode.c"))
|
669 |
+
self._buffer_checks(buffer_types, pythran_types, pyx_code, decl_code, env)
|
670 |
+
if has_object_fallback:
|
671 |
+
pyx_code.context.update(specialized_type_name='object')
|
672 |
+
pyx_code.putln(self.match)
|
673 |
+
else:
|
674 |
+
pyx_code.putln(self.no_match)
|
675 |
+
pyx_code.putln("break")
|
676 |
+
pyx_code.dedent()
|
677 |
+
|
678 |
+
fused_index += 1
|
679 |
+
all_buffer_types.update(buffer_types)
|
680 |
+
all_buffer_types.update(ty.org_buffer for ty in pythran_types)
|
681 |
+
|
682 |
+
if arg.default:
|
683 |
+
default_idx += 1
|
684 |
+
|
685 |
+
if all_buffer_types:
|
686 |
+
self._buffer_declarations(pyx_code, decl_code, all_buffer_types, pythran_types)
|
687 |
+
env.use_utility_code(Code.UtilityCode.load_cached("Import", "ImportExport.c"))
|
688 |
+
env.use_utility_code(Code.UtilityCode.load_cached("ImportNumPyArray", "ImportExport.c"))
|
689 |
+
|
690 |
+
pyx_code.put_chunk(
|
691 |
+
u"""
|
692 |
+
candidates = []
|
693 |
+
for sig in <dict>signatures:
|
694 |
+
match_found = False
|
695 |
+
src_sig = sig.strip('()').split('|')
|
696 |
+
for i in range(len(dest_sig)):
|
697 |
+
dst_type = dest_sig[i]
|
698 |
+
if dst_type is not None:
|
699 |
+
if src_sig[i] == dst_type:
|
700 |
+
match_found = True
|
701 |
+
else:
|
702 |
+
match_found = False
|
703 |
+
break
|
704 |
+
|
705 |
+
if match_found:
|
706 |
+
candidates.append(sig)
|
707 |
+
|
708 |
+
if not candidates:
|
709 |
+
raise TypeError("No matching signature found")
|
710 |
+
elif len(candidates) > 1:
|
711 |
+
raise TypeError("Function call with ambiguous argument types")
|
712 |
+
else:
|
713 |
+
return (<dict>signatures)[candidates[0]]
|
714 |
+
""")
|
715 |
+
|
716 |
+
fragment_code = pyx_code.getvalue()
|
717 |
+
# print decl_code.getvalue()
|
718 |
+
# print fragment_code
|
719 |
+
from .Optimize import ConstantFolding
|
720 |
+
fragment = TreeFragment.TreeFragment(
|
721 |
+
fragment_code, level='module', pipeline=[ConstantFolding()])
|
722 |
+
ast = TreeFragment.SetPosTransform(self.node.pos)(fragment.root)
|
723 |
+
UtilityCode.declare_declarations_in_scope(
|
724 |
+
decl_code.getvalue(), env.global_scope())
|
725 |
+
ast.scope = env
|
726 |
+
# FIXME: for static methods of cdef classes, we build the wrong signature here: first arg becomes 'self'
|
727 |
+
ast.analyse_declarations(env)
|
728 |
+
py_func = ast.stats[-1] # the DefNode
|
729 |
+
self.fragment_scope = ast.scope
|
730 |
+
|
731 |
+
if isinstance(self.node, DefNode):
|
732 |
+
py_func.specialized_cpdefs = self.nodes[:]
|
733 |
+
else:
|
734 |
+
py_func.specialized_cpdefs = [n.py_func for n in self.nodes]
|
735 |
+
|
736 |
+
return py_func
|
737 |
+
|
738 |
+
def update_fused_defnode_entry(self, env):
|
739 |
+
copy_attributes = (
|
740 |
+
'name', 'pos', 'cname', 'func_cname', 'pyfunc_cname',
|
741 |
+
'pymethdef_cname', 'doc', 'doc_cname', 'is_member',
|
742 |
+
'scope'
|
743 |
+
)
|
744 |
+
|
745 |
+
entry = self.py_func.entry
|
746 |
+
|
747 |
+
for attr in copy_attributes:
|
748 |
+
setattr(entry, attr,
|
749 |
+
getattr(self.orig_py_func.entry, attr))
|
750 |
+
|
751 |
+
self.py_func.name = self.orig_py_func.name
|
752 |
+
self.py_func.doc = self.orig_py_func.doc
|
753 |
+
|
754 |
+
env.entries.pop('__pyx_fused_cpdef', None)
|
755 |
+
if isinstance(self.node, DefNode):
|
756 |
+
env.entries[entry.name] = entry
|
757 |
+
else:
|
758 |
+
env.entries[entry.name].as_variable = entry
|
759 |
+
|
760 |
+
env.pyfunc_entries.append(entry)
|
761 |
+
|
762 |
+
self.py_func.entry.fused_cfunction = self
|
763 |
+
for node in self.nodes:
|
764 |
+
if isinstance(self.node, DefNode):
|
765 |
+
node.fused_py_func = self.py_func
|
766 |
+
else:
|
767 |
+
node.py_func.fused_py_func = self.py_func
|
768 |
+
node.entry.as_variable = entry
|
769 |
+
|
770 |
+
self.synthesize_defnodes()
|
771 |
+
self.stats.append(self.__signatures__)
|
772 |
+
|
773 |
+
def analyse_expressions(self, env):
|
774 |
+
"""
|
775 |
+
Analyse the expressions. Take care to only evaluate default arguments
|
776 |
+
once and clone the result for all specializations
|
777 |
+
"""
|
778 |
+
for fused_compound_type in self.fused_compound_types:
|
779 |
+
for fused_type in fused_compound_type.get_fused_types():
|
780 |
+
for specialization_type in fused_type.types:
|
781 |
+
if specialization_type.is_complex:
|
782 |
+
specialization_type.create_declaration_utility_code(env)
|
783 |
+
|
784 |
+
if self.py_func:
|
785 |
+
self.__signatures__ = self.__signatures__.analyse_expressions(env)
|
786 |
+
self.py_func = self.py_func.analyse_expressions(env)
|
787 |
+
self.resulting_fused_function = self.resulting_fused_function.analyse_expressions(env)
|
788 |
+
self.fused_func_assignment = self.fused_func_assignment.analyse_expressions(env)
|
789 |
+
|
790 |
+
self.defaults = defaults = []
|
791 |
+
|
792 |
+
for arg in self.node.args:
|
793 |
+
if arg.default:
|
794 |
+
arg.default = arg.default.analyse_expressions(env)
|
795 |
+
defaults.append(ProxyNode(arg.default))
|
796 |
+
else:
|
797 |
+
defaults.append(None)
|
798 |
+
|
799 |
+
for i, stat in enumerate(self.stats):
|
800 |
+
stat = self.stats[i] = stat.analyse_expressions(env)
|
801 |
+
if isinstance(stat, FuncDefNode):
|
802 |
+
for arg, default in zip(stat.args, defaults):
|
803 |
+
if default is not None:
|
804 |
+
arg.default = CloneNode(default).coerce_to(arg.type, env)
|
805 |
+
|
806 |
+
if self.py_func:
|
807 |
+
args = [CloneNode(default) for default in defaults if default]
|
808 |
+
self.defaults_tuple = TupleNode(self.pos, args=args)
|
809 |
+
self.defaults_tuple = self.defaults_tuple.analyse_types(env, skip_children=True).coerce_to_pyobject(env)
|
810 |
+
self.defaults_tuple = ProxyNode(self.defaults_tuple)
|
811 |
+
self.code_object = ProxyNode(self.specialized_pycfuncs[0].code_object)
|
812 |
+
|
813 |
+
fused_func = self.resulting_fused_function.arg
|
814 |
+
fused_func.defaults_tuple = CloneNode(self.defaults_tuple)
|
815 |
+
fused_func.code_object = CloneNode(self.code_object)
|
816 |
+
|
817 |
+
for i, pycfunc in enumerate(self.specialized_pycfuncs):
|
818 |
+
pycfunc.code_object = CloneNode(self.code_object)
|
819 |
+
pycfunc = self.specialized_pycfuncs[i] = pycfunc.analyse_types(env)
|
820 |
+
pycfunc.defaults_tuple = CloneNode(self.defaults_tuple)
|
821 |
+
return self
|
822 |
+
|
823 |
+
def synthesize_defnodes(self):
|
824 |
+
"""
|
825 |
+
Create the __signatures__ dict of PyCFunctionNode specializations.
|
826 |
+
"""
|
827 |
+
if isinstance(self.nodes[0], CFuncDefNode):
|
828 |
+
nodes = [node.py_func for node in self.nodes]
|
829 |
+
else:
|
830 |
+
nodes = self.nodes
|
831 |
+
|
832 |
+
signatures = [StringEncoding.EncodedString(node.specialized_signature_string)
|
833 |
+
for node in nodes]
|
834 |
+
keys = [ExprNodes.StringNode(node.pos, value=sig)
|
835 |
+
for node, sig in zip(nodes, signatures)]
|
836 |
+
values = [ExprNodes.PyCFunctionNode.from_defnode(node, binding=True)
|
837 |
+
for node in nodes]
|
838 |
+
|
839 |
+
self.__signatures__ = ExprNodes.DictNode.from_pairs(self.pos, zip(keys, values))
|
840 |
+
|
841 |
+
self.specialized_pycfuncs = values
|
842 |
+
for pycfuncnode in values:
|
843 |
+
pycfuncnode.is_specialization = True
|
844 |
+
|
845 |
+
def generate_function_definitions(self, env, code):
|
846 |
+
if self.py_func:
|
847 |
+
self.py_func.pymethdef_required = True
|
848 |
+
self.fused_func_assignment.generate_function_definitions(env, code)
|
849 |
+
|
850 |
+
for stat in self.stats:
|
851 |
+
if isinstance(stat, FuncDefNode) and stat.entry.used:
|
852 |
+
code.mark_pos(stat.pos)
|
853 |
+
stat.generate_function_definitions(env, code)
|
854 |
+
|
855 |
+
def generate_execution_code(self, code):
|
856 |
+
# Note: all def function specialization are wrapped in PyCFunction
|
857 |
+
# nodes in the self.__signatures__ dictnode.
|
858 |
+
for default in self.defaults:
|
859 |
+
if default is not None:
|
860 |
+
default.generate_evaluation_code(code)
|
861 |
+
|
862 |
+
if self.py_func:
|
863 |
+
self.defaults_tuple.generate_evaluation_code(code)
|
864 |
+
self.code_object.generate_evaluation_code(code)
|
865 |
+
|
866 |
+
for stat in self.stats:
|
867 |
+
code.mark_pos(stat.pos)
|
868 |
+
if isinstance(stat, ExprNodes.ExprNode):
|
869 |
+
stat.generate_evaluation_code(code)
|
870 |
+
else:
|
871 |
+
stat.generate_execution_code(code)
|
872 |
+
|
873 |
+
if self.__signatures__:
|
874 |
+
self.resulting_fused_function.generate_evaluation_code(code)
|
875 |
+
|
876 |
+
code.putln(
|
877 |
+
"((__pyx_FusedFunctionObject *) %s)->__signatures__ = %s;" %
|
878 |
+
(self.resulting_fused_function.result(),
|
879 |
+
self.__signatures__.result()))
|
880 |
+
code.put_giveref(self.__signatures__.result())
|
881 |
+
self.__signatures__.generate_post_assignment_code(code)
|
882 |
+
self.__signatures__.free_temps(code)
|
883 |
+
|
884 |
+
self.fused_func_assignment.generate_execution_code(code)
|
885 |
+
|
886 |
+
# Dispose of results
|
887 |
+
self.resulting_fused_function.generate_disposal_code(code)
|
888 |
+
self.resulting_fused_function.free_temps(code)
|
889 |
+
self.defaults_tuple.generate_disposal_code(code)
|
890 |
+
self.defaults_tuple.free_temps(code)
|
891 |
+
self.code_object.generate_disposal_code(code)
|
892 |
+
self.code_object.free_temps(code)
|
893 |
+
|
894 |
+
for default in self.defaults:
|
895 |
+
if default is not None:
|
896 |
+
default.generate_disposal_code(code)
|
897 |
+
default.free_temps(code)
|
898 |
+
|
899 |
+
def annotate(self, code):
|
900 |
+
for stat in self.stats:
|
901 |
+
stat.annotate(code)
|