disdrodb 0.0.21__py3-none-any.whl → 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (264) hide show
  1. disdrodb/__init__.py +132 -15
  2. disdrodb/_config.py +4 -2
  3. disdrodb/_version.py +9 -4
  4. disdrodb/api/checks.py +264 -237
  5. disdrodb/api/configs.py +4 -8
  6. disdrodb/api/create_directories.py +235 -290
  7. disdrodb/api/info.py +217 -26
  8. disdrodb/api/io.py +295 -269
  9. disdrodb/api/path.py +597 -173
  10. disdrodb/api/search.py +486 -0
  11. disdrodb/{metadata/scripts → cli}/disdrodb_check_metadata_archive.py +12 -7
  12. disdrodb/{utils/pandas.py → cli/disdrodb_data_archive_directory.py} +9 -18
  13. disdrodb/cli/disdrodb_download_archive.py +86 -0
  14. disdrodb/cli/disdrodb_download_metadata_archive.py +53 -0
  15. disdrodb/cli/disdrodb_download_station.py +84 -0
  16. disdrodb/{api/scripts → cli}/disdrodb_initialize_station.py +22 -10
  17. disdrodb/cli/disdrodb_metadata_archive_directory.py +32 -0
  18. disdrodb/{data_transfer/scripts/disdrodb_download_station.py → cli/disdrodb_open_data_archive.py} +22 -22
  19. disdrodb/cli/disdrodb_open_logs_directory.py +69 -0
  20. disdrodb/{data_transfer/scripts/disdrodb_upload_station.py → cli/disdrodb_open_metadata_archive.py} +22 -24
  21. disdrodb/cli/disdrodb_open_metadata_directory.py +71 -0
  22. disdrodb/cli/disdrodb_open_product_directory.py +74 -0
  23. disdrodb/cli/disdrodb_open_readers_directory.py +32 -0
  24. disdrodb/{l0/scripts → cli}/disdrodb_run_l0.py +38 -31
  25. disdrodb/{l0/scripts → cli}/disdrodb_run_l0_station.py +32 -30
  26. disdrodb/{l0/scripts → cli}/disdrodb_run_l0a.py +30 -21
  27. disdrodb/{l0/scripts → cli}/disdrodb_run_l0a_station.py +24 -33
  28. disdrodb/{l0/scripts → cli}/disdrodb_run_l0b.py +30 -21
  29. disdrodb/{l0/scripts → cli}/disdrodb_run_l0b_station.py +25 -34
  30. disdrodb/cli/disdrodb_run_l0c.py +130 -0
  31. disdrodb/cli/disdrodb_run_l0c_station.py +129 -0
  32. disdrodb/cli/disdrodb_run_l1.py +122 -0
  33. disdrodb/cli/disdrodb_run_l1_station.py +121 -0
  34. disdrodb/cli/disdrodb_run_l2e.py +122 -0
  35. disdrodb/cli/disdrodb_run_l2e_station.py +122 -0
  36. disdrodb/cli/disdrodb_run_l2m.py +122 -0
  37. disdrodb/cli/disdrodb_run_l2m_station.py +122 -0
  38. disdrodb/cli/disdrodb_upload_archive.py +105 -0
  39. disdrodb/cli/disdrodb_upload_station.py +98 -0
  40. disdrodb/configs.py +90 -25
  41. disdrodb/data_transfer/__init__.py +22 -0
  42. disdrodb/data_transfer/download_data.py +87 -90
  43. disdrodb/data_transfer/upload_data.py +64 -37
  44. disdrodb/data_transfer/zenodo.py +15 -18
  45. disdrodb/docs.py +1 -1
  46. disdrodb/issue/__init__.py +17 -4
  47. disdrodb/issue/checks.py +10 -23
  48. disdrodb/issue/reader.py +9 -12
  49. disdrodb/issue/writer.py +14 -17
  50. disdrodb/l0/__init__.py +17 -26
  51. disdrodb/l0/check_configs.py +35 -23
  52. disdrodb/l0/check_standards.py +32 -42
  53. disdrodb/l0/configs/{Thies_LPM → LPM}/bins_diameter.yml +44 -44
  54. disdrodb/l0/configs/{Thies_LPM → LPM}/bins_velocity.yml +40 -40
  55. disdrodb/l0/configs/LPM/l0a_encodings.yml +80 -0
  56. disdrodb/l0/configs/{Thies_LPM → LPM}/l0b_cf_attrs.yml +62 -59
  57. disdrodb/l0/configs/{Thies_LPM → LPM}/l0b_encodings.yml +9 -9
  58. disdrodb/l0/configs/{Thies_LPM → LPM}/raw_data_format.yml +245 -245
  59. disdrodb/l0/configs/{OTT_Parsivel → PARSIVEL}/bins_diameter.yml +66 -66
  60. disdrodb/l0/configs/{OTT_Parsivel → PARSIVEL}/bins_velocity.yml +64 -64
  61. disdrodb/l0/configs/PARSIVEL/l0a_encodings.yml +32 -0
  62. disdrodb/l0/configs/{OTT_Parsivel → PARSIVEL}/l0b_cf_attrs.yml +22 -20
  63. disdrodb/l0/configs/{OTT_Parsivel → PARSIVEL}/l0b_encodings.yml +17 -17
  64. disdrodb/l0/configs/{OTT_Parsivel → PARSIVEL}/raw_data_format.yml +77 -77
  65. disdrodb/l0/configs/{OTT_Parsivel2 → PARSIVEL2}/bins_diameter.yml +64 -64
  66. disdrodb/l0/configs/{OTT_Parsivel2 → PARSIVEL2}/bins_velocity.yml +64 -64
  67. disdrodb/l0/configs/PARSIVEL2/l0a_encodings.yml +39 -0
  68. disdrodb/l0/configs/{OTT_Parsivel2 → PARSIVEL2}/l0b_cf_attrs.yml +24 -22
  69. disdrodb/l0/configs/{OTT_Parsivel2 → PARSIVEL2}/l0b_encodings.yml +20 -20
  70. disdrodb/l0/configs/{OTT_Parsivel2 → PARSIVEL2}/raw_data_format.yml +98 -98
  71. disdrodb/l0/configs/{RD_80 → RD80}/bins_diameter.yml +40 -40
  72. disdrodb/l0/configs/RD80/l0a_encodings.yml +16 -0
  73. disdrodb/l0/configs/{RD_80 → RD80}/l0b_cf_attrs.yml +3 -3
  74. disdrodb/l0/configs/RD80/l0b_encodings.yml +135 -0
  75. disdrodb/l0/configs/{RD_80 → RD80}/raw_data_format.yml +48 -48
  76. disdrodb/l0/l0_reader.py +216 -340
  77. disdrodb/l0/l0a_processing.py +237 -208
  78. disdrodb/l0/l0b_nc_processing.py +227 -80
  79. disdrodb/l0/l0b_processing.py +93 -173
  80. disdrodb/l0/l0c_processing.py +627 -0
  81. disdrodb/l0/readers/{ARM → LPM/ARM}/ARM_LPM.py +36 -58
  82. disdrodb/l0/readers/LPM/AUSTRALIA/MELBOURNE_2007_LPM.py +226 -0
  83. disdrodb/l0/readers/LPM/BRAZIL/CHUVA_LPM.py +185 -0
  84. disdrodb/l0/readers/LPM/BRAZIL/GOAMAZON_LPM.py +183 -0
  85. disdrodb/l0/readers/LPM/ITALY/GID_LPM.py +179 -0
  86. disdrodb/l0/readers/{UK → LPM/UK}/DIVEN.py +14 -35
  87. disdrodb/l0/readers/PARSIVEL/AUSTRALIA/MELBOURNE_2007_PARSIVEL.py +157 -0
  88. disdrodb/l0/readers/PARSIVEL/CHINA/CHONGQING.py +113 -0
  89. disdrodb/l0/readers/{EPFL → PARSIVEL/EPFL}/ARCTIC_2021.py +40 -57
  90. disdrodb/l0/readers/{EPFL → PARSIVEL/EPFL}/COMMON_2011.py +37 -54
  91. disdrodb/l0/readers/{EPFL → PARSIVEL/EPFL}/DAVOS_2009_2011.py +34 -51
  92. disdrodb/l0/readers/{EPFL → PARSIVEL/EPFL}/EPFL_2009.py +34 -51
  93. disdrodb/l0/readers/{EPFL/PARADISO_2014.py → PARSIVEL/EPFL/EPFL_ROOF_2008.py} +38 -50
  94. disdrodb/l0/readers/PARSIVEL/EPFL/EPFL_ROOF_2010.py +105 -0
  95. disdrodb/l0/readers/{EPFL → PARSIVEL/EPFL}/EPFL_ROOF_2011.py +34 -51
  96. disdrodb/l0/readers/{EPFL → PARSIVEL/EPFL}/EPFL_ROOF_2012.py +33 -51
  97. disdrodb/l0/readers/{EPFL → PARSIVEL/EPFL}/GENEPI_2007.py +25 -44
  98. disdrodb/l0/readers/{EPFL → PARSIVEL/EPFL}/GRAND_ST_BERNARD_2007.py +25 -44
  99. disdrodb/l0/readers/{EPFL → PARSIVEL/EPFL}/GRAND_ST_BERNARD_2007_2.py +25 -44
  100. disdrodb/l0/readers/{EPFL → PARSIVEL/EPFL}/HPICONET_2010.py +34 -51
  101. disdrodb/l0/readers/{EPFL/EPFL_ROOF_2010.py → PARSIVEL/EPFL/HYMEX_LTE_SOP2.py} +37 -50
  102. disdrodb/l0/readers/PARSIVEL/EPFL/HYMEX_LTE_SOP3.py +111 -0
  103. disdrodb/l0/readers/{EPFL → PARSIVEL/EPFL}/HYMEX_LTE_SOP4.py +36 -54
  104. disdrodb/l0/readers/{EPFL → PARSIVEL/EPFL}/LOCARNO_2018.py +34 -52
  105. disdrodb/l0/readers/{EPFL → PARSIVEL/EPFL}/LOCARNO_2019.py +38 -56
  106. disdrodb/l0/readers/PARSIVEL/EPFL/PARADISO_2014.py +105 -0
  107. disdrodb/l0/readers/{EPFL → PARSIVEL/EPFL}/PARSIVEL_2007.py +27 -45
  108. disdrodb/l0/readers/{EPFL → PARSIVEL/EPFL}/PLATO_2019.py +24 -44
  109. disdrodb/l0/readers/PARSIVEL/EPFL/RACLETS_2019.py +140 -0
  110. disdrodb/l0/readers/{EPFL → PARSIVEL/EPFL}/RACLETS_2019_WJF.py +41 -59
  111. disdrodb/l0/readers/{EPFL → PARSIVEL/EPFL}/RIETHOLZBACH_2011.py +34 -51
  112. disdrodb/l0/readers/PARSIVEL/EPFL/SAMOYLOV_2017.py +117 -0
  113. disdrodb/l0/readers/PARSIVEL/EPFL/SAMOYLOV_2019.py +137 -0
  114. disdrodb/l0/readers/{EPFL → PARSIVEL/EPFL}/UNIL_2022.py +42 -55
  115. disdrodb/l0/readers/PARSIVEL/GPM/IFLOODS.py +104 -0
  116. disdrodb/l0/readers/{GPM → PARSIVEL/GPM}/LPVEX.py +29 -48
  117. disdrodb/l0/readers/PARSIVEL/GPM/MC3E.py +184 -0
  118. disdrodb/l0/readers/PARSIVEL/NCAR/CCOPE_2015.py +113 -0
  119. disdrodb/l0/readers/{NCAR/VORTEX_SE_2016_P1.py → PARSIVEL/NCAR/OWLES_MIPS.py} +46 -72
  120. disdrodb/l0/readers/PARSIVEL/NCAR/PECAN_MOBILE.py +125 -0
  121. disdrodb/l0/readers/{NCAR/OWLES_MIPS.py → PARSIVEL/NCAR/PLOWS_MIPS.py} +45 -64
  122. disdrodb/l0/readers/PARSIVEL/NCAR/VORTEX2_2009.py +114 -0
  123. disdrodb/l0/readers/PARSIVEL/NCAR/VORTEX2_2010.py +176 -0
  124. disdrodb/l0/readers/PARSIVEL/NCAR/VORTEX2_2010_UF.py +183 -0
  125. disdrodb/l0/readers/{ARM/ARM_LD.py → PARSIVEL2/ARM/ARM_PARSIVEL2.py} +27 -50
  126. disdrodb/l0/readers/PARSIVEL2/BRAZIL/CHUVA_PARSIVEL2.py +163 -0
  127. disdrodb/l0/readers/PARSIVEL2/BRAZIL/GOAMAZON_PARSIVEL2.py +163 -0
  128. disdrodb/l0/readers/{DENMARK → PARSIVEL2/DENMARK}/EROSION_nc.py +14 -35
  129. disdrodb/l0/readers/PARSIVEL2/FRANCE/SIRTA_PARSIVEL2.py +119 -0
  130. disdrodb/l0/readers/PARSIVEL2/GPM/GCPEX.py +104 -0
  131. disdrodb/l0/readers/PARSIVEL2/GPM/NSSTC.py +176 -0
  132. disdrodb/l0/readers/PARSIVEL2/ITALY/GID_PARSIVEL2.py +32 -0
  133. disdrodb/l0/readers/PARSIVEL2/MEXICO/OH_IIUNAM_nc.py +56 -0
  134. disdrodb/l0/readers/PARSIVEL2/NCAR/PECAN_FP3.py +120 -0
  135. disdrodb/l0/readers/{NCAR → PARSIVEL2/NCAR}/PECAN_MIPS.py +45 -64
  136. disdrodb/l0/readers/PARSIVEL2/NCAR/RELAMPAGO_PARSIVEL2.py +181 -0
  137. disdrodb/l0/readers/PARSIVEL2/NCAR/SNOWIE_PJ.py +160 -0
  138. disdrodb/l0/readers/PARSIVEL2/NCAR/SNOWIE_SB.py +160 -0
  139. disdrodb/l0/readers/{NCAR/PLOWS_MIPS.py → PARSIVEL2/NCAR/VORTEX_SE_2016_P1.py} +49 -66
  140. disdrodb/l0/readers/PARSIVEL2/NCAR/VORTEX_SE_2016_P2.py +118 -0
  141. disdrodb/l0/readers/PARSIVEL2/NCAR/VORTEX_SE_2016_PIPS.py +152 -0
  142. disdrodb/l0/readers/PARSIVEL2/NETHERLANDS/DELFT.py +166 -0
  143. disdrodb/l0/readers/{NCAR/RELAMPAGO_RD80.py → RD80/BRAZIL/CHUVA_RD80.py} +36 -60
  144. disdrodb/l0/readers/{BRAZIL → RD80/BRAZIL}/GOAMAZON_RD80.py +36 -55
  145. disdrodb/l0/readers/{NCAR → RD80/NCAR}/CINDY_2011_RD80.py +35 -54
  146. disdrodb/l0/readers/{BRAZIL/CHUVA_RD80.py → RD80/NCAR/RELAMPAGO_RD80.py} +40 -54
  147. disdrodb/l0/readers/template_reader_raw_netcdf_data.py +62 -0
  148. disdrodb/l0/readers/{reader_template.py → template_reader_raw_text_data.py} +20 -44
  149. disdrodb/l0/routines.py +885 -581
  150. disdrodb/l0/standards.py +72 -236
  151. disdrodb/l0/template_tools.py +104 -109
  152. disdrodb/l1/__init__.py +17 -0
  153. disdrodb/l1/beard_model.py +716 -0
  154. disdrodb/l1/encoding_attrs.py +620 -0
  155. disdrodb/l1/fall_velocity.py +260 -0
  156. disdrodb/l1/filters.py +192 -0
  157. disdrodb/l1/processing.py +200 -0
  158. disdrodb/l1/resampling.py +236 -0
  159. disdrodb/l1/routines.py +357 -0
  160. disdrodb/l1_env/__init__.py +17 -0
  161. disdrodb/l1_env/routines.py +38 -0
  162. disdrodb/l2/__init__.py +17 -0
  163. disdrodb/l2/empirical_dsd.py +1735 -0
  164. disdrodb/l2/event.py +388 -0
  165. disdrodb/l2/processing.py +519 -0
  166. disdrodb/l2/processing_options.py +213 -0
  167. disdrodb/l2/routines.py +868 -0
  168. disdrodb/metadata/__init__.py +9 -2
  169. disdrodb/metadata/checks.py +165 -118
  170. disdrodb/metadata/download.py +81 -0
  171. disdrodb/metadata/geolocation.py +146 -0
  172. disdrodb/metadata/info.py +20 -13
  173. disdrodb/metadata/manipulation.py +1 -1
  174. disdrodb/metadata/reader.py +59 -8
  175. disdrodb/metadata/search.py +77 -144
  176. disdrodb/metadata/standards.py +7 -8
  177. disdrodb/metadata/writer.py +8 -14
  178. disdrodb/psd/__init__.py +38 -0
  179. disdrodb/psd/fitting.py +2146 -0
  180. disdrodb/psd/models.py +774 -0
  181. disdrodb/routines.py +1176 -0
  182. disdrodb/scattering/__init__.py +28 -0
  183. disdrodb/scattering/axis_ratio.py +344 -0
  184. disdrodb/scattering/routines.py +456 -0
  185. disdrodb/utils/__init__.py +17 -0
  186. disdrodb/utils/attrs.py +208 -0
  187. disdrodb/utils/cli.py +269 -0
  188. disdrodb/utils/compression.py +60 -42
  189. disdrodb/utils/dask.py +62 -0
  190. disdrodb/utils/decorators.py +110 -0
  191. disdrodb/utils/directories.py +107 -46
  192. disdrodb/utils/encoding.py +127 -0
  193. disdrodb/utils/list.py +29 -0
  194. disdrodb/utils/logger.py +168 -46
  195. disdrodb/utils/time.py +657 -0
  196. disdrodb/utils/warnings.py +30 -0
  197. disdrodb/utils/writer.py +57 -0
  198. disdrodb/utils/xarray.py +138 -47
  199. disdrodb/utils/yaml.py +0 -1
  200. disdrodb/viz/__init__.py +17 -0
  201. disdrodb/viz/plots.py +17 -0
  202. disdrodb-0.1.0.dist-info/METADATA +321 -0
  203. disdrodb-0.1.0.dist-info/RECORD +216 -0
  204. {disdrodb-0.0.21.dist-info → disdrodb-0.1.0.dist-info}/WHEEL +1 -1
  205. disdrodb-0.1.0.dist-info/entry_points.txt +30 -0
  206. disdrodb/data_transfer/scripts/disdrodb_download_archive.py +0 -53
  207. disdrodb/data_transfer/scripts/disdrodb_upload_archive.py +0 -57
  208. disdrodb/l0/configs/OTT_Parsivel/l0a_encodings.yml +0 -32
  209. disdrodb/l0/configs/OTT_Parsivel2/l0a_encodings.yml +0 -39
  210. disdrodb/l0/configs/RD_80/l0a_encodings.yml +0 -16
  211. disdrodb/l0/configs/RD_80/l0b_encodings.yml +0 -135
  212. disdrodb/l0/configs/Thies_LPM/l0a_encodings.yml +0 -80
  213. disdrodb/l0/io.py +0 -257
  214. disdrodb/l0/l0_processing.py +0 -1091
  215. disdrodb/l0/readers/AUSTRALIA/MELBOURNE_2007_OTT.py +0 -178
  216. disdrodb/l0/readers/AUSTRALIA/MELBOURNE_2007_THIES.py +0 -247
  217. disdrodb/l0/readers/BRAZIL/CHUVA_LPM.py +0 -204
  218. disdrodb/l0/readers/BRAZIL/CHUVA_OTT.py +0 -183
  219. disdrodb/l0/readers/BRAZIL/GOAMAZON_LPM.py +0 -204
  220. disdrodb/l0/readers/BRAZIL/GOAMAZON_OTT.py +0 -183
  221. disdrodb/l0/readers/CHINA/CHONGQING.py +0 -131
  222. disdrodb/l0/readers/EPFL/EPFL_ROOF_2008.py +0 -128
  223. disdrodb/l0/readers/EPFL/HYMEX_LTE_SOP2.py +0 -127
  224. disdrodb/l0/readers/EPFL/HYMEX_LTE_SOP3.py +0 -129
  225. disdrodb/l0/readers/EPFL/RACLETS_2019.py +0 -158
  226. disdrodb/l0/readers/EPFL/SAMOYLOV_2017.py +0 -136
  227. disdrodb/l0/readers/EPFL/SAMOYLOV_2019.py +0 -158
  228. disdrodb/l0/readers/FRANCE/SIRTA_OTT2.py +0 -138
  229. disdrodb/l0/readers/GPM/GCPEX.py +0 -123
  230. disdrodb/l0/readers/GPM/IFLOODS.py +0 -123
  231. disdrodb/l0/readers/GPM/MC3E.py +0 -123
  232. disdrodb/l0/readers/GPM/NSSTC.py +0 -164
  233. disdrodb/l0/readers/ITALY/GID.py +0 -199
  234. disdrodb/l0/readers/MEXICO/OH_IIUNAM_nc.py +0 -92
  235. disdrodb/l0/readers/NCAR/CCOPE_2015.py +0 -133
  236. disdrodb/l0/readers/NCAR/PECAN_FP3.py +0 -137
  237. disdrodb/l0/readers/NCAR/PECAN_MOBILE.py +0 -144
  238. disdrodb/l0/readers/NCAR/RELAMPAGO_OTT.py +0 -195
  239. disdrodb/l0/readers/NCAR/SNOWIE_PJ.py +0 -172
  240. disdrodb/l0/readers/NCAR/SNOWIE_SB.py +0 -179
  241. disdrodb/l0/readers/NCAR/VORTEX2_2009.py +0 -133
  242. disdrodb/l0/readers/NCAR/VORTEX2_2010.py +0 -188
  243. disdrodb/l0/readers/NCAR/VORTEX2_2010_UF.py +0 -191
  244. disdrodb/l0/readers/NCAR/VORTEX_SE_2016_P2.py +0 -135
  245. disdrodb/l0/readers/NCAR/VORTEX_SE_2016_PIPS.py +0 -170
  246. disdrodb/l0/readers/NETHERLANDS/DELFT.py +0 -187
  247. disdrodb/l0/readers/SPAIN/SBEGUERIA.py +0 -179
  248. disdrodb/l0/scripts/disdrodb_run_l0b_concat.py +0 -93
  249. disdrodb/l0/scripts/disdrodb_run_l0b_concat_station.py +0 -85
  250. disdrodb/utils/netcdf.py +0 -452
  251. disdrodb/utils/scripts.py +0 -102
  252. disdrodb-0.0.21.dist-info/AUTHORS.md +0 -18
  253. disdrodb-0.0.21.dist-info/METADATA +0 -186
  254. disdrodb-0.0.21.dist-info/RECORD +0 -168
  255. disdrodb-0.0.21.dist-info/entry_points.txt +0 -15
  256. /disdrodb/l0/configs/{RD_80 → RD80}/bins_velocity.yml +0 -0
  257. /disdrodb/l0/manuals/{Thies_LPM.pdf → LPM.pdf} +0 -0
  258. /disdrodb/l0/manuals/{ODM_470.pdf → ODM470.pdf} +0 -0
  259. /disdrodb/l0/manuals/{OTT_Parsivel.pdf → PARSIVEL.pdf} +0 -0
  260. /disdrodb/l0/manuals/{OTT_Parsivel2.pdf → PARSIVEL2.pdf} +0 -0
  261. /disdrodb/l0/manuals/{PWS_100.pdf → PWS100.pdf} +0 -0
  262. /disdrodb/l0/manuals/{RD_80.pdf → RD80.pdf} +0 -0
  263. {disdrodb-0.0.21.dist-info → disdrodb-0.1.0.dist-info/licenses}/LICENSE +0 -0
  264. {disdrodb-0.0.21.dist-info → disdrodb-0.1.0.dist-info}/top_level.txt +0 -0
disdrodb/utils/logger.py CHANGED
@@ -24,10 +24,9 @@ import re
24
24
  from asyncio.log import logger
25
25
 
26
26
 
27
- def create_file_logger(processed_dir, product, station_name, filename, parallel):
28
- """Create file logger."""
27
+ def create_logger_file(logs_dir, filename, parallel):
28
+ """Create logger file."""
29
29
  # Create logs directory
30
- logs_dir = os.path.join(processed_dir, "logs", product, station_name)
31
30
  os.makedirs(logs_dir, exist_ok=True)
32
31
 
33
32
  # Define logger filepath
@@ -35,25 +34,28 @@ def create_file_logger(processed_dir, product, station_name, filename, parallel)
35
34
  logger_filepath = os.path.join(logs_dir, logger_filename)
36
35
 
37
36
  # Set logger
38
- if parallel:
39
- logger = logging.getLogger(filename) # does not log submodules logs
40
- else:
41
- logger = logging.getLogger() # root logger
37
+ # - getLogger() # root logger
38
+ # - getLogger(filename) does not log submodules logs
39
+ logger = logging.getLogger(filename) if parallel else logging.getLogger()
42
40
 
43
41
  handler = logging.FileHandler(logger_filepath, mode="w")
44
42
  format_type = "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
