File valuefd.py#
File List > libpisoundmicro > pypisoundmicro > pypisoundmicro > valuefd.py
Go to the documentation of this file
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# SPDX-License-Identifier: LGPL-2.1-only
#
# libpisoundmicro - a utility library for Pisound Micro I/O expander capabilities.
# Copyright (c) 2017-2025 Vilniaus Blokas UAB, https://blokas.io/
#
# This file is part of libpisoundmicro.
#
# libpisoundmicro is free software: you can redistribute it and/or modify it under the terms of the
# GNU Lesser General Public License as published by the Free Software Foundation, version 2.1 of the License.
#
# libpisoundmicro is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
# the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
# for more details.
#
# You should have received a copy of the GNU Lesser General Public License along with libpisoundmicro. If not, see <https://www.gnu.org/licenses/>.
import os
from .swig import pypisoundmicro as psm
from ._utils import copy_doc
from typing import Union
@copy_doc(psm.ValueFd)
class ValueFd:
    """A wrapper around a file descriptor for reading/writing element values."""
    _fd_obj: psm.ValueFd = None
    def __init__(self, fd : Union[psm.ValueFd, int]):
        """Create a ValueFd from an existing file descriptor.
        Args:
            fd (int): The file descriptor to wrap
        """
        if isinstance(fd, psm.ValueFd):
            self._fd_obj = fd
        elif isinstance(fd, int):
            self._fd_obj = psm.ValueFd(fd)
        else:
            raise TypeError("fd must be a psm.ValueFd or an int")
    def __del__(self):
        """Close the file descriptor when the object is garbage collected."""
        self.close()
    @property
    @copy_doc(psm.ValueFd.isValid)
    def is_valid(self) -> bool:
        return self._fd_obj.isValid() if self._fd_obj else False
    @copy_doc(psm.ValueFd.take)
    def take(self) -> int:
        if self._fd_obj is None:
            return -1
        fd = self._fd_obj.take()
        self._fd_obj = None
        return fd
    @copy_doc(psm.ValueFd.get)
    def get(self) -> int:
        return self._fd_obj.get() if self._fd_obj else -1
    @copy_doc(psm.ValueFd.close)
    def close(self) -> None:
        if hasattr(self, '_fd_obj') and self._fd_obj is not None:
            err = self._fd_obj.close()
            if err != 0:
                raise OSError(f"Failed to close file descriptor: {err}")
            self._fd_obj = None
    @copy_doc(psm.ValueFd.write)
    def write(self, value) -> int:
        return self._fd_obj.write(value) if self._fd_obj else -1
    def read(self) -> int:
        """
        Reads a decimal number from the fd and returns it as integer.
        :raises OSError: If the file descriptor is invalid or if an error occurs during reading.
        :return: The read value.
        """
        if self._fd_obj is None:
            return (-1, os.EBADF)
        result, err = self._fd_obj.read()
        if err != 0:
            raise OSError(f"Failed to read from file descriptor: {err}")
        return result