winipedia-utils 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.
- winipedia_utils/__init__.py +1 -0
- winipedia_utils/concurrent/__init__.py +1 -0
- winipedia_utils/concurrent/concurrent.py +242 -0
- winipedia_utils/concurrent/multiprocessing.py +115 -0
- winipedia_utils/concurrent/multithreading.py +93 -0
- winipedia_utils/consts.py +22 -0
- winipedia_utils/data/__init__.py +1 -0
- winipedia_utils/data/dataframe.py +7 -0
- winipedia_utils/django/__init__.py +27 -0
- winipedia_utils/django/bulk.py +536 -0
- winipedia_utils/django/command.py +334 -0
- winipedia_utils/django/database.py +304 -0
- winipedia_utils/git/__init__.py +1 -0
- winipedia_utils/git/gitignore.py +80 -0
- winipedia_utils/git/pre_commit/__init__.py +1 -0
- winipedia_utils/git/pre_commit/config.py +60 -0
- winipedia_utils/git/pre_commit/hooks.py +109 -0
- winipedia_utils/git/pre_commit/run_hooks.py +49 -0
- winipedia_utils/iterating/__init__.py +1 -0
- winipedia_utils/iterating/iterate.py +29 -0
- winipedia_utils/logging/__init__.py +1 -0
- winipedia_utils/logging/ansi.py +6 -0
- winipedia_utils/logging/config.py +64 -0
- winipedia_utils/logging/logger.py +26 -0
- winipedia_utils/modules/__init__.py +1 -0
- winipedia_utils/modules/class_.py +76 -0
- winipedia_utils/modules/function.py +86 -0
- winipedia_utils/modules/module.py +361 -0
- winipedia_utils/modules/package.py +350 -0
- winipedia_utils/oop/__init__.py +1 -0
- winipedia_utils/oop/mixins/__init__.py +1 -0
- winipedia_utils/oop/mixins/meta.py +315 -0
- winipedia_utils/oop/mixins/mixin.py +28 -0
- winipedia_utils/os/__init__.py +1 -0
- winipedia_utils/os/os.py +61 -0
- winipedia_utils/projects/__init__.py +1 -0
- winipedia_utils/projects/poetry/__init__.py +1 -0
- winipedia_utils/projects/poetry/config.py +91 -0
- winipedia_utils/projects/poetry/poetry.py +30 -0
- winipedia_utils/setup.py +36 -0
- winipedia_utils/testing/__init__.py +1 -0
- winipedia_utils/testing/assertions.py +23 -0
- winipedia_utils/testing/convention.py +177 -0
- winipedia_utils/testing/create_tests.py +286 -0
- winipedia_utils/testing/fixtures.py +28 -0
- winipedia_utils/testing/tests/__init__.py +1 -0
- winipedia_utils/testing/tests/base/__init__.py +1 -0
- winipedia_utils/testing/tests/base/fixtures/__init__.py +1 -0
- winipedia_utils/testing/tests/base/fixtures/fixture.py +6 -0
- winipedia_utils/testing/tests/base/fixtures/scopes/__init__.py +1 -0
- winipedia_utils/testing/tests/base/fixtures/scopes/class_.py +33 -0
- winipedia_utils/testing/tests/base/fixtures/scopes/function.py +7 -0
- winipedia_utils/testing/tests/base/fixtures/scopes/module.py +31 -0
- winipedia_utils/testing/tests/base/fixtures/scopes/package.py +7 -0
- winipedia_utils/testing/tests/base/fixtures/scopes/session.py +224 -0
- winipedia_utils/testing/tests/base/utils/__init__.py +1 -0
- winipedia_utils/testing/tests/base/utils/utils.py +82 -0
- winipedia_utils/testing/tests/conftest.py +26 -0
- winipedia_utils/text/__init__.py +1 -0
- winipedia_utils/text/string.py +126 -0
- winipedia_utils-0.1.0.dist-info/LICENSE +21 -0
- winipedia_utils-0.1.0.dist-info/METADATA +350 -0
- winipedia_utils-0.1.0.dist-info/RECORD +64 -0
- winipedia_utils-0.1.0.dist-info/WHEEL +4 -0
@@ -0,0 +1,177 @@
|
|
1
|
+
"""Testing conventions and utilities.
|
2
|
+
|
3
|
+
This module provides functions and constants for managing test naming conventions,
|
4
|
+
mapping between test objects and their corresponding implementation objects,
|
5
|
+
and utilities for test discovery and validation.
|
6
|
+
|
7
|
+
Returns:
|
8
|
+
Various utility functions and constants for testing conventions.
|
9
|
+
|
10
|
+
"""
|
11
|
+
|
12
|
+
from collections.abc import Callable, Iterable
|
13
|
+
from types import ModuleType
|
14
|
+
from typing import Any
|
15
|
+
|
16
|
+
from winipedia_utils.modules.module import (
|
17
|
+
get_isolated_obj_name,
|
18
|
+
import_obj_from_importpath,
|
19
|
+
make_obj_importpath,
|
20
|
+
)
|
21
|
+
|
22
|
+
TEST_FUNCTION_PREFIX = "test_"
|
23
|
+
|
24
|
+
TEST_CLASS_PREFIX = "Test"
|
25
|
+
|
26
|
+
TEST_MODULE_PREFIX = TEST_FUNCTION_PREFIX
|
27
|
+
|
28
|
+
TEST_PREFIXES = [TEST_FUNCTION_PREFIX, TEST_CLASS_PREFIX, TEST_MODULE_PREFIX]
|
29
|
+
|
30
|
+
TESTS_PACKAGE_NAME = "tests"
|
31
|
+
|
32
|
+
|
33
|
+
def get_right_test_prefix(obj: Callable[..., Any] | type | ModuleType) -> str:
|
34
|
+
"""Get the appropriate test prefix for an object based on its type.
|
35
|
+
|
36
|
+
Args:
|
37
|
+
obj: The object to get the test prefix for (function, class, or module)
|
38
|
+
|
39
|
+
Returns:
|
40
|
+
The appropriate test prefix string for the given object type
|
41
|
+
|
42
|
+
"""
|
43
|
+
if isinstance(obj, ModuleType):
|
44
|
+
return TEST_MODULE_PREFIX
|
45
|
+
if isinstance(obj, type):
|
46
|
+
return TEST_CLASS_PREFIX
|
47
|
+
return TEST_FUNCTION_PREFIX
|
48
|
+
|
49
|
+
|
50
|
+
def make_test_obj_name(obj: Callable[..., Any] | type | ModuleType) -> str:
|
51
|
+
"""Create a test name for an object by adding the appropriate prefix.
|
52
|
+
|
53
|
+
Args:
|
54
|
+
obj: The object to create a test name for
|
55
|
+
|
56
|
+
Returns:
|
57
|
+
The test name with the appropriate prefix
|
58
|
+
|
59
|
+
"""
|
60
|
+
prefix = get_right_test_prefix(obj)
|
61
|
+
name = get_isolated_obj_name(obj)
|
62
|
+
return prefix + name
|
63
|
+
|
64
|
+
|
65
|
+
def reverse_make_test_obj_name(test_name: str) -> str:
|
66
|
+
"""Extract the original object name from a test name by removing the prefix.
|
67
|
+
|
68
|
+
Args:
|
69
|
+
test_name: The test name to extract the original name from
|
70
|
+
|
71
|
+
Returns:
|
72
|
+
The original object name without the test prefix
|
73
|
+
|
74
|
+
Raises:
|
75
|
+
ValueError: If the test name doesn't start with any of the expected prefixes
|
76
|
+
|
77
|
+
"""
|
78
|
+
for prefix in TEST_PREFIXES:
|
79
|
+
if test_name.startswith(prefix):
|
80
|
+
return test_name.removeprefix(prefix)
|
81
|
+
msg = f"{test_name=} is expected to start with one of {TEST_PREFIXES=}"
|
82
|
+
raise ValueError(msg)
|
83
|
+
|
84
|
+
|
85
|
+
def make_test_obj_importpath_from_obj(
|
86
|
+
obj: Callable[..., Any] | type | ModuleType,
|
87
|
+
) -> str:
|
88
|
+
"""Create an import path for a test object based on the original object.
|
89
|
+
|
90
|
+
Args:
|
91
|
+
obj: The original object to create a test import path for
|
92
|
+
|
93
|
+
Returns:
|
94
|
+
The import path for the corresponding test object
|
95
|
+
|
96
|
+
"""
|
97
|
+
parts = make_obj_importpath(obj).split(".")
|
98
|
+
test_name = make_test_obj_name(obj)
|
99
|
+
test_parts = [
|
100
|
+
(TEST_MODULE_PREFIX if part[0].islower() else TEST_CLASS_PREFIX) + part
|
101
|
+
for part in parts
|
102
|
+
]
|
103
|
+
test_parts[-1] = test_name
|
104
|
+
test_parts.insert(0, TESTS_PACKAGE_NAME)
|
105
|
+
return ".".join(test_parts)
|
106
|
+
|
107
|
+
|
108
|
+
def make_obj_importpath_from_test_obj(
|
109
|
+
test_obj: Callable[..., Any] | type | ModuleType,
|
110
|
+
) -> str:
|
111
|
+
"""Create an import path for an original object based on its test object.
|
112
|
+
|
113
|
+
Args:
|
114
|
+
test_obj: The test object to create an original import path for
|
115
|
+
|
116
|
+
Returns:
|
117
|
+
The import path for the corresponding original object
|
118
|
+
|
119
|
+
"""
|
120
|
+
test_parts = make_obj_importpath(test_obj).split(".")
|
121
|
+
test_parts = test_parts[1:]
|
122
|
+
parts = [reverse_make_test_obj_name(part) for part in test_parts]
|
123
|
+
return ".".join(parts)
|
124
|
+
|
125
|
+
|
126
|
+
def get_test_obj_from_obj(
|
127
|
+
obj: Callable[..., Any] | type | ModuleType,
|
128
|
+
) -> Callable[..., Any] | type | ModuleType:
|
129
|
+
"""Get the test object corresponding to an original object.
|
130
|
+
|
131
|
+
Args:
|
132
|
+
obj: The original object to get the test object for
|
133
|
+
|
134
|
+
Returns:
|
135
|
+
The corresponding test object
|
136
|
+
|
137
|
+
"""
|
138
|
+
test_obj_path = make_test_obj_importpath_from_obj(obj)
|
139
|
+
return import_obj_from_importpath(test_obj_path)
|
140
|
+
|
141
|
+
|
142
|
+
def get_obj_from_test_obj(
|
143
|
+
test_obj: Callable[..., Any] | type | ModuleType,
|
144
|
+
) -> Callable[..., Any] | type | ModuleType:
|
145
|
+
"""Get the original object corresponding to a test object.
|
146
|
+
|
147
|
+
Args:
|
148
|
+
test_obj: The test object to get the original object for
|
149
|
+
|
150
|
+
Returns:
|
151
|
+
The corresponding original object
|
152
|
+
|
153
|
+
"""
|
154
|
+
obj_importpath = make_obj_importpath_from_test_obj(test_obj)
|
155
|
+
return import_obj_from_importpath(obj_importpath)
|
156
|
+
|
157
|
+
|
158
|
+
def make_untested_summary_error_msg(
|
159
|
+
untested_objs: Iterable[str],
|
160
|
+
) -> str:
|
161
|
+
"""Create an error message summarizing untested objects.
|
162
|
+
|
163
|
+
Args:
|
164
|
+
untested_objs: Collection of import paths for untested objects
|
165
|
+
|
166
|
+
Returns:
|
167
|
+
A formatted error message listing all untested objects
|
168
|
+
|
169
|
+
"""
|
170
|
+
msg = """
|
171
|
+
Found untested objects:
|
172
|
+
"""
|
173
|
+
for untested in untested_objs:
|
174
|
+
msg += f"""
|
175
|
+
- {untested}
|
176
|
+
"""
|
177
|
+
return msg
|
@@ -0,0 +1,286 @@
|
|
1
|
+
"""Utilities for automatically creating test files for the project.
|
2
|
+
|
3
|
+
This module provides functions to generate test files for all modules and classes
|
4
|
+
in the project, ensuring that every function and method has a corresponding test.
|
5
|
+
It creates the basic test structure and generates skeleton test functions with
|
6
|
+
NotImplementedError to indicate tests that need to be written.
|
7
|
+
"""
|
8
|
+
|
9
|
+
from pathlib import Path
|
10
|
+
from types import ModuleType
|
11
|
+
from typing import cast
|
12
|
+
|
13
|
+
from winipedia_utils.modules.class_ import (
|
14
|
+
get_all_cls_from_module,
|
15
|
+
get_all_methods_from_cls,
|
16
|
+
)
|
17
|
+
from winipedia_utils.modules.function import get_all_functions_from_module
|
18
|
+
from winipedia_utils.modules.module import (
|
19
|
+
create_module,
|
20
|
+
get_isolated_obj_name,
|
21
|
+
get_module_content_as_str,
|
22
|
+
get_qualname_of_obj,
|
23
|
+
to_path,
|
24
|
+
)
|
25
|
+
from winipedia_utils.modules.package import (
|
26
|
+
copy_package,
|
27
|
+
get_scr_package,
|
28
|
+
walk_package,
|
29
|
+
)
|
30
|
+
from winipedia_utils.testing import tests
|
31
|
+
from winipedia_utils.testing.convention import (
|
32
|
+
TESTS_PACKAGE_NAME,
|
33
|
+
get_test_obj_from_obj,
|
34
|
+
make_test_obj_importpath_from_obj,
|
35
|
+
make_test_obj_name,
|
36
|
+
reverse_make_test_obj_name,
|
37
|
+
)
|
38
|
+
from winipedia_utils.testing.tests.base.utils.utils import (
|
39
|
+
_conftest_content_is_correct,
|
40
|
+
_get_conftest_content,
|
41
|
+
)
|
42
|
+
|
43
|
+
|
44
|
+
def create_tests() -> None:
|
45
|
+
"""Create all test files for the project.
|
46
|
+
|
47
|
+
This function orchestrates the test creation process by first setting up the base
|
48
|
+
test structure and then creating test files for all source packages.
|
49
|
+
"""
|
50
|
+
create_tests_base()
|
51
|
+
create_tests_for_src_package()
|
52
|
+
|
53
|
+
|
54
|
+
def create_tests_base() -> None:
|
55
|
+
"""Create the base test structure.
|
56
|
+
|
57
|
+
This function:
|
58
|
+
1. Creates a mirror of winipedia_utils.testing.tests in the tests directory
|
59
|
+
2. Skips copying __init__.py file contents
|
60
|
+
3. Writes new __init__.py files for all packages
|
61
|
+
4. Creates a conftest.py file with the appropriate pytest plugin configuration
|
62
|
+
5. Does not overwrite anything if it already exists except conftest.py
|
63
|
+
"""
|
64
|
+
tests_path = Path(TESTS_PACKAGE_NAME)
|
65
|
+
copy_package(
|
66
|
+
src_package=tests,
|
67
|
+
dst=".",
|
68
|
+
with_file_content=False,
|
69
|
+
)
|
70
|
+
# write pytest_plugin in the conftest.py
|
71
|
+
conftest_path = tests_path / "conftest.py"
|
72
|
+
# if conftest does not exist or the content is not the same, overwrite it
|
73
|
+
if not _conftest_content_is_correct(conftest_path):
|
74
|
+
conftest_path.write_text(_get_conftest_content())
|
75
|
+
|
76
|
+
|
77
|
+
def create_tests_for_src_package() -> None:
|
78
|
+
"""Create test files for all modules in the source package.
|
79
|
+
|
80
|
+
This function walks through the source package hierarchy and creates corresponding
|
81
|
+
test packages and modules for each package and module found in the source.
|
82
|
+
"""
|
83
|
+
src_package = get_scr_package()
|
84
|
+
for package, modules in walk_package(src_package):
|
85
|
+
create_test_package(package)
|
86
|
+
for module in modules:
|
87
|
+
create_test_module(module)
|
88
|
+
|
89
|
+
|
90
|
+
def create_test_package(package: ModuleType) -> None:
|
91
|
+
"""Create a test package for a source package.
|
92
|
+
|
93
|
+
Args:
|
94
|
+
package: The source package module to create a test package for
|
95
|
+
|
96
|
+
This function creates a test package with the appropriate naming convention
|
97
|
+
if it doesn't already exist.
|
98
|
+
|
99
|
+
"""
|
100
|
+
test_package_name = make_test_obj_importpath_from_obj(package)
|
101
|
+
# create package if it doesn't exist
|
102
|
+
create_module(test_package_name, is_package=True)
|
103
|
+
|
104
|
+
|
105
|
+
def create_test_module(module: ModuleType) -> None:
|
106
|
+
"""Create a test module for a source module.
|
107
|
+
|
108
|
+
Args:
|
109
|
+
module: The source module to create a test module for
|
110
|
+
|
111
|
+
This function:
|
112
|
+
1. Creates a test module with the appropriate naming convention
|
113
|
+
2. Generates the test module content with skeleton test functions
|
114
|
+
3. Writes the content to the test module file
|
115
|
+
|
116
|
+
"""
|
117
|
+
test_module_name = make_test_obj_importpath_from_obj(module)
|
118
|
+
test_module = create_module(test_module_name, is_package=False)
|
119
|
+
test_module_path = to_path(test_module, is_package=False)
|
120
|
+
test_module_path.write_text(get_test_module_content(module))
|
121
|
+
|
122
|
+
|
123
|
+
def get_test_module_content(module: ModuleType) -> str:
|
124
|
+
"""Generate the content for a test module.
|
125
|
+
|
126
|
+
Args:
|
127
|
+
module: The source module to generate test content for
|
128
|
+
|
129
|
+
Returns:
|
130
|
+
The generated test module content as a string
|
131
|
+
|
132
|
+
This function:
|
133
|
+
1. Gets the existing test module content if it exists
|
134
|
+
2. Adds test functions for all functions in the source module
|
135
|
+
3. Adds test classes for all classes in the source module
|
136
|
+
|
137
|
+
"""
|
138
|
+
test_module = cast("ModuleType", (get_test_obj_from_obj(module)))
|
139
|
+
test_module_content = get_module_content_as_str(test_module)
|
140
|
+
|
141
|
+
test_module_content = get_test_functions_content(
|
142
|
+
module, test_module, test_module_content
|
143
|
+
)
|
144
|
+
|
145
|
+
return get_test_classes_content(module, test_module, test_module_content)
|
146
|
+
|
147
|
+
|
148
|
+
def get_test_functions_content(
|
149
|
+
module: ModuleType,
|
150
|
+
test_module: ModuleType,
|
151
|
+
test_module_content: str,
|
152
|
+
) -> str:
|
153
|
+
"""Generate test function content for a module.
|
154
|
+
|
155
|
+
Args:
|
156
|
+
module: The source module containing functions to test
|
157
|
+
test_module: The test module to add function tests to
|
158
|
+
test_module_content: The current content of the test module
|
159
|
+
|
160
|
+
Returns:
|
161
|
+
The updated test module content with function tests added
|
162
|
+
|
163
|
+
This function:
|
164
|
+
1. Identifies all functions in the source module
|
165
|
+
2. Determines which functions don't have corresponding tests
|
166
|
+
3. Generates skeleton test functions for untested functions
|
167
|
+
|
168
|
+
"""
|
169
|
+
funcs = get_all_functions_from_module(module)
|
170
|
+
test_functions = get_all_functions_from_module(test_module)
|
171
|
+
supposed_test_funcs_names = [make_test_obj_name(f) for f in funcs]
|
172
|
+
|
173
|
+
test_funcs_names = [get_qualname_of_obj(f) for f in test_functions]
|
174
|
+
|
175
|
+
untested_funcs_names = [
|
176
|
+
f for f in supposed_test_funcs_names if f not in test_funcs_names
|
177
|
+
]
|
178
|
+
|
179
|
+
for test_func_name in untested_funcs_names:
|
180
|
+
test_module_content += f"""
|
181
|
+
|
182
|
+
def {test_func_name}() -> None:
|
183
|
+
\"\"\"Test func for {reverse_make_test_obj_name(test_func_name)}.\"\"\"
|
184
|
+
raise {NotImplementedError.__name__}
|
185
|
+
"""
|
186
|
+
|
187
|
+
return test_module_content
|
188
|
+
|
189
|
+
|
190
|
+
def get_test_classes_content(
|
191
|
+
module: ModuleType,
|
192
|
+
test_module: ModuleType,
|
193
|
+
test_module_content: str,
|
194
|
+
) -> str:
|
195
|
+
"""Generate test class content for a module.
|
196
|
+
|
197
|
+
Args:
|
198
|
+
module: The source module containing classes to test
|
199
|
+
test_module: The test module to add class tests to
|
200
|
+
test_module_content: The current content of the test module
|
201
|
+
|
202
|
+
Returns:
|
203
|
+
The updated test module content with class tests added
|
204
|
+
|
205
|
+
This function:
|
206
|
+
1. Identifies all classes in the source module
|
207
|
+
2. Determines which classes and methods don't have corresponding tests
|
208
|
+
3. Generates skeleton test classes and methods for untested classes and methods
|
209
|
+
4. Inserts the new test classes into the existing content
|
210
|
+
if the class already exists
|
211
|
+
|
212
|
+
Raises:
|
213
|
+
ValueError: If a test class declaration appears multiple
|
214
|
+
times in the test module
|
215
|
+
|
216
|
+
"""
|
217
|
+
classes = get_all_cls_from_module(module)
|
218
|
+
test_classes = get_all_cls_from_module(test_module)
|
219
|
+
|
220
|
+
class_to_methods = {
|
221
|
+
c: get_all_methods_from_cls(c, exclude_parent_methods=True) for c in classes
|
222
|
+
}
|
223
|
+
test_class_to_methods = {
|
224
|
+
tc: get_all_methods_from_cls(tc, exclude_parent_methods=True)
|
225
|
+
for tc in test_classes
|
226
|
+
}
|
227
|
+
|
228
|
+
supposed_test_class_to_methods_names = {
|
229
|
+
make_test_obj_name(c): [make_test_obj_name(m) for m in ms]
|
230
|
+
for c, ms in class_to_methods.items()
|
231
|
+
}
|
232
|
+
test_class_to_methods_names = {
|
233
|
+
get_isolated_obj_name(tc): [get_isolated_obj_name(tm) for tm in tms]
|
234
|
+
for tc, tms in test_class_to_methods.items()
|
235
|
+
}
|
236
|
+
|
237
|
+
untested_class_to_methods_names: dict[str, list[str]] = {}
|
238
|
+
for (
|
239
|
+
test_class_name,
|
240
|
+
supposed_test_methods_names,
|
241
|
+
) in supposed_test_class_to_methods_names.items():
|
242
|
+
test_methods_names = test_class_to_methods_names.get(test_class_name, [])
|
243
|
+
untested_methods_names = [
|
244
|
+
tmn for tmn in supposed_test_methods_names if tmn not in test_methods_names
|
245
|
+
]
|
246
|
+
if not supposed_test_methods_names:
|
247
|
+
untested_class_to_methods_names[test_class_name] = []
|
248
|
+
if untested_methods_names:
|
249
|
+
untested_class_to_methods_names[test_class_name] = untested_methods_names
|
250
|
+
|
251
|
+
for (
|
252
|
+
test_class_name,
|
253
|
+
untested_methods_names,
|
254
|
+
) in untested_class_to_methods_names.items():
|
255
|
+
test_class_declaration = f"""
|
256
|
+
class {test_class_name}:
|
257
|
+
\"\"\"Test class for {reverse_make_test_obj_name(test_class_name)}.\"\"\"
|
258
|
+
"""
|
259
|
+
test_class_content = test_class_declaration
|
260
|
+
for untested_method_name in untested_methods_names:
|
261
|
+
test_class_content += f"""
|
262
|
+
def {untested_method_name}(self) -> None:
|
263
|
+
\"\"\"Test method for {reverse_make_test_obj_name(untested_method_name)}.\"\"\"
|
264
|
+
raise {NotImplementedError.__name__}
|
265
|
+
"""
|
266
|
+
parts = test_module_content.split(test_class_declaration)
|
267
|
+
expected_parts = 2
|
268
|
+
if len(parts) > expected_parts:
|
269
|
+
msg = f"Found {len(parts)} parts, expected 2"
|
270
|
+
raise ValueError(msg)
|
271
|
+
parts.insert(1, test_class_content)
|
272
|
+
test_module_content = "".join(parts)
|
273
|
+
|
274
|
+
return test_module_content
|
275
|
+
|
276
|
+
|
277
|
+
def main() -> None:
|
278
|
+
"""Entry point for the create_tests script.
|
279
|
+
|
280
|
+
Calls the create_tests function to generate all test files.
|
281
|
+
"""
|
282
|
+
create_tests()
|
283
|
+
|
284
|
+
|
285
|
+
if __name__ == "__main__":
|
286
|
+
main()
|
@@ -0,0 +1,28 @@
|
|
1
|
+
"""Testing fixtures for pytest.
|
2
|
+
|
3
|
+
This module provides custom fixtures for pytest that can be used to
|
4
|
+
automate common testing tasks and provide consistent setup and teardown
|
5
|
+
for tests.
|
6
|
+
"""
|
7
|
+
|
8
|
+
import functools
|
9
|
+
|
10
|
+
import pytest
|
11
|
+
|
12
|
+
function_fixture = functools.partial(pytest.fixture, scope="function")
|
13
|
+
class_fixture = functools.partial(pytest.fixture, scope="class")
|
14
|
+
module_fixture = functools.partial(pytest.fixture, scope="module")
|
15
|
+
package_fixture = functools.partial(pytest.fixture, scope="package")
|
16
|
+
session_fixture = functools.partial(pytest.fixture, scope="session")
|
17
|
+
|
18
|
+
autouse_function_fixture = functools.partial(
|
19
|
+
pytest.fixture, scope="function", autouse=True
|
20
|
+
)
|
21
|
+
autouse_class_fixture = functools.partial(pytest.fixture, scope="class", autouse=True)
|
22
|
+
autouse_module_fixture = functools.partial(pytest.fixture, scope="module", autouse=True)
|
23
|
+
autouse_package_fixture = functools.partial(
|
24
|
+
pytest.fixture, scope="package", autouse=True
|
25
|
+
)
|
26
|
+
autouse_session_fixture = functools.partial(
|
27
|
+
pytest.fixture, scope="session", autouse=True
|
28
|
+
)
|
@@ -0,0 +1 @@
|
|
1
|
+
"""__init__ module for winipedia_utils.testing.tests."""
|
@@ -0,0 +1 @@
|
|
1
|
+
"""__init__ module for winipedia_utils.testing.tests.base."""
|
@@ -0,0 +1 @@
|
|
1
|
+
"""__init__ module for winipedia_utils.testing.tests.base.fixtures."""
|
@@ -0,0 +1 @@
|
|
1
|
+
"""__init__ module for winipedia_utils.testing.tests.base.fixtures.scopes."""
|
@@ -0,0 +1,33 @@
|
|
1
|
+
"""Class-level test fixtures and utilities.
|
2
|
+
|
3
|
+
This module provides fixtures and test functions that operate at the class scope,
|
4
|
+
ensuring that all methods within a test class have corresponding tests.
|
5
|
+
These fixtures are automatically applied to all test classes through pytest's autouse
|
6
|
+
mechanism.
|
7
|
+
"""
|
8
|
+
|
9
|
+
import pytest
|
10
|
+
|
11
|
+
from winipedia_utils.testing.fixtures import autouse_class_fixture
|
12
|
+
from winipedia_utils.testing.tests.base.utils.utils import _assert_no_untested_objs
|
13
|
+
|
14
|
+
|
15
|
+
@autouse_class_fixture
|
16
|
+
def _test_all_methods_tested(request: pytest.FixtureRequest) -> None:
|
17
|
+
"""Verify that all methods in a class have corresponding tests.
|
18
|
+
|
19
|
+
This fixture runs automatically for each test class and checks that every
|
20
|
+
method defined in the corresponding source class has a test method defined
|
21
|
+
in the test class.
|
22
|
+
|
23
|
+
Args:
|
24
|
+
request: The pytest fixture request object containing the current class
|
25
|
+
|
26
|
+
Raises:
|
27
|
+
AssertionError: If any method in the source class lacks a test
|
28
|
+
|
29
|
+
"""
|
30
|
+
class_ = request.node.cls
|
31
|
+
if class_ is None:
|
32
|
+
return
|
33
|
+
_assert_no_untested_objs(class_)
|
@@ -0,0 +1,7 @@
|
|
1
|
+
"""Function-level test fixtures and utilities.
|
2
|
+
|
3
|
+
This module provides fixtures and test functions that operate at the function scope,
|
4
|
+
ensuring proper setup and teardown for individual test functions.
|
5
|
+
These fixtures are automatically applied to all test functions through pytest's autouse
|
6
|
+
mechanism.
|
7
|
+
"""
|
@@ -0,0 +1,31 @@
|
|
1
|
+
"""Module-level test fixtures and utilities.
|
2
|
+
|
3
|
+
This module provides fixtures and test functions that operate at the module scope,
|
4
|
+
ensuring that all functions and classes within a module have corresponding tests.
|
5
|
+
These fixtures are automatically applied to all test modules through pytest's autouse
|
6
|
+
mechanism.
|
7
|
+
"""
|
8
|
+
|
9
|
+
import pytest
|
10
|
+
|
11
|
+
from winipedia_utils.testing.fixtures import autouse_module_fixture
|
12
|
+
from winipedia_utils.testing.tests.base.utils.utils import _assert_no_untested_objs
|
13
|
+
|
14
|
+
|
15
|
+
@autouse_module_fixture
|
16
|
+
def _test_all_funcs_and_classes_tested(request: pytest.FixtureRequest) -> None:
|
17
|
+
"""Verify that all functions and classes in a module have corresponding tests.
|
18
|
+
|
19
|
+
This fixture runs automatically for each test module and checks that every
|
20
|
+
function and class defined in the corresponding source module has a test
|
21
|
+
function or class defined in the test module.
|
22
|
+
|
23
|
+
Args:
|
24
|
+
request: The pytest fixture request object containing the current module
|
25
|
+
|
26
|
+
Raises:
|
27
|
+
AssertionError: If any function or class in the source module lacks a test
|
28
|
+
|
29
|
+
"""
|
30
|
+
module = request.module
|
31
|
+
_assert_no_untested_objs(module)
|
@@ -0,0 +1,7 @@
|
|
1
|
+
"""Package-level test fixtures and utilities.
|
2
|
+
|
3
|
+
This module provides fixtures and test functions that operate at the package scope,
|
4
|
+
ensuring that all modules within a package have corresponding tests.
|
5
|
+
These fixtures are automatically applied to all test packages through pytest's autouse
|
6
|
+
mechanism.
|
7
|
+
"""
|