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