Skip to content

Commit 1084787

Browse files
committed
Merge branch 'main' into writer_canary
2 parents 19fdcb4 + bab97c5 commit 1084787

6 files changed

Lines changed: 68 additions & 68 deletions

File tree

‎Doc/c-api/bytes.rst‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -429,7 +429,7 @@ Low-level API
429429
On success, return ``0``.
430430
On error, set an exception and return ``-1``.
431431
432-
*size* can be negative to shrink the writer.
432+
*grow* can be negative to shrink the writer.
433433
434434
.. c:function:: void* PyBytesWriter_GrowAndUpdatePointer(PyBytesWriter *writer, Py_ssize_t size, void *buf)
435435

‎Lib/test/test_bytes.py‎

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1130,13 +1130,14 @@ def test_translate(self):
11301130
self.assertRaises(ValueError, b.translate, bytes(range(255)))
11311131

11321132
c = b.translate(rosetta, b'hello')
1133-
self.assertEqual(b, b'hello')
1134-
self.assertIsInstance(c, self.type2test)
1133+
self.assertEqual(c, b'')
1134+
self.assertEqual(type(c), self.type2test)
11351135

11361136
c = b.translate(rosetta)
11371137
d = b.translate(rosetta, b'')
1138-
self.assertEqual(c, d)
11391138
self.assertEqual(c, b'helle')
1139+
self.assertEqual(type(c), self.type2test)
1140+
self.assertEqual(d, b'helle')
11401141

11411142
c = b.translate(rosetta, b'l')
11421143
self.assertEqual(c, b'hee')

‎Lib/test/test_capi/test_bytes.py‎

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -465,6 +465,24 @@ def test_grow(self):
465465
writer.grow(0) # noop
466466
self.assertEqual(writer.finish(), b'number=123')
467467

468+
for size in (self.SMALL_BUFFER, self.LARGE_BUFFER):
469+
with self.subTest(size=size):
470+
# Truncate the last byte
471+
data = b'x' * size
472+
writer = self.create_writer(size)
473+
writer.write(0, data)
474+
self.assertEqual(writer.get_data(), data)
475+
writer.grow(-1)
476+
self.assertEqual(writer.get_data(), data[:-1])
477+
self.assertEqual(writer.finish(), data[:-1])
478+
479+
# Make the buffer empty
480+
writer = self.create_writer(size)
481+
writer.write(0, data)
482+
writer.grow(-size)
483+
self.assertEqual(writer.get_data(), b'')
484+
self.assertEqual(writer.finish(), b'')
485+
468486
# Switch from small buffer to large buffer
469487
writer = self.create_writer()
470488
small, large = self.SMALL_BUFFER, self.LARGE_BUFFER
@@ -480,8 +498,8 @@ def test_grow(self):
480498
with self.subTest(size=size):
481499
writer = self.create_writer()
482500
writer.write_bytes(b'x' * size, -1)
483-
with self.assertRaisesRegex(ValueError, 'size must be >= 0'):
484-
writer.grow(-1)
501+
with self.assertRaisesRegex(ValueError, 'invalid size'):
502+
writer.grow(-size - 1)
485503
with self.assertRaises(MemoryError):
486504
writer.grow(_testcapi.PY_SSIZE_T_MAX)
487505
self.assertEqual(writer.finish(), b'x' * size)
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
Remove the accidental acceptance of :class:`bytes` in the C implementation of
2+
:mod:`xml.etree.ElementTree`, a leftover of the Python 2 to Python 3 migration,
3+
for paths of :meth:`~xml.etree.ElementTree.Element.find`
4+
and similar methods, for the tag of :meth:`~xml.etree.ElementTree.Element.iter`,
5+
and for the names of events of :class:`~xml.etree.ElementTree.XMLPullParser`
6+
and :func:`~xml.etree.ElementTree.iterparse`. It now raises the same
7+
exceptions as the Python implementation.

‎Modules/_elementtree.c‎

Lines changed: 6 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1230,24 +1230,6 @@ checkpath(PyObject* tag)
12301230
}
12311231
return 0;
12321232
}
1233-
if (PyBytes_Check(tag)) {
1234-
const char *p = PyBytes_AS_STRING(tag);
1235-
const Py_ssize_t len = PyBytes_GET_SIZE(tag);
1236-
if (len >= 3 && p[0] == '{' && (
1237-
p[1] == '}' || (p[1] == '*' && p[2] == '}'))) {
1238-
/* wildcard: '{}tag' or '{*}tag' */
1239-
return 1;
1240-
}
1241-
for (i = 0; i < len; i++) {
1242-
if (p[i] == '{')
1243-
check = 0;
1244-
else if (p[i] == '}')
1245-
check = 1;
1246-
else if (check && PATHCHAR(p[i]))
1247-
return 1;
1248-
}
1249-
return 0;
1250-
}
12511233

