Skip to content

Commit c8c9696

Browse files
committed
chore: create module for setting up performance metrics
1 parent a2e22eb commit c8c9696

File tree

4 files changed

+111
-10
lines changed

4 files changed

+111
-10
lines changed

api/src/opentrons/cli/analyze.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,7 @@
2828
)
2929

3030
from opentrons_shared_data.robot.dev_types import RobotType
31-
from opentrons import get_robot_context_tracker
32-
33-
_robot_context_tracker = get_robot_context_tracker()
31+
from opentrons.util.performance_helpers import track_analysis
3432

3533

3634
@click.command()
@@ -66,7 +64,7 @@ def _get_input_files(files_and_dirs: Sequence[Path]) -> List[Path]:
6664
return results
6765

6866

69-
@_robot_context_tracker.track_analysis()
67+
@track_analysis
7068
async def _analyze(
7169
files_and_dirs: Sequence[Path],
7270
json_output: Optional[AsyncPath],
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
"""Performance helpers for tracking robot context."""
2+
3+
from pathlib import Path
4+
from opentrons_shared_data.performance.dev_types import (
5+
SupportsTracking,
6+
F,
7+
RobotContextState,
8+
)
9+
from opentrons_shared_data.robot.dev_types import RobotTypeEnum
10+
from opentrons.config import (
11+
get_performance_metrics_data_dir,
12+
robot_configs,
13+
feature_flags as ff,
14+
)
15+
from typing import Callable, Type
16+
17+
performance_metrics_dir: Path = get_performance_metrics_data_dir()
18+
should_track: bool = ff.enable_performance_metrics(
19+
RobotTypeEnum.robot_literal_to_enum(robot_configs.load().model)
20+
)
21+
22+
23+
def _handle_package_import() -> Type[SupportsTracking]:
24+
"""Handle the import of the performance_metrics package.
25+
26+
If the package is not available, return a stubbed tracker.
27+
"""
28+
try:
29+
from performance_metrics import RobotContextTracker
30+
31+
return RobotContextTracker
32+
except ImportError:
33+
return StubbedTracker
34+
35+
36+
package_to_use = _handle_package_import()
37+
_robot_context_tracker: SupportsTracking | None = None
38+
39+
40+
class StubbedTracker(SupportsTracking):
41+
"""A stubbed tracker that does nothing."""
42+
43+
def __init__(self, storage_dir: Path, should_track: bool) -> None:
44+
"""Initialize the stubbed tracker."""
45+
pass
46+
47+
def track(self, state: RobotContextState) -> Callable[[F], F]:
48+
"""Return the function unchanged."""
49+
50+
def inner_decorator(func: F) -> F:
51+
"""Return the function unchanged."""
52+
return func
53+
54+
return inner_decorator
55+
56+
def store(self) -> None:
57+
"""Do nothing."""
58+
pass
59+
60+
61+
def _get_robot_context_tracker() -> SupportsTracking:
62+
"""Singleton for the robot context tracker."""
63+
global _robot_context_tracker
64+
if _robot_context_tracker is None:
65+
_robot_context_tracker = package_to_use(performance_metrics_dir, should_track)
66+
return _robot_context_tracker
67+
68+
69+
def track_analysis(func: F) -> F:
70+
"""Track the analysis of a protocol."""
71+
return _get_robot_context_tracker().track(RobotContextState.ANALYZING_PROTOCOL)(
72+
func
73+
)

api/tests/opentrons/cli/test_cli.py

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,15 @@
1111

1212
import pytest
1313
from click.testing import CliRunner
14-
from opentrons import get_robot_context_tracker
14+
from opentrons.util.performance_helpers import _get_robot_context_tracker
1515

1616

1717
# Enable tracking for the RobotContextTracker
1818
# This must come before the import of the analyze CLI
19-
context_tracker = get_robot_context_tracker()
20-
context_tracker._should_track = True
19+
context_tracker = _get_robot_context_tracker()
20+
21+
# Ignore the type error for the next line, as we're setting a private attribute for testing purposes
22+
context_tracker._should_track = True # type: ignore[attr-defined]
2123

2224
from opentrons.cli.analyze import analyze # noqa: E402
2325

@@ -253,7 +255,7 @@ def test_python_error_line_numbers(
253255
assert error["detail"] == expected_detail
254256

255257

256-
def test_tracking_of_analyis_with_robot_context_tracker(tmp_path: Path) -> None:
258+
def test_track_analysis(tmp_path: Path) -> None:
257259
"""Test that the RobotContextTracker tracks analysis."""
258260
protocol_source = textwrap.dedent(
259261
"""
@@ -267,8 +269,8 @@ def run(protocol):
267269
protocol_source_file = tmp_path / "protocol.py"
268270
protocol_source_file.write_text(protocol_source, encoding="utf-8")
269271

270-
before_analysis = len(context_tracker._storage)
272+
before_analysis = len(context_tracker._storage) # type: ignore[attr-defined]
271273

272274
_get_analysis_result([protocol_source_file])
273275

274-
assert len(context_tracker._storage) == before_analysis + 1
276+
assert len(context_tracker._storage) == before_analysis + 1 # type: ignore[attr-defined]
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
"""Tests for performance_helpers."""
2+
3+
from pathlib import Path
4+
from opentrons_shared_data.performance.dev_types import RobotContextState
5+
from opentrons.util.performance_helpers import (
6+
StubbedTracker,
7+
_get_robot_context_tracker,
8+
)
9+
10+
11+
def test_return_function_unchanged() -> None:
12+
"""Test that the function is returned unchanged when using StubbedTracker."""
13+
tracker = StubbedTracker(Path("/path/to/storage"), True)
14+
15+
def func_to_track() -> None:
16+
pass
17+
18+
assert (
19+
tracker.track(RobotContextState.ANALYZING_PROTOCOL)(func_to_track)
20+
is func_to_track
21+
)
22+
23+
24+
def test_singleton_tracker() -> None:
25+
"""Test that the tracker is a singleton."""
26+
tracker = _get_robot_context_tracker()
27+
tracker2 = _get_robot_context_tracker()
28+
assert tracker is tracker2

0 commit comments

Comments
 (0)