feilian 1.1.2__py3-none-any.whl → 1.1.4__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of feilian might be problematic. Click here for more details.
- feilian/__init__.py +1 -1
- feilian/arg.py +74 -36
- feilian/dataframe.py +22 -9
- feilian/datetime.py +2 -1
- feilian/json.py +2 -0
- feilian/string.py +13 -0
- feilian/version.py +9 -0
- {feilian-1.1.2.dist-info → feilian-1.1.4.dist-info}/METADATA +1 -1
- feilian-1.1.4.dist-info/RECORD +12 -0
- {feilian-1.1.2.dist-info → feilian-1.1.4.dist-info}/WHEEL +1 -1
- feilian/about.py +0 -5
- feilian-1.1.2.dist-info/RECORD +0 -11
- {feilian-1.1.2.dist-info → feilian-1.1.4.dist-info}/top_level.txt +0 -0
feilian/__init__.py
CHANGED
|
@@ -6,7 +6,7 @@ from .dataframe import is_empty_text, is_nonempty_text, is_blank_text, is_non_bl
|
|
|
6
6
|
from .datetime import format_time, format_date
|
|
7
7
|
from .arg import ArgValueParser
|
|
8
8
|
from .json import read_json, save_json
|
|
9
|
-
from .
|
|
9
|
+
from .version import __version__
|
|
10
10
|
|
|
11
11
|
__all__ = [
|
|
12
12
|
'ensure_parent_dir_exist',
|
feilian/arg.py
CHANGED
|
@@ -1,6 +1,30 @@
|
|
|
1
1
|
# -*- coding: utf-8 -*-
|
|
2
2
|
|
|
3
|
-
from typing import Union, List, Any, Iterable, Callable, Set, Optional, Tuple
|
|
3
|
+
from typing import Union, List, Any, Iterable, Callable, Set, Optional, Tuple, Dict, Hashable
|
|
4
|
+
try:
|
|
5
|
+
from typing import Literal
|
|
6
|
+
except ImportError:
|
|
7
|
+
from typing_extensions import Literal
|
|
8
|
+
|
|
9
|
+
_build_in_na_checkers = {
|
|
10
|
+
'always_na': lambda x: True,
|
|
11
|
+
'never_na': lambda x: False,
|
|
12
|
+
'is_none': lambda x: x is None,
|
|
13
|
+
}
|
|
14
|
+
_NA_CHECKER_TYPES = Union[Callable[[Any], bool], Literal['always_na', 'never_na', 'is_none']]
|
|
15
|
+
|
|
16
|
+
_build_in_na_converters = {
|
|
17
|
+
'none': lambda x: None,
|
|
18
|
+
'self': lambda x: x,
|
|
19
|
+
'empty': lambda x: [],
|
|
20
|
+
'single': lambda x: [x],
|
|
21
|
+
}
|
|
22
|
+
_NA_CONVERTER_TYPES = Union[Callable[[Any], Any], Literal['none', 'self', 'empty', 'single']]
|
|
23
|
+
|
|
24
|
+
def _get_or_default(value: Any, mapping: Dict[Hashable, Any], default_key: Any) -> Any:
|
|
25
|
+
if value is None:
|
|
26
|
+
return mapping[default_key]
|
|
27
|
+
return mapping.get(value, value)
|
|
4
28
|
|
|
5
29
|
class ArgValueParser(object):
|
|
6
30
|
@classmethod
|
|
@@ -92,49 +116,63 @@ class ArgValueParser(object):
|
|
|
92
116
|
elem_type=elem_type, allowed_type=allowed_type)
|
|
93
117
|
|
|
94
118
|
@staticmethod
|
|
95
|
-
def
|
|
119
|
+
def ensure_collection(value: Any, expected_type: type, collection_type: Union[type, Tuple[type, ...]],
|
|
120
|
+
na_checker: _NA_CHECKER_TYPES = None, na_converter: _NA_CONVERTER_TYPES = None) -> Any:
|
|
121
|
+
"""
|
|
122
|
+
Ensure the value to be a list, tuple or set.
|
|
123
|
+
:param value: any type value
|
|
124
|
+
:param expected_type: expected return type, can be list, tuple or set
|
|
125
|
+
:param collection_type: other collection type to be convert
|
|
126
|
+
:param na_checker: check if `value` is na, default is 'is_none'
|
|
127
|
+
str value means some built-in functions:
|
|
128
|
+
always_na: always treat the value as na
|
|
129
|
+
never_na: never treat the value as na
|
|
130
|
+
is_none: test if the value is `None`
|
|
131
|
+
:param na_converter: if `value` is na, return output of this function, default is 'self'
|
|
132
|
+
str value means some built-in functions:
|
|
133
|
+
none: `None`
|
|
134
|
+
self: the value no changed
|
|
135
|
+
empty: an empty list
|
|
136
|
+
single: a single value list: `[value]`
|
|
137
|
+
:return: expected to be an instance of `expected_type`, or be `None` for some condition
|
|
138
|
+
"""
|
|
139
|
+
na_checker = _get_or_default(na_checker, _build_in_na_checkers, 'is_none')
|
|
140
|
+
if na_checker(value):
|
|
141
|
+
na_converter = _get_or_default(na_converter, _build_in_na_converters, 'self')
|
|
142
|
+
return na_converter(value)
|
|
143
|
+
if isinstance(value, expected_type):
|
|
144
|
+
return value
|
|
145
|
+
if isinstance(value, collection_type):
|
|
146
|
+
return expected_type(value)
|
|
147
|
+
return expected_type([value])
|
|
148
|
+
|
|
149
|
+
@classmethod
|
|
150
|
+
def ensure_list(cls, value: Any, na_checker: _NA_CHECKER_TYPES = None,
|
|
151
|
+
na_converter: _NA_CONVERTER_TYPES = None) -> Optional[List[Any]]:
|
|
96
152
|
"""
|
|
97
153
|
Ensure the value to be a list.
|
|
98
|
-
|
|
154
|
+
See more arg docs in `ensure_collection()`.
|
|
99
155
|
"""
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
return value
|
|
103
|
-
return [value]
|
|
104
|
-
if isinstance(value, list):
|
|
105
|
-
return value
|
|
106
|
-
if isinstance(value, (set, tuple)):
|
|
107
|
-
return list(value)
|
|
108
|
-
return [value]
|
|
156
|
+
return cls.ensure_collection(value, expected_type=list, collection_type=(tuple, set),
|
|
157
|
+
na_checker=na_checker, na_converter=na_converter)
|
|
109
158
|
|
|
110
|
-
@
|
|
111
|
-
def ensure_tuple(value: Any,
|
|
159
|
+
@classmethod
|
|
160
|
+
def ensure_tuple(cls, value: Any, na_checker: _NA_CHECKER_TYPES = None,
|
|
161
|
+
na_converter: _NA_CONVERTER_TYPES = None) -> Optional[Tuple[Any]]:
|
|
112
162
|
"""
|
|
113
163
|
Ensure the value to be a tuple.
|
|
114
|
-
|
|
164
|
+
See more arg docs in `ensure_collection()`.
|
|
115
165
|
"""
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
return value
|
|
119
|
-
return (value,)
|
|
120
|
-
if isinstance(value, tuple):
|
|
121
|
-
return value
|
|
122
|
-
if isinstance(value, (set, list)):
|
|
123
|
-
return tuple(value)
|
|
124
|
-
return (value,)
|
|
166
|
+
return cls.ensure_collection(value, expected_type=tuple, collection_type=(list, set),
|
|
167
|
+
na_checker=na_checker, na_converter=na_converter)
|
|
125
168
|
|
|
126
|
-
@
|
|
127
|
-
def ensure_set(value: Any,
|
|
169
|
+
@classmethod
|
|
170
|
+
def ensure_set(cls, value: Any, na_checker: _NA_CHECKER_TYPES = None,
|
|
171
|
+
na_converter: _NA_CONVERTER_TYPES = None) -> Optional[Set[Any]]:
|
|
128
172
|
"""
|
|
129
173
|
Ensure the value to be a set.
|
|
130
|
-
|
|
174
|
+
See more arg docs in `ensure_collection()`.
|
|
131
175
|
"""
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
return {value}
|
|
136
|
-
if isinstance(value, set):
|
|
137
|
-
return value
|
|
138
|
-
if isinstance(value, (tuple, list)):
|
|
139
|
-
return set(value)
|
|
140
|
-
return {value}
|
|
176
|
+
return cls.ensure_collection(value, expected_type=set, collection_type=(list, tuple),
|
|
177
|
+
na_checker=na_checker, na_converter=na_converter)
|
|
178
|
+
|
feilian/dataframe.py
CHANGED
|
@@ -4,7 +4,12 @@
|
|
|
4
4
|
Encapsulate methods for pandas `DataFrame`.
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
|
-
from typing import Union, Iterable, Dict,
|
|
7
|
+
from typing import Union, Iterable, Dict, List, Any, Sequence, Callable, Tuple, Hashable
|
|
8
|
+
try:
|
|
9
|
+
from typing import Literal
|
|
10
|
+
except ImportError:
|
|
11
|
+
from typing_extensions import Literal
|
|
12
|
+
|
|
8
13
|
import os
|
|
9
14
|
import pandas as pd
|
|
10
15
|
import random
|
|
@@ -19,14 +24,16 @@ if pd_version[0] < 1 or (pd_version[0] == 1 and pd_version[1] < 5):
|
|
|
19
24
|
|
|
20
25
|
def read_dataframe(file: str, *args, sheet_name=0,
|
|
21
26
|
file_format: Literal['csv', 'tsv', 'json', 'xlsx'] = None,
|
|
22
|
-
jsonl=False,
|
|
27
|
+
jsonl=False, dtype: pd._typing.DtypeArg = None,
|
|
28
|
+
**kwargs) -> Union[pd.DataFrame, Dict[str, pd.DataFrame]]:
|
|
23
29
|
"""
|
|
24
30
|
read file as pandas `DataFrame`
|
|
25
31
|
:param file: the file to be read
|
|
26
32
|
:param args: extra args for `pd.read_xx()`
|
|
27
33
|
:param sheet_name: `sheet_name` for `pd.read_excel()`
|
|
28
34
|
:param file_format: csv, tsv, json ,xlsx
|
|
29
|
-
:param jsonl:
|
|
35
|
+
:param jsonl: jsonl format or not, only used in json format
|
|
36
|
+
:param dtype: `dtype` for `pd.read_xx()`
|
|
30
37
|
:param kwargs: extra kwargs for `pd.read_xx()`
|
|
31
38
|
"""
|
|
32
39
|
# decide the file format
|
|
@@ -47,17 +54,17 @@ def read_dataframe(file: str, *args, sheet_name=0,
|
|
|
47
54
|
kwargs['delimiter'] = '\t'
|
|
48
55
|
|
|
49
56
|
if file_format == 'csv':
|
|
50
|
-
return pd.read_csv(file, *args, **kwargs)
|
|
57
|
+
return pd.read_csv(file, *args, dtype=dtype, **kwargs)
|
|
51
58
|
elif file_format == 'xlsx':
|
|
52
|
-
return pd.read_excel(file, *args, sheet_name=sheet_name, **kwargs)
|
|
59
|
+
return pd.read_excel(file, *args, sheet_name=sheet_name, dtype=dtype, **kwargs)
|
|
53
60
|
elif file_format == 'json':
|
|
54
|
-
return pd.read_json(file, *args, lines=jsonl, **kwargs)
|
|
61
|
+
return pd.read_json(file, *args, lines=jsonl, dtype=dtype, **kwargs)
|
|
55
62
|
else:
|
|
56
63
|
raise IOError(f"Unknown file format: {file}")
|
|
57
64
|
|
|
58
65
|
def save_dataframe(file: Union[str, 'pd.WriteBuffer[bytes]', 'pd.WriteBuffer[str]'],
|
|
59
66
|
df: Union[pd.DataFrame, Iterable[Union[pd.Series, Dict[str, Any]]]],
|
|
60
|
-
*args,
|
|
67
|
+
*args, sheet_name='Sheet1',
|
|
61
68
|
file_format: Literal['csv', 'tsv', 'json', 'xlsx'] = None,
|
|
62
69
|
index=False, index_label=None,
|
|
63
70
|
encoding='utf-8', newline='\n',
|
|
@@ -72,8 +79,10 @@ def save_dataframe(file: Union[str, 'pd.WriteBuffer[bytes]', 'pd.WriteBuffer[st
|
|
|
72
79
|
:param file: where to save the data to
|
|
73
80
|
:param df: the data
|
|
74
81
|
:param args: extra args for df.to_xx()
|
|
82
|
+
:param sheet_name: `sheet_name` for excel format
|
|
75
83
|
:param file_format: csv, tsv, json, xlsx
|
|
76
|
-
:param index: save index or not, see docs in df.to_csv()
|
|
84
|
+
:param index: save index or not, see docs in df.to_csv();
|
|
85
|
+
if set as str and `index_label` not set, `index_label` will be set as this
|
|
77
86
|
:param index_label: header for the index when `index` is `True`
|
|
78
87
|
:param encoding: text file encoding
|
|
79
88
|
:param newline: text file newline
|
|
@@ -114,6 +123,10 @@ def save_dataframe(file: Union[str, 'pd.WriteBuffer[bytes]', 'pd.WriteBuffer[st
|
|
|
114
123
|
if isinstance(file, (str, os.PathLike)):
|
|
115
124
|
ensure_parent_dir_exist(file)
|
|
116
125
|
|
|
126
|
+
# compatible for set index just use arg `index`
|
|
127
|
+
if index_label is None and isinstance(index, str):
|
|
128
|
+
index, index_label = True, index
|
|
129
|
+
|
|
117
130
|
# tsv is actually a csv
|
|
118
131
|
if file_format == 'tsv':
|
|
119
132
|
file_format = 'csv'
|
|
@@ -124,7 +137,7 @@ def save_dataframe(file: Union[str, 'pd.WriteBuffer[bytes]', 'pd.WriteBuffer[st
|
|
|
124
137
|
kwargs[PD_PARAM_NEWLINE] = newline
|
|
125
138
|
df.to_csv(file, *args, index=index, index_label=index_label, encoding=encoding, **kwargs)
|
|
126
139
|
elif file_format == 'xlsx':
|
|
127
|
-
df.to_excel(file, *args, index=index, index_label=index_label, **kwargs)
|
|
140
|
+
df.to_excel(file, *args, index=index, index_label=index_label, sheet_name=sheet_name, **kwargs)
|
|
128
141
|
elif file_format == 'json':
|
|
129
142
|
if jsonl:
|
|
130
143
|
orient = 'records'
|
feilian/datetime.py
CHANGED
|
@@ -16,5 +16,6 @@ def format_time(time: Union[str, int, float, datetime.datetime] = None, fmt='%Y-
|
|
|
16
16
|
raise ValueError(f"Unexpected type: {type(time)}")
|
|
17
17
|
return time.strftime(fmt)
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
# when format a date, no sep is used more
|
|
20
|
+
def format_date(date: Union[str, int, float, datetime.datetime] = None, sep='') -> str:
|
|
20
21
|
return format_time(date, fmt=sep.join(['%Y', '%m', '%d']))
|
feilian/json.py
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
from typing import Dict, List, Union, Any
|
|
4
4
|
import json
|
|
5
|
+
from .io import ensure_parent_dir_exist
|
|
5
6
|
|
|
6
7
|
def read_json(filepath: str, encoding='utf-8', **kwargs):
|
|
7
8
|
"""
|
|
@@ -15,5 +16,6 @@ def save_json(filepath: str, data: Union[Dict[str, Any], List[Any]],
|
|
|
15
16
|
"""
|
|
16
17
|
An agent for `json.dump()` with some default value.
|
|
17
18
|
"""
|
|
19
|
+
ensure_parent_dir_exist(filepath)
|
|
18
20
|
with open(filepath, 'w', encoding=encoding, newline=newline) as f:
|
|
19
21
|
json.dump(data, f, indent=indent, ensure_ascii=ensure_ascii, **kwargs)
|
feilian/string.py
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
from typing import Any, Callable
|
|
4
|
+
|
|
5
|
+
def join_values(*values: Any, sep='', func: Callable[[Any], str] = str, do_trim=False, ignore_empty=False):
|
|
6
|
+
def f():
|
|
7
|
+
for x in values:
|
|
8
|
+
s = func(x)
|
|
9
|
+
if do_trim:
|
|
10
|
+
s = s.strip()
|
|
11
|
+
if s or not ignore_empty:
|
|
12
|
+
yield s
|
|
13
|
+
return sep.join(f())
|
feilian/version.py
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
feilian/__init__.py,sha256=D_OYSAfDALQnRsbaAXMnHyC0LtykaIXLTHq7XNcsYjU,763
|
|
2
|
+
feilian/arg.py,sha256=lGZ99RkU9uhE_ziaFK2SClS3vrygteNNxTm3i_68SWw,8359
|
|
3
|
+
feilian/dataframe.py,sha256=121EcLvAkbBWv_antTABTJUaq3MIl1IHh1bPjaPCC0c,9853
|
|
4
|
+
feilian/datetime.py,sha256=IONvWhLeGEy9IVe6GWKEW3FhrfRrShyhGP8-RTf9r3c,763
|
|
5
|
+
feilian/io.py,sha256=aYN3QwWcLoRKzhGMNutqdkmxArVcXfeWXzxCB07LcFc,155
|
|
6
|
+
feilian/json.py,sha256=1GsnL-CASi4xBaycMN-Tw1ytxty7GeL2wmt7nfLfnB4,754
|
|
7
|
+
feilian/string.py,sha256=G_X3dnR0Oxmi4hXF-6E5jm5M7GPjGoMYrSMyI1dj6Z4,370
|
|
8
|
+
feilian/version.py,sha256=qI88ygIU5YG1b7BXxWD6l2jeVvcb78eQ__3BmRl3KCU,217
|
|
9
|
+
feilian-1.1.4.dist-info/METADATA,sha256=pc2HUo4iTEzUOakzR-Js_SiNrdqHyUSg68h_HRw0dh4,911
|
|
10
|
+
feilian-1.1.4.dist-info/WHEEL,sha256=yQN5g4mg4AybRjkgi-9yy4iQEFibGQmlz78Pik5Or-A,92
|
|
11
|
+
feilian-1.1.4.dist-info/top_level.txt,sha256=1Q2-B6KJrcTr7drW_kik35PTVEUJLPP4wVrn0kYKwGw,8
|
|
12
|
+
feilian-1.1.4.dist-info/RECORD,,
|
feilian/about.py
DELETED
feilian-1.1.2.dist-info/RECORD
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
feilian/__init__.py,sha256=oDG4bUXVJpqC2Q1Yhwt2AY-8-NFX1ZKcv5YyXYKuCC4,761
|
|
2
|
-
feilian/about.py,sha256=_-XUlhoKoRnnHfLXI02xXzYtCUI83o2ww0MU8hlm0Mg,88
|
|
3
|
-
feilian/arg.py,sha256=NwaBcKpHv7m00D5_LFuR8clQBSGX5brVXnh7ubGssas,5918
|
|
4
|
-
feilian/dataframe.py,sha256=ZqGLNQLKFTGaJiK2dw41ch0IIRJhLWTHpdLBHzgafJk,9260
|
|
5
|
-
feilian/datetime.py,sha256=FEZOf3pYDkjE1A1mPJU6eXmj6Mi6jyJgQxCK-04WzuI,722
|
|
6
|
-
feilian/io.py,sha256=aYN3QwWcLoRKzhGMNutqdkmxArVcXfeWXzxCB07LcFc,155
|
|
7
|
-
feilian/json.py,sha256=fcGHxwUEpCVaMkE9HoILC693e1_H-P6J4a8Y_6Locig,676
|
|
8
|
-
feilian-1.1.2.dist-info/METADATA,sha256=sXlS7cKZR0vLodpiVzrxPd2UUpbc-DT9L1DlQ-tYyn4,911
|
|
9
|
-
feilian-1.1.2.dist-info/WHEEL,sha256=5sUXSg9e4bi7lTLOHcm6QEYwO5TIF1TNbTSVFVjcJcc,92
|
|
10
|
-
feilian-1.1.2.dist-info/top_level.txt,sha256=1Q2-B6KJrcTr7drW_kik35PTVEUJLPP4wVrn0kYKwGw,8
|
|
11
|
-
feilian-1.1.2.dist-info/RECORD,,
|
|
File without changes
|