U ofb@sddlmZddlZddlZddlmZddlmZddlmZddlmZddlm Z ddlm Z dd lm Z dd lm Z dd lm Z dd lmZdd lmZddlmZddlmZddlmZddlmZddlmZddlmZddlmZddlmZddlmZddlmZddlmZer6ddlmZeeeeeedffZeee eee efZ eeeedfdfZ!edefZ"edZ#e edfZ$e edeedfedfZ%edZ&edee"d Z'e(d!Z)d"d#d$gZ*Gd%d&d&eZ+Gd'd(d(e,Z-Gd)d*d*e-Z.Gd+d,d,e-Z/Gd-d.d.e-Z0Gd/d0d0e-Z1Gd1d2d2e1Z2Gd3d4d4e1Z3Gd5d6d6e2e3Z4Gd7d8d8Z5Gd9ddZ6ed:d:d;dd?d;d@d=Z7dAdBd;dCd=Z7dDdd;dEdFZ8dS)G) annotationsN)Any)Callable)cast) Collection)Deque)Dict) FrozenSet)Iterable)Iterator)List)Optional)overload)Protocol)Sequence)Set)Tuple) TYPE_CHECKING)TypeVar)Union)util)not_none)Literal.Revision)rzLiteral['base']_T_TR)boundz(?:(.+?)@)?(\w+)?((?:\+|-)\d+)@-+c@s$eZdZdddddddddZdS)_CollectRevisionsProtocol_RevisionIdentifierTypebool;Tuple[Set[Revision], Tuple[Optional[_RevisionOrBase], ...]]upperlower inclusive implicit_baseassert_relative_lengthreturncCsdSNr)selfr'r(r)r*r+rrE/opt/hc_python/lib/python3.8/site-packages/alembic/script/revision.py__call__4sz"_CollectRevisionsProtocol.__call__N)__name__ __module__ __qualname__r0rrrr/r"3sr"c@s eZdZdS) RevisionErrorN)r1r2r3rrrr/r4>sr4cs&eZdZddddfdd ZZS)RangeNotAncestorErrorr#None)r(r'r,cs,||_||_td|pd|p dfdS)Nz-Revision %s is not an ancestor of revision %sbase)r(r'super__init__)r.r(r' __class__rr/r9CszRangeNotAncestorError.__init__r1r2r3r9 __classcell__rrr:r/r5Bsr5cs&eZdZddddfdd ZZS) MultipleHeads Sequence[str] Optional[str]r6)headsargumentr,cs*||_||_td|d|fdS)Nz6Multiple heads are present for given argument '%s'; %s, )rArBr8r9join)r.rArBr:rr/r9Os zMultipleHeads.__init__r<rrr:r/r>Nsr>cs&eZdZddddfdd ZZS)ResolutionErrorstrr6)messagerBr,cst|||_dSr-)r8r9rB)r.rGrBr:rr/r9Ys zResolutionError.__init__r<rrr:r/rEXsrEcs(eZdZdZdddfdd ZZS) CycleDetectedZCycler?r6 revisionsr,cs&||_td|jd|fdS)Nz %s is detected in revisions (%s)rC)rJr8r9kindrDr.rJr:rr/r9as zCycleDetected.__init__r1r2r3rKr9r=rrr:r/rH^srHcs(eZdZdZdddfdd ZZS)DependencyCycleDetectedzDependency cycler?r6rIcst|dSr-r8r9rLr:rr/r9lsz DependencyCycleDetected.__init__rMrrr:r/rNisrNcs(eZdZdZdddfdd ZZS) LoopDetectedz Self-looprFr6revisionr,cst|gdSr-rOr.rRr:rr/r9sszLoopDetected.__init__rMrrr:r/rPpsrPcs(eZdZdZdddfdd ZZS)DependencyLoopDetectedzDependency self-loopr?r6rQcst|dSr-rOrSr:rr/r9zszDependencyLoopDetected.__init__rMrrr:r/rTwsrTc @seZdZdZdddddZejddd d Zejddd d Zejddd dZ ejddddZ ejddddZ dddddddddZ ddddddZ ddddddZddddd d!Zddddd"d#Zdd%d&dd'd(d)Zdd+d+d,d-d.Zd/dd0d1d2Zd3d4d5d6d7Zd+d8d5d9d:Zd/d8d,d;d<Zdd=d+d8d>d?d@ZdAdBdCdDdEZddFd+d&dGdHdIdJZddKdLd&d&dMdNdOZd3dPd5dQdRZddTdTd&d&d&d&dUdVdWdXZddYdZd&d&d&d[d\d]d^ZddYdZd&d&dUd_d`daZddbdYdZd&dUdcdddeZddfdgdhdidjZ ddkdld+d&dmdndodpZ!dTdTd&dqdrdsdtZ"dTdTd&d4drdudvZ#dTdTd&d&d&dwdxdydzZ$dTdTd&d&d&d{dxd|d}Z%ddBd5d~dZ&d*S) RevisionMapzMaintains a map of :class:`.Revision` objects. :class:`.RevisionMap` is used by :class:`.ScriptDirectory` to maintain and traverse the collection of :class:`.Script` objects, which are themselves instances of :class:`.Revision`. z Callable[[], Iterable[Revision]]r6) generatorr,cCs ||_dS)a Construct a new :class:`.RevisionMap`. :param generator: a zero-arg callable that will generate an iterable of :class:`.Revision` instances to be used. These are typically :class:`.Script` subclasses within regular Alembic use. N) _generator)r.rVrrr/r9szRevisionMap.__init__Tuple[str, ...]r,cCs |j|jS)zAll "head" revisions as strings. This is normally a tuple of length one, unless unmerged branches are present. :return: a tuple of string revision numbers. ) _revision_maprAr.rrr/rAs zRevisionMap.headscCs |j|jS)zAll "base" revisions as strings. These are revisions that have a ``down_revision`` of None, or empty tuple. :return: a tuple of string revision numbers. )rZbasesr[rrr/r\s zRevisionMap.basescCs |j|jS)zeAll "real" head revisions as strings. :return: a tuple of string revision numbers. )rZ _real_headsr[rrr/r]szRevisionMap._real_headscCs |j|jS)zeAll "real" base revisions as strings. :return: a tuple of string revision numbers. )rZ _real_basesr[rrr/r^szRevisionMap._real_bases_RevisionMapTypecCst}t}t}d}d}t}t}|D]v}|||j|kr\td|j|||j<|j rv|||||||j r||f7}|j r4||f7}q4| } | |tt|||tt||D]^} | jD]R} | |kr td| | f|| } | | | | jkr2|| || qq||tt||| ||||t|} d| d<| d<tdd|D|_tdd|D|_tdd|D|_td d|D|_||| | S) z_memoized attribute, initializes the revision map from the initial collection. r%Revision %s is present more than once-Revision %s referenced from %s is not presentNcss|] }|jVqdSr-rR.0revrrr/ sz,RevisionMap._revision_map..css|] }|jVqdSr-rbrcrrr/rfscss|] }|jVqdSr-rbrcrrr/rfscss|] }|jVqdSr-rbrcrrr/rfs) sqlautil OrderedDictZ OrderedSetsetrWaddrRrwarn branch_labelsis_base _is_real_basecopy_map_branch_labelsrr__add_depends_onvalues_all_down_revisions add_nextrev_versioned_down_revisionsdiscard_normalize_depends_on_detect_cyclesdictitemstuplerAr]r\r^ _add_branches)r.map_rAr]r\r^Zhas_branch_labelsZ all_revisionsrRrev_mapredownrev down_revisionZ revision_maprrr/rZsf                 zRevisionMap._revision_map_InterimRevisionMapTypez Set[Revision]zTuple[Revision, ...])r~rAr\r]r^r,c Cs |sdS|r|stt|dd|jdd|tt|dDdd|jdd|tt|dD}t||}|rtt||r|st t|d d|jd d|tt|dDd d|jd d|tt|dD}t||}|rt t|dS) NcSsh|] }|jqSrrbrcrrr/ sz-RevisionMap._detect_cycles..cSs|jSr-rurrrr/z,RevisionMap._detect_cycles..r}css|] }|jVqdSr-rbrcrrr/rfsz-RevisionMap._detect_cycles..cSs|jSr-nextrevrrrr/r!rcSsh|] }|jqSrrbrcrrr/r,scSs|jSr-)rsrrrr/r/rcss|] }|jVqdSr-rbrcrrr/rf3scSs|jSr- _all_nextrevrrrr/r6r) rHlist_iterate_related_revisionsrr_ intersectionrikeyssortedrN)r.r~rAr\r]r^Z total_spaceZ deleted_revsrrr/rx sT   zRevisionMap._detect_cycleszCollection[Revision])rJr}r,cCsh|D]^}|jr|jdk st|jD]>}||krX||}|dk sBttd||j|jf|||<q"qdS)Nz;Branch name '%s' in revision %s already used by revision %s)rl_orig_branch_labelsAssertionErrorr4rR)r.rJr}rR branch_labelZmap_revrrr/rp?s    zRevisionMap._map_branch_labelscCs|D]v}|jr|j|j|j|g|ddD]}|j|jq.|}|r|js|js|j|j|jrz||j}qFqqFqdSNFinclude_dependencies)rlupdate_get_descendant_nodes_is_real_branch_pointis_merge_pointr)r.rJr}rRnodeparentrrr/r|Ts(  zRevisionMap._add_branchescsJ|D]@}|jr>fddt|jD}tdd|D|_qd|_qdS)aResolve the 'dependencies' for each revision in a collection in terms of actual revision ids, as opposed to branch labels or other symbolic names. The collection is then assigned to the _resolved_dependencies attribute on each revision object. csg|] }|qSrr)rddeprrr/ ysz/RevisionMap._add_depends_on..cSsg|]}|dk r|jqSr-rbrddrrr/r}srN) dependenciesrto_tupler{_resolved_dependencies)r.rJr}rRdepsrrr/rqks    zRevisionMap._add_depends_oncCsf|D]\}|jrZt|j}|j|gd|dD]"}||kr:q*q*|jr*||jq*t||_qd|_qdS)aCreate a collection of "dependencies" that omits dependencies that are already ancestor nodes for each revision in a given collection. This builds upon the _resolved_dependencies collection created in the _add_depends_on() method, looking in the fully populated revision map for ancestors, and omitting them as the _resolved_dependencies collection as it is copied to a new collection. The new collection is then assigned to the _normalized_resolved_dependencies attribute on each revision object. The collection is then used to determine the immediate "down revision" identifiers for this revision. F)rr}rN)rri_get_ancestor_nodesdifference_updater{!_normalized_resolved_dependencies)r.rJr}rRZnormalized_resolvedrerrr/rws$  z!RevisionMap._normalize_depends_onFrr$)rR_replacer,csB|j}|s&j|kr&tdjn|rBj|krBtdj|j<g}|||||||||jr|j jf7_ j r|j jf7_ j D]0}||krtd|ft ||q|||jrtfdd|jDjf|_jr>tfdd|jDjf|_dS)zadd a single revision to an existing map. This method is for single-revision use cases, it's not appropriate for fully populating an entire revision map. r`zrevision %s not in maprac3s*|]"}|tjjgkr|VqdSr-)rirsunionrRrdheadrbrr/rfs z+RevisionMap.add_revision..c3s*|]"}|tjjgkr|VqdSr-)rirurrRrrbrr/rfs N)rZrRrrk Exceptionr|rprqrmr\rnr^rsrrtrw _is_real_headr{r]is_headrA)r.rRrr}rJrrrbr/ add_revisionsJ        zRevisionMap.add_revisionNr@)rr,cCsL|j}|r|||}t|dkr8t||r2d|nd|rD|dSdSdS)aReturn the current head revision. If the script directory has multiple heads due to branching, an error is raised; :meth:`.ScriptDirectory.get_heads` should be preferred. :param branch_label: optional branch name which will limit the heads considered to those which include that branch_label. :return: a string revision number. .. seealso:: :meth:`.ScriptDirectory.get_heads` z%s@headrrN)rAfilter_for_lineagelenr>)r.r current_headsrrr/get_current_heads zRevisionMap.get_current_headrF) identifierr,cCs||j|Sr-)rr\)r.rrrr/_get_base_revisionsszRevisionMap._get_base_revisionszOptional[_GetRevArg]z%Tuple[Optional[_RevisionOrBase], ...])id_r,cst|ttttfr*tfdd|DdS|\}t|dkrzZt|ddkr d}dk rtfdd |D}tfd d |DWSWnt k rYnXtfd d |DSdS) aReturn the :class:`.Revision` instances with the given rev id or identifiers. May be given a single identifier, a sequence of identifiers, or the special symbols "head" or "base". The result is a tuple of one or more identifiers, or an empty tuple in the case of "base". In the cases where 'head', 'heads' is requested and the revision map is empty, returns an empty tuple. Supports partial identifiers, where the given identifier is matched against all identifiers that start with the given characters; if there is exactly one match, that determines the full revision. csg|]}|qSr) get_revisions)rdZid_elemr[rr/rsz-RevisionMap.get_revisions..rrrrANc3s |]}t|jkr|VqdSr-) is_revisionrlr)rrr/rf(s z,RevisionMap.get_revisions..c3s|]}j|dVqdS))stepsN)_walkr)rintr.rr/rf.sc3s|]}|VqdSr-)_revision_for_identrdrev_id)rr.rr/rf5s) isinstancerr{ri frozensetsum_resolve_revision_numberrintr ValueError)r.r resolved_idZ select_headsr)rrr.r/r s(    zRevisionMap.get_revisionszOptional[Revision]cCs@||\}}t|dkr$t|||r0|dnd}|||S)a Return the :class:`.Revision` instance with the given rev id. If a symbolic name such as "head" or "base" is given, resolves the identifier into the current head or base revision. If the symbolic name refers to multiples, :class:`.MultipleHeads` is raised. Supports partial identifiers, where the given identifier is matched against all identifiers that start with the given characters; if there is exactly one match, that determines the full revision. rrr)rrr>r)r.rrrresolvedrrr/ get_revision:s   zRevisionMap.get_revisionc Csvz|j|}Wn^tk rlz||}Wn2tk r^}ztd|||W5d}~XYn X|YSYnX|SdS)NzNo such branch: '%s')rZKeyErrorrrE)r.r branch_revZ nonbranch_revrerrr/_resolve_branchOszRevisionMap._resolve_branchzUnion[str, Tuple[()], None])r check_branchr,c s.|r||}nd}z|j}Wntk r:d}YnX|dkrވsLtfdd|jD}|rp|||}|stdtdkrdndfnFt|dkrtd d d d |d dDfn|j|d }|r*|dk r*|dk stst||j |j s*td|j |f|S)NFcs*g|]"}|rt|dkr|r|qS))r startswith)rdxrrr/rts  z3RevisionMap._revision_for_ident..z!No such revision or branch '%s'%sz\; please ensure at least four characters are present for partial revision identifier matchesrz)Multiple revisions start with '%s': %s...rCcss|]}d|VqdS)z'%s'Nrrdrrrr/rfsz2RevisionMap._revision_for_ident..rrz*Revision %s is not a member of branch '%s') rrZrrrrErrD_shares_lineagerR)r.rrrrRrevsrrr/r_s^         zRevisionMap._revision_for_identz#Iterable[Optional[_RevisionOrBase]]zSet[Optional[_RevisionOrBase]])targetsr,cCsJt|}t|D]4}|st||j|gdd|gr||q|Sr)rirrrr differencerv)r.rrerrr/_filter_into_branch_headss  z%RevisionMap._filter_into_branch_headsz Iterable[_TR]zTuple[_TR, ...])r check_againstrr,csH|\}}g|r ||r.|tfdd|DS)Nc3s"|]}j|dr|VqdS)rN)r)rdtgrr.Zsharesrr/rfsz1RevisionMap.filter_for_lineage..)rappendextendr{)r.rrrrrrrr/rs  zRevisionMap.filter_for_lineagezOptional[_RevisionOrStr]zSequence[_RevisionOrStr])targettest_against_revsrr,csr|sdSt|ts"t|}n|}fddtj|ddD}ttj|g|d j |g|d |S)NTcs$g|]}t|ts|n|qSr)rrr)rdZtest_against_revr[rr/rs z/RevisionMap._shares_lineage..rdefaultr) rrrrrrr$rirrrr)r.rrrZresolved_targetZresolved_test_against_revsrr[r/rs4    zRevisionMap._shares_lineagez%Tuple[Tuple[str, ...], Optional[str]]cCst|tr$d|kr$|dd\}}nF|dk rft|trH|rHt|dtrVt|ttfsftd|fnd}|j|dkr|r||j||fS|j|fSnT|dkr| |}|r|f|fSd|fSn*|dks|dkrd|fSt j |dd |fSdS) NrrrzSrevision identifier %r is not a string; ensure database driver settings are correctrArrr7r) rrFsplitr{r4rZrrAr]rrr)r.rrZ current_headrrr/rs@       z$RevisionMap._resolve_revision_numberTr#zIterator[Revision])r'r(r*r)r+select_for_downgrader,c csN|r |j}n|j}||||||d\}} ||| D]} t|| Vq4dS)auIterate through script revisions, starting at the given upper revision identifier and ending at the lower. The traversal uses strictly the `down_revision` marker inside each migration script, so it is a requirement that upper >= lower, else you'll get nothing back. The iterator yields :class:`.Revision` objects. )r)r*r+N)_collect_downgrade_revisions_collect_upgrade_revisions_topological_sortrr) r.r'r(r*r)r+rfnrJrArrrr/iterate_revisionss zRevisionMap.iterate_revisionsz%Collection[Optional[_RevisionOrBase]]zOptional[_RevisionMapType]z Iterator[Any])rr}checkomit_immediate_dependenciesrr,csR|rdddfdd }n&|r0ddddd}nddddd}|j|||dS) Nr Iterable[str]rer,cs|kr|jS|jSdSr-)rrrerrr/rCsz-RevisionMap._get_descendant_nodes..fncSs|jSr-rrrrr/rKscSs|jSr-rrrrr/rPsr}rr)r.rr}rrrrrrr/r9sz!RevisionMap._get_descendant_nodes)rr}rrr,cCs8|rddddd}nddddd}|j||||dS)NrrrcSs|jSr-_normalized_down_revisionsrrrr/r`sz+RevisionMap._get_ancestor_nodes..fncSs|jSr-rrrrr/resrr)r.rr}rrrrrr/rWszRevisionMap._get_ancestor_nodesz#Callable[[Revision], Iterable[str]])rrr}rr,ccs|dkr|j}t}t}|D]}t|}|||r@t} |r|} |rZ| | | |krdq@|| || D]4} || } | dk st| j | krt d|| qv| Vq@|r | | |g} | r t d|j d dd| Dfq dS)Nz(Dependency resolution failed; broken mapz@Requested revision %s overlaps with other requested revisions %srCcss|] }|jVqdSr-rbrrrr/rfsz9RevisionMap._iterate_related_revisions..)rZri collectionsdequerrpoprjrrRr4rrrD)r.rrr}rseentodoZ target_forrZ per_targetrerZnext_revoverlapsrrr/rlsJ        z&RevisionMap._iterate_related_revisionsrz List[str])rJrAr,c sjdddfdd dd|Dtj}ttfdd|D|jd fd d D}g}d }r|}t|D] \}} ||kr|| kr|}qnq|kr||||} | d k stfdd | jD} | s|=||=t |dd }qn| j sBt | j dkrB| d |<|| |qn| d |<| dd | d ||<|fdd| dd Dqnrt|S)zYield revision ids of a collection of Revision objects in topological sorted order (i.e. revisions always come after their down_revisions and dependencies). Uses the order of keys in _revision_map to sort. rFSet[str])rr,csdd|gDS)NcSsh|] }|jqSrrbrrrr/rszGRevisionMap._topological_sort..get_ancestors..)r)r) id_to_revr.rr/ get_ancestorssz4RevisionMap._topological_sort..get_ancestorscSsh|] }|jqSrrbrrrr/rsz0RevisionMap._topological_sort..csh|]}|jkr|jqSrrbr)rrr/rs )keycsg|] }|qSrrrrrr/rsz1RevisionMap._topological_sort..rNcs g|]}|kr|kr|qSrrr)rrrr/rsrc3s|]}|VqdSr-rrrrr/rfsz0RevisionMap._topological_sort..)rZrrindex enumeraterremoverrmaxrrrurvr) r.rJrAZinserted_orderZancestors_by_idxoutputZcurrent_candidate_idx candidateZcheck_head_index ancestorsZ candidate_revZ heads_to_addr)rrrr.rr/rsf            zRevisionMap._topological_sortzOptional[Union[str, Revision]]rzOptional[_RevisionOrBase])startrr no_overwalkr,c Cst|tr||}n|}tt|D]}|dkrz|dks>tdd||dkrV|jn|jD}|rt| ||}q|}n0|dkrd}n"||dkr|j n|j }|sd}|s|rdn|} | St |dkrt d |d}q&|S) a Walk the requested number of :steps up (steps > 0) or down (steps < 0) the revision tree. :branch_label is used to select branches only when walking up. If the walk goes past the boundaries of the tree and :no_overwalk is True, None is returned, otherwise the walk terminates early. A RevisionError is raised if there is no unambiguous revision to walk to. rr7cSsg|] }t|qSrrrcrrr/r$sz%RevisionMap._walk..Nr)r7rzAmbiguous walk)rrFrrangeabsrrr\rrrArrr4) r.rrrrinitial_Zwalk_upchildrenretrrr/rs<      zRevisionMap._walkz/Tuple[Optional[str], Optional[_RevisionOrBase]])current_revisionsrr+r,cCs|dkr dSt|tstdt|}|r|\}}}t|}|dkr|dkrhtd|t|f|j ||||d} | dkrtd|| fS|dk} | rV|r t |} | | |} | st tt|| } | | |}dd |D} t| d kst| d}nLt |}|s.td|t|ftt|d krJt d |d}|}|j |dkrn||n|d ||f||d } | dkr| rtd|t|fntd|| fS|d\}}}|sd}|||fS)aX Parse downgrade command syntax :target to retrieve the target revision and branch label (if any) given the :current_revisions stamp of the database. Returns a tuple (branch_label, target_revision) where branch_label is a string from the command specifying the branch to consider (or None if no branch given), and target_revision is a Revision object which the command refers to. target_revisions is None if the command refers to 'base'. The target may be specified in absolute form, or relative to :current_revisions. N)NNz(Expected downgrade target in string formr1Relative revision %s didn't produce %d migrations)rzWalked too farcSsg|]}|r|jn|qSrrbrrrr/rsz7RevisionMap._parse_downgrade_target..rzadowngrade -1 from multiple heads is ambiguous; this usage will be disallowed in a future release.%s@%srrrr)rrFr_relative_destinationmatchgroupsrr4r rrrrrrr_get_all_currentrrirkr rpartition)r.rrr+rrsymbolrelativeZrel_intreZrelative_revisionZcr_tupleZ symbol_listZ all_currentZsl_all_currentr rrr/_parse_downgrade_targetEs         z#RevisionMap._parse_downgrade_targetc Cst|trt|}nd}|s(||St|}|\}}}t|} | dkr,|dkr|sdd}|} |r| |||} | s| | |||} t dd| Ddd| D} | sd} t | dkrt d|j| d| ||d } | dkr t d |t| f| fS|j||| ||d fSnR|dkrJt d | t| f|j|dkrb||n|d ||f| |d fSdS) aJ Parse upgrade command syntax :target to retrieve the target revision and given the :current_revisions stamp of the database. Returns a tuple of Revision objects which should be iterated/upgraded to. The target may be specified in absolute form, or relative to :current_revisions. Nrr-cSsh|] }|jqSrrbrcrrr/rsz4RevisionMap._parse_upgrade_target..cSsh|]}|jD]}|qqSrr)rdreZdownrrr/rsrz1Ambiguous upgrade from multiple current revisions)rrrrrrr)rrFrrrrrrrrrr{rr4rr r) r.rrr+rZcurrent_revisions_tuprrZ relative_strrZ start_revsZactive_on_branchrerrr/_parse_upgrade_targets             z!RevisionMap._parse_upgrade_targetr%r&c Cs`|j|||d\}}|dkr d}|dks6t|ts6t|dkrTdd|jD}n"|r`|g}ndd||jD}|rt|dkrdd |j | |gd d D} d d|d d |D | D}t|dkrt d||} t |j|dd d} t |j | dd } | | |r4| | | ||dk rX| sX|| krXtd|| | fS)a Compute the set of current revisions specified by :upper, and the downgrade target specified by :target. Return all dependents of target which are currently active. :inclusive=True includes the target revision in the set rrr+r7NcSs"g|]}|dk r|jdkr|qSr-rrcrrr/rHs z.cSsg|] }t|qSrr rcrrr/rRsrcSsh|] }|jqSrrbrcrrr/rYsz;RevisionMap._collect_downgrade_revisions..FrcSsg|] }t|qSrr rcrrr/rbscSsh|] }|jqSrrbrcrrr/resrz/Not a valid downgrade target from current headsT)rrzNothing to drop)rrrrrZrrrrrrrrr4ririntersection_updaterrr5) r.r'r(r)r*r+rZtarget_revisionrootsrrAZdowngrade_revisionsZactive_revisionsrrr/r+sr         z(RevisionMap._collect_downgrade_revisionsz*Tuple[Set[Revision], Tuple[Revision, ...]]csdd|j|||dD}t|trd|kr|d\}}|}|dk rx|jkrxt|jdksjtt t |jfdd|D}t |j |d d d  |||} |stfd d | Drt||t| tkstd | r:| ddkr:|j|||d\}} | st| dkr.t} d}n | f} | j}t |j | d d d  | } | } |r~| dd ||D| r|s|jdd| Dd dd } | | | t|fS)a Compute the set of required revisions specified by :upper, and the current set of active revisions specified by :lower. Find the difference between the two to compute the required upgrades. :inclusive=True includes the current/lower revisions in the set :implicit_base=False only returns revisions which are downstream of the current/lower revisions. Dependencies from branches with different bases will not be included. cSsg|] }t|qSrr rcrrr/rsz:RevisionMap._collect_upgrade_revisions..rrNrcsh|]}|jkr|qSr)rl)rdZneed)branchrr/rs z9RevisionMap._collect_upgrade_revisions..T)rrc3s|]}|dk r|kVqdSr-rrc)required_node_setrr/rfsz9RevisionMap._collect_upgrade_revisions..z#current_revisions should be a tuplerr7css|]}t|VqdSr-r rcrrr/rfscSsg|] }t|qSrr rcrrr/rsF)rrrF partitionrrRrrlrnextiterrirrranyr5typer{rrrrr)r.r'r(r)r*r+rr rrreZcurrent_node_setZneedsZlower_descendentsr)r!r"r/rs             z&RevisionMap._collect_upgrade_revisionscCs0t||}||jt|dd||S)NTr)rirrrrr)r.rZtop_revsrrr/rs zRevisionMap._get_all_current)F)N)N)F)F)FFTF)NFFT)NFT)F)NT)'r1r2r3__doc__r9rZmemoized_propertyrAr\r]r^rZrxrpr|rqrwrrrrrrrrrrrrrrrrrrrrrrrrrr/rU~sr     K4(9$1B(,(!2l?xngerUc@sleZdZUdZeZded<eZded<dZded<dZ ded <dZ ded <dZ d ed <d ed<d ed<e dddddZ d2ddddddddZddddZdddddZed dddZed ddd Zed dd!d"Zed#dd$d%Zed#dd&d'Zed#dd(d)Zed#dd*d+Zed#dd,d-Zed#dd.d/Zed#dd0d1ZdS)3raoBase class for revisioned objects. The :class:`.Revision` class is the base of the more public-facing :class:`.Script` object, which represents a migration script. The mechanics of revision management and traversal are encapsulated within :class:`.Revision`, while :class:`.Script` applies this logic to Python files in a version directory. zFrozenSet[str]rrNrFrRzOptional[_RevIdType]rrrrlrXrrr6rQcCs0t|t}|r,tddt||fdS)Nz9Character(s) '%s' not allowed in revision identifier '%s'rC)rir_revision_illegal_charsr4rDr)clsrRZ illegal_charsrrr/ verify_rev_id.szRevision.verify_rev_idz%Optional[Union[str, Tuple[str, ...]]])rRrrrlr,cCs|r|t|krt|n|dk r:|t|kr:t|||||_tt||_tt||_tj|dd|_ t |j |_ dSNrr) rrrPrTr+rRtuple_rev_as_scalarrrrrirl)r.rRrrrlrrr/r97s  zRevision.__init__rYcCsZt|jt|jg}|jr,|d|jf|jrD|d|jfd|jjd|fS)Nzdependencies=%rzbranch_labels=%rz%s(%s)rC) reprrRrrrrlr;r1rD)r.argsrrr/__repr__Ls zRevision.__repr__cCs4|j|jg|_|j|jkr0|j|jg|_dSr-)rrrRrurrSrrr/rtTs zRevision.add_nextrevcCsttj|jdd|jSr,)r dedupe_tuplerrrr[rrr/rsYs zRevision._all_down_revisionscCsttj|jdd|jS)z|return immediate down revisions for a rev, omitting dependencies that are still dependencies of ancestors. rr)rr1rrrr[rrr/r`s z#Revision._normalized_down_revisionscCstj|jddSr,)rrrr[rrr/ruksz"Revision._versioned_down_revisionsr$cCs t|j S)aReturn True if this :class:`.Revision` is a 'head' revision. This is determined based on whether any other :class:`.Script` within the :class:`.ScriptDirectory` refers to this :class:`.Script`. Multiple heads can be present. )r$rr[rrr/ros zRevision.is_headcCs t|j Sr-)r$rr[rrr/rzszRevision._is_real_headcCs |jdkS)zrErHrNrPrTrUrr-rrrrr/s                                 (