id dZddlZddlmZddlmZddlmZddlmZddlm Z dd lm Z dd lm Z dd lm Z dd lm Z dd lmZddlmZddlmZddlmZddlmZddlmZddlmZddlmZddlmZddlmZddlmZddlmZddlmZddlmZddlmZddlmZddlmZddlmZddlm Z dd lm!Z!d!d"lm"Z"d!d#lm#Z#d!d$lm$Z$e#j%Gd%d&ej&ej'ej(Z)Gd'd(e)Z*d)Z+e$j,d*Z-e$j,d+Z.e$j,d,Z/e$j,d-Z0e$j,d.Z1Gd/d0e2Z3Gd1d2e2Z4Gd3d4e4Z5Gd5d6e5Z6Gd7d8e4Z7d9Z8e$j,d:Z9e:e;ee;ee;egZ<e$j=d;gd<Z>Gd=d;e>Z>e>dddZ?efd>Z@efd?ZAdNdAZBdBZC dOdCZD dPdDZEdEZFdFZGdGZHdHZIdQdIZJdJZKdKZLdLZMdMZNdS)RzDefines instrumentation for class attributes and their interaction with instances. This module is usually not directly visible to user applications, but defines a large part of the ORM's interactivity. N) collections)exc) interfaces) ATTR_EMPTY) ATTR_WAS_SET) CALLABLES_OK)INIT_OK) instance_dictinstance_state) instance_str)LOAD_AGAINST_COMMITTED)manager_of_class) NEVER_SET) NO_AUTOFLUSH) NO_CHANGE)NO_RAISE)NO_VALUE)NON_PERSISTENT_OK)PASSIVE_CLASS_MISMATCH)PASSIVE_NO_FETCH)PASSIVE_NO_FETCH_RELATED)PASSIVE_NO_INITIALIZE)PASSIVE_NO_RESULT) PASSIVE_OFF)PASSIVE_ONLY_PERSISTENT)PASSIVE_RETURN_NEVER_SET)RELATED_OBJECT_OK)SQL_OK) state_str)event) inspection)utilc&eZdZdZdZ ddZejdZe dZ e fdZ dZ ejd Zejd Ze d Zd Zd ZdZdZdZdZdZdZddZdZdZejdZ dS)QueryableAttributeaBase class for :term:`descriptor` objects that intercept attribute events on behalf of a :class:`.MapperProperty` object. The actual :class:`.MapperProperty` is accessible via the :attr:`.QueryableAttribute.property` attribute. .. seealso:: :class:`.InstrumentedAttribute` :class:`.MapperProperty` :attr:`_orm.Mapper.all_orm_descriptors` :attr:`_orm.Mapper.attrs` TNc"||_||_||_||_||_||_t |}|rQ|jD]K}||vrC|j ||j||jj r d|j_ JdSdSNT) class_keyimpl comparator _parententity_of_typer_basesdispatch_update_active_history) selfr*r+r,r- parententityof_typemanagerbases N/opt/cloudlinux/venv/lib/python3.11/site-packages/sqlalchemy/orm/attributes.py__init__zQueryableAttribute.__init__Os  $) "6**  =  = =$;;M))$s)*<===Cy)9=8< 5 = = = =c|jjSN)r,supports_populationr4s r9_supports_populationz'QueryableAttribute._supports_populationjs y,,r;c|jjSr=)r, uses_objectsr?s r9_impl_uses_objectsz%QueryableAttribute._impl_uses_objectsns y%%r;cn|jt|t||Sr=)r, get_historyr r )r4instancepassives r9rEzQueryableAttribute.get_historyrs3y$$ 8 $ $mH&=&=w   r;c|Sr=r?s r9__selectable__z!QueryableAttribute.__selectable__ws r;c|jjS)aReturn the 'info' dictionary for the underlying SQL element. The behavior here is as follows: * If the attribute is a column-mapped property, i.e. :class:`.ColumnProperty`, which is mapped directly to a schema-level :class:`_schema.Column` object, this attribute will return the :attr:`.SchemaItem.info` dictionary associated with the core-level :class:`_schema.Column` object. * If the attribute is a :class:`.ColumnProperty` but is mapped to any other kind of SQL expression other than a :class:`_schema.Column`, the attribute will refer to the :attr:`.MapperProperty.info` dictionary associated directly with the :class:`.ColumnProperty`, assuming the SQL expression itself does not have its own ``.info`` attribute (which should be the case, unless a user-defined SQL construct has defined one). * If the attribute refers to any other kind of :class:`.MapperProperty`, including :class:`.RelationshipProperty`, the attribute will refer to the :attr:`.MapperProperty.info` dictionary associated with that :class:`.MapperProperty`. * To access the :attr:`.MapperProperty.info` dictionary of the :class:`.MapperProperty` unconditionally, including for a :class:`.ColumnProperty` that's associated directly with a :class:`_schema.Column`, the attribute can be referred to using :attr:`.QueryableAttribute.property` attribute, as ``MyClass.someattribute.property.info``. .. seealso:: :attr:`.SchemaItem.info` :attr:`.MapperProperty.info` )r-infor?s r9rLzQueryableAttribute.info{sP##r;c4tj|jS)a Return an inspection instance representing the parent. This will be either an instance of :class:`_orm.Mapper` or :class:`.AliasedInsp`, depending upon the nature of the parent entity which this attribute is associated with. )r$inspectr.r?s r9parentzQueryableAttribute.parents!$"4555r;c4|jS)zThe SQL expression object represented by this :class:`.QueryableAttribute`. This will typically be an instance of a :class:`.ColumnElement` subclass representing a column expression. r-__clause_element__r?s r9 expressionzQueryableAttribute.expressions11333r;c4|jSr=rQr?s r9rRz%QueryableAttribute.__clause_element__s11333r;c4|jS)znlike __clause_element__(), but called specifically by :class:`_query.Query` to allow special behavior.)r-_query_clause_elementr?s r9rVz(QueryableAttribute._query_clause_elements44666r;c6|j|S)z'Return setter tuples for a bulk UPDATE.)r-_bulk_update_tuplesr4values r9rXz&QueryableAttribute._bulk_update_tupless225999r;c|jrJ||j|j|j|j||S)N)r,r-r5)r/ __class__entityr+r,r-adapt_to_entityr4r^s r9r^z"QueryableAttribute.adapt_to_entitysQ=   ~~  " H66GG(    r;ct|j|j|j|j||j|S)N)r6)r'r*r+r,r-r6r.)r4clss r9r6zQueryableAttribute.of_typesD! K H I O # #C ( (       r;cP||Sr=)rVlabel)r4names r9rczQueryableAttribute.labels"))++11$777r;c$||jg|Ri|Sr=r-r4opotherkwargss r9operatezQueryableAttribute.operates$r$/4E444V444r;c |||jfi|Sr=rfrgs r9reverse_operatez"QueryableAttribute.reverse_operatesr%33F333r;Fc>|j||duS)N) optimisticFr, hasparent)r4stateros r9rqzQueryableAttribute.hasparents"y""5Z"@@MMr;c  t|j|S#t$rc}tjtdt |jdt |jjd|d||Yd}~dSd}~wwxYw)NNeither object nor  object associated with  has an attribute replace_context)getattrr-AttributeErrorr%raise_type__name__)r4r+errs r9 __getattr__zQueryableAttribute.__getattr__s 4?C00 0    KT +++T_--666   !$           s BAA??Bc.|jjd|jSN.r*r~r+r?s r9__str__zQueryableAttribute.__str__+...99r;c|jjS)zReturn the :class:`.MapperProperty` associated with this :class:`.QueryableAttribute`. Return values here will commonly be instances of :class:`.ColumnProperty` or :class:`.RelationshipProperty`. r-propertyr?s r9rzQueryableAttribute.propertys''r;)NNNNF)r~ __module__ __qualname____doc__ is_attributer:r%memoized_propertyr@rrCrrErJrLrOrSrRrVrXr^r6rcrkrmrqrrrIr;r9r'r'5s $L ====6 ---&&X&-8     '$'$'$R  6 6 644X4444777 :::       888555444NNNN$:::  ( ( ( ( (r;r'c$eZdZdZdZdZdZdS)InstrumentedAttributezClass bound instrumented attribute which adds basic :term:`descriptor` methods. See :class:`.QueryableAttribute` for a description of most features. ct|jt|t||ddSr=)r,setr r )r4rFrZs r9__set__zInstrumentedAttribute.__set__s= 8 $ $mH&=&=ud     r;cp|jt|t|dSr=)r,deleter r )r4rFs r9 __delete__z InstrumentedAttribute.__delete__s0 11=3J3JKKKKKr;c||St|}|jr|j|vr ||jS|jt ||Sr=)r r@r+r,getr )r4rFownerdict_s r9__get__zInstrumentedAttribute.__get__s\  Kh''  $ BU):):? "9==!9!95AA Ar;N)r~rrrrrrrIr;r9rr sS   LLLBBBBBr;rcGfddt}tjdz|_tj|td|S)zCreate an QueryableAttribute / user descriptor hybrid. Returns a new QueryableAttribute type that delegates descriptor behavior and getattr() to the given descriptor. ceZdZdZ d dZdZedZedZej dZ dZ d Z d Z fd ZdS) 'create_proxied_attribute..ProxyzPresents the :class:`.QueryableAttribute` interface as a proxy on top of a Python descriptor / :class:`.PropComparator` combination. Nch||_||_||_||_||_||_||_dSr=)r*r+ descriptororiginal_property _comparator_adapt_to_entityr)r4r*r+rr-r^docrs r9r:z0create_proxied_attribute..Proxy.__init__:s<!DKDH(DO%6D ")D $3D !DLLLr;Tc\|jduo#t|j|jjjSr=)rrzr*r+r,rBr?s r9rCz:create_proxied_attribute..Proxy._impl_uses_objectsNs1&d2EDK227D r;c|jjSr=rr?s r9rz0create_proxied_attribute..Proxy.propertyUs ?+ +r;ctj|jr||_|jr$|j|j|_|jSr=)r%callablerrr^r?s r9r-z2create_proxied_attribute..Proxy.comparatorYsb}T-.. 6#'#3#3#5#5 $ #'#3#C#C)$$ # #r;c\||j|j|j|j|Sr=)r\r]r+rrr_s r9r^z7create_proxied_attribute..Proxy.adapt_to_entitycs1>>&   r;cV|j||}||jur||S|Sr=)rr)r4rFrretvals r9rz/create_proxied_attribute..Proxy.__get__ls7_,,Xu==F((X-=  r;c.|jjd|jSrrr?s r9rz/create_proxied_attribute..Proxy.__str__vs"k222DHH= =r;cp t|S#t$r}|dkr#tjtd| |j} t||cYd}~S#t$r]}tjtdt jdt |jd|d||Yd}~n]d}~wwxYw#t$rH}tjtdt jd|d||Yd}~nd}~wwxYwYd}~dSYd}~dSd}~wwxYw) zNDelegate __getattr__ to the original descriptor and/or comparator.r-rxNrtrurvrwz; object nor unconfigured comparator object associated with )rzr{r%r|r-r}r~)r4 attributerr-err3err2rs r9rz3create_proxied_attribute..Proxy.__getattr__ys# z9555!! ! !  ,,K&|44c!%J&z9========)    *N%)$4$4$=$=$=$($4$4$=$=$=$(DD$-I !"  -1          &K& $J//888$$$ K )-       ! sc D5)D0CA%D5% C /ACD0C  D0 D!>DD0D!!D00D5NNN)r~rrrr:_is_internal_proxyrrCr%rr-r^rrr)rsr9Proxyr3s  !"    $"       , ,  ,   $ $  $       > > >& & & & & & & r;rr)rd from_instance)r'r}r~r%monkeypatch_proxied_specials)rrs` r9create_proxied_attributer)slllllll"lll\*%%.8EN% tJl* Lr;REMOVEAPPENDREPLACE BULK_REPLACEMODIFIEDc>eZdZdZdZdZdZedZdZ dS)EventaA token propagated throughout the course of a chain of attribute events. Serves as an indicator of the source of the event and also provides a means of controlling propagation across a chain of attribute operations. The :class:`.Event` object is sent as the ``initiator`` argument when dealing with events such as :meth:`.AttributeEvents.append`, :meth:`.AttributeEvents.set`, and :meth:`.AttributeEvents.remove`. The :class:`.Event` object is currently interpreted by the backref event handlers, and is used to control the propagation of operations across two mutually-dependent attributes. .. versionadded:: 0.9.0 :attribute impl: The :class:`.AttributeImpl` which is the current event initiator. :attribute op: The symbol :attr:`.OP_APPEND`, :attr:`.OP_REMOVE`, :attr:`.OP_REPLACE`, or :attr:`.OP_BULK_REPLACE`, indicating the source operation. r,rh parent_tokencD||_||_|jj|_dSr=r)r4attribute_implrhs r9r:zEvent.__init__s#"  I2r;cht|to|j|juo|j|jkSr=) isinstancerr,rh)r4ris r9__eq__z Event.__eq__s6 ue $ $ $ di' $DG# r;c|jjSr=)r,r+r?s r9r+z Event.keys y}r;c6|j|Sr=rp)r4rrs r9rqzEvent.hasparentsy""5)))r;N) r~rrr __slots__r:rrr+rqrIr;r9rrsm6-I333    X*****r;rceZdZdZ ddZdZdZdZd Ze eeZ dd Z d Z e fd Zefd ZdZe fdZe fdZe fdZe fdZe ddfdZe fdZdZdS) AttributeImplz4internal implementation for instrumented attributes.FNTc  ||_||_||_||_||_| p||_| |_|tj|_ n||_ | | |_ n |j |_ t||}tj|pgD]}||||r d|j_| |_t%|t&|_dS)a*Construct an AttributeImpl. :param \class_: associated class :param key: string name of the attribute :param \callable_: optional function which generates a callable based on a parent instance, which produces the "default" values for a scalar or collection attribute when it's first accessed, if not present already. :param trackparent: if True, attempt to track if an instance has a parent attached to it via this attribute. :param extension: a single or list of AttributeExtension object(s) which will receive set/delete/append/remove/etc. events. The event package is now used. .. deprecated:: 1.3 The :paramref:`.AttributeImpl.extension` parameter is deprecated and will be removed in a future release, corresponding to the "extension" parameter on the :class:`.MapperProprty` classes like :func:`.column_property` and :func:`_orm.relationship` The events system is now used. :param compare_function: a function that compares two values which are normally assignable to this attribute. :param active_history: indicates that get_history() should always return the "old" value, even if it means executing a lazy callable upon attribute change. :param parent_token: Usually references the MapperProperty, used as a key for the hasparent() function to identify an "owning" attribute. Allows multiple AttributeImpls to all match a single owner attribute. :param expire_missing: if False, don't add an "expiry" callable to this attribute during state.expire_attributes(None), if no value is present for this key. :param send_modified_events: if False, the InstanceState._modified_event method will have no effect; this means the attribute will never show up as changed in a history entry. NT)r*r+ callable_r1 trackparentrsend_modified_eventsoperatoreqis_equalaccepts_scalar_loaderdefault_accepts_scalar_loaderrr%to_list_adapt_listenerr3expire_missingr OP_MODIFIED_modified_token)r4r*r+rr1r extensioncompare_functionactive_historyrrrrrjattrexts r9r:zAttributeImpl.__init__sL "  &(0D$8!  #$KDMM,DM ,)>D & &)-)KD & '',< R00 + +C   c * * * *  1,0DM ),$T;77r;) r*r+rr1rrrrrrrc.|jjd|jSrrr?s r9rzAttributeImpl.__str__Wrr;c|jjS)z(Backwards compat for impl.active_historyr1r3r?s r9_get_active_historyz!AttributeImpl._get_active_historyZs},,r;c||j_dSr=rrYs r9_set_active_historyz!AttributeImpl._set_active_history_s(- %%%r;cd}|js J||jt|j|duS)a4Return the boolean value of a `hasparent` flag attached to the given state. The `optimistic` flag determines what the default return value should be if no `hasparent` flag can be located. As this function is used to determine if an instance is an *orphan*, instances that were loaded from storage should be assumed to not be orphans, until a True/False value for this flag is set. An instance attribute that is loaded by a callable function will also not have a `hasparent` flag. 6This AttributeImpl is not configured to track parents.F)rparentsridr)r4rrromsgs r9rqzAttributeImpl.hasparentdsM G$$$$$ M  b!233Z @ @ M r;c ~d}|js J|t|j}|r ||j|<dS||jvrt|j|}|durc|j|jkrS|=t jdt|dt|d|jddSd|j|<dS)zSet a boolean flag on the given item corresponding to whether or not it is attached to a parent object via the attribute represented by this ``InstrumentedAttribute``. rFNzRemoving state z from parent state z along attribute 'zV', but the parent record has gone stale, can't be sure this is the most recent parent.) rrrrr+objorm_excStaleDataErrorr!)r4rr parent_staterZrid_ last_parents r9 sethasparentzAttributeImpl.sethasparent{s G$$$$$"##  '!-EM#   em###mC0  u,,#<+;;;#((0%44!*% 0 0 0 0 ), 7 7 7 7 $    F!&EM#   r;ctr=NotImplementedErrorr4rrrrGs r9rEzAttributeImpl.get_historys!###r;ct)aReturn a list of tuples of (state, obj) for all objects in this attribute's current state + history. Only applies to object-based attributes. This is an inlining of existing functionality which roughly corresponds to: get_state_history( state, key, passive=PASSIVE_NO_INITIALIZE).sum() rrs r9get_all_pendingzAttributeImpl.get_all_pendings "###r;cXd}|jjD]}||||}|tur|}|S)z;Initialize the given state's attribute with an empty value.N)r1 init_scalarr)r4rrrrZfnrets r9 initializezAttributeImpl.initializesF-+  B"UE5))C*$$ r;c|j|vr ||jS|j}||jvs|j|tur|tzstS||jvr|||}nH||jvr|j|}|||}n%|jr|||}nt}|tus |tur|S|turF ||S#t$r0}tj td|z|Yd}~n(d}~wwxYw|tur||||S|tzstS|||S)zRetrieve a value from the given object. If a callable is assembled on this object's attribute, and passive is False, the callable will be executed and the resulting value will be set as the new value for this attribute. z=Deferred loader for attribute %r failed to populate correctlyrxN)r+committed_staterr rexpired_attributes _load_expired callablesrrrKeyErrorr%r|set_committed_valuer r)r4rrrrGr+rZrrs r9rzAttributeImpl.gets 8u  ? "(C5000(-::--,,%222!//w??EEEO++ % 4I%IeW55EE^' NN5'::EE&E---)1C1C Ll** $Sz)#    $!,.1!2 -0  *,,33E5%HHHW$ 5  ue444sC D$&DDc:||||||dSNrGrr4rrrrZ initiatorrGs r9appendzAttributeImpl.appends$ uiAAAAAr;c<|||d|||dS)N)rG check_oldrrs r9removezAttributeImpl.removes4  5$ 7e      r;c >|||d|||ddS)NT)rGr poprrs r9rzAttributeImpl.pops<           r;ctr=r)r4rrrrZrrGr rs r9rzAttributeImpl.set s"###r;c|j|jvr&|j|j}|ttfvrdS|S||||S)z,return the unchanged value of this attributeNr)r+rrrr)r4rrrrGrZs r9get_committed_valuez!AttributeImpl.get_committed_valuesU 8u, , ,)$(3E9---t 88E5'8:: :r;cR|||j<|||jg|S)z=set an attribute value on the given instance and 'commit' it.)r+_commit)r4rrrrZs r9rz!AttributeImpl.set_committed_value!s, dh edhZ((( r;)FNNFNTTNr)r~rrrr:rrrrrrrqrrrErrrrr r rrrrrIr;r9rrs>>!"b8b8b8b8H I:::--- ...X13FGGN    .%'%'%'N1<$$$$5J$$$$$   )425252525h>IBBBB>I    ;F     "  $ $ $ $9D ; ; ; ;r;rczeZdZdZdZdZdZdZdZdZ fdZ dZ e fdZ e ddfd Zd Zd Zed ZxZS) ScalarAttributeImplz8represents a scalar value-holding InstrumentedAttribute.TF)_replace_token _append_token _remove_tokenctt|j|i|t|tx|_|_t|t|_dSr=) superrr:r OP_REPLACErr OP_REMOVEr)r4argkwr\s r9r:zScalarAttributeImpl.__init__4sX1!4((13="===38z3J3JJd0"433r;c|jjr|||t}n ||jt }|jjr|||||j| |||| |jt }|t ur0|t ur)|j s$|j|j vrtd|zdSdSdSdS)N%s object does not have a value)r1r3rrr+rr fire_remove_eventr_modified_eventrexpiredrr{r4rrroldexistings r9rzScalarAttributeImpl.delete9s = ( 0((5%)ABBCC))DHh//C =  J  " "5%d6H I I I eT3///99TXx00  xM  888 !BT!IJJ J ! 88r;c|j|vr't||||jS|tzr |tz}||||}|t urt St|||Sr)r+Historyfrom_scalar_attributer rr HISTORY_BLANKr4rrrrGcurrents r9rEzScalarAttributeImpl.get_historyL 8u  00ueDHoNN N  #7"hhueWh==G+++$$44T5'JJJr;Nc$|jjr|||t}n ||jt }|jjr||||||}|||||||j<dSr=) r1r3rrr+rrfire_replace_eventr" r4rrrrZrrGr rr%s r9rzScalarAttributeImpl.setXs = ( 0((5%)ABBCC))DHh//C =  ++ueS)E eT3///dhr;cN|jjD]}|||||p|j}|Sr=)r1rrr4rrrrZpreviousrrs r9r/z&ScalarAttributeImpl.fire_replace_eventnsA-#  BBuh (HT5HEE r;cL|jjD]}||||p|jdSr=)r1r rr4rrrrZrrs r9r!z%ScalarAttributeImpl.fire_remove_eventus?-& > >B BueY<$*< = = = = > >r;c4|jjdjdS)Nr)rcolumnsr}r?s r9r}zScalarAttributeImpl.typeys a %%%%r;)r~rrrrrBr> collectiondynamicrr:rrrErr/r!rr} __classcell__r\s@r9rr)sBB$(!LJGBI44444 KKK&1< K K K K$     ,>>>&&X&&&&&r;rcZeZdZdZdZdZdZdZdZdZ e fdZ e fdZ e ddfd Zd Zd ZdS) ScalarObjectAttributeImplzrepresents a scalar-holding InstrumentedAttribute, where the target object is also instrumented. Adds events to delete/set operations. FTrIc|jjr.|||ttzt z}n5|||t tz t ztz}| ||||j | |j t}|tur"|tur|j td|zdSdSdS)Nrr )r1r3rrrrrr rr!rrr+rrr{r$s r9rz ScalarObjectAttributeImpl.deletes = ( ((/()CC(((72()C ueS$2DEEE99TXx00  ,,, ! !BT!IJJ J ! ,,!!r;c|j|vr't||||jS|tzr |tz}||||}|t urt St|||Sr)r+r(from_object_attributer rrr*r+s r9rEz%ScalarObjectAttributeImpl.get_historyr-r;c|j|vr||j}n%|tzr||||}ngS|%|tur|turt ||fg}ndg}|j|jvrN|j|j}|:|tur1|tur(||ur$|t ||f|S)Nr)NN)r+r rrrr rr )r4rrrrGr,roriginals r9rz)ScalarObjectAttributeImpl.get_all_pendings 8u  DHoGG | # hhueWh==GGI  000y(("7++W56CC.C 8u, , ,,TX6H$$555I--G++ N844h?@@@ r;Nc |jjr.|||ttzt z}n5|||t tz t ztz}|I|tur@||ur<|rdStdt|dt|d|j d||||||}|||j <dS)z'Set a value on the given InstanceState.rNzObject z not associated with z on attribute '')r1r3rrrrrr rr ValueErrorrr!r+r/r0s r9rzScalarObjectAttributeImpl.sets = ( ((/()CC(((72()C  !,,,$$  j#I.... %0@0@0@0@$(((L ''ueS)LLdhr;c|jr&|$|t||d|jjD]}||||p|j||||dS)NF)rrr r1r rr"r5s r9r!z+ScalarObjectAttributeImpl.fire_remove_events   C 1   nU33UE B B B-& > >B BueY<$*< = = = = eT511111r;cV|jr9||ur5|dttfvr$|t ||d|jjD]}|||||p|j}|||||jr&|$|t ||d|SNFT) rrrrr r1rrr"r2s r9r/z,ScalarObjectAttributeImpl.fire_replace_event s   Ju$$!:** !!.":":E5III-#  BBuh (HT5HEE eT8444   F !!."7"7EEE r;)r~rrrrrBr>r8rrrrErrrr!r/rIr;r9r=r=~s%*!LJIKKK@1< K K K K5JH * * * * X222r;r=ceZdZdZdZdZdZdZdZdZ dfd Z dZ e fdZ efd Zd Zd Zd Zd ZdZdZe fdZe fdZe fdZde ddfdZdZdZde fdZxZS)CollectionAttributeImplaA collection-holding attribute that instruments changes in membership. Only handles collections of instrumented objects. InstrumentedCollectionAttribute holds an arbitrary, user-specified container object (defaulting to a list) and brokers access to the CollectionAdapter, a "view" onto that object that presents consistent bag semantics to the orm layer independent of the user data implementation. FT)copycollection_factoryrr_bulk_replace_token_duck_typed_asNc  tt|j||||f||| d| ||j}||_||_t |t|_t |t|_ t |t|_ tj||_t!|jddr>t#j|dd} t#j|dd} dSdS)N)rrr _sa_linkerinit_collectionc0||dSr=rPtargetr8collection_adapters r9linkz.CollectionAttributeImpl.__init__..linkcs%%&899999r;dispose_collectionc0|ddSr=rSrTs r9unlinkz0CollectionAttributeImpl.__init__..unlinkgs%%d+++++r;)rrJr:_CollectionAttributeImpl__copyrKrLr OP_APPENDrrrOP_BULK_REPLACErMr%duck_type_collectionrNrzr# listens_for)r4r*r+rr1 typecallablerr copy_functionrrjrWrZr\s r9r:z CollectionAttributeImpl.__init__>sI 6%t,,5     $-     KM! "."433"433#(#?#? "7  # # % %   4*L$ ? ? ,  t%6 7 7 : :8 7 : t%9 : : , ,; : , , , , ,r;c>dtj|DS)Ncg|]}|SrIrI).0ys r9 z2CollectionAttributeImpl.__copy..ls@@@a@@@r;)rrV)r4items r9__copyzCollectionAttributeImpl.__copyks!@@;9$??@@@@r;c||||}|turtSt|||Sr)rrr*r(from_collectionr+s r9rEz#CollectionAttributeImpl.get_historynsC((5%(99 ' ' ' **4@@ @r;c |j|vrgS||j}t|d}|j|jvr|j|j}|ttfvrbd|D}d|D}t |t | fd|D fd|Dzfd|DzSd|DS)N _sa_adapterc<g|]}|durt|pd|fSr=r rdcs r9rfz;CollectionAttributeImpl.get_all_pending..sC"""tm:):):BdAF"""r;c<g|]}|durt|pd|fSr=r rns r9rfz;CollectionAttributeImpl.get_all_pending..sC###tm:):):BdAF###r;c&g|] \}}|v ||fSrIrIrdso original_sets r9rfz;CollectionAttributeImpl.get_all_pending..s6 AqL00A000r;c&g|] \}}|v ||fSrIrIrrs r9rfz;CollectionAttributeImpl.get_all_pending..s+NNN$!QA.s6 AqK//A///r;c0g|]}t||fSrIr )rdrts r9rfz;CollectionAttributeImpl.get_all_pending..s%8881""A&888r;)r+rzrrrdict) r4rrrrGr,rBcurrent_statesoriginal_statesryrus @@r9rz'CollectionAttributeImpl.get_all_pendingusE 85 I/'=11 8u, , ,,TX6H)444""$"""##%### #>22 #O44 $2 ONNN.NNN O $3  988888r;c|jjD]}||||p|j}|||td|jr&|$|t||d|Sr))r1r rr"rrrr r5s r9fire_append_eventz)CollectionAttributeImpl.fire_append_events-& F FBBueY%D$2DEEEE eT9d;;;   B 1   nU33UD A A A r;c@|||tddS)afA special event used for pop() operations. The "remove" event needs to have the item to be removed passed to it, which in the case of pop from a set, we don't have a way to access the item before the operation. the event is used for all pop() operations (even though set.pop is the one where it is really needed). TN)r"r)r4rrrrs r9fire_pre_remove_eventz-CollectionAttributeImpl.fire_pre_remove_events$ eT9d;;;;;r;c|jr&|$|t||d|jjD]}||||p|j|||tddSrH)rrr r1r rr"rr5s r9r!z)CollectionAttributeImpl.fire_remove_events   C 1   nU33UE B B B-& > >B BueY<$*< = = = = eT9d;;;;;r;c|j|vrdS|||td|||j}|||j=dSr))r+r"rget_collectionr{clear_with_event)r4rrrr8s r9rzCollectionAttributeImpl.deletesf 85 F eT9d;;;(( ;; ##%%% $(OOOr;cJ||\}}|||j<|S)z3Initialize this attribute with an empty collection.)_initialize_collectionr+)r4rrr_ user_datas r9rz"CollectionAttributeImpl.initializes,22599 9#dhr;c|j|j||j\}}|j|||||fSr=)r7initialize_collectionr+rLr1rQ)r4rradapterr8s r9rz.CollectionAttributeImpl._initialize_collectionsQ#mAA HeT4   %%eZAAA ""r;c(||||}|turZ|||||}|j|vs Jd||j|dS|||dSNrz,Collection was loaded during event handling.)rrrr+_get_pending_mutationr append_with_eventr4rrrrZrrGr8s r9r zCollectionAttributeImpl.appends((w(GG * * ***5% JJE%%%=&%%  ' ' 1 1 8 8 ? ? ? ? ?  ( ( : : : : :r;c2|||j|}|turZ||||||j|vs Jd||j|dS|||dSr)rr{rr!r+rr remove_with_eventrs r9r zCollectionAttributeImpl.removes(( G(LL * * *  " "5% B B B%%%=&%%  ' ' 1 1 8 8 ? ? ? ? ?  ( ( : : : : :r;cx ||||||dS#tttf$rYdSwxYwr)r rEr IndexErrorrs r9rzCollectionAttributeImpl.popsT  KKueYK H H H H HHj1    DD s 99c|x}} ||\} } |r| j| |}ntj|} |j} | | ur4|durdp |jj}|jj}td|d|dt|dr| }nX| tur@tj r| }n.t|d|j }nt|}t|}|j}|j||||||t(}|t*ur|||}n|| urdS||||d|j}| ||j<t5j||| | |`|j|||dS) NNonezIncompatible collection type: z is not z-like _sa_iterator itervaluesrT)r)r _converterr%r^rNr\r~ TypeErrorhasattrrr{py3kvaluesrziterlistrMr1 bulk_replacerrrrr"rlr+rrX)r4rrrrZrrGr_adaptiterable orig_iterablenew_collectionr setting_typereceiving_typegivenwanted new_valuesevtr%old_collections r9rzCollectionAttributeImpl.sets9$)(=%)$?$?$F$F!  .(4)44X>>#8BB !%!4~55 D(#"7#-6 "09F#) 55&&&*8^44 .'4466HH!T))y#+??#4#4$7$lHO$$$$ $H~~H(^^ & ""5*c:::hhue-DhEE # # #//%//CC M ! ! F eT3555#dh #     O ((^DDDDDr;c4t|d}d|_dS)NrlT)rz invalidated)r4r8rs r9_invalidate_collectionz.CollectionAttributeImpl._invalidate_collectionDs*m44"r;c||\}}|r||||j|j<|||jg|j|jvry||||d|j|j}|j}|j }|D]} | | |D]} | | |S)z=Set an attribute value on the given instance and 'commit' it.T) rappend_multiple_without_eventr{r+r_pending_mutationsr"r added_items deleted_itemsappend_without_eventremove_without_event) r4rrrrZr8rpendingaddedremovedrgs r9rz+CollectionAttributeImpl.set_committed_valueHs!% ; ;E B B I  <  4 4U ; ; ;( 48 edhZ((( 8u/ / /  ! !%y$ ? ? ?.2248<r8r9rr:r[rrErrrrr!rrrr r rrrrrr:r;s@r9rJrJ#s  %*!LJGI+,+,+,+,+,+,ZAAA1<AAAA5J&9&9&9&9P    < < <<<<   ###>I ; ; ; ;>I ; ; ; ;;F IEIEIEIEV###8'+K 1 1 1 1 1 1 1 1r;rJc jjjfdfd}fd}fd}rtjd|ddntjd|ddtjd |ddd S) z6Apply listeners to synchronize a two-way relationship.c ~tdt|d|jd|jdjjd )Nz:Bidirectional attribute conflict detected: Passing object z to attribute "z(" triggers a modify event on attribute "z" via the backref "z".)rEr!rr,) child_stater child_implrs r9_acceptable_key_errz.backref_listeners.._acceptable_key_errsUj +&&&&&&&'''+++    r;c||ur|S||tur|turt|t|}}|jj}|js|js|j}n|j }||ur6| ||| j t|t|t|} }|jj} |jur|j| jur  ||| | j } | jr| jnd} || ur5|| ur1| || | |t|Sr)rrr r r7r,r8r9rrrrrrrrMr )rrchildoldchildr old_stateold_dictr,check_recursive_tokenr child_dictrcheck_append_tokencheck_bulk_replace_tokenrr+ parent_implrs r9"emit_backref_from_scalar_set_eventz=backref_listeners..emit_backref_from_scalar_set_events u  L   111 )) x((h'' I$S).D? ;4< ;(,(;%%(,(:% 555IIKK-,   u%%e$$$K%,S16J&l::**2III##E9jAAA",!9 ( .. %!333%===!!IIKK, " r;cX|dSt|t|}}|j j}|j ur|j|jur ||||j}|jr|jnd}||ur5||ur1|||| |t|Sr) r r r7r,rrr8rMr rr) rrrrrrrrrrr+rs r9)emit_backref_from_collection_append_eventzDbackref_listeners..emit_backref_from_collection_append_events = F"0"7"7u9M9MZ  (-2   ", 6 6&j.EEE  y* = = =(5.8.C MJ * * ! / / /!999    (     r;c||tur|turt|t|}}|j j}|js |js|j}|j } o j }n|j}|jr|j nd}d}||urd||urb|r%tj |j j|s=|||||t"dSdSdSdSdSdSdS)NFr)rrr r r7r,r8r9rrrMr% has_dupesr{r+rrr) rrrrrrrcheck_remove_tokencheck_replace_tokencheck_for_dupes_on_remover+ruselists r9)emit_backref_from_collection_remove_eventzDbackref_listeners..emit_backref_from_collection_remove_eventso  ...Y&&u%%e$$$K%,S16J( 21C 2%/%="&0&?#,3,OK.L.K      ????????B@+++++++Z    5          .      L1  r; NO_HISTORYr(r unchangeddeletedceZdZdZdZeZdZdZdZdZ dZ dZ e d Z e d Ze d Zd S) r(aA 3-tuple of added, unchanged and deleted values, representing the changes which have occurred on an instrumented attribute. The easiest way to get a :class:`.History` object for a particular attribute on an object is to use the :func:`_sa.inspect` function:: from sqlalchemy import inspect hist = inspect(myobject).attrs.myattribute.history Each tuple member is an iterable sequence: * ``added`` - the collection of items added to the attribute (the first tuple element). * ``unchanged`` - the collection of items that have not changed on the attribute (the second tuple element). * ``deleted`` - the collection of items that have been removed from the attribute (the third tuple element). c|tkSr=)r*r?s r9__bool__zHistory.__bool__Xs }$$r;cHt|jp |jp|j S)zhReturn True if this :class:`.History` has no changes and no existing, unchanged state. )boolrrrr?s r9emptyz History.empty]s% 3t|FGGGGr;c<|jpg|jpgz|jpgzS)z3Return a collection of added + unchanged + deleted.rr?s r9sumz History.sumes+Z 2$."6B 74<;M2 N r;c(|jpg|jpgzS)z)Return a collection of added + unchanged.)rrr?s r9 non_deletedzHistory.non_deletedls  bT^%9r::r;c(|jpg|jpgzS)z+Return a collection of unchanged + deleted.)rrr?s r9 non_addedzHistory.non_addedqs$");<.}>   $5N1$5$5=   r;c8g|]}|durt|pdSr=r rns r9rfz$History.as_state..rr;c8g|]}|durt|pdSr=r rns r9rfz$History.as_state..rr;)r(rrrr?s r9as_statezHistory.as_state{sn                  r;c|j|jt}|tur$|tur |dddS|d|gdS|||dur|d|gdSt |tvrd}t |tvrd}n|g}|tur |dd|S||gd|S)NrIT)rrr+ _NO_HISTORYrrr_NO_STATE_SYMBOLSrarrrr,rBrs r9r)zHistory.from_scalar_attributes(,,Y]KHH { " ")##s2r2&s2y"---    2 2d : :3rG9b)) )(||000g;;"333"G#*)##s2r7+++sG9b'222r;c|j|jt}|tur-|tus |t ur |dddS|d|gdS||ur|t ur|d|gdSt |tvs|d}t |tvrd}n|g}|tus |t ur |dd|S||gd|S)NrI)rrr+rrrrrrs r9r@zHistory.from_object_attributes (,,Y]KHH { " "(""g&:&:s2r2&s2y"---  WI%=%=3rG9b)) )(||000H4Dg;;"333"G#*(""g&:&:s2r7+++sG9b'222r;c|j|jt}|tus |t ur |dddSt |d}|tt fvr|t|ddS|tur|dt|dSd|D}d|D}t|t||fd|Dfd|Dfd|DS)NrIrlc<g|]}|durt|pd|fSr=r rns r9rfz+History.from_collection..sC4-6^A%6%6>$Br;c<g|]}|durt|pd|fSr=r rns r9rfz+History.from_collection..sC4-6^A%6%6>$Br;c"g|] \}}|v | SrIrIrrs r9rfz+History.from_collection..s'GGGtq!,1F1F1F1F1Fr;c"g|] \}}|v | SrIrIrrs r9rfz+History.from_collection..s'CCCtq!l1B1B1B1B1Br;c"g|] \}}|v | SrIrIrxs r9rfz+History.from_collection..s'GGGtq!!;2F2F2F2F2Fr;) rrr+rrrrzrr{) rarrrr,rBr|r}ryrus @@r9rjzHistory.from_collectionsT(,,Y]KHH h  'Y"6"63r2r?? "'=11 ), , ,3tG}}b"-- -  $ $3r4=="-- - N!O ~..K00L3GGGG~GGGCCCC~CCCGGGGGGG r;N)r~rrrr __nonzero__rrrrrr classmethodr)r@rjrIr;r9r(r(?s0%%%KHHH   ;;; === 000    33[3<33[3:[r;c|durtjdt}n|durtjdt}t t |||S)a Return a :class:`.History` record for the given object and attribute key. This is the **pre-flush** history for a given attribute, which is reset each time the :class:`.Session` flushes changes to the current database transaction. .. note:: Prefer to use the :attr:`.AttributeState.history` and :meth:`.AttributeState.load_history` accessors to retrieve the :class:`.History` for instance attributes. :param obj: an object whose class is instrumented by the attributes package. :param key: string attribute name. :param passive: indicates loading behavior for the attribute if the value is not already present. This is a bitflag attribute, which defaults to the symbol :attr:`.PASSIVE_OFF` indicating all necessary SQL should be emitted. .. seealso:: :attr:`.AttributeState.history` :meth:`.AttributeState.load_history` - retrieve history using loader callables if the value is not locally present. TzNPassing True for 'passive' is deprecated. Use attributes.PASSIVE_NO_INITIALIZEFzFPassing False for 'passive' is deprecated. Use attributes.PASSIVE_OFF)r%warn_deprecatedrrget_state_historyr )rr+rGs r9rErEswD$  3   ( E    6    ^C00#w ? ??r;c.|||Sr=)rE)rrr+rGs r9rrs   S' * **r;Fclt|}t|}||||S)TODO)rr has_parent)rarr+ror7rrs r9rr"s4s##G 3  E   eS* 5 55r;c |dd}|dd}|dd}t|||||}t||fi||S)Nr-r5r)r)rregister_descriptorregister_attribute_impl)r*r+rr-r5rdescs r9register_attributer)sp d++J66.$//L &&  C vsJ # N N NDFC..2... Kr;c t|}|r4|dd} ||| pt} n|dd} ||j} |r |||| | fi|} n8|rt |||| fd| i|} n#|rt |||| fi|} nt|||| fi|} | ||_|rt||||| |||S)Nr`) rrinstrument_collection_classrr1rJr=rr,rpost_configure_attribute) r*r+rr useobject impl_classbackrefrr7factoryr`r1r,s r9rr2sdv&&G4&&..:: D  vvnd33 s|$H Kz&#|XDDDD  K& CH  ;G KM   K( CH  02  #63 8JJrJJGCL:'#,999 $$S))) 3<r;ct|}t||||}||_||||S)N)r-r5)rrrinstrument_attribute)r*r+r-r5rr7rs r9rr^sTv&&G& JJ   j111 r;cJt||dSr=)runinstrument_attribute)r*r+s r9unregister_attributerms$V33C88888r;cPt|}|j}t|||S)a4Initialize a collection attribute and return the collection adapter. This function is used to provide direct access to collection internals for a previously unloaded attribute. e.g.:: collection_adapter = init_collection(someobject, 'elements') for elem in values: collection_adapter.append_without_event(elem) For an easier way to do the above, see :func:`~sqlalchemy.orm.attributes.set_committed_value`. :param obj: a mapped object :param key: string attribute name where the collection is located. )r r{init_state_collection)rr+rrrs r9rQrQqs*$ 3  E JE s 3 33r;c|j|j}|||}||||S)zDInitialize a collection attribute and return the collection adapter.)r7r,rr)rrrr+rrs r9rrs> =  "Du--I   ueY 7 77r;ct|t|}}|j|j|||dS)a[Set the value of an attribute with no history events. Cancels any previous history present. The value should be a scalar value for scalar-holding attributes, or an iterable for any collection-holding attribute. This is the same underlying method used when a lazy loader fires off and loads additional data from the database. In particular, this method can be used by application code which has loaded additional attributes or collections through separate queries, which can then be attached to an instance as though it were part of its original loaded state. N)r r r7r,r)rFr+rZrrrs r9rrsE"(++]8-D-D5E M#//ueDDDDDr;ct|t|}}|j|j||||dS)asSet the value of an attribute, firing history events. This function may be used regardless of instrumentation applied directly to the class, i.e. no descriptors are required. Custom attribute management schemes will need to make usage of this method to establish attribute state as understood by SQLAlchemy. :param instance: the object that will be modified :param key: string name of the attribute :param value: value to assign :param initiator: an instance of :class:`.Event` that would have been propagated from a previous event listener. This argument is used when the :func:`.set_attribute` function is being used within an existing event listening function where an :class:`.Event` object is being supplied; the object may be used to track the origin of the chain of events. .. versionadded:: 1.2.3 N)r r r7r,r)rFr+rZrrrrs r9 set_attributersG2"(++]8-D-D5E M#ueY?????r;ct|t|}}|j|j||S)aZGet the value of an attribute, firing any callables required. This function may be used regardless of instrumentation applied directly to the class, i.e. no descriptors are required. Custom attribute management schemes will need to make usage of this method to make usage of attribute state as understood by SQLAlchemy. )r r r7r,rrFr+rrrs r9 get_attributers="(++]8-D-D5E =  " & &ue 4 44r;ct|t|}}|j|j||dS)aQDelete the value of an attribute, firing history events. This function may be used regardless of instrumentation applied directly to the class, i.e. no descriptors are required. Custom attribute management schemes will need to make usage of this method to establish attribute state as understood by SQLAlchemy. N)r r r7r,rrs r9 del_attributersC"(++]8-D-D5E M#""5%00000r;ct|t|}}|j|j}|j||j|||tddS)aMark an attribute on an instance as 'modified'. This sets the 'modified' flag on the instance and establishes an unconditional change event for the given attribute. The attribute must have a value present, else an :class:`.InvalidRequestError` is raised. To mark an object "dirty" without referring to any specific attribute so that it is considered within a flush, use the :func:`.attributes.flag_dirty` call. .. seealso:: :func:`.attributes.flag_dirty` T is_userlandN) r r r7r,r1modifiedrr"r)rFr+rrrr,s r9 flag_modifiedr#sj""(++]8-D-D5E =  "DM5$"6777 %xTBBBBBr;c~t|t|}}||dtddS)aMark an instance as 'dirty' without any specific attribute mentioned. This is a special operation that will allow the object to travel through the flush process for interception by events such as :meth:`.SessionEvents.before_flush`. Note that no SQL will be emitted in the flush process for an object that has no changes, even if marked dirty via this method. However, a :meth:`.SessionEvents.before_flush` handler will be able to see the object in the :attr:`.Session.dirty` collection and may establish changes on it, which will then be included in the SQL emitted. .. versionadded:: 1.2 .. seealso:: :func:`.attributes.flag_modified` NTr )r r r"r)rFrrrs r9 flag_dirtyr%s@("(++]8-D-D5E %xTBBBBBr;r)FNFNNrr=)Orrrrrrr8rrr r r r rrrrrrrrrrrrrrrrrrr r!r#r$r%_self_inspects_MappedAttributeInspectionAttrPropComparatorr'rrsymbolrr\rr]robjectrrrr=rJrr frozensetrr namedtupler(r*rErrrrrrrQrrrrrr#r%rIr;r9r/sA ((((((""""""######((((((""""""******''''''######))))))******###### T(T(T(T(T(T(T(T(nBBBBB.BBB8}}}@ DK ! ! DK ! ! T[ # # $+n--dk*%% /*/*/*/*/*F/*/*/*dDDDDDFDDDN R&R&R&R&R&-R&R&R&jbbbbb 3bbbJM1M1M1M1M1mM1M1M1` AAAHdk,'' IRBBxLL""Y--8 $/)%F%F%F G GgggggggggTdD)) #./@/@/@/@d+6++++6666  ))))Z:>    999444.888EEE&@@@@: 5 5 5 1 1 1CCC.CCCCCr;