jaclang 0.4.7__py3-none-any.whl → 0.5.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.

Potentially problematic release.


This version of jaclang might be problematic. Click here for more details.

Files changed (152) hide show
  1. jaclang/__init__.py +5 -2
  2. jaclang/cli/cli.py +56 -8
  3. jaclang/cli/cmdreg.py +16 -9
  4. jaclang/compiler/__jac_gen__/jac_parser.py +11 -15
  5. jaclang/compiler/absyntree.py +53 -19
  6. jaclang/compiler/codeloc.py +3 -1
  7. jaclang/compiler/{transpiler.py → compile.py} +3 -2
  8. jaclang/compiler/constant.py +4 -0
  9. jaclang/compiler/parser.py +156 -108
  10. jaclang/compiler/passes/ir_pass.py +1 -0
  11. jaclang/compiler/passes/main/__init__.py +2 -1
  12. jaclang/compiler/passes/main/def_impl_match_pass.py +1 -0
  13. jaclang/compiler/passes/main/def_use_pass.py +1 -0
  14. jaclang/compiler/passes/main/import_pass.py +18 -18
  15. jaclang/compiler/passes/main/pyast_gen_pass.py +1228 -853
  16. jaclang/compiler/passes/main/pyast_load_pass.py +3 -1
  17. jaclang/compiler/passes/main/pybc_gen_pass.py +46 -0
  18. jaclang/compiler/passes/main/pyout_pass.py +6 -7
  19. jaclang/compiler/passes/main/schedules.py +5 -9
  20. jaclang/compiler/passes/main/sub_node_tab_pass.py +1 -0
  21. jaclang/compiler/passes/main/sym_tab_build_pass.py +21 -9
  22. jaclang/compiler/passes/main/tests/test_decl_def_match_pass.py +2 -1
  23. jaclang/compiler/passes/main/tests/test_def_use_pass.py +2 -1
  24. jaclang/compiler/passes/main/tests/test_import_pass.py +2 -1
  25. jaclang/compiler/passes/main/tests/test_pyast_build_pass.py +1 -0
  26. jaclang/compiler/passes/main/tests/test_pyast_gen_pass.py +15 -38
  27. jaclang/compiler/passes/main/tests/test_pybc_gen_pass.py +25 -0
  28. jaclang/compiler/passes/main/tests/test_sub_node_pass.py +1 -1
  29. jaclang/compiler/passes/main/tests/test_sym_tab_build_pass.py +2 -1
  30. jaclang/compiler/passes/main/tests/test_type_check_pass.py +17 -1
  31. jaclang/compiler/passes/main/type_check_pass.py +9 -6
  32. jaclang/compiler/passes/tool/__init__.py +1 -0
  33. jaclang/compiler/passes/tool/ast_printer_pass.py +1 -0
  34. jaclang/compiler/passes/tool/fuse_comments_pass.py +1 -1
  35. jaclang/compiler/passes/tool/jac_formatter_pass.py +69 -32
  36. jaclang/compiler/passes/tool/schedules.py +1 -0
  37. jaclang/compiler/passes/tool/sym_tab_printer_pass.py +1 -0
  38. jaclang/compiler/passes/tool/tests/test_ast_print_pass.py +2 -1
  39. jaclang/compiler/passes/tool/tests/test_fuse_comments_pass.py +1 -0
  40. jaclang/compiler/passes/tool/tests/test_jac_format_pass.py +4 -3
  41. jaclang/compiler/passes/tool/tests/test_symtab_print_pass.py +2 -1
  42. jaclang/compiler/passes/transform.py +1 -0
  43. jaclang/compiler/passes/utils/mypy_ast_build.py +203 -17
  44. jaclang/compiler/symtable.py +1 -0
  45. jaclang/compiler/tests/test_importer.py +3 -2
  46. jaclang/compiler/tests/test_parser.py +1 -0
  47. jaclang/compiler/tests/test_workspace.py +1 -0
  48. jaclang/compiler/workspace.py +18 -5
  49. jaclang/core/construct.py +9 -32
  50. jaclang/{compiler → core}/importer.py +95 -85
  51. jaclang/core/utils.py +17 -12
  52. jaclang/plugin/__init__.py +1 -0
  53. jaclang/plugin/default.py +145 -43
  54. jaclang/plugin/feature.py +65 -19
  55. jaclang/plugin/spec.py +56 -34
  56. jaclang/plugin/tests/test_features.py +9 -0
  57. jaclang/utils/helpers.py +1 -0
  58. jaclang/utils/lang_tools.py +13 -19
  59. jaclang/utils/tests/test_lang_tools.py +2 -1
  60. jaclang/utils/treeprinter.py +2 -1
  61. jaclang/vendor/lark/common.py +3 -1
  62. jaclang/vendor/lark/lexer.py +6 -12
  63. jaclang/vendor/lark/parsers/lalr_parser.py +1 -0
  64. jaclang/vendor/mypy/applytype.py +2 -1
  65. jaclang/vendor/mypy/binder.py +1 -1
  66. jaclang/vendor/mypy/build.py +7 -9
  67. jaclang/vendor/mypy/checker.py +57 -33
  68. jaclang/vendor/mypy/checkexpr.py +42 -29
  69. jaclang/vendor/mypy/checkmember.py +13 -1
  70. jaclang/vendor/mypy/checkpattern.py +1 -1
  71. jaclang/vendor/mypy/checkstrformat.py +2 -4
  72. jaclang/vendor/mypy/constraints.py +10 -5
  73. jaclang/vendor/mypy/dmypy_server.py +3 -3
  74. jaclang/vendor/mypy/dmypy_util.py +62 -3
  75. jaclang/vendor/mypy/errors.py +1 -1
  76. jaclang/vendor/mypy/evalexpr.py +1 -0
  77. jaclang/vendor/mypy/expandtype.py +29 -29
  78. jaclang/vendor/mypy/fastparse.py +51 -31
  79. jaclang/vendor/mypy/inspections.py +5 -3
  80. jaclang/vendor/mypy/join.py +4 -4
  81. jaclang/vendor/mypy/main.py +6 -6
  82. jaclang/vendor/mypy/message_registry.py +1 -2
  83. jaclang/vendor/mypy/messages.py +31 -23
  84. jaclang/vendor/mypy/metastore.py +1 -2
  85. jaclang/vendor/mypy/modulefinder.py +2 -22
  86. jaclang/vendor/mypy/nodes.py +22 -20
  87. jaclang/vendor/mypy/options.py +4 -0
  88. jaclang/vendor/mypy/parse.py +6 -2
  89. jaclang/vendor/mypy/patterns.py +6 -6
  90. jaclang/vendor/mypy/plugin.py +3 -1
  91. jaclang/vendor/mypy/plugins/attrs.py +52 -10
  92. jaclang/vendor/mypy/plugins/common.py +2 -1
  93. jaclang/vendor/mypy/plugins/enums.py +3 -2
  94. jaclang/vendor/mypy/plugins/functools.py +1 -0
  95. jaclang/vendor/mypy/renaming.py +1 -1
  96. jaclang/vendor/mypy/report.py +15 -15
  97. jaclang/vendor/mypy/semanal.py +22 -13
  98. jaclang/vendor/mypy/semanal_enum.py +1 -1
  99. jaclang/vendor/mypy/semanal_namedtuple.py +1 -2
  100. jaclang/vendor/mypy/semanal_shared.py +3 -6
  101. jaclang/vendor/mypy/semanal_typeddict.py +16 -5
  102. jaclang/vendor/mypy/server/astdiff.py +15 -9
  103. jaclang/vendor/mypy/server/astmerge.py +5 -5
  104. jaclang/vendor/mypy/stats.py +0 -5
  105. jaclang/vendor/mypy/stubdoc.py +1 -1
  106. jaclang/vendor/mypy/stubgen.py +12 -21
  107. jaclang/vendor/mypy/stubgenc.py +16 -8
  108. jaclang/vendor/mypy/stubtest.py +57 -48
  109. jaclang/vendor/mypy/stubutil.py +28 -15
  110. jaclang/vendor/mypy/subtypes.py +4 -4
  111. jaclang/vendor/mypy/test/helpers.py +2 -2
  112. jaclang/vendor/mypy/test/meta/test_parse_data.py +1 -0
  113. jaclang/vendor/mypy/test/meta/test_update_data.py +1 -0
  114. jaclang/vendor/mypy/test/testargs.py +1 -0
  115. jaclang/vendor/mypy/test/testcheck.py +4 -1
  116. jaclang/vendor/mypy/test/testconstraints.py +25 -7
  117. jaclang/vendor/mypy/test/testerrorstream.py +1 -0
  118. jaclang/vendor/mypy/test/testformatter.py +2 -2
  119. jaclang/vendor/mypy/test/testparse.py +6 -4
  120. jaclang/vendor/mypy/test/testpythoneval.py +1 -0
  121. jaclang/vendor/mypy/test/testreports.py +1 -0
  122. jaclang/vendor/mypy/test/teststubgen.py +1 -2
  123. jaclang/vendor/mypy/test/teststubtest.py +98 -4
  124. jaclang/vendor/mypy/test/testtypes.py +1 -1
  125. jaclang/vendor/mypy/test/testutil.py +22 -0
  126. jaclang/vendor/mypy/typeanal.py +302 -158
  127. jaclang/vendor/mypy/typeops.py +22 -13
  128. jaclang/vendor/mypy/types.py +33 -34
  129. jaclang/vendor/mypy/typestate.py +2 -2
  130. jaclang/vendor/mypy/util.py +7 -6
  131. jaclang/vendor/mypy/version.py +1 -1
  132. jaclang/vendor/mypyc/analysis/ircheck.py +1 -0
  133. jaclang/vendor/mypyc/codegen/emitfunc.py +5 -3
  134. jaclang/vendor/mypyc/codegen/emitmodule.py +12 -12
  135. jaclang/vendor/mypyc/codegen/emitwrapper.py +2 -2
  136. jaclang/vendor/mypyc/ir/class_ir.py +10 -6
  137. jaclang/vendor/mypyc/irbuild/builder.py +3 -4
  138. jaclang/vendor/mypyc/irbuild/function.py +5 -3
  139. jaclang/vendor/mypyc/irbuild/nonlocalcontrol.py +1 -2
  140. jaclang/vendor/mypyc/irbuild/prepare.py +6 -6
  141. jaclang/vendor/mypyc/primitives/registry.py +15 -5
  142. jaclang/vendor/mypyc/test/test_run.py +1 -2
  143. jaclang/vendor/mypyc/transform/uninit.py +3 -3
  144. jaclang/vendor/pluggy/_callers.py +1 -0
  145. jaclang/vendor/pluggy/_hooks.py +6 -10
  146. jaclang/vendor/pluggy/_result.py +1 -0
  147. jaclang/vendor/pluggy/_tracing.py +1 -0
  148. {jaclang-0.4.7.dist-info → jaclang-0.5.0.dist-info}/METADATA +1 -1
  149. {jaclang-0.4.7.dist-info → jaclang-0.5.0.dist-info}/RECORD +152 -150
  150. {jaclang-0.4.7.dist-info → jaclang-0.5.0.dist-info}/WHEEL +0 -0
  151. {jaclang-0.4.7.dist-info → jaclang-0.5.0.dist-info}/entry_points.txt +0 -0
  152. {jaclang-0.4.7.dist-info → jaclang-0.5.0.dist-info}/top_level.txt +0 -0
