Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions plugins/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ By leveraging these plugins, you can streamline your workflow and tackle coding
| nvm | Node.js version manager allowing easy switching between different Node.js versions. |
| progress | Insufficient information provided to give a precise description. |
| pyenv | Tool for managing multiple Python versions within a system. |
| [python](python) | Aliases and utilities for Python development, including venv management and pip shortcuts. |
| rbenv | Tool for managing your app's Ruby environment. |
| sdkman | Version and package manager for development tools such as Java, Kotlin, and Gradle. |
| sudo | Utility for executing commands with superuser privileges on Unix and Unix-like systems. |
Expand Down
82 changes: 82 additions & 0 deletions plugins/python/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
# python plugin

Add [oh-my-bash](https://ohmybash.github.io) integration for [Python](https://www.python.org/) development, providing aliases and utilities for everyday workflows including virtual environment management, pip, and project housekeeping. Inspired by the [oh-my-zsh python plugin](https://github.com/ohmyzsh/ohmyzsh/tree/master/plugins/python).

## Installation

Enable the plugin by adding it to your oh-my-bash `plugins` definition in `~/.bashrc`.

```sh
plugins=(python)
```

## Configuration

Set these variables **before** the `source "$OSH/oh-my-bash.sh"` line in your `~/.bashrc`.

| Variable | Default | Description |
|--------------------------------|-----------|----------------------------------------------------------|
| `OMB_PLUGIN_PYTHON_VENV_NAME` | `venv` | Default venv directory name used by `vrun` and `mkv` |
| `OMB_PLUGIN_PYTHON_AUTO_VRUN` | _(unset)_ | Set to `true` to auto-activate venvs on directory change |

## Aliases

### General

| Alias | Command | Description |
|------------|----------------------------|----------------------------------------------------------|
| `py` | `python3` | Shorthand for python3 (if `py` is not already installed) |
| `pyfind` | `find . -name "*.py"` | Find all Python files in current tree |
| `pygrep` | `grep -rn --include="*.py"`| Search inside Python files |
| `pyserver` | `python3 -m http.server` | Serve current directory over HTTP |

### pip

| Alias | Command | Description |
|----------|------------------------------------|------------------------------------------|
| `pipi` | `pip install` | Install a package |
| `pipu` | `pip uninstall` | Uninstall a package |
| `pipup` | `pip install --upgrade` | Upgrade a package |
| `pipr` | `pip install -r requirements.txt` | Install from requirements.txt |
| `pipf` | `pip freeze` | Print installed packages |
| `pipfr` | `pip freeze > requirements.txt` | Save installed packages to requirements |
| `pipls` | `pip list` | List installed packages |
| `pipout` | `pip list --outdated` | List outdated packages |

## Functions

### `pyclean [dir...]`

Remove compiled bytecode files and cache directories (`__pycache__`, `.mypy_cache`, `.pytest_cache`) from the given directories, or the current directory if none are specified.

```bash
pyclean # clean current directory
pyclean src tests # clean specific directories
```

### `vrun [name]`

Activate a virtual environment by name. If no name is given, searches for the first existing directory in `$OMB_PLUGIN_PYTHON_VENV_NAME`, `venv`, `.venv` (in that order).

```bash
vrun # auto-detect and activate
vrun .venv # activate a specific venv
```

### `mkv [name]`

Create a new virtual environment with `python3 -m venv` and immediately activate it. Defaults to `$OMB_PLUGIN_PYTHON_VENV_NAME`.

```bash
mkv # create and activate ./venv
mkv .venv # create and activate ./.venv
```

## Auto-activate venv

When `OMB_PLUGIN_PYTHON_AUTO_VRUN=true`, the plugin registers a `PROMPT_COMMAND` hook to automatically activate a virtual environment when you enter a directory that contains one, and deactivate it when you leave. Using `PROMPT_COMMAND` instead of aliasing `cd` ensures compatibility with other plugins that also hook into directory changes (e.g. `nvm`).

```sh
# ~/.bashrc (before sourcing oh-my-bash)
OMB_PLUGIN_PYTHON_AUTO_VRUN=true
```
142 changes: 142 additions & 0 deletions plugins/python/python.plugin.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
#! bash oh-my-bash.module
# Description: Aliases and utilities for Python development
# Inspired by the oh-my-zsh python plugin (https://github.com/ohmyzsh/ohmyzsh/tree/master/plugins/python)
#
# @var[opt] OMB_PLUGIN_PYTHON_VENV_NAME default venv directory name (default: venv)
# @var[opt] OMB_PLUGIN_PYTHON_AUTO_VRUN set to 'true' to auto-activate venv on directory change

# Use 'py' as a shorthand for python3 if not already defined
_omb_util_command_exists py || alias py='python3'

# Find Python source files
alias pyfind='find . -name "*.py"'

# Grep within Python source files
alias pygrep='grep -rn --include="*.py"'

# Serve the current directory over HTTP
alias pyserver='python3 -m http.server'

# Remove compiled bytecode and cache directories left by Python tools
function pyclean {
find "${@:-.}" -type f -name "*.py[co]" -delete
find "${@:-.}" -type d -name "__pycache__" -delete
find "${@:-.}" -depth -type d -name ".mypy_cache" -exec rm -r "{}" +
find "${@:-.}" -depth -type d -name ".pytest_cache" -exec rm -r "{}" +
}

#------------------------------------------------------------------------------
# pip aliases

alias pipi='pip install'
alias pipu='pip uninstall'
alias pipup='pip install --upgrade'
alias pipr='pip install -r requirements.txt'
alias pipf='pip freeze'
alias pipfr='pip freeze > requirements.txt'
alias pipls='pip list'
alias pipout='pip list --outdated'

#------------------------------------------------------------------------------
# Virtual environment management
#
# @var[opt] OMB_PLUGIN_PYTHON_VENV_NAME default venv name used by vrun/mkv (default: venv)

: "${OMB_PLUGIN_PYTHON_VENV_NAME:=venv}"

# Build the ordered, deduplicated list of venv names to search
_omb_plugin_python_venv_names=("$OMB_PLUGIN_PYTHON_VENV_NAME")
for _omb_plugin_python__n in venv .venv; do
[[ " ${_omb_plugin_python_venv_names[*]} " == *" $_omb_plugin_python__n "* ]] ||
_omb_plugin_python_venv_names+=("$_omb_plugin_python__n")
done
unset -v _omb_plugin_python__n

# Activate a virtual environment.
# Usage: vrun [name]
# If no name is given, searches for the first matching directory in
# $OMB_PLUGIN_PYTHON_VENV_NAME, venv, .venv (in that order).
function vrun {
if [[ -z ${1-} ]]; then
local name
for name in "${_omb_plugin_python_venv_names[@]}"; do
if [[ -d $name ]]; then
vrun "$name"
return $?
fi
done
_omb_util_print 'vrun: no virtual environment found in current directory' >&2
return 1
fi

local name=$1
if [[ ! -d $name ]]; then
_omb_util_print "vrun: no such venv in current directory: $name" >&2
return 1
fi
if [[ ! -f $name/bin/activate ]]; then
_omb_util_print "vrun: '$name' is not a proper virtual environment" >&2
return 1
fi

# shellcheck source=/dev/null
. "$name/bin/activate" || return $?
_omb_util_print "Activated virtual environment $name"
}

# Create a new virtual environment and immediately activate it.
# Usage: mkv [name]
# Defaults to $OMB_PLUGIN_PYTHON_VENV_NAME if no name is given.
function mkv {
local name=${1:-$OMB_PLUGIN_PYTHON_VENV_NAME}
python3 -m venv "$name" || return $?
_omb_util_print "Created venv in '$PWD/$name'"
vrun "$name"
}

#------------------------------------------------------------------------------
# Auto-activate venv on directory change
#
# When OMB_PLUGIN_PYTHON_AUTO_VRUN=true, automatically activates a venv when
# entering a directory that contains one, and deactivates it when leaving.

if [[ ${OMB_PLUGIN_PYTHON_AUTO_VRUN-} == true ]]; then
function _omb_plugin_python_auto_vrun {
# Deactivate if we have left the project directory that owns the current venv.
# Use an exact boundary check to avoid matching sibling dirs with the same prefix
# (e.g. /path/project2 when the venv belongs to /path/project).
if [[ $(type -t deactivate) == function ]] && [[ -n ${VIRTUAL_ENV-} ]]; then
local _omb_plugin_python_project_dir=${VIRTUAL_ENV%/*}
if [[ $PWD != "$_omb_plugin_python_project_dir" &&
$PWD != "$_omb_plugin_python_project_dir/"* ]]; then
deactivate > /dev/null 2>&1
fi
unset -v _omb_plugin_python_project_dir
fi

# Skip if this directory is already the active venv's home
[[ -n ${VIRTUAL_ENV-} && $PWD == "${VIRTUAL_ENV%/*}" ]] && return 0

local name
for name in "${_omb_plugin_python_venv_names[@]}"; do
if [[ -f $name/bin/activate ]]; then
[[ $(type -t deactivate) == function ]] && deactivate > /dev/null 2>&1
# shellcheck source=/dev/null
source "$name/bin/activate" > /dev/null 2>&1
break
fi
done
}

# Use PROMPT_COMMAND instead of aliasing cd so other plugins' cd hooks are not clobbered.
_omb_plugin_python_last_pwd=
function _omb_plugin_python_auto_vrun_hook {
[[ ${_omb_plugin_python_last_pwd-} == "$PWD" ]] && return 0
_omb_plugin_python_last_pwd=$PWD
_omb_plugin_python_auto_vrun
}
_omb_util_add_prompt_command _omb_plugin_python_auto_vrun_hook

# Run once for the shell's starting directory
_omb_plugin_python_auto_vrun_hook
fi