Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Crash for TypedDict with non-literal keys #15557

Closed
gsakkis opened this issue Jun 30, 2023 · 3 comments · Fixed by #16115
Closed

Crash for TypedDict with non-literal keys #15557

gsakkis opened this issue Jun 30, 2023 · 3 comments · Fixed by #16115

Comments

@gsakkis
Copy link

gsakkis commented Jun 30, 2023

Crash Report

Creating a TypedDict with non-literal keys gives TypedDict() expects a dictionary literal as the second argument. Attempting to ignore this with # type: ignore causes an AssertionError if (and only if):

  • any error (unrelated to TypedDict) happens later in a different module that imports the one with the TypedDict definition
  • and .mypy_cache exists

Traceback

✗ mypy --show-traceback main.py
main.py:3: error: Unsupported operand types for + ("int" and "str")  [operator]
Found 1 error in 1 file (checked 1 source file)

✗ mypy --show-traceback main.py
Traceback (most recent call last):
  (...)
  File "mypy/main.py", line 95, in main
  File "mypy/main.py", line 174, in run_build
  File "mypy/build.py", line 197, in build
  File "mypy/build.py", line 270, in _build
  File "mypy/build.py", line 2927, in dispatch
  File "mypy/build.py", line 3318, in process_graph
  File "mypy/build.py", line 3399, in process_fresh_modules
  File "mypy/build.py", line 2114, in fix_cross_refs
  File "mypy/fixup.py", line 53, in fixup_module
  File "mypy/fixup.py", line 126, in visit_symbol_table
AssertionError: ('counts.Counts', 'counts.TypedDict')

To Reproduce

# counts.py

from typing import TypedDict

Counts = TypedDict("Counts", {k: int for k in "abc"})  # type: ignore
# main.py

from counts import Counts

print(1 + "a")

Your Environment

  • Mypy version used: 1.4.1
  • Python version used: 3.10
@AlexWaygood
Copy link
Member

I can reproduce this, but importantly, this doesn't crash the first time you run mypy -- only the second time you run mypy. (This indicates that it's probably something to do with mypy's cache.)

@gsakkis
Copy link
Author

gsakkis commented Jun 30, 2023

Just noticed that in my original code I get different traceback from the MCVE above:

  File "mypy/main.py", line 95, in main
  File "mypy/main.py", line 174, in run_build
  File "mypy/build.py", line 197, in build
  File "mypy/build.py", line 270, in _build
  File "mypy/build.py", line 2927, in dispatch
  File "mypy/build.py", line 3318, in process_graph
  File "mypy/build.py", line 3399, in process_fresh_modules
  File "mypy/build.py", line 2114, in fix_cross_refs
  File "mypy/fixup.py", line 53, in fixup_module
  File "mypy/fixup.py", line 136, in visit_symbol_table
  File "mypy/fixup.py", line 86, in visit_type_info
  File "mypy/types.py", line 2382, in accept
  File "mypy/fixup.py", line 287, in visit_typeddict_type
  File "mypy/types.py", line 391, in accept
  File "mypy/fixup.py", line 231, in visit_type_alias_type
  File "mypy/fixup.py", line 386, in lookup_fully_qualified_alias
AssertionError: Should never get here in normal mode, got NoneType: instead of TypeAlias

@AlexWaygood
Copy link
Member

I can reproduce this, but importantly, this doesn't crash the first time you run mypy -- only the second time you run mypy. (This indicates that it's probably something to do with mypy's cache.)

Here's the traceback I get using mypy master on Python 3.11 with the original repro:

>mypy main.py --show-traceback
Traceback (most recent call last):
  File "<frozen runpy>", line 198, in _run_module_as_main
  File "<frozen runpy>", line 88, in _run_code
  File "C:\Users\alexw\coding\mypy\venv\Scripts\mypy.exe\__main__.py", line 7, in <module>
  File "C:\Users\alexw\coding\mypy\mypy\__main__.py", line 15, in console_entry
    main()
  File "C:\Users\alexw\coding\mypy\mypy\main.py", line 95, in main
    res, messages, blockers = run_build(sources, options, fscache, t0, stdout, stderr)
                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\alexw\coding\mypy\mypy\main.py", line 174, in run_build
    res = build.build(sources, options, None, flush_errors, fscache, stdout, stderr)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\alexw\coding\mypy\mypy\build.py", line 194, in build
    result = _build(
             ^^^^^^^
  File "C:\Users\alexw\coding\mypy\mypy\build.py", line 267, in _build
    graph = dispatch(sources, manager, stdout)
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\alexw\coding\mypy\mypy\build.py", line 2926, in dispatch
    process_graph(graph, manager)
  File "C:\Users\alexw\coding\mypy\mypy\build.py", line 3317, in process_graph
    process_fresh_modules(graph, prev_scc, manager)
  File "C:\Users\alexw\coding\mypy\mypy\build.py", line 3398, in process_fresh_modules
    graph[id].fix_cross_refs()
  File "C:\Users\alexw\coding\mypy\mypy\build.py", line 2113, in fix_cross_refs
    fixup_module(self.tree, self.manager.modules, self.options.use_fine_grained_cache)
  File "C:\Users\alexw\coding\mypy\mypy\fixup.py", line 53, in fixup_module
    node_fixer.visit_symbol_table(tree.names, tree.fullname)
  File "C:\Users\alexw\coding\mypy\mypy\fixup.py", line 126, in visit_symbol_table
    assert stnode.node is not None, (table_fullname + "." + key, cross_ref)
           ^^^^^^^^^^^^^^^^^^^^^^^
AssertionError: ('counts.Counts', 'counts.TypedDict')

hauntsaninja pushed a commit that referenced this issue Sep 15, 2023
Fixes #15557

FWIW I simply copy the logic for handling malformed definitions from
named tuples, that seems to be much more robust.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants