meerschaum 2.1.5__tar.gz → 2.1.6__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 (247) hide show
  1. {meerschaum-2.1.5/meerschaum.egg-info → meerschaum-2.1.6}/PKG-INFO +1 -1
  2. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/actions/sync.py +49 -21
  3. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/config/_version.py +1 -1
  4. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/connectors/sql/_pipes.py +40 -8
  5. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/connectors/sql/tables/__init__.py +0 -16
  6. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/core/Pipe/_data.py +5 -4
  7. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/utils/sql.py +27 -7
  8. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/utils/typing.py +11 -0
  9. {meerschaum-2.1.5 → meerschaum-2.1.6/meerschaum.egg-info}/PKG-INFO +1 -1
  10. {meerschaum-2.1.5 → meerschaum-2.1.6}/tests/test_sync.py +31 -0
  11. {meerschaum-2.1.5 → meerschaum-2.1.6}/LICENSE +0 -0
  12. {meerschaum-2.1.5 → meerschaum-2.1.6}/NOTICE +0 -0
  13. {meerschaum-2.1.5 → meerschaum-2.1.6}/README.md +0 -0
  14. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/__init__.py +0 -0
  15. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/__main__.py +0 -0
  16. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/_internal/__init__.py +0 -0
  17. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/_internal/arguments/__init__.py +0 -0
  18. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/_internal/arguments/_parse_arguments.py +0 -0
  19. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/_internal/arguments/_parser.py +0 -0
  20. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/_internal/docs/__init__.py +0 -0
  21. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/_internal/docs/index.py +0 -0
  22. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/_internal/entry.py +0 -0
  23. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/_internal/gui/__init__.py +0 -0
  24. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/_internal/gui/app/__init__.py +0 -0
  25. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/_internal/gui/app/_windows.py +0 -0
  26. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/_internal/gui/app/actions.py +0 -0
  27. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/_internal/gui/app/pipes.py +0 -0
  28. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/_internal/shell/Shell.py +0 -0
  29. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/_internal/shell/ShellCompleter.py +0 -0
  30. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/_internal/shell/ValidAutoSuggest.py +0 -0
  31. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/_internal/shell/__init__.py +0 -0
  32. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/_internal/shell/resources/__init__.py +0 -0
  33. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/_internal/term/TermPageHandler.py +0 -0
  34. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/_internal/term/__init__.py +0 -0
  35. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/_internal/term/tools.py +0 -0
  36. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/actions/__init__.py +0 -0
  37. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/actions/api.py +0 -0
  38. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/actions/bootstrap.py +0 -0
  39. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/actions/clear.py +0 -0
  40. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/actions/copy.py +0 -0
  41. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/actions/deduplicate.py +0 -0
  42. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/actions/delete.py +0 -0
  43. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/actions/drop.py +0 -0
  44. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/actions/edit.py +0 -0
  45. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/actions/install.py +0 -0
  46. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/actions/login.py +0 -0
  47. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/actions/os.py +0 -0
  48. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/actions/pause.py +0 -0
  49. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/actions/python.py +0 -0
  50. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/actions/register.py +0 -0
  51. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/actions/reload.py +0 -0
  52. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/actions/setup.py +0 -0
  53. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/actions/sh.py +0 -0
  54. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/actions/show.py +0 -0
  55. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/actions/sql.py +0 -0
  56. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/actions/stack.py +0 -0
  57. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/actions/start.py +0 -0
  58. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/actions/stop.py +0 -0
  59. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/actions/tag.py +0 -0
  60. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/actions/uninstall.py +0 -0
  61. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/actions/upgrade.py +0 -0
  62. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/actions/verify.py +0 -0
  63. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/api/__init__.py +0 -0
  64. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/api/_chain.py +0 -0
  65. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/api/_events.py +0 -0
  66. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/api/_oauth2.py +0 -0
  67. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/api/_websockets.py +0 -0
  68. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/api/dash/__init__.py +0 -0
  69. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/api/dash/actions.py +0 -0
  70. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/api/dash/assets/__init__.py +0 -0
  71. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/api/dash/assets/ansi_up.js +0 -0
  72. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/api/dash/assets/banner_1920x320.png +0 -0
  73. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/api/dash/assets/favicon.ico +0 -0
  74. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/api/dash/assets/logo_48x48.png +0 -0
  75. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/api/dash/assets/logo_500x500.png +0 -0
  76. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/api/dash/callbacks/__init__.py +0 -0
  77. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/api/dash/callbacks/dashboard.py +0 -0
  78. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/api/dash/callbacks/jobs.py +0 -0
  79. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/api/dash/callbacks/login.py +0 -0
  80. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/api/dash/callbacks/plugins.py +0 -0
  81. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/api/dash/callbacks/register.py +0 -0
  82. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/api/dash/components.py +0 -0
  83. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/api/dash/connectors.py +0 -0
  84. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/api/dash/graphs.py +0 -0
  85. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/api/dash/jobs.py +0 -0
  86. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/api/dash/keys.py +0 -0
  87. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/api/dash/pages/__init__.py +0 -0
  88. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/api/dash/pages/dashboard.py +0 -0
  89. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/api/dash/pages/error.py +0 -0
  90. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/api/dash/pages/login.py +0 -0
  91. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/api/dash/pages/plugins.py +0 -0
  92. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/api/dash/pages/register.py +0 -0
  93. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/api/dash/pipes.py +0 -0
  94. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/api/dash/plugins.py +0 -0
  95. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/api/dash/sync.py +0 -0
  96. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/api/dash/users.py +0 -0
  97. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/api/dash/websockets.py +0 -0
  98. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/api/dash/webterm.py +0 -0
  99. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/api/models/__init__.py +0 -0
  100. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/api/models/_interfaces.py +0 -0
  101. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/api/models/_locations.py +0 -0
  102. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/api/models/_metrics.py +0 -0
  103. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/api/models/_pipes.py +0 -0
  104. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/api/resources/__init__.py +0 -0
  105. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/api/resources/static/__init__.py +0 -0
  106. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/api/resources/static/css/__init__.py +0 -0
  107. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/api/resources/static/css/bootstrap.min.css +0 -0
  108. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/api/resources/static/css/dash.css +0 -0
  109. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/api/resources/static/css/dbc_dark.css +0 -0
  110. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/api/resources/static/css/styles.css +0 -0
  111. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/api/resources/static/css/xterm.css +0 -0
  112. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/api/resources/static/ico/__init__.py +0 -0
  113. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/api/resources/static/ico/logo.ico +0 -0
  114. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/api/resources/static/js/__init__.py +0 -0
  115. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/api/resources/static/js/action_button.js +0 -0
  116. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/api/resources/static/js/main.js +0 -0
  117. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/api/resources/static/js/terminado.js +0 -0
  118. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/api/resources/static/js/xterm.js +0 -0
  119. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/api/resources/static/png/__init__.py +0 -0
  120. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/api/resources/templates/__init__.py +0 -0
  121. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/api/resources/templates/index.html +0 -0
  122. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/api/resources/templates/old_index.html +0 -0
  123. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/api/resources/templates/secret.html +0 -0
  124. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/api/resources/templates/termpage.html +0 -0
  125. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/api/routes/__init__.py +0 -0
  126. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/api/routes/_actions.py +0 -0
  127. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/api/routes/_connectors.py +0 -0
  128. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/api/routes/_index.py +0 -0
  129. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/api/routes/_login.py +0 -0
  130. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/api/routes/_misc.py +0 -0
  131. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/api/routes/_pipes.py +0 -0
  132. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/api/routes/_plugins.py +0 -0
  133. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/api/routes/_users.py +0 -0
  134. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/api/routes/_version.py +0 -0
  135. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/api/routes/_webterm.py +0 -0
  136. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/api/tables/__init__.py +0 -0
  137. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/config/__init__.py +0 -0
  138. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/config/_default.py +0 -0
  139. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/config/_edit.py +0 -0
  140. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/config/_environment.py +0 -0
  141. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/config/_formatting.py +0 -0
  142. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/config/_jobs.py +0 -0
  143. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/config/_patch.py +0 -0
  144. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/config/_paths.py +0 -0
  145. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/config/_preprocess.py +0 -0
  146. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/config/_read_config.py +0 -0
  147. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/config/_shell.py +0 -0
  148. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/config/_sync.py +0 -0
  149. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/config/resources/__init__.py +0 -0
  150. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/config/stack/__init__.py +0 -0
  151. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/config/stack/grafana/__init__.py +0 -0
  152. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/config/stack/mosquitto/__init__.py +0 -0
  153. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/config/stack/mosquitto/resources/__init__.py +0 -0
  154. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/config/stack/resources/__init__.py +0 -0
  155. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/config/static/__init__.py +0 -0
  156. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/connectors/Connector.py +0 -0
  157. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/connectors/__init__.py +0 -0
  158. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/connectors/api/APIConnector.py +0 -0
  159. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/connectors/api/__init__.py +0 -0
  160. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/connectors/api/_actions.py +0 -0
  161. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/connectors/api/_fetch.py +0 -0
  162. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/connectors/api/_login.py +0 -0
  163. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/connectors/api/_misc.py +0 -0
  164. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/connectors/api/_pipes.py +0 -0
  165. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/connectors/api/_plugins.py +0 -0
  166. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/connectors/api/_request.py +0 -0
  167. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/connectors/api/_uri.py +0 -0
  168. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/connectors/api/_users.py +0 -0
  169. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/connectors/parse.py +0 -0
  170. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/connectors/plugin/PluginConnector.py +0 -0
  171. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/connectors/plugin/__init__.py +0 -0
  172. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/connectors/poll.py +0 -0
  173. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/connectors/sql/SQLConnector.py +0 -0
  174. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/connectors/sql/__init__.py +0 -0
  175. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/connectors/sql/_cli.py +0 -0
  176. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/connectors/sql/_create_engine.py +0 -0
  177. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/connectors/sql/_fetch.py +0 -0
  178. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/connectors/sql/_instance.py +0 -0
  179. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/connectors/sql/_plugins.py +0 -0
  180. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/connectors/sql/_sql.py +0 -0
  181. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/connectors/sql/_uri.py +0 -0
  182. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/connectors/sql/_users.py +0 -0
  183. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/connectors/sql/tables/types.py +0 -0
  184. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/connectors/sql/tools.py +0 -0
  185. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/core/Pipe/__init__.py +0 -0
  186. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/core/Pipe/_attributes.py +0 -0
  187. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/core/Pipe/_bootstrap.py +0 -0
  188. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/core/Pipe/_clear.py +0 -0
  189. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/core/Pipe/_deduplicate.py +0 -0
  190. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/core/Pipe/_delete.py +0 -0
  191. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/core/Pipe/_drop.py +0 -0
  192. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/core/Pipe/_dtypes.py +0 -0
  193. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/core/Pipe/_edit.py +0 -0
  194. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/core/Pipe/_fetch.py +0 -0
  195. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/core/Pipe/_register.py +0 -0
  196. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/core/Pipe/_show.py +0 -0
  197. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/core/Pipe/_sync.py +0 -0
  198. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/core/Pipe/_verify.py +0 -0
  199. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/core/Plugin/__init__.py +0 -0
  200. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/core/User/_User.py +0 -0
  201. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/core/User/__init__.py +0 -0
  202. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/core/__init__.py +0 -0
  203. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/plugins/_Plugin.py +0 -0
  204. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/plugins/__init__.py +0 -0
  205. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/utils/__init__.py +0 -0
  206. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/utils/_get_pipes.py +0 -0
  207. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/utils/daemon/Daemon.py +0 -0
  208. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/utils/daemon/RotatingFile.py +0 -0
  209. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/utils/daemon/__init__.py +0 -0
  210. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/utils/daemon/_names.py +0 -0
  211. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/utils/dataframe.py +0 -0
  212. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/utils/debug.py +0 -0
  213. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/utils/dtypes/__init__.py +0 -0
  214. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/utils/dtypes/sql.py +0 -0
  215. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/utils/formatting/__init__.py +0 -0
  216. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/utils/formatting/_jobs.py +0 -0
  217. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/utils/formatting/_pipes.py +0 -0
  218. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/utils/formatting/_pprint.py +0 -0
  219. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/utils/formatting/_shell.py +0 -0
  220. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/utils/interactive.py +0 -0
  221. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/utils/misc.py +0 -0
  222. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/utils/networking.py +0 -0
  223. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/utils/packages/__init__.py +0 -0
  224. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/utils/packages/_packages.py +0 -0
  225. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/utils/packages/lazy_loader.py +0 -0
  226. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/utils/pool.py +0 -0
  227. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/utils/process.py +0 -0
  228. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/utils/prompt.py +0 -0
  229. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/utils/schedule.py +0 -0
  230. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/utils/threading.py +0 -0
  231. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/utils/venv/_Venv.py +0 -0
  232. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/utils/venv/__init__.py +0 -0
  233. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/utils/warnings.py +0 -0
  234. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum/utils/yaml.py +0 -0
  235. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum.egg-info/SOURCES.txt +0 -0
  236. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum.egg-info/dependency_links.txt +0 -0
  237. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum.egg-info/entry_points.txt +0 -0
  238. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum.egg-info/requires.txt +0 -0
  239. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum.egg-info/top_level.txt +0 -0
  240. {meerschaum-2.1.5 → meerschaum-2.1.6}/meerschaum.egg-info/zip-safe +0 -0
  241. {meerschaum-2.1.5 → meerschaum-2.1.6}/setup.cfg +0 -0
  242. {meerschaum-2.1.5 → meerschaum-2.1.6}/setup.py +0 -0
  243. {meerschaum-2.1.5 → meerschaum-2.1.6}/tests/test_deduplicate.py +0 -0
  244. {meerschaum-2.1.5 → meerschaum-2.1.6}/tests/test_pipes_dtypes.py +0 -0
  245. {meerschaum-2.1.5 → meerschaum-2.1.6}/tests/test_sql.py +0 -0
  246. {meerschaum-2.1.5 → meerschaum-2.1.6}/tests/test_users.py +0 -0
  247. {meerschaum-2.1.5 → meerschaum-2.1.6}/tests/test_verify.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: meerschaum
3
- Version: 2.1.5
3
+ Version: 2.1.6
4
4
  Summary: Sync Time-Series Pipes with Meerschaum
5
5
  Home-page: https://meerschaum.io
6
6
  Author: Bennett Meares
@@ -9,7 +9,7 @@ NOTE: `sync` required a SQL connection and is not intended for client use
9
9
  """
10
10
 
11
11
  from __future__ import annotations
12
- from datetime import timedelta
12
+ from datetime import timedelta, datetime, timezone
13
13
  import meerschaum as mrsm
14
14
  from meerschaum.utils.typing import SuccessTuple, Any, List, Optional, Tuple, Union
15
15
 
@@ -39,7 +39,7 @@ def sync(
39
39
 
40
40
  def _pipes_lap(
41
41
  workers: Optional[int] = None,
42
- debug: bool = None,
42
+ debug: Optional[bool] = None,
43
43
  unblock: bool = False,
44
44
  force: bool = False,
45
45
  min_seconds: int = 1,
@@ -52,7 +52,7 @@ def _pipes_lap(
52
52
  nopretty: bool = False,
53
53
  _progress: Optional['rich.progress.Progress'] = None,
54
54
  **kw: Any
55
- ) -> Tuple[List[meerschaum.Pipe], List[meerschaum.Pipe]]:
55
+ ) -> Tuple[List[mrsm.Pipe], List[mrsm.Pipe]]:
56
56
  """
57
57
  Do a lap of syncing pipes.
58
58
  """
@@ -402,11 +402,20 @@ def _wrap_pipe(
402
402
  Wrapper function for handling exceptions.
403
403
  """
404
404
  import time
405
+ import traceback
406
+ from datetime import datetime, timedelta, timezone
407
+ import meerschaum as mrsm
408
+ from meerschaum.utils.typing import is_success_tuple, SuccessTuple
405
409
  from meerschaum.connectors import get_connector_plugin
406
410
  from meerschaum.utils.venv import Venv
407
411
  from meerschaum.plugins import _pre_sync_hooks, _post_sync_hooks
408
412
  from meerschaum.utils.misc import filter_keywords
413
+ from meerschaum.utils.pool import get_pool
414
+ from meerschaum.utils.warnings import warn
415
+
416
+ pool = get_pool(workers=workers)
409
417
 
418
+ sync_timestamp = datetime.now(timezone.utc)
410
419
  sync_start = time.perf_counter()
411
420
  sync_kwargs = {k: v for k, v in kw.items() if k != 'blocking'}
412
421
  sync_kwargs.update({
@@ -415,8 +424,9 @@ def _wrap_pipe(
415
424
  'debug': debug,
416
425
  'min_seconds': min_seconds,
417
426
  'workers': workers,
418
- 'bounded': 'bounded',
427
+ 'bounded': bounded,
419
428
  'chunk_interval': chunk_interval,
429
+ 'sync_timestamp': sync_timestamp,
420
430
  })
421
431
  if not verify and not deduplicate:
422
432
  sync_method = pipe.sync
@@ -427,12 +437,32 @@ def _wrap_pipe(
427
437
  sync_kwargs['deduplicate'] = deduplicate
428
438
  sync_kwargs['sync_method'] = sync_method
429
439
 
430
- for module_name, pre_sync_hooks in _pre_sync_hooks.items():
431
- plugin_name = module_name.split('.')[-1] if module_name.startswith('plugins.') else None
440
+ def call_sync_hook(plugin_name: str, sync_hook) -> SuccessTuple:
432
441
  plugin = mrsm.Plugin(plugin_name) if plugin_name else None
433
- with Venv(plugin):
434
- for pre_sync_hook in pre_sync_hooks:
435
- _ = pre_sync_hook(pipe, **filter_keywords(pre_sync_hook, **sync_kwargs))
442
+ with mrsm.Venv(plugin):
443
+ try:
444
+ sync_hook_result = sync_hook(pipe, **filter_keywords(sync_hook, **sync_kwargs))
445
+ if is_success_tuple(sync_hook_result):
446
+ return sync_hook_result
447
+ except Exception as e:
448
+ msg = (
449
+ f"Failed to execute sync hook '{sync_hook.__name__}' "
450
+ + f"from plugin '{plugin}':\n{traceback.format_exc()}"
451
+ )
452
+ warn(msg, stack=False)
453
+ return False, msg
454
+ return True, "Success"
455
+
456
+ hook_results = []
457
+ def apply_hooks(is_pre_sync: bool):
458
+ _sync_hooks = (_pre_sync_hooks if is_pre_sync else _post_sync_hooks)
459
+ for module_name, sync_hooks in _sync_hooks.items():
460
+ plugin_name = module_name.split('.')[-1] if module_name.startswith('plugins.') else None
461
+ for sync_hook in sync_hooks:
462
+ hook_result = pool.apply_async(call_sync_hook, (plugin_name, sync_hook))
463
+ hook_results.append(hook_result)
464
+
465
+ apply_hooks(True)
436
466
 
437
467
  try:
438
468
  with Venv(get_connector_plugin(pipe.connector), debug=debug):
@@ -444,18 +474,16 @@ def _wrap_pipe(
444
474
  return_tuple = (False, f"Failed to sync {pipe} with exception:" + "\n" + str(e))
445
475
 
446
476
  duration = time.perf_counter() - sync_start
447
- sync_kwargs['duration'] = duration
448
- for module_name, post_sync_hooks in _post_sync_hooks.items():
449
- plugin_name = module_name.split('.')[-1] if module_name.startswith('plugins.') else None
450
- plugin = mrsm.Plugin(plugin_name) if plugin_name else None
451
- with Venv(plugin):
452
- for post_sync_hook in post_sync_hooks:
453
- _ = post_sync_hook(
454
- pipe,
455
- return_tuple,
456
- **filter_keywords(post_sync_hook, **sync_kwargs)
457
- )
458
-
477
+ sync_kwargs.update({
478
+ 'success_tuple': return_tuple,
479
+ 'sync_duration': duration,
480
+ 'sync_complete_timestamp': datetime.now(timezone.utc),
481
+ })
482
+ apply_hooks(False)
483
+ for hook_result in hook_results:
484
+ hook_success, hook_msg = hook_result.get()
485
+ mrsm.pprint((hook_success, hook_msg))
486
+
459
487
  return return_tuple
460
488
 
461
489
 
@@ -2,4 +2,4 @@
2
2
  Specify the Meerschaum release version.
3
3
  """
4
4
 
5
- __version__ = "2.1.5"
5
+ __version__ = "2.1.6"
@@ -385,7 +385,13 @@ def get_create_index_queries(
385
385
  -------
386
386
  A dictionary of column names mapping to lists of queries.
387
387
  """
388
- from meerschaum.utils.sql import sql_item_name, get_distinct_col_count, update_queries
388
+ from meerschaum.utils.sql import (
389
+ sql_item_name,
390
+ get_distinct_col_count,
391
+ update_queries,
392
+ get_null_replacement,
393
+ COALESCE_UNIQUE_INDEX_FLAVORS,
394
+ )
389
395
  from meerschaum.config import get_config
390
396
  index_queries = {}
391
397
 
@@ -497,15 +503,37 @@ def get_create_index_queries(
497
503
  if ix and ix in existing_cols_types
498
504
  ]
499
505
  )
506
+ coalesce_indices_cols_str = ', '.join(
507
+ [
508
+ (
509
+ "COALESCE("
510
+ + sql_item_name(ix, self.flavor)
511
+ + ", "
512
+ + get_null_replacement(existing_cols_types[ix], self.flavor)
513
+ + ") "
514
+ ) if ix_key != 'datetime' else (sql_item_name(ix, self.flavor))
515
+ for ix_key, ix in pipe.columns.items()
516
+ if ix and ix in existing_cols_types
517
+ ]
518
+ )
519
+ unique_index_name = sql_item_name(pipe.target + '_unique_index', self.flavor)
500
520
  constraint_name = sql_item_name(pipe.target + '_constraint', self.flavor)
501
- constraint_query = (
521
+ add_constraint_query = (
502
522
  f"ALTER TABLE {_pipe_name} ADD CONSTRAINT {constraint_name} UNIQUE ({indices_cols_str})"
503
- if self.flavor != 'sqlite'
504
- else f"CREATE UNIQUE INDEX {constraint_name} ON {_pipe_name} ({indices_cols_str})"
505
523
  )
524
+ unique_index_cols_str = (
525
+ indices_cols_str
526
+ if self.flavor not in COALESCE_UNIQUE_INDEX_FLAVORS
527
+ else coalesce_indices_cols_str
528
+ )
529
+ create_unique_index_query = (
530
+ f"CREATE UNIQUE INDEX {unique_index_name} ON {_pipe_name} ({unique_index_cols_str})"
531
+ )
532
+ constraint_queries = [create_unique_index_query]
533
+ if self.flavor != 'sqlite':
534
+ constraint_queries.append(add_constraint_query)
506
535
  if upsert and indices_cols_str:
507
- index_queries[constraint_name] = [constraint_query]
508
-
536
+ index_queries[unique_index_name] = constraint_queries
509
537
  return index_queries
510
538
 
511
539
 
@@ -1074,7 +1102,7 @@ def get_pipe_attributes(
1074
1102
  def sync_pipe(
1075
1103
  self,
1076
1104
  pipe: mrsm.Pipe,
1077
- df: Union[pandas.DataFrame, str, Dict[Any, Any], None] = None,
1105
+ df: Union[pd.DataFrame, str, Dict[Any, Any], None] = None,
1078
1106
  begin: Optional[datetime] = None,
1079
1107
  end: Optional[datetime] = None,
1080
1108
  chunksize: Optional[int] = -1,
@@ -1286,7 +1314,11 @@ def sync_pipe(
1286
1314
  temp_pipe = Pipe(
1287
1315
  pipe.connector_keys.replace(':', '_') + '_', pipe.metric_key, pipe.location_key,
1288
1316
  instance = pipe.instance_keys,
1289
- columns = pipe.columns,
1317
+ columns = {
1318
+ ix_key: ix
1319
+ for ix_key, ix in pipe.columns.items()
1320
+ if ix and ix in update_df.columns
1321
+ },
1290
1322
  dtypes = pipe.dtypes,
1291
1323
  target = temp_target,
1292
1324
  temporary = True,
@@ -214,22 +214,6 @@ def create_tables(
214
214
  from meerschaum.utils.sql import get_rename_table_queries, table_exists
215
215
  _tables = tables if tables is not None else get_tables(conn)
216
216
 
217
- rename_queries = []
218
- for table_key, table in _tables.items():
219
- if table_exists(
220
- table_key,
221
- conn,
222
- schema = conn.instance_schema,
223
- ):
224
- rename_queries.extend(get_rename_table_queries(
225
- table_key,
226
- table.name,
227
- schema = conn.instance_schema,
228
- flavor = conn.flavor,
229
- ))
230
- if rename_queries:
231
- conn.exec_queries(rename_queries)
232
-
233
217
  try:
234
218
  conn.metadata.create_all(bind=conn.engine)
235
219
  except Exception as e:
@@ -8,7 +8,7 @@ Retrieve Pipes' data from instances.
8
8
 
9
9
  from __future__ import annotations
10
10
  from datetime import datetime, timedelta
11
- from meerschaum.utils.typing import Optional, Dict, Any, Union, Generator, List, Tuple
11
+ from meerschaum.utils.typing import Optional, Dict, Any, Union, Generator, List, Tuple, Iterator
12
12
  from meerschaum.config import get_config
13
13
 
14
14
  def get_data(
@@ -247,7 +247,7 @@ def _get_data_as_iterator(
247
247
  fresh: bool = False,
248
248
  debug: bool = False,
249
249
  **kw: Any
250
- ) -> Generator['pd.DataFrame']:
250
+ ) -> Iterator['pd.DataFrame']:
251
251
  """
252
252
  Return a pipe's data as a generator.
253
253
  """
@@ -267,16 +267,17 @@ def _get_data_as_iterator(
267
267
 
268
268
  _ = kw.pop('as_chunks', None)
269
269
  _ = kw.pop('as_iterator', None)
270
+ dt_col = self.columns.get('datetime', None)
270
271
  min_dt = (
271
272
  begin
272
273
  if begin is not None
273
274
  else self.get_sync_time(round_down=False, newest=False, params=params, debug=debug)
274
- )
275
+ ) if dt_col else None
275
276
  max_dt = (
276
277
  end
277
278
  if end is not None
278
279
  else self.get_sync_time(round_down=False, newest=True, params=params, debug=debug)
279
- )
280
+ ) if dt_col else None
280
281
 
281
282
  ### We want to search just past the maximum value.
282
283
  if end is None:
@@ -38,6 +38,7 @@ version_queries = {
38
38
  'oracle': "SELECT version from PRODUCT_COMPONENT_VERSION WHERE rownum = 1",
39
39
  }
40
40
  SKIP_IF_EXISTS_FLAVORS = {'mssql', 'oracle'}
41
+ COALESCE_UNIQUE_INDEX_FLAVORS = {'timescaledb', 'postgresql', 'citus'}
41
42
  update_queries = {
42
43
  'default': """
43
44
  UPDATE {target_table_name} AS f
@@ -53,25 +54,25 @@ update_queries = {
53
54
  INSERT INTO {target_table_name} ({patch_cols_str})
54
55
  SELECT {patch_cols_str}
55
56
  FROM {patch_table_name}
56
- ON CONFLICT ({join_cols_str}) DO UPDATE {sets_subquery_none_excluded}
57
+ ON CONFLICT ({join_cols_str}) DO {update_or_nothing} {sets_subquery_none_excluded}
57
58
  """,
58
59
  'postgresql-upsert': """
59
60
  INSERT INTO {target_table_name} ({patch_cols_str})
60
61
  SELECT {patch_cols_str}
61
62
  FROM {patch_table_name}
62
- ON CONFLICT ({join_cols_str}) DO UPDATE {sets_subquery_none_excluded}
63
+ ON CONFLICT ({join_cols_str}) DO {update_or_nothing} {sets_subquery_none_excluded}
63
64
  """,
64
65
  'citus-upsert': """
65
66
  INSERT INTO {target_table_name} ({patch_cols_str})
66
67
  SELECT {patch_cols_str}
67
68
  FROM {patch_table_name}
68
- ON CONFLICT ({join_cols_str}) DO UPDATE {sets_subquery_none_excluded}
69
+ ON CONFLICT ({join_cols_str}) DO {update_or_nothing} {sets_subquery_none_excluded}
69
70
  """,
70
71
  'cockroachdb-upsert': """
71
72
  INSERT INTO {target_table_name} ({patch_cols_str})
72
73
  SELECT {patch_cols_str}
73
74
  FROM {patch_table_name}
74
- ON CONFLICT ({join_cols_str}) DO UPDATE {sets_subquery_none_excluded}
75
+ ON CONFLICT ({join_cols_str}) DO {update_or_nothing} {sets_subquery_none_excluded}
75
76
  """,
76
77
  'mysql': """
77
78
  UPDATE {target_table_name} AS f
@@ -122,7 +123,7 @@ update_queries = {
122
123
  SELECT {patch_cols_str}
123
124
  FROM {patch_table_name}
124
125
  WHERE true
125
- ON CONFLICT ({join_cols_str}) DO UPDATE {sets_subquery_none_excluded}
126
+ ON CONFLICT ({join_cols_str}) DO {update_or_nothing} {sets_subquery_none_excluded}
126
127
  """,
127
128
  'sqlite_delete_insert': [
128
129
  """
@@ -1084,7 +1085,7 @@ def get_update_queries(
1084
1085
  for col in patch_table_columns
1085
1086
  ]
1086
1087
  )
1087
- join_cols_str = ','.join(
1088
+ join_cols_str = ', '.join(
1088
1089
  [
1089
1090
  sql_item_name(col, flavor)
1090
1091
  for col in join_cols
@@ -1109,10 +1110,27 @@ def get_update_queries(
1109
1110
  if debug:
1110
1111
  dprint(f"value_cols: {value_cols}")
1111
1112
 
1112
- if not value_cols or not join_cols_types:
1113
+ if not join_cols_types:
1114
+ return []
1115
+ if not value_cols and not upsert:
1113
1116
  return []
1114
1117
 
1118
+ coalesce_join_cols_str = ', '.join(
1119
+ [
1120
+ 'COALESCE('
1121
+ + sql_item_name(c_name, flavor)
1122
+ + ', '
1123
+ + get_null_replacement(c_type, flavor)
1124
+ + ')'
1125
+ for c_name, c_type in join_cols_types
1126
+ ]
1127
+ )
1128
+
1129
+ update_or_nothing = ('UPDATE' if value_cols else 'NOTHING')
1130
+
1115
1131
  def sets_subquery(l_prefix: str, r_prefix: str):
1132
+ if not value_cols:
1133
+ return ''
1116
1134
  return 'SET ' + ',\n'.join([
1117
1135
  (
1118
1136
  l_prefix + sql_item_name(c_name, flavor, None)
@@ -1169,6 +1187,8 @@ def get_update_queries(
1169
1187
  patch_cols_str = patch_cols_str,
1170
1188
  date_bounds_subquery = date_bounds_subquery,
1171
1189
  join_cols_str = join_cols_str,
1190
+ coalesce_join_cols_str = coalesce_join_cols_str,
1191
+ update_or_nothing = update_or_nothing,
1172
1192
  )
1173
1193
  for base_query in base_queries
1174
1194
  ]
@@ -87,3 +87,14 @@ PipesDict = Dict[
87
87
  ]
88
88
  ]
89
89
  WebState = Dict[str, str]
90
+
91
+ def is_success_tuple(x: Any) -> bool:
92
+ """
93
+ Determine whether an object is a `SuccessTuple`.
94
+ """
95
+ return (
96
+ isinstance(x, tuple)
97
+ and len(x) == 2
98
+ and isinstance(x[0], bool)
99
+ and isinstance(x[1], str)
100
+ )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: meerschaum
3
- Version: 2.1.5
3
+ Version: 2.1.6
4
4
  Summary: Sync Time-Series Pipes with Meerschaum
5
5
  Home-page: https://meerschaum.io
6
6
  Author: Bennett Meares
@@ -689,3 +689,34 @@ def test_upsert_sync(flavor: str):
689
689
  assert 'na' in str(df['yes'][0]).lower()
690
690
  assert isinstance(df['num'][0], Decimal)
691
691
  assert df['num'][0] == Decimal('2')
692
+
693
+
694
+ @pytest.mark.parametrize("flavor", get_flavors())
695
+ def test_upsert_no_value_cols(flavor: str):
696
+ """
697
+ Test that setting `upsert` to `True` is able to sync without value columns.
698
+ """
699
+ conn = conns[flavor]
700
+ pipe = Pipe('test', 'upsert', 'no_vals', instance=conn)
701
+ pipe.delete()
702
+ pipe = Pipe(
703
+ 'test', 'upsert', 'no_vals', instance=conn,
704
+ columns = {'datetime': 'dt', 'id': 'id'},
705
+ parameters = {'upsert': True},
706
+ )
707
+
708
+ docs = [
709
+ {'dt': '2023-01-01', 'id': 1},
710
+ {'dt': '2023-01-02', 'id': 2},
711
+ {'dt': '2023-01-03', 'id': 3},
712
+ ]
713
+ success, msg = pipe.sync(docs, debug=debug)
714
+ assert success, msg
715
+
716
+ docs = [
717
+ {'dt': '2023-01-03', 'id': 3},
718
+ ]
719
+ success, msg = pipe.sync(docs, debug=debug)
720
+ assert success, msg
721
+ return pipe
722
+ assert pipe.get_rowcount() == 3
File without changes
File without changes
File without changes