sqlutilpy 0.24.0__tar.gz → 0.26.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.2
1
+ Metadata-Version: 2.4
2
2
  Name: sqlutilpy
3
- Version: 0.24.0
3
+ Version: 0.26.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,13 +41,14 @@ 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
45
- commands given below will also need user='....' and password='...' options
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
47
+ commands given below will also need user='....' and password='...' options.
46
48
 
47
49
  ## Connection information
48
50
 
49
- Most of the sqlutilpy commands require hostname, database name, user etc.
51
+ Most of the `sqlutilpy` commands require hostname, database name.
50
52
  If you don't want to always type it, you can use standard PostgreSQL environment variables
51
53
  like PGPORT, PGDATABASE, PGUSER, PGHOST for the port, database name, user name and hostname
52
54
  of the connection.
@@ -54,7 +56,8 @@ of the connection.
54
56
 
55
57
  ## Querying the database and retrieving the results
56
58
 
57
- This command will run the query and put the columns into variables ra,dec
59
+ This command will run the query and put the columns into variables ra,dec:
60
+
58
61
  ```python
59
62
  import sqlutilpy
60
63
  ra,dec = squtilpy.get('select ra,dec from mytable',
@@ -62,23 +65,28 @@ ra,dec = squtilpy.get('select ra,dec from mytable',
62
65
  db='THE_NAME_OF_MY_DB')
63
66
  ```
64
67
 
65
- By default sqlutilpy.get executes the query and returns the tuple with
66
- results. You can return the results as dictionary using asDict option.
68
+ By default `sqlutilpy.get` executes the query and returns the tuple with
69
+ arrays. One array for each column in the query result.
70
+ You can return the results as dictionary using `asDict` option.
67
71
 
68
72
  ## Uploading your arrays as column in a table
69
73
 
74
+ You can use `sqlutilpy.upload` to upload your arrays as columns in a table.
75
+
70
76
  ```python
71
77
  x = np.arange(10)
72
78
  y = x**.5
73
79
  sqlutilpy.upload('mytable',(x,y),('xcol','ycol'))
74
80
  ```
75
- This will create a table called mytable with columns xcol and ycol
81
+ This will create a table called `mytable` with columns `xcol` and `ycol`
76
82
 
77
83
  ## Join query involving your local data and the database table
78
84
 
79
- Imagine you have arrays myid and y and you want to to extract all the
80
- information from somebigtable for objects with id=myid. In principle
81
- you could upload the arrays in the DB and run a query, but local_join function does that for you.
85
+ Sometimes it is beneficial to run a join query involving your local data and the data in the database.
86
+
87
+ Imagine you have arrays `myid` and `y` and you want to extract all the
88
+ information from `somebigtable` for objects with `id=myid`. In principle,
89
+ you could upload the arrays in the DB and run a query, but `local_join` function does that for you.
82
90
 
83
91
  ```python
84
92
  myid = np.arange(10)
@@ -89,15 +97,14 @@ R=sqlutilpy.local_join('''select * from mytmptable as m,
89
97
  'mytmptable',(myid, y),('myid','ycol'))
90
98
  ```
91
99
 
92
- It executes a query as if you arrays were in mytmptable. (behind the scenes
93
- it uploads the data to the db and runs a query)
100
+ It executes a query as if your arrays were in `mytmptable`. What happens behind the scenes
101
+ is that it uploads the data to the database and runs a query against it.
94
102
 
95
103
  ## Keeping the connection open.
96
104
 
97
105
  Often it is beneficial to preserve an open connection to the database. You can do that if you first
98
- obtain the connection using sqlutilpy.getConnection() and then provide it directly
99
- to sqlutil.get() and friends using conn=conn argument
100
- ```python
106
+ obtain the connection using `sqlutilpy.getConnection()` and then provide it directly
107
+ to `sqlutil.get()` and similar commands using `conn=` keyword:
101
108
  conn = sqlutilpy.getConnection(db='mydb', user='meuser', password='something', host='hostname')
102
109
  R= sqlutilpy.get('select 1', conn=conn)
103
110
  R1= sqlutilpy.get('select 1', conn=conn)
@@ -105,5 +112,5 @@ R1= sqlutilpy.get('select 1', conn=conn)
105
112
 
106
113
  # How to cite the software
107
114
 
108
- If you use this package, please cite it through zenodo https://doi.org/10.5281/zenodo.6867957
115
+ If you use this package, please cite it through Zenodo https://doi.org/10.5281/zenodo.5160118
109
116
 
@@ -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,13 +21,14 @@ 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
26
- commands given below will also need user='....' and password='...' options
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
27
+ commands given below will also need user='....' and password='...' options.
27
28
 
28
29
  ## Connection information
29
30
 
30
- Most of the sqlutilpy commands require hostname, database name, user etc.
31
+ Most of the `sqlutilpy` commands require hostname, database name.
31
32
  If you don't want to always type it, you can use standard PostgreSQL environment variables
32
33
  like PGPORT, PGDATABASE, PGUSER, PGHOST for the port, database name, user name and hostname
33
34
  of the connection.
@@ -35,7 +36,8 @@ of the connection.
35
36
 
36
37
  ## Querying the database and retrieving the results
37
38
 
38
- This command will run the query and put the columns into variables ra,dec
39
+ This command will run the query and put the columns into variables ra,dec:
40
+
39
41
  ```python
40
42
  import sqlutilpy
41
43
  ra,dec = squtilpy.get('select ra,dec from mytable',
@@ -43,23 +45,28 @@ ra,dec = squtilpy.get('select ra,dec from mytable',
43
45
  db='THE_NAME_OF_MY_DB')
44
46
  ```
45
47
 
46
- By default sqlutilpy.get executes the query and returns the tuple with
47
- results. You can return the results as dictionary using asDict option.
48
+ By default `sqlutilpy.get` executes the query and returns the tuple with
49
+ arrays. One array for each column in the query result.
50
+ You can return the results as dictionary using `asDict` option.
48
51
 
49
52
  ## Uploading your arrays as column in a table
50
53
 
54
+ You can use `sqlutilpy.upload` to upload your arrays as columns in a table.
55
+
51
56
  ```python
52
57
  x = np.arange(10)
53
58
  y = x**.5
54
59
  sqlutilpy.upload('mytable',(x,y),('xcol','ycol'))
55
60
  ```
56
- This will create a table called mytable with columns xcol and ycol
61
+ This will create a table called `mytable` with columns `xcol` and `ycol`
57
62
 
58
63
  ## Join query involving your local data and the database table
59
64
 
60
- Imagine you have arrays myid and y and you want to to extract all the
61
- information from somebigtable for objects with id=myid. In principle
62
- you could upload the arrays in the DB and run a query, but local_join function does that for you.
65
+ Sometimes it is beneficial to run a join query involving your local data and the data in the database.
66
+
67
+ Imagine you have arrays `myid` and `y` and you want to extract all the
68
+ information from `somebigtable` for objects with `id=myid`. In principle,
69
+ you could upload the arrays in the DB and run a query, but `local_join` function does that for you.
63
70
 
64
71
  ```python
65
72
  myid = np.arange(10)
@@ -70,15 +77,14 @@ R=sqlutilpy.local_join('''select * from mytmptable as m,
70
77
  'mytmptable',(myid, y),('myid','ycol'))
71
78
  ```
72
79
 
73
- It executes a query as if you arrays were in mytmptable. (behind the scenes
74
- it uploads the data to the db and runs a query)
80
+ It executes a query as if your arrays were in `mytmptable`. What happens behind the scenes
81
+ is that it uploads the data to the database and runs a query against it.
75
82
 
76
83
  ## Keeping the connection open.
77
84
 
78
85
  Often it is beneficial to preserve an open connection to the database. You can do that if you first
79
- obtain the connection using sqlutilpy.getConnection() and then provide it directly
80
- to sqlutil.get() and friends using conn=conn argument
81
- ```python
86
+ obtain the connection using `sqlutilpy.getConnection()` and then provide it directly
87
+ to `sqlutil.get()` and similar commands using `conn=` keyword:
82
88
  conn = sqlutilpy.getConnection(db='mydb', user='meuser', password='something', host='hostname')
83
89
  R= sqlutilpy.get('select 1', conn=conn)
84
90
  R1= sqlutilpy.get('select 1', conn=conn)
@@ -86,5 +92,5 @@ R1= sqlutilpy.get('select 1', conn=conn)
86
92
 
87
93
  # How to cite the software
88
94
 
89
- If you use this package, please cite it through zenodo https://doi.org/10.5281/zenodo.6867957
95
+ If you use this package, please cite it through Zenodo https://doi.org/10.5281/zenodo.5160118
90
96
 
@@ -7,7 +7,6 @@ import psycopg
7
7
  import threading
8
8
  import collections
9
9
  import warnings
10
- from numpy.core import numeric as sb
11
10
 
12
11
  try:
13
12
  import astropy.table as atpy
@@ -92,6 +91,9 @@ def getConnection(db=None,
92
91
  if timeout is None:
93
92
  timeout = 5
94
93
  conn = sqlite3.connect(db, timeout=timeout)
94
+ elif driver == 'duckdb':
95
+ import duckdb
96
+ conn = duckdb.connect(db)
95
97
  else:
96
98
  raise Exception("Unknown driver")
97
99
  return conn
@@ -137,12 +139,12 @@ def __fromrecords(recList, dtype=None, intNullVal=None):
137
139
  """
138
140
 
139
141
  shape = None
140
- descr = sb.dtype((np.core.records.record, dtype))
142
+ descr = np.dtype((np.record, dtype))
141
143
  try:
142
- retval = sb.array(recList, dtype=descr)
144
+ retval = np.array(recList, dtype=descr)
143
145
  except TypeError: # list of lists instead of list of tuples
144
146
  shape = (len(recList), )
145
- _array = np.core.records.recarray(shape, descr)
147
+ _array = np.recarray(shape, descr)
146
148
  try:
147
149
  for k in range(_array.size):
148
150
  _array[k] = tuple(recList[k])
@@ -170,7 +172,7 @@ def __fromrecords(recList, dtype=None, intNullVal=None):
170
172
  if shape is not None and retval.shape != shape:
171
173
  retval.shape = shape
172
174
 
173
- res = retval.view(numpy.core.records.recarray)
175
+ res = retval.view(numpy.recarray)
174
176
 
175
177
  return res
176
178
 
@@ -210,6 +212,7 @@ def __getDType(row, typeCodes, strLength):
210
212
  1022: 'f8',
211
213
  1700: 'f8', # numeric
212
214
  1114: '<M8[us]', # timestamp
215
+ 1184: '<M8[us]', # timestamp with timezone
213
216
  1082: '<M8[us]', # date
214
217
  25: '|U%d',
215
218
  1042: '|U%d', # character()
@@ -407,7 +410,8 @@ def get(query,
407
410
  proc.join(0.2)
408
411
  # in the converter process
409
412
  if proc.is_alive():
410
- proc.terminate()
413
+ # could not kill
414
+ pass
411
415
  raise
412
416
  if proc is not None:
413
417
  proc.join()
@@ -423,14 +427,14 @@ def get(query,
423
427
  tups = cur.fetchall()
424
428
  colNames = [_tmp[0] for _tmp in cur.description]
425
429
  if len(tups) > 0:
426
- res = numpy.core.records.array(tups)
430
+ res = numpy.rec.array(tups)
427
431
  else:
428
432
  return [[]] * len(cur.description)
429
433
  elif driver == 'duckdb':
430
434
  tups = cur.fetchall()
431
435
  colNames = [_tmp[0] for _tmp in cur.description]
432
436
  if len(tups) > 0:
433
- res = numpy.core.records.array(tups)
437
+ res = numpy.rec.array(tups)
434
438
  else:
435
439
  return [[]] * len(cur.description)
436
440
 
@@ -735,7 +739,7 @@ table/pandas/dictionary or provide a separate list of arrays and their names')
735
739
  cur.execute(query1)
736
740
  nsplit = 100000
737
741
  N = len(arrays[0])
738
- names = ','.join(names)
742
+ names = ','.join(['"%s"' % _ for _ in names])
739
743
  for i in range(0, N, nsplit):
740
744
  try:
741
745
  with cur.copy(f'''copy {tableName}({names}) from stdin
@@ -0,0 +1 @@
1
+ __version__ = '0.26.0'
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.2
1
+ Metadata-Version: 2.4
2
2
  Name: sqlutilpy
3
- Version: 0.24.0
3
+ Version: 0.26.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,13 +41,14 @@ 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
45
- commands given below will also need user='....' and password='...' options
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
47
+ commands given below will also need user='....' and password='...' options.
46
48
 
47
49
  ## Connection information
48
50
 
49
- Most of the sqlutilpy commands require hostname, database name, user etc.
51
+ Most of the `sqlutilpy` commands require hostname, database name.
50
52
  If you don't want to always type it, you can use standard PostgreSQL environment variables
51
53
  like PGPORT, PGDATABASE, PGUSER, PGHOST for the port, database name, user name and hostname
52
54
  of the connection.
@@ -54,7 +56,8 @@ of the connection.
54
56
 
55
57
  ## Querying the database and retrieving the results
56
58
 
57
- This command will run the query and put the columns into variables ra,dec
59
+ This command will run the query and put the columns into variables ra,dec:
60
+
58
61
  ```python
59
62
  import sqlutilpy
60
63
  ra,dec = squtilpy.get('select ra,dec from mytable',
@@ -62,23 +65,28 @@ ra,dec = squtilpy.get('select ra,dec from mytable',
62
65
  db='THE_NAME_OF_MY_DB')
63
66
  ```
64
67
 
65
- By default sqlutilpy.get executes the query and returns the tuple with
66
- results. You can return the results as dictionary using asDict option.
68
+ By default `sqlutilpy.get` executes the query and returns the tuple with
69
+ arrays. One array for each column in the query result.
70
+ You can return the results as dictionary using `asDict` option.
67
71
 
68
72
  ## Uploading your arrays as column in a table
69
73
 
74
+ You can use `sqlutilpy.upload` to upload your arrays as columns in a table.
75
+
70
76
  ```python
71
77
  x = np.arange(10)
72
78
  y = x**.5
73
79
  sqlutilpy.upload('mytable',(x,y),('xcol','ycol'))
74
80
  ```
75
- This will create a table called mytable with columns xcol and ycol
81
+ This will create a table called `mytable` with columns `xcol` and `ycol`
76
82
 
77
83
  ## Join query involving your local data and the database table
78
84
 
79
- Imagine you have arrays myid and y and you want to to extract all the
80
- information from somebigtable for objects with id=myid. In principle
81
- you could upload the arrays in the DB and run a query, but local_join function does that for you.
85
+ Sometimes it is beneficial to run a join query involving your local data and the data in the database.
86
+
87
+ Imagine you have arrays `myid` and `y` and you want to extract all the
88
+ information from `somebigtable` for objects with `id=myid`. In principle,
89
+ you could upload the arrays in the DB and run a query, but `local_join` function does that for you.
82
90
 
83
91
  ```python
84
92
  myid = np.arange(10)
@@ -89,15 +97,14 @@ R=sqlutilpy.local_join('''select * from mytmptable as m,
89
97
  'mytmptable',(myid, y),('myid','ycol'))
90
98
  ```
91
99
 
92
- It executes a query as if you arrays were in mytmptable. (behind the scenes
93
- it uploads the data to the db and runs a query)
100
+ It executes a query as if your arrays were in `mytmptable`. What happens behind the scenes
101
+ is that it uploads the data to the database and runs a query against it.
94
102
 
95
103
  ## Keeping the connection open.
96
104
 
97
105
  Often it is beneficial to preserve an open connection to the database. You can do that if you first
98
- obtain the connection using sqlutilpy.getConnection() and then provide it directly
99
- to sqlutil.get() and friends using conn=conn argument
100
- ```python
106
+ obtain the connection using `sqlutilpy.getConnection()` and then provide it directly
107
+ to `sqlutil.get()` and similar commands using `conn=` keyword:
101
108
  conn = sqlutilpy.getConnection(db='mydb', user='meuser', password='something', host='hostname')
102
109
  R= sqlutilpy.get('select 1', conn=conn)
103
110
  R1= sqlutilpy.get('select 1', conn=conn)
@@ -105,5 +112,5 @@ R1= sqlutilpy.get('select 1', conn=conn)
105
112
 
106
113
  # How to cite the software
107
114
 
108
- If you use this package, please cite it through zenodo https://doi.org/10.5281/zenodo.6867957
115
+ If you use this package, please cite it through Zenodo https://doi.org/10.5281/zenodo.5160118
109
116
 
@@ -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)
@@ -340,12 +340,12 @@ def test_upload(setup):
340
340
  'xi32': xi32,
341
341
  'xi64': xi64,
342
342
  'xf32': xf32,
343
- 'xf64': xf64,
343
+ 'XF64': xf64, # one uppercase
344
344
  'xbool': xbool
345
345
  })
346
346
  sqlutil.upload(mytab, astroTab, **kw)
347
347
  yi16, yi32, yi64, yf32, yf64, ybool = sqlutil.get(
348
- '''select xi16,xi32,xi64,xf32,xf64,xbool from %s''' % (mytab), **kw)
348
+ '''select xi16,xi32,xi64,xf32,"XF64",xbool from %s''' % (mytab), **kw)
349
349
  try:
350
350
  assert ((xi16 == yi16).all())
351
351
  assert ((xi32 == yi32).all())
@@ -357,7 +357,7 @@ def test_upload(setup):
357
357
  sqlutil.execute('drop table %s' % mytab, **kw)
358
358
  sqlutil.upload(mytab, astroTab.to_pandas(), **kw)
359
359
  yi16, yi32, yi64, yf32, yf64, ybool = sqlutil.get(
360
- '''select xi16,xi32,xi64,xf32,xf64,xbool from %s''' % (mytab), **kw)
360
+ '''select xi16,xi32,xi64,xf32,"XF64",xbool from %s''' % (mytab), **kw)
361
361
  try:
362
362
  assert ((xi16 == yi16).all())
363
363
  assert ((xi32 == yi32).all())
@@ -1 +0,0 @@
1
- __version__ = '0.24.0'
File without changes
File without changes
File without changes
File without changes
File without changes