Source code for grunnur.api
from __future__ import annotations
from typing import Any, Optional, List, TYPE_CHECKING
from .adapter_base import APIID, APIAdapter
from .adapter_cuda import CuAPIAdapterFactory
from .adapter_opencl import OclAPIAdapterFactory
if TYPE_CHECKING: # pragma: no cover
from .platform import Platform
[docs]def cuda_api_id() -> APIID:
"""
Returns the identifier of CUDA API.
"""
return CuAPIAdapterFactory().api_id
[docs]def opencl_api_id() -> APIID:
"""
Returns the identifier of OpenCL API.
"""
return OclAPIAdapterFactory().api_id
_ALL_API_ADAPTER_FACTORIES = {
factory.api_id: factory
for factory in [
CuAPIAdapterFactory(),
OclAPIAdapterFactory(),
]
}
[docs]def all_api_ids() -> List[APIID]:
"""
Returns a list of identifiers for all APIs available.
"""
return list(_ALL_API_ADAPTER_FACTORIES.keys())
[docs]class API:
"""
A generalized GPGPU API.
"""
id: APIID
"""This API's ID."""
shortcut: str
"""
A shortcut for this API (to use in :py:meth:`all_by_shortcut`,
usually coming from some kind of a CLI).
Equal to ``id.shortcut``.
"""
[docs] @classmethod
def all_available(cls) -> List["API"]:
"""
Returns a list of :py:class:`~grunnur.API` objects
for which backends are available.
"""
return [
cls.from_api_id(api_id)
for api_id, api_factory in _ALL_API_ADAPTER_FACTORIES.items()
if api_factory.available
]
[docs] @classmethod
def all_by_shortcut(cls, shortcut: Optional[str] = None) -> List["API"]:
"""
If ``shortcut`` is a string, returns a list of one :py:class:`~grunnur.API` object
whose :py:attr:`~API.id` attribute has its
:py:attr:`~grunnur.adapter_base.APIID.shortcut` attribute equal to it
(or raises an error if it was not found, or its backend is not available).
If ``shortcut`` is ``None``, returns a list of all available :py:class:`~grunnur.API` objects.
:param shortcut: an API shortcut to match.
"""
if shortcut is None:
apis = cls.all_available()
else:
for api_id, api_factory in _ALL_API_ADAPTER_FACTORIES.items():
if shortcut == api_id.shortcut:
if not api_factory.available:
raise ValueError(str(shortcut) + " API is not available")
apis = [cls.from_api_id(api_id)]
break
else:
raise ValueError("Invalid API shortcut: " + str(shortcut))
return apis
[docs] @classmethod
def from_api_id(cls, api_id: APIID) -> "API":
"""
Creates an :py:class:`~grunnur.API` object out of an identifier.
:param api_id: API identifier.
"""
api_adapter = _ALL_API_ADAPTER_FACTORIES[api_id].make_api_adapter()
return cls(api_adapter)
def __init__(self, api_adapter: APIAdapter):
self._api_adapter = api_adapter
self.id = api_adapter.id
self.shortcut = self.id.shortcut
@property
def platforms(self) -> List["Platform"]:
"""
A list of this API's :py:class:`Platform` objects.
"""
from .platform import Platform # avoiding circular imports
return Platform.all(self)
def __eq__(self, other: Any) -> bool:
return (
type(self) == type(other)
and isinstance(other, API)
and self._api_adapter == other._api_adapter
)
def __hash__(self) -> int:
return hash((type(self), self._api_adapter))
def __str__(self) -> str:
return f"api({self.shortcut})"