streamwright 0.1.8__tar.gz → 0.1.10__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 (258) hide show
  1. streamwright-0.1.10/PKG-INFO +93 -0
  2. streamwright-0.1.10/README.md +65 -0
  3. {streamwright-0.1.8 → streamwright-0.1.10}/pyproject.toml +23 -13
  4. {streamwright-0.1.8 → streamwright-0.1.10}/src/streamwright/core/catalog.py +24 -11
  5. streamwright-0.1.10/src/streamwright/core/cli/__init__.py +5 -0
  6. streamwright-0.1.10/src/streamwright/core/cli/__main__.py +5 -0
  7. streamwright-0.1.10/src/streamwright/core/cli/commands/__init__.py +1 -0
  8. streamwright-0.1.10/src/streamwright/core/cli/commands/connectors.py +173 -0
  9. streamwright-0.1.10/src/streamwright/core/cli/commands/jobs.py +27 -0
  10. streamwright-0.1.10/src/streamwright/core/cli/commands/source.py +307 -0
  11. streamwright-0.1.10/src/streamwright/core/cli/jobs.py +47 -0
  12. streamwright-0.1.10/src/streamwright/core/cli/log_options.py +122 -0
  13. streamwright-0.1.10/src/streamwright/core/cli/main.py +176 -0
  14. streamwright-0.1.10/src/streamwright/core/cli/parser.py +138 -0
  15. {streamwright-0.1.8 → streamwright-0.1.10}/src/streamwright/core/config/inputs.py +25 -17
  16. {streamwright-0.1.8 → streamwright-0.1.10}/src/streamwright/core/config/loader.py +29 -10
  17. {streamwright-0.1.8 → streamwright-0.1.10}/src/streamwright/core/config/reader.py +1 -1
  18. streamwright-0.1.10/src/streamwright/core/engine/bookmarks.py +48 -0
  19. streamwright-0.1.10/src/streamwright/core/engine/builders.py +26 -0
  20. streamwright-0.1.10/src/streamwright/core/engine/errors.py +7 -0
  21. streamwright-0.1.10/src/streamwright/core/engine/execution.py +188 -0
  22. streamwright-0.1.10/src/streamwright/core/engine/factories.py +82 -0
  23. streamwright-0.1.10/src/streamwright/core/engine/partitions.py +187 -0
  24. streamwright-0.1.10/src/streamwright/core/engine/planning.py +71 -0
  25. {streamwright-0.1.8 → streamwright-0.1.10}/src/streamwright/core/engine/queries.py +12 -12
  26. streamwright-0.1.10/src/streamwright/core/engine/readers.py +218 -0
  27. streamwright-0.1.10/src/streamwright/core/engine/responses.py +48 -0
  28. streamwright-0.1.10/src/streamwright/core/engine/rules.py +29 -0
  29. streamwright-0.1.10/src/streamwright/core/engine/runner.py +318 -0
  30. streamwright-0.1.10/src/streamwright/core/engine/session.py +44 -0
  31. streamwright-0.1.10/src/streamwright/core/engine/sql/__init__.py +85 -0
  32. streamwright-0.1.10/src/streamwright/core/engine/sql/compilation.py +255 -0
  33. streamwright-0.1.10/src/streamwright/core/engine/sql/list_parameters.py +82 -0
  34. streamwright-0.1.10/src/streamwright/core/engine/sql/ordering.py +115 -0
  35. streamwright-0.1.10/src/streamwright/core/engine/sql/plans.py +167 -0
  36. streamwright-0.1.10/src/streamwright/core/engine/sql/sandbox.py +384 -0
  37. streamwright-0.1.10/src/streamwright/core/engine/sql/stream_plan.py +86 -0
  38. streamwright-0.1.10/src/streamwright/core/engine/sql/tables.py +145 -0
  39. streamwright-0.1.10/src/streamwright/core/engine/sql/types.py +182 -0
  40. streamwright-0.1.10/src/streamwright/core/engine/values.py +67 -0
  41. streamwright-0.1.10/src/streamwright/core/engine/writers.py +32 -0
  42. streamwright-0.1.10/src/streamwright/core/graph.py +60 -0
  43. streamwright-0.1.10/src/streamwright/core/io/__init__.py +9 -0
  44. streamwright-0.1.10/src/streamwright/core/io/api_calls.py +52 -0
  45. streamwright-0.1.10/src/streamwright/core/io/capabilities.py +17 -0
  46. streamwright-0.1.10/src/streamwright/core/io/database_connections.py +213 -0
  47. streamwright-0.1.10/src/streamwright/core/io/database_rules.py +130 -0
  48. streamwright-0.1.10/src/streamwright/core/io/databases.py +290 -0
  49. streamwright-0.1.10/src/streamwright/core/io/file_formats.py +189 -0
  50. streamwright-0.1.10/src/streamwright/core/io/file_rules.py +84 -0
  51. streamwright-0.1.10/src/streamwright/core/io/files.py +388 -0
  52. streamwright-0.1.10/src/streamwright/core/io/http.py +19 -0
  53. streamwright-0.1.10/src/streamwright/core/io/local.py +181 -0
  54. streamwright-0.1.10/src/streamwright/core/io/locations.py +358 -0
  55. streamwright-0.1.10/src/streamwright/core/io/queries.py +344 -0
  56. streamwright-0.1.10/src/streamwright/core/io/sandbox.py +144 -0
  57. streamwright-0.1.10/src/streamwright/core/io/store_reader.py +180 -0
  58. streamwright-0.1.10/src/streamwright/core/jobs/__init__.py +112 -0
  59. streamwright-0.1.10/src/streamwright/core/jobs/calls.py +123 -0
  60. streamwright-0.1.10/src/streamwright/core/jobs/check/__init__.py +41 -0
  61. streamwright-0.1.10/src/streamwright/core/jobs/check/connections.py +28 -0
  62. streamwright-0.1.10/src/streamwright/core/jobs/check/dependencies.py +34 -0
  63. streamwright-0.1.10/src/streamwright/core/jobs/check/findings.py +60 -0
  64. streamwright-0.1.10/src/streamwright/core/jobs/check/names.py +43 -0
  65. streamwright-0.1.10/src/streamwright/core/jobs/check/outputs.py +53 -0
  66. streamwright-0.1.10/src/streamwright/core/jobs/check/refs.py +68 -0
  67. streamwright-0.1.10/src/streamwright/core/jobs/check/rules.py +124 -0
  68. streamwright-0.1.10/src/streamwright/core/jobs/check/runtime.py +37 -0
  69. streamwright-0.1.10/src/streamwright/core/jobs/check/secrets.py +83 -0
  70. streamwright-0.1.10/src/streamwright/core/jobs/check/sections.py +35 -0
  71. streamwright-0.1.10/src/streamwright/core/jobs/check/spec.py +70 -0
  72. streamwright-0.1.10/src/streamwright/core/jobs/check/steps.py +48 -0
  73. streamwright-0.1.10/src/streamwright/core/jobs/check/structure.py +27 -0
  74. streamwright-0.1.10/src/streamwright/core/jobs/duckdb/__init__.py +52 -0
  75. streamwright-0.1.10/src/streamwright/core/jobs/duckdb/adapter.py +173 -0
  76. streamwright-0.1.10/src/streamwright/core/jobs/duckdb/cli.py +209 -0
  77. streamwright-0.1.10/src/streamwright/core/jobs/duckdb/definition_adapter.py +162 -0
  78. streamwright-0.1.10/src/streamwright/core/jobs/duckdb/engine.py +276 -0
  79. streamwright-0.1.10/src/streamwright/core/jobs/duckdb/executor.py +177 -0
  80. streamwright-0.1.10/src/streamwright/core/jobs/duckdb/guide.md +133 -0
  81. streamwright-0.1.10/src/streamwright/core/jobs/duckdb/loading.py +35 -0
  82. streamwright-0.1.10/src/streamwright/core/jobs/duckdb/plugin.py +61 -0
  83. streamwright-0.1.10/src/streamwright/core/jobs/duckdb/reads.py +249 -0
  84. streamwright-0.1.10/src/streamwright/core/jobs/duckdb/rules.py +267 -0
  85. streamwright-0.1.10/src/streamwright/core/jobs/duckdb/session.py +162 -0
  86. streamwright-0.1.10/src/streamwright/core/jobs/duckdb/steps.py +220 -0
  87. streamwright-0.1.10/src/streamwright/core/jobs/duckdb/writers/__init__.py +23 -0
  88. streamwright-0.1.10/src/streamwright/core/jobs/duckdb/writers/tables.py +82 -0
  89. streamwright-0.1.10/src/streamwright/core/jobs/engine.py +76 -0
  90. streamwright-0.1.10/src/streamwright/core/jobs/fields.py +163 -0
  91. streamwright-0.1.10/src/streamwright/core/jobs/ingest/__init__.py +80 -0
  92. streamwright-0.1.10/src/streamwright/core/jobs/ingest/column_rules.py +163 -0
  93. streamwright-0.1.10/src/streamwright/core/jobs/ingest/formats.py +68 -0
  94. streamwright-0.1.10/src/streamwright/core/jobs/ingest/headers.py +85 -0
  95. streamwright-0.1.10/src/streamwright/core/jobs/ingest/mapped.py +200 -0
  96. streamwright-0.1.10/src/streamwright/core/jobs/ingest/model.py +148 -0
  97. streamwright-0.1.10/src/streamwright/core/jobs/ingest/plain.py +117 -0
  98. streamwright-0.1.10/src/streamwright/core/jobs/inputs.py +102 -0
  99. streamwright-0.1.10/src/streamwright/core/jobs/manifest.py +139 -0
  100. streamwright-0.1.10/src/streamwright/core/jobs/naming.py +292 -0
  101. streamwright-0.1.10/src/streamwright/core/jobs/plan.py +106 -0
  102. streamwright-0.1.10/src/streamwright/core/jobs/policy.py +198 -0
  103. streamwright-0.1.10/src/streamwright/core/jobs/refs.py +212 -0
  104. streamwright-0.1.10/src/streamwright/core/jobs/runner.py +308 -0
  105. streamwright-0.1.10/src/streamwright/core/jobs/schema.py +33 -0
  106. streamwright-0.1.10/src/streamwright/core/jobs/state/__init__.py +65 -0
  107. streamwright-0.1.10/src/streamwright/core/jobs/state/dialects.py +119 -0
  108. streamwright-0.1.10/src/streamwright/core/jobs/state/migrations.py +85 -0
  109. streamwright-0.1.10/src/streamwright/core/jobs/state/protocol.py +95 -0
  110. streamwright-0.1.10/src/streamwright/core/jobs/state/store.py +397 -0
  111. streamwright-0.1.10/src/streamwright/core/jobs/types.py +190 -0
  112. streamwright-0.1.10/src/streamwright/core/jobs/validate.py +126 -0
  113. streamwright-0.1.10/src/streamwright/core/jobs/write_rules.py +254 -0
  114. streamwright-0.1.10/src/streamwright/core/net/auth.py +106 -0
  115. {streamwright-0.1.8 → streamwright-0.1.10}/src/streamwright/core/net/downloads.py +5 -6
  116. {streamwright-0.1.8 → streamwright-0.1.10}/src/streamwright/core/net/encoding.py +4 -4
  117. streamwright-0.1.10/src/streamwright/core/net/errors.py +27 -0
  118. streamwright-0.1.10/src/streamwright/core/net/http.py +370 -0
  119. {streamwright-0.1.8 → streamwright-0.1.10}/src/streamwright/core/net/paginators.py +42 -47
  120. streamwright-0.1.10/src/streamwright/core/net/policies.py +113 -0
  121. streamwright-0.1.10/src/streamwright/core/outputs/base.py +88 -0
  122. streamwright-0.1.10/src/streamwright/core/outputs/dlt_columns.py +43 -0
  123. {streamwright-0.1.8 → streamwright-0.1.10}/src/streamwright/core/outputs/dlt_output.py +40 -101
  124. streamwright-0.1.10/src/streamwright/core/outputs/ducklake.py +231 -0
  125. streamwright-0.1.10/src/streamwright/core/outputs/file_names.py +162 -0
  126. streamwright-0.1.10/src/streamwright/core/outputs/files.py +267 -0
  127. streamwright-0.1.10/src/streamwright/core/outputs/loading.py +36 -0
  128. streamwright-0.1.10/src/streamwright/core/outputs/output.py +194 -0
  129. {streamwright-0.1.8 → streamwright-0.1.10}/src/streamwright/core/outputs/staging.py +37 -28
  130. {streamwright-0.1.8 → streamwright-0.1.10}/src/streamwright/core/outputs/warehouse.py +58 -232
  131. streamwright-0.1.10/src/streamwright/core/runtime/components.py +342 -0
  132. streamwright-0.1.10/src/streamwright/core/runtime/connector_types.py +113 -0
  133. streamwright-0.1.10/src/streamwright/core/runtime/constants.py +4 -0
  134. streamwright-0.1.10/src/streamwright/core/runtime/contract.py +344 -0
  135. streamwright-0.1.10/src/streamwright/core/runtime/contract_declarations.py +253 -0
  136. streamwright-0.1.10/src/streamwright/core/runtime/contract_guide.py +107 -0
  137. streamwright-0.1.10/src/streamwright/core/runtime/contract_terms.py +73 -0
  138. streamwright-0.1.10/src/streamwright/core/runtime/contract_validation.py +308 -0
  139. streamwright-0.1.10/src/streamwright/core/runtime/definitions.py +106 -0
  140. streamwright-0.1.10/src/streamwright/core/runtime/logs/__init__.py +90 -0
  141. streamwright-0.1.10/src/streamwright/core/runtime/logs/formatting.py +79 -0
  142. streamwright-0.1.10/src/streamwright/core/runtime/logs/handlers.py +125 -0
  143. streamwright-0.1.10/src/streamwright/core/runtime/logs/lines.py +91 -0
  144. streamwright-0.1.10/src/streamwright/core/runtime/logs/metrics.py +227 -0
  145. streamwright-0.1.10/src/streamwright/core/runtime/logs/network.py +103 -0
  146. streamwright-0.1.10/src/streamwright/core/runtime/logs/record_factory.py +84 -0
  147. streamwright-0.1.10/src/streamwright/core/runtime/logs/redaction.py +91 -0
  148. streamwright-0.1.10/src/streamwright/core/runtime/logs/setup.py +186 -0
  149. streamwright-0.1.10/src/streamwright/core/runtime/logs/summary.py +38 -0
  150. streamwright-0.1.10/src/streamwright/core/runtime/plugins.py +108 -0
  151. streamwright-0.1.10/src/streamwright/core/runtime/redact.py +31 -0
  152. streamwright-0.1.10/src/streamwright/core/runtime/source_connectors.py +105 -0
  153. {streamwright-0.1.8 → streamwright-0.1.10}/src/streamwright/core/runtime/templates.py +22 -13
  154. {streamwright-0.1.8 → streamwright-0.1.10}/src/streamwright/core/runtime/testing.py +6 -7
  155. streamwright-0.1.10/src/streamwright/core/sdk/__init__.py +33 -0
  156. streamwright-0.1.10/src/streamwright/core/sdk/constants.py +5 -0
  157. streamwright-0.1.10/src/streamwright/core/sdk/contract.py +41 -0
  158. streamwright-0.1.10/src/streamwright/core/sdk/engines/__init__.py +1 -0
  159. streamwright-0.1.10/src/streamwright/core/sdk/engines/duckdb.py +49 -0
  160. streamwright-0.1.10/src/streamwright/core/sdk/engines/source.py +32 -0
  161. streamwright-0.1.10/src/streamwright/core/sdk/messaging.py +43 -0
  162. streamwright-0.1.10/src/streamwright/core/sdk/network.py +9 -0
  163. streamwright-0.1.10/src/streamwright/core/sdk/operations/__init__.py +10 -0
  164. streamwright-0.1.10/src/streamwright/core/sdk/operations/databases.py +65 -0
  165. streamwright-0.1.10/src/streamwright/core/sdk/operations/files.py +74 -0
  166. streamwright-0.1.10/src/streamwright/core/sdk/operations/http.py +74 -0
  167. streamwright-0.1.10/src/streamwright/core/sdk/operations/messages.py +28 -0
  168. streamwright-0.1.10/src/streamwright/core/sdk/operations/tables.py +70 -0
  169. streamwright-0.1.10/src/streamwright/core/sdk/py.typed +0 -0
  170. streamwright-0.1.10/src/streamwright/core/sdk/testing/__init__.py +84 -0
  171. streamwright-0.1.10/src/streamwright/core/sdk/testing/contract.py +199 -0
  172. streamwright-0.1.10/src/streamwright/core/sdk/testing/helpers.py +51 -0
  173. streamwright-0.1.10/src/streamwright/core/sdk/testing/storage.py +221 -0
  174. streamwright-0.1.10/src/streamwright/core/sql/__init__.py +22 -0
  175. streamwright-0.1.10/src/streamwright/core/sql/analysis.py +47 -0
  176. streamwright-0.1.10/src/streamwright/core/sql/conditions.py +96 -0
  177. streamwright-0.1.10/src/streamwright/core/sql/quote.py +55 -0
  178. streamwright-0.1.10/src/streamwright/core/validation/__init__.py +3 -0
  179. streamwright-0.1.10/src/streamwright/core/validation/auth.py +59 -0
  180. streamwright-0.1.10/src/streamwright/core/validation/checker.py +149 -0
  181. streamwright-0.1.10/src/streamwright/core/validation/engine.py +347 -0
  182. streamwright-0.1.10/src/streamwright/core/validation/issues.py +42 -0
  183. streamwright-0.1.10/src/streamwright/core/validation/job_manifests.py +131 -0
  184. streamwright-0.1.8/src/streamwright/core/validation/schema.py → streamwright-0.1.10/src/streamwright/core/validation/json_schemas.py +107 -252
  185. streamwright-0.1.10/src/streamwright/core/validation/marked_yaml.py +137 -0
  186. streamwright-0.1.10/src/streamwright/core/validation/partitions.py +69 -0
  187. streamwright-0.1.10/src/streamwright/core/validation/requests.py +80 -0
  188. streamwright-0.1.10/src/streamwright/core/validation/schema.py +122 -0
  189. streamwright-0.1.10/src/streamwright/core/validation/sections/__init__.py +17 -0
  190. streamwright-0.1.10/src/streamwright/core/validation/sections/async_jobs.py +153 -0
  191. streamwright-0.1.10/src/streamwright/core/validation/sections/document.py +128 -0
  192. streamwright-0.1.10/src/streamwright/core/validation/sections/partitions.py +147 -0
  193. streamwright-0.1.10/src/streamwright/core/validation/sections/references.py +125 -0
  194. streamwright-0.1.10/src/streamwright/core/validation/sections/request_partitions.py +152 -0
  195. streamwright-0.1.10/src/streamwright/core/validation/sections/requests.py +79 -0
  196. streamwright-0.1.10/src/streamwright/core/validation/sections/spec.py +205 -0
  197. streamwright-0.1.10/src/streamwright/core/validation/sections/stream_context.py +47 -0
  198. streamwright-0.1.10/src/streamwright/core/validation/sections/streams.py +171 -0
  199. streamwright-0.1.10/src/streamwright/core/validation/sections/tables.py +132 -0
  200. streamwright-0.1.10/src/streamwright/core/validation/sections/templates.py +32 -0
  201. streamwright-0.1.10/src/streamwright/core/validation/source.py +30 -0
  202. streamwright-0.1.10/src/streamwright/core/validation/streams.py +81 -0
  203. streamwright-0.1.10/src/streamwright/core/validation/vocabulary.py +142 -0
  204. streamwright-0.1.10/src/streamwright.egg-info/PKG-INFO +93 -0
  205. streamwright-0.1.10/src/streamwright.egg-info/SOURCES.txt +239 -0
  206. streamwright-0.1.10/src/streamwright.egg-info/entry_points.txt +12 -0
  207. {streamwright-0.1.8 → streamwright-0.1.10}/src/streamwright.egg-info/requires.txt +1 -1
  208. {streamwright-0.1.8 → streamwright-0.1.10}/tests/test_catalog.py +43 -15
  209. streamwright-0.1.10/tests/test_cli_subcommands.py +139 -0
  210. streamwright-0.1.10/tests/test_conditions.py +42 -0
  211. streamwright-0.1.10/tests/test_connector_api_family.py +129 -0
  212. streamwright-0.1.10/tests/test_connector_contract.py +337 -0
  213. {streamwright-0.1.8 → streamwright-0.1.10}/tests/test_connectors.py +165 -123
  214. {streamwright-0.1.8 → streamwright-0.1.10}/tests/test_dlt_output.py +48 -21
  215. streamwright-0.1.10/tests/test_engine_reach.py +30 -0
  216. {streamwright-0.1.8 → streamwright-0.1.10}/tests/test_exact_decimals.py +24 -29
  217. streamwright-0.1.10/tests/test_graph.py +12 -0
  218. {streamwright-0.1.8 → streamwright-0.1.10}/tests/test_http_engine.py +117 -35
  219. {streamwright-0.1.8 → streamwright-0.1.10}/tests/test_logging.py +222 -85
  220. streamwright-0.1.10/tests/test_output_contract.py +36 -0
  221. {streamwright-0.1.8 → streamwright-0.1.10}/tests/test_output_formats.py +32 -24
  222. streamwright-0.1.10/tests/test_plugin_contract_gate.py +35 -0
  223. {streamwright-0.1.8 → streamwright-0.1.10}/tests/test_runner.py +132 -51
  224. streamwright-0.1.10/tests/test_sdk_plugins.py +162 -0
  225. {streamwright-0.1.8 → streamwright-0.1.10}/tests/test_sql.py +7 -6
  226. streamwright-0.1.10/tests/test_sql_quote.py +34 -0
  227. {streamwright-0.1.8 → streamwright-0.1.10}/tests/test_transform.py +76 -59
  228. {streamwright-0.1.8 → streamwright-0.1.10}/tests/test_validation.py +299 -81
  229. {streamwright-0.1.8 → streamwright-0.1.10}/tests/test_warehouse_output.py +153 -56
  230. streamwright-0.1.8/PKG-INFO +0 -127
  231. streamwright-0.1.8/README.md +0 -98
  232. streamwright-0.1.8/src/streamwright/core/cli.py +0 -662
  233. streamwright-0.1.8/src/streamwright/core/engine/runner.py +0 -1049
  234. streamwright-0.1.8/src/streamwright/core/engine/sql.py +0 -1294
  235. streamwright-0.1.8/src/streamwright/core/net/http.py +0 -475
  236. streamwright-0.1.8/src/streamwright/core/outputs/exporter.py +0 -289
  237. streamwright-0.1.8/src/streamwright/core/outputs/output.py +0 -509
  238. streamwright-0.1.8/src/streamwright/core/runtime/components.py +0 -476
  239. streamwright-0.1.8/src/streamwright/core/runtime/logs.py +0 -791
  240. streamwright-0.1.8/src/streamwright/core/validation/engine.py +0 -595
  241. streamwright-0.1.8/src/streamwright/core/validation/source.py +0 -1265
  242. streamwright-0.1.8/src/streamwright.egg-info/PKG-INFO +0 -127
  243. streamwright-0.1.8/src/streamwright.egg-info/SOURCES.txt +0 -55
  244. streamwright-0.1.8/src/streamwright.egg-info/entry_points.txt +0 -3
  245. streamwright-0.1.8/tests/test_cli_subcommands.py +0 -72
  246. streamwright-0.1.8/tests/test_exporter.py +0 -69
  247. {streamwright-0.1.8 → streamwright-0.1.10}/LICENSE +0 -0
  248. {streamwright-0.1.8 → streamwright-0.1.10}/setup.cfg +0 -0
  249. {streamwright-0.1.8 → streamwright-0.1.10}/setup.py +0 -0
  250. {streamwright-0.1.8 → streamwright-0.1.10}/src/streamwright/core/__init__.py +0 -0
  251. {streamwright-0.1.8 → streamwright-0.1.10}/src/streamwright/core/config/__init__.py +0 -0
  252. {streamwright-0.1.8 → streamwright-0.1.10}/src/streamwright/core/engine/__init__.py +0 -0
  253. {streamwright-0.1.8 → streamwright-0.1.10}/src/streamwright/core/net/__init__.py +0 -0
  254. {streamwright-0.1.8 → streamwright-0.1.10}/src/streamwright/core/outputs/__init__.py +0 -0
  255. /streamwright-0.1.8/src/streamwright/core/runtime/__init__.py → /streamwright-0.1.10/src/streamwright/core/py.typed +0 -0
  256. {streamwright-0.1.8/src/streamwright/core/validation → streamwright-0.1.10/src/streamwright/core/runtime}/__init__.py +0 -0
  257. {streamwright-0.1.8 → streamwright-0.1.10}/src/streamwright.egg-info/dependency_links.txt +0 -0
  258. {streamwright-0.1.8 → streamwright-0.1.10}/src/streamwright.egg-info/top_level.txt +0 -0
