Skip to content

Commit 2ab1f35

Browse files
author
Sameera Salameh
committed
Merge branch 'main' of github.com:RelationalAI/rai-sdk-python into pv-override-auth0-audience
2 parents 71adb67 + e00fa95 commit 2ab1f35

File tree

11 files changed

+110
-53
lines changed

11 files changed

+110
-53
lines changed
Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License
1414

15-
"""Delete a transaction."""
1615

1716
import json
1817
from argparse import ArgumentParser
@@ -24,7 +23,7 @@
2423
def run(id: str, profile: str):
2524
cfg = config.read(profile=profile)
2625
ctx = api.Context(**cfg)
27-
rsp = api.delete_transaction(ctx, id)
26+
rsp = api.cancel_transaction(ctx, id)
2827
print(json.dumps(rsp, indent=2))
2928

3029

examples/get_engine.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121

2222

2323
def run(engine: str, profile: str):
24-
cfg = config.read()
24+
cfg = config.read(profile=profile)
2525
ctx = api.Context(**cfg)
2626
rsp = api.get_engine(ctx, engine)
2727
print(json.dumps(rsp, indent=2))

examples/get_transaction_results.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
"""Fetch results for the given transaction."""
1616

17+
import json
1718
from argparse import ArgumentParser
1819
from urllib.request import HTTPError
1920
from railib import api, config, show
@@ -23,8 +24,13 @@ def run(id: str, profile: str):
2324
cfg = config.read(profile=profile)
2425
ctx = api.Context(**cfg)
2526
rsp = api.get_transaction_results(ctx, id)
27+
print("Results:")
2628
show.results(rsp, "multipart")
2729

30+
rsp = api.get_transaction_problems(ctx, id)
31+
print("\nProblems:")
32+
print(json.dumps(rsp, indent=2))
33+
2834

2935
if __name__ == "__main__":
3036
p = ArgumentParser()

examples/list_transactions.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# Copyright 2021-2022 RelationalAI, Inc.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License
14+
15+
"""Fetch a list of transactions."""
16+
17+
import json
18+
from argparse import ArgumentParser
19+
from urllib.request import HTTPError
20+
from railib import api, config, show
21+
22+
23+
def run(profile: str):
24+
cfg = config.read(profile=profile)
25+
ctx = api.Context(**cfg)
26+
rsp = api.list_transactions(ctx)
27+
print(json.dumps(rsp, indent=2))
28+
29+
30+
if __name__ == "__main__":
31+
p = ArgumentParser()
32+
p.add_argument("-p", "--profile", type=str,
33+
help="profile name", default="default")
34+
args = p.parse_args()
35+
try:
36+
run(args.profile)
37+
except HTTPError as e:
38+
show.http_error(e)

examples/list_users.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,19 +15,23 @@
1515
"""List all users."""
1616

1717
import json
18+
from argparse import ArgumentParser
1819
from urllib.request import HTTPError
1920
from railib import api, config, show
2021

2122

22-
def run():
23-
cfg = config.read()
23+
def run(profile: str):
24+
cfg = config.read(profile=profile)
2425
ctx = api.Context(**cfg)
2526
rsp = api.list_users(ctx)
2627
print(json.dumps(rsp, indent=2))
2728

2829

2930
if __name__ == "__main__":
31+
p = ArgumentParser()
32+
p.add_argument("-p", "--profile", type=str, help="profile name", default="default")
33+
args = p.parse_args()
3034
try:
31-
run()
35+
run(args.profile)
3236
except HTTPError as e:
3337
show.http_error(e)

examples/run renamed to examples/run-all

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22

33
set -ex
44

5-
ENGINE=sdk-test-xs
65
DATABASE=sdk-test
76
DATABASE_CLONE=$DATABASE-clone
7+
ENGINE=sdk-test-xs
88

99
# setup
1010
python3 ./delete_database.py $DATABASE_CLONE
@@ -13,17 +13,20 @@ python3 ./delete_engine.py $ENGINE
1313

