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 raise SymbolException("Symbol conflict: %r" % (symbol,))
125 elif name in self._symbols and self._symbols[name] != symbol:
126 raise SymbolException("Symbol identifier conflict: %r" % (name,))
127 self._symbols[name] = symbol
128
130 """
131 Get symbol table entry
132
133 :Parameters:
134 `name` : ``str``
135 Symbol identifier
136
137 :Return: The symbol
138 :Rtype: ``str``
139
140 :Exceptions:
141 - `KeyError` : Symbol not found
142 """
143 if _util.py2 and not isinstance(name, unicode):
144 name = str(name).decode('ascii')
145 return self._symbols[name]
146
148 """
149 Make item iterator
150
151 :Return: The iterator
152 :Rtype: iterable
153 """
154 return iter(list(self._symbols.items()))
155
156
158 """
159 Type container
160
161 :IVariables:
162 `_types` : ``dict``
163 Type map
164
165 `_symbols` : `Symbols`
166 Symbol table
167 """
168
170 """
171 Initialization
172
173 :Parameters:
174 `symbols` : `Symbols`
175 Symbol table
176 """
177 self._types = {}
178 self._symbols = symbols
179
181 """
182 Set type
183
184 :Parameters:
185 `class_` : ``type``
186 Type to match
187
188 `symbol` : ``str``
189 Type module symbol
190
191 :Exceptions:
192 - `SymbolException` : Type conflict
193 """
194 if class_ in self._types:
195 if self._types[class_] != symbol:
196 raise SymbolException("Type conflict: %r" % (symbol,))
197 else:
198 self._types[class_] = symbol
199
200 - def resolve(self, type_, dialect):
201 """
202 Resolve type to module symbol
203
204 :Parameters:
205 `type_` : ``object``
206 Type to resolve
207
208 `dialect` : ``str``
209 Dialect name
210
211 :Return: Resolved symbol
212 :Rtype: ``str``
213
214 :Exceptions:
215 - `SymbolException` : Type could not be resolved
216 """
217 if type_.__class__ in self._types:
218 return self._symbols[self._types[type_.__class__]]
219 for class_, symbol in self._types.items():
220 if isinstance(type_, class_):
221 return self._symbols[symbol]
222
223 mod = type_.__module__
224 if mod.startswith('sqlalchemy.'):
225 mod = '.'.join(mod.split('.')[:3])
226 if mod == 'sqlalchemy.dialects.%s' % dialect:
227 return self._symbols['type']
228 else:
229 try:
230 _load_dotted('sqlalchemy.dialects.%s.%s' % (
231 dialect, type_.__class__.__name__
232 ))
233 return self._symbols['type']
234 except ImportError:
235 pass
236 raise SymbolException(
237 "Don't know how to address type %r" % (type_,)
238 )
239
240
242 """
243 Import table
244
245 :IVariables:
246 `_imports` : ``list``
247 Import list
248 """
249
251 """ Initialization """
252 self._imports = list(imports or ())
253
255 """ Check if name is in imports """
256 for key, _ in self._imports:
257 if key == name:
258 return True
259 return False
260
262 """
263 Set import
264
265 :Parameters:
266 `name` : ``str``
267 Symbolic name (to support import uniqueness)
268
269 `import_` : ``str``
270 Import statement
271
272 :Exceptions:
273 - `SymbolException` : Import conflict
274 """
275 if _util.py2 and not isinstance(name, unicode):
276 name = str(name).decode('ascii')
277 imports = dict(self._imports)
278 if name in imports:
279 if imports[name] != import_:
280 raise SymbolException("Import conflict: %r: %r vs. %r" % (
281 name, imports[name], import_
282 ))
283 else:
284 self._imports.append((name, import_))
285
287 """
288 Make iterator over the import statements
289
290 :Return: The iterator
291 :Rtype: iterable
292 """
293 return iter(map(_op.itemgetter(1), self._imports))
294
295
297 """
298 Load a dotted name
299
300 (Stolen from wtf-server)
301
302 The dotted name can be anything, which is passively resolvable
303 (i.e. without the invocation of a class to get their attributes or
304 the like).
305
306 :Parameters:
307 `name` : ``str``
308 The dotted name to load
309
310 :Return: The loaded object
311 :Rtype: any
312
313 :Exceptions:
314 - `ImportError` : A module in the path could not be loaded
315 """
316 components = name.split('.')
317 path = [components.pop(0)]
318 obj = __import__(path[0])
319 while components:
320 comp = components.pop(0)
321 path.append(comp)
322 try:
323 obj = getattr(obj, comp)
324 except AttributeError:
325 __import__('.'.join(path))
326 try:
327 obj = getattr(obj, comp)
328 except AttributeError:
329 raise ImportError('.'.join(path))
330 return obj
331