streamwright 0.0.1__tar.gz → 0.1.2__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.2/PKG-INFO +77 -0
- streamwright-0.1.2/README.md +49 -0
- streamwright-0.1.2/pyproject.toml +62 -0
- streamwright-0.1.2/setup.py +21 -0
- streamwright-0.1.2/src/streamwright/core/__init__.py +18 -0
- streamwright-0.1.2/src/streamwright/core/catalog.py +150 -0
- streamwright-0.1.2/src/streamwright/core/cli.py +590 -0
- streamwright-0.1.2/src/streamwright/core/config/__init__.py +0 -0
- streamwright-0.1.2/src/streamwright/core/config/inputs.py +228 -0
- streamwright-0.1.2/src/streamwright/core/config/loader.py +220 -0
- streamwright-0.1.2/src/streamwright/core/config/reader.py +34 -0
- streamwright-0.1.2/src/streamwright/core/connectors.json +91 -0
- streamwright-0.1.2/src/streamwright/core/engine/__init__.py +0 -0
- streamwright-0.1.2/src/streamwright/core/engine/queries.py +130 -0
- streamwright-0.1.2/src/streamwright/core/engine/runner.py +983 -0
- streamwright-0.1.2/src/streamwright/core/engine/sql.py +1294 -0
- streamwright-0.1.2/src/streamwright/core/net/__init__.py +0 -0
- streamwright-0.1.2/src/streamwright/core/net/downloads.py +93 -0
- streamwright-0.1.2/src/streamwright/core/net/http.py +453 -0
- streamwright-0.1.2/src/streamwright/core/outputs/__init__.py +0 -0
- streamwright-0.1.2/src/streamwright/core/outputs/dlt_output.py +252 -0
- streamwright-0.1.2/src/streamwright/core/outputs/exporter.py +289 -0
- streamwright-0.1.2/src/streamwright/core/outputs/output.py +509 -0
- streamwright-0.1.2/src/streamwright/core/outputs/staging.py +206 -0
- streamwright-0.1.2/src/streamwright/core/outputs/warehouse.py +546 -0
- streamwright-0.1.2/src/streamwright/core/runtime/__init__.py +0 -0
- streamwright-0.1.2/src/streamwright/core/runtime/components.py +392 -0
- streamwright-0.1.2/src/streamwright/core/runtime/logs.py +791 -0
- streamwright-0.1.2/src/streamwright/core/runtime/templates.py +199 -0
- streamwright-0.1.2/src/streamwright/core/runtime/testing.py +179 -0
- streamwright-0.1.2/src/streamwright/core/validation/__init__.py +0 -0
- streamwright-0.1.2/src/streamwright/core/validation/engine.py +595 -0
- streamwright-0.1.2/src/streamwright/core/validation/schema.py +384 -0
- streamwright-0.1.2/src/streamwright/core/validation/source.py +1187 -0
- streamwright-0.1.2/src/streamwright.egg-info/PKG-INFO +77 -0
- streamwright-0.1.2/src/streamwright.egg-info/SOURCES.txt +51 -0
- streamwright-0.1.2/src/streamwright.egg-info/entry_points.txt +2 -0
- streamwright-0.1.2/src/streamwright.egg-info/requires.txt +7 -0
- streamwright-0.1.2/src/streamwright.egg-info/top_level.txt +1 -0
- streamwright-0.1.2/tests/test_connectors.py +534 -0
- streamwright-0.1.2/tests/test_dlt_output.py +304 -0
- streamwright-0.1.2/tests/test_exact_decimals.py +442 -0
- streamwright-0.1.2/tests/test_exporter.py +69 -0
- streamwright-0.1.2/tests/test_logging.py +968 -0
- streamwright-0.1.2/tests/test_output_formats.py +456 -0
- streamwright-0.1.2/tests/test_runner.py +866 -0
- streamwright-0.1.2/tests/test_sql.py +380 -0
- streamwright-0.1.2/tests/test_transform.py +1297 -0
- streamwright-0.1.2/tests/test_validation.py +1735 -0
- streamwright-0.1.2/tests/test_warehouse_output.py +591 -0
- streamwright-0.0.1/PKG-INFO +0 -40
- streamwright-0.0.1/README.md +0 -17
- streamwright-0.0.1/pyproject.toml +0 -34
- streamwright-0.0.1/streamwright.egg-info/PKG-INFO +0 -40
- streamwright-0.0.1/streamwright.egg-info/SOURCES.txt +0 -9
- streamwright-0.0.1/streamwright.egg-info/entry_points.txt +0 -2
- streamwright-0.0.1/streamwright.egg-info/requires.txt +0 -1
- streamwright-0.0.1/streamwright.egg-info/top_level.txt +0 -1
- {streamwright-0.0.1 → streamwright-0.1.2}/LICENSE +0 -0
- {streamwright-0.0.1 → streamwright-0.1.2}/setup.cfg +0 -0
- {streamwright-0.0.1 → streamwright-0.1.2/src}/streamwright.egg-info/dependency_links.txt +0 -0
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: streamwright
|
|
3
|
+
Version: 0.1.2
|
|
4
|
+
Summary: Declarative data connectors — pull from APIs, files and databases with YAML, shape with SQL, write anywhere.
|
|
5
|
+
Author: Karthick Jaganathan
|
|
6
|
+
License-Expression: Apache-2.0
|
|
7
|
+
Project-URL: Homepage, https://github.com/karthick-jaganathan/streamwright
|
|
8
|
+
Project-URL: Repository, https://github.com/karthick-jaganathan/streamwright
|
|
9
|
+
Project-URL: Documentation, https://streamwright.web.app/docs/
|
|
10
|
+
Keywords: data,pipeline,etl,connector,singer,yaml
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
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.10
|
|
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>=1.5.2
|
|
24
|
+
Requires-Dist: pytz
|
|
25
|
+
Provides-Extra: dlt
|
|
26
|
+
Requires-Dist: dlt>=1.0; extra == "dlt"
|
|
27
|
+
Dynamic: license-file
|
|
28
|
+
|
|
29
|
+
# StreamWright — the `streamwright` CLI and runtime
|
|
30
|
+
|
|
31
|
+
**StreamWright turns a few YAML files into a working data pipeline.** You describe *what*
|
|
32
|
+
to pull — from an API, a file store or a database — and StreamWright handles the *how*:
|
|
33
|
+
signing in, paging, retries, shaping the data with DuckDB SQL, and writing it out.
|
|
34
|
+
No per-connector code, and one command runs any source.
|
|
35
|
+
|
|
36
|
+
The `streamwright` package is the heart of it: the `streamwright` command plus the runtime for
|
|
37
|
+
`kind: source` sources. *(Formerly published as `adapt-core`.)*
|
|
38
|
+
|
|
39
|
+
- **`streamwright run`** executes a source · **`streamwright validate`** checks one · **`streamwright connectors`** browses and installs connectors.
|
|
40
|
+
- A source is a folder — `source.yaml` (`spec`, `auth`, `http`) and one file per stream in `streams/` — or a single YAML file.
|
|
41
|
+
- Each stream **fetches** (HTTP requests / SDK connectors), **shapes** (sandboxed DuckDB SQL), and **writes** (files, DuckDB/DuckLake or dlt).
|
|
42
|
+
|
|
43
|
+
## Install
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
pip install streamwright
|
|
47
|
+
streamwright --help
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
This installs the `streamwright` CLI, the runtime and the connector hub — but no
|
|
51
|
+
connectors yet. Add the ones you need on demand:
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
streamwright connectors list # browse the hub
|
|
55
|
+
streamwright connectors install files # a reader (files, s3, gcs, postgres)
|
|
56
|
+
streamwright connectors install google_ads # an API connector (pulls in its SDK)
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Quickstart
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
pip install streamwright
|
|
63
|
+
streamwright connectors install files
|
|
64
|
+
|
|
65
|
+
# the runnable examples live in the repo — clone it to try one end-to-end
|
|
66
|
+
git clone https://github.com/karthick-jaganathan/streamwright.git
|
|
67
|
+
streamwright validate streamwright/examples
|
|
68
|
+
streamwright run streamwright/examples/sources/readers/files_demo \
|
|
69
|
+
--set data_root=streamwright/examples/sources/readers/files_demo/data \
|
|
70
|
+
--allow-connector files --output jsonl:out
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
📖 **Full documentation:** https://streamwright.web.app/docs/ — command line,
|
|
74
|
+
streams, outputs, logging, connectors & readers and the Python API.
|
|
75
|
+
|
|
76
|
+
- Architecture guide: https://streamwright.web.app/docs/architecture/
|
|
77
|
+
- Connectors & readers: https://streamwright.web.app/docs/connectors/
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# StreamWright — the `streamwright` CLI and runtime
|
|
2
|
+
|
|
3
|
+
**StreamWright turns a few YAML files into a working data pipeline.** You describe *what*
|
|
4
|
+
to pull — from an API, a file store or a database — and StreamWright handles the *how*:
|
|
5
|
+
signing in, paging, retries, shaping the data with DuckDB SQL, and writing it out.
|
|
6
|
+
No per-connector code, and one command runs any source.
|
|
7
|
+
|
|
8
|
+
The `streamwright` package is the heart of it: the `streamwright` command plus the runtime for
|
|
9
|
+
`kind: source` sources. *(Formerly published as `adapt-core`.)*
|
|
10
|
+
|
|
11
|
+
- **`streamwright run`** executes a source · **`streamwright validate`** checks one · **`streamwright connectors`** browses and installs connectors.
|
|
12
|
+
- A source is a folder — `source.yaml` (`spec`, `auth`, `http`) and one file per stream in `streams/` — or a single YAML file.
|
|
13
|
+
- Each stream **fetches** (HTTP requests / SDK connectors), **shapes** (sandboxed DuckDB SQL), and **writes** (files, DuckDB/DuckLake or dlt).
|
|
14
|
+
|
|
15
|
+
## Install
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
pip install streamwright
|
|
19
|
+
streamwright --help
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
This installs the `streamwright` CLI, the runtime and the connector hub — but no
|
|
23
|
+
connectors yet. Add the ones you need on demand:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
streamwright connectors list # browse the hub
|
|
27
|
+
streamwright connectors install files # a reader (files, s3, gcs, postgres)
|
|
28
|
+
streamwright connectors install google_ads # an API connector (pulls in its SDK)
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Quickstart
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
pip install streamwright
|
|
35
|
+
streamwright connectors install files
|
|
36
|
+
|
|
37
|
+
# the runnable examples live in the repo — clone it to try one end-to-end
|
|
38
|
+
git clone https://github.com/karthick-jaganathan/streamwright.git
|
|
39
|
+
streamwright validate streamwright/examples
|
|
40
|
+
streamwright run streamwright/examples/sources/readers/files_demo \
|
|
41
|
+
--set data_root=streamwright/examples/sources/readers/files_demo/data \
|
|
42
|
+
--allow-connector files --output jsonl:out
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
📖 **Full documentation:** https://streamwright.web.app/docs/ — command line,
|
|
46
|
+
streams, outputs, logging, connectors & readers and the Python API.
|
|
47
|
+
|
|
48
|
+
- Architecture guide: https://streamwright.web.app/docs/architecture/
|
|
49
|
+
- Connectors & readers: https://streamwright.web.app/docs/connectors/
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61.0.0", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "streamwright"
|
|
7
|
+
version = "0.1.2"
|
|
8
|
+
description = "Declarative data connectors — pull from APIs, files and databases with YAML, shape with SQL, write anywhere."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = "Apache-2.0"
|
|
11
|
+
authors = [
|
|
12
|
+
{name = "Karthick Jaganathan"},
|
|
13
|
+
]
|
|
14
|
+
keywords = ["data", "pipeline", "etl", "connector", "singer", "yaml"]
|
|
15
|
+
classifiers = [
|
|
16
|
+
"Development Status :: 3 - Alpha",
|
|
17
|
+
"Intended Audience :: Developers",
|
|
18
|
+
"Programming Language :: Python :: 3",
|
|
19
|
+
"Programming Language :: Python :: 3.10",
|
|
20
|
+
"Programming Language :: Python :: 3.11",
|
|
21
|
+
"Programming Language :: Python :: 3.12",
|
|
22
|
+
"Programming Language :: Python :: 3.13",
|
|
23
|
+
]
|
|
24
|
+
requires-python = ">=3.10"
|
|
25
|
+
dependencies = [
|
|
26
|
+
"pyyaml==6.0.2",
|
|
27
|
+
"requests>=2.25,<3",
|
|
28
|
+
# `select`: the SQL that shapes each stream's records runs in an embedded DuckDB (which needs pytz for
|
|
29
|
+
# timestamps with time zones)
|
|
30
|
+
"duckdb>=1.5.2",
|
|
31
|
+
"pytz",
|
|
32
|
+
]
|
|
33
|
+
|
|
34
|
+
[project.optional-dependencies]
|
|
35
|
+
# --output dlt:DESTINATION; also install the destination's extra, e.g. "dlt[duckdb]" or "dlt[bigquery]"
|
|
36
|
+
dlt = ["dlt>=1.0"]
|
|
37
|
+
|
|
38
|
+
[project.urls]
|
|
39
|
+
Homepage = "https://github.com/karthick-jaganathan/streamwright"
|
|
40
|
+
Repository = "https://github.com/karthick-jaganathan/streamwright"
|
|
41
|
+
Documentation = "https://streamwright.web.app/docs/"
|
|
42
|
+
|
|
43
|
+
[project.scripts]
|
|
44
|
+
# `streamwright run`, `streamwright validate`, `streamwright connectors` - one CLI (see streamwright.core.cli)
|
|
45
|
+
streamwright = "streamwright.core.cli:main"
|
|
46
|
+
|
|
47
|
+
[tool.setuptools]
|
|
48
|
+
# src layout: `streamwright` is a namespace package shared with the connector distributions (streamwright.connectors.*)
|
|
49
|
+
package-dir = {"" = "src"}
|
|
50
|
+
packages = [
|
|
51
|
+
"streamwright.core",
|
|
52
|
+
"streamwright.core.engine",
|
|
53
|
+
"streamwright.core.outputs",
|
|
54
|
+
"streamwright.core.net",
|
|
55
|
+
"streamwright.core.config",
|
|
56
|
+
"streamwright.core.validation",
|
|
57
|
+
"streamwright.core.runtime",
|
|
58
|
+
]
|
|
59
|
+
|
|
60
|
+
[tool.setuptools.package-data]
|
|
61
|
+
# the bundled connector catalog (default for `streamwright connectors`, refreshed from $STREAMWRIGHT_HUB_URL)
|
|
62
|
+
"streamwright.core" = ["connectors.json"]
|
|
@@ -0,0 +1,21 @@
|
|
|
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
|
+
from setuptools import setup
|
|
19
|
+
|
|
20
|
+
# Configuration is now in pyproject.toml
|
|
21
|
+
setup()
|
|
@@ -0,0 +1,18 @@
|
|
|
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
|
+
"""Run-time StreamWright sources (`kind: source`). Entry point: the `streamwright` command (streamwright.core.cli)."""
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
"""The connector catalog: discover and install connectors from the StreamWright hub.
|
|
3
|
+
|
|
4
|
+
A catalog is a static index (bundled with streamwright, optionally refreshed from a
|
|
5
|
+
remote hub URL) that maps a connector key to how it's installed - a PyPI
|
|
6
|
+
requirement, a pinned git URL, or an image. The key is the same name used in
|
|
7
|
+
source YAML (`provider`/`sdk`); the install source is just a delivery detail, so
|
|
8
|
+
a package can move from git to PyPI without changing what users type.
|
|
9
|
+
|
|
10
|
+
Security: non-"official" connectors run third-party code, so `install` asks for
|
|
11
|
+
confirmation (or `--yes`) and refuses non-interactive installs without it.
|
|
12
|
+
"""
|
|
13
|
+
import json
|
|
14
|
+
import os
|
|
15
|
+
import subprocess
|
|
16
|
+
import sys
|
|
17
|
+
from pathlib import Path
|
|
18
|
+
|
|
19
|
+
try:
|
|
20
|
+
from importlib import resources
|
|
21
|
+
except ImportError: # pragma: no cover
|
|
22
|
+
import importlib_resources as resources
|
|
23
|
+
|
|
24
|
+
from streamwright.core.runtime import components
|
|
25
|
+
|
|
26
|
+
HUB_ENV = "STREAMWRIGHT_HUB_URL"
|
|
27
|
+
CACHE = Path(os.path.expanduser("~/.streamwright/connectors.json"))
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def _bundled():
|
|
31
|
+
text = resources.files("streamwright.core").joinpath("connectors.json").read_text()
|
|
32
|
+
return json.loads(text)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def _remote(url):
|
|
36
|
+
import requests
|
|
37
|
+
|
|
38
|
+
response = requests.get(url, timeout=10)
|
|
39
|
+
response.raise_for_status()
|
|
40
|
+
data = response.json()
|
|
41
|
+
try:
|
|
42
|
+
CACHE.parent.mkdir(parents=True, exist_ok=True)
|
|
43
|
+
CACHE.write_text(json.dumps(data))
|
|
44
|
+
except OSError:
|
|
45
|
+
pass
|
|
46
|
+
return data
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def load(hub_url=None):
|
|
50
|
+
"""The catalog: the remote hub if configured (cached), else the bundled default."""
|
|
51
|
+
url = hub_url or os.environ.get(HUB_ENV)
|
|
52
|
+
if url:
|
|
53
|
+
try:
|
|
54
|
+
return _remote(url)
|
|
55
|
+
except Exception: # offline or hub down: fall back
|
|
56
|
+
pass
|
|
57
|
+
if CACHE.exists():
|
|
58
|
+
try:
|
|
59
|
+
return json.loads(CACHE.read_text())
|
|
60
|
+
except Exception:
|
|
61
|
+
pass
|
|
62
|
+
return _bundled()
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def connectors(hub_url=None):
|
|
66
|
+
return load(hub_url).get("connectors", {})
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def installed():
|
|
70
|
+
try:
|
|
71
|
+
return set(components.available())
|
|
72
|
+
except Exception:
|
|
73
|
+
return set()
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def search(text, hub_url=None):
|
|
77
|
+
text = (text or "").lower()
|
|
78
|
+
hits = {}
|
|
79
|
+
for key, entry in connectors(hub_url).items():
|
|
80
|
+
haystack = " ".join([key, entry.get("title", ""), entry.get("summary", ""),
|
|
81
|
+
entry.get("family", "")]).lower()
|
|
82
|
+
if text in haystack:
|
|
83
|
+
hits[key] = entry
|
|
84
|
+
return hits
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def _source_of(install):
|
|
88
|
+
if "pip" in install:
|
|
89
|
+
return "PyPI: " + install["pip"]
|
|
90
|
+
if "git" in install:
|
|
91
|
+
return "git: " + install["git"]
|
|
92
|
+
if "image" in install:
|
|
93
|
+
return "image: " + install["image"]
|
|
94
|
+
return "unknown"
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def listing(hub_url=None):
|
|
98
|
+
"""Lines for `streamwright connectors list`: every catalog connector with install state + trust."""
|
|
99
|
+
have = installed()
|
|
100
|
+
lines = []
|
|
101
|
+
by_family = {}
|
|
102
|
+
for key, entry in connectors(hub_url).items():
|
|
103
|
+
by_family.setdefault(entry.get("family", "other"), []).append((key, entry))
|
|
104
|
+
for family in sorted(by_family):
|
|
105
|
+
lines.append("%s:" % family)
|
|
106
|
+
for key, entry in sorted(by_family[family]):
|
|
107
|
+
mark = "[installed]" if key in have else " "
|
|
108
|
+
trust = entry.get("trust", "community")
|
|
109
|
+
lines.append(" %s %-16s %-10s %s" % (mark, key, trust, entry.get("summary", "")))
|
|
110
|
+
return lines
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def install(key, assume_yes=False, hub_url=None, pip_args=()):
|
|
114
|
+
"""Resolve `key` in the catalog and install it (pip for pip/git; images are run, not installed)."""
|
|
115
|
+
entry = connectors(hub_url).get(key)
|
|
116
|
+
if not entry:
|
|
117
|
+
sys.stderr.write("streamwright: unknown connector %r (try: streamwright connectors list)\n" % key)
|
|
118
|
+
return 2
|
|
119
|
+
inst = entry.get("install", {})
|
|
120
|
+
trust = entry.get("trust", "community")
|
|
121
|
+
|
|
122
|
+
if "image" in inst:
|
|
123
|
+
print("%r is distributed as an image, not a Python package:" % key)
|
|
124
|
+
print(" %s" % inst["image"])
|
|
125
|
+
print("Run it with the docker or k8s execution mode (it is not pip-installed).")
|
|
126
|
+
return 0
|
|
127
|
+
|
|
128
|
+
spec = inst.get("pip") or inst.get("git")
|
|
129
|
+
if not spec:
|
|
130
|
+
sys.stderr.write("streamwright: connector %r has no installable source\n" % key)
|
|
131
|
+
return 2
|
|
132
|
+
|
|
133
|
+
if trust != "official" and not assume_yes:
|
|
134
|
+
source = _source_of(inst)
|
|
135
|
+
if not sys.stdin.isatty():
|
|
136
|
+
sys.stderr.write(
|
|
137
|
+
"streamwright: refusing to install %s connector %r non-interactively; pass --yes to confirm (%s)\n"
|
|
138
|
+
% (trust, key, source))
|
|
139
|
+
return 2
|
|
140
|
+
sys.stderr.write(
|
|
141
|
+
"\n WARNING: %r is a %s connector. Installing runs third-party code from:\n %s\n"
|
|
142
|
+
% (key, trust, source))
|
|
143
|
+
answer = input(" Continue? [y/N] ").strip().lower()
|
|
144
|
+
if answer not in ("y", "yes"):
|
|
145
|
+
print("aborted")
|
|
146
|
+
return 1
|
|
147
|
+
|
|
148
|
+
cmd = [sys.executable, "-m", "pip", "install", *pip_args, spec]
|
|
149
|
+
print("+ " + " ".join(cmd))
|
|
150
|
+
return subprocess.call(cmd)
|