Skip to content

Commit

Permalink
2017-07-14
Browse files Browse the repository at this point in the history
  • Loading branch information
MacHu-GWU committed Jul 14, 2017
1 parent f2ca11c commit a4ac142
Show file tree
Hide file tree
Showing 34 changed files with 8,755 additions and 445 deletions.
29 changes: 22 additions & 7 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -73,34 +73,49 @@ Example
id = 2
name = "beef"
food = Food()
You can visit it's data or child class data in these way:

.. code-block:: python
>>> Fruit.items() # .items() return it's data
# Use class
>>> Fruit.Items() # .Items() return it's data
[('id', 1), ('name', 'fruit')]
>>> Fruit.keys() # .keys() return keys
>>> Fruit.Keys() # .Keys() return keys
['id', 'name']
>>> Fruit.values() # .values() return values
>>> Fruit.Values() # .Values() return values
[1, 'fruit']
>>> Fruit.to_dict() # return data in a dict
>>> Fruit.ToDict() # return data in a dict
{'id': 1, 'name': 'fruit'}
# use instance
>>> food.items() # .Items() return it's data
[('id', 1), ('name', 'fruit')]
>>> food.keys() # .keys() return keys
['id', 'name']
>>> food.values() # .values() return values
[1, 'fruit']
>>> food.to_dict() # return data in a dict
{'id': 1, 'name': 'fruit'}
# iterate on all nested class
>>> Fruit.nested(sort_by='id')
>>> Fruit.Subclasses(sort_by='id')
[class Apple, class Banana]
# get first nested class that kls.id == 1
# useful when you need reverse lookup
>>> Fruit.get_first('id', 1)
>>> Fruit.GetFirst('id', 1)
class Apple
# get all child class that kls.id == 1
>>> Fruit.get_all('id', 1)
>>> Fruit.GetAll('id', 1)
[class Apple, ]
And it provides built-in I/O methods allow you to dump these data in to a dictionary.
Expand Down
2 changes: 1 addition & 1 deletion constant2/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
except:
pass

__version__ = "0.0.4"
__version__ = "0.0.5"
__short_description__ = "provide extensive way of managing your constant variable."
__license__ = "MIT"
__author__ = "Sanhe Hu"
178 changes: 132 additions & 46 deletions constant2/_constant2.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,17 @@
try:
from .pkg.pylru import lrudecorator
from .pkg.sixmini import integer_types, string_types, add_metaclass
from .pkg.inspect_mate import is_class_method, get_all_attributes
from .pkg.inspect_mate import (
is_class_method, is_regular_method, get_all_attributes,
)
from .pkg.pytest import approx
from .pkg.superjson import json
except:
from constant2.pkg.pylru import lrudecorator
from constant2.pkg.sixmini import integer_types, string_types, add_metaclass
from constant2.pkg.inspect_mate import is_class_method, get_all_attributes
from constant2.pkg.inspect_mate import (
is_class_method, is_regular_method, get_all_attributes,
)
from constant2.pkg.pytest import approx
from constant2.pkg.superjson import json

Expand All @@ -25,7 +29,12 @@
pass

_reserved_attrs = set([
"items", "keys", "values", "subclasses", "nested", "get_first", "get_all",
"Items", "Keys", "Values",
"items", "keys", "values",
"ToDict", "to_dict",
"Subclasses", "subclasses",
"GetFirst", "get_first",
"GetAll", "get_all",
"dump", "load", "pprint", "jprint",
])

