Skip to content

TypeError: cannot picke '_io.TextIOWrapper' regression in 0.30 for type=FileType(..), default=sys.stdin) #204

Closed
@mfussenegger

Description

@mfussenegger

It looks like there was a regression in the assembling refactor.
The following used to work:

import sys
import argh
from argparse import FileType


@argh.arg("-x", type=FileType("r", encoding="utf-8"), default=sys.stdin)
def foo(*, x):
    pass


if __name__ == "__main__":
    p = argh.ArghParser(prog="foo")
    p.add_commands([foo])
    p.dispatch()

Since 0.30.0 it results in the following stacktrace:

  File "/path/to/project/venv/lib/python3.11/site-packages/argh/helpers.py", line 47, in add_commands
    return add_commands(self, *args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/path/to/project/venv/lib/python3.11/site-packages/argh/assembling.py", line 557, in add_commands
    set_default_command(
  File "/path/to/project/venv/lib/python3.11/site-packages/argh/assembling.py", line 319, in set_default_command
    spec = _prepare_parser_add_argument_spec(
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/path/to/project/venv/lib/python3.11/site-packages/argh/assembling.py", line 354, in _prepare_parser_add_argument_spec
    spec = ParserAddArgumentSpec(**asdict(parser_add_argument_spec))
                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/dataclasses.py", line 1284, in asdict
    return _asdict_inner(obj, dict_factory)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/dataclasses.py", line 1291, in _asdict_inner
    value = _asdict_inner(getattr(obj, f.name), dict_factory)
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/dataclasses.py", line 1325, in _asdict_inner
    return copy.deepcopy(obj)
           ^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/copy.py", line 161, in deepcopy
    rv = reductor(4)
         ^^^^^^^^^^^
TypeError: cannot pickle '_io.TextIOWrapper' object

I suspect it can't picke sys.stdin?


Side note: Was it intentional that the keyword-only arguments become already mandatory?
#191 mentioned a smooth transition path.

If you change the above example to:

@argh.arg("-x", type=FileType("r", encoding="utf-8"), default=sys.stdin)
def foo(x):
    pass

It fails with argh.exceptions.AssemblingError: foo: argument "x" declared as positional (in function signature) and optional (via decorator)

Not that big of a deal and easy enough to adjust, but given that the issue mentions that there should be a smooth migration I wanted to mention it too.

Metadata

Metadata

Assignees

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions