U
    x^n                     @   s4  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 ddlmZ ddlmZ ddlmZ G dd deZejjdddG dd deZejjdddG dd deZejjdddG dd deZejjdddeddG dd deZdS )zDescriptor properties are more "auxiliary" properties
that exist as configurational elements, but don't participate
as actively in the load/persist ORM loop.

   )
attributes)
properties)query)MapperProperty)PropComparator)	_none_set   )event)exc)schema)sql)util)
expressionc                   @   s    e Zd ZdZdZdZdd ZdS )DescriptorPropertyzS:class:`.MapperProperty` which proxies access to a
        user-defined descriptor.NFc                    s   G fdddt }jd krBt jjd } |rB|_jd krfdd}fdd}fdd}t|||d	_tjj	jjj fd
dj
d}|j|_ jj| d S )Nc                       sL   e Zd ZdZdZdZe fddZdd Ze	 drHe
jf fdd		Zd
S )z7DescriptorProperty.instrument_class.<locals>._ProxyImplFTc                    s    j S N)uses_objectsselfprop G/tmp/pip-install-dq5v43_d/SQLAlchemy/sqlalchemy/orm/descriptor_props.pyr   ,   s    zDDescriptorProperty.instrument_class.<locals>._ProxyImpl.uses_objectsc                 S   s
   || _ d S r   key)r   r   r   r   r   __init__0   s    z@DescriptorProperty.instrument_class.<locals>._ProxyImpl.__init__get_historyc                    s     |||S r   )r   )r   statedict_passiver   r   r   r   5   s    zCDescriptorProperty.instrument_class.<locals>._ProxyImpl.get_historyN)__name__
__module____qualname__Zaccepts_scalar_loaderZexpire_missingZ
collectionpropertyr   r   hasattrr   PASSIVE_OFFr   r   r   r   r   
_ProxyImpl'   s   
r%   c                    s   t |  j| d S r   )setattrname)objvaluer   r   r   fsetA   s    z1DescriptorProperty.instrument_class.<locals>.fsetc                    s   t |  j d S r   )delattrr'   r(   r   r   r   fdelD   s    z1DescriptorProperty.instrument_class.<locals>.fdelc                    s   t |  jS r   )getattrr'   r,   r   r   r   fgetG   s    z1DescriptorProperty.instrument_class.<locals>.fget)r/   r*   r-   c                      s
     S r   )_comparator_factoryr   )mapperr   r   r   <lambda>P       z5DescriptorProperty.instrument_class.<locals>.<lambda>)docZoriginal_property)object
descriptorr.   class_r   Z_is_userland_descriptorr"   r   Zcreate_proxied_attributeparentr4   implZclass_managerZinstrument_attribute)r   r1   r%   descr*   r-   r/   Z
proxy_attrr   )r1   r   r   r   instrument_class$   s*    



z#DescriptorProperty.instrument_class)r   r    r!   __doc__r4   r   r;   r   r   r   r   r      s   r   zsqlalchemy.orm.propertiesT)Z
add_to_allc                       s   e Zd ZdZejdd fddZ fddZdd	 Zd
d Z	ej
dd Zej
dd Zedd Zdd Zdd Zej
dd ZejfddZdd ZG dd dejZG dd deZd d! Z  ZS )"CompositePropertyzDefines a "composite" mapped attribute, representing a collection
    of columns as one attribute.

    :class:`.CompositeProperty` is constructed using the :func:`.composite`
    function.

    .. seealso::

        :ref:`mapper_composite`

    )0.7z:class:`.AttributeExtension` is deprecated in favor of the :class:`.AttributeEvents` listener interface.  The :paramref:`.composite.extension` parameter will be removed in a future release.)	extensionc                    s   t t|   || _|| _|dd| _|dd| _|dd| _|	d| j
