tableio 0.8__tar.gz → 0.9__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 (41) hide show
  1. {tableio-0.8/tableio.egg-info → tableio-0.9}/PKG-INFO +3 -3
  2. {tableio-0.8 → tableio-0.9}/README.md +2 -2
  3. {tableio-0.8 → tableio-0.9}/README_pypi.md +2 -2
  4. {tableio-0.8 → tableio-0.9}/pyproject.toml +1 -1
  5. {tableio-0.8 → tableio-0.9}/setup.py +1 -1
  6. {tableio-0.8 → tableio-0.9}/src/tableio/access_capability.py +23 -10
  7. {tableio-0.8 → tableio-0.9}/src/tableio/config_data_apply.py +52 -12
  8. {tableio-0.8 → tableio-0.9/tableio.egg-info}/PKG-INFO +3 -3
  9. {tableio-0.8 → tableio-0.9}/LICENSE.txt +0 -0
  10. {tableio-0.8 → tableio-0.9}/setup.cfg +0 -0
  11. {tableio-0.8 → tableio-0.9}/src/tableio/__init__.py +0 -0
  12. {tableio-0.8 → tableio-0.9}/src/tableio/_archive_rewrite.py +0 -0
  13. {tableio-0.8 → tableio-0.9}/src/tableio/border_helper.py +0 -0
  14. {tableio-0.8 → tableio-0.9}/src/tableio/capability.py +0 -0
  15. {tableio-0.8 → tableio-0.9}/src/tableio/color.py +0 -0
  16. {tableio-0.8 → tableio-0.9}/src/tableio/config_data.py +0 -0
  17. {tableio-0.8 → tableio-0.9}/src/tableio/config_data_describe.py +0 -0
  18. {tableio-0.8 → tableio-0.9}/src/tableio/config_data_error.py +0 -0
  19. {tableio-0.8 → tableio-0.9}/src/tableio/config_data_validate.py +0 -0
  20. {tableio-0.8 → tableio-0.9}/src/tableio/factory.py +0 -0
  21. {tableio-0.8 → tableio-0.9}/src/tableio/optional_args.py +0 -0
  22. {tableio-0.8 → tableio-0.9}/src/tableio/py.typed +0 -0
  23. {tableio-0.8 → tableio-0.9}/src/tableio/reg_pkg_formats.py +0 -0
  24. {tableio-0.8 → tableio-0.9}/src/tableio/tableio.py +0 -0
  25. {tableio-0.8 → tableio-0.9}/src/tableio/tableio_csv.py +0 -0
  26. {tableio-0.8 → tableio-0.9}/src/tableio/tableio_excel_openpyxl.py +0 -0
  27. {tableio-0.8 → tableio-0.9}/src/tableio/tableio_excel_pylightxl.py +0 -0
  28. {tableio-0.8 → tableio-0.9}/src/tableio/tableio_excel_xlsxwriter.py +0 -0
  29. {tableio-0.8 → tableio-0.9}/src/tableio/tableio_excelbased.py +0 -0
  30. {tableio-0.8 → tableio-0.9}/src/tableio/tableio_mformat.py +0 -0
  31. {tableio-0.8 → tableio-0.9}/src/tableio/tableio_mformatbased.py +0 -0
  32. {tableio-0.8 → tableio-0.9}/src/tableio/tableio_ods_odfdo.py +0 -0
  33. {tableio-0.8 → tableio-0.9}/src/tableio/tableio_spreadsheetbased.py +0 -0
  34. {tableio-0.8 → tableio-0.9}/src/tableio/tableio_textbased.py +0 -0
  35. {tableio-0.8 → tableio-0.9}/src/tableio/tableio_types.py +0 -0
  36. {tableio-0.8 → tableio-0.9}/src/tableio/value_type.py +0 -0
  37. {tableio-0.8 → tableio-0.9}/src/tableio/valueconversion.py +0 -0
  38. {tableio-0.8 → tableio-0.9}/tableio.egg-info/SOURCES.txt +0 -0
  39. {tableio-0.8 → tableio-0.9}/tableio.egg-info/dependency_links.txt +0 -0
  40. {tableio-0.8 → tableio-0.9}/tableio.egg-info/requires.txt +0 -0
  41. {tableio-0.8 → tableio-0.9}/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.8
3
+ Version: 0.9
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>
@@ -137,9 +137,9 @@ a better start by reading the examples.
137
137
 
138
138
  ## Test summary
139
139
 
140
- - Test result: 1311 passed in 19s
140
+ - Test result: 1344 passed in 20s
141
141
  - No flake8 warnings.
142
142
  - No mypy errors found.
