Skip to content

Union[Literal["foo"], ...] evaluates foo in global context  #372

@benclifford

Description

@benclifford

Things to check first

  • I have searched the existing issues and didn't find my bug already reported there

  • I have checked that my bug is still present in the latest release

Typeguard version

4.0.1

Python version

3.11.2

What happened?

The behaviour of Literal inside a Union seems to have changed from typeguard 4.0.0 to 4.0.1

In typeguard 4.0.1, this code:

import typeguard

from typing import Union
from typing import Literal

class Config:
    @typeguard.typechecked
    def __init__(self,

                 p: Union[
                          Literal['foo'],
                         ]):
        pass

c = Config(p = "foo")

raises this error:

$ python x.py 
Traceback (most recent call last):
  File "/home/benc/parsl/src/parsl/x.py", line 15, in <module>
    c = Config(p = "foo")
        ^^^^^^^^^^^^^^^^^
  File "/home/benc/parsl/src/parsl/x.py", line 11, in __init__
    Literal['foo'],
            ^^^^^
NameError: name 'foo' is not defined

With typeguard 4.0.0, this code successfully runs.

If I assign a literal to global variable foo, then it looks as if the global variable is dereferenced to provide the literal value here:

$ cat x.py 
import typeguard

from typing import Union
from typing import Literal

foo = "HELLO"

class Config:
    @typeguard.typechecked
    def __init__(self,

                 p: Union[
                          Literal['foo'],
                         ]):
        pass

c = Config(p = "foo")

gives

