pytest-csv-params 2.2.5__tar.gz → 2.3.0__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 (22) hide show
  1. {pytest_csv_params-2.2.5 → pytest_csv_params-2.3.0}/PKG-INFO +3 -2
  2. {pytest_csv_params-2.2.5 → pytest_csv_params-2.3.0}/README.md +2 -1
  3. {pytest_csv_params-2.2.5 → pytest_csv_params-2.3.0}/_ptcsvp/exception.py +8 -0
  4. {pytest_csv_params-2.2.5 → pytest_csv_params-2.3.0}/_ptcsvp/parametrize.py +50 -0
  5. {pytest_csv_params-2.2.5 → pytest_csv_params-2.3.0}/_ptcsvp/version.py +2 -2
  6. {pytest_csv_params-2.2.5 → pytest_csv_params-2.3.0}/pyproject.toml +5 -3
  7. pytest_csv_params-2.3.0/pytest_csv_params/object.py +43 -0
  8. {pytest_csv_params-2.2.5 → pytest_csv_params-2.3.0}/pytest_csv_params/plugin.py +19 -7
  9. {pytest_csv_params-2.2.5 → pytest_csv_params-2.3.0}/pytest_csv_params/types.py +12 -0
  10. {pytest_csv_params-2.2.5 → pytest_csv_params-2.3.0}/.gitignore +0 -0
  11. {pytest_csv_params-2.2.5 → pytest_csv_params-2.3.0}/LICENSE.txt +0 -0
  12. {pytest_csv_params-2.2.5 → pytest_csv_params-2.3.0}/_ptcsvp/__init__.py +0 -0
  13. {pytest_csv_params-2.2.5 → pytest_csv_params-2.3.0}/_ptcsvp/cmdline.py +0 -0
  14. {pytest_csv_params-2.2.5 → pytest_csv_params-2.3.0}/_ptcsvp/configure.py +0 -0
  15. {pytest_csv_params-2.2.5 → pytest_csv_params-2.3.0}/_ptcsvp/plugin.py +0 -0
  16. {pytest_csv_params-2.2.5 → pytest_csv_params-2.3.0}/_ptcsvp/varname.py +0 -0
  17. {pytest_csv_params-2.2.5 → pytest_csv_params-2.3.0}/pytest_csv_params/__init__.py +0 -0
  18. {pytest_csv_params-2.2.5 → pytest_csv_params-2.3.0}/pytest_csv_params/decorator.py +0 -0
  19. {pytest_csv_params-2.2.5 → pytest_csv_params-2.3.0}/pytest_csv_params/dialect.py +0 -0
  20. {pytest_csv_params-2.2.5 → pytest_csv_params-2.3.0}/pytest_csv_params/exception.py +0 -0
  21. {pytest_csv_params-2.2.5 → pytest_csv_params-2.3.0}/pytest_csv_params/shortcut.py +0 -0
  22. {pytest_csv_params-2.2.5 → pytest_csv_params-2.3.0}/pytest_csv_params/warning.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: pytest-csv-params
3
- Version: 2.2.5
3
+ Version: 2.3.0
4
4
  Summary: Pytest plugin for Test Case Parametrization with CSV files
5
5
  Project-URL: repository, https://git.codebau.dev/pytest-plugins/pytest-csv-params
6
6
  Project-URL: homepage, https://git.codebau.dev/pytest-plugins/pytest-csv-params