@@ -351,7 +351,7 @@ class DocStringParser:
351
351
  return has_arg("*args", signature) and has_arg("**kwargs", signature)
352
352
 
353
353
  # Move functions with (*args, **kwargs) in their signature to last place.
354
- return list(sorted(self.signatures, key=lambda x: 1 if args_kwargs(x) else 0))
354
+ return sorted(self.signatures, key=lambda x: 1 if args_kwargs(x) else 0)
355
355
 
356
356
 
357
357
  def infer_sig_from_docstring(docstr: str | None, name: str) -> list[FunctionSig] | None:
@@ -22,7 +22,7 @@ Basic usage:
22
22
  => Generate out/urllib/parse.pyi.
23
23
 
24
24
  $ stubgen -p urllib
25
- => Generate stubs for whole urlib package (recursively).
25
+ => Generate stubs for whole urllib package (recursively).
26
26
 
27
27
  For C modules, you can get more precise function signatures by parsing .rst (Sphinx)
28
28
  documentation for extra information. For this, use the --doc-dir option:
@@ -312,6 +312,13 @@ class AliasPrinter(NodeVisitor[str]):
312
312
  return repr(node.value)
313
313
 
314
314
  def visit_index_expr(self, node: IndexExpr) -> str:
315
+ base_fullname = self.stubgen.get_fullname(node.base)
316
+ if base_fullname == "typing.Union":
317
+ if isinstance(node.index, TupleExpr):
318
+ return " | ".join([item.accept(self) for item in node.index.items])
319
+ return node.index.accept(self)
320
+ if base_fullname == "typing.Optional":
321
+ return f"{node.index.accept(self)} | None"
315
322
  base = node.base.accept(self)
