wexample-wex-addon-dev-python 10.1.1__tar.gz → 11.0.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.
Files changed (82) hide show
  1. {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-11.0.0}/PKG-INFO +10 -10
  2. {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-11.0.0}/README.md +5 -5
  3. {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-11.0.0}/pyproject.toml +5 -5
  4. {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-11.0.0}/src/wexample_wex_addon_dev_python/commands/code/check/mypy.py +4 -3
  5. {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-11.0.0}/src/wexample_wex_addon_dev_python/commands/code/check/pylint.py +25 -19
  6. {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-11.0.0}/src/wexample_wex_addon_dev_python/commands/code/check/pyright.py +18 -14
  7. {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-11.0.0}/src/wexample_wex_addon_dev_python/commands/code/check.py +4 -7
  8. {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-11.0.0}/src/wexample_wex_addon_dev_python/commands/code/format/black.py +14 -15
  9. {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-11.0.0}/src/wexample_wex_addon_dev_python/commands/code/format/isort.py +14 -15
  10. {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-11.0.0}/src/wexample_wex_addon_dev_python/commands/code/format.py +8 -5
  11. wexample_wex_addon_dev_python-11.0.0/src/wexample_wex_addon_dev_python/commands/code/rename.py +134 -0
  12. {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-11.0.0}/src/wexample_wex_addon_dev_python/commands/examples/validate.py +1 -2
  13. {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-11.0.0}/src/wexample_wex_addon_dev_python/common/pypi_registry_gateway.py +5 -3
  14. {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-11.0.0}/src/wexample_wex_addon_dev_python/config_value/python_package_readme_config_value.py +2 -8
  15. {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-11.0.0}/src/wexample_wex_addon_dev_python/file/python_app_iml_file.py +3 -2
  16. {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-11.0.0}/src/wexample_wex_addon_dev_python/file/python_pyproject_toml_file.py +7 -7
  17. {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-11.0.0}/src/wexample_wex_addon_dev_python/helpers/pdm.py +3 -2
  18. {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-11.0.0}/src/wexample_wex_addon_dev_python/middleware/each_python_file_middleware.py +12 -14
  19. {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-11.0.0}/src/wexample_wex_addon_dev_python/python_addon_manager.py +12 -1
  20. wexample_wex_addon_dev_python-11.0.0/src/wexample_wex_addon_dev_python/refactor/__init__.py +7 -0
  21. wexample_wex_addon_dev_python-11.0.0/src/wexample_wex_addon_dev_python/refactor/python_package_rename_handler.py +215 -0
  22. wexample_wex_addon_dev_python-11.0.0/src/wexample_wex_addon_dev_python/refactor/symbol_kind.py +19 -0
  23. {wexample_wex_addon_dev_python-10.1.1/src/wexample_wex_addon_dev_python/services → wexample_wex_addon_dev_python-11.0.0/src/wexample_wex_addon_dev_python/selection}/__init__.py +0 -0
  24. wexample_wex_addon_dev_python-11.0.0/src/wexample_wex_addon_dev_python/selection/abstract_python_code_selection.py +58 -0
  25. wexample_wex_addon_dev_python-11.0.0/src/wexample_wex_addon_dev_python/selection/python_code_performance_selection.py +171 -0
  26. {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-11.0.0}/src/wexample_wex_addon_dev_python/services/python/commands/service/install.py +7 -10
  27. {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-11.0.0}/src/wexample_wex_addon_dev_python/services/python/commands/service/setup.py +5 -3
  28. {wexample_wex_addon_dev_python-10.1.1/tests/helpers → wexample_wex_addon_dev_python-11.0.0/src/wexample_wex_addon_dev_python/workdir/mixin}/__init__.py +0 -0
  29. {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-11.0.0}/src/wexample_wex_addon_dev_python/workdir/mixin/with_profiling_python_workdir_mixin.py +15 -16
  30. {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-11.0.0}/src/wexample_wex_addon_dev_python/workdir/python_package_workdir.py +47 -58
  31. {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-11.0.0}/src/wexample_wex_addon_dev_python/workdir/python_packages_suite_workdir.py +2 -3
  32. {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-11.0.0}/src/wexample_wex_addon_dev_python/workdir/python_workdir.py +93 -31
  33. wexample_wex_addon_dev_python-11.0.0/tests/helpers/__init__.py +0 -0
  34. wexample_wex_addon_dev_python-11.0.0/tests/unit/__init__.py +0 -0
  35. wexample_wex_addon_dev_python-11.0.0/tests/unit/helpers/__init__.py +0 -0
  36. wexample_wex_addon_dev_python-11.0.0/tests/unit/helpers/test_pdm.py +7 -0
  37. {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-11.0.0}/src/wexample_wex_addon_dev_python/__init__.py +0 -0
  38. {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-11.0.0}/src/wexample_wex_addon_dev_python/__pycache__/__init__.py +0 -0
  39. {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-11.0.0}/src/wexample_wex_addon_dev_python/commands/__init__.py +0 -0
  40. {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-11.0.0}/src/wexample_wex_addon_dev_python/commands/code/__init__.py +0 -0
  41. {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-11.0.0}/src/wexample_wex_addon_dev_python/commands/code/check/__init__.py +0 -0
  42. {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-11.0.0}/src/wexample_wex_addon_dev_python/commands/code/format/__init__.py +0 -0
  43. {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-11.0.0}/src/wexample_wex_addon_dev_python/commands/examples/__init__.py +0 -0
  44. {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-11.0.0}/src/wexample_wex_addon_dev_python/commands/examples/utils/__init__.py +0 -0
  45. {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-11.0.0}/src/wexample_wex_addon_dev_python/commands/examples/utils/some_example_type.py +0 -0
  46. {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-11.0.0}/src/wexample_wex_addon_dev_python/commands/release/__init__.py +0 -0
  47. {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-11.0.0}/src/wexample_wex_addon_dev_python/common/__init__.py +0 -0
  48. {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-11.0.0}/src/wexample_wex_addon_dev_python/config_value/__init__.py +0 -0
  49. {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-11.0.0}/src/wexample_wex_addon_dev_python/config_value/__pycache__/__init__.py +0 -0
  50. {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-11.0.0}/src/wexample_wex_addon_dev_python/const/__init__.py +0 -0
  51. {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-11.0.0}/src/wexample_wex_addon_dev_python/const/__pycache__/__init__.py +0 -0
  52. {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-11.0.0}/src/wexample_wex_addon_dev_python/const/package.py +0 -0
  53. {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-11.0.0}/src/wexample_wex_addon_dev_python/const/python.py +0 -0
  54. {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-11.0.0}/src/wexample_wex_addon_dev_python/const/tags.py +0 -0
  55. {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-11.0.0}/src/wexample_wex_addon_dev_python/file/__init__.py +0 -0
  56. {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-11.0.0}/src/wexample_wex_addon_dev_python/file/__pycache__/__init__.py +0 -0
  57. {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-11.0.0}/src/wexample_wex_addon_dev_python/helpers/__init__.py +0 -0
  58. {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-11.0.0}/src/wexample_wex_addon_dev_python/middleware/__init__.py +0 -0
  59. {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-11.0.0}/src/wexample_wex_addon_dev_python/middleware/__pycache__/__init__.py +0 -0
  60. {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-11.0.0}/src/wexample_wex_addon_dev_python/py.typed +0 -0
  61. {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-11.0.0}/src/wexample_wex_addon_dev_python/resources/.wex.yml +0 -0
  62. {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-11.0.0}/src/wexample_wex_addon_dev_python/resources/docker/Dockerfile.python-profiling +0 -0
  63. {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-11.0.0}/src/wexample_wex_addon_dev_python/resources/package_publish_gitlab.yml +0 -0
  64. {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-11.0.0}/src/wexample_wex_addon_dev_python/resources/readme_templates/tests.md.j2 +0 -0
  65. {wexample_wex_addon_dev_python-10.1.1/src/wexample_wex_addon_dev_python/services/python → wexample_wex_addon_dev_python-11.0.0/src/wexample_wex_addon_dev_python/services}/__init__.py +0 -0
  66. {wexample_wex_addon_dev_python-10.1.1/src/wexample_wex_addon_dev_python/services/python/commands → wexample_wex_addon_dev_python-11.0.0/src/wexample_wex_addon_dev_python/services/python}/__init__.py +0 -0
  67. {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-11.0.0}/src/wexample_wex_addon_dev_python/services/python/app_service.py +0 -0
  68. {wexample_wex_addon_dev_python-10.1.1/src/wexample_wex_addon_dev_python/services/python/commands/service → wexample_wex_addon_dev_python-11.0.0/src/wexample_wex_addon_dev_python/services/python/commands}/__init__.py +0 -0
  69. {wexample_wex_addon_dev_python-10.1.1/src/wexample_wex_addon_dev_python/services/python/samples → wexample_wex_addon_dev_python-11.0.0/src/wexample_wex_addon_dev_python/services/python/commands/service}/__init__.py +0 -0
  70. {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-11.0.0}/src/wexample_wex_addon_dev_python/services/python/docker/.wex.yml +0 -0
  71. {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-11.0.0}/src/wexample_wex_addon_dev_python/services/python/docker/docker-compose.yml +0 -0
  72. {wexample_wex_addon_dev_python-10.1.1/src/wexample_wex_addon_dev_python/services/python/samples/docker → wexample_wex_addon_dev_python-11.0.0/src/wexample_wex_addon_dev_python/services/python/samples}/__init__.py +0 -0
  73. {wexample_wex_addon_dev_python-10.1.1/src/wexample_wex_addon_dev_python/services/python/samples/docker/images → wexample_wex_addon_dev_python-11.0.0/src/wexample_wex_addon_dev_python/services/python/samples/docker}/__init__.py +0 -0
  74. {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-11.0.0}/src/wexample_wex_addon_dev_python/services/python/samples/docker/docker-compose.yml +0 -0
  75. {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-11.0.0}/src/wexample_wex_addon_dev_python/services/python/samples/docker/entrypoint.sh +0 -0
  76. {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-11.0.0}/src/wexample_wex_addon_dev_python/services/python/samples/docker/images/Dockerfile.base +0 -0
  77. {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-11.0.0}/src/wexample_wex_addon_dev_python/services/python/samples/docker/images/Dockerfile.develop +0 -0
  78. {wexample_wex_addon_dev_python-10.1.1/src/wexample_wex_addon_dev_python/workdir → wexample_wex_addon_dev_python-11.0.0/src/wexample_wex_addon_dev_python/services/python/samples/docker/images}/__init__.py +0 -0
  79. {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-11.0.0}/src/wexample_wex_addon_dev_python/services/python/service.yml +0 -0
  80. {wexample_wex_addon_dev_python-10.1.1/src/wexample_wex_addon_dev_python/workdir/__pycache__ → wexample_wex_addon_dev_python-11.0.0/src/wexample_wex_addon_dev_python/workdir}/__init__.py +0 -0
  81. {wexample_wex_addon_dev_python-10.1.1/src/wexample_wex_addon_dev_python/workdir/mixin → wexample_wex_addon_dev_python-11.0.0/src/wexample_wex_addon_dev_python/workdir/__pycache__}/__init__.py +0 -0
  82. {wexample_wex_addon_dev_python-10.1.1 → wexample_wex_addon_dev_python-11.0.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.1.1
3
+ Version: 11.0.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.4.0
19
- Requires-Dist: wexample-filestate-python>=7.0.0
20
- Requires-Dist: wexample-wex-addon-ai>=10.0.0
21
- Requires-Dist: wexample-wex-addon-app>=25.2.0
18
+ Requires-Dist: wexample-api>=6.6.0
19
+ Requires-Dist: wexample-filestate-python>=8.1.0
20
+ Requires-Dist: wexample-wex-addon-ai>=11.1.0
21
+ Requires-Dist: wexample-wex-addon-app>=25.4.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.1.1
29
+ Version: 11.0.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.4.0
116
- - wexample-filestate-python: >=7.0.0
117
- - wexample-wex-addon-ai: >=10.0.0
118
- - wexample-wex-addon-app: >=25.2.0
115
+ - wexample-api: >=6.6.0
116
+ - wexample-filestate-python: >=8.1.0
117
+ - wexample-wex-addon-ai: >=11.1.0
118
+ - wexample-wex-addon-app: >=25.4.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.1.1
3
+ Version: 11.0.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.4.0
90
- - wexample-filestate-python: >=7.0.0
91
- - wexample-wex-addon-ai: >=10.0.0
92
- - wexample-wex-addon-app: >=25.2.0
89
+ - wexample-api: >=6.6.0
90
+ - wexample-filestate-python: >=8.1.0
91
+ - wexample-wex-addon-ai: >=11.1.0
92
+ - wexample-wex-addon-app: >=25.4.0
93
93
 
94
94
  ## Versioning & Compatibility Policy
95
95
 
@@ -6,7 +6,7 @@ build-backend = "pdm.backend"
6
6
 
7
7
  [project]
8
8
  name = "wexample-wex-addon-dev-python"
9
- version = "10.1.1"
9
+ version = "11.0.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.4.0",
28
- "wexample-filestate-python>=7.0.0",
29
- "wexample-wex-addon-ai>=10.0.0",
30
- "wexample-wex-addon-app>=25.2.0",
27
+ "wexample-api>=6.6.0",
28
+ "wexample-filestate-python>=8.1.0",
29
+ "wexample-wex-addon-ai>=11.1.0",
30
+ "wexample-wex-addon-app>=25.4.0",
31
31
  ]
32
32
 
33
33
  [project.readme]
@@ -35,12 +35,13 @@ def _code_check_mypy(kernel: Kernel, file_path: str) -> bool:
35
35
  # Build and check the file
36
36
  source = BuildSource(path=file_path, module=None, text=None)
37
37
  result = build.build(sources=[source], options=options, alt_lib_path=None)
38
- if result.errors:
38
+ errors = result.errors
39
+ if errors:
39
40
  kernel.io.log_indent_up()
40
- kernel.io.error(f"Mypy errors:")
41
+ kernel.io.error("Mypy errors:")
41
42
  kernel.io.log_indent_up()
42
43
 
43
- for error in result.errors:
44
+ for error in errors:
44
45
  kernel.io.error(message=error, symbol=False)
45
46
 
46
47
  kernel.io.log_indent_down(number=2)
@@ -5,6 +5,16 @@ from typing import TYPE_CHECKING
5
5
  if TYPE_CHECKING:
6
6
  from wexample_cli.context.execution_context import ExecutionContext
7
7
 
8
+ # Pre-computed once at import time; avoids list allocation + join on every call.
9
+ _PYLINT_DISABLE_FLAG = "--disable=" + ",".join([
10
+ "missing-module-docstring",
11
+ "import-outside-toplevel",
12
+ "no-name-in-module",
13
+ "broad-exception-caught",
14
+ "c-extension-no-member",
15
+ "line-too-long",
16
+ ])
17
+
8
18
 
