Loading noche/noche.py +17 −9 Original line number Diff line number Diff line Loading @@ -131,10 +131,10 @@ class Noche: def fill_keyword(self, k, val, silent=False): """ Fill new header keyword with its value. Why use this function instea of simply self.header[keyword] = value? Why use this function instead of simply self.header[keyword] = value? Because it also takes care of the format, rounding, and and significant digits taken from header tempalte. taken from header template. Parameters ---------- Loading @@ -152,7 +152,12 @@ class Noche: if typ.strip() == "float": with custom_float(): if val: val = header_round(val, int(fmt)) elif val == 0.0: val = header_round(val, int(fmt)) else: val = None self.header[k] = val Loading Loading @@ -215,8 +220,11 @@ class Noche: val = loc[k] if val is None: log.warning(f"{k:<8} : fixed value missing! Leave blank") if val == None: log.warning(f"{k:<8} : fixed value None! Leave blank") pass if val == "": log.warning(f"{k:<8} : fixed value empty! Leave blank") pass else: log.info(f"{k:<11} : fixed to the value : {val:<28}") Loading Loading @@ -582,11 +590,11 @@ class Noche: log.debug(sys._getframe().f_code.co_name) filename = fits_file hdul = fits.open(filename) self.hdu = hdul[0] with fits.open(filename) as hdul: self.hdu = hdul[0].copy() # to avoid I/O issues with writing def write_noctis_fits(self, filename=None, overwrite=True): data = self.hdu.data # Original data original_hdu = fits.ImageHDU(header=self.hdu.header, name="ORIGINAL") noche_hdu = fits.PrimaryHDU(data=data, header=self.header) Loading tests/test_core.py +130 −46 Original line number Diff line number Diff line # import unittest # import os # import argparse # import sys # from glob import glob # from noche import Noche # class TestNoche(unittest.TestCase): # def test_process_all_observatory_files(self): # print(f"\n--- Avvio Test: Processazione file Noche ---") # for obs in os.listdir("../examples/"): # print(obs) # for f in filter(lambda x: x[0] != '~', glob(f'../examples/{obs}/*')): # print(f) # try: # print("Instanciate Noche") # n = Noche() # print("Process") # n.load_noctis_observatory(obs, f) # print("Write") # filename = os.path.basename(f) # n.write_noctis_fits(f"./examples-tested/processed_{filename}") # print("Done") # del n # except Exception as e: # print(f"Il test è fallito per {obs}/{f} con l'errore: {e}") # raise # if __name__ == '__main__': # unittest.main(argv=sys.argv, exit=False) import unittest from astropy.time import Time import os import sys from glob import glob from noche import Noche from astropy.io.fits import Header import argparse class TestNoche(unittest.TestCase): # --- Configurazione e Rilevamento File --- # Directory radice per gli esempi EXAMPLES_ROOT = "../examples" output_dir = "./examples-tested" # Lista per contenere le tuple (nome_osservatorio, percorso_file) TEST_FILES = [] # Rilevamento dinamico dei file di test if os.path.exists(EXAMPLES_ROOT): # Itera attraverso i contenuti della directory degli esempi (i nomi degli osservatori) for obs in os.listdir(EXAMPLES_ROOT): obs_path = os.path.join(EXAMPLES_ROOT, obs) # Assicurati che sia una directory (l'osservatorio) if os.path.isdir(obs_path): # Cerca tutti i file all'interno della directory dell'osservatorio for f in glob(os.path.join(obs_path, '*')): filename = os.path.basename(f) # Applica il filtro originale: escludi i file che iniziano con '~' if not filename.startswith('~'): TEST_FILES.append((obs, f)) # --- Funzione per la Creazione Dinamica dei Test --- def create_test_for_file(observatory_name, file_path): """Genera un metodo unittest per un file specifico.""" def generated_test_method(self): filename = os.path.basename(file_path) print(f"\n--- Avvio Test: {observatory_name}/{filename} ---") def setUp(self): self.noche = Noche("noche/headers/header_base.ini") self.noche.load_observatory("noche/observatories/oarpaf.ini") def test_init_creates_header(self): self.assertIsInstance(self.noche.header, Header) def test_set_location(self): self.noche.set_location(10.0, 45.0, 100.0) self.assertEqual(self.noche.header['OBS-LONG'], 10.0) self.assertEqual(self.noche.header['OBS-LAT'], 45.0) self.assertEqual(self.noche.header['OBS-ELEV'], 100.0) def test_set_obstime(self): now = Time.now() self.noche.set_obstime(now) self.assertEqual(self.noche.header['DATE-OBS'], now.isot) self.assertAlmostEqual(self.noche.header['MJD-OBS'], now.mjd, places=5) def test_set_coordinates(self): self.noche.set_coordinates(ra=10.0, dec=20.0) self.assertIn('RA', self.noche.header) self.assertIn('DEC', self.noche.header) self.assertAlmostEqual(self.noche.header['RA_DEG'], 150.0, places=4) # 10h -> 150deg self.assertAlmostEqual(self.noche.header['DEC_DEG'], 20.0, places=4) def test_set_object_and_resolve(self): self.noche.set_object("Vega") self.assertEqual(self.noche.header['OBJECT'], "Vega") def test_check_empty_does_not_raise(self): # Should not raise even if empty fields exist try: self.noche.check_empty() # 1. Instanzia Noche n = Noche() # 2. Processa il file n.load_noctis_observatory(observatory_name, file_path) # 3. Scrivi l'output (Crea la directory di output se non esiste) os.makedirs(output_dir, exist_ok=True) output_path = os.path.join(output_dir, f"processed_{filename}") n.write_noctis_fits(output_path) print(f"Successo: {observatory_name}/{filename}") # 4. Asserzione: verifica che il file di output sia stato creato self.assertTrue(os.path.exists(output_path), f"Il file di output non è stato creato: {output_path}") # # 5. Pulizia # del n except Exception as e: self.fail(f"check_empty() raised an exception: {e}") # Cattura l'errore, stampa un messaggio descrittivo e fallisce il test print(f"Il test è fallito per {observatory_name}/{filename} con l'errore: {e}") raise # Ri-lancia l'eccezione per far fallire il singolo test # Crea un nome di metodo sicuro e descrittivo per unittest # Sostituisce caratteri problematici (come . e -) con _ safe_name = os.path.basename(file_path).replace('.', '_').replace('-', '_') test_method_name = f"test_process_{observatory_name}_{safe_name}" generated_test_method.__name__ = test_method_name return generated_test_method # --- Definizione TestCase --- class TestNoche(unittest.TestCase): """ TestCase popolato dinamicamente con un metodo di test per ogni file fits trovato nelle directory degli esempi. """ pass # Popolamento dinamico della classe TestNoche con i metodi di test for obs_name, file_path in TEST_FILES: test_func = create_test_for_file(obs_name, file_path) # Assegna il metodo di test alla classe TestCase setattr(TestNoche, test_func.__name__, test_func) # Se non vengono trovati file, aggiungi un test segnaposto per evitare 'no tests found' if not TEST_FILES: def test_no_files_found(self): print(f"\n[ATTENZIONE] Nessun file di esempio trovato in {EXAMPLES_ROOT}. Test ignorato.") self.skipTest(f"Nessun file di esempio trovato in {EXAMPLES_ROOT}.") setattr(TestNoche, 'test_no_files_found', test_no_files_found) def test_parse_various_types(self): self.assertEqual(self.noche._parse("42"), 42) self.assertEqual(self.noche._parse("3.14"), 3.14) self.assertEqual(self.noche._parse("True"), True) self.assertEqual(self.noche._parse("False"), False) self.assertEqual(self.noche._parse("some string"), "some string") self.assertIsNone(self.noche._parse(" ")) # --- Esecuzione --- if __name__ == '__main__': unittest.main() # Esegue tutti i test trovati nella classe TestNoche unittest.main(argv=sys.argv, exit=False) Loading
noche/noche.py +17 −9 Original line number Diff line number Diff line Loading @@ -131,10 +131,10 @@ class Noche: def fill_keyword(self, k, val, silent=False): """ Fill new header keyword with its value. Why use this function instea of simply self.header[keyword] = value? Why use this function instead of simply self.header[keyword] = value? Because it also takes care of the format, rounding, and and significant digits taken from header tempalte. taken from header template. Parameters ---------- Loading @@ -152,7 +152,12 @@ class Noche: if typ.strip() == "float": with custom_float(): if val: val = header_round(val, int(fmt)) elif val == 0.0: val = header_round(val, int(fmt)) else: val = None self.header[k] = val Loading Loading @@ -215,8 +220,11 @@ class Noche: val = loc[k] if val is None: log.warning(f"{k:<8} : fixed value missing! Leave blank") if val == None: log.warning(f"{k:<8} : fixed value None! Leave blank") pass if val == "": log.warning(f"{k:<8} : fixed value empty! Leave blank") pass else: log.info(f"{k:<11} : fixed to the value : {val:<28}") Loading Loading @@ -582,11 +590,11 @@ class Noche: log.debug(sys._getframe().f_code.co_name) filename = fits_file hdul = fits.open(filename) self.hdu = hdul[0] with fits.open(filename) as hdul: self.hdu = hdul[0].copy() # to avoid I/O issues with writing def write_noctis_fits(self, filename=None, overwrite=True): data = self.hdu.data # Original data original_hdu = fits.ImageHDU(header=self.hdu.header, name="ORIGINAL") noche_hdu = fits.PrimaryHDU(data=data, header=self.header) Loading
tests/test_core.py +130 −46 Original line number Diff line number Diff line # import unittest # import os # import argparse # import sys # from glob import glob # from noche import Noche # class TestNoche(unittest.TestCase): # def test_process_all_observatory_files(self): # print(f"\n--- Avvio Test: Processazione file Noche ---") # for obs in os.listdir("../examples/"): # print(obs) # for f in filter(lambda x: x[0] != '~', glob(f'../examples/{obs}/*')): # print(f) # try: # print("Instanciate Noche") # n = Noche() # print("Process") # n.load_noctis_observatory(obs, f) # print("Write") # filename = os.path.basename(f) # n.write_noctis_fits(f"./examples-tested/processed_{filename}") # print("Done") # del n # except Exception as e: # print(f"Il test è fallito per {obs}/{f} con l'errore: {e}") # raise # if __name__ == '__main__': # unittest.main(argv=sys.argv, exit=False) import unittest from astropy.time import Time import os import sys from glob import glob from noche import Noche from astropy.io.fits import Header import argparse class TestNoche(unittest.TestCase): # --- Configurazione e Rilevamento File --- # Directory radice per gli esempi EXAMPLES_ROOT = "../examples" output_dir = "./examples-tested" # Lista per contenere le tuple (nome_osservatorio, percorso_file) TEST_FILES = [] # Rilevamento dinamico dei file di test if os.path.exists(EXAMPLES_ROOT): # Itera attraverso i contenuti della directory degli esempi (i nomi degli osservatori) for obs in os.listdir(EXAMPLES_ROOT): obs_path = os.path.join(EXAMPLES_ROOT, obs) # Assicurati che sia una directory (l'osservatorio) if os.path.isdir(obs_path): # Cerca tutti i file all'interno della directory dell'osservatorio for f in glob(os.path.join(obs_path, '*')): filename = os.path.basename(f) # Applica il filtro originale: escludi i file che iniziano con '~' if not filename.startswith('~'): TEST_FILES.append((obs, f)) # --- Funzione per la Creazione Dinamica dei Test --- def create_test_for_file(observatory_name, file_path): """Genera un metodo unittest per un file specifico.""" def generated_test_method(self): filename = os.path.basename(file_path) print(f"\n--- Avvio Test: {observatory_name}/{filename} ---") def setUp(self): self.noche = Noche("noche/headers/header_base.ini") self.noche.load_observatory("noche/observatories/oarpaf.ini") def test_init_creates_header(self): self.assertIsInstance(self.noche.header, Header) def test_set_location(self): self.noche.set_location(10.0, 45.0, 100.0) self.assertEqual(self.noche.header['OBS-LONG'], 10.0) self.assertEqual(self.noche.header['OBS-LAT'], 45.0) self.assertEqual(self.noche.header['OBS-ELEV'], 100.0) def test_set_obstime(self): now = Time.now() self.noche.set_obstime(now) self.assertEqual(self.noche.header['DATE-OBS'], now.isot) self.assertAlmostEqual(self.noche.header['MJD-OBS'], now.mjd, places=5) def test_set_coordinates(self): self.noche.set_coordinates(ra=10.0, dec=20.0) self.assertIn('RA', self.noche.header) self.assertIn('DEC', self.noche.header) self.assertAlmostEqual(self.noche.header['RA_DEG'], 150.0, places=4) # 10h -> 150deg self.assertAlmostEqual(self.noche.header['DEC_DEG'], 20.0, places=4) def test_set_object_and_resolve(self): self.noche.set_object("Vega") self.assertEqual(self.noche.header['OBJECT'], "Vega") def test_check_empty_does_not_raise(self): # Should not raise even if empty fields exist try: self.noche.check_empty() # 1. Instanzia Noche n = Noche() # 2. Processa il file n.load_noctis_observatory(observatory_name, file_path) # 3. Scrivi l'output (Crea la directory di output se non esiste) os.makedirs(output_dir, exist_ok=True) output_path = os.path.join(output_dir, f"processed_{filename}") n.write_noctis_fits(output_path) print(f"Successo: {observatory_name}/{filename}") # 4. Asserzione: verifica che il file di output sia stato creato self.assertTrue(os.path.exists(output_path), f"Il file di output non è stato creato: {output_path}") # # 5. Pulizia # del n except Exception as e: self.fail(f"check_empty() raised an exception: {e}") # Cattura l'errore, stampa un messaggio descrittivo e fallisce il test print(f"Il test è fallito per {observatory_name}/{filename} con l'errore: {e}") raise # Ri-lancia l'eccezione per far fallire il singolo test # Crea un nome di metodo sicuro e descrittivo per unittest # Sostituisce caratteri problematici (come . e -) con _ safe_name = os.path.basename(file_path).replace('.', '_').replace('-', '_') test_method_name = f"test_process_{observatory_name}_{safe_name}" generated_test_method.__name__ = test_method_name return generated_test_method # --- Definizione TestCase --- class TestNoche(unittest.TestCase): """ TestCase popolato dinamicamente con un metodo di test per ogni file fits trovato nelle directory degli esempi. """ pass # Popolamento dinamico della classe TestNoche con i metodi di test for obs_name, file_path in TEST_FILES: test_func = create_test_for_file(obs_name, file_path) # Assegna il metodo di test alla classe TestCase setattr(TestNoche, test_func.__name__, test_func) # Se non vengono trovati file, aggiungi un test segnaposto per evitare 'no tests found' if not TEST_FILES: def test_no_files_found(self): print(f"\n[ATTENZIONE] Nessun file di esempio trovato in {EXAMPLES_ROOT}. Test ignorato.") self.skipTest(f"Nessun file di esempio trovato in {EXAMPLES_ROOT}.") setattr(TestNoche, 'test_no_files_found', test_no_files_found) def test_parse_various_types(self): self.assertEqual(self.noche._parse("42"), 42) self.assertEqual(self.noche._parse("3.14"), 3.14) self.assertEqual(self.noche._parse("True"), True) self.assertEqual(self.noche._parse("False"), False) self.assertEqual(self.noche._parse("some string"), "some string") self.assertIsNone(self.noche._parse(" ")) # --- Esecuzione --- if __name__ == '__main__': unittest.main() # Esegue tutti i test trovati nella classe TestNoche unittest.main(argv=sys.argv, exit=False)