Description
Hello, not 100% sure this is a bug, probably I'm missing something.
My app started breaking when I added an import like from litestar import Request or from litestar.datastructures import State, both imports are used only to add type hints to my app code.
Running litestar run now gives an exception like this:
Complete trace
Traceback (most recent call last):
File "/home/jacopo/projects/milanorama/.venv/bin/litestar", line 8, in <module>
sys.exit(run_cli())
^^^^^^^^^
File "/home/jacopo/projects/milanorama/.venv/lib/python3.12/site-packages/litestar/__main__.py", line 6, in run_cli
litestar_group()
File "/home/jacopo/projects/milanorama/.venv/lib/python3.12/site-packages/rich_click/rich_command.py", line 367, in __call__
return super().__call__(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/jacopo/projects/milanorama/.venv/lib/python3.12/site-packages/click/core.py", line 1157, in __call__
return self.main(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/jacopo/projects/milanorama/.venv/lib/python3.12/site-packages/rich_click/rich_command.py", line 151, in main
with self.make_context(prog_name, args, **extra) as ctx:
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/jacopo/projects/milanorama/.venv/lib/python3.12/site-packages/litestar/cli/_utils.py", line 224, in make_context
self._prepare(ctx)
File "/home/jacopo/projects/milanorama/.venv/lib/python3.12/site-packages/litestar/cli/_utils.py", line 206, in _prepare
env = ctx.obj = LitestarEnv.from_env(ctx.params.get("app_path"), ctx.params.get("app_dir"))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/jacopo/projects/milanorama/.venv/lib/python3.12/site-packages/litestar/cli/_utils.py", line 114, in from_env
loaded_app = _autodiscover_app(cwd)
^^^^^^^^^^^^^^^^^^^^^^
File "/home/jacopo/projects/milanorama/.venv/lib/python3.12/site-packages/litestar/cli/_utils.py", line 342, in _autodiscover_app
get_type_hints(value, include_extras=True).get("return") if hasattr(value, "__annotations__") else None
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/jacopo/projects/milanorama/.venv/lib/python3.12/site-packages/typing_extensions.py", line 1230, in get_type_hints
hint = typing.get_type_hints(
^^^^^^^^^^^^^^^^^^^^^^
File "/home/jacopo/.local/share/uv/python/cpython-3.12.7-linux-x86_64-gnu/lib/python3.12/typing.py", line 2275, in get_type_hints
value = _eval_type(value, base_globals, base_locals, base.__type_params__)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/jacopo/.local/share/uv/python/cpython-3.12.7-linux-x86_64-gnu/lib/python3.12/typing.py", line 415, in _eval_type
return t._evaluate(globalns, localns, type_params, recursive_guard=recursive_guard)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/jacopo/.local/share/uv/python/cpython-3.12.7-linux-x86_64-gnu/lib/python3.12/typing.py", line 948, in _evaluate
eval(self.__forward_code__, globalns, localns),
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "<string>", line 1, in <module>
NameError: name 'Scope' is not defined. Did you mean: 'scope'?
investigating a bit I found that it fails when I import that module because, for what I understand, Litestar is scanning the modules to find the CLI commands as explained in the docs, and doing so tries to get their types. It invokes typing_extension which calls typing.get_type_hints from the standard library, which iterates over the elements in __mro__ for the Request class and finds ASGIConnection. This class has a scope member of type Scope which is a type that is imported only for type checking so at runtime it cannot be found.
A similar thing happens with from litestar.datastructures import State, which I use for type hints.
I'm very confused by this, I think this is a basic function and indeed if I create an app from scratch (like the hello world on the homepage) and import this there's no issue. Maybe something else is interfering.
URL to code causing the issue
https://github.com/jacopofar/litestar-mcve
MCVE
MCVE here: https://github.com/jacopofar/litestar-mcve
(on the `this-works` branch there's a minimal variation that works)
from litestar import Request
from typing_extensions import get_type_hints
get_type_hints(Request, include_extras=True)
from litestar.datastructures import State
get_type_hints(State, include_extras=True)
Steps to reproduce
1. clone the repo https://github.com/jacopofar/litestar-mcve
2. Run the app (there's a command in the README), the error is immediate
3. See in the `this-works` branch a small variation which runs
Screenshots
No response
Logs
Usage: litestar [OPTIONS] COMMAND [ARGS]...
Litestar CLI.
╭─ Options ────────────────────────────────────────────────────────────────────╮
│ --app TEXT Module path to a Litestar application (TEXT) │
│ --app-dir DIRECTORY Look for APP in the specified directory, by adding │
│ this to the PYTHONPATH. Defaults to the current │
│ working directory. │
│ (DIRECTORY) │
│ --help -h Show this message and exit. │
╰──────────────────────────────────────────────────────────────────────────────╯
Traceback (most recent call last):
File "/opt/breakme/.venv/bin/litestar", line 8, in <module>
sys.exit(run_cli())
^^^^^^^^^
File "/opt/breakme/.venv/lib/python3.12/site-packages/litestar/__main__.py", line 6, in run_cli
litestar_group()
File "/opt/breakme/.venv/lib/python3.12/site-packages/rich_click/rich_command.py", line 367, in __call__
return super().__call__(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/opt/breakme/.venv/lib/python3.12/site-packages/click/core.py", line 1157, in __call__
return self.main(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/opt/breakme/.venv/lib/python3.12/site-packages/rich_click/rich_command.py", line 151, in main
with self.make_context(prog_name, args, **extra) as ctx:
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/opt/breakme/.venv/lib/python3.12/site-packages/litestar/cli/_utils.py", line 223, in make_context
ctx = super().make_context(info_name, args, parent, **extra)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/opt/breakme/.venv/lib/python3.12/site-packages/rich_click/rich_command.py", line 260, in make_context
return super().make_context(info_name, args, parent, **extra) # type: ignore[return-value]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/opt/breakme/.venv/lib/python3.12/site-packages/click/core.py", line 943, in make_context
self.parse_args(ctx, args)
File "/opt/breakme/.venv/lib/python3.12/site-packages/click/core.py", line 1644, in parse_args
rest = super().parse_args(ctx, args)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/opt/breakme/.venv/lib/python3.12/site-packages/click/core.py", line 1408, in parse_args
value, args = param.handle_parse_result(ctx, opts, args)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/opt/breakme/.venv/lib/python3.12/site-packages/click/core.py", line 2400, in handle_parse_result
value = self.process_value(ctx, value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/opt/breakme/.venv/lib/python3.12/site-packages/click/core.py", line 2362, in process_value
value = self.callback(ctx, self, value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/opt/breakme/.venv/lib/python3.12/site-packages/click/core.py", line 1300, in show_help
echo(ctx.get_help(), color=ctx.color)
^^^^^^^^^^^^^^
File "/opt/breakme/.venv/lib/python3.12/site-packages/click/core.py", line 704, in get_help
return self.command.get_help(self)
^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/opt/breakme/.venv/lib/python3.12/site-packages/click/core.py", line 1325, in get_help
self.format_help(ctx, formatter)
File "/opt/breakme/.venv/lib/python3.12/site-packages/rich_click/rich_command.py", line 359, in format_help
self.format_options(ctx, formatter)
File "/opt/breakme/.venv/lib/python3.12/site-packages/rich_click/rich_command.py", line 296, in format_options
self.format_commands(ctx, formatter) # type: ignore[arg-type]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/opt/breakme/.venv/lib/python3.12/site-packages/rich_click/rich_command.py", line 289, in format_commands
get_rich_commands(self, ctx, formatter)
File "/opt/breakme/.venv/lib/python3.12/site-packages/rich_click/rich_help_rendering.py", line 616, in get_rich_commands
for command in obj.list_commands(ctx):
^^^^^^^^^^^^^^^^^^^^^^
File "/opt/breakme/.venv/lib/python3.12/site-packages/litestar/cli/_utils.py", line 228, in list_commands
self._prepare(ctx)
File "/opt/breakme/.venv/lib/python3.12/site-packages/litestar/cli/_utils.py", line 206, in _prepare
env = ctx.obj = LitestarEnv.from_env(ctx.params.get("app_path"), ctx.params.get("app_dir"))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/opt/breakme/.venv/lib/python3.12/site-packages/litestar/cli/_utils.py", line 114, in from_env
loaded_app = _autodiscover_app(cwd)
^^^^^^^^^^^^^^^^^^^^^^
File "/opt/breakme/.venv/lib/python3.12/site-packages/litestar/cli/_utils.py", line 340, in _autodiscover_app
get_type_hints(value, include_extras=True).get("return") if hasattr(value, "__annotations__") else None
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/opt/breakme/.venv/lib/python3.12/site-packages/typing_extensions.py", line 1230, in get_type_hints
hint = typing.get_type_hints(
^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.12/typing.py", line 2263, in get_type_hints
value = _eval_type(value, base_globals, base_locals, base.__type_params__)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.12/typing.py", line 415, in _eval_type
return t._evaluate(globalns, localns, type_params, recursive_guard=recursive_guard)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.12/typing.py", line 938, in _evaluate
eval(self.__forward_code__, globalns, locals_to_pass),
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "<string>", line 1, in <module>
NameError: name 'Scope' is not defined. Did you mean: 'scope'?
Litestar Version
2.13.0
Platform
Description
Hello, not 100% sure this is a bug, probably I'm missing something.
My app started breaking when I added an import like
from litestar import Requestorfrom litestar.datastructures import State, both imports are used only to add type hints to my app code.Running
litestar runnow gives an exception like this:Complete trace
investigating a bit I found that it fails when I import that module because, for what I understand, Litestar is scanning the modules to find the CLI commands as explained in the docs, and doing so tries to get their types. It invokes
typing_extensionwhich callstyping.get_type_hintsfrom the standard library, which iterates over the elements in__mro__for theRequestclass and findsASGIConnection. This class has a scope member of type Scope which is a type that is imported only for type checking so at runtime it cannot be found.A similar thing happens with
from litestar.datastructures import State, which I use for type hints.I'm very confused by this, I think this is a basic function and indeed if I create an app from scratch (like the hello world on the homepage) and import this there's no issue. Maybe something else is interfering.
URL to code causing the issue
https://github.com/jacopofar/litestar-mcve
MCVE
Steps to reproduce
Screenshots
No response
Logs
Usage: litestar [OPTIONS] COMMAND [ARGS]... Litestar CLI. ╭─ Options ────────────────────────────────────────────────────────────────────╮ │ --app TEXT Module path to a Litestar application (TEXT) │ │ --app-dir DIRECTORY Look for APP in the specified directory, by adding │ │ this to the PYTHONPATH. Defaults to the current │ │ working directory. │ │ (DIRECTORY) │ │ --help -h Show this message and exit. │ ╰──────────────────────────────────────────────────────────────────────────────╯ Traceback (most recent call last): File "/opt/breakme/.venv/bin/litestar", line 8, in <module> sys.exit(run_cli()) ^^^^^^^^^ File "/opt/breakme/.venv/lib/python3.12/site-packages/litestar/__main__.py", line 6, in run_cli litestar_group() File "/opt/breakme/.venv/lib/python3.12/site-packages/rich_click/rich_command.py", line 367, in __call__ return super().__call__(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/opt/breakme/.venv/lib/python3.12/site-packages/click/core.py", line 1157, in __call__ return self.main(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/opt/breakme/.venv/lib/python3.12/site-packages/rich_click/rich_command.py", line 151, in main with self.make_context(prog_name, args, **extra) as ctx: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/opt/breakme/.venv/lib/python3.12/site-packages/litestar/cli/_utils.py", line 223, in make_context ctx = super().make_context(info_name, args, parent, **extra) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/opt/breakme/.venv/lib/python3.12/site-packages/rich_click/rich_command.py", line 260, in make_context return super().make_context(info_name, args, parent, **extra) # type: ignore[return-value] ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/opt/breakme/.venv/lib/python3.12/site-packages/click/core.py", line 943, in make_context self.parse_args(ctx, args) File "/opt/breakme/.venv/lib/python3.12/site-packages/click/core.py", line 1644, in parse_args rest = super().parse_args(ctx, args) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/opt/breakme/.venv/lib/python3.12/site-packages/click/core.py", line 1408, in parse_args value, args = param.handle_parse_result(ctx, opts, args) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/opt/breakme/.venv/lib/python3.12/site-packages/click/core.py", line 2400, in handle_parse_result value = self.process_value(ctx, value) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/opt/breakme/.venv/lib/python3.12/site-packages/click/core.py", line 2362, in process_value value = self.callback(ctx, self, value) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/opt/breakme/.venv/lib/python3.12/site-packages/click/core.py", line 1300, in show_help echo(ctx.get_help(), color=ctx.color) ^^^^^^^^^^^^^^ File "/opt/breakme/.venv/lib/python3.12/site-packages/click/core.py", line 704, in get_help return self.command.get_help(self) ^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/opt/breakme/.venv/lib/python3.12/site-packages/click/core.py", line 1325, in get_help self.format_help(ctx, formatter) File "/opt/breakme/.venv/lib/python3.12/site-packages/rich_click/rich_command.py", line 359, in format_help self.format_options(ctx, formatter) File "/opt/breakme/.venv/lib/python3.12/site-packages/rich_click/rich_command.py", line 296, in format_options self.format_commands(ctx, formatter) # type: ignore[arg-type] ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/opt/breakme/.venv/lib/python3.12/site-packages/rich_click/rich_command.py", line 289, in format_commands get_rich_commands(self, ctx, formatter) File "/opt/breakme/.venv/lib/python3.12/site-packages/rich_click/rich_help_rendering.py", line 616, in get_rich_commands for command in obj.list_commands(ctx): ^^^^^^^^^^^^^^^^^^^^^^ File "/opt/breakme/.venv/lib/python3.12/site-packages/litestar/cli/_utils.py", line 228, in list_commands self._prepare(ctx) File "/opt/breakme/.venv/lib/python3.12/site-packages/litestar/cli/_utils.py", line 206, in _prepare env = ctx.obj = LitestarEnv.from_env(ctx.params.get("app_path"), ctx.params.get("app_dir")) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/opt/breakme/.venv/lib/python3.12/site-packages/litestar/cli/_utils.py", line 114, in from_env loaded_app = _autodiscover_app(cwd) ^^^^^^^^^^^^^^^^^^^^^^ File "/opt/breakme/.venv/lib/python3.12/site-packages/litestar/cli/_utils.py", line 340, in _autodiscover_app get_type_hints(value, include_extras=True).get("return") if hasattr(value, "__annotations__") else None ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/opt/breakme/.venv/lib/python3.12/site-packages/typing_extensions.py", line 1230, in get_type_hints hint = typing.get_type_hints( ^^^^^^^^^^^^^^^^^^^^^^ File "/usr/local/lib/python3.12/typing.py", line 2263, in get_type_hints value = _eval_type(value, base_globals, base_locals, base.__type_params__) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/local/lib/python3.12/typing.py", line 415, in _eval_type return t._evaluate(globalns, localns, type_params, recursive_guard=recursive_guard) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/local/lib/python3.12/typing.py", line 938, in _evaluate eval(self.__forward_code__, globalns, locals_to_pass), ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "<string>", line 1, in <module> NameError: name 'Scope' is not defined. Did you mean: 'scope'?Litestar Version
2.13.0
Platform