2012-03-17 11 views
5

He trabajado mediante la instalación de Python como una aplicación CGI en IIS en Windows 7. Esto es bastante sencillo, pero me gustaría usar el WSGI, para una mejor flexibilidad.¿Cómo instalar correctamente isapi_wsgi en IIS para Python2.7?

he descargado el archivo para isapi_wsgi, la abrió, y luego corrió la instalación según the instructions, así:

\python27\python.exe setup.py install 

Esto sucedió:

enter image description here

Entonces codificados a. El módulo py tenía el pegamento wsgi y trató de instalarlo. Esto fracasó así:

enter image description here

Es un error COM Moniker, y sé que la materia de gestión compatible con IIS6 está basado en COM Monikers, que me recordó que no es un pre-requisito para isapi_wsgi de la Cosas de administración compatibles con IIS6. Ejecuté \windows\system32\OptionalFeatures.exe y lo instalé, luego volví a ejecutar el módulo .py y lo instalé correctamente.

C:\dev\wsgi>\Python27\python.exe app1_wsgi.py 
Configured Virtual Directory: /wsgi 
Installation complete. 

Ok, maravilloso. Ahora cuando miro en el directorio actual, veo una nueva DLL llamada _app1_wsgi.dll, y cuando miro en el Administrador de IIS puedo ver un nuevo vdir de IIS, y un mapa de script dentro de ese vdir para '*', que está mapeado al _app1_wsgi.DLL. Todo bien. ¡Pero! haciendo una solicitud al http://localhost/wsgi me da un error de 500.

A través de un ensayo y error veo que el módulo .py que define mis controladores debe estar en el directorio de paquetes de sitio. Estoy muy sorprendido por esto.

¿Puedo evitar esto? ¿Puedo simplemente colocar el módulo .py en el mismo directorio que el archivo .dll generado? ¿O debo implementar toda mi lógica de python en paquetes de sitio para ejecutarlo desde el mecanismo de WSGI?

+0

¿Huh? No. Esto no es un servidor, es una estación de trabajo dev. Estoy haciendo una pregunta sobre una práctica de desarrollo de Python. – Cheeso

Respuesta

1

La respuesta es:

  • la instalación de isapi_wsgi como se describe en la pregunta, es correcta.

  • con la plantilla estándar de app.py como se muestra en el código de ejemplo que acompaña a isapi_wsgi, las clases de python para la aplicación web deben estar en el directorio site-packages.

  • es posible permitir que los módulos fuente de python residan en el mismo directorio que con el archivo * .dll generado, pero requiere un manejo especial en el archivo * wsgi.py.

  • una mejor forma de ejecutar python en Windows para fines de desarrollo es simplemente descargar Google App Engine y usar el servidor http dedicado incorporado. El marco que viene con GAE SDK maneja la recarga y permite que los módulos .py se coloquen en directorios particulares.


Si no desea descargar e instalar el SDK GAE, entonces es posible que intente lo siguiente. Usando este código, cuando llega una solicitud a isapi_wsgi, el controlador busca en el directorio de inicio un módulo py y lo carga.Si el módulo ya está cargado, verifica el archivo "última hora de modificación" y vuelve a cargar el módulo si la última hora del mod es posterior al tiempo de la carga anterior. Funciona para casos simplistas, pero supongo que será frágil cuando haya dependencias de módulos anidados.

import sys 
import os 
import win32file 
from win32con import * 

# dictionary of [mtime, module] tuple; uses file path as key 
loadedPages = {} 

def request_handler(env, start_response): 
    '''Demo app from wsgiref''' 
    cr = lambda s='': s + '\n' 
    if hasattr(sys, "isapidllhandle"): 
     h = None 
     # get the path of the ISAPI Extension DLL 
     hDll = getattr(sys, "isapidllhandle", None) 
     import win32api 
     dllName = win32api.GetModuleFileName(hDll) 
     p1 = repr(dllName).split('?\\\\') 
     p2 = p1[1].split('\\\\') 
     sep = '\\' 
     homedir = sep.join(p2[:-1]) 

     # the name of the Python module is in the PATH_INFO 
     moduleToImport = env['PATH_INFO'].split('/')[1] 

     pyFile = homedir + sep + moduleToImport + '.py' 

     fd = None 
     try: 
      fd = win32file.CreateFile(pyFile, GENERIC_READ, FILE_SHARE_DELETE, None, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0) 
     except Exception as exc1: 
      fd = None 

     if fd is not None: 
      # file exists, get mtime 
      fd.close() 
      mt = os.path.getmtime(pyFile) 
     else: 
      mt = None 


     if mt is not None: 
      h = None 
      if not pyFile in loadedPages: 
       # need a new import 
       if homedir not in sys.path: 
        sys.path.insert(0, homedir) 

       h = __import__(moduleToImport, globals(), locals(), []) 
       # remember 
       loadedPages[pyFile] = [mt, h] 
      else: 
       # retrieve handle to module 
       h = loadedPages[pyFile][1] 
       if mt != loadedPages[pyFile][0]: 
        # need to reload the page 
        reload(h) 
        loadedPages[pyFile][0] = mt 

      if h is not None: 
       if 'handler' in h.__dict__: 
        for x in h.handler(env, start_response): 
         yield x 
       else: 
        start_response("400 Bad Request", [('Content-Type', 'text/html')]) 
      else: 
       start_response("404 Not Found", [('Content-Type', 'text/html')]) 
       yield cr() 
       yield cr("<html><head><title>Module not found</title>" \ 
          "</head><body>") 
       yield cr("<h3>404 Not Found</h3>") 
       yield cr("<h3>No handle</h3></body></html>") 

     else: 
      start_response("404 Not Found", [('Content-Type', 'text/html')]) 
      yield cr() 
      yield cr("<html><head><title>Module not found</title>" \ 
       "</head><body>") 
      yield cr("<h3>404 Not Found</h3>") 
      yield cr("<h3>That module (" + moduleToImport + ") was not found.</h3></body></html>") 


    else: 
     start_response("500 Internal Server Error", [('Content-Type', 'text/html')]) 
     yield cr() 
     yield cr("<html><head><title>Server Error</title>" \ 
       "</head><body><h1>Server Error - No ISAPI Found</h1></body></html>") 


