Module shaystack.providers

Implementation of Haystack API

Expand source code
# -*- coding: utf-8 -*-
# Haystack API Provider module
# See the accompanying LICENSE file.
# (C) 2021 Engie Digital
#
# vim: set ts=4 sts=4 et tw=78 sw=4 si:
"""
Implementation of Haystack API
"""

from .haystack_interface import HaystackInterface, get_provider
from ..grid import Grid

__all__ = ["HaystackInterface", "get_provider"]

__pdoc__ = \
    {
        "sqldb_protocol": False,
        "db_postgres": False,
        "db_sqlite": False,
        "db_timestream": False,
        "tools": False,
    }


def purge_grid(grid: Grid) -> Grid:
    """
    Purge all entity not in columns
    """
    cols = grid.column
    new_grid = Grid(version=grid.version, metadata=grid.metadata, columns=cols)
    for row in grid:
        new_grid.append({key: val for key, val in row.items() if key in cols})
    return new_grid

Sub-modules

shaystack.providers.db

An generic Haystack Read-Only API provider to expose an Haystack data via the Haystack API …

shaystack.providers.db_haystack_interface

Private extension of haystack implementation to add the link with DB.

shaystack.providers.db_mongo

Tools to convert haystack filter to mongo request

shaystack.providers.db_mysql

Save Haystack ontology in SQLite database with JSon extension. Convert the haystack filter to sqlite SQL equivalent syntax.

shaystack.providers.haystack_interface

Base of haystack implementation.

shaystack.providers.import_db

Import haystack file in SQL database.

shaystack.providers.mongodb

Manipulate Haystack ontology on MongoDB database …

shaystack.providers.ping

An Haystack API provider with a very simple implementation. It's must be used for test.

shaystack.providers.repl_db

User interface to print the translation between filter syntax to others syntaxes.

shaystack.providers.sql

Manipulate Haystack ontology on SQL database …

shaystack.providers.timestream

Add the persistance of time-series with TS database …

shaystack.providers.url

An Haystack Read-Only API provider to expose an Haystack file via the Haystack API. The file must be referenced with the environment variable …

Functions

def get_provider(class_str: str, envs: Dict[str, str], use_cache=True) ‑> HaystackInterface

Return an instance of the provider. If the provider is an abstract class, create a sub class with all the implementation and return an instance of this subclass. Then, the 'ops' method can analyse the current instance and detect the implemented and abstract methods.

Args

class_str
The name of the module that contains the provider.
envs
Environement variable (os.env ?)
use_cache
Use cached provider or create a new one

Returns

A instance of this subclass if it exists

Expand source code
def get_provider(class_str: str, envs: Dict[str, str],  # pylint: disable=protected-access
                 use_cache=True  # pylint: disable=protected-access
                 ) -> HaystackInterface:
    """Return an instance of the provider.
    If the provider is an abstract class, create a sub class with all the implementation
    and return an instance of this subclass. Then, the 'ops' method can analyse the current instance
    and detect the implemented and abstract methods.

    Args:
        class_str: The name of the module that contains the provider.
        envs: Environement variable (os.env ?)
        use_cache: Use cached provider or create a new one

    Returns:
        A instance of this subclass if it exists
    """
    if not class_str.endswith(".Provider"):
        class_str += ".Provider"
    if use_cache and class_str in _providers:
        return _providers[class_str]
    module_path, class_name = class_str.rsplit(".", 1)
    module = import_module(module_path)
    # Get the abstract class name
    provider_class = getattr(module, class_name)

    # Implement all abstract method.
    # Then, it's possible to generate the Ops operator dynamically
    # pylint: disable=missing-function-docstring,useless-super-delegation
    # noinspection PyShadowingNames
    class FullInterface(provider_class):  # pylint: disable=missing-class-docstring
        def __init__(self, envs: Dict[str, str]):
            provider_class.__init__(self, envs)

        def name(self) -> str:
            return super().name()

        def about(
                self, home: str
        ) -> Grid:  # pylint: disable=missing-function-docstring,useless-super-delegation
            return super().about(home)

        def read(
                self,
                limit: int,
                select: Optional[str],
                entity_ids: Optional[List[Ref]],
                grid_filter: Optional[str],
                date_version: Optional[datetime],
        ) -> Grid:
            # pylint: disable=missing-function-docstring,useless-super-delegation
            return super().read(limit, select, entity_ids, grid_filter, date_version)

        def nav(self, nav_id: str) -> Any:
            # pylint: disable=missing-function-docstring,useless-super-delegation
            return super().nav(nav_id)

        def watch_sub(
                self,
                watch_dis: str,
                watch_id: Optional[str],
                ids: List[Ref],
                lease: Optional[int],
        ) -> Grid:
            # pylint: disable=missing-function-docstring,useless-super-delegation
            return super().watch_sub(watch_dis, watch_id, ids, lease)

        def watch_unsub(
                self, watch_id: str, ids: List[Ref], close_all: bool
        ) -> None:
            # pylint: disable=missing-function-docstring,useless-super-delegation
            return super().watch_unsub(watch_id, ids, close_all)

        def watch_poll(self, watch_id: str, refresh: bool) -> Grid:
            return super().watch_poll(watch_id, refresh)

        def point_write_read(  # pylint: disable=missing-function-docstring,useless-super-delegation
                self, entity_id: Ref, date_version: Optional[datetime]
        ) -> Grid:
            return super().point_write_read(entity_id, date_version)

        def point_write_write(  # pylint: disable=missing-function-docstring,useless-super-delegation
                self,
                entity_id: Ref,
                level: int,
                val: Optional[Any],
                duration: Quantity,
                who: Optional[str],
                date_version: Optional[datetime],
        ) -> None:  # pylint: disable=no-self-use
            return super().point_write_write(
                entity_id, level, val, duration, who, date_version
            )

        def his_read(  # pylint: disable=missing-function-docstring,useless-super-delegation
                self,
                entity_id: Ref,
                date_range: Optional[Tuple[datetime, datetime]],
                date_version: Optional[datetime],
        ) -> Grid:
            return super().his_read(entity_id, date_range, date_version)

        def his_write(  # pylint: disable=missing-function-docstring, useless-super-delegation
                self, entity_id: Ref, time_serie: Grid, date_version: Optional[datetime]
        ) -> Grid:
            return super().his_write(entity_id, time_serie, date_version)

        def invoke_action(  # pylint: disable=missing-function-docstring,useless-super-delegation
                self,
                entity_id: Ref,
                action: str,
                params: Dict[str, Any],
        ) -> Grid:
            return super().invoke_action(entity_id, action, params)

    _providers[class_str] = FullInterface(envs)
    return _providers[class_str]

Classes

class HaystackInterface (envs: Dict[str, str])

Interface to implement to be compatible with Haystack REST protocol. The subclasses may be abstract (implemented only a part of methods), the 'ops' code detect that, and can calculate the set of implemented operations.

