nost-tools 2.0.4__tar.gz → 2.0.5__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.

Potentially problematic release.


This version of nost-tools might be problematic. Click here for more details.

Files changed (26) hide show
  1. {nost_tools-2.0.4 → nost_tools-2.0.5}/PKG-INFO +1 -1
  2. {nost_tools-2.0.4 → nost_tools-2.0.5}/nost_tools/__init__.py +1 -1
  3. {nost_tools-2.0.4 → nost_tools-2.0.5}/nost_tools/manager.py +82 -44
  4. {nost_tools-2.0.4 → nost_tools-2.0.5}/nost_tools.egg-info/PKG-INFO +1 -1
  5. {nost_tools-2.0.4 → nost_tools-2.0.5}/LICENSE +0 -0
  6. {nost_tools-2.0.4 → nost_tools-2.0.5}/README.md +0 -0
  7. {nost_tools-2.0.4 → nost_tools-2.0.5}/nost_tools/application.py +0 -0
  8. {nost_tools-2.0.4 → nost_tools-2.0.5}/nost_tools/application_utils.py +0 -0
  9. {nost_tools-2.0.4 → nost_tools-2.0.5}/nost_tools/configuration.py +0 -0
  10. {nost_tools-2.0.4 → nost_tools-2.0.5}/nost_tools/entity.py +0 -0
  11. {nost_tools-2.0.4 → nost_tools-2.0.5}/nost_tools/errors.py +0 -0
  12. {nost_tools-2.0.4 → nost_tools-2.0.5}/nost_tools/logger_application.py +0 -0
  13. {nost_tools-2.0.4 → nost_tools-2.0.5}/nost_tools/managed_application.py +0 -0
  14. {nost_tools-2.0.4 → nost_tools-2.0.5}/nost_tools/observer.py +0 -0
  15. {nost_tools-2.0.4 → nost_tools-2.0.5}/nost_tools/publisher.py +0 -0
  16. {nost_tools-2.0.4 → nost_tools-2.0.5}/nost_tools/schemas.py +0 -0
  17. {nost_tools-2.0.4 → nost_tools-2.0.5}/nost_tools/simulator.py +0 -0
  18. {nost_tools-2.0.4 → nost_tools-2.0.5}/nost_tools.egg-info/SOURCES.txt +0 -0
  19. {nost_tools-2.0.4 → nost_tools-2.0.5}/nost_tools.egg-info/dependency_links.txt +0 -0
  20. {nost_tools-2.0.4 → nost_tools-2.0.5}/nost_tools.egg-info/requires.txt +0 -0
  21. {nost_tools-2.0.4 → nost_tools-2.0.5}/nost_tools.egg-info/top_level.txt +0 -0
  22. {nost_tools-2.0.4 → nost_tools-2.0.5}/pyproject.toml +0 -0
  23. {nost_tools-2.0.4 → nost_tools-2.0.5}/setup.cfg +0 -0
  24. {nost_tools-2.0.4 → nost_tools-2.0.5}/tests/test_entity.py +0 -0
  25. {nost_tools-2.0.4 → nost_tools-2.0.5}/tests/test_observer.py +0 -0
  26. {nost_tools-2.0.4 → nost_tools-2.0.5}/tests/test_simulator.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nost_tools
3
- Version: 2.0.4
3
+ Version: 2.0.5
4
4
  Summary: Tools for Novel Observing Strategies Testbed (NOS-T) Applications
5
5
  Author-email: "Paul T. Grogan" <paul.grogan@asu.edu>, "Emmanuel M. Gonzalez" <emmanuelgonzalez@asu.edu>
6
6
  License-Expression: BSD-3-Clause
@@ -1,4 +1,4 @@
1
- __version__ = "2.0.4"
1
+ __version__ = "2.0.5"
2
2
 
3
3
  from .application import Application
4
4
  from .application_utils import ConnectionConfig, ModeStatusObserver, TimeStatusPublisher