143
143
  - No python layout warnings.
144
- - Built version(s): 0.8
144
+ - Built version(s): 0.9
145
145
  - Build and test using Python 3.14.4
@@ -93,9 +93,9 @@ information about the build system. This README can also be viewed at
93
93
 
94
94
  ## Test summary
95
95
 
96
- - Test result: 1311 passed in 19s
96
+ - Test result: 1344 passed in 20s
97
97
  - No flake8 warnings.
98
98
  - No mypy errors found.
99
99
  - No python layout warnings.
100
- - Built version(s): 0.8
100
+ - Built version(s): 0.9
101
101
  - Build and test using Python 3.14.4
@@ -109,9 +109,9 @@ a better start by reading the examples.
109
109
 
110
110
  ## Test summary
111
111
 
112
- - Test result: 1311 passed in 19s
112
+ - Test result: 1344 passed in 20s
113
113
  - No flake8 warnings.
114
114
  - No mypy errors found.
115
115
  - No python layout warnings.
116
- - Built version(s): 0.8
116
+ - Built version(s): 0.9
117
117
  - Build and test using Python 3.14.4
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "tableio"
7
- version = "0.8"
7
+ version = "0.9"
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.8',
8
+ version='0.9',
9
9
  description='Uniform way to write table data to and read from different ' \
10
10
  'file formats',
11
11
  author='Tom Björkholm',
@@ -4,16 +4,22 @@
4
4
  # Copyright (c) 2026 Tom Björkholm
5
5
  # MIT License
6
6
 
7
- import os
7
+ from enum import Enum, auto
8
8
  from typing import NoReturn, TextIO
9
9
 
10
10
  from tableio.capability import CAP_NEEDED, Capabilities
11
11
  from tableio.tableio_types import FileAccess
12
12
 
13
13
 
14
- # pylint: disable-next=consider-using-with
15
- NO_ERROR_OUTPUT: TextIO = open(os.devnull, 'w', encoding='utf-8')
16
- """Text stream used when helper errors should not be printed."""
14
+ class NoErrorOutput(Enum):
15
+ """Text stream marker when helper errors should not be printed."""
16
+
17
+ NO_OUTPUT = auto()
18
+ """Text stream marker when helper errors should not be printed."""
19
+
20
+
21
+ NO_ERROR_OUTPUT = NoErrorOutput.NO_OUTPUT
22
+ """Text stream marker used when helper errors should not be printed."""
17
23
 
18
24
 
19
25
  class InsufficientCapabilities(ValueError):
@@ -32,13 +38,17 @@ class InsufficientCapabilities(ValueError):
32
38
  super().__init__(message)
33
39
 
34
40
 
35
- def _raise_error(error_file: TextIO, error: Exception) -> NoReturn:
41
+ def _raise_error(error_file: TextIO | NoErrorOutput,
42
+ error: Exception) -> NoReturn:
36
43
  """Write an error message and raise the error."""
44
+ if isinstance(error_file, NoErrorOutput):
45
+ raise error
37
46
  error_file.write(str(error) + '\n')
38
47
  raise error
39
48
 
40
49
 
41
- def _check_access_value(file_access: FileAccess, error_file: TextIO) -> None:
50
+ def _check_access_value(file_access: FileAccess,
51
+ error_file: TextIO | NoErrorOutput) -> None:
42
52
  """Raise if file access is not a supported FileAccess value."""
43
53
  if not isinstance(file_access, FileAccess):
44
54
  error = TypeError('file_access must be a FileAccess value.')
@@ -50,7 +60,7 @@ def _check_access_value(file_access: FileAccess, error_file: TextIO) -> None:
50
60
 
51
61
 
52
62
  def _check_capabilities_value(capabilities: Capabilities,
53
- error_file: TextIO) -> None:
63
+ error_file: TextIO | NoErrorOutput) -> None:
54
64
  """Raise if capabilities is not a Capabilities object."""
55
65
  if not isinstance(capabilities, Capabilities):
56
66
  error = TypeError('capabilities must be a Capabilities object.')
@@ -58,7 +68,8 @@ def _check_capabilities_value(capabilities: Capabilities,
58
68
 
59
69
 
60
70
  def access_capabilities(file_access: FileAccess,
61
- error_file: TextIO = NO_ERROR_OUTPUT) -> Capabilities:
71
+ error_file: TextIO | NoErrorOutput =
72
+ NO_ERROR_OUTPUT) -> Capabilities:
62
73
  """Return the capabilities implied by a file access mode.
63
74
 
64
75
  Args:
@@ -80,7 +91,8 @@ def access_capabilities(file_access: FileAccess,
80
91
 
81
92
  def add_access_capabilities(file_access: FileAccess,
82
93
  capabilities: Capabilities,
83
- error_file: TextIO = NO_ERROR_OUTPUT) \
94
+ error_file: TextIO | NoErrorOutput =
95
+ NO_ERROR_OUTPUT) \
84
96
  -> Capabilities:
85
97
  """Return capabilities with file access requirements added.
