Skip to content

Commit

Permalink
Merge pull request #14 from kinegratii/develop
Browse files Browse the repository at this point in the history
V3.2.0
  • Loading branch information
kinegratii authored May 11, 2020
2 parents db04dd2 + 82e894e commit e7d1d13
Show file tree
Hide file tree
Showing 15 changed files with 602 additions and 48 deletions.
2 changes: 1 addition & 1 deletion borax/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# coding=utf8

__version__ = '3.1.0'
__version__ = '3.2.0'
__author__ = 'kinegratii'
12 changes: 12 additions & 0 deletions borax/calendars/utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# coding=utf8
import calendar
from datetime import date, datetime


def get_last_day_of_this_month(year: int, month: int) -> date:
return date(year, month, calendar.monthrange(year, month)[-1])


def get_fist_day_of_year_week(year: int, week: int) -> date:
fmt = '{}-W{}-1'.format(year, week)
return datetime.strptime(fmt, "%Y-W%W-%w").date()
18 changes: 0 additions & 18 deletions borax/datasets/dict_datasets.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
# coding=utf8


from borax.datasets.join_ import join_one, join


class DictDataset:
def __init__(self, data, primary_field=None):
self._data = []
Expand All @@ -18,18 +15,3 @@ def data(self):
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
106 changes: 104 additions & 2 deletions borax/datasets/join_.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,109 @@
# coding=utf8

import operator

def join_one(data_list, values, from_, as_, default=None):
__all__ = ['join_one', 'join', 'old_join_one', 'old_join']


def join_one(ldata, rdata, on, select_as, default=None):
if isinstance(rdata, (list, tuple)):
rdata = dict(rdata)
if not isinstance(rdata, dict):
raise TypeError("Unsupported Type for values param.")

if isinstance(on, str):
lic = operator.itemgetter(on)
elif callable(on):
lic = on
else:
raise TypeError('str or callable only supported for on param. ')

for litem in ldata:
if not (isinstance(on, str) and on not in litem):
lv = lic(litem)
rvv = rdata.get(lv, default)
litem[select_as] = rvv
return ldata


CLAUSE_SINGLE_TYPES = (str, tuple)


class OnClause(tuple):
def __new__(self, lkey, rkey=None):
rkey = rkey or lkey
return tuple.__new__(OnClause, (lkey, rkey))

@classmethod
def from_val(cls, val):
cm = val.__class__.__name__
if cm == "OnClause":
return val
elif cm == "str":
return cls(val, val)
elif cm == "tuple":
return cls(*val[:2])
else:
raise TypeError("Cannot build OnClause from a {} object.".format(cm))


class SelectClause(tuple):
def __new__(self, rkey, lkey=None, default=None):
lkey = lkey or rkey
return tuple().__new__(SelectClause, (rkey, lkey, default))

@classmethod
def from_val(cls, val):
cm = val.__class__.__name__
if cm == "SelectClause":
return val
elif cm == "str":
return cls(val, val, None)
elif cm == "tuple":
return cls(*val[:3])
else:
raise TypeError("Cannot build SelectClause from a {} object.".format(cm))


OC = OnClause
SC = SelectClause


def join(ldata, rdata, on, select_as):
if isinstance(on, CLAUSE_SINGLE_TYPES):
on = [on]
if isinstance(on, list):
lfields, rfields = zip(*list(map(OnClause.from_val, on)))

def on_callback(_li, _ri):
return operator.itemgetter(*lfields)(_li) == operator.itemgetter(*rfields)(_ri)
elif callable(on):
on_callback = on
else:
raise TypeError('str or callable only supported for on param. ')

if isinstance(select_as, CLAUSE_SINGLE_TYPES):
select_as = [select_as]
sf_list = list(map(SelectClause.from_val, select_as))

def _pick_data(_item, _sfs):
result = {}
for rk, lk, defv in _sfs:
result[lk] = _item.get(rk, defv)
return result

for litem in ldata:
for ritem in rdata:
if on_callback(litem, ritem):
_ri = ritem
break
else:
_ri = {}
litem.update(_pick_data(_ri, sf_list))
return ldata


def old_join_one(data_list, values, from_, as_, default=None):
if isinstance(values, (list, tuple)):
values = dict(values)
if not isinstance(values, dict):
Expand All @@ -17,7 +119,7 @@ def join_one(data_list, values, from_, as_, default=None):
return data_list


def join(data_list, values, from_, to_, as_args=None, as_kwargs=None):
def old_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}
Expand Down
2 changes: 1 addition & 1 deletion borax/fetch.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@

warnings.warn(
'This module is deprecated and will be removed in V3.3.Use borax.datasets.fetch instead.',
category=PendingDeprecationWarning
category=DeprecationWarning
)
26 changes: 22 additions & 4 deletions borax/structures/percentage.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,27 @@
# coding=utf8


def format_percentage(numerator: int, denominator: int, *, places: int = 2, null_val: str = '-') -> str:
if denominator == 0:
return null_val
percent_fmt = '{0:. f}%'.replace(' ', str(places))
val = round(numerator / denominator, places + 2)
return percent_fmt.format(val * 100)


class Percentage:
"""
Percentage(completed=0, total=100, places=2,)
"""

def __init__(self, *, total: int = 100, completed: int = 0, places: int = 2,
display_fmt: str = '{completed} / {total}'):
display_fmt: str = '{completed} / {total}', null_val: str = '-'):
self.total = total
self.completed = completed
self._display_fmt = display_fmt
self._places = places
# string.format will fails here
self._percent_fmt = '{0:. f}%'.replace(' ', str(self._places))
self._null_val = null_val

def increase(self, value: int = 1) -> None:
self.completed += value
Expand All @@ -30,12 +38,19 @@ def percent(self) -> float:

@property
def percent_display(self) -> str:
return self._percent_fmt.format(self.percent * 100)
"""percent format string like '12.34%' """
return format_percentage(self.completed, self.total, places=self._places, null_val=self._null_val)

@property
def display(self) -> str:
def fraction_display(self):
"""return a fractor like '34 / 100'"""
return self._display_fmt.format(completed=self.completed, total=self.total)

@property
def display(self) -> str:
"""old alias name for fraction_display'"""
return self.fraction_display

def as_dict(self, prefix='') -> dict:
return {
prefix + 'total': self.total,
Expand All @@ -52,3 +67,6 @@ def generate(self, char_total=100) -> str:
'░' * (char_total - char_completed),
self.percent * 100
)

def __str__(self):
return '<Percentage:{} {}>'.format(self.display, self.percent_display)
9 changes: 9 additions & 0 deletions borax/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,3 +90,12 @@ def flatten(iterable):
yield from flatten(el)
else:
yield el


def force_list(val, sep=','):
if isinstance(val, (list, set, tuple)):
return val
elif isinstance(val, str):
return val.split(sep)
else:
return val,
17 changes: 16 additions & 1 deletion docs/changelog.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,21 @@
# 更新日志

## v3.1.0
## v3.2.0 (20200510)

> 本版本重写 `borax.datasets.join_` 模块,接口引入重大变更,详情查看 [join模块](guides/join)
- `borax.datasets.join_`模块
- 重写 `join``join_one` 函数,原有的重命名为 `old_join``old_join_one`
- 原有的 `old_*` 将在V4.0版本移除。
- 新增 `borax.calendars.utils` 模块
- `borax.structures.percentage` 模块
- 新增 `format_percentage` 函数
-`Percentage` 新增 `fraction_display` 属性
- 当 total 为 0 ,显示为 `'-'` ,而不是 `'0.00%'`
- `borax.fetch` 模块
- 本模块被标记为 DeprecationWarning ,将在V3.3移除

## v3.1.0 (20200118)

> 新增 Python3.8构建
Expand Down
Loading

0 comments on commit e7d1d13

Please sign in to comment.