Skip to content

Commit

Permalink
Sync readme and client timeout changes (#151)
Browse files Browse the repository at this point in the history
  • Loading branch information
ewanharris authored Nov 26, 2024
2 parents 5e61ff0 + 76d70f4 commit 8434eea
Show file tree
Hide file tree
Showing 8 changed files with 109 additions and 40 deletions.
82 changes: 44 additions & 38 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -349,48 +349,46 @@ Create a new authorization model.
# Initialize the fga_client
# fga_client = OpenFgaClient(configuration)

body = WriteAuthorizationModelRequest(
schema_version="1.1",
type_definitions=[
TypeDefinition(
type="user"
user_type = TypeDefinition(type="user")

document_relations = dict(
writer=Userset(this=dict()),
viewer=Userset(
union=Usersets(
child=[
Userset(this=dict()),
Userset(computed_userset=ObjectRelation(
object="",
relation="writer",
)),
],
),
TypeDefinition(
type="document",
relations=dict(
writer=Userset(
this=dict(),
),
viewer=Userset(
union=Usersets(
child=[
Userset(this=dict()),
Userset(computed_userset=ObjectRelation(
object="",
relation="writer",
)),
],
),
),
),
)

document_metadata = Metadata(
relations=dict(
writer=RelationMetadata(
directly_related_user_types=[
RelationReference(type="user"),
RelationReference(type="user", condition="ViewCountLessThan200"),
]
),
metadata=Metadata(
relations=dict(
writer=RelationMetadata(
directly_related_user_types=[
RelationReference(type="user"),
RelationReference(type="user", condition="ViewCountLessThan200"),
]
),
viewer=RelationMetadata(
directly_related_user_types=[
RelationReference(type="user"),
]
)
)
viewer=RelationMetadata(
directly_related_user_types=[
RelationReference(type="user"),
]
)
)
],
conditions=dict(
)

document_type = TypeDefinition(
type="document",
relations=document_relations,
metadata=document_metadata
)

conditions = dict(
ViewCountLessThan200=Condition(
name="ViewCountLessThan200",
expression="ViewCount < 200",
Expand All @@ -407,6 +405,14 @@ body = WriteAuthorizationModelRequest(
)
)
)

body = WriteAuthorizationModelRequest(
schema_version="1.1",
type_definitions=[
user_type,
document_type
],
conditions=conditions
)

response = await fga_client.write_authorization_model(body)
Expand Down
2 changes: 2 additions & 0 deletions openfga_sdk/client/configuration.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ def __init__(
authorization_model_id=None,
ssl_ca_cert=None,
api_url=None, # TODO: restructure when removing api_scheme/api_host
timeout_millisec: int | None = None,
):
super().__init__(
api_scheme,
Expand All @@ -39,6 +40,7 @@ def __init__(
retry_params,
ssl_ca_cert=ssl_ca_cert,
api_url=api_url,
timeout_millisec=timeout_millisec,
)
self._authorization_model_id = authorization_model_id

Expand Down
30 changes: 30 additions & 0 deletions openfga_sdk/configuration.py
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,7 @@ class Configuration:
:param ssl_ca_cert: str - the path to a file of concatenated CA certificates
in PEM format
:param api_url: str - the URL of the FGA server
:param timeout_millisec: int | None - the default timeout in milliseconds for requests
"""

_default = None
Expand Down Expand Up @@ -206,6 +207,7 @@ def __init__(
]
| None
) = None,
timeout_millisec: int | None = None,
):
"""Constructor"""
self._url = api_url
Expand All @@ -218,6 +220,8 @@ def __init__(
else:
# use the default parameters
self._retry_params = RetryParams()

self._timeout_millisec = timeout_millisec or 5000 * 60
"""Default Base url
"""
self.server_index = 0
Expand Down Expand Up @@ -647,6 +651,18 @@ def is_valid(self):
if self._credentials is not None:
self._credentials.validate_credentials_config()

if self._timeout_millisec is not None:
if not isinstance(self._timeout_millisec, int):
raise FgaValidationException(
f"timeout_millisec unexpected type {self._timeout_millisec}"
)

ten_minutes = 10000 * 60
if self._timeout_millisec < 0 or self._timeout_millisec > ten_minutes:
raise FgaValidationException(
f"timeout_millisec not within reasonable range (0,60000), {self._timeout_millisec}"
)

@property
def api_scheme(self):
"""Return connection is https or http."""
Expand Down Expand Up @@ -718,6 +734,20 @@ def retry_params(self, value):
"""
self._retry_params = value

@property
def timeout_millisec(self):
"""
Return timeout milliseconds
"""
return self._timeout_millisec

@timeout_millisec.setter
def timeout_millisec(self, value):
"""
Update timeout milliseconds
"""
self._timeout_millisec = value

@property
def disabled_client_side_validations(self):
"""Return disable_client_side_validations."""
Expand Down
3 changes: 2 additions & 1 deletion openfga_sdk/rest.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ def __init__(self, configuration, pools_size=4, maxsize=None):

self.proxy = configuration.proxy
self.proxy_headers = configuration.proxy_headers
self._timeout_millisec = configuration.timeout_millisec

# https pool manager
self.pool_manager = aiohttp.ClientSession(connector=connector, trust_env=True)
Expand Down Expand Up @@ -117,7 +118,7 @@ async def request(

post_params = post_params or {}
headers = headers or {}
timeout = _request_timeout or 5 * 60
timeout = _request_timeout or self._timeout_millisec / 1000

if "Content-Type" not in headers:
headers["Content-Type"] = "application/json"
Expand Down
4 changes: 3 additions & 1 deletion openfga_sdk/sync/rest.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,8 @@ def __init__(self, configuration, pools_size=4, maxsize=None):
else:
maxsize = 4

self._timeout_millisec = configuration.timeout_millisec

# https pool manager
if configuration.proxy:
self.pool_manager = urllib3.ProxyManager(
Expand Down Expand Up @@ -148,7 +150,7 @@ def request(
post_params = post_params or {}
headers = headers or {}

timeout = None
timeout = urllib3.Timeout(total=self._timeout_millisec / 1000)
if _request_timeout:
if isinstance(_request_timeout, (float, int)):
timeout = urllib3.Timeout(total=_request_timeout)
Expand Down
11 changes: 11 additions & 0 deletions test/api/open_fga_api_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -1148,6 +1148,17 @@ def test_url_with_scheme_and_host(self):
self.assertEqual(configuration.api_url, "http://localhost:8080")
configuration.is_valid() # Should not throw and complain about scheme being invalid

def test_timeout_millisec(self):
"""
Ensure that timeout_seconds is set and validated
"""
configuration = openfga_sdk.Configuration(
api_url="http://localhost:8080",
timeout_millisec=10000,
)
self.assertEqual(configuration.timeout_millisec, 10000)
configuration.is_valid()

async def test_bad_configuration_read_authorization_model(self):
"""
Test whether FgaValidationException is raised for API (reading authorization models)
Expand Down
6 changes: 6 additions & 0 deletions test/configuration_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ def test_configuration_set_default(self, configuration):
}
default_config.ssl_ca_cert = "/path/to/ca_cert.pem"
default_config.api_url = "https://fga.example/api"
default_config.timeout_millisec = 10000
Configuration.set_default(default_config)

assert Configuration._default.api_scheme == "https"
Expand Down Expand Up @@ -183,6 +184,7 @@ def test_configuration_set_default(self, configuration):
}
assert Configuration._default.ssl_ca_cert == "/path/to/ca_cert.pem"
assert Configuration._default.api_url == "https://fga.example/api"
assert Configuration._default.timeout_millisec == 10000

def test_configuration_get_default_copy(self, configuration):
default_config = Configuration()
Expand Down Expand Up @@ -212,6 +214,7 @@ def test_configuration_get_default_copy(self, configuration):
}
default_config.ssl_ca_cert = "/path/to/ca_cert.pem"
default_config.api_url = "https://fga.example/api"
default_config.timeout_millisec = 10000
Configuration.set_default(default_config)

copied_config = Configuration.get_default_copy()
Expand All @@ -229,6 +232,7 @@ def test_configuration_get_default_copy(self, configuration):
assert copied_config.credentials._api_audience == "audience123"
assert copied_config.credentials._api_issuer == "issuer123"
assert copied_config.credentials._api_token == "token123"
assert Configuration._default.timeout_millisec == 10000


class TestConfigurationValidityChecks:
Expand Down Expand Up @@ -361,6 +365,7 @@ def test_configuration_deepcopy(self, configuration):
},
ssl_ca_cert="/path/to/ca_cert.pem",
api_url="https://fga.example/api",
timeout_millisec=10000,
)

# Perform deep copy
Expand Down Expand Up @@ -394,3 +399,4 @@ def test_configuration_deepcopy(self, configuration):
)
assert copied_config.ssl_ca_cert == config.ssl_ca_cert
assert copied_config.api_url == config.api_url
assert copied_config.timeout_millisec == config.timeout_millisec
11 changes: 11 additions & 0 deletions test/sync/open_fga_api_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -1148,6 +1148,17 @@ def test_url_with_scheme_and_host(self):
self.assertEqual(configuration.api_url, "http://localhost:8080")
configuration.is_valid() # Should not throw and complain about scheme being invalid

def test_timeout_millisec(self):
"""
Ensure that timeout_millisec is set and validated
"""
configuration = Configuration(
api_url="http://localhost:8080",
timeout_millisec=10000,
)
self.assertEqual(configuration.timeout_millisec, 10000)
configuration.is_valid()

async def test_bad_configuration_read_authorization_model(self):
"""
Test whether FgaValidationException is raised for API (reading authorization models)
Expand Down

0 comments on commit 8434eea

Please sign in to comment.