|
7 | 7 | from errno import *
|
8 | 8 | from glob import _StringGlobber, _no_recurse_symlinks
|
9 | 9 | from itertools import chain
|
10 |
| -from stat import S_IMODE, S_ISDIR, S_ISREG, S_ISSOCK, S_ISBLK, S_ISCHR, S_ISFIFO |
| 10 | +from stat import S_ISDIR, S_ISREG, S_ISSOCK, S_ISBLK, S_ISCHR, S_ISFIFO |
11 | 11 | from _collections_abc import Sequence
|
12 | 12 |
|
13 | 13 | try:
|
|
19 | 19 | except ImportError:
|
20 | 20 | grp = None
|
21 | 21 |
|
22 |
| -from pathlib._os import copyfile, PathInfo, DirEntryInfo |
23 |
| -from pathlib._abc import CopyReader, CopyWriter, JoinablePath, ReadablePath, WritablePath |
| 22 | +from pathlib._os import LocalCopyReader, LocalCopyWriter, PathInfo, DirEntryInfo |
| 23 | +from pathlib._abc import JoinablePath, ReadablePath, WritablePath |
24 | 24 |
|
25 | 25 |
|
26 | 26 | __all__ = [
|
@@ -65,141 +65,6 @@ def __repr__(self):
|
65 | 65 | return "<{}.parents>".format(type(self._path).__name__)
|
66 | 66 |
|
67 | 67 |
|
68 |
| -class _LocalCopyReader(CopyReader): |
69 |
| - """This object implements the "read" part of copying local paths. Don't |
70 |
| - try to construct it yourself. |
71 |
| - """ |
72 |
| - __slots__ = () |
73 |
| - |
74 |
| - _readable_metakeys = {'mode', 'times_ns'} |
75 |
| - if hasattr(os.stat_result, 'st_flags'): |
76 |
| - _readable_metakeys.add('flags') |
77 |
| - if hasattr(os, 'listxattr'): |
78 |
| - _readable_metakeys.add('xattrs') |
79 |
| - _readable_metakeys = frozenset(_readable_metakeys) |
80 |
| - |
81 |
| - def _read_metadata(self, metakeys, *, follow_symlinks=True): |
82 |
| - metadata = {} |
83 |
| - if 'mode' in metakeys or 'times_ns' in metakeys or 'flags' in metakeys: |
84 |
| - st = self._path.stat(follow_symlinks=follow_symlinks) |
85 |
| - if 'mode' in metakeys: |
86 |
| - metadata['mode'] = S_IMODE(st.st_mode) |
87 |
| - if 'times_ns' in metakeys: |
88 |
| - metadata['times_ns'] = st.st_atime_ns, st.st_mtime_ns |
89 |
| - if 'flags' in metakeys: |
90 |
| - metadata['flags'] = st.st_flags |
91 |
| - if 'xattrs' in metakeys: |
92 |
| - try: |
93 |
| - metadata['xattrs'] = [ |
94 |
| - (attr, os.getxattr(self._path, attr, follow_symlinks=follow_symlinks)) |
95 |
| - for attr in os.listxattr(self._path, follow_symlinks=follow_symlinks)] |
96 |
| - except OSError as err: |
97 |
| - if err.errno not in (EPERM, ENOTSUP, ENODATA, EINVAL, EACCES): |
98 |
| - raise |
99 |
| - return metadata |
100 |
| - |
101 |
| - |
102 |
| -class _LocalCopyWriter(CopyWriter): |
103 |
| - """This object implements the "write" part of copying local paths. Don't |
104 |
| - try to construct it yourself. |
105 |
| - """ |
106 |
| - __slots__ = () |
107 |
| - |
108 |
| - _writable_metakeys = _LocalCopyReader._readable_metakeys |
109 |
| - |
110 |
| - def _write_metadata(self, metadata, *, follow_symlinks=True): |
111 |
| - def _nop(*args, ns=None, follow_symlinks=None): |
112 |
| - pass |
113 |
| - |
114 |
| - if follow_symlinks: |
115 |
| - # use the real function if it exists |
116 |
| - def lookup(name): |
117 |
| - return getattr(os, name, _nop) |
118 |
| - else: |
119 |
| - # use the real function only if it exists |
120 |
| - # *and* it supports follow_symlinks |
121 |
| - def lookup(name): |
122 |
| - fn = getattr(os, name, _nop) |
123 |
| - if fn in os.supports_follow_symlinks: |
124 |
| - return fn |
125 |
| - return _nop |
126 |
| - |
127 |
| - times_ns = metadata.get('times_ns') |
128 |
| - if times_ns is not None: |
129 |
| - lookup("utime")(self._path, ns=times_ns, follow_symlinks=follow_symlinks) |
130 |
| - # We must copy extended attributes before the file is (potentially) |
131 |
| - # chmod()'ed read-only, otherwise setxattr() will error with -EACCES. |
132 |
| - xattrs = metadata.get('xattrs') |
133 |
| - if xattrs is not None: |
134 |
| - for attr, value in xattrs: |
135 |
| - try: |
136 |
| - os.setxattr(self._path, attr, value, follow_symlinks=follow_symlinks) |
137 |
| - except OSError as e: |
138 |
| - if e.errno not in (EPERM, ENOTSUP, ENODATA, EINVAL, EACCES): |
139 |
| - raise |
140 |
| - mode = metadata.get('mode') |
141 |
| - if mode is not None: |
142 |
| - try: |
143 |
| - lookup("chmod")(self._path, mode, follow_symlinks=follow_symlinks) |
144 |
| - except NotImplementedError: |
145 |
| - # if we got a NotImplementedError, it's because |
146 |
| - # * follow_symlinks=False, |
147 |
| - # * lchown() is unavailable, and |
148 |
| - # * either |
149 |
| - # * fchownat() is unavailable or |
150 |
| - # * fchownat() doesn't implement AT_SYMLINK_NOFOLLOW. |
151 |
| - # (it returned ENOSUP.) |
152 |
| - # therefore we're out of options--we simply cannot chown the |
153 |
| - # symlink. give up, suppress the error. |
154 |
| - # (which is what shutil always did in this circumstance.) |
155 |
| - pass |
156 |
| - flags = metadata.get('flags') |
157 |
| - if flags is not None: |
158 |
| - try: |
159 |
| - lookup("chflags")(self._path, flags, follow_symlinks=follow_symlinks) |
160 |
| - except OSError as why: |
161 |
| - if why.errno not in (EOPNOTSUPP, ENOTSUP): |
162 |
| - raise |
163 |
| - |
164 |
| - if copyfile: |
165 |
| - # Use fast OS routine for local file copying where available. |
166 |
| - def _create_file(self, source, metakeys): |
167 |
| - """Copy the given file to the given target.""" |
168 |
| - try: |
169 |
| - source = os.fspath(source) |
170 |
| - except TypeError: |
171 |
| - if not isinstance(source, WritablePath): |
172 |
| - raise |
173 |
| - super()._create_file(source, metakeys) |
174 |
| - else: |
175 |
| - copyfile(source, os.fspath(self._path)) |
176 |
| - |
177 |
| - if os.name == 'nt': |
178 |
| - # Windows: symlink target might not exist yet if we're copying several |
179 |
| - # files, so ensure we pass is_dir to os.symlink(). |
180 |
| - def _create_symlink(self, source, metakeys): |
181 |
| - """Copy the given symlink to the given target.""" |
182 |
| - self._path.symlink_to(source.readlink(), source.is_dir()) |
183 |
| - if metakeys: |
184 |
| - metadata = source._copy_reader._read_metadata(metakeys, follow_symlinks=False) |
185 |
| - if metadata: |
186 |
| - self._write_metadata(metadata, follow_symlinks=False) |
187 |
| - |
188 |
| - def _ensure_different_file(self, source): |
189 |
| - """ |
190 |
| - Raise OSError(EINVAL) if both paths refer to the same file. |
191 |
| - """ |
192 |
| - try: |
193 |
| - if not self._path.samefile(source): |
194 |
| - return |
195 |
| - except (OSError, ValueError): |
196 |
| - return |
197 |
| - err = OSError(EINVAL, "Source and target are the same file") |
198 |
| - err.filename = str(source) |
199 |
| - err.filename2 = str(self._path) |
200 |
| - raise err |
201 |
| - |
202 |
| - |
203 | 68 | class PurePath(JoinablePath):
|
204 | 69 | """Base class for manipulating paths without I/O.
|
205 | 70 |
|
@@ -1190,8 +1055,8 @@ def replace(self, target):
|
1190 | 1055 | os.replace(self, target)
|
1191 | 1056 | return self.with_segments(target)
|
1192 | 1057 |
|
1193 |
| - _copy_reader = property(_LocalCopyReader) |
1194 |
| - _copy_writer = property(_LocalCopyWriter) |
| 1058 | + _copy_reader = property(LocalCopyReader) |
| 1059 | + _copy_writer = property(LocalCopyWriter) |
1195 | 1060 |
|
1196 | 1061 | def move(self, target):
|
1197 | 1062 | """
|
|
0 commit comments