86
98
 
@@ -135,7 +147,8 @@ def _access_error_message(file_access: FileAccess) -> str:
135
147
 
136
148
  def check_access_capabilities(file_access: FileAccess,
137
149
  capabilities: Capabilities,
138
- error_file: TextIO = NO_ERROR_OUTPUT) -> None:
150
+ error_file: TextIO | NoErrorOutput =
151
+ NO_ERROR_OUTPUT) -> None:
139
152
  """Raise if capabilities are not enough for requested access mode.
140
153
 
141
154
  Args:
@@ -4,7 +4,7 @@
4
4
  # Copyright (c) 2026 Tom Björkholm
5
5
  # MIT License
6
6
 
7
- from typing import Callable, Optional, TypeVar, cast
7
+ from typing import Callable, NoReturn, Optional, TypeVar, cast
8
8
 
9
9
  from mformat.mformat import PathLike
10
10
  from tableio.access_capability import add_access_capabilities
@@ -24,15 +24,14 @@ _FORMAT_PRIORITY = ('excel', 'ods', 'csv')
24
24
  _ValueT = TypeVar('_ValueT')
25
25
 
26
26
 
27
- def _config_error(name: str, message: str) -> None:
27
+ def _config_error(name: str, message: str) -> NoReturn:
28
28
  """Raise one structured configuration error."""
29
29
  raise ConfigError((ConfigIssue(name, message),))
30
30
 
31
31
 
32
32
  def _check_default_input(capabilities: Capabilities, file_access: FileAccess,
33
33
  format_name: Optional[str],
34
- implementation: Optional[str],
35
- include_all_options: bool) -> None:
34
+ implementation: Optional[str]) -> None:
36
35
  """Validate runtime values used for default selection."""
37
36
  if not isinstance(capabilities, Capabilities):
38
37
  _config_error('capabilities', 'must be a Capabilities object.')
@@ -42,8 +41,15 @@ def _check_default_input(capabilities: Capabilities, file_access: FileAccess,
42
41
  _config_error('format_name', 'must be a string or None.')
43
42
  if implementation is not None and not isinstance(implementation, str):
44
43
  _config_error('implementation', 'must be a string or None.')
44
+
45
+
46
+ def _check_default_flags(include_all_options: bool,
47
+ impl_in_cfg: Optional[bool]) -> None:
48
+ """Validate flags used for default selection."""
45
49
  if not isinstance(include_all_options, bool):
46
50
  _config_error('include_all_options', 'must be a bool.')
51
+ if impl_in_cfg is not None and not isinstance(impl_in_cfg, bool):
52
+ _config_error('impl_in_cfg', 'must be a bool or None.')
47
53
 
48
54
 
49
55
  def _registered_formats_by_lower() -> dict[str, str]:
@@ -103,7 +109,6 @@ def _best_default_names(capabilities: Capabilities, format_name: Optional[str],
103
109
  return selected_format, selected_impl
104
110
  name = 'implementation' if implementation is not None else 'format_name'
105
111
  _config_error(name, 'does not match registered TableIO backends.')
106
- raise AssertionError('Unreachable default selection failure.')
107
112
 
108
113
 
109
114
  def _base_arg_items(config: ConfigData) -> list[tuple[str, str, object]]:
@@ -184,7 +189,8 @@ def _filtered_args(config: ConfigData, capabilities: Optional[Capabilities],
184
189
  return filtered
185
190
 
186
191
 
187
- def _all_option_config(format_name: str, implementation: str) -> ConfigData:
192
+ def _all_option_config(format_name: str,
193
+ implementation: Optional[str]) -> ConfigData:
188
194
  """Return a configuration object with all options visible."""
189
195
  csv = CsvConfigData(dialect=CsvDialect.UNIX, delimiter=',', quoting='all',
190
196
  quotechar='"', lineterminator='\n', escapechar='\\')
@@ -198,10 +204,21 @@ def _all_option_config(format_name: str, implementation: str) -> ConfigData:
198
204
  html=html, latex=latex)
199
205
 
200
206
 
201
- def tio_config_default(capabilities: Capabilities, file_access: FileAccess,
207
+ def _include_default_impl(implementation: Optional[str],
208
+ include_all_options: bool,
209
+ impl_in_cfg: Optional[bool]) -> bool:
210
+ """Return true if the default config should pin implementation."""
211
+ if impl_in_cfg is not None:
212
+ return impl_in_cfg
213
+ return implementation is not None or include_all_options
214
+
215
+
216
+ # pylint: disable-next=too-many-arguments
217
+ def tio_config_default(capabilities: Capabilities, file_access: FileAccess, *,
202
218
  format_name: Optional[str] = None,
203
219
  implementation: Optional[str] = None,
204
- include_all_options: bool = False) -> ConfigData:
220
+ include_all_options: bool = False,
221
+ impl_in_cfg: Optional[bool] = None) -> ConfigData:
205
222
  """Return recommended default configuration data.
