Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
advanced.py219 linesDownload Raw Back to samples
1# This extension demonstrates some advanced features of the Python ISAPI2# framework.3# We demonstrate:4# * Reloading your Python module without shutting down IIS (eg, when your5#   .py implementation file changes.)6# * Custom command-line handling - both additional options and commands.7# * Using a query string - any part of the URL after a '?' is assumed to8#   be "variable names" separated by '&' - we will print the values of9#   these server variables.10# * If the tail portion of the URL is "ReportUnhealthy", IIS will be11#   notified we are unhealthy via a HSE_REQ_REPORT_UNHEALTHY request.12#   Whether this is acted upon depends on if the IIS health-checking13#   tools are installed, but you should always see the reason written14#   to the Windows event log - see the IIS documentation for more.15 16import os17import stat18import sys19 20from isapi import isapicon21from isapi.simple import SimpleExtension22 23if hasattr(sys, "isapidllhandle"):24    import win32traceutil25 26# Notes on reloading27# If your HttpFilterProc or HttpExtensionProc functions raises28# 'isapi.InternalReloadException', the framework will not treat it29# as an error but instead will terminate your extension, reload your30# extension module, re-initialize the instance, and re-issue the request.31# The Initialize functions are called with None as their param.  The32# return code from the terminate function is ignored.33#34# This is all the framework does to help you.  It is up to your code35# when you raise this exception.  This sample uses a Win32 "find36# notification".  Whenever windows tells us one of the files in the37# directory has changed, we check if the time of our source-file has38# changed, and set a flag.  Next imcoming request, we check the flag and39# raise the special exception if set.40#41# The end result is that the module is automatically reloaded whenever42# the source-file changes - you need take no further action to see your43# changes reflected in the running server.44 45# The framework only reloads your module - if you have libraries you46# depend on and also want reloaded, you must arrange for this yourself.47# One way of doing this would be to special case the import of these48# modules.  Eg:49# --50# try:51#    my_module = reload(my_module) # module already imported - reload it52# except NameError:53#    import my_module # first time around - import it.54# --55# When your module is imported for the first time, the NameError will56# be raised, and the module imported.  When the ISAPI framework reloads57# your module, the existing module will avoid the NameError, and allow58# you to reload that module.59 60import threading61 62import win32con63import win32event64import win32file65import winerror66 67from isapi import InternalReloadException68 69try:70    reload_counter += 171except NameError:72    reload_counter = 073 74 75# A watcher thread that checks for __file__ changing.76# When it detects it, it simply sets "change_detected" to true.77class ReloadWatcherThread(threading.Thread):78    def __init__(self):79        self.change_detected = False80        self.filename = __file__81        if self.filename.endswith("c") or self.filename.endswith("o"):82            self.filename = self.filename[:-1]83        self.handle = win32file.FindFirstChangeNotification(84            os.path.dirname(self.filename),85            False,  # watch tree?86            win32con.FILE_NOTIFY_CHANGE_LAST_WRITE,87        )88        threading.Thread.__init__(self)89 90    def run(self):91        last_time = os.stat(self.filename)[stat.ST_MTIME]92        while 1:93            try:94                rc = win32event.WaitForSingleObject(self.handle, win32event.INFINITE)95                win32file.FindNextChangeNotification(self.handle)96            except win32event.error as details:97                # handle closed - thread should terminate.98                if details.winerror != winerror.ERROR_INVALID_HANDLE:99                    raise100                break101            this_time = os.stat(self.filename)[stat.ST_MTIME]102            if this_time != last_time:103                print("Detected file change - flagging for reload.")104                self.change_detected = True105                last_time = this_time106 107    def stop(self):108        win32file.FindCloseChangeNotification(self.handle)109 110 111# The ISAPI extension - handles requests in our virtual dir, and sends the112# response to the client.113class Extension(SimpleExtension):114    "Python advanced sample Extension"115 116    def __init__(self):117        self.reload_watcher = ReloadWatcherThread()118        self.reload_watcher.start()119 120    def HttpExtensionProc(self, ecb):121        # NOTE: If you use a ThreadPoolExtension, you must still perform122        # this check in HttpExtensionProc - raising the exception from123        # The "Dispatch" method will just cause the exception to be124        # rendered to the browser.125        if self.reload_watcher.change_detected:126            print("Doing reload")127            raise InternalReloadException128 129        url = ecb.GetServerVariable("UNICODE_URL")130        if url.endswith("ReportUnhealthy"):131            ecb.ReportUnhealthy("I'm a little sick")132 133        ecb.SendResponseHeaders("200 OK", "Content-Type: text/html\r\n\r\n", 0)134        print("<HTML><BODY>", file=ecb)135 136        qs = ecb.GetServerVariable("QUERY_STRING")137        if qs:138            queries = qs.split("&")139            print("<PRE>", file=ecb)140            for q in queries:141                val = ecb.GetServerVariable(q, "&lt;no such variable&gt;")142                print("%s=%r" % (q, val), file=ecb)143            print("</PRE><P/>", file=ecb)144 145        print("This module has been imported", file=ecb)146        print("%d times" % (reload_counter,), file=ecb)147        print("</BODY></HTML>", file=ecb)148        ecb.close()149        return isapicon.HSE_STATUS_SUCCESS150 151    def TerminateExtension(self, status):152        self.reload_watcher.stop()153 154 155# The entry points for the ISAPI extension.156def __ExtensionFactory__():157    return Extension()158 159 160# Our special command line customization.161# Pre-install hook for our virtual directory.162def PreInstallDirectory(params, options):163    # If the user used our special '--description' option,164    # then we override our default.165    if options.description:166        params.Description = options.description167 168 169# Post install hook for our entire script170def PostInstall(params, options):171    print()172    print("The sample has been installed.")173    print("Point your browser to /AdvancedPythonSample")174    print("If you modify the source file and reload the page,")175    print("you should see the reload counter increment")176 177 178# Handler for our custom 'status' argument.179def status_handler(options, log, arg):180    "Query the status of something"181    print("Everything seems to be fine!")182 183 184custom_arg_handlers = {"status": status_handler}185 186if __name__ == "__main__":187    # If run from the command-line, install ourselves.188    from isapi.install import *189 190    params = ISAPIParameters(PostInstall=PostInstall)191    # Setup the virtual directories - this is a list of directories our192    # extension uses - in this case only 1.193    # Each extension has a "script map" - this is the mapping of ISAPI194    # extensions.195    sm = [ScriptMapParams(Extension="*", Flags=0)]196    vd = VirtualDirParameters(197        Name="AdvancedPythonSample",198        Description=Extension.__doc__,199        ScriptMaps=sm,200        ScriptMapUpdate="replace",201        # specify the pre-install hook.202        PreInstall=PreInstallDirectory,203    )204    params.VirtualDirs = [vd]205    # Setup our custom option parser.206    from optparse import OptionParser207 208    parser = OptionParser("")  # blank usage, so isapi sets it.209    parser.add_option(210        "",211        "--description",212        action="store",213        help="custom description to use for the virtual directory",214    )215 216    HandleCommandLine(217        params, opt_parser=parser, custom_arg_handlers=custom_arg_handlers218    )219 
codekingpro/portable-devtools · Team Ai