-
Notifications
You must be signed in to change notification settings - Fork 2.1k
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
feat: make stl.h list|set|map_caster
more user friendly.
#4686
Merged
Merged
Changes from 49 commits
Commits
Show all changes
55 commits
Select commit
Hold shift + click to select a range
d2a36d9
Add `test_pass_std_vector_int()`, `test_pass_std_set_int()` in test_stl
rwgk 7d30378
Change `list_caster` to also accept generator objects (`PyGen_Check(s…
rwgk 039d1b7
Drop in (currently unpublished) PyCLIF code, use in `list_caster`, ad…
rwgk bdba857
Use `PyObjectTypeIsConvertibleToStdSet()` in `set_caster`, adjust tests.
rwgk ec50ca0
Use `PyObjectTypeIsConvertibleToStdMap()` in `map_caster`, add tests.
rwgk eeb59af
Simplify `list_caster` `load()` implementation, push str/bytes check …
rwgk 3631886
clang-tidy cleanup with a few extra `(... != 0)` to be more consistent.
rwgk b4f767b
Also use `PyObjectTypeIsConvertibleToStdVector()` in `array_caster`.
rwgk 42e22d7
Merge branch 'master' into list_caster_pass_generator
rwgk 9647a92
Merge branch 'master' into list_caster_pass_generator
rwgk 1ed90cf
Merge branch 'master' into list_caster_pass_generator
rwgk 3cc034b
Update comment pointing to clif/python/runtime.cc (code is unchanged).
rwgk 18c4153
Merge branch 'master' into list_caster_pass_generator
rwgk e7330f2
Comprehensive test coverage, enhanced set_caster load implementation.
rwgk da29bf5
Resolve clang-tidy eror.
rwgk 1fa338e
Add a long C++ comment explaining what led to the `PyObjectTypeIsConv…
rwgk 6b5c780
Minor function name change in test.
rwgk 9150a88
Merge branch 'master' into list_caster_pass_generator
rwgk 62fda81
Merge branch 'master' into list_caster_pass_generator
rwgk 4b25f74
strcmp -> std::strcmp (thanks @Skylion007 for catching this)
rwgk 3cfc95b
Add `PyCallable_Check(items)` in `PyObjectTypeIsConvertibleToStdMap()`
rwgk 59509f2
Resolve clang-tidy error
rwgk 903faac
Merge branch 'master' into list_caster_pass_generator
rwgk 4ab40d7
Use `PyMapping_Items()` instead of `src.attr("items")()`, to be inter…
rwgk 5f7c9d4
Update link to PyCLIF sources.
rwgk ccfeb02
Fix typo (thanks @wangxf123456 for catching this)
rwgk 6c1ec6a
Merge branch 'master' into list_caster_pass_generator
rwgk cc4d69c
Merge branch 'master' into list_caster_pass_generator
rwgk dacb827
Add `test_pass_std_vector_int()`, `test_pass_std_set_int()` in test_stl
rwgk 3fc2d2a
Change `list_caster` to also accept generator objects (`PyGen_Check(s…
rwgk ff0724f
Drop in (currently unpublished) PyCLIF code, use in `list_caster`, ad…
rwgk be02291
Use `PyObjectTypeIsConvertibleToStdSet()` in `set_caster`, adjust tests.
rwgk 0a79f55
Use `PyObjectTypeIsConvertibleToStdMap()` in `map_caster`, add tests.
rwgk ae95424
Simplify `list_caster` `load()` implementation, push str/bytes check …
rwgk 8aa81d7
clang-tidy cleanup with a few extra `(... != 0)` to be more consistent.
rwgk 4435ed0
Also use `PyObjectTypeIsConvertibleToStdVector()` in `array_caster`.
rwgk 9aca5e8
Update comment pointing to clif/python/runtime.cc (code is unchanged).
rwgk 9dc7d7c
Comprehensive test coverage, enhanced set_caster load implementation.
rwgk d9eeea8
Resolve clang-tidy eror.
rwgk 9ac319b
Add a long C++ comment explaining what led to the `PyObjectTypeIsConv…
rwgk b834767
Minor function name change in test.
rwgk d19a0ff
strcmp -> std::strcmp (thanks @Skylion007 for catching this)
rwgk 69a0da8
Add `PyCallable_Check(items)` in `PyObjectTypeIsConvertibleToStdMap()`
rwgk c86fa97
Resolve clang-tidy error
rwgk 940e190
Use `PyMapping_Items()` instead of `src.attr("items")()`, to be inter…
rwgk f7725e4
Update link to PyCLIF sources.
rwgk fa72918
Fix typo (thanks @wangxf123456 for catching this)
rwgk a6b9a00
Merge branch 'list_caster_pass_generator' of https://github.com/rwgk/…
rwgk ac3ac4d
Merge branch 'master' into list_caster_pass_generator
rwgk 87ff92a
Merge branch 'master' into list_caster_pass_generator
rwgk 3ae34f3
Fix typo discovered by new version of codespell.
rwgk d1ffe4f
Merge branch 'master' into list_caster_pass_generator
rwgk 2267e5c
Merge branch 'master' into list_caster_pass_generator
rwgk a38d0bd
Merge branch 'master' into list_caster_pass_generator
rwgk fbf41fd
Merge branch 'master' into list_caster_pass_generator
rwgk File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
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.
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.
This requires explicit subclasses, rather than any object that conforms to
collections.abc.Sequence
? (Likewise forcollections.abc.Mapping
andcollections.abc.Set
below) The Pythonic way to do this would be to ask if the object has the methods required by these protocols, rather than checking explicit inheritance.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.
Specifically, from https://docs.python.org/3/library/collections.abc.html:
Sequence
:__getitem__
,__len__
,__contains__
,__iter__
,__reversed__
,index
, andcount
.Set
:__contains__
,__iter__
,__len__
,__le__
,__lt__
,__eq__
,__ne__
,__gt__
,__ge__
,__and__
,__or__
,__sub__
,__xor__
, andisdisjoint
.Mapping
:__getitem__
,__iter__
,__len__
,__contains__
,keys
,items
,values
,get
,__eq__
, and__ne__
.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.
In addition to what I wrote yesterday, there was actually another concern in the back of my mind: the current implementation is super fast, direct
strcmp
calls for 5 (vector
) of 1 (set
) very short string(s).In contrast,
hasattr
is far more complex and probably orders of magnitude slower, although I wouldn't really worry about it in the usual bigger context (it'll not even be a blip on the radar in most cases). The code extra code complexity is the bigger worry.So there is a code complexity and runtime overhead cost.
What is the benefit?
That brings me back to my "large-scale field experiment" experience hinted in the PR description. In a nutshell:
Current pybind11 is super restrictive.
Original PyCLIF was super permissive.
I had this huge pile of data from the wild contrasting the two. Based on that I could see very clearly that there is very little to gain from being more permissive than what this PR implements. IOW I don't think paying the code complexity and runtime overhead cost will help in any significant way.
Could you please let me know if you have a different opinion? — It will probably cost me a whole day worth of effort to implement and fully test (global testing) attribute inspection. We will also have to agree on what subsets of the attributes we actually want to test against. I expect that there will be some devils in the details.
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 think having a short path (check inheritance first) could alleviate much of the speed problem - the slower "correct" check could be done if this is not a subclass of X for common X. Also, this list is somewhat arbitrary - you probably included things (like
dict_keys
?dict_items
?) based on usage (in PyCLIF), rather than making a comprehensive list of everything iterable in Python? Also, I believe checking the attributes on a class (you don't need to check them on the instance) is pretty fast if you avoid the descriptor protocol (typing.runtime_checkable
switched to this in 3.12 (since 3.2) which made it much faster).From a usage standpoint, implementing the Protocol specified by these ABC's is supposed to make your class work wherever the standard library classes work, so it seems ideal if this could follow that. Not required (and we could start with this if you really want to), but it seems like the correct thing to do.
This is concretely specified in
collections.abc
. No arguments needed.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 agree. Which basically means: this PR plus follow-on work to make the check more permissive.
Do you think it's reasonable then to merge this PR, and do the fallback attribute inspection in a separate PR? — To be completely honest, I wouldn't want to prioritize this, for the reasons explained before. It a significant amount of work, extra code complexity, and I don't think very many people will ever notice the difference in practice. But if someone else wants to invest the effort, I'd be on board.
I see, sounds good to me, but from a purely practical viewpoint, assuming that most duck-typing only implements a subset of the attributes, insisting on the full set of attributes here probably means nobody will ever see a difference in practice, unless they are specifically looking to pass the checks here.