swansonk14 / typed-argument-parser

Typed argument parser for Python
MIT License
505 stars 40 forks source link

Tapify, docstrings and typing.NamedTuples #129

Open tjgalvin opened 9 months ago

tjgalvin commented 9 months ago

First off, this is a wonderfully cool package and I am very excited to try my hand at using it! I have been looking for something like this for a while.

I am writing a codebase and have become fond of using typing.NamedTuples to create immutable structures that I can more easily pass around my heavy lifting functions. This works nicely for my use cases, as it I don't believe I really want to use dataclasses just yet.

tap mostly works out of the box with NamedTuples, but I am finding that docstrings are not picked up. For example:

from pathlib import Path
from typing import NamedTuple, Optional, get_type_hints

from tap import tapify, Tap

class FieldOptions(NamedTuple):
    """Container that represents the flint related options that
    might be used throughout components related to the actual
    pipeline.

    In its present form this ``FieldOptions`` class is not intended
    to container properties on the data that is being processed,
    rather how those data will be processed.

    These settins are not meant to be adjustable throughout
    rounds of self-calibration.
    """

    flagger_container: Path # This is n example
    """Path to the singularity aoflagger container"""
    calibrate_container: Path
    """Path to the singularity calibrate container"""
    expected_ms: int = 36
    """The expected number of measurement set files to find"""
    rounds: int = 2
    """Number of required rouds of self-calibration to perform"""
    zip_ms: bool = False
    """Whether to zip measurement sets once they are no longer required"""

if __name__ == '__main__':
    tapify(FieldOptions).parse_args()

produces the following help:

testing_tap.py: error: the following arguments are required: --flagger_container, --calibrate_container
(tap_test) ➜  tap_test python testing_tap.py -h
usage: testing_tap.py [-h] --flagger_container FLAGGER_CONTAINER --calibrate_container CALIBRATE_CONTAINER [--expected_ms EXPECTED_MS] [--rounds ROUNDS] [--zip_ms]

Initialize self. See help(type(self)) for accurate signature.

options:
  -h, --help            show this help message and exit
  --flagger_container FLAGGER_CONTAINER
                        (Path, required)
  --calibrate_container CALIBRATE_CONTAINER
                        (Path, required)
  --expected_ms EXPECTED_MS
                        (int, default=36)
  --rounds ROUNDS       (int, default=2)
  --zip_ms              (bool, default=False)

The defaults are all picked up nicely, but it seems like the doc-strings are not being presented. I am curious what is going on, and whether this is user error, or something is getting dropped along the way.

I played around a little and I am pretty sure that the FieldOptions.__doc__ is correct, but so far I have not been able to figure out the right way of getting to the docstrings of the attributes (if indeed I can!).

Any thoughts or suggestions? With some guidance I would be happy to try to add to tap for this use case.