winipedia-utils 0.4.41__tar.gz → 0.4.46__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.

Potentially problematic release.


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

Files changed (94) hide show
  1. {winipedia_utils-0.4.41 → winipedia_utils-0.4.46}/PKG-INFO +7 -1
  2. {winipedia_utils-0.4.41 → winipedia_utils-0.4.46}/README.md +5 -0
  3. {winipedia_utils-0.4.41 → winipedia_utils-0.4.46}/pyproject.toml +4 -1
  4. {winipedia_utils-0.4.41 → winipedia_utils-0.4.46}/winipedia_utils/git/pre_commit/hooks.py +1 -1
  5. {winipedia_utils-0.4.41 → winipedia_utils-0.4.46}/winipedia_utils/iterating/iterate.py +6 -1
  6. {winipedia_utils-0.4.41 → winipedia_utils-0.4.46}/winipedia_utils/modules/module.py +22 -0
  7. {winipedia_utils-0.4.41 → winipedia_utils-0.4.46}/winipedia_utils/modules/package.py +81 -0
  8. {winipedia_utils-0.4.41 → winipedia_utils-0.4.46}/winipedia_utils/projects/poetry/config.py +4 -1
  9. {winipedia_utils-0.4.41 → winipedia_utils-0.4.46}/winipedia_utils/text/config.py +9 -4
  10. {winipedia_utils-0.4.41 → winipedia_utils-0.4.46}/LICENSE +0 -0
  11. {winipedia_utils-0.4.41 → winipedia_utils-0.4.46}/winipedia_utils/__init__.py +0 -0
  12. {winipedia_utils-0.4.41 → winipedia_utils-0.4.46}/winipedia_utils/concurrent/__init__.py +0 -0
  13. {winipedia_utils-0.4.41 → winipedia_utils-0.4.46}/winipedia_utils/concurrent/concurrent.py +0 -0
  14. {winipedia_utils-0.4.41 → winipedia_utils-0.4.46}/winipedia_utils/concurrent/multiprocessing.py +0 -0
  15. {winipedia_utils-0.4.41 → winipedia_utils-0.4.46}/winipedia_utils/concurrent/multithreading.py +0 -0
  16. {winipedia_utils-0.4.41 → winipedia_utils-0.4.46}/winipedia_utils/data/__init__.py +0 -0
  17. {winipedia_utils-0.4.41 → winipedia_utils-0.4.46}/winipedia_utils/data/dataframe/__init__.py +0 -0
  18. {winipedia_utils-0.4.41 → winipedia_utils-0.4.46}/winipedia_utils/data/dataframe/cleaning.py +0 -0
  19. {winipedia_utils-0.4.41 → winipedia_utils-0.4.46}/winipedia_utils/data/structures/__init__.py +0 -0
  20. {winipedia_utils-0.4.41 → winipedia_utils-0.4.46}/winipedia_utils/data/structures/dicts.py +0 -0
  21. {winipedia_utils-0.4.41 → winipedia_utils-0.4.46}/winipedia_utils/git/__init__.py +0 -0
  22. {winipedia_utils-0.4.41 → winipedia_utils-0.4.46}/winipedia_utils/git/github/__init__.py +0 -0
  23. {winipedia_utils-0.4.41 → winipedia_utils-0.4.46}/winipedia_utils/git/github/github.py +0 -0
  24. {winipedia_utils-0.4.41 → winipedia_utils-0.4.46}/winipedia_utils/git/github/repo/__init__.py +0 -0
  25. {winipedia_utils-0.4.41 → winipedia_utils-0.4.46}/winipedia_utils/git/github/repo/protect.py +0 -0
  26. {winipedia_utils-0.4.41 → winipedia_utils-0.4.46}/winipedia_utils/git/github/repo/repo.py +0 -0
  27. {winipedia_utils-0.4.41 → winipedia_utils-0.4.46}/winipedia_utils/git/github/workflows/__init__.py +0 -0
  28. {winipedia_utils-0.4.41 → winipedia_utils-0.4.46}/winipedia_utils/git/github/workflows/base/__init__.py +0 -0
  29. {winipedia_utils-0.4.41 → winipedia_utils-0.4.46}/winipedia_utils/git/github/workflows/base/base.py +0 -0
  30. {winipedia_utils-0.4.41 → winipedia_utils-0.4.46}/winipedia_utils/git/github/workflows/health_check.py +0 -0
  31. {winipedia_utils-0.4.41 → winipedia_utils-0.4.46}/winipedia_utils/git/github/workflows/publish.py +0 -0
  32. {winipedia_utils-0.4.41 → winipedia_utils-0.4.46}/winipedia_utils/git/github/workflows/release.py +0 -0
  33. {winipedia_utils-0.4.41 → winipedia_utils-0.4.46}/winipedia_utils/git/gitignore/__init__.py +0 -0
  34. {winipedia_utils-0.4.41 → winipedia_utils-0.4.46}/winipedia_utils/git/gitignore/config.py +0 -0
  35. {winipedia_utils-0.4.41 → winipedia_utils-0.4.46}/winipedia_utils/git/gitignore/gitignore.py +0 -0
  36. {winipedia_utils-0.4.41 → winipedia_utils-0.4.46}/winipedia_utils/git/pre_commit/__init__.py +0 -0
  37. {winipedia_utils-0.4.41 → winipedia_utils-0.4.46}/winipedia_utils/git/pre_commit/config.py +0 -0
  38. {winipedia_utils-0.4.41 → winipedia_utils-0.4.46}/winipedia_utils/git/pre_commit/run_hooks.py +0 -0
  39. {winipedia_utils-0.4.41 → winipedia_utils-0.4.46}/winipedia_utils/iterating/__init__.py +0 -0
  40. {winipedia_utils-0.4.41 → winipedia_utils-0.4.46}/winipedia_utils/logging/__init__.py +0 -0
  41. {winipedia_utils-0.4.41 → winipedia_utils-0.4.46}/winipedia_utils/logging/ansi.py +0 -0
  42. {winipedia_utils-0.4.41 → winipedia_utils-0.4.46}/winipedia_utils/logging/config.py +0 -0
  43. {winipedia_utils-0.4.41 → winipedia_utils-0.4.46}/winipedia_utils/logging/logger.py +0 -0
  44. {winipedia_utils-0.4.41 → winipedia_utils-0.4.46}/winipedia_utils/modules/__init__.py +0 -0
  45. {winipedia_utils-0.4.41 → winipedia_utils-0.4.46}/winipedia_utils/modules/class_.py +0 -0
  46. {winipedia_utils-0.4.41 → winipedia_utils-0.4.46}/winipedia_utils/modules/function.py +0 -0
  47. {winipedia_utils-0.4.41 → winipedia_utils-0.4.46}/winipedia_utils/oop/__init__.py +0 -0
  48. {winipedia_utils-0.4.41 → winipedia_utils-0.4.46}/winipedia_utils/oop/mixins/__init__.py +0 -0
  49. {winipedia_utils-0.4.41 → winipedia_utils-0.4.46}/winipedia_utils/oop/mixins/meta.py +0 -0
  50. {winipedia_utils-0.4.41 → winipedia_utils-0.4.46}/winipedia_utils/oop/mixins/mixin.py +0 -0
  51. {winipedia_utils-0.4.41 → winipedia_utils-0.4.46}/winipedia_utils/os/__init__.py +0 -0
  52. {winipedia_utils-0.4.41 → winipedia_utils-0.4.46}/winipedia_utils/os/os.py +0 -0
  53. {winipedia_utils-0.4.41 → winipedia_utils-0.4.46}/winipedia_utils/projects/__init__.py +0 -0
  54. {winipedia_utils-0.4.41 → winipedia_utils-0.4.46}/winipedia_utils/projects/poetry/__init__.py +0 -0
  55. {winipedia_utils-0.4.41 → winipedia_utils-0.4.46}/winipedia_utils/projects/poetry/poetry.py +0 -0
  56. {winipedia_utils-0.4.41 → winipedia_utils-0.4.46}/winipedia_utils/projects/project.py +0 -0
  57. {winipedia_utils-0.4.41 → winipedia_utils-0.4.46}/winipedia_utils/py.typed +0 -0
  58. {winipedia_utils-0.4.41 → winipedia_utils-0.4.46}/winipedia_utils/resources/__init__.py +0 -0
  59. {winipedia_utils-0.4.41 → winipedia_utils-0.4.46}/winipedia_utils/resources/svgs/__init__.py +0 -0
  60. {winipedia_utils-0.4.41 → winipedia_utils-0.4.46}/winipedia_utils/resources/svgs/delete_garbage_can.svg +0 -0
  61. {winipedia_utils-0.4.41 → winipedia_utils-0.4.46}/winipedia_utils/resources/svgs/download_arrow.svg +0 -0
  62. {winipedia_utils-0.4.41 → winipedia_utils-0.4.46}/winipedia_utils/resources/svgs/exit_fullscreen_icon.svg +0 -0
  63. {winipedia_utils-0.4.41 → winipedia_utils-0.4.46}/winipedia_utils/resources/svgs/fullscreen_icon.svg +0 -0
  64. {winipedia_utils-0.4.41 → winipedia_utils-0.4.46}/winipedia_utils/resources/svgs/menu_icon.svg +0 -0
  65. {winipedia_utils-0.4.41 → winipedia_utils-0.4.46}/winipedia_utils/resources/svgs/pause_icon.svg +0 -0
  66. {winipedia_utils-0.4.41 → winipedia_utils-0.4.46}/winipedia_utils/resources/svgs/play_icon.svg +0 -0
  67. {winipedia_utils-0.4.41 → winipedia_utils-0.4.46}/winipedia_utils/resources/svgs/plus_icon.svg +0 -0
  68. {winipedia_utils-0.4.41 → winipedia_utils-0.4.46}/winipedia_utils/resources/svgs/svg.py +0 -0
  69. {winipedia_utils-0.4.41 → winipedia_utils-0.4.46}/winipedia_utils/security/__init__.py +0 -0
  70. {winipedia_utils-0.4.41 → winipedia_utils-0.4.46}/winipedia_utils/security/cryptography.py +0 -0
  71. {winipedia_utils-0.4.41 → winipedia_utils-0.4.46}/winipedia_utils/security/keyring.py +0 -0
  72. {winipedia_utils-0.4.41 → winipedia_utils-0.4.46}/winipedia_utils/setup.py +0 -0
  73. {winipedia_utils-0.4.41 → winipedia_utils-0.4.46}/winipedia_utils/testing/__init__.py +0 -0
  74. {winipedia_utils-0.4.41 → winipedia_utils-0.4.46}/winipedia_utils/testing/assertions.py +0 -0
  75. {winipedia_utils-0.4.41 → winipedia_utils-0.4.46}/winipedia_utils/testing/config.py +0 -0
  76. {winipedia_utils-0.4.41 → winipedia_utils-0.4.46}/winipedia_utils/testing/convention.py +0 -0
  77. {winipedia_utils-0.4.41 → winipedia_utils-0.4.46}/winipedia_utils/testing/create_tests.py +0 -0
  78. {winipedia_utils-0.4.41 → winipedia_utils-0.4.46}/winipedia_utils/testing/fixtures.py +0 -0
  79. {winipedia_utils-0.4.41 → winipedia_utils-0.4.46}/winipedia_utils/testing/skip.py +0 -0
  80. {winipedia_utils-0.4.41 → winipedia_utils-0.4.46}/winipedia_utils/testing/tests/__init__.py +0 -0
  81. {winipedia_utils-0.4.41 → winipedia_utils-0.4.46}/winipedia_utils/testing/tests/base/__init__.py +0 -0
  82. {winipedia_utils-0.4.41 → winipedia_utils-0.4.46}/winipedia_utils/testing/tests/base/fixtures/__init__.py +0 -0
  83. {winipedia_utils-0.4.41 → winipedia_utils-0.4.46}/winipedia_utils/testing/tests/base/fixtures/fixture.py +0 -0
  84. {winipedia_utils-0.4.41 → winipedia_utils-0.4.46}/winipedia_utils/testing/tests/base/fixtures/scopes/__init__.py +0 -0
  85. {winipedia_utils-0.4.41 → winipedia_utils-0.4.46}/winipedia_utils/testing/tests/base/fixtures/scopes/class_.py +0 -0
  86. {winipedia_utils-0.4.41 → winipedia_utils-0.4.46}/winipedia_utils/testing/tests/base/fixtures/scopes/function.py +0 -0
  87. {winipedia_utils-0.4.41 → winipedia_utils-0.4.46}/winipedia_utils/testing/tests/base/fixtures/scopes/module.py +0 -0
  88. {winipedia_utils-0.4.41 → winipedia_utils-0.4.46}/winipedia_utils/testing/tests/base/fixtures/scopes/package.py +0 -0
  89. {winipedia_utils-0.4.41 → winipedia_utils-0.4.46}/winipedia_utils/testing/tests/base/fixtures/scopes/session.py +0 -0
  90. {winipedia_utils-0.4.41 → winipedia_utils-0.4.46}/winipedia_utils/testing/tests/base/utils/__init__.py +0 -0
  91. {winipedia_utils-0.4.41 → winipedia_utils-0.4.46}/winipedia_utils/testing/tests/base/utils/utils.py +0 -0
  92. {winipedia_utils-0.4.41 → winipedia_utils-0.4.46}/winipedia_utils/testing/tests/conftest.py +0 -0
  93. {winipedia_utils-0.4.41 → winipedia_utils-0.4.46}/winipedia_utils/text/__init__.py +0 -0
  94. {winipedia_utils-0.4.41 → winipedia_utils-0.4.46}/winipedia_utils/text/string.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: winipedia-utils
3
- Version: 0.4.41
3
+ Version: 0.4.46
4
4
  Summary: A package with many utility functions
5
5
  License-Expression: MIT
6
6
  License-File: LICENSE
@@ -15,6 +15,7 @@ Requires-Dist: cryptography
15
15
  Requires-Dist: defusedxml
16
16
  Requires-Dist: dotenv
17
17
  Requires-Dist: keyring
18
+ Requires-Dist: networkx
18
19
  Requires-Dist: pathspec
19
20
  Requires-Dist: polars
20
21
  Requires-Dist: pygithub
@@ -152,6 +153,10 @@ my_project/
152
153
 
153
154
  For each function, class, and method, skeleton tests are created with `NotImplementedError` placeholders for you to implement.
154
155
 
156
+ If you have autosuse fixtures just write and add them to the `tests/base/fixtures` directory. They will be automatically discovered, plugged into conftest and used in all tests according to defined scope.
157
+ The filenames in the fixtures folder are just for organisation purposes for your convenience. You still have to
158
+ apply the pytest.fixture decorator to the fixture function and define the scope. So a session scoped function defined on function.py will still run as a session scoped fixture.
159
+
155
160
  ## Configuration Files
156
161
 
157
162
  Configuration files are managed automatically by the setup system:
@@ -160,6 +165,7 @@ Configuration files are managed automatically by the setup system:
160
165
  - **Empty files** - If you want to disable a config file, make it empty. This signals that the file is unwanted and won't be modified
161
166
  - **Custom additions** - You can add custom configurations as long as the standard configurations remain intact
162
167
  - **Modified standards** - If you modify the standard configurations, they will be restored on the next setup run
168
+ - **Subclasses** - You can create custom config files by subclassing the standard ones. They will be automatically created and managed when you commit or run pytest. winipedia_utils automatically discovers and calls them. This way you can adjust or add some settings. It is however important the parent class stays a subset of the child class according to the description in the function `nested_structure_is_subset` in `winipedia_utils.iterating.iterate`.
163
169
 
164
170
  ## Branch Protection
165
171
 
@@ -126,6 +126,10 @@ my_project/
126
126
 
127
127
  For each function, class, and method, skeleton tests are created with `NotImplementedError` placeholders for you to implement.
128
128
 
129
+ If you have autosuse fixtures just write and add them to the `tests/base/fixtures` directory. They will be automatically discovered, plugged into conftest and used in all tests according to defined scope.
130
+ The filenames in the fixtures folder are just for organisation purposes for your convenience. You still have to
131
+ apply the pytest.fixture decorator to the fixture function and define the scope. So a session scoped function defined on function.py will still run as a session scoped fixture.
132
+
129
133
  ## Configuration Files
130
134
 
131
135
  Configuration files are managed automatically by the setup system:
@@ -134,6 +138,7 @@ Configuration files are managed automatically by the setup system:
134
138
  - **Empty files** - If you want to disable a config file, make it empty. This signals that the file is unwanted and won't be modified
135
139
  - **Custom additions** - You can add custom configurations as long as the standard configurations remain intact
136
140
  - **Modified standards** - If you modify the standard configurations, they will be restored on the next setup run
141
+ - **Subclasses** - You can create custom config files by subclassing the standard ones. They will be automatically created and managed when you commit or run pytest. winipedia_utils automatically discovers and calls them. This way you can adjust or add some settings. It is however important the parent class stays a subset of the child class according to the description in the function `nested_structure_is_subset` in `winipedia_utils.iterating.iterate`.
137
142
 
138
143
  ## Branch Protection
139
144
 
@@ -1,7 +1,7 @@
1
1
  # Project section
2
2
  [project]
3
3
  name = "winipedia-utils"
4
- version = "0.4.41"
4
+ version = "0.4.46"
5
5
  description = "A package with many utility functions"
6
6
  readme = "README.md"
7
7
  requires-python = ">=3.12"
@@ -32,6 +32,7 @@ cryptography = "*"
32
32
  polars = "*"
33
33
  pygithub = "*"
34
34
  dotenv = "*"
35
+ networkx = "*"
35
36
 
