From da4499393acdaacdf1f643e57f657fe74e138de4 Mon Sep 17 00:00:00 2001 From: Randall Smith Date: Sun, 1 Mar 2009 06:02:57 +0000 Subject: [PATCH] removed redundant methods from Inspector --- lib/sqlalchemy/dialects/postgres/base.py | 18 ++- lib/sqlalchemy/engine/reflection.py | 176 +++++++---------------- 2 files changed, 60 insertions(+), 134 deletions(-) diff --git a/lib/sqlalchemy/dialects/postgres/base.py b/lib/sqlalchemy/dialects/postgres/base.py index 6817ce0bcb..cd64a3c648 100644 --- a/lib/sqlalchemy/dialects/postgres/base.py +++ b/lib/sqlalchemy/dialects/postgres/base.py @@ -499,7 +499,8 @@ class PGDialect(default.DefaultDialect): raise AssertionError("Could not determine version from string '%s'" % v) return tuple([int(x) for x in m.group(1, 2, 3)]) - def _get_table_oid(self, connection, tablename, schemaname=None): + @reflection.cache + def get_table_oid(self, connection, tablename, schemaname=None, **kw): """Fetch the oid for schemaname.tablename. Several reflection methods require the table oid. The idea for using @@ -593,7 +594,8 @@ class PGDialect(default.DefaultDialect): @reflection.cache def get_columns(self, connection, tablename, schemaname=None, **kw): - table_oid = self._get_table_oid(connection, tablename, schemaname) + table_oid = self.get_table_oid(connection, tablename, schemaname, + info_cache=kw.get('info_cache')) SQL_COLS = """ SELECT a.attname, pg_catalog.format_type(a.atttypid, a.atttypmod), @@ -679,7 +681,8 @@ class PGDialect(default.DefaultDialect): @reflection.cache def get_primary_keys(self, connection, tablename, schemaname=None, **kw): - table_oid = self._get_table_oid(connection, tablename, schemaname) + table_oid = self.get_table_oid(connection, tablename, schemaname, + info_cache=kw.get('info_cache')) PK_SQL = """ SELECT attname FROM pg_attribute WHERE attrelid = ( @@ -696,7 +699,8 @@ class PGDialect(default.DefaultDialect): @reflection.cache def get_foreign_keys(self, connection, tablename, schemaname=None, **kw): preparer = self.identifier_preparer - table_oid = self._get_table_oid(connection, tablename, schemaname) + table_oid = self.get_table_oid(connection, tablename, schemaname, + info_cache=kw.get('info_cache')) FK_SQL = """ SELECT conname, pg_catalog.pg_get_constraintdef(oid, true) as condef FROM pg_catalog.pg_constraint r @@ -732,7 +736,8 @@ class PGDialect(default.DefaultDialect): @reflection.cache def get_indexes(self, connection, tablename, schemaname, **kw): - table_oid = self._get_table_oid(connection, tablename, schemaname) + table_oid = self.get_table_oid(connection, tablename, schemaname, + info_cache=kw.get('info_cache')) IDX_SQL = """ SELECT c.relname, i.indisunique, i.indexprs, i.indpred, a.attname @@ -803,7 +808,8 @@ class PGDialect(default.DefaultDialect): colargs.append(schema.DefaultClause(sql.text(default))) table.append_column(schema.Column(name, coltype, nullable=nullable, *colargs)) # Now we have the table oid cached. - table_oid = self._get_table_oid(connection, tablename, schemaname) + table_oid = self.get_table_oid(connection, tablename, schemaname, + info_cache=info_cache) # Primary keys for pk in self.get_primary_keys(connection, tablename, schemaname, info_cache=info_cache): diff --git a/lib/sqlalchemy/engine/reflection.py b/lib/sqlalchemy/engine/reflection.py index 2e1ec9f50d..f1766ec2a6 100644 --- a/lib/sqlalchemy/engine/reflection.py +++ b/lib/sqlalchemy/engine/reflection.py @@ -17,6 +17,7 @@ I'm still trying to decide upon conventions for both the Inspector interface as """ +import inspect import sqlalchemy from sqlalchemy import util from sqlalchemy.types import TypeEngine @@ -266,7 +267,10 @@ class DefaultInfoCache(object): return self._set_table_data('indexes', indexes, tablename, schemaname) class Inspector(object): - """performs database introspection + """Performs database introspection. + + The Inspector acts as a proxy to the dialects' reflection methods and + provides higher level functions for accessing database schema information. """ @@ -276,6 +280,20 @@ class Inspector(object): conn [sqlalchemy.engine.base.#Connectable] + Upon initialization, new members are added corresponding to the + refection members of the current dialect. + + Dev Notes: + + I used attribute assignment rather than __getattr__ because + I want the Inspector to be inspectable including providing proper + documentation strings for the methods is supports. + + The primary reason for this approach: + + 1. DRY. + 2. Provides access to dialect specific reflection methods. + """ self.conn = conn # set the engine @@ -288,117 +306,31 @@ class Inspector(object): self.info_cache = self.engine.dialect.info_cache() else: self.info_cache = {} - + # add methods from dialect + def filter_reflect_members(m): + if inspect.ismethod(m) and m.__name__.startswith('get_'): + argspec = inspect.getargspec(m) + if isinstance(argspec, tuple) and 'connection' in argspec[0]: + return True + return False + reflection_members = inspect.getmembers(self.engine.dialect, + filter_reflect_members) + def wrap_reflection_method(fn): + def decorated(*args, **kwargs): + args = (self.conn,) + args + kwargs['info_cache'] = self.info_cache + return fn(*args, **kwargs) + return decorated + for (member_name, member) in reflection_members: + if not hasattr(self, member_name): + doc = "This method mirrors the dialect method %s." % member_name + wrapped_member = wrap_reflection_method(member) + wrapped_member.__doc__ = "%s\n\n%s" % (doc, member.__doc__) + setattr(self, member_name, wrapped_member) + + @property def default_schema_name(self): return self.engine.dialect.get_default_schema_name(self.conn) - default_schema_name = property(default_schema_name) - - def get_schema_names(self): - """Return all schema names. - - """ - if hasattr(self.engine.dialect, 'get_schema_names'): - return self.engine.dialect.get_schema_names(self.conn, - info_cache=self.info_cache) - return [] - - def get_table_names(self, schemaname=None, order_by=None): - """Return all table names in `schemaname`. - schemaname: - Optional, retrieve names from a non-default schema. - - This should probably not return view names or maybe it should return - them with an indicator t or v. - - """ - if hasattr(self.engine.dialect, 'get_table_names'): - tnames = self.engine.dialect.get_table_names(self.conn, schemaname, - info_cache=self.info_cache) - else: - tnames = self.engine.table_names(schemaname) - if order_by == 'foreign_key': - ordered_tnames = tnames[:] - # Order based on foreign key dependencies. - for tname in tnames: - table_pos = tnames.index(tname) - fkeys = self.get_foreign_keys(tname, schemaname) - for fkey in fkeys: - rtable = fkey['referred_table'] - if rtable in ordered_tnames: - ref_pos = ordered_tnames.index(rtable) - # Make sure it's lower in the list than anything it - # references. - if table_pos > ref_pos: - ordered_tnames.pop(table_pos) # rtable moves up 1 - # insert just below rtable - ordered_tnames.index(ref_pos, tname) - tnames = ordered_tnames - return tnames - - def get_view_names(self, schemaname=None): - """Return all view names in `schemaname`. - schemaname: - Optional, retrieve names from a non-default schema. - - """ - return self.engine.dialect.get_view_names(self.conn, schemaname, - info_cache=self.info_cache) - - def get_view_definition(self, view_name, schemaname=None): - """Return definition for `view_name`. - schemaname: - Optional, retrieve names from a non-default schema. - - """ - return self.engine.dialect.get_view_definition( - self.conn, view_name, schemaname, info_cache=self.info_cache) - - def get_columns(self, tablename, schemaname=None): - """Return information about columns in `tablename`. - - Given a string `tablename` and an optional string `schemaname`, return - column information as a list of dicts with these keys: - - name - the column's name - - type - [sqlalchemy.types#TypeEngine] - - nullable - boolean - - default - the column's default value - - attrs - dict containing optional column attributes - - """ - - col_defs = self.engine.dialect.get_columns(self.conn, tablename, - schemaname, - info_cache=self.info_cache) - for col_def in col_defs: - # make this easy and only return instances for coltype - coltype = col_def['type'] - if not isinstance(coltype, TypeEngine): - col_def['type'] = coltype() - return col_defs - - def get_primary_keys(self, tablename, schemaname=None): - """Return information about primary keys in `tablename`. - - Given a string `tablename`, and an optional string `schemaname`, return - primary key information as a list of column names. - - """ - - pkeys = self.engine.dialect.get_primary_keys(self.conn, tablename, - schemaname, - info_cache=self.info_cache) - - return pkeys def get_foreign_keys(self, tablename, schemaname=None): """Return information about foreign_keys in `tablename`. @@ -433,24 +365,12 @@ class Inspector(object): fk_def['referred_schema'] = referred_schema return fk_defs - def get_indexes(self, tablename, schemaname=None): - """Return information about indexes in `tablename`. - - Given a string `tablename` and an optional string `schemaname`, return - index information as a list of dicts with these keys: - - name - the index's name + def get_relation_map(self, schemaname=None): + """Provide a mapping of the relations between all tables in schemaname. - column_names - list of column names in order - - unique - boolean + This is an example of a higher level function where Inspector can be + very useful. """ - - indexes = self.engine.dialect.get_indexes(self.conn, tablename, - schemaname, - info_cache=self.info_cache) - return indexes + #todo + pass -- 2.47.3