winipedia-utils 0.2.10__py3-none-any.whl → 0.2.18__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.

Potentially problematic release.


This version of winipedia-utils might be problematic. Click here for more details.

Files changed (69) hide show
  1. winipedia_utils/concurrent/concurrent.py +245 -245
  2. winipedia_utils/concurrent/multiprocessing.py +130 -130
  3. winipedia_utils/concurrent/multithreading.py +93 -93
  4. winipedia_utils/consts.py +21 -21
  5. winipedia_utils/data/__init__.py +1 -1
  6. winipedia_utils/data/dataframe/__init__.py +1 -1
  7. winipedia_utils/data/dataframe/cleaning.py +378 -378
  8. winipedia_utils/data/structures/__init__.py +1 -1
  9. winipedia_utils/data/structures/dicts.py +16 -16
  10. winipedia_utils/git/__init__.py +1 -1
  11. winipedia_utils/git/gitignore/__init__.py +1 -1
  12. winipedia_utils/git/gitignore/gitignore.py +136 -136
  13. winipedia_utils/git/pre_commit/__init__.py +1 -1
  14. winipedia_utils/git/pre_commit/config.py +70 -70
  15. winipedia_utils/git/pre_commit/hooks.py +127 -109
  16. winipedia_utils/git/pre_commit/run_hooks.py +49 -49
  17. winipedia_utils/iterating/__init__.py +1 -1
  18. winipedia_utils/iterating/iterate.py +29 -29
  19. winipedia_utils/logging/ansi.py +6 -6
  20. winipedia_utils/logging/config.py +64 -64
  21. winipedia_utils/logging/logger.py +26 -26
  22. winipedia_utils/modules/class_.py +119 -119
  23. winipedia_utils/modules/function.py +101 -101
  24. winipedia_utils/modules/module.py +379 -379
  25. winipedia_utils/modules/package.py +390 -390
  26. winipedia_utils/oop/mixins/meta.py +333 -333
  27. winipedia_utils/oop/mixins/mixin.py +37 -37
  28. winipedia_utils/os/__init__.py +1 -1
  29. winipedia_utils/os/os.py +63 -63
  30. winipedia_utils/projects/__init__.py +1 -1
  31. winipedia_utils/projects/poetry/__init__.py +1 -1
  32. winipedia_utils/projects/poetry/config.py +117 -117
  33. winipedia_utils/projects/poetry/poetry.py +31 -31
  34. winipedia_utils/projects/project.py +48 -48
  35. winipedia_utils/resources/__init__.py +1 -1
  36. winipedia_utils/resources/svgs/__init__.py +1 -1
  37. winipedia_utils/resources/svgs/download_arrow.svg +2 -2
  38. winipedia_utils/resources/svgs/exit_fullscreen_icon.svg +5 -5
  39. winipedia_utils/resources/svgs/fullscreen_icon.svg +2 -2
  40. winipedia_utils/resources/svgs/menu_icon.svg +3 -3
  41. winipedia_utils/resources/svgs/pause_icon.svg +3 -3
  42. winipedia_utils/resources/svgs/play_icon.svg +16 -16
  43. winipedia_utils/resources/svgs/plus_icon.svg +23 -23
  44. winipedia_utils/resources/svgs/svg.py +15 -15
  45. winipedia_utils/security/__init__.py +1 -1
  46. winipedia_utils/security/cryptography.py +29 -29
  47. winipedia_utils/security/keyring.py +70 -70
  48. winipedia_utils/setup.py +47 -47
  49. winipedia_utils/testing/assertions.py +23 -23
  50. winipedia_utils/testing/convention.py +177 -177
  51. winipedia_utils/testing/create_tests.py +297 -297
  52. winipedia_utils/testing/fixtures.py +28 -28
  53. winipedia_utils/testing/tests/base/fixtures/__init__.py +1 -1
  54. winipedia_utils/testing/tests/base/fixtures/fixture.py +6 -6
  55. winipedia_utils/testing/tests/base/fixtures/scopes/class_.py +33 -33
  56. winipedia_utils/testing/tests/base/fixtures/scopes/function.py +7 -7
  57. winipedia_utils/testing/tests/base/fixtures/scopes/module.py +33 -33
  58. winipedia_utils/testing/tests/base/fixtures/scopes/package.py +7 -7
  59. winipedia_utils/testing/tests/base/fixtures/scopes/session.py +296 -296
  60. winipedia_utils/testing/tests/base/utils/utils.py +111 -111
  61. winipedia_utils/testing/tests/conftest.py +32 -32
  62. winipedia_utils/text/string.py +126 -126
  63. winipedia_utils-0.2.18.dist-info/METADATA +715 -0
  64. winipedia_utils-0.2.18.dist-info/RECORD +80 -0
  65. {winipedia_utils-0.2.10.dist-info → winipedia_utils-0.2.18.dist-info}/licenses/LICENSE +21 -21
  66. winipedia_utils/testing/tests/test_0.py +0 -8
  67. winipedia_utils-0.2.10.dist-info/METADATA +0 -355
  68. winipedia_utils-0.2.10.dist-info/RECORD +0 -81
  69. {winipedia_utils-0.2.10.dist-info → winipedia_utils-0.2.18.dist-info}/WHEEL +0 -0
