meerschaum 2.9.0.dev1__tar.gz → 2.9.0rc1__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 (280) hide show
  1. {meerschaum-2.9.0.dev1/meerschaum.egg-info → meerschaum-2.9.0rc1}/PKG-INFO +7 -1
  2. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/config/_default.py +1 -0
  3. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/config/_version.py +1 -1
  4. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/connectors/sql/_SQLConnector.py +3 -0
  5. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/connectors/sql/_cli.py +1 -0
  6. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/connectors/sql/_create_engine.py +51 -4
  7. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/connectors/sql/_pipes.py +13 -2
  8. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/connectors/sql/_sql.py +35 -4
  9. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/utils/dataframe.py +87 -2
  10. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/utils/dtypes/__init__.py +182 -1
  11. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/utils/dtypes/sql.py +114 -2
  12. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/utils/packages/_packages.py +2 -0
  13. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/utils/sql.py +17 -5
  14. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1/meerschaum.egg-info}/PKG-INFO +7 -1
  15. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum.egg-info/requires.txt +6 -0
  16. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/tests/test_pipes_dtypes.py +125 -0
  17. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/LICENSE +0 -0
  18. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/NOTICE +0 -0
  19. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/README.md +0 -0
  20. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/__init__.py +0 -0
  21. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/__main__.py +0 -0
  22. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/_internal/__init__.py +0 -0
  23. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/_internal/arguments/__init__.py +0 -0
  24. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/_internal/arguments/_parse_arguments.py +0 -0
  25. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/_internal/arguments/_parser.py +0 -0
  26. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/_internal/docs/__init__.py +0 -0
  27. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/_internal/docs/index.py +0 -0
  28. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/_internal/entry.py +0 -0
  29. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/_internal/gui/__init__.py +0 -0
  30. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/_internal/gui/app/__init__.py +0 -0
  31. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/_internal/gui/app/_windows.py +0 -0
  32. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/_internal/gui/app/actions.py +0 -0
  33. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/_internal/gui/app/pipes.py +0 -0
  34. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/_internal/shell/Shell.py +0 -0
  35. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/_internal/shell/ShellCompleter.py +0 -0
  36. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/_internal/shell/ValidAutoSuggest.py +0 -0
  37. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/_internal/shell/__init__.py +0 -0
  38. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/_internal/shell/resources/__init__.py +0 -0
  39. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/_internal/shell/updates.py +0 -0
  40. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/_internal/term/TermPageHandler.py +0 -0
  41. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/_internal/term/__init__.py +0 -0
  42. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/_internal/term/tools.py +0 -0
  43. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/actions/__init__.py +0 -0
  44. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/actions/api.py +0 -0
  45. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/actions/attach.py +0 -0
  46. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/actions/bootstrap.py +0 -0
  47. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/actions/clear.py +0 -0
  48. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/actions/copy.py +0 -0
  49. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/actions/deduplicate.py +0 -0
  50. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/actions/delete.py +0 -0
  51. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/actions/drop.py +0 -0
  52. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/actions/edit.py +0 -0
  53. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/actions/index.py +0 -0
  54. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/actions/install.py +0 -0
  55. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/actions/login.py +0 -0
  56. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/actions/os.py +0 -0
  57. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/actions/pause.py +0 -0
  58. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/actions/python.py +0 -0
  59. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/actions/register.py +0 -0
  60. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/actions/reload.py +0 -0
  61. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/actions/restart.py +0 -0
  62. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/actions/setup.py +0 -0
  63. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/actions/sh.py +0 -0
  64. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/actions/show.py +0 -0
  65. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/actions/sql.py +0 -0
  66. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/actions/stack.py +0 -0
  67. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/actions/start.py +0 -0
  68. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/actions/stop.py +0 -0
  69. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/actions/sync.py +0 -0
  70. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/actions/tag.py +0 -0
  71. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/actions/uninstall.py +0 -0
  72. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/actions/upgrade.py +0 -0
  73. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/actions/verify.py +0 -0
  74. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/api/__init__.py +0 -0
  75. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/api/_chain.py +0 -0
  76. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/api/_chunks.py +0 -0
  77. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/api/_events.py +0 -0
  78. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/api/_exceptions.py +0 -0
  79. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/api/_oauth2.py +0 -0
  80. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/api/_websockets.py +0 -0
  81. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/api/dash/__init__.py +0 -0
  82. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/api/dash/assets/__init__.py +0 -0
  83. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/api/dash/assets/ansi_up.js +0 -0
  84. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/api/dash/assets/banner_1920x320.png +0 -0
  85. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/api/dash/assets/favicon.ico +0 -0
  86. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/api/dash/assets/logo_48x48.png +0 -0
  87. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/api/dash/assets/logo_500x500.png +0 -0
  88. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/api/dash/callbacks/__init__.py +0 -0
  89. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/api/dash/callbacks/custom.py +0 -0
  90. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/api/dash/callbacks/dashboard.py +0 -0
  91. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/api/dash/callbacks/jobs.py +0 -0
  92. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/api/dash/callbacks/login.py +0 -0
  93. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/api/dash/callbacks/pipes.py +0 -0
  94. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/api/dash/callbacks/plugins.py +0 -0
  95. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/api/dash/callbacks/register.py +0 -0
  96. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/api/dash/components.py +0 -0
  97. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/api/dash/connectors.py +0 -0
  98. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/api/dash/graphs.py +0 -0
  99. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/api/dash/jobs.py +0 -0
  100. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/api/dash/keys.py +0 -0
  101. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/api/dash/pages/__init__.py +0 -0
  102. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/api/dash/pages/dashboard.py +0 -0
  103. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/api/dash/pages/error.py +0 -0
  104. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/api/dash/pages/job.py +0 -0
  105. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/api/dash/pages/login.py +0 -0
  106. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/api/dash/pages/pipes.py +0 -0
  107. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/api/dash/pages/plugins.py +0 -0
  108. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/api/dash/pages/register.py +0 -0
  109. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/api/dash/pipes.py +0 -0
  110. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/api/dash/plugins.py +0 -0
  111. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/api/dash/sessions.py +0 -0
  112. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/api/dash/sync.py +0 -0
  113. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/api/dash/users.py +0 -0
  114. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/api/dash/websockets.py +0 -0
  115. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/api/dash/webterm.py +0 -0
  116. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/api/models/__init__.py +0 -0
  117. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/api/models/_interfaces.py +0 -0
  118. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/api/models/_locations.py +0 -0
  119. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/api/models/_metrics.py +0 -0
  120. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/api/models/_pipes.py +0 -0
  121. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/api/resources/__init__.py +0 -0
  122. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/api/resources/static/__init__.py +0 -0
  123. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/api/resources/static/css/__init__.py +0 -0
  124. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/api/resources/static/css/bootstrap.min.css +0 -0
  125. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/api/resources/static/css/dash.css +0 -0
  126. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/api/resources/static/css/dbc_dark.css +0 -0
  127. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/api/resources/static/css/styles.css +0 -0
  128. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/api/resources/static/css/xterm.css +0 -0
  129. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/api/resources/static/ico/__init__.py +0 -0
  130. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/api/resources/static/ico/logo.ico +0 -0
  131. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/api/resources/static/js/__init__.py +0 -0
  132. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/api/resources/static/js/action_button.js +0 -0
  133. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/api/resources/static/js/main.js +0 -0
  134. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/api/resources/static/js/terminado.js +0 -0
  135. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/api/resources/static/js/xterm.js +0 -0
  136. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/api/resources/static/png/__init__.py +0 -0
  137. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/api/resources/templates/__init__.py +0 -0
  138. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/api/resources/templates/index.html +0 -0
  139. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/api/resources/templates/old_index.html +0 -0
  140. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/api/resources/templates/secret.html +0 -0
  141. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/api/resources/templates/termpage.html +0 -0
  142. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/api/routes/__init__.py +0 -0
  143. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/api/routes/_actions.py +0 -0
  144. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/api/routes/_connectors.py +0 -0
  145. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/api/routes/_index.py +0 -0
  146. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/api/routes/_jobs.py +0 -0
  147. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/api/routes/_login.py +0 -0
  148. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/api/routes/_misc.py +0 -0
  149. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/api/routes/_pipes.py +0 -0
  150. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/api/routes/_plugins.py +0 -0
  151. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/api/routes/_users.py +0 -0
  152. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/api/routes/_version.py +0 -0
  153. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/api/routes/_webterm.py +0 -0
  154. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/api/tables/__init__.py +0 -0
  155. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/config/__init__.py +0 -0
  156. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/config/_dash.py +0 -0
  157. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/config/_edit.py +0 -0
  158. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/config/_environment.py +0 -0
  159. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/config/_formatting.py +0 -0
  160. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/config/_jobs.py +0 -0
  161. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/config/_patch.py +0 -0
  162. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/config/_paths.py +0 -0
  163. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/config/_preprocess.py +0 -0
  164. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/config/_read_config.py +0 -0
  165. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/config/_shell.py +0 -0
  166. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/config/_sync.py +0 -0
  167. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/config/paths.py +0 -0
  168. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/config/resources/__init__.py +0 -0
  169. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/config/stack/__init__.py +0 -0
  170. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/config/stack/grafana/__init__.py +0 -0
  171. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/config/stack/mosquitto/__init__.py +0 -0
  172. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/config/stack/mosquitto/resources/__init__.py +0 -0
  173. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/config/stack/resources/__init__.py +0 -0
  174. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/config/static/__init__.py +0 -0
  175. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/connectors/_Connector.py +0 -0
  176. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/connectors/__init__.py +0 -0
  177. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/connectors/api/_APIConnector.py +0 -0
  178. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/connectors/api/__init__.py +0 -0
  179. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/connectors/api/_actions.py +0 -0
  180. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/connectors/api/_fetch.py +0 -0
  181. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/connectors/api/_jobs.py +0 -0
  182. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/connectors/api/_login.py +0 -0
  183. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/connectors/api/_misc.py +0 -0
  184. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/connectors/api/_pipes.py +0 -0
  185. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/connectors/api/_plugins.py +0 -0
  186. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/connectors/api/_request.py +0 -0
  187. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/connectors/api/_uri.py +0 -0
  188. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/connectors/api/_users.py +0 -0
  189. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/connectors/parse.py +0 -0
  190. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/connectors/plugin/PluginConnector.py +0 -0
  191. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/connectors/plugin/__init__.py +0 -0
  192. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/connectors/poll.py +0 -0
  193. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/connectors/sql/__init__.py +0 -0
  194. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/connectors/sql/_fetch.py +0 -0
  195. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/connectors/sql/_instance.py +0 -0
  196. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/connectors/sql/_plugins.py +0 -0
  197. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/connectors/sql/_uri.py +0 -0
  198. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/connectors/sql/_users.py +0 -0
  199. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/connectors/sql/tables/__init__.py +0 -0
  200. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/connectors/sql/tables/types.py +0 -0
  201. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/connectors/sql/tools.py +0 -0
  202. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/connectors/valkey/_ValkeyConnector.py +0 -0
  203. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/connectors/valkey/__init__.py +0 -0
  204. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/connectors/valkey/_fetch.py +0 -0
  205. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/connectors/valkey/_pipes.py +0 -0
  206. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/connectors/valkey/_plugins.py +0 -0
  207. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/connectors/valkey/_users.py +0 -0
  208. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/core/Pipe/__init__.py +0 -0
  209. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/core/Pipe/_attributes.py +0 -0
  210. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/core/Pipe/_bootstrap.py +0 -0
  211. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/core/Pipe/_clear.py +0 -0
  212. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/core/Pipe/_copy.py +0 -0
  213. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/core/Pipe/_data.py +0 -0
  214. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/core/Pipe/_deduplicate.py +0 -0
  215. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/core/Pipe/_delete.py +0 -0
  216. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/core/Pipe/_drop.py +0 -0
  217. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/core/Pipe/_dtypes.py +0 -0
  218. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/core/Pipe/_edit.py +0 -0
  219. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/core/Pipe/_fetch.py +0 -0
  220. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/core/Pipe/_index.py +0 -0
  221. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/core/Pipe/_register.py +0 -0
  222. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/core/Pipe/_show.py +0 -0
  223. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/core/Pipe/_sync.py +0 -0
  224. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/core/Pipe/_verify.py +0 -0
  225. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/core/Plugin/__init__.py +0 -0
  226. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/core/User/_User.py +0 -0
  227. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/core/User/__init__.py +0 -0
  228. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/core/__init__.py +0 -0
  229. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/jobs/_Executor.py +0 -0
  230. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/jobs/_Job.py +0 -0
  231. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/jobs/__init__.py +0 -0
  232. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/jobs/systemd.py +0 -0
  233. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/plugins/_Plugin.py +0 -0
  234. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/plugins/__init__.py +0 -0
  235. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/plugins/bootstrap.py +0 -0
  236. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/utils/__init__.py +0 -0
  237. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/utils/_get_pipes.py +0 -0
  238. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/utils/daemon/Daemon.py +0 -0
  239. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/utils/daemon/FileDescriptorInterceptor.py +0 -0
  240. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/utils/daemon/RotatingFile.py +0 -0
  241. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/utils/daemon/StdinFile.py +0 -0
  242. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/utils/daemon/__init__.py +0 -0
  243. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/utils/daemon/_names.py +0 -0
  244. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/utils/debug.py +0 -0
  245. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/utils/formatting/__init__.py +0 -0
  246. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/utils/formatting/_jobs.py +0 -0
  247. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/utils/formatting/_pipes.py +0 -0
  248. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/utils/formatting/_pprint.py +0 -0
  249. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/utils/formatting/_shell.py +0 -0
  250. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/utils/interactive.py +0 -0
  251. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/utils/misc.py +0 -0
  252. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/utils/networking.py +0 -0
  253. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/utils/packages/__init__.py +0 -0
  254. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/utils/packages/lazy_loader.py +0 -0
  255. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/utils/pool.py +0 -0
  256. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/utils/process.py +0 -0
  257. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/utils/prompt.py +0 -0
  258. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/utils/schedule.py +0 -0
  259. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/utils/threading.py +0 -0
  260. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/utils/typing.py +0 -0
  261. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/utils/venv/_Venv.py +0 -0
  262. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/utils/venv/__init__.py +0 -0
  263. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/utils/warnings.py +0 -0
  264. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum/utils/yaml.py +0 -0
  265. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum.egg-info/SOURCES.txt +0 -0
  266. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum.egg-info/dependency_links.txt +0 -0
  267. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum.egg-info/entry_points.txt +0 -0
  268. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum.egg-info/top_level.txt +0 -0
  269. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/meerschaum.egg-info/zip-safe +0 -0
  270. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/setup.cfg +0 -0
  271. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/setup.py +0 -0
  272. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/tests/test_actions.py +0 -0
  273. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/tests/test_arguments.py +0 -0
  274. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/tests/test_deduplicate.py +0 -0
  275. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/tests/test_jobs.py +0 -0
  276. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/tests/test_pipe_data.py +0 -0
  277. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/tests/test_sql.py +0 -0
  278. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/tests/test_sync.py +0 -0
  279. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/tests/test_users.py +0 -0
  280. {meerschaum-2.9.0.dev1 → meerschaum-2.9.0rc1}/tests/test_verify.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: meerschaum
