iripau 1.0.0__py3-none-any.whl → 1.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- iripau/requests.py +81 -0
- iripau/subprocess.py +53 -18
- {iripau-1.0.0.dist-info → iripau-1.1.0.dist-info}/METADATA +2 -1
- {iripau-1.0.0.dist-info → iripau-1.1.0.dist-info}/RECORD +7 -6
- {iripau-1.0.0.dist-info → iripau-1.1.0.dist-info}/WHEEL +0 -0
- {iripau-1.0.0.dist-info → iripau-1.1.0.dist-info}/licenses/LICENSE +0 -0
- {iripau-1.0.0.dist-info → iripau-1.1.0.dist-info}/top_level.txt +0 -0
iripau/requests.py
ADDED
@@ -0,0 +1,81 @@
|
|
1
|
+
"""
|
2
|
+
Utilities for the requests module
|
3
|
+
"""
|
4
|
+
|
5
|
+
import requests
|
6
|
+
|
7
|
+
from curlify import to_curl
|
8
|
+
|
9
|
+
from iripau.subprocess import TeeStreams, Popen
|
10
|
+
|
11
|
+
|
12
|
+
def curlify(
|
13
|
+
response, compressed=False, verify=True, pretty=False,
|
14
|
+
hide_output=False, headers_to_hide=[], headers_to_omit=[],
|
15
|
+
stdout_tees: TeeStreams = [], add_global_stdout_tees=True,
|
16
|
+
stderr_tees: TeeStreams = [], add_global_stderr_tees=True,
|
17
|
+
prompt_tees: TeeStreams = [], add_global_prompt_tees=True,
|
18
|
+
echo=None
|
19
|
+
):
|
20
|
+
""" Simulate the request was executed by a curl subprocess.
|
21
|
+
The command and output can be echoed and/or sent to files as described
|
22
|
+
in subprocess.run
|
23
|
+
"""
|
24
|
+
request = response.request
|
25
|
+
if headers_to_hide or headers_to_omit:
|
26
|
+
request = request.copy()
|
27
|
+
|
28
|
+
for header in headers_to_omit:
|
29
|
+
if header in request.headers:
|
30
|
+
del request.headers[header]
|
31
|
+
|
32
|
+
for header in headers_to_hide:
|
33
|
+
if header in request.headers:
|
34
|
+
request.headers[header] = "***"
|
35
|
+
|
36
|
+
stdout = hide_output and b"***" or response.content
|
37
|
+
if not stdout.endswith(b"\n"):
|
38
|
+
stdout += b"\n"
|
39
|
+
stderr = ""
|
40
|
+
|
41
|
+
Popen.simulate(
|
42
|
+
cmd=to_curl(request, compressed, verify, pretty),
|
43
|
+
stdout=stdout,
|
44
|
+
stderr=stderr,
|
45
|
+
comment=f"{response.status_code} - {response.reason}",
|
46
|
+
stdout_tees=stdout_tees,
|
47
|
+
stderr_tees=stderr_tees,
|
48
|
+
prompt_tees=prompt_tees,
|
49
|
+
add_global_stdout_tees=add_global_stdout_tees,
|
50
|
+
add_global_stderr_tees=add_global_stderr_tees,
|
51
|
+
add_global_prompt_tees=add_global_prompt_tees,
|
52
|
+
echo=echo
|
53
|
+
)
|
54
|
+
|
55
|
+
|
56
|
+
class Session(requests.Session):
|
57
|
+
""" A requests.Session that accepts curlify arguments in the request method """
|
58
|
+
|
59
|
+
def request(
|
60
|
+
self, *args, compressed=False, pretty=False,
|
61
|
+
hide_output=False, headers_to_hide=[], headers_to_omit=[],
|
62
|
+
stdout_tees: TeeStreams = [], add_global_stdout_tees=True,
|
63
|
+
stderr_tees: TeeStreams = [], add_global_stderr_tees=True,
|
64
|
+
prompt_tees: TeeStreams = [], add_global_prompt_tees=True,
|
65
|
+
echo=None, **kwargs
|
66
|
+
):
|
67
|
+
response = super().request(*args, **kwargs)
|
68
|
+
|
69
|
+
verify = kwargs.get("verify")
|
70
|
+
if verify is None:
|
71
|
+
verify = self.verify
|
72
|
+
|
73
|
+
curlify(
|
74
|
+
response, compressed, verify, pretty,
|
75
|
+
hide_output, headers_to_hide, headers_to_omit,
|
76
|
+
stdout_tees, add_global_stdout_tees,
|
77
|
+
stderr_tees, add_global_stderr_tees,
|
78
|
+
prompt_tees, add_global_prompt_tees,
|
79
|
+
echo
|
80
|
+
)
|
81
|
+
return response
|
iripau/subprocess.py
CHANGED
@@ -37,6 +37,7 @@ GLOBAL_PROMPTS = set()
|
|
37
37
|
|
38
38
|
|
39
39
|
TeeStream = Union[io.IOBase, Callable[[], io.IOBase]]
|
40
|
+
TeeStreams = Iterable[TeeStream]
|
40
41
|
|
41
42
|
|
42
43
|
class PipeFile(SpooledTemporaryFile):
|
@@ -123,27 +124,21 @@ class Popen(subprocess.Popen):
|
|
123
124
|
|
124
125
|
def __init__(
|
125
126
|
self, args, *, cwd=None, env=None, encoding=None, errors=None, text=None,
|
126
|
-
stdout_tees:
|
127
|
-
stderr_tees:
|
128
|
-
prompt_tees:
|
127
|
+
stdout_tees: TeeStreams = [], add_global_stdout_tees=True,
|
128
|
+
stderr_tees: TeeStreams = [], add_global_stderr_tees=True,
|
129
|
+
prompt_tees: TeeStreams = [], add_global_prompt_tees=True,
|
129
130
|
echo=None, alias=None, comment=None, **kwargs
|
130
131
|
):
|
131
132
|
stdout = kwargs.get("stdout")
|
132
133
|
stderr = kwargs.get("stderr")
|
133
134
|
|
134
|
-
stdout_tees, stderr_tees, prompt_tees = self._get_tee_sets(
|
135
|
+
stdout_tees, stderr_tees, prompt_tees, err2out = self._get_tee_sets(
|
135
136
|
stdout_tees, add_global_stdout_tees,
|
136
137
|
stderr_tees, add_global_stderr_tees,
|
137
138
|
prompt_tees, add_global_prompt_tees,
|
138
139
|
echo, stdout, stderr
|
139
140
|
)
|
140
141
|
|
141
|
-
if stderr is STDOUT:
|
142
|
-
err2out = True
|
143
|
-
stderr_tees = set()
|
144
|
-
else:
|
145
|
-
err2out = False
|
146
|
-
|
147
142
|
stdout_fds = {tee.fileno() for tee in stdout_tees}
|
148
143
|
stderr_fds = {tee.fileno() for tee in stderr_tees}
|
149
144
|
prompt_fds = {tee.fileno() for tee in prompt_tees}
|
@@ -175,7 +170,7 @@ class Popen(subprocess.Popen):
|
|
175
170
|
self.stderr_process = stderr_process
|
176
171
|
|
177
172
|
@staticmethod
|
178
|
-
def _get_tee_files(tees:
|
173
|
+
def _get_tee_files(tees: TeeStreams):
|
179
174
|
return set(callable(tee) and tee() or tee for tee in tees)
|
180
175
|
|
181
176
|
@classmethod
|
@@ -217,12 +212,52 @@ class Popen(subprocess.Popen):
|
|
217
212
|
if stderr_tees:
|
218
213
|
stderr_tees.add(sys.stderr)
|
219
214
|
|
215
|
+
if stderr is STDOUT:
|
216
|
+
err2out = True
|
217
|
+
stderr_tees = set()
|
218
|
+
else:
|
219
|
+
err2out = False
|
220
|
+
|
220
221
|
return (
|
221
222
|
cls._get_tee_files(stdout_tees),
|
222
223
|
cls._get_tee_files(stderr_tees),
|
223
|
-
cls._get_tee_files(prompt_tees)
|
224
|
+
cls._get_tee_files(prompt_tees),
|
225
|
+
err2out
|
226
|
+
)
|
227
|
+
|
228
|
+
@classmethod
|
229
|
+
def simulate(
|
230
|
+
cls, cmd, stdout, stderr, encoding=None, errors=None, text=None, comment=None,
|
231
|
+
stdout_tees: TeeStreams = [], add_global_stdout_tees=True,
|
232
|
+
stderr_tees: TeeStreams = [], add_global_stderr_tees=True,
|
233
|
+
prompt_tees: TeeStreams = [], add_global_prompt_tees=True,
|
234
|
+
echo=None
|
235
|
+
):
|
236
|
+
stdout_tees, stderr_tees, prompt_tees, err2out = cls._get_tee_sets(
|
237
|
+
stdout_tees, add_global_stdout_tees,
|
238
|
+
stderr_tees, add_global_stderr_tees,
|
239
|
+
prompt_tees, add_global_prompt_tees,
|
240
|
+
echo, DEVNULL, DEVNULL
|
224
241
|
)
|
225
242
|
|
243
|
+
if not (stdout_tees or stderr_tees or prompt_tees):
|
244
|
+
return
|
245
|
+
|
246
|
+
stdout_fds = {tee.fileno() for tee in stdout_tees}
|
247
|
+
stderr_fds = {tee.fileno() for tee in stderr_tees}
|
248
|
+
prompt_fds = {tee.fileno() for tee in prompt_tees}
|
249
|
+
|
250
|
+
if prompt_fds:
|
251
|
+
stream_prompts(prompt_fds, cmd, None, None, err2out, comment)
|
252
|
+
|
253
|
+
if stdout_fds:
|
254
|
+
with Tee(PIPE, stdout_fds, DEVNULL, encoding, errors, text) as tee:
|
255
|
+
tee.communicate(stdout)
|
256
|
+
|
257
|
+
if stderr_fds:
|
258
|
+
with Tee(PIPE, stderr_fds, DEVNULL, encoding, errors, text) as tee:
|
259
|
+
tee.communicate(stderr)
|
260
|
+
|
226
261
|
def get_pids(self):
|
227
262
|
""" Return the pid for all of the processes in the tree """
|
228
263
|
output = run(
|
@@ -382,7 +417,7 @@ if subprocess.run(
|
|
382
417
|
stderr=DEVNULL
|
383
418
|
).stdout.splitlines()[-2:]
|
384
419
|
|
385
|
-
def stream_prompts(fds: Iterable[
|
420
|
+
def stream_prompts(fds: Iterable[int], cmd, cwd=None, env=None, err2out=False, comment=None):
|
386
421
|
""" Write shell prompt and command into file descriptors fds """
|
387
422
|
fds = normalize_outerr_fds(fds)
|
388
423
|
custom_env = {"CPS1": PS1, "CPS2": PS2}
|
@@ -392,7 +427,7 @@ if subprocess.run(
|
|
392
427
|
"(\n"
|
393
428
|
" IFS= read -r \"line\"\n"
|
394
429
|
" echo \"${CPS1@P}${line}\"\n"
|
395
|
-
" while IFS= read line; do\n"
|
430
|
+
" while IFS= read -r \"line\"; do\n"
|
396
431
|
" echo \"${CPS2@P}${line}\"\n"
|
397
432
|
" done\n"
|
398
433
|
") | " + quote(Tee.get_cmd(fds - {1}))
|
@@ -400,7 +435,7 @@ if subprocess.run(
|
|
400
435
|
subprocess.run(
|
401
436
|
["bash", "-c", script],
|
402
437
|
text=True,
|
403
|
-
input=shellify(cmd, err2out, comment),
|
438
|
+
input=shellify(cmd, err2out, comment) + "\n",
|
404
439
|
stdout=None if 1 in fds else DEVNULL,
|
405
440
|
stderr=None if 2 in fds else DEVNULL,
|
406
441
|
pass_fds=fds - {1, 2},
|
@@ -409,7 +444,7 @@ if subprocess.run(
|
|
409
444
|
check=True
|
410
445
|
)
|
411
446
|
else: # Use hard-coded PS1 and PS2 strings
|
412
|
-
def stream_prompts(fds: Iterable[
|
447
|
+
def stream_prompts(fds: Iterable[int], cmd, cwd=None, env=None, err2out=False, comment=None):
|
413
448
|
""" Write shell prompt and command into file descriptors fds """
|
414
449
|
cmd = shellify(cmd, err2out, comment) + "\n"
|
415
450
|
input = "$ " + "> ".join(cmd.splitlines(keepends=True))
|
@@ -449,7 +484,7 @@ def _output_context(kwargs, key, encoding, errors, text):
|
|
449
484
|
|
450
485
|
def run(
|
451
486
|
args, *, input=None, capture_output=False, timeout=None, check=False,
|
452
|
-
encoding=None, errors=None, text=None, sigterm_timeout=10, **kwargs
|
487
|
+
encoding=None, errors=None, text=None, sigterm_timeout=10, comment=None, **kwargs
|
453
488
|
):
|
454
489
|
""" A subprocess.run that instantiates this module's Popen """
|
455
490
|
if input is not None:
|
@@ -463,7 +498,7 @@ def run(
|
|
463
498
|
kwargs["stdout"] = FILE
|
464
499
|
kwargs["stderr"] = FILE
|
465
500
|
|
466
|
-
comment = f"timeout={timeout}" if timeout else
|
501
|
+
comment = " ".join((comment or "", f"timeout={timeout}" if timeout else "")).strip()
|
467
502
|
with (
|
468
503
|
_output_context(kwargs, "stdout", encoding, errors, text) as stdout_file,
|
469
504
|
_output_context(kwargs, "stderr", encoding, errors, text) as stderr_file,
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: iripau
|
3
|
-
Version: 1.
|
3
|
+
Version: 1.1.0
|
4
4
|
Summary: Python utilities focused on command execution
|
5
5
|
Author: Ricardo Quezada
|
6
6
|
Maintainer: Ricardo Quezada
|
@@ -14,6 +14,7 @@ Classifier: Programming Language :: Python
|
|
14
14
|
Requires-Python: >=3.7
|
15
15
|
Description-Content-Type: text/markdown
|
16
16
|
License-File: LICENSE
|
17
|
+
Requires-Dist: curlify
|
17
18
|
Requires-Dist: psutil
|
18
19
|
Dynamic: license-file
|
19
20
|
|
@@ -3,11 +3,12 @@ iripau/executable.py,sha256=W00UNJfMWwZ7cZkEvppwVWy8GaGfbr36eRx0BwaI6mA,3109
|
|
3
3
|
iripau/functools.py,sha256=Jyi0LdOx36Ih6s9TF4aFS3Xk-RW78YE2znB1PBWTAIo,2901
|
4
4
|
iripau/logging.py,sha256=dA-69y5MN8a_c95e_DOlULO0tc7t267okFi9iqJzrmg,2542
|
5
5
|
iripau/random.py,sha256=zC5GxmBdfVa6nAUZcv5gCLwBpZU3sA1TB71Cn311lHo,1023
|
6
|
+
iripau/requests.py,sha256=BJIlz2UzB7wNEHx0IZ-BF1UNfmRxXBhRaW86HBO0jII,2597
|
6
7
|
iripau/shutil.py,sha256=HwU4sUrStzAZjqbIMK7xm-NfjxMXHZx4lWAjwfBf4rw,2558
|
7
|
-
iripau/subprocess.py,sha256=
|
8
|
+
iripau/subprocess.py,sha256=mQDLrBgTOEJ_Ueb1nqIbRkrzMlnYWjfXS8kJsspMcsE,17684
|
8
9
|
iripau/threading.py,sha256=q-a6OuDrz3hg_5u2Q0eMG3hzu_IgGNBfEw-cI_pyaDo,8955
|
9
|
-
iripau-1.
|
10
|
-
iripau-1.
|
11
|
-
iripau-1.
|
12
|
-
iripau-1.
|
13
|
-
iripau-1.
|
10
|
+
iripau-1.1.0.dist-info/licenses/LICENSE,sha256=HyVuytGSiAUQ6ErWBHTqt1iSGHhLmlC8fO7jTCuR8dU,16725
|
11
|
+
iripau-1.1.0.dist-info/METADATA,sha256=U60idKE5l07kZz3VlMhNPWoHXZsco1DdkpKGGCgGqC0,810
|
12
|
+
iripau-1.1.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
13
|
+
iripau-1.1.0.dist-info/top_level.txt,sha256=y2HMFLCoP2EP7kbRIqkyCVIf_YRZfA0cYYLNK28U9cY,7
|
14
|
+
iripau-1.1.0.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|