velocity-python 0.0.29__tar.gz → 0.0.31__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.
Potentially problematic release.
This version of velocity-python might be problematic. Click here for more details.
- {velocity-python-0.0.29 → velocity_python-0.0.31}/PKG-INFO +1 -1
- {velocity-python-0.0.29 → velocity_python-0.0.31}/pyproject.toml +1 -1
- {velocity-python-0.0.29 → velocity_python-0.0.31}/src/velocity/__init__.py +1 -1
- velocity_python-0.0.31/src/velocity/aws/__init__.py +18 -0
- {velocity-python-0.0.29 → velocity_python-0.0.31}/src/velocity/db/core/column.py +31 -20
- {velocity-python-0.0.29 → velocity_python-0.0.31}/src/velocity/db/core/database.py +9 -9
- {velocity-python-0.0.29 → velocity_python-0.0.31}/src/velocity/db/core/engine.py +101 -99
- {velocity-python-0.0.29 → velocity_python-0.0.31}/src/velocity/db/core/exceptions.py +23 -0
- {velocity-python-0.0.29 → velocity_python-0.0.31}/src/velocity/db/core/sequence.py +11 -3
- velocity_python-0.0.31/src/velocity/db/servers/mysql.py +873 -0
- velocity_python-0.0.31/src/velocity/db/servers/sqlite.py +1177 -0
- velocity_python-0.0.31/src/velocity/db/servers/sqlserver.py +1236 -0
- {velocity-python-0.0.29 → velocity_python-0.0.31}/src/velocity/misc/conv/__init__.py +1 -1
- {velocity-python-0.0.29 → velocity_python-0.0.31}/src/velocity/misc/conv/oconv.py +74 -70
- {velocity-python-0.0.29 → velocity_python-0.0.31}/src/velocity/misc/db.py +25 -19
- {velocity-python-0.0.29 → velocity_python-0.0.31}/src/velocity/misc/export.py +50 -43
- {velocity-python-0.0.29 → velocity_python-0.0.31}/src/velocity/misc/format.py +14 -13
- {velocity-python-0.0.29 → velocity_python-0.0.31}/src/velocity/misc/mail.py +12 -5
- {velocity-python-0.0.29 → velocity_python-0.0.31}/src/velocity/misc/merge.py +3 -2
- {velocity-python-0.0.29 → velocity_python-0.0.31}/src/velocity/misc/timer.py +3 -3
- {velocity-python-0.0.29 → velocity_python-0.0.31}/src/velocity_python.egg-info/PKG-INFO +1 -1
- velocity-python-0.0.29/src/velocity/aws/__init__.py +0 -22
- velocity-python-0.0.29/src/velocity/db/servers/mysql.py +0 -575
- velocity-python-0.0.29/src/velocity/db/servers/sqlite.py +0 -899
- velocity-python-0.0.29/src/velocity/db/servers/sqlserver.py +0 -821
- {velocity-python-0.0.29 → velocity_python-0.0.31}/LICENSE +0 -0
- {velocity-python-0.0.29 → velocity_python-0.0.31}/README.md +0 -0
- {velocity-python-0.0.29 → velocity_python-0.0.31}/setup.cfg +0 -0
- {velocity-python-0.0.29 → velocity_python-0.0.31}/src/velocity/aws/handlers/__init__.py +0 -0
- {velocity-python-0.0.29 → velocity_python-0.0.31}/src/velocity/aws/handlers/context.py +0 -0
- {velocity-python-0.0.29 → velocity_python-0.0.31}/src/velocity/aws/handlers/lambda_handler.py +0 -0
- {velocity-python-0.0.29 → velocity_python-0.0.31}/src/velocity/aws/handlers/response.py +0 -0
- {velocity-python-0.0.29 → velocity_python-0.0.31}/src/velocity/aws/handlers/sqs_handler.py +0 -0
- {velocity-python-0.0.29 → velocity_python-0.0.31}/src/velocity/db/__init__.py +0 -0
- {velocity-python-0.0.29 → velocity_python-0.0.31}/src/velocity/db/core/__init__.py +0 -0
- {velocity-python-0.0.29 → velocity_python-0.0.31}/src/velocity/db/core/decorators.py +0 -0
- {velocity-python-0.0.29 → velocity_python-0.0.31}/src/velocity/db/core/result.py +0 -0
- {velocity-python-0.0.29 → velocity_python-0.0.31}/src/velocity/db/core/row.py +0 -0
- {velocity-python-0.0.29 → velocity_python-0.0.31}/src/velocity/db/core/table.py +0 -0
- {velocity-python-0.0.29 → velocity_python-0.0.31}/src/velocity/db/core/transaction.py +0 -0
- {velocity-python-0.0.29 → velocity_python-0.0.31}/src/velocity/db/servers/__init__.py +0 -0
- {velocity-python-0.0.29 → velocity_python-0.0.31}/src/velocity/db/servers/postgres.py +0 -0
- {velocity-python-0.0.29 → velocity_python-0.0.31}/src/velocity/misc/__init__.py +0 -0
- {velocity-python-0.0.29 → velocity_python-0.0.31}/src/velocity/misc/conv/iconv.py +0 -0
- {velocity-python-0.0.29 → velocity_python-0.0.31}/src/velocity_python.egg-info/SOURCES.txt +0 -0
- {velocity-python-0.0.29 → velocity_python-0.0.31}/src/velocity_python.egg-info/dependency_links.txt +0 -0
- {velocity-python-0.0.29 → velocity_python-0.0.31}/src/velocity_python.egg-info/requires.txt +0 -0
- {velocity-python-0.0.29 → velocity_python-0.0.31}/src/velocity_python.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: velocity-python
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.31
|
|
4
4
|
Summary: A rapid application development library for interfacing with data storage
|
|
5
5
|
Author-email: Paul Perez <pperez@codeclubs.org>
|
|
6
6
|
Project-URL: Homepage, https://codeclubs.org/projects/velocity
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import requests
|
|
3
|
+
|
|
4
|
+
DEBUG = (os.environ.get("ENV") != "production") or (os.environ.get("DEBUG") == "Y")
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
# This is helpful for running HTTPS clients on lambda.
|
|
8
|
+
if os.path.exists("/opt/python/ca-certificates.crt"):
|
|
9
|
+
os.environ["REQUESTS_CA_BUNDLE"] = "/opt/python/ca-certificates.crt"
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class AWS(object):
|
|
13
|
+
# Get AWS EC2 Instance ID. Must run this from the EC2 instance itself to get the ID
|
|
14
|
+
@staticmethod
|
|
15
|
+
def instance_id(cls):
|
|
16
|
+
response = requests.get("http://169.254.169.254/latest/meta-data/instance-id")
|
|
17
|
+
instance_id = response.text
|
|
18
|
+
return instance_id
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
from velocity.db import exceptions
|
|
2
2
|
from velocity.db.core.decorators import return_default
|
|
3
3
|
|
|
4
|
+
|
|
4
5
|
class Column(object):
|
|
5
6
|
"""
|
|
6
7
|
Represents a column in a database table.
|
|
7
8
|
"""
|
|
9
|
+
|
|
8
10
|
def __init__(self, table, name):
|
|
9
11
|
"""
|
|
10
12
|
Initializes a column object with the specified table and name.
|
|
@@ -12,11 +14,11 @@ class Column(object):
|
|
|
12
14
|
Args:
|
|
13
15
|
table (table): The table object that the column belongs to.
|
|
14
16
|
name (str): The name of the column.
|
|
15
|
-
|
|
17
|
+
|
|
16
18
|
Raises:
|
|
17
19
|
Exception: If the table parameter is not of type 'table'.
|
|
18
20
|
"""
|
|
19
|
-
if isinstance(table,str):
|
|
21
|
+
if isinstance(table, str):
|
|
20
22
|
raise Exception("column table parameter must be a `table` class.")
|
|
21
23
|
self.tx = table.tx
|
|
22
24
|
self.sql = table.tx.engine.sql
|
|
@@ -39,13 +41,13 @@ class Column(object):
|
|
|
39
41
|
NULL OK: %s
|
|
40
42
|
Foreign Key: %s
|
|
41
43
|
""" % (
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
44
|
+
self.table.name,
|
|
45
|
+
self.name,
|
|
46
|
+
self.exists(),
|
|
47
|
+
self.py_type,
|
|
48
|
+
self.sql_type,
|
|
49
|
+
self.is_nullok,
|
|
50
|
+
self.foreign_key_to,
|
|
49
51
|
)
|
|
50
52
|
|
|
51
53
|
@property
|
|
@@ -55,7 +57,7 @@ class Column(object):
|
|
|
55
57
|
|
|
56
58
|
Returns:
|
|
57
59
|
dict: A dictionary containing information about the column.
|
|
58
|
-
|
|
60
|
+
|
|
59
61
|
Raises:
|
|
60
62
|
DbColumnMissingError: If the column does not exist in the database.
|
|
61
63
|
"""
|
|
@@ -72,7 +74,7 @@ class Column(object):
|
|
|
72
74
|
|
|
73
75
|
Returns:
|
|
74
76
|
dict: A dictionary containing information about the foreign key constraint.
|
|
75
|
-
|
|
77
|
+
|
|
76
78
|
Raises:
|
|
77
79
|
DbColumnMissingError: If the column does not exist in the database.
|
|
78
80
|
"""
|
|
@@ -89,12 +91,14 @@ class Column(object):
|
|
|
89
91
|
|
|
90
92
|
Returns:
|
|
91
93
|
str: The name of the referenced table and column in the format 'referenced_table_name.referenced_column_name'.
|
|
92
|
-
|
|
94
|
+
|
|
93
95
|
Raises:
|
|
94
96
|
DbColumnMissingError: If the column does not exist in the database.
|
|
95
97
|
"""
|
|
96
98
|
try:
|
|
97
|
-
return "{referenced_table_name}.{referenced_column_name}".format(
|
|
99
|
+
return "{referenced_table_name}.{referenced_column_name}".format(
|
|
100
|
+
**self.foreign_key_info
|
|
101
|
+
)
|
|
98
102
|
except exceptions.DbColumnMissingError:
|
|
99
103
|
return None
|
|
100
104
|
|
|
@@ -105,12 +109,12 @@ class Column(object):
|
|
|
105
109
|
|
|
106
110
|
Returns:
|
|
107
111
|
str: The name of the referenced table.
|
|
108
|
-
|
|
112
|
+
|
|
109
113
|
Raises:
|
|
110
114
|
DbColumnMissingError: If the column does not exist in the database.
|
|
111
115
|
"""
|
|
112
116
|
try:
|
|
113
|
-
return self.foreign_key_info[
|
|
117
|
+
return self.foreign_key_info["referenced_table_name"]
|
|
114
118
|
except exceptions.DbColumnMissingError:
|
|
115
119
|
return None
|
|
116
120
|
|
|
@@ -167,7 +171,7 @@ class Column(object):
|
|
|
167
171
|
self.name = name
|
|
168
172
|
|
|
169
173
|
@return_default([])
|
|
170
|
-
def distinct(self, order=
|
|
174
|
+
def distinct(self, order="asc", qty=None):
|
|
171
175
|
"""
|
|
172
176
|
Retrieves distinct values from the column.
|
|
173
177
|
|
|
@@ -178,7 +182,12 @@ class Column(object):
|
|
|
178
182
|
Returns:
|
|
179
183
|
list: A list of distinct values from the column.
|
|
180
184
|
"""
|
|
181
|
-
sql, vals = self.sql.select(
|
|
185
|
+
sql, vals = self.sql.select(
|
|
186
|
+
columns="distinct {}".format(self.name),
|
|
187
|
+
table=self.table.name,
|
|
188
|
+
orderby="{} {}".format(self.name, order),
|
|
189
|
+
qty=qty,
|
|
190
|
+
)
|
|
182
191
|
return self.tx.execute(sql, vals).as_simple_list().all()
|
|
183
192
|
|
|
184
193
|
def max(self, where=None):
|
|
@@ -190,13 +199,15 @@ class Column(object):
|
|
|
190
199
|
|
|
191
200
|
Returns:
|
|
192
201
|
int: The maximum value from the column.
|
|
193
|
-
|
|
202
|
+
|
|
194
203
|
Raises:
|
|
195
204
|
DbTableMissingError: If the table does not exist in the database.
|
|
196
205
|
DbColumnMissingError: If the column does not exist in the database.
|
|
197
206
|
"""
|
|
198
207
|
try:
|
|
199
|
-
sql, vals = self.sql.select(
|
|
208
|
+
sql, vals = self.sql.select(
|
|
209
|
+
columns="max({})".format(self.name), table=self.table.name, where=where
|
|
210
|
+
)
|
|
200
211
|
return self.tx.execute(sql, vals).scalar()
|
|
201
|
-
except (exceptions.DbTableMissingError,exceptions.DbColumnMissingError):
|
|
212
|
+
except (exceptions.DbTableMissingError, exceptions.DbColumnMissingError):
|
|
202
213
|
return 0
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
class Database(object):
|
|
2
|
-
|
|
2
|
+
|
|
3
3
|
def __init__(self, tx, name=None):
|
|
4
4
|
self.tx = tx
|
|
5
|
-
self.name = name or self.tx.engine.config[
|
|
5
|
+
self.name = name or self.tx.engine.config["database"]
|
|
6
6
|
self.sql = tx.engine.sql
|
|
7
7
|
|
|
8
8
|
def __str__(self):
|
|
@@ -12,10 +12,10 @@ class Database(object):
|
|
|
12
12
|
(db exists) %s
|
|
13
13
|
Tables: %s
|
|
14
14
|
""" % (
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
15
|
+
self.tx.engine.sql.server,
|
|
16
|
+
self.name,
|
|
17
|
+
self.exists(),
|
|
18
|
+
len(self.tables),
|
|
19
19
|
)
|
|
20
20
|
|
|
21
21
|
def __enter__(self):
|
|
@@ -28,7 +28,7 @@ class Database(object):
|
|
|
28
28
|
def close(self):
|
|
29
29
|
try:
|
|
30
30
|
self._cursor.close()
|
|
31
|
-
#print("*** database('{}').cursor.close()".format(self.name))
|
|
31
|
+
# print("*** database('{}').cursor.close()".format(self.name))
|
|
32
32
|
except AttributeError:
|
|
33
33
|
pass
|
|
34
34
|
|
|
@@ -37,7 +37,7 @@ class Database(object):
|
|
|
37
37
|
try:
|
|
38
38
|
return self._cursor
|
|
39
39
|
except AttributeError:
|
|
40
|
-
#print("*** database('{}').cursor.open()".format(self.name))
|
|
40
|
+
# print("*** database('{}').cursor.open()".format(self.name))
|
|
41
41
|
self._cursor = self.tx.cursor()
|
|
42
42
|
return self._cursor
|
|
43
43
|
|
|
@@ -57,7 +57,7 @@ class Database(object):
|
|
|
57
57
|
@property
|
|
58
58
|
def tables(self):
|
|
59
59
|
sql, vals = self.sql.tables()
|
|
60
|
-
result = self.tx.execute(sql
|
|
60
|
+
result = self.tx.execute(sql, vals, cursor=self.cursor)
|
|
61
61
|
return ["%s.%s" % x for x in result.as_tuple()]
|
|
62
62
|
|
|
63
63
|
def reindex(self):
|
|
@@ -4,6 +4,7 @@ from velocity.db.core.transaction import Transaction
|
|
|
4
4
|
from functools import wraps
|
|
5
5
|
import inspect, sys, re, traceback
|
|
6
6
|
|
|
7
|
+
|
|
7
8
|
class Engine(object):
|
|
8
9
|
MAX_RETRIES = 100
|
|
9
10
|
|
|
@@ -16,53 +17,52 @@ class Engine(object):
|
|
|
16
17
|
return """[{}] engine({})""".format(self.sql.server, self.config)
|
|
17
18
|
|
|
18
19
|
def connect(self):
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
20
|
+
"""
|
|
21
|
+
Connects to the database and returns the connection object.
|
|
22
|
+
|
|
23
|
+
If the database is missing, it creates the database and then connects to it.
|
|
24
|
+
|
|
25
|
+
Returns:
|
|
26
|
+
conn: The connection object to the database.
|
|
27
|
+
"""
|
|
28
|
+
try:
|
|
29
|
+
conn = self.__connect()
|
|
30
|
+
except exceptions.DbDatabaseMissingError:
|
|
31
|
+
self.create_database()
|
|
32
|
+
conn = self.__connect()
|
|
33
|
+
if self.sql.server == "SQLite3":
|
|
34
|
+
conn.isolation_level = None
|
|
35
|
+
return conn
|
|
35
36
|
|
|
36
37
|
def __connect(self):
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
38
|
+
"""
|
|
39
|
+
Connects to the database using the provided configuration.
|
|
40
|
+
|
|
41
|
+
Returns:
|
|
42
|
+
A connection object representing the connection to the database.
|
|
43
|
+
|
|
44
|
+
Raises:
|
|
45
|
+
Exception: If the configuration parameter is not handled properly.
|
|
46
|
+
ProcessError is called to handle other exceptions.
|
|
47
|
+
"""
|
|
48
|
+
try:
|
|
49
|
+
if isinstance(self.config, dict):
|
|
50
|
+
return self.driver.connect(**self.config)
|
|
51
|
+
elif isinstance(self.config, (tuple, list)):
|
|
52
|
+
return self.driver.connect(*self.config)
|
|
53
|
+
elif isinstance(self.config, str):
|
|
54
|
+
return self.driver.connect(self.config)
|
|
55
|
+
else:
|
|
56
|
+
raise Exception("Unhandled configuration parameter")
|
|
57
|
+
except:
|
|
58
|
+
self.ProcessError()
|
|
59
59
|
|
|
60
60
|
def transaction(self, func_or_cls=None):
|
|
61
61
|
"""
|
|
62
|
-
Decorator for defining a transaction. Use this to wrap a function, method, or class to automatically
|
|
63
|
-
start a transaction if necessary. If the function, method or class is called with a `tx` keyword argument,
|
|
64
|
-
it will use that transaction object instead of creating a new one. If the function, method or class
|
|
65
|
-
is called with a `tx` positional argument, it will use that transaction object instead of creating a new one.
|
|
62
|
+
Decorator for defining a transaction. Use this to wrap a function, method, or class to automatically
|
|
63
|
+
start a transaction if necessary. If the function, method or class is called with a `tx` keyword argument,
|
|
64
|
+
it will use that transaction object instead of creating a new one. If the function, method or class
|
|
65
|
+
is called with a `tx` positional argument, it will use that transaction object instead of creating a new one.
|
|
66
66
|
If the function, method or class is called with a `tx` positional argument and a `tx` keyword argument, it will use the positional
|
|
67
67
|
argument and ignore the keyword argument. If the function, method or class is called without a `tx` argument,
|
|
68
68
|
it will create a new transaction object and use that.
|
|
@@ -72,9 +72,9 @@ class Engine(object):
|
|
|
72
72
|
Returns:
|
|
73
73
|
If `func_or_cls` is a function or method, returns a wrapped version of the function or method that
|
|
74
74
|
automatically starts a transaction if necessary. If `func_or_cls` is a class, returns a subclass of
|
|
75
|
-
`func_or_cls` that wraps all its methods with the transaction decorator.
|
|
76
|
-
|
|
77
|
-
|
|
75
|
+
`func_or_cls` that wraps all its methods with the transaction decorator.
|
|
76
|
+
|
|
77
|
+
|
|
78
78
|
|
|
79
79
|
If `func_or_cls` is not provided, returns a new `Transaction` object associated with the engine.
|
|
80
80
|
"""
|
|
@@ -86,55 +86,60 @@ class Engine(object):
|
|
|
86
86
|
# ...
|
|
87
87
|
#
|
|
88
88
|
engine = self
|
|
89
|
-
if inspect.isfunction(func_or_cls)
|
|
90
|
-
|
|
89
|
+
if inspect.isfunction(func_or_cls) or inspect.ismethod(func_or_cls):
|
|
90
|
+
|
|
91
91
|
@wraps(func_or_cls)
|
|
92
92
|
def NewFunction(*args, **kwds):
|
|
93
93
|
tx = None
|
|
94
94
|
names = list(inspect.signature(func_or_cls).parameters.keys())
|
|
95
|
-
if
|
|
96
|
-
raise NameError(
|
|
97
|
-
|
|
95
|
+
if "_tx" in names:
|
|
96
|
+
raise NameError(
|
|
97
|
+
f"In function named `{func_or_cls.__name__}` You may not name a paramater `_tx`"
|
|
98
|
+
)
|
|
99
|
+
if "tx" not in names:
|
|
98
100
|
return func_or_cls(*args, **kwds)
|
|
99
|
-
elif
|
|
100
|
-
if isinstance(kwds[
|
|
101
|
-
tx = kwds[
|
|
101
|
+
elif "tx" in kwds:
|
|
102
|
+
if isinstance(kwds["tx"], Transaction):
|
|
103
|
+
tx = kwds["tx"]
|
|
102
104
|
else:
|
|
103
|
-
raise TypeError(
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
105
|
+
raise TypeError(
|
|
106
|
+
f"In function named `{func_or_cls.__name__}` keyword `tx` must be a Transaction object"
|
|
107
|
+
)
|
|
108
|
+
elif "tx" in names:
|
|
109
|
+
pos = names.index("tx")
|
|
110
|
+
if len(args) > pos and isinstance(args[pos], Transaction):
|
|
108
111
|
tx = args[pos]
|
|
109
112
|
if tx:
|
|
110
113
|
return engine.exec_function(func_or_cls, tx, *args, **kwds)
|
|
111
114
|
else:
|
|
112
115
|
with Transaction(engine) as tx:
|
|
113
|
-
pos = names.index(
|
|
116
|
+
pos = names.index("tx")
|
|
114
117
|
args = list(args)
|
|
115
118
|
args.insert(pos, tx)
|
|
116
119
|
args = tuple(args)
|
|
117
|
-
return engine.exec_function(func_or_cls, tx, *args, **kwds)
|
|
120
|
+
return engine.exec_function(func_or_cls, tx, *args, **kwds)
|
|
121
|
+
|
|
118
122
|
return NewFunction
|
|
119
123
|
elif inspect.isclass(func_or_cls):
|
|
124
|
+
|
|
120
125
|
class NewCls(func_or_cls):
|
|
121
126
|
def __getattribute__(self, key):
|
|
122
127
|
attr = super(NewCls, self).__getattribute__(key)
|
|
123
|
-
if key in [
|
|
128
|
+
if key in ["start_response"]:
|
|
124
129
|
return attr
|
|
125
130
|
if inspect.ismethod(attr):
|
|
126
131
|
return engine.transaction(attr)
|
|
127
132
|
return attr
|
|
133
|
+
|
|
128
134
|
return NewCls
|
|
129
135
|
|
|
130
136
|
return Transaction(engine)
|
|
131
|
-
|
|
132
137
|
|
|
133
138
|
def exec_function(self, function, _tx, *args, **kwds):
|
|
134
139
|
"""
|
|
135
140
|
Executes the given function with the provided arguments and keyword arguments.
|
|
136
141
|
If there is no transaction object, it executes the function without a transaction.
|
|
137
|
-
|
|
142
|
+
|
|
138
143
|
If there is a transaction object, it executes the function within the transaction.
|
|
139
144
|
If the function raises a `DbRetryTransaction` exception, it rolls back the transaction and retries.
|
|
140
145
|
If the function raises a `DbLockTimeoutError` exception, it rolls back the transaction and retries.
|
|
@@ -169,14 +174,14 @@ class Engine(object):
|
|
|
169
174
|
retry_count += 1
|
|
170
175
|
if retry_count > self.MAX_RETRIES:
|
|
171
176
|
raise
|
|
172
|
-
print(
|
|
177
|
+
print("**Retry Transaction. Rollback and start over")
|
|
173
178
|
_tx.rollback()
|
|
174
179
|
continue
|
|
175
180
|
except exceptions.DbLockTimeoutError:
|
|
176
181
|
tmout_count += 1
|
|
177
182
|
if tmout_count > self.MAX_RETRIES:
|
|
178
183
|
raise
|
|
179
|
-
print(
|
|
184
|
+
print("**DbLockTimeoutError. Rollback and start over")
|
|
180
185
|
_tx.rollback()
|
|
181
186
|
continue
|
|
182
187
|
except:
|
|
@@ -228,22 +233,22 @@ class Engine(object):
|
|
|
228
233
|
def create_database(self, name=None):
|
|
229
234
|
old = None
|
|
230
235
|
if name == None:
|
|
231
|
-
old = self.config[
|
|
232
|
-
self.set_config({
|
|
236
|
+
old = self.config["database"]
|
|
237
|
+
self.set_config({"database": "postgres"})
|
|
233
238
|
name = old
|
|
234
239
|
with Transaction(self) as tx:
|
|
235
240
|
sql, vals = self.sql.create_database(name)
|
|
236
241
|
tx.execute(sql, vals, single=True)
|
|
237
242
|
if old:
|
|
238
|
-
self.set_config({
|
|
243
|
+
self.set_config({"database": old})
|
|
239
244
|
return self
|
|
240
245
|
|
|
241
246
|
def switch_to_database(self, database):
|
|
242
|
-
conf
|
|
243
|
-
if
|
|
244
|
-
conf[
|
|
245
|
-
if
|
|
246
|
-
conf[
|
|
247
|
+
conf = self.config
|
|
248
|
+
if "database" in conf:
|
|
249
|
+
conf["database"] = database
|
|
250
|
+
if "dbname" in conf:
|
|
251
|
+
conf["dbname"] = database
|
|
247
252
|
return self
|
|
248
253
|
|
|
249
254
|
def set_config(self, config):
|
|
@@ -276,27 +281,24 @@ class Engine(object):
|
|
|
276
281
|
result = tx.execute(sql, vals)
|
|
277
282
|
return ["%s.%s" % x for x in result.as_tuple()]
|
|
278
283
|
|
|
279
|
-
|
|
280
284
|
def ProcessError(self, sql_stmt=None, sql_params=None):
|
|
281
285
|
sql = self.sql
|
|
282
286
|
e = sys.exc_info()[1]
|
|
283
287
|
msg = str(e).strip().lower()
|
|
284
|
-
if isinstance(e,exceptions.DbException):
|
|
288
|
+
if isinstance(e, exceptions.DbException):
|
|
285
289
|
raise
|
|
286
|
-
if hasattr(e,
|
|
290
|
+
if hasattr(e, "pgcode"):
|
|
287
291
|
error_code = e.pgcode
|
|
288
292
|
error_mesg = e.pgerror
|
|
289
|
-
elif
|
|
290
|
-
|
|
291
|
-
|
|
293
|
+
elif (
|
|
294
|
+
hasattr(e, "args") and isinstance(e.args, (tuple, list)) and len(e.args) > 1
|
|
295
|
+
):
|
|
292
296
|
error_code = e[0]
|
|
293
297
|
error_mesg = e[1]
|
|
294
|
-
elif hasattr(e,
|
|
295
|
-
and hasattr(e,'text'):
|
|
298
|
+
elif hasattr(e, "number") and hasattr(e, "text"):
|
|
296
299
|
error_code = e.number
|
|
297
300
|
error_mesg = e.text
|
|
298
|
-
elif hasattr(e,
|
|
299
|
-
and hasattr(e,'message'):
|
|
301
|
+
elif hasattr(e, "args") and hasattr(e, "message"):
|
|
300
302
|
# SQLite3
|
|
301
303
|
error_code = None
|
|
302
304
|
error_mesg = e.message
|
|
@@ -320,7 +322,7 @@ class Engine(object):
|
|
|
320
322
|
raise exceptions.DbConnectionError(e)
|
|
321
323
|
elif error_code in sql.DuplicateKeyErrorCodes:
|
|
322
324
|
raise exceptions.DbDuplicateKeyError(e)
|
|
323
|
-
elif re.search(
|
|
325
|
+
elif re.search("key \(sys_id\)=\(\d+\) already exists.", msg, re.M):
|
|
324
326
|
raise exceptions.DbDuplicateKeyError(e)
|
|
325
327
|
elif error_code in sql.DatabaseObjectExistsErrorCodes:
|
|
326
328
|
raise exceptions.DbObjectExistsError(e)
|
|
@@ -328,34 +330,34 @@ class Engine(object):
|
|
|
328
330
|
raise exceptions.DbLockTimeoutError(e)
|
|
329
331
|
elif error_code in sql.RetryTransactionCodes:
|
|
330
332
|
raise exceptions.DbRetryTransaction(e)
|
|
331
|
-
elif re.findall(
|
|
333
|
+
elif re.findall("database.*does not exist", msg, re.M):
|
|
332
334
|
raise exceptions.DbDatabaseMissingError(e)
|
|
333
|
-
elif re.findall(
|
|
335
|
+
elif re.findall("no such database", msg, re.M):
|
|
334
336
|
raise exceptions.DbDatabaseMissingError(e)
|
|
335
|
-
elif re.findall(
|
|
337
|
+
elif re.findall("already exists", msg, re.M):
|
|
336
338
|
raise exceptions.DbObjectExistsError(e)
|
|
337
|
-
elif re.findall(
|
|
339
|
+
elif re.findall("server closed the connection unexpectedly", msg, re.M):
|
|
338
340
|
raise exceptions.DbConnectionError(e)
|
|
339
|
-
elif re.findall(
|
|
341
|
+
elif re.findall("no connection to the server", msg, re.M):
|
|
340
342
|
raise exceptions.DbConnectionError(e)
|
|
341
|
-
elif re.findall(
|
|
343
|
+
elif re.findall("connection timed out", msg, re.M):
|
|
342
344
|
raise exceptions.DbConnectionError(e)
|
|
343
|
-
elif re.findall(
|
|
345
|
+
elif re.findall("could not connect to server", msg, re.M):
|
|
344
346
|
raise exceptions.DbConnectionError(e)
|
|
345
|
-
elif re.findall(
|
|
347
|
+
elif re.findall("cannot connect to server", msg, re.M):
|
|
346
348
|
raise exceptions.DbConnectionError(e)
|
|
347
|
-
elif re.findall(
|
|
349
|
+
elif re.findall("connection already closed", msg, re.M):
|
|
348
350
|
raise exceptions.DbConnectionError(e)
|
|
349
|
-
elif re.findall(
|
|
351
|
+
elif re.findall("cursor already closed", msg, re.M):
|
|
350
352
|
raise exceptions.DbConnectionError(e)
|
|
351
353
|
# SQLite3 errors
|
|
352
|
-
elif
|
|
354
|
+
elif "no such table:" in msg:
|
|
353
355
|
raise exceptions.DbTableMissingError(e)
|
|
354
356
|
print("Unhandled/Unknown Error in connection.ProcessError")
|
|
355
|
-
print(
|
|
356
|
-
print(
|
|
357
|
-
print(
|
|
358
|
-
print(
|
|
357
|
+
print("EXC_TYPE = {}".format(type(e)))
|
|
358
|
+
print("EXC_MSG = {}".format(str(e).strip()))
|
|
359
|
+
print("ERROR_CODE = {}".format(error_code))
|
|
360
|
+
print("ERROR_MSG = {}".format(error_mesg))
|
|
359
361
|
if sql_stmt:
|
|
360
362
|
print("\n")
|
|
361
363
|
print("sql_stmt [velocity.db.engine]: {}".format(sql_stmt))
|
|
@@ -1,31 +1,54 @@
|
|
|
1
1
|
class DbException(Exception):
|
|
2
2
|
pass
|
|
3
3
|
|
|
4
|
+
|
|
4
5
|
class DbApplicationError(DbException):
|
|
5
6
|
pass
|
|
6
7
|
|
|
8
|
+
|
|
7
9
|
class DbForeignKeyMissingError(DbException):
|
|
8
10
|
pass
|
|
11
|
+
|
|
12
|
+
|
|
9
13
|
class DbDatabaseMissingError(DbException):
|
|
10
14
|
pass
|
|
15
|
+
|
|
16
|
+
|
|
11
17
|
class DbTableMissingError(DbException):
|
|
12
18
|
pass
|
|
19
|
+
|
|
20
|
+
|
|
13
21
|
class DbColumnMissingError(DbException):
|
|
14
22
|
pass
|
|
15
23
|
|
|
24
|
+
|
|
16
25
|
class DbTruncationError(DbException):
|
|
17
26
|
pass
|
|
27
|
+
|
|
28
|
+
|
|
18
29
|
class DbConnectionError(DbException):
|
|
19
30
|
pass
|
|
31
|
+
|
|
32
|
+
|
|
20
33
|
class DbDuplicateKeyError(DbException):
|
|
21
34
|
pass
|
|
35
|
+
|
|
36
|
+
|
|
22
37
|
class DbObjectExistsError(DbException):
|
|
23
38
|
pass
|
|
39
|
+
|
|
40
|
+
|
|
24
41
|
class DbLockTimeoutError(DbException):
|
|
25
42
|
pass
|
|
43
|
+
|
|
44
|
+
|
|
26
45
|
class DbRetryTransaction(DbException):
|
|
27
46
|
pass
|
|
47
|
+
|
|
48
|
+
|
|
28
49
|
class DbDataIntegrityError(DbException):
|
|
29
50
|
pass
|
|
51
|
+
|
|
52
|
+
|
|
30
53
|
class DuplicateRowsFoundError(Exception):
|
|
31
54
|
pass
|
|
@@ -10,10 +10,15 @@ class Sequence(object):
|
|
|
10
10
|
def __str__(self):
|
|
11
11
|
return """
|
|
12
12
|
Sequence: %s
|
|
13
|
-
""" % (
|
|
13
|
+
""" % (
|
|
14
|
+
self.name
|
|
15
|
+
)
|
|
14
16
|
|
|
15
17
|
def create(self):
|
|
16
|
-
sql, vals =
|
|
18
|
+
sql, vals = (
|
|
19
|
+
"CREATE SEQUENCE IF NOT EXISTS {} START {};".format(self.name, self.start),
|
|
20
|
+
tuple(),
|
|
21
|
+
)
|
|
17
22
|
return self.tx.execute(sql, vals)
|
|
18
23
|
|
|
19
24
|
def next(self):
|
|
@@ -25,7 +30,10 @@ class Sequence(object):
|
|
|
25
30
|
return self.tx.execute(sql, vals).scalar()
|
|
26
31
|
|
|
27
32
|
def reset(self, start=None):
|
|
28
|
-
sql, vals =
|
|
33
|
+
sql, vals = (
|
|
34
|
+
"ALTER SEQUENCE {} RESTART WITH {};".format(self.name, start or self.start),
|
|
35
|
+
tuple(),
|
|
36
|
+
)
|
|
29
37
|
return self.tx.execute(sql, vals).scalar()
|
|
30
38
|
|
|
31
39
|
def drop(self):
|