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 — gh-108444: Add PyLong_AsInt() public function by vstinner · Pull Request #108445 · python/cpython

Conversation

@vstinner

@vstinner vstinner commented Aug 24, 2023 •
edited by github-actions Bot
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Member
  • Rename _PyLong_AsInt() to PyLong_AsInt().
  • Add documentation.
  • Add test.
  • For now, keep _PyLong_AsInt() as an alias to PyLong_AsInt().
  • Issue: [C API] Add PyLong_AsInt() public function #108444

📚 Documentation preview 📚: https://cpython-previews--108445.org.readthedocs.build/

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
@bedevere-bot bedevere-bot mentioned this pull request Aug 24, 2023
[C API] Add PyLong_AsInt() public function #108444
Closed
@bedevere-bot bedevere-bot added the awaiting core review label Aug 24, 2023
@vstinner

vstinner commented Aug 24, 2023

Copy link
Copy Markdown
Member Author

@serhiy-storchaka: You added the function 10 years, what do you think of making it public now?

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@vstinner
vstinner force-pushed the long_asint branch from 88ca411 to c8c7686 Compare August 24, 2023 18:13
@vstinner
vstinner requested review from a team and encukou as code owners August 24, 2023 18:13
@vstinner
pythongh-108444: Add PyLong_AsInt() public function
3a79210
* Rename _PyLong_AsInt() to PyLong_AsInt().
* Add documentation.
* Add test.
* For now, keep _PyLong_AsInt() as an alias to PyLong_AsInt().
@vstinner
vstinner force-pushed the long_asint branch from c8c7686 to 3a79210 Compare August 24, 2023 18:14
@serhiy-storchaka

serhiy-storchaka commented Aug 24, 2023

Copy link
Copy Markdown
Member

@serhiy-storchaka: You added the function 10 years, what do you think of making it public now?

Just last week I thought about this. (int)PyLong_AsLong() is a common error, so we should make the correct way more easier.

Should we add also PyLong_AsIntAndOverflow() and PyLong_AsUnsignedInt(). I guess that PyLong_AsUnsignedIntMask() is not needed, as (unsigned)PyLong_AsUnsignedLongMask() does correct thing.

Should we add PyLong_AsShort() and others?

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@vstinner

vstinner commented Aug 24, 2023

Copy link
Copy Markdown
Member Author

Having to check result == -1 && PyErr_Occurred() is a pain, and we are trying to avoid that. That's why the new PyDict_GetItemRef() return -1 on error, rather than returning directly the item.

Maybe the API should: int PyLong_AsInt(PyObject *obj, int **result): the Python int value is written into *result, return 0 on success, or return -1 on error (wrong type, overflow). If the fact that the name is too close to current function, maybe we use a different name: PyLong_ToInt(), PyLong_GetInt(), ...

Should we add PyLong_AsShort() and others?

I would prefer to not add too many functions. The int is common, I'm not sure about the short type. For example, there is no existing private function for short.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

serhiy-storchaka
serhiy-storchaka approved these changes Aug 24, 2023
View reviewed changes

@serhiy-storchaka serhiy-storchaka left a comment

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Comment thread Lib/test/test_capi/test_long.py
with self.assertRaises(OverflowError):
PyLong_AsInt(INT_MAX + 1)

# invalid type

@serhiy-storchaka serhiy-storchaka Aug 24, 2023

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add also tests for objects with __index__

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions

@vstinner vstinner Aug 24, 2023

Copy link
Copy Markdown
Member Author

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I added a test

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
@bedevere-bot bedevere-bot added awaiting merge and removed awaiting core review labels Aug 24, 2023
@vstinner
Add test on __index__() method
238d80e
Eclips4
Eclips4 reviewed Aug 24, 2023
View reviewed changes
Comment thread Misc/NEWS.d/next/C API/2023-08-24-20-08-02.gh-issue-108014.20DOSS.rst Resolved

Uh oh!

There was an error while loading. Please reload this page.

Eclips4
Eclips4 reviewed Aug 24, 2023
View reviewed changes
Comment thread Misc/NEWS.d/next/C API/2023-08-24-20-08-02.gh-issue-108014.20DOSS.rst
@@ -0,0 +1,4 @@
Add :c:func:`PyLong_AsInt` function: similar to :c:func:`PyLong_AsLong`, but
store the result in a C :c:expr:`int` instead of a C :c:expr:`long`.
Previously, it was known as the the private function :c:func:`!_PyLong_AsInt`

