summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2012-04-03 18:53:39 -0400
committerMike Bayer <mike_mp@zzzcomputing.com>2012-04-03 18:53:39 -0400
commitf1bdd4e4bbf8366ff7177ebc3ee6647f32fd414f (patch)
tree3ffef191d48fc13c0595c893ef5ab2bf55db5a9e /lib/sqlalchemy
parent53b4337de3ab4d4abe17ca47903aaaa8664cd50f (diff)
downloadsqlalchemy-f1bdd4e4bbf8366ff7177ebc3ee6647f32fd414f.tar.gz
begin implementing inspection system for #2208
Diffstat (limited to 'lib/sqlalchemy')
-rw-r--r--lib/sqlalchemy/__init__.py8
-rw-r--r--lib/sqlalchemy/engine/reflection.py7
-rw-r--r--lib/sqlalchemy/inspection.py44
-rw-r--r--lib/sqlalchemy/orm/instrumentation.py2
-rw-r--r--lib/sqlalchemy/orm/mapper.py34
-rw-r--r--lib/sqlalchemy/orm/state.py4
-rw-r--r--lib/sqlalchemy/orm/util.py29
7 files changed, 115 insertions, 13 deletions
diff --git a/lib/sqlalchemy/__init__.py b/lib/sqlalchemy/__init__.py
index 4e00437ea..ee7bf4c6f 100644
--- a/lib/sqlalchemy/__init__.py
+++ b/lib/sqlalchemy/__init__.py
@@ -4,7 +4,7 @@
# This module is part of SQLAlchemy and is released under
# the MIT License: http://www.opensource.org/licenses/mit-license.php
-import inspect
+import inspect as _inspect
import sys
import sqlalchemy.exc as exceptions
@@ -111,15 +111,17 @@ from sqlalchemy.schema import (
UniqueConstraint,
)
+from sqlalchemy.inspection import inspect
+
from sqlalchemy.engine import create_engine, engine_from_config
__all__ = sorted(name for name, obj in locals().items()
- if not (name.startswith('_') or inspect.ismodule(obj)))
+ if not (name.startswith('_') or _inspect.ismodule(obj)))
__version__ = '0.7.7'
-del inspect, sys
+del _inspect, sys
from sqlalchemy import util as _sa_util
_sa_util.importlater.resolve_all()
diff --git a/lib/sqlalchemy/engine/reflection.py b/lib/sqlalchemy/engine/reflection.py
index 71d97e65f..b2a5a02ef 100644
--- a/lib/sqlalchemy/engine/reflection.py
+++ b/lib/sqlalchemy/engine/reflection.py
@@ -30,7 +30,8 @@ from sqlalchemy import util
from sqlalchemy.util import topological
from sqlalchemy.types import TypeEngine
from sqlalchemy import schema as sa_schema
-
+from sqlalchemy import inspection
+from sqlalchemy.engine.base import Connectable
@util.decorator
def cache(fn, self, con, *args, **kw):
@@ -118,6 +119,10 @@ class Inspector(object):
return bind.dialect.inspector(bind)
return Inspector(bind)
+ @inspection._inspects(Connectable)
+ def _insp(bind):
+ return Inspector.from_engine(bind)
+
@property
def default_schema_name(self):
"""Return the default schema name presented by the dialect
diff --git a/lib/sqlalchemy/inspection.py b/lib/sqlalchemy/inspection.py
new file mode 100644
index 000000000..9ce52beab
--- /dev/null
+++ b/lib/sqlalchemy/inspection.py
@@ -0,0 +1,44 @@
+# sqlalchemy/inspect.py
+# Copyright (C) 2005-2012 the SQLAlchemy authors and contributors <see AUTHORS file>
+#
+# This module is part of SQLAlchemy and is released under
+# the MIT License: http://www.opensource.org/licenses/mit-license.php
+
+"""Base inspect API.
+
+:func:`.inspect` provides access to a contextual object
+regarding a subject.
+
+Various subsections of SQLAlchemy,
+such as the :class:`.Inspector`, :class:`.Mapper`, and
+others register themselves with the "inspection registry" here
+so that they may return a context object given a certain kind
+of argument.
+"""
+
+from sqlalchemy import util
+_registrars = util.defaultdict(list)
+
+def inspect(subject):
+ type_ = type(subject)
+ for cls in type_.__mro__:
+ if cls in _registrars:
+ reg = _registrars[cls]
+ break
+ else:
+ raise exc.InvalidRequestError(
+ "No inspection system is "
+ "available for object of type %s" %
+ type_)
+ return reg(subject)
+
+def _inspects(*types):
+ def decorate(fn_or_cls):
+ for type_ in types:
+ if type_ in _registrars:
+ raise AssertionError(
+ "Type %s is already "
+ "registered" % type_)
+ _registrars[type_] = fn_or_cls
+ return fn_or_cls
+ return decorate
diff --git a/lib/sqlalchemy/orm/instrumentation.py b/lib/sqlalchemy/orm/instrumentation.py
index af9ef7841..1012af67a 100644
--- a/lib/sqlalchemy/orm/instrumentation.py
+++ b/lib/sqlalchemy/orm/instrumentation.py
@@ -23,7 +23,7 @@ An example of full customization is in /examples/custom_attributes.
from sqlalchemy.orm import exc, collections, events
from operator import attrgetter, itemgetter
-from sqlalchemy import event, util
+from sqlalchemy import event, util, inspection
import weakref
from sqlalchemy.orm import state, attributes
diff --git a/lib/sqlalchemy/orm/mapper.py b/lib/sqlalchemy/orm/mapper.py
index e96b7549a..4fa8dfe24 100644
--- a/lib/sqlalchemy/orm/mapper.py
+++ b/lib/sqlalchemy/orm/mapper.py
@@ -33,6 +33,7 @@ from sqlalchemy.orm.util import _INSTRUMENTOR, _class_to_mapper, \
import sys
sessionlib = util.importlater("sqlalchemy.orm", "session")
properties = util.importlater("sqlalchemy.orm", "properties")
+descriptor_props = util.importlater("sqlalchemy.orm", "descriptor_props")
__all__ = (
'Mapper',
@@ -1392,12 +1393,35 @@ class Mapper(object):
continue
yield c
- @property
+ @util.memoized_property
def properties(self):
- raise NotImplementedError(
- "Public collection of MapperProperty objects is "
- "provided by the get_property() and iterate_properties "
- "accessors.")
+ if _new_mappers:
+ configure_mappers()
+ return util.ImmutableProperties(self._props)
+
+ @_memoized_configured_property
+ def synonyms(self):
+ return self._filter_properties(descriptor_props.SynonymProperty)
+
+ @_memoized_configured_property
+ def column_attrs(self):
+ return self._filter_properties(properties.ColumnProperty)
+
+ @_memoized_configured_property
+ def relationships(self):
+ return self._filter_properties(properties.RelationshipProperty)
+
+ @_memoized_configured_property
+ def composites(self):
+ return self._filter_properties(descriptor_props.CompositeProperty)
+
+ def _filter_properties(self, type_):
+ if _new_mappers:
+ configure_mappers()
+ return dict(
+ (k, v) for k, v in self._props.iteritems()
+ if isinstance(v, type_)
+ )
@_memoized_configured_property
def _get_clause(self):
diff --git a/lib/sqlalchemy/orm/state.py b/lib/sqlalchemy/orm/state.py
index 4803ecdc3..156686bc7 100644
--- a/lib/sqlalchemy/orm/state.py
+++ b/lib/sqlalchemy/orm/state.py
@@ -54,6 +54,10 @@ class InstanceState(object):
def pending(self):
return {}
+ @util.memoized_property
+ def mapper(self):
+ return self.manager.mapper
+
@property
def has_identity(self):
return bool(self.key)
diff --git a/lib/sqlalchemy/orm/util.py b/lib/sqlalchemy/orm/util.py
index 0c5f203a7..8d334ce17 100644
--- a/lib/sqlalchemy/orm/util.py
+++ b/lib/sqlalchemy/orm/util.py
@@ -5,7 +5,7 @@
# the MIT License: http://www.opensource.org/licenses/mit-license.php
-from sqlalchemy import sql, util, event, exc as sa_exc
+from sqlalchemy import sql, util, event, exc as sa_exc, inspection
from sqlalchemy.sql import expression, util as sql_util, operators
from sqlalchemy.orm.interfaces import MapperExtension, EXT_CONTINUE,\
PropComparator, MapperProperty
@@ -616,15 +616,34 @@ def object_mapper(instance):
Raises UnmappedInstanceError if no mapping is configured.
+ This function is available via the inspection system as::
+
+ inspect(instance).mapper
+
+ """
+ return object_state(instance).mapper
+
+@inspection._inspects(object)
+def object_state(instance):
+ """Given an object, return the primary Mapper associated with the object
+ instance.
+
+ Raises UnmappedInstanceError if no mapping is configured.
+
+ This function is available via the inspection system as::
+
+ inspect(instance)
+
"""
try:
- state = attributes.instance_state(instance)
- return state.manager.mapper
+ return attributes.instance_state(instance)
except exc.UnmappedClassError:
raise exc.UnmappedInstanceError(instance)
except exc.NO_STATE:
raise exc.UnmappedInstanceError(instance)
+
+@inspection._inspects(type)
def class_mapper(class_, compile=True):
"""Given a class, return the primary :class:`.Mapper` associated
with the key.
@@ -633,6 +652,10 @@ def class_mapper(class_, compile=True):
on the given class, or :class:`.ArgumentError` if a non-class
object is passed.
+ This function is available via the inspection system as::
+
+ inspect(some_mapped_class)
+
"""
try: