diff options
| author | Mike Bayer <mike_mp@zzzcomputing.com> | 2012-04-03 18:53:39 -0400 |
|---|---|---|
| committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2012-04-03 18:53:39 -0400 |
| commit | f1bdd4e4bbf8366ff7177ebc3ee6647f32fd414f (patch) | |
| tree | 3ffef191d48fc13c0595c893ef5ab2bf55db5a9e /lib | |
| parent | 53b4337de3ab4d4abe17ca47903aaaa8664cd50f (diff) | |
| download | sqlalchemy-f1bdd4e4bbf8366ff7177ebc3ee6647f32fd414f.tar.gz | |
begin implementing inspection system for #2208
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/sqlalchemy/__init__.py | 8 | ||||
| -rw-r--r-- | lib/sqlalchemy/engine/reflection.py | 7 | ||||
| -rw-r--r-- | lib/sqlalchemy/inspection.py | 44 | ||||
| -rw-r--r-- | lib/sqlalchemy/orm/instrumentation.py | 2 | ||||
| -rw-r--r-- | lib/sqlalchemy/orm/mapper.py | 34 | ||||
| -rw-r--r-- | lib/sqlalchemy/orm/state.py | 4 | ||||
| -rw-r--r-- | lib/sqlalchemy/orm/util.py | 29 |
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: |
