Cython 3.3.0a2.dev0__py3-none-any.whl → 3.3.0b1__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 (72) hide show
  1. Cython/Build/Dependencies.py +12 -7
  2. Cython/Build/SharedModule.py +99 -18
  3. Cython/Build/Tests/TestInline.py +1 -1
  4. Cython/CodeWriter.py +14 -4
  5. Cython/Compiler/Buffer.py +0 -1
  6. Cython/Compiler/Builtin.py +158 -53
  7. Cython/Compiler/CmdLine.py +154 -44
  8. Cython/Compiler/Code.pxd +2 -0
  9. Cython/Compiler/Code.py +58 -205
  10. Cython/Compiler/CythonScope.py +14 -0
  11. Cython/Compiler/ExprNodes.py +614 -322
  12. Cython/Compiler/FlowControl.pxd +46 -33
  13. Cython/Compiler/FlowControl.py +5 -3
  14. Cython/Compiler/FusedNode.py +15 -13
  15. Cython/Compiler/MatchCaseNodes.py +15 -12
  16. Cython/Compiler/ModuleNode.py +47 -19
  17. Cython/Compiler/Naming.py +3 -0
  18. Cython/Compiler/Nodes.py +400 -37
  19. Cython/Compiler/Optimize.py +172 -63
  20. Cython/Compiler/Options.py +2 -0
  21. Cython/Compiler/ParseTreeTransforms.pxd +1 -0
  22. Cython/Compiler/ParseTreeTransforms.py +67 -3
  23. Cython/Compiler/Parsing.pxd +1 -1
  24. Cython/Compiler/Parsing.py +117 -100
  25. Cython/Compiler/PyrexTypes.py +529 -56
  26. Cython/Compiler/Scanning.pxd +3 -3
  27. Cython/Compiler/StringEncoding.py +92 -35
  28. Cython/Compiler/Symtab.py +45 -16
  29. Cython/Compiler/Tests/TestBuiltin.py +126 -47
  30. Cython/Compiler/Tests/TestCmdLine.py +66 -1
  31. Cython/Compiler/Tests/TestTypes.py +2 -1
  32. Cython/Compiler/Tests/TestVisitor.py +60 -2
  33. Cython/Compiler/TreeFragment.py +6 -5
  34. Cython/Compiler/TypeInference.py +2 -2
  35. Cython/Compiler/UFuncs.py +7 -1
  36. Cython/Compiler/UtilNodes.py +0 -24
  37. Cython/Compiler/UtilityCode.py +9 -3
  38. Cython/Compiler/Visitor.pxd +2 -3
  39. Cython/Compiler/Visitor.py +74 -24
  40. Cython/Debugger/Cygdb.py +50 -13
  41. Cython/Distutils/build_ext.py +4 -0
  42. Cython/Includes/cpython/array.pxd +4 -4
  43. Cython/LZSS.py +35 -21
  44. Cython/Shadow.py +8 -1
  45. Cython/TestUtils.py +10 -6
  46. Cython/Tests/TestShadow.py +16 -1
  47. Cython/Utility/AsyncGen.c +93 -12
  48. Cython/Utility/Builtins.c +178 -43
  49. Cython/Utility/CConvert.pyx +6 -2
  50. Cython/Utility/Coroutine.c +3 -0
  51. Cython/Utility/CpdefEnums.pyx +37 -25
  52. Cython/Utility/CythonFunction.c +74 -45
  53. Cython/Utility/Exceptions.c +298 -5
  54. Cython/Utility/Exceptions_Cy.pyx +109 -0
  55. Cython/Utility/ExtensionTypes.c +26 -13
  56. Cython/Utility/FunctionArguments.c +9 -2
  57. Cython/Utility/ImportExport.c +53 -11
  58. Cython/Utility/MatchCase.c +5 -3
  59. Cython/Utility/MemoryView.pyx +17 -17
  60. Cython/Utility/ModuleSetupCode.c +147 -182
  61. Cython/Utility/ObjectHandling.c +108 -76
  62. Cython/Utility/Optimize.c +13 -12
  63. Cython/Utility/StringTools.c +142 -22
  64. Cython/Utility/TypeConversion.c +32 -0
  65. Cython/Utility/arrayarray.h +16 -18
  66. Cython/Utils.py +3 -0
  67. cython-3.3.0b1.dist-info/METADATA +286 -0
  68. {cython-3.3.0a2.dev0.dist-info → cython-3.3.0b1.dist-info}/RECORD +71 -70
  69. cython-3.3.0a2.dev0.dist-info/METADATA +0 -74
  70. {cython-3.3.0a2.dev0.dist-info → cython-3.3.0b1.dist-info}/WHEEL +0 -0
  71. {cython-3.3.0a2.dev0.dist-info → cython-3.3.0b1.dist-info}/entry_points.txt +0 -0
  72. {cython-3.3.0a2.dev0.dist-info → cython-3.3.0b1.dist-info}/top_level.txt +0 -0
@@ -12,7 +12,7 @@ from collections.abc import Iterable
12
12
 
13
13
  try:
14
14
  import pythran
15
- except:
15
+ except Exception:
16
16
  pythran = None
17
17
 
18
18
  from .. import Utils
@@ -29,7 +29,8 @@ copy_once_if_newer = cached_function(copy_file_to_dir_if_newer)
29
29
  safe_makedirs_once = cached_function(safe_makedirs)
30
30
 
31
31
 
32
- def _make_relative(file_paths, base=None):
32
+ @cython.cfunc
33
+ def _make_relative(file_paths, base=None) -> list[str]:
33
34
  if not base:
34
35
  base = os.getcwd()
35
36
  if base[-1] != os.path.sep:
@@ -158,6 +159,7 @@ distutils_settings = {
158
159
  }
159
160
 
160
161
 
162
+ @cython.cfunc
161
163
  def _legacy_strtobool(val):
162
164
  # Used to be "distutils.util.strtobool", adapted for deprecation warnings.
163
165
  if val == "True":
@@ -1183,12 +1185,15 @@ if os.environ.get('XML_RESULTS'):
1183
1185
  def record_results(func):
1184
1186
  def with_record(*args):
1185
1187
  t = time.time()
1186
- success = True
1188
+ success = False
1187
1189
  try:
1188
- try:
1189
- func(*args)
1190
- except:
1191
- success = False
1190
+ func(*args)
1191
+ success = True
1192
+ except Exception:
1193
+ # It's not obvious that we should really swallow the exception here,
1194
+ # rather than fail loudly after writing the XML result file,
1195
+ # but that's how it's currently implemented.
1196
+ pass
1192
1197
  finally:
1193
1198
  t = time.time() - t
1194
1199
  module = fully_qualified_name(args[0])
@@ -5,9 +5,88 @@ from Cython.Compiler import (
5
5
  )
6
6
  from Cython.Compiler.StringEncoding import EncodedString
7
7
  from Cython.Compiler.Scanning import SharedUtilitySourceDescriptor
8
+ from Cython.Compiler.Errors import warning
8
9
 
9
10
 
10
- def create_shared_library_pipeline(context, scope, options, result):
11
+ def list_of_features(included=None, excluded=None, _list_of_features=[]):
12
+ if _list_of_features:
13
+ feature_names = _list_of_features[:]
14
+ else:
15
+ feature_names = sorted({feature_name for feature_name, _, _ in _iter_exports()})
16
+ _list_of_features[:] = feature_names
17
+
18
+ return _select_features(feature_names, included, excluded)
19
+
20
+
21
+ def _select_features(all_names, included, excluded):
22
+ names = all_names
23
+ if included:
24
+ included = set(included)
25
+ unknown = included.difference(all_names)
26
+ if unknown:
27
+ warning(None, f"Unknown shared module features selected: {', '.join(sorted(unknown))}")
28
+
29
+ names = [name for name in names if name in included]
30
+
31
+ if excluded:
32
+ excluded = set(excluded)
33
+ unknown = excluded.difference(all_names)
34
+ if unknown:
35
+ warning(None, f"Unknown shared module features excluded: {', '.join(sorted(unknown))}")
36
+ unused = excluded.difference(names)
37
+ if unused:
38
+ warning(None, f"Shared module features excluded that was not included: {', '.join(sorted(unused))}")
39
+
40
+ names = [name for name in names if name not in excluded]
41
+
42
+ return names
43
+
44
+
45
+ def _iter_exports(selected_features=None):
46
+ UtilityCode = Code.UtilityCode
47
+ match_special = UtilityCode.get_special_comment_matcher('/')
48
+
49
+ for c_utility_file in os.listdir(Code.get_utility_dir()):
50
+ if not c_utility_file.endswith('.c'):
51
+ continue
52
+
53
+ file_base_name = os.path.splitext(os.path.basename(c_utility_file))[0]
54
+ current_feature_name = file_base_name.partition('_')[0]
55
+
56
+ current_section = None
57
+ for line in Code.read_utilities_hook(c_utility_file):
58
+ if '//' not in line or not line.startswith('//'):
59
+ continue
60
+ match = match_special(line)
61
+ if match is None:
62
+ continue
63
+
64
+ name = match.group('name')
65
+ if name:
66
+ if current_section:
67
+ if selected_features is None or current_section[0] in selected_features:
68
+ yield current_section
69
+ current_section = None
70
+
71
+ section_title = UtilityCode.match_section_title(name) if '.export' in name else None
72
+ if section_title:
73
+ name, section_type = section_title.groups()
74
+ if section_type == 'export':
75
+ current_section = [current_feature_name, name, c_utility_file]
76
+
77
+ elif (tag := match.group('tag')) and tag.startswith('feature') and current_section:
78
+ explicit_feature_name = tag.split(':', 1)[-1].strip()
79
+ assert current_section[0] == current_feature_name, (
80
+ "Conflicting feature names given to the same utility code section: "
81
+ f"{current_section[0]!r} and {explicit_feature_name!r}")
82
+ current_section[0] = explicit_feature_name
83
+
84
+ if current_section:
85
+ if selected_features is None or current_section[0] in selected_features:
86
+ yield current_section
87
+
88
+
89
+ def create_shared_library_pipeline(context, scope, options, result, selected_features=None):
11
90
 
12
91
  parse = Pipeline.parse_stage_factory(context)
13
92
 
@@ -15,11 +94,13 @@ def create_shared_library_pipeline(context, scope, options, result):
15
94
  def generate_tree(compsrc):
16
95
  tree = parse(compsrc)
17
96
 
18
- tree.scope.use_utility_code(
19
- MemoryView.get_view_utility_code(options.shared_utility_qualified_name))
97
+ if selected_features is None or 'MemoryView' in selected_features:
98
+ tree.scope.use_utility_code(
99
+ MemoryView.get_view_utility_code(options.shared_utility_qualified_name))
100
+
101
+ tree.scope.use_utility_code(MemoryView._get_memviewslice_declare_code())
102
+ tree.scope.use_utility_code(MemoryView._get_typeinfo_to_format_code())
20
103
 
21
- tree.scope.use_utility_code(MemoryView._get_memviewslice_declare_code())
22
- tree.scope.use_utility_code(MemoryView._get_typeinfo_to_format_code())
23
104
  context.include_directories.append(Code.get_utility_dir())
24
105
  return tree
25
106
 
@@ -27,18 +108,8 @@ def create_shared_library_pipeline(context, scope, options, result):
27
108
 
28
109
  def generate_c_utilities(module_node):
29
110
  UtilityCode = Code.UtilityCode
30
- match_special = UtilityCode.get_special_comment_matcher('/')
31
- for c_utility_file in os.listdir(Code.get_utility_dir()):
32
- if not c_utility_file.endswith('.c'):
33
- continue
34
- for line in Code.read_utilities_hook(c_utility_file):
35
- if not ((m := match_special(line)) and (name := m.group('name'))):
36
- continue
37
- if not (section_title := UtilityCode.match_section_title(name)):
38
- continue
39
- name, section_type = section_title.groups()
40
- if section_type == 'export':
41
- module_node.scope.use_utility_code(UtilityCode.load_cached(name, c_utility_file))
111
+ for _, name, c_utility_file in _iter_exports(selected_features):
112
+ module_node.scope.use_utility_code(UtilityCode.load_cached(name, c_utility_file))
42
113
  return module_node
43
114
 
44
115
  orig_cimport_from_pyx = Options.cimport_from_pyx
@@ -71,6 +142,13 @@ def generate_shared_module(options):
71
142
  pyx_file = os.path.splitext(dest_c_file)[0] + '.pyx'
72
143
  module_name = os.path.splitext(os.path.basename(dest_c_file))[0]
73
144
 
