-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: new Variable is parsed from @var_property
- Loading branch information
Showing
5 changed files
with
628 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,129 @@ | ||
"""var_property decorator module""" | ||
|
||
from typing import ( | ||
List, | ||
Any, | ||
Callable, | ||
Optional, | ||
) | ||
|
||
|
||
class var_property: | ||
"""var_property decorator that defines property for dictrule.Variable. | ||
Examples: | ||
--------- | ||
>>> class Person: | ||
... @var_property | ||
... def name(self) -> str: | ||
... return "Zooxy" | ||
... def age(self) -> int: | ||
... return 20 | ||
>>> var = dictrule.Variable.from_object(Person()) | ||
>>> print(isinstance(var, Variable)) | ||
True | ||
>>> print(var.name) | ||
Zooxy | ||
>>> print(var.age) | ||
20 | ||
""" | ||
|
||
def __init__( | ||
self, | ||
fget: Optional[Callable[[Any], Any]] = None, | ||
fset: Optional[Callable[[Any, Any], None]] = None, | ||
fdel: Optional[Callable[[Any], None]] = None, | ||
doc: Optional[str] = None, | ||
): | ||
"""var_property decorator | ||
Args: | ||
fget (Optional[Callable[[Any], Any]], optional): Getter method. Defaults to None. | ||
fset (Optional[Callable[[Any, Any], None]], optional): Setter method. Defaults to None. | ||
fdel (Optional[Callable[[Any], None]], optional): Delete method. Defaults to None. | ||
doc (Optional[str], optional): Document string. Defaults to None. | ||
""" | ||
|
||
self.fget = fget | ||
self.fset = fset | ||
self.fdel = fdel | ||
if doc is None and fget is not None: | ||
doc = fget.__doc__ | ||
self.__doc__ = doc | ||
self.__name__ = fget.__name__ | ||
|
||
def __get__(self, obj, objtype=None): | ||
if obj is None: | ||
return self | ||
if self.fget is None: | ||
raise AttributeError("unreadable attribute") | ||
return self.fget(obj) | ||
|
||
def __set__(self, obj, value): | ||
if self.fset is None: | ||
raise AttributeError("can't set attribute") | ||
self.fset(obj, value) | ||
|
||
def __delete__(self, obj): | ||
if self.fdel is None: | ||
raise AttributeError("can't delete attribute") | ||
self.fdel(obj) | ||
|
||
def getter(self, fget): | ||
"""Getter decorator | ||
Examples: | ||
--------- | ||
>>> class Sample: | ||
... @var_property | ||
... def name(self): | ||
... return "Zooxy" | ||
>>> Sample().name | ||
Zooxy | ||
""" | ||
return type(self)(fget, self.fset, self.fdel, self.__doc__) | ||
|
||
def setter(self, fset): | ||
"""Setter decorator | ||
Examples: | ||
--------- | ||
>>> @name.setter | ||
... def name(self, value: Any): | ||
... self._name = value | ||
""" | ||
return type(self)(self.fget, fset, self.fdel, self.__doc__) | ||
|
||
def deleter(self, fdel): | ||
"""Deleter decorator | ||
Examples: | ||
--------- | ||
>>> @name.deleter | ||
... def name(self): | ||
... del self._name | ||
""" | ||
return type(self)(self.fget, self.fset, fdel, self.__doc__) | ||
|
||
@classmethod | ||
def properties( | ||
cls, | ||
instance: Any, | ||
) -> List[Callable[[Any], Any]]: | ||
"""Fetches all `var_property` of `instance`. | ||
Args: | ||
instance (Any): Instance using `var_property`. | ||
Returns: | ||
List[Callable]: List of `var_property` functions | ||
""" | ||
properties: List[Callable] = [] | ||
for name in dir(instance.__class__): | ||
attr = getattr(instance.__class__, name, None) | ||
is_prop = isinstance(attr, var_property) | ||
if not is_prop: | ||
continue | ||
|
||
properties.append(attr) | ||
return properties |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,191 @@ | ||
"""Variable module""" | ||
|
||
from typing import ( | ||
Any, | ||
List, | ||
Dict, | ||
Set, | ||
Optional, | ||
) | ||
|
||
from .var_property import var_property | ||
|
||
|
||
class Variable: | ||
"""Parses instances with nested values. | ||
Supported value types: | ||
- An item in Variable.PRIMITIVE_TYPES: [ | ||
int, | ||
float, | ||
str, | ||
] | ||
- list | ||
- set | ||
- dict | ||
- Variable | ||
Examples: | ||
--------- | ||
>>> class Sample: | ||
... @var_property | ||
... def name(self) -> str: | ||
... return "Zooxy" | ||
... def age(self) -> int: | ||
... return 20 | ||
>>> var = Variable.from_var_property_object(Sample()) | ||
>>> print(var.name) | ||
Zooxy | ||
>>> print(hasattr(var, "age")) | ||
False | ||
""" | ||
|
||
PRIMITIVE_TYPES = set( | ||
[ | ||
int, | ||
float, | ||
str, | ||
] | ||
) | ||
|
||
@staticmethod | ||
def from_var_property_object( | ||
obj: Any, | ||
) -> "Variable": | ||
"""Parses a Variable from obj where properties are decorated with @var_property. | ||
Args: | ||
obj (Any): The object to parse from @var_property and supported values. | ||
Returns: | ||
Variable: The parsed variable. | ||
""" | ||
|
||
return Variable._parse_value(obj) | ||
|
||
def add_object( | ||
self, | ||
obj: Any, | ||
name: str, | ||
): | ||
"""Adds a new object to the Variable instance with a given name. | ||
Args: | ||
obj (Any): The object to be added. | ||
name (str): The name for the object. | ||
""" | ||
|
||
value = self._parse_value(obj) | ||
setattr(self, name, value) | ||
|
||
@staticmethod | ||
def _parse_value( | ||
value: Any, | ||
) -> Optional[Any]: | ||
"""Parses supported values. | ||
Args: | ||
value (Any): The supported value. | ||
Returns: | ||
Optional[Any]: The parsed value. | ||
""" | ||
|
||
if value is None: | ||
return | ||
|
||
parsed_value = None | ||
if type(value) in Variable.PRIMITIVE_TYPES or isinstance(value, Variable): | ||
parsed_value = value | ||
elif isinstance(value, list): | ||
parsed_value = Variable._parse_list( | ||
value=value, | ||
) | ||
elif isinstance(value, set): | ||
parsed_value = Variable._parse_set( | ||
value=value, | ||
) | ||
elif isinstance(value, dict): | ||
parsed_value = Variable._parse_dict( | ||
value=value, | ||
) | ||
else: | ||
attrs = var_property.properties(value) | ||
if not attrs: | ||
return None | ||
|
||
parsed_value = Variable() | ||
for attr in attrs: | ||
setattr(parsed_value, attr.__name__, attr.__get__(value)) | ||
|
||
return parsed_value | ||
|
||
@staticmethod | ||
def _parse_list( | ||
value: List[Any], | ||
): | ||
"""Parses a list value. | ||
Args: | ||
value (List[Any]): The list of values. | ||
Returns: | ||
Optional[List[Any]]: The parsed list. | ||
""" | ||
|
||
new_list: List[Any] = [] | ||
for v in value: | ||
parsed_value = Variable._parse_value(v) | ||
if parsed_value: | ||
new_list.append(parsed_value) | ||
return new_list | ||
|
||
@staticmethod | ||
def _parse_set( | ||
value: Set[Any], | ||
): | ||
"""Parses a set value. | ||
Args: | ||
value (Set[Any]): The set of values. | ||
Returns: | ||
Optional[Set[Any]]: The parsed set. | ||
""" | ||
|
||
new_set: Set[Any] = set() | ||
for v in value: | ||
parsed_value = Variable._parse_value(v) | ||
if not parsed_value: | ||
continue | ||
|
||
new_set.add(parsed_value) | ||
|
||
return new_set | ||
|
||
@staticmethod | ||
def _parse_dict( | ||
value: Dict[Any, Any], | ||
): | ||
"""Parses a dictionary value. | ||
Args: | ||
value (Dict[Any, Any]): The dictionary of values. | ||
Returns: | ||
Optional[Dict[str, Any]]: The parsed dictionary. | ||
""" | ||
|
||
new_dict: Dict[str, Any] = {} | ||
for k, v in value.items(): | ||
parsed_key = Variable._parse_value(k) | ||
if not parsed_key: | ||
continue | ||
|
||
parsed_value = Variable._parse_value(v) | ||
if not parsed_value: | ||
continue | ||
|
||
new_dict[parsed_key] = parsed_value | ||
|
||
return new_dict |
Oops, something went wrong.