-
-
Notifications
You must be signed in to change notification settings - Fork 8.3k
py/objtype: Add basic __init_subclass__ metaclass support. #15511
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
Conversation
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@
## master #15511 +/- ##
=======================================
Coverage 98.43% 98.43%
=======================================
Files 161 161
Lines 21281 21302 +21
=======================================
+ Hits 20948 20969 +21
Misses 333 333 ☔ View full report in Codecov by Sentry. |
Code size report:
|
Thanks for this, it looks like a pretty useful feature (I've never used it myself though in CPython). Especially if MicroPython will never support full CPython metaclasses, this is a good (and more modern) approach to it. |
I'm currently looking to see how to address the issue with the init_subclass recursion now given #15533. |
Oh, that's interesting, that the fix in 15533 breaks this PR. I think 15533 is necessary and should be merged. It's a very simple fix and fixes an edge case that's very difficult to notice in a running program, let alone debug and work around. |
No, mostly it just makes one of the behavioral compromises in the original version of this PR obsolete and unnecessary -- since it was possible to fix that fairly quickly, merging the original half-measure is unnecessary. For that matter, it actually fixes cpydiff/core_class_initsubclass_recursive, so I'll be moving it back to tests -- though frustratingly, it wasn't quite enough to fix cpydiff/core_class_initsubclass_multi the way I'd originally hoped, even if I think I understand why now. I think the fix for that will be tweaking to |
Very good! Then merging #15533 is the right way to move forward.
Hmm, I'm not sure at this stage what the best option is... do what you think is best then we can review it. |
Signed-off-by: Anson Mansfield <amansfield@mantaro.com>
Signed-off-by: Anson Mansfield <amansfield@mantaro.com>
Signed-off-by: Anson Mansfield <amansfield@mantaro.com>
Signed-off-by: Anson Mansfield <amansfield@mantaro.com>
Signed-off-by: Anson Mansfield <amansfield@mantaro.com>
Signed-off-by: Anson Mansfield <amansfield@mantaro.com>
Signed-off-by: Anson Mansfield <amansfield@mantaro.com>
Signed-off-by: Anson Mansfield <amansfield@mantaro.com>
Signed-off-by: Anson Mansfield <amansfield@mantaro.com>
Signed-off-by: Anson Mansfield <amansfield@mantaro.com>
aebeeb8
to
8cf652d
Compare
Retracting in favor of further discussion and consensus about how to implement this part of PEP 487. |
Summary
This PR adds partial support for the
__init_subclass__
data model method defined in PEP487, and gates this added features behind a new feature flag,MICROPY_PY_METACLASSES
.While this PR does not implement "full" metaclasses, it does implement the main mechanism used in practice for most types of meta-class-like class customization.
The behavior implemented here varies from the CPython behavior for two reasons:
__init_subclass__
implementations are not able to recursively callsuper().__init_subclass__()
the way PEP487 specifies. Therefore, this implementation applies a workaround: instead of invoking__init_subclass__
only for the last base class, it invokes it on all direct base classes.__init_subclass__
currently has no kwargs functionality.This PR uses #15503 as its base to ensure the
__init_subclass__
code remains in the correct order with__set_name__
in order to match CPython. It also addsMICROPY_PY_METACLASSES
as an alternative condition for enabling #15503's functionality, for the rare cases of metaclass code that relies on__set_name__
class customization but doesn't need the per-lookup overhead of descriptors.Testing
This PR includes a test verifying this feature, and three cpydiff's precisely outlining the mismatch with CPython. I've also manually verified the functionality using the unix port.
Trade-offs and Alternatives
This increases code size, but only when the corresponding feature flag is enabled.