py-flink-sql-gateway 0.1.0.dev0__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.
@@ -0,0 +1,64 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+
8
+ jobs:
9
+ lint:
10
+ runs-on: ubuntu-latest
11
+ steps:
12
+ - uses: actions/checkout@v4
13
+
14
+ - uses: actions/setup-python@v5
15
+ with:
16
+ python-version: "3.13"
17
+
18
+ - name: Install uv
19
+ uses: astral-sh/setup-uv@v5
20
+
21
+ - name: Install dependencies
22
+ run: uv sync --group dev
23
+
24
+ - name: Run pre-commit
25
+ uses: pre-commit/action@v3.0.1
26
+
27
+ test:
28
+ runs-on: ubuntu-latest
29
+ strategy:
30
+ matrix:
31
+ python-version: ["3.11", "3.12", "3.13"]
32
+ steps:
33
+ - uses: actions/checkout@v4
34
+
35
+ - uses: actions/setup-python@v5
36
+ with:
37
+ python-version: ${{ matrix.python-version }}
38
+
39
+ - name: Install uv
40
+ uses: astral-sh/setup-uv@v5
41
+
42
+ - name: Install dependencies
43
+ run: uv sync --group dev
44
+
45
+ - name: Run unit tests
46
+ run: uv run pytest tests/test_client.py tests/test_dbapi.py -v
47
+
48
+ integration:
49
+ runs-on: ubuntu-latest
50
+ steps:
51
+ - uses: actions/checkout@v4
52
+
53
+ - uses: actions/setup-python@v5
54
+ with:
55
+ python-version: "3.13"
56
+
57
+ - name: Install uv
58
+ uses: astral-sh/setup-uv@v5
59
+
60
+ - name: Install dependencies
61
+ run: uv sync --group dev
62
+
63
+ - name: Run integration tests
64
+ run: uv run pytest tests/test_integration.py -v -s -m integration
@@ -0,0 +1,29 @@
1
+ name: Publish to PyPI
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - "v*"
7
+
8
+ jobs:
9
+ publish:
10
+ runs-on: ubuntu-latest
11
+ permissions:
12
+ id-token: write # Required for trusted publishing
13
+ steps:
14
+ - uses: actions/checkout@v4
15
+ with:
16
+ fetch-depth: 0 # Full history needed for hatch-vcs
17
+
18
+ - uses: actions/setup-python@v5
19
+ with:
20
+ python-version: "3.13"
21
+
22
+ - name: Install build tools
23
+ run: pip install build
24
+
25
+ - name: Build package
26
+ run: python -m build
27
+
28
+ - name: Publish to PyPI
29
+ uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,14 @@
1
+ # Python-generated files
2
+ __pycache__/
3
+ *.py[oc]
4
+ build/
5
+ dist/
6
+ wheels/
7
+ *.egg-info
8
+
9
+ # Virtual environments
10
+ .venv
11
+ .idea
12
+
13
+ # Auto-generated version file
14
+ src/flink_gateway/_version.py
@@ -0,0 +1,30 @@
1
+ default_language_version:
2
+ python: python3.13
3
+ fail_fast: false
4
+ repos:
5
+ - repo: https://github.com/pre-commit/pre-commit-hooks
6
+ rev: v4.4.0
7
+ hooks:
8
+ - id: trailing-whitespace
9
+ - id: end-of-file-fixer
10
+ - id: debug-statements
11
+ - id: check-yaml
12
+ args: [--allow-multiple-documents]
13
+ - repo: https://github.com/pre-commit/mirrors-isort
14
+ rev: v5.10.1
15
+ hooks:
16
+ - id: isort
17
+ - repo: https://github.com/ambv/black
18
+ rev: 23.3.0
19
+ hooks:
20
+ - id: black
21
+ - repo: https://github.com/charliermarsh/ruff-pre-commit
22
+ rev: v0.0.272
23
+ hooks:
24
+ - id: ruff
25
+ args: [--no-cache]
26
+ - repo: https://github.com/pre-commit/mirrors-mypy
27
+ rev: v1.3.0
28
+ hooks:
29
+ - id: mypy
30
+ # additional_dependencies: [types-all]
@@ -0,0 +1 @@
1
+ 3.13
@@ -0,0 +1,128 @@
1
+ Metadata-Version: 2.4
2
+ Name: py-flink-sql-gateway
3
+ Version: 0.1.0.dev0
4
+ Summary: A Python client for the Apache Flink SQL Gateway REST API
5
+ Author-email: Ilya Soin <ilya.soin@exness.com>
6
+ Requires-Python: >=3.11
7
+ Requires-Dist: httpx>=0.28.1
8
+ Description-Content-Type: text/markdown
9
+
10
+ # py-flink-sql-gateway
11
+
12
+ A lightweight Python driver for the **Apache Flink SQL Gateway**, implementing [PEP 249 (DB-API 2.0)](https://peps.python.org/pep-0249/).
13
+
14
+ ## Installation
15
+
16
+ ```bash
17
+ pip install py-flink-sql-gateway
18
+ ```
19
+
20
+ ## Quick start
21
+
22
+ ```python
23
+ from flink_gateway import connect
24
+
25
+ with connect("http://localhost:8083") as conn:
26
+ # Create a streaming source
27
+ with conn.cursor() as cur:
28
+ cur.execute("""
29
+ CREATE TABLE orders (
30
+ id INT NOT NULL,
31
+ item STRING NOT NULL,
32
+ created_at TIMESTAMP(6) NOT NULL,
33
+ customer ROW<
34
+ first_name STRING NOT NULL,
35
+ last_name STRING NOT NULL,
36
+ age INT NOT NULL
37
+ > NOT NULL,
38
+ notes STRING
39
+ ) WITH (
40
+ 'connector' = 'datagen',
41
+ 'rows-per-second' = '5',
42
+ 'fields.id.kind' = 'sequence',
43
+ 'fields.id.start' = '1',
44
+ 'fields.id.end' = '100',
45
+ 'fields.item.length' = '12',
46
+ 'fields.customer.first_name.length' = '8',
47
+ 'fields.customer.last_name.length' = '10',
48
+ 'fields.customer.age.min' = '21',
49
+ 'fields.customer.age.max' = '65',
50
+ 'fields.notes.length' = '12'
51
+ )
52
+ """)
53
+
54
+ # Query and iterate
55
+ with conn.cursor() as cur:
56
+ cur.execute("""
57
+ SELECT id, item, created_at, customer, notes AS note
58
+ FROM orders
59
+ """)
60
+ for i, row in enumerate(cur):
61
+ id_, item, created_at, customer, note = row
62
+ print(
63
+ f"{id_}\t{item}\t{created_at.isoformat()}\t"
64
+ f"{customer['first_name']} {customer['last_name']} ({customer['age']})\t"
65
+ f"{note or ''}"
66
+ )
67
+ if i >= 4:
68
+ break
69
+ ```
70
+
71
+ > **Tip:** `ROW` and `MAP` types arrive as Python `dict`, `ARRAY` arrives as `list`. Binary data is passed through as-is.
72
+
73
+ ### Low-level REST access
74
+
75
+ If you need features beyond DB-API, use the exported client directly:
76
+
77
+ ```python
78
+ from flink_gateway import FlinkSqlGatewayClient
79
+
80
+ with FlinkSqlGatewayClient("http://localhost:8083") as client:
81
+ status = client.get_operation_status("session-handle", "operation-handle")
82
+ print("current status:", status)
83
+ ```
84
+
85
+ ## Type mapping
86
+
87
+ Python uses `None` for SQL NULLs natively — no wrapper types needed.
88
+
89
+ | Flink Type | Python Type |
90
+ |---------------------------|--------------------|
91
+ | TINYINT / SMALLINT / INT | `int` |
92
+ | BIGINT / INTERVAL | `int` |
93
+ | FLOAT / DOUBLE | `float` |
94
+ | BOOLEAN | `bool` |
95
+ | CHAR / VARCHAR / STRING | `str` |
96
+ | DECIMAL | `decimal.Decimal` |
97
+ | DATE | `datetime.date` |
98
+ | TIME | `datetime.time` |
99
+ | TIMESTAMP / TIMESTAMP_LTZ | `datetime.datetime`|
100
+ | BINARY / VARBINARY | raw (passthrough) |
101
+ | ROW | `dict` |
102
+ | MAP | `dict` |
103
+ | ARRAY | `list` |
104
+
105
+ ---
106
+
107
+ ## Development & tests
108
+
109
+ Requires Python 3.13+ and [uv](https://docs.astral.sh/uv/).
110
+
111
+ ```bash
112
+ # Install dependencies
113
+ uv sync
114
+
115
+ # Run unit tests (no Docker needed)
116
+ uv run pytest tests/test_client.py tests/test_dbapi.py -v
117
+
118
+ # Run all tests including integration (requires Docker)
119
+ uv run pytest tests/ -v
120
+ ```
121
+
122
+ Integration tests spin up a Flink cluster (JobManager + TaskManager + SQL Gateway) via [testcontainers-python](https://testcontainers-python.readthedocs.io/).
123
+
124
+ ---
125
+
126
+ ## License
127
+
128
+ MIT (see LICENSE)
@@ -0,0 +1,119 @@
1
+ # py-flink-sql-gateway
2
+
3
+ A lightweight Python driver for the **Apache Flink SQL Gateway**, implementing [PEP 249 (DB-API 2.0)](https://peps.python.org/pep-0249/).
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ pip install py-flink-sql-gateway
9
+ ```
10
+
11
+ ## Quick start
12
+
13
+ ```python
14
+ from flink_gateway import connect
15
+
16
+ with connect("http://localhost:8083") as conn:
17
+ # Create a streaming source
18
+ with conn.cursor() as cur:
19
+ cur.execute("""
20
+ CREATE TABLE orders (
21
+ id INT NOT NULL,
22
+ item STRING NOT NULL,
23
+ created_at TIMESTAMP(6) NOT NULL,
24
+ customer ROW<
25
+ first_name STRING NOT NULL,
26
+ last_name STRING NOT NULL,
27
+ age INT NOT NULL
28
+ > NOT NULL,
29
+ notes STRING
30
+ ) WITH (
31
+ 'connector' = 'datagen',
32
+ 'rows-per-second' = '5',
33
+ 'fields.id.kind' = 'sequence',
34
+ 'fields.id.start' = '1',
35
+ 'fields.id.end' = '100',
36
+ 'fields.item.length' = '12',
37
+ 'fields.customer.first_name.length' = '8',
38
+ 'fields.customer.last_name.length' = '10',
39
+ 'fields.customer.age.min' = '21',
40
+ 'fields.customer.age.max' = '65',
41
+ 'fields.notes.length' = '12'
42
+ )
43
+ """)
44
+
45
+ # Query and iterate
46
+ with conn.cursor() as cur:
47
+ cur.execute("""
48
+ SELECT id, item, created_at, customer, notes AS note
49
+ FROM orders
50
+ """)
51
+ for i, row in enumerate(cur):
52
+ id_, item, created_at, customer, note = row
53
+ print(
54
+ f"{id_}\t{item}\t{created_at.isoformat()}\t"
55
+ f"{customer['first_name']} {customer['last_name']} ({customer['age']})\t"
56
+ f"{note or ''}"
57
+ )
58
+ if i >= 4:
59
+ break
60
+ ```
61
+
62
+ > **Tip:** `ROW` and `MAP` types arrive as Python `dict`, `ARRAY` arrives as `list`. Binary data is passed through as-is.
63
+
64
+ ### Low-level REST access
65
+
66
+ If you need features beyond DB-API, use the exported client directly:
67
+
68
+ ```python
69
+ from flink_gateway import FlinkSqlGatewayClient
70
+
71
+ with FlinkSqlGatewayClient("http://localhost:8083") as client:
72
+ status = client.get_operation_status("session-handle", "operation-handle")
73
+ print("current status:", status)
74
+ ```
75
+
76
+ ## Type mapping
77
+
78
+ Python uses `None` for SQL NULLs natively — no wrapper types needed.
79
+
80
+ | Flink Type | Python Type |
81
+ |---------------------------|--------------------|
82
+ | TINYINT / SMALLINT / INT | `int` |
83
+ | BIGINT / INTERVAL | `int` |
84
+ | FLOAT / DOUBLE | `float` |
85
+ | BOOLEAN | `bool` |
86
+ | CHAR / VARCHAR / STRING | `str` |
87
+ | DECIMAL | `decimal.Decimal` |
88
+ | DATE | `datetime.date` |
89
+ | TIME | `datetime.time` |
90
+ | TIMESTAMP / TIMESTAMP_LTZ | `datetime.datetime`|
91
+ | BINARY / VARBINARY | raw (passthrough) |
92
+ | ROW | `dict` |
93
+ | MAP | `dict` |
94
+ | ARRAY | `list` |
95
+
96
+ ---
97
+
98
+ ## Development & tests
99
+
100
+ Requires Python 3.13+ and [uv](https://docs.astral.sh/uv/).
101
+
102
+ ```bash
103
+ # Install dependencies
104
+ uv sync
105
+
106
+ # Run unit tests (no Docker needed)
107
+ uv run pytest tests/test_client.py tests/test_dbapi.py -v
108
+
109
+ # Run all tests including integration (requires Docker)
110
+ uv run pytest tests/ -v
111
+ ```
112
+
113
+ Integration tests spin up a Flink cluster (JobManager + TaskManager + SQL Gateway) via [testcontainers-python](https://testcontainers-python.readthedocs.io/).
114
+
115
+ ---
116
+
117
+ ## License
118
+
119
+ MIT (see LICENSE)
@@ -0,0 +1,47 @@
1
+ [project]
2
+ name = "py-flink-sql-gateway"
3
+ dynamic = ["version"]
4
+ description = "A Python client for the Apache Flink SQL Gateway REST API"
5
+ readme = "README.md"
6
+ authors = [
7
+ { name = "Ilya Soin", email = "ilya.soin@exness.com" }
8
+ ]
9
+ requires-python = ">=3.11"
10
+ dependencies = [
11
+ "httpx>=0.28.1",
12
+ ]
13
+
14
+ [dependency-groups]
15
+ dev = [
16
+ "pytest>=8.0",
17
+ "testcontainers>=4.14.1",
18
+ ]
19
+
20
+ [build-system]
21
+ requires = ["hatchling", "hatch-vcs"]
22
+ build-backend = "hatchling.build"
23
+
24
+ [tool.hatch.version]
25
+ source = "vcs"
26
+ raw-options = { version_scheme = "guess-next-dev" }
27
+
28
+ [tool.hatch.build.hooks.vcs]
29
+ version-file = "src/flink_gateway/_version.py"
30
+
31
+ [tool.hatch.build.targets.wheel]
32
+ packages = ["src/flink_gateway"]
33
+
34
+ [tool.pytest.ini_options]
35
+ markers = [
36
+ "integration: end-to-end tests requiring Docker (Flink cluster)",
37
+ ]
38
+
39
+ [tool.isort]
40
+ profile = "black"
41
+ line_length = 88
42
+
43
+ [tool.ruff]
44
+ line-length = 88
45
+
46
+ [tool.ruff.per-file-ignores]
47
+ "__init__.py" = ["E402"]
@@ -0,0 +1,104 @@
1
+ """Flink SQL Gateway — Python client library.
2
+
3
+ Implements PEP 249 (DB-API 2.0) on top of the Flink SQL Gateway REST API.
4
+ """
5
+
6
+ from flink_gateway.client import FlinkSqlGatewayClient
7
+ from flink_gateway.connection import Connection, connect
8
+ from flink_gateway.cursor import Cursor
9
+ from flink_gateway.exceptions import (
10
+ DatabaseError,
11
+ Error,
12
+ FlinkSqlGatewayError,
13
+ InterfaceError,
14
+ NotSupportedError,
15
+ OperationalError,
16
+ ProgrammingError,
17
+ )
18
+ from flink_gateway.models import (
19
+ ColumnInfo,
20
+ CompleteStatementRequest,
21
+ ConfigureSessionRequest,
22
+ ExecuteStatementRequest,
23
+ FetchResultsResponse,
24
+ InfoResponse,
25
+ LogicalType,
26
+ OpenSessionRequest,
27
+ RefreshMaterializedTableRequest,
28
+ ResultKind,
29
+ ResultSet,
30
+ ResultType,
31
+ RowData,
32
+ )
33
+ from flink_gateway.types import (
34
+ BINARY,
35
+ DATETIME,
36
+ NUMBER,
37
+ ROWID,
38
+ STRING,
39
+ Binary,
40
+ Date,
41
+ DateFromTicks,
42
+ DBAPITypeObject,
43
+ FlinkType,
44
+ Time,
45
+ TimeFromTicks,
46
+ Timestamp,
47
+ TimestampFromTicks,
48
+ )
49
+
50
+ # PEP 249 module-level globals
51
+ apilevel = "2.0"
52
+ threadsafety = 1 # Threads may share the module but not connections.
53
+ paramstyle = "qmark"
54
+
55
+ __all__ = [
56
+ # PEP 249
57
+ "apilevel",
58
+ "threadsafety",
59
+ "paramstyle",
60
+ "connect",
61
+ "Connection",
62
+ "Cursor",
63
+ # Exceptions
64
+ "Error",
65
+ "InterfaceError",
66
+ "DatabaseError",
67
+ "OperationalError",
68
+ "FlinkSqlGatewayError",
69
+ "ProgrammingError",
70
+ "NotSupportedError",
71
+ # Type objects
72
+ "STRING",
73
+ "BINARY",
74
+ "NUMBER",
75
+ "DATETIME",
76
+ "ROWID",
77
+ "DBAPITypeObject",
78
+ "FlinkType",
79
+ # PEP 249 constructors
80
+ "Date",
81
+ "Time",
82
+ "Timestamp",
83
+ "DateFromTicks",
84
+ "TimeFromTicks",
85
+ "TimestampFromTicks",
86
+ "Binary",
87
+ # Low-level client
88
+ "FlinkSqlGatewayClient",
89
+ "FlinkSqlGatewayError",
90
+ # Models
91
+ "ColumnInfo",
92
+ "CompleteStatementRequest",
93
+ "ConfigureSessionRequest",
94
+ "ExecuteStatementRequest",
95
+ "FetchResultsResponse",
96
+ "InfoResponse",
97
+ "LogicalType",
98
+ "OpenSessionRequest",
99
+ "RefreshMaterializedTableRequest",
100
+ "ResultKind",
101
+ "ResultSet",
102
+ "ResultType",
103
+ "RowData",
104
+ ]
@@ -0,0 +1,34 @@
1
+ # file generated by setuptools-scm
2
+ # don't change, don't track in version control
3
+
4
+ __all__ = [
5
+ "__version__",
6
+ "__version_tuple__",
7
+ "version",
8
+ "version_tuple",
9
+ "__commit_id__",
10
+ "commit_id",
11
+ ]
12
+
13
+ TYPE_CHECKING = False
14
+ if TYPE_CHECKING:
15
+ from typing import Tuple
16
+ from typing import Union
17
+
18
+ VERSION_TUPLE = Tuple[Union[int, str], ...]
19
+ COMMIT_ID = Union[str, None]
20
+ else:
21
+ VERSION_TUPLE = object
22
+ COMMIT_ID = object
23
+
24
+ version: str
25
+ __version__: str
26
+ __version_tuple__: VERSION_TUPLE
27
+ version_tuple: VERSION_TUPLE
28
+ commit_id: COMMIT_ID
29
+ __commit_id__: COMMIT_ID
30
+
31
+ __version__ = version = '0.1.0.dev0'
32
+ __version_tuple__ = version_tuple = (0, 1, 0, 'dev0')
33
+
34
+ __commit_id__ = commit_id = None