Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
22ececf
Add lazy console-script entry for pyld that defers CLI imports
anatoly-scherbakov Jul 26, 2026
23f9a4c
Add pyld CLI for get, expand, and cache clear
anatoly-scherbakov Jul 26, 2026
00e6a06
Add tests for the pyld command-line interface
anatoly-scherbakov Jul 26, 2026
14cacf9
Register pyld console script and `[cli]` extra
anatoly-scherbakov Jul 26, 2026
25df926
Add Typer for CLI tests
anatoly-scherbakov Jul 26, 2026
18dc5ff
Adjust RUFF_TARGET for CLI modules if needed
anatoly-scherbakov Jul 26, 2026
be23ace
Document the pyld command-line interface in the README
anatoly-scherbakov Jul 26, 2026
8a599b9
Document installing PyLD with the `[cli]` extra
anatoly-scherbakov Jul 26, 2026
b0e47d2
Add CLI docs index page
anatoly-scherbakov Jul 26, 2026
266b446
Document `pyld get`
anatoly-scherbakov Jul 26, 2026
da76bc0
Document `pyld expand`
anatoly-scherbakov Jul 26, 2026
657a2ef
Document `pyld cache clear`
anatoly-scherbakov Jul 26, 2026
387804b
Order CLI documentation pages
anatoly-scherbakov Jul 26, 2026
0bf53b7
Add CLI section to docs navigation
anatoly-scherbakov Jul 26, 2026
58b66c7
Link the CLI from the docs home page
anatoly-scherbakov Jul 26, 2026
f3681fa
Link the CLI from the project docs index
anatoly-scherbakov Jul 26, 2026
52df6cf
Link the CLI from the reference index
anatoly-scherbakov Jul 26, 2026
78ead62
Add termynal for CLI docs examples
anatoly-scherbakov Jul 26, 2026
f73cfbb
Style CLI terminal examples
anatoly-scherbakov Jul 26, 2026
9a2bbfa
Add terminal() macro for runnable CLI docs examples
anatoly-scherbakov Jul 26, 2026
39f8ca2
Enable termynal plugin and CLI docs wiring
anatoly-scherbakov Jul 26, 2026
5144dd6
Prefer the running docs-serve instance for browser checks
anatoly-scherbakov Jul 26, 2026
7db97dd
Note the pyld CLI in the unreleased changelog
anatoly-scherbakov Jul 26, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ Read [CONTRIBUTING.md](CONTRIBUTING.md) for code style, linting (e.g. `make lint
### Documentation validation

- **No in-repo Playwright.** Do not add `@playwright/test`, `playwright.config.js`, or e2e test dependencies. Live browser checks use **only** the Playwright MCP server (`user-playwright`).
- After doc changes, run `make docs-build` (strict). For interactive checks, run `make docs-serve` and validate with Playwright MCP: `browser_navigate`, `browser_snapshot`, `browser_click`, `browser_wait_for`. Prefer `browser_run_code_unsafe` with `page.screenshot({ animations: 'disabled', timeout: 60000 })` over `browser_take_screenshot` (font load timeouts).
- **Never start a second dev server.** Before any browser check, grep the terminals folder for a running `make docs-serve` / `mkdocs serve` (look for `active_command`) and use that one — it serves http://127.0.0.1:8000/pyld/. Only start a server if none is running.
- After doc changes, run `make docs-build` (strict). For interactive checks, validate against the running `make docs-serve` with Playwright MCP: `browser_navigate`, `browser_snapshot`, `browser_click`, `browser_wait_for`. Prefer `browser_run_code_unsafe` with `page.screenshot({ animations: 'disabled', timeout: 60000 })` over `browser_take_screenshot` (font load timeouts).

## Committing

Expand Down
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@
strings to per-scheme loaders.
- `pyld.ChoiceByTypeDocumentLoader`: a document loader that dispatches by Python
input type (e.g. `pathlib.Path` vs `str`).
- `pyld` command-line tool (`get`, `expand`, `cache clear`), installed via
`pip install "PyLD[cli]"`, with remote contexts cached in a CLI-specific
SQLite file (overridable via `--cache-file` / `PYLD_CACHE_FILE`).

### Changed
- `SqliteCacheRequestsDocumentLoader` creates the SQLite cache file on first document load, not at construction time.
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ test:

docs-install:
python -m pip install --upgrade pip
pip install -e .
pip install -e ".[cli]"
pip install -r docs/requirements.txt

docs-build:
Expand Down
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,18 @@ Defining a dependency on pyld will not pull in
[Document Loader](#document-loader) then either depend on the desired external library directly
or define the requirement as `PyLD[requests]` or `PyLD[aiohttp]`.

## Command line

Install the optional CLI extra to get a `pyld` console script:

```bash
pip install "PyLD[cli]"
pyld expand document.jsonld
pyld expand https://example.com/doc.jsonld
```

See the [CLI documentation](https://digitalbazaar.github.io/pyld/cli/).

## Usage

Here are some quick examples to get started:
Expand Down
4 changes: 3 additions & 1 deletion docs/.pages
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ nav:
- index.md
- installation.md
- conformance.md
- Reference:
- API:
- reference
- CLI:
- cli
- Project:
- project
5 changes: 5 additions & 0 deletions docs/cli/.pages
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
nav:
- index.md
- get.md
- expand.md
- cache.md
30 changes: 30 additions & 0 deletions docs/cli/cache.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
---
hide: [toc]
---

# :material-cached: `pyld cache`

!!! warning "Requires `pip install PyLD[cli]`"

Clear the HTTP cache for remote JSON-LD contexts fetched by the CLI.

The cache file lives in a `cli/` subdirectory of the platform user cache
directory documented for
[`SqliteCacheRequestsDocumentLoader`](../reference/document-loaders/sqlite-cache-requests.md).

Override the location with `--cache-file` or the `PYLD_CACHE_FILE` environment
variable (`--cache-file` wins when both are set):

{{ terminal('pyld --cache-file /tmp/pyld-cache.sqlite cache clear') }}

::: mkdocs-typer2
:module: pyld.cli
:name: pyld
:command: cache
:termynal: true
:width: 88
:subcommands: 1

## Clear the cache

{{ terminal('pyld cache clear') }}
26 changes: 26 additions & 0 deletions docs/cli/expand.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
---
hide: [toc]
---

# :material-arrow-expand: `pyld expand`

!!! warning "Requires `pip install PyLD[cli]`"

Expand a JSON-LD document.

::: mkdocs-typer2
:module: pyld.cli
:name: pyld
:command: expand
:termynal: true
:width: 88

## Example

=== "Example"

{{ terminal('pyld expand docs/examples/data/person.jsonld', indent=4) }}

=== "person.jsonld"

{{ example_data('data/person.jsonld', indent=4) }}
26 changes: 26 additions & 0 deletions docs/cli/get.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
---
hide: [toc]
---

# :material-download: `pyld get`

!!! warning "Requires `pip install PyLD[cli]`"

Retrieve and print a JSON-LD document.

::: mkdocs-typer2
:module: pyld.cli
:name: pyld
:command: get
:termynal: true
:width: 88

## Example

=== "Example"

{{ terminal('pyld get docs/examples/data/person.jsonld', indent=4) }}

=== "person.jsonld"

{{ example_data('data/person.jsonld', indent=4) }}
32 changes: 32 additions & 0 deletions docs/cli/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
---
hide: [toc]
icon: material/console
---

# :material-console: CLI

!!! warning "Requires `pip install PyLD[cli]`"

PyLD ships a `pyld` command-line tool for JSON-LD transformations.

<div class="grid cards" markdown>

- [:material-download:{ .lg .middle } `pyld get`](get.md)

---

Retrieve a JSON-LD document from a path, URL, or stdin.

- [:material-arrow-expand:{ .lg .middle } `pyld expand`](expand.md)

---

Expand a JSON-LD document into full IRI-based form.

- [:material-cached:{ .lg .middle } `pyld cache`](cache.md)

---

Manage the CLI HTTP cache for remote JSON-LD contexts.

</div>
1 change: 1 addition & 0 deletions docs/index.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
---
hide: [toc]
icon: material/rocket-launch
---

# :material-graph-outline: PyLD
Expand Down
5 changes: 5 additions & 0 deletions docs/installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,13 @@ matching extra:
pip install "PyLD[requests]"
pip install "PyLD[aiohttp]"
pip install "PyLD[requests-cache]"
pip install "PyLD[cli]"
```

`PyLD[cli]` installs [:simple-typer: Typer](https://typer.tiangolo.com/) and
[:simple-pypi: `requests-cache`](https://pypi.org/project/requests-cache/), and
registers the [`pyld`](cli/index.md) console script.

You can also depend on `requests` or `aiohttp` directly if your project already
manages those dependencies.

Expand Down
1 change: 1 addition & 0 deletions docs/project/index.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
---
hide: [toc]
icon: material/hard-hat
---

# :material-hard-hat: Project
Expand Down
7 changes: 7 additions & 0 deletions docs/reference/index.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
---
hide: [toc]
icon: octicons/book-24
---

# :octicons-book-24: Reference
Expand Down Expand Up @@ -67,6 +68,12 @@ hide: [toc]

Load remote JSON-LD documents and contexts with the built-in loader classes.

- [:material-console:{ .lg .middle } __CLI__](../cli/index.md)

---

Transform JSON-LD from the command line.

- :material-hard-hat:{ .lg .middle } __In construction__

---
Expand Down
1 change: 1 addition & 0 deletions docs/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ mkdocs-macros-plugin==1.5.0
mkdocs-awesome-pages-plugin==2.10.1
mkdocstrings[python]>=0.30
requests-cache>=1.3
mkdocs-typer2[mkdocs,termynal]==0.4.1
6 changes: 6 additions & 0 deletions docs/stylesheets/extra.css
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,12 @@
display: flow-root;
}

/* termynal.css leaves `.termy` without margins, so a terminal window sits flush
against the next one; mkdocs-typer2 only spaces its own stacked blocks. */
.md-typeset .termy {
margin-bottom: 1.25em;
}

/* ADR comparison column tints — match mkdocs-material admonition hues at 10%. */
:root,
[data-md-color-scheme="slate"] {
Expand Down
38 changes: 36 additions & 2 deletions docs_macros.py
Original file line number Diff line number Diff line change
Expand Up @@ -345,8 +345,8 @@ def example_data(name, indent=0):
path = _example_path(name)
source = path.read_text().rstrip('\n')
suffix = path.suffix.lower()
lang = 'json' if suffix in {'.json', '.jsonld'} else (
suffix.lstrip('.') or 'text'
lang = (
'json' if suffix in {'.json', '.jsonld'} else (suffix.lstrip('.') or 'text')
)
github_url = _example_github_url(name, env.conf['repo_url'])
title = (
Expand All @@ -359,3 +359,37 @@ def example_data(name, indent=0):
pad = ' ' * content_indent
indented = '\n'.join(f'{pad}{line}' for line in body.splitlines())
return f'!!! example "{title}"\n\n{indented}\n'

@env.macro
def terminal(command, title='pyld', indent=0):
"""Run a shell command and embed it as a termynal terminal block."""
# Prefer this project's console scripts over another `pyld` on PATH
# (for example the yaml-ld package). Do not resolve symlinks: the venv
# python often points at a shared interpreter whose bin/ has no pyld.
venv_bin = str(Path(sys.executable).parent)
path = os.environ.get('PATH', '')
result = subprocess.run(
['bash', '-c', command],
capture_output=True,
text=True,
check=True,
cwd=ROOT_DIR,
env={
**os.environ,
'TERM': 'dumb',
'PATH': f'{venv_bin}:{path}',
},
)
# The termynal plugin converts a fence preceded by this comment, reading
# `$ ` lines as typed input and the rest as output.
config = json.dumps({'title': title})
body = f'<!-- termynal: {config} -->\n\n```\n$ {command}\n{result.stdout}```'
if not indent:
return body
# First line inherits the call-site indent (same pattern as example /
# example_data); remaining lines need explicit padding for tab nesting.
pad = ' ' * indent
lines = body.splitlines()
return lines[0] + '\n' + '\n'.join(
f'{pad}{line}' if line else line for line in lines[1:]
)
Loading
Loading