Skip to content

Commit 95faca4

Browse files
committed
suppress double warning, handle missing class
1 parent af3f542 commit 95faca4

5 files changed

Lines changed: 21 additions & 5 deletions

File tree

python/packages/jumpstarter/jumpstarter/client/client.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import logging
2+
import os
23
from collections import OrderedDict, defaultdict
34
from contextlib import ExitStack, asynccontextmanager
45
from graphlib import TopologicalSorter
@@ -59,7 +60,9 @@ async def client_from_channel(
5960
client_class = import_class(report.labels["jumpstarter.dev/client"], allow, unsafe)
6061
except MissingDriverError as e:
6162
# Create stub client instead of failing
62-
logger.warning("Driver client '%s' is not available.", e.class_path)
63+
# Suppress duplicate warnings
64+
if not os.environ.get("_JMP_SUPPRESS_DRIVER_WARNINGS"):
65+
logger.warning("Driver client '%s' is not available.", e.class_path)
6366
client_class = StubDriverClient
6467

6568
client = client_class(

python/packages/jumpstarter/jumpstarter/common/importlib.py

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,9 +64,20 @@ def import_class(class_path: str, allow: list[str], unsafe: bool):
6464
try:
6565
return cached_import(module_path, class_name)
6666
except ModuleNotFoundError as e:
67+
# Only convert to MissingDriverError if the missing module is the target module itself
68+
# (or a parent package of it). If it's a transitive dependency, re-raise to preserve
69+
# the original error and show the real cause.
70+
if e.name and (e.name == module_path or module_path.startswith(f"{e.name}.")):
71+
raise MissingDriverError(
72+
message=_format_missing_driver_message(class_path),
73+
class_path=class_path,
74+
) from e
75+
else:
76+
# Transitive dependency missing - re-raise to show the real cause
77+
raise
78+
except AttributeError as e:
79+
# Module exists but class doesn't - treat in a similar way to missing module
6780
raise MissingDriverError(
6881
message=_format_missing_driver_message(class_path),
6982
class_path=class_path,
7083
) from e
71-
except AttributeError as e:
72-
raise ImportError(f"{module_path} doesn't have specified class {class_name}") from e

python/packages/jumpstarter/jumpstarter/common/importlib_test.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
import pytest
22

3+
from .exceptions import MissingDriverError
34
from .importlib import import_class
45

56

67
def test_import_class():
78
import_class("os.open", [], True)
89

9-
with pytest.raises(ImportError):
10+
with pytest.raises(MissingDriverError):
1011
import_class("os.invalid", [], True)
1112

1213
with pytest.raises(ImportError):

python/packages/jumpstarter/jumpstarter/common/utils.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ def launch_shell(
108108
common_env = os.environ | {
109109
JUMPSTARTER_HOST: host,
110110
JMP_DRIVERS_ALLOW: "UNSAFE" if unsafe else ",".join(allow),
111+
"_JMP_SUPPRESS_DRIVER_WARNINGS": "1", # Already warned during client initialization
111112
}
112113

113114
if command:

python/packages/jumpstarter/jumpstarter/config/exporter.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ def instantiate(self) -> Driver:
4848
driver_class = import_class(self.root.type, [], True)
4949
except MissingDriverError:
5050
raise ConfigurationError(
51-
f"Exporter configuration: Driver '{self.root.type}' is not installed.\n\n"
51+
f"Driver '{self.root.type}' is not installed. Please check exporter configuration."
5252
) from None
5353

5454
children = {name: child.instantiate() for name, child in self.root.children.items()}

0 commit comments

Comments
 (0)