1 |
commit: e9107ff787011fc48d4d8a48499242f4d4f7c889 |
2 |
Author: Michał Górny <mgorny <AT> gentoo <DOT> org> |
3 |
AuthorDate: Wed Jun 2 15:23:48 2021 +0000 |
4 |
Commit: Michał Górny <mgorny <AT> gentoo <DOT> org> |
5 |
CommitDate: Wed Jun 2 16:12:37 2021 +0000 |
6 |
URL: https://gitweb.gentoo.org/repo/gentoo.git/commit/?id=e9107ff7 |
7 |
|
8 |
dev-python/pyfakefs: Enable py3.10 |
9 |
|
10 |
Signed-off-by: Michał Górny <mgorny <AT> gentoo.org> |
11 |
|
12 |
.../pyfakefs/files/pyfakefs-4.4.0-py310.patch | 265 +++++++++++++++++++++ |
13 |
dev-python/pyfakefs/pyfakefs-4.4.0.ebuild | 6 +- |
14 |
2 files changed, 270 insertions(+), 1 deletion(-) |
15 |
|
16 |
diff --git a/dev-python/pyfakefs/files/pyfakefs-4.4.0-py310.patch b/dev-python/pyfakefs/files/pyfakefs-4.4.0-py310.patch |
17 |
new file mode 100644 |
18 |
index 00000000000..6ef35df7d1f |
19 |
--- /dev/null |
20 |
+++ b/dev-python/pyfakefs/files/pyfakefs-4.4.0-py310.patch |
21 |
@@ -0,0 +1,265 @@ |
22 |
+From a8a70bb7746ba24aa60c9915311e1ff5b402146c Mon Sep 17 00:00:00 2001 |
23 |
+From: Carl Montanari <8515611+carlmontanari@××××××××××××××××××××.com> |
24 |
+Date: Thu, 13 May 2021 22:44:45 -0700 |
25 |
+Subject: [PATCH] Add support for Python 3.10 beta1 (#594) |
26 |
+ |
27 |
+- add Python 3.10-beta1 to CI |
28 |
+- adapt fake pathlib, fix pathlib.Path methods link_to, getcwd, lchmod |
29 |
+- handle dummy encoding "locale" introduced in Python 3.10 |
30 |
+- do not test extra dependencies with Python 3.10 (some are not available) |
31 |
+--- |
32 |
+ pyfakefs/fake_filesystem.py | 15 ++++--- |
33 |
+ pyfakefs/fake_pathlib.py | 64 ++++++++++++++++++++++------- |
34 |
+ pyfakefs/helpers.py | 9 ++++ |
35 |
+ pyfakefs/tests/fake_pathlib_test.py | 27 +++++++++--- |
36 |
+ 6 files changed, 109 insertions(+), 32 deletions(-) |
37 |
+ |
38 |
+diff --git a/pyfakefs/fake_filesystem.py b/pyfakefs/fake_filesystem.py |
39 |
+index 1e9bfc8..971dc93 100644 |
40 |
+--- a/pyfakefs/fake_filesystem.py |
41 |
++++ b/pyfakefs/fake_filesystem.py |
42 |
+@@ -114,7 +114,7 @@ from pyfakefs.fake_scandir import scandir, walk |
43 |
+ from pyfakefs.helpers import ( |
44 |
+ FakeStatResult, BinaryBufferIO, TextBufferIO, |
45 |
+ is_int_type, is_byte_string, is_unicode_string, |
46 |
+- make_string_path, IS_WIN, to_string, matching_string |
47 |
++ make_string_path, IS_WIN, to_string, matching_string, real_encoding |
48 |
+ ) |
49 |
+ from pyfakefs import __version__ # noqa: F401 for upwards compatibility |
50 |
+ |
51 |
+@@ -293,7 +293,7 @@ class FakeFile: |
52 |
+ if st_mode >> 12 == 0: |
53 |
+ st_mode |= S_IFREG |
54 |
+ self.stat_result.st_mode = st_mode |
55 |
+- self.encoding = encoding |
56 |
++ self.encoding = real_encoding(encoding) |
57 |
+ self.errors = errors or 'strict' |
58 |
+ self._byte_contents = self._encode_contents(contents) |
59 |
+ self.stat_result.st_size = ( |
60 |
+@@ -430,7 +430,7 @@ class FakeFile: |
61 |
+ OSError: if `st_size` is not a non-negative integer, |
62 |
+ or if it exceeds the available file system space. |
63 |
+ """ |
64 |
+- self.encoding = encoding |
65 |
++ self.encoding = real_encoding(encoding) |
66 |
+ changed = self._set_initial_contents(contents) |
67 |
+ if self._side_effect is not None: |
68 |
+ self._side_effect(self) |
69 |
+@@ -1177,9 +1177,12 @@ class FakeFilesystem: |
70 |
+ OSError: if the filesystem object doesn't exist. |
71 |
+ """ |
72 |
+ # stat should return the tuple representing return value of os.stat |
73 |
+- file_object = self.resolve( |
74 |
+- entry_path, follow_symlinks, |
75 |
+- allow_fd=True, check_read_perm=False) |
76 |
++ try: |
77 |
++ file_object = self.resolve( |
78 |
++ entry_path, follow_symlinks, |
79 |
++ allow_fd=True, check_read_perm=False) |
80 |
++ except TypeError: |
81 |
++ file_object = self.resolve(entry_path) |
82 |
+ if not is_root(): |
83 |
+ # make sure stat raises if a parent dir is not readable |
84 |
+ parent_dir = file_object.parent_dir |
85 |
+diff --git a/pyfakefs/fake_pathlib.py b/pyfakefs/fake_pathlib.py |
86 |
+index b43b178..09933fa 100644 |
87 |
+--- a/pyfakefs/fake_pathlib.py |
88 |
++++ b/pyfakefs/fake_pathlib.py |
89 |
+@@ -53,8 +53,8 @@ def init_module(filesystem): |
90 |
+ |
91 |
+ def _wrap_strfunc(strfunc): |
92 |
+ @functools.wraps(strfunc) |
93 |
+- def _wrapped(pathobj, *args): |
94 |
+- return strfunc(pathobj.filesystem, str(pathobj), *args) |
95 |
++ def _wrapped(pathobj, *args, **kwargs): |
96 |
++ return strfunc(pathobj.filesystem, str(pathobj), *args, **kwargs) |
97 |
+ |
98 |
+ return staticmethod(_wrapped) |
99 |
+ |
100 |
+@@ -94,19 +94,24 @@ class _FakeAccessor(accessor): |
101 |
+ |
102 |
+ listdir = _wrap_strfunc(FakeFilesystem.listdir) |
103 |
+ |
104 |
+- chmod = _wrap_strfunc(FakeFilesystem.chmod) |
105 |
+- |
106 |
+ if use_scandir: |
107 |
+ scandir = _wrap_strfunc(fake_scandir.scandir) |
108 |
+ |
109 |
+ if hasattr(os, "lchmod"): |
110 |
+ lchmod = _wrap_strfunc(lambda fs, path, mode: FakeFilesystem.chmod( |
111 |
+ fs, path, mode, follow_symlinks=False)) |
112 |
++ chmod = _wrap_strfunc(FakeFilesystem.chmod) |
113 |
+ else: |
114 |
+- def lchmod(self, pathobj, mode): |
115 |
++ def lchmod(self, pathobj, *args, **kwargs): |
116 |
+ """Raises not implemented for Windows systems.""" |
117 |
+ raise NotImplementedError("lchmod() not available on this system") |
118 |
+ |
119 |
++ def chmod(self, pathobj, *args, **kwargs): |
120 |
++ if "follow_symlinks" in kwargs and not kwargs["follow_symlinks"]: |
121 |
++ raise NotImplementedError( |
122 |
++ "lchmod() not available on this system") |
123 |
++ return pathobj.filesystem.chmod(str(pathobj), *args, **kwargs) |
124 |
++ |
125 |
+ mkdir = _wrap_strfunc(FakeFilesystem.makedir) |
126 |
+ |
127 |
+ unlink = _wrap_strfunc(FakeFilesystem.remove) |
128 |
+@@ -124,13 +129,21 @@ class _FakeAccessor(accessor): |
129 |
+ FakeFilesystem.create_symlink(fs, file_path, link_target, |
130 |
+ create_missing_dirs=False)) |
131 |
+ |
132 |
+- if sys.version_info >= (3, 8): |
133 |
++ if (3, 8) <= sys.version_info < (3, 10): |
134 |
+ link_to = _wrap_binary_strfunc( |
135 |
+ lambda fs, file_path, link_target: |
136 |
+ FakeFilesystem.link(fs, file_path, link_target)) |
137 |
+ |
138 |
+- if sys.version_info >= (3, 9): |
139 |
+- readlink = _wrap_strfunc(FakeFilesystem.readlink) |
140 |
++ if sys.version_info >= (3, 10): |
141 |
++ link = _wrap_binary_strfunc( |
142 |
++ lambda fs, file_path, link_target: |
143 |
++ FakeFilesystem.link(fs, file_path, link_target)) |
144 |
++ |
145 |
++ # this will use the fake filesystem because os is patched |
146 |
++ def getcwd(self): |
147 |
++ return os.getcwd() |
148 |
++ |
149 |
++ readlink = _wrap_strfunc(FakeFilesystem.readlink) |
150 |
+ |
151 |
+ utime = _wrap_strfunc(FakeFilesystem.utime) |
152 |
+ |
153 |
+@@ -461,19 +474,42 @@ class FakePath(pathlib.Path): |
154 |
+ cls = (FakePathlibModule.WindowsPath |
155 |
+ if cls.filesystem.is_windows_fs |
156 |
+ else FakePathlibModule.PosixPath) |
157 |
+- self = cls._from_parts(args, init=True) |
158 |
++ self = cls._from_parts(args) |
159 |
+ return self |
160 |
+ |
161 |
+- def _path(self): |
162 |
+- """Returns the underlying path string as used by the fake filesystem. |
163 |
+- """ |
164 |
+- return str(self) |
165 |
++ @classmethod |
166 |
++ def _from_parts(cls, args, init=False): # pylint: disable=unused-argument |
167 |
++ # Overwritten to call _init to set the fake accessor, |
168 |
++ # which is not done since Python 3.10 |
169 |
++ self = object.__new__(cls) |
170 |
++ self._init() |
171 |
++ drv, root, parts = self._parse_args(args) |
172 |
++ self._drv = drv |
173 |
++ self._root = root |
174 |
++ self._parts = parts |
175 |
++ return self |
176 |
++ |
177 |
++ @classmethod |
178 |
++ def _from_parsed_parts(cls, drv, root, parts): |
179 |
++ # Overwritten to call _init to set the fake accessor, |
180 |
++ # which is not done since Python 3.10 |
181 |
++ self = object.__new__(cls) |
182 |
++ self._init() |
183 |
++ self._drv = drv |
184 |
++ self._root = root |
185 |
++ self._parts = parts |
186 |
++ return self |
187 |
+ |
188 |
+ def _init(self, template=None): |
189 |
+ """Initializer called from base class.""" |
190 |
+ self._accessor = _fake_accessor |
191 |
+ self._closed = False |
192 |
+ |
193 |
++ def _path(self): |
194 |
++ """Returns the underlying path string as used by the fake filesystem. |
195 |
++ """ |
196 |
++ return str(self) |
197 |
++ |
198 |
+ @classmethod |
199 |
+ def cwd(cls): |
200 |
+ """Return a new path pointing to the current working directory |
201 |
+@@ -722,7 +758,7 @@ class RealPath(pathlib.Path): |
202 |
+ if cls is RealPathlibModule.Path: |
203 |
+ cls = (RealPathlibModule.WindowsPath if os.name == 'nt' |
204 |
+ else RealPathlibModule.PosixPath) |
205 |
+- self = cls._from_parts(args, init=True) |
206 |
++ self = cls._from_parts(args) |
207 |
+ return self |
208 |
+ |
209 |
+ |
210 |
+diff --git a/pyfakefs/helpers.py b/pyfakefs/helpers.py |
211 |
+index aa3959d..08962fc 100644 |
212 |
+--- a/pyfakefs/helpers.py |
213 |
++++ b/pyfakefs/helpers.py |
214 |
+@@ -57,6 +57,15 @@ def to_string(path): |
215 |
+ return path |
216 |
+ |
217 |
+ |
218 |
++def real_encoding(encoding): |
219 |
++ """Since Python 3.10, the new function ``io.text_encoding`` returns |
220 |
++ "locale" as the encoding if None is defined. This will be handled |
221 |
++ as no encoding in pyfakefs.""" |
222 |
++ if sys.version_info >= (3, 10): |
223 |
++ return encoding if encoding != "locale" else None |
224 |
++ return encoding |
225 |
++ |
226 |
++ |
227 |
+ def matching_string(matched, string): |
228 |
+ """Return the string as byte or unicode depending |
229 |
+ on the type of matched, assuming string is an ASCII string. |
230 |
+diff --git a/pyfakefs/tests/fake_pathlib_test.py b/pyfakefs/tests/fake_pathlib_test.py |
231 |
+index 5dcc57f..efea509 100644 |
232 |
+--- a/pyfakefs/tests/fake_pathlib_test.py |
233 |
++++ b/pyfakefs/tests/fake_pathlib_test.py |
234 |
+@@ -378,10 +378,11 @@ class FakePathlibFileObjectPropertyTest(RealPathlibTestCase): |
235 |
+ # we get stat.S_IFLNK | 0o755 under MacOs |
236 |
+ self.assertEqual(link_stat.st_mode, stat.S_IFLNK | 0o777) |
237 |
+ |
238 |
+- @unittest.skipIf(sys.platform == 'darwin', |
239 |
+- 'Different behavior under MacOs') |
240 |
+ def test_lchmod(self): |
241 |
+ self.skip_if_symlink_not_supported() |
242 |
++ if (sys.version_info >= (3, 10) and self.use_real_fs() and |
243 |
++ 'chmod' not in os.supports_follow_symlinks): |
244 |
++ raise unittest.SkipTest('follow_symlinks not available for chmod') |
245 |
+ file_stat = self.os.stat(self.file_path) |
246 |
+ link_stat = self.os.lstat(self.file_link_path) |
247 |
+ if not hasattr(os, "lchmod"): |
248 |
+@@ -390,8 +391,9 @@ class FakePathlibFileObjectPropertyTest(RealPathlibTestCase): |
249 |
+ else: |
250 |
+ self.path(self.file_link_path).lchmod(0o444) |
251 |
+ self.assertEqual(file_stat.st_mode, stat.S_IFREG | 0o666) |
252 |
+- # we get stat.S_IFLNK | 0o755 under MacOs |
253 |
+- self.assertEqual(link_stat.st_mode, stat.S_IFLNK | 0o444) |
254 |
++ # the exact mode depends on OS and Python version |
255 |
++ self.assertEqual(link_stat.st_mode & 0o777700, |
256 |
++ stat.S_IFLNK | 0o700) |
257 |
+ |
258 |
+ def test_resolve(self): |
259 |
+ self.create_dir(self.make_path('antoine', 'docs')) |
260 |
+@@ -968,7 +970,22 @@ class FakePathlibUsageInOsFunctionsTest(RealPathlibTestCase): |
261 |
+ def test_stat(self): |
262 |
+ path = self.make_path('foo', 'bar', 'baz') |
263 |
+ self.create_file(path, contents='1234567') |
264 |
+- self.assertEqual(self.os.stat(path), self.os.stat(self.path(path))) |
265 |
++ self.assertEqual(self.os.stat(path), self.path(path).stat()) |
266 |
++ |
267 |
++ @unittest.skipIf(sys.version_info < (3, 10), "New in Python 3.10") |
268 |
++ def test_stat_follow_symlinks(self): |
269 |
++ self.check_posix_only() |
270 |
++ directory = self.make_path('foo') |
271 |
++ base_name = 'bar' |
272 |
++ file_path = self.path(self.os.path.join(directory, base_name)) |
273 |
++ link_path = self.path(self.os.path.join(directory, 'link')) |
274 |
++ contents = "contents" |
275 |
++ self.create_file(file_path, contents=contents) |
276 |
++ self.create_symlink(link_path, base_name) |
277 |
++ self.assertEqual(len(contents), |
278 |
++ link_path.stat(follow_symlinks=True)[stat.ST_SIZE]) |
279 |
++ self.assertEqual(len(base_name), |
280 |
++ link_path.stat(follow_symlinks=False)[stat.ST_SIZE]) |
281 |
+ |
282 |
+ def test_utime(self): |
283 |
+ path = self.make_path('some_file') |
284 |
+-- |
285 |
+2.31.1 |
286 |
+ |
287 |
|
288 |
diff --git a/dev-python/pyfakefs/pyfakefs-4.4.0.ebuild b/dev-python/pyfakefs/pyfakefs-4.4.0.ebuild |
289 |
index e7a85e83b59..5e06b22143d 100644 |
290 |
--- a/dev-python/pyfakefs/pyfakefs-4.4.0.ebuild |
291 |
+++ b/dev-python/pyfakefs/pyfakefs-4.4.0.ebuild |
292 |
@@ -3,7 +3,7 @@ |
293 |
|
294 |
EAPI=7 |
295 |
|
296 |
-PYTHON_COMPAT=( python3_{7..9} pypy3 ) |
297 |
+PYTHON_COMPAT=( python3_{7..10} pypy3 ) |
298 |
DISTUTILS_IN_SOURCE_BUILD=1 |
299 |
|
300 |
inherit distutils-r1 |
301 |
@@ -18,6 +18,10 @@ KEYWORDS="~alpha amd64 arm arm64 hppa ~ia64 ~mips ppc ppc64 ~riscv ~s390 sparc x |
302 |
|
303 |
distutils_enable_tests pytest |
304 |
|
305 |
+PATCHES=( |
306 |
+ "${FILESDIR}"/${P}-py310.patch |
307 |
+) |
308 |
+ |
309 |
python_test() { |
310 |
"${EPYTHON}" -m pyfakefs.tests.all_tests -v || die "tests failed under ${EPYTHON}" |
311 |
} |