robotframework-tablelibrary 0.1.4__tar.gz → 0.2.1__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.
- {robotframework_tablelibrary-0.1.4 → robotframework_tablelibrary-0.2.1}/.pre-commit-config.yaml +13 -7
- {robotframework_tablelibrary-0.1.4 → robotframework_tablelibrary-0.2.1}/DEVELOPMENT.md +5 -0
- {robotframework_tablelibrary-0.1.4 → robotframework_tablelibrary-0.2.1}/PKG-INFO +2 -1
- {robotframework_tablelibrary-0.1.4 → robotframework_tablelibrary-0.2.1}/create_release.sh +6 -1
- {robotframework_tablelibrary-0.1.4 → robotframework_tablelibrary-0.2.1}/pyproject.toml +11 -9
- {robotframework_tablelibrary-0.1.4 → robotframework_tablelibrary-0.2.1}/src/Tables/__about__.py +1 -1
- {robotframework_tablelibrary-0.1.4 → robotframework_tablelibrary-0.2.1}/src/Tables/__init__.py +78 -8
- robotframework_tablelibrary-0.2.1/src/Tables/general/library_attributes.py +123 -0
- robotframework_tablelibrary-0.2.1/src/Tables/keywords/configuration.py +201 -0
- {robotframework_tablelibrary-0.1.4 → robotframework_tablelibrary-0.2.1}/src/Tables/keywords/excel.py +2 -6
- {robotframework_tablelibrary-0.1.4 → robotframework_tablelibrary-0.2.1}/src/Tables/keywords/getter.py +25 -27
- {robotframework_tablelibrary-0.1.4 → robotframework_tablelibrary-0.2.1}/src/Tables/keywords/modifier.py +33 -13
- {robotframework_tablelibrary-0.1.4 → robotframework_tablelibrary-0.2.1}/src/Tables/keywords/writer.py +8 -10
- {robotframework_tablelibrary-0.1.4 → robotframework_tablelibrary-0.2.1}/src/Tables/utils/file_reader.py +32 -32
- {robotframework_tablelibrary-0.1.4 → robotframework_tablelibrary-0.2.1}/src/Tables/utils/file_writer.py +63 -52
- robotframework_tablelibrary-0.2.1/src/Tables/utils/settings_stack.py +96 -0
- robotframework_tablelibrary-0.2.1/tests/__init__.py +2 -0
- robotframework_tablelibrary-0.2.1/tests/atest/__init__.robot +17 -0
- robotframework_tablelibrary-0.2.1/tests/atest/test_settings_scopes.robot +60 -0
- {robotframework_tablelibrary-0.1.4 → robotframework_tablelibrary-0.2.1}/tests/atest/test_writer.robot +224 -0
- robotframework_tablelibrary-0.2.1/tests/atest/testdata/example_09_streaming.csv +3 -0
- robotframework_tablelibrary-0.2.1/tests/utest/__init__.py +2 -0
- robotframework_tablelibrary-0.2.1/tests/utest/helper/__init__.py +1 -0
- robotframework_tablelibrary-0.2.1/tests/utest/helper/helpers.py +40 -0
- robotframework_tablelibrary-0.2.1/tests/utest/keywords/__init__.py +1 -0
- robotframework_tablelibrary-0.2.1/tests/utest/keywords/conftest.py +31 -0
- robotframework_tablelibrary-0.2.1/tests/utest/keywords/test_keywords_configuration.py +51 -0
- robotframework_tablelibrary-0.2.1/tests/utest/keywords/test_keywords_excel.py +142 -0
- robotframework_tablelibrary-0.2.1/tests/utest/keywords/test_keywords_getter.py +262 -0
- robotframework_tablelibrary-0.2.1/tests/utest/keywords/test_keywords_init.py +7 -0
- robotframework_tablelibrary-0.2.1/tests/utest/keywords/test_keywords_modifier.py +49 -0
- robotframework_tablelibrary-0.2.1/tests/utest/keywords/test_keywords_writer.py +59 -0
- {robotframework_tablelibrary-0.1.4 → robotframework_tablelibrary-0.2.1}/tests/utest/test_configuration.py +1 -3
- {robotframework_tablelibrary-0.1.4 → robotframework_tablelibrary-0.2.1}/tests/utest/test_getter.py +1 -7
- robotframework_tablelibrary-0.2.1/tests/utest/test_tables_init.py +40 -0
- robotframework_tablelibrary-0.2.1/tests/utest/test_utils_file_access.py +8 -0
- robotframework_tablelibrary-0.2.1/tests/utest/test_utils_file_reader.py +333 -0
- robotframework_tablelibrary-0.2.1/tests/utest/test_utils_file_system.py +25 -0
- robotframework_tablelibrary-0.2.1/tests/utest/test_utils_file_writer.py +224 -0
- robotframework_tablelibrary-0.2.1/tests/utest/test_utils_init.py +6 -0
- robotframework_tablelibrary-0.2.1/tests/utest/test_utils_settings.py +23 -0
- robotframework_tablelibrary-0.2.1/tests/utest/test_utils_settings_stack.py +119 -0
- robotframework_tablelibrary-0.1.4/src/Tables/general/library_attributes.py +0 -68
- robotframework_tablelibrary-0.1.4/src/Tables/keywords/configuration.py +0 -119
- robotframework_tablelibrary-0.1.4/tests/__init__.py +0 -3
- {robotframework_tablelibrary-0.1.4 → robotframework_tablelibrary-0.2.1}/.github/workflows/build.yml +0 -0
- {robotframework_tablelibrary-0.1.4 → robotframework_tablelibrary-0.2.1}/.github/workflows/release.yml +0 -0
- {robotframework_tablelibrary-0.1.4 → robotframework_tablelibrary-0.2.1}/.gitignore +0 -0
- {robotframework_tablelibrary-0.1.4 → robotframework_tablelibrary-0.2.1}/LICENSE +0 -0
- {robotframework_tablelibrary-0.1.4 → robotframework_tablelibrary-0.2.1}/README.md +0 -0
- {robotframework_tablelibrary-0.1.4 → robotframework_tablelibrary-0.2.1}/src/Tables/general/__init__.py +0 -0
- {robotframework_tablelibrary-0.1.4 → robotframework_tablelibrary-0.2.1}/src/Tables/keywords/__init__.py +0 -0
- {robotframework_tablelibrary-0.1.4 → robotframework_tablelibrary-0.2.1}/src/Tables/utils/__init__.py +0 -0
- {robotframework_tablelibrary-0.1.4 → robotframework_tablelibrary-0.2.1}/src/Tables/utils/file_access.py +0 -0
- {robotframework_tablelibrary-0.1.4 → robotframework_tablelibrary-0.2.1}/src/Tables/utils/file_system.py +0 -0
- {robotframework_tablelibrary-0.1.4 → robotframework_tablelibrary-0.2.1}/src/Tables/utils/settings.py +0 -0
- {robotframework_tablelibrary-0.1.4 → robotframework_tablelibrary-0.2.1}/tests/atest/test_excel.robot +0 -0
- {robotframework_tablelibrary-0.1.4 → robotframework_tablelibrary-0.2.1}/tests/atest/test_reader.robot +0 -0
- {robotframework_tablelibrary-0.1.4 → robotframework_tablelibrary-0.2.1}/tests/atest/test_settings.robot +0 -0
- {robotframework_tablelibrary-0.1.4 → robotframework_tablelibrary-0.2.1}/tests/atest/testdata/example_01.csv +0 -0
- {robotframework_tablelibrary-0.1.4 → robotframework_tablelibrary-0.2.1}/tests/atest/testdata/example_01.txt +0 -0
- {robotframework_tablelibrary-0.1.4 → robotframework_tablelibrary-0.2.1}/tests/atest/testdata/example_02.xlsx +0 -0
- {robotframework_tablelibrary-0.1.4 → robotframework_tablelibrary-0.2.1}/tests/atest/testdata/example_03.parquet +0 -0
- {robotframework_tablelibrary-0.1.4 → robotframework_tablelibrary-0.2.1}/tests/atest/testdata/example_04.csv +0 -0
- {robotframework_tablelibrary-0.1.4 → robotframework_tablelibrary-0.2.1}/tests/atest/testdata/example_04.txt +0 -0
- {robotframework_tablelibrary-0.1.4 → robotframework_tablelibrary-0.2.1}/tests/atest/testdata/example_05.parquet +0 -0
- {robotframework_tablelibrary-0.1.4 → robotframework_tablelibrary-0.2.1}/tests/atest/testdata/example_06.xlsx +0 -0
- {robotframework_tablelibrary-0.1.4 → robotframework_tablelibrary-0.2.1}/tests/atest/testdata/example_07.csv +0 -0
- {robotframework_tablelibrary-0.1.4 → robotframework_tablelibrary-0.2.1}/tests/atest/testdata/example_08.csv +0 -0
- {robotframework_tablelibrary-0.1.4 → robotframework_tablelibrary-0.2.1}/utils/imbus-web-logo.svg +0 -0
{robotframework_tablelibrary-0.1.4 → robotframework_tablelibrary-0.2.1}/.pre-commit-config.yaml
RENAMED
|
@@ -9,6 +9,11 @@ repos:
|
|
|
9
9
|
language: python
|
|
10
10
|
types_or: [python, pyi]
|
|
11
11
|
require_serial: true
|
|
12
|
+
args:
|
|
13
|
+
- --disable-error-code
|
|
14
|
+
- no-any-return
|
|
15
|
+
- --disable-error-code
|
|
16
|
+
- arg-type
|
|
12
17
|
|
|
13
18
|
# try generating the libdoc documentation
|
|
14
19
|
- repo: local
|
|
@@ -23,13 +28,6 @@ repos:
|
|
|
23
28
|
# Ruff linter for Python files
|
|
24
29
|
- repo: local
|
|
25
30
|
hooks:
|
|
26
|
-
# - id: ruff-format
|
|
27
|
-
# name: ruff-format
|
|
28
|
-
# description: "Run 'ruff format' for extremely fast Python formatting"
|
|
29
|
-
# entry: ruff format --force-exclude
|
|
30
|
-
# language: python
|
|
31
|
-
# types_or: [python, pyi, jupyter]
|
|
32
|
-
# require_serial: true
|
|
33
31
|
|
|
34
32
|
- id: ruff
|
|
35
33
|
name: ruff
|
|
@@ -39,6 +37,14 @@ repos:
|
|
|
39
37
|
types_or: [python, pyi, jupyter]
|
|
40
38
|
require_serial: true
|
|
41
39
|
|
|
40
|
+
- id: ruff-format
|
|
41
|
+
name: ruff-format
|
|
42
|
+
description: "Run 'ruff format' for extremely fast Python formatting"
|
|
43
|
+
entry: ruff format --force-exclude
|
|
44
|
+
language: python
|
|
45
|
+
types_or: [python, pyi, jupyter]
|
|
46
|
+
require_serial: true
|
|
47
|
+
|
|
42
48
|
# Robocop formatter and linter for Robot Framework (.robot and .resource files)
|
|
43
49
|
- repo: local
|
|
44
50
|
hooks:
|
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
# Development
|
|
2
2
|
|
|
3
|
+
## Unit Testing
|
|
4
|
+
|
|
5
|
+
We are measuring the coverage of the unit tests & expect a minimum coverage of 95% - otherwise the pipeline job for the unit test execution will fail accordingly.
|
|
6
|
+
Please ensure you've added unit tests whenever adding new source code to the project.
|
|
7
|
+
|
|
3
8
|
## Release Creation
|
|
4
9
|
|
|
5
10
|
### Precondition
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: robotframework-tablelibrary
|
|
3
|
-
Version: 0.1
|
|
3
|
+
Version: 0.2.1
|
|
4
4
|
Summary: A Robot Framework library providing generic table keywords for several table file type like csv or excel.
|
|
5
5
|
Project-URL: Homepage, https://github.com/imbus/robotframework-tablelibrary
|
|
6
6
|
Project-URL: Documentation, https://github.com/imbus/robotframework-tablelibrary#readme
|
|
@@ -30,6 +30,7 @@ Requires-Dist: hatch; extra == 'dev'
|
|
|
30
30
|
Requires-Dist: mypy; extra == 'dev'
|
|
31
31
|
Requires-Dist: pre-commit; extra == 'dev'
|
|
32
32
|
Requires-Dist: pytest; extra == 'dev'
|
|
33
|
+
Requires-Dist: pytest-cov; extra == 'dev'
|
|
33
34
|
Requires-Dist: robotframework-robocop; extra == 'dev'
|
|
34
35
|
Requires-Dist: ruff; extra == 'dev'
|
|
35
36
|
Description-Content-Type: text/markdown
|
|
@@ -13,7 +13,12 @@ FILE="src/Tables/__about__.py"
|
|
|
13
13
|
echo "🔧 Updating version to '${NEW_VERSION}' in '${FILE}'"
|
|
14
14
|
|
|
15
15
|
# Example: __version__ = "0.0.6" → __version__ = "0.0.7"
|
|
16
|
-
|
|
16
|
+
if [[ "$OSTYPE" == "darwin"* ]]; then
|
|
17
|
+
sed -i '' -E "s/^(__version__ *= *\")[^\"]+/\1${NEW_VERSION}/" src/Tables/__about__.py
|
|
18
|
+
else
|
|
19
|
+
sed -i.bak -E "s/^(__version__\s*=\s*\")[^\"]+\"/\1${NEW_VERSION}\"/" "$FILE"
|
|
20
|
+
fi
|
|
21
|
+
|
|
17
22
|
rm -f "${FILE}.bak"
|
|
18
23
|
|
|
19
24
|
git checkout main
|
|
@@ -39,6 +39,7 @@ dev = [
|
|
|
39
39
|
"hatch",
|
|
40
40
|
"ruff",
|
|
41
41
|
"pytest",
|
|
42
|
+
"pytest-cov",
|
|
42
43
|
"pre-commit",
|
|
43
44
|
"mypy",
|
|
44
45
|
"robotframework-robocop"
|
|
@@ -91,12 +92,13 @@ exclude_lines = [
|
|
|
91
92
|
[tool.hatch.envs.dev]
|
|
92
93
|
dependencies = [
|
|
93
94
|
"ruff",
|
|
94
|
-
"pytest"
|
|
95
|
+
"pytest",
|
|
96
|
+
"pytest-cov"
|
|
95
97
|
]
|
|
96
98
|
[tool.hatch.envs.dev.scripts]
|
|
97
99
|
lint = "ruff check ."
|
|
98
100
|
atest = "robot tests/atest/"
|
|
99
|
-
utest = "pytest"
|
|
101
|
+
utest = "pytest --cov=Tables --cov-report=term-missing --cov-branch --cov-fail-under=95"
|
|
100
102
|
docs = "libdoc src/Tables results/keyword_docs.html"
|
|
101
103
|
|
|
102
104
|
[tool.mypy]
|
|
@@ -110,27 +112,26 @@ warn_unreachable = true
|
|
|
110
112
|
pretty = true
|
|
111
113
|
|
|
112
114
|
[tool.ruff]
|
|
113
|
-
fix = false
|
|
114
115
|
target-version = "py310"
|
|
115
|
-
line-length =
|
|
116
|
+
line-length = 125
|
|
116
117
|
exclude = [
|
|
117
118
|
"__pycache__",
|
|
118
119
|
".venv",
|
|
119
120
|
"tools",
|
|
120
121
|
"model",
|
|
122
|
+
".git",
|
|
123
|
+
"build",
|
|
124
|
+
"dist"
|
|
121
125
|
]
|
|
122
126
|
|
|
123
127
|
[tool.ruff.format]
|
|
124
128
|
quote-style = "double"
|
|
129
|
+
indent-style = "space"
|
|
125
130
|
|
|
126
131
|
[tool.ruff.lint]
|
|
127
132
|
ignore = [
|
|
128
|
-
"N815", # mixedCase variable in class scope
|
|
129
|
-
"N803", # argument name should be lowercase
|
|
130
|
-
"T201", # Print statements
|
|
131
|
-
"INP001", # part of an implicit namespace package
|
|
132
133
|
"N999", # Invalid module name
|
|
133
|
-
"E501"
|
|
134
|
+
"E501" # docstrings
|
|
134
135
|
]
|
|
135
136
|
select = [
|
|
136
137
|
"E",
|
|
@@ -159,6 +160,7 @@ select = [
|
|
|
159
160
|
"SIM",
|
|
160
161
|
"RUF",
|
|
161
162
|
]
|
|
163
|
+
unfixable = []
|
|
162
164
|
|
|
163
165
|
[tool.robocop.lint]
|
|
164
166
|
select = [
|
{robotframework_tablelibrary-0.1.4 → robotframework_tablelibrary-0.2.1}/src/Tables/__init__.py
RENAMED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
# SPDX-FileCopyrightText: 2025-present Marvin Klerx <marvinklerx20@gmail.com>
|
|
2
2
|
#
|
|
3
3
|
# SPDX-License-Identifier: MIT
|
|
4
|
+
from robot import result, running
|
|
4
5
|
from robot.api.deco import library
|
|
5
6
|
from robotlibcore import HybridCore
|
|
6
7
|
|
|
8
|
+
from Tables.utils.settings_stack import Scope, SettingsStack
|
|
9
|
+
|
|
7
10
|
from .__about__ import __version__
|
|
8
11
|
from .keywords import (
|
|
9
12
|
Configuration,
|
|
@@ -45,6 +48,33 @@ class Tables(HybridCore):
|
|
|
45
48
|
- latin-1
|
|
46
49
|
- further more... (define your own file encoding with the given library argument)
|
|
47
50
|
|
|
51
|
+
== Live Data Streaming ==
|
|
52
|
+
Some keywords allow you to write the inserted or appended data directly into an output table file.
|
|
53
|
+
By default, the table library writes the modified table data first into the internal cache.
|
|
54
|
+
In this case, you decide when to write the data into a file.
|
|
55
|
+
|
|
56
|
+
If you require the modified data on the fly within the file on your file system, you can enable the streaming via ``Configure Streaming``.
|
|
57
|
+
|
|
58
|
+
Afterwards, every keyword that allows the on-the-fly streaming, writes the new data directly into the file system instead of modifying the table just in the cache.
|
|
59
|
+
|
|
60
|
+
Example:
|
|
61
|
+
| # enable the streaming on-the-fly
|
|
62
|
+
| Configure Streaming True Test
|
|
63
|
+
|
|
|
64
|
+
| VAR ${filepath} = ${CURDIR}/results/test_writer_live_streaming_append_row.csv
|
|
65
|
+
| VAR @{headers} = counter random
|
|
66
|
+
| ${uuid} = Tables.Create Table headers=${headers} file_path=${filepath}
|
|
67
|
+
|
|
|
68
|
+
| # append ten rows on-the-fly within the given csv file
|
|
69
|
+
| FOR ${i} IN RANGE ${10}
|
|
70
|
+
| ${random} = Generate Random String 10
|
|
71
|
+
| VAR @{row} = ${i} ${random}
|
|
72
|
+
| Tables.Append Row ${row}
|
|
73
|
+
|
|
|
74
|
+
| ${table_content} = Tables.Read Table ${filepath}
|
|
75
|
+
| Should Be Equal ${table_content}[-1][1] ${random}
|
|
76
|
+
| END
|
|
77
|
+
|
|
48
78
|
== Excel Files ==
|
|
49
79
|
We have included a basic handling of ``Excel`` files,
|
|
50
80
|
but for more complex excel features, please take a look at the following library:
|
|
@@ -155,18 +185,32 @@ class Tables(HybridCore):
|
|
|
155
185
|
| ``quoting`` | Define which values should be surrounded with quotes, please check the CSV quoting for more details. Default is ``MINIMAL`` |
|
|
156
186
|
| ``quoting_character`` | Define quoting character to use for writing table files. Default is ``\"`` |
|
|
157
187
|
"""
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
self.
|
|
161
|
-
|
|
188
|
+
|
|
189
|
+
# required variables for SettingsScope mechanism
|
|
190
|
+
self.scope_stack: dict = {}
|
|
191
|
+
self.suite_ids: dict[str, None] = {}
|
|
192
|
+
self.current_test_id: str | None = None
|
|
193
|
+
self.is_test_case_running = False
|
|
194
|
+
|
|
195
|
+
# following config variables are using SettingsStack engine with scopes
|
|
196
|
+
self.scope_stack["ignore_header"] = SettingsStack(ignore_header, self)
|
|
197
|
+
self.scope_stack["file_type"] = SettingsStack(file_type, self)
|
|
198
|
+
self.scope_stack["separator"] = SettingsStack(separator, self)
|
|
199
|
+
self.scope_stack["line_terminator"] = SettingsStack(line_terminator, self)
|
|
200
|
+
self.scope_stack["file_encoding"] = SettingsStack(
|
|
201
|
+
file_encoding.value if isinstance(file_encoding, FileEncoding) else file_encoding, self
|
|
162
202
|
)
|
|
163
|
-
self.
|
|
164
|
-
self.
|
|
165
|
-
self.
|
|
166
|
-
self._quoting_character = quoting_character
|
|
203
|
+
self.scope_stack["quoting"] = SettingsStack(quoting, self)
|
|
204
|
+
self.scope_stack["quoting_character"] = SettingsStack(quoting_character, self)
|
|
205
|
+
self.scope_stack["enable_streaming"] = SettingsStack(False, self)
|
|
167
206
|
|
|
168
207
|
self.file_access = FileAccess(self)
|
|
169
208
|
|
|
209
|
+
self.ROBOT_LIBRARY_LISTENER = [
|
|
210
|
+
self,
|
|
211
|
+
Modifier(self, self.file_access),
|
|
212
|
+
]
|
|
213
|
+
|
|
170
214
|
libraries = [
|
|
171
215
|
Configuration(self),
|
|
172
216
|
Getter(self, self.file_access),
|
|
@@ -176,3 +220,29 @@ class Tables(HybridCore):
|
|
|
176
220
|
]
|
|
177
221
|
|
|
178
222
|
super().__init__(libraries)
|
|
223
|
+
|
|
224
|
+
def _start_suite(self, _name: running.TestSuite, attrs: result.TestSuite):
|
|
225
|
+
self.suite_ids[attrs.id] = None
|
|
226
|
+
self._add_to_scope_stack(attrs.id, Scope.Suite)
|
|
227
|
+
|
|
228
|
+
def _start_test(self, _name: running.TestCase, attrs: result.TestCase):
|
|
229
|
+
self.current_test_id = attrs.id
|
|
230
|
+
self._add_to_scope_stack(attrs.id, Scope.Test)
|
|
231
|
+
self.is_test_case_running = True
|
|
232
|
+
|
|
233
|
+
def _end_test(self, _name: running.TestCase, attrs: result.TestCase):
|
|
234
|
+
self._remove_from_scope_stack(attrs.id)
|
|
235
|
+
self.current_test_id = None
|
|
236
|
+
self.is_test_case_running = False
|
|
237
|
+
|
|
238
|
+
def _end_suite(self, _name: running.TestSuite, attrs: result.TestSuite):
|
|
239
|
+
self._remove_from_scope_stack(attrs.id)
|
|
240
|
+
self.suite_ids.pop(attrs.id, None)
|
|
241
|
+
|
|
242
|
+
def _add_to_scope_stack(self, scope_id: str, scope: Scope):
|
|
243
|
+
for stack in self.scope_stack.values():
|
|
244
|
+
stack.start(scope_id, scope)
|
|
245
|
+
|
|
246
|
+
def _remove_from_scope_stack(self, scope_id):
|
|
247
|
+
for stack in self.scope_stack.values():
|
|
248
|
+
stack.end(scope_id)
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
from typing import TYPE_CHECKING
|
|
2
|
+
|
|
3
|
+
from Tables.utils.settings import Delimiter, FileEncoding, FileType, LineTerminator, Quoting, QuotingCharacter
|
|
4
|
+
from Tables.utils.settings_stack import SettingsStack
|
|
5
|
+
|
|
6
|
+
if TYPE_CHECKING:
|
|
7
|
+
from .. import Tables
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class LibraryAttributes:
|
|
11
|
+
def __init__(self, library: "Tables") -> None:
|
|
12
|
+
"""
|
|
13
|
+
Expose library attributes to all classes
|
|
14
|
+
"""
|
|
15
|
+
self.library = library
|
|
16
|
+
|
|
17
|
+
###
|
|
18
|
+
### New strategy: use SettingsStack like in Browser library for different scopes
|
|
19
|
+
###
|
|
20
|
+
|
|
21
|
+
# ignore_header
|
|
22
|
+
@property
|
|
23
|
+
def ignore_header(self) -> bool:
|
|
24
|
+
return self.library.scope_stack["ignore_header"].get()
|
|
25
|
+
|
|
26
|
+
@property
|
|
27
|
+
def ignore_header_stack(self) -> SettingsStack:
|
|
28
|
+
return self.library.scope_stack["ignore_header"]
|
|
29
|
+
|
|
30
|
+
@ignore_header_stack.setter
|
|
31
|
+
def ignore_header_stack(self, stack: SettingsStack):
|
|
32
|
+
self.library.scope_stack["ignore_header"] = stack
|
|
33
|
+
|
|
34
|
+
# file_type
|
|
35
|
+
@property
|
|
36
|
+
def file_type(self) -> FileType:
|
|
37
|
+
return self.library.scope_stack["file_type"].get()
|
|
38
|
+
|
|
39
|
+
@property
|
|
40
|
+
def file_type_stack(self) -> SettingsStack:
|
|
41
|
+
return self.library.scope_stack["file_type"]
|
|
42
|
+
|
|
43
|
+
@file_type_stack.setter
|
|
44
|
+
def file_type_stack(self, stack: SettingsStack):
|
|
45
|
+
self.library.scope_stack["file_type"] = stack
|
|
46
|
+
|
|
47
|
+
# separator / delimiter
|
|
48
|
+
@property
|
|
49
|
+
def separator(self) -> Delimiter:
|
|
50
|
+
return self.library.scope_stack["separator"].get()
|
|
51
|
+
|
|
52
|
+
@property
|
|
53
|
+
def separator_stack(self) -> SettingsStack:
|
|
54
|
+
return self.library.scope_stack["separator"]
|
|
55
|
+
|
|
56
|
+
@separator_stack.setter
|
|
57
|
+
def separator_stack(self, stack: SettingsStack):
|
|
58
|
+
self.library.scope_stack["separator"] = stack
|
|
59
|
+
|
|
60
|
+
# line terminator
|
|
61
|
+
@property
|
|
62
|
+
def line_terminator(self) -> LineTerminator:
|
|
63
|
+
return self.library.scope_stack["line_terminator"].get()
|
|
64
|
+
|
|
65
|
+
@property
|
|
66
|
+
def line_terminator_stack(self) -> SettingsStack:
|
|
67
|
+
return self.library.scope_stack["line_terminator"]
|
|
68
|
+
|
|
69
|
+
@line_terminator_stack.setter
|
|
70
|
+
def line_terminator_stack(self, stack: SettingsStack):
|
|
71
|
+
self.library.scope_stack["line_terminator"] = stack
|
|
72
|
+
|
|
73
|
+
# file encoding
|
|
74
|
+
@property
|
|
75
|
+
def file_encoding(self) -> FileEncoding:
|
|
76
|
+
return self.library.scope_stack["file_encoding"].get()
|
|
77
|
+
|
|
78
|
+
@property
|
|
79
|
+
def file_encoding_stack(self) -> SettingsStack:
|
|
80
|
+
return self.library.scope_stack["file_encoding"]
|
|
81
|
+
|
|
82
|
+
@file_encoding_stack.setter
|
|
83
|
+
def file_encoding_stack(self, stack: SettingsStack):
|
|
84
|
+
self.library.scope_stack["file_encoding"] = stack
|
|
85
|
+
|
|
86
|
+
# quoting
|
|
87
|
+
@property
|
|
88
|
+
def quoting(self) -> Quoting:
|
|
89
|
+
return self.library.scope_stack["quoting"].get()
|
|
90
|
+
|
|
91
|
+
@property
|
|
92
|
+
def quoting_stack(self) -> SettingsStack:
|
|
93
|
+
return self.library.scope_stack["quoting"]
|
|
94
|
+
|
|
95
|
+
@quoting_stack.setter
|
|
96
|
+
def quoting_stack(self, stack: SettingsStack):
|
|
97
|
+
self.library.scope_stack["quoting"] = stack
|
|
98
|
+
|
|
99
|
+
# quoting character
|
|
100
|
+
@property
|
|
101
|
+
def quoting_character(self) -> QuotingCharacter:
|
|
102
|
+
return self.library.scope_stack["quoting_character"].get()
|
|
103
|
+
|
|
104
|
+
@property
|
|
105
|
+
def quoting_character_stack(self) -> SettingsStack:
|
|
106
|
+
return self.library.scope_stack["quoting_character"]
|
|
107
|
+
|
|
108
|
+
@quoting_character_stack.setter
|
|
109
|
+
def quoting_character_stack(self, stack: SettingsStack):
|
|
110
|
+
self.library.scope_stack["quoting_character"] = stack
|
|
111
|
+
|
|
112
|
+
# data streaming into files
|
|
113
|
+
@property
|
|
114
|
+
def enable_streaming(self) -> QuotingCharacter:
|
|
115
|
+
return self.library.scope_stack["enable_streaming"].get()
|
|
116
|
+
|
|
117
|
+
@property
|
|
118
|
+
def enable_streaming_stack(self) -> SettingsStack:
|
|
119
|
+
return self.library.scope_stack["enable_streaming"]
|
|
120
|
+
|
|
121
|
+
@enable_streaming_stack.setter
|
|
122
|
+
def enable_streaming_stack(self, stack: SettingsStack):
|
|
123
|
+
self.library.scope_stack["enable_streaming"] = stack
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
from dataclasses import asdict, dataclass
|
|
2
|
+
|
|
3
|
+
from robot.api import logger
|
|
4
|
+
from robot.api.deco import keyword
|
|
5
|
+
|
|
6
|
+
from ..general.library_attributes import LibraryAttributes
|
|
7
|
+
from ..utils.settings import (
|
|
8
|
+
Delimiter,
|
|
9
|
+
FileEncoding,
|
|
10
|
+
FileType,
|
|
11
|
+
LineTerminator,
|
|
12
|
+
Quoting,
|
|
13
|
+
QuotingCharacter,
|
|
14
|
+
)
|
|
15
|
+
from ..utils.settings_stack import Scope
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@dataclass
|
|
19
|
+
class ConfigCtx:
|
|
20
|
+
file_type: FileType
|
|
21
|
+
separator: Delimiter
|
|
22
|
+
quoting: Quoting
|
|
23
|
+
quoting_character: QuotingCharacter
|
|
24
|
+
line_terminator: LineTerminator
|
|
25
|
+
file_encoding: FileEncoding
|
|
26
|
+
ignore_header: bool
|
|
27
|
+
enable_streaming: bool
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class Configuration(LibraryAttributes):
|
|
31
|
+
@keyword(tags=["Configuration"])
|
|
32
|
+
def get_library_configuration(self) -> dict:
|
|
33
|
+
"""
|
|
34
|
+
Keyword returns the current internal library configuration.
|
|
35
|
+
|
|
36
|
+
Return value is type ``ConfigCtx`` and contains all relevant configuration parameters.
|
|
37
|
+
"""
|
|
38
|
+
return asdict(
|
|
39
|
+
ConfigCtx(
|
|
40
|
+
file_type=self.file_type,
|
|
41
|
+
separator=self.separator,
|
|
42
|
+
quoting=self.quoting,
|
|
43
|
+
quoting_character=self.quoting_character,
|
|
44
|
+
line_terminator=self.line_terminator,
|
|
45
|
+
file_encoding=self.file_encoding,
|
|
46
|
+
ignore_header=self.ignore_header,
|
|
47
|
+
enable_streaming=self.enable_streaming,
|
|
48
|
+
)
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
@keyword(tags=["Configuration"])
|
|
52
|
+
def configure_file_type(self, file_type: FileType, scope: Scope = Scope.Suite):
|
|
53
|
+
"""
|
|
54
|
+
Change the internal file type during your test execution dynamically.
|
|
55
|
+
|
|
56
|
+
| =`Arguments`= | =`Description`= |
|
|
57
|
+
| ``file_type`` | Choose the new file type |
|
|
58
|
+
|
|
59
|
+
== Example ==
|
|
60
|
+
| Configure File Type CSV
|
|
61
|
+
| Configure File Type Excel
|
|
62
|
+
| Configure File Type Parquet
|
|
63
|
+
"""
|
|
64
|
+
old_config = self.file_type
|
|
65
|
+
self.file_type_stack.set(file_type, scope)
|
|
66
|
+
logger.debug(f"'file_type': old value: {old_config} - new value: {file_type}")
|
|
67
|
+
return old_config
|
|
68
|
+
|
|
69
|
+
@keyword(tags=["Configuration"])
|
|
70
|
+
def configure_separator(self, separator: Delimiter, scope: Scope = Scope.Suite):
|
|
71
|
+
"""
|
|
72
|
+
Change the internal separator during your test execution dynamically.
|
|
73
|
+
|
|
74
|
+
| =`Arguments`= | =`Description`= |
|
|
75
|
+
| ``separator`` | Define a new separator |
|
|
76
|
+
|
|
77
|
+
== Example ==
|
|
78
|
+
| Configure Delimiter ;
|
|
79
|
+
| Configure Delimiter ,
|
|
80
|
+
| Configure Delimiter \\t
|
|
81
|
+
"""
|
|
82
|
+
old_config = self.separator
|
|
83
|
+
self.separator_stack.set(separator, scope)
|
|
84
|
+
logger.debug(f"'file_type': old value: {old_config} - new value: {separator}")
|
|
85
|
+
return old_config
|
|
86
|
+
|
|
87
|
+
@keyword(tags=["Configuration"])
|
|
88
|
+
def configure_quoting(self, quoting: Quoting, scope: Scope = Scope.Suite):
|
|
89
|
+
"""
|
|
90
|
+
Change the internal quoting mode during your test execution dynamically.
|
|
91
|
+
|
|
92
|
+
| =`Arguments`= | =`Description`= |
|
|
93
|
+
| ``quoting`` | Define a new quoting mode |
|
|
94
|
+
|
|
95
|
+
== Example ==
|
|
96
|
+
| Configure Quoting MINIMAL
|
|
97
|
+
| Configure Quoting NONNUMERIC
|
|
98
|
+
| Configure Quoting NONE
|
|
99
|
+
"""
|
|
100
|
+
old_config = self.quoting
|
|
101
|
+
self.quoting_stack.set(quoting, scope)
|
|
102
|
+
logger.debug(f"'file_type': old value: {old_config} - new value: {quoting}")
|
|
103
|
+
return old_config
|
|
104
|
+
|
|
105
|
+
@keyword(tags=["Configuration"])
|
|
106
|
+
def configure_quoting_character(self, quoting_character: QuotingCharacter, scope: Scope = Scope.Suite):
|
|
107
|
+
"""
|
|
108
|
+
Change the internal quoting character during your test execution dynamically.
|
|
109
|
+
|
|
110
|
+
| =`Arguments`= | =`Description`= |
|
|
111
|
+
| ``quoting`` | Define a new quoting mode |
|
|
112
|
+
|
|
113
|
+
== Example ==
|
|
114
|
+
| Configure Quoting Character "
|
|
115
|
+
| Configure Quoting Character '
|
|
116
|
+
"""
|
|
117
|
+
old_config = self.quoting_character
|
|
118
|
+
self.quoting_character_stack.set(quoting_character, scope)
|
|
119
|
+
logger.debug(f"'file_type': old value: {old_config} - new value: {quoting_character}")
|
|
120
|
+
return old_config
|
|
121
|
+
|
|
122
|
+
@keyword(tags=["Configuration"])
|
|
123
|
+
def configure_line_terminator(self, line_terminator: LineTerminator, scope: Scope = Scope.Suite):
|
|
124
|
+
"""
|
|
125
|
+
Change the internal line terminator during your test execution dynamically.
|
|
126
|
+
|
|
127
|
+
| =`Arguments`= | =`Description`= |
|
|
128
|
+
| ``line_terminator`` | Define a new line_terminator |
|
|
129
|
+
|
|
130
|
+
== Example ==
|
|
131
|
+
| Configure Line Terminator LF
|
|
132
|
+
| Configure Line Terminator CRLF
|
|
133
|
+
"""
|
|
134
|
+
old_config = self.line_terminator
|
|
135
|
+
self.line_terminator_stack.set(line_terminator, scope)
|
|
136
|
+
logger.debug(f"'file_type': old value: {old_config} - new value: {line_terminator}")
|
|
137
|
+
return old_config
|
|
138
|
+
|
|
139
|
+
@keyword(tags=["Configuration"])
|
|
140
|
+
def configure_file_encoding(self, file_encoding: FileEncoding | str, scope: Scope = Scope.Suite):
|
|
141
|
+
"""
|
|
142
|
+
Change the internal file encoding during your test execution dynamically.
|
|
143
|
+
|
|
144
|
+
| =`Arguments`= | =`Description`= |
|
|
145
|
+
| ``file_encoding`` | Define a new file encoding |
|
|
146
|
+
|
|
147
|
+
== Example ==
|
|
148
|
+
| Configure File Encoding UTF_8
|
|
149
|
+
| Configure File Encoding UTF_16
|
|
150
|
+
| Configure File Encoding LATIN_1
|
|
151
|
+
|
|
152
|
+
see [Python Encoding Names|https://docs.python.org/3/library/codecs.html#standard-encodings]
|
|
153
|
+
"""
|
|
154
|
+
old_config = self.file_encoding
|
|
155
|
+
self.file_encoding_stack.set(
|
|
156
|
+
file_encoding.value if isinstance(file_encoding, FileEncoding) else file_encoding, scope
|
|
157
|
+
)
|
|
158
|
+
logger.debug(f"'file_type': old value: {old_config} - new value: {file_encoding}")
|
|
159
|
+
return old_config
|
|
160
|
+
|
|
161
|
+
@keyword(tags=["Configuration"])
|
|
162
|
+
def configure_ignore_header(self, ignore_header: bool, scope: Scope = Scope.Suite):
|
|
163
|
+
"""
|
|
164
|
+
Change the internal setting to (not) ignore the data header lines during your test execution dynamically.
|
|
165
|
+
|
|
166
|
+
| =`Arguments`= | =`Description`= |
|
|
167
|
+
| ``ignore_header`` | Ignore / recognize header columns |
|
|
168
|
+
|
|
169
|
+
== Example ==
|
|
170
|
+
| Configure Ignore Header True
|
|
171
|
+
| Configure Ignore Header False
|
|
172
|
+
"""
|
|
173
|
+
|
|
174
|
+
old_config = self.ignore_header
|
|
175
|
+
self.ignore_header_stack.set(ignore_header, scope)
|
|
176
|
+
logger.debug(f"'ignore_header': old value: {old_config} - new value: {ignore_header}")
|
|
177
|
+
return old_config
|
|
178
|
+
|
|
179
|
+
@keyword(tags=["Configuration"])
|
|
180
|
+
def configure_streaming(self, enable_streaming: bool, scope: Scope = Scope.Suite):
|
|
181
|
+
"""
|
|
182
|
+
Enable / disable the direct streaming of data into the given table file.
|
|
183
|
+
|
|
184
|
+
= Default Behaviour =
|
|
185
|
+
By default, you can open a table, modify the content in the internal cache of the Table library and afterwards to write it into a table file.
|
|
186
|
+
|
|
187
|
+
= Behaviour using Streaming =
|
|
188
|
+
Using the streaming behaviour enables you to write e.g. rows directly into the table file instead of the internal cache.
|
|
189
|
+
This can be required in case you need the data immediately in the file, and not in the cache.
|
|
190
|
+
|
|
191
|
+
| =`Arguments`= | =`Description`= |
|
|
192
|
+
| ``enable_streaming`` | Set to ``True`` to enable the streaming - default: ``False`` |
|
|
193
|
+
|
|
194
|
+
== Example ==
|
|
195
|
+
| Configure Streaming True
|
|
196
|
+
| Configure Streaming False
|
|
197
|
+
"""
|
|
198
|
+
old_config = self.enable_streaming
|
|
199
|
+
self.enable_streaming_stack.set(enable_streaming, scope)
|
|
200
|
+
logger.debug(f"'file_type': old value: {old_config} - new value: {enable_streaming}")
|
|
201
|
+
return old_config
|
{robotframework_tablelibrary-0.1.4 → robotframework_tablelibrary-0.2.1}/src/Tables/keywords/excel.py
RENAMED
|
@@ -42,9 +42,7 @@ class Excel(LibraryAttributes):
|
|
|
42
42
|
###
|
|
43
43
|
|
|
44
44
|
@keyword(tags=["Excel", "Getter"])
|
|
45
|
-
def excel_open(
|
|
46
|
-
self, alias: str, path: str, sheet_name: str | list[str | int] | None = None
|
|
47
|
-
) -> str:
|
|
45
|
+
def excel_open(self, alias: str, path: str, sheet_name: str | list[str | int] | None = None) -> str:
|
|
48
46
|
"""
|
|
49
47
|
Keyword to open the given excel file.
|
|
50
48
|
|
|
@@ -97,9 +95,7 @@ class Excel(LibraryAttributes):
|
|
|
97
95
|
self.current_file = None
|
|
98
96
|
logger.info(f"Excel file '{alias}' is closed!")
|
|
99
97
|
return True
|
|
100
|
-
raise KeyError(
|
|
101
|
-
f"Given file alias '{alias}' does not exist - check all opened files and their alias first!"
|
|
102
|
-
)
|
|
98
|
+
raise KeyError(f"Given file alias '{alias}' does not exist - check all opened files and their alias first!")
|
|
103
99
|
|
|
104
100
|
@keyword(tags=["Excel", "Getter"])
|
|
105
101
|
def excel_get_open_files(self) -> list:
|