U a94 @sdZddlZddlmZddlmZddlmZddlmZddlm Z dd lm Z dd lm Z dd lm Z dd lm Z dd lmZddlmZddlmZddlmZddlmZddlmZddlmZddlmZddlmZddlmZddlmZddlmZddlmZddlmZddlmZddlmZddlmZddlmZddlm Z dd lm!Z!dd!lm"Z"d"d#lm#Z#d"dlmZd"d$lm$Z$d"d%lm%Z%d"d&l&mZ'd"d'l&m(Z(d"d(l&m)Z)d"d)l&m*Z*Gd*d+d+e+Z,e,d,Z-e$j.Gd-d.d.ej/ej0ej1e)j2e(j3e(j4e'j5e'j6 Z7d/d0Z8e%j9rRdd1l:m;Z;mn e?d3d4iZ>Gd5d6d6e7e>Z@Gd7d8d8e@ZAe%Bd9d:gZCd;eC_DeC_EdZHe%Gd?ZIe%Gd@ZJe%GdAZKe%GdBZLGdCdDdDeMZNeNZOGdEdFdFeMZPGdGdHdHePZQGdIdJdJeQZRGdKdLdLePZSdMdNZTe%GdOZUeVeWeeWegZXGdPdQdQe%BdQdRdSdTgZYeYdddZZefdUdVZ[efdWdXZ\dsdYdZZ]d[d\Z^dtd]d^Z_dud_d`Z`dadbZadcddZbdedfZcdgdhZddvdidjZedkdlZfdmdnZgdodpZhdqdrZidS)wzDefines 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)DEFERRED_HISTORY_LOAD)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_NO_VALUE)RELATED_OBJECT_OK)SQL_OK) state_str)event) inspection)util)base)roles) traversals)visitorsc@s eZdZdS)NoKeyN)__name__ __module__ __qualname__r.r.ZC:\Users\vtejo\AppData\Local\Temp\pip-unpacked-wheel-nyjtotrf\sqlalchemy\orm\attributes.pyr*;sr*zno namec@s:eZdZdZdZdZd;ddZdejj fd ejj fd ejj fd ej j fgZ d d ZejddZeddZefddZejddZejddZejddZeddZeddZddZed d!Zd"d#Zd$d%Zd&d'Zd(d)Z d*d+Z!d,d-Z"d.d/Z#d0d1Z$dtk rz}z tj t d||f|dW5d}~XYn X||SdS)zThe SQL expression object represented by this :class:`.QueryableAttribute`. This will typically be an instance of a :class:`_sql.ColumnElement` subclass representing a column expression. entity_namespace) proxy_keyZ proxy_ownerrQz}When interpreting attribute "%s" as a SQL expression, expected __clause_element__() to return a ClauseElement object, got: %r)from_N) r3NO_KEY_entity_namespacer4r6__clause_element__Z _annotateAttributeErrorr%raise_rZInvalidRequestError)r< annotationsZceannoZaer.r.r/ expressions&     zQueryableAttribute.expressioncCs|jSrB)r4rEr.r.r/rUsz$QueryableAttribute._entity_namespacecCs |jSrB)rV _annotationsrEr.r.r/r\szQueryableAttribute._annotationscCs|jSrB)r[rEr.r.r/rVsz%QueryableAttribute.__clause_element__cCs|jjSrB)r[ _from_objectsrEr.r.r/r]sz QueryableAttribute._from_objectscCs |j|S)z'Return setter tuples for a bulk UPDATE.)r6_bulk_update_tuplesr<valuer.r.r/r^ sz&QueryableAttribute._bulk_update_tuplescCs,|jr t|j|j|j|j|j||dS)N)r5r6r=)r7AssertionError __class__rDr3r5r6adapt_to_entityr<rcr.r.r/rcs  z"QueryableAttribute.adapt_to_entityc Cs.t|j|j|j|j|j|t||j dSN)r5r6r>r?) r0r2r3r4r5r6r>r$rOr8)r<rDr.r.r/r>s zQueryableAttribute.of_typec Gs.t|j|j|j|j|jj||j|j|dSre) r0r2r3r4r5r6and_r7r8r<otherr.r.r/rf#s zQueryableAttribute.and_c Ks$t|j|j|j|j|j|j|jdSre)r0r2r3r4r5r6r7r8)r<kwr.r.r/_clone.szQueryableAttribute._clonecCs||SrB)rVlabel)r<namer.r.r/rk9szQueryableAttribute.labelcOs||jf||SrBr6r<oprhkwargsr.r.r/operate<szQueryableAttribute.operatecKs|||jf|SrBrmrnr.r.r/reverse_operate?sz"QueryableAttribute.reverse_operateFcCs|jj||ddk S)N) optimisticFr5 hasparent)r<statersr.r.r/ruBszQueryableAttribute.hasparentc Csbzt|j|WStk r\}z0tjtdt|jt|jj||f|dW5d}~XYnXdS)NFNeither %r object nor %r object associated with %s has an attribute %rZreplace_context)getattrr6rWr%rXtyper+)r<r3errr.r.r/ __getattr__Es  zQueryableAttribute.__getattr__cCsd|jj|jfSNz%s.%sr2r+r3rEr.r.r/__str__WszQueryableAttribute.__str__cCs|jjS)zReturn the :class:`.MapperProperty` associated with this :class:`.QueryableAttribute`. Return values here will commonly be instances of :class:`.ColumnProperty` or :class:`.RelationshipProperty`. r6propertyrEr.r.r/rZs zQueryableAttribute.property)NNNr.)F)(r+r,r-__doc__Z is_attributeZ__visit_name__rAr)ZExtendedInternalTraversalZ dp_stringZdp_multiZInternalTraversalZdp_clauseelement_listZ_cache_key_traversalrFr%memoized_propertyrHrrJrrKrNrPr[rUr\rVr]r^rcr>rfrjrkrqrrrur|rr.r.r.r/r0BsZ           )          r0cCs"|jr||||St||SdSrB)is_aliased_classZ_get_from_serializedry)r3Z mapped_classr=rDr.r.r/rChsrC)TypeVarGeneric_T _Generic_Tr.c@s(eZdZdZddZddZddZdS) Mappeda Represent an ORM mapped :term:`descriptor` attribute for typing purposes. This class represents the complete descriptor interface for any class attribute that will have been :term:`instrumented` by the ORM :class:`_orm.Mapper` class. When used with typing stubs, it is the final type that would be used by a type checker such as mypy to provide the full behavioral contract for the attribute. .. tip:: The :class:`_orm.Mapped` class represents attributes that are handled directly by the :class:`_orm.Mapper` class. It does not include other Python descriptor classes that are provided as extensions, including :ref:`hybrids_toplevel` and the :ref:`associationproxy_toplevel`. While these systems still make use of ORM-specific superclasses and structures, they are not :term:`instrumented` by the :class:`_orm.Mapper` and instead provide their own functionality when they are accessed on a class. When using the :ref:`SQLAlchemy Mypy plugin `, the :class:`_orm.Mapped` construct is used in typing annotations to indicate to the plugin those attributes that are expected to be mapped; the plugin also applies :class:`_orm.Mapped` as an annotation automatically when it scans through declarative mappings in :ref:`orm_declarative_table` style. For more indirect mapping styles such as :ref:`imperative table ` it is typically applied explicitly to class level attributes that expect to be mapped based on a given :class:`_schema.Table` configuration. :class:`_orm.Mapped` is defined in the `sqlalchemy2-stubs `_ project as a :pep:`484` generic class which may subscribe to any arbitrary Python type, which represents the Python type handled by the attribute:: class MyMappedClass(Base): __table_ = Table( "some_table", Base.metadata, Column("id", Integer, primary_key=True), Column("data", String(50)), Column("created_at", DateTime) ) id : Mapped[int] data: Mapped[str] created_at: Mapped[datetime] For complete background on how to use :class:`_orm.Mapped` with pep-484 tools like Mypy, see the link below for background on SQLAlchemy's Mypy plugin. .. versionadded:: 1.4 .. seealso:: :ref:`mypy_toplevel` - complete background on Mypy integration cCs tdSrBNotImplementedError)r<rLownerr.r.r/__get__szMapped.__get__cCs tdSrBrr<rLr`r.r.r/__set__szMapped.__set__cCs tdSrBrr<rLr.r.r/ __delete__szMapped.__delete__N)r+r,r-rrrrr.r.r.r/rzs:rc@s,eZdZdZdZddZddZddZd S) InstrumentedAttributezClass bound instrumented attribute which adds basic :term:`descriptor` methods. See :class:`.QueryableAttribute` for a description of most features. TcCs|jt|t||ddSrB)r5setr r rr.r.r/rs zInstrumentedAttribute.__set__cCs|jt|t|dSrB)r5deleter r rr.r.r/rsz InstrumentedAttribute.__delete__c Cs|dkr |St|}|jr.|j|kr.||jSz t|}Wn6tk rp}ztjt||dW5d}~XYnX|j ||SdS)Nrx) r rHr3r rWr%rXorm_excZUnmappedInstanceErrorr5get)r<rLrdict_rvr{r.r.r/rs  zInstrumentedAttribute.__get__N)r+r,r-rZ inherit_cacherrrr.r.r.r/rs rHasEntityNamespacerQFcs>Gfdddt}tjd|_tj|tdd|S)zCreate an QueryableAttribute / user descriptor hybrid. Returns a new QueryableAttribute type that delegates descriptor behavior and getattr() to the given descriptor. cseZdZdZdZdddZdZeddZed d Z ed d Z ed dZe j ddZ ddZddZddZfddZdS)z'create_proxied_attribute..ProxyzPresents the :class:`.QueryableAttribute` interface as a proxy on top of a Python descriptor / :class:`.PropComparator` combination. r.NcSs.||_||_||_||_||_||_||_dSrB)r2r3 descriptororiginal_property _comparator_adapt_to_entityr)r<r2r3rr6rcdocrr.r.r/rAs z0create_proxied_attribute..Proxy.__init__TcSs|jdk ot|j|jjjSrB)rryr2r3r5rIrEr.r.r/rJs z:create_proxied_attribute..Proxy._impl_uses_objectscSstj|jddS)NF)Zraiseerr)r$rOr2rEr.r.r/r4sz5create_proxied_attribute..Proxy._parententitycSs"t|jdr|jjSt|jSdS)Nr4)hasattrrr4rr2rEr.r.r/rUs z9create_proxied_attribute..Proxy._entity_namespacecSs|jjSrBrrEr.r.r/r%sz0create_proxied_attribute..Proxy.propertycSs0t|jr||_|jr*|j|j|_|jSrB)callablerrrcrEr.r.r/r6)s  z2create_proxied_attribute..Proxy.comparatorcSs||j|j|j|j|SrB)rbrDr3rrrdr.r.r/rc3sz7create_proxied_attribute..Proxy.adapt_to_entitycSs,|j||}||jkr$|dkr$|S|SdSrB)rr)r<rLrretvalr.r.r/r<sz/create_proxied_attribute..Proxy.__get__cSsd|jj|jfSr}r~rEr.r.r/rFsz/create_proxied_attribute..Proxy.__str__c sz t|WStk r}z|dkr:tjtd|dz |j}WnDtk r}z&tjtdtj||f|dW5d}~XYndXzt||WWYRStk r}z.tjtdtjt|j||f|dW5d}~XYnXW5d}~XYnXdS)zNDelegate __getattr__ to the original descriptor and/or comparator.r6rxz[Neither %r object nor unconfigured comparator object associated with %s has an attribute %rNrw)ryrWr%rXr6rzr+)r< attributer{r6Zerr2Zerr3rr.r/r|IsD    z3create_proxied_attribute..Proxy.__getattr__)NNN)r+r,r-rr8rAZ_is_internal_proxyrrJr4rUr%rr6rcrrr|r.rr.r/Proxys*        rr)rlZ from_instance)r0rzr+r%Zmonkeypatch_proxied_specials)rrr.rr/create_proxied_attributes }rZREMOVEAPPENDZREPLACEZ BULK_REPLACEZMODIFIEDc@s8eZdZdZdZddZddZeddZd d Z d S) AttributeEventaA 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. r5ro parent_tokencCs||_||_|jj|_dSrBr)r<Zattribute_implror.r.r/rAszAttributeEvent.__init__cCs"t|to |j|jko |j|jkSrB) isinstancerr5rorgr.r.r/__eq__s    zAttributeEvent.__eq__cCs|jjSrB)r5r3rEr.r.r/r3szAttributeEvent.keycCs |j|SrBrt)r<rvr.r.r/ruszAttributeEvent.hasparentN) r+r,r-r __slots__rArrr3rur.r.r.r/rs rc@seZdZdZd(ddZdZdd Zd d Zd d Ze eeZ d)ddZ ddZ e fddZefddZddZe fddZddZe fddZe fddZe fd d!Ze ddfd"d#Ze fd$d%Zd&d'ZdS)* AttributeImplz4internal implementation for instrumented attributes.FNTc Ks||_||_||_||_||_|p$||_| |_|dkr@tj|_ n||_ | dk rV| |_ n|j |_ | dd} | |_ |r|d|j_| |_t|t|_dS)aConstruct 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 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 load_on_unexpire: if False, don't include this attribute in a load-on-expired operation, i.e. the "expired_attribute_loader" process. The attribute can still be in the "expired" list and be considered to be "expired". Previously, this flag was called "expire_missing" and is only used by a deferred column attribute. :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. N_deferred_historyFT)r2r3 callable_r9 trackparentrsend_modified_eventsoperatoreqis_equalaccepts_scalar_loaderdefault_accepts_scalar_loaderpoprr;load_on_unexpireEvent OP_MODIFIED_modified_token)r<r2r3rr9rcompare_functionactive_historyrrrrrprr.r.r/rAs&;   zAttributeImpl.__init__) r2r3rr9rrrrrrrrcCsd|jj|jfSr}r~rEr.r.r/rszAttributeImpl.__str__cCs|jjS)z(Backwards compat for impl.active_historyr9r;rEr.r.r/_get_active_historysz!AttributeImpl._get_active_historycCs ||j_dSrBrr_r.r.r/_set_active_history$sz!AttributeImpl._set_active_historycCs*d}|jst||jt|j|dk S)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)rraparentsridr)r<rvrsmsgr.r.r/ru)szAttributeImpl.hasparentcCsd}|jst|t|j}|r,||j|<n`||jkr|j|}|dk r|j|jkr|dkr~tdt |t ||jfdSd|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 %s from parent state %s along attribute '%s', but the parent record has gone stale, can't be sure this is the most recent parent.) rrarrrr3objrZStaleDataErrorr!)r<rvZ parent_stater`rZid_Z last_parentr.r.r/ sethasparent@s,       zAttributeImpl.sethasparentcCs tdSrBrr<rvrrMr.r.r/rKgszAttributeImpl.get_historycCs tdS)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() Nrrr.r.r/get_all_pendingjszAttributeImpl.get_all_pendingcCs@|j|kstdd}|jjD]}||||}|tk r|}q|S)z=Produce an empty value for an uninitialized scalar attribute.O_default_value should only be invoked for an uninitialized or expired attributeN)r3rar9Z init_scalarr)r<rvrr`fnretr.r.r/_default_value|s   zAttributeImpl._default_valuec Cs|j|kr||jS|j}||jks2|j|tkr|t@s>tS||||}|tks\|tkr`|S|tkrz ||WStk r}ztj td||dW5d}~XYqXn|t k r| |||S|t @stS| ||SdS)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)r3committed_staterrr_fire_loader_callablesrKeyErrorr%rXrset_committed_valuer r)r<rvrrMr3r`r{r.r.r/rs:    zAttributeImpl.getcCsZ|jr"|jr"||jkr"|||S||jkr@|j|}|||S|jrR|||StSdSrB)rrexpired_attributesZ _load_expiredZ callablesrr)r<rvr3rMrr.r.r/rs     z$AttributeImpl._fire_loader_callablescCs|j|||||ddSNrMrr<rvrr` initiatorrMr.r.r/appendszAttributeImpl.appendcCs|j||d|||ddS)N)rM check_oldrrr.r.r/removeszAttributeImpl.removec Cs|j||d|||dddS)NT)rMrrrrr.r.r/rszAttributeImpl.popcCs tdSrBr)r<rvrr`rrMrrr.r.r/rs zAttributeImpl.setcCs>|j|jkr*|j|j}|tkr$dS|Sn|j|||dSdS)z,return the unchanged value of this attributeNr)r3rrr)r<rvrrMr`r.r.r/get_committed_values   z!AttributeImpl.get_committed_valuecCs|||j<|||jg|S)z=set an attribute value on the given instance and 'commit' it.)r3_commit)r<rvrr`r.r.r/rs z!AttributeImpl.set_committed_value)FNFNTTN)F)r+r,r-rrArrrrrrrurrrKrrrrrrrrrrrr.r.r.r/rs< U  '   +    rcsxeZdZdZdZdZdZdZdZdZ fddZ ddZ e fd d Z e d dfd d ZddZddZeddZZS)ScalarAttributeImplz8represents a scalar value-holding InstrumentedAttribute.TF)_replace_token _append_token _remove_tokencs4tt|j||t|t|_|_t|t|_dSrB) superrrAr OP_REPLACErr OP_REMOVEr)r<argrirbr.r/rAszScalarAttributeImpl.__init__cCs|jjr|||t}n||jt}|jjr@|||||j| |||| |jt}|tkr|tkr|j s|j|j krt d|dS)N%s object does not have a value)r9r;rrr3rrfire_remove_eventr_modified_eventrZexpiredrrWr<rvroldexistingr.r.r/r s  zScalarAttributeImpl.deletecCsv|j|krt||||jS|j|jkr8t||tS|t@rH|tN}|j|||d}|tkrdtSt|||SdSr) r3Historyfrom_scalar_attributerrr rr HISTORY_BLANKr<rvrrMcurrentr.r.r/rKs  zScalarAttributeImpl.get_historyNc Cs\|jjr|||t}n||jt}|jjr@||||||}|||||||j<dSrB) r9r;rrr3rrfire_replace_eventr r<rvrr`rrMrrrr.r.r/r*s zScalarAttributeImpl.setcCs&|jjD]}|||||p|j}q|SrB)r9rrr<rvrr`previousrrr.r.r/r@s z&ScalarAttributeImpl.fire_replace_eventcCs$|jjD]}||||p|jqdSrB)r9rrr<rvrr`rrr.r.r/rGs z%ScalarAttributeImpl.fire_remove_eventcCs|jjdjdS)Nr)rcolumnsrzrEr.r.r/rzKszScalarAttributeImpl.type)r+r,r-rrrIrG collectiondynamicrrArrrKrrrrrz __classcell__r.r.rr/rs$   rc@sdeZdZdZdZdZdZdZdZddZ e fddZ e fd d Z e d dfd d ZddZddZd S)ScalarObjectAttributeImplzrepresents a scalar-holding InstrumentedAttribute, where the target object is also instrumented. Adds events to delete/set operations. FTr.cCs|jjr"|j||ttBtBd}n|j||ttAtBtBd}| ||||j | |j t }|t kr|tk r|j dkrtd|dS)Nrr)r9r;rrrrrr rrrrr3rrrWrr.r.r/r_s8z ScalarObjectAttributeImpl.deletecCs|j|kr||j}n,|t@r&|tN}|j|||d}|tkrBtS|jsVt|||S|j|jt }|tkr|t t Bt Bt BtBB}|||j|}tj||||dSdS)Nr)original)r3r rrrrrfrom_object_attributer _NO_HISTORYrrrrr r)r<rvrrMrrZloader_passiver.r.r/rKsB  z%ScalarObjectAttributeImpl.get_historycCs|j|kr||j}n|t@r0|j|||d}ngS|dk r\|tk r\|tk r\t||fg}ndg}|j|jkr|j|j}|dk r|tk r|tk r||k r|t||f|S)Nr)NN)r3rrrrr rr)r<rvrrMrrrr.r.r/rs2    z)ScalarObjectAttributeImpl.get_all_pendingNc Cs|jjr"|j||ttBtBd}n|j||ttAtBtBd}|dk rz|t k rz||k rz|r^dSt dt |t ||j f||||||}|||j <dS)z'Set a value on the given InstanceState.rNz2Object %s not associated with %s on attribute '%s')r9r;rrrrrr rr ValueErrorrr!r3rrr.r.r/rsD  zScalarObjectAttributeImpl.setcCsX|jr&|dttfkr&|t||d|jjD]}||||p@|jq.||||dS)NF) rrrrr r9rrrrr.r.r/rs z+ScalarObjectAttributeImpl.fire_remove_eventcCs|jr.||k r.|dttfkr.|t||d|jjD]}|||||pJ|j}q6|||||jr~|dk r~|t||d|SNFT) rrrrr r9rrrrr.r.r/rs&  z,ScalarObjectAttributeImpl.fire_replace_event)r+r,r-rrrIrGrrrrrKrrrrrr.r.r.r/rPs  $ - rcseZdZdZdZdZdZdZdZdZ d,fdd Z dd Z e fd d Z efd d ZddZddZddZddZddZddZddZe fddZe fddZe fd d!Zde dddfd"d#Zd$d%Zd&d'Zd(d)Zde fd*d+ZZS)-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  stt|j||||f||d| |dkr2|j}||_||_t|t|_t|t |_ t|t |_ t ||_t|jddrt|ddd} t|ddd} dS) N)rr _sa_linkerinit_collectioncSs||dSrBrtargetrcollection_adapterr.r.r/linkJsz.CollectionAttributeImpl.__init__..linkdispose_collectioncSs|ddSrBrrr.r.r/unlinkNsz0CollectionAttributeImpl.__init__..unlink)rrrA_CollectionAttributeImpl__copyrrr OP_APPENDrrrOP_BULK_REPLACErr%duck_type_collectionrryr#Z listens_for) r<r2r3rr9 typecallabler copy_functionrrpr r rr.r/rA's4        z CollectionAttributeImpl.__init__cCsddt|DS)NcSsg|]}|qSr.r.).0yr.r.r/ Ssz2CollectionAttributeImpl.__copy..)rr)r<itemr.r.r/Z__copyRszCollectionAttributeImpl.__copycCs.|j|||d}|tkrtSt|||SdSr)rrrrfrom_collectionrr.r.r/rKUsz#CollectionAttributeImpl.get_historycs|j|krgS||j}t|d}|j|jkr|j|j}|tk rdd|D}dd|D}t|t|fdd|Dfdd|Dfdd|DSdd|DS) N _sa_adaptercSs$g|]}|dk rt|pd|fqSrBr rcr.r.r/rhsz;CollectionAttributeImpl.get_all_pending..cSs$g|]}|dk rt|pd|fqSrBr rr.r.r/rlscs g|]\}}|kr||fqSr.r.rso original_setr.r/ruscs g|]\}}|kr||fqSr.r.rrr.r/rzscs g|]\}}|kr||fqSr.r.r current_setr.r/r{scSsg|]}t||fqSr.r )rrr.r.r/rs)r3ryrrdict)r<rvrrMrrcurrent_statesoriginal_statesr.r rr/r\s4       z'CollectionAttributeImpl.get_all_pendingcCsT|jjD]}||||p|j}q|||td|jrP|dk rP|t||d|Sr1)r9rrrrrrr rr.r.r/fire_append_events  z)CollectionAttributeImpl.fire_append_eventcCs$|jjD]}||||p|j}q|SrB)r9Zappend_wo_mutationrrr.r.r/fire_append_wo_mutation_events z5CollectionAttributeImpl.fire_append_wo_mutation_eventcCs|||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)rr)r<rvrrr.r.r/fire_pre_remove_events z-CollectionAttributeImpl.fire_pre_remove_eventcCsT|jr |dk r |t||d|jjD]}||||p:|jq(|||tddSr)rrr r9rrrrrr.r.r/rs  z)CollectionAttributeImpl.fire_remove_eventcCs@|j|krdS|||td|||j}|||j=dSr1)r3rrget_collectionr!Zclear_with_event)r<rvrrr.r.r/rs  zCollectionAttributeImpl.deletecCsF|j|kstd|j|jkr*|j|jS||\}}|||S)z;Produce an empty collection for an un-initialized attributer)r3ra_empty_collections_initialize_collectionZ _set_empty)r<rvradapter user_datar.r.r/rs    z&CollectionAttributeImpl._default_valuecCs0|j|j||j\}}|j|||||fSrB)r@Zinitialize_collectionr3rr9r)r<rvr+rr.r.r/r*sz.CollectionAttributeImpl._initialize_collectioncCs^|j|||d}|tkrN|||||}|j|ks:td||j|n |||dSNrz,Collection was loaded during event handling.)r(rr%r3ra_get_pending_mutationrZappend_with_eventr<rvrr`rrMrr.r.r/rszCollectionAttributeImpl.appendcCs`|j||j|d}|tkrP||||||j|ksrr(rr.r.rr/r sJ +  (      K rcsjjjfddfdd}fdd}fdd}rftjd |d d d ntjd |d d d tjd |d d d dS)z6Apply listeners to synchronize a two-way relationship.cs$tdt||j|jjjfdS)NzBidirectional attribute conflict detected: Passing object %s to attribute "%s" triggers a modify event on attribute "%s" via the backref "%s".)rr!rr5) child_stater child_impl)rr.r/_acceptable_key_errsz.backref_listeners.._acceptable_key_errc s||kr |S|dk r~|tk r~|tk r~t|t|}}|jj}|jsV|jsV|j}n|j }||k r~|j ||| j t d|dk r t|t|}} |jj} |jk r|j| jk rȈ||| | j } | jr| jnd} || k r || k r | j|| | |t d|Sr)rrr r r@r5rrrrrrrrrrr) rvchildZoldchildr old_stateZold_dictr5Zcheck_recursive_tokenrB child_dictrCcheck_append_tokencheck_bulk_replace_token)rDr3 parent_implrr.r/"emit_backref_from_scalar_set_eventsd      z=backref_listeners..emit_backref_from_scalar_set_eventcs|dkr dSt|t|}}|jj}|jk rL|j|jk rL||||j}|jr^|jnd}||k r||k r|j||| |t d|Sr) r r r@r5rrrrrrr)rvrErrBrGrCrHrI)rDr3rr.r/)emit_backref_from_collection_append_events0   zDbackref_listeners..emit_backref_from_collection_append_eventc s|dk r|tk r|tk rt|t|}}|jj}|js\|js\|j}|j }oXj }n|j}|jrn|j nd}d}||k r||k r|rt |j j|s|j||||tddS)NFr)rrr r r@r5rrrrrr%Z has_dupesr!r3rrr) rvrErrBrGrCZcheck_remove_tokenZcheck_replace_tokenZcheck_for_dupes_on_remove)r3rJuselistr.r/)emit_backref_from_collection_remove_eventsF   zDbackref_listeners..emit_backref_from_collection_remove_eventrT)rrawrrN)r5rr#listen)rr3rMrKrLrNr.)rDrr3rJrrMr/backref_listenersus8  A -rQZ NO_HISTORYc@steZdZdZddZeZddZddZdd Zd d Z d d Z ddZ e ddZ e efddZe ddZdS)raA 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). cCs|tkSrB)rrEr.r.r/__bool__VszHistory.__bool__cCst|jp|jp|j S)zhReturn True if this :class:`.History` has no changes and no existing, unchanged state. )boolr@deleted unchangedrEr.r.r/empty[sz History.emptycCs|jpg|jpg|jpgS)z3Return a collection of added + unchanged + deleted.)r@rUrTrEr.r.r/sumcsz History.sumcCs|jpg|jpgS)z)Return a collection of added + unchanged.)r@rUrEr.r.r/ non_deletedjszHistory.non_deletedcCs|jpg|jpgS)z+Return a collection of unchanged + deleted.)rUrTrEr.r.r/ non_addedoszHistory.non_addedcCst|jp |jS)z2Return True if this :class:`.History` has changes.)rSr@rTrEr.r.r/ has_changestszHistory.has_changescCs0tdd|jDdd|jDdd|jDS)NcSs g|]}|dk rt|pdqSrBr rr.r.r/r{sz$History.as_state..cSs g|]}|dk rt|pdqSrBr rr.r.r/rscSs g|]}|dk rt|pdqSrBr rr.r.r/rs)rr@rUrTrEr.r.r/as_stateyszHistory.as_statecCs|j|jt}|tkr<|tkr,|dddS|d|gdSnp|tk rb|||dkrb|d|gdSt|tkrd}t|tkrd}n|g}|tkr|dd|S||gd|SdS)Nr.T)rrr3rrrr_NO_STATE_SYMBOLSclsrrvrrrTr.r.r/rs$    zHistory.from_scalar_attributecCs|tkr|j|jt}|tkrD|tkr4|dddS|d|gdSnp||krb|tk rb|d|gdSt|tksv|dkrd}t|tkrd}n|g}|tkr|dd|S||gd|SdS)Nr.)rrrr3rrr\r]r.r.r/rs    zHistory.from_object_attributecs|j|jt}|tkr$|dddSt|d}|tkrF|t|ddS|tkr^|dt|dSdd|D}dd|D}t|t||fdd|Dfdd|Dfdd|DSdS) Nr.rcSs$g|]}|dk rt|pd|fqSrBr rr.r.r/rsz+History.from_collection..cSs$g|]}|dk rt|pd|fqSrBr rr.r.r/rscsg|]\}}|kr|qSr.r.rrr.r/rscsg|]\}}|kr|qSr.r.rrr.r/rscsg|]\}}|kr|qSr.r.rrr.r/rs)rrr3rrryr8r!)r^rrvrrr"r#r.r$r/rs*  zHistory.from_collectionN)r+r,r-rrR __nonzero__rVrWrXrYrZr[ classmethodrrrrr.r.r.r/r=s  ! rr@rUrTcCstt|||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. )get_state_historyr )rr3rMr.r.r/rKs#rKcCs |||SrB)rK)rvr3rMr.r.r/rasracCst|}t|}||||S)ZTODO)rr has_parent)r^rr3rsr@rvr.r.r/rbsrbcKsH|dd}|dd}|dd}t|||||d}t||f||S)Nr6r=r)r)rregister_descriptorregister_attribute_impl)r2r3rir6r=rdescr.r.r/register_attribute s    rfc Kst|}|r*|dd} ||| p$t} n |dd} ||j} |rX|||| | f|} nJ|rxt|||| fd| i|} n*|rt|||| f|} nt|||| f|} | ||_|rt ||||| |||S)Nr) rrZinstrument_collection_classr8r9rrrr5rQZpost_configure_attribute) r2r3rMrZ useobjectZ impl_classZbackrefrir@factoryrr9r5r.r.r/rd)sJ      rdcCs.t|}t||||d}||_||||S)N)r6r=)rrrZinstrument_attribute)r2r3r6r=rr@rr.r.r/rcUs rccCst||dSrB)rZuninstrument_attribute)r2r3r.r.r/unregister_attributedsrhcCst|}|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)rr3rvrr.r.r/rhsrcCs\|j|j}||d}|dk r6|j}||||d|||}||||}||S)zInitialize a collection attribute and return the collection adapter. Discards any existing collection which may be there. NF)r@r5rrr9rr(Z _reset_empty)rvrr3attrrr=r,r+r.r.r/ris   ricCs,t|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 r@r5r)rLr3r`rvrr.r.r/rsrcCs.t|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 r@r5r)rLr3r`rrvrr.r.r/ set_attributesrkcCs&t|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 r@r5rrLr3rvrr.r.r/ get_attributes rmcCs*t|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 r@r5rrlr.r.r/ del_attributes rncCsDt|t|}}|j|j}|j||j|j||tdddS)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` TZ is_userlandN) r r r@r5r9modifiedrrr)rLr3rvrr5r.r.r/ flag_modifieds rqcCs(t|t|}}|j|dtdddS)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` NTro)r r rr)rLrvrr.r.r/ flag_dirtysrr)F)FNFNN)NNN)N)jrrrrrrr&rrrr r r r rrrrrrrrrrrrrrrrrrr r!r#r$r%ZsqlZsql_baser'r(r)strr*rTZ_self_inspectsZ_MappedAttributeZInspectionAttrZPropComparatorZHasCopyInternalsZJoinTargetRoleZ OnClauseRoleZ ImmutableZMemoizedHasCacheKeyr0rCr5typingrrrrrzrr namedtuplerZ is_mapperrrsymbolrr rrrobjectrrrrrrrQr frozensetrr\rrrKrarbrfrdrcrhrrirrkrmrnrqrrr.r.r.r/s                                        '   E%      2FW=kE 0  &    -