Skip to main content

The Python SDK for the Solid Project

Project description

Solid logo

pacific-solid

PyPI License: MIT Python 3.11+ Solid Protocol

The Python SDK for the Solid Project. From gopacific.ai.

Python is the world's most popular programming language: the lingua franca of machine learning and data science. Solid is Tim Berners-Lee's architecture for a world where people control their own data. Created by the inventor of the World Wide Web, now stewarded by the Open Data Institute. The pacific-solid SDK connects them together.

What you can build with this

Citizen Digital Sovereignty

6.5 million Belgian citizens control their data with Solid. Athumi 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.

# 1. Applicant grants Randstad read access to their diploma
await applicant_session.grant(
    resource="https://pods.athumi.be/citizen-12345/credentials/diploma",
    agent="https://randstad.be/solid/profile#id",
    modes=[AccessMode.READ],
)

# 2. Randstad reads the credential from the applicant's pod
credential = await randstad_session.read(
    "https://pods.athumi.be/citizen-12345/credentials/diploma",
    VerifiedCredential,
)

# 3. Verify and act
if credential.issuer == "https://kuleuven.be" and credential.valid:
    approve_application(candidate)

Randstad uses Solid to digitise the validation process for academic records. 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.

Patient record portability

The NHS has piloted 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.

patient = await session.read(
    "https://pods.nhs.uk/jane-doe/medical/summary",
    PatientSummary,
)
patient.conditions.append(new_diagnosis)
await session.update(patient)  # Patient controls who else can see this

Python is the dominant language for health data science, clinical research, and ML. This SDK links those pipelines to the Solid ecosystem.

Solid is the bedrock of the gopacific sovereign graph

Solid is the core of gopacific's 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.

Getting started

pacific-solid requires Python 3.11 or higher.

pip install pacific-solid

Dependencies

Package Purpose
httpx Async HTTP client
rdflib RDF parsing and serialization (wrapped internally, never exposed)
PyJWT DPoP proof-of-possession token generation
cryptography EC key pair generation for DPoP

Quick start

1. Start a Solid server

For local development, run the open-source Community Solid Server in Docker:

docker run --rm -d -p 3000:3000 solidproject/community-server:latest -b http://localhost:3000

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 or your organization's own server.

2. Authenticate and explore a pod

import asyncio
import pacific_solid as ps

async def main():
    # Login once, reuse. ps = "personal store"
    me = await ps.login(
        issuer="http://localhost:3000",
        client_id="YOUR_CLIENT_ID",
        client_secret="YOUR_CLIENT_SECRET",
    )

    # Scope to a pod for relative-path access
    alice = me.pod("http://localhost:3000/my-pod/")

    # List everything in the pod
    resources = await alice.list("")
    for url in resources:
        print(url)

asyncio.run(main())

Authentication handles the full Solid-OIDC flow with DPoP proof-of-possession automatically. Every subsequent request is authenticated. Tokens are refreshed transparently.

3. Define a model and work with data

import pacific_solid as ps
from pacific_solid import SCHEMA

@ps.model
class Note:
    rdf_type = SCHEMA.NoteDigitalDocument
    title: str = ps.field(SCHEMA.name)
    body: str = ps.field(SCHEMA.text)
    tags: list[str] = ps.field(SCHEMA.keywords, multiple=True)

# Create a note in a pod
note = Note(title="Hello Solid", body="My first note from Python.", tags=["solid", "python"])
url = await alice.create("notes/", note.graph, slug="hello")

# Read it back as a typed Python object
note = Note.from_graph(await alice.read(url))
print(note.title)  # "Hello Solid"

# Modify and patch (only changed fields are sent via N3 Patch)
note.tags.append("decentralized")
await alice.patch(url, note.graph)

# Delete
await alice.delete(url)

No raw triples. No manual Turtle construction. Python objects in, Python objects out.

Why Python needs Solid. Why Solid needs Python.

Solid stores data as 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.

Until now, the Solid SDK ecosystem has been a JavaScript monoculture. 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 has years of threads from Python developers who couldn't get past it.

pacific-solid changes that.

Python brings to Solid Solid brings to Python
The dominant language in health data, bioinformatics, and clinical pipelines Patient-controlled health records that Python pipelines can read with consent
Data science and ML on structured, linked data Personal data stores that never leave the user's control
The world's largest developer community A W3C-backed protocol for reading and writing linked data across organizational boundaries
AI agent frameworks that need somewhere to store knowledge Sovereign knowledge graphs that agents populate, users own, and teams share
Automation and scripting for backend services Decentralized authentication that works across providers
Mature RDF tooling (rdflib, 2400+ stars, 914K weekly downloads) A reason for that tooling to exist beyond academic research

Features

Three concepts

import pacific_solid as ps          # ps = "personal store"

me = await ps.login(...)            # Session: who you are
alice = me.pod("https://pod/alice/") # Pod: what you're looking at
graph = await alice.read("notes/")  # Graph: the data

Session is your authenticated identity. Login once, reuse for any pod. Pod is a scoped view onto a remote pod with relative paths. Graph is a set of triples you can query, convert, and diff.

Five methods, five HTTP verbs

graph = await alice.read("notes/hello")          # GET
await alice.write("notes/hello", graph)           # PUT  (full replace)
await alice.patch("notes/hello", note.graph)      # PATCH (N3 Patch from diff)
url = await alice.create("notes/", graph)         # POST (new resource)
await alice.delete("notes/hello")                 # DELETE

No auto-detection between PUT and PATCH. The SDK does what you ask, explicitly.

Typed models (optional)

Define Python classes that map to RDF predicates. The @ps.model decorator adds graph-awareness and snapshot-based dirty tracking.

