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.
- Cython/Build/BuildExecutable.py +169 -0
- Cython/Build/Cache.py +199 -0
- Cython/Build/Cythonize.py +323 -0
- Cython/Build/Dependencies.py +1306 -0
- Cython/Build/Distutils.py +1 -0
- Cython/Build/Inline.py +463 -0
- Cython/Build/IpythonMagic.py +560 -0
- Cython/Build/SharedModule.py +76 -0
- Cython/Build/Tests/TestCyCache.py +194 -0
- Cython/Build/Tests/TestCythonizeArgsParser.py +481 -0
- Cython/Build/Tests/TestDependencies.py +133 -0
- Cython/Build/Tests/TestInline.py +177 -0
- Cython/Build/Tests/TestIpythonMagic.py +287 -0
- Cython/Build/Tests/TestRecythonize.py +212 -0
- Cython/Build/Tests/TestStripLiterals.py +155 -0
- Cython/Build/Tests/__init__.py +1 -0
- Cython/Build/__init__.py +8 -0
- Cython/CodeWriter.py +811 -0
- Cython/Compiler/AnalysedTreeTransforms.py +97 -0
- Cython/Compiler/Annotate.py +326 -0
- Cython/Compiler/AutoDocTransforms.py +320 -0
- Cython/Compiler/Buffer.py +680 -0
- Cython/Compiler/Builtin.py +934 -0
- Cython/Compiler/CmdLine.py +259 -0
- Cython/Compiler/Code.pxd +148 -0
- Cython/Compiler/Code.py +3375 -0
- Cython/Compiler/CodeGeneration.py +33 -0
- Cython/Compiler/CythonScope.py +187 -0
- Cython/Compiler/Dataclass.py +868 -0
- Cython/Compiler/DebugFlags.py +24 -0
- Cython/Compiler/Errors.py +295 -0
- Cython/Compiler/ExprNodes.py +15267 -0
- Cython/Compiler/FlowControl.pxd +97 -0
- Cython/Compiler/FlowControl.py +1455 -0
- Cython/Compiler/FusedNode.py +1002 -0
- Cython/Compiler/Future.py +16 -0
- Cython/Compiler/Interpreter.py +57 -0
- Cython/Compiler/Lexicon.py +340 -0
- Cython/Compiler/LineTable.py +114 -0
- Cython/Compiler/Main.py +853 -0
- Cython/Compiler/MatchCaseNodes.py +259 -0
- Cython/Compiler/MemoryView.py +922 -0
- Cython/Compiler/ModuleNode.py +4024 -0
- Cython/Compiler/Naming.py +374 -0
- Cython/Compiler/Nodes.py +10826 -0
- Cython/Compiler/Optimize.py +5256 -0
- Cython/Compiler/Options.py +835 -0
- Cython/Compiler/ParseTreeTransforms.pxd +77 -0
- Cython/Compiler/ParseTreeTransforms.py +4509 -0
- Cython/Compiler/Parsing.pxd +9 -0
- Cython/Compiler/Parsing.py +4789 -0
- Cython/Compiler/Pipeline.py +439 -0
- Cython/Compiler/PyrexTypes.py +5762 -0
- Cython/Compiler/Pythran.py +232 -0
- Cython/Compiler/Scanning.pxd +40 -0
- Cython/Compiler/Scanning.py +577 -0
- Cython/Compiler/StringEncoding.py +347 -0
- Cython/Compiler/Symtab.py +3080 -0
- Cython/Compiler/Tests/TestBuffer.py +105 -0
- Cython/Compiler/Tests/TestBuiltin.py +72 -0
- Cython/Compiler/Tests/TestCmdLine.py +586 -0
- Cython/Compiler/Tests/TestCode.py +86 -0
- Cython/Compiler/Tests/TestFlowControl.py +65 -0
- Cython/Compiler/Tests/TestGrammar.py +202 -0
- Cython/Compiler/Tests/TestMemView.py +71 -0
- Cython/Compiler/Tests/TestParseTreeTransforms.py +285 -0
- Cython/Compiler/Tests/TestScanning.py +134 -0
- Cython/Compiler/Tests/TestSignatureMatching.py +73 -0
- Cython/Compiler/Tests/TestStringEncoding.py +33 -0
- Cython/Compiler/Tests/TestTreeFragment.py +63 -0
- Cython/Compiler/Tests/TestTreePath.py +103 -0
- Cython/Compiler/Tests/TestTypes.py +75 -0
- Cython/Compiler/Tests/TestUtilityLoad.py +112 -0
- Cython/Compiler/Tests/TestVisitor.py +61 -0
- Cython/Compiler/Tests/Utils.py +36 -0
- Cython/Compiler/Tests/__init__.py +1 -0
- Cython/Compiler/TreeFragment.py +278 -0
- Cython/Compiler/TreePath.py +303 -0
- Cython/Compiler/TypeInference.py +584 -0
- Cython/Compiler/TypeSlots.py +1181 -0
- Cython/Compiler/UFuncs.py +311 -0
- Cython/Compiler/UtilNodes.py +389 -0
- Cython/Compiler/UtilityCode.py +344 -0
- Cython/Compiler/Version.py +8 -0
- Cython/Compiler/Visitor.pxd +53 -0
- Cython/Compiler/Visitor.py +861 -0
- Cython/Compiler/__init__.py +1 -0
- Cython/Coverage.py +448 -0
- Cython/Debugger/Cygdb.py +175 -0
- Cython/Debugger/DebugWriter.py +82 -0
- Cython/Debugger/Tests/TestLibCython.py +275 -0
- Cython/Debugger/Tests/__init__.py +1 -0
- Cython/Debugger/Tests/cfuncs.c +8 -0
- Cython/Debugger/Tests/codefile +49 -0
- Cython/Debugger/Tests/test_libcython_in_gdb.py +578 -0
- Cython/Debugger/Tests/test_libpython_in_gdb.py +90 -0
- Cython/Debugger/__init__.py +1 -0
- Cython/Debugger/libcython.py +1548 -0
- Cython/Debugger/libpython.py +2821 -0
- Cython/Debugging.py +20 -0
- Cython/Distutils/__init__.py +2 -0
- Cython/Distutils/build_ext.py +139 -0
- Cython/Distutils/extension.py +96 -0
- Cython/Distutils/old_build_ext.py +351 -0
- Cython/Includes/cpython/__init__.pxd +173 -0
- Cython/Includes/cpython/array.pxd +174 -0
- Cython/Includes/cpython/bool.pxd +37 -0
- Cython/Includes/cpython/buffer.pxd +112 -0
- Cython/Includes/cpython/bytearray.pxd +33 -0
- Cython/Includes/cpython/bytes.pxd +200 -0
- Cython/Includes/cpython/cellobject.pxd +35 -0
- Cython/Includes/cpython/ceval.pxd +8 -0
- Cython/Includes/cpython/codecs.pxd +121 -0
- Cython/Includes/cpython/complex.pxd +60 -0
- Cython/Includes/cpython/contextvars.pxd +145 -0
- Cython/Includes/cpython/conversion.pxd +36 -0
- Cython/Includes/cpython/datetime.pxd +395 -0
- Cython/Includes/cpython/descr.pxd +26 -0
- Cython/Includes/cpython/dict.pxd +187 -0
- Cython/Includes/cpython/exc.pxd +263 -0
- Cython/Includes/cpython/fileobject.pxd +57 -0
- Cython/Includes/cpython/float.pxd +47 -0
- Cython/Includes/cpython/function.pxd +65 -0
- Cython/Includes/cpython/genobject.pxd +25 -0
- Cython/Includes/cpython/getargs.pxd +12 -0
- Cython/Includes/cpython/instance.pxd +25 -0
- Cython/Includes/cpython/iterator.pxd +36 -0
- Cython/Includes/cpython/iterobject.pxd +24 -0
- Cython/Includes/cpython/list.pxd +92 -0
- Cython/Includes/cpython/long.pxd +149 -0
- Cython/Includes/cpython/longintrepr.pxd +14 -0
- Cython/Includes/cpython/mapping.pxd +63 -0
- Cython/Includes/cpython/marshal.pxd +66 -0
- Cython/Includes/cpython/mem.pxd +120 -0
- Cython/Includes/cpython/memoryview.pxd +50 -0
- Cython/Includes/cpython/method.pxd +49 -0
- Cython/Includes/cpython/module.pxd +208 -0
- Cython/Includes/cpython/number.pxd +258 -0
- Cython/Includes/cpython/object.pxd +433 -0
- Cython/Includes/cpython/pycapsule.pxd +143 -0
- Cython/Includes/cpython/pylifecycle.pxd +68 -0
- Cython/Includes/cpython/pyport.pxd +8 -0
- Cython/Includes/cpython/pystate.pxd +95 -0
- Cython/Includes/cpython/pythread.pxd +53 -0
- Cython/Includes/cpython/ref.pxd +67 -0
- Cython/Includes/cpython/sequence.pxd +134 -0
- Cython/Includes/cpython/set.pxd +119 -0
- Cython/Includes/cpython/slice.pxd +70 -0
- Cython/Includes/cpython/time.pxd +129 -0
- Cython/Includes/cpython/tuple.pxd +72 -0
- Cython/Includes/cpython/type.pxd +53 -0
- Cython/Includes/cpython/unicode.pxd +639 -0
- Cython/Includes/cpython/version.pxd +32 -0
- Cython/Includes/cpython/weakref.pxd +78 -0
- Cython/Includes/libc/__init__.pxd +1 -0
- Cython/Includes/libc/complex.pxd +35 -0
- Cython/Includes/libc/errno.pxd +127 -0
- Cython/Includes/libc/float.pxd +43 -0
- Cython/Includes/libc/limits.pxd +28 -0
- Cython/Includes/libc/locale.pxd +46 -0
- Cython/Includes/libc/math.pxd +209 -0
- Cython/Includes/libc/setjmp.pxd +10 -0
- Cython/Includes/libc/signal.pxd +64 -0
- Cython/Includes/libc/stddef.pxd +9 -0
- Cython/Includes/libc/stdint.pxd +105 -0
- Cython/Includes/libc/stdio.pxd +80 -0
- Cython/Includes/libc/stdlib.pxd +72 -0
- Cython/Includes/libc/string.pxd +50 -0
- Cython/Includes/libc/threads.pxd +84 -0
- Cython/Includes/libc/time.pxd +51 -0
- Cython/Includes/libcpp/__init__.pxd +4 -0
- Cython/Includes/libcpp/algorithm.pxd +320 -0
- Cython/Includes/libcpp/any.pxd +16 -0
- Cython/Includes/libcpp/atomic.pxd +59 -0
- Cython/Includes/libcpp/barrier.pxd +22 -0
- Cython/Includes/libcpp/bit.pxd +29 -0
- Cython/Includes/libcpp/cast.pxd +12 -0
- Cython/Includes/libcpp/cmath.pxd +518 -0
- Cython/Includes/libcpp/complex.pxd +106 -0
- Cython/Includes/libcpp/deque.pxd +165 -0
- Cython/Includes/libcpp/exception.pxd +86 -0
- Cython/Includes/libcpp/execution.pxd +15 -0
- Cython/Includes/libcpp/forward_list.pxd +63 -0
- Cython/Includes/libcpp/functional.pxd +26 -0
- Cython/Includes/libcpp/future.pxd +103 -0
- Cython/Includes/libcpp/iterator.pxd +34 -0
- Cython/Includes/libcpp/latch.pxd +17 -0
- Cython/Includes/libcpp/limits.pxd +61 -0
- Cython/Includes/libcpp/list.pxd +117 -0
- Cython/Includes/libcpp/map.pxd +252 -0
- Cython/Includes/libcpp/memory.pxd +115 -0
- Cython/Includes/libcpp/mutex.pxd +130 -0
- Cython/Includes/libcpp/numbers.pxd +15 -0
- Cython/Includes/libcpp/numeric.pxd +131 -0
- Cython/Includes/libcpp/optional.pxd +34 -0
- Cython/Includes/libcpp/pair.pxd +1 -0
- Cython/Includes/libcpp/queue.pxd +25 -0
- Cython/Includes/libcpp/random.pxd +166 -0
- Cython/Includes/libcpp/semaphore.pxd +44 -0
- Cython/Includes/libcpp/set.pxd +228 -0
- Cython/Includes/libcpp/shared_mutex.pxd +72 -0
- Cython/Includes/libcpp/span.pxd +87 -0
- Cython/Includes/libcpp/stack.pxd +11 -0
- Cython/Includes/libcpp/stop_token.pxd +105 -0
- Cython/Includes/libcpp/string.pxd +355 -0
- Cython/Includes/libcpp/string_view.pxd +181 -0
- Cython/Includes/libcpp/typeindex.pxd +15 -0
- Cython/Includes/libcpp/typeinfo.pxd +10 -0
- Cython/Includes/libcpp/unordered_map.pxd +193 -0
- Cython/Includes/libcpp/unordered_set.pxd +152 -0
- Cython/Includes/libcpp/utility.pxd +30 -0
- Cython/Includes/libcpp/vector.pxd +186 -0
- Cython/Includes/openmp.pxd +50 -0
- Cython/Includes/posix/__init__.pxd +1 -0
- Cython/Includes/posix/dlfcn.pxd +14 -0
- Cython/Includes/posix/fcntl.pxd +86 -0
- Cython/Includes/posix/ioctl.pxd +4 -0
- Cython/Includes/posix/mman.pxd +101 -0
- Cython/Includes/posix/resource.pxd +57 -0
- Cython/Includes/posix/select.pxd +21 -0
- Cython/Includes/posix/signal.pxd +73 -0
- Cython/Includes/posix/stat.pxd +98 -0
- Cython/Includes/posix/stdio.pxd +37 -0
- Cython/Includes/posix/stdlib.pxd +29 -0
- Cython/Includes/posix/strings.pxd +9 -0
- Cython/Includes/posix/time.pxd +71 -0
- Cython/Includes/posix/types.pxd +30 -0
- Cython/Includes/posix/uio.pxd +26 -0
- Cython/Includes/posix/unistd.pxd +271 -0
- Cython/Includes/posix/wait.pxd +38 -0
- Cython/Plex/Actions.pxd +24 -0
- Cython/Plex/Actions.py +119 -0
- Cython/Plex/DFA.pxd +14 -0
- Cython/Plex/DFA.py +164 -0
- Cython/Plex/Errors.py +48 -0
- Cython/Plex/Lexicons.py +178 -0
- Cython/Plex/Machines.pxd +36 -0
- Cython/Plex/Machines.py +238 -0
- Cython/Plex/Regexps.py +539 -0
- Cython/Plex/Scanners.pxd +47 -0
- Cython/Plex/Scanners.py +360 -0
- Cython/Plex/Transitions.pxd +14 -0
- Cython/Plex/Transitions.py +239 -0
- Cython/Plex/__init__.py +34 -0
- Cython/Runtime/__init__.py +1 -0
- Cython/Runtime/refnanny.pyx +237 -0
- Cython/Shadow.py +690 -0
- Cython/Shadow.pyi +521 -0
- Cython/StringIOTree.py +170 -0
- Cython/Tempita/__init__.py +4 -0
- Cython/Tempita/_looper.py +154 -0
- Cython/Tempita/_tempita.py +1091 -0
- Cython/TestUtils.py +410 -0
- Cython/Tests/TestCodeWriter.py +128 -0
- Cython/Tests/TestCythonUtils.py +202 -0
- Cython/Tests/TestJediTyper.py +223 -0
- Cython/Tests/TestShadow.py +114 -0
- Cython/Tests/TestStringIOTree.py +67 -0
- Cython/Tests/TestTestUtils.py +90 -0
- Cython/Tests/__init__.py +1 -0
- Cython/Tests/xmlrunner.py +390 -0
- Cython/Utility/AsyncGen.c +1002 -0
- Cython/Utility/Buffer.c +875 -0
- Cython/Utility/BufferFormatFromTypeInfo.pxd +2 -0
- Cython/Utility/Builtins.c +776 -0
- Cython/Utility/CConvert.pyx +134 -0
- Cython/Utility/CMath.c +104 -0
- Cython/Utility/CommonStructures.c +118 -0
- Cython/Utility/Complex.c +378 -0
- Cython/Utility/Coroutine.c +2206 -0
- Cython/Utility/CpdefEnums.pyx +103 -0
- Cython/Utility/CppConvert.pyx +279 -0
- Cython/Utility/CppSupport.cpp +143 -0
- Cython/Utility/CythonFunction.c +1794 -0
- Cython/Utility/Dataclasses.c +185 -0
- Cython/Utility/Dataclasses.py +112 -0
- Cython/Utility/Embed.c +125 -0
- Cython/Utility/Exceptions.c +1012 -0
- Cython/Utility/ExtensionTypes.c +809 -0
- Cython/Utility/FunctionArguments.c +965 -0
- Cython/Utility/ImportExport.c +987 -0
- Cython/Utility/Lock.c +136 -0
- Cython/Utility/MemoryView.pxd +187 -0
- Cython/Utility/MemoryView.pyx +1481 -0
- Cython/Utility/MemoryView_C.c +1046 -0
- Cython/Utility/ModuleSetupCode.c +3059 -0
- Cython/Utility/NumpyImportArray.c +46 -0
- Cython/Utility/ObjectHandling.c +3342 -0
- Cython/Utility/Optimize.c +1589 -0
- Cython/Utility/Overflow.c +404 -0
- Cython/Utility/Printing.c +86 -0
- Cython/Utility/Profile.c +709 -0
- Cython/Utility/StringTools.c +1259 -0
- Cython/Utility/TestCyUtilityLoader.pyx +8 -0
- Cython/Utility/TestCythonScope.pyx +75 -0
- Cython/Utility/TestUtilityLoader.c +12 -0
- Cython/Utility/TypeConversion.c +1284 -0
- Cython/Utility/UFuncs.pyx +50 -0
- Cython/Utility/UFuncs_C.c +89 -0
- Cython/Utility/__init__.py +28 -0
- Cython/Utility/arrayarray.h +148 -0
- Cython/Utils.py +687 -0
- Cython/__init__.py +10 -0
- Cython/__init__.pyi +7 -0
- Cython/py.typed +0 -0
- cython-3.1.0.dist-info/COPYING.txt +19 -0
- cython-3.1.0.dist-info/LICENSE.txt +176 -0
- cython-3.1.0.dist-info/METADATA +636 -0
- cython-3.1.0.dist-info/RECORD +316 -0
- cython-3.1.0.dist-info/WHEEL +5 -0
- cython-3.1.0.dist-info/entry_points.txt +4 -0
- cython-3.1.0.dist-info/top_level.txt +3 -0
- cython.py +29 -0
- pyximport/__init__.py +4 -0
- pyximport/pyxbuild.py +160 -0
- 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))
|