B
    .`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 )DescriptorPropertyzO: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 N/home/dcms/DCMS/lib/python3.7/site-packages/sqlalchemy/orm/descriptor_props.pyr   ,   s    zDDescriptorProperty.instrument_class.<locals>._ProxyImpl.uses_objectsc             S   s
   || _ d S )N)key)r   r   r   r   r   __init__0   s    z@DescriptorProperty.instrument_class.<locals>._ProxyImpl.__init__get_historyc                s     |||S )N)r   )r   statedict_passive)r   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 )N)setattrname)objvalue)r   r   r   fsetA   s    z1DescriptorProperty.instrument_class.<locals>.fsetc                s   t |  j d S )N)delattrr#   )r$   )r   r   r   fdelD   s    z1DescriptorProperty.instrument_class.<locals>.fdelc                s   t |  jS )N)getattrr#   )r$   )r   r   r   fgetG   s    z1DescriptorProperty.instrument_class.<locals>.fget)r*   r&   r(   c                  s
     S )N)_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parentr/   implZclass_managerZinstrument_attribute)r   r,   r!   descr&   r(   r*   Z
proxy_attrr   )r,   r   r   r   instrument_class$   s(    



z#DescriptorProperty.instrument_class)r   r   r   __doc__r/   r   r6   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`

    )z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)superr8   r   attrscomposite_classgetr:   r;   r<   pop	__class__
Comparatorr=   r>   r   set_creation_order_create_descriptor)r   r2   r@   kwargs)rD   r   r   r   f   s    :
zCompositeProperty.__init__c                s   t t| | |   d S )N)r?   r8   r6   _setup_event_handlers)r   r,   )rD   r   r   r6      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_columns)r   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   
issupersetrA   managerdispatchrefreshrB   )rM   r   r   values)r   )rM   r   r*      s    



z2CompositeProperty._create_descriptor.<locals>.fgetc                s   t | }t | }|j j }| jt j}x |jjD ]}|||||j	}q:W || j< |d krxF j
D ]}t| |d  qlW n*x(t j
| D ]\}}t| || qW d S )N)r   rO   rP   rS   r   rB   NO_VALUErT   setr4   rQ   r"   zip__composite_values__)rM   r%   r   r   attrpreviousfnr   )r   r   r   r&      s    


z2CompositeProperty._create_descriptor.<locals>.fsetc                sb   t | }t | }| jt j}|j j }|j|||j	 x j
D ]}t| |d  qJW d S )N)r   rP   rO   rC   r   rW   rS   rT   remover4   rQ   r"   )rM   r   r   r\   r[   r   )r   r   r   r(      s    

z2CompositeProperty._create_descriptor.<locals>.fdelN)r   r1   )r   r*   r&   r(   r   )r   r   rG      s    	z$CompositeProperty._create_descriptorc                s    fdd j D S )Nc                s   g | ]}t  jj|jqS r   )r)   r3   r2   r   )rL   r   )r   r   r   rN      s    z:CompositeProperty._comparable_elements.<locals>.<listcomp>)props)r   r   )r   r   _comparable_elements   s    z&CompositeProperty._comparable_elementsc             C   s|   g }xr| j D ]h}t|tr,| jj|dd}n>t|tjrF| jj| }n$t|tj	rZ|j
}ntd|f || qW |S )NF)Z_configure_mappersz[Composite expects Column objects or mapped attributes/attribute names as arguments, got: %r)r@   
isinstancestrr3   Zget_propertyr   Column_columntopropertyr   ZInstrumentedAttributer   sa_excArgumentErrorappend)r   r_   r[   r   r   r   r   r_      s    

zCompositeProperty.propsc             C   s   dd | j D S )Nc             S   s   g | ]}t |tjr|qS r   )ra   r   rc   )rL   ar   r   r   rN     s    z-CompositeProperty.columns.<locals>.<listcomp>)r@   )r   r   r   r   columns  s    zCompositeProperty.columnsc             C   s8   x2| j D ](}| j|_| jr(| j|_d|_| j|_qW dS )zwPropagate configuration arguments made on this composite
        to the target columns, for those that apply.

        ))r;   T)Z
instrumentTN)r_   r:   r;   Zstrategy_keyr<   )r   r   r   r   r   rJ     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 )NT)rj   r   )r   rk   )rl   r   r   refresh_handler#  s    z@CompositeProperty._setup_event_handlers.<locals>.refresh_handlerc                sX    j }|sj|krd S xjD ]}||kr d S q W j fddjD  |j< d S )Nc                s   g | ]} j | qS r   )dict)rL   r   )r   r   r   rN   4  s    zZCompositeProperty._setup_event_handlers.<locals>._load_refresh_handler.<locals>.<listcomp>)ro   r   rQ   rA   )r   rk   rj   r   k)r   )r   r   rl   &  s    zFCompositeProperty._setup_event_handlers.<locals>._load_refresh_handlerc                s,   |d kst  j|r(| j jd  d S )N)rX   rQ   intersectionro   rC   r   )r   keys)r   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)ro   rC   r   )r,   
connectionr   )r   r   r   insert_update_handler;  s    zFCompositeProperty._setup_event_handlers.<locals>.insert_update_handlerZafter_insertT)rawZafter_updateload)rv   	propagaterU   ZexpireN)r	   listenr3   )r   rm   rn   rs   ru   r   )rl   r   r   rI     s    
z'CompositeProperty._setup_event_handlersc             C   s   dd | j D S )Nc             S   s   g | ]
}|j qS r   )r   )rL   r   r   r   r   rN   Y  s    z5CompositeProperty._attribute_keys.<locals>.<listcomp>)r_   )r   r   r   r   rQ   W  s    z!CompositeProperty._attribute_keysc             C   s   g }g }d}xt| j D ]j}|j}|j| j||}	|	 r>d}|	 }
|
rV||
 n
