lnbits/lnurl

Upgrading to Pydantic 2

Opened this issue · 3 comments

I was trying to upgrade a project of mine which uses LNURL to Pydantic 2 and FastAPI 100 and I hit a snag.

I've tried going through the upgrade procedure on my own fork of this repo but I'm hitting a ton of errors when running the bump-pydantic tool (which worked nicely on a couple of my own projects).

https://docs.pydantic.dev/2.0/migration/

I'm not sure I have the skilz needed to make this work. Just wondering if anyone here has some advice?

As a stopgap/quick fix, could use the compat API that Pydantic v2 still provides? https://docs.pydantic.dev/2.0/migration/#continue-using-pydantic-v1-features

e.g. from pydantic.v1 import ConstrainedStr etc.?

I'm going to bump this again. I've tried going through and using pydantic.v1 and whilst that works for this library alone, when trying to use this in my own project post Pydantic v2 errors come thick and fast.

I think most of the problems come from the following but I'm struggling with how to fix this so that various parts of Json serialization and validation all work in the Pydantic v2 setting.

This is holding me back and I'm tearing my hair out. I suspect I will have to dump all reliance on LNURL library and recreate the functionality I need only.

class ReprMixin:
    def __repr__(self) -> str:
        attrs = [  # type: ignore
            outer_slot  # type: ignore
            for outer_slot in [slot for slot in self.__slots__ if not slot.startswith("_")]  # type: ignore
            if getattr(self, outer_slot)  # type: ignore
        ]  # type: ignore
        extra = ", " + ", ".join(f"{n}={getattr(self, n).__repr__()}" for n in attrs) if attrs else ""
        return f"{self.__class__.__name__}({super().__repr__()}{extra})"


class Bech32(ReprMixin, str):
    """Bech32 string."""

    __slots__ = ("hrp", "data")

    def __new__(cls, bech32: str, **_) -> "Bech32":
        return str.__new__(cls, bech32)

    def __init__(self, bech32: str, *, hrp: Optional[str] = None, data: Optional[List[int]] = None):
        str.__init__(bech32)
        self.hrp, self.data = (hrp, data) if hrp and data else self.__get_data__(bech32)

    @classmethod
    def __get_data__(cls, bech32: str) -> Tuple[str, List[int]]:
        return _bech32_decode(bech32)

    @classmethod
    def __get_validators__(cls):
        yield str_validator
        yield cls.validate

    @classmethod
    def validate(cls, value: str) -> "Bech32":
        hrp, data = cls.__get_data__(value)
        return cls(value, hrp=hrp, data=data)
dni commented

hey i would love to work on this, but i am still busy with other todos, but at some point this has to be done