tableio 0.7__tar.gz → 0.8__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.7/tableio.egg-info → tableio-0.8}/PKG-INFO +4 -3
  2. {tableio-0.7 → tableio-0.8}/README.md +3 -2
  3. {tableio-0.7 → tableio-0.8}/README_pypi.md +3 -2
  4. {tableio-0.7 → tableio-0.8}/pyproject.toml +1 -1
  5. {tableio-0.7 → tableio-0.8}/setup.py +1 -1
  6. {tableio-0.7 → tableio-0.8}/src/tableio/__init__.py +23 -1
  7. tableio-0.8/src/tableio/access_capability.py +156 -0
  8. {tableio-0.7 → tableio-0.8}/src/tableio/border_helper.py +26 -50
  9. {tableio-0.7 → tableio-0.8}/src/tableio/capability.py +1 -2
  10. tableio-0.8/src/tableio/config_data.py +117 -0
  11. tableio-0.8/src/tableio/config_data_apply.py +403 -0
  12. tableio-0.8/src/tableio/config_data_describe.py +224 -0
  13. tableio-0.8/src/tableio/config_data_error.py +55 -0
  14. tableio-0.8/src/tableio/config_data_validate.py +334 -0
  15. {tableio-0.7 → tableio-0.8}/src/tableio/factory.py +57 -79
  16. {tableio-0.7 → tableio-0.8}/src/tableio/tableio.py +17 -32
  17. {tableio-0.7 → tableio-0.8}/src/tableio/tableio_csv.py +1 -2
  18. {tableio-0.7 → tableio-0.8}/src/tableio/tableio_excel_openpyxl.py +22 -35
  19. {tableio-0.7 → tableio-0.8}/src/tableio/tableio_excel_pylightxl.py +21 -33
  20. {tableio-0.7 → tableio-0.8}/src/tableio/tableio_excel_xlsxwriter.py +15 -27
  21. {tableio-0.7 → tableio-0.8}/src/tableio/tableio_excelbased.py +4 -6
  22. {tableio-0.7 → tableio-0.8}/src/tableio/tableio_mformat.py +49 -82
  23. {tableio-0.7 → tableio-0.8}/src/tableio/tableio_mformatbased.py +8 -14
  24. {tableio-0.7 → tableio-0.8}/src/tableio/tableio_ods_odfdo.py +15 -26
  25. {tableio-0.7 → tableio-0.8}/src/tableio/tableio_spreadsheetbased.py +28 -37
  26. {tableio-0.7 → tableio-0.8}/src/tableio/tableio_textbased.py +1 -2
  27. {tableio-0.7 → tableio-0.8}/src/tableio/value_type.py +6 -12
  28. {tableio-0.7 → tableio-0.8}/src/tableio/valueconversion.py +4 -8
  29. {tableio-0.7 → tableio-0.8/tableio.egg-info}/PKG-INFO +4 -3
  30. {tableio-0.7 → tableio-0.8}/tableio.egg-info/SOURCES.txt +6 -0
  31. {tableio-0.7 → tableio-0.8}/LICENSE.txt +0 -0
  32. {tableio-0.7 → tableio-0.8}/setup.cfg +0 -0
  33. {tableio-0.7 → tableio-0.8}/src/tableio/_archive_rewrite.py +0 -0
  34. {tableio-0.7 → tableio-0.8}/src/tableio/color.py +0 -0
  35. {tableio-0.7 → tableio-0.8}/src/tableio/optional_args.py +0 -0
  36. {tableio-0.7 → tableio-0.8}/src/tableio/py.typed +0 -0
  37. {tableio-0.7 → tableio-0.8}/src/tableio/reg_pkg_formats.py +0 -0
  38. {tableio-0.7 → tableio-0.8}/src/tableio/tableio_types.py +0 -0
  39. {tableio-0.7 → tableio-0.8}/tableio.egg-info/dependency_links.txt +0 -0
  40. {tableio-0.7 → tableio-0.8}/tableio.egg-info/requires.txt +0 -0
  41. {tableio-0.7 → tableio-0.8}/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.7
3
+ Version: 0.8
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,8 +137,9 @@ a better start by reading the examples.
137
137
 
138
138
  ## Test summary
139
139
 
140
- - Test result: 1186 passed in 18s
140
+ - Test result: 1311 passed in 19s
141
141
  - No flake8 warnings.
142
142
  - No mypy errors found.
