-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement linksmith inventory
and linksmith output-formats
#4
Merged
+794
−15
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
*.inv binary |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
# Backlog | ||
|
||
## Iteration +1 | ||
- Docs: Based on sphobjinv. | ||
- Response caching to buffer subsequent invocations | ||
- Add output flavor, like `--details=compact,full`. | ||
**Full details**, well, should display **full URLs**, ready for | ||
navigational consumption (clicking). | ||
- Improve HTML output. (sticky breadcrumb/navbar, etc.) | ||
|
||
## Iteration +2 | ||
sphobjinv call delegation ftw. | ||
``` | ||
# Shorthand command ... | ||
anansi suggest matplotlib draw | ||
# ... for: | ||
sphobjinv suggest -u https://matplotlib.org/stable/ draw | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
(setup)= | ||
# Setup | ||
|
||
Up until published on PyPI, please install the package that way. Thank you. | ||
|
||
```bash | ||
pip install 'linksmith @ git+https://github.com/tech-writing/linksmith.git' | ||
``` | ||
|
||
:::{note} | ||
This command will need an installation of Git on your system. | ||
::: |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
(usage)= | ||
# Usage | ||
|
||
Linksmith provides the `linksmith` command line program. It harbours | ||
different subsystems, accessible by using corresponding subcommands, | ||
like `linksmith inventory`. | ||
|
||
:::{warning} | ||
Here be dragons. Please note the program is pre-alpha, and a work in | ||
progress, so everything may change while we go. | ||
::: | ||
|
||
|
||
## Output Formats | ||
Display all the available output formats at a glance. | ||
```shell | ||
linksmith output-formats | ||
``` | ||
|
||
|
||
## Sphinx Inventories | ||
The `linksmith inventory` subsystem supports working with Sphinx inventories, | ||
it is heavily based on `sphinx.ext.intersphinx` and `sphobjinv`. | ||
|
||
:::{rubric} Single Inventory | ||
::: | ||
Refer to `objects.inv` on the local filesystem or on a remote location. | ||
```shell | ||
linksmith inventory /path/to/objects.inv | ||
``` | ||
```shell | ||
linksmith inventory https://linksmith.readthedocs.io/en/latest/objects.inv | ||
``` | ||
|
||
```shell | ||
linksmith inventory \ | ||
https://linksmith.readthedocs.io/en/latest/objects.inv \ | ||
--format=markdown+table | ||
``` | ||
|
||
:::{rubric} Multiple Inventories | ||
::: | ||
Refer to multiple `objects.inv` resources. | ||
```shell | ||
linksmith inventory \ | ||
https://github.com/crate/crate-docs/raw/main/registry/sphinx-inventories.txt \ | ||
--format=html+table | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
import json | ||
|
||
import rich_click as click | ||
from pueblo.util.cli import boot_click | ||
|
||
from linksmith.settings import help_config | ||
|
||
from .model import OutputFormatRegistry | ||
from .sphinx.cli import cli as inventory_cli | ||
|
||
|
||
@click.group() | ||
@click.rich_config(help_config=help_config) | ||
@click.option("--verbose", is_flag=True, required=False, help="Turn on logging") | ||
@click.option("--debug", is_flag=True, required=False, help="Turn on logging with debug level") | ||
@click.version_option() | ||
@click.pass_context | ||
def cli(ctx: click.Context, verbose: bool, debug: bool): | ||
return boot_click(ctx, verbose, debug) | ||
|
||
|
||
@click.command() | ||
@click.rich_config(help_config=help_config) | ||
@click.pass_context | ||
def output_formats(ctx: click.Context): # noqa: ARG001 | ||
""" | ||
Display available output format aliases. | ||
""" | ||
print(json.dumps(sorted(OutputFormatRegistry.aliases()), indent=2)) | ||
|
||
|
||
cli.add_command(output_formats, name="output-formats") | ||
cli.add_command(inventory_cli, name="inventory") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
import dataclasses | ||
import io | ||
import typing as t | ||
from enum import auto | ||
from pathlib import Path | ||
|
||
from linksmith.util.python import AutoStrEnum | ||
|
||
|
||
class OutputFormat(AutoStrEnum): | ||
TEXT_INSPECT = auto() | ||
TEXT_PLAIN = auto() | ||
MARKDOWN = auto() | ||
MARKDOWN_TABLE = auto() | ||
RESTRUCTUREDTEXT = auto() | ||
HTML = auto() | ||
HTML_TABLE = auto() | ||
JSON = auto() | ||
YAML = auto() | ||
|
||
|
||
@dataclasses.dataclass | ||
class OutputFormatRule: | ||
format: OutputFormat | ||
aliases: t.List[str] | ||
|
||
|
||
class OutputFormatRegistry: | ||
rules = [ | ||
OutputFormatRule(format=OutputFormat.TEXT_INSPECT, aliases=["text"]), | ||
OutputFormatRule(format=OutputFormat.TEXT_PLAIN, aliases=["text+plain"]), | ||
OutputFormatRule(format=OutputFormat.MARKDOWN, aliases=["markdown", "md"]), | ||
OutputFormatRule(format=OutputFormat.MARKDOWN_TABLE, aliases=["markdown+table", "md+table"]), | ||
OutputFormatRule(format=OutputFormat.RESTRUCTUREDTEXT, aliases=["restructuredtext", "rst"]), | ||
OutputFormatRule(format=OutputFormat.HTML, aliases=["html", "html+table"]), | ||
OutputFormatRule(format=OutputFormat.JSON, aliases=["json"]), | ||
OutputFormatRule(format=OutputFormat.YAML, aliases=["yaml"]), | ||
] | ||
|
||
@classmethod | ||
def resolve(cls, format_: str) -> OutputFormat: | ||
for rule in cls.rules: | ||
if format_ in rule.aliases: | ||
return rule.format | ||
raise NotImplementedError(f"Output format not implemented: {format_}") | ||
|
||
@classmethod | ||
def aliases(cls) -> t.List[str]: | ||
data = [] | ||
for rule in cls.rules: | ||
data += rule.aliases | ||
return data | ||
|
||
|
||
class ResourceType(AutoStrEnum): | ||
BUFFER = auto() | ||
PATH = auto() | ||
URL = auto() | ||
|
||
@classmethod | ||
def detect(cls, location): | ||
if isinstance(location, io.IOBase): | ||
return cls.BUFFER | ||
path = Path(location) | ||
if path.exists(): | ||
return cls.PATH | ||
elif location.startswith("http://") or location.startswith("https://"): | ||
return cls.URL | ||
else: | ||
raise NotImplementedError(f"Resource type not implemented: {location}") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
import rich_click as click | ||
|
||
help_config = click.RichHelpConfiguration( | ||
use_markdown=True, | ||
width=100, | ||
style_option="bold white", | ||
style_argument="dim cyan", | ||
style_command="bold yellow", | ||
style_errors_suggestion_command="bold magenta", | ||
) |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
import typing as t | ||
|
||
import rich_click as click | ||
from click import ClickException | ||
|
||
from linksmith.settings import help_config | ||
from linksmith.sphinx.core import inventories_to_text, inventory_to_text | ||
|
||
|
||
@click.command() | ||
@click.rich_config(help_config=help_config) | ||
@click.argument("infiles", nargs=-1) | ||
@click.option("--format", "format_", type=str, default="text", help="Output format") | ||
@click.pass_context | ||
def cli(ctx: click.Context, infiles: t.List[str], format_: str): | ||
""" | ||
Decode one or multiple intersphinx inventories and output in different formats. | ||
Use `linksmith output-formats` to learn about available output formats. | ||
Examples: | ||
Refer to `objects.inv` on the local filesystem or on a remote location: | ||
```bash | ||
linksmith inventory /path/to/objects.inv --format=html | ||
linksmith inventory https://linksmith.readthedocs.io/en/latest/objects.inv --format=markdown | ||
``` | ||
Refer to **multiple** `objects.inv` resources: | ||
```bash | ||
linksmith inventory https://github.com/crate/crate-docs/raw/main/registry/sphinx-inventories.txt | ||
``` | ||
""" | ||
if not infiles: | ||
raise click.ClickException("No input") | ||
for infile in infiles: | ||
try: | ||
if infile.endswith(".inv"): | ||
inventory_to_text(infile, format_=format_) | ||
elif infile.endswith(".txt"): | ||
inventories_to_text(infile, format_=format_) | ||
else: | ||
raise NotImplementedError(f"Unknown input file type: {infile}") | ||
except Exception as ex: | ||
if ctx.parent and ctx.parent.params.get("debug"): | ||
raise | ||
raise ClickException(f"{ex.__class__.__name__}: {ex}") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
# ruff: noqa: T201 `print` found | ||
import io | ||
import logging | ||
import typing as t | ||
from pathlib import Path | ||
|
||
import requests | ||
|
||
from linksmith.model import OutputFormat, OutputFormatRegistry, ResourceType | ||
from linksmith.sphinx.inventory import InventoryFormatter | ||
|
||
logger = logging.getLogger(__name__) | ||
|
||
|
||
def inventory_to_text(url: str, format_: str = "text"): | ||
""" | ||
Display intersphinx inventory for individual project, using selected output format. | ||
""" | ||
of = OutputFormatRegistry.resolve(format_) | ||
inventory = InventoryFormatter(url=url) | ||
|
||
if of is OutputFormat.TEXT_INSPECT: | ||
inventory.to_text_inspect() | ||
elif of is OutputFormat.TEXT_PLAIN: | ||
inventory.to_text_plain() | ||
elif of is OutputFormat.RESTRUCTUREDTEXT: | ||
inventory.to_restructuredtext() | ||
elif of in [OutputFormat.MARKDOWN, OutputFormat.MARKDOWN_TABLE]: | ||
inventory.to_markdown(format_) | ||
elif of is OutputFormat.HTML: | ||
inventory.to_html(format_) | ||
elif of is OutputFormat.JSON: | ||
inventory.to_json() | ||
elif of is OutputFormat.YAML: | ||
inventory.to_yaml() | ||
|
||
|
||
def inventories_to_text(urls: t.Union[str, Path, io.IOBase], format_: str = "text"): | ||
""" | ||
Display intersphinx inventories of multiple projects, using selected output format. | ||
""" | ||
if format_.startswith("html"): | ||
print("<!DOCTYPE html>") | ||
print("<html>") | ||
print( | ||
""" | ||
<style> | ||
html, body, table { | ||
font-size: small; | ||
} | ||
</style> | ||
""", | ||
) | ||
print("<body>") | ||
resource_type = ResourceType.detect(urls) | ||
if resource_type is ResourceType.BUFFER: | ||
url_list = t.cast(io.IOBase, urls).read().splitlines() | ||
elif resource_type is ResourceType.PATH: | ||
url_list = Path(t.cast(str, urls)).read_text().splitlines() | ||
# TODO: Test coverage needs to be unlocked by `test_multiple_inventories_url` | ||
elif resource_type is ResourceType.URL: # pragma: nocover | ||
url_list = requests.get(t.cast(str, urls), timeout=10).text.splitlines() | ||
|
||
# Generate header. | ||
if format_.startswith("html"): | ||
print("<h1>Inventory Overview</h1>") | ||
print(f"<p>Source: {urls}</p>") | ||
for url in url_list: | ||
inventory = InventoryFormatter(url=url) | ||
name = inventory.name | ||
print(f"""- <a href="#{name}">{name}</a><br/>""") | ||
|
||
# Generate content. | ||
for url in url_list: | ||
inventory_to_text(url, format_) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,161 @@ | ||
""" | ||
Format content of Sphinx inventories. | ||
Source: | ||
- https://github.com/crate/crate-docs/blob/5a7b02f/tasks.py | ||
- https://github.com/pyveci/pueblo/blob/878a31f94/pueblo/sphinx/inventory.py | ||
""" | ||
|
||
import dataclasses | ||
import io | ||
import logging | ||
import typing as t | ||
from contextlib import redirect_stdout | ||
|
||
import sphobjinv as soi | ||
import tabulate | ||
import yaml | ||
from marko.ext.gfm import gfm as markdown_to_html | ||
from sphinx.application import Sphinx | ||
from sphinx.ext.intersphinx import fetch_inventory, inspect_main | ||
from sphinx.util.typing import InventoryItem | ||
|
||
from linksmith.model import ResourceType | ||
|
||
logger = logging.getLogger(__name__) | ||
|
||
|
||
@dataclasses.dataclass | ||
class InventoryRecord: | ||
""" | ||
Manage details of a single record of a Sphinx inventory. | ||
""" | ||
|
||
type: str | ||
name: str | ||
project: str | ||
version: str | ||
url_path: str | ||
display_name: str | ||
|
||
|
||
InventoryEntries = t.List[t.Tuple[str, InventoryItem]] | ||
|
||
|
||
class InventoryManager: | ||
def __init__(self, location: str): | ||
self.location = location | ||
|
||
def soi_factory(self) -> soi.Inventory: | ||
resource_type = ResourceType.detect(self.location) | ||
if resource_type is ResourceType.PATH: | ||
return soi.Inventory(source=self.location) | ||
elif resource_type is ResourceType.URL: | ||
return soi.Inventory(url=self.location) | ||
else: # pragma: nocover | ||
raise TypeError(f"Unknown inventory type: {self.location}") | ||
|
||
|
||
class InventoryFormatter: | ||
""" | ||
Decode and process intersphinx inventories created by Sphinx. | ||
https://www.sphinx-doc.org/en/master/usage/extensions/intersphinx.html | ||
""" | ||
|
||
def __init__(self, url: str, labels_only: bool = False, omit_documents: bool = False): | ||
self.url = url | ||
self.labels_only = labels_only | ||
self.omit_documents = omit_documents | ||
|
||
self.invman = InventoryManager(location=self.url) | ||
self.soi = self.invman.soi_factory() | ||
self.name = self.soi.project | ||
|
||
def to_text_inspect(self): | ||
inspect_main([self.url]) | ||
|
||
def to_text_plain(self): | ||
print(self.soi.data_file().decode("utf-8")) | ||
|
||
def to_restructuredtext(self): | ||
line = len(self.name) * "#" | ||
print(line) | ||
print(self.name) | ||
print(line) | ||
print("\n".join(sorted(self.soi.objects_rst))) | ||
|
||
# ruff: noqa: T201 `print` found | ||
def to_markdown(self, format_: str = ""): | ||
class MockConfig: | ||
intersphinx_timeout: t.Union[int, None] = None | ||
tls_verify = False | ||
tls_cacerts: t.Union[str, t.Dict[str, str], None] = None | ||
user_agent: str = "" | ||
|
||
class MockApp: | ||
srcdir = "" | ||
config = MockConfig() | ||
|
||
app = t.cast(Sphinx, MockApp()) | ||
inv_data = fetch_inventory(app, "", self.url) | ||
print(f"# {self.name}") | ||
print() | ||
for key in sorted(inv_data or {}): | ||
if self.labels_only and key != "std:label": | ||
continue | ||
if self.omit_documents and key == "std:doc": | ||
continue | ||
print(f"## {key}") | ||
inv_entries = sorted(inv_data[key].items()) | ||
if format_.endswith("+table"): | ||
print(tabulate.tabulate(inv_entries, headers=("Reference", "Inventory Record (raw)"), tablefmt="pipe")) | ||
else: | ||
print("```text") | ||
records = self.decode_entries(key, inv_entries) | ||
for line in self.format_records(records): | ||
print(line) | ||
print("```") | ||
print() | ||
|
||
def to_html(self, format_: str = ""): | ||
""" | ||
Format intersphinx repository using HTML. | ||
TODO: Reference implementation by @webknjaz. | ||
https://webknjaz.github.io/intersphinx-untangled/setuptools.rtfd.io/ | ||
""" | ||
print(f"""<a id="{self.name}"></a>""") | ||
buffer = io.StringIO() | ||
with redirect_stdout(buffer): | ||
self.to_markdown(format_) | ||
buffer.seek(0) | ||
markdown = buffer.read() | ||
html = markdown_to_html(markdown) | ||
print(html) | ||
|
||
def to_json(self): | ||
print(self.soi.json_dict()) | ||
|
||
def to_yaml(self): | ||
logger.warning("There is certainly a better way to present an inventory in YAML format") | ||
print(yaml.dump(self.soi.json_dict())) | ||
|
||
def decode_entries( | ||
self, | ||
reference_type: str, | ||
inv_entries: InventoryEntries, | ||
) -> t.Generator[InventoryRecord, None, None]: | ||
""" | ||
Decode inv_entries, as per `fetch_inventory`. | ||
item: (_proj, _ver, url_path, display_name) | ||
""" | ||
for name, entry in inv_entries: | ||
yield InventoryRecord(reference_type, name, *entry) | ||
|
||
def format_records(self, records: t.Iterable[InventoryRecord]) -> t.Generator[str, None, None]: | ||
yield (f"{'Reference': <40} {'Display Name': <40} {'Path'}") | ||
yield (f"{'---------': <40} {'------------': <40} {'----'}") | ||
for record in records: | ||
display_name_effective = record.display_name * (record.display_name != "-") | ||
yield (f"{record.name: <40} {display_name_effective: <40} {record.url_path}") |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
from enum import Enum | ||
|
||
|
||
class AutoStrEnum(str, Enum): | ||
""" | ||
StrEnum where enum.auto() returns the field name. | ||
See https://docs.python.org/3.9/library/enum.html#using-automatic-values | ||
From https://stackoverflow.com/a/74539097. | ||
""" | ||
|
||
@staticmethod | ||
def _generate_next_value_(name: str, start: int, count: int, last_values: list) -> str: # noqa: ARG004 | ||
return name | ||
|
||
|
||
class AutoStrEnumLCase(str, Enum): # pragma: nocover | ||
""" | ||
From https://stackoverflow.com/a/74539097. | ||
""" | ||
|
||
@staticmethod | ||
def _generate_next_value_(name, start, count, last_values): # noqa: ARG004 | ||
return name.lower() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
tests/assets/linksmith.inv | ||
tests/assets/sde.inv |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
OBJECTS_INV_URL = "https://linksmith.readthedocs.io/en/latest/objects.inv" | ||
OBJECTS_INV_PATH = "tests/assets/linksmith.inv" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
import pytest | ||
from click.testing import CliRunner | ||
|
||
|
||
@pytest.fixture | ||
def cli_runner() -> CliRunner: | ||
return CliRunner() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
import pytest | ||
|
||
from linksmith.cli import cli | ||
from tests.config import OBJECTS_INV_PATH, OBJECTS_INV_URL | ||
|
||
|
||
def test_cli_version(cli_runner): | ||
""" | ||
CLI test: Invoke `linksmith --version`. | ||
""" | ||
result = cli_runner.invoke( | ||
cli, | ||
args="--version", | ||
catch_exceptions=False, | ||
) | ||
assert result.exit_code == 0 | ||
|
||
|
||
def test_cli_output_formats(cli_runner): | ||
""" | ||
CLI test: Invoke `linksmith output-formats`. | ||
""" | ||
result = cli_runner.invoke( | ||
cli, | ||
args="output-formats", | ||
catch_exceptions=False, | ||
) | ||
assert result.exit_code == 0 | ||
|
||
|
||
def test_cli_inventory_no_input(cli_runner): | ||
""" | ||
CLI test: Invoke `linksmith inventory`. | ||
""" | ||
result = cli_runner.invoke( | ||
cli, | ||
args="inventory", | ||
catch_exceptions=False, | ||
) | ||
assert result.exit_code == 1 | ||
assert "No input" in result.output | ||
|
||
|
||
def test_cli_inventory_unknown_input(cli_runner): | ||
""" | ||
CLI test: Invoke `linksmith inventory example.foo`. | ||
""" | ||
result = cli_runner.invoke( | ||
cli, | ||
args="inventory example.foo", | ||
catch_exceptions=False, | ||
) | ||
assert result.exit_code == 1 | ||
assert "Unknown input file type: example.foo" in result.output | ||
|
||
|
||
def test_cli_inventory_unknown_input_with_debug(cli_runner): | ||
""" | ||
CLI test: Invoke `linksmith inventory example.foo`. | ||
""" | ||
with pytest.raises(NotImplementedError) as ex: | ||
cli_runner.invoke( | ||
cli, | ||
args="--debug inventory example.foo", | ||
catch_exceptions=False, | ||
) | ||
assert ex.match("Unknown input file type: example.foo") | ||
|
||
|
||
def test_cli_single_inventory_path(cli_runner): | ||
""" | ||
CLI test: Invoke `linksmith inventory tests/assets/linksmith.inv --format=text`. | ||
""" | ||
result = cli_runner.invoke( | ||
cli, | ||
args=f"inventory {OBJECTS_INV_PATH} --format=text", | ||
catch_exceptions=False, | ||
) | ||
assert result.exit_code == 0 | ||
|
||
|
||
def test_cli_single_inventory_url(cli_runner): | ||
""" | ||
CLI test: Invoke `linksmith inventory https://linksmith.readthedocs.io/en/latest/objects.inv --format=text`. | ||
""" | ||
result = cli_runner.invoke( | ||
cli, | ||
args=f"inventory {OBJECTS_INV_URL} --format=text", | ||
catch_exceptions=False, | ||
) | ||
assert result.exit_code == 0 | ||
|
||
|
||
def test_cli_multiple_inventories_path(cli_runner): | ||
""" | ||
CLI test: Invoke `linksmith inventory tests/assets/index.txt --format=text`. | ||
""" | ||
result = cli_runner.invoke( | ||
cli, | ||
args="inventory tests/assets/index.txt --format=text", | ||
catch_exceptions=False, | ||
) | ||
assert result.exit_code == 0 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
import io | ||
|
||
import pytest | ||
|
||
from linksmith.model import OutputFormatRegistry | ||
from linksmith.sphinx.core import inventories_to_text, inventory_to_text | ||
from tests.config import OBJECTS_INV_PATH, OBJECTS_INV_URL | ||
|
||
|
||
@pytest.mark.parametrize("format_", OutputFormatRegistry.aliases()) | ||
def test_single_inventory_path(format_: str): | ||
inventory_to_text(OBJECTS_INV_PATH, format_) | ||
|
||
|
||
@pytest.mark.parametrize("format_", OutputFormatRegistry.aliases()) | ||
def test_single_inventory_url(format_: str): | ||
inventory_to_text(OBJECTS_INV_URL, format_) | ||
|
||
|
||
@pytest.mark.parametrize("format_", OutputFormatRegistry.aliases()) | ||
def test_multiple_inventories_path(format_: str): | ||
inventories_to_text("tests/assets/index.txt", format_) | ||
|
||
|
||
@pytest.mark.parametrize("format_", OutputFormatRegistry.aliases()) | ||
def test_multiple_inventories_buffer(format_: str): | ||
urls = io.StringIO( | ||
""" | ||
tests/assets/linksmith.inv | ||
tests/assets/sde.inv | ||
""".strip(), | ||
) | ||
inventories_to_text(urls, format_) | ||
|
||
|
||
@pytest.mark.skip("Does not work yet") | ||
def test_multiple_inventories_url(): | ||
url = "https://github.com/tech-writing/linksmith/raw/main/tests/assets/index.txt" | ||
inventories_to_text(url, "html") | ||
|
||
|
||
def test_unknown_output_format(): | ||
with pytest.raises(NotImplementedError) as ex: | ||
inventory_to_text(OBJECTS_INV_PATH, "foo-format") | ||
ex.match("Output format not implemented: foo-format") | ||
|
||
|
||
def test_unknown_input_format_single(): | ||
with pytest.raises(NotImplementedError) as ex: | ||
inventory_to_text("foo.bar", "text") | ||
ex.match("Resource type not implemented: foo.bar") | ||
|
||
|
||
def test_unknown_input_format_multiple(): | ||
with pytest.raises(NotImplementedError) as ex: | ||
inventories_to_text("foo.bar", "text") | ||
ex.match("Resource type not implemented: foo.bar") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
import pytest | ||
|
||
from linksmith.sphinx.inventory import InventoryFormatter, InventoryManager | ||
from tests.config import OBJECTS_INV_PATH | ||
|
||
|
||
def test_inventory_labels_only(capsys): | ||
inventory = InventoryFormatter(url=OBJECTS_INV_PATH, labels_only=True) | ||
inventory.to_markdown() | ||
out, err = capsys.readouterr() | ||
assert "std:label" in out | ||
assert "std:doc" not in out | ||
|
||
|
||
def test_inventory_omit_documents(capsys): | ||
inventory = InventoryFormatter(url=OBJECTS_INV_PATH, omit_documents=True) | ||
inventory.to_markdown() | ||
out, err = capsys.readouterr() | ||
assert "std:label" in out | ||
assert "std:doc" not in out | ||
|
||
|
||
def test_inventory_manager_unknown(): | ||
invman = InventoryManager("foo") | ||
with pytest.raises(NotImplementedError) as ex: | ||
invman.soi_factory() | ||
assert ex.match("Resource type not implemented: foo") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
import io | ||
|
||
import pytest | ||
|
||
from linksmith.model import OutputFormat, OutputFormatRegistry, ResourceType | ||
|
||
|
||
def test_output_format_success(): | ||
assert OutputFormatRegistry.resolve("text") is OutputFormat.TEXT_INSPECT | ||
|
||
|
||
def test_output_format_unknown(): | ||
with pytest.raises(NotImplementedError) as ex: | ||
OutputFormatRegistry.resolve("foo-format") | ||
assert ex.match("Output format not implemented: foo-format") | ||
|
||
|
||
def test_resource_type_path(): | ||
assert ResourceType.detect("README.md") is ResourceType.PATH | ||
|
||
|
||
def test_resource_type_url(): | ||
assert ResourceType.detect("http://example.org") is ResourceType.URL | ||
|
||
|
||
def test_resource_type_buffer(): | ||
buffer = io.StringIO("http://example.org") | ||
assert ResourceType.detect(buffer) is ResourceType.BUFFER | ||
|
||
|
||
def test_resource_type_unknown(): | ||
with pytest.raises(NotImplementedError) as ex: | ||
ResourceType.detect("foobar") | ||
assert ex.match("Resource type not implemented: foobar") |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Check out bskinn/sphobjinv#283 -- @machow proposed a better JSON output format that might(?) make for more attractive YAML.
I need to actually implement that...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you very much. I knew you would have excellent suggestions about it. 💯
I merged this PR early, to get something working into
main
before going afk, but that does not mean I will not consider any other suggestions here, also in retrospective. Thanks!