Skip to content

Commit ee4a461

Browse files
Exception classes are updated (#312)
* PortException is updated - explicit constructor - own __repr__ implmentation - tests * InitNodeException is updated - explicit constructor - own __repr__ implmentation - tests * BackupException is updated - explicit constructor - own __repr__ implmentation - tests * CatchUpException is updated (attention!) - inherits TestgresException, not QueryException - explicit constructor - own __repr__ implmentation - tests * QueryTimeoutException replaces TimeoutException TimeoutException is saved as an alias of QueryTimeoutException
1 parent ea07d8d commit ee4a461

16 files changed

Lines changed: 322 additions & 13 deletions

File tree

src/__init__.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
TestgresException, \
2020
ExecUtilException, \
2121
QueryException, \
22+
QueryTimeoutException, \
2223
TimeoutException, \
2324
CatchUpException, \
2425
StartNodeException, \
@@ -61,7 +62,9 @@
6162
"NodeBackup", "testgres_config",
6263
"TestgresConfig", "configure_testgres", "scoped_config", "push_config", "pop_config",
6364
"NodeConnection", "DatabaseError", "InternalError", "ProgrammingError", "OperationalError",
64-
"TestgresException", "ExecUtilException", "QueryException", "TimeoutException", "CatchUpException", "StartNodeException", "InitNodeException", "BackupException", "InvalidOperationException",
65+
"TestgresException", "ExecUtilException", "QueryException",
66+
QueryTimeoutException.__name__,
67+
"TimeoutException", "CatchUpException", "StartNodeException", "InitNodeException", "BackupException", "InvalidOperationException",
6568
"XLogMethod", "IsolationLevel", "NodeStatus", "ProcessType", "DumpFormat",
6669
NodeApp.__name__,
6770
PostgresNode.__name__,

src/exceptions.py

Lines changed: 145 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,38 @@
99

1010

1111
class PortForException(TestgresException):
12-
pass
12+
_message: typing.Optional[str]
13+
14+
def __init__(
15+
self,
16+
message: typing.Optional[str] = None,
17+
):
18+
assert message is None or type(message) == str # noqa: E721
19+
super().__init__(message)
20+
self._message = message
21+
return
22+
23+
@property
24+
def message(self) -> str:
25+
assert self._message is None or type(self._message) == str # noqa: E721
26+
if self._message is None:
27+
return ""
28+
return self._message
29+
30+
def __repr__(self) -> str:
31+
args = []
32+
33+
if self._message is not None:
34+
args.append(("message", self._message))
35+
36+
result = "{}(".format(type(self).__name__)
37+
sep = ""
38+
for a in args:
39+
result += sep + a[0] + "=" + repr(a[1])
40+
sep = ", "
41+
continue
42+
result += ")"
43+
return result
1344

1445

1546
@six.python_2_unicode_compatible
@@ -77,12 +108,57 @@ def __repr__(self) -> str:
77108
return result
78109

79110

80-
class TimeoutException(QueryException):
81-
pass
111+
class QueryTimeoutException(QueryException):
112+
def __init__(
113+
self,
114+
message: typing.Optional[str] = None,
115+
query: typing.Optional[str] = None
116+
):
117+
assert message is None or type(message) == str # noqa: E721
118+
assert query is None or type(query) == str # noqa: E721
119+
120+
super().__init__(message, query)
121+
return
122+
82123

124+
# [2026-01-10] To backward compatibility.
125+
TimeoutException = QueryTimeoutException
83126

84-
class CatchUpException(QueryException):
85-
pass
127+
128+
# [2026-01-10] It inherits TestgresException now, not QueryException
129+
class CatchUpException(TestgresException):
130+
_message: typing.Optional[str]
131+
132+
def __init__(
133+
self,
134+
message: typing.Optional[str] = None,
135+
):
136+
assert message is None or type(message) == str # noqa: E721
137+
super().__init__(message)
138+
self._message = message
139+
return
140+
141+
@property
142+
def message(self) -> str:
143+
assert self._message is None or type(self._message) == str # noqa: E721
144+
if self._message is None:
145+
return ""
146+
return self._message
147+
148+
def __repr__(self) -> str:
149+
args = []
150+
151+
if self._message is not None:
152+
args.append(("message", self._message))
153+
154+
result = "{}(".format(type(self).__name__)
155+
sep = ""
156+
for a in args:
157+
result += sep + a[0] + "=" + repr(a[1])
158+
sep = ", "
159+
continue
160+
result += ")"
161+
return result
86162

87163

88164
@six.python_2_unicode_compatible
@@ -151,11 +227,73 @@ def __repr__(self) -> str:
151227

152228

153229
class InitNodeException(TestgresException):
154-
pass
230+
_message: typing.Optional[str]
231+
232+
def __init__(
233+
self,
234+
message: typing.Optional[str] = None,
235+
):
236+
assert message is None or type(message) == str # noqa: E721
237+
super().__init__(message)
238+
self._message = message
239+
return
240+
241+
@property
242+
def message(self) -> str:
243+
assert self._message is None or type(self._message) == str # noqa: E721
244+
if self._message is None:
245+
return ""
246+
return self._message
247+
248+
def __repr__(self) -> str:
249+
args = []
250+
251+
if self._message is not None:
252+
args.append(("message", self._message))
253+
254+
result = "{}(".format(type(self).__name__)
255+
sep = ""
256+
for a in args:
257+
result += sep + a[0] + "=" + repr(a[1])
258+
sep = ", "
259+
continue
260+
result += ")"
261+
return result
155262

156263

157264
class BackupException(TestgresException):
158-
pass
265+
_message: typing.Optional[str]
266+
267+
def __init__(
268+
self,
269+
message: typing.Optional[str] = None,
270+
):
271+
assert message is None or type(message) == str # noqa: E721
272+
super().__init__(message)
273+
self._message = message
274+
return
275+
276+
@property
277+
def message(self) -> str:
278+
assert self._message is None or type(self._message) == str # noqa: E721
279+
if self._message is None:
280+
return ""
281+
return self._message
282+
283+
def __repr__(self) -> str:
284+
args = []
285+
286+
if self._message is not None:
287+
args.append(("message", self._message))
288+
289+
result = "{}(".format(type(self).__name__)
290+
sep = ""
291+
for a in args:
292+
result += sep + a[0] + "=" + repr(a[1])
293+
sep = ", "
294+
continue
295+
result += ")"
296+
return result
159297

160298

161299
assert ExecUtilException.__name__ == "ExecUtilException"

src/node.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@
7171
CatchUpException, \
7272
ExecUtilException, \
7373
QueryException, \
74+
QueryTimeoutException, \
7475
StartNodeException, \
7576
TimeoutException, \
7677
InitNodeException, \
@@ -112,6 +113,9 @@
112113
OperationalError = pglib.OperationalError
113114

114115

116+
assert TimeoutException == QueryTimeoutException
117+
118+
115119
class ProcessProxy(object):
116120
"""
117121
Wrapper for psutil.Process
@@ -1620,7 +1624,7 @@ def poll_query_until(self,
16201624
time.sleep(sleep_time)
16211625
attempts += 1
16221626

1623-
raise TimeoutException('Query timeout')
1627+
raise QueryTimeoutException('Query timeout', query)
16241628

16251629
@method_decorator(positional_args_hack(['dbname', 'query']))
16261630
def execute(self,

tests/test_testgres_common.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
from src import StartNodeException
2828
from src import QueryException
2929
from src import ExecUtilException
30-
from src import TimeoutException
30+
from src import QueryTimeoutException
3131
from src import InvalidOperationException
3232
from src import BackupException
3333
from src import ProgrammingError
@@ -864,7 +864,7 @@ def test_poll_query_until(self, node_svc: PostgresNodeService):
864864
expected=None)
865865

866866
# check arbitrary expected value, fail
867-
with pytest.raises(expected_exception=TimeoutException):
867+
with pytest.raises(expected_exception=QueryTimeoutException):
868868
node.poll_query_until(query='select 3',
869869
expected=1,
870870
max_attempts=3,
@@ -874,7 +874,7 @@ def test_poll_query_until(self, node_svc: PostgresNodeService):
874874
node.poll_query_until(query='select 2', expected=2)
875875

876876
# check timeout
877-
with pytest.raises(expected_exception=TimeoutException):
877+
with pytest.raises(expected_exception=QueryTimeoutException):
878878
node.poll_query_until(query='select 1 > 2',
879879
max_attempts=3,
880880
sleep_time=0.01)
@@ -884,7 +884,7 @@ def test_poll_query_until(self, node_svc: PostgresNodeService):
884884
node.poll_query_until(query='dummy1')
885885

886886
# check ProgrammingError, ok
887-
with pytest.raises(expected_exception=(TimeoutException)):
887+
with pytest.raises(expected_exception=(QueryTimeoutException)):
888888
node.poll_query_until(query='dummy2',
889889
max_attempts=3,
890890
sleep_time=0.01,

tests/units/exceptions/BackupException/__init__.py

Whitespace-only changes.
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
from src.exceptions import BackupException
2+
from src.exceptions import TestgresException as testgres__TestgresException
3+
4+
5+
class TestSet001_Constructor:
6+
def test_001__default(self):
7+
e = BackupException()
8+
assert type(e) == BackupException # noqa: E721
9+
assert isinstance(e, testgres__TestgresException)
10+
assert e.source is None
11+
assert e.message == ""
12+
assert str(e) == ""
13+
assert repr(e) == "BackupException()"
14+
return
15+
16+
def test_002__message(self):
17+
e = BackupException(message="abc\n123")
18+
assert type(e) == BackupException # noqa: E721
19+
assert isinstance(e, testgres__TestgresException)
20+
assert e.source is None
21+
assert e.message == "abc\n123"
22+
assert str(e) == "abc\n123"
23+
assert repr(e) == "BackupException(message='abc\\n123')"
24+
return

tests/units/exceptions/CatchUpException/__init__.py

Whitespace-only changes.
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
from src.exceptions import CatchUpException
2+
from src.exceptions import TestgresException as testgres__TestgresException
3+
4+
5+
class TestSet001_Constructor:
6+
def test_001__default(self):
7+
e = CatchUpException()
8+
assert type(e) == CatchUpException # noqa: E721
9+
assert isinstance(e, testgres__TestgresException)
10+
assert e.source is None
11+
assert e.message == ""
12+
assert str(e) == ""
13+
assert repr(e) == "CatchUpException()"
14+
return
15+
16+
def test_002__message(self):
17+
e = CatchUpException(message="abc\n123")
18+
assert type(e) == CatchUpException # noqa: E721
19+
assert isinstance(e, testgres__TestgresException)
20+
assert e.source is None
21+
assert e.message == "abc\n123"
22+
assert str(e) == "abc\n123"
23+
assert repr(e) == "CatchUpException(message='abc\\n123')"
24+
return

tests/units/exceptions/InitNodeException/__init__.py

Whitespace-only changes.
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
from src.exceptions import InitNodeException
2+
from src.exceptions import TestgresException as testgres__TestgresException
3+
4+
5+
class TestSet001_Constructor:
6+
def test_001__default(self):
7+
e = InitNodeException()
8+
assert type(e) == InitNodeException # noqa: E721
9+
assert isinstance(e, testgres__TestgresException)
10+
assert e.source is None
11+
assert e.message == ""
12+
assert str(e) == ""
13+
assert repr(e) == "InitNodeException()"
14+
return
15+
16+
def test_002__message(self):
17+
e = InitNodeException(message="abc\n123")
18+
assert type(e) == InitNodeException # noqa: E721
19+
assert isinstance(e, testgres__TestgresException)
20+
assert e.source is None
21+
assert e.message == "abc\n123"
22+
assert str(e) == "abc\n123"
23+
assert repr(e) == "InitNodeException(message='abc\\n123')"
24+
return

0 commit comments

Comments
 (0)