diff --git a/docs/api.rst b/docs/api.rst index 0f88467..b965b14 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -23,11 +23,19 @@ db .. automodule:: hobbit_core.flask_hobbit.db :members: :undoc-members: - :exclude-members: SurrogatePK + :exclude-members: SurrogatePK, EnumExt .. autoclass:: SurrogatePK :members: __repr__ + .. autoclass:: EnumExt + :members: + + .. automethod:: strict_dump + .. automethod:: dump + .. automethod:: load + .. automethod:: to_opts + pagination ^^^^^^^^^^ diff --git a/hobbit_core/flask_hobbit/db.py b/hobbit_core/flask_hobbit/db.py index 3063f7f..0c87094 100644 --- a/hobbit_core/flask_hobbit/db.py +++ b/hobbit_core/flask_hobbit/db.py @@ -1,5 +1,6 @@ # -*- encoding: utf-8 -*- import enum +import six from sqlalchemy import Integer, Column, ForeignKey, func, DateTime @@ -61,29 +62,90 @@ def reference_col(tablename, nullable=False, pk_name='id', **kwargs): class EnumExt(enum.Enum): - """ serialize/deserialize sqlalchemy enum field + """ Extension for serialize/deserialize sqlalchemy enum field. + + Be sure ``type(key)`` is ``int`` and ``type(value)`` is ``str`` + (``label = (key, value)``). + + Examples:: + + class TaskState(EnumExt): + # label = (key, value) + CREATED = (0, '新建') + PENDING = (1, '等待') + STARTING = (2, '开始') + RUNNING = (3, '运行中') + FINISHED = (4, '已完成') + FAILED = (5, '失败') """ + @classmethod - def strict_dump(cls, key, verbose=False): - pos = 1 if verbose else 0 - return cls[key].value[pos] + def strict_dump(cls, label, verbose=False): + """Get key or value by label. + + Examples:: + + TaskState.strict_dump('CREATED') # 0 + TaskState.strict_dump('CREATED', verbose=True) # '新建' + + Returns: + int|str: Key or value, If label not exist, raise ``KeyError``. + """ + + return cls[label].value[1 if verbose else 0] @classmethod - def dump(cls, key, verbose=False): - ret = {'key': cls[key].value[0], 'value': cls[key].value[1]} + def dump(cls, label, verbose=False): + """Dump one label to option. + + Examples:: + + TaskState.dump('CREATED') # {'key': 0, 'value': '新建'} + + Returns: + + dict: Dict of label's key and value. If label not exist, + raise ``KeyError``. + """ + + ret = {'key': cls[label].value[0], 'value': cls[label].value[1]} if verbose: - ret.update({'label': key}) + ret.update({'label': label}) return ret @classmethod def load(cls, val): - pos = 1 if isinstance(val, str) else 0 + """Get label by key or value. + + Examples:: + + TaskState.load(4) # 'FINISHED' + TaskState.load('新建') # 'CREATED' + + Returns: + str|None: Label. + """ + + pos = 1 if isinstance(val, six.string_types) else 0 for elem in cls: if elem.value[pos] == val: return elem.name @classmethod def to_opts(cls, verbose=False): + """Enum to options. + + Examples:: + + opts = TaskState.to_opts(verbose=True) + print(opts) + + [{'key': 0, 'label': 'CREATED', 'value': u'新建'}, ...] + + Returns: + list: List of dict which key is `key`, `value`, label. + """ + opts = [] for elem in cls: opt = {'key': elem.value[0], 'value': elem.value[1]} diff --git a/hobbit_core/hobbit/static/bootstrap/shire/pytest.ini.jinja2 b/hobbit_core/hobbit/static/bootstrap/shire/pytest.ini.jinja2 index 47823a2..fe39cf4 100644 --- a/hobbit_core/hobbit/static/bootstrap/shire/pytest.ini.jinja2 +++ b/hobbit_core/hobbit/static/bootstrap/shire/pytest.ini.jinja2 @@ -2,4 +2,4 @@ env = LASK_APP=app/run.py FLASK_ENV=testing -addopts = --cov . --cov-report term-missing -s -x -v -p no:warnings +addopts = --cov . --cov-report term-missing -s -x -vv -p no:warnings diff --git a/pytest.ini b/pytest.ini index 73aa72c..93961b6 100644 --- a/pytest.ini +++ b/pytest.ini @@ -1,2 +1,2 @@ [pytest] -addopts = --cov hobbit_core --cov=tests --cov-report term-missing -s -x -v -p no:warnings +addopts = --cov hobbit_core --cov=tests --cov-report term-missing -s -x -vv -p no:warnings diff --git a/tests/test_db.py b/tests/test_db.py new file mode 100644 index 0000000..6fa3418 --- /dev/null +++ b/tests/test_db.py @@ -0,0 +1,40 @@ +# -*- encoding: utf-8 -*- +import pytest + +from hobbit_core.flask_hobbit import db + +from . import BaseTest + + +class TestEnumExt(BaseTest): + + @pytest.fixture + def TaskState(self): + class _TaskState(db.EnumExt): + CREATED = (0, u'新建') + FINISHED = (1, u'已完成') + return _TaskState + + def test_strict_dump(self, TaskState): + assert 0 == TaskState.strict_dump('CREATED') + assert u'新建' == TaskState.strict_dump('CREATED', True) + + def test_dump(self, TaskState): + assert {'key': 0, 'value': u'新建'} == TaskState.dump('CREATED') + + def test_load(self, TaskState): + assert 'FINISHED' == TaskState.load(1) + assert 'CREATED' == TaskState.load(u'新建') + assert TaskState.load(100) is None + + def test_to_opts(self, TaskState): + opts = TaskState.to_opts() + assert opts == [ + {'key': 0, 'value': u'新建'}, + {'key': 1, 'value': u'已完成'}, + ] + opts = TaskState.to_opts(verbose=True) + assert opts == [ + {'key': 0, 'label': 'CREATED', 'value': u'新建'}, + {'key': 1, 'label': 'FINISHED', 'value': u'已完成'}, + ] diff --git a/tox.ini b/tox.ini index e6b2b64..ed926ee 100644 --- a/tox.ini +++ b/tox.ini @@ -9,4 +9,4 @@ deps = py27: ipython==5.8.0 commands = flake8 . - py.test --cov=hobbit_core --cov=tests --cov-report term-missing -s + py.test