[pypy-svn] r50821 - in pypy/dist/pypy/translator/cli: . src test
antocuni at codespeak.net
antocuni at codespeak.net
Mon Jan 21 12:34:57 CET 2008
Author: antocuni
Date: Mon Jan 21 12:34:55 2008
New Revision: 50821
Modified:
pypy/dist/pypy/translator/cli/dotnet.py
pypy/dist/pypy/translator/cli/gencli.py
pypy/dist/pypy/translator/cli/query.py
pypy/dist/pypy/translator/cli/rte.py
pypy/dist/pypy/translator/cli/src/query.cs
pypy/dist/pypy/translator/cli/support.py
pypy/dist/pypy/translator/cli/test/test_dotnet.py
pypy/dist/pypy/translator/cli/test/test_query.py
Log:
a big refactoring of query.py.
Now info about types are loaded per-assembly instead of per-class, and
they are not cached in pypy/_cache; this is much faster, and removes
all that crappy [cli:query] logs.
Modified: pypy/dist/pypy/translator/cli/dotnet.py
==============================================================================
--- pypy/dist/pypy/translator/cli/dotnet.py (original)
+++ pypy/dist/pypy/translator/cli/dotnet.py Mon Jan 21 12:34:55 2008
@@ -259,6 +259,7 @@
def compute_result_annotation(self):
return SomeOOInstance(self.instance._INSTANCE)
+
class CliNamespace(object):
def __init__(self, name):
self._name = name
@@ -270,23 +271,19 @@
return '%s.%s' % (self._name, name)
def __getattr__(self, attr):
- from pypy.translator.cli.query import load_class_or_namespace
- # .NET namespace are not self-entities but just parts of the
- # FullName of a class. This imply that there is no way ask
- # .NET if a particular name is a namespace; there are many
- # names that are clearly not namespaces such as im_self and
- # _freeze_, but there is no general rule and we have to guess.
- # For now, the heuristic simply check is the first char of the
- # name is a UPPERCASE letter.
+ from pypy.translator.cli.query import get_cli_class, Types, Namespaces
+ from pypy.translator.cli.query import load_assembly, mscorlib
+ load_assembly(mscorlib)
- if attr[0].isalpha() and attr[0] == attr[0].upper():
- # we assume it's a class or namespace
- name = self.__fullname(attr)
- load_class_or_namespace(name)
- assert attr in self.__dict__
- return getattr(self, attr)
+ fullname = self.__fullname(attr)
+ if fullname in Namespaces:
+ value = CliNamespace(fullname)
+ elif fullname in Types:
+ value = get_cli_class(fullname)
else:
- raise AttributeError
+ raise AttributeError, attr
+ setattr(self, attr, value)
+ return value
CLR = CliNamespace(None)
@@ -421,7 +418,7 @@
return res
def _create_NativeException(cliClass):
- from pypy.translator.cli.query import getattr_ex
+ from pypy.translator.cli.support import getattr_ex
TYPE = cliClass._INSTANCE
if PythonNet.__name__ in ('CLR', 'clr'):
# we are using pythonnet -- use the .NET class
@@ -461,12 +458,12 @@
_about_ = new_array
def compute_result_annotation(self, type_s, length_s):
- from pypy.translator.cli.query import load_class_maybe
+ from pypy.translator.cli.query import get_cli_class
assert type_s.is_constant()
assert isinstance(length_s, SomeInteger)
TYPE = type_s.const._INSTANCE
fullname = '%s.%s[]' % (TYPE._namespace, TYPE._classname)
- cliArray = load_class_maybe(fullname)
+ cliArray = get_cli_class(fullname)
return SomeOOInstance(cliArray._INSTANCE)
def specialize_call(self, hop):
@@ -479,7 +476,7 @@
_about_ = init_array
def compute_result_annotation(self, type_s, *args_s):
- from pypy.translator.cli.query import load_class_maybe
+ from pypy.translator.cli.query import get_cli_class
assert type_s.is_constant()
TYPE = type_s.const._INSTANCE
for i, arg_s in enumerate(args_s):
@@ -487,7 +484,7 @@
raise TypeError, 'Wrong type of arg #%d: %s expected, %s found' % \
(i, TYPE, arg_s.ootype)
fullname = '%s.%s[]' % (TYPE._namespace, TYPE._classname)
- cliArray = load_class_maybe(fullname)
+ cliArray = get_cli_class(fullname)
return SomeOOInstance(cliArray._INSTANCE)
def specialize_call(self, hop):
@@ -511,9 +508,9 @@
_about_ = typeof
def compute_result_annotation(self, cliClass_s):
- from query import load_class_maybe
+ from pypy.translator.cli.query import get_cli_class
assert cliClass_s.is_constant()
- cliType = load_class_maybe('System.Type')
+ cliType = get_cli_class('System.Type')
return SomeOOInstance(cliType._INSTANCE)
def specialize_call(self, hop):
Modified: pypy/dist/pypy/translator/cli/gencli.py
==============================================================================
--- pypy/dist/pypy/translator/cli/gencli.py (original)
+++ pypy/dist/pypy/translator/cli/gencli.py Mon Jan 21 12:34:55 2008
@@ -17,7 +17,6 @@
from pypy.translator.cli.rte import get_pypy_dll
from pypy.translator.cli.support import Tee
from pypy.translator.cli.prebuiltnodes import get_prebuilt_nodes
-from pypy.translator.cli import query
from pypy.translator.cli import constant
class GenCli(GenOO):
@@ -50,7 +49,6 @@
def generate_source(self):
GenOO.generate_source(self)
self.db.const_count.dump(self.const_stat)
- query.savedesc()
return self.tmpfile.strpath
def create_assembler(self):
Modified: pypy/dist/pypy/translator/cli/query.py
==============================================================================
--- pypy/dist/pypy/translator/cli/query.py (original)
+++ pypy/dist/pypy/translator/cli/query.py Mon Jan 21 12:34:55 2008
@@ -1,149 +1,147 @@
+import sys
import cPickle as pickle
import os.path
+import py
from py.compat import subprocess
+from pypy.tool.udir import udir
from pypy.rpython.ootypesystem import ootype
from pypy.translator.cli.rte import Query
from pypy.translator.cli.sdk import SDK
from pypy.translator.cli.support import log
from pypy.translator.cli.dotnet import CLR, CliNamespace, CliClass,\
NativeInstance, _overloaded_static_meth, _static_meth, OverloadingResolver
-
-ClassCache = {}
-OOTypeCache = {}
-Descriptions = {}
-
-class Dummy: pass
-fake_root = Dummy()
-fake_root._INSTANCE = ootype.ROOT
-ClassCache['ROOT'] = fake_root
-ClassCache['System.Array'] = fake_root
-del fake_root
-del Dummy
-
-def _descfilename(filename):
- if filename is None:
- curdir = os.path.dirname(__file__)
- return os.path.join(curdir, 'query-descriptions')
+
+Assemblies = set()
+Types = {} # TypeName -> ClassDesc
+Namespaces = set()
+mscorlib = 'mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'
+
+#_______________________________________________________________________________
+# This is the public interface of query.py
+
+def load_assembly(name):
+ if name in Assemblies:
+ return
+ Query.get() # clear the cache if we need to recompile
+ _cache = get_cachedir()
+ outfile = _cache.join(name + '.pickle')
+ if outfile.check():
+ f = outfile.open('rb')
+ types = pickle.load(f)
+ f.close()
else:
- return filename
+ types = load_and_cache_assembly(name, outfile)
-def savedesc(filename=None):
- f = open(_descfilename(filename), 'wb')
- pickle.dump(Descriptions, f, protocol=-1)
+ for ttype in types:
+ parts = ttype.split('.')
+ ns = parts[0]
+ Namespaces.add(ns)
+ for part in parts[1:-1]:
+ ns = '%s.%s' % (ns, part)
+ Namespaces.add(ns)
+ Assemblies.add(name)
+ Types.update(types)
+
+
+def get_cli_class(name):
+ desc = get_class_desc(name)
+ return desc.get_cliclass()
+
+#_______________________________________________________________________________
+
+
+def get_cachedir():
+ import pypy
+ _cache = py.path.local(pypy.__file__).new(basename='_cache').ensure(dir=1)
+ return _cache
+
+def load_and_cache_assembly(name, outfile):
+ tmpfile = udir.join(name)
+ arglist = SDK.runtime() + [Query.get(), name, str(tmpfile)]
+ retcode = subprocess.call(arglist)
+ assert retcode == 0
+ mydict = {}
+ execfile(str(tmpfile), mydict)
+ types = mydict['types']
+ f = outfile.open('wb')
+ pickle.dump(types, f, pickle.HIGHEST_PROTOCOL)
f.close()
+ return types
-def loaddesc(filename=None):
- filename = _descfilename(filename)
- if not os.path.exists(filename):
- return
- f = open(filename, 'rb')
- try:
- newdesc = pickle.load(f)
- except pickle.UnpicklingError:
- log.WARNING('query-descriptions file exits, but failed to unpickle')
+def get_ootype(name):
+ # a bit messy, but works
+ if name.startswith('ootype.'):
+ _, name = name.split('.')
+ return getattr(ootype, name)
else:
- Descriptions.clear()
- Descriptions.update(newdesc)
+ cliclass = get_cli_class(name)
+ return cliclass._INSTANCE
-def getattr_ex(target, attr):
- parts = attr.split('.')
- for part in parts:
- target = getattr(target, part)
- return target
-
-def setattr_ex(target, attr, value):
- if '.' in attr:
- namespace, attr = attr.rsplit('.', 1)
- target = getattr_ex(target, namespace)
- setattr(target, attr, value)
-
-def load_class_or_namespace(name):
- try:
- desc = Descriptions[name]
- except KeyError:
- desc = query_description(name)
- Descriptions[name] = desc
- res = desc.build()
- setattr_ex(CLR, name, res)
- return res
-
-def query_description(name):
- log.query('Loading description for %s' % name)
- arglist = SDK.runtime() + [Query.get(), name]
- query = subprocess.Popen(arglist, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
- universal_newlines=True)
- stdout, stderr = query.communicate()
- retval = query.wait()
- if retval == 0:
- cls = ClassDesc()
- exec stdout in cls.__dict__
- del cls.__dict__['__builtins__']
- return cls
- elif retval == 1:
- raise RuntimeError, 'query.exe failed with this message:\n%s' % stderr
- elif retval == 2:
- # can't load type, assume it's a namespace
- return NamespaceDesc(name)
-
-def load_class_maybe(name):
- if name.startswith('System.Array+InternalArray'):
- res = ClassCache['System.Array']
- ClassCache[name] = res
- return res
- elif name not in ClassCache:
- return load_class_or_namespace(name)
+def get_class_desc(name):
+ if name in Types:
+ return Types[name]
+
+ if name == 'System.Array':
+ desc = ClassDesc()
+ desc.Assembly = mscorlib
+ desc.FullName = name
+ desc.BaseType = 'System.Object'
+ desc.IsArray = True
+ desc.ElementType = 'System.Object' # not really true, but we need something
+ desc.StaticMethods = []
+ desc.Methods = []
+ elif name.endswith('[]'): # it's an array
+ itemname = name[:-2]
+ itemdesc = get_class_desc(itemname)
+ desc = ClassDesc()
+ desc.Assembly = mscorlib
+ desc.FullName = name
+ desc.BaseType = 'System.Array'
+ desc.ElementType = itemdesc.FullName
+ desc.IsArray = True
+ desc.StaticMethods = []
+ desc.Methods = [
+ ('Get', ['ootype.Signed', ], itemdesc.FullName),
+ ('Set', ['ootype.Signed', itemdesc.FullName], 'ootype.Void')
+ ]
else:
- return ClassCache[name]
+ assert False, 'Unknown desc'
+
+ Types[name] = desc
+ return desc
+
+class ClassDesc(object):
+ _cliclass = None
-class Desc:
- def build(self):
- raise NotImplementedError
-
def __eq__(self, other):
return self.__dict__ == other.__dict__
def __hash__(self):
raise TypeError
-
-class NamespaceDesc(Desc):
- def __init__(self, name):
- self.name = name
- def build(self):
- return CliNamespace(self.name)
-
-class ClassDesc(Desc):
- def build(self):
+ def get_cliclass(self):
+ if self._cliclass is not None:
+ return self._cliclass
+
assert self.Assembly.startswith('mscorlib') # TODO: support external assemblies
namespace, name = self.FullName.rsplit('.', 1)
# construct OOTYPE and CliClass
- if self.FullName == 'System.Type':
- # we need to special case System.Type because it contains
- # circular dependencies, since its superclasses have got
- # methods which take System.Type as parameters
- BASETYPE = None
- else:
- load_class_maybe(self.BaseType)
- BASETYPE = ClassCache[self.BaseType]._INSTANCE
- TYPE = NativeInstance('[mscorlib]', namespace, name, BASETYPE, {}, {})
- TYPE._isArray = self.IsArray
- if self.IsArray:
- load_class_maybe(self.ElementType)
- TYPE._ELEMENT = ClassCache[self.ElementType]._INSTANCE
+ # no superclass for now, will add it later
+ TYPE = NativeInstance('[mscorlib]', namespace, name, None, {}, {})
Class = CliClass(TYPE, {})
- OOTypeCache[self.OOType] = TYPE
- ClassCache[self.FullName] = Class
-
- if BASETYPE is None:
- load_class_maybe(self.BaseType)
- BASETYPE = ClassCache[self.BaseType]._INSTANCE
+ self._cliclass = Class
+ # we need to check also for System.Array to prevent a circular recursion
+ if self.FullName in ('System.Object', 'System.Array'):
+ TYPE._set_superclass(ootype.ROOT)
+ else:
+ BASETYPE = get_ootype(self.BaseType)
TYPE._set_superclass(BASETYPE)
- # render dependencies
- for name in self.Depend:
- load_class_maybe(name)
+ TYPE._isArray = self.IsArray
+ if self.IsArray:
+ TYPE._ELEMENT = get_ootype(self.ElementType)
# add both static and instance methods
static_meths = self.group_methods(self.StaticMethods, _overloaded_static_meth,
@@ -167,17 +165,6 @@
return res
def get_method_type(self, Meth, args, result):
- ARGS = [self.get_ootype(arg) for arg in args]
- RESULT = self.get_ootype(result)
+ ARGS = [get_ootype(arg) for arg in args]
+ RESULT = get_ootype(result)
return Meth(ARGS, RESULT)
-
- def get_ootype(self, t):
- # a bit messy, but works
- if t.startswith('ootype.'):
- _, name = t.split('.')
- return getattr(ootype, name)
- else:
- return OOTypeCache[t]
-
-
-loaddesc() ## automatically loads the cached Dependencies
Modified: pypy/dist/pypy/translator/cli/rte.py
==============================================================================
--- pypy/dist/pypy/translator/cli/rte.py (original)
+++ pypy/dist/pypy/translator/cli/rte.py Mon Jan 21 12:34:55 2008
@@ -95,10 +95,10 @@
def compile(cls, sources, out):
# assume that if query.exe need to be recompiled the descriptions cache is invalid
- from pypy.translator.cli.query import _descfilename
- filename = _descfilename(None)
- if os.path.exists(filename):
- os.remove(filename)
+ from pypy.translator.cli.query import get_cachedir, mscorlib
+ mscorlib_cache = get_cachedir().join(mscorlib + '.pickle')
+ if mscorlib_cache.check():
+ mscorlib_cache.remove()
Target.compile.im_func(cls, sources, out)
compile = classmethod(compile)
Modified: pypy/dist/pypy/translator/cli/src/query.cs
==============================================================================
--- pypy/dist/pypy/translator/cli/src/query.cs (original)
+++ pypy/dist/pypy/translator/cli/src/query.cs Mon Jan 21 12:34:55 2008
@@ -1,53 +1,73 @@
using System;
+using System.IO;
using System.Reflection;
using System.Collections.Generic;
public class Query
{
- public static Dictionary<Type, bool> PendingTypes = new Dictionary<Type, bool>();
+ private static StreamWriter outfile = null;
public static int Main(string[] argv)
{
- if (argv.Length != 1) {
- Console.Error.WriteLine("Usage: query full-qualified-name");
+ if (argv.Length != 2) {
+ Console.Error.WriteLine("Usage: query assembly-name output-file");
return 1;
}
string name = argv[0];
- Type t = Type.GetType(name);
- if (t == null) {
- Console.Error.WriteLine("Cannot load type {0}", name);
+ string outname = argv[1];
+ Assembly ass;
+ try {
+ ass = Assembly.Load(name);
+ }
+ catch(System.IO.IOException e) {
+ Console.Error.WriteLine("Cannot load assembly {0}: {1}", name, e.Message);
return 2;
}
- if (!t.IsPublic) {
- Console.Error.WriteLine("Cannot load a non-public type");
- return 2;
+ try {
+ outfile = new StreamWriter(outname);
}
-
- PrintType(t);
+ catch(System.IO.IOException e) {
+ Console.Error.WriteLine("Cannot open file {0}: {1}", outname, e.Message);
+ return 3;
+ }
+
+ PrintAssembly(ass);
+ outfile.Close();
return 0;
}
+ private static void PrintAssembly(Assembly ass)
+ {
+ Type[] types = ass.GetTypes();
+ outfile.WriteLine("# This file has been autogenerated by query.exe -- DO NOT EDIT");
+ outfile.WriteLine("from pypy.translator.cli.query import ClassDesc");
+ outfile.WriteLine("types = {}");
+ foreach(Type t in types) {
+ if (IgnoreType(t))
+ continue;
+ PrintType(t);
+ outfile.WriteLine("types['{0}'] = desc", t.FullName);
+ outfile.WriteLine("del desc");
+ }
+ }
+
private static void PrintType(Type t)
{
- Console.WriteLine("Assembly = '{0}'", t.Assembly.FullName);
- Console.WriteLine("FullName = '{0}'", t.FullName);
- Console.WriteLine("BaseType = '{0}'", GetBaseType(t));
- Console.WriteLine("OOType = '{0}'", GetOOType(t));
- Console.WriteLine("IsArray = {0}", t.IsArray);
- if (t.IsArray)
- Console.WriteLine("ElementType = '{0}'", t.GetElementType().FullName);
- PrintMethods("StaticMethods", t.GetMethods(BindingFlags.Static|BindingFlags.Public|BindingFlags.DeclaredOnly));
- PrintMethods("Methods", t.GetMethods(BindingFlags.Instance|BindingFlags.Public|BindingFlags.DeclaredOnly));
- PendingTypes.Remove(t);
- PrintDepend();
+ outfile.WriteLine("desc = ClassDesc()");
+ outfile.WriteLine("desc.Assembly = '{0}'", t.Assembly.FullName);
+ outfile.WriteLine("desc.FullName = '{0}'", t.FullName);
+ outfile.WriteLine("desc.BaseType = '{0}'", GetBaseType(t));
+ outfile.WriteLine("desc.IsArray = {0}", t.IsArray);
+ PrintMethods("desc.StaticMethods", t.GetMethods(BindingFlags.Static|BindingFlags.Public|BindingFlags.DeclaredOnly));
+ PrintMethods("desc.Methods", t.GetMethods(BindingFlags.Instance|BindingFlags.Public|BindingFlags.DeclaredOnly));
}
private static string GetBaseType(Type t)
{
if (t == typeof(object))
- return "ROOT"; // special case for System.Object to avoid circular dependencies
+ return "System.Object"; // special case for System.Object to avoid circular dependencies
else if (t.BaseType == null)
return "System.Object"; // the only known case is the BaseType of an interface
else
@@ -77,29 +97,25 @@
else if (t == typeof(string))
return "ootype.String";
else {
- PendingTypes[t] = true;
- string name = t.FullName.Replace(".", "_"); // TODO: ensure unicity
- if (t.IsArray)
- name = name.Replace("[]", "___array___");
- return name;
+ return t.FullName;
}
}
private static void PrintMethods(string varname, MethodInfo[] methods)
{
- Console.WriteLine("{0} = [", varname);
+ outfile.WriteLine("{0} = [", varname);
// MethodName, [ARGS], RESULT
foreach(MethodInfo meth in methods) {
if (IgnoreMethod(meth))
continue;
- Console.Write(" ('{0}', [", meth.Name);
+ outfile.Write(" ('{0}', [", meth.Name);
foreach(ParameterInfo par in meth.GetParameters()) {
- Console.Write("'{0}'", GetOOType(par.ParameterType));
- Console.Write(", ");
+ outfile.Write("'{0}'", GetOOType(par.ParameterType));
+ outfile.Write(", ");
}
- Console.WriteLine("], '{0}'),", GetOOType(meth.ReturnType));
+ outfile.WriteLine("], '{0}'),", GetOOType(meth.ReturnType));
}
- Console.WriteLine(" ]");
+ outfile.WriteLine(" ]");
}
private static bool IgnoreMethod(MethodInfo meth)
@@ -124,21 +140,13 @@
{
return !t.IsPrimitive
&& t != typeof(void)
- &&(t == typeof(System.ValueType) ||
- t == typeof(System.Array) ||
+ &&(t == typeof(System.Array) ||
+ t.FullName == null ||
t.FullName.StartsWith("System.Array+InternalArray") ||
- t.IsValueType ||
+ t.IsNotPublic ||
t.IsByRef ||
t.IsPointer ||
t.IsGenericType ||
t.IsGenericTypeDefinition);
}
-
- private static void PrintDepend()
- {
- Console.Write("Depend = [");
- foreach(Type t in PendingTypes.Keys)
- Console.Write("'{0}', ", t.FullName);
- Console.WriteLine("]");
- }
}
Modified: pypy/dist/pypy/translator/cli/support.py
==============================================================================
--- pypy/dist/pypy/translator/cli/support.py (original)
+++ pypy/dist/pypy/translator/cli/support.py Mon Jan 21 12:34:55 2008
@@ -66,3 +66,14 @@
f.write('%s: %d\n' % (label, self.counters[key]))
f.close()
+def getattr_ex(target, attr):
+ parts = attr.split('.')
+ for part in parts:
+ target = getattr(target, part)
+ return target
+
+def setattr_ex(target, attr, value):
+ if '.' in attr:
+ namespace, attr = attr.rsplit('.', 1)
+ target = getattr_ex(target, namespace)
+ setattr(target, attr, value)
Modified: pypy/dist/pypy/translator/cli/test/test_dotnet.py
==============================================================================
--- pypy/dist/pypy/translator/cli/test/test_dotnet.py (original)
+++ pypy/dist/pypy/translator/cli/test/test_dotnet.py Mon Jan 21 12:34:55 2008
@@ -349,6 +349,7 @@
assert res.startswith("Index is less than 0")
def test_typeof(self):
+ System.Int32 # force Int32 to be loaded
def fn():
x = box(42)
return x.GetType() == typeof(System.Int32)
Modified: pypy/dist/pypy/translator/cli/test/test_query.py
==============================================================================
--- pypy/dist/pypy/translator/cli/test/test_query.py (original)
+++ pypy/dist/pypy/translator/cli/test/test_query.py Mon Jan 21 12:34:55 2008
@@ -1,16 +1,21 @@
+import py
from pypy.translator.cli import query
from pypy.translator.cli.dotnet import CLR, CliNamespace
-def test_load_namespace_simple():
- query.load_class_or_namespace('System')
- assert isinstance(CLR.System, CliNamespace)
- assert CLR.System._name == 'System'
+def setup_module(module):
+ from pypy.translator.cli.query import load_assembly, mscorlib
+ load_assembly(mscorlib)
+
+def test_load_assembly():
+ query.load_assembly(query.mscorlib)
+ assert 'System.Math' in query.Types
+ assert 'System.Collections.ArrayList' in query.Types
-def test_load_namespace_complex():
- query.load_class_or_namespace('System.Collections')
- assert isinstance(CLR.System, CliNamespace)
- assert isinstance(CLR.System.Collections, CliNamespace)
+def test_namespaces():
+ assert CLR.System._name == 'System'
assert CLR.System.Collections._name == 'System.Collections'
+ py.test.raises(AttributeError, getattr, CLR, 'Foo')
+ py.test.raises(AttributeError, getattr, CLR.System, 'Foo')
def test_CLR_getattr():
System = CLR.System
@@ -25,17 +30,6 @@
assert 'ToString' in Object._INSTANCE._methods
def test_array():
- query.load_class_or_namespace('System.Object[]')
- cls = query.ClassCache['System.Object[]']
+ cls = query.get_cli_class('System.Object[]')
assert cls._INSTANCE._isArray
assert cls._INSTANCE._ELEMENT is CLR.System.Object._INSTANCE
-
-def test_savedesc():
- from pypy.tool.udir import udir
- CLR.System.Object # force System.Object to be loaded
- olddesc = query.Descriptions.copy()
- tmpfile = str(udir.join('descriptions'))
- query.savedesc(tmpfile)
- query.Descriptions.clear()
- query.loaddesc(tmpfile)
- assert query.Descriptions == olddesc
More information about the pypy-svn
mailing list