streamwright 0.1.6__tar.gz → 0.1.8__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 (57) hide show
  1. {streamwright-0.1.6/src/streamwright.egg-info → streamwright-0.1.8}/PKG-INFO +11 -6
  2. {streamwright-0.1.6 → streamwright-0.1.8}/README.md +7 -3
  3. {streamwright-0.1.6 → streamwright-0.1.8}/pyproject.toml +5 -3
  4. {streamwright-0.1.6 → streamwright-0.1.8}/src/streamwright/core/cli.py +63 -18
  5. {streamwright-0.1.6 → streamwright-0.1.8}/src/streamwright/core/validation/schema.py +94 -5
  6. {streamwright-0.1.6 → streamwright-0.1.8/src/streamwright.egg-info}/PKG-INFO +11 -6
  7. {streamwright-0.1.6 → streamwright-0.1.8}/src/streamwright.egg-info/SOURCES.txt +1 -0
  8. {streamwright-0.1.6 → streamwright-0.1.8}/src/streamwright.egg-info/entry_points.txt +1 -0
  9. streamwright-0.1.8/tests/test_cli_subcommands.py +72 -0
  10. {streamwright-0.1.6 → streamwright-0.1.8}/tests/test_validation.py +9 -1
  11. {streamwright-0.1.6 → streamwright-0.1.8}/LICENSE +0 -0
  12. {streamwright-0.1.6 → streamwright-0.1.8}/setup.cfg +0 -0
  13. {streamwright-0.1.6 → streamwright-0.1.8}/setup.py +0 -0
  14. {streamwright-0.1.6 → streamwright-0.1.8}/src/streamwright/core/__init__.py +0 -0
  15. {streamwright-0.1.6 → streamwright-0.1.8}/src/streamwright/core/catalog.py +0 -0
  16. {streamwright-0.1.6 → streamwright-0.1.8}/src/streamwright/core/config/__init__.py +0 -0
  17. {streamwright-0.1.6 → streamwright-0.1.8}/src/streamwright/core/config/inputs.py +0 -0
  18. {streamwright-0.1.6 → streamwright-0.1.8}/src/streamwright/core/config/loader.py +0 -0
  19. {streamwright-0.1.6 → streamwright-0.1.8}/src/streamwright/core/config/reader.py +0 -0
  20. {streamwright-0.1.6 → streamwright-0.1.8}/src/streamwright/core/engine/__init__.py +0 -0
  21. {streamwright-0.1.6 → streamwright-0.1.8}/src/streamwright/core/engine/queries.py +0 -0
  22. {streamwright-0.1.6 → streamwright-0.1.8}/src/streamwright/core/engine/runner.py +0 -0
  23. {streamwright-0.1.6 → streamwright-0.1.8}/src/streamwright/core/engine/sql.py +0 -0
  24. {streamwright-0.1.6 → streamwright-0.1.8}/src/streamwright/core/net/__init__.py +0 -0
  25. {streamwright-0.1.6 → streamwright-0.1.8}/src/streamwright/core/net/downloads.py +0 -0
  26. {streamwright-0.1.6 → streamwright-0.1.8}/src/streamwright/core/net/encoding.py +0 -0
  27. {streamwright-0.1.6 → streamwright-0.1.8}/src/streamwright/core/net/http.py +0 -0
  28. {streamwright-0.1.6 → streamwright-0.1.8}/src/streamwright/core/net/paginators.py +0 -0
  29. {streamwright-0.1.6 → streamwright-0.1.8}/src/streamwright/core/outputs/__init__.py +0 -0
  30. {streamwright-0.1.6 → streamwright-0.1.8}/src/streamwright/core/outputs/dlt_output.py +0 -0
  31. {streamwright-0.1.6 → streamwright-0.1.8}/src/streamwright/core/outputs/exporter.py +0 -0
  32. {streamwright-0.1.6 → streamwright-0.1.8}/src/streamwright/core/outputs/output.py +0 -0
  33. {streamwright-0.1.6 → streamwright-0.1.8}/src/streamwright/core/outputs/staging.py +0 -0
  34. {streamwright-0.1.6 → streamwright-0.1.8}/src/streamwright/core/outputs/warehouse.py +0 -0
  35. {streamwright-0.1.6 → streamwright-0.1.8}/src/streamwright/core/runtime/__init__.py +0 -0
  36. {streamwright-0.1.6 → streamwright-0.1.8}/src/streamwright/core/runtime/components.py +0 -0
  37. {streamwright-0.1.6 → streamwright-0.1.8}/src/streamwright/core/runtime/logs.py +0 -0
  38. {streamwright-0.1.6 → streamwright-0.1.8}/src/streamwright/core/runtime/templates.py +0 -0
  39. {streamwright-0.1.6 → streamwright-0.1.8}/src/streamwright/core/runtime/testing.py +0 -0
  40. {streamwright-0.1.6 → streamwright-0.1.8}/src/streamwright/core/validation/__init__.py +0 -0
  41. {streamwright-0.1.6 → streamwright-0.1.8}/src/streamwright/core/validation/engine.py +0 -0
  42. {streamwright-0.1.6 → streamwright-0.1.8}/src/streamwright/core/validation/source.py +0 -0
  43. {streamwright-0.1.6 → streamwright-0.1.8}/src/streamwright.egg-info/dependency_links.txt +0 -0
  44. {streamwright-0.1.6 → streamwright-0.1.8}/src/streamwright.egg-info/requires.txt +0 -0
  45. {streamwright-0.1.6 → streamwright-0.1.8}/src/streamwright.egg-info/top_level.txt +0 -0
  46. {streamwright-0.1.6 → streamwright-0.1.8}/tests/test_catalog.py +0 -0
  47. {streamwright-0.1.6 → streamwright-0.1.8}/tests/test_connectors.py +0 -0
  48. {streamwright-0.1.6 → streamwright-0.1.8}/tests/test_dlt_output.py +0 -0
  49. {streamwright-0.1.6 → streamwright-0.1.8}/tests/test_exact_decimals.py +0 -0
  50. {streamwright-0.1.6 → streamwright-0.1.8}/tests/test_exporter.py +0 -0
  51. {streamwright-0.1.6 → streamwright-0.1.8}/tests/test_http_engine.py +0 -0
  52. {streamwright-0.1.6 → streamwright-0.1.8}/tests/test_logging.py +0 -0
  53. {streamwright-0.1.6 → streamwright-0.1.8}/tests/test_output_formats.py +0 -0
  54. {streamwright-0.1.6 → streamwright-0.1.8}/tests/test_runner.py +0 -0
  55. {streamwright-0.1.6 → streamwright-0.1.8}/tests/test_sql.py +0 -0
  56. {streamwright-0.1.6 → streamwright-0.1.8}/tests/test_transform.py +0 -0
  57. {streamwright-0.1.6 → streamwright-0.1.8}/tests/test_warehouse_output.py +0 -0
