o znh6@sdZddlmZddlmZddlZddlmZddlZddlm Z ddlm Z d d lm Z d d lm Z d d l m Z Gd dde jZGdddeZGdddeZGdddeZGdddeZGdddeZGdddeZGdddeZdS)aAttribute implementation for _Dispatch classes. The various listener targets for a particular event class are represented as attributes, which refer to collections of listeners to be fired off. These collections can exist at the class level as well as at the instance level. An event is fired off using code like this:: some_object.dispatch.first_connect(arg1, arg2) Above, ``some_object.dispatch`` would be an instance of ``_Dispatch`` and ``first_connect`` is typically an instance of ``_ListenerCollection`` if event listeners are present, or ``_EmptyListener`` if none are present. The attribute mechanics here spend effort trying to ensure listener functions are available with a minimum of function call overhead, that unnecessary objects aren't created (i.e. many empty per-instance listener collections), as well as that everything is garbage collectable when owning references are lost. Other features such as "propagation" of listener functions across many ``_Dispatch`` instances, "joining" of multiple ``_Dispatch`` instances, as well as support for subclass propagation (e.g. events assigned to ``Pool`` vs. ``QueuePool``) are all implemented here. )absolute_import)with_statementN)chain)legacy)registry)exc)util) threadingc@eZdZdZddZdS) RefCollection)refcCst|tjSN)weakrefrr_collection_gcedselfr@/usr/local/lib/python3.10/dist-packages/sqlalchemy/event/attr.py_memoized_attr_ref1z RefCollection._memoized_attr_refN)__name__ __module__ __qualname__ __slots__rrrrrr . r c@s4eZdZddZddZddZddZd d Zd S) _empty_collectioncCdSrrrelementrrrappend6z_empty_collection.appendcCrrr)rotherrrrextend9r"z_empty_collection.extendcCrrrrrrrremove<r"z_empty_collection.removecCstgSr)iterrrrr__iter__?z_empty_collection.__iter__cCrrrrrrrclearBr"z_empty_collection.clearN)rrrr!r$r%r'r)rrrrr5s  rc@sdeZdZdZdZddZddZddZd d Zd d Z d dZ ddZ ddZ ddZ ddZdS)_ClsLevelDispatchz2Class-level events on :class:`._Dispatch` classes.)name arg_nameshas_kwlegacy_signatures _clslevel __weakref__cCsn|j|_t|}|jdd|_t|j|_t t t t |dgddd|_ t||||_t|_dS)Nr_legacy_signaturescSs|dSNrr)srrrZsz,_ClsLevelDispatch.__init__..)key)rr+r inspect_getfullargspecargsr,boolvarkwr-listreversedsortedgetattrr.r_augment_fn_docs__doc__rWeakKeyDictionaryr/)rparent_dispatch_clsfnargspecrrr__init__Rs  z_ClsLevelDispatch.__init__cCsN|r||}|jr%z tj|dd}Wn tyY|Swt|||}|S)NT)no_self)_wrap_fn_for_kwr.r get_callable_argspec TypeErrorr_wrap_fn_for_legacy)rrBnamedrCrrr_adjust_fn_specbs  z!_ClsLevelDispatch._adjust_fn_speccsfdd}|S)Ncs(ttj|}||di|S)Nr)dictzipr,update)r7kwargdictrBrrrwrap_kwos z2_ClsLevelDispatch._wrap_fn_for_kw..wrap_kwr)rrBrRrrQrrFnsz!_ClsLevelDispatch._wrap_fn_for_kwcC|j}t|ts Jdt|ddstd||g}|rN|d}||||ur9||j vr9| |n||j vrC| ||j | |j |st||dSNz*Class-level Event targets must be classes._sa_propagate_class_eventsTz.Can't assign an event directly to the %s classr)dispatch_target isinstancetyper=r InvalidRequestErrorpopr$__subclasses__r/update_subclass_assign_cls_collection appendleft _listen_fnr_stored_in_collectionr event_key propagatetargetstackclsrrrinsertv*      z_ClsLevelDispatch.insertcCrSrT)rVrWrXr=r rYrZr$r[r/r\r]r!r_rr`rarrrr!rhz_ClsLevelDispatch.appendcCs.t|ddrt|j|<dSt|j|<dS)NrUT)r= collectionsdequer/r)rrdrrrr]s z(_ClsLevelDispatch._assign_cls_collectioncs^||jvr |||j||jddD]}||jvr,fdd|j|DqdS)Nrcsg|]}|vr|qSrr).0rBclslevelrr sz5_ClsLevelDispatch.update_subclass..)r/r]__mro__r$)rrdrfrrlrr\s    z!_ClsLevelDispatch.update_subclasscCsX|j}|g}|r$|d}||||jvr"|j||j|st||dSr2) rVrZr$r[r/r%r_r_removed_from_collection)rrbrdrerfrrrr%s  z_ClsLevelDispatch.removecCs8t}|jD] }|||qt||dS)zClear all class level listenersN)setr/valuesrNr)r_clear)rto_clear dispatcherrrrr)s   z_ClsLevelDispatch.clearcC|S)zReturn an event collection which can be modified. For _ClsLevelDispatch at the class level of a dispatcher, this returns self. rrobjrrr for_modifyz_ClsLevelDispatch.for_modifyN)rrrr?rrDrKrFrgr!r]r\r%r)ryrrrrr*Fs    r*c@r )_InstanceLevelDispatchrcC|j||Sr)parentrKrrBrJrrrrKrz&_InstanceLevelDispatch._adjust_fn_specN)rrrrrKrrrrr{rr{c@sreZdZdZeZdZdZddZddZ dd Z e Z Z Z ZZZd d Zd d ZddZddZeZdS)_EmptyListenerzServes as a proxy interface to the events served by a _ClsLevelDispatch, when there are no instance-level events present. Is replaced by _ListenerCollection when instance-level events are added. r)r}parent_listenersr+cCs2||jvr ||||_|j||_|j|_dSr)r/r\r}rr+rr} target_clsrrrrDs    z_EmptyListener.__init__cCsJt|j|j}t||j|urt||j||Stt||jts#J|S)zReturn an event collection which can be modified. For _EmptyListener at the instance level of a dispatcher, this generates a new _ListenerCollection, applies it to the instance, and returns it. )_ListenerCollectionr} _instance_clsr=r+setattrrW_JoinedListener)rrxresultrrrrys  z_EmptyListener.for_modifycOstd)Nzneed to call for_modify()NotImplementedErrorrr7rOrrr _needs_modifyr(z_EmptyListener._needs_modifycOs|jD] }||i|qdSzExecute this event.N)rrr7rOrBrrr__call__s z_EmptyListener.__call__cC t|jSr)lenrrrrr__len__ z_EmptyListener.__len__cCrr)r&rrrrrr' rz_EmptyListener.__iter__cCrr)r8rrrrr__bool__ rz_EmptyListener.__bool__N)rrrr? frozensetrc listenersrrDryr exec_onceexec_once_unless_exceptionrgr!r%r)rrr'r __nonzero__rrrrrs, rc@sTeZdZdZddZddZddZdd Zd d Zd d Z ddZ ddZ e Z dS)_CompoundListener_exec_once_mutex _exec_oncecCstSr)r Lockrrrr_memoized_attr__exec_once_mutexr(z1_CompoundListener._memoized_attr__exec_once_mutexc Os|j8|js+zz ||i|d}Wnd}W|r|s"d|_n|r'|s*d|_wWddSWddS1s>wYdS)NFTr)rretry_on_exceptionr7rO exceptionrrr_exec_once_impls$"z!_CompoundListener._exec_once_implcO&|js|jdg|Ri|dSdS)z]Execute this event, but only if it has not been executed already for this collection.FNrrrrrrr&sz_CompoundListener.exec_oncecOr)atExecute this event, but only if it has not been executed already for this collection, or was called by a previous exec_once_unless_exception call and raised an exception. If exec_once was already called, then this method will never run the callable regardless of whether it raised or not. .. versionadded:: 1.3.8 TNrrrrrr-s z,_CompoundListener.exec_once_unless_exceptioncOs8|jD] }||i|q|jD] }||i|qdSr)rrrrrrr<s  z_CompoundListener.__call__cCst|jt|jSr)rrrrrrrrDsz_CompoundListener.__len__cCt|j|jSr)rrrrrrrr'Grz_CompoundListener.__iter__cCst|jp|jSr)r8rrrrrrrJz_CompoundListener.__bool__N) rrrrrrrrrrr'rrrrrrrs rc@sNeZdZdZdZddZddZddd Zd d Zd d Z ddZ ddZ dS)rzInstance-level attributes on instances of :class:`._Dispatch`. Represents a collection of listeners. As of 0.7.9, _ListenerCollection is only first created via the _EmptyListener.for_modify() method. )rr}r+rrcr0cCsJ||jvr ||d|_|j||_||_|j|_t|_t |_ dSNF) r/r\rrr}r+rirjrrqrcrrrrrDcs     z_ListenerCollection.__init__cCrv)zReturn an event collection which can be modified. For _ListenerCollection at the instance level of a dispatcher, this returns self. rrwrrrrymrzz_ListenerCollection.for_modifyTcs\j}t|j|jfdd|jD}|||j|}t||dS)zMPopulate from the listeners in another :class:`_Dispatch` object.cs&g|]}|vr r|jvr|qSr)rc)rklexisting_listener_setonly_propagaterrrrn}s z/_ListenerCollection._update..N)rrqrcrNr$unionr_stored_in_collection_multi)rr#rexisting_listenersother_listeners to_associaterrr_updatevs  z_ListenerCollection._updatecC,|||jr|r|j|jdSdSdSr)prepend_to_listrrcaddr_rrbrcrrrrg z_ListenerCollection.insertcCrr)append_to_listrrcrr_rrrrr!rz_ListenerCollection.appendcCs,|j|j|j|jt||dSr)rr%r_rcdiscardrrprrbrrrr%sz_ListenerCollection.removecCs&t||j|j|jdSr)rrsrrcr)rrrrr)s z_ListenerCollection.clearN)T) rrrr?rrDryrrgr!r%r)rrrrrPs    rc@sTeZdZdZddZeddZddZdd Zd d Z d d Z ddZ ddZ dS)r)r}r+localrcCs$d|_||_||_||_|j|_dSr)rr}r+rr)rr}r+rrrrrDs  z_JoinedListener.__init__cCrr)r=r}r+rrrrrsz_JoinedListener.listenerscCr|r)rrKr~rrrrKrz_JoinedListener._adjust_fn_speccCs|j||_|_|Sr)rryrrwrrrrysz_JoinedListener.for_modifycC|j||dSr)rrgrrrrrgz_JoinedListener.insertcCrr)rr!rrrrr!rz_JoinedListener.appendcCs|j|dSr)rr%rrrrr%rz_JoinedListener.removecCstrrrrrrr)sz_JoinedListener.clearN) rrrrrDpropertyrrKryrgr!r%r)rrrrrs  r)r? __future__rrri itertoolsrrrrr r r MemoizedSlotsr objectrr*r{rrrrrrrrs(        ?=O