streamwright 0.1.8__tar.gz → 0.1.9__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.
- streamwright-0.1.9/PKG-INFO +93 -0
- streamwright-0.1.9/README.md +65 -0
- {streamwright-0.1.8 → streamwright-0.1.9}/pyproject.toml +23 -13
- {streamwright-0.1.8 → streamwright-0.1.9}/src/streamwright/core/catalog.py +24 -11
- streamwright-0.1.9/src/streamwright/core/cli/__init__.py +5 -0
- streamwright-0.1.9/src/streamwright/core/cli/__main__.py +5 -0
- streamwright-0.1.9/src/streamwright/core/cli/commands/__init__.py +1 -0
- streamwright-0.1.9/src/streamwright/core/cli/commands/connectors.py +103 -0
- streamwright-0.1.9/src/streamwright/core/cli/commands/jobs.py +27 -0
- streamwright-0.1.9/src/streamwright/core/cli/commands/source.py +307 -0
- streamwright-0.1.9/src/streamwright/core/cli/jobs.py +31 -0
- streamwright-0.1.9/src/streamwright/core/cli/log_options.py +122 -0
- streamwright-0.1.9/src/streamwright/core/cli/main.py +158 -0
- streamwright-0.1.9/src/streamwright/core/cli/parser.py +132 -0
- {streamwright-0.1.8 → streamwright-0.1.9}/src/streamwright/core/config/inputs.py +25 -17
- {streamwright-0.1.8 → streamwright-0.1.9}/src/streamwright/core/config/loader.py +29 -10
- {streamwright-0.1.8 → streamwright-0.1.9}/src/streamwright/core/config/reader.py +1 -1
- streamwright-0.1.9/src/streamwright/core/engine/bookmarks.py +48 -0
- streamwright-0.1.9/src/streamwright/core/engine/builders.py +26 -0
- streamwright-0.1.9/src/streamwright/core/engine/errors.py +7 -0
- streamwright-0.1.9/src/streamwright/core/engine/execution.py +188 -0
- streamwright-0.1.9/src/streamwright/core/engine/factories.py +82 -0
- streamwright-0.1.9/src/streamwright/core/engine/partitions.py +187 -0
- streamwright-0.1.9/src/streamwright/core/engine/planning.py +71 -0
- {streamwright-0.1.8 → streamwright-0.1.9}/src/streamwright/core/engine/queries.py +12 -12
- streamwright-0.1.9/src/streamwright/core/engine/readers.py +218 -0
- streamwright-0.1.9/src/streamwright/core/engine/responses.py +48 -0
- streamwright-0.1.9/src/streamwright/core/engine/rules.py +29 -0
- streamwright-0.1.9/src/streamwright/core/engine/runner.py +318 -0
- streamwright-0.1.9/src/streamwright/core/engine/session.py +44 -0
- streamwright-0.1.9/src/streamwright/core/engine/sql/__init__.py +85 -0
- streamwright-0.1.9/src/streamwright/core/engine/sql/compilation.py +255 -0
- streamwright-0.1.9/src/streamwright/core/engine/sql/list_parameters.py +82 -0
- streamwright-0.1.9/src/streamwright/core/engine/sql/ordering.py +115 -0
- streamwright-0.1.9/src/streamwright/core/engine/sql/plans.py +167 -0
- streamwright-0.1.9/src/streamwright/core/engine/sql/sandbox.py +384 -0
- streamwright-0.1.9/src/streamwright/core/engine/sql/stream_plan.py +86 -0
- streamwright-0.1.9/src/streamwright/core/engine/sql/tables.py +145 -0
- streamwright-0.1.9/src/streamwright/core/engine/sql/types.py +182 -0
- streamwright-0.1.9/src/streamwright/core/engine/values.py +67 -0
- streamwright-0.1.9/src/streamwright/core/engine/writers.py +32 -0
- streamwright-0.1.9/src/streamwright/core/graph.py +60 -0
- streamwright-0.1.9/src/streamwright/core/io/__init__.py +9 -0
- streamwright-0.1.9/src/streamwright/core/io/api_calls.py +52 -0
- streamwright-0.1.9/src/streamwright/core/io/capabilities.py +17 -0
- streamwright-0.1.9/src/streamwright/core/io/database_connections.py +213 -0
- streamwright-0.1.9/src/streamwright/core/io/database_rules.py +130 -0
- streamwright-0.1.9/src/streamwright/core/io/databases.py +290 -0
- streamwright-0.1.9/src/streamwright/core/io/file_formats.py +189 -0
- streamwright-0.1.9/src/streamwright/core/io/file_rules.py +84 -0
- streamwright-0.1.9/src/streamwright/core/io/files.py +388 -0
- streamwright-0.1.9/src/streamwright/core/io/http.py +19 -0
- streamwright-0.1.9/src/streamwright/core/io/local.py +181 -0
- streamwright-0.1.9/src/streamwright/core/io/locations.py +358 -0
- streamwright-0.1.9/src/streamwright/core/io/queries.py +344 -0
- streamwright-0.1.9/src/streamwright/core/io/sandbox.py +144 -0
- streamwright-0.1.9/src/streamwright/core/io/store_reader.py +180 -0
- streamwright-0.1.9/src/streamwright/core/jobs/__init__.py +112 -0
- streamwright-0.1.9/src/streamwright/core/jobs/calls.py +123 -0
- streamwright-0.1.9/src/streamwright/core/jobs/check/__init__.py +41 -0
- streamwright-0.1.9/src/streamwright/core/jobs/check/connections.py +28 -0
- streamwright-0.1.9/src/streamwright/core/jobs/check/dependencies.py +34 -0
- streamwright-0.1.9/src/streamwright/core/jobs/check/findings.py +60 -0
- streamwright-0.1.9/src/streamwright/core/jobs/check/names.py +43 -0
- streamwright-0.1.9/src/streamwright/core/jobs/check/outputs.py +53 -0
- streamwright-0.1.9/src/streamwright/core/jobs/check/refs.py +68 -0
- streamwright-0.1.9/src/streamwright/core/jobs/check/rules.py +124 -0
- streamwright-0.1.9/src/streamwright/core/jobs/check/runtime.py +37 -0
- streamwright-0.1.9/src/streamwright/core/jobs/check/secrets.py +83 -0
- streamwright-0.1.9/src/streamwright/core/jobs/check/sections.py +35 -0
- streamwright-0.1.9/src/streamwright/core/jobs/check/spec.py +70 -0
- streamwright-0.1.9/src/streamwright/core/jobs/check/steps.py +48 -0
- streamwright-0.1.9/src/streamwright/core/jobs/check/structure.py +27 -0
- streamwright-0.1.9/src/streamwright/core/jobs/duckdb/__init__.py +52 -0
- streamwright-0.1.9/src/streamwright/core/jobs/duckdb/adapter.py +173 -0
- streamwright-0.1.9/src/streamwright/core/jobs/duckdb/cli.py +200 -0
- streamwright-0.1.9/src/streamwright/core/jobs/duckdb/definition_adapter.py +162 -0
- streamwright-0.1.9/src/streamwright/core/jobs/duckdb/engine.py +271 -0
- streamwright-0.1.9/src/streamwright/core/jobs/duckdb/executor.py +172 -0
- streamwright-0.1.9/src/streamwright/core/jobs/duckdb/guide.md +62 -0
- streamwright-0.1.9/src/streamwright/core/jobs/duckdb/loading.py +35 -0
- streamwright-0.1.9/src/streamwright/core/jobs/duckdb/plugin.py +61 -0
- streamwright-0.1.9/src/streamwright/core/jobs/duckdb/reads.py +249 -0
- streamwright-0.1.9/src/streamwright/core/jobs/duckdb/rules.py +249 -0
- streamwright-0.1.9/src/streamwright/core/jobs/duckdb/session.py +162 -0
- streamwright-0.1.9/src/streamwright/core/jobs/duckdb/steps.py +220 -0
- streamwright-0.1.9/src/streamwright/core/jobs/duckdb/writers/__init__.py +23 -0
- streamwright-0.1.9/src/streamwright/core/jobs/duckdb/writers/tables.py +82 -0
- streamwright-0.1.9/src/streamwright/core/jobs/engine.py +76 -0
- streamwright-0.1.9/src/streamwright/core/jobs/fields.py +163 -0
- streamwright-0.1.9/src/streamwright/core/jobs/ingest/__init__.py +80 -0
- streamwright-0.1.9/src/streamwright/core/jobs/ingest/column_rules.py +163 -0
- streamwright-0.1.9/src/streamwright/core/jobs/ingest/formats.py +68 -0
- streamwright-0.1.9/src/streamwright/core/jobs/ingest/headers.py +85 -0
- streamwright-0.1.9/src/streamwright/core/jobs/ingest/mapped.py +200 -0
- streamwright-0.1.9/src/streamwright/core/jobs/ingest/model.py +148 -0
- streamwright-0.1.9/src/streamwright/core/jobs/ingest/plain.py +117 -0
- streamwright-0.1.9/src/streamwright/core/jobs/inputs.py +102 -0
- streamwright-0.1.9/src/streamwright/core/jobs/manifest.py +139 -0
- streamwright-0.1.9/src/streamwright/core/jobs/naming.py +292 -0
- streamwright-0.1.9/src/streamwright/core/jobs/plan.py +106 -0
- streamwright-0.1.9/src/streamwright/core/jobs/policy.py +198 -0
- streamwright-0.1.9/src/streamwright/core/jobs/refs.py +212 -0
- streamwright-0.1.9/src/streamwright/core/jobs/runner.py +308 -0
- streamwright-0.1.9/src/streamwright/core/jobs/schema.py +33 -0
- streamwright-0.1.9/src/streamwright/core/jobs/state/__init__.py +65 -0
- streamwright-0.1.9/src/streamwright/core/jobs/state/dialects.py +119 -0
- streamwright-0.1.9/src/streamwright/core/jobs/state/migrations.py +85 -0
- streamwright-0.1.9/src/streamwright/core/jobs/state/protocol.py +95 -0
- streamwright-0.1.9/src/streamwright/core/jobs/state/store.py +397 -0
- streamwright-0.1.9/src/streamwright/core/jobs/types.py +180 -0
- streamwright-0.1.9/src/streamwright/core/jobs/validate.py +126 -0
- streamwright-0.1.9/src/streamwright/core/jobs/write_rules.py +254 -0
- streamwright-0.1.9/src/streamwright/core/net/auth.py +106 -0
- {streamwright-0.1.8 → streamwright-0.1.9}/src/streamwright/core/net/downloads.py +5 -6
- {streamwright-0.1.8 → streamwright-0.1.9}/src/streamwright/core/net/encoding.py +4 -4
- streamwright-0.1.9/src/streamwright/core/net/errors.py +27 -0
- streamwright-0.1.9/src/streamwright/core/net/http.py +370 -0
- {streamwright-0.1.8 → streamwright-0.1.9}/src/streamwright/core/net/paginators.py +42 -47
- streamwright-0.1.9/src/streamwright/core/net/policies.py +113 -0
- streamwright-0.1.9/src/streamwright/core/outputs/base.py +88 -0
- streamwright-0.1.9/src/streamwright/core/outputs/dlt_columns.py +43 -0
- {streamwright-0.1.8 → streamwright-0.1.9}/src/streamwright/core/outputs/dlt_output.py +40 -101
- streamwright-0.1.9/src/streamwright/core/outputs/ducklake.py +231 -0
- streamwright-0.1.9/src/streamwright/core/outputs/file_names.py +162 -0
- streamwright-0.1.9/src/streamwright/core/outputs/files.py +267 -0
- streamwright-0.1.9/src/streamwright/core/outputs/loading.py +36 -0
- streamwright-0.1.9/src/streamwright/core/outputs/output.py +194 -0
- {streamwright-0.1.8 → streamwright-0.1.9}/src/streamwright/core/outputs/staging.py +37 -28
- {streamwright-0.1.8 → streamwright-0.1.9}/src/streamwright/core/outputs/warehouse.py +58 -232
- streamwright-0.1.9/src/streamwright/core/runtime/components.py +342 -0
- streamwright-0.1.9/src/streamwright/core/runtime/connector_types.py +113 -0
- streamwright-0.1.9/src/streamwright/core/runtime/constants.py +4 -0
- streamwright-0.1.9/src/streamwright/core/runtime/contract.py +332 -0
- streamwright-0.1.9/src/streamwright/core/runtime/contract_declarations.py +253 -0
- streamwright-0.1.9/src/streamwright/core/runtime/contract_guide.py +107 -0
- streamwright-0.1.9/src/streamwright/core/runtime/contract_terms.py +72 -0
- streamwright-0.1.9/src/streamwright/core/runtime/contract_validation.py +308 -0
- streamwright-0.1.9/src/streamwright/core/runtime/definitions.py +106 -0
- streamwright-0.1.9/src/streamwright/core/runtime/logs/__init__.py +90 -0
- streamwright-0.1.9/src/streamwright/core/runtime/logs/formatting.py +79 -0
- streamwright-0.1.9/src/streamwright/core/runtime/logs/handlers.py +125 -0
- streamwright-0.1.9/src/streamwright/core/runtime/logs/lines.py +91 -0
- streamwright-0.1.9/src/streamwright/core/runtime/logs/metrics.py +227 -0
- streamwright-0.1.9/src/streamwright/core/runtime/logs/network.py +103 -0
- streamwright-0.1.9/src/streamwright/core/runtime/logs/record_factory.py +84 -0
- streamwright-0.1.9/src/streamwright/core/runtime/logs/redaction.py +91 -0
- streamwright-0.1.9/src/streamwright/core/runtime/logs/setup.py +186 -0
- streamwright-0.1.9/src/streamwright/core/runtime/logs/summary.py +38 -0
- streamwright-0.1.9/src/streamwright/core/runtime/plugins.py +108 -0
- streamwright-0.1.9/src/streamwright/core/runtime/redact.py +31 -0
- streamwright-0.1.9/src/streamwright/core/runtime/source_connectors.py +105 -0
- {streamwright-0.1.8 → streamwright-0.1.9}/src/streamwright/core/runtime/templates.py +22 -13
- {streamwright-0.1.8 → streamwright-0.1.9}/src/streamwright/core/runtime/testing.py +6 -7
- streamwright-0.1.9/src/streamwright/core/sdk/__init__.py +33 -0
- streamwright-0.1.9/src/streamwright/core/sdk/constants.py +5 -0
- streamwright-0.1.9/src/streamwright/core/sdk/contract.py +41 -0
- streamwright-0.1.9/src/streamwright/core/sdk/engines/__init__.py +1 -0
- streamwright-0.1.9/src/streamwright/core/sdk/engines/duckdb.py +49 -0
- streamwright-0.1.9/src/streamwright/core/sdk/engines/source.py +32 -0
- streamwright-0.1.9/src/streamwright/core/sdk/messaging.py +43 -0
- streamwright-0.1.9/src/streamwright/core/sdk/network.py +9 -0
- streamwright-0.1.9/src/streamwright/core/sdk/operations/__init__.py +10 -0
- streamwright-0.1.9/src/streamwright/core/sdk/operations/databases.py +65 -0
- streamwright-0.1.9/src/streamwright/core/sdk/operations/files.py +74 -0
- streamwright-0.1.9/src/streamwright/core/sdk/operations/http.py +74 -0
- streamwright-0.1.9/src/streamwright/core/sdk/operations/messages.py +28 -0
- streamwright-0.1.9/src/streamwright/core/sdk/operations/tables.py +70 -0
- streamwright-0.1.9/src/streamwright/core/sdk/py.typed +0 -0
- streamwright-0.1.9/src/streamwright/core/sdk/testing/__init__.py +84 -0
- streamwright-0.1.9/src/streamwright/core/sdk/testing/contract.py +199 -0
- streamwright-0.1.9/src/streamwright/core/sdk/testing/helpers.py +51 -0
- streamwright-0.1.9/src/streamwright/core/sdk/testing/storage.py +221 -0
- streamwright-0.1.9/src/streamwright/core/sql/__init__.py +22 -0
- streamwright-0.1.9/src/streamwright/core/sql/analysis.py +47 -0
- streamwright-0.1.9/src/streamwright/core/sql/conditions.py +96 -0
- streamwright-0.1.9/src/streamwright/core/sql/quote.py +55 -0
- streamwright-0.1.9/src/streamwright/core/validation/__init__.py +3 -0
- streamwright-0.1.9/src/streamwright/core/validation/auth.py +59 -0
- streamwright-0.1.9/src/streamwright/core/validation/checker.py +149 -0
- streamwright-0.1.9/src/streamwright/core/validation/engine.py +347 -0
- streamwright-0.1.9/src/streamwright/core/validation/issues.py +42 -0
- streamwright-0.1.9/src/streamwright/core/validation/job_manifests.py +131 -0
- streamwright-0.1.8/src/streamwright/core/validation/schema.py → streamwright-0.1.9/src/streamwright/core/validation/json_schemas.py +107 -252
- streamwright-0.1.9/src/streamwright/core/validation/marked_yaml.py +137 -0
- streamwright-0.1.9/src/streamwright/core/validation/partitions.py +69 -0
- streamwright-0.1.9/src/streamwright/core/validation/requests.py +80 -0
- streamwright-0.1.9/src/streamwright/core/validation/schema.py +122 -0
- streamwright-0.1.9/src/streamwright/core/validation/sections/__init__.py +17 -0
- streamwright-0.1.9/src/streamwright/core/validation/sections/async_jobs.py +153 -0
- streamwright-0.1.9/src/streamwright/core/validation/sections/document.py +128 -0
- streamwright-0.1.9/src/streamwright/core/validation/sections/partitions.py +147 -0
- streamwright-0.1.9/src/streamwright/core/validation/sections/references.py +125 -0
- streamwright-0.1.9/src/streamwright/core/validation/sections/request_partitions.py +152 -0
- streamwright-0.1.9/src/streamwright/core/validation/sections/requests.py +79 -0
- streamwright-0.1.9/src/streamwright/core/validation/sections/spec.py +205 -0
- streamwright-0.1.9/src/streamwright/core/validation/sections/stream_context.py +47 -0
- streamwright-0.1.9/src/streamwright/core/validation/sections/streams.py +171 -0
- streamwright-0.1.9/src/streamwright/core/validation/sections/tables.py +132 -0
- streamwright-0.1.9/src/streamwright/core/validation/sections/templates.py +32 -0
- streamwright-0.1.9/src/streamwright/core/validation/source.py +30 -0
- streamwright-0.1.9/src/streamwright/core/validation/streams.py +81 -0
- streamwright-0.1.9/src/streamwright/core/validation/vocabulary.py +142 -0
- streamwright-0.1.9/src/streamwright.egg-info/PKG-INFO +93 -0
- streamwright-0.1.9/src/streamwright.egg-info/SOURCES.txt +239 -0
- streamwright-0.1.9/src/streamwright.egg-info/entry_points.txt +12 -0
- {streamwright-0.1.8 → streamwright-0.1.9}/src/streamwright.egg-info/requires.txt +1 -1
- {streamwright-0.1.8 → streamwright-0.1.9}/tests/test_catalog.py +43 -15
- streamwright-0.1.9/tests/test_cli_subcommands.py +122 -0
- streamwright-0.1.9/tests/test_conditions.py +42 -0
- streamwright-0.1.9/tests/test_connector_api_family.py +129 -0
- streamwright-0.1.9/tests/test_connector_contract.py +329 -0
- {streamwright-0.1.8 → streamwright-0.1.9}/tests/test_connectors.py +165 -123
- {streamwright-0.1.8 → streamwright-0.1.9}/tests/test_dlt_output.py +48 -21
- streamwright-0.1.9/tests/test_engine_reach.py +30 -0
- {streamwright-0.1.8 → streamwright-0.1.9}/tests/test_exact_decimals.py +24 -29
- streamwright-0.1.9/tests/test_graph.py +12 -0
- {streamwright-0.1.8 → streamwright-0.1.9}/tests/test_http_engine.py +117 -35
- {streamwright-0.1.8 → streamwright-0.1.9}/tests/test_logging.py +189 -84
- streamwright-0.1.9/tests/test_output_contract.py +36 -0
- {streamwright-0.1.8 → streamwright-0.1.9}/tests/test_output_formats.py +32 -24
- streamwright-0.1.9/tests/test_plugin_contract_gate.py +35 -0
- {streamwright-0.1.8 → streamwright-0.1.9}/tests/test_runner.py +132 -51
- streamwright-0.1.9/tests/test_sdk_plugins.py +162 -0
- {streamwright-0.1.8 → streamwright-0.1.9}/tests/test_sql.py +7 -6
- streamwright-0.1.9/tests/test_sql_quote.py +34 -0
- {streamwright-0.1.8 → streamwright-0.1.9}/tests/test_transform.py +76 -59
- {streamwright-0.1.8 → streamwright-0.1.9}/tests/test_validation.py +299 -81
- {streamwright-0.1.8 → streamwright-0.1.9}/tests/test_warehouse_output.py +153 -56
- streamwright-0.1.8/PKG-INFO +0 -127
- streamwright-0.1.8/README.md +0 -98
- streamwright-0.1.8/src/streamwright/core/cli.py +0 -662
- streamwright-0.1.8/src/streamwright/core/engine/runner.py +0 -1049
- streamwright-0.1.8/src/streamwright/core/engine/sql.py +0 -1294
- streamwright-0.1.8/src/streamwright/core/net/http.py +0 -475
- streamwright-0.1.8/src/streamwright/core/outputs/exporter.py +0 -289
- streamwright-0.1.8/src/streamwright/core/outputs/output.py +0 -509
- streamwright-0.1.8/src/streamwright/core/runtime/components.py +0 -476
- streamwright-0.1.8/src/streamwright/core/runtime/logs.py +0 -791
- streamwright-0.1.8/src/streamwright/core/validation/engine.py +0 -595
- streamwright-0.1.8/src/streamwright/core/validation/source.py +0 -1265
- streamwright-0.1.8/src/streamwright.egg-info/PKG-INFO +0 -127
- streamwright-0.1.8/src/streamwright.egg-info/SOURCES.txt +0 -55
- streamwright-0.1.8/src/streamwright.egg-info/entry_points.txt +0 -3
- streamwright-0.1.8/tests/test_cli_subcommands.py +0 -72
- streamwright-0.1.8/tests/test_exporter.py +0 -69
- {streamwright-0.1.8 → streamwright-0.1.9}/LICENSE +0 -0
- {streamwright-0.1.8 → streamwright-0.1.9}/setup.cfg +0 -0
- {streamwright-0.1.8 → streamwright-0.1.9}/setup.py +0 -0
- {streamwright-0.1.8 → streamwright-0.1.9}/src/streamwright/core/__init__.py +0 -0
- {streamwright-0.1.8 → streamwright-0.1.9}/src/streamwright/core/config/__init__.py +0 -0
- {streamwright-0.1.8 → streamwright-0.1.9}/src/streamwright/core/engine/__init__.py +0 -0
- {streamwright-0.1.8 → streamwright-0.1.9}/src/streamwright/core/net/__init__.py +0 -0
- {streamwright-0.1.8 → streamwright-0.1.9}/src/streamwright/core/outputs/__init__.py +0 -0
- /streamwright-0.1.8/src/streamwright/core/runtime/__init__.py → /streamwright-0.1.9/src/streamwright/core/py.typed +0 -0
- {streamwright-0.1.8/src/streamwright/core/validation → streamwright-0.1.9/src/streamwright/core/runtime}/__init__.py +0 -0
- {streamwright-0.1.8 → streamwright-0.1.9}/src/streamwright.egg-info/dependency_links.txt +0 -0
- {streamwright-0.1.8 → streamwright-0.1.9}/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.9
|
|
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
|
+
[](https://pypi.org/project/streamwright/)
|
|
32
|
+
[](https://pypi.org/project/streamwright/)
|
|
33
|
+
[](https://github.com/karthick-jaganathan/streamwright/blob/master/LICENSE)
|
|
34
|
+
[](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
|
+
[](https://pypi.org/project/streamwright/)
|
|
4
|
+
[](https://pypi.org/project/streamwright/)
|
|
5
|
+
[](https://github.com/karthick-jaganathan/streamwright/blob/master/LICENSE)
|
|
6
|
+
[](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.
|
|
7
|
+
version = "0.1.9"
|
|
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.
|
|
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>=
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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 @@
|
|
|
1
|
+
"""Built-in commands."""
|
|
@@ -0,0 +1,103 @@
|
|
|
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 sys
|
|
21
|
+
|
|
22
|
+
from streamwright.core import catalog
|
|
23
|
+
from streamwright.core.runtime import components, plugins
|
|
24
|
+
from streamwright.core.runtime.definitions import engine_reach
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def _connector_lines():
|
|
28
|
+
"""
|
|
29
|
+
The installed (and registered) connectors by family: name, title, distribution and version, and how each engine
|
|
30
|
+
reaches them — native or via a call step, in the fixed order source, duckdb, spark (only specs are imported).
|
|
31
|
+
"""
|
|
32
|
+
metadata = {entry["name"]: entry for entry in plugins.discover(plugins.CONNECTORS)}
|
|
33
|
+
groups = {}
|
|
34
|
+
for name in components.available():
|
|
35
|
+
entry = metadata.get(name, {})
|
|
36
|
+
package = "%s %s" % (entry.get("distribution") or "registered in-process", entry.get("version") or "")
|
|
37
|
+
try:
|
|
38
|
+
definition = components.load(name)
|
|
39
|
+
except components.ComponentLoadError as exc:
|
|
40
|
+
groups.setdefault("unavailable", []).append(" %-15s%s" % (name, exc))
|
|
41
|
+
continue
|
|
42
|
+
groups.setdefault(definition.family, []).append(" %-15s%-23s%-34s[%s]" % (
|
|
43
|
+
name, definition.title, package.strip(), ", ".join(engine_reach(definition))))
|
|
44
|
+
lines = []
|
|
45
|
+
for family in sorted(groups):
|
|
46
|
+
if lines:
|
|
47
|
+
lines.append("")
|
|
48
|
+
lines.append("%s:" % family)
|
|
49
|
+
lines.extend(sorted(groups[family]))
|
|
50
|
+
return lines
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def run_connectors_command(args):
|
|
54
|
+
"""`streamwright connectors`: bare = installed list; ls/i/find use the catalog (the hub)."""
|
|
55
|
+
if getattr(args, "flag_list", False):
|
|
56
|
+
action = "ls"
|
|
57
|
+
query = []
|
|
58
|
+
elif getattr(args, "flag_install", None):
|
|
59
|
+
action = "install"
|
|
60
|
+
query = args.flag_install
|
|
61
|
+
elif getattr(args, "flag_search", None):
|
|
62
|
+
action = "find"
|
|
63
|
+
query = args.flag_search
|
|
64
|
+
else:
|
|
65
|
+
action = getattr(args, "action", None)
|
|
66
|
+
query = getattr(args, "query", [])
|
|
67
|
+
|
|
68
|
+
if action is None:
|
|
69
|
+
lines = _connector_lines()
|
|
70
|
+
print("\n".join(lines) if lines else "no connectors installed (use streamwright connectors list to find one)")
|
|
71
|
+
return 0
|
|
72
|
+
|
|
73
|
+
norm_action = action.lower()
|
|
74
|
+
if norm_action in ("ls", "list", "-ls", "--list"):
|
|
75
|
+
lines = catalog.listing(args.hub_url)
|
|
76
|
+
print("\n".join(lines) if lines else "the catalog is empty")
|
|
77
|
+
return 0
|
|
78
|
+
|
|
79
|
+
if norm_action in ("i", "install", "-i", "--install"):
|
|
80
|
+
if not query:
|
|
81
|
+
sys.stderr.write("streamwright: 'connectors -i' needs at least one connector KEY\n")
|
|
82
|
+
return 2
|
|
83
|
+
return catalog.install_many(query, assume_yes=args.yes, hub_url=args.hub_url)
|
|
84
|
+
|
|
85
|
+
if norm_action in ("find", "search", "s", "-s", "-f", "--find", "--search"):
|
|
86
|
+
text = " ".join(query)
|
|
87
|
+
hits = catalog.search(text, args.hub_url)
|
|
88
|
+
if not hits:
|
|
89
|
+
print("no connectors match %r" % text)
|
|
90
|
+
return 0
|
|
91
|
+
for key, entry in sorted(hits.items()):
|
|
92
|
+
print(" %-16s %-10s %s" % (key, entry.get("trust", "community"), entry.get("summary", "")))
|
|
93
|
+
return 0
|
|
94
|
+
|
|
95
|
+
# If action was not a reserved verb, treat it as a direct search query (e.g. `sw connectors ads`)
|
|
96
|
+
text = " ".join([action, *query])
|
|
97
|
+
hits = catalog.search(text, args.hub_url)
|
|
98
|
+
if not hits:
|
|
99
|
+
print("no connectors match %r" % text)
|
|
100
|
+
return 0
|
|
101
|
+
for key, entry in sorted(hits.items()):
|
|
102
|
+
print(" %-16s %-10s %s" % (key, entry.get("trust", "community"), entry.get("summary", "")))
|
|
103
|
+
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
|