1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
|
import builtins
import json
import subprocess
import sys
import unittest
from ..Builtin import (
inferred_method_return_types, find_return_type_of_builtin_method,
unsafe_compile_time_methods, is_safe_compile_time_method,
builtin_scope,
)
from ..Code import (
KNOWN_PYTHON_BUILTINS_VERSION, KNOWN_PYTHON_BUILTINS,
)
class TestBuiltinReturnTypes(unittest.TestCase):
def test_find_return_type_of_builtin_method(self):
# It's enough to test the method existence in a recent Python that likely has them.
look_up_methods = sys.version_info >= (3,10)
for type_name, methods in inferred_method_return_types.items():
py_type = getattr(builtins, type_name if type_name != 'unicode' else 'str')
for method_name, return_type_name in methods.items():
builtin_type = builtin_scope.lookup(type_name).type
return_type = find_return_type_of_builtin_method(builtin_type, method_name)
if return_type.is_builtin_type:
if '[' in return_type_name:
return_type_name = return_type_name.partition('[')[0]
if return_type_name == 'T':
return_type_name = type_name
self.assertEqual(return_type.name, return_type_name)
if look_up_methods:
self.assertTrue(hasattr(py_type, method_name), f"{type_name}.{method_name}")
else:
self.assertEqual(return_type.empty_declaration_code(pyrex=True), return_type_name)
class TestBuiltinCompatibility(unittest.TestCase):
def test_python_builtin_compatibility(self):
expected_builtins = set(KNOWN_PYTHON_BUILTINS)
if sys.platform != 'win32':
expected_builtins.discard("WindowsError")
# Read builtins from fresh Python process to prevent modifications by test dependencies.
output = subprocess.run(
[sys.executable, '-c', 'import builtins, json, sys; sys.stdout.write(json.dumps(dir(builtins)))'],
capture_output=True,
encoding='utf8',
)
runtime_builtins = frozenset(
name for name in json.loads(output.stdout)
if name not in ('__doc__', '__loader__', '__name__', '__package__', '__spec__'))
if sys.version_info < KNOWN_PYTHON_BUILTINS_VERSION:
missing_builtins = expected_builtins - runtime_builtins
if missing_builtins:
self.skipTest(f'skipping test, older Python release found. Missing builtins: {", ".join(sorted(missing_builtins))}')
self.skipTest('skipping test, older Python release found.')
self.assertSetEqual(runtime_builtins, expected_builtins)
def test_unsafe_compile_time_methods(self):
"""Validate the table of builtin methods that are not safe for compile time evaluation
against the table of known builtin methods (and their types).
"""
for builtin_type_name, unsafe_methods in unsafe_compile_time_methods.items():
self.assertIsInstance(unsafe_methods, set)
builtin_type = getattr(builtins, builtin_type_name) # All named types must exist as builtin types.
known_methods = sorted(
inferred_method_return_types[builtin_type_name]) # All types are also in "inferred_method_return_types".
self.assertFalse(unsafe_methods.difference(known_methods)) # Only known methods are listed.
for method_name in known_methods:
builtin_method = getattr(builtin_type, method_name, None)
if builtin_method is None:
self.assertIn(method_name, unsafe_methods) # Non-portable methods are always unsafe.
continue
|