12521234
return 1; /* unknown type; might be path expression */
12531235
}
@@ -1552,10 +1534,6 @@ _elementtree_Element_iter_impl(ElementObject *self, PyTypeObject *cls,
15521534
if (PyUnicode_GET_LENGTH(tag) == 1 && PyUnicode_READ_CHAR(tag, 0) == '*')
15531535
tag = Py_None;
15541536
}
1555-
else if (PyBytes_Check(tag)) {
1556-
if (PyBytes_GET_SIZE(tag) == 1 && *PyBytes_AS_STRING(tag) == '*')
1557-
tag = Py_None;
1558-
}
15591537

15601538
elementtreestate *st = get_elementtree_state_by_cls(cls);
15611539
return create_elementiter(st, self, tag, 0);
@@ -2935,17 +2913,7 @@ treebuilder_handle_data(TreeBuilderObject* self, PyObject* data)
29352913
self->data = Py_NewRef(data);
29362914
} else {
29372915
/* more than one item; use a list to collect items */
2938-
if (PyBytes_CheckExact(self->data)
2939-
&& _PyObject_IsUniquelyReferenced(self->data)
2940-
&& PyBytes_CheckExact(data) && PyBytes_GET_SIZE(data) == 1) {
2941-
/* XXX this code path unused in Python 3? */
2942-
/* expat often generates single character data sections; handle
2943-
the most common case by resizing the existing string... */
2944-
Py_ssize_t size = PyBytes_GET_SIZE(self->data);
2945-
if (_PyBytes_Resize(&self->data, size + 1) < 0)
2946-
return NULL;
2947-
PyBytes_AS_STRING(self->data)[size] = PyBytes_AS_STRING(data)[0];
2948-
} else if (PyList_CheckExact(self->data)) {
2916+
if (PyList_CheckExact(self->data)) {
29492917
if (PyList_Append(self->data, data) < 0)
29502918
return NULL;
29512919
} else {
@@ -4363,18 +4331,14 @@ _elementtree_XMLParser__setevents_impl(XMLParserObject *self,
43634331

43644332
for (i = 0; i < PySequence_Fast_GET_SIZE(events_seq); ++i) {
43654333
PyObject *event_name_obj = PySequence_Fast_GET_ITEM(events_seq, i);
4366-
const char *event_name = NULL;
4367-
if (PyUnicode_Check(event_name_obj)) {
4368-
event_name = PyUnicode_AsUTF8(event_name_obj);
4369-
} else if (PyBytes_Check(event_name_obj)) {
4370-
event_name = PyBytes_AS_STRING(event_name_obj);
4334+
if (!PyUnicode_Check(event_name_obj)) {
4335+
goto unknown_event;
43714336
}
4337+
const char *event_name = PyUnicode_AsUTF8(event_name_obj);
43724338
if (event_name == NULL) {
43734339
Py_DECREF(events_seq);
4374-
PyErr_Format(PyExc_ValueError, "invalid events sequence");
43754340
return NULL;
43764341
}
4377-
43784342
if (strcmp(event_name, "start") == 0) {
43794343
Py_XSETREF(target->start_event_obj, Py_NewRef(event_name_obj));
43804344
} else if (strcmp(event_name, "end") == 0) {
@@ -4406,7 +4370,8 @@ _elementtree_XMLParser__setevents_impl(XMLParserObject *self,
44064370
(XML_ProcessingInstructionHandler) expat_pi_handler
44074371
);
44084372
} else {
4409-
PyErr_Format(PyExc_ValueError, "unknown event '%s'", event_name);
4373+
unknown_event:
4374+
PyErr_Format(PyExc_ValueError, "unknown event %R", event_name_obj);
44104375
Py_DECREF(events_seq);
44114376
return NULL;
44124377
}

‎Objects/bytesobject.c‎

Lines changed: 30 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2276,7 +2276,6 @@ bytes_translate_impl(PyBytesObject *self, PyObject *table,
22762276
PyObject *input_obj = (PyObject*)self;
22772277
const char *output_start, *del_table_chars=NULL;
22782278
Py_ssize_t inlen, tablen, dellen = 0;
2279-
PyObject *result;
22802279
int trans_table[256];
22812280

22822281
if (PyBytes_Check(table)) {
@@ -2321,13 +2320,13 @@ bytes_translate_impl(PyBytesObject *self, PyObject *table,
23212320
}
23222321

23232322
inlen = PyBytes_GET_SIZE(input_obj);
2324-
result = PyBytes_FromStringAndSize((char *)NULL, inlen);
2325-
if (result == NULL) {
2323+
PyBytesWriter *writer = PyBytesWriter_Create(inlen);
2324+
if (writer == NULL) {
23262325
PyBuffer_Release(&del_table_view);
23272326
PyBuffer_Release(&table_view);
23282327
return NULL;
23292328
}
2330-
output_start = output = PyBytes_AS_STRING(result);
2329+
output_start = output = PyBytesWriter_GetData(writer);
23312330
input = PyBytes_AS_STRING(input_obj);
23322331

23332332
if (dellen == 0 && table_chars != NULL) {
@@ -2336,14 +2335,17 @@ bytes_translate_impl(PyBytesObject *self, PyObject *table,
23362335
c = Py_CHARMASK(*input++);
23372336
*output++ = table_chars[c];
23382337
}
2338+
PyObject *result = PyBytesWriter_Finish(writer);
2339+
23392340
/* Check if anything changed (for returning original object) */
23402341
/* We save this check until the end so that the compiler will */
23412342
/* unroll the loop above leading to MUCH faster code. */
2342-
if (PyBytes_CheckExact(input_obj)) {
2343+
if (result != NULL && PyBytes_CheckExact(input_obj)) {
23432344
if (memcmp(PyBytes_AS_STRING(input_obj), output_start, inlen) == 0) {
23442345
Py_SETREF(result, Py_NewRef(input_obj));
23452346
}
23462347
}
2348+
23472349
PyBuffer_Release(&del_table_view);
23482350
PyBuffer_Release(&table_view);
23492351
return result;
@@ -2370,13 +2372,11 @@ bytes_translate_impl(PyBytesObject *self, PyObject *table,
23702372
changed = 1;
23712373
}
23722374
if (!changed && PyBytes_CheckExact(input_obj)) {
2373-
Py_DECREF(result);
2375+
PyBytesWriter_Discard(writer);
23742376
return Py_NewRef(input_obj);
23752377
}
23762378
/* Fix the size of the resulting byte string */
2377-
if (inlen > 0)
2378-
_PyBytes_Resize(&result, output - output_start);
2379-
return result;
2379+
return PyBytesWriter_FinishWithPointer(writer, output);
23802380
}
23812381

23822382

@@ -3889,8 +3889,13 @@ PyBytesWriter_Resize(PyBytesWriter *writer, Py_ssize_t size)
38893889
PyErr_SetString(PyExc_ValueError, "size must be >= 0");
38903890
return -1;
38913891
}
3892-
if (byteswriter_resize(writer, size, 1) < 0) {
3893-
return -1;
3892+
if (writer->size < size) {
3893+
if (byteswriter_resize(writer, size, 1) < 0) {
3894+
return -1;
3895+
}
3896+
}
3897+
else {
3898+
// The buffer is already large enough. Never shrink the buffer.
38943899
}
38953900
writer->size = size;
38963901
#ifdef Py_DEBUG
@@ -3913,22 +3918,26 @@ _PyBytesWriter_ResizeAndUpdatePointer(PyBytesWriter *writer, Py_ssize_t size,
39133918

39143919

39153920
int
3916-
PyBytesWriter_Grow(PyBytesWriter *writer, Py_ssize_t size)
3921+
PyBytesWriter_Grow(PyBytesWriter *writer, Py_ssize_t grow)
39173922
{
3918-
if (size < 0) {
3919-
PyErr_SetString(PyExc_ValueError, "size must be >= 0");
3920-
return -1;
3921-
}
3922-
if (size == 0) {
3923+
if (grow == 0) {
39233924
// Nothing to do
39243925
return 0;
39253926
}
39263927

3927-
if (size > PY_SSIZE_T_MAX - writer->size) {
3928-
PyErr_NoMemory();
3929-
return -1;
3928+
if (grow >= 0) {
3929+
if (grow > PY_SSIZE_T_MAX - writer->size) {
3930+
PyErr_NoMemory();
3931+
return -1;
3932+
}
3933+
}
3934+
else {
3935+
if (writer->size + grow < 0) {
3936+
PyErr_SetString(PyExc_ValueError, "invalid size");
3937+
return -1;
3938+
}
39303939
}
3931-
size = writer->size + size;
3940+
Py_ssize_t size = writer->size + grow;
39323941

39333942
if (byteswriter_resize(writer, size, 1) < 0) {
39343943
return -1;

0 commit comments

Comments
 (0)