Cython 3.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (316) hide show
  1. Cython/Build/BuildExecutable.py +169 -0
  2. Cython/Build/Cache.py +199 -0
  3. Cython/Build/Cythonize.py +323 -0
  4. Cython/Build/Dependencies.py +1306 -0
  5. Cython/Build/Distutils.py +1 -0
  6. Cython/Build/Inline.py +463 -0
  7. Cython/Build/IpythonMagic.py +560 -0
  8. Cython/Build/SharedModule.py +76 -0
  9. Cython/Build/Tests/TestCyCache.py +194 -0
  10. Cython/Build/Tests/TestCythonizeArgsParser.py +481 -0
  11. Cython/Build/Tests/TestDependencies.py +133 -0
  12. Cython/Build/Tests/TestInline.py +177 -0
  13. Cython/Build/Tests/TestIpythonMagic.py +287 -0
  14. Cython/Build/Tests/TestRecythonize.py +212 -0
  15. Cython/Build/Tests/TestStripLiterals.py +155 -0
  16. Cython/Build/Tests/__init__.py +1 -0
  17. Cython/Build/__init__.py +8 -0
  18. Cython/CodeWriter.py +811 -0
  19. Cython/Compiler/AnalysedTreeTransforms.py +97 -0
  20. Cython/Compiler/Annotate.py +326 -0
  21. Cython/Compiler/AutoDocTransforms.py +320 -0
  22. Cython/Compiler/Buffer.py +680 -0
  23. Cython/Compiler/Builtin.py +934 -0
  24. Cython/Compiler/CmdLine.py +259 -0
  25. Cython/Compiler/Code.pxd +148 -0
  26. Cython/Compiler/Code.py +3375 -0
  27. Cython/Compiler/CodeGeneration.py +33 -0
  28. Cython/Compiler/CythonScope.py +187 -0
  29. Cython/Compiler/Dataclass.py +868 -0
  30. Cython/Compiler/DebugFlags.py +24 -0
  31. Cython/Compiler/Errors.py +295 -0
  32. Cython/Compiler/ExprNodes.py +15267 -0
  33. Cython/Compiler/FlowControl.pxd +97 -0
  34. Cython/Compiler/FlowControl.py +1455 -0
  35. Cython/Compiler/FusedNode.py +1002 -0
  36. Cython/Compiler/Future.py +16 -0
  37. Cython/Compiler/Interpreter.py +57 -0
  38. Cython/Compiler/Lexicon.py +340 -0
  39. Cython/Compiler/LineTable.py +114 -0
  40. Cython/Compiler/Main.py +853 -0
  41. Cython/Compiler/MatchCaseNodes.py +259 -0
  42. Cython/Compiler/MemoryView.py +922 -0
  43. Cython/Compiler/ModuleNode.py +4024 -0
  44. Cython/Compiler/Naming.py +374 -0
  45. Cython/Compiler/Nodes.py +10826 -0
  46. Cython/Compiler/Optimize.py +5256 -0
  47. Cython/Compiler/Options.py +835 -0
  48. Cython/Compiler/ParseTreeTransforms.pxd +77 -0
  49. Cython/Compiler/ParseTreeTransforms.py +4509 -0
  50. Cython/Compiler/Parsing.pxd +9 -0
  51. Cython/Compiler/Parsing.py +4789 -0
  52. Cython/Compiler/Pipeline.py +439 -0
  53. Cython/Compiler/PyrexTypes.py +5762 -0
  54. Cython/Compiler/Pythran.py +232 -0
  55. Cython/Compiler/Scanning.pxd +40 -0
  56. Cython/Compiler/Scanning.py +577 -0
  57. Cython/Compiler/StringEncoding.py +347 -0
  58. Cython/Compiler/Symtab.py +3080 -0
  59. Cython/Compiler/Tests/TestBuffer.py +105 -0
  60. Cython/Compiler/Tests/TestBuiltin.py +72 -0
  61. Cython/Compiler/Tests/TestCmdLine.py +586 -0
  62. Cython/Compiler/Tests/TestCode.py +86 -0
  63. Cython/Compiler/Tests/TestFlowControl.py +65 -0
  64. Cython/Compiler/Tests/TestGrammar.py +202 -0
  65. Cython/Compiler/Tests/TestMemView.py +71 -0
  66. Cython/Compiler/Tests/TestParseTreeTransforms.py +285 -0
  67. Cython/Compiler/Tests/TestScanning.py +134 -0
  68. Cython/Compiler/Tests/TestSignatureMatching.py +73 -0
  69. Cython/Compiler/Tests/TestStringEncoding.py +33 -0
  70. Cython/Compiler/Tests/TestTreeFragment.py +63 -0
  71. Cython/Compiler/Tests/TestTreePath.py +103 -0
  72. Cython/Compiler/Tests/TestTypes.py +75 -0
  73. Cython/Compiler/Tests/TestUtilityLoad.py +112 -0
  74. Cython/Compiler/Tests/TestVisitor.py +61 -0
  75. Cython/Compiler/Tests/Utils.py +36 -0
  76. Cython/Compiler/Tests/__init__.py +1 -0
  77. Cython/Compiler/TreeFragment.py +278 -0
  78. Cython/Compiler/TreePath.py +303 -0
  79. Cython/Compiler/TypeInference.py +584 -0
  80. Cython/Compiler/TypeSlots.py +1181 -0
  81. Cython/Compiler/UFuncs.py +311 -0
  82. Cython/Compiler/UtilNodes.py +389 -0
  83. Cython/Compiler/UtilityCode.py +344 -0
  84. Cython/Compiler/Version.py +8 -0
  85. Cython/Compiler/Visitor.pxd +53 -0
  86. Cython/Compiler/Visitor.py +861 -0
  87. Cython/Compiler/__init__.py +1 -0
  88. Cython/Coverage.py +448 -0
  89. Cython/Debugger/Cygdb.py +175 -0
  90. Cython/Debugger/DebugWriter.py +82 -0
  91. Cython/Debugger/Tests/TestLibCython.py +275 -0
  92. Cython/Debugger/Tests/__init__.py +1 -0
  93. Cython/Debugger/Tests/cfuncs.c +8 -0
  94. Cython/Debugger/Tests/codefile +49 -0
  95. Cython/Debugger/Tests/test_libcython_in_gdb.py +578 -0
  96. Cython/Debugger/Tests/test_libpython_in_gdb.py +90 -0
  97. Cython/Debugger/__init__.py +1 -0
  98. Cython/Debugger/libcython.py +1548 -0
  99. Cython/Debugger/libpython.py +2821 -0
  100. Cython/Debugging.py +20 -0
  101. Cython/Distutils/__init__.py +2 -0
  102. Cython/Distutils/build_ext.py +139 -0
  103. Cython/Distutils/extension.py +96 -0
  104. Cython/Distutils/old_build_ext.py +351 -0
  105. Cython/Includes/cpython/__init__.pxd +173 -0
  106. Cython/Includes/cpython/array.pxd +174 -0
  107. Cython/Includes/cpython/bool.pxd +37 -0
  108. Cython/Includes/cpython/buffer.pxd +112 -0
  109. Cython/Includes/cpython/bytearray.pxd +33 -0
  110. Cython/Includes/cpython/bytes.pxd +200 -0
  111. Cython/Includes/cpython/cellobject.pxd +35 -0
  112. Cython/Includes/cpython/ceval.pxd +8 -0
  113. Cython/Includes/cpython/codecs.pxd +121 -0
  114. Cython/Includes/cpython/complex.pxd +60 -0
  115. Cython/Includes/cpython/contextvars.pxd +145 -0
  116. Cython/Includes/cpython/conversion.pxd +36 -0
  117. Cython/Includes/cpython/datetime.pxd +395 -0
  118. Cython/Includes/cpython/descr.pxd +26 -0
  119. Cython/Includes/cpython/dict.pxd +187 -0
  120. Cython/Includes/cpython/exc.pxd +263 -0
  121. Cython/Includes/cpython/fileobject.pxd +57 -0
  122. Cython/Includes/cpython/float.pxd +47 -0
  123. Cython/Includes/cpython/function.pxd +65 -0
  124. Cython/Includes/cpython/genobject.pxd +25 -0
  125. Cython/Includes/cpython/getargs.pxd +12 -0
  126. Cython/Includes/cpython/instance.pxd +25 -0
  127. Cython/Includes/cpython/iterator.pxd +36 -0
  128. Cython/Includes/cpython/iterobject.pxd +24 -0
  129. Cython/Includes/cpython/list.pxd +92 -0
  130. Cython/Includes/cpython/long.pxd +149 -0
  131. Cython/Includes/cpython/longintrepr.pxd +14 -0
  132. Cython/Includes/cpython/mapping.pxd +63 -0
  133. Cython/Includes/cpython/marshal.pxd +66 -0
  134. Cython/Includes/cpython/mem.pxd +120 -0
  135. Cython/Includes/cpython/memoryview.pxd +50 -0
  136. Cython/Includes/cpython/method.pxd +49 -0
  137. Cython/Includes/cpython/module.pxd +208 -0
  138. Cython/Includes/cpython/number.pxd +258 -0
  139. Cython/Includes/cpython/object.pxd +433 -0
  140. Cython/Includes/cpython/pycapsule.pxd +143 -0
  141. Cython/Includes/cpython/pylifecycle.pxd +68 -0
  142. Cython/Includes/cpython/pyport.pxd +8 -0
  143. Cython/Includes/cpython/pystate.pxd +95 -0
  144. Cython/Includes/cpython/pythread.pxd +53 -0
  145. Cython/Includes/cpython/ref.pxd +67 -0
  146. Cython/Includes/cpython/sequence.pxd +134 -0
  147. Cython/Includes/cpython/set.pxd +119 -0
  148. Cython/Includes/cpython/slice.pxd +70 -0
  149. Cython/Includes/cpython/time.pxd +129 -0
  150. Cython/Includes/cpython/tuple.pxd +72 -0
  151. Cython/Includes/cpython/type.pxd +53 -0
  152. Cython/Includes/cpython/unicode.pxd +639 -0
  153. Cython/Includes/cpython/version.pxd +32 -0
  154. Cython/Includes/cpython/weakref.pxd +78 -0
  155. Cython/Includes/libc/__init__.pxd +1 -0
  156. Cython/Includes/libc/complex.pxd +35 -0
  157. Cython/Includes/libc/errno.pxd +127 -0
  158. Cython/Includes/libc/float.pxd +43 -0
  159. Cython/Includes/libc/limits.pxd +28 -0
  160. Cython/Includes/libc/locale.pxd +46 -0
  161. Cython/Includes/libc/math.pxd +209 -0
  162. Cython/Includes/libc/setjmp.pxd +10 -0
  163. Cython/Includes/libc/signal.pxd +64 -0
  164. Cython/Includes/libc/stddef.pxd +9 -0
  165. Cython/Includes/libc/stdint.pxd +105 -0
  166. Cython/Includes/libc/stdio.pxd +80 -0
  167. Cython/Includes/libc/stdlib.pxd +72 -0
  168. Cython/Includes/libc/string.pxd +50 -0
  169. Cython/Includes/libc/threads.pxd +84 -0
  170. Cython/Includes/libc/time.pxd +51 -0
  171. Cython/Includes/libcpp/__init__.pxd +4 -0
  172. Cython/Includes/libcpp/algorithm.pxd +320 -0
  173. Cython/Includes/libcpp/any.pxd +16 -0
  174. Cython/Includes/libcpp/atomic.pxd +59 -0
  175. Cython/Includes/libcpp/barrier.pxd +22 -0
  176. Cython/Includes/libcpp/bit.pxd +29 -0
  177. Cython/Includes/libcpp/cast.pxd +12 -0
  178. Cython/Includes/libcpp/cmath.pxd +518 -0
  179. Cython/Includes/libcpp/complex.pxd +106 -0
  180. Cython/Includes/libcpp/deque.pxd +165 -0
  181. Cython/Includes/libcpp/exception.pxd +86 -0
  182. Cython/Includes/libcpp/execution.pxd +15 -0
  183. Cython/Includes/libcpp/forward_list.pxd +63 -0
  184. Cython/Includes/libcpp/functional.pxd +26 -0
  185. Cython/Includes/libcpp/future.pxd +103 -0
  186. Cython/Includes/libcpp/iterator.pxd +34 -0
  187. Cython/Includes/libcpp/latch.pxd +17 -0
  188. Cython/Includes/libcpp/limits.pxd +61 -0
  189. Cython/Includes/libcpp/list.pxd +117 -0
  190. Cython/Includes/libcpp/map.pxd +252 -0
  191. Cython/Includes/libcpp/memory.pxd +115 -0
  192. Cython/Includes/libcpp/mutex.pxd +130 -0
  193. Cython/Includes/libcpp/numbers.pxd +15 -0
  194. Cython/Includes/libcpp/numeric.pxd +131 -0
  195. Cython/Includes/libcpp/optional.pxd +34 -0
  196. Cython/Includes/libcpp/pair.pxd +1 -0
  197. Cython/Includes/libcpp/queue.pxd +25 -0
  198. Cython/Includes/libcpp/random.pxd +166 -0
  199. Cython/Includes/libcpp/semaphore.pxd +44 -0
  200. Cython/Includes/libcpp/set.pxd +228 -0
  201. Cython/Includes/libcpp/shared_mutex.pxd +72 -0
  202. Cython/Includes/libcpp/span.pxd +87 -0
  203. Cython/Includes/libcpp/stack.pxd +11 -0
  204. Cython/Includes/libcpp/stop_token.pxd +105 -0
  205. Cython/Includes/libcpp/string.pxd +355 -0
  206. Cython/Includes/libcpp/string_view.pxd +181 -0
  207. Cython/Includes/libcpp/typeindex.pxd +15 -0
  208. Cython/Includes/libcpp/typeinfo.pxd +10 -0
  209. Cython/Includes/libcpp/unordered_map.pxd +193 -0
  210. Cython/Includes/libcpp/unordered_set.pxd +152 -0
  211. Cython/Includes/libcpp/utility.pxd +30 -0
  212. Cython/Includes/libcpp/vector.pxd +186 -0
  213. Cython/Includes/openmp.pxd +50 -0
  214. Cython/Includes/posix/__init__.pxd +1 -0
  215. Cython/Includes/posix/dlfcn.pxd +14 -0
  216. Cython/Includes/posix/fcntl.pxd +86 -0
  217. Cython/Includes/posix/ioctl.pxd +4 -0
  218. Cython/Includes/posix/mman.pxd +101 -0
  219. Cython/Includes/posix/resource.pxd +57 -0
  220. Cython/Includes/posix/select.pxd +21 -0
  221. Cython/Includes/posix/signal.pxd +73 -0
  222. Cython/Includes/posix/stat.pxd +98 -0
  223. Cython/Includes/posix/stdio.pxd +37 -0
  224. Cython/Includes/posix/stdlib.pxd +29 -0
  225. Cython/Includes/posix/strings.pxd +9 -0
  226. Cython/Includes/posix/time.pxd +71 -0
  227. Cython/Includes/posix/types.pxd +30 -0
  228. Cython/Includes/posix/uio.pxd +26 -0
  229. Cython/Includes/posix/unistd.pxd +271 -0
  230. Cython/Includes/posix/wait.pxd +38 -0
  231. Cython/Plex/Actions.pxd +24 -0
  232. Cython/Plex/Actions.py +119 -0
  233. Cython/Plex/DFA.pxd +14 -0
  234. Cython/Plex/DFA.py +164 -0
  235. Cython/Plex/Errors.py +48 -0
  236. Cython/Plex/Lexicons.py +178 -0
  237. Cython/Plex/Machines.pxd +36 -0
  238. Cython/Plex/Machines.py +238 -0
  239. Cython/Plex/Regexps.py +539 -0
  240. Cython/Plex/Scanners.pxd +47 -0
  241. Cython/Plex/Scanners.py +360 -0
  242. Cython/Plex/Transitions.pxd +14 -0
  243. Cython/Plex/Transitions.py +239 -0
  244. Cython/Plex/__init__.py +34 -0
  245. Cython/Runtime/__init__.py +1 -0
  246. Cython/Runtime/refnanny.pyx +237 -0
  247. Cython/Shadow.py +690 -0
  248. Cython/Shadow.pyi +521 -0
  249. Cython/StringIOTree.py +170 -0
  250. Cython/Tempita/__init__.py +4 -0
  251. Cython/Tempita/_looper.py +154 -0
  252. Cython/Tempita/_tempita.py +1091 -0
  253. Cython/TestUtils.py +410 -0
  254. Cython/Tests/TestCodeWriter.py +128 -0
  255. Cython/Tests/TestCythonUtils.py +202 -0
  256. Cython/Tests/TestJediTyper.py +223 -0
  257. Cython/Tests/TestShadow.py +114 -0
  258. Cython/Tests/TestStringIOTree.py +67 -0
  259. Cython/Tests/TestTestUtils.py +90 -0
  260. Cython/Tests/__init__.py +1 -0
  261. Cython/Tests/xmlrunner.py +390 -0
  262. Cython/Utility/AsyncGen.c +1002 -0
  263. Cython/Utility/Buffer.c +875 -0
  264. Cython/Utility/BufferFormatFromTypeInfo.pxd +2 -0
  265. Cython/Utility/Builtins.c +776 -0
  266. Cython/Utility/CConvert.pyx +134 -0
  267. Cython/Utility/CMath.c +104 -0
  268. Cython/Utility/CommonStructures.c +118 -0
  269. Cython/Utility/Complex.c +378 -0
  270. Cython/Utility/Coroutine.c +2206 -0
  271. Cython/Utility/CpdefEnums.pyx +103 -0
  272. Cython/Utility/CppConvert.pyx +279 -0
  273. Cython/Utility/CppSupport.cpp +143 -0
  274. Cython/Utility/CythonFunction.c +1794 -0
  275. Cython/Utility/Dataclasses.c +185 -0
  276. Cython/Utility/Dataclasses.py +112 -0
  277. Cython/Utility/Embed.c +125 -0
  278. Cython/Utility/Exceptions.c +1012 -0
  279. Cython/Utility/ExtensionTypes.c +809 -0
  280. Cython/Utility/FunctionArguments.c +965 -0
  281. Cython/Utility/ImportExport.c +987 -0
  282. Cython/Utility/Lock.c +136 -0
  283. Cython/Utility/MemoryView.pxd +187 -0
  284. Cython/Utility/MemoryView.pyx +1481 -0
  285. Cython/Utility/MemoryView_C.c +1046 -0
  286. Cython/Utility/ModuleSetupCode.c +3059 -0
  287. Cython/Utility/NumpyImportArray.c +46 -0
  288. Cython/Utility/ObjectHandling.c +3342 -0
  289. Cython/Utility/Optimize.c +1589 -0
  290. Cython/Utility/Overflow.c +404 -0
  291. Cython/Utility/Printing.c +86 -0
  292. Cython/Utility/Profile.c +709 -0
  293. Cython/Utility/StringTools.c +1259 -0
  294. Cython/Utility/TestCyUtilityLoader.pyx +8 -0
  295. Cython/Utility/TestCythonScope.pyx +75 -0
  296. Cython/Utility/TestUtilityLoader.c +12 -0
  297. Cython/Utility/TypeConversion.c +1284 -0
  298. Cython/Utility/UFuncs.pyx +50 -0
  299. Cython/Utility/UFuncs_C.c +89 -0
  300. Cython/Utility/__init__.py +28 -0
  301. Cython/Utility/arrayarray.h +148 -0
  302. Cython/Utils.py +687 -0
  303. Cython/__init__.py +10 -0
  304. Cython/__init__.pyi +7 -0
  305. Cython/py.typed +0 -0
  306. cython-3.1.0.dist-info/COPYING.txt +19 -0
  307. cython-3.1.0.dist-info/LICENSE.txt +176 -0
  308. cython-3.1.0.dist-info/METADATA +636 -0
  309. cython-3.1.0.dist-info/RECORD +316 -0
  310. cython-3.1.0.dist-info/WHEEL +5 -0
  311. cython-3.1.0.dist-info/entry_points.txt +4 -0
  312. cython-3.1.0.dist-info/top_level.txt +3 -0
  313. cython.py +29 -0
  314. pyximport/__init__.py +4 -0
  315. pyximport/pyxbuild.py +160 -0
  316. pyximport/pyximport.py +482 -0
@@ -0,0 +1,36 @@
1
+ import copy
2
+
3
+ from .. import Options
4
+
5
+
6
+ def backup_Options():
7
+ backup = {}
8
+ for name, value in vars(Options).items():
9
+ # we need a deep copy of _directive_defaults, because they can be changed
10
+ if name == '_directive_defaults':
11
+ value = copy.deepcopy(value)
12
+ backup[name] = value
13
+ return backup
14
+
15
+
16
+ def restore_Options(backup):
17
+ no_value = object()
18
+ for name, orig_value in backup.items():
19
+ if getattr(Options, name, no_value) != orig_value:
20
+ setattr(Options, name, orig_value)
21
+ # strip Options from new keys that might have been added:
22
+ for name in vars(Options).keys():
23
+ if name not in backup:
24
+ delattr(Options, name)
25
+
26
+
27
+ def check_global_options(expected_options, white_list=[]):
28
+ """
29
+ returns error message of "" if check Ok
30
+ """
31
+ no_value = object()
32
+ for name, orig_value in expected_options.items():
33
+ if name not in white_list:
34
+ if getattr(Options, name, no_value) != orig_value:
35
+ return "error in option " + name
36
+ return ""
@@ -0,0 +1 @@
1
+ # empty file
@@ -0,0 +1,278 @@
1
+ #
2
+ # TreeFragments - parsing of strings to trees
3
+ #
4
+
5
+ """
6
+ Support for parsing strings into code trees.
7
+ """
8
+
9
+
10
+ import re
11
+ from io import StringIO
12
+
13
+ from .Scanning import PyrexScanner, StringSourceDescriptor
14
+ from .Symtab import ModuleScope
15
+ from . import PyrexTypes
16
+ from .Visitor import VisitorTransform
17
+ from .Nodes import Node, StatListNode
18
+ from .ExprNodes import NameNode
19
+ from . import Parsing
20
+ from . import Main
21
+ from . import UtilNodes
22
+
23
+
24
+ class StringParseContext(Main.Context):
25
+ def __init__(self, name, include_directories=None, compiler_directives=None, cpp=False):
26
+ if include_directories is None:
27
+ include_directories = []
28
+ if compiler_directives is None:
29
+ compiler_directives = {}
30
+ Main.Context.__init__(self, include_directories, compiler_directives, cpp=cpp, language_level='3')
31
+ self.module_name = name
32
+
33
+ def find_module(self, module_name, from_module=None, pos=None, need_pxd=1, absolute_fallback=True, relative_import=False):
34
+ if module_name not in (self.module_name, 'cython'):
35
+ raise AssertionError("Not yet supporting any cimports/includes from string code snippets")
36
+ return ModuleScope(module_name, parent_module=None, context=self)
37
+
38
+
39
+ def parse_from_strings(name, code, pxds=None, level=None, initial_pos=None,
40
+ context=None, allow_struct_enum_decorator=False,
41
+ in_utility_code=False):
42
+ """
43
+ Utility method to parse a (unicode) string of code. This is mostly
44
+ used for internal Cython compiler purposes (creating code snippets
45
+ that transforms should emit, as well as unit testing).
46
+
47
+ code - a unicode string containing Cython (module-level) code
48
+ name - a descriptive name for the code source (to use in error messages etc.)
49
+ in_utility_code - used to suppress some messages from utility code. False by default
50
+ because some generated code snippets like properties and dataclasses
51
+ probably want to see those messages.
52
+
53
+ RETURNS
54
+
55
+ The tree, i.e. a ModuleNode. The ModuleNode's scope attribute is
56
+ set to the scope used when parsing.
57
+ """
58
+ if context is None:
59
+ context = StringParseContext(name)
60
+ # Since source files carry an encoding, it makes sense in this context
61
+ # to use a unicode string so that code fragments don't have to bother
62
+ # with encoding. This means that test code passed in should not have an
63
+ # encoding header.
64
+ assert isinstance(code, str), "unicode code snippets only please"
65
+ encoding = "UTF-8"
66
+
67
+ module_name = name
68
+ if initial_pos is None:
69
+ initial_pos = (name, 1, 0)
70
+ code_source = StringSourceDescriptor(name, code)
71
+ if in_utility_code:
72
+ code_source.in_utility_code = True
73
+
74
+ scope = context.find_module(module_name, pos=initial_pos, need_pxd=False)
75
+
76
+ buf = StringIO(code)
77
+
78
+ scanner = PyrexScanner(buf, code_source, source_encoding = encoding,
79
+ scope = scope, context = context, initial_pos = initial_pos)
80
+ ctx = Parsing.Ctx(allow_struct_enum_decorator=allow_struct_enum_decorator)
81
+
82
+ if level is None:
83
+ tree = Parsing.p_module(scanner, 0, module_name, ctx=ctx)
84
+ tree.scope = scope
85
+ tree.is_pxd = False
86
+ else:
87
+ tree = Parsing.p_code(scanner, level=level, ctx=ctx)
88
+
89
+ tree.scope = scope
90
+ return tree
91
+
92
+
93
+ class TreeCopier(VisitorTransform):
94
+ def visit_Node(self, node):
95
+ if node is None:
96
+ return node
97
+ else:
98
+ c = node.clone_node()
99
+ self.visitchildren(c)
100
+ return c
101
+
102
+
103
+ class ApplyPositionAndCopy(TreeCopier):
104
+ def __init__(self, pos):
105
+ super().__init__()
106
+ self.pos = pos
107
+
108
+ def visit_Node(self, node):
109
+ copy = super().visit_Node(node)
110
+ copy.pos = self.pos
111
+ return copy
112
+
113
+
114
+ class TemplateTransform(VisitorTransform):
115
+ """
116
+ Makes a copy of a template tree while doing substitutions.
117
+
118
+ A dictionary "substitutions" should be passed in when calling
119
+ the transform; mapping names to replacement nodes. Then replacement
120
+ happens like this:
121
+ - If an ExprStatNode contains a single NameNode, whose name is
122
+ a key in the substitutions dictionary, the ExprStatNode is
123
+ replaced with a copy of the tree given in the dictionary.
124
+ It is the responsibility of the caller that the replacement
125
+ node is a valid statement.
126
+ - If a single NameNode is otherwise encountered, it is replaced
127
+ if its name is listed in the substitutions dictionary in the
128
+ same way. It is the responsibility of the caller to make sure
129
+ that the replacement nodes is a valid expression.
130
+
131
+ Also a list "temps" should be passed. Any names listed will
132
+ be transformed into anonymous, temporary names.
133
+
134
+ Currently supported for tempnames is:
135
+ NameNode
136
+ (various function and class definition nodes etc. should be added to this)
137
+
138
+ Each replacement node gets the position of the substituted node
139
+ recursively applied to every member node.
140
+ """
141
+
142
+ temp_name_counter = 0
143
+
144
+ def __call__(self, node, substitutions, temps, pos):
145
+ self.substitutions = substitutions
146
+ self.pos = pos
147
+ tempmap = {}
148
+ temphandles = []
149
+ for temp in temps:
150
+ TemplateTransform.temp_name_counter += 1
151
+ handle = UtilNodes.TempHandle(PyrexTypes.py_object_type)
152
+ tempmap[temp] = handle
153
+ temphandles.append(handle)
154
+ self.tempmap = tempmap
155
+ result = super().__call__(node)
156
+ if temps:
157
+ result = UtilNodes.TempsBlockNode(self.get_pos(node),
158
+ temps=temphandles,
159
+ body=result)
160
+ return result
161
+
162
+ def get_pos(self, node):
163
+ if self.pos:
164
+ return self.pos
165
+ else:
166
+ return node.pos
167
+
168
+ def visit_Node(self, node):
169
+ if node is None:
170
+ return None
171
+ else:
172
+ c = node.clone_node()
173
+ if self.pos is not None:
174
+ c.pos = self.pos
175
+ self.visitchildren(c)
176
+ return c
177
+
178
+ def try_substitution(self, node, key):
179
+ sub = self.substitutions.get(key)
180
+ if sub is not None:
181
+ pos = self.pos
182
+ if pos is None: pos = node.pos
183
+ return ApplyPositionAndCopy(pos)(sub)
184
+ else:
185
+ return self.visit_Node(node) # make copy as usual
186
+
187
+ def visit_NameNode(self, node):
188
+ temphandle = self.tempmap.get(node.name)
189
+ if temphandle:
190
+ # Replace name with temporary
191
+ return temphandle.ref(self.get_pos(node))
192
+ else:
193
+ return self.try_substitution(node, node.name)
194
+
195
+ def visit_ExprStatNode(self, node):
196
+ # If an expression-as-statement consists of only a replaceable
197
+ # NameNode, we replace the entire statement, not only the NameNode
198
+ if isinstance(node.expr, NameNode):
199
+ return self.try_substitution(node, node.expr.name)
200
+ else:
201
+ return self.visit_Node(node)
202
+
203
+
204
+ def copy_code_tree(node):
205
+ return TreeCopier()(node)
206
+
207
+
208
+ _match_indent = re.compile("^ *").match
209
+
210
+
211
+ def strip_common_indent(lines):
212
+ """Strips empty lines and common indentation from the list of strings given in lines"""
213
+ # TODO: Facilitate textwrap.indent instead
214
+ lines = [x for x in lines if x.strip() != ""]
215
+ if lines:
216
+ minindent = min([len(_match_indent(x).group(0)) for x in lines])
217
+ lines = [x[minindent:] for x in lines]
218
+ return lines
219
+
220
+
221
+ class TreeFragment:
222
+ def __init__(self, code, name=None, pxds=None, temps=None, pipeline=None, level=None, initial_pos=None):
223
+ if pxds is None:
224
+ pxds = {}
225
+ if temps is None:
226
+ temps = []
227
+ if pipeline is None:
228
+ pipeline = []
229
+ if not name:
230
+ name = "(tree fragment)"
231
+
232
+ if isinstance(code, str):
233
+ def fmt(x): return u"\n".join(strip_common_indent(x.split(u"\n")))
234
+
235
+ fmt_code = fmt(code)
236
+ fmt_pxds = {}
237
+ for key, value in pxds.items():
238
+ fmt_pxds[key] = fmt(value)
239
+ mod = t = parse_from_strings(name, fmt_code, fmt_pxds, level=level, initial_pos=initial_pos)
240
+ if level is None:
241
+ t = t.body # Make sure a StatListNode is at the top
242
+ if not isinstance(t, StatListNode):
243
+ t = StatListNode(pos=mod.pos, stats=[t])
244
+ for transform in pipeline:
245
+ if transform is None:
246
+ continue
247
+ t = transform(t)
248
+ self.root = t
249
+ elif isinstance(code, Node):
250
+ if pxds:
251
+ raise NotImplementedError()
252
+ self.root = code
253
+ else:
254
+ raise ValueError("Unrecognized code format (accepts unicode and Node)")
255
+ self.temps = temps
256
+
257
+ def copy(self):
258
+ return copy_code_tree(self.root)
259
+
260
+ def substitute(self, nodes=None, temps=None, pos = None):
261
+ if nodes is None:
262
+ nodes = {}
263
+ if temps is None:
264
+ temps = []
265
+ return TemplateTransform()(self.root,
266
+ substitutions = nodes,
267
+ temps = self.temps + temps, pos = pos)
268
+
269
+
270
+ class SetPosTransform(VisitorTransform):
271
+ def __init__(self, pos):
272
+ super().__init__()
273
+ self.pos = pos
274
+
275
+ def visit_Node(self, node):
276
+ node.pos = self.pos
277
+ self.visitchildren(node)
278
+ return node
@@ -0,0 +1,303 @@
1
+ """
2
+ A simple XPath-like language for tree traversal.
3
+
4
+ This works by creating a filter chain of generator functions. Each
5
+ function selects a part of the expression, e.g. a child node, a
6
+ specific descendant or a node that holds an attribute.
7
+ """
8
+
9
+
10
+ import re
11
+ import operator
12
+
13
+ path_tokenizer = re.compile(
14
+ r"("
15
+ r"b?'[^']*'|b?\"[^\"]*\"|"
16
+ r"//?|"
17
+ r"\(\)|"
18
+ r"==?|"
19
+ r"[/.*\[\]()@])|"
20
+ r"([^/\[\]()@=\s]+)|"
21
+ r"\s+"
22
+ ).findall
23
+
24
+ def iterchildren(node, attr_name):
25
+ # returns an iterable of all child nodes of that name
26
+ child = getattr(node, attr_name)
27
+ if child is not None:
28
+ if type(child) is list:
29
+ return child
30
+ else:
31
+ return [child]
32
+ else:
33
+ return ()
34
+
35
+ def _get_first_or_none(it):
36
+ try:
37
+ return next(it)
38
+ except StopIteration:
39
+ return None
40
+
41
+ def type_name(node):
42
+ return node.__class__.__name__.split('.')[-1]
43
+
44
+ def parse_func(next, token):
45
+ name = token[1]
46
+ token = next()
47
+ if token[0] != '(':
48
+ raise ValueError("Expected '(' after function name '%s'" % name)
49
+ predicate = handle_predicate(next, token)
50
+ return name, predicate
51
+
52
+ def handle_func_not(next, token):
53
+ """
54
+ not(...)
55
+ """
56
+ name, predicate = parse_func(next, token)
57
+
58
+ def select(result):
59
+ for node in result:
60
+ if _get_first_or_none(predicate([node])) is None:
61
+ yield node
62
+ return select
63
+
64
+ def handle_name(next, token):
65
+ """
66
+ /NodeName/
67
+ or
68
+ func(...)
69
+ """
70
+ name = token[1]
71
+ if name in functions:
72
+ return functions[name](next, token)
73
+ def select(result):
74
+ for node in result:
75
+ for attr_name in node.child_attrs:
76
+ for child in iterchildren(node, attr_name):
77
+ if type_name(child) == name:
78
+ yield child
79
+ return select
80
+
81
+ def handle_star(next, token):
82
+ """
83
+ /*/
84
+ """
85
+ def select(result):
86
+ for node in result:
87
+ for name in node.child_attrs:
88
+ yield from iterchildren(node, name)
89
+ return select
90
+
91
+ def handle_dot(next, token):
92
+ """
93
+ /./
94
+ """
95
+ def select(result):
96
+ return result
97
+ return select
98
+
99
+ def handle_descendants(next, token):
100
+ """
101
+ //...
102
+ """
103
+ token = next()
104
+ if token[0] == "*":
105
+ def iter_recursive(node):
106
+ for name in node.child_attrs:
107
+ for child in iterchildren(node, name):
108
+ yield child
109
+ yield from iter_recursive(child)
110
+ elif not token[0]:
111
+ node_name = token[1]
112
+ def iter_recursive(node):
113
+ for name in node.child_attrs:
114
+ for child in iterchildren(node, name):
115
+ if type_name(child) == node_name:
116
+ yield child
117
+ yield from iter_recursive(child)
118
+ else:
119
+ raise ValueError("Expected node name after '//'")
120
+
121
+ def select(result):
122
+ for node in result:
123
+ yield from iter_recursive(node)
124
+
125
+ return select
126
+
127
+
128
+ def handle_attribute(next, token):
129
+ token = next()
130
+ if token[0]:
131
+ raise ValueError("Expected attribute name")
132
+ name = token[1]
133
+ value = None
134
+ token = next.peek()
135
+ if token[0] == '=':
136
+ next()
137
+ value = parse_path_value(next)
138
+
139
+ readattr = operator.attrgetter(name)
140
+ if value is None:
141
+ def select(result):
142
+ for node in result:
143
+ try:
144
+ attr_value = readattr(node)
145
+ except AttributeError:
146
+ continue
147
+ if attr_value is not None:
148
+ yield attr_value
149
+ else:
150
+ def select(result):
151
+ for node in result:
152
+ try:
153
+ attr_value = readattr(node)
154
+ except AttributeError:
155
+ continue
156
+ if attr_value == value:
157
+ yield attr_value
158
+ elif (isinstance(attr_value, bytes) and isinstance(value, str) and
159
+ attr_value == value.encode()):
160
+ # allow a bytes-to-string comparison too
161
+ yield attr_value
162
+
163
+ return select
164
+
165
+
166
+ def parse_path_value(next):
167
+ token = next()
168
+ value = token[0]
169
+ if value:
170
+ if value[:1] == "'" or value[:1] == '"':
171
+ assert value[-1] == value[0]
172
+ return value[1:-1]
173
+ if value[:2] == "b'" or value[:2] == 'b"':
174
+ assert value[-1] == value[1]
175
+ return value[2:-1].encode('UTF-8')
176
+ try:
177
+ return int(value)
178
+ except ValueError:
179
+ pass
180
+ elif token[1].isdigit():
181
+ return int(token[1])
182
+ else:
183
+ name = token[1].lower()
184
+ if name == 'true':
185
+ return True
186
+ elif name == 'false':
187
+ return False
188
+ raise ValueError(f"Invalid attribute predicate: '{value}'")
189
+
190
+
191
+ def handle_predicate(next, token):
192
+ token = next()
193
+
194
+ and_conditions = [[]]
195
+ or_conditions = [and_conditions]
196
+
197
+ while token[0] not in (']', ')'):
198
+ and_conditions[-1].append( operations[token[0]](next, token) )
199
+ try:
200
+ token = next()
201
+ except StopIteration:
202
+ break
203
+ else:
204
+ if token[0] == "/":
205
+ token = next()
206
+
207
+ if not token[0]:
208
+ if token[1] == 'and':
209
+ and_conditions.append([])
210
+ token = next()
211
+ elif token[1] == 'or':
212
+ and_conditions = [[]]
213
+ or_conditions.append(and_conditions)
214
+ token = next()
215
+
216
+ if not and_conditions[-1]:
217
+ raise ValueError("Incomplete predicate")
218
+
219
+ def select(result):
220
+ for node in result:
221
+ node_base = (node,)
222
+ for and_conditions in or_conditions:
223
+ for condition in and_conditions:
224
+ subresult = iter(node_base)
225
+ for select in condition:
226
+ subresult = select(subresult)
227
+ predicate_result = _get_first_or_none(subresult)
228
+ if predicate_result is None:
229
+ # Fail current 'and' condition and skip to next 'or' condition.
230
+ break
231
+ else:
232
+ # All 'and' conditions matched, report and skip following 'or' conditions.
233
+ yield node
234
+ break
235
+
236
+ return select
237
+
238
+
239
+ operations = {
240
+ "@": handle_attribute,
241
+ "": handle_name,
242
+ "*": handle_star,
243
+ ".": handle_dot,
244
+ "//": handle_descendants,
245
+ "[": handle_predicate,
246
+ }
247
+
248
+ functions = {
249
+ 'not' : handle_func_not
250
+ }
251
+
252
+
253
+ class _LookAheadTokenizer:
254
+ def __init__(self, path):
255
+ self._tokens = [
256
+ (special, text)
257
+ for (special, text) in path_tokenizer(path)
258
+ if special or text
259
+ ]
260
+ self._tokens.reverse() # allow efficient .pop()
261
+
262
+ def peek(self, default=(None, None)):
263
+ return self._tokens[-1] if self._tokens else default
264
+
265
+ def __call__(self):
266
+ try:
267
+ return self._tokens.pop()
268
+ except IndexError:
269
+ raise StopIteration from None
270
+
271
+
272
+ def _build_path_iterator(path):
273
+ # parse pattern
274
+ _next = _LookAheadTokenizer(path)
275
+ token = _next()
276
+ selector = []
277
+ while 1:
278
+ try:
279
+ selector.append(operations[token[0]](_next, token))
280
+ except StopIteration:
281
+ raise ValueError("invalid path")
282
+ try:
283
+ token = _next()
284
+ if token[0] == "/":
285
+ token = _next()
286
+ except StopIteration:
287
+ break
288
+ return selector
289
+
290
+ # main module API
291
+
292
+ def iterfind(node, path):
293
+ selector_chain = _build_path_iterator(path)
294
+ result = iter((node,))
295
+ for select in selector_chain:
296
+ result = select(result)
297
+ return result
298
+
299
+ def find_first(node, path):
300
+ return _get_first_or_none(iterfind(node, path))
301
+
302
+ def find_all(node, path):
303
+ return list(iterfind(node, path))