B 4])n@s4dZddlmZddlmZddlmZddlmZddlmZddlm Z dd lm Z dd lm Z dd lm Z dd lmZdd lmZddlmZGdddeZejjdddGdddeZejjdddGdddeZejjdddGdddeZejjdddeddGdddeZdS)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@seZdZdZdZddZdS)DescriptorPropertyzS:class:`.MapperProperty` which proxies access to a user-defined descriptor.NcsGfdddt}jdkrDtjjd}|rD|_jdkrfdd}fdd}fdd}t|||d _tjj jjjfd d j d }|j|_ j j|dS) NcsNeZdZdZdZdZefddZddZe drJe j ffdd Z d S) z7DescriptorProperty.instrument_class.._ProxyImplFTcstjjjjS)N)getattrclass_nameimpl uses_objects)self)mapperpropR/opt/alt/python37/lib64/python3.7/site-packages/sqlalchemy/orm/descriptor_props.pyr*szDDescriptorProperty.instrument_class.._ProxyImpl.uses_objectscSs ||_dS)N)key)rrrrr__init__.sz@DescriptorProperty.instrument_class.._ProxyImpl.__init__ get_historycs|||S)N)r)rstatedict_passive)rrrr3szCDescriptorProperty.instrument_class.._ProxyImpl.get_historyN) __name__ __module__ __qualname__Zaccepts_scalar_loaderZexpire_missingZ collectionpropertyrrhasattrr PASSIVE_OFFrr)rrrr _ProxyImpl%s r&cst|j|dS)N)setattrr)objvalue)rrrfset?sz1DescriptorProperty.instrument_class..fsetcst|jdS)N)delattrr)r()rrrfdelBsz1DescriptorProperty.instrument_class..fdelcs t|jS)N)rr)r()rrrfgetEsz1DescriptorProperty.instrument_class..fget)r-r*r,cs S)N)_comparator_factoryr)rrrrNz5DescriptorProperty.instrument_class..)docZoriginal_property)object descriptorrrrZ_is_userland_descriptorr#rZcreate_proxied_attributeparentr1rZ class_managerZinstrument_attribute)rrr&Zdescr*r,r-Z proxy_attrr)rrrrinstrument_class"s(         z#DescriptorProperty.instrument_class)r r!r"__doc__r1r5rrrrrsrzsqlalchemy.orm.propertiesT)Z add_to_allcseZdZdZejddfddZfddZdd Zd d Z ej d d Z ej ddZ e ddZddZddZej ddZejfddZddZGdddejZGdddeZd d!ZZS)"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` )z0.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.) extensioncstt|||_||_|dd|_|dd|_|dd|_| d|j j |_ d|krj| d|_ t||dS)aQReturn 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_historyFdeferredgroupNcomparator_factoryinfo)superr7rattrscomposite_classgetr9r:r;pop __class__ Comparatorr<r=r set_creation_order_create_descriptor)rrr?kwargs)rCrrrds:  zCompositeProperty.__init__cstt|||dS)N)r>r7r5_setup_event_handlers)rr)rCrrr5sz"CompositeProperty.instrument_classcCs |dS)zInitialization which occurs after the :class:`.CompositeProperty` has been associated with its parent mapper. N)_setup_arguments_on_columns)rrrrdo_initszCompositeProperty.do_initcs6fdd}fdd}fdd}t|||_dS)ztCreate the Python descriptor that will serve as the access point on instances of the mapped class. cst}t}j|krvfddjD}j|krv|jdk sPt|svj||j<|jj |djg| jdS)Ncsg|]}t|qSr)r).0r)instancerr szFCompositeProperty._create_descriptor..fget..) r instance_dictinstance_stater_attribute_keysr issupersetr@managerdispatchrefreshrA)rLrrvalues)r)rLrr-s    z2CompositeProperty._create_descriptor..fgetcst|}t|}|jj}|jtj}x |jjD]}|||||j }q:W||j<|dkrxFj D]}t ||dqlWn*x(t j | D]\}}t |||qWdS)N)rrNrOrRrrANO_VALUErSsetrrPr'zip__composite_values__)rLr)rrattrpreviousfnr)rrrr*s     z2CompositeProperty._create_descriptor..fsetcsbt|}t|}|jtj}|jj}|j|||j xj D]}t ||dqJWdS)N) rrOrNrBrrVrRrSremoverrPr')rLrrr[rZr)rrrr,s    z2CompositeProperty._create_descriptor..fdelN)r#r3)rr-r*r,r)rrrFs   z$CompositeProperty._create_descriptorcsfddjDS)Ncsg|]}tjj|jqSr)rr4rr)rKr)rrrrMsz:CompositeProperty._comparable_elements..)props)rr)rr_comparable_elementssz&CompositeProperty._comparable_elementscCs|g}xr|jD]h}t|tr,|jj|dd}n>t|tjrF|jj|}n$t|tj rZ|j }nt d|f| |q W|S)NF)Z_configure_mappersz[Composite expects Column objects or mapped attributes/attribute names as arguments, got: %r)r? isinstancestrr4Z get_propertyr Column_columntopropertyrZInstrumentedAttributer#sa_exc ArgumentErrorappend)rr^rZrrrrr^s     zCompositeProperty.propscCsdd|jDS)NcSsg|]}t|tjr|qSr)r`r rb)rKarrrrM sz-CompositeProperty.columns..)r?)rrrrcolumns szCompositeProperty.columnscCs8x2|jD](}|j|_|jr(|j|_d|_|j|_qWdS)zwPropagate configuration arguments made on this composite to the target columns, for those that apply. ))r:T)Z instrumentTN)r^r9r:Z strategy_keyr;)rrrrrrIs  z-CompositeProperty._setup_arguments_on_columnscsfdd}fdd}fddfdd}fd d }tjjd |d d tjjd|d d tjjd|d d dtjjd|d d dtjjd|d d ddS)z>Establish events that populate/expire the composite attribute.cs||dddS)NF) is_refreshr)rargs)_load_refresh_handlerrr load_handlersz=CompositeProperty._setup_event_handlers..load_handlercs||dddS)NT)rir)rrj)rkrrrefresh_handler!sz@CompositeProperty._setup_event_handlers..refresh_handlercsXj}|sj|krdSxjD]}||kr dSq WjfddjD|j<dS)Ncsg|]}j|qSr)dict)rKr)rrrrM2szZCompositeProperty._setup_event_handlers.._load_refresh_handler..)rnrrPr@)rrjrirk)r)rrrk$s zFCompositeProperty._setup_event_handlers.._load_refresh_handlercs,|dkstj|r(|jjddS)N)rWrP intersectionrnrBr)rkeys)rrrexpire_handler5sz?CompositeProperty._setup_event_handlers..expire_handlercs|jjddS)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)rnrBr)rZ connectionr)rrrinsert_update_handler9szFCompositeProperty._setup_event_handlers..insert_update_handlerZ after_insertT)rawZ after_updateload)rtZ propagaterTZexpireN)r Zlistenr4)rrlrmrrrsr)rkrrrHs     z'CompositeProperty._setup_event_handlerscCsdd|jDS)NcSsg|] }|jqSr)r)rKrrrrrMWsz5CompositeProperty._attribute_keys..)r^)rrrrrPUsz!CompositeProperty._attribute_keysc Csg}g}d}xt|jD]j}|j}|j|j||} | r>d}| } | rV|| n |d| j rt|| j q|dqW|rt |j |gd|j |gSt d|j |gdSdS)z>Provided for userland code that uses attributes.get_history().FTNr) r^rrRrrZ has_changes non_deletedextendrfdeletedrZHistoryr@) rrrrZaddedrxZ has_historyrrZhistrvrrrrYs*    zCompositeProperty.get_historycCs |||S)N)r<)rrrrrr.ysz%CompositeProperty._comparator_factorycs$eZdZfddZddZZS)z!CompositeProperty.CompositeBundlecs$||_ttj|j|jf|dS)N)r#r>r7CompositeBundlerr)rZ property_expr)rCrrr}s z*CompositeProperty.CompositeBundle.__init__csfdd}|S)NcsjjfddDS)Ncsg|] }|qSrr)rKproc)rowrrrMszXCompositeProperty.CompositeBundle.create_row_processor..proc..)r#r@)r|)procsr)r|rr{szDCompositeProperty.CompositeBundle.create_row_processor..procr)rrr}labelsr{r)r}rrcreate_row_processorsz6CompositeProperty.CompositeBundle.create_row_processor)r r!r"rr __classcell__rr)rCrry|s ryc@sVeZdZdZdZeddZddZddZd d Z e j d d Z d dZ ddZdS)zCompositeProperty.ComparatoraProduce 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` NcCs|S)N)__clause_element__)rrrrclausessz$CompositeProperty.Comparator.clausescCstj|jddiS)Nr;F)rZ ClauseListr_)rrrrrsz/CompositeProperty.Comparator.__clause_element__cCst|j|S)N)r7ryrr)rrrr_query_clause_elementsz2CompositeProperty.Comparator._query_clause_elementcCsT|dkrdd|jjD}n,t||jjr4|}ntd|j|ft|j|S)NcSsg|]}dqS)Nr)rKrrrrrMszDCompositeProperty.Comparator._bulk_update_tuples..z)Can't UPDATE composite attribute %s to %r) rrPr`r@rYrdrerXr_)rr)rUrrr_bulk_update_tupless z0CompositeProperty.Comparator._bulk_update_tuplescs(jrfddjjDSjjSdS)Ncsg|]}tjj|jqSr)r_adapt_to_entityZentityr)rKr)rrrrMszECompositeProperty.Comparator._comparable_elements..)rrr_)rr)rrr_s  z1CompositeProperty.Comparator._comparable_elementscs^|dkrdgtjj}n|}ddtjj|D}jrTfdd|D}tj|S)NcSsg|]\}}||kqSrr)rKrgbrrrrMsz7CompositeProperty.Comparator.__eq__..csg|]}|qSr)Zadapter)rKx)rrrrMs)lenrr_rYrXrr and_)rotherrUZ comparisonsr)rr__eq__sz#CompositeProperty.Comparator.__eq__cCst||S)N)r not_r)rrrrr__ne__sz#CompositeProperty.Comparator.__ne__)r r!r"r6__hash__r#rrrrr memoized_propertyr_rrrrrrrDs    rDcCst|jjjd|jS)N.)rar4rr r)rrrr__str__szCompositeProperty.__str__)r r!r"r6r Zdeprecated_paramsrr5rJrFrr_r^r#rhrIrHrPrr%rr.rZBundleryrrDrrrr)rCrr7Vs" H ;  : Ir7cs(eZdZdZddZfddZZS)ConcreteInheritedPropertya4A '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. cCs:d}x0|jD]"}|j|j}t|ts|j}PqW|S)N)r4Ziterate_to_rootZ_propsrr`rr<)rrZcomparator_callablemprrrr.s  z-ConcreteInheritedProperty._comparator_factorycs<ttfddGfdddt}|_dS)NcstdjjjfdS)NzgConcrete %s does not implement attribute %r at the instance level. Add this property explicitly to %s.)AttributeErrorr4rr)rrrwarnsz0ConcreteInheritedProperty.__init__..warncs2eZdZfddZfddZfddZdS)zDConcreteInheritedProperty.__init__..NoninheritedConcretePropcs dS)Nr)sr(r))rrr__set__szLConcreteInheritedProperty.__init__..NoninheritedConcreteProp.__set__cs dS)Nr)rr()rrr __delete__szOConcreteInheritedProperty.__init__..NoninheritedConcreteProp.__delete__cs|dkrjSdS)N)r3)rr(owner)rrrr__get__szLConcreteInheritedProperty.__init__..NoninheritedConcreteProp.__get__N)r r!r"rrrr)rrrrNoninheritedConcreteProps  r)r>rrr2r3)rr)rC)rrrrs  z"ConcreteInheritedProperty.__init__)r r!r"r6r.rrrr)rCrrs rcsDeZdZd fdd ZejddZddZdd Zd d Z Z S) SynonymPropertyNcsRtt|||_||_||_||_|p6|r4|jp6d|_|rD||_ t |dS)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 ` 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>rrr map_columnr3r<r6r1r=r rE)rrrr3r<r1r=)rCrrrslzSynonymProperty.__init__cCsHt|jj|j}t|dr&t|jtsBt d|jjj |j|f|jS)Nr#zGsynonym() attribute "%s.%s" only supports ORM mapped attributes, got %r) rr4rrr$r`r#rrdZInvalidRequestErrorr )rrZrrr_proxied_propertys  z!SynonymProperty._proxied_propertycCs*|j}|jr|||}n |||}|S)N)rr<)rrrcomprrrr.s  z#SynonymProperty._comparator_factorycOst|jj|j}|jj||S)N)rr4rrrr)rargkwrZrrrrszSynonymProperty.get_historycCs|jr|j|jjkr2td|j|jj|jfnN|jj|j|jkr|j|jj|jj|jkrtd|j|j|j|jft |jj|j}|j |j||dd|j|_ ||_ dS)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)rrZpersist_selectablecrdrer descriptionrcrZColumnPropertyZ_configure_propertyZ_mapped_by_synonymr4)rr4rrrrr set_parents( zSynonymProperty.set_parent)NNNNN) r r!r"rr rrr.rrrrr)rCrrst  rz0.7z:func:`.comparable_property` is deprecated and will be removed in a future release. Please refer to the :mod:`~sqlalchemy.ext.hybrid` extension.cs*eZdZdZdfdd ZddZZS)ComparablePropertyz;Instruments a Python property for use in query expressions.NcsFtt|||_||_|p*|r(|jp*d|_|r8||_t |dS)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>rrr3r<r6r1r=r rE)rr<r3r1r=)rCrrrsBzComparableProperty.__init__cCs |||S)N)r<)rrrrrr.sz&ComparableProperty._comparator_factory)NNN)r r!r"r6rr.rrr)rCrrsIrN)r6rrrZ interfacesrrr rr r rdr r rrZ langhelpersZdependency_forr7rrZdeprecated_clsrrrrr s8            :5;