meerschaum 2.2.0rc1__tar.gz → 2.2.0rc3__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 (251) hide show
  1. {meerschaum-2.2.0rc1/meerschaum.egg-info → meerschaum-2.2.0rc3}/PKG-INFO +19 -21
  2. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/__main__.py +1 -1
  3. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/actions/show.py +68 -43
  4. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/api/__init__.py +16 -11
  5. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/api/dash/callbacks/dashboard.py +2 -7
  6. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/api/dash/pipes.py +33 -9
  7. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/api/dash/plugins.py +25 -9
  8. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/api/resources/templates/termpage.html +3 -0
  9. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/api/routes/_login.py +5 -4
  10. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/api/routes/_plugins.py +6 -3
  11. meerschaum-2.2.0rc3/meerschaum/config/_dash.py +11 -0
  12. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/config/_default.py +3 -1
  13. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/config/_jobs.py +10 -4
  14. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/config/_paths.py +2 -0
  15. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/config/_sync.py +2 -3
  16. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/config/_version.py +1 -1
  17. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/config/stack/__init__.py +6 -6
  18. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/config/stack/grafana/__init__.py +1 -1
  19. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/config/static/__init__.py +4 -1
  20. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/connectors/__init__.py +2 -0
  21. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/connectors/sql/SQLConnector.py +4 -2
  22. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/connectors/sql/_create_engine.py +4 -4
  23. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/connectors/sql/_instance.py +3 -1
  24. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/connectors/sql/_pipes.py +53 -38
  25. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/connectors/sql/_plugins.py +0 -2
  26. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/connectors/sql/_sql.py +7 -9
  27. meerschaum-2.2.0rc3/meerschaum/core/User/_User.py +224 -0
  28. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/core/User/__init__.py +1 -1
  29. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/plugins/_Plugin.py +1 -1
  30. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/plugins/__init__.py +23 -1
  31. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/utils/daemon/Daemon.py +38 -12
  32. meerschaum-2.2.0rc3/meerschaum/utils/daemon/FileDescriptorInterceptor.py +140 -0
  33. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/utils/daemon/RotatingFile.py +82 -59
  34. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/utils/daemon/__init__.py +3 -0
  35. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/utils/packages/__init__.py +10 -4
  36. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/utils/packages/_packages.py +7 -8
  37. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/utils/process.py +13 -10
  38. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/utils/schedule.py +15 -1
  39. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/utils/threading.py +1 -0
  40. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3/meerschaum.egg-info}/PKG-INFO +19 -21
  41. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum.egg-info/SOURCES.txt +1 -0
  42. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum.egg-info/requires.txt +18 -20
  43. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/tests/test_sync.py +2 -1
  44. meerschaum-2.2.0rc1/meerschaum/core/User/_User.py +0 -82
  45. meerschaum-2.2.0rc1/meerschaum/utils/daemon/FileDescriptorInterceptor.py +0 -60
  46. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/LICENSE +0 -0
  47. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/NOTICE +0 -0
  48. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/README.md +0 -0
  49. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/__init__.py +0 -0
  50. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/_internal/__init__.py +0 -0
  51. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/_internal/arguments/__init__.py +0 -0
  52. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/_internal/arguments/_parse_arguments.py +0 -0
  53. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/_internal/arguments/_parser.py +0 -0
  54. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/_internal/docs/__init__.py +0 -0
  55. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/_internal/docs/index.py +0 -0
  56. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/_internal/entry.py +0 -0
  57. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/_internal/gui/__init__.py +0 -0
  58. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/_internal/gui/app/__init__.py +0 -0
  59. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/_internal/gui/app/_windows.py +0 -0
  60. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/_internal/gui/app/actions.py +0 -0
  61. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/_internal/gui/app/pipes.py +0 -0
  62. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/_internal/shell/Shell.py +0 -0
  63. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/_internal/shell/ShellCompleter.py +0 -0
  64. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/_internal/shell/ValidAutoSuggest.py +0 -0
  65. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/_internal/shell/__init__.py +0 -0
  66. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/_internal/shell/resources/__init__.py +0 -0
  67. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/_internal/term/TermPageHandler.py +0 -0
  68. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/_internal/term/__init__.py +0 -0
  69. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/_internal/term/tools.py +0 -0
  70. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/actions/__init__.py +0 -0
  71. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/actions/api.py +0 -0
  72. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/actions/bootstrap.py +0 -0
  73. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/actions/clear.py +0 -0
  74. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/actions/copy.py +0 -0
  75. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/actions/deduplicate.py +0 -0
  76. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/actions/delete.py +0 -0
  77. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/actions/drop.py +0 -0
  78. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/actions/edit.py +0 -0
  79. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/actions/install.py +0 -0
  80. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/actions/login.py +0 -0
  81. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/actions/os.py +0 -0
  82. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/actions/pause.py +0 -0
  83. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/actions/python.py +0 -0
  84. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/actions/register.py +0 -0
  85. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/actions/reload.py +0 -0
  86. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/actions/setup.py +0 -0
  87. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/actions/sh.py +0 -0
  88. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/actions/sql.py +0 -0
  89. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/actions/stack.py +0 -0
  90. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/actions/start.py +0 -0
  91. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/actions/stop.py +0 -0
  92. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/actions/sync.py +0 -0
  93. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/actions/tag.py +0 -0
  94. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/actions/uninstall.py +0 -0
  95. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/actions/upgrade.py +0 -0
  96. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/actions/verify.py +0 -0
  97. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/api/_chain.py +0 -0
  98. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/api/_events.py +0 -0
  99. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/api/_oauth2.py +0 -0
  100. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/api/_websockets.py +0 -0
  101. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/api/dash/__init__.py +0 -0
  102. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/api/dash/actions.py +0 -0
  103. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/api/dash/assets/__init__.py +0 -0
  104. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/api/dash/assets/ansi_up.js +0 -0
  105. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/api/dash/assets/banner_1920x320.png +0 -0
  106. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/api/dash/assets/favicon.ico +0 -0
  107. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/api/dash/assets/logo_48x48.png +0 -0
  108. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/api/dash/assets/logo_500x500.png +0 -0
  109. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/api/dash/callbacks/__init__.py +0 -0
  110. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/api/dash/callbacks/jobs.py +0 -0
  111. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/api/dash/callbacks/login.py +0 -0
  112. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/api/dash/callbacks/plugins.py +0 -0
  113. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/api/dash/callbacks/register.py +0 -0
  114. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/api/dash/components.py +0 -0
  115. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/api/dash/connectors.py +0 -0
  116. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/api/dash/graphs.py +0 -0
  117. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/api/dash/jobs.py +0 -0
  118. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/api/dash/keys.py +0 -0
  119. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/api/dash/pages/__init__.py +0 -0
  120. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/api/dash/pages/dashboard.py +0 -0
  121. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/api/dash/pages/error.py +0 -0
  122. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/api/dash/pages/login.py +0 -0
  123. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/api/dash/pages/plugins.py +0 -0
  124. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/api/dash/pages/register.py +0 -0
  125. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/api/dash/sync.py +0 -0
  126. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/api/dash/users.py +0 -0
  127. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/api/dash/websockets.py +0 -0
  128. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/api/dash/webterm.py +0 -0
  129. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/api/models/__init__.py +0 -0
  130. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/api/models/_interfaces.py +0 -0
  131. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/api/models/_locations.py +0 -0
  132. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/api/models/_metrics.py +0 -0
  133. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/api/models/_pipes.py +0 -0
  134. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/api/resources/__init__.py +0 -0
  135. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/api/resources/static/__init__.py +0 -0
  136. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/api/resources/static/css/__init__.py +0 -0
  137. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/api/resources/static/css/bootstrap.min.css +0 -0
  138. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/api/resources/static/css/dash.css +0 -0
  139. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/api/resources/static/css/dbc_dark.css +0 -0
  140. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/api/resources/static/css/styles.css +0 -0
  141. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/api/resources/static/css/xterm.css +0 -0
  142. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/api/resources/static/ico/__init__.py +0 -0
  143. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/api/resources/static/ico/logo.ico +0 -0
  144. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/api/resources/static/js/__init__.py +0 -0
  145. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/api/resources/static/js/action_button.js +0 -0
  146. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/api/resources/static/js/main.js +0 -0
  147. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/api/resources/static/js/terminado.js +0 -0
  148. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/api/resources/static/js/xterm.js +0 -0
  149. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/api/resources/static/png/__init__.py +0 -0
  150. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/api/resources/templates/__init__.py +0 -0
  151. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/api/resources/templates/index.html +0 -0
  152. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/api/resources/templates/old_index.html +0 -0
  153. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/api/resources/templates/secret.html +0 -0
  154. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/api/routes/__init__.py +0 -0
  155. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/api/routes/_actions.py +0 -0
  156. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/api/routes/_connectors.py +0 -0
  157. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/api/routes/_index.py +0 -0
  158. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/api/routes/_misc.py +0 -0
  159. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/api/routes/_pipes.py +0 -0
  160. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/api/routes/_users.py +0 -0
  161. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/api/routes/_version.py +0 -0
  162. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/api/routes/_webterm.py +0 -0
  163. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/api/tables/__init__.py +0 -0
  164. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/config/__init__.py +0 -0
  165. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/config/_edit.py +0 -0
  166. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/config/_environment.py +0 -0
  167. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/config/_formatting.py +0 -0
  168. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/config/_patch.py +0 -0
  169. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/config/_preprocess.py +0 -0
  170. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/config/_read_config.py +0 -0
  171. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/config/_shell.py +0 -0
  172. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/config/resources/__init__.py +0 -0
  173. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/config/stack/mosquitto/__init__.py +0 -0
  174. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/config/stack/mosquitto/resources/__init__.py +0 -0
  175. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/config/stack/resources/__init__.py +0 -0
  176. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/connectors/Connector.py +0 -0
  177. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/connectors/api/APIConnector.py +0 -0
  178. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/connectors/api/__init__.py +0 -0
  179. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/connectors/api/_actions.py +0 -0
  180. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/connectors/api/_fetch.py +0 -0
  181. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/connectors/api/_login.py +0 -0
  182. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/connectors/api/_misc.py +0 -0
  183. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/connectors/api/_pipes.py +0 -0
  184. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/connectors/api/_plugins.py +0 -0
  185. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/connectors/api/_request.py +0 -0
  186. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/connectors/api/_uri.py +0 -0
  187. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/connectors/api/_users.py +0 -0
  188. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/connectors/parse.py +0 -0
  189. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/connectors/plugin/PluginConnector.py +0 -0
  190. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/connectors/plugin/__init__.py +0 -0
  191. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/connectors/poll.py +0 -0
  192. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/connectors/sql/__init__.py +0 -0
  193. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/connectors/sql/_cli.py +0 -0
  194. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/connectors/sql/_fetch.py +0 -0
  195. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/connectors/sql/_uri.py +0 -0
  196. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/connectors/sql/_users.py +0 -0
  197. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/connectors/sql/tables/__init__.py +0 -0
  198. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/connectors/sql/tables/types.py +0 -0
  199. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/connectors/sql/tools.py +0 -0
  200. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/core/Pipe/__init__.py +0 -0
  201. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/core/Pipe/_attributes.py +0 -0
  202. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/core/Pipe/_bootstrap.py +0 -0
  203. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/core/Pipe/_clear.py +0 -0
  204. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/core/Pipe/_data.py +0 -0
  205. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/core/Pipe/_deduplicate.py +0 -0
  206. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/core/Pipe/_delete.py +0 -0
  207. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/core/Pipe/_drop.py +0 -0
  208. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/core/Pipe/_dtypes.py +0 -0
  209. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/core/Pipe/_edit.py +0 -0
  210. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/core/Pipe/_fetch.py +0 -0
  211. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/core/Pipe/_register.py +0 -0
  212. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/core/Pipe/_show.py +0 -0
  213. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/core/Pipe/_sync.py +0 -0
  214. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/core/Pipe/_verify.py +0 -0
  215. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/core/Plugin/__init__.py +0 -0
  216. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/core/__init__.py +0 -0
  217. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/utils/__init__.py +0 -0
  218. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/utils/_get_pipes.py +0 -0
  219. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/utils/daemon/_names.py +0 -0
  220. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/utils/dataframe.py +0 -0
  221. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/utils/debug.py +0 -0
  222. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/utils/dtypes/__init__.py +0 -0
  223. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/utils/dtypes/sql.py +0 -0
  224. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/utils/formatting/__init__.py +0 -0
  225. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/utils/formatting/_jobs.py +0 -0
  226. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/utils/formatting/_pipes.py +0 -0
  227. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/utils/formatting/_pprint.py +0 -0
  228. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/utils/formatting/_shell.py +0 -0
  229. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/utils/interactive.py +0 -0
  230. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/utils/misc.py +0 -0
  231. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/utils/networking.py +0 -0
  232. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/utils/packages/lazy_loader.py +0 -0
  233. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/utils/pool.py +0 -0
  234. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/utils/prompt.py +0 -0
  235. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/utils/sql.py +0 -0
  236. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/utils/typing.py +0 -0
  237. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/utils/venv/_Venv.py +0 -0
  238. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/utils/venv/__init__.py +0 -0
  239. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/utils/warnings.py +0 -0
  240. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum/utils/yaml.py +0 -0
  241. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum.egg-info/dependency_links.txt +0 -0
  242. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum.egg-info/entry_points.txt +0 -0
  243. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum.egg-info/top_level.txt +0 -0
  244. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/meerschaum.egg-info/zip-safe +0 -0
  245. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/setup.cfg +0 -0
  246. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/setup.py +0 -0
  247. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/tests/test_deduplicate.py +0 -0
  248. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/tests/test_pipes_dtypes.py +0 -0
  249. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/tests/test_sql.py +0 -0
  250. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/tests/test_users.py +0 -0
  251. {meerschaum-2.2.0rc1 → meerschaum-2.2.0rc3}/tests/test_verify.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: meerschaum
