forked from Rust-related/RustPython
Update {test_}posix{path} from CPython 3.10.6
This commit is contained in:
committed by
Jeong YunWon
parent
cee42ca8bd
commit
a27218b8b3
30
Lib/posixpath.py
vendored
30
Lib/posixpath.py
vendored
@@ -265,6 +265,9 @@ def expanduser(path):
|
||||
# password database, return the path unchanged
|
||||
return path
|
||||
userhome = pwent.pw_dir
|
||||
# if no user home, return the path unchanged on VxWorks
|
||||
if userhome is None and sys.platform == "vxworks":
|
||||
return path
|
||||
if isinstance(path, bytes):
|
||||
userhome = os.fsencode(userhome)
|
||||
root = b'/'
|
||||
@@ -352,6 +355,7 @@ def normpath(path):
|
||||
initial_slashes = path.startswith(sep)
|
||||
# POSIX allows one or two initial slashes, but treats three or more
|
||||
# as single slash.
|
||||
# (see http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html#tag_04_13)
|
||||
if (initial_slashes and
|
||||
path.startswith(sep*2) and not path.startswith(sep*3)):
|
||||
initial_slashes = 2
|
||||
@@ -387,16 +391,16 @@ def abspath(path):
|
||||
# Return a canonical path (i.e. the absolute location of a file on the
|
||||
# filesystem).
|
||||
|
||||
def realpath(filename):
|
||||
def realpath(filename, *, strict=False):
|
||||
"""Return the canonical path of the specified filename, eliminating any
|
||||
symbolic links encountered in the path."""
|
||||
filename = os.fspath(filename)
|
||||
path, ok = _joinrealpath(filename[:0], filename, {})
|
||||
path, ok = _joinrealpath(filename[:0], filename, strict, {})
|
||||
return abspath(path)
|
||||
|
||||
# Join two paths, normalizing and eliminating any symbolic links
|
||||
# encountered in the second path.
|
||||
def _joinrealpath(path, rest, seen):
|
||||
def _joinrealpath(path, rest, strict, seen):
|
||||
if isinstance(path, bytes):
|
||||
sep = b'/'
|
||||
curdir = b'.'
|
||||
@@ -425,7 +429,15 @@ def _joinrealpath(path, rest, seen):
|
||||
path = pardir
|
||||
continue
|
||||
newpath = join(path, name)
|
||||
if not islink(newpath):
|
||||
try:
|
||||
st = os.lstat(newpath)
|
||||
except OSError:
|
||||
if strict:
|
||||
raise
|
||||
is_link = False
|
||||
else:
|
||||
is_link = stat.S_ISLNK(st.st_mode)
|
||||
if not is_link:
|
||||
path = newpath
|
||||
continue
|
||||
# Resolve the symbolic link
|
||||
@@ -436,10 +448,14 @@ def _joinrealpath(path, rest, seen):
|
||||
# use cached value
|
||||
continue
|
||||
# The symlink is not resolved, so we must have a symlink loop.
|
||||
# Return already resolved part + rest of the path unchanged.
|
||||
return join(newpath, rest), False
|
||||
if strict:
|
||||
# Raise OSError(errno.ELOOP)
|
||||
os.stat(newpath)
|
||||
else:
|
||||
# Return already resolved part + rest of the path unchanged.
|
||||
return join(newpath, rest), False
|
||||
seen[newpath] = None # not resolved symlink
|
||||
path, ok = _joinrealpath(path, os.readlink(newpath), seen)
|
||||
path, ok = _joinrealpath(path, os.readlink(newpath), strict, seen)
|
||||
if not ok:
|
||||
return join(path, rest), False
|
||||
seen[newpath] = path # resolved symlink
|
||||
|
||||
507
Lib/test/test_posix.py
vendored
507
Lib/test/test_posix.py
vendored
@@ -1,7 +1,9 @@
|
||||
"Test posix functions"
|
||||
|
||||
from test import support
|
||||
from test.support import os_helper, import_helper, warnings_helper
|
||||
from test.support import import_helper
|
||||
from test.support import os_helper
|
||||
from test.support import warnings_helper
|
||||
from test.support.script_helper import assert_python_ok
|
||||
|
||||
# Skip these tests if there is no posix module.
|
||||
@@ -19,6 +21,7 @@ import tempfile
|
||||
import unittest
|
||||
import warnings
|
||||
import textwrap
|
||||
from contextlib import contextmanager
|
||||
|
||||
_DUMMY_SYMLINK = os.path.join(tempfile.gettempdir(),
|
||||
os_helper.TESTFN + '-dummy-symlink')
|
||||
@@ -43,8 +46,8 @@ class PosixTester(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
# create empty file
|
||||
fp = open(os_helper.TESTFN, 'w+')
|
||||
fp.close()
|
||||
with open(os_helper.TESTFN, "wb"):
|
||||
pass
|
||||
self.teardown_files = [ os_helper.TESTFN ]
|
||||
self._warnings_manager = warnings_helper.check_warnings()
|
||||
self._warnings_manager.__enter__()
|
||||
@@ -460,10 +463,14 @@ class PosixTester(unittest.TestCase):
|
||||
def test_utime_nofollow_symlinks(self):
|
||||
now = time.time()
|
||||
posix.utime(os_helper.TESTFN, None, follow_symlinks=False)
|
||||
self.assertRaises(TypeError, posix.utime, os_helper.TESTFN, (None, None), follow_symlinks=False)
|
||||
self.assertRaises(TypeError, posix.utime, os_helper.TESTFN, (now, None), follow_symlinks=False)
|
||||
self.assertRaises(TypeError, posix.utime, os_helper.TESTFN, (None, now), follow_symlinks=False)
|
||||
posix.utime(os_helper.TESTFN, (int(now), int(now)), follow_symlinks=False)
|
||||
self.assertRaises(TypeError, posix.utime, os_helper.TESTFN,
|
||||
(None, None), follow_symlinks=False)
|
||||
self.assertRaises(TypeError, posix.utime, os_helper.TESTFN,
|
||||
(now, None), follow_symlinks=False)
|
||||
self.assertRaises(TypeError, posix.utime, os_helper.TESTFN,
|
||||
(None, now), follow_symlinks=False)
|
||||
posix.utime(os_helper.TESTFN, (int(now), int(now)),
|
||||
follow_symlinks=False)
|
||||
posix.utime(os_helper.TESTFN, (now, now), follow_symlinks=False)
|
||||
posix.utime(os_helper.TESTFN, follow_symlinks=False)
|
||||
|
||||
@@ -638,12 +645,17 @@ class PosixTester(unittest.TestCase):
|
||||
|
||||
@unittest.skipUnless(hasattr(posix, 'mkfifo'), "don't have mkfifo()")
|
||||
def test_mkfifo(self):
|
||||
os_helper.unlink(os_helper.TESTFN)
|
||||
if sys.platform == "vxworks":
|
||||
fifo_path = os.path.join("/fifos/", os_helper.TESTFN)
|
||||
else:
|
||||
fifo_path = os_helper.TESTFN
|
||||
os_helper.unlink(fifo_path)
|
||||
self.addCleanup(os_helper.unlink, fifo_path)
|
||||
try:
|
||||
posix.mkfifo(os_helper.TESTFN, stat.S_IRUSR | stat.S_IWUSR)
|
||||
posix.mkfifo(fifo_path, stat.S_IRUSR | stat.S_IWUSR)
|
||||
except PermissionError as e:
|
||||
self.skipTest('posix.mkfifo(): %s' % e)
|
||||
self.assertTrue(stat.S_ISFIFO(posix.stat(os_helper.TESTFN).st_mode))
|
||||
self.assertTrue(stat.S_ISFIFO(posix.stat(fifo_path).st_mode))
|
||||
|
||||
@unittest.skipUnless(hasattr(posix, 'mknod') and hasattr(stat, 'S_IFIFO'),
|
||||
"don't have mknod()/S_IFIFO")
|
||||
@@ -715,11 +727,20 @@ class PosixTester(unittest.TestCase):
|
||||
chown_func(first_param, uid, -1)
|
||||
check_stat(uid, gid)
|
||||
|
||||
if uid == 0:
|
||||
if sys.platform == "vxworks":
|
||||
# On VxWorks, root user id is 1 and 0 means no login user:
|
||||
# both are super users.
|
||||
is_root = (uid in (0, 1))
|
||||
else:
|
||||
is_root = (uid == 0)
|
||||
if is_root:
|
||||
# Try an amusingly large uid/gid to make sure we handle
|
||||
# large unsigned values. (chown lets you use any
|
||||
# uid/gid you like, even if they aren't defined.)
|
||||
#
|
||||
# On VxWorks uid_t is defined as unsigned short. A big
|
||||
# value greater than 65535 will result in underflow error.
|
||||
#
|
||||
# This problem keeps coming up:
|
||||
# http://bugs.python.org/issue1747858
|
||||
# http://bugs.python.org/issue4591
|
||||
@@ -729,7 +750,7 @@ class PosixTester(unittest.TestCase):
|
||||
# This part of the test only runs when run as root.
|
||||
# Only scary people run their tests as root.
|
||||
|
||||
big_value = 2**31
|
||||
big_value = (2**31 if sys.platform != "vxworks" else 2**15)
|
||||
chown_func(first_param, big_value, big_value)
|
||||
check_stat(big_value, big_value)
|
||||
chown_func(first_param, -1, -1)
|
||||
@@ -893,9 +914,12 @@ class PosixTester(unittest.TestCase):
|
||||
def test_utime(self):
|
||||
now = time.time()
|
||||
posix.utime(os_helper.TESTFN, None)
|
||||
self.assertRaises(TypeError, posix.utime, os_helper.TESTFN, (None, None))
|
||||
self.assertRaises(TypeError, posix.utime, os_helper.TESTFN, (now, None))
|
||||
self.assertRaises(TypeError, posix.utime, os_helper.TESTFN, (None, now))
|
||||
self.assertRaises(TypeError, posix.utime,
|
||||
os_helper.TESTFN, (None, None))
|
||||
self.assertRaises(TypeError, posix.utime,
|
||||
os_helper.TESTFN, (now, None))
|
||||
self.assertRaises(TypeError, posix.utime,
|
||||
os_helper.TESTFN, (None, now))
|
||||
posix.utime(os_helper.TESTFN, (int(now), int(now)))
|
||||
posix.utime(os_helper.TESTFN, (now, now))
|
||||
|
||||
@@ -930,7 +954,8 @@ class PosixTester(unittest.TestCase):
|
||||
@unittest.skipUnless(hasattr(posix, 'lchflags'), 'test needs os.lchflags()')
|
||||
def test_lchflags_regular_file(self):
|
||||
self._test_chflags_regular_file(posix.lchflags, os_helper.TESTFN)
|
||||
self._test_chflags_regular_file(posix.chflags, os_helper.TESTFN, follow_symlinks=False)
|
||||
self._test_chflags_regular_file(posix.chflags, os_helper.TESTFN,
|
||||
follow_symlinks=False)
|
||||
|
||||
@unittest.skipUnless(hasattr(posix, 'lchflags'), 'test needs os.lchflags()')
|
||||
def test_lchflags_symlink(self):
|
||||
@@ -1034,6 +1059,7 @@ class PosixTester(unittest.TestCase):
|
||||
|
||||
|
||||
@unittest.skipUnless(hasattr(os, 'getegid'), "test needs os.getegid()")
|
||||
@unittest.skipUnless(hasattr(os, 'popen'), "test needs os.popen()")
|
||||
def test_getgroups(self):
|
||||
with os.popen('id -G 2>/dev/null') as idg:
|
||||
groups = idg.read().strip()
|
||||
@@ -1049,8 +1075,8 @@ class PosixTester(unittest.TestCase):
|
||||
# Issues 16698: OS X ABIs prior to 10.6 have limits on getgroups()
|
||||
if sys.platform == 'darwin':
|
||||
import sysconfig
|
||||
dt = sysconfig.get_config_var('MACOSX_DEPLOYMENT_TARGET') or '10.0'
|
||||
if tuple(int(n) for n in str(dt).split('.')[0:2]) < (10, 6):
|
||||
dt = sysconfig.get_config_var('MACOSX_DEPLOYMENT_TARGET') or '10.3'
|
||||
if tuple(int(n) for n in dt.split('.')[0:2]) < (10, 6):
|
||||
raise unittest.SkipTest("getgroups(2) is broken prior to 10.6")
|
||||
|
||||
# 'id -G' and 'os.getgroups()' should return the same
|
||||
@@ -1060,176 +1086,6 @@ class PosixTester(unittest.TestCase):
|
||||
symdiff = idg_groups.symmetric_difference(posix.getgroups())
|
||||
self.assertTrue(not symdiff or symdiff == {posix.getegid()})
|
||||
|
||||
# tests for the posix *at functions follow
|
||||
|
||||
@unittest.skipUnless(os.access in os.supports_dir_fd, "test needs dir_fd support for os.access()")
|
||||
def test_access_dir_fd(self):
|
||||
f = posix.open(posix.getcwd(), posix.O_RDONLY)
|
||||
try:
|
||||
self.assertTrue(posix.access(os_helper.TESTFN, os.R_OK, dir_fd=f))
|
||||
finally:
|
||||
posix.close(f)
|
||||
|
||||
@unittest.skipUnless(os.chmod in os.supports_dir_fd, "test needs dir_fd support in os.chmod()")
|
||||
def test_chmod_dir_fd(self):
|
||||
os.chmod(os_helper.TESTFN, stat.S_IRUSR)
|
||||
|
||||
f = posix.open(posix.getcwd(), posix.O_RDONLY)
|
||||
try:
|
||||
posix.chmod(os_helper.TESTFN, stat.S_IRUSR | stat.S_IWUSR, dir_fd=f)
|
||||
|
||||
s = posix.stat(os_helper.TESTFN)
|
||||
self.assertEqual(s[0] & stat.S_IRWXU, stat.S_IRUSR | stat.S_IWUSR)
|
||||
finally:
|
||||
posix.close(f)
|
||||
|
||||
@unittest.skipUnless(os.chown in os.supports_dir_fd, "test needs dir_fd support in os.chown()")
|
||||
def test_chown_dir_fd(self):
|
||||
os_helper.unlink(os_helper.TESTFN)
|
||||
os_helper.create_empty_file(os_helper.TESTFN)
|
||||
|
||||
f = posix.open(posix.getcwd(), posix.O_RDONLY)
|
||||
try:
|
||||
posix.chown(os_helper.TESTFN, os.getuid(), os.getgid(), dir_fd=f)
|
||||
finally:
|
||||
posix.close(f)
|
||||
|
||||
@unittest.skipUnless(os.stat in os.supports_dir_fd, "test needs dir_fd support in os.stat()")
|
||||
def test_stat_dir_fd(self):
|
||||
os_helper.unlink(os_helper.TESTFN)
|
||||
with open(os_helper.TESTFN, 'w') as outfile:
|
||||
outfile.write("testline\n")
|
||||
|
||||
f = posix.open(posix.getcwd(), posix.O_RDONLY)
|
||||
try:
|
||||
s1 = posix.stat(os_helper.TESTFN)
|
||||
s2 = posix.stat(os_helper.TESTFN, dir_fd=f)
|
||||
self.assertEqual(s1, s2)
|
||||
s2 = posix.stat(os_helper.TESTFN, dir_fd=None)
|
||||
self.assertEqual(s1, s2)
|
||||
self.assertRaisesRegex(TypeError, 'should be integer or None, not',
|
||||
posix.stat, os_helper.TESTFN, dir_fd=posix.getcwd())
|
||||
self.assertRaisesRegex(TypeError, 'should be integer or None, not',
|
||||
posix.stat, os_helper.TESTFN, dir_fd=float(f))
|
||||
self.assertRaises(OverflowError,
|
||||
posix.stat, os_helper.TESTFN, dir_fd=10**20)
|
||||
finally:
|
||||
posix.close(f)
|
||||
|
||||
@unittest.skipUnless(os.utime in os.supports_dir_fd, "test needs dir_fd support in os.utime()")
|
||||
def test_utime_dir_fd(self):
|
||||
f = posix.open(posix.getcwd(), posix.O_RDONLY)
|
||||
try:
|
||||
now = time.time()
|
||||
posix.utime(os_helper.TESTFN, None, dir_fd=f)
|
||||
posix.utime(os_helper.TESTFN, dir_fd=f)
|
||||
self.assertRaises(TypeError, posix.utime, os_helper.TESTFN, now, dir_fd=f)
|
||||
self.assertRaises(TypeError, posix.utime, os_helper.TESTFN, (None, None), dir_fd=f)
|
||||
self.assertRaises(TypeError, posix.utime, os_helper.TESTFN, (now, None), dir_fd=f)
|
||||
self.assertRaises(TypeError, posix.utime, os_helper.TESTFN, (None, now), dir_fd=f)
|
||||
self.assertRaises(TypeError, posix.utime, os_helper.TESTFN, (now, "x"), dir_fd=f)
|
||||
posix.utime(os_helper.TESTFN, (int(now), int(now)), dir_fd=f)
|
||||
posix.utime(os_helper.TESTFN, (now, now), dir_fd=f)
|
||||
posix.utime(os_helper.TESTFN,
|
||||
(int(now), int((now - int(now)) * 1e9)), dir_fd=f)
|
||||
posix.utime(os_helper.TESTFN, dir_fd=f,
|
||||
times=(int(now), int((now - int(now)) * 1e9)))
|
||||
|
||||
# try dir_fd and follow_symlinks together
|
||||
if os.utime in os.supports_follow_symlinks:
|
||||
try:
|
||||
posix.utime(os_helper.TESTFN, follow_symlinks=False, dir_fd=f)
|
||||
except ValueError:
|
||||
# whoops! using both together not supported on this platform.
|
||||
pass
|
||||
|
||||
finally:
|
||||
posix.close(f)
|
||||
|
||||
@unittest.skipUnless(os.link in os.supports_dir_fd, "test needs dir_fd support in os.link()")
|
||||
def test_link_dir_fd(self):
|
||||
f = posix.open(posix.getcwd(), posix.O_RDONLY)
|
||||
try:
|
||||
posix.link(os_helper.TESTFN, os_helper.TESTFN + 'link', src_dir_fd=f, dst_dir_fd=f)
|
||||
except PermissionError as e:
|
||||
self.skipTest('posix.link(): %s' % e)
|
||||
else:
|
||||
# should have same inodes
|
||||
self.assertEqual(posix.stat(os_helper.TESTFN)[1],
|
||||
posix.stat(os_helper.TESTFN + 'link')[1])
|
||||
finally:
|
||||
posix.close(f)
|
||||
os_helper.unlink(os_helper.TESTFN + 'link')
|
||||
|
||||
@unittest.skipUnless(os.mkdir in os.supports_dir_fd, "test needs dir_fd support in os.mkdir()")
|
||||
def test_mkdir_dir_fd(self):
|
||||
f = posix.open(posix.getcwd(), posix.O_RDONLY)
|
||||
try:
|
||||
posix.mkdir(os_helper.TESTFN + 'dir', dir_fd=f)
|
||||
posix.stat(os_helper.TESTFN + 'dir') # should not raise exception
|
||||
finally:
|
||||
posix.close(f)
|
||||
os_helper.rmtree(os_helper.TESTFN + 'dir')
|
||||
|
||||
@unittest.skipUnless((os.mknod in os.supports_dir_fd) and hasattr(stat, 'S_IFIFO'),
|
||||
"test requires both stat.S_IFIFO and dir_fd support for os.mknod()")
|
||||
def test_mknod_dir_fd(self):
|
||||
# Test using mknodat() to create a FIFO (the only use specified
|
||||
# by POSIX).
|
||||
os_helper.unlink(os_helper.TESTFN)
|
||||
mode = stat.S_IFIFO | stat.S_IRUSR | stat.S_IWUSR
|
||||
f = posix.open(posix.getcwd(), posix.O_RDONLY)
|
||||
try:
|
||||
posix.mknod(os_helper.TESTFN, mode, 0, dir_fd=f)
|
||||
except OSError as e:
|
||||
# Some old systems don't allow unprivileged users to use
|
||||
# mknod(), or only support creating device nodes.
|
||||
self.assertIn(e.errno, (errno.EPERM, errno.EINVAL, errno.EACCES))
|
||||
else:
|
||||
self.assertTrue(stat.S_ISFIFO(posix.stat(os_helper.TESTFN).st_mode))
|
||||
finally:
|
||||
posix.close(f)
|
||||
|
||||
@unittest.skipUnless(os.open in os.supports_dir_fd, "test needs dir_fd support in os.open()")
|
||||
def test_open_dir_fd(self):
|
||||
os_helper.unlink(os_helper.TESTFN)
|
||||
with open(os_helper.TESTFN, 'w') as outfile:
|
||||
outfile.write("testline\n")
|
||||
a = posix.open(posix.getcwd(), posix.O_RDONLY)
|
||||
b = posix.open(os_helper.TESTFN, posix.O_RDONLY, dir_fd=a)
|
||||
try:
|
||||
res = posix.read(b, 9).decode(encoding="utf-8")
|
||||
self.assertEqual("testline\n", res)
|
||||
finally:
|
||||
posix.close(a)
|
||||
posix.close(b)
|
||||
|
||||
@unittest.skipUnless(os.readlink in os.supports_dir_fd, "test needs dir_fd support in os.readlink()")
|
||||
def test_readlink_dir_fd(self):
|
||||
os.symlink(os_helper.TESTFN, os_helper.TESTFN + 'link')
|
||||
f = posix.open(posix.getcwd(), posix.O_RDONLY)
|
||||
try:
|
||||
self.assertEqual(posix.readlink(os_helper.TESTFN + 'link'),
|
||||
posix.readlink(os_helper.TESTFN + 'link', dir_fd=f))
|
||||
finally:
|
||||
os_helper.unlink(os_helper.TESTFN + 'link')
|
||||
posix.close(f)
|
||||
|
||||
@unittest.skipUnless(os.rename in os.supports_dir_fd, "test needs dir_fd support in os.rename()")
|
||||
def test_rename_dir_fd(self):
|
||||
os_helper.unlink(os_helper.TESTFN)
|
||||
os_helper.create_empty_file(os_helper.TESTFN + 'ren')
|
||||
f = posix.open(posix.getcwd(), posix.O_RDONLY)
|
||||
try:
|
||||
posix.rename(os_helper.TESTFN + 'ren', os_helper.TESTFN, src_dir_fd=f, dst_dir_fd=f)
|
||||
except:
|
||||
posix.rename(os_helper.TESTFN + 'ren', os_helper.TESTFN)
|
||||
raise
|
||||
else:
|
||||
posix.stat(os_helper.TESTFN) # should not raise exception
|
||||
finally:
|
||||
posix.close(f)
|
||||
|
||||
@unittest.skipUnless(hasattr(signal, 'SIGCHLD'), 'CLD_XXXX be placed in si_code for a SIGCHLD signal')
|
||||
@unittest.skipUnless(hasattr(os, 'waitid_result'), "test needs os.waitid_result")
|
||||
def test_cld_xxxx_constants(self):
|
||||
@@ -1240,48 +1096,6 @@ class PosixTester(unittest.TestCase):
|
||||
os.CLD_STOPPED
|
||||
os.CLD_CONTINUED
|
||||
|
||||
@unittest.skipUnless(os.symlink in os.supports_dir_fd, "test needs dir_fd support in os.symlink()")
|
||||
def test_symlink_dir_fd(self):
|
||||
f = posix.open(posix.getcwd(), posix.O_RDONLY)
|
||||
try:
|
||||
posix.symlink(os_helper.TESTFN, os_helper.TESTFN + 'link', dir_fd=f)
|
||||
self.assertEqual(posix.readlink(os_helper.TESTFN + 'link'), os_helper.TESTFN)
|
||||
finally:
|
||||
posix.close(f)
|
||||
os_helper.unlink(os_helper.TESTFN + 'link')
|
||||
|
||||
@unittest.skipUnless(os.unlink in os.supports_dir_fd, "test needs dir_fd support in os.unlink()")
|
||||
def test_unlink_dir_fd(self):
|
||||
f = posix.open(posix.getcwd(), posix.O_RDONLY)
|
||||
os_helper.create_empty_file(os_helper.TESTFN + 'del')
|
||||
posix.stat(os_helper.TESTFN + 'del') # should not raise exception
|
||||
try:
|
||||
posix.unlink(os_helper.TESTFN + 'del', dir_fd=f)
|
||||
except:
|
||||
os_helper.unlink(os_helper.TESTFN + 'del')
|
||||
raise
|
||||
else:
|
||||
self.assertRaises(OSError, posix.stat, os_helper.TESTFN + 'link')
|
||||
finally:
|
||||
posix.close(f)
|
||||
|
||||
# TODO: RUSTPYTHON: AttributeError: module 'os' has no attribute 'mkfifo'
|
||||
#
|
||||
# @unittest.skipUnless(os.mkfifo in os.supports_dir_fd, "test needs dir_fd support in os.mkfifo()")
|
||||
@unittest.expectedFailure
|
||||
def test_mkfifo_dir_fd(self):
|
||||
os_helper.unlink(os_helper.TESTFN)
|
||||
f = posix.open(posix.getcwd(), posix.O_RDONLY)
|
||||
try:
|
||||
try:
|
||||
posix.mkfifo(os_helper.TESTFN,
|
||||
stat.S_IRUSR | stat.S_IWUSR, dir_fd=f)
|
||||
except PermissionError as e:
|
||||
self.skipTest('posix.mkfifo(): %s' % e)
|
||||
self.assertTrue(stat.S_ISFIFO(posix.stat(os_helper.TESTFN).st_mode))
|
||||
finally:
|
||||
posix.close(f)
|
||||
|
||||
requires_sched_h = unittest.skipUnless(hasattr(posix, 'sched_yield'),
|
||||
"don't have scheduling support")
|
||||
requires_sched_affinity = unittest.skipUnless(hasattr(posix, 'sched_setaffinity'),
|
||||
@@ -1369,7 +1183,9 @@ class PosixTester(unittest.TestCase):
|
||||
mask = posix.sched_getaffinity(0)
|
||||
self.assertIsInstance(mask, set)
|
||||
self.assertGreaterEqual(len(mask), 1)
|
||||
self.assertRaises(OSError, posix.sched_getaffinity, -1)
|
||||
if not sys.platform.startswith("freebsd"):
|
||||
# bpo-47205: does not raise OSError on FreeBSD
|
||||
self.assertRaises(OSError, posix.sched_getaffinity, -1)
|
||||
for cpu in mask:
|
||||
self.assertIsInstance(cpu, int)
|
||||
self.assertGreaterEqual(cpu, 0)
|
||||
@@ -1387,7 +1203,9 @@ class PosixTester(unittest.TestCase):
|
||||
self.assertRaises(ValueError, posix.sched_setaffinity, 0, [-10])
|
||||
self.assertRaises(ValueError, posix.sched_setaffinity, 0, map(int, "0X"))
|
||||
self.assertRaises(OverflowError, posix.sched_setaffinity, 0, [1<<128])
|
||||
self.assertRaises(OSError, posix.sched_setaffinity, -1, mask)
|
||||
if not sys.platform.startswith("freebsd"):
|
||||
# bpo-47205: does not raise OSError on FreeBSD
|
||||
self.assertRaises(OSError, posix.sched_setaffinity, -1, mask)
|
||||
|
||||
def test_rtld_constants(self):
|
||||
# check presence of major RTLD_* constants
|
||||
@@ -1488,6 +1306,200 @@ class PosixTester(unittest.TestCase):
|
||||
self.assertEqual(cm.exception.errno, errno.EINVAL)
|
||||
os.close(os.pidfd_open(os.getpid(), 0))
|
||||
|
||||
|
||||
# tests for the posix *at functions follow
|
||||
class TestPosixDirFd(unittest.TestCase):
|
||||
count = 0
|
||||
|
||||
@contextmanager
|
||||
def prepare(self):
|
||||
TestPosixDirFd.count += 1
|
||||
name = f'{os_helper.TESTFN}_{self.count}'
|
||||
base_dir = f'{os_helper.TESTFN}_{self.count}base'
|
||||
posix.mkdir(base_dir)
|
||||
self.addCleanup(posix.rmdir, base_dir)
|
||||
fullname = os.path.join(base_dir, name)
|
||||
assert not os.path.exists(fullname)
|
||||
with os_helper.open_dir_fd(base_dir) as dir_fd:
|
||||
yield (dir_fd, name, fullname)
|
||||
|
||||
@contextmanager
|
||||
def prepare_file(self):
|
||||
with self.prepare() as (dir_fd, name, fullname):
|
||||
os_helper.create_empty_file(fullname)
|
||||
self.addCleanup(posix.unlink, fullname)
|
||||
yield (dir_fd, name, fullname)
|
||||
|
||||
@unittest.skipUnless(os.access in os.supports_dir_fd, "test needs dir_fd support for os.access()")
|
||||
def test_access_dir_fd(self):
|
||||
with self.prepare_file() as (dir_fd, name, fullname):
|
||||
self.assertTrue(posix.access(name, os.R_OK, dir_fd=dir_fd))
|
||||
|
||||
@unittest.skipUnless(os.chmod in os.supports_dir_fd, "test needs dir_fd support in os.chmod()")
|
||||
def test_chmod_dir_fd(self):
|
||||
with self.prepare_file() as (dir_fd, name, fullname):
|
||||
posix.chmod(fullname, stat.S_IRUSR)
|
||||
posix.chmod(name, stat.S_IRUSR | stat.S_IWUSR, dir_fd=dir_fd)
|
||||
s = posix.stat(fullname)
|
||||
self.assertEqual(s.st_mode & stat.S_IRWXU,
|
||||
stat.S_IRUSR | stat.S_IWUSR)
|
||||
|
||||
@unittest.skipUnless(hasattr(os, 'chown') and (os.chown in os.supports_dir_fd),
|
||||
"test needs dir_fd support in os.chown()")
|
||||
def test_chown_dir_fd(self):
|
||||
with self.prepare_file() as (dir_fd, name, fullname):
|
||||
posix.chown(name, os.getuid(), os.getgid(), dir_fd=dir_fd)
|
||||
|
||||
@unittest.skipUnless(os.stat in os.supports_dir_fd, "test needs dir_fd support in os.stat()")
|
||||
def test_stat_dir_fd(self):
|
||||
with self.prepare() as (dir_fd, name, fullname):
|
||||
with open(fullname, 'w') as outfile:
|
||||
outfile.write("testline\n")
|
||||
self.addCleanup(posix.unlink, fullname)
|
||||
|
||||
s1 = posix.stat(fullname)
|
||||
s2 = posix.stat(name, dir_fd=dir_fd)
|
||||
self.assertEqual(s1, s2)
|
||||
s2 = posix.stat(fullname, dir_fd=None)
|
||||
self.assertEqual(s1, s2)
|
||||
|
||||
self.assertRaisesRegex(TypeError, 'should be integer or None, not',
|
||||
posix.stat, name, dir_fd=posix.getcwd())
|
||||
self.assertRaisesRegex(TypeError, 'should be integer or None, not',
|
||||
posix.stat, name, dir_fd=float(dir_fd))
|
||||
self.assertRaises(OverflowError,
|
||||
posix.stat, name, dir_fd=10**20)
|
||||
|
||||
@unittest.skipUnless(os.utime in os.supports_dir_fd, "test needs dir_fd support in os.utime()")
|
||||
def test_utime_dir_fd(self):
|
||||
with self.prepare_file() as (dir_fd, name, fullname):
|
||||
now = time.time()
|
||||
posix.utime(name, None, dir_fd=dir_fd)
|
||||
posix.utime(name, dir_fd=dir_fd)
|
||||
self.assertRaises(TypeError, posix.utime, name,
|
||||
now, dir_fd=dir_fd)
|
||||
self.assertRaises(TypeError, posix.utime, name,
|
||||
(None, None), dir_fd=dir_fd)
|
||||
self.assertRaises(TypeError, posix.utime, name,
|
||||
(now, None), dir_fd=dir_fd)
|
||||
self.assertRaises(TypeError, posix.utime, name,
|
||||
(None, now), dir_fd=dir_fd)
|
||||
self.assertRaises(TypeError, posix.utime, name,
|
||||
(now, "x"), dir_fd=dir_fd)
|
||||
posix.utime(name, (int(now), int(now)), dir_fd=dir_fd)
|
||||
posix.utime(name, (now, now), dir_fd=dir_fd)
|
||||
posix.utime(name,
|
||||
(int(now), int((now - int(now)) * 1e9)), dir_fd=dir_fd)
|
||||
posix.utime(name, dir_fd=dir_fd,
|
||||
times=(int(now), int((now - int(now)) * 1e9)))
|
||||
|
||||
# try dir_fd and follow_symlinks together
|
||||
if os.utime in os.supports_follow_symlinks:
|
||||
try:
|
||||
posix.utime(name, follow_symlinks=False, dir_fd=dir_fd)
|
||||
except ValueError:
|
||||
# whoops! using both together not supported on this platform.
|
||||
pass
|
||||
|
||||
@unittest.skipUnless(os.link in os.supports_dir_fd, "test needs dir_fd support in os.link()")
|
||||
def test_link_dir_fd(self):
|
||||
with self.prepare_file() as (dir_fd, name, fullname), \
|
||||
self.prepare() as (dir_fd2, linkname, fulllinkname):
|
||||
try:
|
||||
posix.link(name, linkname, src_dir_fd=dir_fd, dst_dir_fd=dir_fd2)
|
||||
except PermissionError as e:
|
||||
self.skipTest('posix.link(): %s' % e)
|
||||
self.addCleanup(posix.unlink, fulllinkname)
|
||||
# should have same inodes
|
||||
self.assertEqual(posix.stat(fullname)[1],
|
||||
posix.stat(fulllinkname)[1])
|
||||
|
||||
@unittest.skipUnless(os.mkdir in os.supports_dir_fd, "test needs dir_fd support in os.mkdir()")
|
||||
def test_mkdir_dir_fd(self):
|
||||
with self.prepare() as (dir_fd, name, fullname):
|
||||
posix.mkdir(name, dir_fd=dir_fd)
|
||||
self.addCleanup(posix.rmdir, fullname)
|
||||
posix.stat(fullname) # should not raise exception
|
||||
|
||||
@unittest.skipUnless(hasattr(os, 'mknod')
|
||||
and (os.mknod in os.supports_dir_fd)
|
||||
and hasattr(stat, 'S_IFIFO'),
|
||||
"test requires both stat.S_IFIFO and dir_fd support for os.mknod()")
|
||||
def test_mknod_dir_fd(self):
|
||||
# Test using mknodat() to create a FIFO (the only use specified
|
||||
# by POSIX).
|
||||
with self.prepare() as (dir_fd, name, fullname):
|
||||
mode = stat.S_IFIFO | stat.S_IRUSR | stat.S_IWUSR
|
||||
try:
|
||||
posix.mknod(name, mode, 0, dir_fd=dir_fd)
|
||||
except OSError as e:
|
||||
# Some old systems don't allow unprivileged users to use
|
||||
# mknod(), or only support creating device nodes.
|
||||
self.assertIn(e.errno, (errno.EPERM, errno.EINVAL, errno.EACCES))
|
||||
else:
|
||||
self.addCleanup(posix.unlink, fullname)
|
||||
self.assertTrue(stat.S_ISFIFO(posix.stat(fullname).st_mode))
|
||||
|
||||
@unittest.skipUnless(os.open in os.supports_dir_fd, "test needs dir_fd support in os.open()")
|
||||
def test_open_dir_fd(self):
|
||||
with self.prepare() as (dir_fd, name, fullname):
|
||||
with open(fullname, 'wb') as outfile:
|
||||
outfile.write(b"testline\n")
|
||||
self.addCleanup(posix.unlink, fullname)
|
||||
fd = posix.open(name, posix.O_RDONLY, dir_fd=dir_fd)
|
||||
try:
|
||||
res = posix.read(fd, 9)
|
||||
self.assertEqual(b"testline\n", res)
|
||||
finally:
|
||||
posix.close(fd)
|
||||
|
||||
@unittest.skipUnless(hasattr(os, 'readlink') and (os.readlink in os.supports_dir_fd),
|
||||
"test needs dir_fd support in os.readlink()")
|
||||
def test_readlink_dir_fd(self):
|
||||
with self.prepare() as (dir_fd, name, fullname):
|
||||
os.symlink('symlink', fullname)
|
||||
self.addCleanup(posix.unlink, fullname)
|
||||
self.assertEqual(posix.readlink(name, dir_fd=dir_fd), 'symlink')
|
||||
|
||||
@unittest.skipUnless(os.rename in os.supports_dir_fd, "test needs dir_fd support in os.rename()")
|
||||
def test_rename_dir_fd(self):
|
||||
with self.prepare_file() as (dir_fd, name, fullname), \
|
||||
self.prepare() as (dir_fd2, name2, fullname2):
|
||||
posix.rename(name, name2,
|
||||
src_dir_fd=dir_fd, dst_dir_fd=dir_fd2)
|
||||
posix.stat(fullname2) # should not raise exception
|
||||
posix.rename(fullname2, fullname)
|
||||
|
||||
@unittest.skipUnless(os.symlink in os.supports_dir_fd, "test needs dir_fd support in os.symlink()")
|
||||
def test_symlink_dir_fd(self):
|
||||
with self.prepare() as (dir_fd, name, fullname):
|
||||
posix.symlink('symlink', name, dir_fd=dir_fd)
|
||||
self.addCleanup(posix.unlink, fullname)
|
||||
self.assertEqual(posix.readlink(fullname), 'symlink')
|
||||
|
||||
@unittest.skipUnless(os.unlink in os.supports_dir_fd, "test needs dir_fd support in os.unlink()")
|
||||
def test_unlink_dir_fd(self):
|
||||
with self.prepare() as (dir_fd, name, fullname):
|
||||
os_helper.create_empty_file(fullname)
|
||||
posix.stat(fullname) # should not raise exception
|
||||
try:
|
||||
posix.unlink(name, dir_fd=dir_fd)
|
||||
self.assertRaises(OSError, posix.stat, fullname)
|
||||
except:
|
||||
self.addCleanup(posix.unlink, fullname)
|
||||
raise
|
||||
|
||||
@unittest.skipUnless(os.mkfifo in os.supports_dir_fd, "test needs dir_fd support in os.mkfifo()")
|
||||
def test_mkfifo_dir_fd(self):
|
||||
with self.prepare() as (dir_fd, name, fullname):
|
||||
try:
|
||||
posix.mkfifo(name, stat.S_IRUSR | stat.S_IWUSR, dir_fd=dir_fd)
|
||||
except PermissionError as e:
|
||||
self.skipTest('posix.mkfifo(): %s' % e)
|
||||
self.addCleanup(posix.unlink, fullname)
|
||||
self.assertTrue(stat.S_ISFIFO(posix.stat(fullname).st_mode))
|
||||
|
||||
|
||||
class PosixGroupsTester(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
@@ -1548,7 +1560,7 @@ class _PosixSpawnMixin:
|
||||
args = self.python_args('-c', script)
|
||||
pid = self.spawn_func(args[0], args, os.environ)
|
||||
support.wait_process(pid, exitcode=0)
|
||||
with open(pidfile) as f:
|
||||
with open(pidfile, encoding="utf-8") as f:
|
||||
self.assertEqual(f.read(), str(pid))
|
||||
|
||||
def test_no_such_executable(self):
|
||||
@@ -1573,14 +1585,14 @@ class _PosixSpawnMixin:
|
||||
self.addCleanup(os_helper.unlink, envfile)
|
||||
script = f"""if 1:
|
||||
import os
|
||||
with open({envfile!r}, "w") as envfile:
|
||||
with open({envfile!r}, "w", encoding="utf-8") as envfile:
|
||||
envfile.write(os.environ['foo'])
|
||||
"""
|
||||
args = self.python_args('-c', script)
|
||||
pid = self.spawn_func(args[0], args,
|
||||
{**os.environ, 'foo': 'bar'})
|
||||
support.wait_process(pid, exitcode=0)
|
||||
with open(envfile) as f:
|
||||
with open(envfile, encoding="utf-8") as f:
|
||||
self.assertEqual(f.read(), 'bar')
|
||||
|
||||
def test_none_file_actions(self):
|
||||
@@ -1846,7 +1858,7 @@ class _PosixSpawnMixin:
|
||||
file_actions=file_actions)
|
||||
|
||||
support.wait_process(pid, exitcode=0)
|
||||
with open(outfile) as f:
|
||||
with open(outfile, encoding="utf-8") as f:
|
||||
self.assertEqual(f.read(), 'hello')
|
||||
|
||||
# TODO: RUSTPYTHON: FileNotFoundError: [Errno 2] No such file or directory (os error 2): '@test_55144_tmp' -> 'None'
|
||||
@@ -1859,7 +1871,7 @@ class _PosixSpawnMixin:
|
||||
try:
|
||||
os.fstat(0)
|
||||
except OSError as e:
|
||||
with open({closefile!r}, 'w') as closefile:
|
||||
with open({closefile!r}, 'w', encoding='utf-8') as closefile:
|
||||
closefile.write('is closed %d' % e.errno)
|
||||
"""
|
||||
args = self.python_args('-c', script)
|
||||
@@ -1867,7 +1879,7 @@ class _PosixSpawnMixin:
|
||||
file_actions=[(os.POSIX_SPAWN_CLOSE, 0)])
|
||||
|
||||
support.wait_process(pid, exitcode=0)
|
||||
with open(closefile) as f:
|
||||
with open(closefile, encoding="utf-8") as f:
|
||||
self.assertEqual(f.read(), 'is closed %d' % errno.EBADF)
|
||||
|
||||
def test_dup2(self):
|
||||
@@ -1885,7 +1897,7 @@ class _PosixSpawnMixin:
|
||||
pid = self.spawn_func(args[0], args, os.environ,
|
||||
file_actions=file_actions)
|
||||
support.wait_process(pid, exitcode=0)
|
||||
with open(dupfile) as f:
|
||||
with open(dupfile, encoding="utf-8") as f:
|
||||
self.assertEqual(f.read(), 'hello')
|
||||
|
||||
|
||||
@@ -1931,7 +1943,6 @@ class TestPosixSpawnP(unittest.TestCase, _PosixSpawnMixin):
|
||||
assert_python_ok(*args, PATH=path)
|
||||
|
||||
|
||||
@unittest.skip("TODO: RUSTPYTHON, NameError: name 'ParserCreate' is not defined")
|
||||
@unittest.skipUnless(sys.platform == "darwin", "test weak linking on macOS")
|
||||
class TestPosixWeaklinking(unittest.TestCase):
|
||||
# These test cases verify that weak linking support on macOS works
|
||||
@@ -2159,17 +2170,9 @@ class TestPosixWeaklinking(unittest.TestCase):
|
||||
os.utime("path", dir_fd=0)
|
||||
|
||||
|
||||
def test_main():
|
||||
try:
|
||||
support.run_unittest(
|
||||
PosixTester,
|
||||
PosixGroupsTester,
|
||||
TestPosixSpawn,
|
||||
TestPosixSpawnP,
|
||||
TestPosixWeaklinking
|
||||
)
|
||||
finally:
|
||||
support.reap_children()
|
||||
def tearDownModule():
|
||||
support.reap_children()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
test_main()
|
||||
unittest.main()
|
||||
|
||||
67
Lib/test/test_posixpath.py
vendored
67
Lib/test/test_posixpath.py
vendored
@@ -1,9 +1,11 @@
|
||||
import os
|
||||
import posixpath
|
||||
import sys
|
||||
import unittest
|
||||
from posixpath import realpath, abspath, dirname, basename
|
||||
from test import support, test_genericpath
|
||||
from test.support import os_helper, import_helper
|
||||
from test import test_genericpath
|
||||
from test.support import import_helper
|
||||
from test.support import os_helper
|
||||
from test.support.os_helper import FakePath
|
||||
from unittest import mock
|
||||
|
||||
@@ -269,6 +271,8 @@ class PosixPathTest(unittest.TestCase):
|
||||
self.assertEqual(posixpath.expanduser("~/"), "/")
|
||||
self.assertEqual(posixpath.expanduser("~/foo"), "/foo")
|
||||
|
||||
@unittest.skipIf(sys.platform == "vxworks",
|
||||
"no home directory on VxWorks")
|
||||
def test_expanduser_pwd(self):
|
||||
pwd = import_helper.import_module('pwd')
|
||||
|
||||
@@ -359,6 +363,19 @@ class PosixPathTest(unittest.TestCase):
|
||||
finally:
|
||||
os_helper.unlink(ABSTFN)
|
||||
|
||||
@unittest.skipUnless(hasattr(os, "symlink"),
|
||||
"Missing symlink implementation")
|
||||
@skip_if_ABSTFN_contains_backslash
|
||||
def test_realpath_strict(self):
|
||||
# Bug #43757: raise FileNotFoundError in strict mode if we encounter
|
||||
# a path that does not exist.
|
||||
try:
|
||||
os.symlink(ABSTFN+"1", ABSTFN)
|
||||
self.assertRaises(FileNotFoundError, realpath, ABSTFN, strict=True)
|
||||
self.assertRaises(FileNotFoundError, realpath, ABSTFN + "2", strict=True)
|
||||
finally:
|
||||
os_helper.unlink(ABSTFN)
|
||||
|
||||
@unittest.skipUnless(hasattr(os, "symlink"),
|
||||
"Missing symlink implementation")
|
||||
@skip_if_ABSTFN_contains_backslash
|
||||
@@ -374,7 +391,7 @@ class PosixPathTest(unittest.TestCase):
|
||||
@skip_if_ABSTFN_contains_backslash
|
||||
def test_realpath_symlink_loops(self):
|
||||
# Bug #930024, return the path unchanged if we get into an infinite
|
||||
# symlink loop.
|
||||
# symlink loop in non-strict mode (default).
|
||||
try:
|
||||
os.symlink(ABSTFN, ABSTFN)
|
||||
self.assertEqual(realpath(ABSTFN), ABSTFN)
|
||||
@@ -411,6 +428,48 @@ class PosixPathTest(unittest.TestCase):
|
||||
os_helper.unlink(ABSTFN+"c")
|
||||
os_helper.unlink(ABSTFN+"a")
|
||||
|
||||
@unittest.skipUnless(hasattr(os, "symlink"),
|
||||
"Missing symlink implementation")
|
||||
@skip_if_ABSTFN_contains_backslash
|
||||
def test_realpath_symlink_loops_strict(self):
|
||||
# Bug #43757, raise OSError if we get into an infinite symlink loop in
|
||||
# strict mode.
|
||||
try:
|
||||
os.symlink(ABSTFN, ABSTFN)
|
||||
self.assertRaises(OSError, realpath, ABSTFN, strict=True)
|
||||
|
||||
os.symlink(ABSTFN+"1", ABSTFN+"2")
|
||||
os.symlink(ABSTFN+"2", ABSTFN+"1")
|
||||
self.assertRaises(OSError, realpath, ABSTFN+"1", strict=True)
|
||||
self.assertRaises(OSError, realpath, ABSTFN+"2", strict=True)
|
||||
|
||||
self.assertRaises(OSError, realpath, ABSTFN+"1/x", strict=True)
|
||||
self.assertRaises(OSError, realpath, ABSTFN+"1/..", strict=True)
|
||||
self.assertRaises(OSError, realpath, ABSTFN+"1/../x", strict=True)
|
||||
os.symlink(ABSTFN+"x", ABSTFN+"y")
|
||||
self.assertRaises(OSError, realpath,
|
||||
ABSTFN+"1/../" + basename(ABSTFN) + "y", strict=True)
|
||||
self.assertRaises(OSError, realpath,
|
||||
ABSTFN+"1/../" + basename(ABSTFN) + "1", strict=True)
|
||||
|
||||
os.symlink(basename(ABSTFN) + "a/b", ABSTFN+"a")
|
||||
self.assertRaises(OSError, realpath, ABSTFN+"a", strict=True)
|
||||
|
||||
os.symlink("../" + basename(dirname(ABSTFN)) + "/" +
|
||||
basename(ABSTFN) + "c", ABSTFN+"c")
|
||||
self.assertRaises(OSError, realpath, ABSTFN+"c", strict=True)
|
||||
|
||||
# Test using relative path as well.
|
||||
with os_helper.change_cwd(dirname(ABSTFN)):
|
||||
self.assertRaises(OSError, realpath, basename(ABSTFN), strict=True)
|
||||
finally:
|
||||
os_helper.unlink(ABSTFN)
|
||||
os_helper.unlink(ABSTFN+"1")
|
||||
os_helper.unlink(ABSTFN+"2")
|
||||
os_helper.unlink(ABSTFN+"y")
|
||||
os_helper.unlink(ABSTFN+"c")
|
||||
os_helper.unlink(ABSTFN+"a")
|
||||
|
||||
@unittest.skipUnless(hasattr(os, "symlink"),
|
||||
"Missing symlink implementation")
|
||||
@skip_if_ABSTFN_contains_backslash
|
||||
@@ -680,7 +739,7 @@ class PathLikeTests(unittest.TestCase):
|
||||
path = posixpath
|
||||
|
||||
def setUp(self):
|
||||
self.file_name = os_helper.TESTFN.lower()
|
||||
self.file_name = os_helper.TESTFN
|
||||
self.file_path = FakePath(os_helper.TESTFN)
|
||||
self.addCleanup(os_helper.unlink, self.file_name)
|
||||
with open(self.file_name, 'xb', 0) as file:
|
||||
|
||||
Reference in New Issue
Block a user