porringer 0.2.1.dev88__tar.gz → 0.2.1.dev89__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.
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/PKG-INFO +3 -3
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/core/plugin_schema/tool_based.py +14 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/plugin/pip/plugin.py +34 -3
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/test/pytest/tests.py +73 -2
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/pyproject.toml +8 -7
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/tests/conftest.py +29 -0
- porringer-0.2.1.dev89/tests/integration/test_bare_environment.py +49 -0
- porringer-0.2.1.dev89/tests/unit/plugins/pip/conftest.py +7 -0
- porringer-0.2.1.dev89/tests/unit/plugins/pip/test_auxiliary_tools.py +96 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/tests/unit/test_backend_resolver.py +2 -2
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/LICENSE.md +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/README.md +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/__init__.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/api.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/backend/__init__.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/backend/backend.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/backend/builder.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/backend/cache.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/backend/command/__init__.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/backend/command/core/__init__.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/backend/command/core/action_builder.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/backend/command/core/discovery.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/backend/command/core/execution.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/backend/command/core/phase.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/backend/command/core/presence.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/backend/command/core/resolution.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/backend/command/core/wsl_overlay.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/backend/command/manifest.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/backend/command/package.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/backend/command/plugin.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/backend/command/self.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/backend/command/sync.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/backend/resolver.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/backend/schema.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/console/__init__.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/console/command/__init__.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/console/command/cache.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/console/command/check.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/console/command/download.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/console/command/package.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/console/command/plugin.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/console/command/schema.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/console/command/self.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/console/command/sync.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/console/entry.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/console/schema.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/core/__init__.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/core/path.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/core/plugin_schema/__init__.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/core/plugin_schema/environment.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/core/plugin_schema/manifest.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/core/plugin_schema/plugin_manager.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/core/plugin_schema/project_environment.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/core/plugin_schema/python_environment.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/core/plugin_schema/runtime.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/core/plugin_schema/scm.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/core/schema.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/core/transport.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/plugin/__init__.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/plugin/apt/__init__.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/plugin/apt/plugin.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/plugin/brew/__init__.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/plugin/brew/plugin.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/plugin/bun/__init__.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/plugin/bun/plugin.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/plugin/bun_project/__init__.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/plugin/bun_project/plugin.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/plugin/deno/__init__.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/plugin/deno/plugin.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/plugin/deno_project/__init__.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/plugin/deno_project/plugin.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/plugin/git/__init__.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/plugin/git/plugin.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/plugin/npm/__init__.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/plugin/npm/plugin.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/plugin/npm_project/__init__.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/plugin/npm_project/plugin.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/plugin/pdm/__init__.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/plugin/pdm/plugin.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/plugin/pim/__init__.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/plugin/pim/plugin.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/plugin/pip/__init__.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/plugin/pipx/__init__.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/plugin/pipx/plugin.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/plugin/pnpm/__init__.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/plugin/pnpm/plugin.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/plugin/pnpm_project/__init__.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/plugin/pnpm_project/plugin.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/plugin/poetry/__init__.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/plugin/poetry/plugin.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/plugin/pyenv/__init__.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/plugin/pyenv/plugin.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/plugin/uv/__init__.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/plugin/uv/plugin.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/plugin/uv_project/__init__.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/plugin/uv_project/plugin.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/plugin/winget/__init__.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/plugin/winget/plugin.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/plugin/wsl/__init__.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/plugin/wsl/transport.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/plugin/wsl/utility.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/plugin/yarn_project/__init__.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/plugin/yarn_project/plugin.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/py.typed +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/schema/__init__.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/schema/cache.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/schema/check.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/schema/config.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/schema/download.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/schema/execution.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/schema/manifest.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/schema/plugin.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/schema/progress.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/test/mock/__init__.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/test/mock/environment.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/test/mock/plugin_manager.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/test/mock/project_environment.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/test/mock/scm.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/test/mock/subprocess.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/test/pytest/__init__.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/test/pytest/plugin.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/test/pytest/shared.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/test/pytest/variants.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/utility/__init__.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/utility/download.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/utility/exception.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/utility/py.typed +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/utility/utility.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/tests/__init__.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/tests/fixtures/__init__.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/tests/fixtures/api.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/tests/fixtures/http.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/tests/fixtures/manifests.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/tests/fixtures/mock_plugins.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/tests/fixtures/packages.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/tests/integration/__init__.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/tests/integration/plugins/__init__.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/tests/integration/plugins/git/__init__.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/tests/integration/plugins/git/test_scm.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/tests/integration/plugins/pip/__init__.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/tests/integration/plugins/pip/test_environment.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/tests/integration/plugins/pipx/__init__.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/tests/integration/plugins/pipx/test_environment.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/tests/integration/plugins/winget/__init__.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/tests/integration/plugins/winget/test_environment.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/tests/integration/test_bootstrap_presence.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/tests/integration/test_example_bootstrap.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/tests/integration/test_example_presence.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/tests/integration/test_frozen_app_presence.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/tests/unit/__init__.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/tests/unit/plugins/__init__.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/tests/unit/plugins/apt/__init__.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/tests/unit/plugins/apt/test_environment.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/tests/unit/plugins/brew/__init__.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/tests/unit/plugins/brew/test_environment.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/tests/unit/plugins/bun/__init__.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/tests/unit/plugins/bun/test_environment.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/tests/unit/plugins/bun_project/__init__.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/tests/unit/plugins/bun_project/test_environment.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/tests/unit/plugins/deno/__init__.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/tests/unit/plugins/deno/test_environment.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/tests/unit/plugins/deno_project/__init__.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/tests/unit/plugins/deno_project/test_environment.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/tests/unit/plugins/git/__init__.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/tests/unit/plugins/git/test_clone_detection.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/tests/unit/plugins/git/test_scm.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/tests/unit/plugins/npm/__init__.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/tests/unit/plugins/npm/test_environment.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/tests/unit/plugins/npm_project/__init__.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/tests/unit/plugins/npm_project/test_environment.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/tests/unit/plugins/pdm/__init__.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/tests/unit/plugins/pdm/test_environment.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/tests/unit/plugins/pim/__init__.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/tests/unit/plugins/pim/test_environment.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/tests/unit/plugins/pip/__init__.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/tests/unit/plugins/pip/test_environment.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/tests/unit/plugins/pipx/__init__.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/tests/unit/plugins/pipx/test_environment.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/tests/unit/plugins/pnpm/__init__.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/tests/unit/plugins/pnpm/test_environment.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/tests/unit/plugins/pnpm_project/__init__.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/tests/unit/plugins/pnpm_project/test_environment.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/tests/unit/plugins/poetry/__init__.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/tests/unit/plugins/poetry/test_environment.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/tests/unit/plugins/pyenv/__init__.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/tests/unit/plugins/pyenv/test_environment.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/tests/unit/plugins/uv/__init__.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/tests/unit/plugins/uv/test_environment.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/tests/unit/plugins/uv_project/__init__.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/tests/unit/plugins/uv_project/test_environment.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/tests/unit/plugins/yarn_project/__init__.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/tests/unit/plugins/yarn_project/test_environment.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/tests/unit/test_bootstrap_cross_platform.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/tests/unit/test_cache.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/tests/unit/test_check.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/tests/unit/test_check_updates.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/tests/unit/test_cli.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/tests/unit/test_command_plugin.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/tests/unit/test_command_self.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/tests/unit/test_concurrency_and_client.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/tests/unit/test_deferred_resolution.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/tests/unit/test_event_loop_safety.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/tests/unit/test_extras_introspection.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/tests/unit/test_frozen_app_detection.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/tests/unit/test_frozen_presence_resolution.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/tests/unit/test_manifest.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/tests/unit/test_package_filtering.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/tests/unit/test_package_ref.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/tests/unit/test_package_relation.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/tests/unit/test_path_sync.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/tests/unit/test_plugin_filtering.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/tests/unit/test_plugin_manager.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/tests/unit/test_presence_detection.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/tests/unit/test_project_directory.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/tests/unit/test_project_root.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/tests/unit/test_runtime_context_seeding.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/tests/unit/test_runtime_propagation.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/tests/unit/test_runtime_updates.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/tests/unit/test_sub_action_progress.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/tests/unit/test_uninstall.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/tests/unit/test_update_detection.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/tests/unit/test_upgrade.py +0 -0
- {porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/tests/unit/test_wsl.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: porringer
|
|
3
|
-
Version: 0.2.1.
|
|
3
|
+
Version: 0.2.1.dev89
|
|
4
4
|
Author-Email: Synodic Software <contact@synodic.software>
|
|
5
5
|
License: MIT
|
|
6
6
|
Project-URL: homepage, https://github.com/synodic/porringer
|
|
@@ -8,10 +8,10 @@ Project-URL: repository, https://github.com/synodic/porringer
|
|
|
8
8
|
Requires-Python: >=3.14
|
|
9
9
|
Requires-Dist: typer[all]>=0.24.1
|
|
10
10
|
Requires-Dist: pydantic>=2.12.5
|
|
11
|
-
Requires-Dist: platformdirs>=4.9.
|
|
11
|
+
Requires-Dist: platformdirs>=4.9.6
|
|
12
12
|
Requires-Dist: userpath>=1.9.2
|
|
13
13
|
Requires-Dist: packaging>=26.0
|
|
14
|
-
Requires-Dist: aiohttp>=3.13.
|
|
14
|
+
Requires-Dist: aiohttp>=3.13.5
|
|
15
15
|
Description-Content-Type: text/markdown
|
|
16
16
|
|
|
17
17
|
<p align="center">
|
|
@@ -19,6 +19,7 @@ import logging
|
|
|
19
19
|
import re
|
|
20
20
|
import shutil
|
|
21
21
|
import subprocess
|
|
22
|
+
from collections.abc import Sequence
|
|
22
23
|
from pathlib import Path
|
|
23
24
|
from typing import Any, Self
|
|
24
25
|
|
|
@@ -39,6 +40,19 @@ class ToolBasedPlugin(Plugin):
|
|
|
39
40
|
considered available.
|
|
40
41
|
"""
|
|
41
42
|
|
|
43
|
+
@classmethod
|
|
44
|
+
def auxiliary_tools(cls) -> Sequence[str]:
|
|
45
|
+
"""Return optional CLI tools that may be invoked as post-action side effects.
|
|
46
|
+
|
|
47
|
+
Override to declare tools the plugin calls via ``shutil.which``
|
|
48
|
+
outside its primary ``tool_name()``. The test framework uses
|
|
49
|
+
this to verify that the plugin tolerates each tool being absent.
|
|
50
|
+
|
|
51
|
+
Returns:
|
|
52
|
+
Tool names (empty by default).
|
|
53
|
+
"""
|
|
54
|
+
return ()
|
|
55
|
+
|
|
42
56
|
def with_transport(self, transport: Transport) -> Self:
|
|
43
57
|
"""Create a new instance of this plugin using a different transport."""
|
|
44
58
|
parameters = PluginParameters(distribution=self._distribution, transport=transport)
|
|
@@ -5,7 +5,7 @@ import json
|
|
|
5
5
|
import logging
|
|
6
6
|
import re
|
|
7
7
|
import shutil
|
|
8
|
-
from collections.abc import Callable
|
|
8
|
+
from collections.abc import Callable, Sequence
|
|
9
9
|
from pathlib import Path
|
|
10
10
|
from typing import override
|
|
11
11
|
|
|
@@ -44,6 +44,12 @@ class PIPEnvironment(PythonEnvironment):
|
|
|
44
44
|
the underlying Python installation.
|
|
45
45
|
"""
|
|
46
46
|
|
|
47
|
+
@classmethod
|
|
48
|
+
@override
|
|
49
|
+
def auxiliary_tools(cls) -> Sequence[str]:
|
|
50
|
+
"""Pip may invoke ``pymanager`` to refresh global aliases."""
|
|
51
|
+
return ('pymanager',)
|
|
52
|
+
|
|
47
53
|
@classmethod
|
|
48
54
|
@override
|
|
49
55
|
def tool_name(cls) -> str:
|
|
@@ -127,6 +133,10 @@ class PIPEnvironment(PythonEnvironment):
|
|
|
127
133
|
When a progress_callback is provided, streams stderr line-by-line to
|
|
128
134
|
report download and install phases. Otherwise falls back to the simple
|
|
129
135
|
`run_command` path for zero overhead.
|
|
136
|
+
|
|
137
|
+
On Windows, if the Python Install Manager (pymanager) is available,
|
|
138
|
+
runs ``pymanager install --refresh`` after a successful install to
|
|
139
|
+
regenerate global aliases for newly installed entry points.
|
|
130
140
|
"""
|
|
131
141
|
logger = logging.getLogger('porringer.pip.install')
|
|
132
142
|
args = list(
|
|
@@ -139,9 +149,30 @@ class PIPEnvironment(PythonEnvironment):
|
|
|
139
149
|
|
|
140
150
|
if params.progress_callback is None:
|
|
141
151
|
# Fast path — no streaming needed
|
|
142
|
-
|
|
152
|
+
result = await self._install_simple(args, params.package, logger)
|
|
153
|
+
else:
|
|
154
|
+
result = await self._install_with_progress(args, params, logger)
|
|
143
155
|
|
|
144
|
-
|
|
156
|
+
if not params.dry:
|
|
157
|
+
await self._refresh_pymanager_aliases(logger)
|
|
158
|
+
|
|
159
|
+
return result
|
|
160
|
+
|
|
161
|
+
@staticmethod
|
|
162
|
+
async def _refresh_pymanager_aliases(logger: logging.Logger) -> None:
|
|
163
|
+
"""Best-effort refresh of pymanager global aliases after pip install.
|
|
164
|
+
|
|
165
|
+
No-op when pymanager is absent. Failures never block the install.
|
|
166
|
+
"""
|
|
167
|
+
if shutil.which('pymanager') is None:
|
|
168
|
+
return
|
|
169
|
+
|
|
170
|
+
try:
|
|
171
|
+
result = await run_command(['pymanager', 'install', '--refresh'])
|
|
172
|
+
if result.returncode != 0:
|
|
173
|
+
logger.warning('pymanager install --refresh exited with code %d', result.returncode)
|
|
174
|
+
except Exception as exc:
|
|
175
|
+
logger.warning('Failed to refresh pymanager aliases: %s', exc)
|
|
145
176
|
|
|
146
177
|
@staticmethod
|
|
147
178
|
async def _install_simple(args: list[str], package: PackageRef, logger: logging.Logger) -> Package | None:
|
|
@@ -1,15 +1,19 @@
|
|
|
1
1
|
"""Implementation of tests that should be overridden in plugins"""
|
|
2
2
|
|
|
3
3
|
import shutil
|
|
4
|
-
from abc import ABCMeta
|
|
4
|
+
from abc import ABCMeta, abstractmethod
|
|
5
|
+
from collections.abc import Generator
|
|
6
|
+
from typing import NamedTuple
|
|
7
|
+
from unittest.mock import AsyncMock
|
|
5
8
|
|
|
6
9
|
from packaging.version import Version
|
|
7
10
|
|
|
8
11
|
import pytest
|
|
9
|
-
from porringer.core.plugin_schema.environment import Environment
|
|
12
|
+
from porringer.core.plugin_schema.environment import Environment, PackageParameters
|
|
10
13
|
from porringer.core.plugin_schema.project_environment import ProjectEnvironment
|
|
11
14
|
from porringer.core.plugin_schema.runtime import RuntimeProvider
|
|
12
15
|
from porringer.core.plugin_schema.scm import ScmEnvironment
|
|
16
|
+
from porringer.core.plugin_schema.tool_based import ToolBasedPlugin
|
|
13
17
|
from porringer.core.schema import Distribution, PackageRef, PluginParameters
|
|
14
18
|
from porringer.test.pytest.shared import (
|
|
15
19
|
EnvironmentTests,
|
|
@@ -183,3 +187,70 @@ class RuntimeProviderUnitTests[T: Environment](EnvironmentUnitTests[T], RuntimeP
|
|
|
183
187
|
kind = plugin_type.provided_runtime_kind()
|
|
184
188
|
assert isinstance(kind, str)
|
|
185
189
|
assert len(kind) > 0
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
class InstallContext(NamedTuple):
|
|
193
|
+
"""Context returned by the ``install_context`` fixture."""
|
|
194
|
+
|
|
195
|
+
plugin: Environment
|
|
196
|
+
params: PackageParameters
|
|
197
|
+
mock_run: AsyncMock
|
|
198
|
+
scenario: str
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
class AuxiliaryToolTests[T: ToolBasedPlugin](metaclass=ABCMeta):
|
|
202
|
+
"""Mixin that tests auxiliary-tool interactions declared via ``_auxiliary_tools``.
|
|
203
|
+
|
|
204
|
+
Concrete test classes must provide:
|
|
205
|
+
|
|
206
|
+
* ``fixture_install_context`` — a fixture yielding an
|
|
207
|
+
:class:`InstallContext` whose ``scenario`` field indicates which
|
|
208
|
+
auxiliary-tool configuration is active.
|
|
209
|
+
|
|
210
|
+
Expected scenarios (the fixture should be parametrized over these):
|
|
211
|
+
|
|
212
|
+
* ``"tools_absent"`` — ``shutil.which`` returns ``None`` for
|
|
213
|
+
auxiliary tools; ``run_command`` is not expected to be called
|
|
214
|
+
for them.
|
|
215
|
+
* ``"tools_present"`` — ``shutil.which`` returns a fake path;
|
|
216
|
+
``run_command`` mock returns success.
|
|
217
|
+
* ``"tools_fail_exception"`` — ``shutil.which`` returns a fake
|
|
218
|
+
path; ``run_command`` raises ``OSError`` for auxiliary tools.
|
|
219
|
+
* ``"tools_fail_nonzero"`` — ``shutil.which`` returns a fake path;
|
|
220
|
+
``run_command`` returns non-zero for auxiliary tools.
|
|
221
|
+
|
|
222
|
+
The mixin is intentionally separate from ``EnvironmentUnitTests`` so
|
|
223
|
+
that plugins without auxiliary tools don't inherit meaningless tests.
|
|
224
|
+
"""
|
|
225
|
+
|
|
226
|
+
@abstractmethod
|
|
227
|
+
@pytest.fixture(name='install_context')
|
|
228
|
+
def fixture_install_context(self) -> Generator[InstallContext]:
|
|
229
|
+
"""Yield an ``InstallContext`` with install internals mocked."""
|
|
230
|
+
raise NotImplementedError('Override this fixture')
|
|
231
|
+
|
|
232
|
+
@staticmethod
|
|
233
|
+
async def test_install_succeeds(install_context: InstallContext) -> None:
|
|
234
|
+
"""install() succeeds regardless of auxiliary tool availability."""
|
|
235
|
+
plugin, params, _mock_run, _scenario = install_context
|
|
236
|
+
result = await plugin.install(params)
|
|
237
|
+
# Install should never fail due to auxiliary tool issues
|
|
238
|
+
assert result is not None
|
|
239
|
+
|
|
240
|
+
@staticmethod
|
|
241
|
+
async def test_auxiliary_tools_called_only_when_present(
|
|
242
|
+
install_context: InstallContext,
|
|
243
|
+
) -> None:
|
|
244
|
+
"""Auxiliary tools are invoked when present, skipped when absent."""
|
|
245
|
+
plugin, params, mock_run, scenario = install_context
|
|
246
|
+
aux = type(plugin).auxiliary_tools()
|
|
247
|
+
if not aux:
|
|
248
|
+
pytest.skip('No auxiliary tools declared')
|
|
249
|
+
|
|
250
|
+
await plugin.install(params)
|
|
251
|
+
|
|
252
|
+
called_args = [str(c) for c in mock_run.call_args_list]
|
|
253
|
+
if scenario == 'tools_absent':
|
|
254
|
+
assert not any(tool in arg for arg in called_args for tool in aux)
|
|
255
|
+
else:
|
|
256
|
+
assert any(tool in arg for arg in called_args for tool in aux)
|
|
@@ -10,12 +10,12 @@ requires-python = ">=3.14"
|
|
|
10
10
|
dependencies = [
|
|
11
11
|
"typer[all]>=0.24.1",
|
|
12
12
|
"pydantic>=2.12.5",
|
|
13
|
-
"platformdirs>=4.9.
|
|
13
|
+
"platformdirs>=4.9.6",
|
|
14
14
|
"userpath>=1.9.2",
|
|
15
15
|
"packaging>=26.0",
|
|
16
|
-
"aiohttp>=3.13.
|
|
16
|
+
"aiohttp>=3.13.5",
|
|
17
17
|
]
|
|
18
|
-
version = "0.2.1.
|
|
18
|
+
version = "0.2.1.dev89"
|
|
19
19
|
|
|
20
20
|
[project.license]
|
|
21
21
|
text = "MIT"
|
|
@@ -56,17 +56,17 @@ porringer = "porringer.console.entry:app"
|
|
|
56
56
|
|
|
57
57
|
[dependency-groups]
|
|
58
58
|
lint = [
|
|
59
|
-
"ruff>=0.15.
|
|
60
|
-
"pyrefly>=0.
|
|
59
|
+
"ruff>=0.15.10",
|
|
60
|
+
"pyrefly>=0.60.2",
|
|
61
61
|
]
|
|
62
62
|
test = [
|
|
63
|
-
"pytest>=9.0.
|
|
63
|
+
"pytest>=9.0.3",
|
|
64
64
|
"pytest-cov>=7.1.0",
|
|
65
65
|
"pytest-mock>=3.15.1",
|
|
66
66
|
"pytest-asyncio>=1.3.0",
|
|
67
67
|
]
|
|
68
68
|
docs = [
|
|
69
|
-
"zensical>=0.0.
|
|
69
|
+
"zensical>=0.0.32",
|
|
70
70
|
]
|
|
71
71
|
|
|
72
72
|
[tool.pytest.ini_options]
|
|
@@ -78,6 +78,7 @@ testpaths = [
|
|
|
78
78
|
markers = [
|
|
79
79
|
"fresh_plugins: invalidate the plugin discovery cache before this test",
|
|
80
80
|
"mock_packages: use a cached package list instead of real subprocess calls",
|
|
81
|
+
"bare_environment: simulate a bare system with only the primary tool on PATH",
|
|
81
82
|
]
|
|
82
83
|
|
|
83
84
|
[tool.ruff]
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"""Shared pytest configuration and fixtures."""
|
|
2
2
|
|
|
3
|
+
import shutil
|
|
3
4
|
import sys
|
|
4
5
|
import tempfile
|
|
5
6
|
from collections.abc import Generator
|
|
@@ -55,6 +56,10 @@ def pytest_configure(config: pytest.Config) -> None:
|
|
|
55
56
|
'markers',
|
|
56
57
|
'frozen_app: simulate a frozen (PyInstaller) application environment',
|
|
57
58
|
)
|
|
59
|
+
config.addinivalue_line(
|
|
60
|
+
'markers',
|
|
61
|
+
'bare_environment: simulate a bare system with only the primary tool on PATH',
|
|
62
|
+
)
|
|
58
63
|
|
|
59
64
|
|
|
60
65
|
def pytest_runtest_setup(item: pytest.Item) -> None:
|
|
@@ -104,6 +109,30 @@ def frozen_context(*, which_result: str | None = None) -> Generator[None]:
|
|
|
104
109
|
p.stop()
|
|
105
110
|
|
|
106
111
|
|
|
112
|
+
@contextmanager
|
|
113
|
+
def bare_environment_context(*, allowed_tools: set[str] | None = None) -> Generator[None]:
|
|
114
|
+
"""Context manager that hides all CLI tools except *allowed_tools*.
|
|
115
|
+
|
|
116
|
+
Patches ``shutil.which`` globally so that any tool not in
|
|
117
|
+
*allowed_tools* appears absent. This catches undeclared
|
|
118
|
+
auxiliary-tool dependencies.
|
|
119
|
+
|
|
120
|
+
Args:
|
|
121
|
+
allowed_tools: Tool names that should remain discoverable.
|
|
122
|
+
When ``None``, **all** tools are hidden.
|
|
123
|
+
"""
|
|
124
|
+
allowed = allowed_tools or set()
|
|
125
|
+
original_which = shutil.which
|
|
126
|
+
|
|
127
|
+
def _restricted_which(name: str, *args, **kwargs) -> str | None:
|
|
128
|
+
if name in allowed:
|
|
129
|
+
return original_which(name, *args, **kwargs)
|
|
130
|
+
return None
|
|
131
|
+
|
|
132
|
+
with patch('shutil.which', side_effect=_restricted_which):
|
|
133
|
+
yield
|
|
134
|
+
|
|
135
|
+
|
|
107
136
|
@pytest.fixture(autouse=True)
|
|
108
137
|
def _apply_mock_packages(
|
|
109
138
|
request: pytest.FixtureRequest,
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"""Integration tests that verify plugins tolerate a bare environment.
|
|
2
|
+
|
|
3
|
+
Every available plugin is dry-run installed under a restricted PATH
|
|
4
|
+
where only the plugin's primary tool is discoverable. This catches
|
|
5
|
+
undeclared auxiliary-tool dependencies that would fail on a clean
|
|
6
|
+
machine.
|
|
7
|
+
|
|
8
|
+
Safety guarantees (no system mutation):
|
|
9
|
+
|
|
10
|
+
1. ``dry_run=True`` — the sync engine skips all mutating actions
|
|
11
|
+
(install, clone, post-sync commands). Only read-only subprocess
|
|
12
|
+
calls happen (e.g. ``git rev-parse`` for presence detection,
|
|
13
|
+
``pip list`` for package queries).
|
|
14
|
+
2. ``bare_environment_context`` — restricts ``shutil.which`` so that
|
|
15
|
+
even if a mutating code path were accidentally reached, most tools
|
|
16
|
+
would appear absent and the operation would be skipped or fail
|
|
17
|
+
before spawning a process.
|
|
18
|
+
3. ``session_api`` — uses an isolated temporary directory tree for
|
|
19
|
+
configuration and cache (no writes to user/system porringer dirs).
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
from pathlib import Path
|
|
23
|
+
|
|
24
|
+
import pytest
|
|
25
|
+
|
|
26
|
+
from porringer.api import API
|
|
27
|
+
from porringer.schema import SetupParameters
|
|
28
|
+
from tests.conftest import bare_environment_context
|
|
29
|
+
|
|
30
|
+
_BOOTSTRAP_DIR = Path(__file__).resolve().parents[2] / 'examples' / 'python-bootstrap'
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
@pytest.mark.bare_environment
|
|
34
|
+
@pytest.mark.fresh_plugins
|
|
35
|
+
class TestBareEnvironmentDryRun:
|
|
36
|
+
"""Dry-run the bootstrap example under a bare PATH."""
|
|
37
|
+
|
|
38
|
+
@staticmethod
|
|
39
|
+
async def test_dry_run_succeeds_under_bare_environment(session_api: API) -> None:
|
|
40
|
+
"""Dry-run with only primary tools on PATH should not crash."""
|
|
41
|
+
setup_params = SetupParameters(paths=_BOOTSTRAP_DIR, dry_run=True)
|
|
42
|
+
|
|
43
|
+
with bare_environment_context(allowed_tools={'pip', 'python', 'git'}):
|
|
44
|
+
results = await session_api.sync.run(setup_params)
|
|
45
|
+
|
|
46
|
+
assert len(results.manifest_results) >= 1
|
|
47
|
+
for manifest in results.manifest_results:
|
|
48
|
+
# Every action should resolve without raising
|
|
49
|
+
assert manifest.actions is not None
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
"""Tests for auxiliary-tool interactions in the pip plugin."""
|
|
2
|
+
|
|
3
|
+
from collections.abc import Generator
|
|
4
|
+
from typing import override
|
|
5
|
+
from unittest.mock import AsyncMock, patch
|
|
6
|
+
|
|
7
|
+
import pytest
|
|
8
|
+
from packaging.version import Version
|
|
9
|
+
|
|
10
|
+
from porringer.core.plugin_schema.environment import PackageParameters
|
|
11
|
+
from porringer.core.schema import Distribution, Package, PackageRef, PluginParameters
|
|
12
|
+
from porringer.plugin.pip.plugin import PIPEnvironment
|
|
13
|
+
from porringer.test.pytest.tests import AuxiliaryToolTests, InstallContext
|
|
14
|
+
from porringer.utility.utility import CommandResult
|
|
15
|
+
|
|
16
|
+
_MOCK_PARAMS = PluginParameters(distribution=Distribution(version=Version('0.0.0')))
|
|
17
|
+
|
|
18
|
+
_SCENARIOS = ['tools_absent', 'tools_present', 'tools_fail_exception', 'tools_fail_nonzero']
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def _make_context(scenario: str) -> Generator[InstallContext]:
|
|
22
|
+
"""Build an InstallContext for the given scenario."""
|
|
23
|
+
env = PIPEnvironment(_MOCK_PARAMS)
|
|
24
|
+
params = PackageParameters(package=PackageRef(name='test-pkg'))
|
|
25
|
+
|
|
26
|
+
# Determine shutil.which behavior
|
|
27
|
+
which_return = None if scenario == 'tools_absent' else r'C:\Program Files\pymanager\pymanager.exe'
|
|
28
|
+
|
|
29
|
+
# Determine run_command behavior for auxiliary tool calls
|
|
30
|
+
if scenario == 'tools_fail_exception':
|
|
31
|
+
|
|
32
|
+
async def run_side_effect(args, **kwargs):
|
|
33
|
+
if args == ['pymanager', 'install', '--refresh']:
|
|
34
|
+
raise OSError('pymanager crashed')
|
|
35
|
+
return CommandResult(returncode=0, stdout='', stderr='')
|
|
36
|
+
|
|
37
|
+
mock_run = AsyncMock(side_effect=run_side_effect)
|
|
38
|
+
elif scenario == 'tools_fail_nonzero':
|
|
39
|
+
|
|
40
|
+
async def run_side_effect_nonzero(args, **kwargs):
|
|
41
|
+
if args == ['pymanager', 'install', '--refresh']:
|
|
42
|
+
return CommandResult(returncode=1, stdout='', stderr='something went wrong')
|
|
43
|
+
return CommandResult(returncode=0, stdout='', stderr='')
|
|
44
|
+
|
|
45
|
+
mock_run = AsyncMock(side_effect=run_side_effect_nonzero)
|
|
46
|
+
else:
|
|
47
|
+
mock_run = AsyncMock(return_value=CommandResult(returncode=0, stdout='', stderr=''))
|
|
48
|
+
|
|
49
|
+
with (
|
|
50
|
+
patch.object(
|
|
51
|
+
PIPEnvironment,
|
|
52
|
+
'_install_simple',
|
|
53
|
+
new_callable=AsyncMock,
|
|
54
|
+
return_value=Package(name='test-pkg', version=None),
|
|
55
|
+
),
|
|
56
|
+
patch.object(env, 'install_command', return_value=['python', '-m', 'pip', 'install', 'test-pkg']),
|
|
57
|
+
patch('porringer.plugin.pip.plugin.run_command', mock_run),
|
|
58
|
+
patch('porringer.plugin.pip.plugin.shutil.which', return_value=which_return),
|
|
59
|
+
):
|
|
60
|
+
yield InstallContext(plugin=env, params=params, mock_run=mock_run, scenario=scenario)
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
class TestPymanagerRefresh(AuxiliaryToolTests[PIPEnvironment]):
|
|
64
|
+
"""Auxiliary-tool tests for pip's pymanager refresh integration."""
|
|
65
|
+
|
|
66
|
+
@override
|
|
67
|
+
@pytest.fixture(name='install_context', params=_SCENARIOS)
|
|
68
|
+
def fixture_install_context(self, request: pytest.FixtureRequest) -> Generator[InstallContext]:
|
|
69
|
+
"""Yield an InstallContext parametrized over auxiliary-tool scenarios."""
|
|
70
|
+
yield from _make_context(request.param)
|
|
71
|
+
|
|
72
|
+
@staticmethod
|
|
73
|
+
async def test_refresh_not_called_on_dry_run() -> None:
|
|
74
|
+
"""Dry-run install does not trigger refresh even with pymanager available."""
|
|
75
|
+
env = PIPEnvironment(_MOCK_PARAMS)
|
|
76
|
+
params = PackageParameters(package=PackageRef(name='test-pkg'), dry=True)
|
|
77
|
+
|
|
78
|
+
with (
|
|
79
|
+
patch.object(
|
|
80
|
+
PIPEnvironment,
|
|
81
|
+
'_install_simple',
|
|
82
|
+
new_callable=AsyncMock,
|
|
83
|
+
return_value=Package(name='test-pkg', version=None),
|
|
84
|
+
),
|
|
85
|
+
patch.object(env, 'install_command', return_value=['python', '-m', 'pip', 'install', 'test-pkg']),
|
|
86
|
+
patch(
|
|
87
|
+
'porringer.plugin.pip.plugin.shutil.which',
|
|
88
|
+
return_value=r'C:\Program Files\pymanager\pymanager.exe',
|
|
89
|
+
),
|
|
90
|
+
patch('porringer.plugin.pip.plugin.run_command', new_callable=AsyncMock) as mock_run,
|
|
91
|
+
):
|
|
92
|
+
mock_run.return_value = CommandResult(returncode=0, stdout='', stderr='')
|
|
93
|
+
result = await env.install(params)
|
|
94
|
+
|
|
95
|
+
assert result is not None
|
|
96
|
+
mock_run.assert_not_called()
|
|
@@ -6,7 +6,7 @@ The resolver selects a plugin per (PluginKind, ecosystem) pair using:
|
|
|
6
6
|
"""
|
|
7
7
|
|
|
8
8
|
from pathlib import Path
|
|
9
|
-
from typing import Self
|
|
9
|
+
from typing import Self
|
|
10
10
|
|
|
11
11
|
from packaging.version import Version
|
|
12
12
|
|
|
@@ -36,7 +36,7 @@ class _StubPlugin:
|
|
|
36
36
|
|
|
37
37
|
def with_transport(self, transport: Transport) -> Self:
|
|
38
38
|
parameters = PluginParameters(distribution=self._distribution, transport=transport)
|
|
39
|
-
return
|
|
39
|
+
return type(self)(parameters)
|
|
40
40
|
|
|
41
41
|
@staticmethod
|
|
42
42
|
def ecosystem() -> Ecosystem | None:
|
|
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
|
{porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/backend/command/core/action_builder.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/backend/command/core/resolution.py
RENAMED
|
File without changes
|
{porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/backend/command/core/wsl_overlay.py
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
|
{porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/core/plugin_schema/plugin_manager.py
RENAMED
|
File without changes
|
{porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/core/plugin_schema/project_environment.py
RENAMED
|
File without changes
|
{porringer-0.2.1.dev88 → porringer-0.2.1.dev89}/porringer/core/plugin_schema/python_environment.py
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
|