@@ -9,13 +9,11 @@ import subprocess
99import sys
1010from contextlib import contextmanager
1111from pathlib import Path
12+ from textwrap import dedent
1213from typing import Any , Iterator
1314
1415PYTHON_VERSIONS = os .getenv ("PYTHON_VERSIONS" , "3.8 3.9 3.10 3.11 3.12 3.13" ).split ()
1516
16- exe = ""
17- prefix = ""
18-
1917
2018def shell (cmd : str , capture_output : bool = False , ** kwargs : Any ) -> str | None :
2119 """Run a shell command."""
@@ -37,18 +35,11 @@ def environ(**kwargs: str) -> Iterator[None]:
3735 os .environ .update (original )
3836
3937
40- def uv_install () -> None :
38+ def uv_install (venv : Path ) -> None :
4139 """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+
5243
5344def setup () -> None :
5445 """Setup the project."""
@@ -59,47 +50,27 @@ def setup() -> None:
5950 default_venv = Path (".venv" )
6051 if not default_venv .exists ():
6152 shell ("uv venv --python python" )
62- uv_install ()
53+ uv_install (default_venv )
6354
6455 if PYTHON_VERSIONS :
6556 for version in PYTHON_VERSIONS :
6657 print (f"\n Installing dependencies (python{ version } )" ) # noqa: T201
6758 venv_path = Path (f".venvs/{ version } " )
6859 if not venv_path .exists ():
6960 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 )
9163
9264
9365def run (version : str , cmd : str , * args : str , ** kwargs : Any ) -> None :
9466 """Run a command in a virtual environment."""
9567 kwargs = {"check" : True , ** kwargs }
9668 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
9971 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
10374
10475
10576def multirun (cmd : str , * args : str , ** kwargs : Any ) -> None :
@@ -124,10 +95,10 @@ def clean() -> None:
12495 for path in paths_to_clean :
12596 shell (f"rm -rf { path } " )
12697
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 )
131102
132103
133104def vscode () -> None :
@@ -143,21 +114,24 @@ def main() -> int:
143114 if len (args ) > 1 :
144115 run ("default" , "duty" , "--help" , args [1 ])
145116 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
161135 run ("default" , "duty" , "--list" )
162136 return 0
163137
0 commit comments