Expand source code
class HaystackInterface(ABC):
    """
    Interface to implement to be compatible with Haystack REST protocol.
    The subclasses may be abstract (implemented only a part of methods),
    the 'ops' code detect that, and can calculate the set of implemented operations.
    """
    __slots__ = ['_envs']

    def __init__(self, envs: Dict[str, str]):
        assert envs is not None
        self._envs = envs

    @property
    @abstractmethod
    def name(self) -> str:
        """ The name of the provider. """
        raise NotImplementedError()

    def __repr__(self) -> str:
        return self.name

    def __str__(self) -> str:
        return self.__repr__()

    def __enter__(self):
        return self

    def __exit__(self, exc_type, exc_value, exc_traceback):
        pass

    # noinspection PyMethodMayBeStatic
    def get_tz(self) -> BaseTzInfo:  # pylint: disable=no-self-use
        """ Return server time zone. """
        return get_localzone()

    def get_customer_id(self) -> str:  # pylint: disable=no-self-use
        """ Override this for multi-tenant.
        May be, extract the customer id from the current `Principal`.
        """
        return ''

    def values_for_tag(self, tag: str,
                       date_version: Optional[datetime] = None) -> List[Any]:
        """Get all values for a given tag.

        Args:
            tag: The tag to analyse.
            date_version: version date of the ontology.

        Returns:
            All unique values for a specific tag
        """
        raise NotImplementedError()

    def versions(self) -> List[datetime]:  # pylint: disable=no-self-use
        """
        Return a list of versions fot the current ontology.
        Returns:
            datetime for each version or empty array if unknown
        """
        return []

    @abstractmethod
    def about(self, home: str) -> Grid:
        """Implement the Haystack 'about' ops.

        The subclasse must complet the result with "productUri", "productVersion", "moduleName"
        and "moduleVersion"

        Args:
            home: Home url of the API

        Returns:
            The default 'about' grid.
        """
        grid = Grid(
            version=VER_3_0,
            columns=[
                "haystackVersion",  # Str version of REST implementation
                "tz",  # Str of server's default timezone
                "serverName",  # Str name of the server or project database
                "serverTime",
                "serverBootTime",
                "productName",  # Str name of the server software product
                "productUri",
                "productVersion",
                # module which implements Haystack server protocol
                "moduleName",
                # if its a plug-in to the product
                "moduleVersion"  # Str version of moduleName
            ],
        )
        grid.append(
            {
                "haystackVersion": str(VER_3_0),
                "tz": str(self.get_tz()),
                "serverName": "haystack_" + self._envs.get("AWS_REGION", "local"),
                "serverTime": datetime.now(tz=self.get_tz()).replace(microsecond=0),
                "serverBootTime": datetime.now(tz=self.get_tz()).replace(
                    microsecond=0
                ),
                "productName": "Haystack Provider",
                "productUri": Uri(home),
                "productVersion": "0.1",
                "moduleName": "AbstractProvider",
                "moduleVersion": "0.1",
            }
        )
        return grid

    # noinspection PyUnresolvedReferences
    def ops(self) -> Grid:
        """ Implement the Haystack 'ops' ops.

        Notes:
            Automatically calculate the implemented version.

        Returns:
            A Grid containing 'ops' name operations and its related description
        """
        grid = Grid(
            version=VER_3_0,
            columns={
                "name": {},
                "summary": {},
            },
        )
        all_haystack_ops = {
            "about": "Summary information for server",
            "ops": "Operations supported by this server",
            "formats": "Grid data formats supported by this server",
            "read": "The read op is used to read a set of entity records either by their unique "
                    "identifier or using a filter.",
            "nav": "The nav op is used navigate a project for learning and discovery",
            "watch_sub": "The watch_sub operation is used to create new watches "
                         "or add entities to an existing watch.",
            "watch_unsub": "The watch_unsub operation is used to close a watch entirely "
                           "or remove entities from a watch.",
            "watch_poll": "The watch_poll operation is used to poll a watch for "
                          "changes to the subscribed entity records.",
            "point_write": "The point_write_read op is used to: read the current status of a "
                           "writable point's priority array "
                           "or write to a given level",
            "his_read": "The his_read op is used to read a time-series data "
                        "from historized point.",
            "his_write": "The his_write op is used to post new time-series "
                         "data to a historized point.",
            "invoke_action": "The invoke_action op is used to invoke a "
                             "user action on a target record.",
        }
        # Remove abstract method
        # noinspection PyUnresolvedReferences
        for abstract_method in self.__class__.__base__.__abstractmethods__:
            all_haystack_ops.pop(abstract_method, None)
        if (
                "point_write_read" in self.__class__.__base__.__abstractmethods__
                or "point_write_write" in self.__class__.__base__.__abstractmethods__
        ):
            all_haystack_ops.pop("point_write", None)
        all_haystack_ops = {_to_camel(k): v for k, v in all_haystack_ops.items()}

        grid.extend(
            [
                {"name": name, "summary": summary}
                for name, summary in all_haystack_ops.items()
            ]
        )
        return grid

    def formats(self) -> Optional[Grid]:  # pylint: disable=no-self-use
        """ Implement the Haystack 'formats' ops.

        Notes:
            Implement this method, only if you want to limit the format negotiation
        Returns:
            The grid format or None. If None, the API accept all formats ZINC, TRIO, JSON and CSV.
        """
        return None  # type: ignore

    @abstractmethod
    def read(
            self,
            limit: int,
            select: Optional[str],
            entity_ids: Optional[List[Ref]],
            grid_filter: Optional[str],
            date_version: Optional[datetime],
    ) -> Grid:  # pylint: disable=no-self-use
        """
        Implement the Haystack 'read' ops.

        Args:
            limit: The number of record to return or zero
            select: The selected tag separated with comma, else '' or '*'
            entity_ids: A list en ids. If set, grid_filter and limit are ignored.
            grid_filter: A filter to apply. Ignored if entity_ids is set.
            date_version: The date of the ontology version.

        Returns:
            The requested Grid
        """
        raise NotImplementedError()

    @abstractmethod
    def nav(self, nav_id: str) -> Any:  # pylint: disable=no-self-use
        """ Implement the Haystack 'nav' ops.
        This operation allows servers to expose the database in a human-friendly tree (or graph)
        that can be explored

        Args:
             nav_id: The string for nav id column
        """
        raise NotImplementedError()

    @abstractmethod
    def watch_sub(
            self,
            watch_dis: str,
            watch_id: Optional[str],
            ids: List[Ref],
            lease: Optional[int],
    ) -> Grid:  # pylint: disable=no-self-use
        """
        Implement the Haystack 'watchSub' ops.

        Args:
            watch_dis: Watch description
            watch_id: The user watch_id to update or None.
            ids: The list of ids to watch.
            lease: Lease to apply.

        Returns:
            A Grid
        """
        raise NotImplementedError()

    @abstractmethod
    def watch_unsub(
            self, watch_id: str, ids: List[Ref], close: bool
    ) -> Grid:  # pylint: disable=no-self-use
        """
        Implement the Haystack 'watchUnsub' ops.

        Args:
            watch_id: The user watch_id to update or None
            ids: The list of ids to watch
            close: Set to True to close

        Returns:
            A Grid
        """
        raise NotImplementedError()

    @abstractmethod
    def watch_poll(
            self, watch_id: str, refresh: bool
    ) -> Grid:  # pylint: disable=no-self-use
        """ Implement the Haystack 'watchPoll' ops.

        Args:
            watch_id: The user watch_id to update or None
            refresh: Set to True for refreshing the data

        Returns:
            A Grid where each row corresponds to a watched entity.
        """
        raise NotImplementedError()

    @abstractmethod
    def point_write_read(
            self, entity_id: Ref, date_version: Optional[datetime]
    ) -> Grid:  # pylint: disable=no-self-use
        """ Implement the Haystack 'pointWrite' ops.

        Args:
            entity_id: The entity to update
            date_version: The optional date version to update

        Returns:
            A Grid
        """
        raise NotImplementedError()

    @abstractmethod
    def point_write_write(
            self,
            entity_id: Ref,
            level: int,
            val: Optional[Any],
            duration: Quantity,
            who: Optional[str],
            date_version: Optional[datetime] = None,
    ) -> None:  # pylint: disable=no-self-use
        """ Implement the Haystack 'pointWrite' ops.

        Args:
            entity_id: The entity to update
            level: Number from 1-17 for level to write
            val: Value to write or null to auto the level
            duration: Number with duration unit if setting level 8
            who: Optional username performing the write, otherwise user dis is used
            date_version: The optional date version to update

        Returns:
            None
        """
        raise NotImplementedError()

    # Date dates_range must be:
    # "today"
    # "yesterday"
    # "{date}"
    # "{date},{date}"
    # "{dateTime},{dateTime}"
    # "{dateTime}"
    @abstractmethod
    def his_read(
            self,
            entity_id: Ref,
            dates_range: Tuple[datetime, datetime],
            date_version: Optional[datetime] = None,
    ) -> Grid:  # pylint: disable=no-self-use
        """ Implement the Haystack 'hisRead' ops.

        Args:
            entity_id: The entity to read
            dates_range: May be "today", "yesterday", {date}, ({date},{date}), ({datetime},{datetime}),
            {dateTime}
            date_version: The optional date version to read

        Returns:
            A grid
        """
        raise NotImplementedError()

    @abstractmethod
    def his_write(
            self,
            entity_id: Ref,
            time_series: Grid,
            date_version: Optional[datetime] = None
    ) -> Grid:  # pylint: disable=no-self-use
        """ Implement the Haystack 'hisWrite' ops.

        Args:
            entity_id: The entity to read
            time_series: A grid with a time series
            date_version: The optional date version to update

        Returns:
            A grid
        """
        raise NotImplementedError()

    @abstractmethod
    def invoke_action(
            self,
            entity_id: Ref,
            action: str,
            params: Dict[str, Any],
            date_version: Optional[datetime] = None
    ) -> Grid:  # pylint: disable=no-self-use
        """ Implement the Haystack 'invokeAction' ops.

        Args:
            entity_id: The entity to read
            action: The action string
            params: A dictionary with parameters
            date_version: The optional date version to update

        Returns:
            A grid
        """
        raise NotImplementedError()

