SCUDO 0.1.0__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.
- scudo-0.1.0/PKG-INFO +9 -0
- scudo-0.1.0/README.md +4 -0
- scudo-0.1.0/pyproject.toml +19 -0
- scudo-0.1.0/setup.cfg +4 -0
- scudo-0.1.0/src/SCUDO.egg-info/PKG-INFO +9 -0
- scudo-0.1.0/src/SCUDO.egg-info/SOURCES.txt +19 -0
- scudo-0.1.0/src/SCUDO.egg-info/dependency_links.txt +1 -0
- scudo-0.1.0/src/SCUDO.egg-info/requires.txt +3 -0
- scudo-0.1.0/src/SCUDO.egg-info/top_level.txt +1 -0
- scudo-0.1.0/src/cudo/__init__.py +0 -0
- scudo-0.1.0/src/cudo/doris/__init__.py +0 -0
- scudo-0.1.0/src/cudo/doris/client.py +310 -0
- scudo-0.1.0/src/cudo/doris/pymysql.py +380 -0
- scudo-0.1.0/src/cudo/minio/__init__.py +0 -0
- scudo-0.1.0/src/cudo/minio/minio.py +300 -0
- scudo-0.1.0/src/cudo/spark/__init__.py +0 -0
- scudo-0.1.0/src/cudo/spark/spark.py +239 -0
- scudo-0.1.0/src/cudo/utils/__init__.py +0 -0
- scudo-0.1.0/src/cudo/utils/clinic.py +109 -0
- scudo-0.1.0/src/cudo/utils/logging.py +96 -0
- scudo-0.1.0/src/cudo/utils/vcf.py +319 -0
scudo-0.1.0/PKG-INFO
ADDED
scudo-0.1.0/README.md
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "SCUDO"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "Shared Core Utilities for DataHub Operations"
|
|
5
|
+
authors = [{ name = "CNIC" }]
|
|
6
|
+
requires-python = ">=3.12"
|
|
7
|
+
|
|
8
|
+
dependencies = [
|
|
9
|
+
"pandas",
|
|
10
|
+
"adbc-driver-manager",
|
|
11
|
+
"adbc-driver-flightsql"
|
|
12
|
+
]
|
|
13
|
+
|
|
14
|
+
[build-system]
|
|
15
|
+
requires = ["setuptools"]
|
|
16
|
+
build-backend = "setuptools.build_meta"
|
|
17
|
+
|
|
18
|
+
[tool.setuptools.packages.find]
|
|
19
|
+
where = ["src"]
|
scudo-0.1.0/setup.cfg
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
README.md
|
|
2
|
+
pyproject.toml
|
|
3
|
+
src/SCUDO.egg-info/PKG-INFO
|
|
4
|
+
src/SCUDO.egg-info/SOURCES.txt
|
|
5
|
+
src/SCUDO.egg-info/dependency_links.txt
|
|
6
|
+
src/SCUDO.egg-info/requires.txt
|
|
7
|
+
src/SCUDO.egg-info/top_level.txt
|
|
8
|
+
src/cudo/__init__.py
|
|
9
|
+
src/cudo/doris/__init__.py
|
|
10
|
+
src/cudo/doris/client.py
|
|
11
|
+
src/cudo/doris/pymysql.py
|
|
12
|
+
src/cudo/minio/__init__.py
|
|
13
|
+
src/cudo/minio/minio.py
|
|
14
|
+
src/cudo/spark/__init__.py
|
|
15
|
+
src/cudo/spark/spark.py
|
|
16
|
+
src/cudo/utils/__init__.py
|
|
17
|
+
src/cudo/utils/clinic.py
|
|
18
|
+
src/cudo/utils/logging.py
|
|
19
|
+
src/cudo/utils/vcf.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
cudo
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
|
|
4
|
+
'''
|
|
5
|
+
# Doris Flight SQL Client (ADBC)
|
|
6
|
+
|
|
7
|
+
Python client for interacting with Apache Doris using Arrow Flight SQL via ADBC.
|
|
8
|
+
|
|
9
|
+
This class provides:
|
|
10
|
+
- Simple connection handling
|
|
11
|
+
- Query execution
|
|
12
|
+
- Optimized DataFrame fetching (`fetch_df`)
|
|
13
|
+
- Optional Arrow-based and partition-based methods
|
|
14
|
+
- Timing and logging utilities
|
|
15
|
+
|
|
16
|
+
## Requirements
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
pip install adbc_driver_manager adbc_driver_flightsql pandas
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Example
|
|
23
|
+
client = DorisFlightSQLClient(
|
|
24
|
+
uri="grpc://127.0.0.1:9090",
|
|
25
|
+
username="root",
|
|
26
|
+
password=""
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
df = client.query("SELECT * FROM my_table LIMIT 1000;")
|
|
30
|
+
print(df.head())
|
|
31
|
+
|
|
32
|
+
client.close()
|
|
33
|
+
'''
|
|
34
|
+
|
|
35
|
+
import adbc_driver_manager
|
|
36
|
+
import adbc_driver_flightsql.dbapi as flight_sql
|
|
37
|
+
import pandas as pd
|
|
38
|
+
from datetime import datetime
|
|
39
|
+
from typing import Optional
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class DorisFlightSQLClient:
|
|
44
|
+
'''
|
|
45
|
+
Apache Doris Flight SQL client using ADBC (DB-API 2.0).
|
|
46
|
+
This client wraps the ADBC Flight SQL driver and provides optimized
|
|
47
|
+
methods for querying data into pandas DataFrames.
|
|
48
|
+
|
|
49
|
+
Parameters
|
|
50
|
+
----------
|
|
51
|
+
uri : str
|
|
52
|
+
Flight SQL endpoint (e.g., "grpc://127.0.0.1:9090").
|
|
53
|
+
|
|
54
|
+
username : str
|
|
55
|
+
Database username.
|
|
56
|
+
|
|
57
|
+
password : str
|
|
58
|
+
Database password.
|
|
59
|
+
|
|
60
|
+
Attributes
|
|
61
|
+
----------
|
|
62
|
+
conn : flight_sql.Connection
|
|
63
|
+
Active database connection.
|
|
64
|
+
|
|
65
|
+
cursor : flight_sql.Cursor
|
|
66
|
+
Cursor used for executing queries.
|
|
67
|
+
|
|
68
|
+
Notes
|
|
69
|
+
-----
|
|
70
|
+
- Uses `fetch_df()` by default for best performance.
|
|
71
|
+
- Compatible with Apache Doris Arrow Flight SQL service.
|
|
72
|
+
'''
|
|
73
|
+
|
|
74
|
+
def __init__(self, uri: str, username: str, password: str) -> None:
|
|
75
|
+
self.uri = uri
|
|
76
|
+
self.db_kwargs = {
|
|
77
|
+
adbc_driver_manager.DatabaseOptions.USERNAME.value: username,
|
|
78
|
+
adbc_driver_manager.DatabaseOptions.PASSWORD.value: password,
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
self.conn: Optional[flight_sql.Connection] = None
|
|
82
|
+
self.cursor: Optional[flight_sql.Cursor] = None
|
|
83
|
+
|
|
84
|
+
self._connect()
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
# ------------------------------------------------------------------
|
|
88
|
+
# Connection Handling
|
|
89
|
+
# ------------------------------------------------------------------
|
|
90
|
+
|
|
91
|
+
def _connect(self) -> None:
|
|
92
|
+
'''
|
|
93
|
+
Establish a connection and create a cursor.
|
|
94
|
+
'''
|
|
95
|
+
try:
|
|
96
|
+
self.conn = flight_sql.connect(uri=self.uri, db_kwargs=self.db_kwargs)
|
|
97
|
+
self.cursor = self.conn.cursor()
|
|
98
|
+
except Exception as e:
|
|
99
|
+
raise RuntimeError("Connection failed") from e
|
|
100
|
+
|
|
101
|
+
def close(self) -> None:
|
|
102
|
+
'''
|
|
103
|
+
Close cursor and connection.
|
|
104
|
+
'''
|
|
105
|
+
try:
|
|
106
|
+
if self.cursor:
|
|
107
|
+
self.cursor.close()
|
|
108
|
+
finally:
|
|
109
|
+
if self.conn:
|
|
110
|
+
self.conn.close()
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
# ------------------------------------------------------------------
|
|
114
|
+
# Core Query Method
|
|
115
|
+
# ------------------------------------------------------------------
|
|
116
|
+
|
|
117
|
+
def query(self, sql: str, params: dict | None = None) -> pd.DataFrame:
|
|
118
|
+
'''
|
|
119
|
+
Execute a SQL query and return a pandas DataFrame.
|
|
120
|
+
|
|
121
|
+
This method uses `fetch_df()` (ADBC optimized path),
|
|
122
|
+
which is faster than converting from Arrow manually.
|
|
123
|
+
|
|
124
|
+
Parameters
|
|
125
|
+
----------
|
|
126
|
+
sql : str
|
|
127
|
+
SQL query string.
|
|
128
|
+
|
|
129
|
+
params : dict, optional
|
|
130
|
+
Parameters to safely inject into SQL.
|
|
131
|
+
|
|
132
|
+
Returns
|
|
133
|
+
-------
|
|
134
|
+
pandas.DataFrame
|
|
135
|
+
Query result as a DataFrame.
|
|
136
|
+
|
|
137
|
+
Example
|
|
138
|
+
-------
|
|
139
|
+
>>> df = client.query("SELECT * FROM table LIMIT 100;")
|
|
140
|
+
|
|
141
|
+
'''
|
|
142
|
+
if not self.cursor:
|
|
143
|
+
raise RuntimeError("Cursor is not initialized.")
|
|
144
|
+
|
|
145
|
+
sql = self._render_sql(sql, params=params)
|
|
146
|
+
|
|
147
|
+
start_time = datetime.now()
|
|
148
|
+
|
|
149
|
+
try:
|
|
150
|
+
self.cursor.execute(sql)
|
|
151
|
+
df = self.cursor.fetch_df()
|
|
152
|
+
except Exception as e:
|
|
153
|
+
raise RuntimeError("Query execution failed") from e
|
|
154
|
+
|
|
155
|
+
duration = datetime.now() - start_time
|
|
156
|
+
|
|
157
|
+
print("\n##################")
|
|
158
|
+
print(f"Query executed in: {duration}")
|
|
159
|
+
print(df.info(memory_usage="deep"))
|
|
160
|
+
|
|
161
|
+
return df
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
# ------------------------------------------------------------------
|
|
165
|
+
# Alternative Methods
|
|
166
|
+
# ------------------------------------------------------------------
|
|
167
|
+
|
|
168
|
+
def query_arrow(self, sql: str, params: dict | None = None) -> pd.DataFrame:
|
|
169
|
+
'''
|
|
170
|
+
Execute query using Arrow fetch, then convert to pandas.
|
|
171
|
+
|
|
172
|
+
Slower than `query()` but useful for debugging or Arrow workflows.
|
|
173
|
+
|
|
174
|
+
Parameters
|
|
175
|
+
----------
|
|
176
|
+
sql : str
|
|
177
|
+
SQL query.
|
|
178
|
+
|
|
179
|
+
params : dict, optional
|
|
180
|
+
Parameters to safely inject into SQL.
|
|
181
|
+
|
|
182
|
+
Returns
|
|
183
|
+
-------
|
|
184
|
+
pandas.DataFrame
|
|
185
|
+
'''
|
|
186
|
+
sql = self._render_sql(sql, params=params)
|
|
187
|
+
|
|
188
|
+
start_time = datetime.now()
|
|
189
|
+
|
|
190
|
+
try:
|
|
191
|
+
self.cursor.execute(sql)
|
|
192
|
+
arrow_data = self.cursor.fetchallarrow()
|
|
193
|
+
df = arrow_data.to_pandas()
|
|
194
|
+
except Exception as e:
|
|
195
|
+
raise RuntimeError("Arrow query execution failed") from e
|
|
196
|
+
|
|
197
|
+
duration = datetime.now() - start_time
|
|
198
|
+
|
|
199
|
+
print("\n##################")
|
|
200
|
+
print(f"Arrow fetch in: {duration}, bytes: {arrow_data.nbytes}")
|
|
201
|
+
print(df.info(memory_usage="deep"))
|
|
202
|
+
|
|
203
|
+
return df
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
def query_partition(self, sql: str, params: dict | None = None) -> pd.DataFrame:
|
|
207
|
+
'''
|
|
208
|
+
Execute query using partitioned reads.
|
|
209
|
+
|
|
210
|
+
Useful for parallel processing of large datasets.
|
|
211
|
+
|
|
212
|
+
Parameters
|
|
213
|
+
----------
|
|
214
|
+
sql : str
|
|
215
|
+
SQL query.
|
|
216
|
+
|
|
217
|
+
params : dict, optional
|
|
218
|
+
Parameters to safely inject into SQL.
|
|
219
|
+
|
|
220
|
+
Returns
|
|
221
|
+
-------
|
|
222
|
+
pandas.DataFrame
|
|
223
|
+
'''
|
|
224
|
+
sql = self._render_sql(sql, params=params)
|
|
225
|
+
|
|
226
|
+
start_time = datetime.now()
|
|
227
|
+
|
|
228
|
+
try:
|
|
229
|
+
partitions, schema = self.cursor.adbc_execute_partitions(sql)
|
|
230
|
+
# Example: read first partition (extendable to parallel processing)
|
|
231
|
+
self.cursor.adbc_read_partition(partitions[0])
|
|
232
|
+
arrow_data = self.cursor.fetchallarrow()
|
|
233
|
+
df = arrow_data.to_pandas()
|
|
234
|
+
except Exception as e:
|
|
235
|
+
raise RuntimeError("Partition query execution failed") from e
|
|
236
|
+
|
|
237
|
+
duration = datetime.now() - start_time
|
|
238
|
+
|
|
239
|
+
print("\n##################")
|
|
240
|
+
print(f"Partitions: {len(partitions)}, time: {duration}")
|
|
241
|
+
print(df.info(memory_usage="deep"))
|
|
242
|
+
|
|
243
|
+
return df
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
# ------------------------------------------------------------------
|
|
247
|
+
# Utility Methods
|
|
248
|
+
# ------------------------------------------------------------------
|
|
249
|
+
|
|
250
|
+
def _render_sql(self, sql: str, params: dict | None = None) -> str:
|
|
251
|
+
'''
|
|
252
|
+
Render SQL using simple parameter substitution.
|
|
253
|
+
|
|
254
|
+
Parameters
|
|
255
|
+
----------
|
|
256
|
+
sql : str
|
|
257
|
+
SQL query with `{param}` placeholders.
|
|
258
|
+
|
|
259
|
+
params : dict, optional
|
|
260
|
+
Dictionary of parameters.
|
|
261
|
+
|
|
262
|
+
Returns
|
|
263
|
+
-------
|
|
264
|
+
str
|
|
265
|
+
Rendered SQL string.
|
|
266
|
+
'''
|
|
267
|
+
if params:
|
|
268
|
+
safe_params = {}
|
|
269
|
+
for k, v in params.items():
|
|
270
|
+
if isinstance(v, (int, float)):
|
|
271
|
+
safe_params[k] = v
|
|
272
|
+
elif isinstance(v, str):
|
|
273
|
+
safe_params[k] = "'" + v.replace("'", "''") + "'"
|
|
274
|
+
else:
|
|
275
|
+
raise ValueError(f"Unsafe parameter type for {k}: {type(v)}")
|
|
276
|
+
try:
|
|
277
|
+
return sql.format(**safe_params)
|
|
278
|
+
except KeyError as e:
|
|
279
|
+
raise ValueError(f"Missing SQL parameter: {e}") from e
|
|
280
|
+
|
|
281
|
+
|
|
282
|
+
def execute(self, sql: str) -> None:
|
|
283
|
+
'''
|
|
284
|
+
Execute a SQL statement without returning results.
|
|
285
|
+
|
|
286
|
+
Useful for DDL or INSERT operations.
|
|
287
|
+
|
|
288
|
+
Parameters
|
|
289
|
+
----------
|
|
290
|
+
sql : str
|
|
291
|
+
'''
|
|
292
|
+
if not self.cursor:
|
|
293
|
+
raise RuntimeError("Cursor is not initialized.")
|
|
294
|
+
|
|
295
|
+
print(f"\n### Executing SQL ###\n{sql}")
|
|
296
|
+
self.cursor.execute(sql)
|
|
297
|
+
|
|
298
|
+
|
|
299
|
+
def __enter__(self):
|
|
300
|
+
''' Context manager entry.'''
|
|
301
|
+
return self
|
|
302
|
+
|
|
303
|
+
|
|
304
|
+
def __exit__(self, exc_type, exc_val, exc_tb):
|
|
305
|
+
''' Context manager exit (auto-close).'''
|
|
306
|
+
if exc_type:
|
|
307
|
+
print(f"[DorisFlightSQLClient] Exception: {exc_val}")
|
|
308
|
+
self.close()
|
|
309
|
+
return False # always propagate errors
|
|
310
|
+
|