aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/Lib/test/test_pathlib/support/local_path.py
blob: d481fd45ead49fec78964bb1efac4438885a2edf (plain) (blame)
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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
"""
Implementations of ReadablePath and WritablePath for local paths, for use in
pathlib tests.

LocalPathGround is also defined here. It helps establish the "ground truth"
about local paths in tests.
"""

import os

from . import is_pypi
from .lexical_path import LexicalPath

if is_pypi:
    from shutil import rmtree
    from pathlib_abc import PathInfo, _ReadablePath, _WritablePath
    can_symlink = True
    testfn = "TESTFN"
else:
    from pathlib.types import PathInfo, _ReadablePath, _WritablePath
    from test.support import os_helper
    can_symlink = os_helper.can_symlink()
    testfn = os_helper.TESTFN
    rmtree = os_helper.rmtree


class LocalPathGround:
    can_symlink = can_symlink

    def __init__(self, path_cls):
        self.path_cls = path_cls

    def setup(self, local_suffix=""):
        root = self.path_cls(testfn + local_suffix)
        os.mkdir(root)
        return root

    def teardown(self, root):
        rmtree(root)

    def create_file(self, p, data=b''):
        with open(p, 'wb') as f:
            f.write(data)

    def create_dir(self, p):
        os.mkdir(p)

    def create_symlink(self, p, target):
        os.symlink(target, p)

    def create_hierarchy(self, p):
        os.mkdir(os.path.join(p, 'dirA'))
        os.mkdir(os.path.join(p, 'dirB'))
        os.mkdir(os.path.join(p, 'dirC'))
        os.mkdir(os.path.join(p, 'dirC', 'dirD'))
        with open(os.path.join(p, 'fileA'), 'wb') as f:
            f.write(b"this is file A\n")
        with open(os.path.join(p, 'dirB', 'fileB'), 'wb') as f:
            f.write(b"this is file B\n")
        with open(os.path.join(p, 'dirC', 'fileC'), 'wb') as f:
            f.write(b"this is file C\n")
        with open(os.path.join(p, 'dirC', 'novel.txt'), 'wb') as f:
            f.write(b"this is a novel\n")
        with open(os.path.join(p, 'dirC', 'dirD', 'fileD'), 'wb') as f:
            f.write(b"this is file D\n")
        if self.can_symlink:
            # Relative symlinks.
            os.symlink('fileA', os.path.join(p, 'linkA'))
            os.symlink('non-existing', os.path.join(p, 'brokenLink'))
            os.symlink('dirB',
                       os.path.join(p, 'linkB'),
                       target_is_directory=True)
            os.symlink(os.path.join('..', 'dirB'),
                       os.path.join(p, 'dirA', 'linkC'),
                       target_is_directory=True)
            # Broken symlink (pointing to itself).
            os.symlink('brokenLinkLoop', os.path.join(p, 'brokenLinkLoop'))

    isdir = staticmethod(os.path.isdir)
    isfile = staticmethod(os.path.isfile)
    islink = staticmethod(os.path.islink)
    readlink = staticmethod(os.readlink)

    def readtext(self, p):
        with open(p, 'r', encoding='utf-8') as f:
            return f.read()

    def readbytes(self, p):
        with open(p, 'rb') as f:
            return f.read()


class LocalPathInfo(PathInfo):
    """
    Simple implementation of PathInfo for a local path
    """
    __slots__ = ('_path', '_exists', '_is_dir', '_is_file', '_is_symlink')

    def __init__(self, path):
        self._path = str(path)
        self._exists = None
        self._is_dir = None
        self._is_file = None
        self._is_symlink = None

    def exists(self, *, follow_symlinks=True):
        """Whether this path exists."""
        if not follow_symlinks and self.is_symlink():
            return True
        if self._exists is None:
            self._exists = os.path.exists(self._path)
        return self._exists

    def is_dir(self, *, follow_symlinks=True):
        """Whether this path is a directory."""
        if not follow_symlinks and self.is_symlink():
            return False
        if self._is_dir is None:
            self._is_dir = os.path.isdir(self._path)
        return self._is_dir

    def is_file(self, *, follow_symlinks=True):
        """Whether this path is a regular file."""
        if not follow_symlinks and self.is_symlink():
            return False
        if self._is_file is None:
            self._is_file = os.path.isfile(self._path)
        return self._is_file

    def is_symlink(self):
        """Whether this path is a symbolic link."""
        if self._is_symlink is None:
            self._is_symlink = os.path.islink(self._path)
        return self._is_symlink


class ReadableLocalPath(_ReadablePath, LexicalPath):
    """
    Simple implementation of a ReadablePath class for local filesystem paths.
    """
    __slots__ = ('info',)

    def __init__(self, *pathsegments):
        super().__init__(*pathsegments)
        self.info = LocalPathInfo(self)

    def __fspath__(self):
        return str(self)

    def __open_rb__(self, buffering=-1):
        return open(self, 'rb')

    def iterdir(self):
        return (self / name for name in os.listdir(self))

    def readlink(self):
        return self.with_segments(os.readlink(self))


class WritableLocalPath(_WritablePath, LexicalPath):
    """
    Simple implementation of a WritablePath class for local filesystem paths.
    """

    __slots__ = ()

    def __fspath__(self):
        return str(self)

    def __open_wb__(self, buffering=-1):
        return open(self, 'wb')

    def mkdir(self, mode=0o777):
        os.mkdir(self, mode)

    def symlink_to(self, target, target_is_directory=False):
        os.symlink(target, self, target_is_directory)