Skip to content

Commit

Permalink
refactor: notification queries (#1563)
Browse files Browse the repository at this point in the history
  • Loading branch information
Jonas1312 authored Oct 27, 2023
1 parent daa87fa commit f57c891
Show file tree
Hide file tree
Showing 15 changed files with 163 additions and 83 deletions.
3 changes: 1 addition & 2 deletions docs/sdk/notification.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
# Notification module

## Queries
::: kili.entrypoints.queries.notification.__init__.QueriesNotification
::: kili.presentation.client.notification.NotificationClientMethods
4 changes: 4 additions & 0 deletions src/kili/adapters/kili_api_gateway/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
from kili.adapters.kili_api_gateway.cloud_storage import CloudStorageOperationMixin
from kili.adapters.kili_api_gateway.issue import IssueOperationMixin
from kili.adapters.kili_api_gateway.label.operations_mixin import LabelOperationMixin
from kili.adapters.kili_api_gateway.notification.operations_mixin import (
NotificationOperationMixin,
)
from kili.adapters.kili_api_gateway.organization.operations_mixin import (
OrganizationOperationMixin,
)
Expand All @@ -21,6 +24,7 @@ class KiliAPIGateway(
CloudStorageOperationMixin,
IssueOperationMixin,
LabelOperationMixin,
NotificationOperationMixin,
OrganizationOperationMixin,
ProjectOperationMixin,
TagOperationMixin,
Expand Down
15 changes: 15 additions & 0 deletions src/kili/adapters/kili_api_gateway/notification/mappers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
"""Mappers for notification API calls."""

from typing import Dict

from kili.adapters.kili_api_gateway.user.mappers import user_where_mapper
from kili.domain.notification import NotificationFilter


def map_notification_filter(filters: NotificationFilter) -> Dict:
"""Build the GraphQL NotificationWhere variable to be sent in an operation."""
return {
"hasBeenSeen": filters.has_been_seen,
"id": filters.id,
"user": user_where_mapper(filters.user) if filters.user else None,
}
18 changes: 18 additions & 0 deletions src/kili/adapters/kili_api_gateway/notification/operations.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
"""Collection of notification's related GraphQL queries and mutations."""

GQL_COUNT_NOTIFICATIONS = """
query countNotifications($where: NotificationWhere!) {
data: countNotifications(where: $where)
}
"""


def get_notifications_query(fragment: str) -> str:
"""Get the query for notifications."""
return f"""
query notifications($where: NotificationWhere!, $first: PageSize!, $skip: Int!) {{
data: notifications(where: $where, first: $first, skip: $skip) {{
{fragment}
}}
}}
"""
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
"""Mixin extending Kili API Gateway class with notification-related operations."""

from typing import Dict, Generator

from kili.adapters.kili_api_gateway.base import BaseOperationMixin
from kili.adapters.kili_api_gateway.helpers.queries import (
PaginatedGraphQLQuery,
QueryOptions,
fragment_builder,
)
from kili.domain.notification import NotificationFilter
from kili.domain.types import ListOrTuple

from .mappers import map_notification_filter
from .operations import GQL_COUNT_NOTIFICATIONS, get_notifications_query


class NotificationOperationMixin(BaseOperationMixin):
"""GraphQL Mixin extending GraphQL Gateway class with notification-related operations."""

def list_notifications(
self, filters: NotificationFilter, fields: ListOrTuple[str], options: QueryOptions
) -> Generator[Dict, None, None]:
"""List notifications."""
fragment = fragment_builder(fields)
query = get_notifications_query(fragment)
where = map_notification_filter(filters=filters)
return PaginatedGraphQLQuery(self.graphql_client).execute_query_from_paginated_call(
query, where, options, "Retrieving notifications", GQL_COUNT_NOTIFICATIONS
)

def count_notification(self, filters: NotificationFilter) -> int:
"""Count notifications."""
variables = {"where": map_notification_filter(filters=filters)}
return self.graphql_client.execute(GQL_COUNT_NOTIFICATIONS, variables)["data"]
4 changes: 2 additions & 2 deletions src/kili/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
from kili.entrypoints.mutations.plugins import MutationsPlugins
from kili.entrypoints.mutations.project import MutationsProject
from kili.entrypoints.mutations.project_version import MutationsProjectVersion
from kili.entrypoints.queries.notification import QueriesNotification
from kili.entrypoints.queries.plugins import QueriesPlugins
from kili.entrypoints.queries.project_user import QueriesProjectUser
from kili.entrypoints.queries.project_version import QueriesProjectVersion
Expand All @@ -28,6 +27,7 @@
from kili.presentation.client.internal import InternalClientMethods
from kili.presentation.client.issue import IssueClientMethods
from kili.presentation.client.label import LabelClientMethods
from kili.presentation.client.notification import NotificationClientMethods
from kili.presentation.client.organization import OrganizationClientMethods
from kili.presentation.client.project import ProjectClientMethods
from kili.presentation.client.tag import TagClientMethods
Expand Down Expand Up @@ -55,7 +55,6 @@ class Kili( # pylint: disable=too-many-ancestors,too-many-instance-attributes
MutationsPlugins,
MutationsProject,
MutationsProjectVersion,
QueriesNotification,
QueriesPlugins,
QueriesProjectUser,
QueriesProjectVersion,
Expand All @@ -64,6 +63,7 @@ class Kili( # pylint: disable=too-many-ancestors,too-many-instance-attributes
CloudStorageClientMethods,
IssueClientMethods,
LabelClientMethods,
NotificationClientMethods,
OrganizationClientMethods,
ProjectClientMethods,
TagClientMethods,
Expand Down
51 changes: 0 additions & 51 deletions src/kili/core/graphql/operations/notification/queries.py

This file was deleted.

18 changes: 18 additions & 0 deletions src/kili/domain/notification.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
"""Notification domain."""

from dataclasses import dataclass
from typing import TYPE_CHECKING, NewType, Optional

if TYPE_CHECKING:
from .user import UserFilter

NotificationId = NewType("NotificationId", str)


@dataclass
class NotificationFilter:
"""Notification filter."""

has_been_seen: Optional[bool]
id: Optional[NotificationId] # noqa: A003
user: Optional["UserFilter"]
1 change: 0 additions & 1 deletion src/kili/presentation/client/label.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
"""Client presentation methods for labels."""

# pylint: disable=too-many-lines
# pylint: disable=too-many-lines
import warnings
from itertools import repeat
Expand Down
Original file line number Diff line number Diff line change
@@ -1,27 +1,25 @@
"""Notification queries."""
"""Client presentation methods for notifications."""

from typing import Dict, Generator, Iterable, List, Literal, Optional, overload

from typeguard import typechecked

from kili.adapters.kili_api_gateway.helpers.queries import QueryOptions
from kili.core.graphql.operations.notification.queries import (
NotificationQuery,
NotificationWhere,
)
from kili.domain.notification import NotificationFilter, NotificationId
from kili.domain.types import ListOrTuple
from kili.entrypoints.base import BaseOperationEntrypointMixin
from kili.domain.user import UserFilter, UserId
from kili.presentation.client.helpers.common_validators import (
disable_tqdm_if_as_generator,
)
from kili.use_cases.notification import NotificationUseCases
from kili.utils.logcontext import for_all_methods, log_call

from .base import BaseClientMethods

@for_all_methods(log_call, exclude=["__init__"])
class QueriesNotification(BaseOperationEntrypointMixin):
"""Set of Notification queries."""

# pylint: disable=too-many-arguments
@for_all_methods(log_call, exclude=["__init__"])
class NotificationClientMethods(BaseClientMethods):
"""Methods attached to the Kili client, to run actions on notifications."""

@overload
def notifications(
Expand Down Expand Up @@ -103,17 +101,16 @@ def notifications(
Returns:
An iterable of notifications.
"""
where = NotificationWhere(
has_been_seen=has_been_seen,
notification_id=notification_id,
user_id=user_id,
)
disable_tqdm = disable_tqdm_if_as_generator(as_generator, disable_tqdm)
options = QueryOptions(disable_tqdm, first, skip)
notifications_gen = NotificationQuery(self.graphql_client, self.http_client)(
where, fields, options
filters = NotificationFilter(
has_been_seen=has_been_seen,
id=NotificationId(notification_id) if notification_id else None,
user=UserFilter(id=UserId(user_id)) if user_id else None,
)
notifications_gen = NotificationUseCases(self.kili_api_gateway).list_notifications(
options=options, fields=fields, filters=filters
)

if as_generator:
return notifications_gen
return list(notifications_gen)
Expand All @@ -135,9 +132,9 @@ def count_notifications(
Returns:
The number of notifications with the parameters provided
"""
where = NotificationWhere(
filters = NotificationFilter(
has_been_seen=has_been_seen,
notification_id=notification_id,
user_id=user_id,
id=NotificationId(notification_id) if notification_id else None,
user=UserFilter(id=UserId(user_id)) if user_id else None,
)
return NotificationQuery(self.graphql_client, self.http_client).count(where)
return NotificationUseCases(self.kili_api_gateway).count_notifications(filters=filters)
2 changes: 1 addition & 1 deletion src/kili/services/label_import/importer/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ def process_from_files( # pylint: disable=too-many-arguments

self.logger.warning("%d labels have been successfully imported", len(labels))

def process_from_dict( # pylint: disable=too-many-arguments,too-many-locals
def process_from_dict( # pylint: disable=too-many-arguments
self,
project_id: Optional[str],
labels: List[Dict],
Expand Down
9 changes: 5 additions & 4 deletions src/kili/use_cases/asset/__init__.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"""Asset use cases."""

import itertools
from typing import Dict, Generator, List, Literal, Optional
from typing import Generator, Literal, Optional

from kili.adapters.kili_api_gateway.helpers.queries import QueryOptions
from kili.core.constants import QUERY_BATCH_SIZE
Expand Down Expand Up @@ -44,9 +44,10 @@ def list_assets(

if download_media_function is not None:
# TODO: modify download_media function so it can take a generator of assets
assets_lists: List[List[Dict]] = []
for assets_batch in batcher(assets_gen, QUERY_BATCH_SIZE):
assets_lists.append(download_media_function(assets_batch))
assets_lists = [
download_media_function(assets_batch)
for assets_batch in batcher(assets_gen, QUERY_BATCH_SIZE)
]
assets_gen = (asset for asset in itertools.chain(*assets_lists))

if label_output_format == "parsed_label":
Expand Down
24 changes: 24 additions & 0 deletions src/kili/use_cases/notification/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
"""Notification use cases."""

from typing import Dict, Generator

from kili.adapters.kili_api_gateway.helpers.queries import QueryOptions
from kili.domain.notification import NotificationFilter
from kili.domain.types import ListOrTuple
from kili.use_cases.base import BaseUseCases


class NotificationUseCases(BaseUseCases):
"""Notification use cases."""

def list_notifications(
self, filters: NotificationFilter, fields: ListOrTuple[str], options: QueryOptions
) -> Generator[Dict, None, None]:
"""List notifications."""
return self._kili_api_gateway.list_notifications(
filters=filters, fields=fields, options=options
)

def count_notifications(self, filters: NotificationFilter) -> int:
"""Count notifications."""
return self._kili_api_gateway.count_notification(filters=filters)
21 changes: 21 additions & 0 deletions tests/integration/presentation/test_notification.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import pytest_mock

from kili.presentation.client.notification import NotificationClientMethods
from kili.use_cases.notification import NotificationUseCases


def test_given_client_when_fetching_notifications_it_works(
mocker: pytest_mock.MockerFixture, kili_api_gateway
):
mocker.patch.object(
NotificationUseCases, "list_notifications", return_value=(n for n in [{"id": "notif_id"}])
)
# Given
kili = NotificationClientMethods()
kili.kili_api_gateway = kili_api_gateway

# When
notifs = kili.notifications()

# Then
assert notifs == [{"id": "notif_id"}]

0 comments on commit f57c891

Please sign in to comment.