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

Improve dataclass_json and _process_class type annotations #475

Conversation

ringohoffman
Copy link
Contributor

@ringohoffman ringohoffman commented Aug 19, 2023

Use typing.overload to differentiate the return type of dataclass_json based on whether _cls parameter is None or not.

This is motivated by fixing type issues in flytekit, which does not only use dataclass_json as a decorator.

from dataclasses import dataclass

from dataclasses_json.api import dataclass_json


@dataclass
class Point:
    x: int
    y: int


directly_wrapped = dataclass_json(Point)

reveal_type(directly_wrapped)
# Before:
# pyright: Type of "directly_wrapped" is "((cls: Any) -> Any) | Any"
# mypy: Revealed type is "Any"
# PyCharm: directly_wrapped: (cls: {to_json, from_json, to_dict, from_dict, schema, __init__, dataclass_json_config}) -> {to_json, from_json, to_dict, from_dict, schema, __init__, dataclass_json_config} | {to_json, from_json, to_dict, from_dict, schema, __init__, dataclass_json_config} = dataclass_json(Point)

# After:
# pyright: Type of "dataclass_json(Point)" is "type[Point]"
# mypy: Revealed type is "Type[a.Point]"
# PyCharm: directly_wrapped: Type[Point] = dataclass_json(Point)

indirectly_wrapped = dataclass_json()(Point)

reveal_type(indirectly_wrapped)
# Before:
# pyright: Type of "indirectly_wrapped" is "Any"
# mypy: Revealed type is "Any"
# PyCharm: indirectly_wrapped: {to_json, from_json, to_dict, from_dict, schema, __init__, dataclass_json_config} = dataclass_json()(Point)

# After:
# pyright: Type of "dataclass_json()(Point)" is "type[Point]"
# mypy: Revealed type is "Type[a.Point]"
# PyCharm: indirectly_wrapped: Type[Point] = dataclass_json()(Point)

####################################################################################################


@dataclass_json
@dataclass
class Point2:
    x: int
    y: int


reveal_type(Point2)
# Before:
# pyright: Type of "Point2" is "type[Point2]"
# mypy: Revealed type is "def (x: builtins.int, y: builtins.int) -> a.Point2"
# PyCharm: class Point2

# After:
# pyright: Type of "Point2" is "type[Point2]"
# mypy: Revealed type is "def (x: builtins.int, y: builtins.int) -> a.Point2"
# PyCharm: class Point2


####################################################################################################


@dataclass_json()
@dataclass
class Point3:
    x: int
    y: int

reveal_type(Point3)
# Before:
# pyright: Type of "Point3" is "type[Point3]"
# mypy: Revealed type is "def (x: builtins.int, y: builtins.int) -> a.Point3"
# PyCharm: class Point3

# After:
# pyright: Type of "Point3" is "type[Point3]"
# mypy: Revealed type is "def (x: builtins.int, y: builtins.int) -> a.Point3"
# PyCharm: class Point3

Use typing.overload to differentiate the return type of dataclass_json based on whether _cls parameter is None or not
@george-zubrienko
Copy link
Collaborator

Hi @ringohoffman! If you can provide additional information on how this change interacts with:

  • Pylance (VS code helper)
  • PyCharm editor
  • PyLint (adding a simple test step that runs pylint would be fine)
  • Pyright (adding a simple test step that runs pylint would fine)

This would significantly speed up the review process here, otherwise I'll have to try all these myself before I can review. Community had issues with this codepiece some time ago, so I have to be extra careful here. Also a sidenote, @overload functionality is not a very stable thing to rely on for such change, but let's put that aside and get basic checks done first.

@ringohoffman
Copy link
Contributor Author

What I had already posted were the changes you can see in VS Code using pylance/pyright. Pylance is a Visual Studio Code extension that uses pyright at its core for static type checking. I've gone ahead and added the before and after for PyCharm and mypy to the description as well.

adding a simple test step that runs pylint/pyright would be fine

What do you mean by this? Do you want me to add a GitHub Workflow step to run pyright and pylint?

When I run pyright on the dataclasses_json module, there are 25 pre-existing errors. This PR doesn't add to or resolve these errors. I don't think that adding a workflow step for this is feasible at this time. Moreover, I think the poor type-checking compatibility of the dataclass_json decorator would completely preclude us from enforcing no pyright errors on this codebase.

I don't see any typecheck warnings/errors when I run pylint on the code in my description, before or after. This PR does resolve a pylint warning for the unused LetterCase import in dataclasses_json/api.py since we are using it in the type hints now. Given that pylint didn't catch anything related to these changes, I see adding pylint to the workflow for this repository as a separate issue, but one that I would support.

