bg-helper


Namebg-helper JSON
Version 0.1.24 PyPI version JSON
download
home_pagehttps://github.com/kenjyco/bg-helper
SummaryCLI helpers for background tasks (shell), docker (databases), git, and SSH
upload_time2025-07-23 17:57:17
maintainerNone
docs_urlNone
authorKen
requires_pythonNone
licenseMIT
keywords background shell git ssh docker pyenv redis mongodb postgres postgresql mysql helper kenjyco
VCS
bugtrack_url
requirements fs-helper importlib-metadata input-helper
Travis-CI No Travis.
coveralls test coverage No coveralls.
            ``bg-helper`` is a Python library that provides production-ready shell
command orchestration, Docker service management, git repository
automation, and more. It offers three core execution primitives
(``run``, ``run_output``, ``run_or_die``) with universal timeout
protection and error handling, plus specialized tools for managing
Docker containers (PostgreSQL, MySQL, Redis, MongoDB), git operations
with automatic context management, and Python environment automation via
pyenv. Rather than hiding complexity behind abstractions, ``bg-helper``
provides powerful primitives for shell command orchestration, background
task management, and DevOps workflow automation. You can always pass
``show=True`` to see the actual commands being executed, learn the
underlying tools, and build transferable skills while providing
comprehensive error capture and background task management.

**Who benefits from this?** - **DevOps engineers** who need reliable
automation for git repositories, Docker containers, and development
environments - **Systems administrators** who want Python’s power while
preserving shell command fidelity - **Infrastructure teams** building
automation that must be debuggable, maintainable, and transparent -
**Library developers** who need robust local integration testing with
multiple database services and Python versions - **Anyone** who has been
burned by “magic” tools and wants infrastructure code that reveals
rather than conceals its operations

``bg-helper`` fits naturally into existing toolchains by wrapping and
enhancing familiar tools (git, docker, ssh) rather than replacing them.
It’s designed for REPL-driven exploration that gradually evolves into
production automation.

**Particularly useful for integration testing:** The Docker service
functions enable easy local testing across multiple database types
(PostgreSQL, MySQL, Redis, MongoDB), while the pyenv functions support
testing across Python versions. The
``pyenv_create_venvs_for_py_versions_and_dep_versions`` function is
especially powerful for creating test matrices across Python versions
and dependency combinations, as demonstrated in libraries like
sql-helper.

Install
-------

::

   pip install bg-helper

QuickStart
----------

.. code:: python

   import bg_helper as bh

   # Safe command execution with timeout protection and error capture
   result = bh.run_output('ls -la', show=True)  # Shows actual command executed
   print(result)

   # Comprehensive error handling for any function
   error_info = bh.call_func(lambda: 1/0)
   if error_info['status'] == 'error':
       print(f"Function failed: {error_info['error_type']}")
       print(f"Full traceback: {error_info['traceback_string']}")

   # Git operations with automatic repository context management
   branch = bh.tools.git_current_branch(show=True)  # Learn the actual git commands
   print(f"Current branch: {branch}")

   # Docker service management with intelligent fallback logic
   success = bh.tools.docker_postgres_start(
       name='dev-db',
       port=5432,
       show=True  # See exactly what Docker commands are executed
   )

   # Background task execution with comprehensive error logging
   task = bh.SimpleBackgroundTask('long-running-command --with-args')

**What you gain:** Reliable shell command orchestration with
production-grade error handling, automatic resource cleanup, timeout
protection, and complete operational transparency. Every operation can
show you the exact commands being executed, making debugging and
learning seamless.

API Overview
------------

Core Execution Primitives
~~~~~~~~~~~~~~~~~~~~~~~~~

These three functions form the foundation for all shell command
operations, providing graduated levels of strictness:

-  **``run(cmd, stderr_to_stdout=False, debug=False, timeout=None, exception=False, show=False)``**
   - Execute a shell command and return the exit status

   -  ``cmd``: Shell command string to execute
   -  ``stderr_to_stdout``: Redirect stderr to stdout if True
   -  ``debug``: Insert pdb breakpoint before execution if True
   -  ``timeout``: Seconds to wait before stopping command (prevents
      hanging)
   -  ``exception``: Raise exception on non-zero exit status if True
   -  ``show``: Display the actual command before execution if True
   -  Returns: Integer exit status
   -  Internal calls: None

-  **``run_output(cmd, strip=True, debug=False, timeout=None, exception=False, show=False)``**
   - Execute a shell command and return its output

   -  ``cmd``: Shell command string to execute
   -  ``strip``: Remove leading/trailing whitespace from output if True
   -  ``debug``: Insert pdb breakpoint before execution if True
   -  ``timeout``: Seconds to wait before stopping command
   -  ``exception``: Raise exception on command failure if True
   -  ``show``: Display the actual command before execution if True
   -  Returns: Command output as string
   -  Internal calls: None

-  **``run_or_die(cmd, stderr_to_stdout=False, debug=False, timeout=None, exception=True, show=False)``**
   - Execute a shell command with strict error handling—fail fast on any
   error

   -  ``cmd``: Shell command string to execute
   -  ``stderr_to_stdout``: Redirect stderr to stdout if True
   -  ``debug``: Insert pdb breakpoint before execution if True
   -  ``timeout``: Seconds to wait before stopping command
   -  ``exception``: If True (default), raise exception on failure; if
      False, exit process
   -  ``show``: Display the actual command before execution if True
   -  Returns: Integer exit status (only on success)
   -  Internal calls: None

Error Handling and Background Tasks
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

-  **``call_func(func, *args, **kwargs)``** - Execute any Python
   function with comprehensive error capture and forensic information

   -  ``func``: Python function to execute
   -  ``*args``: Arguments to pass to function
   -  ``**kwargs``: Keyword arguments (special kwargs: ``logger``,
      ``verbose``)
   -  Returns: Dictionary with keys: ``func_name``, ``args``,
      ``kwargs``, ``status`` (always present); ``value`` (on success);
      ``error_type``, ``error_value``, ``traceback_string``, ``fqdn``,
      ``time_epoch``, ``time_string``, ``func_doc``, ``func_module`` (on
      error)
   -  Internal calls: None

-  **``SimpleBackgroundTask(func, *args, **kwargs)``** - Execute a
   function or shell command in a background daemon thread with
   automatic error logging

   -  ``func``: Python callable or shell command string
   -  ``*args``: Arguments for callable (ignored for shell commands)
   -  ``**kwargs``: Keyword arguments for callable
   -  Returns: Background task object (daemon threads won’t prevent
      process exit)
   -  Internal calls: ``call_func()``

Git Operations (``bh.tools.*``)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Git functions provide repository automation with automatic context
management and state isolation.

-  **``ctx_repo_path_root(path, fetch=False, debug=False, timeout=None, exception=True, show=False)``**
   - Context manager that changes to the root directory of a git
   repository

   -  ``path``: Path to file or directory in git repository
   -  ``fetch``: Execute ``git fetch`` after changing directory if True
   -  ``debug``: Insert breakpoint before subprocess calls if True
   -  ``timeout``: Seconds to wait before stopping commands
   -  ``exception``: Raise exception if path not in repo or fetch fails
      if True
   -  ``show``: Display directory change commands if True
   -  Returns: Context manager
   -  Internal calls: ``git_repo_path_root()``, ``git_fetch()``

-  **``git_repo_path_root(path='', exception=False)``** - Return git
   repo path root for path, or None

   -  ``path``: Relative or absolute path to file or directory (current
      working directory used if none specified)
   -  ``exception``: Raise ValueError if path is not in a repo if True
   -  Returns: String path to repo root or empty string
   -  Internal calls: ``fh.repopath()``

-  **``git_repo_update(path='', debug=False, timeout=None, exception=True, show=False)``**
   - Update a repo and return True if it was successful

   -  ``path``: Path to git repo, if not using current working directory
   -  ``debug``: Insert breakpoint before subprocess calls if True
   -  ``timeout``: Seconds to wait before stopping commands
   -  ``exception``: Raise exception if git command has error if True
   -  ``show``: Display git commands before executing if True
   -  Returns: Boolean success status
   -  Internal calls: ``ctx_repo_path_root()``,
      ``git_current_tracking_branch()``, ``git_current_branch()``,
      ``git_origin_url()``, ``git_fetch()``, ``bh.run_output()``,
      ``bh.run()``

-  **``git_clone(url, path='', name='', recursive=False, debug=False, timeout=None, exception=True, show=False)``**
   - Clone a repo

   -  ``url``: URL for a git repo
   -  ``path``: Path to clone git repo to, if not using current working
      directory
   -  ``name``: Name to clone the repo as, if not using the existing
      name
   -  ``recursive``: Pass –recursive to ``git clone`` if True
   -  ``debug``: Insert breakpoint before subprocess calls if True
   -  ``timeout``: Seconds to wait before stopping commands
   -  ``exception``: Raise exception if git command has error if True
   -  ``show``: Display git commands before executing if True
   -  Returns: Local path to cloned repo or None
   -  Internal calls: ``bh.run()``

-  **``git_fetch(path='', output=False, debug=False, timeout=None, exception=True, show=False)``**
   - Perform ``git fetch --all --prune``

   -  ``path``: Path to git repo, if not using current working directory
   -  ``output``: Return output of ``git fetch --all --prune`` if True
   -  ``debug``: Insert breakpoint before subprocess calls if True
   -  ``timeout``: Seconds to wait before stopping commands
   -  ``exception``: Raise exception if git command has error if True
   -  ``show``: Display git commands before executing if True
   -  Returns: Command output if output=True, otherwise None
   -  Internal calls: ``ctx_repo_path_root()``, ``bh.run_output()``

-  **``git_do(path='', fetch=False, cmd=None, output=False, debug=False, timeout=None, exception=True, show=False)``**
   - Run specified cmd and either return the output or the exit status

   -  ``path``: Path to git repo, if not using current working directory
   -  ``fetch``: Call git_fetch func before calling the generated
      ``git`` command if True
   -  ``cmd``: String with shell command (required)
   -  ``output``: Capture output of cmd and return it if True; otherwise
      return exit status of cmd
   -  ``debug``: Insert breakpoint before subprocess calls if True
   -  ``timeout``: Seconds to wait before stopping commands
   -  ``exception``: Raise exception if git command has error if True
   -  ``show``: Display git commands before executing if True
   -  Returns: Command output or exit status depending on output
      parameter
   -  Internal calls: ``ctx_repo_path_root()``, ``bh.run_output()``,
      ``bh.run()``

-  **``git_origin_url(path='')``** - Return url to remote origin (from
   .git/config file)

   -  ``path``: Path to git repo, if not using current working directory
   -  Returns: String URL or empty string
   -  Internal calls: ``git_repo_path_root()``, ``bh.run_output()``

-  **``git_current_branch(path='', debug=False, timeout=None, exception=False, show=False)``**
   - Return current branch name

   -  ``path``: Path to git repo, if not using current working directory
   -  ``debug``: Insert breakpoint before subprocess calls if True
   -  ``timeout``: Seconds to wait before stopping commands
   -  ``exception``: Raise exception if git command has error if True
   -  ``show``: Display git commands before executing if True
   -  Returns: String branch name
   -  Internal calls: ``ctx_repo_path_root()``, ``bh.run_output()``

-  **``git_current_tracking_branch(path='', debug=False, timeout=None, exception=False, show=False)``**
   - Return remote tracking branch for current branch

   -  ``path``: Path to git repo, if not using current working directory
   -  ``debug``: Insert breakpoint before subprocess calls if True
   -  ``timeout``: Seconds to wait before stopping commands
   -  ``exception``: Raise exception if git command has error if True
   -  ``show``: Display git commands before executing if True
   -  Returns: String tracking branch name or empty string
   -  Internal calls: ``ctx_repo_path_root()``, ``bh.run_output()``,
      ``git_current_branch()``, ``bh.tools.grep_output()``

-  **``git_last_tag(path='', debug=False, timeout=None, exception=False, show=False)``**
   - Return the most recent tag made

   -  ``path``: Path to git repo, if not using current working directory
   -  ``debug``: Insert breakpoint before subprocess calls if True
   -  ``timeout``: Seconds to wait before stopping commands
   -  ``exception``: Raise exception if git command has error if True
   -  ``show``: Display git commands before executing if True
   -  Returns: String tag name or empty string
   -  Internal calls: ``ctx_repo_path_root()``, ``bh.run_output()``

-  **``git_tag_message(path='', debug=False, tag='', timeout=None, exception=False, show=False)``**
   - Return the message for specified tag

   -  ``path``: Path to git repo, if not using current working directory
   -  ``tag``: Name of a tag that was made
   -  ``debug``: Insert breakpoint before subprocess calls if True
   -  ``timeout``: Seconds to wait before stopping commands
   -  ``exception``: Raise exception if git command has error if True
   -  ``show``: Display git commands before executing if True
   -  Returns: String tag message
   -  Internal calls: ``ctx_repo_path_root()``, ``git_last_tag()``,
      ``bh.run_output()``

-  **``git_last_tag_message(path='', debug=False, timeout=None, exception=False, show=False)``**
   - Return the message for the most recent tag made

   -  ``path``: Path to git repo, if not using current working directory
   -  ``debug``: Insert breakpoint before subprocess calls if True
   -  ``timeout``: Seconds to wait before stopping commands
   -  ``exception``: Raise exception if git command has error if True
   -  ``show``: Display git commands before executing if True
   -  Returns: String tag message
   -  Internal calls: ``ctx_repo_path_root()``, ``git_last_tag()``,
      ``git_tag_message()``

-  **``git_tags(path='', debug=False, timeout=None, exception=False, show=False)``**
   - Return a list of all tags with most recent first

   -  ``path``: Path to git repo, if not using current working directory
   -  ``debug``: Insert breakpoint before subprocess calls if True
   -  ``timeout``: Seconds to wait before stopping commands
   -  ``exception``: Raise exception if git command has error if True
   -  ``show``: Display git commands before executing if True
   -  Returns: List of tag names
   -  Internal calls: ``ctx_repo_path_root()``, ``bh.run_output()``

-  **``git_first_commit_id(path='', debug=False, timeout=None, exception=False, show=False)``**
   - Get the first commit id for the repo

   -  ``path``: Path to git repo, if not using current working directory
   -  ``debug``: Insert breakpoint before subprocess calls if True
   -  ``timeout``: Seconds to wait before stopping commands
   -  ``exception``: Raise exception if git command has error if True
   -  ``show``: Display git commands before executing if True
   -  Returns: String commit ID or empty string
   -  Internal calls: ``ctx_repo_path_root()``, ``bh.run_output()``

-  **``git_last_commit_id(path='', debug=False, timeout=None, exception=False, show=False)``**
   - Get the last commit id for the repo

   -  ``path``: Path to git repo, if not using current working directory
   -  ``debug``: Insert breakpoint before subprocess calls if True
   -  ``timeout``: Seconds to wait before stopping commands
   -  ``exception``: Raise exception if git command has error if True
   -  ``show``: Display git commands before executing if True
   -  Returns: String commit ID or empty string
   -  Internal calls: ``ctx_repo_path_root()``, ``bh.run_output()``

-  **``git_commits_since_last_tag(path='', until='', debug=False, timeout=None, exception=False, show=False)``**
   - Return a list of commits made since last_tag

   -  ``path``: Path to git repo, if not using current working directory
   -  ``until``: A recent commit id to stop at (instead of last commit)
   -  ``debug``: Insert breakpoint before subprocess calls if True
   -  ``timeout``: Seconds to wait before stopping commands
   -  ``exception``: Raise exception if git command has error if True
   -  ``show``: Display git commands before executing if True
   -  Returns: List of commit strings (if no tag, returns commits since
      first commit)
   -  Internal calls: ``ctx_repo_path_root()``, ``git_last_tag()``,
      ``git_first_commit_id()``, ``git_last_commit_id()``,
      ``bh.run_output()``, ``ih.splitlines()``

-  **``git_unpushed_commits(path='', debug=False, timeout=None, exception=False, show=False)``**
   - Return a list of any local commits that have not been pushed

   -  ``path``: Path to git repo, if not using current working directory
   -  ``debug``: Insert breakpoint before subprocess calls if True
   -  ``timeout``: Seconds to wait before stopping commands
   -  ``exception``: Raise exception if git command has error if True
   -  ``show``: Display git commands before executing if True
   -  Returns: List of unpushed commit strings
   -  Internal calls: ``ctx_repo_path_root()``, ``bh.run_output()``,
      ``ih.splitlines()``

