runps 4.0.0__tar.gz

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.
runps-4.0.0/AUTHORS.md ADDED
@@ -0,0 +1,22 @@
1
+ # Author
2
+
3
+ * Andrew Moffat <andrew.robert.moffat@gmail.com>
4
+
5
+
6
+ # Contributors
7
+
8
+ * Dmitry Medvinsky <dmedvinsky@gmail.com>
9
+ * Jure Žiberna
10
+ * Bahadır Kandemir
11
+ * Jannis Leidel <jezdez@enn.io>
12
+ * tingletech
13
+ * tdudziak
14
+ * Arjen Stolk
15
+ * nemec
16
+ * fruch
17
+ * Ralph Bean
18
+
19
+
20
+ # `runps` fork
21
+
22
+ * xapple
@@ -0,0 +1,19 @@
1
+ Copyright (C) 2011-2012 by Andrew Moffat
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ THE SOFTWARE.
@@ -0,0 +1 @@
1
+ include AUTHORS.md LICENSE.txt README.md
runps-4.0.0/PKG-INFO ADDED
@@ -0,0 +1,502 @@
1
+ Metadata-Version: 2.4
2
+ Name: runps
3
+ Version: 4.0.0
4
+ Summary: A small python utility for launching external processes easily..
5
+ Author: Andrew Moffat, Lucas Sinclair
6
+ License: Copyright (C) 2011-2012 by Andrew Moffat
7
+
8
+ Permission is hereby granted, free of charge, to any person obtaining a copy
9
+ of this software and associated documentation files (the "Software"), to deal
10
+ in the Software without restriction, including without limitation the rights
11
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12
+ copies of the Software, and to permit persons to whom the Software is
13
+ furnished to do so, subject to the following conditions:
14
+
15
+ The above copyright notice and this permission notice shall be included in
16
+ all copies or substantial portions of the Software.
17
+
18
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24
+ THE SOFTWARE.
25
+
26
+ Project-URL: Homepage, https://github.com/xapple/runps/
27
+ Description-Content-Type: text/markdown
28
+ License-File: LICENSE.txt
29
+ License-File: AUTHORS.md
30
+ Dynamic: license-file
31
+
32
+ `runps` version 4.0.0
33
+ =====================
34
+
35
+ #### This is a fork of the `sh` package (formely `pbs` package) that works on Linux, macOS and Windows.
36
+
37
+ | Package | *nix / Python 2 | *nix / Python 3 | Windows / Python 2 | Windows / Python 3 | Compatible forking* |
38
+ |-------------|-----------------|-----------------| --------------- | --------------- | ------------------- |
39
+ | [`sh`](https://github.com/amoffat/sh) | ✅ Works | ✅ Works | 🔴 Not supported | 🔴 Not supported | 🔴 Fails |
40
+ | `runps` | ✅ Works | ✅ Works | ✅ Works | ✅ Works | ✅ Works |
41
+
42
+ \* By compatible forking we mean a method of creating subprocesses that can work successfully inside a debugging environment such as the one provided by PyCharm.
43
+
44
+ ### Why do we need a different version of `sh`?
45
+
46
+ * First, in early 2012, the original `pbs` package was conceived by [@amoffat](https://github.com/amoffat/sh). It could launch subprocesses on both Unix and Windows environments with Python 2.
47
+
48
+ * In late 2012, the `pbs` project was renamed to `sh`, lots of functionality was added, but support for Windows [was completely dropped](http://amoffat.github.io/sh/sections/faq.html#will-windows-be-supported).
49
+
50
+ * For some time, the legacy `pbs` package was still used whenever one needs to launch external processes on Windows machines and was [still available](https://pypi.org/project/pbs/) at `pip install pbs`.
51
+
52
+ * The old `pbs` package was also used for its more compatible way of starting subprocesses. The current `sh` module is [not compatible](https://github.com/amoffat/sh/issues/475) with developing in PyCharm for instance.
53
+
54
+ * However, the last ever published version of `pbs` (v0.110 from Oct 20, 2012) does not work on Python 3. This package fixes that.
55
+
56
+ * `runps` works on all platforms and Python versions.
57
+
58
+
59
+ ### How do I install and use this package?
60
+
61
+ * You can install this version with this command:
62
+
63
+ `pip install runps`
64
+
65
+ * You can use this package with this import statement (if you are porting from `sh` code):
66
+
67
+ `import runps as sh`
68
+
69
+
70
+ ### What exactly did not work in Python 3?
71
+
72
+ This would be the traceback that the old `pbs v0.110` would produce:
73
+
74
+ c:\python37\lib\site-packages\pbs.py in __call__(self, *args, **kwargs)
75
+ 454 cwd=call_args["cwd"], stdin=stdin, stdout=stdout, stderr=stderr)
76
+ 455
77
+ --> 456 return RunningCommand(command_ran, process, call_args, actual_stdin)
78
+ 457
79
+ 458
80
+
81
+ c:\python37\lib\site-packages\pbs.py in __init__(self, command_ran, process, call_args,
82
+ stdin)
83
+ 166 if stdin: stdin = stdin.encode("utf8")
84
+ 167 self._stdout, self._stderr = self.process.communicate(stdin)
85
+ --> 168 self._handle_exit_code(self.process.wait())
86
+ 169
87
+ 170 def __enter__(self):
88
+
89
+ c:\python37\lib\site-packages\pbs.py in _handle_exit_code(self, rc)
90
+ 233 def _handle_exit_code(self, rc):
91
+ 234 if rc not in self.call_args["ok_code"]:
92
+ --> 235 raise get_rc_exc(rc)(self.command_ran, self._stdout, self._stderr)
93
+ 236
94
+ 237 def __len__(self):
95
+
96
+ c:\python37\lib\site-packages\pbs.py in __init__(self, full_cmd, stdout, stderr)
97
+ 93
98
+ 94 msg = "\n\nRan: %r\n\nSTDOUT:\n\n %s\n\nSTDERR:\n\n %s" %\
99
+ ---> 95 (full_cmd, tstdout.decode(), tstderr.decode())
100
+ 96 super(ErrorReturnCode, self).__init__(msg)
101
+ 97
102
+
103
+ AttributeError: 'str' object has no attribute 'decode'
104
+
105
+ This would occur when the program called exited with a non-zero return code.
106
+
107
+ * * *
108
+
109
+
110
+ Original documentation
111
+ ======================
112
+
113
+ runps is a unique subprocess wrapper that maps your system programs to
114
+ Python functions dynamically. runps helps you write shell scripts in
115
+ Python by giving you the good features of Bash (easy command calling, easy
116
+ piping) with all the power and flexibility of Python.
117
+
118
+ ```python
119
+ from runps import ifconfig
120
+ print ifconfig("eth0")
121
+ ```
122
+
123
+ runps is not a collection of system commands implemented in Python.
124
+
125
+ # Getting
126
+
127
+ $> pip install runps
128
+
129
+ # Usage
130
+
131
+ The easiest way to get up and running is to import runps
132
+ directly or import your program from runps:
133
+
134
+ ```python
135
+ import runps
136
+ print runps.ifconfig("eth0")
137
+
138
+ from runps import ifconfig
139
+ print ifconfig("eth0")
140
+ ```
141
+
142
+ A less common usage pattern is through runps Command wrapper, which takes a
143
+ full path to a command and returns a callable object. This is useful for
144
+ programs that have weird characters in their names or programs that aren't in
145
+ your $PATH:
146
+
147
+ ```python
148
+ import runps
149
+ ffmpeg = runps.Command("/usr/bin/ffmpeg")
150
+ ffmpeg(movie_file)
151
+ ```
152
+
153
+ The last usage pattern is for trying runps through an interactive REPL. By
154
+ default, this acts like a star import (so all of your system programs will be
155
+ immediately available as functions):
156
+
157
+ $> python runps.py
158
+
159
+
160
+ # Examples
161
+
162
+ ## Executing Commands
163
+
164
+ Commands work like you'd expect. **Just call your program's name like
165
+ a function:**
166
+
167
+ ```python
168
+ # print the contents of this directory
169
+ print ls("-l")
170
+
171
+ # get the longest line of this file
172
+ longest_line = wc(__file__, "-L")
173
+
174
+ # get interface information
175
+ print ifconfig("eth0")
176
+ ```
177
+
178
+ Note that these aren't Python functions, these are running the binary
179
+ commands on your system dynamically by resolving your PATH, much like Bash does.
180
+ In this way, all the programs on your system are easily available
181
+ in Python.
182
+
183
+ You can also call attributes on commands. This translates to the command
184
+ name followed by the attribute name:
185
+
186
+ ```python
187
+ from runps import git
188
+
189
+ # resolves to "git branch -v"
190
+ print git.branch("-v")
191
+ ```
192
+
193
+ It turns out this is extremely useful for commands whose first argument is often
194
+ another sub-command (like git, svn, time, sudo, etc).
195
+ See "Baking" for an advanced usage of this.
196
+
197
+ ## Keyword Arguments
198
+
199
+ Keyword arguments also work like you'd expect: they get replaced with the
200
+ long-form and short-form commandline option:
201
+
202
+ ```python
203
+ # resolves to "curl http://duckduckgo.com/ -o page.html --silent"
204
+ curl("http://duckduckgo.com/", o="page.html", silent=True)
205
+
206
+ # or if you prefer not to use keyword arguments, this does the same thing:
207
+ curl("http://duckduckgo.com/", "-o", "page.html", "--silent")
208
+
209
+ # resolves to "adduser amoffat --system --shell=/bin/bash --no-create-home"
210
+ adduser("amoffat", system=True, shell="/bin/bash", no_create_home=True)
211
+
212
+ # or
213
+ adduser("amoffat", "--system", "--shell", "/bin/bash", "--no-create-home")
214
+ ```
215
+
216
+ ## Piping
217
+
218
+ Piping has become function composition:
219
+
220
+ ```python
221
+ # sort this directory by biggest file
222
+ print sort(du(glob("*"), "-sb"), "-rn")
223
+
224
+ # print the number of folders and files in /etc
225
+ print wc(ls("/etc", "-1"), "-l")
226
+ ```
227
+
228
+ ## Redirection
229
+
230
+ runps can redirect the standard and error output streams of a process to a file.
231
+ This is done with the special _out and _err keyword arguments. You can pass a
232
+ filename or a file object as the argument value. When the name of an already
233
+ existing file is passed, the contents of the file will be overwritten.
234
+
235
+ ```python
236
+ ls(_out="files.list")
237
+ ls("nonexistent", _err="error.txt")
238
+ ```
239
+
240
+ runps can also redirect the error output stream to the standard output stream,
241
+ using the special _err_to_out=True keyword argument.
242
+
243
+
244
+ ## Sudo and With Contexts
245
+
246
+ Commands can be run within a "with" context. Popular commands using this
247
+ might be "sudo" or "fakeroot":
248
+
249
+ ```python
250
+ with sudo:
251
+ print ls("/root")
252
+ ```
253
+
254
+ If you need
255
+ to run a command in a with context AND call it, for example, specifying
256
+ a -p prompt with sudo, you need to use the "_with" keyword argument.
257
+ This let's the command know that it's being run from a with context so
258
+ it can behave correctly.
259
+
260
+ ```python
261
+ with sudo(p=">", _with=True):
262
+ print ls("/root")
263
+ ```
264
+
265
+ ## Background Processes
266
+
267
+ Commands can be run in the background with the special _bg=True keyword
268
+ argument:
269
+
270
+ ```python
271
+ # blocks
272
+ sleep(3)
273
+ print "...3 seconds later"
274
+
275
+ # doesn't block
276
+ p = sleep(3, _bg=True)
277
+ print "prints immediately!"
278
+ p.wait()
279
+ print "...and 3 seconds later"
280
+ ```
281
+
282
+ You can also pipe together background processes!
283
+
284
+ ```python
285
+ p = wc(curl("http://github.com/", silent=True, _bg=True), "--bytes")
286
+ print "prints immediately!"
287
+ print "byte count of github: %d" % int(p) # lazily completes
288
+ ```
289
+
290
+ This lets you start long-running commands at the beginning of your script
291
+ (like a file download) and continue performing other commands in the
292
+ foreground.
293
+
294
+
295
+ ## Foreground Processes
296
+
297
+ Foreground processes are processes that you want to interact directly with
298
+ the default stdout and stdin of your terminal. In other words, these are
299
+ processes that you do not want to return their output as a return value
300
+ of their call. An example would be opening a text editor:
301
+
302
+ ```python
303
+ vim(file_to_edit)
304
+ ```
305
+
306
+ This will block because runps will be trying to aggregate the output
307
+ of the command to python, without displaying anything to the screen. The
308
+ solution is the "_fg" special keyword arg:
309
+
310
+ ```python
311
+ vim(file_to_edit, _fg=True)
312
+ ```
313
+
314
+ This will open vim as expected and let you use it as expected, with all
315
+ the input coming from the keyboard and the output going to the screen.
316
+ The return value of a foreground process is an empty string.
317
+
318
+
319
+ ## Finding Commands
320
+
321
+ "Which" finds the full path of a program, or returns None if it doesn't exist.
322
+ This command is one of the few commands implemented as a Python function,
323
+ and therefore doesn't rely on the "which" program actually existing.
324
+
325
+ ```python
326
+ print which("python") # "/usr/bin/python"
327
+ print which("ls") # "/bin/ls"
328
+ print which("some_command") # None
329
+
330
+ if not which("supervisorctl"): apt_get("install", "supervisor", "-y")
331
+ ```
332
+
333
+ ## Baking
334
+
335
+ runps is capable of "baking" arguments into commands. This is similar
336
+ to the stdlib functools.partial wrapper. An example can speak volumes:
337
+
338
+ ```python
339
+ from runps import ls
340
+
341
+ ls = ls.bake("-la")
342
+ print ls # "/usr/bin/ls -la"
343
+
344
+ # resolves to "ls / -la"
345
+ print ls("/")
346
+ ```
347
+
348
+ The idea is that calling "bake" on a command creates a callable object
349
+ that automatically passes along all of the arguments passed into "bake".
350
+ This gets **really interesting** when you combine this with the attribute
351
+ access on a command:
352
+
353
+ ```python
354
+ from runps import ssh
355
+
356
+ # calling whoami on the server. this is tedious to do if you're running
357
+ # any more than a few commands.
358
+ iam1 = ssh("myserver.com", "-p 1393", "whoami")
359
+
360
+ # wouldn't it be nice to bake the common parameters into the ssh command?
361
+ myserver = ssh.bake("myserver.com", p=1393)
362
+
363
+ print myserver # "/usr/bin/ssh myserver.com -p 1393"
364
+
365
+ # resolves to "/usr/bin/ssh myserver.com -p 1393 whoami"
366
+ iam2 = myserver.whoami()
367
+
368
+ assert(iam1 == iam2) # True!
369
+ ```
370
+
371
+ Now that the "myserver" callable represents a baked ssh command, you
372
+ can call anything on the server easily:
373
+
374
+ ```python
375
+ # resolves to "/usr/bin/ssh myserver.com -p 1393 tail /var/log/dumb_daemon.log -n 100"
376
+ print myserver.tail("/var/log/dumb_daemon.log", n=100)
377
+ ```
378
+
379
+ ## Environment Variables
380
+
381
+ Environment variables are available much like they are in Bash:
382
+
383
+ ```python
384
+ print HOME
385
+ print SHELL
386
+ print PS1
387
+ ```
388
+
389
+ You can set enviroment variables the usual way, through the os.environ
390
+ mapping:
391
+
392
+ ```python
393
+ import os
394
+ os.environ["TEST"] = "123"
395
+ ```
396
+
397
+ Now any new subprocess commands called from the script will be able to
398
+ access that environment variable.
399
+
400
+ ## Exceptions
401
+
402
+ Exceptions are dynamically generated based on the return code of the command.
403
+ This lets you catch a specific return code, or catch all error return codes
404
+ through the base class ErrorReturnCode:
405
+
406
+ ```python
407
+ try: print ls("/some/non-existant/folder")
408
+ except ErrorReturnCode_2:
409
+ print "folder doesn't exist!"
410
+ create_the_folder()
411
+ except ErrorReturnCode:
412
+ print "unknown error"
413
+ exit(1)
414
+ ```
415
+
416
+ ## Globbing
417
+
418
+ Glob-expansion is not done on your arguments. For example, this will not work:
419
+
420
+ ```python
421
+ from runps import du
422
+ print du("*")
423
+ ```
424
+
425
+ You'll get an error to the effect of "cannot access '\*': No such file or directory".
426
+ This is because the "\*" needs to be glob expanded:
427
+
428
+ ```python
429
+ from runps import du, glob
430
+ print du(glob("*"))
431
+ ```
432
+
433
+
434
+ ## Commandline Arguments
435
+
436
+ You can access commandline arguments similar to Bash's $1, $2, etc by using
437
+ ARG1, ARG2, etc:
438
+
439
+ ```python
440
+ print ARG1, ARG2
441
+
442
+ # if an argument isn't defined, it's set to None
443
+ if ARG10 is None: do_something()
444
+ ```
445
+
446
+ You can access the entire argparse/optparse-friendly list of commandline
447
+ arguments through "ARGV". This is recommended for flexibility:
448
+
449
+ ```python
450
+ import argparse
451
+ parser = argparse.ArgumentParser(prog="PROG")
452
+ parser.add_argument("-x", default=3, type=int)
453
+ ns = parser.parse_args(ARGV)
454
+ print ns.x
455
+ ```
456
+
457
+
458
+ ## Weirdly-named Commands
459
+
460
+ runps automatically handles underscore-dash conversions. For example, if you want
461
+ to call apt-get:
462
+
463
+ ```python
464
+ apt_get("install", "mplayer", y=True)
465
+ ```
466
+
467
+ runps looks for "apt_get", but if it doesn't find it, replaces all underscores
468
+ with dashes and searches again. If the command still isn't found, a
469
+ CommandNotFound exception is raised.
470
+
471
+ Commands with other, less-commonly symbols in their names must be accessed
472
+ directly through the "Command" class wrapper. The Command class takes the full
473
+ path to the program as a string:
474
+
475
+ ```python
476
+ p27 = Command(which("python2.7"))
477
+ print p27("-h")
478
+ ```
479
+
480
+ The Command wrapper is also useful for commands that are not in your standard PATH:
481
+
482
+ ```python
483
+ script = Command("/tmp/temporary-script.sh")
484
+ print script()
485
+ ```
486
+
487
+ ## Non-standard Exit Codes
488
+
489
+ Normally, if a command returns an exit code that is not 0, runps raises an exception
490
+ based on that exit code. However, if you have determined that an error code
491
+ is normal and want to retrieve the output of the command without runps raising an
492
+ exception, you can use the "_ok_code" special argument to suppress the exception:
493
+
494
+ ```python
495
+ output = runps.ls("dir_that_exists", "dir_that_doesnt", _ok_code=2)
496
+ ```
497
+
498
+ In the above example, even though you're trying to list a directory that doesn't
499
+ exist, you can still get the output from the directory that does exist by telling
500
+ the command that 2 is an "ok" exit code, so don't raise an exception.
501
+
502
+ _ok_code can also take a list or tuple of numbers for multiple ok exit codes.