Fast, flexible and type-safe Git commands in Python.
Project description
๐ Gitbolt
Fast, flexible and type-safe Git command execution in Python using subprocess.
โจ Features
- ๐ง Typed: All commands and options are statically type-checked.
- โก Fast: Minimal abstractions over subprocess, runs directly on your system Git.
- ๐งฉ Composable: Git commands and options can be passed around as objects.
- ๐ Overridable: Easily override environment variables and options in a chainable, readable manner.
- ๐ฆ Lightweight: No dependencies on heavy Git libraries or C extensions.
- ๐งฐ Extensible: Future support for output transformers and other plugins.
- ๐จ Exception Handling: Raises any error as a Python-recognisable exception.
- ๐ค Debuggable: Exceptions capture
stdout,stderr, and the return code of the run command. - ๐ค Lazy Execution: Inherently lazily processed.
- ๐ Transparent Output: Returns a Git command's
stdoutas-is. - ๐งช Terminal Functions: Git subcommands are terminal functions.
- ๐งผ Idiomatic Python: Write commands in idiomatic Python at compile-time and be confident theyโll execute smoothly at runtime.
- ๐ Add-ons: Special features provided to ease programming with git. These can be added if required.
- ๐ป CLI-cmd: Take commands from cli and run in
gitbolt.
๐ฆ Installation
pip install gitbolt
๐ก Motivation
Running system commands in Python can be tricky for the following reasons:
- Arguments sent to
subprocessmay not be typed correctly and result in runtime errors. - Argument groups may be mutually exclusive or required conditionally โ again causing runtime issues.
- Errors from subprocess are often unhelpful and difficult to debug.
Also, using subprocess effectively means you must:
- Understand and manage process setup, piping, and teardown.
- Know your CLI command intricacies in depth.
This project exists to fix all that โ with ergonomics, speed, and type-safety.
๐ฏ Project Goals
โ Predictable Compile-Time Behavior
Type-checking ensures runtime safety.
โ Ergonomic APIs
Make git command interfaces as ergonomic to the user as possible.
Provide versions of most used command combinations
git hash-object supports taking multiple files and outputs a hash per file. But in practice, it's most often used to write a single file to the Git object database and return its hash. To match this real-world usage, Gitbolt offers a more ergonomic method that accepts one file and returns one hash โ while still giving you the flexibility to access the full range of git hash-object capabilities when needed.
Let subcommands be passed around as objects
Gitbolt lets you pass subcommands around as typed objects. This enables highly focused, minimal APIs โ you can write functions that accept only the subcommands they truly need. This leads to cleaner logic, better separation of concerns, and compile-time guarantees that help prevent misuse.
import gitbolt
git = gitbolt.get_git()
version_subcmd = git.version_subcmd
add_subcmd = git.add_subcmd
def method_which_only_adds_a_file(add_subcmd: gitbolt.base.Add):
"""
This method only requires the `add` subcommand.
"""
...
method_which_only_adds_a_file(add_subcmd)
โ Subcommands as Objects
git subcommands are modeled as terminal functions that return stdout.
import gitbolt
git = gitbolt.get_git()
version_stdout = git.version_subcmd.version().version()
print(version_stdout)
๐ชผ Modular Architecture
๐งโ๐ป Modular at the programmatic level
Commands are designed to be passed around as objects. This makes them modular and thus users can opt to use only particular commands.
from gitbolt import get_git
git = get_git() # get git object for the current working directory
add_subcmd = git.add_subcmd
ls_tree_subcmd = git.ls_tree_subcmd
# now, functions can be written to accept only the required subcommands and nothing more than that.
๐ฝ๏ธ Modular at project level
Only required commands and hence their implementations can be installed as per user requirement.
e.g.
- To install only the
git addcommand related logic:-
pip install gitbolt[add]
-
- To install command logic related to
git addandgit rmcommands:-
pip install gitbolt[add,rm]
-
- Install all porcelain related commands:
-
pip install gitbolt[porcelain]
-
- Install high performance
pygit2implementations:-
pip install gitbolt[pygit2]
-
pip install gitbolt[add,pygit2,rm]
-
- At last, install every command's implementation:
-
pip install gitbolt[all]
-
๐ง Strong Typing Everywhere
Extensive use of type-hints ensures that invalid usages fail early โ at compile-time. Write at compile-time and be sure that commands run error-free at runtime.
Allow users to set/unset/reset Git environment variables and main command options using typed, chainable, Pythonic methods โ just before a subcommand is executed.
๐งฌ Git Environment Variables
๐ Override a single Git env (e.g., GIT_TRACE)
import gitbolt
git = gitbolt.get_git()
git = git.git_envs_override(GIT_TRACE=True)
๐ Override multiple Git envs (e.g., GIT_TRACE, GIT_DIR, GIT_EDITOR)
from pathlib import Path
import gitbolt
git = gitbolt.get_git()
git = git.git_envs_override(GIT_TRACE=1, GIT_DIR=Path('/tmp/git-dir/'), GIT_EDITOR='vim')
๐ชข Chain multiple overrides fluently
from pathlib import Path
import gitbolt
git = gitbolt.get_git()
overridden_git = git.git_envs_override(GIT_SSH=Path('/tmp/SSH')).git_envs_override(
GIT_TERMINAL_PROMPT=1,
GIT_NO_REPLACE_OBJECTS=True
)
re_overridden_git = overridden_git.git_envs_override(GIT_TRACE=True)
โ Unset Git envs using a special UNSET marker
import gitbolt
from vt.utils.commons.commons.core_py import UNSET
git = gitbolt.get_git()
overridden_git = git.git_envs_override(GIT_ADVICE=True, GIT_TRACE=True)
no_advice_unset_git = overridden_git.git_envs_override(GIT_TRACE=UNSET)
๐ Reset Git envs by setting new values
import gitbolt
git = gitbolt.get_git()
overridden_git = git.git_envs_override(GIT_TRACE=True)
git_trace_reset_git = overridden_git.git_envs_override(GIT_TRACE=False)
Allow users to set/unset/reset git main command options in typed and pythonic manner just before subcommand run to provide maximal flexibility.
โ๏ธ Git Main Command Options
๐ Override a single Git opt (e.g., --no-replace-objects)
import gitbolt
git = gitbolt.get_git()
git = git.git_opts_override(no_replace_objects=True)
๐ Override multiple options (e.g., --git-dir, --paginate)
from pathlib import Path
from gitbolt.subprocess.impl.simple import SimpleGitCommand
git = SimpleGitCommand()
git = git.git_opts_override(no_replace_objects=True, git_dir=Path(), paginate=True)
๐ชข Chain multiple option overrides fluently
import gitbolt
from pathlib import Path
git = gitbolt.get_git()
overridden_git = git.git_opts_override(exec_path=Path('tmp')).git_opts_override(
noglob_pathspecs=True,
no_advice=True
).git_opts_override(
config_env={'auth': 'suhas', 'comm': 'suyog'}
)
re_overridden_git = overridden_git.git_opts_override(glob_pathspecs=True)
โ Unset Git opts using a special UNSET marker
import gitbolt
from pathlib import Path
from vt.utils.commons.commons.core_py import UNSET
git = gitbolt.get_git()
overridden_git = git.git_opts_override(exec_path=Path('tmp'), no_advice=True)
no_advice_unset_git = overridden_git.git_opts_override(no_advice=UNSET)
๐ Reset Git opts by setting new values
import gitbolt
git = gitbolt.get_git()
overridden_git = git.git_opts_override(no_advice=True)
no_advice_reset_git = overridden_git.git_opts_override(no_advice=False)
๐ Run unchecked commands
At last, run unchecked commands in git.
Introduced in 0.0.0dev4 to
- experiment.
- have consistent interfaced commands run until all subcommands are provided by the library.
import gitbolt
git = gitbolt.get_git_command()
git = git.git_opts_override(no_advice=True)
git.subcmd_unchecked.run(['--version']) # run the version option for git.
git.subcmd_unchecked.run(['version']) # run the version subcommand.
๐ป Run commands received from CLI
Introduced in 0.0.0dev11 is the ability to take commands from CLI and run it inside gitbolt.
While making a system it may be required to run cli commands as received from cli using gitbolt. An obvious example
would be to make a system that receives CLI commands and does certain modifications/additions inside gitbolt before
actually running them. An example:
import gitbolt
opts = ["--no-pager", "--namespace", "n1"] # options received from outside your program.
envs = dict(GIT_AUTHOR_NAME="ss") # env-vars received form outside your program.
git = gitbolt.get_git_command(opts=opts, envs=envs)
# these can later be overridden
git = git.git_opts_override(namespace="n2")
๐ Transparent by Default
Output of git commands is returned as-is. No transformations unless explicitly requested. Transformers for formatting/parsing can be added later.
โ Benefits Out-of-the-Box
- ๐ Composable Git commands.
- ๐ค Returns raw stdout.
- ๐จ Exceptions with full context.
- ๐ค Lazy execution.
- ๐ง Strong typing and compile-time guarantees.
- ๐งผ Idiomatic Python.
- ๐งช Terminal subcommands.
- ๐ฃ Fail-fast on invalid usage.
๐ More Information
- ๐ License (Apache-2.0)
- ๐ค Contributing Guide
๐ง Future Goals
- Support
pygit2for direct, fast Git access. - Enable
porcelainsupport usingpygit2where required.pygit2usage will automatically make all commands return in porcelain mode.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file gitbolt-0.0.0.dev15.tar.gz.
File metadata
- Download URL: gitbolt-0.0.0.dev15.tar.gz
- Upload date:
- Size: 44.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e25db36ff8729cec2b90375c693a61abdeb13a5e1d433e1d5a9d2aeef49d7347
|
|
| MD5 |
84c4e1fa5d3da30490c80dfbbe7c5b90
|
|
| BLAKE2b-256 |
ffed2c39c654bbdc348579a4ef55e2a8b4b7713875a909438b2f60d80ecc1ff0
|
Provenance
The following attestation bundles were made for gitbolt-0.0.0.dev15.tar.gz:
Publisher:
python-publish.yml on Vaastav-Technologies/py-gitbolt
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
gitbolt-0.0.0.dev15.tar.gz -
Subject digest:
e25db36ff8729cec2b90375c693a61abdeb13a5e1d433e1d5a9d2aeef49d7347 - Sigstore transparency entry: 1251618272
- Sigstore integration time:
-
Permalink:
Vaastav-Technologies/py-gitbolt@d021b32623de1282a3a999c12f86e4d42d9a2638 -
Branch / Tag:
refs/tags/v0.0.0dev15 - Owner: https://github.com/Vaastav-Technologies
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
python-publish.yml@d021b32623de1282a3a999c12f86e4d42d9a2638 -
Trigger Event:
push
-
Statement type:
File details
Details for the file gitbolt-0.0.0.dev15-py3-none-any.whl.
File metadata
- Download URL: gitbolt-0.0.0.dev15-py3-none-any.whl
- Upload date:
- Size: 48.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
866915a99d98e5eadf0c12ca97043f4b0eca384fdcc6fa98dd5cae257da402f6
|
|
| MD5 |
9a29028bdd7a3ef0f25978aba355d2d5
|
|
| BLAKE2b-256 |
99c4c4f1253b619a1e650fb0c0321c2b15b098c444c1a5637b2d80c9a7d18f09
|
Provenance
The following attestation bundles were made for gitbolt-0.0.0.dev15-py3-none-any.whl:
Publisher:
python-publish.yml on Vaastav-Technologies/py-gitbolt
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
gitbolt-0.0.0.dev15-py3-none-any.whl -
Subject digest:
866915a99d98e5eadf0c12ca97043f4b0eca384fdcc6fa98dd5cae257da402f6 - Sigstore transparency entry: 1251618337
- Sigstore integration time:
-
Permalink:
Vaastav-Technologies/py-gitbolt@d021b32623de1282a3a999c12f86e4d42d9a2638 -
Branch / Tag:
refs/tags/v0.0.0dev15 - Owner: https://github.com/Vaastav-Technologies
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
python-publish.yml@d021b32623de1282a3a999c12f86e4d42d9a2638 -
Trigger Event:
push
-
Statement type: