A bear playing hopscotch

Announcing our new Python Client

Hazal Mestci

We’re excited to announce a new major version of our Python client. We’ve been hard at work on this new vision for the Oso SDK, centered around these features:

  1. A simplified Fact Management API
  2. A powerful Query Builder API


Simplified Fact Management API


Fact Representation and Input Types

Facts are now tuples instead of dicts. You can replace old dict formats like {"name": "has_role", args: [...]}with ("has_role", user, "member", repo). For example, to migrate from tell to insert, convert the arguments from dicts to values and wrap them in a tuple.

Fact arguments should now use the oso_cloud.Value type, improving consistency across the API. Type hinting has been updated as well. Instead of oso_cloud.Value and oso_cloud.Fact, use oso_cloud.IntoValue and oso_cloud.IntoFact, supporting native Python types alongside custom objects.


Management API

The Management API has been condensed from 6 methods to 4: insert, delete, get, and batch.


The new insert API replaces tell. With insert, you can add facts to Oso Cloud:

oso.insert((
  "has_role",
  Value("User", "bob"),
  "owner",
  Value("Organization", "acme")
))


With delete, you can delete a fact or facts with an argument of a particular type. Deleting a single fact would look like below:

oso.delete((
  "has_role", 
  Value("User", "bob"), 
  "maintainer", 
  Value("Repository", "anvils")
))


With get, you can check the existence of a particular fact or fetch all facts that have a particular argument.

# Get one fact
oso.get(("has_role", bob, "admin", anvils))


# List all role-related facts on the `anvils` repo
oso.get(("has_role", None, None, anvils))


The new batch API replaces the bulk, bulk_delete, and bulk_tell APIs.

Additionally, the new batch function supports deleting all facts matching a pattern:

user1 = Value("User", "1")
user2 = Value("User", "2")


# Remove all roles for User 1 and User 2 across the entire system.
with oso.batch() as tx:
    tx.delete(("has_role", user1, None, None))
    tx.delete(("has_role", user2, None, None))


Powerful Query Builder API

We've replaced the Query API with a more powerful and flexible oso.build_query() API with a fluent interface. We've also dropped the authorize_resources APIs in favor of the Query Builder. Queries with wildcards now use typed_var(my_type), while multiple results can be returned as dictionaries for easier processing. If you want to migrate your existing queries as-is, check out the section of queries with no wildcards, queries with type-constrained wildcards, and queries with unconstrained wildcards for more information.

Here's an example of using the Query Builder to filter unauthorized resources from a collection:

repos = ["anvil", "acme"]
actor = Value("User", "bob")
repo = typed_var("Repository")


results = (
  oso
    .build_query(("allow", actor, "read", repo))
    .in_(repo, repos)
    .evaluate(repo)
)
# => Returns the subset of `repos` that bob can read- eg.
# ["anvil"]


See here for how it can support any use case your application demands
.


Get started with the v2 Python client

You can install the v2 Python on PyPI by running: pip install oso-cloud. The full docs are here. If you’re upgrading from v1, check out the Migration Guide.

These changes will be coming to the other language SDKs soon. Let us know if you’re interested in trying RC versions!

Want us to remind you?
We'll email you before the event with a friendly reminder.

Write your first policy