Ancestors

  • abc.ABC

Subclasses

Instance variables

var name : str

The name of the provider.

Expand source code
@property
@abstractmethod
def name(self) -> str:
    """ The name of the provider. """
    raise NotImplementedError()

Methods

def about(self, home: str) ‑> shaystack.grid.Grid

Implement the Haystack 'about' ops.

The subclasse must complet the result with "productUri", "productVersion", "moduleName" and "moduleVersion"

Args

home
Home url of the API

Returns

The default 'about' grid.

Expand source code
@abstractmethod
def about(self, home: str) -> Grid:
    """Implement the Haystack 'about' ops.

    The subclasse must complet the result with "productUri", "productVersion", "moduleName"
    and "moduleVersion"

    Args:
        home: Home url of the API

    Returns:
        The default 'about' grid.
    """
    grid = Grid(
        version=VER_3_0,
        columns=[
            "haystackVersion",  # Str version of REST implementation
            "tz",  # Str of server's default timezone
            "serverName",  # Str name of the server or project database
            "serverTime",
            "serverBootTime",
            "productName",  # Str name of the server software product
            "productUri",
            "productVersion",
            # module which implements Haystack server protocol
            "moduleName",
            # if its a plug-in to the product
            "moduleVersion"  # Str version of moduleName
        ],
    )
    grid.append(
        {
            "haystackVersion": str(VER_3_0),
            "tz": str(self.get_tz()),
            "serverName": "haystack_" + self._envs.get("AWS_REGION", "local"),
            "serverTime": datetime.now(tz=self.get_tz()).replace(microsecond=0),
            "serverBootTime": datetime.now(tz=self.get_tz()).replace(
                microsecond=0
            ),
            "productName": "Haystack Provider",
            "productUri": Uri(home),
            "productVersion": "0.1",
            "moduleName": "AbstractProvider",
            "moduleVersion": "0.1",
        }
    )
    return grid
def formats(self) ‑> Union[shaystack.grid.Grid, NoneType]

Implement the Haystack 'formats' ops.

Notes

Implement this method, only if you want to limit the format negotiation

Returns

The grid format or None. If None, the API accept all formats ZINC, TRIO, JSON and CSV.

Expand source code
def formats(self) -> Optional[Grid]:  # pylint: disable=no-self-use
    """ Implement the Haystack 'formats' ops.

    Notes:
        Implement this method, only if you want to limit the format negotiation
    Returns:
        The grid format or None. If None, the API accept all formats ZINC, TRIO, JSON and CSV.
    """
    return None  # type: ignore
def get_customer_id(self) ‑> str

Override this for multi-tenant. May be, extract the customer id from the current Principal.

Expand source code
def get_customer_id(self) -> str:  # pylint: disable=no-self-use
    """ Override this for multi-tenant.
    May be, extract the customer id from the current `Principal`.
    """
    return ''
def get_tz(self) ‑> pytz.tzinfo.BaseTzInfo

Return server time zone.

Expand source code
def get_tz(self) -> BaseTzInfo:  # pylint: disable=no-self-use
    """ Return server time zone. """
    return get_localzone()
def his_read(self, entity_id: shaystack.datatypes.Ref, dates_range: Tuple[datetime.datetime, datetime.datetime], date_version: Union[datetime.datetime, NoneType] = None) ‑> shaystack.grid.Grid

Implement the Haystack 'hisRead' ops.

Args

entity_id
The entity to read
dates_range
May be "today", "yesterday", {date}, ({date},{date}), ({datetime},{datetime}),
{dateTime}
date_version
The optional date version to read

Returns

A grid

Expand source code
@abstractmethod
def his_read(
        self,
        entity_id: Ref,
        dates_range: Tuple[datetime, datetime],
        date_version: Optional[datetime] = None,
) -> Grid:  # pylint: disable=no-self-use
    """ Implement the Haystack 'hisRead' ops.

    Args:
        entity_id: The entity to read
        dates_range: May be "today", "yesterday", {date}, ({date},{date}), ({datetime},{datetime}),
        {dateTime}
        date_version: The optional date version to read

    Returns:
        A grid
    """
    raise NotImplementedError()
def his_write(self, entity_id: shaystack.datatypes.Ref, time_series: shaystack.grid.Grid, date_version: Union[datetime.datetime, NoneType] = None) ‑> shaystack.grid.Grid

Implement the Haystack 'hisWrite' ops.

Args

entity_id
The entity to read
time_series
A grid with a time series
date_version
The optional date version to update

Returns

A grid

Expand source code
@abstractmethod
def his_write(
        self,
        entity_id: Ref,
        time_series: Grid,
        date_version: Optional[datetime] = None
) -> Grid:  # pylint: disable=no-self-use
    """ Implement the Haystack 'hisWrite' ops.

    Args:
        entity_id: The entity to read
        time_series: A grid with a time series
        date_version: The optional date version to update

    Returns:
        A grid
    """
    raise NotImplementedError()
def invoke_action(self, entity_id: shaystack.datatypes.Ref, action: str, params: Dict[str, Any], date_version: Union[datetime.datetime, NoneType] = None) ‑> shaystack.grid.Grid

Implement the Haystack 'invokeAction' ops.

Args

entity_id
The entity to read
action
The action string
params
A dictionary with parameters
date_version
The optional date version to update

Returns

A grid

Expand source code
@abstractmethod
def invoke_action(
        self,
        entity_id: Ref,
        action: str,
        params: Dict[str, Any],
        date_version: Optional[datetime] = None
) -> Grid:  # pylint: disable=no-self-use
    """ Implement the Haystack 'invokeAction' ops.

    Args:
        entity_id: The entity to read
        action: The action string
        params: A dictionary with parameters
        date_version: The optional date version to update

    Returns:
        A grid
    """
    raise NotImplementedError()
def nav(self, nav_id: str) ‑> Any

Implement the Haystack 'nav' ops. This operation allows servers to expose the database in a human-friendly tree (or graph) that can be explored

Args

nav_id
The string for nav id column
Expand source code
@abstractmethod
def nav(self, nav_id: str) -> Any:  # pylint: disable=no-self-use
    """ Implement the Haystack 'nav' ops.
    This operation allows servers to expose the database in a human-friendly tree (or graph)
    that can be explored

    Args:
         nav_id: The string for nav id column
    """
    raise NotImplementedError()
def ops(self) ‑> shaystack.grid.Grid

Implement the Haystack 'ops' ops.

Notes

Automatically calculate the implemented version.

Returns

A Grid containing 'ops' name operations and its related description

