Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/sqlalchemy/sql/base.py: 56%

642 statements  

« prev     ^ index     » next       coverage.py v7.2.7, created at 2023-06-07 06:35 +0000

1# sql/base.py 

2# Copyright (C) 2005-2023 the SQLAlchemy authors and contributors 

3# <see AUTHORS file> 

4# 

5# This module is part of SQLAlchemy and is released under 

6# the MIT License: https://www.opensource.org/licenses/mit-license.php 

7 

8"""Foundational utilities common to many sql modules. 

9 

10""" 

11 

12 

13import itertools 

14import operator 

15import re 

16 

17from . import roles 

18from . import visitors 

19from .traversals import HasCacheKey # noqa 

20from .traversals import HasCopyInternals # noqa 

21from .traversals import MemoizedHasCacheKey # noqa 

22from .visitors import ClauseVisitor 

23from .visitors import ExtendedInternalTraversal 

24from .visitors import InternalTraversal 

25from .. import exc 

26from .. import util 

27from ..util import HasMemoized 

28from ..util import hybridmethod 

29 

30 

31coercions = None 

32elements = None 

33type_api = None 

34 

35PARSE_AUTOCOMMIT = util.symbol("PARSE_AUTOCOMMIT") 

36NO_ARG = util.symbol("NO_ARG") 

37 

38 

39class Immutable(object): 

40 """mark a ClauseElement as 'immutable' when expressions are cloned.""" 

41 

42 _is_immutable = True 

43 

44 def unique_params(self, *optionaldict, **kwargs): 

45 raise NotImplementedError("Immutable objects do not support copying") 

46 

47 def params(self, *optionaldict, **kwargs): 

48 raise NotImplementedError("Immutable objects do not support copying") 

49 

50 def _clone(self, **kw): 

51 return self 

52 

53 def _copy_internals(self, **kw): 

54 pass 

55 

56 

57class SingletonConstant(Immutable): 

58 """Represent SQL constants like NULL, TRUE, FALSE""" 

59 

60 _is_singleton_constant = True 

61 

62 def __new__(cls, *arg, **kw): 

63 return cls._singleton 

64 

65 @classmethod 

66 def _create_singleton(cls): 

67 obj = object.__new__(cls) 

68 obj.__init__() 

69 

70 # for a long time this was an empty frozenset, meaning 

71 # a SingletonConstant would never be a "corresponding column" in 

72 # a statement. This referred to #6259. However, in #7154 we see 

73 # that we do in fact need "correspondence" to work when matching cols 

74 # in result sets, so the non-correspondence was moved to a more 

75 # specific level when we are actually adapting expressions for SQL 

76 # render only. 

77 obj.proxy_set = frozenset([obj]) 

78 cls._singleton = obj 

79 

80 

81def _from_objects(*elements): 

82 return itertools.chain.from_iterable( 

83 [element._from_objects for element in elements] 

84 ) 

85 

86 

87def _select_iterables(elements): 

88 """expand tables into individual columns in the 

89 given list of column expressions. 

90 

91 """ 

92 return itertools.chain.from_iterable( 

93 [c._select_iterable for c in elements] 

94 ) 

95 

96 

97def _generative(fn): 

98 """non-caching _generative() decorator. 

99 

100 This is basically the legacy decorator that copies the object and 

101 runs a method on the new copy. 

102 

103 """ 

104 

105 @util.decorator 

106 def _generative(fn, self, *args, **kw): 

107 """Mark a method as generative.""" 

108 

109 self = self._generate() 

110 x = fn(self, *args, **kw) 

111 assert x is None, "generative methods must have no return value" 

112 return self 

113 

114 decorated = _generative(fn) 

115 decorated.non_generative = fn 

116 return decorated 

117 

118 

119def _exclusive_against(*names, **kw): 

120 msgs = kw.pop("msgs", {}) 

121 

122 defaults = kw.pop("defaults", {}) 

123 

124 getters = [ 

125 (name, operator.attrgetter(name), defaults.get(name, None)) 

126 for name in names 

127 ] 

128 

129 @util.decorator 

130 def check(fn, *args, **kw): 

131 # make pylance happy by not including "self" in the argument 

132 # list 

133 self = args[0] 

134 args = args[1:] 

135 for name, getter, default_ in getters: 

136 if getter(self) is not default_: 

137 msg = msgs.get( 

138 name, 

139 "Method %s() has already been invoked on this %s construct" 

140 % (fn.__name__, self.__class__), 

141 ) 

142 raise exc.InvalidRequestError(msg) 

143 return fn(self, *args, **kw) 

144 

145 return check 

146 

147 

148def _clone(element, **kw): 

149 return element._clone(**kw) 

150 

151 

152def _expand_cloned(elements): 

153 """expand the given set of ClauseElements to be the set of all 'cloned' 

154 predecessors. 

155 

156 """ 

157 return itertools.chain(*[x._cloned_set for x in elements]) 

158 

159 

160def _cloned_intersection(a, b): 

161 """return the intersection of sets a and b, counting 

162 any overlap between 'cloned' predecessors. 

163 

164 The returned set is in terms of the entities present within 'a'. 

165 

166 """ 

167 all_overlap = set(_expand_cloned(a)).intersection(_expand_cloned(b)) 

168 return set( 

169 elem for elem in a if all_overlap.intersection(elem._cloned_set) 

170 ) 

171 

172 

173def _cloned_difference(a, b): 

174 all_overlap = set(_expand_cloned(a)).intersection(_expand_cloned(b)) 

175 return set( 

176 elem for elem in a if not all_overlap.intersection(elem._cloned_set) 

177 ) 

178 

179 

180class _DialectArgView(util.collections_abc.MutableMapping): 

181 """A dictionary view of dialect-level arguments in the form 

182 <dialectname>_<argument_name>. 

183 

184 """ 

185 

186 def __init__(self, obj): 

187 self.obj = obj 

188 

189 def _key(self, key): 

190 try: 

191 dialect, value_key = key.split("_", 1) 

192 except ValueError as err: 

193 util.raise_(KeyError(key), replace_context=err) 

194 else: 

195 return dialect, value_key 

196 

197 def __getitem__(self, key): 

198 dialect, value_key = self._key(key) 

199 

200 try: 

201 opt = self.obj.dialect_options[dialect] 

202 except exc.NoSuchModuleError as err: 

203 util.raise_(KeyError(key), replace_context=err) 

204 else: 

205 return opt[value_key] 

206 

207 def __setitem__(self, key, value): 

208 try: 

209 dialect, value_key = self._key(key) 

210 except KeyError as err: 

211 util.raise_( 

212 exc.ArgumentError( 

213 "Keys must be of the form <dialectname>_<argname>" 

214 ), 

215 replace_context=err, 

216 ) 

217 else: 

218 self.obj.dialect_options[dialect][value_key] = value 

219 

220 def __delitem__(self, key): 

221 dialect, value_key = self._key(key) 

222 del self.obj.dialect_options[dialect][value_key] 

223 

224 def __len__(self): 

225 return sum( 

226 len(args._non_defaults) 

227 for args in self.obj.dialect_options.values() 

228 ) 

229 

230 def __iter__(self): 

231 return ( 

232 "%s_%s" % (dialect_name, value_name) 

233 for dialect_name in self.obj.dialect_options 

234 for value_name in self.obj.dialect_options[ 

235 dialect_name 

236 ]._non_defaults 

237 ) 