@@ -107,7 +107,8 @@ Simply decorate your test method with `@csv_params` (`pytest_csv_params.decorato
107
107
  | `reuse_id_col` | `bool` (optional) | Allows to re-use the ID column as test data column (since 1.3.0), defaults to `False` for backwards compatibility | `True` |
108
108
  | `skip_when_missing_csv_file` | `bool` (optional) | When the CSV data cannot be loaded, the test will be skipped (since 2.1.0), defaults to `False` for backwards compatibility | `True` |
109
109
  | `skip_when_empty_csv_file` | `bool` (optional) | When the CSV data file is empty, the test will be skipped (since 2.1.0), defaults to `False` for backwards compatibility | `True` |
110
- | `parameters_as_dictionary` | `str` (optional) | Instead of using one method argument per column, all columns are provided in the dict named with this parameter (since 2.2.0) | `test_data` |
110
+ | `parameters_as_dictionary` | `str` (optional) | Instead of using one method argument per column, all columns are provided in the dict named with this parameter (since 2.2.0) | `"test_data"` |
111
+ | `parameters_as_object` | `str` or `(str, pytest_csv_params.object.TestCaseDataObjectFactory)` (optional) | Instead of using one method argument per column, all columns are provided as a object, either just named by `str`, or named by `str` and prepared with the given factory (since 2.3.0) | `"test_data"`, `("test_data", my_obj_factory)` |
111
112
 
112
113
  ## CSV Format
113
114
 
@@ -71,7 +71,8 @@ Simply decorate your test method with `@csv_params` (`pytest_csv_params.decorato
71
71
  | `reuse_id_col` | `bool` (optional) | Allows to re-use the ID column as test data column (since 1.3.0), defaults to `False` for backwards compatibility | `True` |
72
72
  | `skip_when_missing_csv_file` | `bool` (optional) | When the CSV data cannot be loaded, the test will be skipped (since 2.1.0), defaults to `False` for backwards compatibility | `True` |
73
73
  | `skip_when_empty_csv_file` | `bool` (optional) | When the CSV data file is empty, the test will be skipped (since 2.1.0), defaults to `False` for backwards compatibility | `True` |
74
- | `parameters_as_dictionary` | `str` (optional) | Instead of using one method argument per column, all columns are provided in the dict named with this parameter (since 2.2.0) | `test_data` |
74
+ | `parameters_as_dictionary` | `str` (optional) | Instead of using one method argument per column, all columns are provided in the dict named with this parameter (since 2.2.0) | `"test_data"` |
75
+ | `parameters_as_object` | `str` or `(str, pytest_csv_params.object.TestCaseDataObjectFactory)` (optional) | Instead of using one method argument per column, all columns are provided as a object, either just named by `str`, or named by `str` and prepared with the given factory (since 2.3.0) | `"test_data"`, `("test_data", my_obj_factory)` |
75
76
 
76
77
  ## CSV Format
77
78
 
@@ -17,3 +17,11 @@ class PytestVersionTooOldException(RuntimeError):
17
17
 
18
18
  See the exception message for more details.
19
19
  """
20
+
21
+
22
+ class ParametrizationConfigurationException(RuntimeError):
23
+ """
24
+ This exception is thrown when the configuration is invalid.
25
+
26
+ See the exception message for more details.
27
+ """
@@ -10,6 +10,7 @@ from warnings import warn
10
10
  import pytest
11
11
  from _pytest.mark import MarkDecorator
12
12
 
13
+ from _ptcsvp.exception import ParametrizationConfigurationException
13
14
  from _ptcsvp.plugin import BASE_DIR_KEY, SKIP_EMPTY_KEY, SKIP_MISSING_KEY, Plugin
14
15
  from _ptcsvp.varname import make_name_valid
15
16
  from pytest_csv_params.dialect import CsvParamsDefaultDialect
@@ -19,6 +20,7 @@ from pytest_csv_params.exception import (
19
20
  CsvParamsDataFileInvalid,
20
21
  CsvParamsDataFileNotFound,
21
22
  )
23
+ from pytest_csv_params.object import TestCaseDataElementObject, TestCaseDataElementType
22
24
  from pytest_csv_params.types import (
23
25
  BaseDir,
24
26
  CsvDialect,
@@ -27,6 +29,7 @@ from pytest_csv_params.types import (
27
29
  DictionaryName,
28
30
  HeaderRenames,
29
31
  IdColName,
32
+ ParametersObjectConfiguration,
30
33
  SkipConfig,
31
34
  )
32
35
  from pytest_csv_params.warning import CsvParamsOnlyOneColumnIsUsedAsIdAndDataWarning
@@ -106,6 +109,7 @@ def add_parametrization( # pylint: disable=too-many-arguments
106
109
  skip_when_missing_csv_file: SkipConfig = None,
107
110
  skip_when_empty_csv_file: SkipConfig = None,
108
111
  parameters_as_dictionary: DictionaryName = None,
112
+ parameters_as_object: ParametersObjectConfiguration = None,
109
113
  ) -> MarkDecorator:
110
114
  """
111
115
  Parametrize a test function with data from a CSV file.
@@ -122,6 +126,9 @@ def add_parametrization( # pylint: disable=too-many-arguments
122
126
  :param skip_when_missing_csv_file: Let tests automatically skip when CSV source is missing (since 2.1.0)
123
127
  :param skip_when_empty_csv_file: Let tests automatically skip when CSV source does not contain any test data (since 2.1.0)
124
128
  :param parameters_as_dictionary: Instead of using one argument per field, all arguments are passed as a dictionary with the given name (since 2.2.0)
129
+ :param parameters_as_object: Instead of using one argument per field, all arguments are passed as an object with the given name, or with the given name and created by the given factory (since 2.5.0)
130
+
131
+ :raises ParametersObjectConfiguration: When parameters_as_dictionary and parameters_as_object are used at the same time
125
132
 
126
133
  :returns: :meth:`pytest.mark.parametrize` mark decorator, filled with all the data from the CSV.
127
134
  """
@@ -186,8 +193,26 @@ def add_parametrization( # pylint: disable=too-many-arguments
186
193
  id_data = None
187
194
  if id_col is not None:
188
195
  id_data = [tc_data["test_id"] for tc_data in data]
196
+ if parameters_as_dictionary is not None and parameters_as_object is not None:
197
+ raise ParametrizationConfigurationException(
198
+ "it is not possible to use parameters_as_dictionary and parameters_as_object at the same time"
199
+ )
200
+ param_header_name = "_"
189
201
  if parameters_as_dictionary is not None:
190
202
  param_header_name = make_name_valid(parameters_as_dictionary)
203
+ elif parameters_as_object is not None:
204
+ if isinstance(parameters_as_object, str):
205
+ param_header_name = make_name_valid(parameters_as_object)
206
+ elif isinstance(parameters_as_object, tuple):
207
+ if len(parameters_as_object) != 2:
208
+ raise ParametrizationConfigurationException("parameters_as_object must be a tuple of length 2")
209
+ if isinstance(parameters_as_object[0], str):
210
+ param_header_name = make_name_valid(parameters_as_object[0])
211
+ else:
212
+ raise ParametrizationConfigurationException("parameters_as_object[0] must be a string")
213
+ else:
214
+ raise ParametrizationConfigurationException("parameters_as_object must be a string or a tuple")
215
+ if parameters_as_dictionary is not None:
191
216
  list_of_dicts: list[dict[str, Any]] = []
192
217
  for tc_element in [tc_data["data"] for tc_data in data]:
193
218
  list_of_dicts.append(dict(zip(headers, tc_element)))
@@ -196,4 +221,29 @@ def add_parametrization( # pylint: disable=too-many-arguments
196
221
  [pytest.param(d) for d in list_of_dicts],
197
222
  ids=id_data,
198
223
  )
224
+ elif parameters_as_object is not None:
225
+ object_factory = lambda: TestCaseDataElementObject()
226
+ if isinstance(parameters_as_object, tuple):
227
+ object_factory = parameters_as_object[1]
228
+ list_of_objects: list[TestCaseDataElementType] = []
229
+ for tc_element in [tc_data["data"] for tc_data in data]:
230
+ try:
231
+ tc_obj = object_factory()
232
+ except TypeError:
233
+ raise ParametrizationConfigurationException(
234
+ "parameters_as_object[1] must be a TestCaseDataObjectFactory"
235
+ )
236
+ for idx, element in enumerate(tc_element):
237
+ try:
238
+ tc_obj.register_value(headers[idx], element)
239
+ except (AttributeError, TypeError):
240
+ raise ParametrizationConfigurationException(
241
+ "parameters_as_object[1] must be a TestCaseDataObjectFactory"
242
+ )
243
+ list_of_objects.append(tc_obj)
244
+ return pytest.mark.parametrize(
245
+ param_header_name,
246
+ [pytest.param(o) for o in list_of_objects],
247
+ ids=id_data,
248
+ )
199
249
  return pytest.mark.parametrize(headers, [tc_data["data"] for tc_data in data], ids=id_data)
@@ -26,7 +26,7 @@ def check_python_version(min_version: tuple[int, int] = (3, 10), deprecation_bel
26
26
  raise PythonVersionTooOldException(f"At least Python {'.'.join(map(str, min_version))} required")
27
27
 
28
28
  if sys.version_info < deprecation_below:
29
- warnings.warn(f"Python {'.'.join(map(str, deprecation_below))} is deprecated", DeprecationWarning)
29
+ warnings.warn(f"Python <{'.'.join(map(str, deprecation_below))} is deprecated", DeprecationWarning)
30
30
 
31
31
 
32
32
  def check_pytest_version(min_version: tuple[int, int] = (8, 3), deprecation_below: tuple[int, int] = (9, 0)) -> None:
@@ -47,4 +47,4 @@ def check_pytest_version(min_version: tuple[int, int] = (8, 3), deprecation_belo
47
47
  raise PytestVersionTooOldException(f"At least Pytest {pytest_min_version} required")
48
48
 
49
49
  if parsed_actual_version < parse(".".join(map(str, deprecation_below))):
50
- warnings.warn(f"Pytest {'.'.join(map(str, deprecation_below))} is deprecated", DeprecationWarning)
50
+ warnings.warn(f"Pytest <{'.'.join(map(str, deprecation_below))} is deprecated", DeprecationWarning)
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "pytest-csv-params"
3
- version = "2.2.5"
3
+ version = "2.3.0"
4
4
  description = "Pytest plugin for Test Case Parametrization with CSV files"
5
5
  authors = [
6
6
  { name = "Juergen Edelbluth", email = "csv_params@jued.de" },
@@ -75,8 +75,10 @@ homepage = "https://git.codebau.dev/pytest-plugins/pytest-csv-params"
75
75
  [tool.pytest.ini_options]
76
76
  addopts = "--cov --cov-report=term-missing --cov-report=xml --junitxml=test-reports/pytest_csv_params.xml"
77
77
  filterwarnings=[
78
- "ignore:.*zipimport.*",
79
- "ignore:Creating a LegacyVersion has been deprecated and will be removed in the next major release",
78
+ "ignore::_pytest.warning_types.PytestRemovedIn10Warning",
79
+ "ignore:Python <3.11 is deprecated",
80
+ "ignore:Pytest <9.0 is deprecated",
81
+ "ignore::pytest_csv_params.warning.CsvParamsOnlyOneColumnIsUsedAsIdAndDataWarning",
80
82
  ]
81
83
  junit_family = "xunit2"
82
84
  junit_logging = "all"
@@ -0,0 +1,43 @@
1
+ """
2
+ This module defines the smart object as test case data object.
3
+ """
4
+
5
+ from collections.abc import Callable
6
+ from typing import Any
7
+
8
+
9
+ class TestCaseDataElementType:
10
+ """
11
+ This class represents an abstract test case data element.
12
+ """
13
+
14
+ def register_value(self, key: str, value: Any):
15
+ """
16
+ This method registers a value for a given key and is called by the csv_params plugin in order to populate the
17
+ test case data object.
18
+ """
19
+ raise NotImplementedError("register_value is not implemented")
20
+
21
+
22
+ class TestCaseDataElementObject(TestCaseDataElementType):
23
+ """
24
+ This class represents a test case data element.
25
+ """
26
+
27
+ def register_value(self, key: str, value: Any):
28
+ """
29
+ Simply add the value as an attribute to the instance.
30
+ """
31
+ setattr(self, key, value)
32
+
33
+ def __getattribute__(self, name: str, /) -> Any:
34
+ return object.__getattribute__(self, name)
35
+
36
+ def __getattr__(self, name: str) -> None:
37
+ raise AttributeError(f"Attribute '{name}' not found")
38
+
39
+
40
+ TestCaseDataObjectFactory = Callable[[], TestCaseDataElementType]
41
+ """
42
+ This is how a factory function has to look like to build a test case data object.
43
+ """
@@ -4,20 +4,32 @@ This module contains all the code to initialize the pytest plugin. This is the e
4
4
  `pyproject.toml` as `pytest11`.
5
5
  """
6
6
 
7
+ from _pytest.config import Config
8
+
7
9
  from _ptcsvp.cmdline import pytest_addoption as _pytest_addoption
8
10
  from _ptcsvp.configure import pytest_configure as _pytest_configure
9
11
  from _ptcsvp.configure import pytest_unconfigure as _pytest_unconfigure
10
12
  from _ptcsvp.version import check_pytest_version, check_python_version
11
13
 
12
- # Fist at all, check if the python & pytest version matches
13
- check_python_version()
14
- check_pytest_version()
14
+
15
+ # First at all, check if the python & pytest version matches
16
+ def version_check():
17
+ """
18
+ Check if the python & pytest version matches the required versions
19
+ """
20
+ check_python_version()
21
+ check_pytest_version()
22
+
15
23
 
16
24
  # Basic config
17
- pytest_configure = _pytest_configure
18
- """
19
- Hook our :meth:`_ptcsvp.configure.pytest_configure` method to setup the plugin setup
20
- """
25
+ def pytest_configure(config: Config, plugin_name: str = "csv_params"):
26
+ """
27
+ Hook our :meth:`_ptcsvp.configure.pytest_configure` method to setup the plugin setup,
28
+ after executing version checks.
29
+ """
30
+ version_check()
31
+ _pytest_configure(config, plugin_name)
32
+
21
33
 
22
34
  pytest_unconfigure = _pytest_unconfigure
23
35
  """
@@ -8,6 +8,8 @@ import csv
8
8
  from collections.abc import Callable
9
9
  from typing import Any
10
10
 
11
+ from pytest_csv_params.object import TestCaseDataObjectFactory
12
+
11
13
  DataCast = Callable[[str], Any]
12
14
  """
13
15
  A :class:`DataCast` describes how a data casting callable must be implemented. It requires one parameter of the type
@@ -77,3 +79,13 @@ DictionaryName = str | None
77
79
  The :class:`DictionaryName` describes the type of the `parameters_as_dictionary` parameter of the
78
80
  :meth:`~pytest_csv_params.decorator.csv_params` decorator. It is just an optional :class:`str`.
79
81
  """
82
+
83
+ ParametersObjectConfiguration = str | tuple[str, TestCaseDataObjectFactory] | None
84
+ """
85
+ The :class:`ParametersObjectConfiguration` describes the type of the `parameters_as_object` parameter of the
86
+ :meth:`~pytest_csv_params.decorator.csv_params` decorator.
87
+
88
+ - It can be either a :class:`str` which describes only the parameter name.
89
+ - It can be a :class:`tuple` of :class:`str` and :class:`TestCaseDataObjectFactory` to describe the name and the factory.
90
+ - Default is :obj:`None`, to disable the feature.
91
+ """