dbx-tools-postgres 0.6.185__tar.gz → 0.6.188__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.
- {dbx_tools_postgres-0.6.185 → dbx_tools_postgres-0.6.188}/PKG-INFO +7 -6
- {dbx_tools_postgres-0.6.185 → dbx_tools_postgres-0.6.188}/README.md +3 -3
- {dbx_tools_postgres-0.6.185 → dbx_tools_postgres-0.6.188}/pyproject.toml +4 -3
- {dbx_tools_postgres-0.6.185 → dbx_tools_postgres-0.6.188}/pyproject.toml.orig +3 -3
- dbx_tools_postgres-0.6.188/src/dbx_tools/postgres/address.py +31 -0
- {dbx_tools_postgres-0.6.185 → dbx_tools_postgres-0.6.188}/src/dbx_tools/postgres/engine.py +9 -2
- dbx_tools_postgres-0.6.185/src/dbx_tools/postgres/address.py +0 -114
- {dbx_tools_postgres-0.6.185 → dbx_tools_postgres-0.6.188}/src/dbx_tools/postgres/__init__.py +0 -0
- {dbx_tools_postgres-0.6.185 → dbx_tools_postgres-0.6.188}/src/dbx_tools/postgres/advisory_lock.py +0 -0
- {dbx_tools_postgres-0.6.185 → dbx_tools_postgres-0.6.188}/src/dbx_tools/postgres/topic_bus.py +0 -0
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: dbx-tools-postgres
|
|
3
|
-
Version: 0.6.
|
|
3
|
+
Version: 0.6.188
|
|
4
4
|
Summary: WorkspaceClient-backed Lakebase Postgres resolution, SQLAlchemy engines, advisory locks, and LISTEN/NOTIFY topic bus
|
|
5
5
|
Requires-Dist: asyncpg>=0.30
|
|
6
6
|
Requires-Dist: databricks-sdk>=0.63.0
|
|
7
7
|
Requires-Dist: greenlet>=3.2
|
|
8
8
|
Requires-Dist: psycopg[binary]>=3.2.9
|
|
9
9
|
Requires-Dist: sqlalchemy>=2.0.41
|
|
10
|
-
Requires-Dist: dbx-tools-core==0.6.
|
|
11
|
-
Requires-
|
|
10
|
+
Requires-Dist: dbx-tools-core==0.6.188
|
|
11
|
+
Requires-Dist: dbx-tools-core-rs==0.6.188
|
|
12
|
+
Requires-Python: >=3.11, <4
|
|
12
13
|
Project-URL: Source, https://github.com/reggie-db/dbx-tools/tree/main/packages/py/postgres
|
|
13
14
|
Description-Content-Type: text/markdown
|
|
14
15
|
|
|
@@ -16,8 +17,8 @@ Description-Content-Type: text/markdown
|
|
|
16
17
|
|
|
17
18
|
Python Lakebase/Postgres connection setup, advisory locks, and topic fan-out for
|
|
18
19
|
services that already hold a Databricks `WorkspaceClient`. This package is
|
|
19
|
-
the Python counterpart to `@dbx-tools/postgres
|
|
20
|
-
|
|
20
|
+
the Python counterpart to `@dbx-tools/postgres`. Lakebase address parsing comes
|
|
21
|
+
directly from the generated `dbx-tools-core-rs` Rust bindings.
|
|
21
22
|
|
|
22
23
|
Install from PyPI:
|
|
23
24
|
|
|
@@ -34,7 +35,7 @@ pip install "dbx-tools-postgres @ git+https://github.com/reggie-db/dbx-tools.git
|
|
|
34
35
|
Key features:
|
|
35
36
|
|
|
36
37
|
- accepts the same Postgres URI, Lakebase resource path, hostname, and project-id
|
|
37
|
-
address shapes as `@dbx-tools/appkit
|
|
38
|
+
address shapes as `@dbx-tools/appkit` through the native Rust parser;
|
|
38
39
|
- resolves missing autoscaling endpoint fields through
|
|
39
40
|
`WorkspaceClient.api_client`;
|
|
40
41
|
- resolves provisioned Lakebase instance DNS through
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
Python Lakebase/Postgres connection setup, advisory locks, and topic fan-out for
|
|
4
4
|
services that already hold a Databricks `WorkspaceClient`. This package is
|
|
5
|
-
the Python counterpart to `@dbx-tools/postgres
|
|
6
|
-
|
|
5
|
+
the Python counterpart to `@dbx-tools/postgres`. Lakebase address parsing comes
|
|
6
|
+
directly from the generated `dbx-tools-core-rs` Rust bindings.
|
|
7
7
|
|
|
8
8
|
Install from PyPI:
|
|
9
9
|
|
|
@@ -20,7 +20,7 @@ pip install "dbx-tools-postgres @ git+https://github.com/reggie-db/dbx-tools.git
|
|
|
20
20
|
Key features:
|
|
21
21
|
|
|
22
22
|
- accepts the same Postgres URI, Lakebase resource path, hostname, and project-id
|
|
23
|
-
address shapes as `@dbx-tools/appkit
|
|
23
|
+
address shapes as `@dbx-tools/appkit` through the native Rust parser;
|
|
24
24
|
- resolves missing autoscaling endpoint fields through
|
|
25
25
|
`WorkspaceClient.api_client`;
|
|
26
26
|
- resolves provisioned Lakebase instance DNS through
|
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "dbx-tools-postgres"
|
|
3
|
-
version = "0.6.
|
|
3
|
+
version = "0.6.188"
|
|
4
4
|
description = "WorkspaceClient-backed Lakebase Postgres resolution, SQLAlchemy engines, advisory locks, and LISTEN/NOTIFY topic bus"
|
|
5
5
|
readme = "README.md"
|
|
6
|
-
requires-python = ">=3.11,<
|
|
6
|
+
requires-python = ">=3.11,<4"
|
|
7
7
|
dependencies = [
|
|
8
8
|
"asyncpg>=0.30",
|
|
9
9
|
"databricks-sdk>=0.63.0",
|
|
10
10
|
"greenlet>=3.2",
|
|
11
11
|
"psycopg[binary]>=3.2.9",
|
|
12
12
|
"sqlalchemy>=2.0.41",
|
|
13
|
-
"dbx-tools-core==0.6.
|
|
13
|
+
"dbx-tools-core==0.6.188",
|
|
14
|
+
"dbx-tools-core-rs==0.6.188",
|
|
14
15
|
]
|
|
15
16
|
|
|
16
17
|
[project.urls]
|
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
[project]
|
|
4
4
|
name = "dbx-tools-postgres"
|
|
5
|
-
version = "0.6.
|
|
5
|
+
version = "0.6.188"
|
|
6
6
|
description = "WorkspaceClient-backed Lakebase Postgres resolution, SQLAlchemy engines, advisory locks, and LISTEN/NOTIFY topic bus"
|
|
7
7
|
readme = "README.md"
|
|
8
|
-
requires-python = ">=3.11,<
|
|
9
|
-
dependencies = ["asyncpg>=0.30", "databricks-sdk>=0.63.0", "greenlet>=3.2", "psycopg[binary]>=3.2.9", "sqlalchemy>=2.0.41", "dbx-tools-core==0.6.
|
|
8
|
+
requires-python = ">=3.11,<4"
|
|
9
|
+
dependencies = ["asyncpg>=0.30", "databricks-sdk>=0.63.0", "greenlet>=3.2", "psycopg[binary]>=3.2.9", "sqlalchemy>=2.0.41", "dbx-tools-core==0.6.188", "dbx-tools-core-rs==0.6.188"]
|
|
10
10
|
|
|
11
11
|
[project.urls]
|
|
12
12
|
Source = "https://github.com/reggie-db/dbx-tools/tree/main/packages/py/postgres"
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
from typing import Literal, TypeAlias
|
|
2
|
+
|
|
3
|
+
from dbx_tools.core_rs.bindings import (
|
|
4
|
+
ParsedAddress,
|
|
5
|
+
parse_address,
|
|
6
|
+
parse_resource_path,
|
|
7
|
+
)
|
|
8
|
+
from dbx_tools.core_rs.bindings import (
|
|
9
|
+
SslMode as NativeSslMode,
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
"""Lakebase address types and parsers backed by the Databricks Rust bindings."""
|
|
13
|
+
|
|
14
|
+
SslMode = Literal["require", "disable", "prefer"]
|
|
15
|
+
SSL_MODES: tuple[SslMode, ...] = ("require", "disable", "prefer")
|
|
16
|
+
LakebaseConnectionInputs: TypeAlias = ParsedAddress
|
|
17
|
+
|
|
18
|
+
parseAddress = parse_address
|
|
19
|
+
parseResourcePath = parse_resource_path
|
|
20
|
+
|
|
21
|
+
__all__ = [
|
|
22
|
+
"SSL_MODES",
|
|
23
|
+
"LakebaseConnectionInputs",
|
|
24
|
+
"NativeSslMode",
|
|
25
|
+
"ParsedAddress",
|
|
26
|
+
"SslMode",
|
|
27
|
+
"parseAddress",
|
|
28
|
+
"parseResourcePath",
|
|
29
|
+
"parse_address",
|
|
30
|
+
"parse_resource_path",
|
|
31
|
+
]
|
|
@@ -13,7 +13,14 @@ from sqlalchemy import create_engine as sqlalchemy_create_engine
|
|
|
13
13
|
from sqlalchemy.ext.asyncio import AsyncEngine
|
|
14
14
|
from sqlalchemy.ext.asyncio import create_async_engine as sqlalchemy_create_async_engine
|
|
15
15
|
|
|
16
|
-
from .address import
|
|
16
|
+
from .address import (
|
|
17
|
+
SSL_MODES,
|
|
18
|
+
NativeSslMode,
|
|
19
|
+
ParsedAddress,
|
|
20
|
+
SslMode,
|
|
21
|
+
parse_address,
|
|
22
|
+
parse_resource_path,
|
|
23
|
+
)
|
|
17
24
|
|
|
18
25
|
"""Lakebase connection resolution and connect-time credential injection."""
|
|
19
26
|
|
|
@@ -474,7 +481,7 @@ def _parse_port(value: object) -> int:
|
|
|
474
481
|
def _parse_ssl_mode(value: object) -> SslMode:
|
|
475
482
|
if value is None or value == "":
|
|
476
483
|
return _DEFAULT_SSL_MODE
|
|
477
|
-
mode = str(value).strip().lower()
|
|
484
|
+
mode = value.name.lower() if isinstance(value, NativeSslMode) else str(value).strip().lower()
|
|
478
485
|
if mode not in SSL_MODES:
|
|
479
486
|
raise ValueError(f"PGSSLMODE must be one of {', '.join(SSL_MODES)}, got {value!r}")
|
|
480
487
|
return mode # type: ignore[return-value]
|
|
@@ -1,114 +0,0 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
import re
|
|
4
|
-
from dataclasses import asdict, dataclass
|
|
5
|
-
from typing import Literal
|
|
6
|
-
from urllib.parse import parse_qs, unquote, urlparse
|
|
7
|
-
|
|
8
|
-
SslMode = Literal["require", "disable", "prefer"]
|
|
9
|
-
SSL_MODES: tuple[SslMode, ...] = ("require", "disable", "prefer")
|
|
10
|
-
|
|
11
|
-
_URL_SCHEME_RE = re.compile(r"^(postgres|postgresql)://", re.IGNORECASE)
|
|
12
|
-
_PROJECT_ID_RE = re.compile(r"^[a-z][a-z0-9-]{0,61}[a-z0-9]$|^[a-z]$")
|
|
13
|
-
_HOSTNAME_HINT_RE = re.compile(r"^[a-z0-9][a-z0-9-]*(\.[a-z0-9][a-z0-9-]*)+$", re.IGNORECASE)
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
@dataclass(frozen=True, slots=True)
|
|
17
|
-
class LakebaseConnectionInputs:
|
|
18
|
-
project: str | None = None
|
|
19
|
-
branch: str | None = None
|
|
20
|
-
endpoint: str | None = None
|
|
21
|
-
database: str | None = None
|
|
22
|
-
host: str | None = None
|
|
23
|
-
port: int | None = None
|
|
24
|
-
ssl_mode: SslMode | None = None
|
|
25
|
-
|
|
26
|
-
def as_dict(self) -> dict[str, object]:
|
|
27
|
-
return {key: value for key, value in asdict(self).items() if value is not None}
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
@dataclass(frozen=True, slots=True)
|
|
31
|
-
class ParsedAddress(LakebaseConnectionInputs):
|
|
32
|
-
endpoint_id: str | None = None
|
|
33
|
-
database_resource_id: str | None = None
|
|
34
|
-
user: str | None = None
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
def parse_address(value: str | None) -> ParsedAddress:
|
|
38
|
-
if not value or not (address := value.strip()):
|
|
39
|
-
return ParsedAddress()
|
|
40
|
-
if _URL_SCHEME_RE.match(address):
|
|
41
|
-
return _parse_uri(address)
|
|
42
|
-
if address.startswith("projects/"):
|
|
43
|
-
return _parse_resource_path_segments(address)
|
|
44
|
-
if "." in address and _HOSTNAME_HINT_RE.fullmatch(address):
|
|
45
|
-
return ParsedAddress(host=address)
|
|
46
|
-
if _PROJECT_ID_RE.fullmatch(address):
|
|
47
|
-
return ParsedAddress(project=address)
|
|
48
|
-
return ParsedAddress()
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
def parse_resource_path(value: str | None) -> ParsedAddress:
|
|
52
|
-
if not value or not (address := value.strip()).startswith("projects/"):
|
|
53
|
-
return ParsedAddress()
|
|
54
|
-
return _parse_resource_path_segments(address)
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
def _parse_uri(address: str) -> ParsedAddress:
|
|
58
|
-
try:
|
|
59
|
-
parsed = urlparse(address)
|
|
60
|
-
port = parsed.port
|
|
61
|
-
except ValueError:
|
|
62
|
-
return ParsedAddress()
|
|
63
|
-
if parsed.scheme.lower() not in {"postgres", "postgresql"}:
|
|
64
|
-
return ParsedAddress()
|
|
65
|
-
ssl_mode_value = parse_qs(parsed.query).get("sslmode") or parse_qs(parsed.query).get("sslMode")
|
|
66
|
-
ssl_mode = ssl_mode_value[0].lower() if ssl_mode_value else None
|
|
67
|
-
return ParsedAddress(
|
|
68
|
-
host=parsed.hostname or None,
|
|
69
|
-
port=port,
|
|
70
|
-
user=unquote(parsed.username) if parsed.username else None,
|
|
71
|
-
database=unquote(parsed.path.removeprefix("/")) or None,
|
|
72
|
-
ssl_mode=ssl_mode if ssl_mode in SSL_MODES else None,
|
|
73
|
-
)
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
def _parse_resource_path_segments(address: str) -> ParsedAddress:
|
|
77
|
-
parts = address.split("/")
|
|
78
|
-
if len(parts) < 2 or parts[0] != "projects" or not parts[1]:
|
|
79
|
-
return ParsedAddress()
|
|
80
|
-
project = parts[1]
|
|
81
|
-
if len(parts) == 2:
|
|
82
|
-
return ParsedAddress(project=project)
|
|
83
|
-
if len(parts) == 4 and parts[2] == "branches" and parts[3]:
|
|
84
|
-
return ParsedAddress(project=project, branch=parts[3])
|
|
85
|
-
if (
|
|
86
|
-
len(parts) == 6
|
|
87
|
-
and parts[2] == "branches"
|
|
88
|
-
and parts[3]
|
|
89
|
-
and parts[4] == "endpoints"
|
|
90
|
-
and parts[5]
|
|
91
|
-
):
|
|
92
|
-
return ParsedAddress(
|
|
93
|
-
project=project,
|
|
94
|
-
branch=parts[3],
|
|
95
|
-
endpoint=address,
|
|
96
|
-
endpoint_id=parts[5],
|
|
97
|
-
)
|
|
98
|
-
if (
|
|
99
|
-
len(parts) == 6
|
|
100
|
-
and parts[2] == "branches"
|
|
101
|
-
and parts[3]
|
|
102
|
-
and parts[4] == "databases"
|
|
103
|
-
and parts[5]
|
|
104
|
-
):
|
|
105
|
-
return ParsedAddress(
|
|
106
|
-
project=project,
|
|
107
|
-
branch=parts[3],
|
|
108
|
-
database_resource_id=parts[5],
|
|
109
|
-
)
|
|
110
|
-
return ParsedAddress()
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
parseAddress = parse_address
|
|
114
|
-
parseResourcePath = parse_resource_path
|
{dbx_tools_postgres-0.6.185 → dbx_tools_postgres-0.6.188}/src/dbx_tools/postgres/__init__.py
RENAMED
|
File without changes
|
{dbx_tools_postgres-0.6.185 → dbx_tools_postgres-0.6.188}/src/dbx_tools/postgres/advisory_lock.py
RENAMED
|
File without changes
|
{dbx_tools_postgres-0.6.185 → dbx_tools_postgres-0.6.188}/src/dbx_tools/postgres/topic_bus.py
RENAMED
|
File without changes
|