GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — C API: Support "nullable" parameter types in PyArg_Parse* · Issue #112068 · python/cpython

C API: Support "nullable" parameter types in PyArg_Parse* #112068

New issue
Copy link
New issue
Copy link
Open
Open
C API: Support "nullable" parameter types in PyArg_Parse*#112068
Copy link
Assignees
serhiy-storchaka
Labels
topic-C-APItype-featureA feature request or enhancementA feature request or enhancement

Description

@serhiy-storchaka
serhiy-storchaka
opened on Nov 14, 2023
Issue body actions

Feature or enhancement

Some builtin functions accept None as a special value in addition to values that should have the specified type. For example start and stop indices in index(), size in read(), dir_fd in many os functions, and numerous string parameters, e.g. encoding and errors.

There are special format units in PyArg_Parse* functions for "string or None": z, z*, z#. There is half-public converter _PyEval_SliceIndex for indices, and several more private converters. But while NULL can non-ambiguously represent None in C, there is no single integer value for None. In many cases it is -1, but it is 0 and Py_SIZE(self) for indices, AT_FDCWD for dir_fd parameter, etc. This is why _PyEval_SliceIndex keeps the value of the C variable unchanged when the argument is None.

I propose to generalize it to all types. Add the ? modifier. If it occurs after the format unit, and the argument is None, it keeps the initial value of the C variable, like if the argument was optional and missed. For example:

    int dir_fd = AT_FDCWD;
    Py_ssize_t size = PY_SSIZE_T_MAX;
    double speed = 0.0;
    int sep = EOF;
    int flag = -1;
    if (!PyArg_ParseTuple(args, "i?n?d?C?p?", &dir_fd, &size, &speed, &sep, &flag)) {
        return NULL;
    }

The code accepts two integers, a float, a character, and an arbitrary object (as boolean), but any of 5 arguments can also be None, in which case the corresponding variable keeps its initial value.

There was a similar proposition for Argument Clinic: #64540. But this proposition works not only with Argument Clinic, therefore it can be used in third-party code. It works not only with integers, but with all types, including custom converters. It is more convenient, because do not need to use a special structure. I believe that it covers most of use cases, and in few remaining cases you still can handle it manually, as before.

After implementing this for PyArg_Parse* I will add support in Argument Clinic.

Linked PRs

  • gh-112068: C API: Add support of nullable arguments in PyArg_Parse (prefix) #121187
  • gh-112068: C API: Add support of nullable arguments in PyArg_Parse (suffix) #121303
  • Revert "gh-112068: C API: Add support of nullable arguments in PyArg_Parse (GH-121303)" #136991
  • [3.14] Revert "gh-112068: C API: Add support of nullable arguments in PyArg_Parse (GH-121303)" (GH-136991) #137006

Activity

  1. serhiy-storchaka
    added
    type-featureA feature request or enhancementA feature request or enhancement
    topic-C-API
    on Nov 14, 2023
  2. serhiy-storchaka
    self-assigned this
    on Nov 14, 2023
  3. serhiy-storchaka commented on Jun 30, 2024

    @serhiy-storchaka
    serhiy-storchaka
    on Jun 30, 2024
    MemberAuthor
    More actions

    It turned out, that it is much more simpler to implement this as a prefix operator than a suffix. It can even be more efficient in future. So the above example looks:

        int dir_fd = AT_FDCWD;
        Py_ssize_t size = PY_SSIZE_T_MAX;
        double speed = 0.0;
        int sep = EOF;
        int flag = -1;
        if (!PyArg_ParseTuple(args, "?i?n?d?C?p", &dir_fd, &size, &speed, &sep, &flag)) {
            return NULL;
        }
  4. picnixz commented on Jun 30, 2024

    @picnixz
    picnixz
    on Jun 30, 2024
    Member
    More actions

    I feel suffixes are easier to understand and many languages use the ? as a suffix, e.g., for the optional chaining operator: a?.b?.c The way I understand it is a? followed by . on a? so ? is more of a suffix. So personally, I prefer suffixes though prefixes are fine. Is there any plan for implementing it (or do you have perhaps a PoC?)

  5. serhiy-storchaka commented on Jun 30, 2024

    @serhiy-storchaka
    serhiy-storchaka
    on Jun 30, 2024
    MemberAuthor
    More actions

    I created a PoC a long time ago, but had doubts about prefix vs suffix. Prefix only requires adding several lines of code in one place:
    https://github.com/python/cpython/pull/121187/files#diff-3a8078954be00d3c876e02dd0e5057aad07f2c5f82f6c3c76154dcf2866929cfR544-R557

        if (*format == '?') {
            format++;
            if (arg == Py_None) {
                msg = skipitem(&format, p_va, flags);
                if (msg == NULL) {
                    *p_format = format;
                }
                else {
                    levels[0] = 0;
                }
                return msg;
            }
            flags |= FLAG_NULLABLE;
        }

    and simple changes in 30+ other places are only needed to make the error messages better.

    Suffix requires to make additional complex changes in 20-40 places.

  6. serhiy-storchaka
    added a commit that references this issue on Jul 3, 2024

    pythongh-112068: C API: Add support of nullable arguments in PyArg_Parse

    389dfd9
  7. serhiy-storchaka commented on Jul 3, 2024

    @serhiy-storchaka
    serhiy-storchaka
    on Jul 3, 2024
    MemberAuthor
    More actions

    #121303 is an alternative implementation of ? as a suffix. It is more complex, and (...)? is not implemented yet, because of complexity and runtime cost of implementation.

  8. erlend-aasland commented on Aug 15, 2024

    @erlend-aasland
    erlend-aasland
    on Aug 15, 2024
    Contributor
    More actions

    There was a similar proposition for Argument Clinic: #64540.

    The discussion in the linked issue showed that this feature was highly controversial. What changed that made this non-controversial?

  9. serhiy-storchaka commented on Aug 15, 2024

    @serhiy-storchaka
    serhiy-storchaka
    on Aug 15, 2024
    MemberAuthor
    More actions

    To me, it is two things:

    • Time is passed, more code was converted to Argument Clinic and we have now more cases for such feature. There are not much of them, but they exist. I started to work on this feature because I see a benefit from it.
    • The original idea with returning a structure with fields for "error" and "is_null" is quite cumbersome. I propose simpler idea -- None means just the default value. This feature is limited, it can only be used if there is a default value, and you can not distinguish between None and the default value (e.g. in round()), but I believe that it covers most of cases.

    The rest of the discussion looks to me as a pure bikeshedding -- whether it should be called "nullable" or "Noneable" or whatever.

    Reacted by Erlend E. Aasland
  10. serhiy-storchaka
    added a commit that references this issue on Apr 8, 2025

    gh-112068: C API: Add support of nullable arguments in PyArg_Parse (G…

    f5f1ac8
  11. serhiy-storchaka
    closed this as completedon Apr 8, 2025
  12. serhiy-storchaka
    added 3 commits that reference this issue on Jul 22, 2025

    Revert "pythongh-112068: C API: Add support of nullable arguments in …

    a4ebeec

    Revert "pythongh-112068: C API: Add support of nullable arguments in …

    98d400f

    Revert "pythongh-112068: C API: Add support of nullable arguments in …

    264a600
  13. serhiy-storchaka commented on Jul 22, 2025

    @serhiy-storchaka
    serhiy-storchaka
    on Jul 22, 2025
    MemberAuthor
    More actions

    Since then I've come across a few cases where a different version of the feature would have been useful. Since this other version might be more useful, I'm rolling back this change for now. We'll have more time in the 3.15 timeframe.

  14. serhiy-storchaka
    reopened this on Jul 22, 2025
  15. hugovk
    added a commit that references this issue on Jul 22, 2025

    Revert "gh-112068: C API: Add support of nullable arguments in PyArg_…

    3a89dfe
  16. serhiy-storchaka
    added a commit that references this issue on Jul 22, 2025

    [3.14] Revert "pythongh-112068: C API: Add support of nullable argume…

    ab489be
  17. hugovk
    added a commit that references this issue on Jul 22, 2025

    [3.14] Revert "gh-112068: C API: Add support of nullable arguments in…

    805daa2
  18. taegyunkim
    added a commit that references this issue on Aug 4, 2025

    Revert "pythongh-112068: C API: Add support of nullable arguments in …

    3be9e71
  19. Agent-Hellboy
    added a commit that references this issue on Aug 19, 2025

    Revert "pythongh-112068: C API: Add support of nullable arguments in …

    8913b6e
  20. kumaraditya303
    added a commit that references this issue on Sep 9, 2025

    [3.14] Revert "pythongh-112068: C API: Add support of nullable argume…

    9ff2299
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

  • @serhiy-storchaka
    serhiy-storchaka

Labels

topic-C-APItype-featureA feature request or enhancementA feature request or enhancement

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

    You are visitor 01402503 — GeezerVison does not store the pages you look up.
    Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.