36
37
  [tool.poetry.group.dev.dependencies]
37
38
  ruff = "*"
@@ -44,6 +45,7 @@ types-tqdm = "*"
44
45
  types-defusedxml = "*"
45
46
  types-pyyaml = "*"
46
47
  pytest-mock = "*"
48
+ types-networkx = "*"
47
49
 
48
50
  [tool.ruff]
49
51
  exclude = [ ".*", "**/migrations/*.py",]
@@ -64,3 +66,4 @@ files = "."
64
66
  testpaths = [ "tests",]
65
67
 
66
68
  [tool.bandit]
69
+ exclude_dirs = ["experiment.py"]
@@ -127,7 +127,7 @@ def check_static_types() -> list[str | Path]:
127
127
 
128
128
  This function returns the input for subprocess.run() to check the static types.
129
129
  """
130
- return ["mypy"]
130
+ return ["mypy", "--exclude-gitignore"]
131
131
 
132
132
 
133
133
  def check_security() -> list[str | Path]:
@@ -49,7 +49,7 @@ def nested_structure_is_subset(
49
49
  Each value of a key must be equal to the value of the same key in the superset.
50
50
  If the value is dictionary, the function is called recursively.
51
51
  If the value is list, each item must be in the list of the same key in the superset.
52
- The order in lists matters.
52
+ The order in lists does not matter.
53
53
 
54
54
  Returns:
55
55
  True if subset is a nested subset of superset, False otherwise
@@ -68,6 +68,11 @@ def nested_structure_is_subset(
68
68
 
69
69
  def get_actual(key_or_index: Any) -> Any:
70
70
  """Get actual value from superset."""
71
+ subset_val = subset[key_or_index]
72
+ for superset_val in superset:
73
+ if nested_structure_is_subset(subset_val, superset_val):
74
+ return superset_val
75
+
71
76
  return superset[key_or_index] if key_or_index < len(superset) else None
72
77
  else:
73
78
  return subset == superset
@@ -379,3 +379,25 @@ def get_unwrapped_obj(obj: Any) -> Any:
379
379
  if isinstance(obj, property):
380
380
  obj = obj.fget # get the getter function of the property
381
381
  return inspect.unwrap(obj)
382
+
383
+
384
+ def get_executing_module() -> ModuleType:
385
+ """Get the module where execution has started.
386
+
387
+ The executing module is the module that contains the __main__ attribute as __name__
388
+ E.g. if you run `python -m winipedia_utils.setup` from the command line,
389
+ then the executing module is winipedia_utils.modules.setup
390
+
391
+ Returns:
392
+ The module where execution has started
393
+
394
+ Raises:
395
+ ValueError: If no __main__ module is found or if the executing module
396
+ cannot be determined
397
+
398
+ """
399
+ main = sys.modules.get("__main__")
400
+ if main is None:
401
+ msg = "No __main__ module found"
402
+ raise ValueError(msg)
403
+ return main
@@ -9,17 +9,23 @@ The utilities support both static package analysis and dynamic package manipulat
9
9
  making them suitable for code generation, testing frameworks, and package management.
10
10
  """
