module-typica 0.2.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- module_typica-0.2.2/PKG-INFO +31 -0
- module_typica-0.2.2/Readme.md +14 -0
- module_typica-0.2.2/pyproject.toml +25 -0
- module_typica-0.2.2/typica/__init__.py +4 -0
- module_typica-0.2.2/typica/base.py +65 -0
- module_typica-0.2.2/typica/connection.py +137 -0
- module_typica-0.2.2/typica/metadata.py +74 -0
- module_typica-0.2.2/typica/response.py +294 -0
- module_typica-0.2.2/typica/utils/__init__.py +1 -0
- module_typica-0.2.2/typica/utils/enums.py +80 -0
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: module-typica
|
|
3
|
+
Version: 0.2.2
|
|
4
|
+
Summary: Standard Pydantic usages & utilities
|
|
5
|
+
Author: Oktapian
|
|
6
|
+
Author-email: oktapian@jkt1.ebdesk.com
|
|
7
|
+
Requires-Python: >=3.10,<4.0
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
12
|
+
Requires-Dist: deprecated (>=1.2.14,<2.0.0)
|
|
13
|
+
Requires-Dist: pydantic (>=2.9.2,<3.0.0)
|
|
14
|
+
Requires-Dist: pydantic-settings (>=2.6.1,<3.0.0)
|
|
15
|
+
Requires-Dist: tomli (>=2.1.0,<3.0.0)
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
|
|
18
|
+
# Description
|
|
19
|
+
[](https://www.python.org/downloads/release/python-3100/)
|
|
20
|
+
[](https://pydantic.dev)
|
|
21
|
+
|
|
22
|
+
This is a standardized model library that uses the pydantic library, which is often used in work, especially in database connection, parameter, or response in service, and other utilities. This repository provides a standardized model that can be used in various scenarios. It aims to simplify the process of defining and validating models in Python applications.
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
## Contributors
|
|
26
|
+
|
|
27
|
+
[//]: contributor-faces
|
|
28
|
+
|
|
29
|
+
<a href="https://github.com/oktapiancaw"><img src="https://avatars.githubusercontent.com/u/48079010?v=4" title="Oktapian Candra" width="80" height="80" style="border-radius: 50%"></a>
|
|
30
|
+
|
|
31
|
+
[//]: contributor-faces
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# Description
|
|
2
|
+
[](https://www.python.org/downloads/release/python-3100/)
|
|
3
|
+
[](https://pydantic.dev)
|
|
4
|
+
|
|
5
|
+
This is a standardized model library that uses the pydantic library, which is often used in work, especially in database connection, parameter, or response in service, and other utilities. This repository provides a standardized model that can be used in various scenarios. It aims to simplify the process of defining and validating models in Python applications.
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
## Contributors
|
|
9
|
+
|
|
10
|
+
[//]: contributor-faces
|
|
11
|
+
|
|
12
|
+
<a href="https://github.com/oktapiancaw"><img src="https://avatars.githubusercontent.com/u/48079010?v=4" title="Oktapian Candra" width="80" height="80" style="border-radius: 50%"></a>
|
|
13
|
+
|
|
14
|
+
[//]: contributor-faces
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
[tool.poetry]
|
|
2
|
+
name = "module-typica"
|
|
3
|
+
version = "0.2.2"
|
|
4
|
+
description = "Standard Pydantic usages & utilities"
|
|
5
|
+
authors = ["Oktapian <oktapian@jkt1.ebdesk.com>"]
|
|
6
|
+
readme = "Readme.md"
|
|
7
|
+
packages = [{include = "typica"}]
|
|
8
|
+
|
|
9
|
+
[tool.pyright]
|
|
10
|
+
venvPath = "."
|
|
11
|
+
venv = ".venv"
|
|
12
|
+
|
|
13
|
+
[tool.poetry.dependencies]
|
|
14
|
+
python = "^3.10"
|
|
15
|
+
pydantic = "^2.9.2"
|
|
16
|
+
pydantic-settings = "^2.6.1"
|
|
17
|
+
tomli = "^2.1.0"
|
|
18
|
+
deprecated = "^1.2.14"
|
|
19
|
+
|
|
20
|
+
[tool.poetry.group.dev.dependencies]
|
|
21
|
+
faker = "^25.3.0"
|
|
22
|
+
|
|
23
|
+
[build-system]
|
|
24
|
+
requires = ["poetry-core"]
|
|
25
|
+
build-backend = "poetry.core.masonry.api"
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import uuid
|
|
2
|
+
|
|
3
|
+
from typing import Optional
|
|
4
|
+
from datetime import datetime
|
|
5
|
+
|
|
6
|
+
from pydantic import BaseModel, Field, model_validator
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class StringIdentifier(BaseModel):
|
|
10
|
+
id: str = Field(default_factory=lambda: str(uuid.uuid4()), description="Identifier of data with string uuidv4", examples=['f82192c2460965cd0a9ce68305c1969a4'])
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class StringIdentifier_(BaseModel):
|
|
14
|
+
id: str = Field(default_factory=lambda: str(uuid.uuid4()), alias='_id', description="Identifier of data with string uuidv4", examples=['f82192c2460965cd0a9ce68305c1969a4'])
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class UUIDIdentifier(BaseModel):
|
|
18
|
+
id: uuid.UUID = Field(default_factory=uuid.uuid4, description="Identifier of data with UUID format", examples=['f82192c2460965cd0a9ce68305c1969a4'])
|
|
19
|
+
|
|
20
|
+
@model_validator(mode="before")
|
|
21
|
+
def validate_uuid(cls, values):
|
|
22
|
+
"""
|
|
23
|
+
Validate if id is str, then convert to uuid.UUID
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
if isinstance(values.get("id"), str):
|
|
27
|
+
values["id"] = uuid.UUID(values["id"])
|
|
28
|
+
return values
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class UUIDIdentifier_(BaseModel):
|
|
32
|
+
id: uuid.UUID = Field(default_factory=uuid.uuid4, alias='_id', description='Identifier of data with UUID format', examples=['f82192c2460965cd0a9ce68305c1969a4'])
|
|
33
|
+
|
|
34
|
+
@model_validator(mode="before")
|
|
35
|
+
def validate_uuid(cls, values):
|
|
36
|
+
"""
|
|
37
|
+
Validate if _id is str, then convert to uuid.UUID
|
|
38
|
+
"""
|
|
39
|
+
if isinstance(values.get("_id"), str):
|
|
40
|
+
values["_id"] = uuid.UUID(values["_id"])
|
|
41
|
+
return values
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class CreationMeta(BaseModel):
|
|
45
|
+
created_at: Optional[datetime] = Field(
|
|
46
|
+
default_factory=datetime.now, description="When data was created", examples=['2022-08-08T00:00:00.000000+00:00', 1661416000, 1661416000000]
|
|
47
|
+
)
|
|
48
|
+
created_by: Optional[str] = Field(None, description="Whos created the data")
|
|
49
|
+
|
|
50
|
+
@model_validator(mode="before")
|
|
51
|
+
def validate_created_at(cls, values):
|
|
52
|
+
"""
|
|
53
|
+
Validate if created_at is str, then convert to datetime
|
|
54
|
+
If created_at is int, then convert to datetime using fromtimestamp
|
|
55
|
+
If created_at is int and length is more than 10, then divide by 1000 first
|
|
56
|
+
"""
|
|
57
|
+
if isinstance(values.get("created_at"), str):
|
|
58
|
+
values["created_at"] = datetime.fromisoformat(values["created_at"])
|
|
59
|
+
if isinstance(values.get("created_at"), int):
|
|
60
|
+
if str(values["created_at"]).__len__() <= 10:
|
|
61
|
+
values["created_at"] = datetime.fromtimestamp(values["created_at"])
|
|
62
|
+
else:
|
|
63
|
+
values["created_at"] = datetime.fromtimestamp(int(values["created_at"] / 1000))
|
|
64
|
+
return values
|
|
65
|
+
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import re
|
|
2
|
+
from typing import Optional
|
|
3
|
+
|
|
4
|
+
from pydantic import BaseModel, Field, model_validator
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class EndpointMeta(BaseModel):
|
|
9
|
+
host: Optional[str] = Field("localhost", description="Connection host")
|
|
10
|
+
port: Optional[str | int] = Field(8000, description="Connection port")
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class AuthMeta(BaseModel):
|
|
15
|
+
username: Optional[str] = Field(None, description="Database username")
|
|
16
|
+
password: Optional[str] = Field(None, description="Database password")
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class URIConnectionMeta(BaseModel):
|
|
20
|
+
uri: Optional[str] = Field("", description="Database connection URI")
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class DBConnectionMeta(EndpointMeta, AuthMeta, URIConnectionMeta):
|
|
24
|
+
database: Optional[str] = Field(None, description="Database name")
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def uri_string(self, base: str = "http", with_db: bool = True) -> str:
|
|
28
|
+
"""
|
|
29
|
+
Return a URI string for the database connection.
|
|
30
|
+
|
|
31
|
+
:param base: The base of the URI (e.g. "http", "postgresql", etc.).
|
|
32
|
+
:param with_db: Whether to include the database name in the URI.
|
|
33
|
+
:return: A string representing the URI.
|
|
34
|
+
"""
|
|
35
|
+
if self.host:
|
|
36
|
+
meta = f"{self.host}:{self.port}"
|
|
37
|
+
if self.username:
|
|
38
|
+
return f"{base}://{self.username}:{self.password}@{meta}/{self.database if with_db else ''}"
|
|
39
|
+
return f"{base}://{meta}/{self.database if with_db else ''}"
|
|
40
|
+
return ""
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
@model_validator(mode="after")
|
|
44
|
+
def extract_uri(self):
|
|
45
|
+
if self.uri:
|
|
46
|
+
uri = re.sub(r"\w+:(//|/)", "", self.uri)
|
|
47
|
+
metadata, others = (
|
|
48
|
+
re.split(r"\/\?|\/", uri) if re.search(r"\/\?|\/", uri) else [uri, None]
|
|
49
|
+
)
|
|
50
|
+
if others and "&" in others:
|
|
51
|
+
for other in others.split("&"):
|
|
52
|
+
if "=" in other and re.search(r"authSource", other):
|
|
53
|
+
self.database = other.split("=")[-1]
|
|
54
|
+
elif "=" not in other:
|
|
55
|
+
self.database = other
|
|
56
|
+
if "@" in metadata:
|
|
57
|
+
self.username, self.password, self.host, self.port = re.split(
|
|
58
|
+
r"\@|\:", metadata
|
|
59
|
+
)
|
|
60
|
+
else:
|
|
61
|
+
self.host, self.port = re.split(r"\:", metadata)
|
|
62
|
+
if self.port:
|
|
63
|
+
self.port = int(self.port)
|
|
64
|
+
return self
|
|
65
|
+
|
|
66
|
+
class ClusterConnectionMeta(AuthMeta, URIConnectionMeta):
|
|
67
|
+
cluster_uri: Optional[list[EndpointMeta]] = Field([], description="List of clusters endpoint")
|
|
68
|
+
database: Optional[str] = Field(None, description="Database name")
|
|
69
|
+
|
|
70
|
+
def uri_string(self, base: str = "http", with_db: bool = True) -> str:
|
|
71
|
+
"""
|
|
72
|
+
Return a URI string for the database connection.
|
|
73
|
+
|
|
74
|
+
:param base: The base of the URI (e.g. "http", "postgresql", etc.).
|
|
75
|
+
:param with_db: Whether to include the database name in the URI.
|
|
76
|
+
:return: A string representing the URI.
|
|
77
|
+
"""
|
|
78
|
+
if self.cluster_uri:
|
|
79
|
+
meta = ",".join([f"{c.host}:{c.port}" for c in self.cluster_uri])
|
|
80
|
+
if self.username:
|
|
81
|
+
return f"{base}://{self.username}:{self.password}@{meta}/{self.database if with_db else ''}"
|
|
82
|
+
return f"{base}://{meta}/{self.database if with_db else ''}"
|
|
83
|
+
return ""
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
@model_validator(mode="after")
|
|
87
|
+
def extract_uri(self):
|
|
88
|
+
if self.uri:
|
|
89
|
+
uri = re.sub(r"\w+:(//|/)", "", self.uri)
|
|
90
|
+
metadata, others = (
|
|
91
|
+
re.split(r"\/\?|\/", uri) if re.search(r"\/\?|\/", uri) else [uri, None]
|
|
92
|
+
)
|
|
93
|
+
if others and "&" in others:
|
|
94
|
+
for other in others.split("&"):
|
|
95
|
+
if "=" in other and re.search(r"authSource", other):
|
|
96
|
+
self.database = other.split("=")[-1]
|
|
97
|
+
elif "=" not in other:
|
|
98
|
+
self.database = other
|
|
99
|
+
if "@" in metadata:
|
|
100
|
+
if "," in metadata:
|
|
101
|
+
metadata, raw_clusters = re.split(r"\@", metadata)
|
|
102
|
+
self.username, self.password = re.split(r"\:", metadata)
|
|
103
|
+
cluster_uri = []
|
|
104
|
+
for cluster in raw_clusters.split(","):
|
|
105
|
+
hostData = re.split(r"\:", cluster)
|
|
106
|
+
cluster_uri.append(EndpointMeta(host=hostData[0], port=int(hostData[1])))
|
|
107
|
+
self.cluster_uri = cluster_uri
|
|
108
|
+
else:
|
|
109
|
+
self.username, self.password, self.host, self.port = re.split(
|
|
110
|
+
r"\@|\:", metadata
|
|
111
|
+
)
|
|
112
|
+
else:
|
|
113
|
+
self.host, self.port = re.split(r"\:", metadata)
|
|
114
|
+
if self.port:
|
|
115
|
+
self.port = int(self.port)
|
|
116
|
+
return self
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
class S3ConnectionMeta(EndpointMeta):
|
|
120
|
+
access_key: Optional[str] = Field(None, description="S3 access key")
|
|
121
|
+
secret_key: Optional[str] = Field(None, description="S3 secret key")
|
|
122
|
+
bucket: str = Field(..., description="S3 bucket name")
|
|
123
|
+
base_path: Optional[str] = Field("/", description="S3 base path")
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
@property
|
|
127
|
+
def json_meta(self) -> dict:
|
|
128
|
+
"""
|
|
129
|
+
Return a dictionary of metadata for connecting to S3.
|
|
130
|
+
|
|
131
|
+
:return: A dictionary with the endpoint_url, access_key, and secret_key.
|
|
132
|
+
"""
|
|
133
|
+
return {
|
|
134
|
+
"endpoint_url": f"http://{self.host}:{self.port}",
|
|
135
|
+
"key": self.access_key,
|
|
136
|
+
"secret": self.secret_key,
|
|
137
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
|
|
2
|
+
from typing import Optional
|
|
3
|
+
|
|
4
|
+
from pydantic import BaseModel, Field
|
|
5
|
+
|
|
6
|
+
from .utils import MedallionTypes, LocationLevel
|
|
7
|
+
from .connection import DBConnectionMeta, S3ConnectionMeta, ClusterConnectionMeta
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class SchemaMeta(BaseModel):
|
|
11
|
+
field_name: str
|
|
12
|
+
field_type: str
|
|
13
|
+
field_alias: Optional[str] = Field(None, description="Alias name field")
|
|
14
|
+
field_alias_type: Optional[str] = Field(None, description="Alias type field")
|
|
15
|
+
field_required: Optional[bool] = Field(False, description="Required field")
|
|
16
|
+
field_hide: Optional[bool] = Field(False, description="Hide field")
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class SimplifieMetadata(BaseModel):
|
|
20
|
+
id: str = Field(..., description="Identifier for the metadata")
|
|
21
|
+
|
|
22
|
+
# ? basic
|
|
23
|
+
title: str = Field(..., description="Title, name, or label for the metadata")
|
|
24
|
+
source: str = Field(..., description="Source of the metadata, e.g. www.example.com")
|
|
25
|
+
country: str = Field(..., description="Country of origin")
|
|
26
|
+
year: str = Field(..., description="Year of the metadata")
|
|
27
|
+
range_data: str = Field(..., description="Range of data, eg. 2021-2022")
|
|
28
|
+
description: Optional[str] = Field(None)
|
|
29
|
+
|
|
30
|
+
# ? Category
|
|
31
|
+
category: str = Field(..., description="Category of the metadata")
|
|
32
|
+
sub_category: Optional[str] = Field(None)
|
|
33
|
+
|
|
34
|
+
# ? Schemas
|
|
35
|
+
schemas: list[SchemaMeta] = Field(..., description="Description of all fields in data")
|
|
36
|
+
|
|
37
|
+
# ? Database
|
|
38
|
+
database_access: DBConnectionMeta | ClusterConnectionMeta
|
|
39
|
+
table_name: str = Field(..., description="Table name in database")
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
class FullMetadata(SimplifieMetadata):
|
|
43
|
+
# ? Basic
|
|
44
|
+
sub_title: Optional[str] = Field(None)
|
|
45
|
+
|
|
46
|
+
# ? Detail data from source
|
|
47
|
+
# * Use case: bronze
|
|
48
|
+
source_desc: Optional[str] = Field(
|
|
49
|
+
None, description="Description from the source of data"
|
|
50
|
+
)
|
|
51
|
+
source_link: Optional[str] = Field(None, description="Link to the source of data")
|
|
52
|
+
|
|
53
|
+
# ? Medalion & Inheritance data
|
|
54
|
+
# * Use case: silver, gold
|
|
55
|
+
parents_id: Optional[list[str]] = Field([])
|
|
56
|
+
medalion_type: MedallionTypes = Field(
|
|
57
|
+
..., description="Medalion type, e.g. BRONZE, SILVER, GOLD"
|
|
58
|
+
)
|
|
59
|
+
joined_by: Optional[str] = Field(None)
|
|
60
|
+
|
|
61
|
+
# ? Locational
|
|
62
|
+
# * Use case: if the table is a location table
|
|
63
|
+
location_level: Optional[LocationLevel] = Field(None)
|
|
64
|
+
location_field: Optional[str] = Field(None)
|
|
65
|
+
|
|
66
|
+
# ? Data lake
|
|
67
|
+
# * Use case: bronze
|
|
68
|
+
lake_access: Optional[S3ConnectionMeta | DBConnectionMeta | ClusterConnectionMeta] = Field(
|
|
69
|
+
None, description="Data lake access"
|
|
70
|
+
)
|
|
71
|
+
lake_meta_path: Optional[str] = Field(None, description="Data lake metadata path")
|
|
72
|
+
lake_data_path: Optional[str] = Field(None, description="Data lake data path")
|
|
73
|
+
lake_data_format: Optional[str] = Field(None, description="Data lake data format")
|
|
74
|
+
|
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
from typing import Any, Optional
|
|
2
|
+
|
|
3
|
+
from pydantic import BaseModel, Field, create_model
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class BaseResponseMeta(BaseModel):
|
|
7
|
+
code: int
|
|
8
|
+
message: str
|
|
9
|
+
|
|
10
|
+
class PaginationResponseMeta(BaseResponseMeta):
|
|
11
|
+
page: Optional[int] = Field(1, gt=0)
|
|
12
|
+
size: Optional[int] = Field(10, ge=0)
|
|
13
|
+
total: Optional[int] = Field(10, ge=0)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class ServiceResponse:
|
|
17
|
+
|
|
18
|
+
def __init__(self, model: Any, auth: bool = False) -> None:
|
|
19
|
+
self.model = model
|
|
20
|
+
self.auth = auth
|
|
21
|
+
|
|
22
|
+
def basic(self, route: str) -> dict:
|
|
23
|
+
"""
|
|
24
|
+
Generate a basic response, which is a dictionary of common response codes and models.
|
|
25
|
+
|
|
26
|
+
Contains:
|
|
27
|
+
- 400 Bad Request
|
|
28
|
+
- 500 Internal Server Error
|
|
29
|
+
|
|
30
|
+
:param route: The path of the route
|
|
31
|
+
:return: A dictionary of common response codes and models
|
|
32
|
+
"""
|
|
33
|
+
return {
|
|
34
|
+
400: {
|
|
35
|
+
"model": create_model(
|
|
36
|
+
route, code=(int, 400), message=(str, "Bad Request")
|
|
37
|
+
),
|
|
38
|
+
"description": "Occurs when the request you make does not match or is invalid",
|
|
39
|
+
},
|
|
40
|
+
500: {
|
|
41
|
+
"model": create_model(
|
|
42
|
+
route,
|
|
43
|
+
code=(int, 500),
|
|
44
|
+
message=(str, "Internal Server Error"),
|
|
45
|
+
),
|
|
46
|
+
"description": "Occurs when there is an engine or lib error in the engine",
|
|
47
|
+
},
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
def get(self, route: str, model: Any = None, obj: str = "Data", auth: bool = False, exclude_codes: list = [], **kwargs) -> dict:
|
|
51
|
+
"""
|
|
52
|
+
Generate a response for a get request, which is a dictionary of common response codes and models.
|
|
53
|
+
|
|
54
|
+
Contains:
|
|
55
|
+
- 200 Success
|
|
56
|
+
- 404 Not Found
|
|
57
|
+
|
|
58
|
+
:param route: The path of the route
|
|
59
|
+
:param model: The model to use for the response
|
|
60
|
+
:param obj: The object name to use for the response
|
|
61
|
+
:param auth: Whether or not the route requires authentication
|
|
62
|
+
:param exclude_codes: A list of codes to exclude from the response
|
|
63
|
+
:return: A dictionary of common response codes and models
|
|
64
|
+
"""
|
|
65
|
+
response: dict = {
|
|
66
|
+
200: {
|
|
67
|
+
"model": create_model(
|
|
68
|
+
route,
|
|
69
|
+
code=(int, 200),
|
|
70
|
+
message=(str, "Success"),
|
|
71
|
+
data=(model if model else self.model, ...),
|
|
72
|
+
),
|
|
73
|
+
"description": "Success get data",
|
|
74
|
+
},
|
|
75
|
+
404: {
|
|
76
|
+
"model": create_model(
|
|
77
|
+
route, code=(int, 404), message=(str, f"{obj} not found")
|
|
78
|
+
),
|
|
79
|
+
},
|
|
80
|
+
**self.basic(route),
|
|
81
|
+
**kwargs
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
if exclude_codes:
|
|
85
|
+
for code in exclude_codes:
|
|
86
|
+
del response[code]
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
if auth or self.auth:
|
|
90
|
+
response[401] = {
|
|
91
|
+
"model": create_model(
|
|
92
|
+
route, code=(int, 401), message=(str, "Unauthorized")
|
|
93
|
+
)
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return response
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def pagination(self, route: str, model: Any = None, obj: str = "Data", auth: bool = False, exclude_codes: list = [], **kwargs) -> dict:
|
|
101
|
+
"""
|
|
102
|
+
Generate a pagination response, which is a dictionary of common response codes and models.
|
|
103
|
+
|
|
104
|
+
Contains:
|
|
105
|
+
- 200 OK
|
|
106
|
+
- 404 Not Found
|
|
107
|
+
- 401 Unauthorized (optional)
|
|
108
|
+
|
|
109
|
+
:param route: The path of the route
|
|
110
|
+
:param model: The model to use for the response
|
|
111
|
+
:param obj: The object to be gotten
|
|
112
|
+
:param auth: Whether or not the route requires authentication
|
|
113
|
+
:param exclude_codes: A list of codes to exclude from the response
|
|
114
|
+
:return: A dictionary of common response codes and models
|
|
115
|
+
"""
|
|
116
|
+
response: dict = {
|
|
117
|
+
200: {
|
|
118
|
+
"model": create_model(
|
|
119
|
+
route,
|
|
120
|
+
code=(int, 200),
|
|
121
|
+
message=(str, f"Success get all {obj}"),
|
|
122
|
+
data=(model if model else self.model, ...),
|
|
123
|
+
page=(int, 1),
|
|
124
|
+
size=(int, 10),
|
|
125
|
+
total=(int, 10),
|
|
126
|
+
),
|
|
127
|
+
},
|
|
128
|
+
404: {
|
|
129
|
+
"model": create_model(
|
|
130
|
+
route, code=(int, 404), message=(str, f"{obj} not found")
|
|
131
|
+
),
|
|
132
|
+
},
|
|
133
|
+
**self.basic(route),
|
|
134
|
+
**kwargs
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
if exclude_codes:
|
|
138
|
+
for code in exclude_codes:
|
|
139
|
+
del response[code]
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
if auth or self.auth:
|
|
143
|
+
response[401] = {
|
|
144
|
+
"model": create_model(
|
|
145
|
+
route, code=(int, 401), message=(str, "Unauthorized")
|
|
146
|
+
)
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
return response
|
|
150
|
+
|
|
151
|
+
def creation(self, route: str, model: Any = None, obj: str = "Data", auth: bool = False, exclude_codes: list = [], **kwargs) -> dict:
|
|
152
|
+
"""
|
|
153
|
+
Generate a response for a create request, which is a dictionary of common response codes and models.
|
|
154
|
+
|
|
155
|
+
Contains:
|
|
156
|
+
- 201 Created
|
|
157
|
+
- 401 Unauthorized
|
|
158
|
+
|
|
159
|
+
:param route: The path of the route
|
|
160
|
+
:param model: The model to use for the response
|
|
161
|
+
:param obj: The object name to use for the response
|
|
162
|
+
:param auth: Whether or not the route requires authentication
|
|
163
|
+
:param exclude_codes: A list of codes to exclude from the response
|
|
164
|
+
:return: A dictionary of common response codes and models
|
|
165
|
+
"""
|
|
166
|
+
response: dict = {
|
|
167
|
+
201: {
|
|
168
|
+
"model": create_model(
|
|
169
|
+
route,
|
|
170
|
+
code=(int, 201),
|
|
171
|
+
message=(str, f"{obj} created successfully"),
|
|
172
|
+
data=(model if model else self.model, ...),
|
|
173
|
+
),
|
|
174
|
+
},
|
|
175
|
+
**self.basic(route),
|
|
176
|
+
**kwargs
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
if exclude_codes:
|
|
180
|
+
for code in exclude_codes:
|
|
181
|
+
del response[code]
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
if auth or self.auth:
|
|
185
|
+
response[401] = {
|
|
186
|
+
"model": create_model(
|
|
187
|
+
route, code=(int, 401), message=(str, "Unauthorized")
|
|
188
|
+
)
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
return response
|
|
192
|
+
|
|
193
|
+
def update(self, route: str, model: Any = None, obj: str = "Data", auth: bool = False, exclude_codes: list = [], **kwargs) -> dict:
|
|
194
|
+
"""
|
|
195
|
+
Generate a response for a update request, which is a dictionary of common response codes and models.
|
|
196
|
+
|
|
197
|
+
Contains:
|
|
198
|
+
- 200 OK
|
|
199
|
+
- 204 No Content
|
|
200
|
+
- 401 Unauthorized (optional)
|
|
201
|
+
|
|
202
|
+
:param route: The path of the route
|
|
203
|
+
:param model: The model to use for the response
|
|
204
|
+
:param obj: The object name to use for the response
|
|
205
|
+
:param auth: Whether or not the route requires authentication
|
|
206
|
+
:param exclude_codes: A list of codes to exclude from the response
|
|
207
|
+
:return: A dictionary of common response codes and models
|
|
208
|
+
"""
|
|
209
|
+
response: dict = {
|
|
210
|
+
200: {
|
|
211
|
+
"model": create_model(
|
|
212
|
+
route,
|
|
213
|
+
code=(int, 200),
|
|
214
|
+
message=(str, f"{obj} updated successfully"),
|
|
215
|
+
data=(model if model else self.model, ...),
|
|
216
|
+
),
|
|
217
|
+
},
|
|
218
|
+
204: {
|
|
219
|
+
"model": create_model(
|
|
220
|
+
route,
|
|
221
|
+
code=(int, 204),
|
|
222
|
+
message=(str, f"{obj} updated successfully"),
|
|
223
|
+
),
|
|
224
|
+
},
|
|
225
|
+
**self.basic(route),
|
|
226
|
+
**kwargs
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
if exclude_codes:
|
|
230
|
+
for code in exclude_codes:
|
|
231
|
+
del response[code]
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
if auth or self.auth:
|
|
235
|
+
response[401] = {
|
|
236
|
+
"model": create_model(
|
|
237
|
+
route, code=(int, 401), message=(str, "Unauthorized")
|
|
238
|
+
)
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
return response
|
|
242
|
+
|
|
243
|
+
def delete(self, route: str, model: Any = None, obj: str = "Data", auth: bool = False, exclude_codes: list = [], **kwargs) -> dict:
|
|
244
|
+
"""
|
|
245
|
+
Generate a response for a delete request, which is a dictionary of common response codes and models.
|
|
246
|
+
|
|
247
|
+
Contains:
|
|
248
|
+
- 200 Success
|
|
249
|
+
- 204 Success
|
|
250
|
+
- 400 Bad Request
|
|
251
|
+
- 401 Unauthorized (optional)
|
|
252
|
+
- 500 Internal Server Error
|
|
253
|
+
|
|
254
|
+
:param route: The path of the route
|
|
255
|
+
:param model: The model to use for the response
|
|
256
|
+
:param obj: The object name to use for the response
|
|
257
|
+
:param auth: Whether or not the route requires authentication
|
|
258
|
+
:param exclude_codes: A list of codes to exclude from the response
|
|
259
|
+
:return: A dictionary of common response codes and models
|
|
260
|
+
"""
|
|
261
|
+
response: dict = {
|
|
262
|
+
200: {
|
|
263
|
+
"model": create_model(
|
|
264
|
+
route,
|
|
265
|
+
code=(int, 200),
|
|
266
|
+
message=(str, f"{obj} delete successfully"),
|
|
267
|
+
data=(model if model else self.model, ...),
|
|
268
|
+
),
|
|
269
|
+
},
|
|
270
|
+
204: {
|
|
271
|
+
"model": create_model(
|
|
272
|
+
route,
|
|
273
|
+
code=(int, 204),
|
|
274
|
+
message=(str, f"{obj} delete successfully"),
|
|
275
|
+
),
|
|
276
|
+
},
|
|
277
|
+
**self.basic(route),
|
|
278
|
+
**kwargs
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
if exclude_codes:
|
|
282
|
+
for code in exclude_codes:
|
|
283
|
+
del response[code]
|
|
284
|
+
|
|
285
|
+
|
|
286
|
+
if auth or self.auth:
|
|
287
|
+
response[401] = {
|
|
288
|
+
"model": create_model(
|
|
289
|
+
route, code=(int, 401), message=(str, "Unauthorized")
|
|
290
|
+
)
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
return response
|
|
294
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .enums import *
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
from enum import Enum
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class EnumV2(Enum):
|
|
5
|
+
@classmethod
|
|
6
|
+
def list(cls):
|
|
7
|
+
"""
|
|
8
|
+
Return a list of all Enum values.
|
|
9
|
+
|
|
10
|
+
:return: A list of all Enum values.
|
|
11
|
+
"""
|
|
12
|
+
return list(map(lambda c: c.value, cls))
|
|
13
|
+
|
|
14
|
+
def __new__(cls, *args, **kwargs):
|
|
15
|
+
"""
|
|
16
|
+
Create a new instance of the Enum.
|
|
17
|
+
|
|
18
|
+
:param args: The first argument will be used as the value for the Enum.
|
|
19
|
+
:param kwargs: The description keyword argument can be used to set a description for the Enum.
|
|
20
|
+
:return: The new Enum instance.
|
|
21
|
+
"""
|
|
22
|
+
obj = object.__new__(cls)
|
|
23
|
+
obj._value_ = args[0]
|
|
24
|
+
return obj
|
|
25
|
+
|
|
26
|
+
def __init__(self, value, description: str | None = None):
|
|
27
|
+
"""
|
|
28
|
+
Initialize an EnumV2 instance.
|
|
29
|
+
|
|
30
|
+
:param value: The value of the Enum.
|
|
31
|
+
:param description: The description of the Enum.
|
|
32
|
+
"""
|
|
33
|
+
self._value_ = value
|
|
34
|
+
self._description_ = description
|
|
35
|
+
|
|
36
|
+
@property
|
|
37
|
+
def description(self):
|
|
38
|
+
"""
|
|
39
|
+
Get the description of the Enum value.
|
|
40
|
+
|
|
41
|
+
:return: The description associated with the Enum value.
|
|
42
|
+
"""
|
|
43
|
+
return self._description_
|
|
44
|
+
|
|
45
|
+
class Operator(EnumV2):
|
|
46
|
+
equal = ("eq", "value is equals to")
|
|
47
|
+
unequal = ("ne", "value isn't equals to")
|
|
48
|
+
regex = ("re", "regex match")
|
|
49
|
+
gte = ("gte", "value is greater equals to")
|
|
50
|
+
gt = ("gt", "value is greater to")
|
|
51
|
+
lte = ("lte", "value is lower equals to")
|
|
52
|
+
lt = ("lt", "value is lower to")
|
|
53
|
+
include = ("in", "values that must exist")
|
|
54
|
+
exclude = ("nin", "values that don't exist")
|
|
55
|
+
exist = ("exist", "value is exist")
|
|
56
|
+
not_exist = ("exist", "value is exist")
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
class FilterOption(EnumV2):
|
|
60
|
+
must = ("must", "List of filter must exact")
|
|
61
|
+
mustnt = ("mustnt", "List of filter mustn't exact")
|
|
62
|
+
should = ("should", "List of filter should exact")
|
|
63
|
+
shouldnt = ("shouldnt", "List of filter shouldn't exact")
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
class LocationLevel(str, EnumV2):
|
|
67
|
+
CONTINENT = ("continent", "Continent level data")
|
|
68
|
+
COUNTRY = ("country", "Country level data")
|
|
69
|
+
PROVINCE = ("province", "Province level data")
|
|
70
|
+
CITY = ("city", "City level data")
|
|
71
|
+
DISTRICT = ("district", "District level data")
|
|
72
|
+
SUBDISTRICT = ("subdistrict", "Subdistrict level data")
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
class MedallionTypes(str, EnumV2):
|
|
76
|
+
LAKE = ("lake", 'Lake data')
|
|
77
|
+
BRONZE = ("bronze", 'bronze level Medallion')
|
|
78
|
+
SILVER = ("silver", 'silver level Medallion')
|
|
79
|
+
GOLD = ("gold", 'gold level Medallion')
|
|
80
|
+
OTHER = ("other", 'other than any level Medallion')
|