Thanks to visit codestin.com
Credit goes to github.com

Skip to content

set declarative_base() / registry.declarative_base() as legacy, introduce new base class approach #7562

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

Closed
zzzeek opened this issue Jan 12, 2022 · 4 comments
Labels
alchemy 2 goes along with the 2.0 milestone to aid in searching declarative has to do with the declarative API, scanning classes and mixins for attributes to be mapped feature orm typing pep -484 typing issues. independent of "mypy"
Milestone

Comments

@zzzeek
Copy link
Member

zzzeek commented Jan 12, 2022

the declarative_base() function was a convenient approach at the time it was created, however it is not in line with current Python practices. The comments on python/typing#1020 indicate that typing tools have no plans to support this pattern in any way right now, and I also get the vibe, based on the comments, as well as that the actual mypy hook for dynamic classes refers to our own API as the example, that we are the only ones doing this in any prominent way.

on top of that, the declarative_base()'s reliance on metaclasses, which are usually unnecessary these days now that we have __init_subclass__(), has always been a burden on users who were often trying to use their own metaclasses, as well as that it caused problems we had to fix with end-user classes that used __init_subclass__() or __class_getitem__().

on top of that we already have many other ways to mark classes as mapped, most conveniently the @registry.mapped decorator.

However, having a Base class is still a very handy pattern, I still find myself preferring it, and the whole world uses it. We'd also like to get rid of the metaclass requirement without breaking backwards compatibility.

Turns out that with the current API and __init_subclass__(), making a new declarative base that isn't too much trouble is stupidly easy, though it does require two lines on the part of the end user rather than one to create, like this:

class DeclarativeBase(MappedBase):
    registry: ClassVar["registry"]
    metadata: ClassVar[MetaData]
    __mapper__: ClassVar[Mapper]
    __table__: Optional[FromClause]

    if typing.TYPE_CHECKING:
        def __init__(self, **kw: Any):
            ...

    def __init_subclass__(cls) -> None:
        if DeclarativeBase in cls.__bases__:
            cls.registry = registry()
            cls.metadata = cls.registry.metadata
        else:
            cls.registry.mapped(cls)

so end user code does:

from sqlalchemy.orm import DeclarativeBase

class Base(DeclarativeBase):
    pass

that's your Base. mypy no longer complains and you also have a nice place to put custom mixin logic (that works right now too).

so far there's two things we change in the API and we have basically everything we want, except for fully-typed init:

  1. mapped_column constructor
  2. new declarative base as above
@zzzeek zzzeek added feature orm declarative has to do with the declarative API, scanning classes and mixins for attributes to be mapped alchemy 2 goes along with the 2.0 milestone to aid in searching typing pep -484 typing issues. independent of "mypy" labels Jan 12, 2022
@zzzeek zzzeek added this to the 2.0 milestone Jan 12, 2022
@sqla-tester
Copy link
Collaborator

Mike Bayer referenced this issue:

WIP for ORM typing https://gerrit.sqlalchemy.org/c/sqlalchemy/sqlalchemy/+/3495

@jvanasco
Copy link
Member

We should compile a list of docs that need to be changed.

@CaselIT
Copy link
Member

CaselIT commented Jan 13, 2022

We should compile a list of docs that need to be changed.

Great idea!

sqlalchemy-bot pushed a commit that referenced this issue Jan 14, 2022
introduces:

1. new mapped_column() helper
2. DeclarativeBase helper
3. declared_attr has been re-typed
4. rework of Mapped[] to return InstrumentedAtribute for
   class get, so works without Mapped itself having expression
   methods
5. ORM constructs now generic on [_T]

also includes some early typing work, most of which will
be in later commits:

1. URL and History become typing.NamedTuple
2. come up with type-checking friendly way of type
   checking cy extensions, where type checking will be applied
   to the py versions, just needed to come up with a succinct
   conditional pattern for the imports

References: #6810
References: #7535
References: #7562
Change-Id: Ie5d9a44631626c021d130ca4ce395aba623c71fb
@zzzeek
Copy link
Member Author

zzzeek commented May 26, 2022

this is implemented, first revision can be seen at 4999784

docs for all the new declarative patterns will be one big job done separately.

@zzzeek zzzeek closed this as completed May 26, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
alchemy 2 goes along with the 2.0 milestone to aid in searching declarative has to do with the declarative API, scanning classes and mixins for attributes to be mapped feature orm typing pep -484 typing issues. independent of "mypy"
Projects
None yet
Development

No branches or pull requests

4 participants