Expand All @@ -35,12 +44,6 @@ class Meta(type):
"""
def __new__(cls, name, bases, attrs):
for attr, value in attrs.items():
# Make sure reserved attributes are not been override
if attr in _reserved_attrs:
if not isinstance(value, classmethod):
raise AttributeError(
"%r is not a valid attribute name" % attr)

# nested class has to inherit from type or object
# ``class MyClass:`` or ``class MyClass(object):``
if inspect.isclass(value):
Expand All @@ -52,6 +55,13 @@ def __new__(cls, name, bases, attrs):
attrs[attr] = kls

klass = super(Meta, cls).__new__(cls, name, bases, attrs)
for attr in attrs:
# Make sure reserved attributes are not been override
if attr in _reserved_attrs:
if not (is_class_method(klass, attr) or is_regular_method(klass, attr)):
raise AttributeError(
"%r is not a valid attribute name" % attr)

return klass


Expand All @@ -70,12 +80,12 @@ def __init__(self):
.. versionadded:: 0.0.3
"""
for attr, value in self.items():
for attr, value in self.__class__.Items():
value = deepcopy(value)
setattr(self, attr, value)

for attr, subclass in self.subclasses():
value = subclass()
for attr, Subclass in self.Subclasses():
value = Subclass()
setattr(self, attr, value)

self.__creation_index__ = Constant.__creation_index__
Expand All @@ -85,7 +95,7 @@ def __repr__(self):
items_str = ", ".join(["%s=%r" % (attr, value)
for attr, value in self.items()])
nested_str = ", ".join(
["%s=%r" % (attr, subclass()) for attr, subclass in self.subclasses()])
["%s=%r" % (attr, subclass) for attr, subclass in self.subclasses()])

l = list()
if items_str:
Expand All @@ -98,7 +108,7 @@ def __repr__(self):
classname=self.__class__.__name__, args=", ".join(l))

@classmethod
def items(cls):
def Items(cls):
"""non-class attributes ordered by alphabetical order.
"""
l = list()
Expand All @@ -110,30 +120,62 @@ def items(cls):
l.append((attr, value))
return l

def items(self):
"""non-class attributes ordered by alphabetical order.
"""
l = list()
for attr, _ in get_all_attributes(self.__class__):
value = getattr(self, attr)
try:
if not issubclass(value, Constant):
l.append((attr, value))
except:
l.append((attr, value))
return l

def __eq__(self, other):
return self.items() == other.items()

@classmethod
def keys(cls):
def Keys(cls):
"""All non-class attribute name list.
"""
return [attr for attr, _ in cls.items()]

def keys(self):
"""All non-class attribute name list.
"""
return [attr for attr, _ in self.items()]

@classmethod
def values(cls):
def Values(cls):
"""All non-class attribute value list.
"""
return [value for _, value in cls.items()]

def values(self):
"""All non-class attribute value list.
"""
return [value for _, value in self.items()]

@classmethod
def to_dict(cls):
def ToDict(cls):
"""Return regular class variable and it's value as a dictionary data.
"""
return dict(cls.items())

def to_dict(self):
"""Return regular class variable and it's value as a dictionary data.
"""
return dict(self.items())

@classmethod
def subclasses(cls, sort_by=None, reverse=False):
def Subclasses(cls, sort_by=None, reverse=False):
"""Get all nested Constant class and it's name pair.
:param sort_by:
:param reverse:
:param sort_by: the attribute name used for sorting.
:param reverse: if True, return in descend order.
:returns: [(attr, value),...] pairs.
.. versionadded:: 0.0.3
"""
Expand All @@ -153,39 +195,32 @@ def subclasses(cls, sort_by=None, reverse=False):

return l

@classmethod
def nested(cls, sort_by=None, reverse=False):
"""Get all nested Constant class, in alphabetical order.
def subclasses(self, sort_by=None, reverse=False):
"""Get all nested Constant class instance and it's name pair.
:param sort_by:
:param reverse:
:param sort_by: the attribute name used for sorting.
:param reverse: if True, return in descend order.
:returns: [(attr, value),...] pairs.
.. versionadded:: 0.0.4
"""
l = list()
for attr, value in get_all_attributes(cls):
try:
if issubclass(value, Constant):
l.append(value)
except:
pass

if sort_by is None:
sort_by = "__creation_index__"

l = list(
sorted(l, key=lambda x: getattr(x, sort_by), reverse=reverse))
for attr, _ in self.Subclasses(sort_by, reverse):
value = getattr(self, attr)
l.append((attr, value))
return l

@classmethod
@lrudecorator(size=32)
def get_first(cls, attr, value, e=0.000001, sort_by="__name__"):
"""Get the first nested Constantant class that met ``klass.attr == value``.
def GetFirst(cls, attr, value, e=0.000001, sort_by="__name__"):
"""Get the first nested Constant class that met ``klass.attr == value``.
:param attr: attribute name.
:param value: value.
:param e: used for float value comparison.
:param sort_by: nested class is ordered by <sort_by> attribute.
"""
for klass in cls.nested(sort_by=sort_by):
for _, klass in cls.Subclasses(sort_by=sort_by):
try:
if klass.__dict__[attr] == approx(value, e):
return klass
Expand All @@ -194,18 +229,36 @@ def get_first(cls, attr, value, e=0.000001, sort_by="__name__"):

return None

def get_first(self, attr, value, e=0.000001,
sort_by="__name__", reverse=False):
"""Get the first nested Constant class that met ``klass.attr == value``.
:param attr: attribute name.
:param value: value.
:param e: used for float value comparison.
:param sort_by: nested class is ordered by <sort_by> attribute.
"""
for _, klass in self.subclasses(sort_by, reverse):
try:
if getattr(klass, attr) == approx(value, e):
return klass
except:
pass

return None

@classmethod
@lrudecorator(size=32)
def get_all(cls, attr, value, e=0.000001, sort_by="__name__"):
"""Get all nested Constantant class that met ``klass.attr == value``.
def GetAll(cls, attr, value, e=0.000001, sort_by="__name__"):
"""Get all nested Constant class that met ``klass.attr == value``.
:param attr: attribute name.
:param value: value.
:param e: used for float value comparison.
:param sort_by: nested class is ordered by <sort_by> attribute.
"""
matched = list()
for klass in cls.nested(sort_by=sort_by):
for _, klass in cls.Subclasses(sort_by=sort_by):
try:
if klass.__dict__[attr] == approx(value, e):
matched.append(klass)
Expand All @@ -214,15 +267,34 @@ def get_all(cls, attr, value, e=0.000001, sort_by="__name__"):

return matched

def get_all(self, attr, value, e=0.000001,
sort_by="__name__", reverse=False):
"""Get all nested Constant class that met ``klass.attr == value``.
:param attr: attribute name.
:param value: value.
:param e: used for float value comparison.
:param sort_by: nested class is ordered by <sort_by> attribute.
"""
matched = list()
for _, klass in self.subclasses(sort_by, reverse):
try:
if getattr(klass, attr) == approx(value, e):
matched.append(klass)
except:
pass

return matched

@classmethod
def dump(cls):
"""Dump data into a dict.
.. versionadded:: 0.0.2
"""
d = OrderedDict(cls.items())
d = OrderedDict(cls.Items())
d["__classname__"] = cls.__name__
for attr, klass in cls.subclasses():
for attr, klass in cls.Subclasses():
d[attr] = klass.dump()
return OrderedDict([(cls.__name__, d)])

Expand Down Expand Up @@ -277,6 +349,12 @@ def is_same_dict(d1, d2):
else:
assert d1[k] == d2[k]

for k, v in d2.items():
if isinstance(v, dict):
is_same_dict(v, d1[k])
else:
assert d1[k] == d2[k]


if __name__ == "__main__":

Expand Down Expand Up @@ -322,4 +400,12 @@ class Beef:
id = 2
name = "beef"

Food.jprint()
food = Food()
# print(food.Fruit == getattr(food, "Fruit"))

# print(food.Fruit)
# print(food.subclasses())
# print(food.__dict__)
# print(food.Fruit.__dict__)
# print(type(food))
# print(inspect.isclass(food.Fruit))
Binary file added constant2/pkg/PY3.xlsx
Binary file not shown.
Loading

0 comments on commit a4ac142

Please sign in to comment.