Skip to content

Commit c75d98a

Browse files
committed
fix __qualname__ related specs in test.test_funcattrs
1 parent 2a677e6 commit c75d98a

File tree

12 files changed

+127
-20
lines changed

12 files changed

+127
-20
lines changed

src/org/python/compiler/CodeCompiler.java

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -527,7 +527,7 @@ private Object compileFunction(String internalName, java.util.List<expr> decs, j
527527
sig(PyDictionary.class, String[].class, PyObject[].class));
528528

529529
scope.setup_closure();
530-
scope.dump();
530+
// scope.dump();
531531
module.codeConstant(new Suite(node, body), name, true, className, false,
532532
false, node.getLine(), scope, cflags).get(code);
533533

@@ -537,7 +537,7 @@ private Object compileFunction(String internalName, java.util.List<expr> decs, j
537537
} else {
538538
code.aconst_null();
539539
}
540-
code.ldc(className + "." + name);
540+
code.ldc(scope.qualname);
541541

542542
if (!makeClosure(scope)) {
543543
code.invokespecial(p(PyFunction.class), "<init>",
@@ -2536,6 +2536,9 @@ public Object visitLambda(Lambda node) throws Exception {
25362536
"<init>",
25372537
sig(Void.TYPE, PyObject.class, PyObject[].class, PyDictionary.class, PyCode.class, PyObject[].class));
25382538
}
2539+
code.dup();
2540+
code.ldc(scope.qualname);
2541+
code.putfield(p(PyFunction.class), "__qualname__", ci(String.class));
25392542
return null;
25402543
}
25412544

