@@ -89,74 +89,45 @@ fn check_impl(
89
89
90
90
if python_lint {
91
91
eprintln ! ( "linting python files" ) ;
92
- let mut cfg_args_ruff = cfg_args. clone ( ) ;
93
- let mut file_args_ruff = file_args. clone ( ) ;
94
-
95
- let mut cfg_path = root_path. to_owned ( ) ;
96
- cfg_path. extend ( RUFF_CONFIG_PATH ) ;
97
- let mut cache_dir = outdir. to_owned ( ) ;
98
- cache_dir. extend ( RUFF_CACHE_PATH ) ;
99
-
100
- cfg_args_ruff. extend ( [
101
- "--config" . as_ref ( ) ,
102
- cfg_path. as_os_str ( ) ,
103
- "--cache-dir" . as_ref ( ) ,
104
- cache_dir. as_os_str ( ) ,
105
- ] ) ;
106
-
107
- if file_args_ruff. is_empty ( ) {
108
- file_args_ruff. push ( root_path. as_os_str ( ) ) ;
109
- }
110
-
111
- let mut args = merge_args ( & cfg_args_ruff, & file_args_ruff) ;
112
- args. insert ( 0 , "check" . as_ref ( ) ) ;
113
- let res = py_runner ( py_path. as_ref ( ) . unwrap ( ) , true , None , "ruff" , & args) ;
92
+ let py_path = py_path. as_ref ( ) . unwrap ( ) ;
93
+ let res = run_ruff ( root_path, outdir, py_path, & cfg_args, & file_args, & [ "check" . as_ref ( ) ] ) ;
114
94
115
95
if res. is_err ( ) && show_diff {
116
96
eprintln ! ( "\n python linting failed! Printing diff suggestions:" ) ;
117
97
118
- args. insert ( 1 , "--diff" . as_ref ( ) ) ;
119
- let _ = py_runner ( py_path. as_ref ( ) . unwrap ( ) , true , None , "ruff" , & args) ;
98
+ let _ = run_ruff ( root_path, outdir, py_path, & cfg_args, & file_args, & [
99
+ "check" . as_ref ( ) ,
100
+ "--diff" . as_ref ( ) ,
101
+ ] ) ;
120
102
}
121
103
// Rethrow error
122
104
let _ = res?;
123
105
}
124
106
125
107
if python_fmt {
126
- let mut cfg_args_ruff = cfg_args. clone ( ) ;
127
- let mut file_args_ruff = file_args. clone ( ) ;
128
-
108
+ let mut args: Vec < & OsStr > = vec ! [ "format" . as_ref( ) ] ;
129
109
if bless {
130
110
eprintln ! ( "formatting python files" ) ;
131
111
} else {
132
112
eprintln ! ( "checking python file formatting" ) ;
133
- cfg_args_ruff. push ( "--check" . as_ref ( ) ) ;
134
- }
135
-
136
- let mut cfg_path = root_path. to_owned ( ) ;
137
- cfg_path. extend ( RUFF_CONFIG_PATH ) ;
138
- let mut cache_dir = outdir. to_owned ( ) ;
139
- cache_dir. extend ( RUFF_CACHE_PATH ) ;
140
-
141
- cfg_args_ruff. extend ( [ "--config" . as_ref ( ) , cfg_path. as_os_str ( ) ] ) ;
142
-
143
- if file_args_ruff. is_empty ( ) {
144
- file_args_ruff. push ( root_path. as_os_str ( ) ) ;
113
+ args. push ( "--check" . as_ref ( ) ) ;
145
114
}
146
115
147
- let mut args = merge_args ( & cfg_args_ruff, & file_args_ruff) ;
148
- args. insert ( 0 , "format" . as_ref ( ) ) ;
149
- let res = py_runner ( py_path. as_ref ( ) . unwrap ( ) , true , None , "ruff" , & args) ;
116
+ let py_path = py_path. as_ref ( ) . unwrap ( ) ;
117
+ let res = run_ruff ( root_path, outdir, py_path, & cfg_args, & file_args, & args) ;
150
118
151
- if res. is_err ( ) && show_diff {
152
- eprintln ! ( "\n python formatting does not match! Printing diff:" ) ;
153
-
154
- args. insert ( 0 , "--diff" . as_ref ( ) ) ;
155
- let _ = py_runner ( py_path. as_ref ( ) . unwrap ( ) , true , None , "ruff" , & args) ;
156
- }
157
119
if res. is_err ( ) && !bless {
120
+ if show_diff {
121
+ eprintln ! ( "\n python formatting does not match! Printing diff:" ) ;
122
+
123
+ let _ = run_ruff ( root_path, outdir, py_path, & cfg_args, & file_args, & [
124
+ "format" . as_ref ( ) ,
125
+ "--diff" . as_ref ( ) ,
126
+ ] ) ;
127
+ }
158
128
eprintln ! ( "rerun tidy with `--extra-checks=py:fmt --bless` to reformat Python code" ) ;
159
129
}
130
+
160
131
// Rethrow error
161
132
let _ = res?;
162
133
}
@@ -247,6 +218,38 @@ fn check_impl(
247
218
Ok ( ( ) )
248
219
}
249
220
221
+ fn run_ruff (
222
+ root_path : & Path ,
223
+ outdir : & Path ,
224
+ py_path : & Path ,
225
+ cfg_args : & [ & OsStr ] ,
226
+ file_args : & [ & OsStr ] ,
227
+ ruff_args : & [ & OsStr ] ,
228
+ ) -> Result < ( ) , Error > {
229
+ let mut cfg_args_ruff = cfg_args. into_iter ( ) . copied ( ) . collect :: < Vec < _ > > ( ) ;
230
+ let mut file_args_ruff = file_args. into_iter ( ) . copied ( ) . collect :: < Vec < _ > > ( ) ;
231
+
232
+ let mut cfg_path = root_path. to_owned ( ) ;
233
+ cfg_path. extend ( RUFF_CONFIG_PATH ) ;
234
+ let mut cache_dir = outdir. to_owned ( ) ;
235
+ cache_dir. extend ( RUFF_CACHE_PATH ) ;
236
+
237
+ cfg_args_ruff. extend ( [
238
+ "--config" . as_ref ( ) ,
239
+ cfg_path. as_os_str ( ) ,
240
+ "--cache-dir" . as_ref ( ) ,
241
+ cache_dir. as_os_str ( ) ,
242
+ ] ) ;
243
+
244
+ if file_args_ruff. is_empty ( ) {
245
+ file_args_ruff. push ( root_path. as_os_str ( ) ) ;
246
+ }
247
+
248
+ let mut args: Vec < & OsStr > = ruff_args. into_iter ( ) . copied ( ) . collect ( ) ;
249
+ args. extend ( merge_args ( & cfg_args_ruff, & file_args_ruff) ) ;
250
+ py_runner ( py_path, true , None , "ruff" , & args)
251
+ }
252
+
250
253
/// Helper to create `cfg1 cfg2 -- file1 file2` output
251
254
fn merge_args < ' a > ( cfg_args : & [ & ' a OsStr ] , file_args : & [ & ' a OsStr ] ) -> Vec < & ' a OsStr > {
252
255
let mut args = cfg_args. to_owned ( ) ;
@@ -321,8 +324,16 @@ fn get_or_create_venv(venv_path: &Path, src_reqs_path: &Path) -> Result<PathBuf,
321
324
fn create_venv_at_path ( path : & Path ) -> Result < ( ) , Error > {
322
325
/// Preferred python versions in order. Newest to oldest then current
323
326
/// development versions
324
- const TRY_PY : & [ & str ] =
325
- & [ "python3.11" , "python3.10" , "python3.9" , "python3" , "python" , "python3.12" , "python3.13" ] ;
327
+ const TRY_PY : & [ & str ] = & [
328
+ "python3.13" ,
329
+ "python3.12" ,
330
+ "python3.11" ,
331
+ "python3.10" ,
332
+ "python3.9" ,
333
+ "python3" ,
334
+ "python" ,
335
+ "python3.14" ,
336
+ ] ;
326
337
327
338
let mut sys_py = None ;
328
339
let mut found = Vec :: new ( ) ;
@@ -357,22 +368,40 @@ fn create_venv_at_path(path: &Path) -> Result<(), Error> {
357
368
return Err ( ret) ;
358
369
} ;
359
370
360
- eprintln ! ( "creating virtual environment at '{}' using '{sys_py}'" , path. display( ) ) ;
361
- let out = Command :: new ( sys_py) . args ( [ "-m" , "virtualenv" ] ) . arg ( path) . output ( ) . unwrap ( ) ;
371
+ // First try venv, which should be packaged in the Python3 standard library.
372
+ // If it is not available, try to create the virtual environment using the
373
+ // virtualenv package.
374
+ if try_create_venv ( sys_py, path, "venv" ) . is_ok ( ) {
375
+ return Ok ( ( ) ) ;
376
+ }
377
+ try_create_venv ( sys_py, path, "virtualenv" )
378
+ }
379
+
380
+ fn try_create_venv ( python : & str , path : & Path , module : & str ) -> Result < ( ) , Error > {
381
+ eprintln ! (
382
+ "creating virtual environment at '{}' using '{python}' and '{module}'" ,
383
+ path. display( )
384
+ ) ;
385
+ let out = Command :: new ( python) . args ( [ "-m" , module] ) . arg ( path) . output ( ) . unwrap ( ) ;
362
386
363
387
if out. status . success ( ) {
364
388
return Ok ( ( ) ) ;
365
389
}
366
390
367
391
let stderr = String :: from_utf8_lossy ( & out. stderr ) ;
368
- let err = if stderr. contains ( "No module named virtualenv" ) {
392
+ let err = if stderr. contains ( & format ! ( "No module named {module}" ) ) {
369
393
Error :: Generic ( format ! (
370
- "virtualenv not found: you may need to install it \
371
- (`{sys_py} -m pip install virtualenv`)"
394
+ r#"{module} not found: you may need to install it:
395
+ `{python} -m pip install {module}`
396
+ If you see an error about "externally managed environment" when running the above command,
397
+ either install `{module}` using your system package manager
398
+ (e.g. `sudo apt-get install {python}-{module}`) or create a virtual environment manually, install
399
+ `{module}` in it and then activate it before running tidy.
400
+ "#
372
401
) )
373
402
} else {
374
403
Error :: Generic ( format ! (
375
- "failed to create venv at '{}' using {sys_py }: {stderr}" ,
404
+ "failed to create venv at '{}' using {python} -m {module }: {stderr}" ,
376
405
path. display( )
377
406
) )
378
407
} ;
0 commit comments