j| _d|krj|	d| _t|  |   dS )aQ  Return a composite column-based property for use with a Mapper.

        See the mapping documentation section :ref:`mapper_composite` for a
        full usage example.

        The :class:`.MapperProperty` returned by :func:`.composite`
        is the :class:`.CompositeProperty`.

        :param class\_:
          The "composite type" class, or any classmethod or callable which
          will produce a new instance of the composite object given the
          column values in order.

        :param \*cols:
          List of Column objects to be mapped.

        :param active_history=False:
          When ``True``, indicates that the "previous" value for a
          scalar attribute should be loaded when replaced, if not
          already loaded.  See the same flag on :func:`.column_property`.

        :param group:
          A group name for this property when marked as deferred.

        :param deferred:
          When True, the column property is "deferred", meaning that it does
          not load immediately, and is instead loaded when the attribute is
          first accessed on an instance.  See also
          :func:`~sqlalchemy.orm.deferred`.

        :param comparator_factory:  a class which extends
          :class:`.CompositeProperty.Comparator` which provides custom SQL
          clause generation for comparison operations.

        :param doc:
          optional string that will be applied as the doc on the
          class-bound descriptor.

        :param info: Optional data dictionary which will be populated into the
            :attr:`.MapperProperty.info` attribute of this object.

        :param extension:
          an :class:`.AttributeExtension` instance,
          or list of extensions, which will be prepended to the list of
          attribute listeners for the resulting descriptor placed on the
          class.

        active_historyFdeferredgroupNcomparator_factoryinfo)superr=   r   attrscomposite_classgetr@   rA   rB   pop	__class__
ComparatorrC   rD   r   set_creation_order_create_descriptor)r   r7   rF   kwargsrJ   r   r   r   f   s    : 
zCompositeProperty.__init__c                    s   t t| | |   d S r   )rE   r=   r;   _setup_event_handlersr   r1   rO   r   r   r;      s    z"CompositeProperty.instrument_classc                 C   s   |    dS )zInitialization which occurs after the :class:`.CompositeProperty`
        has been associated with its parent mapper.

        N)_setup_arguments_on_columnsr   r   r   r   do_init   s    zCompositeProperty.do_initc                    s6    fdd} fdd} fdd}t ||| _dS )ztCreate the Python descriptor that will serve as
        the access point on instances of the mapped class.

        c                    s   t  }t  }j|krv fddjD }j|krv|jd k	sPt|svj| |j< |jj	
|d jg |jd S )Nc                    s   g | ]}t  |qS r   )r.   .0r   instancer   r   
<listcomp>   s    zFCompositeProperty._create_descriptor.<locals>.fget.<locals>.<listcomp>)r   instance_dictinstance_stater   _attribute_keysr   
issupersetrG   managerdispatchrefreshrH   )rW   r   r   valuesr   rV   r   r/      s    



	
z2CompositeProperty._create_descriptor.<locals>.fgetc                    s   t | }t | }|j j }| jt j}|jjD ]}|||||j	}q8|| j< |d krz j
D ]}t| |d  qfn&t j
| D ]\}}t| || qd S r   )r   rY   rZ   r]   r   rH   NO_VALUEr^   setr9   r[   r&   zip__composite_values__)rW   r)   r   r   attrpreviousfnr   r   r   r   r*      s    



 z2CompositeProperty._create_descriptor.<locals>.fsetc                    s^   t | }t | }| jt j}|j j }|j|||j	  j
D ]}t| |d  qHd S r   )r   rZ   rY   rI   r   ra   r]   r^   remover9   r[   r&   )rW   r   r   rf   re   r   r   r   r   r-      s    


z2CompositeProperty._create_descriptor.<locals>.fdelN)r"   r6   )r   r/   r*   r-   r   r   r   rM      s    	z$CompositeProperty._create_descriptorc                    s    fdd j D S )Nc                    s   g | ]}t  jj|jqS r   )r.   r8   r7   r   rU   r   r   r   r   rX      s     z:CompositeProperty._comparable_elements.<locals>.<listcomp>propsr   r   r   r   _comparable_elements   s    z&CompositeProperty._comparable_elementsc                 C   sx   g }| j D ]h}t|tr*| jj|dd}n>t|tjrD| jj| }n$t|tj	rX|j
}ntd|f || q
|S )NF)Z_configure_mappersz[Composite expects Column objects or mapped attributes/attribute names as arguments, got: %r)rF   
isinstancestrr8   Zget_propertyr   Column_columntopropertyr   ZInstrumentedAttributer"   sa_excArgumentErrorappend)r   rk   re   r   r   r   r   rk      s    

zCompositeProperty.propsc                 C   s   dd | j D S )Nc                 S   s   g | ]}t |tjr|qS r   )rm   r   ro   )rU   ar   r   r   rX     s      z-CompositeProperty.columns.<locals>.<listcomp>)rF   r   r   r   r   columns  s    zCompositeProperty.columnsc                 C   s4   | j D ](}| j|_| jr&| j|_d|_| j|_qdS )zwPropagate configuration arguments made on this composite
        to the target columns, for those that apply.

        ))rA   T)Z
