-
-
Notifications
You must be signed in to change notification settings - Fork 34.9k
gh-104533: Add a dataclass-like decorator for ctypes structures
#153781
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
base: main
Are you sure you want to change the base?
Changes from all commits
f0db59d
b73c912
94eb25a
bba7682
91eb76b
103a740
b14dd51
864b811
c0afd38
2e469b6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,9 +1,16 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import os | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import sys | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| from dataclasses import dataclass | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| lazy import functools | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| lazy import shutil | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| lazy import subprocess | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| lazy import annotationlib | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| lazy from typing import Annotated, get_args, ClassVar, get_origin | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| lazy from ctypes import Structure, BigEndianStructure, LittleEndianStructure | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # find_library(name) returns the pathname of a library, or None. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if os.name == "nt": | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -491,6 +498,82 @@ def dllist(): | |||||||||||||||||||||||||||||||||||||||||||||||||||||
| ctypes.byref(ctypes.py_object(libraries))) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return libraries | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| @dataclass(slots=True, frozen=True) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| class CFieldInfo: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| anonymous: bool = False | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| bit_width: int | None = None | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| def _process_struct(decorated_class, /, *, align, layout, endian, pack): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fields = [] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| anonymous = [] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if issubclass(decorated_class, Structure): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fields.extend(decorated_class._fields_) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| anonymous.extend(decorated_class._anonymous_) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for name, hint in annotationlib.get_annotations(decorated_class).items(): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if get_origin(hint) is ClassVar: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| continue | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| field = [name] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if get_origin(hint) is Annotated: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| cls, field_info = get_args(hint) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| field.append(cls) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if not isinstance(field_info, CFieldInfo): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| raise TypeError(f"expected CFieldInfo in Annotated, got {field_info!r}") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if field_info.bit_width is not None: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| field.append(field_info.bit_width) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if field_info.anonymous is True: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| anonymous.append(name) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| else: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| field.append(hint) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fields.append(field) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if endian == 'big': | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| endian_class = BigEndianStructure | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| elif endian == 'little': | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| endian_class = LittleEndianStructure | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| elif endian == 'native': | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| endian_class = Structure | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| else: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| raise ValueError(f"expected 'big', 'little', or 'native', but got {endian!r}") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| @functools.wraps(decorated_class, updated=()) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| class _Struct(endian_class): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| vars().update(vars(decorated_class)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if align is not None: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| _align_ = align | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if layout is not None: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| _layout_ = layout | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if pack is not None: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| _pack_ = pack | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| _fields_ = fields | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| _anonymous_ = anonymous | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return _Struct | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| def struct(class_or_none=None, /, *, align=None, layout=None, endian='native', pack=None): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| process_the_struct = functools.partial( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| _process_struct, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| align=align, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| layout=layout, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| endian=endian, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| pack=pack | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if class_or_none is None: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| def inner(decorated_class): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return process_the_struct(decorated_class) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return inner | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return process_the_struct(class_or_none) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+560
to
+575
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I meant it like this:
Suggested change
That's how decorators of this fashion are usually made.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ################################################################ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # test code | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
Uh oh!
There was an error while loading. Please reload this page.
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.
Consider adding a collation: old syntax vs. new syntax.
Uh oh!
There was an error while loading. Please reload this page.
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 don't think that's necessary -- the examples for
Structureare right above.