phoenix-channels-python-client 0.5.1__tar.gz → 0.5.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {phoenix_channels_python_client-0.5.1/phoenix_channels_python_client.egg-info → phoenix_channels_python_client-0.5.2}/PKG-INFO +10 -6
- {phoenix_channels_python_client-0.5.1 → phoenix_channels_python_client-0.5.2}/README.md +9 -5
- {phoenix_channels_python_client-0.5.1 → phoenix_channels_python_client-0.5.2}/phoenix_channels_python_client/__init__.py +1 -1
- {phoenix_channels_python_client-0.5.1 → phoenix_channels_python_client-0.5.2}/phoenix_channels_python_client/codec.py +3 -1
- {phoenix_channels_python_client-0.5.1 → phoenix_channels_python_client-0.5.2}/phoenix_channels_python_client/diagnostics.py +29 -9
- {phoenix_channels_python_client-0.5.1 → phoenix_channels_python_client-0.5.2}/phoenix_channels_python_client/messages.py +1 -1
- {phoenix_channels_python_client-0.5.1 → phoenix_channels_python_client-0.5.2}/phoenix_channels_python_client/replies.py +7 -9
- {phoenix_channels_python_client-0.5.1 → phoenix_channels_python_client-0.5.2}/phoenix_channels_python_client/supervisor.py +2 -0
- {phoenix_channels_python_client-0.5.1 → phoenix_channels_python_client-0.5.2}/phoenix_channels_python_client/topic_runtime.py +3 -2
- {phoenix_channels_python_client-0.5.1 → phoenix_channels_python_client-0.5.2/phoenix_channels_python_client.egg-info}/PKG-INFO +10 -6
- {phoenix_channels_python_client-0.5.1 → phoenix_channels_python_client-0.5.2}/pyproject.toml +1 -1
- {phoenix_channels_python_client-0.5.1 → phoenix_channels_python_client-0.5.2}/tests/test_channel_recovery.py +2 -2
- {phoenix_channels_python_client-0.5.1 → phoenix_channels_python_client-0.5.2}/tests/test_security.py +43 -0
- {phoenix_channels_python_client-0.5.1 → phoenix_channels_python_client-0.5.2}/LICENSE +0 -0
- {phoenix_channels_python_client-0.5.1 → phoenix_channels_python_client-0.5.2}/MANIFEST.in +0 -0
- {phoenix_channels_python_client-0.5.1 → phoenix_channels_python_client-0.5.2}/phoenix_channels_python_client/authentication.py +0 -0
- {phoenix_channels_python_client-0.5.1 → phoenix_channels_python_client-0.5.2}/phoenix_channels_python_client/channel.py +0 -0
- {phoenix_channels_python_client-0.5.1 → phoenix_channels_python_client-0.5.2}/phoenix_channels_python_client/client.py +0 -0
- {phoenix_channels_python_client-0.5.1 → phoenix_channels_python_client-0.5.2}/phoenix_channels_python_client/client_state_machine.py +0 -0
- {phoenix_channels_python_client-0.5.1 → phoenix_channels_python_client-0.5.2}/phoenix_channels_python_client/client_types.py +0 -0
- {phoenix_channels_python_client-0.5.1 → phoenix_channels_python_client-0.5.2}/phoenix_channels_python_client/default_decider.py +0 -0
- {phoenix_channels_python_client-0.5.1 → phoenix_channels_python_client-0.5.2}/phoenix_channels_python_client/exceptions.py +0 -0
- {phoenix_channels_python_client-0.5.1 → phoenix_channels_python_client-0.5.2}/phoenix_channels_python_client/protocol.py +0 -0
- {phoenix_channels_python_client-0.5.1 → phoenix_channels_python_client-0.5.2}/phoenix_channels_python_client/protocol_handler.py +0 -0
- {phoenix_channels_python_client-0.5.1 → phoenix_channels_python_client-0.5.2}/phoenix_channels_python_client/py.typed +0 -0
- {phoenix_channels_python_client-0.5.1 → phoenix_channels_python_client-0.5.2}/phoenix_channels_python_client/reconnect_controller.py +0 -0
- {phoenix_channels_python_client-0.5.1 → phoenix_channels_python_client-0.5.2}/phoenix_channels_python_client/send_session.py +0 -0
- {phoenix_channels_python_client-0.5.1 → phoenix_channels_python_client-0.5.2}/phoenix_channels_python_client/shutdown_signals.py +0 -0
- {phoenix_channels_python_client-0.5.1 → phoenix_channels_python_client-0.5.2}/phoenix_channels_python_client/topic_subscription.py +0 -0
- {phoenix_channels_python_client-0.5.1 → phoenix_channels_python_client-0.5.2}/phoenix_channels_python_client/utils.py +0 -0
- {phoenix_channels_python_client-0.5.1 → phoenix_channels_python_client-0.5.2}/phoenix_channels_python_client.egg-info/SOURCES.txt +0 -0
- {phoenix_channels_python_client-0.5.1 → phoenix_channels_python_client-0.5.2}/phoenix_channels_python_client.egg-info/dependency_links.txt +0 -0
- {phoenix_channels_python_client-0.5.1 → phoenix_channels_python_client-0.5.2}/phoenix_channels_python_client.egg-info/requires.txt +0 -0
- {phoenix_channels_python_client-0.5.1 → phoenix_channels_python_client-0.5.2}/phoenix_channels_python_client.egg-info/top_level.txt +0 -0
- {phoenix_channels_python_client-0.5.1 → phoenix_channels_python_client-0.5.2}/setup.cfg +0 -0
- {phoenix_channels_python_client-0.5.1 → phoenix_channels_python_client-0.5.2}/tests/test_binary.py +0 -0
- {phoenix_channels_python_client-0.5.1 → phoenix_channels_python_client-0.5.2}/tests/test_cancel_and_wait.py +0 -0
- {phoenix_channels_python_client-0.5.1 → phoenix_channels_python_client-0.5.2}/tests/test_channel_api.py +0 -0
- {phoenix_channels_python_client-0.5.1 → phoenix_channels_python_client-0.5.2}/tests/test_cleanup_ownership.py +0 -0
- {phoenix_channels_python_client-0.5.1 → phoenix_channels_python_client-0.5.2}/tests/test_client_state.py +0 -0
- {phoenix_channels_python_client-0.5.1 → phoenix_channels_python_client-0.5.2}/tests/test_codec.py +0 -0
- {phoenix_channels_python_client-0.5.1 → phoenix_channels_python_client-0.5.2}/tests/test_connection.py +0 -0
- {phoenix_channels_python_client-0.5.1 → phoenix_channels_python_client-0.5.2}/tests/test_heartbeat.py +0 -0
- {phoenix_channels_python_client-0.5.1 → phoenix_channels_python_client-0.5.2}/tests/test_heartbeat_timeout.py +0 -0
- {phoenix_channels_python_client-0.5.1 → phoenix_channels_python_client-0.5.2}/tests/test_join_installation.py +0 -0
- {phoenix_channels_python_client-0.5.1 → phoenix_channels_python_client-0.5.2}/tests/test_join_lifecycle.py +0 -0
- {phoenix_channels_python_client-0.5.1 → phoenix_channels_python_client-0.5.2}/tests/test_join_params.py +0 -0
- {phoenix_channels_python_client-0.5.1 → phoenix_channels_python_client-0.5.2}/tests/test_join_params_serialization.py +0 -0
- {phoenix_channels_python_client-0.5.1 → phoenix_channels_python_client-0.5.2}/tests/test_join_responses.py +0 -0
- {phoenix_channels_python_client-0.5.1 → phoenix_channels_python_client-0.5.2}/tests/test_optional_lifecycle.py +0 -0
- {phoenix_channels_python_client-0.5.1 → phoenix_channels_python_client-0.5.2}/tests/test_optional_reconnect.py +0 -0
- {phoenix_channels_python_client-0.5.1 → phoenix_channels_python_client-0.5.2}/tests/test_package_typing.py +0 -0
- {phoenix_channels_python_client-0.5.1 → phoenix_channels_python_client-0.5.2}/tests/test_protocol_handler.py +0 -0
- {phoenix_channels_python_client-0.5.1 → phoenix_channels_python_client-0.5.2}/tests/test_public_api.py +0 -0
- {phoenix_channels_python_client-0.5.1 → phoenix_channels_python_client-0.5.2}/tests/test_push.py +0 -0
- {phoenix_channels_python_client-0.5.1 → phoenix_channels_python_client-0.5.2}/tests/test_reconnect.py +0 -0
- {phoenix_channels_python_client-0.5.1 → phoenix_channels_python_client-0.5.2}/tests/test_reconnect_decider.py +0 -0
- {phoenix_channels_python_client-0.5.1 → phoenix_channels_python_client-0.5.2}/tests/test_reconnect_policy_invariants.py +0 -0
- {phoenix_channels_python_client-0.5.1 → phoenix_channels_python_client-0.5.2}/tests/test_reconnect_stress.py +0 -0
- {phoenix_channels_python_client-0.5.1 → phoenix_channels_python_client-0.5.2}/tests/test_run_forever_signals.py +0 -0
- {phoenix_channels_python_client-0.5.1 → phoenix_channels_python_client-0.5.2}/tests/test_send_session.py +0 -0
- {phoenix_channels_python_client-0.5.1 → phoenix_channels_python_client-0.5.2}/tests/test_shutdown_races.py +0 -0
- {phoenix_channels_python_client-0.5.1 → phoenix_channels_python_client-0.5.2}/tests/test_subscriptions.py +0 -0
- {phoenix_channels_python_client-0.5.1 → phoenix_channels_python_client-0.5.2}/tests/test_supervisor_internals.py +0 -0
- {phoenix_channels_python_client-0.5.1 → phoenix_channels_python_client-0.5.2}/tests/test_topic_runtime_internals.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: phoenix-channels-python-client
|
|
3
|
-
Version: 0.5.
|
|
3
|
+
Version: 0.5.2
|
|
4
4
|
Summary: A Python client library for connecting to Phoenix Channels
|
|
5
5
|
Author: Phoenix Channels Python Client
|
|
6
6
|
License-Expression: MIT
|
|
@@ -681,7 +681,9 @@ Expiry or heartbeat send failure force-closes that socket; the supervisor handle
|
|
|
681
681
|
## Logging
|
|
682
682
|
|
|
683
683
|
The library uses loggers under `phoenix_channels_python_client`. Configure
|
|
684
|
-
logging in your application; importing the package does not configure it
|
|
684
|
+
logging in your application; importing the package does not configure it.
|
|
685
|
+
Connection log lines show `<omitted>` in place of values that may carry personal
|
|
686
|
+
data (see [Authentication and diagnostic safety](#authentication-and-diagnostic-safety)):
|
|
685
687
|
|
|
686
688
|
```python
|
|
687
689
|
import logging
|
|
@@ -736,10 +738,12 @@ exception objects, or socket metadata. `client.redact_diagnostic(text)` applies
|
|
|
736
738
|
the credential policy to transport errors a caller needs to retain. Caller-visible
|
|
737
739
|
errors may still contain personal data and should not be logged outside this policy.
|
|
738
740
|
|
|
739
|
-
Connection diagnostics omit dynamic
|
|
740
|
-
headers, frame bodies, user/topic identities, and untrusted server error
|
|
741
|
-
|
|
742
|
-
|
|
741
|
+
Connection diagnostics omit dynamic values and transport payloads, including URLs,
|
|
742
|
+
headers, frame bodies, user/topic identities, numbers, and untrusted server error
|
|
743
|
+
details. Each omitted value appears as `<omitted>`, for example
|
|
744
|
+
`No handler found for event <omitted> on topic <omitted>`. Logs retain static
|
|
745
|
+
lifecycle descriptions, enum values such as connection states, booleans, and
|
|
746
|
+
exception types. Application data and caller-visible errors are not changed;
|
|
743
747
|
applications remain responsible for logs outside this connection-owned boundary.
|
|
744
748
|
|
|
745
749
|
---
|
|
@@ -648,7 +648,9 @@ Expiry or heartbeat send failure force-closes that socket; the supervisor handle
|
|
|
648
648
|
## Logging
|
|
649
649
|
|
|
650
650
|
The library uses loggers under `phoenix_channels_python_client`. Configure
|
|
651
|
-
logging in your application; importing the package does not configure it
|
|
651
|
+
logging in your application; importing the package does not configure it.
|
|
652
|
+
Connection log lines show `<omitted>` in place of values that may carry personal
|
|
653
|
+
data (see [Authentication and diagnostic safety](#authentication-and-diagnostic-safety)):
|
|
652
654
|
|
|
653
655
|
```python
|
|
654
656
|
import logging
|
|
@@ -703,10 +705,12 @@ exception objects, or socket metadata. `client.redact_diagnostic(text)` applies
|
|
|
703
705
|
the credential policy to transport errors a caller needs to retain. Caller-visible
|
|
704
706
|
errors may still contain personal data and should not be logged outside this policy.
|
|
705
707
|
|
|
706
|
-
Connection diagnostics omit dynamic
|
|
707
|
-
headers, frame bodies, user/topic identities, and untrusted server error
|
|
708
|
-
|
|
709
|
-
|
|
708
|
+
Connection diagnostics omit dynamic values and transport payloads, including URLs,
|
|
709
|
+
headers, frame bodies, user/topic identities, numbers, and untrusted server error
|
|
710
|
+
details. Each omitted value appears as `<omitted>`, for example
|
|
711
|
+
`No handler found for event <omitted> on topic <omitted>`. Logs retain static
|
|
712
|
+
lifecycle descriptions, enum values such as connection states, booleans, and
|
|
713
|
+
exception types. Application data and caller-visible errors are not changed;
|
|
710
714
|
applications remain responsible for logs outside this connection-owned boundary.
|
|
711
715
|
|
|
712
716
|
---
|
|
@@ -27,7 +27,7 @@ from phoenix_channels_python_client.messages import Message, Payload, SystemEven
|
|
|
27
27
|
from phoenix_channels_python_client.protocol import ProtocolVersion
|
|
28
28
|
from phoenix_channels_python_client.replies import Reply
|
|
29
29
|
|
|
30
|
-
__version__ = "0.5.
|
|
30
|
+
__version__ = "0.5.2"
|
|
31
31
|
|
|
32
32
|
__all__ = [
|
|
33
33
|
"Channel",
|
|
@@ -120,7 +120,9 @@ def _decode_binary(raw: bytes) -> DecodedMessage:
|
|
|
120
120
|
raise ValueError("Empty binary frame")
|
|
121
121
|
kind = BinaryKind(raw[0])
|
|
122
122
|
fields, payload = _binary_fields(raw, SERVER_HEADER_FIELDS[kind])
|
|
123
|
-
|
|
123
|
+
join_ref: str | None
|
|
124
|
+
ref: str | None
|
|
125
|
+
status: str | None = None
|
|
124
126
|
match kind:
|
|
125
127
|
case BinaryKind.PUSH:
|
|
126
128
|
join_ref, topic, event = fields
|
|
@@ -3,6 +3,7 @@ from __future__ import annotations
|
|
|
3
3
|
import json
|
|
4
4
|
import logging
|
|
5
5
|
import re
|
|
6
|
+
from enum import Enum
|
|
6
7
|
from urllib.parse import parse_qsl, quote, quote_plus, urlsplit
|
|
7
8
|
|
|
8
9
|
from websockets.protocol import State
|
|
@@ -14,7 +15,34 @@ from phoenix_channels_python_client.authentication import (
|
|
|
14
15
|
)
|
|
15
16
|
|
|
16
17
|
REDACTED = "[REDACTED]"
|
|
18
|
+
OMITTED = "<omitted>"
|
|
17
19
|
PERCENT_ESCAPE = re.compile(r"%[0-9a-fA-F]{2}")
|
|
20
|
+
# A printf-style conversion, as logging applies to a record's msg and args.
|
|
21
|
+
PLACEHOLDER = re.compile(
|
|
22
|
+
r"%(?:\([^)]*\))?[#0 +-]*(?:\*|\d+)?(?:\.(?:\*|\d+))?[hlL]?[diouxXeEfFgGcrsa%]"
|
|
23
|
+
)
|
|
24
|
+
WEBSOCKET_STATE_MESSAGE = "= connection is %s"
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def render_value(value: object) -> str:
|
|
28
|
+
# Enum members and booleans are code-defined; any other value, numbers
|
|
29
|
+
# included, may carry personal data.
|
|
30
|
+
return str(value) if isinstance(value, Enum | bool) else OMITTED
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def render_message(record: logging.LogRecord) -> str:
|
|
34
|
+
"""Fill a record's placeholders without exposing its arguments."""
|
|
35
|
+
message = str(record.msg)
|
|
36
|
+
if not record.args:
|
|
37
|
+
return message
|
|
38
|
+
args = record.args if isinstance(record.args, tuple) else ()
|
|
39
|
+
if message == WEBSOCKET_STATE_MESSAGE and args and args[0] in State.__members__:
|
|
40
|
+
return message % args[0]
|
|
41
|
+
values = iter(args)
|
|
42
|
+
return PLACEHOLDER.sub(
|
|
43
|
+
lambda match: "%" if match[0] == "%%" else render_value(next(values, None)),
|
|
44
|
+
message,
|
|
45
|
+
)
|
|
18
46
|
|
|
19
47
|
|
|
20
48
|
AUTHENTICATION_NAMES = frozenset(
|
|
@@ -86,15 +114,7 @@ class ConnectionLogger(logging.Logger):
|
|
|
86
114
|
def handle(self, record: logging.LogRecord) -> None:
|
|
87
115
|
if self.target.disabled:
|
|
88
116
|
return
|
|
89
|
-
message =
|
|
90
|
-
if (
|
|
91
|
-
record.msg == "= connection is %s"
|
|
92
|
-
and isinstance(record.args, tuple)
|
|
93
|
-
and len(record.args) == 1
|
|
94
|
-
and isinstance(record.args[0], str)
|
|
95
|
-
and record.args[0] in State.__members__
|
|
96
|
-
):
|
|
97
|
-
message = record.msg % record.args
|
|
117
|
+
message = render_message(record)
|
|
98
118
|
if record.exc_info and record.exc_info[0]:
|
|
99
119
|
message += " [" + record.exc_info[0].__name__ + "]"
|
|
100
120
|
safe_record = logging.LogRecord(
|
|
@@ -14,7 +14,7 @@ class SystemEvent(StrEnum):
|
|
|
14
14
|
close = "phx_close"
|
|
15
15
|
error = "phx_error"
|
|
16
16
|
# The protocol event intentionally shadows str.join.
|
|
17
|
-
join = "phx_join" # type: ignore[bad-override]
|
|
17
|
+
join = "phx_join" # type: ignore[bad-override, assignment]
|
|
18
18
|
reply = "phx_reply"
|
|
19
19
|
leave = "phx_leave"
|
|
20
20
|
|
|
@@ -20,13 +20,11 @@ def reply_from_message(message: Message, *, binary_status: str | None = None) ->
|
|
|
20
20
|
if binary_status is not None:
|
|
21
21
|
if type(message.payload) is not bytes:
|
|
22
22
|
raise TypeError("Binary reply requires a bytes payload")
|
|
23
|
-
status, response
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
if not isinstance(status, str) or not isinstance(response, dict):
|
|
31
|
-
raise TypeError("Reply must contain a string status and a response map")
|
|
23
|
+
return Reply(status=binary_status, response=message.payload)
|
|
24
|
+
payload = message.payload
|
|
25
|
+
if not isinstance(payload, dict):
|
|
26
|
+
raise TypeError("Text reply requires a response envelope")
|
|
27
|
+
status, response = payload.get("status"), payload.get("response")
|
|
28
|
+
if not isinstance(status, str) or not isinstance(response, dict):
|
|
29
|
+
raise TypeError("Reply must contain a string status and a response map")
|
|
32
30
|
return Reply(status=status, response=response)
|
|
@@ -27,6 +27,7 @@ from phoenix_channels_python_client.messages import (
|
|
|
27
27
|
Message,
|
|
28
28
|
)
|
|
29
29
|
from phoenix_channels_python_client.protocol_handler import PHXProtocolHandler
|
|
30
|
+
from phoenix_channels_python_client.send_session import SessionSends
|
|
30
31
|
from phoenix_channels_python_client.shutdown_signals import handle_shutdown_signals
|
|
31
32
|
from phoenix_channels_python_client.topic_subscription import (
|
|
32
33
|
ChannelState,
|
|
@@ -102,6 +103,7 @@ class SupervisorMixin:
|
|
|
102
103
|
heartbeat_interval_s: float | None
|
|
103
104
|
heartbeat_task: asyncio.Task[None] | None
|
|
104
105
|
pending_heartbeat_ref: str | None
|
|
106
|
+
send_session: SessionSends | None
|
|
105
107
|
on_reconnect: Callable[[], Awaitable[None]] | None
|
|
106
108
|
on_disconnect: Callable[[Exception | None], Awaitable[None]] | None
|
|
107
109
|
on_heartbeat_ack: Callable[[], None] | None
|
|
@@ -838,8 +838,9 @@ class TopicRuntimeMixin:
|
|
|
838
838
|
|
|
839
839
|
def _validate_join_hook(self, topic: TopicSubscription) -> None:
|
|
840
840
|
hook = topic.on_join_response
|
|
841
|
-
if
|
|
842
|
-
|
|
841
|
+
if hook is not None and (
|
|
842
|
+
inspect.iscoroutinefunction(hook)
|
|
843
|
+
or inspect.iscoroutinefunction(type(hook).__call__)
|
|
843
844
|
):
|
|
844
845
|
raise ChannelError("on_join_response must be synchronous")
|
|
845
846
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: phoenix-channels-python-client
|
|
3
|
-
Version: 0.5.
|
|
3
|
+
Version: 0.5.2
|
|
4
4
|
Summary: A Python client library for connecting to Phoenix Channels
|
|
5
5
|
Author: Phoenix Channels Python Client
|
|
6
6
|
License-Expression: MIT
|
|
@@ -681,7 +681,9 @@ Expiry or heartbeat send failure force-closes that socket; the supervisor handle
|
|
|
681
681
|
## Logging
|
|
682
682
|
|
|
683
683
|
The library uses loggers under `phoenix_channels_python_client`. Configure
|
|
684
|
-
logging in your application; importing the package does not configure it
|
|
684
|
+
logging in your application; importing the package does not configure it.
|
|
685
|
+
Connection log lines show `<omitted>` in place of values that may carry personal
|
|
686
|
+
data (see [Authentication and diagnostic safety](#authentication-and-diagnostic-safety)):
|
|
685
687
|
|
|
686
688
|
```python
|
|
687
689
|
import logging
|
|
@@ -736,10 +738,12 @@ exception objects, or socket metadata. `client.redact_diagnostic(text)` applies
|
|
|
736
738
|
the credential policy to transport errors a caller needs to retain. Caller-visible
|
|
737
739
|
errors may still contain personal data and should not be logged outside this policy.
|
|
738
740
|
|
|
739
|
-
Connection diagnostics omit dynamic
|
|
740
|
-
headers, frame bodies, user/topic identities, and untrusted server error
|
|
741
|
-
|
|
742
|
-
|
|
741
|
+
Connection diagnostics omit dynamic values and transport payloads, including URLs,
|
|
742
|
+
headers, frame bodies, user/topic identities, numbers, and untrusted server error
|
|
743
|
+
details. Each omitted value appears as `<omitted>`, for example
|
|
744
|
+
`No handler found for event <omitted> on topic <omitted>`. Logs retain static
|
|
745
|
+
lifecycle descriptions, enum values such as connection states, booleans, and
|
|
746
|
+
exception types. Application data and caller-visible errors are not changed;
|
|
743
747
|
applications remain responsible for logs outside this connection-owned boundary.
|
|
744
748
|
|
|
745
749
|
---
|
|
@@ -91,7 +91,7 @@ async def test_a_crashed_channel_rejoins_on_the_live_socket(
|
|
|
91
91
|
assert (await expect_message(received)).event == EVENT
|
|
92
92
|
assert reconnects.count == 0
|
|
93
93
|
|
|
94
|
-
assert "Recovered channel for topic
|
|
94
|
+
assert "Recovered channel for topic <omitted>" in caplog.text
|
|
95
95
|
|
|
96
96
|
|
|
97
97
|
@each_protocol
|
|
@@ -178,7 +178,7 @@ async def test_a_rejected_channel_rejoin_loses_the_topic(
|
|
|
178
178
|
lost.only_error()
|
|
179
179
|
assert TOPIC not in client.topic_subscriptions.copy()
|
|
180
180
|
assert joins(phoenix_server) == REJOINED_ONCE
|
|
181
|
-
assert "Lost topic
|
|
181
|
+
assert "Lost topic <omitted>" in caplog.text
|
|
182
182
|
|
|
183
183
|
|
|
184
184
|
@each_protocol
|
{phoenix_channels_python_client-0.5.1 → phoenix_channels_python_client-0.5.2}/tests/test_security.py
RENAMED
|
@@ -15,6 +15,7 @@ from phoenix_channels_python_client import Client
|
|
|
15
15
|
from phoenix_channels_python_client.client_types import ReconnectPolicy
|
|
16
16
|
from phoenix_channels_python_client.diagnostics import ConnectionLogger
|
|
17
17
|
from phoenix_channels_python_client.exceptions import SocketError
|
|
18
|
+
from phoenix_channels_python_client.messages import SystemEvent
|
|
18
19
|
from tests.fake_server import FakePhoenixServer
|
|
19
20
|
|
|
20
21
|
URL_CREDENTIAL = "url/private+ credential?x=1&z=#[]"
|
|
@@ -199,6 +200,45 @@ class TestConnectionSecurity:
|
|
|
199
200
|
target.disabled = previous_disabled
|
|
200
201
|
target.removeFilter(reject)
|
|
201
202
|
|
|
203
|
+
@pytest.mark.parametrize(
|
|
204
|
+
("message", "args", "rendered"),
|
|
205
|
+
[
|
|
206
|
+
(
|
|
207
|
+
"No handler found for event %s on topic %s",
|
|
208
|
+
("user_join", "room:42"),
|
|
209
|
+
"No handler found for event <omitted> on topic <omitted>",
|
|
210
|
+
),
|
|
211
|
+
(
|
|
212
|
+
"Channel %s is %s after %d attempts",
|
|
213
|
+
(SystemEvent.join, True, 3),
|
|
214
|
+
"Channel phx_join is True after <omitted> attempts",
|
|
215
|
+
),
|
|
216
|
+
("100%% of %s", ("room:42",), "100% of <omitted>"),
|
|
217
|
+
("%s and %s", ("only-one",), "<omitted> and <omitted>"),
|
|
218
|
+
("%d with text", ("not-a-number",), "<omitted> with text"),
|
|
219
|
+
("%(topic)s by name", ({"topic": "room:42"},), "<omitted> by name"),
|
|
220
|
+
],
|
|
221
|
+
ids=[
|
|
222
|
+
"strings",
|
|
223
|
+
"enum-bool-number",
|
|
224
|
+
"escape",
|
|
225
|
+
"too-few",
|
|
226
|
+
"type-mismatch",
|
|
227
|
+
"mapping",
|
|
228
|
+
],
|
|
229
|
+
)
|
|
230
|
+
def test_placeholders_render_without_exposing_arguments(
|
|
231
|
+
self, message: str, args: tuple[object, ...], rendered: str
|
|
232
|
+
) -> None:
|
|
233
|
+
client = Client("ws://127.0.0.1:1/socket", api_key="synthetic-key")
|
|
234
|
+
collector = BufferingHandler(10)
|
|
235
|
+
client.logger.addHandler(collector)
|
|
236
|
+
client.logger.setLevel(logging.WARNING)
|
|
237
|
+
|
|
238
|
+
client.logger.warning(message, *args)
|
|
239
|
+
|
|
240
|
+
assert [record.getMessage() for record in collector.buffer] == [rendered]
|
|
241
|
+
|
|
202
242
|
@pytest.mark.parametrize(
|
|
203
243
|
"header_names",
|
|
204
244
|
[
|
|
@@ -395,6 +435,9 @@ class TestConnectionSecurity:
|
|
|
395
435
|
"Parsing raw message:" in record.getMessage() for record in collector.buffer
|
|
396
436
|
)
|
|
397
437
|
assert any("OPEN" in record.getMessage() for record in collector.buffer)
|
|
438
|
+
messages = [record.getMessage() for record in collector.buffer]
|
|
439
|
+
assert "Connection callback failed: <omitted> [RuntimeError]" in messages
|
|
440
|
+
assert "Untrusted numeric identity: <omitted> <omitted> <omitted>" in messages
|
|
398
441
|
for record in collector.buffer:
|
|
399
442
|
assert identity not in repr(record.__dict__)
|
|
400
443
|
assert session not in repr(record.__dict__)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{phoenix_channels_python_client-0.5.1 → phoenix_channels_python_client-0.5.2}/tests/test_binary.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{phoenix_channels_python_client-0.5.1 → phoenix_channels_python_client-0.5.2}/tests/test_codec.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{phoenix_channels_python_client-0.5.1 → phoenix_channels_python_client-0.5.2}/tests/test_push.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|