|d |	j	rt||	j	 q|d qW |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   )r_   r   rS   r4   r   Zhas_changesnon_deletedextendrg   deletedr   ZHistoryrA   )r   r   r   r   addedr|   Zhas_historyr   r   histrz   r   r   r   r   [  s*    

zCompositeProperty.get_historyc             C   s   |  | |S )N)r=   )r   r,   r   r   r   r+   {  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 )N)r   r?   r8   CompositeBundler   r   )r   Z	property_expr)rD   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   )rL   proc)rowr   r   rN     s    zXCompositeProperty.CompositeBundle.create_row_processor.<locals>.proc.<locals>.<listcomp>)r   rA   )r   )procsr   )r   r   r     s    zDCompositeProperty.CompositeBundle.create_row_processor.<locals>.procr   )r   r   r   labelsr   r   )r   r   r   create_row_processor  s    z6CompositeProperty.CompositeBundle.create_row_processor)r   r   r   r   r   __classcell__r   r   )rD   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 )N)__clause_element__)r   r   r   r   clauses  s    z$CompositeProperty.Comparator.clausesc             C   s   t j| jddiS )Nr<   F)r   Z
ClauseListr`   )r   r   r   r   r     s    z/CompositeProperty.Comparator.__clause_element__c             C   s   t | j|  S )N)r8   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 )Nr   )rL   r   r   r   r   rN     s    zDCompositeProperty.Comparator._bulk_update_tuples.<locals>.<listcomp>z)Can't UPDATE composite attribute %s to %r)	r   rQ   ra   rA   rZ   re   rf   rY   r`   )r   r%   rV   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   )rL   r   )r   r   r   rN     s   zECompositeProperty.Comparator._comparable_elements.<locals>.<listcomp>)r   r   r`   )r   r   )r   r   r`     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   )rL   rh   br   r   r   rN     s    z7CompositeProperty.Comparator.__eq__.<locals>.<listcomp>c                s   g | ]}  |qS r   )adapter)rL   x)r   r   r   rN     s    )lenr   r`   rZ   rY   r   r   and_)r   otherrV   Zcomparisonsr   )r   r   __eq__  s    z#CompositeProperty.Comparator.__eq__c             C   s   t | |S )N)r   not_r   )r   r   r   r   r   __ne__  s    z#CompositeProperty.Comparator.__ne__)r   r   r   r7   __hash__r   r   r   r   r   r   memoized_propertyr`   r   r   r   r   r   r   rE     s   
rE   c             C   s   t | jjjd | j S )N.)rb   r3   r2   r   r   )r   r   r   r   __str__  s    zCompositeProperty.__str__)r   r   r   r7   r   Zdeprecated_paramsr   r6   rK   rG   r   r`   r_   r   ri   rJ   rI   rQ   r   r    r   r+   r   ZBundler   r   rE   r   r   r   r   )rD   r   r8   X   s"   H;: Ir8   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   s:   d }x0| j  D ]"}|j| j }t|ts|j}P qW |S )N)r3   Ziterate_to_rootZ_propsr   ra   r   r=   )r   r,   Zcomparator_callablempr   r   r   r+     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.)AttributeErrorr3   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 )Nr   )sr$   r%   )r   r   r   __set__  s    zLConcreteInheritedProperty.__init__.<locals>.NoninheritedConcreteProp.__set__c                s
      d S )Nr   )r   r$   )r   r   r   
__delete__  s    zOConcreteInheritedProperty.__init__.<locals>.NoninheritedConcreteProp.__delete__c                s   |d kr j S   d S )N)r1   )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   r   NoninheritedConcreteProp  s   r   )r?   r   r   r0   r1   )r   r   )rD   )r   r   r   r     s    z"ConcreteInheritedProperty.__init__)r   r   r   r7   r+   r   r   r   r   )rD   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:`_schema.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:`_schema.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:`_schema.Column`
          to be under a different name is
          unnecessary. This is usually intended to be used when a
          :class:`_schema.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)r?   r   r   r#   
map_columnr1   r=   r7   r/   r>   r   rF   )r   r#   r   r1   r=   r/   r>   )rD   r   r   r     s    pzSynonymProperty.__init__c             C   s   t | jj| jjjS )N)r)   r3   r2   r#   r4   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)   r3   r2   r#   r   ra   r   r   re   ZInvalidRequestErrorr   )r   r[   r   r   r   _proxied_property  s    
z!SynonymProperty._proxied_propertyc             C   s*   | j }| jr| ||}n|||}|S )N)r   r=   )r   r,   r   compr   r   r   r+     s
    z#SynonymProperty._comparator_factoryc             O   s   t | jj| j}|jj||S )N)r)   r3   r2   r#   r4   r   )r   argkwr[   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cre   rf   r#   descriptionrd   r   ZColumnPropertyZ_configure_propertyZ_mapped_by_synonymr3   )r   r3   r   r   r   r   r   
set_parent  s(    zSynonymProperty.set_parent)NNNNN)r   r   r   r   r   r   r   r   r   r+   r   r   r   r   r   )rD   r   r     s       u	r   z0.7z: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)
r?   r   r   r1   r=   r7   r/   r>   r   rF   )r   r=   r1   r/   r>   )rD   r   r   r     s    BzComparableProperty.__init__c             C   s   |  | |S )N)r=   )r   r,   r   r   r   r+   '  s    z&ComparableProperty._comparator_factory)NNN)r   r   r   r7   r   r+   r   r   r   )rD   r   r     s   Ir   N)r7    r   r   r   Z
interfacesr   r   r   r   r	   r
   re   r   r   r   r   ZlanghelpersZdependency_forr8   r   r   Zdeprecated_clsr   r   r   r   r   <module>   s8   <   5 C