238 

239 

240class _DialectArgDict(util.collections_abc.MutableMapping): 

241 """A dictionary view of dialect-level arguments for a specific 

242 dialect. 

243 

244 Maintains a separate collection of user-specified arguments 

245 and dialect-specified default arguments. 

246 

247 """ 

248 

249 def __init__(self): 

250 self._non_defaults = {} 

251 self._defaults = {} 

252 

253 def __len__(self): 

254 return len(set(self._non_defaults).union(self._defaults)) 

255 

256 def __iter__(self): 

257 return iter(set(self._non_defaults).union(self._defaults)) 

258 

259 def __getitem__(self, key): 

260 if key in self._non_defaults: 

261 return self._non_defaults[key] 

262 else: 

263 return self._defaults[key] 

264 

265 def __setitem__(self, key, value): 

266 self._non_defaults[key] = value 

267 

268 def __delitem__(self, key): 

269 del self._non_defaults[key] 

270 

271 

272@util.preload_module("sqlalchemy.dialects") 

273def _kw_reg_for_dialect(dialect_name): 

274 dialect_cls = util.preloaded.dialects.registry.load(dialect_name) 

275 if dialect_cls.construct_arguments is None: 

276 return None 

277 return dict(dialect_cls.construct_arguments) 

278 

279 

280class DialectKWArgs(object): 

281 """Establish the ability for a class to have dialect-specific arguments 

282 with defaults and constructor validation. 

283 

284 The :class:`.DialectKWArgs` interacts with the 

285 :attr:`.DefaultDialect.construct_arguments` present on a dialect. 

286 

287 .. seealso:: 

288 

289 :attr:`.DefaultDialect.construct_arguments` 

290 

291 """ 

292 

293 _dialect_kwargs_traverse_internals = [ 

294 ("dialect_options", InternalTraversal.dp_dialect_options) 

295 ] 

296 

297 @classmethod 

298 def argument_for(cls, dialect_name, argument_name, default): 

299 """Add a new kind of dialect-specific keyword argument for this class. 

300 

301 E.g.:: 

302 

303 Index.argument_for("mydialect", "length", None) 

304 

305 some_index = Index('a', 'b', mydialect_length=5) 

306 

307 The :meth:`.DialectKWArgs.argument_for` method is a per-argument 

308 way adding extra arguments to the 

309 :attr:`.DefaultDialect.construct_arguments` dictionary. This 

310 dictionary provides a list of argument names accepted by various 

311 schema-level constructs on behalf of a dialect. 

312 

313 New dialects should typically specify this dictionary all at once as a 

314 data member of the dialect class. The use case for ad-hoc addition of 

315 argument names is typically for end-user code that is also using 

316 a custom compilation scheme which consumes the additional arguments. 

317 

318 :param dialect_name: name of a dialect. The dialect must be 

319 locatable, else a :class:`.NoSuchModuleError` is raised. The 

320 dialect must also include an existing 

321 :attr:`.DefaultDialect.construct_arguments` collection, indicating 

322 that it participates in the keyword-argument validation and default 

323 system, else :class:`.ArgumentError` is raised. If the dialect does 

324 not include this collection, then any keyword argument can be 

325 specified on behalf of this dialect already. All dialects packaged 

326 within SQLAlchemy include this collection, however for third party 

327 dialects, support may vary. 

328 

329 :param argument_name: name of the parameter. 

330 

331 :param default: default value of the parameter. 

332 

333 .. versionadded:: 0.9.4 

334 

335 """ 

336 

337 construct_arg_dictionary = DialectKWArgs._kw_registry[dialect_name] 

338 if construct_arg_dictionary is None: 

339 raise exc.ArgumentError( 

340 "Dialect '%s' does have keyword-argument " 

341 "validation and defaults enabled configured" % dialect_name 

342 ) 

343 if cls not in construct_arg_dictionary: 

344 construct_arg_dictionary[cls] = {} 

345 construct_arg_dictionary[cls][argument_name] = default 

346 

347 @util.memoized_property 

348 def dialect_kwargs(self): 

349 """A collection of keyword arguments specified as dialect-specific 

350 options to this construct. 

351 

352 The arguments are present here in their original ``<dialect>_<kwarg>`` 

353 format. Only arguments that were actually passed are included; 

354 unlike the :attr:`.DialectKWArgs.dialect_options` collection, which 

355 contains all options known by this dialect including defaults. 

356 

357 The collection is also writable; keys are accepted of the 

358 form ``<dialect>_<kwarg>`` where the value will be assembled 

359 into the list of options. 

360 

361 .. versionadded:: 0.9.2 

362 

363 .. versionchanged:: 0.9.4 The :attr:`.DialectKWArgs.dialect_kwargs` 

364 collection is now writable. 

365 

366 .. seealso:: 

367 

368 :attr:`.DialectKWArgs.dialect_options` - nested dictionary form 

369 

370 """ 

371 return _DialectArgView(self) 

372 

373 @property 

374 def kwargs(self): 

375 """A synonym for :attr:`.DialectKWArgs.dialect_kwargs`.""" 

376 return self.dialect_kwargs 

377 

378 _kw_registry = util.PopulateDict(_kw_reg_for_dialect) 

379 

380 def _kw_reg_for_dialect_cls(self, dialect_name): 

381 construct_arg_dictionary = DialectKWArgs._kw_registry[dialect_name] 

382 d = _DialectArgDict() 

383 

384 if construct_arg_dictionary is None: 

385 d._defaults.update({"*": None}) 

386 else: 

387 for cls in reversed(self.__class__.__mro__): 

388 if cls in construct_arg_dictionary: 

389 d._defaults.update(construct_arg_dictionary[cls]) 

390 return d 

391 

392 @util.memoized_property 

393 def dialect_options(self): 

394 """A collection of keyword arguments specified as dialect-specific 

395 options to this construct. 

396 

397 This is a two-level nested registry, keyed to ``<dialect_name>`` 

398 and ``<argument_name>``. For example, the ``postgresql_where`` 

399 argument would be locatable as:: 

400 

401 arg = my_object.dialect_options['postgresql']['where'] 

402 

403 .. versionadded:: 0.9.2 

404 

405 .. seealso:: 

406 

407 :attr:`.DialectKWArgs.dialect_kwargs` - flat dictionary form 

408 

409 """ 

410 

411 return util.PopulateDict( 

412 util.portable_instancemethod(self._kw_reg_for_dialect_cls) 

413 ) 

414 

415 def _validate_dialect_kwargs(self, kwargs): 

416 # validate remaining kwargs that they all specify DB prefixes 

417 

418 if not kwargs: 

419 return 

420 

421 for k in kwargs: 

422 m = re.match("^(.+?)_(.+)$", k) 

423 if not m: 

424 raise TypeError( 

425 "Additional arguments should be " 

426 "named <dialectname>_<argument>, got '%s'" % k 

427 ) 

428 dialect_name, arg_name = m.group(1, 2) 

429 

430 try: 

431 construct_arg_dictionary = self.dialect_options[dialect_name] 

432 except exc.NoSuchModuleError: 

433 util.warn( 

434 "Can't validate argument %r; can't " 

435 "locate any SQLAlchemy dialect named %r" 

436 % (k, dialect_name) 

437 ) 

