Please make Column easier to subclass
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?
Comments (8)
-
repo owner -
repo owner - marked as enhancement
- changed milestone to 0.7.xx
-
Account Deleted 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
-
repo owner So what I can do for you here is in e4c04590a6438f73278675e96dd84b57121eeb5f, where an existing attribute
_constructor
is used to create the copy - this method defaults toself.__class__
, equivalent totype(self)
without the function call._constructor
is already used in the_make_proxy()
function, which is similar tocopy()
except it is a much more important method as it is used very frequently within expression transformation -copy()
is only used by thetometadata()
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 ofColumn
, 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 subclassColumn
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 viaInstrumentedAttribute
- which itself implementsPropComparator
to provide all of the column operators, and proxies those requests down to an actualColumn
. 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 !
-
repo owner 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 intocopy()
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
-
Account Deleted Thank you, that should solve my problems. Also thank you for your notes!
Waiting for 0.7.3...
-
Account Deleted 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)
-
repo owner - removed milestone
Removing milestone: 0.7.3 (automated comment)
- Log in to comment
what's your use case for subclassing Column ? I'd prefer to give you another way to do what you need.