Skip to content

Bug: CLI - litestar run raises 'Scope' is not defined when using Request in type annotation #3895

@jacopofar

Description

@jacopofar

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

  • Linux
  • Mac
  • Windows
  • Other (Please specify in the description above)

Metadata

Metadata

Assignees

No one assigned

    Labels

    Bug 🐛This is something that is not working as expectedNeeds MCVEThis needs an MCVE

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions