Positional arguments in any operations result in `Too few arguments` mypy errors
To Reproduce
Consider the following trivial deploy, using server here, but pretty much any operation would reproduce it:
$ cat test.py
from pyinfra.operations import server
server.shell('echo')
$ uv run --extra dev mypy test.py
test.py:2: error: Too few arguments for "__call__" of "PyinfraOperation" [call-arg]
test.py:2: error: Argument 1 to "__call__" of "PyinfraOperation" has incompatible type "str"; expected "bool" [arg-type]
Expected behavior
This should type check without mypy complaining.
Workaround
This is likely caused by this workaround https://github.com/pyinfra-dev/pyinfra/blob/39d1d31b374c85c69f6fe074b067f3aa7989f2a4/pyinfra/api/arguments_typed.py#L29-L79
It seems like using explicit keyword arguments for the operations works around the issue -- this passes mypy:
from pyinfra.operations import server
server.shell(commands='echo')
Proper fix?
I'm not sure if it's really possible, from reading
- https://peps.python.org/pep-0612/#concatenating-keyword-parameters
- https://typing.python.org/en/latest/spec/generics.html#id5
, it seems that it's only possible to provide extra positional arguments by using Protocol with __call__ and ParamSpec. So unless one specifies all the extra arguments (i.e. _sudo/_sudo_user/_use_sudo_login/...), it's not really possible to use arguments from P.args (i.e. the actual operation's arguments) as positional arguments.
So I guess I'm not really expecting a fix, but figured it's worth creating an issue so at least other people can find it and the workaround via search.
Meta
- using latest
3.xpyinfra - related issue: https://github.com/pyinfra-dev/pyinfra/pull/1105
This has been previously discussed on Matrix, it happens with Python 3.13+ releases.
pyinfra is currently only supported and tested on Python 3.10 to 3.12, so you should use a Python 3.12 venv until this is handled.
Hmm, I'm not sure it only happens on 3.13?
$ uv run --python=3.12 --extra dev python3 --version
warning: No `requires-python` value found in the workspace. Defaulting to `>=3.12`.
Python 3.12.6
$ uv run --python=3.12 --extra dev mypy test.py
warning: No `requires-python` value found in the workspace. Defaulting to `>=3.12`.
Warning: Unpack is already enabled by default
test.py:2: error: Too few arguments for "__call__" of "PyinfraOperation" [call-arg]
test.py:2: error: Argument 1 to "__call__" of "PyinfraOperation" has incompatible type "str"; expected "bool" [arg-type]
Found 2 errors in 1 file (checked 1 source file)
I went through the matrix converstaion, but didn't really understand why 3.12 would fix this, changelog for 3.13 doesn't mention anything with ParamSpec except something about defaults handling (which I don't think is at play here?).
it seems that it's only possible to provide extra positional arguments by using Protocol with call and ParamSpec. So unless one specifies all the extra arguments (i.e. _sudo/_sudo_user/_use_sudo_login/...), it's not really possible to use arguments from P.args (i.e. the actual operation's arguments) as positional arguments.
This, unfortunately I believe this is, as it stands today, the situation. Positional args will not pass type checking cleanly.
So I guess I'm not really expecting a fix, but figured it's worth creating an issue so at least other people can find it and the workaround via search.
👍
IMO the correct “fix” here is just to use keyword arguments for all operation calls, which the docs and examples do (or should). Personally I think it makes for more explicit code which is a good thing.
IMO the correct “fix” here is just to use keyword arguments for all operation calls, which the docs and examples do (or should). Personally I think it makes for more explicit code which is a good thing.
Can confirm that moving all positional arguments to keyword arguments fixes these mypy errors. I'll fall into this trap more than once in the future, but I don't see an easy fix to this.