U of9@s0ddlmZddlmZddlZddlZddlZddlZddlZddl m Z ddl m Z ddl m Z ddl mZddl mZdd l mZdd l mZdd l mZdd l mZdd l mZddl mZddl mZddlmZddlmZddlmZddlmZddlmZddlmZerrddlmZddlm Z ddlm!Z!ddl"m#Z#ddl"m$Z$ddl%m&Z&ddl%m'Z'z>ej(rddl)m*Z*dd l)m+Z+nddl,m*Z*dd l,m+Z+Wne-k rdZ*YnXe.d!Z/e.d"Z0e.d#Z1e.d$Z2d%Z3e.d&Z4e.d'Z5Gd(d)d)Z6Gd*d+d+ej!Z7dS),) annotations)contextmanagerN) ModuleType)Any)cast)Iterator)List)Mapping)Optional)Sequence)Set)Tuple) TYPE_CHECKING)Unionrevision) write_hooks)util) migration)compat)not_none) _GetRevArg) _RevIdType)Revision)Config)MessagingOptions) RevisionStep) StampStep)ZoneInfo)ZoneInfoNotFoundErrorz (?!\.\#|__init__)(.*\.py)(c|o)?$z(?!\.\#|__init__)(.*\.py)$z([a-f0-9]+)\.py$z\w+z%(rev)s_%(slug)sz , *|(?: +)z , *|(?: +)|\:c @s$eZdZdZedddddddedejf dddd d dd d d dd d ddZe ddddZ ej ddddZ ddddZ edddddZedhd d d d d ddd d!Zdidddd$d%d&Zd'd(d)d*d+Zd,d-d)d.d/Zdd0d)d1d2Zd d3d)d4d5Zd6d6d7dd8d9d:Zd dd;d<Zd=dd>d?Zd dd@dAZd=ddBdCZdddDdEdFdGZdd dDdEdHdIZdJdJdKdLdMdNZd ddOdPZe dddQdRZ ddd7d dSdTdUZ!ddd dVdWdXZ"dd dYdZd[Z#d\dd]d^Z$djdd d_d`d_d d_d7dadb dcddZ%ddd d\ddedfdgZ&dS)kScriptDirectoryaHProvides operations upon an Alembic script directory. This object is useful to get information as to current revisions, most notably being able to get at the "head" revision, for schemes that want to test if the current revision in the database is the most recent:: from alembic.script import ScriptDirectory from alembic.config import Config config = Config() config.set_main_option("script_location", "myapp:migrations") script = ScriptDirectory.from_config(config) head_revision = script.get_current_head() (NFutf-8rstrz Optional[int]zOptional[List[str]]boolz Optional[str]zOptional[Mapping[str, str]]None) dir file_templatetruncate_slug_lengthversion_locations sourcelessoutput_encodingtimezone hook_configrecursive_version_locationsmessaging_optsreturnc Csv||_||_||_|pd|_||_||_t|j|_ ||_ ||_ | |_ | |_ t|tjsrtdtj|dS)Nr#zVPath doesn't exist: %r. Please use the 'init' command to create a new scripts folder.)r(r)r+r*r,r-rZ RevisionMap_load_revisions revision_mapr.r/r0r1osaccessF_OKr CommandErrorpathabspath) selfr(r)r*r+r,r-r.r/r0r1r<A/opt/hc_python/lib/python3.8/site-packages/alembic/script/base.py__init__Ns"  zScriptDirectory.__init__r2cCs*|j}t|dkrtdn|dSdS)Nrz"Multiple version_locations presentr)_version_locationslenrr8)r;locr<r<r=versionsps  zScriptDirectory.versionsz Sequence[str]cCs4|jrdd|jDStjtj|jdfSdS)NcSsg|]}tjt|qSr<)r5r9r:rcoerce_resource_to_filename).0locationr<r<r= {sz6ScriptDirectory._version_locations..rC)r+r5r9r:joinr(r;r<r<r=r@xs z"ScriptDirectory._version_locationszIterator[Script]c cs|jrdd|jD}n|jg}t}|D]z}t||D]h}tj|}||krbt d|q:| |tj |}tj |}t|||}|dkrq:|Vq:q*dS)NcSsg|]}tj|r|qSr<)r5r9exists)rEversr<r<r=rGs z3ScriptDirectory._load_revisions..zJFile %s loaded twice! ignoring. Please ensure version_locations is unique.)r+r@rCsetScript _list_py_dirr5r9realpathrwarnaddbasenamedirname_from_filename) r;pathsZdupesrK file_path real_pathfilenamedir_namescriptr<r<r=r3s.    zScriptDirectory._load_revisionsr)configr2c CsR|d}|dkrtd|d}|dk r8t|}nd}|d}|r|d}ddtjdd d }z ||}Wn0tk r} ztd || W5d} ~ XYqX|dkrt |} qd d | |D} nd} |d} | rt t | t j dd<|ddk} tt||dt||ddk|dd| |d|di| |jd S)zProduce a new :class:`.ScriptDirectory` given a :class:`.Config` instance. The :class:`.Config` need only have the ``script_location`` key present. script_locationNz0No 'script_location' key found in configuration.r*r+version_path_separator :;)Nspacer5r_r`zV'%s' is not a valid value for version_path_separator; expected 'space', 'os', ':', ';'cSsg|] }|r|qSr<r<)rExr<r<r=rGsz/ScriptDirectory.from_config..prepend_sys_pathrr0truer)r,r-r$r.post_write_hooks) r)r*r,r-r+r.r/r0r1)Zget_main_optionrr8intr5pathsepKeyError ValueError_split_on_space_commasplitlist_split_on_space_comma_colonsysr9r"rD_default_file_templateZ get_sectionr1) clsr[r\Ztslr*Zversion_locations_strr]Z split_on_pathZ split_charZker+rcZrvlr<r<r= from_configsz        zScriptDirectory.from_configzIterator[None])ancestormultiple_headsstartend resolutionr2c csJz dVWn8tjk rz}zN|dkr4tt|j}|dkrHtt|j}|sPd}|||d}t||W5d}~XYntjk r}z4|sd}||p|j t |j d}t||W5d}~XYnztj k r}z"|dkrd|j }t||W5d}~XYn8tj k rD} zt| jd| W5d} ~ XYnXdS)NzgRequested range %(start)s:%(end)s does not refer to ancestor/descendant revisions along the same branchrtruzMultiple head revisions are present for given argument '%(head_arg)s'; please specify a specific target revision, '@%(head_arg)s' to narrow to a specific head, or 'heads' for all heads)Zhead_argheadsz(Can't locate revision identified by '%s'r)rZRangeNotAncestorErrorrrlowerupperrr8Z MultipleHeadsargumentformat_as_commarxResolutionError RevisionErrorargs) r;rrrsrtrurvZrnamhreerrr<r<r=_catch_revision_errorss:     z&ScriptDirectory._catch_revision_errorsbaserx)rheadr2c csD|j||d,|jj||dddD]}tt|Vq$W5QRXdS)a-Iterate through all revisions. :param base: the base revision, or "base" to start from the empty revision. :param head: the head revision; defaults to "heads" to indicate all head revisions. May also be "head" to indicate a single head revision. rwTF)Z inclusiveZassert_relative_lengthN)rr4iterate_revisionsrrM)r;rrrevr<r<r=walk_revisionss  zScriptDirectory.walk_revisionsrzTuple[Script, ...])id_r2c Cs:|(tttdf|j|W5QRSQRXdS)zReturn the :class:`.Script` instance with the given rev identifier, symbolic name, or sequence of identifiers. .N)rrr rMr4 get_revisionsr;rr<r<r=r1s    zScriptDirectory.get_revisionszTuple[str, ...]z Set[Script]c Cs6|$ttt|j|W5QRSQRXdSN)rrr rMr4Z_get_all_currentrr<r<r=get_all_current<s zScriptDirectory.get_all_currentrMc Cs2| tt|j|W5QRSQRXdS)zReturn the :class:`.Script` instance with the given rev id. .. seealso:: :meth:`.ScriptDirectory.get_revisions` N)rrrMr4 get_revisionrr<r<r=r@s zScriptDirectory.get_revisionz%Optional[Union[str, Tuple[str, ...]]]c CsD||j|\}}W5QRX|s,dS|dkr8|S|dSdS)z[Convert a symbolic revision, i.e. 'head' or 'base', into an actual revision number.Nrxr)rr4Z_resolve_revision_number)r;rr branch_namer<r<r=as_revision_numberLs z"ScriptDirectory.as_revision_numberz!Union[str, Tuple[str, ...], None]r)rzrykwr2cKsttt|jj||f|S)aIterate 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:`.Script` objects. .. seealso:: :meth:`.RevisionMap.iterate_revisions` )rrrMr4r)r;rzryrr<r<r=r]sz!ScriptDirectory.iterate_revisionsc Cs.|jdd|jW5QRSQRXdS)aGReturn 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. :return: a string revision number. .. seealso:: :meth:`.ScriptDirectory.get_heads` z}The script directory has multiple heads (due to branching).Please use get_heads(), or merge the branches using alembic merge.rsN)rr4get_current_headrIr<r<r=rwsz ScriptDirectory.get_current_head List[str]cCs t|jjS)aUReturn all "versioned head" revisions as strings. This is normally a list of length one, unless branches are present. The :meth:`.ScriptDirectory.get_current_head()` method can be used normally when a script directory has only one head. :return: a tuple of string revision numbers. )rlr4rxrIr<r<r= get_headss zScriptDirectory.get_headscCs4|}t|dkr tdn|r,|dSdSdS)a#Return the "base" revision as a string. This is the revision number of the script that has a ``down_revision`` of None. If the script directory has multiple bases, an error is raised; :meth:`.ScriptDirectory.get_bases` should be preferred. rz@The script directory has multiple bases. Please use get_bases().rN) get_basesrArr8)r;basesr<r<r=get_bases  zScriptDirectory.get_basecCs t|jjS)zreturn all "base" revisions as strings. This is the revision number of all scripts that have a ``down_revision`` of None. )rlr4rrIr<r<r=rszScriptDirectory.get_baseszList[RevisionStep]) destination current_revr2c sPjd|d8j||dd}fddtt|DW5QRSQRXdS)NzFDestination %(end)s is not a valid upgrade target from current head(s)rrruT)Z implicit_basecsg|]}tjj|qSr<)r MigrationStepZupgrade_from_scriptr4rErZrIr<r=rGs z1ScriptDirectory._upgrade_revs..)rrreversedrlr;rrrevsr<rIr= _upgrade_revss  zScriptDirectory._upgrade_revsc sHjd|d0j||dd}fdd|DW5QRSQRXdS)NzHDestination %(end)s is not a valid downgrade target from current head(s)rT)Zselect_for_downgradecsg|]}tjj|qSr<)rrZdowngrade_from_scriptr4rrIr<r=rGs z3ScriptDirectory._downgrade_revs..)rrrr<rIr=_downgrade_revss zScriptDirectory._downgrade_revsrzList[StampStep])rrxr2c sjdd|}g}|s&d}g}t|D]*}|r4|jjttt ||ddq4t |}|pxdg}|D]}|dkr|fdd|Dq~n ||krq~t j |g} t j |g} | |r"| |rtdd|D} t| |jd d j} || q~q~| |r`d d|D} t| |jdd j} || q~q~td |jddj} || q~q~|W5QRSQRXdS) NzCMultiple heads are present; please specify a single target revisionrrT)Zinclude_dependenciesc s"g|]}t|jdddjqS)NFT)rrrr4rErrIr<r=rGsz/ScriptDirectory._stamp_revs..cSsg|] }|jqSr<rrr<r<r=rGsFcSsg|] }|jqSr<rrr<r<r=rG(sr<)rrrto_tupleextendr4Zfilter_for_lineagerr rMZ unique_listrLZ_get_descendant_nodesZ_get_ancestor_nodes intersectionAssertionErrorrrrappend) r;rrxZ heads_revsZstepsZfiltered_headsrZdestsdestZ descendantsZ ancestorsZ todo_headsstepr<rIr= _stamp_revss             zScriptDirectory._stamp_revscCst|jddS)zRun the script environment. This basically runs the ``env.py`` script present in the migration environment. It is called exclusively by the command functions in :mod:`alembic.command`. env.pyN)rload_python_filer(rIr<r<r=run_env=s zScriptDirectory.run_envcCstjtj|jdS)Nr)r5r9r:rHr(rIr<r<r=env_py_locationHszScriptDirectory.env_py_location)srcrrr2c KsBtjdtj|f|jtj|||jf|W5QRXdSNz Generating )rstatusr5r9r:r1Ztemplate_to_filer-)r;rrrr<r<r=_generate_templateLs z"ScriptDirectory._generate_template)rrr2c Cs:tjdtj|f|jt||W5QRXdSr)rrr5r9r:r1shutilcopy)r;rrr<r<r= _copy_fileRs zScriptDirectory._copy_file)r9r2c CsHtj|}tj|sDtjd|f|jt|W5QRXdS)NzCreating directory )r5r9r:rJrrr1makedirs)r;r9r<r<r=_ensure_directoryXs  z!ScriptDirectory._ensure_directoryzdatetime.datetimecCs|jdk rtdkrtdzt|j}Wntk rBd}YnX|dkrzt|j}Wn&tk rtd|jdYnXtjjtjj d |}n tj }|S)NzePython >= 3.9 is required for timezone support or the 'backports.zoneinfo' package must be installed.zCan't locate timezone: %s)tzinfo) r.r rr8r!rzdatetimeutcnowreplaceutc astimezonenow)r;r create_dater<r<r=_generate_create_date`s4    z%ScriptDirectory._generate_create_datezOptional[_RevIdType]Optional[bool]Optional[Script]) revidmessagersplice branch_labels version_path depends_onrr2c s|dkr d}zt|Wn6tjk rP} zt| jd| W5d} ~ XYnXjdd:tt t ddfj |} | D]} | dkst qW5QRXtt| t| krtd } |dkr$tjd kr| D].} | dk rt| tst tj| j}q$qtd nj}tjtj|}jD]}tj||kr>qlq>td |jr~||||| }|s| D](} | dk r| jstd | jq|r(ddfddt|DD}W5QRXnd}jtjj d|ft!|t"t#dd| Dt$|t"|| tj%|dk rZ|ndd|j&}|rt'(||zt)|}Wn8tjk r} zt| jd| W5d} ~ XYnX|dkrdS|r|j*std|j||jfj +||S)aGenerate a new revision file. This runs the ``script.py.mako`` template, given template arguments, and creates a new file. :param revid: String revision id. Typically this comes from ``alembic.util.rev_id()``. :param message: the revision message, the one passed by the -m argument to the ``revision`` command. :param head: the head revision to generate against. Defaults to the current "head" if no branches are present, else raises an exception. :param splice: if True, allow the "head" version to not be an actual head; otherwise, the selected head must be a head (e.g. endpoint) revision. Nrrz{Multiple heads are present; please specify the head revision on which the new revision should be based, or perform a merge.rr.rz"Duplicate head revisions specifiedrzAMultiple version locations present, please specify --version-pathz7Path %s is not represented in current version locationszeRevision %s is not a head revision; please specify --splice to create a new branch from this revisioncSs$g|]\}}||jkr|n|jqSr<)rr)rErdepr<r<r=rGsz5ScriptDirectory.generate_revision..cs g|]}tj||fqSr<)rr4r)rErrIr<r=rGszscript.py.makocss |]}|dk r|jndVqdSrr)rEhr<r<r= sz4ScriptDirectory.generate_revision..z empty message)Z up_revision down_revisionrrrcommarzVersion %s specified branch_labels %s, however the migration file %s does not have them; have you upgraded your script.py.mako to include the 'branch_labels' section?),rMZ verify_rev_idrr~rr8rrrr r r4rrrArLrr@ isinstancer5r9rSrCnormpathr:r+r _rev_pathis_headZto_listrrHr(r%Ztuple_rev_as_scalartuplerr|r/rZ _run_hooks _from_pathrZ add_revision)r;rrrrrrrrrrxrrZhead_Z norm_pathZ vers_pathr9Zresolved_depends_onrerZr<rIr=generate_revision|s$           $   z!ScriptDirectory.generate_revision)r9rev_idrrr2c Cst|}dt|pd}t||jkrP|d|jdddd}d|j ||||j |j |j |j |j|jd }tj||S)N_rrz%s.py) rslugepochyearmonthdayhourminutesecond)rf timestamprH_slug_refindallryrAr*rsplitr)rrrrrrr5r9)r;r9rrrrrrXr<r<r=rs& zScriptDirectory._rev_path)NNNNN)rrx)NFNNN)'__name__ __module__ __qualname____doc__rorr EMPTY_DICTr>propertyrCZmemoized_propertyr@r3 classmethodrqrrrrrrrrrrrrrrrrrrrrrrrr<r<r<r=r":st$" P.    ^   r"cseZdZUdZddddfdd Zded<ded<d Zd ed <edd d dZedd ddZ edd ddZ dd ddZ d+dddddddddZ d,dddddddddZ dd ddZed dd!d"d#d$Zed dd%d"d&d'Zed ddd!d(d)d*ZZS)-rMzRepresent a single revision file in a ``versions/`` directory. The :class:`.Script` instance is returned by methods such as :meth:`.ScriptDirectory.iterate_revisions`. rr%)modulerr9c sJ||_||_tj||jtjt|ddddtjt|ddddddS)Nrr<)defaultr)r dependencies)rr9superr>rrrgetattr)r;rrr9 __class__r<r=r>3s  zScript.__init__rr9Nr_db_current_indicatorr?cCstd|jdS))Return the docstring given in the script.z r)rrklongdocrIr<r<r=docKsz Script.doccCs6|jj}|r.t|jdr&||jj}|SdSdS)r_alembic_source_encodingrN)rrhasattrdecoderstrip)r;rr<r<r=rQs zScript.longdoccCsd|j|jrdnd|jrdnd|jr(dnd|jr4dndf}|jrV|d|f7}n|d|f7}|jr|d t|j7}|jr|d t|j 7}|j r|d t|j f7}|d |j f7}|d d dd|j D7}|S)NzRev: %s%s%s%s%s  (head)r (branchpoint) (mergepoint) (current)z Merges: %s z Parent: %s zAlso depends on: %s zBranches into: %s zBranch names: %s z Path: %s z %s  css|]}d|VqdS)z %sNr<)rEparar<r<r=rsz#Script.log_entry..)rris_branch_pointis_merge_pointr_format_down_revisionrrr|Znextrevrr9rHr splitlines)r;entryr<r<r= log_entry_s6       zScript.log_entrycCs:d||j|jrdnd|jr"dnd|jr.dnd|jfS)Nz%s -> %s%s%s%s, %srrrr)rrrrrrrIr<r<r=__str__s   zScript.__str__FTr&)include_branches include_docinclude_parentstree_indicatorshead_indicatorsr2cCs|j}|r<|jr,d|t|j|f}nd||f}|dk sHt|rf|jrf|dt|j7}|sn|r|d|jr|dnd|jr|jsdnd|j rdndf7}|r|d |j rd nd|j rd ndf7}|r|d |j 7}|S) Nz %s (%s) -> %sz%s -> %sz (%s)z%s%s%srrz (effective head)rz%s%srrz, %s) rrrrr|rrZ _is_real_headrrrrr)r;rr r r r textr<r<r= _head_onlys<        zScript._head_only)verboserr r r r2cCs|r |jS|||||SdSr)rr)r;rrr r r r<r<r= cmd_formatszScript.cmd_formatcCs|js dSt|jSdS)Nz)rrr|Z_versioned_down_revisionsrIr<r<r=rszScript._format_down_revisionr"r) scriptdirr9r2cCstj|\}}||||Sr)r5r9rkrT)rprr9dir_rXr<r<r=rszScript._from_pathrcsg}tj|ddD]\}}}|dr(qt|D]}|tj||q0|jrtj|dtjrdd|D| fddt D|j sq| q|S)NT)topdown __pycache__cSsh|]}|ddqS).r)rk)rErXr<r<r= sz&Script._list_py_dir..c3s.|]&}|ddkrtj|VqdS)rrN)rkr5r9rH)rEZpycnamesZ py_cache_pathr<r=rsz&Script._list_py_dir..) r5walkendswithsortedrr9rHr,rJrlistdirr0sort)rprr9rUrootdirsfilesrXr<rr=rNs"    zScript._list_py_dir)rrrXr2c Cs|jrt|}n t|}|s$dS|d}|jrR|ddk}|ddk}nd}}|sb|rtjtj||}tjtj||d} |s|r| rdSt ||} t | dst |} | st d|q| d} n| j} t| | tj||S)NrrcoFrzCould not determine revision id from filename %s. Be sure the 'revision' variable is declared inside the script (please see 'Upgrading from Alembic 0.1 to 0.2' in the documentation).)r,_sourceless_rev_filematch_only_source_rev_filegroupr5r9rJrHrrr _legacy_revr8rrM) rprrrXZpy_matchZ py_filenameZis_cZis_oZ py_existsZ pyc_existsrmrr<r<r=rTs6        zScript._from_filename)FFFTT)FFFT)rrrrr>__annotations__rrrrrrrrrrrrNrT __classcell__r<r<rr=rM+s<   # +$rM)8 __future__r contextlibrrr5rrrntypesrtypingrrrrr r r r r rrrrrrruntimerrrrrrr[rrZruntime.migrationrrZpy39Zzoneinfor r!Zbackports.zoneinfo ImportErrorcompiler#r%r'rrorjrmr"rMr<r<r<r=sl                                    v