Skip to content

Commit

Permalink
Install ruff and cleanup the code
Browse files Browse the repository at this point in the history
  • Loading branch information
ruscoder committed Jul 8, 2024
1 parent 8cde907 commit c02de5f
Show file tree
Hide file tree
Showing 17 changed files with 1,409 additions and 1,491 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,5 @@ venv
aidbox_python_sdk.egg-info/
.python-version
.vscode
dist
dist
.history
12 changes: 6 additions & 6 deletions Pipfile
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,9 @@ verify_ssl = true
name = "pypi"

[packages]
aiohttp = "~=3.8.3"
aiohttp = "~=3.9.5"
sqlalchemy = "~=2.0.5"
fhirpy = "~=1.3.0"
coloredlogs = "*"
jsonschema = "~=4.17.3"

[dev-packages]
Expand All @@ -16,7 +15,8 @@ pytest-cov = "~=4.0.0"
pytest-asyncio = "~=0.20.2"
pytest = "~=7.2.0"
black = "~=22.12.0"
isort = "~=5.11.2"
autohooks = "~=22.11.2"
autohooks-plugin-isort = "~=22.8.0"
autohooks-plugin-black = "~=22.11.0"
autohooks = "~=24.2.0"
autohooks-plugin-ruff = "~=24.1.0"
autohooks-plugin-black = "~=23.10.0"
coloredlogs = "*"
ruff = "*"
2,539 changes: 1,246 additions & 1,293 deletions Pipfile.lock

Large diffs are not rendered by default.

41 changes: 20 additions & 21 deletions aidbox_python_sdk/aidboxpy.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
# type: ignore because fhir-py is not typed properly
from abc import ABC

from fhirpy.base import (
SyncClient,
AsyncClient,
SyncSearchSet,
AsyncSearchSet,
SyncResource,
AsyncReference,
AsyncResource,
AsyncSearchSet,
SyncClient,
SyncReference,
AsyncReference,
SyncResource,
SyncSearchSet,
)
from fhirpy.base.resource import BaseResource, BaseReference
from fhirpy.base.resource import BaseReference, BaseResource
from fhirpy.base.searchset import AbstractSearchSet

__title__ = "aidbox-py"
Expand Down Expand Up @@ -76,13 +77,14 @@ def reference(self):
Returns reference if local resource is saved
"""
if self.is_local:
return "{0}/{1}".format(self.resource_type, self.id)
return f"{self.resource_type}/{self.id}"
return self.get("url", None)

@property
def id(self):
if self.is_local:
return self.get("id", None)
return None

@property
def resource_type(self):
Expand All @@ -91,6 +93,7 @@ def resource_type(self):
"""
if self.is_local:
return self.get("resourceType", None)
return None

@property
def is_local(self):
Expand All @@ -109,31 +112,27 @@ class SyncAidboxClient(SyncClient):
searchset_class = SyncAidboxSearchSet
resource_class = SyncAidboxResource

def reference(self, resource_type=None, id=None, reference=None, **kwargs):
def reference(self, resource_type=None, resource_id=None, reference=None, **kwargs):
resource_type = kwargs.pop("resourceType", resource_type)
if reference:
if reference.count("/") > 1:
return SyncAidboxReference(self, url=reference, **kwargs)
resource_type, id = reference.split("/")
if not resource_type and not id:
raise TypeError(
"Arguments `resource_type` and `id` or `reference`" "are required"
)
return SyncAidboxReference(self, resourceType=resource_type, id=id, **kwargs)
resource_type, resource_id = reference.split("/")
if not resource_type and not resource_id:
raise TypeError("Arguments `resource_type` and `id` or `reference`are required")
return SyncAidboxReference(self, resourceType=resource_type, id=resource_id, **kwargs)


class AsyncAidboxClient(AsyncClient):
searchset_class = AsyncAidboxSearchSet
resource_class = AsyncAidboxResource

