pymnemon 0.1.1__py3-none-any.whl

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.
File without changes
@@ -0,0 +1,165 @@
1
+ """
2
+ Minimal Databricks engine shim to mimic SQLAlchemy for metadata + queries.
3
+
4
+ The native Databricks SQL driver is not a SQLAlchemy dialect, so we wrap it
5
+ to provide:
6
+ - `connection.execute(...)` that behaves like a Result (returns_rows, keys, fetchall)
7
+ - `engine.dialect.get_schema_names/get_table_names/get_columns` for reflection-like use
8
+ """
9
+ from dataclasses import dataclass
10
+ from typing import Any, Iterable, List, Optional
11
+
12
+ from databricks import sql
13
+ from sqlalchemy.sql import ClauseElement
14
+
15
+
16
+ @dataclass
17
+ class _ResultAdapter:
18
+ """Lightweight adapter to mimic SQLAlchemy Result for mnemon usage."""
19
+ cursor: Any
20
+ returns_rows: bool = True
21
+
22
+ def keys(self) -> List[str]:
23
+ if not getattr(self.cursor, "description", None):
24
+ return []
25
+ return [col[0] for col in self.cursor.description]
26
+
27
+ def fetchall(self) -> Iterable:
28
+ return self.cursor.fetchall()
29
+
30
+
31
+ class _DatabricksDialect:
32
+ """
33
+ Tiny dialect shim providing inspector-style helpers for tables/columns.
34
+ Uses SHOW/DESCRIBE to avoid relying on information_schema availability.
35
+ """
36
+
37
+ def get_inspector(self, engine: "DatabricksEngine") -> "DatabricksInspector":
38
+ return DatabricksInspector(engine)
39
+
40
+ def get_schema_names(self, connection: "DatabricksConnection") -> List[str]:
41
+ cur = connection.execute("SHOW DATABASES")
42
+ return [row[0] for row in cur.fetchall()]
43
+
44
+ def get_table_names(
45
+ self,
46
+ connection: "DatabricksConnection",
47
+ schema: Optional[str] = None,
48
+ ) -> List[str]:
49
+ stmt = f"SHOW TABLES IN `{schema}`" if schema else "SHOW TABLES"
50
+ cur = connection.execute(stmt)
51
+ rows = cur.fetchall()
52
+ # SHOW TABLES columns: database, tableName, isTemporary
53
+ return [row[1] if len(row) > 1 else row[0] for row in rows]
54
+
55
+ def get_columns(
56
+ self,
57
+ connection: "DatabricksConnection",
58
+ table_name: str,
59
+ schema: Optional[str] = None,
60
+ ) -> List[dict]:
61
+ qualified = f"`{schema}`.`{table_name}`" if schema else f"`{table_name}`"
62
+ cur = connection.execute(f"DESCRIBE TABLE {qualified}")
63
+ cols: List[dict] = []
64
+ for row in cur.fetchall():
65
+ # DESCRIBE TABLE returns: col_name, data_type, comment, ...
66
+ if not row or len(row) < 2:
67
+ continue
68
+ name, dtype = row[0], row[1]
69
+ if name is None or str(name).startswith("#"):
70
+ continue # skip footer rows
71
+ cols.append(
72
+ {
73
+ "name": name,
74
+ "type": dtype,
75
+ "nullable": True, # DESCRIBE does not expose nullability
76
+ "default": None,
77
+ }
78
+ )
79
+ return cols
80
+
81
+
82
+ class DatabricksInspector:
83
+ """Inspector-style helper to mirror SQLAlchemy's reflection surface."""
84
+
85
+ def __init__(self, engine: "DatabricksEngine"):
86
+ self.engine = engine
87
+
88
+ def get_schema_names(self) -> List[str]:
89
+ with self.engine.connect() as conn:
90
+ return self.engine.dialect.get_schema_names(conn)
91
+
92
+ def get_table_names(self, schema: Optional[str] = None) -> List[str]:
93
+ with self.engine.connect() as conn:
94
+ return self.engine.dialect.get_table_names(conn, schema=schema)
95
+
96
+ def get_columns(self, table_name: str, schema: Optional[str] = None) -> List[dict]:
97
+ with self.engine.connect() as conn:
98
+ return self.engine.dialect.get_columns(conn, table_name, schema=schema)
99
+
100
+
101
+ class DatabricksEngine:
102
+ def __init__(self, conn):
103
+ self._conn = conn
104
+ self.dialect = _DatabricksDialect()
105
+
106
+ def connect(self):
107
+ return DatabricksConnection(self._conn, self.dialect, engine=self)
108
+
109
+ def dispose(self):
110
+ try:
111
+ self._conn.close()
112
+ except Exception:
113
+ pass
114
+
115
+
116
+ class DatabricksConnection:
117
+ def __init__(self, conn, dialect: _DatabricksDialect, engine: Optional["DatabricksEngine"] = None):
118
+ self._conn = conn
119
+ self.dialect = dialect
120
+ self.engine = engine
121
+
122
+ def execute(self, statement, parameters=None):
123
+ # Accept either raw SQL string or a compiled ClauseElement
124
+ if isinstance(statement, ClauseElement):
125
+ compiled = statement.compile(compile_kwargs={"literal_binds": True})
126
+ sql_stmt = str(compiled)
127
+ else:
128
+ sql_stmt = str(statement)
129
+
130
+ cursor = self._conn.cursor()
131
+ cursor.execute(sql_stmt, parameters or {})
132
+ return _ResultAdapter(cursor)
133
+
134
+ # Alias to mirror SQLAlchemy Connection API
135
+ def exec_driver_sql(self, statement: str, parameters=None):
136
+ return self.execute(statement, parameters)
137
+
138
+ def __enter__(self):
139
+ return self
140
+
141
+ def __exit__(self, exc_type, exc, tb):
142
+ self.close()
143
+
144
+ def close(self):
145
+ pass
146
+
147
+
148
+ def build_databricks_connection(auth_method: str, config: dict):
149
+ common = {
150
+ "server_hostname": config["host"],
151
+ "http_path": config["http_path"],
152
+ }
153
+
154
+ if auth_method == "oauth_m2m":
155
+ return sql.connect(
156
+ **common,
157
+ auth_type="oauth-m2m",
158
+ client_id=config["client_id"],
159
+ client_secret=config["client_secret"],
160
+ )
161
+
162
+ return sql.connect(
163
+ **common,
164
+ access_token=config["access_token"],
165
+ )
@@ -0,0 +1,374 @@
1
+ """
2
+ DIALECT_QUERIES - Database-specific SQL for introspection methods.
3
+ Used by SchemaDBConnection for cross-database compatibility.
4
+ """
5
+
6
+ DIALECT_QUERIES = {
7
+ "postgresql": {
8
+ "get_schema_tables": """
9
+ SELECT table_name
10
+ FROM information_schema.tables
11
+ WHERE table_schema = :schema
12
+ AND table_type = 'BASE TABLE'
13
+ ORDER BY table_name
14
+ """,
15
+ "get_table_columns": """
16
+ SELECT column_name, data_type, is_nullable, column_default
17
+ FROM information_schema.columns
18
+ WHERE table_schema = :schema AND table_name = :table
19
+ ORDER BY ordinal_position
20
+ """,
21
+ "get_table_sample": 'SELECT * FROM "{schema}"."{table}" LIMIT :limit',
22
+ "get_table_count": 'SELECT COUNT(*) AS count FROM "{schema}"."{table}"',
23
+ "get_schemas": """
24
+ SELECT schema_name
25
+ FROM information_schema.schemata
26
+ WHERE schema_name NOT IN ('pg_catalog', 'information_schema', 'pg_toast')
27
+ ORDER BY schema_name
28
+ """,
29
+ },
30
+
31
+ "snowflake": {
32
+ "get_schema_tables": """
33
+ SELECT table_name
34
+ FROM information_schema.tables
35
+ WHERE table_schema = :schema
36
+ AND table_type = 'BASE TABLE'
37
+ ORDER BY table_name
38
+ """,
39
+ "get_table_columns": """
40
+ SELECT column_name, data_type, is_nullable, column_default
41
+ FROM information_schema.columns
42
+ WHERE table_schema = :schema AND table_name = :table
43
+ ORDER BY ordinal_position
44
+ """,
45
+ "get_table_sample": 'SELECT * FROM "{schema}"."{table}" LIMIT :limit',
46
+ "get_table_count": 'SELECT COUNT(*) AS count FROM "{schema}"."{table}"',
47
+ "get_schemas": """
48
+ SELECT schema_name
49
+ FROM information_schema.schemata
50
+ ORDER BY schema_name
51
+ """,
52
+ },
53
+
54
+ "bigquery": {
55
+ "get_schema_tables": """
56
+ SELECT table_name
57
+ FROM `{project}.{schema}.INFORMATION_SCHEMA.TABLES`
58
+ WHERE table_type = 'BASE TABLE'
59
+ ORDER BY table_name
60
+ """,
61
+ "get_table_columns": """
62
+ SELECT column_name, data_type, is_nullable, column_default
63
+ FROM `{project}.{schema}.INFORMATION_SCHEMA.COLUMNS`
64
+ WHERE table_name = :table
65
+ ORDER BY ordinal_position
66
+ """,
67
+ "get_table_sample": "SELECT * FROM `{project}.{schema}.{table}` LIMIT :limit",
68
+ "get_table_count": "SELECT COUNT(*) AS count FROM `{project}.{schema}.{table}`",
69
+ "get_schemas": """
70
+ SELECT schema_name
71
+ FROM `{project}.INFORMATION_SCHEMA.SCHEMATA`
72
+ ORDER BY schema_name
73
+ """,
74
+ },
75
+
76
+ "redshift": {
77
+ "get_schema_tables": """
78
+ SELECT tablename AS table_name
79
+ FROM pg_tables
80
+ WHERE schemaname = :schema
81
+ ORDER BY tablename
82
+ """,
83
+ "get_table_columns": """
84
+ SELECT column_name, data_type, is_nullable, column_default
85
+ FROM information_schema.columns
86
+ WHERE table_schema = :schema AND table_name = :table
87
+ ORDER BY ordinal_position
88
+ """,
89
+ "get_table_sample": 'SELECT * FROM "{schema}"."{table}" LIMIT :limit',
90
+ "get_table_count": 'SELECT COUNT(*) AS count FROM "{schema}"."{table}"',
91
+ "get_schemas": """
92
+ SELECT schema_name
93
+ FROM information_schema.schemata
94
+ WHERE schema_name NOT IN ('pg_catalog', 'information_schema', 'pg_internal')
95
+ ORDER BY schema_name
96
+ """,
97
+ },
98
+
99
+ "clickhouse": {
100
+ "get_schema_tables": """
101
+ SELECT name AS table_name
102
+ FROM system.tables
103
+ WHERE database = :schema
104
+ AND engine NOT IN ('View', 'MaterializedView')
105
+ ORDER BY name
106
+ """,
107
+ "get_table_columns": """
108
+ SELECT name AS column_name, type AS data_type,
109
+ if(type LIKE 'Nullable%', 'YES', 'NO') AS is_nullable,
110
+ default_expression AS column_default
111
+ FROM system.columns
112
+ WHERE database = :schema AND table = :table
113
+ ORDER BY position
114
+ """,
115
+ "get_table_sample": "SELECT * FROM {schema}.{table} LIMIT :limit",
116
+ "get_table_count": "SELECT COUNT(*) AS count FROM {schema}.{table}",
117
+ "get_schemas": """
118
+ SELECT name AS schema_name
119
+ FROM system.databases
120
+ WHERE name NOT IN ('system', 'INFORMATION_SCHEMA', 'information_schema')
121
+ ORDER BY name
122
+ """,
123
+ },
124
+
125
+ "duckdb": {
126
+ "get_schema_tables": """
127
+ SELECT table_name
128
+ FROM information_schema.tables
129
+ WHERE table_schema = :schema
130
+ AND table_type = 'BASE TABLE'
131
+ ORDER BY table_name
132
+ """,
133
+ "get_table_columns": """
134
+ SELECT column_name, data_type, is_nullable, column_default
135
+ FROM information_schema.columns
136
+ WHERE table_schema = :schema AND table_name = :table
137
+ ORDER BY ordinal_position
138
+ """,
139
+ "get_table_sample": 'SELECT * FROM "{schema}"."{table}" LIMIT :limit',
140
+ "get_table_count": 'SELECT COUNT(*) AS count FROM "{schema}"."{table}"',
141
+ "get_schemas": """
142
+ SELECT schema_name
143
+ FROM information_schema.schemata
144
+ ORDER BY schema_name
145
+ """,
146
+ },
147
+
148
+ "mysql": {
149
+ "get_schema_tables": """
150
+ SELECT table_name
151
+ FROM information_schema.tables
152
+ WHERE table_schema = :schema
153
+ AND table_type = 'BASE TABLE'
154
+ ORDER BY table_name
155
+ """,
156
+ "get_table_columns": """
157
+ SELECT column_name, data_type, is_nullable, column_default
158
+ FROM information_schema.columns
159
+ WHERE table_schema = :schema AND table_name = :table
160
+ ORDER BY ordinal_position
161
+ """,
162
+ "get_table_sample": "SELECT * FROM `{schema}`.`{table}` LIMIT :limit",
163
+ "get_table_count": "SELECT COUNT(*) AS count FROM `{schema}`.`{table}`",
164
+ "get_schemas": """
165
+ SELECT schema_name
166
+ FROM information_schema.schemata
167
+ WHERE schema_name NOT IN ('mysql', 'information_schema', 'performance_schema', 'sys')
168
+ ORDER BY schema_name
169
+ """,
170
+ },
171
+
172
+ "sqlserver": {
173
+ "get_schema_tables": """
174
+ SELECT table_name
175
+ FROM information_schema.tables
176
+ WHERE table_schema = :schema
177
+ AND table_type = 'BASE TABLE'
178
+ ORDER BY table_name
179
+ """,
180
+ "get_table_columns": """
181
+ SELECT column_name, data_type, is_nullable, column_default
182
+ FROM information_schema.columns
183
+ WHERE table_schema = :schema AND table_name = :table
184
+ ORDER BY ordinal_position
185
+ """,
186
+ "get_table_sample": "SELECT TOP (:limit) * FROM [{schema}].[{table}]",
187
+ "get_table_count": "SELECT COUNT(*) AS count FROM [{schema}].[{table}]",
188
+ "get_schemas": """
189
+ SELECT schema_name
190
+ FROM information_schema.schemata
191
+ WHERE schema_name NOT IN ('sys', 'guest', 'INFORMATION_SCHEMA')
192
+ ORDER BY schema_name
193
+ """,
194
+ },
195
+
196
+ "databricks": {
197
+ "get_schema_tables": """
198
+ SELECT table_name
199
+ FROM information_schema.tables
200
+ WHERE table_schema = :schema
201
+ AND table_type = 'BASE TABLE'
202
+ ORDER BY table_name
203
+ """,
204
+ "get_table_columns": """
205
+ SELECT column_name, data_type, is_nullable, column_default
206
+ FROM information_schema.columns
207
+ WHERE table_schema = :schema AND table_name = :table
208
+ ORDER BY ordinal_position
209
+ """,
210
+ "get_table_sample": "SELECT * FROM `{schema}`.`{table}` LIMIT :limit",
211
+ "get_table_count": "SELECT COUNT(*) AS count FROM `{schema}`.`{table}`",
212
+ "get_schemas": """
213
+ SELECT schema_name
214
+ FROM information_schema.schemata
215
+ ORDER BY schema_name
216
+ """,
217
+ },
218
+
219
+ "athena": {
220
+ "get_schema_tables": """
221
+ SELECT table_name
222
+ FROM information_schema.tables
223
+ WHERE table_schema = :schema
224
+ AND table_type = 'BASE TABLE'
225
+ ORDER BY table_name
226
+ """,
227
+ "get_table_columns": """
228
+ SELECT column_name, data_type, is_nullable, '' AS column_default
229
+ FROM information_schema.columns
230
+ WHERE table_schema = :schema AND table_name = :table
231
+ ORDER BY ordinal_position
232
+ """,
233
+ "get_table_sample": 'SELECT * FROM "{schema}"."{table}" LIMIT :limit',
234
+ "get_table_count": 'SELECT COUNT(*) AS count FROM "{schema}"."{table}"',
235
+ "get_schemas": """
236
+ SELECT schema_name
237
+ FROM information_schema.schemata
238
+ ORDER BY schema_name
239
+ """,
240
+ },
241
+
242
+ "trino": {
243
+ "get_schema_tables": """
244
+ SELECT table_name
245
+ FROM information_schema.tables
246
+ WHERE table_schema = :schema
247
+ AND table_type = 'BASE TABLE'
248
+ ORDER BY table_name
249
+ """,
250
+ "get_table_columns": """
251
+ SELECT column_name, data_type, is_nullable, '' AS column_default
252
+ FROM information_schema.columns
253
+ WHERE table_schema = :schema AND table_name = :table
254
+ ORDER BY ordinal_position
255
+ """,
256
+ "get_table_sample": 'SELECT * FROM "{schema}"."{table}" LIMIT :limit',
257
+ "get_table_count": 'SELECT COUNT(*) AS count FROM "{schema}"."{table}"',
258
+ "get_schemas": """
259
+ SELECT schema_name
260
+ FROM information_schema.schemata
261
+ ORDER BY schema_name
262
+ """,
263
+ },
264
+
265
+ "sparksql": {
266
+ "get_schema_tables": """
267
+ SHOW TABLES IN {schema}
268
+ """,
269
+ "get_table_columns": """
270
+ DESCRIBE {schema}.{table}
271
+ """,
272
+ "get_table_sample": "SELECT * FROM {schema}.{table} LIMIT :limit",
273
+ "get_table_count": "SELECT COUNT(*) AS count FROM {schema}.{table}",
274
+ "get_schemas": """
275
+ SHOW DATABASES
276
+ """,
277
+ },
278
+
279
+ "vertica": {
280
+ "get_schema_tables": """
281
+ SELECT table_name
282
+ FROM v_catalog.tables
283
+ WHERE table_schema = :schema
284
+ ORDER BY table_name
285
+ """,
286
+ "get_table_columns": """
287
+ SELECT column_name, data_type, is_nullable, column_default
288
+ FROM v_catalog.columns
289
+ WHERE table_schema = :schema AND table_name = :table
290
+ ORDER BY ordinal_position
291
+ """,
292
+ "get_table_sample": 'SELECT * FROM "{schema}"."{table}" LIMIT :limit',
293
+ "get_table_count": 'SELECT COUNT(*) AS count FROM "{schema}"."{table}"',
294
+ "get_schemas": """
295
+ SELECT schema_name
296
+ FROM v_catalog.schemata
297
+ WHERE NOT is_system_schema
298
+ ORDER BY schema_name
299
+ """,
300
+ },
301
+
302
+ "oracle": {
303
+ "get_schema_tables": """
304
+ SELECT table_name
305
+ FROM all_tables
306
+ WHERE owner = UPPER(:schema)
307
+ ORDER BY table_name
308
+ """,
309
+ "get_table_columns": """
310
+ SELECT column_name, data_type, nullable AS is_nullable, data_default AS column_default
311
+ FROM all_tab_columns
312
+ WHERE owner = UPPER(:schema) AND table_name = UPPER(:table)
313
+ ORDER BY column_id
314
+ """,
315
+ "get_table_sample": 'SELECT * FROM "{schema}"."{table}" WHERE ROWNUM <= :limit',
316
+ "get_table_count": 'SELECT COUNT(*) AS count FROM "{schema}"."{table}"',
317
+ "get_schemas": """
318
+ SELECT username AS schema_name
319
+ FROM all_users
320
+ ORDER BY username
321
+ """,
322
+ },
323
+
324
+ "teradata": {
325
+ "get_schema_tables": """
326
+ SELECT TableName AS table_name
327
+ FROM DBC.TablesV
328
+ WHERE DatabaseName = :schema
329
+ AND TableKind = 'T'
330
+ ORDER BY TableName
331
+ """,
332
+ "get_table_columns": """
333
+ SELECT ColumnName AS column_name, ColumnType AS data_type,
334
+ CASE WHEN Nullable = 'Y' THEN 'YES' ELSE 'NO' END AS is_nullable,
335
+ DefaultValue AS column_default
336
+ FROM DBC.ColumnsV
337
+ WHERE DatabaseName = :schema AND TableName = :table
338
+ ORDER BY ColumnId
339
+ """,
340
+ "get_table_sample": 'SELECT TOP :limit * FROM "{schema}"."{table}"',
341
+ "get_table_count": 'SELECT COUNT(*) AS count FROM "{schema}"."{table}"',
342
+ "get_schemas": """
343
+ SELECT DatabaseName AS schema_name
344
+ FROM DBC.DatabasesV
345
+ ORDER BY DatabaseName
346
+ """,
347
+ },
348
+
349
+ "db2": {
350
+ "get_schema_tables": """
351
+ SELECT tabname AS table_name
352
+ FROM syscat.tables
353
+ WHERE tabschema = UPPER(:schema)
354
+ AND type = 'T'
355
+ ORDER BY tabname
356
+ """,
357
+ "get_table_columns": """
358
+ SELECT colname AS column_name, typename AS data_type,
359
+ CASE WHEN nulls = 'Y' THEN 'YES' ELSE 'NO' END AS is_nullable,
360
+ default AS column_default
361
+ FROM syscat.columns
362
+ WHERE tabschema = UPPER(:schema) AND tabname = UPPER(:table)
363
+ ORDER BY colno
364
+ """,
365
+ "get_table_sample": 'SELECT * FROM "{schema}"."{table}" FETCH FIRST :limit ROWS ONLY',
366
+ "get_table_count": 'SELECT COUNT(*) AS count FROM "{schema}"."{table}"',
367
+ "get_schemas": """
368
+ SELECT schemaname AS schema_name
369
+ FROM syscat.schemata
370
+ WHERE schemaname NOT LIKE 'SYS%'
371
+ ORDER BY schemaname
372
+ """,
373
+ },
374
+ }