from sqlalchemy.orm import interfaces, collections, exc
import sqlalchemy.exceptions as sa_exc
-# lazy imports
-_entity_info = None
-identity_equal = None
-state = None
+mapperutil = util.importlater("sqlalchemy.orm", "util")
PASSIVE_NO_RESULT = util.symbol('PASSIVE_NO_RESULT')
ATTR_WAS_SET = util.symbol('ATTR_WAS_SET')
compare_function=compare_function,
**kwargs)
if compare_function is None:
- self.is_equal = identity_equal
+ self.is_equal = mapperutil.identity_equal
def delete(self, state, dict_):
old = self.get(state, dict_)
_state_mapper, class_mapper, instance_str, state_str,
)
import sys
+sessionlib = util.importlater("sqlalchemy.orm", "session")
+properties = util.importlater("sqlalchemy.orm", "properties")
__all__ = (
'Mapper',
# lock used to synchronize the "mapper compile" step
_COMPILE_MUTEX = util.threading.RLock()
-# initialize these lazily
-ColumnProperty = None
-RelationshipProperty = None
-ConcreteInheritedProperty = None
-_expire_state = None
-_state_session = None
-
class Mapper(object):
"""Define the correlation of class attributes to database table
columns.
self._configure_property(
col.key,
- ColumnProperty(col, _instrument=instrument),
+ properties.ColumnProperty(col, _instrument=instrument),
init=False, setparent=True)
def _adapt_inherited_property(self, key, prop, init):
elif key not in self._props:
self._configure_property(
key,
- ConcreteInheritedProperty(),
+ properties.ConcreteInheritedProperty(),
init=init, setparent=True)
def _configure_property(self, key, prop, init=True, setparent=True):
if not isinstance(prop, MapperProperty):
# we were passed a Column or a list of Columns;
- # generate a ColumnProperty
+ # generate a properties.ColumnProperty
columns = util.to_list(prop)
column = columns[0]
if not expression.is_column(column):
prop = self._props.get(key, None)
- if isinstance(prop, ColumnProperty):
+ if isinstance(prop, properties.ColumnProperty):
# TODO: the "property already exists" case is still not
# well defined here. assuming single-column, etc.
if prop.parent is not self:
- # existing ColumnProperty from an inheriting mapper.
+ # existing properties.ColumnProperty from an inheriting mapper.
# make a copy and append our column to it
prop = prop.copy()
else:
# this hypothetically changes to
# prop.columns.insert(0, column) when we do [ticket:1892]
prop.columns.append(column)
- self._log("appending to existing ColumnProperty %s" % (key))
+ self._log("appending to existing properties.ColumnProperty %s" % (key))
- elif prop is None or isinstance(prop, ConcreteInheritedProperty):
+ elif prop is None or isinstance(prop, properties.ConcreteInheritedProperty):
mapped_column = []
for c in columns:
mc = self.mapped_table.corresponding_column(c)
"force this column to be mapped as a read-only "
"attribute." % (key, self, c))
mapped_column.append(mc)
- prop = ColumnProperty(*mapped_column)
+ prop = properties.ColumnProperty(*mapped_column)
else:
raise sa_exc.ArgumentError(
"WARNING: when configuring property '%s' on %s, "
"columns get mapped." %
(key, self, column.key, prop))
- if isinstance(prop, ColumnProperty):
+ if isinstance(prop, properties.ColumnProperty):
col = self.mapped_table.corresponding_column(prop.columns[0])
# if the column is not present in the mapped table,
col not in self._cols_by_table[col.table]:
self._cols_by_table[col.table].add(col)
- # if this ColumnProperty represents the "polymorphic
+ # if this properties.ColumnProperty represents the "polymorphic
# discriminator" column, mark it. We'll need this when rendering
# columns in SELECT statements.
if not hasattr(prop, '_is_polymorphic_discriminator'):
)
if readonly:
- _expire_state(state, state.dict, readonly)
+ sessionlib._expire_state(state, state.dict, readonly)
# if eager_defaults option is enabled,
# refresh whatever has been expired.
self._set_state_attr_by_column(state, dict_, c, params[c.key])
if postfetch_cols:
- _expire_state(state, state.dict,
+ sessionlib._expire_state(state, state.dict,
[self._columntoproperty[c].key
for c in postfetch_cols]
)
"""initiate a column-based attribute refresh operation."""
mapper = _state_mapper(state)
- session = _state_session(state)
+ session = sessionlib._state_session(state)
if not session:
raise orm_exc.DetachedInstanceError(
"Instance %s is not bound to a Session; "
PropertyLoader = RelationProperty = RelationshipProperty
log.class_logger(RelationshipProperty)
-mapper.ColumnProperty = ColumnProperty
-mapper.RelationshipProperty = RelationshipProperty
-mapper.ConcreteInheritedProperty = ConcreteInheritedProperty
pass
return None
-# Lazy initialization to avoid circular imports
-unitofwork._state_session = _state_session
-from sqlalchemy.orm import mapper
-mapper._expire_state = _expire_state
-mapper._state_session = _state_session
from sqlalchemy.orm import attributes, interfaces
from sqlalchemy.orm import util as mapperutil
from sqlalchemy.orm.util import _state_mapper
-
-# Load lazily
-_state_session = None
+session = util.importlater("sqlalchemy.orm", "session")
class UOWEventHandler(interfaces.AttributeExtension):
"""An event handler added to all relationship attributes which handles
# process "save_update" cascade rules for when
# an instance is appended to the list of another instance
- sess = _state_session(state)
+ sess = session._state_session(state)
if sess:
prop = _state_mapper(state).get_property(self.key)
if prop.cascade.save_update and \
return item
def remove(self, state, item, initiator):
- sess = _state_session(state)
+ sess = session._state_session(state)
if sess:
prop = _state_mapper(state).get_property(self.key)
# expunge pending orphans
if oldvalue is newvalue:
return newvalue
- sess = _state_session(state)
+ sess = session._state_session(state)
if sess:
prop = _state_mapper(state).get_property(self.key)
if newvalue is not None and \
AttributeExtension
from sqlalchemy.orm import attributes, exc
-mapperlib = None
+mapperlib = util.importlater("sqlalchemy.orm", "mapperlib")
all_cascades = frozenset(("delete", "delete-orphan", "all", "merge",
"expunge", "save-update", "refresh-expire",
if isinstance(entity, AliasedClass):
return entity._AliasedClass__mapper, entity._AliasedClass__alias, True
- global mapperlib
- if mapperlib is None:
- from sqlalchemy.orm import mapperlib
-
if isinstance(entity, mapperlib.Mapper):
mapper = entity
def _class_to_mapper(class_or_mapper, compile=True):
if _is_aliased_class(class_or_mapper):
return class_or_mapper._AliasedClass__mapper
+
elif isinstance(class_or_mapper, type):
- return class_mapper(class_or_mapper, compile=compile)
- elif hasattr(class_or_mapper, 'compile'):
- if compile:
- return class_or_mapper.compile()
- else:
- return class_or_mapper
+ try:
+ class_manager = attributes.manager_of_class(class_or_mapper)
+ mapper = class_manager.mapper
+ except exc.NO_STATE:
+ raise exc.UnmappedClassError(class_or_mapper)
+ elif isinstance(class_or_mapper, mapperlib.Mapper):
+ mapper = class_or_mapper
else:
raise exc.UnmappedClassError(class_or_mapper)
+
+ if compile:
+ return mapper.compile()
+ else:
+ return mapper
def has_identity(object):
state = attributes.instance_state(object)
return state.has_identity
def _is_mapped_class(cls):
- global mapperlib
- if mapperlib is None:
- from sqlalchemy.orm import mapperlib
if isinstance(cls, (AliasedClass, mapperlib.Mapper)):
return True
if isinstance(cls, expression.ClauseElement):
return False
return state_a.key == state_b.key
-
-# TODO: Avoid circular import.
-attributes.identity_equal = identity_equal
-attributes._is_aliased_class = _is_aliased_class
-attributes._entity_info = _entity_info
from sqlalchemy import exc, util, dialects
from sqlalchemy.sql import expression, visitors
-URL = None
+sqlutil = util.importlater("sqlalchemy.sql", "util")
+url = util.importlater("sqlalchemy.engine", "url")
+
__all__ = ['SchemaItem', 'Table', 'Column', 'ForeignKey', 'Sequence', 'Index',
'ForeignKeyConstraint', 'PrimaryKeyConstraint', 'CheckConstraint',
def _bind_to(self, bind):
"""Bind this MetaData to an Engine, Connection, string or URL."""
- global URL
- if URL is None:
- from sqlalchemy.engine.url import URL
-
- if isinstance(bind, (basestring, URL)):
+ if isinstance(bind, (basestring, url.URL)):
from sqlalchemy import create_engine
self._bind = create_engine(bind)
else:
"""Returns a list of ``Table`` objects sorted in order of
dependency.
"""
- from sqlalchemy.sql.util import sort_tables
- return sort_tables(self.tables.itervalues())
+ return sqlutil.sort_tables(self.tables.itervalues())
def reflect(self, bind=None, schema=None, views=False, only=None):
"""Load all available table definitions from the database.
def _bind_to(self, bind):
"""Bind to a Connectable in the caller's thread."""
- global URL
- if URL is None:
- from sqlalchemy.engine.url import URL
-
- if isinstance(bind, (basestring, URL)):
+ if isinstance(bind, (basestring, url.URL)):
try:
self.context._engine = self.__engines[bind]
except KeyError:
import itertools, re
from operator import attrgetter
-from sqlalchemy import util, exc #, types as sqltypes
+from sqlalchemy import util, exc
from sqlalchemy.sql import operators
from sqlalchemy.sql.visitors import Visitable, cloned_traverse
import operator
-functions, sql_util, sqltypes = None, None, None
-DefaultDialect = None
+functions = util.importlater("sqlalchemy.sql", "functions")
+sqlutil = util.importlater("sqlalchemy.sql", "util")
+sqltypes = util.importlater("sqlalchemy", "types")
+default = util.importlater("sqlalchemy.engine", "default")
__all__ = [
'Alias', 'ClauseElement', 'ColumnCollection', 'ColumnElement',
o = self.opts.copy()
o.update(kwargs)
if len(self.__names) == 1:
- global functions
- if functions is None:
- from sqlalchemy.sql import functions
func = getattr(functions, self.__names[-1].lower(), None)
if func is not None and \
isinstance(func, type) and \
dictionary.
"""
- global sql_util
- if sql_util is None:
- from sqlalchemy.sql import util as sql_util
- return sql_util.Annotated(self, values)
+ return sqlutil.Annotated(self, values)
def _deannotate(self):
"""return a copy of this ClauseElement with an empty annotations
dialect = self.bind.dialect
bind = self.bind
else:
- global DefaultDialect
- if DefaultDialect is None:
- from sqlalchemy.engine.default import DefaultDialect
- dialect = DefaultDialect()
+ dialect = default.DefaultDialect()
compiler = self._compiler(dialect, bind=bind, **kw)
compiler.compile()
return compiler
"""
- global sql_util
- if sql_util is None:
- from sqlalchemy.sql import util as sql_util
- return sql_util.ClauseAdapter(alias).traverse(self)
+ return sqlutil.ClauseAdapter(alias).traverse(self)
def correspond_on_equivalents(self, column, equivalents):
"""Return corresponding_column for the given column, or if None
columns = [c for c in self.left.columns] + \
[c for c in self.right.columns]
- global sql_util
- if not sql_util:
- from sqlalchemy.sql import util as sql_util
- self._primary_key.extend(sql_util.reduce_columns(
+ self._primary_key.extend(sqlutil.reduce_columns(
(c for c in columns if c.primary_key), self.onclause))
self._columns.update((col._label, col) for col in columns)
self._foreign_keys.update(itertools.chain(
return self.left, self.right, self.onclause
def _match_primaries(self, left, right):
- global sql_util
- if not sql_util:
- from sqlalchemy.sql import util as sql_util
if isinstance(left, Join):
left_right = left.right
else:
left_right = None
- return sql_util.join_condition(left, right, a_subset=left_right)
+ return sqlutil.join_condition(left, right, a_subset=left_right)
def select(self, whereclause=None, fold_equivalents=False, **kwargs):
"""Create a :class:`Select` from this :class:`Join`.
underlying :func:`select()` function.
"""
- global sql_util
- if not sql_util:
- from sqlalchemy.sql import util as sql_util
if fold_equivalents:
- collist = sql_util.folded_equivalents(self)
+ collist = sqlutil.folded_equivalents(self)
else:
collist = [self.left, self.right]
def lazy_gc():
pass
-
-
def picklers():
picklers = set()
# Py2K
from sqlalchemy import util
from sqlalchemy import processors
import collections
+default = util.importlater("sqlalchemy.engine", "default")
-DefaultDialect = None
NoneType = type(None)
if util.jython:
import array
mod = ".".join(tokens)
return getattr(__import__(mod).dialects, tokens[-1]).dialect()
else:
- global DefaultDialect
- if DefaultDialect is None:
- from sqlalchemy.engine.default import DefaultDialect
- return DefaultDialect()
+ return default.DefaultDialect()
def __str__(self):
# Py3K
self.attributes.append(fn.__name__)
return memoized_property(fn)
-
+class importlater(object):
+ """Deferred import object.
+
+ e.g.::
+
+ somesubmod = importlater("mypackage.somemodule", "somesubmod")
+
+ is equivalent to::
+
+ from mypackage.somemodule import somesubmod
+
+ except evaluted upon attribute access to "somesubmod".
+
+ """
+ def __init__(self, path, addtl=None):
+ self._il_path = path
+ self._il_addtl = addtl
+
+ @memoized_property
+ def _il_module(self):
+ m = __import__(self._il_path)
+ for token in self._il_path.split(".")[1:]:
+ m = getattr(m, token)
+ if self._il_addtl:
+ try:
+ return getattr(m, self._il_addtl)
+ except AttributeError:
+ raise AttributeError(
+ "Module %s has no attribute '%s'" %
+ (self._il_path, self._il_addtl)
+ )
+ else:
+ return m
+
+ def __getattr__(self, key):
+ try:
+ attr = getattr(self._il_module, key)
+ except AttributeError:
+ raise AttributeError(
+ "Module %s has no attribute '%s'" %
+ (self._il_path, key)
+ )
+ self.__dict__[key] = attr
+ return attr
+
class WeakIdentityMapping(weakref.WeakKeyDictionary):
"""A WeakKeyDictionary with an object identity index.
class CompileTest(TestBase, AssertsExecutionResults):
@classmethod
def setup_class(cls):
+
global t1, t2, metadata
metadata = MetaData()
t1 = Table('t1', metadata,
Column('c1', Integer, primary_key=True),
Column('c2', String(30)))
+ # do a "compile" ahead of time to load
+ # deferred imports
+ t1.insert().compile()
+
# go through all the TypeEngine
# objects in use and pre-load their _type_affinity
# entries.