# def test(environ, start_response): 
#  '''Simple app as per PEP 333''' 
#  status = '200 OK' 
#  start_response(status, [('Content-type', 'text/plain')]) 
#  return ['Hello world from isapi!'] 


import isapi_wsgi 
# The entry point(s) for the ISAPI extension. 
def __ExtensionFactory__(): 
    return isapi_wsgi.ISAPISimpleHandler(request_handler) 


def PostInstall(params, options): 
    print "The Extension has been installed" 


# Handler for our custom 'status' argument. 
def status_handler(options, log, arg): 
    "Query the status of the ISAPI?" 
    print "Everything seems to be fine..." 


if __name__=='__main__': 
    # This logic gets invoked when the script is run from the command-line. 
    # In that case, it installs this module as an ISAPI. 

    # 
    # The API provided by isapi_wsgi for this is a bit confusing. There 
    # is an ISAPIParameters object. Within that object there is a 
    # VirtualDirs property, which itself is a list of 
    # VirtualDirParameters objects, one per vdir. Each vdir has a set 
    # of scriptmaps, usually this set of script maps will be a wildcard 
    # (*) so that all URLs in the vdir will be served through the ISAPI. 
    # 
    # To configure a single vdir to serve Python scripts through an 
    # ISAPI, create a scriptmap, and stuff it into the 
    # VirtualDirParameters object. Specify the vdir path and other 
    # things in the VirtualDirParameters object. Stuff that vdp object 
    # into a sequence and set it into the ISAPIParameters thing, then 
    # call the vaguely named "HandleCommandLine" function, passing that 
    # ISAPIParameters thing. 
    # 
    # Clear as mud? 
    # 
    # Seriously, this thing could be so much simpler, if it had 
    # reasonable defaults and a reasonable model, but I guess it will 
    # work as is. 

    from isapi.install import * 

    # Setup the virtual directories - 
    # To serve from root, set Name="/" 
    sm = [ ScriptMapParams(Extension="*", Flags=0) ] 
    vdp = VirtualDirParameters(Name="wsgi", # name of vdir/IIS app 
           Description = "ISAPI-WSGI Demo", 
           ScriptMaps = sm, 
           ScriptMapUpdate = "replace" 
          ) 

    params = ISAPIParameters(PostInstall = PostInstall) 
    params.VirtualDirs = [vdp] 
    cah = {"status": status_handler} 

    # from isapi.install, part of pywin32 
    HandleCommandLine(params, custom_arg_handlers = cah) 

Usando este modelo, solicitando http://foo/wsgi/bar intentará bar.py carga desde el directorio personal con el archivo .dll WSGI. Si bar.py no se puede encontrar, obtienes un 404. Si bar.py se ha actualizado desde la última ejecución, vuelve a cargarse. Si la barra no se puede cargar, obtendrá un 500.

bar.py debe exportar públicamente un método llamado handler. Ese método debe ser un generador. de este modo:

import time 

def handler(env, start_response): 
    start_response("200 OK", [('Content-Type', 'text/html')]) 
    cr = lambda s='': s + '\n' 
    yield cr("<html><head><title>Hello world!</title></head><body>") 
    yield cr("<h1>Bargle Bargle Bargle</h1>") 
    yield cr("<p>From the handler...</p>") 
    yield cr("<p>(bargle)</p>") 
    yield cr("<p>The time is now: " + time.asctime() + " </p>") 
    yield cr("</body></html>") 

__all__ = ['handler'] 

Pero como ya he dicho, creo que GAE es probablemente una mejor manera de desarrollar aplicaciones web Python que utilizan Windows.

-2

poner esto en la parte superior de su alforja

sitio de importación site.addsitedir ('ruta/a/su/site-packages')

el mismo problema que tenía, se resolvió con estos dos líneas

Cuestiones relacionadas