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

Pydantic v2 migration issue #99218

Closed
40 of 66 tasks
joostlek opened this issue Aug 28, 2023 · 61 comments · Fixed by DurgNomis-drol/mytoyota#269 or #131963
Closed
40 of 66 tasks

Pydantic v2 migration issue #99218

joostlek opened this issue Aug 28, 2023 · 61 comments · Fixed by DurgNomis-drol/mytoyota#269 or #131963

Comments

@joostlek
Copy link
Member

joostlek commented Aug 28, 2023

The problem

Pydantic released v2 of their library. Some libraries want to utilize the new features of Pydantic v2 so HA should update to Pydantic v2. To not burden all libraries to rework, Pydantic is providing v1 in a separate package of v2. This has been implemented in several libraries already made by some HA community members (https://github.com/AngellusMortis/pyunifiprotect/pull/297). This way the library supports both v1 and v2, this way of working is preferred to not burden the v2 upgrade with a lot of libraries to update at once.

After installing all dependencies and using pipdeptree we see that the current libraries use pydantic.

pydantic==1.10.12
├── aiolivisi==0.0.19 [requires: pydantic]
├── aionotion==2023.5.5 [requires: pydantic>=1.10.7,<2.0.0]
├── aioopenexchangerates==0.4.0 [requires: pydantic>=1.9,<2.0]
├── aiopurpleair==2022.12.1 [requires: pydantic>=1.10.2,<2.0.0]
├── aiowaqi==0.2.1 [requires: pydantic>=1.10.8]
├── demetriek==0.4.0 [requires: pydantic>=1.9.0,<2.0.0]
├── elgato==4.0.1 [requires: pydantic>=1.8.0,<2.0.0]
├── gcal-sync==4.1.4 [requires: pydantic>=1.9.0,<2.0a]
├── google-nest-sdm==2.2.5 [requires: pydantic>=1.10.4]
├── ical==5.0.1 [requires: pydantic>=1.9.1]
│   ├── gcal-sync==4.1.4 [requires: ical>=4.2.5]
│   └── pyrainbird==4.0.0 [requires: ical>=4.2.9]
├── inflect==6.0.4 [requires: pydantic>=1.9.1]
│   ├── jaraco.itertools==6.2.1 [requires: inflect]
│   │   └── jaraco.abode==3.3.0 [requires: jaraco.itertools]
│   └── jaraco.text==3.11.1 [requires: inflect]
│       ├── jaraco.collections==4.2.0 [requires: jaraco.text]
│       │   ├── jaraco.abode==3.3.0 [requires: jaraco.collections]
│       │   ├── jaraco.email==3.1.0 [requires: jaraco.collections]
│       │   │   └── jaraco.net==9.3.1 [requires: jaraco.email]
│       │   │       └── jaraco.abode==3.3.0 [requires: jaraco.net>=9]
│       │   └── jaraco.net==9.3.1 [requires: jaraco.collections]
│       │       └── jaraco.abode==3.3.0 [requires: jaraco.net>=9]
│       ├── jaraco.email==3.1.0 [requires: jaraco.text>=1.3]
│       │   └── jaraco.net==9.3.1 [requires: jaraco.email]
│       │       └── jaraco.abode==3.3.0 [requires: jaraco.net>=9]
│       └── jaraco.net==9.3.1 [requires: jaraco.text]
│           └── jaraco.abode==3.3.0 [requires: jaraco.net>=9]
├── intellifire4py==2.2.2 [requires: pydantic]
├── lacrosse-view==1.0.1 [requires: pydantic>=1.9.0]
├── open-meteo==0.2.1 [requires: pydantic>=1.8.0,<2.0.0]
├── peco==0.0.29 [requires: pydantic>=1.9.0]
├── pvo==1.0.0 [requires: pydantic>=1.8.0,<2.0.0]
├── pyaussiebb==0.0.15 [requires: pydantic>=1.9.0,<2.0.0]
├── pyrainbird==4.0.0 [requires: pydantic>=1.10.4]
├── python-bsblan==0.5.11 [requires: pydantic>=1.9.0]
├── python-kasa==0.5.3 [requires: pydantic>=1,<2]
├── python-opensky==0.2.0 [requires: pydantic>=1.10.8]
├── pytraccar==1.0.0 [requires: pydantic>=1,<2]
├── pyunifiprotect==4.10.6 [requires: pydantic!=1.9.1]
├── radios==0.1.1 [requires: pydantic>=1.9,<2.0]
├── sfrbox-api==0.0.6 [requires: pydantic>=1.10.2]
├── systembridgeconnector==3.4.9 [requires: pydantic>=1.9.0]
├── tailscale==0.2.0 [requires: pydantic>=1.8.0,<2.0.0]
├── vehicle==1.0.1 [requires: pydantic>=1.8.0,<2.0.0]
├── withings-api==2.4.0 [requires: pydantic>=1.7.2,<2.0.0]
├── xbox-webapi==2.0.11 [requires: pydantic]
├── yolink-api==0.3.0 [requires: pydantic>=1.9.0]
├── youtubeaio==1.1.5 [requires: pydantic>=1.10.8]
└── zwave-js-server-python==0.50.1 [requires: pydantic>=1.10.0]

This issue will be the progress tracker of this migration.

❌ aiolivisi Library: [aiolivisi](https://github.com/StefanIacobLivisi/aiolivisi) Integrations using this library: [Livisi](https://github.com/home-assistant/core/tree/dev/homeassistant/components/livisi) Code owners: @StefanIacobLivisi @planbnet

Remarks:

✔️ aionotion

Library: aionotion
Integrations using this library: Notion
Code owners: @bachya

Remarks:
There seems to be no version that supports both v1 and v2, so this library should be directly bumped with the v2 update.

✔️ aioopenexchangerates

--
Library: aioopenexchangerates
Integrations using this library: OpenExchangeRates
Code owners: @MartinHjelmare

Remarks:

❌ aiopurpleair

--
Library: aiopurpleair
Integrations using this library: PurpleAir
Code owners: @bachya

Remarks:
There seems to be no version that supports both v1 and v2, so this library should be directly bumped with the v2 update.

✔️ aiowaqi

--
Library: aiowaqi
Integrations using this library: WAQI
Code owners: @joostlek

Remarks:

❌ demetriek

--
Library: demetriek
Integrations using this library: lametric
Code owners: @robbiet480 @frenck @bachya

Remarks:

✔️ elgato

--
Library: elgato
Integrations using this library: elgato
Code owners: @frenck

Remarks:

✔️ gcal-sync

--
Library: gcal-sync
Integrations using this library: Google Calendar
Code owners: @allenporter

Remarks:
Supports shims. Needs a release so we can bump the dependency beforehand. Latest version also has ical 5.0.1, and that has pydantic v2 support since 5.0.0.

✔️ google-nest-sdm

--
Library: google-nest-sdm
Integrations using this library: Nest
Code owners: @allenporter

Remarks:

✔️ ical

--
Library: ical
Integrations using this library: Local calendar
Code owners: @allenporter

Remarks:

❌ inflect

--
Library: inflect
Integrations using this library: Abode
Code owners: @shred86

  • Supports Pydantic v2 (PR: )
  • Is updated in HA (PR: # )

Remarks:
This seems to be a deeper problem. I need to dive in to this to know the status.

❌ intellifire4py

--
Library: intellifire4py
Integrations using this library: IntelliFire
Code owners: @jeeftor

  • Supports Pydantic v2 (PR: )
  • Is updated in HA (PR: # )

Remarks:

❌ lacrosse-view

--
Library: lacrosse-view
Integrations using this library: LaCrosse View
Code owners: @IceBotYT

  • Supports Pydantic v2 (PR: )
  • Is updated in HA (PR: # )

Remarks:

✔️ open-meteo

--
Library: open-meteo
Integrations using this library: Open Meteo
Code owners: @frenck

Remarks:
To verify: There has been no code change to support it, but in the lock file is 2.0.3 so I am expecting this works.
If this is as expected, it still needs a release and to be bumped.

❌ peco

--
Library: peco
Integrations using this library: PECO Outage Counter
Code owners: @IceBotYT

  • Supports Pydantic v2 (PR: )
  • Is updated in HA (PR: # )

Remarks:
There has been no explicit PR to fix support for v2. This might work but needs to be verified.

✔️ pvo

--
Library: pvo
Integrations using this library: PVOutput
Code owners: @frenck

Remarks:

❌ pyaussiebb

--
Library: pyaussiebb
Integrations using this library: Aussie Broadband
Code owners: @nickw444 @Bre77

Remarks:
Library does not support v1 shims. Should be bumped with the v2 bump.
cc @yaleman

✔️ pyrainbird

--
Library: pyrainbird
Integrations using this library: Rain Bird
Code owners: @konikvranik @allenporter

Remarks:
Still needs to update ical to =>5.0.0 as ical relies on pydantic as well.

✔️ python-bsblan

--
Library: python-bsblan
Integrations using this library: BSB-Lan
Code owners: @liudger

  • Supports Pydantic v2 (PR: )
  • Is updated in HA (PR: # )

Remarks:

✔️ python-kasa

--
Library: python-kasa
Integrations using this library: TP-Link Kasa Smart
Code owners: @rytilahti @TheGardenMonkey

Remarks:

✔️ python-opensky

--
Library: python-opensky
Integrations using this library: OpenSky Network
Code owners: @joostlek

Remarks:

✔️ pytraccar

--
Library: pytraccar
Integrations using this library: Traccar
Code owners: @ludeeus

Remarks:

✔️ pyunifiprotect

--
Library: pyunifiprotect
Integrations using this library: asd
Code owners: @AngellusMortis @bdraco

Remarks:

✔️ radios

--
Library: radios
Integrations using this library: Radio Browser
Code owners: @frenck

Remarks:

✔️ sfrbox-api

--
Library: sfrbox-api
Integrations using this library: SFR Box
Code owners: @epenet

Remarks:

❌ systembridgeconnector

--
Library: systembridgeconnector
Integrations using this library: System Bridge
Code owners: @timmo001

  • Supports Pydantic v2 (PR: )
  • Is updated in HA (PR: # )

Remarks:

✔️ tailscale

--
Library: tailscale
Integrations using this library: asd
Code owners: @frenck

Remarks:
To verify: There has been no code change to support it, but in the lock file is 2.0.3 so I am expecting this works.
If this is as expected, it still needs a release and to be bumped.

✔️ vehicle

--
Library: vehicle
Integrations using this library: RDW
Code owners: @frenck @joostlek

Remarks:

✔️ withings-api

--
Library: withings-api
Integrations using this library: Withings
Code owners: @vangorra

Remarks:
Is now/will be replaced with a new lib without pydantic

❌ xbox-webapi

--
Library: xbox-webapi
Integrations using this library: Xbox
Code owners: @hunterjm

  • Supports Pydantic v2 (PR: )
  • Is updated in HA (PR: # )

Remarks:

✔️ yolink-api

--
Library: yolink-api
Integrations using this library: YoLink
Code owners: @matrixd2

Remarks:

✔️ youtubeaio

--
Library: youtubeaio
Integrations using this library: YouTube
Code owners: @joostlek

  • Supports Pydantic v2 (PR: )
  • Is updated in HA (PR: # )

Remarks:

✔️ zwave-js-server-python

--
Library: zwave-js-server-python
Integrations using this library: Z-Wave
Code owners: @home-assistant/z-wave

Remarks:

--

For the core members, feel free to update where needed. For others, let us know if something has updated in a comment and we will update it.

cc @cdce8p

@frenck
Copy link
Member

frenck commented Aug 28, 2023

As also reported on Discord. But replying here as well, as I was tagged. I have no intention of supporting v2 of Pydantic in my libraries.

Instead, I might be re-evaluating the use of Pydantic overall.

../Frenck

@raman325
Copy link
Contributor

raman325 commented Aug 28, 2023

@frenck if you do find a good alternative please do share it here. Others may want to choose the same option. I have v2 semi working but since all the internals have changed and are IMO more complicated I haven't been interested much in investing time into it

@bachya
Copy link
Contributor

bachya commented Aug 28, 2023

A good reminder: one can retain the V1 standards while upgrading to the V2 library. This is an excellent way to unstick this PR without committing yourself to a complete upgrade (assuming they don't get rid of this path at some point).

https://docs.pydantic.dev/latest/migration/#continue-using-pydantic-v1-features

@frenck
Copy link
Member

frenck commented Aug 28, 2023

As far as I am aware, it doesn't support everything backward. As said, I have no plans of supporting V2 at this point, and I am not willing to spend any second on it until I have explored other options.

../Frenck

@frenck
Copy link
Member

frenck commented Nov 6, 2023

pydantic has been fully removed from tailscale and elgato (and thus no longer taking part in this issue).

@frenck
Copy link
Member

frenck commented Nov 6, 2023

pydantic has been fully removed from vehicle (RDW integration) and thus no longer taking part in this issue.

@joostlek
Copy link
Member Author

joostlek commented Nov 6, 2023

I've been checking all the boxes :)

@frenck
Copy link
Member

frenck commented Nov 6, 2023

Right, but those don't take part in the migration process. It simply aren't using Pydantic at all anymore.

@frenck
Copy link
Member

frenck commented Nov 7, 2023

pydantic has been fully removed from pvo (PVOutput integration) and thus no longer taking part in this issue.

@frenck
Copy link
Member

frenck commented Nov 7, 2023

pydantic has been fully removed from open-meteo and thus no longer taking part in this issue.
PR @ Core: #103613

@frenck
Copy link
Member

frenck commented Nov 7, 2023

pydantic has been fully removed from radios (Radio Browser integration) and thus no longer taking part in this issue.
PR @ Core: #103614

@frenck
Copy link
Member

frenck commented Nov 7, 2023

Man, what a liberating feeling! I should have learned about other options before using Pydantic in the first place. It would have saved me from many headaches now and in the past.

@raman325
Copy link
Contributor

raman325 commented Nov 8, 2023

@frenck Are you using mashumaro as a replacement? I ask because I don't see a way to use it to validate a dict based on a TypedDict which is what I am looking for, so may have to keep looking :/

@frenck
Copy link
Member

frenck commented Nov 9, 2024

I do not plan on adding support for Pydantic 2. As stated before. Sorry.

If anything I will move away from it, as I have done with all other packages. Hopefully, I can find some time to do so soon.

@bvanelli
Copy link
Contributor

bvanelli commented Nov 9, 2024

So do I have to do anything?

@jeeftor as far as I can tell not, if your tests run pydantic 2 then it should integrate fine.

I do not plan on adding support for Pydantic 2. As stated before. Sorry.

If anything I will move away from it, as I have done with all other packages. Hopefully, I can find some time to do so soon.

@frenck Of course I understand your point, but what about the proposal in my comment, what do you think?

@joostlek
Copy link
Member Author

joostlek commented Nov 9, 2024

I also want to add, this list has been outdated. I have been keeping an eye out for new integrations using the shims. But I'm sure I missed some

@frenck
Copy link
Member

frenck commented Nov 9, 2024

So do I have to do anything?

@jeeftor as far as I can tell not, if your tests run pydantic 2 then it should integrate fine.

I do not plan on adding support for Pydantic 2. As stated before. Sorry.

If anything I will move away from it, as I have done with all other packages. Hopefully, I can find some time to do so soon.

@frenck Of course I understand your point, but what about the proposal in my comment, what do you think?

I think replacing it with just dataclasses isn’t the right approach.

@bvanelli
Copy link
Contributor

Just to update, here is the updated list of dependencies using pipdeptree:

pydantic==1.10.18
├── aiolivisi==0.0.19 [requires: pydantic]
├── aiopurpleair==2022.12.1 [requires: pydantic>=1.10.2,<2.0.0]
├── anthropic==0.31.2 [requires: pydantic>=1.9.0,<3]
├── demetriek==0.4.0 [requires: pydantic>=1.9.0,<2.0.0]
├── elevenlabs==1.6.1 [requires: pydantic>=1.9.2]
├── gcal_sync==6.2.0 [requires: pydantic>=1.9.0]
├── google-generativeai==0.8.2 [requires: pydantic]
├── ical==8.2.0 [requires: pydantic>=1.9.1]
│   ├── aioautomower==2024.10.3 [requires: ical>=8.0.1]
│   ├── gcal_sync==6.2.0 [requires: ical>=6.1.0]
│   └── pyrainbird==6.0.1 [requires: ical>=4.2.9]
├── intellifire4py==4.1.9 [requires: pydantic>=1.10.8]
├── lacrosse_view==1.0.3 [requires: pydantic>=1.9.0,<3.0.0]
├── lektricowifi==0.0.43 [requires: pydantic>=1.10.17]
├── mozart_api==4.1.1.116.0 [requires: pydantic>=1.10]
├── openai==1.35.7 [requires: pydantic>=1.9.0,<3]
├── peco==0.0.30 [requires: pydantic>=1.9.0]
├── pyatv==0.15.1 [requires: pydantic>=1.10.10]
├── pyaussiebb==0.0.15 [requires: pydantic>=1.9.0,<2.0.0]
├── pykoplenti==1.2.2 [requires: pydantic~=1.10]
├── python-kasa==0.7.7 [requires: pydantic>=1.10.15]
├── pytouchlinesl==0.1.8 [requires: pydantic]
├── uiprotect==6.4.0 [requires: pydantic>=1.10.17]
├── weheat==2024.9.23 [requires: pydantic>=1.10.5,<2]
├── xbox-webapi==2.0.11 [requires: pydantic]
├── yolink-api==0.4.7 [requires: pydantic>=1.9.0]
├── youtubeaio==1.1.5 [requires: pydantic>=1.10.8]
└── zwave-js-server-python==0.59.0 [requires: pydantic>=1.10.0]

the new dependencies that seem problematic:

@bvanelli
Copy link
Contributor

One more small update, this time for pykoplenti, the upgrade via shims has been done and the new version is already updated on HA. Confirming just to be sure:

$ pip install pykoplenti
Collecting pykoplenti
  Downloading pykoplenti-1.3.0-py3-none-any.whl.metadata (5.8 kB)
...
Downloading pydantic-2.9.2-py3-none-any.whl (434 kB)

--
Library: pykoplenti
Integrations using this library: kostal_plenticore
Code owners: @stegm

@bvanelli
Copy link
Contributor

One more update! This time weheat has been made compatible with pydantic via shims. The dependency has already been upgraded on HA. Thanks for the quick responses and the HA upgrade @jesperraemaekers

--
Library: weheat
Integrations using this library: weheat
Code owners: @jesperraemaekers

@allenporter
Copy link
Contributor

allenporter commented Nov 28, 2024

This all seems very close...

I just reviewed the list and I believe this may be all that is left?

Anything else missing?

@bdraco
Copy link
Member

bdraco commented Nov 30, 2024

It looks like aiolivisi is abandoned and https://home.livisi.de/ is offline. While there is https://github.com/planbnet/livisi_unofficial for anyone holding on to these devices. It seems clear that aiolivisi is never going to be updated so we may want to drop the integration as the service has shutdown.

@bvanelli
Copy link
Contributor

The PR mentions these APIs will shut down too, so maybe something is already broken.

According to this source, Livisi shut down at the end of 2020, but I believe some of their devices still work offline, hence the reason why there is a fork.

As I mentioned in my comment above, I would propose for this library that we do a class patch in order for it to work (from my analysis, this should make the code fully compatible):

Code proposal
from aiolivisi.websocket import (
    Websocket as WebsocketDeprecated,
    EVENT_STATE_CHANGED,
    ON_STATE,
    VALUE,
    LivisiEvent,
    SET_POINT_TEMPERATURE,
    POINT_TEMPERATURE,
    TEMPERATURE,
    HUMIDITY,
    LUMINANCE,
    IS_REACHABLE,
    IS_OPEN,
    EVENT_BUTTON_PRESSED,
    KEY_INDEX,
    KEY_PRESS_LONG,
    KEY_PRESS_TYPE,
)
from pydantic import ValidationError
from typing import Callable


class Websocket(WebsocketDeprecated):
    async def consumer_handler(self, websocket, on_data: Callable):
        """Used when data is transmited using the websocket."""
        async for message in websocket:
            try:
                event_data = LivisiEvent.model_validate(message)
            except ValidationError:
                continue

            if "device" in event_data.source:
                event_data.source = event_data.source.replace("/device/", "")
            if event_data.properties is None:
                continue

            if event_data.type == EVENT_STATE_CHANGED:
                if ON_STATE in event_data.properties.keys():
                    event_data.onState = event_data.properties.get(ON_STATE)
                elif VALUE in event_data.properties.keys() and isinstance(event_data.properties.get(VALUE), bool):
                    event_data.onState = event_data.properties.get(VALUE)
                if SET_POINT_TEMPERATURE in event_data.properties.keys():
                    event_data.vrccData = event_data.properties.get(SET_POINT_TEMPERATURE)
                elif POINT_TEMPERATURE in event_data.properties.keys():
                    event_data.vrccData = event_data.properties.get(POINT_TEMPERATURE)
                elif TEMPERATURE in event_data.properties.keys():
                    event_data.vrccData = event_data.properties.get(TEMPERATURE)
                elif HUMIDITY in event_data.properties.keys():
                    event_data.vrccData = event_data.properties.get(HUMIDITY)
                if LUMINANCE in event_data.properties.keys():
                    event_data.luminance = event_data.properties.get(LUMINANCE)
                if IS_REACHABLE in event_data.properties.keys():
                    event_data.isReachable = event_data.properties.get(IS_REACHABLE)
                if IS_OPEN in event_data.properties.keys():
                    event_data.isOpen = event_data.properties.get(IS_OPEN)
            elif event_data.type == EVENT_BUTTON_PRESSED:
                if KEY_INDEX in event_data.properties.keys():
                    event_data.keyIndex = event_data.properties.get(KEY_INDEX)
                    event_data.isLongKeyPress = KEY_PRESS_LONG == event_data.properties.get(KEY_PRESS_TYPE)
            on_data(event_data)

Anything else missing?

As of now just the demetrik update. @frenck if you have some I would really appreciate if you could review all the PRs I've placed. I've split all unrelated changes into separate PRs described in frenck/python-demetriek#740 (comment). If those get merged then all the workflows and tests should pass on CI for the mashumaro upgrade.

@bdraco
Copy link
Member

bdraco commented Nov 30, 2024

As I mentioned in my comment above, I would propose for this library that we do a class patch in order for it to work (from my analysis, this should make the code fully compatible):

It would be a lot cleaner to fork the library, modify it and republish it under a new name

@joostlek
Copy link
Member Author

It seems clear that aiolivisi is never going to be updated so we may want to drop the integration as the service has shutdown.

The integration apparently is local, and HA is now one of the ways to keep controlling it. So I don't really feel like dropping it, also seeing that there are 237 active installations

@bdraco
Copy link
Member

bdraco commented Dec 6, 2024

I think demetriek is the only one left unless I missed one

@frenck
Copy link
Member

frenck commented Dec 6, 2024

Picking it up this weekend. Planned it last weekend, but unfortunately have experienced an NVMe going belly up on my dev machine.

../Frenck

@frenck
Copy link
Member

frenck commented Dec 9, 2024

Alright LaMetric PR is up here: #132765

Thanks for the help there @bvanelli appreciated ❤️

../Frenck

cdce8p pushed a commit to cdce8p/ha-core that referenced this issue Dec 10, 2024
@bvanelli
Copy link
Contributor

Nice, thanks to everyone who put work into this migration! 🎉

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet