wexample-wex-addon-dev-python 10.1.1__tar.gz → 10.2.0__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.
- {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-10.2.0}/PKG-INFO +10 -10
- {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-10.2.0}/README.md +5 -5
- {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-10.2.0}/pyproject.toml +5 -5
- {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-10.2.0}/src/wexample_wex_addon_dev_python/python_addon_manager.py +12 -1
- {wexample_wex_addon_dev_python-10.1.1/src/wexample_wex_addon_dev_python/services → wexample_wex_addon_dev_python-10.2.0/src/wexample_wex_addon_dev_python/selection}/__init__.py +0 -0
- wexample_wex_addon_dev_python-10.2.0/src/wexample_wex_addon_dev_python/selection/abstract_python_code_selection.py +45 -0
- wexample_wex_addon_dev_python-10.2.0/src/wexample_wex_addon_dev_python/selection/python_code_performance_selection.py +172 -0
- {wexample_wex_addon_dev_python-10.1.1/tests/helpers → wexample_wex_addon_dev_python-10.2.0/src/wexample_wex_addon_dev_python/workdir/mixin}/__init__.py +0 -0
- {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-10.2.0}/src/wexample_wex_addon_dev_python/workdir/python_package_workdir.py +38 -51
- {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-10.2.0}/src/wexample_wex_addon_dev_python/workdir/python_workdir.py +6 -10
- wexample_wex_addon_dev_python-10.2.0/tests/helpers/__init__.py +0 -0
- {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-10.2.0}/src/wexample_wex_addon_dev_python/__init__.py +0 -0
- {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-10.2.0}/src/wexample_wex_addon_dev_python/__pycache__/__init__.py +0 -0
- {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-10.2.0}/src/wexample_wex_addon_dev_python/commands/__init__.py +0 -0
- {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-10.2.0}/src/wexample_wex_addon_dev_python/commands/code/__init__.py +0 -0
- {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-10.2.0}/src/wexample_wex_addon_dev_python/commands/code/check/__init__.py +0 -0
- {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-10.2.0}/src/wexample_wex_addon_dev_python/commands/code/check/mypy.py +0 -0
- {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-10.2.0}/src/wexample_wex_addon_dev_python/commands/code/check/pylint.py +0 -0
- {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-10.2.0}/src/wexample_wex_addon_dev_python/commands/code/check/pyright.py +0 -0
- {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-10.2.0}/src/wexample_wex_addon_dev_python/commands/code/check.py +0 -0
- {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-10.2.0}/src/wexample_wex_addon_dev_python/commands/code/format/__init__.py +0 -0
- {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-10.2.0}/src/wexample_wex_addon_dev_python/commands/code/format/black.py +0 -0
- {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-10.2.0}/src/wexample_wex_addon_dev_python/commands/code/format/isort.py +0 -0
- {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-10.2.0}/src/wexample_wex_addon_dev_python/commands/code/format.py +0 -0
- {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-10.2.0}/src/wexample_wex_addon_dev_python/commands/examples/__init__.py +0 -0
- {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-10.2.0}/src/wexample_wex_addon_dev_python/commands/examples/utils/__init__.py +0 -0
- {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-10.2.0}/src/wexample_wex_addon_dev_python/commands/examples/utils/some_example_type.py +0 -0
- {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-10.2.0}/src/wexample_wex_addon_dev_python/commands/examples/validate.py +0 -0
- {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-10.2.0}/src/wexample_wex_addon_dev_python/commands/release/__init__.py +0 -0
- {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-10.2.0}/src/wexample_wex_addon_dev_python/common/__init__.py +0 -0
- {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-10.2.0}/src/wexample_wex_addon_dev_python/common/pypi_registry_gateway.py +0 -0
- {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-10.2.0}/src/wexample_wex_addon_dev_python/config_value/__init__.py +0 -0
- {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-10.2.0}/src/wexample_wex_addon_dev_python/config_value/__pycache__/__init__.py +0 -0
- {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-10.2.0}/src/wexample_wex_addon_dev_python/config_value/python_package_readme_config_value.py +0 -0
- {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-10.2.0}/src/wexample_wex_addon_dev_python/const/__init__.py +0 -0
- {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-10.2.0}/src/wexample_wex_addon_dev_python/const/__pycache__/__init__.py +0 -0
- {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-10.2.0}/src/wexample_wex_addon_dev_python/const/package.py +0 -0
- {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-10.2.0}/src/wexample_wex_addon_dev_python/const/python.py +0 -0
- {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-10.2.0}/src/wexample_wex_addon_dev_python/const/tags.py +0 -0
- {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-10.2.0}/src/wexample_wex_addon_dev_python/file/__init__.py +0 -0
- {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-10.2.0}/src/wexample_wex_addon_dev_python/file/__pycache__/__init__.py +0 -0
- {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-10.2.0}/src/wexample_wex_addon_dev_python/file/python_app_iml_file.py +0 -0
- {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-10.2.0}/src/wexample_wex_addon_dev_python/file/python_pyproject_toml_file.py +0 -0
- {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-10.2.0}/src/wexample_wex_addon_dev_python/helpers/__init__.py +0 -0
- {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-10.2.0}/src/wexample_wex_addon_dev_python/helpers/pdm.py +0 -0
- {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-10.2.0}/src/wexample_wex_addon_dev_python/middleware/__init__.py +0 -0
- {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-10.2.0}/src/wexample_wex_addon_dev_python/middleware/__pycache__/__init__.py +0 -0
- {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-10.2.0}/src/wexample_wex_addon_dev_python/middleware/each_python_file_middleware.py +0 -0
- {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-10.2.0}/src/wexample_wex_addon_dev_python/py.typed +0 -0
- {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-10.2.0}/src/wexample_wex_addon_dev_python/resources/.wex.yml +0 -0
- {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-10.2.0}/src/wexample_wex_addon_dev_python/resources/docker/Dockerfile.python-profiling +0 -0
- {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-10.2.0}/src/wexample_wex_addon_dev_python/resources/package_publish_gitlab.yml +0 -0
- {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-10.2.0}/src/wexample_wex_addon_dev_python/resources/readme_templates/tests.md.j2 +0 -0
- {wexample_wex_addon_dev_python-10.1.1/src/wexample_wex_addon_dev_python/services/python → wexample_wex_addon_dev_python-10.2.0/src/wexample_wex_addon_dev_python/services}/__init__.py +0 -0
- {wexample_wex_addon_dev_python-10.1.1/src/wexample_wex_addon_dev_python/services/python/commands → wexample_wex_addon_dev_python-10.2.0/src/wexample_wex_addon_dev_python/services/python}/__init__.py +0 -0
- {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-10.2.0}/src/wexample_wex_addon_dev_python/services/python/app_service.py +0 -0
- {wexample_wex_addon_dev_python-10.1.1/src/wexample_wex_addon_dev_python/services/python/commands/service → wexample_wex_addon_dev_python-10.2.0/src/wexample_wex_addon_dev_python/services/python/commands}/__init__.py +0 -0
- {wexample_wex_addon_dev_python-10.1.1/src/wexample_wex_addon_dev_python/services/python/samples → wexample_wex_addon_dev_python-10.2.0/src/wexample_wex_addon_dev_python/services/python/commands/service}/__init__.py +0 -0
- {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-10.2.0}/src/wexample_wex_addon_dev_python/services/python/commands/service/install.py +0 -0
- {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-10.2.0}/src/wexample_wex_addon_dev_python/services/python/commands/service/setup.py +0 -0
- {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-10.2.0}/src/wexample_wex_addon_dev_python/services/python/docker/.wex.yml +0 -0
- {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-10.2.0}/src/wexample_wex_addon_dev_python/services/python/docker/docker-compose.yml +0 -0
- {wexample_wex_addon_dev_python-10.1.1/src/wexample_wex_addon_dev_python/services/python/samples/docker → wexample_wex_addon_dev_python-10.2.0/src/wexample_wex_addon_dev_python/services/python/samples}/__init__.py +0 -0
- {wexample_wex_addon_dev_python-10.1.1/src/wexample_wex_addon_dev_python/services/python/samples/docker/images → wexample_wex_addon_dev_python-10.2.0/src/wexample_wex_addon_dev_python/services/python/samples/docker}/__init__.py +0 -0
- {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-10.2.0}/src/wexample_wex_addon_dev_python/services/python/samples/docker/docker-compose.yml +0 -0
- {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-10.2.0}/src/wexample_wex_addon_dev_python/services/python/samples/docker/entrypoint.sh +0 -0
- {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-10.2.0}/src/wexample_wex_addon_dev_python/services/python/samples/docker/images/Dockerfile.base +0 -0
- {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-10.2.0}/src/wexample_wex_addon_dev_python/services/python/samples/docker/images/Dockerfile.develop +0 -0
- {wexample_wex_addon_dev_python-10.1.1/src/wexample_wex_addon_dev_python/workdir → wexample_wex_addon_dev_python-10.2.0/src/wexample_wex_addon_dev_python/services/python/samples/docker/images}/__init__.py +0 -0
- {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-10.2.0}/src/wexample_wex_addon_dev_python/services/python/service.yml +0 -0
- {wexample_wex_addon_dev_python-10.1.1/src/wexample_wex_addon_dev_python/workdir/__pycache__ → wexample_wex_addon_dev_python-10.2.0/src/wexample_wex_addon_dev_python/workdir}/__init__.py +0 -0
- {wexample_wex_addon_dev_python-10.1.1/src/wexample_wex_addon_dev_python/workdir/mixin → wexample_wex_addon_dev_python-10.2.0/src/wexample_wex_addon_dev_python/workdir/__pycache__}/__init__.py +0 -0
- {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-10.2.0}/src/wexample_wex_addon_dev_python/workdir/mixin/with_profiling_python_workdir_mixin.py +0 -0
- {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-10.2.0}/src/wexample_wex_addon_dev_python/workdir/python_packages_suite_workdir.py +0 -0
- {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-10.2.0}/tests/helpers/test_pdm.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: wexample-wex-addon-dev-python
|
|
3
|
-
Version: 10.
|
|
3
|
+
Version: 10.2.0
|
|
4
4
|
Summary: Python dev addon for wex
|
|
5
5
|
Author-Email: weeger <contact@wexample.com>
|
|
6
6
|
License: MIT
|
|
@@ -15,10 +15,10 @@ Requires-Dist: griffe>=2.0.2
|
|
|
15
15
|
Requires-Dist: networkx
|
|
16
16
|
Requires-Dist: pylint
|
|
17
17
|
Requires-Dist: pyright
|
|
18
|
-
Requires-Dist: wexample-api>=6.
|
|
19
|
-
Requires-Dist: wexample-filestate-python>=
|
|
20
|
-
Requires-Dist: wexample-wex-addon-ai>=
|
|
21
|
-
Requires-Dist: wexample-wex-addon-app>=25.
|
|
18
|
+
Requires-Dist: wexample-api>=6.5.0
|
|
19
|
+
Requires-Dist: wexample-filestate-python>=8.0.0
|
|
20
|
+
Requires-Dist: wexample-wex-addon-ai>=11.0.0
|
|
21
|
+
Requires-Dist: wexample-wex-addon-app>=25.3.0
|
|
22
22
|
Provides-Extra: dev
|
|
23
23
|
Requires-Dist: pytest; extra == "dev"
|
|
24
24
|
Requires-Dist: pytest-cov; extra == "dev"
|
|
@@ -26,7 +26,7 @@ Description-Content-Type: text/markdown
|
|
|
26
26
|
|
|
27
27
|
# wex_addon_dev_python
|
|
28
28
|
|
|
29
|
-
Version: 10.
|
|
29
|
+
Version: 10.2.0
|
|
30
30
|
|
|
31
31
|
Python dev addon for wex
|
|
32
32
|
|
|
@@ -112,10 +112,10 @@ Visit the [Wexample Suite documentation](https://docs.wexample.com) for the comp
|
|
|
112
112
|
- networkx:
|
|
113
113
|
- pylint:
|
|
114
114
|
- pyright:
|
|
115
|
-
- wexample-api: >=6.
|
|
116
|
-
- wexample-filestate-python: >=
|
|
117
|
-
- wexample-wex-addon-ai: >=
|
|
118
|
-
- wexample-wex-addon-app: >=25.
|
|
115
|
+
- wexample-api: >=6.5.0
|
|
116
|
+
- wexample-filestate-python: >=8.0.0
|
|
117
|
+
- wexample-wex-addon-ai: >=11.0.0
|
|
118
|
+
- wexample-wex-addon-app: >=25.3.0
|
|
119
119
|
|
|
120
120
|
## Versioning & Compatibility Policy
|
|
121
121
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# wex_addon_dev_python
|
|
2
2
|
|
|
3
|
-
Version: 10.
|
|
3
|
+
Version: 10.2.0
|
|
4
4
|
|
|
5
5
|
Python dev addon for wex
|
|
6
6
|
|
|
@@ -86,10 +86,10 @@ Visit the [Wexample Suite documentation](https://docs.wexample.com) for the comp
|
|
|
86
86
|
- networkx:
|
|
87
87
|
- pylint:
|
|
88
88
|
- pyright:
|
|
89
|
-
- wexample-api: >=6.
|
|
90
|
-
- wexample-filestate-python: >=
|
|
91
|
-
- wexample-wex-addon-ai: >=
|
|
92
|
-
- wexample-wex-addon-app: >=25.
|
|
89
|
+
- wexample-api: >=6.5.0
|
|
90
|
+
- wexample-filestate-python: >=8.0.0
|
|
91
|
+
- wexample-wex-addon-ai: >=11.0.0
|
|
92
|
+
- wexample-wex-addon-app: >=25.3.0
|
|
93
93
|
|
|
94
94
|
## Versioning & Compatibility Policy
|
|
95
95
|
|
{wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-10.2.0}/pyproject.toml
RENAMED
|
@@ -6,7 +6,7 @@ build-backend = "pdm.backend"
|
|
|
6
6
|
|
|
7
7
|
[project]
|
|
8
8
|
name = "wexample-wex-addon-dev-python"
|
|
9
|
-
version = "10.
|
|
9
|
+
version = "10.2.0"
|
|
10
10
|
description = "Python dev addon for wex"
|
|
11
11
|
authors = [
|
|
12
12
|
{ name = "weeger", email = "contact@wexample.com" },
|
|
@@ -24,10 +24,10 @@ dependencies = [
|
|
|
24
24
|
"networkx",
|
|
25
25
|
"pylint",
|
|
26
26
|
"pyright",
|
|
27
|
-
"wexample-api>=6.
|
|
28
|
-
"wexample-filestate-python>=
|
|
29
|
-
"wexample-wex-addon-ai>=
|
|
30
|
-
"wexample-wex-addon-app>=25.
|
|
27
|
+
"wexample-api>=6.5.0",
|
|
28
|
+
"wexample-filestate-python>=8.0.0",
|
|
29
|
+
"wexample-wex-addon-ai>=11.0.0",
|
|
30
|
+
"wexample-wex-addon-app>=25.3.0",
|
|
31
31
|
]
|
|
32
32
|
|
|
33
33
|
[project.readme]
|
|
@@ -2,13 +2,17 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
from typing import TYPE_CHECKING
|
|
4
4
|
|
|
5
|
+
from wexample_wex_addon_ai.selection.selection_contributing_addon_mixin import (
|
|
6
|
+
SelectionContributingAddonMixin,
|
|
7
|
+
)
|
|
5
8
|
from wexample_wex_core.common.abstract_addon_manager import AbstractAddonManager
|
|
6
9
|
|
|
7
10
|
if TYPE_CHECKING:
|
|
8
11
|
from wexample_cli.middleware.abstract_middleware import AbstractMiddleware
|
|
12
|
+
from wexample_wex_addon_ai.selection.abstract_selection import AbstractSelection
|
|
9
13
|
|
|
10
14
|
|
|
11
|
-
class PythonAddonManager(AbstractAddonManager):
|
|
15
|
+
class PythonAddonManager(SelectionContributingAddonMixin, AbstractAddonManager):
|
|
12
16
|
def get_local_configurable_keys(self) -> list[dict]:
|
|
13
17
|
from wexample_wex_addon_dev_python.helpers.pdm import (
|
|
14
18
|
apply_pdm_bin_dir,
|
|
@@ -32,3 +36,10 @@ class PythonAddonManager(AbstractAddonManager):
|
|
|
32
36
|
return [
|
|
33
37
|
EachPythonFileMiddleware,
|
|
34
38
|
]
|
|
39
|
+
|
|
40
|
+
def get_selection_classes(self) -> list[type[AbstractSelection]]:
|
|
41
|
+
from wexample_wex_addon_dev_python.selection.python_code_performance_selection import (
|
|
42
|
+
PythonCodePerformanceSelection,
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
return [PythonCodePerformanceSelection]
|
|
File without changes
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import ClassVar
|
|
4
|
+
|
|
5
|
+
from wexample_helpers.decorator.base_class import base_class
|
|
6
|
+
from wexample_wex_addon_ai.selection.abstract_code_from_directory_selection import (
|
|
7
|
+
AbstractCodeFromDirectorySelection,
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@base_class
|
|
12
|
+
class AbstractPythonCodeSelection(AbstractCodeFromDirectorySelection):
|
|
13
|
+
"""Shared base for every Python-source Selection (perf, tests, …).
|
|
14
|
+
|
|
15
|
+
Encapsulates the criteria that are constant across every Python use case in
|
|
16
|
+
this codebase:
|
|
17
|
+
- `.py` files only.
|
|
18
|
+
- Skip `__init__.py` regardless of size — re-export modules carry no logic
|
|
19
|
+
for any agent we're building today (perf optimization, test writing,
|
|
20
|
+
docstring extraction would all start by looking at real modules).
|
|
21
|
+
- Skip Python ecosystem non-source dirs: `__pycache__`, `.venv/`,
|
|
22
|
+
`.pdm-build/`, plus the `/tests/`/`/build/`/`/dist/` conventions.
|
|
23
|
+
- 50-byte floor: drops empty stubs (chosen empirically in the shell sweep,
|
|
24
|
+
kept verbatim until we have a reason to change it).
|
|
25
|
+
|
|
26
|
+
Concrete subclasses just pick a `SELECTION_NAME` and, if needed, extend
|
|
27
|
+
`get_excluded_path_fragments()` / `get_excluded_file_names()` with their
|
|
28
|
+
use-case specifics via `super() + (…)`.
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
EXTENSIONS: ClassVar[tuple[str, ...]] = (".py",)
|
|
32
|
+
MIN_SIZE_BYTES: ClassVar[int] = 50
|
|
33
|
+
|
|
34
|
+
def get_excluded_file_names(self) -> tuple[str, ...]:
|
|
35
|
+
return super().get_excluded_file_names() + ("__init__.py",)
|
|
36
|
+
|
|
37
|
+
def get_excluded_path_fragments(self) -> tuple[str, ...]:
|
|
38
|
+
return super().get_excluded_path_fragments() + (
|
|
39
|
+
"__pycache__",
|
|
40
|
+
"/tests/",
|
|
41
|
+
"/build/",
|
|
42
|
+
"/dist/",
|
|
43
|
+
"/.venv/",
|
|
44
|
+
"/.pdm-build/",
|
|
45
|
+
)
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING, ClassVar
|
|
4
|
+
|
|
5
|
+
from wexample_helpers.decorator.base_class import base_class
|
|
6
|
+
|
|
7
|
+
from wexample_wex_addon_dev_python.selection.abstract_python_code_selection import (
|
|
8
|
+
AbstractPythonCodeSelection,
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
if TYPE_CHECKING:
|
|
12
|
+
from pathlib import Path
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@base_class
|
|
16
|
+
class PythonCodePerformanceSelection(AbstractPythonCodeSelection):
|
|
17
|
+
"""Python source files candidate for the performance sweep.
|
|
18
|
+
|
|
19
|
+
Inherits every Python-side filter from `AbstractPythonCodeSelection` —
|
|
20
|
+
nothing perf-specific to declare today beyond the name. If a future need
|
|
21
|
+
emerges (e.g. include `.pyx` Cython modules, exclude a perf-noisy
|
|
22
|
+
`vendor/`), extend the inherited methods via `super() + (…)`.
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
SELECTION_NAME: ClassVar[str] = "python-performance"
|
|
26
|
+
|
|
27
|
+
def get_required_path_fragments(self) -> tuple[str, ...]:
|
|
28
|
+
"""Only library code under `/src/` — the modern Python layout for any
|
|
29
|
+
package that uses PEP 517. Drops package-root scripts, `examples/`,
|
|
30
|
+
`benchmarks/`, `.wex/python/app_manager/*` (wex configuration code, not
|
|
31
|
+
target of optimization), and anything else outside the package's published
|
|
32
|
+
surface.
|
|
33
|
+
|
|
34
|
+
Symmetric with the exclusion list — defined here rather than in
|
|
35
|
+
`AbstractPythonCodeSelection` because the `/src/` requirement is opinionated
|
|
36
|
+
for the perf use case. A test-candidate Selection might want a different
|
|
37
|
+
positive scope (e.g. include `conftest.py` siblings), so we keep this knob
|
|
38
|
+
at the concrete level.
|
|
39
|
+
"""
|
|
40
|
+
return super().get_required_path_fragments() + ("/src/",)
|
|
41
|
+
|
|
42
|
+
def is_candidate(self, item: Path) -> bool:
|
|
43
|
+
"""Drop modules that have no executable code for the perf agent to optimize.
|
|
44
|
+
|
|
45
|
+
Proxy: "module contains at least one NON-TRIVIAL `FunctionDef` /
|
|
46
|
+
`AsyncFunctionDef` somewhere in its AST". A trivial function is one
|
|
47
|
+
whose body is just a stub (`pass`, `...`, docstring only, `raise
|
|
48
|
+
NotImplementedError`, or `super().__init__()` for `__init__`), or any
|
|
49
|
+
function decorated with `@abstractmethod`. See `_is_trivial_function`
|
|
50
|
+
for the exact rules.
|
|
51
|
+
|
|
52
|
+
Catches:
|
|
53
|
+
- Re-export modules (only `from X import Y`).
|
|
54
|
+
- Pure constant / type-alias modules.
|
|
55
|
+
- Empty subclasses (`class Foo(Bar): pass`).
|
|
56
|
+
- Dataclasses without methods, plain Enums, exception classes.
|
|
57
|
+
- Abstract base classes (every method `@abstractmethod` or `raise
|
|
58
|
+
NotImplementedError`).
|
|
59
|
+
- Classes whose only method is `__init__` that just calls `super()`.
|
|
60
|
+
|
|
61
|
+
Cost: ~5ms per file (Python's C `ast.parse`). On the ~1200 files of the
|
|
62
|
+
current sweep that's a few seconds total — orders of magnitude cheaper
|
|
63
|
+
than one LLM call against any single trivial file, and saves N of them.
|
|
64
|
+
|
|
65
|
+
Files we can't decode or parse (UnicodeDecodeError, SyntaxError) are
|
|
66
|
+
treated as non-candidates — perf optimization on unreadable / broken
|
|
67
|
+
files isn't what this sweep is for, the operator fixes those first.
|
|
68
|
+
Other I/O errors (FileNotFoundError, PermissionError) propagate.
|
|
69
|
+
"""
|
|
70
|
+
import ast
|
|
71
|
+
|
|
72
|
+
if not super().is_candidate(item):
|
|
73
|
+
return False
|
|
74
|
+
try:
|
|
75
|
+
source = item.read_text(encoding="utf-8")
|
|
76
|
+
except UnicodeDecodeError:
|
|
77
|
+
return False
|
|
78
|
+
try:
|
|
79
|
+
tree = ast.parse(source)
|
|
80
|
+
except SyntaxError:
|
|
81
|
+
return False
|
|
82
|
+
return any(
|
|
83
|
+
isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef))
|
|
84
|
+
and not self._is_trivial_function(node)
|
|
85
|
+
for node in ast.walk(tree)
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
def _is_trivial_function(self, node) -> bool:
|
|
89
|
+
"""True when `node`'s body has no logic worth optimizing.
|
|
90
|
+
|
|
91
|
+
Recognized trivial bodies (leading docstring stripped first):
|
|
92
|
+
- empty (just a docstring and nothing else).
|
|
93
|
+
- `pass`.
|
|
94
|
+
- `...` (Ellipsis statement — modern stub idiom).
|
|
95
|
+
- `raise NotImplementedError` or `raise NotImplementedError(...)`.
|
|
96
|
+
- `super().__init__(...)` only, when the function IS `__init__`.
|
|
97
|
+
|
|
98
|
+
Plus: any decorator named `abstractmethod` (bare or qualified like
|
|
99
|
+
`abc.abstractmethod`) → trivial regardless of body. Abstract definitions
|
|
100
|
+
are stubs by contract; the concrete subclass is where the optimizable
|
|
101
|
+
code lives.
|
|
102
|
+
|
|
103
|
+
Doesn't recurse into nested functions — `ast.walk` in `is_candidate`
|
|
104
|
+
already visits every descendant function independently. Keeps each
|
|
105
|
+
check decoupled from its container.
|
|
106
|
+
"""
|
|
107
|
+
import ast
|
|
108
|
+
|
|
109
|
+
for deco in node.decorator_list:
|
|
110
|
+
deco_name = (
|
|
111
|
+
deco.id
|
|
112
|
+
if isinstance(deco, ast.Name)
|
|
113
|
+
else deco.attr
|
|
114
|
+
if isinstance(deco, ast.Attribute)
|
|
115
|
+
else None
|
|
116
|
+
)
|
|
117
|
+
if deco_name == "abstractmethod":
|
|
118
|
+
return True
|
|
119
|
+
|
|
120
|
+
body = list(node.body)
|
|
121
|
+
if (
|
|
122
|
+
body
|
|
123
|
+
and isinstance(body[0], ast.Expr)
|
|
124
|
+
and isinstance(body[0].value, ast.Constant)
|
|
125
|
+
and isinstance(body[0].value.value, str)
|
|
126
|
+
):
|
|
127
|
+
body = body[1:]
|
|
128
|
+
|
|
129
|
+
if not body:
|
|
130
|
+
return True
|
|
131
|
+
if len(body) != 1:
|
|
132
|
+
return False
|
|
133
|
+
|
|
134
|
+
stmt = body[0]
|
|
135
|
+
|
|
136
|
+
if isinstance(stmt, ast.Pass):
|
|
137
|
+
return True
|
|
138
|
+
|
|
139
|
+
if (
|
|
140
|
+
isinstance(stmt, ast.Expr)
|
|
141
|
+
and isinstance(stmt.value, ast.Constant)
|
|
142
|
+
and stmt.value.value is Ellipsis
|
|
143
|
+
):
|
|
144
|
+
return True
|
|
145
|
+
|
|
146
|
+
if isinstance(stmt, ast.Raise) and stmt.exc is not None:
|
|
147
|
+
exc = stmt.exc
|
|
148
|
+
if isinstance(exc, ast.Name) and exc.id == "NotImplementedError":
|
|
149
|
+
return True
|
|
150
|
+
if (
|
|
151
|
+
isinstance(exc, ast.Call)
|
|
152
|
+
and isinstance(exc.func, ast.Name)
|
|
153
|
+
and exc.func.id == "NotImplementedError"
|
|
154
|
+
):
|
|
155
|
+
return True
|
|
156
|
+
|
|
157
|
+
if node.name == "__init__" and isinstance(stmt, ast.Expr):
|
|
158
|
+
call = stmt.value
|
|
159
|
+
if (
|
|
160
|
+
isinstance(call, ast.Call)
|
|
161
|
+
and isinstance(call.func, ast.Attribute)
|
|
162
|
+
and call.func.attr == "__init__"
|
|
163
|
+
):
|
|
164
|
+
base = call.func.value
|
|
165
|
+
if (
|
|
166
|
+
isinstance(base, ast.Call)
|
|
167
|
+
and isinstance(base.func, ast.Name)
|
|
168
|
+
and base.func.id == "super"
|
|
169
|
+
):
|
|
170
|
+
return True
|
|
171
|
+
|
|
172
|
+
return False
|
|
File without changes
|
|
@@ -49,7 +49,6 @@ class PythonPackageWorkdir(PythonWorkdir):
|
|
|
49
49
|
)
|
|
50
50
|
|
|
51
51
|
def prepare_value(self, raw_value: DictConfig | None = None) -> DictConfig:
|
|
52
|
-
from wexample_helpers.helpers.array import array_dict_get_by
|
|
53
52
|
from wexample_helpers.helpers.file import file_read
|
|
54
53
|
from wexample_helpers.helpers.module import module_get_path
|
|
55
54
|
|
|
@@ -102,56 +101,44 @@ class PythonPackageWorkdir(PythonWorkdir):
|
|
|
102
101
|
},
|
|
103
102
|
)
|
|
104
103
|
|
|
105
|
-
#
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
],
|
|
115
|
-
"
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
"
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
"
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
"
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
)
|
|
144
|
-
if not isinstance(should_contain_lines, list):
|
|
145
|
-
raise ValueError("'should_contain_lines' must be a list")
|
|
146
|
-
|
|
147
|
-
for category, rules in generic_gitignore_rules.items():
|
|
148
|
-
category_header = f"# {category}"
|
|
149
|
-
if category_header not in should_contain_lines:
|
|
150
|
-
should_contain_lines.append(category_header)
|
|
151
|
-
|
|
152
|
-
for rule in rules:
|
|
153
|
-
if rule not in should_contain_lines:
|
|
154
|
-
should_contain_lines.append(rule)
|
|
104
|
+
# Sectioned Python-package gitignore rules. The rectifier (when it
|
|
105
|
+
# runs on globless files) preserves section headers and sorts
|
|
106
|
+
# entries within each section; here we glob-heavy patterns make most
|
|
107
|
+
# of these no-ops on the rectifier side, but the lines themselves
|
|
108
|
+
# are still ensured by `should_contain_lines`.
|
|
109
|
+
for section, rules in {
|
|
110
|
+
"Python artifacts": [
|
|
111
|
+
"*.egg-info",
|
|
112
|
+
"__pycache__/",
|
|
113
|
+
"*.py[cod]",
|
|
114
|
+
"*.pyo",
|
|
115
|
+
],
|
|
116
|
+
"Build directories": [
|
|
117
|
+
"/build/",
|
|
118
|
+
"/dist/",
|
|
119
|
+
"/pip-wheel-metadata/",
|
|
120
|
+
"/.pdm-build/",
|
|
121
|
+
],
|
|
122
|
+
"Virtual environments": [
|
|
123
|
+
".env",
|
|
124
|
+
".venv",
|
|
125
|
+
"venv/",
|
|
126
|
+
],
|
|
127
|
+
"Test and coverage artifacts": [
|
|
128
|
+
".tox/",
|
|
129
|
+
".mypy_cache/",
|
|
130
|
+
"pytest_cache/",
|
|
131
|
+
".coverage",
|
|
132
|
+
"htmlcov/",
|
|
133
|
+
],
|
|
134
|
+
"Editor and IDE settings": [
|
|
135
|
+
".vscode/",
|
|
136
|
+
".idea/",
|
|
137
|
+
"*.swp",
|
|
138
|
+
"*~",
|
|
139
|
+
],
|
|
140
|
+
}.items():
|
|
141
|
+
self.add_gitignore_rules(children, *rules, section=section)
|
|
155
142
|
|
|
156
143
|
return raw_value
|
|
157
144
|
|
|
@@ -183,7 +183,6 @@ class PythonWorkdir(
|
|
|
183
183
|
from wexample_filestate.option.children_filter_option import (
|
|
184
184
|
ChildrenFilterOption,
|
|
185
185
|
)
|
|
186
|
-
from wexample_helpers.helpers.array import array_dict_get_by
|
|
187
186
|
|
|
188
187
|
from wexample_wex_addon_dev_python.file.python_pyproject_toml_file import (
|
|
189
188
|
PythonPyprojectTomlFile,
|
|
@@ -195,15 +194,12 @@ class PythonWorkdir(
|
|
|
195
194
|
|
|
196
195
|
children = raw_value["children"]
|
|
197
196
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
"
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
".python-version",
|
|
205
|
-
f"/{PYTHON_FILE_PYTEST_COVERAGE_JSON}",
|
|
206
|
-
]
|
|
197
|
+
self.add_gitignore_rules(
|
|
198
|
+
raw_value["children"],
|
|
199
|
+
".pdm-python",
|
|
200
|
+
".python-version",
|
|
201
|
+
f"/{PYTHON_FILE_PYTEST_COVERAGE_JSON}",
|
|
202
|
+
section="Python",
|
|
207
203
|
)
|
|
208
204
|
|
|
209
205
|
children.extend(
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|