@@ -1,296 +1,296 @@
1
- """Session-level test fixtures and utilities.
2
-
3
- This module provides fixtures and test functions that operate at the session scope,
4
- ensuring that project-wide conventions are followed and that the overall project
5
- structure is correct. These fixtures are automatically applied to the test session
6
- through pytest's autouse mechanism.
7
- """
8
-
9
- from importlib import import_module
10
- from pathlib import Path
11
-
12
- from winipedia_utils.consts import _DEV_DEPENDENCIES
13
- from winipedia_utils.git.gitignore.gitignore import _gitignore_is_correct
14
- from winipedia_utils.git.pre_commit.config import (
15
- _pre_commit_config_is_correct,
16
- )
17
- from winipedia_utils.modules.module import to_path
18
- from winipedia_utils.modules.package import (
19
- find_packages,
20
- get_src_package,
21
- walk_package,
22
- )
23
- from winipedia_utils.projects.poetry.config import (
24
- _pyproject_tool_configs_are_correct,
25
- get_dev_dependencies_from_pyproject_toml,
26
- get_poetry_package_name,
27
- )
28
- from winipedia_utils.testing.assertions import assert_with_msg
29
- from winipedia_utils.testing.convention import (
30
- TESTS_PACKAGE_NAME,
31
- make_test_obj_importpath_from_obj,
32
- )
33
- from winipedia_utils.testing.fixtures import autouse_session_fixture
34
- from winipedia_utils.testing.tests.base.utils.utils import (
35
- _conftest_content_is_correct,
36
- )
37
-
38
-
39
- @autouse_session_fixture
40
- def _test_dev_dependencies_const_correct() -> None:
41
- """Verify that the dev dependencies in consts.py are correct.
42
-
43
- This fixture runs once per test session and checks that the dev dependencies
44
- in consts.py are correct by comparing them to the dev dependencies in
45
- pyproject.toml.
46
-
47
- Raises:
48
- AssertionError: If the dev dependencies in consts.py are not correct
49
-
50
- """
51
- if get_poetry_package_name() != "winipedia_utils":
52
- # this const is only used in winipedia_utils
53
- # to be able to install them with setup.py
54
- return
55
- actual_dev_dependencies = get_dev_dependencies_from_pyproject_toml()
56
- assert_with_msg(
57
- set(actual_dev_dependencies) == set(_DEV_DEPENDENCIES),
58
- "Dev dependencies in consts.py are not correct",
59
- )
60
-
61
-
62
- @autouse_session_fixture
63
- def _test_dev_dependencies_are_in_pyproject_toml() -> None:
64
- """Verify that the dev dependencies are installed.
65
-
66
- This fixture runs once per test session and checks that the dev dependencies
67
- are installed by trying to import them.
68
-
69
- Raises:
70
- ImportError: If a dev dependency is not installed
71
-
72
- """
73
- dev_dependencies = get_dev_dependencies_from_pyproject_toml()
74
- assert_with_msg(
75
- set(_DEV_DEPENDENCIES).issubset(set(dev_dependencies)),
76
- "Dev dependencies in consts.py are not a subset of the ones in pyproject.toml",
77
- )
78
-
79
-
80
- @autouse_session_fixture
81
- def _test_conftest_exists_and_is_correct() -> None:
82
- """Verify that the conftest.py file exists and has the correct content.
83
-
84
- This fixture runs once per test session and checks that the conftest.py file
85
- exists in the tests directory and contains the correct pytest_plugins configuration.
86
-
87
- Raises:
88
- AssertionError: If the conftest.py file doesn't exist or has incorrect content
89
-
90
- """
91
- conftest_path = Path(TESTS_PACKAGE_NAME, "conftest.py")
92
- assert_with_msg(
93
- conftest_path.is_file(),
94
- f"Expected conftest.py file at {conftest_path} but it doesn't exist",
95
- )
96
-
97
- assert_with_msg(
98
- _conftest_content_is_correct(conftest_path),
99
- "conftest.py has incorrect content",
100
- )
101
-
102
-
103
- @autouse_session_fixture
104
- def _test_pyproject_toml_is_correct() -> None:
105
- """Verify that the pyproject.toml file exists and has the correct content.
106
-
107
- This fixture runs once per test session and checks that the pyproject.toml file
108
- exists in the root directory and contains the correct content.
109
-
110
- Raises:
111
- AssertionError: If the pyproject.toml file doesn't exist
112
- or has incorrect content
113
-
114
- """
115
- pyproject_toml_path = Path("pyproject.toml")
116
- assert_with_msg(
117
- pyproject_toml_path.is_file(),
118
- f"Expected pyproject.toml file at {pyproject_toml_path} but it doesn't exist",
119
- )
120
- assert_with_msg(
121
- _pyproject_tool_configs_are_correct(),
122
- "pyproject.toml has incorrect content.",
123
- )
124
-
125
-
126
- @autouse_session_fixture
127
- def _test_pre_commit_config_yaml_is_correct() -> None:
128
- """Verify that the pre-commit yaml is correctly defining winipedia utils hook.
129
-
130
- Checks that the yaml starts with the winipedia utils hook.
131
- """
132
- pre_commit_config = Path(".pre-commit-config.yaml")
133
-
134
- assert_with_msg(
135
- pre_commit_config.is_file(),
136
- f"Expected {pre_commit_config} to exist but it doesn't.",
137
- )
138
- assert_with_msg(
139
- _pre_commit_config_is_correct(),
140
- "Pre commit config is not correct.",
141
- )
142
-
143
-
144
- @autouse_session_fixture
145
- def _test_gitignore_is_correct() -> None:
146
- """Verify that the .gitignore file exists and has the correct content.
147
-
148
- This fixture runs once per test session and checks that the .gitignore file
149
- exists in the root directory and contains the correct content.
150
-
151
- Raises:
152
- AssertionError: If the .gitignore file doesn't exist
153
- or has incorrect content
154
-
155
- """
156
- gitignore_path = Path(".gitignore")
157
- assert_with_msg(
158
- gitignore_path.is_file(),
159
- f"Expected {gitignore_path} to exist but it doesn't.",
160
- )
161
- assert_with_msg(
162
- _gitignore_is_correct(),
163
- "Gitignore is not correct.",
164
- )
165
-
166
-
167
- @autouse_session_fixture
168
- def _test_no_namespace_packages() -> None:
169
- """Verify that there are no namespace packages in the project.
170
-
171
- This fixture runs once per test session and checks that all packages in the
172
- project are regular packages with __init__.py files, not namespace packages.
173
-
174
- Raises:
175
- AssertionError: If any namespace packages are found
176
-
177
- """
178
- packages = find_packages(depth=None)
179
- namespace_packages = find_packages(depth=None, include_namespace_packages=True)
180
-
181
- any_namespace_packages = set(namespace_packages) - set(packages)
182
- assert_with_msg(
183
- not any_namespace_packages,
184
- f"Found namespace packages: {any_namespace_packages}. "
185
- f"All packages should have __init__.py files.",
186
- )
187
-
188
-
189
- @autouse_session_fixture
190
- def _test_all_src_code_in_one_package() -> None:
191
- """Verify that all source code is in a single package.
192
-
193
- This fixture runs once per test session and checks that there is only one
194
- source package besides the tests package.
195
-
196
- Raises:
197
- AssertionError: If there are multiple source packages
198
-
199
- """
200
- packages = find_packages(depth=0)
201
- src_package = get_src_package().__name__
202
- expected_packages = {TESTS_PACKAGE_NAME, src_package}
203
- assert_with_msg(
204
- set(packages) == expected_packages,
205
- f"Expected only packages {expected_packages}, but found {packages}",
206
- )
207
-
208
-
209
- @autouse_session_fixture
210
- def _test_src_package_correctly_named() -> None:
211
- """Verify that the source package is correctly named.
212
-
213
- This fixture runs once per test session and checks that the source package
214
- is correctly named after the project.
215
-
216
- Raises:
217
- AssertionError: If the source package is not correctly named
218
-
219
- """
220
- src_package = get_src_package().__name__
221
- assert_with_msg(
222
- src_package == get_poetry_package_name(),
223
- f"Expected source package to be named {get_poetry_package_name()}, "
224
- f"but it is named {src_package}",
225
- )
226
-
227
-
228
- @autouse_session_fixture
229
- def _test_py_typed_exists() -> None:
230
- """Verify that the py.typed file exists in the source package.
231
-
232
- This fixture runs once per test session and checks that the py.typed file
233
- exists in the source package.
234
-
235
- Raises:
236
- AssertionError: If the py.typed file doesn't exist
237
-
238
- """
239
- src_package = get_src_package()
240
- py_typed_path = to_path(src_package.__name__, is_package=True) / "py.typed"
241
- assert_with_msg(
242
- py_typed_path.exists(),
243
- f"Expected py.typed file to exist at {py_typed_path}",
244
- )
245
-
246
-
247
- @autouse_session_fixture
248
- def _test_project_structure_mirrored() -> None:
249
- """Verify that the project structure is mirrored in tests.
250
-
251
- This fixture runs once per test session and checks that for every package and
252
- module in the source package, there is a corresponding test package and module.
253
-
254
- Raises:
255
- AssertionError: If any package or module doesn't have a corresponding test
256
-
257
- """
258
- src_package = get_src_package()
259
-
260
- # we will now go through all the modules in the src package and check
261
- # that there is a corresponding test module
262
- for package, modules in walk_package(src_package):
263
- test_package_name = make_test_obj_importpath_from_obj(package)
264
- test_package = import_module(test_package_name)
265
- assert_with_msg(
266
- bool(test_package),
267
- f"Expected test package {test_package_name} to be a module",
268
- )
269
-
270
- for module in modules:
271
- test_module_name = make_test_obj_importpath_from_obj(module)
272
- test_module = import_module(test_module_name)
273
- assert_with_msg(
274
- bool(test_module),
275
- f"Expected test module {test_module_name} to be a module",
276
- )
277
-
278
-
279
- @autouse_session_fixture
280
- def _test_no_unitest_package_usage() -> None:
281
- """Verify that the unittest package is not used in the project.
282
-
283
- This fixture runs once per test session and checks that the unittest package
284
- is not used in the project.
285
-
286
- Raises:
287
- AssertionError: If the unittest package is used
288
-
289
- """
290
- for path in Path().rglob("*.py"):
291
- if path == to_path(__name__, is_package=False):
292
- continue
293
- assert_with_msg(
294
- "unittest" not in path.read_text(encoding="utf-8"),
295
- f"Found unittest usage in {path}. Use pytest instead.",
296
- )
1
+ """Session-level test fixtures and utilities.
2
+
3
+ This module provides fixtures and test functions that operate at the session scope,
4
+ ensuring that project-wide conventions are followed and that the overall project
5
+ structure is correct. These fixtures are automatically applied to the test session
6
+ through pytest's autouse mechanism.
7
+ """
8
+
9
+ from importlib import import_module
10
+ from pathlib import Path
11
+
12
+ from winipedia_utils.consts import _DEV_DEPENDENCIES
13
+ from winipedia_utils.git.gitignore.gitignore import _gitignore_is_correct
14
+ from winipedia_utils.git.pre_commit.config import (
15
+ _pre_commit_config_is_correct,
16
+ )
17
+ from winipedia_utils.modules.module import to_path
18
+ from winipedia_utils.modules.package import (
19
+ find_packages,
20
+ get_src_package,
21
+ walk_package,
22
+ )
23
+ from winipedia_utils.projects.poetry.config import (
24
+ _pyproject_tool_configs_are_correct,
25
+ get_dev_dependencies_from_pyproject_toml,
26
+ get_poetry_package_name,
27
+ )
28
+ from winipedia_utils.testing.assertions import assert_with_msg
29
+ from winipedia_utils.testing.convention import (
30
+ TESTS_PACKAGE_NAME,
31
+ make_test_obj_importpath_from_obj,
32
+ )
33
+ from winipedia_utils.testing.fixtures import autouse_session_fixture
34
+ from winipedia_utils.testing.tests.base.utils.utils import (
35
+ _conftest_content_is_correct,
36
+ )
37
+
38
+
39
+ @autouse_session_fixture
40
+ def _test_dev_dependencies_const_correct() -> None:
41
+ """Verify that the dev dependencies in consts.py are correct.
42
+
43
+ This fixture runs once per test session and checks that the dev dependencies
44
+ in consts.py are correct by comparing them to the dev dependencies in
45
+ pyproject.toml.
46
+
47
+ Raises:
48
+ AssertionError: If the dev dependencies in consts.py are not correct
49
+
50
+ """
51
+ if get_poetry_package_name() != "winipedia_utils":
52
+ # this const is only used in winipedia_utils
53
+ # to be able to install them with setup.py
54
+ return
55
+ actual_dev_dependencies = get_dev_dependencies_from_pyproject_toml()
56
+ assert_with_msg(
57
+ set(actual_dev_dependencies) == set(_DEV_DEPENDENCIES),
58
+ "Dev dependencies in consts.py are not correct",
59
+ )
60
+
61
+
62
+ @autouse_session_fixture
63
+ def _test_dev_dependencies_are_in_pyproject_toml() -> None:
64
+ """Verify that the dev dependencies are installed.
65
+
66
+ This fixture runs once per test session and checks that the dev dependencies
67
+ are installed by trying to import them.
68
+
69
+ Raises:
70
+ ImportError: If a dev dependency is not installed
71
+
72
+ """
73
+ dev_dependencies = get_dev_dependencies_from_pyproject_toml()
74
+ assert_with_msg(
75
+ set(_DEV_DEPENDENCIES).issubset(set(dev_dependencies)),
76
+ "Dev dependencies in consts.py are not a subset of the ones in pyproject.toml",
77
+ )
78
+
79
+
80
+ @autouse_session_fixture
81
+ def _test_conftest_exists_and_is_correct() -> None:
82
+ """Verify that the conftest.py file exists and has the correct content.
83
+
84
+ This fixture runs once per test session and checks that the conftest.py file
85
+ exists in the tests directory and contains the correct pytest_plugins configuration.
86
+
87
+ Raises:
88
+ AssertionError: If the conftest.py file doesn't exist or has incorrect content
89
+
90
+ """
91
+ conftest_path = Path(TESTS_PACKAGE_NAME, "conftest.py")
92
+ assert_with_msg(
93
+ conftest_path.is_file(),
94
+ f"Expected conftest.py file at {conftest_path} but it doesn't exist",
95
+ )
96
+
97
+ assert_with_msg(
98
+ _conftest_content_is_correct(conftest_path),
99
+ "conftest.py has incorrect content",
100
+ )
101
+
102
+
103
+ @autouse_session_fixture
104
+ def _test_pyproject_toml_is_correct() -> None:
105
+ """Verify that the pyproject.toml file exists and has the correct content.
106
+
107
+ This fixture runs once per test session and checks that the pyproject.toml file
108
+ exists in the root directory and contains the correct content.
109
+
110
+ Raises:
111
+ AssertionError: If the pyproject.toml file doesn't exist
112
+ or has incorrect content
113
+
114
+ """
115
+ pyproject_toml_path = Path("pyproject.toml")
116
+ assert_with_msg(
117
+ pyproject_toml_path.is_file(),
118
+ f"Expected pyproject.toml file at {pyproject_toml_path} but it doesn't exist",
119
+ )
120
+ assert_with_msg(
121
+ _pyproject_tool_configs_are_correct(),
122
+ "pyproject.toml has incorrect content.",
123
+ )
124
+
125
+
126
+ @autouse_session_fixture
127
+ def _test_pre_commit_config_yaml_is_correct() -> None:
128
+ """Verify that the pre-commit yaml is correctly defining winipedia utils hook.
129
+
130
+ Checks that the yaml starts with the winipedia utils hook.
131
+ """
132
+ pre_commit_config = Path(".pre-commit-config.yaml")
133
+
134
+ assert_with_msg(
135
+ pre_commit_config.is_file(),
136
+ f"Expected {pre_commit_config} to exist but it doesn't.",
137
+ )
138
+ assert_with_msg(
139
+ _pre_commit_config_is_correct(),
140
+ "Pre commit config is not correct.",
141
+ )
142
+
143
+
144
+ @autouse_session_fixture
145
+ def _test_gitignore_is_correct() -> None:
146
+ """Verify that the .gitignore file exists and has the correct content.
147
+
148
+ This fixture runs once per test session and checks that the .gitignore file
149
+ exists in the root directory and contains the correct content.
150
+
151
+ Raises:
152
+ AssertionError: If the .gitignore file doesn't exist
153
+ or has incorrect content
154
+
155
+ """
156
+ gitignore_path = Path(".gitignore")
157
+ assert_with_msg(
158
+ gitignore_path.is_file(),
159
+ f"Expected {gitignore_path} to exist but it doesn't.",
160
+ )
161
+ assert_with_msg(
162
+ _gitignore_is_correct(),
163
+ "Gitignore is not correct.",
164
+ )
165
+
166
+
167
+ @autouse_session_fixture
168
+ def _test_no_namespace_packages() -> None:
169
+ """Verify that there are no namespace packages in the project.
170
+
171
+ This fixture runs once per test session and checks that all packages in the
172
+ project are regular packages with __init__.py files, not namespace packages.
173
+
174
+ Raises:
175
+ AssertionError: If any namespace packages are found
176
+
177
+ """
178
+ packages = find_packages(depth=None)
179
+ namespace_packages = find_packages(depth=None, include_namespace_packages=True)
180
+
181
+ any_namespace_packages = set(namespace_packages) - set(packages)
182
+ assert_with_msg(
183
+ not any_namespace_packages,
184
+ f"Found namespace packages: {any_namespace_packages}. "
185
+ f"All packages should have __init__.py files.",
186
+ )
187
+
188
+
189
+ @autouse_session_fixture
190
+ def _test_all_src_code_in_one_package() -> None:
191
+ """Verify that all source code is in a single package.
192
+
193
+ This fixture runs once per test session and checks that there is only one
194
+ source package besides the tests package.
195
+
196
+ Raises:
197
+ AssertionError: If there are multiple source packages
198
+
199
+ """
200
+ packages = find_packages(depth=0)
201
+ src_package = get_src_package().__name__
202
+ expected_packages = {TESTS_PACKAGE_NAME, src_package}
203
+ assert_with_msg(
204
+ set(packages) == expected_packages,
205
+ f"Expected only packages {expected_packages}, but found {packages}",
206
+ )
207
+
208
+
209
+ @autouse_session_fixture
210
+ def _test_src_package_correctly_named() -> None:
211
+ """Verify that the source package is correctly named.
212
+
213
+ This fixture runs once per test session and checks that the source package
214
+ is correctly named after the project.
215
+
216
+ Raises:
217
+ AssertionError: If the source package is not correctly named
218
+
219
+ """
220
+ src_package = get_src_package().__name__
221
+ assert_with_msg(
222
+ src_package == get_poetry_package_name(),
223
+ f"Expected source package to be named {get_poetry_package_name()}, "
224
+ f"but it is named {src_package}",
225
+ )
226
+
227
+
228
+ @autouse_session_fixture
229
+ def _test_py_typed_exists() -> None:
230
+ """Verify that the py.typed file exists in the source package.
231
+
232
+ This fixture runs once per test session and checks that the py.typed file
233
+ exists in the source package.
234
+
235
+ Raises:
236
+ AssertionError: If the py.typed file doesn't exist
237
+
238
+ """
239
+ src_package = get_src_package()
240
+ py_typed_path = to_path(src_package.__name__, is_package=True) / "py.typed"
241
+ assert_with_msg(
242
+ py_typed_path.exists(),
243
+ f"Expected py.typed file to exist at {py_typed_path}",
244
+ )
245
+
246
+
247
+ @autouse_session_fixture
248
+ def _test_project_structure_mirrored() -> None:
249
+ """Verify that the project structure is mirrored in tests.
250
+
251
+ This fixture runs once per test session and checks that for every package and
252
+ module in the source package, there is a corresponding test package and module.
253
+
254
+ Raises:
255
+ AssertionError: If any package or module doesn't have a corresponding test
256
+
257
+ """
258
+ src_package = get_src_package()
259
+
260
+ # we will now go through all the modules in the src package and check
261
+ # that there is a corresponding test module
262
+ for package, modules in walk_package(src_package):
263
+ test_package_name = make_test_obj_importpath_from_obj(package)
264
+ test_package = import_module(test_package_name)
265
+ assert_with_msg(
266
+ bool(test_package),
267
+ f"Expected test package {test_package_name} to be a module",
268
+ )
269
+
270
+ for module in modules:
271
+ test_module_name = make_test_obj_importpath_from_obj(module)
272
+ test_module = import_module(test_module_name)
273
+ assert_with_msg(
274
+ bool(test_module),
275
+ f"Expected test module {test_module_name} to be a module",
276
+ )
277
+
278
+
279
+ @autouse_session_fixture
280
+ def _test_no_unitest_package_usage() -> None:
281
+ """Verify that the unittest package is not used in the project.
282
+
283
+ This fixture runs once per test session and checks that the unittest package
284
+ is not used in the project.
285
+
286
+ Raises:
287
+ AssertionError: If the unittest package is used
288
+
289
+ """
290
+ for path in Path().rglob("*.py"):
291
+ if path == to_path(__name__, is_package=False):
292
+ continue
293
+ assert_with_msg(
294
+ "unittest" not in path.read_text(encoding="utf-8"),
295
+ f"Found unittest usage in {path}. Use pytest instead.",
296
+ )