-  **``git_untracked_files(path='', debug=False, timeout=None, exception=False, show=False)``**
   - Return a list of any local files that are not tracked in the git
   repo

   -  ``path``: Path to git repo, if not using current working directory
   -  ``debug``: Insert breakpoint before subprocess calls if True
   -  ``timeout``: Seconds to wait before stopping commands
   -  ``exception``: Raise exception if git command has error if True
   -  ``show``: Display git commands before executing if True
   -  Returns: List of untracked file paths
   -  Internal calls: ``ctx_repo_path_root()``, ``bh.run_output()``,
      ``ih.splitlines()``

-  **``git_stashlist(path='', debug=False, timeout=None, exception=False, show=False)``**
   - Return a list of any local stashes

   -  ``path``: Path to git repo, if not using current working directory
   -  ``debug``: Insert breakpoint before subprocess calls if True
   -  ``timeout``: Seconds to wait before stopping commands
   -  ``exception``: Raise exception if git command has error if True
   -  ``show``: Display git commands before executing if True
   -  Returns: List of stash entries
   -  Internal calls: ``ctx_repo_path_root()``, ``bh.run_output()``,
      ``ih.splitlines()``

-  **``git_status(path='', debug=False, timeout=None, exception=False, show=False)``**
   - Return a list of any modified or untracked files

   -  ``path``: Path to git repo, if not using current working directory
   -  ``debug``: Insert breakpoint before subprocess calls if True
   -  ``timeout``: Seconds to wait before stopping commands
   -  ``exception``: Raise exception if git command has error if True
   -  ``show``: Display git commands before executing if True
   -  Returns: List of status entries
   -  Internal calls: ``ctx_repo_path_root()``, ``bh.run_output()``,
      ``ih.splitlines_and_strip()``

-  **``git_info_dict(path='', fetch=False, debug=False, timeout=None, exception=False, show=False)``**
   - Return a dict of info about the repo

   -  ``path``: Path to git repo, if not using current working directory
   -  ``fetch``: Call git_fetch func before calling the generated
      ``git`` command if True
   -  ``debug``: Insert breakpoint before subprocess calls if True
   -  ``timeout``: Seconds to wait before stopping commands
   -  ``exception``: Raise exception if git command has error if True
   -  ``show``: Display git commands before executing if True
   -  Returns: Dictionary with keys: ``path_root``, ``url``, ``branch``,
      ``branch_date``, ``branch_tracking``, ``branch_tracking_date``,
      ``last_tag``, ``status``, ``stashes``, ``unpushed``,
      ``commits_since_last_tag``
   -  Internal calls: ``ctx_repo_path_root()``,
      ``git_repo_path_root()``, ``git_origin_url()``,
      ``git_current_branch()``, ``git_branch_date()``,
      ``git_current_tracking_branch()``, ``git_last_tag()``,
      ``git_status()``, ``git_stashlist()``, ``git_unpushed_commits()``,
      ``git_commits_since_last_tag()``

-  **``git_info_string(path='', fetch=False, debug=False, timeout=None, exception=False, show=False)``**
   - Build up a string of info from git_info_dict and return it

   -  ``path``: Path to git repo, if not using current working directory
   -  ``fetch``: Call git_fetch func before calling the generated
      ``git`` command if True
   -  ``debug``: Insert breakpoint before subprocess calls if True
   -  ``timeout``: Seconds to wait before stopping commands
   -  ``exception``: Raise exception if git command has error if True
   -  ``show``: Display git commands before executing if True
   -  Returns: Formatted string with git repository information
   -  Internal calls: ``ctx_repo_path_root()``, ``git_info_dict()``

-  **``git_branch_date(path='', branch='', fetch=False, debug=False, timeout=None, exception=False, show=False)``**
   - Return datetime string (and relative age) of branch

   -  ``path``: Path to git repo, if not using current working directory
   -  ``branch``: Name of branch (prefix with ‘origin/’ for remote
      branch)
   -  ``fetch``: Call git_fetch func before calling the generated
      ``git`` command if True
   -  ``debug``: Insert breakpoint before subprocess calls if True
   -  ``timeout``: Seconds to wait before stopping commands
   -  ``exception``: Raise exception if git command has error if True
   -  ``show``: Display git commands before executing if True
   -  Returns: String with date and relative time
   -  Internal calls: ``ctx_repo_path_root()``, ``bh.run_output()``

-  **``git_remote_branches(path='', fetch=False, grep='', include_times=False, debug=False, timeout=None, exception=False, show=False)``**
   - Return list of remote branch names or list of dicts (via
   ``git ls-remote --heads``)

   -  ``path``: Path to git repo, if not using current working directory
   -  ``fetch``: Call git_fetch func before calling the generated
      ``git`` command if True
   -  ``grep``: ``grep -iE`` pattern to filter branches by
      (case-insensitive)
   -  ``include_times``: Include info from git_branch_date in results if
      True
   -  ``debug``: Insert breakpoint before subprocess calls if True
   -  ``timeout``: Seconds to wait before stopping commands
   -  ``exception``: Raise exception if git command has error if True
   -  ``show``: Display git commands before executing if True
   -  Returns: List of branch names or list of dicts (alphabetized if
      include_times=False, otherwise ordered by most recent commit)
   -  Internal calls: ``ctx_repo_path_root()``, ``bh.run_output()``,
      ``bh.tools.grep_output()``, ``_dates_for_branches()``

-  **``git_local_branches(path='', fetch=False, grep='', include_times=False, debug=False, timeout=None, exception=False, show=False)``**
   - Return list of local branch names or list of dicts (via
   ``git branch``)

   -  ``path``: Path to git repo, if not using current working directory
   -  ``fetch``: Call git_fetch func before calling the generated
      ``git`` command if True
   -  ``grep``: ``grep -iE`` pattern to filter branches by
      (case-insensitive)
   -  ``include_times``: Include info from git_branch_date in results if
      True
   -  ``debug``: Insert breakpoint before subprocess calls if True
   -  ``timeout``: Seconds to wait before stopping commands
   -  ``exception``: Raise exception if git command has error if True
   -  ``show``: Display git commands before executing if True
   -  Returns: List of branch names or list of dicts (alphabetized if
      include_times=False, otherwise ordered by most recent commit)
   -  Internal calls: ``ctx_repo_path_root()``, ``bh.run_output()``,
      ``bh.tools.grep_output()``, ``_dates_for_branches()``

-  **``git_remote_branches_merged_with(path='', branch='develop', fetch=False, include_times=False, debug=False, timeout=None, exception=False, show=False)``**
   - Return a list of branches on origin that have been merged with
   branch

   -  ``path``: Path to git repo, if not using current working directory
   -  ``branch``: Remote branch name (without leading ‘origin/’)
   -  ``fetch``: Call git_fetch func before calling the generated
      ``git`` command if True
   -  ``include_times``: Include info from git_branch_date in results if
      True
   -  ``debug``: Insert breakpoint before subprocess calls if True
   -  ``timeout``: Seconds to wait before stopping commands
   -  ``exception``: Raise exception if git command has error if True
   -  ``show``: Display git commands before executing if True
   -  Returns: List of merged branch names or list of dicts
   -  Internal calls: ``ctx_repo_path_root()``, ``bh.run_output()``,
      ``bh.tools.grep_output()``, ``_dates_for_branches()``

-  **``git_local_branches_merged_with(path='', branch='develop', fetch=False, include_times=False, debug=False, timeout=None, exception=False, show=False)``**
   - Return a list of local branches that have been merged with branch

   -  ``path``: Path to git repo, if not using current working directory
   -  ``branch``: Local branch name
   -  ``fetch``: Call git_fetch func before calling the generated
      ``git`` command if True
   -  ``include_times``: Include info from git_branch_date in results if
      True
   -  ``debug``: Insert breakpoint before subprocess calls if True
   -  ``timeout``: Seconds to wait before stopping commands
   -  ``exception``: Raise exception if git command has error if True
   -  ``show``: Display git commands before executing if True
   -  Returns: List of merged branch names or list of dicts
   -  Internal calls: ``ctx_repo_path_root()``, ``bh.run_output()``,
      ``bh.tools.grep_output()``, ``_dates_for_branches()``

Docker Operations (``bh.tools.*``)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Docker functions provide container lifecycle management with
service-specific shortcuts and platform adaptation.

-  **``docker_ok(exception=False)``** - Check if Docker daemon is
   available and running

   -  ``exception``: Raise exception if Docker unavailable and True
   -  Returns: Boolean indicating Docker availability
   -  Internal calls: ``bh.run_output()``

-  **``docker_stop(name, kill=False, signal='KILL', rm=False, exception=False, show=False)``**
   - Return True if successfully stopped

   -  ``name``: Name of the container
   -  ``kill``: Kill the container instead of stopping if True
   -  ``signal``: Signal to send to the container if kill is True
   -  ``rm``: Remove the container after stop/kill if True
   -  ``exception``: Raise exception if docker has error response and
      True
   -  ``show``: Show the docker commands and output if True
   -  Returns: Boolean success status
   -  Internal calls: ``docker_ok()``, ``bh.run_output()``

-  **``docker_start_or_run(name, image='', command='', detach=True, rm=False, interactive=False, ports='', volumes='', platform='', env_vars={}, exception=False, show=False, force=False)``**
   - Start existing container or create/run container

   -  ``name``: Name for the container
   -  ``image``: Image to use (i.e. image:tag)
   -  ``command``: Command to run in the container
   -  ``detach``: Run container in the background if True (set to False
      if interactive is True)
   -  ``rm``: Automatically delete the container when it exits if True
   -  ``interactive``: Keep STDIN open and allocate pseudo-TTY if True
   -  ``ports``: String containing {host-port}:{container-port} pairs
      separated by , ; \|
   -  ``volumes``: String containing {host-path}:{container-path} pairs
      separated by , ; \|
   -  ``platform``: Platform to set if server is multi-platform capable
   -  ``env_vars``: Dict of environment variables and values to set
   -  ``exception``: Raise exception if docker has error response and
      True
   -  ``show``: Show the docker commands and output if True
   -  ``force``: Stop the container and remove it before re-creating if
      True
   -  Returns: Boolean success status
   -  Internal calls: ``docker_ok()``, ``docker_stop()``,
      ``ih.string_to_list()``, ``bh.run()``, ``bh.run_output()``

-  **``docker_container_id(name)``** - Return the container ID for
   running container name

   -  ``name``: Name of the container
   -  Returns: String container ID or empty string
   -  Internal calls: ``docker_ok()``, ``bh.run_output()``

-  **``docker_container_inspect(name, exception=False, show=False)``** -
   Return detailed information on specified container as a list

   -  ``name``: Name of the container
   -  ``exception``: Raise exception if docker has error response and
      True
   -  ``show``: Show the docker command and output if True
   -  Returns: List of container information dictionaries
   -  Internal calls: ``docker_ok()``, ``bh.run_output()``

-  **``docker_container_config(name, exception=False, show=False)``** -
   Return dict of config information for specified container (from
   inspect)

   -  ``name``: Name of the container
   -  ``exception``: Raise exception if docker has error response and
      True
   -  ``show``: Show the docker command and output if True
   -  Returns: Dictionary of container configuration
   -  Internal calls: ``docker_container_inspect()``

-  **``docker_container_env_vars(name, exception=False, show=False)``**
   - Return dict of environment vars for specified container

   -  ``name``: Name of the container
   -  ``exception``: Raise exception if docker has error response and
      True
   -  ``show``: Show the docker command and output if True
   -  Returns: Dictionary of environment variables
   -  Internal calls: ``docker_container_config()``

-  **``docker_logs(name, num_lines=None, follow=False, details=False, since='', until='', timestamps=False, show=False)``**
   - Show logs on an existing container

   -  ``name``: Name of the container
   -  ``num_lines``: Number of lines to show from the end of the logs
   -  ``follow``: Follow log output if True
   -  ``details``: Show extra details provided to logs if True
   -  ``since``: Show logs since timestamp (iso format or relative)
   -  ``until``: Show logs before timestamp (iso format or relative)
   -  ``timestamps``: Show timestamps if True
   -  ``show``: Show the docker command and output if True
   -  Returns: Exit code or log output
   -  Internal calls: ``docker_ok()``, ``bh.run()``, ``bh.run_output()``

-  **``docker_exec(name, command='pwd', output=False, env_vars={}, show=False)``**
   - Run shell command on an existing container (will be started if
   stopped)

   -  ``name``: Name of the container
   -  ``command``: Command to execute
   -  ``output``: Return output or error from command if True; otherwise
      return exit status
   -  ``env_vars``: Dict of environment variables and values to set
   -  ``show``: Show the docker command and output if True
   -  Returns: Command output or exit status
   -  Internal calls: ``docker_ok()``, ``docker_start_or_run()``,
      ``bh.run_output()``, ``bh.run()``

-  **``docker_exec_wait(name, command='pwd', sleeptime=2, env_vars={}, show=False)``**
   - Wait for a shell command to succeed in an existing container (will
   be started if stopped)

   -  ``name``: Name of the container
   -  ``command``: Command to execute
   -  ``sleeptime``: Time to sleep between checks
   -  ``env_vars``: Dict of environment variables and values to set
   -  ``show``: Show the docker command and output if True
   -  Returns: None (blocks until command succeeds)
   -  Internal calls: ``docker_exec()``

-  **``docker_shell(name, shell='sh', env_vars={}, show=False)``** -
   Start shell on an existing container (will be started if stopped)

   -  ``name``: Name of the container
   -  ``shell``: Name of shell to execute
   -  ``env_vars``: Dict of environment variables and values to set
   -  ``show``: Show the docker command and output if True
   -  Returns: Exit code
   -  Internal calls: ``docker_ok()``, ``docker_start_or_run()``,
      ``bh.run()``

-  **``docker_cleanup_volumes(exception=False, show=False)``** - Use
   this when creating a container fails with ‘No space left on device’

   -  ``exception``: Raise exception if docker has error response and
      True
   -  ``show``: Show the docker command and output if True
   -  Returns: Boolean success status
   -  Internal calls: ``docker_start_or_run()``

Database Service Functions
^^^^^^^^^^^^^^^^^^^^^^^^^^

-  **``docker_redis_start(name, version='6-alpine', port=6300, data_dir=None, aof=True, interactive=False, rm=False, exception=False, show=False, force=False)``**
   - Start or create redis container

   -  ``name``: Name for the container
   -  ``version``: Redis image version
   -  ``port``: Port to map into the container
   -  ``data_dir``: Directory that will map to container’s /data
      (absolute path or subdirectory of current directory)
   -  ``aof``: Use appendonly.aof file if True
   -  ``interactive``: Keep STDIN open and allocate pseudo-TTY if True
   -  ``rm``: Automatically delete the container when it exits if True
   -  ``exception``: Raise exception if docker has error response and
      True
   -  ``show``: Show the docker commands and output if True
   -  ``force``: Stop the container and remove it before re-creating if
      True
   -  Returns: Boolean success status
   -  Internal calls: ``docker_start_or_run()``

-  **``docker_redis_cli(name, show=False)``** - Start redis-cli on an
   existing container (will be started if stopped)

   -  ``name``: Name for the container
   -  ``show``: Show the docker command and output if True
   -  Returns: Exit code
   -  Internal calls: ``docker_shell()``

-  **``docker_mongo_start(name, version='4.4', port=27000, username='mongouser', password='some.pass', data_dir=None, interactive=False, rm=False, exception=False, show=False, force=False, wait=False, sleeptime=2)``**
   - Start or create mongo container

   -  ``name``: Name for the container
   -  ``version``: Mongo image version
   -  ``port``: Port to map into the container
   -  ``username``: Username to set for root user on first run
   -  ``password``: Password to set for root user on first run
   -  ``data_dir``: Directory that will map to container’s /data/db
      (absolute path or subdirectory of current directory)
   -  ``interactive``: Keep STDIN open and allocate pseudo-TTY if True
   -  ``rm``: Automatically delete the container when it exits if True
   -  ``exception``: Raise exception if docker has error response and
      True
   -  ``show``: Show the docker commands and output if True
   -  ``force``: Stop the container and remove it before re-creating if
      True
   -  ``wait``: Don’t return until mongo is able to accept connections
      if True
   -  ``sleeptime``: If wait is True, sleep this number of seconds
      before checks
   -  Returns: Boolean success status
   -  Internal calls: ``docker_start_or_run()``

-  **``docker_mongo_cli(name, show=False)``** - Start mongo on an
   existing container (will be started if stopped)

   -  ``name``: Name for the container
   -  ``show``: Show the docker command and output if True
   -  Returns: Exit code
   -  Internal calls: ``docker_container_env_vars()``,
      ``docker_shell()``

-  **``docker_mongo_wait(name, sleeptime=2, show=False)``** - Wait for
   mongo on an existing container (will be started if stopped)

   -  ``name``: Name of the container
   -  ``sleeptime``: Time to sleep between checks
   -  ``show``: Show the docker command and output if True
   -  Returns: None (blocks until postgres is ready)
   -  Internal calls: ``docker_container_env_vars()``,
      ``docker_exec_wait()``

-  **``docker_postgres_start(name, version='13-alpine', port=5400, username='postgresuser', password='some.pass', db='postgresdb', data_dir=None, interactive=False, rm=False, exception=False, show=False, force=False, wait=False, sleeptime=2)``**
   - Start or create postgres container

   -  ``name``: Name for the container
   -  ``version``: Postgres image version
   -  ``port``: Port to map into the container
   -  ``username``: Username to set as superuser on first run
   -  ``password``: Password to set for superuser on first run
   -  ``db``: Name of default database
   -  ``data_dir``: Directory that will map to container’s
      /var/lib/postgresql/data (absolute path or subdirectory of current
      directory)
   -  ``interactive``: Keep STDIN open and allocate pseudo-TTY if True
   -  ``rm``: Automatically delete the container when it exits if True
   -  ``exception``: Raise exception if docker has error response and
      True
   -  ``show``: Show the docker commands and output if True
   -  ``force``: Stop the container and remove it before re-creating if
      True
   -  ``wait``: Don’t return until postgres is able to accept
      connections if True
   -  ``sleeptime``: If wait is True, sleep this number of seconds
      before checks
   -  Returns: Boolean success status
   -  Internal calls: ``docker_start_or_run()``,
      ``docker_postgres_wait()``

-  **``docker_postgres_cli(name, show=False)``** - Start psql on an
   existing container (will be started if stopped)

   -  ``name``: Name for the container
   -  ``show``: Show the docker command and output if True
   -  Returns: Exit code
   -  Internal calls: ``docker_container_env_vars()``,
      ``docker_shell()``

-  **``docker_postgres_wait(name, sleeptime=2, show=False)``** - Wait
   for psql on an existing container (will be started if stopped)

   -  ``name``: Name of the container
   -  ``sleeptime``: Time to sleep between checks
   -  ``show``: Show the docker command and output if True
   -  Returns: None (blocks until postgres is ready)
   -  Internal calls: ``docker_container_env_vars()``,
      ``docker_exec_wait()``

-  **``docker_mysql_start(name, version='8.0', port=3300, root_password='root.pass', username='mysqluser', password='some.pass', db='mysqldb', data_dir=None, interactive=False, rm=False, exception=False, show=False, force=False, wait=False, sleeptime=2)``**
   - Start or create mysql container

   -  ``name``: Name for the container
   -  ``version``: MySQL image version (or mysql/mysql-server for Mac
      M1)
   -  ``port``: Port to map into the container
   -  ``root_password``: Password to set for the root superuser account
   -  ``username``: Username to set as superuser on first run
   -  ``password``: Password to set for superuser on first run
   -  ``db``: Name of default database
   -  ``data_dir``: Directory that will map to container’s
      /var/lib/mysql (absolute path or subdirectory of current
      directory)
   -  ``interactive``: Keep STDIN open and allocate pseudo-TTY if True
   -  ``rm``: Automatically delete the container when it exits if True
   -  ``exception``: Raise exception if docker has error response and
      True
   -  ``show``: Show the docker commands and output if True
   -  ``force``: Stop the container and remove it before re-creating if
      True
   -  ``wait``: Don’t return until mysql is able to accept connections
      if True
   -  ``sleeptime``: If wait is True, sleep this number of seconds
      before checks
   -  Returns: Boolean success status
   -  Internal calls: ``bh.run_output()``, ``docker_start_or_run()``,
      ``docker_mysql_wait()``

-  **``docker_mysql_cli(name, show=False)``** - Start mysql on an
   existing container (will be started if stopped)

   -  ``name``: Name of the container
   -  ``show``: Show the docker command and output if True
   -  Returns: Exit code
   -  Internal calls: ``docker_container_env_vars()``,
      ``docker_shell()``

-  **``docker_mysql_wait(name, sleeptime=2, show=False)``** - Wait for
   mysql on an existing container (will be started if stopped)

   -  ``name``: Name of the container
   -  ``sleeptime``: Time to sleep between checks
   -  ``show``: Show the docker command and output if True
   -  Returns: None (blocks until mysql is ready)
   -  Internal calls: ``docker_container_env_vars()``,
      ``docker_exec_wait()``

OS Container Functions
^^^^^^^^^^^^^^^^^^^^^^

-  **``docker_alpine_start(name, version='3.12', command='sleep 86400', detach=True, interactive=False, rm=False, exception=False, show=False, force=False)``**
   - Start or create alpine container

   -  ``name``: Name for the container
   -  ``version``: Alpine image version
   -  ``command``: Command to run (default is sleep for a day)
   -  ``detach``: Run container in the background if True (set to False
      if interactive is True)
   -  ``interactive``: Keep STDIN open and allocate pseudo-TTY if True
   -  ``rm``: Automatically delete the container when it exits if True
   -  ``exception``: Raise exception if docker has error response and
      True
   -  ``show``: Show the docker commands and output if True
   -  ``force``: Stop the container and remove it before re-creating if
      True
   -  Returns: Boolean success status
   -  Internal calls: ``docker_start_or_run()``

-  **``docker_ubuntu_start(name, version='18.04', command='sleep 86400', detach=True, interactive=False, rm=False, exception=False, show=False, force=False)``**
   - Start or create ubuntu container

   -  ``name``: Name for the container
   -  ``version``: Ubuntu image version
   -  ``command``: Command to run (default is sleep for a day)
   -  ``detach``: Run container in the background if True (set to False
      if interactive is True)
   -  ``interactive``: Keep STDIN open and allocate pseudo-TTY if True
   -  ``rm``: Automatically delete the container when it exits if True
   -  ``exception``: Raise exception if docker has error response and
      True
   -  ``show``: Show the docker commands and output if True
   -  ``force``: Stop the container and remove it before re-creating if
      True
   -  Returns: Boolean success status
   -  Internal calls: ``docker_start_or_run()``

-  **``docker_fedora_start(name, version='33', command='sleep 86400', detach=True, interactive=False, rm=False, exception=False, show=False, force=False)``**
   - Start or create fedora container

   -  ``name``: Name for the container
   -  ``version``: Fedora image version
   -  ``command``: Command to run (default is sleep for a day)
   -  ``detach``: Run container in the background if True (set to False
      if interactive is True)
   -  ``interactive``: Keep STDIN open and allocate pseudo-TTY if True
   -  ``rm``: Automatically delete the container when it exits if True
   -  ``exception``: Raise exception if docker has error response and
      True
   -  ``show``: Show the docker commands and output if True
   -  ``force``: Stop the container and remove it before re-creating if
      True
   -  Returns: Boolean success status
   -  Internal calls: ``docker_start_or_run()``

SSH Operations (``bh.tools.*``)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

SSH functions provide remote system access with connection management
and key discovery.

-  **``ssh_to_server(ip_or_hostname, user=None, pem_file=None, private_key_file=None, command='', timeout=None, verbose=False)``**
   - Actually SSH to a server and run a command or start interactive
   session

   -  ``ip_or_hostname``: IP address or hostname of server
   -  ``user``: Remote SSH user
   -  ``pem_file``: Absolute path to pem file
   -  ``private_key_file``: Absolute path to private key file
   -  ``command``: Optional command to run on the remote server (if
      specified, output is returned; if not, session is interactive)
   -  ``timeout``: Number of seconds to wait for a specified command to
      run on the remote server
   -  ``verbose``: Print the generated SSH command and result if True
   -  Returns: Command output if command specified, otherwise exit code
   -  Internal calls: ``ssh_configured_hosts()``, ``bh.run_output()``,
      ``bh.run()``

-  **``ssh_pem_files()``** - Find all .pem files in ~/.ssh and return a
   dict with absolute paths

   -  Returns: Dictionary mapping filename (without extension) to
      absolute path
   -  Internal calls: ``fh.strip_extension()``

-  **``ssh_private_key_files()``** - Find all private key files in
   ~/.ssh and return a dict with absolute paths

   -  Returns: Dictionary mapping filename (without extension) to
      absolute path
   -  Internal calls: ``fh.strip_extension()``

-  **``ssh_configured_hosts()``** - Return a set of Hosts from the
   ~/.ssh/config file

   -  Returns: Set of configured host names
   -  Internal calls: ``fh.abspath()``

-  **``ssh_determine_aws_user_for_server(ip_or_hostname, pem_file, verbose=False)``**
   - Determine which AWS default user is setup for server

   -  ``ip_or_hostname``: IP address or hostname of server
   -  ``pem_file``: Absolute path to pem file
   -  ``verbose``: Show info for each attempt if True
   -  Returns: String username if found, otherwise None
   -  Internal calls: ``ssh_to_server()``

Grep Operations (``bh.tools.*``)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Enhanced text search with pattern matching capabilities.

-  **``grep_output(output, pattern=None, regex=None, ignore_case=True, invert=False, lines_before_match=None, lines_after_match=None, results_as_string=False, join_result_string_on='\n', strip_whitespace=False, no_filename=False, line_number=False, only_matching=False, byte_offset=False, suppress_errors=True, extra_pipe=None, show=False)``**
   - Use grep to match lines of output against pattern

   -  ``output``: Some output you would be piping to grep in a shell
      environment
   -  ``pattern``: Grep pattern string (extended ``-E`` style allowed)
   -  ``regex``: Compiled regular expression (from re.compile) or string
      that can be passed to re.compile
   -  ``ignore_case``: Ignore case (``grep -i`` or re.IGNORECASE) if
      True
   -  ``invert``: Select non-matching items (``grep -v``) if True (only
      applied when using pattern, not regex)
   -  ``lines_before_match``: Number of context lines to show before
      match (only applied when using pattern, not regex)
   -  ``lines_after_match``: Number of context lines to show after match
      (only applied when using pattern, not regex)
   -  ``results_as_string``: Return a string instead of a list of
      strings if True
   -  ``join_result_string_on``: Character or string to join a list of
      strings on
   -  ``strip_whitespace``: Strip trailing and leading whitespace for
      results if True
   -  ``no_filename``: Do not prefix matching lines with their
      corresponding file names if True (only applied when using pattern,
      not regex)
   -  ``line_number``: Prefix matching lines with line number within its
      input file if True (only applied when using pattern, not regex)
   -  ``only_matching``: Print only the matched parts of a matching line
      if True (only applied when using pattern, not regex)
   -  ``byte_offset``: Print the byte offset within the input file
      before each line of output if True (only applied when using
      pattern, not regex)
   -  ``suppress_errors``: Suppress error messages about nonexistent or
      unreadable files if True (only applied when using pattern, not
      regex)
   -  ``extra_pipe``: String containing other command(s) to pipe grepped
      output to (only applied when using pattern, not regex)
   -  ``show``: Show the ``grep`` command before executing if True (only
      applied when using pattern, not regex)
   -  Returns: List of strings (split on newline) or string if
      results_as_string=True
   -  Internal calls: ``_prep_common_grep_args()``, ``bh.run_output()``,
      ``ih.splitlines()``, ``ih.splitlines_and_strip()``

-  **``grep_path(pattern, path='', recursive=True, ignore_case=True, invert=False, lines_before_match=None, lines_after_match=None, exclude_files=None, exclude_dirs=None, results_as_string=False, join_result_string_on='\n', strip_whitespace=False, no_filename=False, line_number=False, only_matching=False, byte_offset=False, suppress_errors=True, extra_pipe=None, color=False, show=False)``**
   - Use grep to match lines in files at a path against pattern

   -  ``pattern``: Grep pattern string (extended ``-E`` style allowed)
   -  ``path``: Path to directory where the search should be started, if
      not using current working directory
   -  ``recursive``: Use ``-R`` to search all files at path if True
   -  ``ignore_case``: Ignore case (``grep -i``) if True
   -  ``invert``: Select non-matching items (``grep -v``) if True
   -  ``lines_before_match``: Number of context lines to show before
      match
   -  ``lines_after_match``: Number of context lines to show after match
   -  ``exclude_files``: List of file names and patterns to exclude from
      searching or string separated by , ; \|
   -  ``exclude_dirs``: List of dir names and patterns to exclude from
      searching or string separated by , ; \|
   -  ``results_as_string``: Return a string instead of a list of
      strings if True
   -  ``join_result_string_on``: Character or string to join a list of
      strings on
   -  ``strip_whitespace``: Strip trailing and leading whitespace for
      results if True
   -  ``no_filename``: Do not prefix matching lines with their
      corresponding file names if True
   -  ``line_number``: Prefix matching lines with line number within its
      input file if True
   -  ``only_matching``: Print only the matched parts of a matching line
      if True
   -  ``byte_offset``: Print the byte offset within the input file
      before each line of output if True
   -  ``suppress_errors``: Suppress error messages about nonexistent or
      unreadable files if True
   -  ``extra_pipe``: String containing other command(s) to pipe grepped
      output to
   -  ``color``: Will invoke the generated grep command with ``bh.run``
      (output will not be captured) if True
   -  ``show``: Show the ``grep`` command before executing if True
   -  Returns: List of strings or string if results_as_string=True, or
      exit code if color=True
   -  Internal calls: ``fh.abspath()``, ``_prep_common_grep_args()``,
      ``bh.run()``, ``bh.run_output()``, ``ih.splitlines()``,
      ``ih.splitlines_and_strip()``

-  **``grep_path_count(pattern, path='', recursive=True, ignore_case=True, invert=False, exclude_files=None, exclude_dirs=None, suppress_errors=True, results_as_string=False, join_result_string_on='\n', show=False)``**
   - Use grep to count the match lines in files at a path against
   pattern

   -  ``pattern``: Grep pattern string (extended ``-E`` style allowed)
   -  ``path``: Path to directory where the search should be started, if
      not using current working directory
   -  ``recursive``: Use ``-R`` to search all files at path if True
   -  ``ignore_case``: Ignore case (``grep -i``) if True
   -  ``invert``: Select non-matching items (``grep -v``) if True
   -  ``exclude_files``: List of file names and patterns to exclude from
      searching or string separated by , ; \|
   -  ``exclude_dirs``: List of dir names and patterns to exclude from
      searching or string separated by , ; \|
   -  ``suppress_errors``: Suppress error messages about nonexistent or
      unreadable files if True
   -  ``results_as_string``: Return a string instead of a list of tuples
      if True
   -  ``join_result_string_on``: Character or string to join a list of
      strings on
   -  ``show``: Show the ``grep`` command before executing if True
   -  Returns: List of 2-item tuples (filename, count) sorted by count
      descending then filename ascending
   -  Internal calls: ``fh.abspath()``, ``_prep_common_grep_args()``,
      ``bh.run_output()``

-  **``grep_path_count_dirs(pattern, path='', recursive=True, ignore_case=True, invert=False, exclude_files=None, exclude_dirs=None, suppress_errors=True, results_as_string=False, join_result_string_on='\n', show=False)``**
   - Use grep to count match lines in files against pattern, aggregated
   by dir

   -  ``pattern``: Grep pattern string (extended ``-E`` style allowed)
   -  ``path``: Path to directory where the search should be started, if
      not using current working directory
   -  ``recursive``: Use ``-R`` to search all files at path if True
   -  ``ignore_case``: Ignore case (``grep -i``) if True
   -  ``invert``: Select non-matching items (``grep -v``) if True
   -  ``exclude_files``: List of file names and patterns to exclude from
      searching or string separated by , ; \|
   -  ``exclude_dirs``: List of dir names and patterns to exclude from
      searching or string separated by , ; \|
   -  ``suppress_errors``: Suppress error messages about nonexistent or
      unreadable files if True
   -  ``results_as_string``: Return a string instead of a list of tuples
      if True
   -  ``join_result_string_on``: Character or string to join a list of
      strings on
   -  ``show``: Show the ``grep`` command before executing if True
   -  Returns: List of 2-item tuples (dirname, count) sorted by count
      descending then dirname ascending
   -  Internal calls: ``fh.abspath()``, ``_prep_common_grep_args()``,
      ``bh.run_output()``

-  **``grep_select_vim(pattern, path='', recursive=True, ignore_case=True, invert=False, lines_before_match=None, lines_after_match=None, exclude_files=None, exclude_dirs=None, suppress_errors=True, open_all_together=False)``**
   - Use grep to find files, then present a menu of results and line
   numbers

   -  ``pattern``: Grep pattern string (extended ``-E`` style allowed)
   -  ``path``: Path to directory where the search should be started, if
      not using current working directory
   -  ``recursive``: Use ``-R`` to search all files at path if True
   -  ``ignore_case``: Ignore case (``grep -i``) if True
   -  ``invert``: Select non-matching items (``grep -v``) if True
   -  ``lines_before_match``: Number of context lines to show before
      match
   -  ``lines_after_match``: Number of context lines to show after match
   -  ``exclude_files``: List of file names and patterns to exclude from
      searching or string separated by , ; \|
   -  ``exclude_dirs``: List of dir names and patterns to exclude from
      searching or string separated by , ; \|
   -  ``suppress_errors``: Suppress error messages about nonexistent or
      unreadable files if True
   -  ``open_all_together``: Don’t open each individual file to the line
      number, just open them all in the same vim session if True
   -  Returns: None (opens selected files in vim)
   -  Internal calls: ``fh.abspath()``, ``_prep_common_grep_args()``,
      ``bh.run_output()``, ``ih.splitlines()``,
      ``ih.make_selections()``, ``bh.run()``

