B
    \                 @   s   d Z ddlmZ ddlmZ ddlmZ ddlmZ ddlmZ ddlmZ	 dd	l
mZ dd
lmZ ddlmZ ejdd ZG dd deZdS )a  Provides an abstraction for obtaining database schema information.

Usage Notes:

Here are some general conventions when accessing the low level inspector
methods such as get_table_names, get_columns, etc.

1. Inspector methods return lists of dicts in most cases for the following
   reasons:

   * They're both standard types that can be serialized.
   * Using a dict instead of a tuple allows easy expansion of attributes.
   * Using a list for the outer structure maintains order and is easy to work
     with (e.g. list comprehension [d['name'] for d in cols]).

2. Records that contain a name, such as the column name in a column record
   use the key 'name'. So for most return values, each record will have a
   'name' attribute..
   )Connectable   )exc)
inspection)sql)util)schema)
TypeEngine)
deprecated)topologicalc             O   s   | dd }|d kr&| ||f||S | jtdd |D tdd | D f}| |}|d kr~| ||f||}|||< |S )N
info_cachec             s   s   | ]}t |tjr|V  qd S )N)
isinstancer   string_types).0a r   ;lib/python3.7/site-packages/sqlalchemy/engine/reflection.py	<genexpr>.   s    zcache.<locals>.<genexpr>c             s   s2   | ]*\}}t |tjtj tf r||fV  qd S )N)r   r   r   Z	int_typesfloat)r   kvr   r   r   r   0   s   )get__name__tupleitems)fnselfZconargskwr   keyZretr   r   r   cache'   s    
r    c               @   s<  e Zd ZdZdd Zedd Zee	dd Z
edd	 Zd
d ZejdddCddZdDddZdd Zdd ZdEddZdFddZdGddZdHddZedd dId!d"ZdJd#d$ZdKd%d&ZdLd'd(ZdMd)d*ZdNd+d,ZdOd-d.ZdPd1d2Z d3d4 Z!d5d6 Z"d7d8 Z#d9d: Z$d;d< Z%d=d> Z&d?d@ Z'dAdB Z(dS )Q	Inspectoram  Performs database schema inspection.

    The Inspector acts as a proxy to the reflection methods of the
    :class:`~sqlalchemy.engine.interfaces.Dialect`, providing a
    consistent interface as well as caching support for previously
    fetched metadata.

    A :class:`.Inspector` object is usually created via the
    :func:`.inspect` function::

        from sqlalchemy import inspect, create_engine
        engine = create_engine('...')
        insp = inspect(engine)

    The inspection method above is equivalent to using the
    :meth:`.Inspector.from_engine` method, i.e.::

        engine = create_engine('...')
        insp = Inspector.from_engine(engine)

    Where above, the :class:`~sqlalchemy.engine.interfaces.Dialect` may opt
    to return an :class:`.Inspector` subclass that provides additional
    methods specific to the dialect's target database.

    c             C   sJ   || _ t|dr|j| _n|| _| j|kr6|   | jj| _i | _dS )aj  Initialize a new :class:`.Inspector`.

        :param bind: a :class:`~sqlalchemy.engine.Connectable`,
          which is typically an instance of
          :class:`~sqlalchemy.engine.Engine` or
          :class:`~sqlalchemy.engine.Connection`.

        For a dialect-specific instance of :class:`.Inspector`, see
        :meth:`.Inspector.from_engine`

        engineN)bindhasattrr"   Zconnectclosedialectr   )r   r#   r   r   r   __init__W   s    