143
- - Built version(s): 0.7
143
+ - No python layout warnings.
144
+ - Built version(s): 0.8
144
145
  - Build and test using Python 3.14.4
@@ -93,8 +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: 1186 passed in 18s
96
+ - Test result: 1311 passed in 19s
97
97
  - No flake8 warnings.
98
98
  - No mypy errors found.
99
- - Built version(s): 0.7
99
+ - No python layout warnings.
100
+ - Built version(s): 0.8
100
101
  - Build and test using Python 3.14.4
@@ -109,8 +109,9 @@ a better start by reading the examples.
109
109
 
110
110
  ## Test summary
111
111
 
112
- - Test result: 1186 passed in 18s
112
+ - Test result: 1311 passed in 19s
113
113
  - No flake8 warnings.
114
114
  - No mypy errors found.
115
- - Built version(s): 0.7
115
+ - No python layout warnings.
116
+ - Built version(s): 0.8
116
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.7"
7
+ version = "0.8"
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.7',
8
+ version='0.8',
9
9
  description='Uniform way to write table data to and read from different ' \
10
10
  'file formats',
11
11
  author='Tom Björkholm',
@@ -7,7 +7,18 @@
7
7
 
8
8
  from tableio.capability import CAP_IGNORABLE, CAP_NEEDED, CAP_NOT_USED, \
9
9
  Capabilities
10
+ from tableio.access_capability import NO_ERROR_OUTPUT, \
11
+ InsufficientCapabilities, access_capabilities, add_access_capabilities, \
12
+ check_access_capabilities
10
13
  from tableio.color import Color
14
+ from tableio.config_data import ConfigData, CsvConfigData, HtmlConfigData, \
15
+ LatexConfigData
16
+ from tableio.config_data_apply import tio_config_create, tio_config_default, \
17
+ tio_config_ignored_names, tio_config_optional_args, tio_config_trim
18
+ from tableio.config_data_describe import ConfigSpec, tio_config_describe, \
19
+ tio_config_descriptions, tio_config_specs
20
+ from tableio.config_data_error import ConfigError, ConfigIssue
21
+ from tableio.config_data_validate import tio_config_validate
11
22
  from tableio.factory import create_tableio, filter_args_tableio, \
12
23
  list_implementations_tableio, list_registered_tableio
13
24
  from tableio.optional_args import CsvDialect, OptionalArgs, OptionalArgsDict
@@ -40,10 +51,21 @@ __all__ = ['create_tableio',
40
51
  'CellT',
41
52
  'Color',
42
53
  'Capabilities',
54
+ 'NO_ERROR_OUTPUT',
55
+ 'InsufficientCapabilities',
43
56
  'CAP_NEEDED',
44
57
  'CAP_NOT_USED',
45
58
  'CAP_IGNORABLE',
59
+ 'access_capabilities',
60
+ 'add_access_capabilities',
61
+ 'check_access_capabilities',
46
62
  'filter_args_tableio',
47
63
  'list_registered_tableio',
48
64
  'list_implementations_tableio',
49
- 'CsvDialect']
65
+ 'CsvDialect',
66
+ 'ConfigData', 'ConfigError', 'ConfigIssue', 'ConfigSpec',
67
+ 'CsvConfigData', 'HtmlConfigData', 'LatexConfigData',
68
+ 'tio_config_create', 'tio_config_default',
69
+ 'tio_config_describe', 'tio_config_descriptions',
70
+ 'tio_config_ignored_names', 'tio_config_optional_args',
71
+ 'tio_config_specs', 'tio_config_trim', 'tio_config_validate']
@@ -0,0 +1,156 @@
1
+ #! /usr/bin/env python3
2
+ """Helpers that connect file access modes to capability requests."""
3
+
4
+ # Copyright (c) 2026 Tom Björkholm
5
+ # MIT License
6
+
7
+ import os
8
+ from typing import NoReturn, TextIO
9
+
10
+ from tableio.capability import CAP_NEEDED, Capabilities
11
+ from tableio.tableio_types import FileAccess
12
+
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."""
17
+
18
+
19
+ class InsufficientCapabilities(ValueError):
20
+ """Raised when requested capabilities contradict requested file access.
21
+
22
+ Error raised when the caller supplies file access and explicit
23
+ Capabilities, but the requested capabilities do not include the capability
24
+ implied by that access mode. For example, READ requires can_read, CREATE
25
+ requires can_write, and UPDATE requires both.
26
+ """
27
+
28
+ def __init__(self, message: str, capability_names: tuple[str, ...] =
29
+ ()) -> None:
30
+ """Initialize the exception."""
31
+ self.capability_names = capability_names
32
+ super().__init__(message)
33
+
34
+
35
+ def _raise_error(error_file: TextIO, error: Exception) -> NoReturn:
36
+ """Write an error message and raise the error."""
37
+ error_file.write(str(error) + '\n')
38
+ raise error
39
+
40
+
41
+ def _check_access_value(file_access: FileAccess, error_file: TextIO) -> None:
42
+ """Raise if file access is not a supported FileAccess value."""
43
+ if not isinstance(file_access, FileAccess):
44
+ error = TypeError('file_access must be a FileAccess value.')
45
+ _raise_error(error_file, error)
46
+ valid_access = (FileAccess.READ, FileAccess.CREATE, FileAccess.UPDATE)
47
+ if file_access not in valid_access:
48
+ error = ValueError(f'unsupported file access: {file_access!r}.')
49
+ _raise_error(error_file, error)
50
+
51
+
52
+ def _check_capabilities_value(capabilities: Capabilities,
53
+ error_file: TextIO) -> None:
54
+ """Raise if capabilities is not a Capabilities object."""
55
+ if not isinstance(capabilities, Capabilities):
56
+ error = TypeError('capabilities must be a Capabilities object.')
57
+ _raise_error(error_file, error)
58
+
59
+
60
+ def access_capabilities(file_access: FileAccess,
61
+ error_file: TextIO = NO_ERROR_OUTPUT) -> Capabilities:
62
+ """Return the capabilities implied by a file access mode.
63
+
64
+ Args:
65
+ file_access: File access mode to convert to capability requirements.
66
+ error_file: Text stream receiving error messages before exceptions.
67
+ Raises:
68
+ TypeError: If file_access is not a FileAccess value.
69
+ ValueError: If file_access is an unsupported FileAccess value.
70
+ Returns:
71
+ Capabilities needed for the requested file access.
72
+ """
73
+ _check_access_value(file_access, error_file)
74
+ if file_access == FileAccess.READ:
75
+ return Capabilities(can_read=CAP_NEEDED)
76
+ if file_access == FileAccess.CREATE:
77
+ return Capabilities(can_write=CAP_NEEDED)
78
+ return Capabilities(can_read=CAP_NEEDED, can_write=CAP_NEEDED)
79
+
80
+
81
+ def add_access_capabilities(file_access: FileAccess,
82
+ capabilities: Capabilities,
83
+ error_file: TextIO = NO_ERROR_OUTPUT) \
84
+ -> Capabilities:
85
+ """Return capabilities with file access requirements added.
86
+
87
+ The original capabilities object is not mutated.
88
+
89
+ Args:
90
+ file_access: File access mode to add capability requirements for.
91
+ capabilities: Existing capability requirements to extend.
92
+ error_file: Text stream receiving error messages before exceptions.
93
+ Raises:
94
+ TypeError: If file_access or capabilities has an invalid type.
95
+ ValueError: If file_access is an unsupported FileAccess value.
96
+ Returns:
97
+ New Capabilities object including the file access requirements.
98
+ """
99
+ _check_access_value(file_access, error_file)
100
+ _check_capabilities_value(capabilities, error_file)
101
+ if file_access == FileAccess.READ:
102
+ return capabilities._replace(can_read=CAP_NEEDED)
103
+ if file_access == FileAccess.CREATE:
104
+ return capabilities._replace(can_write=CAP_NEEDED)
105
+ return capabilities._replace(can_read=CAP_NEEDED, can_write=CAP_NEEDED)
106
+
107
+
108
+ def _missing_access_caps(file_access: FileAccess,
109
+ capabilities: Capabilities) -> tuple[str, ...]:
110
+ """Return capability names missing for the requested access mode."""
111
+ if file_access == FileAccess.READ and not capabilities.can_read.supported:
112
+ return ('can_read',)
113
+ if file_access == FileAccess.CREATE and \
114
+ not capabilities.can_write.supported:
115
+ return ('can_write',)
116
+ if file_access == FileAccess.UPDATE:
117
+ missing: list[str] = []
118
+ if not capabilities.can_read.supported:
119
+ missing.append('can_read')
120
+ if not capabilities.can_write.supported:
121
+ missing.append('can_write')
122
+ return tuple(missing)
123
+ return ()
124
+
125
+
126
+ def _access_error_message(file_access: FileAccess) -> str:
127
+ """Return the error message for missing access capabilities."""
128
+ if file_access == FileAccess.READ:
129
+ return 'FileAccess.READ requires can_read capability.'
130
+ if file_access == FileAccess.CREATE:
131
+ return 'FileAccess.CREATE requires can_write capability.'
132
+ return 'FileAccess.UPDATE requires both can_read and can_write ' + \
133
+ 'capabilities.'
134
+
135
+
136
+ def check_access_capabilities(file_access: FileAccess,
137
+ capabilities: Capabilities,
138
+ error_file: TextIO = NO_ERROR_OUTPUT) -> None:
139
+ """Raise if capabilities are not enough for requested access mode.
140
+
141
+ Args:
142
+ file_access: File access mode to check capability requirements for.
143
+ capabilities: Capability requirements to check.
144
+ error_file: Text stream receiving error messages before exceptions.
145
+ Raises:
146
+ TypeError: If file_access or capabilities has an invalid type.
147
+ ValueError: If file_access is an unsupported FileAccess value.
148
+ InsufficientCapabilities: If capabilities do not support file_access.
149
+ """
150
+ _check_access_value(file_access, error_file)
151
+ _check_capabilities_value(capabilities, error_file)
152
+ missing_caps = _missing_access_caps(file_access, capabilities)
153
+ if missing_caps:
154
+ message = _access_error_message(file_access)
155
+ error = InsufficientCapabilities(message, missing_caps)
156
+ _raise_error(error_file, error)
@@ -30,11 +30,8 @@ class CellBorder(NamedTuple):
30
30
  left: BorderWeight
31
31
 
32
32
 
33
- NO_BORDERS = CellBorder(
34
- BorderWeight.NONE,
35
- BorderWeight.NONE,
36
- BorderWeight.NONE,
37
- BorderWeight.NONE)
33
+ NO_BORDERS = CellBorder(BorderWeight.NONE, BorderWeight.NONE,
34
+ BorderWeight.NONE, BorderWeight.NONE)
38
35
  """The absence of borders on all four cell edges."""
39
36
 
40
37
 
@@ -68,61 +65,40 @@ def _thicker(first: BorderWeight, second: BorderWeight) -> BorderWeight:
68
65
 
69
66
  _STYLE_COMPONENTS: dict[TableBorderStyle, _BorderComponents] = {
70
67
  TableBorderStyle.NONE: _BorderComponents(
71
- outer=BorderWeight.NONE,
72
- first_row_separator=BorderWeight.NONE,
73
- inner_horizontal=BorderWeight.NONE,
74
- inner_vertical=BorderWeight.NONE),
68
+ outer=BorderWeight.NONE, first_row_separator=BorderWeight.NONE,
69
+ inner_horizontal=BorderWeight.NONE, inner_vertical=BorderWeight.NONE),
75
70
  TableBorderStyle.OUTER_THIN: _BorderComponents(
76
- outer=BorderWeight.THIN,
77
- first_row_separator=BorderWeight.NONE,
78
- inner_horizontal=BorderWeight.NONE,
79
- inner_vertical=BorderWeight.NONE),
71
+ outer=BorderWeight.THIN, first_row_separator=BorderWeight.NONE,
72
+ inner_horizontal=BorderWeight.NONE, inner_vertical=BorderWeight.NONE),
80
73
  TableBorderStyle.OUTER_THICK: _BorderComponents(
81
- outer=BorderWeight.THICK,
82
- first_row_separator=BorderWeight.NONE,
83
- inner_horizontal=BorderWeight.NONE,
84
- inner_vertical=BorderWeight.NONE),
74
+ outer=BorderWeight.THICK, first_row_separator=BorderWeight.NONE,
75
+ inner_horizontal=BorderWeight.NONE, inner_vertical=BorderWeight.NONE),
85
76
  TableBorderStyle.OUTER_FIRST_ROW_THIN: _BorderComponents(
86
- outer=BorderWeight.THIN,
87
- first_row_separator=BorderWeight.THIN,
88
- inner_horizontal=BorderWeight.NONE,
89
- inner_vertical=BorderWeight.NONE),
77
+ outer=BorderWeight.THIN, first_row_separator=BorderWeight.THIN,
78
+ inner_horizontal=BorderWeight.NONE, inner_vertical=BorderWeight.NONE),
90
79
  TableBorderStyle.OUTER_FIRST_ROW_THICK: _BorderComponents(
91
- outer=BorderWeight.THICK,
92
- first_row_separator=BorderWeight.THICK,
93
- inner_horizontal=BorderWeight.NONE,
94
- inner_vertical=BorderWeight.NONE),
80
+ outer=BorderWeight.THICK, first_row_separator=BorderWeight.THICK,
81
+ inner_horizontal=BorderWeight.NONE, inner_vertical=BorderWeight.NONE),
95
82
  TableBorderStyle.OUTER_THICK_FIRST_ROW_THIN: _BorderComponents(
96
- outer=BorderWeight.THICK,
97
- first_row_separator=BorderWeight.THIN,
98
- inner_horizontal=BorderWeight.NONE,
99
- inner_vertical=BorderWeight.NONE),
83
+ outer=BorderWeight.THICK, first_row_separator=BorderWeight.THIN,
84
+ inner_horizontal=BorderWeight.NONE, inner_vertical=BorderWeight.NONE),
100
85
  TableBorderStyle.OUTER_FIRST_ROW_THICK_VERTICAL_THIN:
101
- _BorderComponents(
102
- outer=BorderWeight.THICK,
103
- first_row_separator=BorderWeight.THICK,
104
- inner_horizontal=BorderWeight.NONE,
105
- inner_vertical=BorderWeight.THIN),
86
+ _BorderComponents(outer=BorderWeight.THICK,
87
+ first_row_separator=BorderWeight.THICK,
88
+ inner_horizontal=BorderWeight.NONE,
89
+ inner_vertical=BorderWeight.THIN),
106
90
  TableBorderStyle.OUTER_FIRST_ROW_THICK_INNER_THIN: _BorderComponents(
107
- outer=BorderWeight.THICK,
108
- first_row_separator=BorderWeight.THICK,
109
- inner_horizontal=BorderWeight.THIN,
110
- inner_vertical=BorderWeight.THIN),
91
+ outer=BorderWeight.THICK, first_row_separator=BorderWeight.THICK,
92
+ inner_horizontal=BorderWeight.THIN, inner_vertical=BorderWeight.THIN),
111
93
  TableBorderStyle.OUTER_THICK_INNER_THIN: _BorderComponents(
112
- outer=BorderWeight.THICK,
113
- first_row_separator=BorderWeight.NONE,
114
- inner_horizontal=BorderWeight.THIN,
115
- inner_vertical=BorderWeight.THIN),
94
+ outer=BorderWeight.THICK, first_row_separator=BorderWeight.NONE,
95
+ inner_horizontal=BorderWeight.THIN, inner_vertical=BorderWeight.THIN),
116
96
  TableBorderStyle.ALL_THIN: _BorderComponents(
117
- outer=BorderWeight.THIN,
118
- first_row_separator=BorderWeight.NONE,
119
- inner_horizontal=BorderWeight.THIN,
120
- inner_vertical=BorderWeight.THIN),
97
+ outer=BorderWeight.THIN, first_row_separator=BorderWeight.NONE,
98
+ inner_horizontal=BorderWeight.THIN, inner_vertical=BorderWeight.THIN),
121
99
  TableBorderStyle.ALL_THICK: _BorderComponents(
122
- outer=BorderWeight.THICK,
123
- first_row_separator=BorderWeight.NONE,
124
- inner_horizontal=BorderWeight.THICK,
125
- inner_vertical=BorderWeight.THICK)
100
+ outer=BorderWeight.THICK, first_row_separator=BorderWeight.NONE,
101
+ inner_horizontal=BorderWeight.THICK, inner_vertical=BorderWeight.THICK)
126
102
  }
127
103
 
128
104
 
@@ -125,8 +125,7 @@ def single_capability_match(offered: SingleCapability,
125
125
  return False
126
126
 
127
127
 
128
- def capability_match(offered: Capabilities,
129
- will_use: Capabilities,
128
+ def capability_match(offered: Capabilities, will_use: Capabilities,
130
129
  ignore_allowed: bool = False) -> bool:
131
130
  """Check if the offered capabilities match the required capabilities.
132
131
 
@@ -0,0 +1,117 @@
1
+ #! /usr/local/bin/python3
2
+ """Configuration data for the tableio package."""
3
+
4
+ # Copyright (c) 2026 Tom Björkholm
5
+ # MIT License
6
+
7
+ from dataclasses import dataclass
8
+ from typing import Optional
9
+ from tableio.optional_args import CsvDialect
10
+
11
+
12
+ @dataclass
13
+ class CsvConfigData:
14
+ """CSV-specific configuration values.
15
+
16
+ This class holds durable user choices that only have meaning for CSV
17
+ output. The values are allowed to be present even when another format is
18
+ selected; helper functions decide whether they are relevant for the
19
+ current TableIO backend. The class has no configuration-framework base
20
+ class, so adapter libraries may combine it with their own base classes.
21
+ """
22
+
23
+ dialect: Optional[CsvDialect] = None
24
+ """The CSV dialect template to use, or ``None`` for backend default."""
25
+
26
+ delimiter: Optional[str] = None
27
+ """The CSV delimiter to use, or ``None`` for backend default."""
28
+
29
+ quoting: Optional[str] = None
30
+ """The CSV quoting style to use, or ``None`` for backend default."""
31
+
32
+ quotechar: Optional[str] = None
33
+ """The CSV quote character to use, or ``None`` for backend default."""
34
+
35
+ lineterminator: Optional[str] = None
36
+ """The CSV line terminator to use, or ``None`` for backend default."""
37
+
38
+ escapechar: Optional[str] = None
39
+ """The CSV escape character to use, or ``None`` for backend default."""
40
+
41
+
42
+ @dataclass
43
+ class HtmlConfigData:
44
+ """HTML-specific configuration values.
45
+
46
+ The class has no configuration-framework base class, so adapter
47
+ libraries may combine it with their own base classes.
48
+ """
49
+
50
+ css_file: Optional[str] = None
51
+ """The CSS file path or URL to reference, or ``None`` for no CSS file."""
52
+
53
+
54
+ @dataclass
55
+ class LatexConfigData:
56
+ """LaTeX-specific configuration values.
57
+
58
+ The class has no configuration-framework base class, so adapter
59
+ libraries may combine it with their own base classes.
60
+ """
61
+
62
+ document_class: Optional[str] = None
63
+ """The LaTeX document class to use, or ``None`` for backend default."""
64
+
65
+ preamble: Optional[str] = None
66
+ """Extra LaTeX preamble text, or ``None`` for backend default."""
67
+
68
+
69
+ @dataclass
70
+ class ConfigData: # pylint: disable=too-many-instance-attributes
71
+ """Durable, framework-neutral TableIO configuration choices.
72
+
73
+ This class intentionally excludes runtime intent. File names, file access,
74
+ capabilities and callbacks are supplied to helper functions instead of
75
+ being stored as configuration values. The default format is Excel, and
76
+ format-specific nested sections default to ``None`` until a user or
77
+ application deliberately configures them.
78
+
79
+ The class has no configuration-framework base class, so adapter libraries
80
+ may combine it with their own base classes.
81
+ """
82
+
83
+ format_name: str = 'excel'
84
+ """The TableIO format name. Matching is case-insensitive."""
85
+
86
+ implementation: Optional[str] = None
87
+ """The optional implementation pin, or ``None`` to choose best match."""
88
+
89
+ character_encoding: Optional[str] = None
90
+ """The text encoding to use, or ``None`` for backend default."""
91
+
92
+ language: Optional[str] = None
93
+ """The document language value mapped to backend ``lang`` arguments."""
94
+
95
+ title: Optional[str] = None
96
+ """The document title, or ``None`` for backend default."""
97
+
98
+ paper_size: Optional[str] = None
99
+ """The document paper size, or ``None`` for backend default."""
100
+
101
+ line_length: Optional[int] = None
102
+ """The preferred text line length, or ``None`` for backend default."""
103
+
104
+ table_max_line_length: Optional[int] = None
105
+ """The preferred text table line length, or ``None`` for default."""
106
+
107
+ table_alignment: Optional[str] = None
108
+ """The preferred text table alignment, or ``None`` for default."""
109
+
110
+ csv: Optional[CsvConfigData] = None
111
+ """CSV-specific configuration values, or ``None`` when unset."""
112
+
113
+ html: Optional[HtmlConfigData] = None
114
+ """HTML-specific configuration values, or ``None`` when unset."""
115
+
116
+ latex: Optional[LatexConfigData] = None
117
+ """LaTeX-specific configuration values, or ``None`` when unset."""