mirror of
https://github.com/Team-Resurgent/XBMC4Xbox.git
synced 2026-08-15 11:18:13 -07:00
If ever adding the XBMC4Xbox source to GitHub use "git add -f -A" or it wont add all the files.
675 lines
23 KiB
Python
675 lines
23 KiB
Python
#!/usr/bin/env python
|
|
|
|
__version__ = '1.3.13'
|
|
__release__ = '1'
|
|
|
|
DEBUG_ERROR = 0
|
|
|
|
##################################################
|
|
# SPYCE - Python-based HTML Scripting
|
|
# Copyright (c) 2002 Rimon Barr.
|
|
#
|
|
# Refer to LICENCE for legalese
|
|
#
|
|
# Name: spyce
|
|
# Author: Rimon Barr <rimon-AT-acm.org>
|
|
# Start date: 8 April 2002
|
|
# Purpose: Python Server Pages
|
|
# WWW: http://spyce.sourceforge.net/
|
|
# CVS: $Id: spyce.py 31144 2012-07-15 15:38:56Z buzz $
|
|
##################################################
|
|
|
|
# note: doc string used in documentation: doc/index.spy
|
|
__doc__ = '''SPYCE is a server-side language that supports simple and
|
|
efficient Python-based dynamic HTML generation, otherwise called <i>Python
|
|
Server Pages</i> (PSP). Those who are familiar with JSP, PHP, or ASP and like
|
|
Python, should have a look at Spyce. Its modular design makes it very flexible
|
|
and extensible. It can also be used as a command-line utility for static text
|
|
pre-processing or as a web-server proxy.'''
|
|
|
|
import sys, os, copy, string, imp
|
|
import spyceConfig, spyceCompile, spyceException
|
|
import spyceModule, spyceTag
|
|
import spyceLock, spyceCache, spyceUtil
|
|
|
|
##################################################
|
|
# Spyce engine globals
|
|
#
|
|
|
|
# spyceServer object - one per engine instance
|
|
SPYCE_SERVER = None
|
|
def getServer(
|
|
config_file=None,
|
|
overide_www_port=None,
|
|
overide_www_root=None,
|
|
force=0):
|
|
global SPYCE_SERVER
|
|
if force or not SPYCE_SERVER:
|
|
SPYCE_SERVER = spyceServer(
|
|
config_file=config_file,
|
|
overide_www_root=overide_www_root,
|
|
overide_www_port=overide_www_port,
|
|
)
|
|
return SPYCE_SERVER
|
|
|
|
SPYCE_GLOBALS = None
|
|
def getServerGlobals():
|
|
global SPYCE_GLOBALS
|
|
return SPYCE_GLOBALS
|
|
|
|
SPYCE_LOADER = 'spyceLoader'
|
|
SPYCE_ENTRY = 'SPYCE_ENTRY'
|
|
DEFAULT_MODULES = ('request', 'response', 'stdout', 'error')
|
|
|
|
##################################################
|
|
# Spyce core objects
|
|
#
|
|
|
|
class spyceServerObject:
|
|
"serverObject placeholder"
|
|
pass
|
|
|
|
class spyceServer:
|
|
"One per server, stored in SPYCE_SERVER (above) at processing of first request."
|
|
def __init__(self,
|
|
config_file=None,
|
|
overide_www_root=None,
|
|
overide_www_port=None,
|
|
):
|
|
global SPYCE_GLOBALS
|
|
# server object
|
|
self.serverobject = spyceServerObject()
|
|
# http headers
|
|
try: self.entry = os.environ[SPYCE_ENTRY]
|
|
except: self.entry = 'UNKNOWN'
|
|
self.spyceHeader = 'Spyce/%s_%s Python/%s' % (self.entry, str(__version__), sys.version[:3])
|
|
# configuration dictionary
|
|
self.config = spyceConfig.spyceConfig(
|
|
file=config_file,
|
|
overide_www_root=overide_www_root,
|
|
overide_www_port=overide_www_port,
|
|
)
|
|
# server globals/constants
|
|
self.globals = self.config.getSpyceGlobals()
|
|
SPYCE_GLOBALS = self.globals # hack
|
|
# now finish processing config file; this way imported modules have
|
|
# access to the globals
|
|
self.config.process ()
|
|
# spyce module search path
|
|
self.path = self.config.getSpycePath()
|
|
# concurrency mode
|
|
self.concurrency = self.config.getSpyceConcurrency()
|
|
# imports
|
|
self.imports = self.config.getSpyceImport()
|
|
# debug mode
|
|
self.debug = self.config.getSpyceDebug()
|
|
# spyce cache
|
|
type, info = self.config.getSpyceCache()
|
|
if type in ('file',):
|
|
type = spyceCache.fileCache(info)
|
|
elif type in ('mem', 'memory'):
|
|
type = spyceCache.memoryCache(info)
|
|
else: type = spyceCache.memoryCache()
|
|
if self.debug: type = None
|
|
self.spyce_cache = spyceCache.semanticCache(type, spyceCacheValid, spyceCacheGenerate)
|
|
# spyce module cache
|
|
self.module_cache = {}
|
|
if self.debug:
|
|
self.module_cache = None
|
|
# page error handler
|
|
pageerror = self.config.getSpycePageError()
|
|
if pageerror[0]=='string':
|
|
pageerror = pageerror[0], self.loadModule(pageerror[2], pageerror[1]+'.py')
|
|
self.pageerror = pageerror
|
|
# engine error handler
|
|
error = self.config.getSpyceError()
|
|
self.error = self.loadModule(error[1], error[0]+'.py')
|
|
# spyce thread-safe stdout object
|
|
if self.concurrency == spyceConfig.SPYCE_CONCURRENCY_THREAD:
|
|
self.stdout = spyceUtil.ThreadedWriter(sys.stdout)
|
|
self.lock = spyceLock.threadLock()
|
|
sys.stdout = self.stdout
|
|
else:
|
|
self.stdout = None
|
|
self.lock = spyceLock.dummyLock()
|
|
# set sys.stdout
|
|
def loadModule(self, name, file=None, rel_file=None):
|
|
"Find and load a module, with caching"
|
|
if not file: file=name+'.py'
|
|
key = name, file, rel_file
|
|
if self.module_cache!=None:
|
|
try: return self.module_cache[key]
|
|
except: pass # cache miss
|
|
def loadModuleHelper(file=file, rel_file=rel_file, path=self.path):
|
|
if rel_file: path = path + [os.path.dirname(rel_file)]
|
|
for p in path:
|
|
f=None
|
|
try:
|
|
p = os.path.join(p, file)
|
|
if os.path.exists(p) and os.access(p, os.R_OK):
|
|
f = open(p, 'r')
|
|
return imp.load_source(SPYCE_LOADER, p, f)
|
|
finally:
|
|
if f: f.close()
|
|
raise 'unable to find module "%s" in path: %s' % (file, path)
|
|
# load and cache module
|
|
dict = {'loadModuleHelper': loadModuleHelper}
|
|
exec 'foo = loadModuleHelper()' in dict
|
|
mod = eval('dict["foo"].%s' % name)
|
|
if self.module_cache!=None:
|
|
self.module_cache[key] = mod
|
|
return mod
|
|
def fileHandler(self, request, response, filename, sig='', args=None, kwargs=None):
|
|
return self.commonHandler(request, response, ('file', (filename, sig)), args, kwargs)
|
|
def stringHandler(self, request, response, code, sig='', args=None, kwargs=None):
|
|
return self.commonHandler(request, response, ('string', (code, sig)), args, kwargs)
|
|
def commonHandler(self, request, response, spyceInfo, args=None, kwargs=None):
|
|
"Handle a request. This method is NOT thread safe."
|
|
try:
|
|
thespyce = theError = None
|
|
try:
|
|
spycecode = self.spyce_cache[spyceInfo]
|
|
thespyce = spycecode.newWrapper()
|
|
response.addHeader('X-Spyce', self.spyceHeader, 1)
|
|
try:
|
|
thespyce.spyceInit(request, response)
|
|
if args==None: args=[]
|
|
if kwargs==None: kwargs={}
|
|
apply(thespyce.spyceProcess, args, kwargs)
|
|
except spyceException.spyceRuntimeException, theError: pass
|
|
finally:
|
|
if DEBUG_ERROR and theError:
|
|
sys.stderr.write(`theError`+'\n')
|
|
if thespyce:
|
|
thespyce.spyceDestroy(theError)
|
|
spycecode.returnWrapper(thespyce)
|
|
except spyceException.spyceDone: pass
|
|
except spyceException.spyceRedirect, e:
|
|
return spyceFileHandler(request, response, e.filename)
|
|
except KeyboardInterrupt: raise
|
|
except (spyceException.spyceNotFound, spyceException.spyceForbidden,
|
|
spyceException.spyceSyntaxError, spyceException.pythonSyntaxError,
|
|
SyntaxError), e:
|
|
return self.error(self, request, response, e)
|
|
except SystemExit: pass
|
|
except:
|
|
errorString = spyceUtil.exceptionString()
|
|
try:
|
|
import cgi
|
|
response.clear()
|
|
response.write('<html><pre>\n')
|
|
response.write('Unexpected exception: (please report!)\n')
|
|
response.write(cgi.escape(errorString))
|
|
response.write('\n</pre></html>\n')
|
|
response.returncode = response.RETURN_OK
|
|
except:
|
|
sys.stderr.write(errorString+'\n')
|
|
return response.returncode
|
|
|
|
class spyceRequest:
|
|
"""Underlying Spyce request object. All implementations (CGI, Apache...)
|
|
should subclass and implement the methods marked 'not implemented'."""
|
|
def __init__(self):
|
|
self._in = None
|
|
def read(self, limit=None):
|
|
if limit:
|
|
return self._in.read(limit)
|
|
else:
|
|
return self._in.read()
|
|
def readline(self, limit=None):
|
|
if limit:
|
|
return self._in.readline(limit)
|
|
else:
|
|
return self._in.readline()
|
|
def env(self, name=None):
|
|
raise 'not implemented'
|
|
def getHeader(self, type=None):
|
|
raise 'not implemented'
|
|
def getServerID(self):
|
|
raise 'not implemented'
|
|
|
|
class spyceResponse:
|
|
"""Underlying Spyce response object. All implementations (CGI, Apache...)
|
|
should subclass and implement the methods marked 'not implemented', and
|
|
also properly define the RETURN codes."""
|
|
RETURN_CONTINUE = 100
|
|
RETURN_SWITCHING_PROTOCOLS = 101
|
|
RETURN_OK = 200
|
|
RETURN_CREATED = 201
|
|
RETURN_ACCEPTED = 202
|
|
RETURN_NON_AUTHORITATIVE_INFORMATION = 203
|
|
RETURN_NO_CONTENT = 204
|
|
RETURN_RESET_CONTENT = 205
|
|
RETURN_PARTIAL_CONTENT = 206
|
|
RETURN_MULTIPLE_CHOICES = 300
|
|
RETURN_MOVED_PERMANENTLY = 301
|
|
RETURN_MOVED_TEMPORARILY = 302
|
|
RETURN_SEE_OTHER = 303
|
|
RETURN_NOT_MODIFIED = 304
|
|
RETURN_USE_PROXY = 305
|
|
RETURN_TEMPORARY_REDIRECT = 307
|
|
RETURN_BAD_REQUEST = 400
|
|
RETURN_UNAUTHORIZED = 401
|
|
RETURN_PAYMENT_REQUIRED = 402
|
|
RETURN_FORBIDDEN = 403
|
|
RETURN_NOT_FOUND = 404
|
|
RETURN_METHOD_NOT_ALLOWED = 405
|
|
RETURN_NOT_ACCEPTABLE = 406
|
|
RETURN_PROXY_AUTHENTICATION_REQUIRED = 407
|
|
RETURN_REQUEST_TIMEOUT = 408
|
|
RETURN_CONFLICT = 409
|
|
RETURN_GONE = 410
|
|
RETURN_LENGTH_REQUIRED = 411
|
|
RETURN_PRECONDITION_FAILED = 412
|
|
RETURN_REQUEST_ENTITY_TOO_LARGE = 413
|
|
RETURN_REQUEST_URI_TOO_LONG = 414
|
|
RETURN_UNSUPPORTED_MEDIA_TYPE = 415
|
|
RETURN_REQUEST_RANGE_NOT_SATISFIABLE = 416
|
|
RETURN_EXPECTATION_FAILED = 417
|
|
RETURN_INTERNAL_SERVER_ERROR = 500
|
|
RETURN_NOT_IMPLEMENTED = 501
|
|
RETURN_BAD_GATEWAY = 502
|
|
RETURN_SERVICE_UNAVAILABLE = 503
|
|
RETURN_GATEWAY_TIMEOUT = 504
|
|
RETURN_HTTP_VERSION_NOT_SUPPORTED = 505
|
|
RETURN_CODE = {
|
|
RETURN_CONTINUE: 'CONTINUE',
|
|
RETURN_SWITCHING_PROTOCOLS: 'SWITCHING PROTOCOLS',
|
|
RETURN_OK: 'OK',
|
|
RETURN_CREATED: 'CREATED',
|
|
RETURN_ACCEPTED: 'ACCEPTED',
|
|
RETURN_NON_AUTHORITATIVE_INFORMATION: 'NON AUTHORITATIVE INFORMATION',
|
|
RETURN_NO_CONTENT: 'NO CONTENT',
|
|
RETURN_RESET_CONTENT: 'RESET CONTENT',
|
|
RETURN_PARTIAL_CONTENT: 'PARTIAL CONTENT',
|
|
RETURN_MULTIPLE_CHOICES: 'MULTIPLE CHOICES',
|
|
RETURN_MOVED_PERMANENTLY: 'MOVED PERMANENTLY',
|
|
RETURN_MOVED_TEMPORARILY: 'MOVED TEMPORARILY',
|
|
RETURN_SEE_OTHER: 'SEE OTHER',
|
|
RETURN_NOT_MODIFIED: 'NOT MODIFIED',
|
|
RETURN_USE_PROXY: 'USE PROXY',
|
|
RETURN_TEMPORARY_REDIRECT: 'TEMPORARY REDIRECT',
|
|
RETURN_BAD_REQUEST: 'BAD REQUEST',
|
|
RETURN_UNAUTHORIZED: 'UNAUTHORIZED',
|
|
RETURN_PAYMENT_REQUIRED: 'PAYMENT REQUIRED',
|
|
RETURN_FORBIDDEN: 'FORBIDDEN',
|
|
RETURN_NOT_FOUND: 'NOT FOUND',
|
|
RETURN_METHOD_NOT_ALLOWED: 'METHOD NOT ALLOWED',
|
|
RETURN_NOT_ACCEPTABLE: 'NOT ACCEPTABLE',
|
|
RETURN_PROXY_AUTHENTICATION_REQUIRED: 'PROXY AUTHENTICATION REQUIRED',
|
|
RETURN_REQUEST_TIMEOUT: 'REQUEST TIMEOUT',
|
|
RETURN_CONFLICT: 'CONFLICT',
|
|
RETURN_GONE: 'GONE',
|
|
RETURN_LENGTH_REQUIRED: 'LENGTH REQUIRED',
|
|
RETURN_PRECONDITION_FAILED: 'PRECONDITION FAILED',
|
|
RETURN_REQUEST_ENTITY_TOO_LARGE: 'REQUEST ENTITY TOO LARGE',
|
|
RETURN_REQUEST_URI_TOO_LONG: 'REQUEST URI TOO LONG',
|
|
RETURN_UNSUPPORTED_MEDIA_TYPE: 'UNSUPPORTED MEDIA TYPE',
|
|
RETURN_REQUEST_RANGE_NOT_SATISFIABLE: 'REQUEST RANGE NOT SATISFIABLE',
|
|
RETURN_EXPECTATION_FAILED: 'EXPECTATION FAILED',
|
|
RETURN_INTERNAL_SERVER_ERROR: 'INTERNAL SERVER ERROR',
|
|
RETURN_NOT_IMPLEMENTED: 'NOT IMPLEMENTED',
|
|
RETURN_BAD_GATEWAY: 'BAD GATEWAY',
|
|
RETURN_SERVICE_UNAVAILABLE: 'SERVICE UNAVAILABLE',
|
|
RETURN_GATEWAY_TIMEOUT: 'GATEWAY TIMEOUT',
|
|
RETURN_HTTP_VERSION_NOT_SUPPORTED: 'HTTP VERSION NOT SUPPORTED',
|
|
}
|
|
def __init__(self):
|
|
pass
|
|
def write(self, s):
|
|
raise 'not implemented'
|
|
def writeErr(self, s):
|
|
raise 'not implemented'
|
|
def close(self):
|
|
raise 'not implemented'
|
|
def clear(self):
|
|
raise 'not implemented'
|
|
def sendHeaders(self):
|
|
raise 'not implemented'
|
|
def clearHeaders(self):
|
|
raise 'not implemented'
|
|
def setContentType(self, content_type):
|
|
raise 'not implemented'
|
|
def setReturnCode(self, code):
|
|
raise 'not implemented'
|
|
def addHeader(self, type, data, replace=0):
|
|
raise 'not implemented'
|
|
def flush(self):
|
|
raise 'not implemented'
|
|
def unbuffer(self):
|
|
raise 'not implemented'
|
|
|
|
class spyceCode:
|
|
'''Takes care of compiling the Spyce file, and generating a wrapper'''
|
|
def __init__(self, code, filename=None, sig='', limit=3):
|
|
# store variables
|
|
self._filename = filename
|
|
self._limit = limit
|
|
# generate code
|
|
self._code, self._coderefs, self._modrefs = \
|
|
spyceCompile.spyceCompile(code, filename, sig, getServer())
|
|
self._wrapperQueue = []
|
|
self._wrappersMade = 0
|
|
# wrappers
|
|
def newWrapper(self):
|
|
"Get a wrapper for this code from queue, or make new one"
|
|
try: return self._wrapperQueue.pop()
|
|
except IndexError: pass
|
|
self._wrappersMade = self._wrappersMade + 1
|
|
return spyceWrapper(self)
|
|
def returnWrapper(self, w):
|
|
"Return wrapper back to queue after use"
|
|
if len(self._wrapperQueue)<self._limit:
|
|
self._wrapperQueue.append(w)
|
|
# serialization
|
|
def __getstate__(self):
|
|
return self._filename, self._code, self._coderefs, self._modrefs, self._limit
|
|
def __setstate__(self, state):
|
|
self._filename, self._code, self._coderefs, self._modrefs, self._limit = state
|
|
self._wrapperQueue = []
|
|
self._wrappersMade = 0
|
|
# accessors
|
|
def getCode(self):
|
|
"Return processed Spyce (i.e. Python) code"
|
|
return self._code
|
|
def getFilename(self):
|
|
"Return source filename, if it exists"
|
|
return self._filename
|
|
def getCodeRefs(self):
|
|
"Return python-to-Spyce code line references"
|
|
return self._coderefs
|
|
def getModRefs(self):
|
|
"Return list of import references in Spyce code"
|
|
return self._modrefs
|
|
|
|
class spyceWrapper:
|
|
"""Wrapper object runs the entire show, bringing together the code, the
|
|
Spyce environment, the request and response objects and the modules. It is
|
|
NOT thread safe - new instances are generated as necessary by spyceCode!
|
|
This object is generated by a spyceCode object. The common Spyce handler
|
|
code calls the 'processing' functions. Module writers interact with this
|
|
object via the spyceModuleAPI calls. This is arguable the trickiest portion
|
|
of the Spyce so don't touch unless you know what you are doing."""
|
|
def __init__(self, spycecode):
|
|
# store variables
|
|
self._spycecode = spycecode
|
|
# api object
|
|
self._api = self
|
|
# module tracking
|
|
self._modCache = {}
|
|
self._modstarted = []
|
|
self._modules = {}
|
|
# compile python code
|
|
self._codeenv = { spyceCompile.SPYCE_WRAPPER: self._api }
|
|
try: exec self._spycecode.getCode() in self._codeenv
|
|
except SyntaxError: raise spyceException.pythonSyntaxError(self)
|
|
self._freshenv = self._codeenv.keys()
|
|
# spyce hooks
|
|
noop = lambda *args: None
|
|
self.process = self._codeenv[spyceCompile.SPYCE_PROCESS_FUNC]
|
|
try: self.init = self._codeenv[spyceCompile.SPYCE_INIT_FUNC]
|
|
except: self.init = noop
|
|
try: self.destroy = self._codeenv[spyceCompile.SPYCE_DESTROY_FUNC]
|
|
except: self.destroy = noop
|
|
# request, response
|
|
self._response = self._request = None
|
|
self._responseCallback = {}
|
|
self._moduleCallback = {}
|
|
def _startModule(self, name, file=None, as=None, force=0):
|
|
"Initialise module for current request."
|
|
if as==None: as=name
|
|
if force or not self._codeenv.has_key(as):
|
|
modclass = getServer().loadModule(name, file, self._spycecode.getFilename())
|
|
mod = modclass(self._api)
|
|
self.setModule(as, mod, 0)
|
|
if DEBUG_ERROR:
|
|
sys.stderr.write(as+'.start\n')
|
|
mod.start()
|
|
self._modstarted.append((as, mod))
|
|
else: mod = self._codeenv[as]
|
|
return mod
|
|
# spyce processing
|
|
def spyceInit(self, request, response):
|
|
"Initialise a Spyce for processing."
|
|
self._request = request
|
|
self._response = response
|
|
for mod in DEFAULT_MODULES:
|
|
self._startModule(mod)
|
|
self._modstarteddefault = self._modstarted
|
|
self._modstarted = []
|
|
for (modname, modfrom, modas) in self.getModRefs():
|
|
self._startModule(modname, modfrom, modas, 1)
|
|
exec '_spyce_start()' in { '_spyce_start': self.init }
|
|
def spyceProcess(self, *args, **kwargs):
|
|
"Process the current Spyce request."
|
|
path = sys.path
|
|
try:
|
|
if self._spycecode.getFilename():
|
|
path = copy.copy(sys.path)
|
|
sys.path.append(os.path.dirname(self._spycecode.getFilename()))
|
|
dict = { '_spyce_process': self.process,
|
|
'_spyce_args': args, '_spyce_kwargs': kwargs, }
|
|
exec '_spyce_result = apply(_spyce_process, _spyce_args, _spyce_kwargs)' in dict
|
|
return dict['_spyce_result']
|
|
finally:
|
|
sys.path = path
|
|
def spyceDestroy(self, theError=None):
|
|
"Cleanup after the request processing."
|
|
try:
|
|
exec '_spyce_finish()' in { '_spyce_finish': self.destroy }
|
|
# explicit modules
|
|
self._modstarted.reverse()
|
|
for as, mod in self._modstarted:
|
|
try:
|
|
if DEBUG_ERROR:
|
|
sys.stderr.write(as+'.finish\n')
|
|
mod.finish(theError)
|
|
except spyceException.spyceDone: pass
|
|
except spyceException.spyceRedirect, e:
|
|
return spyceFileHandler(self._request, self._response, e.filename)
|
|
except KeyboardInterrupt: raise
|
|
except SystemExit: pass
|
|
except: theError = spyceException.spyceRuntimeException(self._api)
|
|
finishError = None
|
|
# default modules
|
|
self._modstarteddefault.reverse()
|
|
for as, mod in self._modstarteddefault:
|
|
try:
|
|
if DEBUG_ERROR:
|
|
sys.stderr.write(as+'.finish\n')
|
|
mod.finish(theError)
|
|
except: finishError = 1
|
|
self._request = None
|
|
self._response = None
|
|
if finishError: raise
|
|
finally:
|
|
self.spyceCleanup()
|
|
def spyceCleanup(self):
|
|
"Sweep the Spyce environment."
|
|
self._modstarteddefault = []
|
|
self._modstarted = []
|
|
self._modules = {}
|
|
if self._freshenv!=None:
|
|
for e in self._codeenv.keys():
|
|
if e not in self._freshenv:
|
|
del self._codeenv[e]
|
|
# API methods
|
|
def getFilename(self):
|
|
"Return filename of current Spyce"
|
|
return self._spycecode.getFilename()
|
|
def getCode(self):
|
|
"Return processed Spyce (i.e. Python) code"
|
|
return self._spycecode.getCode()
|
|
def getCodeRefs(self):
|
|
"Return python-to-Spyce code line references"
|
|
return self._spycecode.getCodeRefs()
|
|
def getModRefs(self):
|
|
"Return list of import references in Spyce code"
|
|
return self._spycecode.getModRefs()
|
|
def getServerObject(self):
|
|
"Return unique (per engine instance) server object"
|
|
return getServer().serverobject
|
|
def getServerGlobals(self):
|
|
"Return server configuration globals"
|
|
return getServer().globals
|
|
def getServerID(self):
|
|
"Return unique server identifier"
|
|
return self._request.getServerID()
|
|
def getPageError(self):
|
|
"Return default page error value"
|
|
return getServer().pageerror
|
|
def getRequest(self):
|
|
"Return internal request object"
|
|
return self._request
|
|
def getResponse(self):
|
|
"Return internal response object"
|
|
return self._response
|
|
def setResponse(self, o):
|
|
"Set internal response object"
|
|
self._response = o
|
|
for f in self._responseCallback.keys(): f()
|
|
def registerResponseCallback(self, f):
|
|
"Register a callback for when internal response changes"
|
|
self._responseCallback[f] = 1
|
|
def unregisterResponseCallback(self, f):
|
|
"Unregister a callback for when internal response changes"
|
|
try: del self._responseCallback[f]
|
|
except KeyError: pass
|
|
def getModules(self):
|
|
"Return references to currently loaded modules"
|
|
return self._modules
|
|
def getModule(self, name):
|
|
"""Get module reference. The module is dynamically loaded and initialised
|
|
if it does not exist (ie. if it was not explicitly imported, but requested
|
|
by another module during processing)"""
|
|
return self._startModule(name)
|
|
def setModule(self, name, mod, notify=1):
|
|
"Add existing module (by reference) to Spyce namespace (used for includes)"
|
|
self._codeenv[name] = mod
|
|
self._modules[name] = mod
|
|
if notify:
|
|
for f in self._moduleCallback.keys():
|
|
f()
|
|
def delModule(self, name, notify=1):
|
|
"Add existing module (by reference) to Spyce namespace (used for includes)"
|
|
del self._codeenv[name]
|
|
del self._modules[name]
|
|
if notify:
|
|
for f in self._moduleCallback.keys():
|
|
f()
|
|
def getGlobals(self):
|
|
"Return the Spyce global namespace dictionary"
|
|
return self._codeenv
|
|
def registerModuleCallback(self, f):
|
|
"Register a callback for modules change"
|
|
self._moduleCallback[f] = 1
|
|
def unregisterModuleCallback(self, f):
|
|
"Unregister a callback for modules change"
|
|
try: del self._moduleCallback[f]
|
|
except KeyError: pass
|
|
def spyceFile(self, file):
|
|
"Return a spyceCode object of a file"
|
|
return getServer().spyce_cache[('file', file)]
|
|
def spyceString(self, code):
|
|
"Return a spyceCode object of a string"
|
|
return getServer().spyce_cache[('string', code)]
|
|
def spyceModule(self, name, file=None, rel_file=None):
|
|
"Return Spyce module class"
|
|
return getServer().loadModule(name, file, rel_file)
|
|
def spyceTaglib(self, name, file=None, rel_file=None):
|
|
"Return Spyce taglib class"
|
|
return getServer().loadModule(name, file, rel_file)
|
|
def setStdout(self, out):
|
|
"Set the stdout stream (thread-safe)"
|
|
serverout = getServer().stdout
|
|
if serverout: serverout.setObject(out)
|
|
else: sys.stdout = out
|
|
def getStdout(self):
|
|
"Get the stdout stream (thread-safe)"
|
|
serverout = getServer().stdout
|
|
if serverout: return serverout.getObject()
|
|
else: return sys.stdout
|
|
|
|
##################################################
|
|
# Spyce cache
|
|
#
|
|
|
|
def spyceFileCacheValid(key, validity):
|
|
"Determine whether compiled Spyce is valid"
|
|
try:
|
|
filename, sig = key
|
|
except:
|
|
filename, sig = key, ''
|
|
try:
|
|
if not os.path.exists(filename):
|
|
return 0
|
|
if not os.access(filename, os.R_OK):
|
|
return 0
|
|
return os.path.getmtime(filename) == validity
|
|
except KeyboardInterrupt: raise
|
|
except:
|
|
return 0
|
|
|
|
def spyceFileCacheGenerate(key):
|
|
"Generate new Spyce wrapper (recompiles)."
|
|
try:
|
|
filename, sig = key
|
|
except:
|
|
filename, sig = key, ''
|
|
# ensure file exists and we have permissions
|
|
if not os.path.exists(filename):
|
|
raise spyceException.spyceNotFound(filename)
|
|
if not os.access(filename, os.R_OK):
|
|
raise spyceException.spyceForbidden(filename)
|
|
# generate
|
|
mtime = os.path.getmtime(filename)
|
|
f = None
|
|
try:
|
|
f = open(filename)
|
|
code = f.read()
|
|
finally:
|
|
if f: f.close()
|
|
s = spyceCode(code, filename=filename, sig=sig)
|
|
return mtime, s
|
|
|
|
def spyceStringCacheValid(code, validity):
|
|
return 1
|
|
|
|
def spyceStringCacheGenerate(key):
|
|
try:
|
|
code, sig = key
|
|
except:
|
|
code, sig = key, ''
|
|
s = spyceCode(code, sig=sig)
|
|
return None, s
|
|
|
|
def spyceCacheValid((type, key), validity):
|
|
return {
|
|
'string': spyceStringCacheValid,
|
|
'file': spyceFileCacheValid,
|
|
}[type](key, validity)
|
|
|
|
def spyceCacheGenerate((type, key)):
|
|
return {
|
|
'string': spyceStringCacheGenerate,
|
|
'file': spyceFileCacheGenerate,
|
|
}[type](key)
|
|
|
|
|
|
##################################################
|
|
# Spyce common entry points
|
|
#
|
|
|
|
def spyceFileHandler(request, response, filename, sig='', args=None, kwargs=None, config_file=None):
|
|
return _spyceCommonHandler(request, response, ('file', (filename, sig)), args, kwargs, config_file)
|
|
|
|
def spyceStringHandler(request, response, code, sig='', args=None, kwargs=None, config_file=None):
|
|
return _spyceCommonHandler(request, response, ('string', (code, sig)), args, kwargs, config_file)
|
|
|
|
def _spyceCommonHandler(request, response, spyceInfo, args=None, kwargs=None, config_file=None):
|
|
return getServer(config_file).commonHandler(request, response, spyceInfo, args, kwargs)
|
|
|
|
if __name__ == '__main__':
|
|
execfile('run_spyceCmd.py')
|
|
|