|
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