gh-102500: Implement PEP 688 (#102521)

Co-authored-by: Kumar Aditya <59607654+kumaraditya303@users.noreply.github.com>
This commit is contained in:
Jelle Zijlstra 2023-05-04 07:59:46 -07:00 committed by GitHub
parent b17d32c114
commit 04f6733275
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
26 changed files with 640 additions and 15 deletions

View File

@ -593,6 +593,7 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) {
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(__await__)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(__await__));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(__bases__)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(__bases__));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(__bool__)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(__bool__));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(__buffer__));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(__build_class__)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(__build_class__));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(__builtins__)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(__builtins__));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(__bytes__)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(__bytes__));
@ -692,6 +693,7 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) {
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(__rdivmod__)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(__rdivmod__));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(__reduce__)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(__reduce__));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(__reduce_ex__)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(__reduce_ex__));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(__release_buffer__));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(__repr__)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(__repr__));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(__reversed__)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(__reversed__));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(__rfloordiv__)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(__rfloordiv__));
@ -1122,6 +1124,7 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) {
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(reducer_override)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(reducer_override));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(registry)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(registry));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(rel_tol)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(rel_tol));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(release));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(reload)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(reload));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(repl)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(repl));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(replace)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(replace));

View File

@ -81,6 +81,7 @@ struct _Py_global_strings {
STRUCT_FOR_ID(__await__) STRUCT_FOR_ID(__await__)
STRUCT_FOR_ID(__bases__) STRUCT_FOR_ID(__bases__)
STRUCT_FOR_ID(__bool__) STRUCT_FOR_ID(__bool__)
STRUCT_FOR_ID(__buffer__)
STRUCT_FOR_ID(__build_class__) STRUCT_FOR_ID(__build_class__)
STRUCT_FOR_ID(__builtins__) STRUCT_FOR_ID(__builtins__)
STRUCT_FOR_ID(__bytes__) STRUCT_FOR_ID(__bytes__)
@ -180,6 +181,7 @@ struct _Py_global_strings {
STRUCT_FOR_ID(__rdivmod__) STRUCT_FOR_ID(__rdivmod__)
STRUCT_FOR_ID(__reduce__) STRUCT_FOR_ID(__reduce__)
STRUCT_FOR_ID(__reduce_ex__) STRUCT_FOR_ID(__reduce_ex__)
STRUCT_FOR_ID(__release_buffer__)
STRUCT_FOR_ID(__repr__) STRUCT_FOR_ID(__repr__)
STRUCT_FOR_ID(__reversed__) STRUCT_FOR_ID(__reversed__)
STRUCT_FOR_ID(__rfloordiv__) STRUCT_FOR_ID(__rfloordiv__)
@ -610,6 +612,7 @@ struct _Py_global_strings {
STRUCT_FOR_ID(reducer_override) STRUCT_FOR_ID(reducer_override)
STRUCT_FOR_ID(registry) STRUCT_FOR_ID(registry)
STRUCT_FOR_ID(rel_tol) STRUCT_FOR_ID(rel_tol)
STRUCT_FOR_ID(release)
STRUCT_FOR_ID(reload) STRUCT_FOR_ID(reload)
STRUCT_FOR_ID(repl) STRUCT_FOR_ID(repl)
STRUCT_FOR_ID(replace) STRUCT_FOR_ID(replace)

View File

@ -0,0 +1,17 @@
#ifndef Py_INTERNAL_MEMORYOBJECT_H
#define Py_INTERNAL_MEMORYOBJECT_H
#ifdef __cplusplus
extern "C" {
#endif
#ifndef Py_BUILD_CORE
# error "this header requires Py_BUILD_CORE define"
#endif
PyObject *
PyMemoryView_FromObjectAndFlags(PyObject *v, int flags);
#ifdef __cplusplus
}
#endif
#endif /* !Py_INTERNAL_MEMORYOBJECT_H */

View File

@ -587,6 +587,7 @@ extern "C" {
INIT_ID(__await__), \ INIT_ID(__await__), \
INIT_ID(__bases__), \ INIT_ID(__bases__), \
INIT_ID(__bool__), \ INIT_ID(__bool__), \
INIT_ID(__buffer__), \
INIT_ID(__build_class__), \ INIT_ID(__build_class__), \
INIT_ID(__builtins__), \ INIT_ID(__builtins__), \
INIT_ID(__bytes__), \ INIT_ID(__bytes__), \
@ -686,6 +687,7 @@ extern "C" {
INIT_ID(__rdivmod__), \ INIT_ID(__rdivmod__), \
INIT_ID(__reduce__), \ INIT_ID(__reduce__), \
INIT_ID(__reduce_ex__), \ INIT_ID(__reduce_ex__), \
INIT_ID(__release_buffer__), \
INIT_ID(__repr__), \ INIT_ID(__repr__), \
INIT_ID(__reversed__), \ INIT_ID(__reversed__), \
INIT_ID(__rfloordiv__), \ INIT_ID(__rfloordiv__), \
@ -1116,6 +1118,7 @@ extern "C" {
INIT_ID(reducer_override), \ INIT_ID(reducer_override), \
INIT_ID(registry), \ INIT_ID(registry), \
INIT_ID(rel_tol), \ INIT_ID(rel_tol), \
INIT_ID(release), \
INIT_ID(reload), \ INIT_ID(reload), \
INIT_ID(repl), \ INIT_ID(repl), \
INIT_ID(replace), \ INIT_ID(replace), \

View File

@ -138,6 +138,8 @@ _Py_type_getattro(PyTypeObject *type, PyObject *name);
PyObject *_Py_slot_tp_getattro(PyObject *self, PyObject *name); PyObject *_Py_slot_tp_getattro(PyObject *self, PyObject *name);
PyObject *_Py_slot_tp_getattr_hook(PyObject *self, PyObject *name); PyObject *_Py_slot_tp_getattr_hook(PyObject *self, PyObject *name);
PyAPI_DATA(PyTypeObject) _PyBufferWrapper_Type;
PyObject * PyObject *
_PySuper_Lookup(PyTypeObject *su_type, PyObject *su_obj, PyObject *name, int *meth_found); _PySuper_Lookup(PyTypeObject *su_type, PyObject *su_obj, PyObject *name, int *meth_found);
PyObject * PyObject *

View File

@ -96,6 +96,9 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) {
string = &_Py_ID(__bool__); string = &_Py_ID(__bool__);
assert(_PyUnicode_CheckConsistency(string, 1)); assert(_PyUnicode_CheckConsistency(string, 1));
_PyUnicode_InternInPlace(interp, &string); _PyUnicode_InternInPlace(interp, &string);
string = &_Py_ID(__buffer__);
assert(_PyUnicode_CheckConsistency(string, 1));
_PyUnicode_InternInPlace(interp, &string);
string = &_Py_ID(__build_class__); string = &_Py_ID(__build_class__);
assert(_PyUnicode_CheckConsistency(string, 1)); assert(_PyUnicode_CheckConsistency(string, 1));
_PyUnicode_InternInPlace(interp, &string); _PyUnicode_InternInPlace(interp, &string);
@ -393,6 +396,9 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) {
string = &_Py_ID(__reduce_ex__); string = &_Py_ID(__reduce_ex__);
assert(_PyUnicode_CheckConsistency(string, 1)); assert(_PyUnicode_CheckConsistency(string, 1));
_PyUnicode_InternInPlace(interp, &string); _PyUnicode_InternInPlace(interp, &string);
string = &_Py_ID(__release_buffer__);
assert(_PyUnicode_CheckConsistency(string, 1));
_PyUnicode_InternInPlace(interp, &string);
string = &_Py_ID(__repr__); string = &_Py_ID(__repr__);
assert(_PyUnicode_CheckConsistency(string, 1)); assert(_PyUnicode_CheckConsistency(string, 1));
_PyUnicode_InternInPlace(interp, &string); _PyUnicode_InternInPlace(interp, &string);
@ -1683,6 +1689,9 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) {
string = &_Py_ID(rel_tol); string = &_Py_ID(rel_tol);
assert(_PyUnicode_CheckConsistency(string, 1)); assert(_PyUnicode_CheckConsistency(string, 1));
_PyUnicode_InternInPlace(interp, &string); _PyUnicode_InternInPlace(interp, &string);
string = &_Py_ID(release);
assert(_PyUnicode_CheckConsistency(string, 1));
_PyUnicode_InternInPlace(interp, &string);
string = &_Py_ID(reload); string = &_Py_ID(reload);
assert(_PyUnicode_CheckConsistency(string, 1)); assert(_PyUnicode_CheckConsistency(string, 1));
_PyUnicode_InternInPlace(interp, &string); _PyUnicode_InternInPlace(interp, &string);

View File

@ -104,7 +104,7 @@ PyAPI_FUNC(void) PyBuffer_Release(Py_buffer *view);
/* Maximum number of dimensions */ /* Maximum number of dimensions */
#define PyBUF_MAX_NDIM 64 #define PyBUF_MAX_NDIM 64
/* Flags for getting buffers */ /* Flags for getting buffers. Keep these in sync with inspect.BufferFlags. */
#define PyBUF_SIMPLE 0 #define PyBUF_SIMPLE 0
#define PyBUF_WRITABLE 0x0001 #define PyBUF_WRITABLE 0x0001

View File

@ -49,7 +49,7 @@ __all__ = ["Awaitable", "Coroutine",
"Mapping", "MutableMapping", "Mapping", "MutableMapping",
"MappingView", "KeysView", "ItemsView", "ValuesView", "MappingView", "KeysView", "ItemsView", "ValuesView",
"Sequence", "MutableSequence", "Sequence", "MutableSequence",
"ByteString", "ByteString", "Buffer",
] ]
# This module has been renamed from collections.abc to _collections_abc to # This module has been renamed from collections.abc to _collections_abc to
@ -439,6 +439,21 @@ class Collection(Sized, Iterable, Container):
return NotImplemented return NotImplemented
class Buffer(metaclass=ABCMeta):
__slots__ = ()
@abstractmethod
def __buffer__(self, flags: int, /) -> memoryview:
raise NotImplementedError
@classmethod
def __subclasshook__(cls, C):
if cls is Buffer:
return _check_methods(C, "__buffer__")
return NotImplemented
class _CallableGenericAlias(GenericAlias): class _CallableGenericAlias(GenericAlias):
""" Represent `Callable[argtypes, resulttype]`. """ Represent `Callable[argtypes, resulttype]`.

View File

@ -43,6 +43,7 @@ __all__ = [
"Attribute", "Attribute",
"BlockFinder", "BlockFinder",
"BoundArguments", "BoundArguments",
"BufferFlags",
"CORO_CLOSED", "CORO_CLOSED",
"CORO_CREATED", "CORO_CREATED",
"CORO_RUNNING", "CORO_RUNNING",
@ -3312,6 +3313,28 @@ def signature(obj, *, follow_wrapped=True, globals=None, locals=None, eval_str=F
globals=globals, locals=locals, eval_str=eval_str) globals=globals, locals=locals, eval_str=eval_str)
class BufferFlags(enum.IntFlag):
SIMPLE = 0x0
WRITABLE = 0x1
FORMAT = 0x4
ND = 0x8
STRIDES = 0x10 | ND
C_CONTIGUOUS = 0x20 | STRIDES
F_CONTIGUOUS = 0x40 | STRIDES
ANY_CONTIGUOUS = 0x80 | STRIDES
INDIRECT = 0x100 | STRIDES
CONTIG = ND | WRITABLE
CONTIG_RO = ND
STRIDED = STRIDES | WRITABLE
STRIDED_RO = STRIDES
RECORDS = STRIDES | WRITABLE | FORMAT
RECORDS_RO = STRIDES | FORMAT
FULL = INDIRECT | WRITABLE | FORMAT
FULL_RO = INDIRECT | FORMAT
READ = 0x100
WRITE = 0x200
def _main(): def _main():
""" Logic for inspecting an object given at command line """ """ Logic for inspecting an object given at command line """
import argparse import argparse

View File

@ -17,6 +17,7 @@ import contextlib
import unittest import unittest
from test import support from test import support
from test.support import os_helper from test.support import os_helper
import inspect
from itertools import permutations, product from itertools import permutations, product
from random import randrange, sample, choice from random import randrange, sample, choice
import warnings import warnings
@ -4438,5 +4439,146 @@ class TestBufferProtocol(unittest.TestCase):
struct.calcsize(format)) struct.calcsize(format))
class TestPythonBufferProtocol(unittest.TestCase):
def test_basic(self):
class MyBuffer:
def __buffer__(self, flags):
return memoryview(b"hello")
mv = memoryview(MyBuffer())
self.assertEqual(mv.tobytes(), b"hello")
self.assertEqual(bytes(MyBuffer()), b"hello")
def test_bad_buffer_method(self):
class MustReturnMV:
def __buffer__(self, flags):
return 42
self.assertRaises(TypeError, memoryview, MustReturnMV())
class NoBytesEither:
def __buffer__(self, flags):
return b"hello"
self.assertRaises(TypeError, memoryview, NoBytesEither())
class WrongArity:
def __buffer__(self):
return memoryview(b"hello")
self.assertRaises(TypeError, memoryview, WrongArity())
def test_release_buffer(self):
class WhatToRelease:
def __init__(self):
self.held = False
self.ba = bytearray(b"hello")
def __buffer__(self, flags):
if self.held:
raise TypeError("already held")
self.held = True
return memoryview(self.ba)
def __release_buffer__(self, buffer):
self.held = False
wr = WhatToRelease()
self.assertFalse(wr.held)
with memoryview(wr) as mv:
self.assertTrue(wr.held)
self.assertEqual(mv.tobytes(), b"hello")
self.assertFalse(wr.held)
def test_same_buffer_returned(self):
class WhatToRelease:
def __init__(self):
self.held = False
self.ba = bytearray(b"hello")
self.created_mv = None
def __buffer__(self, flags):
if self.held:
raise TypeError("already held")
self.held = True
self.created_mv = memoryview(self.ba)
return self.created_mv
def __release_buffer__(self, buffer):
assert buffer is self.created_mv
self.held = False
wr = WhatToRelease()
self.assertFalse(wr.held)
with memoryview(wr) as mv:
self.assertTrue(wr.held)
self.assertEqual(mv.tobytes(), b"hello")
self.assertFalse(wr.held)
def test_buffer_flags(self):
class PossiblyMutable:
def __init__(self, data, mutable) -> None:
self._data = bytearray(data)
self._mutable = mutable
def __buffer__(self, flags):
if flags & inspect.BufferFlags.WRITABLE:
if not self._mutable:
raise RuntimeError("not mutable")
return memoryview(self._data)
else:
return memoryview(bytes(self._data))
mutable = PossiblyMutable(b"hello", True)
immutable = PossiblyMutable(b"hello", False)
with memoryview._from_flags(mutable, inspect.BufferFlags.WRITABLE) as mv:
self.assertEqual(mv.tobytes(), b"hello")
mv[0] = ord(b'x')
self.assertEqual(mv.tobytes(), b"xello")
with memoryview._from_flags(mutable, inspect.BufferFlags.SIMPLE) as mv:
self.assertEqual(mv.tobytes(), b"xello")
with self.assertRaises(TypeError):
mv[0] = ord(b'h')
self.assertEqual(mv.tobytes(), b"xello")
with memoryview._from_flags(immutable, inspect.BufferFlags.SIMPLE) as mv:
self.assertEqual(mv.tobytes(), b"hello")
with self.assertRaises(TypeError):
mv[0] = ord(b'x')
self.assertEqual(mv.tobytes(), b"hello")
with self.assertRaises(RuntimeError):
memoryview._from_flags(immutable, inspect.BufferFlags.WRITABLE)
with memoryview(immutable) as mv:
self.assertEqual(mv.tobytes(), b"hello")
with self.assertRaises(TypeError):
mv[0] = ord(b'x')
self.assertEqual(mv.tobytes(), b"hello")
def test_call_builtins(self):
ba = bytearray(b"hello")
mv = ba.__buffer__(0)
self.assertEqual(mv.tobytes(), b"hello")
ba.__release_buffer__(mv)
with self.assertRaises(OverflowError):
ba.__buffer__(sys.maxsize + 1)
@unittest.skipIf(_testcapi is None, "requires _testcapi")
def test_c_buffer(self):
buf = _testcapi.testBuf()
self.assertEqual(buf.references, 0)
mv = buf.__buffer__(0)
self.assertIsInstance(mv, memoryview)
self.assertEqual(mv.tobytes(), b"test")
self.assertEqual(buf.references, 1)
buf.__release_buffer__(mv)
self.assertEqual(buf.references, 0)
with self.assertRaises(ValueError):
mv.tobytes()
# Calling it again doesn't cause issues
with self.assertRaises(ValueError):
buf.__release_buffer__(mv)
self.assertEqual(buf.references, 0)
if __name__ == "__main__": if __name__ == "__main__":
unittest.main() unittest.main()

View File

@ -25,7 +25,7 @@ from collections.abc import Sized, Container, Callable, Collection
from collections.abc import Set, MutableSet from collections.abc import Set, MutableSet
from collections.abc import Mapping, MutableMapping, KeysView, ItemsView, ValuesView from collections.abc import Mapping, MutableMapping, KeysView, ItemsView, ValuesView
from collections.abc import Sequence, MutableSequence from collections.abc import Sequence, MutableSequence
from collections.abc import ByteString from collections.abc import ByteString, Buffer
class TestUserObjects(unittest.TestCase): class TestUserObjects(unittest.TestCase):
@ -1949,6 +1949,15 @@ class TestCollectionABCs(ABCTestCase):
self.assertFalse(issubclass(memoryview, ByteString)) self.assertFalse(issubclass(memoryview, ByteString))
self.validate_abstract_methods(ByteString, '__getitem__', '__len__') self.validate_abstract_methods(ByteString, '__getitem__', '__len__')
def test_Buffer(self):
for sample in [bytes, bytearray, memoryview]:
self.assertIsInstance(sample(b"x"), Buffer)
self.assertTrue(issubclass(sample, Buffer))
for sample in [str, list, tuple]:
self.assertNotIsInstance(sample(), Buffer)
self.assertFalse(issubclass(sample, Buffer))
self.validate_abstract_methods(Buffer, '__buffer__')
def test_MutableSequence(self): def test_MutableSequence(self):
for sample in [tuple, str, bytes]: for sample in [tuple, str, bytes]:
self.assertNotIsInstance(sample(), MutableSequence) self.assertNotIsInstance(sample(), MutableSequence)

View File

@ -707,7 +707,7 @@ plain ol' Python and is guaranteed to be available.
>>> import builtins >>> import builtins
>>> tests = doctest.DocTestFinder().find(builtins) >>> tests = doctest.DocTestFinder().find(builtins)
>>> 830 < len(tests) < 850 # approximate number of objects with docstrings >>> 830 < len(tests) < 860 # approximate number of objects with docstrings
True True
>>> real_tests = [t for t in tests if len(t.examples) > 0] >>> real_tests = [t for t in tests if len(t.examples) > 0]
>>> len(real_tests) # objects that actually have doctests >>> len(real_tests) # objects that actually have doctests

View File

@ -0,0 +1,3 @@
Make the buffer protocol accessible in Python code using the new
``__buffer__`` and ``__release_buffer__`` magic methods. See :pep:`688` for
details. Patch by Jelle Zijlstra.

View File

@ -169,7 +169,7 @@
@MODULE__XXTESTFUZZ_TRUE@_xxtestfuzz _xxtestfuzz/_xxtestfuzz.c _xxtestfuzz/fuzzer.c @MODULE__XXTESTFUZZ_TRUE@_xxtestfuzz _xxtestfuzz/_xxtestfuzz.c _xxtestfuzz/fuzzer.c
@MODULE__TESTBUFFER_TRUE@_testbuffer _testbuffer.c @MODULE__TESTBUFFER_TRUE@_testbuffer _testbuffer.c
@MODULE__TESTINTERNALCAPI_TRUE@_testinternalcapi _testinternalcapi.c @MODULE__TESTINTERNALCAPI_TRUE@_testinternalcapi _testinternalcapi.c
@MODULE__TESTCAPI_TRUE@_testcapi _testcapimodule.c _testcapi/vectorcall.c _testcapi/vectorcall_limited.c _testcapi/heaptype.c _testcapi/unicode.c _testcapi/getargs.c _testcapi/pytime.c _testcapi/datetime.c _testcapi/docstring.c _testcapi/mem.c _testcapi/watchers.c _testcapi/long.c _testcapi/float.c _testcapi/structmember.c _testcapi/exceptions.c _testcapi/code.c _testcapi/pyos.c _testcapi/immortal.c _testcapi/heaptype_relative.c @MODULE__TESTCAPI_TRUE@_testcapi _testcapimodule.c _testcapi/vectorcall.c _testcapi/vectorcall_limited.c _testcapi/heaptype.c _testcapi/unicode.c _testcapi/getargs.c _testcapi/pytime.c _testcapi/datetime.c _testcapi/docstring.c _testcapi/mem.c _testcapi/watchers.c _testcapi/long.c _testcapi/float.c _testcapi/structmember.c _testcapi/exceptions.c _testcapi/code.c _testcapi/buffer.c _testcapi/pyos.c _testcapi/immortal.c _testcapi/heaptype_relative.c
@MODULE__TESTCLINIC_TRUE@_testclinic _testclinic.c @MODULE__TESTCLINIC_TRUE@_testclinic _testclinic.c
# Some testing modules MUST be built as shared libraries. # Some testing modules MUST be built as shared libraries.

102
Modules/_testcapi/buffer.c Normal file
View File

@ -0,0 +1,102 @@
/* Test PEP 688 - Buffers */
#include "parts.h"
#include "structmember.h" // PyMemberDef
#include <stddef.h> // offsetof
typedef struct {
PyObject_HEAD
PyObject *obj;
Py_ssize_t references;
} testBufObject;
static PyObject *
testbuf_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
PyObject *obj = PyBytes_FromString("test");
if (obj == NULL) {
return NULL;
}
testBufObject *self = (testBufObject *)type->tp_alloc(type, 0);
if (self == NULL) {
Py_DECREF(obj);
return NULL;
}
self->obj = obj;
self->references = 0;
return (PyObject *)self;
}
static int
testbuf_traverse(testBufObject *self, visitproc visit, void *arg)
{
Py_VISIT(self->obj);
return 0;
}
static int
testbuf_clear(testBufObject *self)
{
Py_CLEAR(self->obj);
return 0;
}
static void
testbuf_dealloc(testBufObject *self)
{
PyObject_GC_UnTrack(self);
Py_XDECREF(self->obj);
Py_TYPE(self)->tp_free((PyObject *) self);
}
static int
testbuf_getbuf(testBufObject *self, Py_buffer *view, int flags)
{
int buf = PyObject_GetBuffer(self->obj, view, flags);
Py_SETREF(view->obj, Py_NewRef(self));
self->references++;
return buf;
}
static void
testbuf_releasebuf(testBufObject *self, Py_buffer *view)
{
self->references--;
assert(self->references >= 0);
}
static PyBufferProcs testbuf_as_buffer = {
.bf_getbuffer = (getbufferproc) testbuf_getbuf,
.bf_releasebuffer = (releasebufferproc) testbuf_releasebuf,
};
static struct PyMemberDef testbuf_members[] = {
{"references", T_PYSSIZET, offsetof(testBufObject, references), READONLY},
{NULL},
};
static PyTypeObject testBufType = {
PyVarObject_HEAD_INIT(NULL, 0)
.tp_name = "testBufType",
.tp_basicsize = sizeof(testBufObject),
.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,
.tp_new = testbuf_new,
.tp_dealloc = (destructor) testbuf_dealloc,
.tp_traverse = (traverseproc) testbuf_traverse,
.tp_clear = (inquiry) testbuf_clear,
.tp_as_buffer = &testbuf_as_buffer,
.tp_members = testbuf_members
};
int
_PyTestCapi_Init_Buffer(PyObject *m) {
if (PyType_Ready(&testBufType) < 0) {
return -1;
}
if (PyModule_AddObjectRef(m, "testBuf", (PyObject *)&testBufType)) {
return -1;
}
return 0;
}

View File

@ -38,6 +38,7 @@ int _PyTestCapi_Init_Float(PyObject *module);
int _PyTestCapi_Init_Structmember(PyObject *module); int _PyTestCapi_Init_Structmember(PyObject *module);
int _PyTestCapi_Init_Exceptions(PyObject *module); int _PyTestCapi_Init_Exceptions(PyObject *module);
int _PyTestCapi_Init_Code(PyObject *module); int _PyTestCapi_Init_Code(PyObject *module);
int _PyTestCapi_Init_Buffer(PyObject *module);
int _PyTestCapi_Init_PyOS(PyObject *module); int _PyTestCapi_Init_PyOS(PyObject *module);
int _PyTestCapi_Init_Immortal(PyObject *module); int _PyTestCapi_Init_Immortal(PyObject *module);

View File

@ -3959,7 +3959,6 @@ static PyTypeObject MyList_Type = {
MyList_new, /* tp_new */ MyList_new, /* tp_new */
}; };
/* Test PEP 560 */ /* Test PEP 560 */
typedef struct { typedef struct {
@ -4310,6 +4309,9 @@ PyInit__testcapi(void)
if (_PyTestCapi_Init_Code(m) < 0) { if (_PyTestCapi_Init_Code(m) < 0) {
return NULL; return NULL;
} }
if (_PyTestCapi_Init_Buffer(m) < 0) {
return NULL;
}
if (_PyTestCapi_Init_PyOS(m) < 0) { if (_PyTestCapi_Init_PyOS(m) < 0) {
return NULL; return NULL;
} }

View File

@ -62,6 +62,66 @@ exit:
return return_value; return return_value;
} }
PyDoc_STRVAR(memoryview__from_flags__doc__,
"_from_flags($type, /, object, flags)\n"
"--\n"
"\n"
"Create a new memoryview object which references the given object.");
#define MEMORYVIEW__FROM_FLAGS_METHODDEF \
{"_from_flags", _PyCFunction_CAST(memoryview__from_flags), METH_FASTCALL|METH_KEYWORDS|METH_CLASS, memoryview__from_flags__doc__},
static PyObject *
memoryview__from_flags_impl(PyTypeObject *type, PyObject *object, int flags);
static PyObject *
memoryview__from_flags(PyTypeObject *type, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
{
PyObject *return_value = NULL;
#if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
#define NUM_KEYWORDS 2
static struct {
PyGC_Head _this_is_not_used;
PyObject_VAR_HEAD
PyObject *ob_item[NUM_KEYWORDS];
} _kwtuple = {
.ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS)
.ob_item = { &_Py_ID(object), &_Py_ID(flags), },
};
#undef NUM_KEYWORDS
#define KWTUPLE (&_kwtuple.ob_base.ob_base)
#else // !Py_BUILD_CORE
# define KWTUPLE NULL
#endif // !Py_BUILD_CORE
static const char * const _keywords[] = {"object", "flags", NULL};
static _PyArg_Parser _parser = {
.keywords = _keywords,
.fname = "_from_flags",
.kwtuple = KWTUPLE,
};
#undef KWTUPLE
PyObject *argsbuf[2];
PyObject *object;
int flags;
args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 2, 2, 0, argsbuf);
if (!args) {
goto exit;
}
object = args[0];
flags = _PyLong_AsInt(args[1]);
if (flags == -1 && PyErr_Occurred()) {
goto exit;
}
return_value = memoryview__from_flags_impl(type, object, flags);
exit:
return return_value;
}
PyDoc_STRVAR(memoryview_release__doc__, PyDoc_STRVAR(memoryview_release__doc__,
"release($self, /)\n" "release($self, /)\n"
"--\n" "--\n"
@ -356,4 +416,4 @@ skip_optional_pos:
exit: exit:
return return_value; return return_value;
} }
/*[clinic end generated code: output=a832f2fc44e4794c input=a9049054013a1b77]*/ /*[clinic end generated code: output=01613814112cedd7 input=a9049054013a1b77]*/

View File

@ -85,7 +85,7 @@ mbuf_alloc(void)
} }
static PyObject * static PyObject *
_PyManagedBuffer_FromObject(PyObject *base) _PyManagedBuffer_FromObject(PyObject *base, int flags)
{ {
_PyManagedBufferObject *mbuf; _PyManagedBufferObject *mbuf;
@ -93,7 +93,7 @@ _PyManagedBuffer_FromObject(PyObject *base)
if (mbuf == NULL) if (mbuf == NULL)
return NULL; return NULL;
if (PyObject_GetBuffer(base, &mbuf->master, PyBUF_FULL_RO) < 0) { if (PyObject_GetBuffer(base, &mbuf->master, flags) < 0) {
mbuf->master.obj = NULL; mbuf->master.obj = NULL;
Py_DECREF(mbuf); Py_DECREF(mbuf);
return NULL; return NULL;
@ -777,11 +777,12 @@ PyMemoryView_FromBuffer(const Py_buffer *info)
return mv; return mv;
} }
/* Create a memoryview from an object that implements the buffer protocol. /* Create a memoryview from an object that implements the buffer protocol,
using the given flags.
If the object is a memoryview, the new memoryview must be registered If the object is a memoryview, the new memoryview must be registered
with the same managed buffer. Otherwise, a new managed buffer is created. */ with the same managed buffer. Otherwise, a new managed buffer is created. */
PyObject * PyObject *
PyMemoryView_FromObject(PyObject *v) PyMemoryView_FromObjectAndFlags(PyObject *v, int flags)
{ {
_PyManagedBufferObject *mbuf; _PyManagedBufferObject *mbuf;
@ -792,7 +793,7 @@ PyMemoryView_FromObject(PyObject *v)
} }
else if (PyObject_CheckBuffer(v)) { else if (PyObject_CheckBuffer(v)) {
PyObject *ret; PyObject *ret;
mbuf = (_PyManagedBufferObject *)_PyManagedBuffer_FromObject(v); mbuf = (_PyManagedBufferObject *)_PyManagedBuffer_FromObject(v, flags);
if (mbuf == NULL) if (mbuf == NULL)
return NULL; return NULL;
ret = mbuf_add_view(mbuf, NULL); ret = mbuf_add_view(mbuf, NULL);
@ -805,6 +806,14 @@ PyMemoryView_FromObject(PyObject *v)
Py_TYPE(v)->tp_name); Py_TYPE(v)->tp_name);
return NULL; return NULL;
} }
/* Create a memoryview from an object that implements the buffer protocol.
If the object is a memoryview, the new memoryview must be registered
with the same managed buffer. Otherwise, a new managed buffer is created. */
PyObject *
PyMemoryView_FromObject(PyObject *v)
{
return PyMemoryView_FromObjectAndFlags(v, PyBUF_FULL_RO);
}
/* Copy the format string from a base object that might vanish. */ /* Copy the format string from a base object that might vanish. */
static int static int
@ -851,7 +860,7 @@ memory_from_contiguous_copy(const Py_buffer *src, char order)
if (bytes == NULL) if (bytes == NULL)
return NULL; return NULL;
mbuf = (_PyManagedBufferObject *)_PyManagedBuffer_FromObject(bytes); mbuf = (_PyManagedBufferObject *)_PyManagedBuffer_FromObject(bytes, PyBUF_FULL_RO);
Py_DECREF(bytes); Py_DECREF(bytes);
if (mbuf == NULL) if (mbuf == NULL)
return NULL; return NULL;
@ -968,6 +977,24 @@ memoryview_impl(PyTypeObject *type, PyObject *object)
} }
/*[clinic input]
@classmethod
memoryview._from_flags
object: object
flags: int
Create a new memoryview object which references the given object.
[clinic start generated code]*/
static PyObject *
memoryview__from_flags_impl(PyTypeObject *type, PyObject *object, int flags)
/*[clinic end generated code: output=bf71f9906c266ee2 input=f5f82fd0e744356b]*/
{
return PyMemoryView_FromObjectAndFlags(object, flags);
}
/****************************************************************************/ /****************************************************************************/
/* Previously in abstract.c */ /* Previously in abstract.c */
/****************************************************************************/ /****************************************************************************/
@ -3184,6 +3211,7 @@ static PyMethodDef memory_methods[] = {
MEMORYVIEW_TOLIST_METHODDEF MEMORYVIEW_TOLIST_METHODDEF
MEMORYVIEW_CAST_METHODDEF MEMORYVIEW_CAST_METHODDEF
MEMORYVIEW_TOREADONLY_METHODDEF MEMORYVIEW_TOREADONLY_METHODDEF
MEMORYVIEW__FROM_FLAGS_METHODDEF
{"__enter__", memory_enter, METH_NOARGS, NULL}, {"__enter__", memory_enter, METH_NOARGS, NULL},
{"__exit__", memory_exit, METH_VARARGS, NULL}, {"__exit__", memory_exit, METH_VARARGS, NULL},
{NULL, NULL} {NULL, NULL}

View File

@ -14,6 +14,7 @@
#include "pycore_pymem.h" // _PyMem_IsPtrFreed() #include "pycore_pymem.h" // _PyMem_IsPtrFreed()
#include "pycore_pystate.h" // _PyThreadState_GET() #include "pycore_pystate.h" // _PyThreadState_GET()
#include "pycore_symtable.h" // PySTEntry_Type #include "pycore_symtable.h" // PySTEntry_Type
#include "pycore_typeobject.h" // _PyBufferWrapper_Type
#include "pycore_unionobject.h" // _PyUnion_Type #include "pycore_unionobject.h" // _PyUnion_Type
#include "pycore_interpreteridobject.h" // _PyInterpreterID_Type #include "pycore_interpreteridobject.h" // _PyInterpreterID_Type
@ -2084,6 +2085,7 @@ static PyTypeObject* static_types[] = {
&_PyAsyncGenASend_Type, &_PyAsyncGenASend_Type,
&_PyAsyncGenAThrow_Type, &_PyAsyncGenAThrow_Type,
&_PyAsyncGenWrappedValue_Type, &_PyAsyncGenWrappedValue_Type,
&_PyBufferWrapper_Type,
&_PyContextTokenMissing_Type, &_PyContextTokenMissing_Type,
&_PyCoroWrapper_Type, &_PyCoroWrapper_Type,
&_Py_GenericAliasIterType, &_Py_GenericAliasIterType,

View File

@ -6,6 +6,7 @@
#include "pycore_symtable.h" // _Py_Mangle() #include "pycore_symtable.h" // _Py_Mangle()
#include "pycore_dict.h" // _PyDict_KeysSize() #include "pycore_dict.h" // _PyDict_KeysSize()
#include "pycore_initconfig.h" // _PyStatus_OK() #include "pycore_initconfig.h" // _PyStatus_OK()
#include "pycore_memoryobject.h" // PyMemoryView_FromObjectAndFlags()
#include "pycore_moduleobject.h" // _PyModule_GetDef() #include "pycore_moduleobject.h" // _PyModule_GetDef()
#include "pycore_object.h" // _PyType_HasFeature() #include "pycore_object.h" // _PyType_HasFeature()
#include "pycore_long.h" // _PyLong_IsNegative() #include "pycore_long.h" // _PyLong_IsNegative()
@ -8059,6 +8060,58 @@ wrap_descr_delete(PyObject *self, PyObject *args, void *wrapped)
Py_RETURN_NONE; Py_RETURN_NONE;
} }
static PyObject *
wrap_buffer(PyObject *self, PyObject *args, void *wrapped)
{
PyObject *arg = NULL;
if (!PyArg_UnpackTuple(args, "", 1, 1, &arg)) {
return NULL;
}
Py_ssize_t flags = PyNumber_AsSsize_t(arg, PyExc_OverflowError);
if (flags == -1 && PyErr_Occurred()) {
return NULL;
}
if (flags > INT_MAX) {
PyErr_SetString(PyExc_OverflowError,
"buffer flags too large");
return NULL;
}
return PyMemoryView_FromObjectAndFlags(self, Py_SAFE_DOWNCAST(flags, Py_ssize_t, int));
}
static PyObject *
wrap_releasebuffer(PyObject *self, PyObject *args, void *wrapped)
{
PyObject *arg = NULL;
if (!PyArg_UnpackTuple(args, "", 1, 1, &arg)) {
return NULL;
}
if (!PyMemoryView_Check(arg)) {
PyErr_SetString(PyExc_TypeError,
"expected a memoryview object");
return NULL;
}
PyMemoryViewObject *mview = (PyMemoryViewObject *)arg;
if (mview->view.obj != self) {
PyErr_SetString(PyExc_ValueError,
"memoryview's buffer is not this object");
return NULL;
}
if (mview->flags & _Py_MEMORYVIEW_RELEASED) {
PyErr_SetString(PyExc_ValueError,
"memoryview's buffer has already been released");
return NULL;
}
PyObject *res = PyObject_CallMethodNoArgs((PyObject *)mview, &_Py_ID(release));
if (res == NULL) {
return NULL;
}
Py_DECREF(res);
Py_RETURN_NONE;
}
static PyObject * static PyObject *
wrap_init(PyObject *self, PyObject *args, void *wrapped, PyObject *kwds) wrap_init(PyObject *self, PyObject *args, void *wrapped, PyObject *kwds)
{ {
@ -8895,6 +8948,132 @@ slot_tp_finalize(PyObject *self)
PyErr_SetRaisedException(exc); PyErr_SetRaisedException(exc);
} }
typedef struct _PyBufferWrapper {
PyObject_HEAD
PyObject *mv;
PyObject *obj;
} PyBufferWrapper;
static int
bufferwrapper_traverse(PyBufferWrapper *self, visitproc visit, void *arg)
{
Py_VISIT(self->mv);
Py_VISIT(self->obj);
return 0;
}
static void
bufferwrapper_dealloc(PyObject *self)
{
PyBufferWrapper *bw = (PyBufferWrapper *)self;
_PyObject_GC_UNTRACK(self);
Py_XDECREF(bw->mv);
Py_XDECREF(bw->obj);
Py_TYPE(self)->tp_free(self);
}
static void
bufferwrapper_releasebuf(PyObject *self, Py_buffer *view)
{
PyBufferWrapper *bw = (PyBufferWrapper *)self;
assert(PyMemoryView_Check(bw->mv));
Py_TYPE(bw->mv)->tp_as_buffer->bf_releasebuffer(bw->mv, view);
if (Py_TYPE(bw->obj)->tp_as_buffer != NULL
&& Py_TYPE(bw->obj)->tp_as_buffer->bf_releasebuffer != NULL) {
Py_TYPE(bw->obj)->tp_as_buffer->bf_releasebuffer(bw->obj, view);
}
}
static PyBufferProcs bufferwrapper_as_buffer = {
.bf_releasebuffer = bufferwrapper_releasebuf,
};
PyTypeObject _PyBufferWrapper_Type = {
PyVarObject_HEAD_INIT(&PyType_Type, 0)
.tp_name = "_buffer_wrapper",
.tp_basicsize = sizeof(PyBufferWrapper),
.tp_alloc = PyType_GenericAlloc,
.tp_free = PyObject_GC_Del,
.tp_traverse = (traverseproc)bufferwrapper_traverse,
.tp_dealloc = bufferwrapper_dealloc,
.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,
.tp_as_buffer = &bufferwrapper_as_buffer,
};
static int
slot_bf_getbuffer(PyObject *self, Py_buffer *buffer, int flags)
{
PyObject *flags_obj = PyLong_FromLong(flags);
if (flags_obj == NULL) {
return -1;
}
PyBufferWrapper *wrapper = NULL;
PyObject *stack[2] = {self, flags_obj};
PyObject *ret = vectorcall_method(&_Py_ID(__buffer__), stack, 2);
if (ret == NULL) {
goto fail;
}
if (!PyMemoryView_Check(ret)) {
PyErr_Format(PyExc_TypeError,
"__buffer__ returned non-memoryview object");
goto fail;
}
if (PyObject_GetBuffer(ret, buffer, flags) < 0) {
goto fail;
}
assert(buffer->obj == ret);
wrapper = PyObject_GC_New(PyBufferWrapper, &_PyBufferWrapper_Type);
if (wrapper == NULL) {
goto fail;
}
wrapper->mv = ret;
wrapper->obj = Py_NewRef(self);
_PyObject_GC_TRACK(wrapper);
buffer->obj = (PyObject *)wrapper;
Py_DECREF(ret);
Py_DECREF(flags_obj);
return 0;
fail:
Py_XDECREF(wrapper);
Py_XDECREF(ret);
Py_DECREF(flags_obj);
return -1;
}
static void
slot_bf_releasebuffer(PyObject *self, Py_buffer *buffer)
{
PyObject *mv;
if (Py_TYPE(buffer->obj) == &_PyBufferWrapper_Type) {
// Make sure we pass the same memoryview to
// __release_buffer__() that __buffer__() returned.
mv = Py_NewRef(((PyBufferWrapper *)buffer->obj)->mv);
}
else {
mv = PyMemoryView_FromBuffer(buffer);
if (mv == NULL) {
PyErr_WriteUnraisable(self);
return;
}
}
PyObject *stack[2] = {self, mv};
PyObject *ret = vectorcall_method(&_Py_ID(__release_buffer__), stack, 2);
Py_DECREF(mv);
if (ret == NULL) {
PyErr_WriteUnraisable(self);
}
else {
Py_DECREF(ret);
}
}
static PyObject * static PyObject *
slot_am_await(PyObject *self) slot_am_await(PyObject *self)
{ {
@ -8962,6 +9141,7 @@ an all-zero entry.
#undef TPSLOT #undef TPSLOT
#undef FLSLOT #undef FLSLOT
#undef BUFSLOT
#undef AMSLOT #undef AMSLOT
#undef ETSLOT #undef ETSLOT
#undef SQSLOT #undef SQSLOT
@ -8981,6 +9161,8 @@ an all-zero entry.
#define ETSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC) \ #define ETSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC) \
{#NAME, offsetof(PyHeapTypeObject, SLOT), (void *)(FUNCTION), WRAPPER, \ {#NAME, offsetof(PyHeapTypeObject, SLOT), (void *)(FUNCTION), WRAPPER, \
PyDoc_STR(DOC), .name_strobj = &_Py_ID(NAME) } PyDoc_STR(DOC), .name_strobj = &_Py_ID(NAME) }
#define BUFSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC) \
ETSLOT(NAME, as_buffer.SLOT, FUNCTION, WRAPPER, DOC)
#define AMSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC) \ #define AMSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC) \
ETSLOT(NAME, as_async.SLOT, FUNCTION, WRAPPER, DOC) ETSLOT(NAME, as_async.SLOT, FUNCTION, WRAPPER, DOC)
#define SQSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC) \ #define SQSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC) \
@ -9062,6 +9244,13 @@ static pytype_slotdef slotdefs[] = {
"Create and return new object. See help(type) for accurate signature."), "Create and return new object. See help(type) for accurate signature."),
TPSLOT(__del__, tp_finalize, slot_tp_finalize, (wrapperfunc)wrap_del, ""), TPSLOT(__del__, tp_finalize, slot_tp_finalize, (wrapperfunc)wrap_del, ""),
BUFSLOT(__buffer__, bf_getbuffer, slot_bf_getbuffer, wrap_buffer,
"__buffer__($self, flags, /)\n--\n\n"
"Return a buffer object that exposes the underlying memory of the object."),
BUFSLOT(__release_buffer__, bf_releasebuffer, slot_bf_releasebuffer, wrap_releasebuffer,
"__release_buffer__($self, /)\n--\n\n"
"Release the buffer object that exposes the underlying memory of the object."),
AMSLOT(__await__, am_await, slot_am_await, wrap_unaryfunc, AMSLOT(__await__, am_await, slot_am_await, wrap_unaryfunc,
"__await__($self, /)\n--\n\nReturn an iterator to be used in await expression."), "__await__($self, /)\n--\n\nReturn an iterator to be used in await expression."),
AMSLOT(__aiter__, am_aiter, slot_am_aiter, wrap_unaryfunc, AMSLOT(__aiter__, am_aiter, slot_am_aiter, wrap_unaryfunc,
@ -9208,8 +9397,12 @@ slotptr(PyTypeObject *type, int ioffset)
/* Note: this depends on the order of the members of PyHeapTypeObject! */ /* Note: this depends on the order of the members of PyHeapTypeObject! */
assert(offset >= 0); assert(offset >= 0);
assert((size_t)offset < offsetof(PyHeapTypeObject, as_buffer)); assert((size_t)offset < offsetof(PyHeapTypeObject, ht_name));
if ((size_t)offset >= offsetof(PyHeapTypeObject, as_sequence)) { if ((size_t)offset >= offsetof(PyHeapTypeObject, as_buffer)) {
ptr = (char *)type->tp_as_buffer;
offset -= offsetof(PyHeapTypeObject, as_buffer);
}
else if ((size_t)offset >= offsetof(PyHeapTypeObject, as_sequence)) {
ptr = (char *)type->tp_as_sequence; ptr = (char *)type->tp_as_sequence;
offset -= offsetof(PyHeapTypeObject, as_sequence); offset -= offsetof(PyHeapTypeObject, as_sequence);
} }

View File

@ -110,6 +110,7 @@
<ClCompile Include="..\Modules\_testcapi\structmember.c" /> <ClCompile Include="..\Modules\_testcapi\structmember.c" />
<ClCompile Include="..\Modules\_testcapi\exceptions.c" /> <ClCompile Include="..\Modules\_testcapi\exceptions.c" />
<ClCompile Include="..\Modules\_testcapi\code.c" /> <ClCompile Include="..\Modules\_testcapi\code.c" />
<ClCompile Include="..\Modules\_testcapi\buffer.c" />
<ClCompile Include="..\Modules\_testcapi\pyos.c" /> <ClCompile Include="..\Modules\_testcapi\pyos.c" />
<ClCompile Include="..\Modules\_testcapi\immortal.c" /> <ClCompile Include="..\Modules\_testcapi\immortal.c" />
</ItemGroup> </ItemGroup>

View File

@ -60,6 +60,9 @@
<ClCompile Include="..\Modules\_testcapi\code.c"> <ClCompile Include="..\Modules\_testcapi\code.c">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\Modules\_testcapi\buffer.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\Modules\_testcapi\pyos.c"> <ClCompile Include="..\Modules\_testcapi\pyos.c">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>

View File

@ -121,6 +121,8 @@ IDENTIFIERS = [
'__xor__', '__xor__',
'__divmod__', '__divmod__',
'__rdivmod__', '__rdivmod__',
'__buffer__',
'__release_buffer__',
] ]
NON_GENERATED_IMMORTAL_OBJECTS = [ NON_GENERATED_IMMORTAL_OBJECTS = [

View File

@ -86,6 +86,7 @@ Objects/sliceobject.c - PyEllipsis_Type -
Objects/sliceobject.c - PySlice_Type - Objects/sliceobject.c - PySlice_Type -
Objects/tupleobject.c - PyTupleIter_Type - Objects/tupleobject.c - PyTupleIter_Type -
Objects/tupleobject.c - PyTuple_Type - Objects/tupleobject.c - PyTuple_Type -
Objects/typeobject.c - _PyBufferWrapper_Type -
Objects/typeobject.c - PyBaseObject_Type - Objects/typeobject.c - PyBaseObject_Type -
Objects/typeobject.c - PySuper_Type - Objects/typeobject.c - PySuper_Type -
Objects/typeobject.c - PyType_Type - Objects/typeobject.c - PyType_Type -

Can't render this file because it has a wrong number of fields in line 4.

View File

@ -404,6 +404,7 @@ Modules/_testbuffer.c ndarray_memoryview_from_buffer strides -
Modules/_testbuffer.c ndarray_memoryview_from_buffer suboffsets - Modules/_testbuffer.c ndarray_memoryview_from_buffer suboffsets -
Modules/_testbuffer.c ndarray_push kwlist - Modules/_testbuffer.c ndarray_push kwlist -
Modules/_testbuffer.c staticarray_init kwlist - Modules/_testbuffer.c staticarray_init kwlist -
Modules/_testcapi/buffer.c - testBufType -
Modules/_testcapi/code.c get_code_extra_index key - Modules/_testcapi/code.c get_code_extra_index key -
Modules/_testcapi/datetime.c - test_run_counter - Modules/_testcapi/datetime.c - test_run_counter -
Modules/_testcapi/exceptions.c - PyRecursingInfinitelyError_Type - Modules/_testcapi/exceptions.c - PyRecursingInfinitelyError_Type -

Can't render this file because it has a wrong number of fields in line 4.