is one of
- echo. html to make standalone HTML files
- echo. dirhtml to make HTML files named index.html in directories
- echo. singlehtml to make a single large HTML file
- echo. pickle to make pickle files
- echo. json to make JSON files
- echo. htmlhelp to make HTML files and a HTML help project
- echo. qthelp to make HTML files and a qthelp project
- echo. devhelp to make HTML files and a Devhelp project
- echo. epub to make an epub
- echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter
- echo. text to make text files
- echo. man to make manual pages
- echo. changes to make an overview over all changed/added/deprecated items
- echo. linkcheck to check all external links for integrity
- echo. doctest to run all doctests embedded in the documentation if enabled
- goto end
-)
-
-if "%1" == "clean" (
- for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i
- del /q /s %BUILDDIR%\*
- goto end
-)
-
-if "%1" == "html" (
- %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished. The HTML pages are in %BUILDDIR%/html.
- goto end
-)
-
-if "%1" == "dirhtml" (
- %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.
- goto end
-)
-
-if "%1" == "singlehtml" (
- %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml.
- goto end
-)
-
-if "%1" == "pickle" (
- %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished; now you can process the pickle files.
- goto end
-)
-
-if "%1" == "json" (
- %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished; now you can process the JSON files.
- goto end
-)
-
-if "%1" == "htmlhelp" (
- %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished; now you can run HTML Help Workshop with the ^
-.hhp project file in %BUILDDIR%/htmlhelp.
- goto end
-)
-
-if "%1" == "qthelp" (
- %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished; now you can run "qcollectiongenerator" with the ^
-.qhcp project file in %BUILDDIR%/qthelp, like this:
- echo.^> qcollectiongenerator %BUILDDIR%\qthelp\PyLD.qhcp
- echo.To view the help file:
- echo.^> assistant -collectionFile %BUILDDIR%\qthelp\PyLD.ghc
- goto end
-)
-
-if "%1" == "devhelp" (
- %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished.
- goto end
-)
-
-if "%1" == "epub" (
- %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished. The epub file is in %BUILDDIR%/epub.
- goto end
-)
-
-if "%1" == "latex" (
- %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.
- goto end
-)
-
-if "%1" == "text" (
- %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished. The text files are in %BUILDDIR%/text.
- goto end
-)
-
-if "%1" == "man" (
- %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished. The manual pages are in %BUILDDIR%/man.
- goto end
-)
-
-if "%1" == "changes" (
- %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes
- if errorlevel 1 exit /b 1
- echo.
- echo.The overview file is in %BUILDDIR%/changes.
- goto end
-)
-
-if "%1" == "linkcheck" (
- %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck
- if errorlevel 1 exit /b 1
- echo.
- echo.Link check complete; look for any errors in the above output ^
-or in %BUILDDIR%/linkcheck/output.txt.
- goto end
-)
-
-if "%1" == "doctest" (
- %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest
- if errorlevel 1 exit /b 1
- echo.
- echo.Testing of doctests in the sources finished, look at the ^
-results in %BUILDDIR%/doctest/output.txt.
- goto end
-)
-
-:end
diff --git a/docs/reference/document-loaders/aiohttp.md b/docs/reference/document-loaders/aiohttp.md
new file mode 100644
index 00000000..9a7a7f86
--- /dev/null
+++ b/docs/reference/document-loaders/aiohttp.md
@@ -0,0 +1,22 @@
+# :material-sync: `AioHttpDocumentLoader`
+
+`AioHttpDocumentLoader` retrieves JSON-LD documents with `aiohttp`.
+
+{{ example('document_loaders/aiohttp_class.py', output_syntax='json') }}
+
+This loader uses asynchronous fetching internally, but JSON-LD processing itself
+remains synchronous.
+
+Use `secure=True` to require HTTPS URLs:
+
+{{ example('document_loaders/aiohttp_secure.py', output_syntax='json') }}
+
+Extra keyword arguments are forwarded to `aiohttp` request calls:
+
+{{ example('document_loaders/aiohttp_extra_kwargs.py', output_syntax='json') }}
+
+Install the optional dependency with:
+
+```bash
+pip install "PyLD[aiohttp]"
+```
diff --git a/docs/reference/document-loaders/custom.md b/docs/reference/document-loaders/custom.md
new file mode 100644
index 00000000..e0b7c940
--- /dev/null
+++ b/docs/reference/document-loaders/custom.md
@@ -0,0 +1,8 @@
+# :material-code-braces: Custom Document Loaders
+
+Subclass `DocumentLoader` and implement `__call__` to return a remote document
+mapping with `contentType`, `contextUrl`, `documentUrl`, and `document` keys.
+Custom schemes such as `context://` cannot be fetched over HTTP, so a custom
+loader is required to resolve them.
+
+{{ example('document_loaders/custom_document_loader.py', output_syntax='json') }}
diff --git a/docs/reference/document-loaders/frozen.md b/docs/reference/document-loaders/frozen.md
new file mode 100644
index 00000000..c22012c6
--- /dev/null
+++ b/docs/reference/document-loaders/frozen.md
@@ -0,0 +1,24 @@
+# :material-snowflake: `FrozenDocumentLoader`
+
+`FrozenDocumentLoader` serves only URLs in an allowlist and refuses all other
+document loads. It is intended for air-gapped runs, reproducible builds, and
+deployments that must avoid remote context fetching.
+
+With no arguments, the loader serves the curated `BUNDLED_CONTEXTS` mapping:
+
+{{ example('document_loaders/frozen_default.py', output_syntax='json') }}
+
+## Bundled Contexts
+
+{{ bundled_contexts_table() }}
+
+Extend the bundled mapping with additional vetted contexts:
+
+{{ example('document_loaders/frozen_extend.py', output_syntax='json') }}
+
+The `documents` mapping may contain parsed JSON-LD dictionaries or
+`pathlib.Path` instances pointing to JSON files. Path entries are read lazily
+and cached after the first request.
+
+Any URL outside the allowlist raises `JsonLdError` with code
+`loading document failed`.
diff --git a/docs/reference/document-loaders/index.md b/docs/reference/document-loaders/index.md
new file mode 100644
index 00000000..c784d2bc
--- /dev/null
+++ b/docs/reference/document-loaders/index.md
@@ -0,0 +1,41 @@
+# :material-file-download-outline: Document Loaders
+
+Document loaders retrieve remote JSON-LD documents and contexts. PyLD ships
+class-based loaders for common cases and supports custom subclasses of
+`DocumentLoader`.
+
+
+
+- [:material-cloud-download:{ .lg .middle } `RequestsDocumentLoader`](requests.md)
+
+ ---
+
+ Synchronous remote document loading with `requests`.
+
+- [:material-sync:{ .lg .middle } `AioHttpDocumentLoader`](aiohttp.md)
+
+ ---
+
+ Asynchronous fetching with `aiohttp` while JSON-LD processing stays
+ synchronous.
+
+- [:material-snowflake:{ .lg .middle } `FrozenDocumentLoader`](frozen.md)
+
+ ---
+
+ Serve only documents from an allowlist for air-gapped or reproducible runs.
+
+- [:material-code-braces:{ .lg .middle } __Custom Document Loaders__](custom.md)
+
+ ---
+
+ Subclass `DocumentLoader` for application-specific loading logic.
+
+
+
+## Default Document Loader
+
+The default document loader is selected at import time. PyLD uses
+`RequestsDocumentLoader` if `requests` is available, falls back to
+`AioHttpDocumentLoader` if `aiohttp` is available, and otherwise installs a
+dummy loader that raises when invoked.
diff --git a/docs/reference/document-loaders/requests.md b/docs/reference/document-loaders/requests.md
new file mode 100644
index 00000000..11c2f6b6
--- /dev/null
+++ b/docs/reference/document-loaders/requests.md
@@ -0,0 +1,22 @@
+# :material-cloud-download: `RequestsDocumentLoader`
+
+`RequestsDocumentLoader` retrieves JSON-LD documents with `requests`.
+
+The default remote document loader uses `requests` when it is available.
+Production applications should usually set at least a timeout:
+
+{{ example('document_loaders/requests_timeout.py', output_syntax='json') }}
+
+Use `secure=True` to require HTTPS URLs:
+
+{{ example('document_loaders/requests_secure.py', output_syntax='json') }}
+
+Extra keyword arguments are forwarded to `requests.get()`:
+
+{{ example('document_loaders/requests_extra_kwargs.py', output_syntax='json') }}
+
+Install the optional dependency with:
+
+```bash
+pip install "PyLD[requests]"
+```
diff --git a/docs/reference/index.md b/docs/reference/index.md
new file mode 100644
index 00000000..bc376b99
--- /dev/null
+++ b/docs/reference/index.md
@@ -0,0 +1,21 @@
+---
+hide: [toc]
+---
+
+# :octicons-book-24: Reference
+
+
+
+- [:material-file-download-outline:{ .lg .middle } __Document Loaders__](document-loaders/)
+
+ ---
+
+ Load remote JSON-LD documents and contexts with the built-in loader classes.
+
+- :material-hard-hat:{ .lg .middle } __In construction__
+
+ ---
+
+ We are working on more reference documentation. It is coming soon.
+
+
diff --git a/docs/requirements.txt b/docs/requirements.txt
index 231419d2..f2391f32 100644
--- a/docs/requirements.txt
+++ b/docs/requirements.txt
@@ -1 +1,5 @@
-sphinx-autobuild
+-r ../requirements.txt
+typing_extensions
+mkdocs-material==9.7.6
+mkdocs-macros-plugin==1.5.0
+mkdocs-awesome-pages-plugin==2.10.1
diff --git a/docs/stylesheets/extra.css b/docs/stylesheets/extra.css
new file mode 100644
index 00000000..562e6bbd
--- /dev/null
+++ b/docs/stylesheets/extra.css
@@ -0,0 +1,51 @@
+.md-typeset .grid.cards.maintainers li {
+ display: grid;
+ grid-template-columns: auto 1fr;
+ grid-template-rows: auto auto;
+ align-items: center;
+ column-gap: 1rem;
+ row-gap: 0.25rem;
+}
+
+.md-typeset .grid.cards.maintainers li > p:first-child {
+ grid-row: 1 / span 2;
+ grid-column: 1;
+ margin: 0;
+}
+
+.md-typeset .grid.cards.maintainers li > p:first-child img {
+ width: 4rem;
+ height: 4rem;
+ border-radius: 50%;
+ display: block;
+}
+
+.md-typeset .grid.cards.maintainers li > hr {
+ display: none;
+}
+
+.md-typeset .grid.cards.maintainers li > p:nth-child(2),
+.md-typeset .grid.cards.maintainers li > p:last-child {
+ grid-column: 2;
+ margin: 0;
+}
+
+.md-typeset .grid.cards.maintainers li > p:nth-child(2) {
+ grid-row: 1;
+}
+
+.md-typeset .grid.cards.maintainers li > p:last-child {
+ grid-row: 2;
+}
+
+.md-typeset .admonition.example > .admonition-title {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ gap: 1rem;
+}
+
+.md-typeset .admonition.example > .admonition-title .example-source-link {
+ margin-left: auto;
+ font-weight: normal;
+}
diff --git a/docs_macros.py b/docs_macros.py
new file mode 100644
index 00000000..be94b563
--- /dev/null
+++ b/docs_macros.py
@@ -0,0 +1,138 @@
+import os
+import re
+import subprocess
+import sys
+from pathlib import Path
+
+ROOT_DIR = Path(__file__).resolve().parent
+EXAMPLES_DIR = ROOT_DIR / 'docs' / 'examples'
+sys.path.insert(0, str(ROOT_DIR / 'lib'))
+sys.path.insert(0, str(ROOT_DIR / 'tests'))
+
+MANIFEST_BASES = {
+ 'frame-manifest': 'https://w3c.github.io/json-ld-framing/tests',
+ 'manifest-urgna2012': 'https://w3c.github.io/rdf-canon/tests',
+ 'manifest-urdna2015': 'https://w3c.github.io/rdf-canon/tests',
+}
+DEFAULT_TEST_BASE = 'https://w3c.github.io/json-ld-api/tests'
+
+_SKIP_ID_PATTERN = re.compile(r'^\.\*(?P[^#]+)#(?P[^$]+)\$$')
+
+
+def _parse_skip_id_regex(pattern):
+ match = _SKIP_ID_PATTERN.fullmatch(pattern)
+ if not match:
+ return None
+ return match.group('manifest'), match.group('test_id')
+
+
+def _test_url(manifest, test_id):
+ base = MANIFEST_BASES.get(manifest, DEFAULT_TEST_BASE)
+ return f'{base}/{manifest}#{test_id}'
+
+
+def _example_path(name):
+ path = (EXAMPLES_DIR / name).resolve()
+ if not path.is_relative_to(EXAMPLES_DIR.resolve()):
+ raise ValueError(f'Invalid example path: {name}')
+ return path
+
+
+def _github_branch():
+ branch = os.environ.get('GITHUB_REF_NAME')
+ if branch:
+ return branch
+ result = subprocess.run(
+ ['git', 'symbolic-ref', '--short', 'HEAD'],
+ capture_output=True,
+ text=True,
+ cwd=ROOT_DIR,
+ )
+ if result.returncode == 0 and result.stdout.strip():
+ return result.stdout.strip()
+ return 'master'
+
+
+def _example_github_url(name, repo_url):
+ rel_path = Path('docs/examples') / name
+ branch = 'master'
+ return f'{repo_url.rstrip("/")}/blob/{branch}/{rel_path.as_posix()}'
+
+
+def define_env(env):
+ @env.macro
+ def bundled_contexts_table():
+ from pyld import BUNDLED_CONTEXTS
+
+ rows = [
+ '| Context URL | Bundled file |',
+ '| --- | --- |',
+ ]
+ for url, path in sorted(BUNDLED_CONTEXTS.items()):
+ rows.append(f'| `{url}` | `{Path(path).name}` |')
+ return '\n'.join(rows)
+
+ @env.macro
+ def skipped_tests_table():
+ from runtests import TEST_TYPES
+
+ rows = [
+ '| Reason | Skipped tests |',
+ '| --- | --- |',
+ ]
+
+ linked_tests = []
+ seen_tests = set()
+ for test_type, config in sorted(TEST_TYPES.items()):
+ skip = config.get('skip', {})
+ spec_versions = skip.get('specVersion', [])
+ if 'json-ld-1.0' in spec_versions:
+ rows.append(
+ f'| JSON-LD 1.0 processor behavior (`{test_type}`) | '
+ f'All JSON-LD 1.0 tests |'
+ )
+
+ for pattern in skip.get('idRegex', []):
+ parsed = _parse_skip_id_regex(pattern)
+ if not parsed:
+ continue
+ manifest, test_id = parsed
+ url = _test_url(manifest, test_id)
+ if url in seen_tests:
+ continue
+ seen_tests.add(url)
+ linked_tests.append(f'[{test_id}]({url})')
+
+ if linked_tests:
+ rows.append(
+ '| Explicitly skipped test cases | ' + ', '.join(linked_tests) + ' |'
+ )
+
+ return '\n'.join(rows)
+
+ @env.macro
+ def example(name, output_syntax=None):
+ path = _example_path(name)
+ source = path.read_text()
+ result = subprocess.run(
+ [sys.executable, str(path)],
+ capture_output=True,
+ text=True,
+ check=True,
+ cwd=ROOT_DIR,
+ env={**os.environ, 'PYTHONPATH': str(ROOT_DIR / 'lib')},
+ )
+ github_url = _example_github_url(name, env.conf['repo_url'])
+ display_name = path.name
+ title = (
+ f'Example'
+ f':fontawesome-brands-github: [`{display_name}`]({github_url})'
+ f''
+ )
+ output_lang = output_syntax or 'console'
+ body = (
+ f'```python\n{source}```\n\n'
+ f'```{output_lang} title="Output"\n{result.stdout}```'
+ )
+ indented = '\n'.join(f' {line}' for line in body.splitlines())
+ return f'!!! example "{title}"\n\n{indented}\n'
diff --git a/lib/pyld/context_resolver.py b/lib/pyld/context_resolver.py
index 9b8d2c93..d479bb1f 100644
--- a/lib/pyld/context_resolver.py
+++ b/lib/pyld/context_resolver.py
@@ -24,7 +24,9 @@ class ContextResolver:
Resolves and caches remote contexts.
"""
- def __init__(self, shared_cache, document_loader, max_context_urls: int = MAX_CONTEXT_URLS):
+ def __init__(
+ self, shared_cache, document_loader, max_context_urls: int = MAX_CONTEXT_URLS
+ ):
"""
Creates a ContextResolver.
diff --git a/lib/pyld/jsonld.py b/lib/pyld/jsonld.py
index a60fcd36..e603d001 100644
--- a/lib/pyld/jsonld.py
+++ b/lib/pyld/jsonld.py
@@ -1280,7 +1280,11 @@ def get_values(subject, property):
:return: all of the values for a subject's property as an array.
"""
- return JsonLdProcessor.arrayify(subject.get(property)) if property in subject else []
+ return (
+ JsonLdProcessor.arrayify(subject.get(property))
+ if property in subject
+ else []
+ )
@staticmethod
def remove_property(subject, property):
@@ -1515,7 +1519,11 @@ def _compact(self, active_ctx, active_property, element, options):
rval = self._compact_value(
active_ctx, active_property, element, options
)
- if isinstance(options['link'], dict) and options['link'] and _is_subject_reference(element):
+ if (
+ isinstance(options['link'], dict)
+ and options['link']
+ and _is_subject_reference(element)
+ ):
# store linked element
options['link'].setdefault(element['@id'], []).append(
{'expanded': element, 'compacted': rval}
@@ -1960,9 +1968,13 @@ def _compact(self, active_ctx, active_property, element, options):
type_key = self._compact_iri(active_ctx, '@type')
# Only object items can carry an embedded @type,
# so only call .pop() on object to avoid AttributeError.
- types = JsonLdProcessor.arrayify(
- compacted_item.pop(type_key, [])
- ) if _is_object(compacted_item) else []
+ types = (
+ JsonLdProcessor.arrayify(
+ compacted_item.pop(type_key, [])
+ )
+ if _is_object(compacted_item)
+ else []
+ )
key = types.pop(0) if types else None
if types:
JsonLdProcessor.add_value(
@@ -2143,8 +2155,8 @@ def _expand(
)
# prepare type-scoped contexts when nested
- active_ctx, type_key, type_scoped_ctx = (
- self._prepare_nested_context(active_ctx, element, options)
+ active_ctx, type_key, type_scoped_ctx = self._prepare_nested_context(
+ active_ctx, element, options
)
# process each key and value in element, ignoring @nest content
@@ -2766,8 +2778,8 @@ def _expand_object(
)
# prepare type-scoped contexts when nested
- active_ctx, type_key, type_scoped_ctx = (
- self._prepare_nested_context(term_ctx, nv, options)
+ active_ctx, type_key, type_scoped_ctx = self._prepare_nested_context(
+ term_ctx, nv, options
)
if [
@@ -4700,9 +4712,7 @@ def _validate_frame(self, frame):
# @type must be wildcard, @json, or IRI
if not (
_is_object(type_) or type_ == '@json' or _is_absolute_iri(type_)
- ) or (
- _is_string(type_) and type_.startswith('_:')
- ):
+ ) or (_is_string(type_) and type_.startswith('_:')):
raise JsonLdError(
'Invalid JSON-LD syntax; invalid @type in frame.',
'jsonld.SyntaxError',
diff --git a/mkdocs.yml b/mkdocs.yml
new file mode 100644
index 00000000..4786823d
--- /dev/null
+++ b/mkdocs.yml
@@ -0,0 +1,41 @@
+site_name: PyLD
+site_description: Python implementation of the JSON-LD API
+site_url: https://digitalbazaar.github.io/pyld/
+repo_url: https://github.com/digitalbazaar/pyld
+repo_name: digitalbazaar/pyld
+
+extra_css:
+ - stylesheets/extra.css
+
+theme:
+ name: material
+ features:
+ - content.code.copy
+ - navigation.footer
+ - navigation.indexes
+ - navigation.sections
+ - navigation.tabs
+ - navigation.top
+ - search.highlight
+ - search.suggest
+
+markdown_extensions:
+ - admonition
+ - attr_list
+ - md_in_html
+ - pymdownx.details
+ - pymdownx.emoji:
+ emoji_index: !!python/name:material.extensions.emoji.twemoji
+ emoji_generator: !!python/name:material.extensions.emoji.to_svg
+ - pymdownx.highlight:
+ anchor_linenums: true
+ - pymdownx.superfences
+ - toc:
+ permalink: true
+
+plugins:
+ - awesome-pages:
+ collapse_single_pages: true
+ - macros:
+ module_name: docs_macros
+ - search
diff --git a/setup.py b/setup.py
index 41fe18e9..62f533b1 100644
--- a/setup.py
+++ b/setup.py
@@ -18,7 +18,7 @@
os.path.dirname(__file__), 'lib', 'pyld', '__about__.py')) as fp:
exec(fp.read(), about)
-with open('README.rst') as fp:
+with open('README.md') as fp:
long_description = fp.read()
setup(
@@ -26,7 +26,7 @@
version=about['__version__'],
description='Python implementation of the JSON-LD API',
long_description=long_description,
- long_description_content_type="text/x-rst",
+ long_description_content_type="text/markdown",
author='Digital Bazaar',
author_email='support@digitalbazaar.com',
url='https://github.com/digitalbazaar/pyld',
diff --git a/specifications/json-ld-api b/specifications/json-ld-api
index 265e6b43..04a4eb7d 160000
--- a/specifications/json-ld-api
+++ b/specifications/json-ld-api
@@ -1 +1 @@
-Subproject commit 265e6b433a4eb25bad99d941c95f2ccecd6a8c1d
+Subproject commit 04a4eb7dc7cbc313f3f5be7ad9a3b06e87741693
diff --git a/specifications/json-ld-framing b/specifications/json-ld-framing
index 5437dbc5..fa228743 160000
--- a/specifications/json-ld-framing
+++ b/specifications/json-ld-framing
@@ -1 +1 @@
-Subproject commit 5437dbc5c0db543ccfa1b6b36197cc3687fc1b34
+Subproject commit fa228743e890499c35bc61aabf01e44cf5bbc3bc
diff --git a/tests/test_jsonld.py b/tests/test_jsonld.py
index f4fc22db..c602f18c 100644
--- a/tests/test_jsonld.py
+++ b/tests/test_jsonld.py
@@ -210,7 +210,6 @@ def test_base_does_not_expand_property_terms(self):
}
]
-
def _make_context(self, num_terms):
"""Build a context with `num_terms` @type:@vocab terms sharing a scoped context."""
ctx = {"ex": "https://example.org/"}
@@ -236,7 +235,6 @@ def _make_context(self, num_terms):
ctx[f"prop{i}"] = f"ex:prop{i}"
return ctx
-
def test_single_vocab_term_expands_correctly(self):
"""Single @type:@vocab term should expand bare string to @id."""
ctx = {
@@ -249,8 +247,9 @@ def test_single_vocab_term_expands_correctly(self):
}
doc = {"@context": ctx, "Color": "Red"}
result = jsonld.expand(doc)
- assert result[0]["https://example.org/Color"] == [{"@id": "https://example.org/Red"}]
-
+ assert result[0]["https://example.org/Color"] == [
+ {"@id": "https://example.org/Red"}
+ ]
def test_many_shared_scoped_contexts_expand_correctly(self):
"""
@@ -284,7 +283,6 @@ def test_many_shared_scoped_contexts_expand_correctly(self):
f"EnumProp{i} did not expand to @id"
)
-
def test_last_vocab_term_expands_with_large_context(self):
"""The LAST @type:@vocab term in a large context must also expand correctly.
@@ -295,8 +293,9 @@ def test_last_vocab_term_expands_with_large_context(self):
# Only test the last term
doc = {"@context": ctx, "EnumProp26": "TestValue"}
result = jsonld.expand(doc)
- assert result[0]["https://example.org/EnumProp26"] == [{"@id": "https://example.org/TestValue"}]
-
+ assert result[0]["https://example.org/EnumProp26"] == [
+ {"@id": "https://example.org/TestValue"}
+ ]
def test_structured_value_still_works_with_scoped_context(self):
"""Structured values (objects) should still use the scoped context mappings."""
@@ -395,7 +394,6 @@ def test_scoped_context_on_nest_term_expands_nested_type_scoped_context(self):
assert result == expected
-
def test_mixed_plain_and_vocab_terms(self):
"""Contexts with both plain and @type:@vocab terms should work correctly."""
ctx = {
@@ -424,8 +422,12 @@ def test_mixed_plain_and_vocab_terms(self):
}
result = jsonld.expand(doc)
expanded = result[0]
- assert expanded["https://example.org/Color"] == [{"@id": "https://example.org/Blue"}]
- assert expanded["https://example.org/Shape"] == [{"@id": "https://example.org/Circle"}]
+ assert expanded["https://example.org/Color"] == [
+ {"@id": "https://example.org/Blue"}
+ ]
+ assert expanded["https://example.org/Shape"] == [
+ {"@id": "https://example.org/Circle"}
+ ]
assert expanded["https://example.org/name"] == [{"@value": "test"}]
# Issue 145
@@ -470,6 +472,7 @@ def test_context_contained_with_propagate(self):
expanded = jsonld.expand(input)
assert expanded == expected
+
class TestFrame:
# Issue 11 - PR: https://github.com/digitalbazaar/pyld/issues/149
"""
@@ -794,36 +797,32 @@ def test_circular_references_link_and_embed(self):
"@context": "http://schema.org",
"@graph": [
{
- "id": "http://www.janedoe.com",
- "type": "Person",
- "jobTitle": "Professor",
- "knows": {
- "id": "http://www.johnsmith.me",
+ "id": "http://www.janedoe.com",
"type": "Person",
+ "jobTitle": "Professor",
"knows": {
- "id": "http://www.janedoe.com"
+ "id": "http://www.johnsmith.me",
+ "type": "Person",
+ "knows": {"id": "http://www.janedoe.com"},
+ "name": "John Smith",
},
- "name": "John Smith"
- },
- "name": "Jane Doe",
- "telephone": "(425) 123-4567"
+ "name": "Jane Doe",
+ "telephone": "(425) 123-4567",
},
{
- "id": "http://www.johnsmith.me",
- "type": "Person",
- "knows": {
- "id": "http://www.janedoe.com",
+ "id": "http://www.johnsmith.me",
"type": "Person",
- "jobTitle": "Professor",
"knows": {
- "id": "http://www.johnsmith.me"
+ "id": "http://www.janedoe.com",
+ "type": "Person",
+ "jobTitle": "Professor",
+ "knows": {"id": "http://www.johnsmith.me"},
+ "name": "Jane Doe",
+ "telephone": "(425) 123-4567",
},
- "name": "Jane Doe",
- "telephone": "(425) 123-4567"
+ "name": "John Smith",
},
- "name": "John Smith"
- }
- ]
+ ],
}
frame = {'@context': 'http://schema.org', '@embed': '@once'}
@@ -928,7 +927,7 @@ def test_compound_literal_direction_with_language(self):
assert nquads == expected
- # Issue 204
+ # Issue 204
def test_conflicting_property_names(self):
"""
Conversion to RDF should allow a node in the root @context with
@@ -955,7 +954,6 @@ def test_conflicting_property_names(self):
nquads = jsonld.to_rdf(input, options={'format': 'application/n-quads'})
assert nquads == expected
-
def test_conflicting_property_names_in_nested_node(self):
"""
Conversion to RDF should not ignore a @nest'ed node in the root @context
@@ -981,6 +979,7 @@ def test_conflicting_property_names_in_nested_node(self):
nquads = jsonld.to_rdf(input, options={'format': 'application/n-quads'})
assert nquads == expected
+
class TestFromRDF:
def test_compound_literal_direction_without_language(self):
"""
@@ -1117,6 +1116,7 @@ def test_compound_literal_invalid_language_fails(self):
assert exc.value.code == 'invalid language-tagged string'
+
class TestCompact:
# Issue 59 - PR: https://github.com/digitalbazaar/pyld/pull/60
def test_compaction_with_and_without_explicit_datatypes(self):
@@ -1370,7 +1370,9 @@ def test_no_initial_context_drops_property(self):
assert compacted == expected
@pytest.mark.xfail
- def test_no_initial_context_and_with_skip_expand_does_not_drop_property_whe_not_array(self):
+ def test_no_initial_context_and_with_skip_expand_does_not_drop_property_whe_not_array(
+ self,
+ ):
"""
Compacting document with singular value and without initial context should
output the original input when skipExpansion is enabled.
@@ -1378,11 +1380,15 @@ def test_no_initial_context_and_with_skip_expand_does_not_drop_property_whe_not_
input = {'name': 'Bob'}
- compacted = jsonld.compact(input, {"@vocab": "http://example.org#"}, {"skipExpansion": True})
+ compacted = jsonld.compact(
+ input, {"@vocab": "http://example.org#"}, {"skipExpansion": True}
+ )
expected = {"@context": {"@vocab": "http://example.org#"}, "name": "Bob"}
assert compacted == expected
- def test_no_initial_context_and_with_skip_expand_does_not_drop_property_when_array(self):
+ def test_no_initial_context_and_with_skip_expand_does_not_drop_property_when_array(
+ self,
+ ):
"""
Compacting document with array value and without initial context should
output the original input when skipExpansion is enabled.
@@ -1390,7 +1396,9 @@ def test_no_initial_context_and_with_skip_expand_does_not_drop_property_when_arr
input = {'name': ['Bob']}
- compacted = jsonld.compact(input, {"@vocab": "http://example.org#"}, {"skipExpansion": True})
+ compacted = jsonld.compact(
+ input, {"@vocab": "http://example.org#"}, {"skipExpansion": True}
+ )
expected = {"@context": {"@vocab": "http://example.org#"}, "name": "Bob"}
assert compacted == expected