One could do so. Imho, the post reaches a flawed solution. I personally just keep the Namespace object as-is and pass it as an argument. This keeps everything together, reduces argument count and potential for mixing stuff. This also avoids the unwanted duplication your solution tries to avoid.
Here's what I always do:
```python
import argparse import typing
class Namespace(typing.NamedTuple): """Mock Namespace used for type hinting purposes. Keep in sync with the argument parser defined in parse_args""" option_a: bool option_b: int
def main(args: Namespace): if args.option_a: print(args.option_b) some_logic(args)
def some_logic(args: Namespace): pass
if __name__ == "__main__": args = parse_args() main(args)
```
With that approach, the IDE/linter can do static type checking, and complains when assigning to the namespace, or when types don't match, or when accessed arguments don't exist.
You have to write a unit test though, that ensures that the mock Namespace is in sync with the actual one created by the argument parser. But that's easy enough, just call parse_args() in a test and compare the result keys/value types with the Namespace.__annotations__ dict.
One thing to keep in mind is that the mock Namespace is not the actual Namespace class. So you cannot do checks like `isinstance(args, Namespace)`. But those shouldn't be done in the first place, anyway.
Comment
One could do so.
Imho, the post reaches a flawed solution. I personally just keep the Namespace object as-is and pass it as an argument. This keeps everything together, reduces argument count and potential for mixing stuff. This also avoids the unwanted duplication your solution tries to avoid.
Here's what I always do:
```python
import argparse
import typing
class Namespace(typing.NamedTuple):
"""Mock Namespace used for type hinting purposes. Keep in sync with the argument parser defined in parse_args"""
option_a: bool
option_b: int
def parse_args() -> Namespace:
parser = argparse.ArgumentParser()
parser.add_argument("-o", "--option-a", action="store_true")
parser.add_argument("-n", "--option-b", type=int, default=0)
return parser.parse_args()
def main(args: Namespace):
if args.option_a:
print(args.option_b)
some_logic(args)
def some_logic(args: Namespace):
pass
if __name__ == "__main__":
args = parse_args()
main(args)
```
With that approach, the IDE/linter can do static type checking, and complains when assigning to the namespace, or when types don't match, or when accessed arguments don't exist.
You have to write a unit test though, that ensures that the mock Namespace is in sync with the actual one created by the argument parser. But that's easy enough, just call parse_args() in a test and compare the result keys/value types with the Namespace.__annotations__ dict.
One thing to keep in mind is that the mock Namespace is not the actual Namespace class. So you cannot do checks like `isinstance(args, Namespace)`. But those shouldn't be done in the first place, anyway.