pso-0.98.D-beta/ 0040755 0001752 0001751 00000000000 10074410553 012573 5 ustar thanos users pso-0.98.D-beta/py/ 0040755 0001752 0001751 00000000000 10074410552 013222 5 ustar thanos users pso-0.98.D-beta/py/pso/ 0040755 0001752 0001751 00000000000 10074410553 014024 5 ustar thanos users pso-0.98.D-beta/py/pso/__init__.py 0100666 0001752 0001751 00000001440 07756466403 016157 0 ustar thanos users #
# __init__.py - Python Service Objects
#
# Author: Thanos Vassilakis thanos@0x01.com
#
# Copyright (c) thanos vassilakis 2000,2001, 2002
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public License
# as published by the Free Software Foundation; either version 2.1 of the
# License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
# or FITNESS FOR A PARTICULAR PURPOSE.
# See the GNU Lesser General Public License for more details.
#
# See terms of license at gnu.org.
#
#
# $Id: __init__.py,v 1.2 2002/06/19 15:35:42 thanos Exp $
#
__version__="$Revision: 1.2 $"
pso-0.98.D-beta/py/pso/cgirequest.py 0100666 0001752 0001751 00000003265 07756466403 016602 0 ustar thanos users #
# cgirequest.py - Python Service Objects
#
# Author: Thanos Vassilakis thanos@0x01.com
#
# Copyright (c) thanos vassilakis 2000,2001, 2002
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public License
# as published by the Free Software Foundation; either version 2.1 of the
# License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
# or FITNESS FOR A PARTICULAR PURPOSE.
# See the GNU Lesser General Public License for more details.
#
# See terms of license at gnu.org.
#
# $Id: cgirequest.py,v 1.8 2003/01/20 23:20:00 thanos Exp $
#
__version__="$Revision: 1.8 $"
import sys, operator, os
from request import SERVER_RETURN
from requestimpl import RequestImpl
from copy import copy
class CgiRequest(RequestImpl):
""" Concrete Implementation class for a CGI Request """
COOKIE_KEY='HTTP_COOKIE'
def __init__(self, req=None):
#RequestImpl.__init__(self, req)
self.ostream= sys.stdout
def req(self):
return self
def getOutStream(self):
return self.ostream
def getCookieKey(self):
return self.COOKIE_KEY
def getEnviron(self, handler):
env ={}
keys = os.environ.keys()
values = os.environ.values()
map(operator.setitem, [env]*len(keys), keys, values)
#import os
#env = copy(os.environ)
return env
def send_http_header(self, handler):
handler.write(str(handler.getHeadersOut()))
handler.write('\n')
def getInputs(self, handler):
from cgi import FieldStorage
return FieldStorage()
def getServerReturn(self):
return SERVER_RETURN
pso-0.98.D-beta/py/pso/fields.py 0100644 0001752 0001751 00000005011 10074406623 015641 0 ustar thanos users #
# pso.fields.py - Python Service Objects Form Tag lib
#
# Author: Thanos Vassilakis thanos@0x01.com
#
# Copyright (c) thanos vassilakis 2000,2001, 2002
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public License
# as published by the Free Software Foundation; either version 2.1 of the
# License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
# or FITNESS FOR A PARTICULAR PURPOSE.
# See the GNU Lesser General Public License for more details.
#
# See terms of license at gnu.org.
#
# $Id: fields.py,v 1.5 2004/07/12 04:03:31 thanos Exp $
#
__version__="$Revision: 1.5 $"
from string import letters, digits
from form import ValidationFailure,FieldMissing, ValidationError, DefaultField, Select, Input
from isocodes import USStates
from validation import isZipCode
class StateSelect(Select):
OPTIONS=( ('NN','Non US or Canada'), ) + USStates
class ZipInput(Input):
def validate(self, handler):
value = Input.validate(self, handler)
if not value: return ''
try:
isZipCode(value)
except Exception, e:
raise ValidationError(self.getName(), '%s' % e)
return value
class PhoneInput(Input):
def validate(self, handler):
value = Input.validate(self, handler)
if not value: return ''
class EmailInput(Input):
def validate(self, handler):
value = Input.validate(self, handler)
if len(value):
if value.count('@') != 1:
raise ValidationError(self.getName(), 'invalid e-mail')
if value.count('.') < 1:
raise ValidationError(self.getName(), 'invalid e-mail')
return value
class UrlInput(Input):
def validate(self, handler):
value = Input.validate(self, handler)
if value:
from urllib import urlopen
try:
urlopen(value)
except:
raise ValidationError(self.getName(), 'invalide url')
return value
class UserIdInput(Input):
SIZE=5
VALIDCHAR = letters+digits
REQUIRED=1
def validate(self, handler):
value = Input.validate(self, handler)
v = [ch for ch in value if ch not in self.VALIDCHAR]
if v:
raise ValidationError(value, 'login id must be alphnumerical [a-z, A-Z, 0-9]')
size = int(self.getAttrs().get('size', str(self.SIZE)))
if len(value) < size:
raise ValidationError(value, 'login id must be %d character or longer' % size)
return value
pso-0.98.D-beta/py/pso/form.py 0100644 0001752 0001751 00000035176 10074406573 015361 0 ustar thanos users #
# pso.form.py - Python Service Objects Form Tag lib
#
# Author: Thanos Vassilakis thanos@0x01.com
#
# Copyright (c) thanos vassilakis 2000,2001, 2002
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public License
# as published by the Free Software Foundation; either version 2.1 of the
# License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
# or FITNESS FOR A PARTICULAR PURPOSE.
# See the GNU Lesser General Public License for more details.
#
# See terms of license at gnu.org.
#
# $Id: form.py,v 1.8 2004/07/12 04:03:07 thanos Exp $
#
__version__="$Revision: 1.8 $"
from types import ListType, TupleType, StringType
import md5
from parser import Tag
from util import mkDict, log
class FormException(Exception):pass
class FieldMissing(FormException):
def __init__(self, field, message='is mandatory'):
self.field=field
self.message=message
Exception.__init__(self, message)
class ValidationError(FormException):
def __init__(self, field, message):
self.field=field
self.message=message
Exception.__init__(self, message)
class ValidationFailure(FormException):
def __init__(self, errors):
self.errors=errors
Exception.__init__(self, message)
class FormPart(Tag):
# states
FORMsTATEkEY="formState"
START = "start"
INeRROR = "error"
INcONFIRM="confirm"
INsUBMIT = "submit"
def getState(self, handler):
state = handler.scratch().get(self.FORMsTATEkEY, FormPart.START)
return state
class Form(FormPart):
def init(self):
Tag.init(self)
def validator(self, obj, cdata):
if obj is not self:
if obj and hasattr(obj, 'validate'):
try:
self.handler.scratch()[obj] = obj.validate(self.handler)
except (ValidationError, FieldMissing), e:
self.handler.scratch()[obj] = e
self.handler.scratch()['errors'] = e
except Exception, e:
print child, e
def validate(self, handler):
handler.scratch()['errors'] = []
self.handler= handler
self.travers(self.validator)
self.handler= None
def preProcess(self, handler):
if handler is self: return ''
prevState = handler.req().getInput(self.FORMsTATEkEY)
if not prevState: # first time
currentState = Form.START
elif prevState in (Form.START, Form.INeRROR):
if handler is not self:
self.validate(handler)
if handler.scratch()['errors']:
currentState = Form.INeRROR
else:
currentState = Form.INcONFIRM
elif prevState == Form.INcONFIRM:
currentState = Form.INsUBMIT
else:
currentState = Form.START
handler.scratch()[self.FORMsTATEkEY] = currentState
return ''
def __call__(self, handler, cdata=''):
table = {
Form.START: self.renderForm,
Form.INeRROR: self.renderForm,
Form.INcONFIRM: self.renderConfirm,
Form.INsUBMIT: self.doSubmit
}
method = table[self.getState(handler)]
return method(handler, cdata)
def renderHidden(self, hidden):
if hidden:
html=''
for k,v in hidden.items():
html += '' % (k,v)
return html
def getHidden(self, handler):
return {}
def getAction(self, handler):
action = self.attrs.get('action')
if not action:
url = handler.req().getUrl()
url.clear()
action = str(url)
return action
def renderForm(self, handler, fields):
action = self.getAction(handler)
if action:
formattrs = self.buildAttrs( action = action)
else:
formattrs = self.buildAttrs()
hidden = self.getHidden(handler)
hidden['action']= handler.req().getInput('action')
hidden[self.FORMsTATEkEY] = self.getState(handler)
hidden = self.renderHidden(hidden)
return "
" % ( formattrs, hidden, fields)
def renderConfirm(self, handler, cdata=''):
return self.renderForm(handler, cdata)
def onSubmit(self, handler):
return handler.req().hasInputs('submit.x', 'submit')
def onConfirmed(self, handler):
return handler.req().hasInputs('confirm.x','confirm')
def goNext(self, handler, cdata):
handler.req().log( "GOTO NEXT PAGE")
return "GOTO NEXT PAGE"
def submit(self, handler, cdata):
handler.req().log(handler.req().getInputs())
def doSubmit(self, handler, cdata):
self.submit(handler, cdata)
self.goNext(handler, cdata)
return "form submitted"
class Field(FormPart):
REQUIRED=0
def getName(self):
return self.getAttrs()['name']
def getStartValue(self, handler, name):
startvalue = self.getAttrs().get('value','')
if hasattr(self, 'record'):
record = self.fromDb(self.record(handler))
#if name=='spam':
if record:
startvalue = record.get(name, startvalue)
value = self.getFormValue(handler, name)
if not value:
return startvalue
return value
def getFormValue(self, handler, name, default = ''):
return handler.req().getInput(name, default)
def fromDb(self, value):
return value
def getValue(self, handler):
name = self.getName()
if self.getState(handler) is Form.START:
value = self.getStartValue(handler, name)
else:
value = self.getFormValue(handler, name)
return value
def isGiven(self, handler):
name = self.getName()
value = self.getFormValue(handler, name)
if (self.REQUIRED or self.getAttrs().get('required')) and not value:
raise FieldMissing(self.getName())
return value
def validate(self, handler):
return self.isGiven(handler)
def cData(self, handler, cdata):
return cdata
def __call__(self, handler, cdata=''):
if self.getAttrs().get('readonly'):
value = self.getValue(handler)
return self.renderReadOnly(handler, value, self.cData(handler, cdata))
if self.getState(handler) is Form.START:
value = self.getValue(handler)
return self.renderEditable(handler, value, self.cData(handler, cdata))
if self.getState(handler) is Form.INeRROR:
value = handler.scratch().get(self, '')
if isinstance(value, FormException):
return self.renderInError(handler, value, self.cData(handler, cdata))
else:
return self.renderEditable(handler, value, self.cData(handler, cdata))
if self.getState(handler) is Form.INcONFIRM:
value = handler.scratch().get(self, '')
#value = self.getValue(handler)
return self.renderReadOnly(handler, value, self.cData(handler, cdata))
value = self.getValue(handler)
return self.renderEditable(handler, value, self.cData(handler, cdata))
def buildAttrs(self, handler, **kws):
return Tag.buildAttrs(self, **kws)
def renderInError(self, handler, value, cdata):
return '%s <- %s: %s ' % (self.renderEditable(handler, self.getValue(handler), cdata), self.getName(), value)
def renderEditable(self, handler, value, cdata):
if cdata:
return "<%s %s>%s%s>" % (self.getAttrs()['tagname'], self.buildAttrs(handler, value=value) ,cdata, self.getAttrs()['tagname'])
else:
return "<%s %s />" % (self.getAttrs()['tagname'], self.buildAttrs(handler, value=value) )
def renderReadOnly(self, handler, value, cdata):
return """%s""" % (value, self.getName(), self.getValue(handler))
def renderReadOnly(self, handler, values, cdata):
html= """%s"""
name = self.getName()
if type(values) is type([]):
fields = map(lambda n,v,h=html: h % (v,n,v), ( name,)*len(values), values)
return ','.join(fields)
return """%s""" % (values, self.getName(), self.getValue(handler))
class DefaultField(Field):
TYPE=None
NAME=None
EXT=""
def init(self):
Field.init(self)
if self.TYPE:
self.getAttrs().setdefault('type',self.TYPE)
if not self.getAttrs().has_key('name'):
if not self.NAME:
name = self.__class__.__name__[:-len(self.EXT)]
self.NAME = name[0].lower()+name[1:]
self.getAttrs()['name'] = self.NAME
class Input(DefaultField):
EXT="Input"
class Group(DefaultField):
EXT="Group"
def renderEditable(self, handler, value, cdata):
return cdata
class ReadOnly(DefaultField):
EXT="ReadOnly"
def init(self):
self.getAttrs()['readonly']=1
DefaultField.init(self)
class Hidden(ReadOnly):
TYPE="hidden"
EXT="Hidden"
def renderReadOnly(self, handler, value, cdata):
return """""" % (self.getName(), self.getValue(handler))
class Multiple(DefaultField):
CHECKED="checked"
VALUE = "value"
def getFormValue(self, handler, name, default = ''):
return handler.req().getInputs(name)
def buildAttrs(self, handler, **kws):
attrs = self.processAttrs( **kws)
givenValues = self.getValue(handler)
if type(givenValues) != type([]):
givenValues = [givenValues]
value = self.getAttrs().get('value')
if value:
if value in givenValues:
attrs[self.CHECKED]=None
elif attrs.has_key('checked'):
del attrs[self.CHECKED]
return DefaultField.buildAttrList(self, attrs)
class CheckBox(Multiple):
EXT="CheckBox"
TYPE="checkbox"
def renderEditable(self, handler, value, cdata):
value = self.getAttrs().get('value','')
#return value, self.buildAttrs(handler, value=value)
return DefaultField.renderEditable(self, handler, value, cdata)
class Radio(CheckBox):
TYPE="radio"
EXT="Radio"
class Options(Field):
def getFormValue(self, handler, name, default = ''):
name = self.getName()
return handler.req().getInputs(name)
def renderEditable(self, handler, value, cdata):
return cdata #self.renderReadOnly(handler, values, cdata)
def renderReadOnly(self, handler, values, cdata):
html= """%s"""
name = self.getName()
if type(values) is type([]):
fields = map(lambda n,v,h=html: h % (v,n,v), ( name,)*len(values), values)
return ','.join(fields)
return values
class Submit(DefaultField):
EXT="Submit"
TYPE="submit"
def buildAttrs(self, handler, **kws):
if self.getState(handler)== Form.INcONFIRM:
kws['name']="confirm"
else:
kws['name']="submit"
return DefaultField.buildAttrs(self, handler, **kws)
def renderReadOnly(self, handler, value, cdata):
return self.renderEditable(handler, value , cdata)
class Select(DefaultField):
EXT="Select"
OPTIONS=[]
FIRSTSplit="|"
SECONDSplit=","
def init(self):
DefaultField.init(self)
self.OPTIONS= self.getOptions()
def renderEditable(self, handler, value, cdata):
options = self.getOptionList(value)
if options:
cdata = options
return DefaultField.renderEditable(self, handler, value, cdata)
def getLabel(self, value):
#MING 03-15-2004 some options are list of strings and some are list of tuples. Also, sometimes the first option might be empty string. Therefore can't always index o with 0
for o in self.OPTIONS:
if type(o) == StringType:
if o == str(value):
return o
elif str(o[0]) == str(value):
return o[1]
def renderReadOnly(self, handler, value, cdata):
return """%s""" % (self.getLabel(value), self.getName(), self.getValue(handler))
def getOptionList(self, selected):
options = self.OPTIONS
optionList=""
for o in options:
if type(o) in (ListType, TupleType):
olen = len(o)
if olen ==3:
value, label, chosen = o
else:
value, label, chosen = o[0],o[1],''
else:
value, label, chosen = o, o, ''
if str(value) == str(selected):
chosen='selected'
optionList = '%s' % ( optionList, value, chosen, label)
return optionList
def getOptions(self):
options = self.getAttrs().get('options')
if options is None:
return self.OPTIONS
options = options.split(self.FIRSTSplit)
options = map(lambda x, ch=self.SECONDSplit : x.split(ch), options)
if len(options[0]) == 1:
options = map(None, options, options)
return options
class TextArea(DefaultField):
EXT="TextArea"
def cData(self, handler, cdata):
value = self.getValue(handler)
if value:
cdata = value
return DefaultField.cData(self, handler, cdata)
class File(DefaultField):
EXT="File"
TYPE="file"
CURRENTLABEL=" current choice: %s "
SAVEDAS= "savedAs"
SAVED= "saved"
READoNLYhTML ="""%(filename)s"""
def getStartValue(self, handler, name):
filename = DefaultField.getStartValue(self, handler, name+self.SAVED)
tempname = DefaultField.getStartValue(self, handler, name+self.SAVEDAS)
return filename, tempname
def getFormValue(self, handler, name, default = ''):
file = handler.req().getFile(name)
if file is None or type(file) is type(""):
return default #self.getStartValue(handler, name)
else:
file.keep()
return file.filename, file.tempname
def renderEditable(self, handler, file, cdata):
filename =''
current =''
if not (file is None or type(file) is type("")):
filename, tempname = file
#if filename and tempname:
current = self.getAttrs().get('currentlabel',self.CURRENTLABEL) % self.readOnly(tempname, filename)
return DefaultField.renderEditable(self, handler, filename, cdata) + current
def renderReadOnly(self, handler, file, cdata):
if not (file is None or type(file) is type("")):
filename, tempname = file
else:
filename =''
tempname = ''
return self.readOnly(filename, tempname)
def readOnly(self, filename, tempname):
name = self.getName()
attrs = mkDict(saved= name+self.SAVED, savedAs = name+self.SAVEDAS, filename=filename, tempname= tempname)
return self.READoNLYhTML % attrs
class PasswordEncoder:
def encode(self, x):
if x[:2] !='x:':
return 'x:' + self.crypt(x)
return x
def crypt(self, x):
egg = md5.new(x)
return egg.hexdigest()
class PasswordGroup(PasswordEncoder, Group):
def renderReadOnly(self, handler, value, cdata):
value = self.encode(value)
return """""" % (self.getName(), value)
class PasswordInput(PasswordEncoder, Input):
TYPE="password"
SIZE=7
REQUIRED=1
def renderReadOnly(self, handler, value, cdata):
return """****""" % (self.getName(), value)
def validate(self, handler):
value = Input.validate(self, handler)
size = int(self.getAttrs().get('size', str(self.SIZE)))
if len(value) < size:
raise ValidationError(self.getName(), 'must be %d characters or longer' % size)
return self.encode(value)
class PasswordConfirmInput(PasswordInput):
def validate(self, handler):
value = self.encode(Input.validate(self, handler))
passwd = self.encode(handler.req().getInput('password'))
if passwd != value:
raise ValidationError(self.getName(), 'must be the same as what you entered for password')
return value
pso-0.98.D-beta/py/pso/gui.py 0100666 0001752 0001751 00000020741 07756466466 015222 0 ustar thanos users #
# pso.gui.py - Python Service Objects
#
# Author: Thanos Vassilakis thanos@0x01.com
#
# Copyright (c) thanos vassilakis 2000,2001, 2002
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public License
# as published by the Free Software Foundation; either version 2.1 of the
# License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
# or FITNESS FOR A PARTICULAR PURPOSE.
# See the GNU Lesser General Public License for more details.
#
# See terms of license at gnu.org.
#
# $Id: gui.py,v 1.2 2003/11/18 19:04:22 thanos Exp $
#
#
# created: 21/08/2002 Thanos Vassilakis
#
#
#
from pso.util import mkDict
# application imports
from util.cache import EvalCache
class Bouncer:
def render(self, parser, attr, cdata):
if self.shouldBounce(parser, attr):
return self.bounce(parser, attr, cdata)
return ''
def shouldBounce(self, parser, attr):
return 0
def bounce(self, parser, attr, cdata):
return ''
class Link:
def render(self, parser, attr, cdata):
if self.isEnabled(parser, attr):
return self.renderEnabled(parser, attr, cdata)
else:
return self.renderDisabled(parser, attr, cdata)
def isEnabled(self, parser, attr):
return 1
def renderEnabled(self, parser, attr, cdata):
return parser.handler.url.href(cdata, **attr)
def renderDisabled(self, parser, attr, cdata):
return '%s' % cdata
class Info:
def render(self, parser, attr, cdata):
if self.isEnabled(parser, attr):
return self.renderInfo(parser, attr, cdata)
return ''
def isEnabled(self, parser, attr):
return 1
def renderInfo(self, parser, attr, cdata):
return cdata
class List:
def __init__(self):
self.records=None
def shouldShow(self, parser, attr) : return 1
def getRecords(self, parser, attr): pass
def processRecord(self, parser, attr, record, fields): pass
def prepare(self, parser, attr): return {}
def render(self, parser, attr, cdata):
if not self.shouldShow(parser, attr): return ''
if self.records is None:
self.records = self.sort(parser, attr)
rowlen = len(self.records)
fields = self.prepare(parser, attr)
rows = map(self.processRow, self.records, rowlen*((parser,attr, cdata, fields),))
del self.records[:]
self.records = None
return '\n'.join(rows)
def sort(self, parser, attr):
return self.getRecords(parser, attr)
def processRow (self, record, params):
parser, attr, cdata, fields = params
#MING DEBUG 01-02-03
return cdata % self.processRecord(parser, attr, record, fields)
#return str(self.processRecord(parser, attr, record, fields))
def tableMethods(celf):
table = celf()
return table.render
tableMethods = classmethod(tableMethods)
class Table(List):
PAGESZ='10'
paged=0
PAGER_HTML = """
%(legend)s %(prev)s %(next)s
"""
def processPager(self, parser, attr, cdata):
if self.records is None:
self.records = self.sort(parser, attr)
(legend, prev, next, self.records) = self.tabulate(parser, attr, self.records)
return mkDict(legend=legend, prev=prev, next=next)
def pager(self, parser, attr, cdata):
if not self.shouldShow(parser, attr): return ''
if not cdata:
html = self.PAGER_HTML
return html % self.processPager( parser, attr, cdata)
def uri(self, parser, attr, label, **vars):
tablename = attr.get('name','')
url = parser.handler.url.copy()
sort = vars.get('sort')
if sort is None:
sort = parser.handler.getInput(tablename+'sort')
if sort is not None:
url[tablename+'sort'] = sort
line = vars.get('line')
if not line:
line = parser.handler.getInput(tablename+'line')
if line:
url[tablename+'line'] = line
del url['delta']
return '%s' % (url, label)
def tabulate(self, parser, attr, records):
numberlines = len(self.records)
tablename = attr.get('name','')
line = int(parser.handler.getInput(tablename+'line', value='1'))
pagesz = int(parser.handler.getInput(tablename+'pageSize', value=self.PAGESZ))
if line > numberlines:
line=int(numberlines / pagesz)*pagesz + 1
elif (line < 1):
line=1
numberpages = numberlines/ pagesz + (numberlines % pagesz > 0)
currentpage = line/ pagesz + (line % pagesz > 0)
if (line > (1+(currentpage-1)*pagesz)):
prevpage = 1+(currentpage-1)*pagesz
nextpage=prevpage+pagesz
else:
prevpage = line - pagesz
nextpage=line + pagesz
if prevpage < 0:
prevpage = 0
if nextpage > numberlines:
nextpage = 0
records = records[int(line-1): int(line+pagesz-1)]
if nextpage:
nexturi = self.uri(parser, attr, 'next', line= nextpage)
else:
nexturi = 'next'
if prevpage:
prevuri = self.uri(parser, attr, 'prev', line= prevpage) + ' |'
else:
prevuri = 'prev |'
if not numberpages:
return 'no data', '','', []
return ('%d of %d - ' % ( currentpage, numberpages)), prevuri, nexturi, records
def tableMethods(celf):
table = celf()
return table.pager, table.render
tableMethods = classmethod(tableMethods)
class SortedTable(Table):
def sort(self, parser, attr):
records = self.getRecords(parser, attr)
records.sort()
return records
class SortableTable(Table):
SORTFIELD = "sort"
PAGEFIELD = "line"
def __init__(self):
List.__init__(self)
def toggle(self, parser, attr, current, field):
if abs(current)== field:
return -current
return field
def columnHead(self, parser, attr, currentColumn, innerhtml, default, column):
label, field = column
field +=1
field = self.toggle(parser, attr, currentColumn, field)
return self.buildTitle(parser, attr, field, innerhtml %label)
def buildTitle(self, parser, attr, field, label):
return self.uri(parser, attr, label, sort=field)
def getColumns(self, attr):
columns = attr.get("columns")
if columns:
columns = EvalCache.eval(columns, self.GLOBALS)
return columns
def sortRow(self, parser, attr, html):
if not self.shouldShow(parser, attr): return ''
tablename = attr.get('name','')
columns = self.getColumns(attr)
if columns:
innerHtml = attr.get("innehtml", "%s")
default = EvalCache.eval(attr.get("default","1"), self.GLOBALS)
currentField = parser.handler.getInput(tablename+'sort')
if not currentField:
currentField = default
else:
currentField = int(currentField)
sortrow = [ self.columnHead(parser, attr, currentField, innerHtml, default, column) for column in columns]
return html % tuple(sortrow)
return html
def sort(self, parser, attr):
tablename = attr.get('name','')
records = self.getRecords(parser, attr)
column = parser.handler.getInput(tablename+'sort')
if not column:
column = self.getDefaultSort(parser.handler, attr)
else:
column = int(column)
if column:
records = sortTab(records, column)
return records
def getDefaultSort(self, handler, attr):
value = EvalCache.eval(attr.get("default","0"), self.GLOBALS)
if value > 0:
value +=1
elif value < 0:
value -=1
return value
def tableMethods(celf):
table = celf()
return table.pager, table.sortRow, table.render
tableMethods = classmethod(tableMethods)
class Tab:
def __init__(self, action, label):
self.action, self.label = action, label
def render(self, parser, attr, cdata=''):
if self.isEnabled(parser):
return self.renderEnabled(parser, attr, cdata)
else:
return self.renderDisabled(parser, attr, cdata)
def renderEnabled(self, parser, attr, cdata):
return parser.handler.url.href(self.getLabel(parser), action=self.action)
def renderDisabled(self, parser, attr, cdata):
return self.getLabel(parser)
def getLabel(self, parser):
return self.label
def isEnabled(self, parser):
return parser.handler.getInput('action') != self.action
class TabBar:
SPACER= ' | '
HTML="%s"
def render(self, parser, attr, cdata=''):
if not cdata:
cdata = self.HTML
try:
bar = self.getBar(parser, attr)
spacer = attr.setdefault('spacer', self.SPACER)
if bar:
tabs = [tab.render(parser, attr, cdata) for tab in self.TABS.get(bar, ())]
return cdata % spacer.join(tabs)
return ''
except Exception,e:
print ""
def getBar(self, parser, attr): pass
pso-0.98.D-beta/py/pso/handlers.py 0100666 0001752 0001751 00000003702 07756466466 016234 0 ustar thanos users #
# handlers.py - Python Service Objects
#
# Author: Thanos Vassilakis thanos@0x01.com
#
# Copyright (c) thanos vassilakis 2000,2001, 2002
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public License
# as published by the Free Software Foundation; either version 2.1 of the
# License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
# or FITNESS FOR A PARTICULAR PURPOSE.
# See the GNU Lesser General Public License for more details.
#
# See terms of license at gnu.org.
#
# $Id: handlers.py,v 1.6 2003/11/18 19:04:22 thanos Exp $
#
__version__="$Revision: 1.6 $"
from service import OK
from parser import CachedParser
class TemplateHandler:
TMPL="%s.html"
TMPL_PATH='templates/'
def renderer(self, object, cdata=''):
if object:
return object.render(self, cdata)
return cdata
def parse(self, req):
self._req = req
self._scratch={}
try:
template = self.buildTemplate(self.getTemplate(self.req()))
tree = CachedParser().parseFile(template)
except:
import traceback
traceback.print_exc()
template = self.buildTemplate(self.getDefaultTemplate(req))
tree = CachedParser().parseFile(template)
html = tree.render(self.renderer)
self._req = None
return html
def handle(self, req):
print self.parse(req)
return OK
def req(self):
return self._req
def scratch(self):
return self._scratch
def buildTemplate(self, template):
return self.TMPL_PATH+self.TMPL % template
def getTemplate(self, req):
return req.pso().getEnviron('PATH_INFO', self.getDefaultTemplate(req))
def getDefaultTemplate(self, req):
if not hasattr(self, 'DEFAULT_TEMPLATE'):
raise 'please either define attribute DEFAULT_TEMPLATE or override %s' % self.getDefaultTemplate
return self.DEFAULT_TEMPLATE
pso-0.98.D-beta/py/pso/isocodes.py 0100666 0001752 0001751 00000016240 07756466403 016234 0 ustar thanos users #
# Copyright (c) thanos vassilakis 2000,2001, 2002
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public License
# as published by the Free Software Foundation; either version 2.1 of the
# License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
# or FITNESS FOR A PARTICULAR PURPOSE.
# See the GNU Lesser General Public License for more details.
#
# See terms of license at gnu.org.
#
# $Id: isocodes.py,v 1.1 2003/01/24 17:31:07 thanos Exp $
__version__="$Revision: 1.1 $"
USStates = (
('AL','Alabama'),
('AK','Alaska'),
('AZ','Arizona'),
('AR','Arkansas'),
('CA','California'),
('CO','Colorado'),
('CT','Connecticut'),
('DE','Delaware'),
('FL','Florida'),
('GA','Georgia'),
('HI','Hawaii'),
('ID','Idaho'),
('IL','Illinois'),
('IN','Indiana'),
('IA','Iowa'),
('KS','Kansas'),
('KY','Kentucky'),
('LA','Louisiana'),
('ME','Maine'),
('MD','Maryland'),
('MA','Massachusetts'),
('MI','Michigan'),
('MN','Minnesota'),
('MS','Mississippi'),
('MO','Missouri'),
('MT','Montana'),
('NE','Nebraska'),
('NV','Nevada'),
('NH','New Hampshire'),
('NJ','New Jersey'),
('NM','New Mexico'),
('NY','New York'),
('NC','North Carolina'),
('ND','North Dakota'),
('OH','Ohio'),
('OK','Oklahoma'),
('OR','Oregon'),
('PA','Pennsylvania'),
('RI','Rhode Island'),
('SC','South Carolina'),
('SD','South Dakota'),
('TN','Tennessee'),
('TX','Texas'),
('UT','Utah'),
('VT','Vermont'),
('VA','Virginia'),
('WA','Washington'),
('WV','West Virginia'),
('WI','Wisconsin'),
('WY','Wyoming'))
TLDCodes= (
("ac", "Ascension Island"),
("ad", "Andorra"),
("ae", "United Arab Emirates"),
("af", "Afghanistan"),
("ag", "Antigua and Barbuda"),
("ai", "Anguilla"),
("al", "Albania"),
("am", "Armenia"),
("an", "Netherlands Antilles"),
("ao", "Angola"),
("aq", "Antarctica"),
("ar", "Argentina"),
("as", "American Samoa"),
("at", "Austria"),
("au", "Australia"),
("aw", "Aruba"),
("az", "Azerbaijan"),
("ba", "Bosnia and Herzegovina"),
("bb", "Barbados"),
("bd", "Bangladesh"),
("be", "Belgium"),
("bf", "Burkina Faso"),
("bg", "Bulgaria"),
("bh", "Bahrain"),
("bi", "Burundi"),
("bj", "Benin"),
("bm", "Bermuda"),
("bn", "Brunei Darussalam"),
("bo", "Bolivia"),
("br", "Brazil"),
("bs", "Bahamas"),
("bt", "Bhutan"),
("bv", "Bouvet Island"),
("bw", "Botswana"),
("by", "Belarus"),
("bz", "Belize"),
("ca", "Canada"),
("cc", "Cocos (Keeling) Islands"),
("cd", "Congo, Democratic Republic of the"),
("cf", "Central African Republic"),
("cg", "Congo, Republic of"),
("ch", "Switzerland"),
("ci", "Cote d'Ivoire"),
("ck", "Cook Islands"),
("cl", "Chile"),
("cm", "Cameroon"),
("cn", "China"),
("co", "Colombia"),
("cr", "Costa Rica"),
("cu", "Cuba"),
("cv", "Cap Verde"),
("cx", "Christmas Island"),
("cy", "Cyprus"),
("cz", "Czech Republic"),
("de", "Germany"),
("dj", "Djibouti"),
("dk", "Denmark"),
("dm", "Dominica"),
("do", "Dominican Republic"),
("dz", "Algeria"),
("ec", "Ecuador"),
("ee", "Estonia"),
("eg", "Egypt"),
("eh", "Western Sahara"),
("er", "Eritrea"),
("es", "Spain"),
("et", "Ethiopia"),
("fi", "Finland"),
("fj", "Fiji"),
("fk", "Falkland Islands (Malvina)"),
("fm", "Micronesia, Federal State of"),
("fo", "Faroe Islands"),
("fr", "France"),
("ga", "Gabon"),
("gd", "Grenada"),
("ge", "Georgia"),
("gf", "French Guiana"),
("gg", "Guernsey"),
("gh", "Ghana"),
("gi", "Gibraltar"),
("gl", "Greenland"),
("gm", "Gambia"),
("gn", "Guinea"),
("gp", "Guadeloupe"),
("gq", "Equatorial Guinea"),
("gr", "Greece"),
("gs", "South Georgia and the South Sandwich Islands"),
("gt", "Guatemala"),
("gu", "Guam"),
("gw", "Guinea-Bissau"),
("gy", "Guyana"),
("hk", "Hong Kong"),
("hm", "Heard and McDonald Islands"),
("hn", "Honduras"),
("hr", "Croatia/Hrvatska"),
("ht", "Haiti"),
("hu", "Hungary"),
("id", "Indonesia"),
("ie", "Ireland"),
("il", "Israel"),
("im", "Isle of Man"),
("in", "India"),
("io", "British Indian Ocean Territory"),
("iq", "Iraq"),
("ir", "Iran (Islamic Republic of)"),
("is", "Iceland"),
("it", "Italy"),
("je", "Jersey"),
("jm", "Jamaica"),
("jo", "Jordan"),
("jp", "Japan"),
("ke", "Kenya"),
("kg", "Kyrgyzstan"),
("kh", "Cambodia"),
("ki", "Kiribati"),
("km", "Comoros"),
("kn", "Saint Kitts and Nevis"),
("kp", "Korea, Democratic People's Republic"),
("kr", "Korea, Republic of"),
("kw", "Kuwait"),
("ky", "Cayman Islands"),
("kz", "Kazakhstan"),
("la", "Lao People's Democratic Republic"),
("lb", "Lebanon"),
("lc", "Saint Lucia"),
("li", "Liechtenstein"),
("lk", "Sri Lanka"),
("lr", "Liberia"),
("ls", "Lesotho"),
("lt", "Lithuania"),
("lu", "Luxembourg"),
("lv", "Latvia"),
("ly", "Libyan Arab Jamahiriya"),
("ma", "Morocco"),
("mc", "Monaco"),
("md", "Moldova, Republic of"),
("mg", "Madagascar"),
("mh", "Marshall Islands"),
("mk", "Macedonia, Former Yugoslav Republic"),
("ml", "Mali"),
("mm", "Myanmar"),
("mn", "Mongolia"),
("mo", "Macau"),
("mp", "Northern Mariana Islands"),
("mq", "Martinique"),
("mr", "Mauritania"),
("ms", "Montserrat"),
("mt", "Malta"),
("mu", "Mauritius"),
("mv", "Maldives"),
("mw", "Malawi"),
("mx", "Mexico"),
("my", "Malaysia"),
("mz", "Mozambique"),
("na", "Namibia"),
("nc", "New Caledonia"),
("ne", "Niger"),
("nf", "Norfolk Island"),
("ng", "Nigeria"),
("ni", "Nicaragua"),
("nl", "Netherlands"),
("no", "Norway"),
("np", "Nepal"),
("nr", "Nauru"),
("nu", "Niue"),
("nz", "New Zealand"),
("om", "Oman"),
("pa", "Panama"),
("pe", "Peru"),
("pf", "French Polynesia"),
("pg", "Papua New Guinea"),
("ph", "Philippines"),
("pk", "Pakistan"),
("pl", "Poland"),
("pm", "St. Pierre and Miquelon"),
("pn", "Pitcairn Island"),
("pr", "Puerto Rico"),
("ps", "Palestinian Territories"),
("pt", "Portugal"),
("pw", "Palau"),
("py", "Paraguay"),
("qa", "Qatar"),
("re", "Reunion Island"),
("ro", "Romania"),
("ru", "Russian Federation"),
("rw", "Rwanda"),
("sa", "Saudi Arabia"),
("sb", "Solomon Islands"),
("sc", "Seychelles"),
("sd", "Sudan"),
("se", "Sweden"),
("sg", "Singapore"),
("sh", "St. Helena"),
("si", "Slovenia"),
("sj", "Svalbard and Jan Mayen Islands"),
("sk", "Slovak Republic"),
("sl", "Sierra Leone"),
("sm", "San Marino"),
("sn", "Senegal"),
("so", "Somalia"),
("sr", "Suriname"),
("st", "Sao Tome and Principe"),
("sv", "El Salvador"),
("sy", "Syrian Arab Republic"),
("sz", "Swaziland"),
("tc", "Turks and Caicos Islands"),
("td", "Chad"),
("tf", "French Southern Territories"),
("tg", "Togo"),
("th", "Thailand"),
("tj", "Tajikistan"),
("tk", "Tokelau"),
("tm", "Turkmenistan"),
("tn", "Tunisia"),
("to", "Tonga"),
("tp", "East Timor"),
("tr", "Turkey"),
("tt", "Trinidad and Tobago"),
("tv", "Tuvalu"),
("tw", "Taiwan"),
("tz", "Tanzania"),
("ua", "Ukraine"),
("ug", "Uganda"),
("uk", "United Kingdom"),
("um", "US Minor Outlying Islands"),
("us", "United States"),
("uy", "Uruguay"),
("uz", "Uzbekistan"),
("va", "Holy See (City Vatican State)"),
("vc", "Saint Vincent and the Grenadines"),
("ve", "Venezuela"),
("vg", "Virgin Islands (British)"),
("vi", "Virgin Islands (USA)"),
("vn", "Vietnam"),
("vu", "Vanuatu"),
("wf", "Wallis and Futuna Islands"),
("ws", "Western Samoa"),
("ye", "Yemen"),
("yt", "Mayotte"),
("yu", "Yugoslavia"),
("za", "South Africa"),
("zm", "Zambia"),
("zw", "Zimbabwe"))
pso-0.98.D-beta/py/pso/modpython.py 0100666 0001752 0001751 00000006375 07756466403 016455 0 ustar thanos users #
# modpython.py - Python Service Objects
#
# Author: Thanos Vassilakis thanos@0x01.com
#
# Copyright (c) thanos vassilakis 2000,2001, 2002
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public License
# as published by the Free Software Foundation; either version 2.1 of the
# License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
# or FITNESS FOR A PARTICULAR PURPOSE.
# See the GNU Lesser General Public License for more details.
#
# See terms of license at gnu.org.
#
# $Id: modpython.py,v 1.10 2002/06/19 15:34:51 thanos Exp $
#
__version__="$Revision: 1.10 $"
from operator import setitem, getitem
from pso import service
from cgirequest import CgiRequest
from mod_python import apache, util
def fixup(req, sessionImpl=None):
service.fixup(req, ModPythonRequest, sessionImpl = sessionImpl )
return apache.OK
def cleanup(req):
service.cleanup(req)
return apache.OK
class FormInput(util.FieldStorage):
def getvalue(key, default=None):
reval = default
if self.has_key(key):
value = self[key]
if type(value) is type([]):
retval = map(lambda v:v.value, value)
else:
retval = value.value
return retval
def getfirst(self, key, default =None):
retval = default
if self.has_key(key):
value = self[key]
if type(value) is type([]):
retval = value[0].value
else:
retval = value.value
return retval
def getlist(self, key):
if self.has_key(key):
value = self[key]
if type(value) is type([]):
return value
else:
return [value]
return []
class ModPythonRequest(CgiRequest):
""" Concrete Implementation class for a mod_python Request """
#COOKIE_KEY='Cookie'
def req(self):
return self._req
def setup(self, handler, req):
#req.pso = handler
self._req = req
def getOutStream(self):
return self.req()
def getEnviron(self, handler):
self.req().add_common_vars()
env = {}
subenv = self.req().subprocess_env
keys = subenv.keys()
values = map(getitem, (subenv,)*len(keys), keys)
map(setitem, [env]*len(keys), keys, values)
env["GATEWAY_INTERFACE"] = "Python-CGI/1.1"
if len(self.req().path_info) > 0:
env["SCRIPT_NAME"] = self.req().uri[:-len(self.req().path_info)]
else:
env["SCRIPT_NAME"] = self.req().uri
if self.req().headers_in.has_key("authorization"):
env["HTTP_AUTHORIZATION"] = self.req().headers_in["authorization"]
options = self.req().get_options()
keys = options.keys()
values = map(getitem, (options,)*len(keys), keys)
map(setitem, [env]*len(keys), keys, values)
return env
def send_http_header(self, handler, content_type='text/html'):
self.req().content_type = content_type
self.req().send_http_header()
def getInputs(self, handler, key=None, default=None, index=0):
from modpython import FormInput
return FormInput(self.req())
def getServerReturn(self):
return apache.SERVER_RETURN
def getHeadersOut(self):
return self.req().headers_out
def syncHeadersOut(self, headers): pass
#self.req().headers_out.add('cookie','MyMi')
#for k,v in headers.flatten():
# self.req().headers_out.add(k,v)
pso-0.98.D-beta/py/pso/nsapyrequest.py 0100666 0001752 0001751 00000010527 07756466403 017171 0 ustar thanos users #
# nsapy.py - Python Service Objects
#
# Author: Thanos Vassilakis thanos@0x01.com
#
# Copyright (c) thanos vassilakis 2000,2001, 2002
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public License
# as published by the Free Software Foundation; either version 2.1 of the
# License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
# or FITNESS FOR A PARTICULAR PURPOSE.
# See the GNU Lesser General Public License for more details.
#
# See terms of license at gnu.org.
#
# $Id: nsapyrequest.py,v 1.4 2002/06/19 15:32:44 thanos Exp $
#
__version__="$Revision: 1.4 $"
import os
from pso.request import ServiceRequest
from pso.requestimpl import RequestImpl
def buildEnviron( pblock, environ = {}):
if pblock:
buff = pblock.pblock2str()
buff = buff.replace('\\"', 'MinggniM')
list = buff.split( '"' )
list = map(lambda var,oldsep='MinggniM',newsep='"':var.replace(oldsep, newsep), list)
for n in range( 1, len( list ), 2 ):
key = list[n-1][:-1]
key = key.strip()
environ[key] = list[n]
return environ
def envReKey(environ):
keys = {
"content-length": "CONTENT_LENGTH" ,
"content-type": "CONTENT_TYPE" ,
"accept": "HTTP_ACCEPT" ,
"accept-encoding": "HTTP_ACCEPT_ENCODING" ,
"accept-language": "HTTP_ACCEPT_LANGUAGE" ,
"authorization": "HTTP_AUTHORIZATION" ,
"cookie" :"HTTP_COOKIE" ,
"if-modified-since": "HTTP_IF_MODIFIED_SINCE" ,
"referer": "HTTP_REFERER" ,
"user-agent":"HTTP_USER_AGENT" ,
"auth-type": "AUTH_TYPE" ,
"path-info": "PATH_INFO" ,
"auth-user": "REMOTE_USER" ,
"keysize": "HTTPS_KEYSIZE" ,
"secret-keysize" :"HTTPS_SECRETSIZE" ,
"ip": "REMOTE_ADDR" ,
"security_active": "HTTPS" ,
"host": "HTTP_HOST" ,
"server_hostname": "SERVER_NAME" ,
"query" : "QUERY_STRING",
"clf-request" : "REQUEST_LINE",
"method" : "REQUEST_METHOD",
"uri" : "SCRIPT_NAME",
"protocol" : "SERVER_PROTOCOL"
}
newenv = {}
for key, value in [(key, value) for key, value in environ.items() if key in keys]:
newenv[key] = value
return newenv
class NsapyRequest(RequestImpl):
""" Concrete Implementation class for a Nsapi Request """
COOKIE_KEY='HTTP_COOKIE'
def __init__(self, req=None):
self._req= req
def req(self):
return self._req
def getOutStream(self):
return self.ostream
def getCookieKey(self):
return self.COOKIE_KEY
def getEnviron(self, handler):
env = {}
try:
env.update( os.environ )
except:
pass
env = buildEnviron( self.req().pb, env )
env = buildEnviron( self.req().sn.session_dns(), env )
env = buildEnviron( self.req().sn.client(), env )
env = buildEnviron( self.req().rq.reqpb, env )
env = buildEnviron( self.req().rq.headers, env )
env = buildEnviron( self.req().rq.srvhdrs, env )
env = buildEnviron( self.req().rq.vars, env )
env = envReKey(env)
env["SERVER_PORT"] = env["SERVER_NAME"] = ''
host = env["HTTP_HOST"]
if ":" in host:
host, port = host.split(":")
env["SERVER_PORT"] = port
env["SERVER_NAME"] = host
if env.has_key('PATH_INFO'):
env["SCRIPT_NAME"] = env["SCRIPT_NAME"][:-len( env["PATH-INFO"] )]
env['SERVER_URL'] = "http://%(SERVER_NAME)s:%(SERVER_PORT)s" % env
return env
def send_http_header(self, handler):
handler.write(str(self.getHeadersOut()))
handler.write('\n')
def getInputs(self, handler, key=None, default=None, index=0):
from cgi import FieldStorage
if handler.getEnviron('REQUEST_METHOD') in ( "POST", "PUT" ):
ln = int( self.req().rq.request_header( "content-length", self.sn ) )
data = self.req().sn.form_data( ln )
stdin = StringIO( data )
form = FieldStorage(file = stdin, env = handler.getEnviron())
else:
form = FieldStorage(environ = handler.getEnviron())
return form
def getServerReturn(self):
return SERVER_RETURN
def syncHeadersOut(self, headers):
for k,v in headers.flatten():
self.req().rq.srvhdrs.nvinsert(k, v)
class NSAPYServiceRequest(ServiceRequest):
def __init__(self, sessionImpl=None):
ServiceRequest.__init__(self, NsapyRequest, sessionImpl)
pso-0.98.D-beta/py/pso/parser.py 0100644 0001752 0001751 00000056156 10074406733 015711 0 ustar thanos users """
#
# pso.parser.py - Python Service Objects Parser
#
# Author: Thanos Vassilakis thanos@0x01.com
#
# Copyright (c) thanos vassilakis 2000,2001, 2002
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public License
# as published by the Free Software Foundation; either version 2.1 of the
# License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
# or FITNESS FOR A PARTICULAR PURPOSE.
# See the GNU Lesser General Public License for more details.
#
# See terms of license at gnu.org.
#
# $Id: parser.py,v 1.18 2004/07/12 04:04:43 thanos Exp $
#
SYNOPSIS
Senario One
First you make a template - this is just a normal HTML file with a few extra tags:
For example, test.tmpl:
My Email: thanos@0x01.com
My Name:
Now create the mypanel package, mypanel.py
from pso.parser import Tag
class Email(Tag):
"renders email as a uri"
def render(self, cdata):
return '%s' % ( cdata, cdata)
class Name(Tag):
"renders name as a uri"
def render(self, cdata=''):
return '%(name)s' % self.getAttrs()
Save it in the python path.
Now write the script:
from pso.parser import Parser
psoParser = Parser()
psoTree = psoParser.parseFile("test.tmpl")
print psoTree.render()
Running this script should generate:
My Name: Thanos Vassilakis
Senario Two
Now you might want to just extract the tags and document them...
class TagDocumentor:
def document(self, object, cdata=''):
if object:
self.documentation += '\t
" % self.documentation)
class TagIndexer:
index = 0
def render(self, object, cdata=''):
if object:
self.index +=1
index = self.index
if cdata:
return ":<%s>%s%s>:" % (index, cdata, index)
return ":<%s />:" % index
return cdata
def do(self, infile, outfile):
self.index =0
psoParser = Parser()
psoTree = psoParser.parseFile(infile, )
open(outfile, 'w').write(psoTree.render(self.render))
import time
class TagTimer:
def timer(self, object, cdata=''):
if object:
t = time.time()
r = self.render(object, cdata)
self.tagTimes[object.__class__.__name__] = time.time() - t
return r
return self.render(object, cdata)
def do(self, infile):
self.tagTimes={}
psoParser = Parser()
psoTree = psoParser.parseFile(infile)
print psoTree.render(self.timer)
for k,v in self.tagTimes.items():
print k, v
class IndexerTimer(TagTimer, TagIndexer): pass
try:
import sys
infile = file1 #sys.argv[1]
outfile = 'r3' #sys.argv[2]
TagIndexer().do(infile, 'r2')
TagDocumentor().do(infile, 'r3')
IndexerTimer().do(infile)
except Exception,e:
print e
print """
usage parser.py template_file output_file
"""
pso-0.98.D-beta/py/pso/request.py 0100644 0001752 0001751 00000031474 10074406326 016077 0 ustar thanos users #
# Author: Thanos Vassilakis thanos@0x01.com
#
# Copyright (c) thanos vassilakis 2000,2001, 2002
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public License
# as published by the Free Software Foundation; either version 2.1 of the
# License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
# or FITNESS FOR A PARTICULAR PURPOSE.
# See the GNU Lesser General Public License for more details.
#
# See terms of license at gnu.org.
#
# $Id: request.py,v 1.19 2004/07/12 04:00:22 thanos Exp $
#
__version__="$Revision: 1.19 $"
from tempfile import mktemp
from types import StringType
import time
import sys
from session import Session, CookieFileImpl
from resultcodes import HTTP_MOVED_PERMANENTLY, HTTP_MOVED_TEMPORARILY
class SERVER_RETURN(Exception):pass
from urlparse import urlparse, urlunparse
try:
from urllib import urlencode
except:
pass
try:
from url import Url
except:
Url = None
class RequestIO:
"""
RequestIO is a proxy ouput stream. Everything writen to it will be buffered until the headers are sent or complete.
Then the contents is flused to the real out stream.
"""
def read(self, n = -1): return ""
def readline(self, length = None): return ""
def readlines(self): return []
def writelines(self, list):
self.write(''.join(list))
def isatty(self): return 0
def seek(self, pos, mode = 0): pass
def __init__(self):
self.pos = 0
self.headers_sent = 0
self.out = ""
self.header_out = None
def write(self, s):
if not s: return
if not self.headers_sent:
self.out += s
else:
self.getOutStream().write(s)
self.pos += len(s)
def flush(self):
self.getOutStream().write(self.out)
self.out=""
def getHeadersOut(self):
if self.header_out is None:
self.header_out = self.impl.getHeadersOut()
return self.header_out
def tell(self): return self.pos
def close(self):
#if not self.headers_sent:
self.send_http_header()
self.flush()
def headersSent(self):
self.headers_sent=1
def __del__(self):
self.close()
def setHeaderOut(self, key, value):
""" set a header entry. If this
entry already exits overwrite it.
"""
if type(value) != StringType:
value = str(value)
self.getHeadersOut()[key] = value
def addHeaderOut(self, key, value):
""" add a header entry.
"""
self.getHeadersOut().add(key, value)
def removeHeaderOut(self, key):
del self.getHeadersOut()[key]
class ServiceRequest(RequestIO):
""" Bridge class for a http service Request """
inputs = None
inputSeq = None
inputDict = None
cookies = None
environ = None
_session = None
def __init__(self, implClass, req=None):
RequestIO.__init__(self)
self.impl = implClass()
self.impl.setup(self, req)
self.response=""
self.status = self.getStatusCode(200)
def __call__(self):
return self
def pso(self):
" returns proxy to pso object "
return self
def getOutStream(self):
return self.impl.getOutStream()
def getInStream(self):
return self.impl.getInStream()
def setup(self, serviceHandler, reqHandler): pass
def close(self):
RequestIO.close(self)
if self._session is not None:
self._session.save(self)
#
# basics
#
def getStatusCode(self, code):
self.impl.getStatusCode(code)
#
# environ
#
def getEnviron(self, key=None, default = None):
""" if key is not given returns a dict of
the server environment.
Otherwise returns the entry for key.
If no entry is found returns None or default if given.
"""
if self.environ is None:
self.environ = self.impl.getEnviron(self)
if key is None:
return self.environ
return self.environ.get(key, default)
def setEnviron(self, key, value):
self.getEnviron()[key] = value
#
#
#
#
#
# Session handling
#
def getSession(self, sessionImplClass = CookieFileImpl, **parameters):
""" returns the current session. The session implentation
class may be passed to sessionImplClass, which if None
defaults to CookieFileImpl. The method can be passed keyword
arguments which will be treated as HTTP directives
"""
if sessionImplClass:
for k,v in parameters.items():
self.setEnviron(k, v)
self._session = Session(self, sessionImplClass())
if self._session.isNew():
self.setSession(self._session)
return self._session
def setSession(self, session):
self.impl.setSession(self, session)
session = {} #property(getSession,setSession)
#
# Cookie handling
#
def getCookieKey(self):
return self.impl.getCookieKey()
def getCookies(self):
""" req.getCookies()-> dict
returns a dictionary of cookies.
"""
if self.cookies is None:
cookies = self.getEnviron(self.impl.getCookieKey(), '')
if cookies:
from Cookie import SmartCookie
self.cookies = SmartCookie()
self.cookies.load(cookies)
else:
self.cookies = {}
return self.cookies
def getCookie(self, key, default=None):
""" returns the cookie requested by
key otherwise returns default,
if default is not given returns None.
"""
return self.getCookies().get(key, default)
def setCookie(self, key, value, **attrs):
""" sets cookie, key, to value.
Also will set any attributes given.
e.g. request.setCookie("login",name, comment="user id")
"""
cookiefmt = "%s=%s;"
cookie = cookiefmt % (key, value)
for k,v in attrs.items():
cookie += cookiefmt % (k, v)
self.addHeaderOut('set-cookie', cookie)
def send_http_header(self, content_type='text/html'):
""" send to stdout the content headers. Each on a seperate line.
contenttype has not been set it will default to 'text/html'.
Then send an extra newline
"""
#print
if not self.getHeadersOut().has_key('content-type'):
if not self.getHeadersOut().has_key('location'):
if not self.getHeadersOut().has_key('status'):
self.getHeadersOut()['content-type'] = content_type
self.impl.syncHeadersOut(self.getHeadersOut())
self.headersSent()
self.impl.send_http_header(self)
self.flush()
#
# Control
#
def redirect(self, url, permanent=0):
"""
force an imediate redirect to given url.
"""
self.impl.redirect(self, url, permanent)
def setStatus(self, status):
"""
set the HTTP return status.
This normally defaults to 200.
"""
self.setHeaderOut('status', status)
def sendStatus(self, status):
"""
set the HTTP return status.
This normally defaults to 200.
"""
self.setStatus(status)
self.impl.sendStatus(status)
#
# Input
#
def hasInput(self, key):
"""req.hasInput(key) -> 1 | 0
tests if a field in a form was filled.
"""
return self.getInputs().has_key(key)
def hasInputs(self, *keys):
return [key for key in keys if key in self.getInputs().keys()]
def getInputs(self, key=None):
"""req.getInput(key) -> FiledStorage| List of Fields
if key is given will return a list of fields values for that key.
if there are no values an empty list is returned.
if no key is given returns the cgi.FieldStorage object.
"""
if not self.inputs:
self.inputs = self.impl.getInputs(self)
if not key:
return self.inputs
if hasattr(self.inputs, 'getlist'):
return self.inputs.getlist(key)
else:
if self.inputs.has_key(key):
value = self.inputs.getvalue(key)
if value and type(value) is type([]):
return value
else:
return [value]
return []
def getInputSeq(self):
if not self.inputSeq:
self.inputSeq=[]
for key in self.getInputs().keys():
values = self.getInputs(key)
for value in values:
self.inputSeq.append((key, value))
return self.inputSeq
def getInputDict(self):
if not self.inputDict:
self.inputDict={}
for key in self.getInputs().keys():
self.inputDict[key] = self.getInputs(key)
return self.inputDict
def getInput(self, key, default=None, index=None):
"""req.getInput(key) -> String | default
returns the given form field value as a String.
If there are multiple values under the same key,
it will return the first in the list, unless index is given.
If no value is found will return "", unless default is given.
"""
if not index:
index =0
try:
return self.getInputs(key)[index]
except:
# import traceback
# traceback.print_exc()
return default
def getFile(self, key, default=None):
"""req.getFile(fieldname)-> Field
returns an uploaded file. The filed has the usual cgi.Field members plus
filename - the given file name
file - the actual file uploaded
tempname - is None until keep() is called.
the methods:
keep() - The file object is a temporay file
that will be deleted when the cgi terminates. keep asigns the file a
a temp file name.
save(name) - This method can be used to save the tempfile under the given name.
"""
if self.hasInput(key):
file = self.getInputs()[key]
if file.filename:
file.__class__.tempname= None
file.__class__.keep= keep
file.__class__.save= save
return file
return default
#
# Utilities
#
_url = None
def getUrl(self):
if self._url is None:
self._url= Url("http://%(HTTP_HOST)s%(REQUEST_URI)s" % self.getEnviron())
return self._url
#url = property(getUrl)
def uriParts(self):
if not Url:
raise 'under mod_python urlparse has problems'
url = "http://%(HTTP_HOST)s%(REQUEST_URI)s" % self.getEnviron()
parts = list(urlparse(url))
info_path = self.getEnviron('PATH_INFO','')
path=parts[2]
if info_path:
path,dummy = path.split(info_path)
indx = path.rfind('/')
if indx > -1:
script = path[indx:]
path = path[:indx]
else:
script = path
path=''
parts[2] = path
parts.insert(3, script)
parts.insert(4, info_path)
return parts
def buildUri(self, parts, clean, **kws):
query={}
i = 0
for key in ('scheme', 'netloc', 'path', 'script','pathinfo', 'param', 'fragment'):
if kws.has_key(key):
parts[i] = kws[key]
del kws[key]
i += 1
if clean:
parts[6] =''
qs = parts[6]
if qs:
if type((qs)) ==type(''):
# now for QS key, values:
#
querySeq = parts[6].split('&')
querySeq= map(lambda x: x.split('='), querySeq)
for k,v in querySeq:
if query.has_key(k):
query[k].append(v)
else:
query[k] = [v]
querySeq=[]
query.update(kws)
if query:
for key,values in query.items():
if type(values) == type([]):
for value in values:
querySeq.append((key, value))
else:
querySeq.append((key, values))
query = urlencode(querySeq, doseq=1)
else:
query = parts[6]
if parts[4]:
parts[2]= "%s%s%s" % tuple(parts[2:5])
else:
parts[2]= "%s%s" % tuple(parts[2:4])
del parts[3:5]
parts[4]= query
return urlunparse(parts)
def serviceUri(self, clean=1, **kws):
parts = list(self.uriParts())
url = self.buildUri(parts, clean, **kws)
return url
def baseUri(self):
parts = list(self.uriParts())
return "%s://%s%s/" % tuple(parts[:3])
def pageUri(self, page):
return self.baseUri() + page
def log(self, *args):
args = map(str, args)
post = "\n%s: %s" % ( time.ctime(), ' '.join(args))
try:
sys.stderr.write(post)
except:
import traceback
traceback.print_exc(file=self.stderr)
def keep(fileField):
""" req.getFile(key).keep() -> file
This method is added to file form fields.
Files that are uploaded are stored as nameless
temporary files. This method allows you to store the file, so it can be
processed at a later stage.
Calling it replaces the nameless temp file with the new named temp file.
"""
if not fileField.tempname:
fileField.tempname = mktemp()
fileField.file.seek(0)
fp = open(fileField.tempname,'wb')
fp.write(fileField.file.read())
fp.close()
fileField.file= open(fileField.tempname)
def save(fileField, newName):
""" req.getFile(key).saveAs(somename) -> None
This method is added to file form fields.
Files that are uploaded are stored as nameless
temporary files. This method alows you to store the file with a given name.
"""
if not fileField.tempname:
fileField.keep()
fileField.file.flush()
fileField.file.close()
import os
os.rename(fileField.tempname, newName)
def psoTest(req):
if not req:
req = ServiceRequest()
req.pso().send_http_header()
try:
session['reload'] +=1
except:
session['reload'] = 0
req.pso().write("\n try reload ", req.pso().session)
def simpleTest():
req = ServiceRequest()
import sys
sys.stdout = req
print 1,"hello world"
req.pso().send_http_header()
req.pso().write(" 2. hello world")
print 3, " third time"
def redtest1():
import sys
sys.stdout = req = ServiceRequest()
print "hello",
req.send_http_header()
print "world"
def redtest2():
req = ServiceRequest()
print "hello",
req.send_http_header()
print "world"
if __name__ == '__main__':
if 0:
import pdb
pdb.run("simpleTest()")
else:
redtest2()
pso-0.98.D-beta/py/pso/requestimpl.py 0100666 0001752 0001751 00000003572 07756466403 017002 0 ustar thanos users #
# requestimpl.py - Python Service Objects
#
# Author: Thanos Vassilakis thanos@0x01.com
#
#
# Copyright (c) thanos vassilakis 2000,2001, 2002
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public License
# as published by the Free Software Foundation; either version 2.1 of the
# License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
# or FITNESS FOR A PARTICULAR PURPOSE.
# See the GNU Lesser General Public License for more details.
#
# See terms of license at gnu.org.
# $Id: requestimpl.py,v 1.5 2002/06/19 15:32:44 thanos Exp $
#
__version__="$Revision: 1.5 $"
from resultcodes import HTTP_MOVED_PERMANENTLY, HTTP_MOVED_TEMPORARILY
from table import Table
class RequestImpl:
_req=None
def getOutStream(self): pass
def getInStream(self): pass
def getStatusCode(self, code): pass
def getEnviron(self):pass
def getCookieKey(self): pass
def send_http_header(self): pass
def setup(self, handler, req): pass
def req(self):
return self._req
def setSession(self, handler, session):
session.setSession()
def addHeaderOut(self, handler, key, value):
self.getHeadersOut().add(key, value)
def redirect(self, handler, url, permanent):
handler.setHeaderOut('location', url)
if permanent:
status = HTTP_MOVED_PERMANENTLY
else:
status = HTTP_MOVED_TEMPORARILY
raise self.getServerReturn(), self.getStatusCode(status)
def getStatusCode(self, code):
return code
def getServerReturn(self,code):
return SERVER_RETURN
def getHeadersOut(self):
return Table()
def syncHeadersOut(self, headers): pass
def sendStatus(self, status):
raise self.getServerReturn(), self.getStatusCode(status)
def getInputs(self): pass
pso-0.98.D-beta/py/pso/resultcodes.py 0100666 0001752 0001751 00000005243 07756466403 016761 0 ustar thanos users #
# resultcodes.py - Python Service Objects
#
# Author: Thanos Vassilakis thanos@0x01.com
#
# Copyright (c) thanos vassilakis 2000,2001, 2002
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public License
# as published by the Free Software Foundation; either version 2.1 of the
# License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
# or FITNESS FOR A PARTICULAR PURPOSE.
# See the GNU Lesser General Public License for more details.
#
# See terms of license at gnu.org.
#
# $Id: resultcodes.py,v 1.2 2002/06/19 15:32:44 thanos Exp $
#
__version__="$Revision: 1.2 $"
HTTP_CONTINUE = 100
HTTP_SWITCHING_PROTOCOLS = 101
HTTP_PROCESSING = 102
HTTP_OK = 200
HTTP_CREATED = 201
HTTP_ACCEPTED = 202
HTTP_NON_AUTHORITATIVE = 203
HTTP_NO_CONTENT = 204
HTTP_RESET_CONTENT = 205
HTTP_PARTIAL_CONTENT = 206
HTTP_MULTI_STATUS = 207
HTTP_MULTIPLE_CHOICES = 300
HTTP_MOVED_PERMANENTLY = 301
HTTP_MOVED_TEMPORARILY = 302
HTTP_SEE_OTHER = 303
HTTP_NOT_MODIFIED = 304
HTTP_USE_PROXY = 305
HTTP_TEMPORARY_REDIRECT = 307
HTTP_BAD_REQUEST = 400
HTTP_UNAUTHORIZED = 401
HTTP_PAYMENT_REQUIRED = 402
HTTP_FORBIDDEN = 403
HTTP_NOT_FOUND = 404
HTTP_METHOD_NOT_ALLOWED = 405
HTTP_NOT_ACCEPTABLE = 406
HTTP_PROXY_AUTHENTICATION_REQUIRED= 407
HTTP_REQUEST_TIME_OUT = 408
HTTP_CONFLICT = 409
HTTP_GONE = 410
HTTP_LENGTH_REQUIRED = 411
HTTP_PRECONDITION_FAILED = 412
HTTP_REQUEST_ENTITY_TOO_LARGE = 413
HTTP_REQUEST_URI_TOO_LARGE = 414
HTTP_UNSUPPORTED_MEDIA_TYPE = 415
HTTP_RANGE_NOT_SATISFIABLE = 416
HTTP_EXPECTATION_FAILED = 417
HTTP_UNPROCESSABLE_ENTITY = 422
HTTP_LOCKED = 423
HTTP_FAILED_DEPENDENCY = 424
HTTP_INTERNAL_SERVER_ERROR = 500
HTTP_NOT_IMPLEMENTED = 501
HTTP_BAD_GATEWAY = 502
HTTP_SERVICE_UNAVAILABLE = 503
HTTP_GATEWAY_TIME_OUT = 504
HTTP_VERSION_NOT_SUPPORTED = 505
HTTP_VARIANT_ALSO_VARIES = 506
HTTP_INSUFFICIENT_STORAGE = 507
HTTP_NOT_EXTENDED = 510
pso-0.98.D-beta/py/pso/service.py 0100644 0001752 0001751 00000004210 10074406326 016033 0 ustar thanos users #
# Author: Thanos Vassilakis thanos@0x01.com
#
#
# Copyright (c) thanos vassilakis 2000,2001, 2002
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public License
# as published by the Free Software Foundation; either version 2.1 of the
# License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
# or FITNESS FOR A PARTICULAR PURPOSE.
# See the GNU Lesser General Public License for more details.
#
# See terms of license at gnu.org.
# $Id: service.py,v 1.10 2004/07/12 04:00:22 thanos Exp $
#
__version__="$Revision: 1.10 $"
import sys
from weakref import ref
from time import time, strftime, gmtime
from util import log
from request import ServiceRequest, SERVER_RETURN
from session import CookieFileImpl
from cgirequest import CgiRequest
OK = 0
def fixup(req, requestImpl, sessionImpl=CookieFileImpl):
sys.stdout = req.pso = ServiceRequest(requestImpl, req)
session = req.pso().getSession( sessionImpl)
def cleanup(req):
log('cleaing up', req)
req.pso().close()
class ServiceHandler:
PRODUCTION = 0
def run(self, handler, sessionImpl =CookieFileImpl):
try:
stdout = sys.stdout
stderr = sys.stderr
sys.stdout = pso = ServiceRequest(CgiRequest)
pso.stderr = stderr
logfile = pso.getEnviron('PSOLog')
if logfile:
sys.stderr = open(logfile, 'a', 0)
if sessionImpl:
pso.session = pso.getSession( sessionImpl )
status = handler(pso)
except SERVER_RETURN, status:
pass
except:
sys.stdout = stdout
import traceback
if not self.PRODUCTION:
traceback.print_exc(file = sys.stdout)
else:
traceback.print_exc()
sys.stderr = stderr
def test(req):
print "hello world"
def test1(req):
print "hello world"
req.send_http_header(content_type= 'text/plain')
def test2(req):
print "hi there"
req.sendStatus(204)
def test3(req):
print "hi there"
req.redirect("http://www.w3c.org/")
if __name__ =='__main__':
ServiceHandler().run(test3)
pso-0.98.D-beta/py/pso/session.py 0100644 0001752 0001751 00000025260 10074405346 016067 0 ustar thanos users # session.py - Python Service Objects
#
# Author: Thanos Vassilakis thanos@0x01.com
#
# Copyright (c) thanos vassilakis 2000,2001, 2002
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public License
# as published by the Free Software Foundation; either version 2.1 of the
# License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
# or FITNESS FOR A PARTICULAR PURPOSE.
# See the GNU Lesser General Public License for more details.
#
# See terms of license at gnu.org.
#
# $Id: session.py,v 1.15 2004/07/12 03:52:06 thanos Exp $
#
__version__="$Revision: 1.15 $"
from weakref import ref
from time import time, strftime, gmtime
from cPickle import load, dump
from tempfile import mktemp
from util import MixIn, log
import sys, os
try:
mapClass = dict
except:
import UserDict
mapClass = UserDict.UserDict
class SessionImpl:
"abstract implementaion class"
DEFAULTServiceIdKey = "PSOServiceId"
DEFAULTSessionIdKey = "PSOSessionId"
DEFAULTServiceIdValue = "SESSION_ID"
def getServiceId(self, reqHandler):
"""session.getServiceId(requestHandler) -> String ~ The service id, set in the HTTP directive, is returned.
This will default to the script's name"""
return reqHandler.getEnviron(self.DEFAULTServiceIdKey, self.getDefaultServiceId())
def getDefaultServiceId(self):
return self.DEFAULTServiceIdValue
def getSessionId(self, reqHandler):
"""session.getSessionId(requestHandler) -> String | None ~ The current session id returned.
If none return None.
By default will look for a HTTP directive ServiceId"""
return reqHandler.getEnviron(self.DEFAULTSessonIdKey)
def load(self, reqHandler, session):
"session.load(requestHandler) -> Session"
def save(self, reqHandler, session):
"session.session(requestHandler, self) -> None"
def revert(self, reqHandler):
"session.revert(requestHandler, self) -> None ~reverts the session to last saved copy."
def expire(self, reqHandler, when):
"""
session.expire(requestHandler, when) -> None ~ if when is evals
to a number will expire the session in when seconds, otherwise will try and parse when as a date.
For more on this format see RFC2068 section 3.3.1
[also RCF822 and
RCF1123]
"""
def newSessionId(self):
""" session.newSessionId(self.requestHandler) -> String ~ returns a new sessionId, preferably unique."""
class Session(mapClass):
"""Session Bridge"""
def __init__(self, reqHandler, impl=None):
"""session = Session(requestHandler, SessionImplmentor()) ~ ctor's a session with the given
request handler and session implementation instance"""
mapClass.__init__(self)
self.init(reqHandler, impl)
self.setup()
def init(self, reqHandler, impl):
""" self.init(reqHandler, impl)-> None ~ template init method called by CTOR"""
self.sessionId=None
self.serviceId=None
self.status='new'
self.impl = impl
#self.impl.session = ref(self)
self.reqHandler= ref(reqHandler)
#self.reqHandler= reqHandler
self.expiresWhen=None
def setup(self):
""" self.setup()-> None ~ template method
used to define relationship between session and requestHandler"""
self.serviceId= self.getServiceId()
self.sessionId= self.getSessionId()
if not self.isNew():
self.load()
def isNew(self):
""" session.new()-> 1|0 ~ returns 1 if session was created on this request, otherwise 0
used to define relationship between session and requestHandler"""
return self.status=="new"
def getServiceId(self, reqHandler=None):
""" session.getServiceId()-> String ~ returns serviceId, request passed on to the implementor."""
if reqHandler is None:
reqHandler = self.reqHandler()
if not self.serviceId:
self.serviceId = self.impl.getServiceId(reqHandler)
return self.serviceId
def getSessionId(self, reqHandler=None):
""" session.getSessionId()-> String ~ returns either the current sessionId or a new session id."""
if reqHandler is None:
reqHandler = self.reqHandler()
if not self.sessionId:
self.sessionId = reqHandler.getEnviron(self.getServiceId(reqHandler))
if not self.sessionId:
self.sessionId = self.impl.getSessionId(reqHandler)
if not self.sessionId:
self.status = 'new'
self.sessionId = self.impl.newSessionId(reqHandler)
self.purge(reqHandler)
else:
self.status='open'
return self.sessionId
def purge(self, reqHandler=None):
self.impl.purge(reqHandler)
def load(self, reqHandler=None):
""" session.load()-> None ~ loads a session into its self."""
if reqHandler is None:
reqHandler = self.reqHandler()
try:
session = self.impl.load(reqHandler, self)
if session:
expires = session.getExpire()
if expires is not None and expires < time():
self.status = "new"
return
self.update(session)
else:
self.status = "new"
except Exception, e:
import traceback
traceback.print_exc()
self.status = "new"
return {}
def save(self, reqHandler=None):
""" session.save()-> None ~ saves self."""
if reqHandler is None:
reqHandler = self.reqHandler()
self.reqHandler = None
self.status = 'open'
self.impl.save(reqHandler, self)
self.reqHandler= reqHandler
def getExpire(self):
""" session.getExpire()-> float ~ returns when it will expire in secs since epoche."""
return self.expiresWhen
def expire(self, when = None):
#def expire(self, when = None):
""" session.expire(when)-> None ~ expires session at time.time() + when,
if eval(when) evalutes, otherwise tries to parse when and expire session at when.
For more on this format see RFC2068 section 3.3.1
[also RCF822 and
RCF1123]
"""
self.expireWhen = when
self.impl.expire(self, self.reqHandler(), when)
#self.impl.expire(self, self.req(), when)
def setSession(self, reqHandler=None):
""" session.setSession() -> None ~ adds session to request handler. """
if reqHandler is None:
reqHandler = self.reqHandler()
self.impl.setSession(self, reqHandler)
class FileLoader(MixIn):
DIRECTIVEtAG='PSOSessionFileLoader_'
DIRECTIVES=('Path',)
PATH = os.path.dirname(mktemp())
def getFileName(self, reqHandler, session):
"""session.getFileName(requestHandler) -> String ~ returns a fully qualified session file name."""
path = self.getPath(reqHandler)
file = session.getSessionId(reqHandler)
filename = os.path.join(path, file)
return filename
def getPath(self, reqHandler):
""" session.getPath(requestHandler) -> String ~ returns the path where sessions will be stored."""
return self.getDirectives(FileLoader, reqHandler).get('Path', self.PATH)
def purge(self, reqHandler=None): pass
def newSessionId(self, reqHandler):
"""session.newSessionId(requestHandler) -> String ~ returns a new sessionId, preferably unique."""
id = os.path.basename(mktemp(self.getServiceId( reqHandler)))
return id
def load(self, reqHandler, session):
"""session.load(requestHandler) -> session ~ returns session. All thrown expections passed on."""
return load(open(self.getFileName(reqHandler, session),'r+b'))
def save(self, reqHandler, session):
""" session.save(requestHandler) -> None ~ saves session. All thrown expections passed on."""
file = self.getFileName(reqHandler, session)
f = open(file,'w+b')
dump( session, f)
class CookieSession(MixIn):
DIRECTIVEtAG='PSOCookieSession_'
DIRECTIVES=('expires', 'Path','Comment','Domain','Max-Age','secure','Version')
def getCookie(self, reqHandler):
""" self.getCookie(requestHandler) -> String | None ~ returns the session cookie if found
otherwise none"""
cookie = reqHandler.getEnviron(reqHandler.getCookieKey())
if cookie:
try:
start=0
look4 = self.getServiceId(reqHandler)+'='
start = cookie.index(look4)
start += len(look4)
end = cookie.find(';', start)
if end == -1:
cookie = cookie[start:]
else:
cookie = cookie[start:end]
return cookie.strip()
except Exception, e:
import traceback
traceback.print_exc()
return None
def getSessionId(self, reqHandler):
"""self.getSessionId(requestHandler) -> String | None ~ The current session id returned.
If none return None."""
return self.getCookie(reqHandler)
def when(self, when):
"""self.when(when) -> None ~ utility method to build the correct cookie expire attributes."""
if not hasattr(self, 'attrs'):
self.attrs = {}
if when is not None:
try:
when = eval(str(when))
when = time() + when
#self.attrs['Max-Age']= str(long(when))
self.attrs['expires'] = strftime("%a, %d %b %Y %H:%M:%S GMT", gmtime(when))
except:
self.attrs['expires'] = when
if self.attrs.has_key('Max-Age'):
del self.attrs['Max-Age']
def expire(self, session, reqHandler, when = None):
""" self.expire(session, requestHandler, when)-> None ~ expires session at time.time() + when,
if eval(when) evalutes, otherwise tries to parse when and expire session at when.
For more on this format see RFC2068 section 3.3.1
[also RCF822 and
RCF1123]
"""
self.when(when)
reqHandler.setSession(session)
def getAttrs(self):
""" self.getAttrs() -> Dictionary of cookie attributes ~ utility
method for setting up the session cookie"""
if hasattr(self, 'attrs'):
return self.attrs
else:
return {}
def setSession(self, session, reqHandler):
""" self.setSession(session, reqHandler) -> None ~ adds session to request handler.
Handles setting the cookie when the session is new.
"""
self.attrs = self.getAttrs()
self.attrs.update(self.getDirectives(CookieSession, reqHandler))
value = reqHandler.getEnviron('PSOSessionExpires')
if value:
self.when(value)
reqHandler.setCookie(session.getServiceId(), session.getSessionId(), **self.getAttrs())
class CookieFileImpl(CookieSession, FileLoader, SessionImpl):
""" Default session implementation, using temporary files to
store the session, and using a browser cookie to
pass the session id accross requests."""
class FileSession(Session ):
""" Default session bridge, using CookieFileImpl as the implementaion class"""
def init(self, reqHandler,imp):
Session.init(self, reqHandler, CookieFileImpl())
pso-0.98.D-beta/py/pso/table.py 0100666 0001752 0001751 00000003235 07756466403 015513 0 ustar thanos users # table.py - Python Service Objects
#
# Author: Thanos Vassilakis thanos@@0x01.com
#
#
# Copyright (c) thanos vassilakis 2000,2001, 2002
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public License
# as published by the Free Software Foundation; either version 2.1 of the
# License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
# or FITNESS FOR A PARTICULAR PURPOSE.
# See the GNU Lesser General Public License for more details.
#
# See terms of license at gnu.org.
# $Id: table.py,v 1.5 2002/06/19 15:23:25 thanos Exp $
#
__version__="$Revision: 1.5 $"
from types import ListType
try:
mapClass = dict
except:
import UserDict
mapClass = UserDict.UserDict
class Table(mapClass):
def add(self, key, value):
try:
self[key.lower()].append(value)
except:
self[key.lower()] = [value]
def set(self, key, value):
self[key.lower()] = [value]
def __repr__(self):
text=""
for k, v in self.flatten():
text += "%s: %s\n" % ( k,v)
return text
def flatten(self):
items=[]
for key, values in self.items():
if type(values) is ListType:
for value in values:
items.append((key,value))
else:
items.append((key,values))
return items
class CIMap(mapClass):
def __setitem__(self, key, item):
mapClass.__setitem__(self, key.lower(), item)
if __name__ =='__main__':
print Table.__bases__
t = Table()
t.add("cookie-set","me")
t.add("cookie-set","you")
t.add("max-set","1")
t.set("max-set","2")
print t
pso-0.98.D-beta/py/pso/tags.py 0100666 0001752 0001751 00000015000 10024141047 015323 0 ustar thanos users #
# tags.py - Python Service Objects
#
# Author: Thanos Vassilakis thanos@0x01.com
#
# Copyright (c) thanos vassilakis 2000,2001, 2002
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public License
# as published by the Free Software Foundation; either version 2.1 of the
# License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
# or FITNESS FOR A PARTICULAR PURPOSE.
# See the GNU Lesser General Public License for more details.
#
# See terms of license at gnu.org.
#
# $Id: tags.py,v 1.9 2003/11/18 19:04:23 thanos Exp $
#
from parser import Tag
from handlers import TemplateHandler
import sys
from cStringIO import StringIO
from util import log
class Template(Tag, TemplateHandler):
FIELD_NAME='action'
def getTemplate(self, req):
return req.getInput(self.FIELD_NAME, self.getDefaultTemplate(req))
def __call__(self, handler, cdata=''):
# return self.getTemplate( handler)
return self.parse(handler.req())
def getDefaultTemplate(self, req):
default = self.attrs.get('default')
if not default:
raise 'please set tag attribute default or override me %s' % self.getDefaultTemplate
return default
class Exec(Tag):
def __call__(self, handler, cdata=''):
if not cdata:
return ''
oldout = sys.stdout
try:
sys.stdout = StringIO()
exec cdata
retval = sys.stdout.getvalue()
sys.stdout.close()
finally:
sys.sdtout = oldout
return retval
class DataMixin:
KEY=None
def getKey(self, handler):
return self.KEY
def getRecId(self, handler, key):
return handler.req().getInput(key)
def getRecord(self, handler, key): pass
def record(self, handler):
key = self.getRecId(handler, self.getKey(handler))
if key:
scratchKey = (self.DATAMODEL, key)
record = handler.scratch().get(scratchKey)
if not record:
record = self.getRecord(handler, key)
if record:
handler.scratch()[scratchKey] = record
return record
def getSelect(self, handler): pass
def getSelection(self, handler, select): pass
def getRecNumber(self, handler):
return len(self.selection(handler))
def selection(self, handler):
criteria = self.getSelect(handler)
scratchKey = (self.DATAMODEL, 'select', tuple(criteria.items()))
cursor = handler.scratch().get(scratchKey)
if not cursor:
cursor = self.getSelection(handler, criteria)
if cursor:
handler.scratch()[scratchKey] = cursor
return cursor
class OutLine(Tag):
DELIMITER=','
LI='
%s
'
NAME=''
def getValue(self, handler):
field = self.attrs.get('name', self.NAME)
value = self.record(handler).get(field)
return value
def getList(self, value):
value = value.strip()
delimiter = self.attrs.get('delimiter', self.DELIMITER)
list = value.split(delimiter)
return list
def __call__(self, handler, cdata=''):
try:
return ''.join(map(lambda x: self.LI % x, self.getList(self.getValue(handler))))
except:
return ''
class Condition(Tag):
def toShow(self, handler):
return 1
def __call__(self, handler, cdata=''):
if self.toShow(handler):
return cdata
return ''
class Label(Tag):
def toShow(self, handler):
field = self.attrs.get('field')
return field and self.record(handler).get(field)
class List(Tag):
PAGEsIZEkEY="pagesize"
LINEkEY="line"
PAGEsIZE= 10
HTML = '%s'
NA='NA'
ROWfIELDS=()
def fetch(self, handler, line, pageSize):
cursor = self.selection(handler)
return cursor.fetch(line=line, pageSize= pageSize)
def __call__(self, handler, cdata):
records = self.getRows(handler)
html = ''
for record in records:
html += cdata % self.prepareRow(handler, record)
return html
def getPageSize(self, handler):
return int(handler.req().getInput( self.PAGEsIZEkEY, self.getAttrs().get(self.PAGEsIZEkEY, self.PAGEsIZE)))
def getLine(self, handler):
return int(handler.req().getInput( self.LINEkEY, self.getAttrs().get(self.LINEkEY, '1')))
def getRows(self, handler):
return self.fetch(handler, line=self.getLine(handler), pageSize= self.getPageSize(handler))
def prepareRow(self, handler, record):
for field in self.ROWfIELDS:
if field not in record:
record[field] = self.NA
" must return an dictionary of fields that will be merged with the cdata"
return record
def next(self, handler, cdata):
line = self.getLine(handler)
pageSize = self.getPageSize(handler)
if line < self.getRecNumber(handler) - pageSize:
url = handler.req().getUrl().copy()
url[self.LINEkEY] = line + pageSize
return self.HTML % (url, self.getEnabled(cdata))
else:
return self.getDisabled(cdata)
def prev(self, handler, cdata):
line = self.getLine(handler)
pageSize = self.getPageSize(handler)
if line > pageSize:
url = handler.req().getUrl().copy()
url[self.LINEkEY] = line - pageSize
return self.HTML % (url, self.getEnabled(cdata))
else:
return self.getDisabled(cdata)
def getEnabled(self, cdata):
return cdata
def getDisabled(self, cdata):
return cdata
class TwoColumnList(List):
ACTION=''
def getRows(self, handler):
rows = List.getRows(self, handler)
if len(rows) % 2:
if type(rows) is type([]):
rows = tuple(rows)
rows = rows + ('',)
return [ i for n,i in zip(xrange(100), zip(rows, rows[1:])) if n % 2==0]
def prepareRow(self, handler, record):
url = handler.req().getUrl().copy()
row={}
row['uri0'] = url.uri(action=self.ACTION, category=record[0])
row['uri1'] = url.uri(action=self.ACTION, category=record[1])
row['cat0'] = record[0]
row['cat1'] = record[1]
return row
class DbMixin(DataMixin):
DATAMODEL = None
TABLE=None
TABLENAME = 'table'
QS_TABLENAME = TABLENAME
KEYNAME= "loginId"
QS_KEYNAME= KEYNAME
KEY=None
def getField(self, handler, qs_key, key, default=None):
value = handler.req().getInput(qs_key)
if not value:
value = self.attrs.get(key, default)
return value
def getTable(self, handler):
tabelname = self.getField(handler, self.QS_TABLENAME, self.TABLENAME, self.TABLE)
if tablename:
return getattr(self.DATAMODEL, tablename)
def getKey(self, handler):
return self.getField(handler, self.QS_KEYNAME, self.KEYNAME, self.KEY)
def getRecord(self, handler, key):
table = self.getTable(handler)
return datamodel.get(table, key)
def getSelection(self, handler, selectCriteria):
cursor = datamodel.select(datamodel.Contractor, selectCriteria)
return cursor
pso-0.98.D-beta/py/pso/url.py 0100644 0001752 0001751 00000007564 10074405155 015213 0 ustar thanos users #
# pso.url.py - Python Service Objects
#
# Author: Thanos Vassilakis thanos@0x01.com
#
# Copyright (c) thanos vassilakis 2000,2001, 2002
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public License
# as published by the Free Software Foundation; either version 2.1 of the
# License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
# or FITNESS FOR A PARTICULAR PURPOSE.
# See the GNU Lesser General Public License for more details.
#
# See terms of license at gnu.org.
#
# $Id: url.py,v 1.5 2004/07/12 03:50:05 thanos Exp $
#
# created: thanos vassilakis 1/21/2001
#
# LGPL
#
#
__version__="$Revision: 1.5 $"
from urlparse import urlsplit, urlunsplit
from cgi import parse_qs
from urllib import urlencode
from xml.sax.saxutils import quoteattr
from copy import deepcopy
class Url(object):
_query=None
_script=None
def __init__(self, url, scheme="html"):
self.scheme, self.netlocation, self.path, query, self.fragment = urlsplit(url, scheme)
self.queryTD = self.decryptQuery(query)
self.changed=1
self._formFields =""
def decryptQuery(self, query): return query
def encryptQuery(self, query): return query
def processQuery(self):
if self._query is None:
self._query = parse_qs(self.queryTD)
return self._query
query = property(processQuery)
def getScript(self):
if self.changed or self._script is None:
self._script = urlunsplit((self.scheme, self.netlocation, self.path,'',''))
return self._script
script = property(getScript)
def getBase(self):
if self.changed or self._script is None:
self._script = urlunsplit((self.scheme, self.netlocation, '','',''))
return self._script
base = property(getBase)
def __setitem__(self, key, value):
self.changed=1
self.query[key] = value
def __delitem__(self, key):
try:
self.changed=1
del self.query[key]
except:
pass
def __getitem__(self,key):
value= self.query.get(key, None)
if type(value) is type([]):
if len(value) == 1:
return value[0]
return value
def clear(self, *args):
if not args:
self.query.clear()
else:
for arg in args:
del self[arg]
def append(self, key, value):
self.changed=1
try:
self.query[key].append(value)
except:
self.query[key]=[value]
NDICT={}
def __str__(self):
if self.changed:
self.queryTD= urlencode(self.query, self.query.items())
return urlunsplit((self.scheme, self.netlocation, self.path, self.encryptQuery(self.queryTD), self.fragment))
def getFormFields(self):
if self.changed:
self._formFields =""
for k, values in self.query.items():
if values:
if type(values) is type([]):
for v in values:
self._formFields = '%s\n' % (self._formFields, k, v)
else:
self._formFields = '%s\n' % (self._formFields, k, values)
return self._formFields
formFields = property(getFormFields)
def copy(self):
return deepcopy(self)
def uri(self, **kws):
query ={}
if not kws.get('_cleanup', True):
query.update(self.query)
for k,v in kws.items():
if v is None:
del kws[k]
if k in query:
del query[k]
else:
query[k] = v
query = self.encryptQuery(urlencode(query, query.items()))
return urlunsplit(('','',self.path, query, ''))
def aHref(self, cdata, **kws):
query = self.encryptQuery(urlencode(kws, kws.items()))
return '%s' %(urlunsplit(('','',self.path, query, '')), cdata)
def newA(self, uri, cdata, **attr):
attrlist = ["%s=%s" % (k, quoteattr(v)) for k,v in attr.items() if v]
attrlist.extend([k for k,v in attr.items() if not v])
attrlist = ' '.join(attrlist)
return '%s' %( uri, attrlist, cdata)
pso-0.98.D-beta/py/pso/util.py 0100644 0001752 0001751 00000005424 10074405047 015357 0 ustar thanos users #
# $RSCFile$ - Python Service Objects
#
# Author: Thanos Vassilakis thanos@0x01.com
#
#
# Copyright (c) thanos vassilakis 2000,2001, 2002
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public License
# as published by the Free Software Foundation; either version 2.1 of the
# License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
# or FITNESS FOR A PARTICULAR PURPOSE.
# See the GNU Lesser General Public License for more details.
#
# See terms of license at gnu.org.
# $Id: util.py,v 1.11 2004/07/12 03:48:55 thanos Exp $
#
__version__="$Revision: 1.11 $"
import time, gc, sys, weakref
class Log:
def __init__(self, path=None):
self.logfile = path
def log(self, *args):
args = map(str, args)
post = "\n%s: %s" % ( time.ctime(), ' '.join(args))
try:
open(self.logfile,'a').write(post)
except:
import traceback
traceback.print_exc()
import os, tempfile
logger=Log(os.environ.get('PSOLOG',os.path.join(tempfile.gettempdir(), 'pso.log')))
log = logger.log
class MixIn:
def getDirectives(self, objclass, reqHandler):
directives ={}
for key in objclass.DIRECTIVES:
lkey = objclass.DIRECTIVEtAG + key
value = reqHandler.getEnviron( lkey)
if value:
directives[key] = value
return directives
def mkDict(**kv):
return kv
def get(dict,key, default=None):
if dict.has_key(key):
return dict[key]
return default
"""
class GCDumper:
def __init__(self):
" set up gc in debug mode"
gc.enable()
gc.set_debug(gc.DEBUG_LEAK)
def dump(self, file=None):
" dumps to file, file=stdout by defaut, garbadgeed objects"
gc.collect()
if file is None:
file = sys.stdout
for x in gc.garbage:
strX = str(x)
if len(strX) > 80: tail = '...'
else: tail =''
file.write("%s: %s%s\n" % ( type(x), strX[:77], tail))
class meta_ObjTracker:
classes = {}
def instance(celf, obj):
ref = weakref.ref(obj)
key = obj.__class__.__name__
try:
celf.classes[key].append(ref)
except:
celf.classes[key] = [ref]
instance = classmethod(instance)
def report(celf, classes=None):
if classes is None:
classes = celf.classes.keys()
else:
classes = classes.split()
classes.sort()
for name in classes:
for ref in celf.classes[name]:
obj =ref()
if obj is not None:
print obj
report = classmethod(report)
"""
if __name__ =='__main__':
d = GCDumper()
l =[]
l.append(l)
del l
d.dump()
class A:
def __init__(self):
ObjTracker.instance(self)
class B:
def __init__(self):
ObjTracker.instance(self)
def test():
a =A()
b = B()
for i in xrange(10): test()
ObjTracker.report()
pso-0.98.D-beta/py/pso/validation.py 0100666 0001752 0001751 00000003110 10074403033 016517 0 ustar thanos users #
# Copyright (c) thanos vassilakis 2000,2001, 2002
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public License
# as published by the Free Software Foundation; either version 2.1 of the
# License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
# or FITNESS FOR A PARTICULAR PURPOSE.
# See the GNU Lesser General Public License for more details.
#
# See terms of license at gnu.org.
#
# $Id: validation.py,v 1.1 2003/01/24 17:33:24 thanos Exp $
__version__="$Revision: 1.1 $"
import traceback
def isZipCode(zipCode):
try:
sz = len(zipCode)
if sz == 10:
zipCode.index('-',5)
int(zipCode[:5])
int(zipCode[6:])
elif sz in (5, 9):
code = int(zipCode)
else:
raise Exception()
except:
raise Exception('Invalid zip code, must be 5 or 9 digits')
return zipCode
def test(funcwhat, res1, res2, show=0):
print "trying ", funcwhat,
try:
exec(funcwhat)
except:
if show:
traceback.print_exc()
print res2
else:
print res1
if __name__ =='__main__':
test( "isZipCode('12345-6789')", "OK", "failed")
test( "isZipCode('123456789')", "OK", "failed")
test( "isZipCode('12345')", "OK", "failed")
test( "isZipCode('12345678')", "OK", "failed")
test( "isZipCode('1234256789AB')", "OK", "failed")
pso-0.98.D-beta/setup.py 0100644 0001752 0001751 00000001515 10074410551 014302 0 ustar thanos users #!/usr/bin/env python23
from distutils.core import setup
setup(name="pso",
version="0.98.D-beta",
description="Python Service Objects - An object orientated web development framework.",
author="thanos vassilakis",
author_email="thanos@scriptfoundry.com",
url="http://sourceforge.net/projects/pso",
package_dir = {'': 'py'},
packages=['pso'],
)
"""
classifiers= ['Topic :: Internet :: WWW/HTTP :: Dynamic Content',
'Topic :: Internet :: WWW/HTTP :: Dynamic Content :: CGI Tools/Libraries',
'Topic :: Software Development :: Libraries :: Python Modules',
'Environment :: Web Environment',
'License :: OSI Approved :: GNU Library or Lesser General Public License (LGPL)',
'Operating System :: OS Independent',
'Programming Language :: Python',
'Intended Audience :: Developers']
"""
pso-0.98.D-beta/PKG-INFO 0100644 0001752 0001751 00000000457 10074410553 013673 0 ustar thanos users Metadata-Version: 1.0
Name: pso
Version: 0.98.D-beta
Summary: Python Service Objects - An object orientated web development framework.
Home-page: http://sourceforge.net/projects/pso
Author: thanos vassilakis
Author-email: thanos@scriptfoundry.com
License: UNKNOWN
Description: UNKNOWN
Platform: UNKNOWN