"""The base classes for backends."""
from abc import ABCMeta, abstractmethod
from typing import TYPE_CHECKING, Dict, Optional, Set, Type
if TYPE_CHECKING: # pragma: nocover
from j5.boards import Board # noqa
[docs]class CommunicationError(Exception):
"""
A communication error occurred.
This error is thrown when there is an error communicating with a board, if a more
specific exception is available, then that may be thrown instead, but it should
inherit from this one.
"""
[docs]class Backend(metaclass=BackendMeta):
"""
The base class for a backend.
A backend is an implementation of a specific board for an environment.
It can hold data about the actual board it is controlling. There should be a ratio
of one instance of a Backend to one instance of a Board. The Backend object should
not hold any references to the Board, instead having it's methods executed by the
code for the individual Board.
A Backend usually also implements a number of ComponentInterfaces which thus allow
a physical component to be controlled by the abstract Component representation.
"""
[docs] @classmethod
@abstractmethod
def discover(cls) -> Set['Board']:
"""Discover boards that this backend can control."""
raise NotImplementedError # pragma: no cover
@property
@abstractmethod
def environment(self) -> 'Environment':
"""Environment the backend belongs too."""
raise NotImplementedError # pragma: no cover
@property
@abstractmethod
def board(self) -> Type['Board']:
"""Type of board this backend implements."""
raise NotImplementedError # pragma: no cover
@property
@abstractmethod
def firmware_version(self) -> Optional[str]:
"""The firmware version of the board."""
raise NotImplementedError # pragma: no cover
[docs]class Environment:
"""
A collection of board implementations that can work together.
Auto-populated with board mappings using metaclass magic.
"""
def __init__(self, name: str):
self.name = name
self.board_backend_mapping: Dict[Type['Board'], Type[Backend]] = {}
@property
def supported_boards(self) -> Set[Type['Board']]:
"""The boards that are supported by this backend group."""
return set(self.board_backend_mapping.keys())
def __str__(self) -> str:
"""Get a string representation of this group."""
return self.name
[docs] def register_backend(self, board: Type['Board'], backend: Type[Backend]) -> None:
"""Register a new backend with this Backend Group."""
self.board_backend_mapping[board] = backend
[docs] def get_backend(self, board: Type['Board']) -> Type[Backend]:
"""Get the backend for a board."""
if board not in self.supported_boards:
raise NotImplementedError(f"The {str(self)} does not support {str(board)}")
return self.board_backend_mapping[board]