Pip Operations (``bh.tools.*``)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Python package management utilities.

-  **``installed_packages(name_only=False)``** - Return a dict or list
   of installed packages from importlib_metadata.distributions

   -  ``name_only``: Return a list of package names only if True
   -  Returns: Dictionary mapping package names to versions, or list of
      package names if name_only=True
   -  Internal calls: None

-  **``installed_packages_by_dir()``** - Return a dict of installed
   packages from importlib_metadata.distributions

   -  Returns: Dictionary with ‘standard’ key (dict of standard packages
      and versions) and ‘other’ key (dict of packages installed outside
      of PATH_TO_SITE_PACKAGES)
   -  Internal calls: None

-  **``installed_packages_non_site_packages()``** - Return a dict of
   installed packages from importlib_metadata.distributions

   -  Returns: Dictionary of packages not in PATH_TO_SITE_PACKAGES
      mapped to their paths
   -  Internal calls: None

-  **``pip_freeze(pip_path='', venv_only=True, debug=False, timeout=None, exception=True, show=False)``**
   - Run pip freeze command

   -  ``pip_path``: Absolute path to pip in a virtual environment (use
      derived PATH_TO_PIP if not specified)
   -  ``venv_only``: Only run pip if it’s in a venv if True
   -  ``debug``: Insert breakpoint before subprocess calls if True
   -  ``timeout``: Seconds to wait before stopping commands
   -  ``exception``: Raise exception if pip command has error if True
   -  ``show``: Show the ``pip`` command before executing if True
   -  Returns: Exit code
   -  Internal calls: ``bh.run()``

-  **``pip_install_editable(paths, pip_path='', venv_only=True, debug=False, timeout=None, exception=True, show=False)``**
   - Pip install the given paths in “editable mode”

   -  ``paths``: Local paths to projects to install in “editable mode”
      (list of strings OR string separated by , ; \|)
   -  ``pip_path``: Absolute path to pip in a virtual environment (use
      derived PATH_TO_PIP if not specified)
   -  ``venv_only``: Only run pip if it’s in a venv if True
   -  ``debug``: Insert breakpoint before subprocess calls if True
   -  ``timeout``: Seconds to wait before stopping commands
   -  ``exception``: Raise exception if pip command has error if True
   -  ``show``: Show the ``pip`` command before executing if True
   -  Returns: Exit code
   -  Internal calls: ``ih.get_list_from_arg_strings()``, ``bh.run()``

-  **``pip_extras(package_name, venv_only=True, exception=True)``** -
   Return the extras_requires keys for specified package

   -  ``package_name``: Name of the package to get extras_requires keys
   -  ``venv_only``: Only run pip if it’s in a venv if True
   -  ``exception``: Raise exception if pip command has error if True
   -  Returns: List of extras keys or None
   -  Internal calls: None

-  **``pip_version(pip_path='', venv_only=True, debug=False, exception=True)``**
   - Return a tuple for the pip version (major int, minor int, patch
   string)

   -  ``pip_path``: Absolute path to pip in a virtual environment (use
      derived PATH_TO_PIP if not specified)
   -  ``venv_only``: Only run pip if it’s in a venv if True
   -  ``debug``: Insert breakpoint before subprocess calls if True
   -  ``exception``: Raise exception if pip command has error if True
   -  Returns: Tuple (major, minor, patch)
   -  Internal calls: ``bh.run_output()``, ``bh.tools.grep_output()``,
      ``ih.string_to_version_tuple()``

-  **``pip_package_versions_available(package_name, pip_path='', venv_only=True, debug=False, exception=True)``**
   - Return a list of versions available on pypi for the given package

   -  ``package_name``: Name of the package on pypi.org
   -  ``pip_path``: Absolute path to pip in a virtual environment (use
      derived PATH_TO_PIP if not specified)
   -  ``venv_only``: Only run pip if it’s in a venv if True
   -  ``debug``: Insert breakpoint before subprocess calls if True
   -  ``exception``: Raise exception if pip command has error if True
   -  Returns: List of available version strings
   -  Internal calls: ``pip_version()``, ``bh.run_output()``,
      ``bh.tools.grep_output()``

Process Operations (``bh.tools.*``)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Process management utilities.

-  **``ps_output()``** - Return a list of dicts containing info about
   current running processes

   -  Returns: List of dictionaries with process information
   -  Internal calls: ``bh.run_output()``, ``PsOutputMatcher`` (from
      input_helper)

Python Environment Operations (``bh.tools.*``)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Python environment management through pyenv.

-  **``pyenv_install_python_version(*versions)``** - Use pyenv to
   install versions of Python

   -  ``versions``: List of versions to install (can also be a list of
      versions contained in a single string, separated by , ; \|)
   -  Returns: List of tuples (version, success_boolean)
   -  Internal calls: ``ih.get_list_from_arg_strings()``, ``bh.run()``

-  **``pyenv_update(show=True)``** - Update pyenv

   -  ``show``: Show the command before executing if True
   -  Returns: Boolean success status
   -  Internal calls: ``bh.run()``, ``bh.tools.git_repo_update()``

-  **``pyenv_get_installable_versions(only_py3=True, only_latest_per_group=True, only_released=True, only_non_released=False)``**
   - Return a list of Python versions that can be installed to
   ~/.pyenv/versions

   -  ``only_py3``: Only list standard Python 3.x versions if True
   -  ``only_latest_per_group``: Only include the latest version per
      group if True
   -  ``only_released``: Only include released versions, not
      alpha/beta/rc/dev/src if True
   -  ``only_non_released``: Only include non-released versions, like
      alpha/beta/rc/dev/src if True
   -  Returns: List of installable Python version strings
   -  Internal calls: ``bh.run_output()``, ``bh.tools.grep_output()``,
      ``ih.splitlines_and_strip()``

-  **``pyenv_select_python_versions_to_install(only_py3=True, only_latest_per_group=True, only_released=True, only_non_released=False)``**
   - Select versions of Python to install with pyenv

   -  ``only_py3``: Only select from standard Python 3.x versions if
      True
   -  ``only_latest_per_group``: Only include the latest version per
      group if True
   -  ``only_released``: Only include released versions, not
      alpha/beta/rc/dev/src if True
   -  ``only_non_released``: Only include non-released versions, like
      alpha/beta/rc/dev/src if True
   -  Returns: List of tuples (version, success_boolean) from
      installation
   -  Internal calls: ``pyenv_get_installable_versions()``,
      ``ih.make_selections()``, ``pyenv_install_python_version()``

-  **``pyenv_get_versions()``** - Return a list of Python versions
   locally installed to ~/.pyenv/versions

   -  Returns: List of installed Python version strings
   -  Internal calls: None

-  **``pyenv_path_to_python_version(version)``** - Return path to the
   installed Python binary for the given version or None

   -  ``version``: Python version string
   -  Returns: String path to Python binary or None
   -  Internal calls: None

-  **``pyenv_pip_versions(py_versions='')``** - Return a dict of default
   pip versions for each given Python version

   -  ``py_versions``: String containing locally installed Python
      versions separated by , ; \| (if none specified, use all local
      versions)
   -  Returns: Dictionary mapping Python versions to pip version tuples
   -  Internal calls: ``ih.get_list_from_arg_strings()``,
      ``pyenv_get_versions()``, ``bh.tools.pip_version()``

-  **``pyenv_pip_package_versions_available(package_name, py_versions='', show=False)``**
   - Return a dict of package versions available on pypi for the given
   package

   -  ``package_name``: Name of the package on pypi.org
   -  ``py_versions``: String containing locally installed Python
      versions separated by , ; \| (if none specified, use all local
      versions)
   -  ``show``: Display the results if True
   -  Returns: Dictionary mapping Python versions to lists of available
      package versions
   -  Internal calls: ``ih.get_list_from_arg_strings()``,
      ``pyenv_get_versions()``,
      ``bh.tools.pip_package_versions_available()``

-  **``pyenv_create_venvs_for_py_versions_and_dep_versions(base_dir, py_versions='', pip_version='', pip_latest=False, wheel_version='', wheel_latest=False, clean=False, die=False, local_package_paths='', extra_packages='', dep_versions_dict=None)``**
   - Create a combination of venvs for the given py_versions and
   dep_versions

   -  ``base_dir``: Path to directory where the venvs will be created
   -  ``py_versions``: String containing Python versions to make venvs
      for separated by , ; \| (if none specified, use all local
      versions)
   -  ``pip_version``: Specific version of pip to install first
   -  ``pip_latest``: Install latest version of pip if True (ignored if
      pip_version specified)
   -  ``wheel_version``: Specific version of wheel to install first
   -  ``wheel_latest``: Install latest version of wheel if True (ignored
      if wheel_version specified)
   -  ``clean``: Delete any existing venv that would be created if it
      exists if True
   -  ``die``: Return if any part of venv creation or pip install fails
      if True
   -  ``local_package_paths``: Local paths to projects to install in
      “editable mode” (may be a list or string separated by , ; \|)
   -  ``extra_packages``: String of extra packages to be installed in
      each venv (may be a list or string separated by , ; \|)
   -  ``dep_versions_dict``: Dict where keys are package names and
      values are specific versions (versions may be a list or string
      separated by , ; \|)
   -  Returns: None (creates virtual environments)
   -  Internal calls: ``fh.abspath()``,
      ``ih.get_list_from_arg_strings()``, ``pyenv_get_versions()``,
      ``pyenv_path_to_python_version()``,
      ``pyenv_install_python_version()``, ``bh.run()``

Basic Examples
--------------