145
+ selected_features = None
146
+ if options.shared_utility_features_enabled or options.shared_utility_features_disabled:
147
+ selected_features = list_of_features(
148
+ options.shared_utility_features_enabled,
149
+ options.shared_utility_features_disabled,
150
+ )
151
+
74
152
  context = Main.Context.from_options(options)
75
153
  scope = Symtab.ModuleScope('MemoryView', parent_module = None, context = context, is_package=False)
76
154
 
@@ -78,7 +156,10 @@ def generate_shared_module(options):
78
156
  comp_src = Main.CompilationSource(source_desc, EncodedString(module_name), os.getcwd())
79
157
  result = Main.create_default_resultobj(comp_src, options)
80
158
 
81
- pipeline = create_shared_library_pipeline(context, scope, options, result)
159
+ pipeline = create_shared_library_pipeline(
160
+ context, scope, options, result,
161
+ selected_features=selected_features,
162
+ )
82
163
  err, enddata = Pipeline.run_pipeline(pipeline, comp_src)
83
164
 
84
165
  return err, enddata
@@ -8,7 +8,7 @@ from Cython.TestUtils import CythonTest, TimedTest
8
8
  try:
9
9
  import numpy
10
10
  has_numpy = True
11
- except:
11
+ except Exception:
12
12
  has_numpy = False
13
13
 
14
14
  test_kwds = dict(force=True, quiet=True)
Cython/CodeWriter.py CHANGED
@@ -673,7 +673,7 @@ class ExpressionWriter(TreeVisitor):
673
673
  def visit_CondExprNode(self, node):
674
674
  self.visit(node.true_val)
675
675
  self.put(" if ")
676
- self.visit(node.test)
676
+ self.visit(node.condition)
677
677
  self.put(" else ")
678
678
  self.visit(node.false_val)
679
679
 
@@ -748,9 +748,19 @@ class ExpressionWriter(TreeVisitor):
748
748
  self.visit(node.expr)
749
749
 
750
750
  def visit_DictComprehensionAppendNode(self, node):
751
- self.visit(node.key_expr)
752
- self.put(": ")
753
- self.visit(node.value_expr)
751
+ item = node.dict_item
752
+ if isinstance(item, DictItemNode):
753
+ self.visit(item.key)
754
+ self.put(": ")
755
+ self.visit(item.value)
756
+ else:
757
+ is_simple = item.is_name or item.is_attribute
758
+ self.put("**")
759
+ if not is_simple:
760
+ self.put("(")
761
+ self.visit(item)
762
+ if not is_simple:
763
+ self.put(")")
754
764
 
755
765
  def visit_ComprehensionNode(self, node):
756
766
  tpmap = {'list': "[]", 'dict': "{}", 'set': "{}"}
Cython/Compiler/Buffer.py CHANGED
@@ -674,7 +674,6 @@ raise_indexerror_nogil = load_buffer_utility("BufferIndexErrorNogil")
674
674
  raise_buffer_fallback_code = load_buffer_utility("BufferFallbackError")
675
675
 
676
676
  acquire_utility_code = load_buffer_utility("BufferGetAndValidate", context=context)
677
- buffer_format_check_code = load_buffer_utility("BufferFormatCheck", context=context)
678
677
 
679
678
  # See utility code BufferFormatFromTypeInfo
680
679
  _typeinfo_to_format_code = load_buffer_utility("TypeInfoToFormat")
@@ -2,10 +2,11 @@
2
2
  # Builtin Definitions
3
3
  #
4
4
 
5
+ from itertools import chain
5
6
 
6
7
  from .StringEncoding import EncodedString
7
8
  from .Symtab import BuiltinScope, StructOrUnionScope, ModuleScope, Entry
8
- from .Code import UtilityCode, TempitaUtilityCode, KNOWN_PYTHON_BUILTINS, uncachable_builtins
9
+ from .Code import UtilityCode, TempitaUtilityCode
9
10
  from .TypeSlots import Signature
10
11
  from . import PyrexTypes
11
12
 
