sqlutilpy 0.23.0__tar.gz → 0.25.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.
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: sqlutilpy
3
- Version: 0.23.0
3
+ Version: 0.25.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
@@ -16,6 +16,7 @@ Requires-Dist: numpy
16
16
  Requires-Dist: psycopg[binary]
17
17
  Requires-Dist: numpydoc
18
18
  Requires-Dist: numpy
19
+ Dynamic: license-file
19
20
 
20
21
  [![Build Status](https://github.com/segasai/sqlutilpy/workflows/Testing/badge.svg)](https://github.com/segasai/sqlutilpy/actions)
21
22
  [![Documentation Status](https://readthedocs.org/projects/sqlutilpy/badge/?version=latest)](http://sqlutilpy.readthedocs.io/en/latest/?badge=latest)
@@ -25,8 +26,8 @@ Requires-Dist: numpy
25
26
  # sqlutilpy
26
27
  Python module to query SQL databases and return numpy arrays, upload
27
28
  tables and run join queries involving local arrays and the tables in the DB.
28
- This module is optimized to be able to deal efficiently with query results with millions of rows.
29
- The module only works with PostgreSQL, SQLite and DuckDB databases.
29
+ This module is optimized to deal efficiently with query results with millions of rows.
30
+ The module works with PostgreSQL, SQLite and DuckDB databases.
30
31
 
31
32
  The full documentation is available [here](http://sqlutilpy.readthedocs.io/en/latest/)
32
33
 
@@ -40,8 +41,9 @@ pip install sqlutilpy
40
41
  ```
41
42
  ## Authentication
42
43
 
43
- Throughout this readme, I will assume that the .pgpass file ( https://www.postgresql.org/docs/11/libpq-pgpass.html )
44
- has been created with your login/password details for Postgresql. If that is not the case, all of the
44
+ Throughout this readme, I will assume that if you are using PostgreSQL, then
45
+ the .pgpass file ( https://www.postgresql.org/docs/11/libpq-pgpass.html )
46
+ has been created with your login/password details for Postgresql. If that is not the case, many of the
45
47
  commands given below will also need user='....' and password='...' options
46
48
 
47
49
  ## Connection information
@@ -6,8 +6,8 @@
6
6
  # sqlutilpy
7
7
  Python module to query SQL databases and return numpy arrays, upload
8
8
  tables and run join queries involving local arrays and the tables in the DB.
9
- This module is optimized to be able to deal efficiently with query results with millions of rows.
10
- The module only works with PostgreSQL, SQLite and DuckDB databases.
9
+ This module is optimized to deal efficiently with query results with millions of rows.
10
+ The module works with PostgreSQL, SQLite and DuckDB databases.
11
11
 
12
12
  The full documentation is available [here](http://sqlutilpy.readthedocs.io/en/latest/)
13
13
 
@@ -21,8 +21,9 @@ pip install sqlutilpy
21
21
  ```
22
22
  ## Authentication
23
23
 
24
- Throughout this readme, I will assume that the .pgpass file ( https://www.postgresql.org/docs/11/libpq-pgpass.html )
25
- has been created with your login/password details for Postgresql. If that is not the case, all of the
24
+ Throughout this readme, I will assume that if you are using PostgreSQL, then
25
+ the .pgpass file ( https://www.postgresql.org/docs/11/libpq-pgpass.html )
26
+ has been created with your login/password details for Postgresql. If that is not the case, many of the
26
27
  commands given below will also need user='....' and password='...' options
27
28
 
28
29
  ## Connection information
@@ -92,6 +92,9 @@ def getConnection(db=None,
92
92
  if timeout is None:
93
93
  timeout = 5
94
94
  conn = sqlite3.connect(db, timeout=timeout)
95
+ elif driver == 'duckdb':
96
+ import duckdb
97
+ conn = duckdb.connect(db)
95
98
  else:
96
99
  raise Exception("Unknown driver")
97
100
  return conn
@@ -137,12 +140,12 @@ def __fromrecords(recList, dtype=None, intNullVal=None):
137
140
  """
138
141
 
139
142
  shape = None
140
- descr = sb.dtype((np.core.records.record, dtype))
143
+ descr = sb.dtype((np.record, dtype))
141
144
  try:
142
145
  retval = sb.array(recList, dtype=descr)
143
146
  except TypeError: # list of lists instead of list of tuples
144
147
  shape = (len(recList), )
145
- _array = np.core.records.recarray(shape, descr)
148
+ _array = np.recarray(shape, descr)
146
149
  try:
147
150
  for k in range(_array.size):
148
151
  _array[k] = tuple(recList[k])
@@ -170,7 +173,7 @@ def __fromrecords(recList, dtype=None, intNullVal=None):
170
173
  if shape is not None and retval.shape != shape:
171
174
  retval.shape = shape
172
175
 
173
- res = retval.view(numpy.core.records.recarray)
176
+ res = retval.view(numpy.recarray)
174
177
 
175
178
  return res
176
179
 
@@ -210,6 +213,7 @@ def __getDType(row, typeCodes, strLength):
210
213
  1022: 'f8',
211
214
  1700: 'f8', # numeric
212
215
  1114: '<M8[us]', # timestamp
216
+ 1184: '<M8[us]', # timestamp with timezone
213
217
  1082: '<M8[us]', # date
214
218
  25: '|U%d',
215
219
  1042: '|U%d', # character()
@@ -339,31 +343,38 @@ def get(query,
339
343
  proc = None
340
344
  colNames = []
341
345
  if driver == 'psycopg2':
342
- warnings.warn(
343
- 'psycopg2 driver is not supported anymore using psycopg instead'
344
- )
346
+ warnings.warn('psycopg2 driver is not supported anymore. '
347
+ 'We using psycopg instead')
345
348
  driver = 'psycopg'
346
349
  if driver == 'psycopg':
347
350
  try:
348
- while (True):
351
+ while True:
349
352
  # Iterating over the cursor, retrieving batches of results
350
353
  # and then sending them for conversion
351
354
  tups = cur.fetchmany()
352
355
  desc = cur.description
353
356
 
357
+ # If the is just the start we need to launch the
358
+ # thread doing the conversion
359
+ no_results = tups == []
360
+ if nrec == 0:
361
+ typeCodes = [_tmp.type_code for _tmp in desc]
362
+ colNames = [_tmp.name for _tmp in cur.description]
363
+
354
364
  # No more data
355
- if tups == []:
365
+ if no_results:
366
+ dtype = __getDType([None] * len(typeCodes), typeCodes,
367
+ strLength)
356
368
  break
357
369
 
370
+ dtype = __getDType(tups[0], typeCodes, strLength)
371
+
358
372
  # Send the new batch for conversion
359
373
  qIn.put(tups)
360
374
 
361
375
  # If the is just the start we need to launch the
362
376
  # thread doing the conversion
363
377
  if nrec == 0:
364
- typeCodes = [_tmp.type_code for _tmp in desc]
365
- colNames = [_tmp.name for _tmp in cur.description]
366
- dtype = __getDType(tups[0], typeCodes, strLength)
367
378
  proc = threading.Thread(target=__converter,
368
379
  args=(qIn, qOut, endEvent,
369
380
  dtype, intNullVal))
@@ -416,14 +427,14 @@ def get(query,
416
427
  tups = cur.fetchall()
417
428
  colNames = [_tmp[0] for _tmp in cur.description]
418
429
  if len(tups) > 0:
419
- res = numpy.core.records.array(tups)
430
+ res = numpy.rec.array(tups)
420
431
  else:
421
432
  return [[]] * len(cur.description)
422
433
  elif driver == 'duckdb':
423
434
  tups = cur.fetchall()
424
435
  colNames = [_tmp[0] for _tmp in cur.description]
425
436
  if len(tups) > 0:
426
- res = numpy.core.records.array(tups)
437
+ res = numpy.rec.array(tups)
427
438
  else:
428
439
  return [[]] * len(cur.description)
429
440
 
@@ -731,9 +742,8 @@ table/pandas/dictionary or provide a separate list of arrays and their names')
731
742
  names = ','.join(names)
732
743
  for i in range(0, N, nsplit):
733
744
  try:
734
- with cur.copy(
735
- f'''copy {tableName}({names}) from stdin with delimiter '{delimiter}' '''
736
- ) as copy:
745
+ with cur.copy(f'''copy {tableName}({names}) from stdin
746
+ with delimiter '{delimiter}' ''') as copy:
737
747
  __print_arrays([_[i:i + nsplit] for _ in arrays],
738
748
  copy,
739
749
  delimiter=delimiter)
@@ -0,0 +1 @@
1
+ __version__ = '0.25.0'
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: sqlutilpy
3
- Version: 0.23.0
3
+ Version: 0.25.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
@@ -16,6 +16,7 @@ Requires-Dist: numpy
16
16
  Requires-Dist: psycopg[binary]
17
17
  Requires-Dist: numpydoc
18
18
  Requires-Dist: numpy
19
+ Dynamic: license-file
19
20
 
20
21
  [![Build Status](https://github.com/segasai/sqlutilpy/workflows/Testing/badge.svg)](https://github.com/segasai/sqlutilpy/actions)
21
22
  [![Documentation Status](https://readthedocs.org/projects/sqlutilpy/badge/?version=latest)](http://sqlutilpy.readthedocs.io/en/latest/?badge=latest)
@@ -25,8 +26,8 @@ Requires-Dist: numpy
25
26
  # sqlutilpy
26
27
  Python module to query SQL databases and return numpy arrays, upload
27
28
  tables and run join queries involving local arrays and the tables in the DB.
28
- This module is optimized to be able to deal efficiently with query results with millions of rows.
29
- The module only works with PostgreSQL, SQLite and DuckDB databases.
29
+ This module is optimized to deal efficiently with query results with millions of rows.
30
+ The module works with PostgreSQL, SQLite and DuckDB databases.
30
31
 
31
32
  The full documentation is available [here](http://sqlutilpy.readthedocs.io/en/latest/)
32
33
 
@@ -40,8 +41,9 @@ pip install sqlutilpy
40
41
  ```
41
42
  ## Authentication
42
43
 
43
- Throughout this readme, I will assume that the .pgpass file ( https://www.postgresql.org/docs/11/libpq-pgpass.html )
44
- has been created with your login/password details for Postgresql. If that is not the case, all of the
44
+ Throughout this readme, I will assume that if you are using PostgreSQL, then
45
+ the .pgpass file ( https://www.postgresql.org/docs/11/libpq-pgpass.html )
46
+ has been created with your login/password details for Postgresql. If that is not the case, many of the
45
47
  commands given below will also need user='....' and password='...' options
46
48
 
47
49
  ## Connection information
@@ -11,5 +11,6 @@ src/sqlutilpy.egg-info/dependency_links.txt
11
11
  src/sqlutilpy.egg-info/requires.txt
12
12
  src/sqlutilpy.egg-info/top_level.txt
13
13
  tests/killer.py
14
+ tests/test_duckdb.py
14
15
  tests/test_pg.py
15
16
  tests/test_sqlite.py
@@ -0,0 +1,32 @@
1
+ import pytest
2
+ import os
3
+ import sqlutilpy as sqlutil
4
+ import duckdb
5
+
6
+
7
+ @pytest.fixture()
8
+ def setup():
9
+ fname = 'duck.db'
10
+ kw = dict(db=fname, driver='duckdb')
11
+ conn = duckdb.connect(fname)
12
+ cur = conn.cursor()
13
+ cur.execute('create table tmp (a int, b double precision)')
14
+ cur.execute('insert into tmp values(1,2), (2,3), (3,4), (4,5);')
15
+ conn.commit()
16
+ yield kw
17
+ os.unlink(fname)
18
+
19
+
20
+ def test_simple(setup):
21
+ a, b = sqlutil.get('select a,b from tmp', **setup)
22
+ assert (len(a) == 4)
23
+
24
+
25
+ def test_preamb(setup):
26
+ a, b = sqlutil.get('select a,b from tmp', preamb='select 1', **setup)
27
+ assert (len(a) == 4)
28
+
29
+
30
+ def test_empty(setup):
31
+ a, b = sqlutil.get('select a,b from tmp where a<0', **setup)
32
+ assert (len(a) == 0)
@@ -255,6 +255,12 @@ def test_get_dict(setup):
255
255
  **kw)
256
256
  for i, k in enumerate(cols.split(',')):
257
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
258
264
 
259
265
 
260
266
  def test_get_dict_rep(setup):
@@ -1 +0,0 @@
1
- __version__ = '0.23.0'
File without changes
File without changes
File without changes
File without changes
File without changes