instrumentTN)rk   r@   rA   Zstrategy_keyrB   )r   r   r   r   r   rR     s    
z-CompositeProperty._setup_arguments_on_columnsc                    s    fdd} fdd}fdd fdd}fd	d
}t jjd|dd t jjd|dd t jjd|ddd t jjd|ddd t jjd|ddd dS )z>Establish events that populate/expire the composite attribute.c                    s    | |dd d S )NF
is_refreshr   r   args_load_refresh_handlerr   r   load_handler   s    z=CompositeProperty._setup_event_handlers.<locals>.load_handlerc                    s    | |dd d S )NTrv   r   rx   rz   r   r   refresh_handler#  s    z@CompositeProperty._setup_event_handlers.<locals>.refresh_handlerc                    sV    j }|sj|krd S jD ]}||kr d S qj fddjD  |j< d S )Nc                    s   g | ]} j | qS r   )dictrT   r   r   r   rX   4  s     zZCompositeProperty._setup_event_handlers.<locals>._load_refresh_handler.<locals>.<listcomp>)r~   r   r[   rG   )r   ry   rw   r   kr   r   r   r{   &  s    
zFCompositeProperty._setup_event_handlers.<locals>._load_refresh_handlerc                    s,   |d kst  j|r(| j jd  d S r   )rb   r[   intersectionr~   rI   r   )r   keysr   r   r   expire_handler7  s    z?CompositeProperty._setup_event_handlers.<locals>.expire_handlerc                    s   |j  jd dS )zAfter an insert or update, some columns may be expired due
            to server side defaults, or re-populated due to client side
            defaults.  Pop out the composite value here so that it
            recreates.

            N)r~   rI   r   )r1   
connectionr   r   r   r   insert_update_handler;  s    zFCompositeProperty._setup_event_handlers.<locals>.insert_update_handlerZafter_insertT)rawZafter_updateload)r   	propagater_   ZexpireN)r	   listenr8   )r   r|   r}   r   r   r   )r{   r   r   rP     sL    
                  z'CompositeProperty._setup_event_handlersc                 C   s   dd | j D S )Nc                 S   s   g | ]
}|j qS r   r   ri   r   r   r   rX   Y  s     z5CompositeProperty._attribute_keys.<locals>.<listcomp>rj   r   r   r   r   r[   W  s    z!CompositeProperty._attribute_keysc                 C   s   g }g }d}| j D ]j}|j}|j| j||}	|	 r<d}|	 }
|
rT||
 n
|d |	j	rr||	j	 q|d q|rt
| j| gd| j| gS t
d| j| gdS dS )z>Provided for userland code that uses attributes.get_history().FTNr   )rk   r   r]   r9   r   Zhas_changesnon_deletedextendrs   deletedr   ZHistoryrG   )r   r   r   r   addedr   Zhas_historyr   r   histr   r   r   r   r   [  s,    



zCompositeProperty.get_historyc                 C   s   |  | |S r   rC   rQ   r   r   r   r0   {  s    z%CompositeProperty._comparator_factoryc                       s$   e Zd Z fddZdd Z  ZS )z!CompositeProperty.CompositeBundlec                    s$   || _ ttj| j|jf|  d S r   )r"   rE   r=   CompositeBundler   r   )r   Z	property_exprrO   r   r   r     s    z*CompositeProperty.CompositeBundle.__init__c                    s    fdd}|S )Nc                    s   j j fddD  S )Nc                    s   g | ]}| qS r   r   )rU   procrowr   r   rX     s     zXCompositeProperty.CompositeBundle.create_row_processor.<locals>.proc.<locals>.<listcomp>)r"   rG   r   procsr   r   r   r     s    zDCompositeProperty.CompositeBundle.create_row_processor.<locals>.procr   )r   r   r   labelsr   r   r   r   create_row_processor  s    z6CompositeProperty.CompositeBundle.create_row_processor)r   r    r!   r   r   __classcell__r   r   rO   r   r   ~  s   r   c                   @   sV   e Zd ZdZdZedd Zdd Zdd Zd	d
 Z	e
