# coding: utf-8
# pylint: disable=too-many-lines
import inspect
import sys
from typing import Any, Iterable, List, Optional, Sequence, TypeVar
from owlmixin import util
from owlmixin.errors import InvalidTypeError, RequiredError, UnknownPropertiesError
from owlmixin.owlcollections import TDict, TIterator, TList
# Avoid for breaking changes (import will be not working...)
from owlmixin.owlenum import (
OwlEnum,
OwlObjectEnum,
)
from owlmixin.transformers import (
DictTransformer,
JsonTransformer,
TOption,
ValueTransformer,
YamlTransformer,
traverse_dict, # Avoid for breaking changes (import will be not working...)
)
T = TypeVar("T", bound="OwlMixin")
def _is_generic(type_):
return hasattr(type_, "__origin__")
def assert_extra(cls_properties, arg_dict, cls):
extra_keys: set = set(arg_dict.keys()) - {n for n, t in cls_properties}
if extra_keys:
raise UnknownPropertiesError(cls=cls, props=sorted(extra_keys))
def assert_none(value, type_, cls, name):
if value is None:
raise RequiredError(cls=cls, prop=name, type_=type_)
def assert_types(value, types: tuple, cls, name):
if not isinstance(value, types):
raise InvalidTypeError(
cls=cls, prop=name, value=value, expected=types, actual=type(value)
)
def traverse(
type_, name, value, cls, force_snake_case: bool, force_cast: bool, restrict: bool
) -> Any:
# pylint: disable=too-many-return-statements,too-many-branches,too-many-arguments
if isinstance(type_, str):
type_ = sys.modules[cls.__module__].__dict__.get(type_)
if hasattr(type_, "__forward_arg__"):
# `_ForwardRef` (3.6) or `ForwardRef` (>= 3.7) includes __forward_arg__
# PEP 563 -- Postponed Evaluation of Annotations
type_ = sys.modules[cls.__module__].__dict__.get(type_.__forward_arg__)
if not _is_generic(type_):
assert_none(value, type_, cls, name)
if type_ is any:
return value
if type_ is Any:
return value
if isinstance(value, type_):
return value
if issubclass(type_, OwlMixin):
assert_types(value, (type_, dict), cls, name)
return type_.from_dict(
value,
force_snake_case=force_snake_case,
force_cast=force_cast,
restrict=restrict,
)
if issubclass(type_, ValueTransformer):
return type_.from_value(value)
if force_cast:
return type_(value)
assert_types(value, (type_,), cls, name)
return value
o_type = type_.__origin__
g_type = type_.__args__
if o_type == TList:
assert_none(value, type_, cls, name)
assert_types(value, (list,), cls, name)
return TList(
[
traverse(
g_type[0],
f"{name}.{i}",
v,
cls,
force_snake_case,
force_cast,
restrict,
)
for i, v in enumerate(value)
]
)
if o_type == TIterator:
assert_none(value, type_, cls, name)
assert_types(value, (Iterable,), cls, name)
return TIterator(
traverse(
g_type[0], f"{name}.{i}", v, cls, force_snake_case, force_cast, restrict
)
for i, v in enumerate(value)
)
if o_type == TDict:
assert_none(value, type_, cls, name)
assert_types(value, (dict,), cls, name)
return TDict(
{
k: traverse(
g_type[0],
f"{name}.{k}",
v,
cls,
force_snake_case,
force_cast,
restrict,
)
for k, v in value.items()
}
)
if o_type == TOption:
v = value.get() if isinstance(value, TOption) else value
# TODO: Fot `from_csvf`... need to more simple!!
if (isinstance(v, str) and v) or (not isinstance(v, str) and v is not None):
return TOption(
traverse(
g_type[0], name, v, cls, force_snake_case, force_cast, restrict
)
)
return TOption(None)
raise RuntimeError(f"This generics is not supported `{o_type}`")
class OwlMeta(type):
def __new__(cls, name, bases, class_dict):
ret_cls = type.__new__(cls, name, bases, class_dict)
ret_cls.__methods_dict__ = dict(inspect.getmembers(ret_cls, inspect.ismethod))
return ret_cls
[docs]class OwlMixin(DictTransformer, JsonTransformer, YamlTransformer, metaclass=OwlMeta):
[docs] @classmethod
def from_dict(
cls,
d: dict,
*,
force_snake_case: bool = True,
force_cast: bool = False,
restrict: bool = True,
) -> T:
"""From dict to instance
:param d: Dict
:param force_snake_case: Keys are transformed to snake case in order to compliant PEP8 if True
:param force_cast: Cast forcibly if True
:param restrict: Prohibit extra parameters if True
:return: Instance
Usage:
>>> from owlmixin.samples import Human, Food, Japanese
>>> human: Human = Human.from_dict({
... "id": 1,
... "name": "Tom",
... "favorites": [
... {"name": "Apple", "names_by_lang": {"en": "Apple", "de": "Apfel"}},
... {"name": "Orange"}
... ]
... })
>>> human.id
1
>>> human.name
'Tom'
>>> human.favorites[0].name
'Apple'
>>> human.favorites[0].names_by_lang.get()["de"]
'Apfel'
You can use default value
>>> taro: Japanese = Japanese.from_dict({
... "name": 'taro'
... }) # doctest: +NORMALIZE_WHITESPACE
>>> taro.name
'taro'
>>> taro.language
'japanese'
If you don't set `force_snake=False` explicitly, keys are transformed to snake case as following.
>>> human: Human = Human.from_dict({
... "--id": 1,
... "<name>": "Tom",
... "favorites": [
... {"name": "Apple", "namesByLang": {"en": "Apple"}}
... ]
... })
>>> human.id
1
>>> human.name
'Tom'
>>> human.favorites[0].names_by_lang.get()["en"]
'Apple'
You can allow extra parameters (like ``hogehoge``) if you set `restrict=False`.
>>> apple: Food = Food.from_dict({
... "name": "Apple",
... "hogehoge": "ooooooooooooooooooooo",
... }, restrict=False)
>>> apple.to_dict()
{'name': 'Apple'}
You can prohibit extra parameters (like ``hogehoge``) if you set `restrict=True` (which is default).
>>> human = Human.from_dict({
... "id": 1,
... "name": "Tom",
... "hogehoge1": "ooooooooooooooooooooo",
... "hogehoge2": ["aaaaaaaaaaaaaaaaaa", "iiiiiiiiiiiiiiiii"],
... "favorites": [
... {"name": "Apple", "namesByLang": {"en": "Apple", "de": "Apfel"}},
... {"name": "Orange"}
... ]
... }) # doctest: +NORMALIZE_WHITESPACE
Traceback (most recent call last):
...
owlmixin.errors.UnknownPropertiesError:
. ∧,,_∧ ,___________________
⊂ ( ・ω・ )つ- < Unknown properties error
/// /::/ `-------------------
|::|/⊂ヽノ|::|」
/ ̄ ̄旦 ̄ ̄ ̄/|
______/ | |
|------ー----ー|/
<BLANKLINE>
`owlmixin.samples.Human` has unknown properties ['hogehoge1', 'hogehoge2']!!
<BLANKLINE>
* If you want to allow unknown properties, set `restrict=False`
* If you want to disallow unknown properties, add `hogehoge1` and `hogehoge2` to owlmixin.samples.Human
<BLANKLINE>
If you specify wrong type...
>>> human: Human = Human.from_dict({
... "id": 1,
... "name": "ichiro",
... "favorites": ["apple", "orange"]
... }) # doctest: +NORMALIZE_WHITESPACE
Traceback (most recent call last):
...
owlmixin.errors.InvalidTypeError:
. ∧,,_∧ ,___________________
⊂ ( ・ω・ )つ- < Invalid Type error
/// /::/ `-------------------
|::|/⊂ヽノ|::|」
/ ̄ ̄旦 ̄ ̄ ̄/|
______/ | |
|------ー----ー|/
<BLANKLINE>
`owlmixin.samples.Human#favorites.0 = apple` doesn't match expected types.
Expected type is one of ["<class 'owlmixin.samples.Food'>", "<class 'dict'>"], but actual type is `<class 'str'>`
<BLANKLINE>
* If you want to force cast, set `force_cast=True`
* If you don't want to force cast, specify value which has correct type
<BLANKLINE>
If you don't specify required params... (ex. name
>>> human: Human = Human.from_dict({
... "id": 1
... }) # doctest: +NORMALIZE_WHITESPACE
Traceback (most recent call last):
...
owlmixin.errors.RequiredError:
. ∧,,_∧ ,___________________
⊂ ( ・ω・ )つ- < Required error
/// /::/ `-------------------
|::|/⊂ヽノ|::|」
/ ̄ ̄旦 ̄ ̄ ̄/|
______/ | |
|------ー----ー|/
<BLANKLINE>
`owlmixin.samples.Human#name: <class 'str'>` is empty!!
<BLANKLINE>
* If `name` is certainly required, specify anything.
* If `name` is optional, change type from `<class 'str'>` to `TOption[<class 'str'>]`
<BLANKLINE>
"""
if isinstance(d, cls):
return d
instance: T = cls() # type: ignore
d = util.replace_keys(d, {"self": "_self"}, force_snake_case)
properties = cls.__annotations__.items()
if restrict:
assert_extra(properties, d, cls)
for n, t in properties:
f = cls.__methods_dict__.get(f"_{cls.__name__}___{n}") # type: ignore
arg_v = f(d.get(n)) if f else d.get(n)
def_v = getattr(instance, n, None)
setattr(
instance,
n,
traverse(
type_=t,
name=n,
value=def_v if arg_v is None else arg_v,
cls=cls,
force_snake_case=force_snake_case,
force_cast=force_cast,
restrict=restrict,
),
)
return instance
[docs] @classmethod
def from_optional_dict(
cls,
d: Optional[dict],
*,
force_snake_case: bool = True,
force_cast: bool = False,
restrict: bool = True,
) -> TOption[T]:
"""From dict to optional instance.
:param d: Dict
:param force_snake_case: Keys are transformed to snake case in order to compliant PEP8 if True
:param force_cast: Cast forcibly if True
:param restrict: Prohibit extra parameters if True
:return: Instance
Usage:
>>> from owlmixin.samples import Human
>>> Human.from_optional_dict(None).is_none()
True
>>> Human.from_optional_dict({}).get() # doctest: +NORMALIZE_WHITESPACE
Traceback (most recent call last):
...
owlmixin.errors.RequiredError:
. ∧,,_∧ ,___________________
⊂ ( ・ω・ )つ- < Required error
/// /::/ `-------------------
|::|/⊂ヽノ|::|」
/ ̄ ̄旦 ̄ ̄ ̄/|
______/ | |
|------ー----ー|/
<BLANKLINE>
`owlmixin.samples.Human#id: <class 'int'>` is empty!!
<BLANKLINE>
* If `id` is certainly required, specify anything.
* If `id` is optional, change type from `<class 'int'>` to `TOption[<class 'int'>]`
<BLANKLINE>
"""
return TOption(
cls.from_dict(
d,
force_snake_case=force_snake_case,
force_cast=force_cast,
restrict=restrict,
)
if d is not None
else None
)
[docs] @classmethod
def from_dicts(
cls,
ds: List[dict],
*,
force_snake_case: bool = True,
force_cast: bool = False,
restrict: bool = True,
) -> TList[T]:
"""From list of dict to list of instance
:param ds: List of dict
:param force_snake_case: Keys are transformed to snake case in order to compliant PEP8 if True
:param force_cast: Cast forcibly if True
:param restrict: Prohibit extra parameters if True
:return: List of instance
Usage:
>>> from owlmixin.samples import Human
>>> humans: TList[Human] = Human.from_dicts([
... {"id": 1, "name": "Tom", "favorites": [{"name": "Apple"}]},
... {"id": 2, "name": "John", "favorites": [{"name": "Orange"}]}
... ])
>>> humans[0].name
'Tom'
>>> humans[1].name
'John'
"""
return TList(
[
cls.from_dict(
d,
force_snake_case=force_snake_case,
force_cast=force_cast,
restrict=restrict,
)
for d in ds
]
)
[docs] @classmethod
def from_iterable_dicts(
cls,
ds: Iterable[dict],
*,
force_snake_case: bool = True,
force_cast: bool = False,
restrict: bool = True,
) -> TIterator[T]:
"""From iterable dict to iterable instance
:param ds: Iterable dict
:param force_snake_case: Keys are transformed to snake case in order to compliant PEP8 if True
:param force_cast: Cast forcibly if True
:param restrict: Prohibit extra parameters if True
:return: Iterator
Usage:
>>> from owlmixin.samples import Human
>>> humans: TIterator[Human] = Human.from_iterable_dicts([
... {"id": 1, "name": "Tom", "favorites": [{"name": "Apple"}]},
... {"id": 2, "name": "John", "favorites": [{"name": "Orange"}]}
... ])
>>> humans.next_at(0).get().name
'Tom'
>>> humans.next_at(0).get().name
'John'
"""
return TIterator(
cls.from_dict(
d,
force_snake_case=force_snake_case,
force_cast=force_cast,
restrict=restrict,
)
for d in ds
)
[docs] @classmethod
def from_optional_dicts(
cls,
ds: Optional[List[dict]],
*,
force_snake_case: bool = True,
force_cast: bool = False,
restrict: bool = True,
) -> TOption[TList[T]]:
"""From list of dict to optional list of instance.
:param ds: List of dict
:param force_snake_case: Keys are transformed to snake case in order to compliant PEP8 if True
:param force_cast: Cast forcibly if True
:param restrict: Prohibit extra parameters if True
:return: List of instance
Usage:
>>> from owlmixin.samples import Human
>>> Human.from_optional_dicts(None).is_none()
True
>>> Human.from_optional_dicts([]).get()
[]
"""
return TOption(
cls.from_dicts(
ds,
force_snake_case=force_snake_case,
force_cast=force_cast,
restrict=restrict,
)
if ds is not None
else None
)
[docs] @classmethod
def from_optional_iterable_dicts(
cls,
ds: Optional[Iterable[dict]],
*,
force_snake_case: bool = True,
force_cast: bool = False,
restrict: bool = True,
) -> TOption[TIterator[T]]:
"""From iterable dict to optional iterable instance.
:param ds: Iterable dict
:param force_snake_case: Keys are transformed to snake case in order to compliant PEP8 if True
:param force_cast: Cast forcibly if True
:param restrict: Prohibit extra parameters if True
:return: Iterable instance
Usage:
>>> from owlmixin.samples import Human
>>> Human.from_optional_dicts(None).is_none()
True
>>> Human.from_optional_dicts([]).get()
[]
"""
return TOption(
cls.from_iterable_dicts(
ds,
force_snake_case=force_snake_case,
force_cast=force_cast,
restrict=restrict,
)
if ds is not None
else None
)
[docs] @classmethod
def from_dicts_by_key(
cls,
ds: dict,
*,
force_snake_case: bool = True,
force_cast: bool = False,
restrict: bool = True,
) -> TDict[T]:
"""From dict of dict to dict of instance
:param ds: Dict of dict
:param force_snake_case: Keys are transformed to snake case in order to compliant PEP8 if True
:param force_cast: Cast forcibly if True
:param restrict: Prohibit extra parameters if True
:return: Dict of instance
Usage:
>>> from owlmixin.samples import Human
>>> humans_by_name: TDict[Human] = Human.from_dicts_by_key({
... 'Tom': {"id": 1, "name": "Tom", "favorites": [{"name": "Apple"}]},
... 'John': {"id": 2, "name": "John", "favorites": [{"name": "Orange"}]}
... })
>>> humans_by_name['Tom'].name
'Tom'
>>> humans_by_name['John'].name
'John'
"""
return TDict(
{
k: cls.from_dict(
v,
force_snake_case=force_snake_case,
force_cast=force_cast,
restrict=restrict,
)
for k, v in ds.items()
}
)
[docs] @classmethod
def from_optional_dicts_by_key(
cls,
ds: Optional[dict],
*,
force_snake_case=True,
force_cast: bool = False,
restrict: bool = True,
) -> TOption[TDict[T]]:
"""From dict of dict to optional dict of instance.
:param ds: Dict of dict
:param force_snake_case: Keys are transformed to snake case in order to compliant PEP8 if True
:param force_cast: Cast forcibly if True
:param restrict: Prohibit extra parameters if True
:return: Dict of instance
Usage:
>>> from owlmixin.samples import Human
>>> Human.from_optional_dicts_by_key(None).is_none()
True
>>> Human.from_optional_dicts_by_key({}).get()
{}
"""
return TOption(
cls.from_dicts_by_key(
ds,
force_snake_case=force_snake_case,
force_cast=force_cast,
restrict=restrict,
)
if ds is not None
else None
)
[docs] @classmethod
def from_json(
cls,
data: str,
*,
force_snake_case=True,
force_cast: bool = False,
restrict: bool = False,
) -> T:
"""From json string to instance
:param data: Json string
:param force_snake_case: Keys are transformed to snake case in order to compliant PEP8 if True
:param force_cast: Cast forcibly if True
:param restrict: Prohibit extra parameters if True
:return: Instance
Usage:
>>> from owlmixin.samples import Human
>>> human: Human = Human.from_json('''{
... "id": 1,
... "name": "Tom",
... "favorites": [
... {"name": "Apple", "names_by_lang": {"en": "Apple", "de": "Apfel"}},
... {"name": "Orange"}
... ]
... }''')
>>> human.id
1
>>> human.name
'Tom'
>>> human.favorites[0].names_by_lang.get()["de"]
'Apfel'
"""
return cls.from_dict(
util.load_json(data),
force_snake_case=force_snake_case,
force_cast=force_cast,
restrict=restrict,
)
[docs] @classmethod
def from_jsonf(
cls,
fpath: str,
encoding: str = "utf8",
*,
force_snake_case=True,
force_cast: bool = False,
restrict: bool = False,
) -> T:
"""From json file path to instance
:param fpath: Json file path
:param encoding: Json file encoding
:param force_snake_case: Keys are transformed to snake case in order to compliant PEP8 if True
:param force_cast: Cast forcibly if True
:param restrict: Prohibit extra parameters if True
:return: Instance
"""
return cls.from_dict(
util.load_jsonf(fpath, encoding),
force_snake_case=force_snake_case,
force_cast=force_cast,
restrict=restrict,
)
[docs] @classmethod
def from_json_to_list(
cls,
data: str,
*,
force_snake_case=True,
force_cast: bool = False,
restrict: bool = False,
) -> TList[T]:
"""From json string to list of instance
:param data: Json string
:param force_snake_case: Keys are transformed to snake case in order to compliant PEP8 if True
:param force_cast: Cast forcibly if True
:param restrict: Prohibit extra parameters if True
:return: List of instance
Usage:
>>> from owlmixin.samples import Human
>>> humans: TList[Human] = Human.from_json_to_list('''[
... {"id": 1, "name": "Tom", "favorites": [{"name": "Apple"}]},
... {"id": 2, "name": "John", "favorites": [{"name": "Orange"}]}
... ]''')
>>> humans[0].name
'Tom'
>>> humans[1].name
'John'
"""
return cls.from_dicts(
util.load_json(data),
force_snake_case=force_snake_case,
force_cast=force_cast,
restrict=restrict,
)
[docs] @classmethod
def from_json_to_iterator(
cls,
data: str,
*,
force_snake_case=True,
force_cast: bool = False,
restrict: bool = False,
) -> TIterator[T]:
"""From json string to iterable instance
:param data: Json string
:param force_snake_case: Keys are transformed to snake case in order to compliant PEP8 if True
:param force_cast: Cast forcibly if True
:param restrict: Prohibit extra parameters if True
:return: Iterable instance
Usage:
>>> from owlmixin.samples import Human
>>> humans: TIterator[Human] = Human.from_json_to_iterator('''[
... {"id": 1, "name": "Tom", "favorites": [{"name": "Apple"}]},
... {"id": 2, "name": "John", "favorites": [{"name": "Orange"}]}
... ]''')
>>> humans.next_at(1).get().name
'John'
>>> humans.next_at(0).is_none()
True
"""
return cls.from_iterable_dicts(
util.load_json(data),
force_snake_case=force_snake_case,
force_cast=force_cast,
restrict=restrict,
)
[docs] @classmethod
def from_jsonf_to_list(
cls,
fpath: str,
encoding: str = "utf8",
*,
force_snake_case=True,
force_cast: bool = False,
restrict: bool = False,
) -> TList[T]:
"""From json file path to list of instance
:param fpath: Json file path
:param encoding: Json file encoding
:param force_snake_case: Keys are transformed to snake case in order to compliant PEP8 if True
:param force_cast: Cast forcibly if True
:param restrict: Prohibit extra parameters if True
:return: List of instance
"""
return cls.from_dicts(
util.load_jsonf(fpath, encoding),
force_snake_case=force_snake_case,
force_cast=force_cast,
restrict=restrict,
)
[docs] @classmethod
def from_jsonf_to_iterator(
cls,
fpath: str,
encoding: str = "utf8",
*,
force_snake_case=True,
force_cast: bool = False,
restrict: bool = False,
) -> TIterator[T]:
"""From json file path to iterable instance
:param fpath: Json file path
:param encoding: Json file encoding
:param force_snake_case: Keys are transformed to snake case in order to compliant PEP8 if True
:param force_cast: Cast forcibly if True
:param restrict: Prohibit extra parameters if True
:return: Iterable instance
"""
return cls.from_iterable_dicts(
util.load_jsonf(fpath, encoding),
force_snake_case=force_snake_case,
force_cast=force_cast,
restrict=restrict,
)
[docs] @classmethod
def from_yaml(
cls,
data: str,
*,
force_snake_case=True,
force_cast: bool = False,
restrict: bool = True,
) -> T:
"""From yaml string to instance
:param data: Yaml string
:param force_snake_case: Keys are transformed to snake case in order to compliant PEP8 if True
:param force_cast: Cast forcibly if True
:param restrict: Prohibit extra parameters if True
:return: Instance
Usage:
>>> from owlmixin.samples import Human
>>> human: Human = Human.from_yaml('''
... id: 1
... name: Tom
... favorites:
... - name: Apple
... names_by_lang:
... en: Apple
... de: Apfel
... - name: Orange
... ''')
>>> human.id
1
>>> human.name
'Tom'
>>> human.favorites[0].names_by_lang.get()["de"]
'Apfel'
"""
return cls.from_dict(
util.load_yaml(data),
force_snake_case=force_snake_case,
force_cast=force_cast,
restrict=restrict,
)
[docs] @classmethod
def from_yamlf(
cls,
fpath: str,
encoding: str = "utf8",
*,
force_snake_case=True,
force_cast: bool = False,
restrict: bool = True,
) -> T:
"""From yaml file path to instance
:param fpath: Yaml file path
:param encoding: Yaml file encoding
:param force_snake_case: Keys are transformed to snake case in order to compliant PEP8 if True
:param force_cast: Cast forcibly if True
:param restrict: Prohibit extra parameters if True
:return: Instance
"""
return cls.from_dict(
util.load_yamlf(fpath, encoding),
force_snake_case=force_snake_case,
force_cast=force_cast,
restrict=restrict,
)
[docs] @classmethod
def from_yaml_to_list(
cls,
data: str,
*,
force_snake_case=True,
force_cast: bool = False,
restrict: bool = True,
) -> TList[T]:
"""From yaml string to list of instance
:param data: Yaml string
:param force_snake_case: Keys are transformed to snake case in order to compliant PEP8 if True
:param force_cast: Cast forcibly if True
:param restrict: Prohibit extra parameters if True
:return: List of instance
Usage:
>>> from owlmixin.samples import Human
>>> humans: TList[Human] = Human.from_yaml_to_list('''
... - id: 1
... name: Tom
... favorites:
... - name: Apple
... - id: 2
... name: John
... favorites:
... - name: Orange
... ''')
>>> humans[0].name
'Tom'
>>> humans[1].name
'John'
>>> humans[0].favorites[0].name
'Apple'
"""
return cls.from_dicts(
util.load_yaml(data),
force_snake_case=force_snake_case,
force_cast=force_cast,
restrict=restrict,
)
[docs] @classmethod
def from_yaml_to_iterator(
cls,
data: str,
*,
force_snake_case=True,
force_cast: bool = False,
restrict: bool = True,
) -> TIterator[T]:
"""From yaml string to iterable instance
:param data: Yaml string
:param force_snake_case: Keys are transformed to snake case in order to compliant PEP8 if True
:param force_cast: Cast forcibly if True
:param restrict: Prohibit extra parameters if True
:return: Iterable instance
Usage:
>>> from owlmixin.samples import Human
>>> humans: TIterator[Human] = Human.from_yaml_to_iterator('''
... - id: 1
... name: Tom
... favorites:
... - name: Apple
... - id: 2
... name: John
... favorites:
... - name: Orange
... ''')
>>> human1 = humans.next_at(1).get()
>>> human1.name
'John'
>>> humans.next_at(0).is_none()
True
>>> human1.favorites[0].name
'Orange'
"""
return cls.from_iterable_dicts(
util.load_yaml(data),
force_snake_case=force_snake_case,
force_cast=force_cast,
restrict=restrict,
)
[docs] @classmethod
def from_yamlf_to_list(
cls,
fpath: str,
encoding: str = "utf8",
*,
force_snake_case=True,
force_cast: bool = False,
restrict: bool = True,
) -> TList[T]:
"""From yaml file path to list of instance
:param fpath: Yaml file path
:param encoding: Yaml file encoding
:param force_snake_case: Keys are transformed to snake case in order to compliant PEP8 if True
:param force_cast: Cast forcibly if True
:param restrict: Prohibit extra parameters if True
:return: List of instance
"""
return cls.from_dicts(
util.load_yamlf(fpath, encoding),
force_snake_case=force_snake_case,
force_cast=force_cast,
restrict=restrict,
)
[docs] @classmethod
def from_yamlf_to_iterator(
cls,
fpath: str,
encoding: str = "utf8",
*,
force_snake_case=True,
force_cast: bool = False,
restrict: bool = True,
) -> TIterator[T]:
"""From yaml file path to iterable instance
:param fpath: Yaml file path
:param encoding: Yaml file encoding
:param force_snake_case: Keys are transformed to snake case in order to compliant PEP8 if True
:param force_cast: Cast forcibly if True
:param restrict: Prohibit extra parameters if True
:return: Iterable instance
"""
return cls.from_iterable_dicts(
util.load_yamlf(fpath, encoding),
force_snake_case=force_snake_case,
force_cast=force_cast,
restrict=restrict,
)
[docs] @classmethod
def from_csvf_to_list(
cls,
fpath: str,
fieldnames: Optional[Sequence[str]] = None,
encoding: str = "utf8",
*,
force_snake_case: bool = True,
restrict: bool = True,
) -> TList[T]:
"""From csv file path to list of instance
:param fpath: Csv file path
:param fieldnames: Specify csv header names if not included in the file
:param encoding: Csv file encoding
:param force_snake_case: Keys are transformed to snake case in order to compliant PEP8 if True
:param restrict: Prohibit extra parameters if True
:return: List of Instance
"""
return cls.from_dicts(
list(util.load_csvf(fpath, fieldnames, encoding)),
force_snake_case=force_snake_case,
force_cast=True,
restrict=restrict,
)
[docs] @classmethod
def from_csvf_to_iterator(
cls,
fpath: str,
fieldnames: Optional[Sequence[str]] = None,
encoding: str = "utf8",
*,
force_snake_case: bool = True,
restrict: bool = True,
) -> TIterator[T]:
"""From csv file path to iterable instance
:param fpath: Csv file path
:param fieldnames: Specify csv header names if not included in the file
:param encoding: Csv file encoding
:param force_snake_case: Keys are transformed to snake case in order to compliant PEP8 if True
:param restrict: Prohibit extra parameters if True
:return: Iterable Instance
"""
return cls.from_iterable_dicts(
util.load_csvf(fpath, fieldnames, encoding),
force_snake_case=force_snake_case,
force_cast=True,
restrict=restrict,
)
[docs] @classmethod
def from_json_url(
cls,
url: str,
*,
force_snake_case=True,
force_cast: bool = False,
restrict: bool = False,
) -> T:
"""From url which returns json to instance
:param url: Url which returns json
:param force_snake_case: Keys are transformed to snake case in order to compliant PEP8 if True
:param force_cast: Cast forcibly if True
:param restrict: Prohibit extra parameters if True
:return: Instance
"""
return cls.from_dict(
util.load_json_url(url),
force_snake_case=force_snake_case,
force_cast=force_cast,
restrict=restrict,
)