Skip to content

Commit

Permalink
0.0.13 release
Browse files Browse the repository at this point in the history
  • Loading branch information
MacHu-GWU committed Dec 19, 2018
1 parent 1a6ba4a commit ccf7e14
Show file tree
Hide file tree
Showing 9 changed files with 305 additions and 20 deletions.
4 changes: 3 additions & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,12 @@
Welcome to ``constant2`` Documentation
==============================================================================

If you have lots of constant2 value widely used across your development. A better way is to define ``Constantant Variable`` rather than using the raw value. This can improve the readability.
If you have lots of constant2 value widely used across your development. A better way is to define ``Constantant Variable`` rather than using the raw value. This can improve the readability and accessibility.

``constant2`` is a library provide extensive way of managing your constant2 variable.

**Another powerful feature** is, ``constant2`` allows developer defines normalized entity relationship and is data in ``class`` style, which giving awesome accessibility to every single row, and every single column, free developer from memorizing things.


Quick Links
------------------------------------------------------------------------------
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: # pragma: no cover
pass

__version__ = "0.0.12"
__version__ = "0.0.13"
__short_description__ = "provide extensive way of managing your constant variable."
__license__ = "MIT"
__author__ = "Sanhe Hu"
Expand Down
119 changes: 107 additions & 12 deletions constant2/_constant2.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-

from __future__ import print_function
from __future__ import print_function, unicode_literals
import inspect
from copy import deepcopy
from pprint import pprint
Expand Down Expand Up @@ -259,7 +259,7 @@ def subclasses(self, sort_by=None, reverse=False):
return l

@classmethod
@lrudecorator(size=32)
@lrudecorator(size=64)
def GetFirst(cls, attr, value, e=0.000001, sort_by="__name__"):
"""Get the first nested Constant class that met ``klass.attr == value``.
Expand Down Expand Up @@ -300,7 +300,7 @@ def get_first(self, attr, value, e=0.000001,
return None

@classmethod
@lrudecorator(size=32)
@lrudecorator(size=64)
def GetAll(cls, attr, value, e=0.000001, sort_by="__name__"):
"""Get all nested Constant class that met ``klass.attr == value``.
Expand Down Expand Up @@ -342,6 +342,95 @@ def get_all(self, attr, value, e=0.000001,

return matched

@classmethod
def ToIds(cls, klass_list, id_field="id"):
return [getattr(klass, id_field) for klass in klass_list]

def to_ids(self, instance_list, id_field="id"):
return [getattr(instance, id_field) for instance in instance_list]

@classmethod
def ToClasses(cls, klass_id_list, id_field="id"):
return [cls.GetFirst(id_field, klass_id) for klass_id in klass_id_list]

def to_instances(self, instance_id_list, id_field="id"):
return [self.get_first(id_field, instance_id) for instance_id in instance_id_list]

@classmethod
def SubIds(cls, id_field="id", sort_by=None, reverse=False):
return [
getattr(klass, id_field)
for _, klass in cls.Subclasses(sort_by=sort_by, reverse=reverse)
]

def sub_ids(self, id_field="id", sort_by=None, reverse=False):
return [
getattr(instance, id_field)
for _, instance in self.subclasses(sort_by=sort_by, reverse=reverse)
]

@classmethod
def BackAssign(cls,
other_entity_klass,
this_entity_backpopulate_field,
other_entity_backpopulate_field,
is_many_to_one=False):
"""
Assign defined one side mapping relationship to other side.
For example, each employee belongs to one department, then one department
includes many employees. If you defined each employee's department,
this method will assign employees to ``Department.employees`` field.
This is an one to many (department to employee) example.
Another example would be, each employee has multiple tags. If you defined
tags for each employee, this method will assign employees to
``Tag.employees`` field. This is and many to many (employee to tag) example.
Support:
- many to many mapping
- one to many mapping
:param other_entity_klass: a :class:`Constant` class.
:param this_entity_backpopulate_field: str
:param other_entity_backpopulate_field: str
:param is_many_to_one: bool
:return:
"""
data = dict()
for _, other_klass in other_entity_klass.Subclasses():
other_field_value = getattr(
other_klass, this_entity_backpopulate_field)
if isinstance(other_field_value, (tuple, list)):
for self_klass in other_field_value:
self_key = self_klass.__name__
try:
data[self_key].append(other_klass)
except KeyError:
data[self_key] = [other_klass, ]
else:
if other_field_value is not None:
self_klass = other_field_value
self_key = self_klass.__name__
try:
data[self_key].append(other_klass)
except KeyError:
data[self_key] = [other_klass, ]

if is_many_to_one:
new_data = dict()
for key, value in data.items():
try:
new_data[key] = value[0]
except: # pragma: no cover
pass
data = new_data

for self_key, other_klass_list in data.items():
setattr(getattr(cls, self_key),
other_entity_backpopulate_field, other_klass_list)

@classmethod
def dump(cls):
"""Dump data into a dict.
Expand Down Expand Up @@ -396,15 +485,19 @@ def jprint(cls): # pragma: no cover
print(json.dumps(cls.dump(), pretty=4))


_reserved_attrs = set([
_reserved_attrs = {
"Items", "Keys", "Values",
"items", "keys", "values",
"ToDict", "to_dict",
"Subclasses", "subclasses",
"GetFirst", "get_first",
"GetAll", "get_all",
"ToIds", "to_ids",
"SubIds", "sub_ids",
"BackAssign",
"ToClasses", "to_instances",
"dump", "load", "pprint", "jprint",
])
}


class Meta(type):
Expand All @@ -414,17 +507,19 @@ class Meta(type):
def __new__(cls, name, bases, attrs):
klass = super(Meta, cls).__new__(cls, name, bases, attrs)
for attr in attrs:
# Make sure reserved attributes are not been override
# Make sure reserved attributes are not been overridden
if attr in _reserved_attrs:
if not (is_class_method(klass, attr)
or is_regular_method(klass, attr)):
if (is_class_method(klass, attr) or is_regular_method(klass, attr)):
# raise exception if it is been overridden
if not (getattr(klass, attr) == getattr(_Constant, attr)):
msg = "%s is a reserved attribute / method name" % attr
raise AttributeError(msg)
else:
# raise exception if it is just a value
raise AttributeError(
"%r is not a valid attribute name" % attr
)
else:
if not getattr(klass, attr) == getattr(_Constant, attr):
msg = "%s is a reserved attribute / method name" % attr
raise AttributeError(msg)

return klass


Expand Down
6 changes: 3 additions & 3 deletions constant2/pkg/pylru.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@
# lookup of values by key.

# Class for the node objects.
import functools


class _dlnode(object):
def __init__(self):
self.empty = True
Expand Down Expand Up @@ -518,9 +521,6 @@ def lruwrap(store, size, writeback=False):
return WriteThroughCacheManager(store, size)


import functools


class lrudecorator(object):
def __init__(self, size):
self.cache = lrucache(size)
Expand Down
16 changes: 14 additions & 2 deletions release-history.rst
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
Release and Version History
===========================

0.0.13 (TODO)
0.0.14 (TODO)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
**Features and Improvements**

Expand All @@ -12,6 +12,18 @@ Release and Version History
**Miscellaneous**


0.0.13 (2018-12-18)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
**Features and Improvements**

- add ``Constant2.BackAssign`` method, define entity mapping in a more clean way.
- add ``Constant2.ToIds``, ``Constant2.to_ids``, ``Constant2.ToIds``, ``Constant2.ToIds``, ``Constant2.ToClasses``, ``Constant2.to_instances``, ``Constant2.SubIds``, ``Constant2.sub_ids``.

**Minor Improvements**

- from 98% to 99% test converage.


0.0.12 (2018-09-06)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Expand Down Expand Up @@ -59,7 +71,7 @@ Release and Version History
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
**Features and Improvements**
- Now attribute or sub classes could have mutable attributes. Modify one on this instance will not affect other instance.
- Seperate the methods into two group of API (uppercase for class, lowercase for instance).
- Separate the methods into two group of API (uppercase for class, lowercase for instance).

**Bugfixes**
- Fixed a import problem. Now it doesn't require to install any third party packages.
Expand Down
2 changes: 1 addition & 1 deletion requirements-doc.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
sphinx==1.6.3
docfly
docfly==0.0.15
sphinx_rtd_theme
18 changes: 18 additions & 0 deletions tests/test_basic.py
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,24 @@ def test_get_first_performance(self):
elapsed = time.clock() - st
# print("without lfu_cache elapsed %.6f second." % elapsed)

def test_ToIds(self):
assert Food.ToIds([Food.Fruit, Food.Meat]) == [1, 2]

def test_to_ids(self):
assert food.to_ids([food.Fruit, food.Meat]) == [1, 2]

def test_ToClasses(self):
assert Food.ToClasses([1, 2]) == [Food.Fruit, Food.Meat]

def test_to_instances(self):
assert food.to_instances([1, 2]) == [food.Fruit, food.Meat]

def test_SubIds(self):
assert Food.SubIds() == [1, 2]

def test_sub_ids(self):
assert food.sub_ids() == [1, 2]

def test_ToDict(self):
assert Food.ToDict() == {}
assert Food.Fruit.ToDict() == {"id": 1, "name": "fruit"}
Expand Down

0 comments on commit ccf7e14

Please sign in to comment.