Expand source code
def ops(self) -> Grid:
    """ Implement the Haystack 'ops' ops.

    Notes:
        Automatically calculate the implemented version.

    Returns:
        A Grid containing 'ops' name operations and its related description
    """
    grid = Grid(
        version=VER_3_0,
        columns={
            "name": {},
            "summary": {},
        },
    )
    all_haystack_ops = {
        "about": "Summary information for server",
        "ops": "Operations supported by this server",
        "formats": "Grid data formats supported by this server",
        "read": "The read op is used to read a set of entity records either by their unique "
                "identifier or using a filter.",
        "nav": "The nav op is used navigate a project for learning and discovery",
        "watch_sub": "The watch_sub operation is used to create new watches "
                     "or add entities to an existing watch.",
        "watch_unsub": "The watch_unsub operation is used to close a watch entirely "
                       "or remove entities from a watch.",
        "watch_poll": "The watch_poll operation is used to poll a watch for "
                      "changes to the subscribed entity records.",
        "point_write": "The point_write_read op is used to: read the current status of a "
                       "writable point's priority array "
                       "or write to a given level",
        "his_read": "The his_read op is used to read a time-series data "
                    "from historized point.",
        "his_write": "The his_write op is used to post new time-series "
                     "data to a historized point.",
        "invoke_action": "The invoke_action op is used to invoke a "
                         "user action on a target record.",
    }
    # Remove abstract method
    # noinspection PyUnresolvedReferences
    for abstract_method in self.__class__.__base__.__abstractmethods__:
        all_haystack_ops.pop(abstract_method, None)
    if (
            "point_write_read" in self.__class__.__base__.__abstractmethods__
            or "point_write_write" in self.__class__.__base__.__abstractmethods__
    ):
        all_haystack_ops.pop("point_write", None)
    all_haystack_ops = {_to_camel(k): v for k, v in all_haystack_ops.items()}

    grid.extend(
        [
            {"name": name, "summary": summary}
            for name, summary in all_haystack_ops.items()
        ]
    )
    return grid
def point_write_read(self, entity_id: shaystack.datatypes.Ref, date_version: Union[datetime.datetime, NoneType]) ‑> shaystack.grid.Grid

Implement the Haystack 'pointWrite' ops.

Args

entity_id
The entity to update
date_version
The optional date version to update

Returns

A Grid

Expand source code
@abstractmethod
def point_write_read(
        self, entity_id: Ref, date_version: Optional[datetime]
) -> Grid:  # pylint: disable=no-self-use
    """ Implement the Haystack 'pointWrite' ops.

    Args:
        entity_id: The entity to update
        date_version: The optional date version to update

    Returns:
        A Grid
    """
    raise NotImplementedError()
def point_write_write(self, entity_id: shaystack.datatypes.Ref, level: int, val: Union[Any, NoneType], duration: shaystack.datatypes.Quantity, who: Union[str, NoneType], date_version: Union[datetime.datetime, NoneType] = None) ‑> NoneType

Implement the Haystack 'pointWrite' ops.

Args

entity_id
The entity to update
level
Number from 1-17 for level to write
val
Value to write or null to auto the level
duration
Number with duration unit if setting level 8
who
Optional username performing the write, otherwise user dis is used
date_version
The optional date version to update

Returns

None

Expand source code
@abstractmethod
def point_write_write(
        self,
        entity_id: Ref,
        level: int,
        val: Optional[Any],
        duration: Quantity,
        who: Optional[str],
        date_version: Optional[datetime] = None,
) -> None:  # pylint: disable=no-self-use
    """ Implement the Haystack 'pointWrite' ops.

    Args:
        entity_id: The entity to update
        level: Number from 1-17 for level to write
        val: Value to write or null to auto the level
        duration: Number with duration unit if setting level 8
        who: Optional username performing the write, otherwise user dis is used
        date_version: The optional date version to update

    Returns:
        None
    """
    raise NotImplementedError()
def read(self, limit: int, select: Union[str, NoneType], entity_ids: Union[List[shaystack.datatypes.Ref], NoneType], grid_filter: Union[str, NoneType], date_version: Union[datetime.datetime, NoneType]) ‑> shaystack.grid.Grid

Implement the Haystack 'read' ops.

Args

limit
The number of record to return or zero
select
The selected tag separated with comma, else '' or '*'
entity_ids
A list en ids. If set, grid_filter and limit are ignored.
grid_filter
A filter to apply. Ignored if entity_ids is set.
date_version
The date of the ontology version.