45
43
  handler.setFormatter(logging.Formatter(format_type))
46
44
  logger.addHandler(handler)
47
45
  logger.setLevel(logging.DEBUG)
48
- return logger
46
+
47
+ # Define logger filepath
48
+ # - LogCaptureHandler of pytest does not have baseFilename attribute --> So set None
49
+ logger_filepath = logger.handlers[0].baseFilename if not os.environ.get("PYTEST_CURRENT_TEST") else None
50
+ return logger, logger_filepath
49
51
 
50
52
 
51
- def close_logger(logger: logger) -> None:
52
- """Close the logger
53
+ def close_logger(logger) -> None:
54
+ """Close the logger.
53
55
 
54
56
  Parameters
55
57
  ----------
56
- logger : logger
58
+ logger : logging.Logger
57
59
  Logger object.
58
60
  """
59
61
  handlers = logger.handlers[:]
@@ -71,17 +73,18 @@ def log_debug(logger: logger, msg: str, verbose: bool = False) -> None:
71
73
 
72
74
  Parameters
73
75
  ----------
74
- logger : logger
76
+ logger : logging.Logger
75
77
  Log object.
76
78
  msg : str
77
79
  Message.
78
80
  verbose : bool, optional
79
81
  Whether to verbose the processing.
80
- The default is False.
82
+ The default value is ``False``.
81
83
  """
