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-111140: Adds PyLong_AsNativeBytes and PyLong_FromNative[Unsigned]Bytes functions by zooba · Pull Request #114886 · python/cpython

Conversation

@zooba

@zooba zooba commented Feb 2, 2024 •
edited by bedevere-app Bot
Loading

Uh oh!

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

Copy link
Copy Markdown
Member
  • Issue: C API: Consider adding public PyLong_AsByteArray() and PyLong_FromByteArray() functions #111140

Sorry, something went wrong.

Uh oh!

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

All reactions
@zooba
pythongh-111140: Adds PyLong_AsByteArray functions
c86821e
@bedevere-app bedevere-app Bot mentioned this pull request Feb 2, 2024
C API: Consider adding public PyLong_AsByteArray() and PyLong_FromByteArray() functions #111140
Closed
@zooba

zooba commented Feb 2, 2024

Copy link
Copy Markdown
Member Author

Sharing work so far for feedback/concerns.

I like the unsigned/signed semantics (basically, using "unsigned" suppresses an error where you need one more bit to be a sign bit), and I dislike the mess needed to support byteswapping for non-native endian on arbitrary length buffers. But it's written now and seems to work, so I guess it can stay.

The "FromByteArray" prototypes are a lie right now, but they're coming in next :) Probably need a "WithOptions" variant as well, though I have a feeling the implementation can't be any better than _PyLong_FromByteArray so it should be simple.

All reactions

Sorry, something went wrong.

Uh oh!

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

@zooba
Statics
cd6754a
encukou
encukou reviewed Feb 2, 2024
View reviewed changes
Comment thread Include/cpython/longobject.h Resolved

Uh oh!

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

zooba added 3 commits February 2, 2024 13:38
@zooba
Better options handling and tests
bf86f85
@zooba
Rework into PyLong_CopyBits
22f3d14
@zooba
Merge remote-tracking branch 'upstream/main' into pythongh-111140
0dc0bcc
@zooba zooba changed the title gh-111140: Adds PyLong_AsByteArray functions gh-111140: Adds PyLong_CopyBits function Feb 2, 2024
zooba added 3 commits February 2, 2024 15:37
@zooba
Not static
c30e65a
@zooba
Add motivating example to tests
9661b65
@zooba
Add FromBits functions
79d4942
@zooba zooba changed the title gh-111140: Adds PyLong_CopyBits function gh-111140: Adds PyLong_CopyBits and PyLong_FromBits functions Feb 2, 2024
zooba added 4 commits February 2, 2024 17:00
@zooba
A test and a const
bc9e48c
@zooba
Space
b4761be
@zooba
Merge remote-tracking branch 'upstream/main' into pythongh-111140
043947f
@zooba
Docs
761db5c
@zooba
zooba marked this pull request as ready for review February 5, 2024 17:35
@zooba
zooba requested review from berkerpeksag, corona10, erlend-aasland and rhettinger as code owners February 5, 2024 17:35
@bedevere-app bedevere-app Bot added the awaiting core review label Feb 5, 2024
@rhettinger
rhettinger removed their request for review February 5, 2024 20:57
@zooba zooba mentioned this pull request Feb 5, 2024
Add PyLong_CopyBits and _FromBits functions capi-workgroup/decisions#12
Closed
2 of 5 tasks
zooba added 2 commits February 7, 2024 20:19
@zooba
Merge remote-tracking branch 'upstream/main' into pythongh-111140
22c2a64
@zooba
Rename to PyLong_AsNativeBytes
6e1a89a
@zooba zooba added the 🔨 test-with-buildbots Test PR w/ buildbots; report in status section label Feb 7, 2024
@bedevere-bot

bedevere-bot commented Feb 7, 2024

Copy link
Copy Markdown

🤖 New build scheduled with the buildbot fleet by @zooba for commit 6e1a89a 🤖

If you want to schedule another build, you need to add the 🔨 test-with-buildbots label again.

All reactions

Sorry, something went wrong.

Uh oh!

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

@bedevere-bot bedevere-bot removed the 🔨 test-with-buildbots Test PR w/ buildbots; report in status section label Feb 7, 2024
erlend-aasland
erlend-aasland reviewed Feb 8, 2024
View reviewed changes
Comment thread Doc/c-api/long.rst Resolved

Uh oh!

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

Comment thread Doc/c-api/long.rst Resolved

Uh oh!

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

Comment thread Doc/whatsnew/3.13.rst Resolved

Uh oh!

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

Comment thread Objects/longobject.c Resolved

Uh oh!

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

Comment thread Objects/longobject.c Resolved

Uh oh!

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

Comment thread Objects/longobject.c Resolved

Uh oh!

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

Comment thread Objects/longobject.c Resolved

Uh oh!

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

Comment thread Objects/longobject.c Resolved

Uh oh!

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

Comment thread Objects/longobject.c Resolved

Uh oh!

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

Comment thread Objects/longobject.c Resolved

Uh oh!

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

@zooba
Review feedback
79dd452
@zooba

