wandb 0.21.0__py3-none-win32.whl → 0.21.2__py3-none-win32.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (153) hide show
  1. wandb/__init__.py +16 -14
  2. wandb/__init__.pyi +427 -450
  3. wandb/agents/pyagent.py +41 -12
  4. wandb/analytics/sentry.py +7 -2
  5. wandb/apis/importers/mlflow.py +1 -1
  6. wandb/apis/public/__init__.py +1 -1
  7. wandb/apis/public/api.py +525 -360
  8. wandb/apis/public/artifacts.py +207 -13
  9. wandb/apis/public/automations.py +19 -3
  10. wandb/apis/public/files.py +172 -33
  11. wandb/apis/public/history.py +67 -15
  12. wandb/apis/public/integrations.py +25 -2
  13. wandb/apis/public/jobs.py +90 -2
  14. wandb/apis/public/projects.py +130 -79
  15. wandb/apis/public/query_generator.py +11 -1
  16. wandb/apis/public/registries/_utils.py +14 -16
  17. wandb/apis/public/registries/registries_search.py +183 -304
  18. wandb/apis/public/reports.py +96 -15
  19. wandb/apis/public/runs.py +299 -105
  20. wandb/apis/public/sweeps.py +222 -22
  21. wandb/apis/public/teams.py +41 -4
  22. wandb/apis/public/users.py +45 -4
  23. wandb/automations/_generated/delete_automation.py +1 -3
  24. wandb/automations/_generated/enums.py +13 -11
  25. wandb/beta/workflows.py +66 -30
  26. wandb/bin/gpu_stats.exe +0 -0
  27. wandb/bin/wandb-core +0 -0
  28. wandb/cli/cli.py +127 -3
  29. wandb/env.py +8 -0
  30. wandb/errors/errors.py +4 -1
  31. wandb/integration/lightning/fabric/logger.py +3 -4
  32. wandb/integration/metaflow/__init__.py +6 -0
  33. wandb/integration/metaflow/data_pandas.py +74 -0
  34. wandb/integration/metaflow/data_pytorch.py +75 -0
  35. wandb/integration/metaflow/data_sklearn.py +76 -0
  36. wandb/integration/metaflow/errors.py +13 -0
  37. wandb/integration/metaflow/metaflow.py +167 -223
  38. wandb/integration/openai/fine_tuning.py +1 -2
  39. wandb/integration/weave/__init__.py +6 -0
  40. wandb/integration/weave/interface.py +49 -0
  41. wandb/integration/weave/weave.py +63 -0
  42. wandb/jupyter.py +5 -5
  43. wandb/plot/custom_chart.py +30 -7
  44. wandb/proto/v3/wandb_internal_pb2.py +281 -280
  45. wandb/proto/v3/wandb_telemetry_pb2.py +4 -4
  46. wandb/proto/v4/wandb_internal_pb2.py +280 -280
  47. wandb/proto/v4/wandb_telemetry_pb2.py +4 -4
  48. wandb/proto/v5/wandb_internal_pb2.py +280 -280
  49. wandb/proto/v5/wandb_telemetry_pb2.py +4 -4
  50. wandb/proto/v6/wandb_internal_pb2.py +280 -280
  51. wandb/proto/v6/wandb_telemetry_pb2.py +4 -4
  52. wandb/proto/wandb_deprecated.py +6 -0
  53. wandb/sdk/artifacts/_factories.py +17 -0
  54. wandb/sdk/artifacts/_generated/__init__.py +221 -13
  55. wandb/sdk/artifacts/_generated/artifact_by_id.py +17 -0
  56. wandb/sdk/artifacts/_generated/artifact_by_name.py +22 -0
  57. wandb/sdk/artifacts/_generated/artifact_collection_membership_file_urls.py +43 -0
  58. wandb/sdk/artifacts/_generated/artifact_created_by.py +47 -0
  59. wandb/sdk/artifacts/_generated/artifact_file_urls.py +22 -0
  60. wandb/sdk/artifacts/_generated/artifact_type.py +31 -0
  61. wandb/sdk/artifacts/_generated/artifact_used_by.py +43 -0
  62. wandb/sdk/artifacts/_generated/artifact_via_membership_by_name.py +26 -0
  63. wandb/sdk/artifacts/_generated/delete_artifact.py +28 -0
  64. wandb/sdk/artifacts/_generated/enums.py +5 -0
  65. wandb/sdk/artifacts/_generated/fetch_artifact_manifest.py +38 -0
  66. wandb/sdk/artifacts/_generated/fetch_registries.py +32 -0
  67. wandb/sdk/artifacts/_generated/fragments.py +279 -41
  68. wandb/sdk/artifacts/_generated/link_artifact.py +6 -0
  69. wandb/sdk/artifacts/_generated/operations.py +654 -51
  70. wandb/sdk/artifacts/_generated/registry_collections.py +34 -0
  71. wandb/sdk/artifacts/_generated/registry_versions.py +34 -0
  72. wandb/sdk/artifacts/_generated/unlink_artifact.py +25 -0
  73. wandb/sdk/artifacts/_graphql_fragments.py +3 -86
  74. wandb/sdk/artifacts/_internal_artifact.py +19 -8
  75. wandb/sdk/artifacts/_validators.py +14 -4
  76. wandb/sdk/artifacts/artifact.py +512 -618
  77. wandb/sdk/artifacts/artifact_file_cache.py +10 -6
  78. wandb/sdk/artifacts/artifact_manifest.py +10 -9
  79. wandb/sdk/artifacts/artifact_manifest_entry.py +9 -10
  80. wandb/sdk/artifacts/artifact_manifests/artifact_manifest_v1.py +5 -3
  81. wandb/sdk/artifacts/storage_handlers/http_handler.py +1 -1
  82. wandb/sdk/artifacts/storage_handlers/s3_handler.py +1 -1
  83. wandb/sdk/artifacts/storage_policies/wandb_storage_policy.py +1 -1
  84. wandb/sdk/data_types/audio.py +38 -10
  85. wandb/sdk/data_types/base_types/media.py +6 -56
  86. wandb/sdk/data_types/graph.py +48 -14
  87. wandb/sdk/data_types/helper_types/bounding_boxes_2d.py +1 -3
  88. wandb/sdk/data_types/helper_types/image_mask.py +1 -3
  89. wandb/sdk/data_types/histogram.py +34 -21
  90. wandb/sdk/data_types/html.py +35 -12
  91. wandb/sdk/data_types/image.py +104 -68
  92. wandb/sdk/data_types/molecule.py +32 -19
  93. wandb/sdk/data_types/object_3d.py +36 -17
  94. wandb/sdk/data_types/plotly.py +18 -5
  95. wandb/sdk/data_types/saved_model.py +4 -6
  96. wandb/sdk/data_types/table.py +59 -30
  97. wandb/sdk/data_types/video.py +53 -26
  98. wandb/sdk/integration_utils/auto_logging.py +2 -2
  99. wandb/sdk/interface/interface_queue.py +1 -4
  100. wandb/sdk/interface/interface_shared.py +26 -37
  101. wandb/sdk/interface/interface_sock.py +24 -14
  102. wandb/sdk/internal/internal_api.py +6 -0
  103. wandb/sdk/internal/job_builder.py +6 -0
  104. wandb/sdk/internal/settings_static.py +2 -3
  105. wandb/sdk/launch/agent/agent.py +8 -1
  106. wandb/sdk/launch/agent/run_queue_item_file_saver.py +2 -2
  107. wandb/sdk/launch/create_job.py +15 -2
  108. wandb/sdk/launch/inputs/internal.py +3 -4
  109. wandb/sdk/launch/inputs/schema.py +1 -0
  110. wandb/sdk/launch/runner/kubernetes_monitor.py +1 -0
  111. wandb/sdk/launch/runner/kubernetes_runner.py +323 -1
  112. wandb/sdk/launch/sweeps/scheduler.py +2 -3
  113. wandb/sdk/lib/asyncio_compat.py +19 -16
  114. wandb/sdk/lib/asyncio_manager.py +252 -0
  115. wandb/sdk/lib/deprecate.py +1 -7
  116. wandb/sdk/lib/disabled.py +1 -1
  117. wandb/sdk/lib/hashutil.py +27 -5
  118. wandb/sdk/lib/module.py +7 -13
  119. wandb/sdk/lib/printer.py +2 -2
  120. wandb/sdk/lib/printer_asyncio.py +3 -1
  121. wandb/sdk/lib/progress.py +0 -19
  122. wandb/sdk/lib/retry.py +185 -78
  123. wandb/sdk/lib/service/service_client.py +106 -0
  124. wandb/sdk/lib/service/service_connection.py +20 -26
  125. wandb/sdk/lib/service/service_token.py +30 -13
  126. wandb/sdk/mailbox/mailbox.py +13 -5
  127. wandb/sdk/mailbox/mailbox_handle.py +22 -13
  128. wandb/sdk/mailbox/response_handle.py +42 -106
  129. wandb/sdk/mailbox/wait_with_progress.py +7 -42
  130. wandb/sdk/wandb_init.py +77 -116
  131. wandb/sdk/wandb_login.py +19 -15
  132. wandb/sdk/wandb_metric.py +2 -0
  133. wandb/sdk/wandb_run.py +497 -469
  134. wandb/sdk/wandb_settings.py +145 -4
  135. wandb/sdk/wandb_setup.py +204 -124
  136. wandb/sdk/wandb_sweep.py +14 -13
  137. wandb/sdk/wandb_watch.py +4 -6
  138. wandb/sync/sync.py +10 -0
  139. wandb/util.py +58 -1
  140. wandb/wandb_run.py +1 -2
  141. {wandb-0.21.0.dist-info → wandb-0.21.2.dist-info}/METADATA +1 -1
  142. {wandb-0.21.0.dist-info → wandb-0.21.2.dist-info}/RECORD +145 -129
  143. wandb/sdk/interface/interface_relay.py +0 -38
  144. wandb/sdk/interface/router.py +0 -89
  145. wandb/sdk/interface/router_queue.py +0 -43
  146. wandb/sdk/interface/router_relay.py +0 -50
  147. wandb/sdk/interface/router_sock.py +0 -32
  148. wandb/sdk/lib/sock_client.py +0 -236
  149. wandb/vendor/pynvml/__init__.py +0 -0
  150. wandb/vendor/pynvml/pynvml.py +0 -4779
  151. {wandb-0.21.0.dist-info → wandb-0.21.2.dist-info}/WHEEL +0 -0
  152. {wandb-0.21.0.dist-info → wandb-0.21.2.dist-info}/entry_points.txt +0 -0
  153. {wandb-0.21.0.dist-info → wandb-0.21.2.dist-info}/licenses/LICENSE +0 -0
@@ -1,38 +0,0 @@
1
- """InterfaceRelay - Derived from InterfaceQueue using RelayRouter to preserve uuid req/resp.
2
-
3
- See interface.py for how interface classes relate to each other.
4
- """
5
-
6
- from __future__ import annotations
7
-
8
- import logging
9
- from typing import TYPE_CHECKING
10
-
11
- from wandb.proto import wandb_internal_pb2 as pb
12
- from wandb.sdk.mailbox import Mailbox
13
-
14
- from .interface_queue import InterfaceQueue
15
-
16
- if TYPE_CHECKING:
17
- from queue import Queue
18
-
19
-
20
- logger = logging.getLogger("wandb")
21
-
22
-
23
- class InterfaceRelay(InterfaceQueue):
24
- _mailbox: Mailbox
25
-
26
- def __init__(
27
- self,
28
- mailbox: Mailbox,
29
- record_q: Queue[pb.Record],
30
- result_q: Queue[pb.Result],
31
- relay_q: Queue[pb.Result],
32
- ) -> None:
33
- self.relay_q = relay_q
34
- super().__init__(
35
- record_q=record_q,
36
- result_q=result_q,
37
- mailbox=mailbox,
38
- )
@@ -1,89 +0,0 @@
1
- """Router - handle message router (base class).
2
-
3
- Router to manage responses.
4
-
5
- """
6
-
7
- from __future__ import annotations
8
-
9
- import logging
10
- import threading
11
- from abc import abstractmethod
12
- from typing import TYPE_CHECKING
13
-
14
- from wandb.proto import wandb_internal_pb2 as pb
15
- from wandb.proto import wandb_server_pb2 as spb
16
- from wandb.sdk import mailbox
17
-
18
- if TYPE_CHECKING:
19
- from queue import Queue
20
-
21
-
22
- logger = logging.getLogger("wandb")
23
-
24
-
25
- class MessageRouterClosedError(Exception):
26
- """Router has been closed."""
27
-
28
-
29
- class MessageRouter:
30
- _request_queue: Queue[pb.Record]
31
- _response_queue: Queue[pb.Result]
32
- _mailbox: mailbox.Mailbox | None
33
-
34
- def __init__(self, mailbox: mailbox.Mailbox | None = None) -> None:
35
- self._mailbox = mailbox
36
- self._lock = threading.Lock()
37
-
38
- self._join_event = threading.Event()
39
- self._thread = threading.Thread(target=self.message_loop)
40
- self._thread.name = "MsgRouterThr"
41
- self._thread.daemon = True
42
- self._thread.start()
43
-
44
- @abstractmethod
45
- def _read_message(self) -> pb.Result | spb.ServerResponse | None:
46
- raise NotImplementedError
47
-
48
- @abstractmethod
49
- def _send_message(self, record: pb.Record) -> None:
50
- raise NotImplementedError
51
-
52
- def message_loop(self) -> None:
53
- try:
54
- while not self._join_event.is_set():
55
- try:
56
- msg = self._read_message()
57
- except EOFError:
58
- # On abnormal shutdown the queue will be destroyed underneath
59
- # resulting in EOFError. message_loop needs to exit..
60
- logger.warning("EOFError seen in message_loop")
61
- break
62
- except MessageRouterClosedError as e:
63
- logger.warning("message_loop has been closed", exc_info=e)
64
- break
65
- if not msg:
66
- continue
67
- self._handle_msg_rcv(msg)
68
-
69
- finally:
70
- if self._mailbox:
71
- self._mailbox.close()
72
-
73
- def join(self) -> None:
74
- self._join_event.set()
75
- self._thread.join()
76
-
77
- def _handle_msg_rcv(self, msg: pb.Result | spb.ServerResponse) -> None:
78
- if not self._mailbox:
79
- return
80
-
81
- if isinstance(msg, pb.Result) and msg.control.mailbox_slot:
82
- self._mailbox.deliver(
83
- spb.ServerResponse(
84
- request_id=msg.control.mailbox_slot,
85
- result_communicate=msg,
86
- )
87
- )
88
- elif isinstance(msg, spb.ServerResponse) and msg.request_id:
89
- self._mailbox.deliver(msg)
@@ -1,43 +0,0 @@
1
- """Router - handle message router (queue).
2
-
3
- Router to manage responses from a queue.
4
-
5
- """
6
-
7
- from __future__ import annotations
8
-
9
- import queue
10
- from typing import TYPE_CHECKING
11
-
12
- from wandb.proto import wandb_internal_pb2 as pb
13
- from wandb.sdk.mailbox import Mailbox
14
-
15
- from .router import MessageRouter
16
-
17
- if TYPE_CHECKING:
18
- from queue import Queue
19
-
20
-
21
- class MessageQueueRouter(MessageRouter):
22
- _request_queue: Queue[pb.Record]
23
- _response_queue: Queue[pb.Result]
24
-
25
- def __init__(
26
- self,
27
- request_queue: Queue[pb.Record],
28
- response_queue: Queue[pb.Result],
29
- mailbox: Mailbox | None = None,
30
- ) -> None:
31
- self._request_queue = request_queue
32
- self._response_queue = response_queue
33
- super().__init__(mailbox=mailbox)
34
-
35
- def _read_message(self) -> pb.Result | None:
36
- try:
37
- msg = self._response_queue.get(timeout=1)
38
- except queue.Empty:
39
- return None
40
- return msg
41
-
42
- def _send_message(self, record: pb.Record) -> None:
43
- self._request_queue.put(record)
@@ -1,50 +0,0 @@
1
- """Router - handle message router (relay).
2
-
3
- Router to manage responses from a queue with relay.
4
-
5
- """
6
-
7
- from __future__ import annotations
8
-
9
- from typing import TYPE_CHECKING
10
-
11
- from wandb.proto import wandb_internal_pb2 as pb
12
- from wandb.proto import wandb_server_pb2 as spb
13
- from wandb.sdk.mailbox import Mailbox
14
-
15
- from .router_queue import MessageQueueRouter
16
-
17
- if TYPE_CHECKING:
18
- from queue import Queue
19
-
20
-
21
- class MessageRelayRouter(MessageQueueRouter):
22
- _relay_queue: Queue[pb.Result]
23
-
24
- def __init__(
25
- self,
26
- request_queue: Queue[pb.Record],
27
- response_queue: Queue[pb.Result],
28
- relay_queue: Queue[pb.Result],
29
- mailbox: Mailbox,
30
- ) -> None:
31
- self._relay_queue = relay_queue
32
- super().__init__(
33
- request_queue=request_queue,
34
- response_queue=response_queue,
35
- mailbox=mailbox,
36
- )
37
-
38
- def _handle_msg_rcv(self, msg: pb.Result | spb.ServerResponse) -> None:
39
- if isinstance(msg, pb.Result):
40
- relay_msg = msg
41
- else:
42
- relay_msg = msg.result_communicate
43
-
44
- # This is legacy-service logic for returning responses to the client.
45
- # A different thread reads the "relay queue" and writes responses on
46
- # the socket.
47
- if relay_msg.control.relay_id:
48
- self._relay_queue.put(relay_msg)
49
- else:
50
- super()._handle_msg_rcv(msg)
@@ -1,32 +0,0 @@
1
- """Router - handle message router (sock).
2
-
3
- Router to manage responses from a socket client.
4
-
5
- """
6
-
7
- from __future__ import annotations
8
-
9
- from wandb.proto import wandb_internal_pb2 as pb
10
- from wandb.proto import wandb_server_pb2 as spb
11
- from wandb.sdk.lib.sock_client import SockClient, SockClientClosedError
12
- from wandb.sdk.mailbox import Mailbox
13
-
14
- from .router import MessageRouter, MessageRouterClosedError
15
-
16
-
17
- class MessageSockRouter(MessageRouter):
18
- _sock_client: SockClient
19
- _mailbox: Mailbox
20
-
21
- def __init__(self, sock_client: SockClient, mailbox: Mailbox) -> None:
22
- self._sock_client = sock_client
23
- super().__init__(mailbox=mailbox)
24
-
25
- def _read_message(self) -> spb.ServerResponse | None:
26
- try:
27
- return self._sock_client.read_server_response(timeout=1)
28
- except SockClientClosedError as e:
29
- raise MessageRouterClosedError from e
30
-
31
- def _send_message(self, record: pb.Record) -> None:
32
- self._sock_client.send_record_communicate(record)
@@ -1,236 +0,0 @@
1
- import socket
2
- import struct
3
- import threading
4
- import time
5
- import uuid
6
- from typing import TYPE_CHECKING, Any, List, Optional
7
-
8
- from wandb.proto import wandb_server_pb2 as spb
9
-
10
- if TYPE_CHECKING:
11
- from wandb.proto import wandb_internal_pb2 as pb
12
-
13
-
14
- class SockClientClosedError(Exception):
15
- """Raised on operations on a closed socket."""
16
-
17
-
18
- class SockClientTimeoutError(Exception):
19
- """Raised if the server didn't respond before the timeout."""
20
-
21
-
22
- class SockBuffer:
23
- _buf_list: List[bytes]
24
- _buf_lengths: List[int]
25
- _buf_total: int
26
-
27
- def __init__(self) -> None:
28
- self._buf_list = []
29
- self._buf_lengths = []
30
- self._buf_total = 0
31
-
32
- @property
33
- def length(self) -> int:
34
- return self._buf_total
35
-
36
- def _get(self, start: int, end: int, peek: bool = False) -> bytes:
37
- index: Optional[int] = None
38
- buffers = []
39
- need = end
40
-
41
- # compute buffers needed
42
- for i, (buf_len, buf_data) in enumerate(zip(self._buf_lengths, self._buf_list)):
43
- buffers.append(buf_data[:need] if need < buf_len else buf_data)
44
- if need <= buf_len:
45
- index = i
46
- break
47
- need -= buf_len
48
-
49
- # buffer not large enough, caller should have made sure there was enough data
50
- if index is None:
51
- raise IndexError("SockBuffer index out of range")
52
-
53
- # advance buffer internals if we are not peeking into the data
54
- if not peek:
55
- self._buf_total -= end
56
- if need < buf_len:
57
- # update partially used buffer list
58
- self._buf_list = self._buf_list[index:]
59
- self._buf_lengths = self._buf_lengths[index:]
60
- self._buf_list[0] = self._buf_list[0][need:]
61
- self._buf_lengths[0] -= need
62
- else:
63
- # update fully used buffer list
64
- self._buf_list = self._buf_list[index + 1 :]
65
- self._buf_lengths = self._buf_lengths[index + 1 :]
66
-
67
- return b"".join(buffers)[start:end]
68
-
69
- def get(self, start: int, end: int) -> bytes:
70
- return self._get(start, end)
71
-
72
- def peek(self, start: int, end: int) -> bytes:
73
- return self._get(start, end, peek=True)
74
-
75
- def put(self, data: bytes, data_len: int) -> None:
76
- self._buf_list.append(data)
77
- self._buf_lengths.append(data_len)
78
- self._buf_total += data_len
79
-
80
-
81
- class SockClient:
82
- # current header is magic byte "W" followed by 4 byte length of the message
83
- HEADLEN = 1 + 4
84
-
85
- def __init__(self, sock: socket.socket) -> None:
86
- """Create a SockClient.
87
-
88
- Args:
89
- sock: A connected socket.
90
- """
91
- self._sock = sock
92
-
93
- # TODO: use safe uuid's (python3.7+) or emulate this
94
- self._sockid = uuid.uuid4().hex
95
- self._retry_delay = 0.1
96
- self._lock = threading.Lock()
97
- self._bufsize = 4096
98
- self._buffer = SockBuffer()
99
-
100
- self._detect_bufsize()
101
-
102
- def _detect_bufsize(self) -> None:
103
- sndbuf_size = self._sock.getsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF)
104
- rcvbuf_size = self._sock.getsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF)
105
- self._bufsize = min(sndbuf_size, rcvbuf_size, 65536)
106
-
107
- def close(self) -> None:
108
- self._sock.close()
109
-
110
- def shutdown(self, val: int) -> None:
111
- self._sock.shutdown(val)
112
-
113
- def set_socket(self, sock: socket.socket) -> None:
114
- self._sock = sock
115
- self._detect_bufsize()
116
-
117
- def _sendall_with_error_handle(self, data: bytes) -> None:
118
- # This is a helper function for sending data in a retry fashion.
119
- # Similar to the sendall() function in the socket module, but with
120
- # an error handling in case of timeout.
121
- total_sent = 0
122
- total_data = len(data)
123
- while total_sent < total_data:
124
- start_time = time.monotonic()
125
- try:
126
- sent = self._sock.send(data)
127
- # sent equal to 0 indicates a closed socket
128
- if sent == 0:
129
- raise SockClientClosedError("socket connection broken")
130
- total_sent += sent
131
- # truncate our data to save memory
132
- data = data[sent:]
133
- # we handle the timeout case for the cases when timeout is set
134
- # on a system level by another application
135
- except socket.timeout:
136
- # adding sleep to avoid tight loop
137
- delta_time = time.monotonic() - start_time
138
- if delta_time < self._retry_delay:
139
- time.sleep(self._retry_delay - delta_time)
140
-
141
- def _send_message(self, msg: Any) -> None:
142
- raw_size = msg.ByteSize()
143
- data = msg.SerializeToString()
144
- assert len(data) == raw_size, "invalid serialization"
145
- header = struct.pack("<BI", ord("W"), raw_size)
146
- with self._lock:
147
- self._sendall_with_error_handle(header + data)
148
-
149
- def send_server_request(self, msg: spb.ServerRequest) -> None:
150
- self._send_message(msg)
151
-
152
- def send_server_response(self, msg: spb.ServerResponse) -> None:
153
- try:
154
- self._send_message(msg)
155
- except BrokenPipeError:
156
- # TODO(jhr): user thread might no longer be around to receive responses to
157
- # things like network status poll loop, there might be a better way to quiesce
158
- pass
159
-
160
- def send_record_communicate(self, record: "pb.Record") -> None:
161
- server_req = spb.ServerRequest()
162
- server_req.request_id = record.control.mailbox_slot
163
- server_req.record_communicate.CopyFrom(record)
164
- self.send_server_request(server_req)
165
-
166
- def send_record_publish(self, record: "pb.Record") -> None:
167
- server_req = spb.ServerRequest()
168
- server_req.request_id = record.control.mailbox_slot
169
- server_req.record_publish.CopyFrom(record)
170
- self.send_server_request(server_req)
171
-
172
- def _extract_packet_bytes(self) -> Optional[bytes]:
173
- # Do we have enough data to read the header?
174
- start_offset = self.HEADLEN
175
- if self._buffer.length >= start_offset:
176
- header = self._buffer.peek(0, start_offset)
177
- fields = struct.unpack("<BI", header)
178
- magic, dlength = fields
179
- assert magic == ord("W")
180
- # Do we have enough data to read the full record?
181
- end_offset = self.HEADLEN + dlength
182
- if self._buffer.length >= end_offset:
183
- rec_data = self._buffer.get(start_offset, end_offset)
184
- return rec_data
185
- return None
186
-
187
- def _read_packet_bytes(self, timeout: Optional[int] = None) -> Optional[bytes]:
188
- """Read full message from socket.
189
-
190
- Args:
191
- timeout: number of seconds to wait on socket data.
192
-
193
- Raises:
194
- SockClientClosedError: socket has been closed.
195
- """
196
- while True:
197
- rec = self._extract_packet_bytes()
198
- if rec:
199
- return rec
200
-
201
- if timeout:
202
- self._sock.settimeout(timeout)
203
- try:
204
- data = self._sock.recv(self._bufsize)
205
- except socket.timeout:
206
- break
207
- except OSError as e:
208
- raise SockClientClosedError from e
209
- finally:
210
- if timeout:
211
- self._sock.settimeout(None)
212
- data_len = len(data)
213
- if data_len == 0:
214
- # socket.recv() will return 0 bytes if socket was shutdown
215
- # caller will handle this condition like other connection problems
216
- raise SockClientClosedError
217
- self._buffer.put(data, data_len)
218
- return None
219
-
220
- def read_server_request(self) -> Optional[spb.ServerRequest]:
221
- data = self._read_packet_bytes()
222
- if not data:
223
- return None
224
- rec = spb.ServerRequest()
225
- rec.ParseFromString(data)
226
- return rec
227
-
228
- def read_server_response(
229
- self, timeout: Optional[int] = None
230
- ) -> Optional[spb.ServerResponse]:
231
- data = self._read_packet_bytes(timeout=timeout)
232
- if not data:
233
- return None
234
- rec = spb.ServerResponse()
235
- rec.ParseFromString(data)
236
- return rec
File without changes