numbers-parser 4.14.1__py3-none-any.whl → 4.14.3__py3-none-any.whl

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,7 @@
1
- from datetime import datetime, timedelta
1
+ from __future__ import annotations
2
+
2
3
  from pathlib import Path
3
- from typing import Dict, Iterator, List, Optional, Tuple, Union
4
+ from typing import TYPE_CHECKING
4
5
  from warnings import warn
5
6
 
6
7
  from numbers_parser.cell import (
@@ -33,19 +34,24 @@ from numbers_parser.containers import ItemsList
33
34
  from numbers_parser.model import _NumbersModel
34
35
  from numbers_parser.numbers_cache import Cacheable
35
36
 
37
+ if TYPE_CHECKING: # pragma: nocover
38
+ from collections.abc import Iterator
39
+ from datetime import datetime, timedelta
40
+
36
41
  __all__ = ["Document", "Sheet", "Table"]
37
42
 
38
43
 
39
- class Sheet:
40
- pass
44
+ # class Sheet:
45
+ # pass
41
46
 
42
47
 
43
- class Table:
44
- pass
48
+ # class Table:
49
+ # pass
45
50
 
46
51
 
47
52
  class Document:
48
- """Create an instance of a new Numbers document.
53
+ """
54
+ Create an instance of a new Numbers document.
49
55
 
50
56
  If ``filename`` is ``None``, an empty document is created using the defaults
51
57
  defined by the class constructor. You can optionionally override these
@@ -74,17 +80,20 @@ class Document:
74
80
  If the sheet name already exists in the document.
75
81
  IndexError:
76
82
  If the table name already exists in the first sheet.
83
+ UnsupportedError:
84
+ If the document is encrypted.
85
+
77
86
  """
78
87
 
79
- def __init__( # noqa: PLR0913
88
+ def __init__(
80
89
  self,
81
- filename: Optional[Union[str, Path]] = None,
82
- sheet_name: Optional[str] = "Sheet 1",
83
- table_name: Optional[str] = "Table 1",
84
- num_header_rows: Optional[int] = 1,
85
- num_header_cols: Optional[int] = 1,
86
- num_rows: Optional[int] = DEFAULT_ROW_COUNT,
87
- num_cols: Optional[int] = DEFAULT_COLUMN_COUNT,
90
+ filename: str | Path | None = None,
91
+ sheet_name: str | None = "Sheet 1",
92
+ table_name: str | None = "Table 1",
93
+ num_header_rows: int | None = 1,
94
+ num_header_cols: int | None = 1,
95
+ num_rows: int | None = DEFAULT_ROW_COUNT,
96
+ num_cols: int | None = DEFAULT_COLUMN_COUNT,
88
97
  ) -> None:
89
98
  self._model = _NumbersModel(None if filename is None else Path(filename))
90
99
  refs = self._model.sheet_ids()
@@ -102,7 +111,7 @@ class Document:
102
111
  table.num_header_cols = num_header_cols
103
112
 
104
113
  @property
105
- def sheets(self) -> List[Sheet]:
114
+ def sheets(self) -> list[Sheet]:
106
115
  """List[:class:`Sheet`]: A list of sheets in the document."""
107
116
  return self._sheets
108
117
 
@@ -112,19 +121,21 @@ class Document:
112
121
  return self.sheets[0].tables[0]
113
122
 
114
123
  @property
115
- def styles(self) -> Dict[str, Style]:
124
+ def styles(self) -> dict[str, Style]:
116
125
  """Dict[str, :class:`Style`]: A dict mapping style names to to the corresponding style."""
117
126
  return self._model.styles
118
127
 
119
128
  @property
120
- def custom_formats(self) -> Dict[str, CustomFormatting]:
121
- """Dict[str, :class:`CustomFormatting`]: A dict mapping custom format names
129
+ def custom_formats(self) -> dict[str, CustomFormatting]:
130
+ """
131
+ Dict[str, :class:`CustomFormatting`]: A dict mapping custom format names
122
132
  to the corresponding custom format.
123
133
  """
124
134
  return self._model.custom_formats
125
135
 
126
- def save(self, filename: Union[str, Path], package: bool = False) -> None:
127
- """Save the document in the specified filename.
136
+ def save(self, filename: str | Path, package: bool = False) -> None:
137
+ """
138
+ Save the document in the specified filename.
128
139
 
129
140
  Parameters
130
141
  ----------
@@ -140,6 +151,7 @@ class Document:
140
151
  FileFormatError:
141
152
  If attempting to write a package into a folder that is not an
142
153
  existing Numbers document.
154
+
143
155
  """
144
156
  for sheet in self.sheets:
145
157
  for table in sheet.tables:
@@ -156,12 +168,13 @@ class Document:
156
168
 
157
169
  def add_sheet(
158
170
  self,
159
- sheet_name: Optional[str] = None,
160
- table_name: Optional[str] = "Table 1",
161
- num_rows: Optional[int] = DEFAULT_ROW_COUNT,
162
- num_cols: Optional[int] = DEFAULT_COLUMN_COUNT,
171
+ sheet_name: str | None = None,
172
+ table_name: str | None = "Table 1",
173
+ num_rows: int | None = DEFAULT_ROW_COUNT,
174
+ num_cols: int | None = DEFAULT_COLUMN_COUNT,
163
175
  ) -> None:
164
- """Add a new sheet to the current document.
176
+ """
177
+ Add a new sheet to the current document.
165
178
 
166
179
  If no sheet name is provided, the next available numbered sheet
167
180
  will be generated in the series ``Sheet 1``, ``Sheet 2``, etc.
@@ -180,6 +193,7 @@ class Document:
180
193
  Raises
181
194
  ------
182
195
  IndexError: If the sheet name already exists in the document.
196
+
183
197
  """
184
198
  if sheet_name is not None:
185
199
  if sheet_name in self._sheets:
@@ -211,7 +225,8 @@ class Document:
211
225
  self._sheets.append(new_sheet)
212
226
 
213
227
  def add_style(self, **kwargs) -> Style:
214
- r"""Add a new style to the current document.
228
+ r"""
229
+ Add a new style to the current document.
215
230
 
216
231
  If no style name is provided, the next available numbered style
217
232
  will be generated in the series ``Custom Style 1``, ``Custom Style 2``, etc.
@@ -241,6 +256,7 @@ class Document:
241
256
  If ``font_size`` is not a ``float``, ``font_name`` is not a ``str``,
242
257
  ``bg_image`` is not a :py:class:`~numbers_parser.BackgroundImage`,
243
258
  or if any of the ``bool`` parameters are invalid.
259
+
244
260
  """
245
261
  if "name" in kwargs and kwargs["name"] is not None and kwargs["name"] in self._model.styles:
246
262
  msg = f"style '{kwargs['name']}' already exists"
@@ -260,13 +276,14 @@ class Document:
260
276
  return style
261
277
 
262
278
  def add_custom_format(self, **kwargs) -> CustomFormatting:
263
- r"""Add a new custom format to the current document.
279
+ r"""
280
+ Add a new custom format to the current document.
264
281
 
265
282
  .. code-block:: python
266
283
 
267
284
  long_date = doc.add_custom_format(
268
285
  name="Long Date",
269
- type="date",
286
+ type="datetime",
270
287
  date_time_format="EEEE, d MMMM yyyy"
271
288
  )
272
289
  table.set_cell_formatting("C1", "custom", format=long_date)
@@ -276,9 +293,9 @@ class Document:
276
293
  depending upon the value of ``kwargs["type"]``.
277
294
 
278
295
  :Common Args:
279
- * **name** (``str``) The name of the custom format. If no name is provided,
296
+ * **name** (``str``) - The name of the custom format. If no name is provided,
280
297
  one is generated using the scheme ``Custom Format``, ``Custom Format 1``, ``Custom Format 2``, etc.
281
- * **type** (``str``, *optional*, default: ``number``) The type of format to
298
+ * **type** (``str``, *optional*, default: ``number``) - The type of format to
282
299
  create:
283
300
 
284
301
  * ``"datetime"``: A date and time value with custom formatting.
@@ -286,26 +303,26 @@ class Document:
286
303
  * ``"text"``: A simple text string.
287
304
 
288
305
  :``"number"``:
289
- * **integer_format** (``PaddingType``, *optional*, default: ``PaddingType.NONE``) How
306
+ * **integer_format** (``PaddingType``, *optional*, default: ``PaddingType.NONE``) - How
290
307
  to pad integers.
291
- * **decimal_format** (``PaddingType``, *optional*, default: ``PaddingType.NONE``) How
308
+ * **decimal_format** (``PaddingType``, *optional*, default: ``PaddingType.NONE``) - How
292
309
  to pad decimals.
293
- * **num_integers** (``int``, *optional*, default: ``0``) Integer precision
310
+ * **num_integers** (``int``, *optional*, default: ``0``) - Integer precision
294
311
  when integers are padded.
295
- * **num_decimals** (``int``, *optional*, default: ``0``) Integer precision
312
+ * **num_decimals** (``int``, *optional*, default: ``0``) - Integer precision
296
313
  when decimals are padded.
297
- * **show_thousands_separator** (``bool``, *optional*, default: ``False``) ``True``
314
+ * **show_thousands_separator** (``bool``, *optional*, default: ``False``) - ``True``
298
315
  if the number should include a thousands seperator.
299
316
 
300
317
  :``"datetime"``:
301
- * **format** (``str``, *optional*, default: ``"d MMM y"``) A POSIX strftime-like
318
+ * **format** (``str``, *optional*, default: ``"d MMM y"``) - A POSIX strftime-like
302
319
  formatting string of `Numbers date/time directives <#datetime-formats>`_.
303
320
 
304
321
  :``"text"``:
305
- * **format** (``str``, *optional*, default: ``"%s"``) Text format.
322
+ * **format** (``str``, *optional*, default: ``"%s"``) - Text format.
306
323
  The cell value is inserted in place of %s. Only one substitution is allowed by
307
324
  Numbers, and multiple %s formatting references raise a TypeError exception
308
- """ # noqa: E501
325
+ """
309
326
  if (
310
327
  "name" in kwargs
311
328
  and kwargs["name"] is not None
@@ -342,7 +359,7 @@ class Sheet:
342
359
  self._tables = ItemsList(self._model, refs, Table)
343
360
 
344
361
  @property
345
- def tables(self) -> List[Table]:
362
+ def tables(self) -> list[Table]:
346
363
  """List[:class:`Table`]: A list of tables in the sheet."""
347
364
  return self._tables
348
365
 
@@ -352,18 +369,19 @@ class Sheet:
352
369
  return self._model.sheet_name(self._sheet_id)
353
370
 
354
371
  @name.setter
355
- def name(self, value: str):
372
+ def name(self, value: str) -> None:
356
373
  self._model.sheet_name(self._sheet_id, value)
357
374
 
358
- def add_table( # noqa: PLR0913
375
+ def add_table(
359
376
  self,
360
- table_name: Optional[str] = None,
361
- x: Optional[float] = None,
362
- y: Optional[float] = None,
363
- num_rows: Optional[int] = DEFAULT_ROW_COUNT,
364
- num_cols: Optional[int] = DEFAULT_COLUMN_COUNT,
377
+ table_name: str | None = None,
378
+ x: float | None = None,
379
+ y: float | None = None,
380
+ num_rows: int | None = DEFAULT_ROW_COUNT,
381
+ num_cols: int | None = DEFAULT_COLUMN_COUNT,
365
382
  ) -> Table:
366
- """Add a new table to the current sheet.
383
+ """
384
+ Add a new table to the current sheet.
367
385
 
368
386
  If no table name is provided, the next available numbered table
369
387
  will be generated in the series ``Table 1``, ``Table 2``, etc.
@@ -402,11 +420,12 @@ class Sheet:
402
420
  Raises
403
421
  ------
404
422
  IndexError: If the table name already exists.
423
+
405
424
  """
406
425
  from_table_id = self._tables[-1]._table_id
407
426
  return self._add_table(table_name, from_table_id, x, y, num_rows, num_cols)
408
427
 
409
- def _add_table( # noqa: PLR0913
428
+ def _add_table(
410
429
  self,
411
430
  table_name,
412
431
  from_table_id,
@@ -470,7 +489,7 @@ class Table(Cacheable):
470
489
  return self._model.table_name(self._table_id)
471
490
 
472
491
  @name.setter
473
- def name(self, value: str):
492
+ def name(self, value: str) -> None:
474
493
  self._model.table_name(self._table_id, value)
475
494
 
476
495
  @property
@@ -479,7 +498,7 @@ class Table(Cacheable):
479
498
  return self._model.table_name_enabled(self._table_id)
480
499
 
481
500
  @table_name_enabled.setter
482
- def table_name_enabled(self, enabled: bool):
501
+ def table_name_enabled(self, enabled: bool) -> None:
483
502
  self._model.table_name_enabled(self._table_id, enabled)
484
503
 
485
504
  @property
@@ -502,7 +521,8 @@ class Table(Cacheable):
502
521
 
503
522
  @property
504
523
  def num_header_rows(self) -> int:
505
- """int: The number of header rows.
524
+ """
525
+ int: The number of header rows.
506
526
 
507
527
  Example
508
528
  -------
@@ -516,6 +536,7 @@ class Table(Cacheable):
516
536
  ValueError:
517
537
  If the number of headers is negative, exceeds the number of rows in the
518
538
  table, or exceeds Numbers maxinum number of headers (``MAX_HEADER_COUNT``).
539
+
519
540
  """
520
541
  return self._model.num_header_rows(self._table_id)
521
542
 
@@ -524,17 +545,18 @@ class Table(Cacheable):
524
545
  if num_headers < 0:
525
546
  msg = "Number of headers cannot be negative"
526
547
  raise ValueError(msg)
527
- elif num_headers > self.num_rows:
548
+ if num_headers > self.num_rows:
528
549
  msg = "Number of headers cannot exceed the number of rows"
529
550
  raise ValueError(msg)
530
- elif num_headers > MAX_HEADER_COUNT:
551
+ if num_headers > MAX_HEADER_COUNT:
531
552
  msg = f"Number of headers cannot exceed {MAX_HEADER_COUNT} rows"
532
553
  raise ValueError(msg)
533
554
  return self._model.num_header_rows(self._table_id, num_headers)
534
555
 
535
556
  @property
536
557
  def num_header_cols(self) -> int:
537
- """int: The number of header columns.
558
+ """
559
+ int: The number of header columns.
538
560
 
539
561
  Example
540
562
  -------
@@ -548,6 +570,7 @@ class Table(Cacheable):
548
570
  ValueError:
549
571
  If the number of headers is negative, exceeds the number of rows in the
550
572
  table, or exceeds Numbers maxinum number of headers (``MAX_HEADER_COUNT``).
573
+
551
574
  """
552
575
  return self._model.num_header_cols(self._table_id)
553
576
 
@@ -556,10 +579,10 @@ class Table(Cacheable):
556
579
  if num_headers < 0:
557
580
  msg = "Number of headers cannot be negative"
558
581
  raise ValueError(msg)
559
- elif num_headers > self.num_cols:
582
+ if num_headers > self.num_cols:
560
583
  msg = "Number of headers cannot exceed the number of columns"
561
584
  raise ValueError(msg)
562
- elif num_headers > MAX_HEADER_COUNT:
585
+ if num_headers > MAX_HEADER_COUNT:
563
586
  msg = f"Number of headers cannot exceed {MAX_HEADER_COUNT} columns"
564
587
  raise ValueError(msg)
565
588
  return self._model.num_header_cols(self._table_id, num_headers)
@@ -574,8 +597,9 @@ class Table(Cacheable):
574
597
  """int: The table's width in points."""
575
598
  return self._model.table_width(self._table_id)
576
599
 
577
- def row_height(self, row: int, height: Optional[int] = None) -> int:
578
- """The height of a table row in points.
600
+ def row_height(self, row: int, height: int | None = None) -> int:
601
+ """
602
+ The height of a table row in points.
579
603
 
580
604
  .. code-block:: python
581
605
 
@@ -593,11 +617,13 @@ class Table(Cacheable):
593
617
  -------
594
618
  int:
595
619
  The height of the table row.
620
+
596
621
  """
597
622
  return self._model.row_height(self._table_id, row, height)
598
623
 
599
- def col_width(self, col: int, width: Optional[int] = None) -> int:
600
- """The width of a table column in points.
624
+ def col_width(self, col: int, width: int | None = None) -> int:
625
+ """
626
+ The width of a table column in points.
601
627
 
602
628
  Parameters
603
629
  ----------
@@ -610,16 +636,18 @@ class Table(Cacheable):
610
636
  -------
611
637
  int:
612
638
  The width of the table column.
639
+
613
640
  """
614
641
  return self._model.col_width(self._table_id, col, width)
615
642
 
616
643
  @property
617
- def coordinates(self) -> Tuple[float]:
644
+ def coordinates(self) -> tuple[float]:
618
645
  """Tuple[float]: The table's x, y offsets in points."""
619
646
  return self._model.table_coordinates(self._table_id)
620
647
 
621
- def rows(self, values_only: bool = False) -> Union[List[List[Cell]], List[List[str]]]:
622
- """Return all rows of cells for the Table.
648
+ def rows(self, values_only: bool = False) -> list[list[Cell]] | list[list[str]]:
649
+ """
650
+ Return all rows of cells for the Table.
623
651
 
624
652
  Parameters
625
653
  ----------
@@ -630,15 +658,16 @@ class Table(Cacheable):
630
658
  -------
631
659
  List[List[Cell]] | List[List[str]]:
632
660
  List of rows; each row is a list of :class:`Cell` objects, or string values.
661
+
633
662
  """
634
663
  if values_only:
635
664
  return [[cell.value for cell in row] for row in self._data]
636
- else:
637
- return self._data
665
+ return self._data
638
666
 
639
667
  @property
640
- def merge_ranges(self) -> List[str]:
641
- """List[str]: The merge ranges of cells in A1 notation.
668
+ def merge_ranges(self) -> list[str]:
669
+ """
670
+ List[str]: The merge ranges of cells in A1 notation.
642
671
 
643
672
  Example
644
673
  -------
@@ -650,6 +679,7 @@ class Table(Cacheable):
650
679
  <numbers_parser.cell.TextCell object at 0x1035f4a90>
651
680
  >>> table.cell("A5")
652
681
  <numbers_parser.cell.MergedCell object at 0x1035f5310>
682
+
653
683
  """
654
684
  merge_cells = set()
655
685
  for row, cells in enumerate(self._data):
@@ -659,8 +689,9 @@ class Table(Cacheable):
659
689
  merge_cells.add(xl_range(row, col, row + size[0] - 1, col + size[1] - 1))
660
690
  return sorted(merge_cells)
661
691
 
662
- def cell(self, *args) -> Union[Cell, MergedCell]:
663
- """Return a single cell in the table.
692
+ def cell(self, *args) -> Cell | MergedCell: # noqa: D417
693
+ """
694
+ Return a single cell in the table.
664
695
 
665
696
  The ``cell()`` method supports two forms of notation to designate the position
666
697
  of cells: **Row-column** notation and **A1** notation:
@@ -699,6 +730,7 @@ class Table(Cacheable):
699
730
  <numbers_parser.cell.TextCell object at 0x105a80b90>
700
731
  >>> table.cell("B2").value
701
732
  1234.50
733
+
702
734
  """
703
735
  if isinstance(args[0], str):
704
736
  (row, col) = xl_cell_to_rowcol(args[0])
@@ -716,15 +748,16 @@ class Table(Cacheable):
716
748
 
717
749
  return self._data[row][col]
718
750
 
719
- def iter_rows( # noqa: PLR0913
751
+ def iter_rows(
720
752
  self,
721
- min_row: Optional[int] = None,
722
- max_row: Optional[int] = None,
723
- min_col: Optional[int] = None,
724
- max_col: Optional[int] = None,
725
- values_only: Optional[bool] = False,
726
- ) -> Iterator[Union[Tuple[Cell], Tuple[str]]]:
727
- """Produces cells from a table, by row.
753
+ min_row: int | None = None,
754
+ max_row: int | None = None,
755
+ min_col: int | None = None,
756
+ max_col: int | None = None,
757
+ values_only: bool | None = False,
758
+ ) -> Iterator[tuple[Cell] | tuple[str]]:
759
+ """
760
+ Produces cells from a table, by row.
728
761
 
729
762
  Specify the iteration range using the indexes of the rows and columns.
730
763
 
@@ -758,6 +791,7 @@ class Table(Cacheable):
758
791
 
759
792
  for row in table.iter_rows(min_row=2, max_row=7, values_only=True):
760
793
  sum += row
794
+
761
795
  """
762
796
  min_row = min_row or 0
763
797
  max_row = max_row or self.num_rows - 1
@@ -784,15 +818,16 @@ class Table(Cacheable):
784
818
  else:
785
819
  yield tuple(rows[row][min_col : max_col + 1])
786
820
 
787
- def iter_cols( # noqa: PLR0913
821
+ def iter_cols(
788
822
  self,
789
- min_col: Optional[int] = None,
790
- max_col: Optional[int] = None,
791
- min_row: Optional[int] = None,
792
- max_row: Optional[int] = None,
793
- values_only: Optional[bool] = False,
794
- ) -> Iterator[Union[Tuple[Cell], Tuple[str]]]:
795
- """Produces cells from a table, by column.
823
+ min_col: int | None = None,
824
+ max_col: int | None = None,
825
+ min_row: int | None = None,
826
+ max_row: int | None = None,
827
+ values_only: bool | None = False,
828
+ ) -> Iterator[tuple[Cell] | tuple[str]]:
829
+ """
830
+ Produces cells from a table, by column.
796
831
 
797
832
  Specify the iteration range using the indexes of the rows and columns.
798
833
 
@@ -826,6 +861,7 @@ class Table(Cacheable):
826
861
 
827
862
  for col in table.iter_cols(min_row=2, max_row=7):
828
863
  sum += col.value
864
+
829
865
  """
830
866
  min_row = min_row or 0
831
867
  max_row = max_row or self.num_rows - 1
@@ -877,8 +913,9 @@ class Table(Cacheable):
877
913
 
878
914
  return (row, col, *tuple(values))
879
915
 
880
- def write(self, *args, style: Optional[Union[Style, str, None]] = None) -> None:
881
- """Write a value to a cell and update the style/cell type.
916
+ def write(self, *args, style: Style | str | None = None) -> None: # noqa: D417
917
+ """
918
+ Write a value to a cell and update the style/cell type.
882
919
 
883
920
  The ``write()`` method supports two forms of notation to designate the position
884
921
  of cells: **Row-column** notation and **A1** notation:
@@ -919,6 +956,7 @@ class Table(Cacheable):
919
956
  If the style parameter is an invalid type.
920
957
  ValueError:
921
958
  If the cell type cannot be determined from the type of `param3`.
959
+
922
960
  """
923
961
  # TODO: write needs to retain/init the border
924
962
  (row, col, value) = self._validate_cell_coords(*args)
@@ -933,7 +971,7 @@ class Table(Cacheable):
933
971
  if style is not None:
934
972
  self.set_cell_style(row, col, style)
935
973
 
936
- def set_cell_style(self, *args):
974
+ def set_cell_style(self, *args) -> None:
937
975
  (row, col, style) = self._validate_cell_coords(*args)
938
976
  if isinstance(style, Style):
939
977
  self._data[row][col]._style = style
@@ -948,11 +986,12 @@ class Table(Cacheable):
948
986
 
949
987
  def add_row(
950
988
  self,
951
- num_rows: Optional[int] = 1,
952
- start_row: Optional[Union[int, None]] = None,
953
- default: Optional[Union[str, int, float, bool, datetime, timedelta]] = None,
989
+ num_rows: int | None = 1,
990
+ start_row: int | None = None,
991
+ default: str | float | bool | datetime | timedelta | None = None,
954
992
  ) -> None:
955
- """Add or insert rows to the table.
993
+ """
994
+ Add or insert rows to the table.
956
995
 
957
996
  Parameters
958
997
  ----------
@@ -978,6 +1017,7 @@ class Table(Cacheable):
978
1017
  If the start_row is out of range for the table.
979
1018
  ValueError:
980
1019
  If the default value is unsupported by :py:meth:`numbers_parser.Table.write`.
1020
+
981
1021
  """
982
1022
  if start_row is not None and (start_row < 0 or start_row >= self.num_rows):
983
1023
  msg = "Row number not in range for table"
@@ -994,7 +1034,7 @@ class Table(Cacheable):
994
1034
  [
995
1035
  Cell._empty_cell(self._table_id, row, col, self._model)
996
1036
  for col in range(self.num_cols)
997
- ]
1037
+ ],
998
1038
  )
999
1039
  self._data[start_row:start_row] = rows
1000
1040
 
@@ -1010,11 +1050,12 @@ class Table(Cacheable):
1010
1050
 
1011
1051
  def add_column(
1012
1052
  self,
1013
- num_cols: Optional[int] = 1,
1014
- start_col: Optional[Union[int, None]] = None,
1015
- default: Optional[Union[str, int, float, bool, datetime, timedelta]] = None,
1053
+ num_cols: int | None = 1,
1054
+ start_col: int | None = None,
1055
+ default: str | float | bool | datetime | timedelta | None = None,
1016
1056
  ) -> None:
1017
- """Add or insert columns to the table.
1057
+ """
1058
+ Add or insert columns to the table.
1018
1059
 
1019
1060
  Parameters
1020
1061
  ----------
@@ -1040,6 +1081,7 @@ class Table(Cacheable):
1040
1081
  If the start_col is out of range for the table.
1041
1082
  ValueError:
1042
1083
  If the default value is unsupported by :py:meth:`numbers_parser.Table.write`.
1084
+
1043
1085
  """
1044
1086
  if start_col is not None and (start_col < 0 or start_col >= self.num_cols):
1045
1087
  msg = "Column number not in range for table"
@@ -1066,10 +1108,11 @@ class Table(Cacheable):
1066
1108
 
1067
1109
  def delete_row(
1068
1110
  self,
1069
- num_rows: Optional[int] = 1,
1070
- start_row: Optional[Union[int, None]] = None,
1111
+ num_rows: int | None = 1,
1112
+ start_row: int | None = None,
1071
1113
  ) -> None:
1072
- """Delete rows from the table.
1114
+ """
1115
+ Delete rows from the table.
1073
1116
 
1074
1117
  Parameters
1075
1118
  ----------
@@ -1089,6 +1132,7 @@ class Table(Cacheable):
1089
1132
  ------
1090
1133
  IndexError:
1091
1134
  If the start_row is out of range for the table.
1135
+
1092
1136
  """
1093
1137
  if start_row is not None and (start_row < 0 or start_row >= self.num_rows):
1094
1138
  msg = "Row number not in range for table"
@@ -1110,10 +1154,11 @@ class Table(Cacheable):
1110
1154
 
1111
1155
  def delete_column(
1112
1156
  self,
1113
- num_cols: Optional[int] = 1,
1114
- start_col: Optional[Union[int, None]] = None,
1157
+ num_cols: int | None = 1,
1158
+ start_col: int | None = None,
1115
1159
  ) -> None:
1116
- """Add or delete columns columns from the table.
1160
+ """
1161
+ Add or delete columns columns from the table.
1117
1162
 
1118
1163
  Parameters
1119
1164
  ----------
@@ -1127,6 +1172,7 @@ class Table(Cacheable):
1127
1172
  ------
1128
1173
  IndexError:
1129
1174
  If the start_col is out of range for the table.
1175
+
1130
1176
  """
1131
1177
  if start_col is not None and (start_col < 0 or start_col >= self.num_cols):
1132
1178
  msg = "Column number not in range for table"
@@ -1143,8 +1189,9 @@ class Table(Cacheable):
1143
1189
  self.num_cols -= num_cols
1144
1190
  self._model.number_of_columns(self._table_id, self.num_cols)
1145
1191
 
1146
- def merge_cells(self, cell_range: Union[str, List[str]]) -> None:
1147
- """Convert a cell range or list of cell ranges into merged cells.
1192
+ def merge_cells(self, cell_range: str | list[str]) -> None:
1193
+ """
1194
+ Convert a cell range or list of cell ranges into merged cells.
1148
1195
 
1149
1196
  Parameters
1150
1197
  ----------
@@ -1162,6 +1209,7 @@ class Table(Cacheable):
1162
1209
  >>> table.merge_cells("B2:C2")
1163
1210
  >>> table.cell("B2").is_merged
1164
1211
  True
1212
+
1165
1213
  """
1166
1214
  if isinstance(cell_range, list):
1167
1215
  for x in cell_range:
@@ -1184,8 +1232,9 @@ class Table(Cacheable):
1184
1232
  for col, cell in enumerate(cells):
1185
1233
  cell._set_merge(merge_cells.get((row, col)))
1186
1234
 
1187
- def set_cell_border(self, *args):
1188
- """Set the borders for a cell.
1235
+ def set_cell_border(self, *args) -> None:
1236
+ """
1237
+ Set the borders for a cell.
1189
1238
 
1190
1239
  Cell references can be row-column offsers or Excel/Numbers-style A1 notation. Borders
1191
1240
  can be applied to multiple sides of a cell by passing a list of sides. The name(s)
@@ -1221,10 +1270,11 @@ class Table(Cacheable):
1221
1270
  If an invalid number of arguments is passed or if the types of the arguments
1222
1271
  are invalid.
1223
1272
 
1224
- Warns
1273
+ Warns:
1225
1274
  -----
1226
1275
  RuntimeWarning:
1227
1276
  If any of the sides to which the border is applied have been merged.
1277
+
1228
1278
  """
1229
1279
  (row, col, *args) = self._validate_cell_coords(*args)
1230
1280
  if len(args) == 2:
@@ -1250,20 +1300,17 @@ class Table(Cacheable):
1250
1300
  return
1251
1301
 
1252
1302
  cell = self._data[row][col]
1253
- if cell.is_merged and (
1254
- (side == "right" and cell.size[1] > 1) or (side == "bottom" and cell.size[0] > 1)
1255
- ):
1256
- warn(
1257
- f"{side} edge of [{row},{col}] is merged; border not set",
1258
- RuntimeWarning,
1259
- stacklevel=2,
1303
+ if (
1304
+ cell.is_merged
1305
+ and ((side == "right" and cell.size[1] > 1) or (side == "bottom" and cell.size[0] > 1))
1306
+ ) or (
1307
+ isinstance(cell, MergedCell)
1308
+ and (
1309
+ (side == "top" and cell.row_start < row)
1310
+ or (side == "right" and cell.col_end > col)
1311
+ or (side == "bottom" and cell.row_end > row)
1312
+ or (side == "left" and cell.col_start < col)
1260
1313
  )
1261
- return
1262
- elif isinstance(cell, MergedCell) and (
1263
- (side == "top" and cell.row_start < row)
1264
- or (side == "right" and cell.col_end > col)
1265
- or (side == "bottom" and cell.row_end > row)
1266
- or (side == "left" and cell.col_start < col)
1267
1314
  ):
1268
1315
  warn(
1269
1316
  f"{side} edge of [{row},{col}] is merged; border not set",
@@ -1287,7 +1334,8 @@ class Table(Cacheable):
1287
1334
  self._model.add_stroke(self._table_id, row, col, side, border_value, length)
1288
1335
 
1289
1336
  def set_cell_formatting(self, *args: str, **kwargs) -> None:
1290
- r"""Set the data format for a cell.
1337
+ r"""
1338
+ Set the data format for a cell.
1291
1339
 
1292
1340
  Cell references can be **row-column** offsers or Excel/Numbers-style **A1** notation.
1293
1341
 
@@ -1295,7 +1343,7 @@ class Table(Cacheable):
1295
1343
 
1296
1344
  table.set_cell_formatting(
1297
1345
  "C1",
1298
- "date",
1346
+ "datetime",
1299
1347
  date_time_format="EEEE, d MMMM yyyy"
1300
1348
  )
1301
1349
  table.set_cell_formatting(
@@ -1314,7 +1362,7 @@ class Table(Cacheable):
1314
1362
  )
1315
1363
 
1316
1364
  :Parameters:
1317
- * **args** (*list*, *optional*) Positional arguments for cell reference and data format type (see below)
1365
+ * **args** (*list*, *optional*) - Positional arguments for cell reference and data format type (see below)
1318
1366
  * **kwargs** (*dict*, *optional*) - Key-value pairs defining a formatting options for each data format (see below).
1319
1367
 
1320
1368
  :Args (row-column):
@@ -1343,9 +1391,9 @@ class Table(Cacheable):
1343
1391
  depending upon the value of ``kwargs["type"]``.
1344
1392
 
1345
1393
  :Common Args:
1346
- * **name** (*str*) The name of the custom format. If no name is provided,
1394
+ * **name** (*str*) - The name of the custom format. If no name is provided,
1347
1395
  one is generated using the scheme ``Custom Format``, ``Custom Format 1``, ``Custom Format 2``, etc.
1348
- * **type** (*str, optional, default: number*) The type of format to
1396
+ * **type** (*str, optional, default: number*) - The type of format to
1349
1397
  create:
1350
1398
 
1351
1399
  * ``"base"``: A number base in the range 2-36.
@@ -1363,51 +1411,51 @@ class Table(Cacheable):
1363
1411
  * ``"popup"``: A menu of options.
1364
1412
 
1365
1413
  :``"base"``:
1366
- * **base_use_minus_sign** (*int, optional, default: 10*) The integer
1414
+ * **base_use_minus_sign** (*int, optional, default: 10*) - The integer
1367
1415
  base to represent the number from 2-36.
1368
- * **base_use_minus_sign** (*bool, optional, default: True*) If ``True``
1416
+ * **base_use_minus_sign** (*bool, optional, default: True*) - If ``True``
1369
1417
  use a standard minus sign, otherwise format as two's compliment (only
1370
1418
  possible for binary, octal and hexadecimal.
1371
- * **base_places** (*int, optional, default: 0*) The number of
1419
+ * **base_places** (*int, optional, default: 0*) - The number of
1372
1420
  decimal places, or ``None`` for automatic.
1373
1421
 
1374
1422
  :``"custom"``:
1375
- * **format** (*str | CustomFormating*) The name of a custom
1423
+ * **format** (*str | CustomFormating*) - The name of a custom
1376
1424
  formatin the document or a :py:class:`~numbers_parser.CustomFormatting`
1377
1425
  object.
1378
1426
 
1379
1427
  :``"currency"``:
1380
- * **currency** (*str, optional, default: "GBP"*) An ISO currency
1428
+ * **currency** (*str, optional, default: "GBP"*) - An ISO currency
1381
1429
  code, e.g. ``"GBP"`` or ``"USD"``.
1382
- * **decimal_places** (*int, optional, default: 2*) The number of
1430
+ * **decimal_places** (*int, optional, default: 2*) - The number of
1383
1431
  decimal places, or ``None`` for automatic.
1384
- * **negative_style** (*:py:class:`~numbers_parser.NegativeNumberStyle`, optional, default: NegativeNumberStyle.MINUS*) How negative numbers are represented.
1432
+ * **negative_style** (*:py:class:`~numbers_parser.NegativeNumberStyle`, optional, default: NegativeNumberStyle.MINUS*) - How negative numbers are represented.
1385
1433
  See `Negative number formats <#negative-formats>`_.
1386
- * **show_thousands_separator** (*bool, optional, default: False*) ``True``
1434
+ * **show_thousands_separator** (*bool, optional, default: False*) - ``True``
1387
1435
  if the number should include a thousands seperator, e.g. ``,``
1388
- * **use_accounting_style** (*bool, optional, default: False*) ``True``
1436
+ * **use_accounting_style** (*bool, optional, default: False*) - ``True``
1389
1437
  if the currency symbol should be formatted to the left of the cell and
1390
1438
  separated from the number value by a tab.
1391
1439
 
1392
1440
  :``"datetime"``:
1393
- * **date_time_format** (*str, optional, default: "dd MMM YYY HH:MM"*) A POSIX
1441
+ * **date_time_format** (*str, optional, default: "dd MMM YYY HH:MM"*) - A POSIX
1394
1442
  strftime-like formatting string of `Numbers date/time
1395
1443
  directives <#datetime-formats>`_.
1396
1444
 
1397
1445
  :``"fraction"``:
1398
- * **fraction_accuracy** (*:py:class:`~numbers_parser.FractionAccuracy`, optional, default: FractionAccuracy.THREE* The
1446
+ * **fraction_accuracy** (*:py:class:`~numbers_parser.FractionAccuracy`, optional, default: FractionAccuracy.THREE* - The
1399
1447
  precision of the faction.
1400
1448
 
1401
1449
  :``"percentage"``:
1402
- * **decimal_places** (*float, optional, default: None*) number of
1450
+ * **decimal_places** (*float, optional, default: None*) - number of
1403
1451
  decimal places, or ``None`` for automatic.
1404
- * **negative_style** (*:py:class:`~numbers_parser.NegativeNumberStyle`, optional, default: NegativeNumberStyle.MINUS*) How negative numbers are represented.
1452
+ * **negative_style** (*:py:class:`~numbers_parser.NegativeNumberStyle`, optional, default: NegativeNumberStyle.MINUS*) - How negative numbers are represented.
1405
1453
  See `Negative number formats <#negative-formats>`_.
1406
- * **show_thousands_separator** (*bool, optional, default: False*) ``True``
1454
+ * **show_thousands_separator** (*bool, optional, default: False*) - ``True``
1407
1455
  if the number should include a thousands seperator, e.g. ``,``
1408
1456
 
1409
1457
  :``"scientific"``:
1410
- * **decimal_places** (*float, optional, default: None*) number of
1458
+ * **decimal_places** (*float, optional, default: None*) - number of
1411
1459
  decimal places, or ``None`` for automatic.
1412
1460
 
1413
1461
  :``"tickbox"``:
@@ -1439,13 +1487,13 @@ class Table(Cacheable):
1439
1487
  * **minimum** (*float, optional, default: 1*) - increment value for the stepper
1440
1488
 
1441
1489
  :`"popup"``:
1442
- * **popup_values** (*List[str|int|float], optional, default: None*) values
1490
+ * **popup_values** (*List[str|int|float], optional, default: None*) - values
1443
1491
  for the popup menu
1444
1492
  * **allow_none** (*bool, optional, default: True*) - If ``True``
1445
1493
  include a blank value in the list
1446
1494
 
1447
1495
 
1448
- """ # noqa: E501
1496
+ """
1449
1497
  (row, col, *args) = self._validate_cell_coords(*args)
1450
1498
  if len(args) == 1:
1451
1499
  format_type = args[0]
@@ -1506,9 +1554,9 @@ class Table(Cacheable):
1506
1554
  msg,
1507
1555
  )
1508
1556
 
1509
- format = Formatting(type=format_type, **kwargs)
1557
+ formatting = Formatting(type=format_type, **kwargs)
1510
1558
  if format_type_name in FORMATTING_ACTION_CELLS:
1511
- control_id = self._model.control_cell_archive(self._table_id, format_type, format)
1559
+ control_id = self._model.control_cell_archive(self._table_id, format_type, formatting)
1512
1560
  else:
1513
1561
  control_id = None
1514
1562
 
@@ -1527,20 +1575,20 @@ class Table(Cacheable):
1527
1575
  ) from None
1528
1576
  else:
1529
1577
  number_format_type = FormattingType.NUMBER
1530
- format_id = self._model.format_archive(self._table_id, number_format_type, format)
1578
+ format_id = self._model.format_archive(self._table_id, number_format_type, formatting)
1531
1579
  elif format_type_name == "popup":
1532
- if cell.value == "" and not format.allow_none:
1580
+ if cell.value == "" and not formatting.allow_none:
1533
1581
  msg = "none value not allowed for popup"
1534
1582
  raise IndexError(msg)
1535
- elif cell.value != "" and cell.value not in format.popup_values:
1583
+ if cell.value != "" and cell.value not in formatting.popup_values:
1536
1584
  msg = f"current cell value '{cell.value}' does not match any popup values"
1537
1585
  raise IndexError(
1538
1586
  msg,
1539
1587
  )
1540
1588
 
1541
1589
  popup_format_type = FormattingType.TEXT if isinstance(cell, TextCell) else True
1542
- format_id = self._model.format_archive(self._table_id, popup_format_type, format)
1590
+ format_id = self._model.format_archive(self._table_id, popup_format_type, formatting)
1543
1591
  else:
1544
- format_id = self._model.format_archive(self._table_id, format_type, format)
1592
+ format_id = self._model.format_archive(self._table_id, format_type, formatting)
1545
1593
 
1546
1594
  cell._set_formatting(format_id, format_type, control_id, is_currency=is_currency)