Update some libs to 3.14.6 (#8102)

This commit is contained in:
Shahar Naveh authored and GitHub committed 2026-06-15 11:20:13 +09:00
1 parent eccbc5e658
commit 1dc57e816a
17 files changed
+603 -353

No files matched your search

+73 -48
View File
@@ -1,14 +1,17 @@
"""Test program for the fcntl C module.
"""
import errno
import multiprocessing
import platform
import os
import struct
import sys
import unittest
from multiprocessing import Process
from test.support import verbose, cpython_only
from test.support import (
cpython_only, get_pagesize, is_apple, requires_subprocess, verbose, is_emscripten
)
from test.support.import_helper import import_module
from test.support.os_helper import TESTFN, unlink
from test.support.os_helper import TESTFN, unlink, make_bad_fd
# Skip test if no fcntl module.
@@ -16,37 +19,6 @@ fcntl = import_module('fcntl')
def get_lockdata():
try:
os.O_LARGEFILE
except AttributeError:
start_len = "ll"
else:
start_len = "qq"
if (sys.platform.startswith(('netbsd', 'freebsd', 'openbsd'))
or sys.platform == 'darwin'):
if struct.calcsize('l') == 8:
off_t = 'l'
pid_t = 'i'
else:
off_t = 'lxxxx'
pid_t = 'l'
lockdata = struct.pack(off_t + off_t + pid_t + 'hh', 0, 0, 0,
fcntl.F_WRLCK, 0)
elif sys.platform.startswith('gnukfreebsd'):
lockdata = struct.pack('qqihhi', 0, 0, 0, fcntl.F_WRLCK, 0, 0)
elif sys.platform in ['hp-uxB', 'unixware7']:
lockdata = struct.pack('hhlllii', fcntl.F_WRLCK, 0, 0, 0, 0, 0, 0)
else:
lockdata = struct.pack('hh'+start_len+'hh', fcntl.F_WRLCK, 0, 0, 0, 0, 0)
if lockdata:
if verbose:
print('struct.pack: ', repr(lockdata))
return lockdata
lockdata = get_lockdata()
class BadFile:
def __init__(self, fn):
self.fn = fn
@@ -78,12 +50,45 @@ class TestFcntl(unittest.TestCase):
self.f.close()
unlink(TESTFN)
@staticmethod
def get_lockdata():
try:
os.O_LARGEFILE
except AttributeError:
start_len = "ll"
else:
start_len = "qq"
if (
sys.platform.startswith(('netbsd', 'freebsd', 'openbsd'))
or is_apple
):
if struct.calcsize('l') == 8:
off_t = 'l'
pid_t = 'i'
else:
off_t = 'lxxxx'
pid_t = 'l'
lockdata = struct.pack(off_t + off_t + pid_t + 'hh', 0, 0, 0,
fcntl.F_WRLCK, 0)
elif sys.platform.startswith('gnukfreebsd'):
lockdata = struct.pack('qqihhi', 0, 0, 0, fcntl.F_WRLCK, 0, 0)
elif sys.platform in ['hp-uxB', 'unixware7']:
lockdata = struct.pack('hhlllii', fcntl.F_WRLCK, 0, 0, 0, 0, 0, 0)
else:
lockdata = struct.pack('hh'+start_len+'hh', fcntl.F_WRLCK, 0, 0, 0, 0, 0)
if lockdata:
if verbose:
print('struct.pack: ', repr(lockdata))
return lockdata
def test_fcntl_fileno(self):
# the example from the library docs
self.f = open(TESTFN, 'wb')
rv = fcntl.fcntl(self.f.fileno(), fcntl.F_SETFL, os.O_NONBLOCK)
if verbose:
print('Status from fcntl with O_NONBLOCK: ', rv)
lockdata = self.get_lockdata()
rv = fcntl.fcntl(self.f.fileno(), fcntl.F_SETLKW, lockdata)
if verbose:
print('String from fcntl with F_SETLKW: ', repr(rv))
@@ -95,6 +100,7 @@ class TestFcntl(unittest.TestCase):
rv = fcntl.fcntl(self.f, fcntl.F_SETFL, os.O_NONBLOCK)
if verbose:
print('Status from fcntl with O_NONBLOCK: ', rv)
lockdata = self.get_lockdata()
rv = fcntl.fcntl(self.f, fcntl.F_SETLKW, lockdata)
if verbose:
print('String from fcntl with F_SETLKW: ', repr(rv))
@@ -112,7 +118,9 @@ class TestFcntl(unittest.TestCase):
@cpython_only
def test_fcntl_bad_file_overflow(self):
from _testcapi import INT_MAX, INT_MIN
_testcapi = import_module("_testcapi")
INT_MAX = _testcapi.INT_MAX
INT_MIN = _testcapi.INT_MIN
# Issue 15989
with self.assertRaises(OverflowError):
fcntl.fcntl(INT_MAX + 1, fcntl.F_SETFL, os.O_NONBLOCK)
@@ -124,19 +132,25 @@ class TestFcntl(unittest.TestCase):
fcntl.fcntl(BadFile(INT_MIN - 1), fcntl.F_SETFL, os.O_NONBLOCK)
@unittest.skipIf(
platform.machine().startswith('arm') and platform.system() == 'Linux',
"ARM Linux returns EINVAL for F_NOTIFY DN_MULTISHOT")
(platform.machine().startswith("arm") and platform.system() == "Linux")
or platform.system() == "Android",
"this platform returns EINVAL for F_NOTIFY DN_MULTISHOT")
def test_fcntl_64_bit(self):
# Issue #1309352: fcntl shouldn't fail when the third arg fits in a
# Issue GH-42434: fcntl shouldn't fail when the third arg fits in a
# C 'long' but not in a C 'int'.
try:
cmd = fcntl.F_NOTIFY
# This flag is larger than 2**31 in 64-bit builds
# DN_MULTISHOT is >= 2**31 in 64-bit builds
flags = fcntl.DN_MULTISHOT
except AttributeError:
self.skipTest("F_NOTIFY or DN_MULTISHOT unavailable")
fd = os.open(os.path.dirname(os.path.abspath(TESTFN)), os.O_RDONLY)
try:
try:
fcntl.fcntl(fd, cmd, fcntl.DN_DELETE)
except OSError as exc:
if exc.errno == errno.EINVAL:
self.skipTest("F_NOTIFY not available by this environment")
fcntl.fcntl(fd, cmd, flags)
finally:
os.close(fd)
@@ -155,27 +169,27 @@ class TestFcntl(unittest.TestCase):
self.assertRaises(ValueError, fcntl.flock, -1, fcntl.LOCK_SH)
self.assertRaises(TypeError, fcntl.flock, 'spam', fcntl.LOCK_SH)
# TODO RustPython
@unittest.skipUnless(sys.platform == 'linux', 'test requires Linux')
@unittest.skipIf(platform.system() == "AIX", "AIX returns PermissionError")
@requires_subprocess()
def test_lockf_exclusive(self):
self.f = open(TESTFN, 'wb+')
cmd = fcntl.LOCK_EX | fcntl.LOCK_NB
fcntl.lockf(self.f, cmd)
p = Process(target=try_lockf_on_other_process_fail, args=(TESTFN, cmd))
mp = multiprocessing.get_context('spawn')
p = mp.Process(target=try_lockf_on_other_process_fail, args=(TESTFN, cmd))
p.start()
p.join()
fcntl.lockf(self.f, fcntl.LOCK_UN)
self.assertEqual(p.exitcode, 0)
# TODO RustPython
@unittest.skipUnless(sys.platform == 'linux', 'test requires Linux')
@unittest.skipIf(platform.system() == "AIX", "AIX returns PermissionError")
@requires_subprocess()
def test_lockf_share(self):
self.f = open(TESTFN, 'wb+')
cmd = fcntl.LOCK_SH | fcntl.LOCK_NB
fcntl.lockf(self.f, cmd)
p = Process(target=try_lockf_on_other_process, args=(TESTFN, cmd))
mp = multiprocessing.get_context('spawn')
p = mp.Process(target=try_lockf_on_other_process, args=(TESTFN, cmd))
p.start()
p.join()
fcntl.lockf(self.f, fcntl.LOCK_UN)
@@ -183,7 +197,7 @@ class TestFcntl(unittest.TestCase):
@cpython_only
def test_flock_overflow(self):
import _testcapi
_testcapi = import_module("_testcapi")
self.assertRaises(OverflowError, fcntl.flock, _testcapi.INT_MAX+1,
fcntl.LOCK_SH)
@@ -197,14 +211,16 @@ class TestFcntl(unittest.TestCase):
@unittest.skipUnless(
hasattr(fcntl, "F_SETPIPE_SZ") and hasattr(fcntl, "F_GETPIPE_SZ"),
"F_SETPIPE_SZ and F_GETPIPE_SZ are not available on all platforms.")
@unittest.skipIf(is_emscripten, "Emscripten pipefs doesn't support these")
def test_fcntl_f_pipesize(self):
test_pipe_r, test_pipe_w = os.pipe()
try:
# Get the default pipesize with F_GETPIPE_SZ
pipesize_default = fcntl.fcntl(test_pipe_w, fcntl.F_GETPIPE_SZ)
pipesize = pipesize_default // 2 # A new value to detect change.
if pipesize < 512: # the POSIX minimum
raise unittest.SkitTest(
pagesize_default = get_pagesize()
if pipesize < pagesize_default: # the POSIX minimum
raise unittest.SkipTest(
'default pipesize too small to perform test.')
fcntl.fcntl(test_pipe_w, fcntl.F_SETPIPE_SZ, pipesize)
self.assertEqual(fcntl.fcntl(test_pipe_w, fcntl.F_GETPIPE_SZ),
@@ -213,6 +229,15 @@ class TestFcntl(unittest.TestCase):
os.close(test_pipe_r)
os.close(test_pipe_w)
@unittest.skipUnless(hasattr(fcntl, 'F_DUPFD'), 'need fcntl.F_DUPFD')
def test_bad_fd(self):
# gh-134744: Test error handling
fd = make_bad_fd()
with self.assertRaises(OSError):
fcntl.fcntl(fd, fcntl.F_DUPFD, 0)
with self.assertRaises(OSError):
fcntl.fcntl(fd, fcntl.F_DUPFD, b'\0' * 1024)
if __name__ == '__main__':
unittest.main()
+172 -48
View File
@@ -1,45 +1,79 @@
import array
import os
import struct
import sys
import threading
import unittest
from test.support import get_attribute
from test import support
from test.support import os_helper, threading_helper
from test.support.import_helper import import_module
import os, struct
fcntl = import_module('fcntl')
termios = import_module('termios')
get_attribute(termios, 'TIOCGPGRP') #Can't run tests without this feature
try:
tty = open("/dev/tty", "rb")
except OSError:
raise unittest.SkipTest("Unable to open /dev/tty")
else:
with tty:
# Skip if another process is in foreground
r = fcntl.ioctl(tty, termios.TIOCGPGRP, " ")
rpgrp = struct.unpack("i", r)[0]
if rpgrp not in (os.getpgrp(), os.getsid(0)):
raise unittest.SkipTest("Neither the process group nor the session "
"are attached to /dev/tty")
del tty, r, rpgrp
class IoctlTestsTty(unittest.TestCase):
@classmethod
def setUpClass(cls):
TIOCGPGRP = support.get_attribute(termios, 'TIOCGPGRP')
try:
tty = open("/dev/tty", "rb")
except OSError:
raise unittest.SkipTest("Unable to open /dev/tty")
with tty:
# Skip if another process is in foreground
r = fcntl.ioctl(tty, TIOCGPGRP, struct.pack("i", 0))
rpgrp = struct.unpack("i", r)[0]
if rpgrp not in (os.getpgrp(), os.getsid(0)):
raise unittest.SkipTest("Neither the process group nor the session "
"are attached to /dev/tty")
try:
import pty
except ImportError:
pty = None
class IoctlTests(unittest.TestCase):
def test_ioctl(self):
def test_ioctl_immutable_buf(self):
# If this process has been put into the background, TIOCGPGRP returns
# the session ID instead of the process group id.
ids = (os.getpgrp(), os.getsid(0))
with open("/dev/tty", "rb") as tty:
r = fcntl.ioctl(tty, termios.TIOCGPGRP, " ")
rpgrp = struct.unpack("i", r)[0]
# string
buf = " "*8
r = fcntl.ioctl(tty, termios.TIOCGPGRP, buf)
self.assertIsInstance(r, bytes)
rpgrp = memoryview(r).cast('i')[0]
self.assertIn(rpgrp, ids)
def _check_ioctl_mutate_len(self, nbytes=None):
# bytes
buf = b" "*8
r = fcntl.ioctl(tty, termios.TIOCGPGRP, buf)
self.assertIsInstance(r, bytes)
rpgrp = memoryview(r).cast('i')[0]
self.assertIn(rpgrp, ids)
# read-only buffer
r = fcntl.ioctl(tty, termios.TIOCGPGRP, memoryview(buf))
self.assertIsInstance(r, bytes)
rpgrp = memoryview(r).cast('i')[0]
self.assertIn(rpgrp, ids)
def test_ioctl_mutable_buf(self):
ids = (os.getpgrp(), os.getsid(0))
with open("/dev/tty", "rb") as tty:
buf = bytearray(b" "*8)
r = fcntl.ioctl(tty, termios.TIOCGPGRP, buf)
self.assertEqual(r, 0)
rpgrp = memoryview(buf).cast('i')[0]
self.assertIn(rpgrp, ids)
def test_ioctl_no_mutate_buf(self):
ids = (os.getpgrp(), os.getsid(0))
with open("/dev/tty", "rb") as tty:
buf = bytearray(b" "*8)
save_buf = bytes(buf)
r = fcntl.ioctl(tty, termios.TIOCGPGRP, buf, False)
self.assertEqual(bytes(buf), save_buf)
self.assertIsInstance(r, bytes)
rpgrp = memoryview(r).cast('i')[0]
self.assertIn(rpgrp, ids)
def _create_int_buf(self, nbytes=None):
buf = array.array('i')
intsize = buf.itemsize
ids = (os.getpgrp(), os.getsid(0))
# A fill value unlikely to be in `ids`
fill = -12345
if nbytes is not None:
@@ -48,45 +82,135 @@ class IoctlTests(unittest.TestCase):
self.assertEqual(len(buf) * intsize, nbytes) # sanity check
else:
buf.append(fill)
return buf
def _check_ioctl_mutate_len(self, nbytes=None):
ids = (os.getpgrp(), os.getsid(0))
buf = self._create_int_buf(nbytes)
with open("/dev/tty", "rb") as tty:
r = fcntl.ioctl(tty, termios.TIOCGPGRP, buf, True)
r = fcntl.ioctl(tty, termios.TIOCGPGRP, buf)
rpgrp = buf[0]
self.assertEqual(r, 0)
self.assertIn(rpgrp, ids)
def _check_ioctl_not_mutate_len(self, nbytes=None):
ids = (os.getpgrp(), os.getsid(0))
buf = self._create_int_buf(nbytes)
save_buf = bytes(buf)
with open("/dev/tty", "rb") as tty:
r = fcntl.ioctl(tty, termios.TIOCGPGRP, buf, False)
self.assertIsInstance(r, bytes)
self.assertEqual(len(r), len(save_buf))
self.assertEqual(bytes(buf), save_buf)
rpgrp = array.array('i', r)[0]
rpgrp = memoryview(r).cast('i')[0]
self.assertIn(rpgrp, ids)
buf = bytes(buf)
with open("/dev/tty", "rb") as tty:
r = fcntl.ioctl(tty, termios.TIOCGPGRP, buf, True)
self.assertIsInstance(r, bytes)
self.assertEqual(len(r), len(save_buf))
self.assertEqual(buf, save_buf)
rpgrp = array.array('i', r)[0]
rpgrp = memoryview(r).cast('i')[0]
self.assertIn(rpgrp, ids)
def test_ioctl_mutate(self):
self._check_ioctl_mutate_len()
self._check_ioctl_not_mutate_len()
def test_ioctl_mutate_1024(self):
# Issue #9758: a mutable buffer of exactly 1024 bytes wouldn't be
# copied back after the system call.
self._check_ioctl_mutate_len(1024)
self._check_ioctl_not_mutate_len(1024)
def test_ioctl_mutate_2048(self):
# Test with a larger buffer, just for the record.
self._check_ioctl_mutate_len(2048)
self.assertRaises(ValueError, self._check_ioctl_not_mutate_len, 2048)
def test_ioctl_signed_unsigned_code_param(self):
if not pty:
raise unittest.SkipTest('pty module required')
mfd, sfd = pty.openpty()
try:
if termios.TIOCSWINSZ < 0:
set_winsz_opcode_maybe_neg = termios.TIOCSWINSZ
set_winsz_opcode_pos = termios.TIOCSWINSZ & 0xffffffff
else:
set_winsz_opcode_pos = termios.TIOCSWINSZ
set_winsz_opcode_maybe_neg, = struct.unpack("i",
struct.pack("I", termios.TIOCSWINSZ))
our_winsz = struct.pack("HHHH",80,25,0,0)
# test both with a positive and potentially negative ioctl code
new_winsz = fcntl.ioctl(mfd, set_winsz_opcode_pos, our_winsz)
new_winsz = fcntl.ioctl(mfd, set_winsz_opcode_maybe_neg, our_winsz)
finally:
os.close(mfd)
os.close(sfd)
@unittest.skipUnless(hasattr(os, 'openpty'), "need os.openpty()")
class IoctlTestsPty(unittest.TestCase):
def setUp(self):
self.master_fd, self.slave_fd = os.openpty()
self.addCleanup(os.close, self.slave_fd)
self.addCleanup(os.close, self.master_fd)
@unittest.skipUnless(hasattr(termios, 'TCFLSH'), 'requires termios.TCFLSH')
def test_ioctl_clear_input_or_output(self):
wfd = self.slave_fd
rfd = self.master_fd
# The data is buffered in the input buffer on Linux, and in
# the output buffer on other platforms.
inbuf = sys.platform in ('linux', 'android')
os.write(wfd, b'abcdef')
self.assertEqual(os.read(rfd, 2), b'ab')
if inbuf:
# don't flush input
fcntl.ioctl(rfd, termios.TCFLSH, termios.TCOFLUSH)
else:
# don't flush output
fcntl.ioctl(wfd, termios.TCFLSH, termios.TCIFLUSH)
self.assertEqual(os.read(rfd, 2), b'cd')
if inbuf:
# flush input
fcntl.ioctl(rfd, termios.TCFLSH, termios.TCIFLUSH)
else:
# flush output
fcntl.ioctl(wfd, termios.TCFLSH, termios.TCOFLUSH)
os.write(wfd, b'ABCDEF')
self.assertEqual(os.read(rfd, 1024), b'ABCDEF')
@support.skip_android_selinux('tcflow')
@unittest.skipUnless(sys.platform in ('linux', 'android'), 'only works on Linux')
@unittest.skipUnless(hasattr(termios, 'TCXONC'), 'requires termios.TCXONC')
def test_ioctl_suspend_and_resume_output(self):
wfd = self.slave_fd
rfd = self.master_fd
write_suspended = threading.Event()
write_finished = threading.Event()
def writer():
os.write(wfd, b'abc')
self.assertTrue(write_suspended.wait(support.SHORT_TIMEOUT))
os.write(wfd, b'def')
write_finished.set()
with threading_helper.start_threads([threading.Thread(target=writer)]):
self.assertEqual(os.read(rfd, 3), b'abc')
try:
try:
fcntl.ioctl(wfd, termios.TCXONC, termios.TCOOFF)
finally:
write_suspended.set()
self.assertFalse(write_finished.wait(0.5),
'output was not suspended')
finally:
fcntl.ioctl(wfd, termios.TCXONC, termios.TCOON)
self.assertTrue(write_finished.wait(support.SHORT_TIMEOUT),
'output was not resumed')
self.assertEqual(os.read(rfd, 1024), b'def')
def test_ioctl_set_window_size(self):
# (rows, columns, xpixel, ypixel)
our_winsz = struct.pack("HHHH", 20, 40, 0, 0)
result = fcntl.ioctl(self.master_fd, termios.TIOCSWINSZ, our_winsz)
new_winsz = struct.unpack("HHHH", result)
self.assertEqual(new_winsz[:2], (20, 40))
@unittest.skipUnless(hasattr(fcntl, 'FICLONE'), 'need fcntl.FICLONE')
def test_bad_fd(self):
# gh-134744: Test error handling
fd = os_helper.make_bad_fd()
with self.assertRaises(OSError):
fcntl.ioctl(fd, fcntl.FICLONE, fd)
with self.assertRaises(OSError):
fcntl.ioctl(fd, fcntl.FICLONE, b'\0' * 1024)
if __name__ == "__main__":
unittest.main()
unittest.main()
+2 -2
View File
@@ -58,7 +58,7 @@ class StatsTestCase(unittest.TestCase):
temp_storage_new.close()
os.remove(temp_storage_new.name)
@unittest.skipUnless(cProfile, 'TODO: RUSTPYTHON; _lsprof not implemented')
@unittest.skipUnless(cProfile, "TODO: RUSTPYTHON; _lsprof not implemented")
def test_load_equivalent_to_init(self):
stats = pstats.Stats()
self.temp_storage = tempfile.NamedTemporaryFile(delete=False)
@@ -136,7 +136,7 @@ class StatsTestCase(unittest.TestCase):
SortKey.TIME,
'calls')
@unittest.skipUnless(cProfile, 'TODO: RUSTPYTHON; _lsprof not implemented')
@unittest.skipUnless(cProfile, "TODO: RUSTPYTHON; _lsprof not implemented")
def test_get_stats_profile(self):
def pass1(): pass
def pass2(): pass
+13
View File
@@ -117,6 +117,19 @@ class TestMiscellaneous(unittest.TestCase):
recursive_table_toml = nest_count * "key = {" + nest_count * "}"
tomllib.loads(recursive_table_toml)
def test_key_recursion_limit(self):
nest_count = tomllib._parser.MAX_KEY_PARTS - 2
nested_key_toml = "a." * nest_count + "a = 1"
tomllib.loads(nested_key_toml)
nest_count = tomllib._parser.MAX_KEY_PARTS + 2
nested_key_toml = "a." * nest_count + "a = 1"
with self.assertRaisesRegex(
RecursionError,
r"TOML key has more than the allowed [0-9]+ parts",
):
tomllib.loads(nested_key_toml)
def test_types_import(self):
"""Test that `_types` module runs.
+7
View File
@@ -485,6 +485,13 @@ class DeferredEvaluationTests(unittest.TestCase):
ns = run_code("x: [y for y in range(10)]")
self.assertEqual(ns["__annotate__"](1), {"x": list(range(10))})
def test_class_annotation_dunder_classdict(self):
ns = run_code("""
class C:
__classdict__: int
""")
self.assertEqual(ns["C"].__annotations__, {"__classdict__": int})
def test_future_annotations(self):
code = """
from __future__ import annotations
+20
View File
@@ -675,6 +675,26 @@ class BasicTest(BaseTest):
self.assertEqual(out, "".encode())
self.assertEqual(err, "".encode())
# gh-149701: Test exit code is zero even when hashing is disabled
@unittest.skipIf(os.name == 'nt', 'not relevant on Windows')
def test_deactivate_with_strict_bash_opts_and_hashing_disabled(self):
bash = shutil.which("bash")
if bash is None:
self.skipTest("bash required for this test")
rmtree(self.env_dir)
builder = venv.EnvBuilder(clear=True)
builder.create(self.env_dir)
activate = os.path.join(self.env_dir, self.bindir, "activate")
test_script = os.path.join(self.env_dir, "test_hash_disabled.sh")
with open(test_script, "w") as f:
f.write("set -euo pipefail\n"
"set +h\n" # disable hashing
f"source {activate}\n"
"deactivate")
out, err = check_output([bash, test_script])
self.assertEqual(out, "".encode())
self.assertEqual(err, "".encode())
@unittest.skipUnless(sys.platform == 'darwin', 'only relevant on macOS')
def test_macos_env(self):
+34 -24
View File
@@ -1890,11 +1890,8 @@ class OtherTests(unittest.TestCase):
with zipfile.ZipFile(TESTFN, "r") as zf:
zip_info = zf.getinfo("test_source_date_epoch.txt")
get_time = time.localtime(int(os.environ['SOURCE_DATE_EPOCH']))[:6]
# Compare each element of the date_time tuple
# Allow for a 1-second difference
for z_time, g_time in zip(zip_info.date_time, get_time):
self.assertAlmostEqual(z_time, g_time, delta=1)
expected_utc = (2025, 1, 1, 7, 19, 58)
self.assertEqual(zip_info.date_time, expected_utc)
def test_write_without_source_date_epoch(self):
with os_helper.EnvironmentVarGuard() as env:
@@ -1905,9 +1902,13 @@ class OtherTests(unittest.TestCase):
with zipfile.ZipFile(TESTFN, "r") as zf:
zip_info = zf.getinfo("test_no_source_date_epoch.txt")
current_time = time.localtime()[:6]
for z_time, c_time in zip(zip_info.date_time, current_time):
self.assertAlmostEqual(z_time, c_time, delta=2)
self.assertTimestampAlmostEqual(time.localtime(), zip_info.date_time, tolerance=2)
def assertTimestampAlmostEqual(self, time1, time2, tolerance):
import datetime
dt1 = datetime.datetime(*time1[:6])
dt2 = datetime.datetime(*time2[:6])
self.assertLessEqual((dt1 - dt2).total_seconds(), tolerance)
def test_close(self):
"""Check that the zipfile is closed after the 'with' block."""
@@ -3568,6 +3569,7 @@ class TestExecutablePrependedZip(unittest.TestCase):
output = subprocess.check_output([self.exe_zip64, sys.executable])
self.assertIn(b'number in executable: 5', output)
@unittest.skip("TODO: RUSTPYTHON; LookupError: unknown encoding: shift_jis")
class EncodedMetadataTests(unittest.TestCase):
file_names = ['\u4e00', '\u4e8c', '\u4e09'] # Han 'one', 'two', 'three'
@@ -3646,29 +3648,23 @@ class EncodedMetadataTests(unittest.TestCase):
def test_read_after_append(self):
newname = '\u56db' # Han 'four'
expected_names = [name.encode('shift_jis').decode('cp437')
for name in self.file_names[:2]] + self.file_names[2:]
expected_names.append(newname)
expected_content = (*self.file_content, b"newcontent")
newname2 = 'fünf' # representable in cp437, but still stored as UTF-8
expected_names = [*self.file_names, newname, newname2]
mojibake_expected_names = [name.encode('shift_jis').decode('cp437')
if i < 2 else name
for i, name in enumerate(expected_names)]
expected_content = (*self.file_content, b"newcontent", b"newcontent2")
with zipfile.ZipFile(TESTFN, "a") as zipfp:
zipfp.writestr(newname, "newcontent")
self.assertEqual(sorted(zipfp.namelist()), sorted(expected_names))
zipfp.writestr(newname2, "newcontent2")
self.assertEqual(sorted(zipfp.namelist()), sorted(mojibake_expected_names))
with zipfile.ZipFile(TESTFN, "r") as zipfp:
self._test_read(zipfp, expected_names, expected_content)
self._test_read(zipfp, mojibake_expected_names, expected_content)
with zipfile.ZipFile(TESTFN, "r", metadata_encoding='shift_jis') as zipfp:
self.assertEqual(sorted(zipfp.namelist()), sorted(expected_names))
for i, (name, content) in enumerate(zip(expected_names, expected_content)):
info = zipfp.getinfo(name)
self.assertEqual(info.filename, name)
self.assertEqual(info.file_size, len(content))
if i < 2:
with self.assertRaises(zipfile.BadZipFile):
zipfp.read(name)
else:
self.assertEqual(zipfp.read(name), content)
self._test_read(zipfp, expected_names, expected_content)
def test_write_with_metadata_encoding(self):
ZF = zipfile.ZipFile
@@ -3677,6 +3673,20 @@ class EncodedMetadataTests(unittest.TestCase):
"^metadata_encoding is only"):
ZF("nonesuch.zip", mode, metadata_encoding="shift_jis")
def test_add_comment(self):
with zipfile.ZipFile(TESTFN, "r") as zipfp:
mojibake_expected_names = zipfp.namelist()
with zipfile.ZipFile(TESTFN, "a") as zipfp:
zipfp.comment = b'comment'
self.assertEqual(zipfp.namelist(), mojibake_expected_names)
with zipfile.ZipFile(TESTFN, "r") as zipfp:
self._test_read(zipfp, mojibake_expected_names, self.file_content)
with zipfile.ZipFile(TESTFN, "r", metadata_encoding='shift_jis') as zipfp:
self._test_read(zipfp, self.file_names, self.file_content)
def test_cli_with_metadata_encoding(self):
errmsg = "Non-conforming encodings not supported with -c."
args = ["--metadata-encoding=shift_jis", "-c", "nonesuch", "nonesuch"]
+143 -113
View File
@@ -7,25 +7,25 @@ Checkbutton, Scale, Listbox, Scrollbar, OptionMenu, Spinbox
LabelFrame and PanedWindow.
Properties of the widgets are specified with keyword arguments.
Keyword arguments have the same name as the corresponding resource
Keyword arguments have the same name as the corresponding options
under Tk.
Widgets are positioned with one of the geometry managers Place, Pack
or Grid. These managers can be called with methods place, pack, grid
available in every Widget.
Actions are bound to events by resources (e.g. keyword argument
command) or with the method bind.
Actions are bound to events by options (e.g. the command
keyword argument) or with the bind() method.
Example (Hello, World):
import tkinter
from tkinter.constants import *
tk = tkinter.Tk()
frame = tkinter.Frame(tk, relief=RIDGE, borderwidth=2)
frame.pack(fill=BOTH,expand=1)
frame.pack(fill=BOTH, expand=1)
label = tkinter.Label(frame, text="Hello, World")
label.pack(fill=X, expand=1)
button = tkinter.Button(frame,text="Exit",command=tk.destroy)
button = tkinter.Button(frame, text="Exit", command=tk.destroy)
button.pack(side=BOTTOM)
tk.mainloop()
"""
@@ -295,6 +295,8 @@ class Event:
''.join(' %s=%s' % (k, attrs[k]) for k in keys if k in attrs)
)
__class_getitem__ = classmethod(types.GenericAlias)
_support_default_root = True
_default_root = None
@@ -498,10 +500,14 @@ class Variable:
Return the name of the callback.
This deprecated method wraps a deprecated Tcl method that will
likely be removed in the future. Use trace_add() instead.
This deprecated method wraps a deprecated Tcl method removed
in Tcl 9.0. Use trace_add() instead.
"""
# TODO: Add deprecation warning
import warnings
warnings.warn(
"trace_variable() is deprecated and not supported with Tcl 9; "
"use trace_add() instead.",
DeprecationWarning, stacklevel=2)
cbname = self._register(callback)
self._tk.call("trace", "variable", self._name, mode, cbname)
return cbname
@@ -514,10 +520,14 @@ class Variable:
MODE is one of "r", "w", "u" for read, write, undefine.
CBNAME is the name of the callback returned from trace_variable or trace.
This deprecated method wraps a deprecated Tcl method that will
likely be removed in the future. Use trace_remove() instead.
This deprecated method wraps a deprecated Tcl method removed
in Tcl 9.0. Use trace_remove() instead.
"""
# TODO: Add deprecation warning
import warnings
warnings.warn(
"trace_vdelete() is deprecated and not supported with Tcl 9; "
"use trace_remove() instead.",
DeprecationWarning, stacklevel=2)
self._tk.call("trace", "vdelete", self._name, mode, cbname)
cbname = self._tk.splitlist(cbname)[0]
for m, ca in self.trace_info():
@@ -533,10 +543,14 @@ class Variable:
def trace_vinfo(self):
"""Return all trace callback information.
This deprecated method wraps a deprecated Tcl method that will
likely be removed in the future. Use trace_info() instead.
This deprecated method wraps a deprecated Tcl method removed
in Tcl 9.0. Use trace_info() instead.
"""
# TODO: Add deprecation warning
import warnings
warnings.warn(
"trace_vinfo() is deprecated and not supported with Tcl 9; "
"use trace_info() instead.",
DeprecationWarning, stacklevel=2)
return [self._tk.splitlist(x) for x in self._tk.splitlist(
self._tk.call("trace", "vinfo", self._name))]
@@ -833,7 +847,7 @@ class Misc:
The focus order first goes to the next child, then to
the children of the child recursively and then to the
next sibling which is higher in the stacking order. A
widget is omitted if it has the takefocus resource set
widget is omitted if it has the takefocus option set
to 0."""
name = self.tk.call('tk_focusNext', self._w)
if not name: return None
@@ -845,7 +859,7 @@ class Misc:
if not name: return None
return self._nametowidget(name)
def after(self, ms, func=None, *args):
def after(self, ms, func=None, *args, **kw):
"""Call function once after given time.
MS specifies the time in milliseconds. FUNC gives the
@@ -859,7 +873,7 @@ class Misc:
else:
def callit():
try:
func(*args)
func(*args, **kw)
finally:
try:
self.deletecommand(name)
@@ -873,13 +887,13 @@ class Misc:
name = self._register(callit)
return self.tk.call('after', ms, name)
def after_idle(self, func, *args):
def after_idle(self, func, *args, **kw):
"""Call FUNC once if the Tcl main loop has no event to
process.
Return an identifier to cancel the scheduling with
after_cancel."""
return self.after('idle', func, *args)
return self.after('idle', func, *args, **kw)
def after_cancel(self, id):
"""Cancel scheduling of function identified with ID.
@@ -1813,18 +1827,24 @@ class Misc:
# These used to be defined in Widget:
def configure(self, cnf=None, **kw):
"""Configure resources of a widget.
"""Query or modify the configuration options of the widget.
The values for resources are specified as keyword
arguments. To get an overview about
the allowed keyword arguments call the method keys.
If no arguments are specified, return a dictionary describing
all of the available options for the widget.
If an option name is specified, then return a tuple describing
the one named option.
If one or more keyword arguments are specified or a dictionary
is specified, then modify the widget option(s) to have the given
value(s).
"""
return self._configure('configure', cnf, kw)
config = configure
def cget(self, key):
"""Return the resource value for a KEY given as string."""
"""Return the current value of the configuration option."""
return self.tk.call(self._w, 'cget', '-' + key)
__getitem__ = cget
@@ -1833,7 +1853,7 @@ class Misc:
self.configure({key: value})
def keys(self):
"""Return a list of all resource names of this widget."""
"""Return a list of all option names of this widget."""
splitlist = self.tk.splitlist
return [splitlist(x)[0][1:] for x in
splitlist(self.tk.call(self._w, 'configure'))]
@@ -1846,15 +1866,15 @@ class Misc:
return '<%s.%s object %s>' % (
self.__class__.__module__, self.__class__.__qualname__, self._w)
# Pack methods that apply to the master
# Pack methods that apply to the container widget
_noarg_ = ['_noarg_']
def pack_propagate(self, flag=_noarg_):
"""Set or get the status for propagation of geometry information.
A boolean argument specifies whether the geometry information
of the slaves will determine the size of this widget. If no argument
is given the current setting will be returned.
A boolean argument specifies whether the size of this container will
be determined by the geometry information of its content.
If no argument is given the current setting will be returned.
"""
if flag is Misc._noarg_:
return self._getboolean(self.tk.call(
@@ -1865,28 +1885,28 @@ class Misc:
propagate = pack_propagate
def pack_slaves(self):
"""Return a list of all slaves of this widget
in its packing order."""
"""Returns a list of all of the content widgets in the packing order
for this container."""
return [self._nametowidget(x) for x in
self.tk.splitlist(
self.tk.call('pack', 'slaves', self._w))]
slaves = pack_slaves
# Place method that applies to the master
# Place method that applies to the container widget
def place_slaves(self):
"""Return a list of all slaves of this widget
in its packing order."""
"""Returns a list of all the content widgets for which this widget is
the container."""
return [self._nametowidget(x) for x in
self.tk.splitlist(
self.tk.call(
'place', 'slaves', self._w))]
# Grid methods that apply to the master
# Grid methods that apply to the container widget
def grid_anchor(self, anchor=None): # new in Tk 8.5
"""The anchor value controls how to place the grid within the
master when no row/column has any weight.
container widget when no row/column has any weight.
The default anchor is nw."""
self.tk.call('grid', 'anchor', self._w, anchor)
@@ -1903,7 +1923,7 @@ class Misc:
starts at that cell.
The returned integers specify the offset of the upper left
corner in the master widget and the width and height.
corner in the container widget and the width and height.
"""
args = ('grid', 'bbox', self._w)
if column is not None and row is not None:
@@ -1952,7 +1972,7 @@ class Misc:
def grid_columnconfigure(self, index, cnf={}, **kw):
"""Configure column INDEX of a grid.
Valid resources are minsize (minimum size of the column),
Valid options are minsize (minimum size of the column),
weight (how much does additional space propagate to this column)
and pad (how much space to let additionally)."""
return self._grid_configure('columnconfigure', index, cnf, kw)
@@ -1961,7 +1981,7 @@ class Misc:
def grid_location(self, x, y):
"""Return a tuple of column and row which identify the cell
at which the pixel at position X and Y inside the master
at which the pixel at position X and Y inside the container
widget is located."""
return self._getints(
self.tk.call(
@@ -1970,9 +1990,9 @@ class Misc:
def grid_propagate(self, flag=_noarg_):
"""Set or get the status for propagation of geometry information.
A boolean argument specifies whether the geometry information
of the slaves will determine the size of this widget. If no argument
is given, the current setting will be returned.
A boolean argument specifies whether the size of this container will
be determined by the geometry information of its content.
If no argument is given the current setting will be returned.
"""
if flag is Misc._noarg_:
return self._getboolean(self.tk.call(
@@ -1983,7 +2003,7 @@ class Misc:
def grid_rowconfigure(self, index, cnf={}, **kw):
"""Configure row INDEX of a grid.
Valid resources are minsize (minimum size of the row),
Valid options are minsize (minimum size of the row),
weight (how much does additional space propagate to this row)
and pad (how much space to let additionally)."""
return self._grid_configure('rowconfigure', index, cnf, kw)
@@ -1998,8 +2018,13 @@ class Misc:
size = grid_size
def grid_slaves(self, row=None, column=None):
"""Return a list of all slaves of this widget
in its packing order."""
"""Returns a list of the content widgets.
If no arguments are supplied, a list of all of the content in this
container widget is returned, most recently managed first.
If ROW or COLUMN is specified, only the content in the row or
column is returned.
"""
args = ()
if row is not None:
args = args + ('-row', row)
@@ -2451,9 +2476,7 @@ class Tk(Misc, Wm):
self.tk = None
if baseName is None:
import os
# TODO: RUSTPYTHON
# baseName = os.path.basename(sys.argv[0])
baseName = "" # sys.argv[0]
baseName = os.path.basename(sys.argv[0])
baseName, ext = os.path.splitext(baseName)
if ext not in ('.py', '.pyc'):
baseName = baseName + ext
@@ -2587,8 +2610,8 @@ class Pack:
before=widget - pack it before you will pack widget
expand=bool - expand widget if parent size grows
fill=NONE or X or Y or BOTH - fill widget if widget grows
in=master - use master to contain this widget
in_=master - see 'in' option description
in=container - use the container widget to contain this widget
in_=container - see 'in' option description
ipadx=amount - add internal padding in x direction
ipady=amount - add internal padding in y direction
padx=amount - add padding in x direction
@@ -2627,25 +2650,31 @@ class Place:
def place_configure(self, cnf={}, **kw):
"""Place a widget in the parent widget. Use as options:
in=master - master relative to which the widget is placed
in_=master - see 'in' option description
x=amount - locate anchor of this widget at position x of master
y=amount - locate anchor of this widget at position y of master
in=container - the container widget relative to which this widget is
placed
in_=container - see 'in' option description
x=amount - locate anchor of this widget at position x of the
container widget
y=amount - locate anchor of this widget at position y of the
container widget
relx=amount - locate anchor of this widget between 0.0 and 1.0
relative to width of master (1.0 is right edge)
relative to width of the container widget (1.0 is
right edge)
rely=amount - locate anchor of this widget between 0.0 and 1.0
relative to height of master (1.0 is bottom edge)
anchor=NSEW (or subset) - position anchor according to given direction
relative to height of the container widget (1.0 is
bottom edge)
anchor=NSEW (or subset) - position anchor according to given
direction
width=amount - width of this widget in pixel
height=amount - height of this widget in pixel
relwidth=amount - width of this widget between 0.0 and 1.0
relative to width of master (1.0 is the same width
as the master)
relative to width of the container widget (1.0 is
the same width as the container widget)
relheight=amount - height of this widget between 0.0 and 1.0
relative to height of master (1.0 is the same
height as the master)
relative to height of the container widget (1.0
is the same height as the container widget)
bordermode="inside" or "outside" - whether to take border width of
master widget into account
the container widget into account
"""
self.tk.call(
('place', 'configure', self._w)
@@ -2681,8 +2710,8 @@ class Grid:
"""Position a widget in the parent widget in a grid. Use as options:
column=number - use cell identified with given column (starting with 0)
columnspan=number - this widget will span several columns
in=master - use master to contain this widget
in_=master - see 'in' option description
in=container - use the container widget to contain this widget
in_=container - see 'in' option description
ipadx=amount - add internal padding in x direction
ipady=amount - add internal padding in y direction
padx=amount - add padding in x direction
@@ -2805,7 +2834,7 @@ class Toplevel(BaseWidget, Wm):
def __init__(self, master=None, cnf={}, **kw):
"""Construct a toplevel widget with the parent MASTER.
Valid resource names: background, bd, bg, borderwidth, class,
Valid option names: background, bd, bg, borderwidth, class,
colormap, container, cursor, height, highlightbackground,
highlightcolor, highlightthickness, menu, relief, screen, takefocus,
use, visual, width."""
@@ -2882,7 +2911,7 @@ class Canvas(Widget, XView, YView):
def __init__(self, master=None, cnf={}, **kw):
"""Construct a canvas widget with the parent MASTER.
Valid resource names: background, bd, bg, borderwidth, closeenough,
Valid option names: background, bd, bg, borderwidth, closeenough,
confine, cursor, height, highlightbackground, highlightcolor,
highlightthickness, insertbackground, insertborderwidth,
insertofftime, insertontime, insertwidth, offset, relief,
@@ -3091,16 +3120,14 @@ class Canvas(Widget, XView, YView):
self.tk.call((self._w, 'insert') + args)
def itemcget(self, tagOrId, option):
"""Return the resource value for an OPTION for item TAGORID."""
"""Return the value of OPTION for item TAGORID."""
return self.tk.call(
(self._w, 'itemcget') + (tagOrId, '-'+option))
def itemconfigure(self, tagOrId, cnf=None, **kw):
"""Configure resources of an item TAGORID.
"""Query or modify the configuration options of an item TAGORID.
The values for resources are specified as keyword
arguments. To get an overview about
the allowed keyword arguments call the method without arguments.
Similar to configure() except that it applies to the specified item.
"""
return self._configure(('itemconfigure', tagOrId), cnf, kw)
@@ -3192,7 +3219,7 @@ class Checkbutton(Widget):
def __init__(self, master=None, cnf={}, **kw):
"""Construct a checkbutton widget with the parent MASTER.
Valid resource names: activebackground, activeforeground, anchor,
Valid option names: activebackground, activeforeground, anchor,
background, bd, bg, bitmap, borderwidth, command, cursor,
disabledforeground, fg, font, foreground, height,
highlightbackground, highlightcolor, highlightthickness, image,
@@ -3223,7 +3250,7 @@ class Checkbutton(Widget):
self.tk.call(self._w, 'flash')
def invoke(self):
"""Toggle the button and invoke a command if given as resource."""
"""Toggle the button and invoke a command if given as option."""
return self.tk.call(self._w, 'invoke')
def select(self):
@@ -3241,7 +3268,7 @@ class Entry(Widget, XView):
def __init__(self, master=None, cnf={}, **kw):
"""Construct an entry widget with the parent MASTER.
Valid resource names: background, bd, bg, borderwidth, cursor,
Valid option names: background, bd, bg, borderwidth, cursor,
exportselection, fg, font, foreground, highlightbackground,
highlightcolor, highlightthickness, insertbackground,
insertborderwidth, insertofftime, insertontime, insertwidth,
@@ -3327,7 +3354,7 @@ class Frame(Widget):
def __init__(self, master=None, cnf={}, **kw):
"""Construct a frame widget with the parent MASTER.
Valid resource names: background, bd, bg, borderwidth, class,
Valid option names: background, bd, bg, borderwidth, class,
colormap, container, cursor, height, highlightbackground,
highlightcolor, highlightthickness, relief, takefocus, visual, width."""
cnf = _cnfmerge((cnf, kw))
@@ -3371,7 +3398,7 @@ class Listbox(Widget, XView, YView):
def __init__(self, master=None, cnf={}, **kw):
"""Construct a listbox widget with the parent MASTER.
Valid resource names: background, bd, bg, borderwidth, cursor,
Valid option names: background, bd, bg, borderwidth, cursor,
exportselection, fg, font, foreground, height, highlightbackground,
highlightcolor, highlightthickness, relief, selectbackground,
selectborderwidth, selectforeground, selectmode, setgrid, takefocus,
@@ -3464,18 +3491,15 @@ class Listbox(Widget, XView, YView):
return self.tk.getint(self.tk.call(self._w, 'size'))
def itemcget(self, index, option):
"""Return the resource value for an ITEM and an OPTION."""
"""Return the value of OPTION for item at INDEX."""
return self.tk.call(
(self._w, 'itemcget') + (index, '-'+option))
def itemconfigure(self, index, cnf=None, **kw):
"""Configure resources of an ITEM.
"""Query or modify the configuration options of an item at INDEX.
The values for resources are specified as keyword arguments.
To get an overview about the allowed keyword arguments
call the method without arguments.
Valid resource names: background, bg, foreground, fg,
selectbackground, selectforeground."""
Similar to configure() except that it applies to the specified item.
"""
return self._configure(('itemconfigure', index), cnf, kw)
itemconfig = itemconfigure
@@ -3487,7 +3511,7 @@ class Menu(Widget):
def __init__(self, master=None, cnf={}, **kw):
"""Construct menu widget with the parent MASTER.
Valid resource names: activebackground, activeborderwidth,
Valid option names: activebackground, activeborderwidth,
activeforeground, background, bd, bg, borderwidth, cursor,
disabledforeground, fg, font, foreground, postcommand, relief,
selectcolor, takefocus, tearoff, tearoffcommand, title, type."""
@@ -3568,11 +3592,15 @@ class Menu(Widget):
self.tk.call(self._w, 'delete', index1, index2)
def entrycget(self, index, option):
"""Return the resource value of a menu item for OPTION at INDEX."""
"""Return the value of OPTION for a menu item at INDEX."""
return self.tk.call(self._w, 'entrycget', index, '-' + option)
def entryconfigure(self, index, cnf=None, **kw):
"""Configure a menu item at INDEX."""
"""Query or modify the configuration options of a menu item at INDEX.
Similar to configure() except that it applies to the specified
menu item.
"""
return self._configure(('entryconfigure', index), cnf, kw)
entryconfig = entryconfigure
@@ -3630,7 +3658,7 @@ class Radiobutton(Widget):
def __init__(self, master=None, cnf={}, **kw):
"""Construct a radiobutton widget with the parent MASTER.
Valid resource names: activebackground, activeforeground, anchor,
Valid option names: activebackground, activeforeground, anchor,
background, bd, bg, bitmap, borderwidth, command, cursor,
disabledforeground, fg, font, foreground, height,
highlightbackground, highlightcolor, highlightthickness, image,
@@ -3649,7 +3677,7 @@ class Radiobutton(Widget):
self.tk.call(self._w, 'flash')
def invoke(self):
"""Toggle the button and invoke a command if given as resource."""
"""Toggle the button and invoke a command if given as option."""
return self.tk.call(self._w, 'invoke')
def select(self):
@@ -3663,7 +3691,7 @@ class Scale(Widget):
def __init__(self, master=None, cnf={}, **kw):
"""Construct a scale widget with the parent MASTER.
Valid resource names: activebackground, background, bigincrement, bd,
Valid option names: activebackground, background, bigincrement, bd,
bg, borderwidth, command, cursor, digits, fg, font, foreground, from,
highlightbackground, highlightcolor, highlightthickness, label,
length, orient, relief, repeatdelay, repeatinterval, resolution,
@@ -3702,7 +3730,7 @@ class Scrollbar(Widget):
def __init__(self, master=None, cnf={}, **kw):
"""Construct a scrollbar widget with the parent MASTER.
Valid resource names: activebackground, activerelief,
Valid option names: activebackground, activerelief,
background, bd, bg, borderwidth, command, cursor,
elementborderwidth, highlightbackground,
highlightcolor, highlightthickness, jump, orient,
@@ -3946,7 +3974,11 @@ class Text(Widget, XView, YView):
return self.tk.call(self._w, "image", "cget", index, option)
def image_configure(self, index, cnf=None, **kw):
"""Configure an embedded image at INDEX."""
"""Query or modify the configuration options of an embedded image at INDEX.
Similar to configure() except that it applies to the specified
embedded image.
"""
return self._configure(('image', 'configure', index), cnf, kw)
def image_create(self, index, cnf={}, **kw):
@@ -4084,7 +4116,10 @@ class Text(Widget, XView, YView):
return self.tk.call(self._w, 'tag', 'cget', tagName, option)
def tag_configure(self, tagName, cnf=None, **kw):
"""Configure a tag TAGNAME."""
"""Query or modify the configuration options of a tag TAGNAME.
Similar to configure() except that it applies to the specified tag.
"""
return self._configure(('tag', 'configure', tagName), cnf, kw)
tag_config = tag_configure
@@ -4142,7 +4177,11 @@ class Text(Widget, XView, YView):
return self.tk.call(self._w, 'window', 'cget', index, option)
def window_configure(self, index, cnf=None, **kw):
"""Configure an embedded window at INDEX."""
"""Query or modify the configuration options of an embedded window at INDEX.
Similar to configure() except that it applies to the specified
embedded window.
"""
return self._configure(('window', 'configure', index), cnf, kw)
window_config = window_configure
@@ -4182,12 +4221,12 @@ class OptionMenu(Menubutton):
def __init__(self, master, variable, value, *values, **kwargs):
"""Construct an optionmenu widget with the parent MASTER, with
the resource textvariable set to VARIABLE, the initially selected
the option textvariable set to VARIABLE, the initially selected
value VALUE, the other menu values VALUES and an additional
keyword argument command."""
kw = {"borderwidth": 2, "textvariable": variable,
"indicatoron": 1, "relief": RAISED, "anchor": "c",
"highlightthickness": 2}
"highlightthickness": 2, "name": kwargs.pop("name", None)}
Widget.__init__(self, master, "menubutton", kw)
self.widgetName = 'tk_optionMenu'
menu = self.__menu = Menu(self, name="menu", tearoff=0)
@@ -4284,7 +4323,7 @@ class PhotoImage(Image):
def __init__(self, name=None, cnf={}, master=None, **kw):
"""Create an image with NAME.
Valid resource names: data, format, file, gamma, height, palette,
Valid option names: data, format, file, gamma, height, palette,
width."""
Image.__init__(self, 'photo', name, cnf, master, **kw)
@@ -4494,7 +4533,7 @@ class PhotoImage(Image):
The FORMAT option specifies the name of the image file format
handler to be used. If this option is not given, this method uses
a format that consists of a tuple (one element per row) of strings
containings space separated (one element per pixel/column) colors
containing space-separated (one element per pixel/column) colors
in “#RRGGBB” format (where RR is a pair of hexadecimal digits for
the red channel, GG for green, and BB for blue).
@@ -4547,7 +4586,7 @@ class BitmapImage(Image):
def __init__(self, name=None, cnf={}, master=None, **kw):
"""Create a bitmap with NAME.
Valid resource names: background, data, file, foreground, maskdata, maskfile."""
Valid option names: background, data, file, foreground, maskdata, maskfile."""
Image.__init__(self, 'bitmap', name, cnf, master, **kw)
@@ -4865,26 +4904,17 @@ class PanedWindow(Widget):
return self.sash("place", index, x, y)
def panecget(self, child, option):
"""Query a management option for window.
Option may be any value allowed by the paneconfigure subcommand
"""
"""Return the value of option for a child window."""
return self.tk.call(
(self._w, 'panecget') + (child, '-'+option))
def paneconfigure(self, tagOrId, cnf=None, **kw):
"""Query or modify the management options for window.
"""Query or modify the configuration options for a child window.
If no option is specified, returns a list describing all
of the available options for pathName. If option is
specified with no value, then the command returns a list
describing the one named option (this list will be identical
to the corresponding sublist of the value returned if no
option is specified). If one or more option-value pairs are
specified, then the command modifies the given widget
option(s) to have the given value(s); in this case the
command returns an empty string. The following options
are supported:
Similar to configure() except that it applies to the specified
window.
The following options are supported:
after window
Insert the window after the window specified. window
+1 -1
View File
@@ -23,7 +23,7 @@ class ScrolledText(Text):
self.vbar = Scrollbar(self.frame)
self.vbar.pack(side=RIGHT, fill=Y)
kw.update({'yscrollcommand': self.vbar.set})
kw['yscrollcommand'] = self.vbar.set
Text.__init__(self, self.frame, **kw)
self.pack(side=LEFT, fill=BOTH, expand=True)
self.vbar['command'] = self.yview
+5 -2
View File
@@ -321,6 +321,8 @@ def _tclobj_to_py(val):
elif hasattr(val, 'typename'): # some other (single) Tcl object
val = _convert_stringval(val)
if isinstance(val, tuple) and len(val) == 0:
return ''
return val
def tclobjs_to_py(adict):
@@ -1587,7 +1589,7 @@ class OptionMenu(Menubutton):
def __init__(self, master, variable, default=None, *values, **kwargs):
"""Construct a themed OptionMenu widget with master as the parent,
the resource textvariable set to variable, the initially selected
the option textvariable set to variable, the initially selected
value specified by the default parameter, the menu values given by
*values and additional keywords.
@@ -1601,7 +1603,8 @@ class OptionMenu(Menubutton):
A callback that will be invoked after selecting an item.
"""
kw = {'textvariable': variable, 'style': kwargs.pop('style', None),
'direction': kwargs.pop('direction', None)}
'direction': kwargs.pop('direction', None),
'name': kwargs.pop('name', None)}
Menubutton.__init__(self, master, **kw)
self['menu'] = tkinter.Menu(self, tearoff=False)
+13 -1
View File
@@ -4,6 +4,7 @@
from __future__ import annotations
import sys
from types import MappingProxyType
from ._re import (
@@ -18,10 +19,17 @@ from ._re import (
TYPE_CHECKING = False
if TYPE_CHECKING:
from collections.abc import Iterable
from typing import IO, Any
from typing import IO, Any, Final
from ._types import Key, ParseFloat, Pos
# Pathologically excessive number of parts in a key runs into quadratic
# behavior (e.g. in Flags.is_).
# Even if keys aren't currently parsed using recursion, they name a
# recursive structure, so it makes sense to limit it using getrecursionlimit()
# and RecursionError.
MAX_KEY_PARTS: Final = sys.getrecursionlimit()
ASCII_CTRL = frozenset(chr(i) for i in range(32)) | frozenset(chr(127))
# Neither of these sets include quotation mark or backslash. They are
@@ -462,6 +470,10 @@ def parse_key(src: str, pos: Pos) -> tuple[Pos, Key]:
pos = skip_chars(src, pos, TOML_WS)
pos, key_part = parse_key_part(src, pos)
key += (key_part,)
if len(key) > MAX_KEY_PARTS:
raise RecursionError(
f"TOML key has more than the allowed {MAX_KEY_PARTS} parts"
)
pos = skip_chars(src, pos, TOML_WS)
-2
View File
@@ -12,6 +12,4 @@ pretty = True
# Enable most stricter settings
enable_error_code = ignore-without-code
strict = True
strict_bytes = True
local_partial_types = True
warn_unreachable = True
+9 -10
View File
@@ -74,10 +74,10 @@ def extract_tb(tb, limit=None):
This is useful for alternate formatting of stack traces. If
'limit' is omitted or None, all entries are extracted. A
pre-processed stack trace entry is a FrameSummary object
containing attributes filename, lineno, name, and line
representing the information that is usually printed for a stack
trace. The line is a string with leading and trailing
whitespace stripped; if the source is not available it is None.
representing the information that is usually printed for a
stack trace. The line attribute is a string with
leading and trailing whitespace stripped; if the source is not
available the corresponding attribute is None.
"""
return StackSummary._extract_from_extended_frame_gen(
_walk_tb_with_full_positions(tb), limit=limit)
@@ -253,9 +253,8 @@ def extract_stack(f=None, limit=None):
The return value has the same format as for extract_tb(). The
optional 'f' and 'limit' arguments have the same meaning as for
print_stack(). Each item in the list is a quadruple (filename,
line number, function name, text), and the entries are in order
from oldest to newest stack frame.
print_stack(). Each item in the list is a FrameSummary object,
and the entries are in order from oldest to newest stack frame.
"""
if f is None:
f = sys._getframe().f_back
@@ -283,7 +282,7 @@ class FrameSummary:
active when the frame was captured.
- :attr:`name` The name of the function or method that was executing
when the frame was captured.
- :attr:`line` The text from the linecache module for the
- :attr:`line` The text from the linecache module for the line
of code that was running when the frame was captured.
- :attr:`locals` Either None if locals were not supplied, or a dict
mapping the name to the repr() of the variable.
@@ -958,7 +957,7 @@ def _extract_caret_anchors_from_line_segment(segment):
_WIDE_CHAR_SPECIFIERS = "WF"
def _display_width(line, offset=None):
"""Calculate the extra amount of width space the given source
"""Calculate the amount of width space the given source
code segment might take if it were to be displayed on a fixed
width output device. Supports wide unicode characters and emojis."""
@@ -1044,7 +1043,7 @@ class TracebackException:
def __init__(self, exc_type, exc_value, exc_traceback, *, limit=None,
lookup_lines=True, capture_locals=False, compact=False,
max_group_width=15, max_group_depth=10, save_exc_type=True, _seen=None):
# NB: we need to accept exc_traceback, exc_value, exc_traceback to
# NB: we need to accept exc_type, exc_value, exc_traceback to
# permit backwards compat with the existing API, otherwise we
# need stub thunk objects just to glue it together.
# Handle loops in __cause__ or __context__.
+11 -10
View File
@@ -189,18 +189,19 @@ def get_original_bases(cls, /):
class DynamicClassAttribute:
"""Route attribute access on a class to __getattr__.
This is a descriptor, used to define attributes that act differently when
accessed through an instance and through a class. Instance access remains
normal, but access to an attribute through a class will be routed to the
class's __getattr__ method; this is done by raising AttributeError.
This is a descriptor, used to define attributes that act differently
when accessed through an instance and through a class. Instance access
remains normal, but access to an attribute through a class will be
routed to the class's __getattr__ method; this is done by raising
AttributeError.
This allows one to have properties active on an instance, and have virtual
attributes on the class with the same name. (Enum used this between Python
versions 3.4 - 3.9 .)
This allows one to have properties active on an instance, and have
virtual attributes on the class with the same name. (Enum used this
between Python versions 3.4 - 3.9 .)
Subclass from this to use a different method of accessing virtual attributes
and still be treated properly by the inspect module. (Enum uses this since
Python 3.10 .)
Subclass from this to use a different method of accessing virtual
attributes and still be treated properly by the inspect module. (Enum
uses this since Python 3.10 .)
"""
def __init__(self, fget=None, fset=None, fdel=None, doc=None):
+62 -62
View File
@@ -5,7 +5,7 @@ Among other things, the module includes the following:
* Generic, Protocol, and internal machinery to support generic aliases.
All subscripted types like X[int], Union[int, str] are generic aliases.
* Various "special forms" that have unique meanings in type annotations:
NoReturn, Never, ClassVar, Self, Concatenate, Unpack, and others.
Any, Never, ClassVar, Self, Concatenate, Unpack, and others.
* Classes whose instances can be type arguments to generic classes and functions:
TypeVar, ParamSpec, TypeVarTuple.
* Public helper functions: get_type_hints, overload, cast, final, and others.
@@ -588,12 +588,12 @@ class _AnyMeta(type):
class Any(metaclass=_AnyMeta):
"""Special type indicating an unconstrained type.
- Any is compatible with every type.
- Any assumed to have all methods.
- All values assumed to be instances of Any.
- Any is assignable to every type.
- Any assumed to have all methods and attributes.
- All values are assignable to Any.
Note that all the above statements are true from the point of view of
static type checkers. At runtime, Any should not be used with instance
static type checkers. At runtime, Any cannot be used with instance
checks.
"""
@@ -712,7 +712,7 @@ def ClassVar(self, parameters):
ClassVar accepts only types and cannot be further subscribed.
Note that ClassVar is not a class itself, and should not
Note that ClassVar is not a class itself, and cannot
be used with isinstance() or issubclass().
"""
item = _type_check(parameters, f'{self} accepts only single type.', allow_special_forms=True)
@@ -742,7 +742,7 @@ def Final(self, parameters):
@_SpecialForm
def Optional(self, parameters):
"""Optional[X] is equivalent to Union[X, None]."""
"""Optional[X] is equivalent to X | None."""
arg = _type_check(parameters, f"{self} requires a single type.")
return Union[arg, type(None)]
@@ -785,7 +785,7 @@ def Literal(self, *parameters):
def TypeAlias(self, parameters):
"""Special form for marking type aliases.
Use TypeAlias to indicate that an assignment should
TypeAlias can be used to indicate that an assignment should
be recognized as a proper type alias definition by type
checkers.
@@ -1780,7 +1780,7 @@ def Unpack(self, parameters):
def foo(**kwargs: Unpack[Movie]): ...
Note that there is only some runtime checking of this operator. Not
everything the runtime allows may be accepted by static type checkers.
everything the runtime allows is accepted by static type checkers.
For more information, see PEPs 646 and 692.
"""
@@ -2261,7 +2261,7 @@ def runtime_checkable(cls):
Such protocol can be used with isinstance() and issubclass().
Raise TypeError if applied to a non-protocol class.
This allows a simple-minded structural check very similar to
one trick ponies in collections.abc such as Iterable.
one-trick ponies in collections.abc such as Iterable.
For example::
@@ -2328,8 +2328,8 @@ def get_type_hints(obj, globalns=None, localns=None, include_extras=False,
*, format=None):
"""Return type hints for an object.
This is often the same as obj.__annotations__, but it handles
forward references encoded as string literals and recursively replaces all
This is often the same as annotationlib.get_annotations(obj) or obj.__annotations__,
but it handles forward references encoded as string literals and recursively replaces all
'Annotated[T, ...]' with 'T' (unless 'include_extras=True').
The argument may be a module, class, method, or function. The annotations
@@ -2541,7 +2541,7 @@ def get_args(tp):
def is_typeddict(tp):
"""Check if an annotation is a TypedDict class.
"""Check if an object is a TypedDict class.
For example::
@@ -2655,20 +2655,9 @@ _overload_registry = defaultdict(functools.partial(defaultdict, dict))
def overload(func):
"""Decorator for overloaded functions/methods.
In a stub file, place two or more stub definitions for the same
function in a row, each decorated with @overload.
For example::
@overload
def utf8(value: None) -> None: ...
@overload
def utf8(value: bytes) -> bytes: ...
@overload
def utf8(value: str) -> bytes: ...
In a non-stub file (i.e. a regular .py file), do the same but
follow it with an implementation. The implementation should *not*
In a non-stub file, place two or more stub definitions for the same
function in a row, each decorated with @overload, followed
by an implementation. The implementation should *not*
be decorated with @overload::
@overload
@@ -2680,6 +2669,16 @@ def overload(func):
def utf8(value):
... # implementation goes here
In a stub file or in an abstract method (for example, in a Protocol definition),
the implementation may be omitted::
@overload
def utf8(value: None) -> None: ...
@overload
def utf8(value: bytes) -> bytes: ...
@overload
def utf8(value: str) -> bytes: ...
The overloads for a function can be retrieved at runtime using the
get_overloads() function.
"""
@@ -2714,7 +2713,7 @@ def final(f):
"""Decorator to indicate final methods and final classes.
Use this decorator to indicate to type checkers that the decorated
method cannot be overridden, and decorated class cannot be subclassed.
method cannot be overridden, and the decorated class cannot be subclassed.
For example::
@@ -2756,7 +2755,7 @@ T_co = TypeVar('T_co', covariant=True) # Any type covariant containers.
V_co = TypeVar('V_co', covariant=True) # Any type covariant containers.
VT_co = TypeVar('VT_co', covariant=True) # Value type covariant containers.
T_contra = TypeVar('T_contra', contravariant=True) # Ditto contravariant.
# Internal type variable used for Type[].
# Internal type bound to class object types.
CT_co = TypeVar('CT_co', covariant=True, bound=type)
@@ -2847,7 +2846,7 @@ Type.__doc__ = \
And a function that takes a class argument that's a subclass of
User and returns an instance of the corresponding class::
def new_user[U](user_class: Type[U]) -> U:
def new_user[U](user_class: type[U]) -> U:
user = user_class()
# (Here we could write the user object to a database)
return user
@@ -2860,7 +2859,7 @@ Type.__doc__ = \
@runtime_checkable
class SupportsInt(Protocol):
"""An ABC with one abstract method __int__."""
"""A protocol with one abstract method __int__."""
__slots__ = ()
@@ -2871,7 +2870,7 @@ class SupportsInt(Protocol):
@runtime_checkable
class SupportsFloat(Protocol):
"""An ABC with one abstract method __float__."""
"""A protocol with one abstract method __float__."""
__slots__ = ()
@@ -2882,7 +2881,7 @@ class SupportsFloat(Protocol):
@runtime_checkable
class SupportsComplex(Protocol):
"""An ABC with one abstract method __complex__."""
"""A protocol with one abstract method __complex__."""
__slots__ = ()
@@ -2893,7 +2892,7 @@ class SupportsComplex(Protocol):
@runtime_checkable
class SupportsBytes(Protocol):
"""An ABC with one abstract method __bytes__."""
"""A protocol with one abstract method __bytes__."""
__slots__ = ()
@@ -2904,7 +2903,7 @@ class SupportsBytes(Protocol):
@runtime_checkable
class SupportsIndex(Protocol):
"""An ABC with one abstract method __index__."""
"""A protocol with one abstract method __index__."""
__slots__ = ()
@@ -2915,7 +2914,7 @@ class SupportsIndex(Protocol):
@runtime_checkable
class SupportsAbs[T](Protocol):
"""An ABC with one abstract method __abs__ that is covariant in its return type."""
"""A protocol with one abstract method __abs__ that is covariant in its return type."""
__slots__ = ()
@@ -2926,7 +2925,7 @@ class SupportsAbs[T](Protocol):
@runtime_checkable
class SupportsRound[T](Protocol):
"""An ABC with one abstract method __round__ that is covariant in its return type."""
"""A protocol with one abstract method __round__ that is covariant in its return type."""
__slots__ = ()
@@ -3043,7 +3042,7 @@ class NamedTupleMeta(type):
def NamedTuple(typename, fields=_sentinel, /, **kwargs):
"""Typed version of namedtuple.
"""Typed version of collections.namedtuple.
Usage::
@@ -3055,8 +3054,8 @@ def NamedTuple(typename, fields=_sentinel, /, **kwargs):
Employee = collections.namedtuple('Employee', ['name', 'id'])
The resulting class has an extra __annotations__ attribute, giving a
dict that maps field names to types. (The field names are also in
The types for each field name can be retrieved by calling
annotationlib.get_annotations(Employee). (The field names are also in
the _fields attribute, which is part of the namedtuple API.)
An alternative equivalent functional syntax is also accepted::
@@ -3145,7 +3144,7 @@ class _TypedDictMeta(type):
This method is called when TypedDict is subclassed,
or when TypedDict is instantiated. This way
TypedDict supports all three syntax forms described in its docstring.
TypedDict classes can be created through both class-based and functional syntax.
Subclasses and instances of TypedDict return actual dictionaries.
"""
for base in bases:
@@ -3294,14 +3293,22 @@ def TypedDict(typename, fields=_sentinel, /, *, total=True):
>>> Point2D(x=1, y=2, label='first') == dict(x=1, y=2, label='first')
True
The type info can be accessed via the Point2D.__annotations__ dict, and
the Point2D.__required_keys__ and Point2D.__optional_keys__ frozensets.
The type info can be accessed by calling annotationlib.get_annotations(Point2D), and
via the Point2D.__required_keys__ and Point2D.__optional_keys__ frozensets.
TypedDict supports an additional equivalent form::
Point2D = TypedDict('Point2D', {'x': int, 'y': int, 'label': str})
By default, all keys must be present in a TypedDict. It is possible
to override this by specifying totality::
to override this by using the NotRequired and Required special forms::
class Point2D(TypedDict):
x: int # the "x" key must always be present (Required is the default)
y: NotRequired[int] # the "y" key can be omitted
This means that a Point2D TypedDict can have the "y" key omitted, but the "x" key must be present.
Items are required by default, so the Required special form is not necessary in this example.
In addition, the total argument to the TypedDict function can be used to make all items not required::
class Point2D(TypedDict, total=False):
x: int
@@ -3310,16 +3317,8 @@ def TypedDict(typename, fields=_sentinel, /, *, total=True):
This means that a Point2D TypedDict can have any of the keys omitted. A type
checker is only expected to support a literal False or True as the value of
the total argument. True is the default, and makes all items defined in the
class body be required.
The Required and NotRequired special forms can also be used to mark
individual keys as being required or not required::
class Point2D(TypedDict):
x: int # the "x" key must always be present (Required is the default)
y: NotRequired[int] # the "y" key can be omitted
See PEP 655 for more details on Required and NotRequired.
class body be required. The Required special form can be used to mark individual
keys as required in a total=False TypedDict.
The ReadOnly special form can be used
to mark individual keys as immutable for type checkers::
@@ -3328,6 +3327,7 @@ def TypedDict(typename, fields=_sentinel, /, *, total=True):
id: ReadOnly[int] # the "id" key must not be modified
username: str # the "username" key can be changed
See PEPs 589, 655, and 705 for more information.
"""
if fields is _sentinel or fields is None:
import warnings
@@ -3374,7 +3374,7 @@ def Required(self, parameters):
year: int
m = Movie(
title='The Matrix', # typechecker error if key is omitted
title='The Matrix', # type checker error if key is omitted
year=1999,
)
@@ -3396,7 +3396,7 @@ def NotRequired(self, parameters):
year: NotRequired[int]
m = Movie(
title='The Matrix', # typechecker error if key is omitted
title='The Matrix', # type checker error if key is omitted
year=1999,
)
"""
@@ -3416,7 +3416,7 @@ def ReadOnly(self, parameters):
def mutate_movie(m: Movie) -> None:
m["year"] = 1992 # allowed
m["title"] = "The Matrix" # typechecker error
m["title"] = "The Matrix" # type checker error
There is no runtime checking for this property.
"""
@@ -3503,8 +3503,8 @@ class IO(Generic[AnyStr]):
classes (text vs. binary, read vs. write vs. read/write,
append-only, unbuffered). The TextIO and BinaryIO subclasses
below capture the distinctions between text vs. binary, which is
pervasive in the interface; however we currently do not offer a
way to track the other distinctions in the type system.
pervasive in the interface. For more precise types, define a custom
Protocol.
"""
__slots__ = ()
@@ -3594,7 +3594,7 @@ class IO(Generic[AnyStr]):
class BinaryIO(IO[bytes]):
"""Typed version of the return of open() in binary mode."""
"""Typed approximation of the return of open() in binary mode."""
__slots__ = ()
@@ -3608,7 +3608,7 @@ class BinaryIO(IO[bytes]):
class TextIO(IO[str]):
"""Typed version of the return of open() in text mode."""
"""Typed approximation of the return of open() in text mode."""
__slots__ = ()
@@ -3675,7 +3675,7 @@ def dataclass_transform(
field_specifiers: tuple[type[Any] | Callable[..., Any], ...] = (),
**kwargs: Any,
) -> _IdentityCallable:
"""Decorator to mark an object as providing dataclass-like behaviour.
"""Decorator to mark an object as providing dataclass-like behavior.
The decorator can be applied to a function, class, or metaclass.
+2 -2
View File
@@ -17,7 +17,7 @@ deactivate () {
# Call hash to forget past locations. Without forgetting
# past locations the $PATH changes we made may not be respected.
# See "man bash" for more details. hash is usually a builtin of your shell
hash -r 2> /dev/null
hash -r 2> /dev/null || true
if [ -n "${_OLD_VIRTUAL_PS1:-}" ] ; then
PS1="${_OLD_VIRTUAL_PS1:-}"
@@ -73,4 +73,4 @@ fi
# Call hash to forget past commands. Without forgetting
# past commands the $PATH changes we made may not be respected
hash -r 2> /dev/null
hash -r 2> /dev/null || true
+36 -28
View File
@@ -566,8 +566,12 @@ class ZipInfo:
return header + filename + extra
def _encodeFilenameFlags(self):
if self.flag_bits & _MASK_UTF_FILENAME:
encoding = 'ascii'
else:
encoding = 'cp437'
try:
return self.filename.encode('ascii'), self.flag_bits
return self.filename.encode(encoding), self.flag_bits & ~_MASK_UTF_FILENAME
except UnicodeEncodeError:
return self.filename.encode('utf-8'), self.flag_bits | _MASK_UTF_FILENAME
@@ -620,11 +624,12 @@ class ZipInfo:
def from_file(cls, filename, arcname=None, *, strict_timestamps=True):
"""Construct an appropriate ZipInfo for a file on the filesystem.
filename should be the path to a file or directory on the filesystem.
filename should be the path to a file or directory on the
filesystem.
arcname is the name which it will have within the archive (by default,
this will be the same as filename, but without a drive letter and with
leading path separators removed).
arcname is the name which it will have within the archive (by
default, this will be the same as filename, but without a drive
letter and with leading path separators removed).
"""
if isinstance(filename, os.PathLike):
filename = os.fspath(filename)
@@ -663,9 +668,12 @@ class ZipInfo:
Return self.
"""
# gh-91279: Set the SOURCE_DATE_EPOCH to a specific timestamp
epoch = os.environ.get('SOURCE_DATE_EPOCH')
get_time = int(epoch) if epoch else time.time()
self.date_time = time.localtime(get_time)[:6]
source_date_epoch = os.environ.get('SOURCE_DATE_EPOCH')
if source_date_epoch:
self.date_time = time.gmtime(int(source_date_epoch))[:6]
else:
self.date_time = time.localtime(time.time())[:6]
self.compress_type = archive.compression
self.compress_level = archive.compresslevel
@@ -1392,19 +1400,19 @@ class ZipFile:
mode: The mode can be either read 'r', write 'w', exclusive create 'x',
or append 'a'.
compression: ZIP_STORED (no compression), ZIP_DEFLATED (requires zlib),
ZIP_BZIP2 (requires bz2), ZIP_LZMA (requires lzma), or
ZIP_ZSTANDARD (requires compression.zstd).
allowZip64: if True ZipFile will create files with ZIP64 extensions when
needed, otherwise it will raise an exception when this would
be necessary.
compresslevel: None (default for the given compression type) or an integer
specifying the level to pass to the compressor.
When using ZIP_STORED or ZIP_LZMA this keyword has no effect.
When using ZIP_DEFLATED integers 0 through 9 are accepted.
When using ZIP_BZIP2 integers 1 through 9 are accepted.
When using ZIP_ZSTANDARD integers -7 though 22 are common,
see the CompressionParameter enum in compression.zstd for
details.
ZIP_BZIP2 (requires bz2), ZIP_LZMA (requires lzma), or
ZIP_ZSTANDARD (requires compression.zstd).
allowZip64: if True ZipFile will create files with ZIP64 extensions
when needed, otherwise it will raise an exception when this
would be necessary.
compresslevel: None (default for the given compression type) or
an integer specifying the level to pass to the compressor.
When using ZIP_STORED or ZIP_LZMA this keyword has no effect.
When using ZIP_DEFLATED integers 0 through 9 are accepted.
When using ZIP_BZIP2 integers 1 through 9 are accepted.
When using ZIP_ZSTANDARD integers -7 though 22 are common,
see the CompressionParameter enum in compression.zstd for
details.
"""
@@ -1414,8 +1422,8 @@ class ZipFile:
def __init__(self, file, mode="r", compression=ZIP_STORED, allowZip64=True,
compresslevel=None, *, strict_timestamps=True, metadata_encoding=None):
"""Open the ZIP file with mode read 'r', write 'w', exclusive create 'x',
or append 'a'."""
"""Open the ZIP file with mode read 'r', write 'w', exclusive create
'x', or append 'a'."""
if mode not in ('r', 'w', 'x', 'a'):
raise ValueError("ZipFile requires mode 'r', 'w', 'x', or 'a'")
@@ -1693,10 +1701,10 @@ class ZipFile:
pwd is the password to decrypt files (only used for reading).
When writing, if the file size is not known in advance but may exceed
2 GiB, pass force_zip64 to use the ZIP64 format, which can handle large
files. If the size is known in advance, it is best to pass a ZipInfo
instance for name, with zinfo.file_size set.
When writing, if the file size is not known in advance but may
exceed 2 GiB, pass force_zip64 to use the ZIP64 format, which can
handle large files. If the size is known in advance, it is best to
pass a ZipInfo instance for name, with zinfo.file_size set.
"""
if mode not in {"r", "w"}:
raise ValueError('open() requires mode "r" or "w"')
@@ -1808,7 +1816,7 @@ class ZipFile:
zinfo.compress_size = 0
zinfo.CRC = 0
zinfo.flag_bits = 0x00
zinfo.flag_bits = _MASK_UTF_FILENAME
if zinfo.compress_type == ZIP_LZMA:
# Compressed data includes an end-of-stream (EOS) marker
zinfo.flag_bits |= _MASK_COMPRESS_OPTION_1