ouro-py
The official Python SDK for Ouro.
Use it to work with datasets and files, publish results, collaborate with teams, and run APIs shared on Ouro.
Install
pip install ouro-py
ouro-py requires Python 3.10 or later.
Quickstart
Create a Personal Access Token in your Ouro settings, then export it:
export OURO_API_KEY="your-api-key"
Create a client and start using the API:
from ouro import Ouro
ouro = Ouro()
dataset = ouro.datasets.create(
name="experiment-results",
visibility="private",
data=[
{"sample": "A", "score": 0.82},
{"sample": "B", "score": 0.91},
],
)
results = ouro.datasets.query(dataset.id)
print(results)
The client reads OURO_API_KEY from your environment or a .env file. You can also pass it
directly with Ouro(api_key="...").
Common workflows
Find assets
Datasets, posts, files, services, routes, and quests are all assets. Search across them with
ouro.assets:
results = ouro.assets.search(
"battery materials",
asset_type="dataset",
scope="global",
limit=10,
)
asset = ouro.assets.retrieve(results[0]["id"])
Search scope can be personal, org, global, or all.
Query a dataset
Dataset queries return pandas DataFrames by default:
df = ouro.datasets.query(dataset_id)
summary = ouro.datasets.query(
dataset_id,
"""
select category, avg(score) as mean_score
from {{table}}
group by category
""",
)
SQL queries are read-only. Use {{table}} as the dataset table placeholder.
Save a dataset view
A view is a saved chart. Pass a prompt and the API generates the SQL and chart config — you rarely write those by hand:
view = ouro.datasets.create_view(
dataset.id,
name="Score by sample",
prompt="Bar chart of mean `score` by `sample`, highest first.",
)
You can still pass sql_query and config if you already have them. List,
update, and delete with list_views, update_view, and delete_view. Embed
the chart in a post with
display_config={"visualizationId": view["id"]} on new_inline_asset.
Upload a file
file = ouro.files.create(
name="Crystal structure",
file_path="./structure.cif",
visibility="private",
)
Download any supported asset through the shared asset interface:
download = ouro.assets.download(file.id, output_path="./downloads")
print(download["path"])
Publish a post
Pass markdown directly or build richer content with the editor:
editor = ouro.posts.Editor()
editor.new_header(level=1, text="Experiment summary")
editor.new_paragraph(text="The best sample reached a score of 0.91.")
editor.new_inline_asset(dataset.id, asset_type="dataset", view_mode="preview")
post = ouro.posts.create(
name="Experiment summary",
content=editor,
visibility="private",
)
You can also use content_markdown="..." or content_path="./report.md".
Run an API
Ouro services expose individual endpoints as routes:
action = ouro.routes.execute(
"organization/route-name", # a route slug or UUID
body={"text": "hello"},
)
print(action.status)
print(action.final_data)
Routes can take Ouro assets directly:
action = ouro.routes.execute(
route_id,
input_assets={"structure": file.id},
)
Synchronous and asynchronous routes use the same interface. Pass wait=False to return
immediately, then use ouro.routes.poll_action(action.id) when you are ready for the result.
API overview
Resources are organized under one client:
| Namespace | Use it for |
|---|---|
ouro.assets |
Search, retrieve, share, download, and inspect lineage |
ouro.datasets |
Create, query, update, and visualize tabular data |
ouro.files |
Upload, retrieve, update, and search files |
ouro.posts |
Publish markdown and embedded assets |
ouro.routes |
Execute APIs and inspect actions |
ouro.services |
Publish an API from an OpenAPI specification |
ouro.quests |
Create work, submit entries, and review results |
ouro.organizations / ouro.teams |
Manage workspaces, channels, and membership |
ouro.comments / ouro.conversations |
Discuss assets and send messages |
ouro.users / ouro.notifications |
Work with profiles and notifications |
ouro.money |
Check balances, transactions, and paid access |
See the REST API reference for the underlying API.
Organizations, teams, and visibility
Every asset belongs to an organization and a team. When creating one, pass org_id and team_id
to choose where it appears:
dataset = ouro.datasets.create(
name="shared-results",
data=rows,
visibility="public",
org_id=org_id,
team_id=team_id,
)
If you omit them, Ouro uses your global organization's catch-all team.
Visibility can be public, private, or monetized. Private assets remain private until you
share them explicitly:
ouro.assets.share(asset_id, user_id, role="read")
Licensing and attribution
Set an asset's reuse terms with license_id, and record where the work came from with
the top-level attribution field. These fields are consistent across asset types and separate
from type-specific metadata:
attribution = {
"originality": "derivative",
"github_url": "https://github.com/example/project",
"doi_url": "https://doi.org/10.1234/example",
"relation_type": "IsDerivedFrom",
}
dataset = ouro.datasets.create(
name="published-results",
visibility="public",
data=rows,
license_id="CC-BY-4.0",
attribution=attribution,
)
originality can be original, derivative, or third-party. Attribution can also include
paper_url and external_url. Use relation_type to describe how the Ouro asset relates to the
linked work: IsSupplementTo, IsDerivedFrom, References, IsVariantFormOf, or
IsIdenticalTo.
Pass the same top-level fields when creating another asset type:
service = ouro.services.create(
name="published-model-api",
base_url="https://api.example.com",
license_id="Apache-2.0",
attribution={
"originality": "third-party",
"github_url": "https://github.com/example/model",
"paper_url": "https://arxiv.org/abs/0000.00000",
},
)
Use the license that applies to the asset type and only publish third-party or derivative work when its terms permit redistribution.
Configuration
| Variable | Default | Purpose |
|---|---|---|
OURO_API_KEY |
required | Personal Access Token |
OURO_BACKEND_URL |
https://api.ouro.foundation |
Ouro API base URL |
For local development:
export OURO_BACKEND_URL="http://localhost:8003"
You can also pass api_key and base_url directly to Ouro(...).
Error handling
All SDK exceptions inherit from OuroError:
from ouro import NotFoundError, OuroError
try:
asset = ouro.assets.retrieve(asset_id)
except NotFoundError:
print("Asset not found")
except OuroError as exc:
print(f"Ouro request failed: {exc}")
Development
git clone git@github.com:ourofoundation/ouro-py.git
cd ouro-py
pip install -e .
pytest
Questions and ideas are welcome in GitHub Discussions.
License
MIT
Release files for ouro-py 0.11.18
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| ouro_py-0.11.18.tar.gz | 72.7 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| ouro_py-0.11.18-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 166.5 kB
Release files / ouro_py-0.11.18.tar.gz
| Download URL | ouro_py-0.11.18.tar.gz |
|---|---|
| Size | 72.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
3cd6f9538c38052d4d2cae96de44676e063bea2a79b8af95e0ab90ec1a88259c
|
|
BLAKE2b-256 checksum How to use checksums |
7fbd94d6b8b7a652f2a3cb579e915a705cfcce3bbce3131c67ffd189602158d8
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 16, 2026.
Transparency logRelease files / ouro_py-0.11.18-py3-none-any.whl
| Download URL | ouro_py-0.11.18-py3-none-any.whl |
|---|---|
| Size | 93.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
c48ebb49d9c1e5c3e8493257be5b7bb3693dd2cbb705ed7df3b71f37be18e10c
|
|
BLAKE2b-256 checksum How to use checksums |
e49fc093d8f67cb891431aa6d7bf24f5be45ab97ccfdf2287e944d9cfb19bb68
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 16, 2026.
Transparency log