From c3e3b6895d79bd1089896051bc82a642e35ae36e Mon Sep 17 00:00:00 2001 From: kinegratii Date: Sun, 22 Sep 2019 21:32:08 +0800 Subject: [PATCH 01/20] :sparkles: Remove deprecated modules --- borax/decorators/admin.py | 31 ------------------------------- borax/loader.py | 14 -------------- 2 files changed, 45 deletions(-) delete mode 100644 borax/decorators/admin.py delete mode 100644 borax/loader.py diff --git a/borax/decorators/admin.py b/borax/decorators/admin.py deleted file mode 100644 index 2712e8b..0000000 --- a/borax/decorators/admin.py +++ /dev/null @@ -1,31 +0,0 @@ -# coding=utf8 -import warnings - -__all__ = ['attr', 'admin_action', 'action', 'display_field'] - -warnings.warn('This module is deprecated, use nickel.admin_utils.decorators instead.', DeprecationWarning) - - -def attr(**kwargs): - def _inner(fun): - for name, value in kwargs.items(): - setattr(fun, name, value) - return fun - - return _inner - - -def admin_action(short_description=None, allowed_permissions=None, **kwargs): - if allowed_permissions is not None: - kwargs.update({'allowed_permissions': allowed_permissions}) - return attr(short_description=short_description, **kwargs) - - -# Old name alias -action = admin_action - - -def display_field(short_description, admin_order_field=None, **kwargs): - if admin_order_field is not None: - kwargs.update({'admin_order_field': admin_order_field}) - return attr(short_description=short_description, **kwargs) diff --git a/borax/loader.py b/borax/loader.py deleted file mode 100644 index 4bdc04f..0000000 --- a/borax/loader.py +++ /dev/null @@ -1,14 +0,0 @@ -# coding=utf8 - -import warnings - -from .system import load_class as _load_class - - -def load_class(s): - """Import a class - :param s: the full path of the class - :return: - """ - warnings.warn('This method is deprecated. Use `borax.system.load_class` instead .', DeprecationWarning) - return _load_class(s) From 70b3dbe7aa09cd7c194c24ceba821584834c255c Mon Sep 17 00:00:00 2001 From: kinegratii Date: Thu, 26 Sep 2019 22:05:10 +0800 Subject: [PATCH 02/20] :sparkles: Add windows/linux end style converter --- borax/strings.py | 30 ++++++++++++++++++++++++++++++ docs/changelog.md | 6 ++++++ 2 files changed, 36 insertions(+) diff --git a/borax/strings.py b/borax/strings.py index 7b9428c..dfa56e7 100644 --- a/borax/strings.py +++ b/borax/strings.py @@ -15,3 +15,33 @@ def snake2camel(s): def get_percentage_display(value, places=2): fmt = '{0:. f}%'.replace(' ', str(places)) return fmt.format(value * 100) + + +class FileEndingUtil: + WINDOWS_LINE_ENDING = b'\r\n' + LINUX_LINE_ENDING = b'\n' + + @staticmethod + def windows2linux(content: bytes) -> bytes: + assert isinstance(content, bytes) + return content.replace(FileEndingUtil.WINDOWS_LINE_ENDING, FileEndingUtil.LINUX_LINE_ENDING) + + @staticmethod + def linux2windows(content: bytes) -> bytes: + return content.replace(FileEndingUtil.LINUX_LINE_ENDING, FileEndingUtil.WINDOWS_LINE_ENDING) + + @staticmethod + def convert_to_linux_style_file(file_path): + with open(file_path, 'rb') as f: + content = f.read() + content = FileEndingUtil.windows2linux(content) + with open(file_path, 'wb') as f: + f.write(content) + + @staticmethod + def convert_to_windows_style_file(file_path): + with open(file_path, 'rb') as f: + content = f.read() + content = FileEndingUtil.linux2windows(content) + with open(file_path, 'wb') as f: + f.write(content) diff --git a/docs/changelog.md b/docs/changelog.md index b45c0ed..6727bcc 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -1,5 +1,11 @@ # 更新日志 +## v3.0.0 + +- 新增 windows/linux 换行符转换 `FileEndingUtils` +- 移除 `borax.loader` +- 移除 `borax.decorators.admin` + ## v1.4.2 (20190717) - `counters.serials` 模块 From 6da45b97842a886b417db3ac3d1ac4d13c567ecf Mon Sep 17 00:00:00 2001 From: kinegratii Date: Wed, 9 Oct 2019 23:01:05 +0800 Subject: [PATCH 03/20] :sparkles: Add SerialGenerator.generate_next_one method --- borax/counters/serials.py | 6 ++++++ docs/changelog.md | 2 ++ 2 files changed, 8 insertions(+) diff --git a/borax/counters/serials.py b/borax/counters/serials.py index 5dcd85d..82075d3 100644 --- a/borax/counters/serials.py +++ b/borax/counters/serials.py @@ -39,6 +39,9 @@ def generate(self, num: int) -> List[int]: self.__add_serials(result) return result + def generate_next_one(self) -> int: + return self.generate(1)[0] + def __add_serials(self, serials: Iterable[int]) -> None: for serial in serials: self._data_set.add(serial) @@ -67,6 +70,9 @@ def generate(self, num: int) -> List[str]: res = super().generate(num) return list(map(self._convert, res)) + def generate_next_one(self) -> str: + return self.generate(1)[0] + def add(self, elements: List[str]) -> None: elements = map(self._parse_serial, elements) super().add(elements) diff --git a/docs/changelog.md b/docs/changelog.md index 6727bcc..90bbff9 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -5,6 +5,8 @@ - 新增 windows/linux 换行符转换 `FileEndingUtils` - 移除 `borax.loader` - 移除 `borax.decorators.admin` +- `borax.counters.serials` + - 新增 `SerialGenerator.generate_next_one` 方法 ## v1.4.2 (20190717) From 087349ac0bd1eed0611649c5c3dc866ec12b6036 Mon Sep 17 00:00:00 2001 From: kinegratii Date: Fri, 11 Oct 2019 23:18:38 +0800 Subject: [PATCH 04/20] Fix error for borax.finance --- borax/finance.py | 8 ++++++++ docs/changelog.md | 5 +++-- tests/test_finance.py | 10 ++++++++++ 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/borax/finance.py b/borax/finance.py index b2068dd..ef704c4 100644 --- a/borax/finance.py +++ b/borax/finance.py @@ -15,10 +15,18 @@ (r'^元', '零元') ] +MAX_VALUE_LIMIT = 1000000000000 + def financial_amount_capital(num: Union[int, float, Decimal, str]) -> str: units = '仟佰拾亿仟佰拾万仟佰拾元角分' digits = '零壹贰叁肆伍陆柒捌玖' + if isinstance(num, str): + _n = int(num) + else: + _n = num + if _n < 0 or _n >= MAX_VALUE_LIMIT: + raise ValueError('Out of range') num_str = str(num) + '00' dot_pos = num_str.find('.') diff --git a/docs/changelog.md b/docs/changelog.md index 90bbff9..48cd65d 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -5,9 +5,10 @@ - 新增 windows/linux 换行符转换 `FileEndingUtils` - 移除 `borax.loader` - 移除 `borax.decorators.admin` -- `borax.counters.serials` +- `borax.counters.serials` 模块 - 新增 `SerialGenerator.generate_next_one` 方法 - +- `borax.finance` 模块 + - `financial_amount_capital` 新增上下限检查 ## v1.4.2 (20190717) - `counters.serials` 模块 diff --git a/tests/test_finance.py b/tests/test_finance.py index 6ac917e..95e4c0f 100644 --- a/tests/test_finance.py +++ b/tests/test_finance.py @@ -18,3 +18,13 @@ def test_amount_capital(self): def test_decimal(self): self.assertEqual('肆元伍角零分', financial_amount_capital(decimal.Decimal(4.50))) self.assertEqual('壹拾万柒仟元伍角叁分', financial_amount_capital(decimal.Decimal('107000.53'))) + + def test_valid_range(self): + with self.assertRaises(ValueError): + financial_amount_capital(332342342341234) + with self.assertRaises(ValueError): + financial_amount_capital(1000000000000) + self.assertIsNotNone(financial_amount_capital(999999999999)) + self.assertIsNotNone(financial_amount_capital(999999999999.99)) + with self.assertRaises(ValueError): + financial_amount_capital('1000000000000') From c8a37ccb898cb4891cf7c808dfea8857e1650f8b Mon Sep 17 00:00:00 2001 From: kinegratii Date: Sun, 13 Oct 2019 10:13:14 +0800 Subject: [PATCH 05/20] remove TableLookup.data_dict --- borax/structures/lookup.py | 4 ---- docs/changelog.md | 2 ++ 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/borax/structures/lookup.py b/borax/structures/lookup.py index 7482aec..ca6e9d9 100644 --- a/borax/structures/lookup.py +++ b/borax/structures/lookup.py @@ -26,10 +26,6 @@ def feed(self, table_data): def find(self, key, default=None): return self._dataset.get(key, default) - def data_dict(self, field): - warnings.warn("'data_dict' method is deprecated, use 'select_as_dict' instead.", DeprecationWarning) - return self.select_as_dict(field) - def select_as_dict(self, field): return {k: getattr(v, field) for k, v in self._dataset.items()} diff --git a/docs/changelog.md b/docs/changelog.md index 48cd65d..f40910c 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -5,6 +5,8 @@ - 新增 windows/linux 换行符转换 `FileEndingUtils` - 移除 `borax.loader` - 移除 `borax.decorators.admin` +- `borax.structures` 模块 + - 移除 `TableLookup.data_dict` 方法 - `borax.counters.serials` 模块 - 新增 `SerialGenerator.generate_next_one` 方法 - `borax.finance` 模块 From af738c762ad6e51686139ca58c69c109b9c900b6 Mon Sep 17 00:00:00 2001 From: kinegratii Date: Tue, 22 Oct 2019 22:14:19 +0800 Subject: [PATCH 06/20] Add choice3 module --- borax/choices3.py | 98 ++++++++++++++++++++++++++++++++++++ docs/release/release-v300.md | 21 ++++++++ tests/test_choices3.py | 62 +++++++++++++++++++++++ 3 files changed, 181 insertions(+) create mode 100644 borax/choices3.py create mode 100644 docs/release/release-v300.md create mode 100644 tests/test_choices3.py diff --git a/borax/choices3.py b/borax/choices3.py new file mode 100644 index 0000000..94735b7 --- /dev/null +++ b/borax/choices3.py @@ -0,0 +1,98 @@ +# coding=utf8 + +from collections import OrderedDict + + +class BItem: + _order = 0 + + def __init__(self, value, label=None, *, order=-1): + self._value = value + self._label = label + if order is None: + BItem._order += 1 + self.order = BItem._order + else: + self.order = order + + @property + def value(self): + return self._value + + @property + def label(self): + return self._label + + def __eq__(self, other): + return self._value == other + + +class BChoicesMeta(type): + def __new__(cls, name, bases, attrs): + + fields = {} # {:} + + parents = [b for b in bases if isinstance(b, BChoicesMeta)] + for kls in parents: + for field_name in kls._fields: + fields[field_name] = kls._fields[field_name] + + for k, v in attrs.items(): + if k.startswith('_'): + continue + if isinstance(v, BItem): + fields[k] = v + elif isinstance(v, (tuple, list)) and len(v) == 2: + fields[k] = BItem(v[0], v[1]) + elif isinstance(v, (int, float, str, bytes)): + fields[k] = BItem(v, k.lower()) + + fields = OrderedDict(sorted(fields.items(), key=lambda x: x[1].order)) + for field_name, item in fields.items(): + attrs[field_name] = item + + new_cls = super().__new__(cls, name, bases, attrs) + new_cls._fields = fields + return new_cls + + @property + def fields(cls): + return cls._fields + + @property + def choices(cls): + return [(item.value, item.label) for _, item in cls.fields.items()] + + @property + def values(cls): + return [value for value, _ in cls.choices] + + @property + def labels(cls): + return [label for _, label in cls.choices] + + @property + def display_lookup(cls): + return {value: label for value, label in cls.choices} + + def get_value_display(cls, item): + return cls.display_lookup.get(item) + + def __getattr__(self, item): + if item in self.fields: + return self.fields[item] + return super().__getattr__(item) + + def __contains__(self, item): + return item in self.values + + def __iter__(self): + for item in self.choices: + yield item + + def __len__(self): + return len(self.choices) + + +class BChoices(metaclass=BChoicesMeta): + pass diff --git a/docs/release/release-v300.md b/docs/release/release-v300.md new file mode 100644 index 0000000..cbb495e --- /dev/null +++ b/docs/release/release-v300.md @@ -0,0 +1,21 @@ +# V3.0.0发布日志 + +## 概述 + +2019年11月15日,Borax 正式发布 V3.0.0 。 + +## 1 Borax-Cli + +Borax-V3 新增一系列命令行工具。 + +### windows/unix文件换行符转化 + +转换为 Unix 风格的换行符 + +```shell +// 转换单个文件 +$ borax-cli w2u install.sh + +//转化多个文件,并输出到另外一个目录 +$ borax-cli w2u *.sh --output dist/scripts +``` \ No newline at end of file diff --git a/tests/test_choices3.py b/tests/test_choices3.py new file mode 100644 index 0000000..45b77cc --- /dev/null +++ b/tests/test_choices3.py @@ -0,0 +1,62 @@ +# coding=utf8 + +import unittest + +from borax import choices3 + + +class BItemTestCase(unittest.TestCase): + def test_choice_item_equal(self): + c = choices3.BItem(4, 'Demo') + self.assertTrue(c == 4) + self.assertTrue(4 == c) + self.assertFalse(c != 4) + self.assertFalse(4 != c) + self.assertEqual(4, c) + + def test_member(self): + members = [ + choices3.BItem(2, 'A'), + choices3.BItem(3, 'B'), + choices3.BItem(4, 'C') + ] + self.assertTrue(2 in members) + + +class Demo1Field(choices3.BChoices): + A = 1, 'VER' + B = 2, 'STE' + c = 3, 'SSS' + D = 5 + _E = 6, 'ES' + F = 8 + G = choices3.BItem(10, 'G') + + +class FieldChoiceTestCase(unittest.TestCase): + def test_get_value(self): + self.assertEqual(1, Demo1Field.A) + self.assertEqual(2, Demo1Field.B) + self.assertEqual(5, Demo1Field.D) + + def test_is_valid(self): + self.assertTrue(1 in Demo1Field) + self.assertTrue(2 in Demo1Field) + self.assertTrue(3 in Demo1Field) + self.assertFalse(4 in Demo1Field) + self.assertTrue(5 in Demo1Field) + self.assertFalse(6 in Demo1Field) + + def test_get_display(self): + self.assertEqual('VER', Demo1Field.get_value_display(1)) + self.assertIsNone(Demo1Field.get_value_display(4)) + self.assertEqual('d', Demo1Field.get_value_display(5)) + self.assertEqual('f', Demo1Field.get_value_display(8)) + self.assertEqual('G', Demo1Field.get_value_display(10)) + +class FieldChoicesNewAttrTestCase(unittest.TestCase): + def test_text(self): + self.assertListEqual( + [1, 2, 3, 5, 8, 10], + Demo1Field.values + ) \ No newline at end of file From b65573a7ac18f1309ce11d923187fa0ce1124576 Mon Sep 17 00:00:00 2001 From: kinegratii Date: Wed, 30 Oct 2019 00:15:08 +0800 Subject: [PATCH 07/20] :sparkles: add datdasets modules --- borax/datasets.py | 59 ++++++++++++++++++++++++++++++++++++++++++ tests/test_datasets.py | 26 +++++++++++++++++++ 2 files changed, 85 insertions(+) create mode 100644 borax/datasets.py create mode 100644 tests/test_datasets.py diff --git a/borax/datasets.py b/borax/datasets.py new file mode 100644 index 0000000..1fa6aea --- /dev/null +++ b/borax/datasets.py @@ -0,0 +1,59 @@ +# coding=utf8 + + +def join_one(data_list, values, from_, as_): + if isinstance(values, (list, tuple)): + values = dict(values) + if not isinstance(values, dict): + raise TypeError("Unsupported Type for values param.") + for item in data_list: + if from_ in item: + val = item[from_] + if val in values: + ref_val = values[val] + item[as_] = ref_val + return data_list + + +def join(data_list, values, from_, to_, as_args=None, as_kwargs=None): + as_args = as_args or [] + as_kwargs = as_kwargs or {} + as_fields = {**{a: a for a in as_args}, **as_kwargs} + dict_values = {v[to_]: v for v in values} + for item in data_list: + kv = item[from_] + val_dic = dict_values[kv] + for f1, f2 in as_fields.items(): + item[f2] = val_dic[f1] + return data_list + + +class DictDataset: + def __init__(self, data, primary_field=None): + self._data = [] + if data: + self._data = list(data) + self._primary_field = primary_field + + @property + def data(self): + return self._data + + def __iter__(self): + for item in self.data: + yield item + + def join(self, values, from_, to_, as_args=None, as_kwargs=None): + join( + self._data, + values=values, + from_=from_, + to_=to_, + as_args=as_args, + as_kwargs=as_kwargs, + ) + return self + + def join_one(self, values, from_, as_): + join_one(self._data, values=values, from_=from_, as_=as_) + return self diff --git a/tests/test_datasets.py b/tests/test_datasets.py new file mode 100644 index 0000000..d2f767b --- /dev/null +++ b/tests/test_datasets.py @@ -0,0 +1,26 @@ +# codng=utf8 + + +import unittest + +from borax.datasets import join_one + + +class shortcutMethodTestCase(unittest.TestCase): + + def test_join_one(self): + data_list = [{"id": 1, "name": ""}, {"id": 2, "name": ""}, {"id": 4, "name": ""}] + values = {1: "A", 2: "B"} + join_one(data_list, values, from_='id', as_='name') + self.assertEqual("A", data_list[0]["name"]) + self.assertEqual("", data_list[2]["name"]) + + def test_join_one_choices(self): + data_list = [ + {'id':1, 'name':'Amy', 'gender': 1}, + {'id':2,'name':'John', 'gender':2} + ] + gender_choices = [(1, 'male'),(2,'female')] + + join_one(data_list, gender_choices, from_='gender', as_='gender_name') + self.assertEqual('male', data_list[0]['gender_name']) From 6dd6d2457918dfbb438a7d1ccc25a7836650e935 Mon Sep 17 00:00:00 2001 From: kinegratii Date: Fri, 15 Nov 2019 22:04:28 +0800 Subject: [PATCH 08/20] update v3.0.0Beta --- .gitignore | 3 ++- .travis.yml | 4 ++-- borax/__init__.py | 2 +- borax/choices3.py | 2 ++ borax/structures/lookup.py | 1 - docs/changelog.md | 11 +++++++---- setup.py | 1 + tests/test_choices3.py | 3 ++- tests/test_datasets.py | 21 ++++++++++++--------- 9 files changed, 29 insertions(+), 19 deletions(-) diff --git a/.gitignore b/.gitignore index f2506b7..bb9463d 100644 --- a/.gitignore +++ b/.gitignore @@ -102,4 +102,5 @@ ENV/ .idea -node_modules \ No newline at end of file +node_modules +*.code-workspace \ No newline at end of file diff --git a/.travis.yml b/.travis.yml index 977c0ac..99d57da 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,8 +1,8 @@ language: python python: - - "3.5" - "3.6" - - "3.7-dev" + - "3.7" + - "3.8" branches: only: - master diff --git a/borax/__init__.py b/borax/__init__.py index 34765a0..40a7c9d 100644 --- a/borax/__init__.py +++ b/borax/__init__.py @@ -1,4 +1,4 @@ # coding=utf8 -__version__ = '1.4.2' +__version__ = '3.0.0' __author__ = 'kinegratii' diff --git a/borax/choices3.py b/borax/choices3.py index 94735b7..ac80365 100644 --- a/borax/choices3.py +++ b/borax/choices3.py @@ -47,6 +47,8 @@ def __new__(cls, name, bases, attrs): elif isinstance(v, (int, float, str, bytes)): fields[k] = BItem(v, k.lower()) + # FIXME unordered dict for python3.5 + fields = OrderedDict(sorted(fields.items(), key=lambda x: x[1].order)) for field_name, item in fields.items(): attrs[field_name] = item diff --git a/borax/structures/lookup.py b/borax/structures/lookup.py index ca6e9d9..9dbbead 100644 --- a/borax/structures/lookup.py +++ b/borax/structures/lookup.py @@ -1,7 +1,6 @@ # coding=utf8 import collections -import warnings class TableLookup: diff --git a/docs/changelog.md b/docs/changelog.md index f40910c..778eab4 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -1,16 +1,19 @@ # 更新日志 -## v3.0.0 +## v3.0.0 (20191115) -- 新增 windows/linux 换行符转换 `FileEndingUtils` -- 移除 `borax.loader` -- 移除 `borax.decorators.admin` +- `borax.strings` 模块 + - 新增 windows/linux 换行符转换 `FileEndingUtils` - `borax.structures` 模块 - 移除 `TableLookup.data_dict` 方法 - `borax.counters.serials` 模块 - 新增 `SerialGenerator.generate_next_one` 方法 - `borax.finance` 模块 - `financial_amount_capital` 新增上下限检查 +- 移除 `borax.loader` +- 移除 `borax.decorators.admin` +- 新增 Python3.8构建支持 + ## v1.4.2 (20190717) - `counters.serials` 模块 diff --git a/setup.py b/setup.py index fc24814..7507351 100644 --- a/setup.py +++ b/setup.py @@ -15,6 +15,7 @@ "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3 :: Only", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", diff --git a/tests/test_choices3.py b/tests/test_choices3.py index 45b77cc..1d026c5 100644 --- a/tests/test_choices3.py +++ b/tests/test_choices3.py @@ -54,9 +54,10 @@ def test_get_display(self): self.assertEqual('f', Demo1Field.get_value_display(8)) self.assertEqual('G', Demo1Field.get_value_display(10)) + class FieldChoicesNewAttrTestCase(unittest.TestCase): def test_text(self): self.assertListEqual( [1, 2, 3, 5, 8, 10], Demo1Field.values - ) \ No newline at end of file + ) diff --git a/tests/test_datasets.py b/tests/test_datasets.py index d2f767b..c050ca5 100644 --- a/tests/test_datasets.py +++ b/tests/test_datasets.py @@ -7,20 +7,23 @@ class shortcutMethodTestCase(unittest.TestCase): - def test_join_one(self): - data_list = [{"id": 1, "name": ""}, {"id": 2, "name": ""}, {"id": 4, "name": ""}] + data_list = [ + {"id": 1, "name": ""}, + {"id": 2, "name": ""}, + {"id": 4, "name": ""}, + ] values = {1: "A", 2: "B"} - join_one(data_list, values, from_='id', as_='name') + join_one(data_list, values, from_="id", as_="name") self.assertEqual("A", data_list[0]["name"]) self.assertEqual("", data_list[2]["name"]) - + def test_join_one_choices(self): data_list = [ - {'id':1, 'name':'Amy', 'gender': 1}, - {'id':2,'name':'John', 'gender':2} + {"id": 1, "name": "Amy", "gender": 1}, + {"id": 2, "name": "John", "gender": 2}, ] - gender_choices = [(1, 'male'),(2,'female')] + gender_choices = [(1, "male"), (2, "female")] - join_one(data_list, gender_choices, from_='gender', as_='gender_name') - self.assertEqual('male', data_list[0]['gender_name']) + join_one(data_list, gender_choices, from_="gender", as_="gender_name") + self.assertEqual("male", data_list[0]["gender_name"]) From 1e0de4bd9e84cc07ee10dcdd54f3962bd904a781 Mon Sep 17 00:00:00 2001 From: kinegratii Date: Fri, 15 Nov 2019 22:11:35 +0800 Subject: [PATCH 09/20] Remove python3.8 build --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 99d57da..33fc95c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,7 +2,6 @@ language: python python: - "3.6" - "3.7" - - "3.8" branches: only: - master From 2649d1224ae8e9a8d84fabbf4f6ecf2e932c96f2 Mon Sep 17 00:00:00 2001 From: kinegratii Date: Tue, 10 Dec 2019 22:15:25 +0800 Subject: [PATCH 10/20] New borax.join_module --- borax/datasets.py | 26 +------------------------- borax/join_.py | 28 ++++++++++++++++++++++++++++ tests/test_datasets.py | 4 ++-- 3 files changed, 31 insertions(+), 27 deletions(-) create mode 100644 borax/join_.py diff --git a/borax/datasets.py b/borax/datasets.py index 1fa6aea..3c412a0 100644 --- a/borax/datasets.py +++ b/borax/datasets.py @@ -1,31 +1,7 @@ # coding=utf8 -def join_one(data_list, values, from_, as_): - if isinstance(values, (list, tuple)): - values = dict(values) - if not isinstance(values, dict): - raise TypeError("Unsupported Type for values param.") - for item in data_list: - if from_ in item: - val = item[from_] - if val in values: - ref_val = values[val] - item[as_] = ref_val - return data_list - - -def join(data_list, values, from_, to_, as_args=None, as_kwargs=None): - as_args = as_args or [] - as_kwargs = as_kwargs or {} - as_fields = {**{a: a for a in as_args}, **as_kwargs} - dict_values = {v[to_]: v for v in values} - for item in data_list: - kv = item[from_] - val_dic = dict_values[kv] - for f1, f2 in as_fields.items(): - item[f2] = val_dic[f1] - return data_list +from borax.join_ import join_one, join class DictDataset: diff --git a/borax/join_.py b/borax/join_.py new file mode 100644 index 0000000..4eaa685 --- /dev/null +++ b/borax/join_.py @@ -0,0 +1,28 @@ +# coding=utf8 + + +def join_one(data_list, values, from_, as_): + if isinstance(values, (list, tuple)): + values = dict(values) + if not isinstance(values, dict): + raise TypeError("Unsupported Type for values param.") + for item in data_list: + if from_ in item: + val = item[from_] + if val in values: + ref_val = values[val] + item[as_] = ref_val + return data_list + + +def join(data_list, values, from_, to_, as_args=None, as_kwargs=None): + as_args = as_args or [] + as_kwargs = as_kwargs or {} + as_fields = {**{a: a for a in as_args}, **as_kwargs} + dict_values = {v[to_]: v for v in values} + for item in data_list: + kv = item[from_] + val_dic = dict_values[kv] + for f1, f2 in as_fields.items(): + item[f2] = val_dic[f1] + return data_list diff --git a/tests/test_datasets.py b/tests/test_datasets.py index c050ca5..c38776d 100644 --- a/tests/test_datasets.py +++ b/tests/test_datasets.py @@ -3,10 +3,10 @@ import unittest -from borax.datasets import join_one +from borax.join_ import join_one -class shortcutMethodTestCase(unittest.TestCase): +class ShortcutMethodTestCase(unittest.TestCase): def test_join_one(self): data_list = [ {"id": 1, "name": ""}, From f19a1d5908ce05cf5ee858e93aa3133239e523f7 Mon Sep 17 00:00:00 2001 From: kinegratii Date: Tue, 31 Dec 2019 21:15:13 +0800 Subject: [PATCH 11/20] add tests for join_one --- borax/join_.py | 6 +++-- tests/test_datasets.py | 29 ----------------------- tests/test_join.py | 54 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 58 insertions(+), 31 deletions(-) delete mode 100644 tests/test_datasets.py create mode 100644 tests/test_join.py diff --git a/borax/join_.py b/borax/join_.py index 4eaa685..484cc8b 100644 --- a/borax/join_.py +++ b/borax/join_.py @@ -1,7 +1,7 @@ # coding=utf8 -def join_one(data_list, values, from_, as_): +def join_one(data_list, values, from_, as_, default=None): if isinstance(values, (list, tuple)): values = dict(values) if not isinstance(values, dict): @@ -11,7 +11,9 @@ def join_one(data_list, values, from_, as_): val = item[from_] if val in values: ref_val = values[val] - item[as_] = ref_val + else: + ref_val = default + item[as_] = ref_val return data_list diff --git a/tests/test_datasets.py b/tests/test_datasets.py deleted file mode 100644 index c38776d..0000000 --- a/tests/test_datasets.py +++ /dev/null @@ -1,29 +0,0 @@ -# codng=utf8 - - -import unittest - -from borax.join_ import join_one - - -class ShortcutMethodTestCase(unittest.TestCase): - def test_join_one(self): - data_list = [ - {"id": 1, "name": ""}, - {"id": 2, "name": ""}, - {"id": 4, "name": ""}, - ] - values = {1: "A", 2: "B"} - join_one(data_list, values, from_="id", as_="name") - self.assertEqual("A", data_list[0]["name"]) - self.assertEqual("", data_list[2]["name"]) - - def test_join_one_choices(self): - data_list = [ - {"id": 1, "name": "Amy", "gender": 1}, - {"id": 2, "name": "John", "gender": 2}, - ] - gender_choices = [(1, "male"), (2, "female")] - - join_one(data_list, gender_choices, from_="gender", as_="gender_name") - self.assertEqual("male", data_list[0]["gender_name"]) diff --git a/tests/test_join.py b/tests/test_join.py new file mode 100644 index 0000000..8d1ab09 --- /dev/null +++ b/tests/test_join.py @@ -0,0 +1,54 @@ +# coding=utf8 + +import copy +import unittest + +from borax.join_ import join_one + +catalogs_dict = { + 1: 'Python', + 2: 'Java', + 3: '软件工程' +} +catalogs_list = [ + {'id': 1, 'name': 'Python'}, + {'id': 2, 'name': 'Java'}, + {'id': 3, 'name': '软件工程'}, +] +books = [ + {'name': 'Python入门教程', 'catalog': 1, 'price': 45}, + {'name': 'Java标准库', 'catalog': 2, 'price': 80}, + {'name': '软件工程(本科教学版)', 'catalog': 3, 'price': 45}, + {'name': 'Django Book', 'catalog': 1, 'price': 45}, + {'name': '系统架构设计教程', 'catalog': 3, 'price': 104}, +] + + +class JoinOneTestCase(unittest.TestCase): + def test_join_one(self): + book_data = copy.deepcopy(books) + catalog_books = join_one(book_data, catalogs_dict, from_='catalog', as_='catalog_name') + self.assertTrue(all(['catalog_name' in book for book in catalog_books])) + self.assertEqual('Java', catalog_books[1]['catalog_name']) + + def test_join_one_with_default(self): + book_data = copy.deepcopy(books) + cur_catalogs_dict = { + 1: 'Python', + 2: 'Java' + } + + catalog_books = join_one(book_data, cur_catalogs_dict, from_='catalog', as_='catalog_name') + self.assertTrue(all(['catalog_name' in book for book in catalog_books])) + self.assertEqual(None, catalog_books[2]['catalog_name']) + + def test_join_one_with_custom_default(self): + book_data = copy.deepcopy(books) + cur_catalogs_dict = { + 1: 'Python', + 2: 'Java' + } + + catalog_books = join_one(book_data, cur_catalogs_dict, from_='catalog', as_='catalog_name', default='[未知分类]') + self.assertTrue(all(['catalog_name' in book for book in catalog_books])) + self.assertEqual('[未知分类]', catalog_books[2]['catalog_name']) From fae705533a7752e9c583808b2afc1581fd3957f8 Mon Sep 17 00:00:00 2001 From: kinegratii Date: Wed, 1 Jan 2020 20:30:48 +0800 Subject: [PATCH 12/20] add docs for datasets --- .gitignore | 4 +- docs/_sidebar.md | 8 ++-- docs/changelog.md | 7 ++- docs/guides/join.md | 103 ++++++++++++++++++++++++++++++++++++++++++++ tests/test_join.py | 10 ++++- 5 files changed, 126 insertions(+), 6 deletions(-) create mode 100644 docs/guides/join.md diff --git a/.gitignore b/.gitignore index bb9463d..e051176 100644 --- a/.gitignore +++ b/.gitignore @@ -103,4 +103,6 @@ ENV/ .idea node_modules -*.code-workspace \ No newline at end of file +*.code-workspace + +demo.py \ No newline at end of file diff --git a/docs/_sidebar.md b/docs/_sidebar.md index 5deb7f5..c7d7bbb 100644 --- a/docs/_sidebar.md +++ b/docs/_sidebar.md @@ -2,15 +2,17 @@ - [快速开始](quickstart) - **Borax.Calendar** - [农历](guides/lunardate) - - [节日(新)](guides/festival) - - [生日(新)](guides/birthday) + - [节日](guides/festival) + - [生日](guides/birthday) - **Borax.Pattern** - [单例模式](guides/singleton) - [选项Choices](guides/choices) +- **Borax.Datasets** + - [数据连接(Join)(新)](guides/join) - **文档** - [字典](guides/alias_dictionary) - [树形结构](guides/tree) - - [序列号生成器(新)](guides/serial_generator) + - [序列号生成器](guides/serial_generator) - [百分比](guides/percentage) - [数据拾取](guides/fetch) - [Django-Admin装饰器](guides/admin_decorators) diff --git a/docs/changelog.md b/docs/changelog.md index 778eab4..cfaf5ba 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -1,6 +1,11 @@ # 更新日志 -## v3.0.0 (20191115) +## v3.1.0 + +- 新增 `borax.join_` 模块 +- `join_one`、`join` 新增 default 参数 + +## v3.0.0 (20191125) - `borax.strings` 模块 - 新增 windows/linux 换行符转换 `FileEndingUtils` diff --git a/docs/guides/join.md b/docs/guides/join.md new file mode 100644 index 0000000..f3004ac --- /dev/null +++ b/docs/guides/join.md @@ -0,0 +1,103 @@ +# join 模块 + +> 模块 `borax.join_` + +本模块实现了类似于数据库的 JOIN 数据列表操作,从另一个数据集获取某一个或几个列的值。 + +## 概述 + +本模块示例所用的数据描述如下: + +图书清单 + +```python +books = [ + {'name': 'Python入门教程', 'catalog': 1, 'price': 45}, + {'name': 'Java标准库', 'catalog': 2, 'price': 80}, + {'name': '软件工程(本科教学版)', 'catalog': 3, 'price': 45}, + {'name': 'Django Book', 'catalog': 1, 'price': 45}, + {'name': '系统架构设计教程', 'catalog': 3, 'price': 104}, +] +``` + +类别(字典格式) + +```python +catalogs_dict = { + 1: 'Python', + 2: 'Java', + 3: '软件工程' +} +``` + +类别(列表格式) + +```python +catalogs_list = [ + {'id': 1, 'name': 'Python'}, + {'id': 2, 'name': 'Java'}, + {'id': 3, 'name': '软件工程'}, +] +``` + + + + +## join_one方法 + +*`join_one(data_list, values, from_, as_, default=None)`* + +> V3.1 新增default参数。 + +从字典读取某一列的值。 + +从 `catalogs_dict` 获取类别名称并按照 catalogs.id 分组填充至 `books` 。 + +```python +catalog_books = join_one(books, catalogs_dict, from_='catalog', as_='catalog_name') +``` + +输出 + +```python +[ + {'name': 'Python入门教程', 'catalog': 1, 'price': 45, 'catalog_name': 'Python'}, + {'name': 'Java标准库', 'catalog': 2, 'price': 80, 'catalog_name': 'Java'}, + {'name': '软件工程(本科教学版)', 'catalog': 3, 'price': 45, 'catalog_name': '软件工程'}, + {'name': 'Django Book', 'catalog': 1, 'price': 45, 'catalog_name': 'Python'}, + {'name': '系统架构设计教程', 'catalog': 3, 'price': 104, 'catalog_name': '软件工程'} +] +``` + + + +## join方法 + +*`join(data_list, values, from_, to_, as_args=None, as_kwargs=None):`* + +从字典读取多个列的值。 + +示例1 + +```python +catalog_books = join( + books, + catalogs_list, + from_='catalog', + to_='id', + as_kwargs={'name': 'catalog_name'} +) +``` + +输出 + +```python +[ + {'name': 'Python入门教程', 'catalog': 1, 'price': 45, 'catalog_name': 'Python'}, + {'name': 'Java标准库', 'catalog': 2, 'price': 80, 'catalog_name': 'Java'}, + {'name': '软件工程(本科教学版)', 'catalog': 3, 'price': 45, 'catalog_name': '软件工程'}, + {'name': 'Django Book', 'catalog': 1, 'price': 45, 'catalog_name': 'Python'}, + {'name': '系统架构设计教程', 'catalog': 3, 'price': 104, 'catalog_name': '软件工程'} +] +``` + diff --git a/tests/test_join.py b/tests/test_join.py index 8d1ab09..c2fe894 100644 --- a/tests/test_join.py +++ b/tests/test_join.py @@ -3,7 +3,7 @@ import copy import unittest -from borax.join_ import join_one +from borax.join_ import join_one, join catalogs_dict = { 1: 'Python', @@ -52,3 +52,11 @@ def test_join_one_with_custom_default(self): catalog_books = join_one(book_data, cur_catalogs_dict, from_='catalog', as_='catalog_name', default='[未知分类]') self.assertTrue(all(['catalog_name' in book for book in catalog_books])) self.assertEqual('[未知分类]', catalog_books[2]['catalog_name']) + + +class JoinTestCase(unittest.TestCase): + def test_as_kwargs(self): + book_data = copy.deepcopy(books) + catalog_books = join(book_data, catalogs_list, from_='catalog', to_='id', as_kwargs={'name': 'catalog_name'}) + self.assertTrue(all(['catalog_name' in book for book in catalog_books])) + self.assertEqual('Java', catalog_books[1]['catalog_name']) From 44426e7cdc563cf9f7d7ddab5f13d9b61f9de424 Mon Sep 17 00:00:00 2001 From: kinegratii Date: Wed, 1 Jan 2020 20:48:29 +0800 Subject: [PATCH 13/20] Fix festival match, #11 --- borax/calendars/festivals.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/borax/calendars/festivals.py b/borax/calendars/festivals.py index b7ca643..90f509c 100644 --- a/borax/calendars/festivals.py +++ b/borax/calendars/festivals.py @@ -149,7 +149,12 @@ def __init__(self, month, day, year=YEAR_ANY, leap=0, ignore_leap=1, **kwargs): def match(self, date_obj): date_obj = self._normalize(date_obj) if self._ignore_leap and date_obj.leap == 1: - date_obj = date_obj.replace(leap=0) + try: + date_obj = date_obj.replace(leap=0) + except ValueError: + if date_obj.day == 30: # leap month has 30 days and normal one has 29 days + return False + raise return super().match(date_obj) def _resolve(self, year): From a4e582b0769b65e8b2b557e5c76fe6ced210fee2 Mon Sep 17 00:00:00 2001 From: kinegratii Date: Fri, 3 Jan 2020 21:04:30 +0800 Subject: [PATCH 14/20] Update project meta files --- docs/changelog.md | 5 +++-- docs/index.html | 2 +- pyproject.toml | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/docs/changelog.md b/docs/changelog.md index cfaf5ba..11e0b90 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -1,9 +1,10 @@ # 更新日志 -## v3.1.0 +## v3.0.1 - 新增 `borax.join_` 模块 -- `join_one`、`join` 新增 default 参数 +- `join_one` 新增 default 参数 +- 修正农历闰月转平月错误的BUG ## v3.0.0 (20191125) diff --git a/docs/index.html b/docs/index.html index 19920df..119ebe6 100644 --- a/docs/index.html +++ b/docs/index.html @@ -24,7 +24,7 @@ var footer = [ '
', '' ].join(''); diff --git a/pyproject.toml b/pyproject.toml index a5c2dea..ee09d0e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "borax" -version = "1.4.2" +version = "3.0.1" description = "A util collections for Python3." readme = "long_description.rst" authors = ["kinegratii "] From f5770c7294b94b61fd844acd80b7d2f640ffae37 Mon Sep 17 00:00:00 2001 From: kinegratii Date: Sat, 4 Jan 2020 19:53:32 +0800 Subject: [PATCH 15/20] :truck: Refactor datasets.package --- borax/datasets/__init__.py | 5 +++++ borax/{datasets.py => datasets/dict_datasets.py} | 2 +- borax/{ => datasets}/join_.py | 0 docs/changelog.md | 10 ++++++---- docs/guides/join.md | 2 +- tests/test_join.py | 2 +- 6 files changed, 14 insertions(+), 7 deletions(-) create mode 100644 borax/datasets/__init__.py rename borax/{datasets.py => datasets/dict_datasets.py} (94%) rename borax/{ => datasets}/join_.py (100%) diff --git a/borax/datasets/__init__.py b/borax/datasets/__init__.py new file mode 100644 index 0000000..43c46f6 --- /dev/null +++ b/borax/datasets/__init__.py @@ -0,0 +1,5 @@ +# coding=utf8 + +from borax.datasets.dict_datasets import DictDataset + +__all__ = ['DictDataset'] diff --git a/borax/datasets.py b/borax/datasets/dict_datasets.py similarity index 94% rename from borax/datasets.py rename to borax/datasets/dict_datasets.py index 3c412a0..669f724 100644 --- a/borax/datasets.py +++ b/borax/datasets/dict_datasets.py @@ -1,7 +1,7 @@ # coding=utf8 -from borax.join_ import join_one, join +from borax.datasets.join_ import join_one, join class DictDataset: diff --git a/borax/join_.py b/borax/datasets/join_.py similarity index 100% rename from borax/join_.py rename to borax/datasets/join_.py diff --git a/docs/changelog.md b/docs/changelog.md index 11e0b90..e95e6b6 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -1,10 +1,12 @@ # 更新日志 -## v3.0.1 +## v3.1.0 -- 新增 `borax.join_` 模块 -- `join_one` 新增 default 参数 -- 修正农历闰月转平月错误的BUG +- `datasets` 包 + - 新增 `borax.datasets。join_` 模块 + - `join_one` 新增 default 参数 +- `calendars.lunardate` 模块 + - 修正农历闰月转平月错误的BUG ([#11](https://github.com/kinegratii/borax/issues/11)) ## v3.0.0 (20191125) diff --git a/docs/guides/join.md b/docs/guides/join.md index f3004ac..cde505c 100644 --- a/docs/guides/join.md +++ b/docs/guides/join.md @@ -1,6 +1,6 @@ # join 模块 -> 模块 `borax.join_` +> 模块 `borax.datasets.join_` 本模块实现了类似于数据库的 JOIN 数据列表操作,从另一个数据集获取某一个或几个列的值。 diff --git a/tests/test_join.py b/tests/test_join.py index c2fe894..d6b6b5e 100644 --- a/tests/test_join.py +++ b/tests/test_join.py @@ -3,7 +3,7 @@ import copy import unittest -from borax.join_ import join_one, join +from borax.datasets.join_ import join_one, join catalogs_dict = { 1: 'Python', From 7599e48bcca2dbe7b3f98cb1e5c01db7d6819fdb Mon Sep 17 00:00:00 2001 From: kinegratii Date: Mon, 6 Jan 2020 00:42:50 +0800 Subject: [PATCH 16/20] Add python38 support for Travis CI build (#12) * :green_heart: Add python3.8 for travis build * :green_heart: Add python3.8 for travis build(Fix) --- .travis.yml | 4 +++- requirements_dev.txt | 8 ++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index 33fc95c..6aa1236 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,13 +2,15 @@ language: python python: - "3.6" - "3.7" + - "3.8" branches: only: - master - develop - /^release-.*$/ + - /^beta-.*$/ install: - pip install -r requirements_dev.txt script: - - nosetests --with-coverage --cover-package borax + - nose2 --with-coverage --coverage borax - flake8 borax tests \ No newline at end of file diff --git a/requirements_dev.txt b/requirements_dev.txt index 701f33f..ae07189 100644 --- a/requirements_dev.txt +++ b/requirements_dev.txt @@ -1,5 +1,5 @@ -nose==1.3.7 -coverage==4.4.1 -flake8==3.6.0 +nose2==0.9.1 +coverage==5.0.1 +flake8==3.7.9 mccabe==0.6.1 -wheel==0.31.1 \ No newline at end of file +wheel==0.33.6 \ No newline at end of file From 7576eb45736d843109b214039b071d69e3197065 Mon Sep 17 00:00:00 2001 From: kinegratii Date: Fri, 10 Jan 2020 21:40:44 +0800 Subject: [PATCH 17/20] :white_check_mark: update tests --- tests/test_string_convert.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/test_string_convert.py b/tests/test_string_convert.py index a2ba946..f2cff7c 100644 --- a/tests/test_string_convert.py +++ b/tests/test_string_convert.py @@ -4,6 +4,7 @@ import unittest from unittest.mock import Mock, patch +from nose2.tools.params import params from borax.strings import camel2snake, snake2camel, get_percentage_display from borax.system import rotate_filename, SUFFIX_DT_UNDERLINE @@ -18,11 +19,10 @@ class StringConvertTestCase(unittest.TestCase): - def test_all(self): - for cs, ss in FIXTURES: - with self.subTest(cs=cs, ss=ss): - self.assertEqual(cs, snake2camel(ss)) - self.assertEqual(ss, camel2snake(cs)) + @params(*FIXTURES) + def test_all(self, cs, ss): + self.assertEqual(cs, snake2camel(ss)) + self.assertEqual(ss, camel2snake(cs)) class PercentageStringTestCase(unittest.TestCase): From 350ff33a8551547bccf9ec7ae61cb6ecebad5fd3 Mon Sep 17 00:00:00 2001 From: kinegratii Date: Fri, 10 Jan 2020 22:08:17 +0800 Subject: [PATCH 18/20] :truck: new borax.datasets.fetch module --- README-en.md | 2 +- README.md | 4 +-- borax/datasets/fetch.py | 76 +++++++++++++++++++++++++++++++++++++++ borax/fetch.py | 78 ++++------------------------------------- docs/guides/fetch.md | 16 +++++---- setup.cfg | 2 +- 6 files changed, 95 insertions(+), 83 deletions(-) create mode 100644 borax/datasets/fetch.py diff --git a/README-en.md b/README-en.md index 942539e..5cb4110 100644 --- a/README-en.md +++ b/README-en.md @@ -131,7 +131,7 @@ See [online document](https://kinegratii.github.io/borax) for more detail, which - [x] [Typing Hints](https://www.python.org/dev/peps/pep-0484/) - [x] [Flake8 Code Style](http://flake8.pycqa.org/en/latest/) -- [x] [nose](https://pypi.org/project/nose/) +- [x] [nose2](https://pypi.org/project/nose2/) - [x] [Travis CI](https://travis-ci.org) - [x] [Docsify](https://docsify.js.org) diff --git a/README.md b/README.md index c2887f5..2409081 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ ## 概述 & 安装 -Borax 是一个的 Python3 开发工具集合库,涉及到: +Borax 是一个 Python3 开发工具集合库,涉及到: - 设计模式 - 数据结构及其实现 @@ -111,7 +111,7 @@ print(names) # ['Alice', 'Bob', 'Charlie'] - [x] [Typing Hints](https://www.python.org/dev/peps/pep-0484/) - [x] [Flake8 Code Style](http://flake8.pycqa.org/en/latest/) -- [x] [nose](https://pypi.org/project/nose/) +- [x] [nose2](https://pypi.org/project/nose2/) - [x] [Travis CI](https://travis-ci.org) - [x] [Docsify](https://docsify.js.org) diff --git a/borax/datasets/fetch.py b/borax/datasets/fetch.py new file mode 100644 index 0000000..f0b0b58 --- /dev/null +++ b/borax/datasets/fetch.py @@ -0,0 +1,76 @@ +# coding=utf8 +""" +fetch is a enhance module with fetch. And adjust the parameter order of calling to fit the habit. +""" +from functools import partial +from itertools import tee + +__all__ = ['Empty', 'fetch', 'ifetch', 'fetch_single', 'ifetch_multiple', 'ifetch_single', 'fetch_as_dict'] + + +class Empty(object): + pass + + +EMPTY = Empty() + + +def bget(obj, key, default=Empty): + try: + return getattr(obj, key) + except AttributeError: + pass + + try: + return obj[key] + except KeyError: + pass + if default is not EMPTY: + return default + + raise ValueError('Item %r has no attr or key for %r' % (obj, key)) + + +def ifetch_single(iterable, key, default=EMPTY, getter=None): + """ + getter() g(item, key):pass + """ + + def _getter(item): + if getter: + custom_getter = partial(getter, key=key) + return custom_getter(item) + else: + return partial(bget, key=key, default=default)(item) + + return map(_getter, iterable) + + +def fetch_single(iterable, key, default=EMPTY, getter=None): + return list(ifetch_single(iterable, key, default=default, getter=getter)) + + +def ifetch_multiple(iterable, *keys, defaults=None, getter=None): + defaults = defaults or {} + if len(keys) > 1: + iters = tee(iterable, len(keys)) + else: + iters = (iterable,) + iters = [ifetch_single(it, key, default=defaults.get(key, EMPTY), getter=getter) for it, key in zip(iters, keys)] + return iters + + +def ifetch(iterable, key, *keys, default=EMPTY, defaults=None, getter=None): + if len(keys) > 0: + keys = (key,) + keys + return map(list, ifetch_multiple(iterable, *keys, defaults=defaults, getter=getter)) + else: + return ifetch_single(iterable, key, default=default, getter=getter) + + +def fetch(iterable, key, *keys, default=EMPTY, defaults=None, getter=None): + return list(ifetch(iterable, key, *keys, default=default, defaults=defaults, getter=getter)) + + +def fetch_as_dict(data, key_field, value_value): + return dict([(bget(item, key_field), bget(item, value_value)) for item in data]) diff --git a/borax/fetch.py b/borax/fetch.py index ad62805..3316167 100644 --- a/borax/fetch.py +++ b/borax/fetch.py @@ -1,76 +1,10 @@ # coding=utf8 -""" -fetch is a enhance module with fetch. And adjust the parameter order of calling to fit the habit. -""" -from functools import partial -from itertools import tee -__all__ = ['fetch', 'ifetch', 'fetch_single', 'ifetch_multiple', 'ifetch_single'] +import warnings +from borax.datasets.fetch import * # noqa: F403 -class Empty(object): - pass - - -EMPTY = Empty() - - -def bget(obj, key, default=Empty): - try: - return getattr(obj, key) - except AttributeError: - pass - - try: - return obj[key] - except KeyError: - pass - if default is not EMPTY: - return default - - raise ValueError('Item %r has no attr or key for %r' % (obj, key)) - - -def ifetch_single(iterable, key, default=EMPTY, getter=None): - """ - getter() g(item, key):pass - """ - - def _getter(item): - if getter: - custom_getter = partial(getter, key=key) - return custom_getter(item) - else: - return partial(bget, key=key, default=default)(item) - - return map(_getter, iterable) - - -def fetch_single(iterable, key, default=EMPTY, getter=None): - return list(ifetch_single(iterable, key, default=default, getter=getter)) - - -def ifetch_multiple(iterable, *keys, defaults=None, getter=None): - defaults = defaults or {} - if len(keys) > 1: - iters = tee(iterable, len(keys)) - else: - iters = (iterable,) - iters = [ifetch_single(it, key, default=defaults.get(key, EMPTY), getter=getter) for it, key in zip(iters, keys)] - return iters - - -def ifetch(iterable, key, *keys, default=EMPTY, defaults=None, getter=None): - if len(keys) > 0: - keys = (key,) + keys - return map(list, ifetch_multiple(iterable, *keys, defaults=defaults, getter=getter)) - else: - return ifetch_single(iterable, key, default=default, getter=getter) - - -def fetch(iterable, key, *keys, default=EMPTY, defaults=None, getter=None): - return list(ifetch(iterable, key, *keys, default=default, defaults=defaults, getter=getter)) - - -def fetch_as_dict(data, key_field, value_value): - return dict([(bget(item, key_field), bget(item, value_value)) for item in data]) +warnings.warn( + 'This module is deprecated and will be removed in V3.3.Use borax.datasets.fetch instead.', + category=PendingDeprecationWarning +) diff --git a/docs/guides/fetch.md b/docs/guides/fetch.md index 216dc85..db0922d 100644 --- a/docs/guides/fetch.md +++ b/docs/guides/fetch.md @@ -1,10 +1,12 @@ # Fetch 模块 -> 模块:`borax.fetch` +> 模块:`borax.datasets.fetch` + +> 引用路径:`borax.fetch` ## 函数接口 -`borax.fetch` 模块实现了从数据列表按照指定的一个或多个属性/键选取数据。 +`borax.datasets.fetch` 模块实现了从数据列表按照指定的一个或多个属性/键选取数据。 `fetch` 模块包含了以下几个函数: @@ -31,7 +33,7 @@ 从 `objects` 数据获取 `name` 的数据。 ```python -from borax.fetch import fetch +from borax.datasets.fetch import fetch objects = [ {'id': 282, 'name': 'Alice', 'age': 30}, @@ -54,7 +56,7 @@ print(names) 从 `objects` 数据获取 `name` 和 `age` 的数据。 ```python -from borax.fetch import fetch +from borax.datasets.fetch import fetch objects = [ {'id': 282, 'name': 'Alice', 'age': 30}, @@ -79,7 +81,7 @@ print(ages) 当 `iterable` 数据列表缺少某个属性/键,可以通过指定 `default` 或 `defaults` 参数提供默认值。 ```python -from borax.fetch import fetch +from borax.datasets.fetch import fetch objects = [ {'id': 282, 'name': 'Alice', 'age': 30, 'gender': 'female'}, @@ -113,7 +115,7 @@ Demo for multiple default values 除了上述的键值访问方式,`fetch` 函数还内置属性访问的获取方式。 ```python -from borax.fetch import fetch +from borax.datasets.fetch import fetch class Point: def __init__(self, x, y, z): @@ -163,7 +165,7 @@ getter 需满足下列的几个条件: 例子: ```python -from borax.fetch import fetch +from borax.datasets.fetch import fetch class Point: diff --git a/setup.cfg b/setup.cfg index db9f8ef..52563e9 100644 --- a/setup.cfg +++ b/setup.cfg @@ -5,5 +5,5 @@ long_description = file: long_description.rst universal = 1 [flake8] -ignore = E743,E501 +ignore = E743,E501,F401 max-complexity = 10 \ No newline at end of file From 8c36ac9c2332c582c586ebc62fe1c505870797cd Mon Sep 17 00:00:00 2001 From: kinegratii Date: Tue, 14 Jan 2020 00:11:02 +0800 Subject: [PATCH 19/20] :pencil: Update docs --- docs/_sidebar.md | 1 - docs/changelog.md | 8 +++- docs/guides/admin_decorators.md | 74 --------------------------------- 3 files changed, 6 insertions(+), 77 deletions(-) delete mode 100644 docs/guides/admin_decorators.md diff --git a/docs/_sidebar.md b/docs/_sidebar.md index c7d7bbb..23833ca 100644 --- a/docs/_sidebar.md +++ b/docs/_sidebar.md @@ -15,7 +15,6 @@ - [序列号生成器](guides/serial_generator) - [百分比](guides/percentage) - [数据拾取](guides/fetch) - - [Django-Admin装饰器](guides/admin_decorators) - [bjson](guides/bjson) - [cjson](guides/cjson) - [财务工具](guides/finance) diff --git a/docs/changelog.md b/docs/changelog.md index e95e6b6..ef03c65 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -2,11 +2,16 @@ ## v3.1.0 +> 新增 Python3.8构建 + - `datasets` 包 - - 新增 `borax.datasets。join_` 模块 + - 新增 `borax.datasets.fetch` + - 新增 `borax.datasets.join_` 模块 - `join_one` 新增 default 参数 - `calendars.lunardate` 模块 - 修正农历闰月转平月错误的BUG ([#11](https://github.com/kinegratii/borax/issues/11)) +- `borax.fetch` 模块 + - 本模块被标记为 PendingDeprecationWarning ,将在V3.3移除 ## v3.0.0 (20191125) @@ -20,7 +25,6 @@ - `financial_amount_capital` 新增上下限检查 - 移除 `borax.loader` - 移除 `borax.decorators.admin` -- 新增 Python3.8构建支持 ## v1.4.2 (20190717) diff --git a/docs/guides/admin_decorators.md b/docs/guides/admin_decorators.md deleted file mode 100644 index daa5de9..0000000 --- a/docs/guides/admin_decorators.md +++ /dev/null @@ -1,74 +0,0 @@ -# decorators.admin 模块 - -> 模块: `borax.decorators.admin` - -> 本模块已废弃,将在 v2.0 移除。 - -## attr - -函数签名 - -``` -attr(**kwargs) -``` - -设置函数对象的属性。 - -## display_field - -函数签名 - -``` -display_field(short_description, admin_order_field=None, **kwargs) -``` - -使用装饰器定义回调函数的 [list_display](https://docs.djangoproject.com/en/2.0/ref/contrib/admin/#django.contrib.admin.ModelAdmin.list_display) 。 - - -原始例子: - -```python -def upper_case_name(obj): - return ("%s %s" % (obj.first_name, obj.last_name)).upper() -upper_case_name.short_description = 'Name' - -class PersonAdmin(admin.ModelAdmin): - list_display = (upper_case_name,) -``` - -使用 `@display_field` 改写如下: - -```python -@display_field(short_description='Name') -def upper_case_name(obj): - return ("%s %s" % (obj.first_name, obj.last_name)).upper() - -class PersonAdmin(admin.ModelAdmin): - list_display = (upper_case_name,) -``` - -## action - -函数签名 - -``` -action(short_description=None, allowed_permissions=None, **kwargs) -``` - -使用装饰器定义 [action](https://docs.djangoproject.com/en/2.0/ref/contrib/admin/actions/#writing-action-functions) 函数 。 - -例子: - -```python -def make_published(modeladmin, request, queryset): - queryset.update(status='p') -make_published.short_description = "Mark selected stories as published" -``` - -改写后: - -```python -@action(short_description="Mark selected stories as published") -def make_published(modeladmin, request, queryset): - queryset.update(status='p') -``` \ No newline at end of file From ba81d63d364ad3807fcb4f66a4c84be2bd68b523 Mon Sep 17 00:00:00 2001 From: kinegratii Date: Sat, 18 Jan 2020 20:21:31 +0800 Subject: [PATCH 20/20] :bookmark: release v3.1.0 --- borax/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/borax/__init__.py b/borax/__init__.py index 40a7c9d..24b3c9b 100644 --- a/borax/__init__.py +++ b/borax/__init__.py @@ -1,4 +1,4 @@ # coding=utf8 -__version__ = '3.0.0' +__version__ = '3.1.0' __author__ = 'kinegratii'