1414
# engines
1515
python3 ./create_engine.py $ENGINE --size=XS
16+
python3 ./get_engine.py $ENGINE
1617
python3 ./list_engines.py
1718
python3 ./list_engines.py --state=PROVISIONED
18-
python3 ./get_engine.py $ENGINE
19+
python3 ./list_engines.py --state=NONESENSE
1920

2021
# databases
2122
python3 ./create_database.py $DATABASE
23+
python3 ./get_database.py $DATABASE
2224
python3 ./list_databases.py
2325
python3 ./list_databases.py --state=CREATED
24-
python3 ./get_database.py $DATABASE
25-
python3 ./list_models.py $DATABASE $ENGINE
26+
python3 ./list_databases.py --state=NONSENSE
2627
python3 ./list_edbs.py $DATABASE $ENGINE
28+
python3 ./list_models.py $DATABASE $ENGINE
29+
python3 ./get_model.py $DATABASE $ENGINE stdlib
2730

2831
# run query
2932
QUERY="x, x^2, x^3, x^4 from x in {1; 2; 3; 4; 5}"
@@ -32,11 +35,12 @@ python3 ./run_query.py $DATABASE $ENGINE "$QUERY" --readonly
3235
python3 ./show_results.py $DATABASE $ENGINE
3336
python3 ./show_problems.py $DATABASE $ENGINE
3437

35-
# install model
38+
# load model
3639
python3 ./install_model.py $DATABASE $ENGINE hello.rel
37-
python3 ./list_models.py $DATABASE $ENGINE
3840
python3 ./get_model.py $DATABASE $ENGINE hello
39-
python3 ./list_edbs.py $DATABASE $ENGINE
41+
python3 ./list_models.py $DATABASE $ENGINE
42+
python3 ./delete_model.py $DATABASE $ENGINE hello
43+
python3 ./list_models.py $DATABASE $ENGINE
4044

4145
# load_csv
4246
python3 ./load_csv.py $DATABASE $ENGINE sample.csv -r sample_csv
@@ -53,12 +57,16 @@ python3 ./run_query.py $DATABASE $ENGINE sample_json
5357
python3 ./list_edbs.py $DATABASE $ENGINE
5458

5559
# clone database
60+
python3 ./delete_database.py $DATABASE
61+
python3 ./create_database.py $DATABASE
62+
python3 ./load_json.py $DATABASE $ENGINE sample.json -r sample_json
63+
python3 ./install_model.py $DATABASE $ENGINE hello.rel
5664
python3 ./clone_database.py $DATABASE_CLONE $DATABASE
65+
python3 ./get_database.py $DATABASE_CLONE
5766
python3 ./list_databases.py
5867
python3 ./list_databases.py --state=CREATED
59-
python3 ./get_database.py $DATABASE_CLONE
60-
python3 ./list_models.py $DATABASE_CLONE $ENGINE
6168
python3 ./list_edbs.py $DATABASE_CLONE $ENGINE
69+
python3 ./list_models.py $DATABASE_CLONE $ENGINE
6270
python3 ./get_model.py $DATABASE_CLONE $ENGINE hello
6371

6472
# delete model
@@ -86,7 +94,6 @@ python3 update_user.py $USERID --status=INACTIVE
8694
python3 update_user.py $USERID --status=ACTIVE
8795
python3 update_user.py $USERID --roles=admin --roles=user
8896
python3 update_user.py $USERID --status=INACTIVE --roles=user
89-
python3 update_user.py $USERID
9097

9198
# cleanup
9299
python3 ./delete_database.py $DATABASE_CLONE

examples/run_query_async.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License
14+
1415
from argparse import ArgumentParser
1516
from urllib.request import HTTPError
1617
from railib import api, config, show
@@ -20,7 +21,7 @@ def run(database: str, engine: str, command: str, readonly: bool, profile: str):
2021
cfg = config.read(profile=profile)
2122
ctx = api.Context(**cfg)
2223
rsp = api.query_async(ctx, database, engine, command, readonly=readonly)
23-
show.results(rsp, "multipart" if isinstance(rsp, list) else "wire")
24+
show.results(rsp)
2425

2526

2627
if __name__ == "__main__":

railib/api.py

Lines changed: 31 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,6 @@ class Permission(str, Enum):
7171
# transactions
7272
RUN_TRANSACTION = "run:transaction"
7373
READ_TRANSACTION = "read:transaction"
74-
DELETE_TRANSACTION = "delete:transaction"
7574
# credits
7675
READ_CREDITS_USAGE = "read:credits_usage"
7776
# oauth clients
@@ -109,7 +108,6 @@ class Permission(str, Enum):
109108
"delete_database",
110109
"delete_engine",
111110
"delete_model",
112-
"delete_transaction",
113111
"disable_user",
114112
"enable_user",
115113
"delete_oauth_client",
@@ -120,6 +118,7 @@ class Permission(str, Enum):
120118
"get_transaction",
121119
"get_transaction_metadata",
122120
"get_transaction_results",
121+
"cancel_transaction",
123122
"get_user",
124123
"list_databases",
125124
"list_edbs",
@@ -130,6 +129,7 @@ class Permission(str, Enum):
130129
"load_csv",
131130
"update_user",
132131
"query",
132+
"query_async",
133133
]
134134

135135

@@ -163,7 +163,7 @@ def _get_resource(ctx: Context, path: str, key=None, **kwargs) -> dict:
163163

164164

165165
# Retrieve a generic collection of resources.
166-
def _list_collection(ctx, path: str, key=None, **kwargs):
166+
def _get_collection(ctx, path: str, key=None, **kwargs):
167167
rsp = rest.get(ctx, _mkurl(ctx, path), **kwargs)
168168
rsp = json.loads(rsp.read())
169169
return rsp[key] if key else rsp
@@ -248,12 +248,6 @@ def delete_engine(ctx: Context, engine: str) -> dict:
248248
return json.loads(rsp.read())
249249

250250

251-
def delete_transaction(ctx: Context, id: str) -> dict:
252-
url = _mkurl(ctx, f"{PATH_TRANSACTIONS}/{id}")
253-
rsp = rest.delete(ctx, url, None)
254-
return json.loads(rsp.read())
255-
256-
257251
def delete_user(ctx: Context, id: str) -> dict:
258252
url = _mkurl(ctx, f"{PATH_USER}/{id}")
259253
rsp = rest.delete(ctx, url, None)
@@ -291,7 +285,15 @@ def get_transaction(ctx: Context, id: str) -> dict:
291285

292286

293287
def get_transaction_metadata(ctx: Context, id: str) -> dict:
294-
return _get_resource(ctx, f"{PATH_TRANSACTIONS}/{id}/metadata")
288+
return _get_collection(ctx, f"{PATH_TRANSACTIONS}/{id}/metadata")
289+
290+
291+
def list_transactions(ctx: Context) -> list:
292+
return _get_collection(ctx, PATH_TRANSACTIONS, key="transactions")
293+
294+
295+
def get_transaction_problems(ctx: Context, id: str) -> dict:
296+
return _get_collection(ctx, f"{PATH_TRANSACTIONS}/{id}/problems")
295297

296298

297299
def get_transaction_results(ctx: Context, id: str) -> list:
@@ -303,6 +305,11 @@ def get_transaction_results(ctx: Context, id: str) -> list:
303305
return _parse_multipart(content_type, rsp.read())
304306

305307

308+
def cancel_transaction(ctx: Context, id: str) -> dict:
309+
rsp = rest.post(ctx, _mkurl(ctx, f"{PATH_TRANSACTIONS}/{id}/cancel"), {})
310+
return json.loads(rsp.read())
311+
312+
306313
def get_user(ctx: Context, userid: str) -> dict:
307314
return _get_resource(ctx, f"{PATH_USER}/{userid}", name=userid)
308315

@@ -311,22 +318,22 @@ def list_engines(ctx: Context, state=None) -> list:
311318
kwargs = {}
312319
if state is not None:
313320
kwargs["state"] = state
314-
return _list_collection(ctx, PATH_ENGINE, key="computes", **kwargs)
321+
return _get_collection(ctx, PATH_ENGINE, key="computes", **kwargs)
315322

316323

317324
def list_databases(ctx: Context, state=None) -> list:
318325
kwargs = {}
319326
if state is not None:
320327
kwargs["state"] = state
321-
return _list_collection(ctx, PATH_DATABASE, key="databases", **kwargs)
328+
return _get_collection(ctx, PATH_DATABASE, key="databases", **kwargs)
322329