9
19
  def _code_check_pylint(context: ExecutionContext, file_path: str) -> bool:
10
20
  """Check a Python file using pylint for code quality.
@@ -22,23 +32,13 @@ def _code_check_pylint(context: ExecutionContext, file_path: str) -> bool:
22
32
 
23
33
  # Use subprocess to capture pylint output
24
34
  # This avoids issues with pylint's direct printing to stdout
25
- # List of warnings to disable
26
- disabled_warnings = [
27
- "missing-module-docstring",
28
- "import-outside-toplevel",
29
- "no-name-in-module",
30
- "broad-exception-caught",
31
- "c-extension-no-member",
32
- "line-too-long",
33
- ]
34
-
35
35
  cmd = [
36
36
  sys.executable,
37
37
  "-m",
38
38
  "pylint",
39
39
  file_path,
40
40
  "--output-format=json",
41
- f"--disable={','.join(disabled_warnings)}",
41
+ _PYLINT_DISABLE_FLAG,
42
42
  ]
43
43
  process = subprocess.run(cmd, capture_output=True, text=True, check=False)
44
44
 
@@ -53,19 +53,25 @@ def _code_check_pylint(context: ExecutionContext, file_path: str) -> bool:
53
53
  # Parse the JSON output
54
54
  results = json.loads(json_output)
55
55
 
56
- # Filter messages by type
57
- errors = [msg for msg in results if msg.get("type") in ("error", "fatal")]
58
- warnings = [msg for msg in results if msg.get("type") == "warning"]
59
- conventions = [
60
- msg for msg in results if msg.get("type") in ("convention", "refactor", "info")
61
- ]
56
+ # Categorise messages in a single pass instead of three separate comprehensions.
57
+ errors: list = []
58
+ warnings: list = []
59
+ conventions: list = []
60
+ for msg in results:
61
+ t = msg.get("type")
62
+ if t in ("error", "fatal"):
63
+ errors.append(msg)
64
+ elif t == "warning":
65
+ warnings.append(msg)
66
+ elif t in ("convention", "refactor", "info"):
67
+ conventions.append(msg)
62
68
 
63
69
  # Display results if any issues found
64
70
  if errors or warnings or conventions:
65
71
  # Display errors
66
72
  if errors:
67
73
  context.io.log_indent_up()
68
- context.io.error(f"Pylint errors:")
74
+ context.io.error("Pylint errors:")
69
75
  context.io.log_indent_up()
70
76
 
71
77
  for error in errors:
@@ -80,7 +86,7 @@ def _code_check_pylint(context: ExecutionContext, file_path: str) -> bool:
80
86
  # Display warnings with detailed logging
81
87
  if warnings:
82
88
  context.io.log_indent_up()
83
- context.io.warning(f"Pylint warnings:")
89
+ context.io.warning("Pylint warnings:")
84
90
  context.io.log_indent_up()
85
91
 
86
92
  for warning in warnings:
@@ -1,5 +1,8 @@
1
1
  from __future__ import annotations
2
2
 
3
+ import json
4
+ import subprocess
5
+ import sys
3
6
  from typing import TYPE_CHECKING
4
7
 
5
8
  if TYPE_CHECKING:
@@ -16,10 +19,6 @@ def _code_check_pyright(kernel: Kernel, file_path: str) -> bool:
16
19
  Returns:
17
20
  bool: True if check passes, False otherwise
18
21
  """
