Things to check first
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
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:
raises this error:
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:gives
I think this is incorrect behaviour.
If I remove the
Unionwrapping, then the code behaves as I would expect, executing without error.(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: