mergeron 2024.739087.0__tar.gz → 2024.739088.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.

Files changed (36) hide show
  1. {mergeron-2024.739087.0 → mergeron-2024.739088.0}/PKG-INFO +1 -1
  2. {mergeron-2024.739087.0 → mergeron-2024.739088.0}/pyproject.toml +1 -1
  3. {mergeron-2024.739087.0 → mergeron-2024.739088.0}/src/mergeron/__init__.py +1 -1
  4. {mergeron-2024.739087.0/src/mergeron/core → mergeron-2024.739088.0/src/mergeron/ext}/xlsxw_helper.py +183 -110
  5. {mergeron-2024.739087.0 → mergeron-2024.739088.0}/README.rst +0 -0
  6. {mergeron-2024.739087.0 → mergeron-2024.739088.0}/src/mergeron/License.txt +0 -0
  7. {mergeron-2024.739087.0 → mergeron-2024.739088.0}/src/mergeron/core/__init__.py +0 -0
  8. {mergeron-2024.739087.0 → mergeron-2024.739088.0}/src/mergeron/core/damodaran_margin_data.py +0 -0
  9. {mergeron-2024.739087.0 → mergeron-2024.739088.0}/src/mergeron/core/ftc_merger_investigations_data.py +0 -0
  10. {mergeron-2024.739087.0 → mergeron-2024.739088.0}/src/mergeron/core/guidelines_boundaries.py +0 -0
  11. {mergeron-2024.739087.0 → mergeron-2024.739088.0}/src/mergeron/core/guidelines_boundary_functions.py +0 -0
  12. {mergeron-2024.739087.0 → mergeron-2024.739088.0}/src/mergeron/core/guidelines_boundary_functions_extra.py +0 -0
  13. {mergeron-2024.739087.0 → mergeron-2024.739088.0}/src/mergeron/core/proportions_tests.py +0 -0
  14. {mergeron-2024.739087.0 → mergeron-2024.739088.0}/src/mergeron/core/pseudorandom_numbers.py +0 -0
  15. {mergeron-2024.739087.0 → mergeron-2024.739088.0}/src/mergeron/data/__init__.py +0 -0
  16. {mergeron-2024.739087.0 → mergeron-2024.739088.0}/src/mergeron/data/damodaran_margin_data.xls +0 -0
  17. {mergeron-2024.739087.0 → mergeron-2024.739088.0}/src/mergeron/data/damodaran_margin_data_dict.msgpack +0 -0
  18. {mergeron-2024.739087.0 → mergeron-2024.739088.0}/src/mergeron/data/ftc_invdata.msgpack +0 -0
  19. {mergeron-2024.739087.0 → mergeron-2024.739088.0}/src/mergeron/data/jinja2_LaTeX_templates/clrrate_cis_summary_table_template.tex.jinja2 +0 -0
  20. {mergeron-2024.739087.0 → mergeron-2024.739088.0}/src/mergeron/data/jinja2_LaTeX_templates/ftcinvdata_byhhianddelta_table_template.tex.jinja2 +0 -0
  21. {mergeron-2024.739087.0 → mergeron-2024.739088.0}/src/mergeron/data/jinja2_LaTeX_templates/ftcinvdata_summary_table_template.tex.jinja2 +0 -0
  22. {mergeron-2024.739087.0 → mergeron-2024.739088.0}/src/mergeron/data/jinja2_LaTeX_templates/ftcinvdata_summarypaired_table_template.tex.jinja2 +0 -0
  23. {mergeron-2024.739087.0 → mergeron-2024.739088.0}/src/mergeron/data/jinja2_LaTeX_templates/mergeron.cls +0 -0
  24. {mergeron-2024.739087.0 → mergeron-2024.739088.0}/src/mergeron/data/jinja2_LaTeX_templates/mergeron_table_collection_template.tex.jinja2 +0 -0
  25. {mergeron-2024.739087.0 → mergeron-2024.739088.0}/src/mergeron/data/jinja2_LaTeX_templates/setup_tikz_tables.tex +0 -0
  26. {mergeron-2024.739087.0 → mergeron-2024.739088.0}/src/mergeron/demo/__init__.py +0 -0
  27. {mergeron-2024.739087.0 → mergeron-2024.739088.0}/src/mergeron/demo/visualize_empirical_margin_distribution.py +0 -0
  28. {mergeron-2024.739087.0 → mergeron-2024.739088.0}/src/mergeron/ext/__init__.py +0 -0
  29. {mergeron-2024.739087.0 → mergeron-2024.739088.0}/src/mergeron/ext/tol_colors.py +0 -0
  30. {mergeron-2024.739087.0 → mergeron-2024.739088.0}/src/mergeron/gen/__init__.py +0 -0
  31. {mergeron-2024.739087.0 → mergeron-2024.739088.0}/src/mergeron/gen/_data_generation_functions.py +0 -0
  32. {mergeron-2024.739087.0 → mergeron-2024.739088.0}/src/mergeron/gen/data_generation.py +0 -0
  33. {mergeron-2024.739087.0 → mergeron-2024.739088.0}/src/mergeron/gen/enforcement_stats.py +0 -0
  34. {mergeron-2024.739087.0 → mergeron-2024.739088.0}/src/mergeron/gen/market_sample.py +0 -0
  35. {mergeron-2024.739087.0 → mergeron-2024.739088.0}/src/mergeron/gen/upp_tests.py +0 -0
  36. {mergeron-2024.739087.0 → mergeron-2024.739088.0}/src/mergeron/py.typed +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: mergeron
3
- Version: 2024.739087.0
3
+ Version: 2024.739088.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.739087.0"
16
+ version = "2024.739088.0"
17
17
 
18
18
  # Classifiers list: https://pypi.org/classifiers/
19
19
  classifiers = [
@@ -11,7 +11,7 @@ from numpy.typing import NDArray
11
11
 
12
12
  _PKG_NAME: str = Path(__file__).parent.stem
13
13
 
14
- VERSION = "2024.739087.0"
14
+ VERSION = "2024.739088.0"
15
15
 
16
16
  __version__ = VERSION
17
17
 
@@ -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, will be rendered
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
- TEXT_WRAP: ClassVar = {"text_wrap": True}
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
- AREA_NUM: ClassVar = {"num_format": "0.00000000"}
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": "999999"}
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,
@@ -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(xl_fmt(_xl_book, (_cf, CFmt.BAR_FILL)) for _cf in _cell_format)
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
- _fmt_tuple = _wbk_formats_greened if _ri % 2 else _wbk_formats
426
+ _wbk_fmt_tuple = _wbk_formats_greened if _ri % 2 else _wbk_formats
289
427
  for _ci, _cv in enumerate(_rv):
290
- _cell_fmt = _fmt_tuple[_ci]
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,11 +434,11 @@ 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 | float = "A1",
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.
@@ -337,104 +473,41 @@ def scalar_to_sheet(
337
473
 
338
474
  """
339
475
 
476
+ _cell_addr: tuple[int | str, ...] = ()
477
+ _cell_val: Any = None
478
+ _cell_fmt: xlsxwriter.format.Format = CFmt.XL_DEFAULT
479
+
340
480
  if isinstance(_cell_addr_0, str):
341
481
  if len(_s2s_args) not in (1, 2):
342
- raise ValueError("Too many or too few arguments.")
343
- _cell_addr: tuple[int | str, ...] = (_cell_addr_0,)
344
- _cell_val: Any = _s2s_args[0]
345
- _cell_fmt: CFmt | Sequence[CFmt] = _s2s_args[1] if len(_s2s_args) == 2 else None # type: ignore
482
+ raise ValueError("Incorrect number of arguments.")
483
+ _cell_addr = (_cell_addr_0,)
484
+ _cell_val = _s2s_args[0]
485
+ _cell_fmt = _s2s_args[1] if len(_s2s_args) == 2 else None # type: ignore
346
486
  elif isinstance(_cell_addr_0, int):
347
- if len(_s2s_args) not in (2, 3):
348
- raise ValueError("Too many or too few arguments.")
487
+ if len(_s2s_args) not in (2, 3) or not isinstance(_s2s_args[0], int):
488
+ raise ValueError("Incorrect/incomplete specification for Excel cell data.")
349
489
  _cell_addr = (_cell_addr_0, _s2s_args[0])
350
490
  _cell_val = _s2s_args[1]
351
491
  _cell_fmt = _s2s_args[2] if len(_s2s_args) == 3 else None # type: ignore
352
492
  else:
353
493
  raise ValueError("Incorrect/incomplete specification for Excel cell data.")
354
494
 
355
- _xl_fmt = xl_fmt(_xl_book, _cell_fmt)
356
- if isinstance(_cell_val, str):
357
- _xl_sheet.write_string(*_cell_addr, _cell_val, _xl_fmt)
358
- else:
359
- _xl_sheet.write(
360
- *_cell_addr, repr(_cell_val) if np.ndim(_cell_val) else _cell_val, _xl_fmt
361
- )
362
-
363
-
364
- def xl_fmt(
365
- _xl_book: xlsxwriter.Workbook,
366
- _cell_fmt: Sequence[CFmt | Sequence[CFmt]] | CFmt | None,
367
- /,
368
- ) -> xlsxwriter.format.Format:
369
- """
370
- Return :code:`xlsxwriter` `Format` object given a CFmt aenum, or tuple thereof.
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
495
+ _write_args = (
496
+ (*_cell_addr, repr(_cell_val))
497
+ if np.ndim(_cell_val) or _cell_val in (np.inf, -np.inf, np.nan)
498
+ else (*_cell_addr, _cell_val)
499
+ )
500
+ _write_args = (*_write_args, _cell_fmt) if _cell_fmt else _write_args
501
+
502
+ if empty_as_blank and (_cell_val is None or _cell_val == ""):
503
+ _xl_sheet.write_blank(*_write_args)
504
+ elif (
505
+ _cell_val is None
506
+ or _cell_val == ""
507
+ or isinstance(_cell_val, str)
508
+ or np.ndim(_cell_val)
509
+ or _cell_val in (np.inf, -np.inf, np.nan)
510
+ ):
511
+ _xl_sheet.write_string(*_write_args)
404
512
  else:
405
- raise ValueError("Improperly specified format specification.")
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
- )
513
+ _xl_sheet.write(*_write_args)