numbers-parser 4.8.0__py3-none-any.whl → 4.9.0__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.
@@ -4,24 +4,28 @@ from warnings import warn
4
4
  from pendulum import DateTime, Duration
5
5
 
6
6
  from numbers_parser.cell import (
7
+ BackgroundImage,
7
8
  Border,
8
9
  Cell,
10
+ ControlFormattingType,
9
11
  CustomFormatting,
10
12
  CustomFormattingType,
11
- DateCell,
12
13
  Formatting,
13
14
  FormattingType,
14
15
  MergedCell,
15
- NumberCell,
16
16
  Style,
17
17
  TextCell,
18
18
  UnsupportedWarning,
19
19
  xl_cell_to_rowcol,
20
+ xl_range,
20
21
  )
21
22
  from numbers_parser.cell_storage import CellStorage
22
23
  from numbers_parser.constants import (
24
+ CUSTOM_FORMATTING_ALLOWED_CELLS,
23
25
  DEFAULT_COLUMN_COUNT,
24
26
  DEFAULT_ROW_COUNT,
27
+ FORMATTING_ACTION_CELLS,
28
+ FORMATTING_ALLOWED_CELLS,
25
29
  MAX_COL_COUNT,
26
30
  MAX_HEADER_COUNT,
27
31
  MAX_ROW_COUNT,
@@ -29,7 +33,7 @@ from numbers_parser.constants import (
29
33
  from numbers_parser.containers import ItemsList
30
34
  from numbers_parser.file import write_numbers_file
31
35
  from numbers_parser.model import _NumbersModel
32
- from numbers_parser.numbers_cache import Cacheable, cache
36
+ from numbers_parser.numbers_cache import Cacheable
33
37
 
34
38
  __all__ = ["Document", "Sheet", "Table"]
35
39
 
@@ -197,20 +201,6 @@ class Document:
197
201
  If no style name is provided, the next available numbered style
198
202
  will be generated in the series ``Custom Style 1``, ``Custom Style 2``, etc.
199
203
 
200
- Parameters
201
- ----------
202
- kwargs: dict, optional
203
- Key-value pairs to pass to the :class:`Style` constructor
204
-
205
- Raises
206
- ------
207
- TypeError:
208
- If ``font_size`` is not a ``float``, ``font_name`` is not a ``str``,
209
- or if any of the ``bool`` parameters are invalid.
210
-
211
- Example
212
- -------
213
-
214
204
  .. code-block:: python
215
205
 
216
206
  red_text = doc.add_style(
@@ -224,9 +214,27 @@ class Document:
224
214
  )
225
215
  table.write("B2", "Red", style=red_text)
226
216
  table.set_cell_style("C2", red_text)
217
+
218
+ Parameters
219
+ ----------
220
+ kwargs: dict, optional
221
+ Key-value pairs to pass to the :py:class:`~numbers_parser.Style` constructor.
222
+
223
+ Raises
224
+ ------
225
+ TypeError:
226
+ If ``font_size`` is not a ``float``, ``font_name`` is not a ``str``,
227
+ ``bg_image`` is not a :py:class:`~numbers_parser.BackgroundImage`,
228
+ or if any of the ``bool`` parameters are invalid.
227
229
  """ # noqa: E501
228
230
  if "name" in kwargs and kwargs["name"] is not None and kwargs["name"] in self._model.styles:
229
231
  raise IndexError(f"style '{kwargs['name']}' already exists")
232
+
233
+ if "bg_image" in kwargs and kwargs["bg_image"] is not None:
234
+ if not isinstance(kwargs["bg_image"], BackgroundImage):
235
+ raise TypeError("bg_image must be a BackgroundImage object")
236
+ self._model.store_image((kwargs["bg_image"].data), kwargs["bg_image"].filename)
237
+
230
238
  style = Style(**kwargs)
231
239
  if style.name is None:
232
240
  style.name = self._model.custom_style_name()
@@ -238,20 +246,28 @@ class Document:
238
246
  r"""
239
247
  Add a new custom format to the current document.
240
248
 
249
+ .. code-block:: python
250
+
251
+ long_date = doc.add_custom_format(
252
+ name="Long Date",
253
+ type="date",
254
+ date_time_format="EEEE, d MMMM yyyy"
255
+ )
256
+ table.set_cell_formatting("C1", "custom", format=long_date)
257
+
241
258
  All custom formatting styles share a name and a type, described in the **Common**
242
259
  parameters in the following table. Additional key-value pairs configure the format
243
- depending upon the value of ``kwargs["type"]``. Supported values for
244
- ``kwargs["type"]`` are:
245
-
246
- * ``"datetime"``: A date and time value with custom formatting.
247
- * ``"number"``: A decimal number.
248
- * ``"text"``: A simple text string.
260
+ depending upon the value of ``kwargs["type"]``.
249
261
 
250
- :Common Keys:
262
+ :Common Args:
251
263
  * **name** (``str``) – The name of the custom format. If no name is provided,
252
264
  one is generated using the scheme ``Custom Format``, ``Custom Format 1``, ``Custom Format 2``, etc.
253
265
  * **type** (``str``, *optional*, default: ``number``) – The type of format to
254
- create Supported formats are ``number``, ``datetime`` and ``text``.
266
+ create:
267
+
268
+ * ``"datetime"``: A date and time value with custom formatting.
269
+ * ``"number"``: A decimal number.
270
+ * ``"text"``: A simple text string.
255
271
 
256
272
  :``"number"``:
257
273
  * **integer_format** (``PaddingType``, *optional*, default: ``PaddingType.NONE``) – How
@@ -273,17 +289,6 @@ class Document:
273
289
  * **format** (``str``, *optional*, default: ``"%s"``) – Text format.
274
290
  The cell value is inserted in place of %s. Only one substitution is allowed by
275
291
  Numbers, and multiple %s formatting references raise a TypeError exception
276
-
277
- Example
278
- -------
279
-
280
- .. code-block:: python
281
-
282
- long_date = doc.add_custom_format(
283
- name="Long Date",
284
- type="date",
285
- date_time_format="EEEE, d MMMM yyyy")
286
- table.set_cell_formatting("C1", "custom", format=long_date)
287
292
  """ # noqa: E501
288
293
  if (
289
294
  "name" in kwargs
@@ -312,11 +317,6 @@ class Document:
312
317
 
313
318
 
314
319
  class Sheet:
315
- """
316
- .. NOTE::
317
- Do not instantiate directly. Sheets are created by :py:class:`~numbers_parser.Document`.
318
- """
319
-
320
320
  def __init__(self, model, sheet_id):
321
321
  self._sheet_id = sheet_id
322
322
  self._model = model
@@ -408,11 +408,6 @@ class Sheet:
408
408
 
409
409
 
410
410
  class Table(Cacheable): # noqa: F811
411
- """
412
- .. NOTE::
413
- Do not instantiate directly. Tables are created by :py:class:`~numbers_parser.Document`.
414
- """
415
-
416
411
  def __init__(self, model, table_id):
417
412
  super().__init__()
418
413
  self._model = model
@@ -461,6 +456,14 @@ class Table(Cacheable): # noqa: F811
461
456
  """
462
457
  int: The number of header rows.
463
458
 
459
+ Example
460
+ -------
461
+
462
+ .. code-block:: python
463
+
464
+ # Add an extra header row
465
+ table.num_header_rows += 1
466
+
464
467
  Raises
465
468
  ------
466
469
  ValueError:
@@ -484,6 +487,14 @@ class Table(Cacheable): # noqa: F811
484
487
  """
485
488
  int: The number of header columns.
486
489
 
490
+ Example
491
+ -------
492
+
493
+ .. code-block:: python
494
+
495
+ # Add an extra header column
496
+ table.num_header_cols += 1
497
+
487
498
  Raises
488
499
  ------
489
500
  ValueError:
@@ -516,6 +527,11 @@ class Table(Cacheable): # noqa: F811
516
527
  """
517
528
  The height of a table row in points.
518
529
 
530
+ .. code-block:: python
531
+
532
+ # Double the row's height
533
+ _ = table.row_height(4, table.row_height(4) * 2)
534
+
519
535
  Parameters
520
536
  ----------
521
537
  row: int
@@ -571,7 +587,6 @@ class Table(Cacheable): # noqa: F811
571
587
  return self._data
572
588
 
573
589
  @property
574
- @cache(num_args=0)
575
590
  def merge_ranges(self) -> List[str]:
576
591
  """List[str]: The merge ranges of cells in A1 notation.
577
592
 
@@ -587,8 +602,13 @@ class Table(Cacheable): # noqa: F811
587
602
  >>> table.cell("A5")
588
603
  <numbers_parser.cell.MergedCell object at 0x1035f5310>
589
604
  """
590
- merge_cells = self._model.merge_cells(self._table_id).merge_cell_names()
591
- return sorted(set(list(merge_cells)))
605
+ merge_cells = set()
606
+ for row, cells in enumerate(self._data):
607
+ for col, cell in enumerate(cells):
608
+ if cell.is_merged:
609
+ size = cell.size
610
+ merge_cells.add(xl_range(row, col, row + size[0] - 1, col + size[1] - 1))
611
+ return sorted(list(merge_cells))
592
612
 
593
613
  def cell(self, *args) -> Union[Cell, MergedCell]:
594
614
  """
@@ -804,20 +824,28 @@ class Table(Cacheable): # noqa: F811
804
824
  The ``write()`` method supports two forms of notation to designate the position
805
825
  of cells: **Row-column** notation and **A1** notation:
806
826
 
807
- .. code-block:: python
827
+ .. code:: python
808
828
 
809
- (0, 0) # Row-column notation.
810
- ("A1") # The same cell in A1 notation.
829
+ doc = Document("write.numbers")
830
+ sheets = doc.sheets
831
+ tables = sheets[0].tables
832
+ table = tables[0]
833
+ table.write(1, 1, "This is new text")
834
+ table.write("B7", datetime(2020, 12, 25))
835
+ doc.save("new-sheet.numbers")
811
836
 
812
837
  Parameters
813
838
  ----------
814
839
 
815
- param1: int
840
+ row: int
816
841
  The row number (zero indexed)
817
- param2: int
842
+ col: int
818
843
  The column number (zero indexed)
819
- param3: str | int | float | bool | DateTime | Duration
820
- The value to write to the cell. The generated cell type
844
+ value: str | int | float | bool | DateTime | Duration
845
+ The value to write to the cell. The generated cell type is automatically
846
+ created based on the type of ``value``.
847
+ style: Style | str | None
848
+ The name of a document custom style or a :py:class:`~numbers_parser.cell.Style` object.
821
849
 
822
850
  Warns
823
851
  -----
@@ -833,19 +861,6 @@ class Table(Cacheable): # noqa: F811
833
861
  If the style parameter is an invalid type.
834
862
  ValueError:
835
863
  If the cell type cannot be determined from the type of `param3`.
836
-
837
- Example
838
- -------
839
-
840
- .. code:: python
841
-
842
- doc = Document("write.numbers")
843
- sheets = doc.sheets
844
- tables = sheets[0].tables
845
- table = tables[0]
846
- table.write(1, 1, "This is new text")
847
- table.write("B7", datetime(2020, 12, 25))
848
- doc.save("new-sheet.numbers")
849
864
  """
850
865
  # TODO: write needs to retain/init the border
851
866
  (row, col, value) = self._validate_cell_coords(*args)
@@ -1050,8 +1065,27 @@ class Table(Cacheable): # noqa: F811
1050
1065
  self.num_cols -= num_cols
1051
1066
  self._model.number_of_columns(self._table_id, self.num_cols)
1052
1067
 
1053
- def merge_cells(self, cell_range):
1054
- """Convert a cell range or list of cell ranges into merged cells."""
1068
+ def merge_cells(self, cell_range: Union[str, List[str]]) -> None:
1069
+ """
1070
+ Convert a cell range or list of cell ranges into merged cells.
1071
+
1072
+ Parameters
1073
+ ----------
1074
+ cell_range: str | List[str]
1075
+ Cell range(s) to merge in A1 notation
1076
+
1077
+ Example
1078
+ --------
1079
+ .. code:: python
1080
+
1081
+ >>> table.cell("B2")
1082
+ <numbers_parser.cell.TextCell object at 0x102c0d390>
1083
+ >>> table.cell("B2").is_merged
1084
+ False
1085
+ >>> table.merge_cells("B2:C2")
1086
+ >>> table.cell("B2").is_merged
1087
+ True
1088
+ """
1055
1089
  if isinstance(cell_range, list):
1056
1090
  for x in cell_range:
1057
1091
  self.merge_cells(x)
@@ -1074,6 +1108,48 @@ class Table(Cacheable): # noqa: F811
1074
1108
  cell._set_merge(merge_cells.get((row, col)))
1075
1109
 
1076
1110
  def set_cell_border(self, *args):
1111
+ """
1112
+ Set the borders for a cell.
1113
+
1114
+ Cell references can be row-column offsers or Excel/Numbers-style A1 notation. Borders
1115
+ can be applied to multiple sides of a cell by passing a list of sides. The name(s)
1116
+ of the side(s) must be one of ``"top"``, ``"right"``, ``"bottom"`` or ``"left"``.
1117
+
1118
+ Numbers supports different border styles for each cell within a merged cell range
1119
+ for those cells that are on the outer part of the merge. ``numbers-parser`` will
1120
+ ignore attempts to set these invisible cell edges and issue a ``RuntimeWarning``.
1121
+
1122
+ .. code-block:: python
1123
+
1124
+ # Dashed line for B7's right border
1125
+ table.set_cell_border(6, 1, "right", Border(5.0, RGB(29, 177, 0), "dashes"))
1126
+ # Solid line starting at B7's left border and running for 3 rows
1127
+ table.set_cell_border("B7", "left", Border(8.0, RGB(29, 177, 0), "solid"), 3)
1128
+
1129
+ :Args (row-column):
1130
+ * **param1** (*int*): The row number (zero indexed).
1131
+ * **param2** (*int*): The column number (zero indexed).
1132
+ * **param3** (*str | List[str]*): Which side(s) of the cell to apply the border to.
1133
+ * **param4** (:py:class:`Border`): The border to add.
1134
+ * **param5** (*int*, *optinal*, default: 1): The length of the stroke to add.
1135
+
1136
+ :Args (A1):
1137
+ * **param1** (*str*): A cell reference using Excel/Numbers-style A1 notation.
1138
+ * **param2** (*str | List[str]*): Which side(s) of the cell to apply the border to.
1139
+ * **param3** (:py:class:`Border`): The border to add.
1140
+ * **param4** (*int*, *optional*, default: 1): The length of the stroke to add.
1141
+
1142
+ Raises
1143
+ ------
1144
+ TypeError:
1145
+ If an invalid number of arguments is passed or if the types of the arguments
1146
+ are invalid.
1147
+
1148
+ Warns
1149
+ -----
1150
+ RuntimeWarning:
1151
+ If any of the sides to which the border is applied have been merged.
1152
+ """ # noqa: E501
1077
1153
  (row, col, *args) = self._validate_cell_coords(*args)
1078
1154
  if len(args) == 2:
1079
1155
  (side, border_value) = args
@@ -1094,9 +1170,24 @@ class Table(Cacheable): # noqa: F811
1094
1170
  self.set_cell_border(row, col, s, border_value, length)
1095
1171
  return
1096
1172
 
1097
- if self._data[row][col].is_merged and side in ["bottom", "right"]:
1173
+ cell = self._data[row][col]
1174
+ if cell.is_merged and (
1175
+ (side == "right" and cell.size[1] > 1) or (side == "bottom" and cell.size[0] > 1)
1176
+ ):
1098
1177
  warn(
1099
- f"cell [{row},{col}] is merged; {side} border not set",
1178
+ f"{side} edge of [{row},{col}] is merged; border not set",
1179
+ RuntimeWarning,
1180
+ stacklevel=2,
1181
+ )
1182
+ return
1183
+ elif isinstance(cell, MergedCell) and (
1184
+ (side == "top" and cell.row_start < row)
1185
+ or (side == "right" and cell.col_end > col)
1186
+ or (side == "bottom" and cell.row_end > row)
1187
+ or (side == "left" and cell.col_start < col)
1188
+ ):
1189
+ warn(
1190
+ f"{side} edge of [{row},{col}] is merged; border not set",
1100
1191
  RuntimeWarning,
1101
1192
  stacklevel=2,
1102
1193
  )
@@ -1121,92 +1212,144 @@ class Table(Cacheable): # noqa: F811
1121
1212
 
1122
1213
  Cell references can be **row-column** offsers or Excel/Numbers-style **A1** notation.
1123
1214
 
1215
+ .. code:: python
1216
+
1217
+ table.set_cell_formatting(
1218
+ "C1",
1219
+ "date",
1220
+ date_time_format="EEEE, d MMMM yyyy"
1221
+ )
1222
+ table.set_cell_formatting(
1223
+ 0,
1224
+ 4,
1225
+ "number",
1226
+ decimal_places=3,
1227
+ negative_style=NegativeNumberStyle.RED
1228
+ )
1229
+
1124
1230
  :Parameters:
1125
1231
  * **args** (*list*, *optional*) – Positional arguments for cell reference and data format type (see below)
1126
1232
  * **kwargs** (*dict*, *optional*) - Key-value pairs defining a formatting options for each data format (see below).
1127
1233
 
1128
1234
  :Args (row-column):
1129
- * **param1** (``int``): The row number (zero indexed).
1130
- * **param2** (``int``): The column number (zero indexed).
1131
- * **param3** (``str``): Data format type for the cell (see "data formats" below).
1235
+ * **param1** (*int*): The row number (zero indexed).
1236
+ * **param2** (*int*): The column number (zero indexed).
1237
+ * **param3** (*str*): Data format type for the cell (see "data formats" below).
1132
1238
 
1133
1239
  :Args (A1):
1134
- * **param1** (``str``): A cell reference using Excel/Numbers-style A1 notation.
1135
- * **param2** (``str``): Data format type for the cell (see "data formats" below).
1240
+ * **param1** (*str*): A cell reference using Excel/Numbers-style A1 notation.
1241
+ * **param2** (*str*): Data format type for the cell (see "data formats" below).
1242
+
1243
+ :Raises:
1244
+ * **TypeError** -
1245
+ If a tickbox is chosen for anything other than ``bool`` values.
1136
1246
 
1137
1247
  :Warns:
1138
1248
  * **RuntimeWarning** -
1139
1249
  If ``use_accounting_style`` is used with
1140
- any ``negative_style`` other than ``NegativeNumberStyle.MINUS``.
1250
+ any ``negative_style`` other than ``NegativeNumberStyle.MINUS``, or
1251
+ if a rating is out of range 0 to 5 (rating is clamped to these values).
1141
1252
 
1142
1253
  All formatting styles share a name and a type, described in the **Common**
1143
1254
  parameters in the following table. Additional key-value pairs configure the format
1144
- depending upon the value of ``kwargs["type"]``. Supported values for
1145
- ``kwargs["type"]`` are:
1146
-
1147
- * ``"base"``: A number base in the range 2-36.
1148
- * ``"currency"``: A decimal formatted with a currency symbol.
1149
- * ``"datetime"``: A date and time value with custom formatting.
1150
- * ``"fraction"``: A number formatted as the nearest fraction.
1151
- * ``"percentage"``: A number formatted as a percentage
1152
- * ``"number"``: A decimal number.
1153
- * ``"scientific"``: A decimal number with scientific notation.
1154
-
1155
- :Common keys:
1156
- * **name** (``str``) – The name of the custom format. If no name is provided,
1255
+ depending upon the value of ``kwargs["type"]``.
1256
+
1257
+ :Common Args:
1258
+ * **name** (*str*) The name of the custom format. If no name is provided,
1157
1259
  one is generated using the scheme ``Custom Format``, ``Custom Format 1``, ``Custom Format 2``, etc.
1158
- * **type** (``str``, *optional*, default: ``number``) – The type of format to
1159
- create Supported formats are ``number``, ``datetime`` and ``text``.
1260
+ * **type** (*str, optional, default: number*) – The type of format to
1261
+ create:
1262
+
1263
+ * ``"base"``: A number base in the range 2-36.
1264
+ * ``"currency"``: A decimal formatted with a currency symbol.
1265
+ * ``"datetime"``: A date and time value with custom formatting.
1266
+ * ``"fraction"``: A number formatted as the nearest fraction.
1267
+ * ``"percentage"``: A number formatted as a percentage
1268
+ * ``"number"``: A decimal number.
1269
+ * ``"scientific"``: A decimal number with scientific notation.
1270
+ * ``"tickbox"``: A checkbox (bool values only).
1271
+ * ``"rating"``: A star rating from 0 to 5.
1272
+ * ``"slider"``: A range slider.
1273
+ * ``"stepper"``: An up/down value stepper.
1274
+ * ``"popup"``: A menu of options.
1160
1275
 
1161
1276
  :``"base"``:
1162
- * **base_use_minus_sign** (``int``, *optional*, default: ``10``) – The integer
1277
+ * **base_use_minus_sign** (*int, optional, default: 10*) – The integer
1163
1278
  base to represent the number from 2-36.
1164
- * **base_use_minus_sign** (``bool``, *optional*, default: ``True``) – If ``True``
1279
+ * **base_use_minus_sign** (*bool, optional, default: True*) – If ``True``
1165
1280
  use a standard minus sign, otherwise format as two's compliment (only
1166
1281
  possible for binary, octal and hexadecimal.
1167
- * **base_places** (``int``, *optional*, default: ``0``) – The number of
1282
+ * **base_places** (*int, optional, default: 0*) – The number of
1168
1283
  decimal places, or ``None`` for automatic.
1169
1284
 
1170
1285
  :``"currency"``:
1171
- * **currency** (``str``, *optional*, default: ``"GBP"``) – An ISO currency
1286
+ * **currency** (*str, optional, default: "GBP"*) – An ISO currency
1172
1287
  code, e.g. ``"GBP"`` or ``"USD"``.
1173
- * **decimal_places** (``int``, *optional*, default: ``2``) – The number of
1288
+ * **decimal_places** (*int, optional, default: 2*) – The number of
1174
1289
  decimal places, or ``None`` for automatic.
1175
- * **negative_style** (``NegativeNumberStyle``, *optional*, default: ``NegativeNumberStyle.MINUS``) – How negative numbers are represented.
1290
+ * **negative_style** (*:py:class:`~numbers_parser.NegativeNumberStyle`, optional, default: NegativeNumberStyle.MINUS*) – How negative numbers are represented.
1176
1291
  See `Negative number formats <#negative-formats>`_.
1177
- * **show_thousands_separator** (``bool``, *optional*, default: ``False``) – ``True``
1292
+ * **show_thousands_separator** (*bool, optional, default: False*) – ``True``
1178
1293
  if the number should include a thousands seperator, e.g. ``,``
1179
- * **use_accounting_style** (``bool``, *optional*, default: ``False``) – ``True``
1294
+ * **use_accounting_style** (*bool, optional, default: False*) – ``True``
1180
1295
  if the currency symbol should be formatted to the left of the cell and
1181
1296
  separated from the number value by a tab.
1182
1297
 
1183
1298
  :``"datetime"``:
1184
- * **date_time_format** (``str``, *optional*, default: ``"dd MMM YYY HH:MM"``) – A POSIX
1299
+ * **date_time_format** (*str, optional, default: "dd MMM YYY HH:MM"*) – A POSIX
1185
1300
  strftime-like formatting string of `Numbers date/time
1186
1301
  directives <#datetime-formats>`_.
1187
1302
 
1188
1303
  :``"fraction"``:
1189
- * **fraction_accuracy** (``FractionAccuracy``, *optional*, default: ``FractionAccuracy.THREE`` – The
1304
+ * **fraction_accuracy** (*:py:class:`~numbers_parser.FractionAccuracy`, optional, default: FractionAccuracy.THREE* – The
1190
1305
  precision of the faction.
1191
1306
 
1192
1307
  :``"percentage"``:
1193
- * **decimal_places** (``float``, *optional*, default: ``None``) – number of
1308
+ * **decimal_places** (*float, optional, default: None*) – number of
1194
1309
  decimal places, or ``None`` for automatic.
1195
- * **negative_style** (``NegativeNumberStyle``, *optional*, default: ``NegativeNumberStyle.MINUS``) – How negative numbers are represented.
1310
+ * **negative_style** (*:py:class:`~numbers_parser.NegativeNumberStyle`, optional, default: NegativeNumberStyle.MINUS*) – How negative numbers are represented.
1196
1311
  See `Negative number formats <#negative-formats>`_.
1197
- * **show_thousands_separator** (``bool``, *optional*, default: ``False``) – ``True``
1312
+ * **show_thousands_separator** (*bool, optional, default: False*) – ``True``
1198
1313
  if the number should include a thousands seperator, e.g. ``,``
1199
1314
 
1200
1315
  :``"scientific"``:
1201
- * **decimal_places** (``float``, *optional*, default: ``None``) – number of
1316
+ * **decimal_places** (*float, optional, default: None*) – number of
1202
1317
  decimal places, or ``None`` for automatic.
1203
1318
 
1204
- Example
1319
+ :``"tickbox"``:
1320
+ * No additional parameters defined.
1321
+
1322
+ :``"rating"``:
1323
+ * No additional parameters defined.
1324
+
1325
+ :``"slider"``:
1326
+ * **control_format** (*ControlFormattingType, optional, default: ControlFormattingType.NUMBER*) - the format
1327
+ of the data in the slider. Valid options are ``"base"``, ``"currency"``,
1328
+ ``"datetime"``, ``"fraction"``, ``"percentage"``, ``"number"``,
1329
+ or ``"scientific". Each format allows additional parameters identical to those
1330
+ available for the formats themselves. For example, a slider using fractions
1331
+ is configured with ``fraction_accuracy``.
1332
+ * **increment** (*float, optional, default: 1*) - the slider's minimum value
1333
+ * **maximum** (*float, optional, default: 100*) - the slider's maximum value
1334
+ * **minimum** (*float, optional, default: 1*) - increment value for the slider
1335
+
1336
+ :`"stepper"``:
1337
+ * **control_format** (*ControlFormattingType, optional, default: ControlFormattingType.NUMBER*) - the format
1338
+ of the data in the stepper. Valid options are ``"base"``, ``"currency"``,
1339
+ ``"datetime"``, ``"fraction"``, ``"percentage"``, ``"number"``,
1340
+ or ``"scientific"``. Each format allows additional parameters identical to those
1341
+ available for the formats themselves. For example, a stepper using fractions
1342
+ is configured with ``fraction_accuracy``.
1343
+ * **increment** (*float, optional, default: 1*) - the stepper's minimum value
1344
+ * **maximum** (*float, optional, default: 100*) - the stepper's maximum value
1345
+ * **minimum** (*float, optional, default: 1*) - increment value for the stepper
1346
+
1347
+ :`"popup"``:
1348
+ * **popup_values** (*List[str|int|float], optional, default: None*) – values
1349
+ for the popup menu
1350
+ * **allow_none** (*bool, optional, default: True*) - If ``True``
1351
+ include a blank value in the list
1205
1352
 
1206
- .. code:: python
1207
-
1208
- >>> table.set_cell_formatting("C1", "date", date_time_format="EEEE, d MMMM yyyy")
1209
- >>> table.set_cell_formatting(0, 4, "number", decimal_places=3, negative_style=NegativeNumberStyle.RED)
1210
1353
 
1211
1354
  """ # noqa: E501
1212
1355
  (row, col, *args) = self._validate_cell_coords(*args)
@@ -1218,11 +1361,11 @@ class Table(Cacheable): # noqa: F811
1218
1361
  raise TypeError("no type defined for cell format")
1219
1362
 
1220
1363
  if format_type == "custom":
1221
- self.set_cell_custom_format(row, col, **kwargs)
1364
+ self._set_cell_custom_format(row, col, **kwargs)
1222
1365
  else:
1223
- self.set_cell_data_format(row, col, format_type, **kwargs)
1366
+ self._set_cell_data_format(row, col, format_type, **kwargs)
1224
1367
 
1225
- def set_cell_custom_format(self, row: int, col: int, **kwargs) -> None:
1368
+ def _set_cell_custom_format(self, row: int, col: int, **kwargs) -> None:
1226
1369
  if "format" not in kwargs:
1227
1370
  raise TypeError("no format provided for custom format")
1228
1371
 
@@ -1237,33 +1380,57 @@ class Table(Cacheable): # noqa: F811
1237
1380
  raise TypeError("format must be a CustomFormatting object or format name")
1238
1381
 
1239
1382
  cell = self._data[row][col]
1240
- if custom_format.type == CustomFormattingType.DATETIME and not isinstance(cell, DateCell):
1241
- type_name = type(cell).__name__
1242
- raise TypeError(f"cannot use date/time formatting for cells of type {type_name}")
1243
- elif custom_format.type == CustomFormattingType.NUMBER and not isinstance(cell, NumberCell):
1244
- type_name = type(cell).__name__
1245
- raise TypeError(f"cannot use number formatting for cells of type {type_name}")
1246
- elif custom_format.type == CustomFormattingType.TEXT and not isinstance(cell, TextCell):
1247
- type_name = type(cell).__name__
1248
- raise TypeError(f"cannot use text formatting for cells of type {type_name}")
1383
+ type_name = type(cell).__name__
1384
+ format_type_name = custom_format.type.name.lower()
1385
+ if type_name not in CUSTOM_FORMATTING_ALLOWED_CELLS[format_type_name]:
1386
+ raise TypeError(
1387
+ f"cannot use {format_type_name} formatting for cells of type {type_name}"
1388
+ )
1249
1389
 
1250
1390
  format_id = self._model.custom_format_id(self._table_id, custom_format)
1251
1391
  cell._set_formatting(format_id, custom_format.type)
1252
1392
 
1253
- def set_cell_data_format(self, row: int, col: int, format_type: str, **kwargs) -> None:
1393
+ def _set_cell_data_format(self, row: int, col: int, format_type_name: str, **kwargs) -> None:
1254
1394
  try:
1255
- format_type = FormattingType[format_type.upper()]
1395
+ format_type = FormattingType[format_type_name.upper()]
1256
1396
  except (KeyError, AttributeError):
1257
- raise TypeError(f"unsuported cell format type '{format_type}'") from None
1397
+ raise TypeError(f"unsuported cell format type '{format_type_name}'") from None
1258
1398
 
1259
1399
  cell = self._data[row][col]
1260
- if format_type == FormattingType.DATETIME and not isinstance(cell, DateCell):
1261
- type_name = type(cell).__name__
1262
- raise TypeError(f"cannot use date/time formatting for cells of type {type_name}")
1263
- elif not isinstance(cell, NumberCell) and not isinstance(cell, DateCell):
1264
- type_name = type(cell).__name__
1265
- raise TypeError(f"cannot set formatting for cells of type {type_name}")
1400
+ type_name = type(cell).__name__
1401
+ if type_name not in FORMATTING_ALLOWED_CELLS[format_type_name]:
1402
+ raise TypeError(
1403
+ f"cannot use {format_type_name} formatting for cells of type {type_name}"
1404
+ )
1266
1405
 
1267
1406
  format = Formatting(type=format_type, **kwargs)
1268
- format_id = self._model.format_archive(self._table_id, format_type, format)
1269
- cell._set_formatting(format_id, format_type)
1407
+ if format_type_name in FORMATTING_ACTION_CELLS:
1408
+ control_id = self._model.control_cell_archive(self._table_id, format_type, format)
1409
+ else:
1410
+ control_id = None
1411
+
1412
+ is_currency = True if format_type == FormattingType.CURRENCY else False
1413
+ if format_type_name in ["slider", "stepper"]:
1414
+ if "control_format" in kwargs:
1415
+ try:
1416
+ control_format = kwargs["control_format"].name
1417
+ number_format_type = FormattingType[control_format]
1418
+ is_currency = (
1419
+ True
1420
+ if kwargs["control_format"] == ControlFormattingType.CURRENCY
1421
+ else False
1422
+ )
1423
+ except (KeyError, AttributeError):
1424
+ raise TypeError(
1425
+ "unsupported number format '{control_format}' for format_type_name"
1426
+ ) from None
1427
+ else:
1428
+ number_format_type = FormattingType.NUMBER
1429
+ format_id = self._model.format_archive(self._table_id, number_format_type, format)
1430
+ elif format_type_name == "popup":
1431
+ popup_format_type = FormattingType.TEXT if isinstance(cell, TextCell) else True
1432
+ format_id = self._model.format_archive(self._table_id, popup_format_type, format)
1433
+ else:
1434
+ format_id = self._model.format_archive(self._table_id, format_type, format)
1435
+
1436
+ cell._set_formatting(format_id, format_type, control_id, is_currency=is_currency)