Skip to content

Commit

Permalink
Merge branch 'main' into pythongh-102038
Browse files Browse the repository at this point in the history
  • Loading branch information
hauntsaninja committed Feb 20, 2023
2 parents b83d9fd + 84181c1 commit eab405a
Show file tree
Hide file tree
Showing 29 changed files with 749 additions and 668 deletions.
16 changes: 13 additions & 3 deletions .github/workflows/build.yml
Expand Up @@ -154,15 +154,25 @@ jobs:
needs: check_source
if: needs.check_source.outputs.run_tests == 'true'
env:
HOMEBREW_NO_ANALYTICS: 1
HOMEBREW_NO_AUTO_UPDATE: 1
HOMEBREW_NO_INSTALL_CLEANUP: 1
PYTHONSTRICTEXTENSIONBUILD: 1
steps:
- uses: actions/checkout@v3
- name: Prepare homebrew environment variables
- name: Install Homebrew dependencies
run: brew install pkg-config openssl@1.1 xz gdbm tcl-tk
- name: Prepare Homebrew environment variables
run: |
echo "LDFLAGS=-L$(brew --prefix tcl-tk)/lib" >> $GITHUB_ENV
echo "CFLAGS=-I$(brew --prefix gdbm)/include -I$(brew --prefix xz)/include" >> $GITHUB_ENV
echo "LDFLAGS=-L$(brew --prefix gdbm)/lib -I$(brew --prefix xz)/lib" >> $GITHUB_ENV
echo "PKG_CONFIG_PATH=$(brew --prefix openssl@1.1)/lib/pkgconfig:$(brew --prefix tcl-tk)/lib/pkgconfig" >> $GITHUB_ENV
- name: Configure CPython
run: ./configure --with-pydebug --prefix=/opt/python-dev
run: |
./configure \
--with-pydebug \
--prefix=/opt/python-dev \
--with-openssl="$(brew --prefix openssl@1.1)"
- name: Build CPython
run: make -j4
- name: Display build info
Expand Down
5 changes: 4 additions & 1 deletion Doc/library/importlib.resources.abc.rst
Expand Up @@ -89,9 +89,12 @@

.. class:: Traversable

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

For a representation of the object on the file-system, use
:meth:`importlib.resources.as_file`.

.. versionadded:: 3.9

.. deprecated-removed:: 3.12 3.14
Expand Down
5 changes: 3 additions & 2 deletions Doc/library/zipfile.rst
Expand Up @@ -55,8 +55,9 @@ The module defines the following items:
.. class:: Path
:noindex:

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

.. versionadded:: 3.8

Expand Down
28 changes: 21 additions & 7 deletions Include/cpython/code.h
Expand Up @@ -19,21 +19,35 @@ extern "C" {
typedef union {
uint16_t cache;
struct {
uint8_t opcode;
uint8_t oparg;
};
uint8_t code;
uint8_t arg;
} op;
} _Py_CODEUNIT;

#define _Py_OPCODE(word) ((word).opcode)
#define _Py_OPARG(word) ((word).oparg)

/* These macros only remain defined for compatibility. */
#define _Py_OPCODE(word) ((word).op.code)
#define _Py_OPARG(word) ((word).op.arg)

static inline _Py_CODEUNIT
_py_make_codeunit(uint8_t opcode, uint8_t oparg)
{
// No designated initialisers because of C++ compat
_Py_CODEUNIT word;
word.op.code = opcode;
word.op.arg = oparg;
return word;
}

static inline void
_py_set_opcode(_Py_CODEUNIT *word, uint8_t opcode)
{
word->opcode = opcode;
word->op.code = opcode;
}

#define _Py_SET_OPCODE(word, opcode) _py_set_opocde(&(word), opcode)
#define _Py_MAKE_CODEUNIT(opcode, oparg) _py_make_codeunit((opcode), (oparg))
#define _Py_SET_OPCODE(word, opcode) _py_set_opcode(&(word), (opcode))


typedef struct {
PyObject *_co_code;
Expand Down
91 changes: 90 additions & 1 deletion Lib/test/test_io.py
Expand Up @@ -1042,6 +1042,95 @@ def close(self):
support.gc_collect()
self.assertIsNone(wr(), wr)

@support.cpython_only
class TestIOCTypes(unittest.TestCase):
def setUp(self):
_io = import_helper.import_module("_io")
self.types = [
_io.BufferedRWPair,
_io.BufferedRandom,
_io.BufferedReader,
_io.BufferedWriter,
_io.BytesIO,
_io.FileIO,
_io.IncrementalNewlineDecoder,
_io.StringIO,
_io.TextIOWrapper,
_io._BufferedIOBase,
_io._BytesIOBuffer,
_io._IOBase,
_io._RawIOBase,
_io._TextIOBase,
]
if sys.platform == "win32":
self.types.append(_io._WindowsConsoleIO)
self._io = _io

def test_immutable_types(self):
for tp in self.types:
with self.subTest(tp=tp):
with self.assertRaisesRegex(TypeError, "immutable"):
tp.foo = "bar"

def test_class_hierarchy(self):
def check_subs(types, base):
for tp in types:
with self.subTest(tp=tp, base=base):
self.assertTrue(issubclass(tp, base))

def recursive_check(d):
for k, v in d.items():
if isinstance(v, dict):
recursive_check(v)
elif isinstance(v, set):
check_subs(v, k)
else:
self.fail("corrupt test dataset")

_io = self._io
hierarchy = {
_io._IOBase: {
_io._BufferedIOBase: {
_io.BufferedRWPair,
_io.BufferedRandom,
_io.BufferedReader,
_io.BufferedWriter,
_io.BytesIO,
},
_io._RawIOBase: {
_io.FileIO,
},
_io._TextIOBase: {
_io.StringIO,
_io.TextIOWrapper,
},
},
}
if sys.platform == "win32":
hierarchy[_io._IOBase][_io._RawIOBase].add(_io._WindowsConsoleIO)

recursive_check(hierarchy)

def test_subclassing(self):
_io = self._io
dataset = {k: True for k in self.types}
dataset[_io._BytesIOBuffer] = False

for tp, is_basetype in dataset.items():
with self.subTest(tp=tp, is_basetype=is_basetype):
name = f"{tp.__name__}_subclass"
bases = (tp,)
if is_basetype:
_ = type(name, bases, {})
else:
msg = "not an acceptable base type"
with self.assertRaisesRegex(TypeError, msg):
_ = type(name, bases, {})

def test_disallow_instantiation(self):
_io = self._io
support.check_disallow_instantiation(self, _io._BytesIOBuffer)

class PyIOTest(IOTest):
pass

Expand Down Expand Up @@ -4671,7 +4760,7 @@ def load_tests(loader, tests, pattern):
CIncrementalNewlineDecoderTest, PyIncrementalNewlineDecoderTest,
CTextIOWrapperTest, PyTextIOWrapperTest,
CMiscIOTest, PyMiscIOTest,
CSignalsTest, PySignalsTest,
CSignalsTest, PySignalsTest, TestIOCTypes,
)

# Put the namespaces of the IO module we are testing and some useful mock
Expand Down
62 changes: 62 additions & 0 deletions Lib/test/test_zipfile/test_core.py
Expand Up @@ -3010,5 +3010,67 @@ def test_cli_with_metadata_encoding_extract(self):
self.assertIn(name, listing)


class StripExtraTests(unittest.TestCase):
# Note: all of the "z" characters are technically invalid, but up
# to 3 bytes at the end of the extra will be passed through as they
# are too short to encode a valid extra.

ZIP64_EXTRA = 1

def test_no_data(self):
s = struct.Struct("<HH")
a = s.pack(self.ZIP64_EXTRA, 0)
b = s.pack(2, 0)
c = s.pack(3, 0)

