sqlutilpy 0.22.0__tar.gz → 0.24.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.
- {sqlutilpy-0.22.0/src/sqlutilpy.egg-info → sqlutilpy-0.24.0}/PKG-INFO +5 -4
- {sqlutilpy-0.22.0 → sqlutilpy-0.24.0}/pyproject.toml +3 -2
- {sqlutilpy-0.22.0 → sqlutilpy-0.24.0}/src/sqlutilpy/sqlutil.py +45 -54
- sqlutilpy-0.24.0/src/sqlutilpy/version.py +1 -0
- {sqlutilpy-0.22.0 → sqlutilpy-0.24.0/src/sqlutilpy.egg-info}/PKG-INFO +5 -4
- sqlutilpy-0.24.0/src/sqlutilpy.egg-info/requires.txt +4 -0
- {sqlutilpy-0.22.0 → sqlutilpy-0.24.0}/tests/test_pg.py +35 -9
- {sqlutilpy-0.22.0 → sqlutilpy-0.24.0}/tests/test_sqlite.py +0 -5
- sqlutilpy-0.22.0/src/sqlutilpy/version.py +0 -1
- sqlutilpy-0.22.0/src/sqlutilpy.egg-info/requires.txt +0 -3
- {sqlutilpy-0.22.0 → sqlutilpy-0.24.0}/LICENSE.txt +0 -0
- {sqlutilpy-0.22.0 → sqlutilpy-0.24.0}/MANIFEST.in +0 -0
- {sqlutilpy-0.22.0 → sqlutilpy-0.24.0}/README.md +0 -0
- {sqlutilpy-0.22.0 → sqlutilpy-0.24.0}/setup.cfg +0 -0
- {sqlutilpy-0.22.0 → sqlutilpy-0.24.0}/src/sqlutilpy/__init__.py +0 -0
- {sqlutilpy-0.22.0 → sqlutilpy-0.24.0}/src/sqlutilpy.egg-info/SOURCES.txt +0 -0
- {sqlutilpy-0.22.0 → sqlutilpy-0.24.0}/src/sqlutilpy.egg-info/dependency_links.txt +0 -0
- {sqlutilpy-0.22.0 → sqlutilpy-0.24.0}/src/sqlutilpy.egg-info/top_level.txt +0 -0
- {sqlutilpy-0.22.0 → sqlutilpy-0.24.0}/tests/killer.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
2
|
Name: sqlutilpy
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.24.0
|
|
4
4
|
Summary: Database query code returning numpy arrays
|
|
5
5
|
Author-email: "Sergey E. Koposov" <skoposov@ed.ac.uk>
|
|
6
6
|
License: BSD
|
|
@@ -9,12 +9,13 @@ Keywords: numpy postgresql query sql sqlite array
|
|
|
9
9
|
Classifier: Development Status :: 3 - Alpha
|
|
10
10
|
Classifier: License :: OSI Approved :: BSD License
|
|
11
11
|
Classifier: Topic :: Utilities
|
|
12
|
-
Requires-Python: >=3.
|
|
12
|
+
Requires-Python: >=3.8
|
|
13
13
|
Description-Content-Type: text/markdown
|
|
14
14
|
License-File: LICENSE.txt
|
|
15
15
|
Requires-Dist: numpy
|
|
16
|
-
Requires-Dist:
|
|
16
|
+
Requires-Dist: psycopg[binary]
|
|
17
17
|
Requires-Dist: numpydoc
|
|
18
|
+
Requires-Dist: numpy
|
|
18
19
|
|
|
19
20
|
[](https://github.com/segasai/sqlutilpy/actions)
|
|
20
21
|
[](http://sqlutilpy.readthedocs.io/en/latest/?badge=latest)
|
|
@@ -7,10 +7,11 @@ authors = [
|
|
|
7
7
|
]
|
|
8
8
|
dependencies = [
|
|
9
9
|
"numpy",
|
|
10
|
-
"
|
|
10
|
+
"psycopg[binary]",
|
|
11
11
|
"numpydoc",
|
|
12
|
+
"numpy\n"
|
|
12
13
|
]
|
|
13
|
-
requires-python = ">=3.
|
|
14
|
+
requires-python = ">=3.8"
|
|
14
15
|
readme = "README.md"
|
|
15
16
|
license = {text = "BSD"}
|
|
16
17
|
keywords = ["numpy postgresql query sql sqlite array"]
|
|
@@ -3,13 +3,11 @@
|
|
|
3
3
|
from __future__ import print_function
|
|
4
4
|
import numpy
|
|
5
5
|
import numpy as np
|
|
6
|
-
import
|
|
6
|
+
import psycopg
|
|
7
7
|
import threading
|
|
8
8
|
import collections
|
|
9
9
|
import warnings
|
|
10
10
|
from numpy.core import numeric as sb
|
|
11
|
-
from select import select
|
|
12
|
-
from psycopg2.extensions import POLL_OK, POLL_READ, POLL_WRITE
|
|
13
11
|
|
|
14
12
|
try:
|
|
15
13
|
import astropy.table as atpy
|
|
@@ -22,7 +20,6 @@ except ImportError:
|
|
|
22
20
|
# pandas is not installed
|
|
23
21
|
pandas = None
|
|
24
22
|
|
|
25
|
-
from io import BytesIO as StringIO
|
|
26
23
|
import queue
|
|
27
24
|
|
|
28
25
|
_WAIT_SELECT_TIMEOUT = 10
|
|
@@ -37,31 +34,6 @@ class SqlUtilException(Exception):
|
|
|
37
34
|
pass
|
|
38
35
|
|
|
39
36
|
|
|
40
|
-
def __wait_select_inter(conn):
|
|
41
|
-
""" Make the queries interruptible by Ctrl-C
|
|
42
|
-
|
|
43
|
-
Taken from http://initd.org/psycopg/articles/2014/07/20/cancelling-postgresql-statements-python/ # noqa
|
|
44
|
-
"""
|
|
45
|
-
while True:
|
|
46
|
-
try:
|
|
47
|
-
state = conn.poll()
|
|
48
|
-
if state == POLL_OK:
|
|
49
|
-
break
|
|
50
|
-
elif state == POLL_READ:
|
|
51
|
-
select([conn.fileno()], [], [], _WAIT_SELECT_TIMEOUT)
|
|
52
|
-
elif state == POLL_WRITE:
|
|
53
|
-
select([], [conn.fileno()], [], _WAIT_SELECT_TIMEOUT)
|
|
54
|
-
else:
|
|
55
|
-
raise conn.OperationalError("bad state from poll: %s" % state)
|
|
56
|
-
except KeyboardInterrupt:
|
|
57
|
-
conn.cancel()
|
|
58
|
-
# the loop will be broken by a server error
|
|
59
|
-
continue
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
psycopg2.extensions.set_wait_callback(__wait_select_inter)
|
|
63
|
-
|
|
64
|
-
|
|
65
37
|
def getConnection(db=None,
|
|
66
38
|
driver=None,
|
|
67
39
|
user=None,
|
|
@@ -80,7 +52,7 @@ def getConnection(db=None,
|
|
|
80
52
|
The name of the database (in case of PostgreSQL) or filename in
|
|
81
53
|
case of sqlite db
|
|
82
54
|
driver : string
|
|
83
|
-
The db driver (either '
|
|
55
|
+
The db driver (either 'psycopg' or 'sqlite3')
|
|
84
56
|
user : string, optional
|
|
85
57
|
Username
|
|
86
58
|
password: string, optional
|
|
@@ -99,6 +71,10 @@ def getConnection(db=None,
|
|
|
99
71
|
|
|
100
72
|
"""
|
|
101
73
|
if driver == 'psycopg2':
|
|
74
|
+
warnings.warn(
|
|
75
|
+
'psycopg2 driver is not supported anymore using psycopg instead')
|
|
76
|
+
driver = 'psycopg'
|
|
77
|
+
if driver == 'psycopg':
|
|
102
78
|
conn_dict = dict()
|
|
103
79
|
if db is not None:
|
|
104
80
|
conn_dict['dbname'] = db
|
|
@@ -110,7 +86,7 @@ def getConnection(db=None,
|
|
|
110
86
|
conn_dict['user'] = user
|
|
111
87
|
if password is not None:
|
|
112
88
|
conn_dict['password'] = password
|
|
113
|
-
conn =
|
|
89
|
+
conn = psycopg.connect(**conn_dict)
|
|
114
90
|
elif driver == 'sqlite3':
|
|
115
91
|
import sqlite3
|
|
116
92
|
if timeout is None:
|
|
@@ -126,6 +102,10 @@ def getCursor(conn, driver=None, preamb=None, notNamed=False):
|
|
|
126
102
|
Retrieve the database cursor
|
|
127
103
|
"""
|
|
128
104
|
if driver == 'psycopg2':
|
|
105
|
+
warnings.warn(
|
|
106
|
+
'psycopg2 driver is not supported anymore using psycopg instead')
|
|
107
|
+
driver = 'psycopg'
|
|
108
|
+
if driver == 'psycopg':
|
|
129
109
|
cur = conn.cursor()
|
|
130
110
|
if preamb is not None:
|
|
131
111
|
cur.execute(preamb)
|
|
@@ -267,7 +247,7 @@ def __getDType(row, typeCodes, strLength):
|
|
|
267
247
|
def get(query,
|
|
268
248
|
params=None,
|
|
269
249
|
db="wsdb",
|
|
270
|
-
driver="
|
|
250
|
+
driver="psycopg",
|
|
271
251
|
user=None,
|
|
272
252
|
password=None,
|
|
273
253
|
host=None,
|
|
@@ -304,7 +284,7 @@ def get(query,
|
|
|
304
284
|
db : string
|
|
305
285
|
The name of the database
|
|
306
286
|
driver : string, optional
|
|
307
|
-
The sql driver to be used (
|
|
287
|
+
The sql driver to be used (psycopg or sqlite3)
|
|
308
288
|
user : string, optional
|
|
309
289
|
User name for the DB connection
|
|
310
290
|
password : string, optional
|
|
@@ -359,26 +339,38 @@ def get(query,
|
|
|
359
339
|
proc = None
|
|
360
340
|
colNames = []
|
|
361
341
|
if driver == 'psycopg2':
|
|
342
|
+
warnings.warn('psycopg2 driver is not supported anymore. '
|
|
343
|
+
'We using psycopg instead')
|
|
344
|
+
driver = 'psycopg'
|
|
345
|
+
if driver == 'psycopg':
|
|
362
346
|
try:
|
|
363
|
-
while
|
|
347
|
+
while True:
|
|
364
348
|
# Iterating over the cursor, retrieving batches of results
|
|
365
349
|
# and then sending them for conversion
|
|
366
350
|
tups = cur.fetchmany()
|
|
367
351
|
desc = cur.description
|
|
368
352
|
|
|
353
|
+
# If the is just the start we need to launch the
|
|
354
|
+
# thread doing the conversion
|
|
355
|
+
no_results = tups == []
|
|
356
|
+
if nrec == 0:
|
|
357
|
+
typeCodes = [_tmp.type_code for _tmp in desc]
|
|
358
|
+
colNames = [_tmp.name for _tmp in cur.description]
|
|
359
|
+
|
|
369
360
|
# No more data
|
|
370
|
-
if
|
|
361
|
+
if no_results:
|
|
362
|
+
dtype = __getDType([None] * len(typeCodes), typeCodes,
|
|
363
|
+
strLength)
|
|
371
364
|
break
|
|
372
365
|
|
|
366
|
+
dtype = __getDType(tups[0], typeCodes, strLength)
|
|
367
|
+
|
|
373
368
|
# Send the new batch for conversion
|
|
374
369
|
qIn.put(tups)
|
|
375
370
|
|
|
376
371
|
# If the is just the start we need to launch the
|
|
377
372
|
# thread doing the conversion
|
|
378
373
|
if nrec == 0:
|
|
379
|
-
typeCodes = [_tmp.type_code for _tmp in desc]
|
|
380
|
-
colNames = [_tmp.name for _tmp in cur.description]
|
|
381
|
-
dtype = __getDType(tups[0], typeCodes, strLength)
|
|
382
374
|
proc = threading.Thread(target=__converter,
|
|
383
375
|
args=(qIn, qOut, endEvent,
|
|
384
376
|
dtype, intNullVal))
|
|
@@ -473,7 +465,7 @@ def get(query,
|
|
|
473
465
|
def execute(query,
|
|
474
466
|
params=None,
|
|
475
467
|
db='wsdb',
|
|
476
|
-
driver="
|
|
468
|
+
driver="psycopg",
|
|
477
469
|
user=None,
|
|
478
470
|
password=None,
|
|
479
471
|
host=None,
|
|
@@ -493,7 +485,7 @@ def execute(query,
|
|
|
493
485
|
db : string
|
|
494
486
|
Database name
|
|
495
487
|
driver : string
|
|
496
|
-
Driver for the DB connection ('
|
|
488
|
+
Driver for the DB connection ('psycopg' or 'sqlite3')
|
|
497
489
|
user : string, optional
|
|
498
490
|
user name for the DB connection
|
|
499
491
|
password : string, optional
|
|
@@ -542,7 +534,7 @@ def __create_schema(tableName, arrays, names, temp=False):
|
|
|
542
534
|
(np.uint64, 'bigint'), (np.int16, 'smallint'),
|
|
543
535
|
(np.uint8, 'smallint'), (np.int8, 'smallint'),
|
|
544
536
|
(np.float32, 'real'), (np.float64, 'double precision'),
|
|
545
|
-
(np.
|
|
537
|
+
(np.bytes_, 'varchar'), (np.str_, 'varchar'),
|
|
546
538
|
(np.bool_, 'boolean'), (np.datetime64, 'timestamp')])
|
|
547
539
|
if temp:
|
|
548
540
|
temp = 'temporary'
|
|
@@ -568,7 +560,7 @@ def __print_arrays(arrays, f, delimiter=' '):
|
|
|
568
560
|
format_dict = dict([(np.int32, '%d'), (np.int64, '%d'), (np.int16, '%d'),
|
|
569
561
|
(np.int8, '%d'), (np.uint8, '%d'),
|
|
570
562
|
(np.float32, '%.18e'), (np.float64, '%.18e'),
|
|
571
|
-
(np.
|
|
563
|
+
(np.bytes_, '%s'), (np.str_, '%s'),
|
|
572
564
|
(np.datetime64, '%s'), (np.bool_, '%d')])
|
|
573
565
|
fmts = []
|
|
574
566
|
array_mode = False
|
|
@@ -626,7 +618,7 @@ def upload(tableName,
|
|
|
626
618
|
arrays,
|
|
627
619
|
names=None,
|
|
628
620
|
db="wsdb",
|
|
629
|
-
driver="
|
|
621
|
+
driver="psycopg",
|
|
630
622
|
user=None,
|
|
631
623
|
password=None,
|
|
632
624
|
host=None,
|
|
@@ -653,7 +645,7 @@ def upload(tableName,
|
|
|
653
645
|
db: string
|
|
654
646
|
Databas name
|
|
655
647
|
driver: string
|
|
656
|
-
Python database driver "
|
|
648
|
+
Python database driver "psycopg",
|
|
657
649
|
user: string,
|
|
658
650
|
password: string
|
|
659
651
|
host: string
|
|
@@ -743,18 +735,17 @@ table/pandas/dictionary or provide a separate list of arrays and their names')
|
|
|
743
735
|
cur.execute(query1)
|
|
744
736
|
nsplit = 100000
|
|
745
737
|
N = len(arrays[0])
|
|
738
|
+
names = ','.join(names)
|
|
746
739
|
for i in range(0, N, nsplit):
|
|
747
|
-
f = StringIO()
|
|
748
|
-
__print_arrays([_[i:i + nsplit] for _ in arrays],
|
|
749
|
-
f,
|
|
750
|
-
delimiter=delimiter)
|
|
751
|
-
f.seek(0)
|
|
752
740
|
try:
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
741
|
+
with cur.copy(f'''copy {tableName}({names}) from stdin
|
|
742
|
+
with delimiter '{delimiter}' ''') as copy:
|
|
743
|
+
__print_arrays([_[i:i + nsplit] for _ in arrays],
|
|
744
|
+
copy,
|
|
745
|
+
delimiter=delimiter)
|
|
746
|
+
|
|
756
747
|
finally:
|
|
757
|
-
|
|
748
|
+
pass
|
|
758
749
|
except BaseException:
|
|
759
750
|
failure_cleanup(conn, connSupplied)
|
|
760
751
|
raise
|
|
@@ -772,7 +763,7 @@ def local_join(query,
|
|
|
772
763
|
arrays,
|
|
773
764
|
names,
|
|
774
765
|
db=None,
|
|
775
|
-
driver="
|
|
766
|
+
driver="psycopg",
|
|
776
767
|
user=None,
|
|
777
768
|
password=None,
|
|
778
769
|
host=None,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = '0.24.0'
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
2
|
Name: sqlutilpy
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.24.0
|
|
4
4
|
Summary: Database query code returning numpy arrays
|
|
5
5
|
Author-email: "Sergey E. Koposov" <skoposov@ed.ac.uk>
|
|
6
6
|
License: BSD
|
|
@@ -9,12 +9,13 @@ Keywords: numpy postgresql query sql sqlite array
|
|
|
9
9
|
Classifier: Development Status :: 3 - Alpha
|
|
10
10
|
Classifier: License :: OSI Approved :: BSD License
|
|
11
11
|
Classifier: Topic :: Utilities
|
|
12
|
-
Requires-Python: >=3.
|
|
12
|
+
Requires-Python: >=3.8
|
|
13
13
|
Description-Content-Type: text/markdown
|
|
14
14
|
License-File: LICENSE.txt
|
|
15
15
|
Requires-Dist: numpy
|
|
16
|
-
Requires-Dist:
|
|
16
|
+
Requires-Dist: psycopg[binary]
|
|
17
17
|
Requires-Dist: numpydoc
|
|
18
|
+
Requires-Dist: numpy
|
|
18
19
|
|
|
19
20
|
[](https://github.com/segasai/sqlutilpy/actions)
|
|
20
21
|
[](http://sqlutilpy.readthedocs.io/en/latest/?badge=latest)
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import pytest
|
|
2
2
|
import string
|
|
3
3
|
import os
|
|
4
|
-
import
|
|
4
|
+
import psycopg
|
|
5
5
|
import numpy as np
|
|
6
6
|
import sqlutilpy as sqlutil
|
|
7
7
|
import time
|
|
@@ -16,7 +16,7 @@ PG_PASS = os.environ['SQLUTIL_TEST_PG_PASS']
|
|
|
16
16
|
def getrand(N, float=False):
|
|
17
17
|
# simple deterministic pseudo-random number generator
|
|
18
18
|
a, c = 1103515245, 12345
|
|
19
|
-
m = 2
|
|
19
|
+
m = 2**31
|
|
20
20
|
arr = np.zeros(N)
|
|
21
21
|
arr[0] = 1
|
|
22
22
|
for i in range(1, N):
|
|
@@ -37,8 +37,8 @@ def getconn():
|
|
|
37
37
|
|
|
38
38
|
@pytest.fixture
|
|
39
39
|
def setup():
|
|
40
|
-
conn =
|
|
41
|
-
|
|
40
|
+
conn = psycopg.connect('dbname=%s user=%s host=%s password=%s' %
|
|
41
|
+
(PG_DB, PG_USER, PG_HOST, PG_PASS))
|
|
42
42
|
cur = conn.cursor()
|
|
43
43
|
cur.execute('''
|
|
44
44
|
create unlogged table sqlutil_test (sicol smallint, intcol int,
|
|
@@ -123,11 +123,14 @@ def test_nocommit(setup):
|
|
|
123
123
|
|
|
124
124
|
def test_local_join(setup):
|
|
125
125
|
kw, conn = setup
|
|
126
|
+
N = 1000
|
|
127
|
+
rands = np.random.uniform(size=N)
|
|
126
128
|
R, = sqlutil.local_join(
|
|
127
129
|
'''
|
|
128
|
-
select
|
|
129
|
-
where s.sicol = m.id''', 'mytab', [np.arange(
|
|
130
|
-
|
|
130
|
+
select xf from sqlutil_test as s, mytab as m
|
|
131
|
+
where s.sicol = m.id''', 'mytab', [np.arange(N), rands], ['id', 'xf'],
|
|
132
|
+
**kw)
|
|
133
|
+
assert (len(R) == 2)
|
|
131
134
|
|
|
132
135
|
|
|
133
136
|
def test_big(setup):
|
|
@@ -252,6 +255,12 @@ def test_get_dict(setup):
|
|
|
252
255
|
**kw)
|
|
253
256
|
for i, k in enumerate(cols.split(',')):
|
|
254
257
|
assert ((Rd[k] == R0[i]).all())
|
|
258
|
+
Rempty = sqlutil.get('select %s from sqlutil_test where sicol<-10000' %
|
|
259
|
+
(cols, ),
|
|
260
|
+
asDict=True,
|
|
261
|
+
**kw)
|
|
262
|
+
for i, k in enumerate(cols.split(',')):
|
|
263
|
+
assert k in Rempty
|
|
255
264
|
|
|
256
265
|
|
|
257
266
|
def test_get_dict_rep(setup):
|
|
@@ -392,10 +401,27 @@ def test_upload(setup):
|
|
|
392
401
|
# try the weird names
|
|
393
402
|
sqlutil.upload(mytab1, (xi16, xi32, xi64, xf32, xf64, xbool),
|
|
394
403
|
('xi 16', 'xi(32)', 'xi[64]', 'xf32', 'xf64', 'xbool'),
|
|
395
|
-
|
|
404
|
+
temp=True,
|
|
405
|
+
conn=conn)
|
|
396
406
|
yi16, yi32, yi64, yf32, yf64, ybool = sqlutil.get(
|
|
397
407
|
'''select xi_16,xi_32_,xi_64_,xf32,xf64,xbool from %s''' % (mytab1),
|
|
398
|
-
|
|
408
|
+
conn=conn)
|
|
409
|
+
|
|
410
|
+
|
|
411
|
+
def test_upload_big(setup):
|
|
412
|
+
kw, conn = setup
|
|
413
|
+
mytab = 'sqlutil_test_tab_big'
|
|
414
|
+
nrows = 1_000_000
|
|
415
|
+
xi = np.arange(nrows, dtype=np.int32)
|
|
416
|
+
xf = getrand(nrows, True)
|
|
417
|
+
sqlutil.upload(mytab, (xi, xf), ('xi', 'xf'), **kw)
|
|
418
|
+
yi, yf = sqlutil.get('''select xi,xf from %s order by xi''' % (mytab),
|
|
419
|
+
**kw)
|
|
420
|
+
try:
|
|
421
|
+
assert ((xi == yi).all())
|
|
422
|
+
assert (np.allclose(xf, yf))
|
|
423
|
+
finally:
|
|
424
|
+
sqlutil.execute('drop table %s' % mytab, **kw)
|
|
399
425
|
|
|
400
426
|
|
|
401
427
|
def test_upload_array(setup):
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = '0.22.0'
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|