pacific-solid 0.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.
Files changed (98) hide show
  1. pacific_solid-0.1.0/.claude/settings.local.json +16 -0
  2. pacific_solid-0.1.0/.github/workflows/ci.yml +76 -0
  3. pacific_solid-0.1.0/.gitignore +36 -0
  4. pacific_solid-0.1.0/CLAUDE.md +21 -0
  5. pacific_solid-0.1.0/LICENSE +21 -0
  6. pacific_solid-0.1.0/PKG-INFO +389 -0
  7. pacific_solid-0.1.0/README.md +349 -0
  8. pacific_solid-0.1.0/docker-compose.yml +6 -0
  9. pacific_solid-0.1.0/docs/hackathon/index.html +699 -0
  10. pacific_solid-0.1.0/docs/hackathon/sovereign-modules-brief.html +318 -0
  11. pacific_solid-0.1.0/docs/hackathon/sovereign-modules-brief.md +156 -0
  12. pacific_solid-0.1.0/docs/protocol/n3-patch.md +68 -0
  13. pacific_solid-0.1.0/docs/protocol/solid-client-requirements.json +1333 -0
  14. pacific_solid-0.1.0/docs/protocol/solid-notifications.md +100 -0
  15. pacific_solid-0.1.0/docs/protocol/solid-oidc.md +52 -0
  16. pacific_solid-0.1.0/docs/protocol/solid-protocol.md +112 -0
  17. pacific_solid-0.1.0/docs/protocol/web-access-control.md +94 -0
  18. pacific_solid-0.1.0/docs/protocol/webid-profile.md +43 -0
  19. pacific_solid-0.1.0/docs/research/gov-federated-graphs-lit-review.md +120 -0
  20. pacific_solid-0.1.0/explore_protocol.py +510 -0
  21. pacific_solid-0.1.0/pacific_solid/__init__.py +175 -0
  22. pacific_solid-0.1.0/pacific_solid/_acl/__init__.py +0 -0
  23. pacific_solid-0.1.0/pacific_solid/_acl/acp.py +47 -0
  24. pacific_solid-0.1.0/pacific_solid/_acl/grant.py +22 -0
  25. pacific_solid-0.1.0/pacific_solid/_acl/modes.py +8 -0
  26. pacific_solid-0.1.0/pacific_solid/_acl/wac.py +195 -0
  27. pacific_solid-0.1.0/pacific_solid/_auth/__init__.py +0 -0
  28. pacific_solid-0.1.0/pacific_solid/_auth/auth_code.py +141 -0
  29. pacific_solid-0.1.0/pacific_solid/_auth/credentials.py +74 -0
  30. pacific_solid-0.1.0/pacific_solid/_auth/dpop.py +238 -0
  31. pacific_solid-0.1.0/pacific_solid/_auth/oidc.py +27 -0
  32. pacific_solid-0.1.0/pacific_solid/_auth/pod.py +285 -0
  33. pacific_solid-0.1.0/pacific_solid/_auth/session.py +240 -0
  34. pacific_solid-0.1.0/pacific_solid/_auth/token_validation.py +183 -0
  35. pacific_solid-0.1.0/pacific_solid/_discovery/__init__.py +0 -0
  36. pacific_solid-0.1.0/pacific_solid/_discovery/storage.py +123 -0
  37. pacific_solid-0.1.0/pacific_solid/_graph/__init__.py +0 -0
  38. pacific_solid-0.1.0/pacific_solid/_graph/graph.py +263 -0
  39. pacific_solid-0.1.0/pacific_solid/_graph/triple.py +68 -0
  40. pacific_solid-0.1.0/pacific_solid/_http/__init__.py +0 -0
  41. pacific_solid-0.1.0/pacific_solid/_http/client.py +131 -0
  42. pacific_solid-0.1.0/pacific_solid/_http/errors.py +62 -0
  43. pacific_solid-0.1.0/pacific_solid/_http/headers.py +123 -0
  44. pacific_solid-0.1.0/pacific_solid/_http/tls.py +37 -0
  45. pacific_solid-0.1.0/pacific_solid/_identity/__init__.py +0 -0
  46. pacific_solid-0.1.0/pacific_solid/_identity/webid.py +109 -0
  47. pacific_solid-0.1.0/pacific_solid/_ldn/__init__.py +0 -0
  48. pacific_solid-0.1.0/pacific_solid/_ldn/inbox.py +180 -0
  49. pacific_solid-0.1.0/pacific_solid/_model/__init__.py +0 -0
  50. pacific_solid-0.1.0/pacific_solid/_model/base.py +40 -0
  51. pacific_solid-0.1.0/pacific_solid/_model/decorator.py +238 -0
  52. pacific_solid-0.1.0/pacific_solid/_model/fields.py +36 -0
  53. pacific_solid-0.1.0/pacific_solid/_notifications/__init__.py +0 -0
  54. pacific_solid-0.1.0/pacific_solid/_notifications/discovery.py +138 -0
  55. pacific_solid-0.1.0/pacific_solid/_notifications/message.py +111 -0
  56. pacific_solid-0.1.0/pacific_solid/_notifications/safety.py +95 -0
  57. pacific_solid-0.1.0/pacific_solid/_notifications/subscription.py +128 -0
  58. pacific_solid-0.1.0/pacific_solid/_notifications/websocket.py +61 -0
  59. pacific_solid-0.1.0/pacific_solid/_rdf/__init__.py +0 -0
  60. pacific_solid-0.1.0/pacific_solid/_rdf/namespaces.py +49 -0
  61. pacific_solid-0.1.0/pacific_solid/_rdf/parse.py +48 -0
  62. pacific_solid-0.1.0/pacific_solid/_rdf/patch.py +256 -0
  63. pacific_solid-0.1.0/pacific_solid/_rdf/serialize.py +50 -0
  64. pacific_solid-0.1.0/pacific_solid/py.typed +0 -0
  65. pacific_solid-0.1.0/people/__init__.py +11 -0
  66. pacific_solid-0.1.0/pyproject.toml +62 -0
  67. pacific_solid-0.1.0/ruff.toml +21 -0
  68. pacific_solid-0.1.0/tests/__init__.py +0 -0
  69. pacific_solid-0.1.0/tests/e2e/__init__.py +0 -0
  70. pacific_solid-0.1.0/tests/e2e/conftest.py +153 -0
  71. pacific_solid-0.1.0/tests/e2e/test_smoke.py +349 -0
  72. pacific_solid-0.1.0/tests/unit/__init__.py +0 -0
  73. pacific_solid-0.1.0/tests/unit/test_acp_detection.py +41 -0
  74. pacific_solid-0.1.0/tests/unit/test_auth_code.py +198 -0
  75. pacific_solid-0.1.0/tests/unit/test_dpop.py +163 -0
  76. pacific_solid-0.1.0/tests/unit/test_errors.py +71 -0
  77. pacific_solid-0.1.0/tests/unit/test_graph.py +198 -0
  78. pacific_solid-0.1.0/tests/unit/test_headers.py +100 -0
  79. pacific_solid-0.1.0/tests/unit/test_hostile_client.py +387 -0
  80. pacific_solid-0.1.0/tests/unit/test_hostile_server.py +473 -0
  81. pacific_solid-0.1.0/tests/unit/test_jsonld_parse.py +95 -0
  82. pacific_solid-0.1.0/tests/unit/test_ldn.py +258 -0
  83. pacific_solid-0.1.0/tests/unit/test_model.py +210 -0
  84. pacific_solid-0.1.0/tests/unit/test_namespaces.py +30 -0
  85. pacific_solid-0.1.0/tests/unit/test_notification_discovery.py +120 -0
  86. pacific_solid-0.1.0/tests/unit/test_notification_message.py +144 -0
  87. pacific_solid-0.1.0/tests/unit/test_notification_safety.py +75 -0
  88. pacific_solid-0.1.0/tests/unit/test_notification_subscribe.py +135 -0
  89. pacific_solid-0.1.0/tests/unit/test_patch_builder.py +58 -0
  90. pacific_solid-0.1.0/tests/unit/test_storage_discovery.py +226 -0
  91. pacific_solid-0.1.0/tests/unit/test_tls.py +34 -0
  92. pacific_solid-0.1.0/tests/unit/test_token_validation.py +302 -0
  93. pacific_solid-0.1.0/tests/unit/test_triple.py +106 -0
  94. pacific_solid-0.1.0/tests/unit/test_wac.py +111 -0
  95. pacific_solid-0.1.0/tests/unit/test_wac_groups_external.py +109 -0
  96. pacific_solid-0.1.0/tests/unit/test_wac_origin.py +136 -0
  97. pacific_solid-0.1.0/tests/unit/test_webid_extended.py +224 -0
  98. pacific_solid-0.1.0/tests/unit/test_where_clause.py +108 -0