438 self.dialect_options[dialect_name] = d = _DialectArgDict() 

439 d._defaults.update({"*": None}) 

440 d._non_defaults[arg_name] = kwargs[k] 

441 else: 

442 if ( 

443 "*" not in construct_arg_dictionary 

444 and arg_name not in construct_arg_dictionary 

445 ): 

446 raise exc.ArgumentError( 

447 "Argument %r is not accepted by " 

448 "dialect %r on behalf of %r" 

449 % (k, dialect_name, self.__class__) 

450 ) 

451 else: 

452 construct_arg_dictionary[arg_name] = kwargs[k] 

453 

454 

455class CompileState(object): 

456 """Produces additional object state necessary for a statement to be 

457 compiled. 

458 

459 the :class:`.CompileState` class is at the base of classes that assemble 

460 state for a particular statement object that is then used by the 

461 compiler. This process is essentially an extension of the process that 

462 the SQLCompiler.visit_XYZ() method takes, however there is an emphasis 

463 on converting raw user intent into more organized structures rather than 

464 producing string output. The top-level :class:`.CompileState` for the 

465 statement being executed is also accessible when the execution context 

466 works with invoking the statement and collecting results. 

467 

468 The production of :class:`.CompileState` is specific to the compiler, such 

469 as within the :meth:`.SQLCompiler.visit_insert`, 

470 :meth:`.SQLCompiler.visit_select` etc. methods. These methods are also 

471 responsible for associating the :class:`.CompileState` with the 

472 :class:`.SQLCompiler` itself, if the statement is the "toplevel" statement, 

473 i.e. the outermost SQL statement that's actually being executed. 

474 There can be other :class:`.CompileState` objects that are not the 

475 toplevel, such as when a SELECT subquery or CTE-nested 

476 INSERT/UPDATE/DELETE is generated. 

477 

478 .. versionadded:: 1.4 

479 

480 """ 

481 

482 __slots__ = ("statement",) 

483 

484 plugins = {} 

485 

486 @classmethod 

487 def create_for_statement(cls, statement, compiler, **kw): 

488 # factory construction. 

489 

490 if statement._propagate_attrs: 

491 plugin_name = statement._propagate_attrs.get( 

492 "compile_state_plugin", "default" 

493 ) 

494 klass = cls.plugins.get( 

495 (plugin_name, statement._effective_plugin_target), None 

496 ) 

497 if klass is None: 

498 klass = cls.plugins[ 

499 ("default", statement._effective_plugin_target) 

500 ] 

501 

502 else: 

503 klass = cls.plugins[ 

504 ("default", statement._effective_plugin_target) 

505 ] 

506 

507 if klass is cls: 

508 return cls(statement, compiler, **kw) 

509 else: 

510 return klass.create_for_statement(statement, compiler, **kw) 

511 

512 def __init__(self, statement, compiler, **kw): 

513 self.statement = statement 

514 

515 @classmethod 

516 def get_plugin_class(cls, statement): 

517 plugin_name = statement._propagate_attrs.get( 

518 "compile_state_plugin", None 

519 ) 

520 

521 if plugin_name: 

522 key = (plugin_name, statement._effective_plugin_target) 

523 if key in cls.plugins: 

524 return cls.plugins[key] 

525 

526 # there's no case where we call upon get_plugin_class() and want 

527 # to get None back, there should always be a default. return that 

528 # if there was no plugin-specific class (e.g. Insert with "orm" 

529 # plugin) 

530 try: 

531 return cls.plugins[("default", statement._effective_plugin_target)] 

532 except KeyError: 

533 return None 

534 

535 @classmethod 

536 def _get_plugin_class_for_plugin(cls, statement, plugin_name): 

537 try: 

538 return cls.plugins[ 

539 (plugin_name, statement._effective_plugin_target) 

540 ] 

541 except KeyError: 

542 return None 

543 

544 @classmethod 

545 def plugin_for(cls, plugin_name, visit_name): 

546 def decorate(cls_to_decorate): 

547 cls.plugins[(plugin_name, visit_name)] = cls_to_decorate 

548 return cls_to_decorate 

549 

550 return decorate 

551 

552 

553class Generative(HasMemoized): 

554 """Provide a method-chaining pattern in conjunction with the 

555 @_generative decorator.""" 

556 

557 def _generate(self): 

558 skip = self._memoized_keys 

559 cls = self.__class__ 

560 s = cls.__new__(cls) 

561 if skip: 

562 # ensure this iteration remains atomic 

563 s.__dict__ = { 

564 k: v for k, v in self.__dict__.copy().items() if k not in skip 

565 } 

566 else: 

567 s.__dict__ = self.__dict__.copy() 

568 return s 

569 

570 

571class InPlaceGenerative(HasMemoized): 

572 """Provide a method-chaining pattern in conjunction with the 

573 @_generative decorator that mutates in place.""" 

574 

575 def _generate(self): 

576 skip = self._memoized_keys 

577 for k in skip: 

578 self.__dict__.pop(k, None) 

579 return self 

580 

581 

582class HasCompileState(Generative): 

583 """A class that has a :class:`.CompileState` associated with it.""" 

584 

585 _compile_state_plugin = None 

586 

587 _attributes = util.immutabledict() 

588 

589 _compile_state_factory = CompileState.create_for_statement 

590 

591 

592class _MetaOptions(type): 

593 """metaclass for the Options class.""" 

594 

595 def __init__(cls, classname, bases, dict_): 

596 cls._cache_attrs = tuple( 

597 sorted( 

598 d 

599 for d in dict_ 

600 if not d.startswith("__") 

601 and d not in ("_cache_key_traversal",) 

602 ) 

603 ) 

604 type.__init__(cls, classname, bases, dict_) 

605 

606 def __add__(self, other): 

607 o1 = self() 

608 

609 if set(other).difference(self._cache_attrs): 

610 raise TypeError( 

611 "dictionary contains attributes not covered by " 

612 "Options class %s: %r" 

613 % (self, set(other).difference(self._cache_attrs)) 

614 ) 

615 

616 o1.__dict__.update(other) 

617 return o1 

618 

619 

620class Options(util.with_metaclass(_MetaOptions)): 

621 """A cacheable option dictionary with defaults.""" 

622 

623 def __init__(self, **kw): 

624 self.__dict__.update(kw) 

625 

626 def __add__(self, other): 

627 o1 = self.__class__.__new__(self.__class__) 

628 o1.__dict__.update(self.__dict__) 

629 

630 if set(other).difference(self._cache_attrs): 

631 raise TypeError( 

632 "dictionary contains attributes not covered by " 

633 "Options class %s: %r" 

634 % (self, set(other).difference(self._cache_attrs)) 

635 ) 

636 

637 o1.__dict__.update(other) 

638 return o1 

639 

640 def __eq__(self, other): 

641 # TODO: very inefficient. This is used only in test suites 

642 # right now. 

643 for a, b in util.zip_longest(self._cache_attrs, other._cache_attrs): 

644 if getattr(self, a) != getattr(other, b): 

645 return False 

646 return True 

647 

648 def __repr__(self): 

649 # TODO: fairly inefficient, used only in debugging right now. 

650 

651 return "%s(%s)" % ( 

652 self.__class__.__name__, 

653 ", ".join( 

654 "%s=%r" % (k, self.__dict__[k]) 

655 for k in self._cache_attrs 

656 if k in self.__dict__ 

657 ), 

658 ) 

659 

660 @classmethod 

661 def isinstance(cls, klass): 

662 return issubclass(cls, klass) 

663 

664 @hybridmethod 

665 def add_to_element(self, name, value): 

666 return self + {name: getattr(self, name) + value} 

667 

668 @hybridmethod 

669 def _state_dict(self): 

670 return self.__dict__ 

671 

672 _state_dict_const = util.immutabledict() 

673 

674 @_state_dict.classlevel 

675 def _state_dict(cls): 

676 return cls._state_dict_const 

677 

678 @classmethod 

679 def safe_merge(cls, other): 

680 d = other._state_dict() 

681 

682 # only support a merge with another object of our class 

683 # and which does not have attrs that we don't. otherwise 

684 # we risk having state that might not be part of our cache 

685 # key strategy 

686 

687 if ( 

688 cls is not other.__class__ 

689 and other._cache_attrs 

690 and set(other._cache_attrs).difference(cls._cache_attrs) 

691 ): 

692 raise TypeError( 

693 "other element %r is not empty, is not of type %s, " 

694 "and contains attributes not covered here %r" 

695 % ( 

696 other, 

697 cls, 

698 set(other._cache_attrs).difference(cls._cache_attrs), 

699 ) 

700 ) 

701 return cls + d 

702 

703 @classmethod 

704 def from_execution_options( 

705 cls, key, attrs, exec_options, statement_exec_options 

706 ): 

707 """process Options argument in terms of execution options. 

708 

709 

710 e.g.:: 

711 

712 ( 

713 load_options, 

714 execution_options, 

715 ) = QueryContext.default_load_options.from_execution_options( 

716 "_sa_orm_load_options", 

717 { 

718 "populate_existing", 

719 "autoflush", 

720 "yield_per" 

721 }, 

722 execution_options, 

723 statement._execution_options, 

724 ) 

725 

726 get back the Options and refresh "_sa_orm_load_options" in the 

727 exec options dict w/ the Options as well 

728 

729 """ 

730 

731 # common case is that no options we are looking for are 

732 # in either dictionary, so cancel for that first 

733 check_argnames = attrs.intersection( 

734 set(exec_options).union(statement_exec_options) 

735 ) 

736 

737 existing_options = exec_options.get(key, cls) 

738 

739 if check_argnames: 

740 result = {} 

741 for argname in check_argnames: 

742 local = "_" + argname 

743 if argname in exec_options: 

744 result[local] = exec_options[argname] 

745 elif argname in statement_exec_options: 

746 result[local] = statement_exec_options[argname] 

747 

748 new_options = existing_options + result 

749 exec_options = util.immutabledict().merge_with( 

750 exec_options, {key: new_options} 

751 ) 

752 return new_options, exec_options 

753 

754 else: 

755 return existing_options, exec_options 

756 

757 

758class CacheableOptions(Options, HasCacheKey): 

759 @hybridmethod 

760 def _gen_cache_key(self, anon_map, bindparams): 

761 return HasCacheKey._gen_cache_key(self, anon_map, bindparams) 

762 

763 @_gen_cache_key.classlevel 

764 def _gen_cache_key(cls, anon_map, bindparams): 

765 return (cls, ()) 

766 

767 @hybridmethod 

768 def _generate_cache_key(self): 

769 return HasCacheKey._generate_cache_key_for_object(self) 

770 

771 

772class ExecutableOption(HasCopyInternals): 

773 _annotations = util.EMPTY_DICT 

774 

775 __visit_name__ = "executable_option" 

776 

777 _is_has_cache_key = False 

778 

779 def _clone(self, **kw): 

780 """Create a shallow copy of this ExecutableOption.""" 

781 c = self.__class__.__new__(self.__class__) 

782 c.__dict__ = dict(self.__dict__) 

783 return c 

784 

785 

786class Executable(roles.StatementRole, Generative): 

787 """Mark a :class:`_expression.ClauseElement` as supporting execution. 

788 

789 :class:`.Executable` is a superclass for all "statement" types 

790 of objects, including :func:`select`, :func:`delete`, :func:`update`, 

791 :func:`insert`, :func:`text`. 

792 

793 """ 

794 

795 supports_execution = True 

796 _execution_options = util.immutabledict() 

797 _bind = None 

798 _with_options = () 

799 _with_context_options = () 

800 

801 _executable_traverse_internals = [ 

802 ("_with_options", InternalTraversal.dp_executable_options), 

803 ( 

804 "_with_context_options", 

805 ExtendedInternalTraversal.dp_with_context_options, 

806 ), 

807 ("_propagate_attrs", ExtendedInternalTraversal.dp_propagate_attrs), 

808 ] 

809 

810 is_select = False 

811 is_update = False 

812 is_insert = False 

813 is_text = False 

814 is_delete = False 

815 is_dml = False 

816 

817 @property 

818 def _effective_plugin_target(self): 

819 return self.__visit_name__ 

820 

821 @_generative 

822 def options(self, *options): 

823 """Apply options to this statement. 

824 

825 In the general sense, options are any kind of Python object 

826 that can be interpreted by the SQL compiler for the statement. 

827 These options can be consumed by specific dialects or specific kinds 

828 of compilers. 

829 

830 The most commonly known kind of option are the ORM level options 

831 that apply "eager load" and other loading behaviors to an ORM 

832 query. However, options can theoretically be used for many other 

833 purposes. 

834 

835 For background on specific kinds of options for specific kinds of 

836 statements, refer to the documentation for those option objects. 

837 

838 .. versionchanged:: 1.4 - added :meth:`.Generative.options` to 

839 Core statement objects towards the goal of allowing unified 

840 Core / ORM querying capabilities. 

841 

842 .. seealso:: 

843 

844 :ref:`deferred_options` - refers to options specific to the usage 

845 of ORM queries 

846 

847 :ref:`relationship_loader_options` - refers to options specific 

848 to the usage of ORM queries 

849 

850 """ 

851 self._with_options += tuple( 

852 coercions.expect(roles.ExecutableOptionRole, opt) 

853 for opt in options 

854 ) 

855 

856 @_generative 

857 def _set_compile_options(self, compile_options): 

858 """Assign the compile options to a new value. 

859 

860 :param compile_options: appropriate CacheableOptions structure 

861 

862 """ 

863 

864 self._compile_options = compile_options 

865 

866 @_generative 

867 def _update_compile_options(self, options): 

868 """update the _compile_options with new keys.""" 

869 

870 self._compile_options += options 

871 

872 @_generative 

873 def _add_context_option(self, callable_, cache_args): 

874 """Add a context option to this statement. 

875 

876 These are callable functions that will 

877 be given the CompileState object upon compilation. 

878 

879 A second argument cache_args is required, which will be combined with 

880 the ``__code__`` identity of the function itself in order to produce a 

881 cache key. 

882 

883 """ 

884 self._with_context_options += ((callable_, cache_args),) 

885 

886 @_generative 

887 def execution_options(self, **kw): 

888 """Set non-SQL options for the statement which take effect during 

889 execution. 

890 

891 Execution options can be set on a per-statement or 

892 per :class:`_engine.Connection` basis. Additionally, the 

893 :class:`_engine.Engine` and ORM :class:`~.orm.query.Query` 

894 objects provide 

895 access to execution options which they in turn configure upon 

896 connections. 

897 

898 The :meth:`execution_options` method is generative. A new 

899 instance of this statement is returned that contains the options:: 

900 

901 statement = select(table.c.x, table.c.y) 

902 statement = statement.execution_options(autocommit=True) 

903 

904 Note that only a subset of possible execution options can be applied 

905 to a statement - these include "autocommit" and "stream_results", 

906 but not "isolation_level" or "compiled_cache". 

907 See :meth:`_engine.Connection.execution_options` for a full list of 

908 possible options. 

909 

910 .. seealso:: 

911 

912 :meth:`_engine.Connection.execution_options` 

913 

914 :meth:`_query.Query.execution_options` 

915 

916 :meth:`.Executable.get_execution_options` 

917 

918 """ 

919 if "isolation_level" in kw: 

920 raise exc.ArgumentError( 

921 "'isolation_level' execution option may only be specified " 

922 "on Connection.execution_options(), or " 

923 "per-engine using the isolation_level " 

924 "argument to create_engine()." 

925 ) 

926 if "compiled_cache" in kw: 

927 raise exc.ArgumentError( 

928 "'compiled_cache' execution option may only be specified " 

929 "on Connection.execution_options(), not per statement." 

930 ) 

931 self._execution_options = self._execution_options.union(kw) 

932 

933 def get_execution_options(self): 

934 """Get the non-SQL options which will take effect during execution. 

935 

936 .. versionadded:: 1.3 

937 

938 .. seealso:: 

939 

940 :meth:`.Executable.execution_options` 

941 """ 

942 return self._execution_options 

943 

944 @util.deprecated_20( 

945 ":meth:`.Executable.execute`", 

946 alternative="All statement execution in SQLAlchemy 2.0 is performed " 

947 "by the :meth:`_engine.Connection.execute` method of " 

948 ":class:`_engine.Connection`, " 

949 "or in the ORM by the :meth:`.Session.execute` method of " 

950 ":class:`.Session`.", 

951 ) 

952 def execute(self, *multiparams, **params): 

953 """Compile and execute this :class:`.Executable`.""" 

954 e = self.bind 

955 if e is None: 

956 label = ( 

957 getattr(self, "description", None) or self.__class__.__name__ 

958 ) 

959 msg = ( 

960 "This %s is not directly bound to a Connection or Engine. " 

961 "Use the .execute() method of a Connection or Engine " 

962 "to execute this construct." % label 

963 ) 

964 raise exc.UnboundExecutionError(msg) 

965 return e._execute_clauseelement( 

966 self, multiparams, params, util.immutabledict() 

967 ) 

968 

969 @util.deprecated_20( 

970 ":meth:`.Executable.scalar`", 

971 alternative="Scalar execution in SQLAlchemy 2.0 is performed " 

972 "by the :meth:`_engine.Connection.scalar` method of " 

973 ":class:`_engine.Connection`, " 

974 "or in the ORM by the :meth:`.Session.scalar` method of " 

975 ":class:`.Session`.", 

976 ) 

977 def scalar(self, *multiparams, **params): 

978 """Compile and execute this :class:`.Executable`, returning the 

979 result's scalar representation. 

980 

981 """ 

982 return self.execute(*multiparams, **params).scalar() 

983 

984 @property 

985 @util.deprecated_20( 

986 ":attr:`.Executable.bind`", 

987 alternative="Bound metadata is being removed as of SQLAlchemy 2.0.", 

988 enable_warnings=False, 

989 ) 

990 def bind(self): 

991 """Returns the :class:`_engine.Engine` or :class:`_engine.Connection` 

992 to 

993 which this :class:`.Executable` is bound, or None if none found. 

994 

995 This is a traversal which checks locally, then 

996 checks among the "from" clauses of associated objects 

997 until a bound engine or connection is found. 

998 

999 """ 

1000 if self._bind is not None: 

1001 return self._bind 

1002 

1003 for f in _from_objects(self): 

1004 if f is self: 

1005 continue 

1006 engine = f.bind 

1007 if engine is not None: 

1008 return engine 

1009 else: 

1010 return None 

1011 

1012 

1013class prefix_anon_map(dict): 

1014 """A map that creates new keys for missing key access. 

1015 

1016 Considers keys of the form "<ident> <name>" to produce 

1017 new symbols "<name>_<index>", where "index" is an incrementing integer 

1018 corresponding to <name>. 

1019 

1020 Inlines the approach taken by :class:`sqlalchemy.util.PopulateDict` which 

1021 is otherwise usually used for this type of operation. 

1022 

1023 """ 

1024 

1025 def __missing__(self, key): 

1026 (ident, derived) = key.split(" ", 1) 

1027 anonymous_counter = self.get(derived, 1) 

1028 self[derived] = anonymous_counter + 1 

1029 value = derived + "_" + str(anonymous_counter) 

1030 self[key] = value 

1031 return value 

1032 

1033 

1034class SchemaEventTarget(object): 

1035 """Base class for elements that are the targets of :class:`.DDLEvents` 

1036 events. 

1037 

1038 This includes :class:`.SchemaItem` as well as :class:`.SchemaType`. 

1039 

1040 """ 

1041 

1042 def _set_parent(self, parent, **kw): 

1043 """Associate with this SchemaEvent's parent object.""" 

1044 

1045 def _set_parent_with_dispatch(self, parent, **kw): 

1046 self.dispatch.before_parent_attach(self, parent) 

1047 self._set_parent(parent, **kw) 

1048 self.dispatch.after_parent_attach(self, parent) 

1049 

1050 

1051class SchemaVisitor(ClauseVisitor): 

1052 """Define the visiting for ``SchemaItem`` objects.""" 

1053 

1054 __traverse_options__ = {"schema_visitor": True} 

1055 

1056 

1057class ColumnCollection(object): 

