Commit 852c1347aa30f7487ba504091fc47b0d1fc7158c

Authored by Alain Klotz
1 parent 9fe16961
Exists in master

Add wildcards in filenames.

Showing 2 changed files with 252 additions and 45 deletions   Show diff stats
src/guitastro/dates.py
... ... @@ -263,9 +263,9 @@ class Date(GuitastroTools):
263 263  
264 264 .. note:: Prefer using objdate.date() followed by objdate.jd().
265 265 """
266   - # --- First we do not process if date is ever a Date object
  266 + # --- First we compute jd if date is ever a Date object
267 267 if (isinstance(date, Date)):
268   - return date
  268 + date = date.jd()
269 269 # --- Decode the date
270 270 jd = 0
271 271 init_dateformat = 0
... ...
src/guitastro/filenames.py
... ... @@ -215,6 +215,8 @@ class FileNames(FileNamesException, GuitastroTools):
215 215 self._verbose_level = self.VERBOSE_NONE
216 216 self._longiau_deg = 0.0
217 217 self._naming = self.NAMING_NONE
  218 + self._pathing = self.PATHING_NONE
  219 + self._pathnaming = self._naming
218 220 self._outfilename = os.path.join(self._image_dir, "noname"+self.extension())
219 221 # --- naming_rule
220 222 if len(args) > 0 :
... ... @@ -348,7 +350,7 @@ class FileNames(FileNamesException, GuitastroTools):
348 350 texte += "Example: L0_20221109_235406123456_1_TNC_CH1_0123456789_001_001\n"
349 351 texte += "UUU, CCC are accronyms (string)\n"
350 352 texte += "V, IIIIIIIIII, PPP, FFF are digits (int)\n"
351   - texte += "CCC is a Channel for L0,L1 ftype levels but should by the Album for L2 level"
  353 + texte += "CCC is a Channel for L0,L1 ftype levels but should be the Album for L2 level"
352 354 return texte
353 355  
354 356 def __naming_rules_ros1(self, section):
... ... @@ -597,29 +599,48 @@ class FileNames(FileNamesException, GuitastroTools):
597 599 fname = fn.naming_set(**param)
598 600  
599 601 The answer should be L0_20221109_235406123456_TNC_1_CH1_0123456789_001_001.
600   - If param['date'] is "*" then the date and time will be the current UTC time.
  602 + For naming = "PyROS.1", if param['date'] is "*" then the date and time will be the current UTC time.
  603 +
  604 + If a key is lacking in the dictionary, a wildcard is replaced. Useful to get a glob.
601 605 """
602 606 see_rules = self._see_naming_rules
  607 + # --- wilcards
  608 + if self._naming == self.NAMING_NONE:
  609 + wildcard = "*"
  610 + elif self._naming == self.NAMING_PYROS1:
  611 + wildcard = "??_????????_????????????_?_???_???_??????????_???_???"
  612 + elif self._naming == self.NAMING_ROS1:
  613 + wildcard = "??_????????_????????????_??????_????????"
  614 + # ---
  615 + na = len(args)
  616 + nk = len(kwargs)
603 617 if self._naming == self.NAMING_NONE:
604   - fname = args[0]
  618 + if na > 0:
  619 + fname = args[0]
605 620 if self._naming == self.NAMING_PYROS1:
606   - if len(args) > 0:
607   - if isinstance(args[0],dict):
  621 + if na > 0:
  622 + # case the dict is not **kwargs but *args
  623 + if isinstance(args[0], dict):
608 624 kwargs = args[0]
609   - elif len(kwargs)==0:
610   - return self.naming_rules()
  625 + nk = len(kwargs)
  626 + else:
  627 + texte = "Dictionary of input parameters not found " + see_rules
  628 + raise FileNamesException(FileNamesException.BAD_PARAM, texte)
  629 + elif nk == 0:
  630 + return wildcard
611 631 # -- read kwargs
  632 + wildcards = wildcard.split("_")
612 633 param = {}
613   - param['ftype'] = ""
614   - param['date'] = ""
615   - param['time'] = ""
616   - param['version'] = ""
617   - param['unit'] = ""
618   - param['channel'] = ""
619   - param['id_seq'] = ""
620   - param['plane'] = ""
621   - param['frame'] = ""
622   - if len(kwargs) > 0:
  634 + param['ftype'] = wildcards[0]
  635 + param['date'] = wildcards[1]
  636 + param['time'] = wildcards[2]
  637 + param['version'] = wildcards[3]
  638 + param['unit'] = wildcards[4]
  639 + param['channel'] = wildcards[5]
  640 + param['id_seq'] = wildcards[6]
  641 + param['plane'] = wildcards[7]
  642 + param['frame'] = wildcards[8]
  643 + if nk > 0:
623 644 for key, val in kwargs.items():
624 645 if key in param.keys():
625 646 param[key] = val
... ... @@ -630,13 +651,16 @@ class FileNames(FileNamesException, GuitastroTools):
630 651 raise FileNamesException(FileNamesException.EMPTY_STRING, texte)
631 652 # --- verify ftype
632 653 if isinstance(param['ftype'],str):
633   - if param['ftype'] not in self._naming_0_stypes:
634   - texte = f"File type {param['ftype']} not found amongst {self._naming_0_stypes}" + see_rules
635   - raise FileNamesException(FileNamesException.BAD_PARAM, texte)
  654 + if param['ftype'] != wildcards[0]:
  655 + if param['ftype'] not in self._naming_0_stypes:
  656 + texte = f"File type {param['ftype']} not found amongst {self._naming_0_stypes}" + see_rules
  657 + raise FileNamesException(FileNamesException.BAD_PARAM, texte)
636 658 # --- verify date
637 659 valid = False
638 660 if isinstance(param['date'],str):
639   - if len(param['date']) == 8:
  661 + if param['date'] == wildcards[1]:
  662 + valid = True
  663 + elif len(param['date']) == 8:
640 664 if param['date'].isdigit():
641 665 valid = True
642 666 elif param['date'] == "*":
... ... @@ -652,7 +676,9 @@ class FileNames(FileNamesException, GuitastroTools):
652 676 # --- verify time
653 677 valid = False
654 678 if isinstance(param['time'],str):
655   - if len(param['time']) == 12:
  679 + if param['time'] == wildcards[2]:
  680 + valid = True
  681 + elif len(param['time']) == 12:
656 682 if param['time'].isdigit():
657 683 valid = True
658 684 if valid == False:
... ... @@ -661,7 +687,9 @@ class FileNames(FileNamesException, GuitastroTools):
661 687 # --- verify version
662 688 valid = False
663 689 if isinstance(param['version'],str):
664   - if len(param['version']) == 1:
  690 + if param['version'] == wildcards[3]:
  691 + valid = True
  692 + elif len(param['version']) == 1:
665 693 valid = True
666 694 elif isinstance(param['version'],int):
667 695 param['version'] = f"{param['version']:01d}"
... ... @@ -672,7 +700,9 @@ class FileNames(FileNamesException, GuitastroTools):
672 700 # --- verify unit
673 701 valid = False
674 702 if isinstance(param['unit'],str):
675   - if len(param['unit']) == 3:
  703 + if param['unit'] == wildcards[4]:
  704 + valid = True
  705 + elif len(param['unit']) == 3:
676 706 valid = True
677 707 if valid == False:
678 708 texte = f"Unit {param['unit']} must be a string of 3 characters" + see_rules
... ... @@ -680,7 +710,9 @@ class FileNames(FileNamesException, GuitastroTools):
680 710 # --- verify channel
681 711 valid = False
682 712 if isinstance(param['channel'],str):
683   - if len(param['channel']) == 3:
  713 + if param['channel'] == wildcards[5]:
  714 + valid = True
  715 + elif len(param['channel']) == 3:
684 716 valid = True
685 717 if valid == False:
686 718 texte = f"Channel {param['channel']} must be a string of 3 characters" + see_rules
... ... @@ -688,7 +720,9 @@ class FileNames(FileNamesException, GuitastroTools):
688 720 # --- verify id_seq
689 721 valid = False
690 722 if isinstance(param['id_seq'],str):
691   - if len(param['id_seq']) == 10:
  723 + if param['id_seq'] == wildcards[6]:
  724 + valid = True
  725 + elif len(param['id_seq']) == 10:
692 726 valid = True
693 727 elif isinstance(param['id_seq'],int):
694 728 param['id_seq'] = f"{param['id_seq']:010d}"
... ... @@ -699,7 +733,9 @@ class FileNames(FileNamesException, GuitastroTools):
699 733 # --- verify plane
700 734 valid = False
701 735 if isinstance(param['plane'],str):
702   - if len(param['plane']) == 3:
  736 + if param['plane'] == wildcards[7]:
  737 + valid = True
  738 + elif len(param['plane']) == 3:
703 739 valid = True
704 740 elif isinstance(param['plane'],int):
705 741 param['plane'] = f"{param['plane']:03d}"
... ... @@ -710,7 +746,9 @@ class FileNames(FileNamesException, GuitastroTools):
710 746 # --- verify frame
711 747 valid = False
712 748 if isinstance(param['frame'],str):
713   - if len(param['frame']) == 3:
  749 + if param['frame'] == wildcards[8]:
  750 + valid = True
  751 + elif len(param['frame']) == 3:
714 752 valid = True
715 753 elif isinstance(param['frame'],int):
716 754 param['frame'] = f"{param['frame']:03d}"
... ... @@ -721,19 +759,25 @@ class FileNames(FileNamesException, GuitastroTools):
721 759 # --- form final file name
722 760 fname = param['ftype']+"_"+param['date']+"_"+param['time']+"_"+param['version']+"_"+param['unit']+"_"+param['channel']+"_"+param['id_seq']+"_"+param['plane']+"_"+param['frame']
723 761 if self._naming == self.NAMING_ROS1:
724   - if len(args) > 0:
725   - if isinstance(args[0],dict):
  762 + if na > 0:
  763 + # case the dict is not **kwargs but *args
  764 + if isinstance(args[0], dict):
726 765 kwargs = args[0]
727   - elif len(kwargs)==0:
728   - return self.naming_rules()
  766 + nk = len(kwargs)
  767 + else:
  768 + texte = "Dictionary of input parameters not found " + see_rules
  769 + raise FileNamesException(FileNamesException.BAD_PARAM, texte)
  770 + elif nk == 0:
  771 + return wildcard
729 772 # -- read kwargs
  773 + wildcards = wildcard.split("_")
730 774 param = {}
731   - param['ftype'] = ""
732   - param['date'] = ""
733   - param['time'] = ""
734   - param['id_scene'] = ""
735   - param['unit'] = ""
736   - if len(kwargs) > 0:
  775 + param['ftype'] = wildcards[0]
  776 + param['date'] = wildcards[1]
  777 + param['time'] = wildcards[2]
  778 + param['id_scene'] = "????????????"
  779 + param['unit'] = "??"
  780 + if nk > 0:
737 781 for key, val in kwargs.items():
738 782 if key in param.keys():
739 783 param[key] = val
... ... @@ -744,13 +788,17 @@ class FileNames(FileNamesException, GuitastroTools):
744 788 raise FileNamesException(FileNamesException.EMPTY_STRING, texte)
745 789 # --- verify ftype
746 790 if isinstance(param['ftype'],str):
  791 + if param['ftype'] == wildcards[0]:
  792 + valid = True
747 793 if param['ftype'] not in self._naming_1_stypes:
748 794 texte = f"File type {param['ftype']} not found amongst {self._naming_1_stypes}" + see_rules
749 795 raise FileNamesException(FileNamesException.BAD_PARAM, texte)
750 796 # --- verify date
751 797 valid = False
752 798 if isinstance(param['date'],str):
753   - if len(param['date']) == 8:
  799 + if param['date'] == wildcards[1]:
  800 + valid = True
  801 + elif len(param['date']) == 8:
754 802 if param['date'].isdigit():
755 803 valid = True
756 804 elif param['date'] == "*":
... ... @@ -766,6 +814,8 @@ class FileNames(FileNamesException, GuitastroTools):
766 814 # --- verify time
767 815 valid = False
768 816 if isinstance(param['time'],str):
  817 + if param['time'] == wildcards[2]:
  818 + valid = True
769 819 if len(param['time']) == 9:
770 820 if param['time'].isdigit():
771 821 valid = True
... ... @@ -775,7 +825,9 @@ class FileNames(FileNamesException, GuitastroTools):
775 825 # --- verify id_scene
776 826 valid = False
777 827 if isinstance(param['id_scene'],str):
778   - if len(param['id_scene']) == 12:
  828 + if param['id_scene'] == wildcards[3]:
  829 + valid = True
  830 + elif len(param['id_scene']) == 12:
779 831 valid = True
780 832 elif isinstance(param['id_scene'],int):
781 833 param['id_scene'] = f"{param['id_scene']:012d}"
... ... @@ -786,7 +838,9 @@ class FileNames(FileNamesException, GuitastroTools):
786 838 # --- verify unit
787 839 valid = False
788 840 if isinstance(param['unit'],str):
789   - if len(param['unit']) == 2:
  841 + if param['id_scene'] == wildcards[4]:
  842 + valid = True
  843 + elif len(param['unit']) == 2:
790 844 valid = True
791 845 if valid == False:
792 846 texte = f"Unit {param['unit']} must be a string of 2 characters" + see_rules
... ... @@ -795,6 +849,33 @@ class FileNames(FileNamesException, GuitastroTools):
795 849 fname = param['ftype']+"_"+param['date']+"_"+param['time']+"_"+param['id_scene'][:6]+"_"+param['id_scene'][6:]+param['unit']
796 850 return fname
797 851  
  852 + def naming_date(self, date:Date) -> str:
  853 + """Compute dates in various string formats.
  854 +
  855 + It is a tool that returns a dictionary allowing to form names.
  856 + """
  857 + date = Date(date);
  858 + digits = date.digits(6)
  859 + d = {}
  860 + d['iso'] = date.iso(6, 'T')
  861 + d['iso_'] = d['iso'].replace("-","_")
  862 + d['iso_'] = d['iso_'].replace(":","_")
  863 + d['iso_'] = d['iso_'].replace(".","_")
  864 + d['iso_'] = d['iso_'].replace("T","_")
  865 + d['yyyy'] = digits[:4]
  866 + d['mm'] = digits[4:6]
  867 + d['dd'] = digits[6:8]
  868 + d['hh'] = digits[8:10]
  869 + d['mm'] = digits[10:12]
  870 + d['ss'] = digits[12:14]
  871 + d['yyyymmdd'] = digits[:8]
  872 + d['hhmmss'] = digits[8:14]
  873 + d['hhmmssssssss'] = d['hhmmss'] + digits[15:21]
  874 + return d
  875 +
  876 + def naming_wildcards(self, prepath, pkw:dict, nkw:dict, extension="") -> str:
  877 + pass
  878 +