316
323
  index = node.index.accept(self)
317
324
  if len(index) > 2 and index.startswith("(") and index.endswith(")"):
@@ -706,11 +713,11 @@ class ASTStubGenerator(BaseStubGenerator, mypy.traverser.TraverserVisitor):
706
713
  elif fullname in OVERLOAD_NAMES:
707
714
  self.add_decorator(qualname, require_name=True)
708
715
  o.func.is_overload = True
709
- elif qualname.endswith(".setter"):
716
+ elif qualname.endswith((".setter", ".deleter")):
710
717
  self.add_decorator(qualname, require_name=False)
711
718
 
712
719
  def get_fullname(self, expr: Expression) -> str:
713
- """Return the full name resolving imports and import aliases."""
720
+ """Return the expression's full name."""
714
721
  if (
715
722
  self.analyzed
716
723
  and isinstance(expr, (NameExpr, MemberExpr))
@@ -719,22 +726,7 @@ class ASTStubGenerator(BaseStubGenerator, mypy.traverser.TraverserVisitor):
719
726
  ):
720
727
  return expr.fullname
721
728
  name = get_qualified_name(expr)
722
- if "." not in name:
723
- real_module = self.import_tracker.module_for.get(name)
724
- real_short = self.import_tracker.reverse_alias.get(name, name)
725
- if real_module is None and real_short not in self.defined_names:
726
- real_module = (
727
- "builtins" # not imported and not defined, must be a builtin
728
- )
729
- else:
730
- name_module, real_short = name.split(".", 1)
731
- real_module = self.import_tracker.reverse_alias.get(
732
- name_module, name_module
733
- )
734
- resolved_name = (
735
- real_short if real_module is None else f"{real_module}.{real_short}"
736
- )
737
- return resolved_name
729
+ return self.resolve_name(name)
738
730
 
739
731
  def visit_class_def(self, o: ClassDef) -> None:
740
732
  self._current_class = o
@@ -1921,8 +1913,7 @@ def parse_options(args: list[str]) -> Options:
1921
1913
  )
1922
1914
 
1923
1915
  # Create the output folder if it doesn't already exist.
1924
- if not os.path.exists(ns.output_dir):
1925
- os.makedirs(ns.output_dir)
1916
+ os.makedirs(ns.output_dir, exist_ok=True)
1926
1917
 
1927
1918
  return Options(
1928
1919
  pyversion=pyversion,
@@ -43,7 +43,7 @@ class ExternalSignatureGenerator(SignatureGenerator):
43
43
  self,
44
44
  func_sigs: dict[str, str] | None = None,
45
45
  class_sigs: dict[str, str] | None = None,
46
- ):
46
+ ) -> None:
47
47
  """
48
48
  Takes a mapping of function/method names to signatures and class name to
49
49
  class signatures (usually corresponds to __init__).
@@ -197,7 +197,7 @@ class CFunctionStub:
197
197
  Class that mimics a C function in order to provide parseable docstrings.
198
198
  """
