1
2 r"""
3 ===================
4 Symbol management
5 ===================
6
7 Symbol management.
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 keyword as _keyword
36 import operator as _op
37 import weakref as _weakref
38
39 from . import _util
40
41
44
45
47 """
48 Symbol table
49
50 :IVariables:
51 `_symbols` : ``dict``
52 Symbols
53
54 `imports` : `_Imports`
55 Import container
56
57 `types` : `_Types`
58 Type container
59 """
60
61 - def __init__(self, symbols=None, imports=None):
62 """
63 Initialization
64
65 :Parameters:
66 `symbols` : ``dict``
67 Initial symbols
68 """
69 self._symbols = {}
70 defaults = dict(
71 sa="_sa",
72 meta="m",
73 table="T",
74 type="t",
75 column="C",
76 default="D",
77 pk="PrimaryKey",
78 fk="ForeignKey",
79 uk="Unique",
80 constraints=(
81 __name__.rsplit('.', 1)[0] + '.constraints'
82 ),
83 )
84 self.imports = _Imports(imports=imports)
85 self.types = _Types(_weakref.proxy(self))
86 if symbols is None:
87 symbols = {}
88 else:
89 symbols = dict(symbols)
90 for key, value in defaults.items():
91 symbols.setdefault(key, value)
92 for name, symbol in dict(symbols).items():
93 self[name] = symbol
94
96 """ Remove symbol entry if available """
97 try:
98 del self._symbols[name]
99 except KeyError:
100 pass
101
103 """
104 Set symbol table entry
105
106 :Parameters:
107 `name` : ``str``
108 Symbol identifier
109
110 `symbol` : ``str``
111 Symbol
112
113 :Exceptions:
114 - `SymbolException` : Symbol could not be set because of some
115 conflict
116 """
117 if _util.py2 and not isinstance(name, unicode):
118 name = str(name).decode('ascii')
119 if _keyword.iskeyword(symbol):
120 raise SymbolException(
121 "Cannot use keyword %r as symbol" % (symbol,)
122 )
123 elif symbol in list(self._symbols.values()):
124 if name in self._symbols and self._symbols[name] != symbol:
125 raise SymbolException("Symbol conflict: %r" % (symbol,))
126 elif name in self._symbols and self._symbols[name] != symbol:
127 raise SymbolException("Symbol identifier conflict: %r" % (name,))
128 self._symbols[name] = symbol
129
131 """
132 Get symbol table entry
133
134 :Parameters:
135 `name` : ``str``
136 Symbol identifier
137
138 :Return: The symbol
139 :Rtype: ``str``
140
141 :Exceptions:
142 - `KeyError` : Symbol not found
143 """
144 if _util.py2 and not isinstance(name, unicode):
145 name = str(name).decode('ascii')
146 return self._symbols[name]
147
149 """
150 Check symbol table entry
151
152 :Parameters:
153 `name` : ``str``
154 Symbol identifier
155
156 :Return: The symbol
157 :Rtype: ``str``
158
159 :Exceptions:
160 - `KeyError` : Symbol not found
161 """
162 if _util.py2 and not isinstance(name, unicode):
163 name = str(name).decode('ascii')
164 return name in self._symbols
165
167 """
168 Make item iterator
169
170 :Return: The iterator
171 :Rtype: iterable
172 """
173 return iter(list(self._symbols.items()))
174
175
177 """
178 Type container
179
180 :IVariables:
181 `_types` : ``dict``
182 Type map
183
184 `_symbols` : `Symbols`
185 Symbol table
186 """
187
189 """
190 Initialization
191
192 :Parameters:
193 `symbols` : `Symbols`
194 Symbol table
195 """
196 self._types = {}
197 self._symbols = symbols
198 self.instance_repr = {}
199 self.defines = []
200
202 """
203 Set type
204
205 :Parameters:
206 `class_` : ``type``
207 Type to match
208
209 `symbol` : ``str``
210 Type module symbol
211
212 :Exceptions:
213 - `SymbolException` : Type conflict
214 """
215 if class_ in self._types:
216 if self._types[class_] != symbol:
217 raise SymbolException("Type conflict: %r" % (symbol,))
218 else:
219 self._types[class_] = symbol
220
221 - def resolve(self, type_, dialect):
222 """
223 Resolve type to module symbol
224
225 :Parameters:
226 `type_` : ``object``
227 Type to resolve
228
229 `dialect` : ``str``
230 Dialect name
231
232 :Return: Resolved symbol
233 :Rtype: ``str``
234
235 :Exceptions:
236 - `SymbolException` : Type could not be resolved
237 """
238 if type_.__class__ in self._types:
239 return self._symbols[self._types[type_.__class__]]
240 for class_, symbol in self._types.items():
241 if isinstance(type_, class_):
242 return self._symbols[symbol]
243
244 mod = type_.__module__
245 if mod.startswith('sqlalchemy.'):
246 mod = '.'.join(mod.split('.')[:3])
247 if mod == 'sqlalchemy.dialects.%s' % dialect:
248 return self._symbols['type']
249 else:
250 try:
251 _load_dotted('sqlalchemy.dialects.%s.%s' % (
252 dialect, type_.__class__.__name__
253 ))
254 return self._symbols['type']
255 except ImportError:
256 pass
257 raise SymbolException(
258 "Don't know how to address type %r" % (type_,)
259 )
260
261
263 """
264 Import table
265
266 :IVariables:
267 `_imports` : ``list``
268 Import list
269 """
270
272 """ Initialization """
273 self._imports = list(imports or ())
274
276 """ Check if name is in imports """
277 for key, _ in self._imports:
278 if key == name:
279 return True
280 return False
281
283 """
284 Set import
285
286 :Parameters:
287 `name` : ``str``
288 Symbolic name (to support import uniqueness)
289
290 `import_` : ``str``
291 Import statement
292
293 :Exceptions:
294 - `SymbolException` : Import conflict
295 """
296 if _util.py2 and not isinstance(name, unicode):
297 name = str(name).decode('ascii')
298 imports = dict(self._imports)
299 if name in imports:
300 if imports[name] != import_:
301 raise SymbolException("Import conflict: %r: %r vs. %r" % (
302 name, imports[name], import_
303 ))
304 else:
305 self._imports.append((name, import_))
306
308 """
309 Make iterator over the import statements
310
311 :Return: The iterator
312 :Rtype: iterable
313 """
314 return iter(map(_op.itemgetter(1), self._imports))
315
316
318 """
319 Load a dotted name
320
321 (Stolen from wtf-server)
322
323 The dotted name can be anything, which is passively resolvable
324 (i.e. without the invocation of a class to get their attributes or
325 the like).
326
327 :Parameters:
328 `name` : ``str``
329 The dotted name to load
330
331 :Return: The loaded object
332 :Rtype: any
333
334 :Exceptions:
335 - `ImportError` : A module in the path could not be loaded
336 """
337 components = name.split('.')
338 path = [components.pop(0)]
339 obj = __import__(path[0])
340 while components:
341 comp = components.pop(0)
342 path.append(comp)
343 try:
344 obj = getattr(obj, comp)
345 except AttributeError:
346 __import__('.'.join(path))
347 try:
348 obj = getattr(obj, comp)
349 except AttributeError:
350 raise ImportError('.'.join(path))
351 return obj
352