o 3a^@sddlZddlZddlZddlZddlZddlZddlZddlZddlZddl Z ddl Z ddl m Z ddl mZddlmZddlmZddlZddlmZddlmZddlmZdd lmZdd lmZeZeZd Z e!d Z"gZ#da$zddl%Z%Wn e&ydZ%Ynwzddl'Z'Wn e&ydZ'Ynwd dZ(ddZ)ddZ*ddZ+ddZ,ddZ-ej.ddddZ/ej.ddddZ0dd Z1d!d"Z2d#d$Z3d%d&Z4Gd'd(d(Z5Gd)d*d*e5Z6Gd+d,d,e7Z8Gd-d.d.e5Z9d/d0Z:d1d2Z;d3d4Z.wrapper) functoolswraps)r)r*rr(r check_errors;sr-cCstdurtddS)N)rrrrrraise_last_exceptionTsr/cCstrtjs dSttj}|dtj@sE|dtjO<ttdr-ttjtj }nd}t tjtj ||durGttj|dSdSdS)z} Ensure that echo mode is enabled. Some tools such as PDB disable it which causes usability issues after reload. NSIGTTOU) termiosrstdinisatty tcgetattrECHOhasattrsignalr1SIG_IGN tcsetattrTCSANOW) attr_list old_handlerrrrensure_echo_onZs  r>cCs4ttj}tddttjj|D}t|ttS)Ncss |] }t|tjs|VqdSN) isinstanceweakref ProxyTypes).0mrrr ssz/iter_all_python_module_files..) sortedrmodulestuplemap __getitem__iter_modules_and_files frozensetr!)keysrGrrriter_all_python_module_filesms rNr.)maxsizec Csg}|D]:}t|ts q|jdkrt|dr||jqt|dddur&q|j}|jr>t|j t r6|j j n|j }||qt }t||D]6}|sMqHt|}z|sXWqHWntyr} z td| |WYd} ~ qHd} ~ ww|} || qHt|S)z1Iterate through all modules needed to be watched.__main__r__spec__Nz%"%s" raised when resolving path: "%s")r@rr r7r"rrrQ has_locationloaderrarchiveoriginset itertoolschainrexists ValueErrorloggerdebugresolveabsoluteaddrL) rG extra_filessys_file_pathsrspecrUresultsrre resolved_pathrrrrKws@        rKcsbtdd|Dtdd}i}|D]}|}|D]}||i}q|qfddt|dS)a Return a tuple of common roots that are shared between the given paths. File system watchers operate on directories and aren't cheap to create. Try to find the minimum set of directories to watch that encompass all of the files that need to be watched. cSg|]}|jqSr)parts)rCxrrr z common_roots..T)keyreversec3s@|D]\}}|||fEdHq|st|VdSdSr?)itemsr)noderprefixchild_walkrrrrs zcommon_roots.._walkr)rFlen setdefaultclearrH)paths path_partstreechunksrnchunkrrqr common_rootss   r{ccsHtjD]}t|}|sq|}|r|jVq|VqdS)zZ Yield absolute directories from sys.path, ignoring entries that don't exist. N)rrrrYr]r^is_filer)rrerrrsys_path_directoriess   r}cCsddl}ttjd}tjgddtjD}t|dddur6|jjr6|d|jjg7}|tjdd7}|S| sp| d}| rOt |gtjddS| d |j }| rjg|t |tjddStd ||tj7}|S) z Return the executable. This contains a workaround for Windows if the executable is reported to not have the .exe extension which can cause bugs on reloading. rNcSsg|]}d|qS)z-W%sr)rCorrrrisz'get_child_arguments..rQz-mr.z.exez %s-script.pyzScript %s does not exist.)rPrrargv executable warnoptionsrrQrrY with_suffixstr with_namename RuntimeError)rP py_scriptr#exe_entrypointscript_entrypointrrrget_child_argumentss"   rcCstd|tddS)Nz%s changed, reloading.r0)r[inforexit)rrrrtrigger_reloads rcCs<itjtdi}t} tj||dd}|jdkr|jSq )NtrueTF)env close_fdsr0)osenvironDJANGO_AUTORELOAD_ENVr subprocessrun returncode) new_environr#prrrrestart_with_reloaders rc@sneZdZddZddZdddZdd Zd d Zd d ZddZ e ddZ ddZ e ddZddZdS) BaseReloadercCs t|_tt|_t|_dSr?)rVr`rdirectory_globs threadingEvent_stop_conditionselfrrr__init__ s zBaseReloader.__init__cCs\t|}z|}Wntytjd|ddYdSwtd|||j||dS)Nz6Unable to watch directory %s as it cannot be resolved.T)rzWatching dir %s with glob %s.)rr^FileNotFoundErrorr[r\rr_)rrglobrrr watch_dirs  zBaseReloader.watch_dirTccsTtEdH|jEdH|r&|jD]\}}|D] }||EdHqqdSdS)zq Yield all files that need to be watched, including module files and files within globs. N)rNr`rrmr)r include_globs directorypatternspatternrrr watched_filess  zBaseReloader.watched_filescCs0|r|jjddr dS|stddS)a Wait until Django reports that the apps have been loaded. If the given thread has terminated before the apps are ready, then a SyntaxError or other non-recoverable error has been raised. In that case, stop waiting for the apps_ready event and continue processing. Return True if the thread is alive and the ready event has been triggered, or False if the thread is terminated while waiting for the event. 皙?timeoutTz8Main Django thread has terminated before apps are ready.F)is_alive ready_eventwaitr[r\)rapp_regdjango_main_threadrrrwait_for_apps_ready(s   z BaseReloader.wait_for_apps_readycCsdtd|t|ddlm}z|jWn ty Ynwtdtj |d| dS)NzWaiting for apps ready_event.r) get_resolverz>Apps ready_event triggered. Sending autoreload_started signal.)sender) r[r\rr django.urlsrurlconf_modulerautoreload_startedsendrun_loop)rrrrrrr:s        zBaseReloader.runcCs@|}|jszt|Wn tyYnw|jr|dSr?)tick should_stopnext StopIterationstop)rtickerrrrrKs   zBaseReloader.run_loopcCtd)aX This generator is called in a loop from run_loop. It's important that the method takes care of pausing or otherwise waiting for a period of time. This split between run_loop() and tick() is to improve the testability of the reloader implementations by decoupling the work they do from the loop. z!subclasses must implement tick().NotImplementedErrorrrrrrTszBaseReloader.tickcCr)Nz/subclasses must implement check_availability().rclsrrrcheck_availability^szBaseReloader.check_availabilitycCs>tj||d}td||tdd|Dst|dSdS)N)r file_pathz+%s notified as changed. Signal results: %s.css|]}|dVqdS)r.Nr)rCresrrrrEesz3BaseReloader.notify_file_changed..) file_changedrr[r\anyr)rrrcrrrnotify_file_changedbs  z BaseReloader.notify_file_changedcCs |jSr?)ris_setrrrrris zBaseReloader.should_stopcCs|jdSr?)rrVrrrrrmszBaseReloader.stopN)T)r __module__ __qualname__rrrrrrr classmethodrrpropertyrrrrrrrs      rc@s,eZdZdZddZddZeddZdS) StatReloaderr.ccszi} |D]*\}}||}|||<|dur!td||q||kr2td|||||qt|jdVq)NTz File %s first seen with mtime %sz-File %s previous mtime: %s, current mtime: %s)snapshot_filesgetr[r\rtimesleep SLEEP_TIME)rmtimesfilepathmtimeold_timerrrrts    zStatReloader.tickc csZt}|D]"}||vrqz|j}Wn tyYqw||||fVqdSr?)rVrstatst_mtimeOSErrorr_)r seen_filesfilerrrrrs    zStatReloader.snapshot_filescCsdS)NTrrrrrrszStatReloader.check_availabilityN)r rrrrrrrrrrrrqs rc@s eZdZdS)WatchmanUnavailableN)r rrrrrrrsrcseZdZfddZeddZddZeddZ d d Z d d Z d dZ ddZ ddZddZddZddZddZfddZd"ddZed d!ZZS)#WatchmanReloadercs6tt|_t|_ttj dd|_ t dS)NDJANGO_WATCHMAN_TIMEOUT) rrVrootsrrprocessed_requestintrrrclient_timeoutsuperrr __class__rrrs  zWatchmanReloader.__init__cCstj|jdS)Nr) pywatchmanclientrrrrrrszWatchmanReloader.clientcCst|s|jstd|dS|j}|jdt|}d|vr+td|dtd||d| dfS)Nz>Unable to watch root dir %s as neither it or its parent exist.z watch-projectwarningzWatchman warning: %sz!Watchman watch-project result: %swatch relative_path) rYrr[rrqueryrr^r\r)rrootresultrrr _watch_roots   zWatchmanReloader._watch_rootcCs|jd|dS)Nclock)rr)rrrrr _get_clockszWatchmanReloader._get_clockcCsn||\}}ddddgddgg|g}|dg||dd}|r$||d <td ||||jd |||dS) NallofanyoftypeflrT) expressionfieldssince dedup_results relative_rootz8Issuing watchman subscription %s, for root %s. Query: %s subscribe)rrr[r\rr)rrrrrrel_pathonly_files_expressionrrrr _subscribeszWatchmanReloader._subscribecsvs(jstddSdj}fdd|D}jd|dg}nd}d|g}|d|f|dS) N?Unable to watch directory %s as neither it or its parent exist.zfiles-parent-%scg|] }dj|fqSz%s/%sr)rCrrrrriz3WatchmanReloader._subscribe_dir..r wholenamefiles%s:%s)rYrr[rrr)rr filenamesrorrrr_subscribe_dirs    zWatchmanReloader._subscribe_dircsd}s$jstddSdj}fdd|D}jdg}|D] }|d|d gq)|d |f|dS) a Watch a directory with a specific glob. If the directory doesn't yet exist, attempt to watch the parent directory and amend the patterns to include this. It's important this method isn't called more than one per directory when updating all subscriptions. Subsequent calls will overwrite the named subscription, so it must include all possible glob expressions. rrNzglob-parent-%scrrr)rCrrrrrirz0WatchmanReloader._watch_glob..rmatchr r )rYrr[rrr"r)rrrrorrrrr _watch_globs    zWatchmanReloader._watch_globcCs8|j}dd|D}tt}tg|||RS)NcSrfrr)rCrrrrrirjz2WatchmanReloader.watched_roots..)rrMlistr}rL)rrextra_directorieswatched_file_dirs sys_pathsrrr watched_rootss  zWatchmanReloader.watched_rootscst|jdd}t||}tdt|td|t|D]}||q!|j D] \}| |q.t|ddd}t j |dddD]\}|fd d |DqJdS) NF)rzWatching %s fileszFound common roots: %scS|jSr?rrrrr z2WatchmanReloader._update_watches..)rkcSrr?rrrrrr rcsg|] }t|qSr)r relative_to)rCrrrrri rz4WatchmanReloader._update_watches..)rrr{rr[r\rsrFrrrmrrWgroupbyr )rr found_rootsrr sorted_filesgrouprrr_update_watchess   z WatchmanReloader._update_watchesc CsBz|WdSty }z ||rWYd}~dSd}~wwr?)rrcheck_server_status)rexrrrupdate_watchess zWatchmanReloader.update_watchescCsr|j|}|s dStd||D]$}t|dddd}td||dgD] }|||q,qdS)Nz%Watchman subscription %s has results. subscription:r.zFound root directory %sr )rgetSubscriptionr[r\rsplitrr)rsubr#rroot_directoryrrrr_check_subscriptions   z$WatchmanReloader._check_subscriptioncKstd|jdS)Nz0Request processed. Setting update_watches event.)r[r\rrV)rr$rrrrequest_processed% z"WatchmanReloader.request_processedc cst|j| |jr||jz|jWn't j y+Yn.t j yH}zt d|||WYd}~nd}~wwt|jjD]}||qQdVtdq )NTz+Watchman error: %s, checking server status.r)rconnectr*r"rrrurreceiver SocketTimeout WatchmanErrorr[r\r rsubsrMr)rr)rr!r'rrrr)s*      zWatchmanReloader.tickcs|jtdSr?)rcloserrrrrrr>r+zWatchmanReloader.stopNcCs0z |jdWdStytt||w)z'Return True if the server is available.versionT)rrrrr)rinner_exrrrr Bs  z$WatchmanReloader.check_server_statuscCshtstdtjdd}z|}Wn tytdwt|d}td||dkr2tddS) Nzpywatchman not installed.rrz'Cannot connect to the watchman service.r2zWatchman version %s) z"Watchman 4.9 or later is required.)rrrcapabilityCheckrr r[r\)rrrr2rrrrJs     z#WatchmanReloader.check_availabilityr?)r rrrr rrr+ lru_cacherrr rrrr"r)r*rrr rr __classcell__rrrrrs(     rcCs*ztWtStytYSw)z7Return the most suitable reloader for this environment.)rrrrrrrr get_reloader\s   r9c Ostt|}tj|||dd}d|_||jsJz||Wn#tyD}zt }t d|t d|j jWYd}~nd}~ww|jrdSdS)Nzdjango-main-thread)targetr#r$rTz Error connecting to Watchman: %s!Watching for file changes with %s)r>r-rThreaddaemonstartrrrrr[errorrrr )reloader main_funcr#r$rr!rrr start_djangoes rBcOsttjddz-tjtdkr,t}td|j j t ||g|Ri|WdSt }t |WdSty@YdSw)NcWs tdS)Nr)rr)r#rrrrys z#run_with_reloader..rr;)r8SIGTERMrrrrr9r[rrr rBrrrKeyboardInterrupt)rAr#r$r@ exit_coderrrrun_with_reloaderxs rF)=r+rWloggingrr8rrrrrrA collectionsrpathlibrtypesr zipimportrr django.appsrdjango.core.signalsrdjango.dispatchrdjango.utils.functionalr django.utils.versionr rrr getLoggerr[r!rr2 ImportErrorrrrr-r/r>rNr7rKr{r}rrrrrrrrr9rBrFrrrrsv                - % i&B