@@ -0,0 +1,93 @@
1
+ Metadata-Version: 2.4
2
+ Name: streamwright
3
+ Version: 0.1.10
4
+ Summary: Declarative data connectors — pull from APIs, files and databases with YAML, shape with SQL, write anywhere.
5
+ Author-email: Karthick Jaganathan <kjaganathan.sde@gmail.com>
6
+ License: Apache-2.0
7
+ Project-URL: Homepage, https://streamwright.web.app
8
+ Project-URL: Documentation, https://streamwright.web.app/docs/
9
+ Project-URL: Repository, https://github.com/karthick-jaganathan/streamwright
10
+ Project-URL: Issue Tracker, https://github.com/karthick-jaganathan/streamwright/issues
11
+ Keywords: data,pipeline,etl,connector,singer,yaml,duckdb,rest-api
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Programming Language :: Python :: 3.13
18
+ Requires-Python: >=3.11
19
+ Description-Content-Type: text/markdown
20
+ License-File: LICENSE
21
+ Requires-Dist: pyyaml==6.0.2
22
+ Requires-Dist: requests<3,>=2.25
23
+ Requires-Dist: duckdb<2.1,>=2.0
24
+ Requires-Dist: pytz
25
+ Provides-Extra: dlt
26
+ Requires-Dist: dlt>=1.0; extra == "dlt"
27
+ Dynamic: license-file
28
+
29
+ # StreamWright
30
+
31
+ [![PyPI](https://img.shields.io/pypi/v/streamwright.svg)](https://pypi.org/project/streamwright/)
32
+ [![Python](https://img.shields.io/pypi/pyversions/streamwright.svg)](https://pypi.org/project/streamwright/)
33
+ [![License](https://img.shields.io/pypi/l/streamwright.svg)](https://github.com/karthick-jaganathan/streamwright/blob/master/LICENSE)
34
+ [![Docs](https://img.shields.io/badge/docs-streamwright.web.app-brightgreen.svg)](https://streamwright.web.app/docs/)
35
+
36
+ Declarative data pipelines in YAML: read from APIs, files, databases and ads platforms, shape with DuckDB SQL,
37
+ write to files, DuckDB, DuckLake, Singer or dlt.
38
+
39
+ - **No per-connector code**: authentication, paging, retries, rate limits and incremental state are configuration.
40
+ - **Connectors on demand** from the StreamWright hub: `sw connectors -i <name>`.
41
+ - **Jobs**: `kind: DuckDBJob` SQL pipelines with replay-safe writes; `kind: SparkJob` with
42
+ [streamwright-spark](https://pypi.org/project/streamwright-spark/).
43
+
44
+ ## Install
45
+
46
+ ```bash
47
+ pip install streamwright
48
+ sw connectors -i restapi
49
+ ```
50
+
51
+ ## Example
52
+
53
+ A source is a folder: `source.yaml` and one file per stream.
54
+
55
+ ```yaml
56
+ # my_api/source.yaml
57
+ kind: source
58
+ name: my_api
59
+ spec:
60
+ secrets:
61
+ api_token: {type: string}
62
+ auth:
63
+ provider: restapi
64
+ type: bearer
65
+ token: "{{ secrets.api_token }}"
66
+ http:
67
+ base_url: https://api.example.com
68
+ ```
69
+
70
+ ```yaml
71
+ # my_api/streams/items.yaml
72
+ requests:
73
+ - name: raw_items
74
+ http: {path: /v1/items}
75
+ transform:
76
+ mode: page
77
+ steps:
78
+ - name: items
79
+ select: SELECT record->>'id' AS id, record->>'name' AS name FROM raw_items
80
+ export:
81
+ items: {step: items, primary_key: [id]}
82
+ ```
83
+
84
+ ```bash
85
+ sw validate my_api
86
+ STREAMWRIGHT_SECRET_API_TOKEN=... sw run my_api --output jsonl:out
87
+ ```
88
+
89
+ ## Links
90
+
91
+ [Documentation](https://streamwright.web.app/docs/) ·
92
+ [Quickstart](https://streamwright.web.app/docs/quickstart/) ·
93
+ [Source code](https://github.com/karthick-jaganathan/streamwright)
@@ -0,0 +1,65 @@
1
+ # StreamWright
2
+
3
+ [![PyPI](https://img.shields.io/pypi/v/streamwright.svg)](https://pypi.org/project/streamwright/)
4
+ [![Python](https://img.shields.io/pypi/pyversions/streamwright.svg)](https://pypi.org/project/streamwright/)
5
+ [![License](https://img.shields.io/pypi/l/streamwright.svg)](https://github.com/karthick-jaganathan/streamwright/blob/master/LICENSE)
6
+ [![Docs](https://img.shields.io/badge/docs-streamwright.web.app-brightgreen.svg)](https://streamwright.web.app/docs/)
7
+
8
+ Declarative data pipelines in YAML: read from APIs, files, databases and ads platforms, shape with DuckDB SQL,
9
+ write to files, DuckDB, DuckLake, Singer or dlt.
10
+
11
+ - **No per-connector code**: authentication, paging, retries, rate limits and incremental state are configuration.
12
+ - **Connectors on demand** from the StreamWright hub: `sw connectors -i <name>`.
13
+ - **Jobs**: `kind: DuckDBJob` SQL pipelines with replay-safe writes; `kind: SparkJob` with
14
+ [streamwright-spark](https://pypi.org/project/streamwright-spark/).
15
+
16
+ ## Install
17
+
18
+ ```bash
19
+ pip install streamwright
20
+ sw connectors -i restapi
21
+ ```
22
+
23
+ ## Example
24
+
25
+ A source is a folder: `source.yaml` and one file per stream.
26
+
27
+ ```yaml
28
+ # my_api/source.yaml
29
+ kind: source
30
+ name: my_api
31
+ spec:
32
+ secrets:
33
+ api_token: {type: string}
34
+ auth:
35
+ provider: restapi
36
+ type: bearer
37
+ token: "{{ secrets.api_token }}"
38
+ http:
39
+ base_url: https://api.example.com
40
+ ```
41
+
42
+ ```yaml
43
+ # my_api/streams/items.yaml
44
+ requests:
45
+ - name: raw_items
46
+ http: {path: /v1/items}
47
+ transform:
48
+ mode: page
49
+ steps:
50
+ - name: items
51
+ select: SELECT record->>'id' AS id, record->>'name' AS name FROM raw_items
52
+ export:
53
+ items: {step: items, primary_key: [id]}
54
+ ```
55
+
56
+ ```bash
57
+ sw validate my_api
58
+ STREAMWRIGHT_SECRET_API_TOKEN=... sw run my_api --output jsonl:out
59
+ ```
60
+
61
+ ## Links
62
+
63
+ [Documentation](https://streamwright.web.app/docs/) ·
64
+ [Quickstart](https://streamwright.web.app/docs/quickstart/) ·
65
+ [Source code](https://github.com/karthick-jaganathan/streamwright)
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "streamwright"
7
- version = "0.1.8"
7
+ version = "0.1.10"
8
8
  description = "Declarative data connectors — pull from APIs, files and databases with YAML, shape with SQL, write anywhere."
9
9
  readme = "README.md"
10
10
  license = {text = "Apache-2.0"}
@@ -16,18 +16,17 @@ classifiers = [
16
16
  "Development Status :: 3 - Alpha",
17
17
  "Intended Audience :: Developers",
18
18
  "Programming Language :: Python :: 3",
19
- "Programming Language :: Python :: 3.10",
20
19
  "Programming Language :: Python :: 3.11",
21
20
  "Programming Language :: Python :: 3.12",
22
21
  "Programming Language :: Python :: 3.13",
23
22
  ]
24
- requires-python = ">=3.10"
23
+ requires-python = ">=3.11"
25
24
  dependencies = [
26
25
  "pyyaml==6.0.2",
27
26
  "requests>=2.25,<3",
28
27
  # `select`: the SQL that shapes each stream's records runs in an embedded DuckDB (which needs pytz for
29
28
  # timestamps with time zones)
30
- "duckdb>=1.5.2",
29
+ "duckdb>=2.0,<2.1",
31
30
  "pytz",
32
31
  ]
33
32
 
@@ -46,17 +45,28 @@ Repository = "https://github.com/karthick-jaganathan/streamwright"
46
45
  streamwright = "streamwright.core.cli:main"
47
46
  sw = "streamwright.core.cli:main"
48
47
 
48
+ [project.entry-points."streamwright.commands"]
49
+ duckdb = "streamwright.core.cli.commands.jobs:register"
50
+
51
+ [project.entry-points."streamwright.job_kinds"]
52
+ DuckDBJob = "streamwright.core.jobs.duckdb.plugin:JOB_ENGINE"
53
+
54
+ [project.entry-points."streamwright.duckdb.connectors"]
55
+ # the DuckDBJob engine's built-in adapters; every other provider's adapter ships with its connector
56
+ duckdb = "streamwright.core.jobs.duckdb.adapter:DuckDBCatalogAdapter"
57
+
49
58
 
50
59
  [tool.setuptools]
51
60
  # src layout: `streamwright` is a namespace package shared with the connector distributions (streamwright.connectors.*)
52
61
  package-dir = {"" = "src"}
53
- packages = [
54
- "streamwright.core",
55
- "streamwright.core.engine",
56
- "streamwright.core.outputs",
57
- "streamwright.core.net",
58
- "streamwright.core.config",
59
- "streamwright.core.validation",
60
- "streamwright.core.runtime",
61
- ]
62
62
 
63
+ [tool.setuptools.packages.find]
64
+ # every streamwright.core subpackage ships (jobs, sql, ...); `streamwright` itself stays a namespace
65
+ where = ["src"]
66
+ include = ["streamwright.core*"]
67
+ namespaces = true
68
+
69
+ [tool.setuptools.package-data]
70
+ "streamwright.core" = ["py.typed"]
71
+ "streamwright.core.sdk" = ["py.typed"]
72
+ "streamwright.core.jobs.duckdb" = ["guide.md"]
@@ -12,12 +12,15 @@ what users type.
12
12
  Security: non-"official" connectors run third-party code, so `install` asks for
13
13
  confirmation (or `--yes`) and refuses non-interactive installs without it.
14
14
  """
15
+ import datetime
15
16
  import json
16
17
  import os
17
18
  import subprocess
18
19
  import sys
19
20
  from pathlib import Path
20
21
 
22
+ import requests
23
+
21
24
  from streamwright.core.runtime import components
22
25
 
23
26
  HUB_ENV = "STREAMWRIGHT_HUB_URL"
@@ -26,13 +29,17 @@ CACHE = Path(os.path.expanduser("~/.streamwright/connectors.json"))
26
29
  TIMEOUT_S = 5
27
30
 
28
31
 
32
+ class _Catalog(dict):
33
+ def __init__(self, data, trusted_origin=False):
34
+ super().__init__(data)
35
+ self.trusted_origin = trusted_origin
36
+
37
+
29
38
  def _valid(data):
30
39
  return isinstance(data, dict) and isinstance(data.get("connectors"), dict)
31
40
 
32
41
 
33
42
  def _remote(url):
34
- import requests
35
-
36
43
  response = requests.get(url, timeout=TIMEOUT_S)
37
44
  response.raise_for_status()
38
45
  data = response.json()
@@ -53,7 +60,8 @@ def load(hub_url=None):
53
60
  """
54
61
  url = hub_url or os.environ.get(HUB_ENV) or DEFAULT_HUB
55
62
  try:
56
- return _remote(url)
63
+ data = _remote(url)
64
+ return _Catalog(data, trusted_origin=(url == DEFAULT_HUB and url.startswith("https://")))
57
65
  except Exception as exc: # offline, hub down or a bad publish: fall back, visibly
58
66
  reason = type(exc).__name__ # network errors: the type is enough; an HTTP status or a bad index says why
59
67
  status = getattr(getattr(exc, "response", None), "status_code", None)
@@ -65,8 +73,8 @@ def load(hub_url=None):
65
73
  try:
66
74
  data = json.loads(CACHE.read_text())
67
75
  if _valid(data):
68
- sys.stderr.write("streamwright: the connector hub %s is unreachable (%s); using the copy fetched on %s\n"
69
- % (url, reason, _mtime(CACHE)))
76
+ sys.stderr.write("streamwright: the connector hub %s is unreachable (%s); using the copy fetched on "
77
+ "%s\n" % (url, reason, _mtime(CACHE)))
70
78
  return data
71
79
  except Exception:
72
80
  pass
@@ -74,12 +82,12 @@ def load(hub_url=None):
74
82
 
75
83
 
76
84
  def _mtime(path):
77
- import datetime
78
85
  return datetime.datetime.fromtimestamp(path.stat().st_mtime).strftime("%Y-%m-%d %H:%M")
79
86
 
80
87
 
81
88
  def connectors(hub_url=None):
82
- return load(hub_url).get("connectors", {})
89
+ data = load(hub_url)
90
+ return _Catalog(data.get("connectors", {}), getattr(data, "trusted_origin", False))
83
91
 
84
92
 
85
93
  def installed():
@@ -116,13 +124,14 @@ def listing(hub_url=None):
116
124
  have = installed()
117
125
  lines = []
118
126
  by_family = {}
119
- for key, entry in connectors(hub_url).items():
127
+ catalog_data = connectors(hub_url)
128
+ for key, entry in catalog_data.items():
120
129
  by_family.setdefault(entry.get("family", "other"), []).append((key, entry))
121
130
  for family in sorted(by_family):
122
131
  lines.append("%s:" % family)
123
132
  for key, entry in sorted(by_family[family]):
124
133
  mark = "[installed]" if key in have else " "
125
- trust = entry.get("trust", "community")
134
+ trust = entry.get("trust", "community") if catalog_data.trusted_origin else "community"
126
135
  lines.append(" %s %-16s %-10s %s" % (mark, key, trust, entry.get("summary", "")))
127
136
  return lines
128
137
 
@@ -144,6 +153,7 @@ def install_many(keys, assume_yes=False, hub_url=None, pip_args=()):
144
153
  sys.stderr.write("streamwright: 'connectors install' needs at least one connector KEY\n")
145
154
  return 2
146
155
  catalog = connectors(hub_url)
156
+ trusted_origin = getattr(catalog, "trusted_origin", False)
147
157
  unknown = [key for key in keys if key not in catalog]
148
158
  if unknown:
149
159
  sys.stderr.write("streamwright: unknown connector%s %s (try: streamwright connectors list)\n" % (
@@ -163,8 +173,11 @@ def install_many(keys, assume_yes=False, hub_url=None, pip_args=()):
163
173
  if not spec:
164
174
  sys.stderr.write("streamwright: connector %r has no installable source\n" % key)
165
175
  return 2
176
+ if not isinstance(spec, str) or spec.lstrip().startswith("-"):
177
+ sys.stderr.write("streamwright: connector %r has an invalid install requirement\n" % key)
178
+ return 2
166
179
  specs.append(spec)
167
- trust = entry.get("trust", "community")
180
+ trust = entry.get("trust", "community") if trusted_origin else "community"
168
181
  if trust != "official":
169
182
  untrusted.append((key, trust, _source_of(inst)))
170
183
  if not specs:
@@ -184,6 +197,6 @@ def install_many(keys, assume_yes=False, hub_url=None, pip_args=()):
184
197
  print("aborted")
185
198
  return 1
186
199
 
187
- cmd = [sys.executable, "-m", "pip", "install", *pip_args, *specs]
200
+ cmd = [sys.executable, "-m", "pip", "install", *pip_args, "--", *specs]
188
201
  print("+ " + " ".join(cmd), flush=True)
189
202
  return subprocess.call(cmd)
@@ -0,0 +1,5 @@
1
+ """Public StreamWright command-line interface."""
2
+
3
+ from streamwright.core.cli.main import command_parsers, detect_kind, main, run
4
+
5
+ __all__ = ["command_parsers", "detect_kind", "main", "run"]
@@ -0,0 +1,5 @@
1
+ """Run the CLI as a module."""
2
+
3
+ from streamwright.core.cli import main
4
+
5
+ raise SystemExit(main())
@@ -0,0 +1 @@
1
+ """Built-in commands."""
@@ -0,0 +1,173 @@
1
+ #!/usr/bin/env python
2
+ # /*************************************************************************
3
+ # * Copyright 2025 Karthick Jaganathan
4
+ # *
5
+ # * Licensed under the Apache License, Version 2.0 (the "License");
6
+ # * you may not use this file except in compliance with the License.
7
+ # * You may obtain a copy of the License at
8
+ # *
9
+ # * https://www.apache.org/licenses/LICENSE-2.0
10
+ # *
11
+ # * Unless required by applicable law or agreed to in writing, software
12
+ # * distributed under the License is distributed on an "AS IS" BASIS,
13
+ # * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # * See the License for the specific language governing permissions and
15
+ # * limitations under the License.
16
+ # **************************************************************************/
17
+
18
+ """`streamwright connectors`: the installed connectors, and the catalog's (list, search, install)."""
19
+
20
+ import re
21
+ import sys
22
+ from importlib import metadata
23
+
24
+ import duckdb
25
+
26
+ from streamwright.core import catalog
27
+ from streamwright.core.runtime import components, plugins
28
+ from streamwright.core.runtime.logs.lines import NETWORK
29
+
30
+ _REQUIREMENT_NAME = re.compile(r"^\s*([A-Za-z0-9][A-Za-z0-9._-]*)")
31
+ # a connector that logs on streamwright.network calls through StreamWright's HTTP client, which is built on requests
32
+ HTTP_CLIENT_LIBRARY = "requests"
33
+
34
+
35
+ def _installed(name):
36
+ try:
37
+ return "%s==%s" % (name, metadata.version(name))
38
+ except metadata.PackageNotFoundError:
39
+ return "%s (not installed)" % name
40
+
41
+
42
+ def libraries(distribution, loggers=()):
43
+ """
44
+ The third-party libraries a connector uses, as "name==version" (or "name (not installed)"): what its distribution
45
+ requires (not its extras', not StreamWright's), and requests when it calls through StreamWright's HTTP client.
46
+ """
47
+ try:
48
+ requires = (metadata.requires(distribution) or []) if distribution else []
49
+ except metadata.PackageNotFoundError:
50
+ requires = []
51
+ names = []
52
+ for requirement in requires:
53
+ spec, _, marker = requirement.partition(";")
54
+ match = _REQUIREMENT_NAME.match(spec)
55
+ if "extra" not in marker and match and not match.group(1).lower().startswith("streamwright"):
56
+ names.append(match.group(1))
57
+ if NETWORK.name in loggers and HTTP_CLIENT_LIBRARY not in names:
58
+ names.append(HTTP_CLIENT_LIBRARY)
59
+ return [_installed(name) for name in names]
60
+
61
+
62
+ class DuckDBExtensions:
63
+ """The installed DuckDB's extensions (one in-memory query, made when a connector names one): name@version."""
64
+
65
+ def __init__(self):
66
+ self._installed = None
67
+
68
+ def _load(self):
69
+ self._installed = {}
70
+ rows = duckdb.connect().execute(
71
+ "SELECT extension_name, aliases, installed, extension_version FROM duckdb_extensions()").fetchall()
72
+ for name, aliases, installed, version in rows:
73
+ for key in (name, *(aliases or ())):
74
+ self._installed[key] = (name, version if installed else None)
75
+ self._installed[None] = ("duckdb", duckdb.__version__)
76
+
77
+ def describe(self, names):
78
+ """("duckdb==VERSION", ["EXTENSION@VERSION" or "EXTENSION (not installed)", ...]); (None, []) for no names."""
79
+ if not names:
80
+ return None, []
81
+ if self._installed is None:
82
+ self._load()
83
+ found = []
84
+ for name in names:
85
+ extension, version = self._installed.get(name, (name, None))
86
+ found.append("%s@%s" % (extension, version) if version else "%s (not installed)" % extension)
87
+ return "duckdb==%s" % self._installed[None][1], found
88
+
89
+
90
+ def _fields(name, definition, entry, extensions):
91
+ """A connector's `pip show`-style fields."""
92
+ used = libraries(entry.get("distribution"), definition.loggers)
93
+ duckdb_library, loaded = extensions.describe(definition.duckdb_extensions)
94
+ return (("Name", name), ("Title", definition.title), ("Family", definition.family),
95
+ ("Summary", definition.summary), ("Package", entry.get("distribution") or "(registered in-process)"),
96
+ ("Version", entry.get("version") or ""), ("Libraries", ", ".join(used + [duckdb_library] * bool(loaded))),
97
+ ("DuckDB-Extensions", ", ".join(loaded)), ("Loggers", ", ".join(definition.loggers)))
98
+
99
+
100
+ def _connector_lines(names=None):
101
+ """
102
+ The installed (and registered) connectors, sorted by family and name, as `pip show` shows packages (`---` between
103
+ them): name, title, family, summary, distribution and version, the third-party libraries and DuckDB extensions it
104
+ uses (installed versions) and its loggers (for --log). `names`: only these. Only specs are imported.
105
+ """
106
+ metadata_of = {entry["name"]: entry for entry in plugins.discover(plugins.CONNECTORS)}
107
+ blocks, extensions = [], DuckDBExtensions()
108
+ for name in components.available():
109
+ if names is not None and name not in names:
110
+ continue
111
+ try:
112
+ definition = components.load(name)
113
+ except components.ComponentLoadError as exc:
114
+ blocks.append(("~", name, (("Name", name), ("Error", str(exc))))) # (after the families)
115
+ continue
116
+ blocks.append((definition.family, name, _fields(name, definition, metadata_of.get(name, {}), extensions)))
117
+ lines = []
118
+ for _, _, fields in sorted(blocks, key=lambda block: block[:2]):
119
+ if lines:
120
+ lines.append("---")
121
+ lines.extend(("%s: %s" % (key, value)).rstrip() for key, value in fields)
122
+ return lines
123
+
124
+
125
+ def run_connectors_command(args):
126
+ """`streamwright connectors`: bare or installed names = installed connectors; ls/i/find use the catalog (hub)."""
127
+ if getattr(args, "flag_list", False):
128
+ action = "ls"
129
+ query = []
130
+ elif getattr(args, "flag_install", None):
131
+ action = "install"
132
+ query = args.flag_install
133
+ elif getattr(args, "flag_search", None):
134
+ action = "find"
135
+ query = args.flag_search
136
+ else:
137
+ action = getattr(args, "action", None)
138
+ query = getattr(args, "query", [])
139
+
140
+ if action is None:
141
+ lines = _connector_lines()
142
+ print("\n".join(lines) if lines else "no connectors installed (use streamwright connectors list to find one)")
143
+ return 0
144
+
145
+ norm_action = action.lower()
146
+ if norm_action in ("ls", "list", "-ls", "--list"):
147
+ lines = catalog.listing(args.hub_url)
148
+ print("\n".join(lines) if lines else "the catalog is empty")
149
+ return 0
150
+
151
+ if norm_action in ("i", "install", "-i", "--install"):
152
+ if not query:
153
+ sys.stderr.write("streamwright: 'connectors -i' needs at least one connector KEY\n")
154
+ return 2
155
+ return catalog.install_many(query, assume_yes=args.yes, hub_url=args.hub_url)
156
+
157
+ words = [action, *query]
158
+ if norm_action in ("find", "search", "s", "-s", "-f", "--find", "--search"):
159
+ words = query
160
+ elif set(words) <= set(components.available()):
161
+ # installed connector names show those connectors, as `pip show NAME` does (`sw connectors google_ads s3`)
162
+ print("\n".join(_connector_lines(set(words))))
163
+ return 0
164
+ return _search(" ".join(words), args.hub_url) # any other words search the catalog (`sw connectors ads`)
165
+
166
+
167
+ def _search(text, hub_url):
168
+ hits = catalog.search(text, hub_url)
169
+ if not hits:
170
+ print("no connectors match %r" % text)
171
+ for key, entry in sorted(hits.items()):
172
+ print(" %-16s %-10s %s" % (key, entry.get("trust", "community"), entry.get("summary", "")))
173
+ return 0
@@ -0,0 +1,27 @@
1
+ """Job-kind commands: a manifest's kind runs its installed JobEngine, and `duckdb` is the DuckDBJob shorthand."""
2
+
3
+ import argparse
4
+ import sys
5
+
6
+ from streamwright.core.jobs.engine import load_job_engine
7
+ from streamwright.core.runtime import plugins
8
+
9
+
10
+ def register(subparsers):
11
+ parser = subparsers.add_parser("duckdb", help="run an installed DuckDBJob engine", add_help=False)
12
+ parser.add_argument("arguments", nargs=argparse.REMAINDER)
13
+ parser.set_defaults(command_handler=lambda args: execute(args.arguments))
14
+
15
+
16
+ def execute(arguments):
17
+ return run_job_kind("DuckDBJob", arguments)
18
+
19
+
20
+ def run_job_kind(kind, argv):
21
+ """Runs the installed JobEngine of manifest `kind` on the original arguments (no engine is imported by core)."""
22
+ try:
23
+ job_engine = load_job_engine(kind)
24
+ except plugins.PluginError as exc:
25
+ sys.stderr.write("streamwright: %s\n" % exc)
26
+ return 2
27
+ return job_engine.main(argv) or 0