o znhܵ@sdZddlmZddlmZddlmZddlmZddlmZddlm Z ddlm Z dd lm Z d dlmZ d d lm Z d dlmZGd d d eZGdddeZGdddeZGdddeZGdddeZe ee ee eiZdS)zRelationship dependencies. ) attributes)exc)sync) unitofwork)util) MANYTOMANY) MANYTOONE) ONETOMANY)sqlc@seZdZddZeddZddZddZd d Zd d Z d dZ ddZ ddZ ddZ ddZddZddZddZd%ddZd d!Zd"d#Zd$S)&DependencyProcessorcCs||_|j|_|j|_|j|_|j|_|j|_|j|_|j|_|j|_|j |_ |jr/t j |_ nt j |_ |jr;t j |_nt j |_|j|_|jjsOtd|jdS)Nz|Can't build a DependencyProcessor for relationship %s. No target attributes to populate between parent and child are present)propcascademapperparent secondary direction post_updatepassive_deletespassive_updatesenable_typechecksrPASSIVE_NO_INITIALIZE_passive_delete_flag PASSIVE_OFF_passive_update_flagkeysynchronize_pairssa_exc ArgumentError)selfr r D/usr/local/lib/python3.10/dist-packages/sqlalchemy/orm/dependency.py__init__s0  zDependencyProcessor.__init__cCst|j|SN)_direction_to_processorr)clsr r r r!from_relationship6sz%DependencyProcessor.from_relationshipcCs|jj|j|S)zreturn True if the given object instance has a parent, according to the ``InstrumentedAttribute`` handled by this ``DependencyProcessor``. )r class_managerget_implr hasparentrstater r r!r):szDependencyProcessor.hasparentcCs||ddS)zestablish actions and dependencies related to a flush. These actions will operate on all relevant states in the aggregate. TN)register_preprocessorruowr r r!per_property_preprocessorsBsz.DependencyProcessor.per_property_preprocessorsc Cszt||dd}t||dd}t||jj}t||jj}t||jj}t||jj}||||||||dSNFT)r ProcessAll SaveUpdateAllrprimary_base_mapperr DeleteAllper_property_dependencies)rr. after_save before_delete parent_saves child_savesparent_deletes child_deletesr r r!per_property_flush_actionsKs.z.DependencyProcessor.per_property_flush_actionsc Cs|jj}t||}t||}|rt||dd}d|_n t||dd}d|_||jvr@||jvs5J|df|dfg} d} nd} |sXt||jj } d} }| |jvrWd} nt||jj } d} }| |jvrkd} |D]}|j |j j ||j|r~|jntj}|sqm|rt||d|}| rt||} nt||d|}| rt||} | rg} |D]+\}}||jvrd}n|j|\}}|rt||df}nt||df}| |q| D]\}}||| | |||||qqmdS)zestablish actions and dependencies related to a flush. These actions will operate on all relevant states individually. This occurs only if there are cycles in the 'aggregated' version of events. TFN)NN)rr3rr2r4r1disabledcyclesr base_mappermanagerrimplget_all_pendingdictrrr ProcessState DeleteStateSaveUpdateStatestatesappendper_state_dependencies)rr.rGisdeletechild_base_mapperr9r;r7r6 child_actionschild_in_cyclesr8r:parent_in_cyclesr+sum_ child_statechild child_actiondeletedlistonly childisdeleter r r!per_state_flush_actionsgs             z+DependencyProcessor.per_state_flush_actionscCdSNFr r uowcommitrGr r r!presort_deletesz#DependencyProcessor.presort_deletescCrWrXr rYr r r! presort_savesr\z!DependencyProcessor.presort_savescCdSr#r rYr r r!process_deletesr\z#DependencyProcessor.process_deletescCr^r#r rYr r r! process_savesr\z!DependencyProcessor.process_savescCsp|r|jr tj}n |jturtj}ntj}|D]}|||j|}|r*| s*dSq|o7|j j o7|j |j vS)NT)rrrrrPASSIVE_NO_FETCH_RELATEDrget_attribute_historyremptyr _is_self_referentialrmappers)rrZrGrJpassiveshistoryr r r!prop_has_changess    z$DependencyProcessor.prop_has_changescCs|jjr|durtd|jf|durG|jj||j dsI|jj|ddr8td|j|j|jj|jdtd|j|j|jjddSdS)Nz-Can't flush None value found in collection %s)allow_subtypesTaEAttempting to flush an item of type %(x)s as a member of collection "%(y)s". Expected an object of type %(z)s or a polymorphic subclass of this type. If %(x)s is a subclass of %(z)s, configure mapper "%(zm)s" to load this subtype polymorphically, or set enable_typechecks=False to allow any subtype to be accepted for flush. )xyzzmzAttempting to flush an item of type %(x)s as a member of collection "%(y)s". Expected an object of type %(z)s or a polymorphic subclass of this type.)rkrlrm)r uselistr FlushErrorr_canloadrclass_r*r r r!_verify_canloads8 z#DependencyProcessor._verify_canloadcCtr#NotImplementedError)rr+rQassociationrow clearkeysrZr r r! _synchronize"z DependencyProcessor._synchronizecCs>|jjsdStt|jgdd|jjD}|d|ftS)NcSsg|]}|jqSr )r).0pr r r! *szCDependencyProcessor._get_reversed_processed_set.. reverse_key)r _reverse_propertytuplesortedrmemoset)rr. process_keyr r r!_get_reversed_processed_set%s z/DependencyProcessor._get_reversed_processed_setFcCs:|D]}|r |dur||dd|jjDdSqdS)NcSsg|]\}}|qSr r )r{lrr r r!r}2sz4DependencyProcessor._post_update..)register_post_updater r)rr+rZrelated is_m2o_deleterkr r r! _post_update.s z DependencyProcessor._post_updatecCrtr#rurrZr+r r r! _pks_changed6rzz DependencyProcessor._pks_changedcCsd|jj|jfS)Nz%s(%s)) __class____name__r )rr r r!__repr__9szDependencyProcessor.__repr__N)F)r __module__ __qualname__r" classmethodr&r)r/r<rVr[r]r_r`rirsryrrrrr r r r!r s&  p)  r c@sLeZdZddZddZddZddZd d Zd d Zd dZ ddZ dS) OneToManyDPc Cs|jr/t||jjd}t||jjd} |j||f||f||f|| f| |f| |fgdS|j||f||f||f||f||f||f||fgdSr0rr PostUpdateAllrr3 dependenciesupdate) rr.r8r9r:r;r6r7child_post_updateschild_pre_updatesr r r!r5>s4    z%OneToManyDP.per_property_dependenciesc Cs|jrVt||jjd} t||jjd} |s8|r'|j||f|| fgdS|j||f||f|| fgdS|rH|j|| f| |fgdS|j|| f| |fgdS|si|j||f||f||fgdS|j||f||fgdSr0r) rr. save_parent delete_parentrRr6r7rJrUrrr r r!rIgsR   z"OneToManyDP.per_state_dependenciescCs|jj o |jdk }|D]D}|||j|j}|rQ|jD]}|dur;||dur;|jjr6|j |ddq| |q|rQ|j D]}|durP|j |d|j dqAq dS)NallFTrJdelete operationr ) rrrrbrrrSr) delete_orphanregister_object unchangedr rrZrGshould_null_fksr+rhrQr r r!r[s*    zOneToManyDP.presort_deletesc CsN|d|ft}|jj o|jdk }|D]}|||}|r"|jr&tj}ntj }| ||j |}|r|j D]} | durF|j | dd|jdq6||j |jD]9} |jjsc|rb|j | dd|jdqP|| dur|j | dd|jd|jd| D] \} } } } |j | dd q{qP|r|r|jD]} | dur|j | d|jd |jd qqdS) Nchildren_addedrTadd) cancel_deleterr FrrJrr rz pk changer)rrrrrrrrrrrbraddedrr rrSr)rcascade_iteratorr)rrZrGrrr+ pks_changedrfrhrQcmst_dct_r r r!r]sp        zOneToManyDP.presort_savesc Cs|js|jdksu|d|ft}|D]d}|||j|j}|rt|jD]$}|durF||durF| ||dd|d|jrF|rF| |||gq"|jsN|j j stt|j |D]}|durs| ||dd|d|jrs|rs| |||gqVqdSdS)NrrFT)rrrrrbrrrSr)ryrrrr difference)rrZrGrr+rhrQr r r!r_s>       zOneToManyDP.process_deletesc Cs|jj o |jdk }|D]]}|||jtj}|rj|jD]}|||dd|d|dur8|j r8| |||gq|j D]}|rS|jjsS| |sS|||dd|dq<| ||rj|jD] }|||dd|dq]q dS)NrFT)rrrrbrrrrryrrrSr)rrrr r r!r`/sB          zOneToManyDP.process_savesc Csr|}|}|||dus|js||rdS|r%t||j|jjdSt||j ||j|jj||j o5|dSr#) rsr is_deletedrclearrr rpopulaterr) rr+rQrwrxrZrsourcedestr r r!ryQs( zOneToManyDP._synchronizecCt|||j|jjSr#rsource_modifiedrr rrr r r!rhzOneToManyDP._pks_changedN) rrrr5rIr[r]r_r`ryrr r r r!r=s)C>," rc@sPeZdZddZddZddZddZd d Zd d Zd dZ dddZ dS) ManyToOneDPcCs.t|||jjD] }|jt|q dSr#)r r"rself_and_descendants_dependency_processorsrHDetectKeySwitch)rr rr r r!r"os  zManyToOneDP.__init__c Cs|jr2t||jjd}t||jjd} |j||f||f||f|| f|| f| |f| |fgdS|j||f||f||f||fgdSr0rrrrr3rr) rr.r8r9r:r;r6r7parent_post_updatesparent_pre_updatesr r r!r5ts0    z%ManyToOneDP.per_property_dependenciesc Cs|jrI|s/t||jjd} |r|j|| f| |fgdS|j||f||f|| fgdSt||jjd} |j|| f| |f| |fgdS|sf|s[|j||f||fgdS|j||fgdS|rs|j||fgdSdSr0r) rr.rrrRr6r7rJrUrrr r r!rIsF   z"ManyToOneDP.per_state_dependenciesc Cs|jjs|jjrP|D]G}|||j|j}|rO|jjr |}n|}|D](}|dur-q&|j|dd|j d|j d|}|D] \}} } } |j| ddq@q&q dSdS)NTrrr) rrrrbrrsum non_deletedrr rr) rrZrGr+rhtodeleterQtrrrrr r r!r[s2  zManyToOneDP.presort_deletesc Cs|D]H}|j|d|jd|jjrJ|||j|j}|rJ|jD]*}||durI|j|dd|jd|j d|}|D] \}}} } |j| ddq;qqdS)NrrFTrrr) rr rrrbrrrSr)rr) rrZrGr+rhrQrrrrrr r r!r]s(  zManyToOneDP.presort_savescCsz|jr5|jjs7|jdks9|D],}||ddd||r4|jr4|||j|j}|r4|j||| ddqdSdSdSdS)NrT)r) rrrrryrbrrrr)rrZrGr+rhr r r!r_s&    zManyToOneDP.process_deletesc Cs~|D]:}|||jtj}|r<|jr#|jD] }|||dd|dqn |jr0||ddd|d|jr<|||| qdS)NFrTr) rbrrrrryrSrrr)rrZrGr+rhrQr r r!r`s&    zManyToOneDP.process_savesNc Cs|dus |js||rdS|dur,|dur,|j|s,tdt|||jfdS|s2|dur>t ||j |jj dS| |t ||j||j |jj |ddS)NGObject of type %s not in session, %s operation along '%s' won't proceedF)rrsession_contains_staterwarn mapperutilstate_class_strr rrrrrsrrrr+rQrwrxrZrr r r!ry*s8    zManyToOneDP._synchronizer#) rrrr"r5rIr[r]r_r`ryr r r r!rns(:rc@sheZdZdZddZddZddZdd Zd d Zd d Z ddZ ddZ ddZ ddZ ddZdS)raFor many-to-one relationships with no one-to-many backref, searches for parents through the unit of work when a primary key has changed and updates them. Theoretically, this approach could be expanded to support transparent deletion of objects referenced via many-to-one as well, although the current attribute system doesn't do enough bookkeeping for this to be efficient. cCs<|jjr|jr dSddd|jjDvrdS||ddS)NFcss|]}|jVqdSr#)r)r{r r r r! ds  z=DetectKeySwitch.per_property_preprocessors..)r rrr,r-r r r!r/_sz*DetectKeySwitch.per_property_preprocessorscCs6t||jj}t||dd}|j||fgdSrX)rr2rr?r1rr)rr.r8r6r r r!r<lsz*DetectKeySwitch.per_property_flush_actionscCr^r#r )rr.rGrJr r r!rVqr\z'DetectKeySwitch.per_state_flush_actionscCr^r#r rYr r r!r[tr\zDetectKeySwitch.presort_deletescCs|js |||dSdSr#r_process_key_switches)rr.rGr r r!r]wszDetectKeySwitch.presort_savescCs"|s|jr|||}t|SdSrX)r_key_switchersbool)rr.rGrJdr r r!ri}s  z DetectKeySwitch.prop_has_changescCsJr#r rYr r r!r_r\zDetectKeySwitch.process_deletescCs|jsJ|||dSr#rrYr r r!r`s zDetectKeySwitch.process_savescCsZ|d|fdd\}}||}|D]}||vr*|||r%||q||q|S)N pk_switcherscSs ttfSr#)rr r r r!s z0DetectKeySwitch._key_switchers..)runionrr)rr.rGswitched notswitched allstatesrgr r r!rs     zDetectKeySwitch._key_switchersc Cs|||}|rb|jjD]U}t|j|jjsq|j}||j j |||j d}|t j ura|dura|jjr>|s9q|d}n|}t |}||vra||d|jt||j||j|jj||jqdSdS)N)rfF)rr identity_map all_states issubclassrrrrCr(rgetrrPASSIVE_NO_RESULTr roinstance_staterrrrrr) rdeplistrZ switchersr+dict_r related_obj related_stater r r!rsB     z%DetectKeySwitch._process_key_switchescCs t|jot|||j|jjSr#)rrrrrr rrr r r!rszDetectKeySwitch._pks_changedN)rrr__doc__r/r<rVr[r]rir_r`rrrr r r r!rSs   %rc@sTeZdZddZddZddZddZd d Zd d Zd dZ ddZ ddZ dS) ManyToManyDPc Cs:|j||f||f||f||f||f||f||fgdSr#rr)rr.r8r9r:r;r6r7r r r!r5s z&ManyToManyDP.per_property_dependenciesc Cs\|s |r|j||f||fgdS|j||f||fgdS|j||f||fgdSr#r) rr.rrrRr6r7rJrUr r r!rIs z#ManyToManyDP.per_state_dependenciescCs*|js|D] }|||j|jqdSdSr#)rrbrr)rrZrGr+r r r!r[s zManyToManyDP.presort_deletesc Cs|js|D]}|||r|||jtj}q|jjsdS|D]9}|||jtj}|rX|j D](}| |durW|j |dd|j d|j d|D] \}}}} |j |ddqIq/qdS)NFTrrr)rrrbrrrrrrrSr)rr rr) rrZrGr+rhrQrrrrr r r!r] s8    zManyToManyDP.presort_savesc sg}g}g}||}t}|D]C||j|j}|rS|D]#} | dus1|dur2| f|vr2q!i} || | d|ds?q!|| q!|fdd|Dq|dur]||| ||||dS)NFrc3|]}|fVqdSr#r r{rr+r r!rKz/ManyToManyDP.process_deletes..) rrrbrr non_addedryrHr _run_crud) rrZrGsecondary_deletesecondary_insertsecondary_update processedtmprhrQrwr rr!r_,s@     zManyToManyDP.process_deletesc sg}g}g}||}t}|D]|j o||}|r"tj} ntj} ||j| } | r| j D]} |dur?| f|vr?q2i} | | | d|dsLq2| | q2| j D]} |durb| f|vrbqUi} | | | d|dsoqU| | qU| fdd| j | j D|r| jD]!} i} t |j| d|jjt | |j| d|jj| | qq|dur| ||||||dS)NFrrc3rr#r rrr r!r~rz-ManyToManyDP.process_saves..old_)rrrrrrrrbrrryrHrSrrrrr rrsecondary_synchronize_pairsr) rrZrGrrrrrneed_cascade_pksrfrhrQrwr rr!r`Ts|           zManyToManyDP.process_savescs|j|j}|r?|d|jtjfdd|jjD}|||}| r?|j t |kr?t d|jjt ||j f|rw|d|jtjfdd|jjD}|||}| rw|j t |krwt d|jjt ||j f|r|j}|||dSdS)Nrcs,g|]}|jvr|tj|j|jdkqS)type_rr bindparamtyperrwr r!r}s  z*ManyToManyDP._run_crud..zRDELETE statement on table '%s' expected to delete %d row(s); Only %d were matched.cs0g|]}|jvr|tjd|j|jdkqS)rrrrrr r!r}s  zRUPDATE statement on table '%s' expected to update %d row(s); Only %d were matched.) transaction connectionrrrr and_rexecutesupports_sane_multi_rowcountrowcountlenrStaleDataError descriptionrinsert)rrZrrrr statementresultr rr!rs^      zManyToManyDP._run_crudcCs|||dur dS|dur(|j|s(|js&tdt|||jfdSt ||j ||jj t ||j ||jjdS)NFrT)rsrrrSrrrrr r populate_dictrrrrrr r r!rys* zManyToManyDP._synchronizecCrr#rrr r r!rrzManyToManyDP._pks_changedN) rrrr5rIr[r]r_r`rryrr r r r!rs "(H= !rN)rrrrrrr interfacesrrr rr objectr rrrrr$r r r r!s8           &3fu;