Let me know how you want to move forward based on this and my updated description.

@george-zubrienko
Copy link
Collaborator

I think it's ok, however I'm curious if this works with IDE autocomplete? You snippets are runtime code, but autocomplete does not rely on reveal_type etc. Though people mainly complain about static type checkers, we had cases when they also want IDE autocomplete to work like it does when using a Mixin.

Other small question, we plan to deprecate this function in v1 API (coming soon). How does that affect you?

@ringohoffman
Copy link
Contributor Author

ringohoffman commented Aug 25, 2023

I think it's ok, however I'm curious if this works with IDE autocomplete? You snippets are runtime code, but autocomplete does not rely on reveal_type etc. Though people mainly complain about static type checkers, we had cases when they also want IDE autocomplete to work like it does when using a Mixin.

Other small question, we plan to deprecate this function in v1 API (coming soon). How does that affect you?

I don't think it's possible to make dataclass_json compatible with auto-complete. I think you have to choose the return type as either the wrapped type or as DataClassJsonMixin, but either way static type checkers will lose access to part of the actually available runtime methods. I asked the author of pyright how he would handle making this function static-typing friendly, and he had recommended to just use the mixin as a mixin instead of the decorator.

This doesn't impact me in any major way. I already migrated flytekit to use DataClassJsonMixin as a mixin instead of the dataclass_json decorator: flyteorg/flytekit#1801 They only use dataclass_json in that one place now: https://github.com/flyteorg/flytekit/blob/0a772f3621ce9bd1a3e3b2f1e691458f25a31876/flytekit/core/type_engine.py#L1549

@george-zubrienko
Copy link
Collaborator

This doesn't impact me in any major way. I already migrated flytekit to use DataClassJsonMixin

Good, though v1 deprecates both the Mixin and the annotation - check discussion in #442. Note that we'll release v1 alongside v0 and deprecation of v0 will take very long time so please do not be scared :) But it helps a lot for us to understand the use cases like the code snippet you referenced.

Thanks a lot for contribution, we have a bit of an issue with 3.7 rn, but I plan to go around it and release your commit in 0.6 in a few days.

@george-zubrienko george-zubrienko merged commit dd4c414 into lidatong:master Aug 25, 2023
9 checks passed
renovate bot referenced this pull request in ixm-one/pytest-cmake-presets Dec 10, 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 |
|---|---|---|---|---|---|
| [dataclasses-json](https://togithub.com/lidatong/dataclasses-json)
([changelog](https://togithub.com/lidatong/dataclasses-json/releases)) |
`^0.5.7` -> `^0.6.0` |
[![age](https://developer.mend.io/api/mc/badges/age/pypi/dataclasses-json/0.6.3?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![adoption](https://developer.mend.io/api/mc/badges/adoption/pypi/dataclasses-json/0.6.3?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![passing](https://developer.mend.io/api/mc/badges/compatibility/pypi/dataclasses-json/0.5.9/0.6.3?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![confidence](https://developer.mend.io/api/mc/badges/confidence/pypi/dataclasses-json/0.5.9/0.6.3?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|

---

> [!WARNING]
> Some dependencies could not be looked up. Check the warning logs for
more information.

---

### Release Notes

<details>
<summary>lidatong/dataclasses-json (dataclasses-json)</summary>

###
[`v0.6.3`](https://togithub.com/lidatong/dataclasses-json/releases/tag/v0.6.3)

[Compare
Source](https://togithub.com/lidatong/dataclasses-json/compare/v0.6.2...v0.6.3)

#### What's Changed

- Fixes catchall inheritance issue by
[@&#8203;jasonrock-a3](https://togithub.com/jasonrock-a3) in
[https://github.com/lidatong/dataclasses-json/pull/500](https://togithub.com/lidatong/dataclasses-json/pull/500)

#### New Contributors

- [@&#8203;jasonrock-a3](https://togithub.com/jasonrock-a3) made their
first contribution in
[https://github.com/lidatong/dataclasses-json/pull/500](https://togithub.com/lidatong/dataclasses-json/pull/500)

**Full Changelog**:
lidatong/dataclasses-json@v0.6.2...v0.6.3

###
[`v0.6.2`](https://togithub.com/lidatong/dataclasses-json/releases/tag/v0.6.2)

[Compare
Source](https://togithub.com/lidatong/dataclasses-json/compare/v0.6.1...v0.6.2)

#### What's Changed

- fix: allow using CatchAll with postponed evaluation of annotations by
[@&#8203;2ynn](https://togithub.com/2ynn) in
[https://github.com/lidatong/dataclasses-json/pull/490](https://togithub.com/lidatong/dataclasses-json/pull/490)
- Fix PEP 0673 before 3.11 by
[@&#8203;george-zubrienko](https://togithub.com/george-zubrienko) in
[https://github.com/lidatong/dataclasses-json/pull/487](https://togithub.com/lidatong/dataclasses-json/pull/487)
- fix mypy error when assigning to dataclass_json_config by
[@&#8203;MickaelBergem](https://togithub.com/MickaelBergem) in
[https://github.com/lidatong/dataclasses-json/pull/486](https://togithub.com/lidatong/dataclasses-json/pull/486)
- Fix an issue introduced with hetero tuple decode by
[@&#8203;george-zubrienko](https://togithub.com/george-zubrienko) in
[https://github.com/lidatong/dataclasses-json/pull/493](https://togithub.com/lidatong/dataclasses-json/pull/493)

#### New Contributors

- [@&#8203;2ynn](https://togithub.com/2ynn) made their first
contribution in
[https://github.com/lidatong/dataclasses-json/pull/490](https://togithub.com/lidatong/dataclasses-json/pull/490)
- [@&#8203;MickaelBergem](https://togithub.com/MickaelBergem) made their
first contribution in
[https://github.com/lidatong/dataclasses-json/pull/486](https://togithub.com/lidatong/dataclasses-json/pull/486)

**Full Changelog**:
lidatong/dataclasses-json@v0.6.1...v0.6.2

###
[`v0.6.1`](https://togithub.com/lidatong/dataclasses-json/releases/tag/v0.6.1)

[Compare
Source](https://togithub.com/lidatong/dataclasses-json/compare/v0.6.0...v0.6.1)

##### What's Changed

- Add links to make PyPI a better maintainer reference by
[@&#8203;pydanny](https://togithub.com/pydanny) in
[https://github.com/lidatong/dataclasses-json/pull/482](https://togithub.com/lidatong/dataclasses-json/pull/482)
- improve Union deserialization when "\__type" field specifier is not
present by [@&#8203;idbentley](https://togithub.com/idbentley) in
[https://github.com/lidatong/dataclasses-json/pull/478](https://togithub.com/lidatong/dataclasses-json/pull/478)

##### New Contributors

- [@&#8203;pydanny](https://togithub.com/pydanny) made their first
contribution in
[https://github.com/lidatong/dataclasses-json/pull/482](https://togithub.com/lidatong/dataclasses-json/pull/482)
- [@&#8203;idbentley](https://togithub.com/idbentley) made their first
contribution in
[https://github.com/lidatong/dataclasses-json/pull/478](https://togithub.com/lidatong/dataclasses-json/pull/478)

**Full Changelog**:
lidatong/dataclasses-json@v0.6.0...v0.6.1

###
[`v0.6.0`](https://togithub.com/lidatong/dataclasses-json/releases/tag/v0.6.0)

[Compare
Source](https://togithub.com/lidatong/dataclasses-json/compare/v0.5.14...v0.6.0)

##### What's Changed

- Improve dataclass_json and \_process_class type annotations by
[@&#8203;ringohoffman](https://togithub.com/ringohoffman) in
[https://github.com/lidatong/dataclasses-json/pull/475](https://togithub.com/lidatong/dataclasses-json/pull/475)
- Update Poetry version used for 3.7 test suite and change
Requires-Python boundary by
[@&#8203;george-zubrienko](https://togithub.com/george-zubrienko) in
[https://github.com/lidatong/dataclasses-json/pull/476](https://togithub.com/lidatong/dataclasses-json/pull/476)
- Fix for
[#&#8203;239](https://togithub.com/lidatong/dataclasses-json/issues/239):
Union inside List or Dict is not deserialized as the correspond… by
[@&#8203;pawelwilczewski](https://togithub.com/pawelwilczewski) in
[https://github.com/lidatong/dataclasses-json/pull/464](https://togithub.com/lidatong/dataclasses-json/pull/464)

Due to a behaviour change discovered in
[https://github.com/lidatong/dataclasses-json/issues/466](https://togithub.com/lidatong/dataclasses-json/issues/466)
and also as a matter of preparation for full deprecation of Py3.7, we
are bumping the minor version to 0.6.0. Most important change is that
since 0.5.9 builtins are coerced automatically without throwing an
exception. Please visit the issue for more info :)

##### New Contributors

- [@&#8203;ringohoffman](https://togithub.com/ringohoffman) made their
first contribution in
[https://github.com/lidatong/dataclasses-json/pull/475](https://togithub.com/lidatong/dataclasses-json/pull/475)
- [@&#8203;pawelwilczewski](https://togithub.com/pawelwilczewski) made
their first contribution in
[https://github.com/lidatong/dataclasses-json/pull/464](https://togithub.com/lidatong/dataclasses-json/pull/464)

**Full Changelog**:
lidatong/dataclasses-json@v0.5.15...v0.6.0

###
[`v0.5.14`](https://togithub.com/lidatong/dataclasses-json/releases/tag/v0.5.14)

[Compare
Source](https://togithub.com/lidatong/dataclasses-json/compare/v0.5.13...v0.5.14)

#### What's Changed

- Temporarily disable code coverage publish for fork PRs by
[@&#8203;george-zubrienko](https://togithub.com/george-zubrienko) in
[https://github.com/lidatong/dataclasses-json/pull/444](https://togithub.com/lidatong/dataclasses-json/pull/444)
- fix mashmallow fields.Tuple creation by
[@&#8203;healthmatrice](https://togithub.com/healthmatrice) in
[https://github.com/lidatong/dataclasses-json/pull/434](https://togithub.com/lidatong/dataclasses-json/pull/434)
- Allow the global config dictionary keys to also be Optional\[type] by
[@&#8203;sumnerevans](https://togithub.com/sumnerevans) in
[https://github.com/lidatong/dataclasses-json/pull/255](https://togithub.com/lidatong/dataclasses-json/pull/255)
- Fix global_config.mm_fields having no effect by
[@&#8203;sigmunau](https://togithub.com/sigmunau) in
[https://github.com/lidatong/dataclasses-json/pull/253](https://togithub.com/lidatong/dataclasses-json/pull/253)
- Fixes recursion bug related to enum flags by
[@&#8203;matt035343](https://togithub.com/matt035343) in
[https://github.com/lidatong/dataclasses-json/pull/447](https://togithub.com/lidatong/dataclasses-json/pull/447)
- Update Python version boundaries to include 3.12 by
[@&#8203;cdce8p](https://togithub.com/cdce8p) in
[https://github.com/lidatong/dataclasses-json/pull/449](https://togithub.com/lidatong/dataclasses-json/pull/449)

#### New Contributors

- [@&#8203;healthmatrice](https://togithub.com/healthmatrice) made their
first contribution in
[https://github.com/lidatong/dataclasses-json/pull/434](https://togithub.com/lidatong/dataclasses-json/pull/434)
- [@&#8203;sigmunau](https://togithub.com/sigmunau) made their first
contribution in
[https://github.com/lidatong/dataclasses-json/pull/253](https://togithub.com/lidatong/dataclasses-json/pull/253)
- [@&#8203;cdce8p](https://togithub.com/cdce8p) made their first
contribution in
[https://github.com/lidatong/dataclasses-json/pull/449](https://togithub.com/lidatong/dataclasses-json/pull/449)

**Full Changelog**:
lidatong/dataclasses-json@v0.5.13...v0.5.14

###
[`v0.5.13`](https://togithub.com/lidatong/dataclasses-json/releases/tag/v0.5.13)

[Compare
Source](https://togithub.com/lidatong/dataclasses-json/compare/v0.5.12...v0.5.13)

#### What's Changed

- Fixes bug related to Tuples defined with ellipsis by
[@&#8203;matt035343](https://togithub.com/matt035343) in
[https://github.com/lidatong/dataclasses-json/pull/440](https://togithub.com/lidatong/dataclasses-json/pull/440)
- Revert type hint in annotation call by
[@&#8203;george-zubrienko](https://togithub.com/george-zubrienko) in
[https://github.com/lidatong/dataclasses-json/pull/441](https://togithub.com/lidatong/dataclasses-json/pull/441)

**Full Changelog**:
lidatong/dataclasses-json@v0.5.12...v0.5.13

###
[`v0.5.12`](https://togithub.com/lidatong/dataclasses-json/releases/tag/v0.5.12)

[Compare
Source](https://togithub.com/lidatong/dataclasses-json/compare/v0.5.9...v0.5.12)

#### What's Changed

- Fix multiline scripts in CI by
[@&#8203;george-zubrienko](https://togithub.com/george-zubrienko) in
[https://github.com/lidatong/dataclasses-json/pull/439](https://togithub.com/lidatong/dataclasses-json/pull/439)

**Full Changelog**:
lidatong/dataclasses-json@v0.5.11...v0.5.12

</details>

---

### Configuration

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

🚦 **Automerge**: Enabled.

♻ **Rebasing**: Whenever PR is behind base branch, 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://developer.mend.io/github/ixm-one/pytest-cmake-presets).

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

---------

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

Successfully merging this pull request may close these issues.

2 participants