mirror of
https://github.com/hexolan/panels.git
synced 2026-03-26 12:40:21 +00:00
init comment-service
This commit is contained in:
1
services/comment-service/.dockerignore
Normal file
1
services/comment-service/.dockerignore
Normal file
@@ -0,0 +1 @@
|
||||
.venv
|
||||
9
services/comment-service/.env.example
Normal file
9
services/comment-service/.env.example
Normal file
@@ -0,0 +1,9 @@
|
||||
POSTGRES_USER=postgres
|
||||
POSTGRES_PASS=postgres
|
||||
POSTGRES_HOST=localhost:5435
|
||||
POSTGRES_DATABASE=postgres
|
||||
|
||||
REDIS_HOST=localhost:6381
|
||||
REDIS_PASS=redis
|
||||
|
||||
KAFKA_BROKERS=localhost:9092
|
||||
17
services/comment-service/Dockerfile
Normal file
17
services/comment-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", "comment_service.main"]
|
||||
12
services/comment-service/Makefile
Normal file
12
services/comment-service/Makefile
Normal file
@@ -0,0 +1,12 @@
|
||||
migration-new:
|
||||
migrate create -ext sql -dir ./comment_service/postgres/migrations -seq ${MIGRATION_NAME}
|
||||
|
||||
migration-upgrade:
|
||||
docker run -v "${SERVICE_DIR}/comment_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}/comment_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=./comment_service/models/proto --pyi_out=./comment_service/models/proto --grpc_python_out=./comment_service/models/proto comment.proto post.proto user.proto
|
||||
poetry run python -m protoletariat --dont-create-package --in-place --python-out ./comment_service/models/proto protoc --proto-path=../../protobufs comment.proto post.proto user.proto
|
||||
57
services/comment-service/README.md
Normal file
57
services/comment-service/README.md
Normal file
@@ -0,0 +1,57 @@
|
||||
# Comment Service
|
||||
|
||||
## Event Documentation
|
||||
|
||||
* Events Produced:
|
||||
* **Topic:** "``comment``" | **Schema:** "``CommentEvent``" protobuf
|
||||
* Type: ``"created"`` | Data: ``Comment``
|
||||
* Type: ``"updated"`` | Data: ``Comment``
|
||||
* Type: ``"deleted"`` | Data: ``Comment``
|
||||
|
||||
* Events Consumed:
|
||||
* **Topic:** "``post``" | **Schema:** "``PostEvent``" protobuf
|
||||
* Type: ``"deleted"`` | Data: ``Post`` (only with ``Post.id`` attribute)
|
||||
* **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"
|
||||
|
||||
---
|
||||
|
||||
**Redis:**
|
||||
|
||||
``REDIS_HOST`` (Required)
|
||||
|
||||
* e.g. "localhost:6379"
|
||||
|
||||
``REDIS_PASS`` (Required)
|
||||
|
||||
* e.g. "redis"
|
||||
|
||||
---
|
||||
|
||||
**Kafka:**
|
||||
|
||||
``KAFKA_BROKERS`` (Required)
|
||||
|
||||
* e.g. "localhost:9092" or "localhost:9092,localhost:9093"
|
||||
@@ -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 comment_service.models.config import Config
|
||||
from comment_service.models.service import CommentDBRepository
|
||||
|
||||
|
||||
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[CommentDBRepository]): 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[CommentDBRepository]) -> None:
|
||||
"""Initialise the event consumer.
|
||||
|
||||
Args:
|
||||
config (Config): The app configuration instance (to access brokers list).
|
||||
db_repo (Type[CommentDBRepository]): The repository interface for updating data.
|
||||
|
||||
"""
|
||||
self._db_repo = db_repo
|
||||
self._consumer = AIOKafkaConsumer(
|
||||
self.CONSUMER_TOPIC,
|
||||
bootstrap_servers=config.kafka_brokers,
|
||||
group_id="comment-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")
|
||||
@@ -0,0 +1,33 @@
|
||||
import logging
|
||||
|
||||
from comment_service.models.proto import post_pb2
|
||||
from comment_service.events.base_consumer import EventConsumer
|
||||
|
||||
|
||||
class PostEventConsumer(EventConsumer):
|
||||
"""Consumer class responsible for 'post' events.
|
||||
|
||||
Attributes:
|
||||
CONSUMER_TOPIC: The topic to consume events from.
|
||||
CONSUMER_EVENT_TYPE (post_pb2.PostEvent): Kafka messages are serialised to this type.
|
||||
_db_repo (CommentDBRepository): The repository interface for modifying data.
|
||||
_consumer (aiokafka.AIOKafkaConsumer): The underlying Kafka instance.
|
||||
|
||||
"""
|
||||
CONSUMER_TOPIC = "post"
|
||||
CONSUMER_EVENT_TYPE = post_pb2.PostEvent
|
||||
|
||||
async def _process_event(self, event: post_pb2.PostEvent) -> None:
|
||||
"""Process a recieved event.
|
||||
|
||||
In response to a Post deleted event, delete any comments
|
||||
that fall under that post.
|
||||
|
||||
Args:
|
||||
event (post_pb2.PostEvent): The decoded protobuf message.
|
||||
|
||||
"""
|
||||
if event.type == "deleted":
|
||||
assert event.data.id != ""
|
||||
await self._db_repo.delete_post_comments(event.data.id)
|
||||
logging.info("succesfully processed PostEvent (type: 'deleted')")
|
||||
89
services/comment-service/comment_service/events/producer.py
Normal file
89
services/comment-service/comment_service/events/producer.py
Normal file
@@ -0,0 +1,89 @@
|
||||
import asyncio
|
||||
|
||||
from aiokafka import AIOKafkaProducer
|
||||
|
||||
from comment_service.models.config import Config
|
||||
from comment_service.models.service import Comment
|
||||
from comment_service.models.proto import comment_pb2
|
||||
|
||||
|
||||
class CommentEventProducer:
|
||||
"""Service event producer.
|
||||
|
||||
Attributes:
|
||||
_producer (aiokafka.AIOKafkaProducer): The underlying Kafka instance.
|
||||
_pending_sends (set): Background events that are still awaiting a response.
|
||||
|
||||
"""
|
||||
def __init__(self, config: Config) -> None:
|
||||
"""Initialise the event producer.
|
||||
|
||||
Args:
|
||||
config (Config): The app configuration instance (to access Kafka brokers list).
|
||||
|
||||
"""
|
||||
self._producer = AIOKafkaProducer(
|
||||
bootstrap_servers=config.kafka_brokers,
|
||||
client_id="auth-service"
|
||||
)
|
||||
self._pending_sends = set()
|
||||
|
||||
async def start(self) -> None:
|
||||
"""Start the underlying Kafka instance (open a connection)."""
|
||||
await self._producer.start()
|
||||
|
||||
async def _send_event(self, event: comment_pb2.CommentEvent) -> None:
|
||||
"""Send an event.
|
||||
|
||||
Execute the sending action as a background task to avoid
|
||||
delaying a response to the request.
|
||||
|
||||
Args:
|
||||
event (comment_pb2.CommentEvent): The protobuf class for the event.
|
||||
|
||||
"""
|
||||
bg_task = asyncio.create_task(self._producer.send(
|
||||
topic="comment",
|
||||
value=event.SerializeToString(),
|
||||
))
|
||||
self._pending_sends.add(bg_task)
|
||||
bg_task.add_done_callback(self._pending_sends.discard)
|
||||
|
||||
async def send_created_event(self, comment: Comment) -> None:
|
||||
"""Send a comment created event.
|
||||
|
||||
Args:
|
||||
comment (Comment): The comment to reference.
|
||||
|
||||
"""
|
||||
event = comment_pb2.CommentEvent(
|
||||
type="created",
|
||||
data=Comment.to_protobuf(comment)
|
||||
)
|
||||
await self._send_event(event)
|
||||
|
||||
async def send_updated_event(self, comment: Comment) -> None:
|
||||
"""Send a comment updated event.
|
||||
|
||||
Args:
|
||||
comment (Comment): The comment to reference.
|
||||
|
||||
"""
|
||||
event = comment_pb2.CommentEvent(
|
||||
type="updated",
|
||||
data=Comment.to_protobuf(comment)
|
||||
)
|
||||
await self._send_event(event)
|
||||
|
||||
async def send_deleted_event(self, comment: Comment) -> None:
|
||||
"""Send a comment deleted event.
|
||||
|
||||
Args:
|
||||
comment (Comment): The comment to reference.
|
||||
|
||||
"""
|
||||
event = comment_pb2.CommentEvent(
|
||||
type="deleted",
|
||||
data=Comment.to_protobuf(comment)
|
||||
)
|
||||
await self._send_event(event)
|
||||
67
services/comment-service/comment_service/events/service.py
Normal file
67
services/comment-service/comment_service/events/service.py
Normal file
@@ -0,0 +1,67 @@
|
||||
import asyncio
|
||||
from typing import Type
|
||||
|
||||
from comment_service.models.config import Config
|
||||
from comment_service.models.service import CommentDBRepository
|
||||
from comment_service.events.producer import CommentEventProducer
|
||||
from comment_service.events.post_consumer import PostEventConsumer
|
||||
from comment_service.events.user_consumer import UserEventConsumer
|
||||
|
||||
|
||||
class EventConsumersWrapper:
|
||||
"""A wrapper class for starting the event consumers.
|
||||
|
||||
Attributes:
|
||||
_post_consumer (PostEventConsumer): A wrapped consumer.
|
||||
_user_consumer (UserEventConsumer): A wrapped consumer.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, post_consumer: PostEventConsumer, user_consumer: UserEventConsumer) -> None:
|
||||
"""Add the consumers to the wrapper
|
||||
|
||||
Args:
|
||||
post_consumer (PostEventConsumer): Initialised post consumer.
|
||||
user_consumer (UserEventConsumer): Initialised user consumer.
|
||||
|
||||
"""
|
||||
self._post_consumer = post_consumer
|
||||
self._user_consumer = user_consumer
|
||||
|
||||
async def start(self) -> None:
|
||||
"""Begin consuming events on all the event consumers."""
|
||||
await asyncio.gather(
|
||||
self._post_consumer.start(),
|
||||
self._user_consumer.start()
|
||||
)
|
||||
|
||||
|
||||
def create_consumers(config: Config, db_repo: Type[CommentDBRepository]) -> EventConsumersWrapper:
|
||||
"""Initialse the event consumers and return them in a wrapper.
|
||||
|
||||
Args:
|
||||
config (Config): The app configuration instance.
|
||||
db_repo (Type[CommentDBRepository]): The database repo to pass to the consumers.
|
||||
|
||||
Returns:
|
||||
EventConsumerWrapper
|
||||
|
||||
"""
|
||||
post_consumer = PostEventConsumer(config, db_repo)
|
||||
user_consumer = UserEventConsumer(config, db_repo)
|
||||
return EventConsumersWrapper(post_consumer=post_consumer, user_consumer=user_consumer)
|
||||
|
||||
|
||||
async def create_producer(config: Config) -> CommentEventProducer:
|
||||
"""Create an event producer for the service.
|
||||
|
||||
Args:
|
||||
config (Config): The app configuration instance.
|
||||
|
||||
Returns:
|
||||
CommentEventProducer
|
||||
|
||||
"""
|
||||
producer = CommentEventProducer(config)
|
||||
await producer.start()
|
||||
return producer
|
||||
@@ -0,0 +1,33 @@
|
||||
import logging
|
||||
|
||||
from comment_service.models.proto import user_pb2
|
||||
from comment_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 (CommentDBRepository): 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 comments
|
||||
created by that user.
|
||||
|
||||
Args:
|
||||
event (user_pb2.UserEvent): The decoded protobuf message.
|
||||
|
||||
"""
|
||||
if event.type == "deleted":
|
||||
assert event.data.id != ""
|
||||
await self._db_repo.delete_user_comments(event.data.id)
|
||||
logging.info("succesfully processed UserEvent (type: 'deleted')")
|
||||
32
services/comment-service/comment_service/main.py
Normal file
32
services/comment-service/comment_service/main.py
Normal file
@@ -0,0 +1,32 @@
|
||||
import asyncio
|
||||
import logging
|
||||
from sys import stdout
|
||||
|
||||
from comment_service.models.config import Config
|
||||
from comment_service.events.service import create_producer, create_consumers
|
||||
from comment_service.postgres.service import create_db_repository
|
||||
from comment_service.redis.service import create_redis_repository
|
||||
from comment_service.rpc.service import create_rpc_server
|
||||
from comment_service.service import ServiceRepository
|
||||
|
||||
|
||||
async def main() -> None:
|
||||
config = Config()
|
||||
|
||||
event_prod = await create_producer(config)
|
||||
db_repo = await create_db_repository(config, event_producer=event_prod)
|
||||
redis_repo = await create_redis_repository(config, downstream_repo=db_repo)
|
||||
svc_repo = ServiceRepository(downstream_repo=redis_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())
|
||||
66
services/comment-service/comment_service/models/config.py
Normal file
66
services/comment-service/comment_service/models/config.py
Normal file
@@ -0,0 +1,66 @@
|
||||
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(",")
|
||||
|
||||
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.
|
||||
redis_host (str): Loaded from the 'REDIS_HOST' envvar.
|
||||
redis_pass (str): Loaded from the 'REDIS_PASS' envvar.
|
||||
kafka_brokers (list[str]): Loaded and comma delmited from the 'KAFKA_BROKERS' envvar.
|
||||
postgres_dsn (str): Computed when accessed the first time. (@property)
|
||||
|
||||
"""
|
||||
postgres_user: str
|
||||
postgres_pass: str
|
||||
postgres_host: str
|
||||
postgres_database: str
|
||||
|
||||
redis_host: str
|
||||
redis_pass: str
|
||||
|
||||
kafka_brokers: List[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), )
|
||||
@@ -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)
|
||||
@@ -0,0 +1,34 @@
|
||||
"""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\rcomment.proto\x12\x11panels.comment.v1\x1a\x1bgoogle/protobuf/empty.proto\x1a\x1fgoogle/protobuf/timestamp.proto"\xaa\x01\n\x07Comment\x12\n\n\x02id\x18\x01 \x01(\t\x12\x0f\n\x07post_id\x18\x02 \x01(\t\x12\x11\n\tauthor_id\x18\x03 \x01(\t\x12\x0f\n\x07message\x18\x04 \x01(\t\x12.\n\ncreated_at\x18\x05 \x01(\x0b2\x1a.google.protobuf.Timestamp\x12.\n\nupdated_at\x18\x06 \x01(\x0b2\x1a.google.protobuf.Timestamp"!\n\x0eCommentMutable\x12\x0f\n\x07message\x18\x01 \x01(\t"k\n\x14CreateCommentRequest\x12\x0f\n\x07post_id\x18\x01 \x01(\t\x12\x11\n\tauthor_id\x18\x02 \x01(\t\x12/\n\x04data\x18\x03 \x01(\x0b2!.panels.comment.v1.CommentMutable"S\n\x14UpdateCommentRequest\x12\n\n\x02id\x18\x01 \x01(\t\x12/\n\x04data\x18\x02 \x01(\x0b2!.panels.comment.v1.CommentMutable""\n\x14DeleteCommentRequest\x12\n\n\x02id\x18\x01 \x01(\t"\x1f\n\x11GetCommentRequest\x12\n\n\x02id\x18\x01 \x01(\t")\n\x16GetPostCommentsRequest\x12\x0f\n\x07post_id\x18\x01 \x01(\t"<\n\x0cPostComments\x12,\n\x08comments\x18\x01 \x03(\x0b2\x1a.panels.comment.v1.Comment"F\n\x0cCommentEvent\x12\x0c\n\x04type\x18\x01 \x01(\t\x12(\n\x04data\x18\x02 \x01(\x0b2\x1a.panels.comment.v1.Comment2\xc7\x03\n\x0eCommentService\x12V\n\rCreateComment\x12\'.panels.comment.v1.CreateCommentRequest\x1a\x1a.panels.comment.v1.Comment"\x00\x12V\n\rUpdateComment\x12\'.panels.comment.v1.UpdateCommentRequest\x1a\x1a.panels.comment.v1.Comment"\x00\x12R\n\rDeleteComment\x12\'.panels.comment.v1.DeleteCommentRequest\x1a\x16.google.protobuf.Empty"\x00\x12P\n\nGetComment\x12$.panels.comment.v1.GetCommentRequest\x1a\x1a.panels.comment.v1.Comment"\x00\x12_\n\x0fGetPostComments\x12).panels.comment.v1.GetPostCommentsRequest\x1a\x1f.panels.comment.v1.PostComments"\x00b\x06proto3')
|
||||
_globals = globals()
|
||||
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
|
||||
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'comment_pb2', _globals)
|
||||
if _descriptor._USE_C_DESCRIPTORS == False:
|
||||
DESCRIPTOR._options = None
|
||||
_globals['_COMMENT']._serialized_start = 99
|
||||
_globals['_COMMENT']._serialized_end = 269
|
||||
_globals['_COMMENTMUTABLE']._serialized_start = 271
|
||||
_globals['_COMMENTMUTABLE']._serialized_end = 304
|
||||
_globals['_CREATECOMMENTREQUEST']._serialized_start = 306
|
||||
_globals['_CREATECOMMENTREQUEST']._serialized_end = 413
|
||||
_globals['_UPDATECOMMENTREQUEST']._serialized_start = 415
|
||||
_globals['_UPDATECOMMENTREQUEST']._serialized_end = 498
|
||||
_globals['_DELETECOMMENTREQUEST']._serialized_start = 500
|
||||
_globals['_DELETECOMMENTREQUEST']._serialized_end = 534
|
||||
_globals['_GETCOMMENTREQUEST']._serialized_start = 536
|
||||
_globals['_GETCOMMENTREQUEST']._serialized_end = 567
|
||||
_globals['_GETPOSTCOMMENTSREQUEST']._serialized_start = 569
|
||||
_globals['_GETPOSTCOMMENTSREQUEST']._serialized_end = 610
|
||||
_globals['_POSTCOMMENTS']._serialized_start = 612
|
||||
_globals['_POSTCOMMENTS']._serialized_end = 672
|
||||
_globals['_COMMENTEVENT']._serialized_start = 674
|
||||
_globals['_COMMENTEVENT']._serialized_end = 744
|
||||
_globals['_COMMENTSERVICE']._serialized_start = 747
|
||||
_globals['_COMMENTSERVICE']._serialized_end = 1202
|
||||
@@ -0,0 +1,97 @@
|
||||
from google.protobuf import empty_pb2 as _empty_pb2
|
||||
from google.protobuf import timestamp_pb2 as _timestamp_pb2
|
||||
from google.protobuf.internal import containers as _containers
|
||||
from google.protobuf import descriptor as _descriptor
|
||||
from google.protobuf import message as _message
|
||||
from typing import ClassVar as _ClassVar, Iterable as _Iterable, Mapping as _Mapping, Optional as _Optional, Union as _Union
|
||||
DESCRIPTOR: _descriptor.FileDescriptor
|
||||
|
||||
class Comment(_message.Message):
|
||||
__slots__ = ['id', 'post_id', 'author_id', 'message', 'created_at', 'updated_at']
|
||||
ID_FIELD_NUMBER: _ClassVar[int]
|
||||
POST_ID_FIELD_NUMBER: _ClassVar[int]
|
||||
AUTHOR_ID_FIELD_NUMBER: _ClassVar[int]
|
||||
MESSAGE_FIELD_NUMBER: _ClassVar[int]
|
||||
CREATED_AT_FIELD_NUMBER: _ClassVar[int]
|
||||
UPDATED_AT_FIELD_NUMBER: _ClassVar[int]
|
||||
id: str
|
||||
post_id: str
|
||||
author_id: str
|
||||
message: str
|
||||
created_at: _timestamp_pb2.Timestamp
|
||||
updated_at: _timestamp_pb2.Timestamp
|
||||
|
||||
def __init__(self, id: _Optional[str]=..., post_id: _Optional[str]=..., author_id: _Optional[str]=..., message: _Optional[str]=..., created_at: _Optional[_Union[_timestamp_pb2.Timestamp, _Mapping]]=..., updated_at: _Optional[_Union[_timestamp_pb2.Timestamp, _Mapping]]=...) -> None:
|
||||
...
|
||||
|
||||
class CommentMutable(_message.Message):
|
||||
__slots__ = ['message']
|
||||
MESSAGE_FIELD_NUMBER: _ClassVar[int]
|
||||
message: str
|
||||
|
||||
def __init__(self, message: _Optional[str]=...) -> None:
|
||||
...
|
||||
|
||||
class CreateCommentRequest(_message.Message):
|
||||
__slots__ = ['post_id', 'author_id', 'data']
|
||||
POST_ID_FIELD_NUMBER: _ClassVar[int]
|
||||
AUTHOR_ID_FIELD_NUMBER: _ClassVar[int]
|
||||
DATA_FIELD_NUMBER: _ClassVar[int]
|
||||
post_id: str
|
||||
author_id: str
|
||||
data: CommentMutable
|
||||
|
||||
def __init__(self, post_id: _Optional[str]=..., author_id: _Optional[str]=..., data: _Optional[_Union[CommentMutable, _Mapping]]=...) -> None:
|
||||
...
|
||||
|
||||
class UpdateCommentRequest(_message.Message):
|
||||
__slots__ = ['id', 'data']
|
||||
ID_FIELD_NUMBER: _ClassVar[int]
|
||||
DATA_FIELD_NUMBER: _ClassVar[int]
|
||||
id: str
|
||||
data: CommentMutable
|
||||
|
||||
def __init__(self, id: _Optional[str]=..., data: _Optional[_Union[CommentMutable, _Mapping]]=...) -> None:
|
||||
...
|
||||
|
||||
class DeleteCommentRequest(_message.Message):
|
||||
__slots__ = ['id']
|
||||
ID_FIELD_NUMBER: _ClassVar[int]
|
||||
id: str
|
||||
|
||||
def __init__(self, id: _Optional[str]=...) -> None:
|
||||
...
|
||||
|
||||
class GetCommentRequest(_message.Message):
|
||||
__slots__ = ['id']
|
||||
ID_FIELD_NUMBER: _ClassVar[int]
|
||||
id: str
|
||||
|
||||
def __init__(self, id: _Optional[str]=...) -> None:
|
||||
...
|
||||
|
||||
class GetPostCommentsRequest(_message.Message):
|
||||
__slots__ = ['post_id']
|
||||
POST_ID_FIELD_NUMBER: _ClassVar[int]
|
||||
post_id: str
|
||||
|
||||
def __init__(self, post_id: _Optional[str]=...) -> None:
|
||||
...
|
||||
|
||||
class PostComments(_message.Message):
|
||||
__slots__ = ['comments']
|
||||
COMMENTS_FIELD_NUMBER: _ClassVar[int]
|
||||
comments: _containers.RepeatedCompositeFieldContainer[Comment]
|
||||
|
||||
def __init__(self, comments: _Optional[_Iterable[_Union[Comment, _Mapping]]]=...) -> None:
|
||||
...
|
||||
|
||||
class CommentEvent(_message.Message):
|
||||
__slots__ = ['type', 'data']
|
||||
TYPE_FIELD_NUMBER: _ClassVar[int]
|
||||
DATA_FIELD_NUMBER: _ClassVar[int]
|
||||
type: str
|
||||
data: Comment
|
||||
|
||||
def __init__(self, type: _Optional[str]=..., data: _Optional[_Union[Comment, _Mapping]]=...) -> None:
|
||||
...
|
||||
@@ -0,0 +1,80 @@
|
||||
"""Client and server classes corresponding to protobuf-defined services."""
|
||||
import grpc
|
||||
from . import comment_pb2 as comment__pb2
|
||||
from google.protobuf import empty_pb2 as google_dot_protobuf_dot_empty__pb2
|
||||
|
||||
class CommentServiceStub(object):
|
||||
"""Missing associated documentation comment in .proto file."""
|
||||
|
||||
def __init__(self, channel):
|
||||
"""Constructor.
|
||||
|
||||
Args:
|
||||
channel: A grpc.Channel.
|
||||
"""
|
||||
self.CreateComment = channel.unary_unary('/panels.comment.v1.CommentService/CreateComment', request_serializer=comment__pb2.CreateCommentRequest.SerializeToString, response_deserializer=comment__pb2.Comment.FromString)
|
||||
self.UpdateComment = channel.unary_unary('/panels.comment.v1.CommentService/UpdateComment', request_serializer=comment__pb2.UpdateCommentRequest.SerializeToString, response_deserializer=comment__pb2.Comment.FromString)
|
||||
self.DeleteComment = channel.unary_unary('/panels.comment.v1.CommentService/DeleteComment', request_serializer=comment__pb2.DeleteCommentRequest.SerializeToString, response_deserializer=google_dot_protobuf_dot_empty__pb2.Empty.FromString)
|
||||
self.GetComment = channel.unary_unary('/panels.comment.v1.CommentService/GetComment', request_serializer=comment__pb2.GetCommentRequest.SerializeToString, response_deserializer=comment__pb2.Comment.FromString)
|
||||
self.GetPostComments = channel.unary_unary('/panels.comment.v1.CommentService/GetPostComments', request_serializer=comment__pb2.GetPostCommentsRequest.SerializeToString, response_deserializer=comment__pb2.PostComments.FromString)
|
||||
|
||||
class CommentServiceServicer(object):
|
||||
"""Missing associated documentation comment in .proto file."""
|
||||
|
||||
def CreateComment(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 UpdateComment(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 DeleteComment(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 GetComment(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 GetPostComments(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_CommentServiceServicer_to_server(servicer, server):
|
||||
rpc_method_handlers = {'CreateComment': grpc.unary_unary_rpc_method_handler(servicer.CreateComment, request_deserializer=comment__pb2.CreateCommentRequest.FromString, response_serializer=comment__pb2.Comment.SerializeToString), 'UpdateComment': grpc.unary_unary_rpc_method_handler(servicer.UpdateComment, request_deserializer=comment__pb2.UpdateCommentRequest.FromString, response_serializer=comment__pb2.Comment.SerializeToString), 'DeleteComment': grpc.unary_unary_rpc_method_handler(servicer.DeleteComment, request_deserializer=comment__pb2.DeleteCommentRequest.FromString, response_serializer=google_dot_protobuf_dot_empty__pb2.Empty.SerializeToString), 'GetComment': grpc.unary_unary_rpc_method_handler(servicer.GetComment, request_deserializer=comment__pb2.GetCommentRequest.FromString, response_serializer=comment__pb2.Comment.SerializeToString), 'GetPostComments': grpc.unary_unary_rpc_method_handler(servicer.GetPostComments, request_deserializer=comment__pb2.GetPostCommentsRequest.FromString, response_serializer=comment__pb2.PostComments.SerializeToString)}
|
||||
generic_handler = grpc.method_handlers_generic_handler('panels.comment.v1.CommentService', rpc_method_handlers)
|
||||
server.add_generic_rpc_handlers((generic_handler,))
|
||||
|
||||
class CommentService(object):
|
||||
"""Missing associated documentation comment in .proto file."""
|
||||
|
||||
@staticmethod
|
||||
def CreateComment(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.comment.v1.CommentService/CreateComment', comment__pb2.CreateCommentRequest.SerializeToString, comment__pb2.Comment.FromString, options, channel_credentials, insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
|
||||
|
||||
@staticmethod
|
||||
def UpdateComment(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.comment.v1.CommentService/UpdateComment', comment__pb2.UpdateCommentRequest.SerializeToString, comment__pb2.Comment.FromString, options, channel_credentials, insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
|
||||
|
||||
@staticmethod
|
||||
def DeleteComment(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.comment.v1.CommentService/DeleteComment', comment__pb2.DeleteCommentRequest.SerializeToString, google_dot_protobuf_dot_empty__pb2.Empty.FromString, options, channel_credentials, insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
|
||||
|
||||
@staticmethod
|
||||
def GetComment(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.comment.v1.CommentService/GetComment', comment__pb2.GetCommentRequest.SerializeToString, comment__pb2.Comment.FromString, options, channel_credentials, insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
|
||||
|
||||
@staticmethod
|
||||
def GetPostComments(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.comment.v1.CommentService/GetPostComments', comment__pb2.GetPostCommentsRequest.SerializeToString, comment__pb2.PostComments.FromString, options, channel_credentials, insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
|
||||
@@ -0,0 +1,44 @@
|
||||
"""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\npost.proto\x12\x0epanels.post.v1\x1a\x1bgoogle/protobuf/empty.proto\x1a\x1fgoogle/protobuf/timestamp.proto"\xb7\x01\n\x04Post\x12\n\n\x02id\x18\x01 \x01(\t\x12\x10\n\x08panel_id\x18\x02 \x01(\t\x12\x11\n\tauthor_id\x18\x03 \x01(\t\x12\r\n\x05title\x18\x04 \x01(\t\x12\x0f\n\x07content\x18\x05 \x01(\t\x12.\n\ncreated_at\x18\x06 \x01(\x0b2\x1a.google.protobuf.Timestamp\x12.\n\nupdated_at\x18\x07 \x01(\x0b2\x1a.google.protobuf.Timestamp"M\n\x0bPostMutable\x12\x12\n\x05title\x18\x01 \x01(\tH\x00\x88\x01\x01\x12\x14\n\x07content\x18\x02 \x01(\tH\x01\x88\x01\x01B\x08\n\x06_titleB\n\n\x08_content"a\n\x11CreatePostRequest\x12\x10\n\x08panel_id\x18\x01 \x01(\t\x12\x0f\n\x07user_id\x18\x02 \x01(\t\x12)\n\x04data\x18\x03 \x01(\x0b2\x1b.panels.post.v1.PostMutable"\x1c\n\x0eGetPostRequest\x12\n\n\x02id\x18\x01 \x01(\t"3\n\x13GetPanelPostRequest\x12\x10\n\x08panel_id\x18\x01 \x01(\t\x12\n\n\x02id\x18\x02 \x01(\t"J\n\x11UpdatePostRequest\x12\n\n\x02id\x18\x01 \x01(\t\x12)\n\x04data\x18\x02 \x01(\x0b2\x1b.panels.post.v1.PostMutable"\x1f\n\x11DeletePostRequest\x12\n\n\x02id\x18\x01 \x01(\t"\x15\n\x13GetFeedPostsRequest"0\n\tFeedPosts\x12#\n\x05posts\x18\x01 \x03(\x0b2\x14.panels.post.v1.Post"&\n\x13GetUserPostsRequest\x12\x0f\n\x07user_id\x18\x01 \x01(\t"0\n\tUserPosts\x12#\n\x05posts\x18\x01 \x03(\x0b2\x14.panels.post.v1.Post"(\n\x14GetPanelPostsRequest\x12\x10\n\x08panel_id\x18\x01 \x01(\t"1\n\nPanelPosts\x12#\n\x05posts\x18\x01 \x03(\x0b2\x14.panels.post.v1.Post"=\n\tPostEvent\x12\x0c\n\x04type\x18\x01 \x01(\t\x12"\n\x04data\x18\x02 \x01(\x0b2\x14.panels.post.v1.Post2\xf3\x04\n\x0bPostService\x12G\n\nCreatePost\x12!.panels.post.v1.CreatePostRequest\x1a\x14.panels.post.v1.Post"\x00\x12A\n\x07GetPost\x12\x1e.panels.post.v1.GetPostRequest\x1a\x14.panels.post.v1.Post"\x00\x12K\n\x0cGetPanelPost\x12#.panels.post.v1.GetPanelPostRequest\x1a\x14.panels.post.v1.Post"\x00\x12G\n\nUpdatePost\x12!.panels.post.v1.UpdatePostRequest\x1a\x14.panels.post.v1.Post"\x00\x12I\n\nDeletePost\x12!.panels.post.v1.DeletePostRequest\x1a\x16.google.protobuf.Empty"\x00\x12P\n\x0cGetFeedPosts\x12#.panels.post.v1.GetFeedPostsRequest\x1a\x19.panels.post.v1.FeedPosts"\x00\x12P\n\x0cGetUserPosts\x12#.panels.post.v1.GetUserPostsRequest\x1a\x19.panels.post.v1.UserPosts"\x00\x12S\n\rGetPanelPosts\x12$.panels.post.v1.GetPanelPostsRequest\x1a\x1a.panels.post.v1.PanelPosts"\x00b\x06proto3')
|
||||
_globals = globals()
|
||||
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
|
||||
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'post_pb2', _globals)
|
||||
if _descriptor._USE_C_DESCRIPTORS == False:
|
||||
DESCRIPTOR._options = None
|
||||
_globals['_POST']._serialized_start = 93
|
||||
_globals['_POST']._serialized_end = 276
|
||||
_globals['_POSTMUTABLE']._serialized_start = 278
|
||||
_globals['_POSTMUTABLE']._serialized_end = 355
|
||||
_globals['_CREATEPOSTREQUEST']._serialized_start = 357
|
||||
_globals['_CREATEPOSTREQUEST']._serialized_end = 454
|
||||
_globals['_GETPOSTREQUEST']._serialized_start = 456
|
||||
_globals['_GETPOSTREQUEST']._serialized_end = 484
|
||||
_globals['_GETPANELPOSTREQUEST']._serialized_start = 486
|
||||
_globals['_GETPANELPOSTREQUEST']._serialized_end = 537
|
||||
_globals['_UPDATEPOSTREQUEST']._serialized_start = 539
|
||||
_globals['_UPDATEPOSTREQUEST']._serialized_end = 613
|
||||
_globals['_DELETEPOSTREQUEST']._serialized_start = 615
|
||||
_globals['_DELETEPOSTREQUEST']._serialized_end = 646
|
||||
_globals['_GETFEEDPOSTSREQUEST']._serialized_start = 648
|
||||
_globals['_GETFEEDPOSTSREQUEST']._serialized_end = 669
|
||||
_globals['_FEEDPOSTS']._serialized_start = 671
|
||||
_globals['_FEEDPOSTS']._serialized_end = 719
|
||||
_globals['_GETUSERPOSTSREQUEST']._serialized_start = 721
|
||||
_globals['_GETUSERPOSTSREQUEST']._serialized_end = 759
|
||||
_globals['_USERPOSTS']._serialized_start = 761
|
||||
_globals['_USERPOSTS']._serialized_end = 809
|
||||
_globals['_GETPANELPOSTSREQUEST']._serialized_start = 811
|
||||
_globals['_GETPANELPOSTSREQUEST']._serialized_end = 851
|
||||
_globals['_PANELPOSTS']._serialized_start = 853
|
||||
_globals['_PANELPOSTS']._serialized_end = 902
|
||||
_globals['_POSTEVENT']._serialized_start = 904
|
||||
_globals['_POSTEVENT']._serialized_end = 965
|
||||
_globals['_POSTSERVICE']._serialized_start = 968
|
||||
_globals['_POSTSERVICE']._serialized_end = 1595
|
||||
@@ -0,0 +1,141 @@
|
||||
from google.protobuf import empty_pb2 as _empty_pb2
|
||||
from google.protobuf import timestamp_pb2 as _timestamp_pb2
|
||||
from google.protobuf.internal import containers as _containers
|
||||
from google.protobuf import descriptor as _descriptor
|
||||
from google.protobuf import message as _message
|
||||
from typing import ClassVar as _ClassVar, Iterable as _Iterable, Mapping as _Mapping, Optional as _Optional, Union as _Union
|
||||
DESCRIPTOR: _descriptor.FileDescriptor
|
||||
|
||||
class Post(_message.Message):
|
||||
__slots__ = ['id', 'panel_id', 'author_id', 'title', 'content', 'created_at', 'updated_at']
|
||||
ID_FIELD_NUMBER: _ClassVar[int]
|
||||
PANEL_ID_FIELD_NUMBER: _ClassVar[int]
|
||||
AUTHOR_ID_FIELD_NUMBER: _ClassVar[int]
|
||||
TITLE_FIELD_NUMBER: _ClassVar[int]
|
||||
CONTENT_FIELD_NUMBER: _ClassVar[int]
|
||||
CREATED_AT_FIELD_NUMBER: _ClassVar[int]
|
||||
UPDATED_AT_FIELD_NUMBER: _ClassVar[int]
|
||||
id: str
|
||||
panel_id: str
|
||||
author_id: str
|
||||
title: str
|
||||
content: str
|
||||
created_at: _timestamp_pb2.Timestamp
|
||||
updated_at: _timestamp_pb2.Timestamp
|
||||
|
||||
def __init__(self, id: _Optional[str]=..., panel_id: _Optional[str]=..., author_id: _Optional[str]=..., title: _Optional[str]=..., content: _Optional[str]=..., created_at: _Optional[_Union[_timestamp_pb2.Timestamp, _Mapping]]=..., updated_at: _Optional[_Union[_timestamp_pb2.Timestamp, _Mapping]]=...) -> None:
|
||||
...
|
||||
|
||||
class PostMutable(_message.Message):
|
||||
__slots__ = ['title', 'content']
|
||||
TITLE_FIELD_NUMBER: _ClassVar[int]
|
||||
CONTENT_FIELD_NUMBER: _ClassVar[int]
|
||||
title: str
|
||||
content: str
|
||||
|
||||
def __init__(self, title: _Optional[str]=..., content: _Optional[str]=...) -> None:
|
||||
...
|
||||
|
||||
class CreatePostRequest(_message.Message):
|
||||
__slots__ = ['panel_id', 'user_id', 'data']
|
||||
PANEL_ID_FIELD_NUMBER: _ClassVar[int]
|
||||
USER_ID_FIELD_NUMBER: _ClassVar[int]
|
||||
DATA_FIELD_NUMBER: _ClassVar[int]
|
||||
panel_id: str
|
||||
user_id: str
|
||||
data: PostMutable
|
||||
|
||||
def __init__(self, panel_id: _Optional[str]=..., user_id: _Optional[str]=..., data: _Optional[_Union[PostMutable, _Mapping]]=...) -> None:
|
||||
...
|
||||
|
||||
class GetPostRequest(_message.Message):
|
||||
__slots__ = ['id']
|
||||
ID_FIELD_NUMBER: _ClassVar[int]
|
||||
id: str
|
||||
|
||||
def __init__(self, id: _Optional[str]=...) -> None:
|
||||
...
|
||||
|
||||
class GetPanelPostRequest(_message.Message):
|
||||
__slots__ = ['panel_id', 'id']
|
||||
PANEL_ID_FIELD_NUMBER: _ClassVar[int]
|
||||
ID_FIELD_NUMBER: _ClassVar[int]
|
||||
panel_id: str
|
||||
id: str
|
||||
|
||||
def __init__(self, panel_id: _Optional[str]=..., id: _Optional[str]=...) -> None:
|
||||
...
|
||||
|
||||
class UpdatePostRequest(_message.Message):
|
||||
__slots__ = ['id', 'data']
|
||||
ID_FIELD_NUMBER: _ClassVar[int]
|
||||
DATA_FIELD_NUMBER: _ClassVar[int]
|
||||
id: str
|
||||
data: PostMutable
|
||||
|
||||
def __init__(self, id: _Optional[str]=..., data: _Optional[_Union[PostMutable, _Mapping]]=...) -> None:
|
||||
...
|
||||
|
||||
class DeletePostRequest(_message.Message):
|
||||
__slots__ = ['id']
|
||||
ID_FIELD_NUMBER: _ClassVar[int]
|
||||
id: str
|
||||
|
||||
def __init__(self, id: _Optional[str]=...) -> None:
|
||||
...
|
||||
|
||||
class GetFeedPostsRequest(_message.Message):
|
||||
__slots__ = []
|
||||
|
||||
def __init__(self) -> None:
|
||||
...
|
||||
|
||||
class FeedPosts(_message.Message):
|
||||
__slots__ = ['posts']
|
||||
POSTS_FIELD_NUMBER: _ClassVar[int]
|
||||
posts: _containers.RepeatedCompositeFieldContainer[Post]
|
||||
|
||||
def __init__(self, posts: _Optional[_Iterable[_Union[Post, _Mapping]]]=...) -> None:
|
||||
...
|
||||
|
||||
class GetUserPostsRequest(_message.Message):
|
||||
__slots__ = ['user_id']
|
||||
USER_ID_FIELD_NUMBER: _ClassVar[int]
|
||||
user_id: str
|
||||
|
||||
def __init__(self, user_id: _Optional[str]=...) -> None:
|
||||
...
|
||||
|
||||
class UserPosts(_message.Message):
|
||||
__slots__ = ['posts']
|
||||
POSTS_FIELD_NUMBER: _ClassVar[int]
|
||||
posts: _containers.RepeatedCompositeFieldContainer[Post]
|
||||
|
||||
def __init__(self, posts: _Optional[_Iterable[_Union[Post, _Mapping]]]=...) -> None:
|
||||
...
|
||||
|
||||
class GetPanelPostsRequest(_message.Message):
|
||||
__slots__ = ['panel_id']
|
||||
PANEL_ID_FIELD_NUMBER: _ClassVar[int]
|
||||
panel_id: str
|
||||
|
||||
def __init__(self, panel_id: _Optional[str]=...) -> None:
|
||||
...
|
||||
|
||||
class PanelPosts(_message.Message):
|
||||
__slots__ = ['posts']
|
||||
POSTS_FIELD_NUMBER: _ClassVar[int]
|
||||
posts: _containers.RepeatedCompositeFieldContainer[Post]
|
||||
|
||||
def __init__(self, posts: _Optional[_Iterable[_Union[Post, _Mapping]]]=...) -> None:
|
||||
...
|
||||
|
||||
class PostEvent(_message.Message):
|
||||
__slots__ = ['type', 'data']
|
||||
TYPE_FIELD_NUMBER: _ClassVar[int]
|
||||
DATA_FIELD_NUMBER: _ClassVar[int]
|
||||
type: str
|
||||
data: Post
|
||||
|
||||
def __init__(self, type: _Optional[str]=..., data: _Optional[_Union[Post, _Mapping]]=...) -> None:
|
||||
...
|
||||
@@ -0,0 +1,113 @@
|
||||
"""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 post_pb2 as post__pb2
|
||||
|
||||
class PostServiceStub(object):
|
||||
"""Missing associated documentation comment in .proto file."""
|
||||
|
||||
def __init__(self, channel):
|
||||
"""Constructor.
|
||||
|
||||
Args:
|
||||
channel: A grpc.Channel.
|
||||
"""
|
||||
self.CreatePost = channel.unary_unary('/panels.post.v1.PostService/CreatePost', request_serializer=post__pb2.CreatePostRequest.SerializeToString, response_deserializer=post__pb2.Post.FromString)
|
||||
self.GetPost = channel.unary_unary('/panels.post.v1.PostService/GetPost', request_serializer=post__pb2.GetPostRequest.SerializeToString, response_deserializer=post__pb2.Post.FromString)
|
||||
self.GetPanelPost = channel.unary_unary('/panels.post.v1.PostService/GetPanelPost', request_serializer=post__pb2.GetPanelPostRequest.SerializeToString, response_deserializer=post__pb2.Post.FromString)
|
||||
self.UpdatePost = channel.unary_unary('/panels.post.v1.PostService/UpdatePost', request_serializer=post__pb2.UpdatePostRequest.SerializeToString, response_deserializer=post__pb2.Post.FromString)
|
||||
self.DeletePost = channel.unary_unary('/panels.post.v1.PostService/DeletePost', request_serializer=post__pb2.DeletePostRequest.SerializeToString, response_deserializer=google_dot_protobuf_dot_empty__pb2.Empty.FromString)
|
||||
self.GetFeedPosts = channel.unary_unary('/panels.post.v1.PostService/GetFeedPosts', request_serializer=post__pb2.GetFeedPostsRequest.SerializeToString, response_deserializer=post__pb2.FeedPosts.FromString)
|
||||
self.GetUserPosts = channel.unary_unary('/panels.post.v1.PostService/GetUserPosts', request_serializer=post__pb2.GetUserPostsRequest.SerializeToString, response_deserializer=post__pb2.UserPosts.FromString)
|
||||
self.GetPanelPosts = channel.unary_unary('/panels.post.v1.PostService/GetPanelPosts', request_serializer=post__pb2.GetPanelPostsRequest.SerializeToString, response_deserializer=post__pb2.PanelPosts.FromString)
|
||||
|
||||
class PostServiceServicer(object):
|
||||
"""Missing associated documentation comment in .proto file."""
|
||||
|
||||
def CreatePost(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 GetPost(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 GetPanelPost(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 UpdatePost(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 DeletePost(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 GetFeedPosts(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 GetUserPosts(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 GetPanelPosts(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_PostServiceServicer_to_server(servicer, server):
|
||||
rpc_method_handlers = {'CreatePost': grpc.unary_unary_rpc_method_handler(servicer.CreatePost, request_deserializer=post__pb2.CreatePostRequest.FromString, response_serializer=post__pb2.Post.SerializeToString), 'GetPost': grpc.unary_unary_rpc_method_handler(servicer.GetPost, request_deserializer=post__pb2.GetPostRequest.FromString, response_serializer=post__pb2.Post.SerializeToString), 'GetPanelPost': grpc.unary_unary_rpc_method_handler(servicer.GetPanelPost, request_deserializer=post__pb2.GetPanelPostRequest.FromString, response_serializer=post__pb2.Post.SerializeToString), 'UpdatePost': grpc.unary_unary_rpc_method_handler(servicer.UpdatePost, request_deserializer=post__pb2.UpdatePostRequest.FromString, response_serializer=post__pb2.Post.SerializeToString), 'DeletePost': grpc.unary_unary_rpc_method_handler(servicer.DeletePost, request_deserializer=post__pb2.DeletePostRequest.FromString, response_serializer=google_dot_protobuf_dot_empty__pb2.Empty.SerializeToString), 'GetFeedPosts': grpc.unary_unary_rpc_method_handler(servicer.GetFeedPosts, request_deserializer=post__pb2.GetFeedPostsRequest.FromString, response_serializer=post__pb2.FeedPosts.SerializeToString), 'GetUserPosts': grpc.unary_unary_rpc_method_handler(servicer.GetUserPosts, request_deserializer=post__pb2.GetUserPostsRequest.FromString, response_serializer=post__pb2.UserPosts.SerializeToString), 'GetPanelPosts': grpc.unary_unary_rpc_method_handler(servicer.GetPanelPosts, request_deserializer=post__pb2.GetPanelPostsRequest.FromString, response_serializer=post__pb2.PanelPosts.SerializeToString)}
|
||||
generic_handler = grpc.method_handlers_generic_handler('panels.post.v1.PostService', rpc_method_handlers)
|
||||
server.add_generic_rpc_handlers((generic_handler,))
|
||||
|
||||
class PostService(object):
|
||||
"""Missing associated documentation comment in .proto file."""
|
||||
|
||||
@staticmethod
|
||||
def CreatePost(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.post.v1.PostService/CreatePost', post__pb2.CreatePostRequest.SerializeToString, post__pb2.Post.FromString, options, channel_credentials, insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
|
||||
|
||||
@staticmethod
|
||||
def GetPost(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.post.v1.PostService/GetPost', post__pb2.GetPostRequest.SerializeToString, post__pb2.Post.FromString, options, channel_credentials, insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
|
||||
|
||||
@staticmethod
|
||||
def GetPanelPost(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.post.v1.PostService/GetPanelPost', post__pb2.GetPanelPostRequest.SerializeToString, post__pb2.Post.FromString, options, channel_credentials, insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
|
||||
|
||||
@staticmethod
|
||||
def UpdatePost(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.post.v1.PostService/UpdatePost', post__pb2.UpdatePostRequest.SerializeToString, post__pb2.Post.FromString, options, channel_credentials, insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
|
||||
|
||||
@staticmethod
|
||||
def DeletePost(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.post.v1.PostService/DeletePost', post__pb2.DeletePostRequest.SerializeToString, google_dot_protobuf_dot_empty__pb2.Empty.FromString, options, channel_credentials, insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
|
||||
|
||||
@staticmethod
|
||||
def GetFeedPosts(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.post.v1.PostService/GetFeedPosts', post__pb2.GetFeedPostsRequest.SerializeToString, post__pb2.FeedPosts.FromString, options, channel_credentials, insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
|
||||
|
||||
@staticmethod
|
||||
def GetUserPosts(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.post.v1.PostService/GetUserPosts', post__pb2.GetUserPostsRequest.SerializeToString, post__pb2.UserPosts.FromString, options, channel_credentials, insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
|
||||
|
||||
@staticmethod
|
||||
def GetPanelPosts(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.post.v1.PostService/GetPanelPosts', post__pb2.GetPanelPostsRequest.SerializeToString, post__pb2.PanelPosts.FromString, options, channel_credentials, insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
|
||||
@@ -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
|
||||
@@ -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:
|
||||
...
|
||||
@@ -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)
|
||||
97
services/comment-service/comment_service/models/service.py
Normal file
97
services/comment-service/comment_service/models/service.py
Normal file
@@ -0,0 +1,97 @@
|
||||
from datetime import datetime
|
||||
from typing import List, Optional
|
||||
|
||||
from pydantic import BaseModel
|
||||
from google.protobuf import timestamp_pb2
|
||||
|
||||
from comment_service.models.proto import comment_pb2
|
||||
from comment_service.models.exceptions import ServiceException, ServiceErrorCode
|
||||
|
||||
|
||||
# Validators
|
||||
def is_valid_comment_msg(message: str) -> bool:
|
||||
if len(message) < 3 or len(message) > 512:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
# Service Models
|
||||
class Comment(BaseModel):
|
||||
id: int
|
||||
|
||||
post_id: str
|
||||
author_id: str
|
||||
message: str
|
||||
|
||||
created_at: datetime
|
||||
updated_at: Optional[datetime] = None
|
||||
|
||||
@classmethod
|
||||
def to_protobuf(cls, comment: "Comment") -> comment_pb2.Comment:
|
||||
created_at = timestamp_pb2.Timestamp()
|
||||
created_at.FromDatetime(comment.created_at)
|
||||
|
||||
updated_at = None
|
||||
if comment.updated_at is not None:
|
||||
updated_at = timestamp_pb2.Timestamp()
|
||||
updated_at.FromDatetime(comment.updated_at)
|
||||
|
||||
return comment_pb2.Comment(
|
||||
id=str(comment.id),
|
||||
post_id=comment.post_id,
|
||||
author_id=comment.author_id,
|
||||
message=comment.message,
|
||||
|
||||
created_at=created_at,
|
||||
updated_at=updated_at,
|
||||
)
|
||||
|
||||
|
||||
class CommentCreate(BaseModel):
|
||||
post_id: str
|
||||
author_id: str
|
||||
message: str # todo: validation on message (wrap validator for is_valid_comment_msg)
|
||||
|
||||
@classmethod
|
||||
def from_protobuf(cls, request: comment_pb2.CreateCommentRequest) -> "CommentCreate":
|
||||
return cls(
|
||||
post_id=request.post_id,
|
||||
author_id=request.author_id,
|
||||
message=request.data.message,
|
||||
)
|
||||
|
||||
|
||||
class CommentUpdate(BaseModel):
|
||||
message: Optional[str] = None # todo: validation on message (if set use validator is_valid_comment_msg)
|
||||
|
||||
@classmethod
|
||||
def from_protobuf(cls, request: comment_pb2.UpdateCommentRequest) -> "CommentUpdate":
|
||||
return cls(
|
||||
message=request.data.message
|
||||
)
|
||||
|
||||
|
||||
# Repository Interfaces
|
||||
class CommentRepository:
|
||||
async def get_comment(self, comment_id: int) -> Comment:
|
||||
raise ServiceException("unimplemented internal repository method", ServiceErrorCode.SERVICE_ERROR)
|
||||
|
||||
async def get_post_comments(self, post_id: str) -> List[Comment]:
|
||||
raise ServiceException("unimplemented internal repository method", ServiceErrorCode.SERVICE_ERROR)
|
||||
|
||||
async def create_comment(self, data: CommentCreate) -> Comment:
|
||||
raise ServiceException("unimplemented internal repository method", ServiceErrorCode.SERVICE_ERROR)
|
||||
|
||||
async def update_comment(self, comment_id: int, data: CommentUpdate) -> Comment:
|
||||
raise ServiceException("unimplemented internal repository method", ServiceErrorCode.SERVICE_ERROR)
|
||||
|
||||
async def delete_comment(self, comment_id: int) -> None:
|
||||
raise ServiceException("unimplemented internal repository method", ServiceErrorCode.SERVICE_ERROR)
|
||||
|
||||
|
||||
class CommentDBRepository(CommentRepository):
|
||||
async def delete_post_comments(self, post_id: str) -> None:
|
||||
raise ServiceException("unimplemented internal repository method", ServiceErrorCode.SERVICE_ERROR)
|
||||
|
||||
async def delete_user_comments(self, user_id: str) -> None:
|
||||
raise ServiceException("unimplemented internal repository method", ServiceErrorCode.SERVICE_ERROR)
|
||||
@@ -0,0 +1 @@
|
||||
DROP TABLE IF EXISTS comments CASCADE;
|
||||
@@ -0,0 +1,11 @@
|
||||
CREATE TABLE comments (
|
||||
"id" serial PRIMARY KEY,
|
||||
|
||||
"post_id" varchar(64) NOT NULL,
|
||||
"author_id" varchar(64) NOT NULL,
|
||||
|
||||
"message" varchar(512) NOT NULL,
|
||||
|
||||
"created_at" timestamp NOT NULL DEFAULT timezone('utc', now()),
|
||||
"updated_at" timestamp
|
||||
);
|
||||
@@ -0,0 +1,94 @@
|
||||
from typing import List
|
||||
|
||||
from databases import Database
|
||||
|
||||
from comment_service.events.producer import CommentEventProducer
|
||||
from comment_service.models.exceptions import ServiceException, ServiceErrorCode
|
||||
from comment_service.models.service import CommentDBRepository, Comment, CommentCreate, CommentUpdate
|
||||
|
||||
|
||||
class ServiceDBRepository(CommentDBRepository):
|
||||
"""Database repository responsible for actions
|
||||
relating to the postgres database.
|
||||
|
||||
This repository will be utilised by other upstream repositories
|
||||
or the Kafka event consumers.
|
||||
|
||||
Attributes:
|
||||
_db (Database): The postgres database connection handler.
|
||||
_event_prod (CommentEventProducer): Used to dispatch events upon execution of a CRUD action.
|
||||
|
||||
"""
|
||||
def __init__(self, db: Database, event_producer: CommentEventProducer) -> None:
|
||||
self._db = db
|
||||
self._event_prod = event_producer
|
||||
|
||||
def _result_to_comment(self, result) -> Comment:
|
||||
return Comment(
|
||||
id=result.id,
|
||||
post_id=result.post_id,
|
||||
author_id=result.author_id,
|
||||
message=result.message,
|
||||
created_at=result.created_at,
|
||||
updated_at=result._mapping.get("updated_at", None)
|
||||
)
|
||||
|
||||
async def get_post_comments(self, post_id: str) -> List[Comment]:
|
||||
query = "SELECT id, post_id, author_id, message, created_at, updated_at FROM comments WHERE post_id = :post_id"
|
||||
rows = await self._db.fetch_all(query=query, values={"post_id": post_id})
|
||||
return [self._result_to_comment(result) for result in rows]
|
||||
|
||||
async def create_comment(self, data: CommentCreate) -> Comment:
|
||||
query = "INSERT INTO comments (post_id, author_id, message) VALUES (:post_id, :author_id, :message) RETURNING id"
|
||||
result = await self._db.execute(query=query, values={"post_id": data.post_id, "author_id": data.author_id, "message": data.message})
|
||||
|
||||
comment = await self.get_comment(result)
|
||||
await self._event_prod.send_created_event(comment)
|
||||
return comment
|
||||
|
||||
async def update_comment(self, comment_id: int, data: CommentUpdate) -> Comment:
|
||||
query = "UPDATE comments SET message = :message, updated_at = now() WHERE id = :comment_id"
|
||||
await self._db.execute(query=query, values={"message": data.message, "comment_id": comment_id})
|
||||
|
||||
comment = await self.get_comment(comment_id)
|
||||
await self._event_prod.send_updated_event(comment)
|
||||
return comment
|
||||
|
||||
async def delete_comment(self, comment_id: int) -> None:
|
||||
comment = await self.get_comment(comment_id)
|
||||
|
||||
query = "DELETE FROM comments WHERE id = :comment_id"
|
||||
await self._db.execute(query=query, values={"comment_id": comment_id})
|
||||
|
||||
await self._event_prod.send_deleted_event(comment)
|
||||
|
||||
async def get_comment(self, comment_id: int) -> Comment:
|
||||
query = "SELECT id, post_id, author_id, message, created_at, updated_at FROM comments WHERE id = :comment_id"
|
||||
result = await self._db.fetch_one(query=query, values={"comment_id": comment_id})
|
||||
if result is None:
|
||||
raise ServiceException(message="no comment found", error_code=ServiceErrorCode.NOT_FOUND)
|
||||
|
||||
return self._result_to_comment(result)
|
||||
|
||||
async def delete_post_comments(self, post_id: str) -> None:
|
||||
comments = await self.get_post_comments(post_id)
|
||||
|
||||
query = "DELETE FROM comments WHERE post_id = :post_id"
|
||||
await self._db.execute(query=query, values={"post_id": post_id})
|
||||
|
||||
for comment in comments:
|
||||
await self._event_prod.send_deleted_event(comment)
|
||||
|
||||
async def delete_user_comments(self, user_id: str) -> None:
|
||||
comments = await self.get_post_comments(user_id)
|
||||
|
||||
query = "DELETE FROM comments WHERE author_id = :author_id"
|
||||
await self._db.execute(query=query, values={"author_id": user_id})
|
||||
|
||||
for comment in comments:
|
||||
await self._event_prod.send_deleted_event(comment)
|
||||
|
||||
async def _get_user_comments(self, user_id: str) -> List[Comment]:
|
||||
query = "SELECT id, post_id, author_id, message, created_at, updated_at FROM comments WHERE author_id = :user_id"
|
||||
rows = await self._db.fetch_all(query=query, values={"user_id": user_id})
|
||||
return [self._result_to_comment(result) for result in rows]
|
||||
41
services/comment-service/comment_service/postgres/service.py
Normal file
41
services/comment-service/comment_service/postgres/service.py
Normal file
@@ -0,0 +1,41 @@
|
||||
import logging
|
||||
|
||||
from databases import Database
|
||||
|
||||
from comment_service.models.config import Config
|
||||
from comment_service.events.producer import CommentEventProducer
|
||||
from comment_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, event_producer: CommentEventProducer) -> ServiceDBRepository:
|
||||
"""Create the database repository.
|
||||
|
||||
Open a database connection and instantialise the
|
||||
database repository.
|
||||
|
||||
Returns:
|
||||
ServiceDBRepository
|
||||
|
||||
"""
|
||||
db = await connect_database(config)
|
||||
return ServiceDBRepository(db, event_producer)
|
||||
76
services/comment-service/comment_service/redis/repository.py
Normal file
76
services/comment-service/comment_service/redis/repository.py
Normal file
@@ -0,0 +1,76 @@
|
||||
import pickle
|
||||
import logging
|
||||
from typing import Type, List
|
||||
|
||||
import redis.asyncio as redis
|
||||
|
||||
from comment_service.models.service import CommentRepository, Comment, CommentCreate, CommentUpdate
|
||||
|
||||
|
||||
class ServiceRedisRepository(CommentRepository):
|
||||
"""The Redis repository is responsible for caching
|
||||
requests to help reduce the amount of database calls,
|
||||
allowing for faster data access.
|
||||
|
||||
If the Redis repository does not have the data cached,
|
||||
or does not cache data for that request, then the call is
|
||||
passed downstream to the database repository.
|
||||
|
||||
Attributes:
|
||||
_conn (redis.asyncio.redis.Redis): The Redis connection.
|
||||
_repo (CommentRepository): The next downstream repository (the DB repo).
|
||||
|
||||
"""
|
||||
def __init__(self, redis_conn: redis.Redis, downstream_repo: Type[CommentRepository]) -> None:
|
||||
self._conn = redis_conn
|
||||
self._repo = downstream_repo
|
||||
|
||||
async def _purge_cached_comments(self, post_id: str) -> None:
|
||||
try:
|
||||
self._conn.delete(post_id)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
async def get_comment(self, comment_id: int) -> Comment:
|
||||
return await self._repo.get_comment(comment_id)
|
||||
|
||||
async def get_post_comments(self, post_id: str) -> List[Comment]:
|
||||
post_id = post_id.lower()
|
||||
|
||||
failure = False
|
||||
try:
|
||||
# check for a cached version of the post comments
|
||||
response = await self._conn.get(post_id)
|
||||
if response is not None:
|
||||
comments = pickle.loads(response)
|
||||
assert type(comments) == list
|
||||
return comments
|
||||
except Exception as e:
|
||||
failure = True
|
||||
logging.error("Redis Repo: error whilst getting post comments", e)
|
||||
pass
|
||||
|
||||
comments = await self._repo.get_post_comments(post_id)
|
||||
if failure is False:
|
||||
# cache the retrieved comments
|
||||
try:
|
||||
await self._conn.set(post_id, pickle.dumps(comments), ex=120) # TTL: 2 minutes
|
||||
except Exception:
|
||||
logging.error("Redis Repo: error whilst caching post comments", e)
|
||||
pass
|
||||
|
||||
return comments
|
||||
|
||||
async def create_comment(self, data: CommentCreate) -> Comment:
|
||||
comment = await self._repo.create_comment(data)
|
||||
await self._purge_cached_comments(comment.post_id)
|
||||
return comment
|
||||
|
||||
async def update_comment(self, comment_id: int, data: CommentUpdate) -> Comment:
|
||||
comment = await self._repo.update_comment(comment_id, data)
|
||||
await self._purge_cached_comments(comment.post_id)
|
||||
return comment
|
||||
|
||||
async def delete_comment(self, comment_id: int) -> None:
|
||||
# todo: purge cache of comments on post (instead of waiting for TTL expiry)
|
||||
await self._repo.delete_comment(comment_id)
|
||||
48
services/comment-service/comment_service/redis/service.py
Normal file
48
services/comment-service/comment_service/redis/service.py
Normal file
@@ -0,0 +1,48 @@
|
||||
from typing import Type
|
||||
|
||||
import redis.asyncio as redis
|
||||
|
||||
from comment_service.models.config import Config
|
||||
from comment_service.models.service import CommentRepository
|
||||
from comment_service.redis.repository import ServiceRedisRepository
|
||||
|
||||
|
||||
async def connect_redis(config: Config) -> redis.Redis:
|
||||
"""Opens a connection to Redis.
|
||||
|
||||
Args:
|
||||
config (Config): The app configuration.
|
||||
|
||||
Returns:
|
||||
A connected redis.Redis instance
|
||||
|
||||
"""
|
||||
host, port = config.redis_host, 5432
|
||||
try:
|
||||
host, port = config.redis_host.split(":")
|
||||
port = int(port)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
conn = redis.Redis(host=host, port=port, password=config.redis_pass)
|
||||
await conn.ping()
|
||||
return conn
|
||||
|
||||
|
||||
async def create_redis_repository(config: Config, downstream_repo: Type[CommentRepository]) -> ServiceRedisRepository:
|
||||
"""Create the Redis repository.
|
||||
|
||||
Open a Redis connection and instantialise the
|
||||
Redis repository.
|
||||
|
||||
Args:
|
||||
downstream_repo (Type[CommentRepository]): The next downstream repository
|
||||
that will be called by the Redis repository. (in this case the database
|
||||
repository)
|
||||
|
||||
Returns:
|
||||
ServiceRedisRepository
|
||||
|
||||
"""
|
||||
redis_conn = await connect_redis(config)
|
||||
return ServiceRedisRepository(redis_conn=redis_conn, downstream_repo=downstream_repo)
|
||||
289
services/comment-service/comment_service/rpc/comment.py
Normal file
289
services/comment-service/comment_service/rpc/comment.py
Normal file
@@ -0,0 +1,289 @@
|
||||
import logging
|
||||
import traceback
|
||||
from typing import Type
|
||||
|
||||
from google.protobuf import empty_pb2
|
||||
from grpc import RpcContext, StatusCode
|
||||
|
||||
from comment_service.models.exceptions import ServiceException
|
||||
from comment_service.models.service import CommentRepository, Comment, CommentCreate, CommentUpdate
|
||||
from comment_service.models.proto import comment_pb2, comment_pb2_grpc
|
||||
|
||||
|
||||
class CommentServicer(comment_pb2_grpc.CommentServiceServicer):
|
||||
"""Contains definitions for the service's RPC methods.
|
||||
|
||||
Requests are converted from protobuf to business model
|
||||
form, then directed to the service repository, where the
|
||||
response is then translated back to protobuf.
|
||||
|
||||
Attributes:
|
||||
_svc_repo (Type[CommentRepository]): The highest level service repository.
|
||||
|
||||
"""
|
||||
def __init__(self, svc_repo: Type[CommentRepository]) -> None:
|
||||
self._svc_repo = svc_repo
|
||||
|
||||
def _apply_error(self, context: RpcContext, code: StatusCode, msg: str) -> None:
|
||||
"""Apply an error to a given RPC context.
|
||||
|
||||
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 CreateComment(self, request: comment_pb2.CreateCommentRequest, context: RpcContext) -> comment_pb2.Comment:
|
||||
"""CreateComment RPC Call
|
||||
|
||||
Args:
|
||||
request (comment_pb2.CreateCommentRequest): The request parameters.
|
||||
context (grpc.RpcContext): The context of the RPC call.
|
||||
|
||||
Returns:
|
||||
comment_pb2.Comment: With a succesful comment creation.
|
||||
|
||||
"""
|
||||
# vaLidate the request inputs
|
||||
if request.post_id == "":
|
||||
self._apply_error(
|
||||
context,
|
||||
code=StatusCode.INVALID_ARGUMENT,
|
||||
msg="post not provided"
|
||||
)
|
||||
return
|
||||
|
||||
if request.author_id == "":
|
||||
self._apply_error(
|
||||
context,
|
||||
code=StatusCode.INVALID_ARGUMENT,
|
||||
msg="author not provided"
|
||||
)
|
||||
return
|
||||
|
||||
if request.data == None:
|
||||
self._apply_error(
|
||||
context,
|
||||
code=StatusCode.INVALID_ARGUMENT,
|
||||
msg="malformed request"
|
||||
)
|
||||
return
|
||||
|
||||
if request.data.message == "":
|
||||
self._apply_error(
|
||||
context,
|
||||
code=StatusCode.INVALID_ARGUMENT,
|
||||
msg="comment message not provided"
|
||||
)
|
||||
return
|
||||
|
||||
# convert to service model from protobuf
|
||||
try:
|
||||
data = CommentCreate.from_protobuf(request)
|
||||
comment = await self._svc_repo.create_comment(data)
|
||||
except ServiceException as err:
|
||||
err.apply_to_rpc(context)
|
||||
return
|
||||
except Exception:
|
||||
logging.error(traceback.format_exc())
|
||||
self._apply_unknown_error(context)
|
||||
return
|
||||
|
||||
# convert comment to protobuf form
|
||||
return Comment.to_protobuf(comment)
|
||||
|
||||
async def UpdateComment(self, request: comment_pb2.UpdateCommentRequest, context: RpcContext) -> comment_pb2.Comment:
|
||||
"""UpdateComment RPC Call
|
||||
|
||||
Args:
|
||||
request (comment_pb2.UpdateCommentRequest): The request parameters.
|
||||
context (grpc.RpcContext): The context of the RPC call.
|
||||
|
||||
Returns:
|
||||
comment_pb2.Comment: The updated comment details (if succesfully updated).
|
||||
|
||||
"""
|
||||
# vaLidate the request inputs
|
||||
if request.id == "":
|
||||
self._apply_error(
|
||||
context,
|
||||
code=StatusCode.INVALID_ARGUMENT,
|
||||
msg="comment not provided"
|
||||
)
|
||||
return
|
||||
elif not request.id.isnumeric():
|
||||
self._apply_error(
|
||||
context,
|
||||
code=StatusCode.INVALID_ARGUMENT,
|
||||
msg="invalid comment id provided"
|
||||
)
|
||||
return
|
||||
|
||||
if request.data == None:
|
||||
self._apply_error(
|
||||
context,
|
||||
code=StatusCode.INVALID_ARGUMENT,
|
||||
msg="malformed request"
|
||||
)
|
||||
return
|
||||
|
||||
if request.data.message == "":
|
||||
self._apply_error(
|
||||
context,
|
||||
code=StatusCode.INVALID_ARGUMENT,
|
||||
msg="comment message not provided"
|
||||
)
|
||||
return
|
||||
|
||||
# convert to service model from protobuf
|
||||
try:
|
||||
comment_id = int(request.id)
|
||||
data = CommentUpdate.from_protobuf(request)
|
||||
comment = await self._svc_repo.update_comment(comment_id, data)
|
||||
except ServiceException as err:
|
||||
err.apply_to_rpc(context)
|
||||
return
|
||||
except Exception:
|
||||
logging.error(traceback.format_exc())
|
||||
self._apply_unknown_error(context)
|
||||
return
|
||||
|
||||
# convert comment to protobuf form
|
||||
return Comment.to_protobuf(comment)
|
||||
|
||||
async def DeleteComment(self, request: comment_pb2.DeleteCommentRequest, context: RpcContext) -> empty_pb2.Empty:
|
||||
"""DeleteComment RPC Call
|
||||
|
||||
Args:
|
||||
request (comment_pb2.DeleteCommentRequest): 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.id == "":
|
||||
self._apply_error(
|
||||
context,
|
||||
code=StatusCode.INVALID_ARGUMENT,
|
||||
msg="comment not provided"
|
||||
)
|
||||
return
|
||||
|
||||
if not request.id.isnumeric():
|
||||
self._apply_error(
|
||||
context,
|
||||
code=StatusCode.INVALID_ARGUMENT,
|
||||
msg="invalid comment id provided"
|
||||
)
|
||||
return
|
||||
|
||||
# attempt to delete the comment
|
||||
try:
|
||||
comment_id = int(request.id)
|
||||
await self._svc_repo.delete_comment(comment_id)
|
||||
except ServiceException as err:
|
||||
err.apply_to_rpc(context)
|
||||
return
|
||||
except Exception:
|
||||
logging.error(traceback.format_exc())
|
||||
self._apply_unknown_error(context)
|
||||
return
|
||||
|
||||
return empty_pb2.Empty()
|
||||
|
||||
async def GetComment(self, request: comment_pb2.GetCommentRequest, context: RpcContext) -> comment_pb2.PostComments:
|
||||
"""GetComment RPC Call
|
||||
|
||||
Returns a comment by comment id.
|
||||
|
||||
Args:
|
||||
request (comment_pb2.GetCommentRequest): The request parameters.
|
||||
context (grpc.RpcContext): The context of the RPC call.
|
||||
|
||||
Returns:
|
||||
comment_pb2.Comment: The located comment
|
||||
|
||||
"""
|
||||
# vaLidate the request inputs
|
||||
if request.id == "":
|
||||
self._apply_error(
|
||||
context,
|
||||
code=StatusCode.INVALID_ARGUMENT,
|
||||
msg="comment id not provided"
|
||||
)
|
||||
return
|
||||
|
||||
if not request.id.isnumeric():
|
||||
self._apply_error(
|
||||
context,
|
||||
code=StatusCode.INVALID_ARGUMENT,
|
||||
msg="invalid comment id provided"
|
||||
)
|
||||
return
|
||||
|
||||
# attempt to get the comment
|
||||
try:
|
||||
comment = await self._svc_repo.get_comment(int(request.id))
|
||||
except ServiceException as err:
|
||||
err.apply_to_rpc(context)
|
||||
return
|
||||
except Exception:
|
||||
logging.error(traceback.format_exc())
|
||||
self._apply_unknown_error(context)
|
||||
return
|
||||
|
||||
return Comment.to_protobuf(comment)
|
||||
|
||||
async def GetPostComments(self, request: comment_pb2.GetPostCommentsRequest, context: RpcContext) -> comment_pb2.PostComments:
|
||||
"""GetPostComments RPC Call
|
||||
|
||||
Returns a list of comments that a post has.
|
||||
|
||||
TODO:
|
||||
Implement pagination (?after=comment_id or some effect)
|
||||
to return more comments from a post.
|
||||
|
||||
Args:
|
||||
request (comment_pb2.UpdateCommentRequest): The request parameters.
|
||||
context (grpc.RpcContext): The context of the RPC call.
|
||||
|
||||
Returns:
|
||||
comment_pb2.PostComments: containing a list of the post's comments
|
||||
|
||||
"""
|
||||
# vaLidate the request inputs
|
||||
if request.post_id == "":
|
||||
self._apply_error(
|
||||
context,
|
||||
code=StatusCode.INVALID_ARGUMENT,
|
||||
msg="post id not provided"
|
||||
)
|
||||
return
|
||||
|
||||
# attempt to get the comments
|
||||
try:
|
||||
comments = await self._svc_repo.get_post_comments(request.post_id)
|
||||
except ServiceException as err:
|
||||
err.apply_to_rpc(context)
|
||||
return
|
||||
except Exception:
|
||||
logging.error(traceback.format_exc())
|
||||
self._apply_unknown_error(context)
|
||||
return
|
||||
|
||||
# convert to protobuf
|
||||
return comment_pb2.PostComments(comments=[Comment.to_protobuf(comment) for comment in comments])
|
||||
52
services/comment-service/comment_service/rpc/service.py
Normal file
52
services/comment-service/comment_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 comment_service.rpc.comment import CommentServicer
|
||||
from comment_service.models.proto import comment_pb2_grpc
|
||||
from comment_service.models.service import CommentRepository
|
||||
|
||||
|
||||
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[CommentRepository]) -> None:
|
||||
"""Creates the gRPC server and adds the servicers.
|
||||
|
||||
Args:
|
||||
svc_repo (Type[CommentRepository]): The service repository to pass to the servicers.
|
||||
|
||||
"""
|
||||
self._grpc_server = grpc.aio.server()
|
||||
self._grpc_server.add_insecure_port("[::]:9090")
|
||||
|
||||
comment_servicer = CommentServicer(svc_repo)
|
||||
comment_pb2_grpc.add_CommentServiceServicer_to_server(comment_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[CommentRepository]) -> RPCServerWrapper:
|
||||
"""Instantialise the RPC server wrapper.
|
||||
|
||||
Args:
|
||||
svc_repo (Type[CommentRepository]): The service repository for the RPC servicers to interface with.
|
||||
|
||||
Returns:
|
||||
RPCServerWrapper
|
||||
|
||||
"""
|
||||
return RPCServerWrapper(svc_repo)
|
||||
30
services/comment-service/comment_service/service.py
Normal file
30
services/comment-service/comment_service/service.py
Normal file
@@ -0,0 +1,30 @@
|
||||
from typing import Type, List
|
||||
|
||||
from comment_service.models.service import CommentRepository, Comment, CommentCreate, CommentUpdate
|
||||
|
||||
|
||||
class ServiceRepository(CommentRepository):
|
||||
"""The comment service repository.
|
||||
|
||||
Attributes:
|
||||
_repo (Type[CommentRepository]): The downstream repository (Redis Repository -> DB Repository).
|
||||
|
||||
"""
|
||||
def __init__(self, downstream_repo: Type[CommentRepository]) -> None:
|
||||
self._repo = downstream_repo
|
||||
|
||||
async def get_comment(self, comment_id: int) -> Comment:
|
||||
return await self._repo.get_comment(comment_id)
|
||||
|
||||
async def get_post_comments(self, post_id: str) -> List[Comment]:
|
||||
# todo: pagination
|
||||
return await self._repo.get_post_comments(post_id)
|
||||
|
||||
async def create_comment(self, data: CommentCreate) -> Comment:
|
||||
return await self._repo.create_comment(data)
|
||||
|
||||
async def update_comment(self, comment_id: int, data: CommentUpdate) -> Comment:
|
||||
return await self._repo.update_comment(comment_id, data)
|
||||
|
||||
async def delete_comment(self, comment_id: int) -> None:
|
||||
await self._repo.delete_comment(comment_id)
|
||||
733
services/comment-service/poetry.lock
generated
Normal file
733
services/comment-service/poetry.lock
generated
Normal file
@@ -0,0 +1,733 @@
|
||||
[[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 = "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 = "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 = "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 = "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 = "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 = "redis"
|
||||
version = "5.0.0"
|
||||
description = "Python client for Redis database and key-value store"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
|
||||
[package.dependencies]
|
||||
async-timeout = {version = ">=4.0.2", markers = "python_full_version <= \"3.11.2\""}
|
||||
|
||||
[package.extras]
|
||||
hiredis = ["hiredis (>=1.0.0)"]
|
||||
ocsp = ["cryptography (>=36.0.1)", "pyopenssl (==20.0.1)", "requests (>=2.26.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 = "87657efcec44cfdb339270dc199f74b4e664ea78fd27056a225d2d2384d3a10c"
|
||||
|
||||
[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"},
|
||||
]
|
||||
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"},
|
||||
]
|
||||
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"},
|
||||
]
|
||||
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"},
|
||||
]
|
||||
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"},
|
||||
]
|
||||
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"},
|
||||
]
|
||||
redis = [
|
||||
{file = "redis-5.0.0-py3-none-any.whl", hash = "sha256:06570d0b2d84d46c21defc550afbaada381af82f5b83e5b3777600e05d8e2ed0"},
|
||||
{file = "redis-5.0.0.tar.gz", hash = "sha256:5cea6c0d335c9a7332a460ed8729ceabb4d0c489c7285b0a86dbbf8a017bd120"},
|
||||
]
|
||||
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"},
|
||||
]
|
||||
26
services/comment-service/pyproject.toml
Normal file
26
services/comment-service/pyproject.toml
Normal file
@@ -0,0 +1,26 @@
|
||||
[tool.poetry]
|
||||
name = "comment-service"
|
||||
version = "1.0.0"
|
||||
description = "Panels - Comment 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"
|
||||
aiokafka = "^0.8.1"
|
||||
redis = "^5.0.0"
|
||||
|
||||
[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