Skip to content

Commit

Permalink
Access token created on fix (#143)
Browse files Browse the repository at this point in the history
* * Fix setting of the created_on attribute on AccessToken
* Add support for show.problems on TransactionAsyncResponse
* Fix a number of issues with the examples
* Fix a few embarrassing code formatting issues
* add missing files to changeset
* add logging to _request_access_token
* remove spurious warning log when tokens.json file does not exist
* add notes to CHANGELOG.md
  • Loading branch information
bradlo authored Jan 4, 2024
1 parent ea9d5e8 commit 7c514b3
Show file tree
Hide file tree
Showing 10 changed files with 43 additions and 34 deletions.
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# Changelog

## v0.6.19

* Fix setting of created_on attribute on AccessToken
* Fix show.problems on TransactionAsyncResponse
* add logging to _request_access_token
* remove spurious warning log when tokens.json file does not exist
* Fix several problems with the examples

## v0.6.18

* Added retry mechanism for the authentication flow.
Expand Down
2 changes: 1 addition & 1 deletion examples/create_engine.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
def run(engine: str, size: str, profile: str):
cfg = config.read(profile=profile)
ctx = api.Context(**cfg)
api.create_engine(ctx, engine, size)
api.create_engine_wait(ctx, engine, size)
print(json.dumps(api.get_engine(ctx, engine), indent=2))


Expand Down
14 changes: 7 additions & 7 deletions examples/run-all
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,12 @@ python3 ./list_databases.py --state=CREATED
python3 ./list_databases.py --state=NONSENSE
python3 ./list_edbs.py $DATABASE $ENGINE
python3 ./list_models.py $DATABASE $ENGINE
python3 ./get_model.py $DATABASE $ENGINE stdlib
python3 ./get_model.py $DATABASE $ENGINE "rel/stdlib"

# run query
QUERY="x, x^2, x^3, x^4 from x in {1; 2; 3; 4; 5}"
python3 ./run_query.py $DATABASE $ENGINE "$QUERY"
python3 ./run_query.py $DATABASE $ENGINE "$QUERY" --readonly
python3 ./execute.py $DATABASE $ENGINE "$QUERY"
python3 ./execute.py $DATABASE $ENGINE "$QUERY" --readonly
python3 ./show_results.py $DATABASE $ENGINE
python3 ./show_problems.py $DATABASE $ENGINE

Expand All @@ -44,16 +44,16 @@ python3 ./list_models.py $DATABASE $ENGINE

# load_csv
python3 ./load_csv.py $DATABASE $ENGINE sample.csv -r sample_csv
python3 ./run_query.py $DATABASE $ENGINE sample_csv
python3 ./execute.py $DATABASE $ENGINE sample_csv
python3 ./load_csv.py $DATABASE $ENGINE sample_no_header.csv --header-row=0 -r sample_no_header_csv
python3 ./run_query.py $DATABASE $ENGINE sample_no_header_csv
python3 ./execute.py $DATABASE $ENGINE sample_no_header_csv
python3 ./load_csv.py $DATABASE $ENGINE sample_alt_syntax.csv --delim="|" --quotechar="'" -r sample_alt_syntax_csv
python3 ./run_query.py $DATABASE $ENGINE sample_alt_syntax_csv
python3 ./execute.py $DATABASE $ENGINE sample_alt_syntax_csv
python3 ./list_edbs.py $DATABASE $ENGINE

# load_json
python3 ./load_json.py $DATABASE $ENGINE sample.json -r sample_json
python3 ./run_query.py $DATABASE $ENGINE sample_json
python3 ./execute.py $DATABASE $ENGINE sample_json
python3 ./list_edbs.py $DATABASE $ENGINE

# clone database
Expand Down
2 changes: 1 addition & 1 deletion examples/show_problems.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
def run(database: str, engine: str, profile: str):
cfg = config.read(profile=profile)
ctx = api.Context(**cfg)
rsp = api.query(ctx, database, engine, "def output = **nonsense**")
rsp = api.exec(ctx, database, engine, "def output = **nonsense**")
show.problems(rsp)


Expand Down
2 changes: 1 addition & 1 deletion examples/show_results.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
def run(database: str, engine: str, profile: str):
cfg = config.read(profile=profile)
ctx = api.Context(**cfg)
rsp = api.query(ctx, database, engine, "def output = 'a'; 'b'; 'c'")
rsp = api.exec(ctx, database, engine, "def output = 'a'; 'b'; 'c'")
show.results(rsp)


Expand Down
2 changes: 1 addition & 1 deletion railib/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,5 @@
# See the License for the specific language governing permissions and
# limitations under the License.

__version_info__ = (0, 6, 18)
__version_info__ = (0, 6, 19)
__version__ = ".".join(map(str, __version_info__))
8 changes: 0 additions & 8 deletions railib/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -157,8 +157,6 @@ def __init__(


# Transaction async response class


class TransactionAsyncResponse:
def __init__(
self,
Expand All @@ -184,8 +182,6 @@ def __str__(self):


# Transaction async file class


class TransactionAsyncFile:
def __init__(
self,
Expand Down Expand Up @@ -238,8 +234,6 @@ def _get_collection(ctx, path: str, key=None, **kwargs):


# Parse "multipart/form-data" response


def _parse_multipart_form(
content_type: str, content: bytes
) -> List[TransactionAsyncFile]:
Expand Down Expand Up @@ -268,8 +262,6 @@ def _parse_multipart_form(


# Parse TransactionAsync response


def _parse_transaction_async_response(
files: List[TransactionAsyncFile],
) -> TransactionAsyncResponse:
Expand Down
4 changes: 2 additions & 2 deletions railib/credentials.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,11 @@ class Credentials(ABC):

# Represents an OAuth access token.
class AccessToken:
def __init__(self, access_token: str, scope: str, expires_in: int, created_on: float = time.time()):
def __init__(self, access_token: str, scope: str, expires_in: int, created_on: float = None):
self.access_token = access_token
self.scope = scope
self.expires_in = expires_in
self.created_on = created_on
self.created_on = created_on or time.time()

def is_expired(self):
return (
Expand Down
26 changes: 15 additions & 11 deletions railib/rest.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,11 +128,14 @@ def _cache_file() -> str:

# Read oauth cache
def _read_cache() -> dict:
filename = _cache_file()
if not path.exists(filename):
return {}
try:
with open(_cache_file(), 'r') as cache:
with open(filename, 'r') as cache:
return json.loads(cache.read())
except Exception as e:
logger.warning(f'Failed to read token cache {_cache_file()}: {e}')
logger.error(f"can't read token cache {filename}: {e}")
return {}


Expand All @@ -150,7 +153,6 @@ def _write_token_cache(creds: ClientCredentials):
try:
cache = _read_cache()
cache[creds.client_id] = creds.access_token

with open(_cache_file(), 'w') as f:
f.write(json.dumps(cache, default=vars))
except Exception as e:
Expand All @@ -169,6 +171,13 @@ def _get_access_token(ctx: Context, url: str) -> AccessToken:
return creds.access_token.access_token


def _log_request_response(req, rsp):
content_type = req.headers["Content-Type"] if "Content-Type" in req.headers else ""
agent = req.headers["User-Agent"] if "User-Agent" in req.headers else ""
request_id = rsp.headers["X-Request-ID"] if "X-Request-ID" in rsp.headers else ""
logger.debug(f"{rsp._method} HTTP/{rsp.version} {content_type} {rsp.url} {rsp.status} {agent} {request_id}")


def _request_access_token(ctx: Context, url: str) -> AccessToken:
creds = ctx.credentials
assert isinstance(creds, ClientCredentials)
Expand All @@ -195,9 +204,9 @@ def _request_access_token(ctx: Context, url: str) -> AccessToken:
)
_print_request(req)
with _urlopen_with_retry(req, ctx.retries) as rsp:
_log_request_response(req, rsp)
result = json.loads(rsp.read())
token = result.get(ACCESS_KEY_TOKEN_KEY, None)

if token is not None:
expires_in = result.get(EXPIRES_IN_KEY, None)
scope = result.get(SCOPE, None)
Expand Down Expand Up @@ -230,7 +239,7 @@ def _urlopen_with_retry(req: Request, retries: int = 0):
return urlopen(req)
except (URLError, ConnectionError) as e:
logger.warning(f"URL/Connection error occured {req.full_url} (attempt {attempt + 1}/{attempts}). Error message: {str(e)}")

if attempt == attempts - 1:
logger.error(f"Failed to connect to {req.full_url} after {attempts} attempt{'s' if attempts > 1 else ''}")
raise e
Expand All @@ -246,12 +255,7 @@ def request(ctx: Context, method: str, url: str, headers={}, data=None, **kwargs
req = _authenticate(ctx, req)
_print_request(req)
rsp = _urlopen_with_retry(req, ctx.retries)

# logging
content_type = headers["Content-Type"] if "Content-Type" in headers else ""
agent = headers["User-Agent"] if "User-Agent" in headers else ""
request_id = rsp.headers["X-Request-ID"] if "X-Request-ID" in rsp.headers else ""
logger.debug(f"{rsp._method} HTTP/{rsp.version} {content_type} {rsp.url} {rsp.status} {agent} {request_id}")
_log_request_response(req, rsp)
return rsp


Expand Down
9 changes: 7 additions & 2 deletions railib/show.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,10 +74,15 @@ def _show_rel(rsp: dict) -> None:


# Print the problems in the given response dict.
def problems(rsp: dict) -> None:
def problems(rsp) -> None:
if rsp is None:
return
problems = rsp.get("problems", None)
if isinstance(rsp, dict): # v1 transaction
problems = rsp.get("problems", None)
elif isinstance(rsp, TransactionAsyncResponse):
problems = rsp.problems
else:
raise ValueError("bad response type")
if not problems:
return
for problem in problems:
Expand Down

0 comments on commit 7c514b3

Please sign in to comment.