Skip to content

Commit 4fbde87

Browse files
cleanup: remove unused helpers and legacy paths from SerialManager
Co-authored-by: openhands <openhands@all-hands.dev>
1 parent 80378ee commit 4fbde87

1 file changed

Lines changed: 4 additions & 167 deletions

File tree

benchmesh-serial-service/src/benchmesh_service/serial_manager.py

Lines changed: 4 additions & 167 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,7 @@
33
import time
44
import threading
55
import logging
6-
import importlib
7-
import inspect
8-
from typing import Dict, List, Any, Tuple
6+
from typing import Dict, List, Any
97
import yaml
108
from .logger import setup_logger
119
from .registry import DeviceRegistry
@@ -18,7 +16,6 @@
1816
from .metrics import MetricsRecorder
1917

2018
logger = logging.getLogger(__name__)
21-
IDENTIFY_INTERVAL = 1.0
2219

2320

2421
MANIFEST_ALIASES = {
@@ -48,158 +45,10 @@ def _load_manifest(driver_key: str) -> Dict:
4845

4946

5047

51-
def _get_class_channel_counts(dev: dict) -> Dict[str, int]:
52-
"""Return mapping of class -> channel count for a device from manifest."""
53-
out: Dict[str, int] = {}
54-
try:
55-
driver_key = dev.get("driver")
56-
manifest = _load_manifest(driver_key) if driver_key else None
57-
if not isinstance(manifest, dict):
58-
return out
59-
models = manifest.get("models") or {}
60-
model_key = dev.get("model")
61-
model_cfg = None
62-
if model_key and isinstance(models.get(model_key), dict):
63-
model_cfg = models.get(model_key)
64-
elif isinstance(models, dict) and models:
65-
model_cfg = next(iter(models.values()))
66-
if not isinstance(model_cfg, dict):
67-
return out
68-
inst_class_block = model_cfg.get("instrument_class") or {}
69-
for klass, cfg in (inst_class_block or {}).items():
70-
features = (cfg or {}).get("features") or {}
71-
try:
72-
ch = int(features.get("channels", 1) or 1)
73-
except Exception:
74-
ch = 1
75-
out[str(klass)] = max(1, ch)
76-
# Fallback: detect nested class blocks mistakenly placed under another class
77-
for subk, subcfg in (cfg or {}).items():
78-
if not isinstance(subcfg, dict):
79-
continue
80-
if subk in ("features", "modes", "pooling", "polling"):
81-
continue
82-
sub_features = (subcfg or {}).get("features") or {}
83-
if sub_features:
84-
try:
85-
sch = int(sub_features.get("channels", 1) or 1)
86-
except Exception:
87-
sch = 1
88-
out[str(subk)] = max(1, sch)
89-
return out
90-
except Exception:
91-
return out
92-
93-
94-
def _get_class_poll_intervals(dev: dict) -> Dict[str, float]:
95-
"""Return mapping of class -> poll interval (seconds) for classes that declare a polling method.
96-
97-
Only classes with a defined pooling/polling entry are included. This prevents polling
98-
classes that have no configured poll method.
99-
"""
100-
out: Dict[str, float] = {}
101-
try:
102-
driver_key = dev.get("driver")
103-
manifest = _load_manifest(driver_key) if driver_key else None
104-
if not isinstance(manifest, dict):
105-
return out
106-
models = manifest.get("models") or {}
107-
model_key = dev.get("model")
108-
model_cfg = None
109-
if model_key and isinstance(models.get(model_key), dict):
110-
model_cfg = models.get(model_key)
111-
elif isinstance(models, dict) and models:
112-
model_cfg = next(iter(models.values()))
113-
if not isinstance(model_cfg, dict):
114-
return out
115-
inst_class_block = model_cfg.get("instrument_class") or {}
116-
for klass, cfg in (inst_class_block or {}).items():
117-
pooling = (cfg or {}).get("pooling") or (cfg or {}).get("polling") or []
118-
# Pick the first polling entry we can use for the top-level class
119-
iv = None
120-
for entry in pooling:
121-
try:
122-
mname = entry.get("method")
123-
if mname:
124-
iv = float(entry.get("interval", 2.0))
125-
break
126-
except Exception:
127-
continue
128-
if iv is not None:
129-
out[str(klass)] = iv
130-
# Also detect nested class blocks and their pooling
131-
for subk, subcfg in (cfg or {}).items():
132-
if not isinstance(subcfg, dict) or subk in ("features", "modes", "pooling", "polling"):
133-
continue
134-
sub_pool = (subcfg or {}).get("pooling") or (subcfg or {}).get("polling") or []
135-
sub_iv = None
136-
for entry in sub_pool:
137-
try:
138-
mname = entry.get("method")
139-
if mname:
140-
sub_iv = float(entry.get("interval", 2.0))
141-
break
142-
except Exception:
143-
continue
144-
if sub_iv is not None:
145-
out[str(subk)] = sub_iv
146-
return out
147-
except Exception:
148-
return out
149-
def _load_driver_class(driver_key: str):
150-
"""Load a driver class given its key.
151-
152-
Supports both legacy flat modules (benchmesh_service.drivers.<driver_key>)
153-
and new layout with subpackages (benchmesh_service.drivers.<pkg>.<module>).
154-
The class is expected to be reachable from the imported module namespace,
155-
either defined there or re-exported by the package's __init__.py.
156-
"""
157-
tried = []
158-
folder_key = MANIFEST_ALIASES.get(driver_key, driver_key)
159-
160-
# Candidate import names in order of preference
161-
candidates = [
162-
f"benchmesh_service.drivers.{driver_key}",
163-
f"benchmesh_service.drivers.{folder_key}",
164-
f"benchmesh_service.drivers.{folder_key}.driver",
165-
# explicit known class module for tenma alias
166-
f"benchmesh_service.drivers.{folder_key}.driver" if folder_key == 'tenma_72' else None,
167-
]
168-
candidates = [c for c in candidates if c]
169-
170-
for mod_name in candidates:
171-
try:
172-
mod = importlib.import_module(mod_name)
173-
# Return first class exposed on the module namespace
174-
for _, obj in inspect.getmembers(mod, inspect.isclass):
175-
# Accept classes defined in the module or its submodules
176-
if getattr(obj, "__module__", "").startswith(mod.__name__):
177-
return obj
178-
# If no classes found yet but module imported, keep trying next candidate
179-
tried.append(mod_name)
180-
except Exception as e:
181-
tried.append(f"{mod_name} ({e.__class__.__name__}: {e})")
182-
continue
183-
184-
# As a fallback, attempt direct file import for <folder_key>/<driver_key>.py or <folder_key>/<folder_key>.py
185-
base_dir = os.path.join(os.path.dirname(__file__), 'drivers', folder_key)
186-
for file_base in (driver_key, folder_key, 'driver'):
187-
file_path = os.path.join(base_dir, f"{file_base}.py")
188-
if os.path.exists(file_path):
189-
try:
190-
spec = importlib.util.spec_from_file_location(f"benchmesh_service.drivers.{folder_key}.{file_base}", file_path)
191-
if spec and spec.loader:
192-
mod = importlib.util.module_from_spec(spec)
193-
spec.loader.exec_module(mod)
194-
for _, obj in inspect.getmembers(mod, inspect.isclass):
195-
# Only accept classes defined in this module (exclude imported helpers)
196-
if getattr(obj, "__module__", "").startswith(mod.__name__):
197-
return obj
198-
except Exception as e:
199-
tried.append(f"file:{file_path} ({e.__class__.__name__}: {e})")
200-
continue
20148

202-
raise ImportError(f"No driver class found for key '{driver_key}'. Tried: {tried}")
49+
50+
51+
# Note: legacy dynamic driver loader removed. DriverFactory is the single source of truth.
20352

20453

20554
class SerialManager:
@@ -325,18 +174,6 @@ def identify(self):
325174
self.metrics.inc_identify_fail(dev_id)
326175
return conn.driver
327176

328-
def _try_identify(self, drv):
329-
try:
330-
if hasattr(drv, 'identify'):
331-
return drv.identify()
332-
t = getattr(drv, 't', None)
333-
if t:
334-
t.write_line('*IDN?')
335-
return t.read_until_reol(256)
336-
except Exception as e:
337-
logger.warning("Identify failed: %s", e)
338-
raise
339-
return None
340177

341178
def _update_registry(self, dev_id: str, key: str, value: Any, klass: str | None = None):
342179
self.registry_obj.update(dev_id, key, value, klass)

0 commit comments

Comments
 (0)