Hi,

I tried to support building SWIG 4 on Python 3.x, and post patch.

Since SWIG 4, -classic and -modern options have been dropped. As the result,
SWIG generates new-style classes which are using property() instead of
__swig_[gs]etmethods__.

In attached patch, SWIG would generate new-style classes without
__swig_[gs]etmethods__ when SWIG 3.x is used (-modern option would be used),
in the same as SWIG 4.x.

Verified by check-swig-py with:

 - Python 3.[5678] with SWIG 1.3.40, 2.0.12, 3.0.12 on Ubuntu 16.04 amd64
 - Python 2.7      with SWIG 3.0.12 and 4.0.1       on Ubuntu 16.04 amd64


[[[
Support building SWIG 4 on Python 3.x.

* build/ac-macros/swig.m4 (SVN_FIND_SWIG):
  Allow building with SWIG 4+, and add -modern option when Python 3 and
  SWIG 3.x are detected.

* subversion/bindings/swig/include/proxy.py
  Use _get_instance_attr and _set_instance_attr.

* subversion/bindings/swig/include/proxy.swg
  (_get_instance_attr): New function to get an instance attribute
  without metadata for new-style and old-style classes.
  (_set_instance_attr): New function to set an instance attribute for
  new-style and old-style classes.

]]]


--
Jun Omae <[email protected]> (大前 潤)
diff --git a/build/ac-macros/swig.m4 b/build/ac-macros/swig.m4
index 6c1f97429de..bc2599038f2 100644
--- a/build/ac-macros/swig.m4
+++ b/build/ac-macros/swig.m4
@@ -158,14 +158,17 @@ AC_DEFUN(SVN_FIND_SWIG,
           ])
 
           if test "$ac_cv_python_is_py3" = "yes"; then
-            if test "$SWIG_VERSION" -ge "300010" -a "$SWIG_VERSION" -lt 
"400000"; then
-              SWIG_PY_OPTS="-python -py3"
+            if test "$SWIG_VERSION" -ge "300010"; then
               dnl SWIG Python bindings successfully configured, clear the 
error message dnl
               SWIG_PY_ERRMSG=""
             else
-              SWIG_PY_OPTS="-python -py3 -nofastunpack"
               SWIG_PY_ERRMSG="SWIG version is not suitable"
-              AC_MSG_WARN([Subversion Python bindings for Python 3 require 
3.0.10 <= SWIG < 4.0.0])
+              AC_MSG_WARN([Subversion Python bindings for Python 3 require 
SWIG 3.0.10 or newer])
+            fi
+            if test "$SWIG_VERSION" -lt "400000"; then
+              SWIG_PY_OPTS="-python -py3 -nofastunpack -modern"
+            else
+              SWIG_PY_OPTS="-python -py3 -nofastunpack"
             fi
           else
             if test "$SWIG_VERSION" -lt "400000"; then
diff --git a/subversion/bindings/swig/include/proxy.py 
b/subversion/bindings/swig/include/proxy.py
index f97b7234a24..73ff5ffdad8 100644
--- a/subversion/bindings/swig/include/proxy.py
+++ b/subversion/bindings/swig/include/proxy.py
@@ -25,13 +25,6 @@ def _retrieve_swig_value(self, name, value):
 
     return value
 
-  # SWIG classes generated with -classic do not define this variable,
-  # so set it to 0 when it doesn't exist
-  try:
-    _newclass
-  except NameError:
-    _newclass = 0
-
   # Attribute access must be intercepted to ensure that objects coming from
   # read attribute access match those that are set with write attribute access.
   # Specifically the metadata, such as the associated apr_pool object, should
@@ -58,13 +51,7 @@ def __getattribute__(self, name):
 
       object.__getattribute__(self, 'assert_valid')()
 
-      try:
-        value = object.__getattribute__(self, name)
-      except AttributeError:
-        value = _swig_getattr(self,
-                              object.__getattribute__(self, '__class__'),
-                              name)
-
+      value = _get_instance_attr(self, name)
       fn = object.__getattribute__(self, '_retrieve_swig_value')
       return fn(name, value)
   else:
@@ -85,4 +72,4 @@ def __setattr__(self, name, value):
     # SWIG-land
     self.__dict__.setdefault("_members",{})[name] = value
 
-    return _swig_setattr(self, self.__class__, name, value)
+    return _set_instance_attr(self, name, value)
diff --git a/subversion/bindings/swig/include/proxy.swg 
b/subversion/bindings/swig/include/proxy.swg
index bc929131365..ac67d434ca8 100644
--- a/subversion/bindings/swig/include/proxy.swg
+++ b/subversion/bindings/swig/include/proxy.swg
@@ -64,7 +64,58 @@
         pass
       else:
         fn()
+
 %}
+#if defined(SWIGPYTHON_PY3)
+#if SWIG_VERSION >= 0x040000
+%pythoncode %{
+  # -classic and -modern options have been dropped and this variable
+  # is not generated since SWIG 4
+  _newclass = 1
+  _get_instance_attr = object.__getattribute__
+  _set_instance_attr = 
_swig_setattr_nondynamic_instance_variable(object.__setattr__)
+
+%}
+#else
+%pythoncode %{
+  # SWIG classes generated with -modern do not define this variable
+  try:
+    _newclass
+  except NameError:
+    _newclass = 1
+  else:
+    raise RuntimeError("Require -modern option, but _newclass is defined")
+
+  _get_instance_attr = object.__getattribute__
+  _set_instance_attr = _swig_setattr_nondynamic_method(object.__setattr__)
+
+%}
+#endif
+#else
+%pythoncode %{
+  # SWIG classes generated with -classic do not define this variable,
+  # so set it to 0 when it doesn't exist
+  try:
+    _newclass
+  except NameError:
+    _newclass = 0
+
+  if _newclass:
+    def _get_instance_attr(self, name):
+      try:
+        return object.__getattribute__(self, name)
+      except AttributeError:
+        return _swig_getattr(self, object.__getattribute__(self, '__class__'),
+                             name)
+  else:
+    def _get_instance_attr(self, name):
+      return _swig_getattr(self, self.__class__, name)
+
+  def _set_instance_attr(self, name, value):
+    return _swig_setattr(self, self.__class__, name, value)
+
+%}
+#endif
 
 /* Default code for all wrapped proxy classes in Python.
  * Inline the code from a separate file to avoid issues with

Reply via email to