Skip to content

Commit

Permalink
Enable ruff pyupgrade ruleset
Browse files Browse the repository at this point in the history
Issues fixed automatically.

This also removes typing_extensions as we are not supporting older
versions of Python now.
  • Loading branch information
joeshannon committed Mar 15, 2024
1 parent 9356536 commit b76ae71
Show file tree
Hide file tree
Showing 38 changed files with 190 additions and 176 deletions.
12 changes: 6 additions & 6 deletions .github/pages/make_switcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,28 +3,28 @@
from argparse import ArgumentParser
from pathlib import Path
from subprocess import CalledProcessError, check_output
from typing import List, Optional
from typing import Optional


def report_output(stdout: bytes, label: str) -> List[str]:
def report_output(stdout: bytes, label: str) -> list[str]:
ret = stdout.decode().strip().split("\n")
print(f"{label}: {ret}")
return ret


def get_branch_contents(ref: str) -> List[str]:
def get_branch_contents(ref: str) -> list[str]:
"""Get the list of directories in a branch."""
stdout = check_output(["git", "ls-tree", "-d", "--name-only", ref])
return report_output(stdout, "Branch contents")


def get_sorted_tags_list() -> List[str]:
def get_sorted_tags_list() -> list[str]:
"""Get a list of sorted tags in descending order from the repository."""
stdout = check_output(["git", "tag", "-l", "--sort=-v:refname"])
return report_output(stdout, "Tags list")


def get_versions(ref: str, add: Optional[str]) -> List[str]:
def get_versions(ref: str, add: Optional[str]) -> list[str]:
"""Generate the file containing the list of all GitHub Pages builds."""
# Get the directories (i.e. builds) from the GitHub Pages branch
try:
Expand All @@ -41,7 +41,7 @@ def get_versions(ref: str, add: Optional[str]) -> List[str]:
tags = get_sorted_tags_list()

# Make the sorted versions list from main branches and tags
versions: List[str] = []
versions: list[str] = []
for version in ["master", "main"] + tags:
if version in builds:
versions.append(version)
Expand Down
13 changes: 8 additions & 5 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,8 @@ dependencies = [
"fastapi[all]<0.99",
"uvicorn",
"requests",
"dls-bluesky-core", #requires ophyd-async
"dls-bluesky-core", #requires ophyd-async
"dls-dodal",
"typing_extensions<4.6",
]
dynamic = ["version"]
license.file = "LICENSE"
Expand Down Expand Up @@ -135,9 +134,13 @@ lint.select = [
"F", # pyflakes rules - https://docs.astral.sh/ruff/rules/#pyflakes-f
"W", # pycodestyle warnings - https://docs.astral.sh/ruff/rules/#warning-w
"I", # isort - https://docs.astral.sh/ruff/rules/#isort-i
#"UP", # pyupgrade - https://docs.astral.sh/ruff/rules/#pyupgrade-up
"UP", # pyupgrade - https://docs.astral.sh/ruff/rules/#pyupgrade-up
]

[tool.ruff.lint.flake8-bugbear]
extend-immutable-calls = ["fastapi.Depends", "fastapi.Body", "fastapi.Task", "dls_bluesky_core.core.inject"]

extend-immutable-calls = [
"fastapi.Depends",
"fastapi.Body",
"fastapi.Task",
"dls_bluesky_core.core.inject",
]
4 changes: 2 additions & 2 deletions src/blueapi/cli/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from functools import wraps
from pathlib import Path
from pprint import pprint
from typing import Optional, Tuple, Union
from typing import Optional, Union

import click
from requests.exceptions import ConnectionError
Expand Down Expand Up @@ -34,7 +34,7 @@
"-c", "--config", type=Path, help="Path to configuration YAML file", multiple=True
)
@click.pass_context
def main(ctx: click.Context, config: Union[Optional[Path], Tuple[Path, ...]]) -> None:
def main(ctx: click.Context, config: Union[Optional[Path], tuple[Path, ...]]) -> None:
# if no command is supplied, run with the options passed

config_loader = ConfigLoader(ApplicationConfig)
Expand Down
5 changes: 3 additions & 2 deletions src/blueapi/cli/rest.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from typing import Any, Callable, Literal, Mapping, Optional, Type, TypeVar
from collections.abc import Mapping
from typing import Any, Callable, Literal, Optional, TypeVar

import requests
from pydantic import parse_obj_as
Expand Down Expand Up @@ -98,7 +99,7 @@ def cancel_current_task(
def _request_and_deserialize(
self,
suffix: str,
target_type: Type[T],
target_type: type[T],
data: Optional[Mapping[str, Any]] = None,
method="GET",
raise_if: Callable[[requests.Response], bool] = _is_exception,
Expand Down
5 changes: 3 additions & 2 deletions src/blueapi/cli/updates.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import itertools
from typing import Dict, Mapping, Optional, Union
from collections.abc import Mapping
from typing import Optional, Union

from tqdm import tqdm

Expand All @@ -9,7 +10,7 @@


class ProgressBarRenderer:
_bars: Dict[str, tqdm]
_bars: dict[str, tqdm]
_count: itertools.count

def __init__(self) -> None:
Expand Down
11 changes: 6 additions & 5 deletions src/blueapi/config.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import os
from collections.abc import Mapping
from enum import Enum
from pathlib import Path
from typing import Any, Dict, Generic, Literal, Mapping, Optional, Type, TypeVar, Union
from typing import Any, Generic, Literal, Optional, TypeVar, Union

import yaml
from pydantic import BaseModel, Field, ValidationError, parse_obj_as, validator
Expand Down Expand Up @@ -124,10 +125,10 @@ class ConfigLoader(Generic[C]):
of default values, dictionaries, YAML/JSON files etc.
"""

_schema: Type[C]
_values: Dict[str, Any]
_schema: type[C]
_values: dict[str, Any]

def __init__(self, schema: Type[C]) -> None:
def __init__(self, schema: type[C]) -> None:
self._schema = schema
self._values = {}

Expand All @@ -142,7 +143,7 @@ def use_values(self, values: Mapping[str, Any]) -> None:
if defaults provided.
"""

def recursively_update_map(old: Dict[str, Any], new: Mapping[str, Any]) -> None:
def recursively_update_map(old: dict[str, Any], new: Mapping[str, Any]) -> None:
for key in new:
if (
key in old
Expand Down
22 changes: 13 additions & 9 deletions src/blueapi/core/bluesky_types.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
import inspect
from typing import Any, Callable, Mapping, Optional, Type, Union, get_type_hints
from collections.abc import Mapping
from typing import (
Any,
Callable,
Optional,
Protocol,
Union,
get_type_hints,
runtime_checkable,
)

from bluesky.protocols import (
Checkable,
Expand All @@ -24,11 +33,6 @@

from blueapi.utils import BlueapiBaseModel

try:
from typing import Protocol, runtime_checkable
except ImportError:
from typing_extensions import Protocol, runtime_checkable # type: ignore

PlanWrapper = Callable[[MsgGenerator], MsgGenerator]

#: An object that encapsulates the device to do useful things to produce
Expand Down Expand Up @@ -62,14 +66,14 @@ def is_bluesky_compatible_device(obj: Any) -> bool:
return is_object and _follows_bluesky_protocols(obj)


def is_bluesky_compatible_device_type(cls: Type[Any]) -> bool:
def is_bluesky_compatible_device_type(cls: type[Any]) -> bool:
# We must separately check if Obj refers to an class rather than an
# instance, as both follow the protocols but only one is a type.
return inspect.isclass(cls) and _follows_bluesky_protocols(cls)


def _follows_bluesky_protocols(obj: Any) -> bool:
return any((isinstance(obj, protocol) for protocol in BLUESKY_PROTOCOLS))
return any(isinstance(obj, protocol) for protocol in BLUESKY_PROTOCOLS)


def is_bluesky_plan_generator(func: PlanGenerator) -> bool:
Expand All @@ -89,7 +93,7 @@ class Plan(BlueapiBaseModel):
description: Optional[str] = Field(
description="Description/docstring of the plan", default=None
)
model: Type[BaseModel] = Field(
model: type[BaseModel] = Field(
description="Validation model of the parameters for the plan"
)

Expand Down
22 changes: 9 additions & 13 deletions src/blueapi/core/context.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,15 @@
import functools
import logging
from collections.abc import Sequence
from dataclasses import dataclass, field
from importlib import import_module
from inspect import Parameter, signature
from types import ModuleType
from typing import (
Any,
Callable,
Dict,
Generic,
List,
Optional,
Sequence,
Tuple,
Type,
TypeVar,
Union,
get_args,
Expand Down Expand Up @@ -60,12 +56,12 @@ class BlueskyContext:
default_factory=lambda: RunEngine(context_managers=[])
)
plan_wrappers: Sequence[PlanWrapper] = field(default_factory=list)
plans: Dict[str, Plan] = field(default_factory=dict)
devices: Dict[str, Device] = field(default_factory=dict)
plan_functions: Dict[str, PlanGenerator] = field(default_factory=dict)
plans: dict[str, Plan] = field(default_factory=dict)
devices: dict[str, Device] = field(default_factory=dict)
plan_functions: dict[str, PlanGenerator] = field(default_factory=dict)
sim: bool = field(default=False)

_reference_cache: Dict[Type, Type] = field(default_factory=dict)
_reference_cache: dict[type, type] = field(default_factory=dict)

def wrap(self, plan: MsgGenerator) -> MsgGenerator:
wrapped_plan = functools.reduce(
Expand All @@ -75,7 +71,7 @@ def wrap(self, plan: MsgGenerator) -> MsgGenerator:
)
yield from wrapped_plan

def find_device(self, addr: Union[str, List[str]]) -> Optional[Device]:
def find_device(self, addr: Union[str, list[str]]) -> Optional[Device]:
"""
Find a device in this context, allows for recursive search.
Expand Down Expand Up @@ -199,7 +195,7 @@ def device(self, device: Device, name: Optional[str] = None) -> None:

self.devices[name] = device

def _reference(self, target: Type) -> Type:
def _reference(self, target: type) -> type:
"""
Create an intermediate reference type for the required ``target`` type that
will return an existing device during pydantic deserialisation/validation
Expand Down Expand Up @@ -238,7 +234,7 @@ def __modify_schema__(

def _type_spec_for_function(
self, func: Callable[..., Any]
) -> dict[str, Tuple[Type, Any]]:
) -> dict[str, tuple[type, Any]]:
"""
Parse a function signature and build map of field types and default
values that can be used to deserialise arguments from external sources.
Expand Down Expand Up @@ -271,7 +267,7 @@ def _type_spec_for_function(
)
return new_args

def _convert_type(self, typ: Type) -> Type:
def _convert_type(self, typ: type) -> type:
"""
Recursively convert a type to something that can be deserialised by
pydantic. Bluesky protocols (and types that extend them) are replaced
Expand Down
4 changes: 2 additions & 2 deletions src/blueapi/core/device_lookup.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
from typing import Any, List, Optional, TypeVar
from typing import Any, Optional, TypeVar

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]) -> Optional[D]:
def find_component(obj: Any, addr: list[str]) -> Optional[D]:
"""
Best effort function to locate a child device, either in a dictionary of
devices or a device with child attributes.
Expand Down
4 changes: 2 additions & 2 deletions src/blueapi/core/event.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import itertools
from abc import ABC, abstractmethod
from typing import Callable, Dict, Generic, Optional, TypeVar
from typing import Callable, Generic, Optional, TypeVar

#: Event type
E = TypeVar("E")
Expand Down Expand Up @@ -47,7 +47,7 @@ class EventPublisher(EventStream[E, int]):
Simple Observable that can be fed values to publish
"""

_subscriptions: Dict[int, Callable[[E, Optional[str]], None]]
_subscriptions: dict[int, Callable[[E, Optional[str]], None]]
_count: itertools.count

def __init__(self) -> None:
Expand Down
4 changes: 2 additions & 2 deletions src/blueapi/messaging/base.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from abc import ABC, abstractmethod
from concurrent.futures import Future
from typing import Any, Callable, Optional, Type
from typing import Any, Callable, Optional

from .context import MessageContext

Expand Down Expand Up @@ -86,7 +86,7 @@ def send_and_receive(
self,
destination: str,
obj: Any,
reply_type: Type = str,
reply_type: type = str,
correlation_id: Optional[str] = None,
) -> Future:
"""
Expand Down
12 changes: 6 additions & 6 deletions src/blueapi/messaging/stomptemplate.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import uuid
from dataclasses import dataclass
from threading import Event
from typing import Any, Callable, Dict, List, Optional, Set
from typing import Any, Callable, Optional

import stomp
from pydantic import parse_obj_as
Expand Down Expand Up @@ -74,8 +74,8 @@ class StompMessagingTemplate(MessagingTemplate):
_authentication: BasicAuthentication
_sub_num: itertools.count
_listener: stomp.ConnectionListener
_subscriptions: Dict[str, Subscription]
_pending_subscriptions: Set[str]
_subscriptions: dict[str, Subscription]
_pending_subscriptions: set[str]
_disconnected: Event

# Stateless implementation means attribute can be static
Expand Down Expand Up @@ -133,7 +133,7 @@ def _send_str(
) -> None:
LOGGER.info(f"SENDING {message} to {destination}")

headers: Dict[str, Any] = {"JMSType": "TextMessage"}
headers: dict[str, Any] = {"JMSType": "TextMessage"}
if on_reply is not None:
reply_queue_name = self.destinations.temporary_queue(str(uuid.uuid1()))
headers = {**headers, "reply-to": reply_queue_name}
Expand All @@ -148,7 +148,7 @@ def subscribe(self, destination: str, callback: MessageListener) -> None:

def wrapper(frame: Frame) -> None:
as_dict = json.loads(frame.body)
value = parse_obj_as(obj_type, as_dict)
value: Any = parse_obj_as(obj_type, as_dict)

context = MessageContext(
frame.headers["destination"],
Expand Down Expand Up @@ -193,7 +193,7 @@ def finished_connecting(_: Frame):

self._ensure_subscribed()

def _ensure_subscribed(self, sub_ids: Optional[List[str]] = None) -> None:
def _ensure_subscribed(self, sub_ids: Optional[list[str]] = None) -> None:
# We must defer subscription until after connection, because stomp literally
# sends a SUB to the broker. But it still nice to be able to call subscribe
# on template before it connects, then just run the subscribes after connection.
Expand Down
5 changes: 2 additions & 3 deletions src/blueapi/messaging/utils.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import inspect
from typing import Type

from .base import MessageListener


def determine_deserialization_type(
listener: MessageListener, default: Type = str
) -> Type:
listener: MessageListener, default: type = str
) -> type:
"""
Inspect a message listener function to determine the type to deserialize
a message to
Expand Down
Loading

0 comments on commit b76ae71

Please sign in to comment.