11
11
 
12
+ import importlib.metadata
13
+ import importlib.util
12
14
  import os
13
15
  import pkgutil
16
+ import re
14
17
  import sys
15
18
  from collections.abc import Generator, Iterable
16
19
  from importlib import import_module
17
20
  from pathlib import Path
18
21
  from types import ModuleType
22
+ from typing import Any
19
23
 
24
+ import networkx as nx
20
25
  from setuptools import find_namespace_packages as _find_namespace_packages
21
26
  from setuptools import find_packages as _find_packages
22
27
 
28
+ import winipedia_utils
23
29
  from winipedia_utils.logging.logger import get_logger
24
30
 
25
31
  logger = get_logger(__name__)
@@ -428,3 +434,78 @@ def make_name_from_package(
428
434
  if capitalize:
429
435
  parts = [part.capitalize() for part in parts]
430
436
  return join_on.join(parts)
437
+
438
+
439
+ class DependencyGraph(nx.DiGraph): # type: ignore [type-arg]
440
+ """A directed graph representing Python package dependencies."""
441
+
442
+ def __init__(self, *args: Any, **kwargs: Any) -> None:
443
+ """Initialize the dependency graph and build it immediately."""
444
+ super().__init__(*args, **kwargs)
445
+ self.build()
446
+
447
+ def build(self) -> None:
448
+ """Build the graph from installed Python distributions."""
449
+ for dist in importlib.metadata.distributions():
450
+ name = dist.metadata["Name"].lower()
451
+ self.add_node(name)
452
+
453
+ requires = dist.requires or []
454
+ for req in requires:
455
+ dep = self.parse_pkg_name_from_req(req)
456
+ if dep:
457
+ self.add_edge(name, dep) # package → dependency
458
+
459
+ @staticmethod
460
+ def parse_pkg_name_from_req(req: str) -> str | None:
461
+ """Extract the bare dependency name from a requirement string."""
462
+ if not req:
463
+ return None
464
+ # split on the first non alphanumeric character like >, <, =, etc.
465
+ dep = re.split(r"[^a-zA-Z0-9]", req.strip())[0].strip()
466
+ return dep.lower().strip() if dep else None
467
+
468
+ def get_all_depending_on(
469
+ self, package: ModuleType, *, include_self: bool = False
470
+ ) -> set[ModuleType]:
471
+ """Return all packages that directly or indirectly depend on the given package.
472
+
473
+ Args:
474
+ package: The module whose dependents should be found.
475
+ include_self: Whether to include the package itself in the result.
476
+
477
+ Returns:
478
+ A set of imported module objects representing dependents.
479
+ """
480
+ target = package.__name__.lower()
481
+ if target not in self:
482
+ msg = f"Package '{target}' not found in dependency graph"
483
+ raise ValueError(msg)
484
+
485
+ dependents = nx.ancestors(self, target)
486
+ if include_self:
487
+ dependents.add(target)
488
+
489
+ return self.import_packages(dependents)
490
+
491
+ @staticmethod
492
+ def import_packages(names: set[str]) -> set[ModuleType]:
493
+ """Attempt to import all module names that can be resolved."""
494
+ modules: set[ModuleType] = set()
495
+ for name in names:
496
+ spec = importlib.util.find_spec(name)
497
+ if spec is not None:
498
+ modules.add(importlib.import_module(name))
499
+ return modules
500
+
501
+ def get_all_depending_on_winipedia_utils(
502
+ self, *, include_winipedia_utils: bool = False
503
+ ) -> set[ModuleType]:
504
+ """Return all packages that directly or indirectly depend on winipedia_utils."""
505
+ if get_src_package() == winipedia_utils:
506
+ deps: set[ModuleType] = set()
507
+ else:
508
+ deps = self.get_all_depending_on(winipedia_utils, include_self=False)
509
+ if include_winipedia_utils:
510
+ deps.add(winipedia_utils)
511
+ return deps
@@ -5,6 +5,7 @@ from typing import Any, cast
5
5
 
6
6
  from winipedia_utils.modules.package import get_src_package, make_name_from_package
7
7
  from winipedia_utils.projects.poetry.poetry import VersionConstraint
8
+ from winipedia_utils.testing.config import ExperimentConfigFile
8
9
  from winipedia_utils.testing.convention import TESTS_PACKAGE_NAME
9
10
  from winipedia_utils.text.config import ConfigFile, TomlConfigFile
10
11
 
@@ -62,7 +63,9 @@ class PyprojectConfigFile(TomlConfigFile):
62
63
  "files": ".",
63
64
  },
64
65
  "pytest": {"ini_options": {"testpaths": [TESTS_PACKAGE_NAME]}},
65
- "bandit": {},
66
+ "bandit": {
67
+ "exclude_dirs": [ExperimentConfigFile.get_path().as_posix()],
68
+ },
66
69
  },
67
70
  }
68
71
 
@@ -9,10 +9,9 @@ import tomlkit
9
9
  import yaml
10
10
  from dotenv import dotenv_values
11
11
 
12
- import winipedia_utils
13
12
  from winipedia_utils.iterating.iterate import nested_structure_is_subset
14
13
  from winipedia_utils.modules.class_ import init_all_nonabstract_subclasses
15
- from winipedia_utils.modules.package import get_src_package
14
+ from winipedia_utils.modules.package import DependencyGraph, get_src_package
16
15
  from winipedia_utils.projects.poetry.poetry import (
17
16
  get_python_module_script,
18
17
  )
@@ -149,8 +148,14 @@ class ConfigFile(ABC):
149
148
  @classmethod
150
149
  def init_config_files(cls) -> None:
151
150
  """Initialize all subclasses."""
152
- init_all_nonabstract_subclasses(cls, load_package_before=winipedia_utils)
153
- init_all_nonabstract_subclasses(cls, load_package_before=get_src_package())
151
+ pkgs_depending_on_winipedia_utils = (
152
+ DependencyGraph().get_all_depending_on_winipedia_utils(
153
+ include_winipedia_utils=True
154
+ )
155
+ )
156
+ pkgs_depending_on_winipedia_utils.add(get_src_package())
157
+ for pkg in pkgs_depending_on_winipedia_utils:
158
+ init_all_nonabstract_subclasses(cls, load_package_before=pkg)
154
159
 
155
160
  @staticmethod
156
161
  def get_python_setup_script() -> str: