This repository has been archived by the owner on Mar 8, 2018. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathattrs_sqlalchemy.py
69 lines (58 loc) · 2.38 KB
/
attrs_sqlalchemy.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
"""
Use `attrs <https://attrs.readthedocs.io>`_ to add ``__repr__``, ``__eq__``,
``__cmp__``, and ``__hash__`` methods according to the fields on a SQLAlchemy
model class.
"""
import warnings
import attr
from sqlalchemy import inspect
__version__ = '0.1.0'
__title__ = 'attrs_sqlalchemy'
__description__ = 'Add dunder-methods to SQLAlchemy models with attrs'
__uri__ = 'https://github.com/GoodRx/attrs_sqlalchemy'
__author__ = 'Andy Freeland'
__email__ = '[email protected]'
__license__ = 'MIT'
__copyright__ = 'Copyright (c) 2016 GoodRx'
__all__ = [
'attrs_sqlalchemy',
]
def attrs_sqlalchemy(maybe_cls=None):
"""
A class decorator that adds ``__repr__``, ``__eq__``, ``__cmp__``, and
``__hash__`` methods according to the fields defined on the SQLAlchemy
model class.
"""
def wrap(cls):
warnings.warn(UserWarning('attrs_sqlalchemy is deprecated'))
these = {
name: attr.ib()
# `__mapper__.columns` is a dictionary mapping field names on the
# model class to table columns. SQLAlchemy provides many ways to
# access the fields/columns, but this works at the time the class
# decorator is called:
#
# - We can't use `cls.__table__.columns` because that directly maps
# the column names rather than the field names on the model. For
# example, given `_my_field = Column('field', ...)`,
# `__table__.columns` will contain 'field' rather than '_my_field'.
#
# - We can't use `cls.__dict__`, where values are
# `InstrumentedAttribute`s, because that includes relationships,
# synonyms, and other features.
#
# - We can't use `cls.__mapper__.column_attrs`
# (or `sqlalchemy.inspect`) because they will attempt to
# initialize mappers for all of the classes in the registry,
# which won't be ready yet.
for name in inspect(cls).columns.keys()
}
return attr.s(cls, these=these, init=False)
# `maybe_cls` depends on the usage of the decorator. It's a class if it's
# used as `@attrs_sqlalchemy` but `None` if it's used as
# `@attrs_sqlalchemy()`
# ref: https://github.com/hynek/attrs/blob/15.2.0/src/attr/_make.py#L195
if maybe_cls is None:
return wrap
else:
return wrap(maybe_cls)