Sideboard SQLAlchemy models should have a sensible default str/repr
Closed this issue · 4 comments
If we have a SQLAlchemy class like
class Foo(Base):
bar = Column(Integer())
baz = Column(Unicode())
then it would be good if the str and repr result gave you something like
Foo(bar=5, baz=u'abc')
The main feature that we probably want is to be able to override the default fields displayed, e.g. by setting a _repr_fields class attribute.
I thought this was in, I'll talk with you offline
On Mon, Mar 24, 2014 at 6:42 PM, Eli Courtwright notifications@github.com
wrote:
If we have a SQLAlchemy class like
class Foo(Base): bar = Column(Integer()) baz = Column(Unicode())then it would be good if the str and repr result gave you something like
Foo(bar=5, baz=u'abc')The main feature that we probably want is to be able to override the default fields displayed, e.g. by setting a _repr_fields class attribute.
Reply to this email directly or view it on GitHub:
#14
class Base(object):
"""
Functionality generally useful for each Model class
"""
id = Column(Integer, primary_key=True)
_repr_attr_names = ()
_additional_repr_attr_names = ()
@classmethod
def _get_unique_constraint_column_names(cls):
"""
Utility function for getting and then caching the column names
associated with all the unique constraints for a given model object.
This assists in fetching an existing object using the value of unique
constraints in addition to the primary key of id.
"""
if not hasattr(cls, '_unique_constraint_attributes'):
cls._unique_constraint_attributes = [[column.name for column in constraint.columns]
for constraint in cls.__table__.constraints
if isinstance(constraint, UniqueConstraint)]
return cls._unique_constraint_attributes
@classmethod
def _get_primary_key_names(cls):
if not hasattr(cls, '_pk_names'):
cls._pk_names = [column.name for column in
cls.__table__.primary_key.columns]
return cls._pk_names
def __repr__(self):
"""
useful string representation for logging. Reprs do NOT return unicode,
since python decodes it using the default encoding:
http://bugs.python.org/issue5876
"""
# if no repr attr names have been set, default to the set of all
# unique constraints. This is unordered normally, so we'll order and
# use it here
if not self._repr_attr_names:
# this flattens the unique constraint list
_unique_attrs = itertools.chain.from_iterable(self._get_unique_constraint_column_names())
_primary_keys = self._get_primary_key_names()
attr_names = tuple(sorted(set(itertools.chain(_unique_attrs,
_primary_keys,
self._additional_repr_attr_names))))
else:
attr_names = self._repr_attr_names
if not attr_names:
# there should be SOMETHING, so id is a fallback
attr_names = ('id',)
# specifically using the string interpolation operator and the repr of
# getattr so as to avoid any "hilarious" encode errors for non-ascii
# characters
_kwarg_list = ' '.join('%s=%s' % (name, repr(getattr(self, name, 'undefined')))
for name in attr_names)
return ('<%s %s>' % (self.__class__.__name__, _kwarg_list)).encode('utf-8')
def to_dict(self):
"""
Convert the model object to a dictionary, based on the
_repr_attr_names attribute. It will recurse if the attribute is itself
a model object.
WARNING: it does not detect cycles.
"""
d = dict()
for name in self._repr_attr_names:
value = getattr(self, name, None)
if value is not None:
if hasattr(value, 'to_dict'):
d[name] = value.to_dict()
else:
d[name] = value
return d
the tests we had for this were generally subclasses of the Base classes being initialized and then asserting the repr
still need a specific unit test
I'm marking this as closed because it's been implemented, and while more unit tests would be nice, I don't think we need to hold this ticket open until we have them.