Coverage for /Users/rik/github/cgse/libs/cgse-common/src/egse/env.py: 26%
225 statements
« prev ^ index » next coverage.py v7.10.6, created at 2025-09-15 11:57 +0200
« prev ^ index » next coverage.py v7.10.6, created at 2025-09-15 11:57 +0200
1"""
2This module provides functionality to work with and check your environment variables.
4The module provides functions to get/set the location of the data storage, the configuration data, and the log files.
5The locations are determined from the environment variables that are set for the project.
7Two important and mandatory environment variables are PROJECT and SITE_ID. The PROJECT environment variable is
8used to construct the names of the other environment variables that are specific to the project. The SITE_ID
9environment variable is used in the value that is returned for some the of project specific environment variables.
11Mandatory environment variables:
13- PROJECT: the name of the project, e.g. PLATO, ARIEL. [shall be UPPER case]
14- SITE_ID: the site identifier, e.g. the lab name or organisation acronym. [shall be UPPER case]
16The following environment variables are used by the project:
18- `<PROJECT>_DATA_STORAGE_LOCATION`: the root of the data storage location.
19- `<PROJECT>_CONF_DATA_LOCATION`: the location of the configuration data.
20- `<PROJECT>_CONF_REPO_LOCATION`: the location of the configuration data GitHub repository.
21- `<PROJECT>_LOG_FILE_LOCATION`: the location of the log files.
22- `<PROJECT>_LOCAL_SETTINGS`: the YAML file that contains site specific local settings.
24Do not use the environment variables directly in your code, but use the functions provided by this module to get the
25locations and settings.
27- `get_data_storage_location()`: returns the full path of the data storage location.
28- `get_conf_data_location()`: returns the full path of the location of the configuration data.
29- `get_conf_repo_location()`: returns the full path of the location of the configuration data repository.
30- `get_log_file_location()`: returns the full path of the location of the log files.
31- `get_local_settings()`: returns the fully qualified filename of the local settings YAML file.
33!!! warning
35 These environment variables shall not be changed outside the processes that use them and also not using the
36 `os.environ` within the code. For the known environment variables, use the dedicated 'setters' that are provided
37 by this module. If there is a need to change the environment variables, e.g. in unit tests, make sure to call the
38 `egse.env.initialize()` to reset the proper state.
40"""
42from __future__ import annotations
44__all__ = [
45 "env_var",
46 "get_conf_data_location",
47 "get_conf_data_location_env_name",
48 "get_conf_repo_location",
49 "get_conf_repo_location_env_name",
50 "get_data_storage_location",
51 "get_data_storage_location_env_name",
52 "get_local_settings_path",
53 "get_local_settings_env_name",
54 "get_log_file_location",
55 "get_log_file_location_env_name",
56 "get_project_name",
57 "get_site_id",
58 "set_conf_data_location",
59 "set_conf_repo_location",
60 "set_data_storage_location",
61 "set_local_settings",
62 "set_log_file_location",
63]
65import contextlib
66import os
67import warnings
68from pathlib import Path
70from egse.log import logger
71from egse.system import all_logging_disabled
72from egse.system import get_caller_info
73from egse.system import ignore_m_warning
75from rich.console import Console
77console = Console(width=100)
79# Every project shall have a PROJECT and a SITE_ID environment variable set. This variable will be used to
80# create the other environment variables that are specific to the project.
82MANDATORY_ENVIRONMENT_VARIABLES = [
83 "PROJECT",
84 "SITE_ID",
85]
87# The environment variables that are known to be used by the project. These environment variables shall be set
88# as ${PROJECT}_<variable name>, e.g. PLATO_DATA_STORAGE_LOCATION. For each of these variables, there is a
89# corresponding function that will return the value of the environment variable. The environment variable is not
90# mandatory and if not set, a LookupError will be raised.
92KNOWN_PROJECT_ENVIRONMENT_VARIABLES = [
93 "DATA_STORAGE_LOCATION",
94 "CONF_DATA_LOCATION",
95 "CONF_REPO_LOCATION",
96 "LOG_FILE_LOCATION",
97 "LOCAL_SETTINGS",
98]
101def initialize():
102 """
103 Initialize the environment variables that are required for the CGSE to function properly.
104 This function will print a warning if any of the mandatory environment variables is not set.
106 This function is automatically called on import and can be called whenever the environment
107 variables have been changed, e.g. in unit tests.
108 """
110 global _env
112 for name in MANDATORY_ENVIRONMENT_VARIABLES:
113 try:
114 _env.set(name, os.environ[name])
115 except KeyError:
116 logger.warning(
117 f"The environment variable {name} is not set. {name} is required to define the project settings and "
118 f"environment variables. Please set the environment variable {name} before proceeding."
119 )
120 _env.set(name, NoValue())
122 project = _env.get("PROJECT")
124 for gen_var_name in KNOWN_PROJECT_ENVIRONMENT_VARIABLES:
125 env_var = f"{project}_{gen_var_name}"
126 _env.set(gen_var_name, os.environ.get(env_var, NoValue()))
129class _Env:
130 """Internal class that keeps track of the environment variables."""
132 def __init__(self):
133 self._env = {}
135 def set(self, key, value):
136 if value is None: 136 ↛ 137line 136 didn't jump to line 137 because the condition on line 136 was never true
137 if key in self._env:
138 del self._env[key]
139 else:
140 self._env[key] = value
142 def get(self, key) -> str:
143 return self._env.get(key, NoValue())
145 def __rich__(self):
146 return self._env
149_env = _Env()
152class NoValue:
153 """
154 Represents a no value object, an environment variable that was not set.
156 The truth value of this object is always False, and it is equal to any other NoValue object.
157 """
159 def __eq__(self, other):
160 if isinstance(other, NoValue):
161 return True
162 return False
164 def __bool__(self):
165 return False
167 def __repr__(self):
168 return f"{self.__class__.__name__}"
171# The module needs to be initialized before it can be used.
172initialize()
175def _check_no_value(var_name, value):
176 """Raise a ValueError when the value for the variable is NoValue."""
177 if value == NoValue():
178 project = _env.get("PROJECT")
179 env_name = var_name if var_name in ("PROJECT", "SITE_ID") else f"{project}_{var_name}"
180 raise ValueError(
181 f"The environment variable {env_name} is not set. Please set the environment variable before proceeding."
182 )
185def set_default_environment(
186 project: str,
187 site_id: str,
188 data_storage_location: str | Path,
189 conf_data_location: str | Path | None = None,
190 conf_repo_location: str | Path | None = None,
191 log_file_location: str | Path | None = None,
192 local_settings: str | Path | None = None,
193):
194 set_project_name(project)
195 set_site_id(site_id)
196 set_data_storage_location(data_storage_location)
197 set_conf_data_location(conf_data_location)
198 set_conf_repo_location(conf_repo_location)
199 set_log_file_location(log_file_location)
200 set_local_settings(local_settings)
203def get_project_name() -> str:
204 """Get the PROJECT name. Return None when the PROJECT is not set."""
205 return _env.get("PROJECT") or None
208def set_project_name(name: str):
209 """Set the environment variable PROJECT and its internal representation."""
210 os.environ["PROJECT"] = name
211 _env.set("PROJECT", name)
214def get_site_id() -> str:
215 """Get the SITE_ID. Return None if the SITE_ID is not set."""
216 return _env.get("SITE_ID") or None
219def set_site_id(name: str):
220 """Set the environment variable SITE_ID and its internal representation."""
221 os.environ["SITE_ID"] = name
222 _env.set("SITE_ID", name)
225def get_data_storage_location_env_name() -> str:
226 """Returns the name of the environment variable for the project."""
227 project = _env.get("PROJECT")
228 return f"{project}_DATA_STORAGE_LOCATION"
231def set_data_storage_location(location: str | Path | None):
232 """
233 Sets the environment variable and the internal representation to the given value.
235 Warning:
236 Issues a warning when the given location doesn't exist.
237 """
238 env_name = get_data_storage_location_env_name()
240 if location is None:
241 if env_name in os.environ:
242 del os.environ[env_name]
243 _env.set("DATA_STORAGE_LOCATION", None)
244 return
246 if not Path(location).exists():
247 warnings.warn(f"The location you provided for the environment variable {env_name} doesn't exist: {location}.")
249 os.environ[env_name] = str(location)
250 _env.set("DATA_STORAGE_LOCATION", str(location))
253def get_data_storage_location(site_id: str = None) -> str:
254 """
255 Returns the full path of the data storage location for the given site_id.
257 If the site_id is None, it is determined from the environment variable SITE_ID.
259 If the `${PROJECT}_DATA_STORAGE_LOCATION` environment variable does not end with
260 the site_id, the site_id will be appended to the path on return. That means
261 the actual data storage location will always be site specific.
263 Note:
264 when you specify the `site_id` as an argument, it takes precedence
265 over the SITE_ID environment variable.
267 Args:
268 site_id: the site identifier (to be used instead of the SITE_ID environment variable)
270 Returns:
271 The full path of data storage location as a string.
273 Raises:
274 ValueError: when the SITE_ID or the ${PROJECT}_DATA_STORAGE_LOCATION is not set.
275 """
276 global _env
278 project = _env.get("PROJECT")
279 _check_no_value("PROJECT", project)
281 site_id = site_id or _env.get("SITE_ID")
282 _check_no_value("SITE_ID", site_id)
284 data_root = _env.get("DATA_STORAGE_LOCATION")
285 _check_no_value("DATA_STORAGE_LOCATION", data_root)
287 data_root = data_root.rstrip("/")
289 return data_root if data_root.endswith(site_id) else f"{data_root}/{site_id}"
292def get_conf_data_location_env_name() -> str:
293 """Returns the name of the environment variable for the project."""
294 project = _env.get("PROJECT")
295 return f"{project}_CONF_DATA_LOCATION"
298def set_conf_data_location(location: str | Path | None):
299 """
300 Sets the environment variable and the internal representation to the given value.
302 Warning:
303 Issues a warning when the given location doesn't exist.
304 """
306 env_name = get_conf_data_location_env_name()
308 if location is None:
309 if env_name in os.environ:
310 del os.environ[env_name]
311 _env.set("CONF_DATA_LOCATION", None)
312 return
314 if not Path(location).exists():
315 warnings.warn(f"The location you provided for the environment variable {env_name} doesn't exist: {location}.")
317 os.environ[env_name] = location
318 _env.set("CONF_DATA_LOCATION", location)
321def get_conf_data_location(site_id: str = None) -> str:
322 """
323 Returns the full path of the location of the configuration data for the site id.
325 If the site_id is None, it is determined from the environment variable SITE_ID.
327 When the `${PROJECT}_CONF_DATA_LOCATION` environment variable is not set, the configuration data
328 location will be the `${PROJECT}_DATA_STORAGE_LOCATION + '/conf'`.
330 Args:
331 site_id: the site identifier (to be used instead of the SITE_ID environment variable)
333 Returns:
334 The full path of location of the configuration data as a string.
336 Raises:
337 ValueError: when the SITE_ID or the `${PROJECT}_DATA_STORAGE_LOCATION` is not set.
338 """
340 conf_data_root = _env.get("CONF_DATA_LOCATION")
342 if not conf_data_root:
343 try:
344 data_root = get_data_storage_location(site_id=site_id)
345 except ValueError:
346 raise ValueError(
347 f"Could not determine the location of the configuration files. "
348 f"The environment variable {get_conf_data_location_env_name()} is not set and also the "
349 f"data storage location is unknown."
350 )
352 data_root = data_root.rstrip("/")
353 conf_data_root = f"{data_root}/conf"
355 return conf_data_root
358def get_log_file_location_env_name():
359 """Returns the name of the environment variable for the project."""
360 project = _env.get("PROJECT")
361 return f"{project}_LOG_FILE_LOCATION"
364def set_log_file_location(location: str | Path | None):
365 """
366 Sets the environment variable and the internal representation to the given value.
368 Warning:
369 Issues a warning when the given location doesn't exist.
370 """
372 env_name = get_log_file_location_env_name()
374 if location is None:
375 if env_name in os.environ:
376 del os.environ[env_name]
377 _env.set("LOG_FILE_LOCATION", None)
378 return
380 if not Path(location).exists():
381 warnings.warn(f"The location you provided for the environment variable {env_name} doesn't exist: {location}.")
383 os.environ[env_name] = location
384 _env.set("LOG_FILE_LOCATION", location)
387def get_log_file_location(site_id: str = None) -> str:
388 """
389 Returns the full path of the location of the log files. The log file location is read from the environment
390 variable `${PROJECT}_LOG_FILE_LOCATION`. The location shall be independent of any setting that is subject to change.
392 If the environment variable is not set, a default log file location is created from the data storage location as
393 follows: `<PROJECT>_DATA_STORAGE_LOCATION/<SITE_ID>/log`.
395 Args:
396 site_id: the site identifier
398 Returns:
399 The full path of location of the log files as a string.
401 Raises:
402 ValueError: when the SITE_ID or the ${PROJECT}_DATA_STORAGE_LOCATION is not set.
404 """
406 log_data_root = _env.get("LOG_FILE_LOCATION")
408 if not log_data_root:
409 try:
410 data_root = get_data_storage_location(site_id=site_id)
411 except ValueError:
412 raise ValueError(
413 f"Could not determine the location of the log files. "
414 f"The environment variable {get_log_file_location_env_name()} is not set and also the "
415 f"data storage location is unknown."
416 )
417 data_root = data_root.rstrip("/")
418 log_data_root = f"{data_root}/log"
420 return log_data_root
423def get_local_settings_env_name() -> str:
424 """Returns the name of the environment variable for the project."""
425 project = _env.get("PROJECT")
426 return f"{project}_LOCAL_SETTINGS"
429def set_local_settings(path: str | Path | None):
430 """
431 Sets the environment variable and the internal representation to the given value.
433 When the path is set to None, the environment variable will be unset.
435 Warning:
436 Issues a warning when the given path doesn't exist.
437 """
439 env_name = get_local_settings_env_name()
441 if path is None:
442 if env_name in os.environ:
443 del os.environ[env_name]
444 _env.set("LOCAL_SETTINGS", None)
445 return
447 if not Path(path).exists():
448 warnings.warn(f"The location you provided for the environment variable {env_name} doesn't exist: {path}.")
450 os.environ[env_name] = path
451 _env.set("LOCAL_SETTINGS", path)
454def get_local_settings_path() -> str or None:
455 """
456 Returns the fully qualified filename of the local settings YAML file. When the local settings environment
457 variable is not defined or is an empty string, None is returned.
459 Warning:
460 The function will generate a warning when
462 - When the local settings environment variable is not defined, or
463 - when the path defined by the environment variable doesn't exist.
464 """
466 local_settings = _env.get("LOCAL_SETTINGS")
468 if not local_settings: 468 ↛ 469line 468 didn't jump to line 469 because the condition on line 468 was never true
469 warnings.warn(
470 f"The local settings environment variable '{get_local_settings_env_name()}' "
471 f"is not defined or is an empty string."
472 )
473 return None
475 if not Path(local_settings).exists(): 475 ↛ 476line 475 didn't jump to line 476 because the condition on line 475 was never true
476 warnings.warn(
477 f"The local settings path '{local_settings}' doesn't exist. As a result, "
478 f"the local settings for your project will not be loaded."
479 )
481 return local_settings
484def has_conf_repo_location() -> bool:
485 location = _env.get("CONF_REPO_LOCATION")
486 return True if location in (None, NoValue) else False
489def get_conf_repo_location_env_name() -> str:
490 """Returns the name of the environment variable for the project."""
491 project = _env.get("PROJECT")
492 return f"{project}_CONF_REPO_LOCATION"
495def get_conf_repo_location() -> str | None:
496 """
497 Returns the fully qualified name of the location of the repository with
498 configuration and calibration data.
500 Returns None if no environment variable was defined or if the location doesn't exist.
501 In both cases a Warning is issued.
502 """
504 location = _env.get("CONF_REPO_LOCATION")
506 if location in (None, NoValue()):
507 warnings.warn(
508 f"The environment variable for the configuration data repository is "
509 f"not defined ({get_conf_repo_location_env_name()})."
510 )
511 return None
513 if not Path(location).exists():
514 warnings.warn(f"The location of the configuration data repository doesn't exist: {location}.")
515 return None
517 return location
520def set_conf_repo_location(location: str | Path | None):
521 """
522 Sets the environment variable and the internal representation to the given value.
524 When the location is None, the environment variable will be unset and its internal
525 representation will be NoValue().
527 Warning:
528 Issues a warning when the given location doesn't exist.
529 """
531 env_name = get_conf_repo_location_env_name()
533 if location is None:
534 if env_name in os.environ:
535 del os.environ[env_name]
536 _env.set("CONF_REPO_LOCATION", None)
537 return
539 if not Path(location).exists():
540 warnings.warn(f"The location you provided for the environment variable {env_name} doesn't exist: {location}.")
542 os.environ[env_name] = location
543 _env.set("CONF_REPO_LOCATION", location)
546def print_env():
547 """
548 Prints out the mandatory and known environment variables at the time of the
549 function call. The function and lineno is also printed for information.
550 """
551 col_width = 30
553 console = Console(width=200)
555 with warnings.catch_warnings():
556 warnings.simplefilter("ignore")
557 caller_info = get_caller_info(level=2)
558 console.print(f"[b]Environment as in {caller_info.filename}:{caller_info.lineno}[/]")
559 console.print(f" {'PROJECT':{col_width}s}: {get_project_name()}")
560 console.print(f" {'SITE_ID':{col_width}s}: {get_site_id()}")
561 console.print(f" {get_data_storage_location_env_name():{col_width}s}: {get_data_storage_location()}")
562 console.print(f" {get_log_file_location_env_name():{col_width}s}: {get_log_file_location()}")
563 console.print(f" {get_conf_data_location_env_name():{col_width}s}: {get_conf_data_location()}")
564 console.print(f" {get_conf_repo_location_env_name():{col_width}s}: {get_conf_repo_location()}")
565 console.print(f" {get_local_settings_env_name():{col_width}s}: {get_local_settings_path()}")
568@contextlib.contextmanager
569def env_var(**kwargs: str | int | float | bool | None):
570 """
571 Context manager to run some code that need alternate settings for environment variables.
572 This will automatically initialize the CGSE environment upon entry and re-initialize upon exit.
574 Note:
575 This context manager is different from the one in `egse.system` because of the CGSE environment changes.
577 Args:
578 **kwargs: dictionary with environment variables that are needed
580 Example:
581 ```python
582 from egse.env import env_var
583 with env_var(PLATO_DATA_STORAGE_LOCATION="/Users/rik/data"):
584 # do stuff that needs these alternate setting
585 ...
586 ```
588 """
589 saved_env = {}
591 for k, v in kwargs.items():
592 saved_env[k] = os.environ.get(k)
593 if v is None:
594 if k in os.environ:
595 del os.environ[k]
596 else:
597 os.environ[k] = v
599 initialize()
601 yield
603 for k, v in saved_env.items():
604 if v is None:
605 if k in os.environ:
606 del os.environ[k]
607 else:
608 os.environ[k] = v
610 initialize()
613def main(args: list | None = None): # pragma: no cover
614 import argparse
615 import sys
616 import rich
618 parser = argparse.ArgumentParser()
619 parser.add_argument(
620 "--full",
621 default=False,
622 action="store_true",
623 help="Print a full report on environment variables and paths.",
624 )
625 parser.add_argument(
626 "--doc",
627 default=False,
628 action="store_true",
629 help="Print help on the environment variables and paths.",
630 )
631 parser.add_argument(
632 "--mkdir",
633 default=False,
634 action="store_true",
635 help="Create directory that doesn't exist.",
636 )
638 args = parser.parse_args(args or [])
640 def check_env_dir(env_var: str):
641 value = _env.get(env_var)
643 if value == NoValue():
644 value = "[bold red]not set"
645 elif not value.startswith("/"):
646 value = f"[default]{value} [bold orange3](this is a relative path!)"
647 elif not os.path.exists(value):
648 value = f"[default]{value} [bold red](location doesn't exist!)"
649 elif not os.path.isdir(value):
650 value = f"[default]{value} [bold red](location is not a directory!)"
651 else:
652 value = f"[default]{value}"
653 return value
655 def check_env_file(env_var: str):
656 value = _env.get(env_var)
658 if not value:
659 value = "[bold red]not set"
660 elif not os.path.exists(value):
661 value = f"[default]{value} [bold red](location doesn't exist!)"
662 else:
663 value = f"[default]{value}"
664 return value
666 rich.print("Environment variables:")
668 project = _env.get("PROJECT")
670 for var in MANDATORY_ENVIRONMENT_VARIABLES:
671 rich.print(f" {var} = {_env.get(var)}")
672 for var in KNOWN_PROJECT_ENVIRONMENT_VARIABLES:
673 if var.endswith("_SETTINGS"):
674 rich.print(f" {project}_{var} = {check_env_file(var)}")
675 else:
676 rich.print(f" {project}_{var} = {check_env_dir(var)}")
678 rich.print()
679 rich.print("Generated locations and filenames")
681 with all_logging_disabled():
682 warnings.filterwarnings("ignore", category=UserWarning)
683 try:
684 rich.print(f" {get_data_storage_location() = }", flush=True, end="")
685 location = get_data_storage_location()
686 if not Path(location).exists():
687 if args.mkdir:
688 rich.print(f" [green]⟶ Creating data storage location: {location} (+ daily + obs)[/]")
689 Path(location).mkdir(parents=True)
690 (Path(location) / "daily").mkdir()
691 (Path(location) / "obs").mkdir()
692 else:
693 rich.print(" [red]⟶ ERROR: The data storage location doesn't exist![/]")
694 else:
695 rich.print()
696 except ValueError as exc:
697 rich.print(f" get_data_storage_location() = [red]{exc}[/]")
699 try:
700 rich.print(f" {get_conf_data_location() = }", flush=True, end="")
701 location = get_conf_data_location()
702 if not Path(location).exists():
703 if args.mkdir:
704 rich.print(f" [green]⟶ Creating configuration data location: {location}[/]")
705 Path(location).mkdir(parents=True)
706 else:
707 rich.print(" [red]⟶ ERROR: The configuration data location doesn't exist![/]")
708 else:
709 rich.print()
710 except ValueError as exc:
711 rich.print(f" get_conf_data_location() = [red]{exc}[/]")
713 try:
714 rich.print(f" {get_conf_repo_location() = }", flush=True, end="")
715 location = get_conf_repo_location()
716 if location is None or not Path(location).exists():
717 rich.print(" [red]⟶ ERROR: The configuration repository location doesn't exist![/]")
718 else:
719 rich.print()
720 except ValueError as exc:
721 rich.print(f" get_conf_repo_location() = [red]{exc}[/]")
723 try:
724 rich.print(f" {get_log_file_location() = }", flush=True, end="")
725 location = get_log_file_location()
726 if not Path(location).exists():
727 if args.mkdir:
728 rich.print(f" [green]⟶ Creating log files location: {location}[/]")
729 Path(location).mkdir(parents=True)
730 else:
731 rich.print(" [red]⟶ ERROR: The log files location doesn't exist![/]")
732 else:
733 rich.print()
734 except ValueError as exc:
735 rich.print(f" get_log_file_location() = [red]{exc}[/]")
737 try:
738 rich.print(f" {get_local_settings_path() = }", flush=True, end="")
739 location = get_local_settings_path()
740 if location is None or not Path(location).exists():
741 rich.print(" [red]⟶ ERROR: The local settings file is not defined or doesn't exist![/]")
742 else:
743 rich.print()
744 except ValueError as exc:
745 rich.print(f" get_local_settings() = [red]{exc}[/]")
747 if args.full:
748 rich.print()
749 rich.print(f" PYTHONPATH=[default]{os.environ.get('PYTHONPATH')}")
750 rich.print(f" PYTHONSTARTUP=[default]{os.environ.get('PYTHONSTARTUP')}")
751 rich.print()
752 python_path_msg = "\n ".join(sys.path)
753 rich.print(f" sys.path=[\n {python_path_msg}\n ]")
754 path_msg = "\n ".join(os.environ.get("PATH").split(":"))
755 rich.print(f" PATH=[\n {path_msg}\n ]")
757 help_msg = """
758[bold]PROJECT_INSTALL_LOCATION[/bold]:
759 This variable shall point to the location where the CGSE will be installed and is
760 usually set to `/cgse`. The variable is used by the [blue]update_cgse[/blue] script.
762[bold]PROJECT_CONF_DATA_LOCATION[/bold]:
763 This directory is the root folder for all the Setups of the site, the site is part
764 of the name. By default, this directory is located in the overall data storage folder.
766[bold]PROJECT_CONF_REPO_LOCATION[/bold]:
767 This variable is the root of the working copy of the 'plato-cgse-conf' project.
768 The value is usually set to `~/git/plato-cgse-conf`.
770[bold]PROJECT_DATA_STORAGE_LOCATION[/bold]:
771 This directory contains all the data files from the control servers and other
772 components. This folder is the root folder for all data from all cameras and
773 all sites. Below this folder shall be a folder for each of the cameras and in
774 there a sub-folder for each of the sites where that camera was tested. The
775 hierarchy is therefore: `$PLATO_DATA_STORAGE_LOCATION/<camera name>/<site id>.
776 Each of those folder shall contain at least the sub-folder [blue]daily[/blue], and [blue]obs[/blue].
778 There is also a file called [blue]obsid-table-<site id>.txt[/blue] which is maintained by
779 the configuration manager and contains information about the observations that
780 were run and the commands to start those observation.
782[bold]PROJECT_LOG_FILE_LOCATION[/bold]:
783 This directory contains the log files with all messages that were sent to the
784 logger control server. The log files are rotated on a daily basis at midnight UTC.
785 By default, this directory is also located in the overall data storage folder.
787[bold]PROJECT_LOCAL_SETTINGS[/bold]:
788 This file is used for local site-specific settings. When the environment
789 variable is not set, no local settings will be loaded. By default, this variable
790 is assumed to be '/cgse/local_settings.yaml'.
791"""
793 if args.doc:
794 rich.print(help_msg)
796 if not args.full:
797 rich.print()
798 rich.print("use the '--full' flag to get a more detailed report, '--doc' for help on the variables.")
800 # Do we still use these environment variables?
801 #
802 # PLATO_WORKDIR
803 # PLATO_COMMON_EGSE_PATH - YES
806ignore_m_warning("egse.env")
809if __name__ == "__main__": 809 ↛ 810line 809 didn't jump to line 810 because the condition on line 809 was never true
810 import sys
812 main(sys.argv[1:])