19
- import json
20
- import subprocess
21
- import sys
22
-
23
22
  # Use subprocess to run pyright
24
23
  cmd = [sys.executable, "-m", "pyright", file_path, "--outputjson"]
25
24
  process = subprocess.run(cmd, capture_output=True, text=True, check=False)
@@ -42,20 +41,25 @@ def _code_check_pyright(kernel: Kernel, file_path: str) -> bool:
42
41
  # Parse the JSON output
43
42
  results = json.loads(json_output)
44
43
 
45
- # Extract diagnostics
46
- diagnostics = results.get("diagnostics", [])
47
-
48
- # Filter by severity
49
- errors = [diag for diag in diagnostics if diag.get("severity") == "error"]
50
- warnings = [diag for diag in diagnostics if diag.get("severity") == "warning"]
51
- info = [diag for diag in diagnostics if diag.get("severity") == "information"]
44
+ # Classify diagnostics in a single pass (avoids 3× iteration and repeated .get("severity"))
45
+ errors: list = []
46
+ warnings: list = []
47
+ info: list = []
48
+ for diag in results.get("diagnostics", []):
49
+ sev = diag.get("severity")
50
+ if sev == "error":
51
+ errors.append(diag)
52
+ elif sev == "warning":
53
+ warnings.append(diag)
54
+ elif sev == "information":
55
+ info.append(diag)
52
56
 
