Skip to main content

Fast, flexible and type-safe Git commands in Python.

Project description

๐Ÿš€ Gitbolt

PyPI - Types GitHub License ๐Ÿ”ง test ๐Ÿ’ก typecheck ๐Ÿ› ๏ธ lint ๐Ÿ“Š coverage ๐Ÿ“ค Upload Python Package PyPI - Version

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 stdout as-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:

  1. Arguments sent to subprocess may not be typed correctly and result in runtime errors.
  2. Argument groups may be mutually exclusive or required conditionally โ€” again causing runtime issues.
  3. 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
from gitbolt.git_subprocess.impl.simple import SimpleGitCommand

git = SimpleGitCommand()
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.

from gitbolt.git_subprocess.impl.simple import SimpleGitCommand

git = SimpleGitCommand()
status_out = git.status_subcmd.status()
print(status_out)

๐Ÿชผ 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 add command related logic:
    • pip install gitbolt[add]
      
  • To install command logic related to git add and git rm commands:
    • pip install gitbolt[add,rm]
      
  • Install all porcelain related commands:
    • pip install gitbolt[porcelain]
      
  • Install high performance pygit2 implementations:
    • 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)

from gitbolt.git_subprocess.impl.simple import SimpleGitCommand

git = SimpleGitCommand()
git = git.git_envs_override(GIT_TRACE=True)

๐ŸŒ Override multiple Git envs (e.g., GIT_TRACE, GIT_DIR, GIT_EDITOR)

from pathlib import Path
from gitbolt.git_subprocess.impl.simple import SimpleGitCommand

git = SimpleGitCommand()
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
from gitbolt.git_subprocess.impl.simple import SimpleGitCommand

git = SimpleGitCommand()
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

from gitbolt.git_subprocess.impl.simple import SimpleGitCommand
from vt.utils.commons.commons.core_py import UNSET

git = SimpleGitCommand()
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

from gitbolt.git_subprocess.impl.simple import SimpleGitCommand

git = SimpleGitCommand()
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)

from gitbolt.git_subprocess.impl.simple import SimpleGitCommand

git = SimpleGitCommand()
git = git.git_opts_override(no_replace_objects=True)

๐ŸŒ Override multiple options (e.g., --git-dir, --paginate)

from pathlib import Path
from gitbolt.git_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

from pathlib import Path
from gitbolt.git_subprocess.impl.simple import SimpleGitCommand

git = SimpleGitCommand()
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

from pathlib import Path
from gitbolt.git_subprocess.impl.simple import SimpleGitCommand
from vt.utils.commons.commons.core_py import UNSET

git = SimpleGitCommand()
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

from gitbolt.git_subprocess.impl.simple import SimpleGitCommand

git = SimpleGitCommand()
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.
from gitbolt.git_subprocess.impl.simple import SimpleGitCommand

git = SimpleGitCommand()
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:

from gitbolt.git_subprocess.impl.simple import CLISimpleGitCommand

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 = CLISimpleGitCommand(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


๐Ÿšง Future Goals

  • Support pygit2 for direct, fast Git access.
  • Enable porcelain support using pygit2 where required.

    pygit2 usage will automatically make all commands return in porcelain mode.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

gitbolt-0.0.0.dev14.tar.gz (44.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

gitbolt-0.0.0.dev14-py3-none-any.whl (48.1 kB view details)

Uploaded Python 3

File details

Details for the file gitbolt-0.0.0.dev14.tar.gz.

File metadata

  • Download URL: gitbolt-0.0.0.dev14.tar.gz
  • Upload date:
  • Size: 44.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for gitbolt-0.0.0.dev14.tar.gz
Algorithm Hash digest
SHA256 5de80f25a3536cdbd6d42dc5522c5a52baba6dccb506deb7c453802f4dbbe6ab
MD5 ebace2ad817ae6297c83d0ea016f2795
BLAKE2b-256 de16641c6a0bd966f2401e26d6632e73711bfd6a394f3aa0796997443a3f5aed

See more details on using hashes here.

Provenance

The following attestation bundles were made for gitbolt-0.0.0.dev14.tar.gz:

Publisher: python-publish.yml on Vaastav-Technologies/py-gitbolt

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file gitbolt-0.0.0.dev14-py3-none-any.whl.

File metadata

  • Download URL: gitbolt-0.0.0.dev14-py3-none-any.whl
  • Upload date:
  • Size: 48.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for gitbolt-0.0.0.dev14-py3-none-any.whl
Algorithm Hash digest
SHA256 aa0b6139f3f141b9f07670883b8e0a4ade51e7f4fb55bbb3fa7416ccf29ae4d8
MD5 9d1ac13f3cfa0e6b3647b861e6e8bb5c
BLAKE2b-256 5c6211dee08cd1c4487c1da1d8f6d8d0f197aa7b3d6094402163940cac41e700

See more details on using hashes here.

Provenance

The following attestation bundles were made for gitbolt-0.0.0.dev14-py3-none-any.whl:

Publisher: python-publish.yml on Vaastav-Technologies/py-gitbolt

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page