3
- Version: 2.9.0.dev1
3
+ Version: 2.9.0rc1
4
4
  Summary: Sync Time-Series Pipes with Meerschaum
5
5
  Home-page: https://meerschaum.io
6
6
  Author: Bennett Meares
@@ -127,12 +127,14 @@ Provides-Extra: sql
127
127
  Requires-Dist: numpy>=1.18.5; extra == "sql"
128
128
  Requires-Dist: pandas[parquet]>=2.0.1; extra == "sql"
129
129
  Requires-Dist: geopandas>=1.0.1; extra == "sql"
130
+ Requires-Dist: shapely>=2.0.7; extra == "sql"
130
131
  Requires-Dist: pyarrow>=16.1.0; extra == "sql"
131
132
  Requires-Dist: dask[complete]>=2024.12.1; extra == "sql"
132
133
  Requires-Dist: partd>=1.4.2; extra == "sql"
133
134
  Requires-Dist: pytz; extra == "sql"
134
135
  Requires-Dist: joblib>=0.17.0; extra == "sql"
135
136
  Requires-Dist: SQLAlchemy>=2.0.5; extra == "sql"
137
+ Requires-Dist: GeoAlchemy2>=0.17.1; extra == "sql"
136
138
  Requires-Dist: databases>=0.4.0; extra == "sql"
137
139
  Requires-Dist: aiosqlite>=0.16.0; extra == "sql"
138
140
  Requires-Dist: asyncpg>=0.21.0; extra == "sql"
@@ -188,12 +190,14 @@ Requires-Dist: valkey>=6.0.0; extra == "api"
188
190
  Requires-Dist: numpy>=1.18.5; extra == "api"
189
191
  Requires-Dist: pandas[parquet]>=2.0.1; extra == "api"
190
192
  Requires-Dist: geopandas>=1.0.1; extra == "api"
193
+ Requires-Dist: shapely>=2.0.7; extra == "api"
191
194
  Requires-Dist: pyarrow>=16.1.0; extra == "api"
192
195
  Requires-Dist: dask[complete]>=2024.12.1; extra == "api"
193
196
  Requires-Dist: partd>=1.4.2; extra == "api"
194
197
  Requires-Dist: pytz; extra == "api"
195
198
  Requires-Dist: joblib>=0.17.0; extra == "api"
196
199
  Requires-Dist: SQLAlchemy>=2.0.5; extra == "api"
200
+ Requires-Dist: GeoAlchemy2>=0.17.1; extra == "api"
197
201
  Requires-Dist: databases>=0.4.0; extra == "api"
198
202
  Requires-Dist: aiosqlite>=0.16.0; extra == "api"
