From 11d21b5d11411d5853626f06493e5ea0fb63ce39 Mon Sep 17 00:00:00 2001 From: kinegratii Date: Sat, 8 Aug 2020 18:37:50 +0800 Subject: [PATCH 01/11] :bug: Fix string paramter for financial_amount_capital --- borax/finance.py | 2 +- tests/test_finance.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/borax/finance.py b/borax/finance.py index ef704c4..9e2256e 100644 --- a/borax/finance.py +++ b/borax/finance.py @@ -22,7 +22,7 @@ def financial_amount_capital(num: Union[int, float, Decimal, str]) -> str: units = '仟佰拾亿仟佰拾万仟佰拾元角分' digits = '零壹贰叁肆伍陆柒捌玖' if isinstance(num, str): - _n = int(num) + _n = Decimal(num) else: _n = num if _n < 0 or _n >= MAX_VALUE_LIMIT: diff --git a/tests/test_finance.py b/tests/test_finance.py index 95e4c0f..3a82187 100644 --- a/tests/test_finance.py +++ b/tests/test_finance.py @@ -18,6 +18,7 @@ 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'))) + self.assertEqual('壹拾万柒仟元伍角叁分', financial_amount_capital('107000.53')) def test_valid_range(self): with self.assertRaises(ValueError): From ac5e3ae2ac6201b4564a8653e42ca9e4000eabe0 Mon Sep 17 00:00:00 2001 From: kinegratii Date: Sat, 8 Aug 2020 20:54:38 +0800 Subject: [PATCH 02/11] :fire: remove borax.decorators module --- borax/decorators/__init__.py | 0 setup.cfg | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) delete mode 100644 borax/decorators/__init__.py diff --git a/borax/decorators/__init__.py b/borax/decorators/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/setup.cfg b/setup.cfg index 52563e9..b2aa626 100644 --- a/setup.cfg +++ b/setup.cfg @@ -6,4 +6,4 @@ universal = 1 [flake8] ignore = E743,E501,F401 -max-complexity = 10 \ No newline at end of file +max-complexity = 12 \ No newline at end of file From 495947aa2da09625704f56030fa4dc5da30fb4ca Mon Sep 17 00:00:00 2001 From: kinegratii Date: Sat, 8 Aug 2020 20:59:17 +0800 Subject: [PATCH 03/11] :fire: remove borax.fetch module --- README-en.md | 2 +- README.md | 2 +- borax/fetch.py | 10 ---------- tests/test_fetch.py | 2 +- 4 files changed, 3 insertions(+), 13 deletions(-) delete mode 100644 borax/fetch.py diff --git a/README-en.md b/README-en.md index 5cb4110..87d60e8 100644 --- a/README-en.md +++ b/README-en.md @@ -105,7 +105,7 @@ A function sets for fetch the values of some axises. Get list values from dict list. ```python -from borax.fetch import fetch +from borax.datasets.fetch import fetch objects = [ {'id': 282, 'name': 'Alice', 'age': 30}, diff --git a/README.md b/README.md index 2409081..0ac0899 100644 --- a/README.md +++ b/README.md @@ -91,7 +91,7 @@ print(dls.countdown()) # 344 从数据序列中选择一个或多个字段的数据。 ```python -from borax.fetch import fetch +from borax.datasets.fetch import fetch objects = [ {'id': 282, 'name': 'Alice', 'age': 30}, diff --git a/borax/fetch.py b/borax/fetch.py deleted file mode 100644 index ae79796..0000000 --- a/borax/fetch.py +++ /dev/null @@ -1,10 +0,0 @@ -# coding=utf8 - -import warnings - -from borax.datasets.fetch import * # noqa: F403 - -warnings.warn( - 'This module is deprecated and will be removed in V3.3.Use borax.datasets.fetch instead.', - category=DeprecationWarning -) diff --git a/tests/test_fetch.py b/tests/test_fetch.py index cf8fbfa..3e63992 100644 --- a/tests/test_fetch.py +++ b/tests/test_fetch.py @@ -3,7 +3,7 @@ import unittest -from borax.fetch import fetch, fetch_single, ifetch_multiple, fetch_as_dict +from borax.datasets.fetch import fetch, fetch_single, ifetch_multiple, fetch_as_dict DICT_LIST_DATA = [ {'id': 282, 'name': 'Alice', 'age': 30, 'sex': 'female'}, From 32ecc08832def5f0dd1befe783a34bd3e6a6da3c Mon Sep 17 00:00:00 2001 From: kinegratii Date: Sat, 8 Aug 2020 21:24:29 +0800 Subject: [PATCH 04/11] :sparkles: add borax.numbers module --- borax/finance.py | 41 ++----------------- borax/numbers.py | 78 ++++++++++++++++++++++++++++++++++++ tests/test_chinese_number.py | 15 +++++++ 3 files changed, 96 insertions(+), 38 deletions(-) create mode 100644 borax/numbers.py create mode 100644 tests/test_chinese_number.py diff --git a/borax/finance.py b/borax/finance.py index 9e2256e..02b317d 100644 --- a/borax/finance.py +++ b/borax/finance.py @@ -1,42 +1,7 @@ # coding=utf8 -import re -from decimal import Decimal +from borax.numbers import FinanceNumbers -from typing import Union +__all__ = ['financial_amount_capital'] -RULES = [ - (r'零角零分$', '整'), - (r'零[仟佰拾]', '零'), - (r'零{2,}', '零'), - (r'零([亿|万])', r'\g<1>'), - (r'零+元', '元'), - (r'亿零{0,3}万', '亿'), - (r'^元', '零元') -] - -MAX_VALUE_LIMIT = 1000000000000 - - -def financial_amount_capital(num: Union[int, float, Decimal, str]) -> str: - units = '仟佰拾亿仟佰拾万仟佰拾元角分' - digits = '零壹贰叁肆伍陆柒捌玖' - if isinstance(num, str): - _n = Decimal(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('.') - if dot_pos > -1: - num_str = num_str[:dot_pos] + num_str[dot_pos + 1:dot_pos + 3] - capital_str = ''.join([digits[int(i)] for i in num_str]) - s_units = units[len(units) - len(num_str):] - - o = ''.join('{}{}'.format(u, d) for u, d in zip(capital_str, s_units)) - for p, d in RULES: - o = re.sub(p, d, o) - - return o +financial_amount_capital = FinanceNumbers.to_capital_str diff --git a/borax/numbers.py b/borax/numbers.py new file mode 100644 index 0000000..b02ded7 --- /dev/null +++ b/borax/numbers.py @@ -0,0 +1,78 @@ +# coding=utf8 + + +import re +from decimal import Decimal + +from typing import Union + +MAX_VALUE_LIMIT = 1000000000000 + + +class ChineseNumbers: + RULES = [ + (r'一十', '十'), + (r'零[千百十]', '零'), + (r'零{2,}', '零'), + (r'零([亿|万])', r'\g<1>'), + (r'亿零{0,3}万', '亿'), + (r'零 ', ''), + ] + + @staticmethod + def to_chinese_number(num: Union[int, 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) + capital_str = ''.join([digits[int(i)] for i in num_str]) + s_units = units[len(units) - len(num_str):] + + o = ''.join('{}{}'.format(u, d) for u, d in zip(capital_str, s_units)) + for p, d in ChineseNumbers.RULES: + o = re.sub(p, d, o) + if 10 <= _n < 20: + o.replace('一十', '十') + + return o + + +class FinanceNumbers: + RULES = [ + (r'零角零分$', '整'), + (r'零[仟佰拾]', '零'), + (r'零{2,}', '零'), + (r'零([亿|万])', r'\g<1>'), + (r'零+元', '元'), + (r'亿零{0,3}万', '亿'), + (r'^元', '零元') + ] + + @staticmethod + def to_capital_str(num: Union[int, float, Decimal, str]) -> str: + units = '仟佰拾亿仟佰拾万仟佰拾元角分' + digits = '零壹贰叁肆伍陆柒捌玖' + if isinstance(num, str): + _n = Decimal(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('.') + if dot_pos > -1: + num_str = num_str[:dot_pos] + num_str[dot_pos + 1:dot_pos + 3] + capital_str = ''.join([digits[int(i)] for i in num_str]) + s_units = units[len(units) - len(num_str):] + + o = ''.join('{}{}'.format(u, d) for u, d in zip(capital_str, s_units)) + for p, d in FinanceNumbers.RULES: + o = re.sub(p, d, o) + + return o diff --git a/tests/test_chinese_number.py b/tests/test_chinese_number.py new file mode 100644 index 0000000..0b185eb --- /dev/null +++ b/tests/test_chinese_number.py @@ -0,0 +1,15 @@ +# coding=utf8 + +import decimal +import unittest + +from borax.numbers import ChineseNumbers + +decimal.getcontext().prec = 2 + + +class ChineseNumberTestCase(unittest.TestCase): + def test_chinese_number(self): + self.assertEqual('一亿', ChineseNumbers.to_chinese_number(100000000)) + with self.assertRaises(ValueError): + ChineseNumbers.to_chinese_number(-1) From 2aec7b89be8f083580a4f41d8ad58b4318a73878 Mon Sep 17 00:00:00 2001 From: kinegratii Date: Sat, 8 Aug 2020 22:06:59 +0800 Subject: [PATCH 05/11] :pencil: Update documents --- LICENSE | 2 +- README.md | 15 ++++++++----- docs/_sidebar.md | 2 +- docs/changelog.md | 7 +++++++ docs/guides/{finance.md => numbers.md} | 29 ++++++++++++++++++-------- 5 files changed, 39 insertions(+), 16 deletions(-) rename docs/guides/{finance.md => numbers.md} (85%) diff --git a/LICENSE b/LICENSE index 5240b15..516ead5 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2015-2019 kinegratii +Copyright (c) 2015-2020 kinegratii Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in diff --git a/README.md b/README.md index 0ac0899..8a9a3bf 100644 --- a/README.md +++ b/README.md @@ -77,12 +77,12 @@ print(dls.countdown()) # 344 将金额转化为符合标准的大写数字。 ``` ->>> from borax.finance import financial_amount_capital ->>> financial_amount_capital(100000000) +>>> from borax.numbers import FinanceNumbers +>>> FinanceNumbers.to_capital_str(100000000) '壹亿元整' ->>>financial_amount_capital(4578442.23) +>>>FinanceNumbers.to_capital_str(4578442.23) '肆佰伍拾柒万捌仟肆佰肆拾贰元贰角叁分' ->>>financial_amount_capital(107000.53) +>>>FinanceNumbers.to_capital_str(107000.53) 壹拾万柒仟元伍角叁分 ``` @@ -105,7 +105,12 @@ print(names) # ['Alice', 'Bob', 'Charlie'] ## 文档 -在线文档托管在 [https://kinegratii.github.io/borax](https://kinegratii.github.io/borax) ,由 [docsify](https://docsify.js.org/) 构建。 +文档由 [docsify](https://docsify.js.org/) 构建。 + +| 源 | 网址 | +| ---- | ---- | +| github | [https://kinegratii.github.io/borax](https://kinegratii.github.io/borax) | +| gitee | [https://kinegratii.gitee.io/borax](https://kinegratii.gitee.io/borax) | ## 开发特性和规范 diff --git a/docs/_sidebar.md b/docs/_sidebar.md index 23833ca..a23c6b4 100644 --- a/docs/_sidebar.md +++ b/docs/_sidebar.md @@ -17,7 +17,7 @@ - [数据拾取](guides/fetch) - [bjson](guides/bjson) - [cjson](guides/cjson) - - [财务工具](guides/finance) + - [数字模块](guides/numbers) - [Tkinter界面](guides/ui) - **开发** - [版本日志](changelog) \ No newline at end of file diff --git a/docs/changelog.md b/docs/changelog.md index 5705777..324fccb 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -1,5 +1,12 @@ # 更新日志 +## v3.3.0 + +- 移除 `borax.fetch` 模块 +- `borax.numbers` 模块 (+) +- `borax.finance` 模块 + - 修正小数使用字符串时 `financial_amount_capital` 错误的BUG + ## v3.2.0 (20200510) > 本版本重写 `borax.datasets.join_` 模块,接口引入重大变更,详情查看 [join模块](guides/join) 。 diff --git a/docs/guides/finance.md b/docs/guides/numbers.md similarity index 85% rename from docs/guides/finance.md rename to docs/guides/numbers.md index 05d7450..3bc16c9 100644 --- a/docs/guides/finance.md +++ b/docs/guides/numbers.md @@ -1,10 +1,21 @@ -# Finance 模块 +# numbers 模块 -> 模块:`borax.finance` +> 模块:`borax.numbers` -finance 提供了一系列的此物财务金融工具。 +## 中文数字 + +```python + +from borax.numbers import ChineseNumbers + +print(ChineseNumbers.to_chinese_number(204)) # 二百零四 -## 大写金额 +``` + + +## 财务大写金额 + +finance 提供了一系列的此物财务金融工具。 ### 规范依据 @@ -31,7 +42,7 @@ finance 提供了一系列的此物财务金融工具。 将数字转化为财务大写金额的字符串,函数签名: ```python -def financial_amount_capital(num: Union[int, float, Decimal, str]) -> str: pass +to_capital_str(num: Union[int, float, Decimal, str]) -> str ``` 输入值可以为以下几种类型: @@ -43,11 +54,11 @@ def financial_amount_capital(num: Union[int, float, Decimal, str]) -> str: pass 例子: ``` ->>> from borax.finance import financial_amount_capital ->>> financial_amount_capital(100000000) +>>> from borax.numbers import FinanceNumbers +>>> FinanceNumbers.to_capital_str(100000000) '壹亿元整' ->>>financial_amount_capital(4578442.23) +>>>FinanceNumbers.to_capital_str(4578442.23) '肆佰伍拾柒万捌仟肆佰肆拾贰元贰角叁分' ->>>financial_amount_capital(107000.53) +>>>FinanceNumbers.to_capital_str(107000.53) 壹拾万柒仟元伍角叁分 ``` \ No newline at end of file From 86681269fe7365425ddb101ad9802981eb262348 Mon Sep 17 00:00:00 2001 From: kinegratii Date: Mon, 10 Aug 2020 21:03:25 +0800 Subject: [PATCH 06/11] :sparkles: Make financial_amount_capital deprecated --- borax/finance.py | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/borax/finance.py b/borax/finance.py index 02b317d..065399c 100644 --- a/borax/finance.py +++ b/borax/finance.py @@ -1,7 +1,20 @@ # coding=utf8 +from decimal import Decimal + +from typing import Union + +import warnings + from borax.numbers import FinanceNumbers __all__ = ['financial_amount_capital'] -financial_amount_capital = FinanceNumbers.to_capital_str + +def financial_amount_capital(num: Union[int, float, Decimal, str]) -> str: + warnings.warn( + 'This method is deprecated and will be removed in V3.5.Use borax.numbers.FinanceNumbers instead.', + category=PendingDeprecationWarning + ) + + return FinanceNumbers.to_capital_str(num) From 8518899d2b9ff14aaa293c82b552a377e9b02bf3 Mon Sep 17 00:00:00 2001 From: kinegratii Date: Mon, 10 Aug 2020 22:09:22 +0800 Subject: [PATCH 07/11] :sparkles: Add borax.runtime module --- borax/runtime.py | 43 ++++++++++++++++++++++++++++++++++ tests/test_runtime_measurer.py | 28 ++++++++++++++++++++++ 2 files changed, 71 insertions(+) create mode 100644 borax/runtime.py create mode 100644 tests/test_runtime_measurer.py diff --git a/borax/runtime.py b/borax/runtime.py new file mode 100644 index 0000000..217a8e3 --- /dev/null +++ b/borax/runtime.py @@ -0,0 +1,43 @@ +# coding=utf8 + + +import time +from collections import defaultdict +from contextlib import contextmanager + + +class RuntimeMeasurer: + def __init__(self): + self._data = defaultdict(list) + self._start_time_dict = {} + + def start(self, tag, *tags): + tags = (tag,) + tags + st = time.time() + for _tag in tags: + self._start_time_dict[_tag] = st + + def end(self, tag, *tags): + tags = (tag,) + tags + et = time.time() + for _tag in tags: + if _tag in self._start_time_dict: + self._data[_tag].append(et - self._start_time_dict[_tag]) + + @contextmanager + def measure(self, tag, *tags): + try: + self.start(tag, *tags) + yield + finally: + self.end(tag, *tags) + + def get_measure_data(self): + data = [] + for tag, values in self._data.items(): + data.append({ + 'tag': tag, + 'total': len(values), + 'avg': sum(values) / len(values) + }) + return data diff --git a/tests/test_runtime_measurer.py b/tests/test_runtime_measurer.py new file mode 100644 index 0000000..cec7fd5 --- /dev/null +++ b/tests/test_runtime_measurer.py @@ -0,0 +1,28 @@ +# coding=utf8 +import time +import unittest + +from borax.runtime import RuntimeMeasurer + + +def long_operate(): + time.sleep(1) + + +class RuntimeMeasurerTestCase(unittest.TestCase): + def test_one_hit(self): + rm = RuntimeMeasurer() + rm.start('xt') + long_operate() + rm.end('xt') + data = rm.get_measure_data()[0] + self.assertEqual(1, data['total']) + self.assertAlmostEqual(1, data['avg'], places=2) + + def test_with(self): + rm = RuntimeMeasurer() + with rm.measure('xt'): + long_operate() + data = rm.get_measure_data()[0] + self.assertEqual(1, data['total']) + self.assertAlmostEqual(1, data['avg'], places=2) From d656bc03fae48babfcb1c458d745c0566714b58c Mon Sep 17 00:00:00 2001 From: kinegratii Date: Tue, 11 Aug 2020 21:33:06 +0800 Subject: [PATCH 08/11] :fire: remove borax.dic module --- borax/structures/dic.py | 49 ------------------------ borax/structures/dictionary.py | 18 +++++++++ docs/guides/alias_dictionary.md | 7 ---- docs/guides/percentage.md | 1 + tests/test_alias_dictionary.py | 64 -------------------------------- tests/test_dictionary.py | 66 ++++++++++++++++++++++++++++----- 6 files changed, 76 insertions(+), 129 deletions(-) delete mode 100644 borax/structures/dic.py delete mode 100644 docs/guides/alias_dictionary.md delete mode 100644 tests/test_alias_dictionary.py diff --git a/borax/structures/dic.py b/borax/structures/dic.py deleted file mode 100644 index fe5583b..0000000 --- a/borax/structures/dic.py +++ /dev/null @@ -1,49 +0,0 @@ -# coding=utf8 -"""See more detail at https://github.com/fabric/fabric/blob/1.13.1/fabric/utils.py. -""" - - -class AttributeDict(dict): - def __getattr__(self, key): - try: - return self[key] - except KeyError: - # to conform with __getattr__ spec - raise AttributeError(key) - - def __setattr__(self, key, value): - self[key] = value - - def first(self, *names): - for name in names: - value = self.get(name) - if value: - return value - - -class AliasDict(AttributeDict): - def __init__(self, arg=None, aliases=None): - init = super(AliasDict, self).__init__ - if arg is not None: - init(arg) - else: - init() - # Can't use super() here because of _AttributeDict's setattr override - dict.__setattr__(self, 'aliases', aliases) - - def __setitem__(self, key, value): - # Attr test required to not blow up when deepcopy'd - if hasattr(self, 'aliases') and key in self.aliases: - for aliased in self.aliases[key]: - self[aliased] = value - else: - return super(AliasDict, self).__setitem__(key, value) - - def expand_aliases(self, keys): - ret = [] - for key in keys: - if key in self.aliases: - ret.extend(self.expand_aliases(self.aliases[key])) - else: - ret.append(key) - return ret diff --git a/borax/structures/dictionary.py b/borax/structures/dictionary.py index 20e59b3..8f8d666 100644 --- a/borax/structures/dictionary.py +++ b/borax/structures/dictionary.py @@ -53,3 +53,21 @@ def get_available_items(self): for key, value in self._data.items(): aliases = [k for k, v in self._aliases.items() if v == key] yield key, value, aliases + + +class AttributeDict(dict): + def __getattr__(self, key): + try: + return self[key] + except KeyError: + # to conform with __getattr__ spec + raise AttributeError(key) + + def __setattr__(self, key, value): + self[key] = value + + def first(self, *names): + for name in names: + value = self.get(name) + if value: + return value diff --git a/docs/guides/alias_dictionary.md b/docs/guides/alias_dictionary.md deleted file mode 100644 index 92fbc0d..0000000 --- a/docs/guides/alias_dictionary.md +++ /dev/null @@ -1,7 +0,0 @@ -# AliasDictionary 模块 - -> 模块: `borax.structures.dictionary` - -## 概述 - -别名字典(`AliasDictionary`), 允许定义一个字典的键的别名,并使用该别名访问字典的内容。 \ No newline at end of file diff --git a/docs/guides/percentage.md b/docs/guides/percentage.md index 48da30a..a64d453 100644 --- a/docs/guides/percentage.md +++ b/docs/guides/percentage.md @@ -37,6 +37,7 @@ def __init__(self, *, total=100, completed=0, places=2, display_fmt='{completed} | completed | int | 完成数目 | | places | int | 百分比的小数点,如 place=2,时显示为 34.56% | | display_fmt | string | 显示格式字符串,可用变量:total, completed | +| null_val | string | 空值的字符串形式 | ### 数据属性 diff --git a/tests/test_alias_dictionary.py b/tests/test_alias_dictionary.py deleted file mode 100644 index eafb1b5..0000000 --- a/tests/test_alias_dictionary.py +++ /dev/null @@ -1,64 +0,0 @@ -# coding=utf8 - -from unittest import TestCase - -from borax.structures.dictionary import AliasDictionary - -demo_data = { - 'alias': { - 'A': 'a', - 'A1': 'a', - 'B': 'b', - 'D': 'd', - 'P': 'e' - }, - 'data': { - 'a': 'apple', - 'b': 'banana', - 'e': 'egg', - 'o': 'orange', - 'P': 'pear' - - } -} - - -class AliasDictionaryTestCase(TestCase): - def test_test(self): - ad = AliasDictionary(demo_data['data'], demo_data['alias']) - self.assertEqual('apple', ad.get('a')) - self.assertEqual('CC', ad.get('c', 'CC')) - - def test_get_item(self): - ad = AliasDictionary(demo_data['data'], demo_data['alias']) - self.assertTupleEqual( - ('a', 'a', 'apple'), - ad.get_item('a') - ) - self.assertTupleEqual( - ('A', 'a', 'apple'), - ad.get_item('A') - ) - self.assertTupleEqual( - ('P', 'P', 'pear'), - ad.get_item('P') - ) - - with self.assertRaises(KeyError): - ad.get_item('D') - self.assertTupleEqual( - ('D', None, 'D'), - ad.get_item('D', default='D') - ) - with self.assertRaises(KeyError): - ad.get_item('E') - self.assertTupleEqual( - ('E', None, 'E'), - ad.get_item('E', default='E') - ) - - def test_get_available_items(self): - ad = AliasDictionary(demo_data['data'], demo_data['alias']) - for key, value, aliases in ad.get_available_items(): - if key == 'a': - self.assertSetEqual({'A', 'A1'}, set(aliases)) diff --git a/tests/test_dictionary.py b/tests/test_dictionary.py index 961fb5c..61ae68b 100644 --- a/tests/test_dictionary.py +++ b/tests/test_dictionary.py @@ -2,7 +2,7 @@ import unittest -from borax.structures.dic import AttributeDict, AliasDict +from borax.structures.dictionary import AliasDictionary, AttributeDict class AttributeDictTestCase(unittest.TestCase): @@ -18,13 +18,61 @@ def test_first(self): self.assertEqual('bar', value) -class AliasDictTestCase(unittest.TestCase): - def test_base(self): - ad = AliasDict( - {'biz': True, 'baz': False}, - aliases={'foo': ['bar', 'biz', 'baz']} +demo_data = { + 'alias': { + 'A': 'a', + 'A1': 'a', + 'B': 'b', + 'D': 'd', + 'P': 'e' + }, + 'data': { + 'a': 'apple', + 'b': 'banana', + 'e': 'egg', + 'o': 'orange', + 'P': 'pear' + + } +} + + +class AliasDictionaryTestCase(unittest.TestCase): + def test_test(self): + ad = AliasDictionary(demo_data['data'], demo_data['alias']) + self.assertEqual('apple', ad.get('a')) + self.assertEqual('CC', ad.get('c', 'CC')) + + def test_get_item(self): + ad = AliasDictionary(demo_data['data'], demo_data['alias']) + self.assertTupleEqual( + ('a', 'a', 'apple'), + ad.get_item('a') + ) + self.assertTupleEqual( + ('A', 'a', 'apple'), + ad.get_item('A') + ) + self.assertTupleEqual( + ('P', 'P', 'pear'), + ad.get_item('P') + ) + + with self.assertRaises(KeyError): + ad.get_item('D') + self.assertTupleEqual( + ('D', None, 'D'), + ad.get_item('D', default='D') + ) + with self.assertRaises(KeyError): + ad.get_item('E') + self.assertTupleEqual( + ('E', None, 'E'), + ad.get_item('E', default='E') ) - self.assertEqual(False, ad['baz']) - ad['foo'] = True - self.assertEqual(True, ad['baz']) + def test_get_available_items(self): + ad = AliasDictionary(demo_data['data'], demo_data['alias']) + for key, value, aliases in ad.get_available_items(): + if key == 'a': + self.assertSetEqual({'A', 'A1'}, set(aliases)) From 81bec3c31b3927f9fe399d53aaf192a57753fba8 Mon Sep 17 00:00:00 2001 From: kinegratii Date: Fri, 14 Aug 2020 15:57:38 +0800 Subject: [PATCH 09/11] :fire: Remove borax.cli package --- borax/cli/__init__.py | 0 borax/cli/commands/__init__.py | 0 borax/cli/commands/mpi.py | 87 ---------------------------------- borax/cli/main.py | 36 -------------- 4 files changed, 123 deletions(-) delete mode 100644 borax/cli/__init__.py delete mode 100644 borax/cli/commands/__init__.py delete mode 100644 borax/cli/commands/mpi.py delete mode 100644 borax/cli/main.py diff --git a/borax/cli/__init__.py b/borax/cli/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/borax/cli/commands/__init__.py b/borax/cli/commands/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/borax/cli/commands/mpi.py b/borax/cli/commands/mpi.py deleted file mode 100644 index c2598bf..0000000 --- a/borax/cli/commands/mpi.py +++ /dev/null @@ -1,87 +0,0 @@ -# coding=utf8 -""" -borax-cli mpi -""" -import os -import platform -import configparser - -import click - -BUILTIN_URLS = { - "pypi": "https://pypi.python.org/simple", - "tuna": "https://pypi.tuna.tsinghua.edu.cn/simple", - "douban": "https://pypi.doubanio.com/simple", - "aliyun": "https://mirrors.aliyun.com/pypi/simple", - "ustc": "https://mirrors.ustc.edu.cn/pypi/web/simple" -} - -SECTION_KEY = 'global' -VALUE_KEY = 'index-url' - - -def get_user_config_path(): - if 'Windows' in platform.system(): - config_path = r'~\pip\pip.ini' - else: - config_path = r'~/.pip/pip.conf' - return os.path.expanduser(config_path) - - -def read_url(path): - cp = configparser.ConfigParser() - try: - cp.read(path) - return cp.get(SECTION_KEY, VALUE_KEY) - except configparser.Error: - return None - - -def write_url(path, url): - cp = configparser.ConfigParser() - cp.read(path) - if not cp.has_section(SECTION_KEY): - cp.add_section(SECTION_KEY) - cp.set(SECTION_KEY, VALUE_KEY, url) - with open(path, 'w+') as f: - cp.write(f) - - -@click.command() -@click.option('--name', help='The builtin name of PyPI url.') -@click.option('--url', help='The url of PyPI') -@click.option('--path', help='The pip config path.') -def cli(name, url, path): - if not path: - path = get_user_config_path() - click.secho('[Info] PIP config file: {}\n'.format(path)) - if name is None and url is None: - current = read_url(path) - url_list = [] - for name, url in BUILTIN_URLS.items(): - url_list.append( - ' {0:<3}{1:<10}{2}'.format( - '*' if url == current else ' ', # [' ', '*'][url==current] - name, - url - ) - ) - click.echo('\n'.join(url_list)) - return - if name: - target = BUILTIN_URLS.get(name, None) - if target: - write_url(path, target) - click.secho('[Success] ', nl=False, fg='green') - click.echo('The PyPI index-url has set to {}'.format(target)) - else: - click.secho('[Error] ', nl=False, fg='red') - click.echo('Invalid name for PyPI.Choices are: {}'.format(' '.join(BUILTIN_URLS.keys()))) - else: - if url: - write_url(path, url) - click.secho('[Success] ', nl=False, fg='green') - click.echo('The PyPI index-url has set to {}'.format(url)) - else: - click.secho('[Error] ', nl=False, fg='red') - click.echo('Invalid url for PyPI.') diff --git a/borax/cli/main.py b/borax/cli/main.py deleted file mode 100644 index 1cfcfdc..0000000 --- a/borax/cli/main.py +++ /dev/null @@ -1,36 +0,0 @@ -# coding=utf8 -""" -CLI entry -""" -import os -import click - -plugin_folder = os.path.join(os.path.dirname(__file__), 'commands') - - -class MyCLI(click.MultiCommand): - def list_commands(self, ctx): - rv = [] - for filename in os.listdir(plugin_folder): - # Exclude private module - if not filename.startswith('_') and filename.endswith('.py'): - rv.append(filename.lstrip('_')[:-3]) - rv.sort() - return rv - - def get_command(self, ctx, name): - ns = {} - fn = os.path.join(plugin_folder, name + '.py') - with open(fn) as f: - code = compile(f.read(), fn, 'exec') - eval(code, ns, ns) - return ns['cli'] - - -@click.command(cls=MyCLI) -def cli(): - pass - - -if __name__ == '__main__': - cli() From dfdce701e9418630a6b80fe652f9a827da03acbb Mon Sep 17 00:00:00 2001 From: kinegratii Date: Sat, 15 Aug 2020 09:41:14 +0800 Subject: [PATCH 10/11] :pencil: Update docs --- README-en.md | 30 ++++++++++++++++++++++++++++-- README.md | 23 ++++++++++++++++++++++- docs/README.md | 15 +++------------ docs/_sidebar.md | 1 - docs/changelog.md | 9 ++++++++- docs/guides/bjson.md | 12 ++++++++++++ docs/guides/cjson.md | 11 +++++++++++ docs/guides/numbers.md | 2 ++ docs/guides/serial_generator.md | 2 +- docs/guides/tree.md | 6 ++++-- docs/index.html | 2 +- docs/quickstart.md | 10 +--------- long_description.rst | 8 ++++++-- pyproject.toml | 4 ++-- 14 files changed, 101 insertions(+), 34 deletions(-) diff --git a/README-en.md b/README-en.md index 87d60e8..19b20bd 100644 --- a/README-en.md +++ b/README-en.md @@ -125,7 +125,12 @@ Output ## Document -See [online document](https://kinegratii.github.io/borax) for more detail, which is powered by [docsify](https://docsify.js.org/) . +The document site is powered by [docsify](https://docsify.js.org/), and hosted on the folowing site: + +| Source | Page Link | +| ---- | ---- | +| github | [https://kinegratii.github.io/borax](https://kinegratii.github.io/borax) | +| gitee | [https://kinegratii.gitee.io/borax](https://kinegratii.gitee.io/borax) | ## Development Features @@ -137,4 +142,25 @@ See [online document](https://kinegratii.github.io/borax) for more detail, which ## License -This project is issued with MIT License, see LICENSE file for more detail. \ No newline at end of file +``` +The MIT License (MIT) + +Copyright (c) 2015-2020 kinegratii + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +``` \ No newline at end of file diff --git a/README.md b/README.md index 8a9a3bf..657bf20 100644 --- a/README.md +++ b/README.md @@ -122,7 +122,28 @@ print(names) # ['Alice', 'Bob', 'Charlie'] ## 开源协议 -MIT License (MIT) +``` +The MIT License (MIT) + +Copyright (c) 2015-2020 kinegratii + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +``` ## 捐赠 diff --git a/docs/README.md b/docs/README.md index 218c4c8..cc82701 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,4 +1,4 @@ -# Borax - Python常用工具包 +# Borax - Python3工具集合包 [![PyPI](https://img.shields.io/pypi/v/borax.svg)](https://pypi.org/project/borax) @@ -12,12 +12,12 @@ Borax 是一个的 Python3 开发工具集合库,涉及到: - - 设计模式示例 + - 设计模式 - 数据结构 ## 安装 -Borax 要求 Python 的版本至少为 3.5 以上。可以通过以下三种方式安装 Borax : +Borax 要求 Python 的版本至少为 3.5 以上。可以通过以下两种方式安装 Borax : 1) 使用 *pip* : @@ -30,15 +30,6 @@ $ pip install borax $ poetry add borax ``` -3) 使用开发代码 - -```shell -git clone https://github.com/kinegratii/borax.git -cd borax -python setup.py install -``` - - ## 版本 打印 Borax 的版本。 diff --git a/docs/_sidebar.md b/docs/_sidebar.md index a23c6b4..171ab41 100644 --- a/docs/_sidebar.md +++ b/docs/_sidebar.md @@ -10,7 +10,6 @@ - **Borax.Datasets** - [数据连接(Join)(新)](guides/join) - **文档** - - [字典](guides/alias_dictionary) - [树形结构](guides/tree) - [序列号生成器](guides/serial_generator) - [百分比](guides/percentage) diff --git a/docs/changelog.md b/docs/changelog.md index 324fccb..85ff7ba 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -1,11 +1,18 @@ # 更新日志 -## v3.3.0 +## v3.3.0 (20200815) - 移除 `borax.fetch` 模块 +- `borax.datasets.join_` 模块 + - `old_join` 和 `old_join_one` 标记为 PendingDeprecationWarning ,将在 V3.5移除 +- `borax.runtime` 模块 - `borax.numbers` 模块 (+) + - 新增 `ChineseNumbers` 类 + - 新增 `finaceNumbers` 类,由 `borax.finace` 模块转化 - `borax.finance` 模块 - 修正小数使用字符串时 `financial_amount_capital` 错误的BUG + - 本模块被标记为 `PendingDeprecationWarning` ,将在V3.5移除 +- 移除 `borax.structures.dic` 模块 ## v3.2.0 (20200510) diff --git a/docs/guides/bjson.md b/docs/guides/bjson.md index 5c80574..3ad502d 100644 --- a/docs/guides/bjson.md +++ b/docs/guides/bjson.md @@ -2,6 +2,10 @@ > 模块:`borax.serialize.bjson` + + +## 使用方法 + bjson 模块实现了一个自定义的 JSONEncoder ,支持通过 `__json__` 方法 encode 自定义对象。 例子: @@ -44,3 +48,11 @@ json.dumps(obj, cls=bjson.BJSONEncoder) bjson.dumps(obj) ``` + + +## API + +- `borax.bjson.dumps(obj, **kwargs)` +- `borax.bjson.dumps(obj, fp, **kwargs)` + +和 `json` 模块功能相同,使用 `BJSONEncoder` 编码器。 \ No newline at end of file diff --git a/docs/guides/cjson.md b/docs/guides/cjson.md index 83adf92..64337ab 100644 --- a/docs/guides/cjson.md +++ b/docs/guides/cjson.md @@ -2,6 +2,8 @@ > 模块:`borax.serialize.cjson` +## 使用方法 + `cjson` 是一个基于 [singledispatch](https://docs.python.org/3/library/functools.html#functools.singledispatch) 的json 序列化工具。 一般来说,使用 `cjson.to_serializable.register` 装饰器,为自定义的类绑定一个序列化函数。 @@ -31,3 +33,12 @@ print(output) ``` {"point": [1, 2]} ``` + + + +## API + +- `borax.cjson.dumps(obj, **kwargs)` +- `borax.cjson.dumps(obj, fp, **kwargs)` + +和 `json` 模块功能相同,使用 `CJSONEncoder` 编码器。 \ No newline at end of file diff --git a/docs/guides/numbers.md b/docs/guides/numbers.md index 3bc16c9..e4a6d6c 100644 --- a/docs/guides/numbers.md +++ b/docs/guides/numbers.md @@ -2,6 +2,8 @@ > 模块:`borax.numbers` +> Added in V3.3.0 + ## 中文数字 ```python diff --git a/docs/guides/serial_generator.md b/docs/guides/serial_generator.md index 1a1ce13..a5fb550 100644 --- a/docs/guides/serial_generator.md +++ b/docs/guides/serial_generator.md @@ -50,7 +50,7 @@ def generate_serials(upper: int, num: int = 1, lower: int = 0, serials: Iterable 参数: - upper:整数范围的上限,不包含此数。 -- lower:整数范围的下限,包含次数。 +- lower:整数范围的下限,包含此数。 - num:分配ID的数量。 - serials:已经存在的ID,集合、列表类型。 diff --git a/docs/guides/tree.md b/docs/guides/tree.md index 87ff5b7..d534af8 100644 --- a/docs/guides/tree.md +++ b/docs/guides/tree.md @@ -1,6 +1,8 @@ # tree 模块 -> 模块: `borax.structure.tree` (v1.1.4+) +> 模块: `borax.structure.tree` + +> Added in V1.1.4 ## 功能 @@ -106,7 +108,7 @@ def pll2cnl( } ``` -例如对于配置 extra_key=extra&extra_fields=name ,上述节点将输出为以下格式: +例如对于配置 `{"extra_key": "extra", extra_fields":"name"}` ,上述节点将输出为以下格式: ```json { diff --git a/docs/index.html b/docs/index.html index 119ebe6..0411d68 100644 --- a/docs/index.html +++ b/docs/index.html @@ -2,7 +2,7 @@ - Borax - A Utils Collections for python3 Development + Borax - Python3工具集合库 "] @@ -23,7 +23,7 @@ classifiers=[ ] [tool.poetry.dev-dependencies] -nose = "^1.3" +nose = "^0.9" coverage = "^4.5" flake8 = "^3.5" mccabe = "^0.6" From 40adb3c85d7f47f9c713d24cb8251f874edbc272 Mon Sep 17 00:00:00 2001 From: kinegratii Date: Sat, 15 Aug 2020 09:56:59 +0800 Subject: [PATCH 11/11] :bookmark: Release V3.3.0 --- borax/__init__.py | 2 +- setup.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/borax/__init__.py b/borax/__init__.py index 55d5de3..dec7d2e 100644 --- a/borax/__init__.py +++ b/borax/__init__.py @@ -1,4 +1,4 @@ # coding=utf8 -__version__ = '3.2.0' +__version__ = '3.3.0' __author__ = 'kinegratii' diff --git a/setup.py b/setup.py index 7507351..bea00b7 100644 --- a/setup.py +++ b/setup.py @@ -35,5 +35,5 @@ author='kinegratii', author_email='kinegratii@gmail.com', classifiers=lib_classifiers, - description='A util collections for Python3.', + description='A tool collections for Python3.', )