323330

324331
def list_users(ctx: Context) -> list:
325-
return _list_collection(ctx, PATH_USER, key="users")
332+
return _get_collection(ctx, PATH_USER, key="users")
326333

327334

328335
def list_oauth_clients(ctx: Context) -> list:
329-
return _list_collection(ctx, PATH_OAUTH_CLIENT, key="clients")
336+
return _get_collection(ctx, PATH_OAUTH_CLIENT, key="clients")
330337

331338

332339
def update_user(ctx: Context, userid: str, status: str = None, roles=None):
@@ -340,9 +347,6 @@ def update_user(ctx: Context, userid: str, status: str = None, roles=None):
340347
return json.loads(rsp.read())
341348

342349

343-
#
344-
# Transaction endpoint
345-
#
346350
class Transaction(object):
347351
def __init__(self, database: str, engine: str, abort=False,
348352
mode: Mode = Mode.OPEN, nowait_durable=False, readonly=False,
@@ -398,23 +402,15 @@ def run(self, ctx: Context, *args) -> dict:
398402
return json.loads(rsp.read())
399403

400404

401-
#
402-
# /transactions endpoint
403-
#
404405
class TransactionAsync(object):
405-
def __init__(self, database: str, engine: str, command: str, nowait_durable=False, readonly=False,
406-
inputs: dict = None):
406+
def __init__(self, database: str, engine: str, nowait_durable=False, readonly=False):
407407
self.database = database
408408
self.engine = engine
409-
self.command = command
410409
self.nowait_durable = nowait_durable
411410
self.readonly = readonly
412-
self.inputs = inputs
413411

414412
@property
415413
def data(self):
416-
inputs = self.inputs or {}
417-
inputs = [_query_action_input(k, v) for k, v in inputs.items()]
418414
result = {
419415
"dbname": self.database,
420416
"nowait_durable": self.nowait_durable,
@@ -423,16 +419,18 @@ def data(self):
423419
}
424420
if self.engine is not None:
425421
result["engine_name"] = self.engine
426-
result["query"] = self.command
427-
result["inputs"] = inputs
428422
return result
429423

430-
def run(self, ctx: Context) -> Union[dict, list]:
424+
def run(self, ctx: Context, command: str, inputs: dict = None) -> Union[dict, list]:
431425
data = self.data
432-
url = _mkurl(ctx, PATH_TRANSACTIONS)
433-
rsp = rest.post(ctx, url, data)
426+
data["query"] = command
427+
if not inputs is None:
428+
inputs = [_query_action_input(k, v) for k, v in inputs.items()]
429+
data["v1_inputs"] = inputs
430+
rsp = rest.post(ctx, _mkurl(ctx, PATH_TRANSACTIONS), data)
434431
content_type = rsp.headers.get('content-type', None)
435432
content = rsp.read()
433+
# todo: response model should be based on status code (200 v. 201)
436434
# async mode
437435
if content_type.lower() == "application/json":
438436
return json.loads(content)
@@ -660,8 +658,8 @@ def query(ctx: Context, database: str, engine: str, command: str,
660658

661659
def query_async(ctx: Context, database: str, engine: str, command: str,
662660
readonly: bool = True, inputs: dict = None) -> Union[dict, list]:
663-
tx = TransactionAsync(database, engine, command, readonly=readonly, inputs=inputs)
664-
return tx.run(ctx)
661+
tx = TransactionAsync(database, engine, readonly=readonly)
662+
return tx.run(ctx, command, inputs=inputs)
665663

666664

667665
create_compute = create_engine # deprecated, use create_engine

railib/credentials.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ def __init__(self, access_token: str, expires_in: int):
4646
self.created_on = round(time.time())
4747

4848
def is_expired(self):
49-
return time.time() - self.created_on >= self.expires_in
49+
return time.time() - self.created_on >= self.expires_in - 5 # anticipate token expiration by 5 seconds
5050

5151

5252
# Represents OAuth client credentials.

0 commit comments

Comments
 (0)