3
- Version: 2.2.0rc1
3
+ Version: 2.2.0rc3
4
4
  Summary: Sync Time-Series Pipes with Meerschaum
5
5
  Home-page: https://meerschaum.io
6
6
  Author: Bennett Meares
@@ -71,7 +71,7 @@ Requires-Dist: psycopg[binary]>=3.1.18; extra == "drivers"
71
71
  Requires-Dist: PyMySQL>=0.9.0; extra == "drivers"
72
72
  Requires-Dist: aiomysql>=0.0.21; extra == "drivers"
73
73
  Requires-Dist: sqlalchemy-cockroachdb>=2.0.0; extra == "drivers"
74
- Requires-Dist: duckdb>=0.9.0; extra == "drivers"
74
+ Requires-Dist: duckdb<0.10.0; extra == "drivers"
75
75
  Requires-Dist: duckdb-engine>=0.9.2; extra == "drivers"
76
76
  Provides-Extra: drivers
77
77
  Requires-Dist: pyodbc>=4.0.30; extra == "drivers"
@@ -120,8 +120,8 @@ Requires-Dist: importlib-metadata>=4.12.0; extra == "extras"
120
120
  Provides-Extra: sql
121
121
  Requires-Dist: numpy>=1.18.5; extra == "sql"
122
122
  Requires-Dist: pandas[parquet]>=2.0.1; extra == "sql"
