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 mod = self._symbols.types.resolve(self._ctype, self._dialect)
103 params = []
104
105 if _have_signature:
106 try:
107
108 sign = _inspect.signature(self._ctype.__init__)
109 except (TypeError, ValueError):
110 pass
111 else:
112 varargs, kwds = None, False
113 for arg in sign.parameters.values():
114 if arg.kind == arg.VAR_POSITIONAL:
115 varargs = arg
116 continue
117 elif arg.kind == arg.VAR_KEYWORD:
118 continue
119
120 value = getattr(self._ctype, arg.name)
121 if arg.default is not arg.empty and arg.default == value:
122 kwds = arg.kind != arg.POSITIONAL_ONLY
123 continue
124 if isinstance(value, _sa.types.TypeEngine):
125 rvalue = repr(self.__class__(value, self._dialect,
126 self._symbols))
127 else:
128 rvalue = repr(value)
129
130 if kwds:
131 params.append('%s=%s' % (arg.name, rvalue))
132 else:
133 params.append(rvalue)
134 if not kwds and varargs is not None:
135 if _find_class(self._ctype, '__init__') is not \
136 _sa.types.TypeEngine:
137 params.extend(list(
138 map(repr, getattr(self._ctype, varargs.name, ()))
139 ))
140
141 else:
142 try:
143 spec = _inspect.getargspec(self._ctype.__init__)
144 except TypeError:
145 pass
146 else:
147 defaults = dict(zip(spec[0][::-1], (spec[3] or ())[::-1]))
148 kwds = False
149 for arg in spec[0][1:]:
150 value = getattr(self._ctype, arg)
151 if arg in defaults and defaults[arg] == value:
152 kwds = True
153 continue
154 if isinstance(value, _sa.types.TypeEngine):
155 rvalue = repr(self.__class__(value, self._dialect,
156 self._symbols))
157 else:
158 rvalue = repr(value)
159 if kwds:
160 params.append('%s=%s' % (arg, rvalue))
161 else:
162 params.append(rvalue)
163 if not kwds and spec[1] is not None:
164 if _find_class(self._ctype, '__init__') is not \
165 _sa.types.TypeEngine:
166 params.extend(list(
167 map(repr, getattr(self._ctype, spec[1]))
168 ))
169
170 params = ', '.join(params)
171 if params:
172 params = "(%s)" % (params,)
173 return "%s.%s%s" % (mod, self._ctype.__class__.__name__, params)
174
177 """
178 Find class where a method is defined
179
180 :Parameters:
181 `first_cls` : type
182 Class to start with
183
184 `name` : ``str``
185 Method name
186
187 :Return: class or ``None``
188 :Rtype: ``type``
189 """
190 if not isinstance(first_cls, type):
191 first_cls = first_cls.__class__
192
193 for cls in _inspect.getmro(first_cls):
194 if name in cls.__dict__:
195 return cls
196 return None
197