Returns

The requested Grid

Expand source code
@abstractmethod
def read(
        self,
        limit: int,
        select: Optional[str],
        entity_ids: Optional[List[Ref]],
        grid_filter: Optional[str],
        date_version: Optional[datetime],
) -> Grid:  # pylint: disable=no-self-use
    """
    Implement the Haystack 'read' ops.

    Args:
        limit: The number of record to return or zero
        select: The selected tag separated with comma, else '' or '*'
        entity_ids: A list en ids. If set, grid_filter and limit are ignored.
        grid_filter: A filter to apply. Ignored if entity_ids is set.
        date_version: The date of the ontology version.

    Returns:
        The requested Grid
    """
    raise NotImplementedError()
def values_for_tag(self, tag: str, date_version: Union[datetime.datetime, NoneType] = None) ‑> List[Any]

Get all values for a given tag.

Args

tag
The tag to analyse.
date_version
version date of the ontology.

Returns

All unique values for a specific tag

Expand source code
def values_for_tag(self, tag: str,
                   date_version: Optional[datetime] = None) -> List[Any]:
    """Get all values for a given tag.

    Args:
        tag: The tag to analyse.
        date_version: version date of the ontology.

    Returns:
        All unique values for a specific tag
    """
    raise NotImplementedError()
def versions(self) ‑> List[datetime.datetime]

Return a list of versions fot the current ontology.

Returns

datetime for each version or empty array if unknown

Expand source code
def versions(self) -> List[datetime]:  # pylint: disable=no-self-use
    """
    Return a list of versions fot the current ontology.
    Returns:
        datetime for each version or empty array if unknown
    """
    return []
def watch_poll(self, watch_id: str, refresh: bool) ‑> shaystack.grid.Grid

Implement the Haystack 'watchPoll' ops.

Args

watch_id
The user watch_id to update or None
refresh
Set to True for refreshing the data

Returns

A Grid where each row corresponds to a watched entity.

Expand source code
@abstractmethod
def watch_poll(
        self, watch_id: str, refresh: bool
) -> Grid:  # pylint: disable=no-self-use
    """ Implement the Haystack 'watchPoll' ops.

    Args:
        watch_id: The user watch_id to update or None
        refresh: Set to True for refreshing the data

    Returns:
        A Grid where each row corresponds to a watched entity.
    """
    raise NotImplementedError()
def watch_sub(self, watch_dis: str, watch_id: Union[str, NoneType], ids: List[shaystack.datatypes.Ref], lease: Union[int, NoneType]) ‑> shaystack.grid.Grid

Implement the Haystack 'watchSub' ops.

Args

watch_dis
Watch description
watch_id
The user watch_id to update or None.
ids
The list of ids to watch.
lease
Lease to apply.

Returns

A Grid

Expand source code
@abstractmethod
def watch_sub(
        self,
        watch_dis: str,
        watch_id: Optional[str],
        ids: List[Ref],
        lease: Optional[int],
) -> Grid:  # pylint: disable=no-self-use
    """
    Implement the Haystack 'watchSub' ops.

    Args:
        watch_dis: Watch description
        watch_id: The user watch_id to update or None.
        ids: The list of ids to watch.
        lease: Lease to apply.

    Returns:
        A Grid
    """
    raise NotImplementedError()
def watch_unsub(self, watch_id: str, ids: List[shaystack.datatypes.Ref], close: bool) ‑> shaystack.grid.Grid

Implement the Haystack 'watchUnsub' ops.

Args

watch_id
The user watch_id to update or None
ids
The list of ids to watch
close
Set to True to close

Returns

A Grid

Expand source code
@abstractmethod
def watch_unsub(
        self, watch_id: str, ids: List[Ref], close: bool
) -> Grid:  # pylint: disable=no-self-use
    """
    Implement the Haystack 'watchUnsub' ops.

    Args:
        watch_id: The user watch_id to update or None
        ids: The list of ids to watch
        close: Set to True to close

    Returns:
        A Grid
    """
    raise NotImplementedError()