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