diff options
Diffstat (limited to 'lib/sqlalchemy/engine/reflection.py')
-rw-r--r-- | lib/sqlalchemy/engine/reflection.py | 164 |
1 files changed, 115 insertions, 49 deletions
diff --git a/lib/sqlalchemy/engine/reflection.py b/lib/sqlalchemy/engine/reflection.py index 50b3f774c..45f100518 100644 --- a/lib/sqlalchemy/engine/reflection.py +++ b/lib/sqlalchemy/engine/reflection.py @@ -1,5 +1,5 @@ # engine/reflection.py -# Copyright (C) 2005-2013 the SQLAlchemy authors and contributors <see AUTHORS file> +# Copyright (C) 2005-2014 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 @@ -25,9 +25,9 @@ methods such as get_table_names, get_columns, etc. """ from .. import exc, sql -from .. import schema as sa_schema +from ..sql import schema as sa_schema from .. import util -from ..types import TypeEngine +from ..sql.type_api import TypeEngine from ..util import deprecated from ..util import topological from .. import inspection @@ -161,7 +161,7 @@ class Inspector(object): """Return all table names in referred to within a particular schema. The names are expected to be real tables only, not views. - Views are instead returned using the :meth:`.get_view_names` + Views are instead returned using the :meth:`.Inspector.get_view_names` method. @@ -169,7 +169,7 @@ class Inspector(object): database's default schema is used, else the named schema is searched. If the database does not support named schemas, behavior is undefined if ``schema`` is not - passed as ``None``. + passed as ``None``. For special quoting, use :class:`.quoted_name`. :param order_by: Optional, may be the string "foreign_key" to sort the result on foreign key dependencies. @@ -206,6 +206,13 @@ class Inspector(object): This currently includes some options that apply to MySQL tables. + :param table_name: string name of the table. For special quoting, + use :class:`.quoted_name`. + + :param schema: string schema name; if omitted, uses the default schema + of the database connection. For special quoting, + use :class:`.quoted_name`. + """ if hasattr(self.dialect, 'get_table_options'): return self.dialect.get_table_options( @@ -217,6 +224,8 @@ class Inspector(object): """Return all view names in `schema`. :param schema: Optional, retrieve names from a non-default schema. + For special quoting, use :class:`.quoted_name`. + """ return self.dialect.get_view_names(self.bind, schema, @@ -226,6 +235,8 @@ class Inspector(object): """Return definition for `view_name`. :param schema: Optional, retrieve names from a non-default schema. + For special quoting, use :class:`.quoted_name`. + """ return self.dialect.get_view_definition( @@ -251,6 +262,14 @@ class Inspector(object): attrs dict containing optional column attributes + + :param table_name: string name of the table. For special quoting, + use :class:`.quoted_name`. + + :param schema: string schema name; if omitted, uses the default schema + of the database connection. For special quoting, + use :class:`.quoted_name`. + """ col_defs = self.dialect.get_columns(self.bind, table_name, schema, @@ -288,6 +307,13 @@ class Inspector(object): name optional name of the primary key constraint. + :param table_name: string name of the table. For special quoting, + use :class:`.quoted_name`. + + :param schema: string schema name; if omitted, uses the default schema + of the database connection. For special quoting, + use :class:`.quoted_name`. + """ return self.dialect.get_pk_constraint(self.bind, table_name, schema, info_cache=self.info_cache, @@ -315,6 +341,13 @@ class Inspector(object): name optional name of the foreign key constraint. + :param table_name: string name of the table. For special quoting, + use :class:`.quoted_name`. + + :param schema: string schema name; if omitted, uses the default schema + of the database connection. For special quoting, + use :class:`.quoted_name`. + """ return self.dialect.get_foreign_keys(self.bind, table_name, schema, @@ -336,6 +369,13 @@ class Inspector(object): unique boolean + :param table_name: string name of the table. For special quoting, + use :class:`.quoted_name`. + + :param schema: string schema name; if omitted, uses the default schema + of the database connection. For special quoting, + use :class:`.quoted_name`. + """ return self.dialect.get_indexes(self.bind, table_name, @@ -354,7 +394,14 @@ class Inspector(object): column_names list of column names in order - .. versionadded:: 0.9.0 + :param table_name: string name of the table. For special quoting, + use :class:`.quoted_name`. + + :param schema: string schema name; if omitted, uses the default schema + of the database connection. For special quoting, + use :class:`.quoted_name`. + + .. versionadded:: 0.8.4 """ @@ -384,24 +431,25 @@ class Inspector(object): """ dialect = self.bind.dialect - # table attributes we might need. - reflection_options = dict( - (k, table.kwargs.get(k)) for k in dialect.reflection_options if k in table.kwargs) - schema = table.schema table_name = table.name - # apply table options - tbl_opts = self.get_table_options(table_name, schema, **table.kwargs) - if tbl_opts: - table.kwargs.update(tbl_opts) + # get table-level arguments that are specifically + # intended for reflection, e.g. oracle_resolve_synonyms. + # these are unconditionally passed to related Table + # objects + reflection_options = dict( + (k, table.dialect_kwargs.get(k)) + for k in dialect.reflection_options + if k in table.dialect_kwargs + ) - # table.kwargs will need to be passed to each reflection method. Make - # sure keywords are strings. - tblkw = table.kwargs.copy() - for (k, v) in list(tblkw.items()): - del tblkw[k] - tblkw[str(k)] = v + # reflect table options, like mysql_engine + tbl_opts = self.get_table_options(table_name, schema, **table.dialect_kwargs) + if tbl_opts: + # add additional kwargs to the Table if the dialect + # returned them + table._validate_dialect_kwargs(tbl_opts) if util.py2k: if isinstance(schema, str): @@ -409,10 +457,13 @@ class Inspector(object): if isinstance(table_name, str): table_name = table_name.decode(dialect.encoding) - # columns found_table = False - for col_d in self.get_columns(table_name, schema, **tblkw): + cols_by_orig_name = {} + + for col_d in self.get_columns(table_name, schema, **table.dialect_kwargs): found_table = True + orig_name = col_d['name'] + table.dispatch.column_reflect(self, table, col_d) name = col_d['name'] @@ -422,12 +473,12 @@ class Inspector(object): continue coltype = col_d['type'] - col_kw = { - 'nullable': col_d['nullable'], - } - for k in ('autoincrement', 'quote', 'info', 'key'): - if k in col_d: - col_kw[k] = col_d[k] + + col_kw = dict( + (k, col_d[k]) + for k in ['nullable', 'autoincrement', 'quote', 'info', 'key'] + if k in col_d + ) colargs = [] if col_d.get('default') is not None: @@ -441,7 +492,7 @@ class Inspector(object): ) if 'sequence' in col_d: - # TODO: mssql, maxdb and sybase are using this. + # TODO: mssql and sybase are using this. seq = col_d['sequence'] sequence = sa_schema.Sequence(seq['name'], 1, 1) if 'start' in seq: @@ -450,37 +501,41 @@ class Inspector(object): sequence.increment = seq['increment'] colargs.append(sequence) - col = sa_schema.Column(name, coltype, *colargs, **col_kw) + cols_by_orig_name[orig_name] = col = \ + sa_schema.Column(name, coltype, *colargs, **col_kw) + + if col.key in table.primary_key: + col.primary_key = True table.append_column(col) if not found_table: raise exc.NoSuchTableError(table.name) - # Primary keys - pk_cons = self.get_pk_constraint(table_name, schema, **tblkw) + pk_cons = self.get_pk_constraint(table_name, schema, **table.dialect_kwargs) if pk_cons: pk_cols = [ - table.c[pk] + cols_by_orig_name[pk] for pk in pk_cons['constrained_columns'] - if pk in table.c and pk not in exclude_columns - ] - pk_cols += [ - pk - for pk in table.primary_key - if pk.key in exclude_columns + if pk in cols_by_orig_name and pk not in exclude_columns ] - primary_key_constraint = sa_schema.PrimaryKeyConstraint( - name=pk_cons.get('name'), - *pk_cols - ) - table.append_constraint(primary_key_constraint) + # update pk constraint name + table.primary_key.name = pk_cons.get('name') + + # tell the PKConstraint to re-initialize + # it's column collection + table.primary_key._reload(pk_cols) - # Foreign keys - fkeys = self.get_foreign_keys(table_name, schema, **tblkw) + fkeys = self.get_foreign_keys(table_name, schema, **table.dialect_kwargs) for fkey_d in fkeys: conname = fkey_d['name'] - constrained_columns = fkey_d['constrained_columns'] + # look for columns by orig name in cols_by_orig_name, + # but support columns that are in-Python only as fallback + constrained_columns = [ + cols_by_orig_name[c].key + if c in cols_by_orig_name else c + for c in fkey_d['constrained_columns'] + ] if exclude_columns and set(constrained_columns).intersection( exclude_columns): continue @@ -504,9 +559,14 @@ class Inspector(object): ) for column in referred_columns: refspec.append(".".join([referred_table, column])) + if 'options' in fkey_d: + options = fkey_d['options'] + else: + options = {} table.append_constraint( sa_schema.ForeignKeyConstraint(constrained_columns, refspec, - conname, link_to_name=True)) + conname, link_to_name=True, + **options)) # Indexes indexes = self.get_indexes(table_name, schema) for index_d in indexes: @@ -520,5 +580,11 @@ class Inspector(object): "Omitting %s KEY for (%s), key covers omitted columns." % (flavor, ', '.join(columns))) continue - sa_schema.Index(name, *[table.columns[c] for c in columns], + # look for columns by orig name in cols_by_orig_name, + # but support columns that are in-Python only as fallback + sa_schema.Index(name, *[ + cols_by_orig_name[c] if c in cols_by_orig_name + else table.c[c] + for c in columns + ], **dict(unique=unique)) |