winipedia-utils 0.1.63__py3-none-any.whl → 0.2.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.

Potentially problematic release.


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

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