self.assertEqual(b'', zipfile._strip_extra(a, (self.ZIP64_EXTRA,)))
self.assertEqual(b, zipfile._strip_extra(b, (self.ZIP64_EXTRA,)))
self.assertEqual(
b+b"z", zipfile._strip_extra(b+b"z", (self.ZIP64_EXTRA,)))

self.assertEqual(b+c, zipfile._strip_extra(a+b+c, (self.ZIP64_EXTRA,)))
self.assertEqual(b+c, zipfile._strip_extra(b+a+c, (self.ZIP64_EXTRA,)))
self.assertEqual(b+c, zipfile._strip_extra(b+c+a, (self.ZIP64_EXTRA,)))

def test_with_data(self):
s = struct.Struct("<HH")
a = s.pack(self.ZIP64_EXTRA, 1) + b"a"
b = s.pack(2, 2) + b"bb"
c = s.pack(3, 3) + b"ccc"

self.assertEqual(b"", zipfile._strip_extra(a, (self.ZIP64_EXTRA,)))
self.assertEqual(b, zipfile._strip_extra(b, (self.ZIP64_EXTRA,)))
self.assertEqual(
b+b"z", zipfile._strip_extra(b+b"z", (self.ZIP64_EXTRA,)))

self.assertEqual(b+c, zipfile._strip_extra(a+b+c, (self.ZIP64_EXTRA,)))
self.assertEqual(b+c, zipfile._strip_extra(b+a+c, (self.ZIP64_EXTRA,)))
self.assertEqual(b+c, zipfile._strip_extra(b+c+a, (self.ZIP64_EXTRA,)))

def test_multiples(self):
s = struct.Struct("<HH")
a = s.pack(self.ZIP64_EXTRA, 1) + b"a"
b = s.pack(2, 2) + b"bb"

self.assertEqual(b"", zipfile._strip_extra(a+a, (self.ZIP64_EXTRA,)))
self.assertEqual(b"", zipfile._strip_extra(a+a+a, (self.ZIP64_EXTRA,)))
self.assertEqual(
b"z", zipfile._strip_extra(a+a+b"z", (self.ZIP64_EXTRA,)))
self.assertEqual(
b+b"z", zipfile._strip_extra(a+a+b+b"z", (self.ZIP64_EXTRA,)))

self.assertEqual(b, zipfile._strip_extra(a+a+b, (self.ZIP64_EXTRA,)))
self.assertEqual(b, zipfile._strip_extra(a+b+a, (self.ZIP64_EXTRA,)))
self.assertEqual(b, zipfile._strip_extra(b+a+a, (self.ZIP64_EXTRA,)))

def test_too_short(self):
self.assertEqual(b"", zipfile._strip_extra(b"", (self.ZIP64_EXTRA,)))
self.assertEqual(b"z", zipfile._strip_extra(b"z", (self.ZIP64_EXTRA,)))
self.assertEqual(
b"zz", zipfile._strip_extra(b"zz", (self.ZIP64_EXTRA,)))
self.assertEqual(
b"zzz", zipfile._strip_extra(b"zzz", (self.ZIP64_EXTRA,)))


if __name__ == "__main__":
unittest.main()
2 changes: 2 additions & 0 deletions Lib/zipfile/__init__.py
Expand Up @@ -207,6 +207,8 @@ def _strip_extra(extra, xids):
i = j
if not modified:
return extra
if start != len(extra):
buffer.append(extra[start:])
return b''.join(buffer)

def _check_zipfile(fp):
Expand Down
@@ -0,0 +1 @@
Removes use of non-standard C++ extension in public header files.
@@ -0,0 +1,2 @@
Correctly preserve "extra" fields in ``zipfile`` regardless of their
ordering relative to a zip64 "extra."

0 comments on commit eab405a

Please sign in to comment.