From c5604e94e32d16908bac78c14b369451cc50b444 Mon Sep 17 00:00:00 2001 From: umair Date: Thu, 3 Sep 2026 13:21:21 +0100 Subject: [PATCH 1/7] Move the ably package to core/src/ably_pubsub/core MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Pure relocation plus the mechanical import rewrite that follows from it. The PubSub package split (PDR-091b) builds two distributions out of this repo, so today's single `ably` import package becomes `ably_pubsub.core` under a `core/` workspace member laid out src-style. `git mv` throughout so history follows the files. Every `from ably.x import y` becomes `from ably_pubsub.core.x import y`, and the dotted module paths that appear as strings — mock.patch targets, logger names, and the unasync generator's own replacement tables — move with them. No behaviour changes here; the packaging, the agent header and the new server package land separately. Co-Authored-By: Claude Opus 5 --- ably/__init__.py | 24 ---------- core/src/ably_pubsub/core/__init__.py | 24 ++++++++++ .../src/ably_pubsub/core}/http/__init__.py | 0 .../src/ably_pubsub/core}/http/http.py | 10 ++--- .../src/ably_pubsub/core}/http/httputils.py | 6 +-- .../ably_pubsub/core}/http/paginatedresult.py | 4 +- .../ably_pubsub/core}/realtime/__init__.py | 0 .../ably_pubsub/core}/realtime/annotations.py | 18 ++++---- .../src/ably_pubsub/core}/realtime/channel.py | 38 ++++++++-------- .../ably_pubsub/core}/realtime/connection.py | 12 ++--- .../core}/realtime/connectionmanager.py | 22 +++++----- .../ably_pubsub/core}/realtime/presence.py | 16 +++---- .../ably_pubsub/core}/realtime/presencemap.py | 2 +- .../ably_pubsub/core}/realtime/realtime.py | 6 +-- .../src/ably_pubsub/core}/rest/__init__.py | 0 .../src/ably_pubsub/core}/rest/annotations.py | 10 ++--- .../src/ably_pubsub/core}/rest/auth.py | 18 ++++---- .../src/ably_pubsub/core}/rest/channel.py | 16 +++---- .../src/ably_pubsub/core}/rest/push.py | 6 +-- .../src/ably_pubsub/core}/rest/rest.py | 18 ++++---- .../src/ably_pubsub/core}/scripts/__init__.py | 0 .../src/ably_pubsub/core}/scripts/unasync.py | 16 +++---- .../ably_pubsub/core}/transport/__init__.py | 0 .../ably_pubsub/core}/transport/defaults.py | 0 .../core}/transport/websockettransport.py | 14 +++--- .../src/ably_pubsub/core}/types/__init__.py | 0 .../src/ably_pubsub/core}/types/annotation.py | 10 ++--- .../ably_pubsub/core}/types/authoptions.py | 2 +- .../src/ably_pubsub/core}/types/capability.py | 0 .../ably_pubsub/core}/types/channeldetails.py | 0 .../ably_pubsub/core}/types/channelmode.py | 2 +- .../ably_pubsub/core}/types/channeloptions.py | 6 +-- .../ably_pubsub/core}/types/channelstate.py | 2 +- .../core}/types/channelsubscription.py | 2 +- .../core}/types/connectiondetails.py | 0 .../core}/types/connectionerrors.py | 4 +- .../core}/types/connectionstate.py | 2 +- .../src/ably_pubsub/core}/types/device.py | 2 +- .../src/ably_pubsub/core}/types/flags.py | 0 .../src/ably_pubsub/core}/types/message.py | 12 ++--- .../src/ably_pubsub/core}/types/mixins.py | 4 +- .../src/ably_pubsub/core}/types/operations.py | 0 .../src/ably_pubsub/core}/types/options.py | 8 ++-- .../src/ably_pubsub/core}/types/presence.py | 10 ++--- .../src/ably_pubsub/core}/types/stats.py | 0 .../ably_pubsub/core}/types/tokendetails.py | 2 +- .../ably_pubsub/core}/types/tokenrequest.py | 0 .../ably_pubsub/core}/types/typedbuffer.py | 0 .../src/ably_pubsub/core}/util/__init__.py | 0 .../src/ably_pubsub/core}/util/case.py | 0 .../src/ably_pubsub/core}/util/crypto.py | 4 +- .../src/ably_pubsub/core}/util/encoding.py | 4 +- .../ably_pubsub/core}/util/eventemitter.py | 2 +- .../src/ably_pubsub/core}/util/exceptions.py | 0 .../src/ably_pubsub/core}/util/helper.py | 2 +- .../src/ably_pubsub/core}/util/nocrypto.py | 0 .../src/ably_pubsub/core}/vcdiff/__init__.py | 0 .../core}/vcdiff/defaultvcdiffdecoder.py | 6 +-- test/ably/realtime/eventemitter_test.py | 2 +- test/ably/realtime/presencemap_test.py | 4 +- .../ably/realtime/realtimeannotations_test.py | 10 ++--- test/ably/realtime/realtimeauth_test.py | 10 ++--- .../realtime/realtimechannel_publish_test.py | 22 +++++----- test/ably/realtime/realtimechannel_test.py | 12 ++--- .../realtime/realtimechannel_vcdiff_test.py | 8 ++-- .../realtimechannelmutablemessages_test.py | 6 +-- test/ably/realtime/realtimeconnection_test.py | 8 ++-- test/ably/realtime/realtimeinit_test.py | 6 +-- test/ably/realtime/realtimepresence_test.py | 8 ++-- test/ably/realtime/realtimeresume_test.py | 6 +-- test/ably/rest/encoders_test.py | 44 +++++++++---------- test/ably/rest/restannotations_test.py | 6 +-- test/ably/rest/restauth_test.py | 22 +++++----- test/ably/rest/restcapability_test.py | 4 +- test/ably/rest/restchannelhistory_test.py | 4 +- .../rest/restchannelmutablemessages_test.py | 6 +-- test/ably/rest/restchannelpublish_test.py | 16 +++---- test/ably/rest/restchannels_test.py | 6 +-- test/ably/rest/restcrypto_test.py | 6 +-- test/ably/rest/resthttp_test.py | 8 ++-- test/ably/rest/restinit_test.py | 10 ++--- test/ably/rest/restpaginatedresult_test.py | 2 +- test/ably/rest/restpresence_test.py | 4 +- test/ably/rest/restpush_test.py | 4 +- test/ably/rest/restrequest_test.py | 6 +-- test/ably/rest/reststats_test.py | 6 +-- test/ably/rest/resttime_test.py | 2 +- test/ably/rest/resttoken_test.py | 24 +++++----- test/ably/testapp.py | 12 ++--- test/ably/utils.py | 2 +- test/unit/annotation_test.py | 10 ++--- test/unit/http_test.py | 2 +- test/unit/message_test.py | 6 +-- test/unit/mutable_message_test.py | 6 +-- test/unit/options_test.py | 4 +- 95 files changed, 345 insertions(+), 345 deletions(-) delete mode 100644 ably/__init__.py create mode 100644 core/src/ably_pubsub/core/__init__.py rename {ably => core/src/ably_pubsub/core}/http/__init__.py (100%) rename {ably => core/src/ably_pubsub/core}/http/http.py (97%) rename {ably => core/src/ably_pubsub/core}/http/httputils.py (87%) rename {ably => core/src/ably_pubsub/core}/http/paginatedresult.py (97%) rename {ably => core/src/ably_pubsub/core}/realtime/__init__.py (100%) rename {ably => core/src/ably_pubsub/core}/realtime/annotations.py (93%) rename {ably => core/src/ably_pubsub/core}/realtime/channel.py (96%) rename {ably => core/src/ably_pubsub/core}/realtime/connection.py (90%) rename {ably => core/src/ably_pubsub/core}/realtime/connectionmanager.py (97%) rename {ably => core/src/ably_pubsub/core}/realtime/presence.py (98%) rename {ably => core/src/ably_pubsub/core}/realtime/presencemap.py (99%) rename {ably => core/src/ably_pubsub/core}/realtime/realtime.py (97%) rename {ably => core/src/ably_pubsub/core}/rest/__init__.py (100%) rename {ably => core/src/ably_pubsub/core}/rest/annotations.py (96%) rename {ably => core/src/ably_pubsub/core}/rest/auth.py (96%) rename {ably => core/src/ably_pubsub/core}/rest/channel.py (96%) rename {ably => core/src/ably_pubsub/core}/rest/push.py (96%) rename {ably => core/src/ably_pubsub/core}/rest/rest.py (90%) rename {ably => core/src/ably_pubsub/core}/scripts/__init__.py (100%) rename {ably => core/src/ably_pubsub/core}/scripts/unasync.py (93%) rename {ably => core/src/ably_pubsub/core}/transport/__init__.py (100%) rename {ably => core/src/ably_pubsub/core}/transport/defaults.py (100%) rename {ably => core/src/ably_pubsub/core}/transport/websockettransport.py (96%) rename {ably => core/src/ably_pubsub/core}/types/__init__.py (100%) rename {ably => core/src/ably_pubsub/core}/types/annotation.py (97%) rename {ably => core/src/ably_pubsub/core}/types/authoptions.py (98%) rename {ably => core/src/ably_pubsub/core}/types/capability.py (100%) rename {ably => core/src/ably_pubsub/core}/types/channeldetails.py (100%) rename {ably => core/src/ably_pubsub/core}/types/channelmode.py (96%) rename {ably => core/src/ably_pubsub/core}/types/channeloptions.py (93%) rename {ably => core/src/ably_pubsub/core}/types/channelstate.py (88%) rename {ably => core/src/ably_pubsub/core}/types/channelsubscription.py (97%) rename {ably => core/src/ably_pubsub/core}/types/connectiondetails.py (100%) rename {ably => core/src/ably_pubsub/core}/types/connectionerrors.py (83%) rename {ably => core/src/ably_pubsub/core}/types/connectionstate.py (93%) rename {ably => core/src/ably_pubsub/core}/types/device.py (98%) rename {ably => core/src/ably_pubsub/core}/types/flags.py (100%) rename {ably => core/src/ably_pubsub/core}/types/message.py (97%) rename {ably => core/src/ably_pubsub/core}/types/mixins.py (97%) rename {ably => core/src/ably_pubsub/core}/types/operations.py (100%) rename {ably => core/src/ably_pubsub/core}/types/options.py (97%) rename {ably => core/src/ably_pubsub/core}/types/presence.py (96%) rename {ably => core/src/ably_pubsub/core}/types/stats.py (100%) rename {ably => core/src/ably_pubsub/core}/types/tokendetails.py (97%) rename {ably => core/src/ably_pubsub/core}/types/tokenrequest.py (100%) rename {ably => core/src/ably_pubsub/core}/types/typedbuffer.py (100%) rename {ably => core/src/ably_pubsub/core}/util/__init__.py (100%) rename {ably => core/src/ably_pubsub/core}/util/case.py (100%) rename {ably => core/src/ably_pubsub/core}/util/crypto.py (97%) rename {ably => core/src/ably_pubsub/core}/util/encoding.py (90%) rename {ably => core/src/ably_pubsub/core}/util/eventemitter.py (99%) rename {ably => core/src/ably_pubsub/core}/util/exceptions.py (100%) rename {ably => core/src/ably_pubsub/core}/util/helper.py (98%) rename {ably => core/src/ably_pubsub/core}/util/nocrypto.py (100%) rename {ably => core/src/ably_pubsub/core}/vcdiff/__init__.py (100%) rename {ably => core/src/ably_pubsub/core}/vcdiff/defaultvcdiffdecoder.py (92%) diff --git a/ably/__init__.py b/ably/__init__.py deleted file mode 100644 index e050b7c5..00000000 --- a/ably/__init__.py +++ /dev/null @@ -1,24 +0,0 @@ -import logging - -from ably.realtime.realtime import AblyRealtime -from ably.rest.auth import Auth -from ably.rest.push import Push -from ably.rest.rest import AblyRest -from ably.types.annotation import Annotation, AnnotationAction -from ably.types.capability import Capability -from ably.types.channelmode import ChannelMode -from ably.types.channeloptions import ChannelOptions -from ably.types.channelsubscription import PushChannelSubscription -from ably.types.device import DeviceDetails -from ably.types.message import MessageAction, MessageVersion -from ably.types.operations import MessageOperation, PublishResult, UpdateDeleteResult -from ably.types.options import Options, VCDiffDecoder -from ably.util.crypto import CipherParams -from ably.util.exceptions import AblyAuthException, AblyException, IncompatibleClientIdException -from ably.vcdiff.defaultvcdiffdecoder import AblyVCDiffDecoder - -logger = logging.getLogger(__name__) -logger.addHandler(logging.NullHandler()) - -api_version = '5' -lib_version = '3.1.2' diff --git a/core/src/ably_pubsub/core/__init__.py b/core/src/ably_pubsub/core/__init__.py new file mode 100644 index 00000000..80775b78 --- /dev/null +++ b/core/src/ably_pubsub/core/__init__.py @@ -0,0 +1,24 @@ +import logging + +from ably_pubsub.core.realtime.realtime import AblyRealtime +from ably_pubsub.core.rest.auth import Auth +from ably_pubsub.core.rest.push import Push +from ably_pubsub.core.rest.rest import AblyRest +from ably_pubsub.core.types.annotation import Annotation, AnnotationAction +from ably_pubsub.core.types.capability import Capability +from ably_pubsub.core.types.channelmode import ChannelMode +from ably_pubsub.core.types.channeloptions import ChannelOptions +from ably_pubsub.core.types.channelsubscription import PushChannelSubscription +from ably_pubsub.core.types.device import DeviceDetails +from ably_pubsub.core.types.message import MessageAction, MessageVersion +from ably_pubsub.core.types.operations import MessageOperation, PublishResult, UpdateDeleteResult +from ably_pubsub.core.types.options import Options, VCDiffDecoder +from ably_pubsub.core.util.crypto import CipherParams +from ably_pubsub.core.util.exceptions import AblyAuthException, AblyException, IncompatibleClientIdException +from ably_pubsub.core.vcdiff.defaultvcdiffdecoder import AblyVCDiffDecoder + +logger = logging.getLogger(__name__) +logger.addHandler(logging.NullHandler()) + +api_version = '5' +lib_version = '3.1.2' diff --git a/ably/http/__init__.py b/core/src/ably_pubsub/core/http/__init__.py similarity index 100% rename from ably/http/__init__.py rename to core/src/ably_pubsub/core/http/__init__.py diff --git a/ably/http/http.py b/core/src/ably_pubsub/core/http/http.py similarity index 97% rename from ably/http/http.py rename to core/src/ably_pubsub/core/http/http.py index d21a9386..6b184f6c 100644 --- a/ably/http/http.py +++ b/core/src/ably_pubsub/core/http/http.py @@ -7,11 +7,11 @@ import httpx import msgpack -from ably.http.httputils import HttpUtils -from ably.rest.auth import Auth -from ably.transport.defaults import Defaults -from ably.util.exceptions import AblyException -from ably.util.helper import extract_url_params, is_token_error +from ably_pubsub.core.http.httputils import HttpUtils +from ably_pubsub.core.rest.auth import Auth +from ably_pubsub.core.transport.defaults import Defaults +from ably_pubsub.core.util.exceptions import AblyException +from ably_pubsub.core.util.helper import extract_url_params, is_token_error log = logging.getLogger(__name__) diff --git a/ably/http/httputils.py b/core/src/ably_pubsub/core/http/httputils.py similarity index 87% rename from ably/http/httputils.py rename to core/src/ably_pubsub/core/http/httputils.py index aca46b0f..df96e71e 100644 --- a/ably/http/httputils.py +++ b/core/src/ably_pubsub/core/http/httputils.py @@ -2,7 +2,7 @@ import os import platform -import ably +import ably_pubsub.core class HttpUtils: @@ -39,10 +39,10 @@ def get_host_header(host): @staticmethod def default_headers(version=None): if version is None: - version = ably.api_version + version = ably_pubsub.core.api_version return { "X-Ably-Version": version, - "Ably-Agent": f'ably-python/{ably.lib_version} python/{platform.python_version()}' + "Ably-Agent": f'ably-python/{ably_pubsub.core.lib_version} python/{platform.python_version()}' } @staticmethod diff --git a/ably/http/paginatedresult.py b/core/src/ably_pubsub/core/http/paginatedresult.py similarity index 97% rename from ably/http/paginatedresult.py rename to core/src/ably_pubsub/core/http/paginatedresult.py index a034d9d1..9b4c629f 100644 --- a/ably/http/paginatedresult.py +++ b/core/src/ably_pubsub/core/http/paginatedresult.py @@ -2,8 +2,8 @@ import logging from urllib.parse import urlencode -from ably.http.http import Request -from ably.util import case +from ably_pubsub.core.http.http import Request +from ably_pubsub.core.util import case log = logging.getLogger(__name__) diff --git a/ably/realtime/__init__.py b/core/src/ably_pubsub/core/realtime/__init__.py similarity index 100% rename from ably/realtime/__init__.py rename to core/src/ably_pubsub/core/realtime/__init__.py diff --git a/ably/realtime/annotations.py b/core/src/ably_pubsub/core/realtime/annotations.py similarity index 93% rename from ably/realtime/annotations.py rename to core/src/ably_pubsub/core/realtime/annotations.py index 57400d45..d743c56b 100644 --- a/ably/realtime/annotations.py +++ b/core/src/ably_pubsub/core/realtime/annotations.py @@ -3,17 +3,17 @@ import logging from typing import TYPE_CHECKING -from ably.rest.annotations import RestAnnotations, construct_validate_annotation -from ably.transport.websockettransport import ProtocolMessageAction -from ably.types.annotation import Annotation, AnnotationAction -from ably.types.channelmode import ChannelMode -from ably.types.channelstate import ChannelState -from ably.util.eventemitter import EventEmitter -from ably.util.helper import is_callable_or_coroutine +from ably_pubsub.core.rest.annotations import RestAnnotations, construct_validate_annotation +from ably_pubsub.core.transport.websockettransport import ProtocolMessageAction +from ably_pubsub.core.types.annotation import Annotation, AnnotationAction +from ably_pubsub.core.types.channelmode import ChannelMode +from ably_pubsub.core.types.channelstate import ChannelState +from ably_pubsub.core.util.eventemitter import EventEmitter +from ably_pubsub.core.util.helper import is_callable_or_coroutine if TYPE_CHECKING: - from ably.realtime.channel import RealtimeChannel - from ably.realtime.connectionmanager import ConnectionManager + from ably_pubsub.core.realtime.channel import RealtimeChannel + from ably_pubsub.core.realtime.connectionmanager import ConnectionManager log = logging.getLogger(__name__) diff --git a/ably/realtime/channel.py b/core/src/ably_pubsub/core/realtime/channel.py similarity index 96% rename from ably/realtime/channel.py rename to core/src/ably_pubsub/core/realtime/channel.py index d5aa1a12..39014d72 100644 --- a/ably/realtime/channel.py +++ b/core/src/ably_pubsub/core/realtime/channel.py @@ -4,27 +4,27 @@ import logging from typing import TYPE_CHECKING -from ably.realtime.annotations import RealtimeAnnotations -from ably.realtime.connection import ConnectionState -from ably.realtime.presence import RealtimePresence -from ably.rest.channel import Channel -from ably.rest.channel import Channels as RestChannels -from ably.transport.websockettransport import ProtocolMessageAction -from ably.types.annotation import Annotation -from ably.types.channelmode import ChannelMode, decode_channel_mode, encode_channel_mode -from ably.types.channeloptions import ChannelOptions -from ably.types.channelstate import ChannelState, ChannelStateChange -from ably.types.flags import Flag, has_flag -from ably.types.message import Message, MessageAction, MessageVersion -from ably.types.mixins import DecodingContext -from ably.types.operations import MessageOperation, PublishResult, UpdateDeleteResult -from ably.types.presence import PresenceMessage -from ably.util.eventemitter import EventEmitter -from ably.util.exceptions import AblyException, IncompatibleClientIdException -from ably.util.helper import Timer, is_callable_or_coroutine, validate_message_size +from ably_pubsub.core.realtime.annotations import RealtimeAnnotations +from ably_pubsub.core.realtime.connection import ConnectionState +from ably_pubsub.core.realtime.presence import RealtimePresence +from ably_pubsub.core.rest.channel import Channel +from ably_pubsub.core.rest.channel import Channels as RestChannels +from ably_pubsub.core.transport.websockettransport import ProtocolMessageAction +from ably_pubsub.core.types.annotation import Annotation +from ably_pubsub.core.types.channelmode import ChannelMode, decode_channel_mode, encode_channel_mode +from ably_pubsub.core.types.channeloptions import ChannelOptions +from ably_pubsub.core.types.channelstate import ChannelState, ChannelStateChange +from ably_pubsub.core.types.flags import Flag, has_flag +from ably_pubsub.core.types.message import Message, MessageAction, MessageVersion +from ably_pubsub.core.types.mixins import DecodingContext +from ably_pubsub.core.types.operations import MessageOperation, PublishResult, UpdateDeleteResult +from ably_pubsub.core.types.presence import PresenceMessage +from ably_pubsub.core.util.eventemitter import EventEmitter +from ably_pubsub.core.util.exceptions import AblyException, IncompatibleClientIdException +from ably_pubsub.core.util.helper import Timer, is_callable_or_coroutine, validate_message_size if TYPE_CHECKING: - from ably.realtime.realtime import AblyRealtime + from ably_pubsub.core.realtime.realtime import AblyRealtime log = logging.getLogger(__name__) diff --git a/ably/realtime/connection.py b/core/src/ably_pubsub/core/realtime/connection.py similarity index 90% rename from ably/realtime/connection.py rename to core/src/ably_pubsub/core/realtime/connection.py index 907f56a5..c24d8837 100644 --- a/ably/realtime/connection.py +++ b/core/src/ably_pubsub/core/realtime/connection.py @@ -5,14 +5,14 @@ import logging from typing import TYPE_CHECKING -from ably.realtime.connectionmanager import ConnectionManager -from ably.types.connectiondetails import ConnectionDetails -from ably.types.connectionstate import ConnectionEvent, ConnectionState, ConnectionStateChange -from ably.util.eventemitter import EventEmitter -from ably.util.exceptions import AblyException +from ably_pubsub.core.realtime.connectionmanager import ConnectionManager +from ably_pubsub.core.types.connectiondetails import ConnectionDetails +from ably_pubsub.core.types.connectionstate import ConnectionEvent, ConnectionState, ConnectionStateChange +from ably_pubsub.core.util.eventemitter import EventEmitter +from ably_pubsub.core.util.exceptions import AblyException if TYPE_CHECKING: - from ably.realtime.realtime import AblyRealtime + from ably_pubsub.core.realtime.realtime import AblyRealtime log = logging.getLogger(__name__) diff --git a/ably/realtime/connectionmanager.py b/core/src/ably_pubsub/core/realtime/connectionmanager.py similarity index 97% rename from ably/realtime/connectionmanager.py rename to core/src/ably_pubsub/core/realtime/connectionmanager.py index 8b51fb0f..0f049a81 100644 --- a/ably/realtime/connectionmanager.py +++ b/core/src/ably_pubsub/core/realtime/connectionmanager.py @@ -9,19 +9,19 @@ import httpx -from ably.transport.defaults import Defaults -from ably.transport.websockettransport import ProtocolMessageAction, WebSocketTransport -from ably.types.connectiondetails import ConnectionDetails -from ably.types.connectionerrors import ConnectionErrors -from ably.types.connectionstate import ConnectionEvent, ConnectionState, ConnectionStateChange -from ably.types.operations import PublishResult -from ably.types.tokendetails import TokenDetails -from ably.util.eventemitter import EventEmitter -from ably.util.exceptions import AblyException, IncompatibleClientIdException -from ably.util.helper import Timer, get_random_id, is_token_error +from ably_pubsub.core.transport.defaults import Defaults +from ably_pubsub.core.transport.websockettransport import ProtocolMessageAction, WebSocketTransport +from ably_pubsub.core.types.connectiondetails import ConnectionDetails +from ably_pubsub.core.types.connectionerrors import ConnectionErrors +from ably_pubsub.core.types.connectionstate import ConnectionEvent, ConnectionState, ConnectionStateChange +from ably_pubsub.core.types.operations import PublishResult +from ably_pubsub.core.types.tokendetails import TokenDetails +from ably_pubsub.core.util.eventemitter import EventEmitter +from ably_pubsub.core.util.exceptions import AblyException, IncompatibleClientIdException +from ably_pubsub.core.util.helper import Timer, get_random_id, is_token_error if TYPE_CHECKING: - from ably.realtime.realtime import AblyRealtime + from ably_pubsub.core.realtime.realtime import AblyRealtime log = logging.getLogger(__name__) diff --git a/ably/realtime/presence.py b/core/src/ably_pubsub/core/realtime/presence.py similarity index 98% rename from ably/realtime/presence.py rename to core/src/ably_pubsub/core/realtime/presence.py index 79d73070..dc578e91 100644 --- a/ably/realtime/presence.py +++ b/core/src/ably_pubsub/core/realtime/presence.py @@ -12,15 +12,15 @@ from datetime import datetime, timezone from typing import TYPE_CHECKING, Any -from ably.realtime.connection import ConnectionState -from ably.realtime.presencemap import PresenceMap -from ably.types.channelstate import ChannelState, ChannelStateChange -from ably.types.presence import PresenceAction, PresenceMessage -from ably.util.eventemitter import EventEmitter -from ably.util.exceptions import AblyException +from ably_pubsub.core.realtime.connection import ConnectionState +from ably_pubsub.core.realtime.presencemap import PresenceMap +from ably_pubsub.core.types.channelstate import ChannelState, ChannelStateChange +from ably_pubsub.core.types.presence import PresenceAction, PresenceMessage +from ably_pubsub.core.util.eventemitter import EventEmitter +from ably_pubsub.core.util.exceptions import AblyException if TYPE_CHECKING: - from ably.realtime.channel import RealtimeChannel + from ably_pubsub.core.realtime.channel import RealtimeChannel log = logging.getLogger(__name__) @@ -354,7 +354,7 @@ async def _send_presence(self, presence_messages: list[dict]) -> None: Args: presence_messages: List of encoded presence messages to send """ - from ably.transport.websockettransport import ProtocolMessageAction + from ably_pubsub.core.transport.websockettransport import ProtocolMessageAction protocol_msg = { 'action': ProtocolMessageAction.PRESENCE, diff --git a/ably/realtime/presencemap.py b/core/src/ably_pubsub/core/realtime/presencemap.py similarity index 99% rename from ably/realtime/presencemap.py rename to core/src/ably_pubsub/core/realtime/presencemap.py index 9c5adace..44e02336 100644 --- a/ably/realtime/presencemap.py +++ b/core/src/ably_pubsub/core/realtime/presencemap.py @@ -7,7 +7,7 @@ import logging from typing import Callable, Dict, List, Optional, Tuple -from ably.types.presence import PresenceAction, PresenceMessage +from ably_pubsub.core.types.presence import PresenceAction, PresenceMessage logger = logging.getLogger(__name__) diff --git a/ably/realtime/realtime.py b/core/src/ably_pubsub/core/realtime/realtime.py similarity index 97% rename from ably/realtime/realtime.py rename to core/src/ably_pubsub/core/realtime/realtime.py index ab435304..270193e1 100644 --- a/ably/realtime/realtime.py +++ b/core/src/ably_pubsub/core/realtime/realtime.py @@ -2,9 +2,9 @@ import logging from typing import Optional -from ably.realtime.channel import Channels -from ably.realtime.connection import Connection, ConnectionState -from ably.rest.rest import AblyRest +from ably_pubsub.core.realtime.channel import Channels +from ably_pubsub.core.realtime.connection import Connection, ConnectionState +from ably_pubsub.core.rest.rest import AblyRest log = logging.getLogger(__name__) diff --git a/ably/rest/__init__.py b/core/src/ably_pubsub/core/rest/__init__.py similarity index 100% rename from ably/rest/__init__.py rename to core/src/ably_pubsub/core/rest/__init__.py diff --git a/ably/rest/annotations.py b/core/src/ably_pubsub/core/rest/annotations.py similarity index 96% rename from ably/rest/annotations.py rename to core/src/ably_pubsub/core/rest/annotations.py index 588ffcf3..a049009f 100644 --- a/ably/rest/annotations.py +++ b/core/src/ably_pubsub/core/rest/annotations.py @@ -8,15 +8,15 @@ import msgpack -from ably.http.paginatedresult import PaginatedResult, format_params -from ably.types.annotation import ( +from ably_pubsub.core.http.paginatedresult import PaginatedResult, format_params +from ably_pubsub.core.types.annotation import ( Annotation, AnnotationAction, make_annotation_response_handler, ) -from ably.types.message import Message -from ably.types.options import Options -from ably.util.exceptions import AblyException +from ably_pubsub.core.types.message import Message +from ably_pubsub.core.types.options import Options +from ably_pubsub.core.util.exceptions import AblyException log = logging.getLogger(__name__) diff --git a/ably/rest/auth.py b/core/src/ably_pubsub/core/rest/auth.py similarity index 96% rename from ably/rest/auth.py rename to core/src/ably_pubsub/core/rest/auth.py index d2057533..e9fc0417 100644 --- a/ably/rest/auth.py +++ b/core/src/ably_pubsub/core/rest/auth.py @@ -9,17 +9,17 @@ import httpx -from ably.types.options import Options +from ably_pubsub.core.types.options import Options if TYPE_CHECKING: - from ably.realtime.realtime import AblyRealtime - from ably.rest.rest import AblyRest + from ably_pubsub.core.realtime.realtime import AblyRealtime + from ably_pubsub.core.rest.rest import AblyRest -from ably.types.capability import Capability -from ably.types.tokendetails import TokenDetails -from ably.types.tokenrequest import TokenRequest -from ably.util.exceptions import AblyAuthException, AblyException, IncompatibleClientIdException -from ably.util.helper import extract_url_params +from ably_pubsub.core.types.capability import Capability +from ably_pubsub.core.types.tokendetails import TokenDetails +from ably_pubsub.core.types.tokenrequest import TokenRequest +from ably_pubsub.core.util.exceptions import AblyAuthException, AblyException, IncompatibleClientIdException +from ably_pubsub.core.util.helper import extract_url_params __all__ = ["Auth"] @@ -411,7 +411,7 @@ async def token_request_from_auth_url(self, method: str, url: str, token_params, # Use clean URL for the request url = clean_url - from ably.http.http import Response + from ably_pubsub.core.http.http import Response async with httpx.AsyncClient(http2=True) as client: resp = await client.request(method=method, url=url, headers=headers, params=params, data=body) response = Response(resp) diff --git a/ably/rest/channel.py b/core/src/ably_pubsub/core/rest/channel.py similarity index 96% rename from ably/rest/channel.py rename to core/src/ably_pubsub/core/rest/channel.py index 32cc7e7e..6517efe1 100644 --- a/ably/rest/channel.py +++ b/core/src/ably_pubsub/core/rest/channel.py @@ -8,20 +8,20 @@ import msgpack -from ably.http.paginatedresult import PaginatedResult, format_params -from ably.rest.annotations import RestAnnotations -from ably.types.channeldetails import ChannelDetails -from ably.types.message import ( +from ably_pubsub.core.http.paginatedresult import PaginatedResult, format_params +from ably_pubsub.core.rest.annotations import RestAnnotations +from ably_pubsub.core.types.channeldetails import ChannelDetails +from ably_pubsub.core.types.message import ( Message, MessageAction, MessageVersion, make_message_response_handler, make_single_message_response_handler, ) -from ably.types.operations import MessageOperation, PublishResult, UpdateDeleteResult -from ably.types.presence import Presence -from ably.util.crypto import get_cipher -from ably.util.exceptions import ( +from ably_pubsub.core.types.operations import MessageOperation, PublishResult, UpdateDeleteResult +from ably_pubsub.core.types.presence import Presence +from ably_pubsub.core.util.crypto import get_cipher +from ably_pubsub.core.util.exceptions import ( AblyException, IncompatibleClientIdException, catch_all, diff --git a/ably/rest/push.py b/core/src/ably_pubsub/core/rest/push.py similarity index 96% rename from ably/rest/push.py rename to core/src/ably_pubsub/core/rest/push.py index f99b2b1d..e8c5b051 100644 --- a/ably/rest/push.py +++ b/core/src/ably_pubsub/core/rest/push.py @@ -1,12 +1,12 @@ from typing import Optional -from ably.http.paginatedresult import PaginatedResult, format_params -from ably.types.channelsubscription import ( +from ably_pubsub.core.http.paginatedresult import PaginatedResult, format_params +from ably_pubsub.core.types.channelsubscription import ( PushChannelSubscription, channel_subscriptions_response_processor, channels_response_processor, ) -from ably.types.device import DeviceDetails, device_details_response_processor +from ably_pubsub.core.types.device import DeviceDetails, device_details_response_processor class Push: diff --git a/ably/rest/rest.py b/core/src/ably_pubsub/core/rest/rest.py similarity index 90% rename from ably/rest/rest.py rename to core/src/ably_pubsub/core/rest/rest.py index bc84e638..0a487532 100644 --- a/ably/rest/rest.py +++ b/core/src/ably_pubsub/core/rest/rest.py @@ -2,15 +2,15 @@ from typing import Optional from urllib.parse import urlencode -from ably.http.http import Http -from ably.http.paginatedresult import HttpPaginatedResponse, PaginatedResult, format_params -from ably.rest.auth import Auth -from ably.rest.channel import Channels -from ably.rest.push import Push -from ably.types.options import Options -from ably.types.stats import stats_response_processor -from ably.types.tokendetails import TokenDetails -from ably.util.exceptions import AblyException, catch_all +from ably_pubsub.core.http.http import Http +from ably_pubsub.core.http.paginatedresult import HttpPaginatedResponse, PaginatedResult, format_params +from ably_pubsub.core.rest.auth import Auth +from ably_pubsub.core.rest.channel import Channels +from ably_pubsub.core.rest.push import Push +from ably_pubsub.core.types.options import Options +from ably_pubsub.core.types.stats import stats_response_processor +from ably_pubsub.core.types.tokendetails import TokenDetails +from ably_pubsub.core.util.exceptions import AblyException, catch_all log = logging.getLogger(__name__) diff --git a/ably/scripts/__init__.py b/core/src/ably_pubsub/core/scripts/__init__.py similarity index 100% rename from ably/scripts/__init__.py rename to core/src/ably_pubsub/core/scripts/__init__.py diff --git a/ably/scripts/unasync.py b/core/src/ably_pubsub/core/scripts/unasync.py similarity index 93% rename from ably/scripts/unasync.py rename to core/src/ably_pubsub/core/scripts/unasync.py index d13e20f2..e95b14ac 100644 --- a/ably/scripts/unasync.py +++ b/core/src/ably_pubsub/core/scripts/unasync.py @@ -241,7 +241,7 @@ def run(): _TOKEN_REPLACE["aclose"] = "close" _TOKEN_REPLACE["assert_waiter"] = "assert_waiter_sync" - _IMPORTS_REPLACE["ably"] = "ably.sync" + _IMPORTS_REPLACE["ably"] = "ably_pubsub.core.sync" # here... for class_name in rename_classes: @@ -269,14 +269,14 @@ def run(): _IMPORTS_REPLACE["test.ably"] = "test.ably.sync" _STRING_REPLACE['/../assets/testAppSpec.json'] = '/../../assets/testAppSpec.json' - _STRING_REPLACE['ably.rest.auth.Auth.request_token'] = 'ably.sync.rest.auth.AuthSync.request_token' - _STRING_REPLACE['ably.rest.auth.TokenRequest'] = 'ably.sync.rest.auth.TokenRequest' - _STRING_REPLACE['ably.rest.rest.Http.post'] = 'ably.sync.rest.rest.HttpSync.post' + _STRING_REPLACE['ably_pubsub.core.rest.auth.Auth.request_token'] = 'ably_pubsub.core.sync.rest.auth.AuthSync.request_token' + _STRING_REPLACE['ably_pubsub.core.rest.auth.TokenRequest'] = 'ably_pubsub.core.sync.rest.auth.TokenRequest' + _STRING_REPLACE['ably_pubsub.core.rest.rest.Http.post'] = 'ably_pubsub.core.sync.rest.rest.HttpSync.post' _STRING_REPLACE['httpx.AsyncClient.send'] = 'httpx.Client.send' - _STRING_REPLACE['ably.util.exceptions.AblyException.raise_for_response'] = \ - 'ably.sync.util.exceptions.AblyException.raise_for_response' - _STRING_REPLACE['ably.rest.rest.AblyRest.time'] = 'ably.sync.rest.rest.AblyRestSync.time' - _STRING_REPLACE['ably.rest.auth.Auth._timestamp'] = 'ably.sync.rest.auth.AuthSync._timestamp' + _STRING_REPLACE['ably_pubsub.core.util.exceptions.AblyException.raise_for_response'] = \ + 'ably_pubsub.core.sync.util.exceptions.AblyException.raise_for_response' + _STRING_REPLACE['ably_pubsub.core.rest.rest.AblyRest.time'] = 'ably_pubsub.core.sync.rest.rest.AblyRestSync.time' + _STRING_REPLACE['ably_pubsub.core.rest.auth.Auth._timestamp'] = 'ably_pubsub.core.sync.rest.auth.AuthSync._timestamp' # round 1 src_dir_path = os.path.join(os.getcwd(), "test", "ably") diff --git a/ably/transport/__init__.py b/core/src/ably_pubsub/core/transport/__init__.py similarity index 100% rename from ably/transport/__init__.py rename to core/src/ably_pubsub/core/transport/__init__.py diff --git a/ably/transport/defaults.py b/core/src/ably_pubsub/core/transport/defaults.py similarity index 100% rename from ably/transport/defaults.py rename to core/src/ably_pubsub/core/transport/defaults.py diff --git a/ably/transport/websockettransport.py b/core/src/ably_pubsub/core/transport/websockettransport.py similarity index 96% rename from ably/transport/websockettransport.py rename to core/src/ably_pubsub/core/transport/websockettransport.py index ad4f2856..f2db328a 100644 --- a/ably/transport/websockettransport.py +++ b/core/src/ably_pubsub/core/transport/websockettransport.py @@ -10,12 +10,12 @@ import msgpack -from ably.http.httputils import HttpUtils -from ably.types.connectiondetails import ConnectionDetails -from ably.types.operations import PublishResult -from ably.util.eventemitter import EventEmitter -from ably.util.exceptions import AblyException -from ably.util.helper import Timer, unix_time_ms +from ably_pubsub.core.http.httputils import HttpUtils +from ably_pubsub.core.types.connectiondetails import ConnectionDetails +from ably_pubsub.core.types.operations import PublishResult +from ably_pubsub.core.util.eventemitter import EventEmitter +from ably_pubsub.core.util.exceptions import AblyException +from ably_pubsub.core.util.helper import Timer, unix_time_ms try: # websockets 15+ preferred imports @@ -29,7 +29,7 @@ from websockets.exceptions import ConnectionClosedOK, WebSocketException if TYPE_CHECKING: - from ably.realtime.connection import ConnectionManager + from ably_pubsub.core.realtime.connection import ConnectionManager log = logging.getLogger(__name__) diff --git a/ably/types/__init__.py b/core/src/ably_pubsub/core/types/__init__.py similarity index 100% rename from ably/types/__init__.py rename to core/src/ably_pubsub/core/types/__init__.py diff --git a/ably/types/annotation.py b/core/src/ably_pubsub/core/types/annotation.py similarity index 97% rename from ably/types/annotation.py rename to core/src/ably_pubsub/core/types/annotation.py index fea91468..a5ee3602 100644 --- a/ably/types/annotation.py +++ b/core/src/ably_pubsub/core/types/annotation.py @@ -1,11 +1,11 @@ import logging from enum import IntEnum -from ably.types.mixins import EncodeDataMixin -from ably.types.typedbuffer import TypedBuffer -from ably.util.crypto import CipherData -from ably.util.encoding import encode_data -from ably.util.helper import to_text +from ably_pubsub.core.types.mixins import EncodeDataMixin +from ably_pubsub.core.types.typedbuffer import TypedBuffer +from ably_pubsub.core.util.crypto import CipherData +from ably_pubsub.core.util.encoding import encode_data +from ably_pubsub.core.util.helper import to_text log = logging.getLogger(__name__) diff --git a/ably/types/authoptions.py b/core/src/ably_pubsub/core/types/authoptions.py similarity index 98% rename from ably/types/authoptions.py rename to core/src/ably_pubsub/core/types/authoptions.py index 7ee06af7..4f826442 100644 --- a/ably/types/authoptions.py +++ b/core/src/ably_pubsub/core/types/authoptions.py @@ -1,4 +1,4 @@ -from ably.util.exceptions import AblyException +from ably_pubsub.core.util.exceptions import AblyException class AuthOptions: diff --git a/ably/types/capability.py b/core/src/ably_pubsub/core/types/capability.py similarity index 100% rename from ably/types/capability.py rename to core/src/ably_pubsub/core/types/capability.py diff --git a/ably/types/channeldetails.py b/core/src/ably_pubsub/core/types/channeldetails.py similarity index 100% rename from ably/types/channeldetails.py rename to core/src/ably_pubsub/core/types/channeldetails.py diff --git a/ably/types/channelmode.py b/core/src/ably_pubsub/core/types/channelmode.py similarity index 96% rename from ably/types/channelmode.py rename to core/src/ably_pubsub/core/types/channelmode.py index 23ed735c..80c391ae 100644 --- a/ably/types/channelmode.py +++ b/core/src/ably_pubsub/core/types/channelmode.py @@ -2,7 +2,7 @@ from enum import Enum -from ably.types.flags import Flag +from ably_pubsub.core.types.flags import Flag class ChannelMode(int, Enum): diff --git a/ably/types/channeloptions.py b/core/src/ably_pubsub/core/types/channeloptions.py similarity index 93% rename from ably/types/channeloptions.py rename to core/src/ably_pubsub/core/types/channeloptions.py index 3e5052c6..750d1462 100644 --- a/ably/types/channeloptions.py +++ b/core/src/ably_pubsub/core/types/channeloptions.py @@ -2,9 +2,9 @@ from typing import Any -from ably.types.channelmode import ChannelMode -from ably.util.crypto import CipherParams -from ably.util.exceptions import AblyException +from ably_pubsub.core.types.channelmode import ChannelMode +from ably_pubsub.core.util.crypto import CipherParams +from ably_pubsub.core.util.exceptions import AblyException class ChannelOptions: diff --git a/ably/types/channelstate.py b/core/src/ably_pubsub/core/types/channelstate.py similarity index 88% rename from ably/types/channelstate.py rename to core/src/ably_pubsub/core/types/channelstate.py index dcb68d67..e0313c45 100644 --- a/ably/types/channelstate.py +++ b/core/src/ably_pubsub/core/types/channelstate.py @@ -2,7 +2,7 @@ from enum import Enum from typing import Optional -from ably.util.exceptions import AblyException +from ably_pubsub.core.util.exceptions import AblyException class ChannelState(str, Enum): diff --git a/ably/types/channelsubscription.py b/core/src/ably_pubsub/core/types/channelsubscription.py similarity index 97% rename from ably/types/channelsubscription.py rename to core/src/ably_pubsub/core/types/channelsubscription.py index b4c0dbf8..580b5bac 100644 --- a/ably/types/channelsubscription.py +++ b/core/src/ably_pubsub/core/types/channelsubscription.py @@ -1,4 +1,4 @@ -from ably.util import case +from ably_pubsub.core.util import case class PushChannelSubscription: diff --git a/ably/types/connectiondetails.py b/core/src/ably_pubsub/core/types/connectiondetails.py similarity index 100% rename from ably/types/connectiondetails.py rename to core/src/ably_pubsub/core/types/connectiondetails.py diff --git a/ably/types/connectionerrors.py b/core/src/ably_pubsub/core/types/connectionerrors.py similarity index 83% rename from ably/types/connectionerrors.py rename to core/src/ably_pubsub/core/types/connectionerrors.py index bb2fa1f4..41d93d66 100644 --- a/ably/types/connectionerrors.py +++ b/core/src/ably_pubsub/core/types/connectionerrors.py @@ -1,5 +1,5 @@ -from ably.types.connectionstate import ConnectionState -from ably.util.exceptions import AblyException +from ably_pubsub.core.types.connectionstate import ConnectionState +from ably_pubsub.core.util.exceptions import AblyException ConnectionErrors = { ConnectionState.DISCONNECTED: AblyException( diff --git a/ably/types/connectionstate.py b/core/src/ably_pubsub/core/types/connectionstate.py similarity index 93% rename from ably/types/connectionstate.py rename to core/src/ably_pubsub/core/types/connectionstate.py index ec958358..1c73d8b5 100644 --- a/ably/types/connectionstate.py +++ b/core/src/ably_pubsub/core/types/connectionstate.py @@ -2,7 +2,7 @@ from enum import Enum from typing import Optional -from ably.util.exceptions import AblyException +from ably_pubsub.core.util.exceptions import AblyException class ConnectionState(str, Enum): diff --git a/ably/types/device.py b/core/src/ably_pubsub/core/types/device.py similarity index 98% rename from ably/types/device.py rename to core/src/ably_pubsub/core/types/device.py index c2b84ee5..642e7b65 100644 --- a/ably/types/device.py +++ b/core/src/ably_pubsub/core/types/device.py @@ -1,4 +1,4 @@ -from ably.util import case +from ably_pubsub.core.util import case DevicePushTransportType = {'fcm', 'gcm', 'apns', 'web'} DevicePlatform = {'android', 'ios', 'browser'} diff --git a/ably/types/flags.py b/core/src/ably_pubsub/core/types/flags.py similarity index 100% rename from ably/types/flags.py rename to core/src/ably_pubsub/core/types/flags.py diff --git a/ably/types/message.py b/core/src/ably_pubsub/core/types/message.py similarity index 97% rename from ably/types/message.py rename to core/src/ably_pubsub/core/types/message.py index 2442a587..59efb72c 100644 --- a/ably/types/message.py +++ b/core/src/ably_pubsub/core/types/message.py @@ -1,12 +1,12 @@ import logging from enum import IntEnum -from ably.types.mixins import DeltaExtras, EncodeDataMixin -from ably.types.typedbuffer import TypedBuffer -from ably.util.crypto import CipherData -from ably.util.encoding import encode_data -from ably.util.exceptions import AblyException -from ably.util.helper import to_text +from ably_pubsub.core.types.mixins import DeltaExtras, EncodeDataMixin +from ably_pubsub.core.types.typedbuffer import TypedBuffer +from ably_pubsub.core.util.crypto import CipherData +from ably_pubsub.core.util.encoding import encode_data +from ably_pubsub.core.util.exceptions import AblyException +from ably_pubsub.core.util.helper import to_text log = logging.getLogger(__name__) diff --git a/ably/types/mixins.py b/core/src/ably_pubsub/core/types/mixins.py similarity index 97% rename from ably/types/mixins.py rename to core/src/ably_pubsub/core/types/mixins.py index 2d2b6041..85783d90 100644 --- a/ably/types/mixins.py +++ b/core/src/ably_pubsub/core/types/mixins.py @@ -2,8 +2,8 @@ import json import logging -from ably.util.crypto import CipherData -from ably.util.exceptions import AblyException +from ably_pubsub.core.util.crypto import CipherData +from ably_pubsub.core.util.exceptions import AblyException log = logging.getLogger(__name__) diff --git a/ably/types/operations.py b/core/src/ably_pubsub/core/types/operations.py similarity index 100% rename from ably/types/operations.py rename to core/src/ably_pubsub/core/types/operations.py diff --git a/ably/types/options.py b/core/src/ably_pubsub/core/types/options.py similarity index 97% rename from ably/types/options.py rename to core/src/ably_pubsub/core/types/options.py index 1dad41fb..1fc264b6 100644 --- a/ably/types/options.py +++ b/core/src/ably_pubsub/core/types/options.py @@ -2,9 +2,9 @@ import random from abc import ABC, abstractmethod -from ably.transport.defaults import Defaults -from ably.types.authoptions import AuthOptions -from ably.util.exceptions import AblyException +from ably_pubsub.core.transport.defaults import Defaults +from ably_pubsub.core.types.authoptions import AuthOptions +from ably_pubsub.core.util.exceptions import AblyException log = logging.getLogger(__name__) @@ -80,7 +80,7 @@ def __init__(self, client_id=None, log_level=0, tls=True, rest_host=None, realti ) if idempotent_rest_publishing is None: - from ably import api_version + from ably_pubsub.core import api_version idempotent_rest_publishing = api_version >= '1.2' if environment is not None and endpoint is None: diff --git a/ably/types/presence.py b/core/src/ably_pubsub/core/types/presence.py similarity index 96% rename from ably/types/presence.py rename to core/src/ably_pubsub/core/types/presence.py index 7d1a3c05..6cd20132 100644 --- a/ably/types/presence.py +++ b/core/src/ably_pubsub/core/types/presence.py @@ -1,11 +1,11 @@ from datetime import datetime, timedelta from urllib import parse -from ably.http.paginatedresult import PaginatedResult -from ably.types.mixins import EncodeDataMixin -from ably.types.typedbuffer import TypedBuffer -from ably.util.crypto import CipherData -from ably.util.encoding import encode_data +from ably_pubsub.core.http.paginatedresult import PaginatedResult +from ably_pubsub.core.types.mixins import EncodeDataMixin +from ably_pubsub.core.types.typedbuffer import TypedBuffer +from ably_pubsub.core.util.crypto import CipherData +from ably_pubsub.core.util.encoding import encode_data def _ms_since_epoch(dt): diff --git a/ably/types/stats.py b/core/src/ably_pubsub/core/types/stats.py similarity index 100% rename from ably/types/stats.py rename to core/src/ably_pubsub/core/types/stats.py diff --git a/ably/types/tokendetails.py b/core/src/ably_pubsub/core/types/tokendetails.py similarity index 97% rename from ably/types/tokendetails.py rename to core/src/ably_pubsub/core/types/tokendetails.py index 771b29ec..d3251148 100644 --- a/ably/types/tokendetails.py +++ b/core/src/ably_pubsub/core/types/tokendetails.py @@ -1,7 +1,7 @@ import json import time -from ably.types.capability import Capability +from ably_pubsub.core.types.capability import Capability class TokenDetails: diff --git a/ably/types/tokenrequest.py b/core/src/ably_pubsub/core/types/tokenrequest.py similarity index 100% rename from ably/types/tokenrequest.py rename to core/src/ably_pubsub/core/types/tokenrequest.py diff --git a/ably/types/typedbuffer.py b/core/src/ably_pubsub/core/types/typedbuffer.py similarity index 100% rename from ably/types/typedbuffer.py rename to core/src/ably_pubsub/core/types/typedbuffer.py diff --git a/ably/util/__init__.py b/core/src/ably_pubsub/core/util/__init__.py similarity index 100% rename from ably/util/__init__.py rename to core/src/ably_pubsub/core/util/__init__.py diff --git a/ably/util/case.py b/core/src/ably_pubsub/core/util/case.py similarity index 100% rename from ably/util/case.py rename to core/src/ably_pubsub/core/util/case.py diff --git a/ably/util/crypto.py b/core/src/ably_pubsub/core/util/crypto.py similarity index 97% rename from ably/util/crypto.py rename to core/src/ably_pubsub/core/util/crypto.py index 8d8ddfd9..2763e8df 100644 --- a/ably/util/crypto.py +++ b/core/src/ably_pubsub/core/util/crypto.py @@ -7,8 +7,8 @@ except ImportError: from .nocrypto import AES, Random -from ably.types.typedbuffer import TypedBuffer -from ably.util.exceptions import AblyException +from ably_pubsub.core.types.typedbuffer import TypedBuffer +from ably_pubsub.core.util.exceptions import AblyException log = logging.getLogger(__name__) diff --git a/ably/util/encoding.py b/core/src/ably_pubsub/core/util/encoding.py similarity index 90% rename from ably/util/encoding.py rename to core/src/ably_pubsub/core/util/encoding.py index 5187aec2..df4d9b55 100644 --- a/ably/util/encoding.py +++ b/core/src/ably_pubsub/core/util/encoding.py @@ -2,8 +2,8 @@ import json from typing import Any -from ably.util.crypto import CipherData -from ably.util.exceptions import AblyException +from ably_pubsub.core.util.crypto import CipherData +from ably_pubsub.core.util.exceptions import AblyException def encode_data(data: Any, encoding_array: list, binary: bool = False): diff --git a/ably/util/eventemitter.py b/core/src/ably_pubsub/core/util/eventemitter.py similarity index 99% rename from ably/util/eventemitter.py rename to core/src/ably_pubsub/core/util/eventemitter.py index 74f0beb6..93e0dfda 100644 --- a/ably/util/eventemitter.py +++ b/core/src/ably_pubsub/core/util/eventemitter.py @@ -3,7 +3,7 @@ from pyee.asyncio import AsyncIOEventEmitter -from ably.util.helper import is_callable_or_coroutine +from ably_pubsub.core.util.helper import is_callable_or_coroutine # pyee's event emitter doesn't support attaching a listener to all events # so to patch it, we create a wrapper which uses two event emitters, one diff --git a/ably/util/exceptions.py b/core/src/ably_pubsub/core/util/exceptions.py similarity index 100% rename from ably/util/exceptions.py rename to core/src/ably_pubsub/core/util/exceptions.py diff --git a/ably/util/helper.py b/core/src/ably_pubsub/core/util/helper.py similarity index 98% rename from ably/util/helper.py rename to core/src/ably_pubsub/core/util/helper.py index a35ebe6e..26a916f7 100644 --- a/ably/util/helper.py +++ b/core/src/ably_pubsub/core/util/helper.py @@ -9,7 +9,7 @@ import msgpack -from ably.util.exceptions import AblyException +from ably_pubsub.core.util.exceptions import AblyException def get_random_id(): diff --git a/ably/util/nocrypto.py b/core/src/ably_pubsub/core/util/nocrypto.py similarity index 100% rename from ably/util/nocrypto.py rename to core/src/ably_pubsub/core/util/nocrypto.py diff --git a/ably/vcdiff/__init__.py b/core/src/ably_pubsub/core/vcdiff/__init__.py similarity index 100% rename from ably/vcdiff/__init__.py rename to core/src/ably_pubsub/core/vcdiff/__init__.py diff --git a/ably/vcdiff/defaultvcdiffdecoder.py b/core/src/ably_pubsub/core/vcdiff/defaultvcdiffdecoder.py similarity index 92% rename from ably/vcdiff/defaultvcdiffdecoder.py rename to core/src/ably_pubsub/core/vcdiff/defaultvcdiffdecoder.py index ae2d3263..4e553773 100644 --- a/ably/vcdiff/defaultvcdiffdecoder.py +++ b/core/src/ably_pubsub/core/vcdiff/defaultvcdiffdecoder.py @@ -5,7 +5,7 @@ It implements the VCDiffDecoder interface. Usage: - from ably.vcdiff import AblyVCDiffDecoder, AblyRealtime + from ably_pubsub.core.vcdiff import AblyVCDiffDecoder, AblyRealtime # Create VCDiff decoder vcdiff_decoder = AblyVCDiffDecoder() @@ -19,8 +19,8 @@ import logging -from ably.types.options import VCDiffDecoder -from ably.util.exceptions import AblyException +from ably_pubsub.core.types.options import VCDiffDecoder +from ably_pubsub.core.util.exceptions import AblyException log = logging.getLogger(__name__) diff --git a/test/ably/realtime/eventemitter_test.py b/test/ably/realtime/eventemitter_test.py index 71db2c74..30abfa6d 100644 --- a/test/ably/realtime/eventemitter_test.py +++ b/test/ably/realtime/eventemitter_test.py @@ -2,7 +2,7 @@ import pytest -from ably.realtime.connection import ConnectionState +from ably_pubsub.core.realtime.connection import ConnectionState from test.ably.testapp import TestApp from test.ably.utils import BaseAsyncTestCase diff --git a/test/ably/realtime/presencemap_test.py b/test/ably/realtime/presencemap_test.py index 043baeb0..b40336cf 100644 --- a/test/ably/realtime/presencemap_test.py +++ b/test/ably/realtime/presencemap_test.py @@ -8,8 +8,8 @@ import pytest -from ably.realtime.presencemap import PresenceMap, _is_newer -from ably.types.presence import PresenceAction, PresenceMessage +from ably_pubsub.core.realtime.presencemap import PresenceMap, _is_newer +from ably_pubsub.core.types.presence import PresenceAction, PresenceMessage from test.ably.utils import BaseAsyncTestCase diff --git a/test/ably/realtime/realtimeannotations_test.py b/test/ably/realtime/realtimeannotations_test.py index a82b6b2b..2e3d1e3d 100644 --- a/test/ably/realtime/realtimeannotations_test.py +++ b/test/ably/realtime/realtimeannotations_test.py @@ -5,10 +5,10 @@ import pytest -from ably.types.annotation import Annotation, AnnotationAction -from ably.types.channelmode import ChannelMode -from ably.types.channeloptions import ChannelOptions -from ably.types.message import MessageAction +from ably_pubsub.core.types.annotation import Annotation, AnnotationAction +from ably_pubsub.core.types.channelmode import ChannelMode +from ably_pubsub.core.types.channeloptions import ChannelOptions +from ably_pubsub.core.types.message import MessageAction from test.ably.testapp import TestApp from test.ably.utils import BaseAsyncTestCase, ReusableFuture, assert_waiter @@ -332,7 +332,7 @@ async def on_annotation(annotation): pass # RTAN4e: Should log a warning (not raise), and still register the listener - with caplog.at_level(logging.WARNING, logger='ably.realtime.annotations'): + with caplog.at_level(logging.WARNING, logger='ably_pubsub.core.realtime.annotations'): await channel.annotations.subscribe(on_annotation) # Verify warning was logged mentioning the missing mode diff --git a/test/ably/realtime/realtimeauth_test.py b/test/ably/realtime/realtimeauth_test.py index 6ec53356..b3004a1c 100644 --- a/test/ably/realtime/realtimeauth_test.py +++ b/test/ably/realtime/realtimeauth_test.py @@ -5,11 +5,11 @@ import httpx import pytest -from ably.realtime.connection import ConnectionState -from ably.transport.websockettransport import ProtocolMessageAction -from ably.types.channelstate import ChannelState -from ably.types.connectionstate import ConnectionEvent -from ably.types.tokendetails import TokenDetails +from ably_pubsub.core.realtime.connection import ConnectionState +from ably_pubsub.core.transport.websockettransport import ProtocolMessageAction +from ably_pubsub.core.types.channelstate import ChannelState +from ably_pubsub.core.types.connectionstate import ConnectionEvent +from ably_pubsub.core.types.tokendetails import TokenDetails from test.ably.testapp import TestApp from test.ably.utils import BaseAsyncTestCase, random_string diff --git a/test/ably/realtime/realtimechannel_publish_test.py b/test/ably/realtime/realtimechannel_publish_test.py index 9ecf10f9..9a9b7f5a 100644 --- a/test/ably/realtime/realtimechannel_publish_test.py +++ b/test/ably/realtime/realtimechannel_publish_test.py @@ -2,13 +2,13 @@ import pytest -from ably.realtime.channel import ChannelState -from ably.realtime.connection import ConnectionState -from ably.transport.websockettransport import ProtocolMessageAction -from ably.types.channeloptions import ChannelOptions -from ably.types.message import Message -from ably.util.crypto import CipherParams -from ably.util.exceptions import AblyException, IncompatibleClientIdException +from ably_pubsub.core.realtime.channel import ChannelState +from ably_pubsub.core.realtime.connection import ConnectionState +from ably_pubsub.core.transport.websockettransport import ProtocolMessageAction +from ably_pubsub.core.types.channeloptions import ChannelOptions +from ably_pubsub.core.types.message import Message +from ably_pubsub.core.util.crypto import CipherParams +from ably_pubsub.core.util.exceptions import AblyException, IncompatibleClientIdException from test.ably.testapp import TestApp from test.ably.utils import BaseAsyncTestCase, WaitableEvent, assert_waiter @@ -328,7 +328,7 @@ async def test_msgserial_resets_on_new_connection_id(self): new_connection_id = 'new_connection_id_12345' # Simulate server sending CONNECTED with new connectionId - from ably.types.connectiondetails import ConnectionDetails + from ably_pubsub.core.types.connectiondetails import ConnectionDetails new_connection_details = ConnectionDetails( connection_state_ttl=120000, max_idle_interval=15000, @@ -365,7 +365,7 @@ async def test_msgserial_not_reset_on_same_connection_id(self): # Simulate reconnection with SAME connectionId (transport change, not new connection) same_connection_id = connection_manager.connection_id - from ably.types.connectiondetails import ConnectionDetails + from ably_pubsub.core.types.connectiondetails import ConnectionDetails connection_details = ConnectionDetails( connection_state_ttl=120000, max_idle_interval=15000, @@ -491,7 +491,7 @@ async def check_pending(): assert connection_manager.msg_serial == 1 # Simulate resume with SAME connectionId - from ably.types.connectiondetails import ConnectionDetails + from ably_pubsub.core.types.connectiondetails import ConnectionDetails connection_details = ConnectionDetails( connection_state_ttl=120000, max_idle_interval=15000, @@ -541,7 +541,7 @@ async def check_pending(): assert connection_manager.msg_serial == 1 # Simulate NEW connection (different connectionId = failed resume) - from ably.types.connectiondetails import ConnectionDetails + from ably_pubsub.core.types.connectiondetails import ConnectionDetails new_connection_details = ConnectionDetails( connection_state_ttl=120000, max_idle_interval=15000, diff --git a/test/ably/realtime/realtimechannel_test.py b/test/ably/realtime/realtimechannel_test.py index 6d2865f2..78eb0c2b 100644 --- a/test/ably/realtime/realtimechannel_test.py +++ b/test/ably/realtime/realtimechannel_test.py @@ -2,12 +2,12 @@ import pytest -from ably.realtime.channel import ChannelState, RealtimeChannel -from ably.realtime.connection import ConnectionState -from ably.transport.websockettransport import ProtocolMessageAction -from ably.types.channeloptions import ChannelOptions -from ably.types.message import Message -from ably.util.exceptions import AblyException +from ably_pubsub.core.realtime.channel import ChannelState, RealtimeChannel +from ably_pubsub.core.realtime.connection import ConnectionState +from ably_pubsub.core.transport.websockettransport import ProtocolMessageAction +from ably_pubsub.core.types.channeloptions import ChannelOptions +from ably_pubsub.core.types.message import Message +from ably_pubsub.core.util.exceptions import AblyException from test.ably.testapp import TestApp from test.ably.utils import BaseAsyncTestCase, random_string diff --git a/test/ably/realtime/realtimechannel_vcdiff_test.py b/test/ably/realtime/realtimechannel_vcdiff_test.py index 48a484a9..2d4842e9 100644 --- a/test/ably/realtime/realtimechannel_vcdiff_test.py +++ b/test/ably/realtime/realtimechannel_vcdiff_test.py @@ -3,10 +3,10 @@ import pytest -from ably import AblyVCDiffDecoder -from ably.realtime.connection import ConnectionState -from ably.types.channeloptions import ChannelOptions -from ably.types.options import VCDiffDecoder +from ably_pubsub.core import AblyVCDiffDecoder +from ably_pubsub.core.realtime.connection import ConnectionState +from ably_pubsub.core.types.channeloptions import ChannelOptions +from ably_pubsub.core.types.options import VCDiffDecoder from test.ably.testapp import TestApp from test.ably.utils import BaseAsyncTestCase, WaitableEvent diff --git a/test/ably/realtime/realtimechannelmutablemessages_test.py b/test/ably/realtime/realtimechannelmutablemessages_test.py index afe8a60f..3d891f4c 100644 --- a/test/ably/realtime/realtimechannelmutablemessages_test.py +++ b/test/ably/realtime/realtimechannelmutablemessages_test.py @@ -3,9 +3,9 @@ import pytest -from ably import AblyException, CipherParams, MessageAction -from ably.types.message import Message -from ably.types.operations import MessageOperation +from ably_pubsub.core import AblyException, CipherParams, MessageAction +from ably_pubsub.core.types.message import Message +from ably_pubsub.core.types.operations import MessageOperation from test.ably.testapp import TestApp from test.ably.utils import BaseAsyncTestCase, WaitableEvent, assert_waiter diff --git a/test/ably/realtime/realtimeconnection_test.py b/test/ably/realtime/realtimeconnection_test.py index 2593eb3e..cdf3edbd 100644 --- a/test/ably/realtime/realtimeconnection_test.py +++ b/test/ably/realtime/realtimeconnection_test.py @@ -10,10 +10,10 @@ # websockets 14 and earlier fallback from websockets.server import serve as ws_serve -from ably.realtime.connection import ConnectionEvent, ConnectionState -from ably.transport.defaults import Defaults -from ably.transport.websockettransport import ProtocolMessageAction -from ably.util.exceptions import AblyException +from ably_pubsub.core.realtime.connection import ConnectionEvent, ConnectionState +from ably_pubsub.core.transport.defaults import Defaults +from ably_pubsub.core.transport.websockettransport import ProtocolMessageAction +from ably_pubsub.core.util.exceptions import AblyException from test.ably.testapp import TestApp from test.ably.utils import BaseAsyncTestCase diff --git a/test/ably/realtime/realtimeinit_test.py b/test/ably/realtime/realtimeinit_test.py index 4009d046..9183ea9e 100644 --- a/test/ably/realtime/realtimeinit_test.py +++ b/test/ably/realtime/realtimeinit_test.py @@ -2,9 +2,9 @@ import pytest -from ably import Auth -from ably.realtime.connection import ConnectionState -from ably.util.exceptions import AblyAuthException +from ably_pubsub.core import Auth +from ably_pubsub.core.realtime.connection import ConnectionState +from ably_pubsub.core.util.exceptions import AblyAuthException from test.ably.testapp import TestApp from test.ably.utils import BaseAsyncTestCase diff --git a/test/ably/realtime/realtimepresence_test.py b/test/ably/realtime/realtimepresence_test.py index 86a073c7..42c815a7 100644 --- a/test/ably/realtime/realtimepresence_test.py +++ b/test/ably/realtime/realtimepresence_test.py @@ -9,10 +9,10 @@ import pytest -from ably.realtime.connection import ConnectionState -from ably.types.channelstate import ChannelState -from ably.types.presence import PresenceAction -from ably.util.exceptions import AblyException +from ably_pubsub.core.realtime.connection import ConnectionState +from ably_pubsub.core.types.channelstate import ChannelState +from ably_pubsub.core.types.presence import PresenceAction +from ably_pubsub.core.util.exceptions import AblyException from test.ably.testapp import TestApp from test.ably.utils import BaseAsyncTestCase diff --git a/test/ably/realtime/realtimeresume_test.py b/test/ably/realtime/realtimeresume_test.py index bfe77efa..6e20a707 100644 --- a/test/ably/realtime/realtimeresume_test.py +++ b/test/ably/realtime/realtimeresume_test.py @@ -2,9 +2,9 @@ import pytest -from ably.realtime.channel import ChannelState -from ably.realtime.connection import ConnectionState -from ably.transport.websockettransport import ProtocolMessageAction +from ably_pubsub.core.realtime.channel import ChannelState +from ably_pubsub.core.realtime.connection import ConnectionState +from ably_pubsub.core.transport.websockettransport import ProtocolMessageAction from test.ably.testapp import TestApp from test.ably.utils import BaseAsyncTestCase, random_string diff --git a/test/ably/rest/encoders_test.py b/test/ably/rest/encoders_test.py index f8023c5d..a3279540 100644 --- a/test/ably/rest/encoders_test.py +++ b/test/ably/rest/encoders_test.py @@ -7,9 +7,9 @@ import msgpack import pytest -from ably import CipherParams -from ably.types.message import Message -from ably.util.crypto import get_cipher +from ably_pubsub.core import CipherParams +from ably_pubsub.core.types.message import Message +from ably_pubsub.core.util.crypto import get_cipher from test.ably.testapp import TestApp from test.ably.utils import BaseAsyncTestCase @@ -31,7 +31,7 @@ async def setup(self): async def test_text_utf8(self): channel = self.ably.channels["persisted:publish"] - with mock.patch('ably.rest.rest.Http.post', new_callable=AsyncMock) as post_mock: + with mock.patch('ably_pubsub.core.rest.rest.Http.post', new_callable=AsyncMock) as post_mock: await channel.publish('event', 'foó') _, kwargs = post_mock.call_args assert json.loads(kwargs['body'])['data'] == 'foó' @@ -41,7 +41,7 @@ async def test_str(self): # This test only makes sense for py2 channel = self.ably.channels["persisted:publish"] - with mock.patch('ably.rest.rest.Http.post', new_callable=AsyncMock) as post_mock: + with mock.patch('ably_pubsub.core.rest.rest.Http.post', new_callable=AsyncMock) as post_mock: await channel.publish('event', 'foo') _, kwargs = post_mock.call_args assert json.loads(kwargs['body'])['data'] == 'foo' @@ -50,7 +50,7 @@ async def test_str(self): async def test_with_binary_type(self): channel = self.ably.channels["persisted:publish"] - with mock.patch('ably.rest.rest.Http.post', new_callable=AsyncMock) as post_mock: + with mock.patch('ably_pubsub.core.rest.rest.Http.post', new_callable=AsyncMock) as post_mock: await channel.publish('event', bytearray(b'foo')) _, kwargs = post_mock.call_args raw_data = json.loads(kwargs['body'])['data'] @@ -60,7 +60,7 @@ async def test_with_binary_type(self): async def test_with_bytes_type(self): channel = self.ably.channels["persisted:publish"] - with mock.patch('ably.rest.rest.Http.post', new_callable=AsyncMock) as post_mock: + with mock.patch('ably_pubsub.core.rest.rest.Http.post', new_callable=AsyncMock) as post_mock: await channel.publish('event', b'foo') _, kwargs = post_mock.call_args raw_data = json.loads(kwargs['body'])['data'] @@ -70,7 +70,7 @@ async def test_with_bytes_type(self): async def test_with_json_dict_data(self): channel = self.ably.channels["persisted:publish"] data = {'foó': 'bár'} - with mock.patch('ably.rest.rest.Http.post', new_callable=AsyncMock) as post_mock: + with mock.patch('ably_pubsub.core.rest.rest.Http.post', new_callable=AsyncMock) as post_mock: await channel.publish('event', data) _, kwargs = post_mock.call_args raw_data = json.loads(json.loads(kwargs['body'])['data']) @@ -80,7 +80,7 @@ async def test_with_json_dict_data(self): async def test_with_json_list_data(self): channel = self.ably.channels["persisted:publish"] data = ['foó', 'bár'] - with mock.patch('ably.rest.rest.Http.post', new_callable=AsyncMock) as post_mock: + with mock.patch('ably_pubsub.core.rest.rest.Http.post', new_callable=AsyncMock) as post_mock: await channel.publish('event', data) _, kwargs = post_mock.call_args raw_data = json.loads(json.loads(kwargs['body'])['data']) @@ -161,7 +161,7 @@ def decrypt(self, payload, options=None): async def test_text_utf8(self): channel = self.ably.channels.get("persisted:publish_enc", cipher=self.cipher_params) - with mock.patch('ably.rest.rest.Http.post', new_callable=AsyncMock) as post_mock: + with mock.patch('ably_pubsub.core.rest.rest.Http.post', new_callable=AsyncMock) as post_mock: await channel.publish('event', 'fóo') _, kwargs = post_mock.call_args assert json.loads(kwargs['body'])['encoding'].strip('/') == 'utf-8/cipher+aes-128-cbc/base64' @@ -172,7 +172,7 @@ async def test_str(self): # This test only makes sense for py2 channel = self.ably.channels["persisted:publish"] - with mock.patch('ably.rest.rest.Http.post', new_callable=AsyncMock) as post_mock: + with mock.patch('ably_pubsub.core.rest.rest.Http.post', new_callable=AsyncMock) as post_mock: await channel.publish('event', 'foo') _, kwargs = post_mock.call_args assert json.loads(kwargs['body'])['data'] == 'foo' @@ -182,7 +182,7 @@ async def test_with_binary_type(self): channel = self.ably.channels.get("persisted:publish_enc", cipher=self.cipher_params) - with mock.patch('ably.rest.rest.Http.post', new_callable=AsyncMock) as post_mock: + with mock.patch('ably_pubsub.core.rest.rest.Http.post', new_callable=AsyncMock) as post_mock: await channel.publish('event', bytearray(b'foo')) _, kwargs = post_mock.call_args @@ -195,7 +195,7 @@ async def test_with_json_dict_data(self): channel = self.ably.channels.get("persisted:publish_enc", cipher=self.cipher_params) data = {'foó': 'bár'} - with mock.patch('ably.rest.rest.Http.post', new_callable=AsyncMock) as post_mock: + with mock.patch('ably_pubsub.core.rest.rest.Http.post', new_callable=AsyncMock) as post_mock: await channel.publish('event', data) _, kwargs = post_mock.call_args assert json.loads(kwargs['body'])['encoding'].strip('/') == 'json/utf-8/cipher+aes-128-cbc/base64' @@ -206,7 +206,7 @@ async def test_with_json_list_data(self): channel = self.ably.channels.get("persisted:publish_enc", cipher=self.cipher_params) data = ['foó', 'bár'] - with mock.patch('ably.rest.rest.Http.post', new_callable=AsyncMock) as post_mock: + with mock.patch('ably_pubsub.core.rest.rest.Http.post', new_callable=AsyncMock) as post_mock: await channel.publish('event', data) _, kwargs = post_mock.call_args assert json.loads(kwargs['body'])['encoding'].strip('/') == 'json/utf-8/cipher+aes-128-cbc/base64' @@ -269,7 +269,7 @@ def decode(self, data): async def test_text_utf8(self): channel = self.ably.channels["persisted:publish"] - with mock.patch('ably.rest.rest.Http.post', + with mock.patch('ably_pubsub.core.rest.rest.Http.post', wraps=channel.ably.http.post) as post_mock: await channel.publish('event', 'foó') _, kwargs = post_mock.call_args @@ -279,7 +279,7 @@ async def test_text_utf8(self): async def test_with_binary_type(self): channel = self.ably.channels["persisted:publish"] - with mock.patch('ably.rest.rest.Http.post', + with mock.patch('ably_pubsub.core.rest.rest.Http.post', wraps=channel.ably.http.post) as post_mock: await channel.publish('event', bytearray(b'foo')) _, kwargs = post_mock.call_args @@ -289,7 +289,7 @@ async def test_with_binary_type(self): async def test_with_json_dict_data(self): channel = self.ably.channels["persisted:publish"] data = {'foó': 'bár'} - with mock.patch('ably.rest.rest.Http.post', + with mock.patch('ably_pubsub.core.rest.rest.Http.post', wraps=channel.ably.http.post) as post_mock: await channel.publish('event', data) _, kwargs = post_mock.call_args @@ -300,7 +300,7 @@ async def test_with_json_dict_data(self): async def test_with_json_list_data(self): channel = self.ably.channels["persisted:publish"] data = ['foó', 'bár'] - with mock.patch('ably.rest.rest.Http.post', + with mock.patch('ably_pubsub.core.rest.rest.Http.post', wraps=channel.ably.http.post) as post_mock: await channel.publish('event', data) _, kwargs = post_mock.call_args @@ -367,7 +367,7 @@ def decode(self, data): async def test_text_utf8(self): channel = self.ably.channels.get("persisted:publish_enc", cipher=self.cipher_params) - with mock.patch('ably.rest.rest.Http.post', + with mock.patch('ably_pubsub.core.rest.rest.Http.post', wraps=channel.ably.http.post) as post_mock: await channel.publish('event', 'fóo') _, kwargs = post_mock.call_args @@ -379,7 +379,7 @@ async def test_with_binary_type(self): channel = self.ably.channels.get("persisted:publish_enc", cipher=self.cipher_params) - with mock.patch('ably.rest.rest.Http.post', + with mock.patch('ably_pubsub.core.rest.rest.Http.post', wraps=channel.ably.http.post) as post_mock: await channel.publish('event', bytearray(b'foo')) _, kwargs = post_mock.call_args @@ -393,7 +393,7 @@ async def test_with_json_dict_data(self): channel = self.ably.channels.get("persisted:publish_enc", cipher=self.cipher_params) data = {'foó': 'bár'} - with mock.patch('ably.rest.rest.Http.post', + with mock.patch('ably_pubsub.core.rest.rest.Http.post', wraps=channel.ably.http.post) as post_mock: await channel.publish('event', data) _, kwargs = post_mock.call_args @@ -405,7 +405,7 @@ async def test_with_json_list_data(self): channel = self.ably.channels.get("persisted:publish_enc", cipher=self.cipher_params) data = ['foó', 'bár'] - with mock.patch('ably.rest.rest.Http.post', + with mock.patch('ably_pubsub.core.rest.rest.Http.post', wraps=channel.ably.http.post) as post_mock: await channel.publish('event', data) _, kwargs = post_mock.call_args diff --git a/test/ably/rest/restannotations_test.py b/test/ably/rest/restannotations_test.py index fcf2c696..07276dad 100644 --- a/test/ably/rest/restannotations_test.py +++ b/test/ably/rest/restannotations_test.py @@ -4,9 +4,9 @@ import pytest -from ably import AblyException -from ably.types.annotation import Annotation, AnnotationAction -from ably.types.message import Message +from ably_pubsub.core import AblyException +from ably_pubsub.core.types.annotation import Annotation, AnnotationAction +from ably_pubsub.core.types.message import Message from test.ably.testapp import TestApp from test.ably.utils import BaseAsyncTestCase, assert_waiter diff --git a/test/ably/rest/restauth_test.py b/test/ably/rest/restauth_test.py index 185021e1..e19e4563 100644 --- a/test/ably/rest/restauth_test.py +++ b/test/ably/rest/restauth_test.py @@ -10,9 +10,9 @@ import respx from httpx import AsyncClient, Response -import ably -from ably import AblyAuthException, AblyRest, Auth -from ably.types.tokendetails import TokenDetails +import ably_pubsub.core.types.tokenrequest +from ably_pubsub.core import AblyAuthException, AblyRest, Auth +from ably_pubsub.core.types.tokendetails import TokenDetails from test.ably.testapp import TestApp from test.ably.utils import BaseAsyncTestCase, VaryByProtocolTestsMetaclass, dont_vary_protocol @@ -198,7 +198,7 @@ async def test_authorize_always_creates_new_token(self): async def test_authorize_create_new_token_if_expired(self): token = await self.ably.auth.authorize() - with mock.patch('ably.rest.auth.Auth.token_details_has_expired', + with mock.patch('ably_pubsub.core.rest.auth.Auth.token_details_has_expired', return_value=True): new_token = await self.ably.auth.authorize() @@ -212,7 +212,7 @@ async def test_authorize_returns_a_token_details(self): async def test_authorize_adheres_to_request_token(self): token_params = {'ttl': 10, 'client_id': 'client_id'} auth_params = {'auth_url': 'somewhere.com', 'query_time': True} - with mock.patch('ably.rest.auth.Auth.request_token', new_callable=AsyncMock) as request_mock: + with mock.patch('ably_pubsub.core.rest.auth.Auth.request_token', new_callable=AsyncMock) as request_mock: await self.ably.auth.authorize(token_params, auth_params) token_called, auth_called = request_mock.call_args @@ -251,7 +251,7 @@ async def test_if_parameters_are_stored_and_used_as_defaults(self): auth_options = dict(self.ably.auth.auth_options.auth_options) auth_options['auth_headers'] = {'a_headers': 'a_value'} await self.ably.auth.authorize({'ttl': 555}, auth_options) - with mock.patch('ably.rest.auth.Auth.request_token', + with mock.patch('ably_pubsub.core.rest.auth.Auth.request_token', wraps=self.ably.auth.request_token) as request_mock: await self.ably.auth.authorize() @@ -263,7 +263,7 @@ async def test_if_parameters_are_stored_and_used_as_defaults(self): auth_options = dict(self.ably.auth.auth_options.auth_options) auth_options['auth_headers'] = None await self.ably.auth.authorize({}, auth_options) - with mock.patch('ably.rest.auth.Auth.request_token', + with mock.patch('ably_pubsub.core.rest.auth.Auth.request_token', wraps=self.ably.auth.request_token) as request_mock: await self.ably.auth.authorize() @@ -283,8 +283,8 @@ async def test_timestamp_is_not_stored(self): # call authorize again with timestamp set timestamp = await self.ably.time() - with mock.patch('ably.rest.auth.TokenRequest', - wraps=ably.types.tokenrequest.TokenRequest) as tr_mock: + with mock.patch('ably_pubsub.core.rest.auth.TokenRequest', + wraps=ably_pubsub.core.types.tokenrequest.TokenRequest) as tr_mock: auth_options = dict(self.ably.auth.auth_options.auth_options) auth_options['auth_headers'] = {'a_headers': 'a_value'} token_2 = await self.ably.auth.authorize( @@ -295,8 +295,8 @@ async def test_timestamp_is_not_stored(self): assert tr_mock.call_args[1]['timestamp'] == timestamp # call authorize again with no params - with mock.patch('ably.rest.auth.TokenRequest', - wraps=ably.types.tokenrequest.TokenRequest) as tr_mock: + with mock.patch('ably_pubsub.core.rest.auth.TokenRequest', + wraps=ably_pubsub.core.types.tokenrequest.TokenRequest) as tr_mock: token_4 = await self.ably.auth.authorize() assert isinstance(token_4, TokenDetails) assert token_2 != token_4 diff --git a/test/ably/rest/restcapability_test.py b/test/ably/rest/restcapability_test.py index c95c651d..3d66d087 100644 --- a/test/ably/rest/restcapability_test.py +++ b/test/ably/rest/restcapability_test.py @@ -1,7 +1,7 @@ import pytest -from ably.types.capability import Capability -from ably.util.exceptions import AblyException +from ably_pubsub.core.types.capability import Capability +from ably_pubsub.core.util.exceptions import AblyException from test.ably.testapp import TestApp from test.ably.utils import BaseAsyncTestCase, VaryByProtocolTestsMetaclass, dont_vary_protocol diff --git a/test/ably/rest/restchannelhistory_test.py b/test/ably/rest/restchannelhistory_test.py index a9a2245b..c53c53bb 100644 --- a/test/ably/rest/restchannelhistory_test.py +++ b/test/ably/rest/restchannelhistory_test.py @@ -3,8 +3,8 @@ import pytest import respx -from ably import AblyException -from ably.http.paginatedresult import PaginatedResult +from ably_pubsub.core import AblyException +from ably_pubsub.core.http.paginatedresult import PaginatedResult from test.ably.testapp import TestApp from test.ably.utils import BaseAsyncTestCase, VaryByProtocolTestsMetaclass, dont_vary_protocol diff --git a/test/ably/rest/restchannelmutablemessages_test.py b/test/ably/rest/restchannelmutablemessages_test.py index b4f32ef4..c439365b 100644 --- a/test/ably/rest/restchannelmutablemessages_test.py +++ b/test/ably/rest/restchannelmutablemessages_test.py @@ -3,9 +3,9 @@ import pytest -from ably import AblyException, CipherParams, MessageAction -from ably.types.message import Message -from ably.types.operations import MessageOperation +from ably_pubsub.core import AblyException, CipherParams, MessageAction +from ably_pubsub.core.types.message import Message +from ably_pubsub.core.types.operations import MessageOperation from test.ably.testapp import TestApp from test.ably.utils import BaseAsyncTestCase, assert_waiter diff --git a/test/ably/rest/restchannelpublish_test.py b/test/ably/rest/restchannelpublish_test.py index 41c2018b..963a377c 100644 --- a/test/ably/rest/restchannelpublish_test.py +++ b/test/ably/rest/restchannelpublish_test.py @@ -10,11 +10,11 @@ import msgpack import pytest -from ably import AblyException, IncompatibleClientIdException, api_version -from ably.rest.auth import Auth -from ably.types.message import Message -from ably.types.tokendetails import TokenDetails -from ably.util import case +from ably_pubsub.core import AblyException, IncompatibleClientIdException, api_version +from ably_pubsub.core.rest.auth import Auth +from ably_pubsub.core.types.message import Message +from ably_pubsub.core.types.tokendetails import TokenDetails +from ably_pubsub.core.util import case from test.ably import utils from test.ably.testapp import TestApp from test.ably.utils import BaseAsyncTestCase, VaryByProtocolTestsMetaclass, assert_waiter, dont_vary_protocol @@ -103,7 +103,7 @@ async def test_message_list_generate_one_request(self): expected_messages = [Message(f"name-{i}", str(i)) for i in range(3)] - with mock.patch('ably.rest.rest.Http.post', + with mock.patch('ably_pubsub.core.rest.rest.Http.post', wraps=channel.ably.http.post) as post_mock: await channel.publish(messages=expected_messages) assert post_mock.call_count == 1 @@ -184,7 +184,7 @@ async def test_publish_message_null_name_and_data_keys_arent_sent(self): channel = self.ably.channels[ self.get_channel_name('persisted:null_name_and_data_keys_arent_sent_channel')] - with mock.patch('ably.rest.rest.Http.post', + with mock.patch('ably_pubsub.core.rest.rest.Http.post', wraps=channel.ably.http.post) as post_mock: await channel.publish(name=None, data=None) @@ -244,7 +244,7 @@ async def test_publish_message_without_client_id_on_identified_client(self): channel = self.ably_with_client_id.channels[ self.get_channel_name('persisted:no_client_id_identified_client')] - with mock.patch('ably.rest.rest.Http.post', + with mock.patch('ably_pubsub.core.rest.rest.Http.post', wraps=channel.ably.http.post) as post_mock: await channel.publish(name='publish', data='test') diff --git a/test/ably/rest/restchannels_test.py b/test/ably/rest/restchannels_test.py index b5e59957..339f685f 100644 --- a/test/ably/rest/restchannels_test.py +++ b/test/ably/rest/restchannels_test.py @@ -2,9 +2,9 @@ import pytest -from ably import AblyException -from ably.rest.channel import Channel, Channels, Presence -from ably.util.crypto import generate_random_key +from ably_pubsub.core import AblyException +from ably_pubsub.core.rest.channel import Channel, Channels, Presence +from ably_pubsub.core.util.crypto import generate_random_key from test.ably.testapp import TestApp from test.ably.utils import BaseAsyncTestCase diff --git a/test/ably/rest/restcrypto_test.py b/test/ably/rest/restcrypto_test.py index 94812b29..7aee1cea 100644 --- a/test/ably/rest/restcrypto_test.py +++ b/test/ably/rest/restcrypto_test.py @@ -6,9 +6,9 @@ import pytest from Crypto import Random -from ably import AblyException -from ably.types.message import Message -from ably.util.crypto import CipherParams, generate_random_key, get_cipher, get_default_params +from ably_pubsub.core import AblyException +from ably_pubsub.core.types.message import Message +from ably_pubsub.core.util.crypto import CipherParams, generate_random_key, get_cipher, get_default_params from test.ably import utils from test.ably.testapp import TestApp from test.ably.utils import BaseAsyncTestCase, BaseTestCase, VaryByProtocolTestsMetaclass, dont_vary_protocol diff --git a/test/ably/rest/resthttp_test.py b/test/ably/rest/resthttp_test.py index 01bc6ba6..ab114b9d 100644 --- a/test/ably/rest/resthttp_test.py +++ b/test/ably/rest/resthttp_test.py @@ -9,10 +9,10 @@ import respx from httpx import Response -from ably import AblyRest -from ably.transport.defaults import Defaults -from ably.types.options import Options -from ably.util.exceptions import AblyException +from ably_pubsub.core import AblyRest +from ably_pubsub.core.transport.defaults import Defaults +from ably_pubsub.core.types.options import Options +from ably_pubsub.core.util.exceptions import AblyException from test.ably.testapp import TestApp from test.ably.utils import BaseAsyncTestCase diff --git a/test/ably/rest/restinit_test.py b/test/ably/rest/restinit_test.py index 25e7c5af..04017fb7 100644 --- a/test/ably/rest/restinit_test.py +++ b/test/ably/rest/restinit_test.py @@ -3,9 +3,9 @@ import pytest from httpx import AsyncClient -from ably import AblyException, AblyRest -from ably.transport.defaults import Defaults -from ably.types.tokendetails import TokenDetails +from ably_pubsub.core import AblyException, AblyRest +from ably_pubsub.core.transport.defaults import Defaults +from ably_pubsub.core.types.tokendetails import TokenDetails from test.ably.testapp import TestApp from test.ably.utils import BaseAsyncTestCase, VaryByProtocolTestsMetaclass, dont_vary_protocol @@ -168,8 +168,8 @@ async def test_query_time_param(self): use_binary_protocol=self.use_binary_protocol) timestamp = ably.auth._timestamp - with patch('ably.rest.rest.AblyRest.time', wraps=ably.time) as server_time,\ - patch('ably.rest.auth.Auth._timestamp', wraps=timestamp) as local_time: + with patch('ably_pubsub.core.rest.rest.AblyRest.time', wraps=ably.time) as server_time,\ + patch('ably_pubsub.core.rest.auth.Auth._timestamp', wraps=timestamp) as local_time: await ably.auth.request_token() assert local_time.call_count == 1 assert server_time.call_count == 1 diff --git a/test/ably/rest/restpaginatedresult_test.py b/test/ably/rest/restpaginatedresult_test.py index 9aa85689..6b6f4a4b 100644 --- a/test/ably/rest/restpaginatedresult_test.py +++ b/test/ably/rest/restpaginatedresult_test.py @@ -2,7 +2,7 @@ import respx from httpx import Response -from ably.http.paginatedresult import PaginatedResult +from ably_pubsub.core.http.paginatedresult import PaginatedResult from test.ably.testapp import TestApp from test.ably.utils import BaseAsyncTestCase diff --git a/test/ably/rest/restpresence_test.py b/test/ably/rest/restpresence_test.py index 8767b0c6..48c284b4 100644 --- a/test/ably/rest/restpresence_test.py +++ b/test/ably/rest/restpresence_test.py @@ -3,8 +3,8 @@ import pytest import respx -from ably.http.paginatedresult import PaginatedResult -from ably.types.presence import PresenceMessage +from ably_pubsub.core.http.paginatedresult import PaginatedResult +from ably_pubsub.core.types.presence import PresenceMessage from test.ably.testapp import TestApp from test.ably.utils import BaseAsyncTestCase, VaryByProtocolTestsMetaclass, dont_vary_protocol diff --git a/test/ably/rest/restpush_test.py b/test/ably/rest/restpush_test.py index 867e8b90..57dd4789 100644 --- a/test/ably/rest/restpush_test.py +++ b/test/ably/rest/restpush_test.py @@ -5,8 +5,8 @@ import pytest -from ably import AblyAuthException, AblyException, DeviceDetails, PushChannelSubscription -from ably.http.paginatedresult import PaginatedResult +from ably_pubsub.core import AblyAuthException, AblyException, DeviceDetails, PushChannelSubscription +from ably_pubsub.core.http.paginatedresult import PaginatedResult from test.ably.testapp import TestApp from test.ably.utils import ( BaseAsyncTestCase, diff --git a/test/ably/rest/restrequest_test.py b/test/ably/rest/restrequest_test.py index 967da19e..f0ff20fc 100644 --- a/test/ably/rest/restrequest_test.py +++ b/test/ably/rest/restrequest_test.py @@ -2,9 +2,9 @@ import pytest import respx -from ably import AblyRest -from ably.http.paginatedresult import HttpPaginatedResponse -from ably.transport.defaults import Defaults +from ably_pubsub.core import AblyRest +from ably_pubsub.core.http.paginatedresult import HttpPaginatedResponse +from ably_pubsub.core.transport.defaults import Defaults from test.ably.testapp import TestApp from test.ably.utils import BaseAsyncTestCase, VaryByProtocolTestsMetaclass, dont_vary_protocol diff --git a/test/ably/rest/reststats_test.py b/test/ably/rest/reststats_test.py index cef28817..eecdfe8b 100644 --- a/test/ably/rest/reststats_test.py +++ b/test/ably/rest/reststats_test.py @@ -3,9 +3,9 @@ import pytest -from ably.http.paginatedresult import PaginatedResult -from ably.types.stats import Stats -from ably.util.exceptions import AblyException +from ably_pubsub.core.http.paginatedresult import PaginatedResult +from ably_pubsub.core.types.stats import Stats +from ably_pubsub.core.util.exceptions import AblyException from test.ably.testapp import TestApp from test.ably.utils import BaseAsyncTestCase, VaryByProtocolTestsMetaclass, dont_vary_protocol diff --git a/test/ably/rest/resttime_test.py b/test/ably/rest/resttime_test.py index 4b78620a..e3ce2888 100644 --- a/test/ably/rest/resttime_test.py +++ b/test/ably/rest/resttime_test.py @@ -2,7 +2,7 @@ import pytest -from ably import AblyException +from ably_pubsub.core import AblyException from test.ably.testapp import TestApp from test.ably.utils import BaseAsyncTestCase, VaryByProtocolTestsMetaclass, dont_vary_protocol diff --git a/test/ably/rest/resttoken_test.py b/test/ably/rest/resttoken_test.py index 5052f1be..e58635cf 100644 --- a/test/ably/rest/resttoken_test.py +++ b/test/ably/rest/resttoken_test.py @@ -5,9 +5,9 @@ import pytest -from ably import AblyException, AblyRest, Capability -from ably.types.tokendetails import TokenDetails -from ably.types.tokenrequest import TokenRequest +from ably_pubsub.core import AblyException, AblyRest, Capability +from ably_pubsub.core.types.tokendetails import TokenDetails +from ably_pubsub.core.types.tokenrequest import TokenRequest from test.ably.testapp import TestApp from test.ably.utils import BaseAsyncTestCase, VaryByProtocolTestsMetaclass, dont_vary_protocol @@ -120,8 +120,8 @@ async def test_token_generation_with_invalid_ttl(self): async def test_token_generation_with_local_time(self): timestamp = self.ably.auth._timestamp - with patch('ably.rest.rest.AblyRest.time', wraps=self.ably.time) as server_time,\ - patch('ably.rest.auth.Auth._timestamp', wraps=timestamp) as local_time: + with patch('ably_pubsub.core.rest.rest.AblyRest.time', wraps=self.ably.time) as server_time,\ + patch('ably_pubsub.core.rest.auth.Auth._timestamp', wraps=timestamp) as local_time: await self.ably.auth.request_token() assert local_time.called assert not server_time.called @@ -129,8 +129,8 @@ async def test_token_generation_with_local_time(self): # RSA10k async def test_token_generation_with_server_time(self): timestamp = self.ably.auth._timestamp - with patch('ably.rest.rest.AblyRest.time', wraps=self.ably.time) as server_time,\ - patch('ably.rest.auth.Auth._timestamp', wraps=timestamp) as local_time: + with patch('ably_pubsub.core.rest.rest.AblyRest.time', wraps=self.ably.time) as server_time,\ + patch('ably_pubsub.core.rest.auth.Auth._timestamp', wraps=timestamp) as local_time: await self.ably.auth.request_token(query_time=True) assert local_time.call_count == 1 assert server_time.call_count == 1 @@ -182,8 +182,8 @@ async def test_key_name_and_secret_are_required(self): @dont_vary_protocol async def test_with_local_time(self): timestamp = self.ably.auth._timestamp - with patch('ably.rest.rest.AblyRest.time', wraps=self.ably.time) as server_time,\ - patch('ably.rest.auth.Auth._timestamp', wraps=timestamp) as local_time: + with patch('ably_pubsub.core.rest.rest.AblyRest.time', wraps=self.ably.time) as server_time,\ + patch('ably_pubsub.core.rest.auth.Auth._timestamp', wraps=timestamp) as local_time: await self.ably.auth.create_token_request( key_name=self.key_name, key_secret=self.key_secret, query_time=False) assert local_time.called @@ -193,8 +193,8 @@ async def test_with_local_time(self): @dont_vary_protocol async def test_with_server_time(self): timestamp = self.ably.auth._timestamp - with patch('ably.rest.rest.AblyRest.time', wraps=self.ably.time) as server_time,\ - patch('ably.rest.auth.Auth._timestamp', wraps=timestamp) as local_time: + with patch('ably_pubsub.core.rest.rest.AblyRest.time', wraps=self.ably.time) as server_time,\ + patch('ably_pubsub.core.rest.auth.Auth._timestamp', wraps=timestamp) as local_time: await self.ably.auth.create_token_request( key_name=self.key_name, key_secret=self.key_secret, query_time=True) assert local_time.call_count == 1 @@ -329,7 +329,7 @@ async def test_hmac(self): # AO2g @dont_vary_protocol async def test_query_server_time(self): - with patch('ably.rest.rest.AblyRest.time', wraps=self.ably.time) as server_time: + with patch('ably_pubsub.core.rest.rest.AblyRest.time', wraps=self.ably.time) as server_time: await self.ably.auth.create_token_request( key_name=self.key_name, key_secret=self.key_secret, query_time=True) assert server_time.call_count == 1 diff --git a/test/ably/testapp.py b/test/ably/testapp.py index f657fdd4..2d2a6864 100644 --- a/test/ably/testapp.py +++ b/test/ably/testapp.py @@ -2,12 +2,12 @@ import logging import os -from ably.realtime.realtime import AblyRealtime -from ably.rest.rest import AblyRest -from ably.transport.defaults import Defaults -from ably.types.capability import Capability -from ably.types.options import Options -from ably.util.exceptions import AblyException +from ably_pubsub.core.realtime.realtime import AblyRealtime +from ably_pubsub.core.rest.rest import AblyRest +from ably_pubsub.core.transport.defaults import Defaults +from ably_pubsub.core.types.capability import Capability +from ably_pubsub.core.types.options import Options +from ably_pubsub.core.util.exceptions import AblyException log = logging.getLogger(__name__) diff --git a/test/ably/utils.py b/test/ably/utils.py index ae19e0b5..368a8012 100644 --- a/test/ably/utils.py +++ b/test/ably/utils.py @@ -11,7 +11,7 @@ import respx from httpx import Response -from ably.http.http import Http +from ably_pubsub.core.http.http import Http class BaseTestCase: diff --git a/test/unit/annotation_test.py b/test/unit/annotation_test.py index 2cfb0bef..977d86cb 100644 --- a/test/unit/annotation_test.py +++ b/test/unit/annotation_test.py @@ -15,11 +15,11 @@ import pytest -from ably.rest.annotations import construct_validate_annotation, serial_from_msg_or_serial -from ably.types.annotation import Annotation, AnnotationAction -from ably.types.message import Message -from ably.util.crypto import generate_random_key, get_cipher -from ably.util.exceptions import AblyException +from ably_pubsub.core.rest.annotations import construct_validate_annotation, serial_from_msg_or_serial +from ably_pubsub.core.types.annotation import Annotation, AnnotationAction +from ably_pubsub.core.types.message import Message +from ably_pubsub.core.util.crypto import generate_random_key, get_cipher +from ably_pubsub.core.util.exceptions import AblyException # --- RSAN1a3: type validation --- diff --git a/test/unit/http_test.py b/test/unit/http_test.py index 61e0d35e..00d9aef8 100644 --- a/test/unit/http_test.py +++ b/test/unit/http_test.py @@ -1,4 +1,4 @@ -from ably import AblyRest +from ably_pubsub.core import AblyRest def test_http_get_rest_hosts_works_when_fallback_realtime_host_is_set(): diff --git a/test/unit/message_test.py b/test/unit/message_test.py index 4902d6b5..e3f663e8 100644 --- a/test/unit/message_test.py +++ b/test/unit/message_test.py @@ -1,4 +1,4 @@ -import ably.types.message +import ably_pubsub.core.types.message # TM2a, TM2c, TM2f @@ -14,7 +14,7 @@ def test_update_inner_message_fields_tm2(): } ] } - ably.types.message.Message.update_inner_message_fields(proto_msg) + ably_pubsub.core.types.message.Message.update_inner_message_fields(proto_msg) messages: list[dict] = proto_msg.get('messages') msg_index = 0 for msg in messages: @@ -37,7 +37,7 @@ def test_update_inner_message_fields_for_presence_msg_tm2(): } ] } - ably.types.message.Message.update_inner_message_fields(proto_msg) + ably_pubsub.core.types.message.Message.update_inner_message_fields(proto_msg) presence_messages: list[dict] = proto_msg.get('presence') msg_index = 0 for presence_msg in presence_messages: diff --git a/test/unit/mutable_message_test.py b/test/unit/mutable_message_test.py index 8ce603b9..86fe9062 100644 --- a/test/unit/mutable_message_test.py +++ b/test/unit/mutable_message_test.py @@ -1,5 +1,5 @@ -from ably import MessageAction, MessageOperation, MessageVersion, UpdateDeleteResult -from ably.types.message import Message +from ably_pubsub.core import MessageAction, MessageOperation, MessageVersion, UpdateDeleteResult +from ably_pubsub.core.types.message import Message def test_message_version_none_values_filtered(): @@ -137,7 +137,7 @@ def test_message_extras_none_excluded_from_as_dict(): # RSL15b, RTL32b, TM2u def test_message_annotations_preserved_in_as_dict(): """Test that annotations are included when a Message with annotations is serialized.""" - from ably.types.message import MessageAnnotations + from ably_pubsub.core.types.message import MessageAnnotations annotations = MessageAnnotations(summary={'reaction:distinct.v1': {'thumbsup': 5}}) message = Message( name='test', diff --git a/test/unit/options_test.py b/test/unit/options_test.py index d3ba6129..d349ade3 100644 --- a/test/unit/options_test.py +++ b/test/unit/options_test.py @@ -1,7 +1,7 @@ import pytest -from ably.types.options import Options -from ably.util.exceptions import AblyException +from ably_pubsub.core.types.options import Options +from ably_pubsub.core.util.exceptions import AblyException # REC1b1: endpoint is incompatible with deprecated options From 7b07d9254f906c2e0064ca2843b3ef20dcf9360d Mon Sep 17 00:00:00 2001 From: umair Date: Thu, 3 Sep 2026 13:22:04 +0100 Subject: [PATCH 2/7] Build two distributions from a uv workspace MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PDR-091b splits the Pub/Sub SDK so the package an application installs names the side it runs on, and builds the new packages on a new core rather than on the existing `ably` distribution. This repo therefore stops publishing `ably` and starts publishing two distributions: - `ably-pubsub-core` (core/) ships `ably_pubsub/core/**`. Its description says plainly that it is an internal implementation package. - `ably-pubsub-server` (server/) ships `ably_pubsub/server/**` and pins `ably-pubsub-core==4.0.0` exactly, the analogue of ably-js's exact peer dependency: lockstep versions, and never two cores in one environment. `ably_pubsub` is a PEP 420 namespace with no `__init__.py` in either source tree, so the two wheels can each contribute a subpackage to it and pip never has two distributions writing the same files. That is also why the import namespace is not `ably`: an environment mid-migration may hold both `ably` 3.x and this SDK, and they must not overwrite each other. Both distributions start at 4.0.0 — 3.1.2 is what `ably` reached, and starting over at 1.0.0 would read as a downgrade. `requires-python` becomes ">=3.8", which is what CI already tests; only the 3.7 dependency branches and the two 3.7 mock shims go. The extras (crypto, vcdiff, oldcrypto) forward from server to core at the same exact pin. The root pyproject is now a workspace root only: no publishable [project], just the members, the dev dependency group and the shared pytest/ruff configuration. Locally `[tool.uv.sources]` resolves the pin to the checkout, so `uv sync` gives one venv with both members editable. ruff gains an explicit target-version, which it can no longer infer without a [project] table. unasync now generates `core/src/ably_pubsub/core/sync` from `core/src/ably_pubsub/core`. Its import rewrite keys on the full `ably_pubsub.core` prefix rather than the namespace root, so it cannot reach into `ably_pubsub.server`, whose sync door is hand-written. Co-Authored-By: Claude Opus 5 --- .gitignore | 4 +- LONG_DESCRIPTION.rst | 20 - core/README.md | 33 + core/pyproject.toml | 68 ++ core/src/ably_pubsub/core/__init__.py | 2 +- core/src/ably_pubsub/core/scripts/unasync.py | 20 +- pyproject.toml | 112 +-- server/README.md | 99 +++ server/pyproject.toml | 62 ++ test/ably/rest/encoders_test.py | 7 +- test/ably/rest/restauth_test.py | 7 +- uv.lock | 686 +++---------------- 12 files changed, 402 insertions(+), 718 deletions(-) delete mode 100644 LONG_DESCRIPTION.rst create mode 100644 core/README.md create mode 100644 core/pyproject.toml create mode 100644 server/README.md create mode 100644 server/pyproject.toml diff --git a/.gitignore b/.gitignore index 75ec0f34..c20685d5 100644 --- a/.gitignore +++ b/.gitignore @@ -51,9 +51,9 @@ test_vars_out pytest app_spec app_spec.pkl -ably/types/options.py.orig +core/src/ably_pubsub/core/types/options.py.orig test/ably/restsetup.py.orig .idea/**/* -ably/sync/** +core/src/ably_pubsub/core/sync/** test/ably/sync/** diff --git a/LONG_DESCRIPTION.rst b/LONG_DESCRIPTION.rst deleted file mode 100644 index 3e4a6aed..00000000 --- a/LONG_DESCRIPTION.rst +++ /dev/null @@ -1,20 +0,0 @@ -Official Ably Bindings for Python -================================== - -A Python client library for Ably Realtime messaging. - - -Setup ------ - -You can install this package by using the pip tool and installing: - - pip install ably - - -Using Ably for Python ---------------------- - -- Sign up for Ably at https://ably.com/sign-up -- Get usage examples at https://github.com/ably/ably-python -- Visit https://ably.com/docs for a complete API reference and more examples diff --git a/core/README.md b/core/README.md new file mode 100644 index 00000000..6c3a8697 --- /dev/null +++ b/core/README.md @@ -0,0 +1,33 @@ +# ably-pubsub-core + +**This is an internal implementation package. Do not depend on it directly.** + +`ably-pubsub-core` holds the shared implementation of Ably's Pub/Sub SDK for +Python: the HTTP and realtime clients, channels, presence, authentication, +encryption and the message types. It is published so that the packages +applications *do* install can depend on one shared implementation, pinned to an +exact version. + +Install the package that names the side your code runs on instead: + +| Where your code runs | Install | Import | +| --- | --- | --- | +| A server or other trusted environment | `ably-pubsub-server` | `ably_pubsub.server` | + +Nothing under `ably_pubsub.core` is public API. Its module layout, and the +names within it, may change in any release — including patch releases — without +a deprecation cycle. The supported surface is what `ably_pubsub.server` +re-exports. + +`ably_pubsub` is a [PEP 420](https://peps.python.org/pep-0420/) namespace +package: this distribution ships `ably_pubsub/core/**` and never +`ably_pubsub/__init__.py`, so other distributions can contribute their own +subpackages to the same namespace. + +## Contributing + +See [CONTRIBUTING.md](https://github.com/ably/ably-python/blob/main/CONTRIBUTING.md). + +## License + +Apache License 2.0 — see [LICENSE](https://github.com/ably/ably-python/blob/main/LICENSE). diff --git a/core/pyproject.toml b/core/pyproject.toml new file mode 100644 index 00000000..b103fdb5 --- /dev/null +++ b/core/pyproject.toml @@ -0,0 +1,68 @@ +[project] +name = "ably-pubsub-core" +version = "4.0.0" +description = "INTERNAL implementation package for Ably's Pub/Sub SDKs. Not for direct use — install ably-pubsub-server instead." +readme = "README.md" +requires-python = ">=3.8" +license = { text = "Apache-2.0" } +authors = [ + { name = "Ably", email = "support@ably.com" } +] +classifiers = [ + "Development Status :: 5 - Production/Stable", + "Intended Audience :: Developers", + "License :: OSI Approved :: Apache Software License", + "Operating System :: OS Independent", + "Programming Language :: Python", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", + "Programming Language :: Python :: 3.14", + "Topic :: Software Development :: Libraries :: Python Modules", +] +dependencies = [ + "msgpack>=1.0.0,<2.0.0", + "httpx>=0.25.0,<1.0", + "h2>=4.1.0,<5.0.0", + "websockets>=12.0,<15.0; python_version=='3.8'", + "websockets>=15.0,<16.0; python_version>='3.9'", + "pyee>=11.1.0,<14.0.0", +] + +[project.optional-dependencies] +oldcrypto = ["pycrypto>=2.6.1,<3.0.0"] +crypto = ["pycryptodome"] +vcdiff = ["vcdiff-decoder>=0.1.0,<0.2.0"] + +[project.scripts] +unasync = "ably_pubsub.core.scripts.unasync:run" + +[project.urls] +Homepage = "https://ably.com" +Repository = "https://github.com/ably/ably-python" + +[build-system] +requires = ["hatchling"] +build-backend = "hatchling.build" + +[tool.hatch.build.targets.sdist] +ignore-vcs = true +include = [ + "/src/ably_pubsub", + "/README.md", + "/pyproject.toml" +] +exclude = [ + "**/*.pyc", + "**/__pycache__" +] + +[tool.hatch.build.targets.wheel] +ignore-vcs = true +# PEP 420: `src/ably_pubsub` has no __init__.py, so this ships +# `ably_pubsub/core/**` into the shared `ably_pubsub` namespace. +packages = ["src/ably_pubsub"] diff --git a/core/src/ably_pubsub/core/__init__.py b/core/src/ably_pubsub/core/__init__.py index 80775b78..73d161f9 100644 --- a/core/src/ably_pubsub/core/__init__.py +++ b/core/src/ably_pubsub/core/__init__.py @@ -21,4 +21,4 @@ logger.addHandler(logging.NullHandler()) api_version = '5' -lib_version = '3.1.2' +lib_version = '4.0.0' diff --git a/core/src/ably_pubsub/core/scripts/unasync.py b/core/src/ably_pubsub/core/scripts/unasync.py index e95b14ac..10f09075 100644 --- a/core/src/ably_pubsub/core/scripts/unasync.py +++ b/core/src/ably_pubsub/core/scripts/unasync.py @@ -241,7 +241,10 @@ def run(): _TOKEN_REPLACE["aclose"] = "close" _TOKEN_REPLACE["assert_waiter"] = "assert_waiter_sync" - _IMPORTS_REPLACE["ably"] = "ably_pubsub.core.sync" + # Matched as a substring of the dotted module path, so this must be the full + # `ably_pubsub.core` prefix: a bare "ably_pubsub" would also rewrite + # `ably_pubsub.server`, which is hand-written and never generated. + _IMPORTS_REPLACE["ably_pubsub.core"] = "ably_pubsub.core.sync" # here... for class_name in rename_classes: @@ -249,8 +252,10 @@ def run(): _STRING_REPLACE["Auth"] = "AuthSync" - src_dir_path = os.path.join(os.getcwd(), "ably") - dest_dir_path = os.path.join(os.getcwd(), "ably", "sync") + # The server distribution's sync door is hand-written, so only `core/` is a + # generation source. + src_dir_path = os.path.join(os.getcwd(), "core", "src", "ably_pubsub", "core") + dest_dir_path = os.path.join(src_dir_path, "sync") relevant_src_files = (set(find_files(src_dir_path, "*.py")) - set(find_files(dest_dir_path, "*.py"))) @@ -269,14 +274,17 @@ def run(): _IMPORTS_REPLACE["test.ably"] = "test.ably.sync" _STRING_REPLACE['/../assets/testAppSpec.json'] = '/../../assets/testAppSpec.json' - _STRING_REPLACE['ably_pubsub.core.rest.auth.Auth.request_token'] = 'ably_pubsub.core.sync.rest.auth.AuthSync.request_token' + _STRING_REPLACE['ably_pubsub.core.rest.auth.Auth.request_token'] = \ + 'ably_pubsub.core.sync.rest.auth.AuthSync.request_token' _STRING_REPLACE['ably_pubsub.core.rest.auth.TokenRequest'] = 'ably_pubsub.core.sync.rest.auth.TokenRequest' _STRING_REPLACE['ably_pubsub.core.rest.rest.Http.post'] = 'ably_pubsub.core.sync.rest.rest.HttpSync.post' _STRING_REPLACE['httpx.AsyncClient.send'] = 'httpx.Client.send' _STRING_REPLACE['ably_pubsub.core.util.exceptions.AblyException.raise_for_response'] = \ 'ably_pubsub.core.sync.util.exceptions.AblyException.raise_for_response' - _STRING_REPLACE['ably_pubsub.core.rest.rest.AblyRest.time'] = 'ably_pubsub.core.sync.rest.rest.AblyRestSync.time' - _STRING_REPLACE['ably_pubsub.core.rest.auth.Auth._timestamp'] = 'ably_pubsub.core.sync.rest.auth.AuthSync._timestamp' + _STRING_REPLACE['ably_pubsub.core.rest.rest.AblyRest.time'] = \ + 'ably_pubsub.core.sync.rest.rest.AblyRestSync.time' + _STRING_REPLACE['ably_pubsub.core.rest.auth.Auth._timestamp'] = \ + 'ably_pubsub.core.sync.rest.auth.AuthSync._timestamp' # round 1 src_dir_path = os.path.join(os.getcwd(), "test", "ably") diff --git a/pyproject.toml b/pyproject.toml index e4dbab6e..9c38daa3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,108 +1,47 @@ -[project] -name = "ably" -version = "3.1.2" -description = "Python REST and Realtime client library SDK for Ably realtime messaging service" -readme = "LONG_DESCRIPTION.rst" -requires-python = ">=3.7" -license = { text = "Apache-2.0" } -authors = [ - { name = "Ably", email = "support@ably.com" } -] -classifiers = [ - "Development Status :: 6 - Mature", - "Intended Audience :: Developers", - "License :: OSI Approved :: Apache Software License", - "Operating System :: OS Independent", - "Programming Language :: Python", - "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.7", - "Programming Language :: Python :: 3.8", - "Programming Language :: Python :: 3.9", - "Programming Language :: Python :: 3.10", - "Programming Language :: Python :: 3.11", - "Programming Language :: Python :: 3.12", - "Programming Language :: Python :: 3.13", - "Programming Language :: Python :: 3.14", - "Topic :: Software Development :: Libraries :: Python Modules", -] -dependencies = [ - "msgpack>=1.0.0,<2.0.0", - "httpx>=0.24.1,<1.0; python_version=='3.7'", - "httpx>=0.25.0,<1.0; python_version>='3.8'", - "h2>=4.1.0,<5.0.0", - "websockets>=10.0,<12.0; python_version=='3.7'", - "websockets>=12.0,<15.0; python_version=='3.8'", - "websockets>=15.0,<16.0; python_version>='3.9'", - "pyee>=9.0.4,<10.0.0; python_version=='3.7'", - "pyee>=11.1.0,<14.0.0; python_version>='3.8'", -] +# Workspace root. This file is not published: the two distributions built from +# this repository are `core/` (ably-pubsub-core) and `server/` (ably-pubsub-server). +# It carries the shared developer tooling configuration only. -[project.optional-dependencies] -oldcrypto = ["pycrypto>=2.6.1,<3.0.0"] -crypto = ["pycryptodome"] -vcdiff = ["vcdiff-decoder>=0.1.0,<0.2.0"] +[tool.uv.workspace] +members = ["core", "server"] + +[tool.uv.sources] +ably-pubsub-core = { workspace = true } +ably-pubsub-server = { workspace = true } + +[dependency-groups] dev = [ + "ably-pubsub-core[crypto,vcdiff]", + "ably-pubsub-server", "pytest>=7.1,<8.0", - "pytest-asyncio>=0.21.0,<0.23.0; python_version=='3.7'", - "pytest-asyncio>=0.23.0,<1.0.0; python_version>='3.8'", + "pytest-asyncio>=0.23.0,<1.0.0", "mock>=4.0.3,<5.0.0", "pytest-cov>=2.4,<3.0", "ruff>=0.14.0,<1.0.0", "pytest-xdist>=1.15,<2.0", - "respx>=0.20.0,<0.21.0; python_version=='3.7'", - "respx>=0.22.0,<0.23.0; python_version>='3.8'", + "respx>=0.22.0,<0.23.0", "importlib-metadata>=4.12,<5.0", "pytest-timeout>=2.1.0,<3.0.0", - "async-case>=10.1.0,<11.0.0; python_version=='3.7'", "tokenize_rt", "vcdiff-decoder>=0.1.0a1", ] -[project.scripts] -unasync = "ably.scripts.unasync:run" - -[project.urls] -Homepage = "https://ably.com" -Repository = "https://github.com/ably/ably-python" - -[build-system] -requires = ["hatchling"] -build-backend = "hatchling.build" - -[tool.hatch.build.targets.sdist] -ignore-vcs = true -include = [ - "/ably", - "/COPYRIGHT", - "/README.md", - "/LICENSE", - "/LONG_DESCRIPTION.rst", - "/images", - "/setup.cfg", - "/pyproject.toml" -] -exclude = [ - "**/*.pyc", - "**/__pycache__" -] - -[tool.hatch.build.targets.wheel] -ignore-vcs = true -packages = ["ably"] - -[tool.pytest.ini_options] -timeout = 30 -asyncio_mode = "auto" - [[tool.uv.index]] name = "experimental" url = "https://test.pypi.org/simple/" explicit = true +[tool.pytest.ini_options] +timeout = 30 +asyncio_mode = "auto" + [tool.ruff] line-length = 115 +# The workspace root has no [project] table for ruff to infer this from; it must +# match `requires-python` in core/ and server/. +target-version = "py38" extend-exclude = [ - "ably/sync", + "core/src/ably_pubsub/core/sync", "test/ably/sync", ] @@ -111,8 +50,11 @@ extend-exclude = [ select = ["E", "W", "F", "N", "I", "UP", "B", "C4"] ignore = [ "N818", # exception name should end in 'Error' - "UP026", # mock -> unittest.mock (need mock package for Python 3.7 AsyncMock support) + "UP026", # mock -> unittest.mock (need mock package for AsyncMock support on old Pythons) ] +[tool.ruff.lint.isort] +known-first-party = ["ably_pubsub"] + [tool.ruff.lint.per-file-ignores] "__init__.py" = ["F401"] # imported but unused diff --git a/server/README.md b/server/README.md new file mode 100644 index 00000000..a67f195e --- /dev/null +++ b/server/README.md @@ -0,0 +1,99 @@ +# ably-pubsub-server + +The [Ably](https://ably.com) Pub/Sub SDK for Python **servers** — backends, jobs, +and any other trusted environment that holds an API key. + +Ably is the platform that powers synchronized digital experiences in realtime. +Pub/Sub is its foundational product: publish and subscribe messaging over +channels, presence, history, and token issuing. + +Choosing the package by side matters beyond naming: connections made by this +package declare themselves as server-side on the wire, and server connections +are exempt from monthly-active-user counting. + +## Installation + +```shell +pip install ably-pubsub-server +``` + +Optional extras: `crypto` (channel encryption, via pycryptodome) and `vcdiff` +(delta decoding). + +```shell +pip install "ably-pubsub-server[crypto]" +``` + +## Usage + +Create clients through the factory functions — they are the entry points of this +package. + +```python +from ably_pubsub.server import create_http_client, create_realtime_client +``` + +### Stateless HTTP client + +For publishing, history, presence reads, stats and token issuing: + +```python +import asyncio +from ably_pubsub.server import create_http_client + + +async def main(): + async with create_http_client(key='your-api-key') as client: + channel = client.channels.get('some-channel') + await channel.publish('greeting', 'hello') + +asyncio.run(main()) +``` + +A synchronous flavour of the HTTP client is available for code that has no event +loop: + +```python +from ably_pubsub.server.sync import create_http_client + +client = create_http_client(key='your-api-key') +client.channels.get('some-channel').publish('greeting', 'hello') +``` + +### Realtime client + +When the server also needs to subscribe to channels or enter presence over a +persistent connection: + +```python +import asyncio +from ably_pubsub.server import create_realtime_client + + +async def main(): + client = create_realtime_client(key='your-api-key') + channel = client.channels.get('some-channel') + await channel.subscribe(lambda message: print(message.data)) + await asyncio.sleep(10) + await client.close() + +asyncio.run(main()) +``` + +There is no synchronous realtime client. + +## Relationship to other packages + +- `ably-pubsub-core` — the shared implementation this package is built on. It is + an internal package; do not import `ably_pubsub.core` directly. Everything + supported is re-exported from `ably_pubsub.server`. +- `ably` — the 3.x package this one replaces. See + [UPDATING.md](https://github.com/ably/ably-python/blob/main/UPDATING.md). + +## Contributing + +See [CONTRIBUTING.md](https://github.com/ably/ably-python/blob/main/CONTRIBUTING.md). + +## License + +Apache License 2.0 — see [LICENSE](https://github.com/ably/ably-python/blob/main/LICENSE). diff --git a/server/pyproject.toml b/server/pyproject.toml new file mode 100644 index 00000000..19a9960a --- /dev/null +++ b/server/pyproject.toml @@ -0,0 +1,62 @@ +[project] +name = "ably-pubsub-server" +version = "4.0.0" +description = "Ably Pub/Sub SDK for Python servers — realtime messaging for trusted server environments" +readme = "README.md" +requires-python = ">=3.8" +license = { text = "Apache-2.0" } +authors = [ + { name = "Ably", email = "support@ably.com" } +] +classifiers = [ + "Development Status :: 5 - Production/Stable", + "Intended Audience :: Developers", + "License :: OSI Approved :: Apache Software License", + "Operating System :: OS Independent", + "Programming Language :: Python", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", + "Programming Language :: Python :: 3.14", + "Topic :: Software Development :: Libraries :: Python Modules", +] +# Exact pin: core and server are released in lockstep, and two core versions in +# one environment would be indistinguishable on the wire. +dependencies = [ + "ably-pubsub-core==4.0.0", +] + +[project.optional-dependencies] +oldcrypto = ["ably-pubsub-core[oldcrypto]==4.0.0"] +crypto = ["ably-pubsub-core[crypto]==4.0.0"] +vcdiff = ["ably-pubsub-core[vcdiff]==4.0.0"] + +[project.urls] +Homepage = "https://ably.com" +Repository = "https://github.com/ably/ably-python" + +[build-system] +requires = ["hatchling"] +build-backend = "hatchling.build" + +[tool.hatch.build.targets.sdist] +ignore-vcs = true +include = [ + "/src/ably_pubsub", + "/README.md", + "/pyproject.toml" +] +exclude = [ + "**/*.pyc", + "**/__pycache__" +] + +[tool.hatch.build.targets.wheel] +ignore-vcs = true +# PEP 420: `src/ably_pubsub` has no __init__.py, so this ships +# `ably_pubsub/server/**` into the shared `ably_pubsub` namespace. +packages = ["src/ably_pubsub"] diff --git a/test/ably/rest/encoders_test.py b/test/ably/rest/encoders_test.py index a3279540..09e3243a 100644 --- a/test/ably/rest/encoders_test.py +++ b/test/ably/rest/encoders_test.py @@ -1,8 +1,8 @@ import base64 import json import logging -import sys from unittest import mock +from unittest.mock import AsyncMock import msgpack import pytest @@ -13,11 +13,6 @@ from test.ably.testapp import TestApp from test.ably.utils import BaseAsyncTestCase -if sys.version_info >= (3, 8): - from unittest.mock import AsyncMock -else: - from mock import AsyncMock - log = logging.getLogger(__name__) diff --git a/test/ably/rest/restauth_test.py b/test/ably/rest/restauth_test.py index e19e4563..8986b390 100644 --- a/test/ably/rest/restauth_test.py +++ b/test/ably/rest/restauth_test.py @@ -1,9 +1,9 @@ import base64 import logging -import sys import time import uuid from unittest import mock +from unittest.mock import AsyncMock from urllib.parse import parse_qs import pytest @@ -16,11 +16,6 @@ from test.ably.testapp import TestApp from test.ably.utils import BaseAsyncTestCase, VaryByProtocolTestsMetaclass, dont_vary_protocol -if sys.version_info >= (3, 8): - from unittest.mock import AsyncMock -else: - from mock import AsyncMock - log = logging.getLogger(__name__) diff --git a/uv.lock b/uv.lock index 30a4df76..1849fe9e 100644 --- a/uv.lock +++ b/uv.lock @@ -1,29 +1,47 @@ version = 1 -revision = 3 -requires-python = ">=3.7" +revision = 2 +requires-python = ">=3.8" resolution-markers = [ "python_full_version >= '3.10'", "python_full_version == '3.9.*'", - "python_full_version == '3.8.*'", - "python_full_version < '3.8'", + "python_full_version < '3.9'", ] -[[package]] -name = "ably" -version = "3.1.2" -source = { editable = "." } +[manifest] +members = [ + "ably-pubsub-core", + "ably-pubsub-server", +] + +[manifest.dependency-groups] +dev = [ + { name = "ably-pubsub-core", extras = ["crypto", "vcdiff"], editable = "core" }, + { name = "ably-pubsub-server", editable = "server" }, + { name = "importlib-metadata", specifier = ">=4.12,<5.0" }, + { name = "mock", specifier = ">=4.0.3,<5.0.0" }, + { name = "pytest", specifier = ">=7.1,<8.0" }, + { name = "pytest-asyncio", specifier = ">=0.23.0,<1.0.0" }, + { name = "pytest-cov", specifier = ">=2.4,<3.0" }, + { name = "pytest-timeout", specifier = ">=2.1.0,<3.0.0" }, + { name = "pytest-xdist", specifier = ">=1.15,<2.0" }, + { name = "respx", specifier = ">=0.22.0,<0.23.0" }, + { name = "ruff", specifier = ">=0.14.0,<1.0.0" }, + { name = "tokenize-rt" }, + { name = "vcdiff-decoder", specifier = ">=0.1.0a1" }, +] + +[[package]] +name = "ably-pubsub-core" +version = "4.0.0" +source = { editable = "core" } dependencies = [ { name = "h2", version = "4.1.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.9'" }, { name = "h2", version = "4.3.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.9'" }, - { name = "httpx", version = "0.24.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.8'" }, - { name = "httpx", version = "0.28.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.8'" }, - { name = "msgpack", version = "1.0.5", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.8'" }, - { name = "msgpack", version = "1.1.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.8.*'" }, + { name = "httpx" }, + { name = "msgpack", version = "1.1.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.9'" }, { name = "msgpack", version = "1.1.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.9'" }, - { name = "pyee", version = "9.1.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.8'" }, - { name = "pyee", version = "13.0.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.8'" }, - { name = "websockets", version = "11.0.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.8'" }, - { name = "websockets", version = "13.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.8.*'" }, + { name = "pyee" }, + { name = "websockets", version = "13.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.9'" }, { name = "websockets", version = "15.0.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.9'" }, ] @@ -31,24 +49,6 @@ dependencies = [ crypto = [ { name = "pycryptodome" }, ] -dev = [ - { name = "async-case", marker = "python_full_version < '3.8'" }, - { name = "importlib-metadata" }, - { name = "mock" }, - { name = "pytest" }, - { name = "pytest-asyncio", version = "0.21.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.8'" }, - { name = "pytest-asyncio", version = "0.23.8", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.8'" }, - { name = "pytest-cov" }, - { name = "pytest-timeout" }, - { name = "pytest-xdist" }, - { name = "respx", version = "0.20.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.8'" }, - { name = "respx", version = "0.22.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.8'" }, - { name = "ruff" }, - { name = "tokenize-rt", version = "5.0.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.8'" }, - { name = "tokenize-rt", version = "6.0.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.8.*'" }, - { name = "tokenize-rt", version = "6.2.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.9'" }, - { name = "vcdiff-decoder" }, -] oldcrypto = [ { name = "pycrypto" }, ] @@ -58,65 +58,58 @@ vcdiff = [ [package.metadata] requires-dist = [ - { name = "async-case", marker = "python_full_version == '3.7.*' and extra == 'dev'", specifier = ">=10.1.0,<11.0.0" }, { name = "h2", specifier = ">=4.1.0,<5.0.0" }, - { name = "httpx", marker = "python_full_version == '3.7.*'", specifier = ">=0.24.1,<1.0" }, - { name = "httpx", marker = "python_full_version >= '3.8'", specifier = ">=0.25.0,<1.0" }, - { name = "importlib-metadata", marker = "extra == 'dev'", specifier = ">=4.12,<5.0" }, - { name = "mock", marker = "extra == 'dev'", specifier = ">=4.0.3,<5.0.0" }, + { name = "httpx", specifier = ">=0.25.0,<1.0" }, { name = "msgpack", specifier = ">=1.0.0,<2.0.0" }, { name = "pycrypto", marker = "extra == 'oldcrypto'", specifier = ">=2.6.1,<3.0.0" }, { name = "pycryptodome", marker = "extra == 'crypto'" }, - { name = "pyee", marker = "python_full_version == '3.7.*'", specifier = ">=9.0.4,<10.0.0" }, - { name = "pyee", marker = "python_full_version >= '3.8'", specifier = ">=11.1.0,<14.0.0" }, - { name = "pytest", marker = "extra == 'dev'", specifier = ">=7.1,<8.0" }, - { name = "pytest-asyncio", marker = "python_full_version == '3.7.*' and extra == 'dev'", specifier = ">=0.21.0,<0.23.0" }, - { name = "pytest-asyncio", marker = "python_full_version >= '3.8' and extra == 'dev'", specifier = ">=0.23.0,<1.0.0" }, - { name = "pytest-cov", marker = "extra == 'dev'", specifier = ">=2.4,<3.0" }, - { name = "pytest-timeout", marker = "extra == 'dev'", specifier = ">=2.1.0,<3.0.0" }, - { name = "pytest-xdist", marker = "extra == 'dev'", specifier = ">=1.15,<2.0" }, - { name = "respx", marker = "python_full_version == '3.7.*' and extra == 'dev'", specifier = ">=0.20.0,<0.21.0" }, - { name = "respx", marker = "python_full_version >= '3.8' and extra == 'dev'", specifier = ">=0.22.0,<0.23.0" }, - { name = "ruff", marker = "extra == 'dev'", specifier = ">=0.14.0,<1.0.0" }, - { name = "tokenize-rt", marker = "extra == 'dev'" }, - { name = "vcdiff-decoder", marker = "extra == 'dev'", specifier = ">=0.1.0a1" }, + { name = "pyee", specifier = ">=11.1.0,<14.0.0" }, { name = "vcdiff-decoder", marker = "extra == 'vcdiff'", specifier = ">=0.1.0,<0.2.0" }, - { name = "websockets", marker = "python_full_version == '3.7.*'", specifier = ">=10.0,<12.0" }, { name = "websockets", marker = "python_full_version == '3.8.*'", specifier = ">=12.0,<15.0" }, { name = "websockets", marker = "python_full_version >= '3.9'", specifier = ">=15.0,<16.0" }, ] -provides-extras = ["oldcrypto", "crypto", "vcdiff", "dev"] +provides-extras = ["oldcrypto", "crypto", "vcdiff"] [[package]] -name = "anyio" -version = "3.7.1" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version < '3.8'", -] +name = "ably-pubsub-server" +version = "4.0.0" +source = { editable = "server" } dependencies = [ - { name = "exceptiongroup", marker = "python_full_version < '3.8'" }, - { name = "idna", version = "3.10", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.8'" }, - { name = "sniffio", marker = "python_full_version < '3.8'" }, - { name = "typing-extensions", version = "4.7.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.8'" }, + { name = "ably-pubsub-core" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/28/99/2dfd53fd55ce9838e6ff2d4dac20ce58263798bd1a0dbe18b3a9af3fcfce/anyio-3.7.1.tar.gz", hash = "sha256:44a3c9aba0f5defa43261a8b3efb97891f2bd7d804e0e1f56419befa1adfc780", size = 142927, upload-time = "2023-07-05T16:45:02.294Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/19/24/44299477fe7dcc9cb58d0a57d5a7588d6af2ff403fdd2d47a246c91a3246/anyio-3.7.1-py3-none-any.whl", hash = "sha256:91dee416e570e92c64041bd18b900d1d6fa78dff7048769ce5ac5ddad004fbb5", size = 80896, upload-time = "2023-07-05T16:44:59.805Z" }, + +[package.optional-dependencies] +crypto = [ + { name = "ably-pubsub-core", extra = ["crypto"] }, +] +oldcrypto = [ + { name = "ably-pubsub-core", extra = ["oldcrypto"] }, +] +vcdiff = [ + { name = "ably-pubsub-core", extra = ["vcdiff"] }, ] +[package.metadata] +requires-dist = [ + { name = "ably-pubsub-core", editable = "core" }, + { name = "ably-pubsub-core", extras = ["crypto"], marker = "extra == 'crypto'", editable = "core" }, + { name = "ably-pubsub-core", extras = ["oldcrypto"], marker = "extra == 'oldcrypto'", editable = "core" }, + { name = "ably-pubsub-core", extras = ["vcdiff"], marker = "extra == 'vcdiff'", editable = "core" }, +] +provides-extras = ["oldcrypto", "crypto", "vcdiff"] + [[package]] name = "anyio" version = "4.5.2" source = { registry = "https://pypi.org/simple" } resolution-markers = [ - "python_full_version == '3.8.*'", + "python_full_version < '3.9'", ] dependencies = [ - { name = "exceptiongroup", marker = "python_full_version == '3.8.*'" }, - { name = "idna", version = "3.11", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.8.*'" }, - { name = "sniffio", marker = "python_full_version == '3.8.*'" }, - { name = "typing-extensions", version = "4.13.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.8.*'" }, + { name = "exceptiongroup", marker = "python_full_version < '3.9'" }, + { name = "idna", marker = "python_full_version < '3.9'" }, + { name = "sniffio", marker = "python_full_version < '3.9'" }, + { name = "typing-extensions", version = "4.13.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.9'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/4d/f9/9a7ce600ebe7804daf90d4d48b1c0510a4561ddce43a596be46676f82343/anyio-4.5.2.tar.gz", hash = "sha256:23009af4ed04ce05991845451e11ef02fc7c5ed29179ac9a420e5ad0ac7ddc5b", size = 171293, upload-time = "2024-10-13T22:18:03.307Z" } wheels = [ @@ -133,7 +126,7 @@ resolution-markers = [ ] dependencies = [ { name = "exceptiongroup", marker = "python_full_version >= '3.9' and python_full_version < '3.11'" }, - { name = "idna", version = "3.11", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.9'" }, + { name = "idna", marker = "python_full_version >= '3.9'" }, { name = "sniffio", marker = "python_full_version >= '3.9'" }, { name = "typing-extensions", version = "4.15.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.9' and python_full_version < '3.13'" }, ] @@ -142,12 +135,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/15/b3/9b1a8074496371342ec1e796a96f99c82c945a339cd81a8e73de28b4cf9e/anyio-4.11.0-py3-none-any.whl", hash = "sha256:0287e96f4d26d4149305414d4e3bc32f0dcd0862365a4bddea19d7a1ec38c4fc", size = 109097, upload-time = "2025-09-23T09:19:10.601Z" }, ] -[[package]] -name = "async-case" -version = "10.1.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/c8/09/87f2a23f5696ac6deb2fff92421f8af46226ea2410d101b453d5aa63e53a/async_case-10.1.0.tar.gz", hash = "sha256:b819f68c78f6c640ab1101ecf69fac189402b490901fa2abc314c48edab5d3da", size = 3668, upload-time = "2022-03-15T21:56:16.795Z" } - [[package]] name = "certifi" version = "2026.1.4" @@ -166,82 +153,12 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, ] -[[package]] -name = "coverage" -version = "7.2.7" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version < '3.8'", -] -sdist = { url = "https://files.pythonhosted.org/packages/45/8b/421f30467e69ac0e414214856798d4bc32da1336df745e49e49ae5c1e2a8/coverage-7.2.7.tar.gz", hash = "sha256:924d94291ca674905fe9481f12294eb11f2d3d3fd1adb20314ba89e94f44ed59", size = 762575, upload-time = "2023-05-29T20:08:50.273Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/01/24/be01e62a7bce89bcffe04729c540382caa5a06bee45ae42136c93e2499f5/coverage-7.2.7-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d39b5b4f2a66ccae8b7263ac3c8170994b65266797fb96cbbfd3fb5b23921db8", size = 200724, upload-time = "2023-05-29T20:07:03.422Z" }, - { url = "https://files.pythonhosted.org/packages/3d/80/7060a445e1d2c9744b683dc935248613355657809d6c6b2716cdf4ca4766/coverage-7.2.7-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6d040ef7c9859bb11dfeb056ff5b3872436e3b5e401817d87a31e1750b9ae2fb", size = 201024, upload-time = "2023-05-29T20:07:05.694Z" }, - { url = "https://files.pythonhosted.org/packages/b8/9d/926fce7e03dbfc653104c2d981c0fa71f0572a9ebd344d24c573bd6f7c4f/coverage-7.2.7-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ba90a9563ba44a72fda2e85302c3abc71c5589cea608ca16c22b9804262aaeb6", size = 229528, upload-time = "2023-05-29T20:07:07.307Z" }, - { url = "https://files.pythonhosted.org/packages/d1/3a/67f5d18f911abf96857f6f7e4df37ca840e38179e2cc9ab6c0b9c3380f19/coverage-7.2.7-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e7d9405291c6928619403db1d10bd07888888ec1abcbd9748fdaa971d7d661b2", size = 227842, upload-time = "2023-05-29T20:07:09.331Z" }, - { url = "https://files.pythonhosted.org/packages/b4/bd/1b2331e3a04f4cc9b7b332b1dd0f3a1261dfc4114f8479bebfcc2afee9e8/coverage-7.2.7-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:31563e97dae5598556600466ad9beea39fb04e0229e61c12eaa206e0aa202063", size = 228717, upload-time = "2023-05-29T20:07:11.38Z" }, - { url = "https://files.pythonhosted.org/packages/2b/86/3dbf9be43f8bf6a5ca28790a713e18902b2d884bc5fa9512823a81dff601/coverage-7.2.7-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:ebba1cd308ef115925421d3e6a586e655ca5a77b5bf41e02eb0e4562a111f2d1", size = 234632, upload-time = "2023-05-29T20:07:13.376Z" }, - { url = "https://files.pythonhosted.org/packages/91/e8/469ed808a782b9e8305a08bad8c6fa5f8e73e093bda6546c5aec68275bff/coverage-7.2.7-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:cb017fd1b2603ef59e374ba2063f593abe0fc45f2ad9abdde5b4d83bd922a353", size = 232875, upload-time = "2023-05-29T20:07:15.093Z" }, - { url = "https://files.pythonhosted.org/packages/29/8f/4fad1c2ba98104425009efd7eaa19af9a7c797e92d40cd2ec026fa1f58cb/coverage-7.2.7-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:d62a5c7dad11015c66fbb9d881bc4caa5b12f16292f857842d9d1871595f4495", size = 234094, upload-time = "2023-05-29T20:07:17.013Z" }, - { url = "https://files.pythonhosted.org/packages/94/4e/d4e46a214ae857be3d7dc5de248ba43765f60daeb1ab077cb6c1536c7fba/coverage-7.2.7-cp310-cp310-win32.whl", hash = "sha256:ee57190f24fba796e36bb6d3aa8a8783c643d8fa9760c89f7a98ab5455fbf818", size = 203184, upload-time = "2023-05-29T20:07:18.69Z" }, - { url = "https://files.pythonhosted.org/packages/1f/e9/d6730247d8dec2a3dddc520ebe11e2e860f0f98cee3639e23de6cf920255/coverage-7.2.7-cp310-cp310-win_amd64.whl", hash = "sha256:f75f7168ab25dd93110c8a8117a22450c19976afbc44234cbf71481094c1b850", size = 204096, upload-time = "2023-05-29T20:07:20.153Z" }, - { url = "https://files.pythonhosted.org/packages/c6/fa/529f55c9a1029c840bcc9109d5a15ff00478b7ff550a1ae361f8745f8ad5/coverage-7.2.7-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:06a9a2be0b5b576c3f18f1a241f0473575c4a26021b52b2a85263a00f034d51f", size = 200895, upload-time = "2023-05-29T20:07:21.963Z" }, - { url = "https://files.pythonhosted.org/packages/67/d7/cd8fe689b5743fffac516597a1222834c42b80686b99f5b44ef43ccc2a43/coverage-7.2.7-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5baa06420f837184130752b7c5ea0808762083bf3487b5038d68b012e5937dbe", size = 201120, upload-time = "2023-05-29T20:07:23.765Z" }, - { url = "https://files.pythonhosted.org/packages/8c/95/16eed713202406ca0a37f8ac259bbf144c9d24f9b8097a8e6ead61da2dbb/coverage-7.2.7-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fdec9e8cbf13a5bf63290fc6013d216a4c7232efb51548594ca3631a7f13c3a3", size = 233178, upload-time = "2023-05-29T20:07:25.281Z" }, - { url = "https://files.pythonhosted.org/packages/c1/49/4d487e2ad5d54ed82ac1101e467e8994c09d6123c91b2a962145f3d262c2/coverage-7.2.7-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:52edc1a60c0d34afa421c9c37078817b2e67a392cab17d97283b64c5833f427f", size = 230754, upload-time = "2023-05-29T20:07:27.044Z" }, - { url = "https://files.pythonhosted.org/packages/a7/cd/3ce94ad9d407a052dc2a74fbeb1c7947f442155b28264eb467ee78dea812/coverage-7.2.7-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:63426706118b7f5cf6bb6c895dc215d8a418d5952544042c8a2d9fe87fcf09cb", size = 232558, upload-time = "2023-05-29T20:07:28.743Z" }, - { url = "https://files.pythonhosted.org/packages/8f/a8/12cc7b261f3082cc299ab61f677f7e48d93e35ca5c3c2f7241ed5525ccea/coverage-7.2.7-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:afb17f84d56068a7c29f5fa37bfd38d5aba69e3304af08ee94da8ed5b0865833", size = 241509, upload-time = "2023-05-29T20:07:30.434Z" }, - { url = "https://files.pythonhosted.org/packages/04/fa/43b55101f75a5e9115259e8be70ff9279921cb6b17f04c34a5702ff9b1f7/coverage-7.2.7-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:48c19d2159d433ccc99e729ceae7d5293fbffa0bdb94952d3579983d1c8c9d97", size = 239924, upload-time = "2023-05-29T20:07:32.065Z" }, - { url = "https://files.pythonhosted.org/packages/68/5f/d2bd0f02aa3c3e0311986e625ccf97fdc511b52f4f1a063e4f37b624772f/coverage-7.2.7-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:0e1f928eaf5469c11e886fe0885ad2bf1ec606434e79842a879277895a50942a", size = 240977, upload-time = "2023-05-29T20:07:34.184Z" }, - { url = "https://files.pythonhosted.org/packages/ba/92/69c0722882643df4257ecc5437b83f4c17ba9e67f15dc6b77bad89b6982e/coverage-7.2.7-cp311-cp311-win32.whl", hash = "sha256:33d6d3ea29d5b3a1a632b3c4e4f4ecae24ef170b0b9ee493883f2df10039959a", size = 203168, upload-time = "2023-05-29T20:07:35.869Z" }, - { url = "https://files.pythonhosted.org/packages/b1/96/c12ed0dfd4ec587f3739f53eb677b9007853fd486ccb0e7d5512a27bab2e/coverage-7.2.7-cp311-cp311-win_amd64.whl", hash = "sha256:5b7540161790b2f28143191f5f8ec02fb132660ff175b7747b95dcb77ac26562", size = 204185, upload-time = "2023-05-29T20:07:37.39Z" }, - { url = "https://files.pythonhosted.org/packages/ff/d5/52fa1891d1802ab2e1b346d37d349cb41cdd4fd03f724ebbf94e80577687/coverage-7.2.7-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:f2f67fe12b22cd130d34d0ef79206061bfb5eda52feb6ce0dba0644e20a03cf4", size = 201020, upload-time = "2023-05-29T20:07:38.724Z" }, - { url = "https://files.pythonhosted.org/packages/24/df/6765898d54ea20e3197a26d26bb65b084deefadd77ce7de946b9c96dfdc5/coverage-7.2.7-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a342242fe22407f3c17f4b499276a02b01e80f861f1682ad1d95b04018e0c0d4", size = 233994, upload-time = "2023-05-29T20:07:40.274Z" }, - { url = "https://files.pythonhosted.org/packages/15/81/b108a60bc758b448c151e5abceed027ed77a9523ecbc6b8a390938301841/coverage-7.2.7-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:171717c7cb6b453aebac9a2ef603699da237f341b38eebfee9be75d27dc38e01", size = 231358, upload-time = "2023-05-29T20:07:41.998Z" }, - { url = "https://files.pythonhosted.org/packages/61/90/c76b9462f39897ebd8714faf21bc985b65c4e1ea6dff428ea9dc711ed0dd/coverage-7.2.7-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:49969a9f7ffa086d973d91cec8d2e31080436ef0fb4a359cae927e742abfaaa6", size = 233316, upload-time = "2023-05-29T20:07:43.539Z" }, - { url = "https://files.pythonhosted.org/packages/04/d6/8cba3bf346e8b1a4fb3f084df7d8cea25a6b6c56aaca1f2e53829be17e9e/coverage-7.2.7-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:b46517c02ccd08092f4fa99f24c3b83d8f92f739b4657b0f146246a0ca6a831d", size = 240159, upload-time = "2023-05-29T20:07:44.982Z" }, - { url = "https://files.pythonhosted.org/packages/6e/ea/4a252dc77ca0605b23d477729d139915e753ee89e4c9507630e12ad64a80/coverage-7.2.7-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:a3d33a6b3eae87ceaefa91ffdc130b5e8536182cd6dfdbfc1aa56b46ff8c86de", size = 238127, upload-time = "2023-05-29T20:07:46.522Z" }, - { url = "https://files.pythonhosted.org/packages/9f/5c/d9760ac497c41f9c4841f5972d0edf05d50cad7814e86ee7d133ec4a0ac8/coverage-7.2.7-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:976b9c42fb2a43ebf304fa7d4a310e5f16cc99992f33eced91ef6f908bd8f33d", size = 239833, upload-time = "2023-05-29T20:07:47.992Z" }, - { url = "https://files.pythonhosted.org/packages/69/8c/26a95b08059db1cbb01e4b0e6d40f2e9debb628c6ca86b78f625ceaf9bab/coverage-7.2.7-cp312-cp312-win32.whl", hash = "sha256:8de8bb0e5ad103888d65abef8bca41ab93721647590a3f740100cd65c3b00511", size = 203463, upload-time = "2023-05-29T20:07:49.939Z" }, - { url = "https://files.pythonhosted.org/packages/b7/00/14b00a0748e9eda26e97be07a63cc911108844004687321ddcc213be956c/coverage-7.2.7-cp312-cp312-win_amd64.whl", hash = "sha256:9e31cb64d7de6b6f09702bb27c02d1904b3aebfca610c12772452c4e6c21a0d3", size = 204347, upload-time = "2023-05-29T20:07:51.909Z" }, - { url = "https://files.pythonhosted.org/packages/80/d7/67937c80b8fd4c909fdac29292bc8b35d9505312cff6bcab41c53c5b1df6/coverage-7.2.7-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:58c2ccc2f00ecb51253cbe5d8d7122a34590fac9646a960d1430d5b15321d95f", size = 200580, upload-time = "2023-05-29T20:07:54.076Z" }, - { url = "https://files.pythonhosted.org/packages/7a/05/084864fa4bbf8106f44fb72a56e67e0cd372d3bf9d893be818338c81af5d/coverage-7.2.7-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d22656368f0e6189e24722214ed8d66b8022db19d182927b9a248a2a8a2f67eb", size = 226237, upload-time = "2023-05-29T20:07:56.28Z" }, - { url = "https://files.pythonhosted.org/packages/67/a2/6fa66a50e6e894286d79a3564f42bd54a9bd27049dc0a63b26d9924f0aa3/coverage-7.2.7-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a895fcc7b15c3fc72beb43cdcbdf0ddb7d2ebc959edac9cef390b0d14f39f8a9", size = 224256, upload-time = "2023-05-29T20:07:58.189Z" }, - { url = "https://files.pythonhosted.org/packages/e2/c0/73f139794c742840b9ab88e2e17fe14a3d4668a166ff95d812ac66c0829d/coverage-7.2.7-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e84606b74eb7de6ff581a7915e2dab7a28a0517fbe1c9239eb227e1354064dcd", size = 225550, upload-time = "2023-05-29T20:08:00.383Z" }, - { url = "https://files.pythonhosted.org/packages/03/ec/6f30b4e0c96ce03b0e64aec46b4af2a8c49b70d1b5d0d69577add757b946/coverage-7.2.7-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:0a5f9e1dbd7fbe30196578ca36f3fba75376fb99888c395c5880b355e2875f8a", size = 232440, upload-time = "2023-05-29T20:08:02.495Z" }, - { url = "https://files.pythonhosted.org/packages/22/c1/2f6c1b6f01a0996c9e067a9c780e1824351dbe17faae54388a4477e6d86f/coverage-7.2.7-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:419bfd2caae268623dd469eff96d510a920c90928b60f2073d79f8fe2bbc5959", size = 230897, upload-time = "2023-05-29T20:08:04.382Z" }, - { url = "https://files.pythonhosted.org/packages/8d/d6/53e999ec1bf7498ca4bc5f3b8227eb61db39068d2de5dcc359dec5601b5a/coverage-7.2.7-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:2aee274c46590717f38ae5e4650988d1af340fe06167546cc32fe2f58ed05b02", size = 232024, upload-time = "2023-05-29T20:08:06.031Z" }, - { url = "https://files.pythonhosted.org/packages/e9/40/383305500d24122dbed73e505a4d6828f8f3356d1f68ab6d32c781754b81/coverage-7.2.7-cp37-cp37m-win32.whl", hash = "sha256:61b9a528fb348373c433e8966535074b802c7a5d7f23c4f421e6c6e2f1697a6f", size = 203293, upload-time = "2023-05-29T20:08:07.598Z" }, - { url = "https://files.pythonhosted.org/packages/0e/bc/7e3a31534fabb043269f14fb64e2bb2733f85d4cf39e5bbc71357c57553a/coverage-7.2.7-cp37-cp37m-win_amd64.whl", hash = "sha256:b1c546aca0ca4d028901d825015dc8e4d56aac4b541877690eb76490f1dc8ed0", size = 204040, upload-time = "2023-05-29T20:08:09.919Z" }, - { url = "https://files.pythonhosted.org/packages/c6/fc/be19131010930a6cf271da48202c8cc1d3f971f68c02fb2d3a78247f43dc/coverage-7.2.7-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:54b896376ab563bd38453cecb813c295cf347cf5906e8b41d340b0321a5433e5", size = 200689, upload-time = "2023-05-29T20:08:11.594Z" }, - { url = "https://files.pythonhosted.org/packages/28/d7/9a8de57d87f4bbc6f9a6a5ded1eaac88a89bf71369bb935dac3c0cf2893e/coverage-7.2.7-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:3d376df58cc111dc8e21e3b6e24606b5bb5dee6024f46a5abca99124b2229ef5", size = 200986, upload-time = "2023-05-29T20:08:13.228Z" }, - { url = "https://files.pythonhosted.org/packages/c8/e4/e6182e4697665fb594a7f4e4f27cb3a4dd00c2e3d35c5c706765de8c7866/coverage-7.2.7-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5e330fc79bd7207e46c7d7fd2bb4af2963f5f635703925543a70b99574b0fea9", size = 230648, upload-time = "2023-05-29T20:08:15.11Z" }, - { url = "https://files.pythonhosted.org/packages/7b/e3/f552d5871943f747165b92a924055c5d6daa164ae659a13f9018e22f3990/coverage-7.2.7-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e9d683426464e4a252bf70c3498756055016f99ddaec3774bf368e76bbe02b6", size = 228511, upload-time = "2023-05-29T20:08:16.877Z" }, - { url = "https://files.pythonhosted.org/packages/44/55/49f65ccdd4dfd6d5528e966b28c37caec64170c725af32ab312889d2f857/coverage-7.2.7-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8d13c64ee2d33eccf7437961b6ea7ad8673e2be040b4f7fd4fd4d4d28d9ccb1e", size = 229852, upload-time = "2023-05-29T20:08:18.47Z" }, - { url = "https://files.pythonhosted.org/packages/0d/31/340428c238eb506feb96d4fb5c9ea614db1149517f22cc7ab8c6035ef6d9/coverage-7.2.7-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:b7aa5f8a41217360e600da646004f878250a0d6738bcdc11a0a39928d7dc2050", size = 235578, upload-time = "2023-05-29T20:08:20.298Z" }, - { url = "https://files.pythonhosted.org/packages/dd/ce/97c1dd6592c908425622fe7f31c017d11cf0421729b09101d4de75bcadc8/coverage-7.2.7-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:8fa03bce9bfbeeef9f3b160a8bed39a221d82308b4152b27d82d8daa7041fee5", size = 234079, upload-time = "2023-05-29T20:08:22.365Z" }, - { url = "https://files.pythonhosted.org/packages/de/a3/5a98dc9e239d0dc5f243ef5053d5b1bdcaa1dee27a691dfc12befeccf878/coverage-7.2.7-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:245167dd26180ab4c91d5e1496a30be4cd721a5cf2abf52974f965f10f11419f", size = 234991, upload-time = "2023-05-29T20:08:24.974Z" }, - { url = "https://files.pythonhosted.org/packages/4a/fb/78986d3022e5ccf2d4370bc43a5fef8374f092b3c21d32499dee8e30b7b6/coverage-7.2.7-cp38-cp38-win32.whl", hash = "sha256:d2c2db7fd82e9b72937969bceac4d6ca89660db0a0967614ce2481e81a0b771e", size = 203160, upload-time = "2023-05-29T20:08:26.701Z" }, - { url = "https://files.pythonhosted.org/packages/c3/1c/6b3c9c363fb1433c79128e0d692863deb761b1b78162494abb9e5c328bc0/coverage-7.2.7-cp38-cp38-win_amd64.whl", hash = "sha256:2e07b54284e381531c87f785f613b833569c14ecacdcb85d56b25c4622c16c3c", size = 204085, upload-time = "2023-05-29T20:08:28.146Z" }, - { url = "https://files.pythonhosted.org/packages/88/da/495944ebf0ad246235a6bd523810d9f81981f9b81c6059ba1f56e943abe0/coverage-7.2.7-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:537891ae8ce59ef63d0123f7ac9e2ae0fc8b72c7ccbe5296fec45fd68967b6c9", size = 200725, upload-time = "2023-05-29T20:08:29.851Z" }, - { url = "https://files.pythonhosted.org/packages/ca/0c/3dfeeb1006c44b911ee0ed915350db30325d01808525ae7cc8d57643a2ce/coverage-7.2.7-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:06fb182e69f33f6cd1d39a6c597294cff3143554b64b9825d1dc69d18cc2fff2", size = 201022, upload-time = "2023-05-29T20:08:31.429Z" }, - { url = "https://files.pythonhosted.org/packages/61/af/5964b8d7d9a5c767785644d9a5a63cacba9a9c45cc42ba06d25895ec87be/coverage-7.2.7-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:201e7389591af40950a6480bd9edfa8ed04346ff80002cec1a66cac4549c1ad7", size = 229102, upload-time = "2023-05-29T20:08:32.982Z" }, - { url = "https://files.pythonhosted.org/packages/d9/1d/cd467fceb62c371f9adb1d739c92a05d4e550246daa90412e711226bd320/coverage-7.2.7-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f6951407391b639504e3b3be51b7ba5f3528adbf1a8ac3302b687ecababf929e", size = 227441, upload-time = "2023-05-29T20:08:35.044Z" }, - { url = "https://files.pythonhosted.org/packages/fe/57/e4f8ad64d84ca9e759d783a052795f62a9f9111585e46068845b1cb52c2b/coverage-7.2.7-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6f48351d66575f535669306aa7d6d6f71bc43372473b54a832222803eb956fd1", size = 228265, upload-time = "2023-05-29T20:08:36.861Z" }, - { url = "https://files.pythonhosted.org/packages/88/8b/b0d9fe727acae907fa7f1c8194ccb6fe9d02e1c3e9001ecf74c741f86110/coverage-7.2.7-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b29019c76039dc3c0fd815c41392a044ce555d9bcdd38b0fb60fb4cd8e475ba9", size = 234217, upload-time = "2023-05-29T20:08:38.837Z" }, - { url = "https://files.pythonhosted.org/packages/66/2e/c99fe1f6396d93551aa352c75410686e726cd4ea104479b9af1af22367ce/coverage-7.2.7-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:81c13a1fc7468c40f13420732805a4c38a105d89848b7c10af65a90beff25250", size = 232466, upload-time = "2023-05-29T20:08:40.768Z" }, - { url = "https://files.pythonhosted.org/packages/bb/e9/88747b40c8fb4a783b40222510ce6d66170217eb05d7f46462c36b4fa8cc/coverage-7.2.7-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:975d70ab7e3c80a3fe86001d8751f6778905ec723f5b110aed1e450da9d4b7f2", size = 233669, upload-time = "2023-05-29T20:08:42.944Z" }, - { url = "https://files.pythonhosted.org/packages/b1/d5/a8e276bc005e42114468d4fe03e0a9555786bc51cbfe0d20827a46c1565a/coverage-7.2.7-cp39-cp39-win32.whl", hash = "sha256:7ee7d9d4822c8acc74a5e26c50604dff824710bc8de424904c0982e25c39c6cb", size = 203199, upload-time = "2023-05-29T20:08:44.734Z" }, - { url = "https://files.pythonhosted.org/packages/a9/0c/4a848ae663b47f1195abcb09a951751dd61f80b503303b9b9d768e0fd321/coverage-7.2.7-cp39-cp39-win_amd64.whl", hash = "sha256:eb393e5ebc85245347950143969b241d08b52b88a3dc39479822e073a1a8eb27", size = 204109, upload-time = "2023-05-29T20:08:46.417Z" }, - { url = "https://files.pythonhosted.org/packages/67/fb/b3b1d7887e1ea25a9608b0776e480e4bbc303ca95a31fd585555ec4fff5a/coverage-7.2.7-pp37.pp38.pp39-none-any.whl", hash = "sha256:b7b4c971f05e6ae490fef852c218b0e79d4e52f79ef0c8475566584a8fb3e01d", size = 193207, upload-time = "2023-05-29T20:08:48.153Z" }, -] - [[package]] name = "coverage" version = "7.6.1" source = { registry = "https://pypi.org/simple" } resolution-markers = [ - "python_full_version == '3.8.*'", + "python_full_version < '3.9'", ] sdist = { url = "https://files.pythonhosted.org/packages/f7/08/7e37f82e4d1aead42a7443ff06a1e406aabf7302c4f00a546e4b320b994c/coverage-7.6.1.tar.gz", hash = "sha256:953510dfb7b12ab69d20135a0662397f077c59b1e6379a768e97c59d852ee51d", size = 798791, upload-time = "2024-08-04T19:45:30.9Z" } wheels = [ @@ -539,8 +456,7 @@ name = "exceptiongroup" version = "1.3.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "typing-extensions", version = "4.7.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.8'" }, - { name = "typing-extensions", version = "4.13.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.8.*'" }, + { name = "typing-extensions", version = "4.13.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.9'" }, { name = "typing-extensions", version = "4.15.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.9' and python_full_version < '3.13'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/0b/9f/a65090624ecf468cdca03533906e7c69ed7588582240cfe7cc9e770b50eb/exceptiongroup-1.3.0.tar.gz", hash = "sha256:b241f5885f560bc56a59ee63ca4c6a8bfa46ae4ad651af316d4e81817bb9fd88", size = 29749, upload-time = "2025-05-10T17:42:51.123Z" } @@ -548,56 +464,19 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/36/f4/c6e662dade71f56cd2f3735141b265c3c79293c109549c1e6933b0651ffc/exceptiongroup-1.3.0-py3-none-any.whl", hash = "sha256:4d111e6e0c13d0644cad6ddaa7ed0261a0b36971f6d23e7ec9b4b9097da78a10", size = 16674, upload-time = "2025-05-10T17:42:49.33Z" }, ] -[[package]] -name = "execnet" -version = "2.0.2" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version < '3.8'", -] -sdist = { url = "https://files.pythonhosted.org/packages/e4/c8/d382dc7a1e68a165f4a4ab612a08b20d8534a7d20cc590630b734ca0c54b/execnet-2.0.2.tar.gz", hash = "sha256:cc59bc4423742fd71ad227122eb0dd44db51efb3dc4095b45ac9a08c770096af", size = 161098, upload-time = "2023-07-09T17:14:03.468Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e8/9c/a079946da30fac4924d92dbc617e5367d454954494cf1e71567bcc4e00ee/execnet-2.0.2-py3-none-any.whl", hash = "sha256:88256416ae766bc9e8895c76a87928c0012183da3cc4fc18016e6f050e025f41", size = 37097, upload-time = "2023-07-09T17:14:01.888Z" }, -] - [[package]] name = "execnet" version = "2.1.2" source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version >= '3.10'", - "python_full_version == '3.9.*'", - "python_full_version == '3.8.*'", -] sdist = { url = "https://files.pythonhosted.org/packages/bf/89/780e11f9588d9e7128a3f87788354c7946a9cbb1401ad38a48c4db9a4f07/execnet-2.1.2.tar.gz", hash = "sha256:63d83bfdd9a23e35b9c6a3261412324f964c2ec8dcd8d3c6916ee9373e0befcd", size = 166622, upload-time = "2025-11-12T09:56:37.75Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/ab/84/02fc1827e8cdded4aa65baef11296a9bbe595c474f0d6d758af082d849fd/execnet-2.1.2-py3-none-any.whl", hash = "sha256:67fba928dd5a544b783f6056f449e5e3931a5c378b128bc18501f7ea79e296ec", size = 40708, upload-time = "2025-11-12T09:56:36.333Z" }, ] -[[package]] -name = "h11" -version = "0.14.0" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version < '3.8'", -] -dependencies = [ - { name = "typing-extensions", version = "4.7.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.8'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/f5/38/3af3d3633a34a3316095b39c8e8fb4853a28a536e55d347bd8d8e9a14b03/h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d", size = 100418, upload-time = "2022-09-25T15:40:01.519Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/95/04/ff642e65ad6b90db43e668d70ffb6736436c7ce41fcc549f4e9472234127/h11-0.14.0-py3-none-any.whl", hash = "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761", size = 58259, upload-time = "2022-09-25T15:39:59.68Z" }, -] - [[package]] name = "h11" version = "0.16.0" source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version >= '3.10'", - "python_full_version == '3.9.*'", - "python_full_version == '3.8.*'", -] sdist = { url = "https://files.pythonhosted.org/packages/01/ee/02a2c011bdab74c6fb3c75474d40b3052059d95df7e73351460c8588d963/h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1", size = 101250, upload-time = "2025-04-24T03:35:25.427Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515, upload-time = "2025-04-24T03:35:24.344Z" }, @@ -608,8 +487,7 @@ name = "h2" version = "4.1.0" source = { registry = "https://pypi.org/simple" } resolution-markers = [ - "python_full_version == '3.8.*'", - "python_full_version < '3.8'", + "python_full_version < '3.9'", ] dependencies = [ { name = "hpack", version = "4.0.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.9'" }, @@ -642,8 +520,7 @@ name = "hpack" version = "4.0.0" source = { registry = "https://pypi.org/simple" } resolution-markers = [ - "python_full_version == '3.8.*'", - "python_full_version < '3.8'", + "python_full_version < '3.9'", ] sdist = { url = "https://files.pythonhosted.org/packages/3e/9b/fda93fb4d957db19b0f6b370e79d586b3e8528b20252c729c476a2c02954/hpack-4.0.0.tar.gz", hash = "sha256:fc41de0c63e687ebffde81187a948221294896f6bdc0ae2312708df339430095", size = 49117, upload-time = "2020-08-30T10:35:57.868Z" } wheels = [ @@ -663,75 +540,29 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/07/c6/80c95b1b2b94682a72cbdbfb85b81ae2daffa4291fbfa1b1464502ede10d/hpack-4.1.0-py3-none-any.whl", hash = "sha256:157ac792668d995c657d93111f46b4535ed114f0c9c8d672271bbec7eae1b496", size = 34357, upload-time = "2025-01-22T21:44:56.92Z" }, ] -[[package]] -name = "httpcore" -version = "0.17.3" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version < '3.8'", -] -dependencies = [ - { name = "anyio", version = "3.7.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.8'" }, - { name = "certifi", marker = "python_full_version < '3.8'" }, - { name = "h11", version = "0.14.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.8'" }, - { name = "sniffio", marker = "python_full_version < '3.8'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/63/ad/c98ecdbfe04417e71e143bf2f2fb29128e4787d78d1cedba21bd250c7e7a/httpcore-0.17.3.tar.gz", hash = "sha256:a6f30213335e34c1ade7be6ec7c47f19f50c56db36abef1a9dfa3815b1cb3888", size = 62676, upload-time = "2023-07-05T12:09:31.29Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/94/2c/2bde7ff8dd2064395555220cbf7cba79991172bf5315a07eb3ac7688d9f1/httpcore-0.17.3-py3-none-any.whl", hash = "sha256:c2789b767ddddfa2a5782e3199b2b7f6894540b17b16ec26b2c4d8e103510b87", size = 74513, upload-time = "2023-07-05T12:09:29.425Z" }, -] - [[package]] name = "httpcore" version = "1.0.9" source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version >= '3.10'", - "python_full_version == '3.9.*'", - "python_full_version == '3.8.*'", -] dependencies = [ - { name = "certifi", marker = "python_full_version >= '3.8'" }, - { name = "h11", version = "0.16.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.8'" }, + { name = "certifi" }, + { name = "h11" }, ] sdist = { url = "https://files.pythonhosted.org/packages/06/94/82699a10bca87a5556c9c59b5963f2d039dbd239f25bc2a63907a05a14cb/httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8", size = 85484, upload-time = "2025-04-24T22:06:22.219Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55", size = 78784, upload-time = "2025-04-24T22:06:20.566Z" }, ] -[[package]] -name = "httpx" -version = "0.24.1" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version < '3.8'", -] -dependencies = [ - { name = "certifi", marker = "python_full_version < '3.8'" }, - { name = "httpcore", version = "0.17.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.8'" }, - { name = "idna", version = "3.10", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.8'" }, - { name = "sniffio", marker = "python_full_version < '3.8'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/f8/2a/114d454cb77657dbf6a293e69390b96318930ace9cd96b51b99682493276/httpx-0.24.1.tar.gz", hash = "sha256:5853a43053df830c20f8110c5e69fe44d035d850b2dfe795e196f00fdb774bdd", size = 81858, upload-time = "2023-05-19T00:50:56.678Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ec/91/e41f64f03d2a13aee7e8c819d82ee3aa7cdc484d18c0ae859742597d5aa0/httpx-0.24.1-py3-none-any.whl", hash = "sha256:06781eb9ac53cde990577af654bd990a4949de37a28bdb4a230d434f3a30b9bd", size = 75377, upload-time = "2023-05-19T00:50:54.91Z" }, -] - [[package]] name = "httpx" version = "0.28.1" source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version >= '3.10'", - "python_full_version == '3.9.*'", - "python_full_version == '3.8.*'", -] dependencies = [ - { name = "anyio", version = "4.5.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.8.*'" }, + { name = "anyio", version = "4.5.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.9'" }, { name = "anyio", version = "4.11.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.9'" }, - { name = "certifi", marker = "python_full_version >= '3.8'" }, - { name = "httpcore", version = "1.0.9", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.8'" }, - { name = "idna", version = "3.11", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.8'" }, + { name = "certifi" }, + { name = "httpcore" }, + { name = "idna" }, ] sdist = { url = "https://files.pythonhosted.org/packages/b1/df/48c586a5fe32a0f01324ee087459e112ebb7224f646c0b5023f5e79e9956/httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc", size = 141406, upload-time = "2024-12-06T15:37:23.222Z" } wheels = [ @@ -743,8 +574,7 @@ name = "hyperframe" version = "6.0.1" source = { registry = "https://pypi.org/simple" } resolution-markers = [ - "python_full_version == '3.8.*'", - "python_full_version < '3.8'", + "python_full_version < '3.9'", ] sdist = { url = "https://files.pythonhosted.org/packages/5a/2a/4747bff0a17f7281abe73e955d60d80aae537a5d203f417fa1c2e7578ebb/hyperframe-6.0.1.tar.gz", hash = "sha256:ae510046231dc8e9ecb1a6586f63d2347bf4c8905914aa84ba585ae85f28a914", size = 25008, upload-time = "2021-04-17T12:11:22.757Z" } wheels = [ @@ -764,27 +594,10 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/48/30/47d0bf6072f7252e6521f3447ccfa40b421b6824517f82854703d0f5a98b/hyperframe-6.1.0-py3-none-any.whl", hash = "sha256:b03380493a519fce58ea5af42e4a42317bf9bd425596f7a0835ffce80f1a42e5", size = 13007, upload-time = "2025-01-22T21:41:47.295Z" }, ] -[[package]] -name = "idna" -version = "3.10" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version < '3.8'", -] -sdist = { url = "https://files.pythonhosted.org/packages/f1/70/7703c29685631f5a7590aa73f1f1d3fa9a380e654b86af429e0934a32f7d/idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", size = 190490, upload-time = "2024-09-15T18:07:39.745Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3", size = 70442, upload-time = "2024-09-15T18:07:37.964Z" }, -] - [[package]] name = "idna" version = "3.11" source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version >= '3.10'", - "python_full_version == '3.9.*'", - "python_full_version == '3.8.*'", -] sdist = { url = "https://files.pythonhosted.org/packages/6f/6d/0703ccc57f3a7233505399edb88de3cbd678da106337b9fcde432b65ed60/idna-3.11.tar.gz", hash = "sha256:795dafcc9c04ed0c1fb032c2aa73654d8e8c5023a7df64a53f39190ada629902", size = 194582, upload-time = "2025-10-12T14:55:20.501Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl", hash = "sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea", size = 71008, upload-time = "2025-10-12T14:55:18.883Z" }, @@ -795,9 +608,7 @@ name = "importlib-metadata" version = "4.13.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "typing-extensions", version = "4.7.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.8'" }, - { name = "zipp", version = "3.15.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.8'" }, - { name = "zipp", version = "3.20.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.8.*'" }, + { name = "zipp", version = "3.20.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.9'" }, { name = "zipp", version = "3.23.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.9'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/55/12/ab288357b884ebc807e3f4eff63ce5ba6b941ba61499071bf19f1bbc7f7f/importlib_metadata-4.13.0.tar.gz", hash = "sha256:dd0173e8f150d6815e098fd354f6414b0f079af4644ddfe90c71e2fc6174346d", size = 50445, upload-time = "2022-10-01T17:09:15.698Z" } @@ -805,25 +616,13 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d0/98/c277899f5aa21f6e6946e1c83f2af650cbfee982763ffb91db07ff7d3a13/importlib_metadata-4.13.0-py3-none-any.whl", hash = "sha256:8a8a81bcf996e74fee46f0d16bd3eaa382a7eb20fd82445c3ad11f4090334116", size = 23010, upload-time = "2022-10-01T17:09:13.903Z" }, ] -[[package]] -name = "iniconfig" -version = "2.0.0" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version < '3.8'", -] -sdist = { url = "https://files.pythonhosted.org/packages/d7/4b/cbd8e699e64a6f16ca3a8220661b5f83792b3017d0f79807cb8708d33913/iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3", size = 4646, upload-time = "2023-01-07T11:08:11.254Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ef/a6/62565a6e1cf69e10f5727360368e451d4b7f58beeac6173dc9db836a5b46/iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374", size = 5892, upload-time = "2023-01-07T11:08:09.864Z" }, -] - [[package]] name = "iniconfig" version = "2.1.0" source = { registry = "https://pypi.org/simple" } resolution-markers = [ "python_full_version == '3.9.*'", - "python_full_version == '3.8.*'", + "python_full_version < '3.9'", ] sdist = { url = "https://files.pythonhosted.org/packages/f2/97/ebf4da567aa6827c909642694d71c9fcf53e5b504f2d96afea02718862f3/iniconfig-2.1.0.tar.gz", hash = "sha256:3abbd2e30b36733fee78f9c7f7308f2d0050e88f0087fd25c2645f63c773e1c7", size = 4793, upload-time = "2025-03-19T20:09:59.721Z" } wheels = [ @@ -851,76 +650,12 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/5c/03/b7e605db4a57c0f6fba744b11ef3ddf4ddebcada35022927a2b5fc623fdf/mock-4.0.3-py3-none-any.whl", hash = "sha256:122fcb64ee37cfad5b3f48d7a7d51875d7031aaf3d8be7c42e2bee25044eee62", size = 28536, upload-time = "2020-12-10T07:33:11.564Z" }, ] -[[package]] -name = "msgpack" -version = "1.0.5" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version < '3.8'", -] -sdist = { url = "https://files.pythonhosted.org/packages/dc/a1/eba11a0d4b764bc62966a565b470f8c6f38242723ba3057e9b5098678c30/msgpack-1.0.5.tar.gz", hash = "sha256:c075544284eadc5cddc70f4757331d99dcbc16b2bbd4849d15f8aae4cf36d31c", size = 127834, upload-time = "2023-03-08T17:50:48.564Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/9f/4a/36d936e54cf71e23ad276564465f6a54fb129e3d61520b76e13e0bb29167/msgpack-1.0.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:525228efd79bb831cf6830a732e2e80bc1b05436b086d4264814b4b2955b2fa9", size = 129738, upload-time = "2023-03-08T17:49:18.464Z" }, - { url = "https://files.pythonhosted.org/packages/f2/da/770118f8d48e11cc9a2c7cb60d7d3c8016266526bd42c6ff5bd21013d099/msgpack-1.0.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:4f8d8b3bf1ff2672567d6b5c725a1b347fe838b912772aa8ae2bf70338d5a198", size = 74671, upload-time = "2023-03-08T17:49:20.311Z" }, - { url = "https://files.pythonhosted.org/packages/73/99/f338ce8b69e934c04e5d9187f85de1ae395882cd56e7deb48e78a1749af8/msgpack-1.0.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:cdc793c50be3f01106245a61b739328f7dccc2c648b501e237f0699fe1395b81", size = 70230, upload-time = "2023-03-08T17:49:21.958Z" }, - { url = "https://files.pythonhosted.org/packages/3e/80/bc7fdb75a35bf32c7c529c247dcadfd0502aac2309e207a89b0be6fe42ea/msgpack-1.0.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5cb47c21a8a65b165ce29f2bec852790cbc04936f502966768e4aae9fa763cb7", size = 309410, upload-time = "2023-03-08T17:49:23.337Z" }, - { url = "https://files.pythonhosted.org/packages/59/67/f992ada3b42889f1b984e5651d63ea21ca3a92049cff6d75fe0a4a63e422/msgpack-1.0.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e42b9594cc3bf4d838d67d6ed62b9e59e201862a25e9a157019e171fbe672dd3", size = 316846, upload-time = "2023-03-08T17:49:24.786Z" }, - { url = "https://files.pythonhosted.org/packages/10/fe/9e004c4deb457f1ef1ad88c1188da5691ff1855e0d03a5ac3635ae1f6530/msgpack-1.0.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:55b56a24893105dc52c1253649b60f475f36b3aa0fc66115bffafb624d7cb30b", size = 311396, upload-time = "2023-03-08T17:49:26.075Z" }, - { url = "https://files.pythonhosted.org/packages/95/c9/560c3203c4327881c9f2de26c42dacdd9567bfe7fa43458e2a680c4bdcaf/msgpack-1.0.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:1967f6129fc50a43bfe0951c35acbb729be89a55d849fab7686004da85103f1c", size = 311165, upload-time = "2023-03-08T17:49:27.494Z" }, - { url = "https://files.pythonhosted.org/packages/10/ca/50c3a5e92d459a942169747315afd8c226d05427eccff903ddf33135c574/msgpack-1.0.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:20a97bf595a232c3ee6d57ddaadd5453d174a52594bf9c21d10407e2a2d9b3bd", size = 348664, upload-time = "2023-03-08T17:49:28.736Z" }, - { url = "https://files.pythonhosted.org/packages/29/56/1fb6b96aab759ab3bc05b03ba6d936b350db72aac203cde56ea6bd001237/msgpack-1.0.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:d25dd59bbbbb996eacf7be6b4ad082ed7eacc4e8f3d2df1ba43822da9bfa122a", size = 316731, upload-time = "2023-03-08T17:49:30.041Z" }, - { url = "https://files.pythonhosted.org/packages/7b/e9/b47f9e93fc381885624c40cbbbd0480b18ae11ca588162fe724d43495372/msgpack-1.0.5-cp310-cp310-win32.whl", hash = "sha256:382b2c77589331f2cb80b67cc058c00f225e19827dbc818d700f61513ab47bea", size = 57134, upload-time = "2023-03-08T17:49:31.365Z" }, - { url = "https://files.pythonhosted.org/packages/3c/e5/3d436bed11849ba05d777ed3fd1a0440170bad460335ea541dd6946047ed/msgpack-1.0.5-cp310-cp310-win_amd64.whl", hash = "sha256:4867aa2df9e2a5fa5f76d7d5565d25ec76e84c106b55509e78c1ede0f152659a", size = 61631, upload-time = "2023-03-08T17:49:32.482Z" }, - { url = "https://files.pythonhosted.org/packages/27/ad/4edfe383ec3185611441179ffee8cbc8155d7575fbad73f6d31015e35451/msgpack-1.0.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9f5ae84c5c8a857ec44dc180a8b0cc08238e021f57abdf51a8182e915e6299f0", size = 127502, upload-time = "2023-03-08T17:49:33.974Z" }, - { url = "https://files.pythonhosted.org/packages/c1/57/01f2d8805160f559ec21d095fc7576a26fbaed2475af24ce4a135c380c14/msgpack-1.0.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:9e6ca5d5699bcd89ae605c150aee83b5321f2115695e741b99618f4856c50898", size = 73747, upload-time = "2023-03-08T17:49:35.158Z" }, - { url = "https://files.pythonhosted.org/packages/6c/fe/8a7747ca57074307a2e8f1de58441952a9dbdf9e8a8e5873d53a5ce0835c/msgpack-1.0.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5494ea30d517a3576749cad32fa27f7585c65f5f38309c88c6d137877fa28a5a", size = 69041, upload-time = "2023-03-08T17:49:36.44Z" }, - { url = "https://files.pythonhosted.org/packages/33/0a/aa7b53ae17cf1dc1c352d705ab3162fc572c55048cc3177c1a88009c47fd/msgpack-1.0.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1ab2f3331cb1b54165976a9d976cb251a83183631c88076613c6c780f0d6e45a", size = 316114, upload-time = "2023-03-08T17:49:38.252Z" }, - { url = "https://files.pythonhosted.org/packages/6b/6d/de239d77d347f1990c41b4800075a15e06f748186dd120166270dd071734/msgpack-1.0.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:28592e20bbb1620848256ebc105fc420436af59515793ed27d5c77a217477705", size = 325080, upload-time = "2023-03-08T17:49:39.528Z" }, - { url = "https://files.pythonhosted.org/packages/7e/1c/9d0fd241a4e88e1cd2f5babea4a27ac25b1b86dbbc05fa10741e82079a93/msgpack-1.0.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fe5c63197c55bce6385d9aee16c4d0641684628f63ace85f73571e65ad1c1e8d", size = 319393, upload-time = "2023-03-08T17:49:40.755Z" }, - { url = "https://files.pythonhosted.org/packages/b8/bc/1d5fe4732dc78ff86aaf677596da08f0ae736e60ca8ab49c1f1c7366cb1a/msgpack-1.0.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ed40e926fa2f297e8a653c954b732f125ef97bdd4c889f243182299de27e2aa9", size = 316118, upload-time = "2023-03-08T17:49:41.964Z" }, - { url = "https://files.pythonhosted.org/packages/2c/e9/c79ecc36cfa34d850a01773565e0fccafd69efff07172028c3a5f758b83f/msgpack-1.0.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:b2de4c1c0538dcb7010902a2b97f4e00fc4ddf2c8cda9749af0e594d3b7fa3d7", size = 354984, upload-time = "2023-03-08T17:49:43.251Z" }, - { url = "https://files.pythonhosted.org/packages/45/85/6b55b0cabad846d3e730226a897f878f8f63ee505668bb6c55a697b0bfb0/msgpack-1.0.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:bf22a83f973b50f9d38e55c6aade04c41ddda19b00c4ebc558930d78eecc64ed", size = 323580, upload-time = "2023-03-08T17:49:44.71Z" }, - { url = "https://files.pythonhosted.org/packages/0e/69/3d10e741dd2bbb806af5cdc76551735baab5f5f9773701eb05502c913a6e/msgpack-1.0.5-cp311-cp311-win32.whl", hash = "sha256:c396e2cc213d12ce017b686e0f53497f94f8ba2b24799c25d913d46c08ec422c", size = 56419, upload-time = "2023-03-08T17:49:46.603Z" }, - { url = "https://files.pythonhosted.org/packages/6b/79/0dec8f035160464ca88b221cc79691a71cf88dc25207c17f1d918b2c7bb0/msgpack-1.0.5-cp311-cp311-win_amd64.whl", hash = "sha256:6c4c68d87497f66f96d50142a2b73b97972130d93677ce930718f68828b382e2", size = 60781, upload-time = "2023-03-08T17:49:47.912Z" }, - { url = "https://files.pythonhosted.org/packages/c5/c1/1b591574ba71481fbf38359a8fca5108e4ad130a6dbb9b2acb3e9277d0fe/msgpack-1.0.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:137850656634abddfb88236008339fdaba3178f4751b28f270d2ebe77a563b6c", size = 72520, upload-time = "2023-03-08T17:50:02.199Z" }, - { url = "https://files.pythonhosted.org/packages/62/57/170af6c6fccd2d950ea01e1faa58cae9643226fa8705baded11eca3aa8b5/msgpack-1.0.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0c05a4a96585525916b109bb85f8cb6511db1c6f5b9d9cbcbc940dc6b4be944b", size = 289288, upload-time = "2023-03-08T17:50:04.213Z" }, - { url = "https://files.pythonhosted.org/packages/2b/c4/f2c8695ae69d1425eddc5e2f849c525b562dc8409bc2979e525f3dd4fecd/msgpack-1.0.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:56a62ec00b636583e5cb6ad313bbed36bb7ead5fa3a3e38938503142c72cba4f", size = 299695, upload-time = "2023-03-08T17:50:05.622Z" }, - { url = "https://files.pythonhosted.org/packages/62/5c/9c7fed4ca0235a2d7b8d15b4047c328976b97d2b227719e54cad1e47c244/msgpack-1.0.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ef8108f8dedf204bb7b42994abf93882da1159728a2d4c5e82012edd92c9da9f", size = 293149, upload-time = "2023-03-08T17:50:06.915Z" }, - { url = "https://files.pythonhosted.org/packages/ef/13/c110d89d5079169354394dc226e6f84d818722939bc1fe3f9c25f982e903/msgpack-1.0.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:1835c84d65f46900920b3708f5ba829fb19b1096c1800ad60bae8418652a951d", size = 292899, upload-time = "2023-03-08T17:50:08.215Z" }, - { url = "https://files.pythonhosted.org/packages/72/ac/2eda5af7cd1450c52d031e48c76b280eac5bb2e588678876612f95be34ab/msgpack-1.0.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:e57916ef1bd0fee4f21c4600e9d1da352d8816b52a599c46460e93a6e9f17086", size = 334408, upload-time = "2023-03-08T17:50:10Z" }, - { url = "https://files.pythonhosted.org/packages/e8/60/78906f564804aae23eb1102eca8b8830f1e08a649c179774c05fa7dc0aad/msgpack-1.0.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:17358523b85973e5f242ad74aa4712b7ee560715562554aa2134d96e7aa4cbbf", size = 302791, upload-time = "2023-03-08T17:50:11.414Z" }, - { url = "https://files.pythonhosted.org/packages/ce/b8/89cb1809b076a4651169851aa1f98128b75cbfe14034b914c9040b13c4cf/msgpack-1.0.5-cp37-cp37m-win32.whl", hash = "sha256:cb5aaa8c17760909ec6cb15e744c3ebc2ca8918e727216e79607b7bbce9c8f77", size = 57095, upload-time = "2023-03-08T17:50:12.741Z" }, - { url = "https://files.pythonhosted.org/packages/e8/1f/be19c9c9cfdcc2ae8ee8c65dbe5f281cc1f3331f9b9523735f39b090b448/msgpack-1.0.5-cp37-cp37m-win_amd64.whl", hash = "sha256:ab31e908d8424d55601ad7075e471b7d0140d4d3dd3272daf39c5c19d936bd82", size = 62112, upload-time = "2023-03-08T17:50:13.947Z" }, - { url = "https://files.pythonhosted.org/packages/1a/f7/df5814697c25bdebb14ea97d27ddca04f5d4c6e249f096d086fea521c139/msgpack-1.0.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:b72d0698f86e8d9ddf9442bdedec15b71df3598199ba33322d9711a19f08145c", size = 126923, upload-time = "2023-03-08T17:50:15.214Z" }, - { url = "https://files.pythonhosted.org/packages/33/52/099f0dde1283bac7bf267ab941dfa3b7c89ee701e4252973f8d3c10e68d6/msgpack-1.0.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:379026812e49258016dd84ad79ac8446922234d498058ae1d415f04b522d5b2d", size = 73246, upload-time = "2023-03-08T17:50:16.487Z" }, - { url = "https://files.pythonhosted.org/packages/f1/1f/cc3e8274934c8323f6106dae22cba8bad413166f4efb3819573de58c215c/msgpack-1.0.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:332360ff25469c346a1c5e47cbe2a725517919892eda5cfaffe6046656f0b7bb", size = 68947, upload-time = "2023-03-08T17:50:17.767Z" }, - { url = "https://files.pythonhosted.org/packages/19/0c/2c3b443df88f5d400f2e19a3d867564d004b26e137f18c2f2663913987bc/msgpack-1.0.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:476a8fe8fae289fdf273d6d2a6cb6e35b5a58541693e8f9f019bfe990a51e4ba", size = 313568, upload-time = "2023-03-08T17:50:19.016Z" }, - { url = "https://files.pythonhosted.org/packages/0a/04/bc319ba061f6dc9077745988be288705b3f9f18c5a209772a3e8fcd419fd/msgpack-1.0.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a9985b214f33311df47e274eb788a5893a761d025e2b92c723ba4c63936b69b1", size = 322443, upload-time = "2023-03-08T17:50:20.341Z" }, - { url = "https://files.pythonhosted.org/packages/2f/21/e488871f8e498efe14821b0c870eb95af52cfafb9b8dd41d83fad85b383b/msgpack-1.0.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:48296af57cdb1d885843afd73c4656be5c76c0c6328db3440c9601a98f303d87", size = 315490, upload-time = "2023-03-08T17:50:22.301Z" }, - { url = "https://files.pythonhosted.org/packages/28/8f/c58c53c884217cc572c19349c7e1129b5a6eae36df0a017aae3a8f3d7aa8/msgpack-1.0.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:addab7e2e1fcc04bd08e4eb631c2a90960c340e40dfc4a5e24d2ff0d5a3b3edb", size = 324288, upload-time = "2023-03-08T17:50:23.739Z" }, - { url = "https://files.pythonhosted.org/packages/0d/90/44edef4a8c6f035b054c4b017c5adcb22a35ec377e17e50dd5dced279a6b/msgpack-1.0.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:916723458c25dfb77ff07f4c66aed34e47503b2eb3188b3adbec8d8aa6e00f48", size = 361405, upload-time = "2023-03-08T17:50:24.992Z" }, - { url = "https://files.pythonhosted.org/packages/56/50/bfcc0fad07067b6f1b09d940272ec749d5fe82570d938c2348c3ad0babf7/msgpack-1.0.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:821c7e677cc6acf0fd3f7ac664c98803827ae6de594a9f99563e48c5a2f27eb0", size = 329585, upload-time = "2023-03-08T17:50:26.387Z" }, - { url = "https://files.pythonhosted.org/packages/80/f0/c1fadb4e4a38fda19e35b1b6f887d72cc9c57778af43b53f64a8cd62e922/msgpack-1.0.5-cp38-cp38-win32.whl", hash = "sha256:1c0f7c47f0087ffda62961d425e4407961a7ffd2aa004c81b9c07d9269512f6e", size = 57668, upload-time = "2023-03-08T17:50:28.037Z" }, - { url = "https://files.pythonhosted.org/packages/da/46/855bdcbf004fd87b6a4451e8dcd61329439dcd9039887f71ca5085769216/msgpack-1.0.5-cp38-cp38-win_amd64.whl", hash = "sha256:bae7de2026cbfe3782c8b78b0db9cbfc5455e079f1937cb0ab8d133496ac55e1", size = 62509, upload-time = "2023-03-08T17:50:29.85Z" }, - { url = "https://files.pythonhosted.org/packages/12/6e/0cfd1dc07f61a6ac606587a393f489c3ca463469d285a73c8e5e2f61b021/msgpack-1.0.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:20c784e66b613c7f16f632e7b5e8a1651aa5702463d61394671ba07b2fc9e025", size = 130498, upload-time = "2023-03-08T17:50:31.551Z" }, - { url = "https://files.pythonhosted.org/packages/4b/3d/cc5eb6d69e0ecde80a78cc42f48579971ec333e509d56a4a6de1a2c40ba2/msgpack-1.0.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:266fa4202c0eb94d26822d9bfd7af25d1e2c088927fe8de9033d929dd5ba24c5", size = 75178, upload-time = "2023-03-08T17:50:32.78Z" }, - { url = "https://files.pythonhosted.org/packages/bf/68/032e62ad44f92ba6a4ae7c45054843cdec7f0c405ecdfd166f25123b0c47/msgpack-1.0.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:18334484eafc2b1aa47a6d42427da7fa8f2ab3d60b674120bce7a895a0a85bdd", size = 70460, upload-time = "2023-03-08T17:50:34.57Z" }, - { url = "https://files.pythonhosted.org/packages/49/57/a28120d82f8e77622a1e1efc652389c71145f6b89b47b39814a7c6038373/msgpack-1.0.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:57e1f3528bd95cc44684beda696f74d3aaa8a5e58c816214b9046512240ef437", size = 313499, upload-time = "2023-03-08T17:50:36.329Z" }, - { url = "https://files.pythonhosted.org/packages/ab/ff/ca74e519c47139b6c08fb21db5ead2bd2eed6cb1225f9be69390cdb48182/msgpack-1.0.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:586d0d636f9a628ddc6a17bfd45aa5b5efaf1606d2b60fa5d87b8986326e933f", size = 322301, upload-time = "2023-03-08T17:50:38.097Z" }, - { url = "https://files.pythonhosted.org/packages/43/87/6507d56f62b958d822ae4ffe1c4507ed7d3cf37ad61114665816adcf4adc/msgpack-1.0.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a740fa0e4087a734455f0fc3abf5e746004c9da72fbd541e9b113013c8dc3282", size = 316630, upload-time = "2023-03-08T17:50:39.397Z" }, - { url = "https://files.pythonhosted.org/packages/67/f8/e3ab674f4a945308362e9342297fe6b35a89dd0f648aa325aabffa5dc210/msgpack-1.0.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:3055b0455e45810820db1f29d900bf39466df96ddca11dfa6d074fa47054376d", size = 316251, upload-time = "2023-03-08T17:50:41.153Z" }, - { url = "https://files.pythonhosted.org/packages/e9/f1/45b73a9e97f702bcb5f51569b93990e456bc969363e55122374c22ed7d24/msgpack-1.0.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:a61215eac016f391129a013c9e46f3ab308db5f5ec9f25811e811f96962599a8", size = 352781, upload-time = "2023-03-08T17:50:42.435Z" }, - { url = "https://files.pythonhosted.org/packages/17/10/be97811782473d709d07b65a3955a5a76d47686aff3d62bb41d48aea7c92/msgpack-1.0.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:362d9655cd369b08fda06b6657a303eb7172d5279997abe094512e919cf74b11", size = 321996, upload-time = "2023-03-08T17:50:43.726Z" }, - { url = "https://files.pythonhosted.org/packages/18/3f/3860151fbdf50e369bbe4ffd307a588417669c725025e383f3ce5893690f/msgpack-1.0.5-cp39-cp39-win32.whl", hash = "sha256:ac9dd47af78cae935901a9a500104e2dea2e253207c924cc95de149606dc43cc", size = 57827, upload-time = "2023-03-08T17:50:45.517Z" }, - { url = "https://files.pythonhosted.org/packages/6c/fa/3ca00fb1e53bcacf8c186fa6aff2d2086862b12e289bcf38227d9d40bd86/msgpack-1.0.5-cp39-cp39-win_amd64.whl", hash = "sha256:06f5174b5f8ed0ed919da0e62cbd4ffde676a374aba4020034da05fab67b9164", size = 62775, upload-time = "2023-03-08T17:50:47.305Z" }, -] - [[package]] name = "msgpack" version = "1.1.1" source = { registry = "https://pypi.org/simple" } resolution-markers = [ - "python_full_version == '3.8.*'", + "python_full_version < '3.9'", ] sdist = { url = "https://files.pythonhosted.org/packages/45/b1/ea4f68038a18c77c9467400d166d74c4ffa536f34761f7983a104357e614/msgpack-1.1.1.tar.gz", hash = "sha256:77b79ce34a2bdab2594f490c8e80dd62a02d650b91a75159a63ec413b8d104cd", size = 173555, upload-time = "2025-06-13T06:52:51.324Z" } wheels = [ @@ -1057,53 +792,21 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/14/a7/b1992b4fb3da3b413f5fb78a63bad42f256c3be2352eb69273c3789c2c96/msgpack-1.1.2-cp39-cp39-win_amd64.whl", hash = "sha256:67016ae8c8965124fdede9d3769528ad8284f14d635337ffa6a713a580f6c030", size = 71540, upload-time = "2025-10-08T09:15:55.573Z" }, ] -[[package]] -name = "packaging" -version = "24.0" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version < '3.8'", -] -sdist = { url = "https://files.pythonhosted.org/packages/ee/b5/b43a27ac7472e1818c4bafd44430e69605baefe1f34440593e0332ec8b4d/packaging-24.0.tar.gz", hash = "sha256:eb82c5e3e56209074766e6885bb04b8c38a0c015d0a30036ebe7ece34c9989e9", size = 147882, upload-time = "2024-03-10T09:39:28.33Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/49/df/1fceb2f8900f8639e278b056416d49134fb8d84c5942ffaa01ad34782422/packaging-24.0-py3-none-any.whl", hash = "sha256:2ddfb553fdf02fb784c234c7ba6ccc288296ceabec964ad2eae3777778130bc5", size = 53488, upload-time = "2024-03-10T09:39:25.947Z" }, -] - [[package]] name = "packaging" version = "25.0" source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version >= '3.10'", - "python_full_version == '3.9.*'", - "python_full_version == '3.8.*'", -] sdist = { url = "https://files.pythonhosted.org/packages/a1/d4/1fc4078c65507b51b96ca8f8c3ba19e6a61c8253c72794544580a7b6c24d/packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f", size = 165727, upload-time = "2025-04-19T11:48:59.673Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484", size = 66469, upload-time = "2025-04-19T11:48:57.875Z" }, ] -[[package]] -name = "pluggy" -version = "1.2.0" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version < '3.8'", -] -dependencies = [ - { name = "importlib-metadata", marker = "python_full_version < '3.8'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/8a/42/8f2833655a29c4e9cb52ee8a2be04ceac61bcff4a680fb338cbd3d1e322d/pluggy-1.2.0.tar.gz", hash = "sha256:d12f0c4b579b15f5e054301bb226ee85eeeba08ffec228092f8defbaa3a4c4b3", size = 61613, upload-time = "2023-06-21T09:12:28.745Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/51/32/4a79112b8b87b21450b066e102d6608907f4c885ed7b04c3fdb085d4d6ae/pluggy-1.2.0-py3-none-any.whl", hash = "sha256:c2fd55a7d7a3863cba1a013e4e2414658b1d07b6bc57b3919e0c63c9abb99849", size = 17695, upload-time = "2023-06-21T09:12:27.397Z" }, -] - [[package]] name = "pluggy" version = "1.5.0" source = { registry = "https://pypi.org/simple" } resolution-markers = [ - "python_full_version == '3.8.*'", + "python_full_version < '3.9'", ] sdist = { url = "https://files.pythonhosted.org/packages/96/2d/02d4312c973c6050a18b314a5ad0b3210edb65a906f868e31c111dede4a6/pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1", size = 67955, upload-time = "2024-04-20T21:34:42.531Z" } wheels = [ @@ -1178,32 +881,12 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/2b/62/2392b7879f4d2c1bfa20815720b89d464687877851716936b9609959c201/pycryptodome-3.23.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:ce64e84a962b63a47a592690bdc16a7eaf709d2c2697ababf24a0def566899a6", size = 1802461, upload-time = "2025-05-17T17:21:41.722Z" }, ] -[[package]] -name = "pyee" -version = "9.1.1" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version < '3.8'", -] -dependencies = [ - { name = "typing-extensions", version = "4.7.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.8'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/eb/2c/ebe4fd8213b3d720b193a62f07169607e945dd02a08edc45b28ca52fbe07/pyee-9.1.1.tar.gz", hash = "sha256:a1ebcd38d92e7d780635ab3442c0f6ce49840d9bfe0b0549921a6188860af0db", size = 22634, upload-time = "2023-06-09T06:13:29.141Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f2/53/39b67ce3841a5bb2d444f64ed969fb79ebd5bfed6867c3f88f3916407270/pyee-9.1.1-py2.py3-none-any.whl", hash = "sha256:f4a9853503d2f5a69d4350b54ba70841ebc535c53ebfaaa40c0fb47e63e78b3e", size = 15073, upload-time = "2023-06-09T06:13:27.255Z" }, -] - [[package]] name = "pyee" version = "13.0.0" source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version >= '3.10'", - "python_full_version == '3.9.*'", - "python_full_version == '3.8.*'", -] dependencies = [ - { name = "typing-extensions", version = "4.13.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.8.*'" }, + { name = "typing-extensions", version = "4.13.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.9'" }, { name = "typing-extensions", version = "4.15.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.9'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/95/03/1fd98d5841cd7964a27d729ccf2199602fe05eb7a405c1462eb7277945ed/pyee-13.0.0.tar.gz", hash = "sha256:b391e3c5a434d1f5118a25615001dbc8f669cf410ab67d04c4d4e07c55481c37", size = 31250, upload-time = "2025-03-17T18:53:15.955Z" } @@ -1218,50 +901,24 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "colorama", marker = "sys_platform == 'win32'" }, { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, - { name = "importlib-metadata", marker = "python_full_version < '3.8'" }, - { name = "iniconfig", version = "2.0.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.8'" }, - { name = "iniconfig", version = "2.1.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.8' and python_full_version < '3.10'" }, + { name = "iniconfig", version = "2.1.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, { name = "iniconfig", version = "2.3.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, - { name = "packaging", version = "24.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.8'" }, - { name = "packaging", version = "25.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.8'" }, - { name = "pluggy", version = "1.2.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.8'" }, - { name = "pluggy", version = "1.5.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.8.*'" }, + { name = "packaging" }, + { name = "pluggy", version = "1.5.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.9'" }, { name = "pluggy", version = "1.6.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.9'" }, - { name = "tomli", version = "2.0.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.8'" }, - { name = "tomli", version = "2.3.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.8' and python_full_version < '3.11'" }, + { name = "tomli", marker = "python_full_version < '3.11'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/80/1f/9d8e98e4133ffb16c90f3b405c43e38d3abb715bb5d7a63a5a684f7e46a3/pytest-7.4.4.tar.gz", hash = "sha256:2cf0005922c6ace4a3e2ec8b4080eb0d9753fdc93107415332f50ce9e7994280", size = 1357116, upload-time = "2023-12-31T12:00:18.035Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/51/ff/f6e8b8f39e08547faece4bd80f89d5a8de68a38b2d179cc1c4490ffa3286/pytest-7.4.4-py3-none-any.whl", hash = "sha256:b090cdf5ed60bf4c45261be03239c2c1c22df034fbffe691abe93cd80cea01d8", size = 325287, upload-time = "2023-12-31T12:00:13.963Z" }, ] -[[package]] -name = "pytest-asyncio" -version = "0.21.2" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version < '3.8'", -] -dependencies = [ - { name = "pytest", marker = "python_full_version < '3.8'" }, - { name = "typing-extensions", version = "4.7.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.8'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/ae/53/57663d99acaac2fcdafdc697e52a9b1b7d6fcf36616281ff9768a44e7ff3/pytest_asyncio-0.21.2.tar.gz", hash = "sha256:d67738fc232b94b326b9d060750beb16e0074210b98dd8b58a5239fa2a154f45", size = 30656, upload-time = "2024-04-29T13:23:24.738Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/9c/ce/1e4b53c213dce25d6e8b163697fbce2d43799d76fa08eea6ad270451c370/pytest_asyncio-0.21.2-py3-none-any.whl", hash = "sha256:ab664c88bb7998f711d8039cacd4884da6430886ae8bbd4eded552ed2004f16b", size = 13368, upload-time = "2024-04-29T13:23:23.126Z" }, -] - [[package]] name = "pytest-asyncio" version = "0.23.8" source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version >= '3.10'", - "python_full_version == '3.9.*'", - "python_full_version == '3.8.*'", -] dependencies = [ - { name = "pytest", marker = "python_full_version >= '3.8'" }, + { name = "pytest" }, ] sdist = { url = "https://files.pythonhosted.org/packages/de/b4/0b378b7bf26a8ae161c3890c0b48a91a04106c5713ce81b4b080ea2f4f18/pytest_asyncio-0.23.8.tar.gz", hash = "sha256:759b10b33a6dc61cce40a8bd5205e302978bbbcc00e279a8b61d9a6a3c82e4d3", size = 46920, upload-time = "2024-07-17T17:39:34.617Z" } wheels = [ @@ -1273,8 +930,7 @@ name = "pytest-cov" version = "2.12.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "coverage", version = "7.2.7", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.8'" }, - { name = "coverage", version = "7.6.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.8.*'" }, + { name = "coverage", version = "7.6.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.9'" }, { name = "coverage", version = "7.10.7", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.9.*'" }, { name = "coverage", version = "7.12.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, { name = "pytest" }, @@ -1315,8 +971,7 @@ name = "pytest-xdist" version = "1.34.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "execnet", version = "2.0.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.8'" }, - { name = "execnet", version = "2.1.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.8'" }, + { name = "execnet" }, { name = "pytest" }, { name = "pytest-forked" }, { name = "six" }, @@ -1326,32 +981,12 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/6a/fc/30821e7799bddd56989523ee003cde488c6e6053dfd29ba07db2ba934a04/pytest_xdist-1.34.0-py2.py3-none-any.whl", hash = "sha256:ba5d10729372d65df3ac150872f9df5d2ed004a3b0d499cc0164aafedd8c7b66", size = 36841, upload-time = "2020-07-27T23:05:23.851Z" }, ] -[[package]] -name = "respx" -version = "0.20.2" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version < '3.8'", -] -dependencies = [ - { name = "httpx", version = "0.24.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.8'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/e6/0b/e0df26ea5c7145d95f1ab8ecb20f0778dd8af718e56747977dca9d28362a/respx-0.20.2.tar.gz", hash = "sha256:07cf4108b1c88b82010f67d3c831dae33a375c7b436e54d87737c7f9f99be643", size = 26080, upload-time = "2023-07-20T23:01:23.618Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/47/47/8c5a8b02c2144770fe353585b6db21e392c4318b8cff897738159feff562/respx-0.20.2-py2.py3-none-any.whl", hash = "sha256:ab8e1cf6da28a5b2dd883ea617f8130f77f676736e6e9e4a25817ad116a172c9", size = 22849, upload-time = "2023-07-20T23:01:21.994Z" }, -] - [[package]] name = "respx" version = "0.22.0" source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version >= '3.10'", - "python_full_version == '3.9.*'", - "python_full_version == '3.8.*'", -] dependencies = [ - { name = "httpx", version = "0.28.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.8'" }, + { name = "httpx" }, ] sdist = { url = "https://files.pythonhosted.org/packages/f4/7c/96bd0bc759cf009675ad1ee1f96535edcb11e9666b985717eb8c87192a95/respx-0.22.0.tar.gz", hash = "sha256:3c8924caa2a50bd71aefc07aa812f2466ff489f1848c96e954a5362d17095d91", size = 28439, upload-time = "2024-12-19T22:33:59.374Z" } wheels = [ @@ -1402,24 +1037,12 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235, upload-time = "2024-02-25T23:20:01.196Z" }, ] -[[package]] -name = "tokenize-rt" -version = "5.0.0" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version < '3.8'", -] -sdist = { url = "https://files.pythonhosted.org/packages/40/01/fb40ea8c465f680bf7aa3f5bee39c62ba8b7f52c38048c27aa95aff4f779/tokenize_rt-5.0.0.tar.gz", hash = "sha256:3160bc0c3e8491312d0485171dea861fc160a240f5f5766b72a1165408d10740", size = 5329, upload-time = "2022-10-03T23:28:00.861Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/8d/12/4c7495f25b4c9131706f3aaffb185d4de32c02a6ee49d875e929c5b7c919/tokenize_rt-5.0.0-py2.py3-none-any.whl", hash = "sha256:c67772c662c6b3dc65edf66808577968fb10badfc2042e3027196bed4daf9e5a", size = 5848, upload-time = "2022-10-03T23:27:59.459Z" }, -] - [[package]] name = "tokenize-rt" version = "6.0.0" source = { registry = "https://pypi.org/simple" } resolution-markers = [ - "python_full_version == '3.8.*'", + "python_full_version < '3.9'", ] sdist = { url = "https://files.pythonhosted.org/packages/7d/09/6257dabdeab5097d72c5d874f29b33cd667ec411af6667922d84f85b79b5/tokenize_rt-6.0.0.tar.gz", hash = "sha256:b9711bdfc51210211137499b5e355d3de5ec88a85d2025c520cbb921b5194367", size = 5360, upload-time = "2024-08-04T21:01:19.405Z" } wheels = [ @@ -1448,27 +1071,10 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/44/6f/7120676b6d73228c96e17f1f794d8ab046fc910d781c8d151120c3f1569e/toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b", size = 16588, upload-time = "2020-11-01T01:40:20.672Z" }, ] -[[package]] -name = "tomli" -version = "2.0.1" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version < '3.8'", -] -sdist = { url = "https://files.pythonhosted.org/packages/c0/3f/d7af728f075fb08564c5949a9c95e44352e23dee646869fa104a3b2060a3/tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f", size = 15164, upload-time = "2022-02-08T10:54:04.006Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/97/75/10a9ebee3fd790d20926a90a2547f0bf78f371b2f13aa822c759680ca7b9/tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc", size = 12757, upload-time = "2022-02-08T10:54:02.017Z" }, -] - [[package]] name = "tomli" version = "2.3.0" source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version >= '3.10'", - "python_full_version == '3.9.*'", - "python_full_version == '3.8.*'", -] sdist = { url = "https://files.pythonhosted.org/packages/52/ed/3f73f72945444548f33eba9a87fc7a6e969915e7b1acc8260b30e1f76a2f/tomli-2.3.0.tar.gz", hash = "sha256:64be704a875d2a59753d80ee8a533c3fe183e3f06807ff7dc2232938ccb01549", size = 17392, upload-time = "2025-10-08T22:01:47.119Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/b3/2e/299f62b401438d5fe1624119c723f5d877acc86a4c2492da405626665f12/tomli-2.3.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:88bd15eb972f3664f5ed4b57c1634a97153b4bac4479dcb6a495f41921eb7f45", size = 153236, upload-time = "2025-10-08T22:01:00.137Z" }, @@ -1514,24 +1120,12 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/77/b8/0135fadc89e73be292b473cb820b4f5a08197779206b33191e801feeae40/tomli-2.3.0-py3-none-any.whl", hash = "sha256:e95b1af3c5b07d9e643909b5abbec77cd9f1217e6d0bca72b0234736b9fb1f1b", size = 14408, upload-time = "2025-10-08T22:01:46.04Z" }, ] -[[package]] -name = "typing-extensions" -version = "4.7.1" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version < '3.8'", -] -sdist = { url = "https://files.pythonhosted.org/packages/3c/8b/0111dd7d6c1478bf83baa1cab85c686426c7a6274119aceb2bd9d35395ad/typing_extensions-4.7.1.tar.gz", hash = "sha256:b75ddc264f0ba5615db7ba217daeb99701ad295353c45f9e95963337ceeeffb2", size = 72876, upload-time = "2023-07-02T14:20:55.045Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ec/6b/63cc3df74987c36fe26157ee12e09e8f9db4de771e0f3404263117e75b95/typing_extensions-4.7.1-py3-none-any.whl", hash = "sha256:440d5dd3af93b060174bf433bccd69b0babc3b15b1a8dca43789fd7f61514b36", size = 33232, upload-time = "2023-07-02T14:20:53.275Z" }, -] - [[package]] name = "typing-extensions" version = "4.13.2" source = { registry = "https://pypi.org/simple" } resolution-markers = [ - "python_full_version == '3.8.*'", + "python_full_version < '3.9'", ] sdist = { url = "https://files.pythonhosted.org/packages/f6/37/23083fcd6e35492953e8d2aaaa68b860eb422b34627b13f2ce3eb6106061/typing_extensions-4.13.2.tar.gz", hash = "sha256:e6c81219bd689f51865d9e372991c540bda33a0379d5573cddb9a3a23f7caaef", size = 106967, upload-time = "2025-04-10T14:19:05.416Z" } wheels = [ @@ -1560,92 +1154,12 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/10/d5/0d1153f2dbaa02a11b2491d26b59f08e203409dacb91853c26c13bc28cb6/vcdiff_decoder-0.1.0-py3-none-any.whl", hash = "sha256:42f4e3d77b3bd4be881853858ee471a11d6a474fda375482d589b8576b91318f", size = 26333, upload-time = "2025-09-19T17:15:13.611Z" }, ] -[[package]] -name = "websockets" -version = "11.0.3" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version < '3.8'", -] -sdist = { url = "https://files.pythonhosted.org/packages/d8/3b/2ed38e52eed4cf277f9df5f0463a99199a04d9e29c9e227cfafa57bd3993/websockets-11.0.3.tar.gz", hash = "sha256:88fc51d9a26b10fc331be344f1781224a375b78488fc343620184e95a4b27016", size = 104235, upload-time = "2023-05-07T14:25:20.083Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e1/76/88640f8aeac7eb0d058b913e7bb72682f8d569db44c7d30e576ec4777ce1/websockets-11.0.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3ccc8a0c387629aec40f2fc9fdcb4b9d5431954f934da3eaf16cdc94f67dbfac", size = 123714, upload-time = "2023-05-07T14:23:15.309Z" }, - { url = "https://files.pythonhosted.org/packages/b9/6b/26b28115b46e23e74ede76d95792eedfe8c58b21f4daabfff1e9f159c8fe/websockets-11.0.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d67ac60a307f760c6e65dad586f556dde58e683fab03323221a4e530ead6f74d", size = 120949, upload-time = "2023-05-07T14:23:17.656Z" }, - { url = "https://files.pythonhosted.org/packages/f3/82/2d1f3395d47fab65fa8b801e2251b324300ed8db54753b6fb7919cef0c11/websockets-11.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:84d27a4832cc1a0ee07cdcf2b0629a8a72db73f4cf6de6f0904f6661227f256f", size = 121032, upload-time = "2023-05-07T14:23:20.096Z" }, - { url = "https://files.pythonhosted.org/packages/b2/ec/56bdd12d847e4fc2d0a7ba2d7f1476f79cda50599d11ffb6080b86f21ef1/websockets-11.0.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ffd7dcaf744f25f82190856bc26ed81721508fc5cbf2a330751e135ff1283564", size = 130620, upload-time = "2023-05-07T14:23:21.545Z" }, - { url = "https://files.pythonhosted.org/packages/c9/fb/ae5ed4be3514287cf8f6c348c87e1392a6e3f4d6eadae75c18847a2f84b6/websockets-11.0.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7622a89d696fc87af8e8d280d9b421db5133ef5b29d3f7a1ce9f1a7bf7fcfa11", size = 129628, upload-time = "2023-05-07T14:23:23.105Z" }, - { url = "https://files.pythonhosted.org/packages/58/0a/7570e15661a0a546c3a1152d95fe8c05480459bab36247f0acbf41f01a41/websockets-11.0.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bceab846bac555aff6427d060f2fcfff71042dba6f5fca7dc4f75cac815e57ca", size = 129938, upload-time = "2023-05-07T14:23:24.959Z" }, - { url = "https://files.pythonhosted.org/packages/ba/6c/5c0322b2875e8395e6bf0eff11f43f3e25da7ef5b12f4d908cd3a19ea841/websockets-11.0.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:54c6e5b3d3a8936a4ab6870d46bdd6ec500ad62bde9e44462c32d18f1e9a8e54", size = 134663, upload-time = "2023-05-07T14:23:26.382Z" }, - { url = "https://files.pythonhosted.org/packages/de/0e/d7274e4d41d7b34f204744c27a23707be2ecefaf6f7df2145655f086ecd7/websockets-11.0.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:41f696ba95cd92dc047e46b41b26dd24518384749ed0d99bea0a941ca87404c4", size = 133900, upload-time = "2023-05-07T14:23:28.307Z" }, - { url = "https://files.pythonhosted.org/packages/82/3c/00f051abcf88aec5e952a8840076749b0b26a30c219dcae8ba70200998aa/websockets-11.0.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:86d2a77fd490ae3ff6fae1c6ceaecad063d3cc2320b44377efdde79880e11526", size = 134520, upload-time = "2023-05-07T14:23:30.734Z" }, - { url = "https://files.pythonhosted.org/packages/8f/7b/4d4ecd29be7d08486e38f987a6603c491296d1e33fe55127d79aebb0333e/websockets-11.0.3-cp310-cp310-win32.whl", hash = "sha256:2d903ad4419f5b472de90cd2d40384573b25da71e33519a67797de17ef849b69", size = 124152, upload-time = "2023-05-07T14:23:33.183Z" }, - { url = "https://files.pythonhosted.org/packages/98/a7/0ed69892981351e5acf88fac0ff4c801fabca2c3bdef9fca4c7d3fde8c53/websockets-11.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:1d2256283fa4b7f4c7d7d3e84dc2ece74d341bce57d5b9bf385df109c2a1a82f", size = 124674, upload-time = "2023-05-07T14:23:35.331Z" }, - { url = "https://files.pythonhosted.org/packages/16/49/ae616bd221efba84a3d78737b417f704af1ffa36f40dcaba5eb954dd4753/websockets-11.0.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:e848f46a58b9fcf3d06061d17be388caf70ea5b8cc3466251963c8345e13f7eb", size = 123748, upload-time = "2023-05-07T14:23:37.977Z" }, - { url = "https://files.pythonhosted.org/packages/0a/84/68b848a373493b58615d6c10e9e8ccbaadfd540f84905421739a807704f8/websockets-11.0.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:aa5003845cdd21ac0dc6c9bf661c5beddd01116f6eb9eb3c8e272353d45b3288", size = 120975, upload-time = "2023-05-07T14:23:40.339Z" }, - { url = "https://files.pythonhosted.org/packages/8c/a8/e81533499f84ef6cdd95d11d5b05fa827c0f097925afd86f16e6a2631d8e/websockets-11.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b58cbf0697721120866820b89f93659abc31c1e876bf20d0b3d03cef14faf84d", size = 121017, upload-time = "2023-05-07T14:23:41.874Z" }, - { url = "https://files.pythonhosted.org/packages/6b/ca/65d6986665888494eca4d5435a9741c822022996f0f4200c57ce4b9242f7/websockets-11.0.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:660e2d9068d2bedc0912af508f30bbeb505bbbf9774d98def45f68278cea20d3", size = 131200, upload-time = "2023-05-07T14:23:43.309Z" }, - { url = "https://files.pythonhosted.org/packages/c0/a8/a8a582ebeeecc8b5f332997d44c57e241748f8a9856e06a38a5a13b30796/websockets-11.0.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c1f0524f203e3bd35149f12157438f406eff2e4fb30f71221c8a5eceb3617b6b", size = 130195, upload-time = "2023-05-07T14:23:45.337Z" }, - { url = "https://files.pythonhosted.org/packages/a9/5e/b25c60067d700e811dccb4e3c318eeadd3a19d8b3620de9f97434af777a7/websockets-11.0.3-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:def07915168ac8f7853812cc593c71185a16216e9e4fa886358a17ed0fd9fcf6", size = 130569, upload-time = "2023-05-07T14:23:46.926Z" }, - { url = "https://files.pythonhosted.org/packages/14/fc/5cbbf439c925e1e184a0392ec477a30cee2fabc0e63807c1d4b6d570fb52/websockets-11.0.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:b30c6590146e53149f04e85a6e4fcae068df4289e31e4aee1fdf56a0dead8f97", size = 136015, upload-time = "2023-05-07T14:23:48.43Z" }, - { url = "https://files.pythonhosted.org/packages/0f/d8/a997d3546aef9cc995a1126f7d7ade96c0e16c1a0efb9d2d430aee57c925/websockets-11.0.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:619d9f06372b3a42bc29d0cd0354c9bb9fb39c2cbc1a9c5025b4538738dbffaf", size = 135292, upload-time = "2023-05-07T14:23:50.744Z" }, - { url = "https://files.pythonhosted.org/packages/89/8f/707a05d5725f956c78d252a5fd73b89fa3ac57dd3959381c2d1acb41cb13/websockets-11.0.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:01f5567d9cf6f502d655151645d4e8b72b453413d3819d2b6f1185abc23e82dd", size = 135890, upload-time = "2023-05-07T14:23:52.707Z" }, - { url = "https://files.pythonhosted.org/packages/b5/94/ac47552208583d5dbcce468430c1eb2ae18962f6b3a694a2b7727cc60d4a/websockets-11.0.3-cp311-cp311-win32.whl", hash = "sha256:e1459677e5d12be8bbc7584c35b992eea142911a6236a3278b9b5ce3326f282c", size = 124149, upload-time = "2023-05-07T14:23:53.848Z" }, - { url = "https://files.pythonhosted.org/packages/e1/7c/0ad6e7ef0a054d73092f616d20d3d9bd3e1b837554cb20a52d8dd9f5b049/websockets-11.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:e7837cb169eca3b3ae94cc5787c4fed99eef74c0ab9506756eea335e0d6f3ed8", size = 124670, upload-time = "2023-05-07T14:23:55.812Z" }, - { url = "https://files.pythonhosted.org/packages/b5/a8/8900184ab0b06b6e620ba7e92cf2faa5caa9ba86e148541b8fff1c7b6646/websockets-11.0.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:9f59a3c656fef341a99e3d63189852be7084c0e54b75734cde571182c087b152", size = 120868, upload-time = "2023-05-07T14:23:57.24Z" }, - { url = "https://files.pythonhosted.org/packages/44/a8/66c3a66b70b01a6c55fde486298766177fa11dd0d3a2c1cfc6820f25b4dc/websockets-11.0.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2529338a6ff0eb0b50c7be33dc3d0e456381157a31eefc561771ee431134a97f", size = 130557, upload-time = "2023-05-07T14:23:59.274Z" }, - { url = "https://files.pythonhosted.org/packages/70/fc/71377f36ef3049f3bc7db7c0f3a7696929d5f836d7a18777131d994192a9/websockets-11.0.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:34fd59a4ac42dff6d4681d8843217137f6bc85ed29722f2f7222bd619d15e95b", size = 129640, upload-time = "2023-05-07T14:24:01.412Z" }, - { url = "https://files.pythonhosted.org/packages/36/19/0da435afb26a6c47c0c045a82e414912aa2ac10de5721276a342bd9fdfee/websockets-11.0.3-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:332d126167ddddec94597c2365537baf9ff62dfcc9db4266f263d455f2f031cb", size = 129903, upload-time = "2023-05-07T14:24:02.872Z" }, - { url = "https://files.pythonhosted.org/packages/38/ed/b8b133416536b6816e480594864e5950051db522714623eefc9e5275ec04/websockets-11.0.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:6505c1b31274723ccaf5f515c1824a4ad2f0d191cec942666b3d0f3aa4cb4007", size = 135302, upload-time = "2023-05-07T14:24:04.326Z" }, - { url = "https://files.pythonhosted.org/packages/e9/26/1dfaa81788f61c485b4d65f1b28a19615e39f9c45100dce5e2cbf5ad1352/websockets-11.0.3-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:f467ba0050b7de85016b43f5a22b46383ef004c4f672148a8abf32bc999a87f0", size = 134562, upload-time = "2023-05-07T14:24:05.829Z" }, - { url = "https://files.pythonhosted.org/packages/a7/f7/1e852351e8073c32885172a6bef64c95d14c13ff3634b01d4a1086321491/websockets-11.0.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:9d9acd80072abcc98bd2c86c3c9cd4ac2347b5a5a0cae7ed5c0ee5675f86d9af", size = 135191, upload-time = "2023-05-07T14:24:07.659Z" }, - { url = "https://files.pythonhosted.org/packages/19/d3/2ea3f95d83033675144b0848a0ae2e4998b3f763da09ec3df6bce97ea4e6/websockets-11.0.3-cp37-cp37m-win32.whl", hash = "sha256:e590228200fcfc7e9109509e4d9125eace2042fd52b595dd22bbc34bb282307f", size = 124138, upload-time = "2023-05-07T14:24:09.697Z" }, - { url = "https://files.pythonhosted.org/packages/94/8c/266155c14b7a26deca6fa4c4d5fd15b0ab32725d78a2acfcf6b24943585d/websockets-11.0.3-cp37-cp37m-win_amd64.whl", hash = "sha256:b16fff62b45eccb9c7abb18e60e7e446998093cdcb50fed33134b9b6878836de", size = 124672, upload-time = "2023-05-07T14:24:12.595Z" }, - { url = "https://files.pythonhosted.org/packages/c4/5b/60eccd7e9703bbe93fc4167d1e7ada7e8e8e51544122198d63fd8e3460b7/websockets-11.0.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:fb06eea71a00a7af0ae6aefbb932fb8a7df3cb390cc217d51a9ad7343de1b8d0", size = 123706, upload-time = "2023-05-07T14:24:14.633Z" }, - { url = "https://files.pythonhosted.org/packages/d1/ec/7e2b9bebc2e9b4a48404144106bbc6a7ace781feeb0e6a3829551e725fa5/websockets-11.0.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:8a34e13a62a59c871064dfd8ffb150867e54291e46d4a7cf11d02c94a5275bae", size = 120944, upload-time = "2023-05-07T14:24:16.144Z" }, - { url = "https://files.pythonhosted.org/packages/8a/bd/a5e5973899d78d44a540f50a9e30b01c6771e8bf7883204ee762060cf95a/websockets-11.0.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4841ed00f1026dfbced6fca7d963c4e7043aa832648671b5138008dc5a8f6d99", size = 121030, upload-time = "2023-05-07T14:24:17.905Z" }, - { url = "https://files.pythonhosted.org/packages/ec/3f/0c5cae14e9e86401105833383405787ae4caddd476a8fc5561259253dab7/websockets-11.0.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1a073fc9ab1c8aff37c99f11f1641e16da517770e31a37265d2755282a5d28aa", size = 130811, upload-time = "2023-05-07T14:24:21.175Z" }, - { url = "https://files.pythonhosted.org/packages/a0/39/acc3d4b15c5207ef7cca823c37eca8c74e3e1a1a63a397798986be3bdef7/websockets-11.0.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:68b977f21ce443d6d378dbd5ca38621755f2063d6fdb3335bda981d552cfff86", size = 129876, upload-time = "2023-05-07T14:24:22.498Z" }, - { url = "https://files.pythonhosted.org/packages/58/05/2efb520317340ece74bfc4d88e8f011dd71a4e6c263000bfffb71a343685/websockets-11.0.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e1a99a7a71631f0efe727c10edfba09ea6bee4166a6f9c19aafb6c0b5917d09c", size = 130158, upload-time = "2023-05-07T14:24:25.193Z" }, - { url = "https://files.pythonhosted.org/packages/30/a5/d641f2a9a4b4079cfddbb0726fc1b914be76a610aaedb45e4760899a4ce1/websockets-11.0.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:bee9fcb41db2a23bed96c6b6ead6489702c12334ea20a297aa095ce6d31370d0", size = 134494, upload-time = "2023-05-07T14:24:26.463Z" }, - { url = "https://files.pythonhosted.org/packages/ca/20/25211be61d50189650fb0ec6084b6d6339f5c7c6436a6c217608dcb553e4/websockets-11.0.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:4b253869ea05a5a073ebfdcb5cb3b0266a57c3764cf6fe114e4cd90f4bfa5f5e", size = 133735, upload-time = "2023-05-07T14:24:29.598Z" }, - { url = "https://files.pythonhosted.org/packages/c6/91/f36454b87edf10a95be9c7212d2dcb8c606ddbf7a183afdc498933acdd19/websockets-11.0.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:1553cb82942b2a74dd9b15a018dce645d4e68674de2ca31ff13ebc2d9f283788", size = 134368, upload-time = "2023-05-07T14:24:30.923Z" }, - { url = "https://files.pythonhosted.org/packages/58/68/9403771de1b1c21a2e878e4841815af8c9f8893b094654934e2a5ee4dbc8/websockets-11.0.3-cp38-cp38-win32.whl", hash = "sha256:f61bdb1df43dc9c131791fbc2355535f9024b9a04398d3bd0684fc16ab07df74", size = 124148, upload-time = "2023-05-07T14:24:32.299Z" }, - { url = "https://files.pythonhosted.org/packages/25/25/48540419005d07ed2d368a7eafb44ed4f33a2691ae4c210850bf31123c4a/websockets-11.0.3-cp38-cp38-win_amd64.whl", hash = "sha256:03aae4edc0b1c68498f41a6772d80ac7c1e33c06c6ffa2ac1c27a07653e79d6f", size = 124665, upload-time = "2023-05-07T14:24:34.482Z" }, - { url = "https://files.pythonhosted.org/packages/c0/21/cb9dfbbea8dc0ad89ced52630e7e61edb425fb9fdc6002f8d0c5dd26b94b/websockets-11.0.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:777354ee16f02f643a4c7f2b3eff8027a33c9861edc691a2003531f5da4f6bc8", size = 123707, upload-time = "2023-05-07T14:24:36.007Z" }, - { url = "https://files.pythonhosted.org/packages/8f/f2/8a3eb016be19743c7eb9e67c855df0fdfa5912534ffaf83a05b62667d761/websockets-11.0.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8c82f11964f010053e13daafdc7154ce7385ecc538989a354ccc7067fd7028fd", size = 120963, upload-time = "2023-05-07T14:24:37.478Z" }, - { url = "https://files.pythonhosted.org/packages/a0/1a/3da73e69ebc00649d11ed836541c92c1a2df0b8a8aa641a2c8746e7c2b9c/websockets-11.0.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3580dd9c1ad0701169e4d6fc41e878ffe05e6bdcaf3c412f9d559389d0c9e016", size = 121014, upload-time = "2023-05-07T14:24:39.009Z" }, - { url = "https://files.pythonhosted.org/packages/d9/36/5741e62ccf629c8e38cc20f930491f8a33ce7dba972cae93dba3d6f02552/websockets-11.0.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6f1a3f10f836fab6ca6efa97bb952300b20ae56b409414ca85bff2ad241d2a61", size = 130408, upload-time = "2023-05-07T14:24:40.825Z" }, - { url = "https://files.pythonhosted.org/packages/66/89/799f595c67b97a8a17e13d2764e088f631616bd95668aaa4c04b7cada136/websockets-11.0.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:df41b9bc27c2c25b486bae7cf42fccdc52ff181c8c387bfd026624a491c2671b", size = 129407, upload-time = "2023-05-07T14:24:42.479Z" }, - { url = "https://files.pythonhosted.org/packages/a6/9c/2356ecb952fd3992b73f7a897d65e57d784a69b94bb8d8fd5f97531e5c02/websockets-11.0.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:279e5de4671e79a9ac877427f4ac4ce93751b8823f276b681d04b2156713b9dd", size = 129712, upload-time = "2023-05-07T14:24:44.186Z" }, - { url = "https://files.pythonhosted.org/packages/c4/f5/15998b164c183af0513bba744b51ecb08d396ff86c0db3b55d62624d1f15/websockets-11.0.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:1fdf26fa8a6a592f8f9235285b8affa72748dc12e964a5518c6c5e8f916716f7", size = 134386, upload-time = "2023-05-07T14:24:45.702Z" }, - { url = "https://files.pythonhosted.org/packages/8a/77/a04d2911f6e2b9e781ce7ffc1e8516b54b85f985369eec8c853fd619d8e8/websockets-11.0.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:69269f3a0b472e91125b503d3c0b3566bda26da0a3261c49f0027eb6075086d1", size = 133639, upload-time = "2023-05-07T14:24:46.966Z" }, - { url = "https://files.pythonhosted.org/packages/72/89/0d150939f2e592ed78c071d69237ac1c872462cc62a750c5f592f3d4ab18/websockets-11.0.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:97b52894d948d2f6ea480171a27122d77af14ced35f62e5c892ca2fae9344311", size = 134260, upload-time = "2023-05-07T14:24:48.633Z" }, - { url = "https://files.pythonhosted.org/packages/9a/6e/0fd7274042f46acb589161407f4b505b44c68d369437ce919bae1fa9b8c4/websockets-11.0.3-cp39-cp39-win32.whl", hash = "sha256:c7f3cb904cce8e1be667c7e6fef4516b98d1a6a0635a58a57528d577ac18a128", size = 124146, upload-time = "2023-05-07T14:24:50.566Z" }, - { url = "https://files.pythonhosted.org/packages/f4/3f/65dfa50084a06ab0a05f3ca74195c2c17a1c075b8361327d831ccce0a483/websockets-11.0.3-cp39-cp39-win_amd64.whl", hash = "sha256:c792ea4eabc0159535608fc5658a74d1a81020eb35195dd63214dcf07556f67e", size = 124665, upload-time = "2023-05-07T14:24:52.111Z" }, - { url = "https://files.pythonhosted.org/packages/e2/2f/3ad8ac4a9dc9d685e098e534180a36ed68fe2e85e82e225e00daec86bb94/websockets-11.0.3-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:f2e58f2c36cc52d41f2659e4c0cbf7353e28c8c9e63e30d8c6d3494dc9fdedcf", size = 120795, upload-time = "2023-05-07T14:24:53.421Z" }, - { url = "https://files.pythonhosted.org/packages/a7/8c/7100e9cf310fe1d83d1ae1322203f4eb2b767a7c2b301c1e70db6270306f/websockets-11.0.3-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:de36fe9c02995c7e6ae6efe2e205816f5f00c22fd1fbf343d4d18c3d5ceac2f5", size = 122910, upload-time = "2023-05-07T14:24:54.851Z" }, - { url = "https://files.pythonhosted.org/packages/78/b2/df5452031b02b857851139806308f2af7c749069e25bfe15f2d559ade6e7/websockets-11.0.3-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0ac56b661e60edd453585f4bd68eb6a29ae25b5184fd5ba51e97652580458998", size = 122516, upload-time = "2023-05-07T14:24:56.477Z" }, - { url = "https://files.pythonhosted.org/packages/03/28/3a51ffcf51ac45746639f83128908bbb1cd212aa631e42d15a7acebce5cb/websockets-11.0.3-pp37-pypy37_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e052b8467dd07d4943936009f46ae5ce7b908ddcac3fda581656b1b19c083d9b", size = 122462, upload-time = "2023-05-07T14:24:57.77Z" }, - { url = "https://files.pythonhosted.org/packages/eb/fb/2af7fc3ce2c3f1378d48a15802b4ff2caf6c0dfac13291e73c557caf04f7/websockets-11.0.3-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:42cc5452a54a8e46a032521d7365da775823e21bfba2895fb7b77633cce031bb", size = 124704, upload-time = "2023-05-07T14:24:59.322Z" }, - { url = "https://files.pythonhosted.org/packages/20/62/5c6039c4069912adb27889ddd000403a2de9e0fe6aebe439b4e6b128a6b8/websockets-11.0.3-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:e6316827e3e79b7b8e7d8e3b08f4e331af91a48e794d5d8b099928b6f0b85f20", size = 120795, upload-time = "2023-05-07T14:25:01.047Z" }, - { url = "https://files.pythonhosted.org/packages/38/30/01a10fbf4cc1e7ffa07be9b0401501918fc9433d71fb7da4cfcef3bd26ca/websockets-11.0.3-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8531fdcad636d82c517b26a448dcfe62f720e1922b33c81ce695d0edb91eb931", size = 122908, upload-time = "2023-05-07T14:25:02.734Z" }, - { url = "https://files.pythonhosted.org/packages/99/23/43071c989c0f87f612e7bccee98d00b04bddd3aca0cdc1ffaf31f6f8a4b4/websockets-11.0.3-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c114e8da9b475739dde229fd3bc6b05a6537a88a578358bc8eb29b4030fac9c9", size = 122515, upload-time = "2023-05-07T14:25:04.803Z" }, - { url = "https://files.pythonhosted.org/packages/b6/96/0d586c25d043aeab9457dad8e407251e3baf314d871215f91847e7b995c4/websockets-11.0.3-pp38-pypy38_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e063b1865974611313a3849d43f2c3f5368093691349cf3c7c8f8f75ad7cb280", size = 122465, upload-time = "2023-05-07T14:25:06.352Z" }, - { url = "https://files.pythonhosted.org/packages/27/e9/605b0618d0864e9be7c2a78f22bff57aba9cf56b9fccde3205db9023ae22/websockets-11.0.3-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:92b2065d642bf8c0a82d59e59053dd2fdde64d4ed44efe4870fa816c1232647b", size = 124707, upload-time = "2023-05-07T14:25:07.782Z" }, - { url = "https://files.pythonhosted.org/packages/1b/3d/3dc77699fa4d003f2e810c321592f80f62b81d7b78483509de72ffe581fd/websockets-11.0.3-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:0ee68fe502f9031f19d495dae2c268830df2760c0524cbac5d759921ba8c8e82", size = 120795, upload-time = "2023-05-07T14:25:09.785Z" }, - { url = "https://files.pythonhosted.org/packages/a6/1b/5c83c40f8d3efaf0bb2fdf05af94fb920f74842b7aaf31d7598e3ee44d58/websockets-11.0.3-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dcacf2c7a6c3a84e720d1bb2b543c675bf6c40e460300b628bab1b1efc7c034c", size = 122909, upload-time = "2023-05-07T14:25:11.243Z" }, - { url = "https://files.pythonhosted.org/packages/32/2c/ab8ea64e9a7d8bf62a7ea7a037fb8d328d8bd46dbfe083787a9d452a148e/websockets-11.0.3-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b67c6f5e5a401fc56394f191f00f9b3811fe843ee93f4a70df3c389d1adf857d", size = 122517, upload-time = "2023-05-07T14:25:12.881Z" }, - { url = "https://files.pythonhosted.org/packages/8b/97/34178f5f7c29e679372d597cebfeff2aa45991d741d938117d4616e81a74/websockets-11.0.3-pp39-pypy39_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1d5023a4b6a5b183dc838808087033ec5df77580485fc533e7dab2567851b0a4", size = 122463, upload-time = "2023-05-07T14:25:15.154Z" }, - { url = "https://files.pythonhosted.org/packages/ed/45/466944e00b324ae3a1fddb305b4abf641f582e131548f07bcd970971b154/websockets-11.0.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:ed058398f55163a79bb9f06a90ef9ccc063b204bb346c4de78efc5d15abfe602", size = 124707, upload-time = "2023-05-07T14:25:17.112Z" }, - { url = "https://files.pythonhosted.org/packages/47/96/9d5749106ff57629b54360664ae7eb9afd8302fad1680ead385383e33746/websockets-11.0.3-py3-none-any.whl", hash = "sha256:6681ba9e7f8f3b19440921e99efbb40fc89f26cd71bf539e45d8c8a25c976dc6", size = 118056, upload-time = "2023-05-07T14:25:18.508Z" }, -] - [[package]] name = "websockets" version = "13.1" source = { registry = "https://pypi.org/simple" } resolution-markers = [ - "python_full_version == '3.8.*'", + "python_full_version < '3.9'", ] sdist = { url = "https://files.pythonhosted.org/packages/e2/73/9223dbc7be3dcaf2a7bbf756c351ec8da04b1fa573edaf545b95f6b0c7fd/websockets-13.1.tar.gz", hash = "sha256:a3b3366087c1bc0a2795111edcadddb8b3b59509d5db5d7ea3fdd69f954a8878", size = 158549, upload-time = "2024-09-21T17:34:21.54Z" } wheels = [ @@ -1816,24 +1330,12 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/fa/a8/5b41e0da817d64113292ab1f8247140aac61cbf6cfd085d6a0fa77f4984f/websockets-15.0.1-py3-none-any.whl", hash = "sha256:f7a866fbc1e97b5c617ee4116daaa09b722101d4a3c170c787450ba409f9736f", size = 169743, upload-time = "2025-03-05T20:03:39.41Z" }, ] -[[package]] -name = "zipp" -version = "3.15.0" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version < '3.8'", -] -sdist = { url = "https://files.pythonhosted.org/packages/00/27/f0ac6b846684cecce1ee93d32450c45ab607f65c2e0255f0092032d91f07/zipp-3.15.0.tar.gz", hash = "sha256:112929ad649da941c23de50f356a2b5570c954b65150642bccdd66bf194d224b", size = 18454, upload-time = "2023-02-25T02:17:22.503Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/5b/fa/c9e82bbe1af6266adf08afb563905eb87cab83fde00a0a08963510621047/zipp-3.15.0-py3-none-any.whl", hash = "sha256:48904fc76a60e542af151aded95726c1a5c34ed43ab4134b597665c86d7ad556", size = 6758, upload-time = "2023-02-25T02:17:20.807Z" }, -] - [[package]] name = "zipp" version = "3.20.2" source = { registry = "https://pypi.org/simple" } resolution-markers = [ - "python_full_version == '3.8.*'", + "python_full_version < '3.9'", ] sdist = { url = "https://files.pythonhosted.org/packages/54/bf/5c0000c44ebc80123ecbdddba1f5dcd94a5ada602a9c225d84b5aaa55e86/zipp-3.20.2.tar.gz", hash = "sha256:bc9eb26f4506fda01b81bcde0ca78103b6e62f991b381fec825435c836edbc29", size = 24199, upload-time = "2024-09-13T13:44:16.101Z" } wheels = [ From 7f1cff920eda06f1777286285b41117417869d11 Mon Sep 17 00:00:00 2001 From: umair Date: Thu, 3 Sep 2026 13:22:42 +0100 Subject: [PATCH 3/7] Rename the agent family identifier and make agents extensible MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Ably-Agent header is how the platform tells SDKs apart, and after the package split it is also how a client declares which side it runs on. Two changes, both in the core. The family identifier becomes `ably-pubsub-python`, still versioned with lib_version. It lands on the integration branch before any prerelease ships so that even prerelease traffic partitions cleanly from legacy `ably-python/*` traffic; the maintenance branch keeps `ably-python`. Registered in ably-common#361. `Options` gains an additive `agents: dict[str, str | None]` client option, and `HttpUtils.default_headers()` renders each entry as `name/version`, or as a bare flag when the version is None — matching how the agents registry records entries that carry no version of their own, such as `browser`. Wire shape: ably-pubsub-python/4.0.0 python/3.12.1 ably-pubsub-server Both the HTTP request path and the websocket handshake already funnel through default_headers(), so both now pass the options' agents through and the header is stamped identically on either transport. Co-Authored-By: Claude Opus 5 --- core/src/ably_pubsub/core/http/http.py | 6 ++-- core/src/ably_pubsub/core/http/httputils.py | 35 +++++++++++++++---- .../core/transport/websockettransport.py | 2 +- core/src/ably_pubsub/core/types/options.py | 15 +++++++- test/ably/rest/resthttp_test.py | 2 +- 5 files changed, 49 insertions(+), 11 deletions(-) diff --git a/core/src/ably_pubsub/core/http/http.py b/core/src/ably_pubsub/core/http/http.py index 6b184f6c..6b3a8fe9 100644 --- a/core/src/ably_pubsub/core/http/http.py +++ b/core/src/ably_pubsub/core/http/http.py @@ -165,9 +165,11 @@ async def make_request(self, method, path, version=None, headers=None, body=None body = self.dump_body(body) if body: - all_headers = HttpUtils.default_post_headers(self.options.use_binary_protocol, version=version) + all_headers = HttpUtils.default_post_headers(self.options.use_binary_protocol, version=version, + agents=self.options.agents) else: - all_headers = HttpUtils.default_get_headers(self.options.use_binary_protocol, version=version) + all_headers = HttpUtils.default_get_headers(self.options.use_binary_protocol, version=version, + agents=self.options.agents) params = HttpUtils.get_query_params(self.options) diff --git a/core/src/ably_pubsub/core/http/httputils.py b/core/src/ably_pubsub/core/http/httputils.py index df96e71e..6dff862b 100644 --- a/core/src/ably_pubsub/core/http/httputils.py +++ b/core/src/ably_pubsub/core/http/httputils.py @@ -4,6 +4,24 @@ import ably_pubsub.core +# The agent identifier for this library, sent with its version on every HTTP +# request and websocket handshake. Registered in the ably-common agents +# registry; renaming it partitions this SDK's traffic from its own history, so +# it changes only alongside a registry entry. +LIBRARY_AGENT_IDENTIFIER = 'ably-pubsub-python' + +RUNTIME_AGENT_IDENTIFIER = 'python' + + +def _render_agents(agents): + """Render an ``{identifier: version}`` mapping as Ably-Agent tokens. + + A ``None`` version renders as a bare flag, matching how the agents registry + records entries that carry no version of their own (`browser`, and the + side-declaring entries such as `ably-pubsub-server`). + """ + return [name if version is None else f'{name}/{version}' for name, version in agents.items()] + class HttpUtils: default_format = "json" @@ -16,8 +34,8 @@ class HttpUtils: } @staticmethod - def default_get_headers(binary=False, version=None): - headers = HttpUtils.default_headers(version=version) + def default_get_headers(binary=False, version=None, agents=None): + headers = HttpUtils.default_headers(version=version, agents=agents) if binary: headers["Accept"] = HttpUtils.mime_types['binary'] else: @@ -25,8 +43,8 @@ def default_get_headers(binary=False, version=None): return headers @staticmethod - def default_post_headers(binary=False, version=None): - headers = HttpUtils.default_get_headers(binary=binary, version=version) + def default_post_headers(binary=False, version=None, agents=None): + headers = HttpUtils.default_get_headers(binary=binary, version=version, agents=agents) headers["Content-Type"] = headers["Accept"] return headers @@ -37,12 +55,17 @@ def get_host_header(host): } @staticmethod - def default_headers(version=None): + def default_headers(version=None, agents=None): if version is None: version = ably_pubsub.core.api_version + tokens = [ + f'{LIBRARY_AGENT_IDENTIFIER}/{ably_pubsub.core.lib_version}', + f'{RUNTIME_AGENT_IDENTIFIER}/{platform.python_version()}', + ] + tokens.extend(_render_agents(agents or {})) return { "X-Ably-Version": version, - "Ably-Agent": f'ably-python/{ably_pubsub.core.lib_version} python/{platform.python_version()}' + "Ably-Agent": ' '.join(tokens), } @staticmethod diff --git a/core/src/ably_pubsub/core/transport/websockettransport.py b/core/src/ably_pubsub/core/transport/websockettransport.py index f2db328a..3bd5968f 100644 --- a/core/src/ably_pubsub/core/transport/websockettransport.py +++ b/core/src/ably_pubsub/core/transport/websockettransport.py @@ -78,7 +78,7 @@ def __init__(self, connection_manager: ConnectionManager, host: str, params: dic super().__init__() def connect(self): - headers = HttpUtils.default_headers() + headers = HttpUtils.default_headers(agents=self.options.agents) query_params = urllib.parse.urlencode(self.params) scheme = 'wss' if self.options.tls else 'ws' ws_url = f'{scheme}://{self.host}?{query_params}' diff --git a/core/src/ably_pubsub/core/types/options.py b/core/src/ably_pubsub/core/types/options.py index 1fc264b6..30e13d35 100644 --- a/core/src/ably_pubsub/core/types/options.py +++ b/core/src/ably_pubsub/core/types/options.py @@ -34,7 +34,7 @@ def __init__(self, client_id=None, log_level=0, tls=True, rest_host=None, realti idempotent_rest_publishing=None, loop=None, auto_connect=True, suspended_retry_timeout=None, connectivity_check_url=None, channel_retry_timeout=Defaults.channel_retry_timeout, add_request_ids=False, - vcdiff_decoder: VCDiffDecoder = None, transport_params=None, **kwargs): + vcdiff_decoder: VCDiffDecoder = None, transport_params=None, agents=None, **kwargs): super().__init__(**kwargs) @@ -129,6 +129,7 @@ def __init__(self, client_id=None, log_level=0, tls=True, rest_host=None, realti self.__add_request_ids = add_request_ids self.__vcdiff_decoder = vcdiff_decoder self.__transport_params = transport_params or {} + self.__agents = dict(agents) if agents else {} self.__hosts = self.__get_hosts() @property @@ -306,6 +307,18 @@ def vcdiff_decoder(self): def transport_params(self): return self.__transport_params + @property + def agents(self): + """Additional entries for the ``Ably-Agent`` header, as ``{name: version}``. + + A ``None`` version renders the entry as a bare flag, with no ``/version`` + suffix. Ably's own library and runtime entries are always sent and are + not configurable here; this is for the packages layered on top of the + core -- the side-declaring entry the server package stamps, or a + higher-level SDK's own attribution. + """ + return self.__agents + def __get_hosts(self): """ Return the list of hosts as they should be tried. First comes the main diff --git a/test/ably/rest/resthttp_test.py b/test/ably/rest/resthttp_test.py index ab114b9d..f339790e 100644 --- a/test/ably/rest/resthttp_test.py +++ b/test/ably/rest/resthttp_test.py @@ -184,7 +184,7 @@ async def test_request_headers(self): # Agent assert 'Ably-Agent' in r.request.headers - expr = r"^ably-python\/\d+.\d+.\d+(-beta\.\d+)? python\/\d.\d+.\d+$" + expr = r"^ably-pubsub-python\/\d+.\d+.\d+(-beta\.\d+)? python\/\d.\d+.\d+$" assert re.search(expr, r.request.headers['Ably-Agent']) await ably.close() From 9f7a8fc8b4cc56eb1dfaa46a3774d2c8236f1d51 Mon Sep 17 00:00:00 2001 From: umair Date: Thu, 3 Sep 2026 13:22:56 +0100 Subject: [PATCH 4/7] Add the ably-pubsub-server factory doors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The entry points of the server distribution. `create_http_client()` and `create_realtime_client()` in `ably_pubsub.server`, and `create_http_client()` in `ably_pubsub.server.sync`, each take exactly what the constructor they wrap takes today — the same keyword arguments, the same key/token/token_details disambiguation — so nothing is lost in translation and the migration is a call rewrite, not a re-read of the options documentation. What the factories add is the agent entry `ably-pubsub-server`, stamped without a version because the versioned `ably-pubsub-python` entry sits beside it. The `-server` suffix is load-bearing: realtime grants the MAU server exemption by matching an agent entry ending in it. There is a comment saying so where the constant is defined, as ably-js and ably-ruby have. A caller's own `agents` entries are preserved so that an SDK layered on top of this package keeps its attribution, but the side entry is merged last and wins a collision on its own identifier: which side the package declares is the package's to state, not the caller's to redefine. The types consumers need are enumerated re-exports, not a star import, so that `ably_pubsub.core` — an internal package with no API stability promise — never has to be imported directly. The sync door is hand-written against the generated `ably_pubsub.core.sync`; there is no synchronous realtime client. Co-Authored-By: Claude Opus 5 --- server/src/ably_pubsub/server/__init__.py | 127 ++++++++++++++++++++++ server/src/ably_pubsub/server/sync.py | 78 +++++++++++++ 2 files changed, 205 insertions(+) create mode 100644 server/src/ably_pubsub/server/__init__.py create mode 100644 server/src/ably_pubsub/server/sync.py diff --git a/server/src/ably_pubsub/server/__init__.py b/server/src/ably_pubsub/server/__init__.py new file mode 100644 index 00000000..2aa0d56c --- /dev/null +++ b/server/src/ably_pubsub/server/__init__.py @@ -0,0 +1,127 @@ +"""The Ably Pub/Sub SDK for servers. + +Servers are trusted environments which typically authenticate with an API key, +and whose connections are exempt from monthly-active-user counting. This package +names that side, so the client an application should reach for is the one whose +package matches where it runs. + +Use `create_http_client()` for publish, history, presence reads, stats and token +issuing over HTTP, and `create_realtime_client()` when the server also needs to +subscribe to channels or enter presence over a persistent connection. These +factories are the entry points of the `ably-pubsub-server` distribution; the +types they work with are re-exported here so that `ably_pubsub.core`, which is +an internal implementation package, never needs to be imported directly. +""" + +import asyncio +from typing import Optional + +from ably_pubsub.core import ( + AblyAuthException, + AblyException, + AblyRealtime, + AblyRest, + AblyVCDiffDecoder, + Annotation, + AnnotationAction, + Auth, + Capability, + ChannelMode, + ChannelOptions, + CipherParams, + DeviceDetails, + IncompatibleClientIdException, + MessageAction, + MessageOperation, + MessageVersion, + Options, + PublishResult, + Push, + PushChannelSubscription, + UpdateDeleteResult, + VCDiffDecoder, +) +from ably_pubsub.core.types.tokendetails import TokenDetails + +__version__ = '4.0.0' + +# The agent identifier declaring the server side. +# +# The `-server` suffix is load-bearing, not cosmetic. On API-key auth the realtime +# system grants the MAU server exemption by matching an agent entry ending in +# `-server`, and an identifier that is not yet in the ably-common registry is +# classified by that suffix alone. Renaming it without preserving the suffix +# silently reclassifies every client this package constructs. +# +# The entry is stamped WITHOUT a version, matching its registration in the +# ably-common agents registry (a pure flag, like `browser`): under lockstep +# versioning a version here always duplicates the ably-pubsub-python entry beside +# it, which keeps carrying identity, version and support status. Wire shape: +# ably-pubsub-python/4.0.0 python/3.12.1 ably-pubsub-server +SERVER_AGENT_IDENTIFIER = 'ably-pubsub-server' + + +def _agents_with_side(agents: Optional[dict]) -> dict: + """Return the caller's agent entries carrying this package's side entry. + + The caller's own entries are preserved, so an SDK layered on top of this + package keeps its attribution. The side entry is merged last and so wins a + collision on its own identifier: which side the package declares is the + package's to state, not the caller's to redefine. + """ + return {**(agents or {}), SERVER_AGENT_IDENTIFIER: None} + + +def create_http_client(key: Optional[str] = None, token: Optional[str] = None, + token_details: Optional[TokenDetails] = None, **options) -> AblyRest: + """Create a server Pub/Sub client that operates entirely over HTTP. + + Publishing, history, presence reads, stats and token issuing, with no + persistent connection. Takes the same arguments as the underlying client + constructor, and behaves identically to it. + """ + return AblyRest(key=key, token=token, token_details=token_details, + agents=_agents_with_side(options.pop('agents', None)), **options) + + +def create_realtime_client(key: Optional[str] = None, loop: Optional[asyncio.AbstractEventLoop] = None, + **options) -> AblyRealtime: + """Create a server Pub/Sub client with a persistent realtime connection. + + Everything the HTTP client does, plus subscribing to channels and entering + presence. Takes the same arguments as the underlying client constructor, and + behaves identically to it. + """ + return AblyRealtime(key=key, loop=loop, + agents=_agents_with_side(options.pop('agents', None)), **options) + + +__all__ = [ + 'AblyAuthException', + 'AblyException', + 'AblyRealtime', + 'AblyRest', + 'AblyVCDiffDecoder', + 'Annotation', + 'AnnotationAction', + 'Auth', + 'Capability', + 'ChannelMode', + 'ChannelOptions', + 'CipherParams', + 'DeviceDetails', + 'IncompatibleClientIdException', + 'MessageAction', + 'MessageOperation', + 'MessageVersion', + 'Options', + 'PublishResult', + 'Push', + 'PushChannelSubscription', + 'SERVER_AGENT_IDENTIFIER', + 'TokenDetails', + 'UpdateDeleteResult', + 'VCDiffDecoder', + 'create_http_client', + 'create_realtime_client', +] diff --git a/server/src/ably_pubsub/server/sync.py b/server/src/ably_pubsub/server/sync.py new file mode 100644 index 00000000..dd927bf5 --- /dev/null +++ b/server/src/ably_pubsub/server/sync.py @@ -0,0 +1,78 @@ +"""The synchronous flavour of the Ably Pub/Sub SDK for servers. + +Offers the HTTP client without an event loop. There is no synchronous realtime +client, so a server that needs to subscribe should use +`ably_pubsub.server.create_realtime_client()` instead. + +Hand-written rather than generated: the code generator that produces +`ably_pubsub.core.sync` runs over the core distribution only. +""" + +from typing import Optional + +from ably_pubsub.core.sync import ( + AblyAuthException, + AblyException, + AblyRestSync, + AblyVCDiffDecoder, + Annotation, + AnnotationAction, + AuthSync, + Capability, + ChannelMode, + ChannelOptions, + CipherParams, + DeviceDetails, + IncompatibleClientIdException, + MessageAction, + MessageOperation, + MessageVersion, + Options, + PublishResult, + PushChannelSubscription, + PushSync, + UpdateDeleteResult, + VCDiffDecoder, +) +from ably_pubsub.core.sync.types.tokendetails import TokenDetails +from ably_pubsub.server import SERVER_AGENT_IDENTIFIER, _agents_with_side + + +def create_http_client(key: Optional[str] = None, token: Optional[str] = None, + token_details: Optional[TokenDetails] = None, **options) -> AblyRestSync: + """Create a synchronous server Pub/Sub client that operates entirely over HTTP. + + Takes the same arguments as the underlying client constructor, and behaves + identically to it. + """ + return AblyRestSync(key=key, token=token, token_details=token_details, + agents=_agents_with_side(options.pop('agents', None)), **options) + + +__all__ = [ + 'AblyAuthException', + 'AblyException', + 'AblyRestSync', + 'AblyVCDiffDecoder', + 'Annotation', + 'AnnotationAction', + 'AuthSync', + 'Capability', + 'ChannelMode', + 'ChannelOptions', + 'CipherParams', + 'DeviceDetails', + 'IncompatibleClientIdException', + 'MessageAction', + 'MessageOperation', + 'MessageVersion', + 'Options', + 'PublishResult', + 'PushChannelSubscription', + 'PushSync', + 'SERVER_AGENT_IDENTIFIER', + 'TokenDetails', + 'UpdateDeleteResult', + 'VCDiffDecoder', + 'create_http_client', +] From e6929c0cd53b7a24f4eab24523fb524ecc1a0cae Mon Sep 17 00:00:00 2001 From: umair Date: Thu, 3 Sep 2026 13:27:16 +0100 Subject: [PATCH 5/7] Test the factory doors, the agent header and the packaging invariants MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three new unit test modules, none of which need the network. `pubsub_server_test.py` covers the doors — the clients they return, the arguments they pass through — and then the header they exist to stamp. The agent assertions are written to fail loudly, because this is what billing reads: the whole `Ably-Agent` value is matched against an anchored pattern rather than searched for a substring, `ably-pubsub-server/` in its versioned form is asserted absent (the `name/None` regression ably-js#2297 guards against), and the websocket case asserts on the headers the transport hands to `websockets.connect` rather than on the seam that produced them. A caller's own agents survive; a caller cannot claim the side entry; a bare core client declares no side at all. `pubsub_packaging_test.py` asserts what a release would otherwise be the first thing to check: no `ably_pubsub/__init__.py` in either source tree, the version sites and the server's core pin all agreeing, every extra forwarding at that same pin, and — by building both wheels — that their file lists do not overlap and that the core carries the generated `ably_pubsub/core/sync/`. `pubsub_reexport_test.py` keeps the server's enumerated re-exports level with the core's public surface, so a type added to the core cannot end up reachable only through the internal package. Co-Authored-By: Claude Opus 5 --- test/unit/pubsub_packaging_test.py | 105 ++++++++++++++++++++ test/unit/pubsub_reexport_test.py | 34 +++++++ test/unit/pubsub_server_test.py | 153 +++++++++++++++++++++++++++++ 3 files changed, 292 insertions(+) create mode 100644 test/unit/pubsub_packaging_test.py create mode 100644 test/unit/pubsub_reexport_test.py create mode 100644 test/unit/pubsub_server_test.py diff --git a/test/unit/pubsub_packaging_test.py b/test/unit/pubsub_packaging_test.py new file mode 100644 index 00000000..b71aa961 --- /dev/null +++ b/test/unit/pubsub_packaging_test.py @@ -0,0 +1,105 @@ +"""Invariants of the two distributions built from this repository. + +`ably_pubsub` is assembled at install time out of `ably-pubsub-core` and +`ably-pubsub-server`. That only holds together if the namespace stays a PEP 420 +namespace, if the two wheels never claim the same files, and if the versions +stay in lockstep with the server's exact pin on the core. None of those fail +anywhere closer to the mistake than a release, so they are asserted here. +""" + +import re +import shutil +import subprocess +import zipfile +from pathlib import Path + +import pytest + +import ably_pubsub.core +import ably_pubsub.server + +REPO_ROOT = Path(__file__).resolve().parents[2] +CORE_SRC = REPO_ROOT / 'core' / 'src' / 'ably_pubsub' +SERVER_SRC = REPO_ROOT / 'server' / 'src' / 'ably_pubsub' + + +def pyproject_field(path, field): + # Read rather than parse: tomllib only arrived in Python 3.11, and these are + # double-quoted scalars at the top of the [project] table. + match = re.search(rf'^{field} = "([^"]+)"', path.read_text(), re.MULTILINE) + assert match, f'no {field} in {path}' + return match.group(1) + + +# PEP 420: an __init__.py here would belong to whichever distribution shipped it, +# so the other one's subpackage would vanish when that distribution was removed +@pytest.mark.parametrize('src', [CORE_SRC, SERVER_SRC], ids=['core', 'server']) +def test_ably_pubsub_is_a_namespace_directory(src): + assert src.is_dir() + assert not (src / '__init__.py').exists() + + +def test_each_distribution_ships_only_its_own_subpackage(): + assert {p.name for p in CORE_SRC.iterdir()} == {'core'} + assert {p.name for p in SERVER_SRC.iterdir()} == {'server'} + + +def test_the_three_version_sites_agree(): + core_version = pyproject_field(REPO_ROOT / 'core' / 'pyproject.toml', 'version') + server_version = pyproject_field(REPO_ROOT / 'server' / 'pyproject.toml', 'version') + assert core_version == ably_pubsub.core.lib_version + assert server_version == ably_pubsub.core.lib_version + assert ably_pubsub.server.__version__ == ably_pubsub.core.lib_version + + +def test_the_server_pins_the_core_exactly_including_every_extra(): + pyproject = (REPO_ROOT / 'server' / 'pyproject.toml').read_text() + pins = set(re.findall(r'"ably-pubsub-core(?:\[[\w,]+\])?==([^"]+)"', pyproject)) + assert pins == {ably_pubsub.core.lib_version} + + +@pytest.mark.parametrize('extra', ['crypto', 'vcdiff', 'oldcrypto']) +def test_the_server_forwards_each_core_extra(extra): + pyproject = (REPO_ROOT / 'server' / 'pyproject.toml').read_text() + assert f'"ably-pubsub-core[{extra}]=={ably_pubsub.core.lib_version}"' in pyproject + + +def test_the_server_re_exports_everything_it_declares_public(): + missing = [name for name in ably_pubsub.server.__all__ if not hasattr(ably_pubsub.server, name)] + assert missing == [] + + +def test_the_server_declares_everything_it_re_exports(): + """Nothing pulled out of the core is public by accident and undocumented.""" + from_the_core = { + name for name, value in vars(ably_pubsub.server).items() + if not name.startswith('_') and name[0].isupper() + and getattr(value, '__module__', '').startswith('ably_pubsub.') + } + assert from_the_core + assert from_the_core <= set(ably_pubsub.server.__all__) + + +@pytest.mark.timeout(300) +@pytest.mark.skipif(shutil.which('uv') is None, reason='needs uv to build the distributions') +def test_the_two_wheels_do_not_overlap(tmp_path): + for package in ('ably-pubsub-core', 'ably-pubsub-server'): + subprocess.run( + ['uv', 'build', '--package', package, '--wheel', '--out-dir', str(tmp_path)], + cwd=REPO_ROOT, check=True, capture_output=True) + + wheels = {} + for wheel in tmp_path.glob('*.whl'): + with zipfile.ZipFile(wheel) as z: + wheels[wheel.name.split('-')[0]] = set(z.namelist()) + + assert set(wheels) == {'ably_pubsub_core', 'ably_pubsub_server'} + core, server = wheels['ably_pubsub_core'], wheels['ably_pubsub_server'] + + assert core & server == set() + # The generated sync flavour is not in version control, so a build that + # forgot to run unasync first would otherwise publish silently + assert any(name.startswith('ably_pubsub/core/sync/') for name in core) + assert 'ably_pubsub/__init__.py' not in core | server + assert all(name.startswith(('ably_pubsub/core/', 'ably_pubsub_core-')) for name in core) + assert all(name.startswith(('ably_pubsub/server/', 'ably_pubsub_server-')) for name in server) diff --git a/test/unit/pubsub_reexport_test.py b/test/unit/pubsub_reexport_test.py new file mode 100644 index 00000000..94b45491 --- /dev/null +++ b/test/unit/pubsub_reexport_test.py @@ -0,0 +1,34 @@ +"""The server package re-exports the core's public surface. + +`ably_pubsub.core` is an internal implementation package: consumers are meant to +reach only for `ably_pubsub.server`. So every type the core declares public has +to reach the server package too, or it is unreachable by supported means. +Trimming the surface to what a server actually needs is a later change (091d); +until then, a name that reaches the core and not the server is an omission, and +this catches it. +""" + +import ably_pubsub.core +import ably_pubsub.core.sync +import ably_pubsub.server +from ably_pubsub.server import sync as server_sync + +# ably_pubsub.core.sync is generated from ably_pubsub.core by unasync, so it +# carries a realtime client with the awaits stripped out of code that still +# calls asyncio. That is an artefact of the generation rather than a usable +# client — nothing tests it, and the sync entry point deliberately offers the +# HTTP client only. +SYNC_ONLY_BY_GENERATION = {'AblyRealtime'} + + +def exported_types(module): + """The classes a package offers, which is all the core's __init__ exports.""" + return {name for name in dir(module) if not name.startswith('_') and name[0].isupper()} + + +def test_the_server_re_exports_the_core_surface(): + assert exported_types(ably_pubsub.core) <= set(ably_pubsub.server.__all__) + + +def test_the_sync_door_re_exports_the_sync_core_surface(): + assert exported_types(ably_pubsub.core.sync) - SYNC_ONLY_BY_GENERATION <= set(server_sync.__all__) diff --git a/test/unit/pubsub_server_test.py b/test/unit/pubsub_server_test.py new file mode 100644 index 00000000..e750549b --- /dev/null +++ b/test/unit/pubsub_server_test.py @@ -0,0 +1,153 @@ +"""The `ably_pubsub.server` factory doors. + +The doors are the entry points of the server distribution: they construct the +core's clients unchanged, and they stamp the agent entry that declares the +server side. The header assertions here are what billing reads, so they are +written to fail loudly rather than to be forgiving. +""" + +import re + +import httpx +import pytest +import respx +from mock import MagicMock, patch +from websockets.exceptions import WebSocketException + +import ably_pubsub.core +from ably_pubsub.core import AblyRealtime, AblyRest +from ably_pubsub.core.sync import AblyRestSync +from ably_pubsub.core.transport.websockettransport import WebSocketTransport +from ably_pubsub.core.util.exceptions import AblyException +from ably_pubsub.server import ( + SERVER_AGENT_IDENTIFIER, + create_http_client, + create_realtime_client, +) +from ably_pubsub.server import sync as server_sync + +# The versionless side flag comes last, after the library and runtime entries. +# `ably-pubsub-server/` is the regression ably-js#2297 guards against: +# a `name/None` rendering would send a version the registry does not define. +SERVER_AGENT = re.compile(r'^ably-pubsub-python/\d+\.\d+\.\d+(\S*)? python/\S+ ably-pubsub-server$') + +TEST_KEY = 'name:secret' + + +def assert_declares_the_server_side(agent): + assert SERVER_AGENT.match(agent), agent + assert f'{SERVER_AGENT_IDENTIFIER}/' not in agent, agent + + +async def agent_header_of(client): + """The Ably-Agent an HTTP client puts on the wire.""" + with respx.mock: + route = respx.get(url__regex=r'.*/time').mock( + return_value=httpx.Response(200, json=[1234567890000])) + await client.time() + return route.calls.last.request.headers['Ably-Agent'] + + +def sync_agent_header_of(client): + with respx.mock: + route = respx.get(url__regex=r'.*/time').mock( + return_value=httpx.Response(200, json=[1234567890000])) + client.time() + return route.calls.last.request.headers['Ably-Agent'] + + +class TestFactories: + """The doors return the core's clients, and pass everything through.""" + + def test_clients_are_the_core_clients(self): + assert isinstance(create_http_client(token='foo'), AblyRest) + assert isinstance(create_realtime_client(token='foo', auto_connect=False), AblyRealtime) + assert isinstance(server_sync.create_http_client(token='foo'), AblyRestSync) + + def test_the_version_is_the_core_version(self): + assert ably_pubsub.server.__version__ == ably_pubsub.core.lib_version + + def test_options_are_passed_through(self): + client = create_http_client(key=TEST_KEY, client_id='me', tls=False) + assert client.options.key_name == 'name' + assert client.options.client_id == 'me' + assert client.options.tls is False + + def test_realtime_options_are_passed_through(self): + client = create_realtime_client(key=TEST_KEY, client_id='me', auto_connect=False) + assert client.options.key_name == 'name' + assert client.options.client_id == 'me' + + def test_sync_options_are_passed_through(self): + client = server_sync.create_http_client(key=TEST_KEY, client_id='me', tls=False) + assert client.options.key_name == 'name' + assert client.options.client_id == 'me' + assert client.options.tls is False + + def test_the_key_can_be_positional_as_on_the_constructor(self): + assert create_http_client(TEST_KEY).options.key_name == 'name' + assert create_realtime_client(TEST_KEY, auto_connect=False).options.key_name == 'name' + assert server_sync.create_http_client(TEST_KEY).options.key_name == 'name' + + def test_token_auth_is_passed_through(self): + assert create_http_client(token='foo').options.auth_token == 'foo' + + def test_authentication_is_still_required(self): + with pytest.raises(ValueError): + create_http_client() + + def test_everything_declared_public_is_importable(self): + for module in (ably_pubsub.server, server_sync): + missing = [name for name in module.__all__ if not hasattr(module, name)] + assert missing == [] + + +class TestAgentHeader: + + async def test_the_http_door_declares_the_server_side(self): + client = create_http_client(TEST_KEY) + assert_declares_the_server_side(await agent_header_of(client)) + await client.close() + + def test_the_sync_http_door_declares_the_server_side(self): + client = server_sync.create_http_client(TEST_KEY) + assert_declares_the_server_side(sync_agent_header_of(client)) + client.close() + + async def test_the_realtime_door_declares_the_server_side_on_the_handshake(self): + client = create_realtime_client(TEST_KEY, auto_connect=False) + connect = MagicMock(side_effect=WebSocketException('not connecting in a unit test')) + with patch('ably_pubsub.core.transport.websockettransport.ws_connect', connect): + transport = WebSocketTransport(client.connection.connection_manager, 'realtime.example', {}) + transport.connect() + # The connection cannot succeed here; what matters is the headers it + # handed to websockets before failing. + with pytest.raises(AblyException): + await transport.ws_connect_task + headers = connect.call_args.kwargs['additional_headers'] + assert_declares_the_server_side(headers['Ably-Agent']) + await client.close() + + async def test_the_core_client_alone_declares_no_side(self): + client = AblyRest(TEST_KEY) + agent = await agent_header_of(client) + assert re.match(r'^ably-pubsub-python/\d+\.\d+\.\d+(\S*)? python/\S+$', agent), agent + assert SERVER_AGENT_IDENTIFIER not in agent + await client.close() + + async def test_caller_supplied_agents_survive(self): + client = create_http_client(TEST_KEY, agents={'my-sdk': '1.0'}) + agent = await agent_header_of(client) + assert 'my-sdk/1.0' in agent + assert agent.endswith(f' {SERVER_AGENT_IDENTIFIER}') + await client.close() + + async def test_the_side_entry_cannot_be_overridden_by_the_caller(self): + client = create_http_client(TEST_KEY, agents={SERVER_AGENT_IDENTIFIER: 'x'}) + assert_declares_the_server_side(await agent_header_of(client)) + await client.close() + + def test_a_versionless_agent_renders_as_a_bare_flag(self): + from ably_pubsub.core.http.httputils import HttpUtils + agent = HttpUtils.default_headers(agents={'flag': None, 'versioned': '1.2'})['Ably-Agent'] + assert agent.endswith('flag versioned/1.2') From 15e6d93f710453e328b6ff34cb646a36ee308819 Mon Sep 17 00:00:00 2001 From: umair Date: Thu, 3 Sep 2026 13:27:29 +0100 Subject: [PATCH 6/7] Point CI at the workspace and check the built distributions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `uv sync` on the workspace root installs the dev dependency group, which pulls both members in editable with the core's crypto and vcdiff extras — so one command replaces the old `--extra` pair in check.yml and lint.yml. Both workflows also run on pushes to integration/v4, the branch this work lands on. check.yml gains a step that builds both distributions and asserts the two invariants a namespace mistake would otherwise hide until after publish: the core artifacts contain the generated `ably_pubsub/core/sync/`, and neither wheel contains `ably_pubsub/__init__.py`. This is the check release.yml used to carry, moved to where it runs on every pull request rather than once at a tag. release.yml is otherwise left alone, with a note saying so: reworking it into a lockstep release of the two distributions is the next PR on this branch. The release skill's version-site list becomes the four sites this repo now has, including the server's exact pin on the core, and its changelog links stop pointing at ably-java. Co-Authored-By: Claude Opus 5 --- .claude/skills/release/SKILL.md | 34 ++++++++++++++++++++------------- .github/workflows/check.yml | 32 ++++++++++++++++++++++++++++++- .github/workflows/lint.yml | 3 ++- .github/workflows/release.yml | 28 +++++---------------------- .gitignore | 1 + 5 files changed, 60 insertions(+), 38 deletions(-) diff --git a/.claude/skills/release/SKILL.md b/.claude/skills/release/SKILL.md index 635f9bf8..5a7f67cb 100644 --- a/.claude/skills/release/SKILL.md +++ b/.claude/skills/release/SKILL.md @@ -3,7 +3,9 @@ description: "Create a release branch, bump version, and update CHANGELOG. Usage allowed-tools: Bash, Read, Edit, Write --- -Read the current version from `pyproject.toml` (the `version` property). +Read the current version from `core/pyproject.toml` (the `version` property). Both +distributions built from this repo are released in lockstep, so there is one +version for all of the sites below and they must never diverge. The bump type is: $ARGUMENTS @@ -15,12 +17,18 @@ Compute the new version by incrementing the appropriate component of the current Then perform these steps in order: 1. Run `git checkout -b release/NEW_VERSION` -2. Replace `OLD_VERSION` with `NEW_VERSION` in all of the following files: - - `pyproject.toml` — the `version` property - - `ably/__init__.py` — lib_version value - 3.Run `uv sync` to update `uv.lock` file -4. Commit all files together with message: `chore: bump version to NEW_VERSION` -3. Fetch merged PRs since the last release tag using: +2. Replace `OLD_VERSION` with `NEW_VERSION` in all of the following places: + - `core/pyproject.toml` — the `version` property + - `server/pyproject.toml` — the `version` property, **and** every + `ably-pubsub-core==OLD_VERSION` pin in `[project.dependencies]` and + `[project.optional-dependencies]` + - `core/src/ably_pubsub/core/__init__.py` — `lib_version` value + - `server/src/ably_pubsub/server/__init__.py` — `__version__` value +3. Run `uv sync` to update the `uv.lock` file +4. Run `uv run pytest test/unit/pubsub_packaging_test.py` — it asserts that + every one of those sites agrees +5. Commit all files together with message: `chore: bump version to NEW_VERSION` +6. Fetch merged PRs since the last release tag using: ``` gh pr list --state merged --base main --json number,title,mergedAt --limit 200 ``` @@ -30,23 +38,23 @@ Then perform these steps in order: ``` Filter the PRs to only those merged after that tag date. Format each as: ``` - - Short, one sentence summary from PR title and description [#NUMBER](https://github.com/ably/ably-java/pull/NUMBER) + - Short, one sentence summary from PR title and description [#NUMBER](https://github.com/ably/ably-python/pull/NUMBER) ``` If the tag doesn't exist or there are no merged PRs, use a single `-` placeholder bullet instead. -4. In `CHANGELOG.md`, insert the following block immediately after the `# Change Log` heading (and its trailing blank line), before the first existing `## [` version entry: +7. In `CHANGELOG.md`, insert the following block immediately after the `# Change Log` heading (and its trailing blank line), before the first existing `## [` version entry: ``` -## [NEW_VERSION](https://github.com/ably/ably-java/tree/vNEW_VERSION) +## [NEW_VERSION](https://github.com/ably/ably-python/tree/vNEW_VERSION) -[Full Changelog](https://github.com/ably/ably-java/compare/vOLD_VERSION...vNEW_VERSION) +[Full Changelog](https://github.com/ably/ably-python/compare/vOLD_VERSION...vNEW_VERSION) ### What's Changed -BULLETS_FROM_STEP_3 +BULLETS_FROM_STEP_6 ``` -5. Commit `CHANGELOG.md` with message: `docs: update CHANGELOG for NEW_VERSION release` +8. Commit `CHANGELOG.md` with message: `docs: update CHANGELOG for NEW_VERSION release` After completing all steps, show the user a summary of what was done. If PRs were found, list them. If the placeholder `-` was used instead, remind them to fill in the `### What's Changed` bullet points in `CHANGELOG.md` before merging. diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index 42f6972d..0d5bc7e4 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -10,6 +10,7 @@ on: push: branches: - main + - integration/v4 permissions: {} @@ -46,8 +47,37 @@ jobs: key: venv-${{ runner.os }}-${{ matrix.python-version }}-${{ hashFiles('uv.lock') }} - name: Install dependencies - run: uv sync --extra crypto --extra dev + # The dev dependency group installs both workspace members editable, + # with the core's crypto and vcdiff extras. + run: uv sync - name: Generate rest sync code and tests run: uv run unasync - name: Test with pytest run: uv run pytest --verbose --tb=short --capture=no + + # A namespace mistake would otherwise surface only after publish: an + # ably_pubsub/__init__.py in either wheel makes the two distributions + # fight over the same directory, and a core wheel without the generated + # sync flavour is a build that skipped unasync. + - name: Check the built distributions + run: | + uv build --package ably-pubsub-core --out-dir dist-check + uv build --package ably-pubsub-server --out-dir dist-check + CORE_WHEEL=$(ls dist-check/ably_pubsub_core-*.whl) + if ! unzip -l "$CORE_WHEEL" | grep -q "ably_pubsub/core/sync/"; then + unzip -l "$CORE_WHEEL" + echo "::error::ably_pubsub/core/sync/ not found in the core wheel" + exit 1 + fi + for WHEEL in dist-check/*.whl; do + if unzip -l "$WHEEL" | grep -q "ably_pubsub/__init__.py"; then + echo "::error::$WHEEL ships ably_pubsub/__init__.py; the namespace must stay PEP 420" + exit 1 + fi + done + CORE_TARBALL=$(ls dist-check/ably_pubsub_core-*.tar.gz) + if ! tar -tzf "$CORE_TARBALL" | grep -q "ably_pubsub/core/sync/"; then + tar -tzf "$CORE_TARBALL" + echo "::error::ably_pubsub/core/sync/ not found in the core sdist" + exit 1 + fi diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index d1027713..568a3199 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -5,6 +5,7 @@ on: push: branches: - main + - integration/v4 permissions: {} @@ -37,6 +38,6 @@ jobs: key: venv-${{ runner.os }}-3.9-${{ hashFiles('uv.lock') }} - name: Install dependencies - run: uv sync --extra dev + run: uv sync - name: Lint with ruff run: uv run ruff check diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 8f47e6b0..fa387922 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,3 +1,8 @@ +# TODO: this workflow still builds and publishes the single `ably` distribution +# and does not work against the two-distribution workspace. Reworking it into a +# lockstep release of ably-pubsub-core and ably-pubsub-server is the next PR on +# the integration branch (plan step 15). The artifact checks it used to carry +# have moved to check.yml, where they run on every PR. name: Publish Python distribution to PyPI on: @@ -42,29 +47,6 @@ jobs: with: name: python-package-distributions path: dist/ - - name: Check that wheel and tarball contains ably/sync/ - run: | - # Check wheel - WHEEL=$(ls dist/*.whl | head -n 1) - echo "Checking wheel: $WHEEL" - if unzip -l "$WHEEL" | grep -q "ably/sync/"; then - echo "✅ Found ably/sync/ in wheel" - else - unzip -l "$WHEEL" - echo "❌ ably/sync/ not found in wheel" - exit 1 - fi - - # Check tarball - TARBALL=$(ls dist/*.tar.gz | head -n 1) - echo "Checking tarball: $TARBALL" - if tar -tzf "$TARBALL" | grep -q "ably/sync/"; then - echo "✅ Found ably/sync/ in tarball" - else - tar -tzf "$TARBALL" - echo "❌ ably/sync/ not found in tarball" - exit 1 - fi publish-to-pypi: name: Publish Python distribution to PyPI diff --git a/.gitignore b/.gitignore index c20685d5..9eedd00c 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,7 @@ *.egg *.egg-info dist +dist-check build eggs parts From c415b95fc65e316c7e970c5d113324588d19953a Mon Sep 17 00:00:00 2001 From: umair Date: Thu, 3 Sep 2026 14:10:57 +0100 Subject: [PATCH 7/7] Re-export the message, presence and token types from ably_pubsub.server MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The docs pass (#686) found the gap: 3.x users deep-imported `Message`, `PresenceMessage` and `TokenRequest` from `ably.types.*`, and after the split the only place those live is `ably_pubsub.core` — which the docs tell people never to import. A type that is not re-exported here is not nameable at all by supported means, which makes type hints and direct construction impossible. Adds the value types a consumer legitimately names — the message, presence, channel-detail, state-change and stats types, the two paginated result containers, and `TokenRequest` — plus the four client-reachable object types (`Channel`, `RealtimeChannel`, `Connection`, `RealtimePresence`) that turn up in annotations. The sync door gets the same, minus the realtime types that have no synchronous counterpart, and with unasync's renames applied (`PaginatedResultSync`, `HttpPaginatedResponseSync`, `ChannelSync`). Deliberately not included: transports, the connection manager, HTTP utilities, encoding buffers and the encode/decode mixins. Those are implementation, and 091d may delete or reshape them. `pubsub_reexport_test.py` now guards the list by name in both flavours, so a future trim of the public surface has to drop a name on purpose rather than by omission. Co-Authored-By: Claude Opus 5 --- server/src/ably_pubsub/server/__init__.py | 43 +++++++++++++++++ server/src/ably_pubsub/server/sync.py | 26 ++++++++++ test/unit/pubsub_reexport_test.py | 59 +++++++++++++++++++++++ 3 files changed, 128 insertions(+) diff --git a/server/src/ably_pubsub/server/__init__.py b/server/src/ably_pubsub/server/__init__.py index 2aa0d56c..03801909 100644 --- a/server/src/ably_pubsub/server/__init__.py +++ b/server/src/ably_pubsub/server/__init__.py @@ -41,7 +41,28 @@ UpdateDeleteResult, VCDiffDecoder, ) +from ably_pubsub.core.http.paginatedresult import HttpPaginatedResponse, PaginatedResult +from ably_pubsub.core.realtime.channel import RealtimeChannel +from ably_pubsub.core.realtime.connection import Connection +from ably_pubsub.core.realtime.presence import RealtimePresence +from ably_pubsub.core.rest.channel import Channel +from ably_pubsub.core.types.channeldetails import ( + ChannelDetails, + ChannelMetrics, + ChannelOccupancy, + ChannelStatus, +) +from ably_pubsub.core.types.channelstate import ChannelState, ChannelStateChange +from ably_pubsub.core.types.connectionstate import ( + ConnectionEvent, + ConnectionState, + ConnectionStateChange, +) +from ably_pubsub.core.types.message import Message, MessageAnnotations +from ably_pubsub.core.types.presence import Presence, PresenceAction, PresenceMessage +from ably_pubsub.core.types.stats import Stats from ably_pubsub.core.types.tokendetails import TokenDetails +from ably_pubsub.core.types.tokenrequest import TokenRequest __version__ = '4.0.0' @@ -106,20 +127,42 @@ def create_realtime_client(key: Optional[str] = None, loop: Optional[asyncio.Abs 'AnnotationAction', 'Auth', 'Capability', + 'Channel', + 'ChannelDetails', + 'ChannelMetrics', 'ChannelMode', + 'ChannelOccupancy', 'ChannelOptions', + 'ChannelState', + 'ChannelStateChange', + 'ChannelStatus', 'CipherParams', + 'Connection', + 'ConnectionEvent', + 'ConnectionState', + 'ConnectionStateChange', 'DeviceDetails', + 'HttpPaginatedResponse', 'IncompatibleClientIdException', + 'Message', 'MessageAction', + 'MessageAnnotations', 'MessageOperation', 'MessageVersion', 'Options', + 'PaginatedResult', + 'Presence', + 'PresenceAction', + 'PresenceMessage', 'PublishResult', 'Push', 'PushChannelSubscription', + 'RealtimeChannel', + 'RealtimePresence', 'SERVER_AGENT_IDENTIFIER', + 'Stats', 'TokenDetails', + 'TokenRequest', 'UpdateDeleteResult', 'VCDiffDecoder', 'create_http_client', diff --git a/server/src/ably_pubsub/server/sync.py b/server/src/ably_pubsub/server/sync.py index dd927bf5..1fabbd13 100644 --- a/server/src/ably_pubsub/server/sync.py +++ b/server/src/ably_pubsub/server/sync.py @@ -34,7 +34,19 @@ UpdateDeleteResult, VCDiffDecoder, ) +from ably_pubsub.core.sync.http.paginatedresult import HttpPaginatedResponseSync, PaginatedResultSync +from ably_pubsub.core.sync.rest.channel import ChannelSync +from ably_pubsub.core.sync.types.channeldetails import ( + ChannelDetails, + ChannelMetrics, + ChannelOccupancy, + ChannelStatus, +) +from ably_pubsub.core.sync.types.message import Message, MessageAnnotations +from ably_pubsub.core.sync.types.presence import Presence, PresenceAction, PresenceMessage +from ably_pubsub.core.sync.types.stats import Stats from ably_pubsub.core.sync.types.tokendetails import TokenDetails +from ably_pubsub.core.sync.types.tokenrequest import TokenRequest from ably_pubsub.server import SERVER_AGENT_IDENTIFIER, _agents_with_side @@ -58,20 +70,34 @@ def create_http_client(key: Optional[str] = None, token: Optional[str] = None, 'AnnotationAction', 'AuthSync', 'Capability', + 'ChannelDetails', + 'ChannelMetrics', 'ChannelMode', + 'ChannelOccupancy', 'ChannelOptions', + 'ChannelStatus', + 'ChannelSync', 'CipherParams', 'DeviceDetails', + 'HttpPaginatedResponseSync', 'IncompatibleClientIdException', + 'Message', 'MessageAction', + 'MessageAnnotations', 'MessageOperation', 'MessageVersion', 'Options', + 'PaginatedResultSync', + 'Presence', + 'PresenceAction', + 'PresenceMessage', 'PublishResult', 'PushChannelSubscription', 'PushSync', 'SERVER_AGENT_IDENTIFIER', + 'Stats', 'TokenDetails', + 'TokenRequest', 'UpdateDeleteResult', 'VCDiffDecoder', 'create_http_client', diff --git a/test/unit/pubsub_reexport_test.py b/test/unit/pubsub_reexport_test.py index 94b45491..8d6ea966 100644 --- a/test/unit/pubsub_reexport_test.py +++ b/test/unit/pubsub_reexport_test.py @@ -32,3 +32,62 @@ def test_the_server_re_exports_the_core_surface(): def test_the_sync_door_re_exports_the_sync_core_surface(): assert exported_types(ably_pubsub.core.sync) - SYNC_ONLY_BY_GENERATION <= set(server_sync.__all__) + + +# 3.x users reached for these under `ably.types.*` and `ably.http.*`, which have no +# supported 4.0 equivalent outside the internal core — so they have to be nameable +# from the server package or they are not nameable at all. Guarding the list keeps +# a future trim of the surface (091d) from dropping one silently. +REACHABLE_BY_A_CONSUMER = { + 'Channel', + 'ChannelDetails', + 'ChannelMetrics', + 'ChannelOccupancy', + 'ChannelState', + 'ChannelStateChange', + 'ChannelStatus', + 'Connection', + 'ConnectionEvent', + 'ConnectionState', + 'ConnectionStateChange', + 'HttpPaginatedResponse', + 'Message', + 'MessageAnnotations', + 'PaginatedResult', + 'Presence', + 'PresenceAction', + 'PresenceMessage', + 'RealtimeChannel', + 'RealtimePresence', + 'Stats', + 'TokenDetails', + 'TokenRequest', +} + +# The sync flavour has no realtime client, so the realtime object and state types +# have no counterpart there; unasync renames the rest. +SYNC_REACHABLE_BY_A_CONSUMER = (REACHABLE_BY_A_CONSUMER - { + 'Channel', + 'ChannelState', + 'ChannelStateChange', + 'Connection', + 'ConnectionEvent', + 'ConnectionState', + 'ConnectionStateChange', + 'HttpPaginatedResponse', + 'PaginatedResult', + 'RealtimeChannel', + 'RealtimePresence', +}) | {'ChannelSync', 'HttpPaginatedResponseSync', 'PaginatedResultSync'} + + +def test_the_types_a_consumer_names_are_reachable_from_the_server_package(): + assert REACHABLE_BY_A_CONSUMER <= set(ably_pubsub.server.__all__) + missing = [name for name in REACHABLE_BY_A_CONSUMER if not hasattr(ably_pubsub.server, name)] + assert missing == [] + + +def test_the_types_a_consumer_names_are_reachable_from_the_sync_door(): + assert SYNC_REACHABLE_BY_A_CONSUMER <= set(server_sync.__all__) + missing = [name for name in SYNC_REACHABLE_BY_A_CONSUMER if not hasattr(server_sync, name)] + assert missing == []