1
2 r"""
3 ====================================
4 Type inspection and representation
5 ====================================
6
7 Type inspection and representation.
8
9 :Copyright:
10
11 Copyright 2010 - 2016
12 Andr\xe9 Malo or his licensors, as applicable
13
14 :License:
15
16 Licensed under the Apache License, Version 2.0 (the "License");
17 you may not use this file except in compliance with the License.
18 You may obtain a copy of the License at
19
20 http://www.apache.org/licenses/LICENSE-2.0
21
22 Unless required by applicable law or agreed to in writing, software
23 distributed under the License is distributed on an "AS IS" BASIS,
24 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
25 See the License for the specific language governing permissions and
26 limitations under the License.
27
28 """
29 if __doc__:
30
31 __doc__ = __doc__.encode('ascii').decode('unicode_escape')
32 __author__ = r"Andr\xe9 Malo".encode('ascii').decode('unicode_escape')
33 __docformat__ = "restructuredtext en"
34
35 import inspect as _inspect
36
37 import sqlalchemy as _sa
38
39 _have_signature = hasattr(_inspect, 'signature')
40
41
42 -class Type(object):
43 """
44 Type container
45
46 :IVariables:
47 `_ctype` : SA type
48 Column type
49
50 `_dialect` : ``str``
51 Dialect name
52
53 `_symbols` : ``Symbols``
54 Symbol table
55 """
56
57 - def __init__(self, ctype, dialect_name, symbols):
58 """
59 Initialization
60
61 :Parameters:
62 `ctype` : SA type
63 Column type
64
65 `dialect_name` : ``str``
66 Dialect name
67
68 `symbols` : ``Symbols``
69 Symbol table
70 """
71 self._ctype = ctype
72 self._dialect = dialect_name
73 self._symbols = symbols
74
75 @classmethod
77 """
78 Construct by SA column
79
80 :Parameters:
81 `column` : SA column
82 SA column
83
84 :Return: New Type instance
85 :Rtype: `Type`
86 """
87 return cls(
88 column.type,
89 column.table.metadata.bind.dialect.name,
90 symbols,
91 )
92
94 """
95 Make string representation
96
97 :Return: The string representation
98 :Rtype: ``str``
99 """
100
101
102 try:
103 try:
104 custom_repr = self._symbols.types.instance_repr[self._ctype]
105 except (KeyError, TypeError):
106 try:
107 custom_repr = self._symbols.types.instance_repr[
108 self._ctype.__class__
109 ]
110 except (KeyError, TypeError):
111 custom_repr = self._symbols.types.instance_repr[
112 self._ctype.__class__.__name__
113 ]
114 except (KeyError, TypeError):
115 pass
116 else:
117 return custom_repr(self._ctype, self._dialect, self._symbols)
118
119 mod = self._symbols.types.resolve(self._ctype, self._dialect)
120 params = []
121
122 if _have_signature:
123 try:
124
125 sign = _inspect.signature(self._ctype.__init__)
126 except (TypeError, ValueError):
127 pass
128 else:
129 varargs, kwds = None, False
130 for arg in sign.parameters.values():
131 if arg.kind == arg.VAR_POSITIONAL:
132 varargs = arg
133 continue
134 elif arg.kind == arg.VAR_KEYWORD:
135 continue
136
137 value = getattr(self._ctype, arg.name)
138 if arg.default is not arg.empty and arg.default == value:
139 kwds = arg.kind != arg.POSITIONAL_ONLY
140 continue
141 if isinstance(value, _sa.types.TypeEngine):
142 rvalue = repr(self.__class__(value, self._dialect,
143 self._symbols))
144 else:
145 rvalue = repr(value)
146
147 if kwds:
148 params.append('%s=%s' % (arg.name, rvalue))
149 else:
150 params.append(rvalue)
151 if not kwds and varargs is not None:
152 if _find_class(self._ctype, '__init__') is not \
153 _sa.types.TypeEngine:
154 params.extend(list(
155 map(repr, getattr(self._ctype, varargs.name, ()))
156 ))
157
158 else:
159 try:
160 spec = _inspect.getargspec(self._ctype.__init__)
161 except TypeError:
162 pass
163 else:
164 defaults = dict(zip(spec[0][::-1], (spec[3] or ())[::-1]))
165 kwds = False
166 for arg in spec[0][1:]:
167 value = getattr(self._ctype, arg)
168 if arg in defaults and defaults[arg] == value:
169 kwds = True
170 continue
171 if isinstance(value, _sa.types.TypeEngine):
172 rvalue = repr(self.__class__(value, self._dialect,
173 self._symbols))
174 else:
175 rvalue = repr(value)
176 if kwds:
177 params.append('%s=%s' % (arg, rvalue))
178 else:
179 params.append(rvalue)
180 if not kwds and spec[1] is not None:
181 if _find_class(self._ctype, '__init__') is not \
182 _sa.types.TypeEngine:
183 params.extend(list(
184 map(repr, getattr(self._ctype, spec[1]))
185 ))
186
187 params = ', '.join(params)
188 if params:
189 params = "(%s)" % (params,)
190 return "%s.%s%s" % (mod, self._ctype.__class__.__name__, params)
191
194 """
195 Find class where a method is defined
196
197 :Parameters:
198 `first_cls` : type
199 Class to start with
200
201 `name` : ``str``
202 Method name
203
204 :Return: class or ``None``
205 :Rtype: ``type``
206 """
207 if not isinstance(first_cls, type):
208 first_cls = first_cls.__class__
209
210 for cls in _inspect.getmro(first_cls):
211 if name in cls.__dict__:
212 return cls
213 return None
214