Skip to content

Commit

Permalink
Update to modern packaging
Browse files Browse the repository at this point in the history
Use pyproject.toml, uv, and hatchling.

This produces the following layout using

  uv pip install --no-deps --prefix=/tmp/test-prefix .`

  /tmp/test-prefix/.lock
  /tmp/test-prefix/bin/git-revise
  /tmp/test-prefix/lib/python3.12/site-packages/gitrevise/merge.py
  /tmp/test-prefix/lib/python3.12/site-packages/gitrevise/odb.py
  /tmp/test-prefix/lib/python3.12/site-packages/gitrevise/__init__.py
  /tmp/test-prefix/lib/python3.12/site-packages/gitrevise/utils.py
  /tmp/test-prefix/lib/python3.12/site-packages/gitrevise/tui.py
  /tmp/test-prefix/lib/python3.12/site-packages/gitrevise/todo.py
  /tmp/test-prefix/lib/python3.12/site-packages/gitrevise/__main__.py
  /tmp/test-prefix/lib/python3.12/site-packages/git_revise-0.7.0.dist-info/INSTALLER
  /tmp/test-prefix/lib/python3.12/site-packages/git_revise-0.7.0.dist-info/REQUESTED
  /tmp/test-prefix/lib/python3.12/site-packages/git_revise-0.7.0.dist-info/licenses/LICENSE
  /tmp/test-prefix/lib/python3.12/site-packages/git_revise-0.7.0.dist-info/direct_url.json
  /tmp/test-prefix/lib/python3.12/site-packages/git_revise-0.7.0.dist-info/RECORD
  /tmp/test-prefix/lib/python3.12/site-packages/git_revise-0.7.0.dist-info/entry_points.txt
  /tmp/test-prefix/lib/python3.12/site-packages/git_revise-0.7.0.dist-info/WHEEL
  /tmp/test-prefix/lib/python3.12/site-packages/git_revise-0.7.0.dist-info/METADATA
  /tmp/test-prefix/lib/python3.12/site-packages/git_revise-0.7.0.dist-info/uv_cache.json
  /tmp/test-prefix/share/man/man1/git-revise.1
  • Loading branch information
tamird committed Feb 11, 2025
1 parent 189c9fe commit f63314b
Show file tree
Hide file tree
Showing 16 changed files with 1,686 additions and 172 deletions.
17 changes: 9 additions & 8 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,22 @@ jobs:
name: Test on python ${{ matrix.python-version }} and ${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
python-version: ["3.8", "3.9", "3.10"]
os: [ubuntu-latest, windows-latest, macOS-latest]

steps:
- uses: actions/checkout@v4
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5

- uses: astral-sh/setup-uv@v5
with:
python-version: ${{ matrix.python-version }}
- name: Install tox
run: |
python -m pip install --upgrade pip
pip install tox tox-gh-actions
- name: Test with tox
run: tox

- run: uv sync --all-extras --dev

- run: uv pip install tox tox-gh-actions

- run: uv run tox
env:
PLATFORM: ${{ matrix.os }}
1 change: 0 additions & 1 deletion MANIFEST.in

This file was deleted.

6 changes: 3 additions & 3 deletions docs/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,16 @@ BUILDDIR = _build

# Put it first so that "make" without argument is like "make help".
help:
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
uv run @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)

.PHONY: help man Makefile

# Copy generated manfile into project root for distribution.
man: Makefile
@$(SPHINXBUILD) -M man "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
uv run @$(SPHINXBUILD) -M man "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
cp "$(BUILDDIR)/man/git-revise.1" "$(SOURCEDIR)/.."

# Catch-all target: route all unknown targets to Sphinx using the new
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
%: Makefile
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
uv run @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
4 changes: 3 additions & 1 deletion docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
import os
import sys

from sphinx.application import Sphinx

sys.path.insert(0, os.path.abspath(".."))

import gitrevise
Expand Down Expand Up @@ -122,5 +124,5 @@
# -- Extension configuration -------------------------------------------------


def setup(app):
def setup(app: Sphinx) -> None:
app.add_object_type("gitconfig", "gitconfig", objname="git config value")
24 changes: 12 additions & 12 deletions docs/contributing.rst
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,14 @@ for testing, and :command:`black` for code formatting.

.. code-block:: shell
$ tox # All python versions
$ tox -e py38 # Python 3.8
$ tox -e py39 # Python 3.9
$ tox -e py310 # Python 3.10
$ uv run tox # All python versions
$ uv run tox -e py38 # Python 3.8
$ uv run tox -e py39 # Python 3.9
$ uv run tox -e py310 # Python 3.10
$ tox -e mypy # Mypy Typechecking
$ tox -e lint # Linting
$ tox -e format # Check Formatting
$ uv run tox -e mypy # Mypy Typechecking
$ uv run tox -e lint # Linting
$ uv run tox -e format # Check Formatting
Code Formatting
---------------
Expand All @@ -26,8 +26,8 @@ This project uses ``isort`` and ``black`` for code formatting.

.. code-block:: shell
$ isort . # sort imports
$ black . # format all python code
$ uv run isort . # sort imports
$ uv run ruff format # format all python code
Building Documentation
----------------------
Expand All @@ -44,6 +44,6 @@ Publishing

.. code-block:: shell
$ python3 setup.py sdist bdist_wheel
$ twine check dist/*
$ twine upload dist/*
$ uv build
$ uv run twine check dist/*
$ uv run twine upload dist/*
14 changes: 8 additions & 6 deletions gitrevise/odb.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@
if TYPE_CHECKING:
from subprocess import _FILE

from typing_extensions import Self


class MissingObject(Exception):
"""Exception raised when a commit cannot be found in the ODB"""
Expand All @@ -57,7 +59,7 @@ class Oid(bytes):
def __new__(cls, b: bytes) -> Oid:
if len(b) != 20:
raise ValueError("Expected 160-bit SHA1 hash")
return super().__new__(cls, b) # type: ignore
return super().__new__(cls, b)

@classmethod
def fromhex(cls, instr: str) -> Oid:
Expand Down Expand Up @@ -165,8 +167,8 @@ class Repository:
"""path to GnuPG binary"""

_objects: Dict[int, Dict[Oid, GitObj]]
_catfile: Popen
_tempdir: Optional[TemporaryDirectory]
_catfile: Popen[bytes]
_tempdir: Optional[TemporaryDirectory[str]]

__slots__ = [
"workdir",
Expand Down Expand Up @@ -480,7 +482,7 @@ class GitObj:

__slots__ = ("repo", "body", "oid", "persisted")

def __new__(cls: Type[GitObjT], repo: Repository, body: bytes) -> GitObjT:
def __new__(cls, repo: Repository, body: bytes) -> "Self":
oid = Oid.for_object(cls._git_type(), body)
cache = repo._objects[oid[0]] # pylint: disable=protected-access
if oid in cache:
Expand All @@ -495,7 +497,7 @@ def __new__(cls: Type[GitObjT], repo: Repository, body: bytes) -> GitObjT:
self.persisted = False
cache[oid] = self
self._parse_body() # pylint: disable=protected-access
return cast(GitObjT, self)
return self

@classmethod
def _git_type(cls) -> str:
Expand Down Expand Up @@ -834,7 +836,7 @@ def git(
trim_newline: bool = True,
) -> bytes:
"""Invoke git with the given index as active"""
env = dict(**env) if env is not None else dict(**os.environ)
env = {**env} if env is not None else {**os.environ}
env["GIT_INDEX_FILE"] = str(self.index_file)
return self.repo.git(
*cmd,
Expand Down
2 changes: 1 addition & 1 deletion gitrevise/tui.py
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ def noninteractive(

# Update the commit message on the target commit if requested.
if args.message:
message = b"\n".join(l.encode("utf-8") + b"\n" for l in args.message)
message = b"\n".join(line.encode("utf-8") + b"\n" for line in args.message)
current = current.update(message=message)

# Prompt the user to edit the commit message if requested.
Expand Down
33 changes: 0 additions & 33 deletions pylintrc

This file was deleted.

92 changes: 92 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"

[project]
name = "git-revise"
dynamic = ["version"]
requires-python = ">=3.8"
authors = [{ name = "Nika Layzell", email = "[email protected]" }]
description = "Efficiently update, split, and rearrange git commits"
readme = "README.md"
license = { file = "LICENSE" }
keywords = ["git", "revise", "rebase", "amend", "fixup"]
classifiers = [
"Development Status :: 4 - Beta",
"Intended Audience :: Developers",
"Environment :: Console",
"Topic :: Software Development :: Version Control",
"Topic :: Software Development :: Version Control :: Git",
"License :: OSI Approved :: MIT License",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
]

[project.scripts]
git-revise = "gitrevise.tui:main"

[dependency-groups]
dev = [
"isort~=5.13.2",
"mypy~=1.14.1",
"pylint~=3.2.7",
"pytest-xdist~=3.6.1",
"pytest~=8.3.4",
"ruff~=0.9.6",
"sphinx~=7.1.2",
"tox-uv~=1.13.1",
"tox~=4.24.1",
"twine~=6.1.0",
"typing-extensions~=4.12.2",
]

[project.urls]
Homepage = "https://github.com/mystor/git-revise/"
Issues = "https://github.com/mystor/git-revise/issues/"
Repository = "https://github.com/mystor/git-revise/"
Documentation = "https://git-revise.readthedocs.io/en/latest/"

[tool.hatch.version]
path = "gitrevise/__init__.py"

[tool.hatch.build.targets.wheel]
packages = ["/gitrevise"]

[tool.hatch.build.targets.wheel.shared-data]
"git-revise.1" = "share/man/man1/git-revise.1"

[tool.hatch.build.targets.sdist]
include = ["/gitrevise"]

[tool.pylint.messages_control]
disable = [
"missing-docstring",
"too-few-public-methods",
"too-many-arguments",
"too-many-branches",
"too-many-instance-attributes",
"too-many-return-statements",
"cyclic-import",
"fixme",

# Currently broken analyses which are also handled (better) by mypy
"class-variable-slots-conflict",
"no-member",
]

good-names = [
# "Exception as e" is perfectly fine.
"e",
# "with open(…) as f" is idiomatic.
"f",
# Other contextually-unambiguous names.
"fn",
"repo",
"ed",
]

# TODO(https://github.com/astral-sh/ruff/issues/16105): Remove this once ruff properly respects
# requires-python.
[tool.ruff]
41 changes: 0 additions & 41 deletions setup.py

This file was deleted.

13 changes: 9 additions & 4 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ def main(
check: bool = True,
) -> "subprocess.CompletedProcess[bytes]":
cmd = [sys.executable, "-m", "gitrevise", *args]
print("Running", cmd, dict(cwd=cwd, input=input, check=check))
print("Running", cmd, {"cwd": cwd, "input": input, "check": check})
return subprocess.run(cmd, cwd=cwd, input=input, check=check)


Expand All @@ -128,6 +128,7 @@ def editor_main(
) -> "Generator[Editor, None, subprocess.CompletedProcess[bytes]]":
with pytest.MonkeyPatch().context() as monkeypatch, Editor() as ed, ThreadPoolExecutor() as tpe:
host, port = ed.server_address
host = host.decode() if isinstance(host, (bytes, bytearray)) else host
editor_cmd = " ".join(
shlex.quote(p)
for p in (
Expand All @@ -150,7 +151,10 @@ def cancel_on_error(future: "Future[Any]") -> None:
future.add_done_callback(cancel_on_error)

# Yield the editor, so that tests can process incoming requests via `ed.next_file()`.
yield ed
try:
yield ed
except GeneratorExit:
pass

return future.result()

Expand Down Expand Up @@ -189,7 +193,8 @@ class EditorFileRequestHandler(BaseHTTPRequestHandler):

# pylint: disable=invalid-name
def do_POST(self) -> None:
length = int(self.headers.get("content-length"))
content_length = self.headers.get("content-length")
length = int(content_length) if content_length is not None else 0
in_data = self.rfile.read(length)

status, out_data = 500, b"no traceback"
Expand Down Expand Up @@ -233,7 +238,7 @@ def next_file(self) -> Generator[EditorFile, None, None]:
try:
in_data, result_future = self.pending_edits.get(timeout=self.timeout)
except Empty as e:
raise Exception("timeout while waiting for request") from e
raise RuntimeError("timeout while waiting for request") from e

if result_future.done() or not result_future.set_running_or_notify_cancel():
raise result_future.exception() or CancelledError()
Expand Down
Loading

0 comments on commit f63314b

Please sign in to comment.