Content-Length: 425682 | pFad | http://github.com/python/cpython/pull/128950

CE gh-128715: Expose ctypes.CField, with info attributes by encukou · Pull Request #128950 · python/cpython · GitHub
Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

gh-128715: Expose ctypes.CField, with info attributes #128950

Draft
wants to merge 20 commits into
base: main
Choose a base branch
from

Conversation

encukou
Copy link
Member

@encukou encukou commented Jan 17, 2025

Expose the type of struct/union field descriptors (_ctypes._CField) as ctypes.CField. (This is mainly to make it easier to refer to it -- for typing and documentation. Creating CFields manually is not supported.)

Add attributes for easier introspection:

  • name & type, as defined in _fields_
  • byte_size & byte_offset, specify the chunk of memory to read/write
  • bit_size & bit_offset, which specify the shift & mask for bitfields
  • is_bitfield & is_anonymous booleans

The existing offset remains, as an alias for byte_offset.
The existing size is unchanged. Usually it is the same as byte_size, but for bitfields, it contains a bit-packed combination of bit_size & bit_offset.

Update the repr() of CField.

Use the same values internally as well. (Except bit_size, which might overflow Py_ssize_t for very large types. Instead, in C use bitfield_size, which is 0 for non-bitfields and thus serves as is_bitfield flag. Different name used clarity.)
Old names are removed from the C implementation to ensure a clean transition.
For simplicity, I keep byte_size in CFieldObject for now, even though it's redundant: it's the size of the underlying type.

Add a generic test that ensures the values are consistent, and that we don't have overlapping fields in structs. Use this check throughout test_ctypes, wherever a potentially interesting Structure or Union is created. (Tests for how simple structs behave after they're created don't need the checks, but I erred on the side of adding checks.)

Lift the restriction on maximum field size that was temporarily added in GH-126938. The max size is now Py_ssize_t.

This PR does not yet touch cfield.c getters & setters: the bit-packed “size” argument is computed and passed to those.


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


# Do not use CField outside ctypes, yet.
# The constructor is internal API and may change without warning.
_internal_use=True,
Copy link
Member

Choose a reason for hiding this comment

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

I think this is something that pytest does a lot but how about naming it _cpython=True to stress that it's tied to CPython implementation?

Copy link
Member Author

Choose a reason for hiding this comment

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

Not really -- if there's another implementation of ctypes I'd prefer that they use _internal_use too :)

expected_size = (field.bit_size << 16) + offset_for_size
self.assertEqual(field.size, expected_size)
else:
# size == byte_size
Copy link
Member

Choose a reason for hiding this comment

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

I don't know if you used === above to not uncomment by mistake, so maybe size === byte_size as well? (or maybe the === was a typo)

Copy link
Member Author

@encukou encukou Jan 24, 2025

Choose a reason for hiding this comment

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

Wow, good eye :)
Above it's not a guard against uncommenting; I meant something like -- they're always the same. Here, the else case is where they're equal.

(The comments don't communicate that well, but, it doesn't really matter. The next person can make them consistent if they prefer that.)

Lib/test/test_ctypes/_support.py Outdated Show resolved Hide resolved
Modules/_ctypes/cfield.c Outdated Show resolved Hide resolved
"bit field %R size too large, got %zd",
name, byte_size);
}
bitfield_size = PyLong_AsSsize_t(bit_size_obj);
Copy link
Member

Choose a reason for hiding this comment

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

Note for myself: because bit_size_obj should be small, we would use a fast path so this call would be efficient. However, if it's too large, then it will be slower, but we don't care as we will raise an exception.

Copy link
Member Author

Choose a reason for hiding this comment

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

This is class creation. I'm leaving optimizations to PGO :)

Modules/_ctypes/cfield.c Outdated Show resolved Hide resolved
Modules/_ctypes/cfield.c Outdated Show resolved Hide resolved
Modules/_ctypes/cfield.c Outdated Show resolved Hide resolved
Modules/_ctypes/cfield.c Outdated Show resolved Hide resolved
Modules/_ctypes/cfield.c Outdated Show resolved Hide resolved
@encukou encukou marked this pull request as draft January 31, 2025 16:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants








ApplySandwichStrip

pFad - (p)hone/(F)rame/(a)nonymizer/(d)eclutterfier!      Saves Data!


--- a PPN by Garber Painting Akron. With Image Size Reduction included!

Fetched URL: http://github.com/python/cpython/pull/128950

Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy