mergeron 2024.739079.13__tar.gz → 2024.739087.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.
Potentially problematic release.
This version of mergeron might be problematic. Click here for more details.
- {mergeron-2024.739079.13 → mergeron-2024.739087.0}/PKG-INFO +1 -1
- {mergeron-2024.739079.13 → mergeron-2024.739087.0}/pyproject.toml +2 -1
- {mergeron-2024.739079.13 → mergeron-2024.739087.0}/src/mergeron/__init__.py +1 -1
- mergeron-2024.739079.13/src/mergeron/core/excel_helper.py → mergeron-2024.739087.0/src/mergeron/core/xlsxw_helper.py +102 -35
- {mergeron-2024.739079.13 → mergeron-2024.739087.0}/README.rst +0 -0
- {mergeron-2024.739079.13 → mergeron-2024.739087.0}/src/mergeron/License.txt +0 -0
- {mergeron-2024.739079.13 → mergeron-2024.739087.0}/src/mergeron/core/__init__.py +0 -0
- {mergeron-2024.739079.13 → mergeron-2024.739087.0}/src/mergeron/core/damodaran_margin_data.py +0 -0
- {mergeron-2024.739079.13 → mergeron-2024.739087.0}/src/mergeron/core/ftc_merger_investigations_data.py +0 -0
- {mergeron-2024.739079.13 → mergeron-2024.739087.0}/src/mergeron/core/guidelines_boundaries.py +0 -0
- {mergeron-2024.739079.13 → mergeron-2024.739087.0}/src/mergeron/core/guidelines_boundary_functions.py +0 -0
- {mergeron-2024.739079.13 → mergeron-2024.739087.0}/src/mergeron/core/guidelines_boundary_functions_extra.py +0 -0
- {mergeron-2024.739079.13 → mergeron-2024.739087.0}/src/mergeron/core/proportions_tests.py +0 -0
- {mergeron-2024.739079.13 → mergeron-2024.739087.0}/src/mergeron/core/pseudorandom_numbers.py +0 -0
- {mergeron-2024.739079.13 → mergeron-2024.739087.0}/src/mergeron/data/__init__.py +0 -0
- {mergeron-2024.739079.13 → mergeron-2024.739087.0}/src/mergeron/data/damodaran_margin_data.xls +0 -0
- {mergeron-2024.739079.13 → mergeron-2024.739087.0}/src/mergeron/data/damodaran_margin_data_dict.msgpack +0 -0
- {mergeron-2024.739079.13 → mergeron-2024.739087.0}/src/mergeron/data/ftc_invdata.msgpack +0 -0
- {mergeron-2024.739079.13 → mergeron-2024.739087.0}/src/mergeron/data/jinja2_LaTeX_templates/clrrate_cis_summary_table_template.tex.jinja2 +0 -0
- {mergeron-2024.739079.13 → mergeron-2024.739087.0}/src/mergeron/data/jinja2_LaTeX_templates/ftcinvdata_byhhianddelta_table_template.tex.jinja2 +0 -0
- {mergeron-2024.739079.13 → mergeron-2024.739087.0}/src/mergeron/data/jinja2_LaTeX_templates/ftcinvdata_summary_table_template.tex.jinja2 +0 -0
- {mergeron-2024.739079.13 → mergeron-2024.739087.0}/src/mergeron/data/jinja2_LaTeX_templates/ftcinvdata_summarypaired_table_template.tex.jinja2 +0 -0
- {mergeron-2024.739079.13 → mergeron-2024.739087.0}/src/mergeron/data/jinja2_LaTeX_templates/mergeron.cls +0 -0
- {mergeron-2024.739079.13 → mergeron-2024.739087.0}/src/mergeron/data/jinja2_LaTeX_templates/mergeron_table_collection_template.tex.jinja2 +0 -0
- {mergeron-2024.739079.13 → mergeron-2024.739087.0}/src/mergeron/data/jinja2_LaTeX_templates/setup_tikz_tables.tex +0 -0
- {mergeron-2024.739079.13 → mergeron-2024.739087.0}/src/mergeron/demo/__init__.py +0 -0
- {mergeron-2024.739079.13 → mergeron-2024.739087.0}/src/mergeron/demo/visualize_empirical_margin_distribution.py +0 -0
- {mergeron-2024.739079.13 → mergeron-2024.739087.0}/src/mergeron/ext/__init__.py +0 -0
- {mergeron-2024.739079.13 → mergeron-2024.739087.0}/src/mergeron/ext/tol_colors.py +0 -0
- {mergeron-2024.739079.13 → mergeron-2024.739087.0}/src/mergeron/gen/__init__.py +0 -0
- {mergeron-2024.739079.13 → mergeron-2024.739087.0}/src/mergeron/gen/_data_generation_functions.py +0 -0
- {mergeron-2024.739079.13 → mergeron-2024.739087.0}/src/mergeron/gen/data_generation.py +0 -0
- {mergeron-2024.739079.13 → mergeron-2024.739087.0}/src/mergeron/gen/enforcement_stats.py +0 -0
- {mergeron-2024.739079.13 → mergeron-2024.739087.0}/src/mergeron/gen/market_sample.py +0 -0
- {mergeron-2024.739079.13 → mergeron-2024.739087.0}/src/mergeron/gen/upp_tests.py +0 -0
- {mergeron-2024.739079.13 → mergeron-2024.739087.0}/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.739087.0
|
|
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
|
|
@@ -13,7 +13,7 @@ keywords = [
|
|
|
13
13
|
"upward pricing pressure",
|
|
14
14
|
"GUPPI",
|
|
15
15
|
]
|
|
16
|
-
version = "2024.
|
|
16
|
+
version = "2024.739087.0"
|
|
17
17
|
|
|
18
18
|
# Classifiers list: https://pypi.org/classifiers/
|
|
19
19
|
classifiers = [
|
|
@@ -184,6 +184,7 @@ allow_redefinition = true
|
|
|
184
184
|
plugins = "numpy.typing.mypy_plugin"
|
|
185
185
|
|
|
186
186
|
[tool.pytest.ini_options]
|
|
187
|
+
log_auto_indent = 4
|
|
187
188
|
minversion = "8.0"
|
|
188
189
|
testpaths = ["tests"]
|
|
189
190
|
addopts = ["--import-mode=importlib"]
|
|
@@ -112,15 +112,17 @@ def write_header(
|
|
|
112
112
|
-------
|
|
113
113
|
None
|
|
114
114
|
"""
|
|
115
|
-
if
|
|
115
|
+
if any((center_header, left_header, right_header)):
|
|
116
|
+
_xl_sheet.set_header(
|
|
117
|
+
"".join([
|
|
118
|
+
f"&L{left_header}" if left_header else "",
|
|
119
|
+
f"&C{center_header}" if center_header else "",
|
|
120
|
+
f"&R{right_header}" if right_header else "",
|
|
121
|
+
])
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
else:
|
|
116
125
|
raise ValueError("must specify at least one header")
|
|
117
|
-
_xl_sheet.set_footer(
|
|
118
|
-
"".join([
|
|
119
|
-
f"&L{left_header}" if left_header else "",
|
|
120
|
-
f"&C{center_header}" if center_header else "",
|
|
121
|
-
f"&R{right_header}" if right_header else "",
|
|
122
|
-
])
|
|
123
|
-
)
|
|
124
126
|
|
|
125
127
|
|
|
126
128
|
def write_footer(
|
|
@@ -155,15 +157,16 @@ def write_footer(
|
|
|
155
157
|
"""
|
|
156
158
|
|
|
157
159
|
if not any((center_footer, left_footer, right_footer)):
|
|
158
|
-
|
|
160
|
+
_xl_sheet.set_footer(
|
|
161
|
+
"".join([
|
|
162
|
+
f"&L{left_footer}" if left_footer else "",
|
|
163
|
+
f"&C{center_footer}" if center_footer else "",
|
|
164
|
+
f"&R{right_footer}" if right_footer else "",
|
|
165
|
+
])
|
|
166
|
+
)
|
|
159
167
|
|
|
160
|
-
|
|
161
|
-
""
|
|
162
|
-
f"&L{left_footer}" if left_footer else "",
|
|
163
|
-
f"&C{center_footer}" if center_footer else "",
|
|
164
|
-
f"&R{right_footer}" if right_footer else "",
|
|
165
|
-
])
|
|
166
|
-
)
|
|
168
|
+
else:
|
|
169
|
+
raise ValueError("must specify at least one footer")
|
|
167
170
|
|
|
168
171
|
|
|
169
172
|
def array_to_sheet(
|
|
@@ -174,7 +177,7 @@ def array_to_sheet(
|
|
|
174
177
|
_col_id: int = 0,
|
|
175
178
|
/,
|
|
176
179
|
*,
|
|
177
|
-
cell_format: Sequence[CFmt] | CFmt | None = None,
|
|
180
|
+
cell_format: Sequence[CFmt | Sequence[CFmt]] | CFmt | None = None,
|
|
178
181
|
green_bar_flag: bool = True,
|
|
179
182
|
ragged_flag: bool = True,
|
|
180
183
|
) -> tuple[int, int]:
|
|
@@ -184,6 +187,7 @@ def array_to_sheet(
|
|
|
184
187
|
The given array is required be a two-dimensional array, whether
|
|
185
188
|
a nested list, nested tuple, or a 2-D numpy ndarray.
|
|
186
189
|
|
|
190
|
+
|
|
187
191
|
Parameters
|
|
188
192
|
----------
|
|
189
193
|
_xl_book
|
|
@@ -207,10 +211,25 @@ def array_to_sheet(
|
|
|
207
211
|
green_bar_flag
|
|
208
212
|
Whether to highlight alternating rows as in green bar paper
|
|
209
213
|
|
|
214
|
+
ragged_flag
|
|
215
|
+
Whether to write ragged array, i.e. rows not all the same length
|
|
216
|
+
or not all cells are scalar-valued
|
|
217
|
+
|
|
218
|
+
|
|
210
219
|
Raises
|
|
211
220
|
------
|
|
212
221
|
ValueError
|
|
213
|
-
If
|
|
222
|
+
If array is not two-dimensional
|
|
223
|
+
|
|
224
|
+
ValueError
|
|
225
|
+
If ragged_flag is False and array is not rectangular
|
|
226
|
+
|
|
227
|
+
ValueError
|
|
228
|
+
If array is not rectangular and cell_format is a Sequence
|
|
229
|
+
|
|
230
|
+
ValueError
|
|
231
|
+
If array is rectangular format tuple does not match data in length
|
|
232
|
+
|
|
214
233
|
|
|
215
234
|
Returns
|
|
216
235
|
-------
|
|
@@ -218,27 +237,57 @@ def array_to_sheet(
|
|
|
218
237
|
|
|
219
238
|
"""
|
|
220
239
|
|
|
240
|
+
if not ragged_flag:
|
|
241
|
+
try:
|
|
242
|
+
if np.ndim(_data_table) != 2:
|
|
243
|
+
raise ValueError("Given array must be two-dimensional.")
|
|
244
|
+
except ValueError as _err:
|
|
245
|
+
raise ValueError(
|
|
246
|
+
"Given array must be rectangular and homogenous, with scalar members."
|
|
247
|
+
" Alternatively, try with ragged_flag=True."
|
|
248
|
+
)
|
|
249
|
+
raise _err
|
|
250
|
+
elif not (
|
|
251
|
+
isinstance(_data_table, Sequence | np.ndarray)
|
|
252
|
+
and hasattr(_data_table[0], "__len__")
|
|
253
|
+
):
|
|
254
|
+
raise ValueError("Given array must be two-dimensional array.")
|
|
255
|
+
|
|
221
256
|
# Get the array dimensions and row and column numbers for Excel
|
|
222
257
|
_num_rows = len(_data_table)
|
|
223
258
|
_bottom_row_id = _row_id + _num_rows
|
|
224
259
|
_num_cols = len(_data_table[0])
|
|
225
260
|
_right_column_id = _col_id + _num_cols
|
|
226
261
|
|
|
227
|
-
if isinstance(cell_format,
|
|
228
|
-
|
|
229
|
-
|
|
262
|
+
if isinstance(cell_format, Sequence):
|
|
263
|
+
if ragged_flag:
|
|
264
|
+
raise ValueError(
|
|
265
|
+
"It is not clear whether the sequence of formats applies to all cells,"
|
|
266
|
+
" or to each cell respectively. Please provide a single-valued cell_format."
|
|
267
|
+
" Alternatively, you can iterate over the array using scalar_to_sheet()."
|
|
268
|
+
)
|
|
269
|
+
elif not len(cell_format) == len(_data_table[0]):
|
|
230
270
|
raise ValueError("Format tuple does not match data in length.")
|
|
231
|
-
|
|
271
|
+
ensure_cell_format_spec_tuple(cell_format)
|
|
272
|
+
_cell_format: Sequence[CFmt | Sequence[CFmt]] = cell_format
|
|
232
273
|
elif isinstance(cell_format, CFmt):
|
|
233
274
|
_cell_format = (cell_format,) * len(_data_table[0])
|
|
234
275
|
else:
|
|
235
276
|
_cell_format = (CFmt.XL_DEFAULT,) * len(_data_table[0])
|
|
236
277
|
|
|
278
|
+
# construct vector of xlslwrter.format.Format objects
|
|
279
|
+
_wbk_formats = tuple(xl_fmt(_xl_book, _cf) for _cf in _cell_format)
|
|
280
|
+
if _num_rows > 1:
|
|
281
|
+
_wbk_formats_greened = (
|
|
282
|
+
tuple(xl_fmt(_xl_book, (_cf, CFmt.BAR_FILL)) for _cf in _cell_format)
|
|
283
|
+
if green_bar_flag
|
|
284
|
+
else _wbk_formats
|
|
285
|
+
)
|
|
286
|
+
|
|
237
287
|
for _ri, _rv in enumerate(_data_table):
|
|
288
|
+
_fmt_tuple = _wbk_formats_greened if _ri % 2 else _wbk_formats
|
|
238
289
|
for _ci, _cv in enumerate(_rv):
|
|
239
|
-
_cell_fmt =
|
|
240
|
-
CFmt.BAR_FILL if green_bar_flag and _ri % 2 else {}
|
|
241
|
-
)
|
|
290
|
+
_cell_fmt = _fmt_tuple[_ci]
|
|
242
291
|
scalar_to_sheet(
|
|
243
292
|
_xl_book, _xl_sheet, _row_id + _ri, _col_id + _ci, _cv, _cell_fmt
|
|
244
293
|
)
|
|
@@ -303,18 +352,19 @@ def scalar_to_sheet(
|
|
|
303
352
|
else:
|
|
304
353
|
raise ValueError("Incorrect/incomplete specification for Excel cell data.")
|
|
305
354
|
|
|
355
|
+
_xl_fmt = xl_fmt(_xl_book, _cell_fmt)
|
|
306
356
|
if isinstance(_cell_val, str):
|
|
307
|
-
_xl_sheet.write_string(*_cell_addr, _cell_val,
|
|
357
|
+
_xl_sheet.write_string(*_cell_addr, _cell_val, _xl_fmt)
|
|
308
358
|
else:
|
|
309
359
|
_xl_sheet.write(
|
|
310
|
-
*_cell_addr,
|
|
311
|
-
repr(_cell_val) if np.ndim(_cell_val) else _cell_val,
|
|
312
|
-
xl_fmt(_xl_book, _cell_fmt),
|
|
360
|
+
*_cell_addr, repr(_cell_val) if np.ndim(_cell_val) else _cell_val, _xl_fmt
|
|
313
361
|
)
|
|
314
362
|
|
|
315
363
|
|
|
316
364
|
def xl_fmt(
|
|
317
|
-
_xl_book: xlsxwriter.Workbook,
|
|
365
|
+
_xl_book: xlsxwriter.Workbook,
|
|
366
|
+
_cell_fmt: Sequence[CFmt | Sequence[CFmt]] | CFmt | None,
|
|
367
|
+
/,
|
|
318
368
|
) -> xlsxwriter.format.Format:
|
|
319
369
|
"""
|
|
320
370
|
Return :code:`xlsxwriter` `Format` object given a CFmt aenum, or tuple thereof.
|
|
@@ -327,25 +377,39 @@ def xl_fmt(
|
|
|
327
377
|
_cell_fmt
|
|
328
378
|
:code:`CFmt` aenum object, or tuple thereof
|
|
329
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
|
+
|
|
330
386
|
Returns
|
|
331
387
|
-------
|
|
332
388
|
:code:`xlsxwriter` `Format` object
|
|
333
389
|
|
|
334
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
|
+
|
|
335
397
|
_cell_fmt_dict: Mapping[str, Any] = {}
|
|
336
|
-
if isinstance(_cell_fmt,
|
|
398
|
+
if isinstance(_cell_fmt, Sequence):
|
|
337
399
|
ensure_cell_format_spec_tuple(_cell_fmt)
|
|
338
400
|
for _cf in _cell_fmt:
|
|
339
401
|
_cell_fmt_dict = _cell_fmt_dict | _cf.value
|
|
340
402
|
elif isinstance(_cell_fmt, CFmt):
|
|
341
403
|
_cell_fmt_dict = _cell_fmt.value
|
|
342
404
|
else:
|
|
343
|
-
|
|
405
|
+
raise ValueError("Improperly specified format specification.")
|
|
344
406
|
|
|
345
407
|
return _xl_book.add_format(_cell_fmt_dict)
|
|
346
408
|
|
|
347
409
|
|
|
348
|
-
def ensure_cell_format_spec_tuple(
|
|
410
|
+
def ensure_cell_format_spec_tuple(
|
|
411
|
+
_cell_formats: Sequence[CFmt | Sequence[CFmt]], /
|
|
412
|
+
) -> None:
|
|
349
413
|
"""
|
|
350
414
|
Test that a given format specification is tuple of CFmt enums
|
|
351
415
|
|
|
@@ -357,7 +421,7 @@ def ensure_cell_format_spec_tuple(_cell_formats: Sequence[CFmt], /) -> None:
|
|
|
357
421
|
Raises
|
|
358
422
|
------
|
|
359
423
|
ValueError
|
|
360
|
-
If format specification is not tuple of CFmt
|
|
424
|
+
If format specification is not tuple of CFmt enums
|
|
361
425
|
|
|
362
426
|
Returns
|
|
363
427
|
-------
|
|
@@ -370,4 +434,7 @@ def ensure_cell_format_spec_tuple(_cell_formats: Sequence[CFmt], /) -> None:
|
|
|
370
434
|
ensure_cell_format_spec_tuple(_cell_format)
|
|
371
435
|
|
|
372
436
|
if not (isinstance(_cell_format, CFmt),):
|
|
373
|
-
raise ValueError(
|
|
437
|
+
raise ValueError(
|
|
438
|
+
"Improperly specified format tuple for writing array."
|
|
439
|
+
" Must be tuple of CFmt enums."
|
|
440
|
+
)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mergeron-2024.739079.13 → mergeron-2024.739087.0}/src/mergeron/core/damodaran_margin_data.py
RENAMED
|
File without changes
|
|
File without changes
|
{mergeron-2024.739079.13 → mergeron-2024.739087.0}/src/mergeron/core/guidelines_boundaries.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mergeron-2024.739079.13 → mergeron-2024.739087.0}/src/mergeron/core/pseudorandom_numbers.py
RENAMED
|
File without changes
|
|
File without changes
|
{mergeron-2024.739079.13 → mergeron-2024.739087.0}/src/mergeron/data/damodaran_margin_data.xls
RENAMED
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mergeron-2024.739079.13 → mergeron-2024.739087.0}/src/mergeron/gen/_data_generation_functions.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|