klab-pytest-toolkit-decorators 0.0.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.
@@ -0,0 +1,177 @@
1
+ # Created by https://www.toptal.com/developers/gitignore/api/python
2
+ # Edit at https://www.toptal.com/developers/gitignore?templates=python
3
+
4
+ ### Custom ###
5
+ pytest.xml
6
+ pytest-coverage.txt
7
+
8
+ ### Python ###
9
+ # Byte-compiled / optimized / DLL files
10
+ __pycache__/
11
+ *.py[cod]
12
+ *$py.class
13
+
14
+ # Distribution / packaging
15
+ .Python
16
+ build/
17
+ develop-eggs/
18
+ dist/
19
+ downloads/
20
+ eggs/
21
+ .eggs/
22
+ lib/
23
+ lib64/
24
+ parts/
25
+ sdist/
26
+ var/
27
+ wheels/
28
+ share/python-wheels/
29
+ *.egg-info/
30
+ .installed.cfg
31
+ *.egg
32
+ MANIFEST
33
+
34
+ # PyInstaller
35
+ # Usually these files are written by a python script from a template
36
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
37
+ *.manifest
38
+ *.spec
39
+
40
+ # Installer logs
41
+ pip-log.txt
42
+ pip-delete-this-directory.txt
43
+
44
+ # Unit test / coverage reports
45
+ htmlcov/
46
+ .tox/
47
+ .nox/
48
+ .coverage
49
+ .coverage.*
50
+ .cache
51
+ nosetests.xml
52
+ coverage.xml
53
+ *.cover
54
+ *.py,cover
55
+ .hypothesis/
56
+ .pytest_cache/
57
+ cover/
58
+
59
+ # Translations
60
+ *.mo
61
+ *.pot
62
+
63
+ # Django stuff:
64
+ *.log
65
+ local_settings.py
66
+ db.sqlite3
67
+ db.sqlite3-journal
68
+
69
+ # Flask stuff:
70
+ instance/
71
+ .webassets-cache
72
+
73
+ # Scrapy stuff:
74
+ .scrapy
75
+
76
+ # Sphinx documentation
77
+ docs/_build/
78
+
79
+ # PyBuilder
80
+ .pybuilder/
81
+ target/
82
+
83
+ # Jupyter Notebook
84
+ .ipynb_checkpoints
85
+
86
+ # IPython
87
+ profile_default/
88
+ ipython_config.py
89
+
90
+ # pyenv
91
+ # For a library or package, you might want to ignore these files since the code is
92
+ # intended to run in multiple environments; otherwise, check them in:
93
+ # .python-version
94
+
95
+ # pipenv
96
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
97
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
98
+ # having no cross-platform support, pipenv may install dependencies that don't work, or not
99
+ # install all needed dependencies.
100
+ #Pipfile.lock
101
+
102
+ # poetry
103
+ # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
104
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
105
+ # commonly ignored for libraries.
106
+ # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
107
+ #poetry.lock
108
+
109
+ # pdm
110
+ # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
111
+ #pdm.lock
112
+ # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
113
+ # in version control.
114
+ # https://pdm.fming.dev/#use-with-ide
115
+ .pdm.toml
116
+
117
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
118
+ __pypackages__/
119
+
120
+ # Celery stuff
121
+ celerybeat-schedule
122
+ celerybeat.pid
123
+
124
+ # SageMath parsed files
125
+ *.sage.py
126
+
127
+ # Environments
128
+ .env
129
+ .venv
130
+ env/
131
+ venv/
132
+ ENV/
133
+ env.bak/
134
+ venv.bak/
135
+
136
+ # Spyder project settings
137
+ .spyderproject
138
+ .spyproject
139
+
140
+ # Rope project settings
141
+ .ropeproject
142
+
143
+ # mkdocs documentation
144
+ /site
145
+
146
+ # mypy
147
+ .mypy_cache/
148
+ .dmypy.json
149
+ dmypy.json
150
+
151
+ # Pyre type checker
152
+ .pyre/
153
+
154
+ # pytype static type analyzer
155
+ .pytype/
156
+
157
+ # Cython debug symbols
158
+ cython_debug/
159
+
160
+ # PyCharm
161
+ # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
162
+ # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
163
+ # and can be added to the global gitignore or merged into this file. For a more nuclear
164
+ # option (not recommended) you can uncomment the following to ignore the entire idea folder.
165
+ #.idea/
166
+
167
+ ### Python Patch ###
168
+ # Poetry local configuration file - https://python-poetry.org/docs/configuration/#local-configuration
169
+ poetry.toml
170
+
171
+ # ruff
172
+ .ruff_cache/
173
+
174
+ # LSP config files
175
+ pyrightconfig.json
176
+
177
+ # End of https://www.toptal.com/developers/gitignore/api/python
@@ -0,0 +1,51 @@
1
+ Metadata-Version: 2.4
2
+ Name: klab-pytest-toolkit-decorators
3
+ Version: 0.0.0
4
+ Summary: Pytest decorators for the Klab Pytest Toolkit
5
+ Author-email: Burak Kizilkaya <burak.kizilkaya@outlook.com>
6
+ License-Expression: MIT
7
+ Classifier: Development Status :: 3 - Alpha
8
+ Classifier: Intended Audience :: Developers
9
+ Classifier: License :: OSI Approved :: MIT License
10
+ Classifier: Programming Language :: Python :: 3
11
+ Requires-Python: <4,>=3.11
12
+ Requires-Dist: pytest>=8.3.5
13
+ Description-Content-Type: text/markdown
14
+
15
+ # Klab Pytest Toolkit - Decorators
16
+
17
+ Custom pytest decorators for marking and annotating tests.
18
+
19
+ At the moment the package provides the following decorator:
20
+
21
+ - `@requirement(id: str)`: Marks a test with a requirement ID for traceability. The ID is added to the junit xml output.
22
+
23
+ ## Installation
24
+
25
+ ```bash
26
+ pip install klab_pytest_toolkit_decorators
27
+ ```
28
+
29
+ ## Usage
30
+
31
+ ### Requirement Decorator
32
+
33
+ Mark tests with requirement IDs for traceability:
34
+
35
+ ```python
36
+ from klab_pytest_toolkit_decorators import requirement
37
+
38
+ @requirement("REQ-001")
39
+ def test_something():
40
+ assert True
41
+
42
+ @requirement("REQ-002")
43
+ async def test_async_something():
44
+ assert True
45
+ ```
46
+
47
+ The decorator works with both synchronous and asynchronous test functions. The requirement IDs are added to the junit xml output.
48
+
49
+ ## License
50
+
51
+ MIT
@@ -0,0 +1,37 @@
1
+ # Klab Pytest Toolkit - Decorators
2
+
3
+ Custom pytest decorators for marking and annotating tests.
4
+
5
+ At the moment the package provides the following decorator:
6
+
7
+ - `@requirement(id: str)`: Marks a test with a requirement ID for traceability. The ID is added to the junit xml output.
8
+
9
+ ## Installation
10
+
11
+ ```bash
12
+ pip install klab_pytest_toolkit_decorators
13
+ ```
14
+
15
+ ## Usage
16
+
17
+ ### Requirement Decorator
18
+
19
+ Mark tests with requirement IDs for traceability:
20
+
21
+ ```python
22
+ from klab_pytest_toolkit_decorators import requirement
23
+
24
+ @requirement("REQ-001")
25
+ def test_something():
26
+ assert True
27
+
28
+ @requirement("REQ-002")
29
+ async def test_async_something():
30
+ assert True
31
+ ```
32
+
33
+ The decorator works with both synchronous and asynchronous test functions. The requirement IDs are added to the junit xml output.
34
+
35
+ ## License
36
+
37
+ MIT
@@ -0,0 +1,39 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "klab-pytest-toolkit-decorators"
7
+ dynamic = ["version"]
8
+ description = "Pytest decorators for the Klab Pytest Toolkit"
9
+ authors = [{ name = "Burak Kizilkaya", email = "burak.kizilkaya@outlook.com" }]
10
+ requires-python = ">=3.11,<4"
11
+ readme = "README.md"
12
+ license = "MIT"
13
+ classifiers = [
14
+ "Development Status :: 3 - Alpha",
15
+ "Intended Audience :: Developers",
16
+ "License :: OSI Approved :: MIT License",
17
+ "Programming Language :: Python :: 3",
18
+ ]
19
+ dependencies = [
20
+ "pytest>=8.3.5",
21
+ ]
22
+
23
+ [project.entry-points.pytest11]
24
+ klab_pytest_toolkit_decorators = "klab_pytest_toolkit_decorators.plugin"
25
+
26
+ [tool.hatch.version]
27
+ path = "src/klab_pytest_toolkit_decorators/__init__.py"
28
+
29
+ [tool.hatch.build.targets.sdist]
30
+ exclude = [
31
+ "tests",
32
+ ]
33
+
34
+ [tool.pytest.ini_options]
35
+ asyncio_mode = "auto"
36
+ asyncio_default_fixture_loop_scope = "function"
37
+ pythonpath = [
38
+ "."
39
+ ]
@@ -0,0 +1,4 @@
1
+ from klab_pytest_toolkit_decorators.compliance import requirement
2
+
3
+ __version__ = "0.0.0"
4
+ __all__ = ["requirement"]
@@ -0,0 +1,39 @@
1
+ import functools
2
+ import inspect
3
+ from collections.abc import Awaitable, Callable
4
+
5
+ import pytest
6
+
7
+
8
+ def requirement(*req_ids):
9
+ """Custom decorator to mark a test with requirement ID(s) and log them in the JUnit report.
10
+
11
+ Supports multiple requirements in several ways:
12
+ - Single requirement: @requirement("REQ-001")
13
+ - Multiple arguments: @requirement("REQ-001", "REQ-002", "REQ-003")
14
+ - Multiple decorators: @requirement("REQ-001") @requirement("REQ-002")
15
+ """
16
+ if not req_ids:
17
+ raise ValueError("At least one requirement ID must be provided")
18
+
19
+ def decorator(func: Callable) -> Callable[[], Awaitable[None]]:
20
+ # Apply markers for each requirement ID at decoration time
21
+ marked_func = func
22
+ for req_id in req_ids:
23
+ marked_func = pytest.mark.requirement(req_id)(marked_func)
24
+
25
+ @functools.wraps(marked_func)
26
+ async def async_wrapper(*args, **kwargs):
27
+ return await marked_func(*args, **kwargs)
28
+
29
+ @functools.wraps(marked_func)
30
+ def sync_wrapper(*args, **kwargs):
31
+ return marked_func(*args, **kwargs)
32
+
33
+ wrapper = async_wrapper if inspect.iscoroutinefunction(func) else sync_wrapper
34
+ # Copy over the pytest markers to the wrapper
35
+ # type: ignore is needed because pytestmark is dynamically added
36
+ setattr(wrapper, "pytestmark", getattr(marked_func, "pytestmark", []))
37
+ return wrapper
38
+
39
+ return decorator
@@ -0,0 +1,30 @@
1
+ """Pytest plugin to register custom markers."""
2
+
3
+
4
+ def pytest_configure(config):
5
+ """Register custom markers for klab-pytest-toolkit-decorators."""
6
+ config.addinivalue_line(
7
+ "markers", "requirement(req_id): mark test with a requirement ID for traceability"
8
+ )
9
+
10
+
11
+ def pytest_collection_modifyitems(items):
12
+ """Add requirement IDs to test properties for JUnit XML report."""
13
+ for item in items:
14
+ # Get all requirement markers (there can be multiple)
15
+ requirement_markers = [m for m in item.iter_markers(name="requirement")]
16
+ if requirement_markers:
17
+ # Collect all requirement IDs
18
+ req_ids = []
19
+ for marker in requirement_markers:
20
+ if marker.args:
21
+ req_ids.append(str(marker.args[0]))
22
+
23
+ # Add all requirements as properties for JUnit XML
24
+ # Can be added as comma-separated single property or individual properties
25
+ if req_ids:
26
+ # Add as comma-separated list
27
+ item.user_properties.append(("requirements", ", ".join(req_ids)))
28
+ # Also add individual properties for each requirement
29
+ for req_id in req_ids:
30
+ item.user_properties.append(("requirement", req_id))