From c6e5beeb2b4c1c79a009b3f66bc6c6e0ba2be04e Mon Sep 17 00:00:00 2001 From: Legolas Bloom Date: Thu, 25 Oct 2018 11:33:01 +0800 Subject: [PATCH 1/6] add -vv for pytest cmd --- hobbit_core/hobbit/static/bootstrap/shire/pytest.ini.jinja2 | 2 +- pytest.ini | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) 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 From 1be9b46f63b5e10c8d58bf77dbde95671f064b9a Mon Sep 17 00:00:00 2001 From: Legolas Bloom Date: Sat, 27 Oct 2018 09:41:21 +0800 Subject: [PATCH 2/6] add test for EnumExt.to_opts --- docs/api.rst | 7 ++++++- hobbit_core/flask_hobbit/db.py | 26 +++++++++++++++++++++++++- tests/test_db.py | 28 ++++++++++++++++++++++++++++ 3 files changed, 59 insertions(+), 2 deletions(-) create mode 100644 tests/test_db.py diff --git a/docs/api.rst b/docs/api.rst index 0f88467..e7c75f0 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -23,11 +23,16 @@ 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:: to_opts + pagination ^^^^^^^^^^ diff --git a/hobbit_core/flask_hobbit/db.py b/hobbit_core/flask_hobbit/db.py index 3063f7f..d942da0 100644 --- a/hobbit_core/flask_hobbit/db.py +++ b/hobbit_core/flask_hobbit/db.py @@ -61,8 +61,20 @@ def reference_col(tablename, nullable=False, pk_name='id', **kwargs): class EnumExt(enum.Enum): - """ serialize/deserialize sqlalchemy enum field + """ Serialize/Deserialize sqlalchemy enum field. + + Examples:: + + class TaskState(EnumExt): + 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 @@ -84,6 +96,18 @@ def load(cls, val): @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/tests/test_db.py b/tests/test_db.py new file mode 100644 index 0000000..912ae10 --- /dev/null +++ b/tests/test_db.py @@ -0,0 +1,28 @@ +# -*- encoding: utf-8 -*- +import pytest + +from hobbit_core.flask_hobbit import db + +from . import BaseTest + + +class TestDB(BaseTest): + + @pytest.fixture + def TaskState(self): + class _TaskState(db.EnumExt): + CREATED = (0, u'新建') + FINISHED = (1, u'已完成') + return _TaskState + + def test_enumext_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'已完成'}, + ] From 160fb84123e4ba2353d5f74bd6a39ead201c0fa4 Mon Sep 17 00:00:00 2001 From: Legolas Bloom Date: Sat, 27 Oct 2018 10:14:48 +0800 Subject: [PATCH 3/6] fix EnumExt.load bug & tested & doc --- docs/api.rst | 1 + hobbit_core/flask_hobbit/db.py | 21 +++++++++++++++++++-- tests/test_db.py | 5 +++++ 3 files changed, 25 insertions(+), 2 deletions(-) diff --git a/docs/api.rst b/docs/api.rst index e7c75f0..17f594c 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -31,6 +31,7 @@ db .. autoclass:: EnumExt :members: + .. automethod:: load .. automethod:: to_opts pagination diff --git a/hobbit_core/flask_hobbit/db.py b/hobbit_core/flask_hobbit/db.py index d942da0..30fd657 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,11 +62,15 @@ 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, '开始') @@ -89,7 +94,18 @@ def dump(cls, key, verbose=False): @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 @@ -108,6 +124,7 @@ def to_opts(cls, verbose=False): 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/tests/test_db.py b/tests/test_db.py index 912ae10..677c35f 100644 --- a/tests/test_db.py +++ b/tests/test_db.py @@ -15,6 +15,11 @@ class _TaskState(db.EnumExt): FINISHED = (1, u'已完成') return _TaskState + def test_enumext_load(self, TaskState): + assert 'FINISHED' == TaskState.load(1) + assert 'CREATED' == TaskState.load(u'新建') + assert TaskState.load(100) is None + def test_enumext_to_opts(self, TaskState): opts = TaskState.to_opts() assert opts == [ From 1dc68ace7dc41ae2cdcb50b101f1f8389bcb7a33 Mon Sep 17 00:00:00 2001 From: Legolas Bloom Date: Sat, 27 Oct 2018 10:22:57 +0800 Subject: [PATCH 4/6] doc EnumExt.dump and tested --- docs/api.rst | 1 + hobbit_core/flask_hobbit/db.py | 19 +++++++++++++++---- tests/test_db.py | 5 ++++- 3 files changed, 20 insertions(+), 5 deletions(-) diff --git a/docs/api.rst b/docs/api.rst index 17f594c..cd0c937 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -31,6 +31,7 @@ db .. autoclass:: EnumExt :members: + .. automethod:: dump .. automethod:: load .. automethod:: to_opts diff --git a/hobbit_core/flask_hobbit/db.py b/hobbit_core/flask_hobbit/db.py index 30fd657..8880d31 100644 --- a/hobbit_core/flask_hobbit/db.py +++ b/hobbit_core/flask_hobbit/db.py @@ -77,7 +77,6 @@ class TaskState(EnumExt): RUNNING = (3, '运行中') FINISHED = (4, '已完成') FAILED = (5, '失败') - """ @classmethod @@ -86,10 +85,22 @@ def strict_dump(cls, key, verbose=False): return cls[key].value[pos] @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 diff --git a/tests/test_db.py b/tests/test_db.py index 677c35f..7b6034f 100644 --- a/tests/test_db.py +++ b/tests/test_db.py @@ -6,7 +6,7 @@ from . import BaseTest -class TestDB(BaseTest): +class TestEnumExt(BaseTest): @pytest.fixture def TaskState(self): @@ -15,6 +15,9 @@ class _TaskState(db.EnumExt): FINISHED = (1, u'已完成') return _TaskState + def test_enumext_dump(self, TaskState): + assert {'key': 0, 'value': u'新建'} == TaskState.dump('CREATED') + def test_enumext_load(self, TaskState): assert 'FINISHED' == TaskState.load(1) assert 'CREATED' == TaskState.load(u'新建') From 173f92a49a387dd541d94001457095e7b0cc7a8c Mon Sep 17 00:00:00 2001 From: Legolas Bloom Date: Sat, 27 Oct 2018 10:30:10 +0800 Subject: [PATCH 5/6] doc EnumExt.strict_dump and tested --- docs/api.rst | 1 + hobbit_core/flask_hobbit/db.py | 16 +++++++++++++--- tests/test_db.py | 10 +++++++--- 3 files changed, 21 insertions(+), 6 deletions(-) diff --git a/docs/api.rst b/docs/api.rst index cd0c937..b965b14 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -31,6 +31,7 @@ db .. autoclass:: EnumExt :members: + .. automethod:: strict_dump .. automethod:: dump .. automethod:: load .. automethod:: to_opts diff --git a/hobbit_core/flask_hobbit/db.py b/hobbit_core/flask_hobbit/db.py index 8880d31..0c87094 100644 --- a/hobbit_core/flask_hobbit/db.py +++ b/hobbit_core/flask_hobbit/db.py @@ -80,9 +80,19 @@ class TaskState(EnumExt): """ @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, label, verbose=False): diff --git a/tests/test_db.py b/tests/test_db.py index 7b6034f..6fa3418 100644 --- a/tests/test_db.py +++ b/tests/test_db.py @@ -15,15 +15,19 @@ class _TaskState(db.EnumExt): FINISHED = (1, u'已完成') return _TaskState - def test_enumext_dump(self, 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_enumext_load(self, TaskState): + def test_load(self, TaskState): assert 'FINISHED' == TaskState.load(1) assert 'CREATED' == TaskState.load(u'新建') assert TaskState.load(100) is None - def test_enumext_to_opts(self, TaskState): + def test_to_opts(self, TaskState): opts = TaskState.to_opts() assert opts == [ {'key': 0, 'value': u'新建'}, From 5c5e5e43642d67d5df9f4224633afa7d921051d9 Mon Sep 17 00:00:00 2001 From: Legolas Bloom Date: Sat, 27 Oct 2018 10:33:04 +0800 Subject: [PATCH 6/6] use pytest.ini conf in tox --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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