From 9ee687a6d123c294a3978d4d0b32c78062a44fce Mon Sep 17 00:00:00 2001 From: Dan Kobina Date: Thu, 28 Feb 2019 23:30:02 -0500 Subject: [PATCH] basic attrs wrapper for nested parsing --- .gitignore | 1 + README.md | 7 +++++ jstruct/__init__.py | 6 +++++ jstruct/types.py | 62 +++++++++++++++++++++++++++++++++++++++++++++ setup.py | 14 ++++++++++ 5 files changed, 90 insertions(+) create mode 100644 jstruct/__init__.py create mode 100644 jstruct/types.py create mode 100644 setup.py diff --git a/.gitignore b/.gitignore index 894a44c..1761287 100644 --- a/.gitignore +++ b/.gitignore @@ -102,3 +102,4 @@ venv.bak/ # mypy .mypy_cache/ +.vscode/ \ No newline at end of file diff --git a/README.md b/README.md index 542a6e0..86780df 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,9 @@ # jstruct + JSON to struct to JSON + +## Installation + +```bash +pip install -f https://git.io/purplship jstruct +``` diff --git a/jstruct/__init__.py b/jstruct/__init__.py new file mode 100644 index 0000000..7681455 --- /dev/null +++ b/jstruct/__init__.py @@ -0,0 +1,6 @@ +from jstruct.types import ( + JStruct, + JList, + JDict, + REQUIRED +) diff --git a/jstruct/types.py b/jstruct/types.py new file mode 100644 index 0000000..49d03fc --- /dev/null +++ b/jstruct/types.py @@ -0,0 +1,62 @@ +import attr +from functools import reduce +from typing import List, Dict + + +REQUIRED = True + + +@attr.s(auto_attribs=True) +class _JStruct: + def __getitem__(self, arguments): + class_, required_, *kwargs = arguments if isinstance(arguments, tuple) else (arguments, False) + + def build(args) -> class_: + return class_(**args) if isinstance(args, dict) else args + default_ = dict(default=attr.NOTHING if required_ else None) + return attr.ib( + **default_, + converter=build, + **dict(reduce(lambda r, d: r + list(d.items()), kwargs, [])) + ) + + +@attr.s(auto_attribs=True) +class _JList: + def __getitem__(self, arguments): + class_, required_, *kwargs = arguments if isinstance(arguments, tuple) else (arguments, False) + + def build(args) -> List[class_]: + if isinstance(args, list): + items = args + else: + items = [args] + return [ + (class_(**item) if isinstance(item, dict) else item) + for item in items + ] + default_ = dict(default=attr.NOTHING if required_ else []) + return attr.ib( + **default_, + converter=build, + **dict(reduce(lambda r, d: r + list(d.items()), kwargs, [])) + ) + + +@attr.s(auto_attribs=True) +class _JDict: + def __getitem__(self, arguments): + key_type, value_type, required_, *kwargs = arguments if isinstance(arguments, tuple) else (arguments, False) + + def build(args) -> Dict[key_type, value_type]: + return { + key_type(key): (value_type(**value) if isinstance(value, dict) else value) + for (key, value) in args.items() + } + default_ = dict(default=attr.NOTHING if required_ else {}) + return attr.ib(**default_, converter=build, **kwargs) + + +JStruct = _JStruct() +JList = _JList() +JDict = _JDict() diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..bca7c77 --- /dev/null +++ b/setup.py @@ -0,0 +1,14 @@ +from setuptools import setup + +setup(name='jstruct', + version='1.0.0', + description='Elegant JSON to python Data class', + url='https://github.com/DanH91/jstruct', + author='DanH91', + author_email='danielk.developer@gmail.com', + license='MIT', + packages=['jstruct'], + install_requires=[ + 'attrs==18.2.0' + ], + zip_safe=False) \ No newline at end of file