Source code for pcapkit.corekit.infoclass
# -*- coding: utf-8 -*-
"""info class
:mod:`pcapkit.corekit.infoclass` contains :obj:`dict` like class
:class:`~pcapkit.corekit.infoclass.Info` only, which is originally
designed to work alike :func:`dataclasses.dataclass` as introduced
in :pep:`557`.
"""
import collections.abc
import copy
from pcapkit.utilities.exceptions import UnsupportedCall
from pcapkit.utilities.validations import dict_check
__all__ = ['Info']
[docs]class Info(collections.abc.Mapping):
"""Turn dictionaries into :obj:`object` like instances.
Notes:
* :class:`Info` objects inherit from :obj:`dict` type
* :class:`Info` objects are *iterable*, and support all functions as :obj:`dict`
* :class:`Info` objects are **one-time-modeling**, thus cannot set or delete
attributes after initialisation
"""
[docs] def __new__(cls, dict_=None, **kwargs):
"""Create a new instance.
Args:
dict_ (Dict[str, Any]): Source :obj:`dict` data.
Keyword Args:
**kwargs: Arbitrary keyword arguments.
Notes:
Keys with the same names as the builtin methods will be renamed
with ``2`` suffix implicitly and internally.
"""
def __read__(dict_):
__dict__ = dict()
for (key, value) in dict_.items():
if key in self.__data__:
key = f'{key}2'
if isinstance(value, dict):
__dict__[key] = Info(value)
else:
# if isinstance(key, str):
# key = re.sub(r'\W', '_', key)
__dict__[key] = value
return __dict__
temp = list()
for obj in cls.mro():
temp.extend(dir(obj))
cls.__data__ = set(temp)
self = super().__new__(cls)
if dict_ is not None:
if isinstance(dict_, Info):
self = copy.deepcopy(dict_)
else:
dict_check(dict_)
self.__dict__.update(__read__(dict_))
self.__dict__.update(__read__(kwargs))
return self
def __str__(self):
temp = list()
for (key, value) in self.__dict__.items():
temp.append(f'{key}={value}')
args = ', '.join(temp)
return f'Info({args})'
def __repr__(self):
temp = list()
for (key, value) in self.__dict__.items():
if isinstance(value, Info):
temp.append(f'{key}=Info(...)')
else:
temp.append(f'{key}={value!r}')
args = ', '.join(temp)
return f"Info({args})"
def __len__(self):
return len(self.__dict__)
def __iter__(self):
return iter(self.__dict__)
def __getitem__(self, key):
if key in self.__data__:
key = f'{key}2'
value = self.__dict__[key]
if isinstance(value, (dict, collections.abc.Mapping)):
return Info(value)
return value
def __setattr__(self, name, value):
raise UnsupportedCall("can't set attribute")
def __delattr__(self, name):
raise UnsupportedCall("can't delete attribute")
[docs] def info2dict(self):
"""Convert :class:`Info` into :obj:`dict`.
Returns:
Dict[str, Any]: Converted :obj:`dict`.
"""
dict_ = dict()
for (key, value) in self.__dict__.items():
if isinstance(value, Info):
dict_[key] = value.info2dict()
elif isinstance(value, (tuple, list, set, frozenset)):
temp = list()
for item in value:
if isinstance(item, Info):
temp.append(item.info2dict())
else:
temp.append(item)
dict_[key] = value.__class__(temp)
else:
dict_[key] = value
return dict_