U é üeÖ‰ã@s¾dZddlZddlZddlZddlZddlZddlZddlZddlZddl Z ddl m Z ddl m Z ddl mZddlmZddlmZddlmZdd lmZdd lmZzdd lmZWn ek rÜdd lmZYnXdd lmZdd lmZzddl m!Z!Wnek r$ddl Z YnXdZ"e #e$¡Z%da&a'a(a)a*a+Gdd„de,ƒZ-dd„Z.Gdd„dƒZ/Gdd„deƒZ0dd„Z1Gdd„de ƒZ2dd„Z3dd„Z4Gdd „d eƒZ5dS)!a­ Overview ======== The multiprocess plugin enables you to distribute your test run among a set of worker processes that run tests in parallel. This can speed up CPU-bound test runs (as long as the number of work processeses is around the number of processors or cores available), but is mainly useful for IO-bound tests that spend most of their time waiting for data to arrive from someplace else. .. note :: See :doc:`../doc_tests/test_multiprocess/multiprocess` for additional documentation and examples. Use of this plugin on python 2.5 or earlier requires the multiprocessing_ module, also available from PyPI. .. _multiprocessing : http://code.google.com/p/python-multiprocessing/ How tests are distributed ========================= The ideal case would be to dispatch each test to a worker process separately. This ideal is not attainable in all cases, however, because many test suites depend on context (class, module or package) fixtures. The plugin can't know (unless you tell it -- see below!) if a context fixture can be called many times concurrently (is re-entrant), or if it can be shared among tests running in different processes. Therefore, if a context has fixtures, the default behavior is to dispatch the entire suite to a worker as a unit. Controlling distribution ^^^^^^^^^^^^^^^^^^^^^^^^ There are two context-level variables that you can use to control this default behavior. If a context's fixtures are re-entrant, set ``_multiprocess_can_split_ = True`` in the context, and the plugin will dispatch tests in suites bound to that context as if the context had no fixtures. This means that the fixtures will execute concurrently and multiple times, typically once per test. If a context's fixtures can be shared by tests running in different processes -- such as a package-level fixture that starts an external http server or initializes a shared database -- then set ``_multiprocess_shared_ = True`` in the context. These fixtures will then execute in the primary nose process, and tests in those contexts will be individually dispatched to run in parallel. How results are collected and reported ====================================== As each test or suite executes in a worker process, results (failures, errors, and specially handled exceptions like SkipTest) are collected in that process. When the worker process finishes, it returns results to the main nose process. There, any progress output is printed (dots!), and the results from the test run are combined into a consolidated result set. When results have been received for all dispatched tests, or all workers have died, the result summary is output as normal. Beware! ======= Not all test suites will benefit from, or even operate correctly using, this plugin. For example, CPU-bound tests will run more slowly if you don't have multiple processors. There are also some differences in plugin interactions and behaviors due to the way in which tests are dispatched and loaded. In general, test loading under this plugin operates as if it were always in directed mode instead of discovered mode. For instance, doctests in test modules will always be found when using this plugin with the doctest plugin. But the biggest issue you will face is probably concurrency. Unless you have kept your tests as religiously pure unit tests, with no side-effects, no ordering issues, and no external dependencies, chances are you will experience odd, intermittent and unexplainable failures and errors when using this plugin. This doesn't necessarily mean the plugin is broken; it may mean that your test suite is not safe for concurrency. New Features in 1.1.0 ===================== * functions generated by test generators are now added to the worker queue making them multi-threaded. * fixed timeout functionality, now functions will be terminated with a TimedOutException exception when they exceed their execution time. The worker processes are not terminated. * added ``--process-restartworker`` option to restart workers once they are done, this helps control memory usage. Sometimes memory leaks can accumulate making long runs very difficult. * added global _instantiate_plugins to configure which plugins are started on the worker processes. éN)ÚTextTestRunner)Úfailure)Úloader)ÚPlugin)Úbytes_)ÚTextTestResult)Ú ContextSuite)Ú test_address)Ú_WritelnDecorator)ÚEmpty)Úwarn)ÚStringIOc@seZdZddd„Zdd„ZdS)ÚTimedOutExceptionú Timed OutcCs ||_dS©N)Úvalue)Úselfr©rúG/opt/hc_python/lib/python3.8/site-packages/nose/plugins/multiprocess.pyÚ__init__‡szTimedOutException.__init__cCs t|jƒSr)Úreprr©rrrrÚ__str__‰szTimedOutException.__str__N)r)Ú__name__Ú __module__Ú __qualname__rrrrrrr†s rcCs~zZddlm}mat tjtj¡}|ƒ}t tj|¡|j|j|j|j |j f\aaaa a Wnt k rxt dt ƒYnXdS)Nr)ÚManagerÚProcesszKmultiprocessing module is not available, multiprocess plugin cannot be used)ÚmultiprocessingrrÚsignalÚSIGINTÚSIG_IGNÚQueueÚPoolÚEventÚValueÚArrayÚ ImportErrorr ÚRuntimeWarning)rÚoldÚmrrrÚ _import_mpŒsÿÿr+c@s,eZdZdd„Zdd„Zdd„Zdd„Zd S) ÚTestLetcCs<z| ¡|_Wntk r"YnX| ¡|_t|ƒ|_dSr)ÚidÚ_idÚAttributeErrorÚshortDescriptionÚ_short_descriptionÚstrÚ_str)rÚcaserrrr£s  zTestLet.__init__cCs|jSr)r.rrrrr-«sz TestLet.idcCs|jSr)r1rrrrr0®szTestLet.shortDescriptioncCs|jSr)r3rrrrr±szTestLet.__str__N)rrrrr-r0rrrrrr,¢sr,c@s8eZdZdZdZiZdd„Zdd„Zdd„Zd d „Z d S) Ú MultiProcesszF Run tests in multiple processes. Requires processing module. iècCs\|jdd| dd¡dddd|jd d| d d ¡d d dd|jdd| dd¡ddddS)z0 Register command-line options. z --processesÚstoreZNOSE_PROCESSESrÚmultiprocess_workersZNUMaNSpread test run among this many processes. Set a number equal to the number of processors or cores in your machine for best results. Pass a negative number to have the number of processes automatically set to the number of cores. Passing 0 means to disable parallel testing. Default is 0 unless NOSE_PROCESSES is set. [NOSE_PROCESSES])ÚactionÚdefaultÚdestÚmetavarÚhelpz--process-timeoutZNOSE_PROCESS_TIMEOUTé Úmultiprocess_timeoutZSECONDSzfSet timeout for return of results from each test runner process. Default is 10. [NOSE_PROCESS_TIMEOUT]z--process-restartworkerÚ store_trueZNOSE_PROCESS_RESTARTWORKERFÚmultiprocess_restartworkerz™If set, will restart each worker process once their tests are done, this helps control memory leaks from killing the system. [NOSE_PROCESS_RESTARTWORKER])r8r9r:r<N)Ú add_optionÚget)rÚparserÚenvrrrÚoptions»s" ü  ü ýzMultiProcess.optionsc Csz|j d¡Wntk r$YnXt|dƒs:d|_dS|jrDdS||_zt|jƒ}Wnt t fk rtd}YnX|r t ƒt dkr”d|_dS|dkrÎzddl }| ¡}Wntk rÌd|_YdSXd|_||j_t|jƒ}||j_t|jƒ}||j_d|jd<dS)z# Configure plugin. Úactiver7FNrT)ÚstatusÚpopÚKeyErrorÚhasattrÚenabledÚworkerÚconfigÚintr7Ú TypeErrorÚ ValueErrorr+rrÚ cpu_countÚNotImplementedErrorÚfloatr>r@)rrErMÚworkersrÚtÚrrrrÚ configureÛsB     zMultiProcess.configurecCs |j|_dS)zbRemember loader class so MultiProcessTestRunner can instantiate the right loader. N)Ú __class__Ú loaderClass)rrrrrÚprepareTestLoaderszMultiProcess.prepareTestLoadercCst|j|jj|j|jdS)z9Replace test runner with MultiProcessTestRunner. )ÚstreamÚ verbosityrMrY)ÚMultiProcessTestRunnerr[rMr\rY)rÚrunnerrrrÚprepareTestRunner s ýzMultiProcess.prepareTestRunnerN) rrrÚ__doc__ZscorerGrErWrZr_rrrrr5´s )r5cCs tƒ‚dSr)r)ÚsigÚframerrrÚ signalhandlersrccs€eZdZdZ‡fdd„Zdd„Zdd„Zdd „Zd d „Ze eƒZd d „Z e e ƒZ dd„Z dd„Z e e ƒZ dd„Z dd„Z‡ZS)r]g@c s&| dtj¡|_tt|ƒjf|ŽdS)NrY)rHrZdefaultTestLoaderrYÚsuperr]r)rÚkw©rXrrrszMultiProcessTestRunner.__init__c Csz| |¡D]h}t d|t|ƒ¡t|tjjƒrRt|jt j ƒrRt d¡||ƒq t|t ƒr~|j t j kr~t d¡||ƒq q t|t ƒrR|  |¡rRt d|¡z | ¡WnDttfk rÈ‚Ynˆt dt ¡¡| |t ¡¡Yn^X| |¡|jr>|jj  |g¡}|dd…D]}t|ddƒr"d|_q"| |||||¡q | |||¡} t d t|ƒ| |¡q dS) NzNext batch %s (%s)zCase is a Failurez%s has shared fixturesz%s setup failedéÚ_multiprocess_shared_FTzQueued test %s (%s) to %s)Ú nextBatchÚlogÚdebugÚtypeÚ isinstanceÚnoser4ÚTestÚtestrÚFailurerÚcontextÚsharedFixturesÚsetUpÚKeyboardInterruptÚ SystemExitÚsysÚexc_infoÚaddErrorÚappendÚfactoryrBÚgetattrÚ_multiprocess_can_split_ÚcollectÚaddtaskÚlen) rrpÚ testQueueÚtasksÚ to_teardownÚresultr4Z ancestorsZanÚ test_addrrrrr~sD ÿ      ÿzMultiProcessTestRunner.collectc Csˆtdtdƒƒ}tdt ¡ƒ}tƒ}tt||||||||j|jt  |j ¡f d} || _ || _ || _ t tjt¡} |  ¡t tj| ¡| S)NÚcÚÚd)ÚtargetÚargs)r%rÚtimer$rr^rYrXÚpickleÚdumpsrMÚ currentaddrÚ currentstartÚkeyboardCaughtrÚSIGILLrcÚstart) rÚiworkerrÚ resultQueueÚ shouldStopr„rŽrrÚpr)rrrÚ startProcessEs, øÿ z#MultiProcessTestRunner.startProcessc Cst d||t ¡¡|jj |¡}|dk r.|}|jj |j¡}|dk rL||_t ƒ}t ƒ}g}g}g}g} t ƒ} |  ¡} t   ¡} |  |||| | ¡t d|jj¡t|jjƒD]0} | | ||| | ¡}| |¡t d| d¡q¬t|ƒ}|jj}d}zv|rRt dt|ƒ||¡zP|j|d\}}}}t d||t|ƒ¡zNz| |¡Wn$tk rpt d ||¡YnX|t|ƒ7}| |¡Wn:tk rÄt d |¡t d tt|ƒd ƒ¡YnX| ||g¡| | |¡|jjr|  ¡s|  ¡WqR|jj r^t d |¡||j!dd|  "¡s^| #¡s^t d|¡| |||| | ¡||<WnŒt$k rît dt|ƒ| #¡t|ƒ¡d}t%|ƒD]*\}}| &¡rœt'|j(j)dƒ}t   ¡|j*j)}t|ƒd krü||jjdkrüt d|¡nd}t|ƒd krœ||jjdkrœt d||¡t'dƒ|j(_)|j+ ,¡t   ¡}|j+ "¡sœ| &¡rœt   ¡||j-kr¨t .d|¡| /¡| |||| | ¡||<}qœt 0|j1t2j3¡t  4d¡qLqœ|sê| #¡rêt d¡YqRYnX|jj}|D]R}| &¡rüt|j(j)ƒd krüt   ¡|j*j)}||jjkrüt5||jj|ƒ}qüqöt dt|ƒt|ƒ¡WnFt6t7fk r°}z"t 8d¡|}|  9|t: ;¡¡W5d}~XYnXz | D]V}t d|¡z | <¡Wn6t6t7fk rò‚Yn|  9|t: ;¡¡YnXqºt   ¡}|  =¡|  >| |¡|jj ?| ¡|dkrtt d¡|D]}| &¡rT|j@dddqTt%|ƒD]>\}}| &¡r|t d |¡| !¡| &¡r|t d|¡q|WnPt6t7fk rt 8d ¡|D]}| &¡râ| /¡qâ|r|‚n‚YnX| S)!a Execute the test (which may be a test suite). If the test is a suite, distribute it out among as many processes as have been configured, at as fine a level as is possible given the context fixtures defined in the suite or any sub-suites. z%s.run(%s) (%s)NzStarting %s workerszStarted worker process %séz5Waiting for results (%s/%s tasks), next timeout=%.3fs©Útimeoutz1Results received for worker %d, %s, new tasks: %dz)worker %s failed to remove from tasks: %szGot result for unknown task? %sz current: %srzjoining worker %sz!starting new process on worker %sz8Timed out with %s tasks pending (empty testQueue=%r): %sFÚasciigš™™™™™¹?zLworker %d has finished its work item, but is not exiting? do we wait for it?Tztimed out worker %s: %sr‡zterminating worker %szAll workers deadzCompleted %s tasks (%s remain)z4parent received ctrl-c when waiting for test resultsz#Tearing down shared fixtures for %szTell all workers to stopÚSTOP©Úblockzfailed to join worker %sz=parent received ctrl-c when shutting down: stop all processes)ArjrkÚosÚgetpidrMÚpluginsZ prepareTestZsetOutputStreamr[r"r$Z _makeResultr‹r~r7Úranger—rzr€r>rBÚremoverPr ÚextendrIr2ÚlistÚ consolidateZ stopOnErrorZ wasSuccessfulÚsetr@ÚjoinÚis_setÚemptyr Ú enumerateÚis_aliverrŽrrrÚclearÚ waitkilltimeÚerrorÚ terminateÚkillÚpidrr‘ÚsleepÚminrurvÚinforyrwrxÚtearDownZ printErrorsZ printSummaryÚfinalizeÚput)rrpÚwrapperÚwrappedrr”r‚Ú completedrTrƒr•r„r’Úir–Z total_tasksZ nexttimeoutZ thrownErrorr“ÚaddrZ newtask_addrsÚ batch_resultZ any_aliveÚwZ worker_addrZtimeprocessingZ startkilltimeÚer4ÚstoprLrrrÚrun[s0 ÿÿÿÿ     ÿ   þ ÿþÿÿ      ÿ  "            zMultiProcessTestRunner.runcCstd}t|tjjƒr.t|jdƒr.d|j_|jj}t  |¡}|j ||fdd|dk r^|t |ƒ7}|dk rp|  |¡|S)NÚargFr) rmrnr4rorJrpZ descriptorrÃr]Úaddressr¸r2rz)rr‚r4rÃr…rrrrs   zMultiProcessTestRunner.addtaskcCsºt|dƒr| ¡\}}}n(t|dƒr6t|jƒ\}}}n td|ƒ‚g}|dkrp|dkrdtd|ƒ‚q˜| |¡n(tj |¡\}}|  d¡rŽ|}| |¡|dk rª| |¡d  t t |ƒ¡S)NrÄrrzUnable to convert %s to addresszUnaddressable case %srú:) rJrÄr rrÚ ExceptionrzrŸÚpathÚsplitÚ startswithr¨Úmapr2)r4ÚfileÚmodÚcallÚpartsÚdirnameÚbasenamerrrrÄ!s"       zMultiProcessTestRunner.addressccs²t|dƒrt|jddƒsdSt|tƒr2| |j¡sJt|ddƒrJt|tjƒsŽt|tƒr†t |ƒ}t |ƒdkr†t|dddƒ|jkr†|d}|Vn |D]}|  |¡D] }|Vq q’dS)NrrZ_multiprocess_TZ can_splitr˜r) rJr|rrrmrZ hasFixturesÚ checkCanSplitÚunittestZ TestSuiter¥r€ri)rrpÚ containedr4Úbatchrrrri:s2   ÿ þ ý  ÿÿÿz MultiProcessTestRunner.nextBatchcCs|sdSt|ddƒrdSdS)a8 Callback that we use to check whether the fixtures found in a context or ancestor are ones we care about. Contexts can tell us that their fixtures are reentrant by setting _multiprocess_can_split_. So if we see that, we return False to disregard those fixtures. Fr}T©r|)rrZfixtrrrrÑZs  z$MultiProcessTestRunner.checkCanSplitcCs t|ddƒ}|sdSt|ddƒS)NrrFrhrÕ)rr4rrrrrrsjs z%MultiProcessTestRunner.sharedFixturescCsêt d|¡z|\}}}}}Wn4tk rRt d|¡tjt ¡Ž|ƒYdSX|j |¡|j |7_ |j   |¡|j   |¡t | ¡ƒD]B\}\} } } ||jkrºg| | f|j|<|j|\} } } |   | ¡q’t d||j ¡dS)Nzbatch result is %szresult in unexpected format %szRan %s tests (total: %s))rjrkrPrrqrwrxr[ÚwriteÚtestsRunÚfailuresr¤Úerrorsr¥ÚitemsÚ errorClasses)rr„r¾Úoutputr×rØrÙrÛÚkeyÚstorageÚlabelÚisfailZ mystorageZ_junkrrrr¦ps"       z"MultiProcessTestRunner.consolidate)rrrr®rr~r—rÂrÚ staticmethodrÄrirÑrsr¦Ú __classcell__rrrfrr]s (7 r]c CsjzDzt|||||||||| ƒ WWStk r@t d|¡YnXWn tk rdt d|¡YnXdS)Nz&Worker %s keyboard interrupt, stoppingz%Worker %s timed out waiting for tasks)Ú__runnerrurjrkr ) Úixrr”rŽrrr•rYÚ resultClassrMrrrr^‡s ÿr^c  sÐt ˆ¡‰ˆ ¡} tdk rBtD]"} | ƒ} |  | i¡ˆj | ¡qˆj ˆjˆ¡ˆj  ¡t   d|t   ¡¡|ˆd} t| j_‡‡fdd„}‡‡fdd„}dd„}t|d ƒD]\}}| ¡rÒt  d |¡qÀ|ƒ}|  |g¡}ˆ|_g|_||_t   d |||¡zZ|dk r|t|ƒ}t|ƒ|_t ¡|_||ƒtd ƒ|_| |||j||ƒf¡WnPtk r:}zºt|tƒ}|rŒ| ¡t |jƒrì|r¤d }nd}t  |||¡td ƒ|_t!j"t# $¡Ž|ƒ| |||j||ƒf¡n6|rød}nd}t   |||¡| |||j||ƒf¡|s*‚W5d}~XYnxt%k rftd ƒ|_t  d|¡‚YnLtd ƒ|_t  d|¡t!j"t# $¡Ž|ƒ| |||j||ƒf¡YnXˆj&r®qÀq®t   d|¡dS)NzWorker %s executing, pid=%d)rMcsˆjˆjdS)Nr™)rBr>r)rMrrrrB¢sz__runner..getcs4ttƒƒ}ˆ|dˆjˆd}ˆj |¡}|r0|S|S)Nr˜)Z descriptionsr\rM)r r r\r¡ZprepareTestResult)r[r„Z plug_result)rMrårrÚ makeResult¥s þ z__runner..makeResultcSspdd„|jDƒ}dd„|jDƒ}i}t|j ¡ƒD]&\}\}}}dd„|Dƒ||f||<q2|j ¡|j|||fS)NcSsg|]\}}t|ƒ|f‘qSr©r,©Ú.0r†ÚerrrrrÚ °sz+__runner..batch..cSsg|]\}}t|ƒ|f‘qSrrçrèrrrrë±scSsg|]\}}t|ƒ|f‘qSrrçrèrrrrë´s)rØrÙr¥rÛrÚr[Úgetvaluer×)r„rØrÙrÛrÝrÞrßràrrrrÔ¯s ÿ ûz__runner..batchrœzWorker %d STOPPEDzWorker %s Test is %s (%s)r‡z,Worker %s timed out, failing current test %sz5Worker %s keyboard interrupt, failing current test %szWorker %s test %s timed outz$Worker %s test %s keyboard interruptzWorker %s system exitz1Worker %s error running test or returning resultszWorker %s ending)'rŒÚloadsZ parserClassÚ_instantiate_pluginsZ addOptionsr¡Z addPluginrWrEÚbeginrjrkrŸr ÚNoSharedFixtureContextSuiteZ suiteClassÚiterr©Ú exceptionZloadTestsFromNamesrr‚rÃr2rrr‹r¸rurmrr§r€rrqrwrxrvr@)rärr”rŽrrr•rYrårMZ dummy_parserZ pluginclassÚpluginrrBrærÔr…rÃr„rprÀršÚmsgr)rMrårrrã’s„                   ÿrãcs@eZdZdZdZdZdZ‡fdd„Z‡fdd„Zdd„Z ‡Z S) rða Context suite that never fires shared fixtures. When a context sets _multiprocess_shared_, fixtures in that context are executed by the main process. Using this suite class prevents them from executing in the runner process as well. Ncs$t|ddƒrdStt|ƒ |¡dS©NrhF)r|rdrðÚ setupContext©rrrrfrrröÿs z(NoSharedFixtureContextSuite.setupContextcs$t|ddƒrdStt|ƒ |¡dSrõ)r|rdrðÚteardownContextr÷rfrrrøs z+NoSharedFixtureContextSuite.teardownContextcCsÎt dt|ƒ||j¡|jr0| ||¡|}}n ||}}z | ¡Wn8tk r\‚Yn$d|_| ||  ¡¡YdSXzú|jD]î}t |t jjƒr°|jdk r°|j|j_n|j|_|j|_|j|_|jrÞt d¡qxz ||ƒWqˆtk rt}zjt |tƒ}|rd}nd}t |||¡ttt|ƒƒt ¡d f}|jj ||¡| ||¡|sd‚W5d}~XYqˆXqˆW5d|_ z |  ¡Wn8tk r¦‚Yn"d|_| ||  ¡¡YnXXdS) z5Run tests in suite inside of suite fixtures. z#suite %s (%s) run called, tests: %sÚsetupNTZteardownZstoppingz(Timeout when running test %s in suite %sz2KeyboardInterrupt when running test %s in suite %srg)rjrkr-Z_testsZ resultProxyrtruZ error_contextryZ _exc_infoZhas_runr¶rmrnr4rorÃrprr‚r•rr2rwrxrMr¡)rr„ÚorigrprÀršrôrêrrrrÂsfÿ   ÿ      ÿ  zNoSharedFixtureContextSuite.run) rrrr`rr‚rÃrörørÂrârrrfrrðós  rð)6r`ÚloggingrŸrwr‹Ú tracebackrÒrŒrZ nose.casernZ nose.corerrrZnose.plugins.baserZnose.pyversionrZ nose.resultrZ nose.suiterZ nose.utilr Zunittest.runnerr r'Úqueuer Úwarningsr Úior rîÚ getLoggerrrjrr"r#r$r%r&rurr+r,r5rcr]r^rãrðrrrrÚsR_           _s a