Skip to content

Commit de54653

Browse files
committed
add fixed to load default args
1 parent d369e15 commit de54653

1 file changed

Lines changed: 86 additions & 13 deletions

File tree

micro_manager/config.py

Lines changed: 86 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,14 @@
33
"""
44

55
import json
6+
import logging
67
import os
78
import importlib.metadata
89
import string
910
from collections import defaultdict
1011
from typing import Optional, Type, List, Dict, Any, Callable
1112
import inspect
12-
from tools.logging_wrapper import Logger
13+
from .tools.logging_wrapper import Logger
1314

1415

1516
class ConfigDSL:
@@ -149,10 +150,10 @@ def get_with_default(
149150
if options is not None and current_element not in options:
150151
raise RuntimeError("Wrong option")
151152
except BaseException as e:
152-
self.handle_fmt_error(fmt_error, e, kwargs)
153+
self.handle_fmt_error(fmt_error or "", e, kwargs)
153154
return default
154155

155-
self.handle_fmt_success(fmt_success, current_element, kwargs)
156+
self.handle_fmt_success(fmt_success or "", current_element, kwargs)
156157
return current_element
157158

158159
def get_or_raise(
@@ -197,10 +198,10 @@ def get_or_raise(
197198
if options is not None and current_element not in options:
198199
raise RuntimeError("Wrong option")
199200
except BaseException as e:
200-
self.handle_fmt_error(fmt_error, e, kwargs)
201+
self.handle_fmt_error(fmt_error or "", e, kwargs)
201202
raise e
202203

203-
self.handle_fmt_success(fmt_success, current_element, kwargs)
204+
self.handle_fmt_success(fmt_success or "", current_element, kwargs)
204205
return current_element
205206

206207
def handle_fmt(
@@ -382,6 +383,55 @@ def config_entry(func: Callable) -> Callable:
382383
return ConfigEntryProxy(func)
383384

384385

386+
class ConfigLogContext:
387+
"""
388+
Provides a context in which the loggers of the config can be optionally switched.
389+
If one log uses a high log level, this can disable log-outputs for the subsequent code block.
390+
"""
391+
392+
def __init__(self, config: "Config", should_swap: bool):
393+
"""
394+
Constructs a ConfigLogContext object.
395+
396+
Parameters
397+
----------
398+
config : Config
399+
Config object.
400+
should_swap : bool
401+
Should the loggers be swapped.
402+
"""
403+
self._config: Config = config
404+
self._should_swap: bool = should_swap
405+
406+
def swap(self):
407+
"""
408+
Swaps the loggers used by the config object.
409+
"""
410+
tmp = self._config._logger
411+
self._config._logger = self._config._logger_null
412+
self._config._logger_null = tmp
413+
414+
def __enter__(self) -> "ConfigLogContext":
415+
"""
416+
Called upon entering a with ... statement.
417+
418+
Returns
419+
-------
420+
ctx : ConfigLogContext
421+
Logging context.
422+
"""
423+
if self._should_swap:
424+
self.swap()
425+
return self
426+
427+
def __exit__(self, *args) -> None:
428+
"""
429+
Called upon exiting a with ... statement.
430+
"""
431+
if self._should_swap:
432+
self.swap()
433+
434+
385435
class Config:
386436
"""
387437
Handles the reading of parameters in the JSON configuration file provided by the user. This class is based on
@@ -401,16 +451,20 @@ def __init__(self, config_file_name: str):
401451
self._base_dir: str = os.path.dirname(
402452
os.path.join(os.getcwd(), config_file_name)
403453
)
404-
self._logger: Optional[Logger] = None
454+
self._logger_null: Logger = Logger(Config.__name__, level=logging.CRITICAL)
455+
self._logger: Logger = self._logger_null
405456
self._data: Optional[Dict[str, Any]] = None
406457
self._fields: Dict[str, Any] = defaultdict(lambda: None)
407458

408459
# attach external backing field to all config entries
460+
# inspection triggers assertions: need to temporarily set to value other than None
461+
self._data = {}
409462
config_entries = inspect.getmembers(
410463
self, lambda f: hasattr(f, "attach_instance")
411464
)
412465
for _, e in config_entries:
413466
e.attach_instance(self)
467+
self._data = None
414468

415469
def set_logger(self, logger: Logger):
416470
"""
@@ -423,12 +477,34 @@ def set_logger(self, logger: Logger):
423477
"""
424478
self._logger = logger
425479

480+
def show_log_if(self, cond: bool) -> ConfigLogContext:
481+
"""
482+
Redirects log requests in the resulting context if cond is True.
483+
484+
Usage:
485+
with self.show_log_if(cond):
486+
... load fields ...
487+
488+
Hereby default arguments can be loaded for inactive modules without emitting log output.
489+
490+
Parameters
491+
----------
492+
cond : bool
493+
Should redirect?
494+
495+
Returns
496+
-------
497+
ctx : ConfigLogContext
498+
Logging context
499+
"""
500+
return ConfigLogContext(self, not cond)
501+
426502
@property
427503
def json(self) -> ConfigDSL:
428504
"""
429505
Returns and Object to load JSON values dynamically.
430506
"""
431-
assert self._data is not None and self._logger is not None
507+
assert self._data is not None
432508
return ConfigDSL(self._data, self._logger)
433509

434510
def _read_json_base(self, config_file_name: str):
@@ -440,7 +516,6 @@ def _read_json_base(self, config_file_name: str):
440516
config_file_name : string
441517
Path to the JSON configuration file
442518
"""
443-
assert self._logger is not None
444519
self._logger.log_info_rank_zero(
445520
f"Micro Manager version: {importlib.metadata.version('micro-manager-precice')}"
446521
)
@@ -517,8 +592,7 @@ def _read_json_base(self, config_file_name: str):
517592
# ======================================================
518593
# Tasking
519594
# ======================================================
520-
521-
if self.json["tasking"].exists():
595+
with self.show_log_if(self.json["tasking"].exists()):
522596
self.tasking_backend.set = self.json["tasking"]["backend"].get_with_default(
523597
"socket",
524598
"Tasking backend: {data}",
@@ -558,7 +632,6 @@ def read_json_micro_manager(self):
558632
Reads Micro Manager relevant information from JSON configuration file
559633
and saves the data to the respective instance attributes.
560634
"""
561-
assert self._logger is not None
562635
self._read_json_base(self._config_file_name)
563636

564637
self.precice_config_file_name.set = os.path.join(
@@ -636,7 +709,7 @@ def read_json_micro_manager(self):
636709
"Adaptivity settings are provided but adaptivity is turned off."
637710
)
638711

639-
if self.enable_adaptivity():
712+
with self.show_log_if(self.enable_adaptivity()):
640713
self.adaptivity_type.set = self.json["simulation_params"][
641714
"adaptivity_settings"
642715
]["type"].get_with_default(
@@ -749,6 +822,7 @@ def read_json_micro_manager(self):
749822
else:
750823
self.write_data_names().append("rank_of_sim")
751824

825+
with self.show_log_if(self.enable_load_balancing()):
752826
self.load_balancing_n.set = self.json["simulation_params"][
753827
"load_balancing_settings"
754828
]["every_n_time_windows"].get_with_default(
@@ -877,7 +951,6 @@ def read_json_snapshot(self):
877951
"""
878952
Reads Snapshot relevant information from JSON configuration file
879953
"""
880-
assert self._logger is not None
881954
self._read_json_base(self._config_file_name) # Read base information
882955
self._logger.log_info_rank_zero(
883956
f"Reading JSON configuration file: {self._config_file_name}"

0 commit comments

Comments
 (0)