82
84
  if verbose:
83
85
  print(" - " + msg)
84
- logger.debug(msg)
86
+ if logger is not None:
87
+ logger.debug(msg)
85
88
 
86
89
 
87
90
  def log_info(logger: logger, msg: str, verbose: bool = False) -> None:
@@ -89,17 +92,18 @@ def log_info(logger: logger, msg: str, verbose: bool = False) -> None:
89
92
 
90
93
  Parameters
91
94
  ----------
92
- logger : logger
95
+ logger : logging.Logger
93
96
  Log object.
94
97
  msg : str
95
98
  Message.
96
99
  verbose : bool, optional
97
100
  Whether to verbose the processing.
98
- The default is False.
101
+ The default value is ``False``.
99
102
  """
100
103
  if verbose:
101
104
  print(" - " + msg)
102
- logger.info(msg)
105
+ if logger is not None:
106
+ logger.info(msg)
103
107
 
104
108
 
105
109
  def log_warning(logger: logger, msg: str, verbose: bool = False) -> None:
@@ -107,17 +111,18 @@ def log_warning(logger: logger, msg: str, verbose: bool = False) -> None:
107
111
 
108
112
  Parameters
109
113
  ----------
110
- logger : logger
114
+ logger : logging.Logger
111
115
  Log object.
112
116
  msg : str
113
117
  Message.
114
118
  verbose : bool, optional
115
119
  Whether to verbose the processing.
116
- The default is False.
120
+ The default value is ``False``.
117
121
  """
118
122
  if verbose:
119
123
  print(" - " + msg)
120
- logger.warning(msg)
124
+ if logger is not None:
125
+ logger.warning(msg)
121
126
 
122
127
 
123
128
  def log_error(logger: logger, msg: str, verbose: bool = False) -> None:
@@ -125,25 +130,22 @@ def log_error(logger: logger, msg: str, verbose: bool = False) -> None:
125
130
 
126
131
  Parameters
127
132
  ----------
128
- logger : logger
133
+ logger : logging.Logger
129
134
  Log object.
130
135
  msg : str
131
136
  Message.
132
137
  verbose : bool, optional
133
138
  Whether to verbose the processing.
134
- The default is False.
139
+ The default value is ``False``.
135
140
  """
136
141
  if verbose:
137
142
  print(" - " + msg)
138
- logger.error(msg)
143
+ if logger is not None:
144
+ logger.error(msg)
139
145
 
140
146
 
141
- def _get_logs_dir(list_logs):
142
- list_logs = sorted(list_logs)
143
- station_logs_dir = os.path.dirname(list_logs[0])
144
- station_name = station_logs_dir.split(os.path.sep)[-1]
145
- logs_dir = os.path.dirname(station_logs_dir)
146
- return station_name, logs_dir
147
+ ####---------------------------------------------------------------------------.
148
+ #### SUMMARY LOGS
147
149
 
148
150
 
149
151
  def _define_station_summary_log_file(list_logs, summary_filepath):
@@ -164,16 +166,27 @@ def _define_station_summary_log_file(list_logs, summary_filepath):
164
166
  def _define_station_problem_log_file(list_logs, problem_filepath):
165
167
  # - Copy the log of files with warnings and error
166
168
  list_keywords = ["ERROR"] # "WARNING"
169
+ list_patterns = ["ValueError: Less than 5 timesteps available for day"]
167
170
  re_keyword = re.compile("|".join(list_keywords))
171
+ # Compile patterns to ignore, escaping any special regex characters
172
+ re_patterns = re.compile("|".join(map(re.escape, list_patterns))) if list_patterns else None
173
+ # Initialize problem log file
168
174
  any_problem = False
175
+ n_files = len(list_logs)
176
+ n_files_with_problems = 0
169
177
  with open(problem_filepath, "w") as output_file:
178
+ # Loop over log files and collect problems
170
179
  for log_filepath in list_logs:
171
180
  log_with_problem = False
172
181
  # Check if an error is reported
173
182
  with open(log_filepath) as input_file:
174
183
  for line in input_file:
175
184
  if re_keyword.search(line):
185
+ # If the line matches an ignore pattern, skip it
186
+ if re_patterns and re_patterns.search(line):
187
+ continue
176
188
  log_with_problem = True
189
+ n_files_with_problems += 1
177
190
  any_problem = True
178
191
  break
179
192
  # If it is reported, copy the log file in the logs_problem file
@@ -181,34 +194,143 @@ def _define_station_problem_log_file(list_logs, problem_filepath):
181
194
  with open(log_filepath) as input_file:
182
195
  output_file.write(input_file.read())
183
196
 
197
+ # Add number of files with problems
198
+ msg = f"SUMMARY: {n_files_with_problems} of {n_files} files had problems."
199
+ output_file.write(msg)
200
+
184
201
  # If no problems occurred, remove the logs_problem_<station_name>.log file
185
202
  if not any_problem:
186
203
  os.remove(problem_filepath)
187
204
 
188
205
 
189
- def define_summary_log(list_logs):
190
- """Define a station summary and a problems log file from the list of input logs.
206
+ def create_product_logs(
207
+ product,
208
+ data_source,
209
+ campaign_name,
210
+ station_name,
211
+ data_archive_dir=None,
212
+ # Logs list
213
+ list_logs=None, # If none, list it !
214
+ # Product options
215
+ **product_kwargs,
216
+ ):
217
+ """Create station summary and station problems log files.
218
+
219
+ The summary log selects only logged lines with ``root``, ``WARNING``, and ``ERROR`` keywords.
220
+ The problems log file selects only logged lines with the ``ERROR`` keyword.
221
+
222
+ The logs directory structure is the follow:
223
+ /logs
224
+ - /files/<product_acronym>/<station> (same structure as data ... a log for each processed file)
225
+ - /summary
226
+ --> SUMMARY.<PRODUCT_ACRONYM>.<CAMPAIGN_NAME>.<STATION_NAME>.log
227
+ - /problems
228
+ --> PROBLEMS.<PRODUCT_ACRONYM>.<CAMPAIGN_NAME>.<STATION_NAME>.log
191
229
 
192
- The summary log select only logged lines with root, WARNING and ERROR keywords.
193
- The problems log file select only logged lines with the ERROR keyword.
194
- The two log files are saved in the parent directory of the input list_logs.
195
-
196
- Assume logs to be located at:
197
-
198
- /DISDRODB/Processed/<DATA_SOURCE>/<CAMPAIGN_NAME>/logs/<product>/<station_name>/*.log
230
+ Parameters
231
+ ----------
232
+ product : str
233
+ The DISDRODB product.
234
+ data_source : str
235
+ The data source name.
236
+ campaign_name : str
237
+ The campaign name.
238
+ station_name : str
239
+ The station name.
240
+ data_archive_dir : str, optional
241
+ The base directory path. Default is None.
242
+ sample_interval : str, optional
243
+ The sample interval for L2E option. Default is None.
244
+ rolling : str, optional
245
+ The rolling option for L2E. Default is None.
246
+ model_name : str, optional
247
+ The model name for L2M. Default is None.
248
+ list_logs : list, optional
249
+ List of log file paths. If None, the function will list the log files.
250
+
251
+ Returns
252
+ -------
253
+ None
199
254
 
200
255
  """
256
+ from disdrodb.api.path import define_campaign_dir, define_filename, define_logs_dir
257
+ from disdrodb.utils.directories import list_files
258
+
259
+ # --------------------------------------------------------.
260
+ # Search for logs file
261
+ if list_logs is None:
262
+ # Define product logs directory within /files/....
263
+ logs_dir = define_logs_dir(
264
+ product=product,
265
+ data_archive_dir=data_archive_dir,
266
+ data_source=data_source,
267
+ campaign_name=campaign_name,
268
+ station_name=station_name,
269
+ # Product options
270
+ **product_kwargs,
271
+ )
272
+ list_logs = list_files(logs_dir, glob_pattern="*", recursive=True)
273
+
274
+ # --------------------------------------------------------.
201
275
  # LogCaptureHandler of pytest does not have baseFilename attribute, so it returns None
202
276
  if list_logs[0] is None:
203
- return None
204
-
205
- station_name, logs_dir = _get_logs_dir(list_logs)
206
-
277
+ return
278
+
279
+ # --------------------------------------------------------.
280
+ # Define /summary and /problem directory
281
+ campaign_dir = define_campaign_dir(
282
+ archive_dir=data_archive_dir,
283
+ product=product,
284
+ data_source=data_source,
285
+ campaign_name=campaign_name,
286
+ )
287
+ logs_summary_dir = os.path.join(campaign_dir, "logs", "summary")
288
+ logs_problem_dir = os.path.join(campaign_dir, "logs", "problems")
289
+
290
+ os.makedirs(logs_summary_dir, exist_ok=True)
291
+ os.makedirs(logs_problem_dir, exist_ok=True)
292
+
293
+ # --------------------------------------------------------.
207
294
  # Define station summary log file name
208
- summary_filepath = os.path.join(logs_dir, f"logs_summary_{station_name}.log")
295
+ summary_filename = define_filename(
296
+ product=product,
297
+ campaign_name=campaign_name,
298
+ station_name=station_name,
299
+ # Filename options
300
+ add_version=False,
301
+ add_time_period=False,
302
+ add_extension=False,
303
+ prefix="SUMMARY",
304
+ suffix="log",
305
+ # Product options
306
+ **product_kwargs,
307
+ )
308
+ summary_filepath = os.path.join(logs_summary_dir, summary_filename)
309
+
209
310
  # Define station problem logs file name
210
- problem_filepath = os.path.join(logs_dir, f"logs_problem_{station_name}.log")
211
- # Create station summary log file
311
+ problem_filename = define_filename(
312
+ product=product,
313
+ campaign_name=campaign_name,
314
+ station_name=station_name,
315
+ # Filename options
316
+ add_version=False,
317
+ add_time_period=False,
318
+ add_extension=False,
319
+ prefix="PROBLEMS",
320
+ suffix="log",
321
+ # Product options
322
+ **product_kwargs,
323
+ )
324
+ problem_filepath = os.path.join(logs_problem_dir, problem_filename)
325
+
326
+ # --------------------------------------------------------.
327
+ # Create summary log file
212
328
  _define_station_summary_log_file(list_logs, summary_filepath)
213
- # Create station ptoblems log file (if no problems, no file)
329
+
330
+ # Create problem log file (if no problems, no file created)
214
331
  _define_station_problem_log_file(list_logs, problem_filepath)
332
+
333
+ # --------------------------------------------------------.
334
+ # Remove /problem directory if empty !
335
+ if len(os.listdir(logs_problem_dir)) == 0:
336
+ os.rmdir(logs_problem_dir)