stdpipe 0.4.0__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.
stdpipe/db.py ADDED
@@ -0,0 +1,130 @@
1
+ import psycopg2, psycopg2.extras
2
+
3
+ import numpy as np
4
+
5
+ from astropy.table import Table
6
+
7
+
8
+ class DB:
9
+ """
10
+ Class encapsulating the connection to PostgreSQL database
11
+ """
12
+
13
+ def __init__(
14
+ self,
15
+ dbname=None,
16
+ dbhost=None,
17
+ dbport=None,
18
+ dbuser=None,
19
+ dbpassword=None,
20
+ readonly=False,
21
+ ):
22
+ connstring = ""
23
+ if dbname is not None:
24
+ connstring += "dbname=" + dbname
25
+ if dbhost is not None:
26
+ connstring += " host=" + dbhost
27
+ if dbport is not None:
28
+ connstring += " port=%d" % dbport
29
+ if dbuser is not None:
30
+ connstring += " user=" + dbuser
31
+ if dbpassword is not None:
32
+ connstring += " password='%s'" % dbpassword
33
+
34
+ self.connect(connstring, readonly)
35
+
36
+ def connect(self, connstring, readonly=False):
37
+ self.conn = psycopg2.connect(connstring)
38
+ self.conn.autocommit = True
39
+ self.conn.set_session(readonly=readonly)
40
+ psycopg2.extras.register_default_jsonb(self.conn)
41
+ # FIXME: the following adapter is registered globally!
42
+ psycopg2.extensions.register_adapter(dict, psycopg2.extras.Json)
43
+ psycopg2.extensions.register_adapter(np.float32, psycopg2.extensions.AsIs)
44
+ psycopg2.extensions.register_adapter(np.float64, psycopg2.extensions.AsIs)
45
+
46
+ self.connstring = connstring
47
+ self.readonly = readonly
48
+
49
+ def release(self):
50
+ """Close the connection, giving its server slot back to other clients.
51
+
52
+ A client that queries in bursts and then computes for a long time keeps a
53
+ backend - and one of the server's ``max_connections`` slots - occupied while
54
+ doing nothing. Calling this once the queries of a work item are done frees
55
+ the slot; :func:`query` reconnects transparently when the next query is
56
+ issued, so releasing is voluntary and safe at any point. Worth it only when
57
+ the idle stretch is long compared to the reconnection cost (a few ms).
58
+ """
59
+ if getattr(self, 'conn', None) is not None and not self.conn.closed:
60
+ self.conn.close()
61
+
62
+ def query(self, string="", data=(), table=True, simplify=True, verbose=False):
63
+ log = (verbose if callable(verbose) else print) if verbose else lambda *args, **kwargs: None
64
+
65
+ if self.conn.closed:
66
+ log("DB connection is closed, re-connecting")
67
+ self.connect(self.connstring, self.readonly)
68
+
69
+ # A DictCursor builds a dict-like DictRow per row, which for a large
70
+ # catalogue query costs more than the query itself. The table=True path
71
+ # consumes the rows positionally, so a plain tuple cursor is enough there;
72
+ # the table=False path is kept on DictCursor for its by-name access.
73
+ cur = self.conn.cursor() if table else self.conn.cursor(cursor_factory=psycopg2.extras.DictCursor)
74
+
75
+ if verbose:
76
+ log('Sending DB query:', cur.mogrify(string, data))
77
+
78
+ if data:
79
+ cur.execute(string, data)
80
+ else:
81
+ cur.execute(string)
82
+
83
+ try:
84
+ result = cur.fetchall()
85
+
86
+ if table:
87
+ # Code from astrolibpy, https://code.google.com/p/astrolibpy
88
+ strLength = 256
89
+ __pgTypeHash = {
90
+ 16: bool,
91
+ 18: str,
92
+ 20: 'i8',
93
+ 21: 'i2',
94
+ 23: 'i4',
95
+ 25: '|S%d' % strLength,
96
+ 700: 'f4',
97
+ 701: 'f8',
98
+ 1042: '|S%d' % strLength, # character()
99
+ 1043: '|S%d' % strLength, # varchar
100
+ 1114: '|O', # datetime
101
+ 1700: 'f8', # numeric
102
+ }
103
+
104
+ desc = cur.description
105
+ names = [d.name for d in desc]
106
+ formats = [__pgTypeHash.get(d.type_code, '|O') for d in desc]
107
+
108
+ # table = np.recarray(shape=(cur.rowcount,), formats=formats, names=names)
109
+ table = np.recarray(shape=(cur.rowcount,), formats=formats, names=names)
110
+
111
+ for i, v in enumerate(result):
112
+ table[i] = tuple(v)
113
+
114
+ table = Table(table)
115
+
116
+ return table
117
+
118
+ elif simplify and len(result) == 1:
119
+ # Simplify the result if it is simple
120
+ if len(result[0]) == 1:
121
+ return result[0][0]
122
+ else:
123
+ return result[0]
124
+ else:
125
+ return result
126
+ except:
127
+ # Nothing returned from the query
128
+ # import traceback
129
+ # traceback.print_exc()
130
+ return None