| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167 |
- """Application data stored by virtualenv."""
- from __future__ import annotations
- from abc import ABC, abstractmethod
- from contextlib import contextmanager
- from typing import TYPE_CHECKING
- from virtualenv.info import IS_ZIPAPP
- if TYPE_CHECKING:
- from collections.abc import Generator
- from pathlib import Path
- from typing import Any
- class AppData(ABC):
- """Abstract storage interface for the virtualenv application."""
- @abstractmethod
- def close(self) -> None:
- """Called before virtualenv exits."""
- @abstractmethod
- def reset(self) -> None:
- """Called when the user passes in the reset app data."""
- @abstractmethod
- def py_info(self, path: Path) -> ContentStore:
- """Return a content store for cached interpreter information at the given path.
- :param path: the interpreter executable path
- :returns: a content store for the cached data
- """
- raise NotImplementedError
- @abstractmethod
- def py_info_clear(self) -> None:
- """Clear all cached interpreter information."""
- raise NotImplementedError
- @property
- def can_update(self) -> bool:
- """``True`` if this app data store supports updating cached content."""
- raise NotImplementedError
- @abstractmethod
- def embed_update_log(self, distribution: str, for_py_version: str) -> ContentStore:
- """Return a content store for the embed update log of a distribution.
- :param distribution: the package name (e.g. ``pip``)
- :param for_py_version: the target Python version string
- :returns: a content store for the update log
- """
- raise NotImplementedError
- @property
- def house(self) -> Path:
- """The root directory of the application data store."""
- raise NotImplementedError
- @property
- def transient(self) -> bool:
- """``True`` if this app data store is transient and does not persist across runs."""
- raise NotImplementedError
- @abstractmethod
- def wheel_image(self, for_py_version: str, name: str) -> Path:
- """Return the path to a cached wheel image.
- :param for_py_version: the target Python version string
- :param name: the package name
- :returns: the path to the cached wheel
- """
- raise NotImplementedError
- @contextmanager
- def ensure_extracted(self, path: Path, to_folder: Path | None = None) -> Generator[Path]:
- """Ensure a path is available on disk, extracting from zipapp if needed.
- :param path: the path to ensure is available
- :param to_folder: optional target directory for extraction
- :returns: yields the usable path on disk
- """
- if IS_ZIPAPP:
- with self.extract(path, to_folder) as result:
- yield result
- else:
- yield path
- @abstractmethod
- @contextmanager
- def extract(self, path: Path, to_folder: Path | None) -> Generator[Path]:
- """Extract a path from the zipapp to a location on disk.
- :param path: the path to extract
- :param to_folder: optional target directory
- :returns: yields the extracted path
- """
- raise NotImplementedError
- @abstractmethod
- @contextmanager
- def locked(self, path: Path) -> Generator[None]:
- """Acquire an exclusive lock on the given path.
- :param path: the path to lock
- """
- raise NotImplementedError
- class ContentStore(ABC):
- """A store for reading and writing cached content."""
- @abstractmethod
- def exists(self) -> bool:
- """Check if the stored content exists.
- :returns: ``True`` if content exists
- """
- raise NotImplementedError
- @abstractmethod
- def read(self) -> Any: # noqa: ANN401
- """Read the stored content.
- :returns: the stored content
- """
- raise NotImplementedError
- @abstractmethod
- def write(self, content: Any) -> None: # noqa: ANN401
- """Write content to the store.
- :param content: the content to write
- """
- raise NotImplementedError
- @abstractmethod
- def remove(self) -> None:
- """Remove the stored content."""
- raise NotImplementedError
- @abstractmethod
- @contextmanager
- def locked(self) -> Generator[None]:
- """Acquire an exclusive lock on this content store."""
- __all__ = [
- "AppData",
- "ContentStore",
- ]
|