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

Handle X | Y union in GenericModel #4977

Merged
merged 5 commits into from Feb 6, 2023
Merged

Handle X | Y union in GenericModel #4977

merged 5 commits into from Feb 6, 2023

Conversation

thenx
Copy link

@thenx thenx commented Jan 23, 2023

Change Summary

The root cause of the issue is that X | Y has type types.UnionType which does not have __getitem__. This makes pydantic.generics.replace_types to fail with TypeError: 'type' object is not subscriptable.

In this PR we handle types.UnionType separately.

Related issue number

fix #4146

Peculiarities

  • Had to mute Do not compare types, use 'isinstance()' (E721)
  • For some reason there was no TypeError when running for the second time the code from the issue. Didn't investigate.

Checklist

  • Unit tests for the changes exist
  • Tests pass on CI and coverage remains at 100%
  • Documentation reflects the changes where applicable
  • changes/<pull request or issue id>-<github username>.md file added describing change
    (see changes/README.md for details)
  • My PR is ready to review, please add a comment including the phrase "please review" to assign reviewers

@thenx
Copy link
Author

thenx commented Jan 23, 2023

please review

Copy link
Member

@samuelcolvin samuelcolvin left a comment

Choose a reason for hiding this comment

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

Seems like a good start.

@dmontagu what do you think?

changes/4146-thenx.md Outdated Show resolved Hide resolved
@@ -853,6 +853,17 @@ class Model(GenericModel, Generic[T]):
# example)
assert replace_types(list[Union[str, list, T]], {T: int}) == list[Union[str, list, int]]

if sys.version_info >= (3, 10):
Copy link
Member

Choose a reason for hiding this comment

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

separate test with skipif please.

Copy link
Member

Choose a reason for hiding this comment

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

also, please can you add a standalone test for unions on a generic model.

There should be examples elsewhere of testing | style unions.

Copy link
Author

Choose a reason for hiding this comment

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

separate test with skipif please.

done

also, please can you add a standalone test for unions on a generic model.

There should be examples elsewhere of testing | style unions.

kinda done though i don't have a feeling that that's enough and might add some more later.

Copy link
Member

Choose a reason for hiding this comment

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

sounds good, let me know when it's done.

# PEP-604 syntax (Ex.: list | str) is represented with a types.UnionType object that does not have __getitem__.
# We also cannot use isinstance() since we have to compare types.
if sys.version_info >= (3, 10) and origin_type is types.UnionType: # noqa: E721
return functools.reduce(operator.or_, resolved_type_args)
Copy link
Member

Choose a reason for hiding this comment

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

this seems like a slightly weird approach, could we use pydantic.typing.convert_generics?

Copy link
Author

@thenx thenx Jan 23, 2023

Choose a reason for hiding this comment

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

I'll take a closer look at convert_generics, not sure how it fits, but i guess at least it can be recreated with typing._UnionGenericAlias as it's done in convert_generics.

Co-authored-by: ⬢ Samuel Colvin <s@muelcolvin.com>
@samuelcolvin
Copy link
Member

please update.

@thenx thenx marked this pull request as draft January 30, 2023 23:23
Copy link
Member

@samuelcolvin samuelcolvin left a comment

Choose a reason for hiding this comment

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

LGTM, @dmontagu would appreciate if you could confirm you're happy with this as "king of generics".

please review.

@dmontagu
Copy link
Contributor

@thenx Looks great.

The only one thing I'd like to request: could we add a test that there are no issues with order-of-arguments caching? My main concern is that since int | str == str | int we might one day refactor the generic cache lookup in a way that breaks things.

Basically just copying this test but using the X | Y syntax:

def test_generic_model_caching_detect_order_of_union_args_basic(create_module):
# Basic variant of https://github.com/pydantic/pydantic/issues/4474
@create_module
def module():
from typing import Generic, TypeVar, Union
from pydantic.generics import GenericModel
t = TypeVar('t')
class Model(GenericModel, Generic[t]):
data: t
int_or_float_model = Model[Union[int, float]]
float_or_int_model = Model[Union[float, int]]
assert type(int_or_float_model(data='1').data) is int
assert type(float_or_int_model(data='1').data) is float

No need to copy the (currently skipped) test below.

@samuelcolvin
Copy link
Member

LGTM, @thenx the PR is still in draft, if you think it's ready to be merged, please mark it as "ready for review".

@thenx thenx marked this pull request as ready for review January 31, 2023 17:27
@dmontagu dmontagu merged commit a699707 into pydantic:1.10.X-fixes Feb 6, 2023
renovate bot added a commit to allenporter/flux-local that referenced this pull request Feb 18, 2023
[![Mend
Renovate](https://app.renovatebot.com/images/banner.svg)](https://renovatebot.com)

This PR contains the following updates:

| Package | Change | Age | Adoption | Passing | Confidence |
|---|---|---|---|---|---|
| [pydantic](https://togithub.com/pydantic/pydantic) | `==1.10.4` ->
`==1.10.5` |
[![age](https://badges.renovateapi.com/packages/pypi/pydantic/1.10.5/age-slim)](https://docs.renovatebot.com/merge-confidence/)
|
[![adoption](https://badges.renovateapi.com/packages/pypi/pydantic/1.10.5/adoption-slim)](https://docs.renovatebot.com/merge-confidence/)
|
[![passing](https://badges.renovateapi.com/packages/pypi/pydantic/1.10.5/compatibility-slim/1.10.4)](https://docs.renovatebot.com/merge-confidence/)
|
[![confidence](https://badges.renovateapi.com/packages/pypi/pydantic/1.10.5/confidence-slim/1.10.4)](https://docs.renovatebot.com/merge-confidence/)
|

---

### Release Notes

<details>
<summary>pydantic/pydantic</summary>

###
[`v1.10.5`](https://togithub.com/pydantic/pydantic/releases/tag/v1.10.5):
(2023-02-15)

[Compare
Source](https://togithub.com/pydantic/pydantic/compare/v1.10.4...v1.10.5)

- Fix broken parametrized bases handling with `GenericModel`s with
complex sets of models,
[#&#8203;5052](https://togithub.com/pydantic/pydantic/issues/5052) by
[@&#8203;MarkusSintonen](https://togithub.com/MarkusSintonen)
- Invalidate mypy cache if plugin config changes,
[#&#8203;5007](https://togithub.com/pydantic/pydantic/issues/5007) by
[@&#8203;cdce8p](https://togithub.com/cdce8p)
- Fix `RecursionError` when deep-copying dataclass types wrapped by
pydantic,
[#&#8203;4949](https://togithub.com/pydantic/pydantic/issues/4949) by
[@&#8203;mbillingr](https://togithub.com/mbillingr)
- Fix `X | Y` union syntax breaking `GenericModel`,
[#&#8203;4146](https://togithub.com/pydantic/pydantic/issues/4146) by
[@&#8203;thenx](https://togithub.com/thenx)
- Switch coverage badge to show coverage for this branch/release,
[#&#8203;5060](https://togithub.com/pydantic/pydantic/issues/5060) by
[@&#8203;samuelcolvin](https://togithub.com/samuelcolvin)

#### New Contributors

- [@&#8203;thenx](https://togithub.com/thenx) made their first
contribution in
[pydantic/pydantic#4977
- [@&#8203;mbillingr](https://togithub.com/mbillingr) made their first
contribution in
[pydantic/pydantic#4963
- [@&#8203;MarkusSintonen](https://togithub.com/MarkusSintonen) made
their first contribution in
[pydantic/pydantic#5052

**Full Changelog**:
pydantic/pydantic@v1.10.4...v1.10.5

</details>

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined),
Automerge - At any time (no schedule defined).

🚦 **Automerge**: Enabled.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update
again.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR has been generated by [Mend
Renovate](https://www.mend.io/free-developer-tools/renovate/). View
repository job log
[here](https://app.renovatebot.com/dashboard#github/allenporter/flux-local).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzNC4xNDMuMSIsInVwZGF0ZWRJblZlciI6IjM0LjE0My4xIn0=-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
renovate bot added a commit to allenporter/pyrainbird that referenced this pull request Feb 18, 2023
[![Mend
Renovate](https://app.renovatebot.com/images/banner.svg)](https://renovatebot.com)

This PR contains the following updates:

| Package | Change | Age | Adoption | Passing | Confidence |
|---|---|---|---|---|---|
| [pydantic](https://togithub.com/pydantic/pydantic) | `==1.10.4` ->
`==1.10.5` |
[![age](https://badges.renovateapi.com/packages/pypi/pydantic/1.10.5/age-slim)](https://docs.renovatebot.com/merge-confidence/)
|
[![adoption](https://badges.renovateapi.com/packages/pypi/pydantic/1.10.5/adoption-slim)](https://docs.renovatebot.com/merge-confidence/)
|
[![passing](https://badges.renovateapi.com/packages/pypi/pydantic/1.10.5/compatibility-slim/1.10.4)](https://docs.renovatebot.com/merge-confidence/)
|
[![confidence](https://badges.renovateapi.com/packages/pypi/pydantic/1.10.5/confidence-slim/1.10.4)](https://docs.renovatebot.com/merge-confidence/)
|

---

### Release Notes

<details>
<summary>pydantic/pydantic</summary>

###
[`v1.10.5`](https://togithub.com/pydantic/pydantic/releases/tag/v1.10.5):
(2023-02-15)

[Compare
Source](https://togithub.com/pydantic/pydantic/compare/v1.10.4...v1.10.5)

- Fix broken parametrized bases handling with `GenericModel`s with
complex sets of models,
[#&#8203;5052](https://togithub.com/pydantic/pydantic/issues/5052) by
[@&#8203;MarkusSintonen](https://togithub.com/MarkusSintonen)
- Invalidate mypy cache if plugin config changes,
[#&#8203;5007](https://togithub.com/pydantic/pydantic/issues/5007) by
[@&#8203;cdce8p](https://togithub.com/cdce8p)
- Fix `RecursionError` when deep-copying dataclass types wrapped by
pydantic,
[#&#8203;4949](https://togithub.com/pydantic/pydantic/issues/4949) by
[@&#8203;mbillingr](https://togithub.com/mbillingr)
- Fix `X | Y` union syntax breaking `GenericModel`,
[#&#8203;4146](https://togithub.com/pydantic/pydantic/issues/4146) by
[@&#8203;thenx](https://togithub.com/thenx)
- Switch coverage badge to show coverage for this branch/release,
[#&#8203;5060](https://togithub.com/pydantic/pydantic/issues/5060) by
[@&#8203;samuelcolvin](https://togithub.com/samuelcolvin)

#### New Contributors

- [@&#8203;thenx](https://togithub.com/thenx) made their first
contribution in
[pydantic/pydantic#4977
- [@&#8203;mbillingr](https://togithub.com/mbillingr) made their first
contribution in
[pydantic/pydantic#4963
- [@&#8203;MarkusSintonen](https://togithub.com/MarkusSintonen) made
their first contribution in
[pydantic/pydantic#5052

**Full Changelog**:
pydantic/pydantic@v1.10.4...v1.10.5

</details>

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined),
Automerge - At any time (no schedule defined).

🚦 **Automerge**: Enabled.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update
again.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR has been generated by [Mend
Renovate](https://www.mend.io/free-developer-tools/renovate/). View
repository job log
[here](https://app.renovatebot.com/dashboard#github/allenporter/pyrainbird).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzNC4xNDMuMSIsInVwZGF0ZWRJblZlciI6IjM0LjE0My4xIn0=-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants