Parcourir la source

Clean imports

Casper van der Wel il y a 1 an
Parent
commit
757bfd9284
56 fichiers modifiés avec 176 ajouts et 374 suppressions
  1. 1 29
      clean_python/__init__.py
  2. 4 0
      clean_python/base/__init__.py
  3. 1 0
      clean_python/base/application/__init__.py
  4. 6 7
      clean_python/base/application/manage.py
  5. 11 0
      clean_python/base/domain/__init__.py
  6. 0 0
      clean_python/base/domain/child_entity.py
  7. 0 1
      clean_python/base/domain/domain_event.py
  8. 4 0
      clean_python/base/domain/domain_service.py
  9. 0 1
      clean_python/base/domain/exceptions.py
  10. 0 1
      clean_python/base/domain/pagination.py
  11. 7 8
      clean_python/base/domain/repository.py
  12. 13 3
      clean_python/base/domain/root_entity.py
  13. 5 0
      clean_python/base/domain/value.py
  14. 5 0
      clean_python/base/domain/value_object.py
  15. 3 0
      clean_python/base/infrastructure/__init__.py
  16. 0 131
      clean_python/base/infrastructure/gateway.py
  17. 6 7
      clean_python/base/infrastructure/internal_gateway.py
  18. 0 7
      clean_python/base/infrastructure/now.py
  19. 2 0
      clean_python/base/infrastructure/tmpdir_provider.py
  20. 1 0
      clean_python/base/presentation/__init__.py
  21. 4 2
      clean_python/base/presentation/link.py
  22. 1 0
      clean_python/celery/__init__.py
  23. 3 4
      clean_python/celery/celery_rmq_broker.py
  24. 3 0
      clean_python/dramatiq/__init__.py
  25. 0 3
      clean_python/dramatiq/async_actor.py
  26. 5 3
      clean_python/dramatiq/dramatiq_task_logger.py
  27. 0 1
      clean_python/dramatiq/sleep_task.py
  28. 6 0
      clean_python/fastapi/__init__.py
  29. 0 1
      clean_python/fastapi/context.py
  30. 8 6
      clean_python/fastapi/error_responses.py
  31. 4 2
      clean_python/fastapi/fastapi_access_logger.py
  32. 3 4
      clean_python/fastapi/request_query.py
  33. 3 1
      clean_python/fastapi/resource.py
  34. 9 7
      clean_python/fastapi/service.py
  35. 1 0
      clean_python/fluentbit/__init__.py
  36. 3 6
      clean_python/fluentbit/fluentbit_gateway.py
  37. 1 0
      clean_python/oauth2/__init__.py
  38. 7 11
      clean_python/oauth2/oauth2.py
  39. 2 0
      clean_python/sql/__init__.py
  40. 9 8
      clean_python/sql/sql_gateway.py
  41. 3 59
      clean_python/sql/sql_provider.py
  42. 2 0
      clean_python/testing/__init__.py
  43. 3 0
      clean_python/testing/attr_dict.py
  44. 2 0
      clean_python/testing/profilers.py
  45. 0 34
      clean_python/testing/testing.py
  46. 3 3
      tests/test_async_actor.py
  47. 1 1
      tests/test_celery_rmq_broker.py
  48. 2 2
      tests/test_dramatiq_task_logger.py
  49. 3 3
      tests/test_exceptions.py
  50. 1 1
      tests/test_fastapi_access_logger.py
  51. 0 1
      tests/test_manage.py
  52. 1 2
      tests/test_oauth2.py
  53. 3 3
      tests/test_request_query.py
  54. 5 5
      tests/test_resource.py
  55. 3 3
      tests/test_service.py
  56. 3 3
      tests/test_sql_gateway.py

+ 1 - 29
clean_python/__init__.py

@@ -1,34 +1,6 @@
-# -*- coding: utf-8 -*-
 # (c) Nelen & Schuurmans
 
-from .base.application.manage import Manage  # NOQA
-from .base.domain.domain_event import *  # NOQA
-from .base.domain.domain_service import DomainService  # NOQA
-from .base.domain.exceptions import *  # NOQA
-from .base.domain.pagination import *  # NOQA
-from .base.domain.repository import Repository  # NOQA
-from .base.domain.root_entity import RootEntity  # NOQA
-from .base.domain.value import Value  # NOQA
-from .base.domain.value_object import ValueObject  # NOQA
-from .base.domain.value_object import ValueObjectWithId  # NOQA
-from .base.infrastructure.gateway import *  # NOQA
-from .base.infrastructure.internal_gateway import InternalGateway  # NOQA
-from .base.infrastructure.now import now  # NOQA
-from .base.infrastructure.tmpdir_provider import *  # NOQA
-from .base.presentation.link import Link  # NOQA
-from .celery.celery_rmq_broker import *  # NOQA
-from .dramatiq.async_actor import *  # NOQA
-from .dramatiq.dramatiq_task_logger import *  # NOQA
-from .fastapi.context import *  # NOQA
-from .fastapi.fastapi_access_logger import *  # NOQA
-from .fastapi.request_query import *  # NOQA
-from .fastapi.resource import *  # NOQA
-from .fastapi.service import Service  # NOQA
-from .fluentbit.fluentbit_gateway import FluentbitGateway  # NOQA
-from .oauth2.oauth2 import *  # NOQA
-from .sql.sql_gateway import SQLGateway  # NOQA
-from .sql.sql_provider import *  # NOQA
-from .testing.attr_dict import AttrDict  # NOQA
+from .base import *  # NOQA
 
 # fmt: off
 __version__ = '0.0.1.dev0'

+ 4 - 0
clean_python/base/__init__.py

@@ -0,0 +1,4 @@
+from .application import *  # NOQA
+from .domain import *  # NOQA
+from .infrastructure import *  # NOQA
+from .presentation import *  # NOQA

+ 1 - 0
clean_python/base/application/__init__.py

@@ -0,0 +1 @@
+from .manage import *  # NOQA

+ 6 - 7
clean_python/base/application/manage.py

@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 # (c) Nelen & Schuurmans
 
 from typing import Any
@@ -8,12 +7,12 @@ from typing import Optional
 from typing import Type
 from typing import TypeVar
 
-from clean_python.base.domain.pagination import Page
-from clean_python.base.domain.pagination import PageOptions
-from clean_python.base.domain.repository import Repository
-from clean_python.base.domain.root_entity import RootEntity
-from clean_python.base.infrastructure.gateway import Filter
-from clean_python.base.infrastructure.gateway import Json
+from clean_python.base.domain import Filter
+from clean_python.base.domain import Json
+from clean_python.base.domain import Page
+from clean_python.base.domain import PageOptions
+from clean_python.base.domain import Repository
+from clean_python.base.domain import RootEntity
 
 T = TypeVar("T", bound=RootEntity)
 

+ 11 - 0
clean_python/base/domain/__init__.py

@@ -0,0 +1,11 @@
+from .domain_event import *  # NOQA
+from .domain_service import *  # NOQA
+from .exceptions import *  # NOQA
+from .filter import *  # NOQA
+from .gateway import *  # NOQA
+from .json import *  # NOQA
+from .pagination import *  # NOQA
+from .repository import *  # NOQA
+from .root_entity import *  # NOQA
+from .value import *  # NOQA
+from .value_object import *  # NOQA

+ 0 - 0
clean_python/base/domain/child_entity.py


+ 0 - 1
clean_python/base/domain/domain_event.py

@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 # (c) Nelen & Schuurmans
 
 from abc import ABC

+ 4 - 0
clean_python/base/domain/domain_service.py

@@ -1,5 +1,9 @@
+# (c) Nelen & Schuurmans
+
 from pydantic import BaseModel
 
+__all__ = ["DomainService"]
+
 
 class DomainService(BaseModel):
     class Config:

+ 0 - 1
clean_python/base/domain/exceptions.py

@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 # (c) Nelen & Schuurmans
 
 from typing import Any

+ 0 - 1
clean_python/base/domain/pagination.py

@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 # (c) Nelen & Schuurmans
 
 from typing import Generic

+ 7 - 8
clean_python/base/domain/repository.py

@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 # (c) Nelen & Schuurmans
 
 from typing import Any
@@ -9,13 +8,13 @@ from typing import Type
 from typing import TypeVar
 from typing import Union
 
-from clean_python.base.domain.exceptions import DoesNotExist
-from clean_python.base.domain.pagination import Page
-from clean_python.base.domain.pagination import PageOptions
-from clean_python.base.domain.root_entity import RootEntity
-from clean_python.base.infrastructure.gateway import Filter
-from clean_python.base.infrastructure.gateway import Gateway
-from clean_python.base.infrastructure.gateway import Json
+from .exceptions import DoesNotExist
+from .filter import Filter
+from .gateway import Gateway
+from .json import Json
+from .pagination import Page
+from .pagination import PageOptions
+from .root_entity import RootEntity
 
 T = TypeVar("T", bound=RootEntity)
 

+ 13 - 3
clean_python/base/domain/root_entity.py

@@ -1,14 +1,24 @@
+# (c) Nelen & Schuurmans
+
 from datetime import datetime
+from datetime import timezone
 from typing import Optional
 from typing import Type
 from typing import TypeVar
 
-from clean_python.base.domain.exceptions import BadRequest
-from clean_python.base.domain.value_object import ValueObject
-from clean_python.base.infrastructure.now import now
+from .exceptions import BadRequest
+from .value_object import ValueObject
+
+
+def now():
+    # this function is there so that we can mock it in tests
+    return datetime.now(timezone.utc)
+
 
 T = TypeVar("T", bound="RootEntity")
 
+__all__ = ["RootEntity", "now"]
+
 
 class RootEntity(ValueObject):
     id: Optional[int] = None

+ 5 - 0
clean_python/base/domain/value.py

@@ -1,3 +1,8 @@
+# (c) Nelen & Schuurmans
+
+__all__ = ["Value"]
+
+
 class Value:
     @classmethod
     def __get_validators__(cls):

+ 5 - 0
clean_python/base/domain/value_object.py

@@ -1,3 +1,5 @@
+# (c) Nelen & Schuurmans
+
 from typing import Optional
 from typing import Type
 from typing import TypeVar
@@ -7,6 +9,9 @@ from pydantic import ValidationError
 
 from .exceptions import BadRequest
 
+__all__ = ["ValueObject"]
+
+
 T = TypeVar("T", bound="ValueObject")
 
 

+ 3 - 0
clean_python/base/infrastructure/__init__.py

@@ -0,0 +1,3 @@
+from .in_memory_gateway import *  # NOQA
+from .internal_gateway import *  # NOQA
+from .tmpdir_provider import *  # NOQA

+ 0 - 131
clean_python/base/infrastructure/gateway.py

@@ -1,131 +0,0 @@
-# -*- coding: utf-8 -*-
-# (c) Nelen & Schuurmans
-
-from copy import deepcopy
-from datetime import datetime
-from typing import Any
-from typing import Callable
-from typing import Dict
-from typing import List
-from typing import Optional
-
-from clean_python.base.domain.exceptions import AlreadyExists
-from clean_python.base.domain.exceptions import Conflict
-from clean_python.base.domain.exceptions import DoesNotExist
-from clean_python.base.domain.pagination import PageOptions
-from clean_python.base.domain.value_object import ValueObject
-
-__all__ = ["Gateway", "Json", "Filter", "InMemoryGateway"]
-Json = Dict[str, Any]
-
-
-class Filter(ValueObject):
-    field: str
-    values: List[Any]
-
-
-class Gateway:
-    async def filter(
-        self, filters: List[Filter], params: Optional[PageOptions] = None
-    ) -> List[Json]:
-        raise NotImplementedError()
-
-    async def count(self, filters: List[Filter]) -> int:
-        return len(await self.filter(filters, params=None))
-
-    async def exists(self, filters: List[Filter]) -> bool:
-        return len(await self.filter(filters, params=PageOptions(limit=1))) > 0
-
-    async def get(self, id: int) -> Optional[Json]:
-        result = await self.filter([Filter(field="id", values=[id])], params=None)
-        return result[0] if result else None
-
-    async def add(self, item: Json) -> Json:
-        raise NotImplementedError()
-
-    async def update(
-        self, item: Json, if_unmodified_since: Optional[datetime] = None
-    ) -> Json:
-        raise NotImplementedError()
-
-    async def update_transactional(self, id: int, func: Callable[[Json], Json]) -> Json:
-        existing = await self.get(id)
-        if existing is None:
-            raise DoesNotExist("record", id)
-        return await self.update(
-            func(existing), if_unmodified_since=existing["updated_at"]
-        )
-
-    async def upsert(self, item: Json) -> Json:
-        try:
-            return await self.update(item)
-        except DoesNotExist:
-            return await self.add(item)
-
-    async def remove(self, id: int) -> bool:
-        raise NotImplementedError()
-
-
-class InMemoryGateway(Gateway):
-    """For testing purposes"""
-
-    def __init__(self, data: List[Json]):
-        self.data = {x["id"]: deepcopy(x) for x in data}
-
-    def _get_next_id(self) -> int:
-        if len(self.data) == 0:
-            return 1
-        else:
-            return max(self.data) + 1
-
-    def _paginate(self, objs: List[Json], params: PageOptions) -> List[Json]:
-        objs = sorted(
-            objs,
-            key=lambda x: (x.get(params.order_by) is None, x.get(params.order_by)),
-            reverse=not params.ascending,
-        )
-        return objs[params.offset : params.offset + params.limit]
-
-    async def filter(
-        self, filters: List[Filter], params: Optional[PageOptions] = None
-    ) -> List[Json]:
-        result = []
-        for x in self.data.values():
-            for filter in filters:
-                if x.get(filter.field) not in filter.values:
-                    break
-            else:
-                result.append(deepcopy(x))
-        if params is not None:
-            result = self._paginate(result, params)
-        return result
-
-    async def add(self, item: Json) -> Json:
-        item = item.copy()
-        id_ = item.pop("id", None)
-        # autoincrement (like SQL does)
-        if id_ is None:
-            id_ = self._get_next_id()
-        elif id_ in self.data:
-            raise AlreadyExists(id_)
-
-        self.data[id_] = {"id": id_, **item}
-        return deepcopy(self.data[id_])
-
-    async def update(
-        self, item: Json, if_unmodified_since: Optional[datetime] = None
-    ) -> Json:
-        _id = item.get("id")
-        if _id is None or _id not in self.data:
-            raise DoesNotExist("item", _id)
-        existing = self.data[_id]
-        if if_unmodified_since and existing.get("updated_at") != if_unmodified_since:
-            raise Conflict()
-        existing.update(item)
-        return deepcopy(existing)
-
-    async def remove(self, id: int) -> bool:
-        if id not in self.data:
-            return False
-        del self.data[id]
-        return True

+ 6 - 7
clean_python/base/infrastructure/internal_gateway.py

@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 # (c) Nelen & Schuurmans
 from abc import abstractmethod
 from abc import abstractproperty
@@ -8,12 +7,12 @@ from typing import Optional
 from typing import TypeVar
 
 from clean_python.base.application.manage import Manage
-from clean_python.base.domain.exceptions import BadRequest
-from clean_python.base.domain.exceptions import DoesNotExist
-from clean_python.base.domain.pagination import PageOptions
-from clean_python.base.domain.root_entity import RootEntity
-from clean_python.base.domain.value_object import ValueObject
-from clean_python.base.infrastructure.gateway import Filter
+from clean_python.base.domain import BadRequest
+from clean_python.base.domain import DoesNotExist
+from clean_python.base.domain import Filter
+from clean_python.base.domain import PageOptions
+from clean_python.base.domain import RootEntity
+from clean_python.base.domain import ValueObject
 
 E = TypeVar("E", bound=RootEntity)  # External
 T = TypeVar("T", bound=ValueObject)  # Internal

+ 0 - 7
clean_python/base/infrastructure/now.py

@@ -1,7 +0,0 @@
-from datetime import datetime
-from datetime import timezone
-
-
-def now():
-    # this function is there so that we can mock it in tests
-    return datetime.now(timezone.utc)

+ 2 - 0
clean_python/base/infrastructure/tmpdir_provider.py

@@ -1,3 +1,5 @@
+# (c) Nelen & Schuurmans
+
 from tempfile import TemporaryDirectory
 from typing import Optional
 

+ 1 - 0
clean_python/base/presentation/__init__.py

@@ -0,0 +1 @@
+from .link import *  # NOQA

+ 4 - 2
clean_python/base/presentation/link.py

@@ -1,8 +1,10 @@
-# -*- coding: utf-8 -*-
 # (c) Nelen & Schuurmans
 
+from typing import TypedDict
+
 from pydantic import AnyHttpUrl
-from typing_extensions import TypedDict
+
+__all__ = ["Link"]
 
 
 class Link(TypedDict):

+ 1 - 0
clean_python/celery/__init__.py

@@ -0,0 +1 @@
+from .celery_rmq_broker import *  # NOQA

+ 3 - 4
clean_python/celery/celery_rmq_broker.py

@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 # (c) Nelen & Schuurmans
 
 import json
@@ -9,9 +8,9 @@ import pika
 from asgiref.sync import sync_to_async
 from pydantic import AnyUrl
 
-from clean_python.base.domain.value_object import ValueObject
-from clean_python.base.infrastructure.gateway import Gateway
-from clean_python.base.infrastructure.gateway import Json
+from clean_python import Gateway
+from clean_python import Json
+from clean_python import ValueObject
 
 __all__ = ["CeleryRmqBroker"]
 

+ 3 - 0
clean_python/dramatiq/__init__.py

@@ -0,0 +1,3 @@
+from .async_actor import *  # NOQA
+from .dramatiq_task_logger import *  # NOQA
+from .sleep_task import *  # NOQA

+ 0 - 3
clean_python/dramatiq/async_actor.py

@@ -1,8 +1,5 @@
-# -*- coding: utf-8 -*-
 # (c) Nelen & Schuurmans
 
-"""Dramatiq configuration"""
-
 import asyncio
 import logging
 import threading

+ 5 - 3
clean_python/dramatiq/dramatiq_task_logger.py

@@ -1,3 +1,5 @@
+# (c) Nelen & Schuurmans
+
 import os
 import threading
 import time
@@ -11,10 +13,10 @@ from dramatiq.errors import Retry
 from dramatiq.message import Message
 from dramatiq.middleware import SkipMessage
 
-from clean_python.base.infrastructure.gateway import Gateway
-from clean_python.fluentbit.fluentbit_gateway import FluentbitGateway
+from clean_python import Gateway
+from clean_python.fluentbit import FluentbitGateway
 
-__all__ = ["AsyncLoggingMiddleware"]
+__all__ = ["AsyncLoggingMiddleware", "DramatiqTaskLogger"]
 
 
 class AsyncLoggingMiddleware(Middleware):

+ 0 - 1
clean_python/dramatiq/sleep_task.py

@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 # (c) Nelen & Schuurmans
 
 import asyncio

+ 6 - 0
clean_python/fastapi/__init__.py