def reference(self, resource_type=None, id=None, reference=None, **kwargs):
def reference(self, resource_type=None, resource_id=None, reference=None, **kwargs):
resource_type = kwargs.pop("resourceType", resource_type)
if reference:
if reference.count("/") > 1:
return AsyncAidboxReference(self, url=reference, **kwargs)
resource_type, id = reference.split("/")
if not resource_type and not id:
raise TypeError(
"Arguments `resource_type` and `id` or `reference`" "are required"
)
return AsyncAidboxReference(self, resourceType=resource_type, id=id, **kwargs)
resource_type, resource_id = reference.split("/")
if not resource_type and not resource_id:
raise TypeError("Arguments `resource_type` and `id` or `reference`are required")
return AsyncAidboxReference(self, resourceType=resource_type, id=resource_id, **kwargs)
61 changes: 26 additions & 35 deletions aidbox_python_sdk/db.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,23 @@
import logging
import json
import logging

from aiohttp import BasicAuth, ClientSession
from sqlalchemy import (
BigInteger,
Column,
DateTime,
Enum,
MetaData,
Table,
Text,
text,
TypeDecorator,
Table,
MetaData,
text,
)
from sqlalchemy.dialects.postgresql import ARRAY, JSONB
from sqlalchemy.dialects.postgresql import dialect as postgresql_dialect
from sqlalchemy.sql.elements import ClauseElement
from sqlalchemy.dialects.postgresql import JSONB, ARRAY, dialect as postgresql_dialect

from aidbox_python_sdk.settings import Settings

from .exceptions import AidboxDBException

Expand All @@ -34,24 +37,20 @@ class _JSONB(TypeDecorator):
def process_literal_param(self, value, dialect):
if isinstance(value, dict):
return "'{}'".format(json.dumps(value).replace("'", "''"))
elif isinstance(value, str):
if isinstance(value, str):
return value
raise ValueError(
"Don't know how to literal-quote " "value of type {}".format(type(value))
)
raise ValueError(f"Don't know how to literal-quote value of type {type(value)}")


class _ARRAY(TypeDecorator):
impl = ARRAY

def process_literal_param(self, value, dialect):
if isinstance(value, list):
return "ARRAY{}".format(value)
elif isinstance(value, str):
return f"ARRAY{value}"
if isinstance(value, str):
return value
raise ValueError(
"Don't know how to literal-quote value of type {}".format(type(value))
)
raise ValueError(f"Don't know how to literal-quote value of type {type(value)}")


def create_table(table_name):
Expand All @@ -69,17 +68,18 @@ def create_table(table_name):
nullable=False,
),
Column("resource", _JSONB(astext_type=Text()), nullable=False, index=True),
extend_existing=True
extend_existing=True,
)


class DBProxy(object):
class DBProxy:
_client = None
_settings = None
_table_cache = {}
_table_cache = None

def __init__(self, settings):
def __init__(self, settings: Settings):
self._settings = settings
self._table_cache = {}

async def initialize(self):
basic_auth = BasicAuth(
Expand All @@ -103,19 +103,17 @@ async def raw_sql(self, sql_query, *, execute=False):
if not self._client:
raise ValueError("Client not set")
if not isinstance(sql_query, str):
ValueError("sql_query must be a str")
raise ValueError("sql_query must be a str")
if not execute and sql_query.count(";") > 1:
logger.warning(
"Check that your query does not " "contain two queries separated by `;`"
)
query_url = "{}/$psql".format(self._settings.APP_INIT_URL)
logger.warning("Check that your query does not contain two queries separated by `;`")
query_url = f"{self._settings.APP_INIT_URL}/$psql"
async with self._client.post(
query_url,
json={"query": sql_query},
params={"execute": "true"} if execute else {},
raise_for_status=True,
) as resp:
logger.debug("$psql answer {0}".format(await resp.text()))
logger.debug("$psql answer %s", await resp.text())
results = await resp.json()

if results[0]["status"] == "error":
Expand All @@ -132,31 +130,24 @@ def compile_statement(self, statement):

async def alchemy(self, statement, *, execute=False):
if not isinstance(statement, ClauseElement):
ValueError("statement must be a sqlalchemy expression")
raise ValueError("statement must be a sqlalchemy expression")
query = self.compile_statement(statement)
logger.debug("Built query:\n%s", query)
return await self.raw_sql(query, execute=execute)

async def _get_all_entities_name(self):
# TODO: refactor using sdk.client and fetch_all
query_url = "{}/Entity?type=resource&_elements=id&_count=999".format(
self._settings.APP_INIT_URL
)
query_url = f"{self._settings.APP_INIT_URL}/Entity?type=resource&_elements=id&_count=999"
async with self._client.get(query_url, raise_for_status=True) as resp:
json_resp = await resp.json()
return [entry["resource"]["id"] for entry in json_resp["entry"]]

async def _init_table_cache(self):
table_names = await self._get_all_entities_name()
self._table_cache = {
**{table_name: {"table_name": table_name.lower()} for table_name in table_names},
**{
table_name: {"table_name": table_name.lower()}
for table_name in table_names
},
**{
"{}History".format(table_name): {
"table_name": "{}_history".format(table_name.lower())
}
f"{table_name}History": {"table_name": f"{table_name.lower()}_history"}
for table_name in table_names
},
}
Expand Down
2 changes: 1 addition & 1 deletion aidbox_python_sdk/exceptions.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
class AidboxSDKException(Exception):
class AidboxSDKException(Exception): # noqa: N818
pass


Expand Down
20 changes: 0 additions & 20 deletions aidbox_python_sdk/gunicorn.py

This file was deleted.

18 changes: 8 additions & 10 deletions aidbox_python_sdk/handlers.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import logging
import asyncio
import os
import logging

from aiohttp import web
from fhirpy.base.exceptions import OperationOutcome

Expand All @@ -9,13 +9,13 @@


async def subscription(request, data):
logger.debug("Subscription handler: {}".format(data["handler"]))
logger.debug("Subscription handler: %s", data["handler"])
if "handler" not in data or "event" not in data:
logger.error("`handler` and/or `event` param is missing, data: {}".format(data))
logger.error("`handler` and/or `event` param is missing, data: %s", data)
raise web.HTTPBadRequest()
handler = request.app["sdk"].get_subscription_handler(data["handler"])
if not handler:
logger.error("Subscription handler `{}` was not found".format(data["handler"]))
logger.error("Subscription handler `%s` was not found", "handler")
raise web.HTTPNotFound()
result = handler(data["event"], request)
if asyncio.iscoroutine(result):
Expand All @@ -26,9 +26,7 @@ async def subscription(request, data):
async def operation(request, data):
logger.debug("Operation handler: %s", data["operation"]["id"])
if "operation" not in data or "id" not in data["operation"]:
logger.error(
"`operation` or `operation[id]` param is missing, data: %s", data
)
logger.error("`operation` or `operation[id]` param is missing, data: %s", data)
raise web.HTTPBadRequest()
handler = request.app["sdk"].get_operation_handler(data["operation"]["id"])
if not handler:
Expand Down Expand Up @@ -57,10 +55,10 @@ async def operation(request, data):

@routes.post("/aidbox")
async def dispatch(request):
logger.debug("Dispatch new request {} {}".format(request.method, request.url))
logger.debug("Dispatch new request %s %s", request.method, request.url)
json = await request.json()
if "type" in json and json["type"] in TYPES:
logger.debug("Dispatch to `{}` handler".format(json["type"]))
logger.debug("Dispatch to `%s` handler", json["type"])
return await TYPES[json["type"]](request, json)
req = {
"method": request.method,
Expand Down
Loading

0 comments on commit c02de5f

Please sign in to comment.