instant-python 0.26.0__py3-none-any.whl → 0.27.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. instant_python/__init__.py +1 -1
  2. instant_python/cli/cli.py +11 -16
  3. instant_python/config/infra/question_wizard/step/general_step.py +0 -1
  4. instant_python/initialize/delivery/cli.py +3 -3
  5. instant_python/initialize/infra/env_manager/env_manager_factory.py +1 -3
  6. instant_python/initialize/infra/env_manager/uv_env_manager.py +2 -2
  7. instant_python/initialize/infra/formatter/ruff_project_formatter.py +1 -1
  8. instant_python/initialize/infra/version_control/git_configurer.py +1 -1
  9. instant_python/shared/domain/general_config.py +11 -2
  10. instant_python/shared/supported_managers.py +0 -1
  11. instant_python/templates/boilerplate/.pre-commit-config.yaml +2 -2
  12. instant_python/templates/boilerplate/github/action.yml +0 -8
  13. instant_python/templates/boilerplate/github/ci.yml +2 -22
  14. instant_python/templates/boilerplate/github/release.yml +1 -1
  15. instant_python/templates/boilerplate/pyproject.toml +1 -6
  16. instant_python/templates/boilerplate/scripts/__init__.py +0 -0
  17. instant_python/templates/boilerplate/scripts/makefile +18 -52
  18. instant_python/version/__init__.py +0 -0
  19. instant_python/version/application/__init__.py +0 -0
  20. instant_python/version/application/version_updater.py +21 -0
  21. instant_python/version/delivery/__init__.py +0 -0
  22. instant_python/version/delivery/cli.py +38 -0
  23. instant_python/version/domain/__init__.py +0 -0
  24. instant_python/version/domain/installation_method.py +8 -0
  25. instant_python/version/domain/installation_method_detector.py +9 -0
  26. instant_python/version/domain/latest_version.py +13 -0
  27. instant_python/version/domain/latest_version_repository.py +9 -0
  28. instant_python/version/domain/updater.py +9 -0
  29. instant_python/version/domain/updater_resolver.py +10 -0
  30. instant_python/version/infra/__init__.py +0 -0
  31. instant_python/version/infra/binary_updater.py +47 -0
  32. instant_python/version/infra/pip_updater.py +15 -0
  33. instant_python/version/infra/pipx_updater.py +17 -0
  34. instant_python/version/infra/py_pi_version_repository.py +14 -0
  35. instant_python/version/infra/system_installation_method_detector.py +22 -0
  36. instant_python/version/infra/updater_factory.py +24 -0
  37. instant_python/version/infra/urllib_http_client.py +15 -0
  38. instant_python/version/infra/uv_updater.py +17 -0
  39. {instant_python-0.26.0.dist-info → instant_python-0.27.0.dist-info}/METADATA +1 -1
  40. {instant_python-0.26.0.dist-info → instant_python-0.27.0.dist-info}/RECORD +44 -33
  41. instant_python/initialize/infra/env_manager/pdm_env_manager.py +0 -66
  42. instant_python/templates/boilerplate/scripts/add_dependency.py +0 -45
  43. instant_python/templates/boilerplate/scripts/create_aggregate.py +0 -33
  44. instant_python/templates/boilerplate/scripts/insert_template.py +0 -90
  45. instant_python/templates/boilerplate/scripts/integration.sh +0 -39
  46. instant_python/templates/boilerplate/scripts/local_setup.py +0 -12
  47. instant_python/templates/boilerplate/scripts/post-merge.py +0 -40
  48. instant_python/templates/boilerplate/scripts/pre-commit.py +0 -15
  49. instant_python/templates/boilerplate/scripts/pre-push.py +0 -6
  50. instant_python/templates/boilerplate/scripts/remove_dependency.py +0 -40
  51. instant_python/templates/boilerplate/scripts/unit.sh +0 -40
  52. /instant_python/{initialize/infra/env_manager → shared/infra}/system_console.py +0 -0
  53. {instant_python-0.26.0.dist-info → instant_python-0.27.0.dist-info}/WHEEL +0 -0
  54. {instant_python-0.26.0.dist-info → instant_python-0.27.0.dist-info}/entry_points.txt +0 -0
  55. {instant_python-0.26.0.dist-info → instant_python-0.27.0.dist-info}/licenses/LICENSE +0 -0
@@ -1 +1 @@
1
- __version__ = "0.26.0"
1
+ __version__ = "0.27.0"
instant_python/cli/cli.py CHANGED
@@ -1,44 +1,39 @@
1
- from typing import Annotated
1
+ import warnings
2
2
 
3
3
  import typer
4
4
  from rich.console import Console
5
5
  from rich.panel import Panel
6
6
 
7
- from instant_python import __version__
8
7
  from instant_python.cli.instant_python_typer import InstantPythonTyper
9
8
  from instant_python.config.delivery import cli as config
10
9
  from instant_python.initialize.delivery import cli as init
11
10
  from instant_python.metrics.delivery.metrics_middleware import MetricsMiddleware
12
11
  from instant_python.shared.application_error import ApplicationError
12
+ from instant_python.version.delivery import cli as version
13
13
 
14
14
  app = InstantPythonTyper(cls=MetricsMiddleware)
15
15
  console = Console()
16
16
 
17
17
 
18
- def version_callback(value: bool) -> None:
19
- if value:
20
- console.print(f"instant-python {__version__}")
21
- raise typer.Exit()
18
+ def _show_warning(message: Warning | str, *_args: object, **_kwargs: object) -> None:
19
+ warning_panel = Panel(str(message), title="Warning", border_style="yellow")
20
+ console.print(warning_panel)
21
+
22
+
23
+ warnings.showwarning = _show_warning
24
+ warnings.simplefilter("always", DeprecationWarning)
22
25
 
23
26
 
24
27
  @app.callback(invoke_without_command=True)
25
28
  def main(
26
29
  ctx: typer.Context,
27
- version: Annotated[
28
- bool | None,
29
- typer.Option(
30
- "--version",
31
- "-V",
32
- help="Show the application version",
33
- callback=version_callback,
34
- is_eager=True,
35
- ),
36
- ] = None,
37
30
  ) -> None:
38
31
  if ctx.invoked_subcommand is None:
39
32
  console.print(ctx.get_help())
40
33
 
41
34
 
35
+ app.add_typer(version.app)
36
+
42
37
  app.add_typer(init.app)
43
38
  app.add_typer(config.app)
44
39
 
@@ -24,7 +24,6 @@ class GeneralStep(Step):
24
24
  self._ask_author_name()
25
25
  self._ask_license()
26
26
  self._ask_python_version()
27
- self._ask_dependency_manager()
28
27
 
29
28
  return {self._KEY: self._answers}
30
29
 
@@ -3,14 +3,14 @@ from pathlib import Path
3
3
  import typer
4
4
 
5
5
  from instant_python.initialize.application.project_initializer import ProjectInitializer
6
- from instant_python.initialize.infra.env_manager.env_manager_factory import EnvManagerFactory
7
- from instant_python.initialize.infra.env_manager.system_console import SystemConsole
6
+ from instant_python.initialize.infra.env_manager.uv_env_manager import UvEnvManager
8
7
  from instant_python.initialize.infra.formatter.ruff_project_formatter import RuffProjectFormatter
9
8
  from instant_python.initialize.infra.renderer.jinja_environment import JinjaEnvironment
10
9
  from instant_python.initialize.infra.renderer.jinja_project_renderer import JinjaProjectRenderer
11
10
  from instant_python.initialize.infra.version_control.git_configurer import GitConfigurer
12
11
  from instant_python.initialize.infra.writer.file_system_project_writer import FileSystemProjectWriter
13
12
  from instant_python.shared.infra.persistence.yaml_config_repository import YamlConfigRepository
13
+ from instant_python.shared.infra.system_console import SystemConsole
14
14
 
15
15
  app = typer.Typer()
16
16
 
@@ -32,7 +32,7 @@ def create_new_project(
32
32
  project_initializer = ProjectInitializer(
33
33
  renderer=JinjaProjectRenderer(env=JinjaEnvironment(user_template_path=custom_templates_path)),
34
34
  writer=FileSystemProjectWriter(),
35
- env_manager=EnvManagerFactory.create(dependency_manager=config.dependency_manager, console=console),
35
+ env_manager=UvEnvManager(console=console),
36
36
  version_control_configurer=GitConfigurer(console=console),
37
37
  formatter=RuffProjectFormatter(console=console),
38
38
  )
@@ -1,8 +1,7 @@
1
1
  from instant_python.initialize.domain.env_manager import EnvManager
2
- from instant_python.initialize.infra.env_manager.pdm_env_manager import PdmEnvManager
3
- from instant_python.initialize.infra.env_manager.system_console import SystemConsole
4
2
  from instant_python.initialize.infra.env_manager.uv_env_manager import UvEnvManager
5
3
  from instant_python.shared.application_error import ApplicationError
4
+ from instant_python.shared.infra.system_console import SystemConsole
6
5
  from instant_python.shared.supported_managers import SupportedManagers
7
6
 
8
7
 
@@ -11,7 +10,6 @@ class EnvManagerFactory:
11
10
  def create(dependency_manager: str, console: SystemConsole) -> EnvManager:
12
11
  managers = {
13
12
  SupportedManagers.UV: UvEnvManager,
14
- SupportedManagers.PDM: PdmEnvManager,
15
13
  }
16
14
  try:
17
15
  return managers[SupportedManagers(dependency_manager)](console=console)
@@ -2,12 +2,12 @@ import sys
2
2
  from pathlib import Path
3
3
 
4
4
  from instant_python.initialize.domain.env_manager import EnvManager
5
- from instant_python.initialize.infra.env_manager.system_console import SystemConsole
6
5
  from instant_python.shared.domain.dependency_config import DependencyConfig
6
+ from instant_python.shared.infra.system_console import SystemConsole
7
7
 
8
8
 
9
9
  class UvEnvManager(EnvManager):
10
- def __init__(self, console: SystemConsole | None = None) -> None:
10
+ def __init__(self, console: SystemConsole) -> None:
11
11
  self._console = console
12
12
  self._system_os = sys.platform
13
13
  self._uv = self._set_uv_executable_based_on_os()
@@ -1,5 +1,5 @@
1
1
  from instant_python.initialize.domain.project_formatter import ProjectFormatter
2
- from instant_python.initialize.infra.env_manager.system_console import SystemConsole
2
+ from instant_python.shared.infra.system_console import SystemConsole
3
3
 
4
4
 
5
5
  class RuffProjectFormatter(ProjectFormatter):
@@ -1,6 +1,6 @@
1
1
  from instant_python.initialize.domain.version_control_configurer import VersionControlConfigurer
2
- from instant_python.initialize.infra.env_manager.system_console import SystemConsole
3
2
  from instant_python.shared.domain.git_config import GitConfig
3
+ from instant_python.shared.infra.system_console import SystemConsole
4
4
 
5
5
 
6
6
  class GitConfigurer(VersionControlConfigurer):
@@ -1,5 +1,6 @@
1
1
  import re
2
- from dataclasses import asdict, dataclass
2
+ import warnings
3
+ from dataclasses import asdict, dataclass, field
3
4
 
4
5
  from instant_python.shared.application_error import ApplicationError
5
6
  from instant_python.shared.supported_licenses import SupportedLicenses
@@ -16,7 +17,7 @@ class GeneralConfig:
16
17
  author: str
17
18
  license: str
18
19
  python_version: str
19
- dependency_manager: str
20
+ dependency_manager: str = field(default=SupportedManagers.UV.value)
20
21
 
21
22
  def __post_init__(self) -> None:
22
23
  self.version = str(self.version)
@@ -44,6 +45,14 @@ class GeneralConfig:
44
45
 
45
46
  def _ensure_dependency_manager_is_supported(self) -> None:
46
47
  supported_dependency_managers = SupportedManagers.get_supported_managers()
48
+ if self.dependency_manager == "pdm":
49
+ warnings.warn(
50
+ "`pdm` is no longer supported as a dependency manager and has been replaced with `uv`. "
51
+ "Update your ipy.yml file to remove this warning.",
52
+ DeprecationWarning,
53
+ stacklevel=2,
54
+ )
55
+ self.dependency_manager = SupportedManagers.UV.value
47
56
  if self.dependency_manager not in supported_dependency_managers:
48
57
  raise InvalidDependencyManagerValue(self.dependency_manager, supported_dependency_managers)
49
58
 
@@ -3,7 +3,6 @@ from enum import Enum
3
3
 
4
4
  class SupportedManagers(str, Enum):
5
5
  UV = "uv"
6
- PDM = "pdm"
7
6
 
8
7
  @classmethod
9
8
  def get_supported_managers(cls) -> list[str]:
@@ -58,14 +58,14 @@ repos:
58
58
  hooks:
59
59
  - id: lint
60
60
  name: 🧹 Code Linter
61
- entry: make check-lint
61
+ entry: make lint
62
62
  language: system
63
63
  stages:
64
64
  - pre-push
65
65
 
66
66
  - id: format
67
67
  name: 🎨 Code Formatter
68
- entry: make check-format
68
+ entry: make format
69
69
  language: system
70
70
  stages:
71
71
  - pre-push
@@ -20,16 +20,8 @@ runs:
20
20
 
21
21
  - name: 📦 Install dependencies
22
22
  run: |
23
- {% if general.dependency_manager == "uv" %}
24
23
  uv sync --all-groups
25
- {% elif general.dependency_manager == "pdm" %}
26
- pdm install
27
- {% endif %}
28
24
  {% if "precommit_hook" in template.built_in_features %}
29
- {% if general.dependency_manager == "uv" %}
30
25
  uv run -m pre_commit install
31
- {% elif general.dependency_manager == "pdm" %}
32
- pdm run pre-commit install
33
- {% endif %}
34
26
  {% endif %}
35
27
  shell: bash
@@ -31,30 +31,10 @@ jobs:
31
31
  uses: ./.github/actions/python_setup
32
32
 
33
33
  - name: 🧐 Check linting
34
- run: make check-lint
35
-
36
- format:
37
- name: format
38
- runs-on: ubuntu-latest
39
- steps:
40
- - name: 🛡️ Harden runner
41
- uses: step-security/harden-runner@9af89fc71515a100421586dfdb3dc9c984fbf411 # v2.19.4
42
- with:
43
- egress-policy: audit
44
-
45
- - name: 📥 Checkout the repository
46
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
47
- with:
48
- ref: {% raw %}${{ github.head_ref }}{% endraw %}
49
-
50
- fetch-depth: 0
51
- persist-credentials: false
52
-
53
- - name: 🛠️ Setup environment
54
- uses: ./.github/actions/python_setup
34
+ run: make lint
55
35
 
56
36
  - name: 🧐 Check code format
57
- run: make check-format
37
+ run: make format
58
38
 
59
39
  typing:
60
40
  runs-on: ubuntu-latest
@@ -88,7 +88,7 @@ jobs:
88
88
  uses: ./.github/actions/python_setup
89
89
 
90
90
  - name: 🏃 Build package
91
- run: {{ general.dependency_manager }} build
91
+ run: uv build
92
92
 
93
93
  - name: 🚀 Publish
94
94
  uses: pypa/gh-action-pypi-publish@release/v1
@@ -68,10 +68,7 @@ requires-python = "=={{ general.python_version }}.*"
68
68
  readme = "README.md"
69
69
  license = { file = "LICENSE" }
70
70
 
71
- {% if general.dependency_manager == "pdm" %}
72
- [tool.pdm]
73
- distribution = false
74
- {% endif %}
71
+
75
72
  {% if release_deps.strip() or lint_deps.strip() or test_deps.strip() %}
76
73
  [dependency-groups]
77
74
  dev = [
@@ -106,10 +103,8 @@ docs = [
106
103
  {% endif %}
107
104
  {% endif %}
108
105
 
109
- {% if general.dependency_manager == "uv" %}
110
106
  [tool.uv]
111
107
  exclude-newer = "3 days"
112
- {% endif %}
113
108
 
114
109
  {% if dependencies | has_dependency("ruff") or has_github_actions_or_makefile %}
115
110
  [tool.ruff]
@@ -1,5 +1,3 @@
1
- {% set has_uv = general.dependency_manager == "uv" %}
2
- {% set has_pdm = general.dependency_manager == "pdm" %}
3
1
  {% set has_pre_commit_hooks = "precommit_hook" in template.built_in_features %}
4
2
  {% set has_github_actions_or_makefile = ["github_actions", "makefile"] | is_in(template.built_in_features) %}
5
3
  {% set has_agents = "ai_agents" in template.built_in_features %}
@@ -16,120 +14,96 @@ local-setup: ## Setup git hooks and install dependencies.
16
14
  @echo "⌛ Setting up the project...\n"
17
15
  @make install
18
16
  {% if has_pre_commit_hooks %}
19
- @{{ general.dependency_manager }} run -m pre_commit install --hook-type pre-commit --hook-type commit-msg --hook-type pre-push
17
+ @uv run -m pre_commit install --hook-type pre-commit --hook-type commit-msg --hook-type pre-push
20
18
  {% endif %}
21
19
 
22
20
  .PHONY: install
23
21
  install: ## Install dependencies.
24
22
  @echo "⌛ Installing dependencies...\n"
25
- {% if has_uv %}
26
23
  @uv sync --all-groups
27
- {% elif has_pdm %}
28
- @pdm install
29
- {% endif %}
30
24
 
31
25
  .PHONY: update
32
26
  update: ## Update dependencies.
33
27
  @echo "⌛ Updating dependencies...\n"
34
- {% if has_uv %}
35
28
  @uv lock --upgrade
36
29
  @uv sync --all-groups
37
- {% elif has_pdm %}
38
- @pdm update
39
- {% endif %}
40
30
 
41
31
  .PHONY: add-dep
42
32
  add-dep: ## Add a new dependency
43
- @{{ general.dependency_manager }} add $(dep)
33
+ @uv add $(dep)
44
34
 
45
35
  .PHONY: remove-dep
46
36
  remove-dep: ## Remove a dependency
47
- @{{ general.dependency_manager }} remove $(dep)
37
+ @uv remove $(dep)
48
38
 
49
39
  {% if dependencies | has_dependency("pytest") or has_github_actions_or_makefile %}
50
40
  .PHONY: test
51
41
  test: ## Run all tests (optional: TESTS_PATH=tests/module/).
52
42
  @echo "⌛ Running tests...\n"
53
- @{{ general.dependency_manager }} run pytest $(or $(TESTS_PATH),test) -ra
43
+ @uv run pytest $(or $(TESTS_PATH),test) -ra
54
44
 
55
45
  .PHONY: unit
56
46
  unit: ## Run all unit test (optional: TESTS_PATH=tests/module/).
57
47
  @echo "⌛ Running unit tests...\n"
58
- @{{ general.dependency_manager }} run pytest -m "unit" $(TESTS_PATH) -ra
48
+ @uv run pytest -m "unit" $(TESTS_PATH) -ra
59
49
 
60
50
  .PHONY: integration
61
51
  integration: ## Run all integration test (optional: TESTS_PATH=tests/module/).
62
52
  @echo "⌛ Running integration tests...\n"
63
- @{{ general.dependency_manager }} run pytest -m "integration" $(TESTS_PATH) -ra
53
+ @uv run pytest -m "integration" $(TESTS_PATH) -ra
64
54
 
65
55
  .PHONY: acceptance
66
56
  acceptance: ## Run all acceptance test (optional: TESTS_PATH=tests/module/).
67
57
  @echo "⌛ Running acceptance tests...\n"
68
- @{{ general.dependency_manager }} run pytest -m "acceptance" $(TESTS_PATH) -ra
58
+ @uv run pytest -m "acceptance" $(TESTS_PATH) -ra
69
59
 
70
60
  .PHONY: coverage
71
61
  coverage: ## Run all test with coverage.
72
62
  @echo "⌛ Running tests with coverage...\n"
73
- @{{ general.dependency_manager }} run coverage run --branch -m pytest test
74
- @{{ general.dependency_manager }} run coverage html
63
+ @uv run coverage run --branch -m pytest test
64
+ @uv run coverage html
75
65
  @$(BROWSER) htmlcov/index.html
76
66
  {% endif %}
77
67
  {% if dependencies | has_dependency("pytest-watch") %}
78
68
  .PHONY: watch
79
69
  watch: ## Run all test with every change.
80
70
  @echo "⌛ Running test in watch mode...\n"
81
- @{{ general.dependency_manager }} run ptw --runner "pytest test -ra"
71
+ @uv run ptw --runner "pytest test -ra"
82
72
  {% endif %}
83
73
 
84
74
  .PHONY: check-typing
85
75
  check-typing: ## Run mypy type checking.
86
76
  @echo "⌛ Running type checking...\n"
87
77
  {% if dependencies | has_dependency("mypy") or has_github_actions_or_makefile %}
88
- @{{ general.dependency_manager }} run mypy
78
+ @uv run mypy
89
79
  {% elif dependencies | has_dependency("ty") or has_github_actions_or_makefile %}
90
- @{{ general.dependency_manager }} run ty
80
+ @uv run ty
91
81
  {% elif dependencies | has_dependency("pyright") or has_github_actions_or_makefile %}
92
- @{{ general.dependency_manager }} run pyright
82
+ @uv run pyright
93
83
  {% elif dependencies | has_dependency("pyrefly") or has_github_actions_or_makefile %}
94
- @{{ general.dependency_manager }} run pyrefly
84
+ @uv run pyrefly
95
85
  {% endif %}
96
86
 
97
87
  {% if dependencies | has_dependency("ruff") or has_github_actions_or_makefile or has_pre_commit_hooks %}
98
88
  .PHONY: check-lint
99
89
  check-lint: ## Run ruff linting check.
100
90
  @echo "⌛ Running linting check...\n"
101
- {% if has_pdm %}
102
- @pdm run ruff check src test
103
- {% elif has_uv %}
104
91
  @uvx ruff check src test
105
- {% endif %}
106
92
 
107
93
  .PHONY: lint
108
94
  lint: ## Apply ruff linting fix.
109
95
  @echo "\n⌛ Applying linting fixes...\n"
110
- {% if has_pdm %}
111
- @pdm run ruff check --fix src test
112
- {% elif has_uv %}
113
96
  @uvx ruff check --fix src test
114
- {% endif %}
115
97
 
116
98
  .PHONY: check-format
117
99
  check-format: ## Run ruff format check.
118
100
  @echo "⌛ Checking code formatting...\n"
119
- {% if has_pdm %}
120
- @pdm run ruff format --check src test
121
- {% elif has_uv %}
122
101
  @uvx ruff format --check src test
123
- {% endif %}
124
102
 
125
103
  .PHONY: format
126
104
  format: ## Apply ruff format fix.
127
105
  @echo "⌛ Formatting project code...\n"
128
- {% if has_pdm %}
129
- @pdm run ruff format src test
130
- {% elif has_uv %}
131
106
  @uvx ruff format src test
132
- {% endif %}
133
107
 
134
108
  .PHONY: autostyle
135
109
  autostyle: ## Apply all code style fixes.
@@ -142,22 +116,22 @@ autostyle: ## Apply all code style fixes.
142
116
  .PHONY: secrets
143
117
  secrets: # Check for secrets in the source code
144
118
  @echo "⌛ Checking secrets...\n"
145
- @{{ general.dependency_manager }} run -m pre_commit run gitleaks --all-files
119
+ @uv run -m pre_commit run gitleaks --all-files
146
120
  {% endif %}
147
121
 
148
122
  {% if "github_actions" in template.built_in_features %}
149
123
  .PHONY: audit
150
124
  audit: # It audits dependencies and source code
151
125
  @echo "⌛ Checking for vulnerabilities in dependencies...\n"
152
- @{{ general.dependency_manager }} run -m pip_audit --progress-spinner off
126
+ @uv run -m pip_audit --progress-spinner off
153
127
  {% endif %}
154
128
 
155
129
  .PHONY: clean
156
130
  clean: # Clean up the project, removing the virtual environment and some files
157
131
  @echo "\n⌛ Cleaning up the project...\n"
158
132
 
159
- @{{ general.dependency_manager }} run -m pre_commit clean)
160
- @{{ general.dependency_manager }} run -m pre_commit uninstall --hook-type pre-commit --hook-type commit-msg)
133
+ @uv run -m pre_commit clean)
134
+ @uv run -m pre_commit uninstall --hook-type pre-commit --hook-type commit-msg)
161
135
  @rm --force --recursive .venv
162
136
  @rm --force --recursive `find . -type f -name '*.py[co]'`
163
137
  @rm --force --recursive `find . -name __pycache__`
@@ -171,20 +145,12 @@ clean: # Clean up the project, removing the virtual environment and some files
171
145
 
172
146
  .PHONY: show
173
147
  show: ## Show installed dependencies.
174
- {% if has_pdm %}
175
- @pdm list
176
- {% elif has_uv %}
177
148
  @uv tree
178
- {% endif %}
179
149
 
180
150
  .PHONY: search
181
151
  search: ## Show package details.
182
152
  @read -p "Enter package name to search: " package;\
183
- {% if has_pdm %}
184
- @pdm show $$package
185
- {% elif has_uv %}
186
153
  @uv pip show $$package
187
- {% endif %}
188
154
  {% if has_agents %}
189
155
  .PHONY: claude
190
156
  claude: ## Create symlinks for Claude Code compatibility (CLAUDE.md → AGENTS.md, .claude → .agents).
File without changes
File without changes
@@ -0,0 +1,21 @@
1
+ from instant_python.version.domain.installation_method import InstallationMethod
2
+ from instant_python.version.domain.installation_method_detector import InstallationMethodDetector
3
+ from instant_python.version.domain.updater_resolver import UpdaterResolver
4
+
5
+
6
+ class VersionUpdater:
7
+ def __init__(self, detector: InstallationMethodDetector, updater_resolver: UpdaterResolver) -> None:
8
+ self._detector = detector
9
+ self._updater_resolver = updater_resolver
10
+
11
+ def execute(self, version: str) -> InstallationMethod:
12
+ installation_method = self._detect_installation_method()
13
+ self._update_installed_version(installation_method, version)
14
+ return installation_method
15
+
16
+ def _update_installed_version(self, installation_method: InstallationMethod, version: str) -> None:
17
+ updater = self._updater_resolver.resolve(installation_method)
18
+ updater.update(version)
19
+
20
+ def _detect_installation_method(self) -> InstallationMethod:
21
+ return self._detector.detect()
File without changes
@@ -0,0 +1,38 @@
1
+ from pathlib import Path
2
+
3
+ import typer
4
+ from rich.console import Console
5
+
6
+ from instant_python import __version__
7
+ from instant_python.shared.infra.system_console import SystemConsole
8
+ from instant_python.version.application.version_updater import VersionUpdater
9
+ from instant_python.version.domain.updater import LATEST_VERSION
10
+ from instant_python.version.infra.py_pi_version_repository import PyPiLatestLatestVersionRepository
11
+ from instant_python.version.infra.system_installation_method_detector import SystemInstallationMethodDetector
12
+ from instant_python.version.infra.updater_factory import UpdaterFactory
13
+ from instant_python.version.infra.urllib_http_client import UrllibHttpClient
14
+
15
+ app = typer.Typer()
16
+ console = Console()
17
+
18
+
19
+ @app.command("version", help="Show instant-python version")
20
+ def show_version() -> None:
21
+ latest_version_repository = PyPiLatestLatestVersionRepository(client=UrllibHttpClient())
22
+ latest_version = latest_version_repository.get_latest_version()
23
+ current_version = __version__
24
+ console.print(f"{current_version} - (latest) {latest_version}")
25
+
26
+
27
+ @app.command("update", help="Update instant-python to the latest version or a specific one")
28
+ def update_version(
29
+ version: str = typer.Option(LATEST_VERSION, "--version", help="Specific version to install instead of the latest"),
30
+ ) -> None:
31
+ version_updater = VersionUpdater(
32
+ detector=SystemInstallationMethodDetector(),
33
+ updater_resolver=UpdaterFactory(console=SystemConsole(working_directory=str(Path.cwd()))),
34
+ )
35
+
36
+ console.print(f"Updating instant-python to {version}...")
37
+ installation_method = version_updater.execute(version)
38
+ console.print(f"instant-python updated successfully (installed via {installation_method.value})")
File without changes
@@ -0,0 +1,8 @@
1
+ from enum import Enum
2
+
3
+
4
+ class InstallationMethod(Enum):
5
+ BINARY = "binary"
6
+ PIPX = "pipx"
7
+ UV = "uv"
8
+ PIP = "pip"
@@ -0,0 +1,9 @@
1
+ from abc import ABC, abstractmethod
2
+
3
+ from instant_python.version.domain.installation_method import InstallationMethod
4
+
5
+
6
+ class InstallationMethodDetector(ABC):
7
+ @abstractmethod
8
+ def detect(self) -> InstallationMethod:
9
+ raise NotImplementedError
@@ -0,0 +1,13 @@
1
+ from dataclasses import dataclass
2
+
3
+
4
+ @dataclass
5
+ class LatestVersion:
6
+ version: str
7
+
8
+ @classmethod
9
+ def unknown(cls) -> "LatestVersion":
10
+ return cls("unknown")
11
+
12
+ def __repr__(self) -> str:
13
+ return self.version
@@ -0,0 +1,9 @@
1
+ from abc import ABC, abstractmethod
2
+
3
+ from instant_python.version.domain.latest_version import LatestVersion
4
+
5
+
6
+ class LatestVersionRepository(ABC):
7
+ @abstractmethod
8
+ def get_latest_version(self) -> LatestVersion:
9
+ raise NotImplementedError
@@ -0,0 +1,9 @@
1
+ from abc import ABC, abstractmethod
2
+
3
+ LATEST_VERSION = "latest"
4
+
5
+
6
+ class Updater(ABC):
7
+ @abstractmethod
8
+ def update(self, version: str) -> None:
9
+ raise NotImplementedError
@@ -0,0 +1,10 @@
1
+ from abc import ABC, abstractmethod
2
+
3
+ from instant_python.version.domain.installation_method import InstallationMethod
4
+ from instant_python.version.domain.updater import Updater
5
+
6
+
7
+ class UpdaterResolver(ABC):
8
+ @abstractmethod
9
+ def resolve(self, installation_method: InstallationMethod) -> Updater:
10
+ raise NotImplementedError
File without changes