Fix pythonnondynamic feature for modern classes
Fixes nondynamic mode when an instance variable is set with the same name as a class variable in a class derived from a SWIG proxy class. The python_nondynamic testcase now works using -modern and testcase enhanced slightly too. Fixes #718
This commit is contained in:
parent
5ce880ee41
commit
fe082382c7
3 changed files with 112 additions and 26 deletions
|
|
@ -1,21 +1,41 @@
|
||||||
import python_nondynamic
|
import python_nondynamic
|
||||||
|
|
||||||
|
def is_python_modern():
|
||||||
|
"""Return True if SWIG is generating Python code using -modern. Works only if %python_nondynamic has been used."""
|
||||||
|
return hasattr(python_nondynamic, "_swig_setattr_nondynamic_class_variable")
|
||||||
|
|
||||||
|
def debug_print(s):
|
||||||
|
show_debug = False
|
||||||
|
if show_debug:
|
||||||
|
print(s)
|
||||||
|
|
||||||
aa = python_nondynamic.A()
|
aa = python_nondynamic.A()
|
||||||
|
|
||||||
aa.a = 1
|
aa.a = 1
|
||||||
aa.b = 2
|
aa.b = 2
|
||||||
|
|
||||||
|
# Check values are really set
|
||||||
|
if python_nondynamic.retrieve_A_a(aa) != 1: raise RuntimeError("a not set correctly")
|
||||||
|
if python_nondynamic.retrieve_A_b(aa) != 2: raise RuntimeError("b not set correctly")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
aa.c = 2
|
aa.c = 2
|
||||||
err = 0
|
raise RuntimeError("A is not static")
|
||||||
except:
|
except AttributeError as e:
|
||||||
err = 1
|
debug_print(e)
|
||||||
|
pass
|
||||||
if not err:
|
|
||||||
raise RuntimeError, "A is not static"
|
|
||||||
|
|
||||||
|
class PurePythonClass(object):
|
||||||
|
def __init__(self):
|
||||||
|
self.variables = dict()
|
||||||
|
def __set__(self, name, value):
|
||||||
|
self.variables[name] = value
|
||||||
|
pass
|
||||||
|
|
||||||
class B(python_nondynamic.A):
|
class B(python_nondynamic.A):
|
||||||
c = 4
|
c = 4
|
||||||
|
cc = PurePythonClass()
|
||||||
|
cc.nnn = "new attrib"
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
python_nondynamic.A.__init__(self)
|
python_nondynamic.A.__init__(self)
|
||||||
|
|
@ -23,26 +43,66 @@ class B(python_nondynamic.A):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
bb = B()
|
bb = B()
|
||||||
|
bb.a = 4
|
||||||
|
bb.b = 5
|
||||||
|
# Check values are really set
|
||||||
|
if python_nondynamic.retrieve_A_a(bb) != 4: raise RuntimeError("a not set correctly")
|
||||||
|
if python_nondynamic.retrieve_A_b(bb) != 5: raise RuntimeError("b not set correctly")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
bb.c = 3
|
bb.c = 3
|
||||||
err = 0
|
print("bb.c = {}".format(bb.c))
|
||||||
except:
|
print("B.c = {}".format(B.c))
|
||||||
err = 1
|
raise RuntimeError("B.c class variable messes up nondynamic-ness of B")
|
||||||
|
except AttributeError as e:
|
||||||
if not err:
|
debug_print(e)
|
||||||
print "bb.c = %d" % bb.c
|
pass
|
||||||
print "B.c = %d" % B.c
|
|
||||||
raise RuntimeError, "B.c class variable messes up nondynamic-ness of B"
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
bb.d = 2
|
bb.d = 2
|
||||||
err = 0
|
raise RuntimeError("B is not static")
|
||||||
except:
|
except AttributeError as e:
|
||||||
err = 1
|
debug_print(e)
|
||||||
|
pass
|
||||||
if not err:
|
|
||||||
raise RuntimeError, "B is not static"
|
|
||||||
|
|
||||||
cc = python_nondynamic.C()
|
cc = python_nondynamic.C()
|
||||||
cc.d = 3
|
cc.d = 3
|
||||||
|
|
||||||
|
# An inconsistency between builtin and (non-builtin/modern).
|
||||||
|
# Class variables cannot be set on builtin types, like other Python builtins, eg list.classvar=111 fails
|
||||||
|
if python_nondynamic.is_python_builtin():
|
||||||
|
try:
|
||||||
|
python_nondynamic.C.classvar = 111
|
||||||
|
raise RuntimeError("C should not allow static variables to be added when using builtin")
|
||||||
|
except AttributeError as e:
|
||||||
|
debug_print(e)
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
python_nondynamic.C.classvar = 111
|
||||||
|
|
||||||
|
if is_python_modern():
|
||||||
|
# Not working with builtin or non-modern :(
|
||||||
|
try:
|
||||||
|
B.a = 10
|
||||||
|
raise RuntimeError("B should not allow adding a class variable by setting it as an instance variable")
|
||||||
|
except AttributeError as e:
|
||||||
|
debug_print(e)
|
||||||
|
pass
|
||||||
|
|
||||||
|
try:
|
||||||
|
python_nondynamic.A.a = 10
|
||||||
|
raise RuntimeError("A should not allow adding a class variable by setting it as an instance variable")
|
||||||
|
except AttributeError as e:
|
||||||
|
debug_print(e)
|
||||||
|
pass
|
||||||
|
|
||||||
|
if not python_nondynamic.is_python_builtin():
|
||||||
|
try:
|
||||||
|
bb.cc = 3
|
||||||
|
print("bb.cc = {}".format(bb.cc))
|
||||||
|
print("B.cc = {}".format(B.cc))
|
||||||
|
raise RuntimeError("B.cc class variable messes up nondynamic-ness of B")
|
||||||
|
except AttributeError as e:
|
||||||
|
debug_print(e)
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -54,5 +54,14 @@
|
||||||
int b;
|
int b;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
int retrieve_A_a(const struct A* self) { return self->a; }
|
||||||
|
int retrieve_A_b(const struct A* self) { return self->b; }
|
||||||
|
%}
|
||||||
|
%inline %{
|
||||||
|
#ifdef SWIGPYTHON_BUILTIN
|
||||||
|
int is_python_builtin() { return 1; }
|
||||||
|
#else
|
||||||
|
int is_python_builtin() { return 0; }
|
||||||
|
#endif
|
||||||
%}
|
%}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -951,15 +951,32 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (modern) {
|
if (modern) {
|
||||||
Printv(f_shadow, "\n", "def _swig_setattr_nondynamic_method(set):\n", tab4, "def set_attr(self, name, value):\n",
|
Printv(f_shadow, "\n", "def _swig_setattr_nondynamic_instance_variable(set):\n",
|
||||||
|
tab4, "def set_instance_attr(self, name, value):\n",
|
||||||
#ifdef USE_THISOWN
|
#ifdef USE_THISOWN
|
||||||
tab4, tab4, "if hasattr(self, name) or (name in (\"this\", \"thisown\")):\n",
|
tab4, tab4, "if name in (\"this\", \"thisown\"):\n",
|
||||||
|
tab4, tab4, tab4, "set(self, name, value)\n",
|
||||||
#else
|
#else
|
||||||
tab4, tab4, "if name == \"thisown\":\n", tab8, tab4, "return self.this.own(value)\n", tab4, tab4, "if hasattr(self, name) or (name == \"this\"):\n",
|
tab4, tab4, "if name == \"thisown\":\n",
|
||||||
|
tab4, tab4, tab4, "self.this.own(value)\n",
|
||||||
|
tab4, tab4, "elif name == \"this\":\n",
|
||||||
|
tab4, tab4, tab4, "set(self, name, value)\n",
|
||||||
#endif
|
#endif
|
||||||
|
tab4, tab4, "elif hasattr(self, name) and isinstance(getattr(type(self), name), property):\n",
|
||||||
tab4, tab4, tab4, "set(self, name, value)\n",
|
tab4, tab4, tab4, "set(self, name, value)\n",
|
||||||
tab4, tab4, "else:\n",
|
tab4, tab4, "else:\n",
|
||||||
tab4, tab4, tab4, "raise AttributeError(\"You cannot add attributes to %s\" % self)\n", tab4, "return set_attr\n\n\n", NIL);
|
tab4, tab4, tab4, "raise AttributeError(\"You cannot add instance attributes to %s\" % self)\n",
|
||||||
|
tab4, "return set_instance_attr\n\n", NIL);
|
||||||
|
|
||||||
|
Printv(f_shadow, "\n", "def _swig_setattr_nondynamic_class_variable(set):\n",
|
||||||
|
tab4, "def set_class_attr(cls, name, value):\n",
|
||||||
|
tab4, tab4, "if hasattr(cls, name) and not isinstance(getattr(cls, name), property):\n",
|
||||||
|
tab4, tab4, tab4, "set(cls, name, value)\n",
|
||||||
|
tab4, tab4, "else:\n",
|
||||||
|
tab4, tab4, tab4, "raise AttributeError(\"You cannot add class attributes to %s\" % cls)\n",
|
||||||
|
tab4, "return set_class_attr\n\n", NIL);
|
||||||
|
|
||||||
|
Printv(f_shadow, "\n", NIL);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (directorsEnabled()) {
|
if (directorsEnabled()) {
|
||||||
|
|
@ -4535,8 +4552,8 @@ public:
|
||||||
/* Add static attribute */
|
/* Add static attribute */
|
||||||
if (GetFlag(n, "feature:python:nondynamic")) {
|
if (GetFlag(n, "feature:python:nondynamic")) {
|
||||||
Printv(f_shadow_file,
|
Printv(f_shadow_file,
|
||||||
tab4, "__setattr__ = _swig_setattr_nondynamic_method(object.__setattr__)\n",
|
tab4, "__setattr__ = _swig_setattr_nondynamic_instance_variable(object.__setattr__)\n",
|
||||||
tab4, "class __metaclass__(type):\n", tab4, tab4, "__setattr__ = _swig_setattr_nondynamic_method(type.__setattr__)\n", NIL);
|
tab4, "class __metaclass__(type):\n", tab4, tab4, "__setattr__ = _swig_setattr_nondynamic_class_variable(type.__setattr__)\n", NIL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue