diff --git a/packages/griffelib/src/griffe/_internal/expressions.py b/packages/griffelib/src/griffe/_internal/expressions.py index 4043c04b..67831a29 100644 --- a/packages/griffelib/src/griffe/_internal/expressions.py +++ b/packages/griffelib/src/griffe/_internal/expressions.py @@ -1324,6 +1324,10 @@ def _build_subscript( if isinstance(left, (ExprAttribute, ExprName)) and left.canonical_path in { "typing.Literal", "typing_extensions.Literal", + # A `Literal` that could not be resolved (e.g. used without an + # import) keeps its bare name as canonical path. Its string members + # are literal strings, not forward references, so keep their quotes. + "Literal", }: literal_strings = True slice_expr = _build( diff --git a/packages/griffelib/tests/test_expressions.py b/packages/griffelib/tests/test_expressions.py index e0b2267a..d8ea9f54 100644 --- a/packages/griffelib/tests/test_expressions.py +++ b/packages/griffelib/tests/test_expressions.py @@ -61,6 +61,26 @@ def test_full_expressions(annotation: str) -> None: assert str(module["x"].annotation) == annotation +@pytest.mark.parametrize( + "annotation", + [ + "Literal['a-b']", + "Literal['a', 'b']", + "Literal['hello world']", + ], +) +def test_unresolved_literal_keeps_string_quotes(annotation: str) -> None: + """Assert string members of an unresolved `Literal` keep their quotes. + + An unresolved `Literal` (used without an import) must still treat its + members as literal strings rather than forward references, otherwise + `Literal['a-b']` is mis-parsed as `Literal[a - b]`. + """ + code = f"x: {annotation}" + with temporary_visited_module(code) as module: + assert str(module["x"].annotation) == annotation + + def test_resolving_full_names() -> None: """Assert expressions are correctly transformed to their fully-resolved form.""" with temporary_visited_module(