You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Note that this only affects string arguments that go through `shlex` splitting. `Path` objects and arguments passed with `split=False` are not affected.
142
144
145
+
</details>
146
+
147
+
148
+
## Managing directory and environment variables
149
+
150
+
By default, all commands are executed in the same directory and with the same environment variables as the parent process. However, this can be changed.
151
+
152
+
Pass a string or a `Path` object containing the directory path as the `directory` argument to change the directory itself:
153
+
154
+
```python
155
+
from pathlib import Path
156
+
157
+
run(
158
+
'python -c "import os; print(os.getcwd())"',
159
+
directory=Path('project'),
160
+
)
161
+
```
162
+
163
+
Relative paths are resolved from the parent process's current working directory at the moment `run` is called, so values like `.`, `..`, and `./../.././project/` are valid when they point to an existing directory:
`directory` is separate from [command parsing](#command-parsing). It is not split with `shlex`, and it is not affected by `split` or `double_backslash`. A directory path containing spaces is passed as one directory path:
170
+
171
+
```python
172
+
run('python -c pass', directory='project with spaces')
173
+
```
174
+
175
+
`directory` does not perform shell-style expansion. If you want a path under your home directory, expand it yourself:
176
+
177
+
```python
178
+
from pathlib import Path
179
+
180
+
run('python -c pass', directory=Path.home())
181
+
```
182
+
183
+
> ⚠️ If the directory is “broken” — for example, if it does not exist, or if there is a file at the specified path instead of a directory — a `suby.errors.WrongDirectoryError` exception will be raised. This exception will not be [caught](#exceptions) if `catch_exceptions=True` is used.
184
+
185
+
Use `env` when the subprocess should receive exactly the variables you provide:
> ↑ When `env` is provided, variables from the current process are not added automatically. `env={}` means a truly empty environment, which may make some executables fail on platforms that require system variables.
196
+
197
+
Use `add_env` to start with the current process environment and add or override selected variables:
#> 2024-02-22 02:15:08,155 [INFO] The beginning of the execution of the command "python -c pass".
195
-
#> 2024-02-22 02:15:08,190 [INFO] The command "python -c pass" has been successfully executed.
271
+
#> 2024-02-22 02:15:08,155 [INFO] The beginning of the execution of the command "python -c pass".
272
+
#> 2024-02-22 02:15:08,190 [INFO] The command "python -c pass" has been successfully executed.
196
273
```
197
274
198
275
The message about the start of the command execution is always logged at the `INFO`[level](https://docs.python.org/3/library/logging.html#logging-levels). If the command is completed successfully, the completion message will also be at the `INFO` level. If the command fails, it will be at the `ERROR` level:
#> 2024-02-22 02:20:25,549 [INFO] The beginning of the execution of the command "python -c "raise ValueError"".
203
-
#> 2024-02-22 02:20:25,590 [ERROR] Error when executing the command "python -c "raise ValueError"".
279
+
#> 2024-02-22 02:20:25,549 [INFO] The beginning of the execution of the command "python -c "raise ValueError"".
280
+
#> 2024-02-22 02:20:25,590 [ERROR] Error when executing the command "python -c "raise ValueError"".
204
281
```
205
282
206
283
If you don't need these details, simply omit the logger argument.
@@ -223,7 +300,7 @@ try:
223
300
run('python -c 1/0')
224
301
except RunningCommandError as e:
225
302
print(e)
226
-
#> Error when executing the command "python -c 1/0".
303
+
#> Error when executing the command "python -c 1/0".
227
304
```
228
305
229
306
2. If the subprocess cannot be started, `suby` raises `RunningCommandError` with a startup-specific message and chains the original `OSError` as `__cause__`. In this case, the attached `result.stdout` and `result.stderr` stay empty because the process never started:
@@ -235,11 +312,11 @@ try:
235
312
run('definitely_missing_command')
236
313
except RunningCommandError as e:
237
314
print(e)
238
-
#> The executable for the command "definitely_missing_command" was not found.
315
+
#> The executable for the command "definitely_missing_command" was not found.
239
316
print(type(e.__cause__))
240
-
#> <class 'FileNotFoundError'>
317
+
#> <class 'FileNotFoundError'>
241
318
print(e.result.stderr)
242
-
#>
319
+
#>
243
320
```
244
321
245
322
3. If you pass a [cancellation token](https://cantok.readthedocs.io/en/latest/the_pattern/) when calling the command, and the token is canceled, an exception will be raised [corresponding to the type](https://cantok.readthedocs.io/en/latest/what_are_tokens/exceptions/) of the canceled token. [This feature](#working-with-cancellation-tokens) is integrated with the [cantok](https://cantok.readthedocs.io/en/latest/) library, so we recommend that you familiarize yourself with it first.
@@ -251,7 +328,7 @@ You can prevent `suby` from raising these exceptions. To do this, set the `catch
251
328
```python
252
329
result = run('python -c "import time; time.sleep(10_000)"', timeout=1, catch_exceptions=True)
`catch_exceptions=True` applies to the four subprocess-related cases above. Invalid [directory](#changing-directories) values still raise their validation exceptions before a subprocess is started.
347
+
269
348
<details>
270
349
<summary>Notes about callback and token errors</summary>
271
350
@@ -300,15 +379,15 @@ from cantok import ConditionToken
300
379
301
380
token = ConditionToken(lambda: randint(1, 1000) ==7) # This token will be canceled when a random unlikely event occurs.
#> cantok.errors.ConditionCancellationError: The cancellation condition was satisfied.
382
+
#> cantok.errors.ConditionCancellationError: The cancellation condition was satisfied.
304
383
```
305
384
306
385
However, if you pass the `catch_exceptions=True` argument, the exception will not be raised (see [Exceptions](#exceptions)). Instead, you will get the [usual result](#run-subprocess-and-look-at-the-result) of calling `run` with the `killed_by_token=True` flag:
except TimeoutCancellationError as e: # As you can see, TimeoutCancellationError is available in the suby module.
337
416
print(e)
338
-
#> The timeout of 1 seconds has expired.
417
+
#> The timeout of 1 seconds has expired.
339
418
```
340
419
341
420
Just as with [regular cancellation tokens](#working-with-cancellation-tokens), you can prevent exceptions from being raised using the `catch_exceptions=True` argument:
0 commit comments