@@ -98,6 +98,36 @@ class Manager(Application):
98
98
  auto_delete=True,
99
99
  )
100
100
 
101
+ def _sleep_with_heartbeat(self, total_seconds):
102
+ """
103
+ Sleep for a specified number of seconds while allowing connection heartbeats.
104
+ Works with SelectConnection by using short sleep intervals.
105
+
106
+ Args:
107
+ total_seconds (float): Total number of seconds to sleep
108
+ """
109
+ if total_seconds <= 0:
110
+ return
111
+
112
+ # Sleep in smaller chunks to allow heartbeats to pass through
113
+ check_interval = 30 # Check every 30 seconds at most
114
+ end_time = time.time() + total_seconds
115
+
116
+ logger.debug(f"Starting heartbeat-safe sleep for {total_seconds:.2f} seconds")
117
+
118
+ while time.time() < end_time:
119
+ # Calculate remaining time
120
+ remaining = end_time - time.time()
121
+
122
+ # Sleep for the shorter of check_interval or remaining time
123
+ sleep_time = min(check_interval, remaining)
124
+
125
+ if sleep_time > 0:
126
+ time.sleep(sleep_time)
127
+ logger.debug(
128
+ f"Heartbeat check: {remaining:.2f} seconds remaining in sleep"
129
+ )
130
+
101
131
  def execute_test_plan(self, *args, **kwargs) -> None:
102
132
  """
103
133
  Starts the test plan execution in a background thread.
@@ -147,6 +177,7 @@ class Manager(Application):
147
177
  init_retry_delay_s (float): number of seconds to wait between initialization commands while waiting for required applications
148
178
  init_max_retry (int): number of initialization commands while waiting for required applications before continuing to execution
149
179
  """
180
+ # Initialize parameters from arguments or config
150
181
  if sim_start_time is not None and sim_stop_time is not None:
151
182
  self.sim_start_time = sim_start_time
152
183
  self.sim_stop_time = sim_stop_time
@@ -186,13 +217,10 @@ class Manager(Application):
186
217
  raise ValueError(
187
218
  "No configuration runtime. Please provide simulation start and stop times."
188
219
  )
189
- ####
220
+
190
221
  self.establish_exchange()
191
- # if self.predefined_exchanges_queues:
192
- # self.declare_exchange()
193
- # self.declare_bind_queue()
194
- ####
195
222
 
223
+ # Set up tracking of required applications
196
224
  self.required_apps_status = dict(
197
225
  zip(self.required_apps, [False] * len(self.required_apps))
198
226
  )
@@ -200,35 +228,37 @@ class Manager(Application):
200
228
  self.add_message_callback("*", "status.time", self.on_app_time_status)
201
229
 
202
230
  self._create_time_status_publisher(self.time_status_step, self.time_status_init)
231
+
232
+ # Initialize with retry logic
203
233
  for i in range(self.init_max_retry):
204
- # issue the init command
205
234
  self.init(self.sim_start_time, self.sim_stop_time, self.required_apps)
206
235
  next_try = self.simulator.get_wallclock_time() + timedelta(
207
236
  seconds=self.init_retry_delay_s
208
237
  )
209
- # wait until all required apps are ready
210
238
  while (
211
239
  not all([self.required_apps_status[app] for app in self.required_apps])
212
240
  and self.simulator.get_wallclock_time() < next_try
213
241
  ):
214
242
  time.sleep(0.001)
215
- # self.remove_message_callback("*", "status.ready")
216
- # self.remove_message_callback()
217
- # configure start time
243
+
244
+ # Configure start time if not provided
218
245
  if self.start_time is None:
219
246
  self.start_time = self.simulator.get_wallclock_time() + self.command_lead
220
- # sleep until the start command needs to be issued
221
- time.sleep(
222
- max(
223
- 0,
224
- (
225
- (self.start_time - self.simulator.get_wallclock_time())
226
- - self.command_lead
227
- )
228
- / timedelta(seconds=1),
247
+
248
+ # Sleep until start time using heartbeat-safe approach
249
+ sleep_seconds = max(
250
+ 0,
251
+ (
252
+ (self.start_time - self.simulator.get_wallclock_time())
253
+ - self.command_lead
229
254
  )
255
+ / timedelta(seconds=1),
230
256
  )
231
- # issue the start command
257
+
258
+ # Use our heartbeat-safe sleep
259
+ self._sleep_with_heartbeat(sleep_seconds)
260
+
261
+ # Issue the start command
232
262
  self.start(
233
263
  self.sim_start_time,
234
264
  self.sim_stop_time,
@@ -238,43 +268,51 @@ class Manager(Application):
238
268
  self.time_status_step,
239
269
  self.time_status_init,
240
270
  )
241
- # wait for simulation to start executing
271
+
272
+ # Wait for simulation to start executing
242
273
  while self.simulator.get_mode() != Mode.EXECUTING:
243
274
  time.sleep(0.001)
275
+
276
+ # Process time scale updates
244
277
  for update in self.time_scale_updates:
245
278
  update_time = self.simulator.get_wallclock_time_at_simulation_time(
246
279
  update.sim_update_time
247
280
  )
248
- # sleep until the update command needs to be issued
249
- time.sleep(
250
- max(
251
- 0,
252
- (
253
- (update_time - self.simulator.get_wallclock_time())
254
- - self.command_lead
255
- )
256
- / timedelta(seconds=1),
281
+ # Sleep until update time using heartbeat-safe approach
282
+ sleep_seconds = max(
283
+ 0,
284
+ (
285
+ (update_time - self.simulator.get_wallclock_time())
286
+ - self.command_lead
257
287
  )
288
+ / timedelta(seconds=1),
258
289
  )
259
- # issue the update command
260
- self.update(
261
- update.time_scale_factor, update.sim_update_time, self.required_apps
262
- )
263
- # wait until the update command takes effect
290
+
291
+ # Use our heartbeat-safe sleep
292
+ self._sleep_with_heartbeat(sleep_seconds)
293
+
294
+ # Issue the update command
295
+ self.update(update.time_scale_factor, update.sim_update_time)
296
+
297
+ # Wait until update takes effect
264
298
  while self.simulator.get_time_scale_factor() != update.time_scale_factor:
265
- time.sleep(self.command_lead / timedelta(seconds=1) / 100)
299
+ time.sleep(0.001)
300
+
266
301
  end_time = self.simulator.get_wallclock_time_at_simulation_time(
267
302
  self.simulator.get_end_time()
268
303
  )
269
- # sleep until the stop command should be issued
270
- time.sleep(
271
- max(
272
- 0,
273
- ((end_time - self.simulator.get_wallclock_time()) - self.command_lead)
274
- / timedelta(seconds=1),
275
- )
304
+
305
+ # Sleep until stop time using heartbeat-safe approach
306
+ sleep_seconds = max(
307
+ 0,
308
+ ((end_time - self.simulator.get_wallclock_time()) - self.command_lead)
309
+ / timedelta(seconds=1),
276
310
  )
277
- # issue the stop command
311
+
312
+ # Use our heartbeat-safe sleep
313
+ self._sleep_with_heartbeat(sleep_seconds)
314
+
315
+ # Issue the stop command
278
316
  self.stop(self.sim_stop_time)
279
317
 
280
318
  def on_app_ready_status(self, ch, method, properties, body) -> None:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nost_tools
3
- Version: 2.0.4
3
+ Version: 2.0.5
4
4
  Summary: Tools for Novel Observing Strategies Testbed (NOS-T) Applications
5
5
  Author-email: "Paul T. Grogan" <paul.grogan@asu.edu>, "Emmanuel M. Gonzalez" <emmanuelgonzalez@asu.edu>
6
6
  License-Expression: BSD-3-Clause
File without changes
File without changes
File without changes
File without changes