mergeron 2024.739087.0__tar.gz → 2024.739088.1__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.
Potentially problematic release.
This version of mergeron might be problematic. Click here for more details.
- {mergeron-2024.739087.0 → mergeron-2024.739088.1}/PKG-INFO +1 -1
- {mergeron-2024.739087.0 → mergeron-2024.739088.1}/pyproject.toml +1 -1
- {mergeron-2024.739087.0 → mergeron-2024.739088.1}/src/mergeron/__init__.py +1 -1
- {mergeron-2024.739087.0 → mergeron-2024.739088.1}/src/mergeron/data/jinja2_LaTeX_templates/ftcinvdata_summarypaired_table_template.tex.jinja2 +11 -11
- {mergeron-2024.739087.0 → mergeron-2024.739088.1}/src/mergeron/ext/tol_colors.py +12 -15
- {mergeron-2024.739087.0/src/mergeron/core → mergeron-2024.739088.1/src/mergeron/ext}/xlsxw_helper.py +184 -114
- {mergeron-2024.739087.0 → mergeron-2024.739088.1}/src/mergeron/gen/enforcement_stats.py +144 -104
- {mergeron-2024.739087.0 → mergeron-2024.739088.1}/src/mergeron/gen/market_sample.py +8 -8
- {mergeron-2024.739087.0 → mergeron-2024.739088.1}/src/mergeron/gen/upp_tests.py +32 -32
- {mergeron-2024.739087.0 → mergeron-2024.739088.1}/README.rst +0 -0
- {mergeron-2024.739087.0 → mergeron-2024.739088.1}/src/mergeron/License.txt +0 -0
- {mergeron-2024.739087.0 → mergeron-2024.739088.1}/src/mergeron/core/__init__.py +0 -0
- {mergeron-2024.739087.0 → mergeron-2024.739088.1}/src/mergeron/core/damodaran_margin_data.py +0 -0
- {mergeron-2024.739087.0 → mergeron-2024.739088.1}/src/mergeron/core/ftc_merger_investigations_data.py +0 -0
- {mergeron-2024.739087.0 → mergeron-2024.739088.1}/src/mergeron/core/guidelines_boundaries.py +0 -0
- {mergeron-2024.739087.0 → mergeron-2024.739088.1}/src/mergeron/core/guidelines_boundary_functions.py +0 -0
- {mergeron-2024.739087.0 → mergeron-2024.739088.1}/src/mergeron/core/guidelines_boundary_functions_extra.py +0 -0
- {mergeron-2024.739087.0 → mergeron-2024.739088.1}/src/mergeron/core/proportions_tests.py +0 -0
- {mergeron-2024.739087.0 → mergeron-2024.739088.1}/src/mergeron/core/pseudorandom_numbers.py +0 -0
- {mergeron-2024.739087.0 → mergeron-2024.739088.1}/src/mergeron/data/__init__.py +0 -0
- {mergeron-2024.739087.0 → mergeron-2024.739088.1}/src/mergeron/data/damodaran_margin_data.xls +0 -0
- {mergeron-2024.739087.0 → mergeron-2024.739088.1}/src/mergeron/data/damodaran_margin_data_dict.msgpack +0 -0
- {mergeron-2024.739087.0 → mergeron-2024.739088.1}/src/mergeron/data/ftc_invdata.msgpack +0 -0
- {mergeron-2024.739087.0 → mergeron-2024.739088.1}/src/mergeron/data/jinja2_LaTeX_templates/clrrate_cis_summary_table_template.tex.jinja2 +0 -0
- {mergeron-2024.739087.0 → mergeron-2024.739088.1}/src/mergeron/data/jinja2_LaTeX_templates/ftcinvdata_byhhianddelta_table_template.tex.jinja2 +0 -0
- {mergeron-2024.739087.0 → mergeron-2024.739088.1}/src/mergeron/data/jinja2_LaTeX_templates/ftcinvdata_summary_table_template.tex.jinja2 +0 -0
- {mergeron-2024.739087.0 → mergeron-2024.739088.1}/src/mergeron/data/jinja2_LaTeX_templates/mergeron.cls +0 -0
- {mergeron-2024.739087.0 → mergeron-2024.739088.1}/src/mergeron/data/jinja2_LaTeX_templates/mergeron_table_collection_template.tex.jinja2 +0 -0
- {mergeron-2024.739087.0 → mergeron-2024.739088.1}/src/mergeron/data/jinja2_LaTeX_templates/setup_tikz_tables.tex +0 -0
- {mergeron-2024.739087.0 → mergeron-2024.739088.1}/src/mergeron/demo/__init__.py +0 -0
- {mergeron-2024.739087.0 → mergeron-2024.739088.1}/src/mergeron/demo/visualize_empirical_margin_distribution.py +0 -0
- {mergeron-2024.739087.0 → mergeron-2024.739088.1}/src/mergeron/ext/__init__.py +0 -0
- {mergeron-2024.739087.0 → mergeron-2024.739088.1}/src/mergeron/gen/__init__.py +0 -0
- {mergeron-2024.739087.0 → mergeron-2024.739088.1}/src/mergeron/gen/_data_generation_functions.py +0 -0
- {mergeron-2024.739087.0 → mergeron-2024.739088.1}/src/mergeron/gen/data_generation.py +0 -0
- {mergeron-2024.739087.0 → mergeron-2024.739088.1}/src/mergeron/py.typed +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: mergeron
|
|
3
|
-
Version: 2024.
|
|
3
|
+
Version: 2024.739088.1
|
|
4
4
|
Summary: Merger Policy Analysis using Python
|
|
5
5
|
License: MIT
|
|
6
6
|
Keywords: merger policy analysis,merger guidelines,merger screening,policy presumptions,concentration standards,upward pricing pressure,GUPPI
|
|
@@ -19,19 +19,19 @@
|
|
|
19
19
|
Grouped by Entry Conditions and Reporting Period \\[0.5\baselineskip]}
|
|
20
20
|
\begin{tikzpicture}[auto, font = \sffamily]
|
|
21
21
|
\begin{pgfonlayer}{background}
|
|
22
|
-
\matrix[datatable, nodes = {text width = 27pt,},] (
|
|
22
|
+
\matrix[datatable, nodes = {text width = 27pt,},] (enf_rate_raw) {
|
|
23
23
|
\JINVAR{ tmpl_data.invdata_datstr -}
|
|
24
24
|
};
|
|
25
25
|
% Horizontal scoring for totals
|
|
26
|
-
\draw[color = OBSHDRFill, line width = 1pt] (
|
|
26
|
+
\draw[color = OBSHDRFill, line width = 1pt] (enf_rate_raw-\JINVAR{- tmpl_data.invdata_numrows -}-1.north west) -- (enf_rate_raw-\JINVAR{- tmpl_data.invdata_numrows -}-8.north east);
|
|
27
27
|
% Vertical scoring for column groups
|
|
28
|
-
\draw[color = OBSHDRFill, line width = 1pt] (
|
|
29
|
-
\draw[color = OBSHDRFill, line width = 1pt] (
|
|
30
|
-
\draw[color = OBSHDRFill, line width = 1pt] (
|
|
28
|
+
\draw[color = OBSHDRFill, line width = 1pt] (enf_rate_raw-1-2.north east) -- (enf_rate_raw-\JINVAR{- tmpl_data.invdata_numrows -}-2.south east);
|
|
29
|
+
\draw[color = OBSHDRFill, line width = 1pt] (enf_rate_raw-1-4.north east) -- (enf_rate_raw-\JINVAR{- tmpl_data.invdata_numrows -}-4.south east);
|
|
30
|
+
\draw[color = OBSHDRFill, line width = 1pt] (enf_rate_raw-1-6.north east) -- (enf_rate_raw-\JINVAR{- tmpl_data.invdata_numrows -}-6.south east);
|
|
31
31
|
\end{pgfonlayer}
|
|
32
32
|
|
|
33
33
|
\matrix[hrow,
|
|
34
|
-
above = 0 pt of
|
|
34
|
+
above = 0 pt of enf_rate_raw,
|
|
35
35
|
nodes = {minimum height = 33pt, text depth = 10pt, text width = 60pt, align = left, inner sep = 3pt,},
|
|
36
36
|
] (hdrrow_raw) {
|
|
37
37
|
\node[rotate = 90] {Relative \\ Frequency \\}; &
|
|
@@ -64,12 +64,12 @@
|
|
|
64
64
|
Observed Data \\
|
|
65
65
|
};
|
|
66
66
|
% Vertical scoring for column groups
|
|
67
|
-
\draw[color = white, line width = 1pt] (descrow_raw_pds1-1-1.north east) -- (
|
|
68
|
-
\draw[color = white, line width = 1pt] (descrow_raw_mkt1-1-1.north east) -- (
|
|
69
|
-
\draw[color = white, line width = 1pt] (descrow_raw_pds2-1-1.north east) -- (
|
|
67
|
+
\draw[color = white, line width = 1pt] (descrow_raw_pds1-1-1.north east) -- (enf_rate_raw-1-2.north east);
|
|
68
|
+
\draw[color = white, line width = 1pt] (descrow_raw_mkt1-1-1.north east) -- (enf_rate_raw-1-4.north east);
|
|
69
|
+
\draw[color = white, line width = 1pt] (descrow_raw_pds2-1-1.north east) -- (enf_rate_raw-1-6.north east);
|
|
70
70
|
|
|
71
71
|
% Header column - row heads
|
|
72
|
-
\matrix[hcol, left = 0pt of
|
|
72
|
+
\matrix[hcol, left = 0pt of enf_rate_raw, nodes = {
|
|
73
73
|
text width = \JINVAR{ tmpl_data.hdrcol_raw_width -},
|
|
74
74
|
inner xsep = 3 pt,
|
|
75
75
|
},] (hdrcol_raw) {
|
|
@@ -85,7 +85,7 @@
|
|
|
85
85
|
(hdrcoldesc_raw.north east)
|
|
86
86
|
;
|
|
87
87
|
((# % Separator for header column
|
|
88
|
-
\draw[color = white, line width = 1pt] (descrow_raw_mkt1-1-1.north west) -- (
|
|
88
|
+
\draw[color = white, line width = 1pt] (descrow_raw_mkt1-1-1.north west) -- (enf_rate_raw-1-1.north west); #))
|
|
89
89
|
|
|
90
90
|
% Notes below table
|
|
91
91
|
\matrix[anytable,
|
|
@@ -37,24 +37,21 @@ def discretemap(colormap: str, hexclrs: Sequence[str]) -> LinearSegmentedColorma
|
|
|
37
37
|
|
|
38
38
|
|
|
39
39
|
class TOLcmaps:
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
Attributes
|
|
44
|
-
----------
|
|
45
|
-
cmap
|
|
46
|
-
A matploltib colormap
|
|
47
|
-
|
|
48
|
-
cname
|
|
49
|
-
Colormap name
|
|
40
|
+
def __init__(self) -> None:
|
|
41
|
+
"""
|
|
42
|
+
Class TOLcmaps definition.
|
|
50
43
|
|
|
51
|
-
|
|
52
|
-
|
|
44
|
+
Attributes
|
|
45
|
+
----------
|
|
46
|
+
cmap
|
|
47
|
+
A matploltib colormap
|
|
53
48
|
|
|
54
|
-
|
|
49
|
+
cname
|
|
50
|
+
Colormap name
|
|
55
51
|
|
|
56
|
-
|
|
57
|
-
|
|
52
|
+
namelist
|
|
53
|
+
A list of colormap names
|
|
54
|
+
"""
|
|
58
55
|
# self.cmap: LinearSegmentedColormap | None = None
|
|
59
56
|
self.cname: str = ""
|
|
60
57
|
self.namelist: Sequence[str] = (
|
{mergeron-2024.739087.0/src/mergeron/core → mergeron-2024.739088.1/src/mergeron/ext}/xlsxw_helper.py
RENAMED
|
@@ -21,12 +21,14 @@ from typing import Any, ClassVar
|
|
|
21
21
|
import numpy as np
|
|
22
22
|
import numpy.typing as npt
|
|
23
23
|
import xlsxwriter # type: ignore
|
|
24
|
-
from aenum import Enum, unique # type: ignore
|
|
24
|
+
from aenum import Enum, extend_enum, unique # type: ignore
|
|
25
25
|
|
|
26
26
|
from .. import VERSION # noqa: TID252
|
|
27
27
|
|
|
28
28
|
__version__ = VERSION
|
|
29
29
|
|
|
30
|
+
Workbook = xlsxwriter.Workbook
|
|
31
|
+
|
|
30
32
|
|
|
31
33
|
@unique
|
|
32
34
|
class CFmt(dict, Enum): # type: ignore
|
|
@@ -34,7 +36,7 @@ class CFmt(dict, Enum): # type: ignore
|
|
|
34
36
|
Initialize cell formats for xlsxwriter.
|
|
35
37
|
|
|
36
38
|
The mappings included here, and unions, etc. of them
|
|
37
|
-
and any others added at runtime,
|
|
39
|
+
and any others added at runtime, are rendered
|
|
38
40
|
as xlsxWriter.Workbook.Format objects for writing
|
|
39
41
|
cell values to formatted cells in a spreadsheet.
|
|
40
42
|
|
|
@@ -43,6 +45,7 @@ class CFmt(dict, Enum): # type: ignore
|
|
|
43
45
|
|
|
44
46
|
For more information about xlsxwriter's cell formats,
|
|
45
47
|
see, https://xlsxwriter.readthedocs.io/format.html
|
|
48
|
+
|
|
46
49
|
"""
|
|
47
50
|
|
|
48
51
|
XL_DEFAULT: ClassVar = {"font_name": "Calibri", "font_size": 11}
|
|
@@ -52,28 +55,35 @@ class CFmt(dict, Enum): # type: ignore
|
|
|
52
55
|
A_CTR_ACROSS: ClassVar = {"align": "center_across"}
|
|
53
56
|
A_LEFT: ClassVar = {"align": "left"}
|
|
54
57
|
A_RIGHT: ClassVar = {"align": "right"}
|
|
58
|
+
V_TOP: ClassVar = {"align": "top"}
|
|
59
|
+
V_BOTTOM: ClassVar = {"align": "bottom"}
|
|
60
|
+
V_CTR: ClassVar = {"align": "vcenter"}
|
|
61
|
+
|
|
62
|
+
TEXT_WRAP: ClassVar = {"text_wrap": True}
|
|
63
|
+
TEXT_ROTATE: ClassVar = {"rotation": 90}
|
|
64
|
+
IND_1: ClassVar = {"indent": 1}
|
|
55
65
|
|
|
56
66
|
BOLD: ClassVar = {"bold": True}
|
|
57
67
|
BOLD_ITALIC: ClassVar = {"bold": True, "italic": True}
|
|
58
68
|
ITALIC: ClassVar = {"italic": True}
|
|
59
69
|
ULINE: ClassVar = {"underline": True}
|
|
70
|
+
SOUT: ClassVar = {"font_strikeout": True}
|
|
71
|
+
# Useful with write_rich_text()
|
|
72
|
+
SUPERSCRIPT: ClassVar = {"font_script": 1}
|
|
73
|
+
SUBSCRIPT: ClassVar = {"font_script": 2}
|
|
60
74
|
|
|
61
|
-
|
|
62
|
-
TEXT_ROTATE: ClassVar = {"rotation": 90}
|
|
63
|
-
IND_1: ClassVar = {"indent": 1}
|
|
64
|
-
|
|
75
|
+
AREA_NUM: ClassVar = ({"num_format": "0.00000000"},)
|
|
65
76
|
DOLLAR_NUM: ClassVar = {"num_format": "[$$-409]#,##0.00"}
|
|
66
77
|
DT_NUM: ClassVar = {"num_format": "mm/dd/yyyy"}
|
|
67
|
-
QTY_NUM: ClassVar = {"num_format": "#,##0.0"}
|
|
68
78
|
PCT_NUM: ClassVar = {"num_format": "##0%"}
|
|
69
79
|
PCT2_NUM: ClassVar = {"num_format": "##0.00%"}
|
|
70
80
|
PCT4_NUM: ClassVar = {"num_format": "##0.0000%"}
|
|
71
81
|
PCT6_NUM: ClassVar = {"num_format": "##0.000000%"}
|
|
72
82
|
PCT8_NUM: ClassVar = {"num_format": "##0.00000000%"}
|
|
73
|
-
|
|
83
|
+
QTY_NUM: ClassVar = {"num_format": "#,##0.0"}
|
|
74
84
|
|
|
75
85
|
BAR_FILL: ClassVar = {"pattern": 1, "bg_color": "dfeadf"}
|
|
76
|
-
HDR_FILL: ClassVar = {"pattern": 1, "bg_color": "
|
|
86
|
+
HDR_FILL: ClassVar = {"pattern": 1, "bg_color": "e9e9e9"}
|
|
77
87
|
|
|
78
88
|
LEFT_BORDER: ClassVar = {"left": 1, "left_color": "000000"}
|
|
79
89
|
RIGHT_BORDER: ClassVar = {"right": 1, "right_color": "000000"}
|
|
@@ -81,6 +91,115 @@ class CFmt(dict, Enum): # type: ignore
|
|
|
81
91
|
TOP_BORDER: ClassVar = {"top": 1, "top_color": "000000"}
|
|
82
92
|
HDR_BORDER: ClassVar = TOP_BORDER | BOT_BORDER
|
|
83
93
|
|
|
94
|
+
@classmethod
|
|
95
|
+
def add_new(self, _fmt_name: str, _xlsx_fmt_dict: dict[str, Any], /) -> CFmt:
|
|
96
|
+
"""
|
|
97
|
+
Add new CFmt object to instance.
|
|
98
|
+
|
|
99
|
+
Parameters
|
|
100
|
+
----------
|
|
101
|
+
_fmt_name
|
|
102
|
+
Name of new member to be added to CFmt
|
|
103
|
+
_xlsx_fmt_dict
|
|
104
|
+
Any valid argument to xlsxwriter.Workbook.add_format(), or union of
|
|
105
|
+
same with one or more CFmt objects with same, e.g.,
|
|
106
|
+
CFmt.HDR_BORDER | CFmt.HDR_FILL or
|
|
107
|
+
CFmt.HDR_BORDER | {"pattern": 1, "bg_color": "f2f2f2"}
|
|
108
|
+
|
|
109
|
+
Returns
|
|
110
|
+
-------
|
|
111
|
+
None
|
|
112
|
+
|
|
113
|
+
"""
|
|
114
|
+
|
|
115
|
+
return extend_enum(self, _fmt_name, _xlsx_fmt_dict) # type: ignore
|
|
116
|
+
|
|
117
|
+
@classmethod
|
|
118
|
+
def ensure_cell_format_spec_tuple(
|
|
119
|
+
self, _cell_formats: Sequence[CFmt | Sequence[CFmt]], /
|
|
120
|
+
) -> bool:
|
|
121
|
+
"""
|
|
122
|
+
Test that a given format specification is a tuple of CFmt enums
|
|
123
|
+
|
|
124
|
+
Parameters
|
|
125
|
+
----------
|
|
126
|
+
_cell_formats
|
|
127
|
+
Format specification
|
|
128
|
+
|
|
129
|
+
Raises
|
|
130
|
+
------
|
|
131
|
+
ValueError
|
|
132
|
+
If format specification is not tuple of CFmt enums
|
|
133
|
+
|
|
134
|
+
Returns
|
|
135
|
+
-------
|
|
136
|
+
True if format specification passes, else False
|
|
137
|
+
|
|
138
|
+
"""
|
|
139
|
+
|
|
140
|
+
for _cell_format in _cell_formats:
|
|
141
|
+
if isinstance(_cell_format, tuple):
|
|
142
|
+
self.ensure_cell_format_spec_tuple(_cell_format)
|
|
143
|
+
|
|
144
|
+
if not (isinstance(_cell_format, CFmt),):
|
|
145
|
+
raise ValueError(
|
|
146
|
+
"Improperly specified format tuple for writing array."
|
|
147
|
+
" Must be tuple of CFmt enums."
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
return True
|
|
151
|
+
|
|
152
|
+
@classmethod
|
|
153
|
+
def xl_fmt(
|
|
154
|
+
self,
|
|
155
|
+
_xl_book: xlsxwriter.Workbook,
|
|
156
|
+
_cell_fmt: Sequence[CFmt | Sequence[CFmt]] | CFmt | None,
|
|
157
|
+
/,
|
|
158
|
+
) -> xlsxwriter.format.Format:
|
|
159
|
+
"""
|
|
160
|
+
Return :code:`xlsxwriter` `Format` object given a CFmt aenum, or tuple thereof.
|
|
161
|
+
|
|
162
|
+
Parameters
|
|
163
|
+
----------
|
|
164
|
+
_xl_book
|
|
165
|
+
:code:`xlsxwriter.Workbook` object
|
|
166
|
+
|
|
167
|
+
_cell_fmt
|
|
168
|
+
:code:`CFmt` aenum object, or tuple thereof
|
|
169
|
+
|
|
170
|
+
Raises
|
|
171
|
+
------
|
|
172
|
+
ValueError
|
|
173
|
+
If format specification is not one of None, a CFmt aenum, or
|
|
174
|
+
a xlsxwriter.format.Format object
|
|
175
|
+
|
|
176
|
+
Returns
|
|
177
|
+
-------
|
|
178
|
+
:code:`xlsxwriter` `Format` object
|
|
179
|
+
|
|
180
|
+
"""
|
|
181
|
+
|
|
182
|
+
if isinstance(_cell_fmt, xlsxwriter.format.Format):
|
|
183
|
+
return _cell_fmt
|
|
184
|
+
elif _cell_fmt is None:
|
|
185
|
+
return _xl_book.add_format(CFmt.XL_DEFAULT.value)
|
|
186
|
+
|
|
187
|
+
_cell_fmt_dict: Mapping[str, Any] = {}
|
|
188
|
+
if isinstance(_cell_fmt, Sequence):
|
|
189
|
+
self.ensure_cell_format_spec_tuple(_cell_fmt)
|
|
190
|
+
for _cf in _cell_fmt:
|
|
191
|
+
_cell_fmt_dict = (
|
|
192
|
+
(_cell_fmt_dict | _cfi.value for _cfi in _cf)
|
|
193
|
+
if isinstance(_cf, Sequence)
|
|
194
|
+
else _cell_fmt_dict | _cf.value
|
|
195
|
+
)
|
|
196
|
+
elif isinstance(_cell_fmt, CFmt):
|
|
197
|
+
_cell_fmt_dict = _cell_fmt.value
|
|
198
|
+
else:
|
|
199
|
+
raise ValueError("Improperly specified format specification.")
|
|
200
|
+
|
|
201
|
+
return _xl_book.add_format(_cell_fmt_dict)
|
|
202
|
+
|
|
84
203
|
|
|
85
204
|
def write_header(
|
|
86
205
|
_xl_sheet: xlsxwriter.worksheet.Worksheet,
|
|
@@ -156,7 +275,7 @@ def write_footer(
|
|
|
156
275
|
None
|
|
157
276
|
"""
|
|
158
277
|
|
|
159
|
-
if
|
|
278
|
+
if any((center_footer, left_footer, right_footer)):
|
|
160
279
|
_xl_sheet.set_footer(
|
|
161
280
|
"".join([
|
|
162
281
|
f"&L{left_footer}" if left_footer else "",
|
|
@@ -235,6 +354,17 @@ def array_to_sheet(
|
|
|
235
354
|
-------
|
|
236
355
|
Tuple giving address of cell at right below and after range written
|
|
237
356
|
|
|
357
|
+
|
|
358
|
+
Notes
|
|
359
|
+
-----
|
|
360
|
+
|
|
361
|
+
The keyword argument cell_format may be passed a tuple of CFmt enums,
|
|
362
|
+
if, and only if, ragged_flag is False. If cell_format is a tuple, it must
|
|
363
|
+
have length equal to the number of cells in the range to be written. Further,
|
|
364
|
+
members of cell_format must each be a CFmt enum or a tuple of CFmt enums; in
|
|
365
|
+
other words, `CFmt.ensure_cell_format_spec_tuple(_c)` must return True for
|
|
366
|
+
any tuple `_c` passed as `cell_format`.
|
|
367
|
+
|
|
238
368
|
"""
|
|
239
369
|
|
|
240
370
|
if not ragged_flag:
|
|
@@ -268,7 +398,7 @@ def array_to_sheet(
|
|
|
268
398
|
)
|
|
269
399
|
elif not len(cell_format) == len(_data_table[0]):
|
|
270
400
|
raise ValueError("Format tuple does not match data in length.")
|
|
271
|
-
ensure_cell_format_spec_tuple(cell_format)
|
|
401
|
+
CFmt.ensure_cell_format_spec_tuple(cell_format)
|
|
272
402
|
_cell_format: Sequence[CFmt | Sequence[CFmt]] = cell_format
|
|
273
403
|
elif isinstance(cell_format, CFmt):
|
|
274
404
|
_cell_format = (cell_format,) * len(_data_table[0])
|
|
@@ -276,21 +406,27 @@ def array_to_sheet(
|
|
|
276
406
|
_cell_format = (CFmt.XL_DEFAULT,) * len(_data_table[0])
|
|
277
407
|
|
|
278
408
|
# construct vector of xlslwrter.format.Format objects
|
|
279
|
-
_wbk_formats = tuple(xl_fmt(_xl_book, _cf) for _cf in _cell_format)
|
|
409
|
+
_wbk_formats = tuple(CFmt.xl_fmt(_xl_book, _cf) for _cf in _cell_format)
|
|
280
410
|
if _num_rows > 1:
|
|
281
411
|
_wbk_formats_greened = (
|
|
282
|
-
tuple(
|
|
412
|
+
tuple(
|
|
413
|
+
CFmt.xl_fmt(
|
|
414
|
+
_xl_book,
|
|
415
|
+
(*_cf, CFmt.BAR_FILL)
|
|
416
|
+
if isinstance(_cf, Sequence)
|
|
417
|
+
else (_cf, CFmt.BAR_FILL),
|
|
418
|
+
)
|
|
419
|
+
for _cf in _cell_format
|
|
420
|
+
)
|
|
283
421
|
if green_bar_flag
|
|
284
422
|
else _wbk_formats
|
|
285
423
|
)
|
|
286
424
|
|
|
287
425
|
for _ri, _rv in enumerate(_data_table):
|
|
288
|
-
|
|
426
|
+
_wbk_fmt_tuple = _wbk_formats_greened if _ri % 2 else _wbk_formats
|
|
289
427
|
for _ci, _cv in enumerate(_rv):
|
|
290
|
-
|
|
291
|
-
scalar_to_sheet(
|
|
292
|
-
_xl_book, _xl_sheet, _row_id + _ri, _col_id + _ci, _cv, _cell_fmt
|
|
293
|
-
)
|
|
428
|
+
_cf = _wbk_fmt_tuple[_ci]
|
|
429
|
+
scalar_to_sheet(_xl_sheet, _row_id + _ri, _col_id + _ci, _cv, _cf)
|
|
294
430
|
|
|
295
431
|
_right_column_id = _col_id + _ci + 1 if _ci > _num_cols else _right_column_id
|
|
296
432
|
|
|
@@ -298,20 +434,17 @@ def array_to_sheet(
|
|
|
298
434
|
|
|
299
435
|
|
|
300
436
|
def scalar_to_sheet(
|
|
301
|
-
_xl_book: xlsxwriter.workbook.Workbook,
|
|
302
437
|
_xl_sheet: xlsxwriter.worksheet.Worksheet,
|
|
303
|
-
_cell_addr_0: str | int
|
|
438
|
+
_cell_addr_0: str | int = "A1",
|
|
304
439
|
/,
|
|
305
440
|
*_s2s_args: Any,
|
|
441
|
+
empty_as_blank: bool = True,
|
|
306
442
|
) -> None:
|
|
307
443
|
"""
|
|
308
444
|
Write to a single cell in a worksheet.
|
|
309
445
|
|
|
310
446
|
Parameters
|
|
311
447
|
----------
|
|
312
|
-
_xl_book
|
|
313
|
-
Workbook object
|
|
314
|
-
|
|
315
448
|
_xl_sheet
|
|
316
449
|
Worksheet object to which to write the give array
|
|
317
450
|
|
|
@@ -337,104 +470,41 @@ def scalar_to_sheet(
|
|
|
337
470
|
|
|
338
471
|
"""
|
|
339
472
|
|
|
473
|
+
_cell_addr: tuple[int | str, ...] = ()
|
|
474
|
+
_cell_val: Any = None
|
|
475
|
+
_cell_fmt: xlsxwriter.format.Format = CFmt.XL_DEFAULT
|
|
476
|
+
|
|
340
477
|
if isinstance(_cell_addr_0, str):
|
|
341
478
|
if len(_s2s_args) not in (1, 2):
|
|
342
|
-
raise ValueError("
|
|
343
|
-
_cell_addr
|
|
344
|
-
_cell_val
|
|
345
|
-
_cell_fmt
|
|
479
|
+
raise ValueError("Incorrect number of arguments.")
|
|
480
|
+
_cell_addr = (_cell_addr_0,)
|
|
481
|
+
_cell_val = _s2s_args[0]
|
|
482
|
+
_cell_fmt = _s2s_args[1] if len(_s2s_args) == 2 else None # type: ignore
|
|
346
483
|
elif isinstance(_cell_addr_0, int):
|
|
347
|
-
if len(_s2s_args) not in (2, 3):
|
|
348
|
-
raise ValueError("
|
|
484
|
+
if len(_s2s_args) not in (2, 3) or not isinstance(_s2s_args[0], int):
|
|
485
|
+
raise ValueError("Incorrect/incomplete specification for Excel cell data.")
|
|
349
486
|
_cell_addr = (_cell_addr_0, _s2s_args[0])
|
|
350
487
|
_cell_val = _s2s_args[1]
|
|
351
488
|
_cell_fmt = _s2s_args[2] if len(_s2s_args) == 3 else None # type: ignore
|
|
352
489
|
else:
|
|
353
490
|
raise ValueError("Incorrect/incomplete specification for Excel cell data.")
|
|
354
491
|
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
Parameters
|
|
373
|
-
----------
|
|
374
|
-
_xl_book
|
|
375
|
-
:code:`xlsxwriter.Workbook` object
|
|
376
|
-
|
|
377
|
-
_cell_fmt
|
|
378
|
-
:code:`CFmt` aenum object, or tuple thereof
|
|
379
|
-
|
|
380
|
-
Raises
|
|
381
|
-
------
|
|
382
|
-
ValueError
|
|
383
|
-
If format specification is not one of None, a CFmt aenum, or
|
|
384
|
-
a xlsxwriter.format.Format object
|
|
385
|
-
|
|
386
|
-
Returns
|
|
387
|
-
-------
|
|
388
|
-
:code:`xlsxwriter` `Format` object
|
|
389
|
-
|
|
390
|
-
"""
|
|
391
|
-
|
|
392
|
-
if isinstance(_cell_fmt, xlsxwriter.format.Format):
|
|
393
|
-
return _cell_fmt
|
|
394
|
-
elif _cell_fmt is None:
|
|
395
|
-
return _xl_book.add_format(CFmt.XL_DEFAULT.value)
|
|
396
|
-
|
|
397
|
-
_cell_fmt_dict: Mapping[str, Any] = {}
|
|
398
|
-
if isinstance(_cell_fmt, Sequence):
|
|
399
|
-
ensure_cell_format_spec_tuple(_cell_fmt)
|
|
400
|
-
for _cf in _cell_fmt:
|
|
401
|
-
_cell_fmt_dict = _cell_fmt_dict | _cf.value
|
|
402
|
-
elif isinstance(_cell_fmt, CFmt):
|
|
403
|
-
_cell_fmt_dict = _cell_fmt.value
|
|
492
|
+
_write_args = (
|
|
493
|
+
(*_cell_addr, repr(_cell_val))
|
|
494
|
+
if np.ndim(_cell_val) or _cell_val in (np.inf, -np.inf, np.nan)
|
|
495
|
+
else (*_cell_addr, _cell_val)
|
|
496
|
+
)
|
|
497
|
+
_write_args = (*_write_args, _cell_fmt) if _cell_fmt else _write_args
|
|
498
|
+
|
|
499
|
+
if empty_as_blank and (_cell_val is None or _cell_val == ""):
|
|
500
|
+
_xl_sheet.write_blank(*_write_args)
|
|
501
|
+
elif (
|
|
502
|
+
_cell_val is None
|
|
503
|
+
or _cell_val == ""
|
|
504
|
+
or isinstance(_cell_val, str)
|
|
505
|
+
or np.ndim(_cell_val)
|
|
506
|
+
or _cell_val in (np.inf, -np.inf, np.nan)
|
|
507
|
+
):
|
|
508
|
+
_xl_sheet.write_string(*_write_args)
|
|
404
509
|
else:
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
return _xl_book.add_format(_cell_fmt_dict)
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
def ensure_cell_format_spec_tuple(
|
|
411
|
-
_cell_formats: Sequence[CFmt | Sequence[CFmt]], /
|
|
412
|
-
) -> None:
|
|
413
|
-
"""
|
|
414
|
-
Test that a given format specification is tuple of CFmt enums
|
|
415
|
-
|
|
416
|
-
Parameters
|
|
417
|
-
----------
|
|
418
|
-
_cell_formats
|
|
419
|
-
Format specification
|
|
420
|
-
|
|
421
|
-
Raises
|
|
422
|
-
------
|
|
423
|
-
ValueError
|
|
424
|
-
If format specification is not tuple of CFmt enums
|
|
425
|
-
|
|
426
|
-
Returns
|
|
427
|
-
-------
|
|
428
|
-
True if format specification passes, else False
|
|
429
|
-
|
|
430
|
-
"""
|
|
431
|
-
|
|
432
|
-
for _cell_format in _cell_formats:
|
|
433
|
-
if isinstance(_cell_format, tuple):
|
|
434
|
-
ensure_cell_format_spec_tuple(_cell_format)
|
|
435
|
-
|
|
436
|
-
if not (isinstance(_cell_format, CFmt),):
|
|
437
|
-
raise ValueError(
|
|
438
|
-
"Improperly specified format tuple for writing array."
|
|
439
|
-
" Must be tuple of CFmt enums."
|
|
440
|
-
)
|
|
510
|
+
_xl_sheet.write(*_write_args)
|