@Eclips4 Eclips4 Aug 24, 2023

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Previously, it was known as the the private function :c:func:`!_PyLong_AsInt`
Previously, it was known as the private function :c:func:`!_PyLong_AsInt`

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Eclips4
Eclips4 reviewed Aug 24, 2023
View reviewed changes
Comment thread Doc/whatsnew/3.13.rst Resolved

Uh oh!

There was an error while loading. Please reload this page.

Eclips4
Eclips4 approved these changes Aug 24, 2023
View reviewed changes
vstinner and others added 2 commits August 24, 2023 22:39
@vstinner @Eclips4
Update Misc/NEWS.d/next/C API/2023-08-24-20-08-02.gh-issue-108014.20D…
1eb0f3f
…OSS.rst

Co-authored-by: Kirill Podoprigora <[email protected]>
@vstinner @Eclips4
Update Doc/whatsnew/3.13.rst
5f15646
Co-authored-by: Kirill Podoprigora <[email protected]>
@erlend-aasland

erlend-aasland commented Aug 24, 2023

Copy link
Copy Markdown
Contributor

This API extends the list of problematic APIs listed in capi-workgroup/problems#1. How about a non-ambiguous return value?

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@erlend-aasland

erlend-aasland commented Aug 24, 2023

Copy link
Copy Markdown
Contributor

See also:

  • Determining the failure of C API call is ambiguous #70963
All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@serhiy-storchaka

serhiy-storchaka commented Aug 24, 2023

Copy link
Copy Markdown
Member

_PyLong_AsInt() is used more than 420 times in the CPython code. For comparison, PyLong_AsLong() is used only about 160 times, and PyLong_AsLongLong() -- less than 25 times.

I suppose that the similar proportion should be in the third-party code. But they use PyLong_AsLong() and often ignore integer overflow in conversion to int. Simple replacing PyLong_AsLong() with PyLong_AsInt() in right places should fix a lot of bugs. Replacing it with a function with different interface is not so easy.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@erlend-aasland

erlend-aasland commented Aug 24, 2023

Copy link
Copy Markdown
Contributor

_PyLong_AsInt() is used more than 420 times in the CPython code.

That number is true, but the majority of it comes from Argument Clinic. If you subtract generated code, you will see that the actual number is less then a tenth of 420:

$ git grep _PyLong_AsInt  | grep -v clinic | wc -l
36

I'm not sure a handful of cases warrants the introduction of yet another ambiguous API.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@serhiy-storchaka

serhiy-storchaka commented Aug 24, 2023

Copy link
Copy Markdown
Member

That number is true, but the majority of it comes from Argument Clinic.

And what? Argument Clinic uses _PyLong_AsInt() much more that PyLong_AsLong() because conversion to int is much more wanted.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@erlend-aasland

erlend-aasland commented Aug 24, 2023

Copy link
Copy Markdown
Contributor

And what? Argument Clinic uses _PyLong_AsInt() much more that PyLong_AsLong() because conversion to int is much more wanted.

The point is that there is not 420 occurrences of _PyLong_AsInt to replace, there are only 38; two in clinic.py, and the remaining 36 in various .c files.

You wrote:

_PyLong_AsInt() is used more than 420 times in the CPython code.

Replacing it with a function with different interface is not so easy.

I assumed you meant that it was not easy to use a different API because of the huge number of occurrences (420). My interpretation was that since the actual number of occurrences that need replacement is significantly lower, your argument of it being hard to replace is moot.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@serhiy-storchaka

serhiy-storchaka commented Aug 24, 2023

Copy link
Copy Markdown
Member

No, I mean that you can expect a huge number of use cases for PyLong_AsInt() in hand written third-party code which currently uses PyLong_AsLong() with a chance of integer overflow. Replacing (int)PyLong_AsLong() with PyLong_AsInt() is much simpler that with a function with other interface.

erlend-aasland reacted with thumbs up emoji
All reactions
  • 👍 1 reaction

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@erlend-aasland

erlend-aasland commented Aug 24, 2023

Copy link
Copy Markdown
Contributor

No, I mean that you can expect a huge number of use cases for PyLong_AsInt() in hand written third-party code which currently uses PyLong_AsLong() with a chance of integer overflow. Replacing (int)PyLong_AsLong() with PyLong_AsInt() is much simpler that with a function with other interface.

Aha, sorry, I misunderstood you. Yes, that is a valid point. I withdraw my complain.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@vstinner

vstinner commented Aug 24, 2023

Copy link
Copy Markdown
Member Author