@ps.model
class Person:
    rdf_type = ps.FOAF.Person
    name: str = ps.field(ps.FOAF.name)
    email: str = ps.field(ps.FOAF.mbox)
    knows: list[str] = ps.field(ps.FOAF.knows, multiple=True)

person = Person.from_graph(await alice.read("profile/card"))
person.name = "Alice Smith"
await alice.patch("profile/card", person.graph)  # Patches only the name triple

Missing fields return None for scalars, [] for lists. Type checking is strict by default and configurable per-read with strict=False.

Access control

Permissions are just graphs at .acl URLs. Grant or revoke access for specific agents, groups, or the public.

# Shorthand
await alice.grant("health/gp-records", agent=dr_patel, modes=[ps.Read])
await alice.revoke("health/gp-records", agent=dr_patel)

# Or read the ACL graph directly
acl = await alice.read(graph.acl_url)
for grant in acl.all(ps.Grant):
    print(grant.agent, grant.modes)

WebID discovery

Resolve a WebID URI to discover OIDC issuers and pod storage URLs.

profile = await me.resolve("https://pods.example/alice/profile/card#me")
print(profile.issuers)   # ["https://solid-server.example/"]
print(profile.storages)  # ["https://pods.example/alice/"]

Graph converters

graph.to_dict()                         # always available
graph.to_dataframe()                    # pip install pacific-solid[pandas]
graph.to_networkx()                     # pip install pacific-solid[science]

Debug logging

Every HTTP request, DPoP proof, token refresh, and retry is logged via Python's standard logging module.

import logging
logging.getLogger("pacific_solid").setLevel(logging.DEBUG)

Specifications

pacific-solid implements:

Specification Version Coverage
Solid Protocol 0.11 CRUD, LDP Containers, Content Negotiation, N3 Patch
Solid-OIDC Draft Client credentials + DPoP
Web Access Control 1.0 Read, write, inherited ACLs
WebID Profile Draft OIDC issuer and storage discovery

ACP (Access Control Policy), Solid Notifications, and JSON-LD content negotiation are planned for future releases.

Architecture

pacific_solid/
  _auth/         Session, Pod, Solid-OIDC, DPoP proof generation + verification, credentials
  _graph/        Graph, Triple, URI, Literal, dict/pandas/networkx converters
  _rdf/          Turtle parse/serialize (rdflib wrapper), N3 Patch builder, namespace constants
  _model/        @ps.model decorator, ps.field(), snapshot-based dirty tracking
  _acl/          WAC evaluation, Grant model, access modes
  _identity/     WebID profile resolution, OIDC issuer + storage discovery
  _http/         Authenticated httpx client, Link/WAC-Allow/ETag header parsing, error hierarchy

Leading underscores = private implementation. The public API is re-exported from __init__.py. Users import from pacific_solid, never from internal packages.

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.

Development

git clone https://github.com/Pacific-Systems-Ltd/people.git
cd people
pip install -e ".[dev]"

Running tests

Unit tests (including adversarial/hostile tests) run instantly with no external dependencies. E2E tests run against a real Community Solid Server in Docker.

# Unit tests (181 tests, ~2 seconds)
pytest tests/unit/

# E2E tests (requires Docker)
docker compose up -d
pytest tests/e2e/

# Everything
docker compose up -d
pytest

# Lint and type check
ruff check .
mypy pacific_solid/

Test structure

tests/
  unit/
    test_triple.py          URI, Literal, Triple primitives
    test_graph.py           Graph CRUD, query, snapshot, Turtle round-trip
    test_model.py           @ps.model, field mapping, dirty tracking, Grant model
    test_dpop.py            DPoP generation + verification round-trip
    test_wac.py             WAC evaluation logic
    test_patch_builder.py   N3 Patch construction
    test_headers.py         Link, WAC-Allow, ETag parsing
    test_errors.py          Error hierarchy, status code mapping
    test_namespaces.py      Vocabulary constants
    test_hostile_server.py  Malicious server responses, header attacks, auth manipulation
    test_hostile_client.py  DPoP forgery, WAC bypass, N3 Patch injection
  e2e/
    test_smoke.py           Full CRUD + Patch + WAC + WebID against real CSS

Feedback and contributions

Bug reports and feature requests are welcome on GitHub Issues.

For questions about the Solid ecosystem, see the Solid Community Forum and the Solid Protocol specification.

License

pacific-solid is open source software licensed under MIT.

Copyright 2026 Pacific.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pacific_solid-0.1.0.tar.gz (123.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pacific_solid-0.1.0-py3-none-any.whl (58.9 kB view details)

Uploaded Python 3

File details

Details for the file pacific_solid-0.1.0.tar.gz.

File metadata

  • Download URL: pacific_solid-0.1.0.tar.gz
  • Upload date:
  • Size: 123.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.3

File hashes

Hashes for pacific_solid-0.1.0.tar.gz
Algorithm Hash digest
SHA256 159a555af3072fba107e268fad50055254b73ff11aba209ac3c348daa71a289c
MD5 259ecc7ff6778233490f5dec01ee20cc
BLAKE2b-256 57bd8b2650a6809a4c5810fa5adffb06266732c2db40330bffb3454705416073

See more details on using hashes here.

File details

Details for the file pacific_solid-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: pacific_solid-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 58.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.3

File hashes

Hashes for pacific_solid-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 aaae562d699f38d31d61f0d21eb0092c7b2543942c18f61f71ef4035ed137169
MD5 e8a35127213c9fe5df8454951a35447f
BLAKE2b-256 7684804b3a78e5e5028c39311b003eb444d9aabc25981db33eabc1aba2c5c1f3

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page