Using PythonService.exe to host python service while using virtualenv

前端 未结 4 1001
太阳男子
太阳男子 2020-12-05 20:28

I\'ve got a Windows 7 environment where I need to develop a Python Windows Service using Python 3.4. I\'m using pywin32\'s win32service module to setup the service and most

4条回答
  •  無奈伤痛
    2020-12-05 21:12

    It appears this used to work correctly with the virtualenv module before virtual environments were added to Python 3.3. There's anecdotal evidence (see this answer: https://stackoverflow.com/a/12424980/1055722) that Python's site.py used to look upward from the executable file until it found a directory that would satisfy imports. It would then use that for sys.prefix and this was sufficient for PythonService.exe to find the virtualenv it was inside of and use it.

    If that was the behavior, it appears that site.py no longer does that with the introduction of the venv module. Instead, it looks one level up for a pyvenv.cfg file and configures for a virtual environment in that case only. This of course doesn't work for PythonService.exe which is buried down in the pywin32 module under site-packages.

    To work around it, I adapted the activate_this.py code that comes with the original virtualenv module (see this answer: https://stackoverflow.com/a/33637378/1055722). It is used to bootstrap an interpreter embedded in an executable (which is the case with PythonService.exe) into using a virtualenv. Unfortunately, venv does not include this.

    Here's what worked for me. Note, this assumes the virtual environment is named my-venv and is located one level above the source code location.

    import os
    import sys
    
    if sys.executable.endswith("PythonService.exe"):
    
        # Change current working directory from PythonService.exe location to something better.
        service_directory = os.path.dirname(__file__)
        source_directory = os.path.abspath(os.path.join(service_directory, ".."))
        os.chdir(source_directory)
        sys.path.append(".")
    
        # Adapted from virtualenv's activate_this.py
        # Manually activate a virtual environment inside an already initialized interpreter.
        old_os_path = os.environ['PATH']
        venv_base = os.path.abspath(os.path.join(source_directory, "..", "my-venv"))
        os.environ['PATH'] = os.path.join(venv_base, "Scripts") + os.pathsep + old_os_path
        site_packages = os.path.join(venv_base, 'Lib', 'site-packages')
        prev_sys_path = list(sys.path)
        import site
        site.addsitedir(site_packages)
        sys.real_prefix = sys.prefix
        sys.prefix = venv_base
    
        new_sys_path = []
        for item in list(sys.path):
            if item not in prev_sys_path:
                new_sys_path.append(item)
                sys.path.remove(item)
        sys.path[:0] = new_sys_path
    

    One other factor in my troubles - there is a new pypi wheel for pywin32 that is provided by the Twisted folks that makes it easier to install with pip. The PythonService.exe in that package was acting oddly (couldn't find a pywin32 dll when invoked) compared to the one you get when installing the official win32 exe package into the virtual env using easy_install.

提交回复
热议问题