pyrandyos 1.1.0a1__tar.gz

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 (204) hide show
  1. pyrandyos-1.1.0a1/.gitignore +15 -0
  2. pyrandyos-1.1.0a1/LICENSE +21 -0
  3. pyrandyos-1.1.0a1/PKG-INFO +32 -0
  4. pyrandyos-1.1.0a1/pyproject.toml +81 -0
  5. pyrandyos-1.1.0a1/pyrandyos/__init__.py +2 -0
  6. pyrandyos-1.1.0a1/pyrandyos/__main__.py +14 -0
  7. pyrandyos-1.1.0a1/pyrandyos/_testing/__init__.py +4 -0
  8. pyrandyos-1.1.0a1/pyrandyos/_testing/_pyrandyos_testing.py +13 -0
  9. pyrandyos-1.1.0a1/pyrandyos/_testing/debug.py +35 -0
  10. pyrandyos-1.1.0a1/pyrandyos/app.py +187 -0
  11. pyrandyos-1.1.0a1/pyrandyos/config/__init__.py +2 -0
  12. pyrandyos-1.1.0a1/pyrandyos/config/appconfig.py +270 -0
  13. pyrandyos-1.1.0a1/pyrandyos/config/defaults.py +49 -0
  14. pyrandyos-1.1.0a1/pyrandyos/config/expandutils.py +59 -0
  15. pyrandyos-1.1.0a1/pyrandyos/config/keys.py +58 -0
  16. pyrandyos-1.1.0a1/pyrandyos/config/local.py +112 -0
  17. pyrandyos-1.1.0a1/pyrandyos/gui/__init__.py +144 -0
  18. pyrandyos-1.1.0a1/pyrandyos/gui/callback.py +25 -0
  19. pyrandyos-1.1.0a1/pyrandyos/gui/dialogs/__init__.py +22 -0
  20. pyrandyos-1.1.0a1/pyrandyos/gui/dialogs/config/__init__.py +1 -0
  21. pyrandyos-1.1.0a1/pyrandyos/gui/dialogs/config/icons.py +20 -0
  22. pyrandyos-1.1.0a1/pyrandyos/gui/dialogs/config/pres.py +56 -0
  23. pyrandyos-1.1.0a1/pyrandyos/gui/dialogs/config/view.py +90 -0
  24. pyrandyos-1.1.0a1/pyrandyos/gui/dialogs/log/__init__.py +1 -0
  25. pyrandyos-1.1.0a1/pyrandyos/gui/dialogs/log/mixin.py +29 -0
  26. pyrandyos-1.1.0a1/pyrandyos/gui/dialogs/log/pres.py +115 -0
  27. pyrandyos-1.1.0a1/pyrandyos/gui/dialogs/log/view.py +170 -0
  28. pyrandyos-1.1.0a1/pyrandyos/gui/gui_app.py +170 -0
  29. pyrandyos-1.1.0a1/pyrandyos/gui/icons/__init__.py +5 -0
  30. pyrandyos-1.1.0a1/pyrandyos/gui/icons/assets/.gitattributes +1 -0
  31. pyrandyos-1.1.0a1/pyrandyos/gui/icons/assets/Codicons/codicon.ttf +0 -0
  32. pyrandyos-1.1.0a1/pyrandyos/gui/icons/assets/Codicons/json/LICENSE +395 -0
  33. pyrandyos-1.1.0a1/pyrandyos/gui/icons/assets/Codicons/json/LICENSE-CODE +21 -0
  34. pyrandyos-1.1.0a1/pyrandyos/gui/icons/assets/Codicons/mapping.json +602 -0
  35. pyrandyos-1.1.0a1/pyrandyos/gui/icons/assets/Codicons/ttf/LICENSE.txt +21 -0
  36. pyrandyos-1.1.0a1/pyrandyos/gui/icons/assets/ElusiveIcons/elusiveicons-webfont-2.0.ttf +0 -0
  37. pyrandyos-1.1.0a1/pyrandyos/gui/icons/assets/ElusiveIcons/elusiveicons-webfont-charmap-2.0.json +306 -0
  38. pyrandyos-1.1.0a1/pyrandyos/gui/icons/assets/ElusiveIcons/json/LICENSE.txt +21 -0
  39. pyrandyos-1.1.0a1/pyrandyos/gui/icons/assets/ElusiveIcons/ttf/LICENSE.txt +21 -0
  40. pyrandyos-1.1.0a1/pyrandyos/gui/icons/assets/Fa5/fontawesome5-regular-webfont-5.15.4.ttf +0 -0
  41. pyrandyos-1.1.0a1/pyrandyos/gui/icons/assets/Fa5/fontawesome5-regular-webfont-charmap-5.15.4.json +154 -0
  42. pyrandyos-1.1.0a1/pyrandyos/gui/icons/assets/Fa5/json/LICENSE.txt +21 -0
  43. pyrandyos-1.1.0a1/pyrandyos/gui/icons/assets/Fa5/ttf/LICENSE.txt +21 -0
  44. pyrandyos-1.1.0a1/pyrandyos/gui/icons/assets/Fa5_Brands/fontawesome5-brands-webfont-5.15.4.ttf +0 -0
  45. pyrandyos-1.1.0a1/pyrandyos/gui/icons/assets/Fa5_Brands/fontawesome5-brands-webfont-charmap-5.15.4.json +459 -0
  46. pyrandyos-1.1.0a1/pyrandyos/gui/icons/assets/Fa5_Brands/json/LICENSE.txt +21 -0
  47. pyrandyos-1.1.0a1/pyrandyos/gui/icons/assets/Fa5_Brands/ttf/LICENSE.txt +21 -0
  48. pyrandyos-1.1.0a1/pyrandyos/gui/icons/assets/Fa5_Solid/fontawesome5-solid-webfont-5.15.4.ttf +0 -0
  49. pyrandyos-1.1.0a1/pyrandyos/gui/icons/assets/Fa5_Solid/fontawesome5-solid-webfont-charmap-5.15.4.json +1004 -0
  50. pyrandyos-1.1.0a1/pyrandyos/gui/icons/assets/Fa5_Solid/json/LICENSE.txt +21 -0
  51. pyrandyos-1.1.0a1/pyrandyos/gui/icons/assets/Fa5_Solid/ttf/LICENSE.txt +21 -0
  52. pyrandyos-1.1.0a1/pyrandyos/gui/icons/assets/Fa6/fontawesome6-regular-webfont-6.7.2.ttf +0 -0
  53. pyrandyos-1.1.0a1/pyrandyos/gui/icons/assets/Fa6/fontawesome6-regular-webfont-charmap-6.7.2.json +165 -0
  54. pyrandyos-1.1.0a1/pyrandyos/gui/icons/assets/Fa6/json/LICENSE.txt +21 -0
  55. pyrandyos-1.1.0a1/pyrandyos/gui/icons/assets/Fa6/ttf/LICENSE.txt +21 -0
  56. pyrandyos-1.1.0a1/pyrandyos/gui/icons/assets/Fa6_Brands/fontawesome6-brands-webfont-6.7.2.ttf +0 -0
  57. pyrandyos-1.1.0a1/pyrandyos/gui/icons/assets/Fa6_Brands/fontawesome6-brands-webfont-charmap-6.7.2.json +497 -0
  58. pyrandyos-1.1.0a1/pyrandyos/gui/icons/assets/Fa6_Brands/json/LICENSE.txt +21 -0
  59. pyrandyos-1.1.0a1/pyrandyos/gui/icons/assets/Fa6_Brands/ttf/LICENSE.txt +21 -0
  60. pyrandyos-1.1.0a1/pyrandyos/gui/icons/assets/Fa6_Solid/fontawesome6-solid-webfont-6.7.2.ttf +0 -0
  61. pyrandyos-1.1.0a1/pyrandyos/gui/icons/assets/Fa6_Solid/fontawesome6-solid-webfont-charmap-6.7.2.json +1404 -0
  62. pyrandyos-1.1.0a1/pyrandyos/gui/icons/assets/Fa6_Solid/json/LICENSE.txt +21 -0
  63. pyrandyos-1.1.0a1/pyrandyos/gui/icons/assets/Fa6_Solid/ttf/LICENSE.txt +21 -0
  64. pyrandyos-1.1.0a1/pyrandyos/gui/icons/assets/FluentUI/FluentSystemIcons-Regular.json +8949 -0
  65. pyrandyos-1.1.0a1/pyrandyos/gui/icons/assets/FluentUI/FluentSystemIcons-Regular.ttf +0 -0
  66. pyrandyos-1.1.0a1/pyrandyos/gui/icons/assets/FluentUI/json/LICENSE +21 -0
  67. pyrandyos-1.1.0a1/pyrandyos/gui/icons/assets/FluentUI/ttf/LICENSE +21 -0
  68. pyrandyos-1.1.0a1/pyrandyos/gui/icons/assets/FluentUI_Filled/FluentSystemIcons-Filled.json +9074 -0
  69. pyrandyos-1.1.0a1/pyrandyos/gui/icons/assets/FluentUI_Filled/FluentSystemIcons-Filled.ttf +0 -0
  70. pyrandyos-1.1.0a1/pyrandyos/gui/icons/assets/FluentUI_Filled/json/LICENSE +21 -0
  71. pyrandyos-1.1.0a1/pyrandyos/gui/icons/assets/FluentUI_Filled/ttf/LICENSE +21 -0
  72. pyrandyos-1.1.0a1/pyrandyos/gui/icons/assets/FluentUI_Light/FluentSystemIcons-Light.json +191 -0
  73. pyrandyos-1.1.0a1/pyrandyos/gui/icons/assets/FluentUI_Light/FluentSystemIcons-Light.ttf +0 -0
  74. pyrandyos-1.1.0a1/pyrandyos/gui/icons/assets/FluentUI_Light/json/LICENSE +21 -0
  75. pyrandyos-1.1.0a1/pyrandyos/gui/icons/assets/FluentUI_Light/ttf/LICENSE +21 -0
  76. pyrandyos-1.1.0a1/pyrandyos/gui/icons/assets/FluentUI_Resize/FluentSystemIcons-Resizable.json +5344 -0
  77. pyrandyos-1.1.0a1/pyrandyos/gui/icons/assets/FluentUI_Resize/FluentSystemIcons-Resizable.ttf +0 -0
  78. pyrandyos-1.1.0a1/pyrandyos/gui/icons/assets/FluentUI_Resize/json/LICENSE +21 -0
  79. pyrandyos-1.1.0a1/pyrandyos/gui/icons/assets/FluentUI_Resize/ttf/LICENSE +21 -0
  80. pyrandyos-1.1.0a1/pyrandyos/gui/icons/assets/Material5/json/LICENSE.txt +21 -0
  81. pyrandyos-1.1.0a1/pyrandyos/gui/icons/assets/Material5/materialdesignicons5-webfont-5.9.55.ttf +0 -0
  82. pyrandyos-1.1.0a1/pyrandyos/gui/icons/assets/Material5/materialdesignicons5-webfont-charmap-5.9.55.json +5960 -0
  83. pyrandyos-1.1.0a1/pyrandyos/gui/icons/assets/Material5/ttf/LICENSE.txt +21 -0
  84. pyrandyos-1.1.0a1/pyrandyos/gui/icons/assets/Material6/json/LICENSE.txt +21 -0
  85. pyrandyos-1.1.0a1/pyrandyos/gui/icons/assets/Material6/materialdesignicons6-webfont-6.9.96.ttf +0 -0
  86. pyrandyos-1.1.0a1/pyrandyos/gui/icons/assets/Material6/materialdesignicons6-webfont-charmap-6.9.96.json +7369 -0
  87. pyrandyos-1.1.0a1/pyrandyos/gui/icons/assets/Material6/ttf/LICENSE.txt +21 -0
  88. pyrandyos-1.1.0a1/pyrandyos/gui/icons/assets/Phosphor/json/LICENSE.txt +21 -0
  89. pyrandyos-1.1.0a1/pyrandyos/gui/icons/assets/Phosphor/phosphor-1.3.0.ttf +0 -0
  90. pyrandyos-1.1.0a1/pyrandyos/gui/icons/assets/Phosphor/phosphor-charmap-1.3.0.json +4472 -0
  91. pyrandyos-1.1.0a1/pyrandyos/gui/icons/assets/Phosphor/ttf/LICENSE.txt +21 -0
  92. pyrandyos-1.1.0a1/pyrandyos/gui/icons/assets/RemixIcon/json/LICENSE.txt +21 -0
  93. pyrandyos-1.1.0a1/pyrandyos/gui/icons/assets/RemixIcon/remixicon-2.5.0.ttf +0 -0
  94. pyrandyos-1.1.0a1/pyrandyos/gui/icons/assets/RemixIcon/remixicon-charmap-2.5.0.json +2273 -0
  95. pyrandyos-1.1.0a1/pyrandyos/gui/icons/assets/RemixIcon/ttf/LICENSE.txt +21 -0
  96. pyrandyos-1.1.0a1/pyrandyos/gui/icons/iconfont/__init__.py +18 -0
  97. pyrandyos-1.1.0a1/pyrandyos/gui/icons/iconfont/animation.py +129 -0
  98. pyrandyos-1.1.0a1/pyrandyos/gui/icons/iconfont/font.py +142 -0
  99. pyrandyos-1.1.0a1/pyrandyos/gui/icons/iconfont/fontspec.py +136 -0
  100. pyrandyos-1.1.0a1/pyrandyos/gui/icons/iconfont/icon.py +420 -0
  101. pyrandyos-1.1.0a1/pyrandyos/gui/icons/iconfont/sources.py +102 -0
  102. pyrandyos-1.1.0a1/pyrandyos/gui/icons/init_template.py +5 -0
  103. pyrandyos-1.1.0a1/pyrandyos/gui/icons/thirdparty/__init__.py +0 -0
  104. pyrandyos-1.1.0a1/pyrandyos/gui/icons/thirdparty/codicons/__init__.py +7 -0
  105. pyrandyos-1.1.0a1/pyrandyos/gui/icons/thirdparty/codicons/names.py +602 -0
  106. pyrandyos-1.1.0a1/pyrandyos/gui/icons/thirdparty/elusiveicons/__init__.py +7 -0
  107. pyrandyos-1.1.0a1/pyrandyos/gui/icons/thirdparty/elusiveicons/names.py +306 -0
  108. pyrandyos-1.1.0a1/pyrandyos/gui/icons/thirdparty/fa5/__init__.py +7 -0
  109. pyrandyos-1.1.0a1/pyrandyos/gui/icons/thirdparty/fa5/brands/__init__.py +7 -0
  110. pyrandyos-1.1.0a1/pyrandyos/gui/icons/thirdparty/fa5/brands/names.py +459 -0
  111. pyrandyos-1.1.0a1/pyrandyos/gui/icons/thirdparty/fa5/names.py +154 -0
  112. pyrandyos-1.1.0a1/pyrandyos/gui/icons/thirdparty/fa5/solid/__init__.py +7 -0
  113. pyrandyos-1.1.0a1/pyrandyos/gui/icons/thirdparty/fa5/solid/names.py +1004 -0
  114. pyrandyos-1.1.0a1/pyrandyos/gui/icons/thirdparty/fa6/__init__.py +7 -0
  115. pyrandyos-1.1.0a1/pyrandyos/gui/icons/thirdparty/fa6/brands/__init__.py +7 -0
  116. pyrandyos-1.1.0a1/pyrandyos/gui/icons/thirdparty/fa6/brands/names.py +497 -0
  117. pyrandyos-1.1.0a1/pyrandyos/gui/icons/thirdparty/fa6/names.py +165 -0
  118. pyrandyos-1.1.0a1/pyrandyos/gui/icons/thirdparty/fa6/solid/__init__.py +7 -0
  119. pyrandyos-1.1.0a1/pyrandyos/gui/icons/thirdparty/fa6/solid/names.py +1404 -0
  120. pyrandyos-1.1.0a1/pyrandyos/gui/icons/thirdparty/fluentui/__init__.py +7 -0
  121. pyrandyos-1.1.0a1/pyrandyos/gui/icons/thirdparty/fluentui/filled/__init__.py +7 -0
  122. pyrandyos-1.1.0a1/pyrandyos/gui/icons/thirdparty/fluentui/filled/names.py +9074 -0
  123. pyrandyos-1.1.0a1/pyrandyos/gui/icons/thirdparty/fluentui/light/__init__.py +7 -0
  124. pyrandyos-1.1.0a1/pyrandyos/gui/icons/thirdparty/fluentui/light/names.py +191 -0
  125. pyrandyos-1.1.0a1/pyrandyos/gui/icons/thirdparty/fluentui/names.py +8949 -0
  126. pyrandyos-1.1.0a1/pyrandyos/gui/icons/thirdparty/fluentui/resize/__init__.py +7 -0
  127. pyrandyos-1.1.0a1/pyrandyos/gui/icons/thirdparty/fluentui/resize/names.py +5344 -0
  128. pyrandyos-1.1.0a1/pyrandyos/gui/icons/thirdparty/material5/__init__.py +7 -0
  129. pyrandyos-1.1.0a1/pyrandyos/gui/icons/thirdparty/material5/names.py +5960 -0
  130. pyrandyos-1.1.0a1/pyrandyos/gui/icons/thirdparty/material6/__init__.py +7 -0
  131. pyrandyos-1.1.0a1/pyrandyos/gui/icons/thirdparty/material6/names.py +7369 -0
  132. pyrandyos-1.1.0a1/pyrandyos/gui/icons/thirdparty/phosphor/__init__.py +7 -0
  133. pyrandyos-1.1.0a1/pyrandyos/gui/icons/thirdparty/phosphor/names.py +4472 -0
  134. pyrandyos-1.1.0a1/pyrandyos/gui/icons/thirdparty/remixicon/__init__.py +7 -0
  135. pyrandyos-1.1.0a1/pyrandyos/gui/icons/thirdparty/remixicon/names.py +2273 -0
  136. pyrandyos-1.1.0a1/pyrandyos/gui/icons/update_from_spec.py +70 -0
  137. pyrandyos-1.1.0a1/pyrandyos/gui/icons/utils.py +18 -0
  138. pyrandyos-1.1.0a1/pyrandyos/gui/loadstatus.py +95 -0
  139. pyrandyos-1.1.0a1/pyrandyos/gui/qrc.py +78 -0
  140. pyrandyos-1.1.0a1/pyrandyos/gui/qt.py +92 -0
  141. pyrandyos-1.1.0a1/pyrandyos/gui/splash.py +146 -0
  142. pyrandyos-1.1.0a1/pyrandyos/gui/styles/__init__.py +64 -0
  143. pyrandyos-1.1.0a1/pyrandyos/gui/styles/assets/arrow-down.svg +3 -0
  144. pyrandyos-1.1.0a1/pyrandyos/gui/styles/assets/arrow-left.svg +3 -0
  145. pyrandyos-1.1.0a1/pyrandyos/gui/styles/assets/arrow-right.svg +3 -0
  146. pyrandyos-1.1.0a1/pyrandyos/gui/styles/assets/arrow-up.svg +3 -0
  147. pyrandyos-1.1.0a1/pyrandyos/gui/styles/assets/branch-closed-end.svg +6 -0
  148. pyrandyos-1.1.0a1/pyrandyos/gui/styles/assets/branch-closed-more.svg +6 -0
  149. pyrandyos-1.1.0a1/pyrandyos/gui/styles/assets/branch-closed.svg +3 -0
  150. pyrandyos-1.1.0a1/pyrandyos/gui/styles/assets/branch-end.svg +5 -0
  151. pyrandyos-1.1.0a1/pyrandyos/gui/styles/assets/branch-more.svg +5 -0
  152. pyrandyos-1.1.0a1/pyrandyos/gui/styles/assets/branch-open-end.svg +6 -0
  153. pyrandyos-1.1.0a1/pyrandyos/gui/styles/assets/branch-open-more.svg +6 -0
  154. pyrandyos-1.1.0a1/pyrandyos/gui/styles/assets/branch-open.svg +3 -0
  155. pyrandyos-1.1.0a1/pyrandyos/gui/styles/assets/checkbox-checked.svg +4 -0
  156. pyrandyos-1.1.0a1/pyrandyos/gui/styles/assets/checkbox-unchecked.svg +3 -0
  157. pyrandyos-1.1.0a1/pyrandyos/gui/styles/assets/radio-checked.svg +4 -0
  158. pyrandyos-1.1.0a1/pyrandyos/gui/styles/assets/radio-unchecked.svg +3 -0
  159. pyrandyos-1.1.0a1/pyrandyos/gui/styles/assets/vibedark.qrc +21 -0
  160. pyrandyos-1.1.0a1/pyrandyos/gui/styles/assets/vibedark.qss +602 -0
  161. pyrandyos-1.1.0a1/pyrandyos/gui/styles/assets/vline.svg +4 -0
  162. pyrandyos-1.1.0a1/pyrandyos/gui/styles/qss.py +75 -0
  163. pyrandyos-1.1.0a1/pyrandyos/gui/styles/themes/__init__.py +3 -0
  164. pyrandyos-1.1.0a1/pyrandyos/gui/styles/themes/light.py +81 -0
  165. pyrandyos-1.1.0a1/pyrandyos/gui/styles/themes/qdarkstyle.py +99 -0
  166. pyrandyos-1.1.0a1/pyrandyos/gui/styles/themes/vibedark.py +62 -0
  167. pyrandyos-1.1.0a1/pyrandyos/gui/utils.py +362 -0
  168. pyrandyos-1.1.0a1/pyrandyos/gui/widgets/__init__.py +117 -0
  169. pyrandyos-1.1.0a1/pyrandyos/gui/widgets/graphview.py +20 -0
  170. pyrandyos-1.1.0a1/pyrandyos/gui/widgets/viewbase.py +45 -0
  171. pyrandyos-1.1.0a1/pyrandyos/gui/window.py +45 -0
  172. pyrandyos-1.1.0a1/pyrandyos/logging.py +359 -0
  173. pyrandyos-1.1.0a1/pyrandyos/tools/add_log_func_call_decorators.py +298 -0
  174. pyrandyos-1.1.0a1/pyrandyos/utils/__init__.py +0 -0
  175. pyrandyos-1.1.0a1/pyrandyos/utils/casesafe.py +69 -0
  176. pyrandyos-1.1.0a1/pyrandyos/utils/cfgdict.py +96 -0
  177. pyrandyos-1.1.0a1/pyrandyos/utils/classproperty.py +34 -0
  178. pyrandyos-1.1.0a1/pyrandyos/utils/cli.py +128 -0
  179. pyrandyos-1.1.0a1/pyrandyos/utils/constants/__init__.py +15 -0
  180. pyrandyos-1.1.0a1/pyrandyos/utils/constants/cli.py +60 -0
  181. pyrandyos-1.1.0a1/pyrandyos/utils/constants/windows.py +46 -0
  182. pyrandyos-1.1.0a1/pyrandyos/utils/encoding.py +9 -0
  183. pyrandyos-1.1.0a1/pyrandyos/utils/expandvars.py +166 -0
  184. pyrandyos-1.1.0a1/pyrandyos/utils/filemeta.py +272 -0
  185. pyrandyos-1.1.0a1/pyrandyos/utils/git.py +90 -0
  186. pyrandyos-1.1.0a1/pyrandyos/utils/hash.py +11 -0
  187. pyrandyos-1.1.0a1/pyrandyos/utils/json.py +109 -0
  188. pyrandyos-1.1.0a1/pyrandyos/utils/log.py +232 -0
  189. pyrandyos-1.1.0a1/pyrandyos/utils/main.py +78 -0
  190. pyrandyos-1.1.0a1/pyrandyos/utils/math.py +18 -0
  191. pyrandyos-1.1.0a1/pyrandyos/utils/net.py +39 -0
  192. pyrandyos-1.1.0a1/pyrandyos/utils/notebook.py +30 -0
  193. pyrandyos-1.1.0a1/pyrandyos/utils/paths.py +225 -0
  194. pyrandyos-1.1.0a1/pyrandyos/utils/signature_wrapper.py +156 -0
  195. pyrandyos-1.1.0a1/pyrandyos/utils/sqlite.py +82 -0
  196. pyrandyos-1.1.0a1/pyrandyos/utils/stack.py +517 -0
  197. pyrandyos-1.1.0a1/pyrandyos/utils/string.py +55 -0
  198. pyrandyos-1.1.0a1/pyrandyos/utils/system.py +171 -0
  199. pyrandyos-1.1.0a1/pyrandyos/utils/tqdm.py +112 -0
  200. pyrandyos-1.1.0a1/pyrandyos/utils/windows/__init__.py +1 -0
  201. pyrandyos-1.1.0a1/pyrandyos/utils/windows/ctypes.py +50 -0
  202. pyrandyos-1.1.0a1/pyrandyos/utils/windows/funcs.py +106 -0
  203. pyrandyos-1.1.0a1/pyrandyos/version.py +4 -0
  204. pyrandyos-1.1.0a1/readme.md +9 -0
@@ -0,0 +1,15 @@
1
+ build/
2
+ dist/
3
+ *.egg-info/
4
+ *.egg
5
+ *.py[cod]
6
+ __pycache__/
7
+ *~
8
+ ~$*
9
+
10
+ docs/
11
+ .vscode/settings.json
12
+ .coverage
13
+ .conda
14
+ logs/
15
+ tmp/
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Randy Eckman
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,32 @@
1
+ Metadata-Version: 2.4
2
+ Name: pyrandyos
3
+ Version: 1.1.0a1
4
+ Summary: Library of common functions for Python applications
5
+ Project-URL: Homepage, https://github.com/emanspeaks/pyrandyos
6
+ Project-URL: Issues, https://github.com/emanspeaks/pyrandyos/issues
7
+ Author-email: Randy Eckman <emanspeaks@gmail.com>
8
+ Maintainer-email: Randy Eckman <emanspeaks@gmail.com>
9
+ License-Expression: MIT
10
+ License-File: LICENSE
11
+ Classifier: Operating System :: OS Independent
12
+ Classifier: Programming Language :: Python :: 3
13
+ Requires-Python: >=3.10
14
+ Requires-Dist: numpy
15
+ Requires-Dist: pandas
16
+ Requires-Dist: pyside2
17
+ Requires-Dist: pywin32
18
+ Requires-Dist: tqdm
19
+ Requires-Dist: types-pyside2
20
+ Provides-Extra: qdarkstyle
21
+ Requires-Dist: qdarkstyle; extra == 'qdarkstyle'
22
+ Description-Content-Type: text/markdown
23
+
24
+ # PyRandyOS
25
+
26
+ Library of common functions for Python applications
27
+
28
+ ## Licenses
29
+
30
+ ### Icons
31
+
32
+ This repo uses icons taken from other open source icon libraries. Links to their licensing info are maintained alongside the URLs for the icon fonts in [`pyrandyos/gui/icons/iconfont/sources.py`](pyrandyos/gui/icons/iconfont/sources.py), where the paths to the license files are with respect to the repo root at the given URL.
@@ -0,0 +1,81 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "pyrandyos"
7
+ dynamic = ["version"]
8
+ description = "Library of common functions for Python applications"
9
+ readme = "readme.md"
10
+ authors = [
11
+ {name = "Randy Eckman", email = "emanspeaks@gmail.com"},
12
+ ]
13
+ maintainers = [
14
+ {name = "Randy Eckman", email = "emanspeaks@gmail.com"},
15
+ ]
16
+ dependencies = [
17
+ "pywin32",
18
+ "tqdm",
19
+ "pyside2",
20
+ "types-pyside2",
21
+ "pandas",
22
+ "numpy",
23
+ ]
24
+ license = "MIT"
25
+ license-files = ["LICENSE"]
26
+ requires-python = ">=3.10"
27
+ classifiers = [
28
+ "Programming Language :: Python :: 3",
29
+ "Operating System :: OS Independent",
30
+ ]
31
+
32
+ [project.optional-dependencies]
33
+ qdarkstyle = ["qdarkstyle"]
34
+
35
+ [tool.hatch.version]
36
+ path = "pyrandyos/version.py"
37
+
38
+ [tool.hatch.build]
39
+ include = [
40
+ "pyrandyos/**/*.py",
41
+ "pyrandyos/gui/styles/assets",
42
+ "pyrandyos/gui/icons/assets",
43
+ ]
44
+
45
+ [project.urls]
46
+ Homepage = "https://github.com/emanspeaks/pyrandyos"
47
+ Issues = "https://github.com/emanspeaks/pyrandyos/issues"
48
+
49
+ [tool.coverage.report]
50
+ # ignore_errors = true
51
+
52
+ # Regexes for lines to exclude from consideration
53
+ exclude_also = [
54
+ # Don't complain about missing debug-only code:
55
+ # "def __repr__",
56
+ # "if self\\.debug",
57
+
58
+ # Don't complain if tests don't hit defensive assertion code:
59
+ "raise AssertionError",
60
+ "raise NotImplementedError",
61
+
62
+ # Don't complain if non-runnable code isn't run:
63
+ # "if 0:",
64
+ "if __name__ == .__main__.:",
65
+
66
+ # Don't complain about abstract methods, they aren't run:
67
+ "@(abc\\.)?abstractmethod",
68
+
69
+ 'if TYPE_CHECKING:',
70
+ 'if IS_WIN_CTYPES:'
71
+ ]
72
+
73
+ [tool.coverage.run]
74
+ branch = true
75
+ # https://github.com/nedbat/coveragepy/issues/1392#issuecomment-1149310741
76
+ omit = [
77
+ "shibokensupport/*",
78
+ "pyscript",
79
+ "signature_bootstrap.py",
80
+ "tests/*",
81
+ ]
@@ -0,0 +1,2 @@
1
+ from .version import __version__ # noqa: F401
2
+ from .app import PyRandyOSApp # noqa: F401
@@ -0,0 +1,14 @@
1
+ import sys
2
+
3
+
4
+ args = sys.argv[1:]
5
+ if args[0] == 'log_func_call':
6
+ from .tools.add_log_func_call_decorators import main as main_log_func_call
7
+ if len(args) > 1:
8
+ config_path = args[1]
9
+ main_log_func_call(['.'], config_path=config_path)
10
+ else:
11
+ main_log_func_call(['.'])
12
+
13
+ else:
14
+ raise ValueError(f"Unknown command: {args[0]}")
@@ -0,0 +1,4 @@
1
+ from ._pyrandyos_testing import ( # noqa: F401
2
+ _is_pyrandyos_unittest,
3
+ _is_running_in_ci,
4
+ )
@@ -0,0 +1,13 @@
1
+ from os import environ
2
+
3
+ # these constants are only relevant to testing, do not add to constants
4
+ ENV_CI_RUNNING = 'CI'
5
+ ENV_PYRANDYOS_UNITTEST_ACTIVE = 'PYRANDYOS_UNITTEST_ACTIVE'
6
+
7
+
8
+ def _is_pyrandyos_unittest():
9
+ return bool(environ.get(ENV_PYRANDYOS_UNITTEST_ACTIVE))
10
+
11
+
12
+ def _is_running_in_ci():
13
+ return bool(environ.get(ENV_CI_RUNNING))
@@ -0,0 +1,35 @@
1
+ import sys
2
+
3
+
4
+ def is_debug_enabled():
5
+ # see https://stackoverflow.com/a/77627047/13230486
6
+ try:
7
+ if sys.gettrace() is not None:
8
+ return True
9
+ except AttributeError:
10
+ pass
11
+
12
+ try:
13
+ if sys.monitoring.get_tool(sys.monitoring.DEBUGGER_ID) is not None:
14
+ return True
15
+ except AttributeError:
16
+ pass
17
+
18
+ return False
19
+
20
+
21
+ def hide_splash():
22
+ from pyrandyos.gui.gui_app import get_gui_app
23
+ gui_app = get_gui_app()
24
+ if gui_app and gui_app.splash:
25
+ splash = gui_app.splash.gui_view.qtobj
26
+ if splash.isVisible():
27
+ splash.hide()
28
+ if is_debug_enabled():
29
+ print("Splash screen hidden, debugger is enabled")
30
+ else:
31
+ print("Splash screen hidden")
32
+ else:
33
+ print("Splash screen is already hidden")
34
+ else:
35
+ print("No splash screen to hide")
@@ -0,0 +1,187 @@
1
+ import sys
2
+ from pathlib import Path
3
+ from tempfile import gettempdir
4
+
5
+ from .logging import (
6
+ log_info, Logger, log_func_call, DEBUGLOW2, set_trace_logging,
7
+ set_func_call_logging,
8
+ )
9
+ from .config import AppConfig
10
+ from .config.keys import (
11
+ BASE_LOG_PATH_KEY, APP_NAME_KEY, get_log_dir_keys, APP_PKG_DIR_KEY,
12
+ APP_ASSETS_DIR_KEY, APP_PKG_VERSION_KEY, TMP_DIR_KEY, LOCAL_CFG_KEY
13
+ )
14
+ from .config.local import process_local_config
15
+
16
+ from .utils.constants import DEFAULT_GROUP, DEFAULT_DIR_MODE
17
+ from .utils.log import setup_logging, create_log_file
18
+ from .utils.main import MainContext
19
+ from .utils.system import mkdir_chgrp
20
+ from .utils.stack import (
21
+ top_package_dir_path, top_module_and_name, set_show_traceback_locals
22
+ )
23
+
24
+
25
+ class PyRandyOSApp(AppConfig):
26
+ # abstract class attributes
27
+ APP_NAME: str
28
+ APP_LOG_PREFIX: str
29
+
30
+ # class attributes with fallback defaults
31
+ APP_PATH_KEYS: tuple[str] = ()
32
+ APP_LOG_DIR_KEYS: tuple[str] = ()
33
+ APP_GLOBAL_DEFAULTS = {}
34
+ APP_LOCAL_DEFAULTS = {}
35
+ APP_ASSETS_DIR: str | Path = None
36
+ "path to be resolved when config is processed; may use variable expansion"
37
+
38
+ use_local_config: bool = None
39
+
40
+ @classmethod
41
+ @log_func_call
42
+ def main(cls, *args, **kwargs):
43
+ raise NotImplementedError
44
+
45
+ @classmethod
46
+ @log_func_call
47
+ def init_main(cls, config: dict | str | Path = None,
48
+ setup_log: bool = False, logfile: Path = None,
49
+ logger: Logger = None, **kwargs):
50
+ "returns True if a local config is present and loaded, else False"
51
+ # log = logger or get_logger()
52
+ cls.set_logger(logger)
53
+ cls.init_parse_config(config, kwargs)
54
+
55
+ # setup logging first if necessary:
56
+ if setup_log:
57
+ (
58
+ logdir,
59
+ ts_name,
60
+ append,
61
+ cli_log_level,
62
+ file_log_level,
63
+ log_trace_enabled,
64
+ tb_locals_enabled,
65
+ log_func_call_enabled,
66
+ ) = cls.expand_log_config()
67
+ logfile = logfile or create_log_file(logdir, ts_name, append,
68
+ cls.APP_LOG_PREFIX)
69
+
70
+ set_trace_logging(log_trace_enabled)
71
+ set_func_call_logging(log_func_call_enabled)
72
+ set_show_traceback_locals(tb_locals_enabled)
73
+ setup_logging(logfile, cli_log_level, file_log_level)
74
+
75
+ # start logging and process the rest of the configuration data
76
+ cls.set(BASE_LOG_PATH_KEY, logfile)
77
+ cls.set(APP_PKG_VERSION_KEY, cls.get_package_version())
78
+ pkgdir = cls.get_package_dir()
79
+ cls.set(APP_PKG_DIR_KEY, pkgdir)
80
+ assets_dir = cls.get_assets_dir()
81
+ if assets_dir:
82
+ cls.set(APP_ASSETS_DIR_KEY, assets_dir)
83
+
84
+ appname = cls.APP_NAME
85
+ cls.set(APP_NAME_KEY, appname)
86
+ log_info(f"Starting {appname}")
87
+ cls.process_config()
88
+
89
+ use_local_config = process_local_config(app_path_keys=cls.APP_PATH_KEYS) # noqa: E501
90
+ cls.use_local_config = use_local_config
91
+ return use_local_config
92
+
93
+ @classmethod
94
+ @log_func_call
95
+ def process_config(cls, skip_expansion: str | list[str] = 'skip_expand',
96
+ config: dict = None):
97
+ return super().process_config(skip_expansion, config,
98
+ app_path_keys=cls.APP_PATH_KEYS)
99
+
100
+ @classmethod
101
+ @log_func_call
102
+ def init_parse_config(cls, indata: dict | str | Path = None,
103
+ overrides: dict = None, defaults: dict = None):
104
+ global_defaults = dict()
105
+ global_defaults.update(cls.APP_GLOBAL_DEFAULTS)
106
+ return super().init_parse_config(indata, overrides, defaults,
107
+ global_defaults,
108
+ cls.APP_LOCAL_DEFAULTS)
109
+
110
+ @classmethod
111
+ @log_func_call
112
+ def run_cmdline(cls, args: list[str] = None):
113
+ if args is None:
114
+ args = sys.argv[1:]
115
+
116
+ with MainContext(cls.APP_NAME):
117
+ sys.exit(cls.main(*cls.preprocess_args(args)))
118
+
119
+ @classmethod
120
+ @log_func_call
121
+ def preprocess_args(cls, args: list[str]):
122
+ if len(args) > 0:
123
+ raise ValueError('too many command line arguments')
124
+
125
+ return args
126
+
127
+ @classmethod
128
+ @log_func_call
129
+ def create_log_dirs(cls, group: str = DEFAULT_GROUP,
130
+ mode: int = DEFAULT_DIR_MODE):
131
+ for key in get_log_dir_keys(cls.APP_LOG_DIR_KEYS):
132
+ p: Path = cls.get(key)
133
+ mkdir_chgrp(p, group, mode)
134
+
135
+ @classmethod
136
+ @log_func_call(DEBUGLOW2, trace_only=True)
137
+ def mkdir_temp(cls, name: str = None, group: str = DEFAULT_GROUP,
138
+ mode: int = DEFAULT_DIR_MODE):
139
+ tmp_dir: Path | None = cls.get(TMP_DIR_KEY)
140
+ if not tmp_dir:
141
+ try:
142
+ appname = cls.APP_NAME
143
+ except AttributeError:
144
+ appname = 'PyRandyOSApp'
145
+
146
+ tmp_dir = Path(gettempdir())/appname
147
+ if cls.global_config:
148
+ cls.set(TMP_DIR_KEY, tmp_dir)
149
+
150
+ if name:
151
+ tmp_dir = tmp_dir/name
152
+
153
+ mkdir_chgrp(tmp_dir, group, mode)
154
+ return tmp_dir
155
+
156
+ @classmethod
157
+ @log_func_call
158
+ def get_package_version(cls):
159
+ return getattr(top_module_and_name(cls)[0], '__version__')
160
+
161
+ @classmethod
162
+ @log_func_call
163
+ def get_package_dir(cls):
164
+ return top_package_dir_path(cls)
165
+
166
+ @classmethod
167
+ @log_func_call
168
+ def get_assets_dir(cls):
169
+ assetsdir = cls.get(APP_ASSETS_DIR_KEY, cls.APP_ASSETS_DIR)
170
+ if assetsdir:
171
+ return Path(assetsdir)
172
+
173
+ @classmethod
174
+ @log_func_call(DEBUGLOW2)
175
+ def get_default_win_size(cls):
176
+ return (cls[f'{LOCAL_CFG_KEY}.default_width'],
177
+ cls[f'{LOCAL_CFG_KEY}.default_height'])
178
+
179
+ @classmethod
180
+ @log_func_call(DEBUGLOW2)
181
+ def get_local_config(cls, case_insensitive: bool = None):
182
+ return super().get_local_config(case_insensitive=case_insensitive)
183
+
184
+ @classmethod
185
+ @log_func_call
186
+ def save_local_config(cls, case_insensitive: bool = None):
187
+ return super().save_local_config(cls.APP_PATH_KEYS, case_insensitive)
@@ -0,0 +1,2 @@
1
+ from .appconfig import AppConfig # noqa: F401
2
+ from .local import get_local_config, save_local_config # noqa: F401
@@ -0,0 +1,270 @@
1
+ from logging import Logger
2
+ from pathlib import Path
3
+ from copy import deepcopy
4
+
5
+ from ..logging import (
6
+ DEBUGLOW2, log_func_call, set_trace_logging, set_func_call_logging,
7
+ set_global_logger, get_global_logger
8
+ )
9
+ from ..utils.classproperty import classproperty
10
+ from ..utils.paths import (
11
+ get_expanded_pathobj, get_expanded_pureposixpath, pureposixpath_to_pathobj
12
+ )
13
+ from ..utils.json import load_jsonc
14
+ from ..utils.cfgdict import (
15
+ config_dict_get, config_dict_set, config_dict_update,
16
+ )
17
+ from ..utils.constants import NODEFAULT, IS_WIN32
18
+ from ..utils.system import build_cmd_arg_list
19
+ from ..utils.casesafe import casesafe_is_equal, casesafe_value_in_container
20
+ from ..utils.stack import set_show_traceback_locals
21
+
22
+ from .defaults import get_defaults
23
+ from .keys import (
24
+ BASE_LOG_DIR_KEY, BASE_PATH_KEY, LOG_TIMESTAMP_KEY,
25
+ APPEND_LOG_KEY, CLI_LOG_LEVEL_KEY, get_path_keys, BASE_LOG_PATH_KEY,
26
+ FILE_LOG_LEVEL_KEY, ABS_BASE_PATH_KEY, LOG_TRACE_ENABLED_KEY,
27
+ SHOW_TRACEBACK_LOCALS_KEY, LOG_FUNC_CALL_ENABLED_KEY,
28
+ )
29
+ from .expandutils import expand_key_recursively
30
+
31
+ _GLOBAL_CFG: dict = None
32
+
33
+
34
+ class AppConfigType(type):
35
+ # this is really just here for VSCode syntax highlighting because the real
36
+ # class won't necessarily have access to this as a metaclass.
37
+ # Don't overthink this. Just make sure it's set in AppConfig and
38
+ # its subclasses.
39
+ CONFIG_CASE_INSENSITIVE: bool
40
+
41
+ @log_func_call(DEBUGLOW2, trace_only=True)
42
+ def get_case(cls, case_insensitive: bool = None):
43
+ return (cls.CONFIG_CASE_INSENSITIVE if case_insensitive is None
44
+ else case_insensitive)
45
+
46
+ @log_func_call(DEBUGLOW2, trace_only=True)
47
+ def __contains__(cls, item):
48
+ return casesafe_value_in_container(_GLOBAL_CFG, item, cls.get_case())
49
+
50
+
51
+ class AppConfig(metaclass=AppConfigType):
52
+ CONFIG_CASE_INSENSITIVE: bool = IS_WIN32
53
+
54
+ @log_func_call
55
+ def __init__(self):
56
+ # Class is intended as a singleton
57
+ if type(self) is AppConfig: # pragma: no cover
58
+ raise NotImplementedError('Singleton class should not be '
59
+ 'instantiated')
60
+
61
+ @classproperty
62
+ @log_func_call(DEBUGLOW2, trace_only=True)
63
+ def log(cls):
64
+ return get_global_logger()
65
+
66
+ @classmethod
67
+ @log_func_call
68
+ def set_logger(cls, log: Logger):
69
+ set_global_logger(log)
70
+
71
+ @classmethod
72
+ @log_func_call
73
+ def set(cls, key: str, value, case_insensitive: bool = None):
74
+ config_dict_set(_GLOBAL_CFG, key, value,
75
+ cls.get_case(case_insensitive))
76
+
77
+ @classmethod
78
+ @log_func_call(DEBUGLOW2, trace_only=True)
79
+ def __class_getitem__(cls, key: str):
80
+ return config_dict_get(_GLOBAL_CFG, key,
81
+ case_insensitive=cls.get_case())
82
+
83
+ @classmethod
84
+ @log_func_call
85
+ def set_global_config(cls, config: dict):
86
+ log = get_global_logger()
87
+ log.debug('setting global config')
88
+ global _GLOBAL_CFG
89
+ _GLOBAL_CFG = config
90
+
91
+ @classmethod
92
+ @log_func_call(DEBUGLOW2)
93
+ def get_global_config(cls):
94
+ return _GLOBAL_CFG
95
+
96
+ @classproperty
97
+ @log_func_call(DEBUGLOW2)
98
+ def global_config(cls):
99
+ return cls.get_global_config()
100
+
101
+ @global_config.setter
102
+ @log_func_call
103
+ def global_config(cls, config: dict):
104
+ cls.set_global_config(config)
105
+
106
+ @classmethod
107
+ @log_func_call(DEBUGLOW2, trace_only=True)
108
+ def get(cls, key: str, default=NODEFAULT,
109
+ case_insensitive: bool = None):
110
+ """
111
+ If the global app config has been set, returns the value for the
112
+ given key if present, else returns the default if provided.
113
+ When no global app config is set, returns None.
114
+
115
+ If the key contains '.', it assumes that the key is a dot-delimited
116
+ list of keys of nested dicts or lists, and will recursively drill down
117
+ through the config dict to return the ultimate value.
118
+
119
+ Args:
120
+ key (str): key to get from dict or dot-delimited list of keys
121
+ default (Any, optional): Value to return if key not found.
122
+ Defaults to NODEFAULT, which raises a KeyError if key is
123
+ not found.
124
+
125
+ Raises:
126
+ KeyError: key not found in `config` or its nested children
127
+
128
+ Returns:
129
+ Any: value for key or default value (if provided) or None if the
130
+ global app config is not set.
131
+ """
132
+ if _GLOBAL_CFG:
133
+ return config_dict_get(_GLOBAL_CFG, key, default,
134
+ cls.get_case(case_insensitive))
135
+
136
+ @classmethod
137
+ @log_func_call
138
+ def update(cls, data: dict, case_insensitive: bool = None):
139
+ config_dict_update(_GLOBAL_CFG, data, cls.get_case(case_insensitive))
140
+
141
+ @classmethod
142
+ @log_func_call
143
+ def build_cmd_args_from_config(cls, key: str):
144
+ return build_cmd_arg_list(cls[key])
145
+
146
+ @classmethod
147
+ @log_func_call
148
+ def process_config(cls, skip_expansion: str | list[str] = 'skip_expand',
149
+ config: dict = None, app_path_keys: tuple[str] = (),
150
+ case_insensitive: bool = None):
151
+ config = config or _GLOBAL_CFG
152
+ case = cls.get_case(case_insensitive)
153
+ skip_expansion = skip_expansion or ()
154
+ if isinstance(skip_expansion, str):
155
+ skip_expansion = (skip_expansion,)
156
+
157
+ for k in config.keys():
158
+ # print(k)
159
+ expand_key_recursively(config, k, skip_expansion,
160
+ case_insensitive=case)
161
+
162
+ base_path = get_expanded_pathobj(config[BASE_PATH_KEY], config, case)
163
+ config_dict_set(config, BASE_PATH_KEY, base_path, case)
164
+ config_dict_set(config, ABS_BASE_PATH_KEY, base_path.absolute(), case)
165
+ for k in get_path_keys(app_path_keys):
166
+ if casesafe_is_equal(k, BASE_PATH_KEY):
167
+ continue
168
+
169
+ v = config_dict_get(config, k, None, case)
170
+ if v:
171
+ config_dict_set(config, k, cls.handle_path(v, base_path))
172
+
173
+ set_trace_logging(config_dict_get(config, LOG_TRACE_ENABLED_KEY,
174
+ case_insensitive=case))
175
+ set_func_call_logging(config_dict_get(config,
176
+ LOG_FUNC_CALL_ENABLED_KEY,
177
+ case_insensitive=case))
178
+ set_show_traceback_locals(config_dict_get(config,
179
+ SHOW_TRACEBACK_LOCALS_KEY,
180
+ case_insensitive=case))
181
+ return config
182
+
183
+ @classmethod
184
+ @log_func_call
185
+ def get_base_logpath(cls):
186
+ return config_dict_get(_GLOBAL_CFG, BASE_LOG_PATH_KEY,
187
+ case_insensitive=cls.get_case())
188
+
189
+ @classmethod
190
+ @log_func_call
191
+ def init_parse_config(cls, indata: dict | str | Path = None,
192
+ overrides: dict = None, defaults: dict = None,
193
+ app_global_defaults: dict = {},
194
+ app_local_defaults: dict = {},
195
+ case_insensitive: bool = None):
196
+ defaults = defaults or get_defaults(cls, app_global_defaults,
197
+ app_local_defaults)
198
+
199
+ config = deepcopy(defaults)
200
+ if indata:
201
+ config_dict_update(config, indata if isinstance(indata, dict)
202
+ else load_jsonc(indata), case_insensitive)
203
+
204
+ if overrides:
205
+ config_dict_update(config, overrides, case_insensitive)
206
+
207
+ global _GLOBAL_CFG
208
+ _GLOBAL_CFG = config
209
+
210
+ @classmethod
211
+ @log_func_call
212
+ def expand_log_config(cls, skip_expansion: str | list[str] = None):
213
+ # An abbreviated function to get the log path quickly before further
214
+ # expansions so further error messages can be logged.
215
+ # All of these keys are hardcoded, so we don't need to worry about case
216
+ config = _GLOBAL_CFG
217
+ expand_key_recursively(config, BASE_PATH_KEY, skip_expansion)
218
+ expand_key_recursively(config, BASE_LOG_DIR_KEY, skip_expansion)
219
+ expand_key_recursively(config, LOG_TIMESTAMP_KEY, skip_expansion)
220
+ expand_key_recursively(config, APPEND_LOG_KEY, skip_expansion)
221
+ expand_key_recursively(config, CLI_LOG_LEVEL_KEY, skip_expansion)
222
+ expand_key_recursively(config, FILE_LOG_LEVEL_KEY, skip_expansion)
223
+ expand_key_recursively(config, LOG_TRACE_ENABLED_KEY, skip_expansion)
224
+ expand_key_recursively(config, LOG_FUNC_CALL_ENABLED_KEY,
225
+ skip_expansion)
226
+ expand_key_recursively(config, SHOW_TRACEBACK_LOCALS_KEY,
227
+ skip_expansion)
228
+ base_path = get_expanded_pathobj(config[BASE_PATH_KEY], config)
229
+ logdir = config_dict_get(config, BASE_LOG_DIR_KEY)
230
+ timestamp_name = config_dict_get(config, LOG_TIMESTAMP_KEY)
231
+ append_log = config_dict_get(config, APPEND_LOG_KEY)
232
+ cli_log_level = config_dict_get(config, CLI_LOG_LEVEL_KEY)
233
+ file_log_level = config_dict_get(config, FILE_LOG_LEVEL_KEY)
234
+ log_trace_enabled = config_dict_get(config, LOG_TRACE_ENABLED_KEY)
235
+ log_func_call_enabled = config_dict_get(config,
236
+ LOG_FUNC_CALL_ENABLED_KEY)
237
+ tb_locals_enabled = config_dict_get(config, SHOW_TRACEBACK_LOCALS_KEY)
238
+ return (cls.handle_path(logdir, base_path), timestamp_name,
239
+ append_log, cli_log_level, file_log_level, log_trace_enabled,
240
+ tb_locals_enabled, log_func_call_enabled)
241
+
242
+ @classmethod
243
+ @log_func_call
244
+ def handle_path(cls, x: str, base_path: Path,
245
+ case_insensitive: bool = None) -> Path:
246
+ newppp = get_expanded_pureposixpath(x, _GLOBAL_CFG, case_insensitive)
247
+ newpath = pureposixpath_to_pathobj(newppp)
248
+
249
+ # any relative paths are assumed to be wrt base path for now
250
+ newpathstr = str(newpath)
251
+ if not newpath.is_absolute() and newpathstr[0] != '$':
252
+ if x[:2] in ('./', '.\\'):
253
+ newpath = get_expanded_pathobj(newpath)
254
+ else:
255
+ newpath = base_path/newpath
256
+
257
+ return newpath
258
+
259
+ @staticmethod
260
+ @log_func_call
261
+ def get_local_config(base: dict = None, case_insensitive: bool = None):
262
+ from .local import get_local_config as _getlocal
263
+ return _getlocal(base, case_insensitive)
264
+
265
+ @staticmethod
266
+ @log_func_call
267
+ def save_local_config(app_path_keys: tuple = (),
268
+ case_insensitive: bool = None):
269
+ from .local import save_local_config as _savelocal
270
+ _savelocal(app_path_keys, case_insensitive)