pytrms 0.9.2__py3-none-any.whl → 0.9.3__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.
- pytrms/__init__.py +38 -38
- pytrms/_base/__init__.py +24 -24
- pytrms/_base/ioniclient.py +32 -32
- pytrms/_base/mqttclient.py +119 -119
- pytrms/_version.py +26 -26
- pytrms/clients/__init__.py +33 -33
- pytrms/clients/db_api.py +200 -183
- pytrms/clients/ioniclient.py +87 -87
- pytrms/clients/modbus.py +532 -528
- pytrms/clients/mqtt.py +800 -797
- pytrms/clients/ssevent.py +82 -82
- pytrms/compose/__init__.py +2 -2
- pytrms/compose/composition.py +302 -302
- pytrms/data/IoniTofPrefs.ini +112 -112
- pytrms/data/ParaIDs.csv +731 -731
- pytrms/helpers.py +126 -120
- pytrms/instrument.py +119 -119
- pytrms/measurement.py +173 -173
- pytrms/peaktable.py +499 -501
- pytrms/plotting/__init__.py +4 -4
- pytrms/plotting/plotting.py +27 -27
- pytrms/readers/__init__.py +4 -4
- pytrms/readers/ionitof_reader.py +472 -472
- {pytrms-0.9.2.dist-info → pytrms-0.9.3.dist-info}/LICENSE +339 -339
- {pytrms-0.9.2.dist-info → pytrms-0.9.3.dist-info}/METADATA +3 -2
- pytrms-0.9.3.dist-info/RECORD +27 -0
- {pytrms-0.9.2.dist-info → pytrms-0.9.3.dist-info}/WHEEL +1 -1
- pytrms-0.9.2.dist-info/RECORD +0 -27
pytrms/__init__.py
CHANGED
|
@@ -1,38 +1,38 @@
|
|
|
1
|
-
_version = '0.9.
|
|
2
|
-
|
|
3
|
-
__all__ = ['load', 'connect']
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
def load(path):
|
|
7
|
-
'''Open a datafile for post-analysis or batch processing.
|
|
8
|
-
|
|
9
|
-
`path` may be a glob-expression to collect a whole batch.
|
|
10
|
-
|
|
11
|
-
returns a `Measurement` instance.
|
|
12
|
-
'''
|
|
13
|
-
import glob
|
|
14
|
-
from .measurement import FinishedMeasurement
|
|
15
|
-
|
|
16
|
-
files = glob.glob(path)
|
|
17
|
-
|
|
18
|
-
return FinishedMeasurement(*files)
|
|
19
|
-
|
|
20
|
-
def connect(host=None, method='webapi'):
|
|
21
|
-
'''Connect a client to a running measurement server.
|
|
22
|
-
|
|
23
|
-
'method' is the preferred connection, either 'webapi' (default) or 'modbus'.
|
|
24
|
-
|
|
25
|
-
returns an `Instrument` if connected successfully.
|
|
26
|
-
'''
|
|
27
|
-
from .instrument import Instrument
|
|
28
|
-
|
|
29
|
-
if method.lower() == 'webapi':
|
|
30
|
-
from .clients.ioniclient import IoniClient
|
|
31
|
-
return IoniClient(host)
|
|
32
|
-
|
|
33
|
-
if method.lower() == 'modbus':
|
|
34
|
-
from .modbus import IoniconModbus
|
|
35
|
-
return IoniconModbus(host)
|
|
36
|
-
|
|
37
|
-
raise NotImplementedError(str(method))
|
|
38
|
-
|
|
1
|
+
_version = '0.9.3'
|
|
2
|
+
|
|
3
|
+
__all__ = ['load', 'connect']
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def load(path):
|
|
7
|
+
'''Open a datafile for post-analysis or batch processing.
|
|
8
|
+
|
|
9
|
+
`path` may be a glob-expression to collect a whole batch.
|
|
10
|
+
|
|
11
|
+
returns a `Measurement` instance.
|
|
12
|
+
'''
|
|
13
|
+
import glob
|
|
14
|
+
from .measurement import FinishedMeasurement
|
|
15
|
+
|
|
16
|
+
files = glob.glob(path)
|
|
17
|
+
|
|
18
|
+
return FinishedMeasurement(*files)
|
|
19
|
+
|
|
20
|
+
def connect(host=None, method='webapi'):
|
|
21
|
+
'''Connect a client to a running measurement server.
|
|
22
|
+
|
|
23
|
+
'method' is the preferred connection, either 'webapi' (default) or 'modbus'.
|
|
24
|
+
|
|
25
|
+
returns an `Instrument` if connected successfully.
|
|
26
|
+
'''
|
|
27
|
+
from .instrument import Instrument
|
|
28
|
+
|
|
29
|
+
if method.lower() == 'webapi':
|
|
30
|
+
from .clients.ioniclient import IoniClient
|
|
31
|
+
return IoniClient(host)
|
|
32
|
+
|
|
33
|
+
if method.lower() == 'modbus':
|
|
34
|
+
from .modbus import IoniconModbus
|
|
35
|
+
return IoniconModbus(host)
|
|
36
|
+
|
|
37
|
+
raise NotImplementedError(str(method))
|
|
38
|
+
|
pytrms/_base/__init__.py
CHANGED
|
@@ -1,24 +1,24 @@
|
|
|
1
|
-
from collections import namedtuple
|
|
2
|
-
|
|
3
|
-
from .mqttclient import MqttClientBase
|
|
4
|
-
from .ioniclient import IoniClientBase
|
|
5
|
-
|
|
6
|
-
class itype:
|
|
7
|
-
|
|
8
|
-
table_setting_t = namedtuple('mass_mapping', ['name', 'mass2value'])
|
|
9
|
-
timecycle_t = namedtuple('timecycle', ['rel_cycle','abs_cycle','abs_time','rel_time'])
|
|
10
|
-
masscal_t = namedtuple('masscal', ['mode', 'masses', 'timebins', 'cal_pars', 'cal_segs'])
|
|
11
|
-
add_data_item_t = namedtuple('add_data', ['value', 'name', 'unit', 'view'])
|
|
12
|
-
fullcycle_t = namedtuple('fullcycle', ['timecycle', 'intensity', 'mass_cal', 'add_data'])
|
|
13
|
-
|
|
14
|
-
AME_RUN = 8
|
|
15
|
-
AME_STEP = 7
|
|
16
|
-
AME_ACTION = 5
|
|
17
|
-
USE_MEAN = 2 # (only in AUTO_UseMean)
|
|
18
|
-
|
|
19
|
-
REACT_Udrift = 0
|
|
20
|
-
REACT_pDrift = 1
|
|
21
|
-
REACT_Tdrift = 2
|
|
22
|
-
REACT_PI_Idx = 4 # skipping E/N = 3
|
|
23
|
-
REACT_TM_Idx = 5
|
|
24
|
-
|
|
1
|
+
from collections import namedtuple
|
|
2
|
+
|
|
3
|
+
from .mqttclient import MqttClientBase
|
|
4
|
+
from .ioniclient import IoniClientBase
|
|
5
|
+
|
|
6
|
+
class itype:
|
|
7
|
+
|
|
8
|
+
table_setting_t = namedtuple('mass_mapping', ['name', 'mass2value'])
|
|
9
|
+
timecycle_t = namedtuple('timecycle', ['rel_cycle','abs_cycle','abs_time','rel_time'])
|
|
10
|
+
masscal_t = namedtuple('masscal', ['mode', 'masses', 'timebins', 'cal_pars', 'cal_segs'])
|
|
11
|
+
add_data_item_t = namedtuple('add_data', ['value', 'name', 'unit', 'view'])
|
|
12
|
+
fullcycle_t = namedtuple('fullcycle', ['timecycle', 'intensity', 'mass_cal', 'add_data'])
|
|
13
|
+
|
|
14
|
+
AME_RUN = 8
|
|
15
|
+
AME_STEP = 7
|
|
16
|
+
AME_ACTION = 5
|
|
17
|
+
USE_MEAN = 2 # (only in AUTO_UseMean)
|
|
18
|
+
|
|
19
|
+
REACT_Udrift = 0
|
|
20
|
+
REACT_pDrift = 1
|
|
21
|
+
REACT_Tdrift = 2
|
|
22
|
+
REACT_PI_Idx = 4 # skipping E/N = 3
|
|
23
|
+
REACT_TM_Idx = 5
|
|
24
|
+
|
pytrms/_base/ioniclient.py
CHANGED
|
@@ -1,32 +1,32 @@
|
|
|
1
|
-
from abc import ABC, abstractmethod
|
|
2
|
-
|
|
3
|
-
class IoniClientBase(ABC):
|
|
4
|
-
|
|
5
|
-
@property
|
|
6
|
-
@abstractmethod
|
|
7
|
-
def is_connected(self):
|
|
8
|
-
'''Returns `True` if connection to IoniTOF could be established.'''
|
|
9
|
-
pass
|
|
10
|
-
|
|
11
|
-
@property
|
|
12
|
-
@abstractmethod
|
|
13
|
-
def is_running(self):
|
|
14
|
-
'''Returns `True` if IoniTOF is currently acquiring data.'''
|
|
15
|
-
pass
|
|
16
|
-
|
|
17
|
-
@abstractmethod
|
|
18
|
-
def connect(self, timeout_s):
|
|
19
|
-
pass
|
|
20
|
-
|
|
21
|
-
@abstractmethod
|
|
22
|
-
def disconnect(self):
|
|
23
|
-
pass
|
|
24
|
-
|
|
25
|
-
def __init__(self, host, port):
|
|
26
|
-
# Note: circumvent (potentially sluggish) Windows DNS lookup:
|
|
27
|
-
self.host = '127.0.0.1' if host == 'localhost' else str(host)
|
|
28
|
-
self.port = int(port)
|
|
29
|
-
|
|
30
|
-
def __repr__(self):
|
|
31
|
-
return f"<{self.__class__.__name__} @ {self.host}[:{self.port}]>"
|
|
32
|
-
|
|
1
|
+
from abc import ABC, abstractmethod
|
|
2
|
+
|
|
3
|
+
class IoniClientBase(ABC):
|
|
4
|
+
|
|
5
|
+
@property
|
|
6
|
+
@abstractmethod
|
|
7
|
+
def is_connected(self):
|
|
8
|
+
'''Returns `True` if connection to IoniTOF could be established.'''
|
|
9
|
+
pass
|
|
10
|
+
|
|
11
|
+
@property
|
|
12
|
+
@abstractmethod
|
|
13
|
+
def is_running(self):
|
|
14
|
+
'''Returns `True` if IoniTOF is currently acquiring data.'''
|
|
15
|
+
pass
|
|
16
|
+
|
|
17
|
+
@abstractmethod
|
|
18
|
+
def connect(self, timeout_s):
|
|
19
|
+
pass
|
|
20
|
+
|
|
21
|
+
@abstractmethod
|
|
22
|
+
def disconnect(self):
|
|
23
|
+
pass
|
|
24
|
+
|
|
25
|
+
def __init__(self, host, port):
|
|
26
|
+
# Note: circumvent (potentially sluggish) Windows DNS lookup:
|
|
27
|
+
self.host = '127.0.0.1' if host == 'localhost' else str(host)
|
|
28
|
+
self.port = int(port)
|
|
29
|
+
|
|
30
|
+
def __repr__(self):
|
|
31
|
+
return f"<{self.__class__.__name__} @ {self.host}[:{self.port}]>"
|
|
32
|
+
|
pytrms/_base/mqttclient.py
CHANGED
|
@@ -1,119 +1,119 @@
|
|
|
1
|
-
import os
|
|
2
|
-
import time
|
|
3
|
-
import logging
|
|
4
|
-
import json
|
|
5
|
-
from collections import deque
|
|
6
|
-
from itertools import cycle
|
|
7
|
-
from threading import Condition, RLock
|
|
8
|
-
from datetime import datetime as dt
|
|
9
|
-
|
|
10
|
-
import paho.mqtt.client
|
|
11
|
-
|
|
12
|
-
from .ioniclient import IoniClientBase
|
|
13
|
-
|
|
14
|
-
log = logging.getLogger(__name__)
|
|
15
|
-
|
|
16
|
-
__all__ = ['MqttClientBase']
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
def _on_connect(client, self, flags, rc):
|
|
20
|
-
# Note: ensure subscription after re-connecting,
|
|
21
|
-
# wildcards are '+' (one level), '#' (all levels):
|
|
22
|
-
default_QoS = 2
|
|
23
|
-
topics = set()
|
|
24
|
-
for subscriber in self._subscriber_functions:
|
|
25
|
-
topics.update(set(getattr(subscriber, "topics", [])))
|
|
26
|
-
subs = sorted(zip(topics, cycle([default_QoS])))
|
|
27
|
-
log.debug(f"[{self}] " + "\n --> ".join(["subscribing to"] + list(map(str, subs))))
|
|
28
|
-
rv = client.subscribe(subs)
|
|
29
|
-
log.info(f"[{self}] successfully connected with {rv = }")
|
|
30
|
-
|
|
31
|
-
def _on_subscribe(client, self, mid, granted_qos):
|
|
32
|
-
log.info(f"[{self}] successfully subscribed with {mid = } | {granted_qos = }")
|
|
33
|
-
|
|
34
|
-
def _on_publish(client, self, mid):
|
|
35
|
-
log.debug(f"[{self}] published {mid = }")
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
class MqttClientBase(IoniClientBase):
|
|
39
|
-
|
|
40
|
-
@property
|
|
41
|
-
def is_connected(self):
|
|
42
|
-
'''Returns `True` if connected to the server.
|
|
43
|
-
|
|
44
|
-
Note: this property will be polled on initialization and should
|
|
45
|
-
return `True` if a connection could be established!
|
|
46
|
-
'''
|
|
47
|
-
return (True
|
|
48
|
-
and self.client.is_connected())
|
|
49
|
-
|
|
50
|
-
def __init__(self, host, port, subscriber_functions,
|
|
51
|
-
on_connect, on_subscribe, on_publish,
|
|
52
|
-
connect_timeout_s=10):
|
|
53
|
-
assert len(subscriber_functions) > 0, "no subscribers: for some unknown reason this causes disconnects"
|
|
54
|
-
super().__init__(host, port)
|
|
55
|
-
|
|
56
|
-
# Note: Version 2.0 of paho-mqtt introduced versioning of the user-callback to fix
|
|
57
|
-
# some inconsistency in callback arguments and to provide better support for MQTTv5.
|
|
58
|
-
# VERSION1 of the callback is deprecated, but is still supported in version 2.x.
|
|
59
|
-
# If you want to upgrade to the newer version of the API callback, you will need
|
|
60
|
-
# to update your callbacks:
|
|
61
|
-
paho_version = int(paho.mqtt.__version__.split('.')[0])
|
|
62
|
-
if paho_version == 1:
|
|
63
|
-
self.client = paho.mqtt.client.Client(clean_session=True)
|
|
64
|
-
elif paho_version == 2:
|
|
65
|
-
self.client = paho.mqtt.client.Client(paho.mqtt.client.CallbackAPIVersion.VERSION1,
|
|
66
|
-
clean_session=True)
|
|
67
|
-
else:
|
|
68
|
-
# see https://eclipse.dev/paho/files/paho.mqtt.python/html/migrations.html
|
|
69
|
-
raise NotImplementedError("API VERSION2 for MQTTv5 (use paho-mqtt 2.x or implement user callbacks)")
|
|
70
|
-
|
|
71
|
-
# clean_session is a boolean that determines the client type. If True,
|
|
72
|
-
# the broker will remove all information about this client when it
|
|
73
|
-
# disconnects. If False, the client is a persistent client and
|
|
74
|
-
# subscription information and queued messages will be retained when the
|
|
75
|
-
# client disconnects.
|
|
76
|
-
# The clean_session argument only applies to MQTT versions v3.1.1 and v3.1.
|
|
77
|
-
# It is not accepted if the MQTT version is v5.0 - use the clean_start
|
|
78
|
-
# argument on connect() instead.
|
|
79
|
-
self.client.on_connect = on_connect if on_connect is not None else _on_connect
|
|
80
|
-
self.client.on_subscribe = on_subscribe if on_subscribe is not None else _on_subscribe
|
|
81
|
-
self.client.on_publish = on_publish if on_publish is not None else _on_publish
|
|
82
|
-
# ...subscribe to topics...
|
|
83
|
-
self._subscriber_functions = list(subscriber_functions)
|
|
84
|
-
for subscriber in self._subscriber_functions:
|
|
85
|
-
for topic in getattr(subscriber, "topics", []):
|
|
86
|
-
self.client.message_callback_add(topic, subscriber)
|
|
87
|
-
# ...pass this instance to each callback...
|
|
88
|
-
self.client.user_data_set(self)
|
|
89
|
-
# ...and connect to the server:
|
|
90
|
-
try:
|
|
91
|
-
self.connect(connect_timeout_s)
|
|
92
|
-
except TimeoutError as exc:
|
|
93
|
-
log.warn(f"{exc} (retry connecting when the Instrument is set up)")
|
|
94
|
-
|
|
95
|
-
def connect(self, timeout_s=10):
|
|
96
|
-
log.info(f"[{self}] connecting to MQTT broker...")
|
|
97
|
-
self.client.connect(self.host, self.port, timeout_s)
|
|
98
|
-
self.client.loop_start() # runs in a background thread
|
|
99
|
-
started_at = time.monotonic()
|
|
100
|
-
while time.monotonic() < started_at + timeout_s:
|
|
101
|
-
if self.is_connected:
|
|
102
|
-
break
|
|
103
|
-
|
|
104
|
-
time.sleep(10e-3)
|
|
105
|
-
else:
|
|
106
|
-
self.disconnect()
|
|
107
|
-
raise TimeoutError(f"[{self}] no connection to IoniTOF")
|
|
108
|
-
|
|
109
|
-
def publish_with_ack(self, *args, timeout_s=10, **kwargs):
|
|
110
|
-
# Note: this is important when publishing just before exiting the application
|
|
111
|
-
# to ensure that all messages get through (timeout_s is set on `.__init__()`)
|
|
112
|
-
msg = self.client.publish(*args, **kwargs)
|
|
113
|
-
msg.wait_for_publish(timeout=timeout_s)
|
|
114
|
-
return msg
|
|
115
|
-
|
|
116
|
-
def disconnect(self):
|
|
117
|
-
self.client.loop_stop()
|
|
118
|
-
self.client.disconnect()
|
|
119
|
-
|
|
1
|
+
import os
|
|
2
|
+
import time
|
|
3
|
+
import logging
|
|
4
|
+
import json
|
|
5
|
+
from collections import deque
|
|
6
|
+
from itertools import cycle
|
|
7
|
+
from threading import Condition, RLock
|
|
8
|
+
from datetime import datetime as dt
|
|
9
|
+
|
|
10
|
+
import paho.mqtt.client
|
|
11
|
+
|
|
12
|
+
from .ioniclient import IoniClientBase
|
|
13
|
+
|
|
14
|
+
log = logging.getLogger(__name__)
|
|
15
|
+
|
|
16
|
+
__all__ = ['MqttClientBase']
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def _on_connect(client, self, flags, rc):
|
|
20
|
+
# Note: ensure subscription after re-connecting,
|
|
21
|
+
# wildcards are '+' (one level), '#' (all levels):
|
|
22
|
+
default_QoS = 2
|
|
23
|
+
topics = set()
|
|
24
|
+
for subscriber in self._subscriber_functions:
|
|
25
|
+
topics.update(set(getattr(subscriber, "topics", [])))
|
|
26
|
+
subs = sorted(zip(topics, cycle([default_QoS])))
|
|
27
|
+
log.debug(f"[{self}] " + "\n --> ".join(["subscribing to"] + list(map(str, subs))))
|
|
28
|
+
rv = client.subscribe(subs)
|
|
29
|
+
log.info(f"[{self}] successfully connected with {rv = }")
|
|
30
|
+
|
|
31
|
+
def _on_subscribe(client, self, mid, granted_qos):
|
|
32
|
+
log.info(f"[{self}] successfully subscribed with {mid = } | {granted_qos = }")
|
|
33
|
+
|
|
34
|
+
def _on_publish(client, self, mid):
|
|
35
|
+
log.debug(f"[{self}] published {mid = }")
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class MqttClientBase(IoniClientBase):
|
|
39
|
+
|
|
40
|
+
@property
|
|
41
|
+
def is_connected(self):
|
|
42
|
+
'''Returns `True` if connected to the server.
|
|
43
|
+
|
|
44
|
+
Note: this property will be polled on initialization and should
|
|
45
|
+
return `True` if a connection could be established!
|
|
46
|
+
'''
|
|
47
|
+
return (True
|
|
48
|
+
and self.client.is_connected())
|
|
49
|
+
|
|
50
|
+
def __init__(self, host, port, subscriber_functions,
|
|
51
|
+
on_connect, on_subscribe, on_publish,
|
|
52
|
+
connect_timeout_s=10):
|
|
53
|
+
assert len(subscriber_functions) > 0, "no subscribers: for some unknown reason this causes disconnects"
|
|
54
|
+
super().__init__(host, port)
|
|
55
|
+
|
|
56
|
+
# Note: Version 2.0 of paho-mqtt introduced versioning of the user-callback to fix
|
|
57
|
+
# some inconsistency in callback arguments and to provide better support for MQTTv5.
|
|
58
|
+
# VERSION1 of the callback is deprecated, but is still supported in version 2.x.
|
|
59
|
+
# If you want to upgrade to the newer version of the API callback, you will need
|
|
60
|
+
# to update your callbacks:
|
|
61
|
+
paho_version = int(paho.mqtt.__version__.split('.')[0])
|
|
62
|
+
if paho_version == 1:
|
|
63
|
+
self.client = paho.mqtt.client.Client(clean_session=True)
|
|
64
|
+
elif paho_version == 2:
|
|
65
|
+
self.client = paho.mqtt.client.Client(paho.mqtt.client.CallbackAPIVersion.VERSION1,
|
|
66
|
+
clean_session=True)
|
|
67
|
+
else:
|
|
68
|
+
# see https://eclipse.dev/paho/files/paho.mqtt.python/html/migrations.html
|
|
69
|
+
raise NotImplementedError("API VERSION2 for MQTTv5 (use paho-mqtt 2.x or implement user callbacks)")
|
|
70
|
+
|
|
71
|
+
# clean_session is a boolean that determines the client type. If True,
|
|
72
|
+
# the broker will remove all information about this client when it
|
|
73
|
+
# disconnects. If False, the client is a persistent client and
|
|
74
|
+
# subscription information and queued messages will be retained when the
|
|
75
|
+
# client disconnects.
|
|
76
|
+
# The clean_session argument only applies to MQTT versions v3.1.1 and v3.1.
|
|
77
|
+
# It is not accepted if the MQTT version is v5.0 - use the clean_start
|
|
78
|
+
# argument on connect() instead.
|
|
79
|
+
self.client.on_connect = on_connect if on_connect is not None else _on_connect
|
|
80
|
+
self.client.on_subscribe = on_subscribe if on_subscribe is not None else _on_subscribe
|
|
81
|
+
self.client.on_publish = on_publish if on_publish is not None else _on_publish
|
|
82
|
+
# ...subscribe to topics...
|
|
83
|
+
self._subscriber_functions = list(subscriber_functions)
|
|
84
|
+
for subscriber in self._subscriber_functions:
|
|
85
|
+
for topic in getattr(subscriber, "topics", []):
|
|
86
|
+
self.client.message_callback_add(topic, subscriber)
|
|
87
|
+
# ...pass this instance to each callback...
|
|
88
|
+
self.client.user_data_set(self)
|
|
89
|
+
# ...and connect to the server:
|
|
90
|
+
try:
|
|
91
|
+
self.connect(connect_timeout_s)
|
|
92
|
+
except TimeoutError as exc:
|
|
93
|
+
log.warn(f"{exc} (retry connecting when the Instrument is set up)")
|
|
94
|
+
|
|
95
|
+
def connect(self, timeout_s=10):
|
|
96
|
+
log.info(f"[{self}] connecting to MQTT broker...")
|
|
97
|
+
self.client.connect(self.host, self.port, timeout_s)
|
|
98
|
+
self.client.loop_start() # runs in a background thread
|
|
99
|
+
started_at = time.monotonic()
|
|
100
|
+
while time.monotonic() < started_at + timeout_s:
|
|
101
|
+
if self.is_connected:
|
|
102
|
+
break
|
|
103
|
+
|
|
104
|
+
time.sleep(10e-3)
|
|
105
|
+
else:
|
|
106
|
+
self.disconnect()
|
|
107
|
+
raise TimeoutError(f"[{self}] no connection to IoniTOF")
|
|
108
|
+
|
|
109
|
+
def publish_with_ack(self, *args, timeout_s=10, **kwargs):
|
|
110
|
+
# Note: this is important when publishing just before exiting the application
|
|
111
|
+
# to ensure that all messages get through (timeout_s is set on `.__init__()`)
|
|
112
|
+
msg = self.client.publish(*args, **kwargs)
|
|
113
|
+
msg.wait_for_publish(timeout=timeout_s)
|
|
114
|
+
return msg
|
|
115
|
+
|
|
116
|
+
def disconnect(self):
|
|
117
|
+
self.client.loop_stop()
|
|
118
|
+
self.client.disconnect()
|
|
119
|
+
|
pytrms/_version.py
CHANGED
|
@@ -1,26 +1,26 @@
|
|
|
1
|
-
__version__ = '0.2.2' # must be on the first line!
|
|
2
|
-
|
|
3
|
-
__all__ = ['branch', 'digest', '__version__']
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
from os.path import abspath, dirname, join, isdir
|
|
7
|
-
|
|
8
|
-
# 'gitdir' might be defined by the setup.py script..
|
|
9
|
-
if not 'gitdir' in vars():
|
|
10
|
-
gitdir = abspath(join(dirname(__file__), '..', '.git'))
|
|
11
|
-
|
|
12
|
-
# in development mode: get git branch and digest..
|
|
13
|
-
if isdir(gitdir):
|
|
14
|
-
with open(join(gitdir, 'HEAD')) as f:
|
|
15
|
-
refinfo = f.readline().strip()
|
|
16
|
-
detached = not refinfo.startswith('ref:')
|
|
17
|
-
if detached:
|
|
18
|
-
branch = 'detached-HEAD'
|
|
19
|
-
digest = refinfo[:7]
|
|
20
|
-
else:
|
|
21
|
-
refpath = refinfo.split()[-1]
|
|
22
|
-
branch = refinfo.split('/')[-1]
|
|
23
|
-
digest = open(join(gitdir, refpath)).read(7)
|
|
24
|
-
|
|
25
|
-
if not branch == 'master':
|
|
26
|
-
__version__ += '.dev' + str(eval('0x'+digest))
|
|
1
|
+
__version__ = '0.2.2' # must be on the first line!
|
|
2
|
+
|
|
3
|
+
__all__ = ['branch', 'digest', '__version__']
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
from os.path import abspath, dirname, join, isdir
|
|
7
|
+
|
|
8
|
+
# 'gitdir' might be defined by the setup.py script..
|
|
9
|
+
if not 'gitdir' in vars():
|
|
10
|
+
gitdir = abspath(join(dirname(__file__), '..', '.git'))
|
|
11
|
+
|
|
12
|
+
# in development mode: get git branch and digest..
|
|
13
|
+
if isdir(gitdir):
|
|
14
|
+
with open(join(gitdir, 'HEAD')) as f:
|
|
15
|
+
refinfo = f.readline().strip()
|
|
16
|
+
detached = not refinfo.startswith('ref:')
|
|
17
|
+
if detached:
|
|
18
|
+
branch = 'detached-HEAD'
|
|
19
|
+
digest = refinfo[:7]
|
|
20
|
+
else:
|
|
21
|
+
refpath = refinfo.split()[-1]
|
|
22
|
+
branch = refinfo.split('/')[-1]
|
|
23
|
+
digest = open(join(gitdir, refpath)).read(7)
|
|
24
|
+
|
|
25
|
+
if not branch == 'master':
|
|
26
|
+
__version__ += '.dev' + str(eval('0x'+digest))
|
pytrms/clients/__init__.py
CHANGED
|
@@ -1,33 +1,33 @@
|
|
|
1
|
-
import os
|
|
2
|
-
|
|
3
|
-
_root = os.path.dirname(__file__)
|
|
4
|
-
_par_id_file = os.path.abspath(os.path.join(_root, '..', 'data', 'ParaIDs.csv'))
|
|
5
|
-
assert os.path.exists(_par_id_file), "par-id file not found: please re-install PyTRMS package"
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
import logging as _logging
|
|
9
|
-
|
|
10
|
-
_logging.TRACE = 5 # even more verbose than logging.DEBUG
|
|
11
|
-
|
|
12
|
-
def enable_extended_logging(log_level=_logging.DEBUG):
|
|
13
|
-
'''make output of http-requests more talkative.
|
|
14
|
-
|
|
15
|
-
set 'log_level=logging.TRACE' (defined as 0 in pytrms.__init__) for highest verbosity!
|
|
16
|
-
'''
|
|
17
|
-
if log_level <= _logging.DEBUG:
|
|
18
|
-
# enable logging of http request urls on the library, that is
|
|
19
|
-
# underlying the 'requests'-package:
|
|
20
|
-
_logging.warn(f"enabling logging-output on 'urllib3' ({log_level = })")
|
|
21
|
-
requests_log = _logging.getLogger("urllib3")
|
|
22
|
-
requests_log.setLevel(log_level)
|
|
23
|
-
requests_log.propagate = True
|
|
24
|
-
|
|
25
|
-
if log_level <= _logging.TRACE:
|
|
26
|
-
# Enabling debugging at http.client level (requests->urllib3->http.client)
|
|
27
|
-
# you will see the REQUEST, including HEADERS and DATA, and RESPONSE with
|
|
28
|
-
# HEADERS but without DATA. the only thing missing will be the response.body,
|
|
29
|
-
# which is not logged.
|
|
30
|
-
_logging.warn(f"enabling logging-output on 'HTTPConnection' ({log_level = })")
|
|
31
|
-
from http.client import HTTPConnection
|
|
32
|
-
HTTPConnection.debuglevel = 1
|
|
33
|
-
|
|
1
|
+
import os
|
|
2
|
+
|
|
3
|
+
_root = os.path.dirname(__file__)
|
|
4
|
+
_par_id_file = os.path.abspath(os.path.join(_root, '..', 'data', 'ParaIDs.csv'))
|
|
5
|
+
assert os.path.exists(_par_id_file), "par-id file not found: please re-install PyTRMS package"
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
import logging as _logging
|
|
9
|
+
|
|
10
|
+
_logging.TRACE = 5 # even more verbose than logging.DEBUG
|
|
11
|
+
|
|
12
|
+
def enable_extended_logging(log_level=_logging.DEBUG):
|
|
13
|
+
'''make output of http-requests more talkative.
|
|
14
|
+
|
|
15
|
+
set 'log_level=logging.TRACE' (defined as 0 in pytrms.__init__) for highest verbosity!
|
|
16
|
+
'''
|
|
17
|
+
if log_level <= _logging.DEBUG:
|
|
18
|
+
# enable logging of http request urls on the library, that is
|
|
19
|
+
# underlying the 'requests'-package:
|
|
20
|
+
_logging.warn(f"enabling logging-output on 'urllib3' ({log_level = })")
|
|
21
|
+
requests_log = _logging.getLogger("urllib3")
|
|
22
|
+
requests_log.setLevel(log_level)
|
|
23
|
+
requests_log.propagate = True
|
|
24
|
+
|
|
25
|
+
if log_level <= _logging.TRACE:
|
|
26
|
+
# Enabling debugging at http.client level (requests->urllib3->http.client)
|
|
27
|
+
# you will see the REQUEST, including HEADERS and DATA, and RESPONSE with
|
|
28
|
+
# HEADERS but without DATA. the only thing missing will be the response.body,
|
|
29
|
+
# which is not logged.
|
|
30
|
+
_logging.warn(f"enabling logging-output on 'HTTPConnection' ({log_level = })")
|
|
31
|
+
from http.client import HTTPConnection
|
|
32
|
+
HTTPConnection.debuglevel = 1
|
|
33
|
+
|