# typedattr
<p align="center">
<a href="https://github.com/gingsi/typedattr/actions/workflows/build_py37.yml">
<img alt="build 3.7 status" title="build 3.7 status" src="https://img.shields.io/github/actions/workflow/status/gingsi/typedattr/build_py37.yml?branch=main&label=build%203.7" />
</a>
<a href="https://github.com/gingsi/typedattr/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/gingsi/typedattr/build_py39.yml?branch=main&label=build%203.9" />
</a>
<img alt="coverage" title="coverage" src="https://raw.githubusercontent.com/gingsi/typedattr/main/docs/coverage.svg" />
<a href="https://pypi.org/project/typedattr/">
<img alt="version" title="version" src="https://img.shields.io/pypi/v/typedattr?color=success" />
</a>
</p>
Typechecking and conversion utility for [attrs](https://www.attrs.org/en/stable/)
Parses a dictionary into an attrs instance.
Contains other generic object, type and cache utilities.
## Install
Requires `python>=3.7`
Note: `0.2` breaks some backwards compatibility. Use `0.1` or update your code.
```bash
pip install typedattr
```
## Quickstart
Define the class hierarchy and parse the input using `attrs_from_dict`:
~~~python
from attrs import define
from typing import Optional
from typedattr 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))
~~~
## Features
* 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
### 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)
### 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.
### Other utilities in the package
* `Const`: An alternative to `enum.Enum` for defining constants
* `cacheutils`: Cache objects to disk / to memory
* `objutils`: Various utilities like nested modification of dicts
* Type definitions and other utilities
## Install locally and run tests
Clone repository and cd into, then:
~~~bash
pip install -e .
pip install -U pytest pytest-cov pylint
pylint typedattr
# run tests for python>=3.7
python -m pytest --cov
pylint tests
# run tests for python>=3.9
python -m pytest tests tests_py39 --cov
pylint tests
pylint tests_py39
~~~
## Alternatives
This library should be useful for off-the-shelf typechecking and conversion of dicts to
attrs instances.
For more complex or other related use cases there are many alternatives:
`cattrs`, `attrs-strict`, `pydantic`, `dataconf`, `omegaconf` to name a few.
Raw data
{
"_id": null,
"home_page": "",
"name": "typedattr",
"maintainer": "",
"docs_url": null,
"requires_python": ">=3.7",
"maintainer_email": "",
"keywords": "attrs,typing,dict,attr",
"author": "gingsi",
"author_email": "",
"download_url": "https://files.pythonhosted.org/packages/54/18/bc84ccd46474fe2112e6b3c40eec373c04baaae9ef3ea27b8faac9689bf0/typedattr-0.2.5.tar.gz",
"platform": "any",
"description": "# typedattr\n\n<p align=\"center\">\n<a href=\"https://github.com/gingsi/typedattr/actions/workflows/build_py37.yml\">\n <img alt=\"build 3.7 status\" title=\"build 3.7 status\" src=\"https://img.shields.io/github/actions/workflow/status/gingsi/typedattr/build_py37.yml?branch=main&label=build%203.7\" />\n</a>\n<a href=\"https://github.com/gingsi/typedattr/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/gingsi/typedattr/build_py39.yml?branch=main&label=build%203.9\" />\n</a>\n<img alt=\"coverage\" title=\"coverage\" src=\"https://raw.githubusercontent.com/gingsi/typedattr/main/docs/coverage.svg\" />\n<a href=\"https://pypi.org/project/typedattr/\">\n <img alt=\"version\" title=\"version\" src=\"https://img.shields.io/pypi/v/typedattr?color=success\" />\n</a>\n</p>\n\nTypechecking and conversion utility for [attrs](https://www.attrs.org/en/stable/)\n\nParses a dictionary into an attrs instance.\nContains other generic object, type and cache utilities.\n\n## Install\n\nRequires `python>=3.7`\n\nNote: `0.2` breaks some backwards compatibility. Use `0.1` or update your code. \n\n```bash\npip install typedattr\n```\n\n## Quickstart\n\nDefine the class hierarchy and parse the input using `attrs_from_dict`:\n\n~~~python\nfrom attrs import define\nfrom typing import Optional\nfrom typedattr 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## Features\n\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\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\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### Other utilities in the package \n\n* `Const`: An alternative to `enum.Enum` for defining constants\n* `cacheutils`: Cache objects to disk / to memory\n* `objutils`: Various utilities like nested modification of dicts\n* Type definitions and other utilities\n\n## Install locally and run tests\n\nClone repository and cd into, then:\n\n~~~bash\npip install -e .\npip install -U pytest pytest-cov pylint\npylint typedattr\n\n# run tests for python>=3.7\npython -m pytest --cov\npylint tests\n\n# run tests for python>=3.9\npython -m pytest tests tests_py39 --cov\npylint tests \npylint tests_py39\n~~~\n\n## Alternatives\n\nThis library should be useful for off-the-shelf typechecking and conversion of dicts to\nattrs instances.\n\nFor more complex or other related use cases there are many alternatives:\n`cattrs`, `attrs-strict`, `pydantic`, `dataconf`, `omegaconf` to name a few.\n",
"bugtrack_url": null,
"license": "Apache-2.0",
"summary": "Typed conversion of dictionaries to attrs instances",
"version": "0.2.5",
"project_urls": {
"Project-URL": "https://github.com/gingsi/typedattr"
},
"split_keywords": [
"attrs",
"typing",
"dict",
"attr"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "4a552f39629ff7d5f2c5dfacbe0ef8ca637b376359759026fc8ff13c0c08869e",
"md5": "695e3c9e44e7d10306beb7eae9213a1b",
"sha256": "fb1873646f98774ee8cd0b8aa0c3ef205f481722e122be0674b648694f68419c"
},
"downloads": -1,
"filename": "typedattr-0.2.5-py3-none-any.whl",
"has_sig": false,
"md5_digest": "695e3c9e44e7d10306beb7eae9213a1b",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.7",
"size": 24282,
"upload_time": "2023-06-20T10:24:28",
"upload_time_iso_8601": "2023-06-20T10:24:28.679173Z",
"url": "https://files.pythonhosted.org/packages/4a/55/2f39629ff7d5f2c5dfacbe0ef8ca637b376359759026fc8ff13c0c08869e/typedattr-0.2.5-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "5418bc84ccd46474fe2112e6b3c40eec373c04baaae9ef3ea27b8faac9689bf0",
"md5": "c2383ee354f93e7bc2306102ffcac470",
"sha256": "d93b34f6140dc4bb19542dd1ffb8639c53e59cb096987bb08c8623b7598f3f17"
},
"downloads": -1,
"filename": "typedattr-0.2.5.tar.gz",
"has_sig": false,
"md5_digest": "c2383ee354f93e7bc2306102ffcac470",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.7",
"size": 23433,
"upload_time": "2023-06-20T10:24:30",
"upload_time_iso_8601": "2023-06-20T10:24:30.208857Z",
"url": "https://files.pythonhosted.org/packages/54/18/bc84ccd46474fe2112e6b3c40eec373c04baaae9ef3ea27b8faac9689bf0/typedattr-0.2.5.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2023-06-20 10:24:30",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "gingsi",
"github_project": "typedattr",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"requirements": [
{
"name": "attrs",
"specs": []
},
{
"name": "numpy",
"specs": []
},
{
"name": "joblib",
"specs": []
},
{
"name": "importlib_resources",
"specs": []
},
{
"name": "loguru",
"specs": []
}
],
"lcname": "typedattr"
}