1- # This code is part of X-ray: Generate and Analyse (XGA), a module designed for the XMM Cluster Survey (XCS).
2- # Last modified by David J Turner (djturner@umbc.edu) 5/21/26, 12:59 PM . Copyright (c) The Contributors.
1+ # This code is a part of X-ray: Generate and Analyse (XGA), a module designed for the XMM Cluster Survey (XCS).
2+ # Last modified by David J Turner (djturner@umbc.edu) 26/05/2026, 14:37 . Copyright (c) The Contributors
33
44import importlib .resources
55import json
@@ -257,33 +257,31 @@ def _get_xspec_info() -> Tuple[Union[Version, None], List[str], List[str]]:
257257 return xspec_version , fit_methods , abund_tables
258258
259259
260- def _initialise_xga () :
260+ def _prep_xga_config_file () -> Tuple [ dict , str , str ] :
261261 """
262- The internal function that actually performs the XGA configuration and census loading, as well as
263- checking for the availability of backend software.
264- """
265- global _INITIALISED , CONFIG_PATH , CONFIG_FILE , xga_conf , VALID_CONFIG , USABLE , CENSUS , BLACKLIST , \
266- COMBINED_INSTS , SAS_VERSION , SAS_AVAIL , ESASS_VERSION , ESASS_AVAIL , CIAO_VERSION , CIAO_AVAIL , \
267- CALDB_VERSION , CALDB_AVAIL , XSPEC_VERSION , OUTPUT , NUM_CORES , CENSUS_FILES , BLACKLIST_FILES , \
268- SASERROR_LIST , SASWARNING_LIST , XSPEC_FIT_METHOD , ABUND_TABLES
262+ This function prepares the XGA configuration file, either generating it for the first time (in the
263+ default location or a user-specified directory), updating it if it already exists and was set up for a
264+ previous version of XGA.
265+
266+ No global constant variables are set in this function, so the current state of the configuration
267+ dictionary, the configuration directory path, and the full path to the current configuration file
268+ are returned, so that _initialise_xga function can set them up as global constants.
269269
270+ :return: Local variables containing the current configuration dictionary, the current configuration
271+ path, and the current full path to the configuration file.
272+ :rtype: Tuple[dict, str, str]
273+ """
274+ # ------------------ Preparing for config file reading/generation -------------------
270275 if 'XGA_CONFIG_DIR' in os .environ :
271- CONFIG_PATH = os .path .abspath (os .environ ['XGA_CONFIG_DIR' ])
276+ cur_config_path = os .path .abspath (os .environ ['XGA_CONFIG_DIR' ])
272277 else :
273- CONFIG_PATH = os .path .join (os .environ .get ('XDG_CONFIG_HOME' ,
278+ cur_config_path = os .path .join (os .environ .get ('XDG_CONFIG_HOME' ,
274279 os .path .join (os .path .expanduser ('~' ), '.config' )), 'xga' )
275280
276- if not os .path .exists (CONFIG_PATH ):
277- os .makedirs (CONFIG_PATH )
278-
279- CONFIG_FILE = os .path .join (CONFIG_PATH , 'xga.cfg' )
281+ os .makedirs (cur_config_path , exist_ok = True )
280282
281- # These are used for the observation census files
282- CENSUS_FILES = {tel : os .path .join (CONFIG_PATH , tel , '{}_census.csv' .format (tel )) for tel in ALLOWED_INST }
283- BLACKLIST_FILES = {tel : os .path .join (CONFIG_PATH , tel , '{}_blacklist.csv' .format (tel )) for tel in ALLOWED_INST }
283+ cur_config_file = os .path .join (cur_config_path , 'xga.cfg' )
284284
285- USABLE = {tele : False for tele in TELESCOPES }
286- VALID_CONFIG = {tel : False for tel in TELESCOPES }
287285 # ------------- Creating/checking the entries in the configuration file -------------
288286 # This chunk of utils will be dedicated to making sure that the configuration file has been created (by default with
289287 # sections for every telescope that XGA supports), or that if it already exists it contains valid entries.
@@ -293,7 +291,7 @@ def _initialise_xga():
293291
294292 # In this case we find that the configuration file does not exist, and we set it up using the default sections and
295293 # configurations that were set up toward the top of this file
296- if not os .path .exists (CONFIG_FILE ):
294+ if not os .path .exists (cur_config_file ):
297295 # Define a configuration object
298296 xga_default = ConfigParser ()
299297 # This adds the overall XGA setup section - controls global things like where XGA generated files are stored, and
@@ -310,17 +308,17 @@ def _initialise_xga():
310308 xga_default [cur_sec_name ] = tele_conf_sects [tel ]
311309
312310 # The default configuration file is now written to the path that we expect to find the config file at
313- with open (CONFIG_FILE , 'w' ) as new_cfg :
311+ with open (cur_config_file , 'w' ) as new_cfg :
314312 xga_default .write (new_cfg )
315313
316314 # First time run triggers this message - it used to be an error, and so XGA wouldn't advance beyond this point
317315 # with a new configuration file, but we want people to be able to use the product classes without configuring
318- warn ("This is the first time you've used XGA; to use most functionality you will need to configure {} to match "
319- " your setup, though you can use product classes regardless.". format ( CONFIG_FILE ) , stacklevel = 2 )
316+ warn (f "This is the first time you've used XGA; to use most functionality you will need to configure "
317+ f" { cur_config_file } to match your setup, though you can use product classes regardless." , stacklevel = 2 )
320318
321- xga_conf = ConfigParser ()
319+ cur_xga_conf = ConfigParser ()
322320 # It would be nice to do configparser interpolation, but it wouldn't handle the lists of energy values
323- xga_conf .read (CONFIG_FILE )
321+ cur_xga_conf .read (cur_config_file )
324322
325323 # If the current section name exists in xga_conf then all is well, there hasn't been an update to XGA which added
326324 # a new telescope installed - however if a section is missing then we need to add it. This is slightly inelegant
@@ -331,20 +329,42 @@ def _initialise_xga():
331329 altered = False
332330 for tel in TELESCOPES :
333331 cur_sec_name = "{}_FILES" .format (tel .upper ())
334- if cur_sec_name not in xga_conf :
332+ if cur_sec_name not in cur_xga_conf :
335333 # If there isn't already a files section for one of the telescopes now supported by XGA, then we add it to
336334 # the existing configuration file
337- xga_conf .add_section (cur_sec_name )
338- xga_conf [cur_sec_name ] = tele_conf_sects [tel ]
335+ cur_xga_conf .add_section (cur_sec_name )
336+ cur_xga_conf [cur_sec_name ] = tele_conf_sects [tel ]
339337 altered = True
340338 # If we altered the existing configuration file, then we need to save the altered configuration to disk
341339 if altered :
342340 with open (CONFIG_FILE , 'w' ) as update_cfg :
343- xga_conf .write (update_cfg )
341+ cur_xga_conf .write (update_cfg )
344342
345343 # As it turns out, the ConfigParser class is a pain to work with, so we're converting to a dict here
346344 # Addressing works just the same
347- xga_conf = {str (sect ): dict (xga_conf [str (sect )]) for sect in xga_conf }
345+ cur_xga_conf = {str (sect ): dict (cur_xga_conf [str (sect )]) for sect in cur_xga_conf }
346+
347+ return cur_xga_conf , cur_config_path , cur_config_file
348+
349+
350+ def _initialise_xga ():
351+ """
352+ The internal function that actually performs the XGA configuration and census loading, as well as
353+ checking for the availability of backend software.
354+ """
355+ global _INITIALISED , CONFIG_PATH , CONFIG_FILE , xga_conf , VALID_CONFIG , USABLE , CENSUS , BLACKLIST , \
356+ COMBINED_INSTS , SAS_VERSION , SAS_AVAIL , ESASS_VERSION , ESASS_AVAIL , CIAO_VERSION , CIAO_AVAIL , \
357+ CALDB_VERSION , CALDB_AVAIL , XSPEC_VERSION , OUTPUT , NUM_CORES , CENSUS_FILES , BLACKLIST_FILES , \
358+ SASERROR_LIST , SASWARNING_LIST , XSPEC_FIT_METHOD , ABUND_TABLES
359+
360+ xga_conf , CONFIG_PATH , CONFIG_FILE = _prep_xga_config_file ()
361+
362+ # These are used for the observation census files
363+ CENSUS_FILES = {tel : os .path .join (CONFIG_PATH , tel , '{}_census.csv' .format (tel )) for tel in ALLOWED_INST }
364+ BLACKLIST_FILES = {tel : os .path .join (CONFIG_PATH , tel , '{}_blacklist.csv' .format (tel )) for tel in ALLOWED_INST }
365+
366+ USABLE = {tele : False for tele in TELESCOPES }
367+ VALID_CONFIG = {tel : False for tel in TELESCOPES }
348368
349369 # ------------- Final setup of important constants from the configuration file -------------
350370 # We make sure to create the absolute output path from what was specified in the configuration file
0 commit comments