123
- Requires-Dist: pyarrow>=7.0.0; extra == "sql"
124
- Requires-Dist: dask>=2023.5.0; extra == "sql"
123
+ Requires-Dist: pyarrow>=16.1.0; extra == "sql"
124
+ Requires-Dist: dask[dataframe]>=2024.5.1; extra == "sql"
125
125
  Requires-Dist: pytz; extra == "sql"
126
126
  Requires-Dist: joblib>=0.17.0; extra == "sql"
127
127
  Requires-Dist: SQLAlchemy>=2.0.5; extra == "sql"
@@ -133,7 +133,7 @@ Requires-Dist: psycopg[binary]>=3.1.18; extra == "sql"
133
133
  Requires-Dist: PyMySQL>=0.9.0; extra == "sql"
134
134
  Requires-Dist: aiomysql>=0.0.21; extra == "sql"
135
135
  Requires-Dist: sqlalchemy-cockroachdb>=2.0.0; extra == "sql"
136
- Requires-Dist: duckdb>=0.9.0; extra == "sql"
136
+ Requires-Dist: duckdb<0.10.0; extra == "sql"
137
137
  Requires-Dist: duckdb-engine>=0.9.2; extra == "sql"
138
138
  Requires-Dist: wheel>=0.34.2; extra == "sql"
139
139
  Requires-Dist: setuptools>=63.3.0; extra == "sql"
@@ -167,19 +167,18 @@ Requires-Dist: dash-daq>=0.5.0; extra == "dash"
167
167
  Requires-Dist: terminado>=0.12.1; extra == "dash"
168
168
  Requires-Dist: tornado>=6.1.0; extra == "dash"
169
169
  Provides-Extra: api
170
- Requires-Dist: uvicorn[standard]>=0.22.0; extra == "api"
171
- Requires-Dist: gunicorn>=20.1.0; extra == "api"
170
+ Requires-Dist: uvicorn[standard]>=0.29.0; extra == "api"
171
+ Requires-Dist: gunicorn>=22.0.0; extra == "api"
172
172
  Requires-Dist: python-dotenv>=0.20.0; extra == "api"
173
173
  Requires-Dist: websockets>=11.0.3; extra == "api"
174
- Requires-Dist: fastapi>=0.100.0; extra == "api"
175
- Requires-Dist: passlib>=1.7.4; extra == "api"
174
+ Requires-Dist: fastapi>=0.111.0; extra == "api"
176
175
  Requires-Dist: fastapi-login>=1.7.2; extra == "api"
177
- Requires-Dist: python-multipart>=0.0.5; extra == "api"
176
+ Requires-Dist: python-multipart>=0.0.9; extra == "api"
178
177
  Requires-Dist: httpx>=0.24.1; extra == "api"
179
178
  Requires-Dist: numpy>=1.18.5; extra == "api"
180
179
  Requires-Dist: pandas[parquet]>=2.0.1; extra == "api"
181
- Requires-Dist: pyarrow>=7.0.0; extra == "api"
182
- Requires-Dist: dask>=2023.5.0; extra == "api"
180
+ Requires-Dist: pyarrow>=16.1.0; extra == "api"
181
+ Requires-Dist: dask[dataframe]>=2024.5.1; extra == "api"
183
182
  Requires-Dist: pytz; extra == "api"
184
183
  Requires-Dist: joblib>=0.17.0; extra == "api"
185
184
  Requires-Dist: SQLAlchemy>=2.0.5; extra == "api"
@@ -191,7 +190,7 @@ Requires-Dist: psycopg[binary]>=3.1.18; extra == "api"
191
190
  Requires-Dist: PyMySQL>=0.9.0; extra == "api"
192
191
  Requires-Dist: aiomysql>=0.0.21; extra == "api"
193
192
  Requires-Dist: sqlalchemy-cockroachdb>=2.0.0; extra == "api"
194
- Requires-Dist: duckdb>=0.9.0; extra == "api"
193
+ Requires-Dist: duckdb<0.10.0; extra == "api"
195
194
  Requires-Dist: duckdb-engine>=0.9.2; extra == "api"
196
195
  Requires-Dist: wheel>=0.34.2; extra == "api"
197
196
  Requires-Dist: setuptools>=63.3.0; extra == "api"
@@ -267,15 +266,15 @@ Requires-Dist: psycopg[binary]>=3.1.18; extra == "full"
267
266
  Requires-Dist: PyMySQL>=0.9.0; extra == "full"
268
267
  Requires-Dist: aiomysql>=0.0.21; extra == "full"
269
268
  Requires-Dist: sqlalchemy-cockroachdb>=2.0.0; extra == "full"
270
- Requires-Dist: duckdb>=0.9.0; extra == "full"
269
+ Requires-Dist: duckdb<0.10.0; extra == "full"
271
270
  Requires-Dist: duckdb-engine>=0.9.2; extra == "full"
272
271
  Requires-Dist: toga>=0.3.0-dev29; extra == "full"
273
272
  Requires-Dist: pywebview>=3.6.3; extra == "full"
274
273
  Requires-Dist: pycparser>=2.21.0; extra == "full"
275
274
  Requires-Dist: numpy>=1.18.5; extra == "full"
276
275
  Requires-Dist: pandas[parquet]>=2.0.1; extra == "full"
277
- Requires-Dist: pyarrow>=7.0.0; extra == "full"
278
- Requires-Dist: dask>=2023.5.0; extra == "full"
276
+ Requires-Dist: pyarrow>=16.1.0; extra == "full"
277
+ Requires-Dist: dask[dataframe]>=2024.5.1; extra == "full"
279
278
  Requires-Dist: pytz; extra == "full"
280
279
  Requires-Dist: joblib>=0.17.0; extra == "full"
281
280
  Requires-Dist: SQLAlchemy>=2.0.5; extra == "full"
@@ -290,14 +289,13 @@ Requires-Dist: dash-extensions>=1.0.4; extra == "full"
290
289
  Requires-Dist: dash-daq>=0.5.0; extra == "full"
291
290
  Requires-Dist: terminado>=0.12.1; extra == "full"
292
291
  Requires-Dist: tornado>=6.1.0; extra == "full"
293
- Requires-Dist: uvicorn[standard]>=0.22.0; extra == "full"
294
- Requires-Dist: gunicorn>=20.1.0; extra == "full"
292
+ Requires-Dist: uvicorn[standard]>=0.29.0; extra == "full"
293
+ Requires-Dist: gunicorn>=22.0.0; extra == "full"
295
294
  Requires-Dist: python-dotenv>=0.20.0; extra == "full"
296
295
  Requires-Dist: websockets>=11.0.3; extra == "full"
297
- Requires-Dist: fastapi>=0.100.0; extra == "full"
298
- Requires-Dist: passlib>=1.7.4; extra == "full"
296
+ Requires-Dist: fastapi>=0.111.0; extra == "full"
299
297
  Requires-Dist: fastapi-login>=1.7.2; extra == "full"
300
- Requires-Dist: python-multipart>=0.0.5; extra == "full"
298
+ Requires-Dist: python-multipart>=0.0.9; extra == "full"
301
299
  Requires-Dist: httpx>=0.24.1; extra == "full"
302
300
 
303
301
  <img src="https://meerschaum.io/assets/banner_1920x320.png" alt="Meerschaum banner" style="width: 100%"/>
@@ -4,7 +4,7 @@
4
4
  # vim:fenc=utf-8
5
5
 
6
6
  """
7
- Copyright 2021 Bennett Meares
7
+ Copyright 2024 Bennett Meares
8
8
 
9
9
  Licensed under the Apache License, Version 2.0 (the "License");
10
10
  you may not use this file except in compliance with the License.
@@ -578,7 +578,7 @@ def _show_logs(
578
578
  `show logs myjob myotherjob`
579
579
  """
580
580
  import os, pathlib, random, asyncio
581
- from datetime import datetime
581
+ from datetime import datetime, timezone
582
582
  from meerschaum.utils.packages import attempt_import, import_rich
583
583
  from meerschaum.utils.daemon import get_filtered_daemons, Daemon
584
584
  from meerschaum.utils.warnings import warn, info
@@ -589,81 +589,106 @@ def _show_logs(
589
589
  if not ANSI:
590
590
  info = print
591
591
  colors = get_config('jobs', 'logs', 'colors')
592
+ timestamp_format = get_config('jobs', 'logs', 'timestamp_format')
593
+ follow_timestamp_format = get_config('jobs', 'logs', 'follow_timestamp_format')
592
594
  daemons = get_filtered_daemons(action)
593
-
594
- def _build_buffer_spaces(daemons) -> Dict[str, str]:
595
- _max_len_id = max([len(d.daemon_id) for d in daemons]) if daemons else 0
596
- _buffer_len = max(get_config('jobs', 'logs', 'min_buffer_len'), _max_len_id + 2)
595
+ now = datetime.now(timezone.utc)
596
+ now_str = now.strftime(timestamp_format)
597
+ now_follow_str = now.strftime(follow_timestamp_format)
598
+
599
+ def build_buffer_spaces(daemons) -> Dict[str, str]:
600
+ max_len_id = max(len(d.daemon_id) for d in daemons) if daemons else 0
601
+ buffer_len = max(
602
+ get_config('jobs', 'logs', 'min_buffer_len'),
603
+ max_len_id
604
+ )
597
605
  return {
598
- d.daemon_id: ''.join([' ' for i in range(_buffer_len - len(d.daemon_id))])
606
+ d.daemon_id: ''.join([' ' for i in range(buffer_len - len(d.daemon_id))])
599
607
  for d in daemons
600
608
  }
601
609
 
602
- def _build_job_colors(daemons, _old_job_colors = None) -> Dict[str, str]:
610
+ def build_job_colors(daemons, _old_job_colors = None) -> Dict[str, str]:
603
611
  return {d.daemon_id: colors[i % len(colors)] for i, d in enumerate(daemons)}
604
612
 
605
- _buffer_spaces = _build_buffer_spaces(daemons)
606
- _job_colors = _build_job_colors(daemons)
613
+ buffer_spaces = build_buffer_spaces(daemons)
614
+ job_colors = build_job_colors(daemons)
607
615
 
608
- def _get_buffer_spaces(daemon_id):
609
- nonlocal _buffer_spaces, daemons
610
- if daemon_id not in _buffer_spaces:
616
+ def get_buffer_spaces(daemon_id):
617
+ nonlocal buffer_spaces, daemons
618
+ if daemon_id not in buffer_spaces:
611
619
  d = Daemon(daemon_id=daemon_id)
612
620
  if d not in daemons:
613
621
  daemons = get_filtered_daemons(action)
614
- _buffer_spaces = _build_buffer_spaces(daemons)
615
- return _buffer_spaces[daemon_id]
622
+ buffer_spaces = build_buffer_spaces(daemons)
623
+ return buffer_spaces[daemon_id] or ' '
616
624
 
617
- def _get_job_colors(daemon_id):
618
- nonlocal _job_colors, daemons
619
- if daemon_id not in _job_colors:
625
+ def get_job_colors(daemon_id):
626
+ nonlocal job_colors, daemons
627
+ if daemon_id not in job_colors:
620
628
  d = Daemon(daemon_id=daemon_id)
621
629
  if d not in daemons:
622
630
  daemons = get_filtered_daemons(action)
623
- _job_colors = _build_job_colors(daemons)
624
- return _job_colors[daemon_id]
631
+ job_colors = build_job_colors(daemons)
632
+ return job_colors[daemon_id]
625
633
 
626
- def _follow_pretty_print():
634
+ def follow_pretty_print():
627
635
  watchfiles = attempt_import('watchfiles')
628
636
  rich = import_rich()
629
637
  rich_text = attempt_import('rich.text')
630
- _watch_daemon_ids = {d.daemon_id: d for d in daemons}
638
+ watch_daemon_ids = {d.daemon_id: d for d in daemons}
631
639
  info("Watching log files...")
632
640
 
633
- def _print_job_line(daemon, line):
634
- date_prefix_str = line[:len('YYYY-MM-DD HH:mm')]
641
+ previous_line_timestamp = None
642
+ def print_job_line(daemon, line):
643
+ nonlocal previous_line_timestamp
644
+ date_prefix_str = line[:len(now_str)]
635
645
  try:
636
- line_timestamp = datetime.fromisoformat(date_prefix_str)
646
+ line_timestamp = datetime.strptime(date_prefix_str, timestamp_format)
647
+ previous_line_timestamp = line_timestamp
637
648
  except Exception as e:
638
649
  line_timestamp = None
639
650
  if line_timestamp:
640
- line = line[len('YYYY-MM-DD HH:mm | '):]
641
- if len(line) == 0:
651
+ line = line[(len(now_str) + 3):]
652
+ else:
653
+ line_timestamp = previous_line_timestamp
654
+
655
+ if len(line) == 0 or line == '\n':
642
656
  return
657
+
643
658
  text = rich_text.Text(daemon.daemon_id)
644
- text.append(
645
- _get_buffer_spaces(daemon.daemon_id) + '| '
646
- + (line[:-1] if line[-1] == '\n' else line)
659
+ line_prefix = (
660
+ get_buffer_spaces(daemon.daemon_id)
661
+ + (line_timestamp.strftime(follow_timestamp_format) if line_timestamp else '')
662
+ + ' | '
647
663
  )
664
+ text.append(line_prefix + (line[:-1] if line[-1] == '\n' else line))
648
665
  if ANSI:
649
666
  text.stylize(
650
- _get_job_colors(daemon.daemon_id),
667
+ get_job_colors(daemon.daemon_id),
651
668
  0,
652
- len(daemon.daemon_id) + len(_get_buffer_spaces(daemon.daemon_id)) + 1
669
+ len(daemon.daemon_id) + len(line_prefix)
653
670
  )
654
671
  get_console().print(text)
655
672
 
656
673
 
657
- def _print_log_lines(daemon):
674
+ def print_log_lines(daemon):
658
675
  for line in daemon.readlines():
659
- _print_job_line(daemon, line)
676
+ print_job_line(daemon, line)
660
677
 
661
- def _seek_back_offset(d) -> bool:
678
+ def seek_back_offset(d) -> bool:
662
679
  if d.log_offset_path.exists():
663
680
  d.log_offset_path.unlink()
664
681
 
665
682
  latest_subfile_path = d.rotating_log.get_latest_subfile_path()
666
683
  latest_subfile_index = d.rotating_log.get_latest_subfile_index()
684
+
685
+ ### Sometimes the latest file is empty.
686
+ if os.stat(latest_subfile_path).st_size == 0 and latest_subfile_index > 0:
687
+ latest_subfile_index -= 1
688
+ latest_subfile_path = d.rotating_log.get_subfile_path_from_index(
689
+ latest_subfile_index
690
+ )
691
+
667
692
  with open(latest_subfile_path, 'r', encoding='utf-8') as f:
668
693
  latest_lines = f.readlines()
669
694
 
@@ -683,11 +708,11 @@ def _show_logs(
683
708
  for d in daemons
684
709
  }
685
710
  for d in daemons:
686
- _seek_back_offset(d)
687
- _print_log_lines(d)
711
+ seek_back_offset(d)
712
+ print_log_lines(d)
688
713
 
689
714
  _quit = False
690
- def _watch_logs():
715
+ def watch_logs():
691
716
  for changes in watchfiles.watch(LOGS_RESOURCES_PATH):
692
717
  if _quit:
693
718
  return
@@ -699,7 +724,7 @@ def _show_logs(
699
724
  if not file_path.exists():
700
725
  continue
701
726
  daemon_id = file_path.name.split('.log')[0]
702
- if daemon_id not in _watch_daemon_ids and action:
727
+ if daemon_id not in watch_daemon_ids and action:
703
728
  continue
704
729
  try:
705
730
  daemon = Daemon(daemon_id=daemon_id)
@@ -708,21 +733,21 @@ def _show_logs(
708
733
  warn(f"Seeing new logs for non-existent job '{daemon_id}'.", stack=False)
709
734
 
710
735
  if daemon is not None:
711
- _print_log_lines(daemon)
736
+ print_log_lines(daemon)
712
737
 
713
738
  try:
714
- _watch_logs()
739
+ watch_logs()
715
740
  except KeyboardInterrupt as ki:
716
741
  _quit = True
717
742
 
718
- def _print_nopretty_log_text():
743
+ def print_nopretty_log_text():
719
744
  for d in daemons:
720
745
  log_text = d.log_text
721
746
  print(d.daemon_id)
722
747
  print(log_text)
723
748
 
724
- _print_log_text = _follow_pretty_print if not nopretty else _print_nopretty_log_text
725
- _print_log_text()
749
+ print_log_text = follow_pretty_print if not nopretty else print_nopretty_log_text
750
+ print_log_text()
726
751
 
727
752
  return True, "Success"
728
753
 
@@ -30,21 +30,26 @@ _locks = {'pipes': RLock(), 'connector': RLock(), 'uvicorn_config': RLock()}
30
30
  CHECK_UPDATE = os.environ.get(STATIC_CONFIG['environment']['runtime'], None) != 'docker'
31
31
 
32
32
  endpoints = STATIC_CONFIG['api']['endpoints']
33
- aiofiles = attempt_import('aiofiles', lazy=False, check_update=CHECK_UPDATE)
33
+
34
+ (
35
+ fastapi,
36
+ aiofiles,
37
+ starlette_responses,
38
+ multipart,
39
+ packaging_version,
40
+ ) = attempt_import(
41
+ 'fastapi',
42
+ 'aiofiles',
43
+ 'starlette.responses',
44
+ 'multipart',
45
+ 'packaging.version',
46
+ lazy = False,
47
+ check_update = CHECK_UPDATE,
48
+ )
34
49
  typing_extensions = attempt_import(
35
50
  'typing_extensions', lazy=False, check_update=CHECK_UPDATE,
36
51
  venv = None,
37
52
  )
38
- pydantic_dataclasses = attempt_import(
39
- 'pydantic.dataclasses', lazy=False, check_update=CHECK_UPDATE,
40
- )
41
- fastapi = attempt_import('fastapi', lazy=False, check_update=CHECK_UPDATE)
42
- starlette_reponses = attempt_import(
43
- 'starlette.responses', warn=False, lazy=False,
44
- check_update=CHECK_UPDATE,
45
- )
46
- python_multipart = attempt_import('multipart', lazy=False, check_update=CHECK_UPDATE)
47
- packaging_version = attempt_import('packaging.version', check_update=CHECK_UPDATE)
48
53
  from meerschaum.api._chain import check_allow_chaining, DISALLOW_CHAINING_MESSAGE
49
54
  uvicorn_config_path = API_UVICORN_RESOURCES_PATH / SERVER_ID / 'config.json'
50
55
 
@@ -440,18 +440,13 @@ def update_flags(input_flags_dropdown_values, n_clicks, input_flags_texts):
440
440
  className = 'input-text',
441
441
  )
442
442
 
443
+ remove_index = trigger_dict['index'] if trigger_type == 'input-flags-remove-button' else None
443
444
  rows = [
444
445
  build_row(i, val, val_text)
445
446
  for i, (val, val_text) in enumerate(zip(input_flags_dropdown_values, input_flags_texts))
447
+ if i != remove_index
446
448
  ]
447
449
 
448
- if trigger_type == 'input-flags-remove-button':
449
- remove_index = trigger_dict['index']
450
- try:
451
- del rows[remove_index]
452
- except IndexError:
453
- pass
454
-
455
450
  if not rows or input_flags_dropdown_values[-1]:
456
451
  rows.append(build_row(len(rows), None, None))
457
452
 
@@ -24,6 +24,7 @@ from meerschaum.api.dash import (
24
24
  from meerschaum.api.dash.connectors import get_web_connector
25
25
  from meerschaum.api.dash.components import alert_from_success_tuple
26
26
  from meerschaum.api.dash.users import is_session_authenticated
27
+ from meerschaum.config import get_config
27
28
  import meerschaum as mrsm
28
29
  dbc = attempt_import('dash_bootstrap_components', lazy=False, check_update=CHECK_UPDATE)
29
30
  dash_ace = attempt_import('dash_ace', lazy=False, check_update=CHECK_UPDATE)
@@ -110,12 +111,16 @@ def get_pipes_cards(*keys, session_data: Optional[Dict[str, Any]] = None):
110
111
  session_id = (session_data or {}).get('session-id', None)
111
112
  authenticated = is_session_authenticated(str(session_id))
112
113
 
113
- _pipes = pipes_from_state(*keys, as_list=True)
114
- alerts = [alert_from_success_tuple(_pipes)]
115
- if not isinstance(_pipes, list):
116
- _pipes = []
117
- for p in _pipes:
118
- meta_str = json.dumps(p.meta)
114
+ pipes = pipes_from_state(*keys, as_list=True)
115
+ alerts = [alert_from_success_tuple(pipes)]
116
+ if not isinstance(pipes, list):
117
+ pipes = []
118
+
119
+ max_num_pipes_cards = get_config('dash', 'max_num_pipes_cards')
120
+ overflow_pipes = pipes[max_num_pipes_cards:]
121
+
122
+ for pipe in pipes[:max_num_pipes_cards]:
123
+ meta_str = json.dumps(pipe.meta)
119
124
  footer_children = dbc.Row(
120
125
  [
121
126
  dbc.Col(
@@ -188,13 +193,13 @@ def get_pipes_cards(*keys, session_data: Optional[Dict[str, Any]] = None):
188
193
  )
189
194
  card_body_children = [
190
195
  html.H5(
191
- html.B(str(p)),
196
+ html.B(str(pipe)),
192
197
  className = 'card-title',
193
198
  style = {'font-family': ['monospace']}
194
199
  ),
195
200
  html.Div(
196
201
  dbc.Accordion(
197
- accordion_items_from_pipe(p, authenticated=authenticated),
202
+ accordion_items_from_pipe(pipe, authenticated=authenticated),
198
203
  flush = True,
199
204
  start_collapsed = True,
200
205
  id = {'type': 'pipe-accordion', 'index': meta_str},
@@ -203,11 +208,30 @@ def get_pipes_cards(*keys, session_data: Optional[Dict[str, Any]] = None):
203
208
 
204
209
  ]
205
210
  cards.append(
206
- dbc.Card(children=[
211
+ dbc.Card([
207
212
  dbc.CardBody(children=card_body_children),
208
213
  dbc.CardFooter(children=footer_children),
209
214
  ])
210
215
  )
216
+
217
+ if overflow_pipes:
218
+ cards.append(
219
+ dbc.Card([
220
+ dbc.CardBody(
221
+ html.Ul(
222
+ [
223
+ html.Li(html.H5(
224
+ html.B(str(pipe)),
225
+ className = 'card-title',
226
+ style = {'font-family': ['monospace']}
227
+ ))
228
+ for pipe in overflow_pipes
229
+ ]
230
+ )
231
+ )
232
+ ])
233
+ )
234
+
211
235
  return cards, alerts
212
236
 
213
237
 
@@ -32,17 +32,22 @@ def get_plugins_cards(
32
32
  desc = get_api_connector().get_plugin_attributes(plugin).get(
33
33
  'description', 'No description provided.'
34
34
  )
35
- desc_textarea_kw = dict(
36
- value=desc, readOnly=True, debounce=False, className='plugin-description',
37
- draggable=False, wrap='overflow',
38
- id={'type': 'description-textarea', 'index': plugin_name},
39
- )
35
+ desc_textarea_kw = {
36
+ 'value': desc,
37
+ 'readOnly': True,
38
+ 'debounce': False,
39
+ 'className': 'plugin-description',
40
+ 'draggable': False,
41
+ 'wrap': 'overflow',
42
+ 'placeholder': "Edit the plugin's description",
43
+ 'id': {'type': 'description-textarea', 'index': plugin_name},
44
+ }
40
45
 
41
46
  card_body_children = [html.H4(plugin_name)]
42
47
 
43
48
  if is_plugin_owner(plugin_name, session_data):
44
49
  desc_textarea_kw['readOnly'] = False
45
- card_body_children += [dbc.Textarea(**desc_textarea_kw)]
50
+ card_body_children.append(dbc.Textarea(**desc_textarea_kw))
46
51
  if not desc_textarea_kw['readOnly']:
47
52
  card_body_children += [
48
53
  dbc.Button(
@@ -53,12 +58,23 @@ def get_plugins_cards(
53
58
  ),
54
59
  html.Div(id={'type': 'edit-alert-div', 'index': plugin_name}),
55
60
  ]
56
- _plugin_username = get_api_connector().get_plugin_username(plugin, debug=debug)
61
+ plugin_username = get_api_connector().get_plugin_username(plugin, debug=debug)
62
+ plugin_version = get_api_connector().get_plugin_version(plugin, debug=debug) or ' '
57
63
  card_children = [
58
- dbc.CardHeader([html.A('👤 ' + str(_plugin_username), href='#')]),
64
+ dbc.CardHeader(
65
+ [
66
+ dbc.Row(
67
+ [
68
+ dbc.Col(html.A('👤 ' + str(plugin_username), href='#')),
69
+ dbc.Col(html.Pre(str(plugin_version), style={'text-align': 'right'})),
70
+ ],
71
+ justify = 'between',
72
+ ),
73
+ ],
74
+ ),
59
75
  dbc.CardBody(card_body_children),
60
76
  dbc.CardFooter([
61
- html.A('⬇️ Download source', href=(endpoints['plugins'] + '/' + plugin_name))
77
+ html.A('⬇️ Download', href=(endpoints['plugins'] + '/' + plugin_name))
62
78
  ]),
63
79
  ]
64
80
  cards.append(
@@ -70,6 +70,9 @@ window.addEventListener(
70
70
  if (!fl){ continue; }
71
71
  fl_val = event.data['input_flags_texts'][index];
72
72
  if (!fl_val){ continue; }
73
+ if (fl_val.includes(' ')){
74
+ fl_val = "'" + fl_val + "'";
75
+ }
73
76
  flags_str += " " + fl + " " + fl_val;
74
77
  }
75
78
 
@@ -39,10 +39,11 @@ def login(
39
39
  else (data.username, data.password)
40
40
  ) if not no_auth else ('no-auth', 'no-auth')
41
41
 
42
- from meerschaum.core.User._User import get_pwd_context
42
+ from meerschaum.core.User._User import verify_password
43
43
  user = User(username, password)
44
- correct_password = no_auth or get_pwd_context().verify(
45
- password, get_api_connector().get_user_password_hash(user, debug=debug)
44
+ correct_password = no_auth or verify_password(
45
+ password,
46
+ get_api_connector().get_user_password_hash(user, debug=debug)
46
47
  )
47
48
  if not correct_password:
48
49
  raise InvalidCredentialsException
@@ -51,7 +52,7 @@ def login(
51
52
  expires_delta = timedelta(minutes=expires_minutes)
52
53
  expires_dt = datetime.now(timezone.utc).replace(tzinfo=None) + expires_delta
53
54
  access_token = manager.create_access_token(
54
- data = dict(sub=username),
55
+ data = {'sub': username},
55
56
  expires = expires_delta
56
57
  )
57
58
  return {
@@ -90,18 +90,21 @@ def register_plugin(
90
90
  pass
91
91
 
92
92
  plugin = Plugin(name, version=version, attributes=attributes)
93
+ if curr_user is None:
94
+ return (
95
+ False,
96
+ "Cannot register a plugin without logging in (are you running with `--insecure`)?"
97
+ )
98
+
93
99
  if curr_user is not None:
94
100
  plugin_user_id = get_api_connector().get_plugin_user_id(plugin)
95
101
  curr_user_id = get_api_connector().get_user_id(curr_user) if curr_user is not None else -1
96
102
  if plugin_user_id is not None and plugin_user_id != curr_user_id:
97
103
  return False, f"User '{curr_user.username}' cannot edit plugin '{plugin}'."
98
104
  plugin.user_id = curr_user_id
99
- else:
100
- plugin.user_id = -1
101
105
 
102
106
  success, msg = get_api_connector().register_plugin(plugin, make_archive=False, debug=debug)
103
107
 
104
- ### TODO delete and install new version of plugin on success
105
108
  if success:
106
109
  archive_path = plugin.archive_path
107
110
  temp_archive_path = pathlib.Path(str(archive_path) + '.tmp')
@@ -0,0 +1,11 @@
1
+ #! /usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ # vim:fenc=utf-8
4
+
5
+ """
6
+ Define default configuration for the Dash application.
7
+ """
8
+
9
+ default_dash_config = {
10
+ 'max_num_pipes_cards': 20,
11
+ }
@@ -44,6 +44,7 @@ default_meerschaum_config = {
44
44
  },
45
45
  'local': {
46
46
  'host': 'localhost',
47
+ 'port': 8000,
47
48
  },
48
49
  'mrsm': {
49
50
  'host': 'api.mrsm.io',
@@ -151,7 +152,6 @@ default_config['pipes'] = default_pipes_config
151
152
  default_config['plugins'] = default_plugins_config
152
153
  from meerschaum.config._jobs import default_jobs_config
153
154
  default_config['jobs'] = default_jobs_config
154
- # default_config['experimental'] = default_experimental_config
155
155
  ### add configs from other packages
156
156
  try:
157
157
  import meerschaum.config.stack
@@ -160,6 +160,8 @@ except ImportError as e:
160
160
  finally:
161
161
  from meerschaum.config.stack import default_stack_config
162
162
  default_config['stack'] = default_stack_config
163
+ from meerschaum.config._dash import default_dash_config
164
+ default_config['dash'] = default_dash_config
163
165
 
164
166
  default_header_comment = """
165
167
  #####################################################################
@@ -9,13 +9,19 @@ Default configuration for jobs.
9
9
  default_jobs_config = {
10
10
  'timeout_seconds': 8,
11
11
  'check_timeout_interval_seconds': 0.1,
12
- 'logs' : {
12
+ 'terminal': {
13
+ 'lines': 40,
14
+ 'columns': 70,
15
+ },
16
+ 'logs': {
13
17
  'num_files_to_keep': 5,
14
18
  'max_file_size': 100_000,
15
19
  'lines_to_show': 30,
16
- 'refresh_files_seconds': 5.0,
17
- 'min_buffer_len': 15,
18
- 'colors' : [
20
+ 'refresh_files_seconds': 5,
21
+ 'min_buffer_len': 5,
22
+ 'timestamp_format': '%Y-%m-%d %H:%M',
23
+ 'follow_timestamp_format': '%H:%M',
24
+ 'colors': [
19
25
  'cyan',
20
26
  'magenta',
21
27
  'orange3',
@@ -129,6 +129,7 @@ paths = {
129
129
 
130
130
  'PLUGINS_RESOURCES_PATH' : ('{INTERNAL_RESOURCES_PATH}', 'plugins'),
131
131
  'PLUGINS_INTERNAL_LOCK_PATH' : ('{INTERNAL_RESOURCES_PATH}', 'plugins.lock'),
132
+ 'PLUGINS_PACKAGES_INTERNAL_PATH' : ('{INTERNAL_RESOURCES_PATH}', 'packaged_plugins'),
132
133
  'PLUGINS_ARCHIVES_RESOURCES_PATH': ('{PLUGINS_RESOURCES_PATH}', '.archives'),
133
134
  'PLUGINS_TEMP_RESOURCES_PATH' : ('{PLUGINS_RESOURCES_PATH}', '.tmp'),
134
135
  'PLUGINS_INIT_PATH' : ('{PLUGINS_RESOURCES_PATH}', '__init__.py'),
@@ -153,6 +154,7 @@ paths = {
153
154
 
154
155
  'DAEMON_RESOURCES_PATH' : ('{ROOT_DIR_PATH}', 'jobs'),
155
156
  'LOGS_RESOURCES_PATH' : ('{ROOT_DIR_PATH}', 'logs'),
157
+ 'DAEMON_ERROR_LOG_PATH' : ('{ROOT_DIR_PATH}', 'daemon_errors.log'),
156
158
  }
157
159
 
158
160
  def set_root(root: Union[Path, str]):