pymammotion 0.2.43__py3-none-any.whl → 0.2.45__py3-none-any.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.
@@ -111,7 +111,6 @@ class MowingDevice(DataClassORJSONMixin):
111
111
 
112
112
  self.report_data.update(toapp_report_data.to_dict(casing=betterproto.Casing.SNAKE))
113
113
 
114
-
115
114
  def run_state_update(self, rapid_state: SystemRapidStateTunnelMsg) -> None:
116
115
  coordinate_converter = CoordinateConverter(self.location.RTK.latitude, self.location.RTK.longitude)
117
116
  self.mowing_state = RapidState().from_raw(rapid_state.rapid_state_data)
@@ -70,15 +70,13 @@ class ReportData(DataClassORJSONMixin):
70
70
  locations: list[LocationData] = field(default_factory=list)
71
71
  work: WorkData = field(default_factory=WorkData)
72
72
 
73
- def update(self, data: dict):
73
+ def update(self, data: dict) -> None:
74
74
  locations = self.locations
75
75
  if data.get("locations") is not None:
76
76
  locations = [LocationData.from_dict(loc) for loc in data.get("locations", [])]
77
77
 
78
-
79
- self.connect=ConnectData.from_dict(data.get("connect", asdict(self.connect)))
80
- self.dev=DeviceData.from_dict(data.get("dev", asdict(self.dev)))
81
- self.rtk=RTKData.from_dict(data.get("rtk", asdict(self.rtk)))
82
- self.locations=locations
83
- self.work=WorkData.from_dict(data.get("work", asdict(self.work)))
84
-
78
+ self.connect = ConnectData.from_dict(data.get("connect", asdict(self.connect)))
79
+ self.dev = DeviceData.from_dict(data.get("dev", asdict(self.dev)))
80
+ self.rtk = RTKData.from_dict(data.get("rtk", asdict(self.rtk)))
81
+ self.locations = locations
82
+ self.work = WorkData.from_dict(data.get("work", asdict(self.work)))
@@ -4,7 +4,7 @@ from pymammotion.mammotion.commands.messages.network import MessageNetwork
4
4
  from pymammotion.mammotion.commands.messages.ota import MessageOta
5
5
  from pymammotion.mammotion.commands.messages.system import MessageSystem
6
6
  from pymammotion.mammotion.commands.messages.video import MessageVideo
7
- from pymammotion.proto import dev_net_pb2, luba_msg_pb2
7
+ from pymammotion.utility.movement import get_percent, transform_both_speeds
8
8
 
9
9
 
10
10
  class MammotionCommand(MessageSystem, MessageNavigation, MessageNetwork, MessageOta, MessageVideo, MessageDriver):
@@ -23,3 +23,27 @@ class MammotionCommand(MessageSystem, MessageNavigation, MessageNetwork, Message
23
23
 
24
24
  def set_device_product_key(self, product_key: str) -> None:
25
25
  self._product_key = product_key
26
+
27
+ def move_forward(self, linear: float) -> None:
28
+ """Move forward. values 0.0 1.0."""
29
+ linear_percent = get_percent(abs(linear * 100))
30
+ (linear_speed, angular_speed) = transform_both_speeds(90.0, 0.0, linear_percent, 0.0)
31
+ self.send_movement(linear_speed=linear_speed, angular_speed=angular_speed)
32
+
33
+ def move_back(self, linear: float) -> None:
34
+ """Move back. values 0.0 1.0."""
35
+ linear_percent = get_percent(abs(linear * 100))
36
+ (linear_speed, angular_speed) = transform_both_speeds(270.0, 0.0, linear_percent, 0.0)
37
+ self.send_movement(linear_speed=linear_speed, angular_speed=angular_speed)
38
+
39
+ def move_left(self, angular: float) -> None:
40
+ """Move forward. values 0.0 1.0."""
41
+ angular_percent = get_percent(abs(angular * 100))
42
+ (linear_speed, angular_speed) = transform_both_speeds(0.0, 0.0, 0.0, angular_percent)
43
+ self.send_movement(linear_speed=linear_speed, angular_speed=angular_speed)
44
+
45
+ def move_right(self, angular: float) -> None:
46
+ """Move back. values 0.0 1.0."""
47
+ angular_percent = get_percent(abs(angular * 100))
48
+ (linear_speed, angular_speed) = transform_both_speeds(0.0, 180.0, 0.0, angular_percent)
49
+ self.send_movement(linear_speed=linear_speed, angular_speed=angular_speed)
@@ -12,7 +12,6 @@ from pymammotion.data.state_manager import StateManager
12
12
  from pymammotion.proto import has_field
13
13
  from pymammotion.proto.luba_msg import LubaMsg
14
14
  from pymammotion.proto.mctrl_nav import NavGetCommDataAck, NavGetHashListAck
15
- from pymammotion.utility.movement import get_percent, transform_both_speeds
16
15
 
17
16
  _LOGGER = logging.getLogger(__name__)
18
17
 
@@ -35,7 +34,6 @@ def find_next_integer(lst: list[int], current_hash: int) -> int | None:
35
34
  class MammotionBaseDevice:
36
35
  """Base class for Mammotion devices."""
37
36
 
38
- _mower: MowingDevice
39
37
  _state_manager: StateManager
40
38
  _cloud_device: Device | None = None
41
39
 
@@ -43,8 +41,7 @@ class MammotionBaseDevice:
43
41
  """Initialize MammotionBaseDevice."""
44
42
  self.loop = asyncio.get_event_loop()
45
43
  self._raw_data = LubaMsg().to_dict(casing=betterproto.Casing.SNAKE)
46
- self._mower = device
47
- self._state_manager = StateManager(self._mower)
44
+ self._state_manager = StateManager(device)
48
45
  self._state_manager.gethash_ack_callback = self.datahash_response
49
46
  self._state_manager.get_commondata_ack_callback = self.commdata_response
50
47
  self._notify_future: asyncio.Future[bytes] | None = None
@@ -65,11 +62,11 @@ class MammotionBaseDevice:
65
62
  total_frame = common_data.total_frame
66
63
  current_frame = common_data.current_frame
67
64
 
68
- missing_frames = self._mower.map.missing_frame(common_data)
65
+ missing_frames = self.mower.map.missing_frame(common_data)
69
66
  if len(missing_frames) == 0:
70
67
  # get next in hash ack list
71
68
 
72
- data_hash = find_next_integer(self._mower.nav.toapp_gethash_ack.data_couple, common_data.hash)
69
+ data_hash = find_next_integer(self.mower.nav.toapp_gethash_ack.data_couple, common_data.hash)
73
70
  if data_hash is None:
74
71
  return
75
72
 
@@ -104,7 +101,7 @@ class MammotionBaseDevice:
104
101
  case "ota":
105
102
  self._update_ota_data(tmp_msg)
106
103
 
107
- self._mower.update_raw(self._raw_data)
104
+ self.mower.update_raw(self._raw_data)
108
105
 
109
106
  def _update_nav_data(self, tmp_msg) -> None:
110
107
  """Update navigation data."""
@@ -180,7 +177,7 @@ class MammotionBaseDevice:
180
177
  @property
181
178
  def mower(self) -> MowingDevice:
182
179
  """Get the LubaMsg of the device."""
183
- return self._mower
180
+ return self._state_manager.get_device()
184
181
 
185
182
  @abstractmethod
186
183
  async def queue_command(self, key: str, **kwargs: any) -> bytes | None:
@@ -207,7 +204,7 @@ class MammotionBaseDevice:
207
204
  try:
208
205
  # work out why this crashes sometimes for better proto
209
206
 
210
- if self._cloud_device and len(self._mower.map.area_name) == 0:
207
+ if self._cloud_device and len(self.mower.map.area_name) == 0:
211
208
  await self.queue_command("get_area_name_list", device_id=self._cloud_device.iotId)
212
209
  except Exception:
213
210
  """Do nothing for now."""
@@ -231,30 +228,10 @@ class MammotionBaseDevice:
231
228
  await self.queue_command("allpowerfull_rw", id=5, rw=1, context=2)
232
229
  await self.queue_command("allpowerfull_rw", id=5, rw=1, context=3)
233
230
 
234
- async def move_forward(self, linear: float) -> None:
235
- """Move forward. values 0.0 1.0."""
236
- linear_percent = get_percent(abs(linear * 100))
237
- (linear_speed, angular_speed) = transform_both_speeds(90.0, 0.0, linear_percent, 0.0)
238
- await self.queue_command("send_movement", linear_speed=linear_speed, angular_speed=angular_speed)
239
-
240
- async def move_back(self, linear: float) -> None:
241
- """Move back. values 0.0 1.0."""
242
- linear_percent = get_percent(abs(linear * 100))
243
- (linear_speed, angular_speed) = transform_both_speeds(270.0, 0.0, linear_percent, 0.0)
244
- await self.queue_command("send_movement", linear_speed=linear_speed, angular_speed=angular_speed)
245
-
246
- async def move_left(self, angulur: float) -> None:
247
- """Move forward. values 0.0 1.0."""
248
- angular_percent = get_percent(abs(angulur * 100))
249
- (linear_speed, angular_speed) = transform_both_speeds(0.0, 0.0, 0.0, angular_percent)
250
- await self.queue_command("send_movement", linear_speed=linear_speed, angular_speed=angular_speed)
251
-
252
- async def move_right(self, angulur: float) -> None:
253
- """Move back. values 0.0 1.0."""
254
- angular_percent = get_percent(abs(angulur * 100))
255
- (linear_speed, angular_speed) = transform_both_speeds(0.0, 180.0, 0.0, angular_percent)
256
- await self.queue_command("send_movement", linear_speed=linear_speed, angular_speed=angular_speed)
257
-
258
231
  async def command(self, key: str, **kwargs):
259
232
  """Send a command to the device."""
260
233
  return await self.queue_command(key, **kwargs)
234
+
235
+ @property
236
+ def state_manager(self):
237
+ return self._state_manager
@@ -35,7 +35,6 @@ class ConnectionPreference(Enum):
35
35
  class MammotionMixedDeviceManager:
36
36
  _ble_device: MammotionBaseBLEDevice | None = None
37
37
  _cloud_device: MammotionBaseCloudDevice | None = None
38
- _mowing_state: MowingDevice
39
38
  preference: ConnectionPreference
40
39
 
41
40
  def __init__(
@@ -46,15 +45,25 @@ class MammotionMixedDeviceManager:
46
45
  mqtt: MammotionCloud | None = None,
47
46
  preference: ConnectionPreference = ConnectionPreference.BLUETOOTH,
48
47
  ) -> None:
48
+ self._mower_state = None
49
49
  self.name = name
50
50
  self._mowing_state = MowingDevice()
51
51
  self.add_ble(ble_device)
52
52
  self.add_cloud(cloud_device, mqtt)
53
53
  self.preference = preference
54
54
 
55
+ @property
55
56
  def mower_state(self):
56
57
  return self._mowing_state
57
58
 
59
+ @mower_state.setter
60
+ def mower_state(self, value: MowingDevice) -> None:
61
+ if self._cloud_device:
62
+ self._cloud_device.state_manager.set_device(value)
63
+ if self._ble_device:
64
+ self._ble_device.state_manager.set_device(value)
65
+ self._mowing_state = value
66
+
58
67
  def ble(self) -> MammotionBaseBLEDevice | None:
59
68
  return self._ble_device
60
69
 
@@ -63,12 +72,12 @@ class MammotionMixedDeviceManager:
63
72
 
64
73
  def add_ble(self, ble_device: BLEDevice) -> None:
65
74
  if ble_device is not None:
66
- self._ble_device = MammotionBaseBLEDevice(self._mowing_state, ble_device)
75
+ self._ble_device = MammotionBaseBLEDevice(self.mower_state, ble_device)
67
76
 
68
77
  def add_cloud(self, cloud_device: Device | None = None, mqtt: MammotionCloud | None = None) -> None:
69
78
  if cloud_device is not None:
70
79
  self._cloud_device = MammotionBaseCloudDevice(
71
- mqtt, cloud_device=cloud_device, mowing_state=self._mowing_state
80
+ mqtt, cloud_device=cloud_device, mowing_state=self.mower_state
72
81
  )
73
82
 
74
83
  def replace_cloud(self, cloud_device: MammotionBaseCloudDevice) -> None:
@@ -284,13 +293,13 @@ class Mammotion:
284
293
 
285
294
  async def get_stream_subscription(self, name: str):
286
295
  device = self.get_device_by_name(name)
287
- if self._preference is ConnectionPreference.WIFI:
296
+ if device.preference is ConnectionPreference.WIFI:
288
297
  if device.has_cloud():
289
- _stream_response = await self.cloud().cloud_client.get_stream_subscription(device.cloud().iot_id)
298
+ _stream_response = await device.cloud().mqtt.cloud_client.get_stream_subscription(device.cloud().iot_id)
290
299
  _LOGGER.debug(_stream_response)
291
300
  return _stream_response
292
301
 
293
302
  def mower(self, name: str):
294
303
  device = self.get_device_by_name(name)
295
304
  if device:
296
- return device.mower_state()
305
+ return device.mower_state
@@ -77,7 +77,6 @@ class MammotionBaseBLEDevice(MammotionBaseDevice):
77
77
  self._prev_notification = None
78
78
  self._interface = f"hci{interface}"
79
79
  self._device = device
80
- self._mower = mowing_state
81
80
  self._client: BleakClientWithServiceCache | None = None
82
81
  self._read_char: BleakGATTCharacteristic | int | str | UUID = 0
83
82
  self._write_char: BleakGATTCharacteristic | int | str | UUID = 0
@@ -191,7 +190,7 @@ class MammotionBaseBLEDevice(MammotionBaseDevice):
191
190
  def rssi(self) -> int:
192
191
  """Return RSSI of device."""
193
192
  try:
194
- return cast(self._mower.sys.toapp_report_data.connect.ble_rssi, int)
193
+ return cast(self.mower.sys.toapp_report_data.connect.ble_rssi, int)
195
194
  finally:
196
195
  return 0
197
196
 
@@ -155,7 +155,6 @@ class MammotionBaseCloudDevice(MammotionBaseDevice):
155
155
  self._mqtt = mqtt
156
156
  self.iot_id = cloud_device.iotId
157
157
  self.device = cloud_device
158
- self._mower = mowing_state
159
158
  self._command_futures = {}
160
159
  self._commands: MammotionCommand = MammotionCommand(cloud_device.deviceName)
161
160
  self.currentID = ""
@@ -92,8 +92,6 @@ class MammotionMQTT:
92
92
  """Disconnect from MQTT Server."""
93
93
  logger.info("Disconnecting...")
94
94
 
95
-
96
-
97
95
  self._linkkit_client.disconnect()
98
96
 
99
97
  def _thing_on_thing_enable(self, user_data) -> None:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pymammotion
3
- Version: 0.2.43
3
+ Version: 0.2.45
4
4
  Summary:
5
5
  License: GNU-3.0
6
6
  Author: Michael Arthur
@@ -22,7 +22,7 @@ pymammotion/const.py,sha256=lWRxvTVdXnNHuxqvRkjO5ziK0Ic-fZMM6J2dbe5M6Nc,385
22
22
  pymammotion/data/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
23
23
  pymammotion/data/model/__init__.py,sha256=aSyroxYQQS-WMRi6WmWm2js4wLa9nmsi160gx9tts4o,323
24
24
  pymammotion/data/model/account.py,sha256=vJM-KTf2q6eBfVC-UlNHBSmJvqHiCawZ40vnuhXhaz8,140
25
- pymammotion/data/model/device.py,sha256=s7S6Nicuk3acR8jxeeqZlVTZXB94DjYzo7gYdwjleUs,12071
25
+ pymammotion/data/model/device.py,sha256=s8k43ZZBTnLtvh93pcbCVRirzt8xo08Wx0xht46e-7Q,12070
26
26
  pymammotion/data/model/device_config.py,sha256=RkEbnkubJQ8nXPfZpuGPe_h9mGZGtxCxDSc8mY7UCT8,2824
27
27
  pymammotion/data/model/enums.py,sha256=EpKmO8yVUZyEnTY4yH0DMMVKYNQM42zpW1maUu0i3IE,1582
28
28
  pymammotion/data/model/excute_boarder_params.py,sha256=9CpUqrygcle1C_1hDW-riLmm4map4ZbE842NXjcomEI,1394
@@ -34,7 +34,7 @@ pymammotion/data/model/mowing_modes.py,sha256=5TrHSijUyPtIDWpNtgzx_vFQukRJWRz4gI
34
34
  pymammotion/data/model/plan.py,sha256=mcadkSL7fQXy0iJ0q786I3GEQY4i6kmQXfW6Ri69lcQ,2906
35
35
  pymammotion/data/model/rapid_state.py,sha256=mIdhAG_LZXpVcybxqTLgLXkNOmVmDTn04B9PGIDA8Ls,1251
36
36
  pymammotion/data/model/region_data.py,sha256=OTV15vRyn9JORXsQPjWMNF1ZujuNhsOKl25KeqwMObA,3007
37
- pymammotion/data/model/report_info.py,sha256=gY3L4UGEH37PS314e8d7DWuIczQxTIMfcf66xoVe0sY,2210
37
+ pymammotion/data/model/report_info.py,sha256=AE2u64uKgcJtVooldJcxXBsEHfDyCvH5DnQFUQ5qWmk,2226
38
38
  pymammotion/data/mqtt/__init__.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
39
39
  pymammotion/data/mqtt/event.py,sha256=plt53w3kHulB_MfbkxK9j7AfdQ5ahVU2s4kiQMoLio4,4612
40
40
  pymammotion/data/mqtt/properties.py,sha256=HkBPghr26L9_b4QaOi1DtPgb0UoPIOGSe9wb3kgnM6Y,2815
@@ -48,7 +48,7 @@ pymammotion/http/model/http.py,sha256=1NJP4hkBulcnpbD7Rcwltd8Ry9lnZzQVFJN8Oo7MKe
48
48
  pymammotion/mammotion/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
49
49
  pymammotion/mammotion/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
50
50
  pymammotion/mammotion/commands/abstract_message.py,sha256=nw6r7694yzl7iJKqRqhLmAPRjd_TL_Xo_-JXq2_a_ug,222
51
- pymammotion/mammotion/commands/mammotion_command.py,sha256=84XxnatnBm_5WQ_KOa2N0ltydQOhSvCme3fFqkuyEhg,1056
51
+ pymammotion/mammotion/commands/mammotion_command.py,sha256=tEAeG3FXMF-fbJGGx_NoNDMaKlxd3pmGIn5RGqxjYPY,2387
52
52
  pymammotion/mammotion/commands/messages/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
53
53
  pymammotion/mammotion/commands/messages/driver.py,sha256=ANIOEtjF23k7W_R_Yfgzxmc7p1KSBCF-l-tijUtw0Yg,3709
54
54
  pymammotion/mammotion/commands/messages/media.py,sha256=ps0l06CXy5Ej--gTNCsyKttwo7yHLVrJUpn-wNJYecs,1150
@@ -60,13 +60,13 @@ pymammotion/mammotion/commands/messages/video.py,sha256=_8lJsU4sLm2CGnc7RDkueA0A
60
60
  pymammotion/mammotion/control/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
61
61
  pymammotion/mammotion/control/joystick.py,sha256=QfBVxM_gxpWsZAGO90whtgxCI2tIZ3TTad9wHIPsU9s,5640
62
62
  pymammotion/mammotion/devices/__init__.py,sha256=f2qQFPgLGmV85W2hSlMUh5BYuht9o_Ar_JEAAMD4fsE,102
63
- pymammotion/mammotion/devices/base.py,sha256=53of3422C6g0jiKX0X4uo-eRI1Du31NA4RWLdw2O5u8,11131
64
- pymammotion/mammotion/devices/mammotion.py,sha256=od4crY_1hbBwlDt5St_IV_QT0jOT_tlKv_iplf_CTu4,11966
65
- pymammotion/mammotion/devices/mammotion_bluetooth.py,sha256=Lu8-85fBa-rGzssARqiydfQbPuIeeTcV-1ROIoYBKKM,17512
66
- pymammotion/mammotion/devices/mammotion_cloud.py,sha256=H_O3LrEOSlKm1JB8AoF5of7olyyiDhZAzD2cBXULUlo,11317
63
+ pymammotion/mammotion/devices/base.py,sha256=6g0q94h1RZDtmYEL85SsFkn1F5BegQy_WC5a9hn8kqQ,9665
64
+ pymammotion/mammotion/devices/mammotion.py,sha256=UyIPKY7XMy7zlfwKXmZetIw70bY5Ob8crhF6A-pU5Wo,12283
65
+ pymammotion/mammotion/devices/mammotion_bluetooth.py,sha256=nyO7pkKgAoRPs-28ESf6ee-y3G5JTYRO-MCp4wKPMlE,17476
66
+ pymammotion/mammotion/devices/mammotion_cloud.py,sha256=Q1Il0nCxH-8utg_9AKAY3HxuuhB78uHZV4yVpZ4k1TI,11282
67
67
  pymammotion/mqtt/__init__.py,sha256=Ocs5e-HLJvTuDpVXyECEsWIvwsUaxzj7lZ9mSYutNDY,105
68
68
  pymammotion/mqtt/mammotion_future.py,sha256=_OWqKOlUGl2yT1xOsXFQYpGd-1zQ63OxqXgy7KRQgYc,710
69
- pymammotion/mqtt/mammotion_mqtt.py,sha256=-n_GryLoyl-ioQUQRnth4syToh8MwWOj-pt2p41J0xQ,8750
69
+ pymammotion/mqtt/mammotion_mqtt.py,sha256=LaySave_hf0gU3crUTLqzpdQtxIwK8vu5DM8F8fbU2Y,8748
70
70
  pymammotion/proto/__init__.py,sha256=v3_P1LOsYRBN9qCAhaWrWMX7GWHrox9XD3hdZQxcPZM,190
71
71
  pymammotion/proto/basestation.proto,sha256=_x5gAz3FkZXS1jtq4GgZgaDCuRU-UV-7HTFdsfQ3zbo,1034
72
72
  pymammotion/proto/basestation.py,sha256=js64_N2xQYRxWPRdVNEapO0qe7vBlfYnjW5sE8hi7hw,2026
@@ -118,7 +118,7 @@ pymammotion/utility/map.py,sha256=GYscVMg2cX3IPlNpCBNHDW0S55yS1WGRf1iHnNZ7TfQ,22
118
118
  pymammotion/utility/movement.py,sha256=N75oAoAgFydqoaOedYIxGUHmuTCtPzAOtb-d_29tpfI,615
119
119
  pymammotion/utility/periodic.py,sha256=MbeSb9cfhxzYmdT_RiE0dZe3H9IfbQW_zSqhmSX2RUc,3321
120
120
  pymammotion/utility/rocker_util.py,sha256=6tX7sS87qoQC_tsxbx3NLL-HgS08wtzXiZkhDiz7uo0,7179
121
- pymammotion-0.2.43.dist-info/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
122
- pymammotion-0.2.43.dist-info/METADATA,sha256=EG9s9oLqTmk_dzxkCpAAYxrCw9XP29gH_2N3L9yL_jM,4052
123
- pymammotion-0.2.43.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
124
- pymammotion-0.2.43.dist-info/RECORD,,
121
+ pymammotion-0.2.45.dist-info/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
122
+ pymammotion-0.2.45.dist-info/METADATA,sha256=26Qrc6piAV_O7sCUmWMMfHnkZvammh7ZIAEfr2cpH2g,4052
123
+ pymammotion-0.2.45.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
124
+ pymammotion-0.2.45.dist-info/RECORD,,