Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/zmq/sugar/frame.py: 44%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

59 statements  

1"""0MQ Frame pure Python methods.""" 

2 

3# Copyright (C) PyZMQ Developers 

4# Distributed under the terms of the Modified BSD License. 

5 

6from __future__ import annotations 

7 

8from typing import Literal, overload 

9 

10import zmq 

11from zmq.backend import Frame as FrameBase 

12 

13from .attrsettr import AttributeSetter 

14 

15 

16def _draft( 

17 v: tuple[int] | tuple[int, int] | tuple[int, int, int], 

18 feature: str, 

19) -> None: 

20 zmq.error._check_version(v, feature) 

21 if not zmq.DRAFT_API: 

22 raise RuntimeError( 

23 f"libzmq and pyzmq must be built with draft support for {feature}" 

24 ) 

25 

26 

27class Frame(FrameBase, AttributeSetter): 

28 """ 

29 A zmq message Frame class for non-copying send/recvs and access to message properties. 

30 

31 A ``zmq.Frame`` wraps an underlying ``zmq_msg_t``. 

32 

33 Message *properties* can be accessed by treating a Frame like a dictionary (``frame["User-Id"]``). 

34 

35 .. versionadded:: 14.4, libzmq 4 

36 

37 Frames created by ``recv(copy=False)`` can be used to access message properties and attributes, 

38 such as the CURVE User-Id. 

39 

40 For example:: 

41 

42 frames = socket.recv_multipart(copy=False) 

43 user_id = frames[0]["User-Id"] 

44 

45 This class is used if you want to do non-copying send and recvs. 

46 When you pass a chunk of bytes to this class, e.g. ``Frame(buf)``, the 

47 ref-count of `buf` is increased by two: once because the Frame saves `buf` as 

48 an instance attribute and another because a ZMQ message is created that 

49 points to the buffer of `buf`. This second ref-count increase makes sure 

50 that `buf` lives until all messages that use it have been sent. 

51 Once 0MQ sends all the messages and it doesn't need the buffer of ``buf``, 

52 0MQ will call ``Py_DECREF(s)``. 

53 

54 Parameters 

55 ---------- 

56 

57 data : object, optional 

58 any object that provides the buffer interface will be used to 

59 construct the 0MQ message data. 

60 track : bool 

61 whether a MessageTracker_ should be created to track this object. 

62 Tracking a message has a cost at creation, because it creates a threadsafe 

63 Event object. 

64 copy : bool 

65 default: use copy_threshold 

66 Whether to create a copy of the data to pass to libzmq 

67 or share the memory with libzmq. 

68 If unspecified, copy_threshold is used. 

69 copy_threshold: int 

70 default: :const:`zmq.COPY_THRESHOLD` 

71 If copy is unspecified, messages smaller than this many bytes 

72 will be copied and messages larger than this will be shared with libzmq. 

73 """ 

74 

75 @overload 

76 def __getitem__(self, key: int | Literal["routing_id"]) -> int: ... 

77 @overload 

78 def __getitem__(self, key: bytes | Literal["group"]) -> str: ... 

79 @overload 

80 def __getitem__(self, key: str) -> int | str: ... 

81 def __getitem__(self, key: int | str | bytes) -> int | str: 

82 # map Frame['User-Id'] to Frame.get('User-Id') 

83 return self.get(key) 

84 

85 def __repr__(self) -> str: 

86 """Return the str form of the message.""" 

87 nbytes = len(self) 

88 msg_suffix = "" 

89 if nbytes > 16: 

90 msg_bytes = bytes(memoryview(self.buffer)[:12]) 

91 if nbytes >= 1e9: 

92 unit = "GB" 

93 n = nbytes // 1e9 

94 elif nbytes >= 2**20: 

95 unit = "MB" 

96 n = nbytes // 1e6 

97 elif nbytes >= 1e3: 

98 unit = "kB" 

99 n = nbytes // 1e3 

100 else: 

101 unit = "B" 

102 n = nbytes 

103 msg_suffix = f'...{n:.0f}{unit}' 

104 else: 

105 msg_bytes = self.bytes 

106 

107 _module = self.__class__.__module__ 

108 if _module == "zmq.sugar.frame": 

109 _module = "zmq" 

110 return f"<{_module}.{self.__class__.__name__}({msg_bytes!r}{msg_suffix})>" 

111 

112 @property 

113 def group(self) -> str: 

114 """The RADIO-DISH group of the message. 

115 

116 Requires libzmq >= 4.2 and pyzmq built with draft APIs enabled. 

117 

118 .. versionadded:: 17 

119 """ 

120 _draft((4, 2), "RADIO-DISH") 

121 return self.get('group') 

122 

123 @group.setter 

124 def group(self, group: str | bytes) -> None: 

125 _draft((4, 2), "RADIO-DISH") 

126 self.set('group', group) 

127 

128 @property 

129 def routing_id(self) -> int: 

130 """The CLIENT-SERVER routing id of the message. 

131 

132 Requires libzmq >= 4.2 and pyzmq built with draft APIs enabled. 

133 

134 .. versionadded:: 17 

135 """ 

136 _draft((4, 2), "CLIENT-SERVER") 

137 return self.get('routing_id') 

138 

139 @routing_id.setter 

140 def routing_id(self, routing_id: int) -> None: 

141 _draft((4, 2), "CLIENT-SERVER") 

142 self.set('routing_id', routing_id) 

143 

144 

145# keep deprecated alias 

146Message = Frame 

147 

148__all__ = ['Frame', 'Message']