53
57
  # Display results if any issues found
54
58
  if errors or warnings or info:
55
59
  # Display errors
56
60
  if errors:
57
61
  kernel.io.log_indent_up()
58
- kernel.io.error(f"Pyright errors:")
62
+ kernel.io.error("Pyright errors:")
59
63
 
60
64
  for error in errors:
61
65
  line = error.get("range", {}).get("start", {}).get("line", 0) + 1
@@ -70,7 +74,7 @@ def _code_check_pyright(kernel: Kernel, file_path: str) -> bool:
70
74
  # Display warnings
71
75
  if warnings:
72
76
  kernel.io.log_indent_up()
73
- kernel.io.warning(f"Pyright warnings:")
77
+ kernel.io.warning("Pyright warnings:")
74
78
 
75
79
  for warning in warnings:
76
80
  line = warning.get("range", {}).get("start", {}).get("line", 0) + 1
@@ -85,7 +89,7 @@ def _code_check_pyright(kernel: Kernel, file_path: str) -> bool:
85
89
  # Display information
86
90
  if info:
87
91
  kernel.io.log_indent_up()
88
- kernel.io.info(f"Pyright information:")
92
+ kernel.io.info("Pyright information:")
89
93
  kernel.io.log_indent_up()
90
94
 
91
95
  for item in info:
@@ -74,16 +74,13 @@ def python__code__check(
74
74
  }
75
75
 
76
76
  # Determine which tools to run
77
- if tool and tool.lower() in tool_map:
77
+ tool_lower = tool.lower() if tool else None
78
+ if tool_lower and tool_lower in tool_map:
78
79
  # Run only the specified tool
79
- check_functions = [tool_map[tool.lower()]]
80
+ check_functions = [tool_map[tool_lower]]
80
81
  else:
81
82
  # Run all tools if no specific tool is specified or if the specified tool is invalid
82
- check_functions = [
83
- _code_check_mypy,
84
- _code_check_pylint,
85
- _code_check_pyright,
86
- ]
83
+ check_functions = list(tool_map.values())
87
84
 
88
85
  # Track overall success
89
86
  all_checks_passed = True
@@ -1,5 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
+ import subprocess
4
+ import sys
3
5
  from typing import TYPE_CHECKING
4
6
 
5
7
  if TYPE_CHECKING:
@@ -16,11 +18,8 @@ def _code_format_black(kernel: Kernel, file_path: str) -> bool:
16
18
  Returns:
17
19
  bool: True if formatting succeeds, False otherwise
18
20
  """
19
- import subprocess
20
- import sys
21
-
22
21
  # Use subprocess to run black
23
- cmd = [sys.executable, "-m", "black", file_path]
22
+ cmd = (sys.executable, "-m", "black", file_path)
24
23
  process = subprocess.run(cmd, capture_output=True, text=True, check=False)
25
24
 
26
25
  # Check if the command was successful
@@ -30,17 +29,17 @@ def _code_format_black(kernel: Kernel, file_path: str) -> bool:
30
29
  else:
31
30
  kernel.io.success(f"Black: {file_path} already well formatted")
32
31
  return True
33
- else:
34
- kernel.io.error(f"Black failed to format {file_path}")
35
- kernel.io.log_indent_up()
36
32
 
37
- if process.stderr:
38
- kernel.io.error(f"Error: {process.stderr}", symbol=False)
39
- if process.stdout:
40
- kernel.io.error(f"Output: {process.stdout}", symbol=False)
33
+ kernel.io.error(f"Black failed to format {file_path}")
34
+ kernel.io.log_indent_up()
35
+
36
+ if process.stderr:
37
+ kernel.io.error(f"Error: {process.stderr}", symbol=False)
38
+ if process.stdout:
39
+ kernel.io.error(f"Output: {process.stdout}", symbol=False)
41
40
 
42
- # Add detailed error properties
43
- kernel.io.properties({"returncode": process.returncode, "command": cmd})
41
+ # Add detailed error properties
42
+ kernel.io.properties({"returncode": process.returncode, "command": cmd})
44
43
 
45
- kernel.io.log_indent_down()
46
- return False
44
+ kernel.io.log_indent_down()
45
+ return False
@@ -1,5 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
+ import subprocess
4
+ import sys
3
5
  from typing import TYPE_CHECKING
4
6
 
5
7
  if TYPE_CHECKING:
@@ -16,13 +18,10 @@ def _code_format_isort(kernel: Kernel, file_path: str) -> bool:
16
18
  Returns:
17
19
  bool: True if formatting succeeds, False otherwise
18
20
  """
19
- import subprocess
20
- import sys
21
-
22
21
  # Use subprocess to run isort
23
22
  # --profile=black ensures compatibility with Black formatter
24
23
  cmd = [sys.executable, "-m", "isort", "--profile=black", file_path]
25
- process = subprocess.run(cmd, capture_output=True, text=True, check=False)
24
+ process = subprocess.run(cmd, capture_output=True, text=True)
26
25
 
27
26
  # Check if the command was successful
28
27
  if process.returncode == 0:
@@ -31,17 +30,17 @@ def _code_format_isort(kernel: Kernel, file_path: str) -> bool:
31
30
  else:
32
31
  kernel.io.success(f"isort successfully reformatted imports in {file_path}")
33
32
  return True
34
- else:
35
- kernel.io.error(f"isort failed to format imports in {file_path}")
36
- kernel.io.log_indent_up()
37
33
 
38
- if process.stderr:
39
- kernel.io.error(f"Error: {process.stderr}", symbol=False)
40
- if process.stdout:
41
- kernel.io.error(f"Output: {process.stdout}", symbol=False)
34
+ kernel.io.error(f"isort failed to format imports in {file_path}")
35
+ kernel.io.log_indent_up()
36
+
37
+ if process.stderr:
38
+ kernel.io.error(f"Error: {process.stderr}", symbol=False)
39
+ if process.stdout:
40
+ kernel.io.error(f"Output: {process.stdout}", symbol=False)
42
41
 
43
- # Add detailed error properties
44
- kernel.io.properties({"returncode": process.returncode, "command": cmd})
42
+ # Add detailed error properties
43
+ kernel.io.properties({"returncode": process.returncode, "command": cmd})
45
44
 
46
- kernel.io.log_indent_down()
47
- return False
45
+ kernel.io.log_indent_down()
46
+ return False
@@ -61,13 +61,16 @@ def python__code__format(
61
61
  "isort": _code_format_isort,
62
62
  }
63
63
 
64
+ # Normalise once to avoid repeated .lower() calls
65
+ tool_lower = tool.lower() if tool else None
66
+
64
67
  # Determine which tools to run
65
- if tool and tool.lower() in tool_map:
68
+ if tool_lower in tool_map:
66
69
  # Run only the specified tool
67
- format_functions = [tool_map[tool.lower()]]
70
+ format_functions = [tool_map[tool_lower]]
68
71
  else:
69
- # Run all tools if no specific tool is specified or if the specified tool is invalid
70
- if tool and tool.lower() not in tool_map:
72
+ # In the else branch, a truthy tool_lower is already known to be absent from tool_map
73
+ if tool_lower:
71
74
  kernel.io.warning(f"Unknown tool '{tool}', running all available tools")
72
75
 
73
76
  # Run isort first, then black (recommended order)
