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.
Files changed (20) hide show
  1. wexample_wex_addon_dev_python/commands/code/check/mypy.py +4 -2
  2. wexample_wex_addon_dev_python/commands/code/check/pyright.py +4 -1
  3. wexample_wex_addon_dev_python/commands/code/check.py +2 -4
  4. wexample_wex_addon_dev_python/commands/code/format/black.py +4 -1
  5. wexample_wex_addon_dev_python/commands/code/format/isort.py +4 -1
  6. wexample_wex_addon_dev_python/commands/code/format.py +5 -1
  7. wexample_wex_addon_dev_python/config_value/python_package_readme_config_value.py +33 -22
  8. wexample_wex_addon_dev_python/const/package.py +9 -8
  9. wexample_wex_addon_dev_python/file/python_package_toml_file.py +125 -126
  10. wexample_wex_addon_dev_python/middleware/each_python_file_middleware.py +16 -18
  11. wexample_wex_addon_dev_python/python_addon_manager.py +5 -1
  12. wexample_wex_addon_dev_python/workdir/python_package_workdir.py +108 -100
  13. wexample_wex_addon_dev_python/workdir/python_packages_suite_workdir.py +49 -56
  14. wexample_wex_addon_dev_python/workdir/python_workdir.py +93 -73
  15. {wexample_wex_addon_dev_python-0.0.45.dist-info → wexample_wex_addon_dev_python-0.0.48.dist-info}/METADATA +12 -10
  16. {wexample_wex_addon_dev_python-0.0.45.dist-info → wexample_wex_addon_dev_python-0.0.48.dist-info}/RECORD +18 -20
  17. wexample_wex_addon_dev_python/commands/examples/classes/__init__.py +0 -0
  18. wexample_wex_addon_dev_python/commands/examples/classes/example_pydantic_class_with_public_var_internaly_defined.py +0 -42
  19. {wexample_wex_addon_dev_python-0.0.45.dist-info → wexample_wex_addon_dev_python-0.0.48.dist-info}/WHEEL +0 -0
  20. {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 save_dependency(self, package: PythonPackageWorkdir) -> None:
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
- import re
35
+ Fetch the data from the pyproject.toml file.
36
+ """
37
+ return self.get_project_config_file(reload=reload).read_parsed()
68
38
 
69
- pkg = searched_package.get_package_import_name()
70
- pattern = (
71
- rf"(?m)^\s*(?:"
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
- shell_run(publish_cmd, inherit_stdio=True, cwd=self.get_path())
128
- progress.finish()
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 get_ordered_packages(self) -> list[PythonPackageWorkdir]:
149
- """Return package objects ordered leaves -> trunk."""
150
- order = self.build_ordered_dependencies()
151
- by_name = {p.get_package_name(): p for p in self.get_packages()}
152
- return [by_name[n] for n in order]
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 wexample_filestate.config_option.children_file_factory_config_option import (
19
- ChildrenFileFactoryConfigOption,
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 _create_package_name_snake(self, option: ItemTreeConfigOptionMixin) -> str:
78
- import os
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
- # TODO make generic
81
- return "wexample_" + string_to_snake_case(
82
- os.path.basename(
83
- os.path.dirname(os.path.realpath(option.get_parent_item().get_path()))
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.config_option.children_filter_config_option import (
92
- ChildrenFilterConfigOption,
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([".pdm-python", ".python-version", ".venv"])
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
- ChildrenFilterConfigOption(
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 _create_python_file_children_filter(self) -> ChildrenFileFactoryConfigOption:
192
- from wexample_filestate.config_option.children_filter_config_option import (
193
- ChildrenFilterConfigOption,
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 ChildrenFilterConfigOption(
193
+ return ChildrenFileFactoryOption(
199
194
  pattern={
200
195
  "class": PythonFile,
201
- "name_pattern": r"^.*\.py$",
196
+ "name": "__init__.py",
202
197
  "type": DiskItemType.FILE,
203
- "python": [
204
- # Configured for python >= 3.12
205
- PythonConfigOption.OPTION_NAME_ADD_FUTURE_ANNOTATIONS,
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 _create_init_children_factory(self) -> ChildrenFileFactoryConfigOption:
219
- from wexample_filestate.config_option.children_file_factory_config_option import (
220
- ChildrenFileFactoryConfigOption,
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 wexample_filestate.const.globals import NAME_PATTERN_NO_LEADING_DOT
224
- from wexample_filestate_python.const.name_pattern import (
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 ChildrenFileFactoryConfigOption(
228
+ return ChildrenFilterOption(
230
229
  pattern={
231
230
  "class": PythonFile,
232
- "name": "__init__.py",
231
+ "name_pattern": r"^.*\.py$",
233
232
  "type": DiskItemType.FILE,
234
- "name_pattern": [
235
- NAME_PATTERN_PYTHON_NOT_PYCACHE,
236
- NAME_PATTERN_NO_LEADING_DOT,
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,