Cython 3.2.0__cp39-abi3-win32.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 +350 -0
- Cython/Build/Dependencies.py +1314 -0
- Cython/Build/Distutils.py +1 -0
- Cython/Build/Inline.py +463 -0
- Cython/Build/IpythonMagic.py +560 -0
- Cython/Build/SharedModule.py +94 -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 +11 -0
- Cython/CodeWriter.py +815 -0
- Cython/Compiler/AnalysedTreeTransforms.py +97 -0
- Cython/Compiler/Annotate.py +328 -0
- Cython/Compiler/AutoDocTransforms.py +320 -0
- Cython/Compiler/Buffer.py +680 -0
- Cython/Compiler/Builtin.py +984 -0
- Cython/Compiler/CmdLine.py +263 -0
- Cython/Compiler/Code.pxd +149 -0
- Cython/Compiler/Code.py +3746 -0
- Cython/Compiler/Code.pyd +0 -0
- Cython/Compiler/CodeGeneration.py +33 -0
- Cython/Compiler/CythonScope.py +191 -0
- Cython/Compiler/Dataclass.py +864 -0
- Cython/Compiler/DebugFlags.py +24 -0
- Cython/Compiler/Errors.py +297 -0
- Cython/Compiler/ExprNodes.py +15562 -0
- Cython/Compiler/FlowControl.pxd +97 -0
- Cython/Compiler/FlowControl.py +1451 -0
- Cython/Compiler/FlowControl.pyd +0 -0
- Cython/Compiler/FusedNode.py +971 -0
- Cython/Compiler/FusedNode.pyd +0 -0
- Cython/Compiler/Future.py +16 -0
- Cython/Compiler/Interpreter.py +57 -0
- Cython/Compiler/Lexicon.py +421 -0
- Cython/Compiler/LineTable.py +114 -0
- Cython/Compiler/LineTable.pyd +0 -0
- Cython/Compiler/Main.py +857 -0
- Cython/Compiler/MatchCaseNodes.py +259 -0
- Cython/Compiler/MemoryView.py +905 -0
- Cython/Compiler/ModuleNode.py +4235 -0
- Cython/Compiler/Naming.py +363 -0
- Cython/Compiler/Nodes.py +10831 -0
- Cython/Compiler/Optimize.py +5288 -0
- Cython/Compiler/Options.py +843 -0
- Cython/Compiler/ParseTreeTransforms.pxd +78 -0
- Cython/Compiler/ParseTreeTransforms.py +4638 -0
- Cython/Compiler/Parsing.pxd +9 -0
- Cython/Compiler/Parsing.py +4775 -0
- Cython/Compiler/Parsing.pyd +0 -0
- Cython/Compiler/Pipeline.py +439 -0
- Cython/Compiler/PyrexTypes.py +5870 -0
- Cython/Compiler/Pythran.py +232 -0
- Cython/Compiler/Scanning.pxd +48 -0
- Cython/Compiler/Scanning.py +701 -0
- Cython/Compiler/Scanning.pyd +0 -0
- Cython/Compiler/StringEncoding.py +298 -0
- Cython/Compiler/Symtab.py +3073 -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 +144 -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 +21 -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 +591 -0
- Cython/Compiler/TypeSlots.py +1174 -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/Visitor.pyd +0 -0
- Cython/Compiler/__init__.py +1 -0
- Cython/Coverage.py +448 -0
- Cython/Debugger/Cygdb.py +177 -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 +178 -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 +141 -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 +234 -0
- Cython/Includes/libc/time.pxd +52 -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/condition_variable.pxd +322 -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 +387 -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 +43 -0
- Cython/Includes/libcpp/set.pxd +228 -0
- Cython/Includes/libcpp/shared_mutex.pxd +96 -0
- Cython/Includes/libcpp/span.pxd +87 -0
- Cython/Includes/libcpp/stack.pxd +11 -0
- Cython/Includes/libcpp/stop_token.pxd +117 -0
- Cython/Includes/libcpp/string.pxd +355 -0
- Cython/Includes/libcpp/string_view.pxd +183 -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/numpy/math.pxd +150 -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/Actions.pyd +0 -0
- Cython/Plex/DFA.pxd +14 -0
- Cython/Plex/DFA.py +164 -0
- Cython/Plex/DFA.pyd +0 -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/Machines.pyd +0 -0
- Cython/Plex/Regexps.py +535 -0
- Cython/Plex/Scanners.pxd +45 -0
- Cython/Plex/Scanners.py +328 -0
- Cython/Plex/Scanners.pyd +0 -0
- Cython/Plex/Transitions.pxd +14 -0
- Cython/Plex/Transitions.py +239 -0
- Cython/Plex/Transitions.pyd +0 -0
- Cython/Plex/__init__.py +34 -0
- Cython/Runtime/__init__.py +1 -0
- Cython/Runtime/refnanny.pyd +0 -0
- Cython/Runtime/refnanny.pyx +237 -0
- Cython/Shadow.py +690 -0
- Cython/Shadow.pyi +521 -0
- Cython/StringIOTree.py +170 -0
- Cython/StringIOTree.pyd +0 -0
- Cython/Tempita/__init__.py +4 -0
- Cython/Tempita/_looper.py +154 -0
- Cython/Tempita/_tempita.py +1091 -0
- Cython/Tempita/_tempita.pyd +0 -0
- Cython/TestUtils.py +422 -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 +1031 -0
- Cython/Utility/Buffer.c +865 -0
- Cython/Utility/BufferFormatFromTypeInfo.pxd +2 -0
- Cython/Utility/Builtins.c +810 -0
- Cython/Utility/CConvert.pyx +134 -0
- Cython/Utility/CMath.c +104 -0
- Cython/Utility/CommonStructures.c +226 -0
- Cython/Utility/Complex.c +378 -0
- Cython/Utility/Coroutine.c +2300 -0
- Cython/Utility/CpdefEnums.pyx +103 -0
- Cython/Utility/CppConvert.pyx +282 -0
- Cython/Utility/CppSupport.cpp +151 -0
- Cython/Utility/CythonFunction.c +1832 -0
- Cython/Utility/Dataclasses.c +101 -0
- Cython/Utility/Embed.c +121 -0
- Cython/Utility/Exceptions.c +1016 -0
- Cython/Utility/ExtensionTypes.c +996 -0
- Cython/Utility/FunctionArguments.c +1043 -0
- Cython/Utility/FusedFunction.pyx +44 -0
- Cython/Utility/ImportExport.c +907 -0
- Cython/Utility/MemoryView.pxd +188 -0
- Cython/Utility/MemoryView.pyx +1482 -0
- Cython/Utility/MemoryView_C.c +927 -0
- Cython/Utility/ModuleSetupCode.c +3203 -0
- Cython/Utility/NumpyImportArray.c +46 -0
- Cython/Utility/ObjectHandling.c +3273 -0
- Cython/Utility/Optimize.c +1603 -0
- Cython/Utility/Overflow.c +384 -0
- Cython/Utility/Printing.c +86 -0
- Cython/Utility/Profile.c +732 -0
- Cython/Utility/StringTools.c +1379 -0
- Cython/Utility/Synchronization.c +399 -0
- Cython/Utility/TString.c +356 -0
- Cython/Utility/TestCyUtilityLoader.pyx +8 -0
- Cython/Utility/TestCythonScope.pyx +75 -0
- Cython/Utility/TestUtilityLoader.c +12 -0
- Cython/Utility/TypeConversion.c +1385 -0
- Cython/Utility/UFuncs.pyx +50 -0
- Cython/Utility/UFuncs_C.c +89 -0
- Cython/Utility/__init__.py +28 -0
- Cython/Utility/arrayarray.h +167 -0
- Cython/Utils.py +687 -0
- Cython/Utils.pyd +0 -0
- Cython/__init__.py +10 -0
- Cython/__init__.pyi +7 -0
- Cython/py.typed +0 -0
- cython-3.2.0.dist-info/METADATA +85 -0
- cython-3.2.0.dist-info/RECORD +333 -0
- cython-3.2.0.dist-info/WHEEL +5 -0
- cython-3.2.0.dist-info/entry_points.txt +4 -0
- cython-3.2.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,202 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
import unittest
|
|
3
|
+
from io import StringIO
|
|
4
|
+
|
|
5
|
+
from Cython.Utils import (
|
|
6
|
+
_CACHE_NAME_PATTERN, _build_cache_name, _find_cache_attributes,
|
|
7
|
+
build_hex_version, cached_method, clear_method_caches, try_finally_contextmanager,
|
|
8
|
+
print_version, normalise_float_repr,
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
METHOD_NAME = "cached_next"
|
|
12
|
+
CACHE_NAME = _build_cache_name(METHOD_NAME)
|
|
13
|
+
NAMES = CACHE_NAME, METHOD_NAME
|
|
14
|
+
|
|
15
|
+
class Cached:
|
|
16
|
+
@cached_method
|
|
17
|
+
def cached_next(self, x):
|
|
18
|
+
return next(x)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class TestCythonUtils(unittest.TestCase):
|
|
22
|
+
def test_build_hex_version(self):
|
|
23
|
+
self.assertEqual('0x001D00A1', build_hex_version('0.29a1'))
|
|
24
|
+
self.assertEqual('0x001D03C4', build_hex_version('0.29.3rc4'))
|
|
25
|
+
self.assertEqual('0x001D00F0', build_hex_version('0.29'))
|
|
26
|
+
self.assertEqual('0x040000F0', build_hex_version('4.0'))
|
|
27
|
+
|
|
28
|
+
############################## Cached Methods ##############################
|
|
29
|
+
|
|
30
|
+
def test_cache_method_name(self):
|
|
31
|
+
method_name = "foo"
|
|
32
|
+
cache_name = _build_cache_name(method_name)
|
|
33
|
+
match = _CACHE_NAME_PATTERN.match(cache_name)
|
|
34
|
+
|
|
35
|
+
self.assertIsNot(match, None)
|
|
36
|
+
self.assertEqual(match.group(1), method_name)
|
|
37
|
+
|
|
38
|
+
def test_requirements_for_Cached(self):
|
|
39
|
+
obj = Cached()
|
|
40
|
+
|
|
41
|
+
self.assertFalse(hasattr(obj, CACHE_NAME))
|
|
42
|
+
self.assertTrue(hasattr(obj, METHOD_NAME))
|
|
43
|
+
self.set_of_names_equal(obj, set())
|
|
44
|
+
|
|
45
|
+
def set_of_names_equal(self, obj, value):
|
|
46
|
+
self.assertEqual(set(_find_cache_attributes(obj)), value)
|
|
47
|
+
|
|
48
|
+
def test_find_cache_attributes(self):
|
|
49
|
+
obj = Cached()
|
|
50
|
+
method_name = "bar"
|
|
51
|
+
cache_name = _build_cache_name(method_name)
|
|
52
|
+
|
|
53
|
+
setattr(obj, CACHE_NAME, {})
|
|
54
|
+
setattr(obj, cache_name, {})
|
|
55
|
+
|
|
56
|
+
self.assertFalse(hasattr(obj, method_name))
|
|
57
|
+
self.set_of_names_equal(obj, {NAMES, (cache_name, method_name)})
|
|
58
|
+
|
|
59
|
+
def test_cached_method(self):
|
|
60
|
+
obj = Cached()
|
|
61
|
+
value = iter(range(3))
|
|
62
|
+
cache = {(value,): 0}
|
|
63
|
+
|
|
64
|
+
# cache args
|
|
65
|
+
self.assertEqual(obj.cached_next(value), 0)
|
|
66
|
+
self.set_of_names_equal(obj, {NAMES})
|
|
67
|
+
self.assertEqual(getattr(obj, CACHE_NAME), cache)
|
|
68
|
+
|
|
69
|
+
# use cache
|
|
70
|
+
self.assertEqual(obj.cached_next(value), 0)
|
|
71
|
+
self.set_of_names_equal(obj, {NAMES})
|
|
72
|
+
self.assertEqual(getattr(obj, CACHE_NAME), cache)
|
|
73
|
+
|
|
74
|
+
def test_clear_method_caches(self):
|
|
75
|
+
obj = Cached()
|
|
76
|
+
value = iter(range(3))
|
|
77
|
+
cache = {(value,): 1}
|
|
78
|
+
|
|
79
|
+
obj.cached_next(value) # cache args
|
|
80
|
+
|
|
81
|
+
clear_method_caches(obj)
|
|
82
|
+
self.set_of_names_equal(obj, set())
|
|
83
|
+
|
|
84
|
+
self.assertEqual(obj.cached_next(value), 1)
|
|
85
|
+
self.set_of_names_equal(obj, {NAMES})
|
|
86
|
+
self.assertEqual(getattr(obj, CACHE_NAME), cache)
|
|
87
|
+
|
|
88
|
+
def test_clear_method_caches_with_missing_method(self):
|
|
89
|
+
obj = Cached()
|
|
90
|
+
method_name = "bar"
|
|
91
|
+
cache_name = _build_cache_name(method_name)
|
|
92
|
+
names = cache_name, method_name
|
|
93
|
+
|
|
94
|
+
setattr(obj, cache_name, object())
|
|
95
|
+
|
|
96
|
+
self.assertFalse(hasattr(obj, method_name))
|
|
97
|
+
self.set_of_names_equal(obj, {names})
|
|
98
|
+
|
|
99
|
+
clear_method_caches(obj)
|
|
100
|
+
self.set_of_names_equal(obj, {names})
|
|
101
|
+
|
|
102
|
+
def test_try_finally_contextmanager(self):
|
|
103
|
+
states = []
|
|
104
|
+
@try_finally_contextmanager
|
|
105
|
+
def gen(*args, **kwargs):
|
|
106
|
+
states.append("enter")
|
|
107
|
+
yield (args, kwargs)
|
|
108
|
+
states.append("exit")
|
|
109
|
+
|
|
110
|
+
with gen(1, 2, 3, x=4) as call_args:
|
|
111
|
+
assert states == ["enter"]
|
|
112
|
+
self.assertEqual(call_args, ((1, 2, 3), {'x': 4}))
|
|
113
|
+
assert states == ["enter", "exit"]
|
|
114
|
+
|
|
115
|
+
class MyException(RuntimeError):
|
|
116
|
+
pass
|
|
117
|
+
|
|
118
|
+
del states[:]
|
|
119
|
+
with self.assertRaises(MyException):
|
|
120
|
+
with gen(1, 2, y=4) as call_args:
|
|
121
|
+
assert states == ["enter"]
|
|
122
|
+
self.assertEqual(call_args, ((1, 2), {'y': 4}))
|
|
123
|
+
raise MyException("FAIL INSIDE")
|
|
124
|
+
assert states == ["enter", "exit"]
|
|
125
|
+
|
|
126
|
+
del states[:]
|
|
127
|
+
with self.assertRaises(StopIteration):
|
|
128
|
+
with gen(1, 2, y=4) as call_args:
|
|
129
|
+
assert states == ["enter"]
|
|
130
|
+
self.assertEqual(call_args, ((1, 2), {'y': 4}))
|
|
131
|
+
raise StopIteration("STOP")
|
|
132
|
+
assert states == ["enter", "exit"]
|
|
133
|
+
|
|
134
|
+
def test_print_version(self):
|
|
135
|
+
orig_stderr = sys.stderr
|
|
136
|
+
orig_stdout = sys.stdout
|
|
137
|
+
stderr = sys.stderr = StringIO()
|
|
138
|
+
stdout = sys.stdout = StringIO()
|
|
139
|
+
try:
|
|
140
|
+
print_version()
|
|
141
|
+
finally:
|
|
142
|
+
sys.stdout = orig_stdout
|
|
143
|
+
sys.stderr = orig_stderr
|
|
144
|
+
|
|
145
|
+
stdout = stdout.getvalue()
|
|
146
|
+
stderr = stderr.getvalue()
|
|
147
|
+
|
|
148
|
+
from .. import __version__ as version
|
|
149
|
+
self.assertIn(version, stdout)
|
|
150
|
+
if stderr: # Depends on os.fstat(1/2).
|
|
151
|
+
self.assertIn(version, stderr)
|
|
152
|
+
|
|
153
|
+
def test_print_version_stdouterr(self):
|
|
154
|
+
orig_stderr = sys.stderr
|
|
155
|
+
orig_stdout = sys.stdout
|
|
156
|
+
stdout = sys.stdout = sys.stderr = StringIO() # same!
|
|
157
|
+
try:
|
|
158
|
+
print_version()
|
|
159
|
+
finally:
|
|
160
|
+
sys.stdout = orig_stdout
|
|
161
|
+
sys.stderr = orig_stderr
|
|
162
|
+
|
|
163
|
+
stdout = stdout.getvalue()
|
|
164
|
+
|
|
165
|
+
from .. import __version__ as version
|
|
166
|
+
self.assertIn(version, stdout)
|
|
167
|
+
self.assertEqual(stdout.count(version), 1)
|
|
168
|
+
|
|
169
|
+
def test_normalise_float_repr(self):
|
|
170
|
+
examples = [
|
|
171
|
+
('.0', '.0'),
|
|
172
|
+
('.000000', '.0'),
|
|
173
|
+
('.1', '.1'),
|
|
174
|
+
('1.', '1.'),
|
|
175
|
+
('1.0', '1.'),
|
|
176
|
+
('1.000000000000000000000', '1.'),
|
|
177
|
+
('00000000000000000000001.000000000000000000000', '1.'),
|
|
178
|
+
('12345.0025', '12345.0025'),
|
|
179
|
+
('1E5', '100000.'),
|
|
180
|
+
('.1E-5', '.000001'),
|
|
181
|
+
('1.1E-5', '.000011'),
|
|
182
|
+
('12.3E-5', '.000123'),
|
|
183
|
+
('.1E10', '1000000000.'),
|
|
184
|
+
('1.1E10', '11000000000.'),
|
|
185
|
+
('123.4E10', '1234000000000.'),
|
|
186
|
+
('123.456E0', '123.456'),
|
|
187
|
+
('123.456E-1', '12.3456'),
|
|
188
|
+
('123.456E-2', '1.23456'),
|
|
189
|
+
('123.456E1', '1234.56'),
|
|
190
|
+
('123.456E2', '12345.6'),
|
|
191
|
+
('2.1E80', '210000000000000000000000000000000000000000000000000000000000000000000000000000000.'),
|
|
192
|
+
]
|
|
193
|
+
|
|
194
|
+
for float_str, norm_str in examples:
|
|
195
|
+
self.assertEqual(float(float_str), float(norm_str)) # safety check for test data
|
|
196
|
+
|
|
197
|
+
result = normalise_float_repr(float_str)
|
|
198
|
+
self.assertEqual(float(float_str), float(result))
|
|
199
|
+
self.assertEqual(
|
|
200
|
+
result, norm_str,
|
|
201
|
+
"normalise_float_repr(%r) == %r != %r (%.330f)" % (float_str, result, norm_str, float(float_str))
|
|
202
|
+
)
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
# tag: jedi
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
import sys
|
|
5
|
+
import os.path
|
|
6
|
+
|
|
7
|
+
from textwrap import dedent
|
|
8
|
+
from contextlib import contextmanager
|
|
9
|
+
from tempfile import NamedTemporaryFile
|
|
10
|
+
|
|
11
|
+
from Cython.Compiler.ParseTreeTransforms import NormalizeTree, InterpretCompilerDirectives
|
|
12
|
+
from Cython.Compiler import Main, Symtab, Visitor, Options
|
|
13
|
+
from Cython.TestUtils import TransformTest
|
|
14
|
+
|
|
15
|
+
TOOLS_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..', 'Tools'))
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@contextmanager
|
|
19
|
+
def _tempfile(code):
|
|
20
|
+
code = dedent(code)
|
|
21
|
+
if not isinstance(code, bytes):
|
|
22
|
+
code = code.encode('utf8')
|
|
23
|
+
|
|
24
|
+
with NamedTemporaryFile(suffix='.py') as f:
|
|
25
|
+
f.write(code)
|
|
26
|
+
f.seek(0)
|
|
27
|
+
yield f
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def _test_typing(code, inject=False):
|
|
31
|
+
sys.path.insert(0, TOOLS_DIR)
|
|
32
|
+
try:
|
|
33
|
+
import jedityper
|
|
34
|
+
finally:
|
|
35
|
+
sys.path.remove(TOOLS_DIR)
|
|
36
|
+
lines = []
|
|
37
|
+
with _tempfile(code) as f:
|
|
38
|
+
types = jedityper.analyse(f.name)
|
|
39
|
+
if inject:
|
|
40
|
+
lines = jedityper.inject_types(f.name, types)
|
|
41
|
+
return types, lines
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class DeclarationsFinder(Visitor.VisitorTransform):
|
|
45
|
+
directives = None
|
|
46
|
+
|
|
47
|
+
visit_Node = Visitor.VisitorTransform.recurse_to_children
|
|
48
|
+
|
|
49
|
+
def visit_CompilerDirectivesNode(self, node):
|
|
50
|
+
if not self.directives:
|
|
51
|
+
self.directives = []
|
|
52
|
+
self.directives.append(node)
|
|
53
|
+
self.visitchildren(node)
|
|
54
|
+
return node
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
class TestJediTyper(TransformTest):
|
|
58
|
+
def _test(self, code):
|
|
59
|
+
return _test_typing(code)[0]
|
|
60
|
+
|
|
61
|
+
def test_typing_global_int_loop(self):
|
|
62
|
+
code = '''\
|
|
63
|
+
for i in range(10):
|
|
64
|
+
a = i + 1
|
|
65
|
+
'''
|
|
66
|
+
types = self._test(code)
|
|
67
|
+
self.assertIn((None, (1, 0)), types)
|
|
68
|
+
variables = types.pop((None, (1, 0)))
|
|
69
|
+
self.assertFalse(types)
|
|
70
|
+
self.assertEqual({'a': {'int'}, 'i': {'int'}}, variables)
|
|
71
|
+
|
|
72
|
+
def test_typing_function_int_loop(self):
|
|
73
|
+
code = '''\
|
|
74
|
+
def func(x):
|
|
75
|
+
for i in range(x):
|
|
76
|
+
a = i + 1
|
|
77
|
+
return a
|
|
78
|
+
'''
|
|
79
|
+
types = self._test(code)
|
|
80
|
+
self.assertIn(('func', (1, 0)), types)
|
|
81
|
+
variables = types.pop(('func', (1, 0)))
|
|
82
|
+
self.assertFalse(types)
|
|
83
|
+
self.assertEqual({'a': {'int'}, 'i': {'int'}}, variables)
|
|
84
|
+
|
|
85
|
+
def test_conflicting_types_in_function(self):
|
|
86
|
+
code = '''\
|
|
87
|
+
def func(a, b):
|
|
88
|
+
print(a)
|
|
89
|
+
a = 1
|
|
90
|
+
b += a
|
|
91
|
+
a = 'abc'
|
|
92
|
+
return a, str(b)
|
|
93
|
+
|
|
94
|
+
print(func(1.5, 2))
|
|
95
|
+
'''
|
|
96
|
+
types = self._test(code)
|
|
97
|
+
self.assertIn(('func', (1, 0)), types)
|
|
98
|
+
variables = types.pop(('func', (1, 0)))
|
|
99
|
+
self.assertFalse(types)
|
|
100
|
+
self.assertEqual({'a': {'float', 'int', 'str'}, 'b': {'int'}}, variables)
|
|
101
|
+
|
|
102
|
+
def _test_typing_function_char_loop(self):
|
|
103
|
+
code = '''\
|
|
104
|
+
def func(x):
|
|
105
|
+
l = []
|
|
106
|
+
for c in x:
|
|
107
|
+
l.append(c)
|
|
108
|
+
return l
|
|
109
|
+
|
|
110
|
+
print(func('abcdefg'))
|
|
111
|
+
'''
|
|
112
|
+
types = self._test(code)
|
|
113
|
+
self.assertIn(('func', (1, 0)), types)
|
|
114
|
+
variables = types.pop(('func', (1, 0)))
|
|
115
|
+
self.assertFalse(types)
|
|
116
|
+
self.assertEqual({'a': {'int'}, 'i': {'int'}}, variables)
|
|
117
|
+
|
|
118
|
+
def test_typing_global_list(self):
|
|
119
|
+
code = '''\
|
|
120
|
+
a = [x for x in range(10)]
|
|
121
|
+
b = list(range(10))
|
|
122
|
+
c = a + b
|
|
123
|
+
d = [0]*10
|
|
124
|
+
'''
|
|
125
|
+
types = self._test(code)
|
|
126
|
+
self.assertIn((None, (1, 0)), types)
|
|
127
|
+
variables = types.pop((None, (1, 0)))
|
|
128
|
+
self.assertFalse(types)
|
|
129
|
+
self.assertEqual({'a': {'list'}, 'b': {'list'}, 'c': {'list'}, 'd': {'list'}}, variables)
|
|
130
|
+
|
|
131
|
+
def test_typing_function_list(self):
|
|
132
|
+
code = '''\
|
|
133
|
+
def func(x):
|
|
134
|
+
a = [[], []]
|
|
135
|
+
b = [0]* 10 + a
|
|
136
|
+
c = a[0]
|
|
137
|
+
|
|
138
|
+
print(func([0]*100))
|
|
139
|
+
'''
|
|
140
|
+
types = self._test(code)
|
|
141
|
+
self.assertIn(('func', (1, 0)), types)
|
|
142
|
+
variables = types.pop(('func', (1, 0)))
|
|
143
|
+
self.assertFalse(types)
|
|
144
|
+
self.assertEqual({'a': {'list'}, 'b': {'list'}, 'c': {'list'}, 'x': {'list'}}, variables)
|
|
145
|
+
|
|
146
|
+
def test_typing_global_dict(self):
|
|
147
|
+
code = '''\
|
|
148
|
+
a = dict()
|
|
149
|
+
b = {i: i**2 for i in range(10)}
|
|
150
|
+
c = a
|
|
151
|
+
'''
|
|
152
|
+
types = self._test(code)
|
|
153
|
+
self.assertIn((None, (1, 0)), types)
|
|
154
|
+
variables = types.pop((None, (1, 0)))
|
|
155
|
+
self.assertFalse(types)
|
|
156
|
+
self.assertEqual({'a': {'dict'}, 'b': {'dict'}, 'c': {'dict'}}, variables)
|
|
157
|
+
|
|
158
|
+
def test_typing_function_dict(self):
|
|
159
|
+
code = '''\
|
|
160
|
+
def func(x):
|
|
161
|
+
a = dict()
|
|
162
|
+
b = {i: i**2 for i in range(10)}
|
|
163
|
+
c = x
|
|
164
|
+
|
|
165
|
+
print(func({1:2, 'x':7}))
|
|
166
|
+
'''
|
|
167
|
+
types = self._test(code)
|
|
168
|
+
self.assertIn(('func', (1, 0)), types)
|
|
169
|
+
variables = types.pop(('func', (1, 0)))
|
|
170
|
+
self.assertFalse(types)
|
|
171
|
+
self.assertEqual({'a': {'dict'}, 'b': {'dict'}, 'c': {'dict'}, 'x': {'dict'}}, variables)
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
def test_typing_global_set(self):
|
|
175
|
+
code = '''\
|
|
176
|
+
a = set()
|
|
177
|
+
# b = {i for i in range(10)} # jedi does not support set comprehension yet
|
|
178
|
+
c = a
|
|
179
|
+
d = {1,2,3}
|
|
180
|
+
e = a | b
|
|
181
|
+
'''
|
|
182
|
+
types = self._test(code)
|
|
183
|
+
self.assertIn((None, (1, 0)), types)
|
|
184
|
+
variables = types.pop((None, (1, 0)))
|
|
185
|
+
self.assertFalse(types)
|
|
186
|
+
self.assertEqual({'a': {'set'}, 'c': {'set'}, 'd': {'set'}, 'e': {'set'}}, variables)
|
|
187
|
+
|
|
188
|
+
def test_typing_function_set(self):
|
|
189
|
+
code = '''\
|
|
190
|
+
def func(x):
|
|
191
|
+
a = set()
|
|
192
|
+
# b = {i for i in range(10)} # jedi does not support set comprehension yet
|
|
193
|
+
c = a
|
|
194
|
+
d = a | b
|
|
195
|
+
|
|
196
|
+
print(func({1,2,3}))
|
|
197
|
+
'''
|
|
198
|
+
types = self._test(code)
|
|
199
|
+
self.assertIn(('func', (1, 0)), types)
|
|
200
|
+
variables = types.pop(('func', (1, 0)))
|
|
201
|
+
self.assertFalse(types)
|
|
202
|
+
self.assertEqual({'a': {'set'}, 'c': {'set'}, 'd': {'set'}, 'x': {'set'}}, variables)
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
class TestTypeInjection(TestJediTyper):
|
|
206
|
+
"""
|
|
207
|
+
Subtype of TestJediTyper that additionally tests type injection and compilation.
|
|
208
|
+
"""
|
|
209
|
+
def setUp(self):
|
|
210
|
+
super().setUp()
|
|
211
|
+
compilation_options = Options.CompilationOptions(Options.default_options)
|
|
212
|
+
ctx = Main.Context.from_options(compilation_options)
|
|
213
|
+
transform = InterpretCompilerDirectives(ctx, ctx.compiler_directives)
|
|
214
|
+
transform.module_scope = Symtab.ModuleScope('__main__', None, ctx)
|
|
215
|
+
self.declarations_finder = DeclarationsFinder()
|
|
216
|
+
self.pipeline = [NormalizeTree(None), transform, self.declarations_finder]
|
|
217
|
+
|
|
218
|
+
def _test(self, code):
|
|
219
|
+
types, lines = _test_typing(code, inject=True)
|
|
220
|
+
tree = self.run_pipeline(self.pipeline, ''.join(lines))
|
|
221
|
+
directives = self.declarations_finder.directives
|
|
222
|
+
# TODO: validate directives
|
|
223
|
+
return types
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import unittest
|
|
2
|
+
|
|
3
|
+
from Cython import Shadow
|
|
4
|
+
from Cython.Compiler import Options, CythonScope, PyrexTypes, Errors
|
|
5
|
+
|
|
6
|
+
class TestShadow(unittest.TestCase):
|
|
7
|
+
def test_all_directives_in_shadow(self):
|
|
8
|
+
missing_directives = []
|
|
9
|
+
extra_directives = []
|
|
10
|
+
for full_directive in Options.directive_types.keys():
|
|
11
|
+
# Python 2 doesn't support "directive, *rest = full_directive.split('.')"
|
|
12
|
+
split_directive = full_directive.split('.')
|
|
13
|
+
directive, rest = split_directive[0], split_directive[1:]
|
|
14
|
+
|
|
15
|
+
scope = Options.directive_scopes.get(full_directive)
|
|
16
|
+
if scope and len(scope) == 1 and scope[0] == "module":
|
|
17
|
+
# module-scoped things can't be used from Cython
|
|
18
|
+
if hasattr(Shadow, directive):
|
|
19
|
+
extra_directives.append(full_directive)
|
|
20
|
+
continue
|
|
21
|
+
if full_directive == "collection_type":
|
|
22
|
+
# collection_type is current restricted to utility code only
|
|
23
|
+
# so doesn't need to be in Shadow
|
|
24
|
+
continue
|
|
25
|
+
if full_directive == "staticmethod":
|
|
26
|
+
# staticmethod is a weird special-case and not really intended to be
|
|
27
|
+
# used from the cython module
|
|
28
|
+
continue
|
|
29
|
+
|
|
30
|
+
if not hasattr(Shadow, directive):
|
|
31
|
+
missing_directives.append(full_directive)
|
|
32
|
+
elif rest:
|
|
33
|
+
directive_value = getattr(Shadow, directive)
|
|
34
|
+
for subdirective in rest:
|
|
35
|
+
if (hasattr(type(directive_value), '__getattr__') or
|
|
36
|
+
hasattr(type(directive_value), '__getattribute__')):
|
|
37
|
+
# skip things like "dataclasses" which override attribute lookup
|
|
38
|
+
break
|
|
39
|
+
self.assertEqual(missing_directives, [])
|
|
40
|
+
self.assertEqual(extra_directives, [])
|
|
41
|
+
|
|
42
|
+
def test_all_types_in_shadow(self):
|
|
43
|
+
cython_scope = CythonScope.create_cython_scope(None)
|
|
44
|
+
# Not doing load_cythonscope at this stage because it requires a proper context and
|
|
45
|
+
# Errors.py to be set up
|
|
46
|
+
|
|
47
|
+
missing_types = []
|
|
48
|
+
for key in cython_scope.entries.keys():
|
|
49
|
+
if key.startswith('__') and key.endswith('__'):
|
|
50
|
+
continue
|
|
51
|
+
if key in ('PyTypeObject', 'PyObject_TypeCheck'):
|
|
52
|
+
# These are declared in Shadow.py for reasons that look to
|
|
53
|
+
# be an implementation detail, but it isn't our intention for
|
|
54
|
+
# users to access them from Pure Python mode.
|
|
55
|
+
continue
|
|
56
|
+
if not hasattr(Shadow, key):
|
|
57
|
+
missing_types.append(key)
|
|
58
|
+
self.assertEqual(missing_types, [])
|
|
59
|
+
|
|
60
|
+
def test_int_types_in_shadow(self):
|
|
61
|
+
missing_types = []
|
|
62
|
+
for int_name in Shadow.int_types:
|
|
63
|
+
for sign in ['', 'u', 's']:
|
|
64
|
+
name = sign + int_name
|
|
65
|
+
|
|
66
|
+
if sign and (
|
|
67
|
+
int_name in ['Py_UNICODE', 'Py_UCS4', 'Py_ssize_t',
|
|
68
|
+
'ssize_t', 'ptrdiff_t', 'Py_hash_t'] or
|
|
69
|
+
name == "usize_t"):
|
|
70
|
+
# size_t is special-cased here a little since ssize_t legitimate
|
|
71
|
+
# but usize_t isn't
|
|
72
|
+
self.assertNotIn(name, dir(Shadow))
|
|
73
|
+
self.assertNotIn('p_' + name, dir(Shadow))
|
|
74
|
+
continue
|
|
75
|
+
|
|
76
|
+
if not hasattr(Shadow, name):
|
|
77
|
+
missing_types.append(name)
|
|
78
|
+
|
|
79
|
+
for ptr in range(1, 4):
|
|
80
|
+
ptr_name = 'p' * ptr + '_' + name
|
|
81
|
+
if not hasattr(Shadow, ptr_name):
|
|
82
|
+
missing_types.append(ptr_name)
|
|
83
|
+
self.assertEqual(missing_types, [])
|
|
84
|
+
|
|
85
|
+
def test_most_types(self):
|
|
86
|
+
# TODO it's unfortunately hard to get a definite list of types to confirm that they're
|
|
87
|
+
# present (because they're obtained by on-the-fly string parsing in `cython_scope.lookup_type`)
|
|
88
|
+
|
|
89
|
+
cython_scope = CythonScope.create_cython_scope(None)
|
|
90
|
+
# Set up just enough of "Context" and "Errors" that CythonScope.lookup_type can fail
|
|
91
|
+
class Context:
|
|
92
|
+
cpp = False
|
|
93
|
+
language_level = 3
|
|
94
|
+
future_directives = []
|
|
95
|
+
cython_scope._context = Context
|
|
96
|
+
Errors.init_thread()
|
|
97
|
+
|
|
98
|
+
missing_types = []
|
|
99
|
+
missing_lookups = []
|
|
100
|
+
for (signed, longness, name), type_ in PyrexTypes.modifiers_and_name_to_type.items():
|
|
101
|
+
if name == 'object':
|
|
102
|
+
continue # This probably shouldn't be in Shadow
|
|
103
|
+
if not hasattr(Shadow, name):
|
|
104
|
+
missing_types.append(name)
|
|
105
|
+
if not cython_scope.lookup_type(name):
|
|
106
|
+
missing_lookups.append(name)
|
|
107
|
+
for ptr in range(1, 4):
|
|
108
|
+
ptr_name = 'p' * ptr + '_' + name
|
|
109
|
+
if not hasattr(Shadow, ptr_name):
|
|
110
|
+
missing_types.append(ptr_name)
|
|
111
|
+
if not cython_scope.lookup_type(ptr_name):
|
|
112
|
+
missing_lookups.append(ptr_name)
|
|
113
|
+
self.assertEqual(missing_types, [])
|
|
114
|
+
self.assertEqual(missing_lookups, [])
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import unittest
|
|
2
|
+
|
|
3
|
+
from Cython import StringIOTree as stringtree
|
|
4
|
+
|
|
5
|
+
code = """
|
|
6
|
+
cdef int spam # line 1
|
|
7
|
+
|
|
8
|
+
cdef ham():
|
|
9
|
+
a = 1
|
|
10
|
+
b = 2
|
|
11
|
+
c = 3
|
|
12
|
+
d = 4
|
|
13
|
+
|
|
14
|
+
def eggs():
|
|
15
|
+
pass
|
|
16
|
+
|
|
17
|
+
cpdef bacon():
|
|
18
|
+
print spam
|
|
19
|
+
print 'scotch'
|
|
20
|
+
print 'tea?'
|
|
21
|
+
print 'or coffee?' # line 16
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
linemap = dict(enumerate(code.splitlines()))
|
|
25
|
+
|
|
26
|
+
class TestStringIOTree(unittest.TestCase):
|
|
27
|
+
|
|
28
|
+
def setUp(self):
|
|
29
|
+
self.tree = stringtree.StringIOTree()
|
|
30
|
+
|
|
31
|
+
def test_markers(self):
|
|
32
|
+
assert not self.tree.allmarkers()
|
|
33
|
+
|
|
34
|
+
def test_insertion(self):
|
|
35
|
+
self.write_lines((1, 2, 3))
|
|
36
|
+
line_4_to_6_insertion_point = self.tree.insertion_point()
|
|
37
|
+
self.write_lines((7, 8))
|
|
38
|
+
line_9_to_13_insertion_point = self.tree.insertion_point()
|
|
39
|
+
self.write_lines((14, 15, 16))
|
|
40
|
+
|
|
41
|
+
line_4_insertion_point = line_4_to_6_insertion_point.insertion_point()
|
|
42
|
+
self.write_lines((5, 6), tree=line_4_to_6_insertion_point)
|
|
43
|
+
|
|
44
|
+
line_9_to_12_insertion_point = (
|
|
45
|
+
line_9_to_13_insertion_point.insertion_point())
|
|
46
|
+
self.write_line(13, tree=line_9_to_13_insertion_point)
|
|
47
|
+
|
|
48
|
+
self.write_line(4, tree=line_4_insertion_point)
|
|
49
|
+
self.write_line(9, tree=line_9_to_12_insertion_point)
|
|
50
|
+
line_10_insertion_point = line_9_to_12_insertion_point.insertion_point()
|
|
51
|
+
self.write_line(11, tree=line_9_to_12_insertion_point)
|
|
52
|
+
self.write_line(10, tree=line_10_insertion_point)
|
|
53
|
+
self.write_line(12, tree=line_9_to_12_insertion_point)
|
|
54
|
+
|
|
55
|
+
self.assertEqual(self.tree.allmarkers(), list(range(1, 17)))
|
|
56
|
+
self.assertEqual(code.strip(), self.tree.getvalue().strip())
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def write_lines(self, linenos, tree=None):
|
|
60
|
+
for lineno in linenos:
|
|
61
|
+
self.write_line(lineno, tree=tree)
|
|
62
|
+
|
|
63
|
+
def write_line(self, lineno, tree=None):
|
|
64
|
+
if tree is None:
|
|
65
|
+
tree = self.tree
|
|
66
|
+
tree.markers.append(lineno)
|
|
67
|
+
tree.write(linemap[lineno] + '\n')
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import os.path
|
|
2
|
+
import unittest
|
|
3
|
+
import tempfile
|
|
4
|
+
import textwrap
|
|
5
|
+
import shutil
|
|
6
|
+
|
|
7
|
+
from ..TestUtils import write_file, write_newer_file, _parse_pattern
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class TestTestUtils(unittest.TestCase):
|
|
11
|
+
def setUp(self):
|
|
12
|
+
super().setUp()
|
|
13
|
+
self.temp_dir = tempfile.mkdtemp()
|
|
14
|
+
|
|
15
|
+
def tearDown(self):
|
|
16
|
+
if self.temp_dir and os.path.isdir(self.temp_dir):
|
|
17
|
+
shutil.rmtree(self.temp_dir)
|
|
18
|
+
super().tearDown()
|
|
19
|
+
|
|
20
|
+
def _test_path(self, filename):
|
|
21
|
+
return os.path.join(self.temp_dir, filename)
|
|
22
|
+
|
|
23
|
+
def _test_write_file(self, content, expected, **kwargs):
|
|
24
|
+
file_path = self._test_path("abcfile")
|
|
25
|
+
write_file(file_path, content, **kwargs)
|
|
26
|
+
assert os.path.isfile(file_path)
|
|
27
|
+
|
|
28
|
+
with open(file_path, 'rb') as f:
|
|
29
|
+
found = f.read()
|
|
30
|
+
assert found == expected, (repr(expected), repr(found))
|
|
31
|
+
|
|
32
|
+
def test_write_file_text(self):
|
|
33
|
+
text = "abcüöä"
|
|
34
|
+
self._test_write_file(text, text.encode('utf8'))
|
|
35
|
+
|
|
36
|
+
def test_write_file_dedent(self):
|
|
37
|
+
text = """
|
|
38
|
+
A horse is a horse,
|
|
39
|
+
of course, of course,
|
|
40
|
+
And no one can talk to a horse
|
|
41
|
+
of course
|
|
42
|
+
"""
|
|
43
|
+
self._test_write_file(text, textwrap.dedent(text).encode('utf8'), dedent=True)
|
|
44
|
+
|
|
45
|
+
def test_write_file_bytes(self):
|
|
46
|
+
self._test_write_file(b"ab\0c", b"ab\0c")
|
|
47
|
+
|
|
48
|
+
def test_write_newer_file(self):
|
|
49
|
+
file_path_1 = self._test_path("abcfile1.txt")
|
|
50
|
+
file_path_2 = self._test_path("abcfile2.txt")
|
|
51
|
+
write_file(file_path_1, "abc")
|
|
52
|
+
assert os.path.isfile(file_path_1)
|
|
53
|
+
write_newer_file(file_path_2, file_path_1, "xyz")
|
|
54
|
+
assert os.path.isfile(file_path_2)
|
|
55
|
+
assert os.path.getmtime(file_path_2) > os.path.getmtime(file_path_1)
|
|
56
|
+
|
|
57
|
+
def test_write_newer_file_same(self):
|
|
58
|
+
file_path = self._test_path("abcfile.txt")
|
|
59
|
+
write_file(file_path, "abc")
|
|
60
|
+
mtime = os.path.getmtime(file_path)
|
|
61
|
+
write_newer_file(file_path, file_path, "xyz")
|
|
62
|
+
assert os.path.getmtime(file_path) > mtime
|
|
63
|
+
|
|
64
|
+
def test_write_newer_file_fresh(self):
|
|
65
|
+
file_path = self._test_path("abcfile.txt")
|
|
66
|
+
assert not os.path.exists(file_path)
|
|
67
|
+
write_newer_file(file_path, file_path, "xyz")
|
|
68
|
+
assert os.path.isfile(file_path)
|
|
69
|
+
|
|
70
|
+
def test_parse_pattern(self):
|
|
71
|
+
self.assertEqual(
|
|
72
|
+
_parse_pattern("pattern"),
|
|
73
|
+
(None, None, 'pattern')
|
|
74
|
+
)
|
|
75
|
+
self.assertEqual(
|
|
76
|
+
_parse_pattern("/start/:pattern"),
|
|
77
|
+
('start', None, 'pattern')
|
|
78
|
+
)
|
|
79
|
+
self.assertEqual(
|
|
80
|
+
_parse_pattern(":/end/ pattern"),
|
|
81
|
+
(None, 'end', 'pattern')
|
|
82
|
+
)
|
|
83
|
+
self.assertEqual(
|
|
84
|
+
_parse_pattern("/start/:/end/ pattern"),
|
|
85
|
+
('start', 'end', 'pattern')
|
|
86
|
+
)
|
|
87
|
+
self.assertEqual(
|
|
88
|
+
_parse_pattern("/start/:/end/pattern"),
|
|
89
|
+
('start', 'end', 'pattern')
|
|
90
|
+
)
|
Cython/Tests/__init__.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# empty file
|