Skip to content

Add replacements for PySys_GetObject() #54

@serhiy-storchaka

Description

@serhiy-storchaka

PySys_GetObject() has the following issues:

  • It returns a borrowed reference. The result should be used with care with the GIL, but in the GIL-less build it is always unsafe.
  • It silences all exceptions (including MemoryError and UnicodeDecodeError). This can lead to unexpected behavior in memory starving program, to hiding bugs, and maybe to suppressing user interruption. AFAIK, it is the last of the C API functions that has not get a replacement.
  • It only accept the name as the C string. Usually we add the Object suffix to variants of functions that accept Python string, but PySys_GetObjectObject() would look weird.

There were several private variants (_PySys_GetObject(), _PySys_GetAttr() and others in older Python versions).

By analyzing the uses of PySys_GetObject() and its private variants, I have found, that in half of cases the name is passed as the C string, and in other half it is passed as the Python string. In half of cases the absent sys attribute is not treated as error, and in other hals a RuntimeError is raised (e.g. "lost sys.stdout"). So I came to the conclusion that four new functions are needed:

PyObject *PySys_GetAttr(PyObject *);
PyObject *PySys_GetAttrString(const char *);
int PySys_GetOptionalAttr(PyObject *, PyObject **);
int PySys_GetOptionalAttrString(const char *, PyObject **);

PySys_GetAttr() and PySys_GetAttrString() raise RuntimeError and return NULL if the sys attribute was not found. PySys_GetOptionalAttr() and PySys_GetOptionalAttrString() behave like other C API with "Optional" in the name -- they return 1 and set the strong reference if the sys attribute exists, return 0 (without raising an exception) if it does not exist, and return -1 if other error (like MemoryError or UnicodeDecodeError) occurred.

The number of usages per name:

Function Usages
PySys_GetAttr 13
PySys_GetAttrString 16
PySys_GetOptionalAttr 22
PySys_GetOptionalAttrString 11

Unfortunately, no variant prevails, all functions are equally useful, so we cannot shorten this list. I tried to find better solution since I created an issue 1.5 years ago, but this is what I only have.

Issue: python/cpython#108512
PR: python/cpython#111035

I am ready to listen to your suggestions and advice, and then I will open a poll.

Metadata

Metadata

Assignees

No one assigned

    Labels

    voteThe WG is voting (or has voted)

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions