skilleter-thingy 0.0.40__py3-none-any.whl → 0.0.42__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.

Potentially problematic release.


This version of skilleter-thingy might be problematic. Click here for more details.

Files changed (68) hide show
  1. skilleter_thingy/__init__.py +6 -0
  2. skilleter_thingy/addpath.py +107 -0
  3. skilleter_thingy/borger.py +269 -0
  4. skilleter_thingy/console_colours.py +63 -0
  5. skilleter_thingy/diskspacecheck.py +67 -0
  6. skilleter_thingy/docker_purge.py +113 -0
  7. skilleter_thingy/ffind.py +536 -0
  8. skilleter_thingy/ggit.py +90 -0
  9. skilleter_thingy/ggrep.py +154 -0
  10. skilleter_thingy/git_br.py +180 -0
  11. skilleter_thingy/git_ca.py +142 -0
  12. skilleter_thingy/git_cleanup.py +287 -0
  13. skilleter_thingy/git_co.py +220 -0
  14. skilleter_thingy/git_common.py +61 -0
  15. skilleter_thingy/git_hold.py +154 -0
  16. skilleter_thingy/git_mr.py +92 -0
  17. skilleter_thingy/git_parent.py +77 -0
  18. skilleter_thingy/git_review.py +1428 -0
  19. skilleter_thingy/git_update.py +385 -0
  20. skilleter_thingy/git_wt.py +96 -0
  21. skilleter_thingy/gitcmp_helper.py +322 -0
  22. skilleter_thingy/gitprompt.py +274 -0
  23. skilleter_thingy/gl.py +174 -0
  24. skilleter_thingy/gphotosync.py +610 -0
  25. skilleter_thingy/linecount.py +155 -0
  26. skilleter_thingy/moviemover.py +133 -0
  27. skilleter_thingy/photodupe.py +136 -0
  28. skilleter_thingy/phototidier.py +248 -0
  29. skilleter_thingy/py_audit.py +131 -0
  30. skilleter_thingy/readable.py +270 -0
  31. skilleter_thingy/remdir.py +126 -0
  32. skilleter_thingy/rmdupe.py +550 -0
  33. skilleter_thingy/rpylint.py +91 -0
  34. skilleter_thingy/splitpics.py +99 -0
  35. skilleter_thingy/strreplace.py +82 -0
  36. skilleter_thingy/sysmon.py +435 -0
  37. skilleter_thingy/tfm.py +920 -0
  38. skilleter_thingy/tfparse.py +101 -0
  39. skilleter_thingy/thingy/__init__.py +6 -0
  40. skilleter_thingy/thingy/colour.py +213 -0
  41. skilleter_thingy/thingy/dc_curses.py +278 -0
  42. skilleter_thingy/thingy/dc_defaults.py +221 -0
  43. skilleter_thingy/thingy/dc_util.py +50 -0
  44. skilleter_thingy/thingy/dircolors.py +308 -0
  45. skilleter_thingy/thingy/docker.py +95 -0
  46. skilleter_thingy/thingy/files.py +142 -0
  47. skilleter_thingy/thingy/git.py +1371 -0
  48. skilleter_thingy/thingy/git2.py +1307 -0
  49. skilleter_thingy/thingy/gitlab.py +193 -0
  50. skilleter_thingy/thingy/logger.py +112 -0
  51. skilleter_thingy/thingy/path.py +156 -0
  52. skilleter_thingy/thingy/popup.py +87 -0
  53. skilleter_thingy/thingy/process.py +112 -0
  54. skilleter_thingy/thingy/run.py +334 -0
  55. skilleter_thingy/thingy/tfm_pane.py +595 -0
  56. skilleter_thingy/thingy/tidy.py +160 -0
  57. skilleter_thingy/trimpath.py +84 -0
  58. skilleter_thingy/window_rename.py +92 -0
  59. skilleter_thingy/xchmod.py +125 -0
  60. skilleter_thingy/yamlcheck.py +89 -0
  61. {skilleter_thingy-0.0.40.dist-info → skilleter_thingy-0.0.42.dist-info}/METADATA +5 -1
  62. skilleter_thingy-0.0.42.dist-info/RECORD +66 -0
  63. {skilleter_thingy-0.0.40.dist-info → skilleter_thingy-0.0.42.dist-info}/entry_points.txt +1 -0
  64. skilleter_thingy-0.0.42.dist-info/top_level.txt +1 -0
  65. skilleter_thingy-0.0.40.dist-info/RECORD +0 -6
  66. skilleter_thingy-0.0.40.dist-info/top_level.txt +0 -1
  67. {skilleter_thingy-0.0.40.dist-info → skilleter_thingy-0.0.42.dist-info}/LICENSE +0 -0
  68. {skilleter_thingy-0.0.40.dist-info → skilleter_thingy-0.0.42.dist-info}/WHEEL +0 -0
@@ -0,0 +1,334 @@
1
+ #! /usr/bin/env python3
2
+
3
+ ################################################################################
4
+ """ Code for running a subprocess, optionally capturing stderr and/or stdout and
5
+ optionally echoing either or both to the console in realtime and storing.
6
+
7
+ Uses threads to capture and output stderr and stdout since this seems to be
8
+ the only way to do it (Popen does not have the ability to output the process
9
+ stdout output to the stdout output).
10
+
11
+ Intended for more versatile replacement for the thingy process.run() function
12
+ which can handle all combinations of foreground/background console/return
13
+ stderr/stdout/both options. """
14
+
15
+ # TODO: This does not run on Python versions <3.5 (so Ubuntu 14.04 is a problem!)
16
+ ################################################################################
17
+
18
+ ################################################################################
19
+ # Imports
20
+
21
+ import sys
22
+ import subprocess
23
+ import threading
24
+ import shlex
25
+
26
+ import thingy.colour as colour
27
+ import thingy.tidy as tidy
28
+
29
+ ################################################################################
30
+
31
+ class RunError(Exception):
32
+ """ Run exception """
33
+
34
+ def __init__(self, msg, status=1):
35
+ super().__init__(msg)
36
+ self.msg = msg
37
+ self.status = status
38
+
39
+ ################################################################################
40
+
41
+ def capture_output(cmd, input_stream, output_streams, ansi_clean):
42
+ """ Capture data from a stream (input_stream), optionally
43
+ outputting it (if output_streams is not None and optionally
44
+ saving it into a variable (data, if not None), terminating
45
+ when the specified command (cmd, which is presumed to be the process
46
+ outputting to the input stream) exits.
47
+ TODO: Use of convert_ansi should be controlled via a parameter (off/light/dark)
48
+ TODO: Another issue is that readline() only returns at EOF or EOL, so if you get a prompt "Continue?" with no newline you do not see it until after you respond to it.
49
+ """
50
+
51
+ while True:
52
+ output = input_stream.readline()
53
+
54
+ if output:
55
+ if output_streams:
56
+ for stream in output_streams:
57
+ if isinstance(stream, list):
58
+ stream.append(output.rstrip())
59
+ else:
60
+ if stream in (sys.stdout, sys.stderr):
61
+ stream.write(tidy.convert_ansi(output))
62
+ elif ansi_clean:
63
+ stream.write(colour.clean(output))
64
+ else:
65
+ stream.write(output)
66
+
67
+ elif cmd.poll() is not None:
68
+ return
69
+
70
+ ################################################################################
71
+
72
+ def capture_continuous(cmd, input_stream, output_streams, ansi_clean):
73
+ """ Capture data from a stream (input_stream), optionally
74
+ outputting it (if output_streams is not None and optionally
75
+ saving it into a variable (data, if not None), terminating
76
+ when the specified command (cmd, which is presumed to be the process
77
+ outputting to the input stream) exits.
78
+ TODO: Use of convert_ansi should be controlled via a parameter (off/light/dark)
79
+ TODO: ansi_clean not implemented
80
+ """
81
+
82
+ output_buffer = []
83
+
84
+ while True:
85
+ output = input_stream.read(1)
86
+
87
+ if output:
88
+ if output_streams:
89
+ for stream in output_streams:
90
+ if isinstance(stream, list):
91
+ if output == '\n':
92
+ stream.append(''.join(output_buffer))
93
+ output_buffer = []
94
+ else:
95
+ output_buffer.append(output)
96
+ else:
97
+ stream.write(output)
98
+ stream.flush()
99
+
100
+ elif cmd.poll() is not None:
101
+ if output_buffer:
102
+ stream.append(''.join(output_buffer))
103
+
104
+ return
105
+
106
+ ################################################################################
107
+
108
+ def process(command,
109
+ stdout=None, stderr=None,
110
+ return_stdout=False, return_stderr=False,
111
+ shell=False,
112
+ output=None,
113
+ ansi_clean=False,
114
+ exception=True,
115
+ continuous=False):
116
+ """ Run an external command.
117
+
118
+ stdout and stderr indicate whether stdout/err are output and/or sent to a file and/or stored in a variable.
119
+ They can be boolean (True: output to sys.stdout/err, False: Do nothing), a file handle or a variable, or an
120
+ array of any number of these (except booleans).
121
+
122
+ return_stdout and return_stderr indicate whether stdout/err should be returned from the function (setting
123
+ these to False saves memory if the output is not required).
124
+
125
+ If shell is True the command will be run in a shell and wildcard arguments expanded
126
+
127
+ If exception is True an exception will be raised if the command returns a non-zero status
128
+
129
+ If output is True then stdout and stderr are both output as if stdout=True and stderr=True (in addition to
130
+ any other values passed in those parameters)
131
+
132
+ If ansi_clean is True then ANSI control sequences are removed from any streams in stdout and stderr but
133
+ not from the console output.
134
+
135
+ If continuous is True then output is processed character-by-character (normally for use when output=True)
136
+ TODO: Currently this causes the ansi_clean option to be ignored
137
+
138
+ The return value is a tuple consisting of the status code, captured stdout (if any) and captured
139
+ stderr (if any).
140
+
141
+ Will raise OSError if the command could not be run and RunError if exception is True and the
142
+ command returned a non-zero status code. """
143
+
144
+ # If stdout/stderr are booleans then output to stdout/stderr if True, else discard output
145
+
146
+ if isinstance(stdout, bool):
147
+ stdout = sys.stdout if stdout else None
148
+
149
+ if isinstance(stderr, bool):
150
+ stderr = sys.stderr if stderr else None
151
+
152
+ # If stdout/stderr are not arrays then make them so
153
+
154
+ if not isinstance(stdout, list):
155
+ stdout = [stdout] if stdout else []
156
+
157
+ if not isinstance(stderr, list):
158
+ stderr = [stderr] if stderr else []
159
+
160
+ # If output is True then add stderr/out to the list of outputs
161
+
162
+ if output:
163
+ if sys.stdout not in stdout:
164
+ stdout.append(sys.stdout)
165
+
166
+ if sys.stderr not in stderr:
167
+ stderr.append(sys.stderr)
168
+
169
+ # Capture stdout/stderr to arrays unless asked not to
170
+
171
+ stdout_data = []
172
+ stderr_data = []
173
+
174
+ if return_stdout:
175
+ stdout.append(stdout_data)
176
+
177
+ if return_stderr:
178
+ stderr.append(stderr_data)
179
+
180
+ # If running via the shell then the command should be a string, otherwise
181
+ # it should be an array
182
+
183
+ if shell:
184
+ if not isinstance(command, str):
185
+ command = ' '.join(command)
186
+ else:
187
+ if isinstance(command, str):
188
+ command = shlex.split(command, comments=True)
189
+
190
+ # Use a pipe for stdout/stderr if are are capturing it
191
+ # and send it to /dev/null if we don't care about it at all.
192
+
193
+ if stdout == [sys.stdout] and not stderr:
194
+ stdout_stream = subprocess.STDOUT
195
+ stderr_stream = subprocess.DEVNULL
196
+ else:
197
+ stdout_stream = subprocess.PIPE if stdout else subprocess.DEVNULL
198
+ stderr_stream = subprocess.PIPE if stderr else subprocess.DEVNULL
199
+
200
+ # Run the command with no buffering and capturing output if we
201
+ # want it - this will raise OSError if there was a problem running
202
+ # the command.
203
+
204
+ cmd = subprocess.Popen(command,
205
+ bufsize=0,
206
+ stdout=stdout_stream,
207
+ stderr=stderr_stream,
208
+ text=True,
209
+ errors='ignore',
210
+ encoding='ascii',
211
+ shell=shell)
212
+
213
+ # Create threads to capture stderr and/or stdout if necessary
214
+
215
+ if stdout_stream == subprocess.PIPE:
216
+ stdout_thread = threading.Thread(target=capture_continuous if continuous else capture_output, args=(cmd, cmd.stdout, stdout, ansi_clean), daemon=True)
217
+ stdout_thread.start()
218
+ else:
219
+ stdout_thread = None
220
+
221
+ if stderr_stream == subprocess.PIPE:
222
+ stderr_thread = threading.Thread(target=capture_continuous if continuous else capture_output, args=(cmd, cmd.stderr, stderr, ansi_clean), daemon=True)
223
+ stderr_thread.start()
224
+ else:
225
+ stderr_thread = None
226
+
227
+ # Wait until the command terminates (and set the returncode)
228
+
229
+ if stdout_thread:
230
+ stdout_thread.join()
231
+
232
+ if stderr_thread:
233
+ stderr_thread.join()
234
+
235
+ cmd.wait()
236
+
237
+ # If the command failed, raise an exception (if required)
238
+
239
+ if exception and cmd.returncode:
240
+ if return_stderr:
241
+ raise RunError('\n'.join(stderr_data))
242
+ else:
243
+ raise RunError('Error %d running "%s"' % (cmd.returncode, (command if isinstance(command, str) else ' '.join(command))))
244
+
245
+ # Return status, stdout, stderr (the latter 2 may be empty if we did not capture data).
246
+
247
+ return {'status': cmd.returncode, 'stdout': stdout_data, 'stderr': stderr_data}
248
+
249
+ ################################################################################
250
+
251
+ def run(command,
252
+ stdout=None, stderr=None,
253
+ shell=False,
254
+ output=None,
255
+ ansi_clean=False,
256
+ exception=True,
257
+ continuous=False):
258
+ """ Simple interface to the process() function
259
+ Has the same parameters, with the same defaults.
260
+ The return value is either the data output to stdout, if any
261
+ or the data output to stderr otherwise.
262
+ The status code is not returned, but the function will raise an exception
263
+ by default if it is non-zero """
264
+
265
+ result = process(command=command,
266
+ stdout=stdout, stderr=stderr,
267
+ return_stdout=True, return_stderr=True,
268
+ shell=shell,
269
+ output=output,
270
+ ansi_clean=ansi_clean,
271
+ exception=exception,
272
+ continuous=continuous)
273
+
274
+ return result['stdout'] if result['stdout'] else result['stderr']
275
+
276
+ ################################################################################
277
+
278
+ def status(command, shell=False, output=False):
279
+ """ Alternative simple interface to the process() function
280
+ Just takes a command and the shell flag.
281
+ Runs the command without capturing the output
282
+ Optionally outputting both stdout and stderr
283
+ and returns the status code.
284
+ Will only raise an exception if the command could not be run. """
285
+
286
+ return process(command,
287
+ stdout=output,
288
+ stderr=output,
289
+ shell=shell,
290
+ exception=False)['status']
291
+
292
+ ################################################################################
293
+
294
+ if __name__ == '__main__':
295
+ def test_run(cmd,
296
+ stdout=None, stderr=None,
297
+ return_stdout=True, return_stderr=True,
298
+ shell=False,
299
+ exception=True):
300
+ """ Test wrapper for the process() function. """
301
+
302
+ print('-' * 80)
303
+ print('Running: %s' % (cmd if isinstance(cmd, str) else ' '.join(cmd)))
304
+
305
+ result = process(cmd,
306
+ stdout=stdout, stderr=stderr,
307
+ return_stdout=return_stdout, return_stderr=return_stderr,
308
+ shell=shell,
309
+ exception=exception)
310
+
311
+ print('Status: %d' % result['status'])
312
+
313
+ def test():
314
+ """ Test code """
315
+
316
+ test_run('echo nothing')
317
+
318
+ test_run(['ls', '-l', 'run_jed'])
319
+ test_run(['ls -l run_*'], stdout=True, shell=True)
320
+ test_run('false', exception=False)
321
+ test_run('true', stdout=sys.stdout, exception=False)
322
+ test_run(['git', 'status'], stdout=sys.stdout, stderr=sys.stderr, exception=False)
323
+
324
+ test_run(['make'], stderr=sys.stderr, exception=False)
325
+ test_run(['make'], stdout=sys.stdout, stderr=[sys.stderr], exception=False)
326
+ test_run(['make'], stdout=True, exception=False)
327
+ test_run(['make'], stdout=sys.stdout, exception=False)
328
+ test_run(['make'], exception=False)
329
+
330
+ output = []
331
+ test_run('ls -l x*; sleep 1; echo "Bye!"', stderr=[sys.stderr, output], stdout=sys.stdout, shell=True, return_stdout=False)
332
+ print('Output=%s' % output)
333
+
334
+ test()