Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

release(v0.3.3): misc fixes #55

Merged
merged 5 commits into from
Jan 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions .github/ISSUE_TEMPLATE/bug_report.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,12 @@ By submitting an issue to this repository, you agree to the terms within the [Op

### Version of SDK


```
$ python -m openfga_sdk.help
<paste here>
```

This command is only available on openfga_sdk v0.3.2 and greater. Otherwise, please provide some basic information about your system.
This command is only available on openfga_sdk `v0.3.2` and greater. Otherwise, please provide some basic information about your system.

### Version of OpenFGA (if known)

Expand Down
7 changes: 7 additions & 0 deletions .openapi-generator/FILES
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,13 @@ docs/WriteAssertionsRequest.md
docs/WriteAuthorizationModelRequest.md
docs/WriteAuthorizationModelResponse.md
docs/WriteRequest.md
example/Makefile
example/README.md
example/example1/auth-model.json
example/example1/example1.py
example/example1/requirements.txt
example/example1/setup.cfg
example/example1/setup.py
openfga_sdk/__init__.py
openfga_sdk/api/__init__.py
openfga_sdk/api/open_fga_api.py
Expand Down
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# Changelog

## v0.3.3

### [0.3.3](https://github.com/openfga/python-sdk/compare/v0.3.2...v0.3.3) (2024-01-02)
- fix: correct type hints for list_relations
- fix: handle empty TupleKey in read
- chore: add example project

## v0.3.2

### [0.3.2](https://github.com/openfga/python-sdk/compare/v0.3.1...v0.3.2) (2023-12-15)
Expand Down
2 changes: 1 addition & 1 deletion VERSION.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.3.2
0.3.3
11 changes: 11 additions & 0 deletions example/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
all: run

project_name=example1
openfga_version=latest

run:
python example1/example1.py

run-openfga:
docker pull docker.io/openfga/openfga:${openfga_version} && \
docker run -p 8080:8080 docker.io/openfga/openfga:${openfga_version} run
32 changes: 32 additions & 0 deletions example/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
## Examples of using the OpenFGA Python SDK

A set of examples on how to call the OpenFGA Python SDK

### Examples
Example 1:
A bare-bones example. It creates a store, and runs a set of calls against it including creating a model, writing tuples and checking for access.

### Running the Examples

Prerequisites:
- `docker`
- `make`
- `python` 3.11+

#### Run using a published SDK

Steps:
1. Clone/Copy the example folder
2. If you have an OpenFGA server running, you can use it, otherwise run `make run-openfga` to spin up an instance (you'll need to switch to a different terminal after - don't forget to close it when done)
3. Run `make run` to run the example

#### Run using a local unpublished SDK build

Steps:
1. Build the SDK
2. Change to the example directory
3. Install the local SDK `pip install -e $LOCAL_DIR`
- For example, if your local SDK is located at `$HOME/projects/python-sdk`, run `pip install -e $HOME/projects/python-sdk`
- For advanced users: The above just updates `requirements.txt` and the source of openfga-sdk. If you know how to manually edit this, feel free to do that as well.
4. If you have an OpenFGA server running, you can use it, otherwise run `make run-openfga` to spin up an instance (you'll need to switch to a different terminal after - don't forget to close it when done)
5. Run `make run` to run the example
73 changes: 73 additions & 0 deletions example/example1/auth-model.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
{
"schema_version": "1.1",
"type_definitions": [
{
"type": "user"
},
{
"type": "document",
"relations": {
"reader": {
"this": {}
},
"writer": {
"this": {}
},
"owner": {
"this": {}
}
},
"metadata": {
"relations": {
"reader": {
"directly_related_user_types": [
{
"type": "user"
}
]
},
"writer": {
"directly_related_user_types": [
{
"type": "user"
}
]
},
"owner": {
"directly_related_user_types": [
{
"type": "user"
}
]
},
"conditional_reader": {
"directly_related_user_types": [
{
"condition": "name_starts_with_a",
"type": "user"
}
]
}
}
}
}
],
"conditions": {
"ViewCountLessThan200": {
"name": "ViewCountLessThan200",
"expression": "ViewCount < 200",
"parameters": {
"ViewCount": {
"type_name": "TYPE_NAME_INT"
},
"Type": {
"type_name": "TYPE_NAME_STRING"
},
"Name": {
"type_name": "TYPE_NAME_STRING"
}
}
}
}
}

175 changes: 175 additions & 0 deletions example/example1/example1.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
import asyncio
import json

import openfga_sdk
from openfga_sdk.client.models import ClientAssertion, ClientCheckRequest, ClientReadChangesRequest, ClientTuple, ClientWriteRequest
from openfga_sdk.models import CreateStoreRequest, Metadata, ObjectRelation, RelationMetadata, TupleKey, TypeDefinition, Userset, Usersets, WriteAuthorizationModelRequest
from openfga_sdk import ClientConfiguration, OpenFgaClient
from openfga_sdk.credentials import CredentialConfiguration, Credentials
import os


async def main():
credentials = Credentials()
if os.getenv("FGA_CLIENT_ID") is not None:
credentials = Credentials(
method='client_credentials',
configuration=CredentialConfiguration(
api_issuer=os.getenv('FGA_API_TOKEN_ISSUER'),
api_audience=os.getenv('FGA_API_AUDIENCE'),
client_id=os.getenv('FGA_CLIENT_ID'),
client_secret=os.getenv('FGA_CLIENT_SECRET')
)
)

if os.getenv('FGA_API_HOST') is not None:
configuration = ClientConfiguration(
api_host=os.getenv('FGA_API_HOST'),
credentials=credentials
)
else:
configuration = ClientConfiguration(
api_scheme='http',
api_host='localhost:8080',
credentials=credentials
)

async with OpenFgaClient(configuration) as fga_client:
# ListStores (before create)
print('Listing Stores')
response = await fga_client.list_stores()
print(f"Stores Count: {len(response.stores)}")

store_name = 'Test Store'

# CreateStore (before create)
print('Creating Test Store')
body = CreateStoreRequest(name=store_name)
response = await fga_client.create_store(body)
print(f"Test Store ID: {response.id}")

# Set the store ID
fga_client.set_store_id(response.id)

# ListStores (after create)
print('Listing Stores')
response = await fga_client.list_stores()
print(f"Stores Count: {len(response.stores)}")

# GetStore (after create)
print('Getting Current Store')
response = await fga_client.get_store()
print(f"Current Store Name: {response.name}")

# ReadAuthorizationModels (before write)
print('Reading Authorization Models')
response = await fga_client.read_authorization_models()
print(f"Models Count: {len(response.authorization_models)}")

# ReadLatestAuthorizationModel (before write)
try:
response = await fga_client.read_latest_authorization_model()
if response.authorization_model is not None:
print(f"Latest Authorization Model ID: {response.authorization_model.id}")
except:
print('Latest Authorization Model not found')

# WriteAuthorizationModel
print('Writing an Authorization Model')
with open(os.path.join(os.path.dirname(__file__), 'auth-model.json')) as f:
auth_model_request = json.load(f)
response = await fga_client.write_authorization_model(auth_model_request)
print(f"Authorization Model ID: {response.authorization_model_id}")

# ReadAuthorizationModels (after write)
print('Reading Authorization Models')
response = await fga_client.read_authorization_models()
print(f"Models Count: {len(response.authorization_models)}")

# ReadLatestAuthorizationModel (after write)
response = await fga_client.read_latest_authorization_model()
if response.authorization_model is not None:
print(f"Latest Authorization Model ID: {response.authorization_model.id}")

auth_model_id = response.authorization_model.id

# Write
print('Writing Tuples')
body = ClientWriteRequest(
writes=[
ClientTuple(
user='user:anne',
relation='writer',
object='document:roadmap',
# condition=RelationshipCondition(
# name='ViewCountLessThan200',
# context=dict(
# Name='Roadmap',
# Type='Document',
# ),
# ),
),
],
)
options = {
# You can rely on the model id set in the configuration or override it for this specific request
"authorization_model_id": auth_model_id
}
await fga_client.write(body, options)
print('Done Writing Tuples')

# Set the model ID
fga_client.set_authorization_model_id(auth_model_id)

# Read
print('Reading Tuples')
response = await fga_client.read(TupleKey(user='user:anne', object='document:'))
print(f"Read Tuples: {response.tuples}")

# ReadChanges
print('Reading Tuple Changes')
body = ClientReadChangesRequest('document')
response = await fga_client.read_changes(body)
print(f"Read Changes Tuples: {response.changes}")

# Check
print('Checking for access')
response = await fga_client.check(ClientCheckRequest(
user='user:anne',
relation='reader',
object='document:roadmap',
))
print(f"Allowed: {response.allowed}")

# Checking for access with context
# TODO

# WriteAssertions
await fga_client.write_assertions([
ClientAssertion(
user='user:carl',
relation='writer',
object='document:budget',
expectation=True,
),
ClientAssertion(
user='user:anne',
relation='reader',
object='document:roadmap',
expectation=False,
),
])
print('Assertions updated')

# ReadAssertions
print('Reading Assertions')
response = await fga_client.read_assertions()
print(f"Assertions: {response.assertions}")

# DeleteStore
print('Deleting Current Store')
await fga_client.delete_store()
print(f"Deleted Store: {store_name}")


asyncio.run(main())
11 changes: 11 additions & 0 deletions example/example1/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
aiohttp==3.9.1
aiosignal==1.3.1
attrs==23.1.0
frozenlist==1.4.1
idna==3.6
multidict==6.0.4
openfga-sdk==0.3.2
python-dateutil==2.8.2
six==1.16.0
urllib3==2.1.0
yarl==1.9.4
2 changes: 2 additions & 0 deletions example/example1/setup.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[flake8]
max-line-length=99
33 changes: 33 additions & 0 deletions example/example1/setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# coding: utf-8

"""
Python SDK for OpenFGA

API version: 0.1
Website: https://openfga.dev
Documentation: https://openfga.dev/docs
Support: https://discord.gg/8naAwJfWN6
License: [Apache-2.0](https://github.com/openfga/python-sdk/blob/main/LICENSE)

NOTE: This file was auto generated by OpenAPI Generator (https://openapi-generator.tech). DO NOT EDIT.
"""

from setuptools import setup, find_packages

NAME = "example1"
VERSION = "0.0.1"
REQUIRES = ["openfga-sdk >= 0.3"]

setup(
name=NAME,
version=VERSION,
description="An example of using the OpenFGA Python SDK",
author="OpenFGA (https://openfga.dev)",
author_email="[email protected]",
url="https://github.com/openfga/python-sdk",
install_requires=REQUIRES,
python_requires='>=3.10',
packages=find_packages(exclude=["test", "tests"]),
include_package_data=True,
license="Apache-2.0"
)
2 changes: 1 addition & 1 deletion openfga_sdk/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
NOTE: This file was auto generated by OpenAPI Generator (https://openapi-generator.tech). DO NOT EDIT.
"""

__version__ = "0.3.2"
__version__ = "0.3.3"

from openfga_sdk.client.client import OpenFgaClient
from openfga_sdk.client.configuration import ClientConfiguration
Expand Down
Loading