SQLPyHelper 0.1.6__py3-none-any.whl → 0.1.7__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.
- sqlpyhelper/__init__.py +2 -1
- sqlpyhelper/migration.py +382 -0
- {sqlpyhelper-0.1.6.dist-info → sqlpyhelper-0.1.7.dist-info}/METADATA +2 -2
- sqlpyhelper-0.1.7.dist-info/RECORD +12 -0
- sqlpyhelper-0.1.6.dist-info/RECORD +0 -11
- {sqlpyhelper-0.1.6.dist-info → sqlpyhelper-0.1.7.dist-info}/WHEEL +0 -0
- {sqlpyhelper-0.1.6.dist-info → sqlpyhelper-0.1.7.dist-info}/entry_points.txt +0 -0
- {sqlpyhelper-0.1.6.dist-info → sqlpyhelper-0.1.7.dist-info}/licenses/LICENSE +0 -0
- {sqlpyhelper-0.1.6.dist-info → sqlpyhelper-0.1.7.dist-info}/top_level.txt +0 -0
sqlpyhelper/__init__.py
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
# Match the version in setup.py
|
|
2
|
-
__version__ = "0.1.
|
|
2
|
+
__version__ = "0.1.7"
|
|
3
3
|
|
|
4
4
|
from sqlpyhelper.db_helper import ( # noqa: F401
|
|
5
5
|
BackupError,
|
|
@@ -7,3 +7,4 @@ from sqlpyhelper.db_helper import ( # noqa: F401
|
|
|
7
7
|
QueryError,
|
|
8
8
|
SQLPyHelperError,
|
|
9
9
|
)
|
|
10
|
+
from sqlpyhelper.migration import MigrationError # noqa: F401
|
sqlpyhelper/migration.py
ADDED
|
@@ -0,0 +1,382 @@
|
|
|
1
|
+
"""
|
|
2
|
+
sqlpyhelper.migration
|
|
3
|
+
~~~~~~~~~~~~~~~~~~~~~
|
|
4
|
+
Cross-database table migration utilities.
|
|
5
|
+
|
|
6
|
+
Copies data (and optionally schema) from one database to another.
|
|
7
|
+
Supports SQLite, PostgreSQL, MySQL, SQL Server, and Oracle.
|
|
8
|
+
|
|
9
|
+
Example usage::
|
|
10
|
+
|
|
11
|
+
from sqlpyhelper.db_helper import SQLPyHelper
|
|
12
|
+
from sqlpyhelper.migration import migrate_table
|
|
13
|
+
|
|
14
|
+
with SQLPyHelper(db_type="sqlite", database="local.db") as source:
|
|
15
|
+
with SQLPyHelper(db_type="postgres", host="localhost",
|
|
16
|
+
user="user", password="pass",
|
|
17
|
+
database="mydb") as target:
|
|
18
|
+
|
|
19
|
+
migrate_table(
|
|
20
|
+
source=source,
|
|
21
|
+
target=target,
|
|
22
|
+
table="users",
|
|
23
|
+
)
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
import logging
|
|
27
|
+
from typing import Any, Optional
|
|
28
|
+
|
|
29
|
+
logger = logging.getLogger("sqlpyhelper.migration")
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class MigrationError(Exception):
|
|
33
|
+
"""Raised when a migration operation fails."""
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
# ---------------------------------------------------------------------------
|
|
37
|
+
# Type mapping
|
|
38
|
+
# ---------------------------------------------------------------------------
|
|
39
|
+
|
|
40
|
+
# Maps (source_db_type, generic_type) -> target SQL type string.
|
|
41
|
+
# Generic types are normalised from the source cursor description.
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
_TYPE_MAP: dict[str, dict[str, str]] = {
|
|
45
|
+
"sqlite": {
|
|
46
|
+
"integer": "INTEGER",
|
|
47
|
+
"real": "REAL",
|
|
48
|
+
"text": "TEXT",
|
|
49
|
+
"blob": "BLOB",
|
|
50
|
+
"numeric": "NUMERIC",
|
|
51
|
+
},
|
|
52
|
+
"postgres": {
|
|
53
|
+
"integer": "INTEGER",
|
|
54
|
+
"real": "DOUBLE PRECISION",
|
|
55
|
+
"text": "TEXT",
|
|
56
|
+
"blob": "BYTEA",
|
|
57
|
+
"numeric": "NUMERIC",
|
|
58
|
+
"varchar": "TEXT",
|
|
59
|
+
"bool": "BOOLEAN",
|
|
60
|
+
"date": "DATE",
|
|
61
|
+
"timestamp": "TIMESTAMP",
|
|
62
|
+
},
|
|
63
|
+
"mysql": {
|
|
64
|
+
"integer": "INT",
|
|
65
|
+
"real": "DOUBLE",
|
|
66
|
+
"text": "TEXT",
|
|
67
|
+
"blob": "BLOB",
|
|
68
|
+
"numeric": "DECIMAL",
|
|
69
|
+
"varchar": "VARCHAR(255)",
|
|
70
|
+
"bool": "TINYINT(1)",
|
|
71
|
+
"date": "DATE",
|
|
72
|
+
"timestamp": "DATETIME",
|
|
73
|
+
},
|
|
74
|
+
"sqlserver": {
|
|
75
|
+
"integer": "INT",
|
|
76
|
+
"real": "FLOAT",
|
|
77
|
+
"text": "NVARCHAR(MAX)",
|
|
78
|
+
"blob": "VARBINARY(MAX)",
|
|
79
|
+
"numeric": "DECIMAL",
|
|
80
|
+
"varchar": "NVARCHAR(255)",
|
|
81
|
+
"bool": "BIT",
|
|
82
|
+
"date": "DATE",
|
|
83
|
+
"timestamp": "DATETIME2",
|
|
84
|
+
},
|
|
85
|
+
"oracle": {
|
|
86
|
+
"integer": "NUMBER",
|
|
87
|
+
"real": "FLOAT",
|
|
88
|
+
"text": "CLOB",
|
|
89
|
+
"blob": "BLOB",
|
|
90
|
+
"numeric": "NUMBER",
|
|
91
|
+
"varchar": "VARCHAR2(255)",
|
|
92
|
+
"bool": "NUMBER(1)",
|
|
93
|
+
"date": "DATE",
|
|
94
|
+
"timestamp": "TIMESTAMP",
|
|
95
|
+
},
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def _normalise_type(raw_type: Optional[str]) -> str:
|
|
100
|
+
"""
|
|
101
|
+
Normalise a raw column type string from a cursor description
|
|
102
|
+
into a generic type key used for cross-database mapping.
|
|
103
|
+
"""
|
|
104
|
+
if raw_type is None:
|
|
105
|
+
return "text"
|
|
106
|
+
t = raw_type.lower().split("(")[0].strip()
|
|
107
|
+
if t in (
|
|
108
|
+
"int",
|
|
109
|
+
"integer",
|
|
110
|
+
"int4",
|
|
111
|
+
"int8",
|
|
112
|
+
"bigint",
|
|
113
|
+
"smallint",
|
|
114
|
+
"tinyint",
|
|
115
|
+
"number",
|
|
116
|
+
):
|
|
117
|
+
return "integer"
|
|
118
|
+
if t in ("real", "float", "double", "double precision", "float4", "float8"):
|
|
119
|
+
return "real"
|
|
120
|
+
if t in (
|
|
121
|
+
"text",
|
|
122
|
+
"clob",
|
|
123
|
+
"nvarchar",
|
|
124
|
+
"nvarchar2",
|
|
125
|
+
"ntext",
|
|
126
|
+
"longtext",
|
|
127
|
+
"mediumtext",
|
|
128
|
+
):
|
|
129
|
+
return "text"
|
|
130
|
+
if t in ("varchar", "varchar2", "character varying", "char", "nchar"):
|
|
131
|
+
return "varchar"
|
|
132
|
+
if t in ("blob", "bytea", "varbinary", "binary", "longblob", "mediumblob"):
|
|
133
|
+
return "blob"
|
|
134
|
+
if t in ("numeric", "decimal"):
|
|
135
|
+
return "numeric"
|
|
136
|
+
if t in ("bool", "boolean"):
|
|
137
|
+
return "bool"
|
|
138
|
+
if t in ("date",):
|
|
139
|
+
return "date"
|
|
140
|
+
if t in ("timestamp", "datetime", "datetime2", "timestamp without time zone"):
|
|
141
|
+
return "timestamp"
|
|
142
|
+
return "text" # safe fallback
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
def _map_type(raw_type: Optional[str], target_db: str) -> str:
|
|
146
|
+
"""Map a source column type to the appropriate type for the target database."""
|
|
147
|
+
generic = _normalise_type(raw_type)
|
|
148
|
+
target_types = _TYPE_MAP.get(target_db, _TYPE_MAP["sqlite"])
|
|
149
|
+
return target_types.get(generic, "TEXT")
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
def _get_column_info(source: Any, table: str) -> list[tuple[str, str]]:
|
|
153
|
+
"""
|
|
154
|
+
Return a list of (column_name, raw_type_string) tuples
|
|
155
|
+
by inspecting the source database schema.
|
|
156
|
+
"""
|
|
157
|
+
db_type = source.db_type
|
|
158
|
+
|
|
159
|
+
if db_type == "sqlite":
|
|
160
|
+
source.execute_query(f"PRAGMA table_info({table})")
|
|
161
|
+
rows = source.fetch_all()
|
|
162
|
+
# PRAGMA table_info returns: (cid, name, type, notnull, dflt_value, pk)
|
|
163
|
+
return [(row[1], row[2]) for row in rows]
|
|
164
|
+
|
|
165
|
+
elif db_type == "postgres":
|
|
166
|
+
source.execute_query(
|
|
167
|
+
"""
|
|
168
|
+
SELECT column_name, data_type
|
|
169
|
+
FROM information_schema.columns
|
|
170
|
+
WHERE table_name = %s
|
|
171
|
+
ORDER BY ordinal_position
|
|
172
|
+
""",
|
|
173
|
+
(table,),
|
|
174
|
+
)
|
|
175
|
+
return source.fetch_all()
|
|
176
|
+
|
|
177
|
+
elif db_type == "mysql":
|
|
178
|
+
source.execute_query(
|
|
179
|
+
"""
|
|
180
|
+
SELECT column_name, data_type
|
|
181
|
+
FROM information_schema.columns
|
|
182
|
+
WHERE table_name = %s AND table_schema = DATABASE()
|
|
183
|
+
ORDER BY ordinal_position
|
|
184
|
+
""",
|
|
185
|
+
(table,),
|
|
186
|
+
)
|
|
187
|
+
return source.fetch_all()
|
|
188
|
+
|
|
189
|
+
elif db_type == "sqlserver":
|
|
190
|
+
source.execute_query(
|
|
191
|
+
"""
|
|
192
|
+
SELECT column_name, data_type
|
|
193
|
+
FROM information_schema.columns
|
|
194
|
+
WHERE table_name = %s
|
|
195
|
+
ORDER BY ordinal_position
|
|
196
|
+
""",
|
|
197
|
+
(table,),
|
|
198
|
+
)
|
|
199
|
+
return source.fetch_all()
|
|
200
|
+
|
|
201
|
+
elif db_type == "oracle":
|
|
202
|
+
source.execute_query(
|
|
203
|
+
"""
|
|
204
|
+
SELECT column_name, data_type
|
|
205
|
+
FROM user_tab_columns
|
|
206
|
+
WHERE table_name = UPPER(:1)
|
|
207
|
+
ORDER BY column_id
|
|
208
|
+
""",
|
|
209
|
+
(table,),
|
|
210
|
+
)
|
|
211
|
+
return source.fetch_all()
|
|
212
|
+
|
|
213
|
+
else:
|
|
214
|
+
raise MigrationError(f"Cannot inspect schema for db_type={db_type!r}")
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
def _build_create_table_sql(
|
|
218
|
+
table: str,
|
|
219
|
+
columns: list[tuple[str, str]],
|
|
220
|
+
target_db: str,
|
|
221
|
+
) -> str:
|
|
222
|
+
"""Build a CREATE TABLE IF NOT EXISTS statement for the target database."""
|
|
223
|
+
col_defs = ", ".join(
|
|
224
|
+
f"{col_name} {_map_type(col_type, target_db)}" for col_name, col_type in columns
|
|
225
|
+
)
|
|
226
|
+
return f"CREATE TABLE IF NOT EXISTS {table} ({col_defs})"
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
def _build_insert_sql(
|
|
230
|
+
table: str,
|
|
231
|
+
column_names: list[str],
|
|
232
|
+
target_db: str,
|
|
233
|
+
) -> str:
|
|
234
|
+
"""Build a parameterised INSERT statement for the target database."""
|
|
235
|
+
cols = ", ".join(column_names)
|
|
236
|
+
placeholder = "?" if target_db == "sqlite" else "%s"
|
|
237
|
+
placeholders = ", ".join([placeholder] * len(column_names))
|
|
238
|
+
return f"INSERT INTO {table} ({cols}) VALUES ({placeholders})"
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
# ---------------------------------------------------------------------------
|
|
242
|
+
# Public API
|
|
243
|
+
# ---------------------------------------------------------------------------
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
def migrate_table(
|
|
247
|
+
source: Any,
|
|
248
|
+
target: Any,
|
|
249
|
+
table: str,
|
|
250
|
+
create_table: bool = True,
|
|
251
|
+
batch_size: int = 500,
|
|
252
|
+
truncate_target: bool = False,
|
|
253
|
+
) -> dict[str, Any]:
|
|
254
|
+
"""
|
|
255
|
+
Migrate a table from one database to another.
|
|
256
|
+
|
|
257
|
+
Copies all rows from ``source`` to ``target``. Optionally creates
|
|
258
|
+
the target table using best-effort type mapping from the source schema.
|
|
259
|
+
|
|
260
|
+
Args:
|
|
261
|
+
source: A connected SQLPyHelper instance (the data source).
|
|
262
|
+
target: A connected SQLPyHelper instance (the destination).
|
|
263
|
+
table: Name of the table to migrate.
|
|
264
|
+
create_table: If True, creates the table in the target database
|
|
265
|
+
using best-effort type mapping. If False, the table
|
|
266
|
+
must already exist in the target. Default: True.
|
|
267
|
+
batch_size: Number of rows to insert per batch. Default: 500.
|
|
268
|
+
truncate_target: If True, deletes all existing rows in the target
|
|
269
|
+
table before inserting. Default: False.
|
|
270
|
+
|
|
271
|
+
Returns:
|
|
272
|
+
A dict with migration statistics::
|
|
273
|
+
|
|
274
|
+
{
|
|
275
|
+
"table": "users",
|
|
276
|
+
"rows_migrated": 1234,
|
|
277
|
+
"batches": 3,
|
|
278
|
+
"source_db": "sqlite",
|
|
279
|
+
"target_db": "postgres",
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
Raises:
|
|
283
|
+
MigrationError: If the migration fails for any reason.
|
|
284
|
+
|
|
285
|
+
Example::
|
|
286
|
+
|
|
287
|
+
from sqlpyhelper.db_helper import SQLPyHelper
|
|
288
|
+
from sqlpyhelper.migration import migrate_table
|
|
289
|
+
|
|
290
|
+
with SQLPyHelper(db_type="sqlite", database="local.db") as source:
|
|
291
|
+
with SQLPyHelper(db_type="postgres", host="localhost",
|
|
292
|
+
user="user", password="pass",
|
|
293
|
+
database="mydb") as target:
|
|
294
|
+
|
|
295
|
+
stats = migrate_table(
|
|
296
|
+
source=source,
|
|
297
|
+
target=target,
|
|
298
|
+
table="users",
|
|
299
|
+
create_table=True,
|
|
300
|
+
batch_size=1000,
|
|
301
|
+
)
|
|
302
|
+
print(f"Migrated {stats['rows_migrated']} rows")
|
|
303
|
+
"""
|
|
304
|
+
source_db = source.db_type
|
|
305
|
+
target_db = target.db_type
|
|
306
|
+
|
|
307
|
+
logger.info(
|
|
308
|
+
"Starting migration of table '%s' from %s -> %s",
|
|
309
|
+
table,
|
|
310
|
+
source_db,
|
|
311
|
+
target_db,
|
|
312
|
+
)
|
|
313
|
+
|
|
314
|
+
try:
|
|
315
|
+
# Step 1 — fetch column info from source
|
|
316
|
+
columns = _get_column_info(source, table)
|
|
317
|
+
if not columns:
|
|
318
|
+
raise MigrationError(
|
|
319
|
+
f"Table '{table}' not found in source database " f"or has no columns."
|
|
320
|
+
)
|
|
321
|
+
column_names = [col[0] for col in columns]
|
|
322
|
+
logger.info("Found %d columns: %s", len(columns), column_names)
|
|
323
|
+
|
|
324
|
+
# Step 2 — optionally create the table in the target
|
|
325
|
+
if create_table:
|
|
326
|
+
ddl = _build_create_table_sql(table, columns, target_db)
|
|
327
|
+
logger.info("Creating target table: %s", ddl)
|
|
328
|
+
target.execute_query(ddl)
|
|
329
|
+
|
|
330
|
+
# Step 3 — optionally truncate the target table
|
|
331
|
+
if truncate_target:
|
|
332
|
+
if target_db == "sqlite":
|
|
333
|
+
target.execute_query(f"DELETE FROM {table}")
|
|
334
|
+
else:
|
|
335
|
+
target.execute_query(f"TRUNCATE TABLE {table}")
|
|
336
|
+
logger.info("Truncated target table '%s'", table)
|
|
337
|
+
|
|
338
|
+
# Step 4 — fetch all rows from source
|
|
339
|
+
source.execute_query(f"SELECT * FROM {table}")
|
|
340
|
+
all_rows = source.fetch_all()
|
|
341
|
+
total_rows = len(all_rows)
|
|
342
|
+
logger.info("Fetched %d rows from source", total_rows)
|
|
343
|
+
|
|
344
|
+
if total_rows == 0:
|
|
345
|
+
logger.info("Source table '%s' is empty — nothing to migrate", table)
|
|
346
|
+
return {
|
|
347
|
+
"table": table,
|
|
348
|
+
"rows_migrated": 0,
|
|
349
|
+
"batches": 0,
|
|
350
|
+
"source_db": source_db,
|
|
351
|
+
"target_db": target_db,
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
# Step 5 — insert in batches
|
|
355
|
+
insert_sql = _build_insert_sql(table, column_names, target_db)
|
|
356
|
+
batches = 0
|
|
357
|
+
for i in range(0, total_rows, batch_size):
|
|
358
|
+
batch = all_rows[i : i + batch_size]
|
|
359
|
+
target.cursor.executemany(insert_sql, batch)
|
|
360
|
+
target.connection.commit()
|
|
361
|
+
batches += 1
|
|
362
|
+
logger.info(
|
|
363
|
+
"Inserted batch %d (%d/%d rows)",
|
|
364
|
+
batches,
|
|
365
|
+
min(i + batch_size, total_rows),
|
|
366
|
+
total_rows,
|
|
367
|
+
)
|
|
368
|
+
|
|
369
|
+
logger.info("Migration complete: %d rows in %d batches", total_rows, batches)
|
|
370
|
+
|
|
371
|
+
return {
|
|
372
|
+
"table": table,
|
|
373
|
+
"rows_migrated": total_rows,
|
|
374
|
+
"batches": batches,
|
|
375
|
+
"source_db": source_db,
|
|
376
|
+
"target_db": target_db,
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
except MigrationError:
|
|
380
|
+
raise
|
|
381
|
+
except Exception as e:
|
|
382
|
+
raise MigrationError(f"Migration of '{table}' failed: {e}") from e
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: SQLPyHelper
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.7
|
|
4
4
|
Summary: A simple SQL database helper package for Python.
|
|
5
5
|
Home-page: https://github.com/adebayopeter/sqlpyhelper
|
|
6
6
|
Author: Adebayo Olaonipekun
|
|
@@ -56,11 +56,11 @@ Dynamic: summary
|
|
|
56
56
|
# SQLPyHelper
|
|
57
57
|
|
|
58
58
|
[](https://pypi.org/project/sqlpyhelper/)
|
|
59
|
+
[](https://sqlpyhelper.readthedocs.io/en/latest/)
|
|
59
60
|
[](https://pypi.org/project/sqlpyhelper/)
|
|
60
61
|
[](https://pypi.org/project/sqlpyhelper/)
|
|
61
62
|
[](https://github.com/adebayopeter/sqlpyhelper/blob/main/LICENSE)
|
|
62
63
|
[](https://github.com/adebayopeter/sqlpyhelper)
|
|
63
|
-
[](https://sqlpyhelper.readthedocs.io/en/latest/)
|
|
64
64
|
|
|
65
65
|
SQLPyHelper is a lightweight Python library that gives you a single, consistent API across **SQLite, PostgreSQL, MySQL, SQL Server, and Oracle** — without the overhead of an ORM.
|
|
66
66
|
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
sqlpyhelper/__init__.py,sha256=wiwMpojvoi0j_qunbTQgMfyxzzIsHMkmDr1ADLyhvfY,246
|
|
2
|
+
sqlpyhelper/automation_utils.py,sha256=pC6pH6bJ-k8iPVeHJ4gUiwEe822dasmKg53ya9bMxyE,5381
|
|
3
|
+
sqlpyhelper/cli.py,sha256=yj0kWJu3oh_JLnmi0L7a5ing2_0x4CQGOKSOhZLAtoY,5646
|
|
4
|
+
sqlpyhelper/db_helper.py,sha256=4DbdBVo86zz1d0hNHtSc4b3Tks7bJGTMTyabsydQyOE,14191
|
|
5
|
+
sqlpyhelper/migration.py,sha256=byAn7ToVgIB8tl1N39DB0MbHigjH2l-qX7QSskgzzTg,11673
|
|
6
|
+
sqlpyhelper/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
7
|
+
sqlpyhelper-0.1.7.dist-info/licenses/LICENSE,sha256=9XzXxZ_8mWFM9-2TlqyE3L69zvRf4VPY_xIzSj5iU-g,1076
|
|
8
|
+
sqlpyhelper-0.1.7.dist-info/METADATA,sha256=C2jJX7sEHHqLnQxL5iZxiG8on4xCDHpEu8_8zuaZWlk,9763
|
|
9
|
+
sqlpyhelper-0.1.7.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
|
|
10
|
+
sqlpyhelper-0.1.7.dist-info/entry_points.txt,sha256=uAzSqwkAbbJqQUKHlPNwOebTJVA0FqkOvn2CRP6xSz8,52
|
|
11
|
+
sqlpyhelper-0.1.7.dist-info/top_level.txt,sha256=FrLqTmqTGDa8jHnnf2ZVkYO-gFvLXX9QonpUCE6wKGs,12
|
|
12
|
+
sqlpyhelper-0.1.7.dist-info/RECORD,,
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
sqlpyhelper/__init__.py,sha256=7hQ4FRKUaUU_TiGuU1cldnvTmG4S2riZP43SqxA4fUI,183
|
|
2
|
-
sqlpyhelper/automation_utils.py,sha256=pC6pH6bJ-k8iPVeHJ4gUiwEe822dasmKg53ya9bMxyE,5381
|
|
3
|
-
sqlpyhelper/cli.py,sha256=yj0kWJu3oh_JLnmi0L7a5ing2_0x4CQGOKSOhZLAtoY,5646
|
|
4
|
-
sqlpyhelper/db_helper.py,sha256=4DbdBVo86zz1d0hNHtSc4b3Tks7bJGTMTyabsydQyOE,14191
|
|
5
|
-
sqlpyhelper/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
6
|
-
sqlpyhelper-0.1.6.dist-info/licenses/LICENSE,sha256=9XzXxZ_8mWFM9-2TlqyE3L69zvRf4VPY_xIzSj5iU-g,1076
|
|
7
|
-
sqlpyhelper-0.1.6.dist-info/METADATA,sha256=JA0zdZYH5pceNjom3LQQPuUhfGe9kH_6RjXBrKiOi4A,9763
|
|
8
|
-
sqlpyhelper-0.1.6.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
|
|
9
|
-
sqlpyhelper-0.1.6.dist-info/entry_points.txt,sha256=uAzSqwkAbbJqQUKHlPNwOebTJVA0FqkOvn2CRP6xSz8,52
|
|
10
|
-
sqlpyhelper-0.1.6.dist-info/top_level.txt,sha256=FrLqTmqTGDa8jHnnf2ZVkYO-gFvLXX9QonpUCE6wKGs,12
|
|
11
|
-
sqlpyhelper-0.1.6.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|