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
Improve generic subclass support #2549
Improve generic subclass support #2549
Conversation
Codecov Report
@@ Coverage Diff @@
## master #2549 +/- ##
=========================================
Coverage 100.00% 100.00%
=========================================
Files 25 25
Lines 5109 5133 +24
Branches 1050 1059 +9
=========================================
+ Hits 5109 5133 +24
Continue to review full report at Codecov.
|
6ef9a8d
to
b731c84
Compare
test fastAPI is failling with: As far as I can tell that's not anything I could've incidentally broken. I'm not sure what the best way to proceed with it would be? |
adb7c8e
to
2d690f9
Compare
@diabolo-dan Don't worry you can have a rest for the CI! ;) |
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.
Some minor thoughts
050b132
to
26cba97
Compare
I notice that there was significant generic implementation done by @dmontagu , including the line:
Which is I believe the only concrete claim about the behaviour of reapplication of partially parameterised generic models. (namely extending from the former). This behaviour adds complexity to establishing parameterised bases, and makes for less (because a concrete type could be constructed through arbitrary many type variables). I also think it's less intuitive than always building from the base, (so that I'm just wondering if there was a particular reason for implementing it this way, or if it was just the simplest thing that met the requirements at the time. |
0bc3564
to
39d5566
Compare
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.
Honestly, generics.py
scares the hell out of me. I don't pretend to remember/understand everything in there and I barely ever (never?) use generics myself.
The only consolation is that this isn't part of core validation, just isinstance
checks. (I think?)
I've got a few notes and questions, but overall, and from what I can see it looks reasonable.
pydantic/generics.py
Outdated
elif cls in _assigned_parameters and base_model in _assigned_parameters: | ||
# cls is partially parameterised but not from base_model | ||
# e.g. cls = B[S], base_model = A[S] | ||
# B[S][int] should subclass A[int], (and will be transitively via B[int]) | ||
# but it's not viable to consistently subclass types with arbitrary construction | ||
# So don't attempt to include A[S][int] | ||
continue | ||
elif cls in _assigned_parameters and base_model not in _assigned_parameters: | ||
# cls is partially parameterized, base_model is original generic | ||
# e.g. cls = B[str, T], base_model = B[S, T] | ||
# Need to determine the mapping for the base_model parameters | ||
mapped_types: Parametrization = { | ||
key: typevars_map.get(value, value) for key, value in _assigned_parameters[cls].items() | ||
} | ||
yield from build_base_model(base_model, mapped_types) |
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.
can't these two cases be covered by
elif cls in _assigned_parameters:
if base_model in _assigned_parameters:
...
else:
...
?
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.
My thinking was that the 2 cases were in some sense only incidentally related, so it helped the clarity to have them as top level cases.
I've moved them back to being under a common _assigned_parameters
case.
please update. |
The type was incorrectly being picked up for this style of subclassing, and it can be regardless inferred through cls.
* Improve parameterisation explanation * fix typos * Alias Parameterisation type
* start docstring with newline. * Use None as default over empty tuple. Co-authored-by: Samuel Colvin <samcolvin@gmail.com>
9f1d7ab
to
b4a8841
Compare
please review. |
great, thank you. |
* Derive concrete subclasses for parameterised generics * Resolve type issues * Add negative assertions to generic subclass tests * Remove incorrect subclassing of partial. The type was incorrectly being picked up for this style of subclassing, and it can be regardless inferred through cls. * Apply feedback: * Improve parameterisation explanation * fix typos * Alias Parameterisation type * Apply suggestions from code review * start docstring with newline. * Use None as default over empty tuple. Co-authored-by: Samuel Colvin <samcolvin@gmail.com> * Combine _assigned_parameters cases in __paramaterized_bases__ of generics * Add description for the `_assigned_parameters` variable. Co-authored-by: Samuel Colvin <samcolvin@gmail.com> Co-authored-by: Samuel Colvin <s@muelcolvin.com>
Just a note for anyone watching this PR, this changes here I think have caused a memory build up, see #3829. To mitigate this, I've implemented (and will soon merge) #4083 which limits the size of Feedback on the PR welcome, but in order to include this fix in v1.9.1 I won't being waiting for feedback before merging - any further changes would need to be in another PR. |
Change Summary
Add parameterised subclasses to
__bases__
when constructing new parameterised classes, so thatA <: B => A[int] <: B[int]
.This helps to facilitate a use case based on abstract classes, and leads to less unexpected behaviour when comparing between concrete versions of classes.
Related issue number
fix #2007
Checklist
changes/<pull request or issue id>-<github username>.md
file added describing change(see changes/README.md for details)