@@ -1,12 +1,13 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: streamwright
3
- Version: 0.1.6
3
+ Version: 0.1.8
4
4
  Summary: Declarative data connectors — pull from APIs, files and databases with YAML, shape with SQL, write anywhere.
5
5
  Author-email: Karthick Jaganathan <kjaganathan.sde@gmail.com>
6
6
  License: Apache-2.0
7
- Project-URL: Homepage, https://github.com/karthick-jaganathan/streamwright
8
- Project-URL: Repository, https://github.com/karthick-jaganathan/streamwright
7
+ Project-URL: Homepage, https://streamwright.web.app
9
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
10
11
  Keywords: data,pipeline,etl,connector,singer,yaml,duckdb,rest-api
11
12
  Classifier: Development Status :: 3 - Alpha
12
13
  Classifier: Intended Audience :: Developers
@@ -44,9 +45,12 @@ Each stream follows a three-stage pipeline:
44
45
 
45
46
  ## CLI Commands
46
47
 
47
- - **`streamwright run`** — Execute a source and stream records to the configured destination.
48
- - **`streamwright validate`** — Validate source definitions, authentication specifications, and schemas without executing network requests.
49
- - **`streamwright connectors`** — Browse, inspect, and install connectors from the StreamWright Hub.
48
+ All commands can be invoked interchangeably using `streamwright` or the shorthand `sw` alias (e.g. `sw run`, `sw validate`, `sw connectors`, `sw mcp`).
49
+
50
+ - **`streamwright run`** (or **`sw run`**) — Execute a source and stream records to the configured destination.
51
+ - **`streamwright validate`** (or **`sw validate`**) — Validate source definitions, authentication specifications, and schemas without executing network requests.
52
+ - **`streamwright connectors`** (or **`sw connectors`**) — Browse, inspect, and install connectors from the StreamWright Hub.
53
+ - **`streamwright mcp`** (or **`sw mcp`**) — Launch the Model Context Protocol (MCP) server for AI coding assistants.
50
54
 
51
55
  ## Source Structure
52
56
 
@@ -120,3 +124,4 @@ streamwright run streamwright/examples/sources/readers/files_demo \
120
124
  - **Full documentation:** https://streamwright.web.app/docs/
121
125
  - **Architecture Guide:** https://streamwright.web.app/docs/architecture/
122
126
  - **Connectors & Readers:** https://streamwright.web.app/docs/connectors/
127
+ - **MCP Server Guide:** https://streamwright.web.app/docs/ai/mcp/
@@ -16,9 +16,12 @@ Each stream follows a three-stage pipeline:
16
16
 
17
17
  ## CLI Commands
18
18
 
19
- - **`streamwright run`** — Execute a source and stream records to the configured destination.
20
- - **`streamwright validate`** — Validate source definitions, authentication specifications, and schemas without executing network requests.
21
- - **`streamwright connectors`** — Browse, inspect, and install connectors from the StreamWright Hub.
19
+ All commands can be invoked interchangeably using `streamwright` or the shorthand `sw` alias (e.g. `sw run`, `sw validate`, `sw connectors`, `sw mcp`).
20
+
21
+ - **`streamwright run`** (or **`sw run`**) — Execute a source and stream records to the configured destination.
22
+ - **`streamwright validate`** (or **`sw validate`**) — Validate source definitions, authentication specifications, and schemas without executing network requests.
23
+ - **`streamwright connectors`** (or **`sw connectors`**) — Browse, inspect, and install connectors from the StreamWright Hub.
24
+ - **`streamwright mcp`** (or **`sw mcp`**) — Launch the Model Context Protocol (MCP) server for AI coding assistants.
22
25
 
23
26
  ## Source Structure
24
27
 
@@ -92,3 +95,4 @@ streamwright run streamwright/examples/sources/readers/files_demo \
92
95
  - **Full documentation:** https://streamwright.web.app/docs/
93
96
  - **Architecture Guide:** https://streamwright.web.app/docs/architecture/
94
97
  - **Connectors & Readers:** https://streamwright.web.app/docs/connectors/
