From: Mike Bayer Date: Sun, 13 Jun 2010 19:49:27 +0000 (-0400) Subject: - added documentation for Inspector [ticket:1820] X-Git-Tag: rel_0_6_2~48 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=7378611832a8b58ce040dab3ee0739209c4c8854;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git - added documentation for Inspector [ticket:1820] - fixed "toplevel" regexp to include tokens of the form foo-bar-toplevel (i.e. multiple dashes) - some CSS adjustment so that all API headings are in gray. --- diff --git a/CHANGES b/CHANGES index d0be776fe9..b7a92783d7 100644 --- a/CHANGES +++ b/CHANGES @@ -17,7 +17,10 @@ CHANGES - firebird - Fixed incorrect signature in do_execute(), error introduced in 0.6.1. [ticket:1823] - + +- documentation + - Added documentation for the Inspector. [ticket:1820] + 0.6.1 ===== - orm diff --git a/doc/build/builder/util.py b/doc/build/builder/util.py index a7c4d6b5a3..0ae4de5cd4 100644 --- a/doc/build/builder/util.py +++ b/doc/build/builder/util.py @@ -4,5 +4,5 @@ def striptags(text): return re.compile(r'<[^>]*>').sub('', text) def strip_toplevel_anchors(text): - return re.compile(r'\.html#\w+-toplevel').sub('.html', text) + return re.compile(r'\.html#[-\w]+-toplevel').sub('.html', text) diff --git a/doc/build/metadata.rst b/doc/build/metadata.rst index 2ac0ea2a48..6dcd625f96 100644 --- a/doc/build/metadata.rst +++ b/doc/build/metadata.rst @@ -231,6 +231,8 @@ Alternatively, the ``bind`` attribute of :class:`~sqlalchemy.schema.MetaData` is * Your application talks to multiple database engines at different times, which use the *same* set of :class:`Table` objects. It's usually confusing and unnecessary to begin to create "copies" of :class:`Table` objects just so that different engines can be used for different operations. An example is an application that writes data to a "master" database while performing read-only operations from a "read slave". A global :class:`~sqlalchemy.schema.MetaData` object is *not* appropriate for per-request switching like this, although a :class:`~sqlalchemy.schema.ThreadLocalMetaData` object is. * You are using the ORM :class:`Session` to handle which class/table is bound to which engine, or you are using the :class:`Session` to manage switching between engines. Its a good idea to keep the "binding of tables to engines" in one place - either using :class:`~sqlalchemy.schema.MetaData` only (the :class:`Session` can of course be present, it just has no ``bind`` configured), or using :class:`Session` only (the ``bind`` attribute of :class:`~sqlalchemy.schema.MetaData` is left empty). +.. _metadata_reflection: + Reflecting Tables ----------------- @@ -303,6 +305,11 @@ The :class:`~sqlalchemy.schema.MetaData` object can also get a listing of tables for table in reversed(meta.sorted_tables): someengine.execute(table.delete()) +Fine Grained Reflection with Inspector +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +A low level interface which provides a backend-agnostic system of loading lists of schema, table, column, and constraint descriptions from a given database is also available. This is known as the "Inspector" and is described in the API documentation at :ref:`inspector_api_toplevel`. + Specifying the Schema Name --------------------------- diff --git a/doc/build/reference/sqlalchemy/index.rst b/doc/build/reference/sqlalchemy/index.rst index 2a3362b31a..9970a669c0 100644 --- a/doc/build/reference/sqlalchemy/index.rst +++ b/doc/build/reference/sqlalchemy/index.rst @@ -8,6 +8,7 @@ sqlalchemy pooling expressions schema + inspector types interfaces util diff --git a/doc/build/reference/sqlalchemy/inspector.rst b/doc/build/reference/sqlalchemy/inspector.rst new file mode 100644 index 0000000000..e0ef914607 --- /dev/null +++ b/doc/build/reference/sqlalchemy/inspector.rst @@ -0,0 +1,36 @@ +.. _inspector_api_toplevel: + +Schema Introspection +==================== + +.. module:: sqlalchemy.engine.reflection + +SQLAlchemy provides rich schema introspection capabilities. The most common methods for this include the "autoload" argument of :class:`~sqlalchemy.schema.Table`:: + + from sqlalchemy import create_engine, MetaData, Table + engine = create_engine('...') + meta = MetaData() + user_table = Table('user', meta, autoload=True, autoload_with=engine) + +As well as the :meth:`~sqlalchemy.schema.MetaData.reflect` method of :class:`~sqlalchemy.schema.MetaData`:: + + from sqlalchemy import create_engine, MetaData, Table + engine = create_engine('...') + meta = MetaData() + meta.reflect(engine) + user_table = meta.tables['user'] + +Further examples of reflection using :class:`~sqlalchemy.schema.Table` and :class:`~sqlalchemy.schema.MetaData` can be found at :ref:`metadata_reflection`. + +There is also a low-level inspection interface available for more specific operations, known as the :class:`Inspector`:: + + from sqlalchemy import create_engine + from sqlalchemy.engine import reflection + engine = create_engine('...') + insp = reflection.Inspector.from_engine(engine) + print insp.get_table_names() + +.. autoclass:: Inspector + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/build/static/docs.css b/doc/build/static/docs.css index 33fbca5277..1df49f8b22 100644 --- a/doc/build/static/docs.css +++ b/doc/build/static/docs.css @@ -250,6 +250,9 @@ pre { } dl.function > dt, +dl.attribute > dt, +dl.classmethod > dt, +dl.method > dt, dl.class > dt { background-color:#F0F0F0; @@ -257,6 +260,7 @@ dl.class > dt padding: 0px 10px; } + dt:target, span.highlight { background-color:#FBE54E; } diff --git a/lib/sqlalchemy/__init__.py b/lib/sqlalchemy/__init__.py index 4855602f3f..df041574be 100644 --- a/lib/sqlalchemy/__init__.py +++ b/lib/sqlalchemy/__init__.py @@ -114,6 +114,6 @@ 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))) -__version__ = '0.6.1' +__version__ = '0.6.2' del inspect, sys diff --git a/lib/sqlalchemy/engine/reflection.py b/lib/sqlalchemy/engine/reflection.py index 4a3643a416..a78dac02b7 100644 --- a/lib/sqlalchemy/engine/reflection.py +++ b/lib/sqlalchemy/engine/reflection.py @@ -45,14 +45,34 @@ def cache(fn, self, con, *args, **kw): class Inspector(object): """Performs database schema inspection. - The Inspector acts as a proxy to the dialects' reflection methods and - provides higher level functions for accessing database schema information. + The Inspector acts as a proxy to the reflection methods of the + :class:`~sqlalchemy.engine.base.Dialect`, providing a + consistent interface as well as caching support for previously + fetched metadata. + + The preferred method to construct an :class:`Inspector` is via the + :meth:`Inspector.from_engine` method. I.e.:: + + engine = create_engine('...') + insp = Inspector.from_engine(engine) + + Where above, the :class:`~sqlalchemy.engine.base.Dialect` may opt + to return an :class:`Inspector` subclass that provides additional + methods specific to the dialect's target database. + """ def __init__(self, bind): - """Initialize the instance. + """Initialize a new :class:`Inspector`. + + :param bind: a :class:`~sqlalchemy.engine.base.Connectable`, + which is typically an instance of + :class:`~sqlalchemy.engine.base.Engine` or + :class:`~sqlalchemy.engine.base.Connection`. + + For a dialect-specific instance of :class:`Inspector`, see + :meth:`Inspector.from_engine` - :param bind: a :class:`~sqlalchemy.engine.base.Connectable` """ # ensure initialized @@ -70,13 +90,35 @@ class Inspector(object): self.info_cache = {} @classmethod - def from_engine(cls, engine): - if hasattr(engine.dialect, 'inspector'): - return engine.dialect.inspector(engine) - return Inspector(engine) + def from_engine(cls, bind): + """Construct a new dialect-specific Inspector object from the given engine or connection. + + :param bind: a :class:`~sqlalchemy.engine.base.Connectable`, + which is typically an instance of + :class:`~sqlalchemy.engine.base.Engine` or + :class:`~sqlalchemy.engine.base.Connection`. + + This method differs from direct a direct constructor call of :class:`Inspector` + in that the :class:`~sqlalchemy.engine.base.Dialect` is given a chance to provide + a dialect-specific :class:`Inspector` instance, which may provide additional + methods. + + See the example at :class:`Inspector`. + + """ + if hasattr(bind.dialect, 'inspector'): + return bind.dialect.inspector(engine) + return Inspector(bind) @property def default_schema_name(self): + """Return the default schema name presented by the dialect + for the current engine's database user. + + E.g. this is typically ``public`` for Postgresql and ``dbo`` + for SQL Server. + + """ return self.dialect.default_schema_name def get_schema_names(self): @@ -125,6 +167,11 @@ class Inspector(object): return tnames def get_table_options(self, table_name, schema=None, **kw): + """Return a dictionary of options specified when the table of the given name was created. + + This currently includes some options that apply to MySQL tables. + + """ if hasattr(self.dialect, 'get_table_options'): return self.dialect.get_table_options(self.bind, table_name, schema, info_cache=self.info_cache, @@ -271,7 +318,25 @@ class Inspector(object): return indexes def reflecttable(self, table, include_columns): - + """Given a Table object, load its internal constructs based on introspection. + + This is the underlying method used by most dialects to produce + table reflection. Direct usage is like:: + + from sqlalchemy import create_engine, MetaData, Table + from sqlalchemy.engine import reflection + + engine = create_engine('...') + meta = MetaData() + user_table = Table('user', meta) + insp = Inspector.from_engine(engine) + insp.reflecttable(user_table, None) + + :param table: a :class:`~sqlalchemy.schema.Table` instance. + :param include_columns: a list of string column names to include + in the reflection process. If ``None``, all columns are reflected. + + """ dialect = self.bind.dialect # MySQL dialect does this. Applicable with other dialects?