Index: src/org/python/core/PyFrozenSet.java
===================================================================
--- src/org/python/core/PyFrozenSet.java (revision 4416)
+++ src/org/python/core/PyFrozenSet.java (working copy)
@@ -1,5 +1,7 @@
package org.python.core;
+import java.math.BigInteger;
+
import org.python.expose.ExposedMethod;
import org.python.expose.ExposedNew;
import org.python.expose.ExposedType;
@@ -23,18 +25,35 @@
}
@ExposedNew
- @ExposedMethod
- final void frozenset___init__(PyObject[] args, String[] kwds) {
- int nargs = args.length - kwds.length;
- if (nargs > 1) {
- throw PyBuiltinFunction.DefaultInfo.unexpectedCall(nargs, false, "FrozenSet", 0, 1);
+ public static PyObject frozenset___new__(PyNewWrapper new_, boolean init, PyType subtype,
+ PyObject[] args, String[] keywords) {
+
+ ArgParser ap = new ArgParser("frozenset", args, keywords, new String[] {"iterable"}, 0);
+ PyObject iterable = ap.getPyObject(0, null);
+ PyFrozenSet fset = null;
+
+ if (new_.for_type == subtype) {
+ if (iterable == null) {
+ fset = Py.EmptyFrozenSet;
+ } else if (iterable.getClass() == PyFrozenSet.class) {
+ fset = (PyFrozenSet) iterable;
+ } else {
+ fset = new PyFrozenSet(iterable);
+ if (fset.__len__() == 0) {
+ fset = Py.EmptyFrozenSet;
+ }
+ }
+ } else {
+ fset = new PyFrozenSetDerived(subtype);
+ if (iterable != null) {
+ fset._update(iterable);
+ }
+ if (init) {
+ ((PyFrozenSetDerived)fset).dispatch__init__(subtype, args, keywords);
+ }
}
- if (nargs == 0) {
- return;
- }
- PyObject o = args[0];
- _update(o);
+ return fset;
}
@ExposedMethod(type = MethodType.BINARY)
@@ -114,6 +133,10 @@
@ExposedMethod
final PyObject frozenset_copy() {
+ if (getClass() == PyFrozenSet.class) {
+ return this;
+ }
+ // subclasses should revert to normal behavior of creating a new instance
return baseset_copy();
}
@@ -159,11 +182,11 @@
@ExposedMethod
final int frozenset___hash__() {
- return hashCode();
+ return this._set.hashCode();
}
public int hashCode() {
- return this._set.hashCode();
+ return frozenset___hash__();
}
public PyObject _as_immutable() {
Index: src/org/python/core/PySet.java
===================================================================
--- src/org/python/core/PySet.java (revision 4416)
+++ src/org/python/core/PySet.java (working copy)
@@ -1,6 +1,7 @@
package org.python.core;
import java.util.Iterator;
+import java.util.NoSuchElementException;
import org.python.expose.ExposedMethod;
import org.python.expose.ExposedNew;
@@ -35,6 +36,7 @@
return;
}
+ this._set.clear();
PyObject o = args[0];
_update(o);
}
@@ -213,12 +215,7 @@
@ExposedMethod
final void set_add(PyObject o) {
- try {
- this._set.add(o);
- } catch (PyException e) {
- PyObject immutable = this.asImmutable(e, o);
- this._set.add(immutable);
- }
+ this._set.add(o);
}
@ExposedMethod
@@ -231,7 +228,7 @@
b = this._set.remove(immutable);
}
if (!b) {
- throw new PyException(Py.LookupError, o.toString());
+ throw new PyException(Py.KeyError, o);
}
}
@@ -248,9 +245,13 @@
@ExposedMethod
final PyObject set_pop() {
Iterator iterator = this._set.iterator();
- Object first = iterator.next();
- this._set.remove(first);
- return (PyObject) first;
+ try {
+ Object first = iterator.next();
+ this._set.remove(first);
+ return (PyObject) first;
+ } catch (NoSuchElementException e) {
+ throw new PyException(Py.KeyError, "pop from an empty set");
+ }
}
@ExposedMethod
Index: src/org/python/core/BaseSet.java
===================================================================
--- src/org/python/core/BaseSet.java (revision 4416)
+++ src/org/python/core/BaseSet.java (working copy)
@@ -45,17 +45,13 @@
* @throws PyIgnoreMethodTag Ignore.
*/
protected void _update(PyObject data) throws PyIgnoreMethodTag {
- if(data instanceof BaseSet) {
+ if (data instanceof BaseSet) {
// Skip the iteration if both are sets
this._set.addAll(((BaseSet)data)._set);
return;
}
for (PyObject item : data.asIterable()) {
- try {
- this._set.add(item);
- } catch (PyException e) {
- this._set.add(asImmutable(e, item));
- }
+ this._set.add(item);
}
}
@@ -125,7 +121,7 @@
final PyObject baseset_difference(PyObject other) {
BaseSet bs = (other instanceof BaseSet) ? (BaseSet) other : new PySet(other);
Set set = bs._set;
- BaseSet o = (BaseSet) this.getType().__call__();
+ BaseSet o = BaseSet.makeNewSet(getType());
for (Object p : this._set) {
if (!set.contains(p)) {
o._set.add(p);
@@ -161,7 +157,7 @@
public PyObject baseset_symmetric_difference(PyObject other) {
BaseSet bs = (other instanceof BaseSet) ? (BaseSet) other : new PySet(other);
- BaseSet o = (BaseSet) this.getType().__call__();
+ BaseSet o = BaseSet.makeNewSet(getType());
for (Object p : this._set) {
if (!bs._set.contains(p)) {
o._set.add(p);
@@ -227,7 +223,12 @@
}
final boolean baseset___contains__(PyObject other) {
- return this._set.contains(other);
+ try {
+ return this._set.contains(other);
+ } catch (PyException e) {
+ PyObject immutable = this.asImmutable(e, other);
+ return this._set.contains(immutable);
+ }
}
public int __cmp__(PyObject other) {
@@ -322,7 +323,7 @@
final PyObject baseset___deepcopy__(PyObject memo) {
PyObject copy = __builtin__.__import__("copy");
PyObject deepcopy = copy.__getattr__("deepcopy");
- BaseSet result = (BaseSet) this.getType().__call__();
+ BaseSet result = BaseSet.makeNewSet(getType());
memo.__setitem__(Py.newInteger(Py.id(this)), result);
for (Object p : this._set) {
result._set.add(deepcopy.__call__(Py.java2py(p), memo));
@@ -344,13 +345,12 @@
}
public PyObject baseset_union(PyObject other) {
- BaseSet result = (BaseSet) this.getType().__call__(this);
+ BaseSet result = BaseSet.makeNewSet(getType(), this);
result._update(other);
return result;
}
public PyObject baseset_intersection(PyObject other) {
-
PyObject little, big;
if(!(other instanceof BaseSet)) {
other = new PySet(other);
@@ -365,12 +365,11 @@
}
PyObject common = __builtin__.filter(big.__getattr__("__contains__"), little);
- return other.getType().__call__(common);
+ return BaseSet.makeNewSet(getType(), common);
}
public PyObject baseset_copy() {
- BaseSet copy = (BaseSet) this.getType().__call__();
- copy._set = (HashSet) this._set.clone();
+ BaseSet copy = BaseSet.makeNewSet(getType(), this);
return copy;
}
@@ -428,6 +427,10 @@
/**
* If the exception e
is a TypeError
, attempt to convert
* the object value
into an ImmutableSet.
+ *
+ * This is better than special-casing behavior based on isinstance, because a Python
+ * subclass can override, say, __hash__ and all of a sudden you can't assume that
+ * a non-PyFrozenSet is unhashable anymore.
*
* @param e The exception thrown from a hashable operation.
* @param value The object which was unhashable.
@@ -443,7 +446,41 @@
throw e;
}
-// public int size() {
+ /**
+ * Create a new set of type.
+ *
+ * @param type a set type
+ * @return a new set
+ */
+ protected static BaseSet makeNewSet(PyType type) {
+ return makeNewSet(type, null);
+ }
+
+ /**
+ * Create a new