1058 """Collection of :class:`_expression.ColumnElement` instances, 

1059 typically for 

1060 :class:`_sql.FromClause` objects. 

1061 

1062 The :class:`_sql.ColumnCollection` object is most commonly available 

1063 as the :attr:`_schema.Table.c` or :attr:`_schema.Table.columns` collection 

1064 on the :class:`_schema.Table` object, introduced at 

1065 :ref:`metadata_tables_and_columns`. 

1066 

1067 The :class:`_expression.ColumnCollection` has both mapping- and sequence- 

1068 like behaviors. A :class:`_expression.ColumnCollection` usually stores 

1069 :class:`_schema.Column` objects, which are then accessible both via mapping 

1070 style access as well as attribute access style. 

1071 

1072 To access :class:`_schema.Column` objects using ordinary attribute-style 

1073 access, specify the name like any other object attribute, such as below 

1074 a column named ``employee_name`` is accessed:: 

1075 

1076 >>> employee_table.c.employee_name 

1077 

1078 To access columns that have names with special characters or spaces, 

1079 index-style access is used, such as below which illustrates a column named 

1080 ``employee ' payment`` is accessed:: 

1081 

1082 >>> employee_table.c["employee ' payment"] 

1083 

1084 As the :class:`_sql.ColumnCollection` object provides a Python dictionary 

1085 interface, common dictionary method names like 

1086 :meth:`_sql.ColumnCollection.keys`, :meth:`_sql.ColumnCollection.values`, 

1087 and :meth:`_sql.ColumnCollection.items` are available, which means that 

1088 database columns that are keyed under these names also need to use indexed 

1089 access:: 

1090 

1091 >>> employee_table.c["values"] 

1092 

1093 

1094 The name for which a :class:`_schema.Column` would be present is normally 

1095 that of the :paramref:`_schema.Column.key` parameter. In some contexts, 

1096 such as a :class:`_sql.Select` object that uses a label style set 

1097 using the :meth:`_sql.Select.set_label_style` method, a column of a certain 

1098 key may instead be represented under a particular label name such 

1099 as ``tablename_columnname``:: 

1100 

1101 >>> from sqlalchemy import select, column, table 

1102 >>> from sqlalchemy import LABEL_STYLE_TABLENAME_PLUS_COL 

1103 >>> t = table("t", column("c")) 

1104 >>> stmt = select(t).set_label_style(LABEL_STYLE_TABLENAME_PLUS_COL) 

1105 >>> subq = stmt.subquery() 

1106 >>> subq.c.t_c 

1107 <sqlalchemy.sql.elements.ColumnClause at 0x7f59dcf04fa0; t_c> 

1108 

1109 :class:`.ColumnCollection` also indexes the columns in order and allows 

1110 them to be accessible by their integer position:: 

1111 

1112 >>> cc[0] 

1113 Column('x', Integer(), table=None) 

1114 >>> cc[1] 

1115 Column('y', Integer(), table=None) 

1116 

1117 .. versionadded:: 1.4 :class:`_expression.ColumnCollection` 

1118 allows integer-based 

1119 index access to the collection. 

1120 

1121 Iterating the collection yields the column expressions in order:: 

1122 

1123 >>> list(cc) 

1124 [Column('x', Integer(), table=None), 

1125 Column('y', Integer(), table=None)] 

1126 

1127 The base :class:`_expression.ColumnCollection` object can store 

1128 duplicates, which can 

1129 mean either two columns with the same key, in which case the column 

1130 returned by key access is **arbitrary**:: 

1131 

1132 >>> x1, x2 = Column('x', Integer), Column('x', Integer) 

1133 >>> cc = ColumnCollection(columns=[(x1.name, x1), (x2.name, x2)]) 

1134 >>> list(cc) 

1135 [Column('x', Integer(), table=None), 

1136 Column('x', Integer(), table=None)] 

1137 >>> cc['x'] is x1 

1138 False 

1139 >>> cc['x'] is x2 

1140 True 

1141 

1142 Or it can also mean the same column multiple times. These cases are 

1143 supported as :class:`_expression.ColumnCollection` 

1144 is used to represent the columns in 

1145 a SELECT statement which may include duplicates. 

1146 

1147 A special subclass :class:`.DedupeColumnCollection` exists which instead 

1148 maintains SQLAlchemy's older behavior of not allowing duplicates; this 

1149 collection is used for schema level objects like :class:`_schema.Table` 

1150 and 

1151 :class:`.PrimaryKeyConstraint` where this deduping is helpful. The 

1152 :class:`.DedupeColumnCollection` class also has additional mutation methods 

1153 as the schema constructs have more use cases that require removal and 

1154 replacement of columns. 

1155 

1156 .. versionchanged:: 1.4 :class:`_expression.ColumnCollection` 

1157 now stores duplicate 

1158 column keys as well as the same column in multiple positions. The 

1159 :class:`.DedupeColumnCollection` class is added to maintain the 

1160 former behavior in those cases where deduplication as well as 

1161 additional replace/remove operations are needed. 

1162 

1163 

1164 """ 

1165 

1166 __slots__ = "_collection", "_index", "_colset" 

1167 

1168 def __init__(self, columns=None): 

1169 object.__setattr__(self, "_colset", set()) 

1170 object.__setattr__(self, "_index", {}) 

1171 object.__setattr__(self, "_collection", []) 

1172 if columns: 

1173 self._initial_populate(columns) 

1174 

1175 def _initial_populate(self, iter_): 

1176 self._populate_separate_keys(iter_) 

1177 

1178 @property 

1179 def _all_columns(self): 

1180 return [col for (k, col) in self._collection] 

1181 

1182 def keys(self): 

1183 """Return a sequence of string key names for all columns in this 

1184 collection.""" 

1185 return [k for (k, col) in self._collection] 

1186 

1187 def values(self): 

1188 """Return a sequence of :class:`_sql.ColumnClause` or 

1189 :class:`_schema.Column` objects for all columns in this 

1190 collection.""" 

1191 return [col for (k, col) in self._collection] 

1192 

1193 def items(self): 

1194 """Return a sequence of (key, column) tuples for all columns in this 

1195 collection each consisting of a string key name and a 

1196 :class:`_sql.ColumnClause` or 

1197 :class:`_schema.Column` object. 

1198 """ 

1199 

1200 return list(self._collection) 

1201 

1202 def __bool__(self): 

1203 return bool(self._collection) 

1204 

1205 def __len__(self): 

1206 return len(self._collection) 

1207 

1208 def __iter__(self): 

1209 # turn to a list first to maintain over a course of changes 

1210 return iter([col for k, col in self._collection]) 

1211 

1212 def __getitem__(self, key): 

1213 try: 

1214 return self._index[key] 

1215 except KeyError as err: 

1216 if isinstance(key, util.int_types): 

1217 util.raise_(IndexError(key), replace_context=err) 

1218 else: 

1219 raise 

1220 

1221 def __getattr__(self, key): 

1222 try: 

1223 return self._index[key] 

1224 except KeyError as err: 

1225 util.raise_(AttributeError(key), replace_context=err) 

1226 

1227 def __contains__(self, key): 

1228 if key not in self._index: 

1229 if not isinstance(key, util.string_types): 

1230 raise exc.ArgumentError( 

1231 "__contains__ requires a string argument" 

1232 ) 

1233 return False 

1234 else: 

1235 return True 

1236 

1237 def compare(self, other): 

1238 """Compare this :class:`_expression.ColumnCollection` to another 

1239 based on the names of the keys""" 

1240 

1241 for l, r in util.zip_longest(self, other): 

1242 if l is not r: 

1243 return False 

1244 else: 

1245 return True 

1246 

1247 def __eq__(self, other): 

1248 return self.compare(other) 

1249 

1250 def get(self, key, default=None): 

1251 """Get a :class:`_sql.ColumnClause` or :class:`_schema.Column` object 

1252 based on a string key name from this 

1253 :class:`_expression.ColumnCollection`.""" 

1254 

1255 if key in self._index: 

1256 return self._index[key] 

1257 else: 

1258 return default 

1259 

1260 def __str__(self): 

1261 return "%s(%s)" % ( 

1262 self.__class__.__name__, 

1263 ", ".join(str(c) for c in self), 

1264 ) 

1265 

1266 def __setitem__(self, key, value): 

1267 raise NotImplementedError() 

1268 

1269 def __delitem__(self, key): 

1270 raise NotImplementedError() 

1271 

1272 def __setattr__(self, key, obj): 

1273 raise NotImplementedError() 

1274 

1275 def clear(self): 

1276 """Dictionary clear() is not implemented for 

1277 :class:`_sql.ColumnCollection`.""" 

1278 raise NotImplementedError() 

1279 

1280 def remove(self, column): 

1281 """Dictionary remove() is not implemented for 

1282 :class:`_sql.ColumnCollection`.""" 

1283 raise NotImplementedError() 

1284 

1285 def update(self, iter_): 

1286 """Dictionary update() is not implemented for 

1287 :class:`_sql.ColumnCollection`.""" 

1288 raise NotImplementedError() 

1289 

1290 __hash__ = None 

1291 

1292 def _populate_separate_keys(self, iter_): 

1293 """populate from an iterator of (key, column)""" 

1294 cols = list(iter_) 

1295 self._collection[:] = cols 

1296 self._colset.update(c for k, c in self._collection) 

1297 self._index.update( 

1298 (idx, c) for idx, (k, c) in enumerate(self._collection) 

1299 ) 

1300 self._index.update({k: col for k, col in reversed(self._collection)}) 

1301 

1302 def add(self, column, key=None): 

1303 """Add a column to this :class:`_sql.ColumnCollection`. 

1304 

1305 .. note:: 

1306 

1307 This method is **not normally used by user-facing code**, as the 

1308 :class:`_sql.ColumnCollection` is usually part of an existing 

1309 object such as a :class:`_schema.Table`. To add a 

1310 :class:`_schema.Column` to an existing :class:`_schema.Table` 

1311 object, use the :meth:`_schema.Table.append_column` method. 

1312 

1313 """ 

1314 if key is None: 

1315 key = column.key 

1316 

1317 l = len(self._collection) 

1318 self._collection.append((key, column)) 

1319 self._colset.add(column) 

1320 self._index[l] = column 

1321 if key not in self._index: 

1322 self._index[key] = column 

1323 

1324 def __getstate__(self): 

1325 return {"_collection": self._collection, "_index": self._index} 

1326 

1327 def __setstate__(self, state): 

1328 object.__setattr__(self, "_index", state["_index"]) 

1329 object.__setattr__(self, "_collection", state["_collection"]) 

1330 object.__setattr__( 

1331 self, "_colset", {col for k, col in self._collection} 

1332 ) 

1333 

1334 def contains_column(self, col): 

1335 """Checks if a column object exists in this collection""" 

1336 if col not in self._colset: 

1337 if isinstance(col, util.string_types): 

1338 raise exc.ArgumentError( 

1339 "contains_column cannot be used with string arguments. " 

1340 "Use ``col_name in table.c`` instead." 

1341 ) 

1342 return False 

1343 else: 

1344 return True 

1345 

1346 def as_immutable(self): 

1347 """Return an "immutable" form of this 

1348 :class:`_sql.ColumnCollection`.""" 

1349 

1350 return ImmutableColumnCollection(self) 

1351 

1352 def corresponding_column(self, column, require_embedded=False): 

1353 """Given a :class:`_expression.ColumnElement`, return the exported 

1354 :class:`_expression.ColumnElement` object from this 

1355 :class:`_expression.ColumnCollection` 

1356 which corresponds to that original :class:`_expression.ColumnElement` 

1357 via a common 

1358 ancestor column. 

1359 

1360 :param column: the target :class:`_expression.ColumnElement` 

1361 to be matched. 

1362 

1363 :param require_embedded: only return corresponding columns for 

1364 the given :class:`_expression.ColumnElement`, if the given 

1365 :class:`_expression.ColumnElement` 

1366 is actually present within a sub-element 

1367 of this :class:`_expression.Selectable`. 

1368 Normally the column will match if 

1369 it merely shares a common ancestor with one of the exported 

1370 columns of this :class:`_expression.Selectable`. 

1371 

1372 .. seealso:: 

1373 

1374 :meth:`_expression.Selectable.corresponding_column` 

1375 - invokes this method 

1376 against the collection returned by 

1377 :attr:`_expression.Selectable.exported_columns`. 

1378 

1379 .. versionchanged:: 1.4 the implementation for ``corresponding_column`` 

1380 was moved onto the :class:`_expression.ColumnCollection` itself. 

1381 

1382 """ 

1383 

1384 def embedded(expanded_proxy_set, target_set): 

1385 for t in target_set.difference(expanded_proxy_set): 

1386 if not set(_expand_cloned([t])).intersection( 

1387 expanded_proxy_set 

1388 ): 

1389 return False 

1390 return True 

1391 

1392 # don't dig around if the column is locally present 

1393 if column in self._colset: 

1394 return column 

1395 col, intersect = None, None 

1396 target_set = column.proxy_set 

1397 cols = [c for (k, c) in self._collection] 

1398 for c in cols: 

1399 expanded_proxy_set = set(_expand_cloned(c.proxy_set)) 

1400 i = target_set.intersection(expanded_proxy_set) 

1401 if i and ( 

1402 not require_embedded 

1403 or embedded(expanded_proxy_set, target_set) 

1404 ): 

1405 if col is None: 

1406 

1407 # no corresponding column yet, pick this one. 

1408 

1409 col, intersect = c, i 

1410 elif len(i) > len(intersect): 

1411 

1412 # 'c' has a larger field of correspondence than 

1413 # 'col'. i.e. selectable.c.a1_x->a1.c.x->table.c.x 

1414 # matches a1.c.x->table.c.x better than 

1415 # selectable.c.x->table.c.x does. 

1416 

1417 col, intersect = c, i 

1418 elif i == intersect: 

1419 # they have the same field of correspondence. see 

1420 # which proxy_set has fewer columns in it, which 

1421 # indicates a closer relationship with the root 

1422 # column. Also take into account the "weight" 

1423 # attribute which CompoundSelect() uses to give 

1424 # higher precedence to columns based on vertical 

1425 # position in the compound statement, and discard 

1426 # columns that have no reference to the target 

1427 # column (also occurs with CompoundSelect) 

1428 

1429 col_distance = util.reduce( 

1430 operator.add, 

1431 [ 

1432 sc._annotations.get("weight", 1) 

1433 for sc in col._uncached_proxy_list() 

1434 if sc.shares_lineage(column) 

1435 ], 

1436 ) 

1437 c_distance = util.reduce( 

1438 operator.add, 

1439 [ 

1440 sc._annotations.get("weight", 1) 

1441 for sc in c._uncached_proxy_list() 

1442 if sc.shares_lineage(column) 

1443 ], 

1444 ) 

1445 if c_distance < col_distance: 

1446 col, intersect = c, i 

1447 return col 

1448 

1449 

1450class DedupeColumnCollection(ColumnCollection): 

1451 """A :class:`_expression.ColumnCollection` 

1452 that maintains deduplicating behavior. 

1453 

1454 This is useful by schema level objects such as :class:`_schema.Table` and 

1455 :class:`.PrimaryKeyConstraint`. The collection includes more 

1456 sophisticated mutator methods as well to suit schema objects which 

1457 require mutable column collections. 

1458 

1459 .. versionadded:: 1.4 

1460 

1461 """ 

1462 

1463 def add(self, column, key=None): 

1464 

1465 if key is not None and column.key != key: 

1466 raise exc.ArgumentError( 

1467 "DedupeColumnCollection requires columns be under " 

1468 "the same key as their .key" 

1469 ) 

1470 key = column.key 

1471 

1472 if key is None: 

1473 raise exc.ArgumentError( 

1474 "Can't add unnamed column to column collection" 

1475 ) 

1476 

1477 if key in self._index: 

1478 

1479 existing = self._index[key] 

1480 

1481 if existing is column: 

