PyLD 2.0.4__tar.gz → 3.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {PyLD-2.0.4 → pyld-3.1.0}/CHANGELOG.md +118 -1
- pyld-3.1.0/LICENSE +26 -0
- pyld-3.1.0/MANIFEST.in +2 -0
- pyld-3.1.0/PKG-INFO +466 -0
- pyld-3.1.0/README.md +424 -0
- pyld-3.1.0/README.txt +424 -0
- pyld-3.1.0/lib/PyLD.egg-info/PKG-INFO +466 -0
- pyld-3.1.0/lib/PyLD.egg-info/SOURCES.txt +43 -0
- pyld-3.1.0/lib/pyld/__about__.py +7 -0
- pyld-3.1.0/lib/pyld/__init__.py +19 -0
- pyld-3.1.0/lib/pyld/canon.py +566 -0
- {PyLD-2.0.4 → pyld-3.1.0}/lib/pyld/context_resolver.py +62 -36
- pyld-3.1.0/lib/pyld/documentloader/aiohttp.py +169 -0
- pyld-3.1.0/lib/pyld/documentloader/base.py +42 -0
- pyld-3.1.0/lib/pyld/documentloader/frozen/__init__.py +83 -0
- pyld-3.1.0/lib/pyld/documentloader/frozen/bundled/activitystreams.jsonld +379 -0
- pyld-3.1.0/lib/pyld/documentloader/frozen/bundled/credentials-v1.jsonld +315 -0
- pyld-3.1.0/lib/pyld/documentloader/frozen/bundled/credentials-v2.jsonld +301 -0
- pyld-3.1.0/lib/pyld/documentloader/frozen/bundled/did-v1.jsonld +57 -0
- pyld-3.1.0/lib/pyld/documentloader/frozen/bundled/security-ed25519-2020-v1.jsonld +93 -0
- pyld-3.1.0/lib/pyld/documentloader/frozen/bundled/security-jws-2020-v1.jsonld +78 -0
- pyld-3.1.0/lib/pyld/documentloader/frozen/bundled/security-v1.jsonld +74 -0
- pyld-3.1.0/lib/pyld/documentloader/frozen/bundled/security-v2.jsonld +126 -0
- {PyLD-2.0.4 → pyld-3.1.0}/lib/pyld/documentloader/requests.py +45 -29
- pyld-3.1.0/lib/pyld/identifier_issuer.py +53 -0
- pyld-3.1.0/lib/pyld/iri_resolver.py +323 -0
- {PyLD-2.0.4 → pyld-3.1.0}/lib/pyld/jsonld.py +2113 -2076
- pyld-3.1.0/lib/pyld/nquads.py +244 -0
- {PyLD-2.0.4 → pyld-3.1.0}/lib/pyld/resolved_context.py +2 -0
- pyld-3.1.0/pyproject.toml +57 -0
- {PyLD-2.0.4 → pyld-3.1.0}/setup.py +7 -1
- pyld-3.1.0/tests/test_api.py +25 -0
- pyld-3.1.0/tests/test_document_loader.py +115 -0
- pyld-3.1.0/tests/test_frozen_document_loader.py +119 -0
- pyld-3.1.0/tests/test_iri_resolver.py +508 -0
- pyld-3.1.0/tests/test_jsonld.py +1438 -0
- pyld-3.1.0/tests/test_manifests.py +32 -0
- PyLD-2.0.4/LICENSE +0 -44
- PyLD-2.0.4/MANIFEST.in +0 -1
- PyLD-2.0.4/PKG-INFO +0 -276
- PyLD-2.0.4/README.rst +0 -246
- PyLD-2.0.4/README.txt +0 -246
- PyLD-2.0.4/lib/PyLD.egg-info/PKG-INFO +0 -276
- PyLD-2.0.4/lib/PyLD.egg-info/SOURCES.txt +0 -22
- PyLD-2.0.4/lib/pyld/__about__.py +0 -9
- PyLD-2.0.4/lib/pyld/__init__.py +0 -5
- PyLD-2.0.4/lib/pyld/documentloader/aiohttp.py +0 -119
- {PyLD-2.0.4 → pyld-3.1.0}/lib/PyLD.egg-info/dependency_links.txt +0 -0
- {PyLD-2.0.4 → pyld-3.1.0}/lib/PyLD.egg-info/requires.txt +0 -0
- {PyLD-2.0.4 → pyld-3.1.0}/lib/PyLD.egg-info/top_level.txt +0 -0
- {PyLD-2.0.4 → pyld-3.1.0}/lib/c14n/Canonicalize.py +0 -0
- {PyLD-2.0.4 → pyld-3.1.0}/lib/c14n/NumberToJson.py +0 -0
- {PyLD-2.0.4 → pyld-3.1.0}/lib/c14n/__init__.py +0 -0
- {PyLD-2.0.4 → pyld-3.1.0}/lib/pyld/documentloader/__init__.py +0 -0
- {PyLD-2.0.4 → pyld-3.1.0}/setup.cfg +0 -0
|
@@ -1,5 +1,122 @@
|
|
|
1
1
|
# pyld ChangeLog
|
|
2
2
|
|
|
3
|
+
## 3.1.0 - 2026-06-19
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
- When compacting, expands the index mapping first, then compacts that expanded
|
|
7
|
+
IRI, matching the JSON-LD API compaction correction for compact-IRI index
|
|
8
|
+
mappings. Fixes testcases [compact#t0112](https://w3c.github.io/json-ld-api/tests/compact-manifest.html#t0112)
|
|
9
|
+
and [compact#t0113](https://w3c.github.io/json-ld-api/tests/compact-manifest.html#t0113).
|
|
10
|
+
- Fixes `AttributeError` when compacting with `@none`: the `@type` map
|
|
11
|
+
compaction path now only calls `.pop()` and inspects keys when
|
|
12
|
+
`compacted_item` is actually an object. Fixes
|
|
13
|
+
[compact#tm023](https://w3c.github.io/json-ld-api/tests/compact-manifest.html#tm023)
|
|
14
|
+
- An empty property-scoped context no longer resets the active context in
|
|
15
|
+
`_create_term_definition`. Now only explicit null becomes False; empty
|
|
16
|
+
contexts are preserved. Fixes [compact#tc028](https://w3c.github.io/json-ld-api/tests/compact-manifest.html#tc028),
|
|
17
|
+
[toRdf#tc036](https://w3c.github.io/json-ld-api/tests/toRdf-manifest.html#tc036)
|
|
18
|
+
and [expand#tc036](https://w3c.github.io/json-ld-api/tests/expand-manifest.html#tc036).
|
|
19
|
+
- Options from the test manifest now override the options configured in
|
|
20
|
+
`create_test_options()`, instead of the other way around. This fixes
|
|
21
|
+
tests not able to override default options in the test-setup such as
|
|
22
|
+
`extractAllScripts`. Fixes [html#tf004](https://w3c.github.io/json-ld-api/tests/html-manifest#tf004).
|
|
23
|
+
- When `@type` is `@json` in a frame, it no longer raises an "Invalid JSON-LD
|
|
24
|
+
syntax" error. Fixes [frame#t0069](https://w3c.github.io/json-ld-framing/tests/frame-manifest.html#t0069).
|
|
25
|
+
- Use safeguard for non-dict values of `options['link']`
|
|
26
|
+
- Local and type-scoped contexts are now properly resolved for nested node
|
|
27
|
+
objects, so a scoped context on a `@nest` term is being applied to nested
|
|
28
|
+
properties. Fixes [toRdf#tc037](https://w3c.github.io/json-ld-api/tests/toRdf-manifest.html#tc037),
|
|
29
|
+
[toRdf#tc038](https://w3c.github.io/json-ld-api/tests/toRdf-manifest.html#tc038),
|
|
30
|
+
[expand#tc037](https://w3c.github.io/json-ld-api/tests/expand-manifest.html#tc037)
|
|
31
|
+
and [expand#tc038](https://w3c.github.io/json-ld-api/tests/expand-manifest.html#tc038).
|
|
32
|
+
|
|
33
|
+
### Changed
|
|
34
|
+
- `requests_document_loader()` and `aiohttp_document_loader()` now return
|
|
35
|
+
class-based `DocumentLoader` instances while preserving the existing
|
|
36
|
+
callable factory API. The concrete `RequestsDocumentLoader` and
|
|
37
|
+
`AioHttpDocumentLoader` classes are also importable from `pyld`.
|
|
38
|
+
- The `pytest` test runner now uses plain assert result == expect instead
|
|
39
|
+
of printing EXPECTED / ACTUAL and raising a generic failure. This enables
|
|
40
|
+
`pytests`'s native result comparison.
|
|
41
|
+
- Convert `./README.rst` and `./CONTRIBUTING.rst` (reStructuredText) to
|
|
42
|
+
`./README.md` and `./CONTRIBUTING.md` (markdown). Also update their
|
|
43
|
+
contents to reflect the current state of the repo.
|
|
44
|
+
- Replace the old Sphinx documentation with a MkDocs Material site and add a
|
|
45
|
+
GitHub Pages documentation workflow.
|
|
46
|
+
|
|
47
|
+
### Added
|
|
48
|
+
- `pyld.DocumentLoader` abstract base class for class-based document loaders,
|
|
49
|
+
with a `RemoteDocument` `TypedDict` describing the expected return shape.
|
|
50
|
+
- `pyld.FrozenDocumentLoader`: a class-based loader that serves only URLs in
|
|
51
|
+
its `documents` allowlist and refuses everything else with
|
|
52
|
+
`JsonLdError(code='loading document failed')`. Instantiating with no
|
|
53
|
+
arguments serves the curated `pyld.BUNDLED_CONTEXTS` set; instantiating
|
|
54
|
+
with `dict(BUNDLED_CONTEXTS, **extras)` extends the bundle. Suitable for
|
|
55
|
+
air-gapped, reproducible-build, and security-hardened deployments.
|
|
56
|
+
- `pyld.BUNDLED_CONTEXTS`: curated mapping of high-traffic public W3C / W3ID
|
|
57
|
+
JSON-LD contexts (ActivityStreams, DID v1, VC v1/v2, Linked Data Security
|
|
58
|
+
v1/v2, Ed25519-2020, JWS-2020) to vendored on-disk copies. Refresh with
|
|
59
|
+
`make download-bundled-contexts`.
|
|
60
|
+
- `pyld.ContextResolver`: added the `max_context_urls` property that
|
|
61
|
+
determines maximum number of times contexts can be recusively fetched,
|
|
62
|
+
which replaces the role of the static `MAX_CONTEXT_URLS`. The constructor
|
|
63
|
+
now accepts a `max_context_urls` parameter that sets the value of
|
|
64
|
+
`max_context_urls` which defaults to `MAX_CONTEXT_URLS`.
|
|
65
|
+
- `pyld.fromRdf()` and `pyld.toRdf()` now support compound literals when
|
|
66
|
+
serializing/deserializing RDF to/from JSON-LD. Therefore, both methods accept
|
|
67
|
+
the value `'compound-literal'` for the `'rdfDirection'` option. Fixes
|
|
68
|
+
[fromRdf#tdi11](https://w3c.github.io/json-ld-api/tests/fromRdf-manifest.html#tdi11),
|
|
69
|
+
[fromRdf#tdi12](https://w3c.github.io/json-ld-api/tests/fromRdf-manifest.html#tdi12),
|
|
70
|
+
[toRdf#tdi11](https://w3c.github.io/json-ld-api/tests/toRdf-manifest.html#tdi11), and
|
|
71
|
+
[toRdf#tdi12](https://w3c.github.io/json-ld-api/tests/toRdf-manifest.html#tdi12).
|
|
72
|
+
|
|
73
|
+
## 3.0.0 - 2026-04-02
|
|
74
|
+
|
|
75
|
+
### Changed
|
|
76
|
+
- **BREAKING**: Compaction term selection now follows the JSON-LD 1.1 spec
|
|
77
|
+
(Inverse Context Creation, section 4.3 step 3): terms are ordered by
|
|
78
|
+
shortest first, with lexicographic tiebreak. Previously terms were ordered
|
|
79
|
+
lexicographically first, then by length. This changes which term is
|
|
80
|
+
selected when multiple context keys map to the same IRI. See #247.
|
|
81
|
+
- **BREAKING**: Require supported Python version >= 3.10.
|
|
82
|
+
- Update aiohttp document loader to work with Python 3.14.
|
|
83
|
+
- Minimize async related changes to library code in this release.
|
|
84
|
+
- In sync environment use `asyncio.run`.
|
|
85
|
+
- In async environment use background thread.
|
|
86
|
+
- The default test manifests or directories now default to the
|
|
87
|
+
`./specifications` directory.
|
|
88
|
+
- Add ability to run test suites using pytest and make pytest the default way
|
|
89
|
+
for running (unit)tests.
|
|
90
|
+
- The functionality to resolve relative IRIs to absolute IRIs has been moved
|
|
91
|
+
from `context_resolver.py` to `iri_resolver.py` so it can be maintained
|
|
92
|
+
and tested separately.
|
|
93
|
+
- Migrate the `prepend_base(base, iri)` function to the `resolve(iri, base)`
|
|
94
|
+
function.
|
|
95
|
+
- Move the existing function `remove_dot_segments(path)` and update the
|
|
96
|
+
implementation.
|
|
97
|
+
- Migrate the `remove_base(base, iri)` function to the `unresolve(iri, base)`
|
|
98
|
+
function and update the implementation to use stdlib `urllib.parse` and
|
|
99
|
+
`urllib.unparse` to replace the custom implementation.
|
|
100
|
+
- Update code to use `resolve(iri, base)` and `unresolve(iri, base)` instead.
|
|
101
|
+
Invalid base IRIs (including `None`) are no longer allowed, hence missing
|
|
102
|
+
base IRIs in the JSON-LD context are now handled outside the function call.
|
|
103
|
+
- Add unittests
|
|
104
|
+
- **BREAKING**: the custom `cause` and `traceback` attributes on `JsonLdError`
|
|
105
|
+
are replaced by Python [exception chaining](https://peps.python.org/pep-3134/)
|
|
106
|
+
and the built-in `__cause__` attribute.
|
|
107
|
+
- **BREAKING**: The `IdentifierIssuer` class was moved to `identifier_issuer.py`.
|
|
108
|
+
It's now available at `pyld.identifier_issuer`.
|
|
109
|
+
- **BREAKING**: The classes `URDNA2015` and `URGNA2012` were moved to `canon.py`.
|
|
110
|
+
They are now available at `pyld.canon`.
|
|
111
|
+
- `jsonld.expand()` now accepts a `on_property_dropped` parameter which is a handler
|
|
112
|
+
called on every ignored JSON property.
|
|
113
|
+
- **BREAKING**: In cases where there is no document base (for instance, when
|
|
114
|
+
using a string as input), 'http://example.org/base/' is used as the base IRI
|
|
115
|
+
when `@base` is absent or explicitely set to `null`.
|
|
116
|
+
- **BREAKING**: Some internal parameters were renamed from camelCase to pythonic:
|
|
117
|
+
- `requestProfile` to `request_profile` in `load_document()`
|
|
118
|
+
- `rdfDirection` to `rdf_direction` in `_list_to_rdf()` and `_object_to_rdf()`
|
|
119
|
+
|
|
3
120
|
## 2.0.4 - 2024-02-16
|
|
4
121
|
|
|
5
122
|
### Fixed
|
|
@@ -174,7 +291,7 @@
|
|
|
174
291
|
- **1.0.0**!
|
|
175
292
|
- [Semantic Versioning](https://semver.org/) is now past the "initial
|
|
176
293
|
development" 0.x.y stage (after 6+ years!).
|
|
177
|
-
- [Conformance](README.
|
|
294
|
+
- [Conformance](README.md#conformance):
|
|
178
295
|
- JSON-LD 1.0 + JSON-LD 1.0 errata
|
|
179
296
|
- JSON-LD 1.1 drafts
|
|
180
297
|
- Thanks to the JSON-LD and related communities and the many many people over
|
pyld-3.1.0/LICENSE
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
Copyright (c) 2011-2025 Digital Bazaar, Inc.
|
|
2
|
+
|
|
3
|
+
Redistribution and use in source and binary forms, with or without modification,
|
|
4
|
+
are permitted provided that the following conditions are met:
|
|
5
|
+
|
|
6
|
+
1. Redistributions of source code must retain the above copyright notice, this
|
|
7
|
+
list of conditions and the following disclaimer.
|
|
8
|
+
|
|
9
|
+
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
10
|
+
this list of conditions and the following disclaimer in the documentation and/or
|
|
11
|
+
other materials provided with the distribution.
|
|
12
|
+
|
|
13
|
+
3. Neither the name of the copyright holder nor the names of its contributors
|
|
14
|
+
may be used to endorse or promote products derived from this software without
|
|
15
|
+
specific prior written permission.
|
|
16
|
+
|
|
17
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
18
|
+
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
19
|
+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
20
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
|
21
|
+
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
22
|
+
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
23
|
+
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
|
24
|
+
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
25
|
+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
26
|
+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
pyld-3.1.0/MANIFEST.in
ADDED
pyld-3.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,466 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: PyLD
|
|
3
|
+
Version: 3.1.0
|
|
4
|
+
Summary: Python implementation of the JSON-LD API
|
|
5
|
+
Home-page: https://github.com/digitalbazaar/pyld
|
|
6
|
+
Author: Digital Bazaar
|
|
7
|
+
Author-email: support@digitalbazaar.com
|
|
8
|
+
License: BSD 3-Clause license
|
|
9
|
+
Classifier: Development Status :: 4 - Beta
|
|
10
|
+
Classifier: Environment :: Console
|
|
11
|
+
Classifier: Environment :: Web Environment
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: License :: OSI Approved :: BSD License
|
|
14
|
+
Classifier: Operating System :: OS Independent
|
|
15
|
+
Classifier: Programming Language :: Python
|
|
16
|
+
Classifier: Topic :: Internet
|
|
17
|
+
Classifier: Topic :: Software Development :: Libraries
|
|
18
|
+
Description-Content-Type: text/markdown
|
|
19
|
+
License-File: LICENSE
|
|
20
|
+
Requires-Dist: cachetools
|
|
21
|
+
Requires-Dist: frozendict
|
|
22
|
+
Requires-Dist: lxml
|
|
23
|
+
Provides-Extra: requests
|
|
24
|
+
Requires-Dist: requests; extra == "requests"
|
|
25
|
+
Provides-Extra: aiohttp
|
|
26
|
+
Requires-Dist: aiohttp; extra == "aiohttp"
|
|
27
|
+
Provides-Extra: cachetools
|
|
28
|
+
Requires-Dist: cachetools; extra == "cachetools"
|
|
29
|
+
Provides-Extra: frozendict
|
|
30
|
+
Requires-Dist: frozendict; extra == "frozendict"
|
|
31
|
+
Dynamic: author
|
|
32
|
+
Dynamic: author-email
|
|
33
|
+
Dynamic: classifier
|
|
34
|
+
Dynamic: description
|
|
35
|
+
Dynamic: description-content-type
|
|
36
|
+
Dynamic: home-page
|
|
37
|
+
Dynamic: license
|
|
38
|
+
Dynamic: license-file
|
|
39
|
+
Dynamic: provides-extra
|
|
40
|
+
Dynamic: requires-dist
|
|
41
|
+
Dynamic: summary
|
|
42
|
+
|
|
43
|
+
# PyLD: A Python JSON-LD Processor
|
|
44
|
+
|
|
45
|
+
[Documentation](https://digitalbazaar.github.io/pyld/) |
|
|
46
|
+
[Installation](#installation) | [Usage](#usage) | [Advanced
|
|
47
|
+
Topics](#advanced-topics) | [Contributing](./CONTRIBUTING.md) |
|
|
48
|
+
[Changelog](./CHANGELOG.md)
|
|
49
|
+
|
|
50
|
+
## Introduction
|
|
51
|
+
|
|
52
|
+
This library is an implementation of the JSON-LD specification in
|
|
53
|
+
[Python](https://www.python.org/).
|
|
54
|
+
|
|
55
|
+
JSON, as specified in [RFC7159](http://tools.ietf.org/html/rfc7159), is a simple
|
|
56
|
+
language for representing objects on the Web. Linked Data is a way of describing
|
|
57
|
+
content across different documents or Web sites. Web resources are described
|
|
58
|
+
using IRIs, and typically are dereferencable entities that may be used to find
|
|
59
|
+
more information, creating a "Web of Knowledge". [JSON-LD](https://json-ld.org/)
|
|
60
|
+
is intended to be a simple publishing method for expressing not only Linked Data
|
|
61
|
+
in JSON, but for adding semantics to existing JSON.
|
|
62
|
+
|
|
63
|
+
JSON-LD is designed as a light-weight syntax that can be used to express Linked
|
|
64
|
+
Data. It is primarily intended to be a way to express Linked Data in JavaScript
|
|
65
|
+
and other Web-based programming environments. It is also useful when building
|
|
66
|
+
interoperable Web Services and when storing Linked Data in JSON-based document
|
|
67
|
+
storage engines. It is practical and designed to be as simple as possible,
|
|
68
|
+
utilizing the large number of JSON parsers and existing code that is in use
|
|
69
|
+
today. It is designed to be able to express key-value pairs, RDF data,
|
|
70
|
+
[RDFa](http://www.w3.org/TR/rdfa-core/) data,
|
|
71
|
+
[Microformats](http://microformats.org/) data, and
|
|
72
|
+
[Microdata](http://www.w3.org/TR/microdata/). That is, it supports every major
|
|
73
|
+
Web-based structured data model in use today.
|
|
74
|
+
|
|
75
|
+
The syntax does not require many applications to change their JSON, but easily
|
|
76
|
+
add meaning by adding context in a way that is either in-band or out-of-band.
|
|
77
|
+
The syntax is designed to not disturb already deployed systems running on JSON,
|
|
78
|
+
but provide a smooth migration path from JSON to JSON with added semantics.
|
|
79
|
+
Finally, the format is intended to be fast to parse, fast to generate,
|
|
80
|
+
stream-based and document-based processing compatible, and require a very small
|
|
81
|
+
memory footprint in order to operate.
|
|
82
|
+
|
|
83
|
+
## Requirements
|
|
84
|
+
|
|
85
|
+
* Python (3.10 or later)
|
|
86
|
+
* [Requests](http://docs.python-requests.org/) (optional)
|
|
87
|
+
* [aiohttp](https://aiohttp.readthedocs.io/) (optional)
|
|
88
|
+
|
|
89
|
+
## Installation
|
|
90
|
+
|
|
91
|
+
PyLD can be installed with a [pip](http://www.pip-installer.org/)
|
|
92
|
+
[package](https://pypi.org/project/PyLD/):
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
pip install PyLD
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Defining a dependency on pyld will not pull in
|
|
99
|
+
[Requests](http://docs.python-requests.org/) or
|
|
100
|
+
[aiohttp](https://aiohttp.readthedocs.io/). If you need one of these for a
|
|
101
|
+
[Document Loader](#document-loader) then either depend on the desired external library directly
|
|
102
|
+
or define the requirement as `PyLD[requests]` or `PyLD[aiohttp]`.
|
|
103
|
+
|
|
104
|
+
## Usage
|
|
105
|
+
|
|
106
|
+
Here are some quick examples to get started:
|
|
107
|
+
|
|
108
|
+
```python
|
|
109
|
+
from pyld import jsonld
|
|
110
|
+
import json
|
|
111
|
+
|
|
112
|
+
doc = {
|
|
113
|
+
"http://schema.org/name": "Manu Sporny",
|
|
114
|
+
"http://schema.org/url": {"@id": "http://manu.sporny.org/"},
|
|
115
|
+
"http://schema.org/image": {"@id": "http://manu.sporny.org/images/manu.png"}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
context = {
|
|
119
|
+
"name": "http://schema.org/name",
|
|
120
|
+
"homepage": {"@id": "http://schema.org/url", "@type": "@id"},
|
|
121
|
+
"image": {"@id": "http://schema.org/image", "@type": "@id"}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
# compact a document according to a particular context
|
|
125
|
+
# see: https://json-ld.org/spec/latest/json-ld/#compacted-document-form
|
|
126
|
+
compacted = jsonld.compact(doc, context)
|
|
127
|
+
|
|
128
|
+
print(json.dumps(compacted, indent=2))
|
|
129
|
+
# Output:
|
|
130
|
+
# {
|
|
131
|
+
# "@context": {...},
|
|
132
|
+
# "image": "http://manu.sporny.org/images/manu.png",
|
|
133
|
+
# "homepage": "http://manu.sporny.org/",
|
|
134
|
+
# "name": "Manu Sporny"
|
|
135
|
+
# }
|
|
136
|
+
|
|
137
|
+
# compact using URLs
|
|
138
|
+
jsonld.compact('http://example.org/doc', 'http://example.org/context')
|
|
139
|
+
|
|
140
|
+
# expand a document, removing its context
|
|
141
|
+
# see: https://json-ld.org/spec/latest/json-ld/#expanded-document-form
|
|
142
|
+
expanded = jsonld.expand(compacted)
|
|
143
|
+
|
|
144
|
+
print(json.dumps(expanded, indent=2))
|
|
145
|
+
# Output:
|
|
146
|
+
# [{
|
|
147
|
+
# "http://schema.org/image": [{"@id": "http://manu.sporny.org/images/manu.png"}],
|
|
148
|
+
# "http://schema.org/name": [{"@value": "Manu Sporny"}],
|
|
149
|
+
# "http://schema.org/url": [{"@id": "http://manu.sporny.org/"}]
|
|
150
|
+
# }]
|
|
151
|
+
|
|
152
|
+
# expand using URLs
|
|
153
|
+
jsonld.expand('http://example.org/doc')
|
|
154
|
+
|
|
155
|
+
# flatten a document
|
|
156
|
+
# see: https://json-ld.org/spec/latest/json-ld/#flattened-document-form
|
|
157
|
+
flattened = jsonld.flatten(doc)
|
|
158
|
+
# all deep-level trees flattened to the top-level
|
|
159
|
+
|
|
160
|
+
# frame a document
|
|
161
|
+
# see: https://json-ld.org/spec/latest/json-ld-framing/#introduction
|
|
162
|
+
framed = jsonld.frame(doc, frame)
|
|
163
|
+
# document transformed into a particular tree structure per the given frame
|
|
164
|
+
|
|
165
|
+
# normalize a document using the RDF Dataset Normalization Algorithm
|
|
166
|
+
# (URDNA2015), see: https://www.w3.org/TR/rdf-canon/
|
|
167
|
+
normalized = jsonld.normalize(
|
|
168
|
+
doc, {'algorithm': 'URDNA2015', 'format': 'application/n-quads'})
|
|
169
|
+
# normalized is a string that is a canonical representation of the document
|
|
170
|
+
# that can be used for hashing, comparison, etc.
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
## Features & conformance
|
|
174
|
+
|
|
175
|
+
This library aims to conform with the following W3C Recommendations:
|
|
176
|
+
|
|
177
|
+
| Standard | Status |
|
|
178
|
+
| :--- | :--- |
|
|
179
|
+
| [JSON-LD 1.1](https://www.w3.org/TR/json-ld11/) | W3C Recommendation |
|
|
180
|
+
| [JSON-LD 1.1 Processing Algorithms and API](https://www.w3.org/TR/json-ld11-api/) | W3C Recommendation |
|
|
181
|
+
| [JSON-LD 1.1 Framing](https://www.w3.org/TR/json-ld11-framing/) | W3C Recommendation |
|
|
182
|
+
| [RDF Dataset Canonicalization](https://www.w3.org/TR/rdf-canon/) | W3C Recommendation |
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
The [`test
|
|
186
|
+
runner`](https://github.com/digitalbazaar/pyld/blob/master/tests/runtests.py) is
|
|
187
|
+
often updated to note or skip newer tests that are not yet supported.
|
|
188
|
+
|
|
189
|
+
## Advanced Topics
|
|
190
|
+
|
|
191
|
+
### Document Loader
|
|
192
|
+
|
|
193
|
+
The default document loader for PyLD uses
|
|
194
|
+
[Requests](http://docs.python-requests.org/). In a production environment you
|
|
195
|
+
may want to setup a custom loader that, at a minimum, sets a timeout value. You
|
|
196
|
+
can also force requests to use https, set client certs, disable verification, or
|
|
197
|
+
set other Requests parameters.
|
|
198
|
+
|
|
199
|
+
```python
|
|
200
|
+
jsonld.set_document_loader(jsonld.requests_document_loader(timeout=...))
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
The factory remains the compatibility API, and the concrete class is also
|
|
204
|
+
available when class-based construction is preferred:
|
|
205
|
+
|
|
206
|
+
```python
|
|
207
|
+
from pyld import RequestsDocumentLoader
|
|
208
|
+
|
|
209
|
+
jsonld.set_document_loader(RequestsDocumentLoader(timeout=...))
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
An asynchronous document loader using aiohttp is also available. Please note
|
|
213
|
+
that this document loader limits asynchronicity to fetching documents only. The
|
|
214
|
+
processing loops remain synchronous.
|
|
215
|
+
|
|
216
|
+
```python
|
|
217
|
+
jsonld.set_document_loader(jsonld.aiohttp_document_loader(timeout=...))
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
The concrete aiohttp loader class is available from `pyld` as well:
|
|
221
|
+
|
|
222
|
+
```python
|
|
223
|
+
from pyld import AioHttpDocumentLoader
|
|
224
|
+
|
|
225
|
+
jsonld.set_document_loader(AioHttpDocumentLoader(timeout=...))
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
When no document loader is specified, the default loader is set to
|
|
229
|
+
[Requests](http://docs.python-requests.org/). If Requests is not available, the
|
|
230
|
+
loader is set to aiohttp. The fallback document loader is a dummy document
|
|
231
|
+
loader that raises an exception on every invocation.
|
|
232
|
+
|
|
233
|
+
### Frozen Document Loader
|
|
234
|
+
|
|
235
|
+
For air-gapped runs, reproducible builds, and security-hardened deployments that
|
|
236
|
+
must not perform any remote context fetches at all, PyLD ships
|
|
237
|
+
`FrozenDocumentLoader`: a class-based loader that serves only the URLs in its
|
|
238
|
+
`documents` allowlist and refuses everything else with
|
|
239
|
+
`JsonLdError(code='loading document failed')`.
|
|
240
|
+
|
|
241
|
+
Instantiating with no arguments serves the curated `BUNDLED_CONTEXTS` set
|
|
242
|
+
(ActivityStreams, DID v1, Verifiable Credentials v1 and v2, Linked Data Security
|
|
243
|
+
v1/v2, Ed25519-2020, and JWS-2020). To extend the bundle with additional
|
|
244
|
+
pre-vetted contexts, pass a merged mapping:
|
|
245
|
+
|
|
246
|
+
```python
|
|
247
|
+
from pyld import jsonld, FrozenDocumentLoader, BUNDLED_CONTEXTS
|
|
248
|
+
|
|
249
|
+
loader = FrozenDocumentLoader(documents=dict(
|
|
250
|
+
BUNDLED_CONTEXTS,
|
|
251
|
+
**{'https://example.com/my-ctx': Path('contexts/my-ctx.jsonld')},
|
|
252
|
+
))
|
|
253
|
+
jsonld.expand(doc, options={'documentLoader': loader})
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
This honors the W3C *JSON-LD Best Practices* recommendation that clients SHOULD
|
|
257
|
+
attempt to use a locally cached version of contexts (see
|
|
258
|
+
[§ Cache JSON-LD Contexts](https://w3c.github.io/json-ld-bp/#cache-json-ld-contexts)).
|
|
259
|
+
Refresh the bundled copies with `make download-bundled-contexts`.
|
|
260
|
+
|
|
261
|
+
### Customizing the ContextLoader
|
|
262
|
+
|
|
263
|
+
You can customize the way contexts are loaded and cached by passing an instance
|
|
264
|
+
of `ContextResolver`. The following example implements a loader with a prefilled
|
|
265
|
+
custom document cache and uses a custom LRU cache for resolved contexts:
|
|
266
|
+
|
|
267
|
+
```python
|
|
268
|
+
from pyld.jsonld import compact, expand, set_document_loader, ContextResolver
|
|
269
|
+
import json
|
|
270
|
+
from cachetools import LRUCache
|
|
271
|
+
|
|
272
|
+
# Load the Linked Art context from file-system
|
|
273
|
+
fh = open('linked-art.json')
|
|
274
|
+
js = json.load(fh)
|
|
275
|
+
fh.close()
|
|
276
|
+
|
|
277
|
+
# Add to document cache
|
|
278
|
+
docCache = {
|
|
279
|
+
"https://linked.art/ns/v1/linked-art.json": {
|
|
280
|
+
"contextUrl": None,
|
|
281
|
+
"documentUrl": "https://linked.art/ns/v1/linked-art.json",
|
|
282
|
+
"document": js
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
# Custom loader that uses the document cache
|
|
287
|
+
def load_document_and_cache(url, options={}):
|
|
288
|
+
if url in docCache:
|
|
289
|
+
return docCache[url]
|
|
290
|
+
doc = {"contextUrl": None, "documentUrl": url, "document": ""}
|
|
291
|
+
resp = requests.get(url)
|
|
292
|
+
doc["document"] = resp.json()
|
|
293
|
+
docCache[url] = doc
|
|
294
|
+
return doc
|
|
295
|
+
|
|
296
|
+
# Set the custom loader as global document loader
|
|
297
|
+
set_document_loader(load_document_and_cache)
|
|
298
|
+
# Create custom context resolver with custom LRU cache and custom loader
|
|
299
|
+
resolved_context_cache = LRUCache(maxsize=1000)
|
|
300
|
+
resolver = ContextResolver(resolved_context_cache, load_document_and_cache)
|
|
301
|
+
|
|
302
|
+
# Expand JSON-LD document using custom context resolver
|
|
303
|
+
input = {"@context":"https://linked.art/ns/v1/linked-art.json", "id": "tag:foo", "type": "Person"}
|
|
304
|
+
output = expand(input, options={'contextResolver': resolver})
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
It is also possible to change the maximum number of times that the loader
|
|
308
|
+
recursively fetches contexts, by passing the `max_context_urls` parameter:
|
|
309
|
+
|
|
310
|
+
```python
|
|
311
|
+
resolver = ContextResolver(resolved_context_cache, load_document_and_cache, max_context_urls=20)
|
|
312
|
+
# Or you can do...
|
|
313
|
+
# resolver = ContextResolver(resolved_context_cache, load_document_and_cache)
|
|
314
|
+
# resolver.max_context_urls = 20
|
|
315
|
+
output = expand(input, options={'contextResolver': resolver})
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
### Handling ignored properties during JSON-LD expansion
|
|
319
|
+
|
|
320
|
+
If a property in a JSON-LD document does not map to an absolute IRI then it is
|
|
321
|
+
ignored. You can customize this behaviour by passing a customizable handler to
|
|
322
|
+
`on_property_dropped` parameter of `jsonld.expand()`.
|
|
323
|
+
|
|
324
|
+
For example, you can introduce a strict mode by raising a ValueError on every
|
|
325
|
+
dropped property:
|
|
326
|
+
|
|
327
|
+
```python
|
|
328
|
+
def raise_this(value):
|
|
329
|
+
raise ValueError(value)
|
|
330
|
+
|
|
331
|
+
jsonld.expand(doc, None, on_property_dropped=raise_this)
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
## Contributing
|
|
335
|
+
|
|
336
|
+
Want to contribute to PyLD? Great! Please consult [`CONTRIBUTING.md`](./CONTRIBUTING.md) for some guidelines.
|
|
337
|
+
|
|
338
|
+
### Building the source
|
|
339
|
+
|
|
340
|
+
The source code for the Python implementation of the JSON-LD API is available
|
|
341
|
+
at:
|
|
342
|
+
|
|
343
|
+
[https://github.com/digitalbazaar/pyld](https://github.com/digitalbazaar/pyld)
|
|
344
|
+
|
|
345
|
+
You can install the source using `make`:
|
|
346
|
+
|
|
347
|
+
```
|
|
348
|
+
pip install -r requirements.txt requirements-test.txt
|
|
349
|
+
make install
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
### Testing
|
|
353
|
+
|
|
354
|
+
This library includes a sample testing utility which may be used to verify that
|
|
355
|
+
changes to the processor maintain the correct output.
|
|
356
|
+
|
|
357
|
+
To run the sample tests you will need to get the test suite files, which by
|
|
358
|
+
default, are stored in the `specifications/` folder. The test suites can be
|
|
359
|
+
obtained by either using git submodules or by cloning them manually.
|
|
360
|
+
|
|
361
|
+
#### Using git submodules
|
|
362
|
+
|
|
363
|
+
The test suites are included as git submodules to ensure versions are in sync.
|
|
364
|
+
When cloning the repository, use the `--recurse-submodules` flag to
|
|
365
|
+
automatically clone the submodules. If you have cloned the repository without
|
|
366
|
+
the submodules, you can initialize them with the following commands:
|
|
367
|
+
|
|
368
|
+
```bash
|
|
369
|
+
git submodule init
|
|
370
|
+
git submodule update
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
#### Cloning manually
|
|
374
|
+
|
|
375
|
+
You can also avoid using git submodules by manually cloning the `json-ld-api`,
|
|
376
|
+
`json-ld-framing`, and `normalization` repositories hosted on GitHub using the
|
|
377
|
+
following commands:
|
|
378
|
+
|
|
379
|
+
```bash
|
|
380
|
+
git clone https://github.com/w3c/json-ld-api ./specifications/json-ld-api
|
|
381
|
+
git clone https://github.com/w3c/json-ld-framing ./specifications/json-ld-framing
|
|
382
|
+
git clone https://github.com/json-ld/normalization ./specifications/normalization
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
Note that you can clone these repositories into any location you wish; however,
|
|
386
|
+
if you do not clone them into the default `specifications/` folder, you will
|
|
387
|
+
need to provide the paths to the test runner as arguments when running the
|
|
388
|
+
tests, as explained below.
|
|
389
|
+
|
|
390
|
+
#### Running the sample test suites and unit tests using pytest
|
|
391
|
+
|
|
392
|
+
If the suites repositories are available in the `specifications/` folder of the
|
|
393
|
+
PyLD source directory, then all unittests, including the sample test suites, can
|
|
394
|
+
be run with `pytest`:
|
|
395
|
+
|
|
396
|
+
```bash
|
|
397
|
+
pytest
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
If you wish to store the test suites in a different location than the default
|
|
401
|
+
`specifications/` folder, or you want to test individual manifest `.jsonld`
|
|
402
|
+
files or directories containing a `manifest.jsonld`, then you can supply these
|
|
403
|
+
files or directories as arguments:
|
|
404
|
+
|
|
405
|
+
```bash
|
|
406
|
+
# use: pytest --tests=TEST_PATH [--tests=TEST_PATH...]
|
|
407
|
+
pytest --tests=./specifications/json-ld-api/tests
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
The test runner supports different document loaders by setting `--loader
|
|
411
|
+
requests` or `--loader aiohttp`. The default document loader is set to
|
|
412
|
+
[Requests](http://docs.python-requests.org/).
|
|
413
|
+
|
|
414
|
+
```bash
|
|
415
|
+
pytest --loader=requests --tests=./specifications/json-ld-api/tests
|
|
416
|
+
```
|
|
417
|
+
|
|
418
|
+
An EARL report can be generated using the `--earl` option.
|
|
419
|
+
|
|
420
|
+
```bash
|
|
421
|
+
pytest --earl=./earl-report.json
|
|
422
|
+
```
|
|
423
|
+
|
|
424
|
+
#### Running the sample test suites using the original test runner
|
|
425
|
+
|
|
426
|
+
You can also run the JSON-LD test suites using the original test runner script
|
|
427
|
+
provided:
|
|
428
|
+
|
|
429
|
+
```bash
|
|
430
|
+
python tests/runtests.py
|
|
431
|
+
```
|
|
432
|
+
|
|
433
|
+
If you wish to store the test suites in a different location than the default
|
|
434
|
+
`specifications/` folder, or you want to test individual manifest `.jsonld`
|
|
435
|
+
files or directories containing a `manifest.jsonld`, then you can supply these
|
|
436
|
+
files or directories as arguments:
|
|
437
|
+
|
|
438
|
+
```bash
|
|
439
|
+
python tests/runtests.py TEST_PATH [TEST_PATH...]
|
|
440
|
+
```
|
|
441
|
+
|
|
442
|
+
The test runner supports different document loaders by setting `-l requests` or
|
|
443
|
+
`-l aiohttp`. The default document loader is set to
|
|
444
|
+
[Requests](http://docs.python-requests.org/).
|
|
445
|
+
|
|
446
|
+
```bash
|
|
447
|
+
python tests/runtests.py -l requests ./specifications/json-ld-api/tests
|
|
448
|
+
```
|
|
449
|
+
|
|
450
|
+
An EARL report can be generated using the `-e` or `--earl` option.
|
|
451
|
+
|
|
452
|
+
```bash
|
|
453
|
+
python tests/runtests.py -e ./earl-report.json
|
|
454
|
+
```
|
|
455
|
+
|
|
456
|
+
## License
|
|
457
|
+
|
|
458
|
+
BSD-3-Clause license
|
|
459
|
+
See [`LICENSE`](./LICENSE) file for details.
|
|
460
|
+
|
|
461
|
+
## Maintainers
|
|
462
|
+
|
|
463
|
+
The PyLD library is maintained by [Miel Vander
|
|
464
|
+
Sande](https://github.com/mielvds), [Anatoly
|
|
465
|
+
Scherbakov](https://github.com/anatoly-scherbakov) and [Digital
|
|
466
|
+
Bazaar](https://github.com/digitalbazaar) (Original authors of `PyLD`).
|