Author: chrisz
Date: Fri Nov 24 08:36:47 2006
New Revision: 5932
Modified:
Webware/trunk/AllTests.py
Webware/trunk/MiscUtils/DataTable.py
Webware/trunk/MiscUtils/Funcs.py
Webware/trunk/MiscUtils/Testing/TestDataTable.py
Webware/trunk/UserKit/Role.py
Webware/trunk/WebKit/Cookie.py
Log:
Avoid FutureWarnings when displaying ids of objects in Python 2.3 on certain platforms.
Modified: Webware/trunk/AllTests.py
==============================================================================
--- Webware/trunk/AllTests.py (original)
+++ Webware/trunk/AllTests.py Fri Nov 24 08:36:47 2006
@@ -78,7 +78,7 @@
{ # Edit this file to activate more tests
# Turn on tests that use MySQL?
- 'hasMysql' : False,
+ 'hasMysql' : 0,
# If hasMysql is true, then these are used to connect:
'mysqlTestInfo' : {
Modified: Webware/trunk/MiscUtils/DataTable.py
==============================================================================
--- Webware/trunk/MiscUtils/DataTable.py (original)
+++ Webware/trunk/MiscUtils/DataTable.py Fri Nov 24 08:36:47 2006
@@ -87,11 +87,12 @@
You can control all this behavior through the arguments found in the
initializer and the various readFoo() methods:
- ...delimiter=',', allowComments=1, stripWhite=1
+ ...delimiter=',', allowComments=True, stripWhite=True
For example:
- table = DataTable('foo.tabbed', delimiter='\t', allowComments=0, stripWhite=0)
+ table = DataTable('foo.tabbed', delimiter='\t',
+ allowComments=False, stripWhite=False)
You should access these parameters by their name since additional ones
could appear in the future, thereby changing the order.
@@ -165,9 +166,9 @@
DataTable uses "pickle caching" so that it can read .csv files faster
on subsequent loads. You can disable this across the board with:
from MiscUtils.DataTable import DataTable
- DataTable.usePickleCache = 0
+ DataTable.usePickleCache = False
-Or per instance by passing "usePickleCache=0" to the constructor.
+Or per instance by passing "usePickleCache=False" to the constructor.
See the docstring of PickleCache.py for more information.
@@ -199,10 +200,10 @@
"""
-import os, string, sys
+import os, sys
from CSVParser import CSVParser
from CSVJoiner import joinCSVFields
-from string import join, replace, split, strip
+from Funcs import positive_id
from types import *
try: # backward compatibility for Python < 2.2
@@ -265,20 +266,20 @@
class TableColumn:
- """
- A table column represents a column of the table including name and
- type.
+ """Representation of a table column.
+
+ A table column represents a column of the table including name and type.
+ It does not contain the actual values of the column. These are stored
+ individually in the rows.
- It does not contain the actual values of the column. These are
- stored individually in the rows.
"""
def __init__(self, spec):
# spec is a string such as 'name' or 'name:type'
- fields = split(spec, ':')
+ fields = spec.split(':', 2)
if len(fields) > 2:
- raise DataTableError, 'Invalid column spec %s' % repr(spec)
+ raise DataTableError, 'Invalid column spec %r' % spec
self._name = fields[0]
if len(fields) == 1:
@@ -293,18 +294,23 @@
return self._type
def setType(self, type):
- """ Sets the type (by a string containing the name) of the heading. Usually invoked by DataTable to set the default type for columns whose types were not specified. """
+ """Set the type (by a string containing the name) of the heading.
+
+ Usually invoked by DataTable to set the default type for columns
+ whose types were not specified.
+
+ """
if type == None:
self._type = None
else:
try:
self._type = _types[type.lower()]
except:
- raise DataTableError, 'Unknown type %s. types=%r' % (repr(type), _types.keys())
+ raise DataTableError, 'Unknown type %r. types=%r' % (type, _types.keys())
def __repr__(self):
- return '<%s %s with %s at %x>' % (
- self.__class__.__name__, repr(self._name), repr(self._type), id(self))
+ return '<%s %r with %r at %x>' % (
+ self.__class__.__name__, self._name, self._type, positive_id(self))
def __str__(self):
return self._name
@@ -313,8 +319,16 @@
## Utilities ##
def valueForRawValue(self, rawValue):
- """ The rawValue is typically a string or value already of the appropriate type. TableRecord invokes this method to ensure that values (especially strings that come from files) are the correct types (e.g., ints are ints and floats are floats). """
- # @@ 2000-07-23 ce: an if-else ladder? perhaps these should be dispatched messages or a class hier
+ """Set correct type for raw value.
+
+ The rawValue is typically a string or value already of the appropriate
+ type. TableRecord invokes this method to ensure that values (especially
+ strings that come from files) are the correct types (e.g., ints are
+ ints and floats are floats).
+
+ """
+ # @@ 2000-07-23 ce: an if-else ladder?
+ # perhaps these should be dispatched messages or a class hier
if self._type is StringType:
value = str(rawValue)
elif self._type is IntType:
@@ -343,8 +357,10 @@
class DataTable:
- """
+ """Representation of a data table.
+
See the doc string for this module.
+
"""
usePickleCache = True
@@ -352,13 +368,15 @@
## Init ##
- def __init__(self, filenameOrHeadings=None, delimiter=',', allowComments=1, stripWhite=1, defaultType=None, usePickleCache=None):
+ def __init__(self, filenameOrHeadings=None, delimiter=',',
+ allowComments=True, stripWhite=True,
+ defaultType=None, usePickleCache=None):
if usePickleCache is None:
- self.usePickleCache = self.usePickleCache # grab the class-level attr
+ self.usePickleCache = self.usePickleCache # grab class-level attr
else:
self.usePickleCache = usePickleCache
if defaultType and not _types.has_key(defaultType):
- raise DataTableError, 'Unknown type for default type: %s' % repr(defaultType)
+ raise DataTableError, 'Unknown type for default type: %r' % defaultType
self._defaultType = defaultType
self._filename = None
self._headings = []
@@ -372,7 +390,8 @@
## File I/O ##
- def readFileNamed(self, filename, delimiter=',', allowComments=1, stripWhite=1, worksheet=1, row=1, column=1):
+ def readFileNamed(self, filename, delimiter=',',
+ allowComments=True, stripWhite=True, worksheet=1, row=1, column=1):
self._filename = filename
data = None
if self.usePickleCache:
@@ -391,17 +410,23 @@
self.__dict__ = data.__dict__
return self
- def readFile(self, file, delimiter=',', allowComments=1, stripWhite=1):
- return self.readLines(file.readlines(), delimiter, allowComments, stripWhite)
-
- def readString(self, string, delimiter=',', allowComments=1, stripWhite=1):
- return self.readLines(split(string, '\n'), delimiter, allowComments, stripWhite)
+ def readFile(self, file, delimiter=',',
+ allowComments=True, stripWhite=True):
+ return self.readLines(file.readlines(), delimiter,
+ allowComments, stripWhite)
+
+ def readString(self, string, delimiter=',',
+ allowComments=True, stripWhite=True):
+ return self.readLines(string.split('\n'), delimiter,
+ allowComments, stripWhite)
- def readLines(self, lines, delimiter=',', allowComments=1, stripWhite=1):
+ def readLines(self, lines, delimiter=',',
+ allowComments=True, stripWhite=True):
if self._defaultType is None:
self._defaultType = 'string'
haveReadHeadings = False
- parse = CSVParser(fieldSep=delimiter, allowComments=allowComments, stripWhitespace=stripWhite).parse
+ parse = CSVParser(fieldSep=delimiter, allowComments=allowComments,
+ stripWhitespace=stripWhite).parse
for line in lines:
# process a row, either headings or data
values = parse(line)
@@ -449,24 +474,24 @@
haveReadHeadings = False
rowNum = row
numBlankRows = 0
- valuesBuffer = {} # keyed by row number
+ valuesBuffer = {} # keyed by row number
while 1:
try:
# grab a single row
values = valuesBuffer[rowNum]
except KeyError:
# woops. read buffer is out of fresh rows
- valuesRows = sh.Range('A%i:%s%i' % (rowNum, maxCol, rowNum+numRowsToReadPerCall-1)).Value
+ valuesRows = sh.Range('A%i:%s%i' % (rowNum, maxCol,
+ rowNum+numRowsToReadPerCall-1)).Value
valuesBuffer.clear()
j = rowNum
for valuesRow in valuesRows:
valuesBuffer[j] = valuesRow
j += 1
values = valuesBuffer[rowNum]
-
# non-"buffered" version, one row at a time:
- # values = sh.Range('A%i:%s%i' % (rowNum, maxCol, rowNum)).Value[0]
-
+ # values = sh.Range('A%i:%s%i' % (rowNum, maxCol,
+ # rowNum)).Value[0]
values = [strip(v) for v in values]
nonEmpty = [v for v in values if v]
if nonEmpty:
@@ -496,13 +521,15 @@
file.close()
def writeFile(self, file):
- """
+ """Write the table out as a file.
+
@@ 2000-07-20 ce: This doesn't write the column types (like :int) back out.
- @@ 2000-07-21 ce: It's notable that a blank numeric value gets read as zero and written out that way. Also, values None are written as blanks.
- """
+ @@ 2000-07-21 ce: It's notable that a blank numeric value gets read as zero
+ and written out that way. Also, values None are written as blanks.
+ """
# write headings
- file.write(join(map(lambda h: str(h), self._headings), ','))
+ file.write(','.join(map(str, self._headings)))
file.write('\n')
def ValueWritingMapper(item):
@@ -540,7 +567,8 @@
return self._headings
def setHeadings(self, headings):
- """ Headings can be a list of strings (like ['name', 'age:int']) or a list of TableColumns or None. """
+ """Headings can be a list of strings (like ['name', 'age:int'])
+ or a list of TableColumns or None. """
if not headings:
self._headings = []
elif isinstance(headings[0], StringTypes):
@@ -562,8 +590,12 @@
return self._rows[index]
def append(self, object):
- """ If object is not a TableRecord, then one is created, passing the object to initialize the TableRecord. Therefore, object can be a TableRecord, list, dictionary or object. See TableRecord for details. """
+ """If object is not a TableRecord, then one is created,
+ passing the object to initialize the TableRecord.
+ Therefore, object can be a TableRecord, list, dictionary or object.
+ See TableRecord for details.
+ """
if not isinstance(object, TableRecord):
object = TableRecord(self, object)
self._rows.append(object)
@@ -591,26 +623,30 @@
def __repr__(self):
# Initial info
s = ['DataTable: %s\n%d rows\n' % (self._filename, len(self._rows))]
-
# Headings
s.append(' ')
- s.append(join(map(lambda h: str(h), self._headings), ', '))
+ s.append(', '.join(map(str, self._headings)))
s.append('\n')
-
# Records
i = 0
for row in self._rows:
s.append('%3d. ' % i)
- s.append(join(map(lambda r: str(r), row), ', '))
+ s.append(', '.join(map(str, row)))
s.append('\n')
- i = i + 1
- return join(s, '')
+ i += 1
+ return ''.join(s)
## As a dictionary ##
def dictKeyedBy(self, key):
- """ Returns a dictionary containing the contents of the table indexed by the particular key. This is useful for tables that have a column which represents a unique key (such as a name, serial number, etc.). """
+ """Return a dictionary containing the contents of the table.
+
+ The content is indexed by the particular key. This is useful
+ for tables that have a column which represents a unique key
+ (such as a name, serial number, etc.).
+
+ """
dict = {}
for row in self:
dict[row[key]] = row
@@ -623,16 +659,23 @@
return self._filename
def nameToIndexMap(self):
- """ Table rows keep a reference to this map in order to speed up index-by-names (as in row['name']). """
+ """Speed-up index.
+
+ Table rows keep a reference to this map in order to speed up
+ index-by-names (as in row['name']).
+
+ """
return self._nameToIndexMap
## Self utilities ##
def createNameToIndexMap(self):
- """
+ """Create speed-up index.
+
Invoked by self to create the nameToIndexMap after the table's
headings have been read/initialized.
+
"""
map = {}
for i in range(len(self._headings)):
@@ -640,7 +683,8 @@
self._nameToIndexMap = map
-# @@ 2000-07-20 ce: perhaps for each type we could specify a function to convert from string values to the values of the type
+# @@ 2000-07-20 ce: perhaps for each type we could specify a function
+# to convert from string values to the values of the type.
BlankValues = {
StringType: '',
@@ -652,20 +696,25 @@
class TableRecord:
+ """Representation of a table record."""
## Init ##
def __init__(self, table, values=None):
- """
- Dispatches control to one of the other init methods based on the type of values. Values can be one of three things:
+ """Initialize table record.
+
+ Dispatches control to one of the other init methods based on the type
+ of values. Values can be one of three things:
1. A TableRecord
2. A list
3. A dictionary
4. Any object responding to hasValueForKey() and valueForKey().
+
"""
self._headings = table.headings()
self._nameToIndexMap = table.nameToIndexMap()
- # @@ 2000-07-20 ce: Take out the headings arg to the init method since we have an attribute for that
+ # @@ 2000-07-20 ce: Take out the headings arg to the init method
+ # since we have an attribute for that
if values is not None:
valuesType = type(values)
@@ -681,7 +730,9 @@
def initFromSequence(self, values):
if len(self._headings) < len(values):
- raise DataTableError, ('There are more values than headings.\nheadings(%d, %s)\nvalues(%d, %s)' % (len(self._headings), self._headings, len(values), values))
+ raise DataTableError, ('There are more values than headings.\n'
+ 'headings(%d, %s)\nvalues(%d, %s)' % (len(self._headings),
+ self._headings, len(values), values))
self._values = []
numHeadings = len(self._headings)
numValues = len(values)
@@ -703,19 +754,22 @@
self._values.append(BlankValues[heading.type()])
def initFromObject(self, object):
- """
+ """Initialize from object.
+
The object is expected to response to hasValueForKey(name) and
valueForKey(name) for each of the headings in the table. It's
alright if the object returns False for hasValueForKey(). In that
case, a "blank" value is assumed (such as zero or an empty
string). If hasValueForKey() returns True, then valueForKey() must
return a value.
+
"""
self._values = []
for heading in self._headings:
name = heading.name()
if object.hasValueForKey(name):
- self._values.append(heading.valueForRawValue(object.valueForKey(name)))
+ self._values.append(heading.valueForRawValue(
+ object.valueForKey(name)))
else:
self._values.append(BlankValues[heading.type()])
@@ -731,7 +785,8 @@
try:
return self._values[key]
except TypeError:
- raise TypeError, 'key=%r, key type=%r, self._values=%r' % (key, type(key), self._values)
+ raise TypeError, 'key=%r, key type=%r, self._values=%r' % (
+ key, type(key), self._values)
def __setitem__(self, key, value):
if type(key) is StringType:
@@ -767,15 +822,16 @@
## Additional access ##
def asList(self):
- """
- Returns a sequence whose values are the same at the record's
- and in the order defined by the table.
+ """Return a sequence whose values are the same as the record's.
+
+ The order of the sequence is the one defined by the table.
+
"""
# It just so happens that our implementation already has this
return self._values[:]
def asDict(self):
- """ Returns a dictionary whose key-values match the table record. """
+ """Return a dictionary whose key-values match the table record."""
dict = {}
nameToIndexMap = self._nameToIndexMap
for key in nameToIndexMap.keys():
Modified: Webware/trunk/MiscUtils/Funcs.py
==============================================================================
--- Webware/trunk/MiscUtils/Funcs.py (original)
+++ Webware/trunk/MiscUtils/Funcs.py Fri Nov 24 08:36:47 2006
@@ -5,6 +5,7 @@
"""
import md5, os, random, time, sys, tempfile
+from struct import calcsize
try: # backward compatibility for Python < 2.3
True, False
@@ -31,7 +32,7 @@
else:
i = len(number)
while 1:
- i = i-3
+ i -= 3
if i <= 0 or number[i-1] == '-':
break
number[i:i] = [',']
@@ -64,12 +65,12 @@
t = s[width:]
s = s[:width]
lines[i] = s
- i = i + 1
+ i += 1
lines.insert(i, None)
s = hanging + t
else:
lines[i] = s
- i = i + 1
+ i += 1
return '\n'.join(lines)
@@ -138,6 +139,7 @@
path = mktemp(suffix, dir)
return os.open(path, os.O_RDWR|os.O_CREAT|os.O_EXCL, 0600), path
+
def wordWrap(s, width=78):
"""Return a version of the string word wrapped to the given width.
@@ -251,6 +253,37 @@
return _localIP
+# Addresses can "look negative" on some boxes, some of the time. If you
+# feed a "negative address" to an %x format, Python 2.3 displays it as
+# unsigned, but produces a FutureWarning, because Python 2.4 will display
+# it as signed. So when you want to prodce an address, use positive_id()
+# to obtain it. _address_mask is 2**(number_of_bits_in_a_native_pointer).
+# Adding this to a negative address gives a positive int with the same
+# hex representation as the significant bits in the original.
+# This idea and code were taken from ZODB (http://svn.zope.org).
+
+_address_mask = 256L ** calcsize('P')
+
+def positive_id(obj):
+ """Return id(obj) as a non-negative integer."""
+ result = id(obj)
+ if result < 0:
+ result += _address_mask
+ assert result > 0
+ return result
+
+
+def _descExc(reprOfWhat, e):
+ """Return a description of an exception.
+
+ This is a private function for use by safeDescription().
+
+ """
+ try:
+ return '(exception from repr(%s): %s: %s)' % (reprOfWhat, e.__class__, e)
+ except:
+ return '(exception from repr(%s))' % reprOfWhat
+
def safeDescription(x, what='what'):
"""Return the repr() of x and its class (or type) for help in debugging.
@@ -284,16 +317,6 @@
cRepr = _descExc('type(x)', e)
return '%s=%s type=%s' % (what, xRepr, cRepr)
-def _descExc(reprOfWhat, e):
- """Return a description of an exception.
-
- This is a private function for use by safeDescription().
-
- """
- try:
- return '(exception from repr(%s): %s: %s)' % (reprOfWhat, e.__class__, e)
- except:
- return '(exception from repr(%s))' % reprOfWhat
def timestamp(numSecs=None):
"""Return a dictionary whose keys give different versions of the timestamp.
Modified: Webware/trunk/MiscUtils/Testing/TestDataTable.py
==============================================================================
--- Webware/trunk/MiscUtils/Testing/TestDataTable.py (original)
+++ Webware/trunk/MiscUtils/Testing/TestDataTable.py Fri Nov 24 08:36:47 2006
@@ -1,5 +1,4 @@
import unittest
-import string
import os
from glob import glob
from StringIO import StringIO
@@ -24,7 +23,7 @@
def _testSource(self, name, src, headings, data):
# print name
dt = DataTable()
- lines = split(src, '\n')
+ lines = src.split('\n')
dt.readLines(lines)
assert [col.name() for col in dt.headings()] == headings
i = 0
@@ -33,7 +32,7 @@
self.assertEquals(dt[i].asList(), match,
'For element %d, I expected "%s" but got "%s"'
% (i, match, dt[i].asList()))
- i = i + 1
+ i += 1
def test01_withPickle(self):
DataTable.usePickleCache = 1
Modified: Webware/trunk/UserKit/Role.py
==============================================================================
--- Webware/trunk/UserKit/Role.py (original)
+++ Webware/trunk/UserKit/Role.py Fri Nov 24 08:36:47 2006
@@ -1,3 +1,6 @@
+from MiscUtils.Funcs import positive_id
+
+
class Role:
"""
Roles are used in conjuction with RoleUser to provide role-based security.
@@ -42,12 +45,18 @@
return str(self._name)
def __repr__(self):
- return '<%s %r instance at %X>' % (self.__class__, self._name, id(self))
+ return '<%s %r instance at %x>' % (
+ self.__class__, self._name, positive_id(self))
## The big question ##
def playsRole(self, role):
- """ Returns true if the receiving role plays the role passed in. For Role, this is simply a test of equality. Subclasses may override this method to provide richer semantics (such as hierarchical roles). """
+ """Return true if the receiving role plays the role passed in.
+
+ For Role, this is simply a test of equality. Subclasses may override
+ this method to provide richer semantics (such as hierarchical roles).
+
+ """
assert isinstance(role, Role)
- return self==role
+ return self == role
Modified: Webware/trunk/WebKit/Cookie.py
==============================================================================
--- Webware/trunk/WebKit/Cookie.py (original)
+++ Webware/trunk/WebKit/Cookie.py Fri Nov 24 08:36:47 2006
@@ -1,4 +1,5 @@
from Common import *
+from MiscUtils.Funcs import positive_id
# If this is Python 2.2 or greater, import the standard Cookie module
# as CookieEngine. Otherwise, import WebUtils.Cookie as CookieEngine.
@@ -90,7 +91,7 @@
def __repr__(self):
return '%s(id=0x%x, name=%r, domain=%r,' \
' path=%r, value=%r, expires=%r, maxAge=%r)' % (
- self.__class__.__name__, id(self), self.name(), self.domain(),
+ self.__class__.__name__, positiveid(self), self.name(), self.domain(),
self.path(), self.value(), self.expires(), self.maxAge())
@@ -176,5 +177,5 @@
"""
items = self._cookies.items()
- assert(len(items)==1)
+ assert(len(items) == 1)
return items[0][1].OutputString()
|