199
199
 
200
- def __init__(self, name: str, doc: str, is_abstract: bool = False):
200
+ def __init__(self, name: str, doc: str, is_abstract: bool = False) -> None:
201
201
  self.__name__ = name
202
202
  self.__doc__ = doc
203
203
  self.__abstractmethod__ = is_abstract
@@ -423,7 +423,7 @@ class InspectionStubGenerator(BaseStubGenerator):
423
423
  self.import_tracker.reexport(name)
424
424
 
425
425
  self.set_defined_names(
426
- set([name for name, obj in all_items if not inspect.ismodule(obj)])
426
+ {name for name, obj in all_items if not inspect.ismodule(obj)}
427
427
  )
428
428
 
429
429
  if self.resort_members:
@@ -552,10 +552,16 @@ class InspectionStubGenerator(BaseStubGenerator):
552
552
  def is_staticmethod(
553
553
  self, class_info: ClassInfo | None, name: str, obj: object
554
554
  ) -> bool:
555
- if self.is_c_module:
555
+ if class_info is None:
556
556
  return False
557
+ elif self.is_c_module:
558
+ raw_lookup: Mapping[str, Any] = getattr(
559
+ class_info.cls, "__dict__"
560
+ ) # noqa: B009
561
+ raw_value = raw_lookup.get(name, obj)
562
+ return isinstance(raw_value, staticmethod)
557
563
  else:
