@@ -101,19 +101,6 @@ def __init__(
101101 # Whether we are busy sending a fragmented message.
102102 self .send_in_progress = False
103103
104- # Exception raised in recv_events, to be chained to ConnectionClosed
105- # in the user thread in order to show why the TCP connection dropped.
106- self .recv_exc : BaseException | None = None
107-
108- # Receiving events from the socket. This thread is marked as daemon to
109- # allow creating a connection in a non-daemon thread and using it in a
110- # daemon thread. This mustn't prevent the interpreter from exiting.
111- self .recv_events_thread = threading .Thread (
112- target = self .recv_events ,
113- daemon = True ,
114- )
115- self .recv_events_thread .start ()
116-
117104 # Mapping of ping IDs to pong waiters, in chronological order.
118105 self .pong_waiters : dict [bytes , tuple [threading .Event , float , bool ]] = {}
119106
@@ -133,6 +120,21 @@ def __init__(
133120 # Thread that sends keepalive pings. None when ping_interval is None.
134121 self .keepalive_thread : threading .Thread | None = None
135122
123+ # Exception raised in recv_events, to be chained to ConnectionClosed
124+ # in the user thread in order to show why the TCP connection dropped.
125+ self .recv_exc : BaseException | None = None
126+
127+ # Receiving events from the socket. This thread is marked as daemon to
128+ # allow creating a connection in a non-daemon thread and using it in a
129+ # daemon thread. This mustn't prevent the interpreter from exiting.
130+ self .recv_events_thread = threading .Thread (
131+ target = self .recv_events ,
132+ daemon = True ,
133+ )
134+
135+ # Start recv_events only after all attributes are initialized.
136+ self .recv_events_thread .start ()
137+
136138 # Public attributes
137139
138140 @property
0 commit comments