@@ -2590,7 +2593,7 @@ public Object visitClassDef(ClassDef node) throws Exception {
25902593
if (scope.needs_class_closure) {
25912594
scope.needs_class_closure = false;
25922595
// inner = "<inner" + clsName + ">";
2593-
String outer = "<outer" + clsName + ">";
2596+
String outer = scope.scope_name;
25942597
code.new_(p(PyFunction.class));
25952598
code.dup();
25962599
loadFrame();
@@ -2678,6 +2681,7 @@ public Object visitClassDef(ClassDef node) throws Exception {
26782681
int baseArray = makeArray(node.getInternalBases());
26792682

26802683
code.ldc(inner);
2684+
code.ldc(scope.qualname);
26812685

26822686
code.aload(baseArray);
26832687
if (node.getInternalKeywords() != null && node.getInternalKeywords().size() > 0) {
@@ -2698,12 +2702,12 @@ public Object visitClassDef(ClassDef node) throws Exception {
26982702
// Make class out of name, bases, and code
26992703
if (!makeClosure(scope)) {
27002704
code.invokestatic(p(Py.class), "makeClass",
2701-
sig(PyObject.class, String.class, PyObject[].class, PyObject.class, PyCode.class));
2705+
sig(PyObject.class, String.class, String.class, PyObject[].class, PyObject.class, PyCode.class));
27022706
} else {
27032707
code.invokestatic(
27042708
p(Py.class),
27052709
"makeClass",
2706-
sig(PyObject.class, String.class, PyObject[].class, PyObject.class, PyCode.class,
2710+
sig(PyObject.class, String.class, String.class, PyObject[].class, PyObject.class, PyCode.class,
27072711
PyObject[].class));
27082712
}
27092713

src/org/python/compiler/Module.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -425,6 +425,7 @@ public class Module implements Opcodes, ClassConstants, CompilationContext {
425425

426426
ClassFile classfile;
427427
Constant filename;
428+
String name;
428429
String sfilename;
429430
Constant mainCode;
430431
boolean linenumbers;
@@ -444,6 +445,7 @@ public Module(String name, String filename, boolean linenumbers) {
444445
}
445446

446447
public Module(String name, String filename, boolean linenumbers, long mtime) {
448+
this.name = name;
447449
this.linenumbers = linenumbers;
448450
this.mtime = mtime;
449451
classfile =

src/org/python/compiler/ScopeInfo.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,15 @@
22

33
package org.python.compiler;
44

5+
import com.google.common.base.Joiner;
56
import org.python.antlr.PythonTree;
67

8+
import java.util.ArrayList;
9+
import java.util.Collections;
710
import java.util.Enumeration;
811
import java.util.Hashtable;
912
import java.util.LinkedHashMap;
13+
import java.util.List;
1014
import java.util.Map;
1115
import java.util.Vector;
1216

@@ -18,6 +22,7 @@ public class ScopeInfo extends Object implements ScopeConstants {
1822
public int func_level;
1923
public boolean needs_class_closure;
2024
public boolean async;
25+
public String qualname;
2126

2227
public void dump() { // for debugging
2328
if (org.python.core.Options.verbose < org.python.core.Py.DEBUG)
@@ -280,6 +285,12 @@ public void setup_closure(ScopeInfo up){
280285

281286
}
282287

288+
// check if specified name is defined as global
289+
public boolean isGlobal(String name) {
290+
SymInfo info = tbl.get(name);
291+
return info != null && (info.flags & NGLOBAL) != 0;
292+
}
293+
283294
@Override
284295
public String toString() {
285296
return "ScopeInfo[" + scope_name + " " + kind + "]@" +

src/org/python/compiler/ScopesCompiler.java

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,29 @@ public void beginScope(String name, int kind, PythonTree node,
4141
if (kind == FUNCSCOPE) {
4242
func_level++;
4343
}
44+
String qualname;
45+
if ((cur != null && cur.isGlobal(name)) || level == 1) {
46+
qualname = name;
47+
} else if (level > 1) {
48+
qualname = cur.qualname;
49+
if (cur.kind == FUNCSCOPE && kind != CLASSSCOPE) { // ignore the __class__ closure
50+
qualname += ".<locals>";
51+
}
52+
if (kind == CLASSSCOPE) {
53+
int dot = qualname.lastIndexOf(".");
54+
if (dot != -1) {
55+
qualname = qualname.substring(0, dot + 1) + name; // remove the __class__ closure
56+
} else {
57+
qualname = name;
58+
}
59+
} else {
60+
qualname += "." + name;
61+
}
62+
} else {
63+
qualname = "";
64+
}
4465
cur = new ScopeInfo(name, node, level++, kind, func_level, ac);
66+
cur.qualname = qualname;
4567
nodeScopes.put(node, cur);
4668
}
4769

src/org/python/core/Py.java

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2027,14 +2027,24 @@ protected static void setAdapter(ExtensiblePyObjectAdapter adapter) {
20272027
// XXX: The following two makeClass overrides are *only* for the
20282028
// old compiler, they should be removed when the newcompiler hits
20292029
public static PyObject makeClass(String name, PyObject[] bases, PyObject metaclass, PyCode code) {
2030-
return makeClass(name, bases, metaclass, code, null);
2030+
return makeClass(name, name, bases, metaclass, code, null);
2031+
}
2032+
2033+
public static PyObject makeClass(String name, String qualname, PyObject[] bases, PyObject metaclass, PyCode code) {
2034+
return makeClass(name, qualname, bases, metaclass, code, null);
20312035
}
20322036

20332037
public static PyObject makeClass(String name, PyObject[] bases, PyObject metaclass, PyCode code,
20342038
PyObject[] closure_cells) {
2039+
return makeClass(name, name, bases, metaclass, code, closure_cells);
2040+
}
2041+
2042+
public static PyObject makeClass(String name, String qualname, PyObject[] bases, PyObject metaclass, PyCode code,
2043+
PyObject[] closure_cells) {
20352044
ThreadState state = getThreadState();
20362045
PyObject dict = code.call(state, Py.EmptyObjects, Py.NoKeywords,
20372046
state.frame.f_globals, Py.EmptyObjects, new PyDictionary(), new PyTuple(closure_cells));
2047+
dict.__setitem__("__qualname__", new PyUnicode(qualname));
20382048
return makeClass(name, bases, dict, metaclass);
20392049
}
20402050
public static PyObject makeClass(String name, PyObject base, PyObject dict) {

src/org/python/core/PyBuiltinCallable.java

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ public abstract class PyBuiltinCallable extends PyObject {
1414

1515
protected String doc;
1616

17+
protected boolean isStatic;
18+
1719
protected PyBuiltinCallable(PyType type, Info info) {
1820
super(type);
1921
this.info = info;
@@ -36,11 +38,15 @@ public PyObject fastGetName() {
3638
@ExposedGet(name = "__qualname__")
3739
public PyObject getQualname() {
3840
PyObject self = getSelf();
39-
String qualname;
40-
if (self == null || self.getType().__findattr__("__name__") == null) {
41-
qualname = info.getName();
42-
} else {
43-
qualname = self.getType().__getattr__("__name__") + "." + info.getName();
41+
String qualname = info.getName();
42+
if (self != null && self != Py.None) {
43+
if (!isStatic) {
44+
self = self.getType();
45+
}
46+
PyObject name = self.__getattr__("__name__");
47+
if (name != null) {
48+
qualname = name + "." + info.getName();
49+
}
4450
}
4551
return new PyUnicode(qualname);
4652
}

src/org/python/core/PyCell.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,19 @@ public String toString() {
3838
ob_ref.getType().getName(), Py.idstr(ob_ref));
3939
}
4040

41+
@Override
42+
public PyObject richCompare(PyObject other, CompareOp op) {
43+
if (!(other instanceof PyCell)) {
44+
return Py.NotImplemented;
45+
}
46+
PyObject a = ob_ref;
47+
PyObject b = ((PyCell) other).ob_ref;
48+
if (a != null && b != null) {
49+
return a.richCompare(b, op);
50+
}
51+
int result = (a == null ? 0 : 1) - (b == null ? 0 : 1);
52+
return op.bool(result);
53+
}
4154

4255
/* Traverseproc implementation */
4356
@Override

src/org/python/core/PyFunction.java

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ public class PyFunction extends PyObject implements InvocationHandler, Traversep
3030

3131
/** The qualified name */
3232
@ExposedGet
33+
@ExposedSet
3334
public String __qualname__;
3435

3536
/** The writable doc string. */
@@ -115,6 +116,8 @@ public PyFunction(PyObject globals, PyObject[] defaults, PyDictionary kw_default
115116
public PyFunction(PyObject globals, PyObject[] defaults, PyDictionary kw_defaults, PyCode code, PyObject doc) {
116117
this(globals, defaults, kw_defaults, code, doc, null);
117118
}
119+
120+
// used by visitLambda
118121
public PyFunction(PyObject globals, PyObject[] defaults, PyDictionary kw_defaults, PyCode code) {
119122
this(globals, defaults, kw_defaults, code, null, null);
120123
}
@@ -273,23 +276,23 @@ public void delDict() {
273276

274277
@ExposedSet(name = "__globals__")
275278
public void setGlobals(PyObject value) {
276-
throw Py.TypeError("readonly attribute");
279+
throw Py.AttributeError("readonly attribute");
277280
}
278281

279282
@ExposedDelete(name = "__globals__")
280283
public void delGlobals() {
281-
throw Py.TypeError("readonly attribute");
284+
throw Py.AttributeError("readonly attribute");
282285
}
283286

284287

285288
@ExposedSet(name = "__closure__")
286289
public void setClosure(PyObject value) {
287-
throw Py.TypeError("readonly attribute");
290+
throw Py.AttributeError("readonly attribute");
288291
}
289292

290293
@ExposedDelete(name = "__closure__")
291294
public void delClosure() {
292-
throw Py.TypeError("readonly attribute");
295+
throw Py.AttributeError("readonly attribute");
293296
}
294297

295298
private void ensureDict() {
@@ -410,7 +413,12 @@ public PyObject __call__(ThreadState state, PyObject arg1, PyObject[] args,
410413

411414
@Override
412415
public String toString() {
413-
return String.format("<function %s at %s>", __name__, Py.idstr(this));
416+
return String.format("<function %s at %s>", __qualname__, Py.idstr(this));
417+
}
418+
419+
@ExposedDelete(name = "__qualname__")
420+
public void deleteQualname() {
421+
throw Py.TypeError("__qualname__ must be set to a string object");
414422
}
415423

416424
@Override

src/org/python/core/PyObject.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,7 @@ final PyUnicode object__str__() {
240240
}
241241

242242
public PyUnicode __repr__() {
243-
return new PyUnicode(toString());
243+
return object___repr__();
244244
}
245245

246246
@ExposedMethod(names = "__repr__", doc = BuiltinDocs.object___repr___doc)
@@ -1000,7 +1000,7 @@ public void readonlyAttributeError(String name) {
10001000
// XXX: Should be an AttributeError but CPython throws TypeError for read only
10011001
// member descriptors (in structmember.c::PyMember_SetOne), which is expected by a
10021002
// few tests. fixed in py3k: http://bugs.python.org/issue1687163
1003-
throw Py.TypeError("readonly attribute");
1003+
throw Py.AttributeError("readonly attribute");
10041004
}
10051005

10061006
/**

src/org/python/expose/generate/ClassMethodExposer.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ public ClassMethodExposer(Type onType,
2323
asNames,
2424
defaults,
2525
PyBuiltinClassMethodNarrow.class,
26-
doc);
26+
doc,
27+
true);
2728
actualArgs = Type.getArgumentTypes(desc);
2829
}
2930

0 commit comments

Comments
 (0)