Skip to content

Commit

Permalink
feat: add initial cli (#32)
Browse files Browse the repository at this point in the history
Fixes #1
  • Loading branch information
afuetterer authored May 20, 2024
1 parent 96a7258 commit 0b5b2c4
Show file tree
Hide file tree
Showing 10 changed files with 124 additions and 7 deletions.
1 change: 1 addition & 0 deletions .github/workflows/docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ jobs:
path: ~/.cache/pip
- name: Install pre-requisites (e.g. hatch)
run: python -m pip install --require-hashes --requirement=.github/requirements/ci.txt
- run: hatch run docs:cli
- run: hatch run docs:build
if: github.event_name == 'pull_request'
- run: |
Expand Down
5 changes: 3 additions & 2 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ jobs:
- name: Install pre-requisites (e.g. hatch)
run: python -m pip install --require-hashes --requirement=.github/requirements/ci.txt
- name: Run test suite
run: hatch run cov
run: hatch run cov -s
- name: Generate coverage report
run: |
export TOTAL_COV=$(hatch run cov-total)
Expand Down Expand Up @@ -70,7 +70,8 @@ jobs:
python-version: '3.12'
cache: pip
- run: python -Im pip install --editable .[dev]
- run: python -Ic 'import re3data.__about__; print(re3data.__about__.__version__)'
- run: python -Ic 'import re3data; print(re3data.__version__)'
- run: re3data --version
- name: Set up pipdeptree
if: matrix.os == 'ubuntu-latest'
run: python -m pip install --require-hashes --requirement=.github/requirements/ci.txt
Expand Down
5 changes: 3 additions & 2 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ repos:
hooks:
- id: mdformat
args: [--number, --wrap=120, --ignore-missing-references]
exclude: CHANGELOG.md|.changelog.md|docs/src/api
exclude: CHANGELOG.md|.changelog.md|docs/src/cli.md
additional_dependencies:
- mdformat-mkdocs[recommended]>=v2.0.7

Expand All @@ -73,7 +73,8 @@ repos:
args: [--config-file=pyproject.toml]
additional_dependencies:
- httpx>=0.27
- pytest>=8.1
- pytest>=8.2
- typer>=0.12

- repo: https://github.com/scientific-python/cookie
rev: 28d1a53da26f9daff6d9a49c50260421ad6d05e0 # frozen: 2024.04.23
Expand Down
1 change: 1 addition & 0 deletions docs/mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ watch:

nav:
- Home: index.md
- CLI Reference: cli.md
- Meta:
- Contributor Guide: contributing.md
- License: license.md
Expand Down
16 changes: 16 additions & 0 deletions docs/src/cli.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# CLI Reference

python-re3data.

**Usage**:

```console
$ re3data [OPTIONS] COMMAND [ARGS]...
```

**Options**:

* `-V, --version`: Show python-re3data version and exit.
* `--install-completion`: Install completion for the current shell.
* `--show-completion`: Show completion for the current shell, to copy it or customize the installation.
* `--help`: Show this message and exit.
4 changes: 4 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ optional-dependencies.cli = [
]
optional-dependencies.dev = [
"pre-commit~=3.7",
"python-re3data[cli]",
]
optional-dependencies.docs = [
"mike~=2.1",
Expand Down Expand Up @@ -112,10 +113,12 @@ cov-total = """

[tool.hatch.envs.docs]
features = [
"cli",
"docs",
]
template = "docs"
[tool.hatch.envs.docs.scripts]
cli = "typer src/re3data/_cli.py utils docs --name=re3data --title='CLI Reference' --output docs/src/cli.md"
build = "mkdocs build --config-file=docs/mkdocs.yml"
serve = "mkdocs serve --verbose --config-file=docs/mkdocs.yml"
deploy = "mike deploy --push --update-aliases $(hatch version) latest --config-file=docs/mkdocs.yml"
Expand Down Expand Up @@ -220,6 +223,7 @@ source = [
]
omit = [
"__about__.py",
"__main__.py",
]

[tool.coverage.report]
Expand Down
6 changes: 3 additions & 3 deletions tests/test_version.py → src/re3data/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
#
# SPDX-License-Identifier: MIT

from re3data import __version__
"""Entry point for python-re3data."""

from re3data._cli import app

def test_version() -> None:
assert __version__
app(prog_name="re3data")
41 changes: 41 additions & 0 deletions src/re3data/_cli.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
"""re3data command line interface."""

import logging
import sys
import typing

logger = logging.getLogger(__name__)

try:
import typer
except ImportError:
logger.error("`typer` is missing. Please run 'pip install python-re3data[cli]' to use the CLI.")
sys.exit(1)

CONTEXT_SETTINGS = {"help_option_names": ["-h", "--help"]}

app = typer.Typer(no_args_is_help=True, context_settings=CONTEXT_SETTINGS)


def _version_callback(show_version: bool) -> None:
# Ref: https://typer.tiangolo.com/tutorial/options/version/
from re3data import __version__

if show_version:
typer.echo(f"{__version__}")
raise typer.Exit


@app.callback(context_settings=CONTEXT_SETTINGS)
def callback(
version: typing.Annotated[
bool,
typer.Option(
"--version",
"-V",
help="Show python-re3data version and exit.",
callback=_version_callback,
),
] = False,
) -> None:
"""python-re3data."""
Empty file added src/re3data/py.typed
Empty file.
52 changes: 52 additions & 0 deletions tests/integration/test_cli.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# SPDX-FileCopyrightText: 2024 Heinz-Alexander Fütterer
#
# SPDX-License-Identifier: MIT

import sys
from importlib import reload
from unittest.mock import patch

import pytest
from typer.testing import CliRunner

from re3data import __version__
from re3data._cli import app

runner = CliRunner()

HELP_OPTION_NAMES = ("-h", "--help")
VERSION_OPTION_NAMES = ("-V", "--version")


def test_no_args_displays_help() -> None:
result = runner.invoke(app)
assert result.exit_code == 0
assert "Usage" in result.output
assert "Options" in result.output
assert "Show this message and exit" in result.output


@pytest.mark.parametrize("help_option_name", HELP_OPTION_NAMES)
def test_help_option_displays_help(help_option_name: str) -> None:
result = runner.invoke(app, [help_option_name])
assert result.exit_code == 0
assert "Usage" in result.output
assert "Options" in result.output
assert "Show this message and exit" in result.output


@pytest.mark.parametrize("version_option_name", VERSION_OPTION_NAMES)
def test_version_option_displays_version(version_option_name: str) -> None:
result = runner.invoke(app, [version_option_name])
assert result.exit_code == 0
assert __version__ in result.output


def test_typer_missing_message(caplog: pytest.LogCaptureFixture) -> None:
# act as if "typer" is not installed
with patch.dict(sys.modules, {"typer": None}):
with pytest.raises(SystemExit) as exc_info:
reload(sys.modules["re3data._cli"])
assert exc_info.type == SystemExit
assert exc_info.value.code == 1
assert "Please run 'pip install python-re3data[cli]'" in caplog.text

0 comments on commit 0b5b2c4

Please sign in to comment.