Skip to content

Conversation

@agatti
Copy link

@agatti agatti commented Nov 18, 2025

This PR adds support for optional custom argument type validation to argparse.ArgumentParser, allowing for shorter argument validation code for both simple builtins and complex types, as supported by CPython.

CPython also provides the argparse.FileType class to simplify argument file/directory handling, but that was not added to the MicroPython module. Its behaviour is rather easy to manually replicate if needed anyway.

This change increases the size of the argparse module by 306 bytes, and that's mostly due to the extra error handling and related text strings. Probably those new strings can be shortened, but given that this module isn't usually included in production code, the size increase shouldn't hurt too much I guess.

The unit tests unfortunately do not cover the case of a parameter failing validation, as the module will automatically issue a sys.exit call on error, after printing the relevant exception message. If there are cleaner ways to test that without hijacking sys.exit, let me know so I can update the tests accordingly.

parser.add_argument("-d", type=())
assert False
except ValueError as e:
assert str(e) == "type is not callable"
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

assert "not callable" in str(e) would be CPython-compatible

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, this should be sorted out now.

@stinos
Copy link

stinos commented Nov 18, 2025

I'd suggest to make this as much CPython-compatible as possible. It has this particular behavior: https://docs.python.org/3/library/argparse.html#type

If the type keyword is used with the default keyword, the type converter is only applied if the default is a string.

So in CPython the resulting behavior is this:

parser.add_argument("-g", type=CustomArgType(1), default=1)
parser.add_argument("-i", type=CustomArgType(1), default="1")
args = parser.parse_args([])
assert args.g == 1
assert args.i == 2

@agatti agatti force-pushed the argparse-customtypes branch from abcd3e4 to 5c007f4 Compare November 18, 2025 20:04
This commit adds support for optional custom argument type validation to
argparse.ArgumentParser, allowing for shorter argument validation code
for both simple builtins and complex types.

For example, assuming that a particular command line argument must be an
integer, using "parser.add_argument('-a', type=int)" will make sure that
any value passed to that argument that cannot be converted into an
integer will trigger an argument validation error.

Signed-off-by: Alessandro Gatti <a.gatti@frob.it>
@agatti agatti force-pushed the argparse-customtypes branch from 5c007f4 to 13541ff Compare November 18, 2025 20:15
@agatti
Copy link
Author

agatti commented Nov 18, 2025

I'd suggest to make this as much CPython-compatible as possible. It has this particular behavior: ...

Thanks for spotting that! I've made it more CPython-compatible, at the expense of an increased footprint by 100 more bytes. The case you mentioned should be handled, along with the exception handling limitations of the custom type parser (ie. let anything that's not ArgumentTypeError, TypeError, and ValueError through and catch the rest).

Right now the main differences between this and CPython should be the lack of type registration, and argparse.FileType not being present. This should cover most usages, I suppose.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants