Skip to content

Commit fbae33b

Browse files
committed
Make long_running_operation decorator more specific
It should be specific to the particular D-Bus method that launches the long-running operation. Signed-off-by: mulhern <amulhern@redhat.com>
1 parent 10b24d3 commit fbae33b

3 files changed

Lines changed: 64 additions & 25 deletions

File tree

src/stratis_cli/_actions/_crypt.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ class CryptActions:
5858
"""
5959

6060
@staticmethod
61-
@long_running_operation
61+
@long_running_operation(method_names=["EncryptPool"])
6262
def encrypt(namespace: Namespace):
6363
"""
6464
Encrypt a previously unencrypted pool.
@@ -123,7 +123,7 @@ def encrypt(namespace: Namespace):
123123
)
124124

125125
@staticmethod
126-
@long_running_operation
126+
@long_running_operation(method_names=["DecryptPool"])
127127
def unencrypt(namespace: Namespace):
128128
"""
129129
Unencrypt a previously encrypted pool.
@@ -169,7 +169,7 @@ def unencrypt(namespace: Namespace):
169169
)
170170

171171
@staticmethod
172-
@long_running_operation
172+
@long_running_operation(method_names=["ReencryptPool"])
173173
def reencrypt(namespace: Namespace):
174174
"""
175175
Reencrypt an already encrypted pool with a new key.

src/stratis_cli/_actions/_utils.py

Lines changed: 37 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
from collections.abc import Iterator
2727
from enum import Enum
2828
from functools import wraps
29-
from typing import Any, Callable, Optional, Tuple
29+
from typing import Any, Callable, List, Optional, Tuple
3030
from uuid import UUID
3131

3232
# isort: THIRDPARTY
@@ -36,7 +36,7 @@
3636
from justbytes import Range
3737

3838
# isort: FIRSTPARTY
39-
from dbus_python_client_gen import DPClientInvocationError
39+
from dbus_python_client_gen import DPClientInvocationError, DPClientMethodCallContext
4040

4141
from .._errors import (
4242
StratisCliKeyfileNotFoundError,
@@ -315,23 +315,44 @@ def get_errors(exc: BaseException) -> Iterator[BaseException]:
315315
exc = exc.__cause__
316316

317317

318-
def long_running_operation(func: Callable) -> Callable:
318+
def long_running_operation(
319+
*, method_names: List[str]
320+
) -> Callable[[Callable], Callable]:
319321
"""
320322
Mark a function as a long running operation and catch and ignore NoReply
321-
D-Bus exception.
323+
D-Bus exception so long as the method raising the exception is one
324+
of the methods specified in method_names.
322325
"""
323326

324-
@wraps(func)
325-
def wrapper(namespace: Namespace):
326-
try:
327-
func(namespace)
328-
except DPClientInvocationError as err:
329-
if not any(
330-
isinstance(e, DBusException)
331-
and e.get_dbus_name() == "org.freedesktop.DBus.Error.NoReply"
332-
for e in get_errors(err)
333-
):
327+
def decorator(func: Callable) -> Callable:
328+
"""
329+
Decorator
330+
"""
331+
332+
@wraps(func)
333+
def wrapper(namespace: Namespace):
334+
"""
335+
Wrapper
336+
"""
337+
try:
338+
func(namespace)
339+
except DPClientInvocationError as err:
340+
if not any(
341+
isinstance(e, DBusException)
342+
and e.get_dbus_name() == "org.freedesktop.DBus.Error.NoReply"
343+
for e in get_errors(err)
344+
):
345+
raise err
346+
347+
context = err.context
348+
if (
349+
isinstance(context, DPClientMethodCallContext)
350+
and context.method_name in method_names
351+
):
352+
print("Operation initiated", file=sys.stderr)
353+
334354
raise err
335-
print("Operation initiated", file=sys.stderr)
336355

337-
return wrapper
356+
return wrapper
357+
358+
return decorator

tests/unit/test_running.py

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
import dbus
2323

2424
# isort: FIRSTPARTY
25-
from dbus_python_client_gen import DPClientInvocationError
25+
from dbus_python_client_gen import DPClientInvocationError, DPClientMethodCallContext
2626

2727
# isort: LOCAL
2828
from stratis_cli._actions._utils import long_running_operation
@@ -34,20 +34,38 @@ class LongRunningOperationTestCase(unittest.TestCase):
3434
engine.
3535
"""
3636

37-
def test_raise_dbus_exception(self):
37+
def test_catch_dbus_exception(self):
3838
"""
3939
Should succeed because it catches the distinguishing NoReply D-Bus
40-
error.
40+
error from the identified method.
4141
"""
4242

4343
def raises_error(_):
4444
raise DPClientInvocationError(
45-
"fake", "intf", None
45+
"fake", "intf", DPClientMethodCallContext("MethodName", [])
4646
) from dbus.exceptions.DBusException(
4747
name="org.freedesktop.DBus.Error.NoReply"
4848
)
4949

50-
self.assertIsNone(long_running_operation(raises_error)(None))
50+
self.assertIsNone(
51+
long_running_operation(method_names=["MethodName"])(raises_error)(None)
52+
)
53+
54+
def test_raise_dbus_exception_no_name_match(self):
55+
"""
56+
Should succeed because it catches the distinguishing NoReply D-Bus
57+
error from the identified method.
58+
"""
59+
60+
def raises_error(_):
61+
raise DPClientInvocationError(
62+
"fake", "intf", DPClientMethodCallContext("MethodName", [])
63+
) from dbus.exceptions.DBusException(
64+
name="org.freedesktop.DBus.Error.NoReply"
65+
)
66+
67+
with self.assertRaises(DPClientInvocationError):
68+
long_running_operation(method_names=["OtherMethodName"])(raises_error)(None)
5169

5270
def test_no_dbus_exception(self):
5371
"""
@@ -58,4 +76,4 @@ def raises_error(_):
5876
raise DPClientInvocationError("fake", "intf", None)
5977

6078
with self.assertRaises(DPClientInvocationError):
61-
long_running_operation(raises_error)(None)
79+
long_running_operation(method_names=["OtherMethodName"])(raises_error)(None)

0 commit comments

Comments
 (0)