This API extends the list of problematic APIs listed in capi-workgroup/problems#1. How about a non-ambiguous return value?

I'm well aware of PyLong_AsLong() API issue. But if we fix the API, I would prefer to fix the whole PyLong API family, not a single function. It would be surprising to have a single function with a similar name, but a different API.

By the way, the private _PyLong_AsInt() function is used by these projects:

Affected projects (9):

  • catboost (1.2)
  • fastobo (0.12.2)
  • gnureadline (8.1.2)
  • multiprocess (0.70.14)
  • numpy (1.25.0)
  • orjson (3.9.1)
  • pythonnet (3.0.1)
  • pyzstd (0.15.9)
  • typed_ast (1.5.5)
erlend-aasland reacted with thumbs up emoji
All reactions
  • 👍 1 reaction

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@vstinner
vstinner merged commit be436e0 into python:main Aug 24, 2023
@vstinner
vstinner deleted the long_asint branch August 24, 2023 21:55
@bedevere-bot bedevere-bot added awaiting core review and removed awaiting merge labels Aug 24, 2023
@bedevere-bot

bedevere-bot commented Aug 24, 2023

Copy link
Copy Markdown

There's a new commit after the PR has been approved.

@serhiy-storchaka: please review the changes made to this pull request.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@bedevere-bot bedevere-bot removed the awaiting core review label Aug 24, 2023
@bedevere-bot
bedevere-bot requested a review from serhiy-storchaka August 24, 2023 21:55
@erlend-aasland

erlend-aasland commented Aug 24, 2023

Copy link
Copy Markdown
Contributor

But if we fix the API, I would prefer to fix the whole PyLong API family, not a single function.

Yes, that makes sense.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@vstinner

vstinner commented Aug 24, 2023

Copy link
Copy Markdown
Member Author

The function is more if it's worth it to propose a new set of PyLong_AsLong-like function which avoid having to check PyErr_Occurred(): API like int PyLong_GetLong(PyObject *obj, long **result) that I proposed above.

erlend-aasland reacted with thumbs up emoji
All reactions
  • 👍 1 reaction

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@erlend-aasland

erlend-aasland commented Aug 25, 2023

Copy link
Copy Markdown
Contributor

... or even better: int PyInt_GetLong(...), so it is named after the Python type.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@encukou

encukou commented Aug 31, 2023

Copy link
Copy Markdown
Member

I don't think this should be added to the stable ABI now.
If we do fix the whole PyLong API family, this is one more function that will need to be deprecated shortly after it was added.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@vstinner

vstinner commented Aug 31, 2023

Copy link
Copy Markdown
Member Author

I don't think this should be added to the stable ABI now. If we do fix the whole PyLong API family, this is one more function that will need to be deprecated shortly after it was added.

The private _PyLong_AsInt() function seems to be pretty commonly used in the wild, so adding it as public API helps people to migrate to this new public C API.

I would like to add it the limited C API to be able to use it in C code generated by Argument Clinic which seems to like a lot PyLong_AsInt(). For example, in the main branch, there are 70 .c.h files generated by AC which calls PyLong_AsInt().

For now, there is no concrete plan to deprecate PyLong_AsLong() nor replacement.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@serhiy-storchaka

serhiy-storchaka commented Aug 31, 2023

Copy link
Copy Markdown
Member

Is there a way to gather some reliable statistics about non-public functions used in third-party code? If they are used in a number of non-toy projects, we should consider to provide a public API to satisfy the need.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@encukou

encukou commented Aug 31, 2023

Copy link
Copy Markdown
Member

If they are used in a number of non-toy projects, we should consider to provide a public API to satisfy the need.

I'm on board with that. But we should also use these opportunities to provide better API. Private functions can get away with being hacky.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@vstinner

vstinner commented Aug 31, 2023

Copy link
Copy Markdown
Member Author

I'm on board with that. But we should also use these opportunities to provide better API.

Known issues of PyLong_AsLong() were discussed in previous comments and it was decided to add PyLong_AsInt() as it is anyway.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

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

Reviewers

@Eclips4 Eclips4 Eclips4 approved these changes
@encukou encukou Awaiting requested review from encukou encukou is a code owner
@serhiy-storchaka serhiy-storchaka Awaiting requested review from serhiy-storchaka

Uh oh!

There was an error while loading. Please reload this page.

Assignees

No one assigned

Labels

None yet

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

Uh oh!

There was an error while loading. Please reload this page.

6 participants

@vstinner @serhiy-storchaka @erlend-aasland @bedevere-bot @encukou @Eclips4
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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.