tableio 0.2__tar.gz → 0.4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. {tableio-0.2/tableio.egg-info → tableio-0.4}/PKG-INFO +23 -17
  2. {tableio-0.2 → tableio-0.4}/README.md +2 -2
  3. {tableio-0.2 → tableio-0.4}/README_pypi.md +17 -13
  4. {tableio-0.2 → tableio-0.4}/pyproject.toml +1 -1
  5. {tableio-0.2 → tableio-0.4}/setup.py +6 -4
  6. tableio-0.4/src/tableio/__init__.py +47 -0
  7. tableio-0.4/src/tableio/_archive_rewrite.py +80 -0
  8. {tableio-0.2 → tableio-0.4}/src/tableio/capability.py +14 -0
  9. {tableio-0.2 → tableio-0.4}/src/tableio/factory.py +61 -12
  10. {tableio-0.2 → tableio-0.4}/src/tableio/reg_pkg_formats.py +6 -1
  11. {tableio-0.2 → tableio-0.4}/src/tableio/tableio.py +161 -110
  12. {tableio-0.2 → tableio-0.4}/src/tableio/tableio_excel_openpyxl.py +77 -37
  13. tableio-0.4/src/tableio/tableio_excel_pylightxl.py +731 -0
  14. tableio-0.4/src/tableio/tableio_excel_xlsxwriter.py +407 -0
  15. {tableio-0.2 → tableio-0.4}/src/tableio/tableio_excelbased.py +49 -2
  16. {tableio-0.2 → tableio-0.4}/src/tableio/tableio_ods_odfdo.py +118 -35
  17. {tableio-0.2 → tableio-0.4}/src/tableio/tableio_spreadsheetbased.py +220 -26
  18. tableio-0.4/src/tableio/tableio_types.py +61 -0
  19. {tableio-0.2 → tableio-0.4}/src/tableio/valueconversion.py +3 -2
  20. {tableio-0.2 → tableio-0.4/tableio.egg-info}/PKG-INFO +23 -17
  21. {tableio-0.2 → tableio-0.4}/tableio.egg-info/SOURCES.txt +4 -0
  22. tableio-0.4/tableio.egg-info/requires.txt +10 -0
  23. tableio-0.2/src/tableio/__init__.py +0 -6
  24. tableio-0.2/tableio.egg-info/requires.txt +0 -8
  25. {tableio-0.2 → tableio-0.4}/LICENSE.txt +0 -0
  26. {tableio-0.2 → tableio-0.4}/setup.cfg +0 -0
  27. {tableio-0.2 → tableio-0.4}/src/tableio/color.py +0 -0
  28. {tableio-0.2 → tableio-0.4}/src/tableio/optional_args.py +0 -0
  29. {tableio-0.2 → tableio-0.4}/src/tableio/py.typed +0 -0
  30. {tableio-0.2 → tableio-0.4}/src/tableio/tableio_csv.py +0 -0
  31. {tableio-0.2 → tableio-0.4}/src/tableio/tableio_mformat.py +0 -0
  32. {tableio-0.2 → tableio-0.4}/src/tableio/tableio_mformatbased.py +0 -0
  33. {tableio-0.2 → tableio-0.4}/src/tableio/tableio_textbased.py +0 -0
  34. {tableio-0.2 → tableio-0.4}/src/tableio/value_type.py +0 -0
  35. {tableio-0.2 → tableio-0.4}/tableio.egg-info/dependency_links.txt +0 -0
  36. {tableio-0.2 → tableio-0.4}/tableio.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tableio
3
- Version: 0.2
3
+ Version: 0.4
4
4
  Summary: Uniform way to write table data to and read from different file formats
5
5
  Author: Tom Björkholm
6
6
  Author-email: Tom Björkholm <klausuler_linnet0q@icloud.com>
@@ -13,12 +13,14 @@ Description-Content-Type: text/markdown
13
13
  License-File: LICENSE.txt
14
14
  Requires-Dist: pip>=26.0.1
15
15
  Requires-Dist: setuptools>=82.0.1
16
- Requires-Dist: build>=1.4.0
16
+ Requires-Dist: build>=1.4.2
17
17
  Requires-Dist: wheel>=0.46.3
18
18
  Requires-Dist: mformat-ext>=0.6
19
19
  Requires-Dist: openpyxl>=3.1.5
20
- Requires-Dist: types-openpyxl>=3.1.5.20260322
21
- Requires-Dist: odfdo>=3.22.1
20
+ Requires-Dist: types-openpyxl>=3.1.5.20260402
21
+ Requires-Dist: odfdo>=3.22.4
22
+ Requires-Dist: xlsxwriter>=3.2.9
23
+ Requires-Dist: pylightxl>=1.61
22
24
  Dynamic: author
23
25
  Dynamic: license-file
24
26
  Dynamic: requires-dist
@@ -30,15 +32,15 @@ The tableio package contains a number of classes providing a uniform way for
30
32
  a python program to write table data (rows of columns) to and read table data
31
33
  from a number of different common file formats.
32
34
 
33
- An increasing number of users want output from programs to de in a format
35
+ An increasing number of users want output from programs to be in a format
34
36
  like a spreadsheet, and not the old fashoned raw text files. Similarly,
35
37
  many users want the data they feed into programs to be in a particular format
36
- (like a spreadsheet). The tableio packade tries to make it easier for the
38
+ (like a spreadsheet). The tableio package tries to make it easier for the
37
39
  programmer to fullfil requests like that.
38
40
 
39
- The primary intended use is for text output from a python program, where the
40
- programmer would like the user to be able to select the input and output file
41
- formats.
41
+ The primary intended use is for data table output from a python program
42
+ and data table input to a python program, where the programmer would like
43
+ the user to be able to select the input and output file formats.
42
44
 
43
45
  The support for spreadsheets is for reading and writing data. There is no
44
46
  intention to support reading or writing formulas. There is no support for
@@ -68,6 +70,8 @@ The currently supported formats are:
68
70
  |-------------|----------------|-----------|----------|
69
71
  | CSV | csv | yes | yes |
70
72
  | Excel | OpenPyXL | yes | yes |
73
+ | Excel | XlsxWriter | yes | - |
74
+ | Excel | pylightxl | yes | yes |
71
75
  | ODS | odfdo | yes | yes |
72
76
  | HTML | mformat | yes | - |
73
77
  | LaTeX | mformat | yes | - |
@@ -109,6 +113,8 @@ The main features are:
109
113
  - writing a table to a specific location in a spreadsheet (specified by a box)
110
114
  - reading table data from a specific location in a spreadsheet (specified by a box)
111
115
  - using multiple sheets in spreadsheets
116
+ - finding location where some data is present in spreadsheet and doing modifications
117
+ at that position or at positions relative to that position.
112
118
 
113
119
  ## Example programs
114
120
 
@@ -118,8 +124,6 @@ example programs:
118
124
 
119
125
  ## API documentation
120
126
 
121
- Be aware that this is still in early development. The APIs may change between versions.
122
-
123
127
  You can find the public API documentation at [https://bitbucket.org/tom-bjorkholm/table-io/src/master/doc/api.md](https://bitbucket.org/tom-bjorkholm/table-io/src/master/doc/api.md)
124
128
 
125
129
  You can find the protected API documentation at [https://bitbucket.org/tom-bjorkholm/table-io/src/master/doc/protected_api.md](https://bitbucket.org/tom-bjorkholm/table-io/src/master/doc/protected_api.md)
@@ -132,15 +136,17 @@ a better start by reading the examples.
132
136
 
133
137
  ## Version history
134
138
 
135
- | Version | Date | Python version | Comment |
136
- |---------|-------------|----------------|----------------------------|
137
- | 0.2 | 2026 Mar 28 | 3.12 or newer | More features, API changes |
138
- | 0.1 | 2026 Mar 23 | 3.12 or newer | First released version |
139
+ | Version | Date | Python version | Comment |
140
+ |---------|-------------|----------------|-----------------------------|
141
+ | 0.4 | 2026 Apr 06 | 3.12 or newer | Fix .xlsx and .ods syntax |
142
+ | 0.3 | 2026 Apr 01 | 3.12 or newer | Improved API, more backends |
143
+ | 0.2 | 2026 Mar 28 | 3.12 or newer | More features, API changes |
144
+ | 0.1 | 2026 Mar 23 | 3.12 or newer | First released version |
139
145
 
140
146
  ## Test summary
141
147
 
142
- - Test result: 869 passed in 11s
148
+ - Test result: 1126 passed in 17s
143
149
  - No flake8 warnings.
144
150
  - No mypy errors found.
145
- - Built version(s): 0.2
151
+ - Built version(s): 0.4
146
152
  - Build and test using Python 3.14.3
@@ -93,8 +93,8 @@ information about the build system. This README can also be viewed at
93
93
 
94
94
  ## Test summary
95
95
 
96
- - Test result: 869 passed in 11s
96
+ - Test result: 1126 passed in 17s
97
97
  - No flake8 warnings.
98
98
  - No mypy errors found.
99
- - Built version(s): 0.2
99
+ - Built version(s): 0.4
100
100
  - Build and test using Python 3.14.3
@@ -4,15 +4,15 @@ The tableio package contains a number of classes providing a uniform way for
4
4
  a python program to write table data (rows of columns) to and read table data
5
5
  from a number of different common file formats.
6
6
 
7
- An increasing number of users want output from programs to de in a format
7
+ An increasing number of users want output from programs to be in a format
8
8
  like a spreadsheet, and not the old fashoned raw text files. Similarly,
9
9
  many users want the data they feed into programs to be in a particular format
10
- (like a spreadsheet). The tableio packade tries to make it easier for the
10
+ (like a spreadsheet). The tableio package tries to make it easier for the
11
11
  programmer to fullfil requests like that.
12
12
 
13
- The primary intended use is for text output from a python program, where the
14
- programmer would like the user to be able to select the input and output file
15
- formats.
13
+ The primary intended use is for data table output from a python program
14
+ and data table input to a python program, where the programmer would like
15
+ the user to be able to select the input and output file formats.
16
16
 
17
17
  The support for spreadsheets is for reading and writing data. There is no
18
18
  intention to support reading or writing formulas. There is no support for
@@ -42,6 +42,8 @@ The currently supported formats are:
42
42
  |-------------|----------------|-----------|----------|
43
43
  | CSV | csv | yes | yes |
44
44
  | Excel | OpenPyXL | yes | yes |
45
+ | Excel | XlsxWriter | yes | - |
46
+ | Excel | pylightxl | yes | yes |
45
47
  | ODS | odfdo | yes | yes |
46
48
  | HTML | mformat | yes | - |
47
49
  | LaTeX | mformat | yes | - |
@@ -83,6 +85,8 @@ The main features are:
83
85
  - writing a table to a specific location in a spreadsheet (specified by a box)
84
86
  - reading table data from a specific location in a spreadsheet (specified by a box)
85
87
  - using multiple sheets in spreadsheets
88
+ - finding location where some data is present in spreadsheet and doing modifications
89
+ at that position or at positions relative to that position.
86
90
 
87
91
  ## Example programs
88
92
 
@@ -92,8 +96,6 @@ example programs:
92
96
 
93
97
  ## API documentation
94
98
 
95
- Be aware that this is still in early development. The APIs may change between versions.
96
-
97
99
  You can find the public API documentation at [https://bitbucket.org/tom-bjorkholm/table-io/src/master/doc/api.md](https://bitbucket.org/tom-bjorkholm/table-io/src/master/doc/api.md)
98
100
 
99
101
  You can find the protected API documentation at [https://bitbucket.org/tom-bjorkholm/table-io/src/master/doc/protected_api.md](https://bitbucket.org/tom-bjorkholm/table-io/src/master/doc/protected_api.md)
@@ -106,15 +108,17 @@ a better start by reading the examples.
106
108
 
107
109
  ## Version history
108
110
 
109
- | Version | Date | Python version | Comment |
110
- |---------|-------------|----------------|----------------------------|
111
- | 0.2 | 2026 Mar 28 | 3.12 or newer | More features, API changes |
112
- | 0.1 | 2026 Mar 23 | 3.12 or newer | First released version |
111
+ | Version | Date | Python version | Comment |
112
+ |---------|-------------|----------------|-----------------------------|
113
+ | 0.4 | 2026 Apr 06 | 3.12 or newer | Fix .xlsx and .ods syntax |
114
+ | 0.3 | 2026 Apr 01 | 3.12 or newer | Improved API, more backends |
115
+ | 0.2 | 2026 Mar 28 | 3.12 or newer | More features, API changes |
116
+ | 0.1 | 2026 Mar 23 | 3.12 or newer | First released version |
113
117
 
114
118
  ## Test summary
115
119
 
116
- - Test result: 869 passed in 11s
120
+ - Test result: 1126 passed in 17s
117
121
  - No flake8 warnings.
118
122
  - No mypy errors found.
119
- - Built version(s): 0.2
123
+ - Built version(s): 0.4
120
124
  - Build and test using Python 3.14.3
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "tableio"
7
- version = "0.2"
7
+ version = "0.4"
8
8
  authors = [
9
9
  { name="Tom Björkholm", email="klausuler_linnet0q@icloud.com" },
10
10
  ]
@@ -5,7 +5,7 @@ from setuptools import setup
5
5
 
6
6
  setup(
7
7
  name='tableio',
8
- version='0.2',
8
+ version='0.4',
9
9
  description='Uniform way to write table data to and read from different ' \
10
10
  'file formats',
11
11
  author='Tom Björkholm',
@@ -17,11 +17,13 @@ setup(
17
17
  install_requires=[ # pylint: disable=duplicate-code
18
18
  'pip >= 26.0.1',
19
19
  'setuptools >= 82.0.1',
20
- 'build >= 1.4.0',
20
+ 'build >= 1.4.2',
21
21
  'wheel >= 0.46.3',
22
22
  'mformat-ext >= 0.6',
23
23
  'openpyxl >= 3.1.5',
24
- 'types-openpyxl >= 3.1.5.20260322',
25
- 'odfdo >= 3.22.1'
24
+ 'types-openpyxl >= 3.1.5.20260402',
25
+ 'odfdo >= 3.22.4',
26
+ 'xlsxwriter >= 3.2.9',
27
+ 'pylightxl >= 1.61'
26
28
  ]
27
29
  )
@@ -0,0 +1,47 @@
1
+ #! /usr/local/bin/python3
2
+ """Curated top-level public API for the tableio package."""
3
+
4
+ # Copyright (c) 2026 Tom Björkholm
5
+ # MIT License
6
+ #
7
+
8
+ from tableio.capability import CAP_IGNORABLE, CAP_NEEDED, CAP_NOT_USED, \
9
+ Capabilities
10
+ from tableio.color import Color
11
+ from tableio.factory import create_tableio, filter_args_tableio, \
12
+ list_implementations_tableio, list_registered_tableio
13
+ from tableio.optional_args import CsvDialect, OptionalArgs, OptionalArgsDict
14
+ from tableio.tableio import Box, FileAccess, Position, TableIO
15
+ from tableio.value_type import CellT, DictData, DictDataMap, Fmt, \
16
+ FmtDictData, FmtDictRow, FmtListData, FmtListRow, ListData, \
17
+ ListDataSeq, ReadResult, Value, ValueFmt
18
+
19
+ __all__ = ['create_tableio',
20
+ 'TableIO',
21
+ 'FileAccess',
22
+ 'Box',
23
+ 'Position',
24
+ 'OptionalArgs',
25
+ 'OptionalArgsDict',
26
+ 'Value',
27
+ 'ListData',
28
+ 'ListDataSeq',
29
+ 'DictData',
30
+ 'DictDataMap',
31
+ 'ReadResult',
32
+ 'Fmt',
33
+ 'ValueFmt',
34
+ 'FmtListRow',
35
+ 'FmtDictRow',
36
+ 'FmtListData',
37
+ 'FmtDictData',
38
+ 'CellT',
39
+ 'Color',
40
+ 'Capabilities',
41
+ 'CAP_NEEDED',
42
+ 'CAP_NOT_USED',
43
+ 'CAP_IGNORABLE',
44
+ 'filter_args_tableio',
45
+ 'list_registered_tableio',
46
+ 'list_implementations_tableio',
47
+ 'CsvDialect']
@@ -0,0 +1,80 @@
1
+ #! /usr/bin/env python3
2
+ """Helpers for rewriting spreadsheet ZIP archives safely.
3
+
4
+ Spreadsheet writers first save library output to a temporary archive.
5
+ These helpers then build a rewritten copy in a second temporary archive
6
+ and replace the first archive only after both ZIP files are closed.
7
+ """
8
+
9
+ # Copyright (c) 2026 Tom Björkholm
10
+ # MIT License
11
+
12
+ from pathlib import Path
13
+ from tempfile import NamedTemporaryFile
14
+ from typing import Callable, Optional
15
+ from zipfile import ZIP_DEFLATED, ZipFile, ZipInfo
16
+
17
+
18
+ def temporary_output_path(source_path: Path, suffix: str) -> Path:
19
+ """Return one missing temporary path next to ``source_path``.
20
+
21
+ The temporary file is created in the same directory as
22
+ ``source_path`` so a later ``Path.replace()`` stays on the same
23
+ filesystem. The file name uses ``suffix`` and the returned path does
24
+ not exist when this function returns.
25
+ """
26
+ with NamedTemporaryFile(delete=False, dir=source_path.parent,
27
+ suffix=suffix) as temp_file:
28
+ temp_path = Path(temp_file.name)
29
+ temp_path.unlink()
30
+ return temp_path
31
+
32
+
33
+ def rewrite_zip_archive(
34
+ archive_path: Path,
35
+ rewrite_entry: Callable[[ZipInfo, bytes], Optional[bytes]],
36
+ extra_entries: Optional[dict[str, bytes]] = None) -> None:
37
+ """Rewrite one ZIP archive by copying it into a new archive.
38
+
39
+ The original archive at ``archive_path`` is read entry by entry and
40
+ a rewritten archive is written to a sibling temporary file. The
41
+ callback receives each original ``ZipInfo`` together with its bytes.
42
+ Returning ``None`` drops the entry. Any mapping passed in
43
+ ``extra_entries`` is appended after copied entries, except for names
44
+ that were already written.
45
+
46
+ The original archive is replaced only after both ZIP files have been
47
+ closed. This avoids replacing an archive while it is still open,
48
+ which is a safer pattern on Windows as well as on Unix-like systems.
49
+
50
+ Args:
51
+ archive_path: Path to the archive to rewrite in place.
52
+ rewrite_entry: Callback invoked once for each original ZIP entry.
53
+ The callback receives the original ``ZipInfo`` together with
54
+ the entry bytes. It returns replacement bytes for the output
55
+ archive, or ``None`` to drop the entry completely.
56
+ extra_entries: Optional mapping of extra archive members to add
57
+ after copying rewritten entries. Names that were already
58
+ written are left unchanged.
59
+ """
60
+ temp_path = temporary_output_path(archive_path, archive_path.suffix)
61
+ try:
62
+ with ZipFile(archive_path, 'r') as source_zip, \
63
+ ZipFile(temp_path, 'w',
64
+ compression=ZIP_DEFLATED) as target_zip:
65
+ written_names: set[str] = set()
66
+ for item in source_zip.infolist():
67
+ data = rewrite_entry(item, source_zip.read(item.filename))
68
+ if data is None:
69
+ continue
70
+ target_zip.writestr(item, data)
71
+ written_names.add(item.filename)
72
+ if extra_entries is not None:
73
+ for entry_name, entry_data in extra_entries.items():
74
+ if entry_name in written_names:
75
+ continue
76
+ target_zip.writestr(entry_name, entry_data)
77
+ temp_path.replace(archive_path)
78
+ finally:
79
+ if temp_path.exists():
80
+ temp_path.unlink()
@@ -87,6 +87,9 @@ class Capabilities(NamedTuple):
87
87
  multi_sheet: SingleCapability = SingleCapability()
88
88
  """The reader/writer class can read from or write to multiple sheets."""
89
89
 
90
+ can_find_value_position: SingleCapability = SingleCapability()
91
+ """The reader/writer class can find the position of a value."""
92
+
90
93
 
91
94
  def single_capability_match(offered: SingleCapability,
92
95
  will_use: SingleCapability,
@@ -233,3 +236,14 @@ CAP_UNSUPPORTED = SingleCapability(supported=False,
233
236
  different location would not make sense. Thus the only sensible thing
234
237
  to do is to raise an exception.
235
238
  """
239
+
240
+ CAP_ALL_IMPLEMENTED = Capabilities(can_read=CAP_IMPLEMENTED,
241
+ can_write=CAP_IMPLEMENTED,
242
+ can_fmt_row=CAP_IMPLEMENTED,
243
+ can_fmt_value=CAP_IMPLEMENTED,
244
+ filtered_data_range=CAP_IMPLEMENTED,
245
+ can_write_box=CAP_IMPLEMENTED,
246
+ can_read_box=CAP_IMPLEMENTED,
247
+ can_write_highlight=CAP_IMPLEMENTED,
248
+ multi_sheet=CAP_IMPLEMENTED,
249
+ can_find_value_position=CAP_IMPLEMENTED)
@@ -51,6 +51,37 @@ class TableIOFactoryNoCapabilityMatch(ValueError):
51
51
  """
52
52
 
53
53
 
54
+ class InsufficientCapabilities(ValueError):
55
+ """Raised when requested capabilities contradict requested file access.
56
+
57
+ Error raised when the caller supplies both file access and an explicit
58
+ Capabilities object, but the requested capabilities do not include the
59
+ capability implied by that access mode. For example, READ requires
60
+ can_read, CREATE requires can_write, and UPDATE requires both.
61
+ """
62
+
63
+
64
+ def _check_capabilities_for_file_access(
65
+ file_access: FileAccess,
66
+ capabilities: Optional[Capabilities]) -> None:
67
+ """Raise if explicit capabilities not enough for requested access mode."""
68
+ if capabilities is None:
69
+ return
70
+ if file_access == FileAccess.READ and not capabilities.can_read.supported:
71
+ msg = 'FileAccess.READ requires can_read capability.'
72
+ raise InsufficientCapabilities(msg)
73
+ if file_access == FileAccess.CREATE and \
74
+ not capabilities.can_write.supported:
75
+ msg = 'FileAccess.CREATE requires can_write capability.'
76
+ raise InsufficientCapabilities(msg)
77
+ if file_access == FileAccess.UPDATE and (
78
+ not capabilities.can_write.supported or
79
+ not capabilities.can_read.supported):
80
+ msg = 'FileAccess.UPDATE requires both can_read and '
81
+ msg += 'can_write capabilities.'
82
+ raise InsufficientCapabilities(msg)
83
+
84
+
54
85
  @total_ordering
55
86
  class ImplPrio(NamedTuple):
56
87
  """Priority of an implementation."""
@@ -243,6 +274,17 @@ class FactoryFormatInfo:
243
274
  raise TableIOFactoryNoCapabilityMatch(msg)
244
275
  return ret
245
276
 
277
+ def correct_implementation_name(self, implementation_name: str) -> str:
278
+ """Correct the implementation name to the correct case."""
279
+ if implementation_name in self._registry:
280
+ return implementation_name
281
+ if implementation_name.lower() in self._lower2correct:
282
+ return self._lower2correct[implementation_name.lower()]
283
+ raise TableIOFactoryNoSuchError(
284
+ f'Implementation "{implementation_name}" is not registered. ' +
285
+ 'Available implementations: ' +
286
+ f'{", ".join(list(self._registry.keys()))}')
287
+
246
288
 
247
289
  class TableIOFactory:
248
290
  """Factory class for creating instances of TableIO subclasses.
@@ -339,6 +381,7 @@ class TableIOFactory:
339
381
  An instance of the requested TableIO subclass.
340
382
  Intended to be used as context manager, using a with statement.
341
383
  Raises:
384
+ InsufficientCapabilities: If capabilities contradict file_access.
342
385
  TableIOFactoryNoSuchError: If the format_name is not registered
343
386
  or the implementation name is not
344
387
  registered.
@@ -357,7 +400,17 @@ class TableIOFactory:
357
400
  file_access: FileAccess, args: OptionalArgs = None,
358
401
  implementation: Optional[str] = None,
359
402
  capabilities: Optional[Capabilities] = None) -> TableIO:
360
- """Internally create an instance of a registered subclass."""
403
+ """Internally create an instance of a registered subclass.
404
+
405
+ Raises:
406
+ InsufficientCapabilities: If capabilities contradict file_access.
407
+ TableIOFactoryNoSuchError: If the format_name is not registered
408
+ or the implementation name is not
409
+ registered.
410
+ TableIOFactoryNoCapabilityMatch: If the capabilities cannot be
411
+ matched to any implementation.
412
+ """
413
+ _check_capabilities_for_file_access(file_access, capabilities)
361
414
  correct_name: Optional[str] = None
362
415
  if format_name in self._formats:
363
416
  correct_name = format_name
@@ -371,24 +424,19 @@ class TableIOFactory:
371
424
  )
372
425
  assert correct_name is not None
373
426
  format_info: FactoryFormatInfo = self._formats[correct_name]
374
- best_matches = format_info.best_match_names(capabilities=capabilities,
375
- empty_is_ok=False)
427
+ best_matches = format_info.best_match_names(
428
+ capabilities=capabilities, empty_is_ok=False)
376
429
  if implementation is not None:
377
- fikeys = list(format_info._registry.keys()) # pylint: disable=protected-access # noqa: E501
378
- if implementation not in fikeys:
379
- raise TableIOFactoryNoSuchError(
380
- f'Implementation "{implementation}" is not registered. ' +
381
- 'Available implementations: ' +
382
- f'{", ".join(list(fikeys))}'
383
- )
430
+ corrected_implementation = \
431
+ format_info.correct_implementation_name(implementation)
384
432
  bmatches_impls = [impl.implementation
385
433
  for impl in best_matches.combined()]
386
- if implementation not in bmatches_impls:
434
+ if corrected_implementation not in bmatches_impls:
387
435
  msg3 = f'Implementation "{implementation}" '
388
436
  msg3 += 'does not match the capabilities. Available matches: '
389
437
  msg3 += f'{", ".join(bmatches_impls)}'
390
438
  raise TableIOFactoryNoCapabilityMatch(msg3)
391
- chosen_impl = implementation
439
+ chosen_impl = corrected_implementation
392
440
  else:
393
441
  chosen_impl = best_matches.combined()[0].implementation
394
442
  format_class = format_info._registry[chosen_impl] # pylint: disable=protected-access # noqa: E501
@@ -666,6 +714,7 @@ def create_tableio(format_name: str, # pylint: disable=too-many-arguments, too-
666
714
  Returns:
667
715
  An instance of the requested TableIO subclass.
668
716
  Raises:
717
+ InsufficientCapabilities: If capabilities contradict file_access.
669
718
  TableIOFactoryNoSuchError: If the format_name or implementation
670
719
  name is not registered.
671
720
  TableIOFactoryNoCapabilityMatch: If the capabilities cannot be
@@ -16,6 +16,8 @@ from tableio.tableio_mformat import TableIOMformatHtml, TableIOMformatMd, \
16
16
  TableIOMformatRtf
17
17
  from tableio.tableio_csv import TableIOCsv
18
18
  from tableio.tableio_excel_openpyxl import TableIOExcelOpenPyXL
19
+ from tableio.tableio_excel_pylightxl import TableIOExcelPylightxl
20
+ from tableio.tableio_excel_xlsxwriter import TableIOExcelXlsxWriter
19
21
  from tableio.tableio_ods_odfdo import TableIOOdsOdfdo
20
22
  from tableio.tableio import TableIO
21
23
 
@@ -27,5 +29,8 @@ def register_formats_in_pkg() -> list[type[TableIO]]:
27
29
  TableIOMformatLatex, TableIOMformatDocx,
28
30
  TableIOMformatOdt, TableIOMformatPdf,
29
31
  TableIOMformatRtf, TableIOCsv,
30
- TableIOExcelOpenPyXL, TableIOOdsOdfdo]
32
+ TableIOExcelOpenPyXL,
33
+ TableIOExcelPylightxl,
34
+ TableIOExcelXlsxWriter,
35
+ TableIOOdsOdfdo]
31
36
  return ret