wexample-wex-addon-dev-python 13.3.1__tar.gz → 15.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.
- {wexample_wex_addon_dev_python-13.3.1 → wexample_wex_addon_dev_python-15.0.0}/PKG-INFO +12 -10
- {wexample_wex_addon_dev_python-13.3.1 → wexample_wex_addon_dev_python-15.0.0}/README.md +8 -6
- {wexample_wex_addon_dev_python-13.3.1 → wexample_wex_addon_dev_python-15.0.0}/pyproject.toml +4 -4
- {wexample_wex_addon_dev_python-13.3.1 → wexample_wex_addon_dev_python-15.0.0}/src/wexample_wex_addon_dev_python/python_addon_manager.py +9 -7
- {wexample_wex_addon_dev_python-13.3.1 → wexample_wex_addon_dev_python-15.0.0}/src/wexample_wex_addon_dev_python/resources/ai/agents/describer/agent.yml +1 -0
- {wexample_wex_addon_dev_python-13.3.1 → wexample_wex_addon_dev_python-15.0.0}/src/wexample_wex_addon_dev_python/resources/ai/agents/describer/context.j2 +9 -6
- {wexample_wex_addon_dev_python-13.3.1 → wexample_wex_addon_dev_python-15.0.0}/src/wexample_wex_addon_dev_python/selection/abstract_python_code_selection.py +2 -4
- wexample_wex_addon_dev_python-15.0.0/src/wexample_wex_addon_dev_python/selection/package_description_missing_selection.py +40 -0
- {wexample_wex_addon_dev_python-13.3.1 → wexample_wex_addon_dev_python-15.0.0}/src/wexample_wex_addon_dev_python/selection/python_code_performance_selection.py +2 -4
- {wexample_wex_addon_dev_python-13.3.1/src/wexample_wex_addon_dev_python/option → wexample_wex_addon_dev_python-15.0.0/src/wexample_wex_addon_dev_python/services}/__init__.py +0 -0
- {wexample_wex_addon_dev_python-13.3.1/src/wexample_wex_addon_dev_python/options_provider → wexample_wex_addon_dev_python-15.0.0/src/wexample_wex_addon_dev_python/services/python}/__init__.py +0 -0
- {wexample_wex_addon_dev_python-13.3.1/src/wexample_wex_addon_dev_python/selection → wexample_wex_addon_dev_python-15.0.0/src/wexample_wex_addon_dev_python/services/python/commands}/__init__.py +0 -0
- {wexample_wex_addon_dev_python-13.3.1 → wexample_wex_addon_dev_python-15.0.0}/src/wexample_wex_addon_dev_python/workdir/python_package_workdir.py +25 -1
- {wexample_wex_addon_dev_python-13.3.1 → wexample_wex_addon_dev_python-15.0.0}/src/wexample_wex_addon_dev_python/workdir/python_workdir.py +0 -10
- {wexample_wex_addon_dev_python-13.3.1/src/wexample_wex_addon_dev_python/workdir → wexample_wex_addon_dev_python-15.0.0/tests/helper}/__init__.py +0 -0
- {wexample_wex_addon_dev_python-13.3.1/src/wexample_wex_addon_dev_python/workdir/__pycache__ → wexample_wex_addon_dev_python-15.0.0/tests/integration}/__init__.py +0 -0
- {wexample_wex_addon_dev_python-13.3.1/src/wexample_wex_addon_dev_python/workdir/mixin → wexample_wex_addon_dev_python-15.0.0/tests/integration/refactor}/__init__.py +0 -0
- wexample_wex_addon_dev_python-15.0.0/tests/unit/workdir/test_python_package_workdir.py +53 -0
- wexample_wex_addon_dev_python-13.3.1/src/wexample_wex_addon_dev_python/operation/generated_description_operation.py +0 -127
- wexample_wex_addon_dev_python-13.3.1/src/wexample_wex_addon_dev_python/option/generated_description_option.py +0 -77
- wexample_wex_addon_dev_python-13.3.1/src/wexample_wex_addon_dev_python/options_provider/generative_options_provider.py +0 -26
- wexample_wex_addon_dev_python-13.3.1/tests/unit/refactor/__init__.py +0 -0
- wexample_wex_addon_dev_python-13.3.1/tests/unit/resources/__init__.py +0 -0
- {wexample_wex_addon_dev_python-13.3.1 → wexample_wex_addon_dev_python-15.0.0}/src/wexample_wex_addon_dev_python/__init__.py +0 -0
- {wexample_wex_addon_dev_python-13.3.1 → wexample_wex_addon_dev_python-15.0.0}/src/wexample_wex_addon_dev_python/__pycache__/__init__.py +0 -0
- {wexample_wex_addon_dev_python-13.3.1 → wexample_wex_addon_dev_python-15.0.0}/src/wexample_wex_addon_dev_python/commands/__init__.py +0 -0
- {wexample_wex_addon_dev_python-13.3.1 → wexample_wex_addon_dev_python-15.0.0}/src/wexample_wex_addon_dev_python/commands/code/__init__.py +0 -0
- {wexample_wex_addon_dev_python-13.3.1 → wexample_wex_addon_dev_python-15.0.0}/src/wexample_wex_addon_dev_python/commands/code/check/__init__.py +0 -0
- {wexample_wex_addon_dev_python-13.3.1 → wexample_wex_addon_dev_python-15.0.0}/src/wexample_wex_addon_dev_python/commands/code/check/mypy.py +0 -0
- {wexample_wex_addon_dev_python-13.3.1 → wexample_wex_addon_dev_python-15.0.0}/src/wexample_wex_addon_dev_python/commands/code/check/pylint.py +0 -0
- {wexample_wex_addon_dev_python-13.3.1 → wexample_wex_addon_dev_python-15.0.0}/src/wexample_wex_addon_dev_python/commands/code/check/pyright.py +0 -0
- {wexample_wex_addon_dev_python-13.3.1 → wexample_wex_addon_dev_python-15.0.0}/src/wexample_wex_addon_dev_python/commands/code/check.py +0 -0
- {wexample_wex_addon_dev_python-13.3.1 → wexample_wex_addon_dev_python-15.0.0}/src/wexample_wex_addon_dev_python/commands/code/format/__init__.py +0 -0
- {wexample_wex_addon_dev_python-13.3.1 → wexample_wex_addon_dev_python-15.0.0}/src/wexample_wex_addon_dev_python/commands/code/format/black.py +0 -0
- {wexample_wex_addon_dev_python-13.3.1 → wexample_wex_addon_dev_python-15.0.0}/src/wexample_wex_addon_dev_python/commands/code/format/isort.py +0 -0
- {wexample_wex_addon_dev_python-13.3.1 → wexample_wex_addon_dev_python-15.0.0}/src/wexample_wex_addon_dev_python/commands/code/format.py +0 -0
- {wexample_wex_addon_dev_python-13.3.1 → wexample_wex_addon_dev_python-15.0.0}/src/wexample_wex_addon_dev_python/commands/code/rename.py +0 -0
- {wexample_wex_addon_dev_python-13.3.1 → wexample_wex_addon_dev_python-15.0.0}/src/wexample_wex_addon_dev_python/commands/examples/__init__.py +0 -0
- {wexample_wex_addon_dev_python-13.3.1 → wexample_wex_addon_dev_python-15.0.0}/src/wexample_wex_addon_dev_python/commands/examples/utils/__init__.py +0 -0
- {wexample_wex_addon_dev_python-13.3.1 → wexample_wex_addon_dev_python-15.0.0}/src/wexample_wex_addon_dev_python/commands/examples/utils/some_example_type.py +0 -0
- {wexample_wex_addon_dev_python-13.3.1 → wexample_wex_addon_dev_python-15.0.0}/src/wexample_wex_addon_dev_python/commands/examples/validate.py +0 -0
- {wexample_wex_addon_dev_python-13.3.1 → wexample_wex_addon_dev_python-15.0.0}/src/wexample_wex_addon_dev_python/commands/release/__init__.py +0 -0
- {wexample_wex_addon_dev_python-13.3.1 → wexample_wex_addon_dev_python-15.0.0}/src/wexample_wex_addon_dev_python/common/__init__.py +0 -0
- {wexample_wex_addon_dev_python-13.3.1 → wexample_wex_addon_dev_python-15.0.0}/src/wexample_wex_addon_dev_python/common/pypi_registry_gateway.py +0 -0
- {wexample_wex_addon_dev_python-13.3.1 → wexample_wex_addon_dev_python-15.0.0}/src/wexample_wex_addon_dev_python/config_value/__init__.py +0 -0
- {wexample_wex_addon_dev_python-13.3.1 → wexample_wex_addon_dev_python-15.0.0}/src/wexample_wex_addon_dev_python/config_value/__pycache__/__init__.py +0 -0
- {wexample_wex_addon_dev_python-13.3.1 → wexample_wex_addon_dev_python-15.0.0}/src/wexample_wex_addon_dev_python/config_value/python_package_readme_config_value.py +0 -0
- {wexample_wex_addon_dev_python-13.3.1 → wexample_wex_addon_dev_python-15.0.0}/src/wexample_wex_addon_dev_python/const/__init__.py +0 -0
- {wexample_wex_addon_dev_python-13.3.1 → wexample_wex_addon_dev_python-15.0.0}/src/wexample_wex_addon_dev_python/const/__pycache__/__init__.py +0 -0
- {wexample_wex_addon_dev_python-13.3.1 → wexample_wex_addon_dev_python-15.0.0}/src/wexample_wex_addon_dev_python/const/package.py +0 -0
- {wexample_wex_addon_dev_python-13.3.1 → wexample_wex_addon_dev_python-15.0.0}/src/wexample_wex_addon_dev_python/const/python.py +0 -0
- {wexample_wex_addon_dev_python-13.3.1 → wexample_wex_addon_dev_python-15.0.0}/src/wexample_wex_addon_dev_python/const/tags.py +0 -0
- {wexample_wex_addon_dev_python-13.3.1 → wexample_wex_addon_dev_python-15.0.0}/src/wexample_wex_addon_dev_python/file/__init__.py +0 -0
- {wexample_wex_addon_dev_python-13.3.1 → wexample_wex_addon_dev_python-15.0.0}/src/wexample_wex_addon_dev_python/file/__pycache__/__init__.py +0 -0
- {wexample_wex_addon_dev_python-13.3.1 → wexample_wex_addon_dev_python-15.0.0}/src/wexample_wex_addon_dev_python/file/python_app_iml_file.py +0 -0
- {wexample_wex_addon_dev_python-13.3.1 → wexample_wex_addon_dev_python-15.0.0}/src/wexample_wex_addon_dev_python/file/python_pyproject_toml_file.py +0 -0
- {wexample_wex_addon_dev_python-13.3.1 → wexample_wex_addon_dev_python-15.0.0}/src/wexample_wex_addon_dev_python/formatter/__init__.py +0 -0
- {wexample_wex_addon_dev_python-13.3.1 → wexample_wex_addon_dev_python-15.0.0}/src/wexample_wex_addon_dev_python/formatter/python_code_formatter.py +0 -0
- {wexample_wex_addon_dev_python-13.3.1 → wexample_wex_addon_dev_python-15.0.0}/src/wexample_wex_addon_dev_python/helper/__init__.py +0 -0
- {wexample_wex_addon_dev_python-13.3.1 → wexample_wex_addon_dev_python-15.0.0}/src/wexample_wex_addon_dev_python/helper/pdm.py +0 -0
- {wexample_wex_addon_dev_python-13.3.1 → wexample_wex_addon_dev_python-15.0.0}/src/wexample_wex_addon_dev_python/middleware/__init__.py +0 -0
- {wexample_wex_addon_dev_python-13.3.1 → wexample_wex_addon_dev_python-15.0.0}/src/wexample_wex_addon_dev_python/middleware/__pycache__/__init__.py +0 -0
- {wexample_wex_addon_dev_python-13.3.1 → wexample_wex_addon_dev_python-15.0.0}/src/wexample_wex_addon_dev_python/middleware/each_python_file_middleware.py +0 -0
- {wexample_wex_addon_dev_python-13.3.1 → wexample_wex_addon_dev_python-15.0.0}/src/wexample_wex_addon_dev_python/py.typed +0 -0
- {wexample_wex_addon_dev_python-13.3.1 → wexample_wex_addon_dev_python-15.0.0}/src/wexample_wex_addon_dev_python/refactor/__init__.py +0 -0
- {wexample_wex_addon_dev_python-13.3.1 → wexample_wex_addon_dev_python-15.0.0}/src/wexample_wex_addon_dev_python/refactor/abstract_python_path_rename_handler.py +0 -0
- {wexample_wex_addon_dev_python-13.3.1 → wexample_wex_addon_dev_python-15.0.0}/src/wexample_wex_addon_dev_python/refactor/abstract_python_rename_handler.py +0 -0
- {wexample_wex_addon_dev_python-13.3.1 → wexample_wex_addon_dev_python-15.0.0}/src/wexample_wex_addon_dev_python/refactor/abstract_python_symbol_rename_handler.py +0 -0
- {wexample_wex_addon_dev_python-13.3.1 → wexample_wex_addon_dev_python-15.0.0}/src/wexample_wex_addon_dev_python/refactor/applier.py +0 -0
- {wexample_wex_addon_dev_python-13.3.1 → wexample_wex_addon_dev_python-15.0.0}/src/wexample_wex_addon_dev_python/refactor/python_class_rename_handler.py +0 -0
- {wexample_wex_addon_dev_python-13.3.1 → wexample_wex_addon_dev_python-15.0.0}/src/wexample_wex_addon_dev_python/refactor/python_common.py +0 -0
- {wexample_wex_addon_dev_python-13.3.1 → wexample_wex_addon_dev_python-15.0.0}/src/wexample_wex_addon_dev_python/refactor/python_constant_rename_handler.py +0 -0
- {wexample_wex_addon_dev_python-13.3.1 → wexample_wex_addon_dev_python-15.0.0}/src/wexample_wex_addon_dev_python/refactor/python_function_rename_handler.py +0 -0
- {wexample_wex_addon_dev_python-13.3.1 → wexample_wex_addon_dev_python-15.0.0}/src/wexample_wex_addon_dev_python/refactor/python_module_rename_handler.py +0 -0
- {wexample_wex_addon_dev_python-13.3.1 → wexample_wex_addon_dev_python-15.0.0}/src/wexample_wex_addon_dev_python/refactor/python_package_rename_handler.py +0 -0
- {wexample_wex_addon_dev_python-13.3.1 → wexample_wex_addon_dev_python-15.0.0}/src/wexample_wex_addon_dev_python/refactor/rename_plan.py +0 -0
- {wexample_wex_addon_dev_python-13.3.1 → wexample_wex_addon_dev_python-15.0.0}/src/wexample_wex_addon_dev_python/refactor/symbol_kind.py +0 -0
- {wexample_wex_addon_dev_python-13.3.1 → wexample_wex_addon_dev_python-15.0.0}/src/wexample_wex_addon_dev_python/resources/.wex.yml +0 -0
- {wexample_wex_addon_dev_python-13.3.1 → wexample_wex_addon_dev_python-15.0.0}/src/wexample_wex_addon_dev_python/resources/design_rules/python_code.md +0 -0
- {wexample_wex_addon_dev_python-13.3.1 → wexample_wex_addon_dev_python-15.0.0}/src/wexample_wex_addon_dev_python/resources/docker/Dockerfile.python-profiling +0 -0
- {wexample_wex_addon_dev_python-13.3.1 → wexample_wex_addon_dev_python-15.0.0}/src/wexample_wex_addon_dev_python/resources/package_publish_gitlab.yml +0 -0
- {wexample_wex_addon_dev_python-13.3.1 → wexample_wex_addon_dev_python-15.0.0}/src/wexample_wex_addon_dev_python/resources/readme_templates/install.md.j2 +0 -0
- {wexample_wex_addon_dev_python-13.3.1 → wexample_wex_addon_dev_python-15.0.0}/src/wexample_wex_addon_dev_python/resources/readme_templates/tests.md.j2 +0 -0
- {wexample_wex_addon_dev_python-13.3.1 → wexample_wex_addon_dev_python-15.0.0}/src/wexample_wex_addon_dev_python/resources/writing_rules/python_code.md +0 -0
- {wexample_wex_addon_dev_python-13.3.1/src/wexample_wex_addon_dev_python/operation → wexample_wex_addon_dev_python-15.0.0/src/wexample_wex_addon_dev_python/selection}/__init__.py +0 -0
- {wexample_wex_addon_dev_python-13.3.1 → wexample_wex_addon_dev_python-15.0.0}/src/wexample_wex_addon_dev_python/services/python/app_service.py +0 -0
- {wexample_wex_addon_dev_python-13.3.1/src/wexample_wex_addon_dev_python/services → wexample_wex_addon_dev_python-15.0.0/src/wexample_wex_addon_dev_python/services/python/commands/service}/__init__.py +0 -0
- {wexample_wex_addon_dev_python-13.3.1 → wexample_wex_addon_dev_python-15.0.0}/src/wexample_wex_addon_dev_python/services/python/commands/service/install.py +0 -0
- {wexample_wex_addon_dev_python-13.3.1 → wexample_wex_addon_dev_python-15.0.0}/src/wexample_wex_addon_dev_python/services/python/commands/service/setup.py +0 -0
- {wexample_wex_addon_dev_python-13.3.1 → wexample_wex_addon_dev_python-15.0.0}/src/wexample_wex_addon_dev_python/services/python/docker/.wex.yml +0 -0
- {wexample_wex_addon_dev_python-13.3.1 → wexample_wex_addon_dev_python-15.0.0}/src/wexample_wex_addon_dev_python/services/python/docker/docker-compose.yml +0 -0
- {wexample_wex_addon_dev_python-13.3.1/src/wexample_wex_addon_dev_python/services/python → wexample_wex_addon_dev_python-15.0.0/src/wexample_wex_addon_dev_python/services/python/samples}/__init__.py +0 -0
- {wexample_wex_addon_dev_python-13.3.1/src/wexample_wex_addon_dev_python/services/python/commands → wexample_wex_addon_dev_python-15.0.0/src/wexample_wex_addon_dev_python/services/python/samples/docker}/__init__.py +0 -0
- {wexample_wex_addon_dev_python-13.3.1 → wexample_wex_addon_dev_python-15.0.0}/src/wexample_wex_addon_dev_python/services/python/samples/docker/docker-compose.yml +0 -0
- {wexample_wex_addon_dev_python-13.3.1 → wexample_wex_addon_dev_python-15.0.0}/src/wexample_wex_addon_dev_python/services/python/samples/docker/entrypoint.sh +0 -0
- {wexample_wex_addon_dev_python-13.3.1 → wexample_wex_addon_dev_python-15.0.0}/src/wexample_wex_addon_dev_python/services/python/samples/docker/images/Dockerfile.base +0 -0
- {wexample_wex_addon_dev_python-13.3.1 → wexample_wex_addon_dev_python-15.0.0}/src/wexample_wex_addon_dev_python/services/python/samples/docker/images/Dockerfile.develop +0 -0
- {wexample_wex_addon_dev_python-13.3.1/src/wexample_wex_addon_dev_python/services/python/commands/service → wexample_wex_addon_dev_python-15.0.0/src/wexample_wex_addon_dev_python/services/python/samples/docker/images}/__init__.py +0 -0
- {wexample_wex_addon_dev_python-13.3.1 → wexample_wex_addon_dev_python-15.0.0}/src/wexample_wex_addon_dev_python/services/python/service.yml +0 -0
- {wexample_wex_addon_dev_python-13.3.1/src/wexample_wex_addon_dev_python/services/python/samples → wexample_wex_addon_dev_python-15.0.0/src/wexample_wex_addon_dev_python/workdir}/__init__.py +0 -0
- {wexample_wex_addon_dev_python-13.3.1/src/wexample_wex_addon_dev_python/services/python/samples/docker → wexample_wex_addon_dev_python-15.0.0/src/wexample_wex_addon_dev_python/workdir/__pycache__}/__init__.py +0 -0
- {wexample_wex_addon_dev_python-13.3.1/src/wexample_wex_addon_dev_python/services/python/samples/docker/images → wexample_wex_addon_dev_python-15.0.0/src/wexample_wex_addon_dev_python/workdir/mixin}/__init__.py +0 -0
- {wexample_wex_addon_dev_python-13.3.1 → wexample_wex_addon_dev_python-15.0.0}/src/wexample_wex_addon_dev_python/workdir/mixin/with_profiling_python_workdir_mixin.py +0 -0
- {wexample_wex_addon_dev_python-13.3.1 → wexample_wex_addon_dev_python-15.0.0}/src/wexample_wex_addon_dev_python/workdir/python_packages_suite_workdir.py +0 -0
- {wexample_wex_addon_dev_python-13.3.1 → wexample_wex_addon_dev_python-15.0.0}/tests/.gitkeep +0 -0
- {wexample_wex_addon_dev_python-13.3.1 → wexample_wex_addon_dev_python-15.0.0}/tests/helper/test_pdm.py +0 -0
- {wexample_wex_addon_dev_python-13.3.1 → wexample_wex_addon_dev_python-15.0.0}/tests/integration/refactor/test_python_class_rename_handler.py +0 -0
- {wexample_wex_addon_dev_python-13.3.1 → wexample_wex_addon_dev_python-15.0.0}/tests/integration/refactor/test_python_constant_rename_handler.py +0 -0
- {wexample_wex_addon_dev_python-13.3.1 → wexample_wex_addon_dev_python-15.0.0}/tests/integration/refactor/test_python_function_rename_handler.py +0 -0
- {wexample_wex_addon_dev_python-13.3.1 → wexample_wex_addon_dev_python-15.0.0}/tests/integration/refactor/test_python_module_rename_handler.py +0 -0
- {wexample_wex_addon_dev_python-13.3.1 → wexample_wex_addon_dev_python-15.0.0}/tests/integration/refactor/test_python_package_rename_handler.py +0 -0
- {wexample_wex_addon_dev_python-13.3.1/tests/helper → wexample_wex_addon_dev_python-15.0.0/tests/unit}/__init__.py +0 -0
- {wexample_wex_addon_dev_python-13.3.1/tests/integration → wexample_wex_addon_dev_python-15.0.0/tests/unit/helper}/__init__.py +0 -0
- {wexample_wex_addon_dev_python-13.3.1 → wexample_wex_addon_dev_python-15.0.0}/tests/unit/helper/test_pdm.py +0 -0
- {wexample_wex_addon_dev_python-13.3.1/tests/integration → wexample_wex_addon_dev_python-15.0.0/tests/unit}/refactor/__init__.py +0 -0
- {wexample_wex_addon_dev_python-13.3.1 → wexample_wex_addon_dev_python-15.0.0}/tests/unit/refactor/test_abstract_python_path_rename_handler.py +0 -0
- {wexample_wex_addon_dev_python-13.3.1 → wexample_wex_addon_dev_python-15.0.0}/tests/unit/refactor/test_abstract_python_rename_handler.py +0 -0
- {wexample_wex_addon_dev_python-13.3.1 → wexample_wex_addon_dev_python-15.0.0}/tests/unit/refactor/test_abstract_python_symbol_rename_handler.py +0 -0
- {wexample_wex_addon_dev_python-13.3.1 → wexample_wex_addon_dev_python-15.0.0}/tests/unit/refactor/test_applier.py +0 -0
- {wexample_wex_addon_dev_python-13.3.1 → wexample_wex_addon_dev_python-15.0.0}/tests/unit/refactor/test_python_class_rename_handler.py +0 -0
- {wexample_wex_addon_dev_python-13.3.1 → wexample_wex_addon_dev_python-15.0.0}/tests/unit/refactor/test_python_common.py +0 -0
- {wexample_wex_addon_dev_python-13.3.1 → wexample_wex_addon_dev_python-15.0.0}/tests/unit/refactor/test_python_constant_rename_handler.py +0 -0
- {wexample_wex_addon_dev_python-13.3.1 → wexample_wex_addon_dev_python-15.0.0}/tests/unit/refactor/test_python_function_rename_handler.py +0 -0
- {wexample_wex_addon_dev_python-13.3.1 → wexample_wex_addon_dev_python-15.0.0}/tests/unit/refactor/test_python_module_rename_handler.py +0 -0
- {wexample_wex_addon_dev_python-13.3.1 → wexample_wex_addon_dev_python-15.0.0}/tests/unit/refactor/test_python_package_rename_handler.py +0 -0
- {wexample_wex_addon_dev_python-13.3.1 → wexample_wex_addon_dev_python-15.0.0}/tests/unit/refactor/test_rename_plan.py +0 -0
- {wexample_wex_addon_dev_python-13.3.1 → wexample_wex_addon_dev_python-15.0.0}/tests/unit/refactor/test_symbol_kind.py +0 -0
- {wexample_wex_addon_dev_python-13.3.1/tests/unit → wexample_wex_addon_dev_python-15.0.0/tests/unit/resources}/__init__.py +0 -0
- {wexample_wex_addon_dev_python-13.3.1 → wexample_wex_addon_dev_python-15.0.0}/tests/unit/resources/test_shipped_agents.py +0 -0
- {wexample_wex_addon_dev_python-13.3.1/tests/unit/helper → wexample_wex_addon_dev_python-15.0.0/tests/unit/workdir}/__init__.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: wexample-wex-addon-dev-python
|
|
3
|
-
Version:
|
|
3
|
+
Version: 15.0.0
|
|
4
4
|
Summary: Extends wex with commands to format, lint, and rename Python symbols, plus workdir types for Python packages and suites
|
|
5
5
|
Author-Email: weeger <contact@wexample.com>
|
|
6
6
|
License: MIT
|
|
@@ -18,9 +18,9 @@ Requires-Dist: networkx
|
|
|
18
18
|
Requires-Dist: pylint
|
|
19
19
|
Requires-Dist: pyright
|
|
20
20
|
Requires-Dist: wexample-api>=6.8.0
|
|
21
|
-
Requires-Dist: wexample-filestate-python>=9.
|
|
22
|
-
Requires-Dist: wexample-wex-addon-ai>=
|
|
23
|
-
Requires-Dist: wexample-wex-addon-app>=
|
|
21
|
+
Requires-Dist: wexample-filestate-python>=9.1.0
|
|
22
|
+
Requires-Dist: wexample-wex-addon-ai>=16.0.0
|
|
23
|
+
Requires-Dist: wexample-wex-addon-app>=32.0.0
|
|
24
24
|
Provides-Extra: dev
|
|
25
25
|
Requires-Dist: pytest; extra == "dev"
|
|
26
26
|
Requires-Dist: pytest-cov; extra == "dev"
|
|
@@ -28,7 +28,7 @@ Description-Content-Type: text/markdown
|
|
|
28
28
|
|
|
29
29
|
# wex_addon_dev_python
|
|
30
30
|
|
|
31
|
-
Version:
|
|
31
|
+
Version: 15.0.0
|
|
32
32
|
|
|
33
33
|
`wex_addon_dev_python` extends the wex CLI with a `python::` command group that formats source files with isort and black (`python::code/format`), checks them with mypy, pylint, and pyright (`python::code/check`), and renames Python symbols — packages, modules, classes, functions, constants — while propagating every affected import statement across the workdir (`python::code/rename`). It also ships `PythonPackageWorkdir` and `PythonPackagesSuiteWorkdir`, two workdir types that let wex manage a single PDM-based package or a multi-package suite as a first-class project structure. The intended users are wex operators who develop and maintain Python packages within the wexample ecosystem.
|
|
34
34
|
|
|
@@ -215,12 +215,14 @@ src/wexample_wex_addon_dev_python/selection/abstract_python_code_selection.py es
|
|
|
215
215
|
|
|
216
216
|
src/wexample_wex_addon_dev_python/selection/python_code_performance_selection.py inherits that baseline and adds two constraints: the file must be under `/src/`, and its AST must contain at least one non-trivial function. Trivial is defined as: `pass`, `...`, docstring-only, `raise NotImplementedError`, a same-name `super()` pass-through, or any `@abstractmethod`.
|
|
217
217
|
|
|
218
|
+
src/wexample_wex_addon_dev_python/selection/package_description_missing_selection.py selects the package's own `.wex/config.yml`, and only when `global.description` is empty. Selecting the config file rather than the package makes the item what is to be edited, so the agent writes that one field and leaves the rest of the file alone. The description is copied verbatim into `pyproject.toml` and shown on the package registry.
|
|
219
|
+
|
|
220
|
+
This replaced a filestate operation that called the agent from inside `apply_operation`. Writing a description is a job given to an agent, not a file state to converge on: rectification retried it every pass, and an agent declining to invent a description for a package with no code kept the hole open, which kept the retry going.
|
|
221
|
+
|
|
218
222
|
### Supporting pieces
|
|
219
223
|
|
|
220
224
|
src/wexample_wex_addon_dev_python/common/pypi_registry_gateway.py is a thin HTTP client over the PEP 503 Simple index. It accepts optional Basic auth (`username` + `token`) and exposes `has_version(package, version) -> bool`.
|
|
221
225
|
|
|
222
|
-
src/wexample_wex_addon_dev_python/operation/generated_description_operation.py is a filestate operation that invokes a `ClaudeAgent` to produce a one-sentence `global.description` and writes it to the app config. The model is called only during `apply_operation`, not during dry-run, so a preview is always offline. Failures (network, model, length over 200 chars) leave the key unset and log a warning rather than aborting the rectification.
|
|
223
|
-
|
|
224
226
|
src/wexample_wex_addon_dev_python/services/python/app_service.py contributes the initial `pyproject.toml` and `src/app/` scaffolding when a new Python app service is set up.
|
|
225
227
|
|
|
226
228
|
src/wexample_wex_addon_dev_python/const/tags.py declares the `DomainTag` constants (`domain:format`, `domain:language-python`, `domain:lint`, `domain:service`) used in command `@command(tags=[…])` decorators.
|
|
@@ -255,9 +257,9 @@ Visit the [Wexample Suite documentation](https://docs.wexample.com) for the comp
|
|
|
255
257
|
- pylint:
|
|
256
258
|
- pyright:
|
|
257
259
|
- wexample-api: >=6.8.0
|
|
258
|
-
- wexample-filestate-python: >=9.
|
|
259
|
-
- wexample-wex-addon-ai: >=
|
|
260
|
-
- wexample-wex-addon-app: >=
|
|
260
|
+
- wexample-filestate-python: >=9.1.0
|
|
261
|
+
- wexample-wex-addon-ai: >=16.0.0
|
|
262
|
+
- wexample-wex-addon-app: >=32.0.0
|
|
261
263
|
|
|
262
264
|
## Versioning & Compatibility Policy
|
|
263
265
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# wex_addon_dev_python
|
|
2
2
|
|
|
3
|
-
Version:
|
|
3
|
+
Version: 15.0.0
|
|
4
4
|
|
|
5
5
|
`wex_addon_dev_python` extends the wex CLI with a `python::` command group that formats source files with isort and black (`python::code/format`), checks them with mypy, pylint, and pyright (`python::code/check`), and renames Python symbols — packages, modules, classes, functions, constants — while propagating every affected import statement across the workdir (`python::code/rename`). It also ships `PythonPackageWorkdir` and `PythonPackagesSuiteWorkdir`, two workdir types that let wex manage a single PDM-based package or a multi-package suite as a first-class project structure. The intended users are wex operators who develop and maintain Python packages within the wexample ecosystem.
|
|
6
6
|
|
|
@@ -187,12 +187,14 @@ src/wexample_wex_addon_dev_python/selection/abstract_python_code_selection.py es
|
|
|
187
187
|
|
|
188
188
|
src/wexample_wex_addon_dev_python/selection/python_code_performance_selection.py inherits that baseline and adds two constraints: the file must be under `/src/`, and its AST must contain at least one non-trivial function. Trivial is defined as: `pass`, `...`, docstring-only, `raise NotImplementedError`, a same-name `super()` pass-through, or any `@abstractmethod`.
|
|
189
189
|
|
|
190
|
+
src/wexample_wex_addon_dev_python/selection/package_description_missing_selection.py selects the package's own `.wex/config.yml`, and only when `global.description` is empty. Selecting the config file rather than the package makes the item what is to be edited, so the agent writes that one field and leaves the rest of the file alone. The description is copied verbatim into `pyproject.toml` and shown on the package registry.
|
|
191
|
+
|
|
192
|
+
This replaced a filestate operation that called the agent from inside `apply_operation`. Writing a description is a job given to an agent, not a file state to converge on: rectification retried it every pass, and an agent declining to invent a description for a package with no code kept the hole open, which kept the retry going.
|
|
193
|
+
|
|
190
194
|
### Supporting pieces
|
|
191
195
|
|
|
192
196
|
src/wexample_wex_addon_dev_python/common/pypi_registry_gateway.py is a thin HTTP client over the PEP 503 Simple index. It accepts optional Basic auth (`username` + `token`) and exposes `has_version(package, version) -> bool`.
|
|
193
197
|
|
|
194
|
-
src/wexample_wex_addon_dev_python/operation/generated_description_operation.py is a filestate operation that invokes a `ClaudeAgent` to produce a one-sentence `global.description` and writes it to the app config. The model is called only during `apply_operation`, not during dry-run, so a preview is always offline. Failures (network, model, length over 200 chars) leave the key unset and log a warning rather than aborting the rectification.
|
|
195
|
-
|
|
196
198
|
src/wexample_wex_addon_dev_python/services/python/app_service.py contributes the initial `pyproject.toml` and `src/app/` scaffolding when a new Python app service is set up.
|
|
197
199
|
|
|
198
200
|
src/wexample_wex_addon_dev_python/const/tags.py declares the `DomainTag` constants (`domain:format`, `domain:language-python`, `domain:lint`, `domain:service`) used in command `@command(tags=[…])` decorators.
|
|
@@ -227,9 +229,9 @@ Visit the [Wexample Suite documentation](https://docs.wexample.com) for the comp
|
|
|
227
229
|
- pylint:
|
|
228
230
|
- pyright:
|
|
229
231
|
- wexample-api: >=6.8.0
|
|
230
|
-
- wexample-filestate-python: >=9.
|
|
231
|
-
- wexample-wex-addon-ai: >=
|
|
232
|
-
- wexample-wex-addon-app: >=
|
|
232
|
+
- wexample-filestate-python: >=9.1.0
|
|
233
|
+
- wexample-wex-addon-ai: >=16.0.0
|
|
234
|
+
- wexample-wex-addon-app: >=32.0.0
|
|
233
235
|
|
|
234
236
|
## Versioning & Compatibility Policy
|
|
235
237
|
|
{wexample_wex_addon_dev_python-13.3.1 → wexample_wex_addon_dev_python-15.0.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 = "
|
|
9
|
+
version = "15.0.0"
|
|
10
10
|
description = "Extends wex with commands to format, lint, and rename Python symbols, plus workdir types for Python packages and suites"
|
|
11
11
|
authors = [
|
|
12
12
|
{ name = "weeger", email = "contact@wexample.com" },
|
|
@@ -27,9 +27,9 @@ dependencies = [
|
|
|
27
27
|
"pylint",
|
|
28
28
|
"pyright",
|
|
29
29
|
"wexample-api>=6.8.0",
|
|
30
|
-
"wexample-filestate-python>=9.
|
|
31
|
-
"wexample-wex-addon-ai>=
|
|
32
|
-
"wexample-wex-addon-app>=
|
|
30
|
+
"wexample-filestate-python>=9.1.0",
|
|
31
|
+
"wexample-wex-addon-ai>=16.0.0",
|
|
32
|
+
"wexample-wex-addon-app>=32.0.0",
|
|
33
33
|
]
|
|
34
34
|
|
|
35
35
|
[project.readme]
|
|
@@ -2,23 +2,22 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
from typing import TYPE_CHECKING
|
|
4
4
|
|
|
5
|
+
from wexample_wex_addon_ai.agent.agent_contributing_addon_mixin import (
|
|
6
|
+
AgentContributingAddonMixin,
|
|
7
|
+
)
|
|
5
8
|
from wexample_wex_addon_ai.formatter.formatter_contributing_addon_mixin import (
|
|
6
9
|
FormatterContributingAddonMixin,
|
|
7
10
|
)
|
|
8
|
-
from wexample_wex_addon_ai.selection.selection_contributing_addon_mixin import (
|
|
9
|
-
SelectionContributingAddonMixin,
|
|
10
|
-
)
|
|
11
11
|
from wexample_wex_core.common.abstract_addon_manager import AbstractAddonManager
|
|
12
12
|
|
|
13
13
|
if TYPE_CHECKING:
|
|
14
14
|
from wexample_cli.middleware.abstract_middleware import AbstractMiddleware
|
|
15
15
|
from wexample_wex_addon_ai.formatter.abstract_formatter import AbstractFormatter
|
|
16
|
-
from wexample_wex_addon_ai.selection.abstract_selection import AbstractSelection
|
|
17
16
|
|
|
18
17
|
|
|
19
18
|
class PythonAddonManager(
|
|
19
|
+
AgentContributingAddonMixin,
|
|
20
20
|
FormatterContributingAddonMixin,
|
|
21
|
-
SelectionContributingAddonMixin,
|
|
22
21
|
AbstractAddonManager,
|
|
23
22
|
):
|
|
24
23
|
def get_formatter_classes(self) -> list[type[AbstractFormatter]]:
|
|
@@ -52,12 +51,15 @@ class PythonAddonManager(
|
|
|
52
51
|
EachPythonFileMiddleware,
|
|
53
52
|
]
|
|
54
53
|
|
|
55
|
-
def
|
|
54
|
+
def get_process_selection_classes(self) -> list[type]:
|
|
55
|
+
from wexample_wex_addon_dev_python.selection.package_description_missing_selection import (
|
|
56
|
+
PackageDescriptionMissingSelection,
|
|
57
|
+
)
|
|
56
58
|
from wexample_wex_addon_dev_python.selection.python_code_performance_selection import (
|
|
57
59
|
PythonCodePerformanceSelection,
|
|
58
60
|
)
|
|
59
61
|
|
|
60
|
-
return [PythonCodePerformanceSelection]
|
|
62
|
+
return [PackageDescriptionMissingSelection, PythonCodePerformanceSelection]
|
|
61
63
|
|
|
62
64
|
def get_workdir_types(self) -> dict[str, type]:
|
|
63
65
|
from wexample_wex_addon_dev_python.workdir.python_package_workdir import (
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
## Domain: describing one Python package in one sentence
|
|
2
2
|
|
|
3
|
-
You are given a package directory. You read it and
|
|
4
|
-
|
|
3
|
+
You are given a package directory. You read it and write a single sentence saying what
|
|
4
|
+
the package is for. That sentence lands in `global.description`, from which it is
|
|
5
5
|
copied verbatim into `pyproject.toml` and shown on the package registry.
|
|
6
6
|
|
|
7
7
|
### Read before you write
|
|
@@ -28,9 +28,12 @@ file tree and rectifies the disk to match it" beats "provides file management ut
|
|
|
28
28
|
|
|
29
29
|
### Answering
|
|
30
30
|
|
|
31
|
-
The
|
|
32
|
-
|
|
31
|
+
The target is the package's `.wex/config.yml`. When you are asked to do the work, set
|
|
32
|
+
`global.description` there to the sentence — that one field, nothing else in the file
|
|
33
|
+
touched — then report it as a change (`described the package`). When you are asked to
|
|
34
|
+
change nothing, report the missing description as a finding (`description_missing`) and
|
|
35
|
+
the sentence you would write as a change.
|
|
33
36
|
|
|
34
37
|
If the package is too empty to describe honestly — no source, no README, nothing but
|
|
35
|
-
scaffolding —
|
|
36
|
-
|
|
38
|
+
scaffolding — write nothing and report it as a finding, code `nothing_to_describe`. The
|
|
39
|
+
field stays for a human. Guessing is the one failure that matters here.
|
|
@@ -2,13 +2,11 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
from typing import ClassVar
|
|
4
4
|
|
|
5
|
-
from
|
|
6
|
-
from wexample_wex_addon_ai.selection.abstract_code_from_directory_selection import (
|
|
5
|
+
from wexample_wex_addon_process.selection.abstract_code_from_directory_selection import (
|
|
7
6
|
AbstractCodeFromDirectorySelection,
|
|
8
7
|
)
|
|
9
8
|
|
|
10
9
|
|
|
11
|
-
@base_class
|
|
12
10
|
class AbstractPythonCodeSelection(AbstractCodeFromDirectorySelection):
|
|
13
11
|
"""Shared base for every Python-source Selection (perf, tests, …).
|
|
14
12
|
|
|
@@ -23,7 +21,7 @@ class AbstractPythonCodeSelection(AbstractCodeFromDirectorySelection):
|
|
|
23
21
|
- 50-byte floor: drops empty stubs (chosen empirically in the shell sweep,
|
|
24
22
|
kept verbatim until we have a reason to change it).
|
|
25
23
|
|
|
26
|
-
Concrete subclasses just pick a `
|
|
24
|
+
Concrete subclasses just pick a `name` and, if needed, extend
|
|
27
25
|
`get_excluded_path_fragments()` / `get_excluded_file_names()` with their
|
|
28
26
|
use-case specifics via `super() + (…)`.
|
|
29
27
|
"""
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING, ClassVar
|
|
4
|
+
|
|
5
|
+
from wexample_wex_addon_process.selection.abstract_process_selection import (
|
|
6
|
+
AbstractProcessSelection,
|
|
7
|
+
)
|
|
8
|
+
|
|
9
|
+
if TYPE_CHECKING:
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class PackageDescriptionMissingSelection(AbstractProcessSelection):
|
|
14
|
+
"""The package's `.wex/config.yml`, when its `global.description` is empty.
|
|
15
|
+
|
|
16
|
+
The description is copied verbatim into `pyproject.toml` and shown on the
|
|
17
|
+
package registry. Selecting the config file itself makes the item what is to be
|
|
18
|
+
edited: the agent writes the one field, and nothing else in the file.
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
label: ClassVar[str] = "Python package without a description"
|
|
22
|
+
name: ClassVar[str] = "package-description-missing"
|
|
23
|
+
|
|
24
|
+
def instructions(self, workdir: Path, item: Path) -> str:
|
|
25
|
+
return (
|
|
26
|
+
f"Package directory: {workdir}\n"
|
|
27
|
+
f"Write the description as `global.description` in this file, and change "
|
|
28
|
+
f"nothing else in it."
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
def items(self, workdir: Path) -> list[Path]:
|
|
32
|
+
import yaml
|
|
33
|
+
from wexample_app.const.globals import WORKDIR_SETUP_DIR
|
|
34
|
+
|
|
35
|
+
config = workdir / WORKDIR_SETUP_DIR / "config.yml"
|
|
36
|
+
if not config.is_file():
|
|
37
|
+
return []
|
|
38
|
+
values = yaml.safe_load(config.read_text(encoding="utf-8")) or {}
|
|
39
|
+
description = (values.get("global") or {}).get("description")
|
|
40
|
+
return [] if description else [config]
|
|
@@ -3,8 +3,6 @@ from __future__ import annotations
|
|
|
3
3
|
import ast
|
|
4
4
|
from typing import TYPE_CHECKING, ClassVar
|
|
5
5
|
|
|
6
|
-
from wexample_helpers.decorator.base_class import base_class
|
|
7
|
-
|
|
8
6
|
from wexample_wex_addon_dev_python.selection.abstract_python_code_selection import (
|
|
9
7
|
AbstractPythonCodeSelection,
|
|
10
8
|
)
|
|
@@ -17,7 +15,6 @@ if TYPE_CHECKING:
|
|
|
17
15
|
_FUNC_TYPES: tuple[type, ...] = (ast.FunctionDef, ast.AsyncFunctionDef)
|
|
18
16
|
|
|
19
17
|
|
|
20
|
-
@base_class
|
|
21
18
|
class PythonCodePerformanceSelection(AbstractPythonCodeSelection):
|
|
22
19
|
"""Python source files candidate for the performance sweep.
|
|
23
20
|
|
|
@@ -27,7 +24,8 @@ class PythonCodePerformanceSelection(AbstractPythonCodeSelection):
|
|
|
27
24
|
`vendor/`), extend the inherited methods via `super() + (…)`.
|
|
28
25
|
"""
|
|
29
26
|
|
|
30
|
-
|
|
27
|
+
label: ClassVar[str] = "Python code worth optimizing"
|
|
28
|
+
name: ClassVar[str] = "python-performance"
|
|
31
29
|
|
|
32
30
|
def get_required_path_fragments(self) -> tuple[str, ...]:
|
|
33
31
|
"""Only library code under `/src/` — the modern Python layout for any
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -27,6 +27,16 @@ if TYPE_CHECKING:
|
|
|
27
27
|
class PythonPackageWorkdir(PythonWorkdir):
|
|
28
28
|
_project_info_cache = None
|
|
29
29
|
|
|
30
|
+
@staticmethod
|
|
31
|
+
def path_belongs_to_tests(package_path: Path, file_path: Path) -> bool:
|
|
32
|
+
"""Whether a file lives under the package's own `tests/` directory.
|
|
33
|
+
|
|
34
|
+
Only that one directory, at the package root. A `testing/` package under `src/`
|
|
35
|
+
is shipped code — other packages import it to build their own suites — and has
|
|
36
|
+
every reason to be judged like the rest.
|
|
37
|
+
"""
|
|
38
|
+
return (package_path / "tests") in file_path.parents
|
|
39
|
+
|
|
30
40
|
def check_publish_prerequisites(self) -> None:
|
|
31
41
|
import shutil
|
|
32
42
|
|
|
@@ -162,6 +172,13 @@ class PythonPackageWorkdir(PythonWorkdir):
|
|
|
162
172
|
- import <pkg>(.<sub>)* [as alias]
|
|
163
173
|
|
|
164
174
|
Returns a list of SearchResult with file, line and column for each match.
|
|
175
|
+
|
|
176
|
+
`tests/` is left out. What this feeds is the runtime dependency graph — what a
|
|
177
|
+
consumer installing the package receives — and the test suite is not part of it:
|
|
178
|
+
setuptools does not ship it and coverage omits it. A package a test imports
|
|
179
|
+
belongs in the `dev` extra, which this graph is right not to know about; judging
|
|
180
|
+
a test import against `project.dependencies` asks a correctly declared package
|
|
181
|
+
to declare it twice, in the wrong place.
|
|
165
182
|
"""
|
|
166
183
|
import re
|
|
167
184
|
|
|
@@ -173,7 +190,14 @@ class PythonPackageWorkdir(PythonWorkdir):
|
|
|
173
190
|
rf"|import\s+{escaped}(?:\.[\w\.]+)?(?:\s+as\s+\w+)?\b"
|
|
174
191
|
rf")"
|
|
175
192
|
)
|
|
176
|
-
|
|
193
|
+
results = self.search_in_codebase(pattern, regex=True, flags=re.MULTILINE)
|
|
194
|
+
package_path = self.get_path()
|
|
195
|
+
|
|
196
|
+
return [
|
|
197
|
+
result
|
|
198
|
+
for result in results
|
|
199
|
+
if not self.path_belongs_to_tests(package_path, result.item.get_path())
|
|
200
|
+
]
|
|
177
201
|
|
|
178
202
|
def search_in_codebase(
|
|
179
203
|
self, string: str, *, regex: bool = False, flags: int = 0
|
|
@@ -118,14 +118,9 @@ class PythonWorkdir(
|
|
|
118
118
|
PythonOptionsProvider,
|
|
119
119
|
)
|
|
120
120
|
|
|
121
|
-
from wexample_wex_addon_dev_python.options_provider.generative_options_provider import (
|
|
122
|
-
GenerativeOptionsProvider,
|
|
123
|
-
)
|
|
124
|
-
|
|
125
121
|
options = super().get_options_providers()
|
|
126
122
|
|
|
127
123
|
options.append(PythonOptionsProvider)
|
|
128
|
-
options.append(GenerativeOptionsProvider)
|
|
129
124
|
|
|
130
125
|
return options
|
|
131
126
|
|
|
@@ -212,16 +207,11 @@ class PythonWorkdir(
|
|
|
212
207
|
from wexample_wex_addon_dev_python.file.python_pyproject_toml_file import (
|
|
213
208
|
PythonPyprojectTomlFile,
|
|
214
209
|
)
|
|
215
|
-
from wexample_wex_addon_dev_python.option.generated_description_option import (
|
|
216
|
-
GeneratedDescriptionOption,
|
|
217
|
-
)
|
|
218
210
|
|
|
219
211
|
raw_value = super().prepare_value(raw_value=raw_value)
|
|
220
212
|
|
|
221
213
|
self.append_agents(config=raw_value)
|
|
222
214
|
|
|
223
|
-
raw_value[GeneratedDescriptionOption.get_name()] = True
|
|
224
|
-
|
|
225
215
|
children = raw_value["children"]
|
|
226
216
|
|
|
227
217
|
self.add_gitignore_rules(
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
import pytest
|
|
6
|
+
|
|
7
|
+
PACKAGE = Path("/suite/packages/storage")
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def _belongs_to_tests(file_path: str) -> bool:
|
|
11
|
+
from wexample_wex_addon_dev_python.workdir.python_package_workdir import (
|
|
12
|
+
PythonPackageWorkdir,
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
return PythonPackageWorkdir.path_belongs_to_tests(PACKAGE, Path(file_path))
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def test_the_suite_that_set_this_off_is_out_of_scope() -> None:
|
|
19
|
+
"""storage's test imports wexample-wallet, declared where it belongs: the dev extra.
|
|
20
|
+
|
|
21
|
+
Judging it against `project.dependencies` asked a correct package to declare the
|
|
22
|
+
same thing twice, once in the wrong place.
|
|
23
|
+
"""
|
|
24
|
+
assert _belongs_to_tests("/suite/packages/storage/tests/test_storage.py")
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
@pytest.mark.parametrize(
|
|
28
|
+
"path",
|
|
29
|
+
[
|
|
30
|
+
"/suite/packages/storage/tests/unit/deep/test_thing.py",
|
|
31
|
+
"/suite/packages/storage/tests/conftest.py",
|
|
32
|
+
],
|
|
33
|
+
)
|
|
34
|
+
def test_anything_under_tests_is_out_of_scope(path: str) -> None:
|
|
35
|
+
assert _belongs_to_tests(path)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
@pytest.mark.parametrize(
|
|
39
|
+
"path",
|
|
40
|
+
[
|
|
41
|
+
"/suite/packages/storage/src/wexample_storage/common/storage.py",
|
|
42
|
+
# Shipped, and imported by other packages to build their own suites.
|
|
43
|
+
"/suite/packages/storage/src/wexample_storage/testing/abstract_test.py",
|
|
44
|
+
"/suite/packages/storage/src/wexample_storage/tests_helper.py",
|
|
45
|
+
],
|
|
46
|
+
)
|
|
47
|
+
def test_shipped_code_stays_in_scope(path: str) -> None:
|
|
48
|
+
assert not _belongs_to_tests(path)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def test_another_package_tests_directory_is_not_ours() -> None:
|
|
52
|
+
"""The check is anchored on this package's root, not on the name `tests`."""
|
|
53
|
+
assert not _belongs_to_tests("/suite/packages/wallet/tests/test_wallet.py")
|
|
@@ -1,127 +0,0 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
from typing import TYPE_CHECKING
|
|
4
|
-
|
|
5
|
-
from wexample_filestate.enum.scopes import Scope
|
|
6
|
-
from wexample_filestate.operation.abstract_operation import AbstractOperation
|
|
7
|
-
from wexample_helpers.classes.mixin.has_package_resources import HasPackageResources
|
|
8
|
-
from wexample_helpers.classes.private_field import private_field
|
|
9
|
-
from wexample_helpers.decorator.base_class import base_class
|
|
10
|
-
|
|
11
|
-
if TYPE_CHECKING:
|
|
12
|
-
from pathlib import Path
|
|
13
|
-
|
|
14
|
-
CONFIG_KEY_SECTION = "global"
|
|
15
|
-
CONFIG_KEY_NAME = "description"
|
|
16
|
-
DESCRIPTION_MAX_LENGTH = 200
|
|
17
|
-
DESCRIPTION_PLACEHOLDER = "<one sentence, written by the describer agent on apply>"
|
|
18
|
-
DESCRIPTION_UNKNOWN = "UNKNOWN"
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
@base_class
|
|
22
|
-
class GeneratedDescriptionOperation(HasPackageResources, AbstractOperation):
|
|
23
|
-
"""Write `global.description` into the app config, asking an agent for the sentence.
|
|
24
|
-
|
|
25
|
-
The model call lives here rather than in the option that builds this operation:
|
|
26
|
-
`FileStateDryRunResult` never calls `apply_operation`, so a preview stays offline and
|
|
27
|
-
free, and shows the placeholder instead of a sentence it would then have to produce a
|
|
28
|
-
second time on apply.
|
|
29
|
-
"""
|
|
30
|
-
|
|
31
|
-
_previous: str | None = private_field(
|
|
32
|
-
default=None,
|
|
33
|
-
description="Value this operation replaced, for `undo`. None when the key was absent.",
|
|
34
|
-
)
|
|
35
|
-
|
|
36
|
-
@classmethod
|
|
37
|
-
def get_scopes(cls) -> list[Scope]:
|
|
38
|
-
return [Scope.CONTENT]
|
|
39
|
-
|
|
40
|
-
def apply_operation(self) -> None:
|
|
41
|
-
description = self._generate()
|
|
42
|
-
if description is None:
|
|
43
|
-
return
|
|
44
|
-
|
|
45
|
-
config_file = self.target.get_config_file()
|
|
46
|
-
content = config_file.read_parsed() or {}
|
|
47
|
-
section = content.setdefault(CONFIG_KEY_SECTION, {})
|
|
48
|
-
|
|
49
|
-
self._previous = section.get(CONFIG_KEY_NAME)
|
|
50
|
-
section[CONFIG_KEY_NAME] = description
|
|
51
|
-
config_file.write_parsed(content)
|
|
52
|
-
|
|
53
|
-
self.target.success(f"Description: {description}")
|
|
54
|
-
|
|
55
|
-
def undo(self) -> None:
|
|
56
|
-
config_file = self.target.get_config_file()
|
|
57
|
-
content = config_file.read_parsed() or {}
|
|
58
|
-
section = content.get(CONFIG_KEY_SECTION)
|
|
59
|
-
if not isinstance(section, dict):
|
|
60
|
-
return
|
|
61
|
-
|
|
62
|
-
if self._previous is None:
|
|
63
|
-
section.pop(CONFIG_KEY_NAME, None)
|
|
64
|
-
else:
|
|
65
|
-
section[CONFIG_KEY_NAME] = self._previous
|
|
66
|
-
config_file.write_parsed(content)
|
|
67
|
-
|
|
68
|
-
def _agent_config_path(self) -> Path:
|
|
69
|
-
return self.get_resource_path("ai", "agents", "describer", "agent.yml")
|
|
70
|
-
|
|
71
|
-
def _generate(self) -> str | None:
|
|
72
|
-
"""The sentence, or None when nothing should be written.
|
|
73
|
-
|
|
74
|
-
Every failure mode lands on None: the hole stays, the pass reports it and moves on.
|
|
75
|
-
A rectification must not fail because a model was unreachable.
|
|
76
|
-
"""
|
|
77
|
-
from wexample_wex_addon_ai.agent.claude_agent import ClaudeAgent
|
|
78
|
-
from wexample_wex_addon_ai.file.agent_yaml_file import AgentYamlFile
|
|
79
|
-
|
|
80
|
-
try:
|
|
81
|
-
agent = ClaudeAgent(
|
|
82
|
-
io=self.target.io,
|
|
83
|
-
app_workdir=self.target,
|
|
84
|
-
config_file=AgentYamlFile.create_from_path(
|
|
85
|
-
path=self._agent_config_path()
|
|
86
|
-
),
|
|
87
|
-
)
|
|
88
|
-
sentence = agent.run_value_draft(self._prompt())
|
|
89
|
-
except Exception as exception:
|
|
90
|
-
self.target.warning(
|
|
91
|
-
f"Could not generate a description: {exception}. "
|
|
92
|
-
f"Leaving {CONFIG_KEY_SECTION}.{CONFIG_KEY_NAME} unset."
|
|
93
|
-
)
|
|
94
|
-
return None
|
|
95
|
-
|
|
96
|
-
return self._validate(sentence)
|
|
97
|
-
|
|
98
|
-
def _prompt(self) -> str:
|
|
99
|
-
return (
|
|
100
|
-
f"Package directory: {self.target.get_path()}\n"
|
|
101
|
-
f"Package name: {self.target.get_package_name()}\n"
|
|
102
|
-
f"\n"
|
|
103
|
-
f"Read the package and report its one-sentence description."
|
|
104
|
-
)
|
|
105
|
-
|
|
106
|
-
def _validate(self, sentence: str | None) -> str | None:
|
|
107
|
-
"""Guard the one shape that would still poison a config file: a runaway sentence.
|
|
108
|
-
|
|
109
|
-
`report_value` already delimits the answer, so nothing has to be extracted from the
|
|
110
|
-
agent's prose — a missing report is simply `None`.
|
|
111
|
-
"""
|
|
112
|
-
if sentence is None:
|
|
113
|
-
self.target.warning(
|
|
114
|
-
f"The describer reported nothing — "
|
|
115
|
-
f"leaving {CONFIG_KEY_SECTION}.{CONFIG_KEY_NAME} unset."
|
|
116
|
-
)
|
|
117
|
-
return None
|
|
118
|
-
|
|
119
|
-
if len(sentence) > DESCRIPTION_MAX_LENGTH:
|
|
120
|
-
self.target.warning(
|
|
121
|
-
f"The describer answered {len(sentence)} characters, over the "
|
|
122
|
-
f"{DESCRIPTION_MAX_LENGTH} allowed — leaving "
|
|
123
|
-
f"{CONFIG_KEY_SECTION}.{CONFIG_KEY_NAME} unset."
|
|
124
|
-
)
|
|
125
|
-
return None
|
|
126
|
-
|
|
127
|
-
return sentence
|
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
from collections.abc import Callable
|
|
4
|
-
from typing import TYPE_CHECKING, Any, Union
|
|
5
|
-
|
|
6
|
-
from wexample_config.config_option.abstract_config_option import AbstractConfigOption
|
|
7
|
-
from wexample_filestate.enum.scopes import Scope
|
|
8
|
-
from wexample_filestate.option.mixin.option_mixin import OptionMixin
|
|
9
|
-
from wexample_helpers.decorator.base_class import base_class
|
|
10
|
-
|
|
11
|
-
if TYPE_CHECKING:
|
|
12
|
-
from wexample_filestate.const.types_state_items import TargetFileOrDirectoryType
|
|
13
|
-
from wexample_filestate.operation.abstract_operation import AbstractOperation
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
@base_class
|
|
17
|
-
class GeneratedDescriptionOption(OptionMixin, AbstractConfigOption):
|
|
18
|
-
"""Ask an agent for `global.description` when the app config has none.
|
|
19
|
-
|
|
20
|
-
Only ever fills a hole: a description already written — by a human or by an earlier
|
|
21
|
-
run — is left alone, which is what makes the option convergent. It fires once per
|
|
22
|
-
package, then never again. To have one rewritten, clear the key.
|
|
23
|
-
|
|
24
|
-
Declared on the workdir, not on `pyproject.toml`: the toml's `description` is already
|
|
25
|
-
derived from this key by `PythonPyprojectTomlFile._enforce_project_metadata`, so
|
|
26
|
-
filling the config is enough for the value to reach the manifest through the ordinary
|
|
27
|
-
deterministic path.
|
|
28
|
-
"""
|
|
29
|
-
|
|
30
|
-
@classmethod
|
|
31
|
-
def get_scopes(cls) -> list[Scope]:
|
|
32
|
-
return [Scope.CONTENT]
|
|
33
|
-
|
|
34
|
-
@staticmethod
|
|
35
|
-
def get_raw_value_allowed_type() -> Any:
|
|
36
|
-
return Union[bool, Callable]
|
|
37
|
-
|
|
38
|
-
def applicable_on_file(self) -> bool:
|
|
39
|
-
return False
|
|
40
|
-
|
|
41
|
-
def applicable_on_missing(self) -> bool:
|
|
42
|
-
return False
|
|
43
|
-
|
|
44
|
-
def create_required_operation(
|
|
45
|
-
self, target: TargetFileOrDirectoryType, scopes: set[Scope]
|
|
46
|
-
) -> AbstractOperation | None:
|
|
47
|
-
from wexample_wex_addon_dev_python.operation.generated_description_operation import (
|
|
48
|
-
CONFIG_KEY_NAME,
|
|
49
|
-
CONFIG_KEY_SECTION,
|
|
50
|
-
DESCRIPTION_PLACEHOLDER,
|
|
51
|
-
GeneratedDescriptionOperation,
|
|
52
|
-
)
|
|
53
|
-
|
|
54
|
-
value = self.get_value()
|
|
55
|
-
raw = value.raw if value is not None else None
|
|
56
|
-
if callable(raw):
|
|
57
|
-
raw = raw(target)
|
|
58
|
-
if not bool(raw):
|
|
59
|
-
return None
|
|
60
|
-
|
|
61
|
-
existing = target.get_config().search(
|
|
62
|
-
f"{CONFIG_KEY_SECTION}.{CONFIG_KEY_NAME}"
|
|
63
|
-
)
|
|
64
|
-
if not existing.is_none() and existing.get_str().strip():
|
|
65
|
-
return None
|
|
66
|
-
|
|
67
|
-
return GeneratedDescriptionOperation(
|
|
68
|
-
option=self,
|
|
69
|
-
target=target,
|
|
70
|
-
description=(
|
|
71
|
-
f"Write {CONFIG_KEY_SECTION}.{CONFIG_KEY_NAME}: "
|
|
72
|
-
f"{DESCRIPTION_PLACEHOLDER}"
|
|
73
|
-
),
|
|
74
|
-
)
|
|
75
|
-
|
|
76
|
-
def get_description(self) -> str:
|
|
77
|
-
return "Have an agent write the app description when none is set"
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
from typing import TYPE_CHECKING
|
|
4
|
-
|
|
5
|
-
from wexample_config.options_provider.abstract_options_provider import (
|
|
6
|
-
AbstractOptionsProvider,
|
|
7
|
-
)
|
|
8
|
-
|
|
9
|
-
if TYPE_CHECKING:
|
|
10
|
-
from wexample_config.config_option.abstract_config_option import (
|
|
11
|
-
AbstractConfigOption,
|
|
12
|
-
)
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
class GenerativeOptionsProvider(AbstractOptionsProvider):
|
|
16
|
-
@classmethod
|
|
17
|
-
def get_options(cls) -> list[type[AbstractConfigOption]]:
|
|
18
|
-
if "_options_cache" not in cls.__dict__:
|
|
19
|
-
from wexample_wex_addon_dev_python.option.generated_description_option import (
|
|
20
|
-
GeneratedDescriptionOption,
|
|
21
|
-
)
|
|
22
|
-
|
|
23
|
-
cls._options_cache: list[type[AbstractConfigOption]] = [
|
|
24
|
-
GeneratedDescriptionOption
|
|
25
|
-
]
|
|
26
|
-
return cls._options_cache
|
|
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
|
|
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
|
{wexample_wex_addon_dev_python-13.3.1 → wexample_wex_addon_dev_python-15.0.0}/tests/.gitkeep
RENAMED
|
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
|