@@ -349,6 +350,13 @@ builtin_function_table = [
349
350
 
350
351
  # Builtin types
351
352
 
353
+ hidden_builtin_types = [
354
+ # These are not in the user visible 'builtins' namespace.
355
+ 'dict_keys',
356
+ 'dict_values',
357
+ 'dict_items',
358
+ ]
359
+
352
360
  builtin_types_table = [
353
361
 
354
362
  ("type", "&PyType_Type", []),
@@ -357,6 +365,9 @@ builtin_types_table = [
357
365
 
358
366
  ("int", "&PyLong_Type", []),
359
367
  ("float", "&PyFloat_Type", []),
368
+ ("dict_keys", "&PyDictKeys_Type", []),
369
+ ("dict_values", "&PyDictValues_Type", []),
370
+ ("dict_items", "&PyDictItems_Type", []),
360
371
 
361
372
  ("complex", "&PyComplex_Type", [BuiltinAttribute('cval', field_type_name = 'Py_complex'),
362
373
  BuiltinAttribute('real', 'cval.real', field_type = PyrexTypes.c_double_type),
@@ -390,11 +401,14 @@ builtin_types_table = [
390
401
  ("dict", "&PyDict_Type", [BuiltinMethod("__contains__", "TO", "b", "PyDict_Contains"),
391
402
  BuiltinMethod("has_key", "TO", "b", "PyDict_Contains"),
392
403
  BuiltinMethod("items", "T", "O", "__Pyx_PyDict_Items",
393
- utility_code=UtilityCode.load("py_dict_items", "Builtins.c")),
404
+ utility_code=UtilityCode.load("py_dict_items", "Builtins.c"),
405
+ builtin_return_type='dict_items'),
394
406
  BuiltinMethod("keys", "T", "O", "__Pyx_PyDict_Keys",
395
- utility_code=UtilityCode.load("py_dict_keys", "Builtins.c")),
407
+ utility_code=UtilityCode.load("py_dict_keys", "Builtins.c"),
408
+ builtin_return_type='dict_keys'),
396
409
  BuiltinMethod("values", "T", "O", "__Pyx_PyDict_Values",
397
- utility_code=UtilityCode.load("py_dict_values", "Builtins.c")),
410
+ utility_code=UtilityCode.load("py_dict_values", "Builtins.c"),
411
+ builtin_return_type='dict_values'),
398
412
  BuiltinMethod("iteritems", "T", "O", "__Pyx_PyDict_IterItems",
399
413
  utility_code=UtilityCode.load("py_dict_iteritems", "Builtins.c")),
400
414
  BuiltinMethod("iterkeys", "T", "O", "__Pyx_PyDict_IterKeys",
@@ -443,8 +457,6 @@ builtin_types_table = [
443
457
  BuiltinMethod("add", "TO", "r", "PySet_Add"),
444
458
  BuiltinMethod("pop", "T", "O", "PySet_Pop")]),
445
459
  ("frozenset", "&PyFrozenSet_Type", []),
446
- ("BaseException", "((PyTypeObject*)PyExc_BaseException)", []),
447
- ("Exception", "((PyTypeObject*)PyExc_Exception)", []),
448
460
  ("memoryview", "&PyMemoryView_Type", [
449
461
  # TODO - format would be nice, but hard to get
450
462
  # __len__ can be accessed through a direct lookup of the buffer (but probably in Optimize.c)
@@ -482,7 +494,7 @@ types_that_construct_their_instance = frozenset({
482
494
  'tuple', 'list', 'dict', 'frozendict', 'set', 'frozenset',
483
495
  'memoryview', 'range', 'slice', 'sentinel',
484
496
  # All builtin exception types create their own instance.
485
- *filter(PyrexTypes.is_exception_type_name, KNOWN_PYTHON_BUILTINS),
497
+ *PyrexTypes.KNOWN_EXCEPTION_NAMES,
486
498
 
487
499
  # These types don't currently have a purpose and might become restrictive:
488
500
  #'object',
@@ -497,7 +509,10 @@ types_that_construct_their_instance = frozenset({
497
509
  # When updating this mapping, also update "unsafe_compile_time_methods" below
498
510
  # if methods are added that are not safe to evaluate at compile time.
499
511
  # 'T' - type identical to type in dictionary key
500
- # 'I' - type from subscript - e.g. for list[int], I is `int`
512
+ # 'I' - type of index type:
513
+ # - value type from subscript - e.g. for list[int], I is `int`
514
+ # - for mappings this is the second subscripted type - e.g. for dict[int, str], I is `str`
515
+ # 'K' - key type of dictionary - e.g. for dict[int, str], K is `int`
501
516
  inferred_method_return_types = {
502
517
  'complex': dict(
503
518
  conjugate='complex',
@@ -631,7 +646,7 @@ inferred_method_return_types = {
631
646
  tolist='list',
632
647
  toreadonly='T',
633
648
  ),
634
- 'set': dict(
649
+ 'frozenset': dict(
635
650
  copy='T',
636
651
  difference='T',
637
652
  intersection='T',
@@ -640,17 +655,20 @@ inferred_method_return_types = {
640
655
  issuperset='bint',
641
656
  symmetric_difference='T',
642
657
  union='T',
643
- pop='I',
644
658
  ),
645
- 'frozenset': dict(
646
- # Inherited from 'set' below.
659
+ 'set': dict(
660
+ # Inherited from 'frozenset' above.
661
+ pop='I',
647
662
  ),
648
663
  'dict': dict(
649
664
  copy='T',
650
665
  fromkeys='T', # classmethod
651
- popitem='tuple',
666
+ popitem='tuple[K,I]',
652
667
  pop='I',
653
668
  get='I',
669
+ keys='dict_keys[K]',
670
+ values='dict_values[I]',
671
+ items='dict_items[tuple[K,I]]'
654
672
  ),
655
673
  'frozendict': dict(
656
674
  copy='T',
@@ -659,36 +677,55 @@ inferred_method_return_types = {
659
677
  }
660
678
 
661
679
  inferred_method_return_types['bytearray'].update(inferred_method_return_types['bytes'])
662
- inferred_method_return_types['frozenset'].update(inferred_method_return_types['set'])
680
+ inferred_method_return_types['set'].update(inferred_method_return_types['frozenset'])
681
+
682
+
683
+ def _parse_atomic_signature(builtin_type, sig: str) -> PyrexTypes.PyrexType:
684
+ # Roughly ordered by frequency of occurrence to reduce lookup cost.
685
+ if sig == 'T':
686
+ return builtin_type
687
+ elif sig == 'bint':
688
+ return PyrexTypes.c_bint_type
689
+ elif sig == 'Py_ssize_t':
690
+ return PyrexTypes.c_py_ssize_t_type
691
+ elif sig == 'object':
692
+ return PyrexTypes.py_object_type
693
+ elif sig == 'I':
694
+ return builtin_type.infer_indexed_type() or PyrexTypes.py_object_type
695
+ elif sig == 'K' and builtin_type.is_pyanydict_type:
696
+ return builtin_type.infer_iterator_type() or PyrexTypes.py_object_type
697
+ entry = builtin_scope.lookup(sig)
698
+ if entry is None:
699
+ # Unnamed builtin.
700
+ return builtin_types[sig]
701
+ return entry.type
702
+
703
+
704
+ def _parse_signature(pos, env, builtin_type, return_signature: str) -> PyrexTypes.PyrexType:
705
+ if '[' in return_signature:
706
+ container_name, _, subscript_signature = return_signature[:-1].partition('[')
707
+ container_entry = builtin_scope.lookup(container_name)
708
+ container_type = container_entry.type if container_entry is not None else builtin_types[container_name]
709
+
710
+ if container_name in ('tuple', 'dict', 'frozendict'):
711
+ parsed_subscripted_types = [
712
+ _parse_signature(pos, env, builtin_type, sg)
713
+ for sg in subscript_signature.split(',')
714
+ ]
715
+ else:
716
+ parsed_subscripted_types = [_parse_signature(pos, env, builtin_type, subscript_signature)]
717
+ return container_type.specialize_here(pos, env, parsed_subscripted_types)
718
+ return _parse_atomic_signature(builtin_type, return_signature)
663
719
 
664
720
 
665
- def find_return_type_of_builtin_method(pos, env, builtin_type, method_name):
721
+ def find_return_type_of_builtin_method(pos, env, builtin_type, method_name) -> PyrexTypes.PyrexType:
666
722
  container_type = builtin_type.get_container_type()
667
723
  type_name = container_type.name if container_type else builtin_type.name
668
724
  if type_name in inferred_method_return_types:
669
725
  methods = inferred_method_return_types[type_name]
670
726
  if method_name in methods:
671
- subscripted_type_names: str = ''
672
- return_type_name = methods[method_name]
673
- if '[' in return_type_name:
674
- return_type_name, _, subscripted_type_names = return_type_name[:-1].partition('[')
675
- if return_type_name == 'T':
676
- return builtin_type
677
- if return_type_name == 'I':
678
- return builtin_type.infer_indexed_type() or PyrexTypes.py_object_type
679
- if 'T' in subscripted_type_names:
680
- subscripted_type_names = subscripted_type_names.replace('T', builtin_type.name)
681
- if return_type_name == 'bint':
682
- return PyrexTypes.c_bint_type
683
- elif return_type_name == 'Py_ssize_t':
684
- return PyrexTypes.c_py_ssize_t_type
685
- container_type = builtin_scope.lookup(return_type_name).type
686
- if subscripted_type_names:
687
- subscripted_types = [
688
- entry.type if entry else PyrexTypes.py_object_type
689
- for entry in map(builtin_scope.lookup, subscripted_type_names.split(','))
690
- ]
691
- container_type = container_type.specialize_here(pos, env, subscripted_types)
727
+ return_type_signature: str = methods[method_name]
728
+ container_type = _parse_signature(pos, env, builtin_type, return_type_signature)
692
729
  return container_type
693
730
  return PyrexTypes.py_object_type
694
731
 
@@ -778,6 +815,11 @@ builtin_types = {}
778
815
 
779
816
  def init_builtin_types():
780
817
  global builtin_types
818
+
819
+ # Some builtin types are not available by name,
820
+ # so we declare them in a throw-away scope.
821
+ hidden_builtins_scope = BuiltinScope()
822
+
781
823
  for name, cname, methods in builtin_types_table:
782
824
  if name == 'frozenset':
783
825
  objstruct_cname = 'PySetObject'
@@ -789,15 +831,12 @@ def init_builtin_types():
789
831
  objstruct_cname = 'PyUnicodeObject'
790
832
  elif name == 'bool':
791
833
  objstruct_cname = 'PyLongObject'
792
- elif name == 'BaseException':
793
- objstruct_cname = "PyBaseExceptionObject"
794
- elif name == 'Exception':
795
- objstruct_cname = "PyBaseExceptionObject"
796
834
  else:
797
835
  objstruct_cname = 'Py%sObject' % name.capitalize()
798
836
 
799
837
  utility_code = None
800
838
  type_class = PyrexTypes.BuiltinObjectType
839
+ scope = builtin_scope
801
840
  if name in ['dict', 'list', 'set', 'frozenset', 'frozendict']:
802
841
  type_class = PyrexTypes.BuiltinTypeConstructorObjectType
803
842
  if name == 'frozendict':
@@ -806,8 +845,14 @@ def init_builtin_types():
806
845
  type_class = PyrexTypes.PythonTupleTypeConstructor
807
846
  elif name == 'range':
808
847
  utility_code = range_utility_code
848
+ elif name in hidden_builtin_types:
849
+ type_class = PyrexTypes.BuiltinTypeConstructorObjectType
850
+ scope = hidden_builtins_scope
851
+ # Make sure the 'type' base type is declared in the hidden scope.
852
+ if 'type' not in hidden_builtins_scope.entries:
853
+ hidden_builtins_scope.entries['type'] = builtin_scope.lookup('type')
809
854
 
810
- the_type = builtin_scope.declare_builtin_type(
855
+ the_type = scope.declare_builtin_type(
811
856
  name, cname, objstruct_cname=objstruct_cname, type_class=type_class, utility_code=utility_code)
812
857
  builtin_types[name] = the_type
813
858
  for method in methods:
@@ -817,21 +862,81 @@ def init_builtin_types():
817
862
  def init_builtin_exceptions():
818
863
  """Declare known builtin Python exceptions as types.
819
864
  """
820
- for name in KNOWN_PYTHON_BUILTINS:
821
- if name in uncachable_builtins:
865
+ special_properties = {
866
+ 'StopIteration': ['value'],
867
+ 'NameError': ['name'],
868
+ 'AttributeError': ['name', 'obj'],
869
+ 'SystemExit': ['code'],
870
+ }
871
+ unicode_error_properties = ['encoding', 'object', 'reason']
872
+ for name in ['UnicodeError', 'UnicodeDecodeError', 'UnicodeEncodeError', 'UnicodeTranslateError']:
873
+ special_properties[name] = unicode_error_properties
874
+
875
+ type_check_utility_code = UtilityCode.load_cached("FastTypeChecks", "ModuleSetupCode.c")
876
+
877
+ for name in PyrexTypes.KNOWN_EXCEPTION_NAMES:
878
+ if name in PyrexTypes.uncachable_builtins:
822
879
  # Exclude builtins specific to later Python versions or platforms.
823
880
  continue
824
- if not PyrexTypes.is_exception_type_name(name):
825
- continue
826
- if builtin_scope.lookup_here(name) is not None:
827
- # Already declared as builtin type above in a more specialised way.
828
- continue
829
- utility_code = UtilityCode(
830
- proto=f"#define __Pyx_PyExc_{name}_Check(obj) __Pyx_TypeCheck(obj, PyExc_{name})",
831
- name=f"Py{name}_Check",
881
+
882
+ objstruct_cname = None
883
+ if name == 'BaseException':
884
+ objstruct_cname = "PyBaseExceptionObject"
885
+ utility_code = UtilityCode(
886
+ proto="#define __Pyx_PyExc_BaseException_Check(obj) PyExceptionInstance_Check(obj)",
887
+ name=f"Py{name}_Check",
888
+ )
889
+ else:
890
+ if name == 'Exception':
891
+ objstruct_cname = "PyBaseExceptionObject"
892
+ utility_code = UtilityCode(
893
+ proto=f"#define __Pyx_PyExc_{name}_Check(obj) __Pyx_TypeCheck(obj, PyExc_{name})",
894
+ name=f"Py{name}_Check",
895
+ requires=[type_check_utility_code],
896
+ )
897
+
898
+ assert builtin_scope.lookup_here(name) is None # should not be declared above
899
+ exc_type = builtin_types[name] = builtin_scope.declare_builtin_type(
900
+ name, f"((PyTypeObject*)PyExc_{name})",
901
+ objstruct_cname=objstruct_cname,
902
+ utility_code=utility_code,
832
903
  )
833
- builtin_types[name] = builtin_scope.declare_builtin_type(
834
- name, f"((PyTypeObject*)PyExc_{name})", utility_code=utility_code)
904
+
905
+ # Also cover known subtypes, but avoid overly long chains of type pointer comparisons.
906
+ subtypes = [
907
+ tpname for tpname in PyrexTypes.exception_subtypes.get(name, ())
908
+ if tpname not in PyrexTypes.uncachable_builtins
909
+ ]
910
+ if len(subtypes) > 4:
911
+ subtypes = ()
912
+
913
+ utility_code_config = {'EXC_NAME': name, 'SUBTYPES': subtypes, 'PROPERTY_NAME': ''}
914
+
915
+ for property_name in chain(('args', 'context', 'cause', 'traceback'), special_properties.get(name, ())):
916
+ utility_code_config['PROPERTY_NAME'] = property_name
917
+
918
+ exc_type.scope.declare_cproperty(
919
+ f'__{property_name}__' if property_name in ('context', 'cause', 'traceback') else property_name,
920
+ PyrexTypes.py_object_type,
921
+ f"__Pyx_Py{name}_get_{property_name}",
922
+ f"__Pyx_Py{name}_set_{property_name}",
923
+ utility_code=TempitaUtilityCode.load(
924
+ f"ExceptionGetProperty", "Builtins.c", context=utility_code_config),
925
+ setter_utility_code=TempitaUtilityCode.load(
926
+ f"ExceptionSetProperty", "Builtins.c", context=utility_code_config),
927
+ )
928
+
929
+ for name in PyrexTypes.KNOWN_EXCEPTION_NAMES:
930
+ parents = PyrexTypes.exception_supertypes.get(name)
931
+ if not parents or name not in builtin_types:
932
+ continue
933
+ exc_type = builtin_types[name]
934
+ exc_type.exception_supertypes = [
935
+ # Collect super types bottom up.
936
+ builtin_types.get(parent) for parent in reversed(parents)
937
+ ]
938
+ while None in exc_type.exception_supertypes:
939
+ exc_type.exception_supertypes.remove(None)
835
940
 
836
941
 
837
942
  def init_builtin_structs():