winipedia-utils 0.1.62__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 -423
  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.62.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.62.dist-info → winipedia_utils-0.2.0.dist-info}/WHEEL +1 -1
  89. {winipedia_utils-0.1.62.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.62.dist-info/RECORD +0 -100
@@ -1,49 +1,49 @@
1
- """Contains the pre-commit to run all hooks required by the winipedia_utils package.
2
-
3
- This script is meant to be run by pre-commit (https://pre-commit.com/)
4
- and should not be modified manually.
5
- """
6
-
7
- import sys
8
-
9
- from winipedia_utils.git.pre_commit import hooks
10
- from winipedia_utils.logging.ansi import GREEN, RED, RESET
11
- from winipedia_utils.logging.logger import get_logger
12
- from winipedia_utils.modules.function import get_all_functions_from_module
13
- from winipedia_utils.os.os import run_subprocess
14
-
15
- logger = get_logger(__name__)
16
-
17
-
18
- def _run_all_hooks() -> None:
19
- """Import all funcs defined in hooks.py and runs them."""
20
- hook_funcs = get_all_functions_from_module(hooks)
21
-
22
- exit_code = 0
23
- for hook_func in hook_funcs:
24
- subprocess_args = hook_func()
25
- result = run_subprocess(
26
- subprocess_args, check=False, capture_output=True, text=True
27
- )
28
- passed = result.returncode == 0
29
-
30
- log_method = logger.info
31
- passed_str = (f"{GREEN}PASSED" if passed else f"{RED}FAILED") + RESET
32
- if not passed:
33
- log_method = logger.error
34
- passed_str += f"\n{result.stdout}"
35
- exit_code = 1
36
- # make the dashes always the same lentgth by adjusting to len of hook name
37
- num_dashes = 50 - len(hook_func.__name__)
38
- log_method(
39
- "Hook %s -%s> %s",
40
- hook_func.__name__,
41
- "-" * num_dashes,
42
- passed_str,
43
- )
44
-
45
- sys.exit(exit_code)
46
-
47
-
48
- if __name__ == "__main__":
49
- _run_all_hooks()
1
+ """Contains the pre-commit to run all hooks required by the winipedia_utils package.
2
+
3
+ This script is meant to be run by pre-commit (https://pre-commit.com/)
4
+ and should not be modified manually.
5
+ """
6
+
7
+ import sys
8
+
9
+ from winipedia_utils.git.pre_commit import hooks
10
+ from winipedia_utils.logging.ansi import GREEN, RED, RESET
11
+ from winipedia_utils.logging.logger import get_logger
12
+ from winipedia_utils.modules.function import get_all_functions_from_module
13
+ from winipedia_utils.os.os import run_subprocess
14
+
15
+ logger = get_logger(__name__)
16
+
17
+
18
+ def _run_all_hooks() -> None:
19
+ """Import all funcs defined in hooks.py and runs them."""
20
+ hook_funcs = get_all_functions_from_module(hooks)
21
+
22
+ exit_code = 0
23
+ for hook_func in hook_funcs:
24
+ subprocess_args = hook_func()
25
+ result = run_subprocess(
26
+ subprocess_args, check=False, capture_output=True, text=True
27
+ )
28
+ passed = result.returncode == 0
29
+
30
+ log_method = logger.info
31
+ passed_str = (f"{GREEN}PASSED" if passed else f"{RED}FAILED") + RESET
32
+ if not passed:
33
+ log_method = logger.error
34
+ passed_str += f"\n{result.stdout}"
35
+ exit_code = 1
36
+ # make the dashes always the same lentgth by adjusting to len of hook name
37
+ num_dashes = 50 - len(hook_func.__name__)
38
+ log_method(
39
+ "Hook %s -%s> %s",
40
+ hook_func.__name__,
41
+ "-" * num_dashes,
42
+ passed_str,
43
+ )
44
+
45
+ sys.exit(exit_code)
46
+
47
+
48
+ if __name__ == "__main__":
49
+ _run_all_hooks()
@@ -1 +1 @@
1
- """__init__ module for winipedia_utils.iterating."""
1
+ """__init__ module for winipedia_utils.iterating."""
@@ -1,29 +1,29 @@
1
- """Iterating utilities for handling iterables.
2
-
3
- This module provides utility functions for working with iterables,
4
- including getting the length of an iterable with a default value.
5
- These utilities help with iterable operations and manipulations.
6
- """
7
-
8
- from collections.abc import Iterable
9
- from typing import Any
10
-
11
-
12
- def get_len_with_default(iterable: Iterable[Any], default: int | None = None) -> int:
13
- """Get the length of an iterable with a default value.
14
-
15
- Args:
16
- iterable: Iterable to get the length of
17
- default: Default value to return if the iterable is empty
18
-
19
- Returns:
20
- Length of the iterable or the default value if the iterable is empty
21
-
22
- """
23
- try:
24
- return len(iterable) # type: ignore[arg-type]
25
- except TypeError as e:
26
- if default is None:
27
- msg = "Can't get length of iterable and no default value provided"
28
- raise TypeError(msg) from e
29
- return default
1
+ """Iterating utilities for handling iterables.
2
+
3
+ This module provides utility functions for working with iterables,
4
+ including getting the length of an iterable with a default value.
5
+ These utilities help with iterable operations and manipulations.
6
+ """
7
+
8
+ from collections.abc import Iterable
9
+ from typing import Any
10
+
11
+
12
+ def get_len_with_default(iterable: Iterable[Any], default: int | None = None) -> int:
13
+ """Get the length of an iterable with a default value.
14
+
15
+ Args:
16
+ iterable: Iterable to get the length of
17
+ default: Default value to return if the iterable is empty
18
+
19
+ Returns:
20
+ Length of the iterable or the default value if the iterable is empty
21
+
22
+ """
23
+ try:
24
+ return len(iterable) # type: ignore[arg-type]
25
+ except TypeError as e:
26
+ if default is None:
27
+ msg = "Can't get length of iterable and no default value provided"
28
+ raise TypeError(msg) from e
29
+ return default
@@ -1,6 +1,6 @@
1
- """ANSI escape codes for terminal output."""
2
-
3
- RESET = "\033[0m"
4
-
5
- RED = "\033[91m"
6
- GREEN = "\033[92m"
1
+ """ANSI escape codes for terminal output."""
2
+
3
+ RESET = "\033[0m"
4
+
5
+ RED = "\033[91m"
6
+ GREEN = "\033[92m"
@@ -1,64 +1,64 @@
1
- """Logging configuration for winipedia_utils.
2
-
3
- This module provides a standardized logging configuration dictionary that can be
4
- used with Python's logging.config.dictConfig() to set up consistent logging
5
- across the application. The configuration includes formatters, handlers, and
6
- logger settings for different components.
7
- """
8
-
9
- # This dictionary can be passed directly to logging.config.dictConfig().
10
- # It sets up a single console handler that prints **all** log levels
11
- # (DEBUG, INFO, WARNING, ERROR and CRITICAL) using one consistent format.
12
-
13
- from typing import Any
14
-
15
- LOGGING_CONFIG: dict[str, Any] = {
16
- "version": 1, # Mandatory schema version for dictConfig
17
- "disable_existing_loggers": False, # Keep any loggers already created elsewhere
18
- # ---------------------------- #
19
- # Define a single formatter #
20
- # ---------------------------- #
21
- "formatters": {
22
- "standard": { # You can reference this formatter by name
23
- "format": (
24
- "%(asctime)s | " # • %(asctime)s human-readable timestamp
25
- "%(levelname)-8s | " # • %(asctime)s human-readable timestamp
26
- "%(filename)s:" # • %(filename)s source file where the call was made
27
- "%(lineno)d | " # • %(lineno)d line number in that file
28
- "%(message)s" # • %(message)s the log message itself
29
- ),
30
- "datefmt": "%Y-%m-%d %H:%M:%S", # Override default timestamp style
31
- },
32
- },
33
- # --------------------------- #
34
- # Define the console output #
35
- # --------------------------- #
36
- "handlers": {
37
- "console": {
38
- "class": "logging.StreamHandler", # Send logs to sys.stderr
39
- "level": "DEBUG", # Capture *everything* ≥ DEBUG
40
- "formatter": "standard", # Use the formatter above
41
- "stream": "ext://sys.stdout", # Emit to stdout instead of stderr
42
- },
43
- },
44
- # ------------------------------------------------------- #
45
- # Attach the handler to either the root logger or named #
46
- # loggers. Below we set up the root so every message in #
47
- # your application uses this setup automatically. #
48
- # ------------------------------------------------------- #
49
- "root": {
50
- "level": "DEBUG", # Accept all levels from DEBUG upward
51
- "handlers": ["console"], # Pipe them through the console handler
52
- },
53
- # ------------------------------------------------------- #
54
- # Optionally, tweak individual libraries if they are #
55
- # too noisy. For example, silence urllib3 INFO chatter. #
56
- # ------------------------------------------------------- #
57
- "loggers": {
58
- "urllib3": {
59
- "level": "WARNING", # Raise urllib3's threshold to WARNING
60
- "handlers": ["console"],
61
- "propagate": False, # Prevent double-logging to the root
62
- },
63
- },
64
- }
1
+ """Logging configuration for winipedia_utils.
2
+
3
+ This module provides a standardized logging configuration dictionary that can be
4
+ used with Python's logging.config.dictConfig() to set up consistent logging
5
+ across the application. The configuration includes formatters, handlers, and
6
+ logger settings for different components.
7
+ """
8
+
9
+ # This dictionary can be passed directly to logging.config.dictConfig().
10
+ # It sets up a single console handler that prints **all** log levels
11
+ # (DEBUG, INFO, WARNING, ERROR and CRITICAL) using one consistent format.
12
+
13
+ from typing import Any
14
+
15
+ LOGGING_CONFIG: dict[str, Any] = {
16
+ "version": 1, # Mandatory schema version for dictConfig
17
+ "disable_existing_loggers": False, # Keep any loggers already created elsewhere
18
+ # ---------------------------- #
19
+ # Define a single formatter #
20
+ # ---------------------------- #
21
+ "formatters": {
22
+ "standard": { # You can reference this formatter by name
23
+ "format": (
24
+ "%(asctime)s | " # • %(asctime)s human-readable timestamp
25
+ "%(levelname)-8s | " # • %(asctime)s human-readable timestamp
26
+ "%(filename)s:" # • %(filename)s source file where the call was made
27
+ "%(lineno)d | " # • %(lineno)d line number in that file
28
+ "%(message)s" # • %(message)s the log message itself
29
+ ),
30
+ "datefmt": "%Y-%m-%d %H:%M:%S", # Override default timestamp style
31
+ },
32
+ },
33
+ # --------------------------- #
34
+ # Define the console output #
35
+ # --------------------------- #
36
+ "handlers": {
37
+ "console": {
38
+ "class": "logging.StreamHandler", # Send logs to sys.stderr
39
+ "level": "DEBUG", # Capture *everything* ≥ DEBUG
40
+ "formatter": "standard", # Use the formatter above
41
+ "stream": "ext://sys.stdout", # Emit to stdout instead of stderr
42
+ },
43
+ },
44
+ # ------------------------------------------------------- #
45
+ # Attach the handler to either the root logger or named #
46
+ # loggers. Below we set up the root so every message in #
47
+ # your application uses this setup automatically. #
48
+ # ------------------------------------------------------- #
49
+ "root": {
50
+ "level": "DEBUG", # Accept all levels from DEBUG upward
51
+ "handlers": ["console"], # Pipe them through the console handler
52
+ },
53
+ # ------------------------------------------------------- #
54
+ # Optionally, tweak individual libraries if they are #
55
+ # too noisy. For example, silence urllib3 INFO chatter. #
56
+ # ------------------------------------------------------- #
57
+ "loggers": {
58
+ "urllib3": {
59
+ "level": "WARNING", # Raise urllib3's threshold to WARNING
60
+ "handlers": ["console"],
61
+ "propagate": False, # Prevent double-logging to the root
62
+ },
63
+ },
64
+ }
@@ -1,26 +1,26 @@
1
- """Logger utilities for winipedia_utils.
2
-
3
- This module provides functions for creating and configuring loggers
4
- throughout the application. It applies the standardized logging configuration
5
- defined in the config module to ensure consistent logging behavior.
6
- """
7
-
8
- import logging
9
- from logging.config import dictConfig
10
-
11
- from winipedia_utils.logging.config import LOGGING_CONFIG
12
-
13
- dictConfig(LOGGING_CONFIG)
14
-
15
-
16
- def get_logger(name: str) -> logging.Logger:
17
- """Get a logger with the given name.
18
-
19
- Args:
20
- name: The name for the logger, typically __name__ from the calling module
21
-
22
- Returns:
23
- A configured logger instance with the specified name
24
-
25
- """
26
- return logging.getLogger(name)
1
+ """Logger utilities for winipedia_utils.
2
+
3
+ This module provides functions for creating and configuring loggers
4
+ throughout the application. It applies the standardized logging configuration
5
+ defined in the config module to ensure consistent logging behavior.
6
+ """
7
+
8
+ import logging
9
+ from logging.config import dictConfig
10
+
11
+ from winipedia_utils.logging.config import LOGGING_CONFIG
12
+
13
+ dictConfig(LOGGING_CONFIG)
14
+
15
+
16
+ def get_logger(name: str) -> logging.Logger:
17
+ """Get a logger with the given name.
18
+
19
+ Args:
20
+ name: The name for the logger, typically __name__ from the calling module
21
+
22
+ Returns:
23
+ A configured logger instance with the specified name
24
+
25
+ """
26
+ return logging.getLogger(name)
@@ -1,119 +1,119 @@
1
- """Class utilities for introspection and manipulation.
2
-
3
- This module provides utility functions for working with Python classes,
4
- including extracting methods from classes and finding classes within modules.
5
- These utilities are particularly useful for reflection, testing,
6
- and dynamic code generation.
7
- """
8
-
9
- import inspect
10
- from collections.abc import Callable
11
- from importlib import import_module
12
- from types import ModuleType
13
- from typing import Any
14
-
15
- from winipedia_utils.modules.function import is_func
16
-
17
-
18
- def get_all_methods_from_cls(
19
- class_: type, *, exclude_parent_methods: bool = False
20
- ) -> list[Callable[..., Any]]:
21
- """Get all methods from a class.
22
-
23
- Retrieves all methods (functions or methods) from a class. Can optionally
24
- exclude methods inherited from parent classes.
25
-
26
- Args:
27
- class_: The class to extract methods from
28
- exclude_parent_methods: If True, only include methods defined in this class,
29
- excluding those inherited from parent classes
30
- Returns:
31
- A list of callable methods from the class
32
-
33
- """
34
- from winipedia_utils.modules.module import get_def_line, get_module_of_obj
35
-
36
- methods = [
37
- (method, name) for name, method in inspect.getmembers(class_) if is_func(method)
38
- ]
39
-
40
- if exclude_parent_methods:
41
- methods = [
42
- (method, name)
43
- for method, name in methods
44
- if get_module_of_obj(method).__name__ == class_.__module__
45
- and name in class_.__dict__
46
- ]
47
-
48
- only_methods = [method for method, _name in methods]
49
- # sort by definition order
50
- return sorted(only_methods, key=get_def_line)
51
-
52
-
53
- def get_all_cls_from_module(module: ModuleType | str) -> list[type]:
54
- """Get all classes defined in a module.
55
-
56
- Retrieves all class objects that are defined directly in the specified module,
57
- excluding imported classes.
58
-
59
- Args:
60
- module: The module to extract classes from
61
-
62
- Returns:
63
- A list of class types defined in the module
64
-
65
- """
66
- from winipedia_utils.modules.module import get_def_line, get_module_of_obj
67
-
68
- if isinstance(module, str):
69
- module = import_module(module)
70
-
71
- # necessary for bindings packages like AESGCM from cryptography._rust backend
72
- default = ModuleType("default")
73
- classes = [
74
- obj
75
- for _, obj in inspect.getmembers(module, inspect.isclass)
76
- if get_module_of_obj(obj, default).__name__ == module.__name__
77
- ]
78
- # sort by definition order
79
- return sorted(classes, key=get_def_line)
80
-
81
-
82
- def get_all_subclasses(cls: type) -> list[type]:
83
- """Get all subclasses of a class.
84
-
85
- Retrieves all classes that are subclasses of the specified class.
86
- Also returns subclasses of subclasses (recursive).
87
-
88
- Args:
89
- cls: The class to find subclasses of
90
-
91
- Returns:
92
- A list of subclasses of the given class
93
-
94
- """
95
- subclasses_set = set(cls.__subclasses__())
96
- for subclass in cls.__subclasses__():
97
- subclasses_set.update(get_all_subclasses(subclass))
98
- return list(subclasses_set)
99
-
100
-
101
- def get_all_nonabstract_subclasses(cls: type) -> list[type]:
102
- """Get all non-abstract subclasses of a class.
103
-
104
- Retrieves all classes that are subclasses of the specified class,
105
- excluding abstract classes. Also returns subclasses of subclasses
106
- (recursive).
107
-
108
- Args:
109
- cls: The class to find subclasses of
110
-
111
- Returns:
112
- A list of non-abstract subclasses of the given class
113
-
114
- """
115
- return [
116
- subclass
117
- for subclass in get_all_subclasses(cls)
118
- if not inspect.isabstract(subclass)
119
- ]
1
+ """Class utilities for introspection and manipulation.
2
+
3
+ This module provides utility functions for working with Python classes,
4
+ including extracting methods from classes and finding classes within modules.
5
+ These utilities are particularly useful for reflection, testing,
6
+ and dynamic code generation.
7
+ """
8
+
9
+ import inspect
10
+ from collections.abc import Callable
11
+ from importlib import import_module
12
+ from types import ModuleType
13
+ from typing import Any
14
+
15
+ from winipedia_utils.modules.function import is_func
16
+
17
+
18
+ def get_all_methods_from_cls(
19
+ class_: type, *, exclude_parent_methods: bool = False
20
+ ) -> list[Callable[..., Any]]:
21
+ """Get all methods from a class.
22
+
23
+ Retrieves all methods (functions or methods) from a class. Can optionally
24
+ exclude methods inherited from parent classes.
25
+
26
+ Args:
27
+ class_: The class to extract methods from
28
+ exclude_parent_methods: If True, only include methods defined in this class,
29
+ excluding those inherited from parent classes
30
+ Returns:
31
+ A list of callable methods from the class
32
+
33
+ """
34
+ from winipedia_utils.modules.module import get_def_line, get_module_of_obj
35
+
36
+ methods = [
37
+ (method, name) for name, method in inspect.getmembers(class_) if is_func(method)
38
+ ]
39
+
40
+ if exclude_parent_methods:
41
+ methods = [
42
+ (method, name)
43
+ for method, name in methods
44
+ if get_module_of_obj(method).__name__ == class_.__module__
45
+ and name in class_.__dict__
46
+ ]
47
+
48
+ only_methods = [method for method, _name in methods]
49
+ # sort by definition order
50
+ return sorted(only_methods, key=get_def_line)
51
+
52
+
53
+ def get_all_cls_from_module(module: ModuleType | str) -> list[type]:
54
+ """Get all classes defined in a module.
55
+
56
+ Retrieves all class objects that are defined directly in the specified module,
57
+ excluding imported classes.
58
+
59
+ Args:
60
+ module: The module to extract classes from
61
+
62
+ Returns:
63
+ A list of class types defined in the module
64
+
65
+ """
66
+ from winipedia_utils.modules.module import get_def_line, get_module_of_obj
67
+
68
+ if isinstance(module, str):
69
+ module = import_module(module)
70
+
71
+ # necessary for bindings packages like AESGCM from cryptography._rust backend
72
+ default = ModuleType("default")
73
+ classes = [
74
+ obj
75
+ for _, obj in inspect.getmembers(module, inspect.isclass)
76
+ if get_module_of_obj(obj, default).__name__ == module.__name__
77
+ ]
78
+ # sort by definition order
79
+ return sorted(classes, key=get_def_line)
80
+
81
+
82
+ def get_all_subclasses(cls: type) -> list[type]:
83
+ """Get all subclasses of a class.
84
+
85
+ Retrieves all classes that are subclasses of the specified class.
86
+ Also returns subclasses of subclasses (recursive).
87
+
88
+ Args:
89
+ cls: The class to find subclasses of
90
+
91
+ Returns:
92
+ A list of subclasses of the given class
93
+
94
+ """
95
+ subclasses_set = set(cls.__subclasses__())
96
+ for subclass in cls.__subclasses__():
97
+ subclasses_set.update(get_all_subclasses(subclass))
98
+ return list(subclasses_set)
99
+
100
+
101
+ def get_all_nonabstract_subclasses(cls: type) -> list[type]:
102
+ """Get all non-abstract subclasses of a class.
103
+
104
+ Retrieves all classes that are subclasses of the specified class,
105
+ excluding abstract classes. Also returns subclasses of subclasses
106
+ (recursive).
107
+
108
+ Args:
109
+ cls: The class to find subclasses of
110
+
111
+ Returns:
112
+ A list of non-abstract subclasses of the given class
113
+
114
+ """
115
+ return [
116
+ subclass
117
+ for subclass in get_all_subclasses(cls)
118
+ if not inspect.isabstract(subclass)
119
+ ]