@@ -85,7 +88,7 @@ def python__code__format(
85
88
  format_result = format_function(kernel, file)
86
89
 
87
90
  # Update overall success status
88
- all_formats_passed = all_formats_passed and format_result
91
+ all_formats_passed &= format_result
89
92
 
90
93
  # Stop if a format fails and stop_on_failure is True
91
94
  if not format_result and stop_on_failure:
@@ -0,0 +1,134 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import TYPE_CHECKING
4
+
5
+ from wexample_cli.const.tags import AudienceTag, EffectTag, ScopeTag
6
+ from wexample_cli.decorator.command import command
7
+ from wexample_cli.decorator.middleware import middleware
8
+ from wexample_cli.decorator.option import option
9
+ from wexample_wex_addon_app.middleware.app_middleware import AppMiddleware
10
+ from wexample_wex_core.const.globals import COMMAND_TYPE_ADDON
11
+
12
+ from wexample_wex_addon_dev_python.const.tags import DomainTag
13
+
14
+ if TYPE_CHECKING:
15
+ from wexample_app.response.abstract_response import AbstractResponse
16
+ from wexample_cli.context.execution_context import ExecutionContext
17
+ from wexample_wex_addon_app.workdir.managed_workdir import ManagedWorkdir
18
+
19
+
20
+ @option(
21
+ name="source",
22
+ type=str,
23
+ required=True,
24
+ description="Dotted source name to rename (e.g. 'mylib.helpers').",
25
+ )
26
+ @option(
27
+ name="target",
28
+ type=str,
29
+ required=True,
30
+ description="Dotted target name (e.g. 'mylib.helper').",
31
+ )
32
+ @option(
33
+ name="kind",
34
+ type=str,
35
+ required=False,
36
+ default="package",
37
+ description="Symbol kind to rename. Step 1 supports only 'package'.",
38
+ )
39
+ @option(
40
+ name="dry_run",
41
+ type=bool,
42
+ is_flag=True,
43
+ default=False,
44
+ description="Preview impacted files without writing. Default: changes are applied.",
45
+ )
46
+ @middleware(middleware=AppMiddleware)
47
+ @command(
48
+ type=COMMAND_TYPE_ADDON,
49
+ description=(
50
+ "Rename a Python package directory and propagate the change to every "
51
+ "import statement in the workdir. Dry-run by default."
52
+ ),
53
+ tags=[
54
+ DomainTag.LANGUAGE_PYTHON,
55
+ EffectTag.WRITE,
56
+ AudienceTag.AGENT_SAFE,
57
+ ScopeTag.LOCAL,
58
+ ScopeTag.PACKAGE,
59
+ ],
60
+ )
61
+ def python__code__rename(
62
+ context: ExecutionContext,
63
+ app_workdir: ManagedWorkdir,
64
+ source: str,
65
+ target: str,
66
+ kind: str = "package",
67
+ dry_run: bool = False,
68
+ ) -> AbstractResponse:
69
+ from wexample_app.response.failure_response import FailureResponse
70
+ from wexample_app.response.table_response import TableResponse
71
+
72
+ from wexample_wex_addon_dev_python.refactor.python_package_rename_handler import (
73
+ PythonPackageRenameHandler,
74
+ )
75
+ from wexample_wex_addon_dev_python.refactor.symbol_kind import SymbolKind
76
+
77
+ try:
78
+ kind_enum = SymbolKind(kind)
79
+ except ValueError:
80
+ return FailureResponse(
81
+ kernel=context.kernel,
82
+ message=(
83
+ f"Unknown --kind {kind!r}. Valid: "
84
+ f"{', '.join([k.value for k in SymbolKind])}"
85
+ ),
86
+ )
87
+
88
+ if kind_enum is not SymbolKind.PACKAGE:
89
+ return FailureResponse(
90
+ kernel=context.kernel,
91
+ message=(
92
+ f"--kind {kind_enum.value} not implemented yet "
93
+ "(step 1 covers 'package' only)."
94
+ ),
95
+ )
96
+
97
+ workdir_path = app_workdir.get_path()
98
+ handler = PythonPackageRenameHandler(
99
+ workdir_path=workdir_path,
100
+ source=source,
101
+ target=target,
102
+ dry_run=dry_run,
103
+ )
104
+ try:
105
+ report = handler.run()
106
+ except FileNotFoundError:
107
+ return FailureResponse(
108
+ kernel=context.kernel,
109
+ message=(
110
+ f"No Python package matching '{source}' under {workdir_path}. "
111
+ "Check the dotted name (e.g. 'mylib.helpers') and that you're "
112
+ "in the right workdir."
113
+ ),
114
+ )
115
+ except ValueError as e:
116
+ # Raised on ambiguous match (multiple packages) or invalid dotted name.
117
+ return FailureResponse(kernel=context.kernel, message=str(e))
118
+
119
+ mode = "APPLIED" if not dry_run else "DRY-RUN"
120
+ context.io.log(
121
+ f"[{mode}] {report.package_dir_old} → {report.package_dir_new}"
122
+ )
123
+ context.io.log(
124
+ f"[{mode}] scanned={report.files_scanned} changed={len(report.files_changed)}"
125
+ )
126
+
127
+ rows = [
128
+ [str(p.relative_to(workdir_path))] for p in report.files_changed
129
+ ]
130
+ return TableResponse(
131
+ kernel=context.kernel,
132
+ content=rows,
133
+ headers=["File"],
134
+ )
@@ -27,5 +27,4 @@ def python__examples__validate(
27
27
  ExamplePydanticClassWithPublicVarInternallyDefined,
28
28
  )
29
29
 
30
- example_class = ExamplePydanticClassWithPublicVarInternallyDefined()
31
- context.kernel.log(example_class)
30
+ context.kernel.log(ExamplePydanticClassWithPublicVarInternallyDefined())
@@ -1,9 +1,13 @@
1
1
  from __future__ import annotations
2
2
 
3
+ import base64
4
+
3
5
  from wexample_api.common.abstract_gateway import AbstractGateway
4
6
  from wexample_helpers.classes.field import public_field
5
7
  from wexample_helpers.decorator.base_class import base_class
6
8
 
9
+ _HAS_VERSION_STATUS_CODES: tuple[int, ...] = (200, 404)
10
+
7
11
 
8
12
  @base_class
9
13
  class PypiRegistryGateway(AbstractGateway):
@@ -27,8 +31,6 @@ class PypiRegistryGateway(AbstractGateway):
27
31
  def __attrs_post_init__(self) -> None:
28
32
  super().__attrs_post_init__()
29
33
  if self.token:
30
- import base64
31
-
32
34
  credentials = base64.b64encode(
33
35
  f"{self.username or '__token__'}:{self.token}".encode()
34
36
  ).decode()
@@ -43,7 +45,7 @@ class PypiRegistryGateway(AbstractGateway):
43
45
  """
44
46
  response = self.make_request(
45
47
  endpoint=f"simple/{package}/",
46
- expected_status_codes=[200, 404],
48
+ expected_status_codes=_HAS_VERSION_STATUS_CODES,
47
49
  fatal_if_unexpected=False,
48
50
  quiet=True,
49
51
  )
@@ -1,15 +1,10 @@
1
1
  from __future__ import annotations
2
2
 
3
- from typing import TYPE_CHECKING
4
-
5
3
  from wexample_helpers.decorator.base_class import base_class
6
4
  from wexample_wex_addon_app.config_value.app_readme_config_value import (
7
5
  AppReadmeConfigValue,
8
6
  )
9
7
 
10
- if TYPE_CHECKING:
11
- pass
12
-
13
8
 
14
9
  @base_class
15
10
  class PythonPackageReadmeContentConfigValue(AppReadmeConfigValue):
@@ -22,9 +17,8 @@ class PythonPackageReadmeContentConfigValue(AppReadmeConfigValue):
22
17
  def _get_app_homepage(self) -> str:
23
18
  """Extract homepage URL from pyproject.toml."""
24
19
  project = self.workdir.get_app_config()
25
- urls = (
26
- project.get("urls", {}) if isinstance(project.get("urls", {}), dict) else {}
27
- )
20
+ raw_urls = project.get("urls", {})
21
+ urls = raw_urls if isinstance(raw_urls, dict) else {}
28
22
  return urls.get("homepage") or urls.get("Homepage") or ""
29
23
 
30
24
  def _get_project_license(self) -> str | None:
@@ -29,13 +29,14 @@ class PythonAppImlFile(ImlFile):
29
29
  return ({"@type": "sourceFolder", "@forTests": "false"},)
30
30
 
31
31
  def _default_source_folders(self) -> Iterable[dict[str, Any]]:
32
+ base = self.MODULE_DIR_URL
32
33
  return (
33
34
  {
34
- "@url": f"{self.MODULE_DIR_URL}/src",
35
+ "@url": f"{base}/src",
35
36
  "@isTestSource": "false",
36
37
  },
37
38
  {
38
- "@url": f"{self.MODULE_DIR_URL}/tests",
39
+ "@url": f"{base}/tests",
39
40
  "@isTestSource": "true",
40
41
  },
41
42
  )