jdd Zdd Zdd ZdS )zCompositeProperty.Comparatora  Produce boolean, comparison, and other operators for
        :class:`.CompositeProperty` attributes.

        See the example in :ref:`composite_operations` for an overview
        of usage , as well as the documentation for :class:`.PropComparator`.

        .. seealso::

            :class:`.PropComparator`

            :class:`.ColumnOperators`

            :ref:`types_operators`

            :attr:`.TypeEngine.comparator_factory`

        Nc                 C   s   |   S r   )__clause_element__r   r   r   r   clauses  s    z$CompositeProperty.Comparator.clausesc                 C   s   t j| jddiS )NrB   F)r   Z
ClauseListrl   r   r   r   r   r     s
    z/CompositeProperty.Comparator.__clause_element__c                 C   s   t | j|  S r   )r=   r   r   r   r   r   r   r   _query_clause_element  s     z2CompositeProperty.Comparator._query_clause_elementc                 C   sT   |d krdd | j jD }n,t|| j jr4| }ntd| j |f t| j|S )Nc                 S   s   g | ]}d qS r   r   rT   r   r   r   rX     s     zDCompositeProperty.Comparator._bulk_update_tuples.<locals>.<listcomp>z)Can't UPDATE composite attribute %s to %r)	r   r[   rm   rG   rd   rq   rr   rc   rl   )r   r)   r`   r   r   r   _bulk_update_tuples  s    
z0CompositeProperty.Comparator._bulk_update_tuplesc                    s(    j r fdd jjD S  jjS d S )Nc                    s   g | ]}t  jj|jqS r   )r.   _adapt_to_entityentityr   ri   r   r   r   rX     s   zECompositeProperty.Comparator._comparable_elements.<locals>.<listcomp>)r   r   rl   r   r   r   r   rl     s
    
