Search code examples
pythonpython-typingmypy

No overload variant of subprocess.run matches argument types list[str], dict[str,object]


Below is my python code where I am trying to pass kubeseal_cmd and run_options to subprocess.run method, but it's giving me error

No overload variant of subprocess.run matches argument types list[str], dict[str,object].

What am I missing? I am using python 3.12

kubeseal_path = "/var/tmp/workspace/file.txt"
secret = yaml.safe_load(secret_File.read().encode("utf-8"))
cert_file = = "/var/tmp/workspace/file123.txt"
kubeseal_cmd = [
   kubeseal_path,
   "--cert",
   cert_file,
   "--format=yaml",
   "</dev/stdin>"
]
run_options = {
   "env": {},
   "stdout": subprocess.PIPE,
   "check": True,
   "input": yaml.dump(secret).encode(),
}
sealed_secret = yaml.safe_load(subprocess.run(kubeseal_cmd, **run_options).stdout.decode().strip())

Solution

  • The Easy Answer

    "Hey, doctor, it hurts when I do this!"
    "Don't do that"

    Nothing your code is doing requires the run_options dict. Take it out and the problem is mooted:

    sealed_secret = yaml.safe_load(
        subprocess.run(
            kubeseal_cmd,
            env={},
            stdout=subprocess.PIPE,
            check=True,
            input=yaml.dump(secret).encode(),
        ).stdout.decode().strip()
    )
    

    The Other Approach

    If you really want to be able to represent keyword arguments in a dict, you can do that by building a TypedDict setting out the type of each item.

    Note that this requires a quite current Python release -- the below code is tested on Python 3.12.

    from typing import Any, Literal, TypedDict, NotRequired, IO
    
    class RunOptions(TypedDict):
       env: NotRequired[dict[str, str]]
       check: NotRequired[bool]
       input: NotRequired[None|str|bytes]
       stdout: NotRequired[int | IO[Any]]
    
    run_options = RunOptions({
       "env": {},
       "stdout": subprocess.PIPE,
       "check": True,
       "input": yaml.dump(secret).encode(),
    })
    sealed_secret = yaml.safe_load(
        subprocess.run(kubeseal_cmd, **run_options).stdout.decode().strip()
    )