1482 return 

1483 

1484 self.replace(column) 

1485 

1486 # pop out memoized proxy_set as this 

1487 # operation may very well be occurring 

1488 # in a _make_proxy operation 

1489 util.memoized_property.reset(column, "proxy_set") 

1490 else: 

1491 l = len(self._collection) 

1492 self._collection.append((key, column)) 

1493 self._colset.add(column) 

1494 self._index[l] = column 

1495 self._index[key] = column 

1496 

1497 def _populate_separate_keys(self, iter_): 

1498 """populate from an iterator of (key, column)""" 

1499 cols = list(iter_) 

1500 

1501 replace_col = [] 

1502 for k, col in cols: 

1503 if col.key != k: 

1504 raise exc.ArgumentError( 

1505 "DedupeColumnCollection requires columns be under " 

1506 "the same key as their .key" 

1507 ) 

1508 if col.name in self._index and col.key != col.name: 

1509 replace_col.append(col) 

1510 elif col.key in self._index: 

1511 replace_col.append(col) 

1512 else: 

1513 self._index[k] = col 

1514 self._collection.append((k, col)) 

1515 self._colset.update(c for (k, c) in self._collection) 

1516 self._index.update( 

1517 (idx, c) for idx, (k, c) in enumerate(self._collection) 

1518 ) 

1519 for col in replace_col: 

1520 self.replace(col) 

1521 

1522 def extend(self, iter_): 

1523 self._populate_separate_keys((col.key, col) for col in iter_) 

1524 

1525 def remove(self, column): 

1526 if column not in self._colset: 

1527 raise ValueError( 

1528 "Can't remove column %r; column is not in this collection" 

1529 % column 

1530 ) 

1531 del self._index[column.key] 

1532 self._colset.remove(column) 

1533 self._collection[:] = [ 

1534 (k, c) for (k, c) in self._collection if c is not column 

1535 ] 

1536 self._index.update( 

1537 {idx: col for idx, (k, col) in enumerate(self._collection)} 

1538 ) 

1539 # delete higher index 

1540 del self._index[len(self._collection)] 

1541 

1542 def replace(self, column): 

1543 """add the given column to this collection, removing unaliased 

1544 versions of this column as well as existing columns with the 

1545 same key. 

1546 

1547 e.g.:: 

1548 

1549 t = Table('sometable', metadata, Column('col1', Integer)) 

1550 t.columns.replace(Column('col1', Integer, key='columnone')) 

1551 

1552 will remove the original 'col1' from the collection, and add 

1553 the new column under the name 'columnname'. 

1554 

1555 Used by schema.Column to override columns during table reflection. 

1556 

1557 """ 

1558 

1559 remove_col = set() 

1560 # remove up to two columns based on matches of name as well as key 

1561 if column.name in self._index and column.key != column.name: 

1562 other = self._index[column.name] 

1563 if other.name == other.key: 

1564 remove_col.add(other) 

1565 

1566 if column.key in self._index: 

1567 remove_col.add(self._index[column.key]) 

1568 

1569 new_cols = [] 

1570 replaced = False 

1571 for k, col in self._collection: 

1572 if col in remove_col: 

1573 if not replaced: 

1574 replaced = True 

1575 new_cols.append((column.key, column)) 

1576 else: 

1577 new_cols.append((k, col)) 

1578 

1579 if remove_col: 

1580 self._colset.difference_update(remove_col) 

1581 

1582 if not replaced: 

1583 new_cols.append((column.key, column)) 

1584 

1585 self._colset.add(column) 

1586 self._collection[:] = new_cols 

1587 

1588 self._index.clear() 

1589 self._index.update( 

1590 {idx: col for idx, (k, col) in enumerate(self._collection)} 

1591 ) 

1592 self._index.update(self._collection) 

1593 

1594 

1595class ImmutableColumnCollection(util.ImmutableContainer, ColumnCollection): 

1596 __slots__ = ("_parent",) 

1597 

1598 def __init__(self, collection): 

1599 object.__setattr__(self, "_parent", collection) 

1600 object.__setattr__(self, "_colset", collection._colset) 

1601 object.__setattr__(self, "_index", collection._index) 

1602 object.__setattr__(self, "_collection", collection._collection) 

1603 

1604 def __getstate__(self): 

1605 return {"_parent": self._parent} 

1606 

1607 def __setstate__(self, state): 

1608 parent = state["_parent"] 

1609 self.__init__(parent) 

1610 

1611 add = extend = remove = util.ImmutableContainer._immutable 

1612 

1613 

1614class ColumnSet(util.ordered_column_set): 

1615 def contains_column(self, col): 

1616 return col in self 

1617 

1618 def extend(self, cols): 

1619 for col in cols: 

1620 self.add(col) 

1621 

1622 def __add__(self, other): 

1623 return list(self) + list(other) 

1624 

1625 def __eq__(self, other): 

1626 l = [] 

1627 for c in other: 

1628 for local in self: 

1629 if c.shares_lineage(local): 

1630 l.append(c == local) 

1631 return elements.and_(*l) 

1632 

1633 def __hash__(self): 

1634 return hash(tuple(x for x in self)) 

1635 

1636 

1637def _bind_or_error(schemaitem, msg=None): 

1638 

1639 util.warn_deprecated_20( 

1640 "The ``bind`` argument for schema methods that invoke SQL " 

1641 "against an engine or connection will be required in SQLAlchemy 2.0." 

1642 ) 

1643 bind = schemaitem.bind 

1644 if not bind: 

1645 name = schemaitem.__class__.__name__ 

1646 label = getattr( 

1647 schemaitem, "fullname", getattr(schemaitem, "name", None) 

1648 ) 

1649 if label: 

1650 item = "%s object %r" % (name, label) 

1651 else: 

1652 item = "%s object" % name 

1653 if msg is None: 

1654 msg = ( 

1655 "%s is not bound to an Engine or Connection. " 

1656 "Execution can not proceed without a database to execute " 

1657 "against." % item 

1658 ) 

1659 raise exc.UnboundExecutionError(msg) 

1660 return bind 

1661 

1662 

1663def _entity_namespace(entity): 

1664 """Return the nearest .entity_namespace for the given entity. 

1665 

1666 If not immediately available, does an iterate to find a sub-element 

1667 that has one, if any. 

1668 

1669 """ 

1670 try: 

1671 return entity.entity_namespace 

1672 except AttributeError: 

1673 for elem in visitors.iterate(entity): 

1674 if hasattr(elem, "entity_namespace"): 

1675 return elem.entity_namespace 

1676 else: 

1677 raise 

1678 

1679 

1680def _entity_namespace_key(entity, key, default=NO_ARG): 

1681 """Return an entry from an entity_namespace. 

1682 

1683 

1684 Raises :class:`_exc.InvalidRequestError` rather than attribute error 

1685 on not found. 

1686 

1687 """ 

1688 

1689 try: 

1690 ns = _entity_namespace(entity) 

1691 if default is not NO_ARG: 

1692 return getattr(ns, key, default) 

1693 else: 

1694 return getattr(ns, key) 

1695 except AttributeError as err: 

1696 util.raise_( 

1697 exc.InvalidRequestError( 

1698 'Entity namespace for "%s" has no property "%s"' 

1699 % (entity, key) 

1700 ), 

1701 replace_context=err, 

1702 )