Hi everyone,

I just wanted to share the attached code. It is an init script that can be used to load modules on-demand, e.g. from a remote location. To use it, you just have to create a "library.zip" with cx_Freeze. The files in this zip file can then be put anywhere, say, an internet server. The init script does not implement this functionality but it shows how it could easily be done by subclassing the class AbstractBlobImporter.

Regards,
Markus

#------------------------------------------------------------------------------
#
# Init script for cx_Freeze with custom importer
#
# Written by Markus Meyer <meyer at mesw dot de>
#
# Note: This method ONLY works if you specify the --append-script-to-exe
#       option to cx_Freeze. This way, both the init script AND the main
#       script of your application are appended to the executable. If you
#       don't use this option, both the init script AND the main script of
#       your application are put into "library.zip", but this will fail on
#       runtime because the base executable does not know our custom import
#       mechanics. If you specify, the --append-script-to-exe option, you make
#       sure that the base executable can load the init script. From here, you
#       can do anything you want.
#
# This script is derived from:
#
# Console.py
#   Initialization script for cx_Freeze which manipulates the path so that the
# directory in which the executable is found is searched for extensions but
# no other directory is searched. It also sets the attribute sys.frozen so that
# the Win32 extensions behave as expected.
#------------------------------------------------------------------------------

import encodings
import os
import imp
import sys
import marshal
import warnings
import zipfile

class AbstractBlobImporter:
    """
    This is the base class for all blob importers. A blob importer is an
    importer for Python's sys.meta_path facility which can load binary code
    objects ('blobs') over a defined protocol. Think 'zipimport', but not only
    for ZIP files, but also for RAR files, FTP connections etc.
    
    See the class ZipFileBlobImporter for an example which reimplements
    zipimport using AbstractBlobImporter importer.
    """
    def find_module(self, fullname, path=None):
        """
        Implement find_module() importer function
        
        See PEP 302 for details
        """
        if self._get_path(fullname) is None:
            return None
        else:
            return self
        
    def load_module(self, fullname):
        """
        Implement load_module() importer function
        
        See PEP 302 for details
        """
        ispkg, code = self._get_code(fullname)
        mod = sys.modules.setdefault(fullname, imp.new_module(fullname))
        mod.__file__ = "<%s>" % self.__class__.__name__
        mod.__loader__ = self
        if ispkg:
            mod.__path__ = []
            
        # Execute startup code, eventually loading more modules
        exec code in mod.__dict__
        
        return mod
        
    def _get_path(self, fullname):
        """
        Helper function for getting full path and file name where a given
        module name resides
        """
        # Replace module separator with path separator
        fullname = fullname.replace(".", "/")
        
        for ext in [".pyo", ".pyc"]:
            # Check if it is a module
            path = fullname + ext
            if self.is_blob_available(path):
                return False, path
                
            # Check if it is a package
            path = fullname + "/__init__" + ext
            if self.is_blob_available(path):
                return True, path
            
        return None
        
    def _get_code(self, fullname):
        """
        Helper function to get Python code object for given module name
        """
        ispkg, path = self._get_path(fullname)
        s = self.get_blob(path)
        code_obj = marshal.loads(s[8:]) # strip pyo/pyc file header
        return ispkg, code_obj
        
    def get_blob(self, path):
        """
        This function must be overriden in your subclass. It is given a
        (relative) path to the pyc/pyo file. You should load the pyc/pyo from
        this path (the path is "virtual" in that it does not physically need
        to exist on the file system) and return a Python string which contains
        the contents of the pyc/pyo file.
        
        The given virtual path will always use "/" as the path separator,
        even on Windows system.
        """
        raise NotImplementedError()
        
    def is_blob_available(self, path):
        """
        This function must be overriden in your subclass. It is given a
        (relative) path to the pyc/pyo file. Return True if this pyc/pyo file
        exists in your virtual file system, False otherwise.
        
        The given virtual path will always use "/" as the path separator,
        even on Windows system.
        """
        raise NotImplementedError()


class ZipFileBlobImporter(AbstractBlobImporter):
    """
    This is a simple class which basically emulates zipimport via subclassing
    from the blob importer. It loads the code objects from a ZIP file.
    You can use this class as a starting point for loading the code from
    any other source. For example, you could load the code objects (*.py[c|o]
    files) from a RAR file, over the network using a socket connection, from
    a website etc.
    """
    def __init__(self, filename):
        self._zip = zipfile.ZipFile(filename, "r")
        
    def get_blob(self, path):
        return self._zip.read(path)
        
    def is_blob_available(self, path):
        return path in self._zip.namelist()


#
# Add hook for the importer
#
exe_dir = os.path.abspath(os.path.dirname(sys.argv[0]))
sys.meta_path.append(
    ZipFileBlobImporter(os.path.join(exe_dir, "library.zip")))

#
# Remove everything from the path except the executable path
# (for loading binary extensions)
#
sys.path = [exe_dir]

#
# Bootstrap code (taken from cx_Freeze's Console.py)
#
sys.frozen = True

os.environ["TCL_LIBRARY"] = os.path.join(DIR_NAME, "tcl")
os.environ["TK_LIBRARY"] = os.path.join(DIR_NAME, "tk")

m = __import__("__main__")
import zipimport
importer = zipimport.zipimporter(INITSCRIPT_ZIP_FILE_NAME)
moduleName = m.__name__
code = importer.get_code(moduleName)
exec code in m.__dict__

if sys.version_info[:2] >= (2, 5):
    module = sys.modules.get("threading")
    if module is not None:
        module._shutdown()
-------------------------------------------------------------------------
This SF.Net email is sponsored by the Moblin Your Move Developer's challenge
Build the coolest Linux based applications with Moblin SDK & win great prizes
Grand prize is a trip for two to an Open Source event anywhere in the world
http://moblin-contest.org/redirect.php?banner_id=100&url=/
_______________________________________________
cx-freeze-users mailing list
cx-freeze-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/cx-freeze-users

Reply via email to