@@ -0,0 +1,6 @@
+from .context import *  # NOQA
+from .error_responses import *  # NOQA
+from .fastapi_access_logger import *  # NOQA
+from .request_query import *  # NOQA
+from .resource import *  # NOQA
+from .service import *  # NOQA

+ 0 - 1
clean_python/fastapi/context.py

@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 # (c) Nelen & Schuurmans
 
 from contextvars import ContextVar

+ 8 - 6
clean_python/fastapi/error_responses.py

@@ -1,3 +1,5 @@
+# (c) Nelen & Schuurmans
+
 from typing import List
 from typing import Union
 
@@ -6,12 +8,12 @@ from fastapi.requests import Request
 from fastapi.responses import JSONResponse
 from starlette import status
 
-from clean_python.base.domain.exceptions import BadRequest
-from clean_python.base.domain.exceptions import Conflict
-from clean_python.base.domain.exceptions import DoesNotExist
-from clean_python.base.domain.exceptions import PermissionDenied
-from clean_python.base.domain.exceptions import Unauthorized
-from clean_python.base.domain.value_object import ValueObject
+from clean_python import BadRequest
+from clean_python import Conflict
+from clean_python import DoesNotExist
+from clean_python import PermissionDenied
+from clean_python import Unauthorized
+from clean_python import ValueObject
 
 __all__ = [
     "ValidationErrorResponse",

+ 4 - 2
clean_python/fastapi/fastapi_access_logger.py

@@ -1,3 +1,5 @@
+# (c) Nelen & Schuurmans
+
 import os
 import time
 from datetime import datetime
@@ -10,8 +12,8 @@ from starlette.background import BackgroundTasks
 from starlette.requests import Request
 from starlette.responses import Response
 
-from clean_python.base.infrastructure.gateway import Gateway
-from clean_python.fluentbit.fluentbit_gateway import FluentbitGateway
+from clean_python import Gateway
+from clean_python.fluentbit import FluentbitGateway
 
 __all__ = ["FastAPIAccessLogger"]
 

+ 3 - 4
clean_python/fastapi/request_query.py

@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 # (c) Nelen & Schuurmans
 
 from typing import List
@@ -6,9 +5,9 @@ from typing import List
 from fastapi import Query
 from pydantic import validator
 
-from clean_python.base.domain.pagination import PageOptions
-from clean_python.base.domain.value_object import ValueObject
-from clean_python.base.infrastructure.gateway import Filter
+from clean_python import Filter
+from clean_python import PageOptions
+from clean_python import ValueObject
 
 __all__ = ["RequestQuery"]
 

+ 3 - 1
clean_python/fastapi/resource.py

@@ -1,3 +1,5 @@
+# (c) Nelen & Schuurmans
+
 from enum import Enum
 from functools import partial
 from typing import Any
@@ -10,7 +12,7 @@ from typing import Type
 
 from fastapi.routing import APIRouter
 
-from clean_python.base.domain.value_object import ValueObject
+from clean_python import ValueObject
 
 __all__ = [
     "Resource",

+ 9 - 7
clean_python/fastapi/service.py

@@ -1,3 +1,5 @@
+# (c) Nelen & Schuurmans
+
 import logging
 from typing import Any
 from typing import Callable
@@ -17,13 +19,13 @@ from starlette.status import HTTP_401_UNAUTHORIZED
 from starlette.status import HTTP_403_FORBIDDEN
 from starlette.types import ASGIApp
 
-from clean_python.base.domain.exceptions import Conflict
-from clean_python.base.domain.exceptions import DoesNotExist
-from clean_python.base.domain.exceptions import PermissionDenied
-from clean_python.base.domain.exceptions import Unauthorized
-from clean_python.base.infrastructure.gateway import Gateway
-from clean_python.oauth2.oauth2 import OAuth2AccessTokenVerifier
-from clean_python.oauth2.oauth2 import OAuth2Settings
+from clean_python import Conflict
+from clean_python import DoesNotExist
+from clean_python import Gateway
+from clean_python import PermissionDenied
+from clean_python import Unauthorized
+from clean_python.oauth2 import OAuth2AccessTokenVerifier
+from clean_python.oauth2 import OAuth2Settings
 
 from .context import RequestMiddleware
 from .error_responses import BadRequest

+ 1 - 0
clean_python/fluentbit/__init__.py

@@ -0,0 +1 @@
+from .fluentbit_gateway import *  # NOQA

+ 3 - 6
clean_python/fluentbit/fluentbit_gateway.py

@@ -1,15 +1,12 @@
-# -*- coding: utf-8 -*-
 # (c) Nelen & Schuurmans
 
-from typing import Any
-from typing import Dict
-
 from asgiref.sync import sync_to_async
 from fluent.sender import FluentSender
 
-from clean_python.base.infrastructure.gateway import Gateway
+from clean_python import Gateway
+from clean_python import Json
 
-Json = Dict[str, Any]
+__all__ = ["FluentbitGateway"]
 
 
 class FluentbitGateway(Gateway):

+ 1 - 0
clean_python/oauth2/__init__.py

@@ -0,0 +1 @@
+from .oauth2 import *  # NOQA

+ 7 - 11
clean_python/oauth2/oauth2.py

@@ -1,7 +1,5 @@
-# -*- coding: utf-8 -*-
 # (c) Nelen & Schuurmans
 
-import logging
 from typing import Dict
 from typing import List
 
@@ -16,8 +14,6 @@ from clean_python.base.domain.exceptions import Unauthorized
 
 __all__ = ["OAuth2Settings", "OAuth2AccessTokenVerifier"]
 
-logger = logging.getLogger(__name__)
-
 
 class OAuth2Settings(BaseModel):
     client_id: str
@@ -61,8 +57,8 @@ class OAuth2AccessTokenVerifier:
         # jwt.get_unverified_header will raise a JWTError if the structure is wrong.
         try:
             key = self.get_key(token)  # JSON Web Key
-        except PyJWTError as e:
-            logger.info("Token is invalid: %s", e)
+        except PyJWTError:
+            # logger.info("Token is invalid: %s", e)
             raise Unauthorized()
         # Step 2: Validate the JWT signature and standard claims
         try:
@@ -76,8 +72,8 @@ class OAuth2AccessTokenVerifier:
                     "require": ["exp", "iss", "sub", "scope", "token_use"],
                 },
             )
-        except PyJWTError as e:
-            logger.info("Token is invalid: %s", e)
+        except PyJWTError:
+            # logger.info("Token is invalid: %s", e)
             raise Unauthorized()
         # Step 3: Verify additional claims. At this point, we have passed
         # verification, so unverified claims may be used safely.
@@ -95,7 +91,7 @@ class OAuth2AccessTokenVerifier:
     def verify_token_use(self, claims):
         """Check the token_use claim."""
         if claims["token_use"] != "access":
-            logger.info("Token has invalid token_use claim: %s", claims["token_use"])
+            # logger.info("Token has invalid token_use claim: %s", claims["token_use"])
             raise Unauthorized()
 
     def verify_scope(self, claims):
@@ -106,11 +102,11 @@ class OAuth2AccessTokenVerifier:
            raster.lizard.net/*.readwrite
         """
         if f"{self.resource_server_id}{self.scope}" not in claims["scope"].split(" "):
-            logger.info("Token has invalid scope claim: %s", claims["scope"])
+            # logger.info("Token has invalid scope claim: %s", claims["scope"])
             raise Unauthorized()
 
     def authorize(self, claims):
         """The subject (sub) claim should be in a hard-coded whitelist."""
         if claims.get("sub") not in self.admin_users:
-            logger.info("User with sub %s is not authorized", claims.get("sub"))
+            # logger.info("User with sub %s is not authorized", claims.get("sub"))
             raise PermissionDenied()

+ 2 - 0
clean_python/sql/__init__.py

@@ -0,0 +1,2 @@
+from .sql_gateway import *  # NOQA
+from .sql_provider import *  # NOQA

+ 9 - 8
clean_python/sql/sql_gateway.py

@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 # (c) Nelen & Schuurmans
 from contextlib import asynccontextmanager
 from datetime import datetime
@@ -23,17 +22,19 @@ from sqlalchemy.sql import Executable
 from sqlalchemy.sql.expression import ColumnElement
 from sqlalchemy.sql.expression import false
 
-from clean_python.base.domain.exceptions import AlreadyExists
-from clean_python.base.domain.exceptions import Conflict
-from clean_python.base.domain.exceptions import DoesNotExist
-from clean_python.base.domain.pagination import PageOptions
-from clean_python.base.infrastructure.gateway import Filter
-from clean_python.base.infrastructure.gateway import Gateway
-from clean_python.base.infrastructure.gateway import Json
+from clean_python import AlreadyExists
+from clean_python import Conflict
+from clean_python import DoesNotExist
+from clean_python import Filter
+from clean_python import Gateway
+from clean_python import Json
+from clean_python import PageOptions
 
 from .sql_provider import SQLDatabase
 from .sql_provider import SQLProvider
 
+__all__ = ["SQLGateway"]
+
 
 def _is_unique_violation_error_id(e: IntegrityError, id: int):
     # sqlalchemy wraps the asyncpg error

+ 3 - 59
clean_python/sql/sql_provider.py

@@ -3,19 +3,17 @@ from abc import abstractmethod
 from contextlib import asynccontextmanager
 from typing import AsyncIterator
 from typing import List
-from unittest import mock
 
-from sqlalchemy.dialects import postgresql
 from sqlalchemy.exc import DBAPIError
 from sqlalchemy.ext.asyncio import AsyncConnection
 from sqlalchemy.ext.asyncio import AsyncEngine
 from sqlalchemy.ext.asyncio import create_async_engine
 from sqlalchemy.sql import Executable
 
-from clean_python.base.domain.exceptions import Conflict
-from clean_python.base.infrastructure.gateway import Json
+from clean_python import Conflict
+from clean_python import Json
 
-__all__ = ["SQLProvider", "SQLDatabase", "FakeSQLDatabase", "assert_query_equal"]
+__all__ = ["SQLProvider", "SQLDatabase"]
 
 
 def is_serialization_error(e: DBAPIError) -> bool:
@@ -56,13 +54,6 @@ class SQLDatabase(SQLProvider):
             async with connection.begin():
                 yield SQLTransaction(connection)
 
-    @asynccontextmanager
-    async def testing_transaction(self) -> AsyncIterator[SQLProvider]:
-        async with self.engine.connect() as connection:
-            async with connection.begin() as transaction:
-                yield SQLTestTransaction(connection)
-                await transaction.rollback()
-
 
 class SQLTransaction(SQLProvider):
     def __init__(self, connection: AsyncConnection):
@@ -80,54 +71,7 @@ class SQLTransaction(SQLProvider):
         # https://docs.python.org/3/library/collections.html#collections.somenamedtuple._asdict
         return [x._asdict() for x in result.fetchall()]
 
-
-class SQLTestTransaction(SQLTransaction):
     @asynccontextmanager
     async def transaction(self) -> AsyncIterator[SQLProvider]:
         async with self.connection.begin_nested():
             yield self
-
-
-class FakeSQLDatabase(SQLProvider):
-    def __init__(self):
-        self.queries: List[List[Executable]] = []
-        self.result = mock.Mock(return_value=[])
-
-    async def execute(self, query: Executable) -> List[Json]:
-        self.queries.append([query])
-        return self.result()
-
-    @asynccontextmanager
-    async def transaction(self) -> AsyncIterator["SQLProvider"]:
-        x = FakeSQLTransaction(result=self.result)
-        self.queries.append(x.queries)
-        yield x
-
-
-class FakeSQLTransaction(SQLProvider):
-    def __init__(self, result: mock.Mock):
-        self.queries: List[Executable] = []
-        self.result = result
-
-    async def execute(self, query: Executable) -> List[Json]:
-        self.queries.append(query)
-        return self.result()
-
-
-def assert_query_equal(q: Executable, expected: str, literal_binds: bool = True):
-    """There are two ways of 'binding' parameters (for testing!):
-
-    literal_binds=True: use the built-in sqlalchemy way, which fails on some datatypes (Range)
-    literal_binds=False: do it yourself using %, there is no 'mogrify' so don't expect quotes.
-    """
-    assert isinstance(q, Executable)
-    compiled = q.compile(
-        compile_kwargs={"literal_binds": literal_binds},
-        dialect=postgresql.dialect(),
-    )
-    if not literal_binds:
-        actual = str(compiled) % compiled.params
-    else:
-        actual = str(compiled)
-    actual = actual.replace("\n", "").replace("  ", " ")
-    assert actual == expected

+ 2 - 0
clean_python/testing/__init__.py

@@ -0,0 +1,2 @@
+from .attr_dict import *  # NOQA
+from .profilers import *  # NOQA

+ 3 - 0
clean_python/testing/attr_dict.py

@@ -1,3 +1,6 @@
+# (c) Nelen & Schuurmans
+
+
 class AttrDict(dict):
     def __init__(self, *args, **kwargs):
         super().__init__(*args, **kwargs)

+ 2 - 0
clean_python/testing/profilers.py

@@ -1,3 +1,5 @@
+# (c) Nelen & Schuurmans
+
 from pathlib import Path
 
 import dramatiq

+ 0 - 34
clean_python/testing/testing.py

@@ -1,34 +0,0 @@
-from contextlib import contextmanager
-from typing import Type
-from unittest import mock
-
-from .manage import Manage
-
-
-@contextmanager
-def mock_manage(manage_cls: Type[Manage], skip=()):
-    """Mock all 'manage_' properties of a Manage class"""
-    manager = manage_cls()
-
-    mocks = {}
-    for attr_name in dir(manage_cls):
-        if not attr_name.startswith("manage_") or attr_name in skip:
-            continue
-        other_manager = getattr(manager, attr_name)
-        if not isinstance(other_manager, Manage):
-            continue
-        mocks[attr_name] = mock.MagicMock(other_manager)
-
-    patchers = [
-        mock.patch.object(
-            manage_cls,
-            name,
-            new_callable=mock.PropertyMock(return_value=x),
-        )
-        for name, x in mocks.items()
-    ]
-    for p in patchers:
-        p.start()
-    yield
-    for p in patchers:
-        p.stop()

+ 3 - 3
tests/test_async_actor.py

@@ -4,9 +4,9 @@ from unittest import mock
 
 import pytest
 
-from clean_python.dramatiq.async_actor import async_actor
-from clean_python.dramatiq.async_actor import AsyncActor
-from clean_python.dramatiq.async_actor import AsyncMiddleware
+from clean_python.dramatiq import async_actor
+from clean_python.dramatiq import AsyncActor
+from clean_python.dramatiq import AsyncMiddleware
 from clean_python.dramatiq.async_actor import EventLoopThread
 
 

+ 1 - 1
tests/test_celery_rmq_broker.py

@@ -2,7 +2,7 @@ from unittest import mock
 
 import pytest
 
-from clean_python.celery.celery_rmq_broker import CeleryRmqBroker
+from clean_python.celery import CeleryRmqBroker
 
 
 @pytest.fixture

+ 2 - 2
tests/test_dramatiq_task_logger.py

@@ -5,8 +5,8 @@ import pytest
 from dramatiq.errors import Retry
 from dramatiq.message import Message
 
-from clean_python.base.infrastructure.gateway import InMemoryGateway
-from clean_python.dramatiq.dramatiq_task_logger import DramatiqTaskLogger
+from clean_python import InMemoryGateway
+from clean_python.dramatiq import DramatiqTaskLogger
 
 
 @pytest.fixture

+ 3 - 3
tests/test_exceptions.py

@@ -1,8 +1,8 @@
 from pydantic import ValidationError
 
-from clean_python.base.domain.exceptions import BadRequest
-from clean_python.base.domain.exceptions import DoesNotExist
-from clean_python.base.domain.value_object import ValueObject
+from clean_python import BadRequest
+from clean_python import DoesNotExist
+from clean_python import ValueObject
 
 
 def test_bad_request_short_str():

+ 1 - 1
tests/test_fastapi_access_logger.py

@@ -6,8 +6,8 @@ from starlette.requests import Request
 from starlette.responses import JSONResponse
 from starlette.responses import StreamingResponse
 
-from clean_python import FastAPIAccessLogger
 from clean_python import InMemoryGateway
+from clean_python.fastapi import FastAPIAccessLogger
 
 
 @pytest.fixture

+ 0 - 1
tests/test_manage.py

@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 # (c) Nelen & Schuurmans
 
 from unittest import mock

+ 1 - 2
tests/test_oauth2.py

@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 # (c) Nelen & Schuurmans
 
 import time
@@ -7,9 +6,9 @@ from unittest import mock
 import jwt
 import pytest
 
-from clean_python import OAuth2AccessTokenVerifier
 from clean_python import PermissionDenied
 from clean_python import Unauthorized
+from clean_python.oauth2 import OAuth2AccessTokenVerifier
 
 
 @pytest.fixture

+ 3 - 3
tests/test_request_query.py

@@ -3,9 +3,9 @@ from typing import Optional
 import pytest
 from pydantic import ValidationError
 
-from clean_python.base.domain.pagination import PageOptions
-from clean_python.base.infrastructure.gateway import Filter
-from clean_python.fastapi.request_query import RequestQuery
+from clean_python import Filter
+from clean_python import PageOptions
+from clean_python.fastapi import RequestQuery
 
 
 class SomeQuery(RequestQuery):

+ 5 - 5
tests/test_resource.py

@@ -1,11 +1,11 @@
 import pytest
 from fastapi.routing import APIRouter
 
-from clean_python.fastapi.resource import APIVersion
-from clean_python.fastapi.resource import get
-from clean_python.fastapi.resource import Resource
-from clean_python.fastapi.resource import Stability
-from clean_python.fastapi.resource import v
+from clean_python.fastapi import APIVersion
+from clean_python.fastapi import get
+from clean_python.fastapi import Resource
+from clean_python.fastapi import Stability
+from clean_python.fastapi import v
 
 
 def test_subclass():

+ 3 - 3
tests/test_service.py

@@ -1,8 +1,8 @@
 import pytest
 
-from clean_python import Resource
-from clean_python import Service
-from clean_python import v
+from clean_python.fastapi import Resource
+from clean_python.fastapi import Service
+from clean_python.fastapi import v
 
 
 class V1Foo(Resource, version=v(1), name="foo"):

+ 3 - 3
tests/test_sql_gateway.py

@@ -11,13 +11,13 @@ from sqlalchemy import MetaData
 from sqlalchemy import Table
 from sqlalchemy import Text
 
-from clean_python import assert_query_equal
 from clean_python import Conflict
 from clean_python import DoesNotExist
-from clean_python import FakeSQLDatabase
 from clean_python import Filter
 from clean_python import PageOptions
-from clean_python import SQLGateway
+from clean_python.sql import SQLGateway
+from clean_python.sql.testing import assert_query_equal
+from clean_python.sql.testing import FakeSQLDatabase
 
 writer = Table(
     "writer",