798 879 # =============================================
799 880 # Managing pathing
800 881 # =============================================
... ... @@ -1103,6 +1184,108 @@ class FileNames(FileNamesException, GuitastroTools):
1103 1184 pname = os.path.join(yyyy, mm, dd)
1104 1185 return pname
1105 1186  
  1187 +
  1188 + # =============================================
  1189 + # Managing pathnaming (path + names)
  1190 + # =============================================
  1191 +
  1192 + def pathnamings(self):
  1193 + """List of pathnamings
  1194 +
  1195 + Path and file names can be formed using given rules.
  1196 + This method returns a list of all possible pathnaming rules.
  1197 + The pathanming should be one amongst the namings (pathnaming and naming shared the same symbols).
  1198 + """
  1199 + return self._naming_list
  1200 +
  1201 + def pathnaming(self, *args):
  1202 + """Get the current pathnaming of files or set a new one
  1203 +
  1204 + The choice of a pathnaming will set the pathing and the naming.
  1205 +
  1206 + Args:
  1207 + *args: a string with a new pathnaming of files.
  1208 + See the list using pathnamings().
  1209 +
  1210 + Returns:
  1211 + The new selected pathnaming.
  1212 +
  1213 + Example: To get the current pathnaming
  1214 +
  1215 + ::
  1216 +
  1217 + fn = FileNames()
  1218 + pathnaming = fn.pathnaming()
  1219 +
  1220 + Example: To select a new pathnaming
  1221 +
  1222 + ::
  1223 +
  1224 + fn = FileNames()
  1225 + fn.pathnaming("PyROS.1")
  1226 +
  1227 + """
  1228 + if len(args) >= 1:
  1229 + new_naming = args[0]
  1230 + new_namingu = new_naming.upper()
  1231 + n = len(self._naming_list)
  1232 + found = False
  1233 + for k in range(n):
  1234 + naming = self._naming_list[k]
  1235 + if naming.upper() == new_namingu:
  1236 + self._pathnaming = k
  1237 + found = True
  1238 + if found == False:
  1239 + texte = f"{new_naming} not found amongst {self._naming_list}"
  1240 + raise FileNamesException(FileNamesException.NO_NAMING_FOUND, texte)
  1241 + self._naming = self._pathnaming
  1242 + if self._pathnaming == self.NAMING_PYROS1:
  1243 + self._pathing = self.PATHING_YYYY_MM_DD
  1244 + return self._naming_list[self._pathnaming]
  1245 +
  1246 + def pathnaming_set(self, prepath, pkw:dict, nkw:dict, extension="") -> str:
  1247 + """Set a full file name formed by input parameters according the current pathnaming
  1248 +
  1249 + Args:
  1250 + *args: a pathname if naming is ''.
  1251 + **kwargs: a dictionnary of parameters that depends on the pathing.
  1252 +
  1253 + Returns:
  1254 + The full file name with no extension.
  1255 +
  1256 + Example:
  1257 +
  1258 + ::
  1259 +
  1260 + fn = FileNames()
  1261 + fn.pathnaming("PyROS.1")
  1262 + fn.longitude(45.678)
  1263 + prepath = "/tmp"
  1264 + date = "2021-10-26T13:45:23"
  1265 + fnd = fn.naming_date(date)
  1266 + pparam = {}
  1267 + pparam['date'] = fnd['iso']
  1268 + pparam['night'] = True
  1269 + fparam = {}
  1270 + fparam['ftype'] = "L0"
  1271 + fparam['date'] = fnd['yyyymmdd']
  1272 + fparam['time'] = fnd['hhmmssssssss']
  1273 + fparam['version'] = "1"
  1274 + fparam['unit'] = "TNC"
  1275 + fparam['channel'] = "CH1"
  1276 + fparam['id_seq'] = 123456789
  1277 + fparam['plane'] = 1
  1278 + fparam['frame'] = 1
  1279 + fullname = fn.pathnaming_set(prepath, pparam, fparam, ".fits")
  1280 +
  1281 + The answer should be '/tmp\\2021\\10\\26\\L0_20211026_134522999983_1_TNC_CH1_0123456789_001_001.fits'
  1282 + """
  1283 + if self._pathnaming == self.NAMING_PYROS1:
  1284 + path = self.pathing_set(**pkw)
  1285 + fname = self.naming_set(**nkw)
  1286 + fullname = os.path.join(prepath, path, fname) + extension
  1287 + return fullname
  1288 +
1106 1289 # =============================================
1107 1290 # Managing filenames
1108 1291 # =============================================
... ... @@ -1815,8 +1998,8 @@ class FileNames(FileNamesException, GuitastroTools):
1815 1998  
1816 1999 if __name__ == "__main__":
1817 2000  
1818   - default = 5
1819   - example = input(f"Select the example (0 to 5) ({default}) ")
  2001 + default = 6
  2002 + example = input(f"Select the example (0 to 6) ({default}) ")
1820 2003 try:
1821 2004 example = int(example)
1822 2005 except:
... ... @@ -1906,3 +2089,27 @@ if __name__ == "__main__":
1906 2089 param['night'] = True
1907 2090 pname = fn.pathing_set(**param)
1908 2091  
  2092 + if example == 6:
  2093 + """
  2094 + """
  2095 + fn = FileNames()
  2096 + fn.pathnaming("PyROS.1")
  2097 + fn.longitude(45.678)
  2098 + prepath = "/tmp"
  2099 + date = "2021-10-26T13:45:23"
  2100 + fnd = fn.naming_date(date)
  2101 + pparam = {}
  2102 + pparam['date'] = fnd['iso']
  2103 + pparam['night'] = True
  2104 + fparam = {}
  2105 + fparam['ftype'] = "L0"
  2106 + fparam['date'] = fnd['yyyymmdd']
  2107 + fparam['time'] = fnd['hhmmssssssss']
  2108 + fparam['version'] = "1"
  2109 + fparam['unit'] = "TNC"
  2110 + fparam['channel'] = "CH1"
  2111 + fparam['id_seq'] = 123456789
  2112 + fparam['plane'] = 1
  2113 + fparam['frame'] = 1
  2114 + fullname = fn.pathnaming_set(prepath, pparam, fparam)
  2115 + print(f"fullname={fullname}")
1909 2116 \ No newline at end of file
... ...