Skip to content

Please make Column easier to subclass #2284

Closed
@sqlalchemy-bot

Description

@sqlalchemy-bot

Migrated issue, originally created by Anonymous

Hi everyone!

I'm writing my own ORM based on SQLAlchemy and I need to subclass sqlalchemy.schema.Column. The only issue I have is with copy() function. Now I have to copy-paste it to my code and fix it there.

I wanted to use something like:

class MyProperty(sqlalchemy.Column):
  ...
  def copy(self, **kw):
    c = super(MyProperty, self).copy(**kw)
    c.foo = self.foo
    ...
    return c

But in this case a copy will be of type sqlalchemy.Column instead of MyProperty. Is it possible to rewrite sqlalchemy.Column.copy() like this:

def copy(self, **kw):
        ...

        c = type(self)(
                name=self.name, 
                ...
                doc=self.doc,
                *args
                )
        c.dispatch._update(self.dispatch)
        return c

Can this be done in 0.7.x?

Activity

sqlalchemy-bot

sqlalchemy-bot commented on Sep 23, 2011

@sqlalchemy-bot
CollaboratorAuthor

Michael Bayer (@zzzeek) wrote:

what's your use case for subclassing Column ? I'd prefer to give you another way to do what you need.

sqlalchemy-bot

sqlalchemy-bot commented on Sep 23, 2011

@sqlalchemy-bot
CollaboratorAuthor

Changes by Michael Bayer (@zzzeek):

  • removed labels: bug
  • added labels: feature
  • set milestone to "0.7.xx"
sqlalchemy-bot

sqlalchemy-bot commented on Sep 23, 2011

@sqlalchemy-bot
CollaboratorAuthor

Anonymous wrote:

I'm creating network ORM and subclass Column to introduce additional introspection to it (7 more attributes). E.g.: is it hidden (from prospective of clients), more information on foreign keys and so on

sqlalchemy-bot

sqlalchemy-bot commented on Sep 23, 2011

@sqlalchemy-bot
CollaboratorAuthor

Michael Bayer (@zzzeek) wrote:

So what I can do for you here is in e4c0459, where an existing attribute _constructor is used to create the copy - this method defaults to self.__class__, equivalent to type(self) without the function call. _constructor is already used in the _make_proxy() function, which is similar to copy() except it is a much more important method as it is used very frequently within expression transformation - copy() is only used by the tometadata() utility system. it was likely an oversight that _constructor was not used here already. The unit test added mimics exactly the pattern you're asking for here.

That said, subclassing Column is a little dangerous. I would encourage you to at least store your extra state within the .info dictionary of Column, which is provided for end-user storage of extra attributes. If .info were good enough for you without the need for additional methods/accessors, you could skip the need to subclass Column and just use a function that puts what you want in .info.

It's also worth noting that the SQLAlchemy ORM adds lots of ORM-specific functionality column-bound attributes, but doesn't need to subclass Column itself, since it uses a proxy pattern via InstrumentedAttribute - which itself implements PropComparator to provide all of the column operators, and proxies those requests down to an actual Column. This pattern, that of composition/proxying rather than direct subclassing, allows a lot more trickery to go on at the ORM layer without being destablized by changes in the schema package.

Anyway that's my advice on that, the change committed should resolve the specific issue you're having with subclassing - good luck !

sqlalchemy-bot

sqlalchemy-bot commented on Sep 23, 2011

@sqlalchemy-bot
CollaboratorAuthor

Changes by Michael Bayer (@zzzeek):

  • changed milestone from "0.7.xx" to "0.7.3"
  • changed status to closed
sqlalchemy-bot

sqlalchemy-bot commented on Sep 23, 2011

@sqlalchemy-bot
CollaboratorAuthor

Michael Bayer (@zzzeek) wrote:

Oh I'd also note, you can subclass _constructor() itself too. That was the original idea behind that method - that subclassing _constructor() would eliminate the need to dig into copy() and particularly the _make_proxy() method:

class MyColumn(Column):
    def __init__(self, *arg, **kw):
        self.widget = kw.pop('widget', None)
        super(MyColumn, self).__init__(*arg, **kw)
    
    def _constructor(self):
        def copy(*arg, **kw):
            kw['widget']('widget') = self.widget
            return MyColumn(*arg, **kw)
        return copy
sqlalchemy-bot

sqlalchemy-bot commented on Sep 24, 2011

@sqlalchemy-bot
CollaboratorAuthor

Anonymous wrote:

Thank you, that should solve my problems. Also thank you for your notes!

Waiting for 0.7.3...

sqlalchemy-bot

sqlalchemy-bot commented on Nov 5, 2011

@sqlalchemy-bot
CollaboratorAuthor

Anonymous wrote:

Please note that your example is wrong, the correct one seems to be:

class MyColumn(Column):
    def __init__(self, *arg, **kw):
        self.widget = kw.pop('widget', None)
        super(MyColumn, self).__init__(*arg, **kw)
    
    def _constructor(self):
        kw['widget']('widget') = self.widget
        return MyColumn(*arg, **kw)
added
schemathings related to the DDL related objects like Table, Column, CreateIndex, etc.
on Nov 27, 2018
added this to the 0.7.3 milestone on Nov 27, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    featureschemathings related to the DDL related objects like Table, Column, CreateIndex, etc.

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @sqlalchemy-bot

        Issue actions

          Please make Column easier to subclass · Issue #2284 · sqlalchemy/sqlalchemy