# HG changeset patch # Parent ce1d40c892c83fdc026f99a04e3485210baa2133 diff --git a/CPythonLib.includes b/CPythonLib.includes --- a/CPythonLib.includes +++ b/CPythonLib.includes @@ -110,16 +110,17 @@ pickle.py pickletools.py pipes.py plistlib.py poplib.py posixfile.py pprint.py profile.py pstats.py +pty.py pyclbr.py pydoc_topics.py Queue.py quopri.py random.py re.py reconvert.py repr.py @@ -149,16 +150,17 @@ sysconfig.py tabnanny.py this.py textwrap.py tempfile.py token.py tokenize.py trace.py traceback.py +tty.py tzparse.py urllib2.py urlparse.py user.py UserDict.py UserList.py UserString.py uuid.py diff --git a/CoreExposed.includes b/CoreExposed.includes --- a/CoreExposed.includes +++ b/CoreExposed.includes @@ -81,16 +81,17 @@ org/python/modules/jffi/StructLayout$Fie org/python/modules/jffi/StructLayout$ScalarField.class org/python/modules/_threading/Condition.class org/python/modules/_threading/Lock.class org/python/modules/_weakref/CallableProxyType.class org/python/modules/_weakref/ProxyType.class org/python/modules/_weakref/ReferenceType.class org/python/modules/operator$PyAttrGetter.class org/python/modules/operator$PyItemGetter.class +org/python/modules/operator$PyMethodCaller.class org/python/modules/posix/PyStatResult.class org/python/modules/random/PyRandom.class org/python/modules/thread/PyLocal.class org/python/modules/time/PyTimeTuple.class org/python/modules/zipimport/zipimporter.class org/python/antlr/AST.class org/python/antlr/ast/alias.class org/python/antlr/ast/arguments.class diff --git a/Lib/test/test_operator.py b/Lib/test/test_operator.py --- a/Lib/test/test_operator.py +++ b/Lib/test/test_operator.py @@ -442,17 +442,16 @@ class OperatorTestCase(unittest.TestCase self.assertEqual(sorted(inventory, key=getcount), [('orange', 1), ('banana', 2), ('apple', 3), ('pear', 5)]) # multiple gets data = map(str, range(20)) self.assertEqual(operator.itemgetter(2,10,5)(data), ('2', '10', '5')) self.assertRaises(TypeError, operator.itemgetter(2, 'x', 5), data) - @unittest.skip("FIXME: broken") def test_methodcaller(self): self.assertRaises(TypeError, operator.methodcaller) class A: def foo(self, *args, **kwds): return args[0] + args[1] def bar(self, f=42): return f a = A() diff --git a/src/org/python/modules/operator.java b/src/org/python/modules/operator.java --- a/src/org/python/modules/operator.java +++ b/src/org/python/modules/operator.java @@ -1,22 +1,24 @@ // Copyright (c) Corporation for National Research Initiatives package org.python.modules; import org.python.core.ArgParser; import org.python.core.ClassDictInit; import org.python.core.Py; import org.python.core.PyBuiltinFunctionSet; import org.python.core.PyIgnoreMethodTag; +import org.python.core.PyMethod; import org.python.core.PyNewWrapper; import org.python.core.PyObject; import org.python.core.PyString; import org.python.core.PyTuple; import org.python.core.PyType; import org.python.core.PyUnicode; +import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; import org.python.expose.ExposedType; class OperatorFunctions extends PyBuiltinFunctionSet { public OperatorFunctions(String name, int index, int argcount) { this(name, index, argcount, argcount); @@ -238,16 +240,17 @@ public class operator extends PyObject i dict.__setitem__("itruediv", new OperatorFunctions("itruediv", 50, 2)); dict.__setitem__("__ixor__", new OperatorFunctions("__ixor__", 51, 2)); dict.__setitem__("ixor", new OperatorFunctions("ixor", 51, 2)); dict.__setitem__("__index__", new OperatorFunctions("__index__", 52, 1)); dict.__setitem__("index", new OperatorFunctions("index", 52, 1)); dict.__setitem__("attrgetter", PyAttrGetter.TYPE); dict.__setitem__("itemgetter", PyItemGetter.TYPE); + dict.__setitem__("methodcaller", PyMethodCaller.TYPE); } public static int countOf(PyObject seq, PyObject item) { int count = 0; for (PyObject tmp : seq.asIterable()) { if (item._eq(tmp).__nonzero__()) { count++; @@ -311,25 +314,17 @@ public class operator extends PyObject i } return new PyTuple(result); } private PyObject getattr(PyObject obj, PyObject name) { // XXX: We should probably have a PyObject.__getattr__(PyObject) that does // this. This is different than __builtin__.getattr (in how it handles // exceptions) - String nameStr; - if (name instanceof PyUnicode) { - nameStr = ((PyUnicode)name).encode(); - } else if (name instanceof PyString) { - nameStr = name.asString(); - } else { - throw Py.TypeError(String.format("attribute name must be string, not '%.200s'", - name.getType().fastGetName())); - } + String nameStr = ensureStringAttribute(name); String[] components = nameStr.split("\\."); for (String component : components) { obj = obj.__getattr__(component.intern()); } return obj; } } @@ -374,9 +369,78 @@ public class operator extends PyObject i PyObject[] result = new PyObject[items.length]; int i = 0; for (PyObject item : items) { result[i++] = obj.__getitem__(item); } return new PyTuple(result); } } + + /** + * The methodcaller type. + */ + @ExposedType(name = "operator.methodcaller", isBaseType = false) + static class PyMethodCaller extends PyObject { + + public static final PyType TYPE = PyType.fromClass(PyMethodCaller.class); + + public String name; + public PyObject[] args; + public String[] keywords; + + @ExposedGet + public static PyString __doc__ = new PyString( + "methodcaller(name, ...) --> methodcaller object\n\n" + + "Return a callable object that calls the given method on its operand.\n" + + "After, f = methodcaller('name'), the call f(r) returns r.name().\n" + + "After, g = methodcaller('name', 'date', foo=1), the call g(r) returns\n" + + "r.name('date', foo=1)"); + + public PyMethodCaller(String name, PyObject[] args, String[] keywords) { + this.name = name; + this.args = args; + this.keywords = keywords; + } + + @ExposedNew + final static PyObject methodcaller___new__(PyNewWrapper new_, boolean init, + PyType subtype, PyObject[] args, + String[] keywords) { + + if (args.length == 0) { + throw Py.TypeError("methodcaller needs at least one argument, the method name"); + } + String nameStr = ensureStringAttribute(args[0]); + PyObject[] newArgs = new PyObject[args.length-1]; + System.arraycopy(args, 1, newArgs, 0, args.length-1); + return new PyMethodCaller(nameStr, newArgs, keywords); + } + + @Override + public PyObject __call__(PyObject[] args, String[] keywords) { + return methodcaller___call__(args, keywords); + } + + @ExposedMethod + final PyObject methodcaller___call__(PyObject[] args, String[] keywords) { + if (args.length > 1) { + throw Py.TypeError("methodcaller expected 1 arguments, got " + args.length); + } + ArgParser ap = new ArgParser("methodcaller", args, Py.NoKeywords, "obj"); + PyObject obj = ap.getPyObject(0); + return obj.invoke(name, this.args, this.keywords); + } + } + + private static String ensureStringAttribute(PyObject name) { + String nameStr; + if (name instanceof PyUnicode) { + nameStr = ((PyUnicode)name).encode(); + } else if (name instanceof PyString) { + nameStr = name.asString(); + } else { + throw Py.TypeError(String.format("attribute name must be string, not '%.200s'", + name.getType().fastGetName())); + } + return nameStr; + } }