zooba commented Feb 8, 2024

Copy link
Copy Markdown
Member Author

Thanks @erlend-aasland! Great feedback, and even found a bug (this is why we get reviews!)

I left one open question about doc wording, as I know you're more broadly involved in that than I am.

erlend-aasland reacted with heart emoji
All reactions
  • ❤️ 1 reaction

Sorry, something went wrong.

Uh oh!

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

zooba added 2 commits February 8, 2024 22:59
@zooba
_resolve_endianness
9693afe
@zooba
More reliable test
376e358
encukou
encukou reviewed Feb 9, 2024
View reviewed changes
Comment thread Include/cpython/longobject.h Outdated
Comment on lines +26 to +27
PyAPI_FUNC(int) PyLong_AsNativeBytes(PyObject* v, void* buffer, size_t n_bytes,
int endianness);

@encukou encukou Feb 9, 2024

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.

Shouldn't this return size_t rather than int?

Sorry, something went wrong.

Uh oh!

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

All reactions

@zooba zooba Feb 9, 2024

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.

Negative values are required, so we'd have to do Py_ssize_t and not size_t. The cast is just as annoying either way unless we make n_bytes also signed, which is then inconsistent with other APIs (but probably less bad than making it accept int).

We might need some agreed upon guidelines for choosing types for these kinds of purposes. int is a very common return type, and IMHO that makes things easier for people trying to call this from non-C languages, but they probably have no choice but to support Py_ssize_t as a return type too and so it really wouldn't make a huge difference.

I pity the poor CPU that has to convert a 32 billion bit number 🙃

Sorry, something went wrong.

Uh oh!

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

encukou reacted with thumbs up emoji
All reactions
  • 👍 1 reaction

@encukou encukou Feb 12, 2024

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.

I really need to focus on not mixing up signed/unsigned when I write a comment...

Yes, Py_ssize_t is one of the types that users need to support.
I'd much prefer using Py_ssize_t for sizes. These are arbitrary-sized integers, after all; limited by available memory.

Sorry, something went wrong.

Uh oh!

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

gpshead reacted with heart emoji
All reactions
  • ❤️ 1 reaction
Comment thread Objects/longobject.c Resolved

Uh oh!

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

@encukou

encukou commented Feb 9, 2024 •
edited
Loading

Uh oh!

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

Copy link
Copy Markdown
Member

How should I use PyLong_AsNativeBytes if I have an existing signed long I want to fill -- say, as part of a struct?
It seems that I'd need to allocate a buffer with one more byte, and then check that the extra byte is zero. And then memcpy to the destination.

All reactions

Sorry, something went wrong.

Uh oh!

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

@zooba

zooba commented Feb 9, 2024

Copy link
Copy Markdown
Member Author

How should I use PyLong_AsNativeBytes if I have an existing signed long I want to fill -- say, as part of a struct?

n = PyLong_AsNativeBytes(v, &st.long_value, sizeof(long), -1);
if (n < 0) {
  // exception raised
} else if (n <= sizeof(long)) {
  // success
} else {
  // value overflows, but st.long_value is set correctly, just truncated
}

What you do in the overflow case is up to you. Maybe you can overallocate? Maybe you just have to fail. But you don't have to overallocate to fit precisely into a signed variable.

For an unsigned variable, you may require one extra bit to store the sign bit, e.g. 2**256-1 requires 257 bits (33 bytes) of storage, and so does -(2**256-1). The extra byte will contain all sign bits in both cases, but in the former we don't need it when we know the value is going to be treated as unsigned (the MSB of the 32-byte value is set in both cases).

There really isn't a consistent way for us to handle this, lacking knowledge of what the value actually is. The current (private) function just fails on all negative values if you ask for unsigned, but that doesn't actually touch this issue at all - it just excludes a whole lot of otherwise valid conversions (e.g. +/-(2**255-1) and smaller always fits in 32 bytes with no loss of data).

So the suggestion there is if you know the magnitude of the value fits into your destination, or you don't care, then ignore positive returns from the function. But again, it only affects positive integers that require precisely the number of bits you've provided when treated as unsigned, and so treating as signed requires one extra.

erlend-aasland, encukou, and gpshead reacted with thumbs up emoji
All reactions
  • 👍 3 reactions

Sorry, something went wrong.

Uh oh!

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

@zooba
Doc tweaks
1f2cf3a
erlend-aasland
erlend-aasland approved these changes Feb 12, 2024
View reviewed changes
@bedevere-app bedevere-app Bot added awaiting merge and removed awaiting core review labels Feb 12, 2024
encukou
encukou approved these changes Feb 12, 2024
View reviewed changes

@encukou encukou 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.

Thanks.
IMO it's hard to implement a conversion to native unsigned integer on top of this, but, that could be solved by adding PyLong_AsNativeUnsignedBytes. No need to block this PR.

I trust your judgment on int/*size_t as well; no need for that to block the PR.

Sorry, something went wrong.

Uh oh!

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

All reactions
@zooba

zooba commented Feb 12, 2024

Copy link
Copy Markdown
Member Author

IMO it's hard to implement a conversion to native unsigned integer on top of this, but, that could be solved by adding PyLong_AsNativeUnsignedBytes. No need to block this PR.

I briefly implemented that. It took the size of the provided buffer, allocated a new one with one extra byte, did exactly the same thing, and copied the result into the original buffer or failed if it wasn't going to fit. It seems wasteful, especially compared to the caller doing a static allocation of a larger buffer themselves and calling this API, but we can't really improve on it that much - calculating that the resulting number is going to be in that one-bit worth of grey area isn't obvious. (And IMHO not offering it makes it more likely that people will implement it efficiently for themselves, rather than complaining that we did it inefficiently.)

The thing that isn't trivial is to reject negative values entirely, which someone may want to do. But that's more likely to be an application requirement than an integration/adapter requirement, so I'd expect they'll have a comparison to zero in their own language before they convert anyway, which means they'll go to a native signed integer rather than directly to unsigned, or they'll do the comparison using a Python comparison.

gpshead 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.

@zooba
Merge remote-tracking branch 'upstream/main' into pythongh-111140
7f4431d
@zooba
zooba force-pushed the gh-111140 branch from 66ece6c to 7f4431d Compare February 12, 2024 17:29
@python python deleted a comment Feb 12, 2024
zooba added 2 commits February 12, 2024 17:30
@zooba
Merge remote-tracking branch 'upstream/main' into pythongh-111140
2649d94
@zooba
Switch to Py_ssize_t consistently instead of int and size_t
39962de
@zooba
zooba merged commit 7861dfd into python:main Feb 12, 2024
@bedevere-app bedevere-app Bot removed the awaiting merge label Feb 12, 2024
@zooba

zooba commented Feb 12, 2024

Copy link
Copy Markdown
Member Author

I trust your judgment on int/*size_t as well; no need for that to block the PR.

@encukou It didn't block, I changed them all to Py_ssize_t 😄 My only concern was that comparing the result to sizeof(...) shouldn't cause a warning, but then I realised that the warning would also occur for (signed) int, so it doesn't matter.

All reactions

Sorry, something went wrong.

Uh oh!

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

@zooba
zooba deleted the gh-111140 branch February 12, 2024 20:14
scoder
scoder reviewed Feb 12, 2024
View reviewed changes
Comment thread Doc/c-api/long.rst Resolved

Uh oh!

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

@gpshead

gpshead commented Feb 12, 2024

Copy link
Copy Markdown
Member

additional follow on example and test improvements in #115380

All reactions

Sorry, something went wrong.

Uh oh!

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

@gpshead

gpshead commented Feb 12, 2024

Copy link
Copy Markdown
Member

Looking this API over the main thing I don't like is... unrelated to the API. It appears to be doing the right thing twos compliment wise given that it is returning data in whole bytes with the sign extension filling an entire additional byte when necessary as \xff or \x00.

I do find the need for an additional byte if someone is dealing exclusively with a value they already know to be non-negative yet large enough to occupy the high bit "annoying"... but this API isn't primarily for use by people wanting to merely fill a native type like that. They can add a range check of their own and be happy. ie: The prior understanding of the underlying value as discussed above.

Thus my PR making the example not use it to fill in a mere int to not encourage that pattern given native APIs for many types like that exist.

Granted we could change to encouraging this API everywhere in the future instead of people forgetting to if ((value = PyLong_AsLong(x)) == -1 && PyErr_Occurred()) { ... } being a super common flaw in code. This API maybe more readily encourages checking the return value.

All reactions

Sorry, something went wrong.

Uh oh!

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

AlexWaygood
AlexWaygood reviewed Feb 13, 2024
View reviewed changes
Comment thread Objects/longobject.c Resolved

Uh oh!

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

fsc-eriker pushed a commit to fsc-eriker/cpython that referenced this pull request Feb 14, 2024
@zooba @fsc-eriker
pythongh-111140: Adds PyLong_AsNativeBytes and PyLong_FromNative[Unsi…
52e065a
…gned]Bytes functions (pythonGH-114886)
@davidhewitt davidhewitt mentioned this pull request Feb 17, 2024
Deprecate / remove _Py internal APIs from pyo3-ffi PyO3/pyo3#3762
Open
@coderabbitai coderabbitai Bot mentioned this pull request Jul 25, 2026
feat(field): user-defined fields & EC points via a NEP-42 parametric numpy dtype fractalyze/zk_dtypes#162
Closed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Reviewers

@scoder scoder scoder left review comments
@AlexWaygood AlexWaygood AlexWaygood left review comments
@encukou encukou encukou approved these changes
@erlend-aasland erlend-aasland erlend-aasland approved these changes
@corona10 corona10 Awaiting requested review from corona10 corona10 is a code owner
@berkerpeksag berkerpeksag Awaiting requested review from berkerpeksag

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.

7 participants

@zooba @bedevere-bot @encukou @gpshead @scoder @erlend-aasland @AlexWaygood
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.