Traceback (most recent call last):
  File "/home/benc/parsl/src/parsl/x.py", line 17, in <module>
    c = Config(p = "foo")
        ^^^^^^^^^^^^^^^^^
  File "/home/benc/parsl/src/parsl/x.py", line 10, in __init__
    def __init__(self,
  File "/home/benc/parsl/virtualenv-3.11/lib/python3.11/site-packages/typeguard/_functions.py", line 135, in check_argument_types
    check_type_internal(value, annotation, memo)
  File "/home/benc/parsl/virtualenv-3.11/lib/python3.11/site-packages/typeguard/_checkers.py", line 774, in check_type_internal
    checker(value, origin_type, args, memo)
  File "/home/benc/parsl/virtualenv-3.11/lib/python3.11/site-packages/typeguard/_checkers.py", line 582, in check_literal
    raise TypeCheckError(f"is not any of ({formatted_args})") from None
typeguard.TypeCheckError: argument "p" (str) is not any of ('HELLO')

I think this is incorrect behaviour.

If I remove the Union wrapping, then the code behaves as I would expect, executing without error.

$ cat x.py 
import typeguard

from typing import Union
from typing import Literal

class Config:
    @typeguard.typechecked
    def __init__(self,
                 p: Literal['foo'],
                         ):
        pass

c = Config(p = "foo")

(the broader context is this checkpoint_mode parameter: https://github.com/Parsl/parsl/blob/70b9a2cd663087bc2197f633681a0e5f23ad68e1/parsl/config.py#L79)

How can we reproduce the bug?

The above examples should be pretty minimal. Here's my installed package list:

$ pip list
Package                       Version                        Editable project location
----------------------------- ------------------------------ --------------------------
aiohttp                       3.8.2
aiosignal                     1.3.1
alabaster                     0.7.13
asttokens                     2.2.1
async-timeout                 4.0.2
atomicwrites                  1.4.1
attrs                         22.2.0
autopep8                      2.0.2
Babel                         2.12.1
backcall                      0.2.0
bcrypt                        4.0.1
beautifulsoup4                4.11.2
bleach                        6.0.0
boto3                         1.26.158
botocore                      1.29.158
certifi                       2023.5.7
cffi                          1.15.1
charset-normalizer            2.1.1
click                         8.1.3
cloudpickle                   2.2.1
comm                          0.1.2
conda-pack                    0.6.0
contourpy                     1.0.7
coverage                      7.2.1
cryptography                  41.0.1
cycler                        0.11.0
debugpy                       1.6.6
decorator                     4.4.2
defusedxml                    0.7.1
dill                          0.3.6
dnpcsql                       0                              /home/benc/parsl/src/dnpc
docutils                      0.17.1
entrypoints                   0.4
execnet                       1.9.0
executing                     1.2.0
fastjsonschema                2.16.3
flake8                        6.0.0
Flask                         2.2.3
Flask-SQLAlchemy              2.5.1
fonttools                     4.39.0
frozenlist                    1.3.3
globus-compute-common         0.2.0
globus-compute-sdk            2.2.1
globus-sdk                    3.22.0
greenlet                      2.0.3.dev0
idna                          3.4
imagesize                     1.4.1
importlib-metadata            4.13.0
iniconfig                     2.0.0
ipykernel                     6.21.3
ipyparallel                   8.4.1
ipython                       8.6.0
itsdangerous                  2.1.2
jaraco.classes                3.2.3
jedi                          0.18.2
jeepney                       0.8.0
Jinja2                        3.1.2
jmespath                      1.0.1
jsonschema                    4.17.3
jupyter_client                8.0.3
jupyter_core                  5.2.0
jupyterlab-pygments           0.2.2
keyring                       23.13.1
kiwisolver                    1.4.4
lazy-object-proxy             1.9.0
lockfile                      0.12.2
markdown-it-py                2.2.0
MarkupSafe                    2.1.2
matplotlib                    3.7.1
matplotlib-inline             0.1.6
mccabe                        0.7.0
mdurl                         0.1.2
mistune                       2.0.5
mock                          5.0.1
more-itertools                9.1.0
multidict                     5.2.0
mypy                          1.1.1
mypy-extensions               1.0.0
nbclient                      0.7.2
nbconvert                     7.2.9
nbformat                      5.7.3
nbsphinx                      0.8.12
nest-asyncio                  1.5.6
networkx                      2.5.1
numpy                         1.24.2
packaging                     23.0
pandas                        1.3.5
pandas-stubs                  1.5.3.230304
pandocfilters                 1.5.0
paramiko                      3.2.0
parsl                         2023.7.24.dev0+desc.2023.7.26a /home/benc/parsl/src/parsl
parso                         0.8.3
pexpect                       4.8.0
pickleshare                   0.7.5
pika                          1.3.1
Pillow                        9.4.0
pip                           23.0.1
pkginfo                       1.9.6
platformdirs                  3.1.0
plotly                        5.13.1
pluggy                        0.13.1
prompt-toolkit                3.0.38
psutil                        5.9.5
psycopg2                      2.9.6
ptyprocess                    0.7.0
pure-eval                     0.2.2
py                            1.11.0
pycodestyle                   2.10.0
pycparser                     2.21
pydantic                      1.10.7
pydot                         1.4.2
pyflakes                      3.0.1
Pygments                      2.14.0
PyJWT                         2.7.0
PyNaCl                        1.5.0
pyparsing                     3.0.9
pyrsistent                    0.19.3
pytest                        7.4.0
pytest-cov                    4.0.0
pytest-forked                 1.6.0
pytest-random-order           1.1.0
pytest-xdist                  1.26.1
python-daemon                 2.3.2
python-dateutil               2.8.2
pytz                          2022.7.1
pyzmq                         25.1.0
readme-renderer               37.3
requests                      2.31.0
requests-toolbelt             0.10.1
rfc3986                       2.0.0
rich                          13.3.2
s3transfer                    0.6.1
scipy                         1.10.1
SecretStorage                 3.3.3
serpent                       1.41
setproctitle                  1.3.2
setuptools                    67.4.0
six                           1.16.0
snowballstemmer               2.2.0
soupsieve                     2.4
Sphinx                        4.5.0
sphinx-rtd-theme              1.2.0
sphinxcontrib-applehelp       1.0.4
sphinxcontrib-devhelp         1.0.2
sphinxcontrib-htmlhelp        2.0.1
sphinxcontrib-jquery          2.0.0
sphinxcontrib-jsmath          1.0.1
sphinxcontrib-qthelp          1.0.3
sphinxcontrib-serializinghtml 1.1.5
SQLAlchemy                    1.4.48
sqlalchemy2-stubs             0.0.2a34
stack-data                    0.6.2
tblib                         1.7.0
tenacity                      8.2.2
texttable                     1.6.7
tinycss2                      1.2.1
toml                          0.10.2
tornado                       6.2
tqdm                          4.65.0
traitlets                     5.9.0
twine                         4.0.2
typeguard                     4.0.1
types-paramiko                3.2.0.0
types-python-dateutil         2.8.19.10
types-pytz                    2022.7.1.2
types-requests                2.31.0.1
types-six                     1.16.21.8
types-urllib3                 1.26.25.13
typing_extensions             4.7.1
urllib3                       1.26.16
wcwidth                       0.2.6
webencodings                  0.5.1
websockets                    10.3
Werkzeug                      2.2.3
wheel                         0.38.4
yarl                          1.9.2
zipp                          3.15.0

[notice] A new release of pip is available: 23.0.1 -> 23.2.1
[notice] To update, run: pip install --upgrade pip

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions