Skip to content

Commit

Permalink
619 move to pyright (#632)
Browse files Browse the repository at this point in the history
  • Loading branch information
stan-dot authored Nov 21, 2024
1 parent a4e881d commit 86c5905
Showing 25 changed files with 102 additions and 92 deletions.
2 changes: 1 addition & 1 deletion .copier-answers.yml
Original file line number Diff line number Diff line change
@@ -16,4 +16,4 @@ github_org: DiamondLightSource
package_name: blueapi
pypi: true
repo_name: blueapi
type_checker: mypy
type_checker: pyright
1 change: 1 addition & 0 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
@@ -27,6 +27,7 @@
"redhat.vscode-yaml",
"ryanluker.vscode-coverage-gutters",
"charliermarsh.ruff",
"ms-pyright.pyright",
"ms-azuretools.vscode-docker"
]
}
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -44,7 +44,6 @@ nosetests.xml
coverage.xml
cov.xml
.pytest_cache/
.mypy_cache/

# Translations
*.mo
16 changes: 7 additions & 9 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -35,7 +35,7 @@ dependencies = [
"event-model==1.22.1", # https://github.com/DiamondLightSource/blueapi/issues/684
"opentelemetry-distro>=0.48b0",
"opentelemetry-instrumentation-fastapi>=0.48b0",
"observability-utils>=0.1.4"
"observability-utils>=0.1.4",
]
dynamic = ["version"]
license.file = "LICENSE"
@@ -49,8 +49,8 @@ dev = [
"pipdeptree",
"pre-commit>=3.8.0",
"pydata-sphinx-theme>=0.15.4",
"mypy",
"pytest",
"pyright",
"pytest-cov",
"pytest-asyncio",
"responses",
@@ -82,11 +82,9 @@ name = "Callum Forrester"
[tool.setuptools_scm]
version_file = "src/blueapi/_version.py"

[tool.mypy]
ignore_missing_imports = true # Ignore missing stubs in imported modules

# necessary for tracing sdk to work with mypy, set false once migraion to pyright complete
namespace_packages = true
[tool.pyright]
typeCheckingMode = "standard"
reportMissingImports = false # Ignore missing stubs in imported modules

[tool.pytest.ini_options]
# Run pytest with all our checkers, and don't spam us with massive tracebacks on error
@@ -122,12 +120,12 @@ passenv = *
allowlist_externals =
pytest
pre-commit
mypy
pyright
sphinx-build
sphinx-autobuild
commands =
pre-commit: pre-commit run --all-files --show-diff-on-failure {posargs}
type-checking: mypy src tests {posargs}
type-checking: pyright src tests {posargs}
tests: pytest --cov=blueapi --cov-report term --cov-report xml:cov.xml tests/unit_tests {posargs}
docs: sphinx-{posargs:build -EW --keep-going} -T docs build/html
system-test: pytest tests/system_tests {posargs}
19 changes: 8 additions & 11 deletions src/blueapi/cli/cli.py
Original file line number Diff line number Diff line change
@@ -163,19 +163,16 @@ def get_devices(obj: dict) -> None:
def listen_to_events(obj: dict) -> None:
"""Listen to events output by blueapi"""
config: ApplicationConfig = obj["config"]
if config.stomp is not None:
event_bus_client = EventBusClient(
StompClient.for_broker(
broker=Broker(
host=config.stomp.host,
port=config.stomp.port,
auth=config.stomp.auth,
)
assert config.stomp is not None, "Message bus needs to be configured"
event_bus_client = EventBusClient(
StompClient.for_broker(
broker=Broker(
host=config.stomp.host,
port=config.stomp.port,
auth=config.stomp.auth,
)
)
else:
raise RuntimeError("Message bus needs to be configured")

)
fmt = obj["fmt"]

def on_event(
19 changes: 9 additions & 10 deletions src/blueapi/client/client.py
Original file line number Diff line number Diff line change
@@ -46,17 +46,16 @@ def __init__(
@classmethod
def from_config(cls, config: ApplicationConfig) -> "BlueapiClient":
rest = BlueapiRestClient(config.api)
if config.stomp is not None:
stomp_client = StompClient.for_broker(
broker=Broker(
host=config.stomp.host,
port=config.stomp.port,
auth=config.stomp.auth,
)
if config.stomp is None:
return cls(rest)
client = StompClient.for_broker(
broker=Broker(
host=config.stomp.host,
port=config.stomp.port,
auth=config.stomp.auth,
)
events = EventBusClient(stomp_client)
else:
events = None
)
events = EventBusClient(client)
return cls(rest, events)

@start_as_current_span(TRACER)
6 changes: 3 additions & 3 deletions src/blueapi/core/context.py
Original file line number Diff line number Diff line change
@@ -143,10 +143,10 @@ def my_plan(a: int, b: str):
if not is_bluesky_plan_generator(plan):
raise TypeError(f"{plan} is not a valid plan generator function")

model = create_model( # type: ignore
model = create_model(
plan.__name__,
__config__=BlueapiPlanModelConfig,
**self._type_spec_for_function(plan),
**self._type_spec_for_function(plan), # type: ignore
)
self.plans[plan.__name__] = Plan(
name=plan.__name__, model=model, description=plan.__doc__
@@ -284,7 +284,7 @@ def _convert_type(self, typ: type | Any) -> type:
root = get_origin(typ)
if root == UnionType:
root = Union
return root[new_types] if root else typ
return root[new_types] if root else typ # type: ignore
return typ


7 changes: 2 additions & 5 deletions src/blueapi/core/device_lookup.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
from typing import Any, TypeVar
from typing import Any

from .bluesky_types import Device, is_bluesky_compatible_device

#: Device obeying Bluesky protocols
D = TypeVar("D", bound=Device)


def find_component(obj: Any, addr: list[str]) -> D | None:
def find_component(obj: Any, addr: list[str]) -> Device | None:
"""
Best effort function to locate a child device, either in a dictionary of
devices or a device with child attributes.
14 changes: 8 additions & 6 deletions src/blueapi/service/interface.py
Original file line number Diff line number Diff line change
@@ -6,7 +6,7 @@
from bluesky_stomp.messaging import StompClient
from bluesky_stomp.models import Broker, DestinationBase, MessageTopic

from blueapi.config import ApplicationConfig
from blueapi.config import ApplicationConfig, StompConfig
from blueapi.core.context import BlueskyContext
from blueapi.core.event import EventStream
from blueapi.service.model import DeviceModel, PlanModel, WorkerTask
@@ -50,11 +50,13 @@ def worker() -> TaskWorker:

@cache
def stomp_client() -> StompClient | None:
stomp_config = config().stomp
stomp_config: StompConfig | None = config().stomp
if stomp_config is not None:
stomp_client = StompClient.for_broker(
client = StompClient.for_broker(
broker=Broker(
host=stomp_config.host, port=stomp_config.port, auth=stomp_config.auth
host=stomp_config.host,
port=stomp_config.port,
auth=stomp_config.auth, # type: ignore
)
)

@@ -68,8 +70,8 @@ def stomp_client() -> StompClient | None:
task_worker.data_events: event_topic,
}
)
stomp_client.connect()
return stomp_client
client.connect()
return client
else:
return None

6 changes: 3 additions & 3 deletions src/blueapi/service/main.py
Original file line number Diff line number Diff line change
@@ -101,7 +101,7 @@ def get_app():
TRACER = get_tracer("interface")


async def on_key_error_404(_: Request, __: KeyError):
async def on_key_error_404(_: Request, __: Exception):
return JSONResponse(
status_code=status.HTTP_404_NOT_FOUND,
content={"detail": "Item not found"},
@@ -181,8 +181,8 @@ def submit_task(
runner: WorkerDispatcher = Depends(_runner),
):
"""Submit a task to the worker."""
plan_model = runner.run(interface.get_plan, task.name)
try:
plan_model = runner.run(interface.get_plan, task.name)
task_id: str = runner.run(interface.submit_task, task)
response.headers["Location"] = f"{request.url}/{task_id}"
return TaskResponse(task_id=task_id)
@@ -193,7 +193,7 @@ def submit_task(
)
error_detail_response = f"""
Input validation failed: {formatted_errors},
suppplied params {task.params},
supplied params {task.params},
do not match the expected params: {plan_model.parameter_schema}
"""
raise HTTPException(
4 changes: 2 additions & 2 deletions src/blueapi/service/runner.py
Original file line number Diff line number Diff line change
@@ -69,7 +69,7 @@ def reload(self):
@start_as_current_span(TRACER)
def start(self):
add_span_attributes(
{"_use_subprocess": self._use_subprocess, "_config": self._config}
{"_use_subprocess": self._use_subprocess, "_config": str(self._config)}
)
try:
if self._use_subprocess:
@@ -176,7 +176,7 @@ def _rpc(
ctx = get_global_textmap().extract(carrier)
attach(ctx)
mod = import_module(module_name)
func: Callable[P, T] = _validate_function(
func: Callable[..., T] = _validate_function(
mod.__dict__.get(function_name, None), function_name
)
value = func(*args, **kwargs)
11 changes: 7 additions & 4 deletions src/blueapi/startup/example_plans.py
Original file line number Diff line number Diff line change
@@ -5,11 +5,14 @@

from blueapi.core import MsgGenerator

TEMP: Movable = inject("sample_temperature")
PRESS: Movable = inject("sample_pressure")


def stp_snapshot(
detectors: list[Readable],
temperature: Movable = inject("sample_temperature"),
pressure: Movable = inject("sample_pressure"),
temperature: Movable = TEMP,
pressure: Movable = PRESS,
) -> MsgGenerator:
"""
Moves devices for pressure and temperature (defaults fetched from the context)
@@ -26,5 +29,5 @@ def stp_snapshot(
Yields:
Iterator[MsgGenerator]: Bluesky messages
"""
yield from move({temperature: 0, pressure: 10**5})
yield from count(detectors, 1)
yield from move({temperature: 0, pressure: 10**5}) # type: ignore
yield from count(set(detectors), 1)
12 changes: 6 additions & 6 deletions src/blueapi/startup/simmotor.py
Original file line number Diff line number Diff line change
@@ -3,7 +3,7 @@
from collections.abc import Callable

from ophyd.sim import SynAxis
from ophyd.status import MoveStatus, Status
from ophyd.status import MoveStatus


class SynAxisWithMotionEvents(SynAxis):
@@ -27,8 +27,8 @@ def __init__(
super().__init__(
name=name,
readback_func=readback_func,
value=value,
delay=delay,
value=value, # type: ignore
delay=delay, # type: ignore
precision=precision,
parent=parent,
labels=labels,
@@ -38,7 +38,7 @@ def __init__(
self._events_per_move = events_per_move
self.egu = egu

def set(self, value: float) -> None:
def set(self, value: float) -> MoveStatus:
old_setpoint = self.sim_state["setpoint"]
distance = value - old_setpoint
self.sim_state["setpoint"] = value
@@ -90,5 +90,5 @@ def __init__(self, *, timeout: float, **kwargs) -> None:
super().__init__(**kwargs)
self._timeout = timeout

def set(self, value: float) -> Status:
return Status(timeout=self._timeout)
def set(self, value: float) -> MoveStatus:
return MoveStatus(positioner=self, target=value, timeout=self._timeout)
1 change: 0 additions & 1 deletion src/blueapi/utils/__init__.py
Original file line number Diff line number Diff line change
@@ -7,7 +7,6 @@
__all__ = [
"handle_all_exceptions",
"load_module_all",
"ConfigLoader",
"serialize",
"BlueapiBaseModel",
"BlueapiModelConfig",
1 change: 0 additions & 1 deletion src/blueapi/worker/__init__.py
Original file line number Diff line number Diff line change
@@ -6,7 +6,6 @@
__all__ = [
"TaskWorker",
"Task",
"Worker",
"WorkerEvent",
"WorkerState",
"StatusView",
3 changes: 2 additions & 1 deletion src/blueapi/worker/event.py
Original file line number Diff line number Diff line change
@@ -8,7 +8,8 @@
from blueapi.utils import BlueapiBaseModel

# The RunEngine can return any of these three types as its state
RawRunEngineState = type[PropertyMachine | ProxyString | str]
# RawRunEngineState = type[PropertyMachine | ProxyString | str]
RawRunEngineState = PropertyMachine | ProxyString | str


# NOTE this is interim until refactor
Loading

0 comments on commit 86c5905

Please sign in to comment.