Skip to content

Commit 981dbe8

Browse files
ExecUtilException is updated (RO props) (#4)
* ExecUtilException is updated (RO props) Changes: - message, command, exit_code, out, error are RO-props now - new: description - message returns dynamically created text - description replaces message - __str__ returns message - new: __repl__ method Tests are added, too. * testgres.common v1.0.0 [master] - ExecUtilException::__str__ is inherited from TestgresException - TestgresException provides RO-property 'source'. It has None value
1 parent 5022daf commit 981dbe8

5 files changed

Lines changed: 242 additions & 21 deletions

File tree

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ classifiers = [
4949
dependencies = [
5050
"psutil",
5151
"six>=1.9.0",
52-
"testgres.common>=0.0.3,<1.0.0",
52+
"testgres.common @ git+https://github.com/postgrespro/testgres.common.git@1.0.0",
5353
]
5454

5555
[project.urls]

src/exceptions.py

Lines changed: 102 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,38 +3,122 @@
33
from testgres.common.exceptions import TestgresException
44
from testgres.common.exceptions import InvalidOperationException
55
import six
6+
import typing
7+
8+
9+
T_CMD = typing.Union[str, list]
10+
T_OUT_DATA = typing.Union[str, bytes]
11+
T_ERR_DATA = typing.Union[str, bytes]
612

713

814
class ExecUtilException(TestgresException):
9-
def __init__(self, message=None, command=None, exit_code=0, out=None, error=None):
10-
super(ExecUtilException, self).__init__(message)
15+
_description: typing.Optional[str]
16+
_command: typing.Optional[T_CMD]
17+
_exit_code: typing.Optional[int]
18+
_out: typing.Optional[T_OUT_DATA]
19+
_error: typing.Optional[T_ERR_DATA]
20+
21+
def __init__(
22+
self,
23+
message: typing.Optional[str] = None,
24+
command: typing.Optional[T_CMD] = None,
25+
exit_code: typing.Optional[int] = None,
26+
out: typing.Optional[T_OUT_DATA] = None,
27+
error: typing.Optional[T_ERR_DATA] = None,
28+
):
29+
assert message is None or type(message) == str # noqa: E721
30+
assert command is None or type(command) in [str, list] # noqa: E721
31+
assert exit_code is None or type(exit_code) == int # noqa: E721
32+
assert out is None or type(out) in [str, bytes] # noqa: E721
33+
assert error is None or type(error) in [str, bytes] # noqa: E721
1134

12-
self.message = message
13-
self.command = command
14-
self.exit_code = exit_code
15-
self.out = out
16-
self.error = error
35+
super().__init__(message)
1736

18-
def __str__(self):
37+
self._description = message
38+
self._command = command
39+
self._exit_code = exit_code
40+
self._out = out
41+
self._error = error
42+
43+
@property
44+
def message(self) -> str:
1945
msg = []
2046

21-
if self.message:
22-
msg.append(self.message)
47+
if self._description:
48+
msg.append(self._description)
2349

24-
if self.command:
25-
command_s = ' '.join(self.command) if isinstance(self.command, list) else self.command
50+
if self._command:
51+
command_s = ' '.join(self._command) if isinstance(self._command, list) else self._command
2652
msg.append(u'Command: {}'.format(command_s))
2753

28-
if self.exit_code:
29-
msg.append(u'Exit code: {}'.format(self.exit_code))
54+
if self._exit_code:
55+
msg.append(u'Exit code: {}'.format(self._exit_code))
3056

31-
if self.error:
32-
msg.append(u'---- Error:\n{}'.format(self.error))
57+
if self._error:
58+
msg.append(u'---- Error:\n{}'.format(self._error))
3359

34-
if self.out:
60+
if self._out:
3561
msg.append(u'---- Out:\n{}'.format(self.out))
3662

37-
return self.convert_and_join(msg)
63+
r = self.convert_and_join(msg)
64+
assert type(r) == str # noqa: E721
65+
return r
66+
67+
@property
68+
def description(self) -> typing.Optional[str]:
69+
assert self._description is None or type(self._description) == str # noqa: E721
70+
return self._description
71+
72+
@property
73+
def command(self) -> typing.Optional[T_CMD]:
74+
assert self._command is None or type(self._command) in [str, list] # noqa: E721
75+
return self._command
76+
77+
@property
78+
def exit_code(self) -> typing.Optional[int]:
79+
assert self._exit_code is None or type(self._exit_code) == int # noqa: E721
80+
return self._exit_code
81+
82+
@property
83+
def out(self) -> typing.Optional[T_OUT_DATA]:
84+
assert self._out is None or type(self._out) in [str, bytes] # noqa: E721
85+
return self._out
86+
87+
@property
88+
def error(self) -> typing.Optional[T_ERR_DATA]:
89+
assert self._error is None or type(self._error) in [str, bytes] # noqa: E721
90+
return self._error
91+
92+
def __repr__(self) -> str:
93+
args = []
94+
95+
if self._description is not None:
96+
args.append(("message", self._description))
97+
98+
if self._command is not None:
99+
args.append(("command", self._command))
100+
101+
if self._exit_code is not None:
102+
args.append(("exit_code", self._exit_code))
103+
104+
if self._out is not None:
105+
args.append(("out", self._out))
106+
107+
if self._error is not None:
108+
args.append(("error", self._error))
109+
110+
assert type(self) == ExecUtilException # noqa: E721
111+
assert __class__ == ExecUtilException # noqa: E721
112+
113+
result = "{}(".format(__class__.__name__)
114+
sep = ""
115+
for a in args:
116+
if a[1] is not None:
117+
result += sep + a[0] + "=" + repr(a[1])
118+
sep = ", "
119+
continue
120+
result += ")"
121+
return result
38122

39123
@staticmethod
40124
def convert_and_join(msg_list):

tests/requirements.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ pytest
22
pytest-xdist
33
psutil
44
six
5-
testgres.common>=0.0.2,<1.0.0
5+
git+https://github.com/postgrespro/testgres.common.git@1.0.0
66
black
77
flake8
88
flake8-pyproject

tests/test_os_ops_remote.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,8 @@ def test_rmdirs__try_to_delete_file(self, os_ops: OsOperations):
3333

3434
assert os.path.exists(path)
3535
assert type(x.value) == ExecUtilException # noqa: E721
36-
assert x.value.message == "Utility exited with non-zero code (20). Error: `cannot remove '" + path + "': it is not a directory`"
36+
assert x.value.description == "Utility exited with non-zero code (20). Error: `cannot remove '" + path + "': it is not a directory`"
37+
assert x.value.message.startswith(x.value.description)
3738
assert type(x.value.error) == str # noqa: E721
3839
assert x.value.error.strip() == "cannot remove '" + path + "': it is not a directory"
3940
assert type(x.value.exit_code) == int # noqa: E721
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
from src.exceptions import ExecUtilException
2+
3+
4+
class TestSet001_Constructor:
5+
def test_001__default(self):
6+
e = ExecUtilException()
7+
assert e.source is None
8+
assert e.message == ""
9+
assert e.description is None
10+
assert e.command is None
11+
assert e.exit_code is None
12+
assert e.out is None
13+
assert e.error is None
14+
assert str(e) == ""
15+
assert repr(e) == "ExecUtilException()"
16+
return
17+
18+
def test_002__description(self):
19+
e = ExecUtilException("operation description")
20+
assert e.source is None
21+
assert e.message == "operation description"
22+
assert e.description == "operation description"
23+
assert e.command is None
24+
assert e.exit_code is None
25+
assert e.out is None
26+
assert e.error is None
27+
assert str(e) == "operation description"
28+
assert repr(e) == "ExecUtilException(message='operation description')"
29+
return
30+
31+
def test_003__commandList(self):
32+
e = ExecUtilException(command=["ls", "."])
33+
assert e.source is None
34+
assert e.message == "Command: ls ."
35+
assert e.description is None
36+
assert e.command == ["ls", "."]
37+
assert e.exit_code is None
38+
assert e.out is None
39+
assert e.error is None
40+
assert str(e) == "Command: ls ."
41+
assert repr(e) == "ExecUtilException(command=['ls', '.'])"
42+
return
43+
44+
def test_004__commandStr(self):
45+
e = ExecUtilException(command="ls /home")
46+
assert e.source is None
47+
assert e.message == "Command: ls /home"
48+
assert e.description is None
49+
assert e.command == "ls /home"
50+
assert e.exit_code is None
51+
assert e.out is None
52+
assert e.error is None
53+
assert str(e) == "Command: ls /home"
54+
assert repr(e) == "ExecUtilException(command='ls /home')"
55+
return
56+
57+
def test_005__exit_code(self):
58+
e = ExecUtilException(exit_code=123)
59+
assert e.source is None
60+
assert e.message == "Exit code: 123"
61+
assert e.description is None
62+
assert e.command is None
63+
assert e.exit_code == 123
64+
assert e.out is None
65+
assert e.error is None
66+
assert str(e) == "Exit code: 123"
67+
assert repr(e) == "ExecUtilException(exit_code=123)"
68+
return
69+
70+
def test_006__outBytes(self):
71+
e = ExecUtilException(out=b'abcdefg\n123456')
72+
assert e.source is None
73+
assert e.message == "---- Out:\nb'abcdefg\\n123456'"
74+
assert e.description is None
75+
assert e.command is None
76+
assert e.exit_code is None
77+
assert e.out == b'abcdefg\n123456'
78+
assert e.error is None
79+
assert str(e) == "---- Out:\nb'abcdefg\\n123456'"
80+
assert repr(e) == "ExecUtilException(out=b'abcdefg\\n123456')"
81+
return
82+
83+
def test_007__outStr(self):
84+
e = ExecUtilException(out='abcdefg\n123456')
85+
assert e.source is None
86+
assert e.message == "---- Out:\nabcdefg\n123456"
87+
assert e.description is None
88+
assert e.command is None
89+
assert e.exit_code is None
90+
assert e.out == 'abcdefg\n123456'
91+
assert e.error is None
92+
assert str(e) == "---- Out:\nabcdefg\n123456"
93+
assert repr(e) == "ExecUtilException(out='abcdefg\\n123456')"
94+
return
95+
96+
def test_008__errorBytes(self):
97+
e = ExecUtilException(error=b'abcdefg\n123456')
98+
assert e.source is None
99+
assert e.message == "---- Error:\nb'abcdefg\\n123456'"
100+
assert e.description is None
101+
assert e.command is None
102+
assert e.exit_code is None
103+
assert e.out is None
104+
assert e.error == b'abcdefg\n123456'
105+
assert str(e) == "---- Error:\nb'abcdefg\\n123456'"
106+
assert repr(e) == "ExecUtilException(error=b'abcdefg\\n123456')"
107+
return
108+
109+
def test_009__errorStr(self):
110+
e = ExecUtilException(error='abcdefg\n123456')
111+
assert e.source is None
112+
assert e.message == "---- Error:\nabcdefg\n123456"
113+
assert e.description is None
114+
assert e.command is None
115+
assert e.exit_code is None
116+
assert e.out is None
117+
assert e.error == 'abcdefg\n123456'
118+
assert str(e) == "---- Error:\nabcdefg\n123456"
119+
assert repr(e) == "ExecUtilException(error='abcdefg\\n123456')"
120+
return
121+
122+
def test_010__all(self):
123+
e = ExecUtilException('descr', ['rm', 'me'], -1, 'out\n123456', b'error\n321')
124+
125+
expected_msg = "descr\nCommand: rm me\nExit code: -1\n---- Error:\nb'error\\n321'\n---- Out:\nout\n123456"
126+
127+
assert e.source is None
128+
assert e.message == expected_msg
129+
assert e.description == "descr"
130+
assert e.command == ['rm', 'me']
131+
assert e.exit_code == -1
132+
assert e.out == 'out\n123456'
133+
assert e.error == b'error\n321'
134+
assert str(e) == expected_msg
135+
assert repr(e) == "ExecUtilException(message='descr', command=['rm', 'me'], exit_code=-1, out='out\\n123456', error=b'error\\n321')"
136+
return

0 commit comments

Comments
 (0)