winipedia-utils 0.4.43__py3-none-any.whl → 0.7.1__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 (120) hide show
  1. winipedia_utils/artifacts/build.py +27 -0
  2. winipedia_utils/dev/artifacts/build.py +62 -0
  3. winipedia_utils/{text → dev/configs/base}/config.py +16 -11
  4. winipedia_utils/{git/gitignore/config.py → dev/configs/gitignore.py} +2 -2
  5. winipedia_utils/{git/pre_commit/config.py → dev/configs/pre_commit.py} +6 -6
  6. winipedia_utils/{projects/poetry/config.py → dev/configs/pyproject.py} +120 -32
  7. winipedia_utils/{testing/config.py → dev/configs/testing.py} +7 -4
  8. winipedia_utils/dev/configs/workflows/base/base.py +907 -0
  9. winipedia_utils/dev/configs/workflows/health_check.py +69 -0
  10. winipedia_utils/dev/configs/workflows/publish.py +51 -0
  11. winipedia_utils/dev/configs/workflows/release.py +91 -0
  12. winipedia_utils/dev/git/github/repo/__init__.py +1 -0
  13. winipedia_utils/{git → dev/git}/github/repo/protect.py +5 -5
  14. winipedia_utils/dev/git/pre_commit/hooks.py +85 -0
  15. winipedia_utils/{git → dev/git}/pre_commit/run_hooks.py +23 -13
  16. winipedia_utils/dev/projects/poetry/dev_deps.py +21 -0
  17. winipedia_utils/dev/projects/poetry/poetry.py +248 -0
  18. winipedia_utils/{projects → dev/projects}/project.py +6 -7
  19. winipedia_utils/dev/testing/__init__.py +1 -0
  20. winipedia_utils/{testing → dev/testing}/convention.py +1 -1
  21. winipedia_utils/{testing → dev/testing}/create_tests.py +14 -14
  22. winipedia_utils/dev/testing/tests/__init__.py +1 -0
  23. winipedia_utils/dev/testing/tests/base/__init__.py +1 -0
  24. winipedia_utils/dev/testing/tests/base/fixtures/__init__.py +1 -0
  25. winipedia_utils/{testing → dev/testing}/tests/base/fixtures/fixture.py +1 -1
  26. winipedia_utils/dev/testing/tests/base/fixtures/scopes/__init__.py +1 -0
  27. winipedia_utils/{testing → dev/testing}/tests/base/fixtures/scopes/class_.py +2 -2
  28. winipedia_utils/{testing → dev/testing}/tests/base/fixtures/scopes/module.py +2 -2
  29. winipedia_utils/{testing → dev/testing}/tests/base/fixtures/scopes/session.py +10 -10
  30. winipedia_utils/dev/testing/tests/base/utils/__init__.py +1 -0
  31. winipedia_utils/dev/testing/tests/base/utils/utils.py +1 -0
  32. winipedia_utils/{testing → dev/testing}/tests/conftest.py +2 -2
  33. winipedia_utils/{testing/tests/base/utils → dev/testing}/utils.py +7 -24
  34. winipedia_utils/setup.py +9 -5
  35. winipedia_utils/utils/__init__.py +1 -0
  36. winipedia_utils/utils/data/dataframe/__init__.py +1 -0
  37. winipedia_utils/{data → utils/data}/dataframe/cleaning.py +1 -1
  38. winipedia_utils/utils/data/structures/__init__.py +1 -0
  39. winipedia_utils/{text → utils/data/structures/text}/string.py +36 -3
  40. winipedia_utils/utils/git/__init__.py +1 -0
  41. winipedia_utils/utils/git/github/__init__.py +1 -0
  42. winipedia_utils/{git → utils/git}/github/github.py +1 -1
  43. winipedia_utils/utils/git/github/repo/__init__.py +1 -0
  44. winipedia_utils/{git → utils/git}/github/repo/repo.py +1 -1
  45. winipedia_utils/{git → utils/git}/gitignore/gitignore.py +2 -2
  46. winipedia_utils/{concurrent → utils/iterating/concurrent}/concurrent.py +4 -4
  47. winipedia_utils/{concurrent → utils/iterating/concurrent}/multiprocessing.py +2 -2
  48. winipedia_utils/{concurrent → utils/iterating/concurrent}/multithreading.py +1 -1
  49. winipedia_utils/{logging → utils/logging}/logger.py +1 -1
  50. winipedia_utils/{modules → utils/modules}/class_.py +15 -8
  51. winipedia_utils/{modules → utils/modules}/function.py +10 -4
  52. winipedia_utils/utils/modules/inspection.py +56 -0
  53. winipedia_utils/{modules → utils/modules}/module.py +27 -32
  54. winipedia_utils/{modules → utils/modules}/package.py +100 -34
  55. winipedia_utils/{oop → utils/oop}/mixins/meta.py +4 -4
  56. winipedia_utils/{oop → utils/oop}/mixins/mixin.py +2 -2
  57. winipedia_utils/{os → utils/os}/os.py +2 -2
  58. winipedia_utils/utils/resources/__init__.py +1 -0
  59. winipedia_utils/utils/resources/svgs/__init__.py +1 -0
  60. winipedia_utils/{resources → utils/resources}/svgs/svg.py +1 -1
  61. winipedia_utils/utils/testing/__init__.py +1 -0
  62. winipedia_utils/{testing → utils/testing}/assertions.py +18 -0
  63. winipedia_utils/{testing → utils/testing}/skip.py +1 -1
  64. {winipedia_utils-0.4.43.dist-info → winipedia_utils-0.7.1.dist-info}/METADATA +71 -36
  65. winipedia_utils-0.7.1.dist-info/RECORD +109 -0
  66. winipedia_utils/git/github/workflows/base/base.py +0 -294
  67. winipedia_utils/git/github/workflows/health_check.py +0 -57
  68. winipedia_utils/git/github/workflows/publish.py +0 -49
  69. winipedia_utils/git/github/workflows/release.py +0 -45
  70. winipedia_utils/git/pre_commit/hooks.py +0 -147
  71. winipedia_utils/projects/poetry/poetry.py +0 -129
  72. winipedia_utils/testing/__init__.py +0 -1
  73. winipedia_utils/testing/tests/__init__.py +0 -1
  74. winipedia_utils/testing/tests/base/__init__.py +0 -1
  75. winipedia_utils/testing/tests/base/fixtures/__init__.py +0 -1
  76. winipedia_utils/testing/tests/base/fixtures/scopes/__init__.py +0 -1
  77. winipedia_utils/testing/tests/base/utils/__init__.py +0 -1
  78. winipedia_utils-0.4.43.dist-info/RECORD +0 -94
  79. /winipedia_utils/{data/dataframe → artifacts}/__init__.py +0 -0
  80. /winipedia_utils/{data/structures → dev}/__init__.py +0 -0
  81. /winipedia_utils/{git/github → dev/artifacts}/__init__.py +0 -0
  82. /winipedia_utils/{git/github/repo → dev/configs}/__init__.py +0 -0
  83. /winipedia_utils/{git/github/workflows → dev/configs}/base/__init__.py +0 -0
  84. /winipedia_utils/{git/github → dev/configs}/workflows/__init__.py +0 -0
  85. /winipedia_utils/{resources → dev/configs/workflows/base}/__init__.py +0 -0
  86. /winipedia_utils/{git → dev/git}/__init__.py +0 -0
  87. /winipedia_utils/{resources/svgs → dev/git/github}/__init__.py +0 -0
  88. /winipedia_utils/{git → dev/git}/pre_commit/__init__.py +0 -0
  89. /winipedia_utils/{projects → dev/projects}/__init__.py +0 -0
  90. /winipedia_utils/{projects → dev/projects}/poetry/__init__.py +0 -0
  91. /winipedia_utils/{testing → dev/testing}/tests/base/fixtures/scopes/function.py +0 -0
  92. /winipedia_utils/{testing → dev/testing}/tests/base/fixtures/scopes/package.py +0 -0
  93. /winipedia_utils/{data → utils/data}/__init__.py +0 -0
  94. /winipedia_utils/{data → utils/data}/structures/dicts.py +0 -0
  95. /winipedia_utils/{text → utils/data/structures/text}/__init__.py +0 -0
  96. /winipedia_utils/{git → utils/git}/gitignore/__init__.py +0 -0
  97. /winipedia_utils/{iterating → utils/iterating}/__init__.py +0 -0
  98. /winipedia_utils/{concurrent → utils/iterating/concurrent}/__init__.py +0 -0
  99. /winipedia_utils/{iterating → utils/iterating}/iterate.py +0 -0
  100. /winipedia_utils/{logging → utils/logging}/__init__.py +0 -0
  101. /winipedia_utils/{logging → utils/logging}/ansi.py +0 -0
  102. /winipedia_utils/{logging → utils/logging}/config.py +0 -0
  103. /winipedia_utils/{modules → utils/modules}/__init__.py +0 -0
  104. /winipedia_utils/{oop → utils/oop}/__init__.py +0 -0
  105. /winipedia_utils/{oop → utils/oop}/mixins/__init__.py +0 -0
  106. /winipedia_utils/{os → utils/os}/__init__.py +0 -0
  107. /winipedia_utils/{resources → utils/resources}/svgs/delete_garbage_can.svg +0 -0
  108. /winipedia_utils/{resources → utils/resources}/svgs/download_arrow.svg +0 -0
  109. /winipedia_utils/{resources → utils/resources}/svgs/exit_fullscreen_icon.svg +0 -0
  110. /winipedia_utils/{resources → utils/resources}/svgs/fullscreen_icon.svg +0 -0
  111. /winipedia_utils/{resources → utils/resources}/svgs/menu_icon.svg +0 -0
  112. /winipedia_utils/{resources → utils/resources}/svgs/pause_icon.svg +0 -0
  113. /winipedia_utils/{resources → utils/resources}/svgs/play_icon.svg +0 -0
  114. /winipedia_utils/{resources → utils/resources}/svgs/plus_icon.svg +0 -0
  115. /winipedia_utils/{security → utils/security}/__init__.py +0 -0
  116. /winipedia_utils/{security → utils/security}/cryptography.py +0 -0
  117. /winipedia_utils/{security → utils/security}/keyring.py +0 -0
  118. /winipedia_utils/{testing → utils/testing}/fixtures.py +0 -0
  119. {winipedia_utils-0.4.43.dist-info → winipedia_utils-0.7.1.dist-info}/WHEEL +0 -0
  120. {winipedia_utils-0.4.43.dist-info → winipedia_utils-0.7.1.dist-info}/licenses/LICENSE +0 -0
