indipyclient 0.2.2__tar.gz → 0.2.4__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: indipyclient
3
- Version: 0.2.2
3
+ Version: 0.2.4
4
4
  Summary: Pure python package, providing a terminal client and a set of classes which can be used to create scripts or clients to control remote instruments using the INDI protocol.
5
5
  Keywords: indi,client,astronomy,instrument
6
6
  Author-email: Bernard Czenkusz <bernie@skipole.co.uk>
@@ -6,4 +6,4 @@ from .events import (delProperty, defSwitchVector, defTextVector, defNumberVecto
6
6
 
7
7
  from .propertymembers import getfloat
8
8
 
9
- version = "0.2.2"
9
+ version = "0.2.4"
@@ -123,7 +123,7 @@ class ConsoleControl:
123
123
  "If self._shutdown becomes True, shutdown"
124
124
  while (not self._shutdown) and (not self.client.stopped) and (not self.stop):
125
125
  # no shutdown requested, just continue
126
- await asyncio.sleep(0)
126
+ await asyncio.sleep(0.1)
127
127
  # so either shutdown has been requested or the ipyclient has stopped for some reason
128
128
  if not self.client.stopped:
129
129
  # client is still running, shut it down
@@ -147,6 +147,7 @@ class ConsoleControl:
147
147
  while not self.stop:
148
148
  await asyncio.sleep(0)
149
149
  if isinstance(self.screen, windows.TooSmall):
150
+ await asyncio.sleep(0.1)
150
151
  continue
151
152
  if not self.connected:
152
153
  if isinstance(self.screen, windows.MessagesScreen):
@@ -164,6 +165,7 @@ class ConsoleControl:
164
165
  self.eventque.task_done()
165
166
  except asyncio.QueueEmpty:
166
167
  # no event received, so do not update screen
168
+ await asyncio.sleep(0.02)
167
169
  continue
168
170
  if isinstance(event, VectorTimeOut) and (event.devicename == self.screen.devicename):
169
171
  if isinstance(self.screen, windows.ChooseVectorScreen):
@@ -206,41 +208,32 @@ class ConsoleControl:
206
208
  self.BLOBfiles[(event.devicename, event.vectorname, membername)] = filepath
207
209
  if isinstance(self.screen, windows.MessagesScreen):
208
210
  self.screen.update(event)
209
- continue
210
- if isinstance(self.screen, windows.DevicesScreen):
211
+ elif isinstance(self.screen, windows.DevicesScreen):
211
212
  self.screen.update(event)
212
- continue
213
- if isinstance(self.screen, windows.EnableBLOBsScreen):
213
+ elif isinstance(self.screen, windows.EnableBLOBsScreen):
214
214
  self.screen.update(event)
215
- continue
216
- if event.devicename != self.screen.devicename:
215
+ elif event.devicename == self.screen.devicename:
217
216
  # the remaining screens are only affected if the event devicename
218
217
  # is the device they refer to
219
- continue
220
- if isinstance(event, delProperty):
221
- if event.vectorname is None:
222
- # the whole device is disabled,
223
- if event.devicename and (event.devicename in self.devicenames):
224
- self.devicenames.remove(event.devicename)
225
- # show devicesscreen
226
- self.screen.close("Devices")
227
- continue
228
- if isinstance(self.screen, windows.ChooseVectorScreen):
229
- # one vector has been disabled, update the ChooseVectorScreen
218
+ if isinstance(event, delProperty):
219
+ if event.vectorname is None:
220
+ # the whole device is disabled,
221
+ if event.devicename and (event.devicename in self.devicenames):
222
+ self.devicenames.remove(event.devicename)
223
+ # show devicesscreen
224
+ self.screen.close("Devices")
225
+ elif isinstance(self.screen, windows.ChooseVectorScreen):
226
+ # one vector has been disabled, update the ChooseVectorScreen
227
+ self.screen.update(event)
228
+ elif isinstance(self.screen, windows.VectorScreen) and (self.screen.vectorname == event.vectorname):
229
+ # This vector has been disabled, show ChooseVectorScreen
230
+ self.screen.close("Vectors")
231
+ # so its not a delete property
232
+ elif isinstance(self.screen, windows.ChooseVectorScreen):
233
+ self.screen.update(event)
234
+ elif isinstance(self.screen, windows.VectorScreen) and (self.screen.vectorname == event.vectorname):
235
+ # The event refers to this vector
230
236
  self.screen.update(event)
231
- continue
232
- if isinstance(self.screen, windows.VectorScreen) and (self.screen.vectorname == event.vectorname):
233
- # This vector has been disabled, show ChooseVectorScreen
234
- self.screen.close("Vectors")
235
- continue
236
- continue
237
- # so its not a delete property
238
- if isinstance(self.screen, windows.ChooseVectorScreen):
239
- self.screen.update(event)
240
- continue
241
- if isinstance(self.screen, windows.VectorScreen) and (self.screen.vectorname == event.vectorname):
242
- # The event refers to this vector
243
- self.screen.update(event)
244
237
  except Exception:
245
238
  logger.exception("Exception report from ConsoleControl.updatescreen")
246
239
  raise
@@ -258,7 +251,7 @@ class ConsoleControl:
258
251
  self.maxrows, self.maxcols = self.stdscr.getmaxyx()
259
252
  if self.maxrows < 10 or self.maxcols < 40:
260
253
  self.shutdown()
261
- continue
254
+ break
262
255
  if self.maxrows < MINROWS or self.maxcols < MINCOLS:
263
256
  self.screen = windows.TooSmall(self.stdscr, self)
264
257
  self.screen.show()
@@ -277,7 +270,7 @@ class ConsoleControl:
277
270
  self.maxrows, self.maxcols = self.stdscr.getmaxyx()
278
271
  if self.maxrows < 16 or self.maxcols < 40:
279
272
  self.shutdown()
280
- continue
273
+ break
281
274
  if self.maxrows < MINROWS or self.maxcols < MINCOLS:
282
275
  self.screen = windows.TooSmall(self.stdscr, self)
283
276
  self.screen.show()
@@ -302,7 +295,7 @@ class ConsoleControl:
302
295
  self.maxrows, self.maxcols = self.stdscr.getmaxyx()
303
296
  if self.maxrows < 16 or self.maxcols < 40:
304
297
  self.shutdown()
305
- continue
298
+ break
306
299
  if self.maxrows < MINROWS or self.maxcols < MINCOLS:
307
300
  self.screen = windows.TooSmall(self.stdscr, self)
308
301
  self.screen.show()
@@ -327,7 +320,7 @@ class ConsoleControl:
327
320
  self.maxrows, self.maxcols = self.stdscr.getmaxyx()
328
321
  if self.maxrows < 16 or self.maxcols < 40:
329
322
  self.shutdown()
330
- continue
323
+ break
331
324
  if self.maxrows < MINROWS or self.maxcols < MINCOLS:
332
325
  self.screen = windows.TooSmall(self.stdscr, self)
333
326
  self.screen.show()
@@ -354,7 +347,7 @@ class ConsoleControl:
354
347
  self.maxrows, self.maxcols = self.stdscr.getmaxyx()
355
348
  if self.maxrows < 16 or self.maxcols < 40:
356
349
  self.shutdown()
357
- continue
350
+ break
358
351
  if self.maxrows < MINROWS or self.maxcols < MINCOLS:
359
352
  self.screen = windows.TooSmall(self.stdscr, self)
360
353
  self.screen.show()
@@ -384,29 +377,25 @@ class ConsoleControl:
384
377
  self.maxrows, self.maxcols = self.stdscr.getmaxyx()
385
378
  if self.maxrows < 16 or self.maxcols < 40:
386
379
  self.shutdown()
387
- continue
380
+ break
388
381
  if self.maxrows < MINROWS or self.maxcols < MINCOLS:
389
382
  self.screen = windows.TooSmall(self.stdscr, self)
390
383
  self.screen.show()
391
384
  continue
392
385
  self.screen = windows.VectorScreen(self.stdscr, self, self.screen.devicename, self.screen.vectorname)
393
386
  self.screen.show()
394
- continue
395
- if result == "Quit":
387
+ elif result == "Quit":
396
388
  self.shutdown()
397
389
  break
398
- if result == "Messages":
390
+ elif result == "Messages":
399
391
  self.screen = windows.MessagesScreen(self.stdscr, self)
400
392
  self.screen.show()
401
- continue
402
- if result == "Devices":
393
+ elif result == "Devices":
403
394
  self.screen = windows.DevicesScreen(self.stdscr, self)
404
395
  self.screen.show()
405
- continue
406
- if result == "Vectors":
396
+ elif result == "Vectors":
407
397
  self.screen = windows.ChooseVectorScreen(self.stdscr, self, self.screen.devicename, group=self.screen.vector.group)
408
398
  self.screen.show()
409
- continue
410
399
 
411
400
  except Exception:
412
401
  logger.exception("Exception report from ConsoleControl.getinput")
@@ -418,6 +418,7 @@ class BaseMember:
418
418
  return self._close
419
419
  key = self.stdscr.getch()
420
420
  if key == -1:
421
+ await asyncio.sleep(0.02)
421
422
  continue
422
423
  if key == curses.KEY_RESIZE:
423
424
  return "Resize"
@@ -46,6 +46,7 @@ class ParentScreen:
46
46
  return self._close
47
47
  key = self.stdscr.getch()
48
48
  if key == -1:
49
+ await asyncio.sleep(0.02)
49
50
  continue
50
51
  if key == curses.KEY_RESIZE:
51
52
  return "Resize"
@@ -83,6 +84,7 @@ class ConsoleClientScreen(ParentScreen):
83
84
  return self._close
84
85
  key = self.stdscr.getch()
85
86
  if key == -1:
87
+ await asyncio.sleep(0.02)
86
88
  continue
87
89
  if key == curses.KEY_RESIZE:
88
90
  return "Resize"
@@ -6,8 +6,6 @@ from time import sleep
6
6
 
7
7
  from datetime import datetime, timezone
8
8
 
9
- from base64 import standard_b64encode
10
-
11
9
  import xml.etree.ElementTree as ET
12
10
 
13
11
  import logging
@@ -61,32 +59,6 @@ def _makestart(element):
61
59
  return "".join(attriblist)
62
60
 
63
61
 
64
- def blob_xml_bytes(xmldata):
65
- """A generator yielding blob xml byte strings
66
- for a newBLOBVector.
67
- reads member bytes, b64 encodes the data
68
- and yields the byte string including tags."""
69
-
70
- # yield initial newBLOBVector
71
- newblobvector = _makestart(xmldata)
72
- yield newblobvector.encode()
73
- for oneblob in xmldata.iter('oneBLOB'):
74
- bytescontent = oneblob.text
75
- size = oneblob.get("size")
76
- if size == "0":
77
- oneblob.set("size", str(len(bytescontent)))
78
- # yield start of oneblob
79
- start = _makestart(oneblob)
80
- yield start.encode()
81
- # yield body, b64 encoded, in chunks
82
- encoded_data = standard_b64encode(bytescontent)
83
- chunksize = 1000
84
- for b in range(0, len(encoded_data), chunksize):
85
- yield encoded_data[b:b+chunksize]
86
- yield b"</oneBLOB>"
87
- yield b"</newBLOBVector>\n"
88
-
89
-
90
62
 
91
63
  class IPyClient(collections.UserDict):
92
64
 
@@ -293,7 +265,7 @@ class IPyClient(collections.UserDict):
293
265
  async def _check_alive(self, writer):
294
266
  try:
295
267
  while self.connected and (not self._stop):
296
- await asyncio.sleep(0)
268
+ await asyncio.sleep(0.1)
297
269
  if self.tx_timer:
298
270
  # data has been sent, waiting for reply
299
271
  telapsed = time.time() - self.tx_timer
@@ -314,7 +286,6 @@ class IPyClient(collections.UserDict):
314
286
  finally:
315
287
  self.connected = False
316
288
 
317
-
318
289
  def _logtx(self, txdata):
319
290
  "log tx data with level debug, and detail depends on self._verbose"
320
291
  if not self._verbose:
@@ -324,12 +295,13 @@ class IPyClient(collections.UserDict):
324
295
  binarydata = ET.tostring(txdata)
325
296
  logger.debug(startlog + binarydata.decode())
326
297
  elif self._verbose == 2:
327
- data = copy.deepcopy(txdata)
328
- tag = data.tag
329
- for element in data:
330
- if tag == "newBLOBVector":
298
+ if txdata.tag == "newBLOBVector" or txdata.tag == "setBLOBVector":
299
+ data = copy.deepcopy(txdata)
300
+ for element in data:
331
301
  element.text = "NOT LOGGED"
332
- binarydata = ET.tostring(data)
302
+ binarydata = ET.tostring(data)
303
+ else:
304
+ binarydata = ET.tostring(txdata)
333
305
  logger.debug(startlog + binarydata.decode())
334
306
  elif self._verbose == 1:
335
307
  data = copy.deepcopy(txdata)
@@ -348,25 +320,17 @@ class IPyClient(collections.UserDict):
348
320
  try:
349
321
  txdata = self.writerque.popleft()
350
322
  except IndexError:
323
+ await asyncio.sleep(0.1)
351
324
  continue
352
325
  if not self.connected:
353
326
  break
354
327
  if self._stop:
355
328
  break
356
- if txdata.tag == "newBLOBVector" and len(txdata):
357
- # txdata is a newBLOBVector containing blobs
358
- # the generator blob_xml_bytes yields bytes
359
- for binarydata in blob_xml_bytes(txdata):
360
- # Send to the port
361
- writer.write(binarydata)
362
- await writer.drain()
363
- else:
364
- # its straight xml, send it out on the port
365
- binarydata = ET.tostring(txdata)
366
- # Send to the port
367
- writer.write(binarydata)
368
- await writer.drain()
369
-
329
+ # send it out on the port
330
+ binarydata = ET.tostring(txdata)
331
+ # Send to the port
332
+ writer.write(binarydata)
333
+ await writer.drain()
370
334
  if self.timeout_enable:
371
335
  # data has been transmitted set timers going, do not set timer
372
336
  # for enableBLOB as no answer is expected for that
@@ -3,6 +3,8 @@ import xml.etree.ElementTree as ET
3
3
 
4
4
  import sys, pathlib
5
5
 
6
+ from base64 import standard_b64encode
7
+
6
8
 
7
9
  class ParseException(Exception):
8
10
  "Raised if an error occurs when parsing received data"
@@ -421,13 +423,12 @@ class BLOBMember(ParentBLOBMember):
421
423
  xmldata = ET.Element('oneBLOB')
422
424
  xmldata.set("name", self.name)
423
425
  xmldata.set("format", newformat)
424
- xmldata.set("size", str(newsize))
425
426
  # the value set in the xmldata object should be a bytes object
426
427
  if isinstance(newvalue, bytes):
427
- xmldata.text = newvalue
428
+ bytescontent = newvalue
428
429
  elif isinstance(newvalue, pathlib.Path):
429
430
  try:
430
- xmldata.text = newvalue.read_bytes()
431
+ bytescontent = newvalue.read_bytes()
431
432
  except Exception:
432
433
  raise ParseException("Unable to read the given file")
433
434
  elif hasattr(newvalue, "seek") and hasattr(newvalue, "read") and callable(newvalue.read):
@@ -440,7 +441,6 @@ class BLOBMember(ParentBLOBMember):
440
441
  raise ParseException("The read BLOB is not a bytes object")
441
442
  if bytescontent == b"":
442
443
  raise ParseException("The read BLOB value is empty")
443
- xmldata.text = bytescontent
444
444
  else:
445
445
  # could be a path to a file
446
446
  try:
@@ -450,7 +450,10 @@ class BLOBMember(ParentBLOBMember):
450
450
  raise ParseException("Unable to read the given file")
451
451
  if bytescontent == b"":
452
452
  raise ParseException("The read BLOB value is empty")
453
- xmldata.text = bytescontent
453
+ if not newsize:
454
+ newsize = len(bytescontent)
455
+ xmldata.set("size", str(newsize))
456
+ xmldata.text = standard_b64encode(bytescontent).decode("utf-8")
454
457
  return xmldata
455
458
 
456
459
 
@@ -7,7 +7,7 @@ name = "indipyclient"
7
7
  authors = [{name = "Bernard Czenkusz", email = "bernie@skipole.co.uk"}]
8
8
  license = {file = "LICENSE"}
9
9
  classifiers = ["License :: OSI Approved :: MIT License", "Operating System :: POSIX :: Linux","Topic :: Scientific/Engineering :: Astronomy", "Topic :: Scientific/Engineering :: Interface Engine/Protocol Translator"]
10
- version = "0.2.2"
10
+ version = "0.2.4"
11
11
  description="Pure python package, providing a terminal client and a set of classes which can be used to create scripts or clients to control remote instruments using the INDI protocol."
12
12
  readme = "README.md"
13
13
  requires-python = ">=3.10"
File without changes
File without changes