diff --git a/ably/http/http.py b/ably/http/http.py index e47ffb8f..27b60b7d 100644 --- a/ably/http/http.py +++ b/ably/http/http.py @@ -19,7 +19,7 @@ def reauth_if_expired(func): @functools.wraps(func) async def wrapper(rest, *args, **kwargs): - if kwargs.get("skip_auth"): + if kwargs.get('skip_auth'): return await func(rest, *args, **kwargs) # RSA4b1 Detect expired token to avoid round-trip request @@ -44,8 +44,9 @@ async def wrapper(rest, *args, **kwargs): class Request: - def __init__(self, method='GET', url='/', version=None, headers=None, body=None, - skip_auth=False, raise_on_error=True): + def __init__( + self, method='GET', url='/', version=None, headers=None, body=None, skip_auth=False, raise_on_error=True + ): self.__method = method self.__headers = headers or {} self.__body = body @@ -56,8 +57,9 @@ def __init__(self, method='GET', url='/', version=None, headers=None, body=None, def with_relative_url(self, relative_url): url = urljoin(self.url, relative_url) - return Request(self.method, url, self.version, self.headers, self.body, - self.skip_auth, self.raise_on_error) + return Request( + self.method, url, self.version, self.headers, self.body, self.skip_auth, self.raise_on_error + ) @property def method(self): @@ -104,7 +106,7 @@ def to_native(self): elif content_type.startswith('application/json'): return self.__response.json() - raise ValueError("Unsupported content type") + raise ValueError('Unsupported content type') @property def response(self): @@ -157,8 +159,17 @@ def get_rest_hosts(self): return hosts @reauth_if_expired - async def make_request(self, method, path, version=None, headers=None, body=None, - skip_auth=False, timeout=None, raise_on_error=True): + async def make_request( + self, + method, + path, + version=None, + headers=None, + body=None, + skip_auth=False, + timeout=None, + raise_on_error=True, + ): if body is not None and type(body) not in (bytes, str): body = self.dump_body(body) @@ -172,10 +183,7 @@ async def make_request(self, method, path, version=None, headers=None, body=None if not skip_auth: if self.auth.auth_mechanism == Auth.Method.BASIC and self.preferred_scheme.lower() == 'http': - raise AblyException( - "Cannot use Basic Auth over non-TLS connections", - 401, - 40103) + raise AblyException('Cannot use Basic Auth over non-TLS connections', 401, 40103) auth_headers = await self.auth._get_auth_headers() all_headers.update(auth_headers) if headers: @@ -187,9 +195,7 @@ async def make_request(self, method, path, version=None, headers=None, body=None hosts = self.get_rest_hosts() for retry_count, host in enumerate(hosts): - base_url = "%s://%s:%d" % (self.preferred_scheme, - host, - self.preferred_port) + base_url = '%s://%s:%d' % (self.preferred_scheme, host, self.preferred_port) url = urljoin(base_url, path) request = self.__client.build_request( @@ -228,28 +234,29 @@ async def make_request(self, method, path, version=None, headers=None, body=None raise e async def delete(self, url, headers=None, skip_auth=False, timeout=None): - result = await self.make_request('DELETE', url, headers=headers, - skip_auth=skip_auth, timeout=timeout) + result = await self.make_request('DELETE', url, headers=headers, skip_auth=skip_auth, timeout=timeout) return result async def get(self, url, headers=None, skip_auth=False, timeout=None): - result = await self.make_request('GET', url, headers=headers, - skip_auth=skip_auth, timeout=timeout) + result = await self.make_request('GET', url, headers=headers, skip_auth=skip_auth, timeout=timeout) return result async def patch(self, url, headers=None, body=None, skip_auth=False, timeout=None): - result = await self.make_request('PATCH', url, headers=headers, body=body, - skip_auth=skip_auth, timeout=timeout) + result = await self.make_request( + 'PATCH', url, headers=headers, body=body, skip_auth=skip_auth, timeout=timeout + ) return result async def post(self, url, headers=None, body=None, skip_auth=False, timeout=None): - result = await self.make_request('POST', url, headers=headers, body=body, - skip_auth=skip_auth, timeout=timeout) + result = await self.make_request( + 'POST', url, headers=headers, body=body, skip_auth=skip_auth, timeout=timeout + ) return result async def put(self, url, headers=None, body=None, skip_auth=False, timeout=None): - result = await self.make_request('PUT', url, headers=headers, body=body, - skip_auth=skip_auth, timeout=timeout) + result = await self.make_request( + 'PUT', url, headers=headers, body=body, skip_auth=skip_auth, timeout=timeout + ) return result @property diff --git a/ably/http/httputils.py b/ably/http/httputils.py index b55ae75c..2d3ea93f 100644 --- a/ably/http/httputils.py +++ b/ably/http/httputils.py @@ -6,28 +6,28 @@ class HttpUtils: - default_format = "json" + default_format = 'json' mime_types = { - "json": "application/json", - "xml": "application/xml", - "html": "text/html", - "binary": "application/x-msgpack", + 'json': 'application/json', + 'xml': 'application/xml', + 'html': 'text/html', + 'binary': 'application/x-msgpack', } @staticmethod def default_get_headers(binary=False, version=None): headers = HttpUtils.default_headers(version=version) if binary: - headers["Accept"] = HttpUtils.mime_types['binary'] + headers['Accept'] = HttpUtils.mime_types['binary'] else: - headers["Accept"] = HttpUtils.mime_types['json'] + headers['Accept'] = HttpUtils.mime_types['json'] return headers @staticmethod def default_post_headers(binary=False, version=None): headers = HttpUtils.default_get_headers(binary=binary, version=version) - headers["Content-Type"] = headers["Accept"] + headers['Content-Type'] = headers['Accept'] return headers @staticmethod @@ -41,8 +41,8 @@ def default_headers(version=None): if version is None: version = ably.api_version return { - "X-Ably-Version": version, - "Ably-Agent": 'ably-python/%s python/%s' % (ably.lib_version, platform.python_version()) + 'X-Ably-Version': version, + 'Ably-Agent': 'ably-python/%s python/%s' % (ably.lib_version, platform.python_version()), } @staticmethod diff --git a/ably/http/paginatedresult.py b/ably/http/paginatedresult.py index 6421251b..d353920f 100644 --- a/ably/http/paginatedresult.py +++ b/ably/http/paginatedresult.py @@ -32,7 +32,7 @@ def format_params(params=None, direction=None, start=None, end=None, limit=None, params['end'] = format_time_param(end) if limit: if limit > 1000: - raise ValueError("The maximum allowed limit is 1000") + raise ValueError('The maximum allowed limit is 1000') params['limit'] = '%d' % limit if 'start' in params and 'end' in params and params['start'] > params['end']: @@ -42,8 +42,7 @@ def format_params(params=None, direction=None, start=None, end=None, limit=None, class PaginatedResult: - def __init__(self, http, items, content_type, rel_first, rel_next, - response_processor, response): + def __init__(self, http, items, content_type, rel_first, rel_next, response_processor, response): self.__http = http self.__items = items self.__content_type = content_type @@ -77,21 +76,40 @@ async def __get_rel(self, rel_req): return await self.paginated_query_with_request(self.__http, rel_req, self.__response_processor) @classmethod - async def paginated_query(cls, http, method='GET', url='/', version=None, body=None, - headers=None, response_processor=None, - raise_on_error=True): + async def paginated_query( + cls, + http, + method='GET', + url='/', + version=None, + body=None, + headers=None, + response_processor=None, + raise_on_error=True, + ): headers = headers or {} - req = Request(method, url, version=version, body=body, headers=headers, skip_auth=False, - raise_on_error=raise_on_error) + req = Request( + method, + url, + version=version, + body=body, + headers=headers, + skip_auth=False, + raise_on_error=raise_on_error, + ) return await cls.paginated_query_with_request(http, req, response_processor) @classmethod - async def paginated_query_with_request(cls, http, request, response_processor, - raise_on_error=True): + async def paginated_query_with_request(cls, http, request, response_processor, raise_on_error=True): response = await http.make_request( - request.method, request.url, version=request.version, - headers=request.headers, body=request.body, - skip_auth=request.skip_auth, raise_on_error=request.raise_on_error) + request.method, + request.url, + version=request.version, + headers=request.headers, + body=request.body, + skip_auth=request.skip_auth, + raise_on_error=request.raise_on_error, + ) items = response_processor(response) @@ -107,8 +125,7 @@ async def paginated_query_with_request(cls, http, request, response_processor, else: next_rel_request = None - return cls(http, items, content_type, first_rel_request, - next_rel_request, response_processor, response) + return cls(http, items, content_type, first_rel_request, next_rel_request, response_processor, response) class HttpPaginatedResponse(PaginatedResult): diff --git a/ably/realtime/connectionmanager.py b/ably/realtime/connectionmanager.py index eb49b2d6..f00cfeaa 100644 --- a/ably/realtime/connectionmanager.py +++ b/ably/realtime/connectionmanager.py @@ -53,8 +53,9 @@ def enact_state_change(self, state: ConnectionState, reason: Optional[AblyExcept def check_connection(self) -> bool: try: response = httpx.get(self.options.connectivity_check_url) - return 200 <= response.status_code < 300 and \ - (self.options.connectivity_check_url != Defaults.connectivity_check_url or "yes" in response.text) + return 200 <= response.status_code < 300 and ( + self.options.connectivity_check_url != Defaults.connectivity_check_url or 'yes' in response.text + ) except httpx.HTTPError: return False @@ -64,9 +65,9 @@ def get_state_error(self) -> AblyException: async def __get_transport_params(self) -> dict: protocol_version = Defaults.protocol_version params = await self.ably.auth.get_auth_transport_param() - params["v"] = protocol_version + params['v'] = protocol_version if self.connection_details: - params["resume"] = self.connection_details.connection_key + params['resume'] = self.connection_details.connection_key return params async def close_impl(self) -> None: @@ -97,11 +98,11 @@ async def send_protocol_message(self, protocol_message: dict) -> None: await self.transport.send(protocol_message) else: log.exception( - "ConnectionManager.send_protocol_message(): can not send message with no active transport" + 'ConnectionManager.send_protocol_message(): can not send message with no active transport' ) return - raise AblyException(f"ConnectionManager.send_protocol_message(): called in {self.state}", 500, 50000) + raise AblyException(f'ConnectionManager.send_protocol_message(): called in {self.state}', 500, 50000) def send_queued_messages(self) -> None: log.info(f'ConnectionManager.send_queued_messages(): sending {self.queued_messages.qsize()} message(s)') @@ -110,40 +111,40 @@ def send_queued_messages(self) -> None: def fail_queued_messages(self, err) -> None: log.info( - f"ConnectionManager.fail_queued_messages(): discarding {self.queued_messages.qsize()} messages;" + - f" reason = {err}" + f'ConnectionManager.fail_queued_messages(): discarding {self.queued_messages.qsize()} messages;' + + f' reason = {err}' ) while not self.queued_messages.empty(): msg = self.queued_messages.get() - log.exception(f"ConnectionManager.fail_queued_messages(): Failed to send protocol message: {msg}") + log.exception(f'ConnectionManager.fail_queued_messages(): Failed to send protocol message: {msg}') async def ping(self) -> float: if self.__ping_future: try: response = await self.__ping_future except asyncio.CancelledError: - raise AblyException("Ping request cancelled due to request timeout", 504, 50003) + raise AblyException('Ping request cancelled due to request timeout', 504, 50003) return response self.__ping_future = asyncio.Future() if self.__state in [ConnectionState.CONNECTED, ConnectionState.CONNECTING]: self.__ping_id = get_random_id() ping_start_time = datetime.now().timestamp() - await self.send_protocol_message({"action": ProtocolMessageAction.HEARTBEAT, - "id": self.__ping_id}) + await self.send_protocol_message({'action': ProtocolMessageAction.HEARTBEAT, 'id': self.__ping_id}) else: - raise AblyException("Cannot send ping request. Calling ping in invalid state", 40000, 400) + raise AblyException('Cannot send ping request. Calling ping in invalid state', 40000, 400) try: await asyncio.wait_for(self.__ping_future, self.__timeout_in_secs) except asyncio.TimeoutError: - raise AblyException("Timeout waiting for ping response", 504, 50003) + raise AblyException('Timeout waiting for ping response', 504, 50003) ping_end_time = datetime.now().timestamp() response_time_ms = (ping_end_time - ping_start_time) * 1000 return round(response_time_ms, 2) - def on_connected(self, connection_details: ConnectionDetails, connection_id: str, - reason: Optional[AblyException] = None) -> None: + def on_connected( + self, connection_details: ConnectionDetails, connection_id: str, reason: Optional[AblyException] = None + ) -> None: self.__fail_state = ConnectionState.DISCONNECTED self.__connection_details = connection_details @@ -157,8 +158,9 @@ def on_connected(self, connection_details: ConnectionDetails, connection_id: str return if self.__state == ConnectionState.CONNECTED: - state_change = ConnectionStateChange(ConnectionState.CONNECTED, ConnectionState.CONNECTED, - ConnectionEvent.UPDATE) + state_change = ConnectionStateChange( + ConnectionState.CONNECTED, ConnectionState.CONNECTED, ConnectionEvent.UPDATE + ) self._emit(ConnectionEvent.UPDATE, state_change) else: self.notify_state(ConnectionState.CONNECTED, reason=reason) @@ -179,13 +181,13 @@ async def on_disconnected(self, exception: AblyException) -> None: self.notify_state(self.__fail_state, reason=e) return else: - log.info("No fallback host to try for disconnected protocol message") + log.info('No fallback host to try for disconnected protocol message') elif is_token_error(exception): await self.on_token_error(exception) else: self.notify_state(ConnectionState.DISCONNECTED, exception) else: - log.warn("DISCONNECTED message received without error") + log.warn('DISCONNECTED message received without error') async def on_token_error(self, exception: AblyException) -> None: if self.__error_reason is None or not is_token_error(self.__error_reason): @@ -200,7 +202,7 @@ async def on_token_error(self, exception: AblyException) -> None: self.notify_state(self.__fail_state, exception) async def on_error(self, msg: dict, exception: AblyException) -> None: - if msg.get("channel") is not None: # RTN15i + if msg.get('channel') is not None: # RTN15i self.on_channel_message(msg) return if self.transport: @@ -211,7 +213,7 @@ async def on_error(self, msg: dict, exception: AblyException) -> None: self.enact_state_change(ConnectionState.FAILED, exception) def on_error_from_authorize(self, exception: AblyException) -> None: - log.info("ConnectionManager.on_error_from_authorize(): err = %s", exception) + log.info('ConnectionManager.on_error_from_authorize(): err = %s', exception) # RSA4a if exception.code == 40171: self.notify_state(ConnectionState.FAILED, exception) @@ -257,8 +259,10 @@ def request_state(self, state: ConnectionState, force=False) -> None: if state == ConnectionState.CLOSING and self.__state == ConnectionState.CLOSED: return - if state == ConnectionState.CONNECTING and self.__state in (ConnectionState.CLOSED, - ConnectionState.FAILED): + if state == ConnectionState.CONNECTING and self.__state in ( + ConnectionState.CLOSED, + ConnectionState.FAILED, + ): self.ably.channels._initialize_channels() if not force: @@ -282,7 +286,7 @@ async def connect_with_fallback_hosts(self, fallback_hosts: list) -> Optional[Ex await self.try_host(host) return else: - message = "Unable to connect, network unreachable" + message = 'Unable to connect, network unreachable' log.exception(message) exception = AblyException(message, status_code=404, code=80003) self.notify_state(self.__fail_state, exception) @@ -290,7 +294,7 @@ async def connect_with_fallback_hosts(self, fallback_hosts: list) -> Optional[Ex except Exception as exc: exception = exc log.exception(f'Connection to {host} failed, reason={exception}') - log.exception("No more fallback hosts to try") + log.exception('No more fallback hosts to try') return exception async def connect_base(self) -> None: @@ -302,7 +306,7 @@ async def connect_base(self) -> None: except Exception as exception: log.exception(f'Connection to {primary_host} failed, reason={exception}') if len(fallback_hosts) > 0: - log.info("Attempting connection to fallback host(s)") + log.info('Attempting connection to fallback host(s)') resp = await self.connect_with_fallback_hosts(fallback_hosts) if not resp: return @@ -343,11 +347,16 @@ async def on_transport_failed(exception): except asyncio.CancelledError: return - def notify_state(self, state: ConnectionState, reason: Optional[AblyException] = None, - retry_immediately: Optional[bool] = None) -> None: + def notify_state( + self, + state: ConnectionState, + reason: Optional[AblyException] = None, + retry_immediately: Optional[bool] = None, + ) -> None: # RTN15a retry_immediately = (retry_immediately is not False) and ( - state == ConnectionState.DISCONNECTED and self.__state == ConnectionState.CONNECTED) + state == ConnectionState.DISCONNECTED and self.__state == ConnectionState.CONNECTED + ) log.debug( f'ConnectionManager.notify_state(): new state: {state}' @@ -400,8 +409,7 @@ def on_transition_timer_expire(): self.transition_timer = None log.info(f'ConnectionManager {state} timer expired, notifying new state: {fail_state}') self.notify_state( - fail_state, - AblyException("Connection cancelled due to request timeout", 504, 50003) + fail_state, AblyException('Connection cancelled due to request timeout', 504, 50003) ) log.debug(f'ConnectionManager.start_transition_timer(): setting timer for {timeout}ms') @@ -424,8 +432,7 @@ def on_suspend_timer_expire() -> None: self.suspend_timer = None log.info('ConnectionManager suspend timer expired, requesting new state: suspended') self.notify_state( - ConnectionState.SUSPENDED, - AblyException("Connection to server unavailable", 400, 80002) + ConnectionState.SUSPENDED, AblyException('Connection to server unavailable', 400, 80002) ) self.__fail_state = ConnectionState.SUSPENDED self.__connection_details = None @@ -466,14 +473,9 @@ def disconnect_transport(self) -> None: self.disconnect_transport_task = asyncio.create_task(self.transport.dispose()) async def on_auth_updated(self, token_details: TokenDetails): - log.info(f"ConnectionManager.on_auth_updated(): state = {self.state}") + log.info(f'ConnectionManager.on_auth_updated(): state = {self.state}') if self.state == ConnectionState.CONNECTED: - auth_message = { - "action": ProtocolMessageAction.AUTH, - "auth": { - "accessToken": token_details.token - } - } + auth_message = {'action': ProtocolMessageAction.AUTH, 'auth': {'accessToken': token_details.token}} await self.send_protocol_message(auth_message) state_change = await self.once_async() @@ -495,9 +497,9 @@ def on_state_change(state_change: ConnectionStateChange) -> None: self.off('connectionstate', on_state_change) future.set_result(token_details) if state_change.current in ( - ConnectionState.CLOSED, - ConnectionState.FAILED, - ConnectionState.SUSPENDED + ConnectionState.CLOSED, + ConnectionState.FAILED, + ConnectionState.SUSPENDED, ): self.off('connectionstate', on_state_change) future.set_exception(state_change.reason or self.get_state_error()) diff --git a/ably/realtime/realtime_channel.py b/ably/realtime/realtime_channel.py index 4f7468a4..fc7ef5d9 100644 --- a/ably/realtime/realtime_channel.py +++ b/ably/realtime/realtime_channel.py @@ -86,12 +86,10 @@ async def attach(self) -> None: if self.__realtime.connection.state not in [ ConnectionState.CONNECTING, ConnectionState.CONNECTED, - ConnectionState.DISCONNECTED + ConnectionState.DISCONNECTED, ]: raise AblyException( - message=f"Unable to attach; channel state = {self.state}", - code=90001, - status_code=400 + message=f'Unable to attach; channel state = {self.state}', code=90001, status_code=400 ) if self.state != ChannelState.ATTACHING: @@ -103,18 +101,18 @@ async def attach(self) -> None: raise state_change.reason def _attach_impl(self): - log.debug("RealtimeChannel.attach_impl(): sending ATTACH protocol message") + log.debug('RealtimeChannel.attach_impl(): sending ATTACH protocol message') # RTL4c attach_msg = { - "action": ProtocolMessageAction.ATTACH, - "channel": self.name, + 'action': ProtocolMessageAction.ATTACH, + 'channel': self.name, } if self.__attach_resume: - attach_msg["flags"] = Flag.ATTACH_RESUME + attach_msg['flags'] = Flag.ATTACH_RESUME if self.__channel_serial: - attach_msg["channelSerial"] = self.__channel_serial + attach_msg['channelSerial'] = self.__channel_serial self._send_message(attach_msg) @@ -137,9 +135,7 @@ async def detach(self) -> None: # RTL5g, RTL5b - raise exception if state invalid if self.__realtime.connection.state in [ConnectionState.CLOSING, ConnectionState.FAILED]: raise AblyException( - message=f"Unable to detach; channel state = {self.state}", - code=90001, - status_code=400 + message=f'Unable to detach; channel state = {self.state}', code=90001, status_code=400 ) # RTL5a - if channel already detached do nothing @@ -150,7 +146,7 @@ async def detach(self) -> None: self._notify_state(ChannelState.DETACHED) return elif self.state == ChannelState.FAILED: - raise AblyException("Unable to detach; channel state = failed", 90001, 400) + raise AblyException('Unable to detach; channel state = failed', 90001, 400) else: self._request_state(ChannelState.DETACHING) @@ -164,17 +160,17 @@ async def detach(self) -> None: if new_state == ChannelState.DETACHED: return elif new_state == ChannelState.ATTACHING: - raise AblyException("Detach request superseded by a subsequent attach request", 90000, 409) + raise AblyException('Detach request superseded by a subsequent attach request', 90000, 409) else: raise state_change.reason def _detach_impl(self) -> None: - log.debug("RealtimeChannel.detach_impl(): sending DETACH protocol message") + log.debug('RealtimeChannel.detach_impl(): sending DETACH protocol message') # RTL5d detach_msg = { - "action": ProtocolMessageAction.DETACH, - "channel": self.__name, + 'action': ProtocolMessageAction.DETACH, + 'channel': self.__name, } self._send_message(detach_msg) @@ -212,9 +208,9 @@ async def subscribe(self, *args) -> None: if isinstance(args[0], str): event = args[0] if not args[1]: - raise ValueError("channel.subscribe called without listener") + raise ValueError('channel.subscribe called without listener') if not is_callable_or_coroutine(args[1]): - raise ValueError("subscribe listener must be function or coroutine function") + raise ValueError('subscribe listener must be function or coroutine function') listener = args[1] elif is_callable_or_coroutine(args[0]): listener = args[0] @@ -266,9 +262,9 @@ def unsubscribe(self, *args) -> None: elif isinstance(args[0], str): event = args[0] if not args[1]: - raise ValueError("channel.unsubscribe called without listener") + raise ValueError('channel.unsubscribe called without listener') if not is_callable_or_coroutine(args[1]): - raise ValueError("unsubscribe listener must be a function or coroutine function") + raise ValueError('unsubscribe listener must be a function or coroutine function') listener = args[1] elif is_callable_or_coroutine(args[0]): listener = args[0] @@ -299,7 +295,7 @@ def _on_message(self, proto_msg: dict) -> None: if action == ProtocolMessageAction.ATTACHED: flags = proto_msg.get('flags') - error = proto_msg.get("error") + error = proto_msg.get('error') exception = None resumed = False @@ -313,11 +309,11 @@ def _on_message(self, proto_msg: dict) -> None: if self.state == ChannelState.ATTACHED: if not resumed: state_change = ChannelStateChange(self.state, ChannelState.ATTACHED, resumed, exception) - self._emit("update", state_change) + self._emit('update', state_change) elif self.state == ChannelState.ATTACHING: self._notify_state(ChannelState.ATTACHED, resumed=resumed) else: - log.warn("RealtimeChannel._on_message(): ATTACHED received while not attaching") + log.warn('RealtimeChannel._on_message(): ATTACHED received while not attaching') elif action == ProtocolMessageAction.DETACHED: if self.state == ChannelState.DETACHING: self._notify_state(ChannelState.DETACHED) @@ -338,8 +334,9 @@ def _request_state(self, state: ChannelState) -> None: self._notify_state(state) self._check_pending_state() - def _notify_state(self, state: ChannelState, reason: Optional[AblyException] = None, - resumed: bool = False) -> None: + def _notify_state( + self, state: ChannelState, reason: Optional[AblyException] = None, resumed: bool = False + ) -> None: log.debug(f'RealtimeChannel._notify_state(): state = {state}') self.__clear_state_timer() @@ -381,7 +378,7 @@ def _check_pending_state(self): connection_state = self.__realtime.connection.connection_manager.state if connection_state is not ConnectionState.CONNECTED: - log.debug(f"RealtimeChannel._check_pending_state(): connection state = {connection_state}") + log.debug(f'RealtimeChannel._check_pending_state(): connection state = {connection_state}') return if self.state == ChannelState.ATTACHING: @@ -393,6 +390,7 @@ def _check_pending_state(self): def __start_state_timer(self) -> None: if not self.__state_timer: + def on_timeout() -> None: log.debug('RealtimeChannel.start_state_timer(): timer expired') self.__state_timer = None @@ -408,9 +406,10 @@ def __clear_state_timer(self) -> None: def __timeout_pending_state(self) -> None: if self.state == ChannelState.ATTACHING: self._notify_state( - ChannelState.SUSPENDED, reason=AblyException("Channel attach timed out", 408, 90007)) + ChannelState.SUSPENDED, reason=AblyException('Channel attach timed out', 408, 90007) + ) elif self.state == ChannelState.DETACHING: - self._notify_state(ChannelState.ATTACHED, reason=AblyException("Channel detach timed out", 408, 90007)) + self._notify_state(ChannelState.ATTACHED, reason=AblyException('Channel detach timed out', 408, 90007)) else: self._check_pending_state() @@ -428,7 +427,7 @@ def __cancel_retry_timer(self) -> None: def __on_retry_timer_expire(self) -> None: if self.state == ChannelState.SUSPENDED and self.ably.connection.state == ConnectionState.CONNECTED: self.__retry_timer = None - log.info("RealtimeChannel retry timer expired, attempting a new attach") + log.info('RealtimeChannel retry timer expired, attempting a new attach') self._request_state(ChannelState.ATTACHING) # RTL23 @@ -502,16 +501,14 @@ def _on_channel_message(self, msg: dict) -> None: channel_name = msg.get('channel') if not channel_name: log.error( - 'Channels.on_channel_message()', - f'received event without channel, action = {msg.get("action")}' + 'Channels.on_channel_message()', f'received event without channel, action = {msg.get("action")}' ) return channel = self.__all[channel_name] if not channel: log.warning( - 'Channels.on_channel_message()', - f'receieved event for non-existent channel: {channel_name}' + 'Channels.on_channel_message()', f'receieved event for non-existent channel: {channel_name}' ) return diff --git a/ably/rest/auth.py b/ably/rest/auth.py index 06af2438..6a648b3f 100644 --- a/ably/rest/auth.py +++ b/ably/rest/auth.py @@ -8,6 +8,7 @@ import httpx from ably.types.options import Options + if TYPE_CHECKING: from ably.rest.rest import AblyRest from ably.realtime.realtime import AblyRealtime @@ -17,16 +18,15 @@ from ably.types.tokenrequest import TokenRequest from ably.util.exceptions import AblyAuthException, AblyException, IncompatibleClientIdException -__all__ = ["Auth"] +__all__ = ['Auth'] log = logging.getLogger(__name__) class Auth: - class Method: - BASIC = "BASIC" - TOKEN = "TOKEN" + BASIC = 'BASIC' + TOKEN = 'TOKEN' def __init__(self, ably: Union[AblyRest, AblyRealtime], options: Options): self.__ably = ably @@ -51,9 +51,9 @@ def __init__(self, ably: Union[AblyRest, AblyRealtime], options: Options): if not must_use_token_auth and can_use_basic_auth: # We have the key, no need to authenticate the client # default to using basic auth - log.debug("anonymous, using basic auth") + log.debug('anonymous, using basic auth') self.__auth_mechanism = Auth.Method.BASIC - basic_key = "%s:%s" % (options.key_name, options.key_secret) + basic_key = '%s:%s' % (options.key_name, options.key_secret) basic_key = base64.b64encode(basic_key.encode('utf-8')) self.__basic_credentials = basic_key.decode('ascii') return @@ -71,30 +71,32 @@ def __init__(self, ably: Union[AblyRest, AblyRealtime], options: Options): self.__token_details = None if options.auth_callback: - log.debug("using token auth with auth_callback") + log.debug('using token auth with auth_callback') elif options.auth_url: - log.debug("using token auth with auth_url") + log.debug('using token auth with auth_url') elif options.key_secret: - log.debug("using token auth with client-side signing") + log.debug('using token auth with client-side signing') elif options.auth_token: - log.debug("using token auth with supplied token only") + log.debug('using token auth with supplied token only') elif options.token_details: - log.debug("using token auth with supplied token_details") + log.debug('using token auth with supplied token_details') else: - raise ValueError("Can't authenticate via token, must provide " - "auth_callback, auth_url, key, token or a TokenDetail") + raise ValueError( + "Can't authenticate via token, must provide " + 'auth_callback, auth_url, key, token or a TokenDetail' + ) async def get_auth_transport_param(self): auth_credentials = {} if self.auth_options.client_id: - auth_credentials["client_id"] = self.auth_options.client_id + auth_credentials['client_id'] = self.auth_options.client_id if self.__auth_mechanism == Auth.Method.BASIC: key_name = self.__auth_options.key_name key_secret = self.__auth_options.key_secret - auth_credentials["key"] = f"{key_name}:{key_secret}" + auth_credentials['key'] = f'{key_name}:{key_secret}' elif self.__auth_mechanism == Auth.Method.TOKEN: token_details = await self._ensure_valid_auth_credentials() - auth_credentials["accessToken"] = token_details.token + auth_credentials['accessToken'] = token_details.token return auth_credentials async def __authorize_when_necessary(self, token_params=None, auth_options=None, force=False): @@ -121,8 +123,7 @@ async def _ensure_valid_auth_credentials(self, token_params=None, auth_options=N token_details = self.__token_details if not force and not self.token_details_has_expired(): - log.debug("using cached token; expires = %d", - token_details.expires) + log.debug('using cached token; expires = %d', token_details.expires) return token_details self.__token_details = await self.request_token(token_params, **auth_options) @@ -151,20 +152,26 @@ def token_details_has_expired(self): async def authorize(self, token_params: Optional[dict] = None, auth_options=None): return await self.__authorize_when_necessary(token_params, auth_options, force=True) - async def request_token(self, token_params: Optional[dict] = None, - # auth_options - key_name: Optional[str] = None, key_secret: Optional[str] = None, auth_callback=None, - auth_url: Optional[str] = None, auth_method: Optional[str] = None, - auth_headers: Optional[dict] = None, auth_params: Optional[dict] = None, - query_time=None): + async def request_token( + self, + token_params: Optional[dict] = None, + # auth_options + key_name: Optional[str] = None, + key_secret: Optional[str] = None, + auth_callback=None, + auth_url: Optional[str] = None, + auth_method: Optional[str] = None, + auth_headers: Optional[dict] = None, + auth_params: Optional[dict] = None, + query_time=None, + ): token_params = token_params or {} - token_params = dict(self.auth_options.default_token_params, - **token_params) + token_params = dict(self.auth_options.default_token_params, **token_params) key_name = key_name or self.auth_options.key_name key_secret = key_secret or self.auth_options.key_secret - log.debug("Auth callback: %s" % auth_callback) - log.debug("Auth options: %s" % self.auth_options) + log.debug('Auth callback: %s' % auth_callback) + log.debug('Auth options: %s' % self.auth_options) if query_time is None: query_time = self.auth_options.query_time query_time = bool(query_time) @@ -177,24 +184,25 @@ async def request_token(self, token_params: Optional[dict] = None, auth_headers = auth_headers or self.auth_options.auth_headers or {} - log.debug("Token Params: %s" % token_params) + log.debug('Token Params: %s' % token_params) if auth_callback: - log.debug("using token auth with authCallback") + log.debug('using token auth with authCallback') try: token_request = await auth_callback(token_params) except Exception as e: - raise AblyException("auth_callback raised an exception", 401, 40170, cause=e) + raise AblyException('auth_callback raised an exception', 401, 40170, cause=e) elif auth_url: - log.debug("using token auth with authUrl") + log.debug('using token auth with authUrl') token_request = await self.token_request_from_auth_url( - auth_method, auth_url, token_params, auth_headers, auth_params) + auth_method, auth_url, token_params, auth_headers, auth_params + ) elif key_name is not None and key_secret is not None: token_request = await self.create_token_request( - token_params, key_name=key_name, key_secret=key_secret, - query_time=query_time) + token_params, key_name=key_name, key_secret=key_secret, query_time=query_time + ) else: - msg = "Need a new token but auth_options does not include a way to request one" + msg = 'Need a new token but auth_options does not include a way to request one' log.exception(msg) raise AblyAuthException(msg, 403, 40171) if isinstance(token_request, TokenDetails): @@ -205,32 +213,34 @@ async def request_token(self, token_params: Optional[dict] = None, try: token_request = TokenRequest.from_json(token_request) except TypeError as e: - msg = "Expected token request callback to call back with a token string, token request object, or \ - token details object" + msg = 'Expected token request callback to call back with a token string, token request object, or \ + token details object' raise AblyAuthException(msg, 401, 40170, cause=e) elif isinstance(token_request, str): if len(token_request) == 0: - raise AblyAuthException("Token string is empty", 401, 4017) + raise AblyAuthException('Token string is empty', 401, 4017) return TokenDetails(token=token_request) elif token_request is None: - raise AblyAuthException("Token string was None", 401, 40170) + raise AblyAuthException('Token string was None', 401, 40170) - token_path = "/keys/%s/requestToken" % token_request.key_name + token_path = '/keys/%s/requestToken' % token_request.key_name response = await self.ably.http.post( - token_path, - headers=auth_headers, - body=token_request.to_dict(), - skip_auth=True + token_path, headers=auth_headers, body=token_request.to_dict(), skip_auth=True ) AblyException.raise_for_response(response) response_dict = response.to_native() - log.debug("Token: %s" % str(response_dict.get("token"))) + log.debug('Token: %s' % str(response_dict.get('token'))) return TokenDetails.from_dict(response_dict) - async def create_token_request(self, token_params: Optional[dict] = None, key_name: Optional[str] = None, - key_secret: Optional[str] = None, query_time=None): + async def create_token_request( + self, + token_params: Optional[dict] = None, + key_name: Optional[str] = None, + key_secret: Optional[str] = None, + query_time=None, + ): token_params = token_params or {} token_request = {} @@ -238,7 +248,7 @@ async def create_token_request(self, token_params: Optional[dict] = None, key_na key_secret = key_secret or self.auth_options.key_secret if not key_name or not key_secret: log.debug('key_name or key_secret blank') - raise AblyException("No key specified: no means to generate a token", 401, 40101) + raise AblyException('No key specified: no means to generate a token', 401, 40101) token_request['key_name'] = key_name if token_params.get('timestamp'): @@ -271,14 +281,13 @@ async def create_token_request(self, token_params: Optional[dict] = None, key_na if capability is not None: token_request['capability'] = str(Capability(capability)) - token_request["client_id"] = ( - token_params.get('client_id') or self.client_id) + token_request['client_id'] = token_params.get('client_id') or self.client_id # Note: There is no expectation that the client # specifies the nonce; this is done by the library # However, this can be overridden by the client # simply for testing purposes - token_request["nonce"] = token_params.get('nonce') or self._random_nonce() + token_request['nonce'] = token_params.get('nonce') or self._random_nonce() token_req = TokenRequest(**token_request) @@ -333,7 +342,7 @@ def time_offset(self): return self.__time_offset def _configure_client_id(self, new_client_id): - log.debug("Auth._configure_client_id(): new client_id = %s", new_client_id) + log.debug('Auth._configure_client_id(): new client_id = %s', new_client_id) original_client_id = self.client_id or self.auth_options.client_id # If new client ID from Ably is a wildcard, but preconfigured clientId is set, @@ -346,8 +355,11 @@ def _configure_client_id(self, new_client_id): # If client_id is defined and not a wildcard, prevent it changing, this is not supported if original_client_id is not None and original_client_id != '*' and new_client_id != original_client_id: raise IncompatibleClientIdException( - "Client ID is immutable once configured for a client. " - "Client ID cannot be changed to '{}'".format(new_client_id), 400, 40102) + 'Client ID is immutable once configured for a client. ' + "Client ID cannot be changed to '{}'".format(new_client_id), + 400, + 40102, + ) self.__client_id_validated = True self.__client_id = new_client_id @@ -368,7 +380,7 @@ async def _get_auth_headers(self): if self.client_id: return { 'Authorization': 'Basic %s' % self.basic_credentials, - 'X-Ably-ClientId': base64.b64encode(self.client_id.encode('utf-8')) + 'X-Ably-ClientId': base64.b64encode(self.client_id.encode('utf-8')), } return { 'Authorization': 'Basic %s' % self.basic_credentials, @@ -386,8 +398,7 @@ def _timestamp(self): def _random_nonce(self): return uuid.uuid4().hex[:16] - async def token_request_from_auth_url(self, method: str, url: str, token_params, - headers, auth_params): + async def token_request_from_auth_url(self, method: str, url: str, token_params, headers, auth_params): body = None params = None if method == 'GET': @@ -400,6 +411,7 @@ async def token_request_from_auth_url(self, method: str, url: str, token_params, body = dict(auth_params, **token_params) from ably.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) @@ -409,17 +421,20 @@ async def token_request_from_auth_url(self, method: str, url: str, token_params, content_type = response.response.headers.get('content-type') if not content_type: - raise AblyAuthException("auth_url response missing a content-type header", 401, 40170) + raise AblyAuthException('auth_url response missing a content-type header', 401, 40170) - is_json = "application/json" in content_type - is_text = "application/jwt" in content_type or "text/plain" in content_type + is_json = 'application/json' in content_type + is_text = 'application/jwt' in content_type or 'text/plain' in content_type if is_json: token_request = response.to_native() elif is_text: token_request = response.text else: - msg = 'auth_url responded with unacceptable content-type ' + content_type + \ - ', should be either text/plain, application/jwt or application/json', + msg = ( + 'auth_url responded with unacceptable content-type ' + + content_type + + ', should be either text/plain, application/jwt or application/json', + ) raise AblyAuthException(msg, 401, 40170) return token_request diff --git a/ably/rest/channel.py b/ably/rest/channel.py index d7995607..a9b32782 100644 --- a/ably/rest/channel.py +++ b/ably/rest/channel.py @@ -35,8 +35,7 @@ async def history(self, direction=None, limit: int = None, start=None, end=None) path = self.__base_path + 'messages' + params message_handler = make_message_response_handler(self.__cipher) - return await PaginatedResult.paginated_query( - self.ably.http, url=path, response_processor=message_handler) + return await PaginatedResult.paginated_query(self.ably.http, url=path, response_processor=message_handler) def __publish_request_body(self, messages): """ @@ -54,13 +53,15 @@ def __publish_request_body(self, messages): for m in messages: if m.client_id == '*': raise IncompatibleClientIdException( - 'Wildcard client_id is reserved and cannot be used when publishing messages', - 400, 40012) + 'Wildcard client_id is reserved and cannot be used when publishing messages', 400, 40012 + ) elif m.client_id is not None and not self.ably.auth.can_assume_client_id(m.client_id): raise IncompatibleClientIdException( - 'Cannot publish with client_id \'{}\' as it is incompatible with the ' - 'current configured client_id \'{}\''.format(m.client_id, self.ably.auth.client_id), - 400, 40012) + "Cannot publish with client_id '{}' as it is incompatible with the " + "current configured client_id '{}'".format(m.client_id, self.ably.auth.client_id), + 400, + 40012, + ) if self.cipher: m.encrypt(self.__cipher) @@ -68,8 +69,8 @@ def __publish_request_body(self, messages): request_body_list.append(m) request_body = [ - message.as_dict(binary=self.ably.options.use_binary_protocol) - for message in request_body_list] + message.as_dict(binary=self.ably.options.use_binary_protocol) for message in request_body_list + ] if len(request_body) == 1: request_body = request_body[0] diff --git a/ably/rest/push.py b/ably/rest/push.py index d3cf0e03..358c2300 100644 --- a/ably/rest/push.py +++ b/ably/rest/push.py @@ -6,7 +6,6 @@ class Push: - def __init__(self, ably): self.__ably = ably self.__admin = PushAdmin(ably) @@ -17,7 +16,6 @@ def admin(self): class PushAdmin: - def __init__(self, ably): self.__ably = ably self.__device_registrations = PushDeviceRegistrations(ably) @@ -60,7 +58,6 @@ async def publish(self, recipient: dict, data: dict, timeout: Optional[float] = class PushDeviceRegistrations: - def __init__(self, ably): self.__ably = ably @@ -89,8 +86,8 @@ async def list(self, **params): """ path = '/push/deviceRegistrations' + format_params(params) return await PaginatedResult.paginated_query( - self.ably.http, url=path, - response_processor=device_details_response_processor) + self.ably.http, url=path, response_processor=device_details_response_processor + ) async def save(self, device: dict): """Creates or updates the device. Returns a DeviceDetails object. @@ -125,7 +122,6 @@ async def remove_where(self, **params): class PushChannelSubscriptions: - def __init__(self, ably): self.__ably = ably @@ -141,8 +137,9 @@ async def list(self, **params): - `**params`: the parameters used to filter the list """ path = '/push/channelSubscriptions' + format_params(params) - return await PaginatedResult.paginated_query(self.ably.http, url=path, - response_processor=channel_subscriptions_response_processor) + return await PaginatedResult.paginated_query( + self.ably.http, url=path, response_processor=channel_subscriptions_response_processor + ) async def list_channels(self, **params): """Returns a PaginatedResult object with the list of @@ -152,8 +149,9 @@ async def list_channels(self, **params): - `**params`: the parameters used to filter the list """ path = '/push/channels' + format_params(params) - return await PaginatedResult.paginated_query(self.ably.http, url=path, - response_processor=channels_response_processor) + return await PaginatedResult.paginated_query( + self.ably.http, url=path, response_processor=channels_response_processor + ) async def save(self, subscription: dict): """Creates or updates the subscription. Returns a diff --git a/ably/rest/rest.py b/ably/rest/rest.py index a42ba2fd..95bf9769 100644 --- a/ably/rest/rest.py +++ b/ably/rest/rest.py @@ -19,8 +19,13 @@ class AblyRest: """Ably Rest Client""" - def __init__(self, key: Optional[str] = None, token: Optional[str] = None, - token_details: Optional[TokenDetails] = None, **kwargs): + def __init__( + self, + key: Optional[str] = None, + token: Optional[str] = None, + token_details: Optional[TokenDetails] = None, + **kwargs + ): """Create an AblyRest instance. :Parameters: @@ -45,20 +50,26 @@ def __init__(self, key: Optional[str] = None, token: Optional[str] = None, - `keep_alive`: use persistent connections. Defaults to True """ if key is not None and ('key_name' in kwargs or 'key_secret' in kwargs): - raise ValueError("key and key_name or key_secret are mutually exclusive. " - "Provider either a key or key_name & key_secret") + raise ValueError( + 'key and key_name or key_secret are mutually exclusive. ' + 'Provider either a key or key_name & key_secret' + ) if key is not None: options = Options(key=key, **kwargs) elif token is not None: options = Options(auth_token=token, **kwargs) elif token_details is not None: if not isinstance(token_details, TokenDetails): - raise ValueError("token_details must be an instance of TokenDetails") + raise ValueError('token_details must be an instance of TokenDetails') options = Options(token_details=token_details, **kwargs) - elif not ('auth_callback' in kwargs or 'auth_url' in kwargs or - # and don't have both key_name and key_secret - ('key_name' in kwargs and 'key_secret' in kwargs)): - raise ValueError("key is missing. Either an API key, token, or token auth method must be provided") + elif not ( + 'auth_callback' in kwargs + or 'auth_url' in kwargs + or + # and don't have both key_name and key_secret + ('key_name' in kwargs and 'key_secret' in kwargs) + ): + raise ValueError('key is missing. Either an API key, token, or token auth method must be provided') else: options = Options(**kwargs) @@ -79,13 +90,23 @@ async def __aenter__(self): return self @catch_all - async def stats(self, direction: Optional[str] = None, start=None, end=None, params: Optional[dict] = None, - limit: Optional[int] = None, paginated=None, unit=None, timeout=None): + async def stats( + self, + direction: Optional[str] = None, + start=None, + end=None, + params: Optional[dict] = None, + limit: Optional[int] = None, + paginated=None, + unit=None, + timeout=None, + ): """Returns the stats for this application""" formatted_params = format_params(params, direction=direction, start=start, end=end, limit=limit, unit=unit) url = '/stats' + formatted_params return await PaginatedResult.paginated_query( - self.http, url=url, response_processor=stats_response_processor) + self.http, url=url, response_processor=stats_response_processor + ) @catch_all async def time(self, timeout: Optional[float] = None) -> float: @@ -119,10 +140,11 @@ def options(self): def push(self): return self.__push - async def request(self, method: str, path: str, version: str, params: - Optional[dict] = None, body=None, headers=None): + async def request( + self, method: str, path: str, version: str, params: Optional[dict] = None, body=None, headers=None + ): if version is None: - raise AblyException("No version parameter", 400, 40000) + raise AblyException('No version parameter', 400, 40000) url = path if params: @@ -137,9 +159,15 @@ def response_processor(response): return items return await HttpPaginatedResponse.paginated_query( - self.http, method, url, version=version, body=body, headers=headers, + self.http, + method, + url, + version=version, + body=body, + headers=headers, response_processor=response_processor, - raise_on_error=False) + raise_on_error=False, + ) async def __aexit__(self, *excinfo): await self.close() diff --git a/ably/transport/defaults.py b/ably/transport/defaults.py index 7a732d9a..41ef9b42 100644 --- a/ably/transport/defaults.py +++ b/ably/transport/defaults.py @@ -1,16 +1,16 @@ class Defaults: - protocol_version = "2" + protocol_version = '2' fallback_hosts = [ - "a.ably-realtime.com", - "b.ably-realtime.com", - "c.ably-realtime.com", - "d.ably-realtime.com", - "e.ably-realtime.com", + 'a.ably-realtime.com', + 'b.ably-realtime.com', + 'c.ably-realtime.com', + 'd.ably-realtime.com', + 'e.ably-realtime.com', ] - rest_host = "rest.ably.io" - realtime_host = "realtime.ably.io" # RTN2 - connectivity_check_url = "https://internet-up.ably-realtime.com/is-the-internet-up.txt" + rest_host = 'rest.ably.io' + realtime_host = 'realtime.ably.io' # RTN2 + connectivity_check_url = 'https://internet-up.ably-realtime.com/is-the-internet-up.txt' environment = 'production' port = 80 @@ -48,16 +48,16 @@ def get_port(options): @staticmethod def get_scheme(options): if options.tls: - return "https" + return 'https' else: - return "http" + return 'http' @staticmethod def get_environment_fallback_hosts(environment): return [ - environment + "-a-fallback.ably-realtime.com", - environment + "-b-fallback.ably-realtime.com", - environment + "-c-fallback.ably-realtime.com", - environment + "-d-fallback.ably-realtime.com", - environment + "-e-fallback.ably-realtime.com", + environment + '-a-fallback.ably-realtime.com', + environment + '-b-fallback.ably-realtime.com', + environment + '-c-fallback.ably-realtime.com', + environment + '-d-fallback.ably-realtime.com', + environment + '-e-fallback.ably-realtime.com', ] diff --git a/ably/transport/websockettransport.py b/ably/transport/websockettransport.py index 7c7886fa..fc9ce09a 100644 --- a/ably/transport/websockettransport.py +++ b/ably/transport/websockettransport.py @@ -55,7 +55,7 @@ def __init__(self, connection_manager: ConnectionManager, host: str, params: dic def connect(self): headers = HttpUtils.default_headers() query_params = urllib.parse.urlencode(self.params) - ws_url = (f'wss://{self.host}?{query_params}') + ws_url = f'wss://{self.host}?{query_params}' log.info(f'connect(): attempting to connect to {ws_url}') self.ws_connect_task = asyncio.create_task(self.ws_connect(ws_url, headers)) self.ws_connect_task.add_done_callback(self.on_ws_connect_done) @@ -67,9 +67,7 @@ def on_ws_connect_done(self, task: asyncio.Task): exception = e if exception is None or isinstance(exception, ConnectionClosedOK): return - log.info( - f'WebSocketTransport.on_ws_connect_done(): exception = {exception}' - ) + log.info(f'WebSocketTransport.on_ws_connect_done(): exception = {exception}') async def ws_connect(self, ws_url, headers): try: @@ -122,8 +120,10 @@ async def on_protocol_message(self, msg): try: await self.connection_manager.ably.auth.authorize() except Exception as exc: - log.exception(f"WebSocketTransport.on_protocol_message(): An exception \ - occurred during reauth: {exc}") + log.exception( + f'WebSocketTransport.on_protocol_message(): An exception \ + occurred during reauth: {exc}' + ) elif action == ProtocolMessageAction.CLOSED: if self.ws_connect_task: self.ws_connect_task.cancel() @@ -138,7 +138,7 @@ async def on_protocol_message(self, msg): elif action in ( ProtocolMessageAction.ATTACHED, ProtocolMessageAction.DETACHED, - ProtocolMessageAction.MESSAGE + ProtocolMessageAction.MESSAGE, ): self.connection_manager.on_channel_message(msg) @@ -159,7 +159,7 @@ def on_protcol_message_handled(self, task): except Exception as e: exception = e if exception is not None: - log.exception(f"WebSocketTransport.on_protocol_message_handled(): uncaught exception: {exception}") + log.exception(f'WebSocketTransport.on_protocol_message_handled(): uncaught exception: {exception}') def on_read_loop_done(self, task: asyncio.Task): try: @@ -201,7 +201,7 @@ async def on_idle_timer_expire(self): self.idle_timer = None since_last = unix_time_ms() - self.last_activity time_remaining = self.max_idle_interval - since_last - msg = f"No activity seen from realtime in {since_last} ms; assuming connection has dropped" + msg = f'No activity seen from realtime in {since_last} ms; assuming connection has dropped' if time_remaining <= 0: log.error(msg) await self.disconnect(AblyException(msg, 408, 80003)) diff --git a/ably/types/authoptions.py b/ably/types/authoptions.py index f61a57f5..503e6b4d 100644 --- a/ably/types/authoptions.py +++ b/ably/types/authoptions.py @@ -2,11 +2,22 @@ class AuthOptions: - def __init__(self, auth_callback=None, auth_url=None, auth_method='GET', - auth_token=None, auth_headers=None, auth_params=None, - key_name=None, key_secret=None, key=None, query_time=False, - token_details=None, use_token_auth=None, - default_token_params=None): + def __init__( + self, + auth_callback=None, + auth_url=None, + auth_method='GET', + auth_token=None, + auth_headers=None, + auth_params=None, + key_name=None, + key_secret=None, + key=None, + query_time=False, + token_details=None, + use_token_auth=None, + default_token_params=None, + ): self.__auth_options = {} self.auth_options['auth_callback'] = auth_callback self.auth_options['auth_url'] = auth_url @@ -34,9 +45,7 @@ def set_key(self, key): self.auth_options['key_name'] = key_name self.auth_options['key_secret'] = key_secret except ValueError: - raise AblyException("key of not len 2 parameters: {0}" - .format(key.split(':')), - 401, 40101) + raise AblyException('key of not len 2 parameters: {0}'.format(key.split(':')), 401, 40101) def replace(self, auth_options): if type(auth_options) is dict: diff --git a/ably/types/channeldetails.py b/ably/types/channeldetails.py index d959d487..0be6a7e8 100644 --- a/ably/types/channeldetails.py +++ b/ably/types/channeldetails.py @@ -2,7 +2,6 @@ class ChannelDetails: - def __init__(self, channel_id, status): self.__channel_id = channel_id self.__status = status @@ -17,16 +16,12 @@ def status(self) -> ChannelStatus: @staticmethod def from_dict(obj): - kwargs = { - 'channel_id': obj.get("channelId"), - 'status': ChannelStatus.from_dict(obj.get("status")) - } + kwargs = {'channel_id': obj.get('channelId'), 'status': ChannelStatus.from_dict(obj.get('status'))} return ChannelDetails(**kwargs) class ChannelStatus: - def __init__(self, is_active, occupancy): self.__is_active = is_active self.__occupancy = occupancy @@ -41,16 +36,12 @@ def occupancy(self) -> ChannelOccupancy: @staticmethod def from_dict(obj): - kwargs = { - 'is_active': obj.get("isActive"), - 'occupancy': ChannelOccupancy.from_dict(obj.get("occupancy")) - } + kwargs = {'is_active': obj.get('isActive'), 'occupancy': ChannelOccupancy.from_dict(obj.get('occupancy'))} return ChannelStatus(**kwargs) class ChannelOccupancy: - def __init__(self, metrics): self.__metrics = metrics @@ -60,17 +51,15 @@ def metrics(self) -> ChannelMetrics: @staticmethod def from_dict(obj): - kwargs = { - 'metrics': ChannelMetrics.from_dict(obj.get("metrics")) - } + kwargs = {'metrics': ChannelMetrics.from_dict(obj.get('metrics'))} return ChannelOccupancy(**kwargs) class ChannelMetrics: - - def __init__(self, connections, presence_connections, presence_members, - presence_subscribers, publishers, subscribers): + def __init__( + self, connections, presence_connections, presence_members, presence_subscribers, publishers, subscribers + ): self.__connections = connections self.__presence_connections = presence_connections self.__presence_members = presence_members @@ -105,12 +94,12 @@ def subscribers(self) -> int: @staticmethod def from_dict(obj): kwargs = { - 'connections': obj.get("connections"), - 'presence_connections': obj.get("presenceConnections"), - 'presence_members': obj.get("presenceMembers"), - 'presence_subscribers': obj.get("presenceSubscribers"), - 'publishers': obj.get("publishers"), - 'subscribers': obj.get("subscribers") + 'connections': obj.get('connections'), + 'presence_connections': obj.get('presenceConnections'), + 'presence_members': obj.get('presenceMembers'), + 'presence_subscribers': obj.get('presenceSubscribers'), + 'publishers': obj.get('publishers'), + 'subscribers': obj.get('subscribers'), } return ChannelMetrics(**kwargs) diff --git a/ably/types/channelsubscription.py b/ably/types/channelsubscription.py index b4c0dbf8..62e26d78 100644 --- a/ably/types/channelsubscription.py +++ b/ably/types/channelsubscription.py @@ -2,7 +2,6 @@ class PushChannelSubscription: - def __init__(self, channel, device_id=None, client_id=None, app_id=None): if not device_id and not client_id: raise ValueError('missing expected device or client id') diff --git a/ably/types/connectiondetails.py b/ably/types/connectiondetails.py index a281daed..60ffebb2 100644 --- a/ably/types/connectiondetails.py +++ b/ably/types/connectiondetails.py @@ -7,8 +7,7 @@ class ConnectionDetails: max_idle_interval: int connection_key: str - def __init__(self, connection_state_ttl: int, max_idle_interval: int, - connection_key: str, client_id: str): + def __init__(self, connection_state_ttl: int, max_idle_interval: int, connection_key: str, client_id: str): self.connection_state_ttl = connection_state_ttl self.max_idle_interval = max_idle_interval self.connection_key = connection_key @@ -16,5 +15,9 @@ def __init__(self, connection_state_ttl: int, max_idle_interval: int, @staticmethod def from_dict(json_dict: dict): - return ConnectionDetails(json_dict.get('connectionStateTtl'), json_dict.get('maxIdleInterval'), - json_dict.get('connectionKey'), json_dict.get('clientId')) + return ConnectionDetails( + json_dict.get('connectionStateTtl'), + json_dict.get('maxIdleInterval'), + json_dict.get('connectionKey'), + json_dict.get('clientId'), + ) diff --git a/ably/types/device.py b/ably/types/device.py index 337de002..3117676d 100644 --- a/ably/types/device.py +++ b/ably/types/device.py @@ -7,10 +7,20 @@ class DeviceDetails: - - def __init__(self, id, client_id=None, form_factor=None, metadata=None, - platform=None, push=None, update_token=None, app_id=None, - device_identity_token=None, modified=None, device_secret=None): + def __init__( + self, + id, + client_id=None, + form_factor=None, + metadata=None, + platform=None, + push=None, + update_token=None, + app_id=None, + device_identity_token=None, + modified=None, + device_secret=None, + ): if push: recipient = push.get('recipient') @@ -82,8 +92,19 @@ def device_secret(self): return self.__device_secret def as_dict(self): - keys = ['id', 'client_id', 'form_factor', 'metadata', 'platform', - 'push', 'update_token', 'app_id', 'device_identity_token', 'modified', 'device_secret'] + keys = [ + 'id', + 'client_id', + 'form_factor', + 'metadata', + 'platform', + 'push', + 'update_token', + 'app_id', + 'device_identity_token', + 'modified', + 'device_secret', + ] obj = {} for key in keys: diff --git a/ably/types/message.py b/ably/types/message.py index 240ab173..a2843599 100644 --- a/ably/types/message.py +++ b/ably/types/message.py @@ -18,22 +18,22 @@ def to_text(value): elif isinstance(value, bytes): return value.decode() else: - raise TypeError("expected string or bytes, not %s" % type(value)) + raise TypeError('expected string or bytes, not %s' % type(value)) class Message(EncodeDataMixin): - - def __init__(self, - name=None, # TM2g - data=None, # TM2d - client_id=None, # TM2b - id=None, # TM2a - connection_id=None, # TM2c - connection_key=None, # TM2h - encoding='', # TM2e - timestamp=None, # TM2f - extras=None, # TM2i - ): + def __init__( + self, + name=None, # TM2g + data=None, # TM2d + client_id=None, # TM2b + id=None, # TM2a + connection_id=None, # TM2c + connection_key=None, # TM2h + encoding='', # TM2e + timestamp=None, # TM2f + extras=None, # TM2i + ): super().__init__(encoding) @@ -48,10 +48,12 @@ def __init__(self, def __eq__(self, other): if isinstance(other, Message): - return (self.name == other.name - and self.data == other.data - and self.client_id == other.client_id - and self.timestamp == other.timestamp) + return ( + self.name == other.name + and self.data == other.data + and self.client_id == other.client_id + and self.timestamp == other.timestamp + ) return NotImplemented def __ne__(self, other): @@ -112,8 +114,7 @@ def encrypt(self, channel_cipher): if typed_data.buffer is None: return True encrypted_data = channel_cipher.encrypt(typed_data.buffer) - self.__data = CipherData(encrypted_data, typed_data.type, - cipher_type=channel_cipher.cipher_type) + self.__data = CipherData(encrypted_data, typed_data.type, cipher_type=channel_cipher.cipher_type) @staticmethod def decrypt_data(channel_cipher, data): @@ -155,7 +156,7 @@ def as_dict(self, binary=False): data = bytes(data) if not (isinstance(data, (bytes, str, list, dict, bytearray)) or data is None): - raise AblyException("Invalid data payload", 400, 40011) + raise AblyException('Invalid data payload', 400, 40011) request_body = { 'name': self.name, @@ -197,16 +198,16 @@ def from_encoded(obj, cipher=None): client_id=client_id, timestamp=timestamp, extras=extras, - **decoded_data + **decoded_data, ) @staticmethod def __update_empty_fields(proto_msg: dict, msg: dict, msg_index: int): - if msg.get("id") is None or msg.get("id") == '': + if msg.get('id') is None or msg.get('id') == '': msg['id'] = f"{proto_msg.get('id')}:{msg_index}" - if msg.get("connectionId") is None or msg.get("connectionId") == '': + if msg.get('connectionId') is None or msg.get('connectionId') == '': msg['connectionId'] = proto_msg.get('connectionId') - if msg.get("timestamp") is None or msg.get("timestamp") == 0: + if msg.get('timestamp') is None or msg.get('timestamp') == 0: msg['timestamp'] = proto_msg.get('timestamp') @staticmethod @@ -230,4 +231,5 @@ def make_message_response_handler(cipher): def encrypted_message_response_handler(response): messages = response.to_native() return Message.from_encoded_array(messages, cipher=cipher) + return encrypted_message_response_handler diff --git a/ably/types/mixins.py b/ably/types/mixins.py index 0756ea0d..438a4737 100644 --- a/ably/types/mixins.py +++ b/ably/types/mixins.py @@ -9,7 +9,6 @@ class EncodeDataMixin: - def __init__(self, encoding): self.encoding = encoding @@ -52,8 +51,9 @@ def decode(data, encoding='', cipher=None): data = bytearray(base64.b64decode(data.encode('utf-8'))) elif encoding.startswith('%s+' % CipherData.ENCODING_ID): if not cipher: - log.error('Message cannot be decrypted as the channel is ' - 'not set up for encryption & decryption') + log.error( + 'Message cannot be decrypted as the channel is ' 'not set up for encryption & decryption' + ) encoding_list.append(encoding) break data = cipher.decrypt(data) @@ -62,8 +62,7 @@ def decode(data, encoding='', cipher=None): elif encoding == 'utf-8': pass else: - log.error('Message cannot be decoded. ' - "Unsupported encoding type: '%s'" % encoding) + log.error('Message cannot be decoded. ' "Unsupported encoding type: '%s'" % encoding) encoding_list.append(encoding) break diff --git a/ably/types/options.py b/ably/types/options.py index abfe41c6..450991b3 100644 --- a/ably/types/options.py +++ b/ably/types/options.py @@ -8,13 +8,36 @@ class Options(AuthOptions): - def __init__(self, client_id=None, log_level=0, tls=True, rest_host=None, realtime_host=None, port=0, - tls_port=0, use_binary_protocol=True, queue_messages=False, recover=False, environment=None, - http_open_timeout=None, http_request_timeout=None, realtime_request_timeout=None, - http_max_retry_count=None, http_max_retry_duration=None, fallback_hosts=None, - fallback_retry_timeout=None, disconnected_retry_timeout=None, 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, **kwargs): + def __init__( + self, + client_id=None, + log_level=0, + tls=True, + rest_host=None, + realtime_host=None, + port=0, + tls_port=0, + use_binary_protocol=True, + queue_messages=False, + recover=False, + environment=None, + http_open_timeout=None, + http_request_timeout=None, + realtime_request_timeout=None, + http_max_retry_count=None, + http_max_retry_duration=None, + fallback_hosts=None, + fallback_retry_timeout=None, + disconnected_retry_timeout=None, + 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, + **kwargs, + ): super().__init__(**kwargs) @@ -44,6 +67,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 + idempotent_rest_publishing = api_version >= '1.2' if environment is None: @@ -304,7 +328,7 @@ def __get_realtime_hosts(self): if self.realtime_host is not None: host = self.realtime_host return [host] - elif self.environment != "production": + elif self.environment != 'production': host = f'{self.environment}-{Defaults.realtime_host}' else: host = Defaults.realtime_host diff --git a/ably/types/presence.py b/ably/types/presence.py index 0af7799f..228a3917 100644 --- a/ably/types/presence.py +++ b/ably/types/presence.py @@ -25,18 +25,18 @@ class PresenceAction: class PresenceMessage(EncodeDataMixin): - - def __init__(self, - id=None, # TP3a - action=None, # TP3b - client_id=None, # TP3c - connection_id=None, # TP3d - data=None, # TP3e - encoding=None, # TP3f - timestamp=None, # TP3g - member_key=None, # TP3h (for RT only) - extras=None, # TP3i (functionality not specified) - ): + def __init__( + self, + id=None, # TP3a + action=None, # TP3b + client_id=None, # TP3c + connection_id=None, # TP3d + data=None, # TP3e + encoding=None, # TP3f + timestamp=None, # TP3g + member_key=None, # TP3h (for RT only) + extras=None, # TP3i (functionality not specified) + ): self.__id = id self.__action = action @@ -79,7 +79,7 @@ def timestamp(self): @property def member_key(self): if self.connection_id and self.client_id: - return "%s:%s" % (self.connection_id, self.client_id) + return '%s:%s' % (self.connection_id, self.client_id) @property def extras(self): @@ -123,26 +123,25 @@ def __init__(self, channel): def _path_with_qs(self, rel_path, qs=None): path = rel_path if qs: - path += ('?' + parse.urlencode(qs)) + path += '?' + parse.urlencode(qs) return path async def get(self, limit=None): qs = {} if limit: if limit > 1000: - raise ValueError("The maximum allowed limit is 1000") + raise ValueError('The maximum allowed limit is 1000') qs['limit'] = limit path = self._path_with_qs(self.__base_path + 'presence', qs) presence_handler = make_presence_response_handler(self.__cipher) - return await PaginatedResult.paginated_query( - self.__http, url=path, response_processor=presence_handler) + return await PaginatedResult.paginated_query(self.__http, url=path, response_processor=presence_handler) async def history(self, limit=None, direction=None, start=None, end=None): qs = {} if limit: if limit > 1000: - raise ValueError("The maximum allowed limit is 1000") + raise ValueError('The maximum allowed limit is 1000') qs['limit'] = limit if direction: qs['direction'] = direction @@ -163,12 +162,12 @@ async def history(self, limit=None, direction=None, start=None, end=None): path = self._path_with_qs(self.__base_path + 'presence/history', qs) presence_handler = make_presence_response_handler(self.__cipher) - return await PaginatedResult.paginated_query( - self.__http, url=path, response_processor=presence_handler) + return await PaginatedResult.paginated_query(self.__http, url=path, response_processor=presence_handler) def make_presence_response_handler(cipher): def encrypted_presence_response_handler(response): messages = response.to_native() return PresenceMessage.from_encoded_array(messages, cipher=cipher) + return encrypted_presence_response_handler diff --git a/ably/types/stats.py b/ably/types/stats.py index ead5e548..ec9b425e 100644 --- a/ably/types/stats.py +++ b/ably/types/stats.py @@ -5,7 +5,6 @@ class Stats: - def __init__(self, entries=None, unit=None, interval_id=None, in_progress=None, app_id=None, schema=None): self.interval_id = interval_id or '' self.entries = entries @@ -20,12 +19,12 @@ def from_dict(cls, stats_dict): stats_dict = stats_dict or {} kwargs = { - "entries": stats_dict.get("entries"), - "unit": stats_dict.get("unit"), - "interval_id": stats_dict.get("intervalId"), - "in_progress": stats_dict.get("inProgress"), - "app_id": stats_dict.get("appId"), - "schema": stats_dict.get("schema"), + 'entries': stats_dict.get('entries'), + 'unit': stats_dict.get('unit'), + 'interval_id': stats_dict.get('intervalId'), + 'in_progress': stats_dict.get('inProgress'), + 'app_id': stats_dict.get('appId'), + 'schema': stats_dict.get('schema'), } return cls(**kwargs) @@ -59,7 +58,7 @@ def granularity_from_interval_id(interval_id): return key except ValueError: pass - raise ValueError("Unsupported intervalId") + raise ValueError('Unsupported intervalId') def interval_from_interval_id(interval_id): diff --git a/ably/types/tokendetails.py b/ably/types/tokendetails.py index f3b79e47..89c1d439 100644 --- a/ably/types/tokendetails.py +++ b/ably/types/tokendetails.py @@ -12,8 +12,7 @@ class TokenDetails: # new requests 9000ms before it expires TOKEN_EXPIRY_BUFFER = 15 * 1000 - def __init__(self, token=None, expires=None, issued=0, - capability=None, client_id=None): + def __init__(self, token=None, expires=None, issued=0, capability=None, client_id=None): if expires is None: self.__expires = time.time() * 1000 + TokenDetails.DEFAULTS['ttl'] else: @@ -60,14 +59,10 @@ def to_dict(self): @staticmethod def from_dict(obj): - kwargs = { - 'token': obj.get("token"), - 'capability': obj.get("capability"), - 'client_id': obj.get("clientId") - } - expires = obj.get("expires") + kwargs = {'token': obj.get('token'), 'capability': obj.get('capability'), 'client_id': obj.get('clientId')} + expires = obj.get('expires') kwargs['expires'] = expires if expires is None else int(expires) - issued = obj.get("issued") + issued = obj.get('issued') kwargs['issued'] = issued if issued is None else int(issued) return TokenDetails(**kwargs) @@ -89,9 +84,11 @@ def from_json(data): def __eq__(self, other): if isinstance(other, TokenDetails): - return (self.expires == other.expires - and self.token == other.token - and self.issued == other.issued - and self.capability == other.capability - and self.client_id == other.client_id) + return ( + self.expires == other.expires + and self.token == other.token + and self.issued == other.issued + and self.capability == other.capability + and self.client_id == other.client_id + ) return NotImplemented diff --git a/ably/types/tokenrequest.py b/ably/types/tokenrequest.py index d10a5eb3..75f941c7 100644 --- a/ably/types/tokenrequest.py +++ b/ably/types/tokenrequest.py @@ -5,9 +5,9 @@ class TokenRequest: - - def __init__(self, key_name=None, client_id=None, nonce=None, mac=None, - capability=None, ttl=None, timestamp=None): + def __init__( + self, key_name=None, client_id=None, nonce=None, mac=None, capability=None, ttl=None, timestamp=None + ): self.__key_name = key_name self.__client_id = client_id self.__nonce = nonce @@ -17,15 +17,20 @@ def __init__(self, key_name=None, client_id=None, nonce=None, mac=None, self.__timestamp = timestamp def sign_request(self, key_secret): - sign_text = "\n".join([str(x) for x in [ - self.key_name or "", - self.ttl or "", - self.capability or "", - self.client_id or "", - "%d" % (self.timestamp or 0), - self.nonce or "", - "", # to get the trailing new line - ]]) + sign_text = '\n'.join( + [ + str(x) + for x in [ + self.key_name or '', + self.ttl or '', + self.capability or '', + self.client_id or '', + '%d' % (self.timestamp or 0), + self.nonce or '', + '', # to get the trailing new line + ] + ] + ) try: key_secret = key_secret.encode('utf8') except AttributeError: @@ -45,7 +50,7 @@ def to_dict(self): 'nonce': self.nonce, 'capability': self.capability, 'timestamp': self.timestamp, - 'mac': self.mac + 'mac': self.mac, } @staticmethod @@ -65,13 +70,15 @@ def from_json(data): def __eq__(self, other): if isinstance(other, TokenRequest): - return (self.key_name == other.key_name - and self.client_id == other.client_id - and self.nonce == other.nonce - and self.mac == other.mac - and self.capability == other.capability - and self.ttl == other.ttl - and self.timestamp == other.timestamp) + return ( + self.key_name == other.key_name + and self.client_id == other.client_id + and self.nonce == other.nonce + and self.mac == other.mac + and self.capability == other.capability + and self.ttl == other.ttl + and self.timestamp == other.timestamp + ) return NotImplemented @property diff --git a/ably/types/typedbuffer.py b/ably/types/typedbuffer.py index 56adcd88..e8a45338 100644 --- a/ably/types/typedbuffer.py +++ b/ably/types/typedbuffer.py @@ -22,18 +22,20 @@ class Limits: INT32_MAX = 2 ** 31 INT32_MIN = -(2 ** 31 + 1) INT64_MAX = 2 ** 63 - INT64_MIN = - (2 ** 63 + 1) - - -_decoders = {DataType.TRUE: lambda b: True, - DataType.FALSE: lambda b: False, - DataType.INT32: lambda b: struct.unpack('>i', b)[0], - DataType.INT64: lambda b: struct.unpack('>q', b)[0], - DataType.DOUBLE: lambda b: struct.unpack('>d', b)[0], - DataType.STRING: lambda b: b.decode('utf-8'), - DataType.BUFFER: lambda b: b, - DataType.JSONARRAY: lambda b: json.loads(b.decode('utf-8')), - DataType.JSONOBJECT: lambda b: json.loads(b.decode('utf-8'))} + INT64_MIN = -(2 ** 63 + 1) + + +_decoders = { + DataType.TRUE: lambda b: True, + DataType.FALSE: lambda b: False, + DataType.INT32: lambda b: struct.unpack('>i', b)[0], + DataType.INT64: lambda b: struct.unpack('>q', b)[0], + DataType.DOUBLE: lambda b: struct.unpack('>d', b)[0], + DataType.STRING: lambda b: b.decode('utf-8'), + DataType.BUFFER: lambda b: b, + DataType.JSONARRAY: lambda b: json.loads(b.decode('utf-8')), + DataType.JSONOBJECT: lambda b: json.loads(b.decode('utf-8')), +} class TypedBuffer: diff --git a/ably/util/crypto.py b/ably/util/crypto.py index acd558b6..db1bd29e 100644 --- a/ably/util/crypto.py +++ b/ably/util/crypto.py @@ -44,8 +44,7 @@ def mode(self): class CbcChannelCipher: def __init__(self, cipher_params): - self.__secret_key = (cipher_params.secret_key or - self.__random(cipher_params.key_length / 8)) + self.__secret_key = cipher_params.secret_key or self.__random(cipher_params.key_length / 8) if isinstance(self.__secret_key, str): self.__secret_key = self.__secret_key.encode() self.__iv = cipher_params.iv or self.__random(16) @@ -94,14 +93,14 @@ def encrypt(self, plaintext): plaintext = bytes(plaintext) padded_plaintext = self.__pad(plaintext) encrypted = self.__iv + self.__encryptor.encrypt(padded_plaintext) - self.__iv = encrypted[-self.__block_size:] + self.__iv = encrypted[-self.__block_size :] return encrypted def decrypt(self, ciphertext): if isinstance(ciphertext, bytearray): ciphertext = bytes(ciphertext) - iv = ciphertext[:self.__block_size] - ciphertext = ciphertext[self.__block_size:] + iv = ciphertext[: self.__block_size] + ciphertext = ciphertext[self.__block_size :] decryptor = AES.new(self.__secret_key, AES.MODE_CBC, iv) decrypted = decryptor.decrypt(ciphertext) return bytearray(self.__unpad(decrypted)) @@ -116,8 +115,7 @@ def iv(self): @property def cipher_type(self): - return ("%s-%s-%s" % (self.__algorithm, self.__key_length, - self.__mode)).lower() + return ('%s-%s-%s' % (self.__algorithm, self.__key_length, self.__mode)).lower() class CipherData(TypedBuffer): @@ -143,7 +141,7 @@ def generate_random_key(length=DEFAULT_KEYLENGTH): def get_default_params(params=None): if type(params) in [str, bytes]: - raise ValueError("Calling get_default_params with a key directly is deprecated, it expects a params dict") + raise ValueError('Calling get_default_params with a key directly is deprecated, it expects a params dict') key = params.get('key') algorithm = params.get('algorithm') or 'AES' @@ -151,7 +149,7 @@ def get_default_params(params=None): mode = params.get('mode') or 'CBC' if not key: - raise ValueError("Crypto.get_default_params: a key is required") + raise ValueError('Crypto.get_default_params: a key is required') if type(key) == str: key = base64.b64decode(key) @@ -176,4 +174,5 @@ def validate_cipher_params(cipher_params): return raise ValueError( 'Unsupported key length %s for aes-cbc encryption. Encryption key must be 128 or 256 bits' - ' (16 or 32 ASCII characters)' % key_length) + ' (16 or 32 ASCII characters)' % key_length + ) diff --git a/ably/util/eventemitter.py b/ably/util/eventemitter.py index 4d2bfb41..00e90d88 100644 --- a/ably/util/eventemitter.py +++ b/ably/util/eventemitter.py @@ -66,15 +66,18 @@ def on(self, *args): emitter = self.__named_event_emitter # self.__named_event_emitter.add_listener(args[0], args[1]) else: - raise ValueError("EventEmitter.on(): invalid args") + raise ValueError('EventEmitter.on(): invalid args') if asyncio.iscoroutinefunction(listener): + async def wrapped_listener(*args, **kwargs): try: await listener(*args, **kwargs) except Exception as err: log.exception(f'EventEmitter.emit(): uncaught listener exception: {err}') + else: + def wrapped_listener(*args, **kwargs): try: listener(*args, **kwargs) @@ -111,15 +114,18 @@ def once(self, *args): emitter = self.__named_event_emitter # self.__named_event_emitter.add_listener(args[0], args[1]) else: - raise ValueError("EventEmitter.on(): invalid args") + raise ValueError('EventEmitter.on(): invalid args') if asyncio.iscoroutinefunction(listener): + async def wrapped_listener(*args, **kwargs): try: await listener(*args, **kwargs) except Exception as err: log.exception(f'EventEmitter.emit(): uncaught listener exception: {err}') + else: + def wrapped_listener(*args, **kwargs): try: listener(*args, **kwargs) @@ -155,7 +161,7 @@ def off(self, *args): listener = args[1] emitter = self.__named_event_emitter else: - raise ValueError("EventEmitter.once(): invalid args") + raise ValueError('EventEmitter.once(): invalid args') wrapped_listener = self.__wrapped_listeners.get(listener) diff --git a/ably/util/exceptions.py b/ably/util/exceptions.py index 8b98c5ee..72bf2873 100644 --- a/ably/util/exceptions.py +++ b/ably/util/exceptions.py @@ -37,12 +37,10 @@ def raise_for_response(response): try: json_response = response.json() except Exception: - log.debug("Response not json: %d %s", - response.status_code, - response.text) - raise AblyException(message=response.text, - status_code=response.status_code, - code=response.status_code * 100) + log.debug('Response not json: %d %s', response.status_code, response.text) + raise AblyException( + message=response.text, status_code=response.status_code, code=response.status_code * 100 + ) if json_response and 'error' in json_response: error = json_response['error'] @@ -53,19 +51,17 @@ def raise_for_response(response): code=int(error['code']), ) except KeyError: - msg = "Unexpected exception decoding server response: %s" + msg = 'Unexpected exception decoding server response: %s' msg = msg % response.text raise AblyException(message=msg, status_code=500, code=50000) - raise AblyException(message="", - status_code=response.status_code, - code=response.status_code * 100) + raise AblyException(message='', status_code=response.status_code, code=response.status_code * 100) @staticmethod def from_exception(e): if isinstance(e, AblyException): return e - return AblyException("Unexpected exception: %s" % e, 500, 50000) + return AblyException('Unexpected exception: %s' % e, 500, 50000) @staticmethod def from_dict(value: dict): diff --git a/ably/util/nocrypto.py b/ably/util/nocrypto.py index a66669b3..d8126d7f 100644 --- a/ably/util/nocrypto.py +++ b/ably/util/nocrypto.py @@ -1,9 +1,6 @@ - class InstallPycrypto: def __getattr__(self, name): - raise ImportError( - "This requires to install ably with crypto support: pip install 'ably[crypto]'" - ) + raise ImportError("This requires to install ably with crypto support: pip install 'ably[crypto]'") AES = Random = InstallPycrypto() diff --git a/poetry.lock b/poetry.lock index 1510fa0e..a0632a77 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,10 +1,9 @@ -# This file is automatically @generated by Poetry and should not be changed by hand. +# This file is automatically @generated by Poetry 1.6.1 and should not be changed by hand. [[package]] name = "anyio" version = "3.7.1" description = "High level compatibility layer for multiple asynchronous event loop implementations" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -27,18 +26,66 @@ trio = ["trio (<0.22)"] name = "async-case" version = "10.1.0" description = "Backport of Python 3.8's unittest.async_case" -category = "dev" optional = false python-versions = "*" files = [ {file = "async_case-10.1.0.tar.gz", hash = "sha256:b819f68c78f6c640ab1101ecf69fac189402b490901fa2abc314c48edab5d3da"}, ] +[[package]] +name = "black" +version = "21.12b0" +description = "The uncompromising code formatter." +optional = false +python-versions = ">=3.6.2" +files = [ + {file = "black-21.12b0-py3-none-any.whl", hash = "sha256:a615e69ae185e08fdd73e4715e260e2479c861b5740057fde6e8b4e3b7dd589f"}, + {file = "black-21.12b0.tar.gz", hash = "sha256:77b80f693a569e2e527958459634f18df9b0ba2625ba4e0c2d5da5be42e6f2b3"}, +] + +[package.dependencies] +click = ">=7.1.2" +mypy-extensions = ">=0.4.3" +pathspec = ">=0.9.0,<1" +platformdirs = ">=2" +tomli = ">=0.2.6,<2.0.0" +typed-ast = {version = ">=1.4.2", markers = "python_version < \"3.8\" and implementation_name == \"cpython\""} +typing-extensions = [ + {version = ">=3.10.0.0,<3.10.0.1 || >3.10.0.1", markers = "python_version >= \"3.10\""}, + {version = ">=3.10.0.0", markers = "python_version < \"3.10\""}, +] + +[package.extras] +colorama = ["colorama (>=0.4.3)"] +d = ["aiohttp (>=3.7.4)"] +jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] +python2 = ["typed-ast (>=1.4.3)"] +uvloop = ["uvloop (>=0.15.2)"] + +[[package]] +name = "brunette" +version = "0.2.8" +description = "A best practice Python code formatter" +optional = false +python-versions = "*" +files = [ + {file = "brunette-0.2.8-py2.py3-none-any.whl", hash = "sha256:288e963a423a495fbe69019e101e621773bb758c990d32b2173c0381830abdc0"}, + {file = "brunette-0.2.8.tar.gz", hash = "sha256:e7d0766d3a4b0d18bf0f8830b4bc98a4af4ebcccf89c3b145fc92f9d4727d79b"}, +] + +[package.dependencies] +black = "21.12b0" +click = "*" +setuptools = "*" +wheel = "*" + +[package.extras] +dev = ["coverage (==5.1)", "flake8 (==3.8.0a2)", "ipdb (==0.13.2)", "mccabe (==0.6.1)", "pep8-naming (==0.10.0)", "pytest (==5.4.1)", "pytest-cov (==2.8.1)", "tox (==3.15.0)", "zest.releaser (==6.20.1)"] + [[package]] name = "certifi" version = "2023.7.22" description = "Python package for providing Mozilla's CA Bundle." -category = "main" optional = false python-versions = ">=3.6" files = [ @@ -46,11 +93,25 @@ files = [ {file = "certifi-2023.7.22.tar.gz", hash = "sha256:539cc1d13202e33ca466e88b2807e29f4c13049d6d87031a3c110744495cb082"}, ] +[[package]] +name = "click" +version = "8.1.7" +description = "Composable command line interface toolkit" +optional = false +python-versions = ">=3.7" +files = [ + {file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"}, + {file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "platform_system == \"Windows\""} +importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} + [[package]] name = "colorama" version = "0.4.6" description = "Cross-platform colored terminal text." -category = "dev" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" files = [ @@ -62,7 +123,6 @@ files = [ name = "coverage" version = "7.2.7" description = "Code coverage measurement for Python" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -135,7 +195,6 @@ toml = ["tomli"] name = "exceptiongroup" version = "1.1.3" description = "Backport of PEP 654 (exception groups)" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -150,7 +209,6 @@ test = ["pytest (>=6)"] name = "execnet" version = "2.0.2" description = "execnet: rapid multi-Python deployment" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -165,7 +223,6 @@ testing = ["hatch", "pre-commit", "pytest", "tox"] name = "flake8" version = "3.9.2" description = "the modular source code checker: pep8 pyflakes and co" -category = "dev" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" files = [ @@ -183,7 +240,6 @@ pyflakes = ">=2.3.0,<2.4.0" name = "h11" version = "0.14.0" description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -198,7 +254,6 @@ typing-extensions = {version = "*", markers = "python_version < \"3.8\""} name = "h2" version = "4.1.0" description = "HTTP/2 State-Machine based protocol implementation" -category = "main" optional = false python-versions = ">=3.6.1" files = [ @@ -214,7 +269,6 @@ hyperframe = ">=6.0,<7" name = "hpack" version = "4.0.0" description = "Pure-Python HPACK header compression" -category = "main" optional = false python-versions = ">=3.6.1" files = [ @@ -226,7 +280,6 @@ files = [ name = "httpcore" version = "0.17.3" description = "A minimal low-level HTTP client." -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -238,17 +291,16 @@ files = [ anyio = ">=3.0,<5.0" certifi = "*" h11 = ">=0.13,<0.15" -sniffio = ">=1.0.0,<2.0.0" +sniffio = "==1.*" [package.extras] http2 = ["h2 (>=3,<5)"] -socks = ["socksio (>=1.0.0,<2.0.0)"] +socks = ["socksio (==1.*)"] [[package]] name = "httpx" version = "0.24.1" description = "The next generation HTTP client." -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -265,15 +317,14 @@ sniffio = "*" [package.extras] brotli = ["brotli", "brotlicffi"] -cli = ["click (>=8.0.0,<9.0.0)", "pygments (>=2.0.0,<3.0.0)", "rich (>=10,<14)"] +cli = ["click (==8.*)", "pygments (==2.*)", "rich (>=10,<14)"] http2 = ["h2 (>=3,<5)"] -socks = ["socksio (>=1.0.0,<2.0.0)"] +socks = ["socksio (==1.*)"] [[package]] name = "hyperframe" version = "6.0.1" description = "HTTP/2 framing layer for Python" -category = "main" optional = false python-versions = ">=3.6.1" files = [ @@ -285,7 +336,6 @@ files = [ name = "idna" version = "3.4" description = "Internationalized Domain Names in Applications (IDNA)" -category = "main" optional = false python-versions = ">=3.5" files = [ @@ -297,7 +347,6 @@ files = [ name = "importlib-metadata" version = "4.13.0" description = "Read metadata from Python packages" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -318,7 +367,6 @@ testing = ["flake8 (<5)", "flufl.flake8", "importlib-resources (>=1.3)", "packag name = "iniconfig" version = "2.0.0" description = "brain-dead simple config-ini parsing" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -330,7 +378,6 @@ files = [ name = "mccabe" version = "0.6.1" description = "McCabe checker, plugin for flake8" -category = "dev" optional = false python-versions = "*" files = [ @@ -342,7 +389,6 @@ files = [ name = "methoddispatch" version = "3.0.2" description = "singledispatch decorator for class methods." -category = "main" optional = false python-versions = "*" files = [ @@ -354,7 +400,6 @@ files = [ name = "mock" version = "4.0.3" description = "Rolling backport of unittest.mock for all Pythons" -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -371,7 +416,6 @@ test = ["pytest (<5.4)", "pytest-cov"] name = "msgpack" version = "1.0.5" description = "MessagePack serializer" -category = "main" optional = false python-versions = "*" files = [ @@ -440,23 +484,43 @@ files = [ {file = "msgpack-1.0.5.tar.gz", hash = "sha256:c075544284eadc5cddc70f4757331d99dcbc16b2bbd4849d15f8aae4cf36d31c"}, ] +[[package]] +name = "mypy-extensions" +version = "1.0.0" +description = "Type system extensions for programs checked with the mypy type checker." +optional = false +python-versions = ">=3.5" +files = [ + {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, + {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, +] + [[package]] name = "packaging" -version = "23.1" +version = "23.2" description = "Core utilities for Python packages" -category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "packaging-23.1-py3-none-any.whl", hash = "sha256:994793af429502c4ea2ebf6bf664629d07c1a9fe974af92966e4b8d2df7edc61"}, - {file = "packaging-23.1.tar.gz", hash = "sha256:a392980d2b6cffa644431898be54b0045151319d1e7ec34f0cfed48767dd334f"}, + {file = "packaging-23.2-py3-none-any.whl", hash = "sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7"}, + {file = "packaging-23.2.tar.gz", hash = "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5"}, +] + +[[package]] +name = "pathspec" +version = "0.11.2" +description = "Utility library for gitignore style pattern matching of file paths." +optional = false +python-versions = ">=3.7" +files = [ + {file = "pathspec-0.11.2-py3-none-any.whl", hash = "sha256:1d6ed233af05e679efb96b1851550ea95bbb64b7c490b0f5aa52996c11e92a20"}, + {file = "pathspec-0.11.2.tar.gz", hash = "sha256:e0d8d0ac2f12da61956eb2306b69f9469b42f4deb0f3cb6ed47b9cce9996ced3"}, ] [[package]] name = "pep8-naming" version = "0.4.1" description = "Check PEP-8 naming conventions, plugin for flake8" -category = "dev" optional = false python-versions = "*" files = [ @@ -464,11 +528,28 @@ files = [ {file = "pep8_naming-0.4.1-py2.py3-none-any.whl", hash = "sha256:1b419fa45b68b61cd8c5daf4e0c96d28915ad14d3d5f35fcc1e7e95324a33a2e"}, ] +[[package]] +name = "platformdirs" +version = "3.11.0" +description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." +optional = false +python-versions = ">=3.7" +files = [ + {file = "platformdirs-3.11.0-py3-none-any.whl", hash = "sha256:e9d171d00af68be50e9202731309c4e658fd8bc76f55c11c7dd760d023bda68e"}, + {file = "platformdirs-3.11.0.tar.gz", hash = "sha256:cf8ee52a3afdb965072dcc652433e0c7e3e40cf5ea1477cd4b3b1d2eb75495b3"}, +] + +[package.dependencies] +typing-extensions = {version = ">=4.7.1", markers = "python_version < \"3.8\""} + +[package.extras] +docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.1)", "sphinx-autodoc-typehints (>=1.24)"] +test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4)", "pytest-cov (>=4.1)", "pytest-mock (>=3.11.1)"] + [[package]] name = "pluggy" version = "1.2.0" description = "plugin and hook calling mechanisms for python" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -487,7 +568,6 @@ testing = ["pytest", "pytest-benchmark"] name = "py" version = "1.11.0" description = "library with cross-python path, ini-parsing, io, code, log facilities" -category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" files = [ @@ -499,7 +579,6 @@ files = [ name = "pycodestyle" version = "2.7.0" description = "Python style guide checker" -category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" files = [ @@ -511,7 +590,6 @@ files = [ name = "pycrypto" version = "2.6.1" description = "Cryptographic modules for Python." -category = "main" optional = true python-versions = "*" files = [ @@ -520,51 +598,49 @@ files = [ [[package]] name = "pycryptodome" -version = "3.18.0" +version = "3.19.0" description = "Cryptographic library for Python" -category = "main" optional = true python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" files = [ - {file = "pycryptodome-3.18.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:d1497a8cd4728db0e0da3c304856cb37c0c4e3d0b36fcbabcc1600f18504fc54"}, - {file = "pycryptodome-3.18.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:928078c530da78ff08e10eb6cada6e0dff386bf3d9fa9871b4bbc9fbc1efe024"}, - {file = "pycryptodome-3.18.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:157c9b5ba5e21b375f052ca78152dd309a09ed04703fd3721dce3ff8ecced148"}, - {file = "pycryptodome-3.18.0-cp27-cp27m-manylinux2014_aarch64.whl", hash = "sha256:d20082bdac9218649f6abe0b885927be25a917e29ae0502eaf2b53f1233ce0c2"}, - {file = "pycryptodome-3.18.0-cp27-cp27m-musllinux_1_1_aarch64.whl", hash = "sha256:e8ad74044e5f5d2456c11ed4cfd3e34b8d4898c0cb201c4038fe41458a82ea27"}, - {file = "pycryptodome-3.18.0-cp27-cp27m-win32.whl", hash = "sha256:62a1e8847fabb5213ccde38915563140a5b338f0d0a0d363f996b51e4a6165cf"}, - {file = "pycryptodome-3.18.0-cp27-cp27m-win_amd64.whl", hash = "sha256:16bfd98dbe472c263ed2821284118d899c76968db1a6665ade0c46805e6b29a4"}, - {file = "pycryptodome-3.18.0-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:7a3d22c8ee63de22336679e021c7f2386f7fc465477d59675caa0e5706387944"}, - {file = "pycryptodome-3.18.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:78d863476e6bad2a592645072cc489bb90320972115d8995bcfbee2f8b209918"}, - {file = "pycryptodome-3.18.0-cp27-cp27mu-manylinux2014_aarch64.whl", hash = "sha256:b6a610f8bfe67eab980d6236fdc73bfcdae23c9ed5548192bb2d530e8a92780e"}, - {file = "pycryptodome-3.18.0-cp27-cp27mu-musllinux_1_1_aarch64.whl", hash = "sha256:422c89fd8df8a3bee09fb8d52aaa1e996120eafa565437392b781abec2a56e14"}, - {file = "pycryptodome-3.18.0-cp35-abi3-macosx_10_9_universal2.whl", hash = "sha256:9ad6f09f670c466aac94a40798e0e8d1ef2aa04589c29faa5b9b97566611d1d1"}, - {file = "pycryptodome-3.18.0-cp35-abi3-macosx_10_9_x86_64.whl", hash = "sha256:53aee6be8b9b6da25ccd9028caf17dcdce3604f2c7862f5167777b707fbfb6cb"}, - {file = "pycryptodome-3.18.0-cp35-abi3-manylinux2014_aarch64.whl", hash = "sha256:10da29526a2a927c7d64b8f34592f461d92ae55fc97981aab5bbcde8cb465bb6"}, - {file = "pycryptodome-3.18.0-cp35-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f21efb8438971aa16924790e1c3dba3a33164eb4000106a55baaed522c261acf"}, - {file = "pycryptodome-3.18.0-cp35-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4944defabe2ace4803f99543445c27dd1edbe86d7d4edb87b256476a91e9ffa4"}, - {file = "pycryptodome-3.18.0-cp35-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:51eae079ddb9c5f10376b4131be9589a6554f6fd84f7f655180937f611cd99a2"}, - {file = "pycryptodome-3.18.0-cp35-abi3-musllinux_1_1_i686.whl", hash = "sha256:83c75952dcf4a4cebaa850fa257d7a860644c70a7cd54262c237c9f2be26f76e"}, - {file = "pycryptodome-3.18.0-cp35-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:957b221d062d5752716923d14e0926f47670e95fead9d240fa4d4862214b9b2f"}, - {file = "pycryptodome-3.18.0-cp35-abi3-win32.whl", hash = "sha256:795bd1e4258a2c689c0b1f13ce9684fa0dd4c0e08680dcf597cf9516ed6bc0f3"}, - {file = "pycryptodome-3.18.0-cp35-abi3-win_amd64.whl", hash = "sha256:b1d9701d10303eec8d0bd33fa54d44e67b8be74ab449052a8372f12a66f93fb9"}, - {file = "pycryptodome-3.18.0-pp27-pypy_73-manylinux2010_x86_64.whl", hash = "sha256:cb1be4d5af7f355e7d41d36d8eec156ef1382a88638e8032215c215b82a4b8ec"}, - {file = "pycryptodome-3.18.0-pp27-pypy_73-win32.whl", hash = "sha256:fc0a73f4db1e31d4a6d71b672a48f3af458f548059aa05e83022d5f61aac9c08"}, - {file = "pycryptodome-3.18.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:f022a4fd2a5263a5c483a2bb165f9cb27f2be06f2f477113783efe3fe2ad887b"}, - {file = "pycryptodome-3.18.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:363dd6f21f848301c2dcdeb3c8ae5f0dee2286a5e952a0f04954b82076f23825"}, - {file = "pycryptodome-3.18.0-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:12600268763e6fec3cefe4c2dcdf79bde08d0b6dc1813887e789e495cb9f3403"}, - {file = "pycryptodome-3.18.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:4604816adebd4faf8810782f137f8426bf45fee97d8427fa8e1e49ea78a52e2c"}, - {file = "pycryptodome-3.18.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:01489bbdf709d993f3058e2996f8f40fee3f0ea4d995002e5968965fa2fe89fb"}, - {file = "pycryptodome-3.18.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3811e31e1ac3069988f7a1c9ee7331b942e605dfc0f27330a9ea5997e965efb2"}, - {file = "pycryptodome-3.18.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6f4b967bb11baea9128ec88c3d02f55a3e338361f5e4934f5240afcb667fdaec"}, - {file = "pycryptodome-3.18.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:9c8eda4f260072f7dbe42f473906c659dcbadd5ae6159dfb49af4da1293ae380"}, - {file = "pycryptodome-3.18.0.tar.gz", hash = "sha256:c9adee653fc882d98956e33ca2c1fb582e23a8af7ac82fee75bd6113c55a0413"}, + {file = "pycryptodome-3.19.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:3006c44c4946583b6de24fe0632091c2653d6256b99a02a3db71ca06472ea1e4"}, + {file = "pycryptodome-3.19.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:7c760c8a0479a4042111a8dd2f067d3ae4573da286c53f13cf6f5c53a5c1f631"}, + {file = "pycryptodome-3.19.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:08ce3558af5106c632baf6d331d261f02367a6bc3733086ae43c0f988fe042db"}, + {file = "pycryptodome-3.19.0-cp27-cp27m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45430dfaf1f421cf462c0dd824984378bef32b22669f2635cb809357dbaab405"}, + {file = "pycryptodome-3.19.0-cp27-cp27m-musllinux_1_1_aarch64.whl", hash = "sha256:a9bcd5f3794879e91970f2bbd7d899780541d3ff439d8f2112441769c9f2ccea"}, + {file = "pycryptodome-3.19.0-cp27-cp27m-win32.whl", hash = "sha256:190c53f51e988dceb60472baddce3f289fa52b0ec38fbe5fd20dd1d0f795c551"}, + {file = "pycryptodome-3.19.0-cp27-cp27m-win_amd64.whl", hash = "sha256:22e0ae7c3a7f87dcdcf302db06ab76f20e83f09a6993c160b248d58274473bfa"}, + {file = "pycryptodome-3.19.0-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:7822f36d683f9ad7bc2145b2c2045014afdbbd1d9922a6d4ce1cbd6add79a01e"}, + {file = "pycryptodome-3.19.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:05e33267394aad6db6595c0ce9d427fe21552f5425e116a925455e099fdf759a"}, + {file = "pycryptodome-3.19.0-cp27-cp27mu-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:829b813b8ee00d9c8aba417621b94bc0b5efd18c928923802ad5ba4cf1ec709c"}, + {file = "pycryptodome-3.19.0-cp27-cp27mu-musllinux_1_1_aarch64.whl", hash = "sha256:fc7a79590e2b5d08530175823a242de6790abc73638cc6dc9d2684e7be2f5e49"}, + {file = "pycryptodome-3.19.0-cp35-abi3-macosx_10_9_universal2.whl", hash = "sha256:542f99d5026ac5f0ef391ba0602f3d11beef8e65aae135fa5b762f5ebd9d3bfb"}, + {file = "pycryptodome-3.19.0-cp35-abi3-macosx_10_9_x86_64.whl", hash = "sha256:61bb3ccbf4bf32ad9af32da8badc24e888ae5231c617947e0f5401077f8b091f"}, + {file = "pycryptodome-3.19.0-cp35-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d49a6c715d8cceffedabb6adb7e0cbf41ae1a2ff4adaeec9432074a80627dea1"}, + {file = "pycryptodome-3.19.0-cp35-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e249a784cc98a29c77cea9df54284a44b40cafbfae57636dd2f8775b48af2434"}, + {file = "pycryptodome-3.19.0-cp35-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d033947e7fd3e2ba9a031cb2d267251620964705a013c5a461fa5233cc025270"}, + {file = "pycryptodome-3.19.0-cp35-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:84c3e4fffad0c4988aef0d5591be3cad4e10aa7db264c65fadbc633318d20bde"}, + {file = "pycryptodome-3.19.0-cp35-abi3-musllinux_1_1_i686.whl", hash = "sha256:139ae2c6161b9dd5d829c9645d781509a810ef50ea8b657e2257c25ca20efe33"}, + {file = "pycryptodome-3.19.0-cp35-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:5b1986c761258a5b4332a7f94a83f631c1ffca8747d75ab8395bf2e1b93283d9"}, + {file = "pycryptodome-3.19.0-cp35-abi3-win32.whl", hash = "sha256:536f676963662603f1f2e6ab01080c54d8cd20f34ec333dcb195306fa7826997"}, + {file = "pycryptodome-3.19.0-cp35-abi3-win_amd64.whl", hash = "sha256:04dd31d3b33a6b22ac4d432b3274588917dcf850cc0c51c84eca1d8ed6933810"}, + {file = "pycryptodome-3.19.0-pp27-pypy_73-manylinux2010_x86_64.whl", hash = "sha256:8999316e57abcbd8085c91bc0ef75292c8618f41ca6d2b6132250a863a77d1e7"}, + {file = "pycryptodome-3.19.0-pp27-pypy_73-win32.whl", hash = "sha256:a0ab84755f4539db086db9ba9e9f3868d2e3610a3948cbd2a55e332ad83b01b0"}, + {file = "pycryptodome-3.19.0-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:0101f647d11a1aae5a8ce4f5fad6644ae1b22bb65d05accc7d322943c69a74a6"}, + {file = "pycryptodome-3.19.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8c1601e04d32087591d78e0b81e1e520e57a92796089864b20e5f18c9564b3fa"}, + {file = "pycryptodome-3.19.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:506c686a1eee6c00df70010be3b8e9e78f406af4f21b23162bbb6e9bdf5427bc"}, + {file = "pycryptodome-3.19.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:7919ccd096584b911f2a303c593280869ce1af9bf5d36214511f5e5a1bed8c34"}, + {file = "pycryptodome-3.19.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:560591c0777f74a5da86718f70dfc8d781734cf559773b64072bbdda44b3fc3e"}, + {file = "pycryptodome-3.19.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c1cc2f2ae451a676def1a73c1ae9120cd31af25db3f381893d45f75e77be2400"}, + {file = "pycryptodome-3.19.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:17940dcf274fcae4a54ec6117a9ecfe52907ed5e2e438fe712fe7ca502672ed5"}, + {file = "pycryptodome-3.19.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:d04f5f623a280fbd0ab1c1d8ecbd753193ab7154f09b6161b0f857a1a676c15f"}, + {file = "pycryptodome-3.19.0.tar.gz", hash = "sha256:bc35d463222cdb4dbebd35e0784155c81e161b9284e567e7e933d722e533331e"}, ] [[package]] name = "pyee" version = "9.1.1" description = "A port of node.js's EventEmitter to python." -category = "main" optional = false python-versions = "*" files = [ @@ -579,7 +655,6 @@ typing-extensions = "*" name = "pyflakes" version = "2.3.1" description = "passive checker of Python programs" -category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" files = [ @@ -589,14 +664,13 @@ files = [ [[package]] name = "pytest" -version = "7.4.0" +version = "7.4.2" description = "pytest: simple powerful testing with Python" -category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "pytest-7.4.0-py3-none-any.whl", hash = "sha256:78bf16451a2eb8c7a2ea98e32dc119fd2aa758f1d5d66dbf0a59d69a3969df32"}, - {file = "pytest-7.4.0.tar.gz", hash = "sha256:b4bf8c45bd59934ed84001ad51e11b4ee40d40a1229d2c79f9c592b0a3f6bd8a"}, + {file = "pytest-7.4.2-py3-none-any.whl", hash = "sha256:1d881c6124e08ff0a1bb75ba3ec0bfd8b5354a01c194ddd5a0a870a48d99b002"}, + {file = "pytest-7.4.2.tar.gz", hash = "sha256:a766259cfab564a2ad52cb1aae1b881a75c3eb7e34ca3779697c23ed47c47069"}, ] [package.dependencies] @@ -615,7 +689,6 @@ testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "no name = "pytest-cov" version = "2.12.1" description = "Pytest plugin for measuring coverage." -category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" files = [ @@ -635,7 +708,6 @@ testing = ["fields", "hunter", "process-tests", "pytest-xdist", "six", "virtuale name = "pytest-flake8" version = "1.1.0" description = "pytest plugin to check FLAKE8 requirements" -category = "dev" optional = false python-versions = "*" files = [ @@ -651,7 +723,6 @@ pytest = ">=3.5" name = "pytest-forked" version = "1.6.0" description = "run tests in isolated forked subprocesses" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -665,14 +736,13 @@ pytest = ">=3.10" [[package]] name = "pytest-timeout" -version = "2.1.0" +version = "2.2.0" description = "pytest plugin to abort hanging tests" -category = "dev" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" files = [ - {file = "pytest-timeout-2.1.0.tar.gz", hash = "sha256:c07ca07404c612f8abbe22294b23c368e2e5104b521c1790195561f37e1ac3d9"}, - {file = "pytest_timeout-2.1.0-py3-none-any.whl", hash = "sha256:f6f50101443ce70ad325ceb4473c4255e9d74e3c7cd0ef827309dfa4c0d975c6"}, + {file = "pytest-timeout-2.2.0.tar.gz", hash = "sha256:3b0b95dabf3cb50bac9ef5ca912fa0cfc286526af17afc806824df20c2f72c90"}, + {file = "pytest_timeout-2.2.0-py3-none-any.whl", hash = "sha256:bde531e096466f49398a59f2dde76fa78429a09a12411466f88a07213e220de2"}, ] [package.dependencies] @@ -682,7 +752,6 @@ pytest = ">=5.0.0" name = "pytest-xdist" version = "1.34.0" description = "pytest xdist plugin for distributed testing and loop-on-failing modes" -category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" files = [ @@ -703,7 +772,6 @@ testing = ["filelock"] name = "respx" version = "0.20.2" description = "A utility for mocking out the Python HTTPX and HTTP Core libraries." -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -714,11 +782,26 @@ files = [ [package.dependencies] httpx = ">=0.21.0" +[[package]] +name = "setuptools" +version = "68.0.0" +description = "Easily download, build, install, upgrade, and uninstall Python packages" +optional = false +python-versions = ">=3.7" +files = [ + {file = "setuptools-68.0.0-py3-none-any.whl", hash = "sha256:11e52c67415a381d10d6b462ced9cfb97066179f0e871399e006c4ab101fc85f"}, + {file = "setuptools-68.0.0.tar.gz", hash = "sha256:baf1fdb41c6da4cd2eae722e135500da913332ab3f2f5c7d33af9b492acb5235"}, +] + +[package.extras] +docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-hoverxref (<2)", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (==0.8.3)", "sphinx-reredirects", "sphinxcontrib-towncrier"] +testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pip-run (>=8.8)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] +testing-integration = ["build[virtualenv]", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] + [[package]] name = "six" version = "1.16.0" description = "Python 2 and 3 compatibility utilities" -category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" files = [ @@ -730,7 +813,6 @@ files = [ name = "sniffio" version = "1.3.0" description = "Sniff out which async library your code is running under" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -742,7 +824,6 @@ files = [ name = "toml" version = "0.10.2" description = "Python Library for Tom's Obvious, Minimal Language" -category = "dev" optional = false python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" files = [ @@ -752,21 +833,69 @@ files = [ [[package]] name = "tomli" -version = "2.0.1" +version = "1.2.3" description = "A lil' TOML parser" -category = "dev" optional = false -python-versions = ">=3.7" +python-versions = ">=3.6" files = [ - {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, - {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, + {file = "tomli-1.2.3-py3-none-any.whl", hash = "sha256:e3069e4be3ead9668e21cb9b074cd948f7b3113fd9c8bba083f48247aab8b11c"}, + {file = "tomli-1.2.3.tar.gz", hash = "sha256:05b6166bff487dc068d322585c7ea4ef78deed501cc124060e0f238e89a9231f"}, +] + +[[package]] +name = "typed-ast" +version = "1.5.5" +description = "a fork of Python 2 and 3 ast modules with type comment support" +optional = false +python-versions = ">=3.6" +files = [ + {file = "typed_ast-1.5.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:4bc1efe0ce3ffb74784e06460f01a223ac1f6ab31c6bc0376a21184bf5aabe3b"}, + {file = "typed_ast-1.5.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5f7a8c46a8b333f71abd61d7ab9255440d4a588f34a21f126bbfc95f6049e686"}, + {file = "typed_ast-1.5.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:597fc66b4162f959ee6a96b978c0435bd63791e31e4f410622d19f1686d5e769"}, + {file = "typed_ast-1.5.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d41b7a686ce653e06c2609075d397ebd5b969d821b9797d029fccd71fdec8e04"}, + {file = "typed_ast-1.5.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:5fe83a9a44c4ce67c796a1b466c270c1272e176603d5e06f6afbc101a572859d"}, + {file = "typed_ast-1.5.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:d5c0c112a74c0e5db2c75882a0adf3133adedcdbfd8cf7c9d6ed77365ab90a1d"}, + {file = "typed_ast-1.5.5-cp310-cp310-win_amd64.whl", hash = "sha256:e1a976ed4cc2d71bb073e1b2a250892a6e968ff02aa14c1f40eba4f365ffec02"}, + {file = "typed_ast-1.5.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c631da9710271cb67b08bd3f3813b7af7f4c69c319b75475436fcab8c3d21bee"}, + {file = "typed_ast-1.5.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b445c2abfecab89a932b20bd8261488d574591173d07827c1eda32c457358b18"}, + {file = "typed_ast-1.5.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cc95ffaaab2be3b25eb938779e43f513e0e538a84dd14a5d844b8f2932593d88"}, + {file = "typed_ast-1.5.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:61443214d9b4c660dcf4b5307f15c12cb30bdfe9588ce6158f4a005baeb167b2"}, + {file = "typed_ast-1.5.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:6eb936d107e4d474940469e8ec5b380c9b329b5f08b78282d46baeebd3692dc9"}, + {file = "typed_ast-1.5.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e48bf27022897577d8479eaed64701ecaf0467182448bd95759883300ca818c8"}, + {file = "typed_ast-1.5.5-cp311-cp311-win_amd64.whl", hash = "sha256:83509f9324011c9a39faaef0922c6f720f9623afe3fe220b6d0b15638247206b"}, + {file = "typed_ast-1.5.5-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:44f214394fc1af23ca6d4e9e744804d890045d1643dd7e8229951e0ef39429b5"}, + {file = "typed_ast-1.5.5-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:118c1ce46ce58fda78503eae14b7664163aa735b620b64b5b725453696f2a35c"}, + {file = "typed_ast-1.5.5-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:be4919b808efa61101456e87f2d4c75b228f4e52618621c77f1ddcaae15904fa"}, + {file = "typed_ast-1.5.5-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:fc2b8c4e1bc5cd96c1a823a885e6b158f8451cf6f5530e1829390b4d27d0807f"}, + {file = "typed_ast-1.5.5-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:16f7313e0a08c7de57f2998c85e2a69a642e97cb32f87eb65fbfe88381a5e44d"}, + {file = "typed_ast-1.5.5-cp36-cp36m-win_amd64.whl", hash = "sha256:2b946ef8c04f77230489f75b4b5a4a6f24c078be4aed241cfabe9cbf4156e7e5"}, + {file = "typed_ast-1.5.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:2188bc33d85951ea4ddad55d2b35598b2709d122c11c75cffd529fbc9965508e"}, + {file = "typed_ast-1.5.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0635900d16ae133cab3b26c607586131269f88266954eb04ec31535c9a12ef1e"}, + {file = "typed_ast-1.5.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:57bfc3cf35a0f2fdf0a88a3044aafaec1d2f24d8ae8cd87c4f58d615fb5b6311"}, + {file = "typed_ast-1.5.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:fe58ef6a764de7b4b36edfc8592641f56e69b7163bba9f9c8089838ee596bfb2"}, + {file = "typed_ast-1.5.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:d09d930c2d1d621f717bb217bf1fe2584616febb5138d9b3e8cdd26506c3f6d4"}, + {file = "typed_ast-1.5.5-cp37-cp37m-win_amd64.whl", hash = "sha256:d40c10326893ecab8a80a53039164a224984339b2c32a6baf55ecbd5b1df6431"}, + {file = "typed_ast-1.5.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:fd946abf3c31fb50eee07451a6aedbfff912fcd13cf357363f5b4e834cc5e71a"}, + {file = "typed_ast-1.5.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:ed4a1a42df8a3dfb6b40c3d2de109e935949f2f66b19703eafade03173f8f437"}, + {file = "typed_ast-1.5.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:045f9930a1550d9352464e5149710d56a2aed23a2ffe78946478f7b5416f1ede"}, + {file = "typed_ast-1.5.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:381eed9c95484ceef5ced626355fdc0765ab51d8553fec08661dce654a935db4"}, + {file = "typed_ast-1.5.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:bfd39a41c0ef6f31684daff53befddae608f9daf6957140228a08e51f312d7e6"}, + {file = "typed_ast-1.5.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8c524eb3024edcc04e288db9541fe1f438f82d281e591c548903d5b77ad1ddd4"}, + {file = "typed_ast-1.5.5-cp38-cp38-win_amd64.whl", hash = "sha256:7f58fabdde8dcbe764cef5e1a7fcb440f2463c1bbbec1cf2a86ca7bc1f95184b"}, + {file = "typed_ast-1.5.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:042eb665ff6bf020dd2243307d11ed626306b82812aba21836096d229fdc6a10"}, + {file = "typed_ast-1.5.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:622e4a006472b05cf6ef7f9f2636edc51bda670b7bbffa18d26b255269d3d814"}, + {file = "typed_ast-1.5.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1efebbbf4604ad1283e963e8915daa240cb4bf5067053cf2f0baadc4d4fb51b8"}, + {file = "typed_ast-1.5.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f0aefdd66f1784c58f65b502b6cf8b121544680456d1cebbd300c2c813899274"}, + {file = "typed_ast-1.5.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:48074261a842acf825af1968cd912f6f21357316080ebaca5f19abbb11690c8a"}, + {file = "typed_ast-1.5.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:429ae404f69dc94b9361bb62291885894b7c6fb4640d561179548c849f8492ba"}, + {file = "typed_ast-1.5.5-cp39-cp39-win_amd64.whl", hash = "sha256:335f22ccb244da2b5c296e6f96b06ee9bed46526db0de38d2f0e5a6597b81155"}, + {file = "typed_ast-1.5.5.tar.gz", hash = "sha256:94282f7a354f36ef5dbce0ef3467ebf6a258e370ab33d5b40c249fa996e590dd"}, ] [[package]] name = "typing-extensions" version = "4.7.1" description = "Backported and Experimental Type Hints for Python 3.7+" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -774,11 +903,21 @@ files = [ {file = "typing_extensions-4.7.1.tar.gz", hash = "sha256:b75ddc264f0ba5615db7ba217daeb99701ad295353c45f9e95963337ceeeffb2"}, ] +[[package]] +name = "typing-extensions" +version = "4.8.0" +description = "Backported and Experimental Type Hints for Python 3.8+" +optional = false +python-versions = ">=3.8" +files = [ + {file = "typing_extensions-4.8.0-py3-none-any.whl", hash = "sha256:8f92fc8806f9a6b641eaa5318da32b44d401efaac0f6678c9bc448ba3605faa0"}, + {file = "typing_extensions-4.8.0.tar.gz", hash = "sha256:df8e4339e9cb77357558cbdbceca33c303714cf861d1eef15e1070055ae8b7ef"}, +] + [[package]] name = "websockets" version = "10.4" description = "An implementation of the WebSocket Protocol (RFC 6455 & 7692)" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -853,11 +992,24 @@ files = [ {file = "websockets-10.4.tar.gz", hash = "sha256:eef610b23933c54d5d921c92578ae5f89813438fded840c2e9809d378dc765d3"}, ] +[[package]] +name = "wheel" +version = "0.41.2" +description = "A built-package format for Python" +optional = false +python-versions = ">=3.7" +files = [ + {file = "wheel-0.41.2-py3-none-any.whl", hash = "sha256:75909db2664838d015e3d9139004ee16711748a52c8f336b52882266540215d8"}, + {file = "wheel-0.41.2.tar.gz", hash = "sha256:0c5ac5ff2afb79ac23ab82bab027a0be7b5dbcf2e54dc50efe4bf507de1f7985"}, +] + +[package.extras] +test = ["pytest (>=6.0.0)", "setuptools (>=65)"] + [[package]] name = "zipp" version = "3.15.0" description = "Backport of pathlib-compatible object wrapper for zip files" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -876,4 +1028,4 @@ oldcrypto = ["pycrypto"] [metadata] lock-version = "2.0" python-versions = "^3.7" -content-hash = "885ad9d7e6a0adc96cae0dcf69a7c8d7af8dbbf3651b7cce29deed789ad581e7" +content-hash = "9eb72b69b7540da1943024368ff4b560f8b0fca807bce68dc7586ecdafa88c84" diff --git a/pyproject.toml b/pyproject.toml index 3cb26fb9..be38c14c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -40,6 +40,7 @@ oldcrypto = ["pycrypto"] crypto = ["pycryptodome"] [tool.poetry.dev-dependencies] +brunette="*" pytest = "^7.1" mock = "^4.0.3" pep8-naming = "^0.4.1" diff --git a/setup.cfg b/setup.cfg index 28f68fb8..1ad7b53e 100644 --- a/setup.cfg +++ b/setup.cfg @@ -3,15 +3,18 @@ branch=True [flake8] max-line-length = 115 -ignore = W503, W504, N818 +ignore = W503, W504, N818, E203 per-file-ignores = # imported but unused __init__.py: F401 -exclude = - # Exclude virtual environment check - venv +exclude = .git, .env, .venv [tool:pytest] #log_level = DEBUG + +[tool:brunette] +line-length = 115 +verbose = true +single-quotes = True diff --git a/test/ably/realtime/realtimeauth_test.py b/test/ably/realtime/realtimeauth_test.py index 39213c72..8bb4b44d 100644 --- a/test/ably/realtime/realtimeauth_test.py +++ b/test/ably/realtime/realtimeauth_test.py @@ -41,7 +41,7 @@ async def test_auth_valid_api_key(self): await ably.close() async def test_auth_wrong_api_key(self): - api_key = "js9de7r:08sdnuvfasd" + api_key = 'js9de7r:08sdnuvfasd' ably = await TestApp.get_ably_realtime(key=api_key) state_change = await ably.connection.once_async(ConnectionState.FAILED) assert ably.connection.error_reason == state_change.reason @@ -60,7 +60,7 @@ async def test_auth_with_token_string(self): await ably.close() async def test_auth_with_invalid_token_string(self): - invalid_token = "Sdnurv_some_invalid_token_nkds9r7" + invalid_token = 'Sdnurv_some_invalid_token_nkds9r7' ably = await TestApp.get_ably_realtime(token=invalid_token) state_change = await ably.connection.once_async(ConnectionState.FAILED) assert state_change.reason.code == 40005 @@ -78,7 +78,7 @@ async def test_auth_with_token_details(self): await ably.close() async def test_auth_with_invalid_token_details(self): - invalid_token_details = TokenDetails(token="invalid-token") + invalid_token_details = TokenDetails(token='invalid-token') ably = await TestApp.get_ably_realtime(token_details=invalid_token_details) state_change = await ably.connection.once_async(ConnectionState.FAILED) assert state_change.reason.code == 40005 @@ -129,7 +129,7 @@ async def callback(params): async def test_auth_with_auth_callback_invalid_token(self): async def callback(params): - return "invalid token" + return 'invalid token' ably = await TestApp.get_ably_realtime(auth_callback=callback) state_change = await ably.connection.once_async(ConnectionState.FAILED) @@ -141,7 +141,7 @@ async def test_auth_with_auth_url_json(self): rest = await TestApp.get_ably_rest() token_details = await rest.auth.request_token() token_details_json = json.dumps(token_details.to_dict()) - url_path = f"{echo_url}/?type=json&body={urllib.parse.quote_plus(token_details_json)}" + url_path = f'{echo_url}/?type=json&body={urllib.parse.quote_plus(token_details_json)}' ably = await TestApp.get_ably_realtime(auth_url=url_path) await ably.connection.once_async(ConnectionState.CONNECTED) @@ -153,7 +153,7 @@ async def test_auth_with_auth_url_json(self): async def test_auth_with_auth_url_text_plain(self): rest = await TestApp.get_ably_rest() token_details = await rest.auth.request_token() - url_path = f"{echo_url}/?type=text&body={token_details.token}" + url_path = f'{echo_url}/?type=text&body={token_details.token}' ably = await TestApp.get_ably_realtime(auth_url=url_path) await ably.connection.once_async(ConnectionState.CONNECTED) @@ -165,10 +165,9 @@ async def test_auth_with_auth_url_text_plain(self): async def test_auth_with_auth_url_post(self): rest = await TestApp.get_ably_rest() token_details = await rest.auth.request_token() - url_path = f"{echo_url}/?type=json&" + url_path = f'{echo_url}/?type=json&' - ably = await TestApp.get_ably_realtime(auth_url=url_path, auth_method='POST', - auth_params=token_details) + ably = await TestApp.get_ably_realtime(auth_url=url_path, auth_method='POST', auth_params=token_details) await ably.connection.once_async(ConnectionState.CONNECTED) response_time_ms = await ably.connection.ping() assert response_time_ms is not None @@ -196,6 +195,7 @@ async def send_protocol_message(protocol_message): if protocol_message.get('action') == ProtocolMessageAction.AUTH: fut1.set_result(protocol_message) await original_send_protocol_message(protocol_message) + ably.connection.connection_manager.send_protocol_message = send_protocol_message fut2 = asyncio.Future() @@ -253,12 +253,12 @@ async def callback(params): ably = await TestApp.get_ably_realtime(auth_callback=callback) - await ably.auth.authorize({"capability": {channel_name: "*"}}) + await ably.auth.authorize({'capability': {channel_name: '*'}}) channel = ably.channels.get(channel_name) await channel.attach() - await ably.auth.authorize({"capability": {channel_name: "*", random_string(5): "*"}}) + await ably.auth.authorize({'capability': {channel_name: '*', random_string(5): '*'}}) await channel.once_async(ChannelState.ATTACHED) await ably.close() @@ -273,7 +273,7 @@ async def callback(params): ably = await TestApp.get_ably_realtime(auth_callback=callback) - await ably.auth.authorize({"capability": {channel_name: "*"}}) + await ably.auth.authorize({'capability': {channel_name: '*'}}) channel = ably.channels.get(channel_name) await channel.attach() @@ -285,7 +285,7 @@ def on_channel_state_change(state_change): channel.on(ChannelState.FAILED, on_channel_state_change) - await ably.auth.authorize({"capability": {random_string(5): "*"}}) + await ably.auth.authorize({'capability': {random_string(5): '*'}}) state_change = await future @@ -304,7 +304,7 @@ async def callback(params): ably = await TestApp.get_ably_realtime(auth_callback=callback) msg = { - "action": ProtocolMessageAction.AUTH, + 'action': ProtocolMessageAction.AUTH, } await ably.connection.once_async(ConnectionState.CONNECTED) @@ -313,7 +313,7 @@ async def callback(params): def on_update(state_change): auth_future.set_result(state_change) - ably.connection.on("update", on_update) + ably.connection.on('update', on_update) await ably.connection.connection_manager.transport.on_protocol_message(msg) await auth_future await ably.close() @@ -321,14 +321,13 @@ def on_update(state_change): # RSC8a4 async def test_jwt_reauth(self): test_vars = await TestApp.get_test_vars() - key = test_vars["keys"][0] - key_name = key["key_name"] - key_secret = key["key_secret"] + key = test_vars['keys'][0] + key_name = key['key_name'] + key_secret = key['key_secret'] async def auth_callback(_): response = httpx.get( - echo_url + '/createJWT', - params={"keyName": key_name, "keySecret": key_secret, "expiresIn": 35} + echo_url + '/createJWT', params={'keyName': key_name, 'keySecret': key_secret, 'expiresIn': 35} ) return response.text @@ -350,13 +349,7 @@ async def callback(params): return token_details.token ably = await TestApp.get_ably_realtime(auth_callback=callback) - msg = { - "action": ProtocolMessageAction.ERROR, - "error": { - "code": 40142, - "statusCode": 401 - } - } + msg = {'action': ProtocolMessageAction.ERROR, 'error': {'code': 40142, 'statusCode': 401}} transport = await ably.connection.connection_manager.once_async('transport.pending') original_token_details = ably.auth.token_details @@ -373,7 +366,7 @@ async def test_renew_token_connection_attempt_fails(self): async def callback(params): nonlocal call_count call_count += 1 - params = {"ttl": 1} + params = {'ttl': 1} token_details = await rest.auth.request_token(token_params=params) return token_details @@ -402,82 +395,81 @@ async def test_renew_token_no_renew_means_provided(self): async def test_auth_callback_error(self): async def auth_callback(_): - raise Exception("An error from client code that the authCallback might return") + raise Exception('An error from client code that the authCallback might return') - await auth_callback_failure({ - 'auth_callback': auth_callback - }) + await auth_callback_failure({'auth_callback': auth_callback}) - @pytest.mark.skip(reason="blocked by https://github.com/ably/ably-python/issues/461") + @pytest.mark.skip(reason='blocked by https://github.com/ably/ably-python/issues/461') async def test_auth_callback_timeout(self): async def auth_callback(_): await asyncio.sleep(10_000) - await auth_callback_failure({ - 'auth_callback': auth_callback, - 'realtime_request_timeout': 100, - }) + await auth_callback_failure( + { + 'auth_callback': auth_callback, + 'realtime_request_timeout': 100, + } + ) async def test_auth_callback_nothing(self): async def auth_callback(_): return - await auth_callback_failure({ - 'auth_callback': auth_callback, - }) + await auth_callback_failure( + { + 'auth_callback': auth_callback, + } + ) async def test_auth_callback_malformed(self): async def auth_callback(_): - return {"horse": "ebooks"} + return {'horse': 'ebooks'} - await auth_callback_failure({ - 'auth_callback': auth_callback, - }) + await auth_callback_failure( + { + 'auth_callback': auth_callback, + } + ) async def test_auth_callback_empty_string(self): async def auth_callback(_): - return "" + return '' - await auth_callback_failure({ - 'auth_callback': auth_callback, - }) + await auth_callback_failure( + { + 'auth_callback': auth_callback, + } + ) - @pytest.mark.skip(reason="blocked by https://github.com/ably/ably-python/issues/461") + @pytest.mark.skip(reason='blocked by https://github.com/ably/ably-python/issues/461') async def test_auth_url_timeout(self): - await auth_callback_failure({ - "auth_url": "http://10.255.255.1/" - }) + await auth_callback_failure({'auth_url': 'http://10.255.255.1/'}) async def test_auth_url_404(self): - await auth_callback_failure({ - "auth_url": "http://example.com/404" - }) + await auth_callback_failure({'auth_url': 'http://example.com/404'}) async def test_auth_url_wrong_content_type(self): - await auth_callback_failure({ - "auth_url": "http://example.com/" - }) + await auth_callback_failure({'auth_url': 'http://example.com/'}) async def test_auth_url_401(self): - await auth_callback_failure({ - "auth_url": echo_url + '/respondwith?status=401' - }) + await auth_callback_failure({'auth_url': echo_url + '/respondwith?status=401'}) async def test_auth_url_403(self): - await auth_callback_failure({ - "auth_url": echo_url + '/respondwith?status=403' - }, expect_failure=True) + await auth_callback_failure({'auth_url': echo_url + '/respondwith?status=403'}, expect_failure=True) async def test_auth_url_403_custom_error(self): - error = json.dumps({ - "error": { - "some_custom": "error", + error = json.dumps( + { + 'error': { + 'some_custom': 'error', + } } - }) + ) - await auth_callback_failure({ - "auth_url": echo_url + '/respondwith?status=403&body=' + urllib.parse.quote_plus(error) - }, expect_failure=True) + await auth_callback_failure( + {'auth_url': echo_url + '/respondwith?status=403&body=' + urllib.parse.quote_plus(error)}, + expect_failure=True, + ) # RTN15h2 async def test_renew_token_single_attempt_upon_disconnection(self): @@ -488,13 +480,7 @@ async def callback(params): return token_details.token ably = await TestApp.get_ably_realtime(auth_callback=callback) - msg = { - "action": ProtocolMessageAction.DISCONNECTED, - "error": { - "code": 40142, - "statusCode": 401 - } - } + msg = {'action': ProtocolMessageAction.DISCONNECTED, 'error': {'code': 40142, 'statusCode': 401}} await ably.connection.once_async(ConnectionState.CONNECTED) original_token_details = ably.auth.token_details @@ -512,13 +498,7 @@ async def test_renew_token_no_renew_means_provided_upon_disconnection(self): ably = await TestApp.get_ably_realtime(token_details=token_details) state_change = await ably.connection.once_async(ConnectionState.CONNECTED) - msg = { - "action": ProtocolMessageAction.DISCONNECTED, - "error": { - "code": 40142, - "statusCode": 401 - } - } + msg = {'action': ProtocolMessageAction.DISCONNECTED, 'error': {'code': 40142, 'statusCode': 401}} assert ably.connection.connection_manager.transport await ably.connection.connection_manager.transport.on_protocol_message(msg) @@ -536,13 +516,7 @@ async def callback(params): return token_details.token ably = await TestApp.get_ably_realtime(auth_callback=callback) - msg = { - "action": ProtocolMessageAction.ERROR, - "error": { - "code": 40142, - "statusCode": 401 - } - } + msg = {'action': ProtocolMessageAction.ERROR, 'error': {'code': 40142, 'statusCode': 401}} await ably.connection.once_async(ConnectionState.CONNECTED) connection_key = ably.connection.connection_details.connection_key @@ -550,7 +524,7 @@ async def callback(params): ably.connection.connection_manager.notify_state(ConnectionState.DISCONNECTED) transport = await ably.connection.connection_manager.once_async('transport.pending') - assert ably.connection.connection_manager.transport.params["resume"] == connection_key + assert ably.connection.connection_manager.transport.params['resume'] == connection_key original_token_details = ably.auth.token_details await transport.on_protocol_message(msg) @@ -564,13 +538,7 @@ async def test_renew_token_no_renew_means_provided_on_resume(self): ably = await TestApp.get_ably_realtime(token_details=token_details) - msg = { - "action": ProtocolMessageAction.DISCONNECTED, - "error": { - "code": 40142, - "statusCode": 401 - } - } + msg = {'action': ProtocolMessageAction.DISCONNECTED, 'error': {'code': 40142, 'statusCode': 401}} await ably.connection.once_async(ConnectionState.CONNECTED) connection_key = ably.connection.connection_details.connection_key @@ -578,7 +546,7 @@ async def test_renew_token_no_renew_means_provided_on_resume(self): ably.connection.connection_manager.notify_state(ConnectionState.DISCONNECTED) state_change = await ably.connection.once_async(ConnectionState.CONNECTED) - assert ably.connection.connection_manager.transport.params["resume"] == connection_key + assert ably.connection.connection_manager.transport.params['resume'] == connection_key assert ably.connection.connection_manager.transport await ably.connection.connection_manager.transport.on_protocol_message(msg) @@ -596,7 +564,7 @@ async def test_auth_client_id_inheritance_auth_callback(self): client_id = 'test_client_id' async def auth_callback(_): - return await rest.auth.request_token({"client_id": client_id}) + return await rest.auth.request_token({'client_id': client_id}) realtime = await TestApp.get_ably_realtime(auth_callback=auth_callback) @@ -617,9 +585,9 @@ async def test_auth_client_id_mismatch(self): rest = await TestApp.get_ably_rest() client_id = 'test_client_id' - token_details = await rest.auth.request_token({"client_id": client_id}) + token_details = await rest.auth.request_token({'client_id': client_id}) - realtime = await TestApp.get_ably_realtime(token_details=token_details, client_id="WRONG") + realtime = await TestApp.get_ably_realtime(token_details=token_details, client_id='WRONG') assert realtime.auth.client_id is None @@ -636,7 +604,7 @@ async def test_auth_client_id_wildcard_token(self): rest = await TestApp.get_ably_rest() client_id = 'test_client_id' - token_details = await rest.auth.request_token({"client_id": "*"}) + token_details = await rest.auth.request_token({'client_id': '*'}) realtime = await TestApp.get_ably_realtime(token_details=token_details, client_id=client_id) @@ -655,7 +623,7 @@ async def test_auth_client_id_inheritance_token(self): rest = await TestApp.get_ably_rest() client_id = 'test_client_id' - token_details = await rest.auth.request_token({"client_id": client_id}) + token_details = await rest.auth.request_token({'client_id': client_id}) realtime = await TestApp.get_ably_realtime(token_details=token_details) diff --git a/test/ably/realtime/realtimechannel_test.py b/test/ably/realtime/realtimechannel_test.py index fb9b274e..9ec59f09 100644 --- a/test/ably/realtime/realtimechannel_test.py +++ b/test/ably/realtime/realtimechannel_test.py @@ -12,7 +12,7 @@ class TestRealtimeChannel(BaseAsyncTestCase): async def asyncSetUp(self): self.test_vars = await TestApp.get_test_vars() - self.valid_key_format = "api:key" + self.valid_key_format = 'api:key' async def test_channels_get(self): ably = await TestApp.get_ably_realtime() @@ -27,7 +27,7 @@ async def test_channels_release(self): ably.channels.release('my_channel') for _ in ably.channels: - raise AssertionError("Expected no channels to exist") + raise AssertionError('Expected no channels to exist') await ably.close() @@ -257,6 +257,7 @@ async def new_send_protocol_message(msg): if msg.get('action') == ProtocolMessageAction.ATTACH: return await original_send_protocol_message(msg) + ably.connection.connection_manager.send_protocol_message = new_send_protocol_message channel = ably.channels.get('channel_name') @@ -275,6 +276,7 @@ async def new_send_protocol_message(msg): if msg.get('action') == ProtocolMessageAction.DETACH: return await original_send_protocol_message(msg) + ably.connection.connection_manager.send_protocol_message = new_send_protocol_message channel = ably.channels.get('channel_name') @@ -332,8 +334,8 @@ async def test_channel_attach_retry_immediately_on_unexpected_detached(self): # Simulate an unexpected DETACHED message from ably message = { - "action": ProtocolMessageAction.DETACHED, - "channel": channel_name, + 'action': ProtocolMessageAction.DETACHED, + 'channel': channel_name, } assert ably.connection.connection_manager.transport await ably.connection.connection_manager.transport.on_protocol_message(message) @@ -362,6 +364,7 @@ async def new_send_protocol_message(msg): call_count += 1 return await original_send_protocol_message(msg) + ably.connection.connection_manager.send_protocol_message = new_send_protocol_message with pytest.raises(AblyException): @@ -394,12 +397,12 @@ async def test_channel_error(self): status_code = 123 msg = { - "action": ProtocolMessageAction.ERROR, - "channel": channel_name, - "error": { - "message": "test error", - "code": code, - "statusCode": status_code, + 'action': ProtocolMessageAction.ERROR, + 'channel': channel_name, + 'error': { + 'message': 'test error', + 'code': code, + 'statusCode': status_code, }, } @@ -422,12 +425,12 @@ async def test_channel_error_cleared_upon_attach(self): status_code = 123 msg = { - "action": ProtocolMessageAction.ERROR, - "channel": channel_name, - "error": { - "message": "test error", - "code": code, - "statusCode": status_code, + 'action': ProtocolMessageAction.ERROR, + 'channel': channel_name, + 'error': { + 'message': 'test error', + 'code': code, + 'statusCode': status_code, }, } @@ -449,12 +452,12 @@ async def test_channel_error_cleared_upon_connect_from_terminal_state(self): status_code = 123 msg = { - "action": ProtocolMessageAction.ERROR, - "channel": channel_name, - "error": { - "message": "test error", - "code": code, - "statusCode": status_code, + 'action': ProtocolMessageAction.ERROR, + 'channel': channel_name, + 'error': { + 'message': 'test error', + 'code': code, + 'statusCode': status_code, }, } diff --git a/test/ably/realtime/realtimeconnection_test.py b/test/ably/realtime/realtimeconnection_test.py index 31628b97..027e7ac2 100644 --- a/test/ably/realtime/realtimeconnection_test.py +++ b/test/ably/realtime/realtimeconnection_test.py @@ -11,7 +11,7 @@ class TestRealtimeConnection(BaseAsyncTestCase): async def asyncSetUp(self): self.test_vars = await TestApp.get_test_vars() - self.valid_key_format = "api:key" + self.valid_key_format = 'api:key' async def test_connection_state(self): ably = await TestApp.get_ably_realtime(auto_connect=False) @@ -173,18 +173,20 @@ async def test_connectivity_check_default(self): async def test_connectivity_check_non_default(self): ably = await TestApp.get_ably_realtime( - connectivity_check_url="https://echo.ably.io/respondWith?status=200", auto_connect=False) + connectivity_check_url='https://echo.ably.io/respondWith?status=200', auto_connect=False + ) # A non-default URL should return True with a HTTP OK despite not returning "Yes" in the body assert ably.connection.connection_manager.check_connection() is True async def test_connectivity_check_bad_status(self): ably = await TestApp.get_ably_realtime( - connectivity_check_url="https://echo.ably.io/respondWith?status=400", auto_connect=False) + connectivity_check_url='https://echo.ably.io/respondWith?status=400', auto_connect=False + ) # Should return False when the URL returns a non-2xx response code assert ably.connection.connection_manager.check_connection() is False async def test_unroutable_host(self): - ably = await TestApp.get_ably_realtime(realtime_host="10.255.255.1", realtime_request_timeout=3000) + ably = await TestApp.get_ably_realtime(realtime_host='10.255.255.1', realtime_request_timeout=3000) state_change = await ably.connection.once_async() assert state_change.reason assert state_change.reason.code == 50003 @@ -194,7 +196,7 @@ async def test_unroutable_host(self): await ably.close() async def test_invalid_host(self): - ably = await TestApp.get_ably_realtime(realtime_host="iamnotahost") + ably = await TestApp.get_ably_realtime(realtime_host='iamnotahost') state_change = await ably.connection.once_async() assert state_change.reason assert state_change.reason.code == 40000 @@ -230,7 +232,7 @@ def on_update(connection_state): ably.connection.on(ConnectionEvent.UPDATE, on_update) async def on_transport_pending(transport): - await transport.on_protocol_message({'action': 4, "connectionDetails": {"connectionStateTtl": 200}}) + await transport.on_protocol_message({'action': 4, 'connectionDetails': {'connectionStateTtl': 200}}) ably.connection.connection_manager.on('transport.pending', on_transport_pending) @@ -248,8 +250,8 @@ def on_transport_pending(transport): original_on_protocol_message = transport.on_protocol_message async def on_protocol_message(msg): - if msg["action"] == ProtocolMessageAction.CONNECTED: - msg["connectionDetails"]["maxIdleInterval"] = 100 + if msg['action'] == ProtocolMessageAction.CONNECTED: + msg['connectionDetails']['maxIdleInterval'] = 100 await original_on_protocol_message(msg) @@ -269,10 +271,7 @@ async def on_protocol_message(msg): # RTN15a async def test_retry_immediately_upon_unexpected_disconnection(self): # Set timeouts to 500s so that if the client uses retry delay the test will fail with a timeout - ably = await TestApp.get_ably_realtime( - disconnected_retry_timeout=500_000, - suspended_retry_timeout=500_000 - ) + ably = await TestApp.get_ably_realtime(disconnected_retry_timeout=500_000, suspended_retry_timeout=500_000) # Wait for the client to connect await ably.connection.once_async(ConnectionState.CONNECTED) @@ -292,12 +291,12 @@ async def test_fallback_host(self): await ably.connection.connection_manager.once_async('transport.pending') assert ably.connection.connection_manager.transport - ably.connection.connection_manager.transport._emit('failed', AblyException("test exception", 502, 50200)) + ably.connection.connection_manager.transport._emit('failed', AblyException('test exception', 502, 50200)) await ably.connection.once_async(ConnectionState.CONNECTED) - assert ably.connection.connection_manager.transport.host != self.test_vars["realtime_host"] - assert ably.options.fallback_realtime_host != self.test_vars["realtime_host"] + assert ably.connection.connection_manager.transport.host != self.test_vars['realtime_host'] + assert ably.options.fallback_realtime_host != self.test_vars['realtime_host'] await ably.close() async def test_fallback_host_no_connection(self): @@ -311,14 +310,14 @@ def check_connection(): ably.connection.connection_manager.check_connection = check_connection - asyncio.create_task(ably.connection.connection_manager.transport.on_protocol_message({ - "action": ProtocolMessageAction.DISCONNECTED, - "error": { - "statusCode": 502, - "code": 50200, - "message": "test exception" - } - })) + asyncio.create_task( + ably.connection.connection_manager.transport.on_protocol_message( + { + 'action': ProtocolMessageAction.DISCONNECTED, + 'error': {'statusCode': 502, 'code': 50200, 'message': 'test exception'}, + } + ) + ) await ably.connection.once_async(ConnectionState.DISCONNECTED) @@ -330,19 +329,19 @@ async def test_fallback_host_disconnected_protocol_msg(self): await ably.connection.connection_manager.once_async('transport.pending') assert ably.connection.connection_manager.transport - asyncio.create_task(ably.connection.connection_manager.transport.on_protocol_message({ - "action": ProtocolMessageAction.DISCONNECTED, - "error": { - "statusCode": 502, - "code": 50200, - "message": "test exception" - } - })) + asyncio.create_task( + ably.connection.connection_manager.transport.on_protocol_message( + { + 'action': ProtocolMessageAction.DISCONNECTED, + 'error': {'statusCode': 502, 'code': 50200, 'message': 'test exception'}, + } + ) + ) await ably.connection.once_async(ConnectionState.CONNECTED) - assert ably.connection.connection_manager.transport.host != self.test_vars["realtime_host"] - assert ably.options.fallback_realtime_host != self.test_vars["realtime_host"] + assert ably.connection.connection_manager.transport.host != self.test_vars['realtime_host'] + assert ably.options.fallback_realtime_host != self.test_vars['realtime_host'] await ably.close() # RTN2d @@ -354,7 +353,7 @@ async def test_connection_null_client_id_query_params(self): realtime = await TestApp.get_ably_realtime(token_details=token_details) await realtime.connection.once_async(ConnectionState.CONNECTED) - assert realtime.connection.connection_manager.transport.params.get("client_id") is None + assert realtime.connection.connection_manager.transport.params.get('client_id') is None assert realtime.auth.client_id is None await realtime.close() @@ -366,7 +365,7 @@ async def test_connection_client_id_query_params(self): ably = await TestApp.get_ably_realtime(client_id=client_id) await ably.connection.once_async(ConnectionState.CONNECTED) - assert ably.connection.connection_manager.transport.params["client_id"] == client_id + assert ably.connection.connection_manager.transport.params['client_id'] == client_id assert ably.auth.client_id == client_id await ably.close() @@ -381,8 +380,8 @@ def on_transport_pending(transport): original_on_protocol_message = transport.on_protocol_message async def on_protocol_message(msg): - if msg["action"] == ProtocolMessageAction.CONNECTED: - msg["connectionDetails"]["maxIdleInterval"] = 1000 + if msg['action'] == ProtocolMessageAction.CONNECTED: + msg['connectionDetails']['maxIdleInterval'] = 1000 await original_on_protocol_message(msg) diff --git a/test/ably/realtime/realtimeinit_test.py b/test/ably/realtime/realtimeinit_test.py index 96fa540c..0b6d0deb 100644 --- a/test/ably/realtime/realtimeinit_test.py +++ b/test/ably/realtime/realtimeinit_test.py @@ -9,22 +9,22 @@ class TestRealtimeInit(BaseAsyncTestCase): async def asyncSetUp(self): self.test_vars = await TestApp.get_test_vars() - self.valid_key_format = "api:key" + self.valid_key_format = 'api:key' async def test_init_with_valid_key(self): - ably = await TestApp.get_ably_realtime(key=self.test_vars["keys"][0]["key_str"], auto_connect=False) - assert Auth.Method.BASIC == ably.auth.auth_mechanism, "Unexpected Auth method mismatch" - assert ably.auth.auth_options.key_name == self.test_vars["keys"][0]['key_name'] - assert ably.auth.auth_options.key_secret == self.test_vars["keys"][0]['key_secret'] + ably = await TestApp.get_ably_realtime(key=self.test_vars['keys'][0]['key_str'], auto_connect=False) + assert Auth.Method.BASIC == ably.auth.auth_mechanism, 'Unexpected Auth method mismatch' + assert ably.auth.auth_options.key_name == self.test_vars['keys'][0]['key_name'] + assert ably.auth.auth_options.key_secret == self.test_vars['keys'][0]['key_secret'] async def test_init_with_incorrect_key(self): with pytest.raises(AblyAuthException): - await TestApp.get_ably_realtime(key="some invalid key", auto_connect=False) + await TestApp.get_ably_realtime(key='some invalid key', auto_connect=False) async def test_init_with_valid_key_format(self): - key = self.valid_key_format.split(":") + key = self.valid_key_format.split(':') ably = await TestApp.get_ably_realtime(key=self.valid_key_format, auto_connect=False) - assert Auth.Method.BASIC == ably.auth.auth_mechanism, "Unexpected Auth method mismatch" + assert Auth.Method.BASIC == ably.auth.auth_mechanism, 'Unexpected Auth method mismatch' assert ably.auth.auth_options.key_name == key[0] assert ably.auth.auth_options.key_secret == key[1] diff --git a/test/ably/realtime/realtimeresume_test.py b/test/ably/realtime/realtimeresume_test.py index 7d1a72e8..9741d445 100644 --- a/test/ably/realtime/realtimeresume_test.py +++ b/test/ably/realtime/realtimeresume_test.py @@ -23,7 +23,7 @@ def on_message(_): class TestRealtimeResume(BaseAsyncTestCase): async def asyncSetUp(self): self.test_vars = await TestApp.get_test_vars() - self.valid_key_format = "api:key" + self.valid_key_format = 'api:key' # RTN15c6 - valid resume response async def test_connection_resume(self): @@ -37,7 +37,7 @@ async def test_connection_resume(self): await ably.connection.once_async(ConnectionState.CONNECTED) new_connection_id = ably.connection.connection_manager.connection_id - assert ably.connection.connection_manager.transport.params["resume"] == connection_key + assert ably.connection.connection_manager.transport.params['resume'] == connection_key assert prev_connection_id == new_connection_id await ably.close() @@ -47,7 +47,7 @@ async def test_fatal_resume_error(self): ably = await TestApp.get_ably_realtime() await ably.connection.once_async(ConnectionState.CONNECTED) - ably.auth.auth_options.key_name = "wrong-key" + ably.auth.auth_options.key_name = 'wrong-key' await ably.connection.connection_manager.transport.dispose() ably.connection.connection_manager.notify_state(ConnectionState.DISCONNECTED) @@ -178,22 +178,18 @@ async def test_resume_update_channel_attached(self): await channel.attach() error_code = 123 error_status_code = 456 - error_message = "some error" + error_message = 'some error' message = { - "action": ProtocolMessageAction.ATTACHED, - "channel": name, - "error": { - "code": error_code, - "statusCode": error_status_code, - "message": error_message - } + 'action': ProtocolMessageAction.ATTACHED, + 'channel': name, + 'error': {'code': error_code, 'statusCode': error_status_code, 'message': error_message}, } future = asyncio.Future() def on_update(state_change): future.set_result(state_change) - channel.once("update", on_update) + channel.once('update', on_update) await realtime.connection.connection_manager.transport.on_protocol_message(message) state_change = await future diff --git a/test/ably/rest/encoders_test.py b/test/ably/rest/encoders_test.py index 6bffba65..64f1f428 100644 --- a/test/ably/rest/encoders_test.py +++ b/test/ably/rest/encoders_test.py @@ -29,7 +29,7 @@ async def asyncTearDown(self): await self.ably.close() async def test_text_utf8(self): - channel = self.ably.channels["persisted:publish"] + channel = self.ably.channels['persisted:publish'] with mock.patch('ably.rest.rest.Http.post', new_callable=AsyncMock) as post_mock: await channel.publish('event', 'foó') @@ -39,7 +39,7 @@ async def test_text_utf8(self): async def test_str(self): # This test only makes sense for py2 - channel = self.ably.channels["persisted:publish"] + channel = self.ably.channels['persisted:publish'] with mock.patch('ably.rest.rest.Http.post', new_callable=AsyncMock) as post_mock: await channel.publish('event', 'foo') @@ -48,7 +48,7 @@ async def test_str(self): assert not json.loads(kwargs['body']).get('encoding', '') async def test_with_binary_type(self): - channel = self.ably.channels["persisted:publish"] + channel = self.ably.channels['persisted:publish'] with mock.patch('ably.rest.rest.Http.post', new_callable=AsyncMock) as post_mock: await channel.publish('event', bytearray(b'foo')) @@ -58,7 +58,7 @@ async def test_with_binary_type(self): assert json.loads(kwargs['body'])['encoding'].strip('/') == 'base64' async def test_with_bytes_type(self): - channel = self.ably.channels["persisted:publish"] + channel = self.ably.channels['persisted:publish'] with mock.patch('ably.rest.rest.Http.post', new_callable=AsyncMock) as post_mock: await channel.publish('event', b'foo') @@ -68,7 +68,7 @@ async def test_with_bytes_type(self): assert json.loads(kwargs['body'])['encoding'].strip('/') == 'base64' async def test_with_json_dict_data(self): - channel = self.ably.channels["persisted:publish"] + channel = self.ably.channels['persisted:publish'] data = {'foó': 'bár'} with mock.patch('ably.rest.rest.Http.post', new_callable=AsyncMock) as post_mock: await channel.publish('event', data) @@ -78,7 +78,7 @@ async def test_with_json_dict_data(self): assert json.loads(kwargs['body'])['encoding'].strip('/') == 'json' async def test_with_json_list_data(self): - channel = self.ably.channels["persisted:publish"] + channel = self.ably.channels['persisted:publish'] data = ['foó', 'bár'] with mock.patch('ably.rest.rest.Http.post', new_callable=AsyncMock) as post_mock: await channel.publish('event', data) @@ -88,7 +88,7 @@ async def test_with_json_list_data(self): assert json.loads(kwargs['body'])['encoding'].strip('/') == 'json' async def test_text_utf8_decode(self): - channel = self.ably.channels["persisted:stringdecode"] + channel = self.ably.channels['persisted:stringdecode'] await channel.publish('event', 'fóo') history = await channel.history() @@ -98,7 +98,7 @@ async def test_text_utf8_decode(self): assert not message.encoding async def test_text_str_decode(self): - channel = self.ably.channels["persisted:stringnonutf8decode"] + channel = self.ably.channels['persisted:stringnonutf8decode'] await channel.publish('event', 'foo') history = await channel.history() @@ -108,7 +108,7 @@ async def test_text_str_decode(self): assert not message.encoding async def test_with_binary_type_decode(self): - channel = self.ably.channels["persisted:binarydecode"] + channel = self.ably.channels['persisted:binarydecode'] await channel.publish('event', bytearray(b'foob')) history = await channel.history() @@ -118,7 +118,7 @@ async def test_with_binary_type_decode(self): assert not message.encoding async def test_with_json_dict_data_decode(self): - channel = self.ably.channels["persisted:jsondict"] + channel = self.ably.channels['persisted:jsondict'] data = {'foó': 'bár'} await channel.publish('event', data) history = await channel.history() @@ -127,7 +127,7 @@ async def test_with_json_dict_data_decode(self): assert not message.encoding async def test_with_json_list_data_decode(self): - channel = self.ably.channels["persisted:jsonarray"] + channel = self.ably.channels['persisted:jsonarray'] data = ['foó', 'bár'] await channel.publish('event', data) history = await channel.history() @@ -146,8 +146,7 @@ def test_decode_with_invalid_encoding(self): class TestTextEncodersEncryption(BaseAsyncTestCase): async def asyncSetUp(self): self.ably = await TestApp.get_ably_rest(use_binary_protocol=False) - self.cipher_params = CipherParams(secret_key='keyfordecrypt_16', - algorithm='aes') + self.cipher_params = CipherParams(secret_key='keyfordecrypt_16', algorithm='aes') async def asyncTearDown(self): await self.ably.close() @@ -160,8 +159,7 @@ def decrypt(self, payload, options=None): return cipher.decrypt(ciphertext) async def test_text_utf8(self): - channel = self.ably.channels.get("persisted:publish_enc", - cipher=self.cipher_params) + 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: await channel.publish('event', 'fóo') _, kwargs = post_mock.call_args @@ -171,7 +169,7 @@ async def test_text_utf8(self): async def test_str(self): # This test only makes sense for py2 - channel = self.ably.channels["persisted:publish"] + channel = self.ably.channels['persisted:publish'] with mock.patch('ably.rest.rest.Http.post', new_callable=AsyncMock) as post_mock: await channel.publish('event', 'foo') @@ -180,8 +178,7 @@ async def test_str(self): assert not json.loads(kwargs['body']).get('encoding', '') async def test_with_binary_type(self): - channel = self.ably.channels.get("persisted:publish_enc", - cipher=self.cipher_params) + 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: await channel.publish('event', bytearray(b'foo')) @@ -193,8 +190,7 @@ async def test_with_binary_type(self): assert isinstance(data, bytearray) async def test_with_json_dict_data(self): - channel = self.ably.channels.get("persisted:publish_enc", - cipher=self.cipher_params) + 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: await channel.publish('event', data) @@ -204,8 +200,7 @@ async def test_with_json_dict_data(self): assert json.loads(raw_data) == data async def test_with_json_list_data(self): - channel = self.ably.channels.get("persisted:publish_enc", - cipher=self.cipher_params) + 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: await channel.publish('event', data) @@ -215,8 +210,7 @@ async def test_with_json_list_data(self): assert json.loads(raw_data) == data async def test_text_utf8_decode(self): - channel = self.ably.channels.get("persisted:enc_stringdecode", - cipher=self.cipher_params) + channel = self.ably.channels.get('persisted:enc_stringdecode', cipher=self.cipher_params) await channel.publish('event', 'foó') history = await channel.history() message = history.items[0] @@ -225,8 +219,7 @@ async def test_text_utf8_decode(self): assert not message.encoding async def test_with_binary_type_decode(self): - channel = self.ably.channels.get("persisted:enc_binarydecode", - cipher=self.cipher_params) + channel = self.ably.channels.get('persisted:enc_binarydecode', cipher=self.cipher_params) await channel.publish('event', bytearray(b'foob')) history = await channel.history() @@ -236,8 +229,7 @@ async def test_with_binary_type_decode(self): assert not message.encoding async def test_with_json_dict_data_decode(self): - channel = self.ably.channels.get("persisted:enc_jsondict", - cipher=self.cipher_params) + channel = self.ably.channels.get('persisted:enc_jsondict', cipher=self.cipher_params) data = {'foó': 'bár'} await channel.publish('event', data) history = await channel.history() @@ -246,8 +238,7 @@ async def test_with_json_dict_data_decode(self): assert not message.encoding async def test_with_json_list_data_decode(self): - channel = self.ably.channels.get("persisted:enc_list", - cipher=self.cipher_params) + channel = self.ably.channels.get('persisted:enc_list', cipher=self.cipher_params) data = ['foó', 'bár'] await channel.publish('event', data) history = await channel.history() @@ -257,7 +248,6 @@ async def test_with_json_list_data_decode(self): class TestBinaryEncodersNoEncryption(BaseAsyncTestCase): - async def asyncSetUp(self): self.ably = await TestApp.get_ably_rest() @@ -268,30 +258,27 @@ def decode(self, data): return msgpack.unpackb(data) async def test_text_utf8(self): - channel = self.ably.channels["persisted:publish"] + channel = self.ably.channels['persisted:publish'] - with mock.patch('ably.rest.rest.Http.post', - wraps=channel.ably.http.post) as post_mock: + with mock.patch('ably.rest.rest.Http.post', wraps=channel.ably.http.post) as post_mock: await channel.publish('event', 'foó') _, kwargs = post_mock.call_args assert self.decode(kwargs['body'])['data'] == 'foó' assert self.decode(kwargs['body']).get('encoding', '').strip('/') == '' async def test_with_binary_type(self): - channel = self.ably.channels["persisted:publish"] + channel = self.ably.channels['persisted:publish'] - with mock.patch('ably.rest.rest.Http.post', - wraps=channel.ably.http.post) as post_mock: + with mock.patch('ably.rest.rest.Http.post', wraps=channel.ably.http.post) as post_mock: await channel.publish('event', bytearray(b'foo')) _, kwargs = post_mock.call_args assert self.decode(kwargs['body'])['data'] == bytearray(b'foo') assert self.decode(kwargs['body']).get('encoding', '').strip('/') == '' async def test_with_json_dict_data(self): - channel = self.ably.channels["persisted:publish"] + channel = self.ably.channels['persisted:publish'] data = {'foó': 'bár'} - with mock.patch('ably.rest.rest.Http.post', - wraps=channel.ably.http.post) as post_mock: + with mock.patch('ably.rest.rest.Http.post', wraps=channel.ably.http.post) as post_mock: await channel.publish('event', data) _, kwargs = post_mock.call_args raw_data = json.loads(self.decode(kwargs['body'])['data']) @@ -299,10 +286,9 @@ async def test_with_json_dict_data(self): assert self.decode(kwargs['body'])['encoding'].strip('/') == 'json' async def test_with_json_list_data(self): - channel = self.ably.channels["persisted:publish"] + channel = self.ably.channels['persisted:publish'] data = ['foó', 'bár'] - with mock.patch('ably.rest.rest.Http.post', - wraps=channel.ably.http.post) as post_mock: + with mock.patch('ably.rest.rest.Http.post', wraps=channel.ably.http.post) as post_mock: await channel.publish('event', data) _, kwargs = post_mock.call_args raw_data = json.loads(self.decode(kwargs['body'])['data']) @@ -310,7 +296,7 @@ async def test_with_json_list_data(self): assert self.decode(kwargs['body'])['encoding'].strip('/') == 'json' async def test_text_utf8_decode(self): - channel = self.ably.channels["persisted:stringdecode-bin"] + channel = self.ably.channels['persisted:stringdecode-bin'] await channel.publish('event', 'fóo') history = await channel.history() @@ -320,7 +306,7 @@ async def test_text_utf8_decode(self): assert not message.encoding async def test_with_binary_type_decode(self): - channel = self.ably.channels["persisted:binarydecode-bin"] + channel = self.ably.channels['persisted:binarydecode-bin'] await channel.publish('event', bytearray(b'foob')) history = await channel.history() @@ -329,7 +315,7 @@ async def test_with_binary_type_decode(self): assert not message.encoding async def test_with_json_dict_data_decode(self): - channel = self.ably.channels["persisted:jsondict-bin"] + channel = self.ably.channels['persisted:jsondict-bin'] data = {'foó': 'bár'} await channel.publish('event', data) history = await channel.history() @@ -338,7 +324,7 @@ async def test_with_json_dict_data_decode(self): assert not message.encoding async def test_with_json_list_data_decode(self): - channel = self.ably.channels["persisted:jsonarray-bin"] + channel = self.ably.channels['persisted:jsonarray-bin'] data = ['foó', 'bár'] await channel.publish('event', data) history = await channel.history() @@ -348,7 +334,6 @@ async def test_with_json_list_data_decode(self): class TestBinaryEncodersEncryption(BaseAsyncTestCase): - async def asyncSetUp(self): self.ably = await TestApp.get_ably_rest() self.cipher_params = CipherParams(secret_key='keyfordecrypt_16', algorithm='aes') @@ -366,10 +351,8 @@ def decode(self, data): return msgpack.unpackb(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', - wraps=channel.ably.http.post) as post_mock: + channel = self.ably.channels.get('persisted:publish_enc', cipher=self.cipher_params) + with mock.patch('ably.rest.rest.Http.post', wraps=channel.ably.http.post) as post_mock: await channel.publish('event', 'fóo') _, kwargs = post_mock.call_args assert self.decode(kwargs['body'])['encoding'].strip('/') == 'utf-8/cipher+aes-128-cbc' @@ -377,11 +360,9 @@ async def test_text_utf8(self): assert data == 'fóo' async def test_with_binary_type(self): - channel = self.ably.channels.get("persisted:publish_enc", - cipher=self.cipher_params) + channel = self.ably.channels.get('persisted:publish_enc', cipher=self.cipher_params) - with mock.patch('ably.rest.rest.Http.post', - wraps=channel.ably.http.post) as post_mock: + with mock.patch('ably.rest.rest.Http.post', wraps=channel.ably.http.post) as post_mock: await channel.publish('event', bytearray(b'foo')) _, kwargs = post_mock.call_args @@ -391,11 +372,9 @@ async def test_with_binary_type(self): assert isinstance(data, bytearray) async def test_with_json_dict_data(self): - channel = self.ably.channels.get("persisted:publish_enc", - cipher=self.cipher_params) + channel = self.ably.channels.get('persisted:publish_enc', cipher=self.cipher_params) data = {'foó': 'bár'} - with mock.patch('ably.rest.rest.Http.post', - wraps=channel.ably.http.post) as post_mock: + with mock.patch('ably.rest.rest.Http.post', wraps=channel.ably.http.post) as post_mock: await channel.publish('event', data) _, kwargs = post_mock.call_args assert self.decode(kwargs['body'])['encoding'].strip('/') == 'json/utf-8/cipher+aes-128-cbc' @@ -403,11 +382,9 @@ async def test_with_json_dict_data(self): assert json.loads(raw_data) == data async def test_with_json_list_data(self): - channel = self.ably.channels.get("persisted:publish_enc", - cipher=self.cipher_params) + channel = self.ably.channels.get('persisted:publish_enc', cipher=self.cipher_params) data = ['foó', 'bár'] - with mock.patch('ably.rest.rest.Http.post', - wraps=channel.ably.http.post) as post_mock: + with mock.patch('ably.rest.rest.Http.post', wraps=channel.ably.http.post) as post_mock: await channel.publish('event', data) _, kwargs = post_mock.call_args assert self.decode(kwargs['body'])['encoding'].strip('/') == 'json/utf-8/cipher+aes-128-cbc' @@ -415,8 +392,7 @@ async def test_with_json_list_data(self): assert json.loads(raw_data) == data async def test_text_utf8_decode(self): - channel = self.ably.channels.get("persisted:enc_stringdecode-bin", - cipher=self.cipher_params) + channel = self.ably.channels.get('persisted:enc_stringdecode-bin', cipher=self.cipher_params) await channel.publish('event', 'foó') history = await channel.history() message = history.items[0] @@ -425,8 +401,7 @@ async def test_text_utf8_decode(self): assert not message.encoding async def test_with_binary_type_decode(self): - channel = self.ably.channels.get("persisted:enc_binarydecode-bin", - cipher=self.cipher_params) + channel = self.ably.channels.get('persisted:enc_binarydecode-bin', cipher=self.cipher_params) await channel.publish('event', bytearray(b'foob')) history = await channel.history() @@ -436,8 +411,7 @@ async def test_with_binary_type_decode(self): assert not message.encoding async def test_with_json_dict_data_decode(self): - channel = self.ably.channels.get("persisted:enc_jsondict-bin", - cipher=self.cipher_params) + channel = self.ably.channels.get('persisted:enc_jsondict-bin', cipher=self.cipher_params) data = {'foó': 'bár'} await channel.publish('event', data) history = await channel.history() @@ -446,8 +420,7 @@ async def test_with_json_dict_data_decode(self): assert not message.encoding async def test_with_json_list_data_decode(self): - channel = self.ably.channels.get("persisted:enc_list-bin", - cipher=self.cipher_params) + channel = self.ably.channels.get('persisted:enc_list-bin', cipher=self.cipher_params) data = ['foó', 'bár'] await channel.publish('event', data) history = await channel.history() diff --git a/test/ably/rest/restauth_test.py b/test/ably/rest/restauth_test.py index a6ac0ceb..8146c338 100644 --- a/test/ably/rest/restauth_test.py +++ b/test/ably/rest/restauth_test.py @@ -33,15 +33,15 @@ async def asyncSetUp(self): self.test_vars = await TestApp.get_test_vars() def test_auth_init_key_only(self): - ably = AblyRest(key=self.test_vars["keys"][0]["key_str"]) - assert Auth.Method.BASIC == ably.auth.auth_mechanism, "Unexpected Auth method mismatch" - assert ably.auth.auth_options.key_name == self.test_vars["keys"][0]['key_name'] - assert ably.auth.auth_options.key_secret == self.test_vars["keys"][0]['key_secret'] + ably = AblyRest(key=self.test_vars['keys'][0]['key_str']) + assert Auth.Method.BASIC == ably.auth.auth_mechanism, 'Unexpected Auth method mismatch' + assert ably.auth.auth_options.key_name == self.test_vars['keys'][0]['key_name'] + assert ably.auth.auth_options.key_secret == self.test_vars['keys'][0]['key_secret'] def test_auth_init_token_only(self): - ably = AblyRest(token="this_is_not_really_a_token") + ably = AblyRest(token='this_is_not_really_a_token') - assert Auth.Method.TOKEN == ably.auth.auth_mechanism, "Unexpected Auth method mismatch" + assert Auth.Method.TOKEN == ably.auth.auth_mechanism, 'Unexpected Auth method mismatch' def test_auth_token_details(self): td = TokenDetails() @@ -55,30 +55,29 @@ async def test_auth_init_with_token_callback(self): def token_callback(token_params): callback_called.append(True) - return "this_is_not_really_a_token_request" + return 'this_is_not_really_a_token_request' ably = await TestApp.get_ably_rest( - key=None, - key_name=self.test_vars["keys"][0]["key_name"], - auth_callback=token_callback) + key=None, key_name=self.test_vars['keys'][0]['key_name'], auth_callback=token_callback + ) try: await ably.stats(None) except Exception: pass - assert callback_called, "Token callback not called" - assert Auth.Method.TOKEN == ably.auth.auth_mechanism, "Unexpected Auth method mismatch" + assert callback_called, 'Token callback not called' + assert Auth.Method.TOKEN == ably.auth.auth_mechanism, 'Unexpected Auth method mismatch' def test_auth_init_with_key_and_client_id(self): - ably = AblyRest(key=self.test_vars["keys"][0]["key_str"], client_id='testClientId') + ably = AblyRest(key=self.test_vars['keys'][0]['key_str'], client_id='testClientId') - assert Auth.Method.BASIC == ably.auth.auth_mechanism, "Unexpected Auth method mismatch" + assert Auth.Method.BASIC == ably.auth.auth_mechanism, 'Unexpected Auth method mismatch' assert ably.auth.client_id == 'testClientId' async def test_auth_init_with_token(self): - ably = await TestApp.get_ably_rest(key=None, token="this_is_not_really_a_token") - assert Auth.Method.TOKEN == ably.auth.auth_mechanism, "Unexpected Auth method mismatch" + ably = await TestApp.get_ably_rest(key=None, token='this_is_not_really_a_token') + assert Auth.Method.TOKEN == ably.auth.auth_mechanism, 'Unexpected Auth method mismatch' # RSA11 async def test_request_basic_auth_header(self): @@ -123,11 +122,11 @@ def test_if_cant_authenticate_via_token(self): AblyRest(use_token_auth=True) def test_use_auth_token(self): - ably = AblyRest(use_token_auth=True, key=self.test_vars["keys"][0]["key_str"]) + ably = AblyRest(use_token_auth=True, key=self.test_vars['keys'][0]['key_str']) assert ably.auth.auth_mechanism == Auth.Method.TOKEN def test_with_client_id(self): - ably = AblyRest(use_token_auth=True, client_id='client_id', key=self.test_vars["keys"][0]["key_str"]) + ably = AblyRest(use_token_auth=True, client_id='client_id', key=self.test_vars['keys'][0]['key_str']) assert ably.auth.auth_mechanism == Auth.Method.TOKEN def test_with_auth_url(self): @@ -159,13 +158,11 @@ def test_with_auth_params(self): assert ably.auth.auth_options.auth_params == {'p': 'v'} def test_with_default_token_params(self): - ably = AblyRest(key=self.test_vars["keys"][0]["key_str"], - default_token_params={'ttl': 12345}) + ably = AblyRest(key=self.test_vars['keys'][0]['key_str'], default_token_params={'ttl': 12345}) assert ably.auth.auth_options.default_token_params == {'ttl': 12345} class TestAuthAuthorize(BaseAsyncTestCase, metaclass=VaryByProtocolTestsMetaclass): - async def asyncSetUp(self): self.ably = await TestApp.get_ably_rest() self.test_vars = await TestApp.get_test_vars() @@ -178,11 +175,11 @@ def per_protocol_setup(self, use_binary_protocol): self.use_binary_protocol = use_binary_protocol async def test_if_authorize_changes_auth_mechanism_to_token(self): - assert Auth.Method.BASIC == self.ably.auth.auth_mechanism, "Unexpected Auth method mismatch" + assert Auth.Method.BASIC == self.ably.auth.auth_mechanism, 'Unexpected Auth method mismatch' await self.ably.auth.authorize() - assert Auth.Method.TOKEN == self.ably.auth.auth_mechanism, "Authorize should change the Auth method" + assert Auth.Method.TOKEN == self.ably.auth.auth_mechanism, 'Authorize should change the Auth method' # RSA10a @dont_vary_protocol @@ -196,8 +193,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', - return_value=True): + with mock.patch('ably.rest.auth.Auth.token_details_has_expired', return_value=True): new_token = await self.ably.auth.authorize() assert token is not new_token @@ -218,27 +214,28 @@ async def test_authorize_adheres_to_request_token(self): # Authorize may call request_token with some default auth_options. for arg, value in auth_params.items(): - assert auth_called[arg] == value, "%s called with wrong value: %s" % (arg, value) + assert auth_called[arg] == value, '%s called with wrong value: %s' % (arg, value) async def test_with_token_str_https(self): token = await self.ably.auth.authorize() token = token.token - ably = await TestApp.get_ably_rest(key=None, token=token, tls=True, - use_binary_protocol=self.use_binary_protocol) + ably = await TestApp.get_ably_rest( + key=None, token=token, tls=True, use_binary_protocol=self.use_binary_protocol + ) await ably.channels.test_auth_with_token_str.publish('event', 'foo_bar') await ably.close() async def test_with_token_str_http(self): token = await self.ably.auth.authorize() token = token.token - ably = await TestApp.get_ably_rest(key=None, token=token, tls=False, - use_binary_protocol=self.use_binary_protocol) + ably = await TestApp.get_ably_rest( + key=None, token=token, tls=False, use_binary_protocol=self.use_binary_protocol + ) await ably.channels.test_auth_with_token_str.publish('event', 'foo_bar') await ably.close() async def test_if_default_client_id_is_used(self): - ably = await TestApp.get_ably_rest(client_id='my_client_id', - use_binary_protocol=self.use_binary_protocol) + ably = await TestApp.get_ably_rest(client_id='my_client_id', use_binary_protocol=self.use_binary_protocol) token = await ably.auth.authorize() assert token.client_id == 'my_client_id' await ably.close() @@ -249,8 +246,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', - wraps=self.ably.auth.request_token) as request_mock: + with mock.patch('ably.rest.auth.Auth.request_token', wraps=self.ably.auth.request_token) as request_mock: await self.ably.auth.authorize() token_called, auth_called = request_mock.call_args @@ -261,8 +257,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', - wraps=self.ably.auth.request_token) as request_mock: + with mock.patch('ably.rest.auth.Auth.request_token', wraps=self.ably.auth.request_token) as request_mock: await self.ably.auth.authorize() token_called, auth_called = request_mock.call_args @@ -274,27 +269,23 @@ async def test_timestamp_is_not_stored(self): # authorize once with arbitrary defaults auth_options = dict(self.ably.auth.auth_options.auth_options) auth_options['auth_headers'] = {'a_headers': 'a_value'} - token_1 = await self.ably.auth.authorize( - {'ttl': 60 * 1000, 'client_id': 'new_id'}, - auth_options) + token_1 = await self.ably.auth.authorize({'ttl': 60 * 1000, 'client_id': 'new_id'}, auth_options) assert isinstance(token_1, TokenDetails) # 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.rest.auth.TokenRequest', wraps=ably.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( - {'ttl': 60 * 1000, 'client_id': 'new_id', 'timestamp': timestamp}, - auth_options) + {'ttl': 60 * 1000, 'client_id': 'new_id', 'timestamp': timestamp}, auth_options + ) assert isinstance(token_2, TokenDetails) assert token_1 != token_2 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.rest.auth.TokenRequest', wraps=ably.types.tokenrequest.TokenRequest) as tr_mock: token_4 = await self.ably.auth.authorize() assert isinstance(token_4, TokenDetails) assert token_2 != token_4 @@ -306,13 +297,13 @@ async def test_client_id_precedence(self): ably = await TestApp.get_ably_rest( use_binary_protocol=self.use_binary_protocol, client_id=client_id, - default_token_params={'client_id': overridden_client_id}) + default_token_params={'client_id': overridden_client_id}, + ) token = await ably.auth.authorize() assert token.client_id == client_id assert ably.auth.client_id == client_id - channel = ably.channels[ - self.get_channel_name('test_client_id_precedence')] + channel = ably.channels[self.get_channel_name('test_client_id_precedence')] await channel.publish('test', 'data') history = await channel.history() assert history.items[0].client_id == client_id @@ -320,7 +311,6 @@ async def test_client_id_precedence(self): class TestRequestToken(BaseAsyncTestCase, metaclass=VaryByProtocolTestsMetaclass): - async def asyncSetUp(self): self.test_vars = await TestApp.get_test_vars() @@ -334,8 +324,9 @@ async def test_with_key(self): assert isinstance(token_details, TokenDetails) await ably.close() - ably = await TestApp.get_ably_rest(key=None, token_details=token_details, - use_binary_protocol=self.use_binary_protocol) + ably = await TestApp.get_ably_rest( + key=None, token_details=token_details, use_binary_protocol=self.use_binary_protocol + ) channel = self.get_channel_name('test_request_token_with_key') await ably.channels[channel].publish('event', 'foo') @@ -363,16 +354,20 @@ def call_back(request): assert parse_qs(request.content.decode('utf-8')) == {'foo': ['token'], 'spam': ['eggs']} return Response( status_code=200, - content="token_string", + content='token_string', headers={ - "Content-Type": "text/plain", - } + 'Content-Type': 'text/plain', + }, ) auth_route.side_effect = call_back token_details = await ably.auth.request_token( - token_params=token_params, auth_url=url, auth_headers=headers, - auth_method='POST', auth_params=auth_params) + token_params=token_params, + auth_url=url, + auth_headers=headers, + auth_method='POST', + auth_params=auth_params, + ) assert 1 == auth_route.called assert isinstance(token_details, TokenDetails) @@ -385,9 +380,11 @@ async def test_with_auth_url_headers_and_params_GET(self): # noqa: N802 url = 'http://www.example.com' headers = {'foo': 'bar'} ably = await TestApp.get_ably_rest( - key=None, auth_url=url, + key=None, + auth_url=url, auth_headers={'this': 'will_not_be_used'}, - auth_params={'this': 'will_not_be_used'}) + auth_params={'this': 'will_not_be_used'}, + ) auth_params = {'foo': 'auth', 'spam': 'eggs'} token_params = {'foo': 'token'} @@ -398,14 +395,12 @@ def call_back(request): assert 'this' not in request.headers assert not request.content - return Response( - status_code=200, - json={'issued': 1, 'token': 'another_token_string'} - ) + return Response(status_code=200, json={'issued': 1, 'token': 'another_token_string'}) + auth_route.side_effect = call_back token_details = await ably.auth.request_token( - token_params=token_params, auth_url=url, auth_headers=headers, - auth_params=auth_params) + token_params=token_params, auth_url=url, auth_headers=headers, auth_params=auth_params + ) assert 'another_token_string' == token_details.token await ably.close() @@ -419,8 +414,7 @@ async def callback(token_params): ably = await TestApp.get_ably_rest(key=None, auth_callback=callback) - token_details = await ably.auth.request_token( - token_params=called_token_params, auth_callback=callback) + token_details = await ably.auth.request_token(token_params=called_token_params, auth_callback=callback) assert isinstance(token_details, TokenDetails) assert 'token_string' == token_details.token @@ -428,8 +422,7 @@ async def callback(token_params): assert token_params == called_token_params return TokenDetails(token='another_token_string') - token_details = await ably.auth.request_token( - token_params=called_token_params, auth_callback=callback) + token_details = await ably.auth.request_token(token_params=called_token_params, auth_callback=callback) assert 'another_token_string' == token_details.token await ably.close() @@ -440,10 +433,9 @@ async def test_when_auth_url_has_query_string(self): headers = {'foo': 'bar'} ably = await TestApp.get_ably_rest(key=None, auth_url=url) auth_route = respx.get('http://www.example.com', params={'with': 'query', 'spam': 'eggs'}).mock( - return_value=Response(status_code=200, content='token_string', headers={"Content-Type": "text/plain"})) - await ably.auth.request_token(auth_url=url, - auth_headers=headers, - auth_params={'spam': 'eggs'}) + return_value=Response(status_code=200, content='token_string', headers={'Content-Type': 'text/plain'}) + ) + await ably.auth.request_token(auth_url=url, auth_headers=headers, auth_params={'spam': 'eggs'}) assert auth_route.called await ably.close() @@ -451,8 +443,9 @@ async def test_when_auth_url_has_query_string(self): async def test_client_id_null_for_anonymous_auth(self): ably = await TestApp.get_ably_rest( key=None, - key_name=self.test_vars["keys"][0]["key_name"], - key_secret=self.test_vars["keys"][0]["key_secret"]) + key_name=self.test_vars['keys'][0]['key_name'], + key_secret=self.test_vars['keys'][0]['key_secret'], + ) token = await ably.auth.authorize() assert isinstance(token, TokenDetails) @@ -463,8 +456,7 @@ async def test_client_id_null_for_anonymous_auth(self): @dont_vary_protocol async def test_client_id_null_until_auth(self): client_id = uuid.uuid4().hex - token_ably = await TestApp.get_ably_rest( - default_token_params={'client_id': client_id}) + token_ably = await TestApp.get_ably_rest(default_token_params={'client_id': client_id}) # before auth, client_id is None assert token_ably.auth.client_id is None @@ -478,7 +470,6 @@ async def test_client_id_null_until_auth(self): class TestRenewToken(BaseAsyncTestCase): - async def asyncSetUp(self): self.test_vars = await TestApp.get_test_vars() self.host = 'fake-host.ably.io' @@ -490,15 +481,12 @@ async def asyncSetUp(self): headers = {'Content-Type': 'application/json'} self.mocked_api = respx.mock(base_url='https://{}'.format(self.host)) self.request_token_route = self.mocked_api.post( - "/keys/{}/requestToken".format(self.test_vars["keys"][0]['key_name']), - name="request_token_route") + '/keys/{}/requestToken'.format(self.test_vars['keys'][0]['key_name']), name='request_token_route' + ) self.request_token_route.return_value = Response( status_code=200, headers=headers, - json={ - 'token': tokens[self.request_token_route.call_count - 1], - 'expires': (time.time() + 60) * 1000 - }, + json={'token': tokens[self.request_token_route.call_count - 1], 'expires': (time.time() + 60) * 1000}, ) def call_back(request): @@ -512,13 +500,12 @@ def call_back(request): return Response( status_code=401, headers=headers, - json={ - 'error': {'message': 'Authentication failure', 'statusCode': 401, 'code': 40140} - }, + json={'error': {'message': 'Authentication failure', 'statusCode': 401, 'code': 40140}}, ) - self.publish_attempt_route = self.mocked_api.post("/channels/{}/messages".format(self.channel), - name="publish_attempt_route") + self.publish_attempt_route = self.mocked_api.post( + '/channels/{}/messages'.format(self.channel), name='publish_attempt_route' + ) self.publish_attempt_route.side_effect = call_back self.mocked_api.start() @@ -532,12 +519,12 @@ async def asyncTearDown(self): async def test_when_renewable(self): await self.ably.auth.authorize() await self.ably.channels[self.channel].publish('evt', 'msg') - assert self.mocked_api["request_token_route"].call_count == 1 + assert self.mocked_api['request_token_route'].call_count == 1 assert self.publish_attempts == 1 # Triggers an authentication 401 failure which should automatically request a new token await self.ably.channels[self.channel].publish('evt', 'msg') - assert self.mocked_api["request_token_route"].call_count == 2 + assert self.mocked_api['request_token_route'].call_count == 2 assert self.publish_attempts == 3 # RSA4a @@ -548,68 +535,64 @@ async def test_when_not_renewable(self): key=None, rest_host=self.host, token='token ID cannot be used to create a new token', - use_binary_protocol=False) + use_binary_protocol=False, + ) await self.ably.channels[self.channel].publish('evt', 'msg') assert self.publish_attempts == 1 publish = self.ably.channels[self.channel].publish - match = "Need a new token but auth_options does not include a way to request one" + match = 'Need a new token but auth_options does not include a way to request one' with pytest.raises(AblyAuthException, match=match): await publish('evt', 'msg') - assert not self.mocked_api["request_token_route"].called + assert not self.mocked_api['request_token_route'].called # RSA4a async def test_when_not_renewable_with_token_details(self): token_details = TokenDetails(token='a_dummy_token') self.ably = await TestApp.get_ably_rest( - key=None, - rest_host=self.host, - token_details=token_details, - use_binary_protocol=False) + key=None, rest_host=self.host, token_details=token_details, use_binary_protocol=False + ) await self.ably.channels[self.channel].publish('evt', 'msg') - assert self.mocked_api["publish_attempt_route"].call_count == 1 + assert self.mocked_api['publish_attempt_route'].call_count == 1 publish = self.ably.channels[self.channel].publish - match = "Need a new token but auth_options does not include a way to request one" + match = 'Need a new token but auth_options does not include a way to request one' with pytest.raises(AblyAuthException, match=match): await publish('evt', 'msg') - assert not self.mocked_api["request_token_route"].called + assert not self.mocked_api['request_token_route'].called class TestRenewExpiredToken(BaseAsyncTestCase): - async def asyncSetUp(self): self.test_vars = await TestApp.get_test_vars() self.publish_attempts = 0 self.channel = uuid.uuid4().hex self.host = 'fake-host.ably.io' - key = self.test_vars["keys"][0]['key_name'] + key = self.test_vars['keys'][0]['key_name'] headers = {'Content-Type': 'application/json'} self.mocked_api = respx.mock(base_url='https://{}'.format(self.host)) - self.request_token_route = self.mocked_api.post("/keys/{}/requestToken".format(key), - name="request_token_route") + self.request_token_route = self.mocked_api.post( + '/keys/{}/requestToken'.format(key), name='request_token_route' + ) self.request_token_route.return_value = Response( status_code=200, headers=headers, json={ 'token': 'a_token', 'expires': int(time.time() * 1000), # Always expires - } + }, ) - self.publish_message_route = self.mocked_api.post("/channels/{}/messages".format(self.channel), - name="publish_message_route") - self.time_route = self.mocked_api.get("/time", name="time_route") - self.time_route.return_value = Response( - status_code=200, - headers=headers, - json=[int(time.time() * 1000)] + self.publish_message_route = self.mocked_api.post( + '/channels/{}/messages'.format(self.channel), name='publish_message_route' ) + self.time_route = self.mocked_api.get('/time', name='time_route') + self.time_route.return_value = Response(status_code=200, headers=headers, json=[int(time.time() * 1000)]) def cb_publish(request): self.publish_attempts += 1 @@ -617,14 +600,9 @@ def cb_publish(request): self.publish_fail = False return Response( status_code=401, - json={ - 'error': {'message': 'Authentication failure', 'statusCode': 401, 'code': 40140} - } + json={'error': {'message': 'Authentication failure', 'statusCode': 401, 'code': 40140}}, ) - return Response( - status_code=201, - json='[]' - ) + return Response(status_code=201, json='[]') self.publish_message_route.side_effect = cb_publish self.mocked_api.start() diff --git a/test/ably/rest/restcapability_test.py b/test/ably/rest/restcapability_test.py index 0182dcb0..74fa3ecc 100644 --- a/test/ably/rest/restcapability_test.py +++ b/test/ably/rest/restcapability_test.py @@ -8,7 +8,6 @@ class TestRestCapability(BaseAsyncTestCase, metaclass=VaryByProtocolTestsMetaclass): - async def asyncSetUp(self): self.test_vars = await TestApp.get_test_vars() self.ably = await TestApp.get_ably_rest() @@ -21,24 +20,22 @@ def per_protocol_setup(self, use_binary_protocol): async def test_blanket_intersection_with_key(self): key = self.test_vars['keys'][1] - token_details = await self.ably.auth.request_token(key_name=key['key_name'], - key_secret=key['key_secret']) - expected_capability = Capability(key["capability"]) - assert token_details.token is not None, "Expected token" - assert expected_capability == token_details.capability, "Unexpected capability." + token_details = await self.ably.auth.request_token(key_name=key['key_name'], key_secret=key['key_secret']) + expected_capability = Capability(key['capability']) + assert token_details.token is not None, 'Expected token' + assert expected_capability == token_details.capability, 'Unexpected capability.' async def test_equal_intersection_with_key(self): key = self.test_vars['keys'][1] token_details = await self.ably.auth.request_token( - key_name=key['key_name'], - key_secret=key['key_secret'], - token_params={'capability': key['capability']}) + key_name=key['key_name'], key_secret=key['key_secret'], token_params={'capability': key['capability']} + ) - expected_capability = Capability(key["capability"]) + expected_capability = Capability(key['capability']) - assert token_details.token is not None, "Expected token" - assert expected_capability == token_details.capability, "Unexpected capability" + assert token_details.token is not None, 'Expected token' + assert expected_capability == token_details.capability, 'Unexpected capability' @dont_vary_protocol async def test_empty_ops_intersection(self): @@ -47,7 +44,8 @@ async def test_empty_ops_intersection(self): await self.ably.auth.request_token( key_name=key['key_name'], key_secret=key['key_secret'], - token_params={'capability': {'testchannel': ['subscribe']}}) + token_params={'capability': {'testchannel': ['subscribe']}}, + ) @dont_vary_protocol async def test_empty_paths_intersection(self): @@ -56,167 +54,146 @@ async def test_empty_paths_intersection(self): await self.ably.auth.request_token( key_name=key['key_name'], key_secret=key['key_secret'], - token_params={'capability': {"testchannelx": ["publish"]}}) + token_params={'capability': {'testchannelx': ['publish']}}, + ) async def test_non_empty_ops_intersection(self): key = self.test_vars['keys'][4] - token_params = {"capability": { - "channel2": ["presence", "subscribe"] - }} + token_params = {'capability': {'channel2': ['presence', 'subscribe']}} kwargs = { - "key_name": key["key_name"], - "key_secret": key["key_secret"], + 'key_name': key['key_name'], + 'key_secret': key['key_secret'], } - expected_capability = Capability({ - "channel2": ["subscribe"] - }) + expected_capability = Capability({'channel2': ['subscribe']}) token_details = await self.ably.auth.request_token(token_params, **kwargs) - assert token_details.token is not None, "Expected token" - assert expected_capability == token_details.capability, "Unexpected capability" + assert token_details.token is not None, 'Expected token' + assert expected_capability == token_details.capability, 'Unexpected capability' async def test_non_empty_paths_intersection(self): key = self.test_vars['keys'][4] token_params = { - "capability": { - "channel2": ["presence", "subscribe"], - "channelx": ["presence", "subscribe"], + 'capability': { + 'channel2': ['presence', 'subscribe'], + 'channelx': ['presence', 'subscribe'], } } - kwargs = { - "key_name": key["key_name"], - - "key_secret": key["key_secret"] - } + kwargs = {'key_name': key['key_name'], 'key_secret': key['key_secret']} - expected_capability = Capability({ - "channel2": ["subscribe"] - }) + expected_capability = Capability({'channel2': ['subscribe']}) token_details = await self.ably.auth.request_token(token_params, **kwargs) - assert token_details.token is not None, "Expected token" - assert expected_capability == token_details.capability, "Unexpected capability" + assert token_details.token is not None, 'Expected token' + assert expected_capability == token_details.capability, 'Unexpected capability' async def test_wildcard_ops_intersection(self): key = self.test_vars['keys'][4] token_params = { - "capability": { - "channel2": ["*"], + 'capability': { + 'channel2': ['*'], }, } kwargs = { - "key_name": key["key_name"], - "key_secret": key["key_secret"], + 'key_name': key['key_name'], + 'key_secret': key['key_secret'], } - expected_capability = Capability({ - "channel2": ["subscribe", "publish"] - }) + expected_capability = Capability({'channel2': ['subscribe', 'publish']}) token_details = await self.ably.auth.request_token(token_params, **kwargs) - assert token_details.token is not None, "Expected token" - assert expected_capability == token_details.capability, "Unexpected capability" + assert token_details.token is not None, 'Expected token' + assert expected_capability == token_details.capability, 'Unexpected capability' async def test_wildcard_ops_intersection_2(self): key = self.test_vars['keys'][4] token_params = { - "capability": { - "channel6": ["publish", "subscribe"], + 'capability': { + 'channel6': ['publish', 'subscribe'], }, } kwargs = { - "key_name": key["key_name"], - "key_secret": key["key_secret"], + 'key_name': key['key_name'], + 'key_secret': key['key_secret'], } - expected_capability = Capability({ - "channel6": ["subscribe", "publish"] - }) + expected_capability = Capability({'channel6': ['subscribe', 'publish']}) token_details = await self.ably.auth.request_token(token_params, **kwargs) - assert token_details.token is not None, "Expected token" - assert expected_capability == token_details.capability, "Unexpected capability" + assert token_details.token is not None, 'Expected token' + assert expected_capability == token_details.capability, 'Unexpected capability' async def test_wildcard_resources_intersection(self): key = self.test_vars['keys'][2] token_params = { - "capability": { - "cansubscribe": ["subscribe"], + 'capability': { + 'cansubscribe': ['subscribe'], }, } kwargs = { - "key_name": key["key_name"], - "key_secret": key["key_secret"], + 'key_name': key['key_name'], + 'key_secret': key['key_secret'], } - expected_capability = Capability({ - "cansubscribe": ["subscribe"] - }) + expected_capability = Capability({'cansubscribe': ['subscribe']}) token_details = await self.ably.auth.request_token(token_params, **kwargs) - assert token_details.token is not None, "Expected token" - assert expected_capability == token_details.capability, "Unexpected capability" + assert token_details.token is not None, 'Expected token' + assert expected_capability == token_details.capability, 'Unexpected capability' async def test_wildcard_resources_intersection_2(self): key = self.test_vars['keys'][2] token_params = { - "capability": { - "cansubscribe:check": ["subscribe"], + 'capability': { + 'cansubscribe:check': ['subscribe'], }, } kwargs = { - "key_name": key["key_name"], - "key_secret": key["key_secret"], + 'key_name': key['key_name'], + 'key_secret': key['key_secret'], } - expected_capability = Capability({ - "cansubscribe:check": ["subscribe"] - }) + expected_capability = Capability({'cansubscribe:check': ['subscribe']}) token_details = await self.ably.auth.request_token(token_params, **kwargs) - assert token_details.token is not None, "Expected token" - assert expected_capability == token_details.capability, "Unexpected capability" + assert token_details.token is not None, 'Expected token' + assert expected_capability == token_details.capability, 'Unexpected capability' async def test_wildcard_resources_intersection_3(self): key = self.test_vars['keys'][2] token_params = { - "capability": { - "cansubscribe:*": ["subscribe"], + 'capability': { + 'cansubscribe:*': ['subscribe'], }, } kwargs = { - "key_name": key["key_name"], - "key_secret": key["key_secret"], - + 'key_name': key['key_name'], + 'key_secret': key['key_secret'], } - expected_capability = Capability({ - "cansubscribe:*": ["subscribe"] - }) + expected_capability = Capability({'cansubscribe:*': ['subscribe']}) token_details = await self.ably.auth.request_token(token_params, **kwargs) - assert token_details.token is not None, "Expected token" - assert expected_capability == token_details.capability, "Unexpected capability" + assert token_details.token is not None, 'Expected token' + assert expected_capability == token_details.capability, 'Unexpected capability' @dont_vary_protocol async def test_invalid_capabilities(self): with pytest.raises(AblyException) as excinfo: - await self.ably.auth.request_token( - token_params={'capability': {"channel0": ["publish_"]}}) + await self.ably.auth.request_token(token_params={'capability': {'channel0': ['publish_']}}) the_exception = excinfo.value assert 400 == the_exception.status_code @@ -225,8 +202,7 @@ async def test_invalid_capabilities(self): @dont_vary_protocol async def test_invalid_capabilities_2(self): with pytest.raises(AblyException) as excinfo: - await self.ably.auth.request_token( - token_params={'capability': {"channel0": ["*", "publish"]}}) + await self.ably.auth.request_token(token_params={'capability': {'channel0': ['*', 'publish']}}) the_exception = excinfo.value assert 400 == the_exception.status_code @@ -235,8 +211,7 @@ async def test_invalid_capabilities_2(self): @dont_vary_protocol async def test_invalid_capabilities_3(self): with pytest.raises(AblyException) as excinfo: - await self.ably.auth.request_token( - token_params={'capability': {"channel0": []}}) + await self.ably.auth.request_token(token_params={'capability': {'channel0': []}}) the_exception = excinfo.value assert 400 == the_exception.status_code diff --git a/test/ably/rest/restchannelhistory_test.py b/test/ably/rest/restchannelhistory_test.py index d1ea1591..6af4273e 100644 --- a/test/ably/rest/restchannelhistory_test.py +++ b/test/ably/rest/restchannelhistory_test.py @@ -12,7 +12,6 @@ class TestRestChannelHistory(BaseAsyncTestCase, metaclass=VaryByProtocolTestsMetaclass): - async def asyncSetUp(self): self.ably = await TestApp.get_ably_rest(fallback_hosts=[]) self.test_vars = await TestApp.get_test_vars() @@ -34,18 +33,22 @@ async def test_channel_history_types(self): history = await history0.history() assert isinstance(history, PaginatedResult) messages = history.items - assert messages is not None, "Expected non-None messages" - assert 4 == len(messages), "Expected 4 messages" + assert messages is not None, 'Expected non-None messages' + assert 4 == len(messages), 'Expected 4 messages' message_contents = {m.name: m for m in messages} - assert "This is a string message payload" == message_contents["history0"].data, \ - "Expect history0 to be expected String)" - assert b"This is a byte[] message payload" == message_contents["history1"].data, \ - "Expect history1 to be expected byte[]" - assert {"test": "This is a JSONObject message payload"} == message_contents["history2"].data, \ - "Expect history2 to be expected JSONObject" - assert ["This is a JSONArray message payload"] == message_contents["history3"].data, \ - "Expect history3 to be expected JSONObject" + assert ( + 'This is a string message payload' == message_contents['history0'].data + ), 'Expect history0 to be expected String)' + assert ( + b'This is a byte[] message payload' == message_contents['history1'].data + ), 'Expect history1 to be expected byte[]' + assert {'test': 'This is a JSONObject message payload'} == message_contents[ + 'history2' + ].data, 'Expect history2 to be expected JSONObject' + assert ['This is a JSONArray message payload'] == message_contents[ + 'history3' + ].data, 'Expect history3 to be expected JSONObject' expected_message_history = [ message_contents['history3'], @@ -53,7 +56,7 @@ async def test_channel_history_types(self): message_contents['history1'], message_contents['history0'], ] - assert expected_message_history == messages, "Expect messages in reverse order" + assert expected_message_history == messages, 'Expect messages in reverse order' async def test_channel_history_multi_50_forwards(self): history0 = self.get_channel('persisted:channelhistory_multi_50_f') @@ -64,7 +67,7 @@ async def test_channel_history_multi_50_forwards(self): history = await history0.history(direction='forwards') assert history is not None messages = history.items - assert len(messages) == 50, "Expected 50 messages" + assert len(messages) == 50, 'Expected 50 messages' message_contents = {m.name: m for m in messages} expected_messages = [message_contents['history%d' % i] for i in range(50)] @@ -79,7 +82,7 @@ async def test_channel_history_multi_50_backwards(self): history = await history0.history(direction='backwards') assert history is not None messages = history.items - assert 50 == len(messages), "Expected 50 messages" + assert 50 == len(messages), 'Expected 50 messages' message_contents = {m.name: m for m in messages} expected_messages = [message_contents['history%d' % i] for i in range(49, -1, -1)] @@ -89,7 +92,7 @@ def history_mock_url(self, channel_name): kwargs = { 'scheme': 'https' if self.test_vars['tls'] else 'http', 'host': self.test_vars['host'], - 'channel_name': channel_name + 'channel_name': channel_name, } port = self.test_vars['tls_port'] if self.test_vars.get('tls') else kwargs['port'] if port == 80: @@ -138,7 +141,7 @@ async def test_channel_history_limit_forwards(self): history = await history0.history(direction='forwards', limit=25) assert history is not None messages = history.items - assert len(messages) == 25, "Expected 25 messages" + assert len(messages) == 25, 'Expected 25 messages' message_contents = {m.name: m for m in messages} expected_messages = [message_contents['history%d' % i] for i in range(25)] @@ -153,7 +156,7 @@ async def test_channel_history_limit_backwards(self): history = await history0.history(direction='backwards', limit=25) assert history is not None messages = history.items - assert len(messages) == 25, "Expected 25 messages" + assert len(messages) == 25, 'Expected 25 messages' message_contents = {m.name: m for m in messages} expected_messages = [message_contents['history%d' % i] for i in range(49, 24, -1)] @@ -175,8 +178,7 @@ async def test_channel_history_time_forwards(self): for i in range(40, 60): await history0.publish('history%d' % i, str(i)) - history = await history0.history(direction='forwards', start=interval_start, - end=interval_end) + history = await history0.history(direction='forwards', start=interval_start, end=interval_end) messages = history.items assert 20 == len(messages) @@ -201,8 +203,7 @@ async def test_channel_history_time_backwards(self): for i in range(40, 60): await history0.publish('history%d' % i, str(i)) - history = await history0.history(direction='backwards', start=interval_start, - end=interval_end) + history = await history0.history(direction='backwards', start=interval_start, end=interval_end) messages = history.items assert 20 == len(messages) diff --git a/test/ably/rest/restchannelpublish_test.py b/test/ably/rest/restchannelpublish_test.py index 6cf458eb..fa6c03de 100644 --- a/test/ably/rest/restchannelpublish_test.py +++ b/test/ably/rest/restchannelpublish_test.py @@ -26,7 +26,6 @@ # Ignore library warning regarding client_id @pytest.mark.filterwarnings('ignore::DeprecationWarning') class TestRestChannelPublish(BaseAsyncTestCase, metaclass=VaryByProtocolTestsMetaclass): - async def asyncSetUp(self): self.test_vars = await TestApp.get_test_vars() self.ably = await TestApp.get_ably_rest() @@ -43,47 +42,49 @@ def per_protocol_setup(self, use_binary_protocol): self.use_binary_protocol = use_binary_protocol async def test_publish_various_datatypes_text(self): - publish0 = self.ably.channels[ - self.get_channel_name('persisted:publish0')] + publish0 = self.ably.channels[self.get_channel_name('persisted:publish0')] - await publish0.publish("publish0", "This is a string message payload") - await publish0.publish("publish1", b"This is a byte[] message payload") - await publish0.publish("publish2", {"test": "This is a JSONObject message payload"}) - await publish0.publish("publish3", ["This is a JSONArray message payload"]) + await publish0.publish('publish0', 'This is a string message payload') + await publish0.publish('publish1', b'This is a byte[] message payload') + await publish0.publish('publish2', {'test': 'This is a JSONObject message payload'}) + await publish0.publish('publish3', ['This is a JSONArray message payload']) # Get the history for this channel history = await publish0.history() messages = history.items - assert messages is not None, "Expected non-None messages" - assert len(messages) == 4, "Expected 4 messages" + assert messages is not None, 'Expected non-None messages' + assert len(messages) == 4, 'Expected 4 messages' message_contents = dict((m.name, m.data) for m in messages) - log.debug("message_contents: %s" % str(message_contents)) + log.debug('message_contents: %s' % str(message_contents)) - assert message_contents["publish0"] == "This is a string message payload", \ - "Expect publish0 to be expected String)" + assert ( + message_contents['publish0'] == 'This is a string message payload' + ), 'Expect publish0 to be expected String)' - assert message_contents["publish1"] == b"This is a byte[] message payload", \ - "Expect publish1 to be expected byte[]. Actual: %s" % str(message_contents['publish1']) + assert ( + message_contents['publish1'] == b'This is a byte[] message payload' + ), 'Expect publish1 to be expected byte[]. Actual: %s' % str(message_contents['publish1']) - assert message_contents["publish2"] == {"test": "This is a JSONObject message payload"}, \ - "Expect publish2 to be expected JSONObject" + assert message_contents['publish2'] == { + 'test': 'This is a JSONObject message payload' + }, 'Expect publish2 to be expected JSONObject' - assert message_contents["publish3"] == ["This is a JSONArray message payload"], \ - "Expect publish3 to be expected JSONObject" + assert message_contents['publish3'] == [ + 'This is a JSONArray message payload' + ], 'Expect publish3 to be expected JSONObject' @dont_vary_protocol async def test_unsupported_payload_must_raise_exception(self): - channel = self.ably.channels["persisted:publish0"] + channel = self.ably.channels['persisted:publish0'] for data in [1, 1.1, True]: with pytest.raises(AblyException): await channel.publish('event', data) async def test_publish_message_list(self): - channel = self.ably.channels[ - self.get_channel_name('persisted:message_list_channel')] + channel = self.ably.channels[self.get_channel_name('persisted:message_list_channel')] - expected_messages = [Message("name-{}".format(i), str(i)) for i in range(3)] + expected_messages = [Message('name-{}'.format(i), str(i)) for i in range(3)] await channel.publish(messages=expected_messages) @@ -91,21 +92,19 @@ async def test_publish_message_list(self): history = await channel.history() messages = history.items - assert messages is not None, "Expected non-None messages" - assert len(messages) == len(expected_messages), "Expected 3 messages" + assert messages is not None, 'Expected non-None messages' + assert len(messages) == len(expected_messages), 'Expected 3 messages' for m, expected_m in zip(messages, reversed(expected_messages)): assert m.name == expected_m.name assert m.data == expected_m.data async def test_message_list_generate_one_request(self): - channel = self.ably.channels[ - self.get_channel_name('persisted:message_list_channel_one_request')] + channel = self.ably.channels[self.get_channel_name('persisted:message_list_channel_one_request')] - expected_messages = [Message("name-{}".format(i), str(i)) for i in range(3)] + expected_messages = [Message('name-{}'.format(i), str(i)) for i in range(3)] - with mock.patch('ably.rest.rest.Http.post', - wraps=channel.ably.http.post) as post_mock: + with mock.patch('ably.rest.rest.Http.post', wraps=channel.ably.http.post) as post_mock: await channel.publish(messages=expected_messages) assert post_mock.call_count == 1 @@ -120,52 +119,48 @@ async def test_message_list_generate_one_request(self): async def test_publish_error(self): ably = await TestApp.get_ably_rest(use_binary_protocol=self.use_binary_protocol) - await ably.auth.authorize( - token_params={'capability': {"only_subscribe": ["subscribe"]}}) + await ably.auth.authorize(token_params={'capability': {'only_subscribe': ['subscribe']}}) with pytest.raises(AblyException) as excinfo: - await ably.channels["only_subscribe"].publish() + await ably.channels['only_subscribe'].publish() assert 401 == excinfo.value.status_code assert 40160 == excinfo.value.code await ably.close() async def test_publish_message_null_name(self): - channel = self.ably.channels[ - self.get_channel_name('persisted:message_null_name_channel')] + channel = self.ably.channels[self.get_channel_name('persisted:message_null_name_channel')] - data = "String message" + data = 'String message' await channel.publish(name=None, data=data) # Get the history for this channel history = await channel.history() messages = history.items - assert messages is not None, "Expected non-None messages" - assert len(messages) == 1, "Expected 1 message" + assert messages is not None, 'Expected non-None messages' + assert len(messages) == 1, 'Expected 1 message' assert messages[0].name is None assert messages[0].data == data async def test_publish_message_null_data(self): - channel = self.ably.channels[ - self.get_channel_name('persisted:message_null_data_channel')] + channel = self.ably.channels[self.get_channel_name('persisted:message_null_data_channel')] - name = "Test name" + name = 'Test name' await channel.publish(name=name, data=None) # Get the history for this channel history = await channel.history() messages = history.items - assert messages is not None, "Expected non-None messages" - assert len(messages) == 1, "Expected 1 message" + assert messages is not None, 'Expected non-None messages' + assert len(messages) == 1, 'Expected 1 message' assert messages[0].name == name assert messages[0].data is None async def test_publish_message_null_name_and_data(self): - channel = self.ably.channels[ - self.get_channel_name('persisted:null_name_and_data_channel')] + channel = self.ably.channels[self.get_channel_name('persisted:null_name_and_data_channel')] await channel.publish(name=None, data=None) await channel.publish() @@ -174,26 +169,24 @@ async def test_publish_message_null_name_and_data(self): history = await channel.history() messages = history.items - assert messages is not None, "Expected non-None messages" - assert len(messages) == 2, "Expected 2 messages" + assert messages is not None, 'Expected non-None messages' + assert len(messages) == 2, 'Expected 2 messages' for m in messages: assert m.name is None assert m.data is None 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')] + 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', - wraps=channel.ably.http.post) as post_mock: + with mock.patch('ably.rest.rest.Http.post', wraps=channel.ably.http.post) as post_mock: await channel.publish(name=None, data=None) history = await channel.history() messages = history.items - assert messages is not None, "Expected non-None messages" - assert len(messages) == 1, "Expected 1 message" + assert messages is not None, 'Expected non-None messages' + assert len(messages) == 1, 'Expected 1 message' assert post_mock.call_count == 1 @@ -206,12 +199,9 @@ async def test_publish_message_null_name_and_data_keys_arent_sent(self): assert 'data' not in posted_body async def test_message_attr(self): - publish0 = self.ably.channels[ - self.get_channel_name('persisted:publish_message_attr')] + publish0 = self.ably.channels[self.get_channel_name('persisted:publish_message_attr')] - messages = [Message('publish', - {"test": "This is a JSONObject message payload"}, - client_id='client_id')] + messages = [Message('publish', {'test': 'This is a JSONObject message payload'}, client_id='client_id')] await publish0.publish(messages=messages) # Get the history for this channel @@ -230,8 +220,7 @@ async def test_token_is_bound_to_options_client_id_after_publish(self): assert self.ably_with_client_id.auth.token_details is None # created after message publish and will have client_id - channel = self.ably_with_client_id.channels[ - self.get_channel_name('persisted:restricted_to_client_id')] + channel = self.ably_with_client_id.channels[self.get_channel_name('persisted:restricted_to_client_id')] await channel.publish(name='publish', data='test') # defined after publish @@ -243,26 +232,24 @@ async def test_token_is_bound_to_options_client_id_after_publish(self): 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')] + self.get_channel_name('persisted:no_client_id_identified_client') + ] - with mock.patch('ably.rest.rest.Http.post', - wraps=channel.ably.http.post) as post_mock: + with mock.patch('ably.rest.rest.Http.post', wraps=channel.ably.http.post) as post_mock: await channel.publish(name='publish', data='test') history = await channel.history() messages = history.items - assert messages is not None, "Expected non-None messages" - assert len(messages) == 1, "Expected 1 message" + assert messages is not None, 'Expected non-None messages' + assert len(messages) == 1, 'Expected 1 message' assert post_mock.call_count == 2 if self.use_binary_protocol: - posted_body = msgpack.unpackb( - post_mock.mock_calls[0][2]['body']) + posted_body = msgpack.unpackb(post_mock.mock_calls[0][2]['body']) else: - posted_body = json.loads( - post_mock.mock_calls[0][2]['body']) + posted_body = json.loads(post_mock.mock_calls[0][2]['body']) assert 'client_id' not in posted_body @@ -270,23 +257,24 @@ async def test_publish_message_without_client_id_on_identified_client(self): history = await channel.history() messages = history.items - assert messages is not None, "Expected non-None messages" - assert len(messages) == 1, "Expected 1 message" + assert messages is not None, 'Expected non-None messages' + assert len(messages) == 1, 'Expected 1 message' assert messages[0].client_id == self.ably_with_client_id.client_id async def test_publish_message_with_client_id_on_identified_client(self): # works if same channel = self.ably_with_client_id.channels[ - self.get_channel_name('persisted:with_client_id_identified_client')] + self.get_channel_name('persisted:with_client_id_identified_client') + ] message = Message(name='publish', data='test', client_id=self.ably_with_client_id.client_id) await channel.publish(message) history = await channel.history() messages = history.items - assert messages is not None, "Expected non-None messages" - assert len(messages) == 1, "Expected 1 message" + assert messages is not None, 'Expected non-None messages' + assert len(messages) == 1, 'Expected 1 message' assert messages[0].client_id == self.ably_with_client_id.client_id @@ -297,12 +285,11 @@ async def test_publish_message_with_client_id_on_identified_client(self): async def test_publish_message_with_wrong_client_id_on_implicit_identified_client(self): new_token = await self.ably.auth.authorize(token_params={'client_id': uuid.uuid4().hex}) - new_ably = await TestApp.get_ably_rest(key=None, - token=new_token.token, - use_binary_protocol=self.use_binary_protocol) + new_ably = await TestApp.get_ably_rest( + key=None, token=new_token.token, use_binary_protocol=self.use_binary_protocol + ) - channel = new_ably.channels[ - self.get_channel_name('persisted:wrong_client_id_implicit_client')] + channel = new_ably.channels[self.get_channel_name('persisted:wrong_client_id_implicit_client')] message = Message(name='publish', data='test', client_id='invalid') with pytest.raises(AblyException) as excinfo: @@ -316,13 +303,11 @@ async def test_publish_message_with_wrong_client_id_on_implicit_identified_clien async def test_wildcard_client_id_can_publish_as_others(self): wildcard_token_details = await self.ably.auth.request_token({'client_id': '*'}) wildcard_ably = await TestApp.get_ably_rest( - key=None, - token_details=wildcard_token_details, - use_binary_protocol=self.use_binary_protocol) + key=None, token_details=wildcard_token_details, use_binary_protocol=self.use_binary_protocol + ) assert wildcard_ably.auth.client_id == '*' - channel = wildcard_ably.channels[ - self.get_channel_name('persisted:wildcard_client_id')] + channel = wildcard_ably.channels[self.get_channel_name('persisted:wildcard_client_id')] await channel.publish(name='publish1', data='no client_id') some_client_id = uuid.uuid4().hex message = Message(name='publish2', data='some client_id', client_id=some_client_id) @@ -331,8 +316,8 @@ async def test_wildcard_client_id_can_publish_as_others(self): history = await channel.history() messages = history.items - assert messages is not None, "Expected non-None messages" - assert len(messages) == 2, "Expected 2 messages" + assert messages is not None, 'Expected non-None messages' + assert len(messages) == 2, 'Expected 2 messages' assert messages[0].client_id == some_client_id assert messages[1].client_id is None @@ -342,7 +327,7 @@ async def test_wildcard_client_id_can_publish_as_others(self): # TM2h @dont_vary_protocol async def test_invalid_connection_key(self): - channel = self.ably.channels["persisted:invalid_connection_key"] + channel = self.ably.channels['persisted:invalid_connection_key'] message = Message(data='payload', connection_key='should.be.wrong') with pytest.raises(AblyException) as excinfo: await channel.publish(messages=[message]) @@ -352,11 +337,10 @@ async def test_invalid_connection_key(self): # TM2i, RSL6a2, RSL1h async def test_publish_extras(self): - channel = self.ably.channels[ - self.get_channel_name('canpublish:extras_channel')] + channel = self.ably.channels[self.get_channel_name('canpublish:extras_channel')] extras = { 'push': { - 'notification': {"title": "Testing"}, + 'notification': {'title': 'Testing'}, } } message = Message(name='test-name', data='test-data', extras=extras) @@ -374,7 +358,7 @@ async def test_interoperability(self): name = self.get_channel_name('persisted:interoperability_channel') channel = self.ably.channels[name] - url = 'https://%s/channels/%s/messages' % (self.test_vars["host"], name) + url = 'https://%s/channels/%s/messages' % (self.test_vars['host'], name) key = self.test_vars['keys'][0] auth = (key['key_name'], key['key_secret']) @@ -442,7 +426,6 @@ async def test_publish_params(self): class TestRestChannelPublishIdempotent(BaseAsyncTestCase, metaclass=VaryByProtocolTestsMetaclass): - async def asyncSetUp(self): self.ably = await TestApp.get_ably_rest() self.ably_idempotent = await TestApp.get_ably_rest(idempotent_rest_publishing=True) @@ -530,7 +513,7 @@ def get_ably_rest(self, *args, **kwargs): # RSL1k4 async def test_idempotent_library_generated_retry(self): test_vars = await TestApp.get_test_vars() - ably = await self.get_ably_rest(idempotent_rest_publishing=True, fallback_hosts=[test_vars["host"]] * 3) + ably = await self.get_ably_rest(idempotent_rest_publishing=True, fallback_hosts=[test_vars['host']] * 3) channel = ably.channels[self.get_channel_name()] state = {'failures': 0} diff --git a/test/ably/rest/restchannels_test.py b/test/ably/rest/restchannels_test.py index b567781f..f66ae1f6 100644 --- a/test/ably/rest/restchannels_test.py +++ b/test/ably/rest/restchannels_test.py @@ -12,7 +12,6 @@ # makes no request, no need to use different protocols class TestChannels(BaseAsyncTestCase): - async def asyncSetUp(self): self.test_vars = await TestApp.get_test_vars() self.ably = await TestApp.get_ably_rest() @@ -82,8 +81,8 @@ def test_channel_has_presence(self): assert isinstance(channel.presence, Presence) async def test_without_permissions(self): - key = self.test_vars["keys"][2] - ably = await TestApp.get_ably_rest(key=key["key_str"]) + key = self.test_vars['keys'][2] + ably = await TestApp.get_ably_rest(key=key['key_str']) with pytest.raises(AblyException) as excinfo: await ably.channels['test_publish_without_permission'].publish('foo', 'woop') diff --git a/test/ably/rest/restchannelstatus_test.py b/test/ably/rest/restchannelstatus_test.py index c1c6e5e1..7ae30634 100644 --- a/test/ably/rest/restchannelstatus_test.py +++ b/test/ably/rest/restchannelstatus_test.py @@ -7,7 +7,6 @@ class TestRestChannelStatus(BaseAsyncTestCase, metaclass=VaryByProtocolTestsMetaclass): - async def asyncSetUp(self): self.ably = await TestApp.get_ably_rest() @@ -24,24 +23,30 @@ async def test_channel_status(self): channel_status = await channel.status() - assert channel_status is not None, "Expected non-None channel_status" - assert channel_name == channel_status.channel_id, "Expected channel name to match" - assert channel_status.status.is_active is True, "Expected is_active to be True" - assert isinstance(channel_status.status.occupancy.metrics.publishers, int) and\ - channel_status.status.occupancy.metrics.publishers >= 0,\ - "Expected publishers to be a non-negative int" - assert isinstance(channel_status.status.occupancy.metrics.connections, int) and\ - channel_status.status.occupancy.metrics.connections >= 0,\ - "Expected connections to be a non-negative int" - assert isinstance(channel_status.status.occupancy.metrics.subscribers, int) and\ - channel_status.status.occupancy.metrics.subscribers >= 0,\ - "Expected subscribers to be a non-negative int" - assert isinstance(channel_status.status.occupancy.metrics.presence_members, int) and\ - channel_status.status.occupancy.metrics.presence_members >= 0,\ - "Expected presence_members to be a non-negative int" - assert isinstance(channel_status.status.occupancy.metrics.presence_connections, int) and\ - channel_status.status.occupancy.metrics.presence_connections >= 0,\ - "Expected presence_connections to be a non-negative int" - assert isinstance(channel_status.status.occupancy.metrics.presence_subscribers, int) and\ - channel_status.status.occupancy.metrics.presence_subscribers >= 0,\ - "Expected presence_subscribers to be a non-negative int" + assert channel_status is not None, 'Expected non-None channel_status' + assert channel_name == channel_status.channel_id, 'Expected channel name to match' + assert channel_status.status.is_active is True, 'Expected is_active to be True' + assert ( + isinstance(channel_status.status.occupancy.metrics.publishers, int) + and channel_status.status.occupancy.metrics.publishers >= 0 + ), 'Expected publishers to be a non-negative int' + assert ( + isinstance(channel_status.status.occupancy.metrics.connections, int) + and channel_status.status.occupancy.metrics.connections >= 0 + ), 'Expected connections to be a non-negative int' + assert ( + isinstance(channel_status.status.occupancy.metrics.subscribers, int) + and channel_status.status.occupancy.metrics.subscribers >= 0 + ), 'Expected subscribers to be a non-negative int' + assert ( + isinstance(channel_status.status.occupancy.metrics.presence_members, int) + and channel_status.status.occupancy.metrics.presence_members >= 0 + ), 'Expected presence_members to be a non-negative int' + assert ( + isinstance(channel_status.status.occupancy.metrics.presence_connections, int) + and channel_status.status.occupancy.metrics.presence_connections >= 0 + ), 'Expected presence_connections to be a non-negative int' + assert ( + isinstance(channel_status.status.occupancy.metrics.presence_subscribers, int) + and channel_status.status.occupancy.metrics.presence_subscribers >= 0 + ), 'Expected presence_subscribers to be a non-negative int' diff --git a/test/ably/rest/restcrypto_test.py b/test/ably/rest/restcrypto_test.py index 18bf69ac..ef6a4723 100644 --- a/test/ably/rest/restcrypto_test.py +++ b/test/ably/rest/restcrypto_test.py @@ -18,7 +18,6 @@ class TestRestCrypto(BaseAsyncTestCase, metaclass=VaryByProtocolTestsMetaclass): - async def asyncSetUp(self): self.test_vars = await TestApp.get_test_vars() self.ably = await TestApp.get_ably_rest() @@ -36,26 +35,23 @@ def per_protocol_setup(self, use_binary_protocol): @dont_vary_protocol def test_cbc_channel_cipher(self): - key = ( - b'\x93\xe3\x5c\xc9\x77\x53\xfd\x1a' - b'\x79\xb4\xd8\x84\xe7\xdc\xfd\xdf') + key = b'\x93\xe3\x5c\xc9\x77\x53\xfd\x1a' b'\x79\xb4\xd8\x84\xe7\xdc\xfd\xdf' - iv = ( - b'\x28\x4c\xe4\x8d\x4b\xdc\x9d\x42' - b'\x8a\x77\x6b\x53\x2d\xc7\xb5\xc0') + iv = b'\x28\x4c\xe4\x8d\x4b\xdc\x9d\x42' b'\x8a\x77\x6b\x53\x2d\xc7\xb5\xc0' - log.debug("KEY_LEN: %d" % len(key)) - log.debug("IV_LEN: %d" % len(iv)) + log.debug('KEY_LEN: %d' % len(key)) + log.debug('IV_LEN: %d' % len(iv)) cipher = get_cipher({'key': key, 'iv': iv}) - plaintext = b"The quick brown fox" + plaintext = b'The quick brown fox' expected_ciphertext = ( b'\x28\x4c\xe4\x8d\x4b\xdc\x9d\x42' b'\x8a\x77\x6b\x53\x2d\xc7\xb5\xc0' b'\x83\x5c\xcf\xce\x0c\xfd\xbe\x37' b'\xb7\x92\x12\x04\x1d\x45\x68\xa4' b'\xdf\x7f\x6e\x38\x17\x4a\xff\x50' - b'\x73\x23\xbb\xca\x16\xb0\xe2\x84') + b'\x73\x23\xbb\xca\x16\xb0\xe2\x84' + ) actual_ciphertext = cipher.encrypt(plaintext) @@ -65,30 +61,34 @@ async def test_crypto_publish(self): channel_name = self.get_channel_name('persisted:crypto_publish_text') publish0 = self.ably.channels.get(channel_name, cipher={'key': generate_random_key()}) - await publish0.publish("publish3", "This is a string message payload") - await publish0.publish("publish4", b"This is a byte[] message payload") - await publish0.publish("publish5", {"test": "This is a JSONObject message payload"}) - await publish0.publish("publish6", ["This is a JSONArray message payload"]) + await publish0.publish('publish3', 'This is a string message payload') + await publish0.publish('publish4', b'This is a byte[] message payload') + await publish0.publish('publish5', {'test': 'This is a JSONObject message payload'}) + await publish0.publish('publish6', ['This is a JSONArray message payload']) history = await publish0.history() messages = history.items - assert messages is not None, "Expected non-None messages" - assert 4 == len(messages), "Expected 4 messages" + assert messages is not None, 'Expected non-None messages' + assert 4 == len(messages), 'Expected 4 messages' message_contents = dict((m.name, m.data) for m in messages) - log.debug("message_contents: %s" % str(message_contents)) + log.debug('message_contents: %s' % str(message_contents)) - assert "This is a string message payload" == message_contents["publish3"],\ - "Expect publish3 to be expected String)" + assert ( + 'This is a string message payload' == message_contents['publish3'] + ), 'Expect publish3 to be expected String)' - assert b"This is a byte[] message payload" == message_contents["publish4"],\ - "Expect publish4 to be expected byte[]. Actual: %s" % str(message_contents['publish4']) + assert ( + b'This is a byte[] message payload' == message_contents['publish4'] + ), 'Expect publish4 to be expected byte[]. Actual: %s' % str(message_contents['publish4']) - assert {"test": "This is a JSONObject message payload"} == message_contents["publish5"],\ - "Expect publish5 to be expected JSONObject" + assert {'test': 'This is a JSONObject message payload'} == message_contents[ + 'publish5' + ], 'Expect publish5 to be expected JSONObject' - assert ["This is a JSONArray message payload"] == message_contents["publish6"],\ - "Expect publish6 to be expected JSONObject" + assert ['This is a JSONArray message payload'] == message_contents[ + 'publish6' + ], 'Expect publish6 to be expected JSONObject' async def test_crypto_publish_256(self): rndfile = Random.new() @@ -98,40 +98,44 @@ async def test_crypto_publish_256(self): publish0 = self.ably.channels.get(channel_name, cipher={'key': key}) - await publish0.publish("publish3", "This is a string message payload") - await publish0.publish("publish4", b"This is a byte[] message payload") - await publish0.publish("publish5", {"test": "This is a JSONObject message payload"}) - await publish0.publish("publish6", ["This is a JSONArray message payload"]) + await publish0.publish('publish3', 'This is a string message payload') + await publish0.publish('publish4', b'This is a byte[] message payload') + await publish0.publish('publish5', {'test': 'This is a JSONObject message payload'}) + await publish0.publish('publish6', ['This is a JSONArray message payload']) history = await publish0.history() messages = history.items - assert messages is not None, "Expected non-None messages" - assert 4 == len(messages), "Expected 4 messages" + assert messages is not None, 'Expected non-None messages' + assert 4 == len(messages), 'Expected 4 messages' message_contents = dict((m.name, m.data) for m in messages) - log.debug("message_contents: %s" % str(message_contents)) + log.debug('message_contents: %s' % str(message_contents)) - assert "This is a string message payload" == message_contents["publish3"],\ - "Expect publish3 to be expected String)" + assert ( + 'This is a string message payload' == message_contents['publish3'] + ), 'Expect publish3 to be expected String)' - assert b"This is a byte[] message payload" == message_contents["publish4"],\ - "Expect publish4 to be expected byte[]. Actual: %s" % str(message_contents['publish4']) + assert ( + b'This is a byte[] message payload' == message_contents['publish4'] + ), 'Expect publish4 to be expected byte[]. Actual: %s' % str(message_contents['publish4']) - assert {"test": "This is a JSONObject message payload"} == message_contents["publish5"],\ - "Expect publish5 to be expected JSONObject" + assert {'test': 'This is a JSONObject message payload'} == message_contents[ + 'publish5' + ], 'Expect publish5 to be expected JSONObject' - assert ["This is a JSONArray message payload"] == message_contents["publish6"],\ - "Expect publish6 to be expected JSONObject" + assert ['This is a JSONArray message payload'] == message_contents[ + 'publish6' + ], 'Expect publish6 to be expected JSONObject' async def test_crypto_publish_key_mismatch(self): channel_name = self.get_channel_name('persisted:crypto_publish_key_mismatch') publish0 = self.ably.channels.get(channel_name, cipher={'key': generate_random_key()}) - await publish0.publish("publish3", "This is a string message payload") - await publish0.publish("publish4", b"This is a byte[] message payload") - await publish0.publish("publish5", {"test": "This is a JSONObject message payload"}) - await publish0.publish("publish6", ["This is a JSONArray message payload"]) + await publish0.publish('publish3', 'This is a string message payload') + await publish0.publish('publish4', b'This is a byte[] message payload') + await publish0.publish('publish5', {'test': 'This is a JSONObject message payload'}) + await publish0.publish('publish6', ['This is a JSONArray message payload']) rx_channel = self.ably2.channels.get(channel_name, cipher={'key': generate_random_key()}) @@ -145,32 +149,36 @@ async def test_crypto_send_unencrypted(self): channel_name = self.get_channel_name('persisted:crypto_send_unencrypted') publish0 = self.ably.channels[channel_name] - await publish0.publish("publish3", "This is a string message payload") - await publish0.publish("publish4", b"This is a byte[] message payload") - await publish0.publish("publish5", {"test": "This is a JSONObject message payload"}) - await publish0.publish("publish6", ["This is a JSONArray message payload"]) + await publish0.publish('publish3', 'This is a string message payload') + await publish0.publish('publish4', b'This is a byte[] message payload') + await publish0.publish('publish5', {'test': 'This is a JSONObject message payload'}) + await publish0.publish('publish6', ['This is a JSONArray message payload']) rx_channel = self.ably2.channels.get(channel_name, cipher={'key': generate_random_key()}) history = await rx_channel.history() messages = history.items - assert messages is not None, "Expected non-None messages" - assert 4 == len(messages), "Expected 4 messages" + assert messages is not None, 'Expected non-None messages' + assert 4 == len(messages), 'Expected 4 messages' message_contents = dict((m.name, m.data) for m in messages) - log.debug("message_contents: %s" % str(message_contents)) + log.debug('message_contents: %s' % str(message_contents)) - assert "This is a string message payload" == message_contents["publish3"],\ - "Expect publish3 to be expected String" + assert ( + 'This is a string message payload' == message_contents['publish3'] + ), 'Expect publish3 to be expected String' - assert b"This is a byte[] message payload" == message_contents["publish4"],\ - "Expect publish4 to be expected byte[]. Actual: %s" % str(message_contents['publish4']) + assert ( + b'This is a byte[] message payload' == message_contents['publish4'] + ), 'Expect publish4 to be expected byte[]. Actual: %s' % str(message_contents['publish4']) - assert {"test": "This is a JSONObject message payload"} == message_contents["publish5"],\ - "Expect publish5 to be expected JSONObject" + assert {'test': 'This is a JSONObject message payload'} == message_contents[ + 'publish5' + ], 'Expect publish5 to be expected JSONObject' - assert ["This is a JSONArray message payload"] == message_contents["publish6"],\ - "Expect publish6 to be expected JSONObject" + assert ['This is a JSONArray message payload'] == message_contents[ + 'publish6' + ], 'Expect publish6 to be expected JSONObject' async def test_crypto_encrypted_unhandled(self): channel_name = self.get_channel_name('persisted:crypto_send_encrypted_unhandled') @@ -178,7 +186,7 @@ async def test_crypto_encrypted_unhandled(self): data = 'foobar' publish0 = self.ably.channels.get(channel_name, cipher={'key': key}) - await publish0.publish("publish0", data) + await publish0.publish('publish0', data) rx_channel = self.ably2.channels[channel_name] history = await rx_channel.history() @@ -201,7 +209,6 @@ def test_cipher_params(self): class AbstractTestCryptoWithFixture: - @classmethod def setUpClass(cls): resources_path = os.path.dirname(__file__) + '/../../../submodules/test-resources/%s' % cls.fixture_file diff --git a/test/ably/rest/resthttp_test.py b/test/ably/rest/resthttp_test.py index a7f83783..187e4686 100644 --- a/test/ably/rest/resthttp_test.py +++ b/test/ably/rest/resthttp_test.py @@ -20,7 +20,7 @@ class TestRestHttp(BaseAsyncTestCase): async def test_max_retry_attempts_and_timeouts_defaults(self): - ably = AblyRest(token="foo") + ably = AblyRest(token='foo') assert 'http_open_timeout' in ably.http.CONNECTION_RETRY_DEFAULTS assert 'http_request_timeout' in ably.http.CONNECTION_RETRY_DEFAULTS @@ -33,7 +33,7 @@ async def test_max_retry_attempts_and_timeouts_defaults(self): await ably.close() async def test_cumulative_timeout(self): - ably = AblyRest(token="foo") + ably = AblyRest(token='foo') assert 'http_max_retry_duration' in ably.http.CONNECTION_RETRY_DEFAULTS ably.options.http_max_retry_duration = 0.5 @@ -50,12 +50,10 @@ def sleep_and_raise(*args, **kwargs): await ably.close() async def test_host_fallback(self): - ably = AblyRest(token="foo") + ably = AblyRest(token='foo') def make_url(host): - base_url = "%s://%s:%d" % (ably.http.preferred_scheme, - host, - ably.http.preferred_port) + base_url = '%s://%s:%d' % (ably.http.preferred_scheme, host, ably.http.preferred_port) return urljoin(base_url, '/') with mock.patch('httpx.Request', wraps=httpx.Request) as request_mock: @@ -65,10 +63,7 @@ def make_url(host): assert send_mock.call_count == Defaults.http_max_retry_count - expected_urls_set = { - make_url(host) - for host in Options(http_max_retry_count=10).get_rest_hosts() - } + expected_urls_set = {make_url(host) for host in Options(http_max_retry_count=10).get_rest_hosts()} for ((_, url), _) in request_mock.call_args_list: assert url in expected_urls_set expected_urls_set.remove(url) @@ -82,9 +77,9 @@ def make_url(host): @respx.mock async def test_no_host_fallback_nor_retries_if_custom_host(self): custom_host = 'example.org' - ably = AblyRest(token="foo", rest_host=custom_host) + ably = AblyRest(token='foo', rest_host=custom_host) - mock_route = respx.get("https://example.org").mock(side_effect=httpx.RequestError('')) + mock_route = respx.get('https://example.org').mock(side_effect=httpx.RequestError('')) with pytest.raises(httpx.RequestError): await ably.http.make_request('GET', '/', skip_auth=True) @@ -132,14 +127,11 @@ async def side_effect(*args, **kwargs): @respx.mock async def test_no_retry_if_not_500_to_599_http_code(self): default_host = Options().get_rest_host() - ably = AblyRest(token="foo") + ably = AblyRest(token='foo') - default_url = "%s://%s:%d/" % ( - ably.http.preferred_scheme, - default_host, - ably.http.preferred_port) + default_url = '%s://%s:%d/' % (ably.http.preferred_scheme, default_host, ably.http.preferred_port) - mock_response = httpx.Response(600, json={'message': "", 'status_code': 600, 'code': 50500}) + mock_response = httpx.Response(600, json={'message': '', 'status_code': 600, 'code': 50500}) mock_route = respx.get(default_url).mock(return_value=mock_response) @@ -157,14 +149,15 @@ async def test_500_errors(self): https://github.com/ably/ably-python/issues/160 """ - ably = AblyRest(token="foo") + ably = AblyRest(token='foo') def raise_ably_exception(*args, **kwargs): - raise AblyException(message="", status_code=500, code=50000) + raise AblyException(message='', status_code=500, code=50000) with mock.patch('httpx.Request', wraps=httpx.Request): - with mock.patch('ably.util.exceptions.AblyException.raise_for_response', - side_effect=raise_ably_exception) as send_mock: + with mock.patch( + 'ably.util.exceptions.AblyException.raise_for_response', side_effect=raise_ably_exception + ) as send_mock: with pytest.raises(AblyException): await ably.http.make_request('GET', '/', skip_auth=True) @@ -173,8 +166,12 @@ def raise_ably_exception(*args, **kwargs): def test_custom_http_timeouts(self): ably = AblyRest( - token="foo", http_request_timeout=30, http_open_timeout=8, - http_max_retry_count=6, http_max_retry_duration=20) + token='foo', + http_request_timeout=30, + http_open_timeout=8, + http_max_retry_count=6, + http_max_retry_duration=20, + ) assert ably.http.http_request_timeout == 30 assert ably.http.http_open_timeout == 8 @@ -192,7 +189,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-python\/\d.\d.\d(-beta\.\d)? python\/\d.\d+.\d+$' assert re.search(expr, r.request.headers['Ably-Agent']) await ably.close() diff --git a/test/ably/rest/restinit_test.py b/test/ably/rest/restinit_test.py index 10dd8282..c066c01f 100644 --- a/test/ably/rest/restinit_test.py +++ b/test/ably/rest/restinit_test.py @@ -12,23 +12,22 @@ class TestRestInit(BaseAsyncTestCase, metaclass=VaryByProtocolTestsMetaclass): - async def asyncSetUp(self): self.test_vars = await TestApp.get_test_vars() @dont_vary_protocol def test_key_only(self): - ably = AblyRest(key=self.test_vars["keys"][0]["key_str"]) - assert ably.options.key_name == self.test_vars["keys"][0]["key_name"], "Key name does not match" - assert ably.options.key_secret == self.test_vars["keys"][0]["key_secret"], "Key secret does not match" + ably = AblyRest(key=self.test_vars['keys'][0]['key_str']) + assert ably.options.key_name == self.test_vars['keys'][0]['key_name'], 'Key name does not match' + assert ably.options.key_secret == self.test_vars['keys'][0]['key_secret'], 'Key secret does not match' def per_protocol_setup(self, use_binary_protocol): self.use_binary_protocol = use_binary_protocol @dont_vary_protocol def test_with_token(self): - ably = AblyRest(token="foo") - assert ably.options.auth_token == "foo", "Token not set at options" + ably = AblyRest(token='foo') + assert ably.options.auth_token == 'foo', 'Token not set at options' @dont_vary_protocol def test_with_token_details(self): @@ -39,28 +38,29 @@ def test_with_token_details(self): @dont_vary_protocol def test_with_options_token_callback(self): def token_callback(**params): - return "this_is_not_really_a_token_request" + return 'this_is_not_really_a_token_request' + AblyRest(auth_callback=token_callback) @dont_vary_protocol def test_ambiguous_key_raises_value_error(self): - with pytest.raises(ValueError, match="mutually exclusive"): - AblyRest(key=self.test_vars["keys"][0]["key_str"], key_name='x') - with pytest.raises(ValueError, match="mutually exclusive"): - AblyRest(key=self.test_vars["keys"][0]["key_str"], key_secret='x') + with pytest.raises(ValueError, match='mutually exclusive'): + AblyRest(key=self.test_vars['keys'][0]['key_str'], key_name='x') + with pytest.raises(ValueError, match='mutually exclusive'): + AblyRest(key=self.test_vars['keys'][0]['key_str'], key_secret='x') @dont_vary_protocol def test_with_key_name_or_secret_only(self): - with pytest.raises(ValueError, match="key is missing"): + with pytest.raises(ValueError, match='key is missing'): AblyRest(key_name='x') - with pytest.raises(ValueError, match="key is missing"): + with pytest.raises(ValueError, match='key is missing'): AblyRest(key_secret='x') @dont_vary_protocol def test_with_key_name_and_secret(self): - ably = AblyRest(key_name="foo", key_secret="bar") - assert ably.options.key_name == "foo", "Key name does not match" - assert ably.options.key_secret == "bar", "Key secret does not match" + ably = AblyRest(key_name='foo', key_secret='bar') + assert ably.options.key_name == 'foo', 'Key name does not match' + assert ably.options.key_secret == 'bar', 'Key secret does not match' @dont_vary_protocol def test_with_options_auth_url(self): @@ -70,23 +70,22 @@ def test_with_options_auth_url(self): @dont_vary_protocol def test_rest_host_and_environment(self): # rest host - ably = AblyRest(token='foo', rest_host="some.other.host") - assert "some.other.host" == ably.options.rest_host, "Unexpected host mismatch" + ably = AblyRest(token='foo', rest_host='some.other.host') + assert 'some.other.host' == ably.options.rest_host, 'Unexpected host mismatch' # environment: production - ably = AblyRest(token='foo', environment="production") + ably = AblyRest(token='foo', environment='production') host = ably.options.get_rest_host() - assert "rest.ably.io" == host, "Unexpected host mismatch %s" % host + assert 'rest.ably.io' == host, 'Unexpected host mismatch %s' % host # environment: other - ably = AblyRest(token='foo', environment="sandbox") + ably = AblyRest(token='foo', environment='sandbox') host = ably.options.get_rest_host() - assert "sandbox-rest.ably.io" == host, "Unexpected host mismatch %s" % host + assert 'sandbox-rest.ably.io' == host, 'Unexpected host mismatch %s' % host # both, as per #TO3k2 with pytest.raises(ValueError): - ably = AblyRest(token='foo', rest_host="some.other.host", - environment="some.other.environment") + ably = AblyRest(token='foo', rest_host='some.other.host', environment='some.other.environment') # RSC15 @dont_vary_protocol @@ -105,7 +104,8 @@ def test_fallback_hosts(self): # Specify environment (RSC15g2) ably = AblyRest(token='foo', environment='sandbox', http_max_retry_count=10) assert sorted(Defaults.get_environment_fallback_hosts('sandbox')) == sorted( - ably.options.get_fallback_rest_hosts()) + ably.options.get_fallback_rest_hosts() + ) # Fallback hosts and environment not specified (RSC15g3) ably = AblyRest(token='foo', http_max_retry_count=10) @@ -119,38 +119,41 @@ def test_fallback_hosts(self): @dont_vary_protocol def test_specified_realtime_host(self): - ably = AblyRest(token='foo', realtime_host="some.other.host") - assert "some.other.host" == ably.options.realtime_host, "Unexpected host mismatch" + ably = AblyRest(token='foo', realtime_host='some.other.host') + assert 'some.other.host' == ably.options.realtime_host, 'Unexpected host mismatch' @dont_vary_protocol def test_specified_port(self): ably = AblyRest(token='foo', port=9998, tls_port=9999) - assert 9999 == Defaults.get_port(ably.options),\ - "Unexpected port mismatch. Expected: 9999. Actual: %d" % ably.options.tls_port + assert 9999 == Defaults.get_port(ably.options), ( + 'Unexpected port mismatch. Expected: 9999. Actual: %d' % ably.options.tls_port + ) @dont_vary_protocol def test_specified_non_tls_port(self): ably = AblyRest(token='foo', port=9998, tls=False) - assert 9998 == Defaults.get_port(ably.options),\ - "Unexpected port mismatch. Expected: 9999. Actual: %d" % ably.options.tls_port + assert 9998 == Defaults.get_port(ably.options), ( + 'Unexpected port mismatch. Expected: 9999. Actual: %d' % ably.options.tls_port + ) @dont_vary_protocol def test_specified_tls_port(self): ably = AblyRest(token='foo', tls_port=9999, tls=True) - assert 9999 == Defaults.get_port(ably.options),\ - "Unexpected port mismatch. Expected: 9999. Actual: %d" % ably.options.tls_port + assert 9999 == Defaults.get_port(ably.options), ( + 'Unexpected port mismatch. Expected: 9999. Actual: %d' % ably.options.tls_port + ) @dont_vary_protocol def test_tls_defaults_to_true(self): ably = AblyRest(token='foo') - assert ably.options.tls, "Expected encryption to default to true" - assert Defaults.tls_port == Defaults.get_port(ably.options), "Unexpected port mismatch" + assert ably.options.tls, 'Expected encryption to default to true' + assert Defaults.tls_port == Defaults.get_port(ably.options), 'Unexpected port mismatch' @dont_vary_protocol def test_tls_can_be_disabled(self): ably = AblyRest(token='foo', tls=False) - assert not ably.options.tls, "Expected encryption to be False" - assert Defaults.port == Defaults.get_port(ably.options), "Unexpected port mismatch" + assert not ably.options.tls, 'Expected encryption to be False' + assert Defaults.port == Defaults.get_port(ably.options), 'Unexpected port mismatch' @dont_vary_protocol def test_with_no_params(self): @@ -164,12 +167,12 @@ def test_with_no_auth_params(self): # RSA10k async def test_query_time_param(self): - ably = await TestApp.get_ably_rest(query_time=True, - use_binary_protocol=self.use_binary_protocol) + ably = await TestApp.get_ably_rest(query_time=True, 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.rest.rest.AblyRest.time', wraps=ably.time) as server_time, patch( + 'ably.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 @@ -218,8 +221,12 @@ async def test_environment(self): @dont_vary_protocol def test_accepts_custom_http_timeouts(self): ably = AblyRest( - token="foo", http_request_timeout=30, http_open_timeout=8, - http_max_retry_count=6, http_max_retry_duration=20) + token='foo', + http_request_timeout=30, + http_open_timeout=8, + http_max_retry_count=6, + http_max_retry_duration=20, + ) assert ably.options.http_request_timeout == 30 assert ably.options.http_open_timeout == 8 diff --git a/test/ably/rest/restpaginatedresult_test.py b/test/ably/rest/restpaginatedresult_test.py index 1ad693bf..89b96a37 100644 --- a/test/ably/rest/restpaginatedresult_test.py +++ b/test/ably/rest/restpaginatedresult_test.py @@ -8,22 +8,13 @@ class TestPaginatedResult(BaseAsyncTestCase): - def get_response_callback(self, headers, body, status): def callback(request): res = request.url.params.get('page') if res: - return Response( - status_code=status, - headers=headers, - content='[{"page": %i}]' % int(res) - ) + return Response(status_code=status, headers=headers, content='[{"page": %i}]' % int(res)) - return Response( - status_code=status, - headers=headers, - content=body - ) + return Response(status_code=status, headers=headers, content=body) return callback @@ -43,12 +34,11 @@ async def asyncSetUp(self): self.ch2_route.side_effect = self.get_response_callback( headers={ 'content-type': 'application/json', - 'link': - '; rel="first",' - ' ; rel="next"' + 'link': '; rel="first",' + ' ; rel="next"', }, body='[{"id": 0}, {"id": 1}]', - status=200 + status=200, ) # start intercepting requests self.mocked_api.start() @@ -56,11 +46,13 @@ async def asyncSetUp(self): self.paginated_result = await PaginatedResult.paginated_query( self.ably.http, url='http://rest.ably.io/channels/channel_name/ch1', - response_processor=lambda response: response.to_native()) + response_processor=lambda response: response.to_native(), + ) self.paginated_result_with_headers = await PaginatedResult.paginated_query( self.ably.http, url='http://rest.ably.io/channels/channel_name/ch2', - response_processor=lambda response: response.to_native()) + response_processor=lambda response: response.to_native(), + ) async def asyncTearDown(self): self.mocked_api.stop() diff --git a/test/ably/rest/restpresence_test.py b/test/ably/rest/restpresence_test.py index 2c525b02..e67d12f4 100644 --- a/test/ably/rest/restpresence_test.py +++ b/test/ably/rest/restpresence_test.py @@ -11,7 +11,6 @@ class TestPresence(BaseAsyncTestCase, metaclass=VaryByProtocolTestsMetaclass): - async def asyncSetUp(self): self.test_vars = await TestApp.get_test_vars() self.ably = await TestApp.get_ably_rest() @@ -54,12 +53,12 @@ async def test_channel_presence_history(self): async def test_presence_get_encoded(self): presence_history = await self.channel.presence.history() - assert presence_history.items[-1].data == "true" - assert presence_history.items[-2].data == "24" - assert presence_history.items[-3].data == "This is a string clientData payload" + assert presence_history.items[-1].data == 'true' + assert presence_history.items[-2].data == '24' + assert presence_history.items[-3].data == 'This is a string clientData payload' # this one doesn't have encoding field assert presence_history.items[-4].data == '{ "test": "This is a JSONObject clientData payload"}' - assert presence_history.items[-5].data == {"example": {"json": "Object"}} + assert presence_history.items[-5].data == {'example': {'json': 'Object'}} async def test_timestamp_is_datetime(self): presence_page = await self.channel.presence.get() @@ -70,13 +69,10 @@ async def test_presence_message_has_correct_member_key(self): presence_page = await self.channel.presence.get() member = presence_page.items[0] - assert member.member_key == "%s:%s" % (member.connection_id, member.client_id) + assert member.member_key == '%s:%s' % (member.connection_id, member.client_id) def presence_mock_url(self): - kwargs = { - 'scheme': 'https' if self.test_vars['tls'] else 'http', - 'host': self.test_vars['host'] - } + kwargs = {'scheme': 'https' if self.test_vars['tls'] else 'http', 'host': self.test_vars['host']} port = self.test_vars['tls_port'] if self.test_vars.get('tls') else kwargs['port'] if port == 80: kwargs['port_sufix'] = '' @@ -86,10 +82,7 @@ def presence_mock_url(self): return url.format(**kwargs) def history_mock_url(self): - kwargs = { - 'scheme': 'https' if self.test_vars['tls'] else 'http', - 'host': self.test_vars['host'] - } + kwargs = {'scheme': 'https' if self.test_vars['tls'] else 'http', 'host': self.test_vars['host']} port = self.test_vars['tls_port'] if self.test_vars.get('tls') else kwargs['port'] if port == 80: kwargs['port_sufix'] = '' @@ -188,7 +181,6 @@ async def test_with_start_gt_end(self): class TestPresenceCrypt(BaseAsyncTestCase, metaclass=VaryByProtocolTestsMetaclass): - async def asyncSetUp(self): self.ably = await TestApp.get_ably_rest() key = b'0123456789abcdef' diff --git a/test/ably/rest/restpush_test.py b/test/ably/rest/restpush_test.py index f4a6a81a..87cf6be6 100644 --- a/test/ably/rest/restpush_test.py +++ b/test/ably/rest/restpush_test.py @@ -18,7 +18,6 @@ class TestPush(BaseAsyncTestCase, metaclass=VaryByProtocolTestsMetaclass): - async def asyncSetUp(self): self.ably = await TestApp.get_ably_rest() diff --git a/test/ably/rest/restrequest_test.py b/test/ably/rest/restrequest_test.py index d0c9ad9d..d03f725a 100644 --- a/test/ably/rest/restrequest_test.py +++ b/test/ably/rest/restrequest_test.py @@ -12,7 +12,6 @@ # RSC19 class TestRestRequest(BaseAsyncTestCase, metaclass=VaryByProtocolTestsMetaclass): - async def asyncSetUp(self): self.ably = await TestApp.get_ably_rest() self.test_vars = await TestApp.get_test_vars() @@ -61,18 +60,18 @@ async def test_get(self): assert item['name'] == 'event0' assert item['data'] == 'lorem ipsum 0' - assert result.status_code == 200 # HP4 - assert result.success is True # HP5 - assert result.error_code is None # HP6 + assert result.status_code == 200 # HP4 + assert result.success is True # HP5 + assert result.error_code is None # HP6 assert result.error_message is None # HP7 - assert isinstance(result.headers, list) # HP7 + assert isinstance(result.headers, list) # HP7 @dont_vary_protocol async def test_not_found(self): result = await self.ably.request('GET', '/not-found', version=Defaults.protocol_version) assert isinstance(result, HttpPaginatedResponse) # RSC19d - assert result.status_code == 404 # HP4 - assert result.success is False # HP5 + assert result.status_code == 404 # HP4 + assert result.success is False # HP5 @dont_vary_protocol async def test_error(self): @@ -95,7 +94,7 @@ async def test_headers(self): async def test_timeout(self): # Timeout timeout = 0.000001 - ably = AblyRest(token="foo", http_request_timeout=timeout) + ably = AblyRest(token='foo', http_request_timeout=timeout) assert ably.http.http_request_timeout == timeout with pytest.raises(httpx.ReadTimeout): await ably.request('GET', '/time', version=Defaults.protocol_version) @@ -108,25 +107,25 @@ async def test_timeout(self): with respx.mock: default_route = respx.get(default_endpoint) fallback_route = respx.get(fallback_endpoint) - headers = { - "Content-Type": "application/json" - } + headers = {'Content-Type': 'application/json'} default_route.side_effect = httpx.ConnectError('') fallback_route.return_value = httpx.Response(200, headers=headers, text='[123]') await ably.request('GET', '/time', version=Defaults.protocol_version) await ably.close() # Bad host, no Fallback - ably = AblyRest(key=self.test_vars["keys"][0]["key_str"], - rest_host='some.other.host', - port=self.test_vars["port"], - tls_port=self.test_vars["tls_port"], - tls=self.test_vars["tls"]) + ably = AblyRest( + key=self.test_vars['keys'][0]['key_str'], + rest_host='some.other.host', + port=self.test_vars['port'], + tls_port=self.test_vars['tls_port'], + tls=self.test_vars['tls'], + ) with pytest.raises(httpx.ConnectError): await ably.request('GET', '/time', version=Defaults.protocol_version) await ably.close() async def test_version(self): - version = "150" # chosen arbitrarily - result = await self.ably.request('GET', '/time', "150") - assert result.response.request.headers["X-Ably-Version"] == version + version = '150' # chosen arbitrarily + result = await self.ably.request('GET', '/time', '150') + assert result.response.request.headers['X-Ably-Version'] == version diff --git a/test/ably/rest/reststats_test.py b/test/ably/rest/reststats_test.py index ca0547b8..e8fa49f7 100644 --- a/test/ably/rest/reststats_test.py +++ b/test/ably/rest/reststats_test.py @@ -18,12 +18,7 @@ class TestRestAppStatsSetup: __stats_added = False def get_params(self): - return { - 'start': self.last_interval, - 'end': self.last_interval, - 'unit': 'minute', - 'limit': 1 - } + return {'start': self.last_interval, 'end': self.last_interval, 'unit': 'minute', 'limit': 1} async def asyncSetUp(self): self.ably = await TestApp.get_ably_rest() @@ -36,16 +31,14 @@ async def asyncSetUp(self): previous_year_stats = 120 stats = [ { - 'intervalId': Stats.to_interval_id(self.last_interval - timedelta(minutes=2), - 'minute'), + 'intervalId': Stats.to_interval_id(self.last_interval - timedelta(minutes=2), 'minute'), 'inbound': {'realtime': {'messages': {'count': 50, 'data': 5000}}}, - 'outbound': {'realtime': {'messages': {'count': 20, 'data': 2000}}} + 'outbound': {'realtime': {'messages': {'count': 20, 'data': 2000}}}, }, { - 'intervalId': Stats.to_interval_id(self.last_interval - timedelta(minutes=1), - 'minute'), + 'intervalId': Stats.to_interval_id(self.last_interval - timedelta(minutes=1), 'minute'), 'inbound': {'realtime': {'messages': {'count': 60, 'data': 6000}}}, - 'outbound': {'realtime': {'messages': {'count': 10, 'data': 1000}}} + 'outbound': {'realtime': {'messages': {'count': 10, 'data': 1000}}}, }, { 'intervalId': Stats.to_interval_id(self.last_interval, 'minute'), @@ -56,16 +49,15 @@ async def asyncSetUp(self): 'channels': {'peak': 50, 'opened': 30}, 'apiRequests': {'succeeded': 50, 'failed': 10}, 'tokenRequests': {'succeeded': 60, 'failed': 20}, - } + }, ] previous_stats = [] for i in range(previous_year_stats): previous_stats.append( { - 'intervalId': Stats.to_interval_id(self.previous_interval - timedelta(minutes=i), - 'minute'), - 'inbound': {'realtime': {'messages': {'count': i}}} + 'intervalId': Stats.to_interval_id(self.previous_interval - timedelta(minutes=i), 'minute'), + 'inbound': {'realtime': {'messages': {'count': i}}}, } ) # asynctest does not support setUpClass method @@ -82,48 +74,39 @@ def per_protocol_setup(self, use_binary_protocol): self.ably.options.use_binary_protocol = use_binary_protocol -class TestDirectionForwards(TestRestAppStatsSetup, BaseAsyncTestCase, - metaclass=VaryByProtocolTestsMetaclass): - +class TestDirectionForwards(TestRestAppStatsSetup, BaseAsyncTestCase, metaclass=VaryByProtocolTestsMetaclass): def get_params(self): return { 'start': self.last_interval - timedelta(minutes=2), 'end': self.last_interval, 'unit': 'minute', 'direction': 'forwards', - 'limit': 1 + 'limit': 1, } async def test_stats_are_forward(self): stats_pages = await self.ably.stats(**self.get_params()) stats = stats_pages.items stat = stats[0] - assert stat.entries["messages.inbound.realtime.all.count"] == 50 + assert stat.entries['messages.inbound.realtime.all.count'] == 50 async def test_three_pages(self): stats_pages = await self.ably.stats(**self.get_params()) assert not stats_pages.is_last() page2 = await stats_pages.next() page3 = await page2.next() - assert page3.items[0].entries["messages.inbound.realtime.all.count"] == 70 - + assert page3.items[0].entries['messages.inbound.realtime.all.count'] == 70 -class TestDirectionBackwards(TestRestAppStatsSetup, BaseAsyncTestCase, - metaclass=VaryByProtocolTestsMetaclass): +class TestDirectionBackwards(TestRestAppStatsSetup, BaseAsyncTestCase, metaclass=VaryByProtocolTestsMetaclass): def get_params(self): - return { - 'end': self.last_interval, - 'unit': 'minute', - 'direction': 'backwards', - 'limit': 1 - } + return {'end': self.last_interval, 'unit': 'minute', 'direction': 'backwards', 'limit': 1} async def test_stats_are_forward(self): stats_pages = await self.ably.stats(**self.get_params()) stats = stats_pages.items stat = stats[0] - assert stat.entries["messages.inbound.realtime.all.count"] == 70 + assert stat.entries['messages.inbound.realtime.all.count'] == 70 async def test_three_pages(self): stats_pages = await self.ably.stats(**self.get_params()) @@ -131,29 +114,21 @@ async def test_three_pages(self): page2 = await stats_pages.next() page3 = await page2.next() assert not stats_pages.is_last() - assert page3.items[0].entries["messages.inbound.realtime.all.count"] == 50 - + assert page3.items[0].entries['messages.inbound.realtime.all.count'] == 50 -class TestOnlyLastYear(TestRestAppStatsSetup, BaseAsyncTestCase, - metaclass=VaryByProtocolTestsMetaclass): +class TestOnlyLastYear(TestRestAppStatsSetup, BaseAsyncTestCase, metaclass=VaryByProtocolTestsMetaclass): def get_params(self): - return { - 'end': self.last_interval, - 'unit': 'minute', - 'limit': 3 - } + return {'end': self.last_interval, 'unit': 'minute', 'limit': 3} async def test_default_is_backwards(self): stats_pages = await self.ably.stats(**self.get_params()) stats = stats_pages.items - assert stats[0].entries["messages.inbound.realtime.messages.count"] == 70 - assert stats[-1].entries["messages.inbound.realtime.messages.count"] == 50 + assert stats[0].entries['messages.inbound.realtime.messages.count'] == 70 + assert stats[-1].entries['messages.inbound.realtime.messages.count'] == 50 -class TestPreviousYear(TestRestAppStatsSetup, BaseAsyncTestCase, - metaclass=VaryByProtocolTestsMetaclass): - +class TestPreviousYear(TestRestAppStatsSetup, BaseAsyncTestCase, metaclass=VaryByProtocolTestsMetaclass): def get_params(self): return { 'end': self.previous_interval, @@ -168,9 +143,7 @@ async def test_default_100_pagination(self): assert len(next_page.items) == 20 -class TestRestAppStats(TestRestAppStatsSetup, BaseAsyncTestCase, - metaclass=VaryByProtocolTestsMetaclass): - +class TestRestAppStats(TestRestAppStatsSetup, BaseAsyncTestCase, metaclass=VaryByProtocolTestsMetaclass): @dont_vary_protocol async def test_protocols(self): stats_pages = await self.ably.stats(**self.get_params()) @@ -189,13 +162,13 @@ async def test_units(self): 'end': self.last_interval, 'unit': unit, 'direction': 'forwards', - 'limit': 1 + 'limit': 1, } stats_pages = await self.ably.stats(**params) stat = stats_pages.items[0] assert len(stats_pages.items) == 1 - assert stat.entries["messages.all.messages.count"] == 50 + 20 + 60 + 10 + 70 + 40 - assert stat.entries["messages.all.messages.data"] == 5000 + 2000 + 6000 + 1000 + 7000 + 4000 + assert stat.entries['messages.all.messages.count'] == 50 + 20 + 60 + 10 + 70 + 40 + assert stat.entries['messages.all.messages.data'] == 5000 + 2000 + 6000 + 1000 + 7000 + 4000 @dont_vary_protocol async def test_when_argument_start_is_after_end(self): @@ -209,11 +182,8 @@ async def test_when_argument_start_is_after_end(self): @dont_vary_protocol async def test_when_limit_gt_1000(self): - params = { - 'end': self.last_interval, - 'limit': 5000 - } - with pytest.raises(AblyException, match="The maximum allowed limit is 1000"): + params = {'end': self.last_interval, 'limit': 5000} + with pytest.raises(AblyException, match='The maximum allowed limit is 1000'): await self.ably.stats(**params) async def test_no_arguments(self): @@ -226,79 +196,79 @@ async def test_no_arguments(self): async def test_got_1_record(self): stats_pages = await self.ably.stats(**self.get_params()) - assert 1 == len(stats_pages.items), "Expected 1 record" + assert 1 == len(stats_pages.items), 'Expected 1 record' async def test_return_aggregated_message_data(self): # returns aggregated message data stats_pages = await self.ably.stats(**self.get_params()) stats = stats_pages.items stat = stats[0] - assert stat.entries["messages.all.messages.count"] == 70 + 40 - assert stat.entries["messages.all.messages.data"] == 7000 + 4000 + assert stat.entries['messages.all.messages.count'] == 70 + 40 + assert stat.entries['messages.all.messages.data'] == 7000 + 4000 async def test_inbound_realtime_all_data(self): # returns inbound realtime all data stats_pages = await self.ably.stats(**self.get_params()) stats = stats_pages.items stat = stats[0] - assert stat.entries["messages.inbound.realtime.all.count"] == 70 - assert stat.entries["messages.inbound.realtime.all.data"] == 7000 + assert stat.entries['messages.inbound.realtime.all.count'] == 70 + assert stat.entries['messages.inbound.realtime.all.data'] == 7000 async def test_inboud_realtime_message_data(self): # returns inbound realtime message data stats_pages = await self.ably.stats(**self.get_params()) stats = stats_pages.items stat = stats[0] - assert stat.entries["messages.inbound.realtime.messages.count"] == 70 - assert stat.entries["messages.inbound.realtime.messages.data"] == 7000 + assert stat.entries['messages.inbound.realtime.messages.count'] == 70 + assert stat.entries['messages.inbound.realtime.messages.data'] == 7000 async def test_outbound_realtime_all_data(self): # returns outboud realtime all data stats_pages = await self.ably.stats(**self.get_params()) stats = stats_pages.items stat = stats[0] - assert stat.entries["messages.outbound.realtime.all.count"] == 40 - assert stat.entries["messages.outbound.realtime.all.data"] == 4000 + assert stat.entries['messages.outbound.realtime.all.count'] == 40 + assert stat.entries['messages.outbound.realtime.all.data'] == 4000 async def test_persisted_data(self): # returns persisted presence all data stats_pages = await self.ably.stats(**self.get_params()) stats = stats_pages.items stat = stats[0] - assert stat.entries["messages.persisted.all.count"] == 20 - assert stat.entries["messages.persisted.all.data"] == 2000 + assert stat.entries['messages.persisted.all.count'] == 20 + assert stat.entries['messages.persisted.all.data'] == 2000 async def test_connections_data(self): # returns connections all data stats_pages = await self.ably.stats(**self.get_params()) stats = stats_pages.items stat = stats[0] - assert stat.entries["connections.all.peak"] == 20 - assert stat.entries["connections.all.opened"] == 10 + assert stat.entries['connections.all.peak'] == 20 + assert stat.entries['connections.all.opened'] == 10 async def test_channels_all_data(self): # returns channels all data stats_pages = await self.ably.stats(**self.get_params()) stats = stats_pages.items stat = stats[0] - assert stat.entries["channels.peak"] == 50 - assert stat.entries["channels.opened"] == 30 + assert stat.entries['channels.peak'] == 50 + assert stat.entries['channels.opened'] == 30 async def test_api_requests_data(self): # returns api_requests data stats_pages = await self.ably.stats(**self.get_params()) stats = stats_pages.items stat = stats[0] - assert stat.entries["apiRequests.other.succeeded"] == 50 - assert stat.entries["apiRequests.other.failed"] == 10 + assert stat.entries['apiRequests.other.succeeded'] == 50 + assert stat.entries['apiRequests.other.failed'] == 10 async def test_token_requests(self): # returns token_requests data stats_pages = await self.ably.stats(**self.get_params()) stats = stats_pages.items stat = stats[0] - assert stat.entries["apiRequests.tokenRequests.succeeded"] == 60 - assert stat.entries["apiRequests.tokenRequests.failed"] == 20 + assert stat.entries['apiRequests.tokenRequests.succeeded'] == 60 + assert stat.entries['apiRequests.tokenRequests.failed'] == 20 async def test_interval(self): # interval diff --git a/test/ably/rest/resttime_test.py b/test/ably/rest/resttime_test.py index 6189ebd0..8838fc70 100644 --- a/test/ably/rest/resttime_test.py +++ b/test/ably/rest/resttime_test.py @@ -9,7 +9,6 @@ class TestRestTime(BaseAsyncTestCase, metaclass=VaryByProtocolTestsMetaclass): - def per_protocol_setup(self, use_binary_protocol): self.ably.options.use_binary_protocol = use_binary_protocol self.use_binary_protocol = use_binary_protocol @@ -25,18 +24,18 @@ async def test_time_accuracy(self): actual_time = time.time() * 1000.0 seconds = 10 - assert abs(actual_time - reported_time) < seconds * 1000, "Time is not within %s seconds" % seconds + assert abs(actual_time - reported_time) < seconds * 1000, 'Time is not within %s seconds' % seconds async def test_time_without_key_or_token(self): reported_time = await self.ably.time() actual_time = time.time() * 1000.0 seconds = 10 - assert abs(actual_time - reported_time) < seconds * 1000, "Time is not within %s seconds" % seconds + assert abs(actual_time - reported_time) < seconds * 1000, 'Time is not within %s seconds' % seconds @dont_vary_protocol async def test_time_fails_without_valid_host(self): - ably = await TestApp.get_ably_rest(key=None, token='foo', rest_host="this.host.does.not.exist") + ably = await TestApp.get_ably_rest(key=None, token='foo', rest_host='this.host.does.not.exist') with pytest.raises(AblyException): await ably.time() diff --git a/test/ably/rest/resttoken_test.py b/test/ably/rest/resttoken_test.py index a50c5ea4..3bb6780d 100644 --- a/test/ably/rest/resttoken_test.py +++ b/test/ably/rest/resttoken_test.py @@ -18,12 +18,11 @@ class TestRestToken(BaseAsyncTestCase, metaclass=VaryByProtocolTestsMetaclass): - async def server_time(self): return await self.ably.time() async def asyncSetUp(self): - capability = {"*": ["*"]} + capability = {'*': ['*']} self.permit_all = str(Capability(capability)) self.ably = await TestApp.get_ably_rest() @@ -38,19 +37,19 @@ async def test_request_token_null_params(self): pre_time = await self.server_time() token_details = await self.ably.auth.request_token() post_time = await self.server_time() - assert token_details.token is not None, "Expected token" - assert token_details.issued + 300 >= pre_time, "Unexpected issued time" - assert token_details.issued <= post_time, "Unexpected issued time" - assert self.permit_all == str(token_details.capability), "Unexpected capability" + assert token_details.token is not None, 'Expected token' + assert token_details.issued + 300 >= pre_time, 'Unexpected issued time' + assert token_details.issued <= post_time, 'Unexpected issued time' + assert self.permit_all == str(token_details.capability), 'Unexpected capability' async def test_request_token_explicit_timestamp(self): pre_time = await self.server_time() token_details = await self.ably.auth.request_token(token_params={'timestamp': pre_time}) post_time = await self.server_time() - assert token_details.token is not None, "Expected token" - assert token_details.issued + 300 >= pre_time, "Unexpected issued time" - assert token_details.issued <= post_time, "Unexpected issued time" - assert self.permit_all == str(Capability(token_details.capability)), "Unexpected Capability" + assert token_details.token is not None, 'Expected token' + assert token_details.issued + 300 >= pre_time, 'Unexpected issued time' + assert token_details.issued <= post_time, 'Unexpected issued time' + assert self.permit_all == str(Capability(token_details.capability)), 'Unexpected Capability' async def test_request_token_explicit_invalid_timestamp(self): request_time = await self.server_time() @@ -63,52 +62,45 @@ async def test_request_token_with_system_timestamp(self): pre_time = await self.server_time() token_details = await self.ably.auth.request_token(query_time=True) post_time = await self.server_time() - assert token_details.token is not None, "Expected token" - assert token_details.issued >= pre_time, "Unexpected issued time" - assert token_details.issued <= post_time, "Unexpected issued time" - assert self.permit_all == str(Capability(token_details.capability)), "Unexpected Capability" + assert token_details.token is not None, 'Expected token' + assert token_details.issued >= pre_time, 'Unexpected issued time' + assert token_details.issued <= post_time, 'Unexpected issued time' + assert self.permit_all == str(Capability(token_details.capability)), 'Unexpected Capability' async def test_request_token_with_duplicate_nonce(self): request_time = await self.server_time() - token_params = { - 'timestamp': request_time, - 'nonce': '1234567890123456' - } + token_params = {'timestamp': request_time, 'nonce': '1234567890123456'} token_details = await self.ably.auth.request_token(token_params) - assert token_details.token is not None, "Expected token" + assert token_details.token is not None, 'Expected token' with pytest.raises(AblyException): await self.ably.auth.request_token(token_params) async def test_request_token_with_capability_that_subsets_key_capability(self): - capability = Capability({ - "onlythischannel": ["subscribe"] - }) + capability = Capability({'onlythischannel': ['subscribe']}) - token_details = await self.ably.auth.request_token( - token_params={'capability': capability}) + token_details = await self.ably.auth.request_token(token_params={'capability': capability}) assert token_details is not None assert token_details.token is not None - assert capability == token_details.capability, "Unexpected capability" + assert capability == token_details.capability, 'Unexpected capability' async def test_request_token_with_specified_key(self): test_vars = await TestApp.get_test_vars() - key = test_vars["keys"][1] - token_details = await self.ably.auth.request_token( - key_name=key["key_name"], key_secret=key["key_secret"]) - assert token_details.token is not None, "Expected token" - assert key.get("capability") == token_details.capability, "Unexpected capability" + key = test_vars['keys'][1] + token_details = await self.ably.auth.request_token(key_name=key['key_name'], key_secret=key['key_secret']) + assert token_details.token is not None, 'Expected token' + assert key.get('capability') == token_details.capability, 'Unexpected capability' @dont_vary_protocol async def test_request_token_with_invalid_mac(self): with pytest.raises(AblyException): - await self.ably.auth.request_token(token_params={'mac': "thisisnotavalidmac"}) + await self.ably.auth.request_token(token_params={'mac': 'thisisnotavalidmac'}) async def test_request_token_with_specified_ttl(self): token_details = await self.ably.auth.request_token(token_params={'ttl': 100}) - assert token_details.token is not None, "Expected token" - assert token_details.issued + 100 == token_details.expires, "Unexpected expires" + assert token_details.token is not None, 'Expected token' + assert token_details.issued + 100 == token_details.expires, 'Unexpected expires' @dont_vary_protocol async def test_token_with_excessive_ttl(self): @@ -123,8 +115,9 @@ 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.rest.rest.AblyRest.time', wraps=self.ably.time) as server_time, patch( + 'ably.rest.auth.Auth._timestamp', wraps=timestamp + ) as local_time: await self.ably.auth.request_token() assert local_time.called assert not server_time.called @@ -132,8 +125,9 @@ 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.rest.rest.AblyRest.time', wraps=self.ably.time) as server_time, patch( + 'ably.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 @@ -159,7 +153,6 @@ async def test_request_token_float_and_timedelta(self): class TestCreateTokenRequest(BaseAsyncTestCase, metaclass=VaryByProtocolTestsMetaclass): - async def asyncSetUp(self): self.ably = await TestApp.get_ably_rest() self.key_name = self.ably.options.key_name @@ -175,20 +168,22 @@ def per_protocol_setup(self, use_binary_protocol): @dont_vary_protocol async def test_key_name_and_secret_are_required(self): ably = await TestApp.get_ably_rest(key=None, token='not a real token') - with pytest.raises(AblyException, match="40101 401 No key specified"): + with pytest.raises(AblyException, match='40101 401 No key specified'): await ably.auth.create_token_request() - with pytest.raises(AblyException, match="40101 401 No key specified"): + with pytest.raises(AblyException, match='40101 401 No key specified'): await ably.auth.create_token_request(key_name=self.key_name) - with pytest.raises(AblyException, match="40101 401 No key specified"): + with pytest.raises(AblyException, match='40101 401 No key specified'): await ably.auth.create_token_request(key_secret=self.key_secret) @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.rest.rest.AblyRest.time', wraps=self.ably.time) as server_time, patch( + 'ably.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) + key_name=self.key_name, key_secret=self.key_secret, query_time=False + ) assert local_time.called assert not server_time.called @@ -196,28 +191,32 @@ 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.rest.rest.AblyRest.time', wraps=self.ably.time) as server_time, patch( + 'ably.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) + key_name=self.key_name, key_secret=self.key_secret, query_time=True + ) assert local_time.call_count == 1 assert server_time.call_count == 1 await self.ably.auth.create_token_request( - key_name=self.key_name, key_secret=self.key_secret, query_time=True) + key_name=self.key_name, key_secret=self.key_secret, query_time=True + ) assert local_time.call_count == 2 assert server_time.call_count == 1 async def test_token_request_can_be_used_to_get_a_token(self): token_request = await self.ably.auth.create_token_request( - key_name=self.key_name, key_secret=self.key_secret) + key_name=self.key_name, key_secret=self.key_secret + ) assert isinstance(token_request, TokenRequest) async def auth_callback(token_params): return token_request - ably = await TestApp.get_ably_rest(key=None, - auth_callback=auth_callback, - use_binary_protocol=self.use_binary_protocol) + ably = await TestApp.get_ably_rest( + key=None, auth_callback=auth_callback, use_binary_protocol=self.use_binary_protocol + ) token = await ably.auth.authorize() assert isinstance(token, TokenDetails) @@ -225,15 +224,16 @@ async def auth_callback(token_params): async def test_token_request_dict_can_be_used_to_get_a_token(self): token_request = await self.ably.auth.create_token_request( - key_name=self.key_name, key_secret=self.key_secret) + key_name=self.key_name, key_secret=self.key_secret + ) assert isinstance(token_request, TokenRequest) async def auth_callback(token_params): return token_request.to_dict() - ably = await TestApp.get_ably_rest(key=None, - auth_callback=auth_callback, - use_binary_protocol=self.use_binary_protocol) + ably = await TestApp.get_ably_rest( + key=None, auth_callback=auth_callback, use_binary_protocol=self.use_binary_protocol + ) token = await ably.auth.authorize() assert isinstance(token, TokenDetails) @@ -243,7 +243,8 @@ async def auth_callback(token_params): @dont_vary_protocol async def test_token_request_from_json(self): token_request = await self.ably.auth.create_token_request( - key_name=self.key_name, key_secret=self.key_secret) + key_name=self.key_name, key_secret=self.key_secret + ) assert isinstance(token_request, TokenRequest) token_request_dict = token_request.to_dict() @@ -255,11 +256,13 @@ async def test_token_request_from_json(self): @dont_vary_protocol async def test_nonce_is_random_and_longer_than_15_characters(self): token_request = await self.ably.auth.create_token_request( - key_name=self.key_name, key_secret=self.key_secret) + key_name=self.key_name, key_secret=self.key_secret + ) assert len(token_request.nonce) > 15 another_token_request = await self.ably.auth.create_token_request( - key_name=self.key_name, key_secret=self.key_secret) + key_name=self.key_name, key_secret=self.key_secret + ) assert len(another_token_request.nonce) > 15 assert token_request.nonce != another_token_request.nonce @@ -268,14 +271,16 @@ async def test_nonce_is_random_and_longer_than_15_characters(self): @dont_vary_protocol async def test_ttl_is_optional_and_specified_in_ms(self): token_request = await self.ably.auth.create_token_request( - key_name=self.key_name, key_secret=self.key_secret) + key_name=self.key_name, key_secret=self.key_secret + ) assert token_request.ttl is None # RSA6 @dont_vary_protocol async def test_capability_is_optional(self): token_request = await self.ably.auth.create_token_request( - key_name=self.key_name, key_secret=self.key_secret) + key_name=self.key_name, key_secret=self.key_secret + ) assert token_request.capability is None @dont_vary_protocol @@ -289,7 +294,8 @@ async def test_accept_all_token_params(self): } token_request = await self.ably.auth.create_token_request( token_params, - key_name=self.key_name, key_secret=self.key_secret, + key_name=self.key_name, + key_secret=self.key_secret, ) assert token_request.ttl == token_params['ttl'] assert token_request.capability == str(token_params['capability']) @@ -300,15 +306,16 @@ async def test_accept_all_token_params(self): async def test_capability(self): capability = Capability({'channel': ['publish']}) token_request = await self.ably.auth.create_token_request( - key_name=self.key_name, key_secret=self.key_secret, - token_params={'capability': capability}) + key_name=self.key_name, key_secret=self.key_secret, token_params={'capability': capability} + ) assert token_request.capability == str(capability) async def auth_callback(token_params): return token_request - ably = await TestApp.get_ably_rest(key=None, auth_callback=auth_callback, - use_binary_protocol=self.use_binary_protocol) + ably = await TestApp.get_ably_rest( + key=None, auth_callback=auth_callback, use_binary_protocol=self.use_binary_protocol + ) token = await ably.auth.authorize() @@ -325,7 +332,8 @@ async def test_hmac(self): 'timestamp': 1000, } token_request = await ably.auth.create_token_request( - token_params, key_secret='a_secret', key_name='a_key_name') + token_params, key_secret='a_secret', key_name='a_key_name' + ) assert token_request.mac == 'sYkCH0Un+WgzI7/Nhy0BoQIKq9HmjKynCRs4E3qAbGQ=' await ably.close() @@ -334,9 +342,11 @@ async def test_hmac(self): async def test_query_server_time(self): with patch('ably.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) + key_name=self.key_name, key_secret=self.key_secret, query_time=True + ) assert server_time.call_count == 1 await self.ably.auth.create_token_request( - key_name=self.key_name, key_secret=self.key_secret, query_time=False) + key_name=self.key_name, key_secret=self.key_secret, query_time=False + ) assert server_time.call_count == 1 diff --git a/test/ably/testapp.py b/test/ably/testapp.py index 86741f3c..31f6b3c9 100644 --- a/test/ably/testapp.py +++ b/test/ably/testapp.py @@ -13,7 +13,7 @@ with open(os.path.dirname(__file__) + '/../assets/testAppSpec.json', 'r') as f: app_spec_local = json.loads(f.read()) -tls = (os.environ.get('ABLY_TLS') or "true").lower() == "true" +tls = (os.environ.get('ABLY_TLS') or 'true').lower() == 'true' rest_host = os.environ.get('ABLY_REST_HOST', 'sandbox-rest.ably.io') realtime_host = os.environ.get('ABLY_REALTIME_HOST', 'sandbox-realtime.ably.io') @@ -22,16 +22,20 @@ port = 80 tls_port = 443 -if rest_host and not rest_host.endswith("rest.ably.io"): - tls = tls and rest_host != "localhost" +if rest_host and not rest_host.endswith('rest.ably.io'): + tls = tls and rest_host != 'localhost' port = 8080 tls_port = 8081 -ably = AblyRest(token='not_a_real_token', - port=port, tls_port=tls_port, tls=tls, - environment=environment, - use_binary_protocol=False) +ably = AblyRest( + token='not_a_real_token', + port=port, + tls_port=tls_port, + tls=tls, + environment=environment, + use_binary_protocol=False, +) class TestApp: @@ -40,32 +44,34 @@ class TestApp: @staticmethod async def get_test_vars(): if not TestApp.__test_vars: - r = await ably.http.post("/apps", body=app_spec_local, skip_auth=True) + r = await ably.http.post('/apps', body=app_spec_local, skip_auth=True) AblyException.raise_for_response(r) app_spec = r.json() - app_id = app_spec.get("appId", "") + app_id = app_spec.get('appId', '') test_vars = { - "app_id": app_id, - "host": rest_host, - "port": port, - "tls_port": tls_port, - "tls": tls, - "environment": environment, - "realtime_host": realtime_host, - "keys": [{ - "key_name": "%s.%s" % (app_id, k.get("id", "")), - "key_secret": k.get("value", ""), - "key_str": "%s.%s:%s" % (app_id, k.get("id", ""), k.get("value", "")), - "capability": Capability(json.loads(k.get("capability", "{}"))), - } for k in app_spec.get("keys", [])] + 'app_id': app_id, + 'host': rest_host, + 'port': port, + 'tls_port': tls_port, + 'tls': tls, + 'environment': environment, + 'realtime_host': realtime_host, + 'keys': [ + { + 'key_name': '%s.%s' % (app_id, k.get('id', '')), + 'key_secret': k.get('value', ''), + 'key_str': '%s.%s:%s' % (app_id, k.get('id', ''), k.get('value', '')), + 'capability': Capability(json.loads(k.get('capability', '{}'))), + } + for k in app_spec.get('keys', []) + ], } TestApp.__test_vars = test_vars - log.debug([(app_id, k.get("id", ""), k.get("value", "")) - for k in app_spec.get("keys", [])]) + log.debug([(app_id, k.get('id', ''), k.get('value', '')) for k in app_spec.get('keys', [])]) return TestApp.__test_vars @@ -85,17 +91,17 @@ async def get_ably_realtime(**kw): @staticmethod def get_options(test_vars, **kwargs): options = { - 'port': test_vars["port"], - 'tls_port': test_vars["tls_port"], - 'tls': test_vars["tls"], - 'environment': test_vars["environment"], + 'port': test_vars['port'], + 'tls_port': test_vars['tls_port'], + 'tls': test_vars['tls'], + 'environment': test_vars['environment'], } - auth_methods = ["auth_url", "auth_callback", "token", "token_details", "key"] + auth_methods = ['auth_url', 'auth_callback', 'token', 'token_details', 'key'] if not any(x in kwargs for x in auth_methods): - options["key"] = test_vars["keys"][0]["key_str"] + options['key'] = test_vars['keys'][0]['key_str'] - if any(x in kwargs for x in ["rest_host", "realtime_host"]): - options["environment"] = None + if any(x in kwargs for x in ['rest_host', 'realtime_host']): + options['environment'] = None options.update(kwargs) @@ -104,11 +110,11 @@ def get_options(test_vars, **kwargs): @staticmethod async def clear_test_vars(): test_vars = TestApp.__test_vars - options = Options(key=test_vars["keys"][0]["key_str"]) - options.rest_host = test_vars["host"] - options.port = test_vars["port"] - options.tls_port = test_vars["tls_port"] - options.tls = test_vars["tls"] + options = Options(key=test_vars['keys'][0]['key_str']) + options.rest_host = test_vars['host'] + options.port = test_vars['port'] + options.tls_port = test_vars['tls_port'] + options.tls = test_vars['tls'] ably = await TestApp.get_ably_rest() await ably.http.delete('/apps/' + test_vars['app_id']) TestApp.__test_vars = None diff --git a/test/ably/utils.py b/test/ably/utils.py index cb0a5b0d..afd847a5 100644 --- a/test/ably/utils.py +++ b/test/ably/utils.py @@ -3,6 +3,7 @@ import string import unittest import sys + if sys.version_info >= (3, 8): from unittest import IsolatedAsyncioTestCase else: @@ -17,12 +18,9 @@ class BaseTestCase(unittest.TestCase): - def respx_add_empty_msg_pack(self, url, method='GET'): respx.route(method=method, url=url).return_value = Response( - status_code=200, - headers={'content-type': 'application/x-msgpack'}, - content=msgpack.packb({}) + status_code=200, headers={'content-type': 'application/x-msgpack'}, content=msgpack.packb({}) ) @classmethod @@ -36,12 +34,9 @@ def get_channel(cls, prefix=''): class BaseAsyncTestCase(IsolatedAsyncioTestCase): - def respx_add_empty_msg_pack(self, url, method='GET'): respx.route(method=method, url=url).return_value = Response( - status_code=200, - headers={'content-type': 'application/x-msgpack'}, - content=msgpack.packb({}) + status_code=200, headers={'content-type': 'application/x-msgpack'}, content=msgpack.packb({}) ) @classmethod @@ -90,8 +85,9 @@ async def test_decorated(self, *args, **kwargs): await fn(self, *args, **kwargs) unpatch(patcher) - assert len(responses) >= 1,\ - "If your test doesn't make any requests, use the @dont_vary_protocol decorator" + assert ( + len(responses) >= 1 + ), "If your test doesn't make any requests, use the @dont_vary_protocol decorator" for response in responses: # In HTTP/2 some header fields are optional in case of 204 status code @@ -107,6 +103,7 @@ async def test_decorated(self, *args, **kwargs): msgpack.unpackb(response.content) return test_decorated + return test_decorator @@ -122,10 +119,10 @@ def per_protocol_setup(self, use_binary_protocol): is called * exclude tests with the @dont_vary_protocol decorator """ + def __new__(cls, clsname, bases, dct): for key, value in tuple(dct.items()): - if key.startswith('test') and not getattr(value, 'dont_vary_protocol', - False): + if key.startswith('test') and not getattr(value, 'dont_vary_protocol', False): wrapper_bin = cls.wrap_as('bin', key, value) wrapper_text = cls.wrap_as('text', key, value) @@ -145,6 +142,7 @@ async def wrapper(self): if hasattr(self, 'per_protocol_setup'): self.per_protocol_setup(ttype == 'bin') await old_func(self) + wrapper.__name__ = old_name + '_' + ttype return wrapper diff --git a/test/unit/message_test.py b/test/unit/message_test.py index 4902d6b5..237b3a7c 100644 --- a/test/unit/message_test.py +++ b/test/unit/message_test.py @@ -7,18 +7,13 @@ def test_update_inner_message_fields_tm2(): 'id': 'abcdefg', 'connectionId': 'custom_connection_id', 'timestamp': 23134, - 'messages': [ - { - 'event': 'test', - 'data': 'hello there''' - } - ] + 'messages': [{'event': 'test', 'data': 'hello there' ''}], } ably.types.message.Message.update_inner_message_fields(proto_msg) messages: list[dict] = proto_msg.get('messages') msg_index = 0 for msg in messages: - assert msg.get('id') == f"abcdefg:{msg_index}" + assert msg.get('id') == f'abcdefg:{msg_index}' assert msg.get('connectionId') == 'custom_connection_id' assert msg.get('timestamp') == 23134 msg_index = msg_index + 1 @@ -30,18 +25,13 @@ def test_update_inner_message_fields_for_presence_msg_tm2(): 'id': 'abcdefg', 'connectionId': 'custom_connection_id', 'timestamp': 23134, - 'presence': [ - { - 'event': 'test', - 'data': 'hello there' - } - ] + 'presence': [{'event': 'test', 'data': 'hello there'}], } ably.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: - assert presence_msg.get('id') == f"abcdefg:{msg_index}" + assert presence_msg.get('id') == f'abcdefg:{msg_index}' assert presence_msg.get('connectionId') == 'custom_connection_id' assert presence_msg.get('timestamp') == 23134 msg_index = msg_index + 1