[Zope3-checkins] CVS: Zope3/src/zodbcode/tests - __init__.py:1.1
_pmtest.py:1.1 atestmodule.py:1.1 test_class.py:1.1
test_module.py:1.1 test_patch.py:1.1
tobeimportedbyatestmodule.py:1.1
Fred L. Drake, Jr.
fred at zope.com
Fri Feb 20 17:02:25 EST 2004
Update of /cvs-repository/Zope3/src/zodbcode/tests
In directory cvs.zope.org:/tmp/cvs-serv14949/src/zodbcode/tests
Added Files:
__init__.py _pmtest.py atestmodule.py test_class.py
test_module.py test_patch.py tobeimportedbyatestmodule.py
Log Message:
convert the zodb.code package to be zodbcode
=== Added File Zope3/src/zodbcode/tests/__init__.py ===
#
# This file is necessary to make this directory a package.
=== Added File Zope3/src/zodbcode/tests/_pmtest.py ===
##############################################################################
#
# Copyright (c) 2003 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""A simple module"""
# XXX why aren't modules pickleable?
# import os
# from xml import sax
a = 1
b = 2
c = 3
def f(x):
return a * x ** 2 + b * x + c
=== Added File Zope3/src/zodbcode/tests/atestmodule.py ===
##############################################################################
#
# Copyright (c) 2003 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""A module used to test persistent module patching."""
from ZODB.utils import *
def aFunc():
def nestedFunc():
return aFunc
return 1
class Foo(object):
def meth(self):
return 0
class Nested(object):
def bar(self):
return 1
# put aFunc inside a function to be sure it is found
foo = (aFunc,)
class Bar:
def bar(self, x):
return 2 * x
static = staticmethod(aFunc)
alias = aFunc
classbar = classmethod(bar)
class Sub(Bar):
pass
def anotherFunc():
class NotFound:
pass
# import a module that won't be imported by something else:
from zodbcode.tests import tobeimportedbyatestmodule
=== Added File Zope3/src/zodbcode/tests/test_class.py ===
##############################################################################
#
# Copyright (c) 2002 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
import unittest
from zodbcode.tests.test_module import TestBase
from transaction import get_transaction
from persistent.cPersistence import CHANGED, UPTODATE
class TestClass(TestBase):
# TODO
# test classes with getstate and setstate
# make sure class invalidation works correctly
class_with_init = """class Foo:
def __init__(self, arg):
self.var = arg""" "\n"
def _load_path(self, path):
# Load an object from a new connection given a database path.
root = self.db.open().root()
obj = root
for part in path.split("."):
try:
obj = obj[part]
except TypeError:
obj = getattr(obj, part)
return obj
def _load_name(self, name):
# Load a class from a new connection given a dotted name
i = name.rfind(".")
module = name[:i]
klass = name[i+1:]
# The following depends entirely on the internals of the
# implementation.
return self._load_path("registry._mgrs.%s._module.%s"
% (module, klass))
def testClassWithInit(self):
self.registry.newModule("testclass", self.class_with_init)
get_transaction().commit()
import testclass
x = testclass.Foo(12)
self.assertEqual(x.var, 12)
Foo2 = self._load_name("testclass.Foo")
y = Foo2(12)
self.assertEqual(y.var, 12)
class_and_instance = """class Foo:
def __init__(self, arg):
self.var = arg
# The class must have a getinitargs because the instance
# will be pickled during module conversion.
def __getinitargs__(self):
return self.var,
y = Foo(11)
x = Foo(12)""" "\n"
def testClassAndInstance(self):
self.registry.newModule("testclass", self.class_and_instance)
get_transaction().commit()
import testclass
self.assertEqual(testclass.x.var, 12)
Foo2 = self._load_name("testclass.Foo")
self.assertEqual(Foo2(12).var, 12)
x = self._load_name("testclass.x")
self.assertEqual(x.var, 12)
y = self._load_name("testclass.y")
self.assertEqual(y.var, 11)
self.assert_(not hasattr(x, "_p_oid"))
self.assert_(not hasattr(y, "_p_oid"))
x._p_oid = 1234
y._p_oid = 4321
class_interface = """class Foo:
__implements__ = 1""" + "\n"
def testClassInterface(self):
# this doesn't do a proper zope interface, but we're really
# only concerned about handling of the __implements__ attribute.
self.registry.newModule("testclass", self.class_interface)
get_transaction().commit()
import testclass
obj = testclass.Foo()
self.assertEqual(obj.__implements__, 1)
cross_module_import = "from testclass import Foo"
def testCrossModuleImport(self):
self.registry.newModule("testclass", self.class_with_init)
get_transaction().commit()
self.registry.newModule("another", self.cross_module_import)
get_transaction().commit()
update_in_place1 = """class Foo:
def meth(self, arg):
return arg * 3""" "\n"
update_in_place2 = """class Foo:
def meth(self, arg):
return arg + 3""" "\n"
def testUpdateInPlace(self):
self.registry.newModule("testclass", self.update_in_place1)
get_transaction().commit()
import testclass
inst = testclass.Foo()
self.assertEqual(inst.meth(4), 12)
Foo2 = self._load_name("testclass.Foo")
inst2 = Foo2()
self.assertEqual(inst2.meth(4), 12)
self.registry.updateModule("testclass", self.update_in_place2)
get_transaction().commit()
self.assertEqual(inst.meth(4), 7)
# The old instance's connection hasn't processed the
# invalidation yet.
self.assertEqual(inst2.meth(4), 12)
self.assertEqual(Foo2().meth(4), 12)
inst2.__class__._p_jar.sync()
self.assertEqual(inst2.meth(4), 7)
self.assertEqual(Foo2().meth(4), 7)
parent1 = """class Foo(object):
def meth(self, arg):
return arg * 2""" "\n"
parent2 = """class Foo(object):
def meth(self, arg):
return arg // 2""" "\n"
child = """import parent
class Bar(parent.Foo):
def meth(self, arg):
return super(Bar, self).meth(arg) + 5""" "\n"
def testInheritanceAcrossModules(self):
self.registry.newModule("parent", self.parent1)
self.registry.newModule("child", self.child)
get_transaction().commit()
import child
self.assertEqual(child.Bar().meth(3), 3*2+5)
self.registry.updateModule("parent", self.parent2)
get_transaction().commit()
self.assertEqual(child.Bar().meth(3), 3//2+5)
Bar = self._load_name("child.Bar")
self.assertEqual(Bar().meth(3), 3//2+5)
persist = """from persistence import Persistent
class Foo(Persistent):
pass""" "\n"
def testPersistentSubclass(self):
self.registry.newModule("persist", self.persist)
get_transaction().commit()
import persist
# Verify that the instances are persistent and that the
# _p_ namespace is separate.
obj = persist.Foo()
foo_oid = persist.Foo._p_oid
self.assertEqual(obj._p_oid, None)
obj._p_oid = 1
self.assertEqual(obj._p_oid, 1)
self.assertEqual(persist.Foo._p_oid, foo_oid)
save_persist = """from persist import Foo
x = Foo()
"""
def testSavePersistentSubclass(self):
self.registry.newModule("persist", self.persist)
get_transaction().commit()
import persist
self.registry.newModule("save_persist", self.save_persist)
get_transaction().commit()
import save_persist
def XXXtestUpdateClassAttribute(self):
self.registry.newModule("parent", self.parent1)
get_transaction().commit()
import parent
parent.Foo.attr = 2
self.assertEqual(parent.Foo._p_state, CHANGED)
get_transaction().commit()
self.assertEqual(parent.Foo._p_state, UPTODATE)
Foo = self._load_name("parent.Foo")
self.assertEqual(Foo.attr, 2)
def test_suite():
return unittest.makeSuite(TestClass)
=== Added File Zope3/src/zodbcode/tests/test_module.py ===
##############################################################################
#
# Copyright (c) 2002 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
import os
import pickle
import unittest
from persistence.dict import PersistentDict
from persistent import UPTODATE
from transaction import get_transaction
import ZODB.tests.util
from zodbcode import tests # import this package, to get at __file__ reliably
from zodbcode.module \
import ManagedRegistry, PersistentModuleImporter, PersistentPackage
# snippets of source code used by testModules
foo_src = """\
import string
x = 1
def f(y):
return x + y
"""
quux_src = """\
from foo import x
def f(y):
return x + y
"""
side_effect_src = """\
x = 1
def inc():
global x
x += 1
return x
"""
builtin_src = """\
x = 1, 2, 3
def f():
return len(x)
"""
nested_src = """\
def f(x):
def g(y):
def z(z):
return x + y + z
return x + y
return g
"""
nested_err_src = nested_src + """\
g = f(3)
"""
closure_src = """\
def f(x):
def g(y):
return x + y
return g
inc = f(1)
"""
class TestPersistentModuleImporter(PersistentModuleImporter):
def __init__(self, registry):
self._registry = registry
self._registry._p_activate()
def __import__(self, name, globals={}, locals={}, fromlist=[]):
mod = self._import(self._registry, name, self._get_parent(globals),
fromlist)
if mod is not None:
return mod
return self._saved_import(name, globals, locals, fromlist)
class TestBase(unittest.TestCase):
def setUp(self):
self.db = ZODB.tests.util.DB()
self.root = self.db.open().root()
self.registry = ManagedRegistry()
self.importer = TestPersistentModuleImporter(self.registry)
self.importer.install()
self.root["registry"] = self.registry
get_transaction().commit()
_dir, _file = os.path.split(tests.__file__)
self._pmtest = os.path.join(_dir, "_pmtest.py")
def tearDown(self):
self.importer.uninstall()
# just in case
get_transaction().abort()
self.db.close()
def sameModules(self, registry):
m1 = self.registry.modules()
m1.sort()
m2 = registry.modules()
m2.sort()
self.assertEqual(m1, m2)
def useNewConnection(self):
# load modules using a separate connection to test that
# modules can be recreated from the database
cn = self.db.open()
reg = cn.root()["registry"]
self.sameModules(reg)
for name in reg.modules():
mod = reg.findModule(name)
mod._p_activate()
self.assertEqual(mod._p_state, UPTODATE)
for obj in mod.__dict__.values():
if hasattr(obj, "_p_activate"):
obj._p_activate()
# XXX somehow objects are getting registered here, but not
# modified. need to figure out what is going wrong, but for
# now just abort the transaction.
##assert not cn._registered
get_transaction().abort()
cn.close()
class TestModule(TestBase):
def testModule(self):
self.registry.newModule("pmtest", open(self._pmtest).read())
get_transaction().commit()
self.assert_(self.registry.findModule("pmtest"))
import pmtest
pmtest._p_deactivate()
self.assertEqual(pmtest.a, 1)
pmtest.f(4)
self.useNewConnection()
def testUpdateFunction(self):
self.registry.newModule("pmtest", "def f(x): return x")
get_transaction().commit()
import pmtest
self.assertEqual(pmtest.f(3), 3)
copy = pmtest.f
self.registry.updateModule("pmtest", "def f(x): return x + 1")
get_transaction().commit()
pmtest._p_deactivate()
self.assertEqual(pmtest.f(3), 4)
self.assertEqual(copy(3), 4)
self.useNewConnection()
def testUpdateClass(self):
self.registry.newModule("pmtest", src)
get_transaction().commit()
import pmtest
inst = pmtest.Foo()
v0 = inst.x
v1 = inst.m()
v2 = inst.n()
self.assertEqual(v1 - 1, v2)
self.assertEqual(v0 + 1, v1)
self.registry.updateModule("pmtest", src2)
get_transaction().commit()
self.assertRaises(AttributeError, getattr, inst, "n")
self.useNewConnection()
def testModules(self):
self.registry.newModule("foo", foo_src)
# quux has a copy of foo.x
self.registry.newModule("quux", quux_src)
# bar has a reference to foo
self.registry.newModule("bar", "import foo")
# baz has reference to f and copy of x,
# remember the the global x in f is looked up in foo
self.registry.newModule("baz", "from foo import *")
import foo, bar, baz, quux
self.assert_(foo._p_oid is None)
get_transaction().commit()
self.assert_(foo._p_oid)
self.assert_(bar._p_oid)
self.assert_(baz._p_oid)
self.assert_(quux._p_oid)
self.assertEqual(foo.f(4), 5)
self.assertEqual(bar.foo.f(4), 5)
self.assertEqual(baz.f(4), 5)
self.assertEqual(quux.f(4), 5)
self.assert_(foo.f is bar.foo.f)
self.assert_(foo.f is baz.f)
foo.x = 42
self.assertEqual(quux.f(4), 5)
get_transaction().commit()
self.assertEqual(quux.f(4), 5)
foo._p_deactivate()
# foo is deactivated, which means its dict is empty when f()
# is activated, how do we guarantee that foo is also
# activated?
self.assertEqual(baz.f(4), 46)
self.assertEqual(bar.foo.f(4), 46)
self.assertEqual(foo.f(4), 46)
self.useNewConnection()
def testFunctionAttrs(self):
self.registry.newModule("foo", foo_src)
import foo
A = foo.f.attr = "attr"
self.assertEqual(foo.f.attr, A)
get_transaction().commit()
self.assertEqual(foo.f.attr, A)
foo.f._p_deactivate()
self.assertEqual(foo.f.attr, A)
del foo.f.attr
self.assertRaises(AttributeError, getattr, foo.f, "attr")
foo.f.func_code
self.useNewConnection()
def testFunctionSideEffects(self):
self.registry.newModule("effect", side_effect_src)
import effect
effect.inc()
get_transaction().commit()
effect.inc()
self.assert_(effect._p_changed)
self.useNewConnection()
def testBuiltins(self):
self.registry.newModule("test", builtin_src)
get_transaction().commit()
import test
self.assertEqual(test.f(), len(test.x))
test._p_deactivate()
self.assertEqual(test.f(), len(test.x))
self.useNewConnection()
def testNested(self):
self.assertRaises(TypeError,
self.registry.newModule, "nested", nested_err_src)
self.registry.newModule("nested", nested_src)
get_transaction().commit()
import nested
g = nested.f(3)
self.assertEqual(g(4), 7)
def testLambda(self):
# test a lambda that contains another lambda as a default
self.registry.newModule("test",
"f = lambda x, y = lambda: 1: x + y()")
get_transaction().commit()
import test
self.assertEqual(test.f(1), 2)
self.useNewConnection()
def testClass(self):
self.registry.newModule("foo", src)
get_transaction().commit()
import foo
obj = foo.Foo()
obj.m()
self.root["m"] = obj
get_transaction().commit()
foo._p_deactivate()
o = foo.Foo()
i = o.m()
j = o.m()
self.assertEqual(i + 1, j)
self.useNewConnection()
def testPackage(self):
self.registry.newModule("A.B.C", "def f(x): return x")
get_transaction().commit()
import A.B.C
self.assert_(isinstance(A, PersistentPackage))
self.assertEqual(A.B.C.f("A"), "A")
self.assertRaises(ValueError, self.registry.newModule,
"A.B", "def f(x): return x + 1")
self.registry.newModule("A.B.D", "def f(x): return x")
get_transaction().commit()
from A.B import D
self.assert_(hasattr(A.B.D, "f"))
self.useNewConnection()
def testPackageInit(self):
self.registry.newModule("A.B.C", "def f(x): return x")
get_transaction().commit()
import A.B.C
self.registry.newModule("A.B.__init__", "x = 2")
get_transaction().commit()
import A.B
self.assert_(hasattr(A.B, "C"))
self.assertEqual(A.B.x, 2)
self.assertRaises(ValueError, self.registry.newModule,
"A.__init__.D", "x = 2")
self.useNewConnection()
def testPackageRelativeImport(self):
self.registry.newModule("A.B.C", "def f(x): return x")
get_transaction().commit()
self.registry.newModule("A.Q", "from B.C import f")
get_transaction().commit()
import A.Q
self.assertEqual(A.B.C.f, A.Q.f)
self.registry.updateModule("A.Q", "import B.C")
get_transaction().commit()
self.assertEqual(A.B.C.f, A.Q.B.C.f)
try:
import A.B.Q
except ImportError:
pass
self.useNewConnection()
def testImportAll(self):
self.registry.newModule("A.B.C",
"""__all__ = ["a", "b"]; a, b, c = 1, 2, 3""")
get_transaction().commit()
d = {}
exec "from A.B.C import *" in d
self.assertEqual(d['a'], 1)
self.assertEqual(d['b'], 2)
self.assertRaises(KeyError, d.__getitem__, "c")
self.registry.newModule("A.B.D", "from C import *")
get_transaction().commit()
import A.B.D
self.assert_(hasattr(A.B.D, "a"))
self.assert_(hasattr(A.B.D, "b"))
self.assert_(not hasattr(A.B.D, "c"))
self.registry.newModule("A.__init__", """__all__ = ["B", "F"]""")
get_transaction().commit()
self.registry.newModule("A.F", "spam = 1")
get_transaction().commit()
import A
self.assertEqual(A.F.spam, 1)
self.useNewConnection()
class TestModuleReload(unittest.TestCase):
"""Test reloading of modules"""
def setUp(self):
self.db = ZODB.tests.util.DB()
self.open()
_dir, _file = os.path.split(tests.__file__)
self._pmtest = os.path.join(_dir, "_pmtest.py")
def tearDown(self):
get_transaction().abort()
self.db.close()
def open(self):
# open a new db and importer from the storage
self.root = self.db.open().root()
self.registry = self.root.get("registry")
if self.registry is None:
self.root["registry"] = self.registry = ManagedRegistry()
self.importer = TestPersistentModuleImporter(self.registry)
self.importer.install()
get_transaction().commit()
def close(self):
self.importer.uninstall()
self.root._p_jar.close()
def testModuleReload(self):
self.registry.newModule("pmtest", open(self._pmtest).read())
get_transaction().commit()
import pmtest
pmtest._p_deactivate()
self.assertEqual(pmtest.a, 1)
pmtest.f(4)
self.close()
pmtest._p_deactivate()
self.importer.uninstall()
self.open()
del pmtest
import pmtest
def testClassReload(self):
self.registry.newModule("foo", src)
get_transaction().commit()
import foo
obj = foo.Foo()
obj.m()
self.root["d"] = d = PersistentDict()
d["m"] = obj
get_transaction().commit()
self.close()
foo._p_deactivate()
self.importer.uninstall()
self.open()
del foo
import foo
def testModulePicklability(self):
from zodbcode.tests import test_module
s = pickle.dumps(test_module)
m = pickle.loads(s)
self.assertEqual(m, test_module)
def test_suite():
s = unittest.TestSuite()
for klass in TestModule, TestModuleReload:
s.addTest(unittest.makeSuite(klass))
return s
src = """\
class Foo(object):
def __init__(self):
self.x = id(self)
def m(self):
self.x += 1
return self.x
def n(self):
self.x -= 1
return self.x
"""
src2 = """\
class Foo(object):
def __init__(self):
self.x = 0
def m(self):
self.x += 10
return self.x
"""
=== Added File Zope3/src/zodbcode/tests/test_patch.py ===
##############################################################################
#
# Copyright (c) 2003 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
from zodbcode.patch import NameFinder, convert
from zodbcode.tests import atestmodule
import unittest
from types import FunctionType as function
class TestNameFinder(unittest.TestCase):
def testNameFinder(self):
nf = NameFinder(atestmodule)
names = nf.names()
for name in ("Foo", "Bar", "aFunc", "anotherFunc",
"Foo.meth", "Foo.Nested", "Bar.bar",
"Foo.Nested.bar"):
self.assert_(name in names)
for name in ("aFunc.nestedFunc", "anotherFunc.NotFound"):
self.assert_(name not in names)
class TestPatch(unittest.TestCase):
def setUp(self):
self.olddict = atestmodule.__dict__.copy()
def tearDown(self):
atestmodule.__dict__.clear()
atestmodule.__dict__.update(self.olddict)
def testPatch(self):
# verify obvious facts of object identity
self.assert_(atestmodule.Bar is atestmodule.Sub.__bases__[0])
self.assert_(atestmodule.aFunc is atestmodule.foo[0])
moddict = self.olddict
convert(atestmodule, {})
newdict = atestmodule.__dict__
L1 = moddict.keys()
L2 = newdict.keys()
L1.sort()
L2.sort()
self.assertEqual(L1, L2)
self.assertEqual(atestmodule.__dict__, atestmodule.aFunc.func_globals)
# make sure object identity is maintained by patch
Bar = newdict["Bar"]
Bar_as_base = newdict["Sub"].__bases__[0]
self.assert_(Bar is Bar_as_base)
self.assert_(newdict["aFunc"] is newdict["foo"][0])
# The patch should not touch modules, functions, etc. that
# are imported from other modules.
import ZODB.utils
for name in dir(ZODB.utils):
obj = getattr(ZODB.utils, name)
if isinstance(obj, type) or isinstance(obj, function):
self.assert_(obj is newdict[name])
def test_suite():
s = unittest.TestSuite()
for c in TestNameFinder, TestPatch:
s.addTest(unittest.makeSuite(c))
return s
=== Added File Zope3/src/zodbcode/tests/tobeimportedbyatestmodule.py ===
##############################################################################
#
# Copyright (c) 2004 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""This module exists soley to e imported by atestmodule
$Id: tobeimportedbyatestmodule.py,v 1.1 2004/02/20 22:02:24 fdrake Exp $
"""
x = 1
class C:
pass
More information about the Zope3-Checkins
mailing list