Skip to content

Commit

Permalink
big asyncapi update (#32, #37, #38, #39, #40, #41, #46)
Browse files Browse the repository at this point in the history
  • Loading branch information
Lancetnik committed Jun 7, 2023
1 parent 4d42151 commit 44c2a71
Show file tree
Hide file tree
Showing 75 changed files with 1,681 additions and 274 deletions.
2 changes: 1 addition & 1 deletion docs/docs/ru/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
* [**Управление зависимостями**](getting_started/1_quick-start/#_4): Эффективное переиспользование за счет аннотации типов. Доступ к зависимостями во всем стеке вызова.
* [**Интeграция**](getting_started/1_quick-start/#http): Propan полностью совместим с [любыми HTTP фреймворками](integrations/1_integrations-index/)
* **Независимость от брокеров**: Единый интерфейс для популярных брокеров:
* **Redis** (основан на [redis-py]("{{ urls.redis }}"){target="_blank"})
* **Redis** (основан на [redis-py]({{ urls.redis }}){target="_blank"})
* **RabbitMQ** (основан на [aio-pika]({{ urls.aio_pika }}){target="_blank"})
* **Kafka** (основан на [aiokafka]({{ urls.aiokafka }}){target="_blank"})
* **SQS** (основан на [aiobotocore]({{ urls.aiobotocore }}){target="_blank"})
Expand Down
9 changes: 8 additions & 1 deletion propan/asyncapi/__init__.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
from propan.asyncapi.bindings import AsyncAPIChannelBinding
from propan.asyncapi.channels import AsyncAPIChannel
from propan.asyncapi.info import AsyncAPIContact, AsyncAPIInfo, AsyncAPILicense
from propan.asyncapi.main import ASYNC_API_VERSION, AsyncAPISchema
from propan.asyncapi.main import ASYNC_API_VERSION, AsyncAPIComponents, AsyncAPISchema
from propan.asyncapi.message import AsyncAPIMessage
from propan.asyncapi.security import AsyncAPISecuritySchemeComponent
from propan.asyncapi.servers import AsyncAPIServer
from propan.asyncapi.utils import AsyncAPIExternalDocs, AsyncAPITag

__all__ = (
# main
"ASYNC_API_VERSION",
"AsyncAPISchema",
"AsyncAPIComponents",
# info
"AsyncAPIInfo",
"AsyncAPIContact",
Expand All @@ -22,4 +25,8 @@
"AsyncAPIExternalDocs",
# bindings
"AsyncAPIChannelBinding",
# messages
"AsyncAPIMessage",
# security
"AsyncAPISecuritySchemeComponent",
)
8 changes: 6 additions & 2 deletions propan/asyncapi/bindings/amqp.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ class Config:

class AsyncAPIAmqpChannelBinding(BaseModel):
is_: Literal["queue", "routingKey"] = Field(..., alias="is")
version: Optional[str] = Field(
default=None,
version: str = Field(
default="0.2.0",
alias="bindingVersion",
)
queue: Optional[AsyncAPIAmqpQueue] = None
Expand All @@ -48,6 +48,10 @@ class AsyncAPIAmqpOperationBinding(BaseModel):
cc: Optional[str] = None
ack: bool = True
reply_to: Optional[AnyDict] = Field(default=None, alias="replyTo")
version: str = Field(
default="0.2.0",
alias="bindingVersion",
)

class Config:
allow_population_by_field_name = True
41 changes: 41 additions & 0 deletions propan/asyncapi/bindings/kafka.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
from typing import List, Optional

from pydantic import BaseModel, Field

from propan.types import AnyDict


class AsyncAPIKafkaChannelBinding(BaseModel):
topic: List[str]
partitions: Optional[int] = None
replicas: Optional[int] = None
# TODO:
# topicConfiguration
version: str = Field(
default="0.4.0",
alias="bindingVersion",
)

class Config:
allow_population_by_field_name = True


class AsyncAPIKafkaOperationBinding(BaseModel):
group_id: Optional[AnyDict] = Field(
default=None,
alias="groupId",
)
client_id: Optional[AnyDict] = Field(
default=None,
alias="clientId",
)

reply_to: Optional[AnyDict] = Field(default=None, alias="replyTo")

version: str = Field(
default="0.4.0",
alias="bindingVersion",
)

class Config:
allow_population_by_field_name = True
24 changes: 24 additions & 0 deletions propan/asyncapi/bindings/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,35 @@
AsyncAPIAmqpChannelBinding,
AsyncAPIAmqpOperationBinding,
)
from propan.asyncapi.bindings.kafka import (
AsyncAPIKafkaChannelBinding,
AsyncAPIKafkaOperationBinding,
)
from propan.asyncapi.bindings.nats import (
AsyncAPINatsChannelBinding,
AsyncAPINatsOperationBinding,
)
from propan.asyncapi.bindings.redis import (
AsyncAPIRedisChannelBinding,
AsyncAPIRedisOperationBinding,
)
from propan.asyncapi.bindings.sqs import (
AsyncAPISQSChannelBinding,
AsyncAPISQSOperationBinding,
)


class AsyncAPIChannelBinding(BaseModel):
amqp: Optional[AsyncAPIAmqpChannelBinding] = None
kafka: Optional[AsyncAPIKafkaChannelBinding] = None
sqs: Optional[AsyncAPISQSChannelBinding] = None
nats: Optional[AsyncAPINatsChannelBinding] = None
redis: Optional[AsyncAPIRedisChannelBinding] = None


class AsyncAPIOperationBinding(BaseModel):
amqp: Optional[AsyncAPIAmqpOperationBinding] = None
kafka: Optional[AsyncAPIKafkaOperationBinding] = None
sqs: Optional[AsyncAPISQSOperationBinding] = None
nats: Optional[AsyncAPINatsOperationBinding] = None
redis: Optional[AsyncAPIRedisOperationBinding] = None
28 changes: 28 additions & 0 deletions propan/asyncapi/bindings/nats.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
from typing import Optional

from pydantic import BaseModel, Field

from propan.types import AnyDict


class AsyncAPINatsChannelBinding(BaseModel):
subject: str
queue: Optional[str] = None
version: str = Field(
default="custom",
alias="bindingVersion",
)

class Config:
allow_population_by_field_name = True


class AsyncAPINatsOperationBinding(BaseModel):
reply_to: Optional[AnyDict] = Field(default=None, alias="replyTo")
version: str = Field(
default="custom",
alias="bindingVersion",
)

class Config:
allow_population_by_field_name = True
29 changes: 29 additions & 0 deletions propan/asyncapi/bindings/redis.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
from typing import Optional

from pydantic import BaseModel, Field
from typing_extensions import Literal

from propan.types import AnyDict


class AsyncAPIRedisChannelBinding(BaseModel):
channel: str
method: Literal["ssubscribe", "psubscribe", "subscribe"] = "subscribe"
version: str = Field(
default="custom",
alias="bindingVersion",
)

class Config:
allow_population_by_field_name = True


class AsyncAPIRedisOperationBinding(BaseModel):
reply_to: Optional[AnyDict] = Field(default=None, alias="replyTo")
version: str = Field(
default="custom",
alias="bindingVersion",
)

class Config:
allow_population_by_field_name = True
28 changes: 28 additions & 0 deletions propan/asyncapi/bindings/sqs.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
from typing import Optional

from pydantic import BaseModel, Field

from propan.types import AnyDict


class AsyncAPISQSChannelBinding(BaseModel):
queue: AnyDict
version: str = Field(
default="custom",
alias="bindingVersion",
)

class Config:
allow_population_by_field_name = True


class AsyncAPISQSOperationBinding(BaseModel):
reply_to: Optional[AnyDict] = Field(default=None, alias="replyTo")

version: str = Field(
default="custom",
alias="bindingVersion",
)

class Config:
allow_population_by_field_name = True
1 change: 1 addition & 0 deletions propan/asyncapi/channels.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ class AsyncAPIPublish(BaseModel):


class AsyncAPIChannelParameters(BaseModel):
# TODO
...


Expand Down
25 changes: 24 additions & 1 deletion propan/asyncapi/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,36 @@

from propan.asyncapi.channels import AsyncAPIChannel
from propan.asyncapi.info import AsyncAPIInfo
from propan.asyncapi.message import AsyncAPIMessage
from propan.asyncapi.servers import AsyncAPIServer
from propan.asyncapi.utils import AsyncAPIExternalDocs, AsyncAPITag
from propan.brokers._model.schemas import ContentTypes
from propan.types import AnyDict

ASYNC_API_VERSION = "2.6.0"


class AsyncAPIComponents(BaseModel):
# TODO
# servers
# serverVariavles
# channels
messages: Optional[Dict[str, AsyncAPIMessage]] = None
schemas: Optional[Dict[str, AnyDict]] = None

# securitySchemes
# parameters
# correlationIds
# operationTraits
# messageTraits
# serverBindings
# channelBindings
# operationBindings
# messageBindings
class Config:
allow_population_by_field_name = True


class AsyncAPISchema(BaseModel):
asyncapi: str = ASYNC_API_VERSION
default_content_type: str = Field(
Expand All @@ -28,7 +51,7 @@ class AsyncAPISchema(BaseModel):

# TODO:
# id
# components
components: Optional[AsyncAPIComponents] = None

class Config:
allow_population_by_field_name = True
1 change: 1 addition & 0 deletions propan/asyncapi/message.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ class AsyncAPIMessage(BaseModel):
)

payload: Dict[str, Any]
# TODO:
# headers
# schemaFormat
# bindings
Expand Down
2 changes: 1 addition & 1 deletion propan/asyncapi/servers.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
class AsyncAPIServer(BaseModel):
url: str
protocol: str
description: str = ""
description: Optional[str] = None
protocol_version: Optional[str] = Field(
default=None,
alias="protocolVersion",
Expand Down
44 changes: 24 additions & 20 deletions propan/asyncapi/utils.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import json
import sys
from typing import Optional, Type

from pydantic import BaseModel, Field
Expand All @@ -22,24 +23,27 @@ class Config:


def add_example_to_model(model: Type[BaseModel]) -> Type[BaseModel]:
from polyfactory.factories.pydantic_factory import (
ModelFactory,
) # mv it to hide from main dependencies

factory = type(f"{model.__name__}_factory", (ModelFactory,), {"__model__": model})

return type(
model.__name__,
(model,),
{
"Config": type(
"Config",
(model.Config,),
{
"schema_extra": {
"example": json.loads(factory.build().json()),
if sys.version_info >= (3, 8):
from polyfactory.factories.pydantic_factory import ModelFactory

factory = type(
f"{model.__name__}_factory", (ModelFactory,), {"__model__": model}
)

return type(
model.__name__,
(model,),
{
"Config": type(
"Config",
(model.Config,),
{
"schema_extra": {
"example": json.loads(factory.build().json()),
},
},
},
)
},
)
)
},
)
else: # pragma: no cover
return model
Loading

0 comments on commit 44c2a71

Please sign in to comment.