File: _base.py

package info (click to toggle)
fonttools 4.61.1-3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 27,584 kB
  • sloc: python: 145,091; xml: 103; makefile: 24
file content (134 lines) | stat: -rw-r--r-- 4,010 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
from __future__ import annotations

import typing
from abc import ABC, abstractmethod

from ._copy import copy_dir, copy_file
from ._errors import (
    DestinationExists,
    DirectoryExpected,
    FileExpected,
    FilesystemClosed,
    NoSysPath,
    ResourceNotFound,
)
from ._path import dirname
from ._walk import BoundWalker

if typing.TYPE_CHECKING:
    from typing import IO, Any, Collection, Iterator, Self, Type

    from ._info import Info
    from ._subfs import SubFS


class FS(ABC):
    """Abstract base class for custom filesystems."""

    _closed: bool = False

    @abstractmethod
    def open(self, path: str, mode: str = "rb", **kwargs) -> IO[Any]: ...

    @abstractmethod
    def exists(self, path: str) -> bool: ...

    @abstractmethod
    def isdir(self, path: str) -> bool: ...

    @abstractmethod
    def isfile(self, path: str) -> bool: ...

    @abstractmethod
    def listdir(self, path: str) -> list[str]: ...

    @abstractmethod
    def makedir(self, path: str, recreate: bool = False) -> SubFS: ...

    @abstractmethod
    def makedirs(self, path: str, recreate: bool = False) -> SubFS: ...

    @abstractmethod
    def getinfo(self, path: str, namespaces: Collection[str] | None = None) -> Info: ...

    @abstractmethod
    def remove(self, path: str) -> None: ...

    @abstractmethod
    def removedir(self, path: str) -> None: ...

    @abstractmethod
    def removetree(self, path: str) -> None: ...

    @abstractmethod
    def movedir(self, src: str, dst: str, create: bool = False) -> None: ...

    def getsyspath(self, path: str) -> str:
        raise NoSysPath(f"the filesystem {self!r} has no system path")

    def close(self):
        self._closed = True

    def isclosed(self) -> bool:
        return self._closed

    def __enter__(self) -> Self:
        return self

    def __exit__(self, exc_type, exc, tb):
        self.close()
        return False  # never swallow exceptions

    def check(self):
        if self._closed:
            raise FilesystemClosed(f"the filesystem {self!r} is closed")

    def opendir(self, path: str, *, factory: Type[SubFS] | None = None) -> SubFS:
        """Return a sub‑filesystem rooted at `path`."""
        if factory is None:
            from ._subfs import SubFS

            factory = SubFS
        return factory(self, path)

    def scandir(
        self, path: str, namespaces: Collection[str] | None = None
    ) -> Iterator[Info]:
        return (self.getinfo(f"{path}/{p}", namespaces) for p in self.listdir(path))

    @property
    def walk(self) -> BoundWalker:
        return BoundWalker(self)

    def readbytes(self, path: str) -> bytes:
        with self.open(path, "rb") as f:
            return f.read()

    def writebytes(self, path: str, data: bytes):
        with self.open(path, "wb") as f:
            f.write(data)

    def create(self, path: str, wipe: bool = False):
        if not wipe and self.exists(path):
            return False
        with self.open(path, "wb"):
            pass  # 'touch' empty file
        return True

    def copy(self, src_path: str, dst_path: str, overwrite=False):
        if not self.exists(src_path):
            raise ResourceNotFound(f"{src_path!r} does not exist")
        elif not self.isfile(src_path):
            raise FileExpected(f"path {src_path!r} should be a file")
        if not overwrite and self.exists(dst_path):
            raise DestinationExists(f"destination {dst_path!r} already exists")
        if not self.isdir(dirname(dst_path)):
            raise DirectoryExpected(f"path {dirname(dst_path)!r} should be a directory")
        copy_file(self, src_path, self, dst_path)

    def copydir(self, src_path: str, dst_path: str, create=False):
        if not create and not self.exists(dst_path):
            raise ResourceNotFound(f"{dst_path!r} does not exist")
        if not self.isdir(src_path):
            raise DirectoryExpected(f"path {src_path!r} should be a directory")
        copy_dir(self, src_path, self, dst_path)