206
223
 
207
224
  Default format and implementation selection first prefers implementations
@@ -211,6 +228,17 @@ def tio_config_default(capabilities: Capabilities, file_access: FileAccess,
211
228
  If several implementations of the selected format match equally well,
212
229
  their TableIO implementation priority is used.
213
230
 
231
+ Usually it is better to not include the implementation name in the
232
+ configuration, as that allows the TableIO library to choose the best
233
+ implementation based on the capabilities and file access at runtime.
234
+ If you want to include the implementation name in the configuration,
235
+ you can set the impl_in_cfg parameter to True. If you set it to False,
236
+ the implementation name will always be omitted from the configuration.
237
+ If you set it to None, the implementation name will normally be omitted
238
+ from the configuration, but if include_all_options is True or if
239
+ implementation was explicitly provided, the implementation name will be
240
+ included.
241
+
214
242
  Args:
215
243
  capabilities: Runtime capabilities the application intends to use.
216
244
  file_access: Runtime file access requested by the application.
@@ -218,12 +246,21 @@ def tio_config_default(capabilities: Capabilities, file_access: FileAccess,
218
246
  implementation: Optional preferred implementation name.
219
247
  include_all_options: Include visible non-None values for all
220
248
  configuration options, for teaching and configuration templates.
249
+ impl_in_cfg: Optional flag to include the implementation name in the
250
+ configuration. If None, the implementation name will normally be
251
+ omitted from the configuration, but if include_all_options is True
252
+ or if implementation was explicitly provided, the implementation
253
+ name will be included. If True, the implementation name will be
254
+ included in the configuration. If False, the implementation name
255
+ will always be omitted from the configuration.
221
256
  Returns:
222
257
  A configuration object containing durable user choices only.
223
258
  """
224
259
  _check_default_input(capabilities, file_access, format_name,
225
- implementation, include_all_options)
260
+ implementation)
261
+ _check_default_flags(include_all_options, impl_in_cfg)
226
262
  match_caps = add_access_capabilities(file_access, capabilities)
263
+ selected_impl: Optional[str] = None
227
264
  selected_format, selected_impl = _best_default_names(match_caps,
228
265
  format_name,
229
266
  implementation)
@@ -231,6 +268,9 @@ def tio_config_default(capabilities: Capabilities, file_access: FileAccess,
231
268
  selected_format = format_name
232
269
  if implementation is not None:
233
270
  selected_impl = implementation
271
+ if not _include_default_impl(implementation, include_all_options,
272
+ impl_in_cfg):
273
+ selected_impl = None
234
274
  if include_all_options:
235
275
  config = _all_option_config(selected_format, selected_impl)
236
276
  else:
@@ -341,9 +381,9 @@ def tio_config_trim(config: ConfigData,
341
381
  filtered_names),
342
382
  line_length=_kept(config.line_length, 'line_length',
343
383
  filtered_names),
344
- table_max_line_length=_kept(
345
- config.table_max_line_length,
346
- 'table_max_line_length', filtered_names),
384
+ table_max_line_length=_kept(config.table_max_line_length,
385
+ 'table_max_line_length',
386
+ filtered_names),
347
387
  table_alignment=_kept(config.table_alignment,
348
388
  'table_alignment', filtered_names),
349
389
  csv=csv, html=html, latex=latex)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tableio
3
- Version: 0.8
3
+ Version: 0.9
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>
@@ -137,9 +137,9 @@ a better start by reading the examples.
137
137
 
138
138
  ## Test summary
139
139
 
140
- - Test result: 1311 passed in 19s
140
+ - Test result: 1344 passed in 20s
141
141
  - No flake8 warnings.
142
142
  - No mypy errors found.
143
143
  - No python layout warnings.
144
- - Built version(s): 0.8
144
+ - Built version(s): 0.9
145
145
  - Build and test using Python 3.14.4
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes