typedparser


Nametypedparser JSON
Version 0.22.2 PyPI version JSON
download
home_pageNone
SummaryExtension for python argparse with typehints and typechecks.
upload_time2024-12-18 17:41:35
maintainerNone
docs_urlNone
authorsimon-ging
requires_python>=3.8
licenseApache-2.0
keywords attrs typing dict attr
VCS
bugtrack_url
requirements attrs
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # typedparser

<p align="center">
<a href="https://github.com/simon-ging/typedparser/actions/workflows/build-py38.yml">
  <img alt="build 3.8 status" title="build 3.8 status" src="https://img.shields.io/github/actions/workflow/status/simon-ging/typedparser/build-py38.yml?branch=main&label=python%203.8" />
</a>
<a href="https://github.com/simon-ging/typedparser/actions/workflows/build-py39.yml">
  <img alt="build 3.9 status" title="build 3.9 status" src="https://img.shields.io/github/actions/workflow/status/simon-ging/typedparser/build-py39.yml?branch=main&label=python%203.9" />
</a>
<a href="https://github.com/simon-ging/typedparser/actions/workflows/build-py310.yml">
  <img alt="build 3.10 status" title="build 3.10 status" src="https://img.shields.io/github/actions/workflow/status/simon-ging/typedparser/build-py310.yml?branch=main&label=python%203.10" />
</a>
<a href="https://github.com/simon-ging/typedparser/actions/workflows/build-py311.yml">
  <img alt="build 3.11 status" title="build 3.11 status" src="https://img.shields.io/github/actions/workflow/status/simon-ging/typedparser/build-py311.yml?branch=main&label=python%203.11" />
</a>
<a href="https://github.com/simon-ging/typedparser/actions/workflows/build-py312.yml">
  <img alt="build 3.12 status" title="build 3.12 status" src="https://img.shields.io/github/actions/workflow/status/simon-ging/typedparser/build-py312.yml?branch=main&label=python%203.12" />
</a>
<a href="https://github.com/simon-ging/typedparser/actions/workflows/build-py312-full.yml">
  <img alt="build 3.12 full status" title="build 3.12 full status" src="https://img.shields.io/github/actions/workflow/status/simon-ging/typedparser/build-py312-full.yml?branch=main&label=python%203.12%20full" />
</a>
<img alt="coverage" title="coverage" src="https://raw.githubusercontent.com/simon-ging/typedparser/main/docs/coverage.svg" />
<a href="https://pypi.org/project/typedparser/">
  <img alt="version" title="version" src="https://img.shields.io/pypi/v/typedparser?color=success" />
</a>
</p>

Typing extension for python argparse using [attrs](https://www.attrs.org/en/stable/).

Includes typechecking and conversion utilities to parse a dictionary into an attrs instance. 

## Install

Requires `python>=3.8`

```bash
pip install typedparser
```

## Basic usage

1. Create an attrs class (decorate with `@attr.define`). Note that optional arguments must also be typed as optional.
2. Define and type the fields with `typedparser.add_argument` - the syntax extends [add_argument from argparse](https://docs.python.org/3/library/argparse.html#the-add-argument-method).
3. Parse the args with `TypedParser` and enjoy args with type hints. Disable typechecking by setting `strict=False`.

```python
from typing import Optional
from attrs import define
from typedparser import add_argument, TypedParser


@define
class Args:   
    # omit the argument name to have it inferred from the field name
    foo: str = add_argument(positional=True)
    bar: int = add_argument(shortcut="-b", type=int, default=0)
    opt: Optional[str] = add_argument()

    # # in case you prefer the regular argparse syntax:
    # foo: str = add_argument("foo")
    # bar: int = add_argument("-b", "--bar", type=int, default=0)
    # opt: Optional[str] = add_argument("--opt")
    
    

def main():
    parser = TypedParser.create_parser(Args, strict=True)
    args: Args = parser.parse_args()
    print(args)


if __name__ == "__main__":
    main()

```

## Features

* Create commandline arguments with type hints and checks while
staying close to the syntax of the standard library's argparse.
* Utilities for typechecking and converting nested objects:
  * Nested checking and conversion of python standard types
  * Supports old and new style typing (e.g. `typing.List` and `list`)
  * Supports positional and keyword arguments in classes
  * Can also typecheck existing attrs instances
  * Allows custom conversions, by default converts source type `str` to target type `Path` and
    `int` to `float`
  * Allows to redefine which objects will be recursed into, by default recurses into standard
    containers (list, dict, etc.)
  * `@definenumpy` decorator for equality check if the instances contains numpy arrays
* Some object utilities in `typedparser.objects` required for everything else

## Advanced usage

* Use `TypedParser.from_parser(parser, Args)` to add typing to an existing parser. This is useful
to cover usecases like subparsers or argument groups.
* Snippet for argument lists `xarg: List[int] = add_argument(shortcut="-x", type=int, action="append", help="Xarg", default=[])`,
use as `-x 1 -x 2` to get `[1, 2]` in the args instance.

### Usage of attr utilities

Define the class hierarchy and parse the input using `attrs_from_dict`.
Use `@define(slots=False)` to allow multiple inheritance and setting attributes later.

```python
from attrs import define
from typing import Optional
from typedparser import attrs_from_dict

@define
class Cfg:
    foo: int = 12
    bar: Optional[int] = None

print(attrs_from_dict(Cfg, {"foo": 1, "bar": 2}))
# Cfg(foo=1, bar=2)


@define
class CfgNested:
    sub_cfg: Cfg = None

print(attrs_from_dict(CfgNested, {"sub_cfg": {"foo": 1, "bar": 2}}))
# CfgNested(sub_cfg=Cfg(foo=1, bar=2))
```

### Strict mode (default)

* Convert everything to the target type, e.g. if the input is a list and the annotation is a tuple,
  the output will be a tuple
* Raise errors if types cannot be matched, there are unknown fields in the input or
  abstract annotation types are used (e.g. Sequence)
* Set `_allow_extra_keys = True` in the class definition to allow unknown fields in the input

### Non-strict mode

Enabled by calling `attrs_from_dict` with `strict=False`

* No conversion except for creating the attrs instance from the dict
* Ignore silently if types cannot be matched or abstract annotation types are used
* Unknown fields in the input will be added to the attrs instance if possible
  (see the hint below about slots)

### Skip unknowns

Set `skip_unknowns=True` to ignore all unknown input fields.

### Hints

The following behaviour stems from the `attrs` package:

* New attributes cannot to be added after class definition to an attrs instance,
  unless it is created with `@define(slots=False)`
  [Explanation](https://www.attrs.org/en/21.2.0/glossary.html#term-slotted-classes)
* Untyped fields or "ClassVar" typed fields will be ignored by @attrs.define
  and therefore also by this library.

## Install locally and run tests

Clone repository and cd into. Setup python 3.7 or higher. 
Note: Some tests are skipped for python 3.7.

```bash
pip install -e .
pip install pytest pytest-cov pylint
pylint typedparser

# run tests
python -m pytest --cov
pylint tests
```

            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "typedparser",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.8",
    "maintainer_email": null,
    "keywords": "attrs, typing, dict, attr",
    "author": "simon-ging",
    "author_email": null,
    "download_url": "https://files.pythonhosted.org/packages/cd/19/ba5d90ec5e0aa2060937db6f2693c77975d7c2e3fc8b677fda95cf8ebd88/typedparser-0.22.2.tar.gz",
    "platform": "any",
    "description": "# typedparser\n\n<p align=\"center\">\n<a href=\"https://github.com/simon-ging/typedparser/actions/workflows/build-py38.yml\">\n  <img alt=\"build 3.8 status\" title=\"build 3.8 status\" src=\"https://img.shields.io/github/actions/workflow/status/simon-ging/typedparser/build-py38.yml?branch=main&label=python%203.8\" />\n</a>\n<a href=\"https://github.com/simon-ging/typedparser/actions/workflows/build-py39.yml\">\n  <img alt=\"build 3.9 status\" title=\"build 3.9 status\" src=\"https://img.shields.io/github/actions/workflow/status/simon-ging/typedparser/build-py39.yml?branch=main&label=python%203.9\" />\n</a>\n<a href=\"https://github.com/simon-ging/typedparser/actions/workflows/build-py310.yml\">\n  <img alt=\"build 3.10 status\" title=\"build 3.10 status\" src=\"https://img.shields.io/github/actions/workflow/status/simon-ging/typedparser/build-py310.yml?branch=main&label=python%203.10\" />\n</a>\n<a href=\"https://github.com/simon-ging/typedparser/actions/workflows/build-py311.yml\">\n  <img alt=\"build 3.11 status\" title=\"build 3.11 status\" src=\"https://img.shields.io/github/actions/workflow/status/simon-ging/typedparser/build-py311.yml?branch=main&label=python%203.11\" />\n</a>\n<a href=\"https://github.com/simon-ging/typedparser/actions/workflows/build-py312.yml\">\n  <img alt=\"build 3.12 status\" title=\"build 3.12 status\" src=\"https://img.shields.io/github/actions/workflow/status/simon-ging/typedparser/build-py312.yml?branch=main&label=python%203.12\" />\n</a>\n<a href=\"https://github.com/simon-ging/typedparser/actions/workflows/build-py312-full.yml\">\n  <img alt=\"build 3.12 full status\" title=\"build 3.12 full status\" src=\"https://img.shields.io/github/actions/workflow/status/simon-ging/typedparser/build-py312-full.yml?branch=main&label=python%203.12%20full\" />\n</a>\n<img alt=\"coverage\" title=\"coverage\" src=\"https://raw.githubusercontent.com/simon-ging/typedparser/main/docs/coverage.svg\" />\n<a href=\"https://pypi.org/project/typedparser/\">\n  <img alt=\"version\" title=\"version\" src=\"https://img.shields.io/pypi/v/typedparser?color=success\" />\n</a>\n</p>\n\nTyping extension for python argparse using [attrs](https://www.attrs.org/en/stable/).\n\nIncludes typechecking and conversion utilities to parse a dictionary into an attrs instance. \n\n## Install\n\nRequires `python>=3.8`\n\n```bash\npip install typedparser\n```\n\n## Basic usage\n\n1. Create an attrs class (decorate with `@attr.define`). Note that optional arguments must also be typed as optional.\n2. Define and type the fields with `typedparser.add_argument` - the syntax extends [add_argument from argparse](https://docs.python.org/3/library/argparse.html#the-add-argument-method).\n3. Parse the args with `TypedParser` and enjoy args with type hints. Disable typechecking by setting `strict=False`.\n\n```python\nfrom typing import Optional\nfrom attrs import define\nfrom typedparser import add_argument, TypedParser\n\n\n@define\nclass Args:   \n    # omit the argument name to have it inferred from the field name\n    foo: str = add_argument(positional=True)\n    bar: int = add_argument(shortcut=\"-b\", type=int, default=0)\n    opt: Optional[str] = add_argument()\n\n    # # in case you prefer the regular argparse syntax:\n    # foo: str = add_argument(\"foo\")\n    # bar: int = add_argument(\"-b\", \"--bar\", type=int, default=0)\n    # opt: Optional[str] = add_argument(\"--opt\")\n    \n    \n\ndef main():\n    parser = TypedParser.create_parser(Args, strict=True)\n    args: Args = parser.parse_args()\n    print(args)\n\n\nif __name__ == \"__main__\":\n    main()\n\n```\n\n## Features\n\n* Create commandline arguments with type hints and checks while\nstaying close to the syntax of the standard library's argparse.\n* Utilities for typechecking and converting nested objects:\n  * Nested checking and conversion of python standard types\n  * Supports old and new style typing (e.g. `typing.List` and `list`)\n  * Supports positional and keyword arguments in classes\n  * Can also typecheck existing attrs instances\n  * Allows custom conversions, by default converts source type `str` to target type `Path` and\n    `int` to `float`\n  * Allows to redefine which objects will be recursed into, by default recurses into standard\n    containers (list, dict, etc.)\n  * `@definenumpy` decorator for equality check if the instances contains numpy arrays\n* Some object utilities in `typedparser.objects` required for everything else\n\n## Advanced usage\n\n* Use `TypedParser.from_parser(parser, Args)` to add typing to an existing parser. This is useful\nto cover usecases like subparsers or argument groups.\n* Snippet for argument lists `xarg: List[int] = add_argument(shortcut=\"-x\", type=int, action=\"append\", help=\"Xarg\", default=[])`,\nuse as `-x 1 -x 2` to get `[1, 2]` in the args instance.\n\n### Usage of attr utilities\n\nDefine the class hierarchy and parse the input using `attrs_from_dict`.\nUse `@define(slots=False)` to allow multiple inheritance and setting attributes later.\n\n```python\nfrom attrs import define\nfrom typing import Optional\nfrom typedparser import attrs_from_dict\n\n@define\nclass Cfg:\n    foo: int = 12\n    bar: Optional[int] = None\n\nprint(attrs_from_dict(Cfg, {\"foo\": 1, \"bar\": 2}))\n# Cfg(foo=1, bar=2)\n\n\n@define\nclass CfgNested:\n    sub_cfg: Cfg = None\n\nprint(attrs_from_dict(CfgNested, {\"sub_cfg\": {\"foo\": 1, \"bar\": 2}}))\n# CfgNested(sub_cfg=Cfg(foo=1, bar=2))\n```\n\n### Strict mode (default)\n\n* Convert everything to the target type, e.g. if the input is a list and the annotation is a tuple,\n  the output will be a tuple\n* Raise errors if types cannot be matched, there are unknown fields in the input or\n  abstract annotation types are used (e.g. Sequence)\n* Set `_allow_extra_keys = True` in the class definition to allow unknown fields in the input\n\n### Non-strict mode\n\nEnabled by calling `attrs_from_dict` with `strict=False`\n\n* No conversion except for creating the attrs instance from the dict\n* Ignore silently if types cannot be matched or abstract annotation types are used\n* Unknown fields in the input will be added to the attrs instance if possible\n  (see the hint below about slots)\n\n### Skip unknowns\n\nSet `skip_unknowns=True` to ignore all unknown input fields.\n\n### Hints\n\nThe following behaviour stems from the `attrs` package:\n\n* New attributes cannot to be added after class definition to an attrs instance,\n  unless it is created with `@define(slots=False)`\n  [Explanation](https://www.attrs.org/en/21.2.0/glossary.html#term-slotted-classes)\n* Untyped fields or \"ClassVar\" typed fields will be ignored by @attrs.define\n  and therefore also by this library.\n\n## Install locally and run tests\n\nClone repository and cd into. Setup python 3.7 or higher. \nNote: Some tests are skipped for python 3.7.\n\n```bash\npip install -e .\npip install pytest pytest-cov pylint\npylint typedparser\n\n# run tests\npython -m pytest --cov\npylint tests\n```\n",
    "bugtrack_url": null,
    "license": "Apache-2.0",
    "summary": "Extension for python argparse with typehints and typechecks.",
    "version": "0.22.2",
    "project_urls": {
        "Project-URL": "https://github.com/simon-ging/typedparser"
    },
    "split_keywords": [
        "attrs",
        " typing",
        " dict",
        " attr"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "eaad6ad3525ecf75652e4850b2b6b1782c0db814fef8c57a9f92cb312cefa37d",
                "md5": "a4d0e4a80d96753283e625a0b7ad58a7",
                "sha256": "60aabf821e070c45f1ed647c4ce90bec5a8e4edd0f391041e7c873eebfa59c3e"
            },
            "downloads": -1,
            "filename": "typedparser-0.22.2-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "a4d0e4a80d96753283e625a0b7ad58a7",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.8",
            "size": 21045,
            "upload_time": "2024-12-18T17:41:32",
            "upload_time_iso_8601": "2024-12-18T17:41:32.899208Z",
            "url": "https://files.pythonhosted.org/packages/ea/ad/6ad3525ecf75652e4850b2b6b1782c0db814fef8c57a9f92cb312cefa37d/typedparser-0.22.2-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "cd19ba5d90ec5e0aa2060937db6f2693c77975d7c2e3fc8b677fda95cf8ebd88",
                "md5": "17a228d8ffa9014bb904be9ab40e6dca",
                "sha256": "07517de48d402aac5c4cd403469f7bcd823c42d3ad2168452510c3a052409e41"
            },
            "downloads": -1,
            "filename": "typedparser-0.22.2.tar.gz",
            "has_sig": false,
            "md5_digest": "17a228d8ffa9014bb904be9ab40e6dca",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.8",
            "size": 21968,
            "upload_time": "2024-12-18T17:41:35",
            "upload_time_iso_8601": "2024-12-18T17:41:35.365271Z",
            "url": "https://files.pythonhosted.org/packages/cd/19/ba5d90ec5e0aa2060937db6f2693c77975d7c2e3fc8b677fda95cf8ebd88/typedparser-0.22.2.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-12-18 17:41:35",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "simon-ging",
    "github_project": "typedparser",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "requirements": [
        {
            "name": "attrs",
            "specs": []
        }
    ],
    "lcname": "typedparser"
}
        
Elapsed time: 0.43128s