Update of /cvsroot/webware/Webware/WebKit/Experimental
In directory sc8-pr-cvs1:/tmp/cvs-serv19084
Added Files:
DictCall.html DictCall.py DictCall.txt default.css
Log Message:
Added an experimental function (probably would end up in MiscUtils)
that unpacks dictionaries to call functions, as you might unpack
request.fields() to call a method.
--- NEW FILE: DictCall.html ---
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="generator" content="Docutils 0.2.8: http://docutils.sourceforge.net/" />
<title>DictCall</title>
<link rel="stylesheet" href="default.css" type="text/css" />
</head>
<body>
<div class="document" id="dictcall">
<h1 class="title">DictCall</h1>
<p>DictCall primarily exports the function <cite>dictCall</cite>, which may
raise the exceptions <cite>NotFound</cite> or <cite>Invalid</cite> (both of which
are inherited from <cite>DictCallError</cite>.</p>
<!-- include: dictCall -->
<a class="target" id="id1" name="id1"></a><div class="topic">
<p class="topic-title"><tt class="literal"><span class="pre">dictCall(func,</span> <span class="pre">d)</span></tt>:</p>
<p>Calls the function <cite>func</cite> with the information from dictionary
<cite>d</cite>.</p>
<p><cite>d</cite> is expected to be a dictionary of strings, possibly with
lists of strings for some keys, as might be generated by the
<cite>cgi</cite> module. <cite>dictCall</cite> will match the keys of the dictionary
with the arguments of the function.</p>
<p>The function can provide type information, so that the input is
verified and coerced in some fashion. However, type information
is not required.</p>
<p><strong>Defining Parameter Types</strong></p>
<p>There are two ways of providing type information: by the parameter
names themselves, or in the docstring.</p>
<p>Parameter names can be typed by appending the types to the name,
like <tt class="literal"><span class="pre">var_int</span></tt>. The dictionary will still be searched for a
variable <tt class="literal"><span class="pre">var</span></tt>, but then it will be converted into an int.
However, note that your parameter is still named var_int! This
can be annoying.</p>
<p>Instead you can put the type information in the docstring. You
should begin this information with a line like:</p>
<pre class="literal-block">
call types:
</pre>
<p>on a line by itself. Later lines should be of the format:</p>
<pre class="literal-block">
var: dict, int
</pre>
<p>where <tt class="literal"><span class="pre">dict,</span> <span class="pre">int</span></tt> equivalent to var_dict_int (types are
described later). You end this section of information with a
blank line. Indentation is not significant. Variables that are
simply strings may be omited.</p>
<p>You can also put the information in a function attribute, like:</p>
<pre class="literal-block">
def myFunc(a, b, c):
pass
myFunc.callTypes={'a': 'dict,int', 'c': 'int'}
</pre>
<p>This is equivalent to <tt class="literal"><span class="pre">myFunc(a_dict_int,</span> <span class="pre">b,</span> <span class="pre">c_int)</span></tt>. Note
Python 2.3 you can use:</p>
<pre class="literal-block">
myFunc.callTypes=dict(a='dict,int', c='int')
</pre>
<p><strong>Parameter Types</strong></p>
<p>The basic types, besides the implicit string type, are <tt class="literal"><span class="pre">int</span></tt> and
<tt class="literal"><span class="pre">float</span></tt>.</p>
<p>In addition to these types there are three compound types:</p>
<dl>
<dt><tt class="literal"><span class="pre">set</span></tt>:</dt>
<dd><p class="first">Sets are actually returned as lists, but they are not
generally ordered. When a dictionary is passed in like
<tt class="literal"><span class="pre">{'var':</span> <span class="pre">['a',</span> <span class="pre">'b']}</span></tt>, this returns <tt class="literal"><span class="pre">['a',</span> <span class="pre">'b']</span></tt> (it's
Invalid if you don't indicate that it's a set). It also
promotes non-lists to a list, and if nothing is present
returns the empty list (i.e., <tt class="literal"><span class="pre">{'var':</span> <span class="pre">'a'}</span></tt> returns
<tt class="literal"><span class="pre">['a']</span></tt>, and <tt class="literal"><span class="pre">{}</span></tt> returns <tt class="literal"><span class="pre">[]</span></tt>).</p>
<p class="last">Sets can be used with <tt class="literal"><span class="pre">int</span></tt> and <tt class="literal"><span class="pre">float</span></tt>, i.e., a type
of <tt class="literal"><span class="pre">set,</span> <span class="pre">int</span></tt> will return a list of integers. You cannot
put a <tt class="literal"><span class="pre">dict</span></tt> or <tt class="literal"><span class="pre">list</span></tt> inside a set, though a set can
go inside them.</p>
</dd>
<dt><tt class="literal"><span class="pre">dict</span></tt>:</dt>
<dd><p class="first">A dictionary takes keys of the form <tt class="literal"><span class="pre">var1:key</span></tt> and
turns them into nested dictionaries. So with a type
dict, <tt class="literal"><span class="pre">{'var:a':</span> <span class="pre">'apple',</span> <span class="pre">'var:b':</span> <span class="pre">'banana'}</span></tt> will
return <tt class="literal"><span class="pre">{'a':</span> <span class="pre">'apple',</span> <span class="pre">'b':</span> <span class="pre">'banana'}</span></tt>.</p>
<p class="last">Dict can be nested, so that keys like <tt class="literal"><span class="pre">var1:key1:key2</span></tt>
are possible, and can also be nested with <tt class="literal"><span class="pre">list</span></tt> and
contain <tt class="literal"><span class="pre">set</span></tt>, <tt class="literal"><span class="pre">int</span></tt>, or <tt class="literal"><span class="pre">float</span></tt>.</p>
</dd>
<dt><tt class="literal"><span class="pre">list</span></tt>:</dt>
<dd>Essentially the same as dict, only it uses the keys only
for ordering, and expects those keys to be integers.
So <tt class="literal"><span class="pre">{'var:1':</span> <span class="pre">'first',</span> <span class="pre">'var:2':</span> <span class="pre">'second'}</span></tt> returns
<tt class="literal"><span class="pre">['first',</span> <span class="pre">'second']</span></tt>.</dd>
</dl>
<p><strong>Using Types Together</strong></p>
<p>If you are, for instance, collecting a list of first and
last names, you can use compound types to manage the fields.
Generate the form like:</p>
<pre class="literal-block">
for i in range(len(names)):
self.write('<input type="text" name="names:%i:fname" value="%s">'
% (i, htmlEncode(names[i]['fname'])))
self.write('<input type="text" name="names:%i:lname" value="%s">'
% (i, htmlEncode(names[i]['fname'])))
</pre>
<p>Then the method that accepts the form looks like:</p>
<pre class="literal-block">
def saveNames(self, names_list_dict)
</pre>
<p><tt class="literal"><span class="pre">names_list_dict</span></tt> will look like
<tt class="literal"><span class="pre">[{'fname':</span> <span class="pre">...,</span> <span class="pre">'lname':</span> <span class="pre">...},</span> <span class="pre">...]</span></tt></p>
</div>
<a class="target" id="specdict" name="specdict"></a><div class="topic">
<p class="topic-title"><tt class="literal"><span class="pre">specDict(func)</span></tt>:</p>
<p>Returns a dictionary that contains whatever type specification
there is for the function.</p>
<p>That dictionary has a key for each value expected or allowed in
the request dictionary -- essentially a key for each argument
variable. For each key there's another dictionary. There's keys
<tt class="literal"><span class="pre">targetName</span></tt> and <tt class="literal"><span class="pre">type</span></tt>, where targetName gives the variable
name in the function definition (which may contain type
information embedded, e.g. var1_int would be considered the
variable <tt class="literal"><span class="pre">"var1"</span></tt> with a type <tt class="literal"><span class="pre">["int"]</span></tt> and a targetName
<tt class="literal"><span class="pre">"var1_int"</span></tt>. Also has the key <tt class="literal"><span class="pre">default</span></tt> which is a boolean,
whether this key has a default value.</p>
<p>The presence of the key <tt class="literal"><span class="pre">**</span></tt> means that extra keyword arguments
are allowed (always as strings, unparsed).</p>
</div>
</div>
</body>
</html>
--- NEW FILE: DictCall.py ---
"""
DictCall primarily exports the function `dictCall`, which may
raise the exceptions `NotFound` or `Invalid` (both of which
are inherited from `DictCallError`.
.. include: dictCall
.. ignore: DictCallError, NotFound, Invalid
.. ignore: parseCallTypes, parseDocString, fixupSpec, parseArgList
.. ignore: extractVariable, extractVariableConverted
.. ignore: convertDict, unconvertDict
"""
import re
import inspect
True, False = 1==1, 1==0
__all__ = ['DictCallError', 'NotFound', 'Invalid', 'dictCall']
class DictCallError(Exception): pass
class NotFound(DictCallError):
def __init__(self, var, dict=None, *args):
# @@: do something with these variables...
DictCallError(self, *args)
self._var = var
self._dict = dict
class Invalid(DictCallError): pass
def dictCall(func, d):
"""
Calls the function `func` with the information from dictionary
`d`.
`d` is expected to be a dictionary of strings, possibly with
lists of strings for some keys, as might be generated by the
`cgi` module. `dictCall` will match the keys of the dictionary
with the arguments of the function.
The function can provide type information, so that the input is
verified and coerced in some fashion. However, type information
is not required.
**Defining Parameter Types**
There are two ways of providing type information: by the parameter
names themselves, or in the docstring.
Parameter names can be typed by appending the types to the name,
like ``var_int``. The dictionary will still be searched for a
variable ``var``, but then it will be converted into an int.
However, note that your parameter is still named var_int! This
can be annoying.
Instead you can put the type information in the docstring. You
should begin this information with a line like::
call types:
on a line by itself. Later lines should be of the format::
var: dict, int
where ``dict, int`` equivalent to var_dict_int (types are
described later). You end this section of information with a
blank line. Indentation is not significant. Variables that are
simply strings may be omited.
You can also put the information in a function attribute, like::
def myFunc(a, b, c):
pass
myFunc.callTypes={'a': 'dict,int', 'c': 'int'}
This is equivalent to ``myFunc(a_dict_int, b, c_int)``. Note
Python 2.3 you can use::
myFunc.callTypes=dict(a='dict,int', c='int')
**Parameter Types**
The basic types, besides the implicit string type, are ``int`` and
``float``.
In addition to these types there are three compound types:
``set``:
Sets are actually returned as lists, but they are not
generally ordered. When a dictionary is passed in like
``{'var': ['a', 'b']}``, this returns ``['a', 'b']`` (it's
Invalid if you don't indicate that it's a set). It also
promotes non-lists to a list, and if nothing is present
returns the empty list (i.e., ``{'var': 'a'}`` returns
``['a']``, and ``{}`` returns ``[]``).
Sets can be used with ``int`` and ``float``, i.e., a type
of ``set, int`` will return a list of integers. You cannot
put a ``dict`` or ``list`` inside a set, though a set can
go inside them.
``dict``:
A dictionary takes keys of the form ``var1:key`` and
turns them into nested dictionaries. So with a type
dict, ``{'var:a': 'apple', 'var:b': 'banana'}`` will
return ``{'a': 'apple', 'b': 'banana'}``.
Dict can be nested, so that keys like ``var1:key1:key2``
are possible, and can also be nested with ``list`` and
contain ``set``, ``int``, or ``float``.
``list``:
Essentially the same as dict, only it uses the keys only
for ordering, and expects those keys to be integers.
So ``{'var:1': 'first', 'var:2': 'second'}`` returns
``['first', 'second']``.
**Using Types Together**
If you are, for instance, collecting a list of first and
last names, you can use compound types to manage the fields.
Generate the form like::
for i in range(len(names)):
self.write('<input type="text" name="names:%i:fname" value="%s">'
% (i, htmlEncode(names[i]['fname'])))
self.write('<input type="text" name="names:%i:lname" value="%s">'
% (i, htmlEncode(names[i]['fname'])))
Then the method that accepts the form looks like::
def saveNames(self, names_list_dict)
``names_list_dict`` will look like
``[{'fname': ..., 'lname': ...}, ...]``
"""
spec = specDict(func)
d = convertDict(d)
callDict = {}
for variable, spec in spec.items():
if variable == '**':
continue
targetName = spec['targetName']
t = spec['type']
try:
callDict[targetName], d = extractVariableConverted(variable, t, d)
except NotFound:
if not spec['default']:
raise
if d and not spec.has_key('**'):
raise TypeError, "Arguments unconverted: %s" % repr(d)
for key in d.keys():
if callDict.has_key(key):
raise TypeError, "Argument unparsed: %s" % key
callDict.update(d)
return func(**callDict)
def specDict(func):
"""
Returns a dictionary that contains whatever type specification
there is for the function.
That dictionary has a key for each value expected or allowed in
the request dictionary -- essentially a key for each argument
variable. For each key there's another dictionary. There's keys
``targetName`` and ``type``, where targetName gives the variable
name in the function definition (which may contain type
information embedded, e.g. var1_int would be considered the
variable ``"var1"`` with a type ``["int"]`` and a targetName
``"var1_int"``. Also has the key ``default`` which is a boolean,
whether this key has a default value.
The presence of the key ``**`` means that extra keyword arguments
are allowed (always as strings, unparsed).
"""
if hasattr(func, 'specDict'):
pass
elif hasattr(func, 'callTypes'):
func.specDict = parseCallTypes(func)
elif func.__doc__ and specDictDocRE.search(func.__doc__):
func.specDict = parseDocString(func)
else:
func.specDict = parseArgList(func)
return func.specDict
def parseCallTypes(func):
callTypes = func.callTypes
spec = {}
for arg, typeList in func.callTypes.items():
info = {}
info['targetName'] = arg
if type(typeList) is not type([]):
typeList = [typeList]
info['type'] = []
for subT in typeList:
info['type'].extend([t.strip() for t in subT.split(',')])
spec[arg] = info
return fixupSpec(func, spec)
specDictDocRE = re.compile(r'call types:\s*\n', re.I)
specLineRE = re.compile(r'([a-zA-Z_][a-zA-Z_0-9]*): (.*)')
def parseDocString(func):
doc = func.__doc__
match = specDictDocRE.search(doc)
doc = doc[match.end():].strip()
lines = [l.strip() for l in doc.split('\n')]
while lines and not lines[0]:
# get rid of leading blank lines
lines.pop(0)
try:
lines = lines[:lines.index('')]
except ValueError:
pass
spec = {}
for line in lines:
match = specLineRE.search(line)
if not match:
raise TypeError, "Doc string line not understood: %s" % repr(line)
info = {}
info['targetName'] = match.group(1)
info['type'] = [t.strip() for t in match.group(2).split(',')]
spec[match.group(1)] = info
return fixupSpec(func, spec)
def fixupSpec(func, spec):
args, varargs, varkw, defaults = inspect.getargspec(func)
if varkw:
spec['**'] = 1
for i in range(len(args)):
arg = args[i]
if not spec.has_key(arg):
spec[arg] = {'targetName': arg, 'type': []}
spec[arg]['default'] = i < len(args) - len(defaults)
return spec
_specialEndings = ['int', 'float', 'dict', 'list', 'set']
def parseArgList(func):
args, varargs, varkw, defaults = inspect.getargspec(func)
spec = {}
if varkw:
spec['**'] = 1
for i in range(len(args)):
info = {}
t = []
arg = args[i]
info['targetName'] = arg
info['default'] = i < len(args) - len(defaults)
while 1:
changed = 0
for ending in _specialEndings:
if arg.endswith('_' + ending):
arg = arg[:-(len(ending)+1)]
t = [ending] + t
changed = 1
break
if not changed:
break
info['type'] = t
spec[arg] = info
return spec
def extractVariable(var, t, d):
"""
Extracts variable `var`, which is of type `t`, from dictionary
`d`. `t` should be a list (possibly empty) of types, such
as ``["list", "int"]`` which means list-of-integers. String
is implied in absense of a type.
``d`` is a dictionary of strings (keys and values). Values,
however, may be a list of strings.
These basic types are supported:
``string`` (or nothing):
A string, if empty returns ``''``. If a list is in the
value it will throw an exception, like all the basic
types (use ``['set', 'string']`` instead).
``int``:
Integer, if empty string returns None.
``float``:
Float, if empty string returns None.
And these compound types:
``set``:
Returns an list of values, ordered arbitrarily. Will take
lists that are in the value of the dictionary, or promote
to a list a normal string.
``dict``:
Expects variables like var:key.
``list``:
Like ``dict``, with var:index, and then sorts by index
(as an integer), and returns just the values sorted that
way.
Raises NotFound if a variable can't be found, Invalid if
there's some other parsing problem.
Returns a tuple of the parsed-out values, and the portion
of the dictionary that wasn't used.
"""
value, d = extractVariableConverted(var, t, convertDict(d))
return value, unconvertDict(d)
def extractVariableConverted(var, t, d):
# basic types
if not t or t[0] in _basicConvertTypes:
try:
val = d[var]
except KeyError:
raise NotFound(var=var, dict=d)
del d[var]
val = _basicConvertValue(t, val)
return val, d
# compound types
t, rest = t[0], t[1:]
if t == 'set':
try:
val = d[var]
except KeyError:
return [], d
del d[var]
if type(val) is not type([]):
val = [val]
if not rest or rest[0] in _basicConvertTypes:
for v in val:
if type(v) is type({}):
# @@: better error
raise Invalid, 'Nested dictionaries not expected (got: %s)' % v
if rest:
val = [_basicConvertValue(rest, v) for v in val]
return val, d
raise TypeError, 'set cannot contain other compound types (like %s)' % rest
elif t in ('dict', 'list'):
try:
val = d[var]
except KeyError:
return {}, d
del d[var]
if type(val) is not type({}):
# @@: better error
raise Invalid
if rest and rest[0] in _basicConvertTypes:
for key in val.keys():
val[key] = _basicConvertValue(rest, val[key])
elif rest:
for key in val.keys():
val[key], ignore = extractVariableConverted(key, rest, val)
if t == 'list':
val = [(int(key), value) for key, value in val.items()]
val.sort()
val = [value for key, value in val]
return val, d
_basicConvertTypes = ['int', 'float']
def _basicConvertValue(t, val):
"""
Convert a value based on [] (string), [``int``], [``float``].
"""
if t and len(t) > 1:
raise TypeError, '"%s" must be the last type in a type list (got: %s)' % (t[0], repr(t))
if not t: # string
if not type(val) is type(""):
# @@: better error
raise Invalid
return val
elif t[0] == 'int':
if val == '':
return None
try:
return int(val)
except:
# @@: better error
raise Invalid
elif t[0] == 'float':
if val == '':
return None
try:
return float(val)
except:
# @@: better error
raise Invalid
def convertDict(d):
"""
Takes a flat dictionary and makes it deeper, where keys
are strings and may be separated by ``:``, so that a key
``val1:val2`` which mean that ``val1`` will be a dictionary
with the key ``val2`` in it.
"""
result = {}
for key in d.keys():
if key.find(':') == -1:
# Just a quick optimization for this common case
result[key] = d[key]
continue
parts = key.split(':')
inner = result
for part in parts[:-1]:
try:
inner = inner[part]
except KeyError:
inner[part] = {}
inner = inner[part]
inner[parts[-1]] = d[key]
return result
def unconvertDict(d):
"""
Flattens a dictionary, undoing `convertDict`.
"""
result = {}
for key, value in d.items():
if type(value) is type({}):
value = unconvertDict(value)
for key2, value2 in value.items():
result["%s:%s" % (key, key2)] = value2
else:
result[key] = value
return result
if __name__ == '__main__':
def callMe(a, b, c, d=None):
print 'a=%r\nb=%r\nc=%r\nd=%r' % (a, b, c, d)
callMe.specDict = {
'a': {'targetName': 'a',
'type': ['int'],
'default': False},
'b': {'targetName': 'b',
'type': ['list', 'float'],
'default': False},
'c': {'targetName': 'c',
'type': ['set'],
'default': False},
'd': {'targetName': 'd',
'type': ['dict', 'dict'],
'default': True}}
def callMe2(a_int, b_list_float, c_set, d_dict_dict=None):
print 'a=%r\nb=%r\nc=%r\nd=%r' % (a_int, b_list_float, c_set, d_dict_dict)
def callMe3(a, b, c, d=10):
"""
call types:
a: int
b: list, float
c: set
d: dict, dict
"""
print 'a=%r\nb=%r\nc=%r\nd=%r' % (a, b, c, d)
def callMe4(a, b, c, d=None):
print 'a=%r\nb=%r\nc=%r\nd=%r' % (a, b, c, d)
callMe4.callTypes = {
'a': 'int', 'b': 'list,float', 'c': 'set', 'd': ['dict', 'dict']}
t = """
>>> convertDict({'a': 'A', 'b:c': 'C', 'b:d': 'D', '1:2:3': '4'})
>>> unconvertDict(convertDict({'a': 'A', 'b:c': 'C', 'b:d': 'D', '1:2:3': '4'}))
>>> extractVariable('happy', ['int'], {'happy': '102'})
>>> extractVariable('t', ['set', 'int'], {})
>>> extractVariable('t', ['set', 'int'], {'t': '20'})
>>> extractVariable('t', ['set', 'int'], {'t': ['20', '30', '20']})
>>> extractVariable('t', ['dict', 'int'], {'t:a': '20', 't:b': '30'})
>>> extractVariable('t', ['dict', 'int'], {'t:a': '20', 't:b': '30', 'c': 'hey'})
>>> extractVariable('t', ['dict', 'set', 'int'], {'t:a': '20', 't:b': ['30', '40']})
>>> extractVariable('t', ['dict', 'dict', 'int'], {'t:a:c': '20', 't:b:d': '40'})
>>> extractVariable('t', ['list', 'int'], {'t:2': '20', 't:1': '40', 't:3': '60'})
>>> extractVariable('t', ['list', 'dict', 'int'], {'t:2:c': '20', 't:1:d': '40'})
>>> dictCall(callMe, {'a': '20', 'b:2': '10.2', 'b:5': '0', 'b:7': '', 'c': 'hey', 'c': 'you', 'c': 'whatever', 'd:d:d': 'yep'})
>>> dictCall(callMe2, {'a': '20', 'b:2': '10.2', 'b:5': '0', 'b:7': '', 'c': 'hey', 'c': 'you', 'c': 'whatever', 'd:d:d': 'yep'})
>>> dictCall(callMe3, {'a': '20', 'b:2': '10.2', 'b:5': '0', 'b:7': '', 'c': 'hey', 'c': 'you', 'c': 'whatever', 'd:d:d': 'yep'})
>>> dictCall(callMe4, {'a': '20', 'b:2': '10.2', 'b:5': '0', 'b:7': '', 'c': 'hey', 'c': 'you', 'c': 'whatever', 'd:d:d': 'yep'})
"""
for line in t.split('\n'):
if line.startswith('>>>'):
print line
line = line[3:].strip()
val = eval(line)
if val is not None: print val
--- NEW FILE: DictCall.txt ---
DictCall
========
.. contents::
DictCall primarily exports the function `dictCall`, which may
raise the exceptions `NotFound` or `Invalid` (both of which
are inherited from `DictCallError`.
.. include: dictCall
.. _dictCall:
.. topic:: ``dictCall(func, d)``:
Calls the function `func` with the information from dictionary
`d`.
`d` is expected to be a dictionary of strings, possibly with
lists of strings for some keys, as might be generated by the
`cgi` module. `dictCall` will match the keys of the dictionary
with the arguments of the function.
The function can provide type information, so that the input is
verified and coerced in some fashion. However, type information
is not required.
**Defining Parameter Types**
There are two ways of providing type information: by the parameter
names themselves, or in the docstring.
Parameter names can be typed by appending the types to the name,
like ``var_int``. The dictionary will still be searched for a
variable ``var``, but then it will be converted into an int.
However, note that your parameter is still named var_int! This
can be annoying.
Instead you can put the type information in the docstring. You
should begin this information with a line like::
call types:
on a line by itself. Later lines should be of the format::
var: dict, int
where ``dict, int`` equivalent to var_dict_int (types are
described later). You end this section of information with a
blank line. Indentation is not significant. Variables that are
simply strings may be omited.
You can also put the information in a function attribute, like::
def myFunc(a, b, c):
pass
myFunc.callTypes={'a': 'dict,int', 'c': 'int'}
This is equivalent to ``myFunc(a_dict_int, b, c_int)``. Note
Python 2.3 you can use::
myFunc.callTypes=dict(a='dict,int', c='int')
**Parameter Types**
The basic types, besides the implicit string type, are ``int`` and
``float``.
In addition to these types there are three compound types:
``set``:
Sets are actually returned as lists, but they are not
generally ordered. When a dictionary is passed in like
``{'var': ['a', 'b']}``, this returns ``['a', 'b']`` (it's
Invalid if you don't indicate that it's a set). It also
promotes non-lists to a list, and if nothing is present
returns the empty list (i.e., ``{'var': 'a'}`` returns
``['a']``, and ``{}`` returns ``[]``).
Sets can be used with ``int`` and ``float``, i.e., a type
of ``set, int`` will return a list of integers. You cannot
put a ``dict`` or ``list`` inside a set, though a set can
go inside them.
``dict``:
A dictionary takes keys of the form ``var1:key`` and
turns them into nested dictionaries. So with a type
dict, ``{'var:a': 'apple', 'var:b': 'banana'}`` will
return ``{'a': 'apple', 'b': 'banana'}``.
Dict can be nested, so that keys like ``var1:key1:key2``
are possible, and can also be nested with ``list`` and
contain ``set``, ``int``, or ``float``.
``list``:
Essentially the same as dict, only it uses the keys only
for ordering, and expects those keys to be integers.
So ``{'var:1': 'first', 'var:2': 'second'}`` returns
``['first', 'second']``.
**Using Types Together**
If you are, for instance, collecting a list of first and
last names, you can use compound types to manage the fields.
Generate the form like::
for i in range(len(names)):
self.write('<input type="text" name="names:%i:fname" value="%s">'
% (i, htmlEncode(names[i]['fname'])))
self.write('<input type="text" name="names:%i:lname" value="%s">'
% (i, htmlEncode(names[i]['fname'])))
Then the method that accepts the form looks like::
def saveNames(self, names_list_dict)
``names_list_dict`` will look like
``[{'fname': ..., 'lname': ...}, ...]``
.. _specDict:
.. topic:: ``specDict(func)``:
Returns a dictionary that contains whatever type specification
there is for the function.
That dictionary has a key for each value expected or allowed in
the request dictionary -- essentially a key for each argument
variable. For each key there's another dictionary. There's keys
``targetName`` and ``type``, where targetName gives the variable
name in the function definition (which may contain type
information embedded, e.g. var1_int would be considered the
variable ``"var1"`` with a type ``["int"]`` and a targetName
``"var1_int"``. Also has the key ``default`` which is a boolean,
whether this key has a default value.
The presence of the key ``**`` means that extra keyword arguments
are allowed (always as strings, unparsed).
--- NEW FILE: default.css ---
/*
:Author: David Goodger
:Contact: goodger@...
:date: $Date: 2003/03/07 08:32:54 $
:version: $Revision: 1.1 $
:copyright: This stylesheet has been placed in the public domain.
Default cascading style sheet for the HTML output of Docutils.
Modified slightly for Webware.
*/
.first {
margin-top: 0 }
.last {
margin-bottom: 0 }
a.toc-backref {
text-decoration: none ;
color: black }
dd {
margin-bottom: 0.5em }
div.abstract {
margin: 2em 5em }
div.abstract p.topic-title {
font-weight: bold ;
text-align: center }
div.attention, div.caution, div.danger, div.error, div.hint,
div.important, div.note, div.tip, div.warning {
margin: 2em ;
border: medium outset ;
padding: 1em }
div.attention p.admonition-title, div.caution p.admonition-title,
div.danger p.admonition-title, div.error p.admonition-title,
div.warning p.admonition-title {
color: red ;
font-weight: bold ;
font-family: sans-serif }
div.hint p.admonition-title, div.important p.admonition-title,
div.note p.admonition-title, div.tip p.admonition-title {
font-weight: bold ;
font-family: sans-serif }
div.dedication {
margin: 2em 5em ;
text-align: center ;
font-style: italic }
div.dedication p.topic-title {
font-weight: bold ;
font-style: normal }
div.figure {
margin-left: 2em }
div.footer, div.header {
font-size: smaller }
div.system-messages {
margin: 5em }
div.system-messages h1 {
color: red }
div.system-message {
border: medium outset ;
padding: 1em }
div.system-message p.system-message-title {
color: red ;
font-weight: bold }
div.topic {
margin: 2em }
h1.title {
text-align: center;
}
h1, h2, h3, h4, h5, h6 {
font-family: Helvetica, Arial, sans-serif; }
h2.subtitle {
text-align: center }
hr {
width: 75% }
ol.simple, ul.simple {
margin-bottom: 1em }
ol.arabic {
list-style: decimal }
ol.loweralpha {
list-style: lower-alpha }
ol.upperalpha {
list-style: upper-alpha }
ol.lowerroman {
list-style: lower-roman }
ol.upperroman {
list-style: upper-roman }
p.caption {
font-style: italic }
p.credits {
font-style: italic ;
font-size: smaller }
p.label {
white-space: nowrap }
p.topic-title {
font-weight: bold }
pre.address {
margin-bottom: 0 ;
margin-top: 0 ;
font-family: serif ;
font-size: 100% }
pre.line-block {
font-family: serif ;
font-size: 100% }
pre.literal-block, pre.doctest-block {
margin-left: 2em ;
margin-right: 2em ;
background-color: #eeeeee }
span.classifier {
font-family: sans-serif ;
font-style: oblique }
span.classifier-delimiter {
font-family: sans-serif ;
font-weight: bold }
span.interpreted {
font-family: sans-serif }
span.option-argument {
font-style: italic }
span.pre {
white-space: pre }
span.problematic {
color: red }
table {
margin-top: 0.5em ;
margin-bottom: 0.5em }
table.citation {
border-left: solid thin gray ;
padding-left: 0.5ex }
table.docinfo {
margin: 2em 4em }
table.footnote {
border-left: solid thin black ;
padding-left: 0.5ex }
td, th {
padding-left: 0.5em ;
padding-right: 0.5em ;
vertical-align: top }
th.docinfo-name, th.field-name {
font-weight: bold ;
text-align: left ;
white-space: nowrap }
h1 tt, h2 tt, h3 tt, h4 tt, h5 tt, h6 tt {
font-size: 100% }
/* tt {
background-color: #eeeeee } */
ul.auto-toc {
list-style-type: none }
|