558
- return class_info is not None and isinstance(
564
+ return isinstance(
559
565
  inspect.getattr_static(class_info.cls, name), staticmethod
560
566
  )
561
567
 
@@ -798,11 +804,11 @@ class InspectionStubGenerator(BaseStubGenerator):
798
804
  The result lines will be appended to 'output'. If necessary, any
799
805
  required names will be added to 'imports'.
800
806
  """
801
- raw_lookup = getattr(cls, "__dict__") # noqa: B009
807
+ raw_lookup: Mapping[str, Any] = getattr(cls, "__dict__") # noqa: B009
802
808
  items = self.get_members(cls)
803
809
  if self.resort_members:
804
810
  items = sorted(items, key=lambda x: method_name_sort_key(x[0]))
805
- names = set(x[0] for x in items)
811
+ names = {x[0] for x in items}
806
812
  methods: list[str] = []
807
813
  types: list[str] = []
808
814
  static_properties: list[str] = []
@@ -830,7 +836,9 @@ class InspectionStubGenerator(BaseStubGenerator):
830
836
  continue
831
837
  attr = "__init__"
832
838
  # FIXME: make this nicer
833
- if self.is_classmethod(class_info, attr, value):
839
+ if self.is_staticmethod(class_info, attr, value):
840
+ class_info.self_var = ""
841
+ elif self.is_classmethod(class_info, attr, value):
834
842
  class_info.self_var = "cls"
835
843
  else:
836
844
  class_info.self_var = "self"
@@ -10,6 +10,7 @@ import argparse
10
10
  import collections.abc
11
11
  import copy
12
12
  import enum
13
+ import functools
13
14
  import importlib
14
15
  import importlib.machinery
15
16
  import inspect
@@ -317,47 +318,31 @@ def _verify_exported_names(
317
318
  stub_object=MISSING,
318
319
  runtime_object=MISSING,
319
320
  stub_desc=(
320
- f"Names exported in the stub but not at runtime: "
321
- f"{names_in_stub_not_runtime}"
321
+ f"Names exported in the stub but not at runtime: {names_in_stub_not_runtime}"
322
322
  ),
323
323
  runtime_desc=(
324
- f"Names exported at runtime but not in the stub: "
325
- f"{names_in_runtime_not_stub}"
324
+ f"Names exported at runtime but not in the stub: {names_in_runtime_not_stub}"
326
325
  ),
327
326
  )
328
327
 
329
328
 
330
- def _get_imported_symbol_names(runtime: types.ModuleType) -> frozenset[str] | None:
331
- """Retrieve the names in the global namespace which are known to be imported.
329
+ @functools.lru_cache
330
+ def _module_symbol_table(runtime: types.ModuleType) -> symtable.SymbolTable | None:
331
+ """Retrieve the symbol table for the module (or None on failure).
332
332
 
333
- 1). Use inspect to retrieve the source code of the module
334
- 2). Use symtable to parse the source and retrieve names that are known to be imported
335
- from other modules.
336
-
337
- If either of the above steps fails, return `None`.
338
-
339
- Note that if a set of names is returned,
340
- it won't include names imported via `from foo import *` imports.
333
+ 1) Use inspect to retrieve the source code of the module
334
+ 2) Use symtable to parse the source (and use what symtable knows for its purposes)
341
335
  """
342
336
  try:
343
337
  source = inspect.getsource(runtime)
344
338
  except (OSError, TypeError, SyntaxError):
345
339
  return None
346
340
 
347
- if not source.strip():
348
- # The source code for the module was an empty file,
349
- # no point in parsing it with symtable
350
- return frozenset()
351
-
352
341
  try:
353
- module_symtable = symtable.symtable(source, runtime.__name__, "exec")
342
+ return symtable.symtable(source, runtime.__name__, "exec")
354
343
  except SyntaxError:
355
344
  return None
356
345
 
357
- return frozenset(
358
- sym.get_name() for sym in module_symtable.get_symbols() if sym.is_imported()
359
- )
360
-
361
346
 
362
347
  @verify.register(nodes.MypyFile)
363
348
  def verify_mypyfile(
@@ -390,25 +375,37 @@ def verify_mypyfile(
390
375
  if not o.module_hidden and (not is_probably_private(m) or hasattr(runtime, m))
391
376
  }
392
377
 
393
- imported_symbols = _get_imported_symbol_names(runtime)
394
-
395
378
  def _belongs_to_runtime(r: types.ModuleType, attr: str) -> bool:
396
379
  """Heuristics to determine whether a name originates from another module."""
397
380
  obj = getattr(r, attr)
398
381
  if isinstance(obj, types.ModuleType):
399
382
  return False
400
- if callable(obj):
401
- # It's highly likely to be a class or a function if it's callable,
402
- # so the __module__ attribute will give a good indication of which module it comes from
383
+
384
+ symbol_table = _module_symbol_table(r)
385
+ if symbol_table is not None:
403
386
  try:
404
- obj_mod = obj.__module__
405
- except Exception:
387
+ symbol = symbol_table.lookup(attr)
388
+ except KeyError:
406
389
  pass
407
390
  else:
408
- if isinstance(obj_mod, str):
409
- return bool(obj_mod == r.__name__)
410
- if imported_symbols is not None:
411
- return attr not in imported_symbols
391
+ if symbol.is_imported():
392
+ # symtable says we got this from another module
393
+ return False
394
+ # But we can't just return True here, because symtable doesn't know about symbols
395
+ # that come from `from module import *`
396
+ if symbol.is_assigned():
397
+ # symtable knows we assigned this symbol in the module
398
+ return True
399
+
400
+ # The __module__ attribute is unreliable for anything except functions and classes,
401
+ # but it's our best guess at this point
402
+ try:
403
+ obj_mod = obj.__module__
404
+ except Exception:
405
+ pass
406
+ else:
407
+ if isinstance(obj_mod, str):
408
+ return bool(obj_mod == r.__name__)
412
409
  return True
413
410
 
414
411
  runtime_public_contents = (
@@ -713,7 +710,7 @@ def _verify_arg_default_value(
713
710
  runtime_type is not None
714
711
  and stub_type is not None
715
712
  # Avoid false positives for marker objects
716
- and type(runtime_arg.default) != object
713
+ and type(runtime_arg.default) is not object
717
714
  # And ellipsis
718
715
  and runtime_arg.default is not ...
719
716
  and not is_subtype_helper(runtime_type, stub_type)
@@ -875,7 +872,10 @@ class Signature(Generic[T]):
875
872
  # argument. To accomplish this, we just make up a fake index-based name.
876
873
  name = (
877
874
  f"__{index}"
878
- if arg.variable.name.startswith("__") or assume_positional_only
875
+ if arg.variable.name.startswith("__")
876
+ or arg.pos_only
877
+ or assume_positional_only
878
+ or arg.variable.name.strip("_") == "self"
879
879
  else arg.variable.name
880
880
  )
881
881
  all_args.setdefault(name, []).append((arg, index))
@@ -920,6 +920,7 @@ class Signature(Generic[T]):
920
920
  type_annotation=None,
921
921
  initializer=None,
922
922
  kind=get_kind(arg_name),
923
+ pos_only=all(arg.pos_only for arg, _ in all_args[arg_name]),
923
924
  )
924
925
  if arg.kind.is_positional():
925
926
  sig.pos.append(arg)
@@ -947,7 +948,7 @@ def _verify_signature(
947
948
  runtime_arg.kind == inspect.Parameter.POSITIONAL_ONLY
948
949
  and not stub_arg.pos_only
949
950
  and not stub_arg.variable.name.startswith("__")
950
- and not stub_arg.variable.name.strip("_") == "self"
951
+ and stub_arg.variable.name.strip("_") != "self"
951
952
  and not is_dunder(
952
953
  function_name, exclude_special=True
953
954
  ) # noisy for dunder methods
@@ -959,6 +960,7 @@ def _verify_signature(
959
960
  if (
960
961
  runtime_arg.kind != inspect.Parameter.POSITIONAL_ONLY
961
962
  and (stub_arg.pos_only or stub_arg.variable.name.startswith("__"))
963
+ and stub_arg.variable.name.strip("_") != "self"
962
964
  and not is_dunder(
963
965
  function_name, exclude_special=True
964
966
  ) # noisy for dunder methods
@@ -1153,6 +1155,13 @@ def verify_var(
1153
1155
  runtime_type = get_mypy_type_of_runtime_value(runtime.value)
1154
1156
  if runtime_type is not None and is_subtype_helper(runtime_type, stub.type):
1155
1157
  should_error = False
1158
+ # We always allow setting the stub value to ...
1159
+ proper_type = mypy.types.get_proper_type(stub.type)
1160
+ if (
1161
+ isinstance(proper_type, mypy.types.Instance)
1162
+ and proper_type.type.fullname == "builtins.ellipsis"
1163
+ ):
1164
+ should_error = False
1156
1165
 
1157
1166
  if should_error:
1158
1167
  yield Error(
@@ -1603,9 +1612,11 @@ def safe_inspect_signature(runtime: Any) -> inspect.Signature | None:
1603
1612
  sig = inspect._signature_fromstr(inspect.Signature, runtime, sig) # type: ignore[attr-defined]
1604
1613
  assert isinstance(sig, inspect.Signature)
1605
1614
  new_params = [
1606
- parameter.replace(default=UNREPRESENTABLE)
1607
- if parameter.default is ...
1608
- else parameter
1615
+ (
1616
+ parameter.replace(default=UNREPRESENTABLE)
1617
+ if parameter.default is ...
1618
+ else parameter
1619
+ )
1609
1620
  for parameter in sig.parameters.values()
1610
1621
  ]
1611
1622
  return sig.replace(parameters=new_params)
@@ -1872,9 +1883,9 @@ def get_importable_stdlib_modules() -> set[str]:
1872
1883
  all_stdlib_modules = sys.stdlib_module_names
1873
1884
  else:
1874
1885
  all_stdlib_modules = set(sys.builtin_module_names)
1875
- modules_by_finder: defaultdict[
1876
- importlib.machinery.FileFinder, set[str]
1877
- ] = defaultdict(set)
1886
+ modules_by_finder: defaultdict[importlib.machinery.FileFinder, set[str]] = (
1887
+ defaultdict(set)
1888
+ )
1878
1889
  for m in pkgutil.iter_modules():
1879
1890
  if isinstance(m.module_finder, importlib.machinery.FileFinder):
1880
1891
  modules_by_finder[m.module_finder].add(m.name)
@@ -1924,10 +1935,8 @@ def get_importable_stdlib_modules() -> set[str]:
1924
1935
  # test.* modules do weird things like raising exceptions in __del__ methods,
1925
1936
  # leading to unraisable exceptions being logged to the terminal
1926
1937
  # as a warning at the end of the stubtest run
1927
- if (
1928
- submodule_name.endswith(".__main__")
1929
- or submodule_name.startswith("idlelib.")
1930
- or submodule_name.startswith("test.")
1938
+ if submodule_name.endswith(".__main__") or submodule_name.startswith(
1939
+ ("idlelib.", "test.")
1931
1940
  ):
1932
1941
  continue
1933
1942
 
@@ -148,13 +148,11 @@ def fail_missing(mod: str, reason: ModuleNotFoundReason) -> None:
148
148
 
149
149
 
150
150
  @overload
151
- def remove_misplaced_type_comments(source: bytes) -> bytes:
152
- ...
151
+ def remove_misplaced_type_comments(source: bytes) -> bytes: ...
153
152
 
154
153
 
155
154
  @overload
156
- def remove_misplaced_type_comments(source: str) -> str:
157
- ...
155
+ def remove_misplaced_type_comments(source: str) -> str: ...
158
156
 
159
157
 
160
158
  def remove_misplaced_type_comments(source: str | bytes) -> str | bytes:
@@ -236,6 +234,11 @@ class AnnotationPrinter(TypeStrVisitor):
236
234
 
237
235
  def visit_unbound_type(self, t: UnboundType) -> str:
238
236
  s = t.name
237
+ fullname = self.stubgen.resolve_name(s)
238
+ if fullname == "typing.Union":
239
+ return " | ".join([item.accept(self) for item in t.args])
240
+ if fullname == "typing.Optional":
241
+ return f"{t.args[0].accept(self)} | None"
239
242
  if self.known_modules is not None and "." in s:
240
243
  # see if this object is from any of the modules that we're currently processing.
241
244
  # reverse sort so that subpackages come before parents: e.g. "foo.bar" before "foo".
@@ -515,9 +518,9 @@ class ImportTracker:
515
518
 
516
519
  for name in sorted(
517
520
  self.required_names,
518
- key=lambda n: (self.reverse_alias[n], n)
519
- if n in self.reverse_alias
520
- else (n, ""),
521
+ key=lambda n: (
522
+ (self.reverse_alias[n], n) if n in self.reverse_alias else (n, "")
523
+ ),
521
524
  ):
522
525
  # If we haven't seen this name in an import statement, ignore it
523
526
  if name not in self.module_for:
@@ -593,7 +596,7 @@ class BaseStubGenerator:
593
596
  include_private: bool = False,
594
597
  export_less: bool = False,
595
598
  include_docstrings: bool = False,
596
- ):
599
+ ) -> None:
597
600
  # Best known value of __all__.
598
601
  self._all_ = _all_
599
602
  self._include_private = include_private
@@ -623,14 +626,24 @@ class BaseStubGenerator:
623
626
  def get_sig_generators(self) -> list[SignatureGenerator]:
624
627
  return []
625
628
 
626
- def refers_to_fullname(self, name: str, fullname: str | tuple[str, ...]) -> bool:
627
- """Return True if the variable name identifies the same object as the given fullname(s)."""
628
- if isinstance(fullname, tuple):
629
- return any(self.refers_to_fullname(name, fname) for fname in fullname)
630
- module, short = fullname.rsplit(".", 1)
631
- return self.import_tracker.module_for.get(name) == module and (
632
- name == short or self.import_tracker.reverse_alias.get(name) == short
629
+ def resolve_name(self, name: str) -> str:
630
+ """Return the full name resolving imports and import aliases."""
631
+ if "." not in name:
632
+ real_module = self.import_tracker.module_for.get(name)
633
+ real_short = self.import_tracker.reverse_alias.get(name, name)
634
+ if real_module is None and real_short not in self.defined_names:
635
+ real_module = (
636
+ "builtins" # not imported and not defined, must be a builtin
637
+ )
638
+ else:
639
+ name_module, real_short = name.split(".", 1)
640
+ real_module = self.import_tracker.reverse_alias.get(
641
+ name_module, name_module
642
+ )
643
+ resolved_name = (
644
+ real_short if real_module is None else f"{real_module}.{real_short}"
633
645
  )
646
+ return resolved_name
634
647
 
635
648
  def add_name(self, fullname: str, require: bool = True) -> str:
636
649
  """Add a name to be imported and return the name reference.
@@ -746,10 +746,10 @@ class SubtypeVisitor(TypeVisitor[bool]):
746
746
  is_proper_subtype=self.proper_subtype,
747
747
  ignore_pos_arg_names=self.subtype_context.ignore_pos_arg_names,
748
748
  strict_concatenate=(
749
- self.options.extra_checks or self.options.strict_concatenate
750
- )
751
- if self.options
752
- else False,
749
+ (self.options.extra_checks or self.options.strict_concatenate)
750
+ if self.options
751
+ else False
752
+ ),
753
753
  )
754
754
  elif isinstance(right, Overloaded):
755
755
  return all(self._is_subtype(left, item) for item in right.items)
@@ -157,7 +157,7 @@ def assert_module_equivalence(
157
157
  expected_normalized,
158
158
  actual_normalized,
159
159
  (
160
- "Actual modules ({}) do not match expected modules ({}) " 'for "[{} ...]"'
160
+ 'Actual modules ({}) do not match expected modules ({}) for "[{} ...]"'
161
161
  ).format(", ".join(actual_normalized), ", ".join(expected_normalized), name),
162
162
  )
163
163
 
@@ -170,7 +170,7 @@ def assert_target_equivalence(
170
170
  expected,
171
171
  actual,
172
172
  (
173
- "Actual targets ({}) do not match expected targets ({}) " 'for "[{} ...]"'
173
+ 'Actual targets ({}) do not match expected targets ({}) for "[{} ...]"'
174
174
  ).format(", ".join(actual), ", ".join(expected), name),
175
175
  )
176
176
 
@@ -2,6 +2,7 @@
2
2
  A "meta test" which tests the parsing of .test files. This is not meant to become exhaustive
3
3
  but to ensure we maintain a basic level of ergonomics for mypy contributors.
4
4
  """
5
+
5
6
  from mypy.test.helpers import Suite
6
7
  from mypy.test.meta._pytest import PytestResult, run_pytest_data_suite
7
8
 
@@ -3,6 +3,7 @@ A "meta test" which tests the `--update-data` feature for updating .test files.
3
3
  Updating the expected output, especially when it's in the form of inline (comment) assertions,
4
4
  can be brittle, which is why we're "meta-testing" here.
5
5
  """
6
+
6
7
  from mypy.test.helpers import Suite
7
8
  from mypy.test.meta._pytest import PytestResult, dedent_docstring, run_pytest_data_suite
8
9
 
@@ -4,6 +4,7 @@ In particular, verify that the argparse defaults are the same as the Options
4
4
  defaults, and that argparse doesn't assign any new members to the Options
5
5
  object it creates.
6
6
  """
7
+
7
8
  from __future__ import annotations
8
9
 
9
10
  import argparse
@@ -34,6 +34,7 @@ try:
34
34
  except ImportError:
35
35
  lxml = None
36
36
 
37
+
37
38
  import pytest
38
39
 
39
40
  # List of files that contain test case descriptions.
@@ -108,9 +109,11 @@ class TypeCheckSuite(DataSuite):
108
109
  def run_case_once(
109
110
  self,
110
111
  testcase: DataDrivenTestCase,
111
- operations: list[FileOperation] = [],
112
+ operations: list[FileOperation] | None = None,
112
113
  incremental_step: int = 0,
113
114
  ) -> None:
115
+ if operations is None:
116
+ operations = []
114
117
  original_program_text = "\n".join(testcase.input)
115
118
  module_data = self.parse_module(original_program_text, incremental_step)
116
119
 
@@ -36,17 +36,24 @@ class ConstraintsSuite(Suite):
36
36
 
37
37
  def test_basic_type_var_tuple(self) -> None:
38
38
  fx = self.fx
39
- assert infer_constraints(
40
- Instance(fx.gvi, [UnpackType(fx.ts)]),
41
- Instance(fx.gvi, [fx.a, fx.b]),
42
- SUPERTYPE_OF,
43
- ) == [
39
+ assert set(
40
+ infer_constraints(
41
+ Instance(fx.gvi, [UnpackType(fx.ts)]),
42
+ Instance(fx.gvi, [fx.a, fx.b]),
43
+ SUPERTYPE_OF,
44
+ )
45
+ ) == {
44
46
  Constraint(
45
47
  type_var=fx.ts,
46
48
  op=SUPERTYPE_OF,
47
49
  target=TupleType([fx.a, fx.b], fx.std_tuple),
48
- )
49
- ]
50
+ ),
51
+ Constraint(
52
+ type_var=fx.ts,
53
+ op=SUBTYPE_OF,
54
+ target=TupleType([fx.a, fx.b], fx.std_tuple),
55
+ ),
56
+ }
50
57
 
51
58
  def test_type_var_tuple_with_prefix_and_suffix(self) -> None:
52
59
  fx = self.fx
@@ -63,6 +70,11 @@ class ConstraintsSuite(Suite):
63
70
  op=SUPERTYPE_OF,
64
71
  target=TupleType([fx.b, fx.c], fx.std_tuple),
65
72
  ),
73
+ Constraint(
74
+ type_var=fx.ts,
75
+ op=SUBTYPE_OF,
76
+ target=TupleType([fx.b, fx.c], fx.std_tuple),
77
+ ),
66
78
  Constraint(type_var=fx.s, op=SUPERTYPE_OF, target=fx.d),
67
79
  }
68
80
 
@@ -76,7 +88,9 @@ class ConstraintsSuite(Suite):
76
88
  )
77
89
  ) == {
78
90
  Constraint(type_var=fx.t, op=SUPERTYPE_OF, target=fx.a),
91
+ Constraint(type_var=fx.t, op=SUBTYPE_OF, target=fx.a),
79
92
  Constraint(type_var=fx.t, op=SUPERTYPE_OF, target=fx.b),
93
+ Constraint(type_var=fx.t, op=SUBTYPE_OF, target=fx.b),
80
94
  }
81
95
 
82
96
  def test_unpack_homogenous_tuple_with_prefix_and_suffix(self) -> None:
@@ -92,7 +106,9 @@ class ConstraintsSuite(Suite):
92
106
  ) == {
93
107
  Constraint(type_var=fx.t, op=SUPERTYPE_OF, target=fx.a),
94
108
  Constraint(type_var=fx.s, op=SUPERTYPE_OF, target=fx.b),
109
+ Constraint(type_var=fx.s, op=SUBTYPE_OF, target=fx.b),
95
110
  Constraint(type_var=fx.s, op=SUPERTYPE_OF, target=fx.c),
111
+ Constraint(type_var=fx.s, op=SUBTYPE_OF, target=fx.c),
96
112
  Constraint(type_var=fx.u, op=SUPERTYPE_OF, target=fx.d),
97
113
  }
98
114
 
@@ -107,7 +123,9 @@ class ConstraintsSuite(Suite):
107
123
  ) == {
108
124
  Constraint(type_var=fx.u, op=SUPERTYPE_OF, target=fx.a),
109
125
  Constraint(type_var=fx.t, op=SUPERTYPE_OF, target=fx.b),
126
+ Constraint(type_var=fx.t, op=SUBTYPE_OF, target=fx.b),
110
127
  Constraint(type_var=fx.s, op=SUPERTYPE_OF, target=fx.c),
128
+ Constraint(type_var=fx.s, op=SUBTYPE_OF, target=fx.c),
111
129
  Constraint(type_var=fx.u, op=SUPERTYPE_OF, target=fx.d),
112
130
  }
113
131
 
@@ -1,4 +1,5 @@
1
1
  """Tests for mypy incremental error output."""
2
+
2
3
  from __future__ import annotations
3
4
 
4
5
  from mypy import build
@@ -52,14 +52,14 @@ class FancyErrorFormattingTestCases(TestCase):
52
52
 
53
53
  def test_split_words(self) -> None:
54
54
  assert split_words("Simple message") == ["Simple", "message"]
55
- assert split_words('Message with "Some[Long, Types]"' " in it") == [
55
+ assert split_words('Message with "Some[Long, Types]" in it') == [
56
56
  "Message",
57
57
  "with",
58
58
  '"Some[Long, Types]"',
59
59
  "in",
60
60
  "it",
61
61
  ]
62
- assert split_words('Message with "Some[Long, Types]"' " and [error-code]") == [
62
+ assert split_words('Message with "Some[Long, Types]" and [error-code]') == [
63
63
  "Message",
64
64
  "with",
65
65
  '"Some[Long, Types]"',
@@ -8,7 +8,7 @@ from pytest import skip
8
8
 
9
9
  from mypy import defaults
10
10
  from mypy.config_parser import parse_mypy_comments
11
- from mypy.errors import CompileError
11
+ from mypy.errors import CompileError, Errors
12
12
  from mypy.options import Options
13
13
  from mypy.parse import parse
14
14
  from mypy.test.data import DataDrivenTestCase, DataSuite
@@ -54,8 +54,9 @@ def test_parser(testcase: DataDrivenTestCase) -> None:
54
54
  bytes(source, "ascii"),
55
55
  fnam="main",
56
56
  module="__main__",
57
- errors=None,
57
+ errors=Errors(options),
58
58
  options=options,
59
+ raise_on_error=True,
59
60
  )
60
61
  a = n.str_with_options(options).split("\n")
61
62
  except CompileError as e:
@@ -91,8 +92,9 @@ def test_parse_error(testcase: DataDrivenTestCase) -> None:
91
92
  bytes("\n".join(testcase.input), "utf-8"),
92
93
  INPUT_FILE_NAME,
93
94
  "__main__",
94
- None,
95
- options,
95
+ errors=Errors(options),
96
+ options=options,
97
+ raise_on_error=True,
96
98
  )
97
99
  raise AssertionError("No errors reported")
98
100
  except CompileError as e:
@@ -55,6 +55,7 @@ def test_python_evaluation(testcase: DataDrivenTestCase, cache_dir: str) -> None
55
55
  "--hide-error-codes",
56
56
  "--allow-empty-bodies",
57
57
  "--force-uppercase-builtins",
58
+ "--test-env", # Speeds up some checks
58
59
  ]
59
60
  interpreter = python3_path
60
61
  mypy_cmdline.append(f"--python-version={'.'.join(map(str, PYTHON3_VERSION))}")