98
+ - **MCP Server Guide:** https://streamwright.web.app/docs/ai/mcp/
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "streamwright"
7
- version = "0.1.6"
7
+ version = "0.1.8"
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"}
@@ -36,13 +36,15 @@ dependencies = [
36
36
  dlt = ["dlt>=1.0"]
37
37
 
38
38
  [project.urls]
39
- Homepage = "https://github.com/karthick-jaganathan/streamwright"
40
- Repository = "https://github.com/karthick-jaganathan/streamwright"
39
+ Homepage = "https://streamwright.web.app"
41
40
  Documentation = "https://streamwright.web.app/docs/"
41
+ Repository = "https://github.com/karthick-jaganathan/streamwright"
42
+ "Issue Tracker" = "https://github.com/karthick-jaganathan/streamwright/issues"
42
43
 
43
44
  [project.scripts]
44
45
  # `streamwright run`, `streamwright validate`, `streamwright connectors` - one CLI (see streamwright.core.cli)
45
46
  streamwright = "streamwright.core.cli:main"
47
+ sw = "streamwright.core.cli:main"
46
48
 
47
49
 
48
50
  [tool.setuptools]
@@ -16,7 +16,7 @@
16
16
  # **************************************************************************/
17
17
 
18
18
  """
19
- The `streamwright` command.
19
+ The `streamwright` command (shorthand: `sw`).
20
20
 
21
21
  streamwright run SOURCE [--config FILE] [--set NAME=VALUE] [--secrets FILE] [--state FILE] [--stream NAME] [--output ...]
22
22
  [--file-name TEMPLATE] [--allow-connector NAME] [--summary FILE] [logging options]
@@ -25,6 +25,7 @@ The `streamwright` command.
25
25
  streamwright connectors list | search WORDS | install KEY [KEY ...] [--yes] [--hub-url URL]
26
26
  (the catalog; install resolves every KEY, then runs one pip install)
27
27
  streamwright validate PATH... (streamwright-validate, plus the checks of the installed connectors and query builders)
28
+ streamwright mcp [--transport stdio|sse] (Model Context Protocol server for AI assistants)
28
29
 
29
30
  Logging options (streamwright run and streamwright validate): --log-level LEVEL, --log NAME=LEVEL, --log-format text|json,
30
31
  --log-config FILE, --log-max-chars N. Loggers: streamwright.source (progress, summaries, warnings), streamwright.network (INFO: a
@@ -240,12 +241,18 @@ def _parser():
240
241
  _add_log_options(run)
241
242
 
242
243
  conn = commands.add_parser("connectors",
243
- help="list, search or install connectors (bare: the installed connectors and their "
244
+ help="list, find or install connectors (bare: the installed connectors and their "
244
245
  "SDK loggers)")
245
- conn.add_argument("action", nargs="?", choices=["list", "search", "install"],
246
- help="list (catalog + installed), search TEXT, or install KEY [KEY ...]")
246
+ conn.add_argument("-ls", "--list", action="store_true", dest="flag_list",
247
+ help="list catalog and installed connectors")
248
+ conn.add_argument("-i", "--install", nargs="+", dest="flag_install", metavar="KEY",
249
+ help="install one or more connector keys")
250
+ conn.add_argument("-s", "-f", "--search", "--find", nargs="+", dest="flag_search", metavar="TEXT",
251
+ help="find/search connectors in the catalog by keyword")
252
+ conn.add_argument("action", nargs="?", metavar="{ls,i,find}",
253
+ help="ls (catalog + installed), -i KEY (install), or find TEXT (search catalog)")
247
254
  conn.add_argument("query", nargs="*", metavar="KEY|TEXT",
248
- help="connector keys (install: one or more) or words (search)")
255
+ help="connector keys (install: one or more) or search words")
249
256
  conn.add_argument("--yes", action="store_true", help="skip the confirmation prompt when installing")
250
257
  conn.add_argument("--hub-url", metavar="URL",
251
258
  help="the connector hub (default: $STREAMWRIGHT_HUB_URL, else the live StreamWright hub; when it is "
@@ -254,6 +261,9 @@ def _parser():
254
261
  validate = commands.add_parser("validate", help="check configuration files: streamwright-validate, plus the checks of "
255
262
  "the installed connectors and query builders", add_help=False)
256
263
  validate.add_argument("arguments", nargs=argparse.REMAINDER)
264
+
265
+ mcp_cmd = commands.add_parser("mcp", help="run the StreamWright Model Context Protocol (MCP) server", add_help=False)
266
+ mcp_cmd.add_argument("arguments", nargs=argparse.REMAINDER)
257
267
  return parser
258
268
 
259
269
 
@@ -558,19 +568,42 @@ def _connector_lines():
558
568
 
559
569
 
560
570
  def _connectors_command(args):
561
- """`streamwright connectors`: bare = installed list; list/search/install use the catalog (the hub)."""
562
- action = getattr(args, "action", None)
571
+ """`streamwright connectors`: bare = installed list; ls/i/find use the catalog (the hub)."""
572
+ if getattr(args, "flag_list", False):
573
+ action = "ls"
574
+ query = []
575
+ elif getattr(args, "flag_install", None):
576
+ action = "install"
577
+ query = args.flag_install
578
+ elif getattr(args, "flag_search", None):
579
+ action = "find"
580
+ query = args.flag_search
581
+ else:
582
+ action = getattr(args, "action", None)
583
+ query = getattr(args, "query", [])
584
+
563
585
  if action is None:
564
586
  lines = _connector_lines()
565
- print("\n".join(lines) if lines else "no connectors installed (e.g. streamwright connectors install postgres)")
587
+ print("\n".join(lines) if lines else "no connectors installed (e.g. streamwright connectors -i postgres)")
566
588
  return 0
567
- from streamwright.core import catalog
568
- if action == "list":
589
+
590
+ norm_action = action.lower()
591
+ if norm_action in ("ls", "list", "-ls", "--list"):
592
+ from streamwright.core import catalog
569
593
  lines = catalog.listing(args.hub_url)
570
594
  print("\n".join(lines) if lines else "the catalog is empty")
571
595
  return 0
572
- if action == "search":
573
- text = " ".join(args.query)
596
+
597
+ if norm_action in ("i", "install", "-i", "--install"):
598
+ from streamwright.core import catalog
599
+ if not query:
600
+ sys.stderr.write("streamwright: 'connectors -i' needs at least one connector KEY\n")
601
+ return 2
602
+ return catalog.install_many(query, assume_yes=args.yes, hub_url=args.hub_url)
603
+
604
+ if norm_action in ("find", "search", "s", "-s", "-f", "--find", "--search"):
605
+ from streamwright.core import catalog
606
+ text = " ".join(query)
574
607
  hits = catalog.search(text, args.hub_url)
575
608
  if not hits:
576
609
  print("no connectors match %r" % text)
@@ -578,12 +611,17 @@ def _connectors_command(args):
578
611
  for key, entry in sorted(hits.items()):
579
612
  print(" %-16s %-10s %s" % (key, entry.get("trust", "community"), entry.get("summary", "")))
580
613
  return 0
581
- if action == "install":
582
- if not args.query:
583
- sys.stderr.write("streamwright: 'connectors install' needs at least one connector KEY\n")
584
- return 2
585
- return catalog.install_many(args.query, assume_yes=args.yes, hub_url=args.hub_url)
586
- return 2
614
+
615
+ # If action was not a reserved verb, treat it as a direct search query (e.g. `sw connectors ads`)
616
+ from streamwright.core import catalog
617
+ text = " ".join([action] + query)
618
+ hits = catalog.search(text, args.hub_url)
619
+ if not hits:
620
+ print("no connectors match %r" % text)
621
+ return 0
622
+ for key, entry in sorted(hits.items()):
623
+ print(" %-16s %-10s %s" % (key, entry.get("trust", "community"), entry.get("summary", "")))
624
+ return 0
587
625
 
588
626
 
589
627
  def main(argv=None):
@@ -601,6 +639,13 @@ def main(argv=None):
601
639
  non_strict_codes=("connector-not-installed",))
602
640
  finally:
603
641
  setup.close()
642
+ if argv[:1] == ["mcp"]:
643
+ try:
644
+ from streamwright_mcp.cli import main as mcp_main
645
+ except ImportError:
646
+ sys.stderr.write("streamwright: 'streamwright-mcp' is not installed. Install it with: pip install streamwright-mcp\n")
647
+ return 1
648
+ return mcp_main(argv[1:]) or 0
604
649
  args = _parser().parse_args(argv)
605
650
  if args.command == "connectors":
606
651
  return _connectors_command(args)
@@ -16,12 +16,101 @@
16
16
  # **************************************************************************/
17
17
 
18
18
  """
19
- Specification of the StreamWright source configuration format (`kind: source`).
19
+ Specification and single source of truth for the StreamWright source and stream declarative format (`kind: source`).
20
20
 
21
- Single source of truth for streamwright-validate's source checks (source_validator) and the published
22
- JSON Schemas (`streamwright-validate --export-schema DIR` writes DIR/source.schema.json and DIR/stream.schema.json for the
23
- stream files of source folders).
24
- Design: docs/design/source-format.md.
21
+ Defines structural schemas, valid keys, data types, authentication schemes, transformation contracts,
22
+ and export definitions for streamwright-validate, streamwright-mcp, and AI runtime assistants.
23
+
24
+ ### 1. `source.yaml` Schema Structure
25
+ ```yaml
26
+ kind: source # Required: must be 'source'
27
+ name: my_pipeline # Required: snake_case identifier
28
+ description: "Pipeline purpose" # Optional: text description
29
+
30
+ spec: # Declares runtime parameters and credentials
31
+ config: # Visible parameters passed via CLI (--set) or environment
32
+ tenant_id: {type: string, required: true}
33
+ batch_limit: {type: integer, default: 500}
34
+ start_date: {type: date, required: false}
35
+ secrets: # Redacted credentials from STREAMWRIGHT_SECRET_<NAME> or --secrets
36
+ api_key: {type: string, required: true}
37
+
38
+ auth: # Authentication provider or protocol
39
+ provider: <connector_name> # e.g. restapi, postgres, s3, google_ads
40
+ # Standard HTTP Auth Types:
41
+ # - bearer: {token: "{{ secrets.token }}"}
42
+ # - api_key: {name: "X-Api-Key", value: "{{ secrets.key }}", in: "header" | "query"}
43
+ # - basic: {username: "user", password: "{{ secrets.password }}"}
44
+ # - oauth2_refresh_token: {token_url, client_id, client_secret, refresh_token}
45
+
46
+ http: # Optional HTTP defaults shared by all streams
47
+ base_url: "https://api.example.com"
48
+ headers: {Accept: "application/json"}
49
+ params_encoding: plain # "plain" | "dotted"
50
+ paginator: # "offset" | "cursor" | "page"
51
+ type: cursor
52
+ token_path: next_cursor
53
+ param: cursor
54
+ records: {path: data} # JMESPath/key to extract record array from envelope
55
+ rate_limit: {requests: 10, per: 1s}
56
+ retry: {codes: [429, 500, 502, 503, 504], max_attempts: 5, backoff: exponential}
57
+
58
+ # Streams can be declared inline under `streams:` or as individual YAML files in `streams/<name>.yaml`.
59
+ ```
60
+
61
+ ### 2. `streams/<name>.yaml` Schema Structure
62
+ ```yaml
63
+ description: "Stream documentation"
64
+
65
+ # Optional partitioning (parallel or sequential chunk execution)
66
+ # partitions:
67
+ # - {name: account_id, values: "{{ config.account_ids }}"}
68
+ # - {name: child_id, from_stream: parent_stream, field: id}
69
+
70
+ # Optional incremental state sync
71
+ # incremental:
72
+ # cursor_field: updated_at
73
+ # start: "2026-01-01T00:00:00Z"
74
+ # window: 1d
75
+ # lookback: 1h
76
+
77
+ requests: # 1 or more extraction requests
78
+ # HTTP extraction:
79
+ - name: raw_items
80
+ http:
81
+ path: /v1/items
82
+ method: GET
83
+ params: {status: active}
84
+
85
+ # Or Connector SDK extraction:
86
+ # - name: raw_records
87
+ # sdk: postgres
88
+ # service: database
89
+ # method: query
90
+ # arguments:
91
+ # query: "SELECT * FROM orders WHERE created_at >= $since"
92
+ # params: {since: "{{ window.start }}"}
93
+
94
+ transform: # Relational DuckDB SQL transformations
95
+ mode: page # "page" (streamed per page) or "run" (accumulated whole run)
96
+ steps:
97
+ - name: cleaned_items
98
+ select: |
99
+ SELECT
100
+ record->>'id' AS item_id,
101
+ record->>'name' AS item_name,
102
+ (record->>'price')::DOUBLE AS price
103
+ FROM raw_items
104
+
105
+ export: # Final output datasets and identity contracts
106
+ items:
107
+ step: cleaned_items
108
+ primary_key: [item_id]
109
+ ```
110
+
111
+ ### 3. Programmatic Schemas
112
+ Use `json_schema()` and `stream_json_schema()` to get JSON Schema Draft 7 specifications
113
+ for validating source and stream configurations programmatically.
25
114
  """
26
115
 
27
116
  __all__ = ["VERSION", "SUPPORTED_VERSIONS", "KIND", "json_schema", "stream_json_schema", "split_outside_quotes"]
@@ -1,12 +1,13 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: streamwright
3
- Version: 0.1.6
3
+ Version: 0.1.8
4
4
  Summary: Declarative data connectors — pull from APIs, files and databases with YAML, shape with SQL, write anywhere.
5
5
  Author-email: Karthick Jaganathan <kjaganathan.sde@gmail.com>
6
6
  License: Apache-2.0
7
- Project-URL: Homepage, https://github.com/karthick-jaganathan/streamwright
8
- Project-URL: Repository, https://github.com/karthick-jaganathan/streamwright
7
+ Project-URL: Homepage, https://streamwright.web.app
9
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
10
11
  Keywords: data,pipeline,etl,connector,singer,yaml,duckdb,rest-api
11
12
  Classifier: Development Status :: 3 - Alpha
12
13
  Classifier: Intended Audience :: Developers
@@ -44,9 +45,12 @@ Each stream follows a three-stage pipeline:
44
45
 
45
46
  ## CLI Commands
46
47
 
47
- - **`streamwright run`** — Execute a source and stream records to the configured destination.
48
- - **`streamwright validate`** — Validate source definitions, authentication specifications, and schemas without executing network requests.
49
- - **`streamwright connectors`** — Browse, inspect, and install connectors from the StreamWright Hub.
48
+ All commands can be invoked interchangeably using `streamwright` or the shorthand `sw` alias (e.g. `sw run`, `sw validate`, `sw connectors`, `sw mcp`).
49
+
50
+ - **`streamwright run`** (or **`sw run`**) — Execute a source and stream records to the configured destination.
51
+ - **`streamwright validate`** (or **`sw validate`**) — Validate source definitions, authentication specifications, and schemas without executing network requests.
52
+ - **`streamwright connectors`** (or **`sw connectors`**) — Browse, inspect, and install connectors from the StreamWright Hub.
53
+ - **`streamwright mcp`** (or **`sw mcp`**) — Launch the Model Context Protocol (MCP) server for AI coding assistants.
50
54
 
51
55
  ## Source Structure
52
56
 
@@ -120,3 +124,4 @@ streamwright run streamwright/examples/sources/readers/files_demo \
120
124
  - **Full documentation:** https://streamwright.web.app/docs/
121
125
  - **Architecture Guide:** https://streamwright.web.app/docs/architecture/
122
126
  - **Connectors & Readers:** https://streamwright.web.app/docs/connectors/
127
+ - **MCP Server Guide:** https://streamwright.web.app/docs/ai/mcp/
@@ -40,6 +40,7 @@ src/streamwright/core/validation/engine.py
40
40
  src/streamwright/core/validation/schema.py
41
41
  src/streamwright/core/validation/source.py
42
42
  tests/test_catalog.py
43
+ tests/test_cli_subcommands.py
43
44
  tests/test_connectors.py
44
45
  tests/test_dlt_output.py
45
46
  tests/test_exact_decimals.py
@@ -1,2 +1,3 @@
1
1
  [console_scripts]
2
2
  streamwright = streamwright.core.cli:main
3
+ sw = streamwright.core.cli:main
@@ -0,0 +1,72 @@
1
+ import subprocess
2
+ import sys
3
+ from unittest.mock import patch
4
+
5
+ from streamwright.core import cli
6
+
7
+
8
+ def test_cli_help():
9
+ result = subprocess.run([sys.executable, "-m", "streamwright.core.cli", "--help"],
10
+ stdout=subprocess.PIPE, stderr=subprocess.PIPE,
11
+ universal_newlines=True)
12
+ assert result.returncode == 0
13
+ assert "mcp" in result.stdout
14
+
15
+
16
+ def test_cli_mcp_delegation():
17
+ from unittest.mock import MagicMock
18
+ mock_mcp = MagicMock(return_value=0)
19
+ mock_mod = MagicMock(main=mock_mcp)
20
+ with patch.dict(sys.modules, {"streamwright_mcp": MagicMock(), "streamwright_mcp.cli": mock_mod}):
21
+ code = cli.main(["mcp", "--help"])
22
+ assert code == 0
23
+ mock_mcp.assert_called_once_with(["--help"])
24
+
25
+
26
+ def test_cli_mcp_not_installed(capsys):
27
+ with patch.dict(sys.modules, {"streamwright_mcp.cli": None}):
28
+ with patch("builtins.__import__", side_effect=ImportError("No module named 'streamwright_mcp'")):
29
+ code = cli.main(["mcp"])
30
+ assert code == 1
31
+ captured = capsys.readouterr()
32
+ assert "'streamwright-mcp' is not installed" in captured.err
33
+
34
+
35
+ def test_cli_connectors_help():
36
+ result = subprocess.run([sys.executable, "-m", "streamwright.core.cli", "connectors", "--help"],
37
+ stdout=subprocess.PIPE, stderr=subprocess.PIPE,
38
+ universal_newlines=True)
39
+ assert result.returncode == 0
40
+ assert "-ls" in result.stdout
41
+ assert "-i" in result.stdout
42
+ assert "-s" in result.stdout or "find" in result.stdout
43
+
44
+
45
+ def test_cli_connectors_variants(monkeypatch, capsys):
46
+ from streamwright.core import catalog
47
+ fake_catalog = {
48
+ "postgres": {"title": "Postgres", "summary": "Postgres DB", "trust": "official"}
49
+ }
50
+ monkeypatch.setattr(catalog, "connectors", lambda hub_url=None: fake_catalog)
51
+ monkeypatch.setattr(catalog, "listing", lambda hub_url=None: ["catalog-listing-item"])
52
+
53
+ # Test ls subcommand
54
+ code = cli.main(["connectors", "ls"])
55
+ assert code == 0
56
+ assert "catalog-listing-item" in capsys.readouterr().out
57
+
58
+ # Test -ls flag
59
+ code = cli.main(["connectors", "-ls"])
60
+ assert code == 0
61
+ assert "catalog-listing-item" in capsys.readouterr().out
62
+
63
+ # Test find subcommand
64
+ code = cli.main(["connectors", "find", "postgres"])
65
+ assert code == 0
66
+ assert "postgres" in capsys.readouterr().out
67
+
68
+ # Test -s flag
69
+ code = cli.main(["connectors", "-s", "postgres"])
70
+ assert code == 0
71
+ assert "postgres" in capsys.readouterr().out
72
+
@@ -376,7 +376,15 @@ def test_templates_are_not_allowed_in_names_and_records():
376
376
  # * ----
377
377
 
378
378
  def test_auth_checks():
379
- assert codes(check(lambda d: d["auth"].update(provider="google_ads"))) == [(ERROR, "bad-value")]
379
+ from streamwright.core.runtime.components import Connector, register, unregister
380
+ class MockSdkValConnector(Connector):
381
+ name = "mock_sdk_val"
382
+ transport = "sdk"
383
+ register(MockSdkValConnector())
384
+ try:
385
+ assert codes(check(lambda d: d["auth"].update(provider="mock_sdk_val"))) == [(ERROR, "bad-value")]
386
+ finally:
387
+ unregister("mock_sdk_val")
380
388
  assert codes(check(lambda d: d["auth"].update(type="bearr"))) == [(ERROR, "bad-value")]
381
389
  issues = check(lambda d: d.update(auth={"type": "oauth2_refresh_token", "token_url": "https://x/token",
382
390
  "client_id": "id", "client_secret": "s3cret",
File without changes
File without changes
File without changes