The fluree package runs the Fluree engine inside your Python process: no
server to start, and the same engine the server and CLI run. This page gets
you started and shows how the rest of this book reads from Python. The
Python documentation has a guide to the
whole package and its API reference, and each class and method carries its
documentation for help() and your editor.
pip install fluree # or "fluree[pandas]", "fluree[polars]"Wheels are published for Linux (x86-64 and arm64, glibc 2.28 or later), macOS 14 or later on Apple silicon, and Windows (x86-64), for CPython 3.10 and later. The package version is the version of the engine inside it.
import fluree
with fluree.connect("./data") as conn: # or fluree.connect(":memory:")
people = conn.create("people")
people.insert("""
@prefix ex: <http://example.org/> .
ex:alice ex:name "Alice" ; ex:age 42 .
""")
commit = people.insert({
"@context": {"ex": "http://example.org/"},
"@id": "ex:bob", "ex:name": "Bob", "ex:age": 37,
})
rows = people.select("""
PREFIX ex: <http://example.org/>
SELECT ?name ?age WHERE { ?s ex:name ?name ; ex:age ?age } ORDER BY ?name
""")
for name, age in rows:
print(name, age) # Alice 42, then Bob 37: native str and int
# Every past state stays queryable.
before_bob = people.at(t=commit.t - 1)
print(before_bob.query("PREFIX ex: <http://example.org/> ASK { ex:bob ?p ?o }")) # Falseconn.ledger("people") opens an existing ledger. Results come back as Python
values: int, Decimal, datetime, str, and fluree.IRI for IRIs. A
result converts to a DataFrame with to_pandas() or to_polars().
The queries and transactions in this book work as written. A SPARQL, JSON-LD
or Cypher query that a page sends to the server goes to ledger.query(), and a
transaction body goes to insert(), upsert() or update():
| In this book | From Python |
|---|---|
| Query: JSON-LD, SPARQL or Cypher | ledger.query(query), or ledger.select(query) for a table |
A query whose FROM names ledgers (datasets) |
conn.query(query) |
| Insert, upsert, update | ledger.insert(data), ledger.upsert(data), ledger.update(txn) |
| Sync a graph to a payload | ledger.sync(data, graph=...) |
Time travel (t, ISO time, commit) |
ledger.at(t=..., time=..., commit=...) |
| Branching | ledger.branch(name), merge(), rebase(), revert() |
Policy options (identity, policyClass, ...) |
ledger.with_policy(identity=..., policy_class=...) |
| Ledger configuration | ledger.update(...) writing the config graph |
| Full-text and vector search | ledger.set_full_text(...), fluree.Vector, and the query functions |
| Graph sources: Iceberg, Delta, SQL | conn.map_iceberg(...), conn.map_delta(...), conn.map_sql(...) |
| Export, and archives | ledger.export(...), ledger.archive(path), conn.restore(path, name) |
| Connection configuration (S3, DynamoDB, encryption) | fluree.connect(config={...}) |
A few things differ from the server:
- Policy belongs to the handle. Choose it with
ledger.with_policy(...). A query or write that names its own policy (JSON-LDopts, a SPARQL# PRAGMA) is refused, so a query passed in from elsewhere cannot widen what the handle sees. - A ledger's query reads that ledger. A query that names other ledgers
goes to
conn.query(). - Several writes can be one commit.
with ledger.transaction() as txn:stages writes in any language together, andledger.transact(fn)runs read-then-write work again when another commit lands first. - Parameters.
query(),update()andstream()take values by name, from a dict or keyword arguments:ledger.query("... $name ...", name="Alice").
fluree.aio is the same API with coroutines, for FastAPI and other asyncio
applications. Cancelling a task stops its query in the engine:
import fluree.aio
async with fluree.aio.connect("./data") as conn:
people = await conn.ledger("people")
rows = await people.query("SELECT ...")fluree.doc.read reads one document with an extraction model reached over
HTTP, exactly as fluree doc read does: it
parses the file (PDF, Word, PowerPoint, HTML, Markdown, text, spreadsheets,
transcripts, email), sends its text and structure with your ontology and
catalog, and returns the reading, which inserts into a ledger as it is:
import fluree
reading = fluree.doc.read("invoice.pdf", ontology="invoices.ttl",
catalog="suppliers.ttl", model="reader-small")
print(reading.usage.note) # 1,032 tokens
for m in reading.mentions(): # text, begin, end, entity, element
print(m["text"], "->", m["entity"])
with fluree.connect("./data") as conn:
conn.create("invoices").insert(reading.to_jsonld())text= reads a string instead of a file, under an IRI derived from its
content unless doc_iri= names one; catalog takes a list of files, each
optionally (file, class IRI); to_turtle() and claims() give the reading
as Turtle and as rows. Offsets index the parser's text (what
fluree doc parse --format text prints), not the file's bytes. The rows read
NIF offsets and the pipeline's doc: terms; a reader writing terms of its own
keeps them, as written, in reading.nodes and to_jsonld().
The credential: api_key with auth_header is sent as is to url;
api_key alone is traded for an hour's token when it is a Fluree.ai API key
(flk_…) and sent as a bearer token otherwise; with no key, this machine's
fluree login, else FLUREE_AI_API_KEY, each only to its own service (a
url elsewhere is called with no credential). With cache_dir, a request
read once is answered from there afterwards. Python does no vision
escalation: pages the parser can't read are listed in reading.notes.
- The Python guide for the whole package (results, transactions, Cypher, search, graph sources, branches, errors, logging and concurrency) and the API reference.
- Concepts for how Fluree works.
- Guides for task-oriented recipes; their queries run
unchanged through
ledger.query().