Skip to content

File element.py#

File List > build > lib.linux-armv7l-cpython-311 > pypisoundmicro > element.py

Go to the documentation of this file

from .swig import pypisoundmicro as psm
from ._utils import copy_doc
from typing import Optional, Self, Type, Union
from .name import ElementName
from .types import Pin, ElementType, PinDirection, PinPull, ActivityType
from .valuefd import ValueFd
import os

@copy_doc(psm.Element)
class Element:

    def __init__(self, native_obj: Optional[psm.Element]=None) -> None:
        """Initialize an Element.

        Args:
            native_obj: The native SWIG-wrapped Element object
        """
        psm.upisnd_init()
        self._native_obj = native_obj if native_obj is not None else psm.Element()

    @property
    def is_valid(self) -> bool:
        """ Checks if the element is valid."""
        if self._native_obj:
            return self._native_obj.isValid()
        return False

    def release(self) -> None:
        """ Unreferences the underlying C #upisnd_element_ref_t handle and resets the object."""
        if self._native_obj:
            self._native_obj.release()
            self._native_obj = None
            psm.upisnd_uninit()

    @property
    def name(self) -> Optional[str]:
        """ Gets the name of the element."""
        if self._native_obj:
            return self._native_obj.getName()
        return None

    @property
    def type(self) -> ElementType:
        """ Gets the type of the element."""
        if self._native_obj:
            return ElementType(self._native_obj.getType())
        return ElementType.INVALID

    @property
    def pin(self) -> Pin:
        """ Gets the pin of the element."""
        if self._native_obj:
            return Pin(self._native_obj.getPin())
        return Pin.INVALID

    def open_value_fd(self, flags: int=os.O_RDWR | os.O_CLOEXEC) -> Optional[ValueFd]:
        """
         Opens the Element's `value` attribute as a file descriptor.

        :type flags: int
        :param flags: The flags to pass to ::open.

        See also: upisnd_element_open_value_fd
        """
        if self._native_obj:
            native_fd = self._native_obj.openValueFd(flags)
            if native_fd and native_fd.isValid():
                return ValueFd(native_fd)
        return None

    def as_encoder(self) -> Optional['Encoder']:
        """Cast the element to an Encoder if possible."""
        from .encoder import Encoder
        if self._native_obj and self.typetypetype == ElementType.ENCODER:
            swig_encoder = self._native_obj.as_encoder()
            if swig_encoder and swig_encoder.isValid():
                return Encoder(swig_encoder)
        return None

    def as_analog_input(self) -> Optional['AnalogInput']:
        """Cast the element to an AnalogInput if possible."""
        from .analoginput import AnalogInput
        if self._native_obj and self.typetypetype == ElementType.ANALOG_INPUT:
            swig_analog = self._native_obj.as_analog_input()
            if swig_analog and swig_analog.isValid():
                return AnalogInput(swig_analog)
        return None

    def as_gpio(self) -> Optional['Gpio']:
        """Cast the element to a GPIO if possible."""
        from .gpio import Gpio
        if self._native_obj and self.typetypetype == ElementType.GPIO:
            swig_gpio = self._native_obj.as_gpio()
            if swig_gpio and swig_gpio.isValid():
                return Gpio(swig_gpio)
        return None

    def as_activity(self) -> Optional['Activity']:
        """Cast the element to an Activity if possible."""
        from .activity import Activity
        if self._native_obj and self.typetypetype == ElementType.ACTIVITY:
            swig_activity = self._native_obj.as_activity()
            if swig_activity and swig_activity.isValid():
                return Activity(swig_activity)
        return None

    @classmethod
    def get(cls, name: Union[str, ElementName]) -> Optional[Self]:
        """
         Gets an Element following ::upisnd_element_get semantics.

        :type name: :py:class:`ElementName`
        :param name: The name of the element to get. Can be provided as a string constant or `const char *`.
        """
        if isinstance(name, str):
            name = psm.ElementName.regular(name)
        native_obj = psm.Element.get(name)
        if native_obj.isValid():
            return cls(native_obj)
        return None

    @classmethod
    def setup(cls, name: Union[str, ElementName], setup: Union[int, 'Setup']) -> Optional[Self]:
        """
         Sets up a new Element from a #upisnd_setup_t setup option container.

        :type name: :py:class:`ElementName`
        :param name: The name of the element to get. Can be provided as a string constant or `const char *`.
        :type setup: int
        :param setup: The setup option container. See ::upisnd_setup_set_element_type and the rest of the
            upisnd_setup_* APIs in api.h.
        """
        if isinstance(name, str):
            name = psm.ElementName.regular(name)
        if hasattr(setup, 'to_int'):
            setup_value = setup.to_int()
        else:
            setup_value = setup
        native_obj = psm.Element.setup(name, setup_value)
        if native_obj.isValid():
            return cls(native_obj)
        return None

    def __enter__(self) -> Self:
        """Context manager support."""
        return self

    def __exit__(self, exc_type, exc_val, exc_tb) -> None:
        """Context manager support for auto-releasing resources."""
        self.releaserelease()

    def __del__(self) -> None:
        """Destructor to ensure resources are released.

        Note: This may not always be called immediately when the object goes out of scope,
        especially if the object is part of a reference cycle. For deterministic cleanup,
        use the release() method explicitly or use the object as a context manager.
        """
        try:
            if hasattr(self, '_native_obj') and self._native_obj:
                self.releaserelease()
        except Exception:
            pass