Source code for spyder.api.utils
# -----------------------------------------------------------------------------
# Copyright (c) 2021- Spyder Project Contributors
#
# Released under the terms of the MIT License
# (see LICENSE.txt in the project root directory for details)
# -----------------------------------------------------------------------------
"""
Helper functions to work with the Spyder plugin API.
"""
from __future__ import annotations
from abc import ABCMeta as BaseABCMeta
import collections.abc
import sys
import typing
if sys.version_info < (3, 10):
from typing_extensions import ParamSpec
else:
from typing import ParamSpec # noqa: ICN003
_P = ParamSpec("_P")
_T = typing.TypeVar("_T")
[docs]
def get_class_values(cls) -> list[str]:
"""
Get the attribute values for the class enumerations used in our API.
Idea from `Stack Overflow <https://stackoverflow.com/a/17249228/438386>`__.
Parameters
----------
cls
Class object to list the enumeration values of.
Returns
-------
list[str]
String attribute values from a Spyder pseudo-"enum" class.
"""
return [v for (k, v) in cls.__dict__.items() if k[:1] != "_"]
[docs]
class PrefixNode:
"""Utility class used to represent a prefixed string tuple."""
[docs]
def __init__(self, path: tuple[str, ...] | None = None) -> None:
"""
Representation of a prefixed string tuple.
Parameters
----------
path : tuple[str, ...] | None, optional
Underlying prefixed string tuple. The default is None.
Returns
-------
None
"""
self.children = {}
self.path = path
def __iter__(self):
prefix = [((self.path,), self)]
while prefix != []:
current_prefix, node = prefix.pop(0)
prefix += [
(current_prefix + (c,), node.children[c])
for c in node.children
]
yield current_prefix
[docs]
def add_path(self, path: tuple[str, ...]) -> None:
"""
Add a path to the prefix node.
Parameters
----------
path : tuple[str, ...]
Underlying prefixed string tuple.
Returns
-------
None
"""
prefix, *rest = path
if prefix not in self.children:
self.children[prefix] = PrefixNode(prefix)
if len(rest) > 0:
child = self.children[prefix]
child.add_path(rest)
[docs]
class PrefixedTuple(PrefixNode):
"""Utility class to store and iterate over prefixed string tuples."""
def __iter__(self):
for key in self.children:
child = self.children[key]
for prefix in child:
yield prefix
[docs]
class classproperty(property):
"""
Decorator to declare class constants requiring computation as properties.
Idea from `Stack Overflow <https://stackoverflow.com/a/7864317/438386>`__.
"""
[docs]
def __get__(self, cls, owner):
return classmethod(self.fget).__get__(None, owner)()
[docs]
class DummyAttribute:
"""Dummy class to mark abstract attributes."""
pass
[docs]
def abstract_attribute(
obj: collections.abc.Callable[_P, _T] | DummyAttribute | None = None,
) -> _T:
"""
Decorator to mark abstract attributes.
Must be used in conjunction with the :class:`abc.ABCMeta` metaclass.
Parameters
----------
obj: collections.abc.Callable[_P, _T] | DummyAttribute | None, optional
The callable attribute to mark as abstract, a new instance of
:class:`DummyAttribute` by default.
Returns
-------
_T
The result of executing the callable attribute ``obj``.
"""
if obj is None:
obj = DummyAttribute()
setattr(obj, "__is_abstract_attribute__", True)
return obj # type: ignore