dukit 0.2.7__tar.gz → 0.3.0__tar.gz
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.
- {dukit-0.2.7 → dukit-0.3.0}/PKG-INFO +3 -2
- dukit-0.3.0/pyproject.toml +48 -0
- dukit-0.2.7/pyproject.toml → dukit-0.3.0/pyproject.toml.orig +4 -4
- {dukit-0.2.7 → dukit-0.3.0}/src/dukit/_test_utils.py +8 -8
- {dukit-0.2.7 → dukit-0.3.0}/src/dukit/diffing.py +8 -8
- {dukit-0.2.7 → dukit-0.3.0}/src/dukit/os.py +1 -1
- {dukit-0.2.7 → dukit-0.3.0}/src/dukit/pandas.py +23 -26
- {dukit-0.2.7 → dukit-0.3.0}/src/dukit/qlang/symbols.py +2 -2
- {dukit-0.2.7 → dukit-0.3.0}/README.md +0 -0
- {dukit-0.2.7 → dukit-0.3.0}/src/dukit/__init__.py +0 -0
- {dukit-0.2.7 → dukit-0.3.0}/src/dukit/excel.py +0 -0
- {dukit-0.2.7 → dukit-0.3.0}/src/dukit/interfaces.py +0 -0
- {dukit-0.2.7 → dukit-0.3.0}/src/dukit/py.typed +0 -0
- {dukit-0.2.7 → dukit-0.3.0}/src/dukit/qlang/__init__.py +0 -0
- {dukit-0.2.7 → dukit-0.3.0}/src/dukit/qlang/engine.py +0 -0
- {dukit-0.2.7 → dukit-0.3.0}/src/dukit/typing.py +0 -0
- {dukit-0.2.7 → dukit-0.3.0}/src/dukit/utils.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: dukit
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: dukit - data utilities kit for exploring, modifying and visualizing small but messy data using pandas
|
|
5
5
|
Keywords: pandas,query,utility,data,diff
|
|
6
6
|
Author: MartinVoelkl94
|
|
@@ -10,7 +10,8 @@ Classifier: Programming Language :: Python
|
|
|
10
10
|
Classifier: Programming Language :: Python :: 3
|
|
11
11
|
Requires-Dist: ipython>=9.15.0
|
|
12
12
|
Requires-Dist: jinja2>=3.1.6
|
|
13
|
-
Requires-Dist:
|
|
13
|
+
Requires-Dist: openpyxl>=3.1.5
|
|
14
|
+
Requires-Dist: pandas>=3.1.0
|
|
14
15
|
Requires-Python: >=3.14
|
|
15
16
|
Project-URL: Repository, https://github.com/MartinVoelkl94/dukit
|
|
16
17
|
Description-Content-Type: text/markdown
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "dukit"
|
|
3
|
+
version = "0.3.0"
|
|
4
|
+
description = "dukit - data utilities kit for exploring, modifying and visualizing small but messy data using pandas"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
license = "MIT"
|
|
7
|
+
requires-python = ">=3.14"
|
|
8
|
+
classifiers = [
|
|
9
|
+
"Programming Language :: Python",
|
|
10
|
+
"Programming Language :: Python :: 3",
|
|
11
|
+
]
|
|
12
|
+
keywords = [
|
|
13
|
+
"pandas",
|
|
14
|
+
"query",
|
|
15
|
+
"utility",
|
|
16
|
+
"data",
|
|
17
|
+
"diff",
|
|
18
|
+
]
|
|
19
|
+
dependencies = [
|
|
20
|
+
"ipython>=9.15.0",
|
|
21
|
+
"jinja2>=3.1.6",
|
|
22
|
+
"openpyxl>=3.1.5",
|
|
23
|
+
"pandas>=3.1.0",
|
|
24
|
+
]
|
|
25
|
+
|
|
26
|
+
[[project.authors]]
|
|
27
|
+
name = "MartinVoelkl94"
|
|
28
|
+
email = "martinv16248@gmail.com"
|
|
29
|
+
|
|
30
|
+
[project.urls]
|
|
31
|
+
Repository = "https://github.com/MartinVoelkl94/dukit"
|
|
32
|
+
|
|
33
|
+
[build-system]
|
|
34
|
+
requires = ["uv_build>=0.10.9,<0.11.0"]
|
|
35
|
+
build-backend = "uv_build"
|
|
36
|
+
|
|
37
|
+
[dependency-groups]
|
|
38
|
+
dev = [
|
|
39
|
+
"faker>=40.28.1",
|
|
40
|
+
"flake8>=7.3.0",
|
|
41
|
+
"ipykernel>=7.3.0",
|
|
42
|
+
"ipywidgets>=8.1.8",
|
|
43
|
+
"pip>=26.1.2",
|
|
44
|
+
"pylance>=8.0.0",
|
|
45
|
+
"pytest>=9.2.0",
|
|
46
|
+
"pytest-cov>=7.1.0",
|
|
47
|
+
"viztracer>=1.1.1",
|
|
48
|
+
]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "dukit"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.3.0"
|
|
4
4
|
description = "dukit - data utilities kit for exploring, modifying and visualizing small but messy data using pandas"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
authors = [{ name = "MartinVoelkl94", email = "martinv16248@gmail.com" }]
|
|
@@ -20,7 +20,8 @@ keywords = [
|
|
|
20
20
|
dependencies = [
|
|
21
21
|
"ipython>=9.15.0",
|
|
22
22
|
"jinja2>=3.1.6",
|
|
23
|
-
"
|
|
23
|
+
"openpyxl>=3.1.5",
|
|
24
|
+
"pandas>=3.1.0",
|
|
24
25
|
]
|
|
25
26
|
|
|
26
27
|
|
|
@@ -39,10 +40,9 @@ dev = [
|
|
|
39
40
|
"flake8>=7.3.0",
|
|
40
41
|
"ipykernel>=7.3.0",
|
|
41
42
|
"ipywidgets>=8.1.8",
|
|
42
|
-
"openpyxl>=3.1.5",
|
|
43
43
|
"pip>=26.1.2",
|
|
44
44
|
"pylance>=8.0.0",
|
|
45
|
-
"pytest>=9.
|
|
45
|
+
"pytest>=9.2.0",
|
|
46
46
|
"pytest-cov>=7.1.0",
|
|
47
47
|
"viztracer>=1.1.1",
|
|
48
48
|
]
|
|
@@ -63,7 +63,7 @@ def _get_expected_new():
|
|
|
63
63
|
expected.loc['x2', 'a'] = 1
|
|
64
64
|
expected.loc['z', 'a'] = pd.NA
|
|
65
65
|
|
|
66
|
-
expected.reset_index(drop=True
|
|
66
|
+
expected = expected.reset_index(drop=True)
|
|
67
67
|
|
|
68
68
|
return expected.convert_dtypes()
|
|
69
69
|
|
|
@@ -107,7 +107,7 @@ def _get_expected_newplus():
|
|
|
107
107
|
expected.loc['z', 'a *old'] = 3
|
|
108
108
|
|
|
109
109
|
expected['b *old'] = expected['b *old'].astype('Int64')
|
|
110
|
-
expected.reset_index(drop=True
|
|
110
|
+
expected = expected.reset_index(drop=True)
|
|
111
111
|
|
|
112
112
|
return expected.convert_dtypes()
|
|
113
113
|
|
|
@@ -142,7 +142,7 @@ def _get_expected_old():
|
|
|
142
142
|
expected.loc['y', 'c'] = 2
|
|
143
143
|
expected.loc['z', 'c'] = 3
|
|
144
144
|
|
|
145
|
-
expected.reset_index(drop=True
|
|
145
|
+
expected = expected.reset_index(drop=True)
|
|
146
146
|
|
|
147
147
|
return expected.convert_dtypes()
|
|
148
148
|
|
|
@@ -187,7 +187,7 @@ def _get_expected_mix():
|
|
|
187
187
|
expected.loc['z', 'c'] = 3
|
|
188
188
|
expected.loc['x', 'c'] = 1
|
|
189
189
|
|
|
190
|
-
expected.reset_index(drop=True
|
|
190
|
+
expected = expected.reset_index(drop=True)
|
|
191
191
|
|
|
192
192
|
return expected.convert_dtypes()
|
|
193
193
|
|
|
@@ -218,7 +218,7 @@ def _get_expected_style_new():
|
|
|
218
218
|
expected.loc['x2', 'a'] = f'background-color: {GREEN};'
|
|
219
219
|
expected.loc['z', 'a'] = f'background-color: {RED_LIGHT};'
|
|
220
220
|
|
|
221
|
-
expected.reset_index(drop=True
|
|
221
|
+
expected = expected.reset_index(drop=True)
|
|
222
222
|
|
|
223
223
|
return expected.convert_dtypes()
|
|
224
224
|
|
|
@@ -256,7 +256,7 @@ def _get_expected_style_newplus():
|
|
|
256
256
|
expected.loc['x2', 'a *old'] = f'font-style: italic;background-color: {GREEN};'
|
|
257
257
|
expected.loc['z', 'a *old'] = 'font-style: italic;'
|
|
258
258
|
|
|
259
|
-
expected.reset_index(drop=True
|
|
259
|
+
expected = expected.reset_index(drop=True)
|
|
260
260
|
|
|
261
261
|
return expected.convert_dtypes()
|
|
262
262
|
|
|
@@ -286,7 +286,7 @@ def _get_expected_style_old():
|
|
|
286
286
|
expected.loc['y', 'c'] = f'background-color: {RED};'
|
|
287
287
|
expected.loc['z', 'c'] = f'background-color: {RED};'
|
|
288
288
|
|
|
289
|
-
expected.reset_index(drop=True
|
|
289
|
+
expected = expected.reset_index(drop=True)
|
|
290
290
|
|
|
291
291
|
return expected.convert_dtypes()
|
|
292
292
|
|
|
@@ -325,6 +325,6 @@ def _get_expected_style_mix():
|
|
|
325
325
|
expected.loc['z', 'c'] = f'background-color: {RED};'
|
|
326
326
|
|
|
327
327
|
|
|
328
|
-
expected.reset_index(drop=True
|
|
328
|
+
expected = expected.reset_index(drop=True)
|
|
329
329
|
|
|
330
330
|
return expected.convert_dtypes()
|
|
@@ -1058,15 +1058,15 @@ def _set_uid(d: Diff, uid: typing.Any) -> Diff:
|
|
|
1058
1058
|
)
|
|
1059
1059
|
d.old.index = d.old[uid]
|
|
1060
1060
|
d.new.index = d.new[uid]
|
|
1061
|
-
d.old.drop(columns=uid
|
|
1062
|
-
d.new.drop(columns=uid
|
|
1061
|
+
d.old = d.old.drop(columns=uid)
|
|
1062
|
+
d.new = d.new.drop(columns=uid)
|
|
1063
1063
|
d.uid = uid
|
|
1064
1064
|
|
|
1065
1065
|
elif uid in d.old.columns and uid in d.new.columns:
|
|
1066
1066
|
d.old.index = d.old[uid]
|
|
1067
1067
|
d.new.index = d.new[uid]
|
|
1068
|
-
d.old.drop(columns=uid
|
|
1069
|
-
d.new.drop(columns=uid
|
|
1068
|
+
d.old = d.old.drop(columns=uid)
|
|
1069
|
+
d.new = d.new.drop(columns=uid)
|
|
1070
1070
|
d.uid = uid
|
|
1071
1071
|
|
|
1072
1072
|
else:
|
|
@@ -1295,7 +1295,7 @@ def _create_meta_cols(d: Diff) -> Diff:
|
|
|
1295
1295
|
|
|
1296
1296
|
df_meta = values.loc[:, col_mapping.keys()].copy()
|
|
1297
1297
|
df_meta.loc[:, :] = pd.NA
|
|
1298
|
-
df_meta.rename(columns=col_mapping
|
|
1298
|
+
df_meta = df_meta.rename(columns=col_mapping)
|
|
1299
1299
|
|
|
1300
1300
|
data = {
|
|
1301
1301
|
colname: ['font-style: italic;'] * len(values.index)
|
|
@@ -1577,8 +1577,8 @@ def _reset_index(d: Diff) -> Diff:
|
|
|
1577
1577
|
|
|
1578
1578
|
index_diff = d._values.index.difference(d._style.index)
|
|
1579
1579
|
if index_diff.empty:
|
|
1580
|
-
d._values.reset_index(drop=True
|
|
1581
|
-
d._style.reset_index(drop=True
|
|
1580
|
+
d._values = d._values.reset_index(drop=True)
|
|
1581
|
+
d._style = d._style.reset_index(drop=True)
|
|
1582
1582
|
else:
|
|
1583
1583
|
msg = (
|
|
1584
1584
|
'ERROR: index of values and style dfs do not match.'
|
|
@@ -1602,7 +1602,7 @@ def _apply_style(d: Diff) -> Diff:
|
|
|
1602
1602
|
)
|
|
1603
1603
|
log(msg, context, d.verbosity)
|
|
1604
1604
|
|
|
1605
|
-
d._style.fillna(''
|
|
1605
|
+
d._style = d._style.fillna('')
|
|
1606
1606
|
d.result = (
|
|
1607
1607
|
d._values
|
|
1608
1608
|
.style
|
|
@@ -442,7 +442,7 @@ def compose(
|
|
|
442
442
|
|
|
443
443
|
col_new = df[cols].apply(lambda row: template.format(*row), axis='columns')
|
|
444
444
|
df.insert(pos, col, col_new)
|
|
445
|
-
df.drop(columns=cols
|
|
445
|
+
df = df.drop(columns=cols)
|
|
446
446
|
|
|
447
447
|
return df
|
|
448
448
|
|
|
@@ -550,7 +550,7 @@ def stack(
|
|
|
550
550
|
_stack_check_uid_unique1(df, uid, verbosity)
|
|
551
551
|
|
|
552
552
|
uid_old = ensure_unique_string(uid, df.columns)
|
|
553
|
-
df.set_index(uid
|
|
553
|
+
df = df.set_index(uid)
|
|
554
554
|
df.index.name = uid_old
|
|
555
555
|
cols_keep = list_(cols_keep)
|
|
556
556
|
cols_stack = [col for col in df.columns if col not in cols_keep]
|
|
@@ -579,10 +579,7 @@ def stack(
|
|
|
579
579
|
for subid_val in subdfs.keys():
|
|
580
580
|
subdf = subdfs[subid_val]
|
|
581
581
|
if dropna:
|
|
582
|
-
subdf.dropna(
|
|
583
|
-
inplace=True,
|
|
584
|
-
how='all',
|
|
585
|
-
)
|
|
582
|
+
subdf = subdf.dropna(how='all')
|
|
586
583
|
uid_vals = [
|
|
587
584
|
uid_template.format(uid=uid_old, subid=subid_val)
|
|
588
585
|
for uid_old in subdf.index
|
|
@@ -596,13 +593,13 @@ def stack(
|
|
|
596
593
|
on=uid_old,
|
|
597
594
|
how='right',
|
|
598
595
|
)
|
|
599
|
-
df_new.drop(columns=[uid_old]
|
|
596
|
+
df_new = df_new.drop(columns=[uid_old])
|
|
600
597
|
|
|
601
598
|
_stack_check_missed_values(df_new, uid, cols_keep, non_na_vals, verbosity)
|
|
602
599
|
|
|
603
600
|
if sort:
|
|
604
|
-
df_new.sort_values(by=uid
|
|
605
|
-
df_new.reset_index(drop=True
|
|
601
|
+
df_new = df_new.sort_values(by=uid)
|
|
602
|
+
df_new = df_new.reset_index(drop=True)
|
|
606
603
|
|
|
607
604
|
_stack_check_uid_unique2(uid, verbosity, df_new)
|
|
608
605
|
|
|
@@ -678,9 +675,9 @@ def unstack(
|
|
|
678
675
|
_unstack_check_successfull_extraction(df, uid, ids, expected_cols, verbosity)
|
|
679
676
|
|
|
680
677
|
|
|
681
|
-
ids.set_index('uid'
|
|
678
|
+
ids = ids.set_index('uid')
|
|
682
679
|
df[uid] = ids.index
|
|
683
|
-
df.set_index(uid
|
|
680
|
+
df = df.set_index(uid)
|
|
684
681
|
subid_col = ids['subid']
|
|
685
682
|
subid_vals = subid_col.unique()
|
|
686
683
|
cols_keep = list_(cols_keep)
|
|
@@ -720,9 +717,9 @@ def unstack(
|
|
|
720
717
|
how='left'
|
|
721
718
|
)
|
|
722
719
|
|
|
723
|
-
_unstack_check_missed_values(uid, cols_keep,
|
|
720
|
+
_unstack_check_missed_values(df_new, uid, cols_keep, non_na_vals, verbosity)
|
|
724
721
|
|
|
725
|
-
df_new.reset_index(
|
|
722
|
+
df_new = df_new.reset_index()
|
|
726
723
|
|
|
727
724
|
return df_new
|
|
728
725
|
|
|
@@ -762,22 +759,22 @@ def _unstack_check_successfull_extraction(df, uid, ids, expected_cols, verbosity
|
|
|
762
759
|
log(msg, 'dk.pandas.unstack', verbosity)
|
|
763
760
|
|
|
764
761
|
|
|
765
|
-
def _unstack_check_missed_values(uid, cols_keep,
|
|
762
|
+
def _unstack_check_missed_values(df_new, uid, cols_keep, non_na_vals, verbosity):
|
|
766
763
|
cols_stacked = [
|
|
767
764
|
col for col
|
|
768
765
|
in df_new.columns
|
|
769
766
|
if col not in cols_keep + [uid]
|
|
770
767
|
]
|
|
771
|
-
|
|
768
|
+
non_na_vals_new = int(
|
|
772
769
|
df_new[cols_stacked]
|
|
773
770
|
.notna()
|
|
774
771
|
.sum()
|
|
775
772
|
.sum()
|
|
776
773
|
)
|
|
777
|
-
if
|
|
774
|
+
if non_na_vals != non_na_vals_new:
|
|
778
775
|
msg = (
|
|
779
776
|
'WARNING: Non-NA value mismatch: '
|
|
780
|
-
f'before={
|
|
777
|
+
f'before={non_na_vals}, after={non_na_vals_new}'
|
|
781
778
|
)
|
|
782
779
|
log(msg, 'dk.pandas.unstack', verbosity)
|
|
783
780
|
|
|
@@ -809,8 +806,8 @@ def transpose(
|
|
|
809
806
|
df = df.T
|
|
810
807
|
df.columns = cols_new
|
|
811
808
|
df.insert(0, header, cols_old)
|
|
812
|
-
df.drop(header, axis=0
|
|
813
|
-
df.reset_index(drop=True
|
|
809
|
+
df = df.drop(header, axis=0)
|
|
810
|
+
df = df.reset_index(drop=True)
|
|
814
811
|
|
|
815
812
|
return df
|
|
816
813
|
|
|
@@ -857,10 +854,10 @@ def date_delta(
|
|
|
857
854
|
|
|
858
855
|
for col in df_dates.columns:
|
|
859
856
|
if df_dates[col].isna().all():
|
|
860
|
-
df_dates.drop(columns=col
|
|
857
|
+
df_dates = df_dates.drop(columns=col)
|
|
861
858
|
else:
|
|
862
859
|
cols_dates.append(col)
|
|
863
|
-
df.drop(columns=col
|
|
860
|
+
df = df.drop(columns=col)
|
|
864
861
|
|
|
865
862
|
df = pd.concat([df, df_dates], axis=1)[cols_all]
|
|
866
863
|
|
|
@@ -942,7 +939,7 @@ def date_table(
|
|
|
942
939
|
msg = f'WARNING: no dates found in reference col "{reference_col}"'
|
|
943
940
|
log(msg, 'dk.date_delta', verbosity)
|
|
944
941
|
else:
|
|
945
|
-
df.drop(columns=col
|
|
942
|
+
df = df.drop(columns=col)
|
|
946
943
|
|
|
947
944
|
reference = df[reference_col].apply(date_).apply(_fix_nas)
|
|
948
945
|
|
|
@@ -1088,7 +1085,7 @@ def split_col(
|
|
|
1088
1085
|
pos = df.columns.get_loc(col)
|
|
1089
1086
|
splits = df[col].str.partition(sep)
|
|
1090
1087
|
|
|
1091
|
-
df.drop(columns=[col]
|
|
1088
|
+
df = df.drop(columns=[col])
|
|
1092
1089
|
if new1 is None:
|
|
1093
1090
|
new1 = col
|
|
1094
1091
|
elif new1 in df.columns:
|
|
@@ -1123,7 +1120,7 @@ def collapse(
|
|
|
1123
1120
|
df = df.map(lambda x: _to_lines(x, template_item))
|
|
1124
1121
|
df.columns = [template_col.format(colname=col) for col in df.columns]
|
|
1125
1122
|
df.insert(0, on, df.index)
|
|
1126
|
-
df.reset_index(drop=True
|
|
1123
|
+
df = df.reset_index(drop=True)
|
|
1127
1124
|
return df
|
|
1128
1125
|
|
|
1129
1126
|
|
|
@@ -1253,7 +1250,7 @@ def flatten(
|
|
|
1253
1250
|
|
|
1254
1251
|
df = df[cols_new]
|
|
1255
1252
|
df.insert(0, on, df.index)
|
|
1256
|
-
df.reset_index(drop=True
|
|
1253
|
+
df = df.reset_index(drop=True)
|
|
1257
1254
|
|
|
1258
1255
|
return df
|
|
1259
1256
|
|
|
@@ -1311,7 +1308,7 @@ def stagger(
|
|
|
1311
1308
|
col_new.name = template.format(counter=i + 1, colname=col)
|
|
1312
1309
|
df_new = pd.concat([df_new, col_new], axis=1)
|
|
1313
1310
|
|
|
1314
|
-
df_new.reset_index(drop=True
|
|
1311
|
+
df_new = df_new.reset_index(drop=True)
|
|
1315
1312
|
|
|
1316
1313
|
return df_new
|
|
1317
1314
|
|
|
@@ -2879,7 +2879,7 @@ class GetIsNA(Symbol):
|
|
|
2879
2879
|
if 'strict' in self.flags:
|
|
2880
2880
|
mask = series.isna()
|
|
2881
2881
|
else:
|
|
2882
|
-
mask = series.apply(lambda x: na_(x, errors='X'))
|
|
2882
|
+
mask = series.apply(lambda x: na_(x, errors='X')).isna()
|
|
2883
2883
|
return mask
|
|
2884
2884
|
|
|
2885
2885
|
|
|
@@ -5111,7 +5111,7 @@ class SetToYN(Symbol):
|
|
|
5111
5111
|
args: list,
|
|
5112
5112
|
q: Query,
|
|
5113
5113
|
) -> pd.Series:
|
|
5114
|
-
series_new = series[mask].apply(yn_).
|
|
5114
|
+
series_new = series[mask].apply(yn_).astype('string')
|
|
5115
5115
|
if mask.all():
|
|
5116
5116
|
series = series_new
|
|
5117
5117
|
else:
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|