z1CompositeProperty.Comparator._comparable_elementsc                    s^   |d krd gt  jj }n| }dd t jj|D } jrT fdd|D }tj| S )Nc                 S   s   g | ]\}}||kqS r   r   )rU   rt   br   r   r   rX     s    z7CompositeProperty.Comparator.__eq__.<locals>.<listcomp>c                    s   g | ]}  |qS r   )adapter)rU   xr   r   r   rX     s     )lenr   rl   rd   rc   r   r   and_)r   otherr`   Zcomparisonsr   r   r   __eq__  s    z#CompositeProperty.Comparator.__eq__c                 C   s   t | |S r   )r   not_r   )r   r   r   r   r   __ne__  s    z#CompositeProperty.Comparator.__ne__)r   r    r!   r<   __hash__r"   r   r   r   r   r   memoized_propertyrl   r   r   r   r   r   r   rK     s   

	rK   c                 C   s   t | jjjd | j S )N.)rn   r8   r7   r   r   r   r   r   r   __str__  s    zCompositeProperty.__str__)r   r    r!   r<   r   Zdeprecated_paramsr   r;   rS   rM   r   rl   rk   r"   ru   rR   rP   r[   r   r$   r   r0   r   ZBundler   r   rK   r   r   r   r   rO   r   r=   X   s.   	A;


:
 Ir=   c                       s(   e Zd ZdZdd Z fddZ  ZS )ConcreteInheritedPropertya4  A 'do nothing' :class:`.MapperProperty` that disables
    an attribute on a concrete subclass that is only present
    on the inherited mapper, not the concrete classes' mapper.

    Cases where this occurs include:

    * When the superclass mapper is mapped against a
      "polymorphic union", which includes all attributes from
      all subclasses.
    * When a relationship() is configured on an inherited mapper,
      but not on the subclass mapper.  Concrete mappers require
      that relationship() is configured explicitly on each
      subclass.

    c                 C   s8   d }| j  D ]$}|j| j }t|ts|j} q4q|S r   )r8   Ziterate_to_rootZ_propsr   rm   r   rC   )r   r1   Zcomparator_callablempr   r   r   r0     s    
z-ConcreteInheritedProperty._comparator_factoryc                    s<   t t    fddG  fdddt}|  _d S )Nc                      s   t d j j jf d S )NzgConcrete %s does not implement attribute %r at the instance level.  Add this property explicitly to %s.)AttributeErrorr8   r   r   r   r   r   warn  s
    z0ConcreteInheritedProperty.__init__.<locals>.warnc                       s2   e Zd ZfddZfddZ fddZdS )zDConcreteInheritedProperty.__init__.<locals>.NoninheritedConcretePropc                    s
      d S r   r   )sr(   r)   r   r   r   __set__  s    zLConcreteInheritedProperty.__init__.<locals>.NoninheritedConcreteProp.__set__c                    s
      d S r   r   )r   r(   r   r   r   
__delete__  s    zOConcreteInheritedProperty.__init__.<locals>.NoninheritedConcreteProp.__delete__c                    s   |d kr j S   d S r   )r6   )r   r(   ownerr   r   r   r   __get__  s    zLConcreteInheritedProperty.__init__.<locals>.NoninheritedConcreteProp.__get__N)r   r    r!   r   r   r   r   r   r   r   NoninheritedConcreteProp  s   r   )rE   r   r   r5   r6   )r   r   rO   r   r   r     s    z"ConcreteInheritedProperty.__init__)r   r    r!   r<   r0   r   r   r   r   rO   r   r     s   
r   c                       sP   e Zd Zd fdd	Zedd Zejdd Zdd	 Z	d
d Z
dd Z  ZS )SynonymPropertyNc                    sR   t t|   || _|| _|| _|| _|p6|r4|jp6d| _|rD|| _	t
|  dS )a}  Denote an attribute name as a synonym to a mapped property,
        in that the attribute will mirror the value and expression behavior
        of another attribute.

        e.g.::

            class MyClass(Base):
                __tablename__ = 'my_table'

                id = Column(Integer, primary_key=True)
                job_status = Column(String(50))

                status = synonym("job_status")


        :param name: the name of the existing mapped property.  This
          can refer to the string name ORM-mapped attribute
          configured on the class, including column-bound attributes
          and relationships.

        :param descriptor: a Python :term:`descriptor` that will be used
          as a getter (and potentially a setter) when this attribute is
          accessed at the instance level.

        :param map_column: **For classical mappings and mappings against
          an existing Table object only**.  if ``True``, the :func:`.synonym`
          construct will locate the :class:`.Column` object upon the mapped
          table that would normally be associated with the attribute name of
          this synonym, and produce a new :class:`.ColumnProperty` that instead
          maps this :class:`.Column` to the alternate name given as the "name"
          argument of the synonym; in this way, the usual step of redefining
          the mapping of the :class:`.Column` to be under a different name is
          unnecessary. This is usually intended to be used when a
          :class:`.Column` is to be replaced with an attribute that also uses a
          descriptor, that is, in conjunction with the
          :paramref:`.synonym.descriptor` parameter::

            my_table = Table(
                "my_table", metadata,
                Column('id', Integer, primary_key=True),
                Column('job_status', String(50))
            )

            class MyClass(object):
                @property
                def _job_status_descriptor(self):
                    return "Status: %s" % self._job_status


            mapper(
                MyClass, my_table, properties={
                    "job_status": synonym(
                        "_job_status", map_column=True,
                        descriptor=MyClass._job_status_descriptor)
                }
            )

          Above, the attribute named ``_job_status`` is automatically
          mapped to the ``job_status`` column::

            >>> j1 = MyClass()
            >>> j1._job_status = "employed"
            >>> j1.job_status
            Status: employed

          When using Declarative, in order to provide a descriptor in
          conjunction with a synonym, use the
          :func:`sqlalchemy.ext.declarative.synonym_for` helper.  However,
          note that the :ref:`hybrid properties <mapper_hybrids>` feature
          should usually be preferred, particularly when redefining attribute
          behavior.

        :param info: Optional data dictionary which will be populated into the
            :attr:`.InspectionAttr.info` attribute of this object.

            .. versionadded:: 1.0.0

        :param comparator_factory: A subclass of :class:`.PropComparator`
          that will provide custom comparison behavior at the SQL expression
          level.

          .. note::

            For the use case of providing an attribute which redefines both
            Python-level and SQL-expression level behavior of an attribute,
            please refer to the Hybrid attribute introduced at
            :ref:`mapper_hybrids` for a more effective technique.

        .. seealso::

            :ref:`synonyms` - Overview of synonyms

            :func:`.synonym_for` - a helper oriented towards Declarative

            :ref:`mapper_hybrids` - The Hybrid Attribute extension provides an
            updated approach to augmenting attribute behavior more flexibly
            than can be achieved with synonyms.

        N)rE   r   r   r'   
map_columnr6   rC   r<   r4   rD   r   rL   )r   r'   r   r6   rC   r4   rD   rO   r   r   r     s    lzSynonymProperty.__init__c                 C   s   t | jj| jjjS r   )r.   r8   r7   r'   r9   r   r   r   r   r   r     s    zSynonymProperty.uses_objectsc                 C   sH   t | jj| j}t|dr&t|jtsBt	d| jjj
| j|f |jS )Nr"   zGsynonym() attribute "%s.%s" only supports ORM mapped attributes, got %r)r.   r8   r7   r'   r#   rm   r"   r   rq   ZInvalidRequestErrorr   )r   re   r   r   r   _proxied_property  s     z!SynonymProperty._proxied_propertyc                 C   s*   | j }| jr| ||}n|||}|S r   )r   rC   )r   r1   r   compr   r   r   r0     s
    z#SynonymProperty._comparator_factoryc                 O   s   t | jj| j}|jj||S r   )r.   r8   r7   r'   r9   r   )r   argkwre   r   r   r   r     s    zSynonymProperty.get_historyc                 C   s   | j r| j|jjkr2td| j|jj| jf nN|jj| j |jkr|j|jj| j  j| jkrtd| j| j| j| jf t	
|jj| j }|j| j||dd | j|_|| _d S )Nz>Can't compile synonym '%s': no column on table '%s' named '%s'zpCan't call map_column=True for synonym %r=%r, a ColumnProperty already exists keyed to the name %r for column %rT)initZ	setparent)r   r   Zpersist_selectablecrq   rr   r'   descriptionrp   r   ZColumnPropertyZ_configure_propertyZ_mapped_by_synonymr8   )r   r8   r   r   r   r   r   
set_parent  s>    
zSynonymProperty.set_parent)NNNNN)r   r    r!   r   r"   r   r   r   r   r0   r   r   r   r   r   rO   r   r     s        x

	r   r>   z:func:`.comparable_property` is deprecated and will be removed in a future release.  Please refer to the :mod:`~sqlalchemy.ext.hybrid` extension.c                       s*   e Zd ZdZd fdd	Zdd Z  ZS )ComparablePropertyz;Instruments a Python property for use in query expressions.Nc                    sF   t t|   || _|| _|p*|r(|jp*d| _|r8|| _t	|  dS )a	  Provides a method of applying a :class:`.PropComparator`
        to any Python descriptor attribute.


        Allows any Python descriptor to behave like a SQL-enabled
        attribute when used at the class level in queries, allowing
        redefinition of expression operator behavior.

        In the example below we redefine :meth:`.PropComparator.operate`
        to wrap both sides of an expression in ``func.lower()`` to produce
        case-insensitive comparison::

            from sqlalchemy.orm import comparable_property
            from sqlalchemy.orm.interfaces import PropComparator
            from sqlalchemy.sql import func
            from sqlalchemy import Integer, String, Column
            from sqlalchemy.ext.declarative import declarative_base

            class CaseInsensitiveComparator(PropComparator):
                def __clause_element__(self):
                    return self.prop

                def operate(self, op, other):
                    return op(
                        func.lower(self.__clause_element__()),
                        func.lower(other)
                    )

            Base = declarative_base()

            class SearchWord(Base):
                __tablename__ = 'search_word'
                id = Column(Integer, primary_key=True)
                word = Column(String)
                word_insensitive = comparable_property(lambda prop, mapper:
                                CaseInsensitiveComparator(
                                    mapper.c.word, mapper)
                            )


        A mapping like the above allows the ``word_insensitive`` attribute
        to render an expression like::

            >>> print SearchWord.word_insensitive == "Trucks"
            lower(search_word.word) = lower(:lower_1)

        :param comparator_factory:
          A PropComparator subclass or factory that defines operator behavior
          for this property.

        :param descriptor:
          Optional when used in a ``properties={}`` declaration.  The Python
          descriptor or property to layer comparison behavior on top of.

          The like-named descriptor will be automatically retrieved from the
          mapped class if left blank in a ``properties`` declaration.

        :param info: Optional data dictionary which will be populated into the
            :attr:`.InspectionAttr.info` attribute of this object.

            .. versionadded:: 1.0.0

        N)
rE   r   r   r6   rC   r<   r4   rD   r   rL   )r   rC   r6   r4   rD   rO   r   r   r     s    BzComparableProperty.__init__c                 C   s   |  | |S r   r   rQ   r   r   r   r0   #  s    z&ComparableProperty._comparator_factory)NNN)r   r    r!   r<   r   r0   r   r   r   rO   r   r     s        Jr   N)r<    r   r   r   Z
interfacesr   r   r   r   r	   r
   rq   r   r   r   r   ZlanghelpersZdependency_forr=   r   r   Zdeprecated_clsr   r   r   r   r   <module>   s:   <   5 ?