yaml-test-params 0.1.0__py3-none-any.whl

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.
@@ -0,0 +1,29 @@
1
+ from .args_loader import load_parametrize_args
2
+ from .models import (
3
+ BaseTestCase,
4
+ BaseTestConfig,
5
+ BaseTestConfigCollection,
6
+ ListConfig,
7
+ ParametrizeInteger,
8
+ ParametrizeIntegerConfigModels,
9
+ ParametrizeString,
10
+ ParametrizeStringConfigModels,
11
+ RangeConfig,
12
+ ValueConfig,
13
+ )
14
+ from .parametrize_args import ParametrizeArgs
15
+
16
+ __all__ = [
17
+ "BaseTestCase",
18
+ "BaseTestConfig",
19
+ "BaseTestConfigCollection",
20
+ "ListConfig",
21
+ "ParametrizeArgs",
22
+ "ParametrizeInteger",
23
+ "ParametrizeIntegerConfigModels",
24
+ "ParametrizeString",
25
+ "ParametrizeStringConfigModels",
26
+ "RangeConfig",
27
+ "ValueConfig",
28
+ "load_parametrize_args",
29
+ ]
@@ -0,0 +1,29 @@
1
+ import pathlib
2
+ from typing import Type, TypeVar, Union
3
+
4
+ import yaml
5
+
6
+ from .models import BaseTestConfigCollection
7
+ from .parametrize_args import ParametrizeArgs
8
+
9
+
10
+ TestConfigCollection = TypeVar(
11
+ "TestConfigCollection",
12
+ bound=BaseTestConfigCollection,
13
+ )
14
+
15
+
16
+ def load_parametrize_args(
17
+ path_to_configs: Union[pathlib.Path, str],
18
+ config_collection_model: Type[TestConfigCollection],
19
+ collection_name: str,
20
+ ) -> ParametrizeArgs:
21
+ with open(path_to_configs, "r", encoding="utf-8") as f:
22
+ yaml_config = yaml.safe_load(f) # type: ignore[attr-defined]
23
+ test_configs = config_collection_model.model_validate(yaml_config)
24
+
25
+ for cfg in test_configs.collection:
26
+ if cfg.name == collection_name:
27
+ return cfg.generate_parametrize_args()
28
+
29
+ raise ValueError(f"No test configuration found for collection name: {collection_name}")
@@ -0,0 +1,209 @@
1
+ from abc import ABC, abstractmethod
2
+ from itertools import product
3
+ from typing import Union, List, get_args, get_origin
4
+
5
+ from pydantic import BaseModel, Field
6
+
7
+ from .parametrize_args import ParametrizeArgs
8
+
9
+
10
+ class ValueConfig(BaseModel):
11
+ """Configuration for parameters with a simple value"""
12
+
13
+ value: Union[int, str] = Field(..., alias="value")
14
+
15
+ model_config = {"populate_by_name": True}
16
+
17
+ def __str__(self) -> str:
18
+ return str(self.value)
19
+
20
+
21
+ class ListConfig(BaseModel):
22
+ """Configuration for parameters with a list of values"""
23
+
24
+ values: list[Union[int, str]] = Field(..., alias="values")
25
+
26
+ model_config = {"populate_by_name": True}
27
+
28
+ def __str__(self) -> str:
29
+ return str(self.values)
30
+
31
+
32
+ class RangeConfig(BaseModel):
33
+ """Configuration for parameters with a range (from/to/step)"""
34
+
35
+ from_: int = Field(..., alias="from")
36
+ to: int
37
+ step: int = Field(..., gt=0)
38
+
39
+ model_config = {"populate_by_name": True}
40
+
41
+ def __str__(self) -> str:
42
+ return f"From {self.from_} To {self.to} Step {self.step}"
43
+
44
+
45
+ ParametrizeIntegerConfigModels = Union[RangeConfig, ListConfig, ValueConfig]
46
+ ParametrizeStringConfigModels = Union[ListConfig, ValueConfig]
47
+ ParametrizeInteger = Union[int, ParametrizeIntegerConfigModels]
48
+ ParametrizeString = Union[str, ParametrizeStringConfigModels]
49
+
50
+
51
+ class BaseTestCase(BaseModel, ABC):
52
+ test_name: str
53
+
54
+ @property
55
+ @abstractmethod
56
+ def arg_id(self) -> str:
57
+ return self.test_name
58
+
59
+
60
+ class BaseTestConfig(BaseModel):
61
+ name: str
62
+ test_cases: list[BaseTestCase]
63
+
64
+ @staticmethod
65
+ def _generate_range_values(range_config: RangeConfig) -> list[int]:
66
+ """
67
+ Generate a list of values from a RangeConfig.
68
+
69
+ Args:
70
+ range_config: RangeConfig object with from_, to, and step
71
+
72
+ Returns:
73
+ List of integer values in the range
74
+ """
75
+ return list(range(range_config.from_, range_config.to + 1, range_config.step))
76
+
77
+ @staticmethod
78
+ def _format_range_values(values: tuple) -> str:
79
+ """
80
+ Format range values into a string for test naming.
81
+
82
+ Args:
83
+ values: Tuple of values
84
+
85
+ Returns:
86
+ Formatted string representation
87
+ """
88
+ return "_".join(str(v) for v in values)
89
+
90
+ @property
91
+ def test_case_type(self) -> BaseTestCase:
92
+ raw_type = self.__annotations__["test_cases"]
93
+ origin = get_origin(raw_type)
94
+
95
+ if origin is None or origin not in (list, List):
96
+ raise TypeError(f"Field 'test_cases' has to be List[…] , not {origin!r}")
97
+
98
+ (inner_type,) = get_args(raw_type)
99
+ return inner_type
100
+
101
+ def _expand_range_configs(self, test_case: BaseTestCase) -> list[BaseTestCase]:
102
+ """
103
+ Expand a test case with RangeConfig and ListConfig values into multiple test cases.
104
+
105
+ Args:
106
+ test_case: Single BaseTestCase with potential RangeConfig or ListConfig values
107
+
108
+ Returns:
109
+ List of expanded BaseTestCase objects
110
+ """
111
+ # Check if any of the parameters use ValueConfig, ListConfig or RangeConfig
112
+ params_with_configs = []
113
+
114
+ fields = getattr(type(test_case), "model_fields")
115
+
116
+ for key in fields.keys():
117
+ value = getattr(test_case, key)
118
+ if isinstance(value, (ValueConfig, ListConfig, RangeConfig)):
119
+ params_with_configs.append((key, value))
120
+
121
+ # If no value configs, return the original test case
122
+ if not params_with_configs:
123
+ return [test_case]
124
+
125
+ # Get all possible values for each parameter
126
+ param_values = []
127
+ param_names = []
128
+
129
+ for param_name, config in params_with_configs:
130
+ values: list[int] | list[int | str]
131
+ if isinstance(config, ValueConfig):
132
+ values = [config.value]
133
+ elif isinstance(config, ListConfig):
134
+ values = config.values
135
+ elif isinstance(config, RangeConfig):
136
+ values = self._generate_range_values(config)
137
+ else:
138
+ raise ValueError("Unsupported configuration type.")
139
+ param_values.append(values)
140
+ param_names.append(param_name)
141
+
142
+ # Generate all combinations
143
+ combinations = list(product(*param_values))
144
+
145
+ # Create new test cases for each combination
146
+ expanded_cases = []
147
+ for combo in combinations:
148
+ # Create a copy of the original test case
149
+ new_test_case = test_case.model_copy(deep=True)
150
+
151
+ # Update the parameters with specific values
152
+ for i, param_name in enumerate(param_names):
153
+ setattr(new_test_case, param_name, ValueConfig(value=combo[i]))
154
+
155
+ # Update test name to reflect the specific values
156
+ new_test_case.test_name = f"{test_case.test_name}__{self._format_range_values(combo)}"
157
+
158
+ expanded_cases.append(new_test_case)
159
+
160
+ return expanded_cases
161
+
162
+ def generate_parametrize_args(self) -> ParametrizeArgs:
163
+ """
164
+ Generate parametrize args (test_cases) based on the BaseTestCase model,
165
+ handling value configs appropriately.
166
+
167
+ Returns:
168
+ MetafuncParametrizeArgs object
169
+ """
170
+
171
+ parametrize_args = ParametrizeArgs()
172
+ parametrize_args.init_arg_names(self.test_case_type)
173
+
174
+ for test_case in self.test_cases:
175
+ # Handle RangeConfig values by expanding them into individual test cases
176
+ expanded_test_cases = self._expand_range_configs(test_case)
177
+
178
+ for expanded_case in expanded_test_cases:
179
+ # Create a tuple of parameters for this test case
180
+ arg_values = []
181
+
182
+ for key in parametrize_args.keys:
183
+ attr = getattr(expanded_case, key)
184
+ if isinstance(attr, ValueConfig):
185
+ arg_values.append(attr.value)
186
+ else:
187
+ arg_values.append(attr)
188
+
189
+ parametrize_args.add_params(arg_id=expanded_case.arg_id, arg_values=tuple(arg_values))
190
+
191
+ return parametrize_args
192
+
193
+
194
+ class BaseTestConfigCollection(BaseModel):
195
+ collection: list[BaseTestConfig]
196
+
197
+
198
+ __all__ = [
199
+ "ValueConfig",
200
+ "ListConfig",
201
+ "RangeConfig",
202
+ "ParametrizeIntegerConfigModels",
203
+ "ParametrizeStringConfigModels",
204
+ "ParametrizeInteger",
205
+ "ParametrizeString",
206
+ "BaseTestCase",
207
+ "BaseTestConfig",
208
+ "BaseTestConfigCollection",
209
+ ]
@@ -0,0 +1,52 @@
1
+ from dataclasses import asdict, dataclass, field
2
+ from typing import Type, Union
3
+
4
+ from pydantic import BaseModel
5
+
6
+
7
+ ERROR_INIT_ARGS_MSG = "Argument names are not initialized"
8
+
9
+
10
+ def _filter_private(items: list) -> dict:
11
+ return {k: v for k, v in items if not k.startswith("_")}
12
+
13
+
14
+ @dataclass
15
+ class ParametrizeArgs:
16
+ argnames: Union[str, None] = None
17
+ argvalues: list[tuple] = field(default_factory=list)
18
+ ids: list[str] = field(default_factory=list)
19
+ _model_cls: Union[Type[BaseModel], BaseModel] = None
20
+ _arg_keys: Union[tuple, None] = None
21
+
22
+ def init_arg_names(self, model_cls: BaseModel) -> None:
23
+ if self.argnames is None:
24
+ model_cls = model_cls if isinstance(model_cls, type) else type(model_cls)
25
+ if hasattr(model_cls, "model_fields"):
26
+ self._model_cls = model_cls
27
+ fields = getattr(model_cls, "model_fields")
28
+ self._arg_keys = tuple(fields.keys())
29
+ self.argnames = ", ".join(fields.keys())
30
+ else:
31
+ raise ValueError("No pydantic fields found for model")
32
+ else:
33
+ raise ValueError("Argname already set")
34
+
35
+ def add_params(self, arg_id: str, arg_values: tuple) -> None:
36
+ self.ids.append(arg_id)
37
+ self.argvalues.append(arg_values)
38
+
39
+ @property
40
+ def keys(self) -> tuple:
41
+ if self._arg_keys is None:
42
+ raise ValueError(ERROR_INIT_ARGS_MSG)
43
+ return self._arg_keys
44
+
45
+ @property
46
+ def keys_set(self) -> set:
47
+ if self._arg_keys is None:
48
+ raise ValueError(ERROR_INIT_ARGS_MSG)
49
+ return set(self._arg_keys)
50
+
51
+ def to_dict(self) -> dict:
52
+ return asdict(self, dict_factory=_filter_private)
@@ -0,0 +1 @@
1
+
@@ -0,0 +1,454 @@
1
+ Metadata-Version: 2.4
2
+ Name: yaml-test-params
3
+ Version: 0.1.0
4
+ Summary: Generate pytest and unittest parameters from YAML configuration files.
5
+ Project-URL: Homepage, https://github.com/fomenko-ai/yaml-test-params
6
+ Project-URL: Repository, https://github.com/fomenko-ai/yaml-test-params
7
+ Project-URL: Issues, https://github.com/fomenko-ai/yaml-test-params/issues
8
+ Author-email: Aleksei Fomenko <fomenko_ai@proton.me>
9
+ License: MIT
10
+ License-File: LICENSE.txt
11
+ Keywords: parametrize,pydantic,pytest,testing,unittest,yaml
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.9
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Programming Language :: Python :: 3.13
21
+ Classifier: Topic :: Software Development :: Testing
22
+ Classifier: Typing :: Typed
23
+ Requires-Python: >=3.9
24
+ Requires-Dist: pydantic>=2.0
25
+ Requires-Dist: pyyaml>=6.0.2
26
+ Provides-Extra: dev
27
+ Requires-Dist: pytest>=8.4.2; extra == 'dev'
28
+ Description-Content-Type: text/markdown
29
+
30
+ # yaml-test-params
31
+
32
+ [![PyPI - Python Version](https://img.shields.io/pypi/pyversions/yaml-test-params)](https://pypi.org/project/yaml-test-params/)
33
+ [![PyPI - License](https://img.shields.io/pypi/l/yaml-test-params)](LICENSE.txt)
34
+
35
+ A Python library for dynamic test parameter generation from YAML configuration files. This library enables flexible, data-driven test scenarios by combining Pydantic models with pytest's parametrize functionality or Python's built-in unittest library.
36
+
37
+ ## Features
38
+
39
+ - **Configuration-driven tests**: Define test parameters in YAML files instead of hardcoding them
40
+ - **Pydantic validation**: Type-safe configuration models with automatic validation
41
+ - **Automatic test expansion**: Range configurations are automatically expanded into individual test cases
42
+ - **Seamless pytest integration**: Works with pytest's native parametrize mechanism
43
+ - **unittest support**: Generated parameter sets can be iterated in standard `unittest.TestCase` tests
44
+ - **Flexible parameter types**: Support for simple values, lists, and ranges
45
+ - **Custom test case data**: `test_cases` can include any YAML data types accepted by your Pydantic models
46
+
47
+ ## Installation
48
+
49
+ ```bash
50
+ uv add yaml-test-params
51
+ ```
52
+
53
+ **Dependencies:**
54
+
55
+ - Python >= 3.9
56
+ - pydantic >= 2.0
57
+ - pyyaml >= 6.0.2
58
+
59
+ For local development and examples, install the development extra:
60
+
61
+ ```bash
62
+ uv sync --extra dev
63
+ ```
64
+
65
+ ## How It Works
66
+
67
+ The project supports dynamic parameter generation for tests from configuration files, enabling flexible test scenarios.
68
+
69
+ ### Workflow
70
+
71
+ 1. **Base Pydantic models** define the structure of test cases and the YAML configuration file structure.
72
+ 2. **YAML configuration** defines test parameters and scenarios.
73
+ 3. **Test runner integration** uses the generated arguments either through a `pytest_generate_tests` hook or directly inside `unittest.TestCase`.
74
+
75
+ ## Quick Start
76
+
77
+ ### Step 1: Define Your Models
78
+
79
+ Create Pydantic models that represent your test case structure:
80
+
81
+ ```python
82
+ from yaml_test_params.models import (
83
+ BaseTestCase,
84
+ BaseTestConfig,
85
+ BaseTestConfigCollection,
86
+ ParametrizeInteger,
87
+ ParametrizeString,
88
+ )
89
+
90
+
91
+ class ExampleTestCase(BaseTestCase):
92
+ test_name: str
93
+ integer: ParametrizeInteger
94
+ string: ParametrizeString
95
+
96
+ @property
97
+ def arg_id(self) -> str:
98
+ return self.test_name
99
+
100
+
101
+ class ExampleTestConfig(BaseTestConfig):
102
+ test_cases: list[ExampleTestCase]
103
+
104
+
105
+ class ExampleTestConfigCollection(BaseTestConfigCollection):
106
+ collection: list[ExampleTestConfig]
107
+ ```
108
+
109
+ ### Step 2: Create YAML Configuration
110
+
111
+ Define your test parameters in a YAML file:
112
+
113
+ ```yaml
114
+ collection:
115
+ - name: examples
116
+ test_cases:
117
+ - test_name: int_1,2,3__str_a
118
+ integer:
119
+ values: [1, 2, 3]
120
+ string: a
121
+
122
+ - test_name: int_42__str_a,b,c
123
+ integer: 42
124
+ string:
125
+ values: [a, b, c]
126
+
127
+ - test_name: int_1_10_1__str_a
128
+ integer:
129
+ from: 1
130
+ to: 10
131
+ step: 1
132
+ string: a
133
+
134
+ - test_name: int_1_10_2__str_a,b,c
135
+ integer:
136
+ from: 1
137
+ to: 10
138
+ step: 2
139
+ string:
140
+ values: [a, b, c]
141
+ ```
142
+
143
+ ### Step 3: Use Generated Parameters in Tests
144
+
145
+ You can use the generated parameters with either pytest or unittest.
146
+
147
+ #### Option A: Configure pytest Hook
148
+
149
+ Add the hook to your `conftest.py`:
150
+
151
+ ```python
152
+ import pytest
153
+
154
+ from yaml_test_params.args_loader import load_parametrize_args
155
+ from ..models import ExampleTestConfigCollection
156
+
157
+
158
+ def pytest_generate_tests(metafunc: pytest.Metafunc) -> None:
159
+ test_cls = getattr(metafunc, "cls", None)
160
+ if test_cls is None:
161
+ return
162
+
163
+ full_cls_name = f"{test_cls.__module__}.{test_cls.__qualname__}"
164
+
165
+ if (
166
+ full_cls_name == "examples.pytest_tests.test_examples.TestParametrizeExamples"
167
+ and metafunc.function.__name__ == "test_values"
168
+ ):
169
+ parametrize_args = load_parametrize_args(
170
+ path_to_configs="examples/collection.yaml",
171
+ config_collection_model=ExampleTestConfigCollection,
172
+ collection_name="examples",
173
+ )
174
+ needed_args = parametrize_args.keys_set
175
+ if needed_args.issubset(set(metafunc.fixturenames)):
176
+ metafunc.parametrize(**parametrize_args.to_dict())
177
+ ```
178
+
179
+ Then write tests that accept the parameters defined in your configuration:
180
+
181
+ ```python
182
+ class TestParametrizeExamples:
183
+ """Test class demonstrating pytest parametrize with integer and string variables."""
184
+
185
+ def test_values(self, test_name: str, integer: int, string: str):
186
+ """Test that integer and string parameters are correctly passed."""
187
+ print(f"\n==============\n")
188
+ print(f"Test name: {test_name}")
189
+ print(f"integer: {integer}\nstring: {string}")
190
+ ```
191
+
192
+ Run the pytest example:
193
+
194
+ ```bash
195
+ uv run pytest -s examples/pytest_tests
196
+ ```
197
+
198
+ #### Option B: Use unittest
199
+
200
+ Load the generated arguments once and iterate over them in a `unittest.TestCase`:
201
+
202
+ ```python
203
+ import unittest
204
+
205
+ from yaml_test_params.args_loader import load_parametrize_args
206
+ from ..models import ExampleTestConfigCollection
207
+
208
+
209
+ parametrize_args = load_parametrize_args(
210
+ path_to_configs="examples/collection.yaml",
211
+ config_collection_model=ExampleTestConfigCollection,
212
+ collection_name="examples",
213
+ )
214
+
215
+
216
+ class TestParametrizeExamples(unittest.TestCase):
217
+ """Test class demonstrating unittest with generated YAML parameters."""
218
+
219
+ cases = parametrize_args.argvalues
220
+
221
+ def test_values(self):
222
+ """Test that integer and string parameters are correctly passed."""
223
+ for test_name, integer, string in self.cases:
224
+ with self.subTest(test_name=test_name, integer=integer, string=string):
225
+ print(f"\n==============\n")
226
+ print(f"Test name: {test_name}")
227
+ print(f"integer: {integer}\nstring: {string}")
228
+ ```
229
+
230
+ Run the unittest example:
231
+
232
+ ```bash
233
+ uv run python -m unittest examples.unittest_tests.test_examples
234
+ ```
235
+
236
+ See the full examples in [`examples/pytest_tests`](examples/pytest_tests/) and [`examples/unittest_tests`](examples/unittest_tests/).
237
+
238
+ ## Configuration Types
239
+
240
+ The library supports three types of parameter configurations:
241
+
242
+ `test_cases` may also contain any additional fields and data types that can be
243
+ represented in YAML and validated by your Pydantic models, such as booleans,
244
+ lists, dictionaries, nested models, dates, or enums. These fields are passed to
245
+ generated test arguments according to the model definition.
246
+
247
+ The built-in parametrization config models currently expand only `int` and
248
+ `str` values through `ParametrizeInteger` and `ParametrizeString`.
249
+
250
+ ```python
251
+ class ExampleTestCase(BaseTestCase):
252
+ integer: ParametrizeInteger
253
+ string: ParametrizeString
254
+ list_of_types: list[int, str, float]
255
+ ```
256
+
257
+ ```yaml
258
+ test_cases:
259
+ - test_name: int_1_10_2__str_a,b,c__42_abc_0.07
260
+ integer:
261
+ from: 1
262
+ to: 10
263
+ step: 2
264
+ string:
265
+ values: [a, b, c]
266
+ list_of_types: [42, abc, 0.07]
267
+ ```
268
+
269
+ ### Simple Value
270
+
271
+ A single value for a parameter:
272
+
273
+ ```yaml
274
+ integer: 42
275
+ string: "hello"
276
+ ```
277
+
278
+ ### List of Values
279
+
280
+ Multiple discrete values:
281
+
282
+ ```yaml
283
+ integer:
284
+ values: [1, 2, 3]
285
+ string:
286
+ values: [a, b, c]
287
+ ```
288
+
289
+ ### Range
290
+
291
+ A range of values with start, end, and step:
292
+
293
+ ```yaml
294
+ integer:
295
+ from: 1
296
+ to: 10
297
+ step: 2
298
+ ```
299
+
300
+ This generates values: `[1, 3, 5, 7, 9]`.
301
+
302
+ `step` must be a positive integer.
303
+
304
+ ## Available Models
305
+
306
+ ### ValueConfig
307
+
308
+ Configuration for parameters with a simple value:
309
+
310
+ ```python
311
+ class ValueConfig(BaseModel):
312
+ value: int | str
313
+ ```
314
+
315
+ ### ListConfig
316
+
317
+ Configuration for parameters with a list of values:
318
+
319
+ ```python
320
+ class ListConfig(BaseModel):
321
+ values: list[int | str]
322
+ ```
323
+
324
+ ### RangeConfig
325
+
326
+ Configuration for parameters with a range:
327
+
328
+ ```python
329
+ class RangeConfig(BaseModel):
330
+ from_: int
331
+ to: int
332
+ step: int
333
+ ```
334
+
335
+ ### Type Aliases
336
+
337
+ ```python
338
+ ParametrizeIntegerConfigModels = RangeConfig | ListConfig | ValueConfig
339
+ ParametrizeStringConfigModels = ListConfig | ValueConfig
340
+ ParametrizeInteger = int | ParametrizeIntegerConfigModels
341
+ ParametrizeString = str | ParametrizeStringConfigModels
342
+ ```
343
+
344
+ ### Base Classes
345
+
346
+ ```python
347
+ class BaseTestCase(BaseModel, ABC):
348
+ test_name: str
349
+
350
+ class BaseTestConfig(BaseModel):
351
+ name: str
352
+ test_cases: list[BaseTestCase]
353
+
354
+ class BaseTestConfigCollection(BaseModel):
355
+ collection: list[BaseTestConfig]
356
+ ```
357
+
358
+ ## API Reference
359
+
360
+ ### `load_parametrize_args()`
361
+
362
+ Loads and parses a YAML configuration file and returns parametrize arguments.
363
+
364
+ ```python
365
+ def load_parametrize_args(
366
+ path_to_configs: Union[pathlib.Path, str],
367
+ config_collection_model: Type[TestConfigCollection],
368
+ collection_name: str,
369
+ ) -> ParametrizeArgs:
370
+ ```
371
+
372
+ **Parameters:**
373
+
374
+ | Parameter | Type | Description |
375
+ |-----------|------|-------------|
376
+ | `path_to_configs` | `pathlib.Path \| str` | Path to the YAML configuration file |
377
+ | `config_collection_model` | `Type[TestConfigCollection]` | Pydantic model class for parsing the configuration |
378
+ | `collection_name` | `str` | Name of the test collection to use from the configuration |
379
+
380
+ **Returns:** `ParametrizeArgs` object containing parametrize arguments
381
+
382
+ **Raises:** `ValueError` if no configuration is found for the given collection name
383
+
384
+ ### `ParametrizeArgs`
385
+
386
+ Dataclass holding generated test parameters for pytest and unittest integrations:
387
+
388
+ ```python
389
+ @dataclass
390
+ class ParametrizeArgs:
391
+ argnames: str | None = None
392
+ argvalues: list[tuple] = field(default_factory=list)
393
+ ids: list[str] = field(default_factory=list)
394
+ ```
395
+
396
+ **Methods:**
397
+
398
+ | Method | Description |
399
+ |--------|-------------|
400
+ | `init_arg_names(model_cls)` | Initialize argument names from a Pydantic model |
401
+ | `add_params(arg_id, arg_values)` | Add a parameterized test case |
402
+ | `to_dict()` | Convert to dictionary for `metafunc.parametrize()` |
403
+ | `keys` | Property returning the tuple of argument keys |
404
+ | `keys_set` | Property returning the set of argument keys |
405
+
406
+ ## Exported Symbols
407
+
408
+ ```python
409
+ __all__ = [
410
+ "BaseTestCase",
411
+ "BaseTestConfig",
412
+ "BaseTestConfigCollection",
413
+ "ListConfig",
414
+ "ParametrizeArgs",
415
+ "ParametrizeInteger",
416
+ "ParametrizeIntegerConfigModels",
417
+ "ParametrizeString",
418
+ "ParametrizeStringConfigModels",
419
+ "RangeConfig",
420
+ "ValueConfig",
421
+ "load_parametrize_args",
422
+ ]
423
+ ```
424
+
425
+ ## Project Structure
426
+
427
+ ```
428
+ yaml-test-params/
429
+ ├── examples/
430
+ │ ├── collection.yaml
431
+ │ ├── models.py
432
+ │ ├── pytest_tests/
433
+ │ │ ├── conftest.py
434
+ │ │ └── test_examples.py
435
+ │ └── unittest_tests/
436
+ │ └── test_examples.py
437
+ ├── tests/
438
+ │ ├── test_args_loader.py
439
+ │ ├── test_models.py
440
+ │ └── test_parametrize_args.py
441
+ ├── yaml_test_params/
442
+ │ ├── __init__.py
443
+ │ ├── args_loader.py # YAML configuration loader
444
+ │ ├── models.py # Pydantic model definitions
445
+ │ └── parametrize_args.py # Parametrize arguments dataclass
446
+ ├── CONTRIBUTING.md
447
+ ├── LICENSE.txt
448
+ ├── pyproject.toml
449
+ └── README.md
450
+ ```
451
+
452
+ ## License
453
+
454
+ MIT
@@ -0,0 +1,9 @@
1
+ yaml_test_params/__init__.py,sha256=JDcCzCarO5AuGL2jXYda9WuCndJSq7zNZtsg899SLHQ,676
2
+ yaml_test_params/args_loader.py,sha256=G14mFL9OWMxMPMcjsgt2laEMAGatSF84-VLchkrwWZA,871
3
+ yaml_test_params/models.py,sha256=aoDPyzZ7FaoGZMppUs4b8JqD6YJXuzut5-MgeRmUqd4,6476
4
+ yaml_test_params/parametrize_args.py,sha256=HtbghZsa8tXkrZsp9oA87hnLGoBc1wdmTYd1Neyp64c,1714
5
+ yaml_test_params/py.typed,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
6
+ yaml_test_params-0.1.0.dist-info/METADATA,sha256=K6aLCk32dDFq3EZzm195QJ6sooNq5ZKjsMUIOLKuBYs,12248
7
+ yaml_test_params-0.1.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
8
+ yaml_test_params-0.1.0.dist-info/licenses/LICENSE.txt,sha256=F-35ycqPcYW243OjxMHCggr_AHQgZLX2zvtZgobVEvo,1072
9
+ yaml_test_params-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.27.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Aleksei Fomenko
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.