mergeron_extra 2024.739148.0__tar.gz → 2024.739148.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.1
2
2
  Name: mergeron_extra
3
- Version: 2024.739148.0
3
+ Version: 2024.739148.5
4
4
  Summary: Tools for users of the mergeron package.
5
5
  License: MIT
6
6
  Author: Murthy Kambhampaty
@@ -20,7 +20,7 @@ Classifier: Programming Language :: Python :: Implementation :: CPython
20
20
  Requires-Dist: aenum (>=3.1.15,<4.0.0)
21
21
  Requires-Dist: certifi (>=2023.11.17)
22
22
  Requires-Dist: matplotlib (>=3.8)
23
- Requires-Dist: numpy (>=1.26)
23
+ Requires-Dist: numpy (>=2.0)
24
24
  Requires-Dist: scipy (>=1.12)
25
25
  Requires-Dist: xlsxwriter (>=3.1)
26
26
  Description-Content-Type: text/x-rst
@@ -4,7 +4,7 @@ description = "Tools for users of the mergeron package."
4
4
  authors = ["Murthy Kambhampaty <smk@capeconomics.com>"]
5
5
  license = "MIT"
6
6
  readme = "README.rst"
7
- version = "2024.739148.0"
7
+ version = "2024.739148.5"
8
8
 
9
9
  classifiers = [
10
10
  "Development Status :: 4 - Beta",
@@ -30,7 +30,7 @@ build-backend = "poetry.core.masonry.api"
30
30
  # if poetry dependency resolution appears to hang (read the page at link to the end)
31
31
  aenum = "^3.1.15"
32
32
  matplotlib = ">=3.8"
33
- numpy = ">=1.26"
33
+ numpy = ">=2.0"
34
34
  python = "^3.12"
35
35
  scipy = ">=1.12"
36
36
  xlsxwriter = ">=3.1"
@@ -147,6 +147,7 @@ preview = true
147
147
  python_version = "3.12"
148
148
  ignore_missing_imports = false
149
149
  strict = true
150
+ enable_incomplete_feature = ["NewGenericSyntax", "PreciseTupleTypes"]
150
151
 
151
152
  show_column_numbers = true
152
153
  show_error_codes = true
@@ -155,8 +156,6 @@ show_error_context = true
155
156
  no_implicit_optional = true
156
157
  no_implicit_reexport = true
157
158
 
158
- allow_redefinition = true
159
-
160
159
  plugins = "numpy.typing.mypy_plugin"
161
160
 
162
161
  [tool.pytest.ini_options]
@@ -1,25 +1,12 @@
1
1
  from __future__ import annotations
2
2
 
3
- from pathlib import Path
4
-
5
3
  import numpy as np
6
4
  from numpy.typing import NDArray
7
5
 
8
- _PKG_NAME: str = Path(__file__).parent.stem
9
-
10
- VERSION = "2024.739097.4"
6
+ VERSION = "2024.739148.5"
11
7
 
12
8
  __version__ = VERSION
13
9
 
14
- DATA_DIR: Path = Path.home() / _PKG_NAME
15
- """
16
- Defines a subdirectory named for this package in the user's home path.
17
-
18
- If the subdirectory doesn't exist, it is created on package invocation.
19
- """
20
- if not DATA_DIR.is_dir():
21
- DATA_DIR.mkdir(parents=False)
22
-
23
10
  np.set_printoptions(precision=24, floatmode="fixed")
24
11
 
25
12
  type ArrayBoolean = NDArray[np.bool_]
@@ -9,11 +9,11 @@ All rights reserved.
9
9
  License: Standard 3-clause BSD
10
10
  """
11
11
 
12
- __version__ = "2022.10"
12
+ __version__ = "2022.10.p0"
13
13
 
14
14
  from collections import namedtuple
15
15
  from collections.abc import Callable, Sequence
16
- from typing import Literal
16
+ from typing import Final, Literal, TypeAlias
17
17
 
18
18
  import numpy as np
19
19
  from matplotlib.colors import LinearSegmentedColormap, to_rgba_array
@@ -54,7 +54,7 @@ class TOLcmaps:
54
54
  """
55
55
  # self.cmap: LinearSegmentedColormap | None = None
56
56
  self.cname: str = ""
57
- self.namelist: Sequence[str] = (
57
+ self.namelist: Final = (
58
58
  "sunset_discrete",
59
59
  "sunset",
60
60
  "nightfall_discrete",
@@ -648,9 +648,7 @@ class TOLcmaps:
648
648
  return self.cmap
649
649
 
650
650
 
651
- def tol_cmap(
652
- colormap: str | None = None, lut: int | None = None
653
- ) -> Sequence[str] | LinearSegmentedColormap:
651
+ def tol_cmap(colormap: str, lut: int | None = None) -> LinearSegmentedColormap:
654
652
  """
655
653
  Continuous and discrete color sets for ordered data.
656
654
 
@@ -658,8 +656,6 @@ def tol_cmap(
658
656
  Parameter lut is ignored for all colormaps except 'rainbow_discrete'.
659
657
  """
660
658
  obj = TOLcmaps()
661
- if colormap is None:
662
- return obj.namelist
663
659
  if colormap not in obj.namelist:
664
660
  colormap = "rainbow_PuRd"
665
661
  print(
@@ -670,6 +666,10 @@ def tol_cmap(
670
666
  return obj.get(colormap, lut)
671
667
 
672
668
 
669
+ TCName: TypeAlias = Literal[
670
+ "bright", "high-contrast", "vibrant", "muted", "medium-contrast", "light"
671
+ ]
672
+ TCNameList: TypeAlias = tuple[TCName, ...]
673
673
  Bcset = namedtuple("Bcset", "blue red green yellow cyan purple grey black")
674
674
  Hcset = namedtuple("Hcset", "blue yellow red black")
675
675
  Vcset = namedtuple("Vcset", "orange blue cyan magenta red teal grey black")
@@ -685,9 +685,19 @@ Lcset = namedtuple(
685
685
  )
686
686
 
687
687
 
688
+ QL_NAME_LIST: TCNameList = (
689
+ "bright",
690
+ "high-contrast",
691
+ "vibrant",
692
+ "muted",
693
+ "medium-contrast",
694
+ "light",
695
+ )
696
+
697
+
688
698
  def tol_cset( # noqa: PLR0911
689
- colorset: str | None = None,
690
- ) -> Sequence[str] | Bcset | Hcset | Vcset | Muset | Mcset | Lcset:
699
+ colorset: TCName | None,
700
+ ) -> Bcset | Hcset | Vcset | Muset | Mcset | Lcset:
691
701
  """
692
702
  Discrete color sets for qualitative data.
693
703
 
@@ -698,15 +708,6 @@ def tol_cset( # noqa: PLR0911
698
708
  - list(cset) gives a list with all colors
699
709
  """
700
710
 
701
- namelist = (
702
- "bright",
703
- "high-contrast",
704
- "vibrant",
705
- "muted",
706
- "medium-contrast",
707
- "light",
708
- )
709
-
710
711
  Bcinst = Bcset(
711
712
  "#4477AA",
712
713
  "#EE6677",
@@ -718,13 +719,10 @@ def tol_cset( # noqa: PLR0911
718
719
  "#000000",
719
720
  )
720
721
 
721
- if colorset is None:
722
- return namelist
723
-
724
- elif colorset == "bright":
722
+ if colorset == "bright":
725
723
  return Bcinst
726
724
 
727
- elif colorset == "high-contrast":
725
+ if colorset == "high-contrast":
728
726
  return Hcset("#004488", "#DDAA33", "#BB5566", "#000000")
729
727
 
730
728
  elif colorset == "vibrant":
@@ -776,7 +774,7 @@ def tol_cset( # noqa: PLR0911
776
774
  colorset = "bright"
777
775
  print(
778
776
  "*** Warning: requested colorset not defined,",
779
- "known colorsets are {}.".format(namelist), # noqa: UP032
777
+ "known colorsets are {}.".format(QL_NAME_LIST), # noqa: UP032
780
778
  "Using {}.".format(colorset), # noqa: UP032
781
779
  )
782
780
  return Bcinst
@@ -790,27 +788,27 @@ def main() -> None:
790
788
  # plt.cm.register_cmap('rainbow_PuRd', tol_cmap('rainbow_PuRd'))
791
789
  # plt.rc('image', cmap='rainbow_PuRd')
792
790
  # Show colorsets tol_cset(<scheme>).
793
- schemes: Sequence[str] = tol_cset()
794
- fig, axes = plt.subplots(ncols=len(schemes), figsize=(9, 3))
791
+ ql_schemes: TCNameList = QL_NAME_LIST
792
+ fig, axes = plt.subplots(ncols=len(ql_schemes), figsize=(9, 3))
795
793
  fig.subplots_adjust(top=0.9, bottom=0.02, left=0.02, right=0.92)
796
- for ax, scheme in zip(axes, schemes): # type: ignore
797
- cset = tol_cset(scheme)
798
- names = cset._fields # type: ignore
794
+ for ax, ql_scheme in zip(axes, ql_schemes):
795
+ cset = tol_cset(ql_scheme)
796
+ names = cset._fields
799
797
  colors = list(cset)
800
798
  for name, color in zip(names, colors):
801
799
  ax.scatter([], [], c=color, s=80, label=name)
802
800
  ax.set_axis_off()
803
801
  ax.legend(loc=2)
804
- ax.set_title(scheme)
802
+ ax.set_title(ql_scheme)
805
803
  plt.show()
806
804
 
807
805
  # Show colormaps tol_cmap(<scheme>).
808
- schemes: Sequence[str] = tol_cmap() # type: ignore
806
+ schemes = TOLcmaps().namelist
809
807
  gradient = np.linspace(0, 1, 256)
810
808
  gradient = np.vstack((gradient, gradient))
811
809
  fig, axes = plt.subplots(nrows=len(schemes))
812
810
  fig.subplots_adjust(top=0.98, bottom=0.02, left=0.2, right=0.99)
813
- for ax, scheme in zip(axes, schemes): # type: ignore
811
+ for ax, scheme in zip(axes, schemes):
814
812
  pos = list(ax.get_position().bounds)
815
813
  ax.set_axis_off()
816
814
  ax.imshow(gradient, aspect=4, cmap=tol_cmap(scheme))
@@ -829,7 +827,7 @@ def main() -> None:
829
827
  gradient = np.vstack((gradient, gradient))
830
828
  fig, axes = plt.subplots(nrows=23)
831
829
  fig.subplots_adjust(top=0.98, bottom=0.02, left=0.25, right=0.99)
832
- for lut, ax in enumerate(axes, start=1): # type: ignore
830
+ for lut, ax in enumerate(axes, start=1):
833
831
  pos = list(ax.get_position().bounds)
834
832
  ax.set_axis_off()
835
833
  ax.imshow(gradient, aspect=4, cmap=tol_cmap("rainbow_discrete", lut))
@@ -24,14 +24,15 @@ https://mit-license.org/
24
24
  from __future__ import annotations
25
25
 
26
26
  from collections.abc import Sequence
27
+ from types import MappingProxyType
27
28
  from typing import Any, ClassVar, Literal, TypeAlias, TypedDict
28
29
 
29
30
  import numpy as np
30
31
  from aenum import Enum, extend_enum, unique # type: ignore
31
32
  from numpy.typing import NDArray
32
- from xlsxwriter.format import Format
33
- from xlsxwriter.workbook import Workbook
34
- from xlsxwriter.worksheet import Worksheet
33
+ from xlsxwriter.format import Format # type: ignore
34
+ from xlsxwriter.workbook import Workbook # type: ignore
35
+ from xlsxwriter.worksheet import Worksheet # type: ignore
35
36
 
36
37
  from . import VERSION
37
38
 
@@ -150,49 +151,52 @@ class CFmt(Enum): # type: ignore
150
151
 
151
152
  """
152
153
 
153
- XL_DEFAULT: ClassVar = {"font_name": "Calibri", "font_size": 11}
154
- XL_DEFAULT_2003: ClassVar = {"font_name": "Arial", "font_size": 10}
155
-
156
- A_CTR: ClassVar = {"align": "center"}
157
- A_CTR_ACROSS: ClassVar = {"align": "center_across"}
158
- A_LEFT: ClassVar = {"align": "left"}
159
- A_RIGHT: ClassVar = {"align": "right"}
160
- V_TOP: ClassVar = {"align": "top"}
161
- V_BOTTOM: ClassVar = {"align": "bottom"}
162
- V_CTR: ClassVar = {"align": "vcenter"}
163
-
164
- TEXT_WRAP: ClassVar = {"text_wrap": True}
165
- TEXT_ROTATE: ClassVar = {"rotation": 90}
166
- IND_1: ClassVar = {"indent": 1}
167
-
168
- BOLD: ClassVar = {"bold": True}
169
- BOLD_ITALIC: ClassVar = {"bold": True, "italic": True}
170
- ITALIC: ClassVar = {"italic": True}
171
- ULINE: ClassVar = {"underline": "single"}
172
- SOUT: ClassVar = {"font_strikeout": True}
154
+ XL_DEFAULT: ClassVar = MappingProxyType({"font_name": "Calibri", "font_size": 11})
155
+ XL_DEFAULT_2003: ClassVar = MappingProxyType({
156
+ "font_name": "Arial",
157
+ "font_size": 10,
158
+ })
159
+
160
+ A_CTR: ClassVar = MappingProxyType({"align": "center"})
161
+ A_CTR_ACROSS: ClassVar = MappingProxyType({"align": "center_across"})
162
+ A_LEFT: ClassVar = MappingProxyType({"align": "left"})
163
+ A_RIGHT: ClassVar = MappingProxyType({"align": "right"})
164
+ V_TOP: ClassVar = MappingProxyType({"align": "top"})
165
+ V_BOTTOM: ClassVar = MappingProxyType({"align": "bottom"})
166
+ V_CTR: ClassVar = MappingProxyType({"align": "vcenter"})
167
+
168
+ TEXT_WRAP: ClassVar = MappingProxyType({"text_wrap": True})
169
+ TEXT_ROTATE: ClassVar = MappingProxyType({"rotation": 90})
170
+ IND_1: ClassVar = MappingProxyType({"indent": 1})
171
+
172
+ BOLD: ClassVar = MappingProxyType({"bold": True})
173
+ BOLD_ITALIC: ClassVar = MappingProxyType({"bold": True, "italic": True})
174
+ ITALIC: ClassVar = MappingProxyType({"italic": True})
175
+ ULINE: ClassVar = MappingProxyType({"underline": "single"})
176
+ SOUT: ClassVar = MappingProxyType({"font_strikeout": True})
173
177
  # Useful with write_rich_text()
174
- SUPERSCRIPT: ClassVar = {"font_script": 1}
175
- SUBSCRIPT: ClassVar = {"font_script": 2}
176
-
177
- AREA_NUM: ClassVar = {"num_format": "0.00000000"}
178
- DOLLAR_NUM: ClassVar = {"num_format": "[$$-409]#,##0.00"}
179
- DT_NUM: ClassVar = {"num_format": "mm/dd/yyyy"}
180
- PCT_NUM: ClassVar = {"num_format": "##0%"}
181
- PCT2_NUM: ClassVar = {"num_format": "##0.00%"}
182
- PCT4_NUM: ClassVar = {"num_format": "##0.0000%"}
183
- PCT6_NUM: ClassVar = {"num_format": "##0.000000%"}
184
- PCT8_NUM: ClassVar = {"num_format": "##0.00000000%"}
185
- QTY_NUM: ClassVar = {"num_format": "#,##0.0"}
186
-
187
- BAR_FILL: ClassVar = {"pattern": 1, "bg_color": "dfeadf"}
188
- HDR_FILL: ClassVar = {"pattern": 1, "bg_color": "bfbfbf"}
189
-
190
- FULL_BORDER: ClassVar = {"border": 1, "border_color": "000000"}
191
- BOTTOM_BORDER: ClassVar = {"bottom": 1, "bottom_color": "000000"}
192
- LEFT_BORDER: ClassVar = {"left": 1, "left_color": "000000"}
193
- RIGHT_BORDER: ClassVar = {"right": 1, "right_color": "000000"}
194
- TOP_BORDER: ClassVar = {"top": 1, "top_color": "000000"}
195
- HDR_BORDER: ClassVar = TOP_BORDER | BOTTOM_BORDER
178
+ SUPERSCRIPT: ClassVar = MappingProxyType({"font_script": 1})
179
+ SUBSCRIPT: ClassVar = MappingProxyType({"font_script": 2})
180
+
181
+ AREA_NUM: ClassVar = MappingProxyType({"num_format": "0.00000000"})
182
+ DOLLAR_NUM: ClassVar = MappingProxyType({"num_format": "[$$-409]#,##0.00"})
183
+ DT_NUM: ClassVar = MappingProxyType({"num_format": "mm/dd/yyyy"})
184
+ PCT_NUM: ClassVar = MappingProxyType({"num_format": "##0%"})
185
+ PCT2_NUM: ClassVar = MappingProxyType({"num_format": "##0.00%"})
186
+ PCT4_NUM: ClassVar = MappingProxyType({"num_format": "##0.0000%"})
187
+ PCT6_NUM: ClassVar = MappingProxyType({"num_format": "##0.000000%"})
188
+ PCT8_NUM: ClassVar = MappingProxyType({"num_format": "##0.00000000%"})
189
+ QTY_NUM: ClassVar = MappingProxyType({"num_format": "#,##0.0"})
190
+
191
+ BAR_FILL: ClassVar = MappingProxyType({"pattern": 1, "bg_color": "dfeadf"})
192
+ HDR_FILL: ClassVar = MappingProxyType({"pattern": 1, "bg_color": "bfbfbf"})
193
+
194
+ FULL_BORDER: ClassVar = MappingProxyType({"border": 1, "border_color": "000000"})
195
+ BOTTOM_BORDER: ClassVar = MappingProxyType({"bottom": 1, "bottom_color": "000000"})
196
+ LEFT_BORDER: ClassVar = MappingProxyType({"left": 1, "left_color": "000000"})
197
+ RIGHT_BORDER: ClassVar = MappingProxyType({"right": 1, "right_color": "000000"})
198
+ TOP_BORDER: ClassVar = MappingProxyType({"top": 1, "top_color": "000000"})
199
+ HDR_BORDER: ClassVar = MappingProxyType(TOP_BORDER | BOTTOM_BORDER)
196
200
 
197
201
  @classmethod
198
202
  def add_new(cls, _fmt_name: str, _xlsx_fmt_dict: CFmtVal, /) -> CFmt:
@@ -401,7 +405,6 @@ def array_to_sheet(
401
405
  /,
402
406
  *,
403
407
  cell_format: Sequence[CFmt | Sequence[CFmt]] | CFmt | None = None,
404
- empty_as_blank: bool = True,
405
408
  green_bar_flag: bool = True,
406
409
  ragged_flag: bool = True,
407
410
  ) -> tuple[int, int]:
@@ -510,11 +513,11 @@ def array_to_sheet(
510
513
  elif not len(cell_format) == len(_data_table[0]):
511
514
  raise ValueError("Format tuple does not match data in length.")
512
515
  CFmt.ensure_cell_format_spec_tuple(cell_format)
513
- _cell_format: Sequence[CFmt | Sequence[CFmt]] = cell_format
516
+ _cell_format = cell_format
514
517
  elif isinstance(cell_format, CFmt):
515
518
  _cell_format = (cell_format,) * len(_data_table[0])
516
519
  else:
517
- _cell_format = (CFmt.XL_DEFAULT,) * len(_data_table[0]) # pyright: ignore
520
+ _cell_format = (CFmt.XL_DEFAULT,) * len(_data_table[0])
518
521
 
519
522
  # construct vector of xlslwrter.format.Format objects
520
523
  _wbk_formats = tuple(CFmt.xl_fmt(_xl_book, _cf) for _cf in _cell_format)
@@ -538,17 +541,11 @@ def array_to_sheet(
538
541
  _wbk_fmt_tuple = _wbk_formats_greened if _ri % 2 else _wbk_formats
539
542
  for _ci, _cv in enumerate(_rv):
540
543
  _cf = _wbk_fmt_tuple[_ci]
541
- scalar_to_sheet(
542
- _xl_book,
543
- _xl_sheet,
544
- _row_id + _ri,
545
- _col_id + _ci,
546
- _cv,
547
- _cf,
548
- empty_as_blank=empty_as_blank,
549
- )
544
+ scalar_to_sheet(_xl_book, _xl_sheet, _row_id + _ri, _col_id + _ci, _cv, _cf)
550
545
 
551
- _right_column_id = _col_id + _ci + 1 if _ci > _num_cols else _right_column_id
546
+ _right_column_id = (
547
+ _col_id + len(_rv) if len(_rv) > _num_cols else _right_column_id
548
+ )
552
549
 
553
550
  return _bottom_row_id, _right_column_id
554
551
 
@@ -559,7 +556,6 @@ def scalar_to_sheet(
559
556
  _cell_addr_0: str | int = "A1",
560
557
  /,
561
558
  *_s2s_args: Any,
562
- empty_as_blank: bool = True,
563
559
  ) -> None:
564
560
  """
565
561
  Write to a single cell in a worksheet.
@@ -625,12 +621,10 @@ def scalar_to_sheet(
625
621
  (*_write_args, CFmt.xl_fmt(_xl_book, _cell_fmt)) if _cell_fmt else _write_args
626
622
  )
627
623
 
628
- if empty_as_blank and (_cell_val is None or _cell_val == ""):
624
+ if _cell_val is None or _cell_val == "":
629
625
  _xl_sheet.write_blank(*_write_args)
630
626
  elif (
631
- _cell_val is None
632
- or _cell_val == ""
633
- or isinstance(_cell_val, str)
627
+ isinstance(_cell_val, str)
634
628
  or np.ndim(_cell_val)
635
629
  or _cell_val in (np.inf, -np.inf, np.nan)
636
630
  ):