@@ -9,13 +9,11 @@ import subprocess
9
9
import sys
10
10
from contextlib import contextmanager
11
11
from pathlib import Path
12
+ from textwrap import dedent
12
13
from typing import Any , Iterator
13
14
14
15
PYTHON_VERSIONS = os .getenv ("PYTHON_VERSIONS" , "3.8 3.9 3.10 3.11 3.12 3.13" ).split ()
15
16
16
- exe = ""
17
- prefix = ""
18
-
19
17
20
18
def shell (cmd : str , capture_output : bool = False , ** kwargs : Any ) -> str | None :
21
19
"""Run a shell command."""
@@ -37,18 +35,11 @@ def environ(**kwargs: str) -> Iterator[None]:
37
35
os .environ .update (original )
38
36
39
37
40
- def uv_install () -> None :
38
+ def uv_install (venv : Path ) -> None :
41
39
"""Install dependencies using uv."""
42
- uv_opts = ""
43
- if "UV_RESOLUTION" in os .environ :
44
- uv_opts = f"--resolution={ os .getenv ('UV_RESOLUTION' )} "
45
- requirements = shell (f"uv pip compile { uv_opts } pyproject.toml devdeps.txt" , capture_output = True )
46
- shell ("uv pip install -r -" , input = requirements , text = True )
47
- if "CI" not in os .environ :
48
- shell ("uv pip install --no-deps -e ." )
49
- else :
50
- shell ("uv pip install --no-deps ." )
51
-
40
+ with environ (UV_PROJECT_ENVIRONMENT = str (venv )):
41
+ shell ("uv sync" )
42
+
52
43
53
44
def setup () -> None :
54
45
"""Setup the project."""
@@ -59,47 +50,27 @@ def setup() -> None:
59
50
default_venv = Path (".venv" )
60
51
if not default_venv .exists ():
61
52
shell ("uv venv --python python" )
62
- uv_install ()
53
+ uv_install (default_venv )
63
54
64
55
if PYTHON_VERSIONS :
65
56
for version in PYTHON_VERSIONS :
66
57
print (f"\n Installing dependencies (python{ version } )" ) # noqa: T201
67
58
venv_path = Path (f".venvs/{ version } " )
68
59
if not venv_path .exists ():
69
60
shell (f"uv venv --python { version } { venv_path } " )
70
- with environ (VIRTUAL_ENV = str (venv_path .resolve ())):
71
- uv_install ()
72
-
73
-
74
- def activate (path : str ) -> None :
75
- """Activate a virtual environment."""
76
- global exe , prefix # noqa: PLW0603
77
-
78
- if (bin := Path (path , "bin" )).exists ():
79
- activate_script = bin / "activate_this.py"
80
- elif (scripts := Path (path , "Scripts" )).exists ():
81
- activate_script = scripts / "activate_this.py"
82
- exe = ".exe"
83
- prefix = f"{ path } /Scripts/"
84
- else :
85
- raise ValueError (f"make: activate: Cannot find activation script in { path } " )
86
-
87
- if not activate_script .exists ():
88
- raise ValueError (f"make: activate: Cannot find activation script in { path } " )
89
-
90
- exec (activate_script .read_text (), {"__file__" : str (activate_script )}) # noqa: S102
61
+ with environ (UV_PROJECT_ENVIRONMENT = str (venv_path .resolve ())):
62
+ uv_install (venv_path )
91
63
92
64
93
65
def run (version : str , cmd : str , * args : str , ** kwargs : Any ) -> None :
94
66
"""Run a command in a virtual environment."""
95
67
kwargs = {"check" : True , ** kwargs }
96
68
if version == "default" :
97
- activate ( ".venv" )
98
- subprocess .run ([f" { prefix } { cmd } { exe } " , * args ], ** kwargs ) # noqa: S603, PLW1510
69
+ with environ ( UV_PROJECT_ENVIRONMENT = ".venv" ):
70
+ subprocess .run (["uv" , "run" , cmd , * args ], ** kwargs ) # noqa: S603, PLW1510
99
71
else :
100
- activate (f".venvs/{ version } " )
101
- os .environ ["MULTIRUN" ] = "1"
102
- subprocess .run ([f"{ prefix } { cmd } { exe } " , * args ], ** kwargs ) # noqa: S603, PLW1510
72
+ with environ (UV_PROJECT_ENVIRONMENT = f".venvs/{ version } " , MULTIRUN = "1" ):
73
+ subprocess .run (["uv" , "run" , cmd , * args ], ** kwargs ) # noqa: S603, PLW1510
103
74
104
75
105
76
def multirun (cmd : str , * args : str , ** kwargs : Any ) -> None :
@@ -124,10 +95,10 @@ def clean() -> None:
124
95
for path in paths_to_clean :
125
96
shell (f"rm -rf { path } " )
126
97
127
- cache_dirs = [ ".cache" , ".pytest_cache" , ".mypy_cache" , ".ruff_cache" , "__pycache__" ]
128
- for dirpath in Path ("." ).rglob ("*" ):
129
- if any ( dirpath .match ( pattern ) for pattern in cache_dirs ) and not ( dirpath . match ( ".venv" ) or dirpath . match ( ".venvs" )) :
130
- shutil .rmtree (path , ignore_errors = True )
98
+ cache_dirs = { ".cache" , ".pytest_cache" , ".mypy_cache" , ".ruff_cache" , "__pycache__" }
99
+ for dirpath in Path ("." ).rglob ("*/ " ):
100
+ if dirpath .parts [ 0 ] not in ( ".venv" , ".venvs" ) and dirpath . name in cache_dirs :
101
+ shutil .rmtree (dirpath , ignore_errors = True )
131
102
132
103
133
104
def vscode () -> None :
@@ -143,21 +114,24 @@ def main() -> int:
143
114
if len (args ) > 1 :
144
115
run ("default" , "duty" , "--help" , args [1 ])
145
116
else :
146
- print ("Available commands" ) # noqa: T201
147
- print (" help Print this help. Add task name to print help." ) # noqa: T201
148
- print (" setup Setup all virtual environments (install dependencies)." ) # noqa: T201
149
- print (" run Run a command in the default virtual environment." ) # noqa: T201
150
- print (" multirun Run a command for all configured Python versions." ) # noqa: T201
151
- print (" allrun Run a command in all virtual environments." ) # noqa: T201
152
- print (" 3.x Run a command in the virtual environment for Python 3.x." ) # noqa: T201
153
- print (" clean Delete build artifacts and cache files." ) # noqa: T201
154
- print (" vscode Configure VSCode to work on this project." ) # noqa: T201
155
- try :
156
- run ("default" , "python" , "-V" , capture_output = True )
157
- except (subprocess .CalledProcessError , ValueError ):
158
- pass
159
- else :
160
- print ("\n Available tasks" ) # noqa: T201
117
+ print (
118
+ dedent (
119
+ """
120
+ Available commands
121
+ help Print this help. Add task name to print help.
122
+ setup Setup all virtual environments (install dependencies).
123
+ run Run a command in the default virtual environment.
124
+ multirun Run a command for all configured Python versions.
125
+ allrun Run a command in all virtual environments.
126
+ 3.x Run a command in the virtual environment for Python 3.x.
127
+ clean Delete build artifacts and cache files.
128
+ vscode Configure VSCode to work on this project.
129
+ """
130
+ ),
131
+ flush = True ,
132
+ ) # noqa: T201
133
+ if os .path .exists (".venv" ):
134
+ print ("\n Available tasks" , flush = True ) # noqa: T201
161
135
run ("default" , "duty" , "--list" )
162
136
return 0
163
137
0 commit comments