dukit 0.2.3__tar.gz → 0.2.5__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dukit
3
- Version: 0.2.3
3
+ Version: 0.2.5
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
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "dukit"
3
- version = "0.2.3"
3
+ version = "0.2.5"
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" }]
@@ -1,11 +1,7 @@
1
1
 
2
- from .utils import (
3
- log,
4
- )
5
- from .diffing import (
6
- diff,
7
- rediff,
8
- )
2
+ from importlib.metadata import version
3
+ __version__ = version('dukit')
4
+
9
5
  from . import qlang
10
6
  from .qlang import (
11
7
  q,
@@ -13,23 +9,42 @@ from .qlang import (
13
9
  qs,
14
10
  )
15
11
  from .interfaces import (
16
- DukitAccessor,
12
+ DukitAccessor
13
+ )
14
+ from .diffing import (
15
+ diff,
16
+ rediff,
17
+ )
18
+ from .utils import (
19
+ log,
20
+ ensure_unique_string,
21
+ )
22
+ from .excel import (
23
+ format,
24
+ save,
17
25
  )
18
26
  from .pandas import (
19
- get_df,
20
- get_dfs,
27
+ collapse,
28
+ date_delta,
29
+ date_table,
21
30
  deduplicate,
31
+ embed,
22
32
  flatten,
33
+ get_df,
34
+ get_dfs,
23
35
  stagger,
24
- embed,
25
- collapse,
26
36
  transpose,
27
- date_delta,
28
- date_table,
29
37
  )
30
- from .excel import (
31
- format,
32
- save,
38
+ from .os import (
39
+ cd,
40
+ cp,
41
+ fetch,
42
+ isdir,
43
+ isfile,
44
+ ispath,
45
+ mv,
46
+ mkdir,
47
+ pwd,
33
48
  )
34
49
  from .typing import (
35
50
  Box,
@@ -44,44 +59,53 @@ from .typing import (
44
59
  nk_ as nk,
45
60
  yn_ as yn,
46
61
  type_ as type,
62
+ dtype_ as dtype,
47
63
  convert_ as convert,
48
64
  typeinfo_ as typeinfo,
49
65
  typeinfostrict_ as typeinfostrict,
50
66
  list_ as list,
51
67
  )
52
- from .os import (
53
- pwd,
54
- cd,
55
- cp,
56
- mv,
57
- mkdir,
58
- isdir,
59
- isfile,
60
- ispath,
61
- fetch,
62
- )
68
+
63
69
 
64
70
  __all__ = (
65
- 'log',
66
- 'diff',
67
- 'rediff',
71
+ '__version__',
72
+
68
73
  'qlang',
69
74
  'q',
70
75
  'qr',
71
76
  'qs',
72
77
  'DukitAccessor',
73
- 'get_df',
74
- 'get_dfs',
78
+
79
+ 'diff',
80
+ 'rediff',
81
+
82
+ 'log',
83
+ 'ensure_unique_string',
84
+
85
+ 'format',
86
+ 'save',
87
+
88
+ 'collapse',
89
+ 'date_delta',
90
+ 'date_table',
75
91
  'deduplicate',
92
+ 'embed',
76
93
  'flatten',
94
+ 'get_df',
95
+ 'get_dfs',
77
96
  'stagger',
78
- 'embed',
79
- 'collapse',
80
97
  'transpose',
81
- 'date_delta',
82
- 'date_table',
83
- 'format',
84
- 'save',
98
+
99
+ 'cd',
100
+ 'cp',
101
+ 'fetch',
102
+ 'isdir',
103
+ 'isfile',
104
+ 'ispath',
105
+ 'mv',
106
+ 'mkdir',
107
+ 'pwd',
108
+
85
109
  'Box',
86
110
  'str',
87
111
  'int',
@@ -94,17 +118,9 @@ __all__ = (
94
118
  'nk',
95
119
  'yn',
96
120
  'type',
121
+ 'dtype',
97
122
  'convert',
98
123
  'typeinfo',
99
124
  'typeinfostrict',
100
125
  'list',
101
- 'pwd',
102
- 'cd',
103
- 'cp',
104
- 'mv',
105
- 'mkdir',
106
- 'isdir',
107
- 'isfile',
108
- 'ispath',
109
- 'fetch',
110
126
  )
@@ -1,5 +1,6 @@
1
1
 
2
2
  import pandas as pd
3
+
3
4
  from .utils import (
4
5
  GREEN,
5
6
  RED,
@@ -1,7 +1,7 @@
1
1
 
2
- import pandas as pd
3
- import typing
4
2
  import os
3
+ import typing
4
+ import pandas as pd
5
5
 
6
6
  from .pandas import deduplicate
7
7
  from .excel import format
@@ -35,33 +35,56 @@ def diff(
35
35
  verbosity=3,
36
36
  ) -> Diffs:
37
37
  """
38
- Calculates differences between dfs,
39
- CSV or Excel files and returns a Diffs object.
40
-
38
+ compare two dfs or pairs of CSV or Excel files.
41
39
 
42
40
  Parameters
43
41
  ----------
44
-
45
- old, new : pd.DataFrame or filepath to CSV or Excel file
46
-
47
- uid : identifies corresponding rows in old and new data.
48
- * "COLNAME": use the specified col as unique identifier.
49
- * None: try to find a suitable col automatically.
50
- * False: use the index as unique identifier.
51
-
52
- mode : how to display differences in the result.
53
- * "mix": show rows and cols from old and new df
54
- * "old": show only rows and cols from old df
55
- * "new": show only rows and cols from new df
56
- * "new+": also adds hidden columns with old values for comparison
57
-
58
- rename_cols : dictionary to rename cols before comparison.
59
- remove_cols : remove col(s) from both dfs.
60
- remove_cols_by_suffix : remove cols that end with the specified suffix.
61
- retain_cols : remove col(s) from both dfs, then readd to the result.
62
- ignore_cols : keep col(s) but ignore them for comparison.
63
- remove_sheets : remove sheets before comparison (only for excel files).
64
-
42
+ old, new : pandas.DataFrame or str
43
+ data sources to compare. Both arguments must be dfs, CSV
44
+ paths, or Excel paths.
45
+ uid : str, False, or None, default None
46
+ col used to identify corresponding rows. If ``None``, a suitable
47
+ shared col is selected automatically. If ``False``, the index is
48
+ used.
49
+ mode : {'mix', 'old', 'new', 'new+'}, default 'mix'
50
+ controls the values included in each result.
51
+ - 'mix': show rows and cols from old and new df.
52
+ additions and deletions are highlighted.
53
+ - 'old': show only rows and cols from the old df.
54
+ deletions are highlighted.
55
+ - 'new': show only rows and cols from the new df.
56
+ additions are highlighted.
57
+ - 'new+': also preserve changed old values in parallel metadata cols.
58
+ rename_cols : dict, optional
59
+ mapping of original col names to names used during comparison.
60
+ remove_cols : list or str, optional
61
+ cols removed from both inputs before comparison.
62
+ remove_cols_by_suffix : str, default ''
63
+ remove cols whose names end with this suffix.
64
+ retain_cols : list or str, optional
65
+ keep only the cols from the old df.
66
+ ignore_cols : list or str, optional
67
+ cols excluded from comparison.
68
+ remove_sheets : list or str, optional
69
+ excel sheet names excluded before comparison.
70
+ name : str, default 'data'
71
+ name used for df comparisons and single-sheet files.
72
+ linebreak : str, default '<br>'
73
+ text inserted between multiple diff descriptions.
74
+ suffix_old : str, default ' *old'
75
+ suffix used for metadata cols containing old values in ``'new+'`` mode.
76
+ verbosity : int, default 3
77
+ logging verbosity level.
78
+
79
+ Returns
80
+ -------
81
+ Diffs
82
+ object containing one :class:`Diff` per compared sheet.
83
+
84
+ Raises
85
+ ------
86
+ ValueError
87
+ if the inputs, mode, or UID are invalid.
65
88
 
66
89
  Examples
67
90
  --------
@@ -117,9 +140,9 @@ def rediff(
117
140
  verbosity=3,
118
141
  ) -> Diffs:
119
142
  """
120
- Same as diff(), but using defaults appropriate for
143
+ same as diff(), but using defaults appropriate for
121
144
  when the old data is already a diff output.
122
- Can be imagined as diffing the data
145
+ can be imagined as diffing the data
123
146
  while managing metadata appropriately.
124
147
  """
125
148
  diffs = Diffs(
@@ -145,8 +168,8 @@ def rediff(
145
168
 
146
169
  class Diffs:
147
170
  """
148
- Stores differences between (multiple) dfs.
149
- For more detailed documentation see diff().
171
+ stores differences between (multiple) dfs.
172
+ for more detailed documentation see diff().
150
173
  """
151
174
 
152
175
  def __init__(
@@ -218,7 +241,7 @@ class Diffs:
218
241
 
219
242
  def __getitem__(self, key):
220
243
  """
221
- Get a specific Diff by sheetname or index.
244
+ get a specific Diff by sheetname or index.
222
245
  """
223
246
  if isinstance(key, str):
224
247
  item = self.diffs[key]
@@ -229,7 +252,17 @@ class Diffs:
229
252
 
230
253
  def show(self, sheet=0):
231
254
  """
232
- Show a styled df with highlighted differences between dfs.
255
+ return a styled df with highlighted differences.
256
+
257
+ Parameters
258
+ ----------
259
+ sheet : str or int, default 0
260
+ sheet name or zero-based position.
261
+
262
+ Returns
263
+ -------
264
+ pandas.io.formats.style.Styler
265
+ styled result for the selected sheet.
233
266
  """
234
267
  diff = self[sheet]
235
268
  return diff.result
@@ -237,7 +270,13 @@ class Diffs:
237
270
 
238
271
  def info(self):
239
272
  """
240
- Basic information about the dfs.
273
+ return a df with basic information
274
+ about the compared data sources.
275
+
276
+ Returns
277
+ -------
278
+ pandas.DataFrame
279
+ source names and sizes in kilobytes.
241
280
  """
242
281
  data = {
243
282
  'data': [self.old_name, self.new_name],
@@ -249,7 +288,13 @@ class Diffs:
249
288
 
250
289
  def summary(self) -> pd.DataFrame:
251
290
  """
252
- Summary of differences between dfs.
291
+ return a df with a compact summary
292
+ of differences for each data source.
293
+
294
+ Returns
295
+ -------
296
+ pandas.DataFrame
297
+ counts of changed cols, rows, and values.
253
298
  """
254
299
 
255
300
  details = self.details()
@@ -275,7 +320,13 @@ class Diffs:
275
320
 
276
321
  def details(self) -> pd.DataFrame:
277
322
  """
278
- Detailed information about differences between dfs.
323
+ return a df with detailed information
324
+ on differences for each data source.
325
+
326
+ Returns
327
+ -------
328
+ pandas.DataFrame
329
+ counts and lists of added, removed, and changed items.
279
330
  """
280
331
 
281
332
  names = [name for name in self.diffs.keys()]
@@ -363,29 +414,34 @@ class Diffs:
363
414
  hide_summary=False,
364
415
  ):
365
416
  """
366
- Export diff results to an Excel file with formatting.
417
+ export diff results to an Excel file with formatting.
367
418
 
368
- Creates an Excel file containing diff metadata and individual
369
- sheets for each comparison with highlighted differences. Applies
370
- Excel-specific formatting and hides columns with old values.
419
+ creates an Excel file containing diff metadata and individual
420
+ sheets for each comparison with highlighted differences. applies
421
+ excel-specific formatting and hides cols with old values.
371
422
 
372
423
 
373
424
  Parameters
374
425
  ----------
375
- path : str
376
- File path for the output Excel file
426
+ path : str or os.PathLike
427
+ destination workbook path.
377
428
  index : bool, default False
378
- Whether to include row indices in the Excel output
429
+ whether to include row indices
379
430
  apply_format : bool, default True
380
- Whether to apply formatting to the Excel file
431
+ whether to apply worksheet formatting
381
432
  freeze_panes : str, default 'C2'
382
- Cell reference for freezing panes in the Excel file
433
+ cell reference for freezing panes
383
434
  hide_info : bool, default True
384
- Whether to hide the info sheet in the Excel file
435
+ whether to hide the info sheet
385
436
  hide_details : bool, default True
386
- Whether to hide the details sheet in the Excel file
437
+ whether to hide the details sheet
387
438
  hide_summary : bool, default False
388
- Whether to hide the summary sheet in the Excel file
439
+ whether to hide the summary sheet.
440
+
441
+ Returns
442
+ -------
443
+ None
444
+ the workbook is written to ``path``.
389
445
  """
390
446
 
391
447
  msg = f'DEBUG: saving differences to "{path}"'
@@ -724,8 +780,11 @@ def _get_single_diff(
724
780
 
725
781
  class Diff:
726
782
  """
727
- Stores differences between 2 dfs.
728
- For more detailed documentation see diff().
783
+ store differences between two dfs.
784
+
785
+ a ``Diff`` is normally created internally by :func:`diff` and contains
786
+ comparison statistics, difference masks, and a styled result for one
787
+ sheet.
729
788
  """
730
789
 
731
790
  def __init__(
@@ -821,7 +880,10 @@ class Diff:
821
880
 
822
881
  def _handle_edgecases(d: Diff) -> Diff:
823
882
  """
824
- Handle edge cases where one or both dfs are empty.
883
+ handle comparisons where one or both dfs are empty.
884
+
885
+ the result is marked as empty, added, or removed
886
+ and receives the corresponding worksheet styling.
825
887
  """
826
888
 
827
889
  if d.old.empty and d.new.empty:
@@ -926,8 +988,7 @@ def _remove_cols(d: Diff, cols: list) -> Diff:
926
988
 
927
989
  def _remove_cols_by_suffix(d: Diff, suffix: str) -> Diff:
928
990
  """
929
- Remove cols from both dfs ending with
930
- a specific suffix before diffing.
991
+ remove cols ending with ``suffix`` before comparison.
931
992
  """
932
993
 
933
994
  if not suffix:
@@ -955,8 +1016,9 @@ def _remove_cols_by_suffix(d: Diff, suffix: str) -> Diff:
955
1016
 
956
1017
  def _set_uid(d: Diff, uid: typing.Any) -> Diff:
957
1018
  """
958
- set unique identifier (uid) column for
959
- comparing rows between old and new dfs.
1019
+ set the row identifier used to compare the two dfs.
1020
+
1021
+ duplicate identifiers are made unique with :func:`deduplicate`.
960
1022
  """
961
1023
 
962
1024
  if uid is False:
@@ -989,7 +1051,7 @@ def _set_uid(d: Diff, uid: typing.Any) -> Diff:
989
1051
  d.uid = uid
990
1052
 
991
1053
  else:
992
- raise ValueError(f"UID column {uid!r} not found in both dataframes.")
1054
+ raise ValueError(f"UID column {uid!r} not found in both dfs.")
993
1055
 
994
1056
 
995
1057
  if not d.old.index.is_unique:
@@ -1049,7 +1111,7 @@ def _find_uid(
1049
1111
 
1050
1112
  def _retain_cols(d: Diff, cols: list) -> Diff:
1051
1113
  """
1052
- Remove cols from both dfs before diffing,
1114
+ remove cols from both dfs before diffing,
1053
1115
  then readd the ones from the old df to
1054
1116
  the diff result later.
1055
1117
  """
@@ -1073,8 +1135,7 @@ def _retain_cols(d: Diff, cols: list) -> Diff:
1073
1135
 
1074
1136
  def _ignore_cols(d: Diff, cols: list) -> Diff:
1075
1137
  """
1076
- Ignore columns for diffing,
1077
- but keep them in both dfs.
1138
+ keep selected cols while excluding them from comparison.
1078
1139
  """
1079
1140
 
1080
1141
  if not cols:
@@ -2,6 +2,7 @@
2
2
  import os
3
3
  import openpyxl
4
4
  import pandas as pd
5
+
5
6
  from .typing import list_
6
7
  from .utils import (
7
8
  log,
@@ -20,12 +21,43 @@ def format(
20
21
  align_horizontal='left',
21
22
  wrap_text=True,
22
23
  verbosity=3,
23
- ): #pragma: no cover (does not affect reading of xlsx files)
24
+ ):
24
25
  """
25
- applies formatting to an Excel file:
26
- - adjust col width to max length of cell content (accounts for linebreaks)
27
- - set cell alignment to top-left and wrap text
28
- - hide specified columns
26
+ apply formatting to an Excel file in place.
27
+
28
+ col widths are adjusted to cell content,
29
+ text is aligned and wrapped, and requested
30
+ sheets or cols can be hidden.
31
+
32
+ Parameters
33
+ ----------
34
+ path : str or os.PathLike
35
+ file to format.
36
+ sheet : str or list[str], optional
37
+ sheets to format. defaults to all sheets.
38
+ freeze_panes : str, optional
39
+ excel cell reference for frozen panes.
40
+ hide_sheets : str or list[str], optional
41
+ sheets to hide.
42
+ hide_cols : str or list[str], optional
43
+ col names to hide.
44
+ col_width_max : int, default 70
45
+ maximum calculated col width.
46
+ col_width_padding : int, default 2
47
+ extra width added to calculated widths.
48
+ align_vertical : str, default 'top'
49
+ vertical cell alignment.
50
+ align_horizontal : str, default 'left'
51
+ horizontal cell alignment.
52
+ wrap_text : bool, default True
53
+ whether cell contents should wrap.
54
+ verbosity : int, default 3
55
+ logging verbosity level.
56
+
57
+ Returns
58
+ -------
59
+ None
60
+ the workbook is saved back to ``path``.
29
61
  """
30
62
 
31
63
  wb = openpyxl.load_workbook(path)
@@ -106,6 +138,30 @@ def save(
106
138
  format_excel=True,
107
139
  **kwargs,
108
140
  ):
141
+ """
142
+ write a df to an Excel file.
143
+
144
+ Parameters
145
+ ----------
146
+ df : pandas.DataFrame
147
+ df to write.
148
+ path : str
149
+ destination file path.
150
+ sheet_name : str, default 'df'
151
+ sheet name.
152
+ index : bool, default False
153
+ whether to write the df index.
154
+ format_excel : bool, default True
155
+ whether to format the workbook after writing.
156
+ **kwargs
157
+ additional keyword arguments passed to
158
+ :meth:`pandas.DataFrame.to_excel`.
159
+
160
+ Returns
161
+ -------
162
+ None
163
+ the df is written to ``path``.
164
+ """
109
165
 
110
166
  if os.path.exists(path):
111
167
  writer = pd.ExcelWriter(