queue-func 0.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of queue-func might be problematic. Click here for more details.

Files changed (40) hide show
  1. queue_func/__init__.py +1 -0
  2. queue_func/broker/__init__.py +1 -0
  3. queue_func/broker/base.py +82 -0
  4. queue_func/broker/queue.py +44 -0
  5. queue_func/config/__init__.py +1 -0
  6. queue_func/config/general.py +32 -0
  7. queue_func/config/queue.py +14 -0
  8. queue_func/config/utils.py +15 -0
  9. queue_func/consumer/__init__.py +1 -0
  10. queue_func/consumer/base.py +97 -0
  11. queue_func/consumer/queue.py +55 -0
  12. queue_func/factory/__init__.py +12 -0
  13. queue_func/factory/backend.py +13 -0
  14. queue_func/factory/builders/__init__.py +9 -0
  15. queue_func/factory/builders/queue.py +20 -0
  16. queue_func/factory/deco.py +93 -0
  17. queue_func/factory/registry.py +41 -0
  18. queue_func/factory/runtime.py +40 -0
  19. queue_func/message/__init__.py +1 -0
  20. queue_func/message/base.py +39 -0
  21. queue_func/message/general.py +30 -0
  22. queue_func/pool_executor/__init__.py +1 -0
  23. queue_func/pool_executor/base.py +31 -0
  24. queue_func/pool_executor/general.py +42 -0
  25. queue_func/pool_executor/utils.py +49 -0
  26. queue_func/producer/__init__.py +1 -0
  27. queue_func/producer/base.py +36 -0
  28. queue_func/producer/queue.py +30 -0
  29. queue_func/serializer/__init__.py +1 -0
  30. queue_func/serializer/base.py +38 -0
  31. queue_func/serializer/json_ser.py +25 -0
  32. queue_func/serializer/orjson_ser.py +30 -0
  33. queue_func/serializer/utils.py +16 -0
  34. queue_func/task/__init__.py +1 -0
  35. queue_func/task/base.py +28 -0
  36. queue_func/task/thread.py +26 -0
  37. queue_func-0.1.dist-info/METADATA +121 -0
  38. queue_func-0.1.dist-info/RECORD +40 -0
  39. queue_func-0.1.dist-info/WHEEL +4 -0
  40. queue_func-0.1.dist-info/licenses/LICENSE +201 -0
queue_func/__init__.py ADDED
@@ -0,0 +1 @@
1
+ # coding: utf-8
@@ -0,0 +1 @@
1
+ # coding: utf-8
@@ -0,0 +1,82 @@
1
+ # coding: utf-8
2
+
3
+ import abc
4
+ import typing as t
5
+
6
+ from queue_func.message.base import BaseMessage, Packed
7
+
8
+ if t.TYPE_CHECKING:
9
+ from queue_func.config.general import Config
10
+ from queue_func.producer.base import BaseProducer
11
+ from queue_func.consumer.base import BaseConsumer
12
+
13
+
14
+ ConfigType = t.TypeVar("ConfigType", bound="Config")
15
+
16
+
17
+ class BaseBroker(t.Generic[ConfigType, Packed], metaclass=abc.ABCMeta):
18
+ """一条通道的装配者。
19
+
20
+ 创建时准备好双方共用的 Message,并持有配置与 Producer/Consumer。
21
+ 对外通过 publish、start_consumer 等入口操作;运行期业务逻辑仍在 Producer/Consumer 内完成。
22
+ """
23
+
24
+ __slots__ = (
25
+ "_config",
26
+ "_message",
27
+ "_producer",
28
+ "_consumer",
29
+ )
30
+
31
+ def __init__(self, config: ConfigType):
32
+
33
+ self._config = config
34
+ self._message: BaseMessage[Packed] = self._config.message_cls(
35
+ message_serializer_cls=self._config.message_serializer_cls,
36
+ enable_serializer=self._config.enable_message_serializer,
37
+ )
38
+ self._producer = self._create_producer()
39
+ self._consumer = self._create_consumer()
40
+
41
+ @abc.abstractmethod
42
+ def _create_producer(self) -> "BaseProducer[Packed]":
43
+
44
+ pass
45
+
46
+ @abc.abstractmethod
47
+ def _create_consumer(self) -> "BaseConsumer[Packed]":
48
+
49
+ pass
50
+
51
+ @property
52
+ def message(self) -> BaseMessage[Packed]:
53
+
54
+ return self._message
55
+
56
+ async def publish(
57
+ self,
58
+ coro_args: tuple[t.Any, ...],
59
+ coro_kwargs: dict[str, t.Any] | None = None,
60
+ **kwargs: t.Any) -> None:
61
+
62
+ await self._producer.publish(coro_args, coro_kwargs, **kwargs)
63
+
64
+ async def start_consumer(self) -> None:
65
+
66
+ await self._consumer.consume()
67
+
68
+ async def stop_consumer(self) -> None:
69
+
70
+ await self._consumer.stop()
71
+
72
+ async def join_consumer(self) -> None:
73
+
74
+ await self._consumer.join()
75
+
76
+ async def stop_producer(self) -> None:
77
+
78
+ await self._producer.stop()
79
+
80
+ async def join_producer(self) -> None:
81
+
82
+ await self._producer.join()
@@ -0,0 +1,44 @@
1
+ # coding: utf-8
2
+
3
+ import asyncio
4
+ import typing as t
5
+
6
+ from queue_func.message.base import Packed
7
+ from queue_func.broker.base import BaseBroker as _BaseBroker
8
+ from queue_func.producer.queue import Producer
9
+ from queue_func.consumer.queue import Consumer
10
+
11
+ if t.TYPE_CHECKING:
12
+ from queue_func.config.queue import Config
13
+
14
+
15
+ class Broker(_BaseBroker["Config", Packed]):
16
+ """内存队列通道。队列由这里创建,再交给 Producer 和 Consumer。"""
17
+
18
+ __slots__ = (
19
+ "_queue",
20
+ )
21
+
22
+ def __init__(self, config: "Config"):
23
+ self._queue: asyncio.Queue[Packed] = asyncio.Queue(maxsize=config.maxsize)
24
+ super().__init__(config)
25
+
26
+ def _create_producer(self) -> Producer[Packed]:
27
+
28
+ return Producer(
29
+ queue=self._queue,
30
+ publish_timeout=self._config.publish_timeout,
31
+ message=self._message,
32
+ )
33
+
34
+ def _create_consumer(self) -> Consumer[Packed]:
35
+
36
+ return Consumer(
37
+ queue=self._queue,
38
+ consume_timeout=self._config.consume_timeout,
39
+ message=self._message,
40
+ coro=self._config.coro,
41
+ enable_consumer=self._config.enable_consumer,
42
+ pool_executor_cls=self._config.consumer_pool_executor_cls,
43
+ pool_maxsize=self._config.consumer_pool_maxsize,
44
+ )
@@ -0,0 +1 @@
1
+ # coding: utf-8
@@ -0,0 +1,32 @@
1
+ # coding: utf-8
2
+
3
+ import typing as t
4
+
5
+ from pydantic.dataclasses import dataclass as pyd_dataclass
6
+
7
+ from queue_func.config.utils import ExtraIgnoreConfig
8
+ from queue_func.message.base import BaseMessage
9
+ from queue_func.message.general import Message
10
+ from queue_func.serializer.base import BaseSerializer
11
+ from queue_func.serializer.orjson_ser import OrJSONSerializer
12
+ from queue_func.pool_executor.base import BasePoolExecutor
13
+ from queue_func.pool_executor.general import PoolExecutor
14
+
15
+
16
+ @pyd_dataclass(frozen=True, config=ExtraIgnoreConfig)
17
+ class Config:
18
+
19
+ # consumer
20
+ coro: t.Callable[[...], t.Coroutine]
21
+ enable_consumer: bool = True
22
+ consume_timeout: float = 2.0
23
+ consumer_pool_executor_cls: type[BasePoolExecutor] = PoolExecutor
24
+ consumer_pool_maxsize: int = 200
25
+
26
+ # broker
27
+ message_cls: type[BaseMessage] = Message
28
+ message_serializer_cls: type[BaseSerializer] = OrJSONSerializer
29
+ enable_message_serializer: bool = True
30
+
31
+ # producer
32
+ publish_timeout: float | None = None
@@ -0,0 +1,14 @@
1
+ # coding: utf-8
2
+
3
+ import typing as t
4
+ from pydantic.dataclasses import dataclass as pyd_dataclass
5
+
6
+ from queue_func.config.utils import ExtraIgnoreConfig
7
+ from queue_func.config.general import Config as _Config
8
+
9
+
10
+ @pyd_dataclass(frozen=True, config=ExtraIgnoreConfig)
11
+ class Config(_Config):
12
+
13
+ # broker
14
+ maxsize: int = 200
@@ -0,0 +1,15 @@
1
+ # coding: utf-8
2
+
3
+ from pydantic.config import ConfigDict
4
+
5
+ __all__ = (
6
+ "ExtraIgnoreConfig",
7
+ )
8
+
9
+
10
+ ExtraIgnoreConfig = ConfigDict(
11
+ extra="ignore",
12
+ validate_assignment=True,
13
+ arbitrary_types_allowed=True,
14
+ coerce_numbers_to_str=True,
15
+ )
@@ -0,0 +1 @@
1
+ # coding: utf-8
@@ -0,0 +1,97 @@
1
+ # coding: utf-8
2
+
3
+ import abc
4
+ import asyncio
5
+ import logging
6
+ import contextlib
7
+ import typing as t
8
+ from functools import wraps
9
+
10
+ from queue_func.message.base import BaseMessage, Packed
11
+ from queue_func.pool_executor.base import BasePoolExecutor
12
+
13
+
14
+ class BaseConsumer(t.Generic[Packed], metaclass=abc.ABCMeta):
15
+
16
+ __slots__ = (
17
+ "_message",
18
+ "_coro",
19
+ "_enable_consumer",
20
+ "_pool_executor",
21
+ "_task",
22
+ "_stop_flag",
23
+ "_logger",
24
+ )
25
+
26
+ def __init__(
27
+ self,
28
+ message: BaseMessage[Packed],
29
+ coro: t.Callable[..., t.Coroutine],
30
+ enable_consumer: bool,
31
+ pool_executor_cls: type[BasePoolExecutor],
32
+ pool_maxsize: int):
33
+
34
+ self._message = message
35
+ self._coro = coro
36
+ self._enable_consumer = enable_consumer
37
+ self._pool_executor = self._init_pool_executor(pool_executor_cls, pool_maxsize)
38
+ self._task: asyncio.Task | None = None
39
+ self._stop_flag = False
40
+ self._logger = logging.getLogger(__name__)
41
+
42
+ def _init_pool_executor(
43
+ self,
44
+ consumer_pool_executor_cls: type[BasePoolExecutor],
45
+ consumer_pool_maxsize: int) -> BasePoolExecutor | None:
46
+
47
+ if self._enable_consumer:
48
+ return consumer_pool_executor_cls(consumer_pool_maxsize)
49
+ return None
50
+
51
+ def _run_until_stopped(
52
+ self,
53
+ coro: t.Callable[..., t.Awaitable],
54
+ delay: float = 0.02) -> t.Callable[..., t.Coroutine]:
55
+
56
+ @wraps(coro)
57
+ async def wrapped(*args, **kwargs) -> None:
58
+
59
+ while not self._stop_flag:
60
+ try:
61
+ await coro(*args, **kwargs)
62
+ except Exception as e:
63
+ self._logger.exception(e)
64
+ await asyncio.sleep(delay)
65
+
66
+ return wrapped
67
+
68
+ async def _dispatch(self, coro_args: tuple[t.Any], coro_kwargs: dict[str, t.Any], **_kwargs) -> None:
69
+
70
+ assert self._pool_executor is not None, "consumer pool not initialized"
71
+ await self._pool_executor.submit(self._coro, coro_args, coro_kwargs)
72
+
73
+ async def consume(self) -> None:
74
+
75
+ if self._enable_consumer:
76
+ self._stop_flag = False
77
+ consume_loop = self._run_until_stopped(self._consume)
78
+ self._task = asyncio.create_task(consume_loop())
79
+ return None
80
+
81
+ @abc.abstractmethod
82
+ async def _consume(self) -> None: # pragma: no cover
83
+
84
+ pass
85
+
86
+ async def stop(self) -> None:
87
+
88
+ self._stop_flag = True
89
+
90
+ async def join(self) -> None:
91
+
92
+ if self._task is not None:
93
+ with contextlib.suppress(asyncio.CancelledError):
94
+ await self._task
95
+
96
+ if self._pool_executor is not None:
97
+ await self._pool_executor.join()
@@ -0,0 +1,55 @@
1
+ # coding: utf-8
2
+
3
+ import asyncio
4
+ import typing as t
5
+
6
+ from queue_func.message.base import BaseMessage, Packed
7
+ from queue_func.pool_executor.base import BasePoolExecutor
8
+ from queue_func.consumer.base import BaseConsumer as _BaseConsumer
9
+
10
+
11
+ class Consumer(_BaseConsumer[Packed]):
12
+
13
+ __slots__ = (
14
+ "_queue",
15
+ "_consume_timeout",
16
+ )
17
+
18
+ def __init__(
19
+ self,
20
+ queue: asyncio.Queue[Packed],
21
+ consume_timeout: float,
22
+ message: BaseMessage[Packed],
23
+ coro: t.Callable[..., t.Coroutine],
24
+ enable_consumer: bool,
25
+ pool_executor_cls: type[BasePoolExecutor],
26
+ pool_maxsize: int):
27
+
28
+ super().__init__(
29
+ message,
30
+ coro,
31
+ enable_consumer,
32
+ pool_executor_cls,
33
+ pool_maxsize,
34
+ )
35
+ self._queue = queue
36
+ self._consume_timeout = consume_timeout
37
+
38
+ async def _consume(self) -> None:
39
+
40
+ while (not self._stop_flag) or (not self._queue.empty()):
41
+ try:
42
+ message: Packed = await asyncio.wait_for(
43
+ self._queue.get(),
44
+ timeout=self._consume_timeout,
45
+ )
46
+ except asyncio.TimeoutError:
47
+ continue
48
+ coro_args, coro_kwargs = self._message.unpack(message)
49
+ await self._dispatch(coro_args, coro_kwargs)
50
+ self._queue.task_done()
51
+
52
+ async def join(self) -> None:
53
+
54
+ await super().join()
55
+ await self._queue.join()
@@ -0,0 +1,12 @@
1
+ # coding: utf-8
2
+
3
+ from queue_func.factory.backend import Backend
4
+ from queue_func.factory.deco import QueueFunc, queue
5
+ from queue_func.factory.runtime import QueueFuncRuntime
6
+
7
+ __all__ = (
8
+ "Backend",
9
+ "QueueFunc",
10
+ "QueueFuncRuntime",
11
+ "queue",
12
+ )
@@ -0,0 +1,13 @@
1
+ # coding: utf-8
2
+
3
+ from enum import StrEnum, unique
4
+
5
+ __all__ = (
6
+ "Backend",
7
+ )
8
+
9
+
10
+ @unique
11
+ class Backend(StrEnum):
12
+
13
+ QUEUE = "queue"
@@ -0,0 +1,9 @@
1
+ # coding: utf-8
2
+
3
+ """Import builder modules so they register with :func:`register_backend`."""
4
+
5
+ from queue_func.factory.builders import queue as queue
6
+
7
+ __all__ = (
8
+ "queue",
9
+ )
@@ -0,0 +1,20 @@
1
+ # coding: utf-8
2
+
3
+ import typing as t
4
+
5
+ from queue_func.factory.backend import Backend
6
+ from queue_func.factory.registry import register_backend
7
+
8
+ if t.TYPE_CHECKING:
9
+ from queue_func.broker.base import BaseBroker
10
+
11
+
12
+ @register_backend(Backend.QUEUE)
13
+ def build_queue_broker(
14
+ coro: t.Callable[..., t.Coroutine],
15
+ **kwargs: t.Any) -> "BaseBroker[t.Any, t.Any]":
16
+
17
+ from queue_func.broker.queue import Broker
18
+ from queue_func.config.queue import Config
19
+
20
+ return Broker(Config(coro=coro, **kwargs))
@@ -0,0 +1,93 @@
1
+ # coding: utf-8
2
+
3
+ import typing as t
4
+
5
+ from queue_func.factory import builders as _builders # noqa: F401 — register backends
6
+ from queue_func.factory.backend import Backend
7
+ from queue_func.factory.registry import build_broker
8
+
9
+ if t.TYPE_CHECKING:
10
+ from queue_func.broker.base import BaseBroker
11
+ from queue_func.config.general import Config as GeneralConfig
12
+ from queue_func.message.base import BaseMessage
13
+ from queue_func.pool_executor.base import BasePoolExecutor
14
+ from queue_func.serializer.base import BaseSerializer
15
+
16
+ _P = t.ParamSpec("_P")
17
+ _R = t.TypeVar("_R")
18
+
19
+ __all__ = (
20
+ "QueueFunc",
21
+ "queue",
22
+ )
23
+
24
+
25
+ class QueueFunc(t.Generic[_P, _R]):
26
+ """可调用协程,并附带 push。"""
27
+
28
+ def __init__(
29
+ self,
30
+ fn: t.Callable[_P, t.Coroutine[t.Any, t.Any, _R]],
31
+ broker: "BaseBroker[t.Any, t.Any]") -> None:
32
+
33
+ self._fn = fn
34
+ self._broker = broker
35
+ self.__wrapped__ = fn
36
+ self.__name__ = fn.__name__
37
+ self.__qualname__ = fn.__qualname__
38
+ self.__doc__ = fn.__doc__
39
+ self.__annotations__ = getattr(fn, "__annotations__", {})
40
+
41
+ async def __call__(self, *args: _P.args, **kwargs: _P.kwargs) -> _R:
42
+
43
+ return await self._fn(*args, **kwargs)
44
+
45
+ async def push(
46
+ self,
47
+ *,
48
+ args: tuple[t.Any, ...] = (),
49
+ kwargs: dict[str, t.Any] | None = None) -> None:
50
+
51
+ await self._broker.publish(coro_args=args, coro_kwargs=kwargs)
52
+
53
+ @property
54
+ def broker(self) -> "BaseBroker[t.Any, t.Any]":
55
+
56
+ return self._broker
57
+
58
+
59
+ def _queue_impl(
60
+ backend: Backend,
61
+ **config_kwargs: t.Any) -> t.Callable[[t.Callable[_P, t.Coroutine[t.Any, t.Any, _R]]], QueueFunc[_P, _R]]:
62
+
63
+ def decorator(fn: t.Callable[_P, t.Coroutine[t.Any, t.Any, _R]]) -> QueueFunc[_P, _R]:
64
+
65
+ broker = build_broker(backend, fn, **config_kwargs)
66
+ return QueueFunc(fn, broker)
67
+
68
+ return decorator
69
+
70
+
71
+ @t.overload
72
+ def queue(
73
+ backend: t.Literal[Backend.QUEUE],
74
+ *,
75
+ enable_consumer: bool = ...,
76
+ consume_timeout: float = ...,
77
+ consumer_pool_executor_cls: type["BasePoolExecutor"] = ...,
78
+ consumer_pool_maxsize: int = ...,
79
+ message_cls: type["BaseMessage"] = ...,
80
+ message_serializer_cls: type["BaseSerializer"] = ...,
81
+ enable_message_serializer: bool = ...,
82
+ publish_timeout: float | None = ...,
83
+ maxsize: int = ...,
84
+ ) -> t.Callable[[t.Callable[_P, t.Coroutine[t.Any, t.Any, _R]]], QueueFunc[_P, _R]]:
85
+
86
+ ...
87
+
88
+
89
+ def queue(
90
+ backend: Backend,
91
+ **config_kwargs: t.Any) -> t.Callable[[t.Callable[_P, t.Coroutine[t.Any, t.Any, _R]]], QueueFunc[_P, _R]]:
92
+
93
+ return _queue_impl(backend, **config_kwargs)
@@ -0,0 +1,41 @@
1
+ # coding: utf-8
2
+
3
+ import typing as t
4
+
5
+ from queue_func.factory.backend import Backend
6
+
7
+ if t.TYPE_CHECKING:
8
+ from queue_func.broker.base import BaseBroker
9
+
10
+ __all__ = (
11
+ "register_backend",
12
+ "build_broker",
13
+ )
14
+
15
+ BrokerBuilder = t.Callable[..., "BaseBroker[t.Any, t.Any]"]
16
+
17
+ _BUILDERS: dict[Backend, BrokerBuilder] = {}
18
+
19
+
20
+ def register_backend(backend: Backend) -> t.Callable[[BrokerBuilder], BrokerBuilder]:
21
+
22
+ def decorator(fn: BrokerBuilder) -> BrokerBuilder:
23
+
24
+ if backend in _BUILDERS:
25
+ raise ValueError(f"backend {backend!r} is already registered")
26
+ _BUILDERS[backend] = fn
27
+ return fn
28
+
29
+ return decorator
30
+
31
+
32
+ def build_broker(
33
+ backend: Backend,
34
+ coro: t.Callable[..., t.Coroutine],
35
+ **kwargs: t.Any) -> "BaseBroker[t.Any, t.Any]":
36
+
37
+ try:
38
+ builder = _BUILDERS[backend]
39
+ except KeyError:
40
+ raise NotImplementedError(f"backend {backend!r} is not implemented yet") from None
41
+ return builder(coro, **kwargs)
@@ -0,0 +1,40 @@
1
+ # coding: utf-8
2
+
3
+ import typing as t
4
+
5
+ from queue_func.factory.deco import QueueFunc
6
+
7
+ __all__ = (
8
+ "QueueFuncRuntime",
9
+ )
10
+
11
+
12
+ class QueueFuncRuntime:
13
+ """按固定顺序批量启动 / 关闭多个 :class:`QueueFunc`。
14
+
15
+ stop:consumer 逐个 stop → join;producer 先全体 stop,再全体 join。
16
+ """
17
+
18
+ __slots__ = (
19
+ "_funcs",
20
+ )
21
+
22
+ def __init__(self, funcs: t.Iterable[QueueFunc[t.Any, t.Any]]) -> None:
23
+
24
+ self._funcs = list(funcs)
25
+
26
+ async def start(self) -> None:
27
+
28
+ for func in reversed(self._funcs):
29
+ await func.broker.start_consumer()
30
+
31
+ async def stop(self) -> None:
32
+
33
+ for func in self._funcs:
34
+ await func.broker.stop_consumer()
35
+ await func.broker.join_consumer()
36
+
37
+ for func in self._funcs:
38
+ await func.broker.stop_producer()
39
+ for func in self._funcs:
40
+ await func.broker.join_producer()
@@ -0,0 +1 @@
1
+ # coding: utf-8
@@ -0,0 +1,39 @@
1
+ # coding: utf-8
2
+
3
+ import abc
4
+ import typing as t
5
+
6
+ from queue_func.serializer.base import BaseSerializer
7
+
8
+ Packed = t.TypeVar("Packed")
9
+
10
+ type ArgsMessage = tuple[tuple[t.Any], dict[str, t.Any]]
11
+
12
+
13
+ class BaseMessage(t.Generic[Packed], metaclass=abc.ABCMeta):
14
+
15
+ __slots__ = (
16
+ "_enable_serializer",
17
+ "_serializer",
18
+ )
19
+
20
+ def __init__(
21
+ self,
22
+ message_serializer_cls: type[BaseSerializer],
23
+ enable_serializer: bool):
24
+
25
+ self._serializer = message_serializer_cls()
26
+ self._enable_serializer = enable_serializer
27
+
28
+ @abc.abstractmethod
29
+ def pack(
30
+ self,
31
+ coro_args: tuple[t.Any],
32
+ coro_kwargs: dict[str, t.Any] | None = None) -> Packed:
33
+
34
+ pass
35
+
36
+ @abc.abstractmethod
37
+ def unpack(self, message: Packed) -> ArgsMessage:
38
+
39
+ pass
@@ -0,0 +1,30 @@
1
+ # coding: utf-8
2
+
3
+ import typing as t
4
+
5
+ from queue_func.message.base import ArgsMessage, BaseMessage
6
+
7
+ type PackedMessage = ArgsMessage | bytes
8
+
9
+
10
+ class Message(BaseMessage[PackedMessage]):
11
+
12
+ __slots__ = ()
13
+
14
+ def pack(
15
+ self,
16
+ coro_args: tuple[t.Any],
17
+ coro_kwargs: dict[str, t.Any] | None = None) -> PackedMessage:
18
+
19
+ if coro_kwargs is None:
20
+ coro_kwargs = {}
21
+ message: ArgsMessage = (coro_args, coro_kwargs)
22
+ if self._enable_serializer:
23
+ return self._serializer.dumps(message, return_bytes=True)
24
+ return message
25
+
26
+ def unpack(self, message: PackedMessage) -> ArgsMessage:
27
+
28
+ if self._enable_serializer:
29
+ return t.cast(ArgsMessage, self._serializer.loads(message))
30
+ return t.cast(ArgsMessage, message)
@@ -0,0 +1 @@
1
+ # coding: utf-8