diff --git a/docs/git-draft.1.adoc b/docs/git-draft.1.adoc index acf9cc5..a117898 100644 --- a/docs/git-draft.1.adoc +++ b/docs/git-draft.1.adoc @@ -78,10 +78,6 @@ The template will be created automatically if it did not already exist. --help:: Show help message and exit. --j:: ---json:: -Use JSON output. - -E:: --list-events:: Display all events corresponding to a draft. diff --git a/poetry.lock b/poetry.lock index 2c8440f..72932bb 100644 --- a/poetry.lock +++ b/poetry.lock @@ -799,24 +799,6 @@ tomli = ">=1.2.2" [package.extras] poetry-plugin = ["poetry (>=1.0,<2.0)"] -[[package]] -name = "prettytable" -version = "3.16.0" -description = "A simple Python library for easily displaying tabular data in a visually appealing ASCII table format" -optional = false -python-versions = ">=3.9" -groups = ["main"] -files = [ - {file = "prettytable-3.16.0-py3-none-any.whl", hash = "sha256:b5eccfabb82222f5aa46b798ff02a8452cf530a352c31bddfa29be41242863aa"}, - {file = "prettytable-3.16.0.tar.gz", hash = "sha256:3c64b31719d961bf69c9a7e03d0c1e477320906a98da63952bc6698d6164ff57"}, -] - -[package.dependencies] -wcwidth = "*" - -[package.extras] -tests = ["pytest", "pytest-cov", "pytest-lazy-fixtures"] - [[package]] name = "pydantic" version = "2.11.7" @@ -1490,18 +1472,6 @@ h11 = ">=0.8" [package.extras] standard = ["colorama (>=0.4) ; sys_platform == \"win32\"", "httptools (>=0.6.3)", "python-dotenv (>=0.13)", "pyyaml (>=5.1)", "uvloop (>=0.15.1) ; sys_platform != \"win32\" and sys_platform != \"cygwin\" and platform_python_implementation != \"PyPy\"", "watchfiles (>=0.13)", "websockets (>=10.4)"] -[[package]] -name = "wcwidth" -version = "0.2.13" -description = "Measures the displayed width of unicode strings in a terminal" -optional = false -python-versions = "*" -groups = ["main"] -files = [ - {file = "wcwidth-0.2.13-py2.py3-none-any.whl", hash = "sha256:3da69048e4540d84af32131829ff948f1e022c1c6bdb8d6102117aac784f6859"}, - {file = "wcwidth-0.2.13.tar.gz", hash = "sha256:72ea0c06399eb286d978fdedb6923a9eb47e1c486ce63e9b4e64fc18303972b5"}, -] - [[package]] name = "xdg-base-dirs" version = "6.0.2" @@ -1536,4 +1506,4 @@ openai = ["openai"] [metadata] lock-version = "2.1" python-versions = ">=3.12,<4" -content-hash = "e1aa784ff4ebbf16297fabf5e64de2b5bac0bf92d241ed0e9ab4f2e6cc852d0d" +content-hash = "b39f90ca96b5e0dc3f48935995802685cf7f89083d6cb41e42d65a1dec322707" diff --git a/pyproject.toml b/pyproject.toml index 3ff3bab..438a639 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -10,7 +10,6 @@ dependencies = [ "docopt-ng (>=0.9,<0.10)", "jinja2 (>=3.1.5,<4)", "msgspec (>=0.19.0,<0.20.0)", - "prettytable (>=3.15.1,<4)", "xdg-base-dirs (>=6.0.2,<7)", "yaspin (>=3.1.0,<4)", ] diff --git a/src/git_draft/__main__.py b/src/git_draft/__main__.py index 2f270b4..f6bb495 100644 --- a/src/git_draft/__main__.py +++ b/src/git_draft/__main__.py @@ -20,7 +20,7 @@ PromptMetadata, TemplatedPrompt, find_prompt_metadata, - templates_table, + list_templates, ) from .store import Store @@ -94,12 +94,6 @@ def callback( help="edit prompt or template", action="store_true", ) - parser.add_option( - "-j", - "--json", - help="use JSON for table output", - action="store_true", - ) parser.add_option( "--no-accept", @@ -218,8 +212,8 @@ async def run() -> None: # noqa: PLR0912 PLR0915 drafter.quit_folio() case "list-events": draft_id = args[0] if args else None - for elem in drafter.list_draft_events(draft_id): - print(elem) + for line in drafter.list_draft_events(draft_id): + print(line) case "show-template": if len(args) != 1: raise ValueError("Expected exactly one argument") @@ -235,8 +229,8 @@ async def run() -> None: # noqa: PLR0912 PLR0915 raise ValueError(f"No template named {name!r}") print(meta.source()) case "list-templates": - table = templates_table() - print(table.to_json() if opts.json else table) + for line in list_templates(): + print(line) case _: raise UnreachableError() diff --git a/src/git_draft/common.py b/src/git_draft/common.py index 5c903ec..79a6093 100644 --- a/src/git_draft/common.py +++ b/src/git_draft/common.py @@ -9,12 +9,10 @@ import logging import os from pathlib import Path -import sqlite3 import textwrap import tomllib -from typing import Any, ClassVar, Self +from typing import Any, Self -import prettytable import xdg_base_dirs @@ -119,32 +117,3 @@ def qualified_class_name(cls: type) -> str: def now() -> datetime: return datetime.now().astimezone() - - -class Table: - """Pretty-printable table""" - - _kwargs: ClassVar[Mapping[str, Any]] = dict(border=False) # Shared options - - def __init__(self, data: prettytable.PrettyTable) -> None: - self.data = data - self.data.align = "l" - - def __bool__(self) -> bool: - return len(self.data.rows) > 0 - - def __str__(self) -> str: - return str(self.data) if self else "" - - def to_json(self) -> str: - return self.data.get_json_string(header=False) - - @classmethod - def empty(cls) -> Self: - return cls(prettytable.PrettyTable([], **cls._kwargs)) - - @classmethod - def from_cursor(cls, cursor: sqlite3.Cursor) -> Self: - table = prettytable.from_db_cursor(cursor, **cls._kwargs) - assert table - return cls(table) diff --git a/src/git_draft/drafter.py b/src/git_draft/drafter.py index fbbcc25..42256ef 100644 --- a/src/git_draft/drafter.py +++ b/src/git_draft/drafter.py @@ -2,7 +2,7 @@ from __future__ import annotations -from collections.abc import Callable, Sequence +from collections.abc import Callable, Iterator, Sequence import dataclasses from datetime import datetime, timedelta import logging @@ -452,14 +452,13 @@ def latest_draft_prompt(self) -> str | None: prompt = "\n\n".join([prompt, reindent(question, prefix="> ")]) return prompt - def list_draft_events(self, draft_ref: str | None = None) -> Sequence[str]: + def list_draft_events(self, draft_ref: str | None = None) -> Iterator[str]: if draft_ref: folio_id, seqno = _parse_draft_ref(draft_ref) else: folio = _active_folio(self._repo) folio_id = folio.id seqno = None - elems = [] with self._store.cursor() as cursor: rows = cursor.execute( sql("list-action-events"), @@ -470,8 +469,7 @@ def list_draft_events(self, draft_ref: str | None = None) -> Sequence[str]: occurred_at, class_name, data = row event = decoders[class_name].decode(data) description = _format_event(event) - elems.append(f"{occurred_at}\t{class_name}\t{description}") - return elems + yield "\t".join([occurred_at, class_name, description]) @dataclasses.dataclass(frozen=True) diff --git a/src/git_draft/prompt.py b/src/git_draft/prompt.py index 177af23..068591b 100644 --- a/src/git_draft/prompt.py +++ b/src/git_draft/prompt.py @@ -2,7 +2,7 @@ from __future__ import annotations -from collections.abc import Mapping, Sequence +from collections.abc import Iterator, Mapping, Sequence import dataclasses import enum import functools @@ -15,7 +15,7 @@ import jinja2 from .bots import Worktree -from .common import Config, Table, package_root +from .common import Config, package_root from .worktrees import EmptyWorktree @@ -210,11 +210,9 @@ def find_prompt_metadata(name: PromptName) -> PromptMetadata | None: return prompt.metadata -def templates_table(*, include_local: bool = True) -> Table: +def list_templates(*, include_local: bool = True) -> Iterator[str]: env = _jinja_environment(include_local=include_local) worktree = EmptyWorktree() - table = Table.empty() - table.data.field_names = ["name", "local", "description"] for rel_path in env.list_templates(extensions=[_extension]): if any(p.startswith(".") for p in rel_path.split(os.sep)): continue @@ -222,5 +220,4 @@ def templates_table(*, include_local: bool = True) -> Table: prompt = _load_prompt(env, name, worktree) metadata = prompt.metadata local = "y" if metadata.is_local() else "n" - table.data.add_row([name, local, metadata.description or ""]) - return table + yield "\t".join([name, local, metadata.description or ""]) diff --git a/tests/git_draft/drafter_test.py b/tests/git_draft/drafter_test.py index a03e78c..ab87d33 100644 --- a/tests/git_draft/drafter_test.py +++ b/tests/git_draft/drafter_test.py @@ -192,5 +192,5 @@ async def test_latest_draft_prompt_no_active_branch(self) -> None: async def test_list_draft_events(self) -> None: bot = _SimpleBot({"prompt": lambda goal: goal.prompt}) await self._drafter.generate_draft("prompt1", bot, "theirs") - elems = self._drafter.list_draft_events() - assert len(elems) == 1 + lines = list(self._drafter.list_draft_events()) + assert len(lines) == 1 diff --git a/tests/git_draft/prompt_test.py b/tests/git_draft/prompt_test.py index 37614f6..619d2d7 100644 --- a/tests/git_draft/prompt_test.py +++ b/tests/git_draft/prompt_test.py @@ -41,5 +41,6 @@ def test_missing(self) -> None: assert sut.find_prompt_metadata("foo") is None -def test_templates_table() -> None: - assert sut.templates_table(include_local=False) +def test_list_templates() -> None: + templates = list(sut.list_templates(include_local=False)) + assert templates