@@ -13,7 +13,7 @@ from collections.abc import Callable, Iterable
13
13
  from types import ModuleType
14
14
  from typing import Any
15
15
 
16
- from winipedia_utils.modules.module import (
16
+ from winipedia_utils.utils.modules.module import (
17
17
  get_isolated_obj_name,
18
18
  import_obj_from_importpath,
19
19
  make_obj_importpath,
@@ -9,31 +9,31 @@ NotImplementedError to indicate tests that need to be written.
9
9
  from types import ModuleType
10
10
  from typing import cast
11
11
 
12
- from winipedia_utils.modules.class_ import (
12
+ from winipedia_utils.dev.configs.testing import ConftestConfigFile, ZeroTestConfigFile
13
+ from winipedia_utils.dev.testing import tests
14
+ from winipedia_utils.dev.testing.convention import (
15
+ get_test_obj_from_obj,
16
+ make_test_obj_importpath_from_obj,
17
+ make_test_obj_name,
18
+ reverse_make_test_obj_name,
19
+ )
20
+ from winipedia_utils.utils.modules.class_ import (
13
21
  get_all_cls_from_module,
14
22
  get_all_methods_from_cls,
15
23
  )
16
- from winipedia_utils.modules.function import get_all_functions_from_module
17
- from winipedia_utils.modules.module import (
24
+ from winipedia_utils.utils.modules.function import get_all_functions_from_module
25
+ from winipedia_utils.utils.modules.inspection import get_qualname_of_obj
26
+ from winipedia_utils.utils.modules.module import (
18
27
  create_module,
19
28
  get_isolated_obj_name,
20
29
  get_module_content_as_str,
21
- get_qualname_of_obj,
22
30
  to_path,
23
31
  )
24
- from winipedia_utils.modules.package import (
32
+ from winipedia_utils.utils.modules.package import (
25
33
  copy_package,
26
34
  get_src_package,
27
35
  walk_package,
28
36
  )
29
- from winipedia_utils.testing import tests
30
- from winipedia_utils.testing.config import ConftestConfigFile, ZeroTestConfigFile
31
- from winipedia_utils.testing.convention import (
32
- get_test_obj_from_obj,
33
- make_test_obj_importpath_from_obj,
34
- make_test_obj_name,
35
- reverse_make_test_obj_name,
36
- )
37
37
 
38
38
 
39
39
  def create_tests() -> None:
@@ -50,7 +50,7 @@ def create_tests_base() -> None:
50
50
  """Create the base test structure.
51
51
 
52
52
  This function:
53
- 1. Creates a mirror of winipedia_utils.testing.tests in the tests directory
53
+ 1. Creates a mirror of testing.tests in the tests directory
54
54
  2. Skips copying __init__.py file contents
55
55
  3. Writes new __init__.py files for all packages
56
56
  4. Creates a conftest.py file with the appropriate pytest plugin configuration
@@ -0,0 +1 @@
1
+ """__init__ module."""
@@ -0,0 +1 @@
1
+ """__init__ module."""
@@ -0,0 +1 @@
1
+ """__init__ module."""
@@ -10,7 +10,7 @@ from pathlib import Path
10
10
 
11
11
  import pytest
12
12
 
13
- from winipedia_utils.text.config import ConfigFile
13
+ from winipedia_utils.dev.configs.base.config import ConfigFile
14
14
 
15
15
 
16
16
  @pytest.fixture
@@ -0,0 +1 @@
1
+ """__init__ module."""
@@ -8,8 +8,8 @@ mechanism.
8
8
 
9
9
  import pytest
10
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
11
+ from winipedia_utils.dev.testing.utils import assert_no_untested_objs
12
+ from winipedia_utils.utils.testing.fixtures import autouse_class_fixture
13
13
 
14
14
 
15
15
  @autouse_class_fixture
@@ -10,8 +10,8 @@ from typing import TYPE_CHECKING
10
10
 
11
11
  import pytest
12
12
 
13
- from winipedia_utils.testing.fixtures import autouse_module_fixture
14
- from winipedia_utils.testing.tests.base.utils.utils import assert_no_untested_objs
13
+ from winipedia_utils.dev.testing.utils import assert_no_untested_objs
14
+ from winipedia_utils.utils.testing.fixtures import autouse_module_fixture
15
15
 
16
16
  if TYPE_CHECKING:
17
17
  from types import ModuleType
@@ -10,21 +10,21 @@ from importlib import import_module
10
10
  from pathlib import Path
11
11
 
12
12
  import winipedia_utils
13
- from winipedia_utils.modules.package import (
14
- find_packages,
15
- get_src_package,
16
- walk_package,
17
- )
18
- from winipedia_utils.projects.poetry.config import (
13
+ from winipedia_utils.dev.configs.base.config import ConfigFile
14
+ from winipedia_utils.dev.configs.pyproject import (
19
15
  PyprojectConfigFile,
20
16
  )
21
- from winipedia_utils.testing.assertions import assert_with_msg
22
- from winipedia_utils.testing.convention import (
17
+ from winipedia_utils.dev.testing.convention import (
23
18
  TESTS_PACKAGE_NAME,
24
19
  make_test_obj_importpath_from_obj,
25
20
  )
26
- from winipedia_utils.testing.fixtures import autouse_session_fixture
27
- from winipedia_utils.text.config import ConfigFile
21
+ from winipedia_utils.utils.modules.package import (
22
+ find_packages,
23
+ get_src_package,
24
+ walk_package,
25
+ )
26
+ from winipedia_utils.utils.testing.assertions import assert_with_msg
27
+ from winipedia_utils.utils.testing.fixtures import autouse_session_fixture
28
28
 
29
29
 
30
30
  @autouse_session_fixture
@@ -0,0 +1 @@
1
+ """__init__ module."""
@@ -0,0 +1 @@
1
+ """Testing utilities."""
@@ -7,13 +7,13 @@ and adds them to pytest_plugins. This way defining reusable fixtures is easy.
7
7
  from pathlib import Path
8
8
 
9
9
  import winipedia_utils
10
- from winipedia_utils.modules.module import to_module_name, to_path
10
+ from winipedia_utils.utils.modules.module import to_module_name, to_path
11
11
 
12
12
  package_path = Path(winipedia_utils.__path__[0])
13
13
 
14
14
  custom_plugin_path = to_path("tests.base.fixtures", is_package=True)
15
15
  package_plugin_path = (
16
- package_path / to_path("testing", is_package=True) / custom_plugin_path
16
+ package_path / to_path("dev.testing", is_package=True) / custom_plugin_path
17
17
  )
18
18
 
19
19
  custom_plugin_module_names = [
@@ -13,18 +13,17 @@ from collections.abc import Callable
13
13
  from types import ModuleType
14
14
  from typing import Any
15
15
 
16
- from winipedia_utils.logging.logger import get_logger
17
- from winipedia_utils.modules.function import is_abstractmethod
18
- from winipedia_utils.modules.module import (
19
- get_objs_from_obj,
20
- make_obj_importpath,
21
- )
22
- from winipedia_utils.testing.assertions import assert_with_msg
23
- from winipedia_utils.testing.convention import (
16
+ from winipedia_utils.dev.testing.convention import (
24
17
  get_obj_from_test_obj,
25
18
  make_test_obj_importpath_from_obj,
26
19
  make_untested_summary_error_msg,
27
20
  )
21
+ from winipedia_utils.utils.logging.logger import get_logger
22
+ from winipedia_utils.utils.modules.module import (
23
+ get_objs_from_obj,
24
+ make_obj_importpath,
25
+ )
26
+ from winipedia_utils.utils.testing.assertions import assert_with_msg
28
27
 
29
28
  logger = get_logger(__name__)
30
29
 
@@ -63,19 +62,3 @@ def assert_no_untested_objs(
63
62
  untested_objs = supposed_test_objs_paths - test_objs_paths
64
63
 
65
64
  assert_with_msg(not untested_objs, make_untested_summary_error_msg(untested_objs))
66
-
67
-
68
- def assert_isabstrct_method(method: Any) -> None:
69
- """Assert that a method is an abstract method.
70
-
71
- Args:
72
- method: The method to check
73
-
74
- Raises:
75
- AssertionError: If the method is not an abstract method
76
-
77
- """
78
- assert_with_msg(
79
- is_abstractmethod(method),
80
- f"Expected {method} to be abstract method",
81
- )
winipedia_utils/setup.py CHANGED
@@ -9,16 +9,20 @@ This script is intended to be called once at the beginning of a project.
9
9
  from collections.abc import Callable
10
10
  from typing import Any
11
11
 
12
- from winipedia_utils.git.gitignore.config import GitIgnoreConfigFile
13
- from winipedia_utils.git.pre_commit.run_hooks import run_hooks
14
- from winipedia_utils.logging.logger import get_logger
15
- from winipedia_utils.projects.project import create_project_root
12
+ from winipedia_utils.dev.configs.gitignore import GitIgnoreConfigFile
13
+ from winipedia_utils.dev.configs.pyproject import PyprojectConfigFile
14
+ from winipedia_utils.dev.git.pre_commit.run_hooks import run_hooks
15
+ from winipedia_utils.dev.projects.project import create_project_root
16
+ from winipedia_utils.utils.logging.logger import get_logger
16
17
 
17
18
  logger = get_logger(__name__)
18
19
 
19
20
 
20
21
  SETUP_STEPS: list[Callable[..., Any]] = [
21
- GitIgnoreConfigFile, # must be first
22
+ GitIgnoreConfigFile, # must be before create_project_root
23
+ PyprojectConfigFile, # must be before create_project_root
24
+ PyprojectConfigFile.update_poetry, # must be before create_project_root
25
+ PyprojectConfigFile.update_with_dev, # must be before create_project_root
22
26
  create_project_root,
23
27
  run_hooks,
24
28
  ]
@@ -0,0 +1 @@
1
+ """__init__ module."""
@@ -0,0 +1 @@
1
+ """__init__ module."""
@@ -12,7 +12,7 @@ from typing import Any
12
12
  import polars as pl
13
13
  from polars.datatypes.classes import FloatType
14
14
 
15
- from winipedia_utils.oop.mixins.mixin import ABCLoggingMixin
15
+ from winipedia_utils.utils.oop.mixins.mixin import ABCLoggingMixin
16
16
 
17
17
 
18
18
  class CleaningDF(ABCLoggingMixin):
@@ -0,0 +1 @@
1
+ """__init__ module."""
@@ -7,14 +7,17 @@ These utilities simplify common string manipulation tasks throughout the applica
7
7
 
8
8
  import hashlib
9
9
  import textwrap
10
+ from collections.abc import Callable
10
11
  from io import StringIO
12
+ from types import ModuleType
13
+ from typing import Any
11
14
 
12
15
  from defusedxml import ElementTree as DefusedElementTree
13
16
 
14
- from winipedia_utils.concurrent.multiprocessing import (
17
+ from winipedia_utils.utils.iterating.concurrent.multiprocessing import (
15
18
  cancel_on_timeout,
16
19
  )
17
- from winipedia_utils.logging.logger import get_logger
20
+ from winipedia_utils.utils.logging.logger import get_logger
18
21
 
19
22
  logger = get_logger(__name__)
20
23
 
@@ -114,7 +117,7 @@ def split_on_uppercase(string: str) -> list[str]:
114
117
 
115
118
  """
116
119
  letters = list(string)
117
- parts = []
120
+ parts: list[str] = []
118
121
  current_part = ""
119
122
  for letter in letters:
120
123
  if letter.isupper() and current_part:
@@ -124,3 +127,33 @@ def split_on_uppercase(string: str) -> list[str]:
124
127
  current_part += letter
125
128
  parts.append(current_part)
126
129
  return parts
130
+
131
+
132
+ def make_name_from_obj(
133
+ package: ModuleType | Callable[..., Any] | type | str,
134
+ split_on: str = "_",
135
+ join_on: str = "-",
136
+ *,
137
+ capitalize: bool = True,
138
+ ) -> str:
139
+ """Make a name from a package.
140
+
141
+ takes a package and makes a name from it that is readable by humans.
142
+
143
+ Args:
144
+ package (ModuleType): The package to make a name from
145
+ split_on (str, optional): what to split the package name on. Defaults to "_".
146
+ join_on (str, optional): what to join the package name with. Defaults to "-".
147
+ capitalize (bool, optional): Whether to capitalize each part. Defaults to True.
148
+
149
+ Returns:
150
+ str: _description_
151
+ """
152
+ if not isinstance(package, str):
153
+ package_name = package.__name__.split(".")[-1]
154
+ else:
155
+ package_name = package
156
+ parts = package_name.split(split_on)
157
+ if capitalize:
158
+ parts = [part.capitalize() for part in parts]
159
+ return join_on.join(parts)
@@ -0,0 +1 @@
1
+ """__init__ module for winipedia_utils.git."""
@@ -0,0 +1 @@
1
+ """__init__ module."""
@@ -2,7 +2,7 @@
2
2
 
3
3
  import os
4
4
 
5
- from winipedia_utils.text.config import DotEnvConfigFile
5
+ from winipedia_utils.dev.configs.base.config import DotEnvConfigFile
6
6
 
7
7
 
8
8
  def get_github_repo_token() -> str:
@@ -0,0 +1 @@
1
+ """__init__ module."""
@@ -6,7 +6,7 @@ from github import Github
6
6
  from github.Auth import Token
7
7
  from github.Repository import Repository
8
8
 
9
- from winipedia_utils.logging.logger import get_logger
9
+ from winipedia_utils.utils.logging.logger import get_logger
10
10
 
11
11
  logger = get_logger(__name__)
12
12
 
@@ -12,8 +12,8 @@ from pathlib import Path
12
12
 
13
13
  import pathspec
14
14
 
15
- from winipedia_utils.git.gitignore.config import GitIgnoreConfigFile
16
- from winipedia_utils.logging.logger import get_logger
15
+ from winipedia_utils.dev.configs.gitignore import GitIgnoreConfigFile
16
+ from winipedia_utils.utils.logging.logger import get_logger
17
17
 
18
18
  logger = get_logger(__name__)
19
19
 
@@ -20,8 +20,8 @@ from typing import TYPE_CHECKING, Any, cast
20
20
 
21
21
  from tqdm import tqdm
22
22
 
23
- from winipedia_utils.iterating.iterate import get_len_with_default
24
- from winipedia_utils.logging.logger import get_logger
23
+ from winipedia_utils.utils.iterating.iterate import get_len_with_default
24
+ from winipedia_utils.utils.logging.logger import get_logger
25
25
 
26
26
  if TYPE_CHECKING:
27
27
  from multiprocessing.pool import Pool
@@ -208,10 +208,10 @@ def concurrent_loop( # noqa: PLR0913
208
208
  Returns:
209
209
  list[Any]: Results from the process_function executions
210
210
  """
211
- from winipedia_utils.concurrent.multiprocessing import ( # noqa: PLC0415 # avoid circular import
211
+ from winipedia_utils.utils.iterating.concurrent.multiprocessing import ( # noqa: PLC0415 # avoid circular import
212
212
  get_spwan_pool,
213
213
  )
214
- from winipedia_utils.concurrent.multithreading import ( # noqa: PLC0415 # avoid circular import
214
+ from winipedia_utils.utils.iterating.concurrent.multithreading import ( # noqa: PLC0415 # avoid circular import
215
215
  imap_unordered,
216
216
  )
217
217
 
@@ -15,8 +15,8 @@ from functools import wraps
15
15
  from multiprocessing.pool import Pool
16
16
  from typing import Any
17
17
 
18
- from winipedia_utils.concurrent.concurrent import concurrent_loop
19
- from winipedia_utils.logging.logger import get_logger
18
+ from winipedia_utils.utils.iterating.concurrent.concurrent import concurrent_loop
19
+ from winipedia_utils.utils.logging.logger import get_logger
20
20
 
21
21
  logger = get_logger(__name__)
22
22
 
@@ -15,7 +15,7 @@ from collections.abc import Callable, Generator, Iterable
15
15
  from concurrent.futures import Future, ThreadPoolExecutor, as_completed
16
16
  from typing import Any
17
17
 
18
- from winipedia_utils.concurrent.concurrent import concurrent_loop
18
+ from winipedia_utils.utils.iterating.concurrent.concurrent import concurrent_loop
19
19
 
20
20
 
21
21
  def get_future_results_as_completed(
@@ -8,7 +8,7 @@ defined in the config module to ensure consistent logging behavior.
8
8
  import logging
9
9
  from logging.config import dictConfig
10
10
 
11
- from winipedia_utils.logging.config import LOGGING_CONFIG
11
+ from winipedia_utils.utils.logging.config import LOGGING_CONFIG
12
12
 
13
13
  dictConfig(LOGGING_CONFIG)
14
14
 
@@ -12,11 +12,15 @@ from importlib import import_module
12
12
  from types import ModuleType
13
13
  from typing import Any
14
14
 
15
- from winipedia_utils.modules.function import is_func
15
+ from winipedia_utils.utils.modules.function import is_func
16
+ from winipedia_utils.utils.modules.inspection import get_def_line, get_obj_members
16
17
 
17
18
 
18
19
  def get_all_methods_from_cls(
19
- class_: type, *, exclude_parent_methods: bool = False
20
+ class_: type,
21
+ *,
22
+ exclude_parent_methods: bool = False,
23
+ include_annotate: bool = False,
20
24
  ) -> list[Callable[..., Any]]:
21
25
  """Get all methods from a class.
22
26
 
@@ -27,17 +31,21 @@ def get_all_methods_from_cls(
27
31
  class_: The class to extract methods from
28
32
  exclude_parent_methods: If True, only include methods defined in this class,
29
33
  excluding those inherited from parent classes
34
+ include_annotate: If False, exclude __annotate__ method
35
+ introduced in Python 3.14, defaults to False
36
+
30
37
  Returns:
31
38
  A list of callable methods from the class
32
39
 
33
40
  """
34
- from winipedia_utils.modules.module import ( # noqa: PLC0415 # avoid circular import
35
- get_def_line,
41
+ from winipedia_utils.utils.modules.module import ( # noqa: PLC0415 # avoid circular import
36
42
  get_module_of_obj,
37
43
  )
38
44
 
39
45
  methods = [
40
- (method, name) for name, method in inspect.getmembers(class_) if is_func(method)
46
+ (method, name)
47
+ for name, method in get_obj_members(class_, include_annotate=include_annotate)
48
+ if is_func(method)
41
49
  ]
42
50
 
43
51
  if exclude_parent_methods:
@@ -66,8 +74,7 @@ def get_all_cls_from_module(module: ModuleType | str) -> list[type]:
66
74
  A list of class types defined in the module
67
75
 
68
76
  """
69
- from winipedia_utils.modules.module import ( # noqa: PLC0415 # avoid circular import
70
- get_def_line,
77
+ from winipedia_utils.utils.modules.module import ( # noqa: PLC0415 # avoid circular import
71
78
  get_module_of_obj,
72
79
  )
73
80
 
@@ -104,7 +111,7 @@ def get_all_subclasses(
104
111
  A list of subclasses of the given class
105
112
 
106
113
  """
107
- from winipedia_utils.modules.package import ( # noqa: PLC0415 # avoid circular import
114
+ from winipedia_utils.utils.modules.package import ( # noqa: PLC0415 # avoid circular import
108
115
  walk_package,
109
116
  )
110
117
 
@@ -12,6 +12,8 @@ from importlib import import_module
12
12
  from types import ModuleType
13
13
  from typing import Any
14
14
 
15
+ from winipedia_utils.utils.modules.inspection import get_def_line, get_obj_members
16
+
15
17
 
16
18
  def is_func_or_method(obj: Any) -> bool:
17
19
  """Return True if *obj* is a function or method.
@@ -57,7 +59,9 @@ def is_func(obj: Any) -> bool:
57
59
  return is_func_or_method(unwrapped)
58
60
 
59
61
 
60
- def get_all_functions_from_module(module: ModuleType | str) -> list[Callable[..., Any]]:
62
+ def get_all_functions_from_module(
63
+ module: ModuleType | str, *, include_annotate: bool = False
64
+ ) -> list[Callable[..., Any]]:
61
65
  """Get all functions defined in a module.
62
66
 
63
67
  Retrieves all function objects that are defined directly in the specified module,
@@ -66,13 +70,14 @@ def get_all_functions_from_module(module: ModuleType | str) -> list[Callable[...
66
70
 
67
71
  Args:
68
72
  module: The module to extract functions from
73
+ include_annotate: If False, exclude __annotate__ method
74
+ introduced in Python 3.14, defaults to False
69
75
 
70
76
  Returns:
71
77
  A list of callable functions defined in the module
72
78
 
73
79
  """
74
- from winipedia_utils.modules.module import ( # noqa: PLC0415 # avoid circular import
75
- get_def_line,
80
+ from winipedia_utils.utils.modules.module import ( # noqa: PLC0415 # avoid circular import
76
81
  get_module_of_obj,
77
82
  )
78
83
 
@@ -80,7 +85,8 @@ def get_all_functions_from_module(module: ModuleType | str) -> list[Callable[...
80
85
  module = import_module(module)
81
86
  funcs = [
82
87
  func
83
- for _name, func in inspect.getmembers(module, is_func)
88
+ for _name, func in get_obj_members(module, include_annotate=include_annotate)
89
+ if is_func(func)
84
90
  if get_module_of_obj(func).__name__ == module.__name__
85
91
  ]
86
92
  # sort by definition order
@@ -0,0 +1,56 @@
1
+ """Inspection utilities for introspecting Python objects.
2
+
3
+ This module provides utility functions for inspecting Python objects,
4
+ including checking if an object is a function or method, and unwrapping
5
+ methods to their underlying functions.
6
+ """
7
+
8
+ import inspect
9
+ import sys
10
+ from collections.abc import Callable
11
+ from typing import Any, cast
12
+
13
+
14
+ def get_obj_members(
15
+ obj: Any, *, include_annotate: bool = False
16
+ ) -> list[tuple[str, Any]]:
17
+ """Get all members of an object."""
18
+ members = [(member, value) for member, value in inspect.getmembers(obj)]
19
+ if not include_annotate:
20
+ members = [
21
+ (member, value)
22
+ for member, value in members
23
+ if member not in ("__annotate__", "__annotate_func__")
24
+ ]
25
+ return members
26
+
27
+
28
+ def inside_frozen_bundle() -> bool:
29
+ """Return True if the code is running inside a frozen bundle."""
30
+ return getattr(sys, "frozen", False)
31
+
32
+
33
+ def get_def_line(obj: Any) -> int:
34
+ """Return the line number where a method-like object is defined."""
35
+ if isinstance(obj, property):
36
+ obj = obj.fget
37
+ unwrapped = inspect.unwrap(obj)
38
+ if hasattr(unwrapped, "__code__"):
39
+ return int(unwrapped.__code__.co_firstlineno)
40
+ # getsourcelines does not work if in a pyinstaller bundle or something
41
+ if inside_frozen_bundle():
42
+ return 0
43
+ return inspect.getsourcelines(unwrapped)[1]
44
+
45
+
46
+ def get_unwrapped_obj(obj: Any) -> Any:
47
+ """Return the unwrapped version of a method-like object."""
48
+ if isinstance(obj, property):
49
+ obj = obj.fget # get the getter function of the property
50
+ return inspect.unwrap(obj)
51
+
52
+
53
+ def get_qualname_of_obj(obj: Callable[..., Any] | type) -> str:
54
+ """Return the name of a method-like object."""
55
+ unwrapped = get_unwrapped_obj(obj)
56
+ return cast("str", unwrapped.__qualname__)