199
203
  Requires-Dist: asyncpg>=0.21.0; extra == "api"
@@ -294,12 +298,14 @@ Requires-Dist: pycparser>=2.21.0; extra == "full"
294
298
  Requires-Dist: numpy>=1.18.5; extra == "full"
295
299
  Requires-Dist: pandas[parquet]>=2.0.1; extra == "full"
296
300
  Requires-Dist: geopandas>=1.0.1; extra == "full"
301
+ Requires-Dist: shapely>=2.0.7; extra == "full"
297
302
  Requires-Dist: pyarrow>=16.1.0; extra == "full"
298
303
  Requires-Dist: dask[complete]>=2024.12.1; extra == "full"
299
304
  Requires-Dist: partd>=1.4.2; extra == "full"
300
305
  Requires-Dist: pytz; extra == "full"
301
306
  Requires-Dist: joblib>=0.17.0; extra == "full"
302
307
  Requires-Dist: SQLAlchemy>=2.0.5; extra == "full"
308
+ Requires-Dist: GeoAlchemy2>=0.17.1; extra == "full"
303
309
  Requires-Dist: databases>=0.4.0; extra == "full"
304
310
  Requires-Dist: aiosqlite>=0.16.0; extra == "full"
305
311
  Requires-Dist: asyncpg>=0.21.0; extra == "full"
@@ -70,6 +70,7 @@ default_system_config = {
70
70
  'sql': {
71
71
  'bulk_insert': {
72
72
  'postgresql': True,
73
+ 'postgis': True,
73
74
  'citus': True,
74
75
  'timescaledb': True,
75
76
  'mssql': True,
@@ -2,4 +2,4 @@
2
2
  Specify the Meerschaum release version.
3
3
  """
4
4
 
5
- __version__ = "2.9.0.dev1"
5
+ __version__ = "2.9.0rc1"
@@ -151,6 +151,9 @@ class SQLConnector(Connector):
151
151
  if uri.startswith('timescaledb://'):
152
152
  uri = uri.replace('timescaledb://', 'postgresql+psycopg://', 1)
153
153
  flavor = 'timescaledb'
154
+ if uri.startswith('postgis://'):
155
+ uri = uri.replace('postgis://', 'postgresql+psycopg://', 1)
156
+ flavor = 'postgis'
154
157
  kw['uri'] = uri
155
158
  from_uri_params = self.from_uri(kw['uri'], as_dict=True)
156
159
  label = label or from_uri_params.get('label', None)
@@ -15,6 +15,7 @@ from meerschaum.utils.typing import SuccessTuple
15
15
 
16
16
  flavor_clis = {
17
17
  'postgresql' : 'pgcli',
18
+ 'postgis' : 'pgcli',
18
19
  'timescaledb' : 'pgcli',
19
20
  'cockroachdb' : 'pgcli',
20
21
  'citus' : 'pgcli',
@@ -7,6 +7,7 @@ This module contains the logic that builds the sqlalchemy engine string.
7
7
  """
8
8
 
9
9
  import traceback
10
+ import meerschaum as mrsm
10
11
  from meerschaum.utils.debug import dprint
11
12
 
12
13
  ### determine driver and requirements from flavor
@@ -47,6 +48,16 @@ flavor_configs = {
47
48
  'port': 5432,
48
49
  },
49
50
  },
51
+ 'postgis': {
52
+ 'engine': 'postgresql+psycopg',
53
+ 'create_engine': default_create_engine_args,
54
+ 'omit_create_engine': {'method',},
55
+ 'to_sql': {},
56
+ 'requirements': default_requirements,
57
+ 'defaults': {
58
+ 'port': 5432,
59
+ },
60
+ },
50
61
  'citus': {
51
62
  'engine': 'postgresql+psycopg',
52
63
  'create_engine': default_create_engine_args,
@@ -162,6 +173,7 @@ install_flavor_drivers = {
162
173
  'mariadb': ['pymysql'],
163
174
  'timescaledb': ['psycopg'],
164
175
  'postgresql': ['psycopg'],
176
+ 'postgis': ['psycopg', 'geoalchemy'],
165
177
  'citus': ['psycopg'],
166
178
  'cockroachdb': ['psycopg', 'sqlalchemy_cockroachdb', 'sqlalchemy_cockroachdb.psycopg'],
167
179
  'mssql': ['pyodbc'],
@@ -198,8 +210,7 @@ def create_engine(
198
210
  warn=False,
199
211
  )
200
212
  if self.flavor == 'mssql':
201
- pyodbc = attempt_import('pyodbc', debug=debug, lazy=False, warn=False)
202
- pyodbc.pooling = False
213
+ _init_mssql_sqlalchemy()
203
214
  if self.flavor in require_patching_flavors:
204
215
  from meerschaum.utils.packages import determine_version, _monkey_patch_get_distribution
205
216
  import pathlib
@@ -257,8 +268,8 @@ def create_engine(
257
268
 
258
269
  ### Sometimes the timescaledb:// flavor can slip in.
259
270
  if _uri and self.flavor in _uri:
260
- if self.flavor == 'timescaledb':
261
- engine_str = engine_str.replace(f'{self.flavor}', 'postgresql', 1)
271
+ if self.flavor in ('timescaledb', 'postgis'):
272
+ engine_str = engine_str.replace(self.flavor, 'postgresql', 1)
262
273
  elif _uri.startswith('postgresql://'):
263
274
  engine_str = engine_str.replace('postgresql://', 'postgresql+psycopg2://')
264
275
 
@@ -313,3 +324,39 @@ def create_engine(
313
324
  if include_uri:
314
325
  return engine, engine_str
315
326
  return engine
327
+
328
+
329
+ def _init_mssql_sqlalchemy():
330
+ """
331
+ When first instantiating a SQLAlchemy connection to MSSQL,
332
+ monkey-patch `pyodbc` handling in SQLAlchemy.
333
+ """
334
+ pyodbc, sqlalchemy_dialects_mssql_pyodbc = mrsm.attempt_import(
335
+ 'pyodbc',
336
+ 'sqlalchemy.dialects.mssql.pyodbc',
337
+ lazy=False,
338
+ warn=False,
339
+ )
340
+ pyodbc.pooling = False
341
+
342
+ MSDialect_pyodbc = sqlalchemy_dialects_mssql_pyodbc.MSDialect_pyodbc
343
+
344
+ def _handle_geometry(val):
345
+ from binascii import hexlify
346
+ hex_str = f"0x{hexlify(val).decode().upper()}"
347
+ return hex_str
348
+
349
+ def custom_on_connect(self):
350
+ super_ = super(MSDialect_pyodbc, self).on_connect()
351
+
352
+ def _on_connect(conn):
353
+ if super_ is not None:
354
+ super_(conn)
355
+
356
+ self._setup_timestampoffset_type(conn)
357
+ conn.add_output_converter(-151, _handle_geometry)
358
+
359
+ return _on_connect
360
+
361
+ ### TODO: Parse proprietary MSSQL geometry bytes into WKB.
362
+ # MSDialect_pyodbc.on_connect = custom_on_connect
@@ -731,7 +731,7 @@ def get_create_index_queries(
731
731
  ) + f"{primary_key_name})"
732
732
  ),
733
733
  ])
734
- elif self.flavor in ('citus', 'postgresql', 'duckdb'):
734
+ elif self.flavor in ('citus', 'postgresql', 'duckdb', 'postgis'):
735
735
  primary_queries.extend([
736
736
  (
737
737
  f"ALTER TABLE {_pipe_name}\n"
@@ -1052,6 +1052,7 @@ def get_pipe_data(
1052
1052
  attempt_cast_to_numeric,
1053
1053
  attempt_cast_to_uuid,
1054
1054
  attempt_cast_to_bytes,
1055
+ attempt_cast_to_geometry,
1055
1056
  are_dtypes_equal,
1056
1057
  )
1057
1058
  from meerschaum.utils.dtypes.sql import get_pd_type_from_db_type
@@ -1138,6 +1139,11 @@ def get_pipe_data(
1138
1139
  for col, typ in pipe.dtypes.items()
1139
1140
  if typ == 'bytes' and col in dtypes
1140
1141
  ]
1142
+ geometry_columns = [
1143
+ col
1144
+ for col, typ in pipe.dtypes.items()
1145
+ if typ.startswith('geometry') and col in dtypes
1146
+ ]
1141
1147
 
1142
1148
  kw['coerce_float'] = kw.get('coerce_float', (len(numeric_columns) == 0))
1143
1149
 
@@ -1162,6 +1168,11 @@ def get_pipe_data(
1162
1168
  continue
1163
1169
  df[col] = df[col].apply(attempt_cast_to_bytes)
1164
1170
 
1171
+ for col in geometry_columns:
1172
+ if col not in df.columns:
1173
+ continue
1174
+ df[col] = df[col].apply(attempt_cast_to_geometry)
1175
+
1165
1176
  if self.flavor == 'sqlite':
1166
1177
  ignore_dt_cols = [
1167
1178
  col
@@ -1511,7 +1522,7 @@ def get_pipe_attributes(
1511
1522
  if isinstance(parameters, str) and parameters[0] == '{':
1512
1523
  parameters = json.loads(parameters)
1513
1524
  attributes['parameters'] = parameters
1514
- except Exception as e:
1525
+ except Exception:
1515
1526
  attributes['parameters'] = {}
1516
1527
 
1517
1528
  return attributes
@@ -17,7 +17,7 @@ from meerschaum.utils.debug import dprint
17
17
  from meerschaum.utils.warnings import warn
18
18
 
19
19
  ### database flavors that can use bulk insert
20
- _bulk_flavors = {'postgresql', 'timescaledb', 'citus', 'mssql'}
20
+ _bulk_flavors = {'postgresql', 'postgis', 'timescaledb', 'citus', 'mssql'}
21
21
  ### flavors that do not support chunks
22
22
  _disallow_chunks_flavors = ['duckdb']
23
23
  _max_chunks_flavors = {'sqlite': 1000}
@@ -798,6 +798,7 @@ def to_sql(
798
798
  get_numeric_cols,
799
799
  get_uuid_cols,
800
800
  get_bytes_cols,
801
+ get_geometry_cols,
801
802
  )
802
803
  from meerschaum.utils.dtypes import (
803
804
  are_dtypes_equal,
@@ -805,7 +806,9 @@ def to_sql(
805
806
  encode_bytes_for_bytea,
806
807
  serialize_bytes,
807
808
  serialize_decimal,
809
+ serialize_geometry,
808
810
  json_serialize_value,
811
+ get_geometry_type_srid,
809
812
  )
810
813
  from meerschaum.utils.dtypes.sql import (
811
814
  PD_TO_SQLALCHEMY_DTYPES_FLAVORS,
@@ -822,6 +825,7 @@ def to_sql(
822
825
 
823
826
  bytes_cols = get_bytes_cols(df)
824
827
  numeric_cols = get_numeric_cols(df)
828
+ geometry_cols = get_geometry_cols(df)
825
829
  ### NOTE: This excludes non-numeric serialized Decimals (e.g. SQLite).
826
830
  numeric_cols_dtypes = {
827
831
  col: typ
@@ -830,7 +834,6 @@ def to_sql(
830
834
  col in df.columns
831
835
  and 'numeric' in str(typ).lower()
832
836
  )
833
-
834
837
  }
835
838
  numeric_cols.extend([col for col in numeric_cols_dtypes if col not in numeric_cols])
836
839
  numeric_cols_precisions_scales = {
@@ -841,6 +844,22 @@ def to_sql(
841
844
  )
842
845
  for col, typ in numeric_cols_dtypes.items()
843
846
  }
847
+ geometry_cols_dtypes = {
848
+ col: typ
849
+ for col, typ in kw.get('dtype', {}).items()
850
+ if (
851
+ col in df.columns
852
+ and 'geometry' in str(typ).lower() or 'geography' in str(typ).lower()
853
+ )
854
+ }
855
+ geometry_cols.extend([col for col in geometry_cols_dtypes if col not in geometry_cols])
856
+ geometry_cols_types_srids = {
857
+ col: (typ.geometry_type, typ.srid)
858
+ if hasattr(typ, 'srid')
859
+ else get_geometry_type_srid()
860
+ for col, typ in geometry_cols_dtypes.items()
861
+ }
862
+
844
863
  cols_pd_types = {
845
864
  col: get_pd_type_from_db_type(str(typ))
846
865
  for col, typ in kw.get('dtype', {}).items()
@@ -856,8 +875,9 @@ def to_sql(
856
875
  }
857
876
 
858
877
  enable_bulk_insert = mrsm.get_config(
859
- 'system', 'connectors', 'sql', 'bulk_insert'
860
- ).get(self.flavor, False)
878
+ 'system', 'connectors', 'sql', 'bulk_insert', self.flavor,
879
+ warn=False,
880
+ ) or False
861
881
  stats = {'target': name}
862
882
  ### resort to defaults if None
863
883
  copied = False
@@ -901,6 +921,17 @@ def to_sql(
901
921
  )
902
922
  )
903
923
 
924
+ for col in geometry_cols:
925
+ geometry_type, srid = geometry_cols_types_srids.get(col, get_geometry_type_srid())
926
+ with warnings.catch_warnings():
927
+ warnings.simplefilter("ignore")
928
+ df[col] = df[col].apply(
929
+ functools.partial(
930
+ serialize_geometry,
931
+ as_wkt=(self.flavor == 'mssql')
932
+ )
933
+ )
934
+
904
935
  stats['method'] = method.__name__ if hasattr(method, '__name__') else str(method)
905
936
 
906
937
  default_chunksize = self._sys_config.get('chunksize', None)
@@ -153,6 +153,7 @@ def filter_unseen_df(
153
153
  attempt_cast_to_numeric,
154
154
  attempt_cast_to_uuid,
155
155
  attempt_cast_to_bytes,
156
+ attempt_cast_to_geometry,
156
157
  coerce_timezone,
157
158
  serialize_decimal,
158
159
  )
@@ -350,6 +351,10 @@ def filter_unseen_df(
350
351
  new_bytes_cols = get_bytes_cols(new_df)
351
352
  bytes_cols = set(new_bytes_cols + old_bytes_cols)
352
353
 
354
+ old_geometry_cols = get_geometry_cols(old_df)
355
+ new_geometry_cols = get_geometry_cols(new_df)
356
+ geometry_cols = set(new_geometry_cols + old_geometry_cols)
357
+
353
358
  joined_df = merge(
354
359
  new_df.infer_objects(copy=False).fillna(NA),
355
360
  old_df.infer_objects(copy=False).fillna(NA),
@@ -400,6 +405,14 @@ def filter_unseen_df(
400
405
  except Exception:
401
406
  warn(f"Unable to parse bytes column '{bytes_col}':\n{traceback.format_exc()}")
402
407
 
408
+ for geometry_col in geometry_cols:
409
+ if geometry_col not in delta_df.columns:
410
+ continue
411
+ try:
412
+ delta_df[geometry_col] = delta_df[geometry_col].apply(attempt_cast_to_geometry)
413
+ except Exception:
414
+ warn(f"Unable to parse bytes column '{bytes_col}':\n{traceback.format_exc()}")
415
+
403
416
  return delta_df
404
417
 
405
418
 
@@ -858,6 +871,44 @@ def get_bytes_cols(df: 'pd.DataFrame') -> List[str]:
858
871
  ]
859
872
 
860
873
 
874
+ def get_geometry_cols(df: 'pd.DataFrame') -> List[str]:
875
+ """
876
+ Get the columns which contain shapely objects from a Pandas DataFrame.
877
+
878
+ Parameters
879
+ ----------
880
+ df: pd.DataFrame
881
+ The DataFrame which may contain bytes strings.
882
+
883
+ Returns
884
+ -------
885
+ A list of columns to treat as `geometry`.
886
+ """
887
+ if df is None:
888
+ return []
889
+
890
+ is_dask = 'dask' in df.__module__
891
+ if is_dask:
892
+ df = get_first_valid_dask_partition(df)
893
+
894
+ if len(df) == 0:
895
+ return []
896
+
897
+ cols_indices = {
898
+ col: df[col].first_valid_index()
899
+ for col in df.columns
900
+ }
901
+ return [
902
+ col
903
+ for col, ix in cols_indices.items()
904
+ if (
905
+ ix is not None
906
+ and
907
+ 'shapely' in str(type(df.loc[ix][col]))
908
+ )
909
+ ]
910
+
911
+
861
912
  def enforce_dtypes(
862
913
  df: 'pd.DataFrame',
863
914
  dtypes: Dict[str, str],
@@ -911,6 +962,7 @@ def enforce_dtypes(
911
962
  attempt_cast_to_numeric,
912
963
  attempt_cast_to_uuid,
913
964
  attempt_cast_to_bytes,
965
+ attempt_cast_to_geometry,
914
966
  coerce_timezone as _coerce_timezone,
915
967
  )
916
968
  from meerschaum.utils.dtypes.sql import get_numeric_precision_scale
@@ -937,6 +989,11 @@ def enforce_dtypes(
937
989
  for col, typ in dtypes.items()
938
990
  if typ.startswith('numeric')
939
991
  ]
992
+ geometry_cols = [
993
+ col
994
+ for col, typ in dtypes.items()
995
+ if typ.startswith('geometry') or typ.startswith('geography')
996
+ ]
940
997
  uuid_cols = [
941
998
  col
942
999
  for col, typ in dtypes.items()
@@ -1026,6 +1083,24 @@ def enforce_dtypes(
1026
1083
  if col in df.columns:
1027
1084
  df[col] = _coerce_timezone(df[col], strip_utc=strip_timezone)
1028
1085
 
1086
+ if geometry_cols:
1087
+ geopandas = mrsm.attempt_import('geopandas')
1088
+ if debug:
1089
+ dprint(f"Checking for geometry: {geometry_cols}")
1090
+ parsed_geom_cols = []
1091
+ for col in geometry_cols:
1092
+ try:
1093
+ df[col] = df[col].apply(attempt_cast_to_geometry)
1094
+ parsed_geom_cols.append(col)
1095
+ except Exception as e:
1096
+ if debug:
1097
+ dprint(f"Unable to parse column '{col}' as geometry:\n{e}")
1098
+
1099
+ if parsed_geom_cols:
1100
+ if debug:
1101
+ dprint(f"Converting to GeoDataFrame (geometry column: '{parsed_geom_cols[0]}')...")
1102
+ df = geopandas.GeoDataFrame(df, geometry=parsed_geom_cols[0])
1103
+
1029
1104
  df_dtypes = {c: str(t) for c, t in df.dtypes.items()}
1030
1105
  if are_dtypes_equal(df_dtypes, pipe_pandas_dtypes):
1031
1106
  if debug:
@@ -1602,13 +1677,19 @@ def to_json(
1602
1677
  -------
1603
1678
  A JSON string.
1604
1679
  """
1680
+ import warnings
1605
1681
  from meerschaum.utils.packages import import_pandas
1606
- from meerschaum.utils.dtypes import serialize_bytes, serialize_decimal
1682
+ from meerschaum.utils.dtypes import (
1683
+ serialize_bytes,
1684
+ serialize_decimal,
1685
+ serialize_geometry,
1686
+ )
1607
1687
  pd = import_pandas()
1608
1688
  uuid_cols = get_uuid_cols(df)
1609
1689
  bytes_cols = get_bytes_cols(df)
1610
1690
  numeric_cols = get_numeric_cols(df)
1611
- if safe_copy and bool(uuid_cols or bytes_cols):
1691
+ geometry_cols = get_geometry_cols(df)
1692
+ if safe_copy and bool(uuid_cols or bytes_cols or geometry_cols or numeric_cols):
1612
1693
  df = df.copy()
1613
1694
  for col in uuid_cols:
1614
1695
  df[col] = df[col].astype(str)
@@ -1616,6 +1697,10 @@ def to_json(
1616
1697
  df[col] = df[col].apply(serialize_bytes)
1617
1698
  for col in numeric_cols:
1618
1699
  df[col] = df[col].apply(serialize_decimal)
1700
+ with warnings.catch_warnings():
1701
+ warnings.simplefilter("ignore")
1702
+ for col in geometry_cols:
1703
+ df[col] = df[col].apply(serialize_geometry)
1619
1704
  return df.infer_objects(copy=False).fillna(pd.NA).to_json(
1620
1705
  date_format=date_format,
1621
1706
  date_unit=date_unit,