""" [ urlimport.py ] Enables remote module importing. version: 0.42b author: Jure Vrscaj homepage: http://urlimport.codeshift.net license: GNU GPL == history == v0.42b 2006-12-30 - added support for DOS-style source files - eval() chokes on "\r\n" v0.42 2006-06-26 - added verbose mode setting v0.41 2006-06-05 - client ssl certificate support v0.32 2006-05-10 - ftp, https support :) v0.31 2006-02-24 - recursion patch: non-packages now have no __path__ - load_module now returns the module from sys.modules, in case the module itself was messing with sys.modules v0.30 2006-02-23 package importing now possible v0.02 2006-02-23 remote modules now first check own url when they have to import sth v0.01 2006-02-19 made basic (single-file) importing v0.00 2006-02-18 playing with path_hooks """ import sys, os, re import imp re_url_ok = re.compile(r'^http://|^ftp://|^https://') re_url_split = re.compile('^(.+):\/\/(.+?)(?::(\d+))?(\/.*)$') settings = sys.__dict__.setdefault( 'urlimport_settings', {'ssl_cert': '', 'ssl_key': '', 'debug': 1} ) def debug(s, pf='| |', lvl=1): if lvl <= settings.get('debug'): print "%s %s" % (pf, s) class UrlFinder: def __init__(self, path): if re_url_ok.match(path): debug("UrlFinder: accepting '%s'." % path, lvl=2) self.path = path if not self.path.endswith("/"): self.path += '/' else: debug("UrlFinder: rejecting non-url path item: '%s'" % path, lvl=3) raise ImportError def find_module(self, fullname, mpath=None): """try to locate the remote module, do this: a) try to get fullname.py from http://self.path/ b) try to get __init__.py from http://self.path/fullname/ """ fullname = fullname.split('.')[-1] for url, path in [ (self.path + fullname + '.py', None), (self.path + fullname + '/__init__.py', self.path + fullname + '/')]: try: source = self.get_source(url) except Exception, e: debug("find_module: failed to get '%s'. (%s)" % (url, e), lvl=3) else: debug("find_module: got '%s'." % url, lvl=1) return UrlLoader(url, path, source) return None def get_source(self, url): """Download the source from given url. """ from urllib2 import urlopen src = '' key = settings.get('ssl_key') cert = settings.get('ssl_cert') proto, host, port, path = re_url_split.findall(url)[0] try: port = int(port) except: port = 443 if proto == 'https' and cert: # handle http over ssl with client certificate import httplib conn = httplib.HTTPSConnection( host=host, port=port, key_file=key, cert_file=cert, ) conn.putrequest('GET', path) conn.endheaders() response = conn.getresponse() if response.status != 200: raise StandardError, "HTTPS Error: %d"%response.status src = response.read() else: # handle everything else src = urlopen(url).read() src = src.replace("\r\n", "\n") return src class UrlLoader: def __init__(self, url, path, source): self.url = url self.path = path self.source = source self._files = {} def load_module(self, fullname): """add the new module to sys.modules, execute its source and return it """ mod = sys.modules.setdefault(fullname, imp.new_module(fullname)) mod.__file__ = "%s" % self.url mod.__loader__ = self if self.path: mod.__path__ = [self.path] for line in self.source.split('\n'): debug(line, pf='|>|', lvl=4) debug("load_module: executing %s's source..." % fullname, lvl=2) exec self.source in mod.__dict__ mod = sys.modules[fullname] return mod def config(**kwargs): """config(key=value) - Set key to value. config() - Display settings. """ settings.update(kwargs) for k,v in (kwargs or settings).iteritems(): debug(" "+str(k)+"="+repr(v), lvl=0 ) # register The Hook sys.path_hooks = [x for x in sys.path_hooks if x.__name__ != 'UrlFinder'] sys.path_hooks.append(UrlFinder) #sys.path_importer_cache.clear() debug("Url importing enabled. Add urls to sys.path.", lvl=0) debug("Use urlimport.config(key=value) to manipulate settings:", lvl=0) # print settings config() debug("", lvl=0) debug("This stuff is experimental, use at your own risk. Enjoy.", lvl=0)