::

   % ipython
   ...

   In [1]: import bg_helper as bh

   In [2]: def lame():
      ...:     return 1/0

   In [3]: def blah(*args, **kwargs):
      ...:     return locals()

   In [4]: bh.call_func(blah)
   Out[4]:
   {'args': '()',
    'func_name': 'blah',
    'kwargs': '{}',
    'status': 'ok',
    'value': {'args': (), 'kwargs': {}}}

   In [5]: bh.call_func(blah, 'cats', 'dogs')
   Out[5]:
   {'args': "('cats', 'dogs')",
    'func_name': 'blah',
    'kwargs': '{}',
    'status': 'ok',
    'value': {'args': ('cats', 'dogs'), 'kwargs': {}}}

   In [6]: bh.call_func(blah, 'cats', 'dogs', meh=[1, 2, 3, 4, 5])
   Out[6]:
   {'args': "('cats', 'dogs')",
    'func_name': 'blah',
    'kwargs': "{'meh': [1, 2, 3, 4, 5]}",
    'status': 'ok',
    'value': {'args': ('cats', 'dogs'), 'kwargs': {'meh': [1, 2, 3, 4, 5]}}}

   In [7]: bh.call_func(lame)
   ======================================================================
   2017-04-01 12:32:35,107: func=lame args=() kwargs={}
   Traceback (most recent call last):
     File "/tmp/here/venv/lib/python3.5/site-packages/bg_helper/__init__.py", line 70, in call_func
       value = func(*args, **kwargs)
     File "<ipython-input-2-ac0fa5de647a>", line 2, in lame
       return 1/0
   ZeroDivisionError: division by zero

   Out[7]:
   {'args': '()',
    'error_type': "<class 'ZeroDivisionError'>",
    'error_value': "ZeroDivisionError('division by zero',)",
    'fqdn': 'x200-purple',
    'func_doc': None,
    'func_module': '__main__',
    'func_name': 'lame',
    'kwargs': '{}',
    'status': 'error',
    'time_epoch': 1491067955.1004958,
    'time_string': '2017_0401-Sat-123235',
    'traceback_string': 'Traceback (most recent call last):\n  File "/tmp/here/venv/lib/python3.5/site-packages/bg_helper/__init__.py", line 70, in call_func\n    value = func(*args, **kwargs)\n  File "<ipython-input-2-ac0fa5de647a>", line 2, in lame\n    return 1/0\nZeroDivisionError: division by zero\n'}

   In [8]: cat log--bg-helper.log
   2017-04-01 12:32:35,107 - ERROR - call_func: func=lame args=() kwargs={}
   Traceback (most recent call last):
     File "/tmp/here/venv/lib/python3.5/site-packages/bg_helper/__init__.py", line 70, in call_func
       value = func(*args, **kwargs)
     File "<ipython-input-2-ac0fa5de647a>", line 2, in lame
       return 1/0
   ZeroDivisionError: division by zero

   In [9]: bh.SimpleBackgroundTask('echo "hello from console" > /tmp/blahblah.txt')
   Out[9]: <bg_helper.SimpleBackgroundTask at 0x7ff112229c18>

   In [10]: ls /tmp/blahblah.txt
   /tmp/blahblah.txt

   In [11]: cat /tmp/blahblah.txt
   hello from console

   In [12]: bh.SimpleBackgroundTask('echo "$(date)" >> /tmp/blahblah.txt')
   Out[12]: <bg_helper.SimpleBackgroundTask at 0x7ff110057cf8>

   In [13]: cat /tmp/blahblah.txt
   hello from console
   Sat Apr  1 12:33:23 CDT 2017



            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/kenjyco/bg-helper",
    "name": "bg-helper",
    "maintainer": null,
    "docs_url": null,
    "requires_python": null,
    "maintainer_email": null,
    "keywords": "background, shell, git, ssh, docker, pyenv, redis, mongodb, postgres, postgresql, mysql, helper, kenjyco",
    "author": "Ken",
    "author_email": "kenjyco@gmail.com",
    "download_url": "https://github.com/kenjyco/bg-helper/tarball/v0.1.24",
    "platform": null,
    "description": "``bg-helper`` is a Python library that provides production-ready shell\ncommand orchestration, Docker service management, git repository\nautomation, and more. It offers three core execution primitives\n(``run``, ``run_output``, ``run_or_die``) with universal timeout\nprotection and error handling, plus specialized tools for managing\nDocker containers (PostgreSQL, MySQL, Redis, MongoDB), git operations\nwith automatic context management, and Python environment automation via\npyenv. Rather than hiding complexity behind abstractions, ``bg-helper``\nprovides powerful primitives for shell command orchestration, background\ntask management, and DevOps workflow automation. You can always pass\n``show=True`` to see the actual commands being executed, learn the\nunderlying tools, and build transferable skills while providing\ncomprehensive error capture and background task management.\n\n**Who benefits from this?** - **DevOps engineers** who need reliable\nautomation for git repositories, Docker containers, and development\nenvironments - **Systems administrators** who want Python\u2019s power while\npreserving shell command fidelity - **Infrastructure teams** building\nautomation that must be debuggable, maintainable, and transparent -\n**Library developers** who need robust local integration testing with\nmultiple database services and Python versions - **Anyone** who has been\nburned by \u201cmagic\u201d tools and wants infrastructure code that reveals\nrather than conceals its operations\n\n``bg-helper`` fits naturally into existing toolchains by wrapping and\nenhancing familiar tools (git, docker, ssh) rather than replacing them.\nIt\u2019s designed for REPL-driven exploration that gradually evolves into\nproduction automation.\n\n**Particularly useful for integration testing:** The Docker service\nfunctions enable easy local testing across multiple database types\n(PostgreSQL, MySQL, Redis, MongoDB), while the pyenv functions support\ntesting across Python versions. The\n``pyenv_create_venvs_for_py_versions_and_dep_versions`` function is\nespecially powerful for creating test matrices across Python versions\nand dependency combinations, as demonstrated in libraries like\nsql-helper.\n\nInstall\n-------\n\n::\n\n   pip install bg-helper\n\nQuickStart\n----------\n\n.. code:: python\n\n   import bg_helper as bh\n\n   # Safe command execution with timeout protection and error capture\n   result = bh.run_output('ls -la', show=True)  # Shows actual command executed\n   print(result)\n\n   # Comprehensive error handling for any function\n   error_info = bh.call_func(lambda: 1/0)\n   if error_info['status'] == 'error':\n       print(f\"Function failed: {error_info['error_type']}\")\n       print(f\"Full traceback: {error_info['traceback_string']}\")\n\n   # Git operations with automatic repository context management\n   branch = bh.tools.git_current_branch(show=True)  # Learn the actual git commands\n   print(f\"Current branch: {branch}\")\n\n   # Docker service management with intelligent fallback logic\n   success = bh.tools.docker_postgres_start(\n       name='dev-db',\n       port=5432,\n       show=True  # See exactly what Docker commands are executed\n   )\n\n   # Background task execution with comprehensive error logging\n   task = bh.SimpleBackgroundTask('long-running-command --with-args')\n\n**What you gain:** Reliable shell command orchestration with\nproduction-grade error handling, automatic resource cleanup, timeout\nprotection, and complete operational transparency. Every operation can\nshow you the exact commands being executed, making debugging and\nlearning seamless.\n\nAPI Overview\n------------\n\nCore Execution Primitives\n~~~~~~~~~~~~~~~~~~~~~~~~~\n\nThese three functions form the foundation for all shell command\noperations, providing graduated levels of strictness:\n\n-  **``run(cmd, stderr_to_stdout=False, debug=False, timeout=None, exception=False, show=False)``**\n   - Execute a shell command and return the exit status\n\n   -  ``cmd``: Shell command string to execute\n   -  ``stderr_to_stdout``: Redirect stderr to stdout if True\n   -  ``debug``: Insert pdb breakpoint before execution if True\n   -  ``timeout``: Seconds to wait before stopping command (prevents\n      hanging)\n   -  ``exception``: Raise exception on non-zero exit status if True\n   -  ``show``: Display the actual command before execution if True\n   -  Returns: Integer exit status\n   -  Internal calls: None\n\n-  **``run_output(cmd, strip=True, debug=False, timeout=None, exception=False, show=False)``**\n   - Execute a shell command and return its output\n\n   -  ``cmd``: Shell command string to execute\n   -  ``strip``: Remove leading/trailing whitespace from output if True\n   -  ``debug``: Insert pdb breakpoint before execution if True\n   -  ``timeout``: Seconds to wait before stopping command\n   -  ``exception``: Raise exception on command failure if True\n   -  ``show``: Display the actual command before execution if True\n   -  Returns: Command output as string\n   -  Internal calls: None\n\n-  **``run_or_die(cmd, stderr_to_stdout=False, debug=False, timeout=None, exception=True, show=False)``**\n   - Execute a shell command with strict error handling\u2014fail fast on any\n   error\n\n   -  ``cmd``: Shell command string to execute\n   -  ``stderr_to_stdout``: Redirect stderr to stdout if True\n   -  ``debug``: Insert pdb breakpoint before execution if True\n   -  ``timeout``: Seconds to wait before stopping command\n   -  ``exception``: If True (default), raise exception on failure; if\n      False, exit process\n   -  ``show``: Display the actual command before execution if True\n   -  Returns: Integer exit status (only on success)\n   -  Internal calls: None\n\nError Handling and Background Tasks\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n-  **``call_func(func, *args, **kwargs)``** - Execute any Python\n   function with comprehensive error capture and forensic information\n\n   -  ``func``: Python function to execute\n   -  ``*args``: Arguments to pass to function\n   -  ``**kwargs``: Keyword arguments (special kwargs: ``logger``,\n      ``verbose``)\n   -  Returns: Dictionary with keys: ``func_name``, ``args``,\n      ``kwargs``, ``status`` (always present); ``value`` (on success);\n      ``error_type``, ``error_value``, ``traceback_string``, ``fqdn``,\n      ``time_epoch``, ``time_string``, ``func_doc``, ``func_module`` (on\n      error)\n   -  Internal calls: None\n\n-  **``SimpleBackgroundTask(func, *args, **kwargs)``** - Execute a\n   function or shell command in a background daemon thread with\n   automatic error logging\n\n   -  ``func``: Python callable or shell command string\n   -  ``*args``: Arguments for callable (ignored for shell commands)\n   -  ``**kwargs``: Keyword arguments for callable\n   -  Returns: Background task object (daemon threads won\u2019t prevent\n      process exit)\n   -  Internal calls: ``call_func()``\n\nGit Operations (``bh.tools.*``)\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nGit functions provide repository automation with automatic context\nmanagement and state isolation.\n\n-  **``ctx_repo_path_root(path, fetch=False, debug=False, timeout=None, exception=True, show=False)``**\n   - Context manager that changes to the root directory of a git\n   repository\n\n   -  ``path``: Path to file or directory in git repository\n   -  ``fetch``: Execute ``git fetch`` after changing directory if True\n   -  ``debug``: Insert breakpoint before subprocess calls if True\n   -  ``timeout``: Seconds to wait before stopping commands\n   -  ``exception``: Raise exception if path not in repo or fetch fails\n      if True\n   -  ``show``: Display directory change commands if True\n   -  Returns: Context manager\n   -  Internal calls: ``git_repo_path_root()``, ``git_fetch()``\n\n-  **``git_repo_path_root(path='', exception=False)``** - Return git\n   repo path root for path, or None\n\n   -  ``path``: Relative or absolute path to file or directory (current\n      working directory used if none specified)\n   -  ``exception``: Raise ValueError if path is not in a repo if True\n   -  Returns: String path to repo root or empty string\n   -  Internal calls: ``fh.repopath()``\n\n-  **``git_repo_update(path='', debug=False, timeout=None, exception=True, show=False)``**\n   - Update a repo and return True if it was successful\n\n   -  ``path``: Path to git repo, if not using current working directory\n   -  ``debug``: Insert breakpoint before subprocess calls if True\n   -  ``timeout``: Seconds to wait before stopping commands\n   -  ``exception``: Raise exception if git command has error if True\n   -  ``show``: Display git commands before executing if True\n   -  Returns: Boolean success status\n   -  Internal calls: ``ctx_repo_path_root()``,\n      ``git_current_tracking_branch()``, ``git_current_branch()``,\n      ``git_origin_url()``, ``git_fetch()``, ``bh.run_output()``,\n      ``bh.run()``\n\n-  **``git_clone(url, path='', name='', recursive=False, debug=False, timeout=None, exception=True, show=False)``**\n   - Clone a repo\n\n   -  ``url``: URL for a git repo\n   -  ``path``: Path to clone git repo to, if not using current working\n      directory\n   -  ``name``: Name to clone the repo as, if not using the existing\n      name\n   -  ``recursive``: Pass \u2013recursive to ``git clone`` if True\n   -  ``debug``: Insert breakpoint before subprocess calls if True\n   -  ``timeout``: Seconds to wait before stopping commands\n   -  ``exception``: Raise exception if git command has error if True\n   -  ``show``: Display git commands before executing if True\n   -  Returns: Local path to cloned repo or None\n   -  Internal calls: ``bh.run()``\n\n-  **``git_fetch(path='', output=False, debug=False, timeout=None, exception=True, show=False)``**\n   - Perform ``git fetch --all --prune``\n\n   -  ``path``: Path to git repo, if not using current working directory\n   -  ``output``: Return output of ``git fetch --all --prune`` if True\n   -  ``debug``: Insert breakpoint before subprocess calls if True\n   -  ``timeout``: Seconds to wait before stopping commands\n   -  ``exception``: Raise exception if git command has error if True\n   -  ``show``: Display git commands before executing if True\n   -  Returns: Command output if output=True, otherwise None\n   -  Internal calls: ``ctx_repo_path_root()``, ``bh.run_output()``\n\n-  **``git_do(path='', fetch=False, cmd=None, output=False, debug=False, timeout=None, exception=True, show=False)``**\n   - Run specified cmd and either return the output or the exit status\n\n   -  ``path``: Path to git repo, if not using current working directory\n   -  ``fetch``: Call git_fetch func before calling the generated\n      ``git`` command if True\n   -  ``cmd``: String with shell command (required)\n   -  ``output``: Capture output of cmd and return it if True; otherwise\n      return exit status of cmd\n   -  ``debug``: Insert breakpoint before subprocess calls if True\n   -  ``timeout``: Seconds to wait before stopping commands\n   -  ``exception``: Raise exception if git command has error if True\n   -  ``show``: Display git commands before executing if True\n   -  Returns: Command output or exit status depending on output\n      parameter\n   -  Internal calls: ``ctx_repo_path_root()``, ``bh.run_output()``,\n      ``bh.run()``\n\n-  **``git_origin_url(path='')``** - Return url to remote origin (from\n   .git/config file)\n\n   -  ``path``: Path to git repo, if not using current working directory\n   -  Returns: String URL or empty string\n   -  Internal calls: ``git_repo_path_root()``, ``bh.run_output()``\n\n-  **``git_current_branch(path='', debug=False, timeout=None, exception=False, show=False)``**\n   - Return current branch name\n\n   -  ``path``: Path to git repo, if not using current working directory\n   -  ``debug``: Insert breakpoint before subprocess calls if True\n   -  ``timeout``: Seconds to wait before stopping commands\n   -  ``exception``: Raise exception if git command has error if True\n   -  ``show``: Display git commands before executing if True\n   -  Returns: String branch name\n   -  Internal calls: ``ctx_repo_path_root()``, ``bh.run_output()``\n\n-  **``git_current_tracking_branch(path='', debug=False, timeout=None, exception=False, show=False)``**\n   - Return remote tracking branch for current branch\n\n   -  ``path``: Path to git repo, if not using current working directory\n   -  ``debug``: Insert breakpoint before subprocess calls if True\n   -  ``timeout``: Seconds to wait before stopping commands\n   -  ``exception``: Raise exception if git command has error if True\n   -  ``show``: Display git commands before executing if True\n   -  Returns: String tracking branch name or empty string\n   -  Internal calls: ``ctx_repo_path_root()``, ``bh.run_output()``,\n      ``git_current_branch()``, ``bh.tools.grep_output()``\n\n-  **``git_last_tag(path='', debug=False, timeout=None, exception=False, show=False)``**\n   - Return the most recent tag made\n\n   -  ``path``: Path to git repo, if not using current working directory\n   -  ``debug``: Insert breakpoint before subprocess calls if True\n   -  ``timeout``: Seconds to wait before stopping commands\n   -  ``exception``: Raise exception if git command has error if True\n   -  ``show``: Display git commands before executing if True\n   -  Returns: String tag name or empty string\n   -  Internal calls: ``ctx_repo_path_root()``, ``bh.run_output()``\n\n-  **``git_tag_message(path='', debug=False, tag='', timeout=None, exception=False, show=False)``**\n   - Return the message for specified tag\n\n   -  ``path``: Path to git repo, if not using current working directory\n   -  ``tag``: Name of a tag that was made\n   -  ``debug``: Insert breakpoint before subprocess calls if True\n   -  ``timeout``: Seconds to wait before stopping commands\n   -  ``exception``: Raise exception if git command has error if True\n   -  ``show``: Display git commands before executing if True\n   -  Returns: String tag message\n   -  Internal calls: ``ctx_repo_path_root()``, ``git_last_tag()``,\n      ``bh.run_output()``\n\n-  **``git_last_tag_message(path='', debug=False, timeout=None, exception=False, show=False)``**\n   - Return the message for the most recent tag made\n\n   -  ``path``: Path to git repo, if not using current working directory\n   -  ``debug``: Insert breakpoint before subprocess calls if True\n   -  ``timeout``: Seconds to wait before stopping commands\n   -  ``exception``: Raise exception if git command has error if True\n   -  ``show``: Display git commands before executing if True\n   -  Returns: String tag message\n   -  Internal calls: ``ctx_repo_path_root()``, ``git_last_tag()``,\n      ``git_tag_message()``\n\n-  **``git_tags(path='', debug=False, timeout=None, exception=False, show=False)``**\n   - Return a list of all tags with most recent first\n\n   -  ``path``: Path to git repo, if not using current working directory\n   -  ``debug``: Insert breakpoint before subprocess calls if True\n   -  ``timeout``: Seconds to wait before stopping commands\n   -  ``exception``: Raise exception if git command has error if True\n   -  ``show``: Display git commands before executing if True\n   -  Returns: List of tag names\n   -  Internal calls: ``ctx_repo_path_root()``, ``bh.run_output()``\n\n-  **``git_first_commit_id(path='', debug=False, timeout=None, exception=False, show=False)``**\n   - Get the first commit id for the repo\n\n   -  ``path``: Path to git repo, if not using current working directory\n   -  ``debug``: Insert breakpoint before subprocess calls if True\n   -  ``timeout``: Seconds to wait before stopping commands\n   -  ``exception``: Raise exception if git command has error if True\n   -  ``show``: Display git commands before executing if True\n   -  Returns: String commit ID or empty string\n   -  Internal calls: ``ctx_repo_path_root()``, ``bh.run_output()``\n\n-  **``git_last_commit_id(path='', debug=False, timeout=None, exception=False, show=False)``**\n   - Get the last commit id for the repo\n\n   -  ``path``: Path to git repo, if not using current working directory\n   -  ``debug``: Insert breakpoint before subprocess calls if True\n   -  ``timeout``: Seconds to wait before stopping commands\n   -  ``exception``: Raise exception if git command has error if True\n   -  ``show``: Display git commands before executing if True\n   -  Returns: String commit ID or empty string\n   -  Internal calls: ``ctx_repo_path_root()``, ``bh.run_output()``\n\n-  **``git_commits_since_last_tag(path='', until='', debug=False, timeout=None, exception=False, show=False)``**\n   - Return a list of commits made since last_tag\n\n   -  ``path``: Path to git repo, if not using current working directory\n   -  ``until``: A recent commit id to stop at (instead of last commit)\n   -  ``debug``: Insert breakpoint before subprocess calls if True\n   -  ``timeout``: Seconds to wait before stopping commands\n   -  ``exception``: Raise exception if git command has error if True\n   -  ``show``: Display git commands before executing if True\n   -  Returns: List of commit strings (if no tag, returns commits since\n      first commit)\n   -  Internal calls: ``ctx_repo_path_root()``, ``git_last_tag()``,\n      ``git_first_commit_id()``, ``git_last_commit_id()``,\n      ``bh.run_output()``, ``ih.splitlines()``\n\n-  **``git_unpushed_commits(path='', debug=False, timeout=None, exception=False, show=False)``**\n   - Return a list of any local commits that have not been pushed\n\n   -  ``path``: Path to git repo, if not using current working directory\n   -  ``debug``: Insert breakpoint before subprocess calls if True\n   -  ``timeout``: Seconds to wait before stopping commands\n   -  ``exception``: Raise exception if git command has error if True\n   -  ``show``: Display git commands before executing if True\n   -  Returns: List of unpushed commit strings\n   -  Internal calls: ``ctx_repo_path_root()``, ``bh.run_output()``,\n      ``ih.splitlines()``\n\n-  **``git_untracked_files(path='', debug=False, timeout=None, exception=False, show=False)``**\n   - Return a list of any local files that are not tracked in the git\n   repo\n\n   -  ``path``: Path to git repo, if not using current working directory\n   -  ``debug``: Insert breakpoint before subprocess calls if True\n   -  ``timeout``: Seconds to wait before stopping commands\n   -  ``exception``: Raise exception if git command has error if True\n   -  ``show``: Display git commands before executing if True\n   -  Returns: List of untracked file paths\n   -  Internal calls: ``ctx_repo_path_root()``, ``bh.run_output()``,\n      ``ih.splitlines()``\n\n-  **``git_stashlist(path='', debug=False, timeout=None, exception=False, show=False)``**\n   - Return a list of any local stashes\n\n   -  ``path``: Path to git repo, if not using current working directory\n   -  ``debug``: Insert breakpoint before subprocess calls if True\n   -  ``timeout``: Seconds to wait before stopping commands\n   -  ``exception``: Raise exception if git command has error if True\n   -  ``show``: Display git commands before executing if True\n   -  Returns: List of stash entries\n   -  Internal calls: ``ctx_repo_path_root()``, ``bh.run_output()``,\n      ``ih.splitlines()``\n\n-  **``git_status(path='', debug=False, timeout=None, exception=False, show=False)``**\n   - Return a list of any modified or untracked files\n\n   -  ``path``: Path to git repo, if not using current working directory\n   -  ``debug``: Insert breakpoint before subprocess calls if True\n   -  ``timeout``: Seconds to wait before stopping commands\n   -  ``exception``: Raise exception if git command has error if True\n   -  ``show``: Display git commands before executing if True\n   -  Returns: List of status entries\n   -  Internal calls: ``ctx_repo_path_root()``, ``bh.run_output()``,\n      ``ih.splitlines_and_strip()``\n\n-  **``git_info_dict(path='', fetch=False, debug=False, timeout=None, exception=False, show=False)``**\n   - Return a dict of info about the repo\n\n   -  ``path``: Path to git repo, if not using current working directory\n   -  ``fetch``: Call git_fetch func before calling the generated\n      ``git`` command if True\n   -  ``debug``: Insert breakpoint before subprocess calls if True\n   -  ``timeout``: Seconds to wait before stopping commands\n   -  ``exception``: Raise exception if git command has error if True\n   -  ``show``: Display git commands before executing if True\n   -  Returns: Dictionary with keys: ``path_root``, ``url``, ``branch``,\n      ``branch_date``, ``branch_tracking``, ``branch_tracking_date``,\n      ``last_tag``, ``status``, ``stashes``, ``unpushed``,\n      ``commits_since_last_tag``\n   -  Internal calls: ``ctx_repo_path_root()``,\n      ``git_repo_path_root()``, ``git_origin_url()``,\n      ``git_current_branch()``, ``git_branch_date()``,\n      ``git_current_tracking_branch()``, ``git_last_tag()``,\n      ``git_status()``, ``git_stashlist()``, ``git_unpushed_commits()``,\n      ``git_commits_since_last_tag()``\n\n-  **``git_info_string(path='', fetch=False, debug=False, timeout=None, exception=False, show=False)``**\n   - Build up a string of info from git_info_dict and return it\n\n   -  ``path``: Path to git repo, if not using current working directory\n   -  ``fetch``: Call git_fetch func before calling the generated\n      ``git`` command if True\n   -  ``debug``: Insert breakpoint before subprocess calls if True\n   -  ``timeout``: Seconds to wait before stopping commands\n   -  ``exception``: Raise exception if git command has error if True\n   -  ``show``: Display git commands before executing if True\n   -  Returns: Formatted string with git repository information\n   -  Internal calls: ``ctx_repo_path_root()``, ``git_info_dict()``\n\n-  **``git_branch_date(path='', branch='', fetch=False, debug=False, timeout=None, exception=False, show=False)``**\n   - Return datetime string (and relative age) of branch\n\n   -  ``path``: Path to git repo, if not using current working directory\n   -  ``branch``: Name of branch (prefix with \u2018origin/\u2019 for remote\n      branch)\n   -  ``fetch``: Call git_fetch func before calling the generated\n      ``git`` command if True\n   -  ``debug``: Insert breakpoint before subprocess calls if True\n   -  ``timeout``: Seconds to wait before stopping commands\n   -  ``exception``: Raise exception if git command has error if True\n   -  ``show``: Display git commands before executing if True\n   -  Returns: String with date and relative time\n   -  Internal calls: ``ctx_repo_path_root()``, ``bh.run_output()``\n\n-  **``git_remote_branches(path='', fetch=False, grep='', include_times=False, debug=False, timeout=None, exception=False, show=False)``**\n   - Return list of remote branch names or list of dicts (via\n   ``git ls-remote --heads``)\n\n   -  ``path``: Path to git repo, if not using current working directory\n   -  ``fetch``: Call git_fetch func before calling the generated\n      ``git`` command if True\n   -  ``grep``: ``grep -iE`` pattern to filter branches by\n      (case-insensitive)\n   -  ``include_times``: Include info from git_branch_date in results if\n      True\n   -  ``debug``: Insert breakpoint before subprocess calls if True\n   -  ``timeout``: Seconds to wait before stopping commands\n   -  ``exception``: Raise exception if git command has error if True\n   -  ``show``: Display git commands before executing if True\n   -  Returns: List of branch names or list of dicts (alphabetized if\n      include_times=False, otherwise ordered by most recent commit)\n   -  Internal calls: ``ctx_repo_path_root()``, ``bh.run_output()``,\n      ``bh.tools.grep_output()``, ``_dates_for_branches()``\n\n-  **``git_local_branches(path='', fetch=False, grep='', include_times=False, debug=False, timeout=None, exception=False, show=False)``**\n   - Return list of local branch names or list of dicts (via\n   ``git branch``)\n\n   -  ``path``: Path to git repo, if not using current working directory\n   -  ``fetch``: Call git_fetch func before calling the generated\n      ``git`` command if True\n   -  ``grep``: ``grep -iE`` pattern to filter branches by\n      (case-insensitive)\n   -  ``include_times``: Include info from git_branch_date in results if\n      True\n   -  ``debug``: Insert breakpoint before subprocess calls if True\n   -  ``timeout``: Seconds to wait before stopping commands\n   -  ``exception``: Raise exception if git command has error if True\n   -  ``show``: Display git commands before executing if True\n   -  Returns: List of branch names or list of dicts (alphabetized if\n      include_times=False, otherwise ordered by most recent commit)\n   -  Internal calls: ``ctx_repo_path_root()``, ``bh.run_output()``,\n      ``bh.tools.grep_output()``, ``_dates_for_branches()``\n\n-  **``git_remote_branches_merged_with(path='', branch='develop', fetch=False, include_times=False, debug=False, timeout=None, exception=False, show=False)``**\n   - Return a list of branches on origin that have been merged with\n   branch\n\n   -  ``path``: Path to git repo, if not using current working directory\n   -  ``branch``: Remote branch name (without leading \u2018origin/\u2019)\n   -  ``fetch``: Call git_fetch func before calling the generated\n      ``git`` command if True\n   -  ``include_times``: Include info from git_branch_date in results if\n      True\n   -  ``debug``: Insert breakpoint before subprocess calls if True\n   -  ``timeout``: Seconds to wait before stopping commands\n   -  ``exception``: Raise exception if git command has error if True\n   -  ``show``: Display git commands before executing if True\n   -  Returns: List of merged branch names or list of dicts\n   -  Internal calls: ``ctx_repo_path_root()``, ``bh.run_output()``,\n      ``bh.tools.grep_output()``, ``_dates_for_branches()``\n\n-  **``git_local_branches_merged_with(path='', branch='develop', fetch=False, include_times=False, debug=False, timeout=None, exception=False, show=False)``**\n   - Return a list of local branches that have been merged with branch\n\n   -  ``path``: Path to git repo, if not using current working directory\n   -  ``branch``: Local branch name\n   -  ``fetch``: Call git_fetch func before calling the generated\n      ``git`` command if True\n   -  ``include_times``: Include info from git_branch_date in results if\n      True\n   -  ``debug``: Insert breakpoint before subprocess calls if True\n   -  ``timeout``: Seconds to wait before stopping commands\n   -  ``exception``: Raise exception if git command has error if True\n   -  ``show``: Display git commands before executing if True\n   -  Returns: List of merged branch names or list of dicts\n   -  Internal calls: ``ctx_repo_path_root()``, ``bh.run_output()``,\n      ``bh.tools.grep_output()``, ``_dates_for_branches()``\n\nDocker Operations (``bh.tools.*``)\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nDocker functions provide container lifecycle management with\nservice-specific shortcuts and platform adaptation.\n\n-  **``docker_ok(exception=False)``** - Check if Docker daemon is\n   available and running\n\n   -  ``exception``: Raise exception if Docker unavailable and True\n   -  Returns: Boolean indicating Docker availability\n   -  Internal calls: ``bh.run_output()``\n\n-  **``docker_stop(name, kill=False, signal='KILL', rm=False, exception=False, show=False)``**\n   - Return True if successfully stopped\n\n   -  ``name``: Name of the container\n   -  ``kill``: Kill the container instead of stopping if True\n   -  ``signal``: Signal to send to the container if kill is True\n   -  ``rm``: Remove the container after stop/kill if True\n   -  ``exception``: Raise exception if docker has error response and\n      True\n   -  ``show``: Show the docker commands and output if True\n   -  Returns: Boolean success status\n   -  Internal calls: ``docker_ok()``, ``bh.run_output()``\n\n-  **``docker_start_or_run(name, image='', command='', detach=True, rm=False, interactive=False, ports='', volumes='', platform='', env_vars={}, exception=False, show=False, force=False)``**\n   - Start existing container or create/run container\n\n   -  ``name``: Name for the container\n   -  ``image``: Image to use (i.e.\u00a0image:tag)\n   -  ``command``: Command to run in the container\n   -  ``detach``: Run container in the background if True (set to False\n      if interactive is True)\n   -  ``rm``: Automatically delete the container when it exits if True\n   -  ``interactive``: Keep STDIN open and allocate pseudo-TTY if True\n   -  ``ports``: String containing {host-port}:{container-port} pairs\n      separated by , ; \\|\n   -  ``volumes``: String containing {host-path}:{container-path} pairs\n      separated by , ; \\|\n   -  ``platform``: Platform to set if server is multi-platform capable\n   -  ``env_vars``: Dict of environment variables and values to set\n   -  ``exception``: Raise exception if docker has error response and\n      True\n   -  ``show``: Show the docker commands and output if True\n   -  ``force``: Stop the container and remove it before re-creating if\n      True\n   -  Returns: Boolean success status\n   -  Internal calls: ``docker_ok()``, ``docker_stop()``,\n      ``ih.string_to_list()``, ``bh.run()``, ``bh.run_output()``\n\n-  **``docker_container_id(name)``** - Return the container ID for\n   running container name\n\n   -  ``name``: Name of the container\n   -  Returns: String container ID or empty string\n   -  Internal calls: ``docker_ok()``, ``bh.run_output()``\n\n-  **``docker_container_inspect(name, exception=False, show=False)``** -\n   Return detailed information on specified container as a list\n\n   -  ``name``: Name of the container\n   -  ``exception``: Raise exception if docker has error response and\n      True\n   -  ``show``: Show the docker command and output if True\n   -  Returns: List of container information dictionaries\n   -  Internal calls: ``docker_ok()``, ``bh.run_output()``\n\n-  **``docker_container_config(name, exception=False, show=False)``** -\n   Return dict of config information for specified container (from\n   inspect)\n\n   -  ``name``: Name of the container\n   -  ``exception``: Raise exception if docker has error response and\n      True\n   -  ``show``: Show the docker command and output if True\n   -  Returns: Dictionary of container configuration\n   -  Internal calls: ``docker_container_inspect()``\n\n-  **``docker_container_env_vars(name, exception=False, show=False)``**\n   - Return dict of environment vars for specified container\n\n   -  ``name``: Name of the container\n   -  ``exception``: Raise exception if docker has error response and\n      True\n   -  ``show``: Show the docker command and output if True\n   -  Returns: Dictionary of environment variables\n   -  Internal calls: ``docker_container_config()``\n\n-  **``docker_logs(name, num_lines=None, follow=False, details=False, since='', until='', timestamps=False, show=False)``**\n   - Show logs on an existing container\n\n   -  ``name``: Name of the container\n   -  ``num_lines``: Number of lines to show from the end of the logs\n   -  ``follow``: Follow log output if True\n   -  ``details``: Show extra details provided to logs if True\n   -  ``since``: Show logs since timestamp (iso format or relative)\n   -  ``until``: Show logs before timestamp (iso format or relative)\n   -  ``timestamps``: Show timestamps if True\n   -  ``show``: Show the docker command and output if True\n   -  Returns: Exit code or log output\n   -  Internal calls: ``docker_ok()``, ``bh.run()``, ``bh.run_output()``\n\n-  **``docker_exec(name, command='pwd', output=False, env_vars={}, show=False)``**\n   - Run shell command on an existing container (will be started if\n   stopped)\n\n   -  ``name``: Name of the container\n   -  ``command``: Command to execute\n   -  ``output``: Return output or error from command if True; otherwise\n      return exit status\n   -  ``env_vars``: Dict of environment variables and values to set\n   -  ``show``: Show the docker command and output if True\n   -  Returns: Command output or exit status\n   -  Internal calls: ``docker_ok()``, ``docker_start_or_run()``,\n      ``bh.run_output()``, ``bh.run()``\n\n-  **``docker_exec_wait(name, command='pwd', sleeptime=2, env_vars={}, show=False)``**\n   - Wait for a shell command to succeed in an existing container (will\n   be started if stopped)\n\n   -  ``name``: Name of the container\n   -  ``command``: Command to execute\n   -  ``sleeptime``: Time to sleep between checks\n   -  ``env_vars``: Dict of environment variables and values to set\n   -  ``show``: Show the docker command and output if True\n   -  Returns: None (blocks until command succeeds)\n   -  Internal calls: ``docker_exec()``\n\n-  **``docker_shell(name, shell='sh', env_vars={}, show=False)``** -\n   Start shell on an existing container (will be started if stopped)\n\n   -  ``name``: Name of the container\n   -  ``shell``: Name of shell to execute\n   -  ``env_vars``: Dict of environment variables and values to set\n   -  ``show``: Show the docker command and output if True\n   -  Returns: Exit code\n   -  Internal calls: ``docker_ok()``, ``docker_start_or_run()``,\n      ``bh.run()``\n\n-  **``docker_cleanup_volumes(exception=False, show=False)``** - Use\n   this when creating a container fails with \u2018No space left on device\u2019\n\n   -  ``exception``: Raise exception if docker has error response and\n      True\n   -  ``show``: Show the docker command and output if True\n   -  Returns: Boolean success status\n   -  Internal calls: ``docker_start_or_run()``\n\nDatabase Service Functions\n^^^^^^^^^^^^^^^^^^^^^^^^^^\n\n-  **``docker_redis_start(name, version='6-alpine', port=6300, data_dir=None, aof=True, interactive=False, rm=False, exception=False, show=False, force=False)``**\n   - Start or create redis container\n\n   -  ``name``: Name for the container\n   -  ``version``: Redis image version\n   -  ``port``: Port to map into the container\n   -  ``data_dir``: Directory that will map to container\u2019s /data\n      (absolute path or subdirectory of current directory)\n   -  ``aof``: Use appendonly.aof file if True\n   -  ``interactive``: Keep STDIN open and allocate pseudo-TTY if True\n   -  ``rm``: Automatically delete the container when it exits if True\n   -  ``exception``: Raise exception if docker has error response and\n      True\n   -  ``show``: Show the docker commands and output if True\n   -  ``force``: Stop the container and remove it before re-creating if\n      True\n   -  Returns: Boolean success status\n   -  Internal calls: ``docker_start_or_run()``\n\n-  **``docker_redis_cli(name, show=False)``** - Start redis-cli on an\n   existing container (will be started if stopped)\n\n   -  ``name``: Name for the container\n   -  ``show``: Show the docker command and output if True\n   -  Returns: Exit code\n   -  Internal calls: ``docker_shell()``\n\n-  **``docker_mongo_start(name, version='4.4', port=27000, username='mongouser', password='some.pass', data_dir=None, interactive=False, rm=False, exception=False, show=False, force=False, wait=False, sleeptime=2)``**\n   - Start or create mongo container\n\n   -  ``name``: Name for the container\n   -  ``version``: Mongo image version\n   -  ``port``: Port to map into the container\n   -  ``username``: Username to set for root user on first run\n   -  ``password``: Password to set for root user on first run\n   -  ``data_dir``: Directory that will map to container\u2019s /data/db\n      (absolute path or subdirectory of current directory)\n   -  ``interactive``: Keep STDIN open and allocate pseudo-TTY if True\n   -  ``rm``: Automatically delete the container when it exits if True\n   -  ``exception``: Raise exception if docker has error response and\n      True\n   -  ``show``: Show the docker commands and output if True\n   -  ``force``: Stop the container and remove it before re-creating if\n      True\n   -  ``wait``: Don\u2019t return until mongo is able to accept connections\n      if True\n   -  ``sleeptime``: If wait is True, sleep this number of seconds\n      before checks\n   -  Returns: Boolean success status\n   -  Internal calls: ``docker_start_or_run()``\n\n-  **``docker_mongo_cli(name, show=False)``** - Start mongo on an\n   existing container (will be started if stopped)\n\n   -  ``name``: Name for the container\n   -  ``show``: Show the docker command and output if True\n   -  Returns: Exit code\n   -  Internal calls: ``docker_container_env_vars()``,\n      ``docker_shell()``\n\n-  **``docker_mongo_wait(name, sleeptime=2, show=False)``** - Wait for\n   mongo on an existing container (will be started if stopped)\n\n   -  ``name``: Name of the container\n   -  ``sleeptime``: Time to sleep between checks\n   -  ``show``: Show the docker command and output if True\n   -  Returns: None (blocks until postgres is ready)\n   -  Internal calls: ``docker_container_env_vars()``,\n      ``docker_exec_wait()``\n\n-  **``docker_postgres_start(name, version='13-alpine', port=5400, username='postgresuser', password='some.pass', db='postgresdb', data_dir=None, interactive=False, rm=False, exception=False, show=False, force=False, wait=False, sleeptime=2)``**\n   - Start or create postgres container\n\n   -  ``name``: Name for the container\n   -  ``version``: Postgres image version\n   -  ``port``: Port to map into the container\n   -  ``username``: Username to set as superuser on first run\n   -  ``password``: Password to set for superuser on first run\n   -  ``db``: Name of default database\n   -  ``data_dir``: Directory that will map to container\u2019s\n      /var/lib/postgresql/data (absolute path or subdirectory of current\n      directory)\n   -  ``interactive``: Keep STDIN open and allocate pseudo-TTY if True\n   -  ``rm``: Automatically delete the container when it exits if True\n   -  ``exception``: Raise exception if docker has error response and\n      True\n   -  ``show``: Show the docker commands and output if True\n   -  ``force``: Stop the container and remove it before re-creating if\n      True\n   -  ``wait``: Don\u2019t return until postgres is able to accept\n      connections if True\n   -  ``sleeptime``: If wait is True, sleep this number of seconds\n      before checks\n   -  Returns: Boolean success status\n   -  Internal calls: ``docker_start_or_run()``,\n      ``docker_postgres_wait()``\n\n-  **``docker_postgres_cli(name, show=False)``** - Start psql on an\n   existing container (will be started if stopped)\n\n   -  ``name``: Name for the container\n   -  ``show``: Show the docker command and output if True\n   -  Returns: Exit code\n   -  Internal calls: ``docker_container_env_vars()``,\n      ``docker_shell()``\n\n-  **``docker_postgres_wait(name, sleeptime=2, show=False)``** - Wait\n   for psql on an existing container (will be started if stopped)\n\n   -  ``name``: Name of the container\n   -  ``sleeptime``: Time to sleep between checks\n   -  ``show``: Show the docker command and output if True\n   -  Returns: None (blocks until postgres is ready)\n   -  Internal calls: ``docker_container_env_vars()``,\n      ``docker_exec_wait()``\n\n-  **``docker_mysql_start(name, version='8.0', port=3300, root_password='root.pass', username='mysqluser', password='some.pass', db='mysqldb', data_dir=None, interactive=False, rm=False, exception=False, show=False, force=False, wait=False, sleeptime=2)``**\n   - Start or create mysql container\n\n   -  ``name``: Name for the container\n   -  ``version``: MySQL image version (or mysql/mysql-server for Mac\n      M1)\n   -  ``port``: Port to map into the container\n   -  ``root_password``: Password to set for the root superuser account\n   -  ``username``: Username to set as superuser on first run\n   -  ``password``: Password to set for superuser on first run\n   -  ``db``: Name of default database\n   -  ``data_dir``: Directory that will map to container\u2019s\n      /var/lib/mysql (absolute path or subdirectory of current\n      directory)\n   -  ``interactive``: Keep STDIN open and allocate pseudo-TTY if True\n   -  ``rm``: Automatically delete the container when it exits if True\n   -  ``exception``: Raise exception if docker has error response and\n      True\n   -  ``show``: Show the docker commands and output if True\n   -  ``force``: Stop the container and remove it before re-creating if\n      True\n   -  ``wait``: Don\u2019t return until mysql is able to accept connections\n      if True\n   -  ``sleeptime``: If wait is True, sleep this number of seconds\n      before checks\n   -  Returns: Boolean success status\n   -  Internal calls: ``bh.run_output()``, ``docker_start_or_run()``,\n      ``docker_mysql_wait()``\n\n-  **``docker_mysql_cli(name, show=False)``** - Start mysql on an\n   existing container (will be started if stopped)\n\n   -  ``name``: Name of the container\n   -  ``show``: Show the docker command and output if True\n   -  Returns: Exit code\n   -  Internal calls: ``docker_container_env_vars()``,\n      ``docker_shell()``\n\n-  **``docker_mysql_wait(name, sleeptime=2, show=False)``** - Wait for\n   mysql on an existing container (will be started if stopped)\n\n   -  ``name``: Name of the container\n   -  ``sleeptime``: Time to sleep between checks\n   -  ``show``: Show the docker command and output if True\n   -  Returns: None (blocks until mysql is ready)\n   -  Internal calls: ``docker_container_env_vars()``,\n      ``docker_exec_wait()``\n\nOS Container Functions\n^^^^^^^^^^^^^^^^^^^^^^\n\n-  **``docker_alpine_start(name, version='3.12', command='sleep 86400', detach=True, interactive=False, rm=False, exception=False, show=False, force=False)``**\n   - Start or create alpine container\n\n   -  ``name``: Name for the container\n   -  ``version``: Alpine image version\n   -  ``command``: Command to run (default is sleep for a day)\n   -  ``detach``: Run container in the background if True (set to False\n      if interactive is True)\n   -  ``interactive``: Keep STDIN open and allocate pseudo-TTY if True\n   -  ``rm``: Automatically delete the container when it exits if True\n   -  ``exception``: Raise exception if docker has error response and\n      True\n   -  ``show``: Show the docker commands and output if True\n   -  ``force``: Stop the container and remove it before re-creating if\n      True\n   -  Returns: Boolean success status\n   -  Internal calls: ``docker_start_or_run()``\n\n-  **``docker_ubuntu_start(name, version='18.04', command='sleep 86400', detach=True, interactive=False, rm=False, exception=False, show=False, force=False)``**\n   - Start or create ubuntu container\n\n   -  ``name``: Name for the container\n   -  ``version``: Ubuntu image version\n   -  ``command``: Command to run (default is sleep for a day)\n   -  ``detach``: Run container in the background if True (set to False\n      if interactive is True)\n   -  ``interactive``: Keep STDIN open and allocate pseudo-TTY if True\n   -  ``rm``: Automatically delete the container when it exits if True\n   -  ``exception``: Raise exception if docker has error response and\n      True\n   -  ``show``: Show the docker commands and output if True\n   -  ``force``: Stop the container and remove it before re-creating if\n      True\n   -  Returns: Boolean success status\n   -  Internal calls: ``docker_start_or_run()``\n\n-  **``docker_fedora_start(name, version='33', command='sleep 86400', detach=True, interactive=False, rm=False, exception=False, show=False, force=False)``**\n   - Start or create fedora container\n\n   -  ``name``: Name for the container\n   -  ``version``: Fedora image version\n   -  ``command``: Command to run (default is sleep for a day)\n   -  ``detach``: Run container in the background if True (set to False\n      if interactive is True)\n   -  ``interactive``: Keep STDIN open and allocate pseudo-TTY if True\n   -  ``rm``: Automatically delete the container when it exits if True\n   -  ``exception``: Raise exception if docker has error response and\n      True\n   -  ``show``: Show the docker commands and output if True\n   -  ``force``: Stop the container and remove it before re-creating if\n      True\n   -  Returns: Boolean success status\n   -  Internal calls: ``docker_start_or_run()``\n\nSSH Operations (``bh.tools.*``)\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nSSH functions provide remote system access with connection management\nand key discovery.\n\n-  **``ssh_to_server(ip_or_hostname, user=None, pem_file=None, private_key_file=None, command='', timeout=None, verbose=False)``**\n   - Actually SSH to a server and run a command or start interactive\n   session\n\n   -  ``ip_or_hostname``: IP address or hostname of server\n   -  ``user``: Remote SSH user\n   -  ``pem_file``: Absolute path to pem file\n   -  ``private_key_file``: Absolute path to private key file\n   -  ``command``: Optional command to run on the remote server (if\n      specified, output is returned; if not, session is interactive)\n   -  ``timeout``: Number of seconds to wait for a specified command to\n      run on the remote server\n   -  ``verbose``: Print the generated SSH command and result if True\n   -  Returns: Command output if command specified, otherwise exit code\n   -  Internal calls: ``ssh_configured_hosts()``, ``bh.run_output()``,\n      ``bh.run()``\n\n-  **``ssh_pem_files()``** - Find all .pem files in ~/.ssh and return a\n   dict with absolute paths\n\n   -  Returns: Dictionary mapping filename (without extension) to\n      absolute path\n   -  Internal calls: ``fh.strip_extension()``\n\n-  **``ssh_private_key_files()``** - Find all private key files in\n   ~/.ssh and return a dict with absolute paths\n\n   -  Returns: Dictionary mapping filename (without extension) to\n      absolute path\n   -  Internal calls: ``fh.strip_extension()``\n\n-  **``ssh_configured_hosts()``** - Return a set of Hosts from the\n   ~/.ssh/config file\n\n   -  Returns: Set of configured host names\n   -  Internal calls: ``fh.abspath()``\n\n-  **``ssh_determine_aws_user_for_server(ip_or_hostname, pem_file, verbose=False)``**\n   - Determine which AWS default user is setup for server\n\n   -  ``ip_or_hostname``: IP address or hostname of server\n   -  ``pem_file``: Absolute path to pem file\n   -  ``verbose``: Show info for each attempt if True\n   -  Returns: String username if found, otherwise None\n   -  Internal calls: ``ssh_to_server()``\n\nGrep Operations (``bh.tools.*``)\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nEnhanced text search with pattern matching capabilities.\n\n-  **``grep_output(output, pattern=None, regex=None, ignore_case=True, invert=False, lines_before_match=None, lines_after_match=None, results_as_string=False, join_result_string_on='\\n', strip_whitespace=False, no_filename=False, line_number=False, only_matching=False, byte_offset=False, suppress_errors=True, extra_pipe=None, show=False)``**\n   - Use grep to match lines of output against pattern\n\n   -  ``output``: Some output you would be piping to grep in a shell\n      environment\n   -  ``pattern``: Grep pattern string (extended ``-E`` style allowed)\n   -  ``regex``: Compiled regular expression (from re.compile) or string\n      that can be passed to re.compile\n   -  ``ignore_case``: Ignore case (``grep -i`` or re.IGNORECASE) if\n      True\n   -  ``invert``: Select non-matching items (``grep -v``) if True (only\n      applied when using pattern, not regex)\n   -  ``lines_before_match``: Number of context lines to show before\n      match (only applied when using pattern, not regex)\n   -  ``lines_after_match``: Number of context lines to show after match\n      (only applied when using pattern, not regex)\n   -  ``results_as_string``: Return a string instead of a list of\n      strings if True\n   -  ``join_result_string_on``: Character or string to join a list of\n      strings on\n   -  ``strip_whitespace``: Strip trailing and leading whitespace for\n      results if True\n   -  ``no_filename``: Do not prefix matching lines with their\n      corresponding file names if True (only applied when using pattern,\n      not regex)\n   -  ``line_number``: Prefix matching lines with line number within its\n      input file if True (only applied when using pattern, not regex)\n   -  ``only_matching``: Print only the matched parts of a matching line\n      if True (only applied when using pattern, not regex)\n   -  ``byte_offset``: Print the byte offset within the input file\n      before each line of output if True (only applied when using\n      pattern, not regex)\n   -  ``suppress_errors``: Suppress error messages about nonexistent or\n      unreadable files if True (only applied when using pattern, not\n      regex)\n   -  ``extra_pipe``: String containing other command(s) to pipe grepped\n      output to (only applied when using pattern, not regex)\n   -  ``show``: Show the ``grep`` command before executing if True (only\n      applied when using pattern, not regex)\n   -  Returns: List of strings (split on newline) or string if\n      results_as_string=True\n   -  Internal calls: ``_prep_common_grep_args()``, ``bh.run_output()``,\n      ``ih.splitlines()``, ``ih.splitlines_and_strip()``\n\n-  **``grep_path(pattern, path='', recursive=True, ignore_case=True, invert=False, lines_before_match=None, lines_after_match=None, exclude_files=None, exclude_dirs=None, results_as_string=False, join_result_string_on='\\n', strip_whitespace=False, no_filename=False, line_number=False, only_matching=False, byte_offset=False, suppress_errors=True, extra_pipe=None, color=False, show=False)``**\n   - Use grep to match lines in files at a path against pattern\n\n   -  ``pattern``: Grep pattern string (extended ``-E`` style allowed)\n   -  ``path``: Path to directory where the search should be started, if\n      not using current working directory\n   -  ``recursive``: Use ``-R`` to search all files at path if True\n   -  ``ignore_case``: Ignore case (``grep -i``) if True\n   -  ``invert``: Select non-matching items (``grep -v``) if True\n   -  ``lines_before_match``: Number of context lines to show before\n      match\n   -  ``lines_after_match``: Number of context lines to show after match\n   -  ``exclude_files``: List of file names and patterns to exclude from\n      searching or string separated by , ; \\|\n   -  ``exclude_dirs``: List of dir names and patterns to exclude from\n      searching or string separated by , ; \\|\n   -  ``results_as_string``: Return a string instead of a list of\n      strings if True\n   -  ``join_result_string_on``: Character or string to join a list of\n      strings on\n   -  ``strip_whitespace``: Strip trailing and leading whitespace for\n      results if True\n   -  ``no_filename``: Do not prefix matching lines with their\n      corresponding file names if True\n   -  ``line_number``: Prefix matching lines with line number within its\n      input file if True\n   -  ``only_matching``: Print only the matched parts of a matching line\n      if True\n   -  ``byte_offset``: Print the byte offset within the input file\n      before each line of output if True\n   -  ``suppress_errors``: Suppress error messages about nonexistent or\n      unreadable files if True\n   -  ``extra_pipe``: String containing other command(s) to pipe grepped\n      output to\n   -  ``color``: Will invoke the generated grep command with ``bh.run``\n      (output will not be captured) if True\n   -  ``show``: Show the ``grep`` command before executing if True\n   -  Returns: List of strings or string if results_as_string=True, or\n      exit code if color=True\n   -  Internal calls: ``fh.abspath()``, ``_prep_common_grep_args()``,\n      ``bh.run()``, ``bh.run_output()``, ``ih.splitlines()``,\n      ``ih.splitlines_and_strip()``\n\n-  **``grep_path_count(pattern, path='', recursive=True, ignore_case=True, invert=False, exclude_files=None, exclude_dirs=None, suppress_errors=True, results_as_string=False, join_result_string_on='\\n', show=False)``**\n   - Use grep to count the match lines in files at a path against\n   pattern\n\n   -  ``pattern``: Grep pattern string (extended ``-E`` style allowed)\n   -  ``path``: Path to directory where the search should be started, if\n      not using current working directory\n   -  ``recursive``: Use ``-R`` to search all files at path if True\n   -  ``ignore_case``: Ignore case (``grep -i``) if True\n   -  ``invert``: Select non-matching items (``grep -v``) if True\n   -  ``exclude_files``: List of file names and patterns to exclude from\n      searching or string separated by , ; \\|\n   -  ``exclude_dirs``: List of dir names and patterns to exclude from\n      searching or string separated by , ; \\|\n   -  ``suppress_errors``: Suppress error messages about nonexistent or\n      unreadable files if True\n   -  ``results_as_string``: Return a string instead of a list of tuples\n      if True\n   -  ``join_result_string_on``: Character or string to join a list of\n      strings on\n   -  ``show``: Show the ``grep`` command before executing if True\n   -  Returns: List of 2-item tuples (filename, count) sorted by count\n      descending then filename ascending\n   -  Internal calls: ``fh.abspath()``, ``_prep_common_grep_args()``,\n      ``bh.run_output()``\n\n-  **``grep_path_count_dirs(pattern, path='', recursive=True, ignore_case=True, invert=False, exclude_files=None, exclude_dirs=None, suppress_errors=True, results_as_string=False, join_result_string_on='\\n', show=False)``**\n   - Use grep to count match lines in files against pattern, aggregated\n   by dir\n\n   -  ``pattern``: Grep pattern string (extended ``-E`` style allowed)\n   -  ``path``: Path to directory where the search should be started, if\n      not using current working directory\n   -  ``recursive``: Use ``-R`` to search all files at path if True\n   -  ``ignore_case``: Ignore case (``grep -i``) if True\n   -  ``invert``: Select non-matching items (``grep -v``) if True\n   -  ``exclude_files``: List of file names and patterns to exclude from\n      searching or string separated by , ; \\|\n   -  ``exclude_dirs``: List of dir names and patterns to exclude from\n      searching or string separated by , ; \\|\n   -  ``suppress_errors``: Suppress error messages about nonexistent or\n      unreadable files if True\n   -  ``results_as_string``: Return a string instead of a list of tuples\n      if True\n   -  ``join_result_string_on``: Character or string to join a list of\n      strings on\n   -  ``show``: Show the ``grep`` command before executing if True\n   -  Returns: List of 2-item tuples (dirname, count) sorted by count\n      descending then dirname ascending\n   -  Internal calls: ``fh.abspath()``, ``_prep_common_grep_args()``,\n      ``bh.run_output()``\n\n-  **``grep_select_vim(pattern, path='', recursive=True, ignore_case=True, invert=False, lines_before_match=None, lines_after_match=None, exclude_files=None, exclude_dirs=None, suppress_errors=True, open_all_together=False)``**\n   - Use grep to find files, then present a menu of results and line\n   numbers\n\n   -  ``pattern``: Grep pattern string (extended ``-E`` style allowed)\n   -  ``path``: Path to directory where the search should be started, if\n      not using current working directory\n   -  ``recursive``: Use ``-R`` to search all files at path if True\n   -  ``ignore_case``: Ignore case (``grep -i``) if True\n   -  ``invert``: Select non-matching items (``grep -v``) if True\n   -  ``lines_before_match``: Number of context lines to show before\n      match\n   -  ``lines_after_match``: Number of context lines to show after match\n   -  ``exclude_files``: List of file names and patterns to exclude from\n      searching or string separated by , ; \\|\n   -  ``exclude_dirs``: List of dir names and patterns to exclude from\n      searching or string separated by , ; \\|\n   -  ``suppress_errors``: Suppress error messages about nonexistent or\n      unreadable files if True\n   -  ``open_all_together``: Don\u2019t open each individual file to the line\n      number, just open them all in the same vim session if True\n   -  Returns: None (opens selected files in vim)\n   -  Internal calls: ``fh.abspath()``, ``_prep_common_grep_args()``,\n      ``bh.run_output()``, ``ih.splitlines()``,\n      ``ih.make_selections()``, ``bh.run()``\n\nPip Operations (``bh.tools.*``)\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nPython package management utilities.\n\n-  **``installed_packages(name_only=False)``** - Return a dict or list\n   of installed packages from importlib_metadata.distributions\n\n   -  ``name_only``: Return a list of package names only if True\n   -  Returns: Dictionary mapping package names to versions, or list of\n      package names if name_only=True\n   -  Internal calls: None\n\n-  **``installed_packages_by_dir()``** - Return a dict of installed\n   packages from importlib_metadata.distributions\n\n   -  Returns: Dictionary with \u2018standard\u2019 key (dict of standard packages\n      and versions) and \u2018other\u2019 key (dict of packages installed outside\n      of PATH_TO_SITE_PACKAGES)\n   -  Internal calls: None\n\n-  **``installed_packages_non_site_packages()``** - Return a dict of\n   installed packages from importlib_metadata.distributions\n\n   -  Returns: Dictionary of packages not in PATH_TO_SITE_PACKAGES\n      mapped to their paths\n   -  Internal calls: None\n\n-  **``pip_freeze(pip_path='', venv_only=True, debug=False, timeout=None, exception=True, show=False)``**\n   - Run pip freeze command\n\n   -  ``pip_path``: Absolute path to pip in a virtual environment (use\n      derived PATH_TO_PIP if not specified)\n   -  ``venv_only``: Only run pip if it\u2019s in a venv if True\n   -  ``debug``: Insert breakpoint before subprocess calls if True\n   -  ``timeout``: Seconds to wait before stopping commands\n   -  ``exception``: Raise exception if pip command has error if True\n   -  ``show``: Show the ``pip`` command before executing if True\n   -  Returns: Exit code\n   -  Internal calls: ``bh.run()``\n\n-  **``pip_install_editable(paths, pip_path='', venv_only=True, debug=False, timeout=None, exception=True, show=False)``**\n   - Pip install the given paths in \u201ceditable mode\u201d\n\n   -  ``paths``: Local paths to projects to install in \u201ceditable mode\u201d\n      (list of strings OR string separated by , ; \\|)\n   -  ``pip_path``: Absolute path to pip in a virtual environment (use\n      derived PATH_TO_PIP if not specified)\n   -  ``venv_only``: Only run pip if it\u2019s in a venv if True\n   -  ``debug``: Insert breakpoint before subprocess calls if True\n   -  ``timeout``: Seconds to wait before stopping commands\n   -  ``exception``: Raise exception if pip command has error if True\n   -  ``show``: Show the ``pip`` command before executing if True\n   -  Returns: Exit code\n   -  Internal calls: ``ih.get_list_from_arg_strings()``, ``bh.run()``\n\n-  **``pip_extras(package_name, venv_only=True, exception=True)``** -\n   Return the extras_requires keys for specified package\n\n   -  ``package_name``: Name of the package to get extras_requires keys\n   -  ``venv_only``: Only run pip if it\u2019s in a venv if True\n   -  ``exception``: Raise exception if pip command has error if True\n   -  Returns: List of extras keys or None\n   -  Internal calls: None\n\n-  **``pip_version(pip_path='', venv_only=True, debug=False, exception=True)``**\n   - Return a tuple for the pip version (major int, minor int, patch\n   string)\n\n   -  ``pip_path``: Absolute path to pip in a virtual environment (use\n      derived PATH_TO_PIP if not specified)\n   -  ``venv_only``: Only run pip if it\u2019s in a venv if True\n   -  ``debug``: Insert breakpoint before subprocess calls if True\n   -  ``exception``: Raise exception if pip command has error if True\n   -  Returns: Tuple (major, minor, patch)\n   -  Internal calls: ``bh.run_output()``, ``bh.tools.grep_output()``,\n      ``ih.string_to_version_tuple()``\n\n-  **``pip_package_versions_available(package_name, pip_path='', venv_only=True, debug=False, exception=True)``**\n   - Return a list of versions available on pypi for the given package\n\n   -  ``package_name``: Name of the package on pypi.org\n   -  ``pip_path``: Absolute path to pip in a virtual environment (use\n      derived PATH_TO_PIP if not specified)\n   -  ``venv_only``: Only run pip if it\u2019s in a venv if True\n   -  ``debug``: Insert breakpoint before subprocess calls if True\n   -  ``exception``: Raise exception if pip command has error if True\n   -  Returns: List of available version strings\n   -  Internal calls: ``pip_version()``, ``bh.run_output()``,\n      ``bh.tools.grep_output()``\n\nProcess Operations (``bh.tools.*``)\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nProcess management utilities.\n\n-  **``ps_output()``** - Return a list of dicts containing info about\n   current running processes\n\n   -  Returns: List of dictionaries with process information\n   -  Internal calls: ``bh.run_output()``, ``PsOutputMatcher`` (from\n      input_helper)\n\nPython Environment Operations (``bh.tools.*``)\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nPython environment management through pyenv.\n\n-  **``pyenv_install_python_version(*versions)``** - Use pyenv to\n   install versions of Python\n\n   -  ``versions``: List of versions to install (can also be a list of\n      versions contained in a single string, separated by , ; \\|)\n   -  Returns: List of tuples (version, success_boolean)\n   -  Internal calls: ``ih.get_list_from_arg_strings()``, ``bh.run()``\n\n-  **``pyenv_update(show=True)``** - Update pyenv\n\n   -  ``show``: Show the command before executing if True\n   -  Returns: Boolean success status\n   -  Internal calls: ``bh.run()``, ``bh.tools.git_repo_update()``\n\n-  **``pyenv_get_installable_versions(only_py3=True, only_latest_per_group=True, only_released=True, only_non_released=False)``**\n   - Return a list of Python versions that can be installed to\n   ~/.pyenv/versions\n\n   -  ``only_py3``: Only list standard Python 3.x versions if True\n   -  ``only_latest_per_group``: Only include the latest version per\n      group if True\n   -  ``only_released``: Only include released versions, not\n      alpha/beta/rc/dev/src if True\n   -  ``only_non_released``: Only include non-released versions, like\n      alpha/beta/rc/dev/src if True\n   -  Returns: List of installable Python version strings\n   -  Internal calls: ``bh.run_output()``, ``bh.tools.grep_output()``,\n      ``ih.splitlines_and_strip()``\n\n-  **``pyenv_select_python_versions_to_install(only_py3=True, only_latest_per_group=True, only_released=True, only_non_released=False)``**\n   - Select versions of Python to install with pyenv\n\n   -  ``only_py3``: Only select from standard Python 3.x versions if\n      True\n   -  ``only_latest_per_group``: Only include the latest version per\n      group if True\n   -  ``only_released``: Only include released versions, not\n      alpha/beta/rc/dev/src if True\n   -  ``only_non_released``: Only include non-released versions, like\n      alpha/beta/rc/dev/src if True\n   -  Returns: List of tuples (version, success_boolean) from\n      installation\n   -  Internal calls: ``pyenv_get_installable_versions()``,\n      ``ih.make_selections()``, ``pyenv_install_python_version()``\n\n-  **``pyenv_get_versions()``** - Return a list of Python versions\n   locally installed to ~/.pyenv/versions\n\n   -  Returns: List of installed Python version strings\n   -  Internal calls: None\n\n-  **``pyenv_path_to_python_version(version)``** - Return path to the\n   installed Python binary for the given version or None\n\n   -  ``version``: Python version string\n   -  Returns: String path to Python binary or None\n   -  Internal calls: None\n\n-  **``pyenv_pip_versions(py_versions='')``** - Return a dict of default\n   pip versions for each given Python version\n\n   -  ``py_versions``: String containing locally installed Python\n      versions separated by , ; \\| (if none specified, use all local\n      versions)\n   -  Returns: Dictionary mapping Python versions to pip version tuples\n   -  Internal calls: ``ih.get_list_from_arg_strings()``,\n      ``pyenv_get_versions()``, ``bh.tools.pip_version()``\n\n-  **``pyenv_pip_package_versions_available(package_name, py_versions='', show=False)``**\n   - Return a dict of package versions available on pypi for the given\n   package\n\n   -  ``package_name``: Name of the package on pypi.org\n   -  ``py_versions``: String containing locally installed Python\n      versions separated by , ; \\| (if none specified, use all local\n      versions)\n   -  ``show``: Display the results if True\n   -  Returns: Dictionary mapping Python versions to lists of available\n      package versions\n   -  Internal calls: ``ih.get_list_from_arg_strings()``,\n      ``pyenv_get_versions()``,\n      ``bh.tools.pip_package_versions_available()``\n\n-  **``pyenv_create_venvs_for_py_versions_and_dep_versions(base_dir, py_versions='', pip_version='', pip_latest=False, wheel_version='', wheel_latest=False, clean=False, die=False, local_package_paths='', extra_packages='', dep_versions_dict=None)``**\n   - Create a combination of venvs for the given py_versions and\n   dep_versions\n\n   -  ``base_dir``: Path to directory where the venvs will be created\n   -  ``py_versions``: String containing Python versions to make venvs\n      for separated by , ; \\| (if none specified, use all local\n      versions)\n   -  ``pip_version``: Specific version of pip to install first\n   -  ``pip_latest``: Install latest version of pip if True (ignored if\n      pip_version specified)\n   -  ``wheel_version``: Specific version of wheel to install first\n   -  ``wheel_latest``: Install latest version of wheel if True (ignored\n      if wheel_version specified)\n   -  ``clean``: Delete any existing venv that would be created if it\n      exists if True\n   -  ``die``: Return if any part of venv creation or pip install fails\n      if True\n   -  ``local_package_paths``: Local paths to projects to install in\n      \u201ceditable mode\u201d (may be a list or string separated by , ; \\|)\n   -  ``extra_packages``: String of extra packages to be installed in\n      each venv (may be a list or string separated by , ; \\|)\n   -  ``dep_versions_dict``: Dict where keys are package names and\n      values are specific versions (versions may be a list or string\n      separated by , ; \\|)\n   -  Returns: None (creates virtual environments)\n   -  Internal calls: ``fh.abspath()``,\n      ``ih.get_list_from_arg_strings()``, ``pyenv_get_versions()``,\n      ``pyenv_path_to_python_version()``,\n      ``pyenv_install_python_version()``, ``bh.run()``\n\nBasic Examples\n--------------\n\n::\n\n   % ipython\n   ...\n\n   In [1]: import bg_helper as bh\n\n   In [2]: def lame():\n      ...:     return 1/0\n\n   In [3]: def blah(*args, **kwargs):\n      ...:     return locals()\n\n   In [4]: bh.call_func(blah)\n   Out[4]:\n   {'args': '()',\n    'func_name': 'blah',\n    'kwargs': '{}',\n    'status': 'ok',\n    'value': {'args': (), 'kwargs': {}}}\n\n   In [5]: bh.call_func(blah, 'cats', 'dogs')\n   Out[5]:\n   {'args': \"('cats', 'dogs')\",\n    'func_name': 'blah',\n    'kwargs': '{}',\n    'status': 'ok',\n    'value': {'args': ('cats', 'dogs'), 'kwargs': {}}}\n\n   In [6]: bh.call_func(blah, 'cats', 'dogs', meh=[1, 2, 3, 4, 5])\n   Out[6]:\n   {'args': \"('cats', 'dogs')\",\n    'func_name': 'blah',\n    'kwargs': \"{'meh': [1, 2, 3, 4, 5]}\",\n    'status': 'ok',\n    'value': {'args': ('cats', 'dogs'), 'kwargs': {'meh': [1, 2, 3, 4, 5]}}}\n\n   In [7]: bh.call_func(lame)\n   ======================================================================\n   2017-04-01 12:32:35,107: func=lame args=() kwargs={}\n   Traceback (most recent call last):\n     File \"/tmp/here/venv/lib/python3.5/site-packages/bg_helper/__init__.py\", line 70, in call_func\n       value = func(*args, **kwargs)\n     File \"<ipython-input-2-ac0fa5de647a>\", line 2, in lame\n       return 1/0\n   ZeroDivisionError: division by zero\n\n   Out[7]:\n   {'args': '()',\n    'error_type': \"<class 'ZeroDivisionError'>\",\n    'error_value': \"ZeroDivisionError('division by zero',)\",\n    'fqdn': 'x200-purple',\n    'func_doc': None,\n    'func_module': '__main__',\n    'func_name': 'lame',\n    'kwargs': '{}',\n    'status': 'error',\n    'time_epoch': 1491067955.1004958,\n    'time_string': '2017_0401-Sat-123235',\n    'traceback_string': 'Traceback (most recent call last):\\n  File \"/tmp/here/venv/lib/python3.5/site-packages/bg_helper/__init__.py\", line 70, in call_func\\n    value = func(*args, **kwargs)\\n  File \"<ipython-input-2-ac0fa5de647a>\", line 2, in lame\\n    return 1/0\\nZeroDivisionError: division by zero\\n'}\n\n   In [8]: cat log--bg-helper.log\n   2017-04-01 12:32:35,107 - ERROR - call_func: func=lame args=() kwargs={}\n   Traceback (most recent call last):\n     File \"/tmp/here/venv/lib/python3.5/site-packages/bg_helper/__init__.py\", line 70, in call_func\n       value = func(*args, **kwargs)\n     File \"<ipython-input-2-ac0fa5de647a>\", line 2, in lame\n       return 1/0\n   ZeroDivisionError: division by zero\n\n   In [9]: bh.SimpleBackgroundTask('echo \"hello from console\" > /tmp/blahblah.txt')\n   Out[9]: <bg_helper.SimpleBackgroundTask at 0x7ff112229c18>\n\n   In [10]: ls /tmp/blahblah.txt\n   /tmp/blahblah.txt\n\n   In [11]: cat /tmp/blahblah.txt\n   hello from console\n\n   In [12]: bh.SimpleBackgroundTask('echo \"$(date)\" >> /tmp/blahblah.txt')\n   Out[12]: <bg_helper.SimpleBackgroundTask at 0x7ff110057cf8>\n\n   In [13]: cat /tmp/blahblah.txt\n   hello from console\n   Sat Apr  1 12:33:23 CDT 2017\n\n\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "CLI helpers for background tasks (shell), docker (databases), git, and SSH",
    "version": "0.1.24",
    "project_urls": {
        "Download": "https://github.com/kenjyco/bg-helper/tarball/v0.1.24",
        "Homepage": "https://github.com/kenjyco/bg-helper"
    },
    "split_keywords": [
        "background",
        " shell",
        " git",
        " ssh",
        " docker",
        " pyenv",
        " redis",
        " mongodb",
        " postgres",
        " postgresql",
        " mysql",
        " helper",
        " kenjyco"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "b8b5f42473539e6cab6bcb4ceb570ecfd046a889f97903680d0d74f4c84b9ce5",
                "md5": "dc49a1bf3250fa786f518c0be458ac43",
                "sha256": "ec20c0624425393735a308fbea784676f9ced4ff8ea7827d9612461b6b80afb2"
            },
            "downloads": -1,
            "filename": "bg_helper-0.1.24-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "dc49a1bf3250fa786f518c0be458ac43",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": null,
            "size": 37201,
            "upload_time": "2025-07-23T17:57:17",
            "upload_time_iso_8601": "2025-07-23T17:57:17.884552Z",
            "url": "https://files.pythonhosted.org/packages/b8/b5/f42473539e6cab6bcb4ceb570ecfd046a889f97903680d0d74f4c84b9ce5/bg_helper-0.1.24-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-07-23 17:57:17",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "kenjyco",
    "github_project": "bg-helper",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": false,
    "requirements": [
        {
            "name": "fs-helper",
            "specs": []
        },
        {
            "name": "importlib-metadata",
            "specs": []
        },
        {
            "name": "input-helper",
            "specs": []
        }
    ],
    "lcname": "bg-helper"
}
        
Ken
Elapsed time: 1.01949s