'L idZddlmZddlZddlmZddlmZddlmZddlmZddl Z ddl m Z ddl Z ddl Z dd l mZddlZddlZdd lmZddlZddlZddlZddlZddlZddlZdd lmZdd lmZdd lmZddlmZddlmZddlmZddlm Z ddlm!Z!ddl"m#Z#ddl$m%Z%ddl$m&Z&ddl'm(Z(ddl)m*Z*ddl+m,Z,ddl-m.Z.ddl-m/Z/ddl0m1Z1ddl0m2Z2ddl0m3Z3ddl0m4Z4ddl0m5Z5dd l0m6Z6dd!l7m8Z8dd"l9m:Z:dd#l;mm?Z?dd&l@mAZAdd'lBmCZCdd(lBmDZDdd)lEmFZFdd*lEmGZGdd+lEmHZHdd,lImJZJdd-lImKZKdd.lLmMZMdd/lLmNZNdd0lOmPZPdd1lQmRZRe!rddlSZSd2gZTd3gZUdTd4ZVdUd5ZWGd6d7ZXed?Z\eeZdZddZddZeddd dZy) rIc (tjdk\rtj}ntjd}t j dddttjft jt jdd|j}dd}g}|jd D]Z}||s |jd }|d d d}|d d d}|tvr6|jd sH|j!||f\|S)N) Fr5z-Ffn0-pT)stdoutstderrchecktextencodingcT|jdxrd|vxrd|vxr d|vxrd|vS)Nfdeletedmemtxtcwd startswith)lines rCisopenz0LsofFdLeakChecker.get_open_files..isopensI??3'%&%&%&%  rE r/)rcstrreturnbool)sys version_infolocale getencodinggetpreferredencodingr=runriosgetpidPIPEDEVNULLrVsplit IGNORE_PAMrbappend) selfrZoutrd open_filesrcfieldsfdfilenames rCget_open_filesz LsofFdLeakChecker.get_open_fileszs   w &))+H2259Hnn WdC $4 5??%%   &   IIdO 6Dd|D)AYqr]!!9QR=z)&&s+%%r8n5 6rEcr tjddy#ttjf$rYywxYw)N)r5z-vT)rXF)r=rqOSErrorCalledProcessErrorrys rCrJz#LsofFdLeakChecker.matching_platforms9  NN> 6667  s 66T)wrappertryfirstc #\K|j} dttdrtj|j}|Dchc]}|d c}|Dchc]}|d c}z }|Dcgc] }|d|vs |}}|rdt |dgd|Ddd|Ddd |Ddt |dd j |jd }|jtd j|SScc}wcc}wcc}w#ttdrtj|j}|Dchc]}|d ncc}wc}|Dchc]}|d ncc}wc}z }|Dcgc] }|d|vs |ncc}w}}|rdt |dgd|Ddd|Ddd |Ddt |dd j |jd }|jtd j|wwxYww) Npypy_version_inforz***** z FD leakage detectedc32K|]}t|ywNri.0r\s rC z.s3c!f3z *** Before:c32K|]}t|ywrrrs rCrz.-c!f-rz *** After:c32K|]}t|ywrrrs rCrz.rrz*** function {}:{}: {} zSee issue #2366re) rhasattrrlgccollectlenformatlocationwarnr1join)ryitemlines1lines2tnew_fds leaked_fileserrors rCpytest_runtest_protocolz)LsofFdLeakChecker.pytest_runtest_protocols{$$& =s/0 ((*F%+,qt,f/E!/EEG'-A!1AALAS.//CD 3l3 " .f-  !  .f- S.//CD 5-44dmmD &  /$))E*:;<-/EA s/0 ((*F%+,qt,,f/E!/E/EEG'-A!1AAALAS.//CD 3l3 " .f-  !  .f- S.//CD 5-44dmmD &  /$))E*:;<sqH,D8H, DH,! D- H,6 DDBH,9H) E$# H)/ E< ;H) FFBH))H,N)rjzlist[tuple[str, str]])rjrk)rr(rjzGenerator[None, object, object])__name__ __module__ __qualname__rrJrrrErCrIrIys(#JdT*=+=rErI PytestArgct|S)zReturn a helper which offers a gethookrecorder(hook) method which returns a HookRecorder instance which helps to make assertions about called hooks.)rrequests rC_pytestrs W rEceZdZddZddZy)rc||_yr)_request)ryrs rC__init__zPytestArg.__init__s  rEczt|j}|jj|j|Sr) HookRecorder_pmr addfinalizerfinish_recording)ryhook hookrecorders rCgethookrecorderzPytestArg.gethookrecorders.#DHH-  ""<#@#@ArEN)rr$rjNone)rjr)rrrrrrrErCrrs  rEc>|Dcgc] }|ddk7s |c}Scc}w)zDOnly return names from iterator values without a leading underscore.r_r)valuesxs rCget_public_namesrs  -!1A -- -s c.eZdZdZddZddZerddZyy) RecordedHookCalla;A recorded call to a hook. The arguments to the hook call are set as attributes. For example: .. code-block:: python calls = hook_recorder.getcalls("pytest_runtest_setup") # Suppose pytest_runtest_setup was called once with `item=an_item`. assert calls[0].item is an_item cH|jj|||_yr)__dict__update_name)rynamekwargss rCrzRecordedHookCall.__init__s V$ rEcb|jj}|d=d|jd|dS)Nrz)rcopyr)ryds rC__repr__zRecordedHookCall.__repr__s4 MM    gJ#DJJ>QE<.before s JJ  .y&A BrEcyrr)outcomerrrs rCafterz$HookRecorder.__init__..afters rE)rrirjr)r"_pluginmanagerrretadd_hookcall_monitoring_undo_wrapping)ryrKrrrs` rCrzHookRecorder.__init__sE y!+-/ *. C ,CCFERrEc$|jyr)rrs rCrzHookRecorder.finish_recordings rEct|tr|j}|jDcgc]}|j|vs|c}Scc}w)z?Get all recorded calls to hooks with the given names (or name).) isinstancerirvrr)rynamescalls rCgetcallszHookRecorder.getcallss: eS !KKME!%CtzzU/BCCCs A A cd}d}t|}ttjdj}|r|j d\}}t |j|dD]\}}|j|k(r^td||t|||jrtdt|d|ntdt|d|i||dzz }n!td |d |td |d ||ryy) NTrrg NAMEMATCH CHECKERMATCHz->NOCHECKERMATCH- NONAMEMATCHwithzcould not find z check )listdictrl _getframef_localspop enumeraterrprintevalrreprr)) ryentries__tracebackhide__i backlocalsrrXindrs rCassert_containszHookRecorder.assert_containss  w-#--*334 !++a.KD%&tzz!"~6 A T::%+tT2E:t}}=nd5k4F.U S$G qLAmT648 AthgeY?@rEc&d}t|jD]%\}}|j|k(s|j|=|cSd|dg}|j|jDcgc]}d| c}t dj |ycc}w)NTzcould not find call z, in:z re)rrrextendr)r)ryrrrrlinesrs rCpopcallzHookRecorder.popcall2s  , GAtzzT!JJqM  (xu56  311#h34 TYYu 4s Bc\|j|}t|dk(s J||f|dS)Nrgr)rr)ryrrs rCgetcallzHookRecorder.getcall<s5t$6{a/$/ayrEcyrrryrs rC getreportszHookRecorder.getreportsC#&rEcyrrrs rCrzHookRecorder.getreportsI #rEcyrrrs rCrzHookRecorder.getreportsO03rEc^|j|Dcgc]}|jc}Scc}wr)rreport)ryrrs rCrzHookRecorder.getreportsXs%#'--"67Q777s*Nc`g}|j|D]c}|s|jdk7r |jr!|r|j|k7r3|r||jj dvsS|j |e|st d|dt|dkDrt d|d||d S) z5Return a testreport whose dotted import path matches.)rr::z$could not find test report matching z: no test reports at all!rgz%found 2 or more testreports matching : r)rwhenpassednodeidrvrx ValueErrorr)ry inamepartrr rreps rC matchreportzHookRecorder.matchreportas???/ #CCHH.3::D( SZZ-=-=d-C C c" #6ymD**  v;?7 }BvhO ayrEcyrrrs rC getfailureszHookRecorder.getfailuresrrEcyrrrs rCrzHookRecorder.getfailuresrrEcyrrrs rCrzHookRecorder.getfailuresrrEcd|j|Dcgc]}|js|c}Scc}wr)rfailed)ryrrs rCrzHookRecorder.getfailuress' $u5DDDDs--c$|jdS)Npytest_collectreport)rrs rCgetfailedcollectionsz!HookRecorder.getfailedcollectionss 677rEcNg}g}g}|jdD]}|jr4|jdk(st|tsJ|j |C|j r|j |a|js Jd||j ||||fS)Nrpytest_runtest_logreportrzUnexpected outcome: )rrr rr/rxskippedr)ryrr rrs rC listoutcomeszHookRecorder.listoutcomess?? @ #Czz88v%%c:666MM#&s#zzA%9##AAz c" #w&&rEcZ|jDcgc] }t|c}Scc}wr)r!r)ryrs rC countoutcomeszHookRecorder.countoutcomess# $ 1 1 341A444s(cLd}ddlm}|j}|||||y)NTr) assertoutcome)rr r)_pytest.pytester_assertionsr%r!)ryrr rrr%outcomess rCr%zHookRecorder.assertoutcomes- =$$&   rEc"g|jddyr)rrs rCclearzHookRecorder.clears 1 rE)rKr rrkrjrrjr)rstr | Iterable[str]rjzlist[RecordedHookCall])rzSequence[tuple[str, str]]rjr)rrirjr)rzLiteral['pytest_collectreport']rjSequence[CollectReport])rz#Literal['pytest_runtest_logreport']rjzSequence[TestReport])r)rr+rjz$Sequence[CollectReport | TestReport]))rrN)rrirr+r  str | NonerjzCollectReport | TestReport)rjr,)rjzgtuple[Sequence[TestReport], Sequence[CollectReport | TestReport], Sequence[CollectReport | TestReport]])rjz list[int])rrr)rintr r/rr/rjr)rrrrrrrrrrrrrrrr!r#r%r)rrErCrrsHMS0S@DS S"D A,&.& !&& #2# ## & 3"3 . 33& 8"8 . 8&  # $<&.& !&& #2# ## & 3"3 . 33& E"E . E8' '05  rErLineCompctS)zeA :class: `LineComp` instance for checking that an input linearly contains a sequence of strings.)r0rrErClinecompr2s  :rE LineMatcherrctS)zA reference to the :class: `LineMatcher`. This is instantiable with a list of lines (without their trailing newlines). This is useful for testing large texts, such as the output of commands. )r3rs rCLineMatcher_fixturer6s  rEPytesterc t|||dS)a  Facilities to write tests/configuration files, execute pytest in isolation, and match against expected output, perfect for black-box testing of pytest plugins. It attempts to isolate the test run from external factors as much as possible, modifying the current working directory to ``path`` and environment variables during initialization. It is particularly useful for testing plugins. It is similar to the :fixture:`tmp_path` fixture but provides methods which aid in testing pytest itself. Tr)r7)rtmp_path_factory monkeypatchs rCpytesterr;s G-{d KKrEc#|Kt}t}d|j|jywr)SysPathsSnapshotSysModulesSnapshotrestore) snappathssnapmodss rC _sys_snapshotrBs1 "I!#H   s:<c#NKddlm}|}||jyw)Nr) get_config)_pytest.configrD_ensure_unconfigure)rDrNs rC_config_for_testrGs!) \F L  s#%z \d+\.\d\dsz (\d+) (\w+)ceZdZdZ ddZd dZd dZed dZ d d dZ y) RunResultz?The result of running a command from :class:`~pytest.Pytester`.c t||_ ||_ ||_ t ||_ t ||_ ||_y#t$r ||_YLwxYwr) rrroutlineserrlinesr3rVrWduration)ryrrKrLrMs rCrzRunResult.__init__ so '/}DH #! 1  1!(+  "(+ 5  " DH sA A A c d|jdt|jjdt|jjd|j dd S)Nz)rrrVrrWrMrs rCrzRunResult.__repr__$s^dhh\*!!$T[[%6%6!7 89!!$T[[%6%6!7 89 c*" . rEc8|j|jS)aUReturn a dictionary of outcome noun -> count from parsing the terminal output that the test process produced. The returned nouns will always be in plural form:: ======= 1 failed, 1 passed, 1 warning, 1 error in 0.13s ==== Will return ``{"failed": 1, "passed": 1, "warnings": 1, "errors": 1}``. )parse_summary_nounsrKrs rC parseoutcomeszRunResult.parseoutcomes,s'' 66rEc Vt|D]L}tj|stj |}|Dcic]\}}|t |}}}n t dddd}|jD cic]\}} |j||| c} }Scc}}wcc} }w)aExtract the nouns from a pytest terminal summary line. It always returns the plural noun for consistency:: ======= 1 failed, 1 passed, 1 warning, 1 error in 0.13s ==== Will return ``{"failed": 1, "passed": 1, "warnings": 1, "errors": 1}``. z(Pytest terminal summary report not foundwarningserrors)warningr) reversedrex_session_durationsearch rex_outcomefindallr/ritemsget) clsrrcr'countnounr to_pluralkvs rCrPzRunResult.parse_summary_nouns8sUO ID#**40&..t4=EFMUDtSZ'FF  I GH H" 4799;?41a a#Q&??G@s B>B%Nc Vd} ddlm} |j} | | |||||||| y)z Assert that the specified outcomes appear with the respective numbers (0 means it didn't occur) in the text output from a test run. ``warnings`` and ``deselected`` are only checked if not None. Tr)assert_outcomes)rr rrTxpassedxfailedrS deselectedN)r&rdrQ) ryrr rrTrerfrSrgrrdr's rCrdzRunResult.assert_outcomesPs>"!?%%' ! rE) rzint | ExitCoderK list[str]rLrhrMfloatrjrr)rjzdict[str, int])rrrrrrNN)rr/r r/rr/rTr/rer/rfr/rS int | Nonergrjrjr) rrrrrrrQ classmethodrPrdrrErCrIrIsI# ## #  #  #6  7@@2#!%              rErIceZdZdddZddZy)r>NcN||_ttj|_yr)_SysModulesSnapshot__preserverrlmodules_SysModulesSnapshot__saved)rypreserves rCrzSysModulesSnapshot.__init__ss"CKK( rEc,jr@jjfdtjj Dtjj tjjjy)Nc3PK|]\}}j|s||fywr)rn)rramrys rCrz-SysModulesSnapshot.restore..ys) 1a$//!:LA s& &)rnrprrlror[r)rs`rCr?zSysModulesSnapshot.restorews^ ?? LL   #&;;#4#4#6    4<<(rEr)rqzCallable[[str], bool] | Nonerjrr*rrrrr?rrErCr>r>rs ))rEr>ceZdZddZddZy)r=crttjttjf|_yr)rrlpath meta_path_SysPathsSnapshot__savedrs rCrzSysPathsSnapshot.__init__sCHH~tCMM':: rEcf|j\tjddtjddyr)rzrlrxryrs rCr?zSysPathsSnapshot.restores!(, % S]]1%rENr*rurrErCr=r=s ;5rEr=ceZdZUdZdZeZded<GddeZ dd d;dZ e dd Zd?d Zd@d Zd>dZ dA dBdZdCdZdDdZdDdZdDdZdEdZdDdZd>2}}++55mD -44tD6]T4R!,,B  )3t/A/A+BC - / "E 2dii. &'" -) +s#rEc|jS)zBTemporary directory path used to create files/run tests from, etc.)rrs rCrxz Pytester.pathszzrEc"d|jdS)Nz )rxrs rCrzPytester.__repr__sDII=**rEcl|jj|jjy)a Clean up global state artifacts. Some methods modify the global interpreter state and this tries to clean this up. It does not remove the temporary directory however so it can be looked at after the test run has finished. N)rr?rrs rCrzPytester._finalizes( ""**, '')rEc d}t|S)Nc$|jdS)N)zopereadlinerar4s rCpreserve_modulez=Pytester.__take_sys_modules_snapshot..preserve_modules??#78 8rE)rq)r>)ryrs rC__take_sys_modules_snapshotz$Pytester.__take_sys_modules_snapshots 9"?;;rEcxt|dx|_}|jj|j|S)zFCreate a new :class:`HookRecorder` for a :class:`PytestPluginManager`.Tr)rreprecrrr)ryrKrs rCmake_hook_recorderzPytester.make_hook_recorders3(4]d(SS v ""6#:#:; rEcN|jj|jy)zaCd into the temporary directory. This is done automatically upon instantiation. N)rrrxrs rCrzPytester.chdirs  *rEcz t|j}| td|r"|jdst d|d|d fd |r:dj fd|D}|j }|jd||fd}|D]\}} |jj|j|} | jjd d t| } dj fd | jD}| j|j! || }|J|S)Nzext must not be None.z1pytester.makefile expects a file extension, try .z instead of c\t|tr|jSt|Sr)rbytesdecoderi)srZs rCto_textz#Pytester._makefile..to_texts$)3Au)=188H% I3q6 IrErec3.K|] }|ywrr)rrrs rCrz%Pytester._makefile..s9awqz9rT)parentsexist_okc3.K|] }|ywrr)rrcrs rCrz%Pytester._makefile..sGwt}GrrZ)rz Any | bytesrjri)rr[ TypeErrorrbrrrinsertrxjoinpath with_suffixparentmkdirrr write_textstrip) ryextrfilesrZr[sourcebasenamervaluepsource_rs ` @rC _makefilezPytester._makefiles+U[[]# ;23 3 s~~c*CC5 UXTYZ  J YY9599FzzH LLXv. /$ OHe ""8,88=A HHNN4$N 7UmGYYGGGF LL(L ;{  rEc(|j|||S)aCreate new text file(s) in the test directory. :param ext: The extension the file(s) should use, including the dot, e.g. `.py`. :param args: All args are treated as strings and joined using newlines. The result is written as contents to the file. The name of the file is based on the test function requesting this fixture. :param kwargs: Each keyword is the name of a file, while the value of it will be written as contents of the file. :returns: The first created file. Examples: .. code-block:: python pytester.makefile(".txt", "line1", "line2") pytester.makefile(".ini", pytest="[pytest]\naddopts=-rs\n") To create binary files, use :meth:`pathlib.Path.write_bytes` directly: .. code-block:: python filename = pytester.path.joinpath("foo.bin") filename.write_bytes(b"...") r)ryrargsrs rCmakefilezPytester.makefiles<~~c400rEc&|j|S)zpWrite a conftest.py file. :param source: The contents. :returns: The conftest.py file. )conftest) makepyfileryrs rC makeconftestzPytester.makeconftest8s //rEc(|jd|S)zhWrite a tox.ini file. :param source: The contents. :returns: The tox.ini file. z.ini)toxrrs rCmakeinizPytester.makeini@s }}V}00rEc(|jd|S)zWrite a pytest.toml file. :param source: The contents. :returns: The pytest.toml file. .. versionadded:: 9.0 .toml)pytestrrs rCmaketomlzPytester.maketomlHs}}WV}44rEcR|j|}tt|dS)z7Return the pytest section from the tox.ini config file.r)rrri)ryrrs rC getinicfgzPytester.getinicfgRs$ LL Q **rEc(|jd|S)zWrite a pyproject.toml file. :param source: The contents. :returns: The pyproject.ini file. .. versionadded:: 6.0 r) pyprojectrrs rCmakepyprojecttomlzPytester.makepyprojecttomlWs}}W}77rEc(|jd||S)aSShortcut for .makefile() with a .py extension. Defaults to the test name with a '.py' extension, e.g test_foobar.py, overwriting existing files. Examples: .. code-block:: python def test_something(pytester): # Initial file is created test_something.py. pytester.makepyfile("foobar") # To create multiple files, pass kwargs accordingly. pytester.makepyfile(custom="foobar") # At this point, both 'test_something.py' & 'custom.py' exist in the test directory. .pyrryrrs rCrzPytester.makepyfileas$~~eT622rEc(|jd||S)a[Shortcut for .makefile() with a .txt extension. Defaults to the test name with a '.txt' extension, e.g test_foobar.txt, overwriting existing files. Examples: .. code-block:: python def test_something(pytester): # Initial file is created test_something.txt. pytester.maketxtfile("foobar") # To create multiple files, pass kwargs accordingly. pytester.maketxtfile(custom="foobar") # At this point, both 'test_something.txt' & 'custom.txt' exist in the test directory. z.txtrrs rC maketxtfilezPytester.maketxtfileus$~~fdF33rENch| |j}|jjt|y)zPrepend a directory to sys.path, defaults to :attr:`path`. This is undone automatically when this object dies at the end of each test. :param path: The path. N)rxrsyspath_prependri)ryrxs rC syspathinsertzPytester.syspathinserts* <99D ))#d)4rEcD|j|z }|j|S)zCreate a new (sub)directory. :param name: The name of the directory, relative to the pytester path. :returns: The created directory. :rtype: pathlib.Path )rxrryrrs rCrzPytester.mkdirs  II   rEc|j|z }|j|jdj|S)zCreate a new python package. This creates a (sub)directory with an empty ``__init__.py`` file so it gets recognised as a Python package. __init__.py)rxrrtouchrs rCmkpydirzPytester.mkpydirs5 II    =!'')rEc|jjjd}| td|jjj|z }|jj j dD])}|jsJ|j|j}+|O|j}||z }||dzz }|jr|}n4|jr|}n!t|d||j|}|jrN|jdjs/tj||jdd|jS|jr=|jj|j } tj"|| | Std |d ) zCopy file from project's directory into the testdir. :param name: The name of the file to copy. :return: Path to the copied directory (inside ``self.path``). :rtype: pathlib.Path r?z2pytester_example_dir is unset, can't copy examplespytester_example_pathrz( can't be found as module or package in rT)symlinks dirs_exist_okz example "z%" is not found as a file or directory)rrNgetinirrootpathr iter_markersrrris_diris_file LookupErrorshutilcopytreerxrr) ryr example_dir_ example_dir extra_element func_name maybe_dir maybe_file example_pathresults rC copy_examplezPytester.copy_examples}}++223IJ  QR R MM0099LH !]]//<<=TU DM %% %%.+.. 0B0BCK D < I#i/I$ E(9:J!( ##%) ! k!I+W'//5L    )>)>})M)U)U)W OOL$))dRV W99   ! ! #YY'' (9(9:F KK f -ML>)NO rEcltj|}dt|vsJttj j |}|jj||jt|gdd}|jj|tj|S)aGet the collection node of a file. :param config: A pytest config. See :py:meth:`parseconfig` and :py:meth:`parseconfigure` for creating it. :param arg: Path to the file. :returns: The node. r sessionFgenitemsrr exitstatus) r% from_configrir rrrxabspathrpytest_sessionstartperform_collectpytest_sessionfinishrOK)ryrNargrrress rCgetnodezPytester.getnodes%%f-3s8### % & '''8%%s1vh%?B ((X[[(Q rEcPt|}|j|}tj|}t |j |}|j j||j|gdd}|j j|tj|S)aReturn the collection node of a file. This is like :py:meth:`getnode` but uses :py:meth:`parseconfigure` to create the (configured) pytest Config instance. :param path: Path to the file. :returns: The node. rFrrr) r parseconfigurer%r r,rxrr r rrr)ryrxrNrrrs rC getpathnodezPytester.getpathnodesDz$$T*%%f-  d + '''8%%qcE%:1= ((X[[(Q rEcv|dj}g}|D]"}|j|j|$|S)aGenerate all test items from a collection node. This recurses into the collection node and returns a list of all the test items contained within. :param colitems: The collection nodes. :returns: The collected items. r)rrr)rycolitemsrrcolitems rCrzPytester.genitemssC1+%% 5G MM'**73 4 5 rEc|j|}|jj}|j}||S)a Run the "test_func" Item. The calling test instance (class containing the test method) must provide a ``.getrunner()`` method which should return a runner which can run the test protocol for a single item, e.g. ``_pytest.runner.runtestprotocol``. )getitemrinstance getrunner)ryrrtestclassinstancerunners rCrunitemzPytester.runitems:||F# MM22",,.d|rEc`|j|}gt||}|j|S)agRun a test module in process using ``pytest.main()``. This run writes "source" into a temporary file and runs ``pytest.main()`` on it, returning a :py:class:`HookRecorder` instance for the result. :param source: The source code of the test module. :param cmdlineargs: Any extra command line arguments to use. )rr inline_run)ryr cmdlineargsrrs rCinline_runsourcezPytester.inline_runsource$s7 OOF #(4 $(a(t''rEc|jdg|}|jdDcgc]}|j}}||fScc}w)a"Run ``pytest.main(['--collect-only'])`` in-process. Runs the :py:func:`pytest.main` function to run all of pytest inside the test process itself like :py:meth:`inline_run`, but returns a tuple of the collected items and a :py:class:`HookRecorder` instance. z--collect-onlypytest_itemcollected)r!rr)ryrrecrr[s rCinline_genitemszPytester.inline_genitems2sKdoo.66!$.D!EFAFFczGsAr)rno_reraise_ctrlcc ddlm tjt |}g} |j j j|j tjg G fdd}|j |t|Dcgc] }t|c}|}t dk(r j}n Gdd}||_ |tjk(r?|s=|j!d } | r*| d j"j$t&k(r t'||D] } |  Scc}w#|D] } |  wxYw) aRun ``pytest.main()`` in-process, returning a HookRecorder. Runs the :py:func:`pytest.main` function to run all of pytest inside the test process itself. This means it can return a :py:class:`HookRecorder` instance which gives more detailed results from that run than can be done by matching stdout/stderr from :py:meth:`runpytest`. :param args: Command line arguments to pass to :py:func:`pytest.main`. :param plugins: Extra plugin instances the ``pytest.main()`` instance should use. :param no_reraise_ctrlc: Typically we reraise keyboard interrupts from the child run. If True, the KeyboardInterrupt exception is captured. r)gc_collect_iterations_keyc(eZdZedfd Zy)1Pytester.inline_run..PytesterHelperPlugincxjj|jd|j<y)Nr)rxrrKstash)rNr*r&rys rCrPzBPytester.inline_run..PytesterHelperPlugin.pytest_configurems2JJt66v7K7KLM?@FLL!:;rENrNrrjr)rrr staticmethodrP)r*r&rysrCPytesterHelperPluginr,ls@@rEr1)rrgc eZdZy)#Pytester.inline_run..reprecNrrrErCrr3{srErpytest_keyboard_interrupt)_pytest.unraisableexceptionr* importlibinvalidate_cachesrrxrr?r=rrirrrr INTERRUPTEDrexcinfotypeKeyboardInterrupt) ryrr(r finalizersr1rrrr finalizerr*r&s ` @@rCr!zPytester.inline_run=sD, J ##%w- -    d>>@HH I   .088 9C @ @ NN/1 2-1A-w?C3x1}FJh***3C(CDU2Y..337HH+--'    %.$(    sA;E'E9B EEE)c(|jdd}|r|jtj}t d}|j  |j |i|}|j\} } |jt j"j%| t j&j%| |j(Jt+|j(| j-| j-|j/j0} || _| S#t$rM}|jd} t|jd}n#t$rYnwxYwGdd}Yd}~d}~wt$r"tjGdd}YBwxYw#|j\} } |jt j"j%| t j&j%| wxYw) ztReturn result of running pytest in-process, providing a similar interface to what self.runpytest() provides.rFrlrceZdZeZy),Pytester.runpytest_inprocess..reprecN)rrrrrrErCrrAsCrErNceZdZedZy)rArSN)rrrrrrrErCrz,Pytester.runpytest_inprocess..reprecs "1+CrE)rrrInstantrstart_capturingr! SystemExitrrr Exception traceback print_exc readouterrstop_capturingrlrVwriterWrrI splitlineselapsedsecondsr) ryrrrinstantcapturererrzerrrs rCrunpytest_inprocesszPytester.runpytest_inprocesss  ?E:     .."#E*! " &($9&9$))+HC  " " $ JJ  S ! JJ  S !zz%%% JJ(#..*:GOO AsA9cD|j|}|j|S)zReturn a new pytest configured Config instance. Returns a new :py:class:`pytest.Config` instance like :py:meth:`parseconfig`, but also calls the :hook:`pytest_configure` hook. )r] _do_configure)ryrrNs rCrzPytester.parseconfigures'"!!4( rEcv|j|}|D]}|j|k(s|cSJ|d|d|)aReturn the test item for a test function. Writes the source to a python file and runs pytest's collection on the resulting module, returning the test item for the requested function name. :param source: The module source. :param funcname: The name of the test function for which to return a test item. :returns: The test item. z item not found in module: z items: )getitemsr)ryrfuncnamer[rs rCrzPytester.getitemsQ  f% DyyH$   VXL .s:3 #:s!rVrWzrunning:z in:wutf8r)rqrVrWNcxd}d}jjj|)NTz! second timeout expired running: )killwaitr)rtimeout_messagerxryryrzs rChandle_timeoutz$Pytester.run..handle_timeouts=$(!%,I-Nwi"X  ))/::rEr*)tuplerxrrr r`openrrCryrqrwrr=rflushreadrL _dump_linesrlrVrW contextlibsuppressrrrIrMrN)ryrzrqrxrp1p2f1f2rOrrrzrRrys`` ` @rCrqz Pytester.rungs=J!:':: YY   ) YY   ) j#7# j$((*% WWS6W * b"''#'2O SUnn&GJJ E {{& !!# ; ;jjl%**W-C HHJ HHJ9  <WWfW % )RWWfW-E )'')&&(C'')&&(C ) ) cjj) cjj)   , 3-C c3(9(A(ABB"00%"$%3    < ) ) ) )  sy J A,I4 I I4>J J3=J0J J&I1-I40I11I44I> 9JJ J JJ#&J/cj |D]}t||y#t$rtd|dYywxYw)N)filezcouldn't print to z because of encoding)rUnicodeEncodeError)ryrfprcs rCrzPytester._dump_linessE A %d$ %! A &rd*>? @ As 22c&tjdfS)Nz-mpytest)rl executablers rC_getpytestargszPytester._getpytestargss~~z))rEcB|jtj|S)z8Run a python script using sys.executable as interpreter.rqrlr)ryscripts rC runpythonzPytester.runpythonsxx//rEcD|jtjd|S)zRun ``python -c "command"``.z-cr)rycommands rC runpython_czPytester.runpython_csxxg66rE)rzcd}t|jdd}d|g|}|jD]'}t|tst d|d|g|})|j |z}|j|d|iS) aRun pytest as a subprocess with given arguments. Any plugins added to the :py:attr:`plugins` list will be added using the ``-p`` command line option. Additionally ``--basetemp`` is used to put any temporary files and directories in a numbered directory prefixed with "runpytest-" to not conflict with the normal numbered pytest location for temporary files and directories. :param args: The sequence of arguments to pass to the pytest subprocess. :param timeout: The period in seconds after which to timeout and raise :py:class:`Pytester.TimeoutExpired`. :returns: The result. Tz runpytest-)rootprefixmodez --basetemp=zeSpecifying plugins as objects is not supported in pytester subprocess mode; specify by name instead: rUrz)r-rxrrrirrrq)ryrzrrrplugins rCrVzPytester.runpytest_subprocesss&! 499\ NaS!)D)ll )Ffc* 006x9&(4(D  )""$t+txx/w//rEc|jdz }|jddjtt|j }|d|d|}|j ||S)zRun pytest using pexpect. This makes sure to use the right pytest and sets up the temporary directory locations. The pexpect child is returned. z temp-pexpectr)r z --basetemp=)expect_timeout)rxrrmaprirspawn)rystringrrZinvokecmds rC spawn_pytestzPytester.spawn_pytestsg99~-E"#c4#6#6#89: XJax8zz#nz==rEcvtdd}ttdr!dtjvr t dt|ds t d|j jdjd }|j||| }|jj|j|S) zMRun a command using pexpect. The pexpect child is returned. pexpectz3.0r64zpypy-64 bit not supportedrzpexpect.spawn not availablez spawn.outwb)logfilerz) r*rrlplatformmachiner+rxrrrrrrw)ryrrrrchilds rCrzPytester.spawns y%0 3+ ,9I9I9K1K , -w( . /))$$[166t< c7NK ""7==1 rE) rr$r9r0r:r&rrkrjr)rjr rr*)rjr>)rKr rjr)zutf-8) rrirzSequence[Any | bytes]rzdict[str, str]rZrirjr )rrirrirrirjr )rrirjr )rrirjrr)rxzstr | os.PathLike[str] | Nonerjr)rstr | os.PathLike[str]rjr )rr.rjr )rNrrrrjCollector | Item)rxrrjr)rzSequence[Item | Collector]rj list[Item])rrirjr )rrirjr)rjztuple[list[Item], HookRecorder])rrr(rkrjr)rrrr rjrI)r Sequence[str | os.PathLike[str]]rjzlist[str | os.PathLike[str]])rrrjr) test_func)rrrbrirjr()rrrjr)r)rrrfrk)rer'rrirjzItem | Collector | None)rxrrV int | TextIOrWrrq"NotSetType | bytes | IO[Any] | int)rxrrz float | NonerqrrjrI)rjztuple[str, ...])rzos.PathLike[str]rjrI)rrirjrI)rrrzrrjrI)g$@)rrirrirj pexpect.spawn)rrirrirjr):rrrr__test__rr}__annotations__rFrrpropertyrxrrrrrrrrrrrrrrrrrrrrrrr#r'r!rSr<rUr]rrrardrmr=rtryrqrrrrrVrrrrErCr7r7sHK   ,$,$*,$! ,$  ,$ ,$\+ * < + # #%# #  #  #J1@015+ 83(4( 5  ,\&("  ( !& L%L L  L\*+*7:* *XM 4  % . ?JV,V8;V V,' *  *& *  *D& *)4? $1$$ $ 2 $R!%4? TC(TCTC2 TC  TClA*07 FJ0+06B0 0@ >rEceZdZddZddZy)r0c"t|_yr)r stringiors rCrzLineComp.__init__s  DrEcd}|jj}|jjd|jjd|j d}t |j |y)zAssert that ``lines2`` are contained (linearly) in :attr:`stringio`'s value. Lines are matched using :func:`LineMatcher.fnmatch_lines `. TrreN)rrHtruncateseekrvr3 fnmatch_lines)ryrrvalrs rCassert_contains_lineszLineComp.assert_contains_liness` !mm$$& q! 14F))&1rENr*r Sequence[str]rjr)rrrrrrrErCr0r0s E 2rEceZdZdZddZddZddZddZddZ ddZ ddZ dd Z e dd Z d d  dd Zd d  ddZd d  ddZddZddZ d dZd!dZddZy)"r3zFlexible matching of text. This is a convenience class to test large texts like the output of commands. The constructor takes a list of lines without their trailing newlines, i.e. ``text.splitlines()``. c ||_g|_yr)r _log_output)ryrs rCrzLineMatcher.__init__*s &(rEc8dj|jS)zReturn the entire original text. .. versionadded:: 6.2 You can use :meth:`str` in older versions. re)rrrs rC__str__zLineMatcher.__str__.s yy$$rEct|tr t|}t|tr|jj}|Sr)rrirrr)ryrs rC _getlineszLineMatcher._getlines6s5 fc "F^F ff %\\^))F rEc4d}|j|ty)zTCheck lines exist in the output in any order (using :func:`python:fnmatch.fnmatch`).TN)_match_lines_randomrryrrs rCfnmatch_lines_randomz LineMatcher.fnmatch_lines_random=s    1rEc.d}|j|dy)zMCheck lines exist in the output in any order (using :func:`python:re.match`).Tc@ttj||Srrkrematchrpats rCz3LineMatcher.re_match_lines_random..Es4d@S;TrEN)rrs rCre_match_lines_randomz!LineMatcher.re_match_lines_randomBs    )TUrEcd}|j|}|D]f}|jD]-}||k(s |||s|jdt|>d|d}|j||j |hy)NTz matched: line  not found in output)rr_logr_fail)ryr match_funcrrcrmsgs rCrzLineMatcher._match_lines_randomGs!' DZZ 19 1d 3IIk4:6 dX%9: # 3 rEct|jD]*\}}||k(s t||s|j|dzdcStd|d)zsReturn all lines following the given line in the text. The given line can contain glob wildcards. rgNrr)rrrr)ryfnlinerrcs rCget_lines_afterzLineMatcher.get_lines_afterVs\ !, +GAt~v!6zz!a%'** +5 *>?@@rEcf|jjdjd|Dy)Nrc32K|]}t|ywrr)rrs rCrz#LineMatcher._log..as(>AQ(>r)rrxr)ryrs rCrzLineMatcher._log`s% (>(> >?rEc8dj|jS)Nre)rrrs rC _log_textzLineMatcher._log_textcsyy))**rEF consecutivec:d}|j|td|y)aCheck lines exist in the output (using :func:`python:fnmatch.fnmatch`). The argument is a list of lines which have to match and can use glob wildcards. If they do not match a pytest.fail() is called. The matches and non-matches are also shown as part of the error message. :param lines2: String patterns to match. :param consecutive: Match lines consecutively? TrrN) _match_linesrryrrrs rCrzLineMatcher.fnmatch_linesgs!! &'9+NrEc4d}|j|dd|y)aCheck lines exist in the output (using :func:`python:re.match`). The argument is a list of lines which have to match using ``re.match``. If they do not match a pytest.fail() is called. The matches and non-matches are also shown as part of the error message. :param lines2: string patterns to match. :param consecutive: match lines consecutively? Tc@ttj||Srrrs rCrz,LineMatcher.re_match_lines..sd288C#67rEre.matchrN)rrs rCre_match_lineszLineMatcher.re_match_linesvs)!   7 #  rEct|tjjs!t dt |j |j|}|jdd}g}d}t|dz}d} |D]} d} |rR|jd} | | k(r|jdt| d} =|| | rM|j|dt| |jd jd | t| d} |rU| rSd | } |j| |jd jd | t| |j| | s.|jd jd | t| d} |jd jd| t| |j| |rRd| } |j| |j| g|_y)aqUnderlying implementation of ``fnmatch_lines`` and ``re_match_lines``. :param Sequence[str] lines2: List of string patterns to match. The actual format depends on ``match_func``. :param match_func: A callable ``match_func(line, pattern)`` where line is the captured line from stdout/stderr and pattern is the matching pattern. :param str match_nickname: The nickname for the match function that will be logged to stdout when a match occurs. :param consecutive: Match lines consecutively? zinvalid type for lines2: NTrgFrz exact match:: {:>{width}}with:widthzno consecutive match: nomatch:and:zremains unmatched: )r collectionsabcrrr;rrrrrrrrrrxr)ryrrmatch_nicknamerr extralinesrwnickstartedrcnomatchprintednextliners rCrzLineMatcher._match_liness.&+//":":;7V 8M8M7NOP P'A  N#a'! D"N!::a=8#IInd4j9"G$/II 02DJ?II%,,WE,BDN#G"w 6th? # )000FX 3) )0050I4PT:*.IIm2262GhX!!(+7:,D84 # 3C! DrEc6d}|j|tdy)zEnsure captured lines do not match the given pattern, using ``fnmatch.fnmatch``. :param str pat: The pattern to match lines. TrN)_no_match_linerryrrs rCno_fnmatch_linezLineMatcher.no_fnmatch_lines ! C)4rEc0d}|j|ddy)zEnsure captured lines do not match the given pattern, using ``re.match``. :param str pat: The regular expression to match lines. Tc@ttj||Srrrs rCrz.LineMatcher.no_re_match_line..s4d(;#<rErN)rr s rCno_re_match_linezLineMatcher.no_re_match_lines !  > XrEct|S)z Return the entire original text.rrs rCrizLineMatcher.strs 4yrEN)rrhrjrr)rzstr | Sequence[str] | Sourcerjrr)rrrCallable[[str, str], bool]rjr)rrirjrr*)rrrrkrjr) rrrrrrirrkrjr)rrirjr)rrirrrrirjr)rrirjr)rrrrrrrrrrrrrrrrrr r rrrirrErCr3r3 s")%2 V  #  1K    A@++=B O# O59 O  O =B # 59  6" AA/A A  A AF5 $>PS . rE)rBr!rjrr/)rr$rjr)rz Iterable[str]rjrh)rjr0)rr$rjztype[LineMatcher])rr$r9r0r:r&rjr7)rjzGenerator[None])rjzGenerator[Config])kr __future__rcollections.abcrrrrrrrrr7ior rnrrpathlibr rrrr=rlrGtypingr r r rrrrrweakrefr iniconfigrrrr _pytest._coder_pytest.capturer_pytest.compatrrrErrrrrr _pytest.config.argparsingr!_pytest.deprecatedr"_pytest.fixturesr#r$ _pytest.mainr%_pytest.monkeypatchr& _pytest.nodesr'r(_pytest.outcomesr)r*r+_pytest.pathlibr,r-_pytest.reportsr.r/_pytest.tmpdirr0_pytest.warning_typesr1rpytest_pluginsrwrDrPrIrrrrr2r6r;rBrGcompilerWrYrIr>r=r7r0r3rrErCr+sa #$%$$     %$ -!%(!##.,-$+ +#!)!'-)&*1(( 2 F=F=X  . ---6OOOd    m  L  L/> LMX L  L  L    ! !"rzz-0bjj( i i i X ) )55BBBJ22$__rE