zInspector.__init__c             C   s    t |jdr|j|S t|S )a  Construct a new dialect-specific Inspector object from the given
        engine or connection.

        :param bind: a :class:`~sqlalchemy.engine.Connectable`,
          which is typically an instance of
          :class:`~sqlalchemy.engine.Engine` or
          :class:`~sqlalchemy.engine.Connection`.

        This method differs from direct a direct constructor call of
        :class:`.Inspector` in that the
        :class:`~sqlalchemy.engine.interfaces.Dialect` is given a chance to
        provide a dialect-specific :class:`.Inspector` instance, which may
        provide additional methods.

        See the example at :class:`.Inspector`.

        	inspector)r$   r&   r(   r!   )clsr#   r   r   r   from_engines   s    zInspector.from_enginec             C   s
   t | S )N)r!   r*   )r#   r   r   r   _insp   s    zInspector._inspc             C   s   | j jS )zReturn 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.

        )r&   default_schema_name)r   r   r   r   r,      s    	zInspector.default_schema_namec             C   s$   t | jdr | jj| j| jdS g S )z!Return all schema names.
        get_schema_names)r   )r$   r&   r-   r#   r   )r   r   r   r   r-      s    zInspector.get_schema_names)z1.0zThe :paramref:`get_table_names.order_by` parameter is deprecated and will be removed in a future release.  Please refer to :meth:`.Inspector.get_sorted_table_and_fkc_names` for a more comprehensive solution to resolving foreign key cycles between tables.)order_byNc             C   s   t | jdr$| jj| j|| jd}n| j|}|dkrg }x@|D ]8}x2| ||D ]"}||d krT||d |f qTW qBW t	t
||}|S )a  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:`.Inspector.get_view_names`
        method.


        :param schema: Schema name. If ``schema`` is left at ``None``, the
         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``.  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.  Does not automatically
         resolve cycles, and will raise :class:`.CircularDependencyError`
         if cycles exist.

        .. seealso::

            :meth:`.Inspector.get_sorted_table_and_fkc_names`

            :attr:`.MetaData.sorted_tables`

        get_table_names)r   Zforeign_keyreferred_table)r$   r&   r/   r#   r   r"   table_namesget_foreign_keysappendlistr   sort)r   r   r.   tnamestuplestnamefkeyr   r   r   r/      s    %
zInspector.get_table_namesc       	   
      sD  t | jdr$| jj| j|| jd}n| j|}t }t i xZ|D ]R}| ||}tdd |D |< x*|D ]"}||d krr|	|d |f qrW qFW yt
t||}W np tjk
r  } zNx8|jD ]. |   fdd d  D  qW t
t||}W d	d	}~X Y nX fd
d|D d	t
fg S )ax  Return dependency-sorted table and foreign key constraint names in
        referred to within a particular schema.

        This will yield 2-tuples of
        ``(tablename, [(tname, fkname), (tname, fkname), ...])``
        consisting of table names in CREATE order grouped with the foreign key
        constraint names that are not detected as belonging to a cycle.
        The final element
        will be ``(None, [(tname, fkname), (tname, fkname), ..])``
        which will consist of remaining
        foreign key constraint names that would require a separate CREATE
        step after-the-fact, based on dependencies between tables.

        .. versionadded:: 1.0.-

        .. seealso::

            :meth:`.Inspector.get_table_names`

            :func:`.sort_tables_and_constraints` - similar method which works
             with an already-given :class:`.MetaData`.

        r/   )r   c             S   s   g | ]}|d  qS )namer   )r   Zfkr   r   r   
<listcomp>   s    z<Inspector.get_sorted_table_and_fkc_names.<locals>.<listcomp>r0   c             3   s   | ]} d  |fV  qdS )r   Nr   )r   Zfkc)edger   r   r     s    z;Inspector.get_sorted_table_and_fkc_names.<locals>.<genexpr>r   Nc                s   g | ]}| |  fqS r   )
difference)r   r8   )fknames_for_tableremaining_fkcsr   r   r;     s   )r$   r&   r/   r#   r   r"   r1   setr2   addr4   r   r5   r   ZCircularDependencyErrorZedgesremoveupdate)	r   r   r6   r7   r8   fkeysr9   Zcandidate_sorterrr   )r<   r>   r?   r   get_sorted_table_and_fkc_names   s0    


 "z(Inspector.get_sorted_table_and_fkc_namesc             C   s   | j j| j| jdS )zreturn a list of temporary table names for the current bind.

        This method is unsupported by most dialects; currently
        only SQLite implements it.

        .. versionadded:: 1.0.0

        )r   )r&   get_temp_table_namesr#   r   )r   r   r   r   rG     s    	zInspector.get_temp_table_namesc             C   s   | j j| j| jdS )zreturn a list of temporary view names for the current bind.

        This method is unsupported by most dialects; currently
        only SQLite implements it.

        .. versionadded:: 1.0.0

        )r   )r&   get_temp_view_namesr#   r   )r   r   r   r   rH     s    	zInspector.get_temp_view_namesc             K   s0   t | jdr,| jj| j||fd| ji|S i S )a  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.

        :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`.

        get_table_optionsr   )r$   r&   rI   r#   r   )r   
table_namer   r   r   r   r   rI   )  s    zInspector.get_table_optionsc             C   s   | j j| j|| jdS )zReturn all view names in `schema`.

        :param schema: Optional, retrieve names from a non-default schema.
         For special quoting, use :class:`.quoted_name`.

        )r   )r&   get_view_namesr#   r   )r   r   r   r   r   rK   =  s    zInspector.get_view_namesc             C   s   | j j| j||| jdS )zReturn definition for `view_name`.

        :param schema: Optional, retrieve names from a non-default schema.
         For special quoting, use :class:`.quoted_name`.

        )r   )r&   get_view_definitionr#   r   )r   Z	view_namer   r   r   r   rL   I  s    zInspector.get_view_definitionc             K   sN   | j j| j||fd| ji|}x(|D ] }|d }t|ts&| |d< q&W |S )a  Return information about columns in `table_name`.

        Given a string `table_name` and an optional string `schema`, return
        column information as a list of dicts with these keys:

        * ``name`` - the column's name

        * ``type`` - the type of this column; an instance of
          :class:`~sqlalchemy.types.TypeEngine`

        * ``nullable`` - boolean flag if the column is NULL or NOT NULL

        * ``default`` - the column's server default value - this is returned
          as a string SQL expression.

        * ``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`.

        :return: list of dictionaries, each representing the definition of
         a database column.

        r   type)r&   get_columnsr#   r   r   r	   )r   rJ   r   r   Zcol_defsZcol_defcoltyper   r   r   rN   U  s    

zInspector.get_columnsz0.7zThe :meth:`.Inspector.get_primary_keys` method is deprecated and will be removed in a future release.  Please refer to the :meth:`.Inspector.get_pk_constraint` method.c             K   s$   | j j| j||fd| ji|d S )zReturn information about primary keys in `table_name`.

        Given a string `table_name`, and an optional string `schema`, return
        primary key information as a list of column names.
        r   constrained_columns)r&   get_pk_constraintr#   r   )r   rJ   r   r   r   r   r   get_primary_keys}  s    zInspector.get_primary_keysc             K   s    | j j| j||fd| ji|S )a  Return information about primary key constraint on `table_name`.

        Given a string `table_name`, and an optional string `schema`, return
        primary key information as a dictionary with these keys:

        constrained_columns
          a list of column names that make up the primary key

        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`.

        r   )r&   rQ   r#   r   )r   rJ   r   r   r   r   r   rQ     s    zInspector.get_pk_constraintc             K   s    | j j| j||fd| ji|S )a  Return information about foreign_keys in `table_name`.

        Given a string `table_name`, and an optional string `schema`, return
        foreign key information as a list of dicts with these keys:

        constrained_columns
          a list of column names that make up the foreign key

        referred_schema
          the name of the referred schema

        referred_table
          the name of the referred table

        referred_columns
          a list of column names in the referred table that correspond to
          constrained_columns

        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`.

        r   )r&   r2   r#   r   )r   rJ   r   r   r   r   r   r2     s    zInspector.get_foreign_keysc             K   s    | j j| j||fd| ji|S )a  Return information about indexes in `table_name`.

        Given a string `table_name` and an optional string `schema`, return
        index information as a list of dicts with these keys:

        name
          the index's name

        column_names
          list of column names in order

        unique
          boolean

        dialect_options
          dict of dialect-specific index options.  May not be present
          for all dialects.

          .. versionadded:: 1.0.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`.

        r   )r&   get_indexesr#   r   )r   rJ   r   r   r   r   r   rS     s    zInspector.get_indexesc             K   s    | j j| j||fd| ji|S )ao  Return information about unique constraints in `table_name`.

        Given a string `table_name` and an optional string `schema`, return
        unique constraint information as a list of dicts with these keys:

        name
          the unique constraint's name

        column_names
          list of column names in order

        :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`.

        r   )r&   get_unique_constraintsr#   r   )r   rJ   r   r   r   r   r   rT     s    z Inspector.get_unique_constraintsc             K   s    | j j| j||fd| ji|S )a  Return information about the table comment for ``table_name``.

        Given a string ``table_name`` and an optional string ``schema``,
        return table comment information as a dictionary with these keys:

        text
            text of the comment.

        Raises ``NotImplementedError`` for a dialect that does not support
        comments.

        .. versionadded:: 1.2

        r   )r&   get_table_commentr#   r   )r   rJ   r   r   r   r   r   rU     s    zInspector.get_table_commentc             K   s    | j j| j||fd| ji|S )a  Return information about check constraints in `table_name`.

        Given a string `table_name` and an optional string `schema`, return
        check constraint information as a list of dicts with these keys:

        name
          the check constraint's name

        sqltext
          the check constraint's SQL expression

        :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:: 1.1.0

        r   )r&   get_check_constraintsr#   r   )r   rJ   r   r   r   r   r   rV     s    zInspector.get_check_constraintsr   Tc          
      sl  |dk	r |krdS |   | jj}| j } j}t fdd|jD }	| j||f j}
|
rp 	|
 t
jrt|tr||j}t|tr||j}d}i }x0| j||f jD ]}d}|  |||| qW |st j| || || | || |||||	 | || ||||	 | || ||||	 | || ||||	 | || |	 dS )a  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.reflection import Inspector

            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.

        Nc             3   s(   | ] }| j kr| j |fV  qd S )N)dialect_kwargsr   )r   r   )tabler   r   r   a  s   z)Inspector.reflecttable.<locals>.<genexpr>FT)rA   r#   r&   Zschema_for_objectr:   dictreflection_optionsrI   rW   Z_validate_dialect_kwargsr   Zpy2kr   strdecodeencodingrN   _reflect_columnr   ZNoSuchTableError_reflect_pk_reflect_fk_reflect_indexes_reflect_unique_constraints_reflect_check_constraints_reflect_table_comment)r   rX   include_columnsexclude_columnsresolve_fks
_extend_onr&   r   rJ   rZ   Ztbl_optsZfound_tablecols_by_orig_namecol_dr   )rX   r   reflecttable3  s    





zInspector.reflecttablec                s(   d }|j | |   d }|r,||ks8|r<||kr<d S  d }t fdddD }	d krp|	 d  g }
 dd k	rֈ d }t|tjjrt	j
|dd	}n$t|t	jst	j
t d dd	}|
| d
 kr|  |
 t	j||f|
|	 ||< }|j|jkrd|_|| d S )Nr:   rM   c             3   s"   | ]}| kr| | fV  qd S )Nr   )r   r   )rj   r   r   r     s   z,Inspector._reflect_column.<locals>.<genexpr>)ZnullableZautoincrementZquoteinfor   commentdialect_optionsdefaultT)Z
_reflectedsequence)dispatchZcolumn_reflectrY   rC   r   r   r   elementsZ
TextClause	sa_schemaZDefaultClauseZFetchedValuetextr3   _reflect_col_sequenceZColumnr   primary_keyZappend_column)r   rX   rj   re   rf   ri   Z	orig_namer:   rO   Zcol_kwcolargsro   colr   )rj   r   r^     s8    


zInspector._reflect_columnc             C   sT   d|krP|d }t |d dd}d|kr4|d |_d|krF|d |_|| d S )Nrp   r:   r   start	increment)rs   Sequencery   rz   r3   )r   rj   rw   seqrp   r   r   r   ru     s    

zInspector._reflect_col_sequencec                sL   | j ||f|j}|rH fdd|d D }|d|j_|j| d S )Nc                s$   g | ]}| kr|kr | qS r   r   )r   Zpk)ri   rf   r   r   r;     s   z)Inspector._reflect_pk.<locals>.<listcomp>rP   r:   )rQ   rW   r   rv   r:   Z_reload)r   rJ   r   rX   ri   rf   Zpk_consZpk_colsr   )ri   rf   r   r_     s    zInspector._reflect_pkc	          	      sL  | j ||f|j}	x2|	D ](}
|
d } fdd|
d D }|rRt||rRq|
d }|
d }|
d }g }|d k	r|rtj||jfd|| j|d	| xn|D ]}|d
	|||g qW nJ|rtj||jfd| jtj
|d| x |D ]}|d
	||g qW d|
kr |
d }ni }|tj|||fddi| qW d S )Nr:   c                s"   g | ]}| kr | j n|qS r   )r   )r   c)ri   r   r   r;   $  s   z)Inspector._reflect_fk.<locals>.<listcomp>rP   referred_schemar0   referred_columnsT)autoloadr   autoload_withrh   .)r   r   r   rh   optionsZlink_to_name)r2   rW   r@   intersectionrs   ZTableZmetadatar#   r3   joinZBLANK_SCHEMAappend_constraintZForeignKeyConstraint)r   rJ   r   rX   ri   rf   rg   rh   rZ   rD   Zfkey_dconnamerP   r~   r0   r   Zrefspeccolumnr   r   )ri   r   r`     s^    




zInspector._reflect_fkc             C   s"  |  ||}x|D ]}	|	d }
|	d }|	d }|	dd}|	di }|	d}|rt||std|d	|f  q|rqg }x^|D ]V}y||kr|| n|j| }W n( tk
r   td
|||f  Y qX |	| qW t
j|
f|d|itt| d|fg  qW d S )Nr:   column_namesuniquerM   indexrn   Zduplicates_constraintz5Omitting %s key for (%s), key covers omitted columns.z, z5%s key '%s' was not located in columns for table '%s'Z_table)rS   r   r@   issubsetr   warnr   r}   KeyErrorr3   rs   ZIndexrY   r4   r   )r   rJ   r   rX   ri   re   rf   rZ   ZindexesZindex_dr:   columnsr   Zflavorrn   
duplicatesZidx_colsr}   Zidx_colr   r   r   ra   Y  s<    

zInspector._reflect_indexesc          
   C   s   y|  ||}W n tk
r$   d S X x|D ]}	|	d }
|	d }|	d}|rrt||srtdd|  q,|rxq,g }x\|D ]T}y||kr|| n|j| }W n& t	k
r   td||f  Y qX |
| qW |tj|d|
i q,W d S )Nr:   r   Zduplicates_indexzDOmitting unique constraint key for (%s), key covers omitted columns.z, zDunique constraint key '%s' was not located in columns for table '%s')rT   NotImplementedErrorr   r@   r   r   r   r   r}   r   r3   r   rs   ZUniqueConstraint)r   rJ   r   rX   ri   re   rf   rZ   constraintsconst_dr   r   r   Zconstrained_colsr}   Zconstrained_colr   r   r   rb     s6    


z%Inspector._reflect_unique_constraintsc       
      C   sJ   y|  ||}W n tk
r$   d S X x|D ]}	|tjf |	 q,W d S )N)rV   r   r   rs   ZCheckConstraint)
r   rJ   r   rX   ri   re   rf   rZ   r   r   r   r   r   rc     s    

z$Inspector._reflect_check_constraintsc             C   s8   y|  ||}W n tk
r$   d S X |dd |_d S )Nrt   )rU   r   r   rm   )r   rJ   r   rX   rZ   Zcomment_dictr   r   r   rd     s
    z Inspector._reflect_table_comment)NN)N)N)N)N)N)N)N)N)N)N)N)N)r   TN))r   
__module____qualname____doc__r'   classmethodr*   r   Z	_inspectsr   r+   propertyr,   r-   r   Zdeprecated_paramsr/   rF   rG   rH   rI   rK   rL   rN   r
   rR   rQ   r2   rS   rT   rU   rV   rk   r^   ru   r_   r`   ra   rb   rc   rd   r   r   r   r   r!   <   sL   
*
8



(

#
"


  
 9H53r!   N)r   baser    r   r   r   r   r   rs   Zsql.type_apir	   r
   r   Z	decoratorr    objectr!   r   r   r   r   <module>   s   