mirror of
https://github.com/hexolan/panels.git
synced 2026-03-26 12:40:21 +00:00
init auth-service
This commit is contained in:
1
services/auth-service/.dockerignore
Normal file
1
services/auth-service/.dockerignore
Normal file
@@ -0,0 +1 @@
|
||||
.venv
|
||||
11
services/auth-service/.env.example
Normal file
11
services/auth-service/.env.example
Normal file
@@ -0,0 +1,11 @@
|
||||
POSTGRES_USER=postgres
|
||||
POSTGRES_PASS=postgres
|
||||
POSTGRES_HOST=localhost:5434
|
||||
POSTGRES_DATABASE=postgres
|
||||
|
||||
KAFKA_BROKERS=localhost:9092
|
||||
|
||||
JWT_PUBLIC_KEY=LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUlJQklqQU5CZ2txaGtpRzl3MEJBUUVGQUFPQ0FROEFNSUlCQ2dLQ0FRRUE3TGhQekc1cmNVMkE1NXFlazRmSwpFN1QwWXlYTFRrRVhqVVh2ZDdmLzdVWTIxQmVsZ0hWVFMyTDcxUW1zL3NPakhFWHdSOGx3dlA5VnhXRFRBMGJ4Cm45cnBYVFYwVXVGRWFtOEpGZTcwTzdaOSs0M1d1ampiYWdNT04vMTVZa3dGOTR4aVpQcllyWjE4TEUyZVZIaUMKZVFtdFczVzhBSzVxWnpydkREd0FkYlRMdm1LRWtEcGVKYTgyQXkwTy9jcW1JUTdDdHU0R1djendSSk1iTTJUbQo1UFkzWUNWZ0V0WE1WY1AwZWVhd2NJQXRZNVdyWXJ0T1VkTUFodFl0RlhYVWlObWliQVI4bFM4TXUyMGp1Rnc5CmJnb2FQUXZSN2FXLzhLL2hwaUdmbXN5V1lmbGpHM0xOYlJCMEpiclU5cTZ6NlcvckQzRlVCQmVDeW9WelA4TjMKU3dJREFRQUIKLS0tLS1FTkQgUFVCTElDIEtFWS0tLS0tCg==
|
||||
JWT_PRIVATE_KEY=LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFcGdJQkFBS0NBUUVBN0xoUHpHNXJjVTJBNTVxZWs0ZktFN1QwWXlYTFRrRVhqVVh2ZDdmLzdVWTIxQmVsCmdIVlRTMkw3MVFtcy9zT2pIRVh3Ujhsd3ZQOVZ4V0RUQTBieG45cnBYVFYwVXVGRWFtOEpGZTcwTzdaOSs0M1cKdWpqYmFnTU9OLzE1WWt3Rjk0eGlaUHJZcloxOExFMmVWSGlDZVFtdFczVzhBSzVxWnpydkREd0FkYlRMdm1LRQprRHBlSmE4MkF5ME8vY3FtSVE3Q3R1NEdXY3p3UkpNYk0yVG01UFkzWUNWZ0V0WE1WY1AwZWVhd2NJQXRZNVdyCllydE9VZE1BaHRZdEZYWFVpTm1pYkFSOGxTOE11MjBqdUZ3OWJnb2FQUXZSN2FXLzhLL2hwaUdmbXN5V1lmbGoKRzNMTmJSQjBKYnJVOXE2ejZXL3JEM0ZVQkJlQ3lvVnpQOE4zU3dJREFRQUJBb0lCQVFEWHNyYWIyLzJ4RjJNZgpKd2ZaL0lDSTVubE5vdEdYTTc3SEx2T2VqaDM0MGVNQjdhNFQyRlNXdTlJbTlCTWJiWjdDRTRSM2xUbFNMZ08wCnY1NW5QUXpNa1lmVk0vRVQyRW9rQlpzc3pqamo5RXpsbkFBT1hlS292YklHR01TemFmeUI3ZngyY1JCaFdzQWMKQ25uOEZIY20zVWVHc0Vnb0FzWFgzSjZYOGxDazd1R0hHZ0hnMk9vSUd5M2dIeGJwOEJiVlJXeEFIMm5rV2Nxegp6QzQ1anpFK2tubVprVzdJOTllQXdMTjc3QXpEZlhZSU1rdjZFdnhwWVdQZ1VJa253eXd3MmdoY0dtbFhwazdMCmdUM2t5dWpEaCtqOVprQVp2N1F3YktWa2EvSFdBRDJDR0tQNFhMK2dhZW9zZUdDMTlja0VvbHl3YWYxYzRneTIKRE41Z0JDSHBBb0dCQVByalFob2NoSXUxYzNTOE5hd0NhRTc3Z0YxcURXQTM1b25JS0Z1aFQwYTV3Vi9ZTHNVcgprMkl6TnZoTHFvV0tTbmRhTmd4aWNpOTVkK3dYVk9wS0tDWVgrR2NVNWZEdWJJeDdqb0tWcUxqK2hNdGIvNUFLClMwUDAwcmpCUGZQcU1rK21XYUcxWE1ieDEvbmUzYm9XVlZDcitQblZvNzJlWjl6OHVsKzdtenN0QW9HQkFQR0wKSmU3aUU3ZmRLWXgxQ3IzbDdJbXFocG1UbUcrd29od3BadVR4NEtDeWMwZVpSUEpKR0txMytUdHp6eFNkRzk0VAozY3p5Ulo3TWJqWUtyeVZPdzRHMklpMWVaMW9pSVJrSThRMkNCV0NZYWl5WFhBd0xlSkhvQzl5amdBRDB6V21TCkxHcWZwSnBaSkU5Q3N1SDJVMjdxY0ZrQThvM2tmOENFOHJDRkNLZFhBb0dCQUpmOWkzTTBLWnhWemQ4L2tpaGwKd1Bsd1plQ3h1ZTY3anQrVHNkZHBEeFRpdmVLcG5oUDNCUyt0cFRTZzZtcENVRUNrRnpCRGg3ZDVHQXlnU2VJeQpFTWFiS1BLUjk0ZVJlWk5WMncwRFM1YmZJbVhza3hPWkdPWFBjTVZhMUlSck1oV015cW9yckV3ZUFXQ3dBcFdVCnFCVGFTbGhZYy8wUTlRMHMwbC9pMFBUMUFvR0JBTk9wSUx0OVp0UUd2TUwxU1Uxdzd0OFFERlVGemwySlJmVXgKbnBYZkV2MGVnd0JwNGM0Q21kZjMwVEgwNExEcW42SHlmTGw4VDkvQXVvOG11NllRcUNmQlI1L0VDd01qeHljZAorOFhmZXdEVGJxN1dqL1dLRThTZnQ4MUhoUUxSZ2pNUndWUkp3cjd5Z0d2b1FjTGF6Ty8wQmpFb01HU0FxQ1kzCkdrZnV1OCtQQW9HQkFPVXhGcXNrSVNxb3AyUGJZRmQ4SEU3NHhKYlZBRzFKZjh1WEllMnlzRHFrdnU5RmJ6djUKWnc1aW52dHA1VkhwWjBTTFN5dFViNktzSGNSaXFJNXMybW5NbmFMaXAyUmd0bkVzQTVmY25XeDFhRlFJclhYYgpVUXFEdklLd1JoT2ZjZkRkdTFDTFlpb2J0Y0Nlc0JISUcxc08yKy9UYmF1WG5scGFXWXo3Q1hrVgotLS0tLUVORCBSU0EgUFJJVkFURSBLRVktLS0tLQo=
|
||||
|
||||
PASSWORD_PEPPER=4d0c18c368489d4c0b48c497efb1d6b3
|
||||
17
services/auth-service/Dockerfile
Normal file
17
services/auth-service/Dockerfile
Normal file
@@ -0,0 +1,17 @@
|
||||
FROM python:3.9-alpine
|
||||
|
||||
RUN python -m pip install poetry==1.6.1
|
||||
RUN poetry config virtualenvs.in-project true
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Install the dependencies
|
||||
COPY pyproject.toml poetry.lock /app/
|
||||
RUN poetry install --no-cache --no-root
|
||||
|
||||
# Install the package
|
||||
COPY . .
|
||||
RUN poetry install --no-cache --only-root
|
||||
|
||||
EXPOSE 9090
|
||||
CMD ["poetry", "run", "python", "-m", "auth_service.main"]
|
||||
12
services/auth-service/Makefile
Normal file
12
services/auth-service/Makefile
Normal file
@@ -0,0 +1,12 @@
|
||||
migration-new:
|
||||
migrate create -ext sql -dir ./auth_service/postgres/migrations -seq ${MIGRATION_NAME}
|
||||
|
||||
migration-upgrade:
|
||||
docker run -v "${SERVICE_DIR}/auth_service/postgres/migrations:/migrations" --network host migrate/migrate:4 -path=/migrations/ -database postgresql://${POSTGRES_USER}:${POSTGRES_PASS}@${POSTGRES_HOST}/${POSTGRES_DATABASE}?sslmode=disable up
|
||||
|
||||
migration-downgrade:
|
||||
docker run -v "${SERVICE_DIR}/auth_service/postgres/migrations:/migrations" --network host migrate/migrate:4 -path=/migrations/ -database postgresql://${POSTGRES_USER}:${POSTGRES_PASS}@${POSTGRES_HOST}/${POSTGRES_DATABASE}?sslmode=disable down
|
||||
|
||||
protobufs-compile:
|
||||
poetry run python -m grpc_tools.protoc -I../../protobufs --python_out=./auth_service/models/proto --pyi_out=./auth_service/models/proto --grpc_python_out=./auth_service/models/proto auth.proto user.proto
|
||||
poetry run python -m protoletariat --dont-create-package --in-place --python-out ./auth_service/models/proto protoc --proto-path=../../protobufs auth.proto user.proto
|
||||
66
services/auth-service/README.md
Normal file
66
services/auth-service/README.md
Normal file
@@ -0,0 +1,66 @@
|
||||
# Auth Service
|
||||
|
||||
## Event Documentation
|
||||
|
||||
* Events Produced:
|
||||
* N/A
|
||||
|
||||
* Events Consumed:
|
||||
* **Topic:** "``user``" | **Schema:** "``UserEvent``" protobuf
|
||||
* Type: ``"deleted"`` | Data: ``User``
|
||||
|
||||
## Configuration
|
||||
|
||||
### Environment Variables
|
||||
|
||||
**PostgreSQL:**
|
||||
|
||||
``POSTGRES_USER`` (Required)
|
||||
|
||||
* e.g. "postgres"
|
||||
|
||||
``POSTGRES_PASS`` (Required)
|
||||
|
||||
* e.g. "postgres"
|
||||
|
||||
``POSTGRES_HOST`` (Required)
|
||||
|
||||
* e.g. "localhost:5432"
|
||||
|
||||
``POSTGRES_DATABASE`` (Required)
|
||||
|
||||
* e.g. "postgres"
|
||||
|
||||
---
|
||||
|
||||
**Kafka:**
|
||||
|
||||
``KAFKA_BROKERS`` (Required)
|
||||
|
||||
* e.g. "localhost:9092" or "localhost:9092,localhost:9093"
|
||||
|
||||
---
|
||||
|
||||
**Other:**
|
||||
|
||||
``JWT_PRIVATE_KEY`` (Required)
|
||||
|
||||
* RSA Private Key (used to encode JWT tokens) represented in base64
|
||||
|
||||
* Generating:
|
||||
* Using OpenSSL: ``openssl genrsa -out private.pem 2048``
|
||||
* Getting Base64 Representation: ``python -c "import base64;private_key=open('private.pem', 'r').read();print(base64.standard_b64encode(private_key.encode('utf-8')).decode('utf-8'))"``
|
||||
|
||||
``JWT_PUBLIC_KEY`` (Required)
|
||||
|
||||
* RSA Public Key (used to verify JWT tokens) represented in base64
|
||||
|
||||
* Generating:
|
||||
* Using OpenSSL: ``openssl rsa -in private.pem -pubout -out public.pem``
|
||||
* Getting Base64 Representation: ``python -c "import base64;private_key=open('public.pem', 'r').read();print(base64.standard_b64encode(private_key.encode('utf-8')).decode('utf-8'))"``
|
||||
|
||||
``PASSWORD_PEPPER`` (Required)
|
||||
|
||||
* A secret salt applied globally along with generated password salts.
|
||||
|
||||
* Generate with ``python -c "import secrets;print(secrets.token_hex(nbytes=16))"`` or similar method.
|
||||
80
services/auth-service/auth_service/events/base_consumer.py
Normal file
80
services/auth-service/auth_service/events/base_consumer.py
Normal file
@@ -0,0 +1,80 @@
|
||||
import logging
|
||||
from typing import Type
|
||||
|
||||
from google.protobuf import message
|
||||
from aiokafka import AIOKafkaConsumer
|
||||
from aiokafka.structs import ConsumerRecord
|
||||
|
||||
from auth_service.models.config import Config
|
||||
from auth_service.models.service import AuthDBRepository
|
||||
|
||||
|
||||
class EventConsumer:
|
||||
"""An abstract consumer base class.
|
||||
|
||||
Attributes:
|
||||
CONSUMER_TOPIC: The topic to consume events from.
|
||||
CONSUMER_EVENT_TYPE (Type[message.Message]): The protobuf class type of the event msgs (used for deserialisation).
|
||||
_db_repo (Type[AuthDBRepository]): The repository interface for modifying data.
|
||||
_consumer (aiokafka.AIOKafkaConsumer): The underlying Kafka instance.
|
||||
|
||||
"""
|
||||
CONSUMER_TOPIC: str
|
||||
CONSUMER_EVENT_TYPE: Type[message.Message]
|
||||
|
||||
def __init__(self, config: Config, db_repo: Type[AuthDBRepository]) -> None:
|
||||
"""Initialise the event consumer.
|
||||
|
||||
Args:
|
||||
config (Config): The app configuration instance (to access brokers list).
|
||||
db_repo (Type[AuthDBRepository]): The repository interface for updating data.
|
||||
|
||||
"""
|
||||
self._db_repo = db_repo
|
||||
self._consumer = AIOKafkaConsumer(
|
||||
self.CONSUMER_TOPIC,
|
||||
bootstrap_servers=config.kafka_brokers,
|
||||
group_id="auth-service"
|
||||
)
|
||||
|
||||
async def start(self) -> None:
|
||||
"""Begin consuming messages."""
|
||||
await self._consumer.start()
|
||||
try:
|
||||
async for msg in self._consumer:
|
||||
await self._process_msg(msg)
|
||||
except Exception as e:
|
||||
logging.error(f"error whilst consuming messages (on topic '{self.CONSUMER_TOPIC}'): {e}")
|
||||
finally:
|
||||
await self._consumer.stop()
|
||||
|
||||
async def _process_msg(self, msg: ConsumerRecord) -> None:
|
||||
"""Process a recieved message.
|
||||
|
||||
The messages are deserialise from bytes into their protobuf form,
|
||||
then passed to the `_process_event` method to handle the logic.
|
||||
|
||||
Args:
|
||||
msg (kafka.Message): The event to process.
|
||||
|
||||
"""
|
||||
try:
|
||||
event = self.CONSUMER_EVENT_TYPE()
|
||||
event.ParseFromString(msg.value)
|
||||
assert event.type != ""
|
||||
await self._process_event(event)
|
||||
except AssertionError:
|
||||
logging.error("invalid event recieved")
|
||||
return
|
||||
except Exception as e:
|
||||
logging.error("error whilst processing recieved event:", e)
|
||||
return
|
||||
|
||||
async def _process_event(self, event: Type[message.Message]) -> None:
|
||||
"""Process a recieved event.
|
||||
|
||||
Args:
|
||||
event (Type[message.Message]): The event serialised to protobuf form.
|
||||
|
||||
"""
|
||||
raise NotImplementedError("required consumer method (_process_event) not implemented")
|
||||
42
services/auth-service/auth_service/events/service.py
Normal file
42
services/auth-service/auth_service/events/service.py
Normal file
@@ -0,0 +1,42 @@
|
||||
from typing import Type
|
||||
|
||||
from auth_service.models.config import Config
|
||||
from auth_service.models.service import AuthDBRepository
|
||||
from auth_service.events.user_consumer import UserEventConsumer
|
||||
|
||||
|
||||
class EventConsumersWrapper:
|
||||
"""A wrapper class for starting the event consumers.
|
||||
|
||||
Attributes:
|
||||
_user_consumer (UserEventConsumer): Wrapped consumer.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, user_consumer: UserEventConsumer) -> None:
|
||||
"""Add the consumers to the wrapper
|
||||
|
||||
Args:
|
||||
user_consumer (UserEventConsumer): Initialised user consumer.
|
||||
|
||||
"""
|
||||
self._user_consumer = user_consumer
|
||||
|
||||
async def start(self) -> None:
|
||||
"""Begin consuming events on all the event consumers."""
|
||||
await self._user_consumer.start()
|
||||
|
||||
|
||||
def create_consumers(config: Config, db_repo: Type[AuthDBRepository]) -> EventConsumersWrapper:
|
||||
"""Initialse the event consumers and return them in a wrapper.
|
||||
|
||||
Args:
|
||||
config (Config): The app configuration instance.
|
||||
db_repo (Type[AuthDBRepository]): The database repo to pass to the consumers.
|
||||
|
||||
Returns:
|
||||
EventConsumerWrapper
|
||||
|
||||
"""
|
||||
user_consumer = UserEventConsumer(config, db_repo)
|
||||
return EventConsumersWrapper(user_consumer=user_consumer)
|
||||
32
services/auth-service/auth_service/events/user_consumer.py
Normal file
32
services/auth-service/auth_service/events/user_consumer.py
Normal file
@@ -0,0 +1,32 @@
|
||||
import logging
|
||||
|
||||
from auth_service.models.proto import user_pb2
|
||||
from auth_service.events.base_consumer import EventConsumer
|
||||
|
||||
|
||||
class UserEventConsumer(EventConsumer):
|
||||
"""Consumer class responsible for 'user' events.
|
||||
|
||||
Attributes:
|
||||
CONSUMER_TOPIC: The topic to consume events from.
|
||||
CONSUMER_EVENT_TYPE (user_pb2.UserEvent): Kafka messages are serialised to this type.
|
||||
_db_repo (AuthDBRepository): The repository interface for modifying data.
|
||||
_consumer (aiokafka.AIOKafkaConsumer): The underlying Kafka instance.
|
||||
|
||||
"""
|
||||
CONSUMER_TOPIC = "user"
|
||||
CONSUMER_EVENT_TYPE = user_pb2.UserEvent
|
||||
|
||||
async def _process_event(self, event: user_pb2.UserEvent) -> None:
|
||||
"""Process a recieved event.
|
||||
|
||||
In response to a User deleted event, delete any auth methods
|
||||
this service has in relation to that user.
|
||||
|
||||
Args:
|
||||
event (user_pb2.UserEvent): The decoded protobuf message.
|
||||
|
||||
"""
|
||||
if event.type == "deleted":
|
||||
await self._db_repo.delete_password_auth_method(event.data.id)
|
||||
logging.info("succesfully processed UserEvent (type: 'deleted')")
|
||||
29
services/auth-service/auth_service/main.py
Normal file
29
services/auth-service/auth_service/main.py
Normal file
@@ -0,0 +1,29 @@
|
||||
import asyncio
|
||||
import logging
|
||||
from sys import stdout
|
||||
|
||||
from auth_service.models.config import Config
|
||||
from auth_service.events.service import create_consumers
|
||||
from auth_service.postgres.service import create_db_repository
|
||||
from auth_service.service import ServiceRepository
|
||||
from auth_service.rpc.service import create_rpc_server
|
||||
|
||||
|
||||
async def main() -> None:
|
||||
config = Config()
|
||||
|
||||
db_repo = await create_db_repository(config)
|
||||
svc_repo = ServiceRepository(config, downstream_repo=db_repo)
|
||||
|
||||
rpc_server = create_rpc_server(svc_repo)
|
||||
event_consumers = create_consumers(config, db_repo=db_repo)
|
||||
|
||||
await asyncio.gather(
|
||||
rpc_server.start(),
|
||||
event_consumers.start()
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
logging.basicConfig(stream=stdout, level=logging.INFO)
|
||||
asyncio.run(main())
|
||||
75
services/auth-service/auth_service/models/config.py
Normal file
75
services/auth-service/auth_service/models/config.py
Normal file
@@ -0,0 +1,75 @@
|
||||
import base64
|
||||
from typing import Any, List
|
||||
|
||||
from pydantic import computed_field
|
||||
from pydantic.fields import FieldInfo
|
||||
from pydantic_settings import BaseSettings, EnvSettingsSource
|
||||
from pydantic_settings.main import BaseSettings
|
||||
from pydantic_settings.sources import PydanticBaseSettingsSource
|
||||
|
||||
|
||||
class ConfigSource(EnvSettingsSource):
|
||||
"""Responsible for loading config options from environment variables."""
|
||||
def prepare_field_value(self, field_name: str, field: FieldInfo, value: Any, value_is_complex: bool) -> Any:
|
||||
if field_name == "kafka_brokers":
|
||||
# Comma delimit the kafka brokers.
|
||||
if value == None:
|
||||
return None
|
||||
return value.split(",")
|
||||
elif field_name == "jwt_public_key" or field_name == "jwt_private_key":
|
||||
# Decode the JWT public and private keys from base64.
|
||||
if value == None:
|
||||
return None
|
||||
return base64.standard_b64decode(value).decode(encoding="utf-8")
|
||||
|
||||
return super().prepare_field_value(field_name, field, value, value_is_complex)
|
||||
|
||||
|
||||
class Config(BaseSettings):
|
||||
"""The service configuration loaded from environment
|
||||
variables.
|
||||
|
||||
Attributes:
|
||||
postgres_user (str): Loaded from the 'POSTGRES_USER' envvar.
|
||||
postgres_pass (str): Loaded from the 'POSTGRES_PASS' envvar.
|
||||
postgres_host (str): Loaded from the 'POSTGRES_HOST' envvar.
|
||||
postgres_database (str): Loaded from the 'POSTGRES_DATABASE' envvar.
|
||||
kafka_brokers (list[str]): Loaded and comma delmited from the 'KAFKA_BROKERS' envvar.
|
||||
jwt_public_key (str): Loaded and decoded, from base64, from the 'JWT_PUBLIC_KEY' envvar.
|
||||
jwt_private_key (str): Loaded and decoded, from base64, from the 'JWT_PRIVATE_KEY' envvar.
|
||||
password_pepper (str): Loaded from the 'PASSWORD_PEPPER' envvar.
|
||||
postgres_dsn (str): Computed when accessed the first time. (@property)
|
||||
|
||||
"""
|
||||
postgres_user: str
|
||||
postgres_pass: str
|
||||
postgres_host: str
|
||||
postgres_database: str
|
||||
|
||||
kafka_brokers: List[str]
|
||||
|
||||
jwt_public_key: str
|
||||
jwt_private_key: str
|
||||
|
||||
password_pepper: str
|
||||
|
||||
@computed_field
|
||||
@property
|
||||
def postgres_dsn(self) -> str:
|
||||
"""Uses the postgres_user, postgres_pass, postgres_host,
|
||||
and postgres_database options to assemble a DSN.
|
||||
|
||||
Returns:
|
||||
str: DSN for connecting to the database.
|
||||
|
||||
"""
|
||||
return "postgresql+asyncpg://{user}:{password}@{host}/{db}".format(
|
||||
user=self.postgres_user,
|
||||
password=self.postgres_pass,
|
||||
host=self.postgres_host,
|
||||
db=self.postgres_database
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def settings_customise_sources(cls, settings_cls: type[BaseSettings], *args, **kwargs) -> tuple[PydanticBaseSettingsSource, ...]:
|
||||
return (ConfigSource(settings_cls), )
|
||||
59
services/auth-service/auth_service/models/exceptions.py
Normal file
59
services/auth-service/auth_service/models/exceptions.py
Normal file
@@ -0,0 +1,59 @@
|
||||
from enum import Enum, auto
|
||||
|
||||
from grpc import RpcContext, StatusCode
|
||||
|
||||
|
||||
class ServiceErrorCode(Enum):
|
||||
"""Error codes used for classifying ServiceExceptions."""
|
||||
INVALID_ARGUMENT = auto()
|
||||
CONFLICT = auto()
|
||||
NOT_FOUND = auto()
|
||||
INVALID_CREDENTIALS = auto()
|
||||
SERVICE_ERROR = auto()
|
||||
|
||||
__RPC_CODE_MAP__ = {
|
||||
INVALID_ARGUMENT: StatusCode.INVALID_ARGUMENT,
|
||||
CONFLICT: StatusCode.ALREADY_EXISTS,
|
||||
NOT_FOUND: StatusCode.NOT_FOUND,
|
||||
INVALID_CREDENTIALS: StatusCode.UNAUTHENTICATED,
|
||||
SERVICE_ERROR: StatusCode.INTERNAL
|
||||
}
|
||||
|
||||
def to_rpc_code(self) -> StatusCode:
|
||||
"""Convert a service error code to a gRPC status code.
|
||||
|
||||
Returns:
|
||||
The mapped RPC status code, if found, otherwise gRPC Unknown status code.
|
||||
|
||||
"""
|
||||
return self.__class__.__RPC_CODE_MAP__.get(self.value, StatusCode.UNKNOWN)
|
||||
|
||||
|
||||
class ServiceException(Exception):
|
||||
"""This exception provides an interface to convert service errors
|
||||
into gRPC errors, which can then be returned to the caller.
|
||||
|
||||
Args:
|
||||
msg (str): Error message.
|
||||
error_code (ServiceErrorCode): Categorisation code for the error.
|
||||
|
||||
Attributes:
|
||||
msg (str): The error message.
|
||||
error_code (ServiceErrorCode): Categorisation code for the error.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, msg: str, error_code: ServiceErrorCode) -> None:
|
||||
super().__init__(msg)
|
||||
self.msg = msg
|
||||
self.error_code = error_code
|
||||
|
||||
def apply_to_rpc(self, context: RpcContext) -> None:
|
||||
"""Apply the exception to an RPC context.
|
||||
|
||||
Args:
|
||||
context (grpc.RpcContext): The context to apply to.
|
||||
|
||||
"""
|
||||
context.set_code(self.error_code.to_rpc_code())
|
||||
context.set_details(self.msg)
|
||||
23
services/auth-service/auth_service/models/proto/auth_pb2.py
Normal file
23
services/auth-service/auth_service/models/proto/auth_pb2.py
Normal file
@@ -0,0 +1,23 @@
|
||||
"""Generated protocol buffer code."""
|
||||
from google.protobuf import descriptor as _descriptor
|
||||
from google.protobuf import descriptor_pool as _descriptor_pool
|
||||
from google.protobuf import symbol_database as _symbol_database
|
||||
from google.protobuf.internal import builder as _builder
|
||||
_sym_db = _symbol_database.Default()
|
||||
from google.protobuf import empty_pb2 as google_dot_protobuf_dot_empty__pb2
|
||||
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\nauth.proto\x12\x0epanels.auth.v1\x1a\x1bgoogle/protobuf/empty.proto":\n\x15SetPasswordAuthMethod\x12\x0f\n\x07user_id\x18\x01 \x01(\t\x12\x10\n\x08password\x18\x02 \x01(\t"+\n\x18DeletePasswordAuthMethod\x12\x0f\n\x07user_id\x18\x01 \x01(\t"8\n\x13PasswordAuthRequest\x12\x0f\n\x07user_id\x18\x01 \x01(\t\x12\x10\n\x08password\x18\x02 \x01(\t"`\n\tAuthToken\x12\x12\n\ntoken_type\x18\x01 \x01(\t\x12\x14\n\x0caccess_token\x18\x02 \x01(\t\x12\x15\n\rrefresh_token\x18\x03 \x01(\t\x12\x12\n\nexpires_in\x18\x04 \x01(\x032\x91\x02\n\x0bAuthService\x12T\n\x10AuthWithPassword\x12#.panels.auth.v1.PasswordAuthRequest\x1a\x19.panels.auth.v1.AuthToken"\x00\x12R\n\x0fSetPasswordAuth\x12%.panels.auth.v1.SetPasswordAuthMethod\x1a\x16.google.protobuf.Empty"\x00\x12X\n\x12DeletePasswordAuth\x12(.panels.auth.v1.DeletePasswordAuthMethod\x1a\x16.google.protobuf.Empty"\x00b\x06proto3')
|
||||
_globals = globals()
|
||||
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
|
||||
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'auth_pb2', _globals)
|
||||
if _descriptor._USE_C_DESCRIPTORS == False:
|
||||
DESCRIPTOR._options = None
|
||||
_globals['_SETPASSWORDAUTHMETHOD']._serialized_start = 59
|
||||
_globals['_SETPASSWORDAUTHMETHOD']._serialized_end = 117
|
||||
_globals['_DELETEPASSWORDAUTHMETHOD']._serialized_start = 119
|
||||
_globals['_DELETEPASSWORDAUTHMETHOD']._serialized_end = 162
|
||||
_globals['_PASSWORDAUTHREQUEST']._serialized_start = 164
|
||||
_globals['_PASSWORDAUTHREQUEST']._serialized_end = 220
|
||||
_globals['_AUTHTOKEN']._serialized_start = 222
|
||||
_globals['_AUTHTOKEN']._serialized_end = 318
|
||||
_globals['_AUTHSERVICE']._serialized_start = 321
|
||||
_globals['_AUTHSERVICE']._serialized_end = 594
|
||||
47
services/auth-service/auth_service/models/proto/auth_pb2.pyi
Normal file
47
services/auth-service/auth_service/models/proto/auth_pb2.pyi
Normal file
@@ -0,0 +1,47 @@
|
||||
from google.protobuf import empty_pb2 as _empty_pb2
|
||||
from google.protobuf import descriptor as _descriptor
|
||||
from google.protobuf import message as _message
|
||||
from typing import ClassVar as _ClassVar, Optional as _Optional
|
||||
DESCRIPTOR: _descriptor.FileDescriptor
|
||||
|
||||
class SetPasswordAuthMethod(_message.Message):
|
||||
__slots__ = ['user_id', 'password']
|
||||
USER_ID_FIELD_NUMBER: _ClassVar[int]
|
||||
PASSWORD_FIELD_NUMBER: _ClassVar[int]
|
||||
user_id: str
|
||||
password: str
|
||||
|
||||
def __init__(self, user_id: _Optional[str]=..., password: _Optional[str]=...) -> None:
|
||||
...
|
||||
|
||||
class DeletePasswordAuthMethod(_message.Message):
|
||||
__slots__ = ['user_id']
|
||||
USER_ID_FIELD_NUMBER: _ClassVar[int]
|
||||
user_id: str
|
||||
|
||||
def __init__(self, user_id: _Optional[str]=...) -> None:
|
||||
...
|
||||
|
||||
class PasswordAuthRequest(_message.Message):
|
||||
__slots__ = ['user_id', 'password']
|
||||
USER_ID_FIELD_NUMBER: _ClassVar[int]
|
||||
PASSWORD_FIELD_NUMBER: _ClassVar[int]
|
||||
user_id: str
|
||||
password: str
|
||||
|
||||
def __init__(self, user_id: _Optional[str]=..., password: _Optional[str]=...) -> None:
|
||||
...
|
||||
|
||||
class AuthToken(_message.Message):
|
||||
__slots__ = ['token_type', 'access_token', 'refresh_token', 'expires_in']
|
||||
TOKEN_TYPE_FIELD_NUMBER: _ClassVar[int]
|
||||
ACCESS_TOKEN_FIELD_NUMBER: _ClassVar[int]
|
||||
REFRESH_TOKEN_FIELD_NUMBER: _ClassVar[int]
|
||||
EXPIRES_IN_FIELD_NUMBER: _ClassVar[int]
|
||||
token_type: str
|
||||
access_token: str
|
||||
refresh_token: str
|
||||
expires_in: int
|
||||
|
||||
def __init__(self, token_type: _Optional[str]=..., access_token: _Optional[str]=..., refresh_token: _Optional[str]=..., expires_in: _Optional[int]=...) -> None:
|
||||
...
|
||||
@@ -0,0 +1,58 @@
|
||||
"""Client and server classes corresponding to protobuf-defined services."""
|
||||
import grpc
|
||||
from . import auth_pb2 as auth__pb2
|
||||
from google.protobuf import empty_pb2 as google_dot_protobuf_dot_empty__pb2
|
||||
|
||||
class AuthServiceStub(object):
|
||||
"""Missing associated documentation comment in .proto file."""
|
||||
|
||||
def __init__(self, channel):
|
||||
"""Constructor.
|
||||
|
||||
Args:
|
||||
channel: A grpc.Channel.
|
||||
"""
|
||||
self.AuthWithPassword = channel.unary_unary('/panels.auth.v1.AuthService/AuthWithPassword', request_serializer=auth__pb2.PasswordAuthRequest.SerializeToString, response_deserializer=auth__pb2.AuthToken.FromString)
|
||||
self.SetPasswordAuth = channel.unary_unary('/panels.auth.v1.AuthService/SetPasswordAuth', request_serializer=auth__pb2.SetPasswordAuthMethod.SerializeToString, response_deserializer=google_dot_protobuf_dot_empty__pb2.Empty.FromString)
|
||||
self.DeletePasswordAuth = channel.unary_unary('/panels.auth.v1.AuthService/DeletePasswordAuth', request_serializer=auth__pb2.DeletePasswordAuthMethod.SerializeToString, response_deserializer=google_dot_protobuf_dot_empty__pb2.Empty.FromString)
|
||||
|
||||
class AuthServiceServicer(object):
|
||||
"""Missing associated documentation comment in .proto file."""
|
||||
|
||||
def AuthWithPassword(self, request, context):
|
||||
"""Missing associated documentation comment in .proto file."""
|
||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||
context.set_details('Method not implemented!')
|
||||
raise NotImplementedError('Method not implemented!')
|
||||
|
||||
def SetPasswordAuth(self, request, context):
|
||||
"""Missing associated documentation comment in .proto file."""
|
||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||
context.set_details('Method not implemented!')
|
||||
raise NotImplementedError('Method not implemented!')
|
||||
|
||||
def DeletePasswordAuth(self, request, context):
|
||||
"""Missing associated documentation comment in .proto file."""
|
||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||
context.set_details('Method not implemented!')
|
||||
raise NotImplementedError('Method not implemented!')
|
||||
|
||||
def add_AuthServiceServicer_to_server(servicer, server):
|
||||
rpc_method_handlers = {'AuthWithPassword': grpc.unary_unary_rpc_method_handler(servicer.AuthWithPassword, request_deserializer=auth__pb2.PasswordAuthRequest.FromString, response_serializer=auth__pb2.AuthToken.SerializeToString), 'SetPasswordAuth': grpc.unary_unary_rpc_method_handler(servicer.SetPasswordAuth, request_deserializer=auth__pb2.SetPasswordAuthMethod.FromString, response_serializer=google_dot_protobuf_dot_empty__pb2.Empty.SerializeToString), 'DeletePasswordAuth': grpc.unary_unary_rpc_method_handler(servicer.DeletePasswordAuth, request_deserializer=auth__pb2.DeletePasswordAuthMethod.FromString, response_serializer=google_dot_protobuf_dot_empty__pb2.Empty.SerializeToString)}
|
||||
generic_handler = grpc.method_handlers_generic_handler('panels.auth.v1.AuthService', rpc_method_handlers)
|
||||
server.add_generic_rpc_handlers((generic_handler,))
|
||||
|
||||
class AuthService(object):
|
||||
"""Missing associated documentation comment in .proto file."""
|
||||
|
||||
@staticmethod
|
||||
def AuthWithPassword(request, target, options=(), channel_credentials=None, call_credentials=None, insecure=False, compression=None, wait_for_ready=None, timeout=None, metadata=None):
|
||||
return grpc.experimental.unary_unary(request, target, '/panels.auth.v1.AuthService/AuthWithPassword', auth__pb2.PasswordAuthRequest.SerializeToString, auth__pb2.AuthToken.FromString, options, channel_credentials, insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
|
||||
|
||||
@staticmethod
|
||||
def SetPasswordAuth(request, target, options=(), channel_credentials=None, call_credentials=None, insecure=False, compression=None, wait_for_ready=None, timeout=None, metadata=None):
|
||||
return grpc.experimental.unary_unary(request, target, '/panels.auth.v1.AuthService/SetPasswordAuth', auth__pb2.SetPasswordAuthMethod.SerializeToString, google_dot_protobuf_dot_empty__pb2.Empty.FromString, options, channel_credentials, insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
|
||||
|
||||
@staticmethod
|
||||
def DeletePasswordAuth(request, target, options=(), channel_credentials=None, call_credentials=None, insecure=False, compression=None, wait_for_ready=None, timeout=None, metadata=None):
|
||||
return grpc.experimental.unary_unary(request, target, '/panels.auth.v1.AuthService/DeletePasswordAuth', auth__pb2.DeletePasswordAuthMethod.SerializeToString, google_dot_protobuf_dot_empty__pb2.Empty.FromString, options, channel_credentials, insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
|
||||
36
services/auth-service/auth_service/models/proto/user_pb2.py
Normal file
36
services/auth-service/auth_service/models/proto/user_pb2.py
Normal file
@@ -0,0 +1,36 @@
|
||||
"""Generated protocol buffer code."""
|
||||
from google.protobuf import descriptor as _descriptor
|
||||
from google.protobuf import descriptor_pool as _descriptor_pool
|
||||
from google.protobuf import symbol_database as _symbol_database
|
||||
from google.protobuf.internal import builder as _builder
|
||||
_sym_db = _symbol_database.Default()
|
||||
from google.protobuf import empty_pb2 as google_dot_protobuf_dot_empty__pb2
|
||||
from google.protobuf import timestamp_pb2 as google_dot_protobuf_dot_timestamp__pb2
|
||||
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\nuser.proto\x12\x0epanels.user.v1\x1a\x1bgoogle/protobuf/empty.proto\x1a\x1fgoogle/protobuf/timestamp.proto"\x96\x01\n\x04User\x12\n\n\x02id\x18\x01 \x01(\t\x12\x10\n\x08username\x18\x02 \x01(\t\x12\x10\n\x08is_admin\x18\x03 \x01(\x08\x12.\n\ncreated_at\x18\x04 \x01(\x0b2\x1a.google.protobuf.Timestamp\x12.\n\nupdated_at\x18\x05 \x01(\x0b2\x1a.google.protobuf.Timestamp"1\n\x0bUserMutable\x12\x15\n\x08username\x18\x01 \x01(\tH\x00\x88\x01\x01B\x0b\n\t_username">\n\x11CreateUserRequest\x12)\n\x04data\x18\x01 \x01(\x0b2\x1b.panels.user.v1.UserMutable" \n\x12GetUserByIdRequest\x12\n\n\x02id\x18\x01 \x01(\t"(\n\x14GetUserByNameRequest\x12\x10\n\x08username\x18\x01 \x01(\t"N\n\x15UpdateUserByIdRequest\x12\n\n\x02id\x18\x01 \x01(\t\x12)\n\x04data\x18\x02 \x01(\x0b2\x1b.panels.user.v1.UserMutable"V\n\x17UpdateUserByNameRequest\x12\x10\n\x08username\x18\x01 \x01(\t\x12)\n\x04data\x18\x02 \x01(\x0b2\x1b.panels.user.v1.UserMutable"#\n\x15DeleteUserByIdRequest\x12\n\n\x02id\x18\x01 \x01(\t"+\n\x17DeleteUserByNameRequest\x12\x10\n\x08username\x18\x01 \x01(\t"=\n\tUserEvent\x12\x0c\n\x04type\x18\x01 \x01(\t\x12"\n\x04data\x18\x02 \x01(\x0b2\x14.panels.user.v1.User2\xb4\x04\n\x0bUserService\x12G\n\nCreateUser\x12!.panels.user.v1.CreateUserRequest\x1a\x14.panels.user.v1.User"\x00\x12E\n\x07GetUser\x12".panels.user.v1.GetUserByIdRequest\x1a\x14.panels.user.v1.User"\x00\x12M\n\rGetUserByName\x12$.panels.user.v1.GetUserByNameRequest\x1a\x14.panels.user.v1.User"\x00\x12K\n\nUpdateUser\x12%.panels.user.v1.UpdateUserByIdRequest\x1a\x14.panels.user.v1.User"\x00\x12S\n\x10UpdateUserByName\x12\'.panels.user.v1.UpdateUserByNameRequest\x1a\x14.panels.user.v1.User"\x00\x12M\n\nDeleteUser\x12%.panels.user.v1.DeleteUserByIdRequest\x1a\x16.google.protobuf.Empty"\x00\x12U\n\x10DeleteUserByName\x12\'.panels.user.v1.DeleteUserByNameRequest\x1a\x16.google.protobuf.Empty"\x00b\x06proto3')
|
||||
_globals = globals()
|
||||
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
|
||||
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'user_pb2', _globals)
|
||||
if _descriptor._USE_C_DESCRIPTORS == False:
|
||||
DESCRIPTOR._options = None
|
||||
_globals['_USER']._serialized_start = 93
|
||||
_globals['_USER']._serialized_end = 243
|
||||
_globals['_USERMUTABLE']._serialized_start = 245
|
||||
_globals['_USERMUTABLE']._serialized_end = 294
|
||||
_globals['_CREATEUSERREQUEST']._serialized_start = 296
|
||||
_globals['_CREATEUSERREQUEST']._serialized_end = 358
|
||||
_globals['_GETUSERBYIDREQUEST']._serialized_start = 360
|
||||
_globals['_GETUSERBYIDREQUEST']._serialized_end = 392
|
||||
_globals['_GETUSERBYNAMEREQUEST']._serialized_start = 394
|
||||
_globals['_GETUSERBYNAMEREQUEST']._serialized_end = 434
|
||||
_globals['_UPDATEUSERBYIDREQUEST']._serialized_start = 436
|
||||
_globals['_UPDATEUSERBYIDREQUEST']._serialized_end = 514
|
||||
_globals['_UPDATEUSERBYNAMEREQUEST']._serialized_start = 516
|
||||
_globals['_UPDATEUSERBYNAMEREQUEST']._serialized_end = 602
|
||||
_globals['_DELETEUSERBYIDREQUEST']._serialized_start = 604
|
||||
_globals['_DELETEUSERBYIDREQUEST']._serialized_end = 639
|
||||
_globals['_DELETEUSERBYNAMEREQUEST']._serialized_start = 641
|
||||
_globals['_DELETEUSERBYNAMEREQUEST']._serialized_end = 684
|
||||
_globals['_USEREVENT']._serialized_start = 686
|
||||
_globals['_USEREVENT']._serialized_end = 747
|
||||
_globals['_USERSERVICE']._serialized_start = 750
|
||||
_globals['_USERSERVICE']._serialized_end = 1314
|
||||
100
services/auth-service/auth_service/models/proto/user_pb2.pyi
Normal file
100
services/auth-service/auth_service/models/proto/user_pb2.pyi
Normal file
@@ -0,0 +1,100 @@
|
||||
from google.protobuf import empty_pb2 as _empty_pb2
|
||||
from google.protobuf import timestamp_pb2 as _timestamp_pb2
|
||||
from google.protobuf import descriptor as _descriptor
|
||||
from google.protobuf import message as _message
|
||||
from typing import ClassVar as _ClassVar, Mapping as _Mapping, Optional as _Optional, Union as _Union
|
||||
DESCRIPTOR: _descriptor.FileDescriptor
|
||||
|
||||
class User(_message.Message):
|
||||
__slots__ = ['id', 'username', 'is_admin', 'created_at', 'updated_at']
|
||||
ID_FIELD_NUMBER: _ClassVar[int]
|
||||
USERNAME_FIELD_NUMBER: _ClassVar[int]
|
||||
IS_ADMIN_FIELD_NUMBER: _ClassVar[int]
|
||||
CREATED_AT_FIELD_NUMBER: _ClassVar[int]
|
||||
UPDATED_AT_FIELD_NUMBER: _ClassVar[int]
|
||||
id: str
|
||||
username: str
|
||||
is_admin: bool
|
||||
created_at: _timestamp_pb2.Timestamp
|
||||
updated_at: _timestamp_pb2.Timestamp
|
||||
|
||||
def __init__(self, id: _Optional[str]=..., username: _Optional[str]=..., is_admin: bool=..., created_at: _Optional[_Union[_timestamp_pb2.Timestamp, _Mapping]]=..., updated_at: _Optional[_Union[_timestamp_pb2.Timestamp, _Mapping]]=...) -> None:
|
||||
...
|
||||
|
||||
class UserMutable(_message.Message):
|
||||
__slots__ = ['username']
|
||||
USERNAME_FIELD_NUMBER: _ClassVar[int]
|
||||
username: str
|
||||
|
||||
def __init__(self, username: _Optional[str]=...) -> None:
|
||||
...
|
||||
|
||||
class CreateUserRequest(_message.Message):
|
||||
__slots__ = ['data']
|
||||
DATA_FIELD_NUMBER: _ClassVar[int]
|
||||
data: UserMutable
|
||||
|
||||
def __init__(self, data: _Optional[_Union[UserMutable, _Mapping]]=...) -> None:
|
||||
...
|
||||
|
||||
class GetUserByIdRequest(_message.Message):
|
||||
__slots__ = ['id']
|
||||
ID_FIELD_NUMBER: _ClassVar[int]
|
||||
id: str
|
||||
|
||||
def __init__(self, id: _Optional[str]=...) -> None:
|
||||
...
|
||||
|
||||
class GetUserByNameRequest(_message.Message):
|
||||
__slots__ = ['username']
|
||||
USERNAME_FIELD_NUMBER: _ClassVar[int]
|
||||
username: str
|
||||
|
||||
def __init__(self, username: _Optional[str]=...) -> None:
|
||||
...
|
||||
|
||||
class UpdateUserByIdRequest(_message.Message):
|
||||
__slots__ = ['id', 'data']
|
||||
ID_FIELD_NUMBER: _ClassVar[int]
|
||||
DATA_FIELD_NUMBER: _ClassVar[int]
|
||||
id: str
|
||||
data: UserMutable
|
||||
|
||||
def __init__(self, id: _Optional[str]=..., data: _Optional[_Union[UserMutable, _Mapping]]=...) -> None:
|
||||
...
|
||||
|
||||
class UpdateUserByNameRequest(_message.Message):
|
||||
__slots__ = ['username', 'data']
|
||||
USERNAME_FIELD_NUMBER: _ClassVar[int]
|
||||
DATA_FIELD_NUMBER: _ClassVar[int]
|
||||
username: str
|
||||
data: UserMutable
|
||||
|
||||
def __init__(self, username: _Optional[str]=..., data: _Optional[_Union[UserMutable, _Mapping]]=...) -> None:
|
||||
...
|
||||
|
||||
class DeleteUserByIdRequest(_message.Message):
|
||||
__slots__ = ['id']
|
||||
ID_FIELD_NUMBER: _ClassVar[int]
|
||||
id: str
|
||||
|
||||
def __init__(self, id: _Optional[str]=...) -> None:
|
||||
...
|
||||
|
||||
class DeleteUserByNameRequest(_message.Message):
|
||||
__slots__ = ['username']
|
||||
USERNAME_FIELD_NUMBER: _ClassVar[int]
|
||||
username: str
|
||||
|
||||
def __init__(self, username: _Optional[str]=...) -> None:
|
||||
...
|
||||
|
||||
class UserEvent(_message.Message):
|
||||
__slots__ = ['type', 'data']
|
||||
TYPE_FIELD_NUMBER: _ClassVar[int]
|
||||
DATA_FIELD_NUMBER: _ClassVar[int]
|
||||
type: str
|
||||
data: User
|
||||
|
||||
def __init__(self, type: _Optional[str]=..., data: _Optional[_Union[User, _Mapping]]=...) -> None:
|
||||
...
|
||||
102
services/auth-service/auth_service/models/proto/user_pb2_grpc.py
Normal file
102
services/auth-service/auth_service/models/proto/user_pb2_grpc.py
Normal file
@@ -0,0 +1,102 @@
|
||||
"""Client and server classes corresponding to protobuf-defined services."""
|
||||
import grpc
|
||||
from google.protobuf import empty_pb2 as google_dot_protobuf_dot_empty__pb2
|
||||
from . import user_pb2 as user__pb2
|
||||
|
||||
class UserServiceStub(object):
|
||||
"""Missing associated documentation comment in .proto file."""
|
||||
|
||||
def __init__(self, channel):
|
||||
"""Constructor.
|
||||
|
||||
Args:
|
||||
channel: A grpc.Channel.
|
||||
"""
|
||||
self.CreateUser = channel.unary_unary('/panels.user.v1.UserService/CreateUser', request_serializer=user__pb2.CreateUserRequest.SerializeToString, response_deserializer=user__pb2.User.FromString)
|
||||
self.GetUser = channel.unary_unary('/panels.user.v1.UserService/GetUser', request_serializer=user__pb2.GetUserByIdRequest.SerializeToString, response_deserializer=user__pb2.User.FromString)
|
||||
self.GetUserByName = channel.unary_unary('/panels.user.v1.UserService/GetUserByName', request_serializer=user__pb2.GetUserByNameRequest.SerializeToString, response_deserializer=user__pb2.User.FromString)
|
||||
self.UpdateUser = channel.unary_unary('/panels.user.v1.UserService/UpdateUser', request_serializer=user__pb2.UpdateUserByIdRequest.SerializeToString, response_deserializer=user__pb2.User.FromString)
|
||||
self.UpdateUserByName = channel.unary_unary('/panels.user.v1.UserService/UpdateUserByName', request_serializer=user__pb2.UpdateUserByNameRequest.SerializeToString, response_deserializer=user__pb2.User.FromString)
|
||||
self.DeleteUser = channel.unary_unary('/panels.user.v1.UserService/DeleteUser', request_serializer=user__pb2.DeleteUserByIdRequest.SerializeToString, response_deserializer=google_dot_protobuf_dot_empty__pb2.Empty.FromString)
|
||||
self.DeleteUserByName = channel.unary_unary('/panels.user.v1.UserService/DeleteUserByName', request_serializer=user__pb2.DeleteUserByNameRequest.SerializeToString, response_deserializer=google_dot_protobuf_dot_empty__pb2.Empty.FromString)
|
||||
|
||||
class UserServiceServicer(object):
|
||||
"""Missing associated documentation comment in .proto file."""
|
||||
|
||||
def CreateUser(self, request, context):
|
||||
"""Missing associated documentation comment in .proto file."""
|
||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||
context.set_details('Method not implemented!')
|
||||
raise NotImplementedError('Method not implemented!')
|
||||
|
||||
def GetUser(self, request, context):
|
||||
"""Missing associated documentation comment in .proto file."""
|
||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||
context.set_details('Method not implemented!')
|
||||
raise NotImplementedError('Method not implemented!')
|
||||
|
||||
def GetUserByName(self, request, context):
|
||||
"""Missing associated documentation comment in .proto file."""
|
||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||
context.set_details('Method not implemented!')
|
||||
raise NotImplementedError('Method not implemented!')
|
||||
|
||||
def UpdateUser(self, request, context):
|
||||
"""Missing associated documentation comment in .proto file."""
|
||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||
context.set_details('Method not implemented!')
|
||||
raise NotImplementedError('Method not implemented!')
|
||||
|
||||
def UpdateUserByName(self, request, context):
|
||||
"""Missing associated documentation comment in .proto file."""
|
||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||
context.set_details('Method not implemented!')
|
||||
raise NotImplementedError('Method not implemented!')
|
||||
|
||||
def DeleteUser(self, request, context):
|
||||
"""Missing associated documentation comment in .proto file."""
|
||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||
context.set_details('Method not implemented!')
|
||||
raise NotImplementedError('Method not implemented!')
|
||||
|
||||
def DeleteUserByName(self, request, context):
|
||||
"""Missing associated documentation comment in .proto file."""
|
||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||
context.set_details('Method not implemented!')
|
||||
raise NotImplementedError('Method not implemented!')
|
||||
|
||||
def add_UserServiceServicer_to_server(servicer, server):
|
||||
rpc_method_handlers = {'CreateUser': grpc.unary_unary_rpc_method_handler(servicer.CreateUser, request_deserializer=user__pb2.CreateUserRequest.FromString, response_serializer=user__pb2.User.SerializeToString), 'GetUser': grpc.unary_unary_rpc_method_handler(servicer.GetUser, request_deserializer=user__pb2.GetUserByIdRequest.FromString, response_serializer=user__pb2.User.SerializeToString), 'GetUserByName': grpc.unary_unary_rpc_method_handler(servicer.GetUserByName, request_deserializer=user__pb2.GetUserByNameRequest.FromString, response_serializer=user__pb2.User.SerializeToString), 'UpdateUser': grpc.unary_unary_rpc_method_handler(servicer.UpdateUser, request_deserializer=user__pb2.UpdateUserByIdRequest.FromString, response_serializer=user__pb2.User.SerializeToString), 'UpdateUserByName': grpc.unary_unary_rpc_method_handler(servicer.UpdateUserByName, request_deserializer=user__pb2.UpdateUserByNameRequest.FromString, response_serializer=user__pb2.User.SerializeToString), 'DeleteUser': grpc.unary_unary_rpc_method_handler(servicer.DeleteUser, request_deserializer=user__pb2.DeleteUserByIdRequest.FromString, response_serializer=google_dot_protobuf_dot_empty__pb2.Empty.SerializeToString), 'DeleteUserByName': grpc.unary_unary_rpc_method_handler(servicer.DeleteUserByName, request_deserializer=user__pb2.DeleteUserByNameRequest.FromString, response_serializer=google_dot_protobuf_dot_empty__pb2.Empty.SerializeToString)}
|
||||
generic_handler = grpc.method_handlers_generic_handler('panels.user.v1.UserService', rpc_method_handlers)
|
||||
server.add_generic_rpc_handlers((generic_handler,))
|
||||
|
||||
class UserService(object):
|
||||
"""Missing associated documentation comment in .proto file."""
|
||||
|
||||
@staticmethod
|
||||
def CreateUser(request, target, options=(), channel_credentials=None, call_credentials=None, insecure=False, compression=None, wait_for_ready=None, timeout=None, metadata=None):
|
||||
return grpc.experimental.unary_unary(request, target, '/panels.user.v1.UserService/CreateUser', user__pb2.CreateUserRequest.SerializeToString, user__pb2.User.FromString, options, channel_credentials, insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
|
||||
|
||||
@staticmethod
|
||||
def GetUser(request, target, options=(), channel_credentials=None, call_credentials=None, insecure=False, compression=None, wait_for_ready=None, timeout=None, metadata=None):
|
||||
return grpc.experimental.unary_unary(request, target, '/panels.user.v1.UserService/GetUser', user__pb2.GetUserByIdRequest.SerializeToString, user__pb2.User.FromString, options, channel_credentials, insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
|
||||
|
||||
@staticmethod
|
||||
def GetUserByName(request, target, options=(), channel_credentials=None, call_credentials=None, insecure=False, compression=None, wait_for_ready=None, timeout=None, metadata=None):
|
||||
return grpc.experimental.unary_unary(request, target, '/panels.user.v1.UserService/GetUserByName', user__pb2.GetUserByNameRequest.SerializeToString, user__pb2.User.FromString, options, channel_credentials, insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
|
||||
|
||||
@staticmethod
|
||||
def UpdateUser(request, target, options=(), channel_credentials=None, call_credentials=None, insecure=False, compression=None, wait_for_ready=None, timeout=None, metadata=None):
|
||||
return grpc.experimental.unary_unary(request, target, '/panels.user.v1.UserService/UpdateUser', user__pb2.UpdateUserByIdRequest.SerializeToString, user__pb2.User.FromString, options, channel_credentials, insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
|
||||
|
||||
@staticmethod
|
||||
def UpdateUserByName(request, target, options=(), channel_credentials=None, call_credentials=None, insecure=False, compression=None, wait_for_ready=None, timeout=None, metadata=None):
|
||||
return grpc.experimental.unary_unary(request, target, '/panels.user.v1.UserService/UpdateUserByName', user__pb2.UpdateUserByNameRequest.SerializeToString, user__pb2.User.FromString, options, channel_credentials, insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
|
||||
|
||||
@staticmethod
|
||||
def DeleteUser(request, target, options=(), channel_credentials=None, call_credentials=None, insecure=False, compression=None, wait_for_ready=None, timeout=None, metadata=None):
|
||||
return grpc.experimental.unary_unary(request, target, '/panels.user.v1.UserService/DeleteUser', user__pb2.DeleteUserByIdRequest.SerializeToString, google_dot_protobuf_dot_empty__pb2.Empty.FromString, options, channel_credentials, insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
|
||||
|
||||
@staticmethod
|
||||
def DeleteUserByName(request, target, options=(), channel_credentials=None, call_credentials=None, insecure=False, compression=None, wait_for_ready=None, timeout=None, metadata=None):
|
||||
return grpc.experimental.unary_unary(request, target, '/panels.user.v1.UserService/DeleteUserByName', user__pb2.DeleteUserByNameRequest.SerializeToString, google_dot_protobuf_dot_empty__pb2.Empty.FromString, options, channel_credentials, insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
|
||||
55
services/auth-service/auth_service/models/service.py
Normal file
55
services/auth-service/auth_service/models/service.py
Normal file
@@ -0,0 +1,55 @@
|
||||
from time import time
|
||||
from typing import Optional
|
||||
from datetime import timedelta
|
||||
|
||||
from pydantic import BaseModel, Field, SecretStr
|
||||
|
||||
from auth_service.models.proto import auth_pb2
|
||||
from auth_service.models.exceptions import ServiceException, ServiceErrorCode
|
||||
|
||||
|
||||
class AuthRecord(BaseModel):
|
||||
user_id: str
|
||||
password: SecretStr # Hashed Password
|
||||
|
||||
|
||||
class AuthToken(BaseModel):
|
||||
token_type: str = "Bearer"
|
||||
access_token: str
|
||||
expires_in: int = Field(default=int(timedelta(minutes=30).total_seconds()))
|
||||
# refresh_token: str # todo: implement functionality in the future
|
||||
|
||||
@classmethod
|
||||
def to_protobuf(cls, auth_token: "AuthToken") -> auth_pb2.AuthToken:
|
||||
return auth_pb2.AuthToken(**auth_token.model_dump())
|
||||
|
||||
|
||||
class AccessTokenClaims(BaseModel):
|
||||
sub: str
|
||||
iat: int = Field(default_factory=lambda: int(time()))
|
||||
exp: int = Field(default_factory=lambda: int(time() + timedelta(minutes=30).total_seconds()))
|
||||
|
||||
|
||||
class AuthRepository:
|
||||
"""Abstract repository interface"""
|
||||
async def auth_with_password(self, user_id: str, password: str) -> AuthToken:
|
||||
raise ServiceException("unimplemented internal repository method", ServiceErrorCode.SERVICE_ERROR)
|
||||
|
||||
async def set_password_auth_method(self, user_id: str, password: str) -> None:
|
||||
raise ServiceException("unimplemented internal repository method", ServiceErrorCode.SERVICE_ERROR)
|
||||
|
||||
async def delete_password_auth_method(self, user_id: str) -> None:
|
||||
raise ServiceException("unimplemented internal repository method", ServiceErrorCode.SERVICE_ERROR)
|
||||
|
||||
|
||||
class AuthDBRepository(AuthRepository):
|
||||
"""Abstract database repository interface"""
|
||||
async def get_auth_record(self, user_id: str) -> Optional[AuthRecord]:
|
||||
raise ServiceException("unimplemented internal repository method", ServiceErrorCode.SERVICE_ERROR)
|
||||
|
||||
async def create_password_auth_method(self, user_id: str, password: str) -> None:
|
||||
raise ServiceException("unimplemented internal repository method", ServiceErrorCode.SERVICE_ERROR)
|
||||
|
||||
async def update_password_auth_method(self, user_id: str, password: str) -> None:
|
||||
raise ServiceException("unimplemented internal repository method", ServiceErrorCode.SERVICE_ERROR)
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
DROP TABLE IF EXISTS auth_methods CASCADE;
|
||||
@@ -0,0 +1,4 @@
|
||||
CREATE TABLE auth_methods (
|
||||
"user_id" varchar(64) PRIMARY KEY,
|
||||
"password" varchar(128) NOT NULL
|
||||
);
|
||||
39
services/auth-service/auth_service/postgres/repository.py
Normal file
39
services/auth-service/auth_service/postgres/repository.py
Normal file
@@ -0,0 +1,39 @@
|
||||
from typing import Optional
|
||||
|
||||
from databases import Database
|
||||
|
||||
from auth_service.models.service import AuthDBRepository, AuthRecord
|
||||
|
||||
|
||||
class ServiceDBRepository(AuthDBRepository):
|
||||
"""Database repository responsible for CRUD actions
|
||||
on the database.
|
||||
|
||||
This repository will be utilised by other upstream repositories
|
||||
or the Kafka event consumers.
|
||||
|
||||
Attributes:
|
||||
_db (Database): The postgres database connection handler.
|
||||
|
||||
"""
|
||||
def __init__(self, db: Database) -> None:
|
||||
self._db = db
|
||||
|
||||
async def get_auth_record(self, user_id: str) -> Optional[AuthRecord]:
|
||||
query = "SELECT user_id, password FROM auth_methods WHERE user_id = :user_id"
|
||||
result = await self._db.fetch_one(query=query, values={"user_id": user_id})
|
||||
if result is None:
|
||||
return None
|
||||
return AuthRecord(user_id=result["user_id"], password=result["password"])
|
||||
|
||||
async def create_password_auth_method(self, user_id: str, password: str) -> None:
|
||||
query = "INSERT INTO auth_methods (user_id, password) VALUES (:user_id, :password)"
|
||||
await self._db.execute(query=query, values={"user_id": user_id, "password": password})
|
||||
|
||||
async def update_password_auth_method(self, user_id: str, password: str) -> None:
|
||||
query = "UPDATE auth_methods SET password = :password WHERE user_id = :user_id"
|
||||
await self._db.execute(query=query, values={"user_id": user_id, "password": password})
|
||||
|
||||
async def delete_password_auth_method(self, user_id: str) -> None:
|
||||
query = "DELETE FROM auth_methods WHERE user_id = :user_id"
|
||||
await self._db.execute(query=query, values={"user_id": user_id})
|
||||
40
services/auth-service/auth_service/postgres/service.py
Normal file
40
services/auth-service/auth_service/postgres/service.py
Normal file
@@ -0,0 +1,40 @@
|
||||
import logging
|
||||
|
||||
from databases import Database
|
||||
|
||||
from auth_service.models.config import Config
|
||||
from auth_service.postgres.repository import ServiceDBRepository
|
||||
|
||||
|
||||
async def connect_database(config: Config) -> Database:
|
||||
"""Opens a connection to the database.
|
||||
|
||||
Args:
|
||||
config (Config): The app configuration.
|
||||
|
||||
Returns:
|
||||
A connected databases.Database instance
|
||||
|
||||
"""
|
||||
db = Database(config.postgres_dsn)
|
||||
try:
|
||||
await db.connect()
|
||||
except Exception:
|
||||
logging.error("failed to connect to postgresql database")
|
||||
raise
|
||||
|
||||
return db
|
||||
|
||||
|
||||
async def create_db_repository(config: Config) -> ServiceDBRepository:
|
||||
"""Create the database repository.
|
||||
|
||||
Open a database connection and instantialise the
|
||||
database repository.
|
||||
|
||||
Returns:
|
||||
ServiceDBRepository
|
||||
|
||||
"""
|
||||
db = await connect_database(config)
|
||||
return ServiceDBRepository(db)
|
||||
0
services/auth-service/auth_service/rpc/__init__.py
Normal file
0
services/auth-service/auth_service/rpc/__init__.py
Normal file
185
services/auth-service/auth_service/rpc/auth.py
Normal file
185
services/auth-service/auth_service/rpc/auth.py
Normal file
@@ -0,0 +1,185 @@
|
||||
import logging
|
||||
import traceback
|
||||
from typing import Type
|
||||
|
||||
from google.protobuf import empty_pb2
|
||||
from grpc import RpcContext, StatusCode
|
||||
|
||||
from auth_service.models.exceptions import ServiceException
|
||||
from auth_service.models.service import AuthRepository, AuthToken
|
||||
from auth_service.models.proto import auth_pb2, auth_pb2_grpc
|
||||
|
||||
|
||||
class AuthServicer(auth_pb2_grpc.AuthServiceServicer):
|
||||
"""Contains definitions for the service's RPC methods.
|
||||
|
||||
The request attributes are validated and translated
|
||||
from protobufs into business model form, then passed
|
||||
along to the service repository to handling the
|
||||
business logic.
|
||||
|
||||
Responses from calls to methods in the service repository
|
||||
are then translated back to protobuf form to return
|
||||
to the user.
|
||||
|
||||
Attributes:
|
||||
_svc_repo (Type[AuthRepository]): The highest level service repository.
|
||||
|
||||
"""
|
||||
def __init__(self, svc_repo: Type[AuthRepository]) -> None:
|
||||
self._svc_repo = svc_repo
|
||||
|
||||
def _apply_error(self, context: RpcContext, code: StatusCode, msg: str) -> None:
|
||||
"""Set an error on a given RPC request.
|
||||
|
||||
Args:
|
||||
context (grpc.RpcContext): The context to apply the error to.
|
||||
code (grpc.StatusCode): The gRPC status code.
|
||||
msg (str): The error details.
|
||||
|
||||
"""
|
||||
context.set_code(code)
|
||||
context.set_details(msg)
|
||||
|
||||
def _apply_unknown_error(self, context: RpcContext) -> None:
|
||||
"""Apply a de facto error fallback message.
|
||||
|
||||
Args:
|
||||
context (grpc.RpcContext): The context to apply the error to.
|
||||
|
||||
"""
|
||||
self._apply_error(context, StatusCode.UNKNOWN, "unknown error occured")
|
||||
|
||||
async def AuthWithPassword(self, request: auth_pb2.PasswordAuthRequest, context: RpcContext) -> auth_pb2.AuthToken:
|
||||
"""AuthWithPassword RPC Call
|
||||
|
||||
Args:
|
||||
request (auth_pb2.PasswordAuthRequest): The request parameters.
|
||||
context (grpc.RpcContext): The context of the RPC call.
|
||||
|
||||
Returns:
|
||||
auth_pb2.AuthToken: With a succesfully authentication.
|
||||
|
||||
"""
|
||||
# validate the request inputs
|
||||
if request.user_id == "":
|
||||
self._apply_error(
|
||||
context,
|
||||
code=StatusCode.INVALID_ARGUMENT,
|
||||
msg="user not provided"
|
||||
)
|
||||
return
|
||||
|
||||
if request.password == "":
|
||||
self._apply_error(
|
||||
context,
|
||||
code=StatusCode.INVALID_ARGUMENT,
|
||||
msg="password not provided"
|
||||
)
|
||||
return
|
||||
|
||||
if len(request.password) < 8:
|
||||
self._apply_error(
|
||||
context,
|
||||
code=StatusCode.INVALID_ARGUMENT,
|
||||
msg="invalid password"
|
||||
)
|
||||
return
|
||||
|
||||
# Attempt to authenticate the user
|
||||
try:
|
||||
token = await self._svc_repo.auth_with_password(request.user_id, request.password)
|
||||
except ServiceException as err:
|
||||
err.apply_to_rpc(context)
|
||||
return
|
||||
except Exception:
|
||||
logging.error(traceback.format_exc())
|
||||
self._apply_unknown_error(context)
|
||||
return
|
||||
|
||||
# Convert token to protobuf
|
||||
return AuthToken.to_protobuf(token)
|
||||
|
||||
async def SetPasswordAuth(self, request: auth_pb2.SetPasswordAuthMethod, context: RpcContext) -> empty_pb2.Empty:
|
||||
"""SetPasswordAuth RPC Call
|
||||
|
||||
Args:
|
||||
request (auth_pb2.SetPasswordAuthMethod): The request parameters.
|
||||
context (grpc.RpcContext): The context of the RPC call.
|
||||
|
||||
Returns:
|
||||
empty_pb2.Empty: Empty protobuf response (in effect returns None).
|
||||
|
||||
"""
|
||||
# validate the request inputs
|
||||
if request.user_id == "":
|
||||
self._apply_error(
|
||||
context,
|
||||
code=StatusCode.INVALID_ARGUMENT,
|
||||
msg="user id not provided"
|
||||
)
|
||||
return
|
||||
|
||||
if request.password == "":
|
||||
self._apply_error(
|
||||
context,
|
||||
code=StatusCode.INVALID_ARGUMENT,
|
||||
msg="password not provided"
|
||||
)
|
||||
return
|
||||
|
||||
if len(request.password) < 8:
|
||||
self._apply_error(
|
||||
context,
|
||||
code=StatusCode.INVALID_ARGUMENT,
|
||||
msg="password must be at least 8 characters"
|
||||
)
|
||||
return
|
||||
|
||||
# Attempt to create the auth method
|
||||
try:
|
||||
await self._svc_repo.set_password_auth_method(request.user_id, request.password)
|
||||
except ServiceException as err:
|
||||
err.apply_to_rpc(context)
|
||||
return
|
||||
except Exception:
|
||||
logging.error(traceback.format_exc())
|
||||
self._apply_unknown_error(context)
|
||||
return
|
||||
|
||||
# Success
|
||||
return empty_pb2.Empty()
|
||||
|
||||
async def DeletePasswordAuth(self, request: auth_pb2.DeletePasswordAuthMethod, context: RpcContext) -> empty_pb2.Empty:
|
||||
"""DeletePasswordAuth RPC Call
|
||||
|
||||
Args:
|
||||
request (auth_pb2.DeletePasswordAuthMethod): The request parameters.
|
||||
context (grpc.RpcContext): The context of the RPC call.
|
||||
|
||||
Returns:
|
||||
empty_pb2.Empty: Empty protobuf response (in effect returns None).
|
||||
|
||||
"""
|
||||
# Ensure a user id is provided
|
||||
if request.user_id == "":
|
||||
self._apply_error(
|
||||
context,
|
||||
code=StatusCode.INVALID_ARGUMENT,
|
||||
msg="user id not provided"
|
||||
)
|
||||
return
|
||||
|
||||
# Attempt to delete the auth method
|
||||
try:
|
||||
await self._svc_repo.delete_password_auth_method(request.user_id, request.password)
|
||||
except ServiceException as err:
|
||||
err.apply_to_rpc(context)
|
||||
return
|
||||
except Exception:
|
||||
logging.error(traceback.format_exc())
|
||||
self._apply_unknown_error(context)
|
||||
return
|
||||
|
||||
# Success
|
||||
return empty_pb2.Empty()
|
||||
52
services/auth-service/auth_service/rpc/service.py
Normal file
52
services/auth-service/auth_service/rpc/service.py
Normal file
@@ -0,0 +1,52 @@
|
||||
import logging
|
||||
from typing import Type
|
||||
|
||||
import grpc
|
||||
from grpc_health.v1 import health, health_pb2_grpc
|
||||
|
||||
from auth_service.models.proto import auth_pb2_grpc
|
||||
from auth_service.models.service import AuthRepository
|
||||
from auth_service.rpc.auth import AuthServicer
|
||||
|
||||
|
||||
class RPCServerWrapper:
|
||||
"""A wrapper class for the RPC server.
|
||||
|
||||
Attributes:
|
||||
_grpc_server (grpc.aio.Server): The gRPC server instance.
|
||||
|
||||
"""
|
||||
def __init__(self, svc_repo: Type[AuthRepository]) -> None:
|
||||
"""Creates the gRPC server and adds the servicers.
|
||||
|
||||
Args:
|
||||
svc_repo (Type[AuthRepository]): The service repository to pass to the servicers.
|
||||
|
||||
"""
|
||||
self._grpc_server = grpc.aio.server()
|
||||
self._grpc_server.add_insecure_port("[::]:9090")
|
||||
|
||||
auth_servicer = AuthServicer(svc_repo)
|
||||
auth_pb2_grpc.add_AuthServiceServicer_to_server(auth_servicer, self._grpc_server)
|
||||
|
||||
health_servicer = health.aio.HealthServicer()
|
||||
health_pb2_grpc.add_HealthServicer_to_server(health_servicer, self._grpc_server)
|
||||
|
||||
async def start(self) -> None:
|
||||
"""Begin serving RPC asynchronously."""
|
||||
logging.info("attempting to serve RPC...")
|
||||
await self._grpc_server.start()
|
||||
await self._grpc_server.wait_for_termination()
|
||||
|
||||
|
||||
def create_rpc_server(svc_repo: Type[AuthRepository]) -> RPCServerWrapper:
|
||||
"""Instantialise the RPC server wrapper.
|
||||
|
||||
Args:
|
||||
svc_repo (Type[AuthRepository]): The service repository for the RPC servicers to interface with.
|
||||
|
||||
Returns:
|
||||
RPCServerWrapper
|
||||
|
||||
"""
|
||||
return RPCServerWrapper(svc_repo)
|
||||
161
services/auth-service/auth_service/service.py
Normal file
161
services/auth-service/auth_service/service.py
Normal file
@@ -0,0 +1,161 @@
|
||||
import hmac
|
||||
import hashlib
|
||||
from typing import Type
|
||||
|
||||
import jwt
|
||||
from argon2 import PasswordHasher
|
||||
from argon2.exceptions import VerificationError
|
||||
|
||||
from auth_service.models.config import Config
|
||||
from auth_service.models.exceptions import ServiceException, ServiceErrorCode
|
||||
from auth_service.models.service import AuthRepository, AuthDBRepository, AuthToken, AccessTokenClaims
|
||||
|
||||
|
||||
class ServiceRepository(AuthRepository):
|
||||
"""The service repository responsible for handling
|
||||
the business logic.
|
||||
|
||||
As I've developed most of the services in this project
|
||||
using a repository pattern, this provides a level
|
||||
of abstraction, allowing me to swap out the downstream
|
||||
repositories to add additional layers.
|
||||
|
||||
For example, instead of have the next downstream
|
||||
repository (`_repo` attribute) point directly
|
||||
to the DB repo instance, I could point it to a
|
||||
Redis repository to use as a caching layer, as I
|
||||
have done so in some of the other services in this
|
||||
project.
|
||||
|
||||
Attributes:
|
||||
_repo (AuthDBRepository): The downstream database repository.
|
||||
_jwt_private (str): RSA private key for producing JWT tokens.
|
||||
_hasher (argon2.PasswordHasher): Library class utilised for hashing passwords.
|
||||
_pepper (bytes): An additional 'secret salt' applied to all passwords when hashed.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, config: Config, downstream_repo: Type[AuthDBRepository]) -> None:
|
||||
self._repo = downstream_repo
|
||||
|
||||
self._jwt_private = config.jwt_private_key
|
||||
|
||||
self._hasher = PasswordHasher() # Use default RFC_9106_LOW_MEMORY profile
|
||||
self._pepper = bytes(config.password_pepper, encoding="utf-8")
|
||||
|
||||
def _apply_pepper(self, password: str) -> str:
|
||||
"""Apply the pepper ('secret salt') to
|
||||
a given password using HMAC.
|
||||
|
||||
Args:
|
||||
password (str): The password to apply to pepper to.
|
||||
|
||||
Returns:
|
||||
str: The password with applied pepper (in hexadecimal form).
|
||||
|
||||
"""
|
||||
return hmac.new(key=self._pepper, msg=bytes(password, encoding="utf-8"), digestmod=hashlib.sha256).hexdigest()
|
||||
|
||||
def _hash_password(self, password: str) -> str:
|
||||
"""Hash a given password.
|
||||
|
||||
The pepper is applied to the password, and the result
|
||||
is then hashed using Argon2id.
|
||||
|
||||
Args:
|
||||
password (str): The password to hash.
|
||||
|
||||
Returns:
|
||||
str: The hashed password.
|
||||
|
||||
"""
|
||||
return self._hasher.hash(self._apply_pepper(password))
|
||||
|
||||
def _verify_password(self, hash: str, password: str) -> None:
|
||||
"""Verify that an input password matches
|
||||
a hash.
|
||||
|
||||
The pepper is applied to the input password
|
||||
and compared to the stored hash.
|
||||
|
||||
Args:
|
||||
hash (str): The existing hashed password.
|
||||
password (str): The password to verify against the hash.
|
||||
|
||||
Raises:
|
||||
argon2.Exceptions.VerificationError: if the password does not match
|
||||
|
||||
"""
|
||||
self._hasher.verify(hash, self._apply_pepper(password))
|
||||
|
||||
def _issue_auth_token(self, user_id: str) -> AuthToken:
|
||||
"""Issue an auth token.
|
||||
|
||||
Args:
|
||||
user_id (str): The user to issue the tokens to.
|
||||
|
||||
Returns:
|
||||
AuthToken: A response containing the generated access token,
|
||||
token type and expiry time.
|
||||
"""
|
||||
claims = AccessTokenClaims(sub=user_id)
|
||||
access_token = jwt.encode(claims.model_dump(), self._jwt_private, algorithm="RS256")
|
||||
return AuthToken(access_token=access_token)
|
||||
|
||||
async def auth_with_password(self, user_id: str, password: str) -> AuthToken:
|
||||
"""Attempt to authenticate a user with a
|
||||
provided password.
|
||||
|
||||
Args:
|
||||
user_id (str): The user to attempt to authenticate.
|
||||
password (str): The password to verify against.
|
||||
|
||||
"""
|
||||
# Get the auth record for that user
|
||||
auth_record = await self._repo.get_auth_record(user_id)
|
||||
if not auth_record:
|
||||
raise ServiceException("invalid user id or password", ServiceErrorCode.INVALID_CREDENTIALS)
|
||||
|
||||
# Verify the password hashes
|
||||
try:
|
||||
self._verify_password(auth_record.password.get_secret_value(), password)
|
||||
except VerificationError:
|
||||
raise ServiceException("invalid user id or password", ServiceErrorCode.INVALID_CREDENTIALS)
|
||||
|
||||
# Update the auth record if the password needs rehash
|
||||
if self._hasher.check_needs_rehash(auth_record.password.get_secret_value()):
|
||||
await self._repo.update_password_auth_method(auth_record.user_id, self._hash_password(password))
|
||||
|
||||
# Issue a token for the user
|
||||
return self._issue_auth_token(auth_record.user_id)
|
||||
|
||||
async def set_password_auth_method(self, user_id: str, password: str) -> None:
|
||||
"""Set a user's password for use when authenticating.
|
||||
|
||||
If the specified user does not already have an existing
|
||||
authentication method, then insert a record, otherwise
|
||||
update their existing record.
|
||||
|
||||
Args:
|
||||
user_id (str): The referenced user.
|
||||
password (str): The new password for that user.
|
||||
|
||||
"""
|
||||
# Hash the password
|
||||
password = self._hash_password(password)
|
||||
|
||||
# Update the auth method or create one if it doesn't exist
|
||||
auth_record = await self._repo.get_auth_record(user_id)
|
||||
if auth_record is not None:
|
||||
await self._repo.update_password_auth_method(user_id, password)
|
||||
else:
|
||||
await self._repo.create_password_auth_method(user_id, password)
|
||||
|
||||
async def delete_password_auth_method(self, user_id: str) -> None:
|
||||
"""Delete a user's authentication method.
|
||||
|
||||
Args:
|
||||
user_id (str): The referenced user.
|
||||
|
||||
"""
|
||||
await self._repo.delete_password_auth_method(user_id)
|
||||
929
services/auth-service/poetry.lock
generated
Normal file
929
services/auth-service/poetry.lock
generated
Normal file
@@ -0,0 +1,929 @@
|
||||
[[package]]
|
||||
name = "aiokafka"
|
||||
version = "0.8.1"
|
||||
description = "Kafka integration with asyncio."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
|
||||
[package.dependencies]
|
||||
async-timeout = "*"
|
||||
kafka-python = ">=2.0.2"
|
||||
packaging = "*"
|
||||
|
||||
[package.extras]
|
||||
all = ["python-snappy (>=0.5)", "lz4", "zstandard", "gssapi"]
|
||||
gssapi = ["gssapi"]
|
||||
lz4 = ["lz4"]
|
||||
snappy = ["python-snappy (>=0.5)"]
|
||||
zstd = ["zstandard"]
|
||||
|
||||
[[package]]
|
||||
name = "annotated-types"
|
||||
version = "0.5.0"
|
||||
description = "Reusable constraint types to use with typing.Annotated"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
|
||||
[[package]]
|
||||
name = "argon2-cffi"
|
||||
version = "23.1.0"
|
||||
description = "Argon2 for Python"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
|
||||
[package.dependencies]
|
||||
argon2-cffi-bindings = "*"
|
||||
|
||||
[package.extras]
|
||||
dev = ["argon2-cffi", "tox (>4)"]
|
||||
docs = ["furo", "myst-parser", "sphinx", "sphinx-copybutton", "sphinx-notfound-page"]
|
||||
tests = ["hypothesis", "pytest"]
|
||||
typing = ["mypy"]
|
||||
|
||||
[[package]]
|
||||
name = "argon2-cffi-bindings"
|
||||
version = "21.2.0"
|
||||
description = "Low-level CFFI bindings for Argon2"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
|
||||
[package.dependencies]
|
||||
cffi = ">=1.0.1"
|
||||
|
||||
[package.extras]
|
||||
dev = ["pytest", "cogapp", "pre-commit", "wheel"]
|
||||
tests = ["pytest"]
|
||||
|
||||
[[package]]
|
||||
name = "async-timeout"
|
||||
version = "4.0.3"
|
||||
description = "Timeout context manager for asyncio programs"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
|
||||
[[package]]
|
||||
name = "asyncpg"
|
||||
version = "0.28.0"
|
||||
description = "An asyncio PostgreSQL driver"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.7.0"
|
||||
|
||||
[package.extras]
|
||||
docs = ["Sphinx (>=5.3.0,<5.4.0)", "sphinxcontrib-asyncio (>=0.3.0,<0.4.0)", "sphinx-rtd-theme (>=1.2.2)"]
|
||||
test = ["flake8 (>=5.0,<6.0)", "uvloop (>=0.15.3)"]
|
||||
|
||||
[[package]]
|
||||
name = "cffi"
|
||||
version = "1.15.1"
|
||||
description = "Foreign Function Interface for Python calling C code."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
|
||||
[package.dependencies]
|
||||
pycparser = "*"
|
||||
|
||||
[[package]]
|
||||
name = "click"
|
||||
version = "8.1.7"
|
||||
description = "Composable command line interface toolkit"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
|
||||
[package.dependencies]
|
||||
colorama = {version = "*", markers = "platform_system == \"Windows\""}
|
||||
|
||||
[[package]]
|
||||
name = "colorama"
|
||||
version = "0.4.6"
|
||||
description = "Cross-platform colored terminal text."
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7"
|
||||
|
||||
[[package]]
|
||||
name = "cryptography"
|
||||
version = "41.0.3"
|
||||
description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
|
||||
[package.dependencies]
|
||||
cffi = ">=1.12"
|
||||
|
||||
[package.extras]
|
||||
docs = ["sphinx (>=5.3.0)", "sphinx-rtd-theme (>=1.1.1)"]
|
||||
docstest = ["pyenchant (>=1.6.11)", "twine (>=1.12.0)", "sphinxcontrib-spelling (>=4.0.1)"]
|
||||
nox = ["nox"]
|
||||
pep8test = ["black", "ruff", "mypy", "check-sdist"]
|
||||
sdist = ["build"]
|
||||
ssh = ["bcrypt (>=3.1.5)"]
|
||||
test = ["pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-xdist", "pretend"]
|
||||
test-randomorder = ["pytest-randomly"]
|
||||
|
||||
[[package]]
|
||||
name = "databases"
|
||||
version = "0.8.0"
|
||||
description = "Async database support for Python."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
|
||||
[package.dependencies]
|
||||
asyncpg = {version = "*", optional = true, markers = "extra == \"asyncpg\""}
|
||||
sqlalchemy = ">=1.4.42,<1.5"
|
||||
|
||||
[package.extras]
|
||||
aiomysql = ["aiomysql"]
|
||||
aiopg = ["aiopg"]
|
||||
aiosqlite = ["aiosqlite"]
|
||||
asyncmy = ["asyncmy"]
|
||||
asyncpg = ["asyncpg"]
|
||||
mysql = ["aiomysql"]
|
||||
postgresql = ["asyncpg"]
|
||||
sqlite = ["aiosqlite"]
|
||||
|
||||
[[package]]
|
||||
name = "greenlet"
|
||||
version = "2.0.2"
|
||||
description = "Lightweight in-process concurrent programming"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*"
|
||||
|
||||
[package.extras]
|
||||
docs = ["sphinx", "docutils (<0.18)"]
|
||||
test = ["objgraph", "psutil"]
|
||||
|
||||
[[package]]
|
||||
name = "grpcio"
|
||||
version = "1.57.0"
|
||||
description = "HTTP/2-based RPC framework"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
|
||||
[package.extras]
|
||||
protobuf = ["grpcio-tools (>=1.57.0)"]
|
||||
|
||||
[[package]]
|
||||
name = "grpcio-health-checking"
|
||||
version = "1.57.0"
|
||||
description = "Standard Health Checking Service for gRPC"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
|
||||
[package.dependencies]
|
||||
grpcio = ">=1.57.0"
|
||||
protobuf = ">=4.21.6"
|
||||
|
||||
[[package]]
|
||||
name = "grpcio-tools"
|
||||
version = "1.57.0"
|
||||
description = "Protobuf code generator for gRPC"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
|
||||
[package.dependencies]
|
||||
grpcio = ">=1.57.0"
|
||||
protobuf = ">=4.21.6,<5.0dev"
|
||||
|
||||
[[package]]
|
||||
name = "kafka-python"
|
||||
version = "2.0.2"
|
||||
description = "Pure Python client for Apache Kafka"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
|
||||
[package.extras]
|
||||
crc32c = ["crc32c"]
|
||||
|
||||
[[package]]
|
||||
name = "packaging"
|
||||
version = "23.1"
|
||||
description = "Core utilities for Python packages"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
|
||||
[[package]]
|
||||
name = "protobuf"
|
||||
version = "4.24.2"
|
||||
description = ""
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
|
||||
[[package]]
|
||||
name = "protoletariat"
|
||||
version = "3.2.19"
|
||||
description = "Python protocol buffers for the rest of us"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.8,<4.0"
|
||||
|
||||
[package.dependencies]
|
||||
click = ">=8,<9"
|
||||
protobuf = ">=3.19.1,<5"
|
||||
|
||||
[package.extras]
|
||||
grpcio-tools = ["grpcio-tools (>=1.42.0,<2)"]
|
||||
|
||||
[[package]]
|
||||
name = "pycparser"
|
||||
version = "2.21"
|
||||
description = "C parser in Python"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
||||
|
||||
[[package]]
|
||||
name = "pydantic"
|
||||
version = "2.3.0"
|
||||
description = "Data validation using Python type hints"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
|
||||
[package.dependencies]
|
||||
annotated-types = ">=0.4.0"
|
||||
pydantic-core = "2.6.3"
|
||||
typing-extensions = ">=4.6.1"
|
||||
|
||||
[package.extras]
|
||||
email = ["email-validator (>=2.0.0)"]
|
||||
|
||||
[[package]]
|
||||
name = "pydantic-core"
|
||||
version = "2.6.3"
|
||||
description = ""
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
|
||||
[package.dependencies]
|
||||
typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0"
|
||||
|
||||
[[package]]
|
||||
name = "pydantic-settings"
|
||||
version = "2.0.3"
|
||||
description = "Settings management using Pydantic"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
|
||||
[package.dependencies]
|
||||
pydantic = ">=2.0.1"
|
||||
python-dotenv = ">=0.21.0"
|
||||
|
||||
[[package]]
|
||||
name = "pyjwt"
|
||||
version = "2.8.0"
|
||||
description = "JSON Web Token implementation in Python"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
|
||||
[package.dependencies]
|
||||
cryptography = {version = ">=3.4.0", optional = true, markers = "extra == \"crypto\""}
|
||||
|
||||
[package.extras]
|
||||
crypto = ["cryptography (>=3.4.0)"]
|
||||
dev = ["sphinx (>=4.5.0,<5.0.0)", "sphinx-rtd-theme", "zope.interface", "cryptography (>=3.4.0)", "pytest (>=6.0.0,<7.0.0)", "coverage[toml] (==5.0.4)", "pre-commit"]
|
||||
docs = ["sphinx (>=4.5.0,<5.0.0)", "sphinx-rtd-theme", "zope.interface"]
|
||||
tests = ["pytest (>=6.0.0,<7.0.0)", "coverage[toml] (==5.0.4)"]
|
||||
|
||||
[[package]]
|
||||
name = "python-dotenv"
|
||||
version = "1.0.0"
|
||||
description = "Read key-value pairs from a .env file and set them as environment variables"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
|
||||
[package.extras]
|
||||
cli = ["click (>=5.0)"]
|
||||
|
||||
[[package]]
|
||||
name = "sqlalchemy"
|
||||
version = "1.4.49"
|
||||
description = "Database Abstraction Library"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7"
|
||||
|
||||
[package.dependencies]
|
||||
greenlet = {version = "!=0.4.17", markers = "python_version >= \"3\" and (platform_machine == \"aarch64\" or platform_machine == \"ppc64le\" or platform_machine == \"x86_64\" or platform_machine == \"amd64\" or platform_machine == \"AMD64\" or platform_machine == \"win32\" or platform_machine == \"WIN32\")"}
|
||||
|
||||
[package.extras]
|
||||
aiomysql = ["greenlet (!=0.4.17)", "aiomysql"]
|
||||
aiosqlite = ["typing_extensions (!=3.10.0.1)", "greenlet (!=0.4.17)", "aiosqlite"]
|
||||
asyncio = ["greenlet (!=0.4.17)"]
|
||||
asyncmy = ["greenlet (!=0.4.17)", "asyncmy (>=0.2.3,!=0.2.4)"]
|
||||
mariadb_connector = ["mariadb (>=1.0.1,!=1.1.2)"]
|
||||
mssql = ["pyodbc"]
|
||||
mssql_pymssql = ["pymssql"]
|
||||
mssql_pyodbc = ["pyodbc"]
|
||||
mypy = ["sqlalchemy2-stubs", "mypy (>=0.910)"]
|
||||
mysql = ["mysqlclient (>=1.4.0,<2)", "mysqlclient (>=1.4.0)"]
|
||||
mysql_connector = ["mysql-connector-python"]
|
||||
oracle = ["cx_oracle (>=7,<8)", "cx_oracle (>=7)"]
|
||||
postgresql = ["psycopg2 (>=2.7)"]
|
||||
postgresql_asyncpg = ["greenlet (!=0.4.17)", "asyncpg"]
|
||||
postgresql_pg8000 = ["pg8000 (>=1.16.6,!=1.29.0)"]
|
||||
postgresql_psycopg2binary = ["psycopg2-binary"]
|
||||
postgresql_psycopg2cffi = ["psycopg2cffi"]
|
||||
pymysql = ["pymysql (<1)", "pymysql"]
|
||||
sqlcipher = ["sqlcipher3-binary"]
|
||||
|
||||
[[package]]
|
||||
name = "typing-extensions"
|
||||
version = "4.7.1"
|
||||
description = "Backported and Experimental Type Hints for Python 3.7+"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
|
||||
[metadata]
|
||||
lock-version = "1.1"
|
||||
python-versions = "^3.9"
|
||||
content-hash = "5dfd84147a63871a9cf83342dd0cc1ba26b27eb8891189ae646b6e02c922c742"
|
||||
|
||||
[metadata.files]
|
||||
aiokafka = [
|
||||
{file = "aiokafka-0.8.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:1f6044ed270b946d31f265903b5eb101940ed0ff3a902eaf8178103c943bbcc9"},
|
||||
{file = "aiokafka-0.8.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1e24839088fd6d3ff481cc09a48ea487b997328df11630bc0a1b88255edbcfe9"},
|
||||
{file = "aiokafka-0.8.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3816bcfc3c57dfa4ed77fe1dc3a9a464e17b6400061348155115f282c8150c47"},
|
||||
{file = "aiokafka-0.8.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b2bf97548fa77ad31062ca580368d346b16ba9fdca5856c435f256f3699ab12b"},
|
||||
{file = "aiokafka-0.8.1-cp310-cp310-win32.whl", hash = "sha256:6421ee81084532f915501074a132acb2afc8cb88bf5ddb11e584230a30f6f006"},
|
||||
{file = "aiokafka-0.8.1-cp310-cp310-win_amd64.whl", hash = "sha256:9f19d90b7360bc2239fcd8b147508ae39c3e5b1acfc8e6a2a9b0f306070f7ffe"},
|
||||
{file = "aiokafka-0.8.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:673c163dee62dfe45146d5250af0e395da5cc92b63f8878c592abc7dc1862899"},
|
||||
{file = "aiokafka-0.8.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4693fbe3c10f125bf3e2df8a8ccbca3eff2bdaaa6589d28c7532c10e7d84598b"},
|
||||
{file = "aiokafka-0.8.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bbffc431d9285328c0bc108949132ae11cec863f1dd5a43a1fc3d45a69ffb8a9"},
|
||||
{file = "aiokafka-0.8.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4fccd599ab6b3fda4f4187d854b343f153b40d05d6774be9acf238618da50031"},
|
||||
{file = "aiokafka-0.8.1-cp311-cp311-win32.whl", hash = "sha256:90960356513f3979754261b132b12a96b0d9e3c6eb44420e3a90a7c31156a81a"},
|
||||
{file = "aiokafka-0.8.1-cp311-cp311-win_amd64.whl", hash = "sha256:7f09784322c0d2c4fcc222add4337a5ac394aa30a248eb4e0e4587a125573c75"},
|
||||
{file = "aiokafka-0.8.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ff318d29ecbeea8c58d69c91c24d48d7ed4a8d3e829b607e670d118a9a35d5ba"},
|
||||
{file = "aiokafka-0.8.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:af6df9a41e08b61d7e62c0a416feeabd81bad76fa5c70d499b083d6af9ce72c3"},
|
||||
{file = "aiokafka-0.8.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7d327d66b41c4e3bafff7f9efb71936a08f940aa665680717e20862e4272a068"},
|
||||
{file = "aiokafka-0.8.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:24373bb2d519abac036d5b04ebc43452ef4ad1916953b6678b9801a9c93ba237"},
|
||||
{file = "aiokafka-0.8.1-cp38-cp38-win32.whl", hash = "sha256:fd8f9e17bc9cd2ea664a7f5133aede39a8fffebffe0c450252d475dbdedb4a35"},
|
||||
{file = "aiokafka-0.8.1-cp38-cp38-win_amd64.whl", hash = "sha256:2fa54b8b068d9d8735cb6757a0f48168f8cf9be68860b0bae6b3ed1684cef49b"},
|
||||
{file = "aiokafka-0.8.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:bf7473c55dc7959d4b7f9d750fa6017b325813d6cb761e488c2d9ea44e922954"},
|
||||
{file = "aiokafka-0.8.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c4332d37cb9d52181cfda4236566b4028c7c188549277f87bcc3027577d72b1b"},
|
||||
{file = "aiokafka-0.8.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1f43d2afd7d3e4407ada8d754895fad7c344ca00648a8a38418d76564eaaf6cd"},
|
||||
{file = "aiokafka-0.8.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a8a641a8102c51422afe111d4bc70c51f335f38fc5906e4c839bd17afeaf3cb2"},
|
||||
{file = "aiokafka-0.8.1-cp39-cp39-win32.whl", hash = "sha256:935da8c4da9a00a1e16020d88e578206097b4bb72ebc2a25fbd2cb817907ef28"},
|
||||
{file = "aiokafka-0.8.1-cp39-cp39-win_amd64.whl", hash = "sha256:45cd28af6590d6a999bb706803166570121ba8a5a0d06c51ebd8a59fab53593c"},
|
||||
{file = "aiokafka-0.8.1.tar.gz", hash = "sha256:d300188e358cd29989c817f6ee2a2965a039e5a71de8ade6f80f02ebb9bd07b8"},
|
||||
]
|
||||
annotated-types = [
|
||||
{file = "annotated_types-0.5.0-py3-none-any.whl", hash = "sha256:58da39888f92c276ad970249761ebea80ba544b77acddaa1a4d6cf78287d45fd"},
|
||||
{file = "annotated_types-0.5.0.tar.gz", hash = "sha256:47cdc3490d9ac1506ce92c7aaa76c579dc3509ff11e098fc867e5130ab7be802"},
|
||||
]
|
||||
argon2-cffi = [
|
||||
{file = "argon2_cffi-23.1.0-py3-none-any.whl", hash = "sha256:c670642b78ba29641818ab2e68bd4e6a78ba53b7eff7b4c3815ae16abf91c7ea"},
|
||||
{file = "argon2_cffi-23.1.0.tar.gz", hash = "sha256:879c3e79a2729ce768ebb7d36d4609e3a78a4ca2ec3a9f12286ca057e3d0db08"},
|
||||
]
|
||||
argon2-cffi-bindings = [
|
||||
{file = "argon2-cffi-bindings-21.2.0.tar.gz", hash = "sha256:bb89ceffa6c791807d1305ceb77dbfacc5aa499891d2c55661c6459651fc39e3"},
|
||||
{file = "argon2_cffi_bindings-21.2.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:ccb949252cb2ab3a08c02024acb77cfb179492d5701c7cbdbfd776124d4d2367"},
|
||||
{file = "argon2_cffi_bindings-21.2.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9524464572e12979364b7d600abf96181d3541da11e23ddf565a32e70bd4dc0d"},
|
||||
{file = "argon2_cffi_bindings-21.2.0-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b746dba803a79238e925d9046a63aa26bf86ab2a2fe74ce6b009a1c3f5c8f2ae"},
|
||||
{file = "argon2_cffi_bindings-21.2.0-cp36-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:58ed19212051f49a523abb1dbe954337dc82d947fb6e5a0da60f7c8471a8476c"},
|
||||
{file = "argon2_cffi_bindings-21.2.0-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:bd46088725ef7f58b5a1ef7ca06647ebaf0eb4baff7d1d0d177c6cc8744abd86"},
|
||||
{file = "argon2_cffi_bindings-21.2.0-cp36-abi3-musllinux_1_1_i686.whl", hash = "sha256:8cd69c07dd875537a824deec19f978e0f2078fdda07fd5c42ac29668dda5f40f"},
|
||||
{file = "argon2_cffi_bindings-21.2.0-cp36-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:f1152ac548bd5b8bcecfb0b0371f082037e47128653df2e8ba6e914d384f3c3e"},
|
||||
{file = "argon2_cffi_bindings-21.2.0-cp36-abi3-win32.whl", hash = "sha256:603ca0aba86b1349b147cab91ae970c63118a0f30444d4bc80355937c950c082"},
|
||||
{file = "argon2_cffi_bindings-21.2.0-cp36-abi3-win_amd64.whl", hash = "sha256:b2ef1c30440dbbcba7a5dc3e319408b59676e2e039e2ae11a8775ecf482b192f"},
|
||||
{file = "argon2_cffi_bindings-21.2.0-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:e415e3f62c8d124ee16018e491a009937f8cf7ebf5eb430ffc5de21b900dad93"},
|
||||
{file = "argon2_cffi_bindings-21.2.0-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:3e385d1c39c520c08b53d63300c3ecc28622f076f4c2b0e6d7e796e9f6502194"},
|
||||
{file = "argon2_cffi_bindings-21.2.0-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2c3e3cc67fdb7d82c4718f19b4e7a87123caf8a93fde7e23cf66ac0337d3cb3f"},
|
||||
{file = "argon2_cffi_bindings-21.2.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6a22ad9800121b71099d0fb0a65323810a15f2e292f2ba450810a7316e128ee5"},
|
||||
{file = "argon2_cffi_bindings-21.2.0-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f9f8b450ed0547e3d473fdc8612083fd08dd2120d6ac8f73828df9b7d45bb351"},
|
||||
{file = "argon2_cffi_bindings-21.2.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:93f9bf70084f97245ba10ee36575f0c3f1e7d7724d67d8e5b08e61787c320ed7"},
|
||||
{file = "argon2_cffi_bindings-21.2.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:3b9ef65804859d335dc6b31582cad2c5166f0c3e7975f324d9ffaa34ee7e6583"},
|
||||
{file = "argon2_cffi_bindings-21.2.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d4966ef5848d820776f5f562a7d45fdd70c2f330c961d0d745b784034bd9f48d"},
|
||||
{file = "argon2_cffi_bindings-21.2.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:20ef543a89dee4db46a1a6e206cd015360e5a75822f76df533845c3cbaf72670"},
|
||||
{file = "argon2_cffi_bindings-21.2.0-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ed2937d286e2ad0cc79a7087d3c272832865f779430e0cc2b4f3718d3159b0cb"},
|
||||
{file = "argon2_cffi_bindings-21.2.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:5e00316dabdaea0b2dd82d141cc66889ced0cdcbfa599e8b471cf22c620c329a"},
|
||||
]
|
||||
async-timeout = [
|
||||
{file = "async-timeout-4.0.3.tar.gz", hash = "sha256:4640d96be84d82d02ed59ea2b7105a0f7b33abe8703703cd0ab0bf87c427522f"},
|
||||
{file = "async_timeout-4.0.3-py3-none-any.whl", hash = "sha256:7405140ff1230c310e51dc27b3145b9092d659ce68ff733fb0cefe3ee42be028"},
|
||||
]
|
||||
asyncpg = [
|
||||
{file = "asyncpg-0.28.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0a6d1b954d2b296292ddff4e0060f494bb4270d87fb3655dd23c5c6096d16d83"},
|
||||
{file = "asyncpg-0.28.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0740f836985fd2bd73dca42c50c6074d1d61376e134d7ad3ad7566c4f79f8184"},
|
||||
{file = "asyncpg-0.28.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e907cf620a819fab1737f2dd90c0f185e2a796f139ac7de6aa3212a8af96c050"},
|
||||
{file = "asyncpg-0.28.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:86b339984d55e8202e0c4b252e9573e26e5afa05617ed02252544f7b3e6de3e9"},
|
||||
{file = "asyncpg-0.28.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:0c402745185414e4c204a02daca3d22d732b37359db4d2e705172324e2d94e85"},
|
||||
{file = "asyncpg-0.28.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c88eef5e096296626e9688f00ab627231f709d0e7e3fb84bb4413dff81d996d7"},
|
||||
{file = "asyncpg-0.28.0-cp310-cp310-win32.whl", hash = "sha256:90a7bae882a9e65a9e448fdad3e090c2609bb4637d2a9c90bfdcebbfc334bf89"},
|
||||
{file = "asyncpg-0.28.0-cp310-cp310-win_amd64.whl", hash = "sha256:76aacdcd5e2e9999e83c8fbcb748208b60925cc714a578925adcb446d709016c"},
|
||||
{file = "asyncpg-0.28.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a0e08fe2c9b3618459caaef35979d45f4e4f8d4f79490c9fa3367251366af207"},
|
||||
{file = "asyncpg-0.28.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b24e521f6060ff5d35f761a623b0042c84b9c9b9fb82786aadca95a9cb4a893b"},
|
||||
{file = "asyncpg-0.28.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:99417210461a41891c4ff301490a8713d1ca99b694fef05dabd7139f9d64bd6c"},
|
||||
{file = "asyncpg-0.28.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f029c5adf08c47b10bcdc857001bbef551ae51c57b3110964844a9d79ca0f267"},
|
||||
{file = "asyncpg-0.28.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ad1d6abf6c2f5152f46fff06b0e74f25800ce8ec6c80967f0bc789974de3c652"},
|
||||
{file = "asyncpg-0.28.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d7fa81ada2807bc50fea1dc741b26a4e99258825ba55913b0ddbf199a10d69d8"},
|
||||
{file = "asyncpg-0.28.0-cp311-cp311-win32.whl", hash = "sha256:f33c5685e97821533df3ada9384e7784bd1e7865d2b22f153f2e4bd4a083e102"},
|
||||
{file = "asyncpg-0.28.0-cp311-cp311-win_amd64.whl", hash = "sha256:5e7337c98fb493079d686a4a6965e8bcb059b8e1b8ec42106322fc6c1c889bb0"},
|
||||
{file = "asyncpg-0.28.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:1c56092465e718a9fdcc726cc3d9dcf3a692e4834031c9a9f871d92a75d20d48"},
|
||||
{file = "asyncpg-0.28.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4acd6830a7da0eb4426249d71353e8895b350daae2380cb26d11e0d4a01c5472"},
|
||||
{file = "asyncpg-0.28.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:63861bb4a540fa033a56db3bb58b0c128c56fad5d24e6d0a8c37cb29b17c1c7d"},
|
||||
{file = "asyncpg-0.28.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:a93a94ae777c70772073d0512f21c74ac82a8a49be3a1d982e3f259ab5f27307"},
|
||||
{file = "asyncpg-0.28.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:d14681110e51a9bc9c065c4e7944e8139076a778e56d6f6a306a26e740ed86d2"},
|
||||
{file = "asyncpg-0.28.0-cp37-cp37m-win32.whl", hash = "sha256:8aec08e7310f9ab322925ae5c768532e1d78cfb6440f63c078b8392a38aa636a"},
|
||||
{file = "asyncpg-0.28.0-cp37-cp37m-win_amd64.whl", hash = "sha256:319f5fa1ab0432bc91fb39b3960b0d591e6b5c7844dafc92c79e3f1bff96abef"},
|
||||
{file = "asyncpg-0.28.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b337ededaabc91c26bf577bfcd19b5508d879c0ad009722be5bb0a9dd30b85a0"},
|
||||
{file = "asyncpg-0.28.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4d32b680a9b16d2957a0a3cc6b7fa39068baba8e6b728f2e0a148a67644578f4"},
|
||||
{file = "asyncpg-0.28.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f4f62f04cdf38441a70f279505ef3b4eadf64479b17e707c950515846a2df197"},
|
||||
{file = "asyncpg-0.28.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f20cac332c2576c79c2e8e6464791c1f1628416d1115935a34ddd7121bfc6a4"},
|
||||
{file = "asyncpg-0.28.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:59f9712ce01e146ff71d95d561fb68bd2d588a35a187116ef05028675462d5ed"},
|
||||
{file = "asyncpg-0.28.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:fc9e9f9ff1aa0eddcc3247a180ac9e9b51a62311e988809ac6152e8fb8097756"},
|
||||
{file = "asyncpg-0.28.0-cp38-cp38-win32.whl", hash = "sha256:9e721dccd3838fcff66da98709ed884df1e30a95f6ba19f595a3706b4bc757e3"},
|
||||
{file = "asyncpg-0.28.0-cp38-cp38-win_amd64.whl", hash = "sha256:8ba7d06a0bea539e0487234511d4adf81dc8762249858ed2a580534e1720db00"},
|
||||
{file = "asyncpg-0.28.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d009b08602b8b18edef3a731f2ce6d3f57d8dac2a0a4140367e194eabd3de457"},
|
||||
{file = "asyncpg-0.28.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ec46a58d81446d580fb21b376ec6baecab7288ce5a578943e2fc7ab73bf7eb39"},
|
||||
{file = "asyncpg-0.28.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7b48ceed606cce9e64fd5480a9b0b9a95cea2b798bb95129687abd8599c8b019"},
|
||||
{file = "asyncpg-0.28.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8858f713810f4fe67876728680f42e93b7e7d5c7b61cf2118ef9153ec16b9423"},
|
||||
{file = "asyncpg-0.28.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:5e18438a0730d1c0c1715016eacda6e9a505fc5aa931b37c97d928d44941b4bf"},
|
||||
{file = "asyncpg-0.28.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:e9c433f6fcdd61c21a715ee9128a3ca48be8ac16fa07be69262f016bb0f4dbd2"},
|
||||
{file = "asyncpg-0.28.0-cp39-cp39-win32.whl", hash = "sha256:41e97248d9076bc8e4849da9e33e051be7ba37cd507cbd51dfe4b2d99c70e3dc"},
|
||||
{file = "asyncpg-0.28.0-cp39-cp39-win_amd64.whl", hash = "sha256:3ed77f00c6aacfe9d79e9eff9e21729ce92a4b38e80ea99a58ed382f42ebd55b"},
|
||||
{file = "asyncpg-0.28.0.tar.gz", hash = "sha256:7252cdc3acb2f52feaa3664280d3bcd78a46bd6c10bfd681acfffefa1120e278"},
|
||||
]
|
||||
cffi = [
|
||||
{file = "cffi-1.15.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:a66d3508133af6e8548451b25058d5812812ec3798c886bf38ed24a98216fab2"},
|
||||
{file = "cffi-1.15.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:470c103ae716238bbe698d67ad020e1db9d9dba34fa5a899b5e21577e6d52ed2"},
|
||||
{file = "cffi-1.15.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:9ad5db27f9cabae298d151c85cf2bad1d359a1b9c686a275df03385758e2f914"},
|
||||
{file = "cffi-1.15.1-cp27-cp27m-win32.whl", hash = "sha256:b3bbeb01c2b273cca1e1e0c5df57f12dce9a4dd331b4fa1635b8bec26350bde3"},
|
||||
{file = "cffi-1.15.1-cp27-cp27m-win_amd64.whl", hash = "sha256:e00b098126fd45523dd056d2efba6c5a63b71ffe9f2bbe1a4fe1716e1d0c331e"},
|
||||
{file = "cffi-1.15.1-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:d61f4695e6c866a23a21acab0509af1cdfd2c013cf256bbf5b6b5e2695827162"},
|
||||
{file = "cffi-1.15.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:ed9cb427ba5504c1dc15ede7d516b84757c3e3d7868ccc85121d9310d27eed0b"},
|
||||
{file = "cffi-1.15.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:39d39875251ca8f612b6f33e6b1195af86d1b3e60086068be9cc053aa4376e21"},
|
||||
{file = "cffi-1.15.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:285d29981935eb726a4399badae8f0ffdff4f5050eaa6d0cfc3f64b857b77185"},
|
||||
{file = "cffi-1.15.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3eb6971dcff08619f8d91607cfc726518b6fa2a9eba42856be181c6d0d9515fd"},
|
||||
{file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:21157295583fe8943475029ed5abdcf71eb3911894724e360acff1d61c1d54bc"},
|
||||
{file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5635bd9cb9731e6d4a1132a498dd34f764034a8ce60cef4f5319c0541159392f"},
|
||||
{file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2012c72d854c2d03e45d06ae57f40d78e5770d252f195b93f581acf3ba44496e"},
|
||||
{file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd86c085fae2efd48ac91dd7ccffcfc0571387fe1193d33b6394db7ef31fe2a4"},
|
||||
{file = "cffi-1.15.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:fa6693661a4c91757f4412306191b6dc88c1703f780c8234035eac011922bc01"},
|
||||
{file = "cffi-1.15.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:59c0b02d0a6c384d453fece7566d1c7e6b7bae4fc5874ef2ef46d56776d61c9e"},
|
||||
{file = "cffi-1.15.1-cp310-cp310-win32.whl", hash = "sha256:cba9d6b9a7d64d4bd46167096fc9d2f835e25d7e4c121fb2ddfc6528fb0413b2"},
|
||||
{file = "cffi-1.15.1-cp310-cp310-win_amd64.whl", hash = "sha256:ce4bcc037df4fc5e3d184794f27bdaab018943698f4ca31630bc7f84a7b69c6d"},
|
||||
{file = "cffi-1.15.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3d08afd128ddaa624a48cf2b859afef385b720bb4b43df214f85616922e6a5ac"},
|
||||
{file = "cffi-1.15.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3799aecf2e17cf585d977b780ce79ff0dc9b78d799fc694221ce814c2c19db83"},
|
||||
{file = "cffi-1.15.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a591fe9e525846e4d154205572a029f653ada1a78b93697f3b5a8f1f2bc055b9"},
|
||||
{file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3548db281cd7d2561c9ad9984681c95f7b0e38881201e157833a2342c30d5e8c"},
|
||||
{file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:91fc98adde3d7881af9b59ed0294046f3806221863722ba7d8d120c575314325"},
|
||||
{file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:94411f22c3985acaec6f83c6df553f2dbe17b698cc7f8ae751ff2237d96b9e3c"},
|
||||
{file = "cffi-1.15.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:03425bdae262c76aad70202debd780501fabeaca237cdfddc008987c0e0f59ef"},
|
||||
{file = "cffi-1.15.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:cc4d65aeeaa04136a12677d3dd0b1c0c94dc43abac5860ab33cceb42b801c1e8"},
|
||||
{file = "cffi-1.15.1-cp311-cp311-win32.whl", hash = "sha256:a0f100c8912c114ff53e1202d0078b425bee3649ae34d7b070e9697f93c5d52d"},
|
||||
{file = "cffi-1.15.1-cp311-cp311-win_amd64.whl", hash = "sha256:04ed324bda3cda42b9b695d51bb7d54b680b9719cfab04227cdd1e04e5de3104"},
|
||||
{file = "cffi-1.15.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50a74364d85fd319352182ef59c5c790484a336f6db772c1a9231f1c3ed0cbd7"},
|
||||
{file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e263d77ee3dd201c3a142934a086a4450861778baaeeb45db4591ef65550b0a6"},
|
||||
{file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cec7d9412a9102bdc577382c3929b337320c4c4c4849f2c5cdd14d7368c5562d"},
|
||||
{file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4289fc34b2f5316fbb762d75362931e351941fa95fa18789191b33fc4cf9504a"},
|
||||
{file = "cffi-1.15.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:173379135477dc8cac4bc58f45db08ab45d228b3363adb7af79436135d028405"},
|
||||
{file = "cffi-1.15.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:6975a3fac6bc83c4a65c9f9fcab9e47019a11d3d2cf7f3c0d03431bf145a941e"},
|
||||
{file = "cffi-1.15.1-cp36-cp36m-win32.whl", hash = "sha256:2470043b93ff09bf8fb1d46d1cb756ce6132c54826661a32d4e4d132e1977adf"},
|
||||
{file = "cffi-1.15.1-cp36-cp36m-win_amd64.whl", hash = "sha256:30d78fbc8ebf9c92c9b7823ee18eb92f2e6ef79b45ac84db507f52fbe3ec4497"},
|
||||
{file = "cffi-1.15.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:198caafb44239b60e252492445da556afafc7d1e3ab7a1fb3f0584ef6d742375"},
|
||||
{file = "cffi-1.15.1-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5ef34d190326c3b1f822a5b7a45f6c4535e2f47ed06fec77d3d799c450b2651e"},
|
||||
{file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8102eaf27e1e448db915d08afa8b41d6c7ca7a04b7d73af6514df10a3e74bd82"},
|
||||
{file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5df2768244d19ab7f60546d0c7c63ce1581f7af8b5de3eb3004b9b6fc8a9f84b"},
|
||||
{file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a8c4917bd7ad33e8eb21e9a5bbba979b49d9a97acb3a803092cbc1133e20343c"},
|
||||
{file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e2642fe3142e4cc4af0799748233ad6da94c62a8bec3a6648bf8ee68b1c7426"},
|
||||
{file = "cffi-1.15.1-cp37-cp37m-win32.whl", hash = "sha256:e229a521186c75c8ad9490854fd8bbdd9a0c9aa3a524326b55be83b54d4e0ad9"},
|
||||
{file = "cffi-1.15.1-cp37-cp37m-win_amd64.whl", hash = "sha256:a0b71b1b8fbf2b96e41c4d990244165e2c9be83d54962a9a1d118fd8657d2045"},
|
||||
{file = "cffi-1.15.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:320dab6e7cb2eacdf0e658569d2575c4dad258c0fcc794f46215e1e39f90f2c3"},
|
||||
{file = "cffi-1.15.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e74c6b51a9ed6589199c787bf5f9875612ca4a8a0785fb2d4a84429badaf22a"},
|
||||
{file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5c84c68147988265e60416b57fc83425a78058853509c1b0629c180094904a5"},
|
||||
{file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3b926aa83d1edb5aa5b427b4053dc420ec295a08e40911296b9eb1b6170f6cca"},
|
||||
{file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:87c450779d0914f2861b8526e035c5e6da0a3199d8f1add1a665e1cbc6fc6d02"},
|
||||
{file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f2c9f67e9821cad2e5f480bc8d83b8742896f1242dba247911072d4fa94c192"},
|
||||
{file = "cffi-1.15.1-cp38-cp38-win32.whl", hash = "sha256:8b7ee99e510d7b66cdb6c593f21c043c248537a32e0bedf02e01e9553a172314"},
|
||||
{file = "cffi-1.15.1-cp38-cp38-win_amd64.whl", hash = "sha256:00a9ed42e88df81ffae7a8ab6d9356b371399b91dbdf0c3cb1e84c03a13aceb5"},
|
||||
{file = "cffi-1.15.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:54a2db7b78338edd780e7ef7f9f6c442500fb0d41a5a4ea24fff1c929d5af585"},
|
||||
{file = "cffi-1.15.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:fcd131dd944808b5bdb38e6f5b53013c5aa4f334c5cad0c72742f6eba4b73db0"},
|
||||
{file = "cffi-1.15.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7473e861101c9e72452f9bf8acb984947aa1661a7704553a9f6e4baa5ba64415"},
|
||||
{file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6c9a799e985904922a4d207a94eae35c78ebae90e128f0c4e521ce339396be9d"},
|
||||
{file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3bcde07039e586f91b45c88f8583ea7cf7a0770df3a1649627bf598332cb6984"},
|
||||
{file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:33ab79603146aace82c2427da5ca6e58f2b3f2fb5da893ceac0c42218a40be35"},
|
||||
{file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5d598b938678ebf3c67377cdd45e09d431369c3b1a5b331058c338e201f12b27"},
|
||||
{file = "cffi-1.15.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:db0fbb9c62743ce59a9ff687eb5f4afbe77e5e8403d6697f7446e5f609976f76"},
|
||||
{file = "cffi-1.15.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:98d85c6a2bef81588d9227dde12db8a7f47f639f4a17c9ae08e773aa9c697bf3"},
|
||||
{file = "cffi-1.15.1-cp39-cp39-win32.whl", hash = "sha256:40f4774f5a9d4f5e344f31a32b5096977b5d48560c5592e2f3d2c4374bd543ee"},
|
||||
{file = "cffi-1.15.1-cp39-cp39-win_amd64.whl", hash = "sha256:70df4e3b545a17496c9b3f41f5115e69a4f2e77e94e1d2a8e1070bc0c38c8a3c"},
|
||||
{file = "cffi-1.15.1.tar.gz", hash = "sha256:d400bfb9a37b1351253cb402671cea7e89bdecc294e8016a707f6d1d8ac934f9"},
|
||||
]
|
||||
click = [
|
||||
{file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"},
|
||||
{file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"},
|
||||
]
|
||||
colorama = [
|
||||
{file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"},
|
||||
{file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"},
|
||||
]
|
||||
cryptography = [
|
||||
{file = "cryptography-41.0.3-cp37-abi3-macosx_10_12_universal2.whl", hash = "sha256:652627a055cb52a84f8c448185922241dd5217443ca194d5739b44612c5e6507"},
|
||||
{file = "cryptography-41.0.3-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:8f09daa483aedea50d249ef98ed500569841d6498aa9c9f4b0531b9964658922"},
|
||||
{file = "cryptography-41.0.3-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4fd871184321100fb400d759ad0cddddf284c4b696568204d281c902fc7b0d81"},
|
||||
{file = "cryptography-41.0.3-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:84537453d57f55a50a5b6835622ee405816999a7113267739a1b4581f83535bd"},
|
||||
{file = "cryptography-41.0.3-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:3fb248989b6363906827284cd20cca63bb1a757e0a2864d4c1682a985e3dca47"},
|
||||
{file = "cryptography-41.0.3-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:42cb413e01a5d36da9929baa9d70ca90d90b969269e5a12d39c1e0d475010116"},
|
||||
{file = "cryptography-41.0.3-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:aeb57c421b34af8f9fe830e1955bf493a86a7996cc1338fe41b30047d16e962c"},
|
||||
{file = "cryptography-41.0.3-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:6af1c6387c531cd364b72c28daa29232162010d952ceb7e5ca8e2827526aceae"},
|
||||
{file = "cryptography-41.0.3-cp37-abi3-win32.whl", hash = "sha256:0d09fb5356f975974dbcb595ad2d178305e5050656affb7890a1583f5e02a306"},
|
||||
{file = "cryptography-41.0.3-cp37-abi3-win_amd64.whl", hash = "sha256:a983e441a00a9d57a4d7c91b3116a37ae602907a7618b882c8013b5762e80574"},
|
||||
{file = "cryptography-41.0.3-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:5259cb659aa43005eb55a0e4ff2c825ca111a0da1814202c64d28a985d33b087"},
|
||||
{file = "cryptography-41.0.3-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:67e120e9a577c64fe1f611e53b30b3e69744e5910ff3b6e97e935aeb96005858"},
|
||||
{file = "cryptography-41.0.3-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:7efe8041897fe7a50863e51b77789b657a133c75c3b094e51b5e4b5cec7bf906"},
|
||||
{file = "cryptography-41.0.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:ce785cf81a7bdade534297ef9e490ddff800d956625020ab2ec2780a556c313e"},
|
||||
{file = "cryptography-41.0.3-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:57a51b89f954f216a81c9d057bf1a24e2f36e764a1ca9a501a6964eb4a6800dd"},
|
||||
{file = "cryptography-41.0.3-pp38-pypy38_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:4c2f0d35703d61002a2bbdcf15548ebb701cfdd83cdc12471d2bae80878a4207"},
|
||||
{file = "cryptography-41.0.3-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:23c2d778cf829f7d0ae180600b17e9fceea3c2ef8b31a99e3c694cbbf3a24b84"},
|
||||
{file = "cryptography-41.0.3-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:95dd7f261bb76948b52a5330ba5202b91a26fbac13ad0e9fc8a3ac04752058c7"},
|
||||
{file = "cryptography-41.0.3-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:41d7aa7cdfded09b3d73a47f429c298e80796c8e825ddfadc84c8a7f12df212d"},
|
||||
{file = "cryptography-41.0.3-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:d0d651aa754ef58d75cec6edfbd21259d93810b73f6ec246436a21b7841908de"},
|
||||
{file = "cryptography-41.0.3-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:ab8de0d091acbf778f74286f4989cf3d1528336af1b59f3e5d2ebca8b5fe49e1"},
|
||||
{file = "cryptography-41.0.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:a74fbcdb2a0d46fe00504f571a2a540532f4c188e6ccf26f1f178480117b33c4"},
|
||||
{file = "cryptography-41.0.3.tar.gz", hash = "sha256:6d192741113ef5e30d89dcb5b956ef4e1578f304708701b8b73d38e3e1461f34"},
|
||||
]
|
||||
databases = [
|
||||
{file = "databases-0.8.0-py3-none-any.whl", hash = "sha256:0ceb7fd5c740d846e1f4f58c0256d780a6786841ec8e624a21f1eb1b51a9093d"},
|
||||
{file = "databases-0.8.0.tar.gz", hash = "sha256:6544d82e9926f233d694ec29cd018403444c7fb6e863af881a8304d1ff5cfb90"},
|
||||
]
|
||||
greenlet = [
|
||||
{file = "greenlet-2.0.2-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:bdfea8c661e80d3c1c99ad7c3ff74e6e87184895bbaca6ee8cc61209f8b9b85d"},
|
||||
{file = "greenlet-2.0.2-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:9d14b83fab60d5e8abe587d51c75b252bcc21683f24699ada8fb275d7712f5a9"},
|
||||
{file = "greenlet-2.0.2-cp27-cp27m-win32.whl", hash = "sha256:6c3acb79b0bfd4fe733dff8bc62695283b57949ebcca05ae5c129eb606ff2d74"},
|
||||
{file = "greenlet-2.0.2-cp27-cp27m-win_amd64.whl", hash = "sha256:283737e0da3f08bd637b5ad058507e578dd462db259f7f6e4c5c365ba4ee9343"},
|
||||
{file = "greenlet-2.0.2-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:d27ec7509b9c18b6d73f2f5ede2622441de812e7b1a80bbd446cb0633bd3d5ae"},
|
||||
{file = "greenlet-2.0.2-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:30bcf80dda7f15ac77ba5af2b961bdd9dbc77fd4ac6105cee85b0d0a5fcf74df"},
|
||||
{file = "greenlet-2.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:26fbfce90728d82bc9e6c38ea4d038cba20b7faf8a0ca53a9c07b67318d46088"},
|
||||
{file = "greenlet-2.0.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9190f09060ea4debddd24665d6804b995a9c122ef5917ab26e1566dcc712ceeb"},
|
||||
{file = "greenlet-2.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d75209eed723105f9596807495d58d10b3470fa6732dd6756595e89925ce2470"},
|
||||
{file = "greenlet-2.0.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:3a51c9751078733d88e013587b108f1b7a1fb106d402fb390740f002b6f6551a"},
|
||||
{file = "greenlet-2.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:76ae285c8104046b3a7f06b42f29c7b73f77683df18c49ab5af7983994c2dd91"},
|
||||
{file = "greenlet-2.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:2d4686f195e32d36b4d7cf2d166857dbd0ee9f3d20ae349b6bf8afc8485b3645"},
|
||||
{file = "greenlet-2.0.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:c4302695ad8027363e96311df24ee28978162cdcdd2006476c43970b384a244c"},
|
||||
{file = "greenlet-2.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c48f54ef8e05f04d6eff74b8233f6063cb1ed960243eacc474ee73a2ea8573ca"},
|
||||
{file = "greenlet-2.0.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a1846f1b999e78e13837c93c778dcfc3365902cfb8d1bdb7dd73ead37059f0d0"},
|
||||
{file = "greenlet-2.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3a06ad5312349fec0ab944664b01d26f8d1f05009566339ac6f63f56589bc1a2"},
|
||||
{file = "greenlet-2.0.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:eff4eb9b7eb3e4d0cae3d28c283dc16d9bed6b193c2e1ace3ed86ce48ea8df19"},
|
||||
{file = "greenlet-2.0.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:5454276c07d27a740c5892f4907c86327b632127dd9abec42ee62e12427ff7e3"},
|
||||
{file = "greenlet-2.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:7cafd1208fdbe93b67c7086876f061f660cfddc44f404279c1585bbf3cdc64c5"},
|
||||
{file = "greenlet-2.0.2-cp35-cp35m-macosx_10_14_x86_64.whl", hash = "sha256:910841381caba4f744a44bf81bfd573c94e10b3045ee00de0cbf436fe50673a6"},
|
||||
{file = "greenlet-2.0.2-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:18a7f18b82b52ee85322d7a7874e676f34ab319b9f8cce5de06067384aa8ff43"},
|
||||
{file = "greenlet-2.0.2-cp35-cp35m-win32.whl", hash = "sha256:03a8f4f3430c3b3ff8d10a2a86028c660355ab637cee9333d63d66b56f09d52a"},
|
||||
{file = "greenlet-2.0.2-cp35-cp35m-win_amd64.whl", hash = "sha256:4b58adb399c4d61d912c4c331984d60eb66565175cdf4a34792cd9600f21b394"},
|
||||
{file = "greenlet-2.0.2-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:703f18f3fda276b9a916f0934d2fb6d989bf0b4fb5a64825260eb9bfd52d78f0"},
|
||||
{file = "greenlet-2.0.2-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:32e5b64b148966d9cccc2c8d35a671409e45f195864560829f395a54226408d3"},
|
||||
{file = "greenlet-2.0.2-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2dd11f291565a81d71dab10b7033395b7a3a5456e637cf997a6f33ebdf06f8db"},
|
||||
{file = "greenlet-2.0.2-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e0f72c9ddb8cd28532185f54cc1453f2c16fb417a08b53a855c4e6a418edd099"},
|
||||
{file = "greenlet-2.0.2-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cd021c754b162c0fb55ad5d6b9d960db667faad0fa2ff25bb6e1301b0b6e6a75"},
|
||||
{file = "greenlet-2.0.2-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:3c9b12575734155d0c09d6c3e10dbd81665d5c18e1a7c6597df72fd05990c8cf"},
|
||||
{file = "greenlet-2.0.2-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:b9ec052b06a0524f0e35bd8790686a1da006bd911dd1ef7d50b77bfbad74e292"},
|
||||
{file = "greenlet-2.0.2-cp36-cp36m-win32.whl", hash = "sha256:dbfcfc0218093a19c252ca8eb9aee3d29cfdcb586df21049b9d777fd32c14fd9"},
|
||||
{file = "greenlet-2.0.2-cp36-cp36m-win_amd64.whl", hash = "sha256:9f35ec95538f50292f6d8f2c9c9f8a3c6540bbfec21c9e5b4b751e0a7c20864f"},
|
||||
{file = "greenlet-2.0.2-cp37-cp37m-macosx_10_15_x86_64.whl", hash = "sha256:d5508f0b173e6aa47273bdc0a0b5ba055b59662ba7c7ee5119528f466585526b"},
|
||||
{file = "greenlet-2.0.2-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:f82d4d717d8ef19188687aa32b8363e96062911e63ba22a0cff7802a8e58e5f1"},
|
||||
{file = "greenlet-2.0.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c9c59a2120b55788e800d82dfa99b9e156ff8f2227f07c5e3012a45a399620b7"},
|
||||
{file = "greenlet-2.0.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2780572ec463d44c1d3ae850239508dbeb9fed38e294c68d19a24d925d9223ca"},
|
||||
{file = "greenlet-2.0.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:937e9020b514ceedb9c830c55d5c9872abc90f4b5862f89c0887033ae33c6f73"},
|
||||
{file = "greenlet-2.0.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:36abbf031e1c0f79dd5d596bfaf8e921c41df2bdf54ee1eed921ce1f52999a86"},
|
||||
{file = "greenlet-2.0.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:18e98fb3de7dba1c0a852731c3070cf022d14f0d68b4c87a19cc1016f3bb8b33"},
|
||||
{file = "greenlet-2.0.2-cp37-cp37m-win32.whl", hash = "sha256:3f6ea9bd35eb450837a3d80e77b517ea5bc56b4647f5502cd28de13675ee12f7"},
|
||||
{file = "greenlet-2.0.2-cp37-cp37m-win_amd64.whl", hash = "sha256:7492e2b7bd7c9b9916388d9df23fa49d9b88ac0640db0a5b4ecc2b653bf451e3"},
|
||||
{file = "greenlet-2.0.2-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:b864ba53912b6c3ab6bcb2beb19f19edd01a6bfcbdfe1f37ddd1778abfe75a30"},
|
||||
{file = "greenlet-2.0.2-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:ba2956617f1c42598a308a84c6cf021a90ff3862eddafd20c3333d50f0edb45b"},
|
||||
{file = "greenlet-2.0.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fc3a569657468b6f3fb60587e48356fe512c1754ca05a564f11366ac9e306526"},
|
||||
{file = "greenlet-2.0.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8eab883b3b2a38cc1e050819ef06a7e6344d4a990d24d45bc6f2cf959045a45b"},
|
||||
{file = "greenlet-2.0.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:acd2162a36d3de67ee896c43effcd5ee3de247eb00354db411feb025aa319857"},
|
||||
{file = "greenlet-2.0.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:0bf60faf0bc2468089bdc5edd10555bab6e85152191df713e2ab1fcc86382b5a"},
|
||||
{file = "greenlet-2.0.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b0ef99cdbe2b682b9ccbb964743a6aca37905fda5e0452e5ee239b1654d37f2a"},
|
||||
{file = "greenlet-2.0.2-cp38-cp38-win32.whl", hash = "sha256:b80f600eddddce72320dbbc8e3784d16bd3fb7b517e82476d8da921f27d4b249"},
|
||||
{file = "greenlet-2.0.2-cp38-cp38-win_amd64.whl", hash = "sha256:4d2e11331fc0c02b6e84b0d28ece3a36e0548ee1a1ce9ddde03752d9b79bba40"},
|
||||
{file = "greenlet-2.0.2-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:88d9ab96491d38a5ab7c56dd7a3cc37d83336ecc564e4e8816dbed12e5aaefc8"},
|
||||
{file = "greenlet-2.0.2-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:561091a7be172ab497a3527602d467e2b3fbe75f9e783d8b8ce403fa414f71a6"},
|
||||
{file = "greenlet-2.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:971ce5e14dc5e73715755d0ca2975ac88cfdaefcaab078a284fea6cfabf866df"},
|
||||
{file = "greenlet-2.0.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:be4ed120b52ae4d974aa40215fcdfde9194d63541c7ded40ee12eb4dda57b76b"},
|
||||
{file = "greenlet-2.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:94c817e84245513926588caf1152e3b559ff794d505555211ca041f032abbb6b"},
|
||||
{file = "greenlet-2.0.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:1a819eef4b0e0b96bb0d98d797bef17dc1b4a10e8d7446be32d1da33e095dbb8"},
|
||||
{file = "greenlet-2.0.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:7efde645ca1cc441d6dc4b48c0f7101e8d86b54c8530141b09fd31cef5149ec9"},
|
||||
{file = "greenlet-2.0.2-cp39-cp39-win32.whl", hash = "sha256:ea9872c80c132f4663822dd2a08d404073a5a9b5ba6155bea72fb2a79d1093b5"},
|
||||
{file = "greenlet-2.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:db1a39669102a1d8d12b57de2bb7e2ec9066a6f2b3da35ae511ff93b01b5d564"},
|
||||
{file = "greenlet-2.0.2.tar.gz", hash = "sha256:e7c8dc13af7db097bed64a051d2dd49e9f0af495c26995c00a9ee842690d34c0"},
|
||||
]
|
||||
grpcio = [
|
||||
{file = "grpcio-1.57.0-cp310-cp310-linux_armv7l.whl", hash = "sha256:092fa155b945015754bdf988be47793c377b52b88d546e45c6a9f9579ac7f7b6"},
|
||||
{file = "grpcio-1.57.0-cp310-cp310-macosx_12_0_universal2.whl", hash = "sha256:2f7349786da979a94690cc5c2b804cab4e8774a3cf59be40d037c4342c906649"},
|
||||
{file = "grpcio-1.57.0-cp310-cp310-manylinux_2_17_aarch64.whl", hash = "sha256:82640e57fb86ea1d71ea9ab54f7e942502cf98a429a200b2e743d8672171734f"},
|
||||
{file = "grpcio-1.57.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:40b72effd4c789de94ce1be2b5f88d7b9b5f7379fe9645f198854112a6567d9a"},
|
||||
{file = "grpcio-1.57.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2f708a6a17868ad8bf586598bee69abded4996b18adf26fd2d91191383b79019"},
|
||||
{file = "grpcio-1.57.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:60fe15288a0a65d5c1cb5b4a62b1850d07336e3ba728257a810317be14f0c527"},
|
||||
{file = "grpcio-1.57.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6907b1cf8bb29b058081d2aad677b15757a44ef2d4d8d9130271d2ad5e33efca"},
|
||||
{file = "grpcio-1.57.0-cp310-cp310-win32.whl", hash = "sha256:57b183e8b252825c4dd29114d6c13559be95387aafc10a7be645462a0fc98bbb"},
|
||||
{file = "grpcio-1.57.0-cp310-cp310-win_amd64.whl", hash = "sha256:7b400807fa749a9eb286e2cd893e501b110b4d356a218426cb9c825a0474ca56"},
|
||||
{file = "grpcio-1.57.0-cp311-cp311-linux_armv7l.whl", hash = "sha256:c6ebecfb7a31385393203eb04ed8b6a08f5002f53df3d59e5e795edb80999652"},
|
||||
{file = "grpcio-1.57.0-cp311-cp311-macosx_10_10_universal2.whl", hash = "sha256:00258cbe3f5188629828363ae8ff78477ce976a6f63fb2bb5e90088396faa82e"},
|
||||
{file = "grpcio-1.57.0-cp311-cp311-manylinux_2_17_aarch64.whl", hash = "sha256:23e7d8849a0e58b806253fd206ac105b328171e01b8f18c7d5922274958cc87e"},
|
||||
{file = "grpcio-1.57.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5371bcd861e679d63b8274f73ac281751d34bd54eccdbfcd6aa00e692a82cd7b"},
|
||||
{file = "grpcio-1.57.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aed90d93b731929e742967e236f842a4a2174dc5db077c8f9ad2c5996f89f63e"},
|
||||
{file = "grpcio-1.57.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:fe752639919aad9ffb0dee0d87f29a6467d1ef764f13c4644d212a9a853a078d"},
|
||||
{file = "grpcio-1.57.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fada6b07ec4f0befe05218181f4b85176f11d531911b64c715d1875c4736d73a"},
|
||||
{file = "grpcio-1.57.0-cp311-cp311-win32.whl", hash = "sha256:bb396952cfa7ad2f01061fbc7dc1ad91dd9d69243bcb8110cf4e36924785a0fe"},
|
||||
{file = "grpcio-1.57.0-cp311-cp311-win_amd64.whl", hash = "sha256:e503cb45ed12b924b5b988ba9576dc9949b2f5283b8e33b21dcb6be74a7c58d0"},
|
||||
{file = "grpcio-1.57.0-cp37-cp37m-linux_armv7l.whl", hash = "sha256:fd173b4cf02b20f60860dc2ffe30115c18972d7d6d2d69df97ac38dee03be5bf"},
|
||||
{file = "grpcio-1.57.0-cp37-cp37m-macosx_10_10_universal2.whl", hash = "sha256:d7f8df114d6b4cf5a916b98389aeaf1e3132035420a88beea4e3d977e5f267a5"},
|
||||
{file = "grpcio-1.57.0-cp37-cp37m-manylinux_2_17_aarch64.whl", hash = "sha256:76c44efa4ede1f42a9d5b2fed1fe9377e73a109bef8675fb0728eb80b0b8e8f2"},
|
||||
{file = "grpcio-1.57.0-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4faea2cfdf762a664ab90589b66f416274887641ae17817de510b8178356bf73"},
|
||||
{file = "grpcio-1.57.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c60b83c43faeb6d0a9831f0351d7787a0753f5087cc6fa218d78fdf38e5acef0"},
|
||||
{file = "grpcio-1.57.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:b363bbb5253e5f9c23d8a0a034dfdf1b7c9e7f12e602fc788c435171e96daccc"},
|
||||
{file = "grpcio-1.57.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:f1fb0fd4a1e9b11ac21c30c169d169ef434c6e9344ee0ab27cfa6f605f6387b2"},
|
||||
{file = "grpcio-1.57.0-cp37-cp37m-win_amd64.whl", hash = "sha256:34950353539e7d93f61c6796a007c705d663f3be41166358e3d88c45760c7d98"},
|
||||
{file = "grpcio-1.57.0-cp38-cp38-linux_armv7l.whl", hash = "sha256:871f9999e0211f9551f368612460442a5436d9444606184652117d6a688c9f51"},
|
||||
{file = "grpcio-1.57.0-cp38-cp38-macosx_10_10_universal2.whl", hash = "sha256:a8a8e560e8dbbdf29288872e91efd22af71e88b0e5736b0daf7773c1fecd99f0"},
|
||||
{file = "grpcio-1.57.0-cp38-cp38-manylinux_2_17_aarch64.whl", hash = "sha256:2313b124e475aa9017a9844bdc5eafb2d5abdda9d456af16fc4535408c7d6da6"},
|
||||
{file = "grpcio-1.57.0-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b4098b6b638d9e0ca839a81656a2fd4bc26c9486ea707e8b1437d6f9d61c3941"},
|
||||
{file = "grpcio-1.57.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5e5b58e32ae14658085c16986d11e99abd002ddbf51c8daae8a0671fffb3467f"},
|
||||
{file = "grpcio-1.57.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:0f80bf37f09e1caba6a8063e56e2b87fa335add314cf2b78ebf7cb45aa7e3d06"},
|
||||
{file = "grpcio-1.57.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:5b7a4ce8f862fe32b2a10b57752cf3169f5fe2915acfe7e6a1e155db3da99e79"},
|
||||
{file = "grpcio-1.57.0-cp38-cp38-win32.whl", hash = "sha256:9338bacf172e942e62e5889b6364e56657fbf8ac68062e8b25c48843e7b202bb"},
|
||||
{file = "grpcio-1.57.0-cp38-cp38-win_amd64.whl", hash = "sha256:e1cb52fa2d67d7f7fab310b600f22ce1ff04d562d46e9e0ac3e3403c2bb4cc16"},
|
||||
{file = "grpcio-1.57.0-cp39-cp39-linux_armv7l.whl", hash = "sha256:fee387d2fab144e8a34e0e9c5ca0f45c9376b99de45628265cfa9886b1dbe62b"},
|
||||
{file = "grpcio-1.57.0-cp39-cp39-macosx_10_10_universal2.whl", hash = "sha256:b53333627283e7241fcc217323f225c37783b5f0472316edcaa4479a213abfa6"},
|
||||
{file = "grpcio-1.57.0-cp39-cp39-manylinux_2_17_aarch64.whl", hash = "sha256:f19ac6ac0a256cf77d3cc926ef0b4e64a9725cc612f97228cd5dc4bd9dbab03b"},
|
||||
{file = "grpcio-1.57.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e3fdf04e402f12e1de8074458549337febb3b45f21076cc02ef4ff786aff687e"},
|
||||
{file = "grpcio-1.57.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5613a2fecc82f95d6c51d15b9a72705553aa0d7c932fad7aed7afb51dc982ee5"},
|
||||
{file = "grpcio-1.57.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:b670c2faa92124b7397b42303e4d8eb64a4cd0b7a77e35a9e865a55d61c57ef9"},
|
||||
{file = "grpcio-1.57.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:7a635589201b18510ff988161b7b573f50c6a48fae9cb567657920ca82022b37"},
|
||||
{file = "grpcio-1.57.0-cp39-cp39-win32.whl", hash = "sha256:d78d8b86fcdfa1e4c21f8896614b6cc7ee01a2a758ec0c4382d662f2a62cf766"},
|
||||
{file = "grpcio-1.57.0-cp39-cp39-win_amd64.whl", hash = "sha256:20ec6fc4ad47d1b6e12deec5045ec3cd5402d9a1597f738263e98f490fe07056"},
|
||||
{file = "grpcio-1.57.0.tar.gz", hash = "sha256:4b089f7ad1eb00a104078bab8015b0ed0ebcb3b589e527ab009c53893fd4e613"},
|
||||
]
|
||||
grpcio-health-checking = [
|
||||
{file = "grpcio-health-checking-1.57.0.tar.gz", hash = "sha256:697fdae12d22646476e3e8bd9060ccf38ff132686107b308efebd5c704779f00"},
|
||||
{file = "grpcio_health_checking-1.57.0-py3-none-any.whl", hash = "sha256:c0cc3f6e7420c8aebbdb11d7b2304a946645b9ddf861f87b6238ac35ffa966a9"},
|
||||
]
|
||||
grpcio-tools = [
|
||||
{file = "grpcio-tools-1.57.0.tar.gz", hash = "sha256:2f16130d869ce27ecd623194547b649dd657333ec7e8644cc571c645781a9b85"},
|
||||
{file = "grpcio_tools-1.57.0-cp310-cp310-linux_armv7l.whl", hash = "sha256:4fb8a8468031f858381a576078924af364a08833d8f8f3237018252c4573a802"},
|
||||
{file = "grpcio_tools-1.57.0-cp310-cp310-macosx_12_0_universal2.whl", hash = "sha256:35bf0dad8a3562043345236c26d0053a856fb06c04d7da652f2ded914e508ae7"},
|
||||
{file = "grpcio_tools-1.57.0-cp310-cp310-manylinux_2_17_aarch64.whl", hash = "sha256:ec9aab2fb6783c7fc54bc28f58eb75f1ca77594e6b0fd5e5e7a8114a95169fe0"},
|
||||
{file = "grpcio_tools-1.57.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0cf5fc0a1c23f8ea34b408b72fb0e90eec0f404ad4dba98e8f6da3c9ce34e2ed"},
|
||||
{file = "grpcio_tools-1.57.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:26e69d08a515554e0cfe1ec4d31568836f4b17f0ff82294f957f629388629eb9"},
|
||||
{file = "grpcio_tools-1.57.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:c39a3656576b6fdaaf28abe0467f7a7231df4230c1bee132322dbc3209419e7f"},
|
||||
{file = "grpcio_tools-1.57.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:f64f8ab22d27d4a5693310748d35a696061c3b5c7b8c4fb4ab3b4bc1068b6b56"},
|
||||
{file = "grpcio_tools-1.57.0-cp310-cp310-win32.whl", hash = "sha256:d2a134756f4db34759a5cc7f7e43f7eb87540b68d1cca62925593c6fb93924f7"},
|
||||
{file = "grpcio_tools-1.57.0-cp310-cp310-win_amd64.whl", hash = "sha256:9a3d60fb8d46ede26c1907c146561b3a9caa20a7aff961bc661ef8226f85a2e9"},
|
||||
{file = "grpcio_tools-1.57.0-cp311-cp311-linux_armv7l.whl", hash = "sha256:aac98ecad8f7bd4301855669d42a5d97ef7bb34bec2b1e74c7a0641d47e313cf"},
|
||||
{file = "grpcio_tools-1.57.0-cp311-cp311-macosx_10_10_universal2.whl", hash = "sha256:cdd020cb68b51462983b7c2dfbc3eb6ede032b8bf438d4554df0c3f08ce35c76"},
|
||||
{file = "grpcio_tools-1.57.0-cp311-cp311-manylinux_2_17_aarch64.whl", hash = "sha256:f54081b08419a39221cd646363b5708857c696b3ad4784f1dcf310891e33a5f7"},
|
||||
{file = "grpcio_tools-1.57.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ed85a0291fff45b67f2557fe7f117d3bc7af8b54b8619d27bf374b5c8b7e3ca2"},
|
||||
{file = "grpcio_tools-1.57.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e868cd6feb3ef07d4b35be104fe1fd0657db05259ff8f8ec5e08f4f89ca1191d"},
|
||||
{file = "grpcio_tools-1.57.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:dfb6f6120587b8e228a3cae5ee4985b5bdc18501bad05c49df61965dfc9d70a9"},
|
||||
{file = "grpcio_tools-1.57.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:4a7ad7f328e28fc97c356d0f10fb10d8b5151bb65aa7cf14bf8084513f0b7306"},
|
||||
{file = "grpcio_tools-1.57.0-cp311-cp311-win32.whl", hash = "sha256:9867f2817b1a0c93c523f89ac6c9d8625548af4620a7ce438bf5a76e23327284"},
|
||||
{file = "grpcio_tools-1.57.0-cp311-cp311-win_amd64.whl", hash = "sha256:1f9e917a9f18087f6c14b4d4508fb94fca5c2f96852363a89232fb9b2124ac1f"},
|
||||
{file = "grpcio_tools-1.57.0-cp37-cp37m-linux_armv7l.whl", hash = "sha256:9f2aefa8a37bd2c4db1a3f1aca11377e2766214520fb70e67071f4ff8d8b0fa5"},
|
||||
{file = "grpcio_tools-1.57.0-cp37-cp37m-macosx_10_10_universal2.whl", hash = "sha256:850cbda0ec5d24c39e7215ede410276040692ca45d105fbbeada407fa03f0ac0"},
|
||||
{file = "grpcio_tools-1.57.0-cp37-cp37m-manylinux_2_17_aarch64.whl", hash = "sha256:6fa52972c9647876ea35f6dc2b51002a74ed900ec7894586cbb2fe76f64f99de"},
|
||||
{file = "grpcio_tools-1.57.0-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:76c0eea89d7542719594e50e2283f51a072978b953e8b3e9fd7c59a2c762d4c1"},
|
||||
{file = "grpcio_tools-1.57.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f3da5240211252fc70a6451fe00c143e2ab2f7bfc2445695ad2ed056b8e48d96"},
|
||||
{file = "grpcio_tools-1.57.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:a0256f8786ac9e4db618a1aa492bb3472569a0946fd3ee862ffe23196323da55"},
|
||||
{file = "grpcio_tools-1.57.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:c026bdf5c1366ce88b7bbe2d8207374d675afd3fd911f60752103de3da4a41d2"},
|
||||
{file = "grpcio_tools-1.57.0-cp37-cp37m-win_amd64.whl", hash = "sha256:9053c2f655589545be08b9d6a673e92970173a4bf11a4b9f18cd6e9af626b587"},
|
||||
{file = "grpcio_tools-1.57.0-cp38-cp38-linux_armv7l.whl", hash = "sha256:81ec4dbb696e095057b2528d11a8da04be6bbe2b967fa07d4ea9ba6354338cbf"},
|
||||
{file = "grpcio_tools-1.57.0-cp38-cp38-macosx_10_10_universal2.whl", hash = "sha256:495e2946406963e0b9f063f76d5af0f2a19517dac2b367b5b044432ac9194296"},
|
||||
{file = "grpcio_tools-1.57.0-cp38-cp38-manylinux_2_17_aarch64.whl", hash = "sha256:7b46fc6aa8eb7edd18cafcd21fd98703cb6c09e46b507de335fca7f0161dfccb"},
|
||||
{file = "grpcio_tools-1.57.0-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fb81ff861692111fa81bd85f64584e624cb4013bd66fbce8a209b8893f5ce398"},
|
||||
{file = "grpcio_tools-1.57.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8a42dc220eb5305f470855c9284f4c8e85ae59d6d742cd07946b0cbe5e9ca186"},
|
||||
{file = "grpcio_tools-1.57.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:90d10d9038ba46a595a223a34f136c9230e3d6d7abc2433dbf0e1c31939d3a8b"},
|
||||
{file = "grpcio_tools-1.57.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:5bc3e6d338aefb052e19cedabe00452be46d0c10a4ed29ee77abb00402e438fe"},
|
||||
{file = "grpcio_tools-1.57.0-cp38-cp38-win32.whl", hash = "sha256:34b36217b17b5bea674a414229913e1fd80ede328be51e1b531fcc62abd393b0"},
|
||||
{file = "grpcio_tools-1.57.0-cp38-cp38-win_amd64.whl", hash = "sha256:dbde4004a0688400036342ff73e3706e8940483e2871547b1354d59e93a38277"},
|
||||
{file = "grpcio_tools-1.57.0-cp39-cp39-linux_armv7l.whl", hash = "sha256:784574709b9690dc28696617ea69352e2132352fdfc9bc89afa8e39f99ae538e"},
|
||||
{file = "grpcio_tools-1.57.0-cp39-cp39-macosx_10_10_universal2.whl", hash = "sha256:85ac4e62eb44428cde025fd9ab7554002315fc7880f791c553fc5a0015cc9931"},
|
||||
{file = "grpcio_tools-1.57.0-cp39-cp39-manylinux_2_17_aarch64.whl", hash = "sha256:dc771d4db5701f280957bbcee91745e0686d00ed1c6aa7e05ba30a58b02d70a1"},
|
||||
{file = "grpcio_tools-1.57.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f3ac06703c412f8167a9062eaf6099409967e33bf98fa5b02be4b4689b6bdf39"},
|
||||
{file = "grpcio_tools-1.57.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:02d78c034109f46032c7217260066d49d41e6bcaf588fa28fa40fe2f83445347"},
|
||||
{file = "grpcio_tools-1.57.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:2db25f15ed44327f2e02d0c4fe741ac966f9500e407047d8a7c7fccf2df65616"},
|
||||
{file = "grpcio_tools-1.57.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:2b417c97936d94874a3ce7ed8deab910f2233e3612134507cfee4af8735c38a6"},
|
||||
{file = "grpcio_tools-1.57.0-cp39-cp39-win32.whl", hash = "sha256:f717cce5093e6b6049d9ea6d12fdf3658efdb1a80772f7737db1f8510b876df6"},
|
||||
{file = "grpcio_tools-1.57.0-cp39-cp39-win_amd64.whl", hash = "sha256:1c0e8a1a32973a5d59fbcc19232f925e5c48116e9411f788033a31c5ca5130b4"},
|
||||
]
|
||||
kafka-python = [
|
||||
{file = "kafka-python-2.0.2.tar.gz", hash = "sha256:04dfe7fea2b63726cd6f3e79a2d86e709d608d74406638c5da33a01d45a9d7e3"},
|
||||
{file = "kafka_python-2.0.2-py2.py3-none-any.whl", hash = "sha256:2d92418c7cb1c298fa6c7f0fb3519b520d0d7526ac6cb7ae2a4fc65a51a94b6e"},
|
||||
]
|
||||
packaging = [
|
||||
{file = "packaging-23.1-py3-none-any.whl", hash = "sha256:994793af429502c4ea2ebf6bf664629d07c1a9fe974af92966e4b8d2df7edc61"},
|
||||
{file = "packaging-23.1.tar.gz", hash = "sha256:a392980d2b6cffa644431898be54b0045151319d1e7ec34f0cfed48767dd334f"},
|
||||
]
|
||||
protobuf = [
|
||||
{file = "protobuf-4.24.2-cp310-abi3-win32.whl", hash = "sha256:58e12d2c1aa428ece2281cef09bbaa6938b083bcda606db3da4e02e991a0d924"},
|
||||
{file = "protobuf-4.24.2-cp310-abi3-win_amd64.whl", hash = "sha256:77700b55ba41144fc64828e02afb41901b42497b8217b558e4a001f18a85f2e3"},
|
||||
{file = "protobuf-4.24.2-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:237b9a50bd3b7307d0d834c1b0eb1a6cd47d3f4c2da840802cd03ea288ae8880"},
|
||||
{file = "protobuf-4.24.2-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:25ae91d21e3ce8d874211110c2f7edd6384816fb44e06b2867afe35139e1fd1c"},
|
||||
{file = "protobuf-4.24.2-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:c00c3c7eb9ad3833806e21e86dca448f46035242a680f81c3fe068ff65e79c74"},
|
||||
{file = "protobuf-4.24.2-cp37-cp37m-win32.whl", hash = "sha256:4e69965e7e54de4db989289a9b971a099e626f6167a9351e9d112221fc691bc1"},
|
||||
{file = "protobuf-4.24.2-cp37-cp37m-win_amd64.whl", hash = "sha256:c5cdd486af081bf752225b26809d2d0a85e575b80a84cde5172a05bbb1990099"},
|
||||
{file = "protobuf-4.24.2-cp38-cp38-win32.whl", hash = "sha256:6bd26c1fa9038b26c5c044ee77e0ecb18463e957fefbaeb81a3feb419313a54e"},
|
||||
{file = "protobuf-4.24.2-cp38-cp38-win_amd64.whl", hash = "sha256:bb7aa97c252279da65584af0456f802bd4b2de429eb945bbc9b3d61a42a8cd16"},
|
||||
{file = "protobuf-4.24.2-cp39-cp39-win32.whl", hash = "sha256:2b23bd6e06445699b12f525f3e92a916f2dcf45ffba441026357dea7fa46f42b"},
|
||||
{file = "protobuf-4.24.2-cp39-cp39-win_amd64.whl", hash = "sha256:839952e759fc40b5d46be319a265cf94920174d88de31657d5622b5d8d6be5cd"},
|
||||
{file = "protobuf-4.24.2-py3-none-any.whl", hash = "sha256:3b7b170d3491ceed33f723bbf2d5a260f8a4e23843799a3906f16ef736ef251e"},
|
||||
{file = "protobuf-4.24.2.tar.gz", hash = "sha256:7fda70797ddec31ddfa3576cbdcc3ddbb6b3078b737a1a87ab9136af0570cd6e"},
|
||||
]
|
||||
protoletariat = [
|
||||
{file = "protoletariat-3.2.19-py3-none-any.whl", hash = "sha256:4bed510011cb352b26998008167a5a7ae697fb49d76fe4848bffa27856feab35"},
|
||||
{file = "protoletariat-3.2.19.tar.gz", hash = "sha256:3c23aa88bcceadde5a589bf0c1dd91e08636309e5b3d115ddebb38f5b1873d53"},
|
||||
]
|
||||
pycparser = [
|
||||
{file = "pycparser-2.21-py2.py3-none-any.whl", hash = "sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9"},
|
||||
{file = "pycparser-2.21.tar.gz", hash = "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206"},
|
||||
]
|
||||
pydantic = [
|
||||
{file = "pydantic-2.3.0-py3-none-any.whl", hash = "sha256:45b5e446c6dfaad9444819a293b921a40e1db1aa61ea08aede0522529ce90e81"},
|
||||
{file = "pydantic-2.3.0.tar.gz", hash = "sha256:1607cc106602284cd4a00882986570472f193fde9cb1259bceeaedb26aa79a6d"},
|
||||
]
|
||||
pydantic-core = [
|
||||
{file = "pydantic_core-2.6.3-cp310-cp310-macosx_10_7_x86_64.whl", hash = "sha256:1a0ddaa723c48af27d19f27f1c73bdc615c73686d763388c8683fe34ae777bad"},
|
||||
{file = "pydantic_core-2.6.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5cfde4fab34dd1e3a3f7f3db38182ab6c95e4ea91cf322242ee0be5c2f7e3d2f"},
|
||||
{file = "pydantic_core-2.6.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5493a7027bfc6b108e17c3383959485087d5942e87eb62bbac69829eae9bc1f7"},
|
||||
{file = "pydantic_core-2.6.3-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:84e87c16f582f5c753b7f39a71bd6647255512191be2d2dbf49458c4ef024588"},
|
||||
{file = "pydantic_core-2.6.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:522a9c4a4d1924facce7270c84b5134c5cabcb01513213662a2e89cf28c1d309"},
|
||||
{file = "pydantic_core-2.6.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:aaafc776e5edc72b3cad1ccedb5fd869cc5c9a591f1213aa9eba31a781be9ac1"},
|
||||
{file = "pydantic_core-2.6.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3a750a83b2728299ca12e003d73d1264ad0440f60f4fc9cee54acc489249b728"},
|
||||
{file = "pydantic_core-2.6.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9e8b374ef41ad5c461efb7a140ce4730661aadf85958b5c6a3e9cf4e040ff4bb"},
|
||||
{file = "pydantic_core-2.6.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:b594b64e8568cf09ee5c9501ede37066b9fc41d83d58f55b9952e32141256acd"},
|
||||
{file = "pydantic_core-2.6.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:2a20c533cb80466c1d42a43a4521669ccad7cf2967830ac62c2c2f9cece63e7e"},
|
||||
{file = "pydantic_core-2.6.3-cp310-none-win32.whl", hash = "sha256:04fe5c0a43dec39aedba0ec9579001061d4653a9b53a1366b113aca4a3c05ca7"},
|
||||
{file = "pydantic_core-2.6.3-cp310-none-win_amd64.whl", hash = "sha256:6bf7d610ac8f0065a286002a23bcce241ea8248c71988bda538edcc90e0c39ad"},
|
||||
{file = "pydantic_core-2.6.3-cp311-cp311-macosx_10_7_x86_64.whl", hash = "sha256:6bcc1ad776fffe25ea5c187a028991c031a00ff92d012ca1cc4714087e575973"},
|
||||
{file = "pydantic_core-2.6.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:df14f6332834444b4a37685810216cc8fe1fe91f447332cd56294c984ecbff1c"},
|
||||
{file = "pydantic_core-2.6.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0b7486d85293f7f0bbc39b34e1d8aa26210b450bbd3d245ec3d732864009819"},
|
||||
{file = "pydantic_core-2.6.3-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a892b5b1871b301ce20d40b037ffbe33d1407a39639c2b05356acfef5536d26a"},
|
||||
{file = "pydantic_core-2.6.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:883daa467865e5766931e07eb20f3e8152324f0adf52658f4d302242c12e2c32"},
|
||||
{file = "pydantic_core-2.6.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d4eb77df2964b64ba190eee00b2312a1fd7a862af8918ec70fc2d6308f76ac64"},
|
||||
{file = "pydantic_core-2.6.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ce8c84051fa292a5dc54018a40e2a1926fd17980a9422c973e3ebea017aa8da"},
|
||||
{file = "pydantic_core-2.6.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:22134a4453bd59b7d1e895c455fe277af9d9d9fbbcb9dc3f4a97b8693e7e2c9b"},
|
||||
{file = "pydantic_core-2.6.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:02e1c385095efbd997311d85c6021d32369675c09bcbfff3b69d84e59dc103f6"},
|
||||
{file = "pydantic_core-2.6.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d79f1f2f7ebdb9b741296b69049ff44aedd95976bfee38eb4848820628a99b50"},
|
||||
{file = "pydantic_core-2.6.3-cp311-none-win32.whl", hash = "sha256:430ddd965ffd068dd70ef4e4d74f2c489c3a313adc28e829dd7262cc0d2dd1e8"},
|
||||
{file = "pydantic_core-2.6.3-cp311-none-win_amd64.whl", hash = "sha256:84f8bb34fe76c68c9d96b77c60cef093f5e660ef8e43a6cbfcd991017d375950"},
|
||||
{file = "pydantic_core-2.6.3-cp311-none-win_arm64.whl", hash = "sha256:5a2a3c9ef904dcdadb550eedf3291ec3f229431b0084666e2c2aa8ff99a103a2"},
|
||||
{file = "pydantic_core-2.6.3-cp312-cp312-macosx_10_7_x86_64.whl", hash = "sha256:8421cf496e746cf8d6b677502ed9a0d1e4e956586cd8b221e1312e0841c002d5"},
|
||||
{file = "pydantic_core-2.6.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:bb128c30cf1df0ab78166ded1ecf876620fb9aac84d2413e8ea1594b588c735d"},
|
||||
{file = "pydantic_core-2.6.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:37a822f630712817b6ecc09ccc378192ef5ff12e2c9bae97eb5968a6cdf3b862"},
|
||||
{file = "pydantic_core-2.6.3-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:240a015102a0c0cc8114f1cba6444499a8a4d0333e178bc504a5c2196defd456"},
|
||||
{file = "pydantic_core-2.6.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3f90e5e3afb11268628c89f378f7a1ea3f2fe502a28af4192e30a6cdea1e7d5e"},
|
||||
{file = "pydantic_core-2.6.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:340e96c08de1069f3d022a85c2a8c63529fd88709468373b418f4cf2c949fb0e"},
|
||||
{file = "pydantic_core-2.6.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1480fa4682e8202b560dcdc9eeec1005f62a15742b813c88cdc01d44e85308e5"},
|
||||
{file = "pydantic_core-2.6.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f14546403c2a1d11a130b537dda28f07eb6c1805a43dae4617448074fd49c282"},
|
||||
{file = "pydantic_core-2.6.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:a87c54e72aa2ef30189dc74427421e074ab4561cf2bf314589f6af5b37f45e6d"},
|
||||
{file = "pydantic_core-2.6.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:f93255b3e4d64785554e544c1c76cd32f4a354fa79e2eeca5d16ac2e7fdd57aa"},
|
||||
{file = "pydantic_core-2.6.3-cp312-none-win32.whl", hash = "sha256:f70dc00a91311a1aea124e5f64569ea44c011b58433981313202c46bccbec0e1"},
|
||||
{file = "pydantic_core-2.6.3-cp312-none-win_amd64.whl", hash = "sha256:23470a23614c701b37252618e7851e595060a96a23016f9a084f3f92f5ed5881"},
|
||||
{file = "pydantic_core-2.6.3-cp312-none-win_arm64.whl", hash = "sha256:1ac1750df1b4339b543531ce793b8fd5c16660a95d13aecaab26b44ce11775e9"},
|
||||
{file = "pydantic_core-2.6.3-cp37-cp37m-macosx_10_7_x86_64.whl", hash = "sha256:a53e3195f134bde03620d87a7e2b2f2046e0e5a8195e66d0f244d6d5b2f6d31b"},
|
||||
{file = "pydantic_core-2.6.3-cp37-cp37m-macosx_11_0_arm64.whl", hash = "sha256:f2969e8f72c6236c51f91fbb79c33821d12a811e2a94b7aa59c65f8dbdfad34a"},
|
||||
{file = "pydantic_core-2.6.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:672174480a85386dd2e681cadd7d951471ad0bb028ed744c895f11f9d51b9ebe"},
|
||||
{file = "pydantic_core-2.6.3-cp37-cp37m-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:002d0ea50e17ed982c2d65b480bd975fc41086a5a2f9c924ef8fc54419d1dea3"},
|
||||
{file = "pydantic_core-2.6.3-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3ccc13afee44b9006a73d2046068d4df96dc5b333bf3509d9a06d1b42db6d8bf"},
|
||||
{file = "pydantic_core-2.6.3-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:439a0de139556745ae53f9cc9668c6c2053444af940d3ef3ecad95b079bc9987"},
|
||||
{file = "pydantic_core-2.6.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d63b7545d489422d417a0cae6f9898618669608750fc5e62156957e609e728a5"},
|
||||
{file = "pydantic_core-2.6.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b44c42edc07a50a081672e25dfe6022554b47f91e793066a7b601ca290f71e42"},
|
||||
{file = "pydantic_core-2.6.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:1c721bfc575d57305dd922e6a40a8fe3f762905851d694245807a351ad255c58"},
|
||||
{file = "pydantic_core-2.6.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:5e4a2cf8c4543f37f5dc881de6c190de08096c53986381daebb56a355be5dfe6"},
|
||||
{file = "pydantic_core-2.6.3-cp37-none-win32.whl", hash = "sha256:d9b4916b21931b08096efed090327f8fe78e09ae8f5ad44e07f5c72a7eedb51b"},
|
||||
{file = "pydantic_core-2.6.3-cp37-none-win_amd64.whl", hash = "sha256:a8acc9dedd304da161eb071cc7ff1326aa5b66aadec9622b2574ad3ffe225525"},
|
||||
{file = "pydantic_core-2.6.3-cp38-cp38-macosx_10_7_x86_64.whl", hash = "sha256:5e9c068f36b9f396399d43bfb6defd4cc99c36215f6ff33ac8b9c14ba15bdf6b"},
|
||||
{file = "pydantic_core-2.6.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:e61eae9b31799c32c5f9b7be906be3380e699e74b2db26c227c50a5fc7988698"},
|
||||
{file = "pydantic_core-2.6.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d85463560c67fc65cd86153a4975d0b720b6d7725cf7ee0b2d291288433fc21b"},
|
||||
{file = "pydantic_core-2.6.3-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9616567800bdc83ce136e5847d41008a1d602213d024207b0ff6cab6753fe645"},
|
||||
{file = "pydantic_core-2.6.3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9e9b65a55bbabda7fccd3500192a79f6e474d8d36e78d1685496aad5f9dbd92c"},
|
||||
{file = "pydantic_core-2.6.3-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f468d520f47807d1eb5d27648393519655eadc578d5dd862d06873cce04c4d1b"},
|
||||
{file = "pydantic_core-2.6.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9680dd23055dd874173a3a63a44e7f5a13885a4cfd7e84814be71be24fba83db"},
|
||||
{file = "pydantic_core-2.6.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9a718d56c4d55efcfc63f680f207c9f19c8376e5a8a67773535e6f7e80e93170"},
|
||||
{file = "pydantic_core-2.6.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:8ecbac050856eb6c3046dea655b39216597e373aa8e50e134c0e202f9c47efec"},
|
||||
{file = "pydantic_core-2.6.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:788be9844a6e5c4612b74512a76b2153f1877cd845410d756841f6c3420230eb"},
|
||||
{file = "pydantic_core-2.6.3-cp38-none-win32.whl", hash = "sha256:07a1aec07333bf5adebd8264047d3dc518563d92aca6f2f5b36f505132399efc"},
|
||||
{file = "pydantic_core-2.6.3-cp38-none-win_amd64.whl", hash = "sha256:621afe25cc2b3c4ba05fff53525156d5100eb35c6e5a7cf31d66cc9e1963e378"},
|
||||
{file = "pydantic_core-2.6.3-cp39-cp39-macosx_10_7_x86_64.whl", hash = "sha256:813aab5bfb19c98ae370952b6f7190f1e28e565909bfc219a0909db168783465"},
|
||||
{file = "pydantic_core-2.6.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:50555ba3cb58f9861b7a48c493636b996a617db1a72c18da4d7f16d7b1b9952b"},
|
||||
{file = "pydantic_core-2.6.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:19e20f8baedd7d987bd3f8005c146e6bcbda7cdeefc36fad50c66adb2dd2da48"},
|
||||
{file = "pydantic_core-2.6.3-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b0a5d7edb76c1c57b95df719af703e796fc8e796447a1da939f97bfa8a918d60"},
|
||||
{file = "pydantic_core-2.6.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f06e21ad0b504658a3a9edd3d8530e8cea5723f6ea5d280e8db8efc625b47e49"},
|
||||
{file = "pydantic_core-2.6.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ea053cefa008fda40f92aab937fb9f183cf8752e41dbc7bc68917884454c6362"},
|
||||
{file = "pydantic_core-2.6.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:171a4718860790f66d6c2eda1d95dd1edf64f864d2e9f9115840840cf5b5713f"},
|
||||
{file = "pydantic_core-2.6.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5ed7ceca6aba5331ece96c0e328cd52f0dcf942b8895a1ed2642de50800b79d3"},
|
||||
{file = "pydantic_core-2.6.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:acafc4368b289a9f291e204d2c4c75908557d4f36bd3ae937914d4529bf62a76"},
|
||||
{file = "pydantic_core-2.6.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:1aa712ba150d5105814e53cb141412217146fedc22621e9acff9236d77d2a5ef"},
|
||||
{file = "pydantic_core-2.6.3-cp39-none-win32.whl", hash = "sha256:44b4f937b992394a2e81a5c5ce716f3dcc1237281e81b80c748b2da6dd5cf29a"},
|
||||
{file = "pydantic_core-2.6.3-cp39-none-win_amd64.whl", hash = "sha256:9b33bf9658cb29ac1a517c11e865112316d09687d767d7a0e4a63d5c640d1b17"},
|
||||
{file = "pydantic_core-2.6.3-pp310-pypy310_pp73-macosx_10_7_x86_64.whl", hash = "sha256:d7050899026e708fb185e174c63ebc2c4ee7a0c17b0a96ebc50e1f76a231c057"},
|
||||
{file = "pydantic_core-2.6.3-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:99faba727727b2e59129c59542284efebbddade4f0ae6a29c8b8d3e1f437beb7"},
|
||||
{file = "pydantic_core-2.6.3-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5fa159b902d22b283b680ef52b532b29554ea2a7fc39bf354064751369e9dbd7"},
|
||||
{file = "pydantic_core-2.6.3-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:046af9cfb5384f3684eeb3f58a48698ddab8dd870b4b3f67f825353a14441418"},
|
||||
{file = "pydantic_core-2.6.3-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:930bfe73e665ebce3f0da2c6d64455098aaa67e1a00323c74dc752627879fc67"},
|
||||
{file = "pydantic_core-2.6.3-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:85cc4d105747d2aa3c5cf3e37dac50141bff779545ba59a095f4a96b0a460e70"},
|
||||
{file = "pydantic_core-2.6.3-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:b25afe9d5c4f60dcbbe2b277a79be114e2e65a16598db8abee2a2dcde24f162b"},
|
||||
{file = "pydantic_core-2.6.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:e49ce7dc9f925e1fb010fc3d555250139df61fa6e5a0a95ce356329602c11ea9"},
|
||||
{file = "pydantic_core-2.6.3-pp37-pypy37_pp73-macosx_10_7_x86_64.whl", hash = "sha256:2dd50d6a1aef0426a1d0199190c6c43ec89812b1f409e7fe44cb0fbf6dfa733c"},
|
||||
{file = "pydantic_core-2.6.3-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c6595b0d8c8711e8e1dc389d52648b923b809f68ac1c6f0baa525c6440aa0daa"},
|
||||
{file = "pydantic_core-2.6.3-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4ef724a059396751aef71e847178d66ad7fc3fc969a1a40c29f5aac1aa5f8784"},
|
||||
{file = "pydantic_core-2.6.3-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:3c8945a105f1589ce8a693753b908815e0748f6279959a4530f6742e1994dcb6"},
|
||||
{file = "pydantic_core-2.6.3-pp37-pypy37_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:c8c6660089a25d45333cb9db56bb9e347241a6d7509838dbbd1931d0e19dbc7f"},
|
||||
{file = "pydantic_core-2.6.3-pp37-pypy37_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:692b4ff5c4e828a38716cfa92667661a39886e71136c97b7dac26edef18767f7"},
|
||||
{file = "pydantic_core-2.6.3-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:f1a5d8f18877474c80b7711d870db0eeef9442691fcdb00adabfc97e183ee0b0"},
|
||||
{file = "pydantic_core-2.6.3-pp38-pypy38_pp73-macosx_10_7_x86_64.whl", hash = "sha256:3796a6152c545339d3b1652183e786df648ecdf7c4f9347e1d30e6750907f5bb"},
|
||||
{file = "pydantic_core-2.6.3-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:b962700962f6e7a6bd77e5f37320cabac24b4c0f76afeac05e9f93cf0c620014"},
|
||||
{file = "pydantic_core-2.6.3-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:56ea80269077003eaa59723bac1d8bacd2cd15ae30456f2890811efc1e3d4413"},
|
||||
{file = "pydantic_core-2.6.3-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75c0ebbebae71ed1e385f7dfd9b74c1cff09fed24a6df43d326dd7f12339ec34"},
|
||||
{file = "pydantic_core-2.6.3-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:252851b38bad3bfda47b104ffd077d4f9604a10cb06fe09d020016a25107bf98"},
|
||||
{file = "pydantic_core-2.6.3-pp38-pypy38_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:6656a0ae383d8cd7cc94e91de4e526407b3726049ce8d7939049cbfa426518c8"},
|
||||
{file = "pydantic_core-2.6.3-pp38-pypy38_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:d9140ded382a5b04a1c030b593ed9bf3088243a0a8b7fa9f071a5736498c5483"},
|
||||
{file = "pydantic_core-2.6.3-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:d38bbcef58220f9c81e42c255ef0bf99735d8f11edef69ab0b499da77105158a"},
|
||||
{file = "pydantic_core-2.6.3-pp39-pypy39_pp73-macosx_10_7_x86_64.whl", hash = "sha256:c9d469204abcca28926cbc28ce98f28e50e488767b084fb3fbdf21af11d3de26"},
|
||||
{file = "pydantic_core-2.6.3-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:48c1ed8b02ffea4d5c9c220eda27af02b8149fe58526359b3c07eb391cb353a2"},
|
||||
{file = "pydantic_core-2.6.3-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8b2b1bfed698fa410ab81982f681f5b1996d3d994ae8073286515ac4d165c2e7"},
|
||||
{file = "pydantic_core-2.6.3-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf9d42a71a4d7a7c1f14f629e5c30eac451a6fc81827d2beefd57d014c006c4a"},
|
||||
{file = "pydantic_core-2.6.3-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4292ca56751aebbe63a84bbfc3b5717abb09b14d4b4442cc43fd7c49a1529efd"},
|
||||
{file = "pydantic_core-2.6.3-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:7dc2ce039c7290b4ef64334ec7e6ca6494de6eecc81e21cb4f73b9b39991408c"},
|
||||
{file = "pydantic_core-2.6.3-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:615a31b1629e12445c0e9fc8339b41aaa6cc60bd53bf802d5fe3d2c0cda2ae8d"},
|
||||
{file = "pydantic_core-2.6.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:1fa1f6312fb84e8c281f32b39affe81984ccd484da6e9d65b3d18c202c666149"},
|
||||
{file = "pydantic_core-2.6.3.tar.gz", hash = "sha256:1508f37ba9e3ddc0189e6ff4e2228bd2d3c3a4641cbe8c07177162f76ed696c7"},
|
||||
]
|
||||
pydantic-settings = [
|
||||
{file = "pydantic_settings-2.0.3-py3-none-any.whl", hash = "sha256:ddd907b066622bd67603b75e2ff791875540dc485b7307c4fffc015719da8625"},
|
||||
{file = "pydantic_settings-2.0.3.tar.gz", hash = "sha256:962dc3672495aad6ae96a4390fac7e593591e144625e5112d359f8f67fb75945"},
|
||||
]
|
||||
pyjwt = [
|
||||
{file = "PyJWT-2.8.0-py3-none-any.whl", hash = "sha256:59127c392cc44c2da5bb3192169a91f429924e17aff6534d70fdc02ab3e04320"},
|
||||
{file = "PyJWT-2.8.0.tar.gz", hash = "sha256:57e28d156e3d5c10088e0c68abb90bfac3df82b40a71bd0daa20c65ccd5c23de"},
|
||||
]
|
||||
python-dotenv = [
|
||||
{file = "python-dotenv-1.0.0.tar.gz", hash = "sha256:a8df96034aae6d2d50a4ebe8216326c61c3eb64836776504fcca410e5937a3ba"},
|
||||
{file = "python_dotenv-1.0.0-py3-none-any.whl", hash = "sha256:f5971a9226b701070a4bf2c38c89e5a3f0d64de8debda981d1db98583009122a"},
|
||||
]
|
||||
sqlalchemy = [
|
||||
{file = "SQLAlchemy-1.4.49-cp27-cp27m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:2e126cf98b7fd38f1e33c64484406b78e937b1a280e078ef558b95bf5b6895f6"},
|
||||
{file = "SQLAlchemy-1.4.49-cp27-cp27mu-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:03db81b89fe7ef3857b4a00b63dedd632d6183d4ea5a31c5d8a92e000a41fc71"},
|
||||
{file = "SQLAlchemy-1.4.49-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:95b9df9afd680b7a3b13b38adf6e3a38995da5e162cc7524ef08e3be4e5ed3e1"},
|
||||
{file = "SQLAlchemy-1.4.49-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a63e43bf3f668c11bb0444ce6e809c1227b8f067ca1068898f3008a273f52b09"},
|
||||
{file = "SQLAlchemy-1.4.49-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f835c050ebaa4e48b18403bed2c0fda986525896efd76c245bdd4db995e51a4c"},
|
||||
{file = "SQLAlchemy-1.4.49-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c21b172dfb22e0db303ff6419451f0cac891d2e911bb9fbf8003d717f1bcf91"},
|
||||
{file = "SQLAlchemy-1.4.49-cp310-cp310-win32.whl", hash = "sha256:5fb1ebdfc8373b5a291485757bd6431de8d7ed42c27439f543c81f6c8febd729"},
|
||||
{file = "SQLAlchemy-1.4.49-cp310-cp310-win_amd64.whl", hash = "sha256:f8a65990c9c490f4651b5c02abccc9f113a7f56fa482031ac8cb88b70bc8ccaa"},
|
||||
{file = "SQLAlchemy-1.4.49-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:8923dfdf24d5aa8a3adb59723f54118dd4fe62cf59ed0d0d65d940579c1170a4"},
|
||||
{file = "SQLAlchemy-1.4.49-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a9ab2c507a7a439f13ca4499db6d3f50423d1d65dc9b5ed897e70941d9e135b0"},
|
||||
{file = "SQLAlchemy-1.4.49-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5debe7d49b8acf1f3035317e63d9ec8d5e4d904c6e75a2a9246a119f5f2fdf3d"},
|
||||
{file = "SQLAlchemy-1.4.49-cp311-cp311-win32.whl", hash = "sha256:82b08e82da3756765c2e75f327b9bf6b0f043c9c3925fb95fb51e1567fa4ee87"},
|
||||
{file = "SQLAlchemy-1.4.49-cp311-cp311-win_amd64.whl", hash = "sha256:171e04eeb5d1c0d96a544caf982621a1711d078dbc5c96f11d6469169bd003f1"},
|
||||
{file = "SQLAlchemy-1.4.49-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:36e58f8c4fe43984384e3fbe6341ac99b6b4e083de2fe838f0fdb91cebe9e9cb"},
|
||||
{file = "SQLAlchemy-1.4.49-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b31e67ff419013f99ad6f8fc73ee19ea31585e1e9fe773744c0f3ce58c039c30"},
|
||||
{file = "SQLAlchemy-1.4.49-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:c14b29d9e1529f99efd550cd04dbb6db6ba5d690abb96d52de2bff4ed518bc95"},
|
||||
{file = "SQLAlchemy-1.4.49-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c40f3470e084d31247aea228aa1c39bbc0904c2b9ccbf5d3cfa2ea2dac06f26d"},
|
||||
{file = "SQLAlchemy-1.4.49-cp36-cp36m-win32.whl", hash = "sha256:706bfa02157b97c136547c406f263e4c6274a7b061b3eb9742915dd774bbc264"},
|
||||
{file = "SQLAlchemy-1.4.49-cp36-cp36m-win_amd64.whl", hash = "sha256:a7f7b5c07ae5c0cfd24c2db86071fb2a3d947da7bd487e359cc91e67ac1c6d2e"},
|
||||
{file = "SQLAlchemy-1.4.49-cp37-cp37m-macosx_11_0_x86_64.whl", hash = "sha256:4afbbf5ef41ac18e02c8dc1f86c04b22b7a2125f2a030e25bbb4aff31abb224b"},
|
||||
{file = "SQLAlchemy-1.4.49-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:24e300c0c2147484a002b175f4e1361f102e82c345bf263242f0449672a4bccf"},
|
||||
{file = "SQLAlchemy-1.4.49-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:201de072b818f8ad55c80d18d1a788729cccf9be6d9dc3b9d8613b053cd4836d"},
|
||||
{file = "SQLAlchemy-1.4.49-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7653ed6817c710d0c95558232aba799307d14ae084cc9b1f4c389157ec50df5c"},
|
||||
{file = "SQLAlchemy-1.4.49-cp37-cp37m-win32.whl", hash = "sha256:647e0b309cb4512b1f1b78471fdaf72921b6fa6e750b9f891e09c6e2f0e5326f"},
|
||||
{file = "SQLAlchemy-1.4.49-cp37-cp37m-win_amd64.whl", hash = "sha256:ab73ed1a05ff539afc4a7f8cf371764cdf79768ecb7d2ec691e3ff89abbc541e"},
|
||||
{file = "SQLAlchemy-1.4.49-cp38-cp38-macosx_11_0_x86_64.whl", hash = "sha256:37ce517c011560d68f1ffb28af65d7e06f873f191eb3a73af5671e9c3fada08a"},
|
||||
{file = "SQLAlchemy-1.4.49-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1878ce508edea4a879015ab5215546c444233881301e97ca16fe251e89f1c55"},
|
||||
{file = "SQLAlchemy-1.4.49-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:0e8e608983e6f85d0852ca61f97e521b62e67969e6e640fe6c6b575d4db68557"},
|
||||
{file = "SQLAlchemy-1.4.49-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ccf956da45290df6e809ea12c54c02ace7f8ff4d765d6d3dfb3655ee876ce58d"},
|
||||
{file = "SQLAlchemy-1.4.49-cp38-cp38-win32.whl", hash = "sha256:f167c8175ab908ce48bd6550679cc6ea20ae169379e73c7720a28f89e53aa532"},
|
||||
{file = "SQLAlchemy-1.4.49-cp38-cp38-win_amd64.whl", hash = "sha256:45806315aae81a0c202752558f0df52b42d11dd7ba0097bf71e253b4215f34f4"},
|
||||
{file = "SQLAlchemy-1.4.49-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:b6d0c4b15d65087738a6e22e0ff461b407533ff65a73b818089efc8eb2b3e1de"},
|
||||
{file = "SQLAlchemy-1.4.49-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a843e34abfd4c797018fd8d00ffffa99fd5184c421f190b6ca99def4087689bd"},
|
||||
{file = "SQLAlchemy-1.4.49-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:1c890421651b45a681181301b3497e4d57c0d01dc001e10438a40e9a9c25ee77"},
|
||||
{file = "SQLAlchemy-1.4.49-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d26f280b8f0a8f497bc10573849ad6dc62e671d2468826e5c748d04ed9e670d5"},
|
||||
{file = "SQLAlchemy-1.4.49-cp39-cp39-win32.whl", hash = "sha256:ec2268de67f73b43320383947e74700e95c6770d0c68c4e615e9897e46296294"},
|
||||
{file = "SQLAlchemy-1.4.49-cp39-cp39-win_amd64.whl", hash = "sha256:bbdf16372859b8ed3f4d05f925a984771cd2abd18bd187042f24be4886c2a15f"},
|
||||
{file = "SQLAlchemy-1.4.49.tar.gz", hash = "sha256:06ff25cbae30c396c4b7737464f2a7fc37a67b7da409993b182b024cec80aed9"},
|
||||
]
|
||||
typing-extensions = [
|
||||
{file = "typing_extensions-4.7.1-py3-none-any.whl", hash = "sha256:440d5dd3af93b060174bf433bccd69b0babc3b15b1a8dca43789fd7f61514b36"},
|
||||
{file = "typing_extensions-4.7.1.tar.gz", hash = "sha256:b75ddc264f0ba5615db7ba217daeb99701ad295353c45f9e95963337ceeeffb2"},
|
||||
]
|
||||
27
services/auth-service/pyproject.toml
Normal file
27
services/auth-service/pyproject.toml
Normal file
@@ -0,0 +1,27 @@
|
||||
[tool.poetry]
|
||||
name = "auth-service"
|
||||
version = "1.0.0"
|
||||
description = "Panels - Auth Service"
|
||||
license = "Apache-2.0"
|
||||
readme = "README.md"
|
||||
repository = "https://github.com/hexolan/panels"
|
||||
authors = ["Declan <declan@hexolan.dev>"]
|
||||
|
||||
[tool.poetry.dependencies]
|
||||
python = "^3.9"
|
||||
grpcio = "^1.57.0"
|
||||
pydantic = "^2.3.0"
|
||||
pydantic-settings = "^2.0.3"
|
||||
databases = {extras = ["asyncpg"], version = "^0.8.0"}
|
||||
grpcio-health-checking = "^1.57.0"
|
||||
argon2-cffi = "^23.1.0"
|
||||
PyJWT = {extras = ["crypto"], version = "^2.8.0"}
|
||||
aiokafka = "^0.8.1"
|
||||
|
||||
[tool.poetry.dev-dependencies]
|
||||
grpcio-tools = "^1.57.0"
|
||||
protoletariat = "^3.2.19"
|
||||
|
||||
[build-system]
|
||||
requires = ["poetry-core>=1.0.0"]
|
||||
build-backend = "poetry.core.masonry.api"
|
||||
Reference in New Issue
Block a user