Source code for konfoo.providers

# -*- coding: utf-8 -*-
"""
providers.py
~~~~~~~~~~~~
Data provider.

:copyright: (c) 2015-2022 by Jochen Gerhaeusser.
:license: BSD, see LICENSE for details
"""
from __future__ import annotations

import abc
from pathlib import Path


[docs]class Provider: """ The :class:`Provider` class provides access for the :class:`Pointer` class to **read** and **write** byte streams from and back to a data *source*. The :class:`Provider` class servers as a metaclass. A derived class must implement the two methods :meth:`read` and :meth:`write` for reading and writing byte streams from and back to the data *source*. """
[docs] @abc.abstractmethod def read(self, address: int = 0, count: int = 0) -> bytes: """ Returns a *number* of bytes read from a data `source` beginning at the start *address*. :param int address: start address to read from. :param int count: number of bytes to read from a data `source`. .. note:: This abstract method must be implemented by a derived class. """ return bytes()
[docs] @abc.abstractmethod def write(self, buffer: bytes | bytearray = bytearray(), address: int = 0, count: int = 0) -> None: """ Writes the content of the *buffer* to a data `source` beginning at the start *address*. :param bytes|bytearray buffer: content to write. :param int address: start address to write to. :param int count: number of bytes to write to a data `source`. .. note:: This abstract method must be implemented by a derived class. """ pass
[docs]class FileProvider(Provider): """ The :class:`FileProvider` is a byte stream :class:`Provider` for binary files. The *file* content is internal stored in a :attr:`~Provider.cache`. The :meth:`read` and :meth:`write` methods only operate on the internal :attr:`~Provider.cache`. Call :meth:`flush` to store the updated file content to the same or a new file. :param Path|str file: name and location of the file to read. """ def __init__(self, file: Path | str) -> None: #: File path. self.path = Path(file).absolute() # File cache. self._cache = bytearray(self.path.read_bytes()) def __str__(self) -> str: return (f"{self.__class__.__name__}" f"({self.path!s}, {len(self._cache)!s})") def __repr__(self) -> str: return (f"{self.__class__.__name__}" f"(file={self.path!r}, size={len(self._cache)!r})") @property def cache(self) -> bytearray: """ Returns the internal byte stream cache of the `Provider` (read-only).""" return self._cache
[docs] def read(self, address: int = 0, count: int = 0) -> bytes: """ Returns a *number* of bytes read from the :attr:`cache` beginning at the start *address*. :param int address: start address. :param int count: number of bytes to read from the cache. """ return self._cache[address:]
[docs] def write(self, buffer: bytes | bytearray = bytes(), address: int = 0, count: int = 0) -> None: """ Writes the content of the *buffer* to the :attr:`cache` beginning at the start *address*. :param bytes|bytearray buffer: content to write. :param int address: start address. :param int count: number of bytes to write to the cache. """ view = memoryview(self._cache) view[address:address + count] = buffer
[docs] def flush(self, file: Path | str | None = None) -> None: """ Flushes the updated file content to the given *file*. .. note:: Overwrites an existing file. :param Path|str|None file: name and location of the file. Default is the original file. """ if file is None: self.path.write_bytes(self._cache) else: Path(file).write_bytes(self._cache)