@@ -0,0 +1,16 @@
1
+ {
2
+ "permissions": {
3
+ "allow": [
4
+ "WebFetch(domain:solid.github.io)",
5
+ "WebFetch(domain:solidproject.org)",
6
+ "Bash(python3 -m ruff check people/ tests/)",
7
+ "Bash(pip3 install:*)",
8
+ "Bash(python3 -m ruff check people/ tests/ --fix)",
9
+ "Bash(python3 -m pytest tests/unit/ -v --tb=short)",
10
+ "WebFetch(domain:scholar.google.com)",
11
+ "WebFetch(domain:www.tandfonline.com)",
12
+ "WebFetch(domain:link.springer.com)",
13
+ "WebFetch(domain:www.sciencedirect.com)"
14
+ ]
15
+ }
16
+ }
@@ -0,0 +1,76 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ branches: [main]
8
+
9
+ jobs:
10
+ lint:
11
+ runs-on: ubuntu-latest
12
+ steps:
13
+ - uses: actions/checkout@v4
14
+ - uses: actions/setup-python@v5
15
+ with:
16
+ python-version: "3.13"
17
+ - run: pip install ruff
18
+ - run: ruff check .
19
+
20
+ typecheck:
21
+ runs-on: ubuntu-latest
22
+ steps:
23
+ - uses: actions/checkout@v4
24
+ - uses: actions/setup-python@v5
25
+ with:
26
+ python-version: "3.13"
27
+ - run: pip install -e ".[dev]"
28
+ - run: mypy people/ --ignore-missing-imports
29
+
30
+ unit:
31
+ runs-on: ubuntu-latest
32
+ strategy:
33
+ matrix:
34
+ python-version: ["3.11", "3.12", "3.13"]
35
+ steps:
36
+ - uses: actions/checkout@v4
37
+ - uses: actions/setup-python@v5
38
+ with:
39
+ python-version: ${{ matrix.python-version }}
40
+ - run: pip install -e ".[dev]"
41
+ - run: pytest tests/unit/ -v
42
+
43
+ e2e:
44
+ runs-on: ubuntu-latest
45
+ services:
46
+ css:
47
+ image: solidproject/community-server:latest
48
+ ports:
49
+ - 3000:3000
50
+ options: >-
51
+ --health-cmd "curl -f http://localhost:3000/ || exit 1"
52
+ --health-interval 5s
53
+ --health-timeout 5s
54
+ --health-retries 10
55
+ steps:
56
+ - uses: actions/checkout@v4
57
+ - uses: actions/setup-python@v5
58
+ with:
59
+ python-version: "3.13"
60
+ - run: pip install -e ".[dev]"
61
+ - run: pytest tests/e2e/ -v
62
+
63
+ publish:
64
+ if: startsWith(github.ref, 'refs/tags/v')
65
+ needs: [lint, typecheck, unit, e2e]
66
+ runs-on: ubuntu-latest
67
+ permissions:
68
+ id-token: write
69
+ steps:
70
+ - uses: actions/checkout@v4
71
+ - uses: actions/setup-python@v5
72
+ with:
73
+ python-version: "3.13"
74
+ - run: pip install build
75
+ - run: python -m build
76
+ - uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,36 @@
1
+
2
+ # Python
3
+ __pycache__/
4
+ *.py[cod]
5
+ *$py.class
6
+ *.egg-info/
7
+ dist/
8
+ build/
9
+ .eggs/
10
+ *.egg
11
+
12
+ # Virtual environments
13
+ .venv/
14
+ venv/
15
+ ENV/
16
+
17
+ # IDE
18
+ .idea/
19
+ .vscode/
20
+ *.swp
21
+ *.swo
22
+
23
+ # OS
24
+ .DS_Store
25
+ Thumbs.db
26
+
27
+ # Testing
28
+ .pytest_cache/
29
+ .coverage
30
+ htmlcov/
31
+ .mypy_cache/
32
+ .gopacific
33
+
34
+ # Distribution
35
+ *.tar.gz
36
+ *.whl
@@ -0,0 +1,21 @@
1
+ # people
2
+
3
+ Python SDK for the Solid Project (solidproject.org). Open source, MIT license.
4
+
5
+ ## Skill routing
6
+
7
+ When the user's request matches an available skill, ALWAYS invoke it using the Skill
8
+ tool as your FIRST action. Do NOT answer directly, do NOT use other tools first.
9
+ The skill has specialized workflows that produce better results than ad-hoc answers.
10
+
11
+ Key routing rules:
12
+ - Product ideas, "is this worth building", brainstorming → invoke office-hours
13
+ - Bugs, errors, "why is this broken", 500 errors → invoke investigate
14
+ - Ship, deploy, push, create PR → invoke ship
15
+ - QA, test the site, find bugs → invoke qa
16
+ - Code review, check my diff → invoke review
17
+ - Update docs after shipping → invoke document-release
18
+ - Weekly retro → invoke retro
19
+ - Design system, brand → invoke design-consultation
20
+ - Visual audit, design polish → invoke design-review
21
+ - Architecture review → invoke plan-eng-review
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright 2026 Pacific
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,389 @@
1
+ Metadata-Version: 2.4
2
+ Name: pacific-solid
3
+ Version: 0.1.0
4
+ Summary: The Python SDK for the Solid Project
5
+ Project-URL: Homepage, https://github.com/Pacific-Systems-Ltd/people
6
+ Project-URL: Issues, https://github.com/Pacific-Systems-Ltd/people/issues
7
+ Author: Pacific
8
+ License-Expression: MIT
9
+ License-File: LICENSE
10
+ Classifier: Development Status :: 3 - Alpha
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: License :: OSI Approved :: MIT License
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.11
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Classifier: Programming Language :: Python :: 3.13
17
+ Classifier: Topic :: Internet :: WWW/HTTP
18
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
19
+ Requires-Python: >=3.11
20
+ Requires-Dist: cryptography>=42.0
21
+ Requires-Dist: httpx>=0.27
22
+ Requires-Dist: pyjwt[crypto]>=2.8
23
+ Requires-Dist: rdflib>=7.0
24
+ Requires-Dist: websockets>=13.0
25
+ Provides-Extra: all
26
+ Requires-Dist: networkx>=3.0; extra == 'all'
27
+ Requires-Dist: pandas>=2.0; extra == 'all'
28
+ Provides-Extra: dev
29
+ Requires-Dist: hypothesis>=6.0; extra == 'dev'
30
+ Requires-Dist: mypy>=1.10; extra == 'dev'
31
+ Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
32
+ Requires-Dist: pytest>=8.0; extra == 'dev'
33
+ Requires-Dist: respx>=0.21; extra == 'dev'
34
+ Requires-Dist: ruff>=0.4; extra == 'dev'
35
+ Provides-Extra: pandas
36
+ Requires-Dist: pandas>=2.0; extra == 'pandas'
37
+ Provides-Extra: science
38
+ Requires-Dist: networkx>=3.0; extra == 'science'
39
+ Description-Content-Type: text/markdown
40
+
41
+ <p align="right">
42
+ <img src="https://solidproject.org/assets/img/solid-emblem.svg" alt="Solid logo" height="120">
43
+ </p>
44
+
45
+ # pacific-solid
46
+
47
+ [![PyPI](https://img.shields.io/pypi/v/pacific-solid.svg)](https://pypi.org/project/pacific-solid/)
48
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
49
+ [![Python 3.11+](https://img.shields.io/badge/python-3.11%2B-blue.svg)](https://www.python.org/downloads/)
50
+ [![Solid Protocol](https://img.shields.io/badge/Solid_Protocol-v0.11-green.svg)](https://solidproject.org/TR/protocol)
51
+
52
+ **The Python SDK for the [Solid Project](https://solidproject.org). From [gopacific.ai](www.gopacific.ai).**
53
+
54
+ [Python](https://www.python.org) is the world's most popular programming language: the lingua franca of machine learning and data science. [Solid](https://solidproject.org/about) is [Tim Berners-Lee](https://en.wikipedia.org/wiki/Tim_Berners-Lee)'s architecture for a world where people control their own data. Created by the inventor of the [World Wide Web](https://en.wikipedia.org/wiki/World_Wide_Web), now stewarded by the [Open Data Institute](https://theodi.org/). The pacific-solid SDK connects them together.
55
+
56
+
57
+ ## What you can build with this
58
+
59
+ ### Citizen Digital Sovereignty
60
+
61
+ 6.5 million Belgian citizens control their data with Solid. [Athumi](https://www.inrupt.com/case-study/flanders-strengthens-trusted-data-economy) was created by the Flemish government as Europe's first data utility company: a feduciary for the selective disclosure of personal data to government, employers, and businesses.
62
+
63
+ ```python
64
+ # 1. Applicant grants Randstad read access to their diploma
65
+ await applicant_session.grant(
66
+ resource="https://pods.athumi.be/citizen-12345/credentials/diploma",
67
+ agent="https://randstad.be/solid/profile#id",
68
+ modes=[AccessMode.READ],
69
+ )
70
+
71
+ # 2. Randstad reads the credential from the applicant's pod
72
+ credential = await randstad_session.read(
73
+ "https://pods.athumi.be/citizen-12345/credentials/diploma",
74
+ VerifiedCredential,
75
+ )
76
+
77
+ # 3. Verify and act
78
+ if credential.issuer == "https://kuleuven.be" and credential.valid:
79
+ approve_application(candidate)
80
+ ```
81
+
82
+ Randstad uses Solid to [digitise the validation process for academic records](https://www.bbc.co.uk/news/business-68286395). This removes friction in the job market, helping people find work more easily. Meanwhile, citizens remain in control of their data. With pacific-solid, Python developers have easy access to the same toolkit.
83
+
84
+
85
+ ### Patient record portability
86
+
87
+ The [NHS has piloted](https://www.janeirodigital.com/blog/janeiro-digital-at-solid-world-nhs-personal-health-stores-with-xform-health-and-solid/) patient-controlled health records on Solid, and the Solid community is actively working on FHIR RDF in pods. When patients move between services, their medical history should move with them. No data migration, no lost history, fewer patients slipping through the gaps.
88
+
89
+ ```python
90
+ patient = await session.read(
91
+ "https://pods.nhs.uk/jane-doe/medical/summary",
92
+ PatientSummary,
93
+ )
94
+ patient.conditions.append(new_diagnosis)
95
+ await session.update(patient) # Patient controls who else can see this
96
+ ```
97
+
98
+ Python is the [dominant language](https://www.unosquare.com/blog/programming-languages-for-biotech-from-drug-discovery-ai-to-clinical-systems/) for health data science, clinical research, and ML. This SDK links those pipelines to the Solid ecosystem.
99
+
100
+
101
+ ### Solid is the bedrock of the gopacific sovereign graph
102
+
103
+ Solid is the core of [gopacific's](https://gopacific.ai) organisational intelligence engine. When users interact in a gopacific network, Solid's disclosure mechanics ensure that sensitive data remain under their owners' control. We built this SDK to unlock the power of the Solid protocol for the Python community.
104
+
105
+
106
+ ## Getting started
107
+
108
+ pacific-solid requires [Python](https://www.python.org/downloads/) 3.11 or higher.
109
+
110
+ ```bash
111
+ pip install pacific-solid
112
+ ```
113
+
114
+ ### Dependencies
115
+
116
+ | Package | Purpose |
117
+ |---------|---------|
118
+ | [httpx](https://www.python-httpx.org/) | Async HTTP client |
119
+ | [rdflib](https://rdflib.readthedocs.io/) | RDF parsing and serialization (wrapped internally, never exposed) |
120
+ | [PyJWT](https://pyjwt.readthedocs.io/) | DPoP proof-of-possession token generation |
121
+ | [cryptography](https://cryptography.io/) | EC key pair generation for DPoP |
122
+
123
+
124
+ ## Quick start
125
+
126
+ ### 1. Start a Solid server
127
+
128
+ For local development, run the open-source [Community Solid Server](https://github.com/CommunitySolidServer/CommunitySolidServer) in Docker:
129
+
130
+ ```bash
131
+ docker run --rm -d -p 3000:3000 solidproject/community-server:latest -b http://localhost:3000
132
+ ```
133
+
134
+ Open http://localhost:3000, sign up for an account, create a pod, and generate client credentials from the account page. In production, you would point at a hosted Solid provider like [solidcommunity.net](https://solidcommunity.net/) or your organization's own server.
135
+
136
+ ### 2. Authenticate and explore a pod
137
+
138
+ ```python
139
+ import asyncio
140
+ import pacific_solid as ps
141
+
142
+ async def main():
143
+ # Login once, reuse. ps = "personal store"
144
+ me = await ps.login(
145
+ issuer="http://localhost:3000",
146
+ client_id="YOUR_CLIENT_ID",
147
+ client_secret="YOUR_CLIENT_SECRET",
148
+ )
149
+
150
+ # Scope to a pod for relative-path access
151
+ alice = me.pod("http://localhost:3000/my-pod/")
152
+
153
+ # List everything in the pod
154
+ resources = await alice.list("")
155
+ for url in resources:
156
+ print(url)
157
+
158
+ asyncio.run(main())
159
+ ```
160
+
161
+ Authentication handles the full [Solid-OIDC](https://solidproject.org/TR/oidc) flow with DPoP proof-of-possession automatically. Every subsequent request is authenticated. Tokens are refreshed transparently.
162
+
163
+ ### 3. Define a model and work with data
164
+
165
+ ```python
166
+ import pacific_solid as ps
167
+ from pacific_solid import SCHEMA
168
+
169
+ @ps.model
170
+ class Note:
171
+ rdf_type = SCHEMA.NoteDigitalDocument
172
+ title: str = ps.field(SCHEMA.name)
173
+ body: str = ps.field(SCHEMA.text)
174
+ tags: list[str] = ps.field(SCHEMA.keywords, multiple=True)
175
+
176
+ # Create a note in a pod
177
+ note = Note(title="Hello Solid", body="My first note from Python.", tags=["solid", "python"])
178
+ url = await alice.create("notes/", note.graph, slug="hello")
179
+
180
+ # Read it back as a typed Python object
181
+ note = Note.from_graph(await alice.read(url))
182
+ print(note.title) # "Hello Solid"
183
+
184
+ # Modify and patch (only changed fields are sent via N3 Patch)
185
+ note.tags.append("decentralized")
186
+ await alice.patch(url, note.graph)
187
+
188
+ # Delete
189
+ await alice.delete(url)
190
+ ```
191
+
192
+ No raw triples. No manual Turtle construction. Python objects in, Python objects out.
193
+
194
+ ## Why Python needs Solid. Why Solid needs Python.
195
+
196
+ Solid stores data as [RDF](https://www.w3.org/RDF/), a graph-based data model built on open W3C standards. Python already has the richest ecosystem for working with graph data, linked data, and knowledge graphs through libraries like rdflib, NetworkX, and the scientific Python stack.
197
+
198
+ Until now, the Solid SDK ecosystem has been a [JavaScript monoculture](https://docs.inrupt.com/developer-tools/javascript/client-libraries/). Inrupt maintains production-grade JS/TS and Java SDKs. Every other language, Python included, has had either fragmented community efforts or nothing at all. Authentication alone (Solid-OIDC with DPoP) has been the barrier that kills non-JS implementations. The [Solid Community Forum](https://forum.solidproject.org/) has years of threads from Python developers who couldn't get past it.
199
+
200
+ pacific-solid changes that.
201
+
202
+ | Python brings to Solid | Solid brings to Python |
203
+ |----------------------|----------------------|
204
+ | The dominant language in health data, bioinformatics, and clinical pipelines | Patient-controlled health records that Python pipelines can read with consent |
205
+ | Data science and ML on structured, linked data | Personal data stores that never leave the user's control |
206
+ | The world's largest developer community | A W3C-backed protocol for reading and writing linked data across organizational boundaries |
207
+ | AI agent frameworks that need somewhere to store knowledge | Sovereign knowledge graphs that agents populate, users own, and teams share |
208
+ | Automation and scripting for backend services | Decentralized authentication that works across providers |
209
+ | Mature RDF tooling (rdflib, 2400+ stars, 914K weekly downloads) | A reason for that tooling to exist beyond academic research |
210
+
211
+ ## Features
212
+
213
+ ### Three concepts
214
+
215
+ ```python
216
+ import pacific_solid as ps # ps = "personal store"
217
+
218
+ me = await ps.login(...) # Session: who you are
219
+ alice = me.pod("https://pod/alice/") # Pod: what you're looking at
220
+ graph = await alice.read("notes/") # Graph: the data
221
+ ```
222
+
223
+ **Session** is your authenticated identity. Login once, reuse for any pod.
224
+ **Pod** is a scoped view onto a remote pod with relative paths.
225
+ **Graph** is a set of triples you can query, convert, and diff.
226
+
227
+ ### Five methods, five HTTP verbs
228
+
229
+ ```python
230
+ graph = await alice.read("notes/hello") # GET
231
+ await alice.write("notes/hello", graph) # PUT (full replace)
232
+ await alice.patch("notes/hello", note.graph) # PATCH (N3 Patch from diff)
233
+ url = await alice.create("notes/", graph) # POST (new resource)
234
+ await alice.delete("notes/hello") # DELETE
235
+ ```
236
+
237
+ No auto-detection between PUT and PATCH. The SDK does what you ask, explicitly.
238
+
239
+ ### Typed models (optional)
240
+
241
+ Define Python classes that map to RDF predicates. The `@ps.model` decorator adds graph-awareness and snapshot-based dirty tracking.
242
+
243
+ ```python
244
+ @ps.model
245
+ class Person:
246
+ rdf_type = ps.FOAF.Person
247
+ name: str = ps.field(ps.FOAF.name)
248
+ email: str = ps.field(ps.FOAF.mbox)
249
+ knows: list[str] = ps.field(ps.FOAF.knows, multiple=True)
250
+
251
+ person = Person.from_graph(await alice.read("profile/card"))
252
+ person.name = "Alice Smith"
253
+ await alice.patch("profile/card", person.graph) # Patches only the name triple
254
+ ```
255
+
256
+ Missing fields return `None` for scalars, `[]` for lists. Type checking is strict by default and configurable per-read with `strict=False`.
257
+
258
+ ### Access control
259
+
260
+ Permissions are just graphs at `.acl` URLs. Grant or revoke access for specific agents, groups, or the public.
261
+
262
+ ```python
263
+ # Shorthand
264
+ await alice.grant("health/gp-records", agent=dr_patel, modes=[ps.Read])
265
+ await alice.revoke("health/gp-records", agent=dr_patel)
266
+
267
+ # Or read the ACL graph directly
268
+ acl = await alice.read(graph.acl_url)
269
+ for grant in acl.all(ps.Grant):
270
+ print(grant.agent, grant.modes)
271
+ ```
272
+
273
+ ### WebID discovery
274
+
275
+ Resolve a WebID URI to discover OIDC issuers and pod storage URLs.
276
+
277
+ ```python
278
+ profile = await me.resolve("https://pods.example/alice/profile/card#me")
279
+ print(profile.issuers) # ["https://solid-server.example/"]
280
+ print(profile.storages) # ["https://pods.example/alice/"]
281
+ ```
282
+
283
+ ### Graph converters
284
+
285
+ ```python
286
+ graph.to_dict() # always available
287
+ graph.to_dataframe() # pip install pacific-solid[pandas]
288
+ graph.to_networkx() # pip install pacific-solid[science]
289
+ ```
290
+
291
+ ### Debug logging
292
+
293
+ Every HTTP request, DPoP proof, token refresh, and retry is logged via Python's standard `logging` module.
294
+
295
+ ```python
296
+ import logging
297
+ logging.getLogger("pacific_solid").setLevel(logging.DEBUG)
298
+ ```
299
+
300
+ ## Specifications
301
+
302
+ pacific-solid implements:
303
+
304
+ | Specification | Version | Coverage |
305
+ |--------------|---------|----------|
306
+ | [Solid Protocol](https://solidproject.org/TR/protocol) | 0.11 | CRUD, LDP Containers, Content Negotiation, N3 Patch |
307
+ | [Solid-OIDC](https://solidproject.org/TR/oidc) | Draft | Client credentials + DPoP |
308
+ | [Web Access Control](https://solid.github.io/web-access-control-spec/) | 1.0 | Read, write, inherited ACLs |
309
+ | [WebID Profile](https://solid.github.io/webid-profile/) | Draft | OIDC issuer and storage discovery |
310
+
311
+ ACP (Access Control Policy), Solid Notifications, and JSON-LD content negotiation are planned for future releases.
312
+
313
+ ## Architecture
314
+
315
+ ```
316
+ pacific_solid/
317
+ _auth/ Session, Pod, Solid-OIDC, DPoP proof generation + verification, credentials
318
+ _graph/ Graph, Triple, URI, Literal, dict/pandas/networkx converters
319
+ _rdf/ Turtle parse/serialize (rdflib wrapper), N3 Patch builder, namespace constants
320
+ _model/ @ps.model decorator, ps.field(), snapshot-based dirty tracking
321
+ _acl/ WAC evaluation, Grant model, access modes
322
+ _identity/ WebID profile resolution, OIDC issuer + storage discovery
323
+ _http/ Authenticated httpx client, Link/WAC-Allow/ETag header parsing, error hierarchy
324
+ ```
325
+
326
+ Leading underscores = private implementation. The public API is re-exported from `__init__.py`. Users import from `pacific_solid`, never from internal packages.
327
+
328
+ rdflib is used internally for RDF parsing and serialization but is never exposed in the public API. The abstraction layer allows the RDF backend to be swapped (e.g. to Oxigraph) without breaking changes.
329
+
330
+ ## Development
331
+
332
+ ```bash
333
+ git clone https://github.com/Pacific-Systems-Ltd/people.git
334
+ cd people
335
+ pip install -e ".[dev]"
336
+ ```
337
+
338
+ ### Running tests
339
+
340
+ Unit tests (including adversarial/hostile tests) run instantly with no external dependencies. E2E tests run against a real [Community Solid Server](https://github.com/CommunitySolidServer/CommunitySolidServer) in Docker.
341
+
342
+ ```bash
343
+ # Unit tests (181 tests, ~2 seconds)
344
+ pytest tests/unit/
345
+
346
+ # E2E tests (requires Docker)
347
+ docker compose up -d
348
+ pytest tests/e2e/
349
+
350
+ # Everything
351
+ docker compose up -d
352
+ pytest
353
+
354
+ # Lint and type check
355
+ ruff check .
356
+ mypy pacific_solid/
357
+ ```
358
+
359
+ ### Test structure
360
+
361
+ ```
362
+ tests/
363
+ unit/
364
+ test_triple.py URI, Literal, Triple primitives
365
+ test_graph.py Graph CRUD, query, snapshot, Turtle round-trip
366
+ test_model.py @ps.model, field mapping, dirty tracking, Grant model
367
+ test_dpop.py DPoP generation + verification round-trip
368
+ test_wac.py WAC evaluation logic
369
+ test_patch_builder.py N3 Patch construction
370
+ test_headers.py Link, WAC-Allow, ETag parsing
371
+ test_errors.py Error hierarchy, status code mapping
372
+ test_namespaces.py Vocabulary constants
373
+ test_hostile_server.py Malicious server responses, header attacks, auth manipulation
374
+ test_hostile_client.py DPoP forgery, WAC bypass, N3 Patch injection
375
+ e2e/
376
+ test_smoke.py Full CRUD + Patch + WAC + WebID against real CSS
377
+ ```
378
+
379
+ ## Feedback and contributions
380
+
381
+ Bug reports and feature requests are welcome on [GitHub Issues](https://github.com/Pacific-Systems-Ltd/people/issues).
382
+
383
+ For questions about the Solid ecosystem, see the [Solid Community Forum](https://forum.solidproject.org/) and the [Solid Protocol specification](https://solidproject.org/TR/protocol).
384
+
385
+ ## License
386
+
387
+ pacific-solid is open source software [licensed under MIT](LICENSE).
388
+
389
+ Copyright 2026 Pacific.