wexample-wex-addon-dev-python 0.0.45__py3-none-any.whl → 0.0.48__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.
- wexample_wex_addon_dev_python/commands/code/check/mypy.py +4 -2
- wexample_wex_addon_dev_python/commands/code/check/pyright.py +4 -1
- wexample_wex_addon_dev_python/commands/code/check.py +2 -4
- wexample_wex_addon_dev_python/commands/code/format/black.py +4 -1
- wexample_wex_addon_dev_python/commands/code/format/isort.py +4 -1
- wexample_wex_addon_dev_python/commands/code/format.py +5 -1
- wexample_wex_addon_dev_python/config_value/python_package_readme_config_value.py +33 -22
- wexample_wex_addon_dev_python/const/package.py +9 -8
- wexample_wex_addon_dev_python/file/python_package_toml_file.py +125 -126
- wexample_wex_addon_dev_python/middleware/each_python_file_middleware.py +16 -18
- wexample_wex_addon_dev_python/python_addon_manager.py +5 -1
- wexample_wex_addon_dev_python/workdir/python_package_workdir.py +108 -100
- wexample_wex_addon_dev_python/workdir/python_packages_suite_workdir.py +49 -56
- wexample_wex_addon_dev_python/workdir/python_workdir.py +93 -73
- {wexample_wex_addon_dev_python-0.0.45.dist-info → wexample_wex_addon_dev_python-0.0.48.dist-info}/METADATA +12 -10
- {wexample_wex_addon_dev_python-0.0.45.dist-info → wexample_wex_addon_dev_python-0.0.48.dist-info}/RECORD +18 -20
- wexample_wex_addon_dev_python/commands/examples/classes/__init__.py +0 -0
- wexample_wex_addon_dev_python/commands/examples/classes/example_pydantic_class_with_public_var_internaly_defined.py +0 -42
- {wexample_wex_addon_dev_python-0.0.45.dist-info → wexample_wex_addon_dev_python-0.0.48.dist-info}/WHEEL +0 -0
- {wexample_wex_addon_dev_python-0.0.45.dist-info → wexample_wex_addon_dev_python-0.0.48.dist-info}/entry_points.txt +0 -0
|
@@ -2,133 +2,54 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
from typing import TYPE_CHECKING
|
|
4
4
|
|
|
5
|
-
from wexample_config.const.types import DictConfig
|
|
6
5
|
from wexample_filestate.config_value.readme_content_config_value import (
|
|
7
6
|
ReadmeContentConfigValue,
|
|
8
7
|
)
|
|
9
|
-
from wexample_helpers.const.types import StructuredData
|
|
10
|
-
from wexample_helpers.helpers.array import array_dict_get_by
|
|
11
|
-
from wexample_wex_addon_dev_python.file.python_package_toml_file import (
|
|
12
|
-
PythonPackageTomlFile,
|
|
13
|
-
)
|
|
14
8
|
from wexample_wex_addon_dev_python.workdir.python_workdir import PythonWorkdir
|
|
15
9
|
|
|
16
10
|
if TYPE_CHECKING:
|
|
17
11
|
from tomlkit import TOMLDocument
|
|
12
|
+
from wexample_config.const.types import DictConfig
|
|
18
13
|
from wexample_filestate.common.search_result import SearchResult
|
|
14
|
+
from wexample_filestate.config_value.readme_content_config_value import (
|
|
15
|
+
ReadmeContentConfigValue,
|
|
16
|
+
)
|
|
17
|
+
from wexample_helpers.const.types import StructuredData
|
|
19
18
|
from wexample_prompt.common.progress.progress_handle import ProgressHandle
|
|
19
|
+
from wexample_wex_addon_dev_python.file.python_package_toml_file import (
|
|
20
|
+
PythonPackageTomlFile,
|
|
21
|
+
)
|
|
20
22
|
|
|
21
23
|
|
|
22
24
|
class PythonPackageWorkdir(PythonWorkdir):
|
|
23
25
|
_project_info_cache = None
|
|
24
26
|
|
|
25
|
-
def get_project_config_file(self, reload: bool = True) -> PythonPackageTomlFile:
|
|
26
|
-
config_file = self.find_by_name("pyproject.toml")
|
|
27
|
-
assert isinstance(config_file, PythonPackageTomlFile)
|
|
28
|
-
# Read once to populate content with file source.
|
|
29
|
-
config_file.read_text(reload=reload)
|
|
30
|
-
return config_file
|
|
31
|
-
|
|
32
|
-
def save_project_config_file(self, config: StructuredData) -> None:
|
|
33
|
-
config_file = self.get_project_config_file()
|
|
34
|
-
config_file.write(config)
|
|
35
|
-
|
|
36
|
-
def get_project_config(self, reload: bool = True) -> TOMLDocument:
|
|
37
|
-
"""
|
|
38
|
-
Fetch the data from the pyproject.toml file.
|
|
39
|
-
"""
|
|
40
|
-
return self.get_project_config_file(reload=reload).read_parsed()
|
|
41
|
-
|
|
42
27
|
def depends_from(self, package: PythonPackageWorkdir) -> bool:
|
|
43
28
|
for dependence_name in self.get_dependencies():
|
|
44
29
|
if package.get_package_name() == dependence_name:
|
|
45
30
|
return True
|
|
46
31
|
return False
|
|
47
32
|
|
|
48
|
-
def
|
|
49
|
-
"""Add a dependency, use strict version as this is the intended internal management."""
|
|
50
|
-
config = self.get_project_config_file()
|
|
51
|
-
config.add_dependency(
|
|
52
|
-
f"{package.get_package_name()}=={package.get_project_version()}"
|
|
53
|
-
)
|
|
54
|
-
config.write_parsed()
|
|
55
|
-
|
|
56
|
-
def search_imports_in_codebase(
|
|
57
|
-
self, searched_package: PythonPackageWorkdir
|
|
58
|
-
) -> list[SearchResult]:
|
|
59
|
-
"""Find import statements that reference the given package.
|
|
60
|
-
|
|
61
|
-
Supports common Python forms:
|
|
62
|
-
- from <pkg>(.<sub>)* import ...
|
|
63
|
-
- import <pkg>(.<sub>)* [as alias]
|
|
64
|
-
|
|
65
|
-
Returns a list of SearchResult with file, line and column for each match.
|
|
33
|
+
def get_project_config(self, reload: bool = True) -> TOMLDocument:
|
|
66
34
|
"""
|
|
67
|
-
|
|
35
|
+
Fetch the data from the pyproject.toml file.
|
|
36
|
+
"""
|
|
37
|
+
return self.get_project_config_file(reload=reload).read_parsed()
|
|
68
38
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
rf"from\s+{re.escape(pkg)}(?:\.[\w\.]+)?\s+import\s+"
|
|
73
|
-
rf"|import\s+{re.escape(pkg)}(?:\.[\w\.]+)?(?:\s+as\s+\w+)?\b"
|
|
74
|
-
rf")"
|
|
39
|
+
def get_project_config_file(self, reload: bool = True) -> PythonPackageTomlFile:
|
|
40
|
+
from wexample_wex_addon_dev_python.file.python_package_toml_file import (
|
|
41
|
+
PythonPackageTomlFile,
|
|
75
42
|
)
|
|
76
|
-
return self.search_in_codebase(pattern, regex=True, flags=re.MULTILINE)
|
|
77
|
-
|
|
78
|
-
def search_in_codebase(
|
|
79
|
-
self, string: str, *, regex: bool = False, flags: int = 0
|
|
80
|
-
) -> list[SearchResult]:
|
|
81
|
-
found = []
|
|
82
|
-
from wexample_filestate.common.search_result import SearchResult
|
|
83
|
-
from wexample_filestate_python.file.python_file import PythonFile
|
|
84
|
-
|
|
85
|
-
def _search(item: PythonFile) -> None:
|
|
86
|
-
found.extend(
|
|
87
|
-
SearchResult.create_for_all_matches(
|
|
88
|
-
string, item, regex=regex, flags=flags
|
|
89
|
-
)
|
|
90
|
-
)
|
|
91
|
-
|
|
92
|
-
self.for_each_child_of_type_recursive(callback=_search, class_type=PythonFile)
|
|
93
|
-
|
|
94
|
-
return found
|
|
95
|
-
|
|
96
|
-
def publish(
|
|
97
|
-
self,
|
|
98
|
-
progress: ProgressHandle | None = None,
|
|
99
|
-
) -> None:
|
|
100
|
-
from wexample_filestate_python.common.pipy_gateway import PipyGateway
|
|
101
|
-
from wexample_helpers.helpers.shell import shell_run
|
|
102
|
-
|
|
103
|
-
progress.update(total=3, current=0)
|
|
104
|
-
super().publish(progress=progress.create_range_handle(to_step=1))
|
|
105
|
-
|
|
106
|
-
progress.update(current=2, label="Publishing to Pipy")
|
|
107
|
-
client = PipyGateway(parent_io_handler=self)
|
|
108
|
-
|
|
109
|
-
package_name = self.get_package_name()
|
|
110
|
-
version = self.get_project_version()
|
|
111
|
-
if client.package_release_exists(package_name=package_name, version=version):
|
|
112
|
-
self.warning(
|
|
113
|
-
f'Trying to publish an existing release for package "{package_name}" version {version}'
|
|
114
|
-
)
|
|
115
|
-
else:
|
|
116
|
-
# Map token to PyPI's token-based authentication if provided
|
|
117
|
-
username = "__token__"
|
|
118
|
-
password = self.get_env_parameter("PIPY_TOKEN")
|
|
119
|
-
|
|
120
|
-
# Build the publish command, adding credentials only when given
|
|
121
|
-
publish_cmd = ["pdm", "publish"]
|
|
122
|
-
if username is not None:
|
|
123
|
-
publish_cmd += ["--username", username]
|
|
124
|
-
if password is not None:
|
|
125
|
-
publish_cmd += ["--password", password]
|
|
126
43
|
|
|
127
|
-
|
|
128
|
-
|
|
44
|
+
config_file = self.find_by_name("pyproject.toml")
|
|
45
|
+
assert isinstance(config_file, PythonPackageTomlFile)
|
|
46
|
+
# Read once to populate content with file source.
|
|
47
|
+
config_file.read_text(reload=reload)
|
|
48
|
+
return config_file
|
|
129
49
|
|
|
130
50
|
def prepare_value(self, raw_value: DictConfig | None = None) -> DictConfig:
|
|
131
51
|
from wexample_filestate.const.disk import DiskItemType
|
|
52
|
+
from wexample_helpers.helpers.array import array_dict_get_by
|
|
132
53
|
from wexample_wex_addon_dev_python.file.python_package_toml_file import (
|
|
133
54
|
PythonPackageTomlFile,
|
|
134
55
|
)
|
|
@@ -198,6 +119,93 @@ class PythonPackageWorkdir(PythonWorkdir):
|
|
|
198
119
|
|
|
199
120
|
return raw_value
|
|
200
121
|
|
|
122
|
+
def publish(
|
|
123
|
+
self,
|
|
124
|
+
progress: ProgressHandle | None = None,
|
|
125
|
+
) -> None:
|
|
126
|
+
from wexample_filestate_python.common.pipy_gateway import PipyGateway
|
|
127
|
+
from wexample_helpers.helpers.shell import shell_run
|
|
128
|
+
|
|
129
|
+
progress.update(total=3, current=0)
|
|
130
|
+
super().publish(progress=progress.create_range_handle(to_step=1))
|
|
131
|
+
|
|
132
|
+
progress.update(current=2, label="Publishing to Pipy")
|
|
133
|
+
client = PipyGateway(parent_io_handler=self)
|
|
134
|
+
|
|
135
|
+
package_name = self.get_package_name()
|
|
136
|
+
version = self.get_project_version()
|
|
137
|
+
if client.package_release_exists(package_name=package_name, version=version):
|
|
138
|
+
self.warning(
|
|
139
|
+
f'Trying to publish an existing release for package "{package_name}" version {version}'
|
|
140
|
+
)
|
|
141
|
+
else:
|
|
142
|
+
# Map token to PyPI's token-based authentication if provided
|
|
143
|
+
username = "__token__"
|
|
144
|
+
password = self.get_env_parameter("PIPY_TOKEN")
|
|
145
|
+
|
|
146
|
+
# Build the publish command, adding credentials only when given
|
|
147
|
+
publish_cmd = ["pdm", "publish"]
|
|
148
|
+
if username is not None:
|
|
149
|
+
publish_cmd += ["--username", username]
|
|
150
|
+
if password is not None:
|
|
151
|
+
publish_cmd += ["--password", password]
|
|
152
|
+
|
|
153
|
+
shell_run(publish_cmd, inherit_stdio=True, cwd=self.get_path())
|
|
154
|
+
progress.finish()
|
|
155
|
+
|
|
156
|
+
def save_dependency(self, package: PythonPackageWorkdir) -> None:
|
|
157
|
+
"""Add a dependency, use strict version as this is the intended internal management."""
|
|
158
|
+
config = self.get_project_config_file()
|
|
159
|
+
config.add_dependency(
|
|
160
|
+
f"{package.get_package_name()}=={package.get_project_version()}"
|
|
161
|
+
)
|
|
162
|
+
config.write_parsed()
|
|
163
|
+
|
|
164
|
+
def save_project_config_file(self, config: StructuredData) -> None:
|
|
165
|
+
config_file = self.get_project_config_file()
|
|
166
|
+
config_file.write(config)
|
|
167
|
+
|
|
168
|
+
def search_imports_in_codebase(
|
|
169
|
+
self, searched_package: PythonPackageWorkdir
|
|
170
|
+
) -> list[SearchResult]:
|
|
171
|
+
"""Find import statements that reference the given package.
|
|
172
|
+
|
|
173
|
+
Supports common Python forms:
|
|
174
|
+
- from <pkg>(.<sub>)* import ...
|
|
175
|
+
- import <pkg>(.<sub>)* [as alias]
|
|
176
|
+
|
|
177
|
+
Returns a list of SearchResult with file, line and column for each match.
|
|
178
|
+
"""
|
|
179
|
+
import re
|
|
180
|
+
|
|
181
|
+
pkg = searched_package.get_package_import_name()
|
|
182
|
+
pattern = (
|
|
183
|
+
rf"(?m)^\s*(?:"
|
|
184
|
+
rf"from\s+{re.escape(pkg)}(?:\.[\w\.]+)?\s+import\s+"
|
|
185
|
+
rf"|import\s+{re.escape(pkg)}(?:\.[\w\.]+)?(?:\s+as\s+\w+)?\b"
|
|
186
|
+
rf")"
|
|
187
|
+
)
|
|
188
|
+
return self.search_in_codebase(pattern, regex=True, flags=re.MULTILINE)
|
|
189
|
+
|
|
190
|
+
def search_in_codebase(
|
|
191
|
+
self, string: str, *, regex: bool = False, flags: int = 0
|
|
192
|
+
) -> list[SearchResult]:
|
|
193
|
+
from wexample_filestate.common.search_result import SearchResult
|
|
194
|
+
from wexample_filestate_python.file.python_file import PythonFile
|
|
195
|
+
|
|
196
|
+
found = []
|
|
197
|
+
|
|
198
|
+
def _search(item: PythonFile) -> None:
|
|
199
|
+
found.extend(
|
|
200
|
+
SearchResult.create_for_all_matches(
|
|
201
|
+
string, item, regex=regex, flags=flags
|
|
202
|
+
)
|
|
203
|
+
)
|
|
204
|
+
|
|
205
|
+
self.for_each_child_of_type_recursive(callback=_search, class_type=PythonFile)
|
|
206
|
+
|
|
207
|
+
return found
|
|
208
|
+
|
|
201
209
|
def _get_readme_content(self) -> ReadmeContentConfigValue | None:
|
|
202
210
|
from wexample_wex_addon_dev_python.config_value.python_package_readme_config_value import (
|
|
203
211
|
PythonPackageReadmeContentConfigValue,
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
from pathlib import Path
|
|
4
3
|
from typing import TYPE_CHECKING
|
|
5
4
|
|
|
6
5
|
from wexample_wex_core.workdir.framework_packages_suite_workdir import (
|
|
@@ -8,6 +7,8 @@ from wexample_wex_core.workdir.framework_packages_suite_workdir import (
|
|
|
8
7
|
)
|
|
9
8
|
|
|
10
9
|
if TYPE_CHECKING:
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
|
|
11
12
|
from wexample_wex_addon_dev_python.workdir.python_package_workdir import (
|
|
12
13
|
PythonPackageWorkdir,
|
|
13
14
|
)
|
|
@@ -17,49 +18,6 @@ if TYPE_CHECKING:
|
|
|
17
18
|
|
|
18
19
|
|
|
19
20
|
class PythonPackagesSuiteWorkdir(FrameworkPackageSuiteWorkdir):
|
|
20
|
-
def packages_validate_internal_dependencies_declarations(self) -> None:
|
|
21
|
-
dependencies_map = self.build_dependencies_map()
|
|
22
|
-
for package_name in dependencies_map:
|
|
23
|
-
package = self.get_package(package_name)
|
|
24
|
-
|
|
25
|
-
for package_name_search in dependencies_map:
|
|
26
|
-
searched_package = self.get_package(package_name_search)
|
|
27
|
-
imports = package.search_imports_in_codebase(searched_package)
|
|
28
|
-
if len(imports) > 0:
|
|
29
|
-
dependencies_stack = self.build_dependencies_stack(
|
|
30
|
-
package, searched_package, dependencies_map
|
|
31
|
-
)
|
|
32
|
-
|
|
33
|
-
if len(dependencies_stack) == 0:
|
|
34
|
-
# Build a readable list of import locations to help debugging
|
|
35
|
-
imports_details = "\n".join(
|
|
36
|
-
f" - {res.item.get_path()}:{res.line}:{res.column}"
|
|
37
|
-
for res in imports
|
|
38
|
-
)
|
|
39
|
-
raise AssertionError(
|
|
40
|
-
(
|
|
41
|
-
'Dependency violation: package "{pkg}" imports code from "{dep}" '
|
|
42
|
-
"but there is no declared local dependency path. "
|
|
43
|
-
'Add "{dep}" to the \'project.dependencies\' of "{pkg}" in its pyproject.toml, '
|
|
44
|
-
'or declare an intermediate local package that depends on "{dep}".\n\n'
|
|
45
|
-
"Detected import locations:\n{locations}"
|
|
46
|
-
).format(
|
|
47
|
-
pkg=package_name,
|
|
48
|
-
dep=package_name_search,
|
|
49
|
-
locations=imports_details
|
|
50
|
-
or " - <no locations captured>",
|
|
51
|
-
)
|
|
52
|
-
)
|
|
53
|
-
|
|
54
|
-
def get_dependents(
|
|
55
|
-
self, package: PythonPackageWorkdir
|
|
56
|
-
) -> list[PythonPackageWorkdir]:
|
|
57
|
-
dependents = []
|
|
58
|
-
for neighbor_package in self.get_packages():
|
|
59
|
-
if neighbor_package.depends_from(package):
|
|
60
|
-
dependents.append(neighbor_package)
|
|
61
|
-
return dependents
|
|
62
|
-
|
|
63
21
|
def build_dependencies_stack(
|
|
64
22
|
self,
|
|
65
23
|
package: PythonPackageWorkdir,
|
|
@@ -74,7 +32,6 @@ class PythonPackagesSuiteWorkdir(FrameworkPackageSuiteWorkdir):
|
|
|
74
32
|
Returns a list of PythonPackageWorkdir objects [package, ..., dependency],
|
|
75
33
|
or an empty list if no path exists.
|
|
76
34
|
"""
|
|
77
|
-
|
|
78
35
|
start = package.get_package_name()
|
|
79
36
|
target = dependency.get_package_name()
|
|
80
37
|
|
|
@@ -117,6 +74,48 @@ class PythonPackagesSuiteWorkdir(FrameworkPackageSuiteWorkdir):
|
|
|
117
74
|
# Build and validate the dependency map, then compute a stable topological order
|
|
118
75
|
return self.topological_order(self.build_dependencies_map())
|
|
119
76
|
|
|
77
|
+
def get_dependents(
|
|
78
|
+
self, package: PythonPackageWorkdir
|
|
79
|
+
) -> list[PythonPackageWorkdir]:
|
|
80
|
+
dependents = []
|
|
81
|
+
for neighbor_package in self.get_packages():
|
|
82
|
+
if neighbor_package.depends_from(package):
|
|
83
|
+
dependents.append(neighbor_package)
|
|
84
|
+
return dependents
|
|
85
|
+
|
|
86
|
+
def get_ordered_packages(self) -> list[PythonPackageWorkdir]:
|
|
87
|
+
"""Return package objects ordered leaves -> trunk."""
|
|
88
|
+
order = self.build_ordered_dependencies()
|
|
89
|
+
by_name = {p.get_package_name(): p for p in self.get_packages()}
|
|
90
|
+
return [by_name[n] for n in order]
|
|
91
|
+
|
|
92
|
+
def packages_validate_internal_dependencies_declarations(self) -> None:
|
|
93
|
+
dependencies_map = self.build_dependencies_map()
|
|
94
|
+
for package_name in dependencies_map:
|
|
95
|
+
package = self.get_package(package_name)
|
|
96
|
+
|
|
97
|
+
for package_name_search in dependencies_map:
|
|
98
|
+
searched_package = self.get_package(package_name_search)
|
|
99
|
+
imports = package.search_imports_in_codebase(searched_package)
|
|
100
|
+
if len(imports) > 0:
|
|
101
|
+
dependencies_stack = self.build_dependencies_stack(
|
|
102
|
+
package, searched_package, dependencies_map
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
if len(dependencies_stack) == 0:
|
|
106
|
+
# Build a readable list of import locations to help debugging
|
|
107
|
+
imports_details = "\n".join(
|
|
108
|
+
f" - {res.item.get_path()}:{res.line}:{res.column}"
|
|
109
|
+
for res in imports
|
|
110
|
+
)
|
|
111
|
+
raise AssertionError(
|
|
112
|
+
f'Dependency violation: package "{package_name}" imports code from "{package_name_search}" '
|
|
113
|
+
f"but there is no declared local dependency path. "
|
|
114
|
+
f'Add "{package_name_search}" to the \'project.dependencies\' of "{package_name}" in its pyproject.toml, '
|
|
115
|
+
f'or declare an intermediate local package that depends on "{package_name_search}".\n\n'
|
|
116
|
+
f"Detected import locations:\n{imports_details}"
|
|
117
|
+
)
|
|
118
|
+
|
|
120
119
|
def topological_order(self, dep_map: dict[str, list[str]]) -> list[str]:
|
|
121
120
|
"""Deterministic topological order using graphlib.TopologicalSorter.
|
|
122
121
|
Returns a leaves -> trunk order (dependencies before dependents).
|
|
@@ -145,11 +144,11 @@ class PythonPackagesSuiteWorkdir(FrameworkPackageSuiteWorkdir):
|
|
|
145
144
|
# Return only local packages (original keys of dep_map)
|
|
146
145
|
return [n for n in order if n in dep_map]
|
|
147
146
|
|
|
148
|
-
def
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
return
|
|
147
|
+
def _child_is_package_directory(self, entry: Path) -> bool:
|
|
148
|
+
return entry.is_dir() and (entry / "pyproject.toml").is_file()
|
|
149
|
+
|
|
150
|
+
def _get_children_package_directory_name(self) -> str:
|
|
151
|
+
return "pip"
|
|
153
152
|
|
|
154
153
|
def _get_children_package_workdir_class(self) -> type[CodeBaseWorkdir]:
|
|
155
154
|
from wexample_wex_addon_dev_python.workdir.python_package_workdir import (
|
|
@@ -157,9 +156,3 @@ class PythonPackagesSuiteWorkdir(FrameworkPackageSuiteWorkdir):
|
|
|
157
156
|
)
|
|
158
157
|
|
|
159
158
|
return PythonPackageWorkdir
|
|
160
|
-
|
|
161
|
-
def _child_is_package_directory(self, entry: Path) -> bool:
|
|
162
|
-
return entry.is_dir() and (entry / "pyproject.toml").is_file()
|
|
163
|
-
|
|
164
|
-
def _get_children_package_directory_name(self) -> str:
|
|
165
|
-
return "pip"
|
|
@@ -2,21 +2,17 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
from typing import TYPE_CHECKING
|
|
4
4
|
|
|
5
|
-
from wexample_config.const.types import DictConfig
|
|
6
|
-
from wexample_config.options_provider.abstract_options_provider import (
|
|
7
|
-
AbstractOptionsProvider,
|
|
8
|
-
)
|
|
9
|
-
from wexample_filestate_python.config_option.python_config_option import (
|
|
10
|
-
PythonConfigOption,
|
|
11
|
-
)
|
|
12
|
-
from wexample_helpers.helpers.string import string_to_snake_case
|
|
13
5
|
from wexample_wex_core.workdir.code_base_workdir import (
|
|
14
6
|
CodeBaseWorkdir,
|
|
15
7
|
)
|
|
16
8
|
|
|
17
9
|
if TYPE_CHECKING:
|
|
18
|
-
from
|
|
19
|
-
|
|
10
|
+
from wexample_config.const.types import DictConfig
|
|
11
|
+
from wexample_config.options_provider.abstract_options_provider import (
|
|
12
|
+
AbstractOptionsProvider,
|
|
13
|
+
)
|
|
14
|
+
from wexample_filestate.option.children_file_factory_option import (
|
|
15
|
+
ChildrenFileFactoryOption,
|
|
20
16
|
)
|
|
21
17
|
from wexample_filestate.config_option.mixin.item_config_option_mixin import (
|
|
22
18
|
ItemTreeConfigOptionMixin,
|
|
@@ -27,15 +23,6 @@ if TYPE_CHECKING:
|
|
|
27
23
|
|
|
28
24
|
|
|
29
25
|
class PythonWorkdir(CodeBaseWorkdir):
|
|
30
|
-
def get_package_import_name(self) -> str:
|
|
31
|
-
# TODO concat suite name prefix.
|
|
32
|
-
return f"wexample_{self.get_project_name()}"
|
|
33
|
-
|
|
34
|
-
def get_package_name(self) -> str:
|
|
35
|
-
from wexample_helpers.helpers.string import string_to_kebab_case
|
|
36
|
-
|
|
37
|
-
return string_to_kebab_case(self.get_package_import_name())
|
|
38
|
-
|
|
39
26
|
def get_dependencies(self) -> list[str]:
|
|
40
27
|
from packaging.requirements import Requirement
|
|
41
28
|
|
|
@@ -44,21 +31,6 @@ class PythonWorkdir(CodeBaseWorkdir):
|
|
|
44
31
|
dependencies.append(Requirement(dependency).name)
|
|
45
32
|
return dependencies
|
|
46
33
|
|
|
47
|
-
def get_options_providers(self) -> list[type[AbstractOptionsProvider]]:
|
|
48
|
-
from wexample_filestate_python.options_provider.python_options_provider import (
|
|
49
|
-
PythonOptionsProvider,
|
|
50
|
-
)
|
|
51
|
-
|
|
52
|
-
options = super().get_options_providers()
|
|
53
|
-
|
|
54
|
-
options.extend(
|
|
55
|
-
[
|
|
56
|
-
PythonOptionsProvider,
|
|
57
|
-
]
|
|
58
|
-
)
|
|
59
|
-
|
|
60
|
-
return options
|
|
61
|
-
|
|
62
34
|
def get_operations_providers(self) -> list[type[AbstractOperationsProvider]]:
|
|
63
35
|
from wexample_filestate_python.operations_provider.python_operations_provider import (
|
|
64
36
|
PythonOperationsProvider,
|
|
@@ -74,35 +46,54 @@ class PythonWorkdir(CodeBaseWorkdir):
|
|
|
74
46
|
|
|
75
47
|
return operations
|
|
76
48
|
|
|
77
|
-
def
|
|
78
|
-
import
|
|
49
|
+
def get_options_providers(self) -> list[type[AbstractOptionsProvider]]:
|
|
50
|
+
from wexample_filestate_python.options_provider.python_options_provider import (
|
|
51
|
+
PythonOptionsProvider,
|
|
52
|
+
)
|
|
79
53
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
54
|
+
options = super().get_options_providers()
|
|
55
|
+
|
|
56
|
+
options.extend(
|
|
57
|
+
[
|
|
58
|
+
PythonOptionsProvider,
|
|
59
|
+
]
|
|
85
60
|
)
|
|
86
61
|
|
|
62
|
+
return options
|
|
63
|
+
|
|
64
|
+
def get_package_import_name(self) -> str:
|
|
65
|
+
# TODO concat suite name prefix.
|
|
66
|
+
return f"wexample_{self.get_project_name()}"
|
|
67
|
+
|
|
68
|
+
def get_package_name(self) -> str:
|
|
69
|
+
from wexample_helpers.helpers.string import string_to_kebab_case
|
|
70
|
+
|
|
71
|
+
return string_to_kebab_case(self.get_package_import_name())
|
|
72
|
+
|
|
87
73
|
def prepare_value(self, raw_value: DictConfig | None = None) -> DictConfig:
|
|
88
74
|
from wexample_config.config_value.callback_render_config_value import (
|
|
89
75
|
CallbackRenderConfigValue,
|
|
90
76
|
)
|
|
91
|
-
from wexample_filestate.
|
|
92
|
-
|
|
77
|
+
from wexample_filestate.option.children_filter_option import (
|
|
78
|
+
ChildrenFilterOption,
|
|
93
79
|
)
|
|
94
80
|
from wexample_filestate.const.disk import DiskItemType
|
|
81
|
+
from wexample_helpers.helpers.array import array_dict_get_by
|
|
95
82
|
|
|
96
83
|
raw_value = super().prepare_value(raw_value=raw_value)
|
|
97
84
|
|
|
98
85
|
children = raw_value["children"]
|
|
99
86
|
|
|
100
|
-
from wexample_helpers.helpers.array import array_dict_get_by
|
|
101
|
-
|
|
102
87
|
# Add rules to .gitignore
|
|
103
88
|
array_dict_get_by("name", ".gitignore", raw_value["children"]).setdefault(
|
|
104
89
|
"should_contain_lines", []
|
|
105
|
-
).extend(
|
|
90
|
+
).extend(
|
|
91
|
+
[
|
|
92
|
+
".pdm-python",
|
|
93
|
+
".python-version",
|
|
94
|
+
".venv",
|
|
95
|
+
]
|
|
96
|
+
)
|
|
106
97
|
|
|
107
98
|
children.extend(
|
|
108
99
|
[
|
|
@@ -153,7 +144,7 @@ class PythonWorkdir(CodeBaseWorkdir):
|
|
|
153
144
|
"type": DiskItemType.DIRECTORY,
|
|
154
145
|
"should_exist": False,
|
|
155
146
|
},
|
|
156
|
-
|
|
147
|
+
ChildrenFilterOption(
|
|
157
148
|
pattern={
|
|
158
149
|
"name_pattern": r"^.*\.egg-info$",
|
|
159
150
|
"type": DiskItemType.DIRECTORY,
|
|
@@ -188,52 +179,81 @@ class PythonWorkdir(CodeBaseWorkdir):
|
|
|
188
179
|
|
|
189
180
|
return raw_value
|
|
190
181
|
|
|
191
|
-
def
|
|
192
|
-
from wexample_filestate.
|
|
193
|
-
|
|
182
|
+
def _create_init_children_factory(self) -> ChildrenFileFactoryOption:
|
|
183
|
+
from wexample_filestate.option.children_file_factory_option import (
|
|
184
|
+
ChildrenFileFactoryOption,
|
|
194
185
|
)
|
|
195
186
|
from wexample_filestate.const.disk import DiskItemType
|
|
187
|
+
from wexample_filestate.const.globals import NAME_PATTERN_NO_LEADING_DOT
|
|
188
|
+
from wexample_filestate_python.const.name_pattern import (
|
|
189
|
+
NAME_PATTERN_PYTHON_NOT_PYCACHE,
|
|
190
|
+
)
|
|
196
191
|
from wexample_filestate_python.file.python_file import PythonFile
|
|
197
192
|
|
|
198
|
-
return
|
|
193
|
+
return ChildrenFileFactoryOption(
|
|
199
194
|
pattern={
|
|
200
195
|
"class": PythonFile,
|
|
201
|
-
"
|
|
196
|
+
"name": "__init__.py",
|
|
202
197
|
"type": DiskItemType.FILE,
|
|
203
|
-
"
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
PythonConfigOption.OPTION_NAME_REMOVE_UNUSED,
|
|
207
|
-
PythonConfigOption.OPTION_NAME_SORT_IMPORTS,
|
|
208
|
-
PythonConfigOption.OPTION_NAME_MODERNIZE_TYPING,
|
|
209
|
-
PythonConfigOption.OPTION_NAME_FSTRINGIFY,
|
|
210
|
-
PythonConfigOption.OPTION_NAME_ADD_RETURN_TYPES,
|
|
211
|
-
PythonConfigOption.OPTION_NAME_UNQUOTE_ANNOTATIONS,
|
|
212
|
-
PythonConfigOption.OPTION_NAME_FORMAT,
|
|
198
|
+
"name_pattern": [
|
|
199
|
+
NAME_PATTERN_PYTHON_NOT_PYCACHE,
|
|
200
|
+
NAME_PATTERN_NO_LEADING_DOT,
|
|
213
201
|
],
|
|
214
202
|
},
|
|
215
203
|
recursive=True,
|
|
216
204
|
)
|
|
217
205
|
|
|
218
|
-
def
|
|
219
|
-
|
|
220
|
-
|
|
206
|
+
def _create_package_name_snake(self, option: ItemTreeConfigOptionMixin) -> str:
|
|
207
|
+
import os
|
|
208
|
+
|
|
209
|
+
from wexample_helpers.helpers.string import string_to_snake_case
|
|
210
|
+
|
|
211
|
+
# TODO make generic
|
|
212
|
+
return "wexample_" + string_to_snake_case(
|
|
213
|
+
os.path.basename(
|
|
214
|
+
os.path.dirname(os.path.realpath(option.get_parent_item().get_path()))
|
|
215
|
+
)
|
|
216
|
+
)
|
|
217
|
+
|
|
218
|
+
def _create_python_file_children_filter(self) -> ChildrenFileFactoryOption:
|
|
219
|
+
from wexample_filestate.option.children_filter_option import (
|
|
220
|
+
ChildrenFilterOption,
|
|
221
221
|
)
|
|
222
222
|
from wexample_filestate.const.disk import DiskItemType
|
|
223
|
-
from
|
|
224
|
-
|
|
225
|
-
NAME_PATTERN_PYTHON_NOT_PYCACHE,
|
|
223
|
+
from wexample_filestate_python.config_option.python_config_option import (
|
|
224
|
+
PythonConfigOption,
|
|
226
225
|
)
|
|
227
226
|
from wexample_filestate_python.file.python_file import PythonFile
|
|
228
227
|
|
|
229
|
-
return
|
|
228
|
+
return ChildrenFilterOption(
|
|
230
229
|
pattern={
|
|
231
230
|
"class": PythonFile,
|
|
232
|
-
"
|
|
231
|
+
"name_pattern": r"^.*\.py$",
|
|
233
232
|
"type": DiskItemType.FILE,
|
|
234
|
-
"
|
|
235
|
-
|
|
236
|
-
|
|
233
|
+
"python": [
|
|
234
|
+
# Configured for python >= 3.12
|
|
235
|
+
# Order matters.
|
|
236
|
+
PythonConfigOption.OPTION_NAME_ADD_FUTURE_ANNOTATIONS,
|
|
237
|
+
PythonConfigOption.OPTION_NAME_RELOCATE_IMPORTS,
|
|
238
|
+
PythonConfigOption.OPTION_NAME_REMOVE_UNUSED,
|
|
239
|
+
PythonConfigOption.OPTION_NAME_SORT_IMPORTS,
|
|
240
|
+
PythonConfigOption.OPTION_NAME_MODERNIZE_TYPING,
|
|
241
|
+
PythonConfigOption.OPTION_NAME_FSTRINGIFY,
|
|
242
|
+
PythonConfigOption.OPTION_NAME_ADD_RETURN_TYPES,
|
|
243
|
+
PythonConfigOption.OPTION_NAME_UNQUOTE_ANNOTATIONS,
|
|
244
|
+
PythonConfigOption.OPTION_NAME_FIX_ATTRS,
|
|
245
|
+
PythonConfigOption.OPTION_NAME_ORDER_TYPE_CHECKING_BLOCK,
|
|
246
|
+
PythonConfigOption.OPTION_NAME_ORDER_MODULE_DOCSTRING,
|
|
247
|
+
PythonConfigOption.OPTION_NAME_ORDER_MODULE_METADATA,
|
|
248
|
+
PythonConfigOption.OPTION_NAME_ORDER_CONSTANTS,
|
|
249
|
+
PythonConfigOption.OPTION_NAME_ORDER_ITERABLE_ITEMS,
|
|
250
|
+
PythonConfigOption.OPTION_NAME_ORDER_MODULE_FUNCTIONS,
|
|
251
|
+
PythonConfigOption.OPTION_NAME_ORDER_MAIN_GUARD,
|
|
252
|
+
PythonConfigOption.OPTION_NAME_ORDER_CLASS_DOCSTRING,
|
|
253
|
+
PythonConfigOption.OPTION_NAME_ORDER_CLASS_ATTRIBUTES,
|
|
254
|
+
PythonConfigOption.OPTION_NAME_ORDER_CLASS_METHODS,
|
|
255
|
+
PythonConfigOption.OPTION_NAME_FIX_BLANK_LINES,
|
|
256
|
+
PythonConfigOption.OPTION_NAME_FORMAT,
|
|
237
257
|
],
|
|
238
258
|
},
|
|
239
259
|
recursive=True,
|