appinfra 0.0.1__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 (308) hide show
  1. appinfra-0.0.1/LICENSE +201 -0
  2. appinfra-0.0.1/PKG-INFO +43 -0
  3. appinfra-0.0.1/README.md +457 -0
  4. appinfra-0.0.1/appinfra/__init__.py +112 -0
  5. appinfra-0.0.1/appinfra/_build_info.py +8 -0
  6. appinfra-0.0.1/appinfra/app/__init__.py +128 -0
  7. appinfra-0.0.1/appinfra/app/args.py +37 -0
  8. appinfra-0.0.1/appinfra/app/builder/__init__.py +52 -0
  9. appinfra-0.0.1/appinfra/app/builder/app.py +738 -0
  10. appinfra-0.0.1/appinfra/app/builder/config.py +315 -0
  11. appinfra-0.0.1/appinfra/app/builder/configurer/__init__.py +20 -0
  12. appinfra-0.0.1/appinfra/app/builder/configurer/advanced.py +115 -0
  13. appinfra-0.0.1/appinfra/app/builder/configurer/logging.py +286 -0
  14. appinfra-0.0.1/appinfra/app/builder/configurer/server.py +164 -0
  15. appinfra-0.0.1/appinfra/app/builder/configurer/tool.py +135 -0
  16. appinfra-0.0.1/appinfra/app/builder/configurer/version.py +202 -0
  17. appinfra-0.0.1/appinfra/app/builder/hook.py +338 -0
  18. appinfra-0.0.1/appinfra/app/builder/middleware.py +286 -0
  19. appinfra-0.0.1/appinfra/app/builder/plugin.py +262 -0
  20. appinfra-0.0.1/appinfra/app/builder/tool.py +267 -0
  21. appinfra-0.0.1/appinfra/app/builder/validation.py +374 -0
  22. appinfra-0.0.1/appinfra/app/cli/__init__.py +14 -0
  23. appinfra-0.0.1/appinfra/app/cli/commands.py +91 -0
  24. appinfra-0.0.1/appinfra/app/cli/help.py +93 -0
  25. appinfra-0.0.1/appinfra/app/cli/parser.py +68 -0
  26. appinfra-0.0.1/appinfra/app/constants.py +14 -0
  27. appinfra-0.0.1/appinfra/app/core/__init__.py +21 -0
  28. appinfra-0.0.1/appinfra/app/core/app.py +692 -0
  29. appinfra-0.0.1/appinfra/app/core/config.py +317 -0
  30. appinfra-0.0.1/appinfra/app/core/lifecycle.py +479 -0
  31. appinfra-0.0.1/appinfra/app/core/logging_utils.py +335 -0
  32. appinfra-0.0.1/appinfra/app/core/shutdown.py +75 -0
  33. appinfra-0.0.1/appinfra/app/decorators.py +600 -0
  34. appinfra-0.0.1/appinfra/app/decorators.pyi +172 -0
  35. appinfra-0.0.1/appinfra/app/docs/__init__.py +23 -0
  36. appinfra-0.0.1/appinfra/app/docs/generator.py +325 -0
  37. appinfra-0.0.1/appinfra/app/errors.py +125 -0
  38. appinfra-0.0.1/appinfra/app/fastapi/__init__.py +130 -0
  39. appinfra-0.0.1/appinfra/app/fastapi/builder/__init__.py +7 -0
  40. appinfra-0.0.1/appinfra/app/fastapi/builder/route.py +191 -0
  41. appinfra-0.0.1/appinfra/app/fastapi/builder/server.py +229 -0
  42. appinfra-0.0.1/appinfra/app/fastapi/builder/subprocess.py +189 -0
  43. appinfra-0.0.1/appinfra/app/fastapi/builder/uvicorn.py +95 -0
  44. appinfra-0.0.1/appinfra/app/fastapi/config/__init__.py +11 -0
  45. appinfra-0.0.1/appinfra/app/fastapi/config/api.py +54 -0
  46. appinfra-0.0.1/appinfra/app/fastapi/config/ipc.py +31 -0
  47. appinfra-0.0.1/appinfra/app/fastapi/config/uvicorn.py +64 -0
  48. appinfra-0.0.1/appinfra/app/fastapi/plugin.py +156 -0
  49. appinfra-0.0.1/appinfra/app/fastapi/runtime/__init__.py +11 -0
  50. appinfra-0.0.1/appinfra/app/fastapi/runtime/adapter.py +230 -0
  51. appinfra-0.0.1/appinfra/app/fastapi/runtime/ipc.py +278 -0
  52. appinfra-0.0.1/appinfra/app/fastapi/runtime/logging.py +78 -0
  53. appinfra-0.0.1/appinfra/app/fastapi/runtime/server.py +297 -0
  54. appinfra-0.0.1/appinfra/app/fastapi/runtime/subprocess.py +247 -0
  55. appinfra-0.0.1/appinfra/app/server/__init__.py +31 -0
  56. appinfra-0.0.1/appinfra/app/server/base.py +251 -0
  57. appinfra-0.0.1/appinfra/app/server/handlers.py +152 -0
  58. appinfra-0.0.1/appinfra/app/server/routes.py +116 -0
  59. appinfra-0.0.1/appinfra/app/testing.py +71 -0
  60. appinfra-0.0.1/appinfra/app/tools/__init__.py +14 -0
  61. appinfra-0.0.1/appinfra/app/tools/base.py +347 -0
  62. appinfra-0.0.1/appinfra/app/tools/group.py +190 -0
  63. appinfra-0.0.1/appinfra/app/tools/protocol.py +128 -0
  64. appinfra-0.0.1/appinfra/app/tools/registry.py +143 -0
  65. appinfra-0.0.1/appinfra/app/tracing/__init__.py +10 -0
  66. appinfra-0.0.1/appinfra/app/tracing/traceable.py +176 -0
  67. appinfra-0.0.1/appinfra/app/utils.py +4 -0
  68. appinfra-0.0.1/appinfra/cli/__init__.py +14 -0
  69. appinfra-0.0.1/appinfra/cli/cli.py +73 -0
  70. appinfra-0.0.1/appinfra/cli/output.py +142 -0
  71. appinfra-0.0.1/appinfra/cli/tools/__init__.py +0 -0
  72. appinfra-0.0.1/appinfra/cli/tools/check_functions.py +816 -0
  73. appinfra-0.0.1/appinfra/cli/tools/code_quality.py +67 -0
  74. appinfra-0.0.1/appinfra/cli/tools/completion_tool.py +266 -0
  75. appinfra-0.0.1/appinfra/cli/tools/config_tool.py +185 -0
  76. appinfra-0.0.1/appinfra/cli/tools/docs_tool.py +791 -0
  77. appinfra-0.0.1/appinfra/cli/tools/doctor_tool.py +360 -0
  78. appinfra-0.0.1/appinfra/cli/tools/etc_path_tool.py +59 -0
  79. appinfra-0.0.1/appinfra/cli/tools/scaffold/Makefile.framework.in +46 -0
  80. appinfra-0.0.1/appinfra/cli/tools/scaffold/Makefile.standalone.in +70 -0
  81. appinfra-0.0.1/appinfra/cli/tools/scaffold/__init__.py +0 -0
  82. appinfra-0.0.1/appinfra/cli/tools/scaffold_tool.py +494 -0
  83. appinfra-0.0.1/appinfra/cli/tools/scripts_path_tool.py +33 -0
  84. appinfra-0.0.1/appinfra/cli/tools/version_tool.py +230 -0
  85. appinfra-0.0.1/appinfra/config/__init__.py +67 -0
  86. appinfra-0.0.1/appinfra/config/config.py +761 -0
  87. appinfra-0.0.1/appinfra/config/constants.py +6 -0
  88. appinfra-0.0.1/appinfra/config/schemas.py +209 -0
  89. appinfra-0.0.1/appinfra/config/watcher.py +361 -0
  90. appinfra-0.0.1/appinfra/db/__init__.py +11 -0
  91. appinfra-0.0.1/appinfra/db/db.py +275 -0
  92. appinfra-0.0.1/appinfra/db/pg/__init__.py +4 -0
  93. appinfra-0.0.1/appinfra/db/pg/connection.py +185 -0
  94. appinfra-0.0.1/appinfra/db/pg/core.py +264 -0
  95. appinfra-0.0.1/appinfra/db/pg/interface.py +78 -0
  96. appinfra-0.0.1/appinfra/db/pg/pg.py +270 -0
  97. appinfra-0.0.1/appinfra/db/pg/reconnection.py +158 -0
  98. appinfra-0.0.1/appinfra/db/pg/session.py +153 -0
  99. appinfra-0.0.1/appinfra/deprecation.py +60 -0
  100. appinfra-0.0.1/appinfra/dict.py +118 -0
  101. appinfra-0.0.1/appinfra/docs/LICENSE +201 -0
  102. appinfra-0.0.1/appinfra/docs/README.md +248 -0
  103. appinfra-0.0.1/appinfra/docs/SECURITY.md +641 -0
  104. appinfra-0.0.1/appinfra/docs/api/app-builder.md +249 -0
  105. appinfra-0.0.1/appinfra/docs/api/app.md +206 -0
  106. appinfra-0.0.1/appinfra/docs/api/database.md +143 -0
  107. appinfra-0.0.1/appinfra/docs/api/exceptions.md +109 -0
  108. appinfra-0.0.1/appinfra/docs/api/fastapi.md +497 -0
  109. appinfra-0.0.1/appinfra/docs/api/index.md +156 -0
  110. appinfra-0.0.1/appinfra/docs/api/logging.md +295 -0
  111. appinfra-0.0.1/appinfra/docs/api/time.md +321 -0
  112. appinfra-0.0.1/appinfra/docs/api/ui.md +251 -0
  113. appinfra-0.0.1/appinfra/docs/api/utilities.md +314 -0
  114. appinfra-0.0.1/appinfra/docs/api/version.md +301 -0
  115. appinfra-0.0.1/appinfra/docs/getting-started.md +502 -0
  116. appinfra-0.0.1/appinfra/docs/guides/api-stability.md +168 -0
  117. appinfra-0.0.1/appinfra/docs/guides/config-based-logging.md +68 -0
  118. appinfra-0.0.1/appinfra/docs/guides/contributing.md +295 -0
  119. appinfra-0.0.1/appinfra/docs/guides/coverage-targets.md +62 -0
  120. appinfra-0.0.1/appinfra/docs/guides/environment-variables.md +331 -0
  121. appinfra-0.0.1/appinfra/docs/guides/framework-integration.md +264 -0
  122. appinfra-0.0.1/appinfra/docs/guides/hot-reload-logging.md +431 -0
  123. appinfra-0.0.1/appinfra/docs/guides/logging-builder.md +196 -0
  124. appinfra-0.0.1/appinfra/docs/guides/makefile-customization.md +897 -0
  125. appinfra-0.0.1/appinfra/docs/guides/pg-test-helper.md +86 -0
  126. appinfra-0.0.1/appinfra/docs/guides/test-naming-standards.md +344 -0
  127. appinfra-0.0.1/appinfra/docs/guides/virtual-environment.md +73 -0
  128. appinfra-0.0.1/appinfra/docs/index.md +54 -0
  129. appinfra-0.0.1/appinfra/dot_dict.py +328 -0
  130. appinfra-0.0.1/appinfra/etc/README.md +709 -0
  131. appinfra-0.0.1/appinfra/etc/fastapi.yaml +69 -0
  132. appinfra-0.0.1/appinfra/etc/infra.yaml +39 -0
  133. appinfra-0.0.1/appinfra/etc/lg.yaml +63 -0
  134. appinfra-0.0.1/appinfra/etc/mkdocs.yaml +86 -0
  135. appinfra-0.0.1/appinfra/etc/pg.yaml +81 -0
  136. appinfra-0.0.1/appinfra/ewma.py +85 -0
  137. appinfra-0.0.1/appinfra/examples/01_basics/README.md +57 -0
  138. appinfra-0.0.1/appinfra/examples/01_basics/hello_world.py +57 -0
  139. appinfra-0.0.1/appinfra/examples/01_basics/hello_world_with_cfg.py +85 -0
  140. appinfra-0.0.1/appinfra/examples/02_app_framework/README.md +125 -0
  141. appinfra-0.0.1/appinfra/examples/02_app_framework/app_with_commands.py +58 -0
  142. appinfra-0.0.1/appinfra/examples/02_app_framework/app_with_subtools.py +108 -0
  143. appinfra-0.0.1/appinfra/examples/02_app_framework/app_with_ticker.py +92 -0
  144. appinfra-0.0.1/appinfra/examples/02_app_framework/app_with_tool.py +64 -0
  145. appinfra-0.0.1/appinfra/examples/02_app_framework/app_with_tool_builders.py +109 -0
  146. appinfra-0.0.1/appinfra/examples/03_logging/README.md +185 -0
  147. appinfra-0.0.1/appinfra/examples/03_logging/database_logging.py +677 -0
  148. appinfra-0.0.1/appinfra/examples/03_logging/disabled_logging_example.py +253 -0
  149. appinfra-0.0.1/appinfra/examples/03_logging/location_color_example.py +241 -0
  150. appinfra-0.0.1/appinfra/examples/03_logging/logging_builder_example.py +628 -0
  151. appinfra-0.0.1/appinfra/examples/03_logging/topic_logging_config.yaml +80 -0
  152. appinfra-0.0.1/appinfra/examples/03_logging/topic_logging_example.py +341 -0
  153. appinfra-0.0.1/appinfra/examples/04_configuration/README.md +216 -0
  154. appinfra-0.0.1/appinfra/examples/04_configuration/env_overrides_example.py +357 -0
  155. appinfra-0.0.1/appinfra/examples/04_configuration/etc/01_basic_database.yaml +6 -0
  156. appinfra-0.0.1/appinfra/examples/04_configuration/etc/01_basic_main.yaml +6 -0
  157. appinfra-0.0.1/appinfra/examples/04_configuration/etc/02_nested_level1.yaml +4 -0
  158. appinfra-0.0.1/appinfra/examples/04_configuration/etc/02_nested_level2.yaml +4 -0
  159. appinfra-0.0.1/appinfra/examples/04_configuration/etc/02_nested_level3.yaml +3 -0
  160. appinfra-0.0.1/appinfra/examples/04_configuration/etc/02_nested_main.yaml +4 -0
  161. appinfra-0.0.1/appinfra/examples/04_configuration/etc/03_variables_databases.yaml +8 -0
  162. appinfra-0.0.1/appinfra/examples/04_configuration/etc/03_variables_main.yaml +10 -0
  163. appinfra-0.0.1/appinfra/examples/04_configuration/etc/04_multiple_cache.yaml +4 -0
  164. appinfra-0.0.1/appinfra/examples/04_configuration/etc/04_multiple_database.yaml +4 -0
  165. appinfra-0.0.1/appinfra/examples/04_configuration/etc/04_multiple_logging.yaml +4 -0
  166. appinfra-0.0.1/appinfra/examples/04_configuration/etc/04_multiple_main.yaml +8 -0
  167. appinfra-0.0.1/appinfra/examples/04_configuration/etc/05_organized_main.yaml +7 -0
  168. appinfra-0.0.1/appinfra/examples/04_configuration/etc/06_env_dev.yaml +5 -0
  169. appinfra-0.0.1/appinfra/examples/04_configuration/etc/06_env_prod.yaml +5 -0
  170. appinfra-0.0.1/appinfra/examples/04_configuration/etc/07_circular_a.yaml +4 -0
  171. appinfra-0.0.1/appinfra/examples/04_configuration/etc/07_circular_b.yaml +4 -0
  172. appinfra-0.0.1/appinfra/examples/04_configuration/etc/common.yaml +4 -0
  173. appinfra-0.0.1/appinfra/examples/04_configuration/etc/database/config.yaml +5 -0
  174. appinfra-0.0.1/appinfra/examples/04_configuration/etc/database/connection.yaml +5 -0
  175. appinfra-0.0.1/appinfra/examples/04_configuration/etc/database/pool.yaml +4 -0
  176. appinfra-0.0.1/appinfra/examples/04_configuration/etc/env/dev/database.yaml +6 -0
  177. appinfra-0.0.1/appinfra/examples/04_configuration/etc/env/prod/database.yaml +6 -0
  178. appinfra-0.0.1/appinfra/examples/04_configuration/etc/hot_reload.yaml +22 -0
  179. appinfra-0.0.1/appinfra/examples/04_configuration/etc/logging/config.yaml +4 -0
  180. appinfra-0.0.1/appinfra/examples/04_configuration/etc/logging/handlers.yaml +9 -0
  181. appinfra-0.0.1/appinfra/examples/04_configuration/hot_reload_example.py +166 -0
  182. appinfra-0.0.1/appinfra/examples/04_configuration/tool_config_access.py +174 -0
  183. appinfra-0.0.1/appinfra/examples/04_configuration/yaml_include_example.py +364 -0
  184. appinfra-0.0.1/appinfra/examples/05_database/README.md +216 -0
  185. appinfra-0.0.1/appinfra/examples/05_database/advanced_critical_flush.py +330 -0
  186. appinfra-0.0.1/appinfra/examples/05_database/basic_critical_flush_example.py +262 -0
  187. appinfra-0.0.1/appinfra/examples/05_database/pg_test_helper_custom_config.py +266 -0
  188. appinfra-0.0.1/appinfra/examples/05_database/pg_test_helper_example.py +806 -0
  189. appinfra-0.0.1/appinfra/examples/06_advanced/README.md +217 -0
  190. appinfra-0.0.1/appinfra/examples/06_advanced/generator_usage_example.py +128 -0
  191. appinfra-0.0.1/appinfra/examples/06_advanced/graceful_shutdown_demo.py +225 -0
  192. appinfra-0.0.1/appinfra/examples/06_advanced/tcp_server.py +112 -0
  193. appinfra-0.0.1/appinfra/examples/06_advanced/ticker_standalone.py +42 -0
  194. appinfra-0.0.1/appinfra/examples/07_fastapi/fastapi_server.py +249 -0
  195. appinfra-0.0.1/appinfra/examples/08_decorators/README.md +285 -0
  196. appinfra-0.0.1/appinfra/examples/08_decorators/hierarchical_commands.py +105 -0
  197. appinfra-0.0.1/appinfra/examples/08_decorators/mixed_approach.py +212 -0
  198. appinfra-0.0.1/appinfra/examples/08_decorators/simple_decorator.py +70 -0
  199. appinfra-0.0.1/appinfra/examples/09_ui/README.md +69 -0
  200. appinfra-0.0.1/appinfra/examples/09_ui/deploy_tool.py +329 -0
  201. appinfra-0.0.1/appinfra/examples/09_ui/interactive_prompts.py +225 -0
  202. appinfra-0.0.1/appinfra/examples/09_ui/progress_logger_example.py +203 -0
  203. appinfra-0.0.1/appinfra/examples/09_ui/rich_output.py +138 -0
  204. appinfra-0.0.1/appinfra/examples/09_ui/scrollable_selection.py +147 -0
  205. appinfra-0.0.1/appinfra/examples/09_ui/secret_masking.py +206 -0
  206. appinfra-0.0.1/appinfra/examples/09_ui/spinners_and_progress.py +678 -0
  207. appinfra-0.0.1/appinfra/examples/10_plugins/README.md +100 -0
  208. appinfra-0.0.1/appinfra/examples/10_plugins/example_plugins.py +205 -0
  209. appinfra-0.0.1/appinfra/examples/11_docs/docs_generation.py +239 -0
  210. appinfra-0.0.1/appinfra/examples/12_version_tracking/README.md +113 -0
  211. appinfra-0.0.1/appinfra/examples/12_version_tracking/standalone_tracker.py +66 -0
  212. appinfra-0.0.1/appinfra/examples/12_version_tracking/version_tracking_demo.py +120 -0
  213. appinfra-0.0.1/appinfra/examples/README.md +185 -0
  214. appinfra-0.0.1/appinfra/exceptions.py +172 -0
  215. appinfra-0.0.1/appinfra/log/__init__.py +346 -0
  216. appinfra-0.0.1/appinfra/log/builder/__init__.py +91 -0
  217. appinfra-0.0.1/appinfra/log/builder/builder.py +358 -0
  218. appinfra-0.0.1/appinfra/log/builder/console.py +159 -0
  219. appinfra-0.0.1/appinfra/log/builder/database/__init__.py +24 -0
  220. appinfra-0.0.1/appinfra/log/builder/database/builder.py +375 -0
  221. appinfra-0.0.1/appinfra/log/builder/database/config.py +154 -0
  222. appinfra-0.0.1/appinfra/log/builder/database/handler.py +216 -0
  223. appinfra-0.0.1/appinfra/log/builder/file.py +301 -0
  224. appinfra-0.0.1/appinfra/log/builder/interface.py +236 -0
  225. appinfra-0.0.1/appinfra/log/builder/json.py +533 -0
  226. appinfra-0.0.1/appinfra/log/builder/quick.py +439 -0
  227. appinfra-0.0.1/appinfra/log/callback.py +196 -0
  228. appinfra-0.0.1/appinfra/log/colors.py +184 -0
  229. appinfra-0.0.1/appinfra/log/config.py +170 -0
  230. appinfra-0.0.1/appinfra/log/config_holder.py +138 -0
  231. appinfra-0.0.1/appinfra/log/constants.py +44 -0
  232. appinfra-0.0.1/appinfra/log/exceptions.py +40 -0
  233. appinfra-0.0.1/appinfra/log/factory.py +355 -0
  234. appinfra-0.0.1/appinfra/log/formatters.py +508 -0
  235. appinfra-0.0.1/appinfra/log/handler_factory.py +504 -0
  236. appinfra-0.0.1/appinfra/log/level_manager.py +436 -0
  237. appinfra-0.0.1/appinfra/log/logger.py +340 -0
  238. appinfra-0.0.1/appinfra/log/reloader.py +116 -0
  239. appinfra-0.0.1/appinfra/net/__init__.py +21 -0
  240. appinfra-0.0.1/appinfra/net/exceptions.py +30 -0
  241. appinfra-0.0.1/appinfra/net/http.py +114 -0
  242. appinfra-0.0.1/appinfra/net/tcp.py +351 -0
  243. appinfra-0.0.1/appinfra/observability/__init__.py +10 -0
  244. appinfra-0.0.1/appinfra/observability/hooks.py +261 -0
  245. appinfra-0.0.1/appinfra/rate_limit.py +62 -0
  246. appinfra-0.0.1/appinfra/regex_utils.py +264 -0
  247. appinfra-0.0.1/appinfra/scripts/check.sh +573 -0
  248. appinfra-0.0.1/appinfra/scripts/cicd-test.sh +101 -0
  249. appinfra-0.0.1/appinfra/scripts/docker/pg/docker-compose.repl.yaml +76 -0
  250. appinfra-0.0.1/appinfra/scripts/docker/pg/docker-compose.single.yaml +24 -0
  251. appinfra-0.0.1/appinfra/scripts/docker/pg/pg_hba.conf +13 -0
  252. appinfra-0.0.1/appinfra/scripts/docs-config.sh +63 -0
  253. appinfra-0.0.1/appinfra/scripts/install_deps.py +15 -0
  254. appinfra-0.0.1/appinfra/scripts/make/Makefile.all +40 -0
  255. appinfra-0.0.1/appinfra/scripts/make/Makefile.cicd +57 -0
  256. appinfra-0.0.1/appinfra/scripts/make/Makefile.clean +53 -0
  257. appinfra-0.0.1/appinfra/scripts/make/Makefile.config +184 -0
  258. appinfra-0.0.1/appinfra/scripts/make/Makefile.dev +201 -0
  259. appinfra-0.0.1/appinfra/scripts/make/Makefile.docs +37 -0
  260. appinfra-0.0.1/appinfra/scripts/make/Makefile.env +109 -0
  261. appinfra-0.0.1/appinfra/scripts/make/Makefile.help +59 -0
  262. appinfra-0.0.1/appinfra/scripts/make/Makefile.install +60 -0
  263. appinfra-0.0.1/appinfra/scripts/make/Makefile.pg +215 -0
  264. appinfra-0.0.1/appinfra/scripts/make/Makefile.pytest +167 -0
  265. appinfra-0.0.1/appinfra/scripts/make/Makefile.utils +15 -0
  266. appinfra-0.0.1/appinfra/scripts/pg-config.sh +52 -0
  267. appinfra-0.0.1/appinfra/scripts/pg-info.sh +162 -0
  268. appinfra-0.0.1/appinfra/scripts/type-hint.sh +50 -0
  269. appinfra-0.0.1/appinfra/scripts/yaml2json.sh +5 -0
  270. appinfra-0.0.1/appinfra/security/__init__.py +35 -0
  271. appinfra-0.0.1/appinfra/security/filter.py +125 -0
  272. appinfra-0.0.1/appinfra/security/masking.py +232 -0
  273. appinfra-0.0.1/appinfra/security/patterns.py +96 -0
  274. appinfra-0.0.1/appinfra/size.py +286 -0
  275. appinfra-0.0.1/appinfra/subprocess/__init__.py +9 -0
  276. appinfra-0.0.1/appinfra/subprocess/context.py +137 -0
  277. appinfra-0.0.1/appinfra/time/__init__.py +74 -0
  278. appinfra-0.0.1/appinfra/time/date_range.py +162 -0
  279. appinfra-0.0.1/appinfra/time/delta.py +518 -0
  280. appinfra-0.0.1/appinfra/time/eta.py +113 -0
  281. appinfra-0.0.1/appinfra/time/sched.py +614 -0
  282. appinfra-0.0.1/appinfra/time/ticker.py +507 -0
  283. appinfra-0.0.1/appinfra/time/time.py +291 -0
  284. appinfra-0.0.1/appinfra/ui/__init__.py +88 -0
  285. appinfra-0.0.1/appinfra/ui/console.py +291 -0
  286. appinfra-0.0.1/appinfra/ui/fallback.py +219 -0
  287. appinfra-0.0.1/appinfra/ui/help.py +202 -0
  288. appinfra-0.0.1/appinfra/ui/progress_logger.py +323 -0
  289. appinfra-0.0.1/appinfra/ui/prompts.py +707 -0
  290. appinfra-0.0.1/appinfra/utils.py +40 -0
  291. appinfra-0.0.1/appinfra/version/__init__.py +48 -0
  292. appinfra-0.0.1/appinfra/version/actions.py +131 -0
  293. appinfra-0.0.1/appinfra/version/build_info.py +112 -0
  294. appinfra-0.0.1/appinfra/version/info.py +353 -0
  295. appinfra-0.0.1/appinfra/version/setup_hook.py +287 -0
  296. appinfra-0.0.1/appinfra/version/setuptools_hook.py +111 -0
  297. appinfra-0.0.1/appinfra/version/sources.py +371 -0
  298. appinfra-0.0.1/appinfra/version/tracker.py +159 -0
  299. appinfra-0.0.1/appinfra/yaml.py +1017 -0
  300. appinfra-0.0.1/appinfra.egg-info/PKG-INFO +43 -0
  301. appinfra-0.0.1/appinfra.egg-info/SOURCES.txt +307 -0
  302. appinfra-0.0.1/appinfra.egg-info/dependency_links.txt +1 -0
  303. appinfra-0.0.1/appinfra.egg-info/entry_points.txt +5 -0
  304. appinfra-0.0.1/appinfra.egg-info/requires.txt +38 -0
  305. appinfra-0.0.1/appinfra.egg-info/top_level.txt +1 -0
  306. appinfra-0.0.1/pyproject.toml +188 -0
  307. appinfra-0.0.1/setup.cfg +7 -0
  308. appinfra-0.0.1/setup.py +104 -0
appinfra-0.0.1/LICENSE ADDED
@@ -0,0 +1,201 @@
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ http://www.apache.org/licenses/
4
+
5
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
+
7
+ 1. Definitions.
8
+
9
+ "License" shall mean the terms and conditions for use, reproduction,
10
+ and distribution as defined by Sections 1 through 9 of this document.
11
+
12
+ "Licensor" shall mean the copyright owner or entity authorized by
13
+ the copyright owner that is granting the License.
14
+
15
+ "Legal Entity" shall mean the union of the acting entity and all
16
+ other entities that control, are controlled by, or are under common
17
+ control with that entity. For the purposes of this definition,
18
+ "control" means (i) the power, direct or indirect, to cause the
19
+ direction or management of such entity, whether by contract or
20
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
21
+ outstanding shares, or (iii) beneficial ownership of such entity.
22
+
23
+ "You" (or "Your") shall mean an individual or Legal Entity
24
+ exercising permissions granted by this License.
25
+
26
+ "Source" form shall mean the preferred form for making modifications,
27
+ including but not limited to software source code, documentation
28
+ source, and configuration files.
29
+
30
+ "Object" form shall mean any form resulting from mechanical
31
+ transformation or translation of a Source form, including but
32
+ not limited to compiled object code, generated documentation,
33
+ and conversions to other media types.
34
+
35
+ "Work" shall mean the work of authorship, whether in Source or
36
+ Object form, made available under the License, as indicated by a
37
+ copyright notice that is included in or attached to the work
38
+ (an example is provided in the Appendix below).
39
+
40
+ "Derivative Works" shall mean any work, whether in Source or Object
41
+ form, that is based on (or derived from) the Work and for which the
42
+ editorial revisions, annotations, elaborations, or other modifications
43
+ represent, as a whole, an original work of authorship. For the purposes
44
+ of this License, Derivative Works shall not include works that remain
45
+ separable from, or merely link (or bind by name) to the interfaces of,
46
+ the Work and Derivative Works thereof.
47
+
48
+ "Contribution" shall mean any work of authorship, including
49
+ the original version of the Work and any modifications or additions
50
+ to that Work or Derivative Works thereof, that is intentionally
51
+ submitted to Licensor for inclusion in the Work by the copyright owner
52
+ or by an individual or Legal Entity authorized to submit on behalf of
53
+ the copyright owner. For the purposes of this definition, "submitted"
54
+ means any form of electronic, verbal, or written communication sent
55
+ to the Licensor or its representatives, including but not limited to
56
+ communication on electronic mailing lists, source code control systems,
57
+ and issue tracking systems that are managed by, or on behalf of, the
58
+ Licensor for the purpose of discussing and improving the Work, but
59
+ excluding communication that is conspicuously marked or otherwise
60
+ designated in writing by the copyright owner as "Not a Contribution."
61
+
62
+ "Contributor" shall mean Licensor and any individual or Legal Entity
63
+ on behalf of whom a Contribution has been received by Licensor and
64
+ subsequently incorporated within the Work.
65
+
66
+ 2. Grant of Copyright License. Subject to the terms and conditions of
67
+ this License, each Contributor hereby grants to You a perpetual,
68
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69
+ copyright license to reproduce, prepare Derivative Works of,
70
+ publicly display, publicly perform, sublicense, and distribute the
71
+ Work and such Derivative Works in Source or Object form.
72
+
73
+ 3. Grant of Patent License. Subject to the terms and conditions of
74
+ this License, each Contributor hereby grants to You a perpetual,
75
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76
+ (except as stated in this section) patent license to make, have made,
77
+ use, offer to sell, sell, import, and otherwise transfer the Work,
78
+ where such license applies only to those patent claims licensable
79
+ by such Contributor that are necessarily infringed by their
80
+ Contribution(s) alone or by combination of their Contribution(s)
81
+ with the Work to which such Contribution(s) was submitted. If You
82
+ institute patent litigation against any entity (including a
83
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
84
+ or a Contribution incorporated within the Work constitutes direct
85
+ or contributory patent infringement, then any patent licenses
86
+ granted to You under this License for that Work shall terminate
87
+ as of the date such litigation is filed.
88
+
89
+ 4. Redistribution. You may reproduce and distribute copies of the
90
+ Work or Derivative Works thereof in any medium, with or without
91
+ modifications, and in Source or Object form, provided that You
92
+ meet the following conditions:
93
+
94
+ (a) You must give any other recipients of the Work or
95
+ Derivative Works a copy of this License; and
96
+
97
+ (b) You must cause any modified files to carry prominent notices
98
+ stating that You changed the files; and
99
+
100
+ (c) You must retain, in the Source form of any Derivative Works
101
+ that You distribute, all copyright, patent, trademark, and
102
+ attribution notices from the Source form of the Work,
103
+ excluding those notices that do not pertain to any part of
104
+ the Derivative Works; and
105
+
106
+ (d) If the Work includes a "NOTICE" text file as part of its
107
+ distribution, then any Derivative Works that You distribute must
108
+ include a readable copy of the attribution notices contained
109
+ within such NOTICE file, excluding those notices that do not
110
+ pertain to any part of the Derivative Works, in at least one
111
+ of the following places: within a NOTICE text file distributed
112
+ as part of the Derivative Works; within the Source form or
113
+ documentation, if provided along with the Derivative Works; or,
114
+ within a display generated by the Derivative Works, if and
115
+ wherever such third-party notices normally appear. The contents
116
+ of the NOTICE file are for informational purposes only and
117
+ do not modify the License. You may add Your own attribution
118
+ notices within Derivative Works that You distribute, alongside
119
+ or as an addendum to the NOTICE text from the Work, provided
120
+ that such additional attribution notices cannot be construed
121
+ as modifying the License.
122
+
123
+ You may add Your own copyright statement to Your modifications and
124
+ may provide additional or different license terms and conditions
125
+ for use, reproduction, or distribution of Your modifications, or
126
+ for any such Derivative Works as a whole, provided Your use,
127
+ reproduction, and distribution of the Work otherwise complies with
128
+ the conditions stated in this License.
129
+
130
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
131
+ any Contribution intentionally submitted for inclusion in the Work
132
+ by You to the Licensor shall be under the terms and conditions of
133
+ this License, without any additional terms or conditions.
134
+ Notwithstanding the above, nothing herein shall supersede or modify
135
+ the terms of any separate license agreement you may have executed
136
+ with Licensor regarding such Contributions.
137
+
138
+ 6. Trademarks. This License does not grant permission to use the trade
139
+ names, trademarks, service marks, or product names of the Licensor,
140
+ except as required for reasonable and customary use in describing the
141
+ origin of the Work and reproducing the content of the NOTICE file.
142
+
143
+ 7. Disclaimer of Warranty. Unless required by applicable law or
144
+ agreed to in writing, Licensor provides the Work (and each
145
+ Contributor provides its Contributions) on an "AS IS" BASIS,
146
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147
+ implied, including, without limitation, any warranties or conditions
148
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149
+ PARTICULAR PURPOSE. You are solely responsible for determining the
150
+ appropriateness of using or redistributing the Work and assume any
151
+ risks associated with Your exercise of permissions under this License.
152
+
153
+ 8. Limitation of Liability. In no event and under no legal theory,
154
+ whether in tort (including negligence), contract, or otherwise,
155
+ unless required by applicable law (such as deliberate and grossly
156
+ negligent acts) or agreed to in writing, shall any Contributor be
157
+ liable to You for damages, including any direct, indirect, special,
158
+ incidental, or consequential damages of any character arising as a
159
+ result of this License or out of the use or inability to use the
160
+ Work (including but not limited to damages for loss of goodwill,
161
+ work stoppage, computer failure or malfunction, or any and all
162
+ other commercial damages or losses), even if such Contributor
163
+ has been advised of the possibility of such damages.
164
+
165
+ 9. Accepting Warranty or Additional Support. While redistributing
166
+ the Work or Derivative Works thereof, You may choose to offer,
167
+ and charge a fee for, acceptance of support, warranty, indemnity,
168
+ or other liability obligations and/or rights consistent with this
169
+ License. However, in accepting such obligations, You may act only
170
+ on Your own behalf and on Your sole responsibility, not on behalf
171
+ of any other Contributor, and only if You agree to indemnify,
172
+ defend, and hold each Contributor harmless for any liability
173
+ incurred by, or claims asserted against, such Contributor by reason
174
+ of your accepting any such warranty or additional liability.
175
+
176
+ END OF TERMS AND CONDITIONS
177
+
178
+ APPENDIX: How to apply the Apache License to your work.
179
+
180
+ To apply the Apache License to your work, attach the following
181
+ boilerplate notice, with the fields enclosed by brackets "[]"
182
+ replaced with your own identifying information. (Don't include
183
+ the brackets!) The text should be enclosed in the appropriate
184
+ comment syntax for the file format. We also recommend that a
185
+ file or class name and description of purpose be included on the
186
+ same "printed page" as the copyright notice for easier
187
+ identification within third-party archives.
188
+
189
+ Copyright 2025 serendip-ml
190
+
191
+ Licensed under the Apache License, Version 2.0 (the "License");
192
+ you may not use this file except in compliance with the License.
193
+ You may obtain a copy of the License at
194
+
195
+ http://www.apache.org/licenses/LICENSE-2.0
196
+
197
+ Unless required by applicable law or agreed to in writing, software
198
+ distributed under the License is distributed on an "AS IS" BASIS,
199
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200
+ See the License for the specific language governing permissions and
201
+ limitations under the License.
@@ -0,0 +1,43 @@
1
+ Metadata-Version: 2.4
2
+ Name: appinfra
3
+ Version: 0.0.1
4
+ Summary: Infrastructure framework for Python applications
5
+ Author: serendip-ml (github.com/serendip-ml)
6
+ Project-URL: Homepage, https://github.com/serendip-ml/appinfra
7
+ Project-URL: Repository, https://github.com/serendip-ml/appinfra
8
+ Project-URL: Issues, https://github.com/serendip-ml/appinfra/issues
9
+ Requires-Python: >=3.11
10
+ License-File: LICENSE
11
+ Requires-Dist: sqlalchemy<3.0.0,>=2.0.0
12
+ Requires-Dist: sqlalchemy-utils<1.0.0,>=0.42.0
13
+ Requires-Dist: psycopg2-binary<3.0.0,>=2.9.0
14
+ Requires-Dist: PyYAML<7.0,>=6.0
15
+ Requires-Dist: requests<3.0.0,>=2.32.0
16
+ Requires-Dist: urllib3<3.0.0,>=2.6.0
17
+ Provides-Extra: dev
18
+ Requires-Dist: coverage<8.0.0,>=7.0.0; extra == "dev"
19
+ Requires-Dist: ruff<1.0.0,>=0.1.0; extra == "dev"
20
+ Requires-Dist: mypy<2.0.0,>=1.0.0; extra == "dev"
21
+ Requires-Dist: pytest<10.0.0,>=7.0.0; extra == "dev"
22
+ Requires-Dist: pytest-asyncio<2.0.0,>=0.21.0; extra == "dev"
23
+ Requires-Dist: pytest-cov<8.0.0,>=4.0.0; extra == "dev"
24
+ Requires-Dist: pytest-xdist<4.0.0,>=3.0.0; extra == "dev"
25
+ Requires-Dist: hypothesis<7.0.0,>=6.0.0; extra == "dev"
26
+ Requires-Dist: pip-audit<3.0.0,>=2.0.0; extra == "dev"
27
+ Provides-Extra: validation
28
+ Requires-Dist: pydantic<3.0.0,>=2.0.0; extra == "validation"
29
+ Provides-Extra: docs
30
+ Requires-Dist: mkdocs<2.0.0,>=1.5.3; extra == "docs"
31
+ Requires-Dist: mkdocs-material<10.0.0,>=9.5.0; extra == "docs"
32
+ Requires-Dist: mkdocstrings[python]<2.0.0,>=1.0.0; extra == "docs"
33
+ Requires-Dist: mkdocs-autorefs<2.0.0,>=1.4.0; extra == "docs"
34
+ Provides-Extra: fastapi
35
+ Requires-Dist: fastapi<1.0.0,>=0.100.0; extra == "fastapi"
36
+ Requires-Dist: uvicorn[standard]<1.0.0,>=0.23.0; extra == "fastapi"
37
+ Provides-Extra: hotreload
38
+ Requires-Dist: watchdog<5.0.0,>=3.0.0; extra == "hotreload"
39
+ Provides-Extra: ui
40
+ Requires-Dist: rich<14.0.0,>=13.0.0; extra == "ui"
41
+ Requires-Dist: questionary<3.0.0,>=2.0.0; extra == "ui"
42
+ Requires-Dist: InquirerPy<1.0.0,>=0.3.0; extra == "ui"
43
+ Dynamic: license-file
@@ -0,0 +1,457 @@
1
+ # appinfra
2
+
3
+ ![Python](https://img.shields.io/badge/python-3.11+-blue.svg)
4
+ ![Coverage](https://img.shields.io/badge/coverage-95%25-brightgreen.svg)
5
+ ![Type Hints](https://img.shields.io/badge/type%20hints-100%25-brightgreen.svg)
6
+ ![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)
7
+
8
+ Production-grade Python infrastructure framework for building reliable CLI tools and services.
9
+
10
+ ## Scope
11
+
12
+ **Best for:** Production CLI tools, background services, systems-level Python applications.
13
+
14
+ **Not for:** Web APIs (use FastAPI), async-heavy applications, ORMs.
15
+
16
+ See [docs/README.md](docs/README.md) for full scope and philosophy.
17
+
18
+ ## Features
19
+
20
+ - **Logging** - Structured logging with custom levels, rotation, JSON output, and database handlers
21
+ - **Database** - PostgreSQL interface with connection pooling and query monitoring
22
+ - **App Framework** - Fluent builder API for CLI tools with lifecycle management
23
+ - **Configuration** - YAML config with environment variable overrides and path resolution
24
+ - **Time Utilities** - Scheduling, periodic execution, and duration formatting
25
+
26
+ ## Requirements
27
+
28
+ - Python 3.11+
29
+ - PostgreSQL 17 (optional, for database features)
30
+
31
+ ## Installation
32
+
33
+ ```bash
34
+ pip install appinfra
35
+ ```
36
+
37
+ Optional features:
38
+
39
+ ```bash
40
+ pip install appinfra[ui] # Rich console, interactive prompts
41
+ pip install appinfra[fastapi] # FastAPI integration
42
+ pip install appinfra[validation] # Pydantic config validation
43
+ pip install appinfra[hotreload] # Config file watching
44
+ ```
45
+
46
+ ## Documentation
47
+
48
+ Full documentation is available in [docs/README.md](docs/README.md), or via CLI:
49
+
50
+ ```bash
51
+ appinfra docs # Overview
52
+ appinfra docs list # List all guides and examples
53
+ appinfra docs show <topic> # Read a specific guide
54
+ ```
55
+
56
+ ## Highlights
57
+
58
+ ### App Framework
59
+
60
+ **AppBuilder for CLI tools** - Build production CLI applications with lifecycle management, config,
61
+ logging, and tools. Focused configurers provide clean separation of concerns. Config files are
62
+ resolved from `--etc-dir` (default: `./etc`):
63
+
64
+ ```python
65
+ from appinfra.app import AppBuilder
66
+
67
+ app = (
68
+ AppBuilder("myapp")
69
+ .with_description("Data processing tool")
70
+ .with_config_file("config.yaml") # Resolved from --etc-dir
71
+ .logging.with_level("info").with_location(1).done()
72
+ .tools.with_tool(ProcessorTool()).with_main(MainTool()).done()
73
+ .advanced.with_hook("startup", init_database).done()
74
+ .build()
75
+ )
76
+
77
+ app.run()
78
+ ```
79
+
80
+ **Fluent builder APIs** - All components use chainable builder patterns for clean, readable
81
+ configuration. No more scattered setup code or complex constructor arguments:
82
+
83
+ ```python
84
+ from appinfra.log import LoggingBuilder
85
+
86
+ logger = (
87
+ LoggingBuilder("my_app")
88
+ .with_level("info")
89
+ .with_format("%(asctime)s [%(levelname)s] %(message)s")
90
+ .console_handler(colors=True)
91
+ .file_handler("logs/app.log", rotate_mb=10)
92
+ .build()
93
+ )
94
+ ```
95
+
96
+ **Decorator-based CLI tools** - Build command-line tools with minimal boilerplate. Tools
97
+ automatically get logging, config access, and argument parsing:
98
+
99
+ ```python
100
+ from appinfra.app import AppBuilder
101
+
102
+ app = AppBuilder("mytool").build()
103
+
104
+ @app.tool(name="sync", help="Synchronize data")
105
+ @app.argument("--force", action="store_true", help="Force sync")
106
+ @app.argument("--limit", type=int, default=100)
107
+ def sync_tool(self):
108
+ self.lg.info(f"Syncing {self.args.limit} items")
109
+ if self.args.force:
110
+ self.lg.warning("Force mode enabled")
111
+ return 0
112
+ ```
113
+
114
+ **Nested subcommands** - Organize complex CLIs with hierarchical command structures using the
115
+ `@subtool` decorator:
116
+
117
+ ```python
118
+ app = AppBuilder("myapp").build()
119
+
120
+ @app.tool(name="db", help="Database operations")
121
+ def db_tool(self):
122
+ return self.run_subtool()
123
+
124
+ @db_tool.subtool(name="migrate", help="Run migrations")
125
+ @app.argument("--step", type=int, default=1)
126
+ def db_migrate(self):
127
+ self.lg.info(f"Migrating {self.args.step} steps...")
128
+
129
+ @db_tool.subtool(name="status")
130
+ def db_status(self):
131
+ self.lg.info("Database is healthy")
132
+
133
+ # Usage: myapp db migrate --step 3
134
+ # myapp db status
135
+ ```
136
+
137
+ **Multi-source version tracking** - Automatically detect version and git commit from PEP 610
138
+ metadata, build-time info, or git runtime. Integrates with AppBuilder for --version flag and
139
+ startup logging:
140
+
141
+ ```python
142
+ app = (
143
+ AppBuilder("myapp")
144
+ .version
145
+ .with_semver("1.0.0")
146
+ .with_build_info() # App's own commit from _build_info.py
147
+ .with_package("appinfra") # Track framework version
148
+ .done()
149
+ .build()
150
+ )
151
+ # --version shows: myapp 1.0.0 (abc123f) + tracked packages
152
+ # Startup logs commit hash, warns if repo has uncommitted changes
153
+ ```
154
+
155
+ ### Configuration
156
+
157
+ **YAML includes with security** - Build modular configurations with file includes, environment
158
+ variable validation, and automatic path resolution. Includes are protected against path traversal
159
+ and circular dependencies:
160
+
161
+ ```yaml
162
+ # config.yaml
163
+ !include "./base.yaml" # Document-level merge
164
+
165
+ database:
166
+ primary: !include "./db/primary.yaml" # Nested includes
167
+ credentials:
168
+ password: !secret ${DB_PASSWORD} # Validated env var reference
169
+
170
+ paths:
171
+ models: !path ../models # Resolved relative to this file
172
+ cache: !path ~/.cache/myapp # Expands ~
173
+ ```
174
+
175
+ **DotDict config access** - Access nested configuration with attribute syntax or dot-notation paths.
176
+ Automatic conversion of nested dicts, with safe traversal methods:
177
+
178
+ ```python
179
+ from appinfra.dot_dict import DotDict
180
+
181
+ config = DotDict({
182
+ "database": {"host": "localhost", "port": 5432},
183
+ "features": {"beta": True}
184
+ })
185
+
186
+ # Attribute-style access
187
+ print(config.database.host) # "localhost"
188
+ print(config.features.beta) # True
189
+
190
+ # Dot-notation path queries
191
+ if config.has("database.ssl.enabled"):
192
+ setup_ssl(config.get("database.ssl.cert"))
193
+ ```
194
+
195
+ **Hot-reload configuration** - Change log levels, feature flags, or any config value without
196
+ restarting your application. Uses content-based change detection to avoid spurious reloads:
197
+
198
+ ```python
199
+ from appinfra.config import ConfigWatcher
200
+
201
+ def on_config_change(new_config):
202
+ logger.info("Config updated, applying changes...")
203
+ apply_feature_flags(new_config.features)
204
+
205
+ watcher = ConfigWatcher(lg=logger, etc_dir="./etc")
206
+ watcher.configure("config.yaml", debounce_ms=500)
207
+ watcher.add_section_callback("features", on_config_change)
208
+ watcher.start()
209
+ ```
210
+
211
+ ### Logging & Security
212
+
213
+ **Topic-based log levels** - Control logging granularity with glob patterns. Set debug logging for
214
+ database queries while keeping network calls at warning level, all without touching application
215
+ code:
216
+
217
+ ```python
218
+ from appinfra.log import LogLevelManager
219
+
220
+ manager = LogLevelManager.get_instance()
221
+ manager.add_rule("/app/db/*", "debug") # All database loggers
222
+ manager.add_rule("/app/db/queries", "trace") # Even more detail for queries
223
+ manager.add_rule("/app/net/**", "warning") # Network and all children
224
+ manager.add_rule("/app/cache", "error") # Only errors from cache
225
+ ```
226
+
227
+ **Automatic secret masking** - Protect sensitive data in logs with pattern-based detection. Covers
228
+ 20+ secret formats including AWS keys, GitHub tokens, JWTs, and database URLs:
229
+
230
+ ```python
231
+ from appinfra.security import SecretMasker, SecretMaskingFilter
232
+
233
+ masker = SecretMasker()
234
+ masker.add_known_secret(os.environ["API_KEY"]) # Track known secrets
235
+
236
+ # Patterns auto-detect common formats
237
+ text = masker.mask("token=ghp_abc123secret") # "token=[MASKED]"
238
+ text = masker.mask("aws_secret=AKIA...") # "aws_secret=[MASKED]"
239
+
240
+ # Integrate with logging
241
+ handler.addFilter(SecretMaskingFilter(masker))
242
+ ```
243
+
244
+ **Lightweight observability hooks** - Event-based callbacks without heavy frameworks. Register
245
+ handlers for specific events or globally, with automatic timing in context:
246
+
247
+ ```python
248
+ from appinfra.observability import ObservabilityHooks, HookEvent, HookContext
249
+
250
+ hooks = ObservabilityHooks()
251
+
252
+ @hooks.on(HookEvent.QUERY_START)
253
+ def on_query(ctx: HookContext):
254
+ logger.debug(f"Query: {ctx.data.get('sql')}")
255
+
256
+ @hooks.on(HookEvent.QUERY_END)
257
+ def on_complete(ctx: HookContext):
258
+ logger.info(f"Completed in {ctx.duration:.3f}s")
259
+
260
+ # Trigger events with arbitrary data
261
+ hooks.trigger(HookEvent.QUERY_START, sql="SELECT * FROM users")
262
+ ```
263
+
264
+ ### Time & Scheduling
265
+
266
+ **Dual-mode ticker** - Run periodic tasks with scheduled intervals or continuous execution. Context
267
+ manager handles signals for graceful shutdown:
268
+
269
+ ```python
270
+ from appinfra.time import Ticker
271
+
272
+ # Scheduled mode: run every 30 seconds
273
+ with Ticker(logger, secs=30) as ticker:
274
+ for tick_count in ticker: # Stops on SIGTERM/SIGINT
275
+ run_health_check()
276
+ if tick_count >= 100:
277
+ break
278
+
279
+ # Continuous mode: run as fast as possible
280
+ for tick in Ticker(logger): # No secs = continuous
281
+ process_queue_item()
282
+ ```
283
+
284
+ **Human-readable durations** - Format seconds to readable strings and parse them back. Supports
285
+ microseconds to days, with precise mode for sub-millisecond accuracy:
286
+
287
+ ```python
288
+ from appinfra.time import delta_str, delta_to_secs
289
+
290
+ # Formatting
291
+ delta_str(3661.5) # "1h1m1s"
292
+ delta_str(0.000042) # "42μs"
293
+ delta_str(90061) # "1d1h1m1s"
294
+
295
+ # Parsing
296
+ delta_to_secs("2h30m") # 9000.0
297
+ delta_to_secs("1d12h") # 129600.0
298
+ delta_to_secs("500ms") # 0.5
299
+ ```
300
+
301
+ **Time-based task scheduler** - Execute tasks at specific times with daily, weekly, monthly, or
302
+ hourly periods. Generator-based iteration with signal handling for graceful shutdown:
303
+
304
+ ```python
305
+ from appinfra.time import Sched, Period
306
+
307
+ # Daily at 14:30
308
+ sched = Sched(logger, Period.DAILY, "14:30")
309
+
310
+ # Weekly on Monday at 09:00
311
+ sched = Sched(logger, Period.WEEKLY, "09:00", weekday=0)
312
+
313
+ for timestamp in sched.run(): # Yields after each scheduled time
314
+ generate_report()
315
+ ```
316
+
317
+ **ETA progress tracking** - Accurate time-to-completion estimates using EWMA-smoothed processing
318
+ rates. Handles variable update intervals without spike errors:
319
+
320
+ ```python
321
+ from appinfra.time import ETA, delta_str
322
+
323
+ eta = ETA(total=1000)
324
+ for i, item in enumerate(items):
325
+ process(item)
326
+ eta.update(i + 1)
327
+ remaining = eta.remaining_secs()
328
+ print(f"{eta.percent():.1f}% - {delta_str(remaining)} remaining")
329
+ ```
330
+
331
+ **Business day iteration** - Memory-efficient date range processing with weekend filtering. Iterates
332
+ from start date to today without materializing the full range:
333
+
334
+ ```python
335
+ from appinfra.time import iter_dates
336
+ import datetime
337
+
338
+ start = datetime.date(2025, 12, 1)
339
+ for date in iter_dates(start, skip_weekends=True):
340
+ process_business_day(date) # Mon-Fri only, up to today
341
+ ```
342
+
343
+ ### CLI & UI
344
+
345
+ **Testable CLI output** - Write testable CLI tools without mocking stdout. Swap output
346
+ implementations for production, testing, or silent operation:
347
+
348
+ ```python
349
+ from appinfra.cli.output import ConsoleOutput, BufferedOutput, NullOutput
350
+
351
+ def run_command(output=None):
352
+ output = output or ConsoleOutput()
353
+ output.write("Processing...")
354
+ output.write("Done!")
355
+
356
+ # In tests: capture output
357
+ buf = BufferedOutput()
358
+ run_command(output=buf)
359
+ assert "Done!" in buf.text
360
+ assert buf.lines == ["Processing...", "Done!"]
361
+ ```
362
+
363
+ **Interactive CLI prompts** - Smart prompts that work in TTY, non-interactive, and CI environments.
364
+ Auto-detects available libraries with graceful fallbacks:
365
+
366
+ ```python
367
+ from appinfra.ui import confirm, select, text
368
+
369
+ env = select("Environment:", ["dev", "staging", "prod"])
370
+ name = text("Project name:", validate=lambda x: len(x) > 0)
371
+
372
+ if confirm(f"Deploy {name} to {env}?"):
373
+ deploy()
374
+ ```
375
+
376
+ **Progress with logging coordination** - Rich spinner or progress bar that pauses for log output.
377
+ Falls back to plain logging on non-TTY:
378
+
379
+ ```python
380
+ from appinfra.ui import ProgressLogger
381
+
382
+ with ProgressLogger(logger, "Processing...", total=100) as pl:
383
+ for item in items:
384
+ result = process(item)
385
+ pl.log(f"Processed {item.name}") # Pauses spinner, logs, resumes
386
+ pl.update(advance=1)
387
+ ```
388
+
389
+ ### Database
390
+
391
+ **Database auto-reconnection** - Automatic retry with exponential backoff on transient failures.
392
+ Configured via YAML, transparent to application code:
393
+
394
+ ```yaml
395
+ # etc/config.yaml
396
+ database:
397
+ url: postgresql://...
398
+ auto_reconnect: true
399
+ max_retries: 3 # Attempts before raising
400
+ retry_delay: 0.5 # Initial delay, doubles each retry
401
+ ```
402
+
403
+ **Read-only database mode** - Transaction-level enforcement preventing accidental writes. Validates
404
+ configuration to catch conflicts early:
405
+
406
+ ```python
407
+ pg = PG(config, readonly=True)
408
+ with pg.session() as session:
409
+ # SELECT queries work normally
410
+ # INSERT/UPDATE/DELETE raise errors at transaction level
411
+ ```
412
+
413
+ ### Server
414
+
415
+ **FastAPI subprocess isolation** - Run FastAPI in a subprocess with queue-based IPC. Main process
416
+ stays responsive while workers handle requests, with automatic restart on failure:
417
+
418
+ ```python
419
+ from appinfra.app.fastapi import FastAPIBuilder
420
+
421
+ server = (
422
+ FastAPIBuilder("api")
423
+ .with_config(config)
424
+ .with_port(8000)
425
+ .with_subprocess_mode(
426
+ request_queue=request_q,
427
+ response_queue=response_q,
428
+ auto_restart=True
429
+ )
430
+ .build()
431
+ )
432
+
433
+ server.start() # Non-blocking, runs in subprocess
434
+ ```
435
+
436
+ ## Completeness
437
+
438
+ Built for production with comprehensive validation:
439
+
440
+ - **4,000+ tests** across unit, integration, e2e, security, and performance categories
441
+ - **95% code coverage** on 11,000+ statements
442
+ - **100% type hints** verified by mypy strict mode
443
+ - **Security tests** for YAML injection, path traversal, ReDoS, and secret exposure
444
+
445
+ ## Contributing
446
+
447
+ See the [Contributing Guide](docs/guides/contributing.md) for development setup and guidelines.
448
+
449
+ ## Links
450
+
451
+ - [Changelog](CHANGELOG.md)
452
+ - [Security Policy](SECURITY.md)
453
+ - [API Stability](docs/guides/api-stability.md)
454
+
455
+ ## License
456
+
457
+ Apache License 2.0 - see [LICENSE](LICENSE) for details.