Assorted process and subprocess management functions.
*Latest release 20241206*:
run(): accept new remote= and ssh_exe= parameters to support remote execution, default via @uses_cmd_options(ssh_exe).
Not to be confused with the excellent
(psutil)[https://pypi.org/project/psutil/] package.
## <a name="groupargv"></a>`groupargv(pre_argv, argv, post_argv=(), max_argv=None, encode=False)`
Distribute the array `argv` over multiple arrays
to fit within `MAX_ARGV`.
Return a list of argv lists.
Parameters:
* `pre_argv`: the sequence of leading arguments
* `argv`: the sequence of arguments to distribute; this may not be empty
* `post_argv`: optional, the sequence of trailing arguments
* `max_argv`: optional, the maximum length of each distributed
argument list, default from `MAX_ARGV`: `131072`
* `encode`: default `False`.
If true, encode the argv sequences into bytes for accurate tallying.
If `encode` is a Boolean,
encode the elements with their .encode() method.
If `encode` is a `str`, encode the elements with their `.encode()`
method with `encode` as the encoding name;
otherwise presume that `encode` is a callable
for encoding each element.
The returned argv arrays will contain the encoded element values.
## <a name="PidFileManager"></a>`PidFileManager(path, pid=None)`
Context manager for a pid file.
Parameters:
* `path`: the path to the process id file.
* `pid`: the process id to store in the pid file,
default from `os.etpid`.
Writes the process id file at the start
and removes the process id file at the end.
## <a name="pipefrom"></a>`pipefrom(argv, *, quiet: bool, remote=None, ssh_exe, text=True, stdin=-3, **popen_kw)`
Pipe text (usually) from a command using `subprocess.Popen`.
Return the `Popen` object with `.stdout` as a pipe.
Parameters:
* `argv`: the command argument list
* `quiet`: optional flag, default `False`;
if true, print the command to `stderr`
* `text`: optional flag, default `True`; passed to `Popen`.
* `stdin`: optional value for `Popen`'s `stdin`, default `DEVNULL`
Other keyword arguments are passed to `Popen`.
Note that `argv` is passed through `prep_argv` before use,
allowing direct invocation with conditional parts.
See the `prep_argv` function for details.
## <a name="pipeto"></a>`pipeto(argv, *, quiet: bool, remote=None, ssh_exe, **kw)`
Pipe text to a command.
Optionally trace invocation.
Return the Popen object with .stdin encoded as text.
Parameters:
* `argv`: the command argument list
* `trace`: if true (default `False`),
if `trace` is `True`, recite invocation to stderr
otherwise presume that `trace` is a stream
to which to recite the invocation.
Other keyword arguments are passed to the `io.TextIOWrapper`
which wraps the command's input.
Note that `argv` is passed through `prep_argv` before use,
allowing direct invocation with conditional parts.
See the `prep_argv` function for details.
## <a name="prep_argv"></a>`prep_argv(*argv, ssh_exe, remote=None)`
A trite list comprehension to reduce an argument list `*argv`
to the entries which are not `None` or `False`
and to flatten other entries which are not strings.
This exists ease the construction of argument lists
with methods like this:
>>> command_exe = 'hashindex'
>>> hashname = 'sha1'
>>> quiet = False
>>> verbose = True
>>> prep_argv(
... command_exe,
... quiet and '-q',
... verbose and '-v',
... hashname and ('-h', hashname),
... )
['hashindex', '-v', '-h', 'sha1']
where `verbose` is a `bool` governing the `-v` option
and `hashname` is either `str` to be passed with `-h hashname`
or `None` to omit the option.
If `remote` is not `None` it is taken to be a remote host on
which to run `argv`. This is done via the `ssh_exe` argument,
which defaults to the string `'ssh'`. The value of `ssh_exe`
is a command string parsed with `shlex.split`. A new `argv`
is computed as:
[
*shlex.split(ssh_exe),
remote,
'--',
shlex.join(argv),
]
## <a name="print_argv"></a>`print_argv(*argv, indent='', subindent=' ', end='\n', file=None, fold=False, print=None)`
Print an indented possibly folded command line.
## <a name="remove_pidfile"></a>`remove_pidfile(path)`
Truncate and remove a pidfile, permissions permitting.
## <a name="run"></a>`run(argv, *, check=True, doit: bool, input=None, logger=None, print=None, quiet: bool, remote=None, ssh_exe=None, stdin=None, **subp_options)`
Run a command via `subprocess.run`.
Return the `CompletedProcess` result or `None` if `doit` is false.
Positional parameter:
* `argv`: the command line to run
Note that `argv` is passed through `prep_argv(argv,remote=remote,ssh_exe=ssh_exe)`
before use, allowing direct invocation with conditional parts.
See the `prep_argv` function for details.
Keyword parameters:
* `check`: passed to `subprocess.run`, default `True`;
NB: _unlike_ the `subprocess.run` default, which is `False`
* `doit`: optional flag, default `True`;
if false do not run the command and return `None`
* `input`: default `None`: alternative to `stdin`;
passed to `subprocess.run`
* `logger`: optional logger, default `None`;
if `True`, use `logging.getLogger()`;
if not `None` or `False` trace using `print_argv`
* `quiet`: default `False`; if false, print the command and its output
* `remote`: optional remote target on which to run `argv`
* `ssh_exe`: optional command string for the remote shell
* `stdin`: standard input for the subprocess, default `subprocess.DEVNULL`;
passed to `subprocess.run`
Other keyword parameters are passed to `subprocess.run`.
## <a name="signal_handler"></a>`signal_handler(sig, handler, call_previous=False)`
Context manager to push a new signal handler,
yielding the old handler,
restoring the old handler on exit.
If `call_previous` is true (default `False`)
also call the old handler after the new handler on receipt of the signal.
Parameters:
* `sig`: the `int` signal number to catch
* `handler`: the handler function to call with `(sig,frame)`
* `call_previous`: optional flag (default `False`);
if true, also call the old handler (if any) after `handler`
## <a name="signal_handlers"></a>`signal_handlers(sig_hnds, call_previous=False, _stacked=None)`
Context manager to stack multiple signal handlers,
yielding a mapping of `sig`=>`old_handler`.
Parameters:
* `sig_hnds`: a mapping of `sig`=>`new_handler`
or an iterable of `(sig,new_handler)` pairs
* `call_previous`: optional flag (default `False`), passed
to `signal_handler()`
## <a name="stop"></a>`stop(pid, signum=<Signals.SIGTERM: 15>, wait=None, do_SIGKILL=False)`
Stop the process specified by `pid`, optionally await its demise.
Parameters:
* `pid`: process id.
If `pid` is a string, treat as a process id file and read the
process id from it.
* `signum`: the signal to send, default `signal.SIGTERM`.
* `wait`: whether to wait for the process, default `None`.
If `None`, return `True` (signal delivered).
If `0`, wait indefinitely until the process exits as tested by
`os.kill(pid, 0)`.
If greater than 0, wait up to `wait` seconds for the process to die;
if it exits, return `True`, otherwise `False`;
* `do_SIGKILL`: if true (default `False`),
send the process `signal.SIGKILL` as a final measure before return.
## <a name="write_pidfile"></a>`write_pidfile(path, pid=None)`
Write a process id to a pid file.
Parameters:
* `path`: the path to the pid file.
* `pid`: the process id to write, defautl from `os.getpid`.
# Release Log
*Release 20241206*:
run(): accept new remote= and ssh_exe= parameters to support remote execution, default via @uses_cmd_options(ssh_exe).
*Release 20241122*:
* print_argv: new print= parameter to provide a print() function, refactor to use print instead of file.write.
* run: new optional print parameter, plumb to print_argv.
* Use @uses_doit and @uses_quiet to provide the default quiet and doit states.
*Release 20240316*:
Fixed release upload artifacts.
*Release 20240211*:
* run: new optional input= parameter to presupply input data.
* New prep_argv(*argv) function to flatten and trim computes argv lists; use automatically in run(), pipeot(), pipefrom().
*Release 20231129*:
run(): default stdin=subprocess.DEVNULL.
*Release 20230612*:
* pipefrom: default stdin=DEVNULL.
* Make many parameters keyword only.
*Release 20221228*:
* signal_handlers: bugfix iteration of sig_hnds.
* Use cs.gimmicks instead of cs.logutils.
* Drop use of cs.upd, fixes circular import; users of run() may need to call "with Upd().above()" themselves.
*Release 20221118*:
run: do not print cp.stdout.
*Release 20220805*:
run: print trace to stderr.
*Release 20220626*:
run: default quiet=True.
*Release 20220606*:
* run: fold in the superior run() from cs.ebooks.
* pipefrom,pipeto: replace trace= with quiet= like run().
* print_argv: add an `end` parameter (used by pipefrom).
*Release 20220531*:
* New print_argv function for writing shell command lines out nicely.
* Bump requirements for cs.gimmicks.
*Release 20220504*:
signal_handlers: reshape try/except to avoid confusing traceback.
*Release 20220429*:
* New signal_handler(sig,handler,call_previous=False) context manager to push a signal handler.
* New signal_handlers() context manager to stack handlers for multiple signals.
*Release 20190101*:
Bugfix context manager cleanup. groupargv improvements.
*Release 20171112*:
Bugfix array length counting.
*Release 20171110*:
New function groupargv for breaking up argv lists to fit within the maximum argument limit; constant MAX_ARGV for the default limit.
*Release 20171031*:
run: accept optional pids parameter, a setlike collection of process ids.
*Release 20171018*:
run: replace `trace` parameter with `logger`, default None
*Release 20170908.1*:
remove dependency on cs.pfx
*Release 20170908*:
run: pass extra keyword arguments to subprocess.call
*Release 20170906.1*:
Add run, pipefrom and pipeto - were incorrectly in another module.
*Release 20170906*:
First PyPI release.
Raw data
{
"_id": null,
"home_page": null,
"name": "cs-psutils",
"maintainer": null,
"docs_url": null,
"requires_python": null,
"maintainer_email": null,
"keywords": "python2, python3",
"author": null,
"author_email": "Cameron Simpson <cs@cskk.id.au>",
"download_url": "https://files.pythonhosted.org/packages/13/91/4b725c42cf4155b72fab0263a01f4d05ca4ed39a64bac0e3d34d27d62291/cs_psutils-20241206.tar.gz",
"platform": null,
"description": "Assorted process and subprocess management functions.\n\n*Latest release 20241206*:\nrun(): accept new remote= and ssh_exe= parameters to support remote execution, default via @uses_cmd_options(ssh_exe).\n\nNot to be confused with the excellent\n(psutil)[https://pypi.org/project/psutil/] package.\n\n## <a name=\"groupargv\"></a>`groupargv(pre_argv, argv, post_argv=(), max_argv=None, encode=False)`\n\nDistribute the array `argv` over multiple arrays\nto fit within `MAX_ARGV`.\nReturn a list of argv lists.\n\nParameters:\n* `pre_argv`: the sequence of leading arguments\n* `argv`: the sequence of arguments to distribute; this may not be empty\n* `post_argv`: optional, the sequence of trailing arguments\n* `max_argv`: optional, the maximum length of each distributed\n argument list, default from `MAX_ARGV`: `131072`\n* `encode`: default `False`.\n If true, encode the argv sequences into bytes for accurate tallying.\n If `encode` is a Boolean,\n encode the elements with their .encode() method.\n If `encode` is a `str`, encode the elements with their `.encode()`\n method with `encode` as the encoding name;\n otherwise presume that `encode` is a callable\n for encoding each element.\n\nThe returned argv arrays will contain the encoded element values.\n\n## <a name=\"PidFileManager\"></a>`PidFileManager(path, pid=None)`\n\nContext manager for a pid file.\n\nParameters:\n* `path`: the path to the process id file.\n* `pid`: the process id to store in the pid file,\n default from `os.etpid`.\n\nWrites the process id file at the start\nand removes the process id file at the end.\n\n## <a name=\"pipefrom\"></a>`pipefrom(argv, *, quiet: bool, remote=None, ssh_exe, text=True, stdin=-3, **popen_kw)`\n\nPipe text (usually) from a command using `subprocess.Popen`.\nReturn the `Popen` object with `.stdout` as a pipe.\n\nParameters:\n* `argv`: the command argument list\n* `quiet`: optional flag, default `False`;\n if true, print the command to `stderr`\n* `text`: optional flag, default `True`; passed to `Popen`.\n* `stdin`: optional value for `Popen`'s `stdin`, default `DEVNULL`\nOther keyword arguments are passed to `Popen`.\n\nNote that `argv` is passed through `prep_argv` before use,\nallowing direct invocation with conditional parts.\nSee the `prep_argv` function for details.\n\n## <a name=\"pipeto\"></a>`pipeto(argv, *, quiet: bool, remote=None, ssh_exe, **kw)`\n\nPipe text to a command.\nOptionally trace invocation.\nReturn the Popen object with .stdin encoded as text.\n\nParameters:\n* `argv`: the command argument list\n* `trace`: if true (default `False`),\n if `trace` is `True`, recite invocation to stderr\n otherwise presume that `trace` is a stream\n to which to recite the invocation.\n\nOther keyword arguments are passed to the `io.TextIOWrapper`\nwhich wraps the command's input.\n\nNote that `argv` is passed through `prep_argv` before use,\nallowing direct invocation with conditional parts.\nSee the `prep_argv` function for details.\n\n## <a name=\"prep_argv\"></a>`prep_argv(*argv, ssh_exe, remote=None)`\n\nA trite list comprehension to reduce an argument list `*argv`\nto the entries which are not `None` or `False`\nand to flatten other entries which are not strings.\n\nThis exists ease the construction of argument lists\nwith methods like this:\n\n >>> command_exe = 'hashindex'\n >>> hashname = 'sha1'\n >>> quiet = False\n >>> verbose = True\n >>> prep_argv(\n ... command_exe,\n ... quiet and '-q',\n ... verbose and '-v',\n ... hashname and ('-h', hashname),\n ... )\n ['hashindex', '-v', '-h', 'sha1']\n\nwhere `verbose` is a `bool` governing the `-v` option\nand `hashname` is either `str` to be passed with `-h hashname`\nor `None` to omit the option.\n\nIf `remote` is not `None` it is taken to be a remote host on\nwhich to run `argv`. This is done via the `ssh_exe` argument,\nwhich defaults to the string `'ssh'`. The value of `ssh_exe`\nis a command string parsed with `shlex.split`. A new `argv`\nis computed as:\n\n [\n *shlex.split(ssh_exe),\n remote,\n '--',\n shlex.join(argv),\n ]\n\n## <a name=\"print_argv\"></a>`print_argv(*argv, indent='', subindent=' ', end='\\n', file=None, fold=False, print=None)`\n\nPrint an indented possibly folded command line.\n\n## <a name=\"remove_pidfile\"></a>`remove_pidfile(path)`\n\nTruncate and remove a pidfile, permissions permitting.\n\n## <a name=\"run\"></a>`run(argv, *, check=True, doit: bool, input=None, logger=None, print=None, quiet: bool, remote=None, ssh_exe=None, stdin=None, **subp_options)`\n\nRun a command via `subprocess.run`.\nReturn the `CompletedProcess` result or `None` if `doit` is false.\n\nPositional parameter:\n* `argv`: the command line to run\n\nNote that `argv` is passed through `prep_argv(argv,remote=remote,ssh_exe=ssh_exe)`\nbefore use, allowing direct invocation with conditional parts.\nSee the `prep_argv` function for details.\n\nKeyword parameters:\n* `check`: passed to `subprocess.run`, default `True`;\n NB: _unlike_ the `subprocess.run` default, which is `False`\n* `doit`: optional flag, default `True`;\n if false do not run the command and return `None`\n* `input`: default `None`: alternative to `stdin`;\n passed to `subprocess.run`\n* `logger`: optional logger, default `None`;\n if `True`, use `logging.getLogger()`;\n if not `None` or `False` trace using `print_argv`\n* `quiet`: default `False`; if false, print the command and its output\n* `remote`: optional remote target on which to run `argv`\n* `ssh_exe`: optional command string for the remote shell\n* `stdin`: standard input for the subprocess, default `subprocess.DEVNULL`;\n passed to `subprocess.run`\n\nOther keyword parameters are passed to `subprocess.run`.\n\n## <a name=\"signal_handler\"></a>`signal_handler(sig, handler, call_previous=False)`\n\nContext manager to push a new signal handler,\nyielding the old handler,\nrestoring the old handler on exit.\nIf `call_previous` is true (default `False`)\nalso call the old handler after the new handler on receipt of the signal.\n\nParameters:\n* `sig`: the `int` signal number to catch\n* `handler`: the handler function to call with `(sig,frame)`\n* `call_previous`: optional flag (default `False`);\n if true, also call the old handler (if any) after `handler`\n\n## <a name=\"signal_handlers\"></a>`signal_handlers(sig_hnds, call_previous=False, _stacked=None)`\n\nContext manager to stack multiple signal handlers,\nyielding a mapping of `sig`=>`old_handler`.\n\nParameters:\n* `sig_hnds`: a mapping of `sig`=>`new_handler`\n or an iterable of `(sig,new_handler)` pairs\n* `call_previous`: optional flag (default `False`), passed\n to `signal_handler()`\n\n## <a name=\"stop\"></a>`stop(pid, signum=<Signals.SIGTERM: 15>, wait=None, do_SIGKILL=False)`\n\nStop the process specified by `pid`, optionally await its demise.\n\nParameters:\n* `pid`: process id.\n If `pid` is a string, treat as a process id file and read the\n process id from it.\n* `signum`: the signal to send, default `signal.SIGTERM`.\n* `wait`: whether to wait for the process, default `None`.\n If `None`, return `True` (signal delivered).\n If `0`, wait indefinitely until the process exits as tested by\n `os.kill(pid, 0)`.\n If greater than 0, wait up to `wait` seconds for the process to die;\n if it exits, return `True`, otherwise `False`;\n* `do_SIGKILL`: if true (default `False`),\n send the process `signal.SIGKILL` as a final measure before return.\n\n## <a name=\"write_pidfile\"></a>`write_pidfile(path, pid=None)`\n\nWrite a process id to a pid file.\n\nParameters:\n* `path`: the path to the pid file.\n* `pid`: the process id to write, defautl from `os.getpid`.\n\n# Release Log\n\n\n\n*Release 20241206*:\nrun(): accept new remote= and ssh_exe= parameters to support remote execution, default via @uses_cmd_options(ssh_exe).\n\n*Release 20241122*:\n* print_argv: new print= parameter to provide a print() function, refactor to use print instead of file.write.\n* run: new optional print parameter, plumb to print_argv.\n* Use @uses_doit and @uses_quiet to provide the default quiet and doit states.\n\n*Release 20240316*:\nFixed release upload artifacts.\n\n*Release 20240211*:\n* run: new optional input= parameter to presupply input data.\n* New prep_argv(*argv) function to flatten and trim computes argv lists; use automatically in run(), pipeot(), pipefrom().\n\n*Release 20231129*:\nrun(): default stdin=subprocess.DEVNULL.\n\n*Release 20230612*:\n* pipefrom: default stdin=DEVNULL.\n* Make many parameters keyword only.\n\n*Release 20221228*:\n* signal_handlers: bugfix iteration of sig_hnds.\n* Use cs.gimmicks instead of cs.logutils.\n* Drop use of cs.upd, fixes circular import; users of run() may need to call \"with Upd().above()\" themselves.\n\n*Release 20221118*:\nrun: do not print cp.stdout.\n\n*Release 20220805*:\nrun: print trace to stderr.\n\n*Release 20220626*:\nrun: default quiet=True.\n\n*Release 20220606*:\n* run: fold in the superior run() from cs.ebooks.\n* pipefrom,pipeto: replace trace= with quiet= like run().\n* print_argv: add an `end` parameter (used by pipefrom).\n\n*Release 20220531*:\n* New print_argv function for writing shell command lines out nicely.\n* Bump requirements for cs.gimmicks.\n\n*Release 20220504*:\nsignal_handlers: reshape try/except to avoid confusing traceback.\n\n*Release 20220429*:\n* New signal_handler(sig,handler,call_previous=False) context manager to push a signal handler.\n* New signal_handlers() context manager to stack handlers for multiple signals.\n\n*Release 20190101*:\nBugfix context manager cleanup. groupargv improvements.\n\n*Release 20171112*:\nBugfix array length counting.\n\n*Release 20171110*:\nNew function groupargv for breaking up argv lists to fit within the maximum argument limit; constant MAX_ARGV for the default limit.\n\n*Release 20171031*:\nrun: accept optional pids parameter, a setlike collection of process ids.\n\n*Release 20171018*:\nrun: replace `trace` parameter with `logger`, default None\n\n*Release 20170908.1*:\nremove dependency on cs.pfx\n\n*Release 20170908*:\nrun: pass extra keyword arguments to subprocess.call\n\n*Release 20170906.1*:\nAdd run, pipefrom and pipeto - were incorrectly in another module.\n\n*Release 20170906*:\nFirst PyPI release.\n",
"bugtrack_url": null,
"license": "GNU General Public License v3 or later (GPLv3+)",
"summary": "Assorted process and subprocess management functions.",
"version": "20241206",
"project_urls": {
"MonoRepo Commits": "https://bitbucket.org/cameron_simpson/css/commits/branch/main",
"Monorepo Git Mirror": "https://github.com/cameron-simpson/css",
"Monorepo Hg/Mercurial Mirror": "https://hg.sr.ht/~cameron-simpson/css",
"Source": "https://github.com/cameron-simpson/css/blob/main/lib/python/cs/psutils.py"
},
"split_keywords": [
"python2",
" python3"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "14df1cafcda47858978def1a5b8b62e1fdd43d2c4ca39ba8ab11941ce81a1a60",
"md5": "8802ee7d529a793011eb0668c3f32a0f",
"sha256": "83844fc774d4988b97a676a5d2220a190d9085f6bb7b0b72ba17367733c37624"
},
"downloads": -1,
"filename": "cs_psutils-20241206-py3-none-any.whl",
"has_sig": false,
"md5_digest": "8802ee7d529a793011eb0668c3f32a0f",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": null,
"size": 10055,
"upload_time": "2024-12-06T04:24:38",
"upload_time_iso_8601": "2024-12-06T04:24:38.394667Z",
"url": "https://files.pythonhosted.org/packages/14/df/1cafcda47858978def1a5b8b62e1fdd43d2c4ca39ba8ab11941ce81a1a60/cs_psutils-20241206-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "13914b725c42cf4155b72fab0263a01f4d05ca4ed39a64bac0e3d34d27d62291",
"md5": "d8126659b3f1bdab17cadfb0b66bc31f",
"sha256": "5d2e0ef31d78784e34eeefbde89eb7c3c7bcf258fc7c6d77b3846c41d209cf07"
},
"downloads": -1,
"filename": "cs_psutils-20241206.tar.gz",
"has_sig": false,
"md5_digest": "d8126659b3f1bdab17cadfb0b66bc31f",
"packagetype": "sdist",
"python_version": "source",
"requires_python": null,
"size": 10905,
"upload_time": "2024-12-06T04:24:41",
"upload_time_iso_8601": "2024-12-06T04:24:41.014441Z",
"url": "https://files.pythonhosted.org/packages/13/91/4b725c42cf4155b72fab0263a01f4d05ca4ed39a64bac0e3d34d27d62291/cs_psutils-20241206.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2024-12-06 04:24:41",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "cameron-simpson",
"github_project": "css",
"travis_ci": false,
"coveralls": false,
"github_actions": false,
"lcname": "cs-psutils"
}