1515
1616
1717PYTHON_VERSIONS = os .getenv ("PYTHON_VERSIONS" , "3.9 3.10 3.11 3.12 3.13 3.14" ).split ()
18+ PYTHON_DEV = "3.14"
1819
1920
2021def shell (cmd : str , * , capture_output : bool = False , ** kwargs : Any ) -> str | None :
@@ -67,16 +68,31 @@ def setup() -> None:
6768 uv_install (venv_path )
6869
6970
71+ class _RunError (subprocess .CalledProcessError ):
72+ def __init__ (self , * args : Any , python_version : str , ** kwargs : Any ):
73+ super ().__init__ (* args , ** kwargs )
74+ self .python_version = python_version
75+
76+
7077def run (version : str , cmd : str , * args : str , ** kwargs : Any ) -> None :
7178 """Run a command in a virtual environment."""
7279 kwargs = {"check" : True , ** kwargs }
7380 uv_run = ["uv" , "run" , "--no-sync" ]
74- if version == "default" :
75- with environ (UV_PROJECT_ENVIRONMENT = ".venv" ):
76- subprocess .run ([* uv_run , cmd , * args ], ** kwargs ) # noqa: S603, PLW1510
77- else :
78- with environ (UV_PROJECT_ENVIRONMENT = f".venvs/{ version } " , MULTIRUN = "1" ):
79- subprocess .run ([* uv_run , cmd , * args ], ** kwargs ) # noqa: S603, PLW1510
81+ try :
82+ if version == "default" :
83+ with environ (UV_PROJECT_ENVIRONMENT = ".venv" ):
84+ subprocess .run ([* uv_run , cmd , * args ], ** kwargs ) # noqa: S603, PLW1510
85+ else :
86+ with environ (UV_PROJECT_ENVIRONMENT = f".venvs/{ version } " , MULTIRUN = "1" ):
87+ subprocess .run ([* uv_run , cmd , * args ], ** kwargs ) # noqa: S603, PLW1510
88+ except subprocess .CalledProcessError as process :
89+ raise _RunError (
90+ returncode = process .returncode ,
91+ python_version = version ,
92+ cmd = process .cmd ,
93+ output = process .output ,
94+ stderr = process .stderr ,
95+ ) from process
8096
8197
8298def multirun (cmd : str , * args : str , ** kwargs : Any ) -> None :
@@ -144,19 +160,31 @@ def main() -> int:
144160 cmd = args .pop (0 )
145161
146162 if cmd == "run" :
147- run ("default" , * args )
163+ if not args :
164+ print ("make: run: missing command" , file = sys .stderr )
165+ return 1
166+ run ("default" , * args ) # ty: ignore[missing-argument]
148167 return 0
149168
150169 if cmd == "multirun" :
151- multirun (* args )
170+ if not args :
171+ print ("make: run: missing command" , file = sys .stderr )
172+ return 1
173+ multirun (* args ) # ty: ignore[missing-argument]
152174 return 0
153175
154176 if cmd == "allrun" :
155- allrun (* args )
177+ if not args :
178+ print ("make: run: missing command" , file = sys .stderr )
179+ return 1
180+ allrun (* args ) # ty: ignore[missing-argument]
156181 return 0
157182
158183 if cmd .startswith ("3." ):
159- run (cmd , * args )
184+ if not args :
185+ print ("make: run: missing command" , file = sys .stderr )
186+ return 1
187+ run (cmd , * args ) # ty: ignore[missing-argument]
160188 return 0
161189
162190 opts = []
@@ -183,7 +211,14 @@ def main() -> int:
183211if __name__ == "__main__" :
184212 try :
185213 sys .exit (main ())
186- except subprocess . CalledProcessError as process :
214+ except _RunError as process :
187215 if process .output :
188216 print (process .output , file = sys .stderr )
189- sys .exit (process .returncode )
217+ if (code := process .returncode ) == 139 : # noqa: PLR2004
218+ print (
219+ f"✗ (python{ process .python_version } ) '{ ' ' .join (process .cmd )} ' failed with return code { code } (segfault)" ,
220+ file = sys .stderr ,
221+ )
222+ if process .python_version == PYTHON_DEV :
223+ code = 0
224+ sys .exit (code )
0 commit comments