Skip to content

Commit b071747

Browse files
authored
Merge branch 'main' into optimized-idle-semaphore-in-thread-pool-executor
2 parents 0f50fe5 + 84181c1 commit b071747

31 files changed

+780
-674
lines changed

.github/workflows/build.yml

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -154,15 +154,25 @@ jobs:
154154
needs: check_source
155155
if: needs.check_source.outputs.run_tests == 'true'
156156
env:
157+
HOMEBREW_NO_ANALYTICS: 1
158+
HOMEBREW_NO_AUTO_UPDATE: 1
159+
HOMEBREW_NO_INSTALL_CLEANUP: 1
157160
PYTHONSTRICTEXTENSIONBUILD: 1
158161
steps:
159162
- uses: actions/checkout@v3
160-
- name: Prepare homebrew environment variables
163+
- name: Install Homebrew dependencies
164+
run: brew install pkg-config [email protected] xz gdbm tcl-tk
165+
- name: Prepare Homebrew environment variables
161166
run: |
162-
echo "LDFLAGS=-L$(brew --prefix tcl-tk)/lib" >> $GITHUB_ENV
167+
echo "CFLAGS=-I$(brew --prefix gdbm)/include -I$(brew --prefix xz)/include" >> $GITHUB_ENV
168+
echo "LDFLAGS=-L$(brew --prefix gdbm)/lib -I$(brew --prefix xz)/lib" >> $GITHUB_ENV
163169
echo "PKG_CONFIG_PATH=$(brew --prefix [email protected])/lib/pkgconfig:$(brew --prefix tcl-tk)/lib/pkgconfig" >> $GITHUB_ENV
164170
- name: Configure CPython
165-
run: ./configure --with-pydebug --prefix=/opt/python-dev
171+
run: |
172+
./configure \
173+
--with-pydebug \
174+
--prefix=/opt/python-dev \
175+
--with-openssl="$(brew --prefix [email protected])"
166176
- name: Build CPython
167177
run: make -j4
168178
- name: Display build info

Doc/library/importlib.resources.abc.rst

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,9 +89,12 @@
8989

9090
.. class:: Traversable
9191

92-
An object with a subset of pathlib.Path methods suitable for
92+
An object with a subset of :class:`pathlib.Path` methods suitable for
9393
traversing directories and opening files.
9494

95+
For a representation of the object on the file-system, use
96+
:meth:`importlib.resources.as_file`.
97+
9598
.. versionadded:: 3.9
9699

97100
.. deprecated-removed:: 3.12 3.14

Doc/library/zipfile.rst

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,9 @@ The module defines the following items:
5555
.. class:: Path
5656
:noindex:
5757

58-
A pathlib-compatible wrapper for zip files. See section
59-
:ref:`path-objects` for details.
58+
Class that implements a subset of the interface provided by
59+
:class:`pathlib.Path`, including the full
60+
:class:`importlib.resources.abc.Traversable` interface.
6061

6162
.. versionadded:: 3.8
6263

Include/cpython/code.h

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,21 +19,35 @@ extern "C" {
1919
typedef union {
2020
uint16_t cache;
2121
struct {
22-
uint8_t opcode;
23-
uint8_t oparg;
24-
};
22+
uint8_t code;
23+
uint8_t arg;
24+
} op;
2525
} _Py_CODEUNIT;
2626

27-
#define _Py_OPCODE(word) ((word).opcode)
28-
#define _Py_OPARG(word) ((word).oparg)
27+
28+
/* These macros only remain defined for compatibility. */
29+
#define _Py_OPCODE(word) ((word).op.code)
30+
#define _Py_OPARG(word) ((word).op.arg)
31+
32+
static inline _Py_CODEUNIT
33+
_py_make_codeunit(uint8_t opcode, uint8_t oparg)
34+
{
35+
// No designated initialisers because of C++ compat
36+
_Py_CODEUNIT word;
37+
word.op.code = opcode;
38+
word.op.arg = oparg;
39+
return word;
40+
}
2941

3042
static inline void
3143
_py_set_opcode(_Py_CODEUNIT *word, uint8_t opcode)
3244
{
33-
word->opcode = opcode;
45+
word->op.code = opcode;
3446
}
3547

36-
#define _Py_SET_OPCODE(word, opcode) _py_set_opocde(&(word), opcode)
48+
#define _Py_MAKE_CODEUNIT(opcode, oparg) _py_make_codeunit((opcode), (oparg))
49+
#define _Py_SET_OPCODE(word, opcode) _py_set_opcode(&(word), (opcode))
50+
3751

3852
typedef struct {
3953
PyObject *_co_code;

Lib/test/test_io.py

Lines changed: 90 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1042,6 +1042,95 @@ def close(self):
10421042
support.gc_collect()
10431043
self.assertIsNone(wr(), wr)
10441044

1045+
@support.cpython_only
1046+
class TestIOCTypes(unittest.TestCase):
1047+
def setUp(self):
1048+
_io = import_helper.import_module("_io")
1049+
self.types = [
1050+
_io.BufferedRWPair,
1051+
_io.BufferedRandom,
1052+
_io.BufferedReader,
1053+
_io.BufferedWriter,
1054+
_io.BytesIO,
1055+
_io.FileIO,
1056+
_io.IncrementalNewlineDecoder,
1057+
_io.StringIO,
1058+
_io.TextIOWrapper,
1059+
_io._BufferedIOBase,
1060+
_io._BytesIOBuffer,
1061+
_io._IOBase,
1062+
_io._RawIOBase,
1063+
_io._TextIOBase,
1064+
]
1065+
if sys.platform == "win32":
1066+
self.types.append(_io._WindowsConsoleIO)
1067+
self._io = _io
1068+
1069+
def test_immutable_types(self):
1070+
for tp in self.types:
1071+
with self.subTest(tp=tp):
1072+
with self.assertRaisesRegex(TypeError, "immutable"):
1073+
tp.foo = "bar"
1074+
1075+
def test_class_hierarchy(self):
1076+
def check_subs(types, base):
1077+
for tp in types:
1078+
with self.subTest(tp=tp, base=base):
1079+
self.assertTrue(issubclass(tp, base))
1080+
1081+
def recursive_check(d):
1082+
for k, v in d.items():
1083+
if isinstance(v, dict):
1084+
recursive_check(v)
1085+
elif isinstance(v, set):
1086+
check_subs(v, k)
1087+
else:
1088+
self.fail("corrupt test dataset")
1089+
1090+
_io = self._io
1091+
hierarchy = {
1092+
_io._IOBase: {
1093+
_io._BufferedIOBase: {
1094+
_io.BufferedRWPair,
1095+
_io.BufferedRandom,
1096+
_io.BufferedReader,
1097+
_io.BufferedWriter,
1098+
_io.BytesIO,
1099+
},
1100+
_io._RawIOBase: {
1101+
_io.FileIO,
1102+
},
1103+
_io._TextIOBase: {
1104+
_io.StringIO,
1105+
_io.TextIOWrapper,
1106+
},
1107+
},
1108+
}
1109+
if sys.platform == "win32":
1110+
hierarchy[_io._IOBase][_io._RawIOBase].add(_io._WindowsConsoleIO)
1111+
1112+
recursive_check(hierarchy)
1113+
1114+
def test_subclassing(self):
1115+
_io = self._io
1116+
dataset = {k: True for k in self.types}
1117+
dataset[_io._BytesIOBuffer] = False
1118+
1119+
for tp, is_basetype in dataset.items():
1120+
with self.subTest(tp=tp, is_basetype=is_basetype):
1121+
name = f"{tp.__name__}_subclass"
1122+
bases = (tp,)
1123+
if is_basetype:
1124+
_ = type(name, bases, {})
1125+
else:
1126+
msg = "not an acceptable base type"
1127+
with self.assertRaisesRegex(TypeError, msg):
1128+
_ = type(name, bases, {})
1129+
1130+
def test_disallow_instantiation(self):
1131+
_io = self._io
1132+
support.check_disallow_instantiation(self, _io._BytesIOBuffer)
1133+
10451134
class PyIOTest(IOTest):
10461135
pass
10471136

@@ -4671,7 +4760,7 @@ def load_tests(loader, tests, pattern):
46714760
CIncrementalNewlineDecoderTest, PyIncrementalNewlineDecoderTest,
46724761
CTextIOWrapperTest, PyTextIOWrapperTest,
46734762
CMiscIOTest, PyMiscIOTest,
4674-
CSignalsTest, PySignalsTest,
4763+
CSignalsTest, PySignalsTest, TestIOCTypes,
46754764
)
46764765

46774766
# Put the namespaces of the IO module we are testing and some useful mock

Lib/test/test_zipfile/test_core.py

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3010,5 +3010,67 @@ def test_cli_with_metadata_encoding_extract(self):
30103010
self.assertIn(name, listing)
30113011

30123012

3013+
class StripExtraTests(unittest.TestCase):
3014+
# Note: all of the "z" characters are technically invalid, but up
3015+
# to 3 bytes at the end of the extra will be passed through as they
3016+
# are too short to encode a valid extra.
3017+
3018+
ZIP64_EXTRA = 1
3019+
3020+
def test_no_data(self):
3021+
s = struct.Struct("<HH")
3022+
a = s.pack(self.ZIP64_EXTRA, 0)
3023+
b = s.pack(2, 0)
3024+
c = s.pack(3, 0)
3025+
3026+
self.assertEqual(b'', zipfile._strip_extra(a, (self.ZIP64_EXTRA,)))
3027+
self.assertEqual(b, zipfile._strip_extra(b, (self.ZIP64_EXTRA,)))
3028+
self.assertEqual(
3029+
b+b"z", zipfile._strip_extra(b+b"z", (self.ZIP64_EXTRA,)))
3030+
3031+
self.assertEqual(b+c, zipfile._strip_extra(a+b+c, (self.ZIP64_EXTRA,)))
3032+
self.assertEqual(b+c, zipfile._strip_extra(b+a+c, (self.ZIP64_EXTRA,)))
3033+
self.assertEqual(b+c, zipfile._strip_extra(b+c+a, (self.ZIP64_EXTRA,)))
3034+
3035+
def test_with_data(self):
3036+
s = struct.Struct("<HH")
3037+
a = s.pack(self.ZIP64_EXTRA, 1) + b"a"
3038+
b = s.pack(2, 2) + b"bb"
3039+
c = s.pack(3, 3) + b"ccc"
3040+
3041+
self.assertEqual(b"", zipfile._strip_extra(a, (self.ZIP64_EXTRA,)))
3042+
self.assertEqual(b, zipfile._strip_extra(b, (self.ZIP64_EXTRA,)))
3043+
self.assertEqual(
3044+
b+b"z", zipfile._strip_extra(b+b"z", (self.ZIP64_EXTRA,)))
3045+
3046+
self.assertEqual(b+c, zipfile._strip_extra(a+b+c, (self.ZIP64_EXTRA,)))
3047+
self.assertEqual(b+c, zipfile._strip_extra(b+a+c, (self.ZIP64_EXTRA,)))
3048+
self.assertEqual(b+c, zipfile._strip_extra(b+c+a, (self.ZIP64_EXTRA,)))
3049+
3050+
def test_multiples(self):
3051+
s = struct.Struct("<HH")
3052+
a = s.pack(self.ZIP64_EXTRA, 1) + b"a"
3053+
b = s.pack(2, 2) + b"bb"
3054+
3055+
self.assertEqual(b"", zipfile._strip_extra(a+a, (self.ZIP64_EXTRA,)))
3056+
self.assertEqual(b"", zipfile._strip_extra(a+a+a, (self.ZIP64_EXTRA,)))
3057+
self.assertEqual(
3058+
b"z", zipfile._strip_extra(a+a+b"z", (self.ZIP64_EXTRA,)))
3059+
self.assertEqual(
3060+
b+b"z", zipfile._strip_extra(a+a+b+b"z", (self.ZIP64_EXTRA,)))
3061+
3062+
self.assertEqual(b, zipfile._strip_extra(a+a+b, (self.ZIP64_EXTRA,)))
3063+
self.assertEqual(b, zipfile._strip_extra(a+b+a, (self.ZIP64_EXTRA,)))
3064+
self.assertEqual(b, zipfile._strip_extra(b+a+a, (self.ZIP64_EXTRA,)))
3065+
3066+
def test_too_short(self):
3067+
self.assertEqual(b"", zipfile._strip_extra(b"", (self.ZIP64_EXTRA,)))
3068+
self.assertEqual(b"z", zipfile._strip_extra(b"z", (self.ZIP64_EXTRA,)))
3069+
self.assertEqual(
3070+
b"zz", zipfile._strip_extra(b"zz", (self.ZIP64_EXTRA,)))
3071+
self.assertEqual(
3072+
b"zzz", zipfile._strip_extra(b"zzz", (self.ZIP64_EXTRA,)))
3073+
3074+
30133075
if __name__ == "__main__":
30143076
unittest.main()

Lib/zipfile/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,8 @@ def _strip_extra(extra, xids):
207207
i = j
208208
if not modified:
209209
return extra
210+
if start != len(extra):
211+
buffer.append(extra[start:])
210212
return b''.join(buffer)
211213

212214
def _check_zipfile(fp):
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Removes use of non-standard C++ extension in public header files.
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Correctly preserve "extra" fields in ``zipfile`` regardless of their
2+
ordering relative to a zip64 "extra."
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fix potential undefined behaviour in corner cases of floating-point-to-time
2+
conversions.

0 commit comments

Comments
 (0)