Skip to content

Commit

Permalink
Make ruff happy.
Browse files Browse the repository at this point in the history
  • Loading branch information
pkhalaj committed May 15, 2024
1 parent 16fefaf commit 99b7800
Show file tree
Hide file tree
Showing 15 changed files with 117 additions and 40 deletions.
4 changes: 4 additions & 0 deletions trolldb/api/routes/databases.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
response_model=list[str],
summary="Gets the list of all database names")
async def database_names(exclude_defaults: bool = exclude_defaults_query) -> list[str]:
"""TODO."""
db_names = await MongoDB.list_database_names()

if not exclude_defaults:
Expand All @@ -37,6 +38,7 @@ async def database_names(exclude_defaults: bool = exclude_defaults_query) -> lis
responses=Databases.union().fastapi_descriptor,
summary="Gets the list of all collection names for the given database name")
async def collection_names(db: CheckDataBaseDependency) -> list[str]:
"""TODO."""
return await db.list_collection_names()


Expand All @@ -45,6 +47,7 @@ async def collection_names(db: CheckDataBaseDependency) -> list[str]:
responses=database_collection_error_descriptor,
summary="Gets the object ids of all documents for the given database and collection name")
async def documents(collection: CheckCollectionDependency) -> list[str]:
"""TODO."""
return await get_ids(collection.find({}))


Expand All @@ -53,6 +56,7 @@ async def documents(collection: CheckCollectionDependency) -> list[str]:
responses=database_collection_document_error_descriptor,
summary="Gets the document content in json format given its object id, database, and collection name")
async def document_by_id(collection: CheckCollectionDependency, _id: MongoObjectId) -> _DocumentType:
"""TODO."""
if document := await collection.find_one({"_id": _id}):
return dict(document) | {"_id": str(_id)}

Expand Down
5 changes: 5 additions & 0 deletions trolldb/api/routes/datetime_.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,19 @@


class TimeModel(TypedDict):
"""TODO."""
_id: str
_time: datetime


class TimeEntry(TypedDict):
"""TODO."""
_min: TimeModel
_max: TimeModel


class ResponseModel(BaseModel):
"""TODO."""
start_time: TimeEntry
end_time: TimeEntry

Expand All @@ -38,6 +41,7 @@ class ResponseModel(BaseModel):
responses=database_collection_error_descriptor,
summary="Gets the the minimum and maximum values for the start and end times")
async def datetime(collection: CheckCollectionDependency) -> ResponseModel:
"""TODO."""
agg_result = await collection.aggregate([{
"$group": {
"_id": None,
Expand All @@ -48,6 +52,7 @@ async def datetime(collection: CheckCollectionDependency) -> ResponseModel:
}}]).next()

def _aux(query):
"""TODO."""
return get_id(collection.find_one(query))

return ResponseModel(
Expand Down
1 change: 1 addition & 0 deletions trolldb/api/routes/platforms.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,5 @@
responses=database_collection_error_descriptor,
summary="Gets the list of all platform names")
async def platform_names(collection: CheckCollectionDependency) -> list[str]:
"""TODO."""
return await get_distinct_items_in_collection(collection, "platform_name")
9 changes: 5 additions & 4 deletions trolldb/api/routes/queries.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,11 @@
summary="Gets the database UUIDs of the documents that match specifications determined by the query string")
async def queries(
collection: CheckCollectionDependency,
platform: list[str] = Query(None),
sensor: list[str] = Query(None),
time_min: datetime.datetime = Query(None),
time_max: datetime.datetime = Query(None)) -> list[str]:
platform: list[str] = Query(default=None), # noqa: B008
sensor: list[str] = Query(default=None), # noqa: B008
time_min: datetime.datetime = Query(default=None), # noqa: B008
time_max: datetime.datetime = Query(default=None)) -> list[str]: # noqa: B008
"""TODO."""
pipelines = Pipelines()

if platform:
Expand Down
1 change: 1 addition & 0 deletions trolldb/api/routes/root.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,5 @@

@router.get("/", summary="The root route which is mainly used to check the status of connection")
async def root() -> Response:
"""TODO."""
return Response(status_code=status.HTTP_200_OK)
1 change: 1 addition & 0 deletions trolldb/api/routes/sensors.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,5 @@
responses=database_collection_error_descriptor,
summary="Gets the list of all sensor names")
async def sensor_names(collection: CheckCollectionDependency) -> list[str]:
"""TODO."""
return await get_distinct_items_in_collection(collection, "sensor")
10 changes: 7 additions & 3 deletions trolldb/api/tests/conftest.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
"""TODO."""

import pytest

from trolldb.api.api import server_process_context
Expand All @@ -7,13 +9,15 @@


@pytest.fixture(scope="session")
def run_mongodb_server_instance():
def _run_mongodb_server_instance():
"""TODO."""
with mongodb_instance_server_process_context():
yield


@pytest.fixture(scope="session", autouse=True)
def test_server_fixture(run_mongodb_server_instance):
@pytest.fixture(scope="session")
def _test_server_fixture(_run_mongodb_server_instance):
"""TODO."""
TestDatabase.prepare()
with server_process_context(test_app_config, startup_time=2000):
yield
14 changes: 11 additions & 3 deletions trolldb/api/tests/test_api.py
Original file line number Diff line number Diff line change
@@ -1,37 +1,44 @@
"""TODO."""
import pytest
from fastapi import status

from trolldb.test_utils.common import assert_equal, http_get
from trolldb.test_utils.mongodb_database import TestDatabase, test_mongodb_context


@pytest.mark.usefixtures("_test_server_fixture")
def test_root():
"""Checks that the server is up and running, i.e. the root routes responds with 200."""
assert_equal(http_get().status, status.HTTP_200_OK)


@pytest.mark.usefixtures("_test_server_fixture")
def test_platforms():
"""Checks that the retrieved platform names match the expected names."""
assert_equal(http_get("platforms").json(), TestDatabase.platform_names)


@pytest.mark.usefixtures("_test_server_fixture")
def test_sensors():
"""Checks that the retrieved sensor names match the expected names.
"""
"""Checks that the retrieved sensor names match the expected names."""
assert_equal(http_get("sensors").json(), TestDatabase.sensors)


@pytest.mark.usefixtures("_test_server_fixture")
def test_database_names():
"""Checks that the retrieved database names match the expected names."""
assert_equal(http_get("databases").json(), TestDatabase.database_names)
assert_equal(http_get("databases?exclude_defaults=True").json(), TestDatabase.database_names)
assert_equal(http_get("databases?exclude_defaults=False").json(), TestDatabase.all_database_names)


@pytest.mark.usefixtures("_test_server_fixture")
def test_database_names_negative():
"""Checks that the non-existing databases cannot be found."""
assert_equal(http_get("databases/non_existing_database").status, status.HTTP_404_NOT_FOUND)


@pytest.mark.usefixtures("_test_server_fixture")
def test_collections():
"""Check the presence of existing collections and that the ids of documents therein can be correctly retrieved."""
with test_mongodb_context() as client:
Expand All @@ -50,9 +57,10 @@ def test_collections():
)


@pytest.mark.usefixtures("_test_server_fixture")
def test_collections_negative():
"""Checks that the non-existing collections cannot be found."""
for database_name, collection_name in zip(TestDatabase.database_names, TestDatabase.collection_names, strict=False):
for database_name in TestDatabase.database_names:
assert_equal(
http_get(f"databases/{database_name}/non_existing_collection").status,
status.HTTP_404_NOT_FOUND
Expand Down
14 changes: 6 additions & 8 deletions trolldb/database/errors.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
"""The modules which defines the error responses that might occur while working with the
MongoDB database.
"""The modules which defines the error responses that might occur while working with the MongoDB database.
Note:
The error responses are grouped into classes, with each class representing the major
Expand Down Expand Up @@ -79,14 +78,13 @@ class Documents(ResponsesErrorGroup):
database_collection_error_descriptor = (
Databases.union() | Collections.union()
).fastapi_descriptor
"""
A response descriptor for the Fast API routes. This combines all the error messages that might
occur as result of working with databases and collections. See the fast api documentation for TODO.
"""A response descriptor for the Fast API routes.
This combines all the error messages that might occur as result of working with databases and collections. See the
fast api documentation for TODO.
"""

database_collection_document_error_descriptor = (
Databases.union() | Collections.union() | Documents.union()
).fastapi_descriptor
"""
Same as :obj:`database_collection_error_descriptor` but including documents as well.
"""
"""Same as :obj:`database_collection_error_descriptor` but including documents as well."""
15 changes: 15 additions & 0 deletions trolldb/database/piplines.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,45 +21,60 @@ class PipelineDict(dict):
"""

def __or__(self, other: Self):
"""TODO."""
return PipelineDict({"$or": [self, other]})

def __and__(self, other: Self):
"""TODO."""
return PipelineDict({"$and": [self, other]})


class PipelineAttribute:
"""TODO."""

def __init__(self, key: str):
"""TODO."""
self.__key = key

def __eq__(self, other: Any) -> PipelineDict:
"""TODO."""
if isinstance(other, list):
return PipelineDict(**{"$or": [{self.__key: v} for v in other]})
return PipelineDict(**{self.__key: other})

def __aux_operators(self, other: Any, operator: str) -> PipelineDict:
"""TODO."""
return PipelineDict(**{self.__key: {operator: other}} if other else {})

def __ge__(self, other: Any) -> PipelineDict:
"""TODO."""
return self.__aux_operators(other, "$gte")

def __gt__(self, other: Any) -> PipelineDict:
"""TODO."""
return self.__aux_operators(other, "$gt")

def __le__(self, other: Any) -> PipelineDict:
"""TODO."""
return self.__aux_operators(other, "$lte")

def __lt__(self, other: Any) -> PipelineDict:
"""TODO."""
return self.__aux_operators(other, "$le")


class Pipelines(list):
"""TODO."""
def __init__(self, *args, **kwargs):
"""TODO."""
super().__init__(*args, **kwargs)

def __iadd__(self, other):
"""TODO."""
self.extend([{"$match": other}])
return self

def __add__(self, other):
"""TODO."""
self.append({"$match": other})
return self
26 changes: 18 additions & 8 deletions trolldb/errors/errors.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""The module which defines the base functionality for error responses that will be returned by the API.
This module only includes the generic utilities using which each module should define its own error responses
specifically. See :obj:`trolldb.database.errors` as an example on how this module is used.
"""
Expand All @@ -18,19 +19,18 @@ class ResponseError(Exception):
"""The base class for all error responses. This is derivative of the ``Exception`` class."""

descriptor_delimiter: str = " |OR| "
"""
A delimiter to combine the message part of several error responses into a single one. This will be shown in textual
format for the response descriptors of the Fast API routes. For example:
"""A delimiter to combine the message part of several error responses into a single one.
This will be shown in textual format for the response descriptors of the Fast API routes. For example:
``ErrorA |OR| ErrorB``
"""

defaultResponseClass: Response = PlainTextResponse
"""
The default type of the response which will be returned when an error occurs.
"""
DefaultResponseClass: Response = PlainTextResponse
"""The default type of the response which will be returned when an error occurs."""

def __init__(self, args_dict: OrderedDict[StatusCode, str | list[str]] | dict) -> None:
"""TODO."""
self.__dict: OrderedDict = OrderedDict(args_dict)
self.extra_information: dict | None = None

Expand Down Expand Up @@ -64,6 +64,7 @@ def __or__(self, other: Self):
def __assert_existence_multiple_response_codes(
self,
status_code: StatusCode | None = None) -> (StatusCode, str):
"""TODO."""
match status_code, len(self.__dict):
case None, n if n > 1:
raise ValueError("In case of multiple response status codes, the status code must be specified.")
Expand All @@ -80,6 +81,7 @@ def get_error_details(
self,
extra_information: dict | None = None,
status_code: int | None = None) -> (StatusCode, str):
"""TODO."""
status_code, msg = self.__assert_existence_multiple_response_codes(status_code)
return (
status_code,
Expand All @@ -91,6 +93,7 @@ def sys_exit_log(
exit_code: int = -1,
extra_information: dict | None = None,
status_code: int | None = None) -> None:
"""TODO."""
msg, _ = self.get_error_details(extra_information, status_code)
logger.error(msg)
exit(exit_code)
Expand All @@ -99,32 +102,39 @@ def log_as_warning(
self,
extra_information: dict | None = None,
status_code: int | None = None):
"""TODO."""
msg, _ = self.get_error_details(extra_information, status_code)
logger.warning(msg)

@property
def fastapi_descriptor(self) -> dict[StatusCode, dict[Literal["description"], str]]:
"""TODO."""
return {status: {Literal["description"]: ResponseError.__stringify(msg)} for status, msg in self.__dict.items()}

@staticmethod
def __listify(item: str | list[str]) -> list[str]:
"""TODO."""
return item if isinstance(item, list) else [item]

@staticmethod
def __stringify(item: str | list[str]) -> str:
"""TODO."""
return ResponseError.descriptor_delimiter.join(ResponseError.__listify(item))


class ResponsesErrorGroup:
"""TODO."""

@classmethod
def fields(cls):
"""TODO."""
return {k: v for k, v in cls.__dict__.items() if isinstance(v, ResponseError)}

@classmethod
def union(cls):
"""TODO."""
buff = None
for k, v in cls.fields().items():
for v in cls.fields().values():
if buff is None:
buff = v
else:
Expand Down
2 changes: 1 addition & 1 deletion trolldb/run_api.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
"""The main entry point to run the API server according to the configurations given in `config.yaml`
"""The main entry point to run the API server according to the configurations given in `config.yaml`.
Note:
For more information on the API server, see the automatically generated documentation by FastAPI.
Expand Down
Loading

0 comments on commit 99b7800

Please sign in to comment.