HydPy 6.2.dev1__cp313-cp313-win_amd64.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 (890) hide show
  1. hydpy/__init__.py +275 -0
  2. hydpy/aliases.py +2554 -0
  3. hydpy/auxs/__init__.py +0 -0
  4. hydpy/auxs/anntools.py +1305 -0
  5. hydpy/auxs/armatools.py +883 -0
  6. hydpy/auxs/calibtools.py +3337 -0
  7. hydpy/auxs/interptools.py +1094 -0
  8. hydpy/auxs/iuhtools.py +543 -0
  9. hydpy/auxs/networktools.py +597 -0
  10. hydpy/auxs/ppolytools.py +809 -0
  11. hydpy/auxs/quadtools.py +61 -0
  12. hydpy/auxs/roottools.py +228 -0
  13. hydpy/auxs/smoothtools.py +273 -0
  14. hydpy/auxs/statstools.py +2125 -0
  15. hydpy/auxs/validtools.py +81 -0
  16. hydpy/conf/HydPyConfigBase.xsd +68637 -0
  17. hydpy/conf/HydPyConfigBase.xsdt +358 -0
  18. hydpy/conf/HydPyConfigMultipleRuns.xsd +25 -0
  19. hydpy/conf/HydPyConfigSingleRun.xsd +24 -0
  20. hydpy/conf/__init__.py +0 -0
  21. hydpy/conf/a_coefficients_explicit_lobatto_sequence.npy +0 -0
  22. hydpy/conf/support_points_for_smoothpar_logistic2.npy +0 -0
  23. hydpy/config.py +42 -0
  24. hydpy/core/__init__.py +0 -0
  25. hydpy/core/aliastools.py +214 -0
  26. hydpy/core/autodoctools.py +1947 -0
  27. hydpy/core/auxfiletools.py +1169 -0
  28. hydpy/core/devicetools.py +3810 -0
  29. hydpy/core/exceptiontools.py +269 -0
  30. hydpy/core/filetools.py +1985 -0
  31. hydpy/core/hydpytools.py +3089 -0
  32. hydpy/core/importtools.py +1398 -0
  33. hydpy/core/indextools.py +345 -0
  34. hydpy/core/itemtools.py +1849 -0
  35. hydpy/core/masktools.py +460 -0
  36. hydpy/core/modeltools.py +4868 -0
  37. hydpy/core/netcdftools.py +2683 -0
  38. hydpy/core/objecttools.py +2023 -0
  39. hydpy/core/optiontools.py +1045 -0
  40. hydpy/core/parametertools.py +4674 -0
  41. hydpy/core/printtools.py +222 -0
  42. hydpy/core/propertytools.py +643 -0
  43. hydpy/core/pubtools.py +254 -0
  44. hydpy/core/selectiontools.py +1571 -0
  45. hydpy/core/sequencetools.py +4476 -0
  46. hydpy/core/seriestools.py +339 -0
  47. hydpy/core/testtools.py +2483 -0
  48. hydpy/core/timetools.py +3567 -0
  49. hydpy/core/typingtools.py +333 -0
  50. hydpy/core/variabletools.py +2615 -0
  51. hydpy/cythons/__init__.py +24 -0
  52. hydpy/cythons/annutils.pxd +33 -0
  53. hydpy/cythons/annutils.pyi +25 -0
  54. hydpy/cythons/annutils.pyx +120 -0
  55. hydpy/cythons/autogen/__init__.py +0 -0
  56. hydpy/cythons/autogen/annutils.cp313-win_amd64.pyd +0 -0
  57. hydpy/cythons/autogen/annutils.pxd +42 -0
  58. hydpy/cythons/autogen/annutils.pyx +129 -0
  59. hydpy/cythons/autogen/c_arma.cp313-win_amd64.pyd +0 -0
  60. hydpy/cythons/autogen/c_arma.pxd +179 -0
  61. hydpy/cythons/autogen/c_arma.pyx +356 -0
  62. hydpy/cythons/autogen/c_arma_rimorido.cp313-win_amd64.pyd +0 -0
  63. hydpy/cythons/autogen/c_arma_rimorido.pxd +179 -0
  64. hydpy/cythons/autogen/c_arma_rimorido.pyx +356 -0
  65. hydpy/cythons/autogen/c_conv.cp313-win_amd64.pyd +0 -0
  66. hydpy/cythons/autogen/c_conv.pxd +198 -0
  67. hydpy/cythons/autogen/c_conv.pyx +491 -0
  68. hydpy/cythons/autogen/c_conv_idw.cp313-win_amd64.pyd +0 -0
  69. hydpy/cythons/autogen/c_conv_idw.pxd +124 -0
  70. hydpy/cythons/autogen/c_conv_idw.pyx +264 -0
  71. hydpy/cythons/autogen/c_conv_idw_ed.cp313-win_amd64.pyd +0 -0
  72. hydpy/cythons/autogen/c_conv_idw_ed.pxd +197 -0
  73. hydpy/cythons/autogen/c_conv_idw_ed.pyx +481 -0
  74. hydpy/cythons/autogen/c_conv_nn.cp313-win_amd64.pyd +0 -0
  75. hydpy/cythons/autogen/c_conv_nn.pxd +120 -0
  76. hydpy/cythons/autogen/c_conv_nn.pyx +224 -0
  77. hydpy/cythons/autogen/c_dam.cp313-win_amd64.pyd +0 -0
  78. hydpy/cythons/autogen/c_dam.pxd +805 -0
  79. hydpy/cythons/autogen/c_dam.pyx +1477 -0
  80. hydpy/cythons/autogen/c_dam_llake.cp313-win_amd64.pyd +0 -0
  81. hydpy/cythons/autogen/c_dam_llake.pxd +364 -0
  82. hydpy/cythons/autogen/c_dam_llake.pyx +705 -0
  83. hydpy/cythons/autogen/c_dam_lreservoir.cp313-win_amd64.pyd +0 -0
  84. hydpy/cythons/autogen/c_dam_lreservoir.pxd +365 -0
  85. hydpy/cythons/autogen/c_dam_lreservoir.pyx +708 -0
  86. hydpy/cythons/autogen/c_dam_lretention.cp313-win_amd64.pyd +0 -0
  87. hydpy/cythons/autogen/c_dam_lretention.pxd +340 -0
  88. hydpy/cythons/autogen/c_dam_lretention.pyx +625 -0
  89. hydpy/cythons/autogen/c_dam_pump.cp313-win_amd64.pyd +0 -0
  90. hydpy/cythons/autogen/c_dam_pump.pxd +402 -0
  91. hydpy/cythons/autogen/c_dam_pump.pyx +724 -0
  92. hydpy/cythons/autogen/c_dam_pump_sluice.cp313-win_amd64.pyd +0 -0
  93. hydpy/cythons/autogen/c_dam_pump_sluice.pxd +452 -0
  94. hydpy/cythons/autogen/c_dam_pump_sluice.pyx +829 -0
  95. hydpy/cythons/autogen/c_dam_sluice.cp313-win_amd64.pyd +0 -0
  96. hydpy/cythons/autogen/c_dam_sluice.pxd +404 -0
  97. hydpy/cythons/autogen/c_dam_sluice.pyx +726 -0
  98. hydpy/cythons/autogen/c_dam_v001.cp313-win_amd64.pyd +0 -0
  99. hydpy/cythons/autogen/c_dam_v001.pxd +452 -0
  100. hydpy/cythons/autogen/c_dam_v001.pyx +816 -0
  101. hydpy/cythons/autogen/c_dam_v002.cp313-win_amd64.pyd +0 -0
  102. hydpy/cythons/autogen/c_dam_v002.pxd +394 -0
  103. hydpy/cythons/autogen/c_dam_v002.pyx +703 -0
  104. hydpy/cythons/autogen/c_dam_v003.cp313-win_amd64.pyd +0 -0
  105. hydpy/cythons/autogen/c_dam_v003.pxd +417 -0
  106. hydpy/cythons/autogen/c_dam_v003.pyx +744 -0
  107. hydpy/cythons/autogen/c_dam_v004.cp313-win_amd64.pyd +0 -0
  108. hydpy/cythons/autogen/c_dam_v004.pxd +486 -0
  109. hydpy/cythons/autogen/c_dam_v004.pyx +891 -0
  110. hydpy/cythons/autogen/c_dam_v005.cp313-win_amd64.pyd +0 -0
  111. hydpy/cythons/autogen/c_dam_v005.pxd +524 -0
  112. hydpy/cythons/autogen/c_dam_v005.pyx +928 -0
  113. hydpy/cythons/autogen/c_dummy.cp313-win_amd64.pyd +0 -0
  114. hydpy/cythons/autogen/c_dummy.pxd +151 -0
  115. hydpy/cythons/autogen/c_dummy.pyx +263 -0
  116. hydpy/cythons/autogen/c_dummy_interceptedwater.cp313-win_amd64.pyd +0 -0
  117. hydpy/cythons/autogen/c_dummy_interceptedwater.pxd +69 -0
  118. hydpy/cythons/autogen/c_dummy_interceptedwater.pyx +104 -0
  119. hydpy/cythons/autogen/c_dummy_node2node.cp313-win_amd64.pyd +0 -0
  120. hydpy/cythons/autogen/c_dummy_node2node.pxd +89 -0
  121. hydpy/cythons/autogen/c_dummy_node2node.pyx +148 -0
  122. hydpy/cythons/autogen/c_dummy_snowalbedo.cp313-win_amd64.pyd +0 -0
  123. hydpy/cythons/autogen/c_dummy_snowalbedo.pxd +69 -0
  124. hydpy/cythons/autogen/c_dummy_snowalbedo.pyx +104 -0
  125. hydpy/cythons/autogen/c_dummy_snowcover.cp313-win_amd64.pyd +0 -0
  126. hydpy/cythons/autogen/c_dummy_snowcover.pxd +69 -0
  127. hydpy/cythons/autogen/c_dummy_snowcover.pyx +104 -0
  128. hydpy/cythons/autogen/c_dummy_snowycanopy.cp313-win_amd64.pyd +0 -0
  129. hydpy/cythons/autogen/c_dummy_snowycanopy.pxd +69 -0
  130. hydpy/cythons/autogen/c_dummy_snowycanopy.pyx +104 -0
  131. hydpy/cythons/autogen/c_dummy_soilwater.cp313-win_amd64.pyd +0 -0
  132. hydpy/cythons/autogen/c_dummy_soilwater.pxd +69 -0
  133. hydpy/cythons/autogen/c_dummy_soilwater.pyx +104 -0
  134. hydpy/cythons/autogen/c_evap.cp313-win_amd64.pyd +0 -0
  135. hydpy/cythons/autogen/c_evap.pxd +1029 -0
  136. hydpy/cythons/autogen/c_evap.pyx +2601 -0
  137. hydpy/cythons/autogen/c_evap_aet_hbv96.cp313-win_amd64.pyd +0 -0
  138. hydpy/cythons/autogen/c_evap_aet_hbv96.pxd +227 -0
  139. hydpy/cythons/autogen/c_evap_aet_hbv96.pyx +584 -0
  140. hydpy/cythons/autogen/c_evap_aet_minhas.cp313-win_amd64.pyd +0 -0
  141. hydpy/cythons/autogen/c_evap_aet_minhas.pxd +193 -0
  142. hydpy/cythons/autogen/c_evap_aet_minhas.pyx +478 -0
  143. hydpy/cythons/autogen/c_evap_aet_morsim.cp313-win_amd64.pyd +0 -0
  144. hydpy/cythons/autogen/c_evap_aet_morsim.pxd +681 -0
  145. hydpy/cythons/autogen/c_evap_aet_morsim.pyx +1642 -0
  146. hydpy/cythons/autogen/c_evap_pet_ambav1.cp313-win_amd64.pyd +0 -0
  147. hydpy/cythons/autogen/c_evap_pet_ambav1.pxd +532 -0
  148. hydpy/cythons/autogen/c_evap_pet_ambav1.pyx +1296 -0
  149. hydpy/cythons/autogen/c_evap_pet_hbv96.cp313-win_amd64.pyd +0 -0
  150. hydpy/cythons/autogen/c_evap_pet_hbv96.pxd +179 -0
  151. hydpy/cythons/autogen/c_evap_pet_hbv96.pyx +328 -0
  152. hydpy/cythons/autogen/c_evap_pet_m.cp313-win_amd64.pyd +0 -0
  153. hydpy/cythons/autogen/c_evap_pet_m.pxd +124 -0
  154. hydpy/cythons/autogen/c_evap_pet_m.pyx +214 -0
  155. hydpy/cythons/autogen/c_evap_pet_mlc.cp313-win_amd64.pyd +0 -0
  156. hydpy/cythons/autogen/c_evap_pet_mlc.pxd +126 -0
  157. hydpy/cythons/autogen/c_evap_pet_mlc.pyx +214 -0
  158. hydpy/cythons/autogen/c_evap_ret_fao56.cp313-win_amd64.pyd +0 -0
  159. hydpy/cythons/autogen/c_evap_ret_fao56.pxd +305 -0
  160. hydpy/cythons/autogen/c_evap_ret_fao56.pyx +624 -0
  161. hydpy/cythons/autogen/c_evap_ret_io.cp313-win_amd64.pyd +0 -0
  162. hydpy/cythons/autogen/c_evap_ret_io.pxd +112 -0
  163. hydpy/cythons/autogen/c_evap_ret_io.pyx +176 -0
  164. hydpy/cythons/autogen/c_evap_ret_tw2002.cp313-win_amd64.pyd +0 -0
  165. hydpy/cythons/autogen/c_evap_ret_tw2002.pxd +139 -0
  166. hydpy/cythons/autogen/c_evap_ret_tw2002.pyx +273 -0
  167. hydpy/cythons/autogen/c_exch.cp313-win_amd64.pyd +0 -0
  168. hydpy/cythons/autogen/c_exch.pxd +230 -0
  169. hydpy/cythons/autogen/c_exch.pyx +462 -0
  170. hydpy/cythons/autogen/c_exch_branch_hbv96.cp313-win_amd64.pyd +0 -0
  171. hydpy/cythons/autogen/c_exch_branch_hbv96.pxd +134 -0
  172. hydpy/cythons/autogen/c_exch_branch_hbv96.pyx +255 -0
  173. hydpy/cythons/autogen/c_exch_waterlevel.cp313-win_amd64.pyd +0 -0
  174. hydpy/cythons/autogen/c_exch_waterlevel.pxd +54 -0
  175. hydpy/cythons/autogen/c_exch_waterlevel.pyx +78 -0
  176. hydpy/cythons/autogen/c_exch_weir_hbv96.cp313-win_amd64.pyd +0 -0
  177. hydpy/cythons/autogen/c_exch_weir_hbv96.pxd +156 -0
  178. hydpy/cythons/autogen/c_exch_weir_hbv96.pyx +282 -0
  179. hydpy/cythons/autogen/c_ga.cp313-win_amd64.pyd +0 -0
  180. hydpy/cythons/autogen/c_ga.pxd +353 -0
  181. hydpy/cythons/autogen/c_ga.pyx +1204 -0
  182. hydpy/cythons/autogen/c_ga_garto.cp313-win_amd64.pyd +0 -0
  183. hydpy/cythons/autogen/c_ga_garto.pxd +330 -0
  184. hydpy/cythons/autogen/c_ga_garto.pyx +1105 -0
  185. hydpy/cythons/autogen/c_ga_garto_submodel1.cp313-win_amd64.pyd +0 -0
  186. hydpy/cythons/autogen/c_ga_garto_submodel1.pxd +236 -0
  187. hydpy/cythons/autogen/c_ga_garto_submodel1.pyx +944 -0
  188. hydpy/cythons/autogen/c_gland.cp313-win_amd64.pyd +0 -0
  189. hydpy/cythons/autogen/c_gland.pxd +437 -0
  190. hydpy/cythons/autogen/c_gland.pyx +726 -0
  191. hydpy/cythons/autogen/c_gland_gr4.cp313-win_amd64.pyd +0 -0
  192. hydpy/cythons/autogen/c_gland_gr4.pxd +382 -0
  193. hydpy/cythons/autogen/c_gland_gr4.pyx +605 -0
  194. hydpy/cythons/autogen/c_gland_gr5.cp313-win_amd64.pyd +0 -0
  195. hydpy/cythons/autogen/c_gland_gr5.pxd +368 -0
  196. hydpy/cythons/autogen/c_gland_gr5.pyx +568 -0
  197. hydpy/cythons/autogen/c_gland_gr6.cp313-win_amd64.pyd +0 -0
  198. hydpy/cythons/autogen/c_gland_gr6.pxd +420 -0
  199. hydpy/cythons/autogen/c_gland_gr6.pyx +673 -0
  200. hydpy/cythons/autogen/c_hland.cp313-win_amd64.pyd +0 -0
  201. hydpy/cythons/autogen/c_hland.pxd +855 -0
  202. hydpy/cythons/autogen/c_hland.pyx +2486 -0
  203. hydpy/cythons/autogen/c_hland_96.cp313-win_amd64.pyd +0 -0
  204. hydpy/cythons/autogen/c_hland_96.pxd +631 -0
  205. hydpy/cythons/autogen/c_hland_96.pyx +1724 -0
  206. hydpy/cythons/autogen/c_hland_96c.cp313-win_amd64.pyd +0 -0
  207. hydpy/cythons/autogen/c_hland_96c.pxd +621 -0
  208. hydpy/cythons/autogen/c_hland_96c.pyx +1822 -0
  209. hydpy/cythons/autogen/c_hland_96p.cp313-win_amd64.pyd +0 -0
  210. hydpy/cythons/autogen/c_hland_96p.pxd +683 -0
  211. hydpy/cythons/autogen/c_hland_96p.pyx +1911 -0
  212. hydpy/cythons/autogen/c_kinw.cp313-win_amd64.pyd +0 -0
  213. hydpy/cythons/autogen/c_kinw.pxd +509 -0
  214. hydpy/cythons/autogen/c_kinw.pyx +965 -0
  215. hydpy/cythons/autogen/c_kinw_williams.cp313-win_amd64.pyd +0 -0
  216. hydpy/cythons/autogen/c_kinw_williams.pxd +409 -0
  217. hydpy/cythons/autogen/c_kinw_williams.pyx +763 -0
  218. hydpy/cythons/autogen/c_kinw_williams_ext.cp313-win_amd64.pyd +0 -0
  219. hydpy/cythons/autogen/c_kinw_williams_ext.pxd +220 -0
  220. hydpy/cythons/autogen/c_kinw_williams_ext.pyx +440 -0
  221. hydpy/cythons/autogen/c_lland.cp313-win_amd64.pyd +0 -0
  222. hydpy/cythons/autogen/c_lland.pxd +1386 -0
  223. hydpy/cythons/autogen/c_lland.pyx +3679 -0
  224. hydpy/cythons/autogen/c_lland_dd.cp313-win_amd64.pyd +0 -0
  225. hydpy/cythons/autogen/c_lland_dd.pxd +679 -0
  226. hydpy/cythons/autogen/c_lland_dd.pyx +1719 -0
  227. hydpy/cythons/autogen/c_lland_knauf.cp313-win_amd64.pyd +0 -0
  228. hydpy/cythons/autogen/c_lland_knauf.pxd +1096 -0
  229. hydpy/cythons/autogen/c_lland_knauf.pyx +2784 -0
  230. hydpy/cythons/autogen/c_lland_knauf_ic.cp313-win_amd64.pyd +0 -0
  231. hydpy/cythons/autogen/c_lland_knauf_ic.pxd +1369 -0
  232. hydpy/cythons/autogen/c_lland_knauf_ic.pyx +3625 -0
  233. hydpy/cythons/autogen/c_meteo.cp313-win_amd64.pyd +0 -0
  234. hydpy/cythons/autogen/c_meteo.pxd +469 -0
  235. hydpy/cythons/autogen/c_meteo.pyx +879 -0
  236. hydpy/cythons/autogen/c_meteo_clear_glob_io.cp313-win_amd64.pyd +0 -0
  237. hydpy/cythons/autogen/c_meteo_clear_glob_io.pxd +75 -0
  238. hydpy/cythons/autogen/c_meteo_clear_glob_io.pyx +107 -0
  239. hydpy/cythons/autogen/c_meteo_glob_fao56.cp313-win_amd64.pyd +0 -0
  240. hydpy/cythons/autogen/c_meteo_glob_fao56.pxd +209 -0
  241. hydpy/cythons/autogen/c_meteo_glob_fao56.pyx +339 -0
  242. hydpy/cythons/autogen/c_meteo_glob_io.cp313-win_amd64.pyd +0 -0
  243. hydpy/cythons/autogen/c_meteo_glob_io.pxd +63 -0
  244. hydpy/cythons/autogen/c_meteo_glob_io.pyx +91 -0
  245. hydpy/cythons/autogen/c_meteo_glob_morsim.cp313-win_amd64.pyd +0 -0
  246. hydpy/cythons/autogen/c_meteo_glob_morsim.pxd +289 -0
  247. hydpy/cythons/autogen/c_meteo_glob_morsim.pyx +527 -0
  248. hydpy/cythons/autogen/c_meteo_precip_io.cp313-win_amd64.pyd +0 -0
  249. hydpy/cythons/autogen/c_meteo_precip_io.pxd +112 -0
  250. hydpy/cythons/autogen/c_meteo_precip_io.pyx +176 -0
  251. hydpy/cythons/autogen/c_meteo_psun_sun_glob_io.cp313-win_amd64.pyd +0 -0
  252. hydpy/cythons/autogen/c_meteo_psun_sun_glob_io.pxd +87 -0
  253. hydpy/cythons/autogen/c_meteo_psun_sun_glob_io.pyx +123 -0
  254. hydpy/cythons/autogen/c_meteo_sun_fao56.cp313-win_amd64.pyd +0 -0
  255. hydpy/cythons/autogen/c_meteo_sun_fao56.pxd +209 -0
  256. hydpy/cythons/autogen/c_meteo_sun_fao56.pyx +343 -0
  257. hydpy/cythons/autogen/c_meteo_sun_morsim.cp313-win_amd64.pyd +0 -0
  258. hydpy/cythons/autogen/c_meteo_sun_morsim.pxd +286 -0
  259. hydpy/cythons/autogen/c_meteo_sun_morsim.pyx +519 -0
  260. hydpy/cythons/autogen/c_meteo_temp_io.cp313-win_amd64.pyd +0 -0
  261. hydpy/cythons/autogen/c_meteo_temp_io.pxd +112 -0
  262. hydpy/cythons/autogen/c_meteo_temp_io.pyx +176 -0
  263. hydpy/cythons/autogen/c_musk.cp313-win_amd64.pyd +0 -0
  264. hydpy/cythons/autogen/c_musk.pxd +282 -0
  265. hydpy/cythons/autogen/c_musk.pyx +605 -0
  266. hydpy/cythons/autogen/c_musk_classic.cp313-win_amd64.pyd +0 -0
  267. hydpy/cythons/autogen/c_musk_classic.pxd +138 -0
  268. hydpy/cythons/autogen/c_musk_classic.pyx +226 -0
  269. hydpy/cythons/autogen/c_musk_mct.cp313-win_amd64.pyd +0 -0
  270. hydpy/cythons/autogen/c_musk_mct.pxd +282 -0
  271. hydpy/cythons/autogen/c_musk_mct.pyx +609 -0
  272. hydpy/cythons/autogen/c_rconc.cp313-win_amd64.pyd +0 -0
  273. hydpy/cythons/autogen/c_rconc.pxd +119 -0
  274. hydpy/cythons/autogen/c_rconc.pyx +174 -0
  275. hydpy/cythons/autogen/c_rconc_nash.cp313-win_amd64.pyd +0 -0
  276. hydpy/cythons/autogen/c_rconc_nash.pxd +111 -0
  277. hydpy/cythons/autogen/c_rconc_nash.pyx +185 -0
  278. hydpy/cythons/autogen/c_rconc_uh.cp313-win_amd64.pyd +0 -0
  279. hydpy/cythons/autogen/c_rconc_uh.pxd +92 -0
  280. hydpy/cythons/autogen/c_rconc_uh.pyx +125 -0
  281. hydpy/cythons/autogen/c_sw1d.cp313-win_amd64.pyd +0 -0
  282. hydpy/cythons/autogen/c_sw1d.pxd +511 -0
  283. hydpy/cythons/autogen/c_sw1d.pyx +1263 -0
  284. hydpy/cythons/autogen/c_sw1d_channel.cp313-win_amd64.pyd +0 -0
  285. hydpy/cythons/autogen/c_sw1d_channel.pxd +119 -0
  286. hydpy/cythons/autogen/c_sw1d_channel.pyx +300 -0
  287. hydpy/cythons/autogen/c_sw1d_gate_out.cp313-win_amd64.pyd +0 -0
  288. hydpy/cythons/autogen/c_sw1d_gate_out.pxd +240 -0
  289. hydpy/cythons/autogen/c_sw1d_gate_out.pyx +476 -0
  290. hydpy/cythons/autogen/c_sw1d_lias.cp313-win_amd64.pyd +0 -0
  291. hydpy/cythons/autogen/c_sw1d_lias.pxd +320 -0
  292. hydpy/cythons/autogen/c_sw1d_lias.pyx +619 -0
  293. hydpy/cythons/autogen/c_sw1d_lias_sluice.cp313-win_amd64.pyd +0 -0
  294. hydpy/cythons/autogen/c_sw1d_lias_sluice.pxd +325 -0
  295. hydpy/cythons/autogen/c_sw1d_lias_sluice.pyx +644 -0
  296. hydpy/cythons/autogen/c_sw1d_network.cp313-win_amd64.pyd +0 -0
  297. hydpy/cythons/autogen/c_sw1d_network.pxd +90 -0
  298. hydpy/cythons/autogen/c_sw1d_network.pyx +246 -0
  299. hydpy/cythons/autogen/c_sw1d_pump.cp313-win_amd64.pyd +0 -0
  300. hydpy/cythons/autogen/c_sw1d_pump.pxd +256 -0
  301. hydpy/cythons/autogen/c_sw1d_pump.pyx +502 -0
  302. hydpy/cythons/autogen/c_sw1d_q_in.cp313-win_amd64.pyd +0 -0
  303. hydpy/cythons/autogen/c_sw1d_q_in.pxd +224 -0
  304. hydpy/cythons/autogen/c_sw1d_q_in.pyx +383 -0
  305. hydpy/cythons/autogen/c_sw1d_q_out.cp313-win_amd64.pyd +0 -0
  306. hydpy/cythons/autogen/c_sw1d_q_out.pxd +224 -0
  307. hydpy/cythons/autogen/c_sw1d_q_out.pyx +383 -0
  308. hydpy/cythons/autogen/c_sw1d_storage.cp313-win_amd64.pyd +0 -0
  309. hydpy/cythons/autogen/c_sw1d_storage.pxd +193 -0
  310. hydpy/cythons/autogen/c_sw1d_storage.pyx +349 -0
  311. hydpy/cythons/autogen/c_sw1d_weir_out.cp313-win_amd64.pyd +0 -0
  312. hydpy/cythons/autogen/c_sw1d_weir_out.pxd +212 -0
  313. hydpy/cythons/autogen/c_sw1d_weir_out.pyx +404 -0
  314. hydpy/cythons/autogen/c_test.cp313-win_amd64.pyd +0 -0
  315. hydpy/cythons/autogen/c_test.pxd +175 -0
  316. hydpy/cythons/autogen/c_test.pyx +348 -0
  317. hydpy/cythons/autogen/c_test_discontinous.cp313-win_amd64.pyd +0 -0
  318. hydpy/cythons/autogen/c_test_discontinous.pxd +146 -0
  319. hydpy/cythons/autogen/c_test_discontinous.pyx +256 -0
  320. hydpy/cythons/autogen/c_test_stiff0d.cp313-win_amd64.pyd +0 -0
  321. hydpy/cythons/autogen/c_test_stiff0d.pxd +146 -0
  322. hydpy/cythons/autogen/c_test_stiff0d.pyx +250 -0
  323. hydpy/cythons/autogen/c_test_stiff1d.cp313-win_amd64.pyd +0 -0
  324. hydpy/cythons/autogen/c_test_stiff1d.pxd +145 -0
  325. hydpy/cythons/autogen/c_test_stiff1d.pyx +294 -0
  326. hydpy/cythons/autogen/c_whmod.cp313-win_amd64.pyd +0 -0
  327. hydpy/cythons/autogen/c_whmod.pxd +482 -0
  328. hydpy/cythons/autogen/c_whmod.pyx +1156 -0
  329. hydpy/cythons/autogen/c_whmod_rural.cp313-win_amd64.pyd +0 -0
  330. hydpy/cythons/autogen/c_whmod_rural.pxd +411 -0
  331. hydpy/cythons/autogen/c_whmod_rural.pyx +982 -0
  332. hydpy/cythons/autogen/c_whmod_urban.cp313-win_amd64.pyd +0 -0
  333. hydpy/cythons/autogen/c_whmod_urban.pxd +482 -0
  334. hydpy/cythons/autogen/c_whmod_urban.pyx +1155 -0
  335. hydpy/cythons/autogen/c_wland.cp313-win_amd64.pyd +0 -0
  336. hydpy/cythons/autogen/c_wland.pxd +842 -0
  337. hydpy/cythons/autogen/c_wland.pyx +1890 -0
  338. hydpy/cythons/autogen/c_wland_gd.cp313-win_amd64.pyd +0 -0
  339. hydpy/cythons/autogen/c_wland_gd.pxd +829 -0
  340. hydpy/cythons/autogen/c_wland_gd.pyx +1847 -0
  341. hydpy/cythons/autogen/c_wland_wag.cp313-win_amd64.pyd +0 -0
  342. hydpy/cythons/autogen/c_wland_wag.pxd +810 -0
  343. hydpy/cythons/autogen/c_wland_wag.pyx +1780 -0
  344. hydpy/cythons/autogen/c_wq.cp313-win_amd64.pyd +0 -0
  345. hydpy/cythons/autogen/c_wq.pxd +275 -0
  346. hydpy/cythons/autogen/c_wq.pyx +652 -0
  347. hydpy/cythons/autogen/c_wq_trapeze.cp313-win_amd64.pyd +0 -0
  348. hydpy/cythons/autogen/c_wq_trapeze.pxd +170 -0
  349. hydpy/cythons/autogen/c_wq_trapeze.pyx +400 -0
  350. hydpy/cythons/autogen/c_wq_trapeze_strickler.cp313-win_amd64.pyd +0 -0
  351. hydpy/cythons/autogen/c_wq_trapeze_strickler.pxd +243 -0
  352. hydpy/cythons/autogen/c_wq_trapeze_strickler.pyx +578 -0
  353. hydpy/cythons/autogen/c_wq_walrus.cp313-win_amd64.pyd +0 -0
  354. hydpy/cythons/autogen/c_wq_walrus.pxd +61 -0
  355. hydpy/cythons/autogen/c_wq_walrus.pyx +82 -0
  356. hydpy/cythons/autogen/configutils.cp313-win_amd64.pyd +0 -0
  357. hydpy/cythons/autogen/configutils.pxd +17 -0
  358. hydpy/cythons/autogen/configutils.pyx +119 -0
  359. hydpy/cythons/autogen/interfaceutils.cp313-win_amd64.pyd +0 -0
  360. hydpy/cythons/autogen/interfaceutils.pxd +31 -0
  361. hydpy/cythons/autogen/interfaceutils.pyx +82 -0
  362. hydpy/cythons/autogen/interputils.cp313-win_amd64.pyd +0 -0
  363. hydpy/cythons/autogen/interputils.pxd +42 -0
  364. hydpy/cythons/autogen/interputils.pyx +118 -0
  365. hydpy/cythons/autogen/masterinterface.cp313-win_amd64.pyd +0 -0
  366. hydpy/cythons/autogen/masterinterface.pxd +153 -0
  367. hydpy/cythons/autogen/masterinterface.pyx +222 -0
  368. hydpy/cythons/autogen/pointerutils.cp313-win_amd64.pyd +0 -0
  369. hydpy/cythons/autogen/pointerutils.pxd +31 -0
  370. hydpy/cythons/autogen/pointerutils.pyx +650 -0
  371. hydpy/cythons/autogen/ppolyutils.cp313-win_amd64.pyd +0 -0
  372. hydpy/cythons/autogen/ppolyutils.pxd +35 -0
  373. hydpy/cythons/autogen/ppolyutils.pyx +59 -0
  374. hydpy/cythons/autogen/quadutils.cp313-win_amd64.pyd +0 -0
  375. hydpy/cythons/autogen/quadutils.pxd +26 -0
  376. hydpy/cythons/autogen/quadutils.pyx +973 -0
  377. hydpy/cythons/autogen/rootutils.cp313-win_amd64.pyd +0 -0
  378. hydpy/cythons/autogen/rootutils.pxd +28 -0
  379. hydpy/cythons/autogen/rootutils.pyx +109 -0
  380. hydpy/cythons/autogen/sequenceutils.cp313-win_amd64.pyd +0 -0
  381. hydpy/cythons/autogen/sequenceutils.pxd +45 -0
  382. hydpy/cythons/autogen/sequenceutils.pyx +101 -0
  383. hydpy/cythons/autogen/smoothutils.cp313-win_amd64.pyd +0 -0
  384. hydpy/cythons/autogen/smoothutils.pxd +29 -0
  385. hydpy/cythons/autogen/smoothutils.pyx +833 -0
  386. hydpy/cythons/configutils.pxd +8 -0
  387. hydpy/cythons/configutils.pyi +5 -0
  388. hydpy/cythons/configutils.pyx +110 -0
  389. hydpy/cythons/interfaceutils.pxd +22 -0
  390. hydpy/cythons/interfaceutils.pyi +15 -0
  391. hydpy/cythons/interfaceutils.pyx +73 -0
  392. hydpy/cythons/interputils.pxd +33 -0
  393. hydpy/cythons/interputils.pyi +32 -0
  394. hydpy/cythons/interputils.pyx +109 -0
  395. hydpy/cythons/modelutils.py +2990 -0
  396. hydpy/cythons/pointerutils.pxd +22 -0
  397. hydpy/cythons/pointerutils.pyi +89 -0
  398. hydpy/cythons/pointerutils.pyx +641 -0
  399. hydpy/cythons/ppolyutils.pxd +26 -0
  400. hydpy/cythons/ppolyutils.pyi +21 -0
  401. hydpy/cythons/ppolyutils.pyx +50 -0
  402. hydpy/cythons/quadutils.pxd +17 -0
  403. hydpy/cythons/quadutils.pyi +13 -0
  404. hydpy/cythons/quadutils.pyx +964 -0
  405. hydpy/cythons/rootutils.pxd +19 -0
  406. hydpy/cythons/rootutils.pyi +21 -0
  407. hydpy/cythons/rootutils.pyx +100 -0
  408. hydpy/cythons/sequenceutils.pxd +36 -0
  409. hydpy/cythons/sequenceutils.pyi +7 -0
  410. hydpy/cythons/sequenceutils.pyx +92 -0
  411. hydpy/cythons/smoothutils.pxd +20 -0
  412. hydpy/cythons/smoothutils.pyi +15 -0
  413. hydpy/cythons/smoothutils.pyx +824 -0
  414. hydpy/data/HydPy-H-Lahn/conditions/init_1996_01_01_00_00_00/land_dill_assl.py +13 -0
  415. hydpy/data/HydPy-H-Lahn/conditions/init_1996_01_01_00_00_00/land_lahn_kalk.py +13 -0
  416. hydpy/data/HydPy-H-Lahn/conditions/init_1996_01_01_00_00_00/land_lahn_leun.py +14 -0
  417. hydpy/data/HydPy-H-Lahn/conditions/init_1996_01_01_00_00_00/land_lahn_marb.py +13 -0
  418. hydpy/data/HydPy-H-Lahn/conditions/init_1996_01_01_00_00_00/stream_dill_assl_lahn_leun.py +5 -0
  419. hydpy/data/HydPy-H-Lahn/conditions/init_1996_01_01_00_00_00/stream_lahn_leun_lahn_kalk.py +5 -0
  420. hydpy/data/HydPy-H-Lahn/conditions/init_1996_01_01_00_00_00/stream_lahn_marb_lahn_leun.py +5 -0
  421. hydpy/data/HydPy-H-Lahn/control/default/land.py +9 -0
  422. hydpy/data/HydPy-H-Lahn/control/default/land_dill_assl.py +57 -0
  423. hydpy/data/HydPy-H-Lahn/control/default/land_lahn_kalk.py +57 -0
  424. hydpy/data/HydPy-H-Lahn/control/default/land_lahn_leun.py +56 -0
  425. hydpy/data/HydPy-H-Lahn/control/default/land_lahn_marb.py +57 -0
  426. hydpy/data/HydPy-H-Lahn/control/default/stream_dill_assl_lahn_leun.py +7 -0
  427. hydpy/data/HydPy-H-Lahn/control/default/stream_lahn_leun_lahn_kalk.py +7 -0
  428. hydpy/data/HydPy-H-Lahn/control/default/stream_lahn_marb_lahn_leun.py +7 -0
  429. hydpy/data/HydPy-H-Lahn/multiple_runs.xml +309 -0
  430. hydpy/data/HydPy-H-Lahn/multiple_runs_alpha.xml +71 -0
  431. hydpy/data/HydPy-H-Lahn/network/default/headwaters.py +11 -0
  432. hydpy/data/HydPy-H-Lahn/network/default/nonheadwaters.py +11 -0
  433. hydpy/data/HydPy-H-Lahn/network/default/streams.py +8 -0
  434. hydpy/data/HydPy-H-Lahn/series/default/dill_assl_obs_q.asc +11387 -0
  435. hydpy/data/HydPy-H-Lahn/series/default/evap_pet_hbv96_input_normalairtemperature.nc +0 -0
  436. hydpy/data/HydPy-H-Lahn/series/default/evap_pet_hbv96_input_normalevapotranspiration.nc +0 -0
  437. hydpy/data/HydPy-H-Lahn/series/default/hland_96_input_p.nc +0 -0
  438. hydpy/data/HydPy-H-Lahn/series/default/hland_96_input_t.nc +0 -0
  439. hydpy/data/HydPy-H-Lahn/series/default/lahn_kalk_obs_q.asc +11387 -0
  440. hydpy/data/HydPy-H-Lahn/series/default/lahn_leun_obs_q.asc +11387 -0
  441. hydpy/data/HydPy-H-Lahn/series/default/lahn_marb_obs_q.asc +11387 -0
  442. hydpy/data/HydPy-H-Lahn/series/default/land_dill_assl_evap_pet_hbv96_input_normalairtemperature.asc +11387 -0
  443. hydpy/data/HydPy-H-Lahn/series/default/land_dill_assl_evap_pet_hbv96_input_normalevapotranspiration.asc +11387 -0
  444. hydpy/data/HydPy-H-Lahn/series/default/land_dill_assl_hland_96_input_p.asc +11387 -0
  445. hydpy/data/HydPy-H-Lahn/series/default/land_dill_assl_hland_96_input_t.asc +11387 -0
  446. hydpy/data/HydPy-H-Lahn/series/default/land_lahn_kalk_evap_pet_hbv96_input_normalairtemperature.asc +11387 -0
  447. hydpy/data/HydPy-H-Lahn/series/default/land_lahn_kalk_evap_pet_hbv96_input_normalevapotranspiration.asc +11387 -0
  448. hydpy/data/HydPy-H-Lahn/series/default/land_lahn_kalk_hland_96_input_p.asc +11387 -0
  449. hydpy/data/HydPy-H-Lahn/series/default/land_lahn_kalk_hland_96_input_t.asc +11387 -0
  450. hydpy/data/HydPy-H-Lahn/series/default/land_lahn_leun_evap_pet_hbv96_input_normalairtemperature.asc +11387 -0
  451. hydpy/data/HydPy-H-Lahn/series/default/land_lahn_leun_evap_pet_hbv96_input_normalevapotranspiration.asc +11387 -0
  452. hydpy/data/HydPy-H-Lahn/series/default/land_lahn_leun_hland_96_input_p.asc +11387 -0
  453. hydpy/data/HydPy-H-Lahn/series/default/land_lahn_leun_hland_96_input_t.asc +11387 -0
  454. hydpy/data/HydPy-H-Lahn/series/default/land_lahn_marb_evap_pet_hbv96_input_normalairtemperature.asc +11387 -0
  455. hydpy/data/HydPy-H-Lahn/series/default/land_lahn_marb_evap_pet_hbv96_input_normalevapotranspiration.asc +11387 -0
  456. hydpy/data/HydPy-H-Lahn/series/default/land_lahn_marb_hland_96_input_p.asc +11387 -0
  457. hydpy/data/HydPy-H-Lahn/series/default/land_lahn_marb_hland_96_input_t.asc +11387 -0
  458. hydpy/data/HydPy-H-Lahn/series/default/obs_q.nc +0 -0
  459. hydpy/data/HydPy-H-Lahn/single_run.xml +152 -0
  460. hydpy/data/HydPy-H-Lahn/single_run.xmlt +143 -0
  461. hydpy/data/__init__.py +17 -0
  462. hydpy/docs/__init__.py +0 -0
  463. hydpy/docs/autofigs/__init__.py +0 -0
  464. hydpy/docs/bib/__init__.py +0 -0
  465. hydpy/docs/bib/refs.bib +566 -0
  466. hydpy/docs/combine_docversions.py +133 -0
  467. hydpy/docs/draw_model_sketches.py +1301 -0
  468. hydpy/docs/enable_autodoc.py +7 -0
  469. hydpy/docs/figs/HydPy-G-GR4.png +0 -0
  470. hydpy/docs/figs/HydPy-G-GR5.png +0 -0
  471. hydpy/docs/figs/HydPy-G-GR6.png +0 -0
  472. hydpy/docs/figs/HydPy-H-HBV96-COSERO.png +0 -0
  473. hydpy/docs/figs/HydPy-H-HBV96-PREVAH.png +0 -0
  474. hydpy/docs/figs/HydPy-H-HBV96.png +0 -0
  475. hydpy/docs/figs/HydPy-H-Lahn.png +0 -0
  476. hydpy/docs/figs/HydPy-KinW-Williams.png +0 -0
  477. hydpy/docs/figs/HydPy-L-DD.png +0 -0
  478. hydpy/docs/figs/HydPy-W-Wag.png +0 -0
  479. hydpy/docs/figs/HydPy_Logo.png +0 -0
  480. hydpy/docs/figs/HydPy_Logo_Text.png +0 -0
  481. hydpy/docs/figs/IDLE-editor.png +0 -0
  482. hydpy/docs/figs/IDLE-shell.png +0 -0
  483. hydpy/docs/figs/LAWA_river-basin-bumbers.png +0 -0
  484. hydpy/docs/figs/__init__.py +0 -0
  485. hydpy/docs/html_/__init__.py +0 -0
  486. hydpy/docs/polish_html.py +57 -0
  487. hydpy/docs/prepare.py +224 -0
  488. hydpy/docs/publish_docs.py +53 -0
  489. hydpy/docs/rst/HydPy-ARMA.rst +27 -0
  490. hydpy/docs/rst/HydPy-Conv.rst +22 -0
  491. hydpy/docs/rst/HydPy-Dam.rst +79 -0
  492. hydpy/docs/rst/HydPy-Dummy.rst +21 -0
  493. hydpy/docs/rst/HydPy-Evap.rst +26 -0
  494. hydpy/docs/rst/HydPy-Exch.rst +36 -0
  495. hydpy/docs/rst/HydPy-G.rst +40 -0
  496. hydpy/docs/rst/HydPy-GA.rst +34 -0
  497. hydpy/docs/rst/HydPy-H.rst +24 -0
  498. hydpy/docs/rst/HydPy-KinW.rst +32 -0
  499. hydpy/docs/rst/HydPy-L.rst +42 -0
  500. hydpy/docs/rst/HydPy-Meteo.rst +28 -0
  501. hydpy/docs/rst/HydPy-Musk.rst +21 -0
  502. hydpy/docs/rst/HydPy-Rconc.rst +17 -0
  503. hydpy/docs/rst/HydPy-SW1D.rst +49 -0
  504. hydpy/docs/rst/HydPy-Test.rst +19 -0
  505. hydpy/docs/rst/HydPy-W.rst +20 -0
  506. hydpy/docs/rst/HydPy-WHMod.rst +19 -0
  507. hydpy/docs/rst/HydPy-WQ.rst +20 -0
  508. hydpy/docs/rst/__init__.py +0 -0
  509. hydpy/docs/rst/additional_repositories.rst +40 -0
  510. hydpy/docs/rst/auxiliaries.rst +31 -0
  511. hydpy/docs/rst/continuous_integration.rst +75 -0
  512. hydpy/docs/rst/core.rst +75 -0
  513. hydpy/docs/rst/cythons.rst +47 -0
  514. hydpy/docs/rst/definitions.rst +506 -0
  515. hydpy/docs/rst/developer_guide.rst +54 -0
  516. hydpy/docs/rst/example_projects.rst +40 -0
  517. hydpy/docs/rst/execution.rst +22 -0
  518. hydpy/docs/rst/framework_tools.rst +56 -0
  519. hydpy/docs/rst/how_to_read_the_reference_manual.rst +156 -0
  520. hydpy/docs/rst/hydpydependencies.rst +55 -0
  521. hydpy/docs/rst/index.rst +125 -0
  522. hydpy/docs/rst/installation.rst +155 -0
  523. hydpy/docs/rst/model_families.rst +79 -0
  524. hydpy/docs/rst/model_overview.rst +291 -0
  525. hydpy/docs/rst/modelimports.rst +10 -0
  526. hydpy/docs/rst/options.rst +119 -0
  527. hydpy/docs/rst/programming_style.rst +572 -0
  528. hydpy/docs/rst/project_structure.rst +520 -0
  529. hydpy/docs/rst/quickstart.rst +304 -0
  530. hydpy/docs/rst/reference_manual.rst +29 -0
  531. hydpy/docs/rst/required_tools.rst +50 -0
  532. hydpy/docs/rst/simulation.rst +514 -0
  533. hydpy/docs/rst/submodel_interfaces.rst +32 -0
  534. hydpy/docs/rst/tests_and_documentation.rst +85 -0
  535. hydpy/docs/rst/user_guide.rst +38 -0
  536. hydpy/docs/rst/version_control.rst +116 -0
  537. hydpy/docs/rst/zbibliography.rst +8 -0
  538. hydpy/docs/sphinx/__init__.py +0 -0
  539. hydpy/docs/sphinx/_themes/basic_hydpy/changes/frameset.html +11 -0
  540. hydpy/docs/sphinx/_themes/basic_hydpy/changes/rstsource.html +15 -0
  541. hydpy/docs/sphinx/_themes/basic_hydpy/changes/versionchanges.html +33 -0
  542. hydpy/docs/sphinx/_themes/basic_hydpy/defindex.html +35 -0
  543. hydpy/docs/sphinx/_themes/basic_hydpy/domainindex.html +56 -0
  544. hydpy/docs/sphinx/_themes/basic_hydpy/genindex-single.html +63 -0
  545. hydpy/docs/sphinx/_themes/basic_hydpy/genindex-split.html +41 -0
  546. hydpy/docs/sphinx/_themes/basic_hydpy/genindex.html +76 -0
  547. hydpy/docs/sphinx/_themes/basic_hydpy/globaltoc.html +11 -0
  548. hydpy/docs/sphinx/_themes/basic_hydpy/layout.html +221 -0
  549. hydpy/docs/sphinx/_themes/basic_hydpy/localtoc.html +15 -0
  550. hydpy/docs/sphinx/_themes/basic_hydpy/opensearch.xml +13 -0
  551. hydpy/docs/sphinx/_themes/basic_hydpy/page.html +13 -0
  552. hydpy/docs/sphinx/_themes/basic_hydpy/relations.html +23 -0
  553. hydpy/docs/sphinx/_themes/basic_hydpy/search.html +65 -0
  554. hydpy/docs/sphinx/_themes/basic_hydpy/searchbox.html +21 -0
  555. hydpy/docs/sphinx/_themes/basic_hydpy/searchfield.html +23 -0
  556. hydpy/docs/sphinx/_themes/basic_hydpy/sourcelink.html +18 -0
  557. hydpy/docs/sphinx/_themes/basic_hydpy/static/basic.css_t +925 -0
  558. hydpy/docs/sphinx/_themes/basic_hydpy/static/doctools.js +156 -0
  559. hydpy/docs/sphinx/_themes/basic_hydpy/static/documentation_options.js_t +13 -0
  560. hydpy/docs/sphinx/_themes/basic_hydpy/static/file.png +0 -0
  561. hydpy/docs/sphinx/_themes/basic_hydpy/static/language_data.js_t +26 -0
  562. hydpy/docs/sphinx/_themes/basic_hydpy/static/minus.png +0 -0
  563. hydpy/docs/sphinx/_themes/basic_hydpy/static/plus.png +0 -0
  564. hydpy/docs/sphinx/_themes/basic_hydpy/static/searchtools.js +574 -0
  565. hydpy/docs/sphinx/_themes/basic_hydpy/static/sphinx_highlight.js +154 -0
  566. hydpy/docs/sphinx/_themes/basic_hydpy/theme.conf +16 -0
  567. hydpy/docs/sphinx/_themes/classic_hydpy/layout.html +23 -0
  568. hydpy/docs/sphinx/_themes/classic_hydpy/static/classic.css_t +358 -0
  569. hydpy/docs/sphinx/_themes/classic_hydpy/static/sidebar.js_t +72 -0
  570. hydpy/docs/sphinx/_themes/classic_hydpy/theme.conf +32 -0
  571. hydpy/docs/sphinx/conf.py +398 -0
  572. hydpy/docs/sphinx/defaultlinks_extension.py +36 -0
  573. hydpy/docs/sphinx/integrationtest_extension.py +104 -0
  574. hydpy/docs/sphinx/projectstructure_extension.py +58 -0
  575. hydpy/docs/sphinx/submodelgraph_extension.py +53 -0
  576. hydpy/exe/__init__.py +0 -0
  577. hydpy/exe/commandtools.py +651 -0
  578. hydpy/exe/hyd.py +277 -0
  579. hydpy/exe/modelimports.py +41 -0
  580. hydpy/exe/replacetools.py +216 -0
  581. hydpy/exe/servertools.py +2348 -0
  582. hydpy/exe/xmltools.py +3280 -0
  583. hydpy/interfaces/__init__.py +0 -0
  584. hydpy/interfaces/aetinterfaces.py +94 -0
  585. hydpy/interfaces/dischargeinterfaces.py +45 -0
  586. hydpy/interfaces/petinterfaces.py +117 -0
  587. hydpy/interfaces/precipinterfaces.py +42 -0
  588. hydpy/interfaces/radiationinterfaces.py +79 -0
  589. hydpy/interfaces/rconcinterfaces.py +30 -0
  590. hydpy/interfaces/routinginterfaces.py +324 -0
  591. hydpy/interfaces/soilinterfaces.py +96 -0
  592. hydpy/interfaces/stateinterfaces.py +98 -0
  593. hydpy/interfaces/tempinterfaces.py +46 -0
  594. hydpy/models/__init__.py +0 -0
  595. hydpy/models/arma/__init__.py +14 -0
  596. hydpy/models/arma/arma_control.py +383 -0
  597. hydpy/models/arma/arma_derived.py +204 -0
  598. hydpy/models/arma/arma_fluxes.py +41 -0
  599. hydpy/models/arma/arma_inlets.py +11 -0
  600. hydpy/models/arma/arma_logs.py +19 -0
  601. hydpy/models/arma/arma_model.py +461 -0
  602. hydpy/models/arma/arma_outlets.py +11 -0
  603. hydpy/models/arma_rimorido.py +381 -0
  604. hydpy/models/conv/__init__.py +12 -0
  605. hydpy/models/conv/conv_control.py +303 -0
  606. hydpy/models/conv/conv_derived.py +271 -0
  607. hydpy/models/conv/conv_fluxes.py +54 -0
  608. hydpy/models/conv/conv_inlets.py +11 -0
  609. hydpy/models/conv/conv_model.py +687 -0
  610. hydpy/models/conv/conv_outlets.py +11 -0
  611. hydpy/models/conv_idw.py +120 -0
  612. hydpy/models/conv_idw_ed.py +184 -0
  613. hydpy/models/conv_nn.py +112 -0
  614. hydpy/models/dam/__init__.py +16 -0
  615. hydpy/models/dam/dam_aides.py +17 -0
  616. hydpy/models/dam/dam_control.py +346 -0
  617. hydpy/models/dam/dam_derived.py +559 -0
  618. hydpy/models/dam/dam_factors.py +46 -0
  619. hydpy/models/dam/dam_fluxes.py +179 -0
  620. hydpy/models/dam/dam_inlets.py +29 -0
  621. hydpy/models/dam/dam_logs.py +52 -0
  622. hydpy/models/dam/dam_model.py +5011 -0
  623. hydpy/models/dam/dam_outlets.py +23 -0
  624. hydpy/models/dam/dam_receivers.py +41 -0
  625. hydpy/models/dam/dam_senders.py +23 -0
  626. hydpy/models/dam/dam_solver.py +75 -0
  627. hydpy/models/dam/dam_states.py +11 -0
  628. hydpy/models/dam_llake.py +499 -0
  629. hydpy/models/dam_lreservoir.py +548 -0
  630. hydpy/models/dam_lretention.py +343 -0
  631. hydpy/models/dam_pump.py +278 -0
  632. hydpy/models/dam_pump_sluice.py +339 -0
  633. hydpy/models/dam_sluice.py +319 -0
  634. hydpy/models/dam_v001.py +1127 -0
  635. hydpy/models/dam_v002.py +381 -0
  636. hydpy/models/dam_v003.py +422 -0
  637. hydpy/models/dam_v004.py +665 -0
  638. hydpy/models/dam_v005.py +479 -0
  639. hydpy/models/dummy/__init__.py +15 -0
  640. hydpy/models/dummy/dummy_control.py +22 -0
  641. hydpy/models/dummy/dummy_fluxes.py +11 -0
  642. hydpy/models/dummy/dummy_inlets.py +11 -0
  643. hydpy/models/dummy/dummy_inputs.py +41 -0
  644. hydpy/models/dummy/dummy_model.py +196 -0
  645. hydpy/models/dummy/dummy_outlets.py +11 -0
  646. hydpy/models/dummy_interceptedwater.py +85 -0
  647. hydpy/models/dummy_node2node.py +83 -0
  648. hydpy/models/dummy_snowalbedo.py +84 -0
  649. hydpy/models/dummy_snowcover.py +84 -0
  650. hydpy/models/dummy_snowycanopy.py +86 -0
  651. hydpy/models/dummy_soilwater.py +85 -0
  652. hydpy/models/evap/__init__.py +13 -0
  653. hydpy/models/evap/evap_control.py +354 -0
  654. hydpy/models/evap/evap_derived.py +236 -0
  655. hydpy/models/evap/evap_factors.py +188 -0
  656. hydpy/models/evap/evap_fixed.py +68 -0
  657. hydpy/models/evap/evap_fluxes.py +150 -0
  658. hydpy/models/evap/evap_inputs.py +54 -0
  659. hydpy/models/evap/evap_logs.py +91 -0
  660. hydpy/models/evap/evap_masks.py +48 -0
  661. hydpy/models/evap/evap_model.py +9170 -0
  662. hydpy/models/evap/evap_parameters.py +149 -0
  663. hydpy/models/evap/evap_sequences.py +32 -0
  664. hydpy/models/evap/evap_states.py +18 -0
  665. hydpy/models/evap_aet_hbv96.py +372 -0
  666. hydpy/models/evap_aet_minhas.py +331 -0
  667. hydpy/models/evap_aet_morsim.py +627 -0
  668. hydpy/models/evap_pet_ambav1.py +483 -0
  669. hydpy/models/evap_pet_hbv96.py +147 -0
  670. hydpy/models/evap_pet_m.py +94 -0
  671. hydpy/models/evap_pet_mlc.py +107 -0
  672. hydpy/models/evap_ret_fao56.py +265 -0
  673. hydpy/models/evap_ret_io.py +74 -0
  674. hydpy/models/evap_ret_tw2002.py +165 -0
  675. hydpy/models/exch/__init__.py +14 -0
  676. hydpy/models/exch/exch_control.py +262 -0
  677. hydpy/models/exch/exch_derived.py +36 -0
  678. hydpy/models/exch/exch_factors.py +26 -0
  679. hydpy/models/exch/exch_fluxes.py +48 -0
  680. hydpy/models/exch/exch_inlets.py +11 -0
  681. hydpy/models/exch/exch_logs.py +12 -0
  682. hydpy/models/exch/exch_model.py +451 -0
  683. hydpy/models/exch/exch_outlets.py +17 -0
  684. hydpy/models/exch/exch_receivers.py +17 -0
  685. hydpy/models/exch_branch_hbv96.py +186 -0
  686. hydpy/models/exch_waterlevel.py +73 -0
  687. hydpy/models/exch_weir_hbv96.py +609 -0
  688. hydpy/models/ga/__init__.py +14 -0
  689. hydpy/models/ga/ga_aides.py +17 -0
  690. hydpy/models/ga/ga_control.py +208 -0
  691. hydpy/models/ga/ga_derived.py +77 -0
  692. hydpy/models/ga/ga_fluxes.py +83 -0
  693. hydpy/models/ga/ga_inputs.py +26 -0
  694. hydpy/models/ga/ga_logs.py +17 -0
  695. hydpy/models/ga/ga_model.py +2952 -0
  696. hydpy/models/ga/ga_states.py +87 -0
  697. hydpy/models/ga_garto.py +1001 -0
  698. hydpy/models/ga_garto_submodel1.py +79 -0
  699. hydpy/models/gland/__init__.py +14 -0
  700. hydpy/models/gland/gland_control.py +90 -0
  701. hydpy/models/gland/gland_derived.py +113 -0
  702. hydpy/models/gland/gland_fluxes.py +137 -0
  703. hydpy/models/gland/gland_inputs.py +12 -0
  704. hydpy/models/gland/gland_model.py +1439 -0
  705. hydpy/models/gland/gland_outlets.py +11 -0
  706. hydpy/models/gland/gland_states.py +90 -0
  707. hydpy/models/gland_gr4.py +501 -0
  708. hydpy/models/gland_gr5.py +463 -0
  709. hydpy/models/gland_gr6.py +487 -0
  710. hydpy/models/hland/__init__.py +20 -0
  711. hydpy/models/hland/hland_aides.py +19 -0
  712. hydpy/models/hland/hland_constants.py +37 -0
  713. hydpy/models/hland/hland_control.py +1530 -0
  714. hydpy/models/hland/hland_derived.py +683 -0
  715. hydpy/models/hland/hland_factors.py +57 -0
  716. hydpy/models/hland/hland_fixed.py +42 -0
  717. hydpy/models/hland/hland_fluxes.py +279 -0
  718. hydpy/models/hland/hland_inputs.py +19 -0
  719. hydpy/models/hland/hland_masks.py +107 -0
  720. hydpy/models/hland/hland_model.py +4664 -0
  721. hydpy/models/hland/hland_outlets.py +11 -0
  722. hydpy/models/hland/hland_parameters.py +227 -0
  723. hydpy/models/hland/hland_sequences.py +382 -0
  724. hydpy/models/hland/hland_states.py +236 -0
  725. hydpy/models/hland_96.py +1812 -0
  726. hydpy/models/hland_96c.py +1196 -0
  727. hydpy/models/hland_96p.py +1204 -0
  728. hydpy/models/kinw/__init__.py +18 -0
  729. hydpy/models/kinw/kinw_aides.py +306 -0
  730. hydpy/models/kinw/kinw_control.py +270 -0
  731. hydpy/models/kinw/kinw_derived.py +197 -0
  732. hydpy/models/kinw/kinw_fixed.py +33 -0
  733. hydpy/models/kinw/kinw_fluxes.py +37 -0
  734. hydpy/models/kinw/kinw_inlets.py +11 -0
  735. hydpy/models/kinw/kinw_model.py +3026 -0
  736. hydpy/models/kinw/kinw_outlets.py +11 -0
  737. hydpy/models/kinw/kinw_solver.py +45 -0
  738. hydpy/models/kinw/kinw_states.py +17 -0
  739. hydpy/models/kinw_williams.py +1299 -0
  740. hydpy/models/kinw_williams_ext.py +768 -0
  741. hydpy/models/lland/__init__.py +42 -0
  742. hydpy/models/lland/lland_aides.py +38 -0
  743. hydpy/models/lland/lland_constants.py +88 -0
  744. hydpy/models/lland/lland_control.py +1329 -0
  745. hydpy/models/lland/lland_derived.py +380 -0
  746. hydpy/models/lland/lland_factors.py +18 -0
  747. hydpy/models/lland/lland_fixed.py +128 -0
  748. hydpy/models/lland/lland_fluxes.py +626 -0
  749. hydpy/models/lland/lland_inlets.py +12 -0
  750. hydpy/models/lland/lland_inputs.py +33 -0
  751. hydpy/models/lland/lland_logs.py +17 -0
  752. hydpy/models/lland/lland_masks.py +212 -0
  753. hydpy/models/lland/lland_model.py +7690 -0
  754. hydpy/models/lland/lland_outlets.py +12 -0
  755. hydpy/models/lland/lland_parameters.py +195 -0
  756. hydpy/models/lland/lland_sequences.py +67 -0
  757. hydpy/models/lland/lland_states.py +280 -0
  758. hydpy/models/lland_dd.py +2270 -0
  759. hydpy/models/lland_knauf.py +2156 -0
  760. hydpy/models/lland_knauf_ic.py +1920 -0
  761. hydpy/models/meteo/__init__.py +12 -0
  762. hydpy/models/meteo/meteo_control.py +154 -0
  763. hydpy/models/meteo/meteo_derived.py +159 -0
  764. hydpy/models/meteo/meteo_factors.py +88 -0
  765. hydpy/models/meteo/meteo_fixed.py +19 -0
  766. hydpy/models/meteo/meteo_fluxes.py +46 -0
  767. hydpy/models/meteo/meteo_inputs.py +47 -0
  768. hydpy/models/meteo/meteo_logs.py +30 -0
  769. hydpy/models/meteo/meteo_model.py +2904 -0
  770. hydpy/models/meteo/meteo_parameters.py +14 -0
  771. hydpy/models/meteo/meteo_sequences.py +22 -0
  772. hydpy/models/meteo_clear_glob_io.py +77 -0
  773. hydpy/models/meteo_glob_fao56.py +217 -0
  774. hydpy/models/meteo_glob_io.py +68 -0
  775. hydpy/models/meteo_glob_morsim.py +444 -0
  776. hydpy/models/meteo_precip_io.py +76 -0
  777. hydpy/models/meteo_psun_sun_glob_io.py +83 -0
  778. hydpy/models/meteo_sun_fao56.py +188 -0
  779. hydpy/models/meteo_sun_morsim.py +466 -0
  780. hydpy/models/meteo_temp_io.py +76 -0
  781. hydpy/models/musk/__init__.py +15 -0
  782. hydpy/models/musk/musk_control.py +328 -0
  783. hydpy/models/musk/musk_derived.py +32 -0
  784. hydpy/models/musk/musk_factors.py +53 -0
  785. hydpy/models/musk/musk_fluxes.py +24 -0
  786. hydpy/models/musk/musk_inlets.py +11 -0
  787. hydpy/models/musk/musk_masks.py +15 -0
  788. hydpy/models/musk/musk_model.py +838 -0
  789. hydpy/models/musk/musk_outlets.py +11 -0
  790. hydpy/models/musk/musk_sequences.py +88 -0
  791. hydpy/models/musk/musk_solver.py +68 -0
  792. hydpy/models/musk/musk_states.py +64 -0
  793. hydpy/models/musk_classic.py +228 -0
  794. hydpy/models/musk_mct.py +1247 -0
  795. hydpy/models/rconc/__init__.py +12 -0
  796. hydpy/models/rconc/rconc_control.py +473 -0
  797. hydpy/models/rconc/rconc_derived.py +76 -0
  798. hydpy/models/rconc/rconc_fluxes.py +19 -0
  799. hydpy/models/rconc/rconc_logs.py +74 -0
  800. hydpy/models/rconc/rconc_model.py +260 -0
  801. hydpy/models/rconc/rconc_states.py +11 -0
  802. hydpy/models/rconc_nash.py +48 -0
  803. hydpy/models/rconc_uh.py +53 -0
  804. hydpy/models/sw1d/__init__.py +17 -0
  805. hydpy/models/sw1d/sw1d_control.py +356 -0
  806. hydpy/models/sw1d/sw1d_derived.py +85 -0
  807. hydpy/models/sw1d/sw1d_factors.py +78 -0
  808. hydpy/models/sw1d/sw1d_fixed.py +12 -0
  809. hydpy/models/sw1d/sw1d_fluxes.py +55 -0
  810. hydpy/models/sw1d/sw1d_inlets.py +17 -0
  811. hydpy/models/sw1d/sw1d_model.py +3385 -0
  812. hydpy/models/sw1d/sw1d_outlets.py +11 -0
  813. hydpy/models/sw1d/sw1d_receivers.py +11 -0
  814. hydpy/models/sw1d/sw1d_senders.py +11 -0
  815. hydpy/models/sw1d/sw1d_states.py +23 -0
  816. hydpy/models/sw1d_channel.py +2051 -0
  817. hydpy/models/sw1d_gate_out.py +599 -0
  818. hydpy/models/sw1d_lias.py +105 -0
  819. hydpy/models/sw1d_lias_sluice.py +531 -0
  820. hydpy/models/sw1d_network.py +1219 -0
  821. hydpy/models/sw1d_pump.py +448 -0
  822. hydpy/models/sw1d_q_in.py +79 -0
  823. hydpy/models/sw1d_q_out.py +81 -0
  824. hydpy/models/sw1d_storage.py +78 -0
  825. hydpy/models/sw1d_weir_out.py +75 -0
  826. hydpy/models/test/__init__.py +14 -0
  827. hydpy/models/test/test_control.py +28 -0
  828. hydpy/models/test/test_fluxes.py +17 -0
  829. hydpy/models/test/test_model.py +201 -0
  830. hydpy/models/test/test_solver.py +48 -0
  831. hydpy/models/test/test_states.py +17 -0
  832. hydpy/models/test_discontinous.py +46 -0
  833. hydpy/models/test_stiff0d.py +47 -0
  834. hydpy/models/test_stiff1d.py +42 -0
  835. hydpy/models/whmod/__init__.py +21 -0
  836. hydpy/models/whmod/whmod_constants.py +77 -0
  837. hydpy/models/whmod/whmod_control.py +333 -0
  838. hydpy/models/whmod/whmod_derived.py +210 -0
  839. hydpy/models/whmod/whmod_factors.py +9 -0
  840. hydpy/models/whmod/whmod_fluxes.py +105 -0
  841. hydpy/models/whmod/whmod_inputs.py +15 -0
  842. hydpy/models/whmod/whmod_masks.py +178 -0
  843. hydpy/models/whmod/whmod_model.py +2091 -0
  844. hydpy/models/whmod/whmod_parameters.py +155 -0
  845. hydpy/models/whmod/whmod_sequences.py +193 -0
  846. hydpy/models/whmod/whmod_states.py +73 -0
  847. hydpy/models/whmod_rural.py +794 -0
  848. hydpy/models/whmod_urban.py +1011 -0
  849. hydpy/models/wland/__init__.py +43 -0
  850. hydpy/models/wland/wland_aides.py +55 -0
  851. hydpy/models/wland/wland_constants.py +103 -0
  852. hydpy/models/wland/wland_control.py +508 -0
  853. hydpy/models/wland/wland_derived.py +330 -0
  854. hydpy/models/wland/wland_factors.py +11 -0
  855. hydpy/models/wland/wland_fixed.py +12 -0
  856. hydpy/models/wland/wland_fluxes.py +166 -0
  857. hydpy/models/wland/wland_inputs.py +33 -0
  858. hydpy/models/wland/wland_masks.py +54 -0
  859. hydpy/models/wland/wland_model.py +3755 -0
  860. hydpy/models/wland/wland_outlets.py +11 -0
  861. hydpy/models/wland/wland_parameters.py +214 -0
  862. hydpy/models/wland/wland_sequences.py +108 -0
  863. hydpy/models/wland/wland_solver.py +45 -0
  864. hydpy/models/wland/wland_states.py +56 -0
  865. hydpy/models/wland_gd.py +888 -0
  866. hydpy/models/wland_wag.py +1244 -0
  867. hydpy/models/wq/__init__.py +14 -0
  868. hydpy/models/wq/wq_control.py +117 -0
  869. hydpy/models/wq/wq_derived.py +182 -0
  870. hydpy/models/wq/wq_factors.py +79 -0
  871. hydpy/models/wq/wq_fluxes.py +17 -0
  872. hydpy/models/wq/wq_model.py +1889 -0
  873. hydpy/models/wq_trapeze.py +168 -0
  874. hydpy/models/wq_trapeze_strickler.py +101 -0
  875. hydpy/models/wq_walrus.py +57 -0
  876. hydpy/py.typed +0 -0
  877. hydpy/tests/.coveragerc +22 -0
  878. hydpy/tests/__init__.py +0 -0
  879. hydpy/tests/check_consistency.py +32 -0
  880. hydpy/tests/hydpydoctestcustomize.pth +1 -0
  881. hydpy/tests/hydpydoctestcustomize.py +15 -0
  882. hydpy/tests/iotesting/__init__.py +0 -0
  883. hydpy/tests/run_doctests.py +233 -0
  884. hydpy-6.2.dev1.data/scripts/hyd.py +277 -0
  885. hydpy-6.2.dev1.dist-info/LICENSE +165 -0
  886. hydpy-6.2.dev1.dist-info/METADATA +163 -0
  887. hydpy-6.2.dev1.dist-info/RECORD +890 -0
  888. hydpy-6.2.dev1.dist-info/WHEEL +5 -0
  889. hydpy-6.2.dev1.dist-info/licenses_hydpy_installer.txt +42 -0
  890. hydpy-6.2.dev1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,2023 @@
1
+ """This module implements tools to help to standardize the functionality of the
2
+ different objects defined by the HydPy framework."""
3
+
4
+ # import...
5
+ # ...from standard library
6
+ from __future__ import annotations
7
+ import builtins
8
+ import contextlib
9
+ import copy
10
+ import inspect
11
+ import itertools
12
+ import numbers
13
+ import sys
14
+ import textwrap
15
+ import types
16
+
17
+ # ...from site-packages
18
+ import black
19
+ import numpy
20
+ import wrapt
21
+
22
+ # ...from HydPy
23
+ import hydpy
24
+ from hydpy import config
25
+ from hydpy.core import exceptiontools
26
+ from hydpy.core.typingtools import *
27
+
28
+ if TYPE_CHECKING:
29
+ from hydpy.core import devicetools
30
+ from hydpy.core import modeltools
31
+ from hydpy.core import parametertools
32
+ from hydpy.core import sequencetools
33
+
34
+ _builtinnames = set(dir(builtins))
35
+
36
+ ReprArg: TypeAlias = Union[
37
+ numbers.Number, Iterable[numbers.Number], Iterable[Iterable[numbers.Number]]
38
+ ]
39
+
40
+
41
+ def classname(self: object) -> str:
42
+ """Return the class name of the given instance object or class.
43
+
44
+ >>> from hydpy import classname
45
+ >>> from hydpy import pub
46
+ >>> classname(float)
47
+ 'float'
48
+ >>> classname(pub.options)
49
+ 'Options'
50
+ """
51
+ if inspect.isclass(self):
52
+ return self.__name__
53
+ return type(self).__name__
54
+
55
+
56
+ def value_of_type(value: object) -> str:
57
+ """Returns a string containing both the informal string and the type of the given
58
+ value.
59
+
60
+ This function is intended to simplifying writing HydPy exceptions, which frequently
61
+ contain the following phrase:
62
+
63
+ >>> from hydpy.core.objecttools import value_of_type
64
+ >>> value_of_type(999)
65
+ 'value `999` of type `int`'
66
+ """
67
+ return f"value `{value}` of type `{classname(value)}`"
68
+
69
+
70
+ def modulename(self: object) -> str:
71
+ """Return the module name of the given instance object.
72
+
73
+ >>> from hydpy.core.objecttools import modulename
74
+ >>> from hydpy import pub
75
+ >>> print(modulename(pub.options))
76
+ optiontools
77
+ """
78
+ return self.__module__.split(".")[-1]
79
+
80
+
81
+ def _search_device(self: object) -> devicetools.Node | devicetools.Element | None:
82
+ # pylint: disable=import-outside-toplevel
83
+ from hydpy.core import devicetools as dt
84
+ from hydpy.core import modeltools as mt
85
+ from hydpy.core import parametertools as pt
86
+ from hydpy.core import sequencetools as st
87
+
88
+ if isinstance(self, (pt.Parameter, st.ModelSequence, st.NodeSequence)):
89
+ self = self.subvars
90
+ if isinstance(self, (pt.SubParameters, st.ModelSequences)):
91
+ self = self.vars
92
+ if isinstance(self, (pt.Parameters, st.Sequences)):
93
+ self = self.model
94
+ if isinstance(self, mt.Model):
95
+ return exceptiontools.getattr_(self, "element", None)
96
+ if isinstance(self, st.NodeSequences):
97
+ return self.node
98
+ if isinstance(self, (dt.Node, dt.Element)):
99
+ return self
100
+ return None
101
+
102
+
103
+ def devicename(self: object) -> str:
104
+ """Try to return the name of the (indirect) master |Node| or |Element| instance, if
105
+ not possible return `?`.
106
+
107
+ >>> from hydpy import prepare_model
108
+ >>> model = prepare_model("hland_96")
109
+ >>> from hydpy.core.objecttools import devicename
110
+ >>> devicename(model)
111
+ '?'
112
+
113
+ >>> from hydpy import Element
114
+ >>> e1 = Element("e1", outlets="n1")
115
+ >>> e1.model = model
116
+ >>> devicename(e1)
117
+ 'e1'
118
+ >>> devicename(model)
119
+ 'e1'
120
+ """
121
+ device = _search_device(self)
122
+ if device is None:
123
+ return "?"
124
+ return device.name
125
+
126
+
127
+ def _devicephrase(self: object, objname: str | None = None) -> str:
128
+ name_ = getattr(self, "name", type(self).__name__.lower())
129
+ device = _search_device(self)
130
+ if device and objname:
131
+ return f"`{name_}` of {objname} `{device.name}`"
132
+ if objname:
133
+ return f"`{name_}` of {objname} `?`"
134
+ if device:
135
+ return f"`{name_}` of {type(device).__name__.lower()} `{device.name}`"
136
+ return f"`{name_}`"
137
+
138
+
139
+ def elementphrase(self: object) -> str:
140
+ """Return the phrase used in exception messages to indicate
141
+ which |Element| is affected.
142
+
143
+ >>> from hydpy.core.modeltools import Model
144
+ >>> class Test(Model):
145
+ ... def connect(self):
146
+ ... pass
147
+ >>> model = Test()
148
+ >>> from hydpy.core.objecttools import elementphrase
149
+ >>> elementphrase(model)
150
+ '`test` of element `?`'
151
+
152
+ >>> from hydpy import Element
153
+ >>> model.element = Element("e1")
154
+ >>> elementphrase(model)
155
+ '`test` of element `e1`'
156
+ """
157
+ return _devicephrase(self, "element")
158
+
159
+
160
+ def nodephrase(self: object) -> str:
161
+ """Return the phrase used in exception messages to indicate which |Node| is
162
+ affected.
163
+
164
+ >>> from hydpy.core.sequencetools import Sequences
165
+ >>> sequences = Sequences(None)
166
+ >>> from hydpy.core.objecttools import nodephrase
167
+ >>> nodephrase(sequences)
168
+ '`sequences` of node `?`'
169
+
170
+ >>> sequences.name = "test"
171
+ >>> nodephrase(sequences)
172
+ '`test` of node `?`'
173
+
174
+ >>> from hydpy import Node
175
+ >>> n1 = Node("n1")
176
+ >>> nodephrase(n1.sequences.sim)
177
+ '`sim` of node `n1`'
178
+ """
179
+ return _devicephrase(self, "node")
180
+
181
+
182
+ def devicephrase(self: object) -> str:
183
+ """Try to return the phrase used in exception messages to indicate which |Element|
184
+ or which |Node| is affected. If not possible, return just the name of the given
185
+ object.
186
+
187
+ >>> from hydpy.core.modeltools import Model
188
+ >>> class Test(Model):
189
+ ... def connect(self):
190
+ ... return None
191
+ >>> model = Test()
192
+ >>> from hydpy.core.objecttools import devicephrase
193
+ >>> devicephrase(model)
194
+ '`test`'
195
+
196
+ >>> from hydpy import Element
197
+ >>> model.element = Element("e1")
198
+ >>> devicephrase(model)
199
+ '`test` of element `e1`'
200
+
201
+ >>> from hydpy import Node
202
+ >>> n1 = Node("n1")
203
+ >>> devicephrase(n1.sequences.sim)
204
+ '`sim` of node `n1`'
205
+ """
206
+ return _devicephrase(self)
207
+
208
+
209
+ def submodelphrase(model: modeltools.Model, include_subsubmodels: bool = True) -> str:
210
+ """Return a standard phrase for listing a model and its submodels in exception
211
+ messages.
212
+
213
+ >>> from hydpy import prepare_model
214
+ >>> from hydpy.core.objecttools import submodelphrase
215
+ >>> model = prepare_model("lland_dd")
216
+ >>> submodelphrase(model)
217
+ 'model `lland_dd`'
218
+
219
+ >>> model.aetmodel = prepare_model("evap_aet_minhas")
220
+ >>> submodelphrase(model)
221
+ 'model `lland_dd` and its submodel (`aetmodel/evap_aet_minhas`)'
222
+
223
+ >>> model.soilmodel = prepare_model("ga_garto_submodel1")
224
+ >>> submodelphrase(model)
225
+ 'model `lland_dd` and its submodels (`aetmodel/evap_aet_minhas` and \
226
+ `soilmodel/ga_garto_submodel1`)'
227
+ """
228
+ submodels = model.find_submodels(include_subsubmodels=include_subsubmodels)
229
+ if submodels:
230
+ suffix = "s" if len(submodels) > 1 else ""
231
+ names = enumeration(
232
+ f"`{name.rpartition('.')[2]}/{submodel}`"
233
+ for name, submodel in submodels.items()
234
+ )
235
+ return f"model `{model}` and its submodel{suffix} ({names})"
236
+ return f"model `{model}`"
237
+
238
+
239
+ def valid_variable_identifier(string: str) -> None:
240
+ """Raises an |ValueError| if the given name is not a valid Python
241
+ identifier.
242
+
243
+ For example, the string `test_1` (with underscore) is valid...
244
+
245
+ >>> from hydpy.core.objecttools import valid_variable_identifier
246
+ >>> valid_variable_identifier("test_1")
247
+
248
+ ...but the string `test 1` (with white space) is not:
249
+
250
+ >>> valid_variable_identifier("test 1")
251
+ Traceback (most recent call last):
252
+ ...
253
+ ValueError: The given name string `test 1` does not define a valid variable \
254
+ identifier. Valid identifiers do not contain characters like `-` or empty spaces, do \
255
+ not start with numbers, cannot be mistaken with Python built-ins like `for`...)
256
+
257
+ Also, names of Python built ins are not allowed:
258
+
259
+ >>> valid_variable_identifier("print") # doctest: +ELLIPSIS
260
+ Traceback (most recent call last):
261
+ ...
262
+ ValueError: The given name string `print` does not define...
263
+ """
264
+ if string in _builtinnames or not string.isidentifier():
265
+ raise ValueError(
266
+ f"The given name string `{string}` does not define a valid variable "
267
+ f"identifier. Valid identifiers do not contain characters like `-` or "
268
+ f"empty spaces, do not start with numbers, cannot be mistaken with Python "
269
+ f"built-ins like `for`...)"
270
+ )
271
+
272
+
273
+ def augment_excmessage(
274
+ prefix: str | None = None, suffix: str | None = None
275
+ ) -> NoReturn:
276
+ """Augment an exception message with additional information while keeping the
277
+ original traceback.
278
+
279
+ You can prefix and/or suffix text. If you prefix something (which happens much
280
+ more often in the HydPy framework), the sub-clause ", the following error
281
+ occurred:" is automatically included:
282
+
283
+ >>> from hydpy.core import objecttools
284
+ >>> import textwrap
285
+ >>> try:
286
+ ... 1 + "1"
287
+ ... except BaseException:
288
+ ... prefix = "While showing how prefixing works"
289
+ ... suffix = "(This is a final remark.)"
290
+ ... objecttools.augment_excmessage(prefix, suffix)
291
+ Traceback (most recent call last):
292
+ ...
293
+ TypeError: While showing how prefixing works, the following error occurred: \
294
+ unsupported operand type(s) for +: 'int' and 'str' (This is a final remark.)
295
+
296
+ Some exceptions derived by site-packages do not support exception chaining due to
297
+ requiring multiple initialisation arguments. In such cases, |augment_excmessage|
298
+ generates an exception with the same name on the fly and raises it afterwards:
299
+
300
+ >>> class WrongError(BaseException):
301
+ ... def __init__(self, arg1, arg2):
302
+ ... pass
303
+ >>> try:
304
+ ... raise WrongError("info 1", "info 2")
305
+ ... except BaseException:
306
+ ... objecttools.augment_excmessage("While showing how prefixing works")
307
+ Traceback (most recent call last):
308
+ ...
309
+ hydpy.core.objecttools.WrongError: While showing how prefixing works, the \
310
+ following error occurred: ('info 1', 'info 2')
311
+
312
+ Never use function |augment_excmessage| outside except clauses:
313
+
314
+ >>> objecttools.augment_excmessage("While trying to do something")
315
+ Traceback (most recent call last):
316
+ ...
317
+ RuntimeError: No exception available. (Call function `augment_excmessage` only \
318
+ inside except clauses.)
319
+ """
320
+ exc_old = sys.exc_info()[1]
321
+ if exc_old is None:
322
+ raise RuntimeError(
323
+ "No exception available. (Call function `augment_excmessage` only inside "
324
+ "except clauses.)"
325
+ )
326
+ message = str(exc_old)
327
+ if prefix is not None:
328
+ message = f"{prefix}, the following error occurred: {message}"
329
+ if suffix is not None:
330
+ message = f"{message} {suffix}"
331
+ try:
332
+ exc_new = type(exc_old)(message)
333
+ except BaseException:
334
+ exc_name = str(type(exc_old)).split("'")[1].split(".")[-1]
335
+ exc_type = type(exc_name, (BaseException,), {})
336
+ exc_type.__module__ = exc_old.__module__
337
+ raise exc_type(message) from exc_old
338
+ raise exc_new from exc_old
339
+
340
+
341
+ F = TypeVar("F", bound=Callable[..., Any])
342
+
343
+
344
+ def decorator(wrapper: Callable[..., Any]) -> Callable[[F], F]:
345
+ """Function |decorator| adds type hints to function `decorator` of the site-package
346
+ `wrapt` without changing its functionality."""
347
+ return wrapt.decorator(wrapper)
348
+
349
+
350
+ def excmessage_decorator(
351
+ description_: str,
352
+ ) -> Callable[[Callable[P, T]], Callable[P, T]]:
353
+ """Wrap a function with |augment_excmessage|.
354
+
355
+ Function |excmessage_decorator| is a means to apply function |augment_excmessage|
356
+ more efficiently. Suppose you would apply function |augment_excmessage| in a
357
+ function that adds and returns to numbers:
358
+
359
+ >>> from hydpy.core import objecttools
360
+ >>> def add(x, y):
361
+ ... try:
362
+ ... return x + y
363
+ ... except BaseException:
364
+ ... objecttools.augment_excmessage("While trying to add `x` and `y`")
365
+
366
+ This works as excepted...
367
+
368
+ >>> add(1, 2)
369
+ 3
370
+ >>> add(1, [])
371
+ Traceback (most recent call last):
372
+ ...
373
+ TypeError: While trying to add `x` and `y`, the following error occurred: \
374
+ unsupported operand type(s) for +: 'int' and 'list'
375
+
376
+ ...but can be achieved with much less code using |excmessage_decorator|:
377
+
378
+ >>> @objecttools.excmessage_decorator("add `x` and `y`")
379
+ ... def add(x, y):
380
+ ... return x+y
381
+
382
+ >>> add(1, 2)
383
+ 3
384
+
385
+ >>> add(1, [])
386
+ Traceback (most recent call last):
387
+ ...
388
+ TypeError: While trying to add `x` and `y`, the following error occurred: \
389
+ unsupported operand type(s) for +: 'int' and 'list'
390
+
391
+ Additionally, exception messages related to wrong function calls are now also
392
+ augmented:
393
+
394
+ >>> add(1)
395
+ Traceback (most recent call last):
396
+ ...
397
+ TypeError: While trying to add `x` and `y`, the following error occurred: add() \
398
+ missing 1 required positional argument: 'y'
399
+
400
+ |excmessage_decorator| evaluates the given string like an f-string, allowing to
401
+ mention the argument values of the called function and to make use of all string
402
+ modification functions provided by modules |objecttools|:
403
+
404
+ >>> @objecttools.excmessage_decorator(
405
+ ... "add `x` ({repr_(x, 2)}) and `y` ({repr_(y, 2)})")
406
+ ... def add(x, y):
407
+ ... return x+y
408
+
409
+ >>> add(1.1111, "wrong")
410
+ Traceback (most recent call last):
411
+ ...
412
+ TypeError: While trying to add `x` (1.11) and `y` (wrong), the following error \
413
+ occurred: unsupported operand type(s) for +: 'float' and 'str'
414
+ >>> add(1)
415
+ Traceback (most recent call last):
416
+ ...
417
+ TypeError: While trying to add `x` (1) and `y` (?), the following error occurred: \
418
+ add() missing 1 required positional argument: 'y'
419
+ >>> add(y=1)
420
+ Traceback (most recent call last):
421
+ ...
422
+ TypeError: While trying to add `x` (?) and `y` (1), the following error occurred: \
423
+ add() missing 1 required positional argument: 'x'
424
+
425
+ Apply |excmessage_decorator| on methods also works fine:
426
+
427
+ >>> class Adder:
428
+ ... def __init__(self):
429
+ ... self.value = 0
430
+ ... @objecttools.excmessage_decorator(
431
+ ... "add an instance of class `{classname(self)}` with value "
432
+ ... "`{repr_(other, 2)}` of type `{classname(other)}`")
433
+ ... def __iadd__(self, other):
434
+ ... self.value += other
435
+ ... return self
436
+
437
+ >>> adder = Adder()
438
+ >>> adder += 1
439
+ >>> adder.value
440
+ 1
441
+ >>> adder += "wrong"
442
+ Traceback (most recent call last):
443
+ ...
444
+ TypeError: While trying to add an instance of class `Adder` with value `wrong` of \
445
+ type `str`, the following error occurred: unsupported operand type(s) for +=: 'int' \
446
+ and 'str'
447
+
448
+ It is made sure that no information of the decorated function is lost:
449
+
450
+ >>> add.__name__
451
+ 'add'
452
+ """
453
+
454
+ @wrapt.decorator
455
+ def wrapper(wrapped, instance, args, kwargs):
456
+ """Apply |augment_excmessage| when the wrapped function fails."""
457
+ try:
458
+ return wrapped(*args, **kwargs)
459
+ except BaseException:
460
+ info = kwargs.copy()
461
+ info["self"] = instance
462
+ argnames = inspect.getfullargspec(wrapped).args
463
+ if argnames and (argnames[0] == "self"):
464
+ argnames = argnames[1:]
465
+ for argname, arg in zip(argnames, args):
466
+ info[argname] = arg
467
+ for argname in argnames:
468
+ if argname not in info:
469
+ info[argname] = "?"
470
+ message = eval(f"f'While trying to {description_}'", globals(), info)
471
+ augment_excmessage(message)
472
+
473
+ return cast(Callable[[F], F], wrapper)
474
+
475
+
476
+ class ResetAttrFuncs:
477
+ """Reset all attribute related methods of the given class temporarily.
478
+
479
+ The "related methods" are defined in class attribute |ResetAttrFuncs.funcnames|.
480
+
481
+ There are (at least) two use cases for class |ResetAttrFuncs|, initialisation and
482
+ copying, which are described below.
483
+
484
+ In HydPy, some classes define a `__setattr__` method which raises exceptions when
485
+ one tries to set "improper" instance attributes. The problem is, that such
486
+ customized `setattr` methods often prevent from defining instance attributes within
487
+ `__init__` methods in the usual manner. Working on instance dictionaries instead
488
+ can confuse some automatic tools (e.g. pylint). Class |ResetAttrFuncs| implements
489
+ a trick to circumvent this problem.
490
+
491
+ To show how |ResetAttrFuncs| works, we first define a class with a `__setattr__`
492
+ method that does not allow to set any attribute:
493
+
494
+ >>> class Test:
495
+ ... def __setattr__(self, name, value):
496
+ ... raise AttributeError
497
+ >>> test = Test()
498
+ >>> test.var1 = 1
499
+ Traceback (most recent call last):
500
+ ...
501
+ AttributeError
502
+
503
+ Assigning this class to |ResetAttrFuncs| allows for setting attributes to all its
504
+ instances inside a `with` block in the usual manner:
505
+
506
+ >>> from hydpy.core.objecttools import ResetAttrFuncs
507
+ >>> with ResetAttrFuncs(test):
508
+ ... test.var1 = 1
509
+ >>> test.var1
510
+ 1
511
+
512
+ After the end of the `with` block, the custom `__setattr__` method of the test
513
+ class works again and prevents from setting attributes:
514
+
515
+ >>> test.var2 = 2
516
+ Traceback (most recent call last):
517
+ ...
518
+ AttributeError
519
+
520
+ The second use case is related to method `__getattr__` and copying. The following
521
+ test class stores its attributes (for whatever reasons) in a special dictionary
522
+ called "dic" (note that how |ResetAttrFuncs| is used in the `__init__` method):
523
+
524
+ >>> class Test:
525
+ ... def __init__(self):
526
+ ... with ResetAttrFuncs(self):
527
+ ... self.dic = {}
528
+ ... def __setattr__(self, name, value):
529
+ ... self.dic[name] = value
530
+ ... def __getattr__(self, name):
531
+ ... try:
532
+ ... return self.dic[name]
533
+ ... except KeyError:
534
+ ... raise AttributeError
535
+
536
+ Principally, this simple implementation does its job but its instances are not
537
+ easily copyable under all Python versions:
538
+
539
+ >>> test = Test()
540
+ >>> test.var1 = 1
541
+ >>> test.var1
542
+ 1
543
+ >>> import copy
544
+ >>> copy.deepcopy(test) # doctest: +SKIP
545
+ Traceback (most recent call last):
546
+ ...
547
+ RecursionError: maximum recursion depth exceeded ...
548
+
549
+ |ResetAttrFuncs| can be used to implement specialized `__copy__` and `__deepcopy__`
550
+ methods, which rely on the temporary disabling of `__getattr__`. For simple cases,
551
+ one can import the predefined functions |copy_| and |deepcopy_|:
552
+
553
+ >>> from hydpy.core.objecttools import copy_, deepcopy_
554
+ >>> Test.__copy__ = copy_
555
+ >>> test2 = copy.copy(test)
556
+ >>> test2.var1
557
+ 1
558
+ >>> Test.__deepcopy__ = deepcopy_
559
+ >>> test3 = copy.deepcopy(test)
560
+ >>> test3.var1
561
+ 1
562
+
563
+ Note that an infinite recursion is avoided by also disabling methods `__copy__` and
564
+ `__deepcopy__` themselves.
565
+ """
566
+
567
+ __slots__ = ("cls", "name2func")
568
+ funcnames = (
569
+ "__getattr__",
570
+ "__setattr__",
571
+ "__delattr__",
572
+ "__copy__",
573
+ "__deepcopy__",
574
+ )
575
+
576
+ def __init__(self, obj: object) -> None:
577
+ self.cls = type(obj)
578
+ self.name2func = {}
579
+ for name_ in self.funcnames:
580
+ if hasattr(self.cls, name_):
581
+ self.name2func[name_] = self.cls.__dict__.get(name_)
582
+
583
+ def __enter__(self) -> Self:
584
+ for name_ in self.name2func:
585
+ if name_ in ("__setattr__", "__delattr__"):
586
+ setattr(self.cls, name_, getattr(object, name_))
587
+ elif name_ == "__getattr__":
588
+ setattr(self.cls, name_, object.__getattribute__)
589
+ else:
590
+ setattr(self.cls, name_, None)
591
+ return self
592
+
593
+ def __exit__(
594
+ self,
595
+ exception_type: type[BaseException],
596
+ exception_value: BaseException,
597
+ traceback_: types.TracebackType,
598
+ ) -> None:
599
+ for name_, func in self.name2func.items():
600
+ if func:
601
+ setattr(self.cls, name_, func)
602
+ else:
603
+ delattr(self.cls, name_)
604
+
605
+
606
+ def copy_(self: T) -> T:
607
+ """Copy function for classes with modified attribute functions.
608
+
609
+ See the documentation on class |ResetAttrFuncs| for further information.
610
+ """
611
+ with ResetAttrFuncs(self):
612
+ return copy.copy(self)
613
+
614
+
615
+ def deepcopy_(self: T, memo: dict[int, object] | None) -> T:
616
+ """Deepcopy function for classes with modified attribute functions.
617
+
618
+ See the documentation on class |ResetAttrFuncs| for further information.
619
+ """
620
+ with ResetAttrFuncs(self):
621
+ return copy.deepcopy(self, memo)
622
+
623
+
624
+ class _PreserveStrings:
625
+ r"""Modifies |repr| for strings and floats, mainly for supporting clean float and
626
+ path representations that are compatible with |doctest|.
627
+
628
+ Use the already available instance `repr_` instead of initialising a new |Repr_|
629
+ object.
630
+
631
+ When value is a string, it is returned without any modification, except that the
632
+ path separator "\" (Windows) is replaced with "/" (Linux):
633
+
634
+ >>> from hydpy.core.objecttools import repr_
635
+
636
+ >>> print(r"directory\file")
637
+ directory\file
638
+ >>> print(repr(r"directory\file"))
639
+ 'directory\\file'
640
+ >>> print(repr_(r"directory\file"))
641
+ directory/file
642
+
643
+ You can change this behaviour of function object |repr|, when necessary:
644
+
645
+ >>> with repr_.preserve_strings(True):
646
+ ... print(repr_(r"directory\file"))
647
+ "directory/file"
648
+
649
+ Behind the with block, |repr_| works as before
650
+ (even in case of an error):
651
+
652
+ >>> print(repr_(r"directory\file"))
653
+ directory/file
654
+
655
+ When value is a float, the result depends on how the option |Options.reprdigits| is
656
+ set. Without defining a special value, |repr| defines the number of digits in the
657
+ usual, system dependent manner:
658
+
659
+ >>> from hydpy import pub
660
+ >>> with pub.options.reprdigits(-1):
661
+ ... repr(1.0/3.0) == repr_(1.0/3.0)
662
+ True
663
+
664
+ Through setting |Options.reprdigits| to a positive integer value, one defines the
665
+ maximum number of decimal places, which allows for doctesting across different
666
+ systems and Python versions:
667
+
668
+ >>> repr_(1.0/3.0)
669
+ '0.333333'
670
+ >>> repr_(2.0/3.0)
671
+ '0.666667'
672
+ >>> repr_(1.0/2.0)
673
+ '0.5'
674
+
675
+ Changing the number of decimal places can be done via a with block:
676
+
677
+ >>> with pub.options.reprdigits(3):
678
+ ... print(repr_(1.0/3.0))
679
+ 0.333
680
+
681
+ Such a change is only temporary (even in case of an error):
682
+
683
+ >>> repr_(1.0/3.0)
684
+ '0.333333'
685
+
686
+ |repr| can also be applied on numpy's float types:
687
+
688
+ >>> import numpy
689
+ >>> repr_(numpy.float64(1.0/3.0))
690
+ '0.333333'
691
+ >>> repr_(numpy.float32(1.0/3.0))
692
+ '0.333333'
693
+ >>> repr_(numpy.float16(1.0/3.0))
694
+ '0.333252'
695
+
696
+ Note that the deviation from the `true` result in the last example is due to the
697
+ low precision of |numpy.float16|.
698
+
699
+ For scalar |numpy.ndarray| objects, |repr_| returns its item's string
700
+ representation:
701
+
702
+ >>> repr_(numpy.array(1.0/3.0))
703
+ '0.333333'
704
+
705
+ On all types not mentioned above, the usual |repr| function is applied, e.g.:
706
+
707
+ >>> repr([1, 2, 3])
708
+ '[1, 2, 3]'
709
+ >>> repr_([1, 2, 3])
710
+ '[1, 2, 3]'
711
+ """
712
+
713
+ newvalue: bool
714
+ oldvalue: bool
715
+
716
+ def __init__(self, preserve_strings: bool) -> None:
717
+ self.newvalue = preserve_strings
718
+ self.oldvalue = getattr(repr_, "_preserve_strings")
719
+
720
+ def __enter__(self) -> None:
721
+ setattr(repr_, "_preserve_strings", self.newvalue)
722
+
723
+ def __exit__(
724
+ self,
725
+ exception_type: type[BaseException],
726
+ exception_value: BaseException,
727
+ traceback: types.TracebackType,
728
+ ) -> None:
729
+ setattr(repr_, "_preserve_strings", self.oldvalue)
730
+
731
+
732
+ class _Repr:
733
+ """Modifies |repr| for strings and floats, mainly for supporting clean float and
734
+ path representations that are compatible with |doctest|."""
735
+
736
+ def __init__(self) -> None:
737
+ self._preserve_strings = False
738
+
739
+ def __call__(self, value: object, decimals: int | None = None) -> str:
740
+ if decimals is None:
741
+ decimals = hydpy.pub.options.reprdigits
742
+ if isinstance(value, str):
743
+ string = value.replace("\\", "/")
744
+ if self._preserve_strings:
745
+ return f'"{string}"'
746
+ return string
747
+ if isinstance(value, numpy.ndarray) and not value.ndim:
748
+ value = value.item()
749
+ if isinstance(value, numbers.Real) and (
750
+ not isinstance(value, numbers.Integral)
751
+ ):
752
+ value = float(value)
753
+ if decimals > -1:
754
+ string = f"{value:.{decimals}f}"
755
+ string = string.rstrip("0")
756
+ if string.endswith("."):
757
+ string += "0"
758
+ if string == "-0.0":
759
+ return "0.0"
760
+ return string
761
+ if isinstance(value, config.NP_INT):
762
+ return str(int(value))
763
+ if isinstance(value, config.NP_BOOL):
764
+ return str(bool(value))
765
+ return repr(value)
766
+
767
+ @staticmethod
768
+ def preserve_strings(preserve_strings: bool) -> _PreserveStrings:
769
+ """Change the `preserve_string` option inside a with block."""
770
+ return _PreserveStrings(preserve_strings)
771
+
772
+
773
+ repr_ = _Repr()
774
+ r"""Modifies |repr| for strings and floats, mainly for supporting clean float and path
775
+ representations that are compatible with |doctest|.
776
+
777
+ Use the already available instance `repr_` instead of initialising a new |Repr_| object.
778
+
779
+ When value is a string, it is returned without any modification, except that the path
780
+ separator "\" (Windows) is replaced with "/" (Linux):
781
+
782
+ >>> from hydpy.core.objecttools import repr_
783
+
784
+ >>> print(r"directory\file")
785
+ directory\file
786
+ >>> print(repr(r"directory\file"))
787
+ 'directory\\file'
788
+ >>> print(repr_(r"directory\file"))
789
+ directory/file
790
+
791
+ You can change this behaviour of function object |repr|, when necessary:
792
+
793
+ >>> with repr_.preserve_strings(True):
794
+ ... print(repr_(r"directory\file"))
795
+ "directory/file"
796
+
797
+ Behind the with block, |repr_| works as before
798
+ (even in case of an error):
799
+
800
+ >>> print(repr_(r"directory\file"))
801
+ directory/file
802
+
803
+ When value is a float, the result depends on how the option |Options.reprdigits| is set.
804
+ Without defining a special value, |repr| defines the number of digits in the usual,
805
+ system dependent manner:
806
+
807
+ >>> from hydpy import pub
808
+ >>> with pub.options.reprdigits(-1):
809
+ ... repr(1.0/3.0) == repr_(1.0/3.0)
810
+ True
811
+
812
+ Through setting |Options.reprdigits| to a positive integer value, one defines the
813
+ maximum number of decimal places, which allows for doctesting across different systems
814
+ and Python versions:
815
+
816
+ >>> repr_(1.0/3.0)
817
+ '0.333333'
818
+ >>> repr_(2.0/3.0)
819
+ '0.666667'
820
+ >>> repr_(1.0/2.0)
821
+ '0.5'
822
+
823
+ Changing the number of decimal places can be done via a with block:
824
+
825
+ >>> with pub.options.reprdigits(3):
826
+ ... print(repr_(1.0/3.0))
827
+ 0.333
828
+
829
+ Such a change is only temporary (even in case of an error):
830
+
831
+ >>> repr_(1.0/3.0)
832
+ '0.333333'
833
+
834
+ |repr| can also be applied on numpy's float types:
835
+
836
+ >>> import numpy
837
+ >>> repr_(numpy.float64(1.0/3.0))
838
+ '0.333333'
839
+ >>> repr_(numpy.float32(1.0/3.0))
840
+ '0.333333'
841
+ >>> repr_(numpy.float16(1.0/3.0))
842
+ '0.333252'
843
+
844
+ Note that the deviation from the `true` result in the last example is due to the low
845
+ precision of |numpy.float16|.
846
+
847
+ For scalar |numpy.ndarray| objects, |repr_| returns its item's string representation:
848
+
849
+ >>> repr_(numpy.array(1.0/3.0))
850
+ '0.333333'
851
+
852
+ On all types not mentioned above, the usual |repr| function is applied, e.g.:
853
+
854
+ >>> repr([1, 2, 3])
855
+ '[1, 2, 3]'
856
+ >>> repr_([1, 2, 3])
857
+ '[1, 2, 3]'
858
+ """
859
+
860
+
861
+ def repr_values(values: VectorInputObject) -> str:
862
+ """Return comma separated representations of the given values using function
863
+ |repr_|.
864
+
865
+ >>> from hydpy.core.objecttools import repr_values
866
+ >>> repr_values([1.0/1.0, 1.0/2.0, 1.0/3.0])
867
+ '1.0, 0.5, 0.333333'
868
+
869
+ Note that the returned string is not wrapped.
870
+ """
871
+ return ", ".join(repr_(value) for value in values)
872
+
873
+
874
+ def repr_numbers(values: ReprArg) -> str:
875
+ """Return comma separated representations of the given numbers using function
876
+ |repr_|.
877
+
878
+ Currently, function |repr_numbers| can handle scalar values, 1-dimensional vectors,
879
+ and 2-dimensional matrices:
880
+
881
+ >>> from hydpy.core.objecttools import repr_numbers
882
+ >>> repr_numbers(1.0/3.0)
883
+ '0.333333'
884
+ >>> repr_numbers([1.0/1.0, 1.0/2.0, 1.0/3.0])
885
+ '1.0, 0.5, 0.333333'
886
+ >>> repr_numbers([[1.0/1.0, 1.0/2.0, 1.0/3.0], [1.0/4.0, 1.0/5.0, 1.0/6.0]])
887
+ '1.0, 0.5, 0.333333; 0.25, 0.2, 0.166667'
888
+
889
+ Note that the returned string is not wrapped.
890
+ """
891
+ if isinstance(values, numbers.Number):
892
+ return repr_(values)
893
+ result = []
894
+ ndim = 1
895
+ for value in values:
896
+ if isinstance(value, numbers.Number):
897
+ result.append(repr_(value))
898
+ else:
899
+ result.append(", ".join(repr_(v) for v in value))
900
+ ndim = 2
901
+ if ndim == 1:
902
+ return ", ".join(result)
903
+ return "; ".join(result)
904
+
905
+
906
+ def print_vector(values: VectorInputObject, width: int = 70) -> None:
907
+ """Print the given vector in multiple lines with a certain maximum width.
908
+
909
+ By default, each line contains at most 70 characters:
910
+
911
+ >>> from hydpy import print_vector
912
+ >>> print_vector(range(21))
913
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
914
+ 20
915
+
916
+ You can change this default behaviour by passing an alternative number of
917
+ characters:
918
+
919
+ >>> print_vector(range(21), width=30)
920
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
921
+ 10, 11, 12, 13, 14, 15, 16,
922
+ 17, 18, 19, 20
923
+ """
924
+ for line in textwrap.wrap(
925
+ text=repr_values(values), width=width, break_long_words=False
926
+ ):
927
+ print(line)
928
+
929
+
930
+ def print_matrix(values: MatrixInputObject, width: int = 70) -> None:
931
+ """Print the given matrix in multiple lines with a certain maximum width.
932
+
933
+ By default, each line contains at most 70 characters:
934
+
935
+ >>> from hydpy import print_matrix
936
+ >>> print_matrix([range(5), range(20), range(10)])
937
+ | 0, 1, 2, 3, 4 |
938
+ | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, >
939
+ > 19 |
940
+ | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 |
941
+
942
+ You can change this default behaviour by passing an alternative number of
943
+ characters:
944
+
945
+ >>> print_matrix([range(5), range(20), range(10)], width=30)
946
+ | 0, 1, 2, 3, 4 |
947
+ | 0, 1, 2, 3, 4, 5, 6, 7, 8, >
948
+ > 9, 10, 11, 12, 13, 14, 15, >
949
+ > 16, 17, 18, 19 |
950
+ | 0, 1, 2, 3, 4, 5, 6, 7, 8, >
951
+ > 9 |
952
+ """
953
+ for subvalues in values:
954
+ lines = textwrap.wrap(
955
+ text=repr_values(subvalues), width=width - 4, break_long_words=False
956
+ )
957
+ for i, line in enumerate(lines):
958
+ print("|" if i == 0 else ">", line, "|" if i == len(lines) - 1 else ">")
959
+
960
+
961
+ def repr_tuple(values: VectorInputObject) -> str:
962
+ """Return a tuple representation of the given values using function |repr|.
963
+
964
+ >>> from hydpy.core.objecttools import repr_tuple
965
+ >>> repr_tuple([1./1., 1./2., 1./3.])
966
+ '(1.0, 0.5, 0.333333)'
967
+
968
+ Note that the returned string is not wrapped.
969
+
970
+ In the special case of an iterable with only one entry, the returned string is
971
+ still a valid tuple:
972
+
973
+ >>> repr_tuple([1.])
974
+ '(1.0,)'
975
+ """
976
+ if len(list(values)) == 1:
977
+ return f"({repr_values(values)},)"
978
+ return f"({repr_values(values)})"
979
+
980
+
981
+ def repr_list(values: VectorInputObject) -> str:
982
+ """Return a list representation of the given values using function |repr|.
983
+
984
+ >>> from hydpy.core.objecttools import repr_list
985
+ >>> repr_list([1./1., 1./2., 1./3.])
986
+ '[1.0, 0.5, 0.333333]'
987
+
988
+ Note that the returned string is not wrapped.
989
+ """
990
+ return f"[{repr_values(values)}]"
991
+
992
+
993
+ def assignrepr_value(value: object, prefix: str) -> str:
994
+ """Return a prefixed string representation of the given value using function
995
+ |repr|.
996
+
997
+ Note that the argument has no effect. It is thought for increasing usage
998
+ compatibility with functions like |assignrepr_list| only.
999
+
1000
+ >>> from hydpy.core.objecttools import assignrepr_value
1001
+ >>> print(assignrepr_value(1./3., "test = "))
1002
+ test = 0.333333
1003
+ """
1004
+ return prefix + repr_(value)
1005
+
1006
+
1007
+ def assignrepr_values(
1008
+ values: VectorInputObject, prefix: str, width: int | None = None, _fakeend: int = 0
1009
+ ) -> str:
1010
+ """Return a prefixed, wrapped and properly aligned string representation of the
1011
+ given values using function |repr|.
1012
+
1013
+ >>> from hydpy.core.objecttools import assignrepr_values
1014
+ >>> print(assignrepr_values(range(1, 13), "test(", 20) + ")")
1015
+ test(1, 2, 3, 4, 5,
1016
+ 6, 7, 8, 9, 10,
1017
+ 11, 12)
1018
+
1019
+ If no width is given, no wrapping is performed:
1020
+
1021
+ >>> print(assignrepr_values(range(1, 13), "test(") + ")")
1022
+ test(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12)
1023
+
1024
+
1025
+ To circumvent defining too long string representations, make use of the ellipsis
1026
+ option:
1027
+
1028
+ >>> from hydpy import pub
1029
+ >>> with pub.options.ellipsis(1):
1030
+ ... print(assignrepr_values(range(1, 13), "test(", 20) + ")")
1031
+ test(1, ...,12)
1032
+
1033
+ >>> with pub.options.ellipsis(5):
1034
+ ... print(assignrepr_values(range(1, 13), "test(", 20) + ")")
1035
+ test(1, 2, 3, 4, 5,
1036
+ ...,8, 9, 10,
1037
+ 11, 12)
1038
+
1039
+ >>> with pub.options.ellipsis(6):
1040
+ ... print(assignrepr_values(range(1, 13), "test(", 20) + ")")
1041
+ test(1, 2, 3, 4, 5,
1042
+ 6, 7, 8, 9, 10,
1043
+ 11, 12)
1044
+ """
1045
+ ellipsis_ = int(hydpy.pub.options.ellipsis)
1046
+ if (ellipsis_ > 0) and (len(values) > 2 * ellipsis_):
1047
+ string = (
1048
+ f"{repr_values(values[:ellipsis_])}"
1049
+ f", ...,"
1050
+ f"{repr_values(values[-ellipsis_:])}"
1051
+ )
1052
+ else:
1053
+ string = repr_values(values)
1054
+ blanks = " " * len(prefix)
1055
+ if width is None:
1056
+ wrapped = [string]
1057
+ _fakeend = 0
1058
+ else:
1059
+ width -= len(prefix)
1060
+ wrapped = textwrap.wrap(
1061
+ text=string + "_" * _fakeend, width=width, break_long_words=False
1062
+ )
1063
+ if not wrapped:
1064
+ wrapped = [""]
1065
+ lines = []
1066
+ for idx, line in enumerate(wrapped):
1067
+ if idx == 0:
1068
+ lines.append(f"{prefix}{line}")
1069
+ else:
1070
+ lines.append(f"{blanks}{line}")
1071
+ string = "\n".join(lines)
1072
+ return string[: len(string) - _fakeend]
1073
+
1074
+
1075
+ class _AssignReprBracketed:
1076
+ """ "Double Singleton class", see the documentation on |assignrepr_tuple| and
1077
+ |assignrepr_list|."""
1078
+
1079
+ class _AlwaysBracketed:
1080
+ _new_value: bool
1081
+ _old_value: bool
1082
+
1083
+ def __init__(self, value: bool) -> None:
1084
+ self._new_value = value
1085
+ self._old_value = _AssignReprBracketed._always_bracketed
1086
+
1087
+ def __enter__(self) -> None:
1088
+ _AssignReprBracketed._always_bracketed = self._new_value
1089
+
1090
+ def __exit__(
1091
+ self,
1092
+ exception_type: type[BaseException],
1093
+ exception_value: BaseException,
1094
+ traceback: types.TracebackType,
1095
+ ) -> None:
1096
+ _AssignReprBracketed._always_bracketed = self._old_value
1097
+
1098
+ _always_bracketed: bool = True
1099
+ _brackets: Literal["()", "[]", "{}"]
1100
+
1101
+ def __init__(self, brackets: Literal["()", "[]", "{}"]) -> None:
1102
+ self._brackets = brackets
1103
+
1104
+ def __call__(
1105
+ self, values: VectorInputObject, prefix: str, width: int | None = None
1106
+ ) -> str:
1107
+ nmb_values = len(values)
1108
+ if (nmb_values == 1) and not self._always_bracketed:
1109
+ return assignrepr_value(values[0], prefix)
1110
+ if nmb_values:
1111
+ string = (
1112
+ assignrepr_values(
1113
+ values=values,
1114
+ prefix=prefix + self._brackets[0],
1115
+ width=width,
1116
+ _fakeend=1,
1117
+ )
1118
+ + self._brackets[1]
1119
+ )
1120
+ if (len(values) == 1) and (self._brackets[1] == ")"):
1121
+ return string[:-1] + ",)"
1122
+ return string
1123
+ return prefix + self._brackets
1124
+
1125
+ @classmethod
1126
+ def always_bracketed(cls, always_bracketed: bool) -> _AlwaysBracketed:
1127
+ """Change the `always_bracketed` option inside a with block."""
1128
+ return cls._AlwaysBracketed(always_bracketed)
1129
+
1130
+
1131
+ assignrepr_tuple = _AssignReprBracketed("()")
1132
+ """Return a prefixed, wrapped and properly aligned tuple string representation of the
1133
+ given values using function |repr|.
1134
+
1135
+ >>> from hydpy.core.objecttools import assignrepr_tuple
1136
+ >>> print(assignrepr_tuple(range(10), "test = ", 22))
1137
+ test = (0, 1, 2, 3, 4,
1138
+ 5, 6, 7, 8, 9)
1139
+
1140
+ If no width is given, no wrapping is performed:
1141
+
1142
+ >>> print(assignrepr_tuple(range(10), "test = "))
1143
+ test = (0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
1144
+
1145
+ Functions |assignrepr_tuple| works also on empty iterables and those which possess only
1146
+ one entry:
1147
+
1148
+ >>> print(assignrepr_tuple([], "test = "))
1149
+ test = ()
1150
+ >>> print(assignrepr_tuple([10], "test = "))
1151
+ test = (10,)
1152
+
1153
+ Optionally, bracketing single values can be prevented:
1154
+
1155
+ >>> with assignrepr_tuple.always_bracketed(False):
1156
+ ... print(assignrepr_tuple([], "test = "))
1157
+ ... print(assignrepr_tuple([10], "test = "))
1158
+ ... print(assignrepr_tuple([10, 10], "test = "))
1159
+ test = ()
1160
+ test = 10
1161
+ test = (10, 10)
1162
+
1163
+ Behind the with block, |assignrepr_tuple| works as before
1164
+ (even in case of an error):
1165
+
1166
+ >>> print(assignrepr_tuple([10], "test = "))
1167
+ test = (10,)
1168
+ """
1169
+
1170
+
1171
+ assignrepr_list = _AssignReprBracketed("[]")
1172
+ """Return a prefixed, wrapped and properly aligned list string representation of the
1173
+ given values using function |repr|.
1174
+
1175
+ >>> from hydpy.core.objecttools import assignrepr_list
1176
+ >>> print(assignrepr_list(range(10), "test = ", 22))
1177
+ test = [0, 1, 2, 3, 4,
1178
+ 5, 6, 7, 8, 9]
1179
+
1180
+ If no width is given, no wrapping is performed:
1181
+
1182
+ >>> print(assignrepr_list(range(10), "test = "))
1183
+ test = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
1184
+
1185
+ Functions |assignrepr_list| works also on empty iterables:
1186
+
1187
+ >>> print(assignrepr_list((), "test = "))
1188
+ test = []
1189
+
1190
+ Optionally, bracketing single values can be prevented:
1191
+
1192
+ >>> with assignrepr_list.always_bracketed(False):
1193
+ ... print(assignrepr_list([], "test = "))
1194
+ ... print(assignrepr_list([10], "test = "))
1195
+ ... print(assignrepr_list([10, 10], "test = "))
1196
+ test = []
1197
+ test = 10
1198
+ test = [10, 10]
1199
+
1200
+ Behind the with block, |assignrepr_list| works as before (even in case of an error):
1201
+
1202
+ >>> print(assignrepr_list([10], "test = "))
1203
+ test = [10,]
1204
+ """
1205
+
1206
+
1207
+ def assignrepr_values2(
1208
+ values: MatrixInputObject, prefix: str, width: int | None = None
1209
+ ) -> str:
1210
+ """Return a prefixed and properly aligned string representation of the given
1211
+ 2-dimensional value matrix using function |repr|.
1212
+
1213
+ >>> from hydpy.core.objecttools import assignrepr_values2
1214
+ >>> import numpy
1215
+ >>> print(assignrepr_values2(numpy.eye(3), "test(") + ")")
1216
+ test(1.0, 0.0, 0.0,
1217
+ 0.0, 1.0, 0.0,
1218
+ 0.0, 0.0, 1.0)
1219
+
1220
+ Functions |assignrepr_values2| works also on empty iterables:
1221
+
1222
+ >>> print(assignrepr_values2([[]], "test(") + ")")
1223
+ test()
1224
+ """
1225
+ lines = []
1226
+ blanks = " " * len(prefix)
1227
+ for idx, subvalues in enumerate(values):
1228
+ if idx == 0:
1229
+ lines.append(f"{assignrepr_values(subvalues, prefix=prefix, width=width)},")
1230
+ else:
1231
+ lines.append(f"{assignrepr_values(subvalues, prefix=blanks, width=width)},")
1232
+ lines[-1] = lines[-1][:-1]
1233
+ return "\n".join(lines)
1234
+
1235
+
1236
+ def _assignrepr_bracketed2(
1237
+ assignrepr_bracketed1: _AssignReprBracketed,
1238
+ values: MatrixInputObject,
1239
+ prefix: str,
1240
+ width: int | None = None,
1241
+ ) -> str:
1242
+ """Return a prefixed, wrapped and properly aligned bracketed string representation
1243
+ of the given 2-dimensional value matrix using function |repr|."""
1244
+ brackets = getattr(assignrepr_bracketed1, "_brackets")
1245
+ prefix += brackets[0]
1246
+ lines = []
1247
+ blanks = " " * len(prefix)
1248
+ for idx, subvalues in enumerate(values):
1249
+ if idx == 0:
1250
+ lines.append(assignrepr_bracketed1(subvalues, prefix, width))
1251
+ else:
1252
+ lines.append(assignrepr_bracketed1(subvalues, blanks, width))
1253
+ lines[-1] += ","
1254
+ if lines:
1255
+ if (len(values) > 1) or (brackets != "()"):
1256
+ lines[-1] = lines[-1][:-1]
1257
+ lines[-1] += brackets[1]
1258
+ else:
1259
+ lines.append(prefix + brackets[1])
1260
+ return "\n".join(lines)
1261
+
1262
+
1263
+ def assignrepr_tuple2(
1264
+ values: MatrixInputObject, prefix: str, width: int | None = None
1265
+ ) -> str:
1266
+ """Return a prefixed, wrapped and properly aligned tuple string representation of
1267
+ the given 2-dimensional value matrix using function |repr|.
1268
+
1269
+ >>> from hydpy.core.objecttools import assignrepr_tuple2
1270
+ >>> import numpy
1271
+ >>> print(assignrepr_tuple2(numpy.eye(3), "test = ", 18))
1272
+ test = ((1.0, 0.0,
1273
+ 0.0),
1274
+ (0.0, 1.0,
1275
+ 0.0),
1276
+ (0.0, 0.0,
1277
+ 1.0))
1278
+
1279
+ If no width is given, no wrapping is performed:
1280
+
1281
+ >>> print(assignrepr_tuple2(numpy.eye(3), "test = "))
1282
+ test = ((1.0, 0.0, 0.0),
1283
+ (0.0, 1.0, 0.0),
1284
+ (0.0, 0.0, 1.0))
1285
+
1286
+ Functions |assignrepr_tuple2| works also on empty iterables and those which possess
1287
+ only one entry:
1288
+
1289
+ >>> print(assignrepr_tuple2([[]], "test = "))
1290
+ test = ((),)
1291
+ >>> print(assignrepr_tuple2([], "test = "))
1292
+ test = ()
1293
+ >>> print(assignrepr_tuple2([[], [1]], "test = "))
1294
+ test = ((),
1295
+ (1,))
1296
+ """
1297
+ return _assignrepr_bracketed2(assignrepr_tuple, values, prefix, width)
1298
+
1299
+
1300
+ def assignrepr_list2(
1301
+ values: MatrixInputObject, prefix: str, width: int | None = None
1302
+ ) -> str:
1303
+ """Return a prefixed, wrapped and properly aligned list string representation of
1304
+ the given 2-dimensional value matrix using function |repr|.
1305
+
1306
+ >>> from hydpy.core.objecttools import assignrepr_list2
1307
+ >>> import numpy
1308
+ >>> print(assignrepr_list2(numpy.eye(3), "test = ", 18))
1309
+ test = [[1.0, 0.0,
1310
+ 0.0],
1311
+ [0.0, 1.0,
1312
+ 0.0],
1313
+ [0.0, 0.0,
1314
+ 1.0]]
1315
+
1316
+ If no width is given, no wrapping is performed:
1317
+
1318
+ >>> print(assignrepr_list2(numpy.eye(3), "test = "))
1319
+ test = [[1.0, 0.0, 0.0],
1320
+ [0.0, 1.0, 0.0],
1321
+ [0.0, 0.0, 1.0]]
1322
+
1323
+ Functions |assignrepr_list2| works also on empty iterables:
1324
+
1325
+ >>> print(assignrepr_list2([[]], "test = "))
1326
+ test = [[]]
1327
+ >>> print(assignrepr_list2([], "test = "))
1328
+ test = []
1329
+ >>> print(assignrepr_list2([[], [1]], "test = "))
1330
+ test = [[],
1331
+ [1]]
1332
+ """
1333
+ return _assignrepr_bracketed2(assignrepr_list, values, prefix, width)
1334
+
1335
+
1336
+ def _assignrepr_bracketed3(
1337
+ assignrepr_bracketed1: _AssignReprBracketed,
1338
+ values: TensorInputObject,
1339
+ prefix: str,
1340
+ width: int | None = None,
1341
+ ) -> str:
1342
+ """Return a prefixed, wrapped and properly aligned bracketed string representation
1343
+ of the given 3-dimensional value matrix using function |repr|."""
1344
+ brackets = getattr(assignrepr_bracketed1, "_brackets")
1345
+ prefix += brackets[0]
1346
+ lines = []
1347
+ blanks = " " * len(prefix)
1348
+ for idx, subvalues in enumerate(values):
1349
+ if idx == 0:
1350
+ lines.append(
1351
+ _assignrepr_bracketed2(assignrepr_bracketed1, subvalues, prefix, width)
1352
+ )
1353
+ else:
1354
+ lines.append(
1355
+ _assignrepr_bracketed2(assignrepr_bracketed1, subvalues, blanks, width)
1356
+ )
1357
+ lines[-1] += ","
1358
+ if lines:
1359
+ if (len(values) > 1) or (brackets != "()"):
1360
+ lines[-1] = lines[-1][:-1]
1361
+ lines[-1] += brackets[1]
1362
+ else:
1363
+ lines.append(prefix + brackets[1])
1364
+ return "\n".join(lines)
1365
+
1366
+
1367
+ def assignrepr_tuple3(
1368
+ values: TensorInputObject, prefix: str, width: int | None = None
1369
+ ) -> str:
1370
+ """Return a prefixed, wrapped and properly aligned tuple string representation of
1371
+ the given 3-dimensional value matrix using function |repr|.
1372
+
1373
+ >>> from hydpy.core.objecttools import assignrepr_tuple3
1374
+ >>> import numpy
1375
+ >>> values = [numpy.eye(3), numpy.ones((3, 3))]
1376
+ >>> print(assignrepr_tuple3(values, "test = ", 18))
1377
+ test = (((1.0,
1378
+ 0.0,
1379
+ 0.0),
1380
+ (0.0,
1381
+ 1.0,
1382
+ 0.0),
1383
+ (0.0,
1384
+ 0.0,
1385
+ 1.0)),
1386
+ ((1.0,
1387
+ 1.0,
1388
+ 1.0),
1389
+ (1.0,
1390
+ 1.0,
1391
+ 1.0),
1392
+ (1.0,
1393
+ 1.0,
1394
+ 1.0)))
1395
+
1396
+ If no width is given, no wrapping is performed:
1397
+
1398
+ >>> print(assignrepr_tuple3(values, "test = "))
1399
+ test = (((1.0, 0.0, 0.0),
1400
+ (0.0, 1.0, 0.0),
1401
+ (0.0, 0.0, 1.0)),
1402
+ ((1.0, 1.0, 1.0),
1403
+ (1.0, 1.0, 1.0),
1404
+ (1.0, 1.0, 1.0)))
1405
+
1406
+ Functions |assignrepr_tuple3| works also on empty iterables and those which possess
1407
+ only one entry:
1408
+
1409
+ >>> print(assignrepr_tuple3([[[]]], "test = "))
1410
+ test = (((),),)
1411
+ >>> print(assignrepr_tuple3([[]], "test = "))
1412
+ test = ((),)
1413
+ >>> print(assignrepr_tuple3([], "test = "))
1414
+ test = ()
1415
+ >>> print(assignrepr_tuple3([[[], [1]]], "test = "))
1416
+ test = (((),
1417
+ (1,)),)
1418
+ """
1419
+ return _assignrepr_bracketed3(assignrepr_tuple, values, prefix, width)
1420
+
1421
+
1422
+ def assignrepr_list3(
1423
+ values: TensorInputObject, prefix: str, width: int | None = None
1424
+ ) -> str:
1425
+ """Return a prefixed, wrapped and properly aligned list string representation of
1426
+ the given 3-dimensional value matrix using function |repr|.
1427
+
1428
+ >>> from hydpy.core.objecttools import assignrepr_list3
1429
+ >>> import numpy
1430
+ >>> values = [numpy.eye(3), numpy.ones((3, 3))]
1431
+ >>> print(assignrepr_list3(values, "test = ", 18))
1432
+ test = [[[1.0,
1433
+ 0.0,
1434
+ 0.0],
1435
+ [0.0,
1436
+ 1.0,
1437
+ 0.0],
1438
+ [0.0,
1439
+ 0.0,
1440
+ 1.0]],
1441
+ [[1.0,
1442
+ 1.0,
1443
+ 1.0],
1444
+ [1.0,
1445
+ 1.0,
1446
+ 1.0],
1447
+ [1.0,
1448
+ 1.0,
1449
+ 1.0]]]
1450
+
1451
+ If no width is given, no wrapping is performed:
1452
+
1453
+ >>> print(assignrepr_list3(values, "test = "))
1454
+ test = [[[1.0, 0.0, 0.0],
1455
+ [0.0, 1.0, 0.0],
1456
+ [0.0, 0.0, 1.0]],
1457
+ [[1.0, 1.0, 1.0],
1458
+ [1.0, 1.0, 1.0],
1459
+ [1.0, 1.0, 1.0]]]
1460
+
1461
+ Functions |assignrepr_list3| works also on empty iterables and those which possess
1462
+ only one entry:
1463
+
1464
+ >>> print(assignrepr_list3([[[]]], "test = "))
1465
+ test = [[[]]]
1466
+ >>> print(assignrepr_list3([[]], "test = "))
1467
+ test = [[]]
1468
+ >>> print(assignrepr_list3([], "test = "))
1469
+ test = []
1470
+ >>> print(assignrepr_list3([[[], [1]]], "test = "))
1471
+ test = [[[],
1472
+ [1]]]
1473
+ """
1474
+ return _assignrepr_bracketed3(assignrepr_list, values, prefix, width)
1475
+
1476
+
1477
+ def flatten_repr(self: object) -> str:
1478
+ """Remove the newline characters from the string representation of the given
1479
+ object.
1480
+
1481
+ Complex string representations like the following one convenient when working
1482
+ interactively but cause line breaks when included in strings like in exception
1483
+ messages:
1484
+
1485
+ >>> from hydpy import Node
1486
+ >>> node = Node("name", keywords="test")
1487
+ >>> node
1488
+ Node("name", variable="Q",
1489
+ keywords="test")
1490
+
1491
+ Use function |flatten_repr| to prevent any line breaks:
1492
+
1493
+ >>> from hydpy.core.objecttools import flatten_repr
1494
+ >>> print(flatten_repr(node))
1495
+ Node("name", variable="Q", keywords="test")
1496
+
1497
+ When implementing a new class into the HydPy framework requiring a complex "|repr|
1498
+ string", either customise a simpler "|str| string" manually (as already done for
1499
+ the class |Node| or use function |flatten_repr|:
1500
+
1501
+ >>> print(f"We print {node}!")
1502
+ We print name!
1503
+ >>> __str__ = Node.__str__
1504
+ >>> Node.__str__ = flatten_repr
1505
+ >>> print(f"We print {node}!")
1506
+ We print Node("name", variable="Q", keywords="test")!
1507
+
1508
+ >>> Node.__str__ = __str__
1509
+
1510
+ The named tuple subclass |kinw_williams.Characteristics| of application model
1511
+ |kinw_williams| relies on function |flatten_repr|:
1512
+
1513
+ >>> from hydpy.models.kinw_williams import Characteristics
1514
+ >>> characteristics = Characteristics(
1515
+ ... waterstage=1.0,
1516
+ ... discharge=5.0,
1517
+ ... derivative=0.1,
1518
+ ... length_orig=3.0,
1519
+ ... nmb_subsections=4,
1520
+ ... length_adj=2.0,
1521
+ ... )
1522
+
1523
+ >>> characteristics
1524
+ Characteristics(
1525
+ waterstage=1.0,
1526
+ discharge=5.0,
1527
+ derivative=0.1,
1528
+ length_orig=3.0,
1529
+ nmb_subsections=4,
1530
+ length_adj=2.0,
1531
+ )
1532
+
1533
+ >>> print(characteristics)
1534
+ Characteristics(waterstage=1.0, discharge=5.0, derivative=0.1, length_orig=3.0, \
1535
+ nmb_subsections=4, length_adj=2.0)
1536
+
1537
+ You can apply function |flatten_repr| on arbitrary objects on the fly, but without
1538
+ any guarantee, the result always looks good. For the following simple examples on
1539
+ some built-in types, everything seems to work:
1540
+
1541
+ >>> flatten_repr(1)
1542
+ '1'
1543
+ >>> flatten_repr((1, 2))
1544
+ '(1, 2)'
1545
+ >>> flatten_repr([(1,2),(3,4)])
1546
+ '[(1, 2), (3, 4)]'
1547
+ """
1548
+ string = " ".join(string.strip() for string in repr(self).split("\n"))
1549
+ idx = string.find("(")
1550
+ if idx > 0:
1551
+ string = f"{string[:idx]}({string[idx+1:].strip()}"
1552
+ if string.endswith(", )"):
1553
+ string = f"{string[:-3]})"
1554
+ return string
1555
+
1556
+
1557
+ @overload
1558
+ def round_(
1559
+ values: object | Iterable[object],
1560
+ decimals: int | None = None,
1561
+ *,
1562
+ sep: str = " ",
1563
+ end: str = "\n",
1564
+ file_: TextIO | None = None,
1565
+ ) -> None: ...
1566
+
1567
+
1568
+ @overload
1569
+ def round_(
1570
+ values: object | Iterable[object],
1571
+ decimals: int | None = None,
1572
+ *,
1573
+ width: int = 0,
1574
+ lfill: str | None = None,
1575
+ sep: str = " ",
1576
+ end: str = "\n",
1577
+ file_: TextIO | None = None,
1578
+ ) -> None: ...
1579
+
1580
+
1581
+ @overload
1582
+ def round_(
1583
+ values: object | Iterable[object],
1584
+ decimals: int | None = None,
1585
+ *,
1586
+ width: int = 0,
1587
+ rfill: str | None = None,
1588
+ sep: str = " ",
1589
+ end: str = "\n",
1590
+ file_: TextIO | None = None,
1591
+ ) -> None: ...
1592
+
1593
+
1594
+ def round_(
1595
+ values: object | VectorInputObject,
1596
+ decimals: int | None = None,
1597
+ *,
1598
+ width: int = 0,
1599
+ lfill: str | None = None,
1600
+ rfill: str | None = None,
1601
+ sep: str = " ",
1602
+ end: str = "\n",
1603
+ file_: TextIO | None = None,
1604
+ ) -> None:
1605
+ """Prints values with a maximum number of digits in doctests.
1606
+
1607
+ See the documentation on function |repr| for more details, and note that the
1608
+ optional keyword arguments are passed to the print function.
1609
+
1610
+ Usually one would apply function |round_| on a single or a vector of numbers:
1611
+
1612
+ >>> from hydpy import round_
1613
+ >>> round_(1.0/3.0, decimals=6)
1614
+ 0.333333
1615
+ >>> round_((1.0/2.0, 1.0/3.0, 1.0/4.0), decimals=4)
1616
+ 0.5, 0.3333, 0.25
1617
+
1618
+ The special case of 0-dimensional |numpy| |numpy.ndarray| objects does not cause
1619
+ a problem:
1620
+
1621
+ >>> from numpy import array
1622
+ >>> round_(array(1.0/3.0))
1623
+ 0.333333
1624
+
1625
+ Additionally, one can supply a `width` and a `rfill` argument:
1626
+
1627
+ >>> round_(1.0, width=6, rfill="0")
1628
+ 1.0000
1629
+
1630
+ Alternatively, one can use the `lfill` arguments, which might e.g. be usefull for
1631
+ aligning different strings:
1632
+
1633
+ >>> round_("test", width=6, lfill="_")
1634
+ __test
1635
+
1636
+ Using both the `lfill` and the `rfill` argument raises an error:
1637
+
1638
+ >>> round_(1.0, lfill="_", rfill="0")
1639
+ Traceback (most recent call last):
1640
+ ...
1641
+ ValueError: For function `round_` values are passed for both arguments `lfill` \
1642
+ and `rfill`. This is not allowed.
1643
+ """
1644
+ if decimals is None:
1645
+ decimals = hydpy.pub.options.reprdigits
1646
+ with hydpy.pub.options.reprdigits(decimals):
1647
+ if isinstance(values, numpy.ndarray) and (values.ndim == 0):
1648
+ string = repr_(values.item())
1649
+ elif isinstance(values, str):
1650
+ string = repr_(values)
1651
+ elif isinstance(values, (numpy.ndarray, Sequence)):
1652
+ string = repr_values(values)
1653
+ else:
1654
+ string = repr_(values)
1655
+ if (lfill is not None) and (rfill is not None):
1656
+ raise ValueError(
1657
+ "For function `round_` values are passed for both arguments `lfill` "
1658
+ "and `rfill`. This is not allowed."
1659
+ )
1660
+ width = max(width, len(string))
1661
+ if lfill is not None:
1662
+ string = string.rjust(width, lfill)
1663
+ if rfill is not None:
1664
+ string = string.ljust(width, rfill)
1665
+ print(string, sep=sep, end=end, file=file_)
1666
+
1667
+
1668
+ @overload
1669
+ def extract(
1670
+ values: Iterable[object] | object, types_: tuple[type[T1]], skip: bool = False
1671
+ ) -> Iterator[T1]:
1672
+ """Extract all objects of one defined type."""
1673
+
1674
+
1675
+ @overload
1676
+ def extract(
1677
+ values: Iterable[object] | object,
1678
+ types_: tuple[type[T1], type[T2]],
1679
+ skip: bool = False,
1680
+ ) -> Iterator[T1 | T2]:
1681
+ """Extract all objects of two defined types."""
1682
+
1683
+
1684
+ @overload
1685
+ def extract(
1686
+ values: Iterable[object] | object,
1687
+ types_: tuple[type[T1], type[T2], type[T3]],
1688
+ skip: bool = False,
1689
+ ) -> Iterator[T1 | T2 | T3]:
1690
+ """Extract all objects of three defined types."""
1691
+
1692
+
1693
+ def extract(
1694
+ values: Iterable[object] | object,
1695
+ types_: (
1696
+ tuple[type[T1]]
1697
+ | tuple[type[T1], type[T2]]
1698
+ | tuple[type[T1], type[T2], type[T3]]
1699
+ ),
1700
+ skip: bool = False,
1701
+ ) -> Iterator[T1 | T2 | T3]:
1702
+ """Return a generator that extracts certain objects from `values`.
1703
+
1704
+ This function is thought for supporting the definition of functions with arguments,
1705
+ that can be objects of certain types or that can be iterables containing these
1706
+ objects.
1707
+
1708
+ The following examples show that function |extract| basically implements a type
1709
+ specific flattening mechanism:
1710
+
1711
+ >>> from hydpy.core.objecttools import extract
1712
+ >>> tuple(extract("str1", (str, int)))
1713
+ ('str1',)
1714
+ >>> tuple(extract(["str1", "str2"], (str, int)))
1715
+ ('str1', 'str2')
1716
+ >>> tuple(extract((["str1", "str2"], [1,]), (str, int)))
1717
+ ('str1', 'str2', 1)
1718
+
1719
+ If an object is neither iterable nor of the required type, the following exception
1720
+ is raised:
1721
+
1722
+ >>> tuple(extract("str1", (int,)))
1723
+ Traceback (most recent call last):
1724
+ ...
1725
+ TypeError: The given (sub)value `'str1'` is not an instance of the following \
1726
+ classes: int.
1727
+
1728
+ >>> tuple(extract((["str1", "str2"], [None, 1]), (str, int)))
1729
+ Traceback (most recent call last):
1730
+ ...
1731
+ TypeError: The given (sub)value `None` is not an instance of the following \
1732
+ classes: str and int.
1733
+
1734
+ Optionally, |None| values can be skipped:
1735
+
1736
+ >>> tuple(extract(None, (str, int), True))
1737
+ ()
1738
+ >>> tuple(extract((["str1", "str2"], [None, 1]), (str, int), True))
1739
+ ('str1', 'str2', 1)
1740
+ """
1741
+ if isinstance(values, types_):
1742
+ yield values # type: ignore[misc] # see issue 4949
1743
+ elif skip and (values is None):
1744
+ return
1745
+ else:
1746
+ try:
1747
+ if isinstance(values, str) or not isinstance(values, Iterable):
1748
+ raise TypeError("temp")
1749
+ for value in values:
1750
+ yield from extract(value, types_, skip)
1751
+ except TypeError as exc:
1752
+ if exc.args[0].startswith("The given (sub)value"):
1753
+ raise exc
1754
+ enum = enumeration(types_, converter=lambda x: x.__name__)
1755
+ raise TypeError(
1756
+ f"The given (sub)value `{repr(values)}` is not an instance of the "
1757
+ f"following classes: {enum}."
1758
+ ) from None
1759
+
1760
+
1761
+ def enumeration(
1762
+ values: Iterable[T],
1763
+ converter: Callable[[T], str] = str,
1764
+ default: str = "",
1765
+ conjunction: str = "and",
1766
+ ) -> str:
1767
+ """Return an enumeration string based on the given values.
1768
+
1769
+ The following four examples show the standard output of function |enumeration|:
1770
+
1771
+ >>> from hydpy.core.objecttools import enumeration
1772
+ >>> enumeration(("text", 3, []))
1773
+ 'text, 3, and []'
1774
+ >>> enumeration(('text', 3))
1775
+ 'text and 3'
1776
+ >>> enumeration(('text',))
1777
+ 'text'
1778
+ >>> enumeration(())
1779
+ ''
1780
+
1781
+ All given objects are converted to strings by function |str|, as shown by the first
1782
+ two examples. A callback function expecting a single argument and returning a
1783
+ string can change this behaviour.
1784
+
1785
+ >>> from hydpy import classname
1786
+ >>> enumeration(("text", 3, []), converter=classname)
1787
+ 'str, int, and list'
1788
+
1789
+ You can define a default value that |enumeration| will return if it receives an
1790
+ empty iterable:
1791
+
1792
+ >>> enumeration((), default="nothing")
1793
+ 'nothing'
1794
+
1795
+ Function |enumeration| respects option |Options.ellipsis|:
1796
+
1797
+ >>> from hydpy import pub
1798
+ >>> with pub.options.ellipsis(3):
1799
+ ... enumeration(range(10))
1800
+ '0, 1, 2, ..., 7, 8, and 9'
1801
+
1802
+ You can replace the conjunction "and" with any other word:
1803
+
1804
+ >>> enumeration(range(1), conjunction="or")
1805
+ '0'
1806
+ >>> enumeration(range(2), conjunction="or")
1807
+ '0 or 1'
1808
+ >>> with pub.options.ellipsis(3):
1809
+ ... enumeration(range(10), conjunction="or")
1810
+ '0, 1, 2, ..., 7, 8, or 9'
1811
+ """
1812
+ values_ = list(converter(value) for value in values)
1813
+ if not values_:
1814
+ return default
1815
+ if len(values_) == 1:
1816
+ return values_[0]
1817
+ if len(values_) == 2:
1818
+ return f" {conjunction} ".join(values_)
1819
+ ellipsis_ = int(hydpy.pub.options.ellipsis)
1820
+ if (ellipsis_ > 0) and (len(values_) > 2 * ellipsis_):
1821
+ values_ = values_[:ellipsis_] + ["..."] + values_[-ellipsis_:]
1822
+ return f", {conjunction} ".join((", ".join(values_[:-1]), values_[-1]))
1823
+
1824
+
1825
+ def description(self: object) -> str:
1826
+ """Returns the first "paragraph" of the docstring of the given object.
1827
+
1828
+ Note that ugly things like multiple whitespaces and newline characters are removed:
1829
+
1830
+ >>> from hydpy.core.objecttools import description, augment_excmessage
1831
+ >>> description(augment_excmessage)
1832
+ 'Augment an exception message with additional information while keeping \
1833
+ the original traceback.'
1834
+
1835
+ In case the given object does not define a docstring, the following
1836
+ is returned:
1837
+ >>> description(type("Test", (), {}))
1838
+ 'no description available'
1839
+ """
1840
+ doc = self.__doc__
1841
+ if doc is None or doc == "":
1842
+ return "no description available"
1843
+ return " ".join(doc.split("\n\n")[0].split())
1844
+
1845
+
1846
+ @contextlib.contextmanager
1847
+ def get_printtarget(file_: TextIO | str | None) -> Generator[TextIO, None, None]:
1848
+ """Get a suitable file object reading for writing text useable as the `file`
1849
+ argument of the standard |print| function.
1850
+
1851
+ Function |get_printtarget| supports three types of arguments. For |None|,
1852
+ it returns `sys.stdout`:
1853
+
1854
+ >>> from hydpy.core.objecttools import get_printtarget
1855
+ >>> import sys
1856
+ >>> with get_printtarget(None) as printtarget:
1857
+ ... print("printtarget = stdout", file=printtarget)
1858
+ printtarget = stdout
1859
+
1860
+ It passes already opened file objects, flushing but not closing them:
1861
+
1862
+ >>> from hydpy import TestIO
1863
+ >>> with (
1864
+ ... TestIO(),
1865
+ ... open("testfile1.txt", "w") as testfile1,
1866
+ ... get_printtarget(testfile1) as printtarget
1867
+ ... ):
1868
+ ... print("printtarget = testfile1", file=printtarget, end="")
1869
+ >>> with TestIO(), open("testfile1.txt", "r") as testfile1:
1870
+ ... print(testfile1.read())
1871
+ printtarget = testfile1
1872
+
1873
+ It creates a new file and closes it after leaving the `with` block when receiving a
1874
+ file name:
1875
+
1876
+ >>> with TestIO(), get_printtarget("testfile2.txt") as printtarget:
1877
+ ... print("printtarget = testfile2", file=printtarget, end="")
1878
+ >>> with TestIO(), open("testfile2.txt", "r") as testfile2:
1879
+ ... print(testfile2.read())
1880
+ printtarget = testfile2
1881
+ """
1882
+ if file_ is None:
1883
+ yield sys.stdout
1884
+ elif isinstance(file_, str):
1885
+ with open(file_, "w", encoding=config.ENCODING) as printobject:
1886
+ yield printobject
1887
+ else:
1888
+ yield file_
1889
+ file_.flush()
1890
+
1891
+
1892
+ _black_filemode = black.FileMode()
1893
+
1894
+
1895
+ def apply_black(name: str, *args: object, **kwargs: object) -> str:
1896
+ """Return a string representation of an instance of a class based on the given
1897
+ name, positional arguments and keyword arguments.
1898
+
1899
+ .. _`black`: https://black.readthedocs.io/en/stable/
1900
+ .. _`PEP 8`: https://www.python.org/dev/peps/pep-0008/
1901
+
1902
+ |apply_black| helps to define `__repr__` methods that agree with `PEP 8` by using
1903
+ the code formatter `black`_:
1904
+
1905
+ >>> from hydpy.core.objecttools import apply_black
1906
+ >>> print(apply_black("Tester"))
1907
+ Tester()
1908
+ >>> print(apply_black("Tester", 1, "test"))
1909
+ Tester(1, "test")
1910
+ >>> print(apply_black("Tester", number=1, string="test"))
1911
+ Tester(number=1, string="test")
1912
+ >>> print(apply_black("Tester", 1, "test", number=2, \
1913
+ string=f"a {10*'very '}long test"))
1914
+ Tester(
1915
+ 1,
1916
+ "test",
1917
+ number=2,
1918
+ string="a very very very very very very very very very very long test",
1919
+ )
1920
+ """
1921
+ with repr_.preserve_strings(True):
1922
+ arguments = ", ".join(
1923
+ itertools.chain(
1924
+ (repr_(arg) for arg in args),
1925
+ (f"{name}={repr_(value)}" for name, value in kwargs.items()),
1926
+ )
1927
+ )
1928
+ return black.format_str(f"{name}({arguments})", mode=_black_filemode)[:-1]
1929
+
1930
+
1931
+ def value2bool(argument: str, value: str | int) -> bool:
1932
+ """Convert the given string or integer value to a boolean and return it.
1933
+
1934
+ >>> from hydpy.core.objecttools import value2bool
1935
+ >>> value2bool("x", 0), value2bool("x", 1)
1936
+ (False, True)
1937
+ >>> for value in ("1", "tRue", "T", "yEs", "y", "oN"):
1938
+ ... assert value2bool("x", value)
1939
+ >>> for value in ("0 ", "False", "f", "No", "N", "OfF"):
1940
+ ... assert not value2bool("x", value)
1941
+ >>> value2bool("x", "Tr ue")
1942
+ Traceback (most recent call last):
1943
+ ...
1944
+ ValueError: The value `Tr ue` given for argument `x` cannot be interpreted as a \
1945
+ boolean.
1946
+ """
1947
+ if isinstance(value, int):
1948
+ return bool(value)
1949
+ normed = value.strip().lower()
1950
+ if normed in ("1", "true", "t", "yes", "y", "on"):
1951
+ return True
1952
+ if normed in ("0", "false", "f", "no", "n", "off"):
1953
+ return False
1954
+ raise ValueError(
1955
+ f"The value `{value}` given for argument `{argument}` cannot be interpreted "
1956
+ f"as a boolean."
1957
+ )
1958
+
1959
+
1960
+ def is_equal(xs: NestedFloat, ys: NestedFloat, /) -> bool:
1961
+ """Check if the given nested data objects agree in their structure and values.
1962
+
1963
+ |is_equal| always considers numpy arrays as unequal to lists and tuples and nan
1964
+ values as equal to other nan values.
1965
+
1966
+ >>> from hydpy.core.objecttools import is_equal
1967
+ >>> from numpy import array, nan, ones
1968
+
1969
+ Scalars:
1970
+
1971
+ >>> assert not is_equal(1, [1])
1972
+ >>> assert is_equal(1, 1)
1973
+ >>> assert not is_equal(1, 2)
1974
+ >>> assert is_equal(nan, nan)
1975
+ >>> assert not is_equal(1, nan)
1976
+ >>> assert not is_equal(nan, 2)
1977
+
1978
+ Arrays:
1979
+
1980
+ >>> assert not is_equal(ones(2), [1, 1])
1981
+ >>> assert is_equal(ones(2), ones(2))
1982
+ >>> assert not is_equal(ones(2), ones(3))
1983
+ >>> assert is_equal(array([1, nan, 3]), array([1, nan, 3]))
1984
+ >>> assert not is_equal(array([1, nan, 3]), array([1, nan, nan]))
1985
+
1986
+ Dictionarie:
1987
+
1988
+ >>> assert not is_equal({"a": 1}, 1)
1989
+ >>> assert is_equal({}, {})
1990
+ >>> assert not is_equal({"a": 1}, {"b": 1})
1991
+ >>> assert is_equal({"a": 1}, {"a": 1})
1992
+
1993
+ Lists and tuples:
1994
+
1995
+ >>> assert not is_equal([1], 1)
1996
+ >>> assert is_equal([], ())
1997
+ >>> assert is_equal([1, 2], (1, 2))
1998
+ >>> assert not is_equal([1, 2], (1, 3))
1999
+ >>> assert not is_equal([1, 2], (1,))
2000
+
2001
+ Combinations:
2002
+
2003
+ >>> assert is_equal([1, {"a": [2, ones(3)]}], [1, {"a": [2, ones(3)]}])
2004
+ >>> assert not is_equal([1, {"a": [2, ones(3)]}], [1, {"a": [2, ones(4)]}])
2005
+ """
2006
+ if isinstance(xs, (float, int, bool)):
2007
+ if not isinstance(ys, (float, int, bool)):
2008
+ return False
2009
+ return (xs == ys) or (numpy.isnan(xs) and numpy.isnan(ys))
2010
+ if isinstance(xs, numpy.ndarray):
2011
+ if not isinstance(ys, numpy.ndarray):
2012
+ return False
2013
+ return numpy.array_equal(xs, ys, equal_nan=True)
2014
+ if isinstance(xs, Mapping):
2015
+ if not isinstance(ys, Mapping) or (tuple(xs) != tuple(ys)):
2016
+ return False
2017
+ xs, ys = tuple(xs.values()), tuple(ys.values())
2018
+ if not isinstance(ys, Sequence) or (len(xs) != len(ys)):
2019
+ return False
2020
+ for x, y in zip(xs, ys):
2021
+ if not is_equal(x, y):
2022
+ return False
2023
+ return True