Skip to content

Commit

Permalink
cleanup: annotations future (#1606)
Browse files Browse the repository at this point in the history
* target, soc_target: use annotations future
* cortex_m: annotations future, use .read_core_register_raw() to fix a couple type errors
* coresight: dap: annotations future
* core: session: annotations future
* probe: annotations future

Use annotations future for CMSISDAPProbe, DebugProbe, and StlinkProbe.

* coresight: ap: annotations future

Also ignore some type errors that are not problems.
  • Loading branch information
flit authored Aug 9, 2023
1 parent 28288ae commit f84ceda
Show file tree
Hide file tree
Showing 9 changed files with 176 additions and 127 deletions.
76 changes: 51 additions & 25 deletions pyocd/core/session.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# pyOCD debugger
# Copyright (c) 2018-2020 Arm Limited
# Copyright (c) 2021-2022 Chris Reed
# Copyright (c) 2021-2023 Chris Reed
# SPDX-License-Identifier: Apache-2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
Expand All @@ -15,16 +15,20 @@
# See the License for the specific language governing permissions and
# limitations under the License.

from __future__ import annotations

from contextlib import contextmanager
import logging
import logging.config
import yaml
import os
from pathlib import Path
import sys
import weakref
from inspect import (getfullargspec, signature)
from types import SimpleNamespace
from typing import (Any, Callable, Generator, Sequence, Union, cast, Dict, List, Mapping, Optional, TYPE_CHECKING)
from typing_extensions import Self

from . import exceptions
from .options_manager import OptionsManager
Expand All @@ -38,6 +42,9 @@
from ..gdbserver.gdbserver import GDBServer
from ..board.board import Board

# Check whether the eval_str parameter for inspect.signature is available.
HAS_SIGNATURE_EVAL_STR = (sys.version_info[:2] >= (3, 10))

LOG = logging.getLogger(__name__)

## @brief Set of default config filenames to search for.
Expand Down Expand Up @@ -95,7 +102,7 @@ class Session(Notifier):
_current_session: Optional[weakref.ref] = None

@classmethod
def get_current(cls) -> "Session":
def get_current(cls) -> Self:
"""@brief Return the most recently created Session instance or a default Session.
By default this method will return the most recently created Session object that is
Expand All @@ -111,11 +118,11 @@ def get_current(cls) -> "Session":
if session is not None:
return session

return Session(None)
return cls(None)

def __init__(
self,
probe: Optional["DebugProbe"],
probe: Optional[DebugProbe],
auto_open: bool = True,
options: Optional[Mapping[str, Any]] = None,
option_defaults: Optional[Mapping[str, Any]] = None,
Expand Down Expand Up @@ -159,8 +166,8 @@ def __init__(
self._delegate: Optional[Any] = None
self._auto_open = auto_open
self._options = OptionsManager()
self._gdbservers: Dict[int, "GDBServer"] = {}
self._probeserver: Optional["DebugProbeServer"] = None
self._gdbservers: Dict[int, GDBServer] = {}
self._probeserver: Optional[DebugProbeServer] = None
self._context_state = SimpleNamespace()

# Set this session on the probe, if we were given a probe.
Expand Down Expand Up @@ -314,17 +321,17 @@ def is_open(self) -> bool:
return self._inited and not self._closed

@property
def probe(self) -> Optional["DebugProbe"]:
def probe(self) -> Optional[DebugProbe]:
"""@brief The @ref pyocd.probe.debug_probe.DebugProbe "DebugProbe" instance."""
return self._probe

@property
def board(self) -> Optional["Board"]:
def board(self) -> Optional[Board]:
"""@brief The @ref pyocd.board.board.Board "Board" object."""
return self._board

@property
def target(self) -> Optional["SoCTarget"]:
def target(self) -> Optional[SoCTarget]:
"""@brief The @ref pyocd.core.target.soc_target "SoCTarget" object representing the SoC.
This is the @ref pyocd.core.target.soc_target "SoCTarget" instance owned by the board.
Expand Down Expand Up @@ -352,7 +359,7 @@ def delegate(self, new_delegate: Any) -> None:
self._delegate = new_delegate

@property
def user_script_proxy(self) -> "UserScriptDelegateProxy":
def user_script_proxy(self) -> UserScriptDelegateProxy:
"""@brief The UserScriptDelegateProxy object for a loaded user script."""
# Create a proxy if there isn't already one. This is a fallback in case there isn't a user script,
# yet a Python $-command is executed and needs the user script namespace in which to run.
Expand All @@ -363,21 +370,21 @@ def user_script_proxy(self) -> "UserScriptDelegateProxy":
return self._user_script_proxy

@property
def user_script_print_proxy(self) -> "PrintProxy":
def user_script_print_proxy(self) -> PrintProxy:
return self._user_script_print_proxy

@property
def gdbservers(self) -> Dict[int, "GDBServer"]:
def gdbservers(self) -> Dict[int, GDBServer]:
"""@brief Dictionary of core numbers to @ref pyocd.gdbserver.gdbserver.GDBServer "GDBServer" instances."""
return self._gdbservers

@property
def probeserver(self) -> Optional["DebugProbeServer"]:
def probeserver(self) -> Optional[DebugProbeServer]:
"""@brief A @ref pyocd.probe.tcp_probe_server.DebugProbeServer "DebugProbeServer" instance."""
return self._probeserver

@probeserver.setter
def probeserver(self, server: "DebugProbeServer") -> None:
def probeserver(self, server: DebugProbeServer) -> None:
"""@brief Setter for the `probeserver` property."""
self._probeserver = server

Expand Down Expand Up @@ -405,7 +412,7 @@ def __enter__(self) -> "Session":
raise
return self

def __exit__(self, exc_type: type, value: Any, traceback: "TracebackType") -> bool:
def __exit__(self, exc_type: type, value: Any, traceback: TracebackType) -> bool:
self.close()
return False

Expand Down Expand Up @@ -642,7 +649,10 @@ def _command_decorator(fn: Callable):
classname = names_list[0].capitalize() + "Command"

# Examine the command function's signature to extract arguments and their types.
sig = signature(fn)
if HAS_SIGNATURE_EVAL_STR:
sig = signature(fn, eval_str=True)
else:
sig = signature(fn)
arg_converters = []
has_var_args = False
usage_fields: List[str] = []
Expand All @@ -663,19 +673,35 @@ def _command_decorator(fn: Callable):
if typ is parm.empty:
LOG.error("user command function '%s' is missing type annotation for parameter '%s'",
fn.__name__, parm.name)
return fn
return None

# If we don't have Python 3.10 or later, then we must manually un-stringize the type.
# Using eval() to un-stringize won't work in all cases, but is sufficient for the types
# supported by pyocd's commands.
if not HAS_SIGNATURE_EVAL_STR:
try:
typ = eval(typ, fn.__globals__)
except Exception:
LOG.error("parameter '%s' of user command function '%s' has an unsupported type",
parm.name, fn.__name__)
return None

# Otherwise add to param converter list.
if issubclass(typ, str):
arg_converters.append(lambda _, x: x)
elif issubclass(typ, float):
arg_converters.append(lambda _, x: float(x))
elif issubclass(typ, int):
arg_converters.append(CommandBase._convert_value)
else:
try:
if issubclass(typ, str):
arg_converters.append(lambda _, x: x)
elif issubclass(typ, float):
arg_converters.append(lambda _, x: float(x))
elif issubclass(typ, int):
arg_converters.append(CommandBase._convert_value)
else:
LOG.error("parameter '%s' of user command function '%s' has an unsupported type",
parm.name, fn.__name__)
return None
except TypeError:
LOG.error("parameter '%s' of user command function '%s' has an unsupported type",
parm.name, fn.__name__)
return fn
return None
usage_fields.append(parm.name.upper())

# parse() method of the new command class.
Expand Down
26 changes: 14 additions & 12 deletions pyocd/core/soc_target.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# pyOCD debugger
# Copyright (c) 2020 Arm Limited
# Copyright (c) 2021-2022 Chris Reed
# Copyright (c) 2021-2023 Chris Reed
# SPDX-License-Identifier: Apache-2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
Expand All @@ -15,6 +15,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.

from __future__ import annotations

import logging
from typing import (Callable, Dict, List, Optional, overload, Sequence, Union, TYPE_CHECKING)
from typing_extensions import Literal
Expand Down Expand Up @@ -59,7 +61,7 @@ class SoCTarget(TargetGraphNode):

VENDOR = "Generic"

def __init__(self, session: "Session", memory_map: Optional["MemoryMap"] = None) -> None:
def __init__(self, session: Session, memory_map: Optional[MemoryMap] = None) -> None:
super().__init__(session, memory_map)
self.vendor: str = self.VENDOR
self.part_families: List[str] = getattr(self, 'PART_FAMILIES', [])
Expand Down Expand Up @@ -133,7 +135,7 @@ def supported_security_states(self) -> Sequence[Target.SecurityState]:
return self.selected_core_or_raise.supported_security_states

@property
def core_registers(self) -> "CoreRegistersIndex":
def core_registers(self) -> CoreRegistersIndex:
return self.selected_core_or_raise.core_registers

def add_core(self, core: CoreTarget) -> None:
Expand Down Expand Up @@ -241,25 +243,25 @@ def read_memory_block8(self, addr: int, size: int) -> Sequence[int]:
def read_memory_block32(self, addr: int, size: int) -> Sequence[int]:
return self.selected_core_or_raise.read_memory_block32(addr, size)

def read_core_register(self, id: "CoreRegisterNameOrNumberType") -> "CoreRegisterValueType":
def read_core_register(self, id: CoreRegisterNameOrNumberType) -> CoreRegisterValueType:
return self.selected_core_or_raise.read_core_register(id)

def write_core_register(self, id: "CoreRegisterNameOrNumberType", data: "CoreRegisterValueType") -> None:
def write_core_register(self, id: CoreRegisterNameOrNumberType, data: CoreRegisterValueType) -> None:
return self.selected_core_or_raise.write_core_register(id, data)

def read_core_register_raw(self, reg: "CoreRegisterNameOrNumberType") -> int:
def read_core_register_raw(self, reg: CoreRegisterNameOrNumberType) -> int:
return self.selected_core_or_raise.read_core_register_raw(reg)

def read_core_registers_raw(self, reg_list: Sequence["CoreRegisterNameOrNumberType"]) -> List[int]:
def read_core_registers_raw(self, reg_list: Sequence[CoreRegisterNameOrNumberType]) -> List[int]:
return self.selected_core_or_raise.read_core_registers_raw(reg_list)

def write_core_register_raw(self, reg: "CoreRegisterNameOrNumberType", data: int) -> None:
def write_core_register_raw(self, reg: CoreRegisterNameOrNumberType, data: int) -> None:
self.selected_core_or_raise.write_core_register_raw(reg, data)

def write_core_registers_raw(self, reg_list: Sequence["CoreRegisterNameOrNumberType"], data_list: Sequence[int]) -> None:
def write_core_registers_raw(self, reg_list: Sequence[CoreRegisterNameOrNumberType], data_list: Sequence[int]) -> None:
self.selected_core_or_raise.write_core_registers_raw(reg_list, data_list)

def find_breakpoint(self, addr: int) -> Optional["Breakpoint"]:
def find_breakpoint(self, addr: int) -> Optional[Breakpoint]:
return self.selected_core_or_raise.find_breakpoint(addr)

def set_breakpoint(self, addr: int, type: Target.BreakpointType = Target.BreakpointType.AUTO) -> bool:
Expand Down Expand Up @@ -305,7 +307,7 @@ def set_vector_catch(self, enable_mask: int) -> None:
def get_vector_catch(self) -> int:
return self.selected_core_or_raise.get_vector_catch()

def get_target_context(self, core: Optional[int] = None) -> "DebugContext":
def get_target_context(self, core: Optional[int] = None) -> DebugContext:
if core is not None:
core_obj = self.cores[core]
else:
Expand All @@ -318,7 +320,7 @@ def trace_start(self):
def trace_stop(self):
self.call_delegate('trace_stop', target=self, mode=0)

def add_target_command_groups(self, command_set: "CommandSet"):
def add_target_command_groups(self, command_set: CommandSet):
"""@brief Hook for adding target-specific commands to a command set."""
self.call_delegate('add_target_command_groups', target=self, command_set=command_set)

34 changes: 18 additions & 16 deletions pyocd/core/target.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# pyOCD debugger
# Copyright (c) 2006-2019 Arm Limited
# Copyright (c) 2021-2022 Chris Reed
# Copyright (c) 2021-2023 Chris Reed
# SPDX-License-Identifier: Apache-2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
Expand All @@ -15,8 +15,10 @@
# See the License for the specific language governing permissions and
# limitations under the License.

from __future__ import annotations

from enum import Enum
from typing import (Any, Callable, List, Optional, Sequence, TYPE_CHECKING, Set)
from typing import (Callable, List, Optional, Sequence, TYPE_CHECKING, Set)

from .memory_interface import MemoryInterface
from .memory_map import MemoryMap
Expand Down Expand Up @@ -187,7 +189,7 @@ class HaltReason(Enum):
## PMU event. v8.1-M only.
PMU = 7

def __init__(self, session: "Session", memory_map: Optional[MemoryMap] = None) -> None:
def __init__(self, session: Session, memory_map: Optional[MemoryMap] = None) -> None:
self._session = session
# Make a target-specific copy of the memory map. This is safe to do without locking
# because the memory map may not be mutated until target initialization.
Expand All @@ -196,19 +198,19 @@ def __init__(self, session: "Session", memory_map: Optional[MemoryMap] = None) -
self._svd_device: Optional[SVDDevice] = None

@property
def session(self) -> "Session":
def session(self) -> Session:
return self._session

@property
def svd_device(self) -> Optional["SVDDevice"]:
def svd_device(self) -> Optional[SVDDevice]:
return self._svd_device

@property
def supported_security_states(self) -> Sequence[SecurityState]:
raise NotImplementedError()

@property
def core_registers(self) -> "CoreRegistersIndex":
def core_registers(self) -> CoreRegistersIndex:
raise NotImplementedError()

@property
Expand All @@ -219,7 +221,7 @@ def supported_reset_types(self) -> Set[ResetType]:
def is_locked(self) -> bool:
return False

def create_init_sequence(self) -> "CallSequence":
def create_init_sequence(self) -> CallSequence:
raise NotImplementedError()

def init(self) -> None:
Expand All @@ -245,25 +247,25 @@ def resume(self) -> None:
def mass_erase(self) -> None:
raise NotImplementedError()

def read_core_register(self, id: "CoreRegisterNameOrNumberType") -> "CoreRegisterValueType":
def read_core_register(self, id: CoreRegisterNameOrNumberType) -> CoreRegisterValueType:
raise NotImplementedError()

def write_core_register(self, id: "CoreRegisterNameOrNumberType", data: "CoreRegisterValueType") -> None:
def write_core_register(self, id: CoreRegisterNameOrNumberType, data: CoreRegisterValueType) -> None:
raise NotImplementedError()

def read_core_register_raw(self, reg: "CoreRegisterNameOrNumberType") -> int:
def read_core_register_raw(self, reg: CoreRegisterNameOrNumberType) -> int:
raise NotImplementedError()

def read_core_registers_raw(self, reg_list: Sequence["CoreRegisterNameOrNumberType"]) -> List[int]:
def read_core_registers_raw(self, reg_list: Sequence[CoreRegisterNameOrNumberType]) -> List[int]:
raise NotImplementedError()

def write_core_register_raw(self, reg: "CoreRegisterNameOrNumberType", data: int) -> None:
def write_core_register_raw(self, reg: CoreRegisterNameOrNumberType, data: int) -> None:
raise NotImplementedError()

def write_core_registers_raw(self, reg_list: Sequence["CoreRegisterNameOrNumberType"], data_list: Sequence[int]) -> None:
def write_core_registers_raw(self, reg_list: Sequence[CoreRegisterNameOrNumberType], data_list: Sequence[int]) -> None:
raise NotImplementedError()

def find_breakpoint(self, addr: int) -> Optional["Breakpoint"]:
def find_breakpoint(self, addr: int) -> Optional[Breakpoint]:
raise NotImplementedError()

def set_breakpoint(self, addr: int, type: BreakpointType = BreakpointType.AUTO) -> bool:
Expand Down Expand Up @@ -315,12 +317,12 @@ def set_vector_catch(self, enable_mask: int) -> None:
def get_vector_catch(self) -> int:
raise NotImplementedError()

def get_target_context(self, core: Optional[int] = None) -> "DebugContext":
def get_target_context(self, core: Optional[int] = None) -> DebugContext:
raise NotImplementedError()

class TargetGraphNode(Target, GraphNode):
"""@brief Abstract class for a target that is a graph node."""

def __init__(self, session: "Session", memory_map: Optional[MemoryMap] = None) -> None:
def __init__(self, session: Session, memory_map: Optional[MemoryMap] = None) -> None:
Target.__init__(self, session, memory_map)
GraphNode.__init__(self)
Loading

0 comments on commit f84ceda

Please sign in to comment.