-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
6672e59
commit f998ba0
Showing
19 changed files
with
322 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
3 changes: 3 additions & 0 deletions
3
src/country_workspace/contrib/dedup_engine/adapters/__init__.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
from .deduplication_set import DeduplicationSetAdapter # noqa | ||
from .duplicate import DuplicateAdapter # noqa | ||
from .image import ImageAdapter # noqa |
25 changes: 25 additions & 0 deletions
25
src/country_workspace/contrib/dedup_engine/adapters/base.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
from urllib.parse import urljoin | ||
from uuid import UUID | ||
|
||
from requests import Session | ||
|
||
from country_workspace.contrib.dedup_engine.models import DeduplicationSet, Image | ||
|
||
|
||
class BaseAdapter: | ||
def __init__(self, session: Session, base_url: str, resource: str) -> None: | ||
self.session = session | ||
self.base_url = urljoin(base_url, f"{resource}/") | ||
|
||
def prepare_url(self, *parts: str) -> str: | ||
return urljoin(self.base_url, "/".join(parts)) | ||
|
||
@staticmethod | ||
def get_entity_id(entity: DeduplicationSet | Image | UUID, id_field: str = "id") -> UUID: | ||
if isinstance(entity, UUID): | ||
return entity | ||
elif isinstance(entity, (DeduplicationSet, Image)): | ||
if not hasattr(entity, id_field): | ||
raise AttributeError(f"Object of type {type(entity).__name__} does not have attribute '{id_field}'") | ||
return getattr(entity, id_field) | ||
raise TypeError(f"Expected DeduplicationSet, Image, or UUID, but got {type(entity).__name__}") |
43 changes: 43 additions & 0 deletions
43
src/country_workspace/contrib/dedup_engine/adapters/deduplication_set.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
from uuid import UUID | ||
|
||
from requests import Session | ||
|
||
from country_workspace.contrib.dedup_engine.adapters.base import BaseAdapter | ||
from country_workspace.contrib.dedup_engine.models import DeduplicationSet, DeduplicationSetCreate | ||
|
||
|
||
class DeduplicationSetAdapter(BaseAdapter): | ||
def __init__(self, session: Session, base_url: str) -> None: | ||
super().__init__(session, base_url, "deduplication_sets") | ||
|
||
def create(self, data: DeduplicationSetCreate) -> DeduplicationSet: | ||
url = self.base_url | ||
response = self.session.post(url, json=data.model_dump(by_alias=True)) | ||
response.raise_for_status() | ||
return DeduplicationSet(**response.json()) | ||
|
||
def destroy(self, data: DeduplicationSet | UUID) -> None: | ||
deduplication_set_id = self.get_entity_id(data) | ||
url = self.prepare_url(str(deduplication_set_id)) | ||
response = self.session.delete(url) | ||
if response.status_code != 204: | ||
response.raise_for_status() | ||
|
||
def list(self) -> list[DeduplicationSet]: | ||
response = self.session.get(self.base_url) | ||
response.raise_for_status() | ||
return [DeduplicationSet(**item) for item in response.json()] | ||
|
||
def retrieve(self, data: DeduplicationSet | UUID) -> DeduplicationSet: | ||
deduplication_set_id = self.get_entity_id(data) | ||
url = self.prepare_url(str(deduplication_set_id)) | ||
response = self.session.get(url) | ||
response.raise_for_status() | ||
return DeduplicationSet(**response.json()) | ||
|
||
def process(self, data: DeduplicationSet | UUID) -> None: | ||
deduplication_set_id = self.get_entity_id(data) | ||
url = self.prepare_url(f"{deduplication_set_id}/process/") | ||
response = self.session.post(url) | ||
if response.status_code != 200: | ||
response.raise_for_status() |
20 changes: 20 additions & 0 deletions
20
src/country_workspace/contrib/dedup_engine/adapters/duplicate.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
from urllib.parse import urljoin | ||
from uuid import UUID | ||
|
||
from requests import Session | ||
|
||
from country_workspace.contrib.dedup_engine.adapters.base import BaseAdapter | ||
from country_workspace.contrib.dedup_engine.models import DeduplicationSet, Duplicate | ||
|
||
|
||
class DuplicateAdapter(BaseAdapter): | ||
def __init__(self, session: Session, base_url: str) -> None: | ||
self.session = session | ||
self.base_url = urljoin(base_url, "deduplication_sets/") | ||
|
||
def list(self, data: DeduplicationSet | UUID) -> list[Duplicate]: | ||
deduplication_set_id = self.get_entity_id(data) | ||
url = self.prepare_url(f"{deduplication_set_id}/duplicates/") | ||
response = self.session.get(url) | ||
response.raise_for_status() | ||
return [Duplicate(**item) for item in response.json()] |
35 changes: 35 additions & 0 deletions
35
src/country_workspace/contrib/dedup_engine/adapters/image.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
from urllib.parse import urljoin | ||
from uuid import UUID | ||
|
||
from requests import Session | ||
|
||
from country_workspace.contrib.dedup_engine.adapters.base import BaseAdapter | ||
from country_workspace.contrib.dedup_engine.models import DeduplicationSet, Image, ImageCreate | ||
|
||
|
||
class ImageAdapter(BaseAdapter): | ||
def __init__(self, session: Session, base_url: str) -> None: | ||
self.session = session | ||
self.base_url = urljoin(base_url, "deduplication_sets/") | ||
|
||
def list(self, data: DeduplicationSet | UUID) -> list[Image]: | ||
deduplication_set_id = self.get_entity_id(data) | ||
url = self.prepare_url(f"{deduplication_set_id}/images/") | ||
response = self.session.get(url) | ||
response.raise_for_status() | ||
return [Image(**item) for item in response.json()] | ||
|
||
def create(self, deduplication_set: DeduplicationSet | UUID, data: ImageCreate) -> Image: | ||
deduplication_set_id = self.get_entity_id(deduplication_set) | ||
url = self.prepare_url(f"{deduplication_set_id}/images/") | ||
response = self.session.post(url, json=data.model_dump(by_alias=True)) | ||
response.raise_for_status() | ||
return Image(**response.json()) | ||
|
||
def delete(self, deduplication_set: DeduplicationSet | UUID, image: Image | UUID) -> None: | ||
deduplication_set_id = self.get_entity_id(deduplication_set) | ||
image_id = self.get_entity_id(image) | ||
url = self.prepare_url(f"{deduplication_set_id}/images/{image_id}/") | ||
response = self.session.delete(url) | ||
if response.status_code != 204: | ||
response.raise_for_status() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
from django.apps import AppConfig | ||
|
||
|
||
class Config(AppConfig): | ||
name = __name__.rpartition(".")[0] | ||
verbose_name = "Country Workspace | Dedup Engine Client" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
from requests import Session | ||
from requests.auth import AuthBase | ||
from requests.models import PreparedRequest | ||
|
||
from country_workspace.contrib.dedup_engine.adapters import DeduplicationSetAdapter, DuplicateAdapter, ImageAdapter | ||
|
||
|
||
class Auth(AuthBase): | ||
def __init__(self, token: str) -> None: | ||
self._auth_header = f"Token {token}" | ||
|
||
def __call__(self, request: PreparedRequest) -> PreparedRequest: | ||
request.headers["Authorization"] = self._auth_header | ||
return request | ||
|
||
|
||
class HDEAPIClient: | ||
def __init__(self, *, base_url: str, token: str) -> None: | ||
self.base_url = base_url.rstrip("/") | ||
self.session = Session() | ||
self.session.auth = Auth(token) | ||
|
||
@property | ||
def deduplication_set(self) -> DeduplicationSetAdapter: | ||
return DeduplicationSetAdapter(self.session, self.base_url) | ||
|
||
@property | ||
def duplicate(self) -> DuplicateAdapter: | ||
return DuplicateAdapter(self.session, self.base_url) | ||
|
||
@property | ||
def image(self) -> ImageAdapter: | ||
return ImageAdapter(self.session, self.base_url) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
class DedupEngineAPIBusinessError(Exception): | ||
def __init__(self, detail: str): | ||
self.detail = detail | ||
super().__init__(f"Business logic error: {detail}") |
3 changes: 3 additions & 0 deletions
3
src/country_workspace/contrib/dedup_engine/models/__init__.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
from .deduplication_set import DeduplicationSet, DeduplicationSetCreate # noqa | ||
from .duplicate import Duplicate # noqa | ||
from .image import Image, ImageCreate # noqa |
52 changes: 52 additions & 0 deletions
52
src/country_workspace/contrib/dedup_engine/models/deduplication_set.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
from datetime import datetime | ||
from enum import Enum | ||
from typing import Any | ||
from uuid import UUID | ||
|
||
from pydantic import BaseModel | ||
|
||
|
||
class DeduplicationSetStatus(Enum): | ||
CLEAN = "Clean" | ||
DIRTY = "Dirty" | ||
|
||
@property | ||
def label(self) -> str: | ||
return self.value | ||
|
||
@property | ||
def description(self) -> str: | ||
if self == DeduplicationSetStatus.CLEAN: | ||
return "Deduplication set is created or already processed" | ||
elif self == DeduplicationSetStatus.DIRTY: | ||
return "Deduplication set needs processing" | ||
|
||
|
||
class DeduplicationSetConfig(BaseModel): | ||
name: str | None = None | ||
settings: dict[str, Any] | None = None | ||
|
||
|
||
class DeduplicationSetCreate(BaseModel): | ||
reference_pk: str | ||
name: str | None = None | ||
description: str | None = None | ||
notification_url: str | None = None | ||
|
||
|
||
class DeduplicationSet(DeduplicationSetCreate): | ||
id: UUID | ||
state: DeduplicationSetStatus | ||
config: DeduplicationSetConfig | None = None | ||
created_at: datetime | ||
updated_at: datetime | None = None | ||
external_system: str | ||
created_by: int | ||
updated_by: int | None = None | ||
|
||
model_config = { | ||
"json_encoders": { | ||
datetime: lambda v: v.isoformat(), | ||
DeduplicationSetStatus: lambda v: v.label, | ||
} | ||
} |
13 changes: 13 additions & 0 deletions
13
src/country_workspace/contrib/dedup_engine/models/duplicate.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
from uuid import UUID | ||
|
||
from pydantic import BaseModel | ||
|
||
|
||
class DuplicateReference(BaseModel): | ||
reference_pk: UUID | ||
|
||
|
||
class Duplicate(BaseModel): | ||
first: DuplicateReference | ||
second: DuplicateReference | ||
score: float |
22 changes: 22 additions & 0 deletions
22
src/country_workspace/contrib/dedup_engine/models/image.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
from datetime import datetime | ||
from uuid import UUID | ||
|
||
from pydantic import BaseModel | ||
|
||
|
||
class ImageCreate(BaseModel): | ||
reference_pk: str # perhaps better UUID, but need changes in the server | ||
filename: str | ||
|
||
|
||
class Image(ImageCreate): | ||
id: UUID | ||
deduplication_set: UUID | ||
created_by: int | None = None | ||
created_at: datetime | ||
|
||
model_config = { | ||
"json_encoders": { | ||
datetime: lambda v: v.isoformat(), | ||
} | ||
} |
Oops, something went wrong.