Skip to content

[C API] PEP 782: Add PyBytesWriter API #129813

Closed

Description

@vstinner

Feature or enhancement

Proposal:

I propose adding a PyBytesWriter API to create bytes objects.

API:

typedef struct PyBytesWriter PyBytesWriter;

PyAPI_FUNC(void*) PyBytesWriter_Create(
    PyBytesWriter **writer,
    Py_ssize_t alloc);
PyAPI_FUNC(void) PyBytesWriter_Discard(
    PyBytesWriter *writer);
PyAPI_FUNC(PyObject*) PyBytesWriter_Finish(
    PyBytesWriter *writer,
    void *buf);

PyAPI_FUNC(Py_ssize_t) PyBytesWriter_GetRemaining(
    PyBytesWriter *writer,
    void *buf);
PyAPI_FUNC(void*) PyBytesWriter_Extend(
    PyBytesWriter *writer,
    void *buf,
    Py_ssize_t extend);
PyAPI_FUNC(void*) PyBytesWriter_WriteBytes(
    PyBytesWriter *writer,
    void *buf,
    const void *bytes,
    Py_ssize_t size);
PyAPI_FUNC(void*) PyBytesWriter_Format(
    PyBytesWriter *writer,
    void *buf,
    const char *format,
    ...);

Simple example creating the string b"abc":

PyObject* create_abc(void)
{
    PyBytesWriter *writer;
    char *str = PyBytesWriter_Create(&writer, 3);
    if (writer == NULL) return NULL;

    memcpy(str, "abc", 3);
    str += 3;

    return PyBytesWriter_Finish(writer, str);
}

Example formatting an integer in decimal, the size is not known in advance::

PyObject* format_int(int value)
{
    PyBytesWriter *writer;
    char *str = PyBytesWriter_Create(&writer, 20);
    if (writer == NULL) return NULL;

    str += PyOS_snprintf(str, 20, "%i", value);

    return PyBytesWriter_Finish(writer, str);
}

Note: using PyBytesWriter_Format() would make this code simpler.

Example using PyBytesWriter_Extend(),smilar to bytes.center() with a different API: spaces are number of whitespaces added to the left and to the right:

static PyObject *
byteswriter_center_example(Py_ssize_t spaces, char *str, Py_ssize_t str_size)
{
    PyBytesWriter *writer;
    char *buf = PyBytesWriter_Create(&writer, spaces * 2);
    if (buf == NULL) {
        goto error;
    }
    assert(PyBytesWriter_GetRemaining(writer, buf) == spaces * 2);

    // Add left spaces
    memset(buf, ' ', spaces);
    buf += spaces;
    assert(PyBytesWriter_GetRemaining(writer, buf) == spaces);

    // Copy string
    buf = PyBytesWriter_Extend(writer, buf, str_size);
    if (buf == NULL) {
        goto error;
    }
    assert(PyBytesWriter_GetRemaining(writer, buf) == spaces + str_size);

    memcpy(buf, str, str_size);
    buf += str_size;
    assert(PyBytesWriter_GetRemaining(writer, buf) == spaces);

    // Add right spaces
    memset(buf, ' ', spaces);
    buf += spaces;
    assert(PyBytesWriter_GetRemaining(writer, buf) == 0);

    return PyBytesWriter_Finish(writer, buf);

error:
    PyBytesWriter_Discard(writer);
    return NULL;
}

Has this already been discussed elsewhere?

No response given

Links to previous discussion of this feature:

My previous attempt in July/August 2024:

Linked PRs

Activity

  1. added 4 commits that reference this issue on Mar 20, 2025
  2. changed the title [-][C API] Add PyBytesWriter API[/-] [+][C API] PEP 782: Add PyBytesWriter API[/+] on Apr 22, 2025
  3. added 20 commits that reference this issue on Sep 12, 2025
  4. added 16 commits that reference this issue on Sep 12, 2025
  5. added a commit that references this issue on Sep 15, 2025
  6. added 20 commits that reference this issue on Sep 15, 2025
  7. added 20 commits that reference this issue on Sep 15, 2025
  8. added 13 commits that reference this issue on Sep 18, 2025
  9. added a commit that references this issue on Sep 19, 2025
  10. added 6 commits that reference this issue on Sep 23, 2025
  11. vstinner commented on Sep 24, 2025

    @vstinner
    MemberAuthor

    I converted most functions using PyBytes_FromStringAndSize(NULL, size) and _PyBytes_Resize() to the new public PyBytesWriter API. I also converted all functions using the old private _PyBytesWriter API and I removed this private API.

  12. added 4 commits that reference this issue on Oct 10, 2025
  13. added a commit that references this issue on Dec 6, 2025
  14. added 3 commits that reference this issue on Mar 13, 2026
  15. added a commit that references this issue on Apr 25, 2026
  16. added a commit that references this issue on Sep 5, 2026
  17. added a commit that references this issue on Sep 5, 2026
  18. added 3 commits that reference this issue on Sep 9, 2026
  19. added 2 commits that reference this issue on Sep 12, 2026
  20. added a commit that references this issue on Sep 14, 2026
  21. added a commit that references this issue on Oct 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions