From 3d8ddfc442f1f73bc2c567aaa972680d14fea0df Mon Sep 17 00:00:00 2001 From: Haoyu Bai Date: Thu, 11 Sep 2008 17:18:07 +0000 Subject: Merged the Python 3.0 support branch. The merging progress is not so smooth, so hope this commit won't make anything broken. This is the (incomplemete) log produced by svnmerge.py: Merged revisions 10405-10409,10420-10422,10426,10438,10445,10451,10454-10465,10467,10473-10475,10485,10488-10489,10493-10495,10497,10509-10510,10513-10514,10517,10520,10525,10528-10529,10533-10535,10554-10557,10570,10573,10593,10614,10666-10669,10673,10678,10687,10690,10704-10706,10731,10744,10750-10752,10755,10759,10770,10775-10776,10813,10819 via svnmerge from https://swig.svn.sourceforge.net/svnroot/swig/branches/gsoc2008-bhy git-svn-id: https://swig.svn.sourceforge.net/svnroot/swig/trunk@10834 626c5289-ae23-0410-ae9c-e8d60b6d4f22 --- Doc/Manual/Python.html | 253 ++++++++++- Examples/GIFPlot/Python/full/Makefile | 3 +- Examples/GIFPlot/Python/shadow/Makefile | 3 +- Examples/GIFPlot/Python/simple/Makefile | 3 +- Examples/Makefile.in | 60 ++- Examples/python/callback/Makefile | 1 + Examples/python/class/Makefile | 1 + Examples/python/constants/Makefile | 1 + Examples/python/contract/Makefile | 1 + Examples/python/docstrings/Makefile | 1 + Examples/python/enum/Makefile | 1 + Examples/python/exception/Makefile | 1 + Examples/python/exceptproxy/Makefile | 1 + Examples/python/extend/Makefile | 1 + Examples/python/funcptr/Makefile | 1 + Examples/python/funcptr2/Makefile | 1 + Examples/python/functor/Makefile | 1 + Examples/python/import/Makefile | 1 + Examples/python/import_template/Makefile | 1 + Examples/python/libffi/Makefile | 1 + Examples/python/multimap/Makefile | 1 + Examples/python/multimap/example.i | 32 +- Examples/python/operator/Makefile | 1 + Examples/python/pointer/Makefile | 1 + Examples/python/reference/Makefile | 1 + Examples/python/simple/Makefile | 1 + Examples/python/smartptr/Makefile | 1 + Examples/python/std_map/Makefile | 1 + Examples/python/std_vector/Makefile | 1 + Examples/python/swigrun/Makefile | 1 + Examples/python/template/Makefile | 1 + Examples/python/varargs/Makefile | 1 + Examples/python/variables/Makefile | 1 + Examples/python/weave/Makefile | 1 + Examples/test-suite/common.mk | 1 + Examples/test-suite/li_cstring.i | 8 +- Examples/test-suite/li_cwstring.i | 8 +- Examples/test-suite/name_warnings.i | 3 +- Examples/test-suite/namespace_typemap.i | 2 +- Examples/test-suite/operbool.i | 10 + Examples/test-suite/python/Makefile.in | 67 ++- Examples/test-suite/python/README | 6 +- Examples/test-suite/python/abstractbase.i | 18 + Examples/test-suite/python/abstractbase_runme3.py | 8 + Examples/test-suite/python/cpp_namespace_runme.py | 20 +- .../test-suite/python/director_classic_runme.py | 68 +-- .../test-suite/python/director_exception_runme.py | 1 - Examples/test-suite/python/file_test_runme.py | 3 +- Examples/test-suite/python/hugemod.pl | 8 +- Examples/test-suite/python/operbool_runme.py | 4 + Examples/test-suite/python/pybuf.i | 34 ++ Examples/test-suite/python/pybuf_benchmark.i | 31 ++ .../test-suite/python/pybuf_benchmark_runme.py | 16 + .../test-suite/python/pybuf_benchmark_runme3.py | 16 + Examples/test-suite/python/pybuf_runme3.py | 15 + .../python/template_typedef_cplx2_runme.py | 13 +- .../python/template_typedef_cplx_runme.py | 13 +- Lib/python/file.i | 4 +- Lib/python/pyabc.i | 10 + Lib/python/pyapi.swg | 14 + Lib/python/pybuffer.i | 107 +++++ Lib/python/pycontainer.swg | 61 +++ Lib/python/pyerrors.swg | 6 +- Lib/python/pyhead.swg | 44 ++ Lib/python/pyinit.swg | 68 ++- Lib/python/pyiterators.swg | 8 + Lib/python/pyopers.swg | 6 + Lib/python/pyrun.swg | 113 ++++- Lib/python/pystrings.swg | 20 +- Lib/python/pywstrings.swg | 2 + Lib/python/std_map.i | 4 + Source/CParse/cscanner.c | 18 +- Source/CParse/parser.y | 8 + Source/Modules/python.cxx | 498 ++++++++++++++++----- configure.in | 107 ++++- 75 files changed, 1605 insertions(+), 248 deletions(-) create mode 100644 Examples/test-suite/operbool.i create mode 100644 Examples/test-suite/python/abstractbase.i create mode 100644 Examples/test-suite/python/abstractbase_runme3.py create mode 100644 Examples/test-suite/python/operbool_runme.py create mode 100644 Examples/test-suite/python/pybuf.i create mode 100644 Examples/test-suite/python/pybuf_benchmark.i create mode 100644 Examples/test-suite/python/pybuf_benchmark_runme.py create mode 100644 Examples/test-suite/python/pybuf_benchmark_runme3.py create mode 100644 Examples/test-suite/python/pybuf_runme3.py create mode 100644 Lib/python/pyabc.i create mode 100644 Lib/python/pybuffer.i diff --git a/Doc/Manual/Python.html b/Doc/Manual/Python.html index 62b72fabf..c0b71b52d 100644 --- a/Doc/Manual/Python.html +++ b/Doc/Manual/Python.html @@ -46,7 +46,7 @@
  • Memory management
  • Python 2.2 and classic classes -
  • Cross language polymorphism +
  • Cross language polymorphism
  • Python Packages +
  • Python 3 Support + @@ -113,9 +119,9 @@

    This chapter describes SWIG's support of Python. SWIG is compatible -with most recent Python versions including Python 2.2 as well as older -versions dating back to Python 1.5.2. For the best results, consider using Python -2.0 or newer. +with most recent Python versions including Python 3.0 and Python 2.6, +as well as older versions dating back to Python 2.0. For the best results, +consider using Python 2.3 or newer.

    @@ -2544,7 +2550,7 @@ class itself. In Python-2.1 and earlier, they have to be accessed as a global function or through an instance (see the earlier section).

    -

    30.5 Cross language polymorphism

    +

    30.5 Cross language polymorphism

    @@ -4929,7 +4935,7 @@ with more than one line.

    Using the package option of the %module directive allows you to specify what Python package that the module will be -living in when installed. +living in when installed.

    @@ -4950,6 +4956,241 @@ and also in base class declarations, etc. if the package name is different than its own.

    +

    30.12 Python 3 Support

    + + +

    +SWIG is able to support Python 3.0. The wrapper code generated by +SWIG can be compiled with both Python 2.x or 3.0. Further more, by +passing the -py3 command line option to SWIG, wrapper code +with some Python 3 specific features can be generated (see below +subsections for details of these features). The -py3 option also +disables some incompatible features for Python 3, such as +-classic. + +

    +There is a list of known-to-be-broken features in Python 3: +

    +
      +
    • No more support for FILE* typemaps, because PyFile_AsFile has been dropped + in Python 3.
    • +
    • The -apply command line option is removed and generating + code using apply() is no longer supported.
    • +
    + +

    +The following are Python 3.0 new features that are currently supported by +SWIG. +

    + +

    30.12.1 Function annotation

    + + +

    +The -py3 option will enable function annotation support. When used +SWIG is able to generate proxy method definitions like +this: +

    + +
    +  def foo(self, bar : "int" = 0) -> "void" : ...
    +
    + +

    +For details of usage of function annotation, see PEP 3107. +

    + +

    30.12.2 Buffer interface

    + + +

    +Buffer protocols were revised in Python 3. SWIG also gains a series of +new typemaps to support buffer interfaces. These typemap macros are +defined in pybuffer.i, which must be included in order to use them. +By using these typemaps, your wrapped function will be able to +accept any Python object that exposes a suitable buffer interface. +

    + +

    +For example, the get_path() function puts the path string +into the memory pointed to by its argument: +

    + +
    +void get_path(char *s);
    +
    + +

    +Then you can write a typemap like this: (the following example is +applied to both Python 3.0 and 2.6, since the bytearray type +is backported to 2.6. +

    + + +
    +%include <pybuffer.i>
    +%pybuffer_mutable_string(char *str);
    +void get_path(char *s);
    +
    + +

    +And then on the Python side the wrapped get_path could be used in this +way: +

    + +
    +>>> p = bytearray(10)
    +>>> get_path(p)
    +>>> print(p)
    +bytearray(b'/Foo/Bar/\x00')
    +
    + +

    +The macros defined in pybuffer.i are similar to those in +cstring.i: +

    + +

    +%pybuffer_mutable_binary(parm, size_parm) +

    + +
    + +

    +The macro can be used to generate a typemap which maps a buffer of an +object to a pointer provided by parm and a size argument +provided by size_parm. For example: +

    + +
    +%pybuffer_mutable_binary(char *str, size_t size);
    +...
    +int snprintf(char *str, size_t size, const char *format, ...);
    +
    + +

    +In Python: +

    + +
    +>>> buf = bytearray(6)
    +>>> snprintf(buf, "Hello world!")
    +>>> print(buf)
    +bytearray(b'Hello\x00')
    +>>> 
    +
    + +
    + +

    +%pybuffer_mutable_string(parm) +

    + +
    + +

    +This typemap macro requires the buffer to be a zero terminated string, +and maps the pointer of the buffer to parm. For example: +

    + +
    +%pybuffer_mutable_string(char *str);
    +...
    +size_t make_upper(char *str);
    +
    + +

    +In Python: +

    + +
    +>>> buf = bytearray(b'foo\x00')
    +>>> make_upper(buf)
    +>>> print(buf)
    +bytearray(b'FOO\x00')
    +>>>
    +
    + +

    +Both %pybuffer_mutable_binary and %pybuffer_mutable_string +require the provided buffer to be mutable, eg. they can accept a +bytearray type but can't accept an immutable byte +type. +

    + +
    + +

    +%pybuffer_binary(parm, size_parm) +

    + +
    + +

    +This macro maps an object's buffer to a pointer parm and a +size size_parm. It is similar to +%pybuffer_mutable_binary, except the +%pybuffer_binary an accept both mutable and immutable +buffers. As a result, the wrapped function should not modify the buffer. +

    + +
    + +

    +%pybuffer_string(parm) +

    + +
    + +

    +This macro maps an object's buffer as a string pointer parm. +It is similar to %pybuffer_mutable_string but the buffer +could be both mutable and immutable. And your function should not +modify the buffer. +

    + +
    + + +

    30.12.3 Abstract base classes

    + + +

    +By including pyabc.i and using the -py3 command +line option when calling SWIG, the proxy classes of the STL containers +will automatically gain an appropriate abstract base class. For +example, the following SWIG interface: +

    + +
    +%include <pyabc.i>
    +%include <std_map.i>
    +%include <std_list.i>
    +
    +namespace std {
    +  %template(Mapii) map<int, int>;
    +  %template(IntList) list<int>;
    +}
    +
    + +

    +will generate a Python proxy class Mapii inheriting from +collections.MutableMap and a proxy class IntList +inheriting from collections.MutableSequence. +

    + +

    +pyabc.i also provides a macro %pythonabc that could be +used to define an abstract base class for your own C++ class: +

    + +
    +%pythonabc(MySet, collections.MutableSet);
    +
    + +

    +For details of abstract base class, please see PEP 3119. +

    diff --git a/Examples/GIFPlot/Python/full/Makefile b/Examples/GIFPlot/Python/full/Makefile index ae927b72b..83a7c864b 100644 --- a/Examples/GIFPlot/Python/full/Makefile +++ b/Examples/GIFPlot/Python/full/Makefile @@ -1,5 +1,5 @@ TOP = ../../.. -SWIG = $(TOP)/../swig +SWIG = $(TOP)/../preinst-swig SWIGOPT = -I../../Include SRCS = TARGET = gifplot @@ -23,3 +23,4 @@ clean:: rm -f *.gif check: all + $(MAKE) -f $(TOP)/Makefile python_run diff --git a/Examples/GIFPlot/Python/shadow/Makefile b/Examples/GIFPlot/Python/shadow/Makefile index 1f5014895..73fca9673 100644 --- a/Examples/GIFPlot/Python/shadow/Makefile +++ b/Examples/GIFPlot/Python/shadow/Makefile @@ -1,5 +1,5 @@ TOP = ../../.. -SWIG = $(TOP)/../swig +SWIG = $(TOP)/../preinst-swig SWIGOPT = -I../../Interface SRCS = TARGET = gifplot @@ -23,3 +23,4 @@ clean:: rm -f *.gif check: all + $(MAKE) -f $(TOP)/Makefile python_run diff --git a/Examples/GIFPlot/Python/simple/Makefile b/Examples/GIFPlot/Python/simple/Makefile index 5eb0344e8..9fc9a6c72 100644 --- a/Examples/GIFPlot/Python/simple/Makefile +++ b/Examples/GIFPlot/Python/simple/Makefile @@ -1,5 +1,5 @@ TOP = ../../.. -SWIG = $(TOP)/../swig +SWIG = $(TOP)/../preinst-swig SWIGOPT = SRCS = TARGET = simple @@ -23,3 +23,4 @@ clean:: rm -f *.gif check: all + $(MAKE) -f $(TOP)/Makefile python_run diff --git a/Examples/Makefile.in b/Examples/Makefile.in index 555aa3e92..f85075906 100644 --- a/Examples/Makefile.in +++ b/Examples/Makefile.in @@ -223,19 +223,39 @@ perl5_clean: ################################################################## # Make sure these locate your Python installation -PYTHON_INCLUDE= $(DEFS) @PYINCLUDE@ -PYTHON_LIB = @PYLIB@ - -# Extra Python specific dynamic linking options -PYTHON_DLNK = @PYTHONDYNAMICLINKING@ +ifeq (,$(PY3)) + PYTHON_INCLUDE= $(DEFS) @PYINCLUDE@ + PYTHON_LIB = @PYLIB@ + PYTHON = @PYTHON@ +else + PYTHON_INCLUDE= $(DEFS) @PY3INCLUDE@ + PYTHON_LIB = @PY3LIB@ + PYTHON = @PYTHON3@ +endif + +# Extra Python specific linking options +ifeq (,$(PY3)) + PYTHON_DLNK = @PYTHONDYNAMICLINKING@ + PYTHON_LINK = @PYLINK@ +else + PYTHON_DLNK = @PYTHON3DYNAMICLINKING@ + PYTHON_LINK = @PY3LINK@ +endif PYTHON_SO = @PYTHON_SO@ +# SWIG option for Python +ifeq (,$(PY3)) + SWIGPYTHON = $(SWIG) -python +else + SWIGPYTHON = $(SWIG) -python -py3 +endif + # ---------------------------------------------------------------- # Build a C dynamically loadable module # ---------------------------------------------------------------- python: $(SRCS) - $(SWIG) -python $(SWIGOPT) $(INTERFACE) + $(SWIGPYTHON) $(SWIGOPT) $(INTERFACE) $(CC) -c $(CCSHARED) $(CFLAGS) $(ISRCS) $(SRCS) $(INCLUDES) $(PYTHON_INCLUDE) $(LDSHARED) $(CFLAGS) $(OBJS) $(IOBJS) $(PYTHON_DLNK) $(LIBS) -o $(LIBPREFIX)_$(TARGET)$(PYTHON_SO) @@ -244,7 +264,7 @@ python: $(SRCS) # ----------------------------------------------------------------- python_cpp: $(SRCS) - $(SWIG) -c++ -python $(SWIGOPT) $(INTERFACE) + $(SWIGPYTHON) -c++ $(SWIGOPT) $(INTERFACE) $(CXX) -c $(CCSHARED) $(CFLAGS) $(ICXXSRCS) $(SRCS) $(CXXSRCS) $(INCLUDES) $(PYTHON_INCLUDE) $(CXXSHARED) $(CFLAGS) $(OBJS) $(IOBJS) $(PYTHON_DLNK) $(LIBS) $(CPP_DLLIBS) -o $(LIBPREFIX)_$(TARGET)$(PYTHON_SO) @@ -257,18 +277,37 @@ python_cpp: $(SRCS) #TKINTER = -L/usr/X11R6.3/lib -L/usr/local/compat/lib -ltk4.0 -ltcl7.4 -lX11 TKINTER = -PYTHON_LIBOPTS = @PYLINK@ @LIBS@ $(TKINTER) $(SYSLIBS) +PYTHON_LIBOPTS = $(PYTHON_LINK) @LIBS@ $(TKINTER) $(SYSLIBS) python_static: $(SRCS) - $(SWIG) -python -lembed.i $(SWIGOPT) $(INTERFACE) + $(SWIGPYTHON) -lembed.i $(SWIGOPT) $(INTERFACE) $(CC) $(CFLAGS) @LINKFORSHARED@ $(ISRCS) $(SRCS) $(INCLUDES) \ $(PYTHON_INCLUDE) $(LIBS) -L$(PYTHON_LIB) $(PYTHON_LIBOPTS) -o $(TARGET) python_static_cpp: $(SRCS) - $(SWIG) -c++ -python -lembed.i $(SWIGOPT) $(INTERFACE) + $(SWIGPYTHON) -c++ -lembed.i $(SWIGOPT) $(INTERFACE) $(CXX) $(CFLAGS) $(ICXXSRCS) $(SRCS) $(CXXSRCS) $(INCLUDES) \ $(PYTHON_INCLUDE) $(LIBS) -L$(PYTHON_LIB) $(PYTHON_LIBOPTS) -o $(TARGET) +# ----------------------------------------------------------------- +# Running a Python example +# ----------------------------------------------------------------- + +ifeq (,$(PY3)) + SCRIPT = runme.py +else + SCRIPT = runme3.py +endif + +PY2TO3 = 2to3 `2to3 -l | grep -v -E "Available|import$$" | awk '{print "-f "$$0}'` + +python_run: $(SCRIPT) + env LD_LIBRARY_PATH=.:$$LD_LIBRARY_PATH PYTHONPATH=$(srcdir):$$PYTHONPATH $(PYTHON) $(SCRIPT) >/dev/null + +runme3.py: runme.py + cp $< $@ + $(PY2TO3) -w $@ >/dev/null 2>&1 + # ----------------------------------------------------------------- # Cleaning the python examples # ----------------------------------------------------------------- @@ -278,6 +317,7 @@ python_clean: rm -f core @EXTRA_CLEAN@ rm -f *.@OBJEXT@ *@SO@ *@PYTHON_SO@ + ################################################################## ##### OCTAVE ###### ################################################################## diff --git a/Examples/python/callback/Makefile b/Examples/python/callback/Makefile index ad36d7d7e..a29276e58 100644 --- a/Examples/python/callback/Makefile +++ b/Examples/python/callback/Makefile @@ -19,3 +19,4 @@ clean:: rm -f $(TARGET).py check: all + $(MAKE) -f $(TOP)/Makefile python_run diff --git a/Examples/python/class/Makefile b/Examples/python/class/Makefile index f331b8203..74625b992 100644 --- a/Examples/python/class/Makefile +++ b/Examples/python/class/Makefile @@ -18,3 +18,4 @@ clean:: rm -f $(TARGET).py check: all + $(MAKE) -f $(TOP)/Makefile python_run diff --git a/Examples/python/constants/Makefile b/Examples/python/constants/Makefile index 01d0f943a..1420b4e0b 100644 --- a/Examples/python/constants/Makefile +++ b/Examples/python/constants/Makefile @@ -17,3 +17,4 @@ clean:: rm -f $(TARGET).py check: all + $(MAKE) -f $(TOP)/Makefile python_run diff --git a/Examples/python/contract/Makefile b/Examples/python/contract/Makefile index c7b476995..77fe94b1a 100644 --- a/Examples/python/contract/Makefile +++ b/Examples/python/contract/Makefile @@ -17,3 +17,4 @@ clean:: rm -f $(TARGET).py check: all + $(MAKE) -f $(TOP)/Makefile python_run diff --git a/Examples/python/docstrings/Makefile b/Examples/python/docstrings/Makefile index 74ab112a1..f25450cac 100644 --- a/Examples/python/docstrings/Makefile +++ b/Examples/python/docstrings/Makefile @@ -21,3 +21,4 @@ clean:: rm -f $(TARGET).py check: all + $(MAKE) -f $(TOP)/Makefile python_run diff --git a/Examples/python/enum/Makefile b/Examples/python/enum/Makefile index f331b8203..74625b992 100644 --- a/Examples/python/enum/Makefile +++ b/Examples/python/enum/Makefile @@ -18,3 +18,4 @@ clean:: rm -f $(TARGET).py check: all + $(MAKE) -f $(TOP)/Makefile python_run diff --git a/Examples/python/exception/Makefile b/Examples/python/exception/Makefile index 17c4f30b7..7dbdde944 100644 --- a/Examples/python/exception/Makefile +++ b/Examples/python/exception/Makefile @@ -18,3 +18,4 @@ clean:: rm -f $(TARGET).py check: all + $(MAKE) -f $(TOP)/Makefile python_run diff --git a/Examples/python/exceptproxy/Makefile b/Examples/python/exceptproxy/Makefile index a4f334311..ba5c79827 100644 --- a/Examples/python/exceptproxy/Makefile +++ b/Examples/python/exceptproxy/Makefile @@ -19,3 +19,4 @@ clean:: rm -f $(TARGET).py check: all + $(MAKE) -f $(TOP)/Makefile python_run diff --git a/Examples/python/extend/Makefile b/Examples/python/extend/Makefile index ad36d7d7e..a29276e58 100644 --- a/Examples/python/extend/Makefile +++ b/Examples/python/extend/Makefile @@ -19,3 +19,4 @@ clean:: rm -f $(TARGET).py check: all + $(MAKE) -f $(TOP)/Makefile python_run diff --git a/Examples/python/funcptr/Makefile b/Examples/python/funcptr/Makefile index 4a1e1bb71..0f4a1e077 100644 --- a/Examples/python/funcptr/Makefile +++ b/Examples/python/funcptr/Makefile @@ -17,3 +17,4 @@ clean:: rm -f $(TARGET).py check: all + $(MAKE) -f $(TOP)/Makefile python_run diff --git a/Examples/python/funcptr2/Makefile b/Examples/python/funcptr2/Makefile index 4a1e1bb71..0f4a1e077 100644 --- a/Examples/python/funcptr2/Makefile +++ b/Examples/python/funcptr2/Makefile @@ -17,3 +17,4 @@ clean:: rm -f $(TARGET).py check: all + $(MAKE) -f $(TOP)/Makefile python_run diff --git a/Examples/python/functor/Makefile b/Examples/python/functor/Makefile index c45536529..fe389757a 100644 --- a/Examples/python/functor/Makefile +++ b/Examples/python/functor/Makefile @@ -19,3 +19,4 @@ clean:: rm -f $(TARGET).py check: all + $(MAKE) -f $(TOP)/Makefile python_run diff --git a/Examples/python/import/Makefile b/Examples/python/import/Makefile index e00e81864..74d4f88cf 100644 --- a/Examples/python/import/Makefile +++ b/Examples/python/import/Makefile @@ -19,3 +19,4 @@ clean:: @rm -f foo.py bar.py spam.py base.py check: all + $(MAKE) -f $(TOP)/Makefile python_run diff --git a/Examples/python/import_template/Makefile b/Examples/python/import_template/Makefile index fa49f3145..ee47e994d 100644 --- a/Examples/python/import_template/Makefile +++ b/Examples/python/import_template/Makefile @@ -19,3 +19,4 @@ clean:: @rm -f foo.py bar.py spam.py base.py check: all + $(MAKE) -f $(TOP)/Makefile python_run diff --git a/Examples/python/libffi/Makefile b/Examples/python/libffi/Makefile index 8c7edfa65..fafb7de09 100644 --- a/Examples/python/libffi/Makefile +++ b/Examples/python/libffi/Makefile @@ -17,3 +17,4 @@ clean:: rm -f $(TARGET).py check: all + $(MAKE) -f $(TOP)/Makefile python_run diff --git a/Examples/python/multimap/Makefile b/Examples/python/multimap/Makefile index 4a1e1bb71..0f4a1e077 100644 --- a/Examples/python/multimap/Makefile +++ b/Examples/python/multimap/Makefile @@ -17,3 +17,4 @@ clean:: rm -f $(TARGET).py check: all + $(MAKE) -f $(TOP)/Makefile python_run diff --git a/Examples/python/multimap/example.i b/Examples/python/multimap/example.i index 163d7cc8e..3d5a09771 100644 --- a/Examples/python/multimap/example.i +++ b/Examples/python/multimap/example.i @@ -17,6 +17,7 @@ extern int gcd(int x, int y); %typemap(in,fragment="t_output_helper") (int argc, char *argv[]) { int i; + int l; if (!PyList_Check($input)) { SWIG_exception(SWIG_ValueError, "Expecting a list"); } @@ -27,11 +28,21 @@ extern int gcd(int x, int y); $2 = (char **) malloc(($1+1)*sizeof(char *)); for (i = 0; i < $1; i++) { PyObject *s = PyList_GetItem($input,i); - if (!PyString_Check(s)) { +%#if PY_VERSION_HEX >= 0x03000000 + if (!PyUnicode_Check(s)) +%#else + if (!PyString_Check(s)) +%#endif + { free($2); SWIG_exception(SWIG_ValueError, "List items must be strings"); } +%#if PY_VERSION_HEX >= 0x03000000 + $2[i] = PyUnicode_AsStringAndSize(s, &l); +%#else $2[i] = PyString_AsString(s); +%#endif + } $2[i] = 0; } @@ -39,12 +50,21 @@ extern int gcd(int x, int y); extern int gcdmain(int argc, char *argv[]); %typemap(in) (char *bytes, int len) { + +%#if PY_VERSION_HEX >= 0x03000000 + if (!PyUnicode_Check($input)) { + PyErr_SetString(PyExc_ValueError,"Expected a string"); + return NULL; + } + $1 = PyUnicode_AsStringAndSize($input, &$2); +%#else if (!PyString_Check($input)) { PyErr_SetString(PyExc_ValueError,"Expected a string"); return NULL; } $1 = PyString_AsString($input); $2 = PyString_Size($input); +%#endif } extern int count(char *bytes, int len, char c); @@ -56,9 +76,15 @@ extern int count(char *bytes, int len, char c); so that we don't violate it's mutability */ %typemap(in) (char *str, int len) { +%#if PY_VERSION_HEX >= 0x03000000 + $2 = PyUnicode_GetSize($input); + $1 = (char *) malloc($2+1); + memmove($1,PyUnicode_AsString($input),$2); +%#else $2 = PyString_Size($input); $1 = (char *) malloc($2+1); memmove($1,PyString_AsString($input),$2); +%#endif } /* Return the mutated string as a new object. The t_output_helper @@ -67,7 +93,11 @@ extern int count(char *bytes, int len, char c); %typemap(argout) (char *str, int len) { PyObject *o; +%#if PY_VERSION_HEX >= 0x03000000 + o = PyUnicode_FromStringAndSize($1,$2); +%#else o = PyString_FromStringAndSize($1,$2); +%#endif $result = t_output_helper($result,o); free($1); } diff --git a/Examples/python/operator/Makefile b/Examples/python/operator/Makefile index c45536529..fe389757a 100644 --- a/Examples/python/operator/Makefile +++ b/Examples/python/operator/Makefile @@ -19,3 +19,4 @@ clean:: rm -f $(TARGET).py check: all + $(MAKE) -f $(TOP)/Makefile python_run diff --git a/Examples/python/pointer/Makefile b/Examples/python/pointer/Makefile index 4a1e1bb71..0f4a1e077 100644 --- a/Examples/python/pointer/Makefile +++ b/Examples/python/pointer/Makefile @@ -17,3 +17,4 @@ clean:: rm -f $(TARGET).py check: all + $(MAKE) -f $(TOP)/Makefile python_run diff --git a/Examples/python/reference/Makefile b/Examples/python/reference/Makefile index f331b8203..74625b992 100644 --- a/Examples/python/reference/Makefile +++ b/Examples/python/reference/Makefile @@ -18,3 +18,4 @@ clean:: rm -f $(TARGET).py check: all + $(MAKE) -f $(TOP)/Makefile python_run diff --git a/Examples/python/simple/Makefile b/Examples/python/simple/Makefile index 4a1e1bb71..0f4a1e077 100644 --- a/Examples/python/simple/Makefile +++ b/Examples/python/simple/Makefile @@ -17,3 +17,4 @@ clean:: rm -f $(TARGET).py check: all + $(MAKE) -f $(TOP)/Makefile python_run diff --git a/Examples/python/smartptr/Makefile b/Examples/python/smartptr/Makefile index 58d139643..f73802a6b 100644 --- a/Examples/python/smartptr/Makefile +++ b/Examples/python/smartptr/Makefile @@ -19,3 +19,4 @@ clean:: rm -f $(TARGET).py check: all + $(MAKE) -f $(TOP)/Makefile python_run diff --git a/Examples/python/std_map/Makefile b/Examples/python/std_map/Makefile index 2d4c1b4a3..5d13da764 100644 --- a/Examples/python/std_map/Makefile +++ b/Examples/python/std_map/Makefile @@ -22,3 +22,4 @@ run: python runme.py check: all + $(MAKE) -f $(TOP)/Makefile python_run diff --git a/Examples/python/std_vector/Makefile b/Examples/python/std_vector/Makefile index a4f334311..ba5c79827 100644 --- a/Examples/python/std_vector/Makefile +++ b/Examples/python/std_vector/Makefile @@ -19,3 +19,4 @@ clean:: rm -f $(TARGET).py check: all + $(MAKE) -f $(TOP)/Makefile python_run diff --git a/Examples/python/swigrun/Makefile b/Examples/python/swigrun/Makefile index 53bf701c9..2142be5bb 100644 --- a/Examples/python/swigrun/Makefile +++ b/Examples/python/swigrun/Makefile @@ -22,3 +22,4 @@ clean:: check: all + $(MAKE) -f $(TOP)/Makefile python_run diff --git a/Examples/python/template/Makefile b/Examples/python/template/Makefile index a4f334311..ba5c79827 100644 --- a/Examples/python/template/Makefile +++ b/Examples/python/template/Makefile @@ -19,3 +19,4 @@ clean:: rm -f $(TARGET).py check: all + $(MAKE) -f $(TOP)/Makefile python_run diff --git a/Examples/python/varargs/Makefile b/Examples/python/varargs/Makefile index 01d0f943a..1420b4e0b 100644 --- a/Examples/python/varargs/Makefile +++ b/Examples/python/varargs/Makefile @@ -17,3 +17,4 @@ clean:: rm -f $(TARGET).py check: all + $(MAKE) -f $(TOP)/Makefile python_run diff --git a/Examples/python/variables/Makefile b/Examples/python/variables/Makefile index 4a1e1bb71..0f4a1e077 100644 --- a/Examples/python/variables/Makefile +++ b/Examples/python/variables/Makefile @@ -17,3 +17,4 @@ clean:: rm -f $(TARGET).py check: all + $(MAKE) -f $(TOP)/Makefile python_run diff --git a/Examples/python/weave/Makefile b/Examples/python/weave/Makefile index 822779bd1..88f95c095 100644 --- a/Examples/python/weave/Makefile +++ b/Examples/python/weave/Makefile @@ -19,3 +19,4 @@ clean:: rm -f $(TARGET).py check: all + $(MAKE) -f $(TOP)/Makefile python_run diff --git a/Examples/test-suite/common.mk b/Examples/test-suite/common.mk index 0a3a0858a..57b57c271 100644 --- a/Examples/test-suite/common.mk +++ b/Examples/test-suite/common.mk @@ -237,6 +237,7 @@ CPP_TEST_CASES += \ null_pointer \ operator_overload \ operator_overload_break \ + operbool \ ordering \ overload_copy \ overload_extend \ diff --git a/Examples/test-suite/li_cstring.i b/Examples/test-suite/li_cstring.i index fd92ac7d3..28e8049e8 100644 --- a/Examples/test-suite/li_cstring.i +++ b/Examples/test-suite/li_cstring.i @@ -4,7 +4,7 @@ #ifndef SWIG_CSTRING_UNIMPL -%cstring_input_binary(char *in, int n); +%cstring_input_binary(char *str_in, int n); %cstring_bounded_output(char *out1, 512); %cstring_chunk_output(char *out2, 64); %cstring_bounded_mutable(char *out3, 512); @@ -22,13 +22,13 @@ %inline %{ -int count(char *in, int n, char c) { +int count(char *str_in, int n, char c) { int r = 0; while (n > 0) { - if (*in == c) { + if (*str_in == c) { r++; } - in++; + str_in++; --n; } return r; diff --git a/Examples/test-suite/li_cwstring.i b/Examples/test-suite/li_cwstring.i index dc9a1c4b9..769dcce12 100644 --- a/Examples/test-suite/li_cwstring.i +++ b/Examples/test-suite/li_cwstring.i @@ -4,7 +4,7 @@ #ifndef SWIG_CWSTRING_UNIMPL -%cwstring_input_binary(wchar_t *in, int n); +%cwstring_input_binary(wchar_t *str_in, int n); %cwstring_bounded_output(wchar_t *out1, 512); %cwstring_chunk_output(wchar_t *out2, 64); %cwstring_bounded_mutable(wchar_t *out3, 512); @@ -22,13 +22,13 @@ %inline %{ -int count(wchar_t *in, int n, wchar_t c) { +int count(wchar_t *str_in, int n, wchar_t c) { int r = 0; while (n > 0) { - if (*in == c) { + if (*str_in == c) { r++; } - in++; + str_in++; --n; } return r; diff --git a/Examples/test-suite/name_warnings.i b/Examples/test-suite/name_warnings.i index a9cb35686..527dbcfaa 100644 --- a/Examples/test-suite/name_warnings.i +++ b/Examples/test-suite/name_warnings.i @@ -58,13 +58,12 @@ namespace std %template(max_i) max; - %inline { /* silently rename the parameter names in csharp/java */ #ifdef SWIGR double foo(double inparam, double out) { return 1.0; } #else - double foo(double in, double out) { return 1.0; } + double foo(double abstract, double out) { return 1.0; } #endif double bar(double native, bool boolean) { return 1.0; } } diff --git a/Examples/test-suite/namespace_typemap.i b/Examples/test-suite/namespace_typemap.i index e4e0af905..984b93a6f 100644 --- a/Examples/test-suite/namespace_typemap.i +++ b/Examples/test-suite/namespace_typemap.i @@ -75,7 +75,7 @@ namespace test { class string_class; #ifdef SWIGPYTHON %typemap(in) string_class * { - $1 = new string_class(PyString_AsString($input)); + $1 = new string_class(SWIG_Python_str_AsChar($input)); } %typemap(freearg) string_class * { delete $1; diff --git a/Examples/test-suite/operbool.i b/Examples/test-suite/operbool.i new file mode 100644 index 000000000..d6d7fc706 --- /dev/null +++ b/Examples/test-suite/operbool.i @@ -0,0 +1,10 @@ +%module operbool + +%inline %{ + class Test { + public: + operator bool() { + return false; + } + }; +%} diff --git a/Examples/test-suite/python/Makefile.in b/Examples/test-suite/python/Makefile.in index 7f11cd495..a3a027453 100644 --- a/Examples/test-suite/python/Makefile.in +++ b/Examples/test-suite/python/Makefile.in @@ -2,14 +2,41 @@ # Makefile for python test-suite ####################################################################### +ifeq (,$(PY3)) + PYBIN = @PYTHON@ +else + PYBIN = @PYTHON3@ +endif + LANGUAGE = python -PYTHON = @PYTHON@ -SCRIPTSUFFIX = _runme.py +ifneq (,$(USE_VALGRIND)) + PYTHON = valgrind --leak-check=full --suppressions=pyswig.supp $(PYBIN) +else + PYTHON = $(PYBIN) +endif + +#*_runme.py for Python 2.x, *_runme3.py for Python 3.x +PY2SCRIPTSUFFIX = _runme.py +PY3SCRIPTSUFFIX = _runme3.py + +ifeq (,$(PY3)) + SCRIPTSUFFIX = $(PY2SCRIPTSUFFIX) +else + SCRIPTSUFFIX = $(PY3SCRIPTSUFFIX) +endif + srcdir = @srcdir@ top_srcdir = @top_srcdir@ top_builddir = @top_builddir@ + +#Use the tricky command because we want to disable the "import" fixer, +#but currently 2to3 has no option to let us do it +PY2TO3 = 2to3 `2to3 -l | grep -v -E "Available|import$$" | awk '{print "-f "$$0}'` + + CPP_TEST_CASES += \ + abstractbase \ argcargvtest \ autodoc \ callback \ @@ -77,12 +104,35 @@ VALGRIND_OPT += --suppressions=pythonswig.supp +$(swig_and_compile_multi_cpp) $(run_testcase) + +# Call 2to3 to generate Python 3.x test from the Python 2.x's *_runme.py file +%$(PY3SCRIPTSUFFIX): %$(PY2SCRIPTSUFFIX) + cp $< $@ + $(PY2TO3) -w $@ >/dev/null 2>&1 + + # Runs the testcase. A testcase is only run if -# a file is found which has _runme.py appended after the testcase name. +# a file is found which has _runme.py (or _runme3.py for Python 3) appended after the testcase name. + +run_python = env LD_LIBRARY_PATH=.:$$LD_LIBRARY_PATH PYTHONPATH=$(srcdir):$$PYTHONPATH $(RUNTOOL) $(PYTHON) $(srcdir)/$(SCRIPTPREFIX)$*$(SCRIPTSUFFIX) + +ifeq (,$(PY3)) run_testcase = \ if [ -f $(srcdir)/$(SCRIPTPREFIX)$*$(SCRIPTSUFFIX) ]; then ( \ - env LD_LIBRARY_PATH=.:$$LD_LIBRARY_PATH PYTHONPATH=$(srcdir):$$PYTHONPATH $(RUNTOOL) $(PYTHON) $(srcdir)/$(SCRIPTPREFIX)$*$(SCRIPTSUFFIX);) \ + $(run_python);)\ + fi; +else +py2_runme = $(srcdir)/$(SCRIPTPREFIX)$*$(PY2SCRIPTSUFFIX) +py3_runme = $(srcdir)/$(SCRIPTPREFIX)$*$(PY3SCRIPTSUFFIX) + +run_testcase = \ + if [ -f $(py2_runme) ]; then ( \ + $(MAKE) -f $(srcdir)/Makefile $(py3_runme) && \ + $(run_python);) \ + elif [ -f $(py3_runme)]; then ( \ + $(run_python);) \ fi; +endif # Clean: remove the generated .py file %.clean: @@ -101,14 +151,15 @@ cvsignore: @echo clientdata_prop_b.py @echo imports_a.py @echo imports_b.py - @echo mod_a.py mod_b.py + @echo mod_a.py mod_b.py @echo hugemod.h hugemod_a.i hugemod_b.i hugemod_a.py hugemod_b.py hugemod_runme.py @echo template_typedef_import.py +hugemod_runme = hugemod$(SCRIPTPREFIX) hugemod: - perl hugemod.pl + perl hugemod.pl $(hugemod_runme) $(MAKE) hugemod_a.cpptest $(MAKE) hugemod_b.cpptest - time $(PYTHON) hugemod_runme.py - time $(PYTHON) hugemod_runme.py + sh -c "time $(PYTHON) $(hugemod_runme)" + sh -c "time $(PYTHON) $(hugemod_runme)" diff --git a/Examples/test-suite/python/README b/Examples/test-suite/python/README index b86ec5289..71db759b5 100644 --- a/Examples/test-suite/python/README +++ b/Examples/test-suite/python/README @@ -1,4 +1,8 @@ See ../README for common README file. -Any testcases which have _runme.py appended after the testcase name will be detected and run. +Any testcases which have _runme.py (or _runme3.py for Python 3) appended after the testcase name will be detected and run. +If you intend to write a testcase for both Python 2.x and 3.x, do *not* directly put the _runme3.py in this directory. Just write Python 2.x's _runme.py testcase and it will be automatically converted to Python 3 code during test. + +You can run make with PY3=y to run test case with Python 3.x, eg. + $ make voidtest.cpptest PY3=y diff --git a/Examples/test-suite/python/abstractbase.i b/Examples/test-suite/python/abstractbase.i new file mode 100644 index 000000000..530f21921 --- /dev/null +++ b/Examples/test-suite/python/abstractbase.i @@ -0,0 +1,18 @@ +%module abstractbase +%include +%include +%include +%include +%include +%include +%include + +namespace std +{ + %template(Mapii) map; + %template(Multimapii) multimap; + %template(IntSet) set; + %template(IntMultiset) multiset; + %template(IntVector) vector; + %template(IntList) list; +} diff --git a/Examples/test-suite/python/abstractbase_runme3.py b/Examples/test-suite/python/abstractbase_runme3.py new file mode 100644 index 000000000..13a87ee5e --- /dev/null +++ b/Examples/test-suite/python/abstractbase_runme3.py @@ -0,0 +1,8 @@ +from abstractbase import * +from collections import * +assert issubclass(Mapii, MutableMapping) +assert issubclass(Multimapii, MutableMapping) +assert issubclass(IntSet, MutableSet) +assert issubclass(IntMultiset, MutableSet) +assert issubclass(IntVector, MutableSequence) +assert issubclass(IntList, MutableSequence) diff --git a/Examples/test-suite/python/cpp_namespace_runme.py b/Examples/test-suite/python/cpp_namespace_runme.py index 3108b4f47..a454774f5 100644 --- a/Examples/test-suite/python/cpp_namespace_runme.py +++ b/Examples/test-suite/python/cpp_namespace_runme.py @@ -3,20 +3,20 @@ import cpp_namespace n = cpp_namespace.fact(4) if n != 24: - raise "Bad return value!" + raise RuntimeError("Bad return value!") if cpp_namespace.cvar.Foo != 42: - raise "Bad variable value!" + raise RuntimeError("Bad variable value!") t = cpp_namespace.Test() if t.method() != "Test::method": - raise "Bad method return value!" + raise RuntimeError("Bad method return value!") if cpp_namespace.do_method(t) != "Test::method": - raise "Bad return value!" + raise RuntimeError("Bad return value!") if cpp_namespace.do_method2(t) != "Test::method": - raise "Bad return value!" + raise RuntimeError("Bad return value!") cpp_namespace.weird("hello", 4) @@ -28,18 +28,18 @@ t4 = cpp_namespace.Test4() t5 = cpp_namespace.Test5() if cpp_namespace.foo3(42) != 42: - raise "Bad return value!" + raise RuntimeError("Bad return value!") if cpp_namespace.do_method3(t2,40) != "Test2::method": - raise "Bad return value!" + raise RuntimeError("Bad return value!") if cpp_namespace.do_method3(t3,40) != "Test3::method": - raise "Bad return value!" + raise RuntimeError("Bad return value!") if cpp_namespace.do_method3(t4,40) != "Test4::method": - raise "Bad return value!" + raise RuntimeError("Bad return value!") if cpp_namespace.do_method3(t5,40) != "Test5::method": - raise "Bad return value!" + raise RuntimeError("Bad return value!") diff --git a/Examples/test-suite/python/director_classic_runme.py b/Examples/test-suite/python/director_classic_runme.py index 878905679..7e18a9a61 100644 --- a/Examples/test-suite/python/director_classic_runme.py +++ b/Examples/test-suite/python/director_classic_runme.py @@ -1,56 +1,56 @@ from director_classic import * class TargetLangPerson(Person): - def __init__(self): - Person.__init__(self) - def id(self): - identifier = "TargetLangPerson" - return identifier + def __init__(self): + Person.__init__(self) + def id(self): + identifier = "TargetLangPerson" + return identifier class TargetLangChild(Child): - def __init__(self): - Child.__init__(self) - def id(self): - identifier = "TargetLangChild" - return identifier + def __init__(self): + Child.__init__(self) + def id(self): + identifier = "TargetLangChild" + return identifier class TargetLangGrandChild(GrandChild): - def __init__(self): - GrandChild.__init__(self) - def id(self): - identifier = "TargetLangGrandChild" - return identifier + def __init__(self): + GrandChild.__init__(self) + def id(self): + identifier = "TargetLangGrandChild" + return identifier # Semis - don't override id() in target language class TargetLangSemiPerson(Person): - def __init__(self): - Person.__init__(self) + def __init__(self): + Person.__init__(self) # No id() override class TargetLangSemiChild(Child): - def __init__(self): - Child.__init__(self) + def __init__(self): + Child.__init__(self) # No id() override class TargetLangSemiGrandChild(GrandChild): - def __init__(self): - GrandChild.__init__(self) + def __init__(self): + GrandChild.__init__(self) # No id() override # Orphans - don't override id() in C++ class TargetLangOrphanPerson(OrphanPerson): - def __init__(self): - OrphanPerson.__init__(self) - def id(self): - identifier = "TargetLangOrphanPerson" - return identifier + def __init__(self): + OrphanPerson.__init__(self) + def id(self): + identifier = "TargetLangOrphanPerson" + return identifier class TargetLangOrphanChild(OrphanChild): - def __init__(self): - Child.__init__(self) - def id(self): - identifier = "TargetLangOrphanChild" - return identifier + def __init__(self): + Child.__init__(self) + def id(self): + identifier = "TargetLangOrphanChild" + return identifier def check(person, expected): @@ -61,7 +61,7 @@ def check(person, expected): if (debug): print(ret) if (ret != expected): - raise ("Failed. Received: " + ret + " Expected: " + expected) + raise RuntimeError("Failed. Received: " + str(ret) + " Expected: " + expected) # Polymorphic call from C++ caller = Caller() @@ -70,7 +70,7 @@ def check(person, expected): if (debug): print(ret) if (ret != expected): - raise ("Failed. Received: " + ret + " Expected: " + expected) + raise RuntimeError("Failed. Received: " + str(ret) + " Expected: " + expected) # Polymorphic call of object created in target language and passed to C++ and back again baseclass = caller.baseClass() @@ -78,7 +78,7 @@ def check(person, expected): if (debug): print(ret) if (ret != expected): - raise ("Failed. Received: " + ret + " Expected: " + expected) + raise RuntimeError("Failed. Received: " + str(ret)+ " Expected: " + expected) caller.resetCallback() if (debug): diff --git a/Examples/test-suite/python/director_exception_runme.py b/Examples/test-suite/python/director_exception_runme.py index 28521ffa5..ef7a044f1 100644 --- a/Examples/test-suite/python/director_exception_runme.py +++ b/Examples/test-suite/python/director_exception_runme.py @@ -1,5 +1,4 @@ from director_exception import * -from exceptions import * class MyException(Exception): def __init__(self, a, b): diff --git a/Examples/test-suite/python/file_test_runme.py b/Examples/test-suite/python/file_test_runme.py index 64154c619..de4e2669e 100644 --- a/Examples/test-suite/python/file_test_runme.py +++ b/Examples/test-suite/python/file_test_runme.py @@ -1,7 +1,8 @@ import sys import file_test -file_test.nfile(sys.stdout) +if sys.version_info < (3,0): + file_test.nfile(sys.stdout) cstdout = file_test.GetStdOut() diff --git a/Examples/test-suite/python/hugemod.pl b/Examples/test-suite/python/hugemod.pl index 15c4ce41b..5420926e4 100644 --- a/Examples/test-suite/python/hugemod.pl +++ b/Examples/test-suite/python/hugemod.pl @@ -2,8 +2,12 @@ use strict; +my $modsize = 399; #adjust it so you can have a smaller or bigger hugemod + +my $runme = shift @ARGV; + open HEADER, ">hugemod.h" or die "error"; -open TEST, ">hugemod_runme.py" or die "error"; +open TEST, ">$runme" or die "error"; open I1, ">hugemod_a.i" or die "error"; open I2, ">hugemod_b.i" or die "error"; @@ -21,7 +25,7 @@ print I2 "\%inline \%{\n"; my $i; -for ($i = 0; $i < 6000; $i++) { +for ($i = 0; $i < $modsize; $i++) { my $t = $i * 4; print HEADER "class type$i { public: int a; };\n"; print I2 "class dtype$i : public type$i { public: int b; };\n"; diff --git a/Examples/test-suite/python/operbool_runme.py b/Examples/test-suite/python/operbool_runme.py new file mode 100644 index 000000000..4218b5dd4 --- /dev/null +++ b/Examples/test-suite/python/operbool_runme.py @@ -0,0 +1,4 @@ +#!/usr/bin/env python +import operbool +assert not operbool.Test() + diff --git a/Examples/test-suite/python/pybuf.i b/Examples/test-suite/python/pybuf.i new file mode 100644 index 000000000..207b5b7e9 --- /dev/null +++ b/Examples/test-suite/python/pybuf.i @@ -0,0 +1,34 @@ +%module pybuf +%include + +%pybuffer_mutable_binary(char *buf1, int len); +%pybuffer_mutable_string(char *buf2); +%pybuffer_binary(const char *buf3, int len); +%pybuffer_string(const char *buf4); + +%inline %{ + void func1(char *buf1, int len) + { + int i; + for (i=0; i +%include +%pybuffer_mutable_string(char *str1); +%cstring_mutable(char *str2); + +%inline %{ +void title(char *str) { + int outword = 0; + while(*str) { + if (isalnum(*str)) { + if (outword) { + outword = 1; + *str = toupper(*str); + } + } + else { + outword = 0; + } + str++; + } +} + +void title1(char *str1) { + title(str1); +} +void title2(char *str2) { + title(str2); +} +%} diff --git a/Examples/test-suite/python/pybuf_benchmark_runme.py b/Examples/test-suite/python/pybuf_benchmark_runme.py new file mode 100644 index 000000000..6676a910b --- /dev/null +++ b/Examples/test-suite/python/pybuf_benchmark_runme.py @@ -0,0 +1,16 @@ +import pybuf +import time +k=1000000 +n=7 + +t=time.time() +a = bytearray(b'hello world') +for i in range(k): + pybuf.title1(a) +print "Time used by bytearray:",time.time()-t + +t=time.time() +b = 'hello world' +for i in range(k): + pybuf.title2(b) +print "Time used by string:",time.time()-t diff --git a/Examples/test-suite/python/pybuf_benchmark_runme3.py b/Examples/test-suite/python/pybuf_benchmark_runme3.py new file mode 100644 index 000000000..e412d5993 --- /dev/null +++ b/Examples/test-suite/python/pybuf_benchmark_runme3.py @@ -0,0 +1,16 @@ +import pybuf +import time +k=1000000 +n=7 + +t=time.time() +a = bytearray(b'hello world') +for i in range(k): + pybuf.title1(a) +print("Time used by bytearray:",time.time()-t) + +t=time.time() +b = 'hello world' +for i in range(k): + pybuf.title2(b) +print("Time used by string:",time.time()-t) diff --git a/Examples/test-suite/python/pybuf_runme3.py b/Examples/test-suite/python/pybuf_runme3.py new file mode 100644 index 000000000..462736bf0 --- /dev/null +++ b/Examples/test-suite/python/pybuf_runme3.py @@ -0,0 +1,15 @@ +import pybuf +buf1 = bytearray(10) +buf2 = bytearray(50) + +pybuf.func1(buf1) +assert buf1 == b'a'*10 + +pybuf.func2(buf2) +assert buf2.startswith(b"Hello world!\x00") + +count = pybuf.func3(buf2) +assert count==10 #number of alpha and number in 'Hello world!' + +length = pybuf.func4(buf2) +assert length==12 diff --git a/Examples/test-suite/python/template_typedef_cplx2_runme.py b/Examples/test-suite/python/template_typedef_cplx2_runme.py index 030fe02d8..04c599329 100644 --- a/Examples/test-suite/python/template_typedef_cplx2_runme.py +++ b/Examples/test-suite/python/template_typedef_cplx2_runme.py @@ -1,4 +1,3 @@ -import string from template_typedef_cplx2 import * # @@ -13,7 +12,7 @@ except: raise RuntimeError s = '%s' % d -if string.find(s, 'ArithUnaryFunction') == -1: +if str.find(s, 'ArithUnaryFunction') == -1: print d, "is not an ArithUnaryFunction" raise RuntimeError @@ -25,7 +24,7 @@ except: raise RuntimeError s = '%s' % e -if string.find(s, 'ArithUnaryFunction') == -1: +if str.find(s, 'ArithUnaryFunction') == -1: print e, "is not an ArithUnaryFunction" raise RuntimeError @@ -42,7 +41,7 @@ except: raise RuntimeError s = '%s' % c -if string.find(s, 'ArithUnaryFunction') == -1: +if str.find(s, 'ArithUnaryFunction') == -1: print c, "is not an ArithUnaryFunction" raise RuntimeError @@ -54,7 +53,7 @@ except: raise RuntimeError s = '%s' % f -if string.find(s, 'ArithUnaryFunction') == -1: +if str.find(s, 'ArithUnaryFunction') == -1: print f, "is not an ArithUnaryFunction" raise RuntimeError @@ -70,7 +69,7 @@ except: raise RuntimeError s = '%s' % g -if string.find(s, 'ArithUnaryFunction') == -1: +if str.find(s, 'ArithUnaryFunction') == -1: print g, "is not an ArithUnaryFunction" raise RuntimeError @@ -83,7 +82,7 @@ except: raise RuntimeError s = '%s' % h -if string.find(s, 'ArithUnaryFunction') == -1: +if str.find(s, 'ArithUnaryFunction') == -1: print h, "is not an ArithUnaryFunction" raise RuntimeError diff --git a/Examples/test-suite/python/template_typedef_cplx_runme.py b/Examples/test-suite/python/template_typedef_cplx_runme.py index 99ffcb9aa..2cd9c8348 100644 --- a/Examples/test-suite/python/template_typedef_cplx_runme.py +++ b/Examples/test-suite/python/template_typedef_cplx_runme.py @@ -1,4 +1,3 @@ -import string from template_typedef_cplx import * # @@ -13,7 +12,7 @@ except: raise RuntimeError s = '%s' % d -if string.find(s, 'ArithUnaryFunction') == -1: +if str.find(s, 'ArithUnaryFunction') == -1: print d, "is not an ArithUnaryFunction" raise RuntimeError @@ -25,7 +24,7 @@ except: raise RuntimeError s = '%s' % e -if string.find(s, 'ArithUnaryFunction') == -1: +if str.find(s, 'ArithUnaryFunction') == -1: print e, "is not an ArithUnaryFunction" raise RuntimeError @@ -42,7 +41,7 @@ except: raise RuntimeError s = '%s' % c -if string.find(s, 'ArithUnaryFunction') == -1: +if str.find(s, 'ArithUnaryFunction') == -1: print c, "is not an ArithUnaryFunction" raise RuntimeError @@ -54,7 +53,7 @@ except: raise RuntimeError s = '%s' % f -if string.find(s, 'ArithUnaryFunction') == -1: +if str.find(s, 'ArithUnaryFunction') == -1: print f, "is not an ArithUnaryFunction" raise RuntimeError @@ -70,7 +69,7 @@ except: raise RuntimeError s = '%s' % g -if string.find(s, 'ArithUnaryFunction') == -1: +if str.find(s, 'ArithUnaryFunction') == -1: print g, "is not an ArithUnaryFunction" raise RuntimeError @@ -83,6 +82,6 @@ except: raise RuntimeError s = '%s' % h -if string.find(s, 'ArithUnaryFunction') == -1: +if str.find(s, 'ArithUnaryFunction') == -1: print h, "is not an ArithUnaryFunction" raise RuntimeError diff --git a/Lib/python/file.i b/Lib/python/file.i index c0e7d5ea9..294ab9178 100644 --- a/Lib/python/file.i +++ b/Lib/python/file.i @@ -20,11 +20,13 @@ SWIG_AsValFilePtr(PyObject *obj, FILE **val) { if ((SWIG_ConvertPtr(obj, &vptr, desc, 0)) == SWIG_OK) { if (val) *val = (FILE *)vptr; return SWIG_OK; - } + } +%#if PY_VERSION_HEX < 0x03000000 if (PyFile_Check(obj)) { if (val) *val = PyFile_AsFile(obj); return SWIG_OK; } +%#endif return SWIG_TypeError; } } diff --git a/Lib/python/pyabc.i b/Lib/python/pyabc.i new file mode 100644 index 000000000..3da06b5a9 --- /dev/null +++ b/Lib/python/pyabc.i @@ -0,0 +1,10 @@ +%define %pythonabc(Type, Abc) + %feature("python:abc", #Abc) Type; +%enddef +%pythoncode {import collections}; +%pythonabc(std::vector, collections.MutableSequence); +%pythonabc(std::list, collections.MutableSequence); +%pythonabc(std::map, collections.MutableMapping); +%pythonabc(std::multimap, collections.MutableMapping); +%pythonabc(std::set, collections.MutableSet); +%pythonabc(std::multiset, collections.MutableSet); diff --git a/Lib/python/pyapi.swg b/Lib/python/pyapi.swg index 1d5148dbf..d980f9263 100644 --- a/Lib/python/pyapi.swg +++ b/Lib/python/pyapi.swg @@ -27,6 +27,20 @@ typedef struct swig_const_info { swig_type_info **ptype; } swig_const_info; + +/* ----------------------------------------------------------------------------- + * Wrapper of PyInstanceMethod_New() used in Python 3 + * It is exported to the generated module, used for -fastproxy + * ----------------------------------------------------------------------------- */ +SWIGRUNTIME PyObject* SWIG_PyInstanceMethod_New(PyObject *self, PyObject *func) +{ +#if PY_VERSION_HEX >= 0x03000000 + return PyInstanceMethod_New(func); +#else + return NULL; +#endif +} + #ifdef __cplusplus #if 0 { /* cc-mode */ diff --git a/Lib/python/pybuffer.i b/Lib/python/pybuffer.i new file mode 100644 index 000000000..3dc4c2121 --- /dev/null +++ b/Lib/python/pybuffer.i @@ -0,0 +1,107 @@ +/* Impelementing buffer protocol typemaps */ + +/* %pybuffer_mutable_binary(TYPEMAP, SIZE) + * + * Macro for functions accept mutable buffer pointer with a size. + * This can be used for both input and output. For example: + * + * %pybuffer_mutable_binary(char *buff, int size); + * void foo(char *buff, int size) { + * for(int i=0; i ObjX > ObjB + but ObjA < ObjB + */ + if( PyErr_Occurred() && PyErr_ExceptionMatches(PyExc_TypeError) ) + { + /* Objects can't be compared, this mostly occured in Python 3.0 */ + /* Compare their ptr directly for a workaround */ + res = (v < w); + PyErr_Clear(); + } SWIG_PYTHON_THREAD_END_BLOCK; return res; } @@ -597,6 +608,11 @@ namespace swig return !(self->empty()); } + /* Alias for Python 3 compatibility */ + bool __bool__() const { + return !(self->empty()); + } + size_type __len__() const { return self->size(); } @@ -618,6 +634,14 @@ namespace swig return x; } + /* typemap for slice object support */ + %typemap(in) PySliceObject* { + $1 = (PySliceObject *) $input; + } + %typemap(typecheck,precedence=SWIG_TYPECHECK_POINTER) PySliceObject* { + $1 = PySlice_Check($input); + } + Sequence* __getslice__(difference_type i, difference_type j) throw (std::out_of_range) { return swig::getslice(self, i, j); } @@ -634,6 +658,43 @@ namespace swig void __delitem__(difference_type i) throw (std::out_of_range) { self->erase(swig::getpos(self,i)); } + + + /* Overloaded methods for Python 3 compatibility + * (Also useful in Python 2.x) + */ + Sequence* __getitem__(PySliceObject *slice) throw (std::out_of_range) { + Py_ssize_t i, j, step; + if( !PySlice_Check(slice) ) { + SWIG_Error(SWIG_TypeError, "Slice object expected."); + return NULL; + } + PySlice_GetIndices(slice, self->size(), &i, &j, &step); + return swig::getslice(self, i, j); + } + + void __setitem__(PySliceObject *slice, const Sequence& v) + throw (std::out_of_range, std::invalid_argument) { + Py_ssize_t i, j, step; + if( !PySlice_Check(slice) ) { + SWIG_Error(SWIG_TypeError, "Slice object expected."); + return; + } + PySlice_GetIndices(slice, self->size(), &i, &j, &step); + swig::setslice(self, i, j, v); + } + + void __delitem__(PySliceObject *slice) + throw (std::out_of_range) { + Py_ssize_t i, j, step; + if( !PySlice_Check(slice) ) { + SWIG_Error(SWIG_TypeError, "Slice object expected."); + return; + } + PySlice_GetIndices(slice, self->size(), &i, &j, &step); + swig::delslice(self, i,j); + } + } %enddef diff --git a/Lib/python/pyerrors.swg b/Lib/python/pyerrors.swg index e287e2fc8..01cf53e9b 100644 --- a/Lib/python/pyerrors.swg +++ b/Lib/python/pyerrors.swg @@ -58,12 +58,12 @@ SWIG_Python_AddErrorMsg(const char* mesg) PyObject *old_str = PyObject_Str(value); PyErr_Clear(); Py_XINCREF(type); - PyErr_Format(type, "%s %s", PyString_AsString(old_str), mesg); + + PyErr_Format(type, "%s %s", + SWIG_Python_str_AsChar(old_str), mesg); Py_DECREF(old_str); Py_DECREF(value); } else { PyErr_SetString(PyExc_RuntimeError, mesg); } } - - diff --git a/Lib/python/pyhead.swg b/Lib/python/pyhead.swg index 7839511bc..d73d3d112 100644 --- a/Lib/python/pyhead.swg +++ b/Lib/python/pyhead.swg @@ -1,3 +1,47 @@ +/* Compatibility marcos for Python 3 */ +#if PY_VERSION_HEX >= 0x03000000 + +#define PyClass_Check(obj) PyObject_IsInstance(obj, (PyObject *)&PyType_Type) + +#define PyInt_Check(x) PyLong_Check(x) +#define PyInt_AsLong(x) PyLong_AsLong(x) +#define PyInt_FromLong(x) PyLong_FromLong(x) + +#define PyString_Format(fmt, args) PyUnicode_Format(fmt, args) +#endif + +#ifndef Py_TYPE +# define Py_TYPE(op) ((op)->ob_type) +#endif + +/* SWIG APIs for compatibility of boht Python 2 & 3 */ + +#if PY_VERSION_HEX >= 0x03000000 +# define SWIG_Python_str_FromFormat PyUnicode_FromFormat +#else +# define SWIG_Python_str_FromFormat PyString_FromFormat +#endif + +SWIGINTERN char* +SWIG_Python_str_AsChar(PyObject *str) +{ +#if PY_VERSION_HEX >= 0x03000000 + str = PyUnicode_AsUTF8String(str); + return PyBytes_AsString(str); +#else + return PyString_AsString(str); +#endif +} + +SWIGINTERN PyObject* +SWIG_Python_str_FromChar(const char *c) +{ +#if PY_VERSION_HEX >= 0x03000000 + return PyUnicode_FromString(c); +#else + return PyString_FromString(c); +#endif +} /* Add PyOS_snprintf for old Pythons */ #if PY_VERSION_HEX < 0x02020000 diff --git a/Lib/python/pyinit.swg b/Lib/python/pyinit.swg index e6109b7bd..ab55765ad 100644 --- a/Lib/python/pyinit.swg +++ b/Lib/python/pyinit.swg @@ -33,18 +33,48 @@ typedef struct swig_varlinkobject { SWIGINTERN PyObject * swig_varlink_repr(swig_varlinkobject *SWIGUNUSEDPARM(v)) { +#if PY_VERSION_HEX >= 0x03000000 + return PyUnicode_InternFromString(""); +#else return PyString_FromString(""); +#endif } SWIGINTERN PyObject * swig_varlink_str(swig_varlinkobject *v) { +#if PY_VERSION_HEX >= 0x03000000 + PyObject *str = PyUnicode_InternFromString("("); + PyObject *tail; + PyObject *joined; + swig_globalvar *var; + for (var = v->vars; var; var=var->next) { + tail = PyUnicode_FromString(var->name); + joined = PyUnicode_Concat(str, tail); + Py_DecRef(str); + Py_DecRef(tail); + str = joined; + if (var->next) { + tail = PyUnicode_InternFromString(", "); + joined = PyUnicode_Concat(str, tail); + Py_DecRef(str); + Py_DecRef(tail); + str = joined; + } + } + tail = PyUnicode_InternFromString(")"); + joined = PyUnicode_Concat(str, tail); + Py_DecRef(str); + Py_DecRef(tail); + str = joined; +#else PyObject *str = PyString_FromString("("); - swig_globalvar *var; + swig_globalvar *var; for (var = v->vars; var; var=var->next) { PyString_ConcatAndDel(&str,PyString_FromString(var->name)); if (var->next) PyString_ConcatAndDel(&str,PyString_FromString(", ")); } PyString_ConcatAndDel(&str,PyString_FromString(")")); +#endif return str; } @@ -52,7 +82,7 @@ SWIGINTERN int swig_varlink_print(swig_varlinkobject *v, FILE *fp, int SWIGUNUSEDPARM(flags)) { PyObject *str = swig_varlink_str(v); fprintf(fp,"Swig global variables "); - fprintf(fp,"%s\n", PyString_AsString(str)); + fprintf(fp,"%s\n", SWIG_Python_str_AsChar(str)); Py_DECREF(str); return 0; } @@ -110,8 +140,13 @@ swig_varlink_type(void) { if (!type_init) { const PyTypeObject tmp = { + /* PyObject header changed in Python 3 */ +#if PY_VERSION_HEX >= 0x03000000 + PyVarObject_HEAD_INIT(&PyType_Type, 0) +#else PyObject_HEAD_INIT(NULL) 0, /* Number of items in variable part (ob_size) */ +#endif (char *)"swigvarlink", /* Type name (tp_name) */ sizeof(swig_varlinkobject), /* Basic size (tp_basicsize) */ 0, /* Itemsize (tp_itemsize) */ @@ -147,7 +182,10 @@ swig_varlink_type(void) { #endif }; varlink_type = tmp; + /* for Python 3 we already assigned the ob_type in PyVarObject_HEAD_INIT() */ +#if PY_VERSION_HEX < 0x03000000 varlink_type.ob_type = &PyType_Type; +#endif type_init = 1; } return &varlink_type; @@ -272,13 +310,35 @@ SWIG_Python_FixMethods(PyMethodDef *methods, #ifdef __cplusplus extern "C" #endif -SWIGEXPORT void SWIG_init(void) { + +SWIGEXPORT +#if PY_VERSION_HEX >= 0x03000000 + PyObject* +#else + void +#endif +SWIG_init(void) { PyObject *m, *d; /* Fix SwigMethods to carry the callback ptrs when needed */ SWIG_Python_FixMethods(SwigMethods, swig_const_table, swig_types, swig_type_initial); - +#if PY_VERSION_HEX >= 0x03000000 + static struct PyModuleDef SWIG_module = { + PyModuleDef_HEAD_INIT, + (char *) SWIG_name, + NULL, + -1, + SwigMethods, + NULL, + NULL, + NULL, + NULL + }; + + m = PyModule_Create(&SWIG_module); +#else m = Py_InitModule((char *) SWIG_name, SwigMethods); +#endif d = PyModule_GetDict(m); SWIG_InitializeModule(0); diff --git a/Lib/python/pyiterators.swg b/Lib/python/pyiterators.swg index 38f1791a9..62a7eaf70 100644 --- a/Lib/python/pyiterators.swg +++ b/Lib/python/pyiterators.swg @@ -66,6 +66,12 @@ namespace swig { return obj; } + /* Make an alias for Python 3.x */ + PyObject *__next__() + { + return next(); + } + PyObject *previous() { SWIG_PYTHON_THREAD_BEGIN_BLOCK; // disable threads @@ -335,6 +341,7 @@ namespace swig %catches(swig::stop_iteration) PySwigIterator::decr(size_t n = 1); %catches(std::invalid_argument) PySwigIterator::distance(const PySwigIterator &x) const; %catches(std::invalid_argument) PySwigIterator::equal (const PySwigIterator &x) const; + %catches(swig::stop_iteration) PySwigIterator::__next__(); %catches(swig::stop_iteration) PySwigIterator::next(); %catches(swig::stop_iteration) PySwigIterator::previous(); %catches(swig::stop_iteration) PySwigIterator::advance(ptrdiff_t n); @@ -370,6 +377,7 @@ namespace swig virtual PySwigIterator *copy() const = 0; PyObject *next(); + PyObject *__next__(); PyObject *previous(); PySwigIterator *advance(ptrdiff_t n); diff --git a/Lib/python/pyopers.swg b/Lib/python/pyopers.swg index 76f1e6789..bd5c954f0 100644 --- a/Lib/python/pyopers.swg +++ b/Lib/python/pyopers.swg @@ -33,6 +33,12 @@ /* Special cases */ %rename(__invert__) *::operator~; %rename(__call__) *::operator(); + +%feature("shadow") *::operator bool %{ +def __nonzero__(self): + return $action(self) +__bool__ = __nonzero__ +%}; %rename(__nonzero__) *::operator bool; /* Ignored operators */ diff --git a/Lib/python/pyrun.swg b/Lib/python/pyrun.swg index 844a66bec..4f51d3a95 100644 --- a/Lib/python/pyrun.swg +++ b/Lib/python/pyrun.swg @@ -348,9 +348,13 @@ PySwigObject_format(const char* fmt, PySwigObject *v) PyObject *args = PyTuple_New(1); if (args) { if (PyTuple_SetItem(args, 0, PySwigObject_long(v)) == 0) { - PyObject *ofmt = PyString_FromString(fmt); + PyObject *ofmt = SWIG_Python_str_FromChar(fmt); if (ofmt) { +#if PY_VERSION_HEX >= 0x03000000 + res = PyUnicode_Format(ofmt,args); +#else res = PyString_Format(ofmt,args); +#endif Py_DECREF(ofmt); } Py_DECREF(args); @@ -380,7 +384,7 @@ PySwigObject_repr(PySwigObject *v, PyObject *args) { const char *name = SWIG_TypePrettyName(v->ty); PyObject *hex = PySwigObject_hex(v); - PyObject *repr = PyString_FromFormat("", name, PyString_AsString(hex)); + PyObject *repr = SWIG_Python_str_FromFormat("", name, hex); Py_DECREF(hex); if (v->next) { #ifdef METH_NOARGS @@ -388,7 +392,14 @@ PySwigObject_repr(PySwigObject *v, PyObject *args) #else PyObject *nrep = PySwigObject_repr((PySwigObject *)v->next, args); #endif +#if PY_VERSION_HEX >= 0x03000000 + PyObject *joined = PyUnicode_Concat(repr, nrep); + Py_DecRef(repr); + Py_DecRef(nrep); + repr = joined; +#else PyString_ConcatAndDel(&repr,nrep); +#endif } return repr; } @@ -402,7 +413,7 @@ PySwigObject_print(PySwigObject *v, FILE *fp, int SWIGUNUSEDPARM(flags)) PyObject *repr = PySwigObject_repr(v, NULL); #endif if (repr) { - fputs(PyString_AsString(repr), fp); + fputs(SWIG_Python_str_AsChar(repr), fp); Py_DECREF(repr); return 0; } else { @@ -415,7 +426,7 @@ PySwigObject_str(PySwigObject *v) { char result[SWIG_BUFFER_SIZE]; return SWIG_PackVoidPtr(result, v->ptr, v->ty->name, sizeof(result)) ? - PyString_FromString(result) : 0; + SWIG_Python_str_FromChar(result) : 0; } SWIGRUNTIME int @@ -426,6 +437,24 @@ PySwigObject_compare(PySwigObject *v, PySwigObject *w) return (i < j) ? -1 : ((i > j) ? 1 : 0); } +/* Added for Python 3.x, whould it also useful for Python 2.x? */ +SWIGRUNTIME PyObject* +PySwigObject_richcompare(PySwigObject *v, PySwigObject *w, int op) +{ + PyObject* res; + if( op != Py_EQ && op != Py_NE ) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + if( (PySwigObject_compare(v, w)==0) == (op == Py_EQ) ) + res = Py_True; + else + res = Py_False; + Py_INCREF(res); + return res; +} + + SWIGRUNTIME PyTypeObject* _PySwigObject_type(void); SWIGRUNTIME PyTypeObject* @@ -436,8 +465,8 @@ PySwigObject_type(void) { SWIGRUNTIMEINLINE int PySwigObject_Check(PyObject *op) { - return ((op)->ob_type == PySwigObject_type()) - || (strcmp((op)->ob_type->tp_name,"PySwigObject") == 0); + return (Py_TYPE(op) == PySwigObject_type()) + || (strcmp(Py_TYPE(op)->tp_name,"PySwigObject") == 0); } SWIGRUNTIME PyObject * @@ -610,7 +639,10 @@ _PySwigObject_type(void) { (binaryfunc)0, /*nb_add*/ (binaryfunc)0, /*nb_subtract*/ (binaryfunc)0, /*nb_multiply*/ + /* nb_divide removed in Python 3 */ +#if PY_VERSION_HEX < 0x03000000 (binaryfunc)0, /*nb_divide*/ +#endif (binaryfunc)0, /*nb_remainder*/ (binaryfunc)0, /*nb_divmod*/ (ternaryfunc)0,/*nb_power*/ @@ -624,13 +656,19 @@ _PySwigObject_type(void) { 0, /*nb_and*/ 0, /*nb_xor*/ 0, /*nb_or*/ - (coercion)0, /*nb_coerce*/ +#if PY_VERSION_HEX < 0x03000000 + 0, /*nb_coerce*/ +#endif (unaryfunc)PySwigObject_long, /*nb_int*/ (unaryfunc)PySwigObject_long, /*nb_long*/ (unaryfunc)0, /*nb_float*/ +#if PY_VERSION_HEX < 0x03000000 (unaryfunc)PySwigObject_oct, /*nb_oct*/ (unaryfunc)PySwigObject_hex, /*nb_hex*/ -#if PY_VERSION_HEX >= 0x02050000 /* 2.5.0 */ +#endif +#if PY_VERSION_HEX >= 0x03000000 /* 3.0 */ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 /* nb_inplace_add -> nb_index, nb_inplace_divide removed */ +#elif PY_VERSION_HEX >= 0x02050000 /* 2.5.0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 /* nb_inplace_add -> nb_index */ #elif PY_VERSION_HEX >= 0x02020000 /* 2.2.0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 /* nb_inplace_add -> nb_inplace_true_divide */ @@ -644,8 +682,13 @@ _PySwigObject_type(void) { if (!type_init) { const PyTypeObject tmp = { - PyObject_HEAD_INIT(NULL) - 0, /* ob_size */ + /* PyOjbect header changed in Python 3 */ +#if PY_VERSION_HEX >= 0x03000000 + PyVarObject_HEAD_INIT(&PyType_Type, 0) +#else + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ +#endif (char *)"PySwigObject", /* tp_name */ sizeof(PySwigObject), /* tp_basicsize */ 0, /* tp_itemsize */ @@ -672,7 +715,7 @@ _PySwigObject_type(void) { swigobject_doc, /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ - 0, /* tp_richcompare */ + (richcmpfunc)PySwigObject_richcompare, /* tp_richcompare */ 0, /* tp_weaklistoffset */ #if PY_VERSION_HEX >= 0x02020000 0, /* tp_iter */ @@ -704,7 +747,10 @@ _PySwigObject_type(void) { #endif }; pyswigobject_type = tmp; + /* for Python 3 we already assigned the ob_type in PyVarObject_HEAD_INIT() */ +#if PY_VERSION_HEX < 0x03000000 pyswigobject_type.ob_type = &PyType_Type; +#endif type_init = 1; } return &pyswigobject_type; @@ -753,9 +799,9 @@ PySwigPacked_repr(PySwigPacked *v) { char result[SWIG_BUFFER_SIZE]; if (SWIG_PackDataName(result, v->pack, v->size, 0, sizeof(result))) { - return PyString_FromFormat("", result, v->ty->name); + return SWIG_Python_str_FromFormat("", result, v->ty->name); } else { - return PyString_FromFormat("", v->ty->name); + return SWIG_Python_str_FromFormat("", v->ty->name); } } @@ -764,9 +810,9 @@ PySwigPacked_str(PySwigPacked *v) { char result[SWIG_BUFFER_SIZE]; if (SWIG_PackDataName(result, v->pack, v->size, 0, sizeof(result))){ - return PyString_FromFormat("%s%s", result, v->ty->name); + return SWIG_Python_str_FromFormat("%s%s", result, v->ty->name); } else { - return PyString_FromString(v->ty->name); + return SWIG_Python_str_FromChar(v->ty->name); } } @@ -811,8 +857,13 @@ _PySwigPacked_type(void) { if (!type_init) { const PyTypeObject tmp = { + /* PyObject header changed in Python 3 */ +#if PY_VERSION_HEX>=0x03000000 + PyVarObject_HEAD_INIT(&PyType_Type, 0) +#else PyObject_HEAD_INIT(NULL) - 0, /* ob_size */ + 0, /* ob_size */ +#endif (char *)"PySwigPacked", /* tp_name */ sizeof(PySwigPacked), /* tp_basicsize */ 0, /* tp_itemsize */ @@ -867,7 +918,10 @@ _PySwigPacked_type(void) { #endif }; pyswigpacked_type = tmp; + /* for Python 3 the ob_type already assigned in PyVarObject_HEAD_INIT() */ +#if PY_VERSION_HEX < 0x03000000 pyswigpacked_type.ob_type = &PyType_Type; +#endif type_init = 1; } return &pyswigpacked_type; @@ -912,7 +966,7 @@ PySwigPacked_UnpackData(PyObject *obj, void *ptr, size_t size) SWIGRUNTIMEINLINE PyObject * _SWIG_This(void) { - return PyString_FromString("this"); + return SWIG_Python_str_FromChar("this"); } SWIGRUNTIME PyObject * @@ -924,6 +978,11 @@ SWIG_This(void) /* #define SWIG_PYTHON_SLOW_GETSET_THIS */ +/* TODO: I don't know how to implement the fast getset in Python 3 right now */ +#if PY_VERSION_HEX>=0x03000000 +#define SWIG_PYTHON_SLOW_GETSET_THIS +#endif + SWIGRUNTIME PySwigObject * SWIG_Python_GetSwigThis(PyObject *pyobj) { @@ -1161,10 +1220,17 @@ SWIG_Python_NewShadowInstance(PySwigClientData *data, PyObject *swig_this) #endif } } else { +#if PY_VERSION_HEX >= 0x03000000 + inst = PyBaseObject_Type.tp_new((PyTypeObject*) data->newargs, Py_None, Py_None); + Py_INCREF(data->newargs); + PyObject_SetAttr(inst, SWIG_This(), swig_this); + Py_TYPE(inst)->tp_flags &= ~Py_TPFLAGS_VALID_VERSION_TAG; +#else PyObject *dict = PyDict_New(); PyDict_SetItem(dict, SWIG_This(), swig_this); inst = PyInstance_NewRaw(data->newargs, dict); Py_DECREF(dict); +#endif } return inst; #else @@ -1344,8 +1410,13 @@ SWIGRUNTIME void SWIG_Python_SetModule(swig_module_info *swig_module) { static PyMethodDef swig_empty_runtime_method_table[] = { {NULL, NULL, 0, NULL} };/* Sentinel */ +#if PY_VERSION_HEX >= 0x03000000 + /* Add a dummy module object into sys.modules */ + PyObject *module = PyImport_AddModule((char*)"swig_runtime_data" SWIG_RUNTIME_VERSION); +#else PyObject *module = Py_InitModule((char*)"swig_runtime_data" SWIG_RUNTIME_VERSION, swig_empty_runtime_method_table); +#endif PyObject *pointer = PyCObject_FromVoidPtr((void *) swig_module, SWIG_Python_DestroyModule); if (pointer && module) { PyModule_AddObject(module, (char*)"type_pointer" SWIG_TYPE_TABLE_NAME, pointer); @@ -1365,7 +1436,7 @@ SWIGRUNTIME swig_type_info * SWIG_Python_TypeQuery(const char *type) { PyObject *cache = SWIG_Python_TypeCache(); - PyObject *key = PyString_FromString(type); + PyObject *key = SWIG_Python_str_FromChar(type); PyObject *obj = PyDict_GetItem(cache, key); swig_type_info *descriptor; if (obj) { @@ -1403,9 +1474,9 @@ SWIG_Python_AddErrMesg(const char* mesg, int infront) Py_XINCREF(type); PyErr_Clear(); if (infront) { - PyErr_Format(type, "%s %s", mesg, PyString_AsString(old_str)); + PyErr_Format(type, "%s %s", mesg, SWIG_Python_str_AsChar(old_str)); } else { - PyErr_Format(type, "%s %s", PyString_AsString(old_str), mesg); + PyErr_Format(type, "%s %s", SWIG_Python_str_AsChar(old_str), mesg); } Py_DECREF(old_str); } @@ -1454,7 +1525,7 @@ SWIG_Python_TypeError(const char *type, PyObject *obj) const char *otype = (obj ? obj->ob_type->tp_name : 0); if (otype) { PyObject *str = PyObject_Str(obj); - const char *cstr = str ? PyString_AsString(str) : 0; + const char *cstr = str ? SWIG_Python_str_AsChar(str) : 0; if (cstr) { PyErr_Format(PyExc_TypeError, "a '%s' is expected, '%s(%s)' is received", type, otype, cstr); diff --git a/Lib/python/pystrings.swg b/Lib/python/pystrings.swg index d4d60c42b..5a06792d7 100644 --- a/Lib/python/pystrings.swg +++ b/Lib/python/pystrings.swg @@ -5,10 +5,20 @@ SWIGINTERN int SWIG_AsCharPtrAndSize(PyObject *obj, char** cptr, size_t* psize, int *alloc) { - if (PyString_Check(obj)) { +%#if PY_VERSION_HEX>=0x03000000 + if (PyUnicode_Check(obj)) +%#else + if (PyString_Check(obj)) +%#endif + { char *cstr; Py_ssize_t len; +%#if PY_VERSION_HEX>=0x03000000 + obj = PyUnicode_AsUTF8String(obj); + PyBytes_AsStringAndSize(obj, &cstr, &len); +%#else PyString_AsStringAndSize(obj, &cstr, &len); - if (cptr) { +%#endif + if (cptr) { if (alloc) { /* In python the user should not be able to modify the inner @@ -33,7 +43,7 @@ SWIG_AsCharPtrAndSize(PyObject *obj, char** cptr, size_t* psize, int *alloc) *alloc = SWIG_OLDOBJ; } } else { - *cptr = PyString_AsString(obj); + *cptr = SWIG_Python_str_AsChar(obj); } } if (psize) *psize = len + 1; @@ -64,7 +74,11 @@ SWIG_FromCharPtrAndSize(const char* carray, size_t size) return pchar_descriptor ? SWIG_NewPointerObj(%const_cast(carray,char *), pchar_descriptor, 0) : SWIG_Py_Void(); } else { +%#if PY_VERSION_HEX >= 0x03000000 + return PyUnicode_FromStringAndSize(carray, %numeric_cast(size,int)); +%#else return PyString_FromStringAndSize(carray, %numeric_cast(size,int)); +%#endif } } else { return SWIG_Py_Void(); diff --git a/Lib/python/pywstrings.swg b/Lib/python/pywstrings.swg index 8254bf8f7..4161dcb0f 100644 --- a/Lib/python/pywstrings.swg +++ b/Lib/python/pywstrings.swg @@ -8,12 +8,14 @@ SWIG_AsWCharPtrAndSize(PyObject *obj, wchar_t **cptr, size_t *psize, int *alloc) { PyObject *tmp = 0; int isunicode = PyUnicode_Check(obj); +%#if PY_VERSION_HEX < 0x03000000 if (!isunicode && PyString_Check(obj)) { if (cptr) { obj = tmp = PyUnicode_FromObject(obj); } isunicode = 1; } +%#endif if (isunicode) { int len = PyUnicode_GetSize(obj); if (cptr) { diff --git a/Lib/python/std_map.i b/Lib/python/std_map.i index 12dc23ccf..b080731f0 100644 --- a/Lib/python/std_map.i +++ b/Lib/python/std_map.i @@ -22,6 +22,10 @@ int res = SWIG_ERROR; if (PyDict_Check(obj)) { PyObject_var items = PyObject_CallMethod(obj,(char *)"items",NULL); +%#if PY_VERSION_HEX >= 0x03000000 + /* In Python 3.x the ".items()" method return a dict_items object */ + items = PySequence_Fast(items, ".items() havn't returned a sequence!"); +%#endif res = traits_asptr_stdseq, std::pair >::asptr(items, val); } else { map_type *p; diff --git a/Source/CParse/cscanner.c b/Source/CParse/cscanner.c index 032c71f7e..871565df8 100644 --- a/Source/CParse/cscanner.c +++ b/Source/CParse/cscanner.c @@ -690,7 +690,15 @@ int yylex(void) { termtoken = SWIG_TOKEN_LPAREN; termvalue = "("; break; - } else if (nexttok == SWIG_TOKEN_SEMI) { + } else if (nexttok == SWIG_TOKEN_CODEBLOCK) { + termtoken = SWIG_TOKEN_CODEBLOCK; + termvalue = Scanner_text(scan); + break; + } else if (nexttok == SWIG_TOKEN_LBRACE) { + termtoken = SWIG_TOKEN_LBRACE; + termvalue = "{"; + break; + } else if (nexttok == SWIG_TOKEN_SEMI) { termtoken = SWIG_TOKEN_SEMI; termvalue = ";"; break; @@ -859,8 +867,14 @@ int yylex(void) { return (INLINE); if (strcmp(yytext, "%typemap") == 0) return (TYPEMAP); - if (strcmp(yytext, "%feature") == 0) + if (strcmp(yytext, "%feature") == 0) { + /* The rename_active indicates we don't need the information of the + * following function's return type. This applied for %rename, so do + * %feature. + */ + rename_active = 1; return (FEATURE); + } if (strcmp(yytext, "%except") == 0) return (EXCEPT); if (strcmp(yytext, "%importfile") == 0) diff --git a/Source/CParse/parser.y b/Source/CParse/parser.y index 58e0c0c41..69c2a503d 100644 --- a/Source/CParse/parser.y +++ b/Source/CParse/parser.y @@ -2290,21 +2290,25 @@ feature_directive : FEATURE LPAREN idstring RPAREN declarator cpp_const stringbr String *val = $7 ? NewString($7) : NewString("1"); new_feature($3, val, 0, $5.id, $5.type, $5.parms, $6.qualifier); $$ = 0; + scanner_clear_rename(); } | FEATURE LPAREN idstring COMMA stringnum RPAREN declarator cpp_const SEMI { String *val = Len($5) ? NewString($5) : 0; new_feature($3, val, 0, $7.id, $7.type, $7.parms, $8.qualifier); $$ = 0; + scanner_clear_rename(); } | FEATURE LPAREN idstring featattr RPAREN declarator cpp_const stringbracesemi { String *val = $8 ? NewString($8) : NewString("1"); new_feature($3, val, $4, $6.id, $6.type, $6.parms, $7.qualifier); $$ = 0; + scanner_clear_rename(); } | FEATURE LPAREN idstring COMMA stringnum featattr RPAREN declarator cpp_const SEMI { String *val = Len($5) ? NewString($5) : 0; new_feature($3, val, $6, $8.id, $8.type, $8.parms, $9.qualifier); $$ = 0; + scanner_clear_rename(); } /* Global feature */ @@ -2312,21 +2316,25 @@ feature_directive : FEATURE LPAREN idstring RPAREN declarator cpp_const stringbr String *val = $5 ? NewString($5) : NewString("1"); new_feature($3, val, 0, 0, 0, 0, 0); $$ = 0; + scanner_clear_rename(); } | FEATURE LPAREN idstring COMMA stringnum RPAREN SEMI { String *val = Len($5) ? NewString($5) : 0; new_feature($3, val, 0, 0, 0, 0, 0); $$ = 0; + scanner_clear_rename(); } | FEATURE LPAREN idstring featattr RPAREN stringbracesemi { String *val = $6 ? NewString($6) : NewString("1"); new_feature($3, val, $4, 0, 0, 0, 0); $$ = 0; + scanner_clear_rename(); } | FEATURE LPAREN idstring COMMA stringnum featattr RPAREN SEMI { String *val = Len($5) ? NewString($5) : 0; new_feature($3, val, $6, 0, 0, 0, 0); $$ = 0; + scanner_clear_rename(); } ; diff --git a/Source/Modules/python.cxx b/Source/Modules/python.cxx index ddd23d1f3..7a878b4f8 100644 --- a/Source/Modules/python.cxx +++ b/Source/Modules/python.cxx @@ -49,10 +49,11 @@ static String *shadow_indent = 0; static int in_class = 0; static int classic = 0; static int modern = 0; -static int apply = 0; static int new_repr = 1; static int no_header_file = 0; +static int py3 = 0; + /* C++ Support + Shadow Classes */ static int have_constructor; @@ -96,7 +97,6 @@ enum autodoc_t { static const char *usage1 = (char *) "\ Python Options (available with -python)\n\ -aliasobj0 - Alias obj0 when using fastunpack, needed for some old typemaps \n\ - -apply - Use apply() in proxy classes\n\ -buildnone - Use Py_BuildValue(" ") to obtain Py_None (default in Windows)\n\ -castmode - Enable the casting mode, which allows implicit cast between types in python\n\ -classic - Use classic classes only\n\ @@ -148,6 +148,8 @@ static const char *usage3 = (char *) "\ -O - Enable all the optimization options: \n\ -modern -fastdispatch -dirvtable -nosafecstrings -fvirtual -noproxydel \n\ -fastproxy -fastinit -fastunpack -fastquery -modernargs -nobuildnone \n\ + -py3 - Generate code with Python 3 specific features:\n\ + Function annotation \n\ \n"; class PYTHON:public Language { @@ -259,9 +261,6 @@ public: } else if ((strcmp(argv[i], "-shadow") == 0) || ((strcmp(argv[i], "-proxy") == 0))) { shadow = 1; Swig_mark_arg(i); - } else if (strcmp(argv[i], "-apply") == 0) { - apply = 1; - Swig_mark_arg(i); } else if ((strcmp(argv[i], "-new_repr") == 0) || (strcmp(argv[i], "-newrepr") == 0)) { new_repr = 1; Swig_mark_arg(i); @@ -284,7 +283,6 @@ public: } else if (strcmp(argv[i], "-classic") == 0) { classic = 1; modernargs = 0; - apply = 1; modern = 0; Swig_mark_arg(i); } else if (strcmp(argv[i], "-cppcast") == 0) { @@ -390,7 +388,6 @@ public: proxydel = 0; Swig_mark_arg(i); } else if (strcmp(argv[i], "-modern") == 0) { - apply = 0; classic = 0; modern = 1; modernargs = 1; @@ -408,7 +405,6 @@ public: no_header_file = 1; Swig_mark_arg(i); } else if (strcmp(argv[i], "-O") == 0) { - apply = 0; classic = 0; modern = 1; dirvtable = 1; @@ -429,8 +425,17 @@ public: fputs(usage1, stdout); fputs(usage2, stdout); fputs(usage3, stdout); - } + } else if (strcmp(argv[i], "-py3") == 0) { + py3 = 1; + Swig_mark_arg(i); + } + } + } /* for */ + + if (py3) { + /* force disable features that not compatible with Python 3.x */ + classic = 0; } if (cppcast) { @@ -691,6 +696,13 @@ public: Printv(f_shadow, "\nfrom sys import version_info\n", NULL); + if(fastproxy) + { + Printv(f_shadow, "if version_info >= (3,0,0):\n", NULL); + Printf(f_shadow, tab4 "new_instancemethod = lambda func, inst, cls: %s.SWIG_PyInstanceMethod_New(func)\n", module); + Printv(f_shadow, "else:\n", NULL); + Printv(f_shadow, tab4, "from new import instancemethod as new_instancemethod\n", NULL); + } /* Import the C-extension module. This should be a relative import, * since the shadow module may also have been imported by a relative * import, and there is thus no guarantee that the C-extension is on @@ -719,11 +731,9 @@ public: * module. */ Printv(f_shadow, "del version_info\n", NULL); - Printv(f_shadow, "import new\n", NULL); - Printv(f_shadow, "new_instancemethod = new.instancemethod\n", NULL); if (modern || !classic) { Printv(f_shadow, "try:\n", tab4, "_swig_property = property\n", "except NameError:\n", tab4, "pass # Python < 2.2 doesn't have 'property'.\n", NULL); - } + } /* if (!modern) */ /* always needed, a class can be forced to be no-modern, such as an exception */ { @@ -750,7 +760,7 @@ public: "def _swig_getattr(self,class_type,name):\n", tab4, "if (name == \"thisown\"): return self.this.own()\n", tab4, "method = class_type.__swig_getmethods__.get(name,None)\n", - tab4, "if method: return method(self)\n", tab4, "raise AttributeError,name\n\n", NIL); + tab4, "if method: return method(self)\n", tab4, "raise AttributeError(name)\n\n", NIL); Printv(f_shadow, "def _swig_repr(self):\n", @@ -758,11 +768,17 @@ public: tab4, "except: strthis = \"\"\n", tab4, "return \"<%s.%s; %s >\" % (self.__class__.__module__, self.__class__.__name__, strthis,)\n\n", NIL); if (!classic) { + /* Usage of types.ObjectType is deprecated. + * But don't sure wether this would broken old Python? + */ Printv(f_shadow, - "import types\n", +// "import types\n", "try:\n", - " _object = types.ObjectType\n", - " _newclass = 1\n", "except AttributeError:\n", " class _object : pass\n", " _newclass = 0\n", "del types\n", "\n\n", NIL); +// " _object = types.ObjectType\n", + " _object = object\n", + " _newclass = 1\n", "except AttributeError:\n", " class _object : pass\n", " _newclass = 0\n", +// "del types\n", + "\n\n", NIL); } } if (modern) { @@ -788,7 +804,11 @@ public: } - Printf(f_header, "#define SWIG_init init%s\n\n", module); + Printf(f_header, "#if PY_VERSION_HEX >= 0x03000000\n"); + Printf(f_header, "# define SWIG_init PyInit_%s\n\n", module); + Printf(f_header, "#else\n"); + Printf(f_header, "# define SWIG_init init%s\n\n", module); + Printf(f_header, "#endif\n"); Printf(f_header, "#define SWIG_name \"%s\"\n", module); Printf(f_wrappers, "#ifdef __cplusplus\n"); @@ -797,6 +817,9 @@ public: Append(const_code, "static swig_const_info swig_const_table[] = {\n"); Append(methods, "static PyMethodDef SwigMethods[] = {\n"); + /* the method exported for replacement of new.instancemethod in Python 3 */ + add_pyinstancemethod_new(); + /* emit code */ Language::top(n); @@ -815,6 +838,12 @@ public: Append(const_code, "{0, 0, 0, 0.0, 0, 0}};\n"); Printf(f_wrappers, "%s\n", const_code); initialize_threads(f_init); + + Printf(f_init, "#if PY_VERSION_HEX >= 0x03000000\n"); + Printf(f_init, " return m;\n"); + Printf(f_init, "#else\n"); + Printf(f_init, " return;\n"); + Printf(f_init, "#endif\n"); Printf(f_init, "}\n"); Printf(f_wrappers, "#ifdef __cplusplus\n"); @@ -822,10 +851,6 @@ public: Printf(f_wrappers, "#endif\n"); if (shadow) { - /* - Printf(f_shadow_imports,"\nimport %s\n", module); - Printv(f_shadow_py, f_shadow_imports, "\n",NIL); - */ Printv(f_shadow_py, f_shadow, "\n", NIL); Printv(f_shadow_py, f_shadow_stubs, "\n", NIL); @@ -859,6 +884,19 @@ public: return SWIG_OK; } + + /* ------------------------------------------------------------ + * Emit the wrapper for PyInstanceMethod_New to MethodDef array. + * This wrapper is used to implement -fastproxy, + * as a replacement of new.instancemethod in Python 3. + * ------------------------------------------------------------ */ + int add_pyinstancemethod_new() + { + String* name = NewString("SWIG_PyInstanceMethod_New"); + Printf(methods, "\t { (char *)\"%s\", (PyCFunction)%s, METH_O, NULL},", name, name); + Delete(name); + return 0; + } /* ------------------------------------------------------------ * importDirective() @@ -902,25 +940,19 @@ public: return Language::importDirective(n); } - /* ------------------------------------------------------------ - * emitFuncCallHelper() - * Write the shadow code to call a function in the extension - * module. Takes into account the -apply flag and whether - * to use keyword args or not. + * funcCall() + * Emit shadow code to call a function in the extension + * module. Using proper argument and calling style for + * given node n. * ------------------------------------------------------------ */ + String *funcCall(String *name, String *parms) { + String *str = NewString(""); - String *funcCallHelper(String *name, int kw) { - String *str; - - str = NewString(""); - if (apply) { - Printv(str, "apply(", module, ".", name, ", args", (kw ? ", kwargs" : ""), ")", NIL); - } else { - Printv(str, module, ".", name, "(*args", (kw ? ", **kwargs" : ""), ")", NIL); - } + Printv(str, module, ".", name, "(", parms, ")", NIL); return str; - } + } + /* ------------------------------------------------------------ * pythoncode() - Output python code into the shadow file @@ -1088,29 +1120,84 @@ public: return doc; } + /* ----------------------------------------------------------------------------- + * makeParameterName() + * Note: the generated name should consist with that in kwnames[] + * + * Inputs: + * n - Node + * p - parameter node + * arg_num - parameter argument number + * Return: + * arg - a unique parameter name + * ----------------------------------------------------------------------------- */ + + String *makeParameterName(ParmList *plist, Parm *p, int arg_num) { + String *arg = 0; + String *pn = Swig_name_make(p, 0, Getattr(p, "name"), 0, 0); + // Use C parameter name unless it is a duplicate or an empty parameter name + int count = 0; + if ( SwigType_isvarargs(Getattr(p, "type")) ) { + return NewString("*args"); + } + while (plist) { + if ((Cmp(pn, Getattr(plist, "name")) == 0)) + count++; + plist = nextSibling(plist); + } + arg = (!pn || !Len(pn) || (count > 1)) ? NewStringf("arg%d", arg_num) : Copy(pn); + return arg; + } + + /* ------------------------------------------------------------ * make_autodocParmList() * Generate the documentation for the function parameters + * Parameters: + * func_annotation: Function annotation support * ------------------------------------------------------------ */ - String *make_autodocParmList(Node *n, bool showTypes) { + String *make_autodocParmList(Node *n, bool showTypes, bool calling=false, bool func_annotation=false) { + + String *doc = NewString(""); String *pdocs = Copy(Getattr(n, "feature:pdocs")); ParmList *plist = CopyParmList(Getattr(n, "parms")); Parm *p; Parm *pnext; - Node *lookup; + Node *lookup; + + int lines = 0; + int arg_num = 0; const int maxwidth = 50; + if(calling) + func_annotation = false; + if (pdocs) Append(pdocs, "\n"); - Swig_typemap_attach_parms("in", plist, 0); Swig_typemap_attach_parms("doc", plist, 0); - + + if (Strcmp(ParmList_protostr(plist), "void")==0) { + //No parameters actually + return doc; + } + for (p = plist; p; p = pnext) { + + String *tm = Getattr(p, "tmap:in"); + if (tm) { + pnext = Getattr(p, "tmap:in:next"); + if (checkAttribute(p, "tmap:in:numinputs", "0")) { + continue; + } + } else { + pnext = nextSibling(p); + } + String *name = 0; String *type = 0; String *value = 0; @@ -1127,12 +1214,14 @@ public: type = type ? type : Getattr(p, "type"); value = value ? value : Getattr(p, "value"); - String *tm = Getattr(p, "tmap:in"); - if (tm) { - pnext = Getattr(p, "tmap:in:next"); - } else { - pnext = nextSibling(p); - } + name = makeParameterName(plist, p, arg_num); + // Reset it for convinient in further use. (mainly for makeParameterName()) + // Since the plist is created by CopyParmList, + // we can hope that the set would have no side effect + Setattr(p, "name", name); + + arg_num++; + if (Len(doc)) { // add a comma to the previous one if any @@ -1144,39 +1233,40 @@ public: lines += 1; } } + + type = SwigType_base(type); + lookup = Swig_symbol_clookup(type, 0); + if (lookup) + type = Getattr(lookup, "sym:name"); + // Do the param type too? - if (showTypes) { - type = SwigType_base(type); - lookup = Swig_symbol_clookup(type, 0); - if (lookup) - type = Getattr(lookup, "sym:name"); - Printf(doc, "%s ", type); - } - - if (name) { - Append(doc, name); - if (pdoc) { - if (!pdocs) - pdocs = NewString("Parameters:\n"); - Printf(pdocs, " %s\n", pdoc); - } - } else { - Append(doc, "?"); + if (showTypes) + Printf(doc, "%s ", type); + + + Append(doc, name); + if (pdoc) { + if (!pdocs) + pdocs = NewString("Parameters:\n"); + Printf(pdocs, " %s\n", pdoc); } - if (value) { - if (Strcmp(value, "NULL") == 0) - value = NewString("None"); - else if (Strcmp(value, "true") == 0 || Strcmp(value, "TRUE") == 0) - value = NewString("True"); - else if (Strcmp(value, "false") == 0 || Strcmp(value, "FALSE") == 0) - value = NewString("False"); + // Write the function annoation + if (func_annotation) + Printf(doc, " : '%s'", type); + + // Write default value + if (value && !calling) { + String* pv = pyvalue(value, Getattr(p, "type")); + if (pv) + value = pv; else { lookup = Swig_symbol_clookup(value, 0); - if (lookup) + if (lookup) { value = Getattr(lookup, "sym:name"); + } } - Printf(doc, "=%s", value); + Printf(doc, " = %s", value); } } if (pdocs) @@ -1314,6 +1404,132 @@ public: return doc; } + + /* ------------------------------------------------------------ + * pyvalue() + * Check if string v can be a Python value literal, + * (eg. number or string), or translate it to a Python literal. + * ------------------------------------------------------------ */ + String* pyvalue(String *v, SwigType *t) + { + if (v && Len(v)>0) { + char fc = (Char(v))[0]; + if (('0'<=fc && fc<='9') || '\''==fc || '"'==fc) { + /* number or string (or maybe NULL pointer)*/ + if (SwigType_ispointer(t) && Strcmp(v, "0")==0) + return NewString("None"); + else + return v; + } + if (Strcmp(v, "true")==0 || Strcmp(v, "FALSE")==0) + return NewString("True"); + if (Strcmp(v, "false")==0 || Strcmp(v, "FALSE")==0) + return NewString("False"); + if (Strcmp(v, "NULL")==0) + return NewString("None"); + } + return 0; + } + /* ------------------------------------------------------------ + * is_primitive_defaultargs() + * Check if all the default args have primitive type. + * (So we can generate proper parameter list with default + * values..) + * ------------------------------------------------------------ */ + bool is_primitive_defaultargs(Node *n) + { + ParmList *plist = CopyParmList(Getattr(n, "parms")); + Parm *p; + Parm *pnext; + + Swig_typemap_attach_parms("in", plist, 0); + for (p = plist; p; p = pnext) { + String *tm = Getattr(p, "tmap:in"); + if (tm) { + pnext = Getattr(p, "tmap:in:next"); + if (checkAttribute(p, "tmap:in:numinputs", "0")) { + continue; + } + } else { + pnext = nextSibling(p); + } + String *type = Getattr(p, "type"); + String *value = Getattr(p, "value"); + if (!pyvalue(value, type)) + return false; + } + return true; + } + + + /* ------------------------------------------------------------ + * is_real_overloaded() + * Check if the function is overloaded, but not just have some + * siblings generated due to the original function have + * default arguments. + * ------------------------------------------------------------ */ + bool is_real_overloaded(Node *n) + { + Node *h = Getattr(n, "sym:overloaded"); + Node *i; + if (!h) + return false; + + i = Getattr(h, "sym:nextSibling"); + while (i) { + Node *nn = Getattr(i, "defaultargs"); + if (nn != h) { + /* Check if overloaded function has defaultargs and + * pointed to the first overloaded. */ + return true; + } + i = Getattr(i, "sym:nextSibling"); + } + + return false; + } + + /* ------------------------------------------------------------ + * make_pyParmList() + * Generate parameter list for Python functions or methods, + * reuse make_autodocParmList() to do so. + * ------------------------------------------------------------ */ + String* make_pyParmList(Node *n, bool in_class, bool is_calling, int kw) + { + /* Get the original function for a defaultargs copy, + * see default_arguments() in parser.y. */ + Node *nn = Getattr(n, "defaultargs"); + if (nn) n = nn; + + /* For overloaded function, just use *args */ + if (is_real_overloaded(n) || + GetFlag(n, "feature:compactdefaultargs") || + !is_primitive_defaultargs(n)) + { + String *parms = NewString(""); + if(in_class) + Printf(parms, "self, "); + Printf(parms, "*args"); + if (kw) + Printf(parms, ", **kwargs"); + return parms; + } + + bool funcanno = py3 ? true : false; + String *params = NewString(""); + String *_params = make_autodocParmList(n, false, is_calling, funcanno); + + if (in_class) + { + Printf(params, "self"); + if(Len(_params) > 0) + Printf(params, ", "); + } + + Printv(params, _params, NULL); + + return params; + } /* ------------------------------------------------------------ * have_pythonprepend() @@ -1379,6 +1595,40 @@ public: return have_pythonappend(n) || have_pythonprepend(n) || have_docstring(n); } + + /* ------------------------------------------------------------ + * returnTypeAnnotation() + * Helper function for constructing the function annotation + * of the returning type, return a empty string for Python 2.x + * ------------------------------------------------------------ */ + String* returnTypeAnnotation(Node *n) + { + String *ret=0; + Parm *p = Getattr(n, "parms"); + String *tm; + /* Try to guess the returning type by argout typemap, + * however the result may not accurate. */ + while (p) { + if ((tm=Getattr(p, "tmap:argout:match_type"))) { + tm = SwigType_str(tm, 0); + if (ret) + Printv(ret, ", ", tm, NULL); + else + ret = tm; + p = Getattr(p, "tmap:argout:next"); + } else { + p = nextSibling(p); + } + } + /* If no argout typemap, then get the returning type from + * the function prototype. */ + if (!ret) { + ret = Getattr(n, "type"); + if (ret) ret = SwigType_str(ret, 0); + } + return (ret && py3) ? NewStringf(" -> \"%s\" ", ret) + : NewString(""); + } /* ------------------------------------------------------------ * emitFunctionShadowHelper() @@ -1388,24 +1638,26 @@ public: * ------------------------------------------------------------ */ void emitFunctionShadowHelper(Node *n, File *f_dest, String *name, int kw) { - if (Getattr(n, "feature:python:callback") || !have_addtofunc(n)) { - /* If there is no addtofunc directive then just assign from the extension module */ - Printv(f_dest, name, " = ", module, ".", name, "\n", NIL); + String *parms = make_pyParmList(n, false, false, kw); + String *callParms = make_pyParmList(n, false, true, kw); + /* Make a wrapper function to insert the code into */ + Printv(f_dest, "\ndef ", name, "(", parms, ")", returnTypeAnnotation(n), ":\n", NIL); + if (have_docstring(n)) + Printv(f_dest, ctab4, docstring(n, AUTODOC_FUNC, tab4), "\n", NIL); + if (have_pythonprepend(n)) + Printv(f_dest, ctab4, pythonprepend(n), "\n", NIL); + if (have_pythonappend(n)) { + Printv(f_dest, ctab4, "val = ", funcCall(name, callParms), "\n", NIL); + Printv(f_dest, ctab4, pythonappend(n), "\n", NIL); + Printv(f_dest, ctab4, "return val\n", NIL); } else { - /* Otherwise make a wrapper function to insert the code into */ - Printv(f_dest, "\ndef ", name, "(*args", (kw ? ", **kwargs" : ""), "):\n", NIL); - if (have_docstring(n)) - Printv(f_dest, ctab4, docstring(n, AUTODOC_FUNC, tab4), "\n", NIL); - if (have_pythonprepend(n)) - Printv(f_dest, ctab4, pythonprepend(n), "\n", NIL); - if (have_pythonappend(n)) { - Printv(f_dest, ctab4, "val = ", funcCallHelper(name, kw), "\n", NIL); - Printv(f_dest, ctab4, pythonappend(n), "\n", NIL); - Printv(f_dest, ctab4, "return val\n", NIL); - } else { - Printv(f_dest, ctab4, "return ", funcCallHelper(name, kw), "\n", NIL); - } + Printv(f_dest, ctab4, "return ", funcCall(name, callParms), "\n", NIL); } + + if (Getattr(n, "feature:python:callback") || !have_addtofunc(n)) { + /* If there is no addtofunc directive then just assign from the extension module (for speed up) */ + Printv(f_dest, name, " = ", module, ".", name, "\n", NIL); + } } @@ -2488,7 +2740,7 @@ public: Printf(f_directors_h, " PyObject *swig_get_method(size_t method_index, const char *method_name) const {\n"); Printf(f_directors_h, " PyObject *method = vtable[method_index];\n"); Printf(f_directors_h, " if (!method) {\n"); - Printf(f_directors_h, " swig::PyObject_var name = PyString_FromString(method_name);\n"); + Printf(f_directors_h, " swig::PyObject_var name = SWIG_Python_str_FromChar(method_name);\n"); Printf(f_directors_h, " method = PyObject_GetAttr(swig_get_self(), name);\n"); Printf(f_directors_h, " if (method == NULL) {\n"); Printf(f_directors_h, " std::string msg = \"Method in class %s doesn't exist, undefined \";\n", classname); @@ -2623,6 +2875,16 @@ public: } } } + + /* dealing with abstract base class */ + String *abcs = Getattr(n, "feature:python:abc"); + if (py3 && abcs) { + if (Len(base_class)) { + Putc(',', base_class); + } + Printv(base_class, abcs, NIL); + } + Printv(f_shadow, "class ", class_name, NIL); if (Len(base_class)) { @@ -2631,6 +2893,9 @@ public: if (!classic) { Printf(f_shadow, modern ? "(object)" : "(_object)"); } + if (GetFlag(n, "feature:exceptionclass") ) { + Printf(f_shadow, "(Exception)"); + } } Printf(f_shadow, ":\n"); if (have_docstring(n)) { @@ -2721,7 +2986,7 @@ public: Delete(realct); } if (!have_constructor) { - Printv(f_shadow_file, tab4, "def __init__(self, *args, **kwargs): raise AttributeError, \"No constructor defined\"\n", NIL); + Printv(f_shadow_file, tab4, "def __init__(self, *args, **kwargs): raise AttributeError(\"No constructor defined\")\n", NIL); } else if (fastinit) { Printv(f_wrappers, "SWIGINTERN PyObject *", class_name, "_swiginit(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {\n", NIL); @@ -2834,13 +3099,15 @@ public: Delete(pycode); fproxy = 0; } else { + String *parms = make_pyParmList(n, true, false, allow_kwargs); + String *callParms = make_pyParmList(n, true, true, allow_kwargs); if (!have_addtofunc(n)) { if (!fastproxy || olddefs) { - Printv(f_shadow, tab4, "def ", symname, "(*args", (allow_kwargs ? ", **kwargs" : ""), "):", NIL); - Printv(f_shadow, " return ", funcCallHelper(Swig_name_member(class_name, symname), allow_kwargs), "\n", NIL); + Printv(f_shadow, tab4, "def ", symname, "(", parms, ")", returnTypeAnnotation(n), ":", NIL); + Printv(f_shadow, " return ", funcCall(Swig_name_member(class_name, symname), callParms), "\n", NIL); } } else { - Printv(f_shadow, tab4, "def ", symname, "(*args", (allow_kwargs ? ", **kwargs" : ""), "):", NIL); + Printv(f_shadow, tab4, "def ", symname, "(",parms , ")", returnTypeAnnotation(n), ":", NIL); Printv(f_shadow, "\n", NIL); if (have_docstring(n)) Printv(f_shadow, tab8, docstring(n, AUTODOC_METHOD, tab8), "\n", NIL); @@ -2850,11 +3117,11 @@ public: } if (have_pythonappend(n)) { fproxy = 0; - Printv(f_shadow, tab8, "val = ", funcCallHelper(Swig_name_member(class_name, symname), allow_kwargs), "\n", NIL); + Printv(f_shadow, tab8, "val = ", funcCall(Swig_name_member(class_name, symname), callParms), "\n", NIL); Printv(f_shadow, tab8, pythonappend(n), "\n", NIL); Printv(f_shadow, tab8, "return val\n\n", NIL); } else { - Printv(f_shadow, tab8, "return ", funcCallHelper(Swig_name_member(class_name, symname), allow_kwargs), "\n\n", NIL); + Printv(f_shadow, tab8, "return ", funcCall(Swig_name_member(class_name, symname), callParms), "\n\n", NIL); } } } @@ -2887,17 +3154,19 @@ public: if (shadow) { if (!classic && !Getattr(n, "feature:python:callback") && have_addtofunc(n)) { int kw = (check_kwargs(n) && !Getattr(n, "sym:overloaded")) ? 1 : 0; - Printv(f_shadow, tab4, "def ", symname, "(*args", (kw ? ", **kwargs" : ""), "):\n", NIL); + String *parms = make_pyParmList(n, true, false, kw); + String *callParms = make_pyParmList(n, true, true, kw); + Printv(f_shadow, tab4, "def ", symname, "(", parms, ")", returnTypeAnnotation(n), ":\n", NIL); if (have_docstring(n)) Printv(f_shadow, tab8, docstring(n, AUTODOC_STATICFUNC, tab8), "\n", NIL); if (have_pythonprepend(n)) Printv(f_shadow, tab8, pythonprepend(n), "\n", NIL); if (have_pythonappend(n)) { - Printv(f_shadow, tab8, "val = ", funcCallHelper(Swig_name_member(class_name, symname), kw), "\n", NIL); + Printv(f_shadow, tab8, "val = ", funcCall(Swig_name_member(class_name, symname), callParms), "\n", NIL); Printv(f_shadow, tab8, pythonappend(n), "\n", NIL); Printv(f_shadow, tab8, "return val\n\n", NIL); } else { - Printv(f_shadow, tab8, "return ", funcCallHelper(Swig_name_member(class_name, symname), kw), "\n\n", NIL); + Printv(f_shadow, tab8, "return ", funcCall(Swig_name_member(class_name, symname), callParms), "\n\n", NIL); } Printv(f_shadow, tab4, modern ? "" : "if _newclass:", symname, " = staticmethod(", symname, ")\n", NIL); @@ -2969,8 +3238,8 @@ public: handled_as_init = (Strcmp(nname, sname) == 0) || (Strcmp(nname, cname) == 0); Delete(cname); } - - if (!have_constructor && handled_as_init) { + + if (!have_constructor && handled_as_init) { if (Getattr(n, "feature:shadow")) { String *pycode = pythoncode(Getattr(n, "feature:shadow"), tab4); String *pyaction = NewStringf("%s.%s", module, Swig_name_construct(symname)); @@ -2984,23 +3253,30 @@ public: String *classname = Swig_class_name(parent); String *rclassname = Swig_class_name(getCurrentClass()); assert(rclassname); - if (use_director) { + + String *parms = make_pyParmList(n, true, false, allow_kwargs); + /* Pass 'self' only if using director */ + String *callParms = make_pyParmList(n, false, true, allow_kwargs); + + if (use_director) { + Insert(callParms, 0, "_self, "); Printv(pass_self, tab8, NIL); Printf(pass_self, "if self.__class__ == %s:\n", classname); - Printv(pass_self, tab8, tab4, "args = (None,) + args\n", tab8, "else:\n", tab8, tab4, "args = (self,) + args\n", NIL); + //Printv(pass_self, tab8, tab4, "args = (None,) + args\n", tab8, "else:\n", tab8, tab4, "args = (self,) + args\n", NIL); + Printv(pass_self, tab8, tab4, "_self = None\n", tab8, "else:\n", tab8, tab4, "_self = self\n", NIL); } - Printv(f_shadow, tab4, "def __init__(self, *args", (allow_kwargs ? ", **kwargs" : ""), "): \n", NIL); + Printv(f_shadow, tab4, "def __init__(", parms, ")", returnTypeAnnotation(n), ": \n", NIL); if (have_docstring(n)) Printv(f_shadow, tab8, docstring(n, AUTODOC_CTOR, tab8), "\n", NIL); if (have_pythonprepend(n)) Printv(f_shadow, tab8, pythonprepend(n), "\n", NIL); Printv(f_shadow, pass_self, NIL); if (fastinit) { - Printv(f_shadow, tab8, module, ".", class_name, "_swiginit(self,", funcCallHelper(Swig_name_construct(symname), allow_kwargs), ")\n", NIL); + Printv(f_shadow, tab8, module, ".", class_name, "_swiginit(self,", funcCall(Swig_name_construct(symname), callParms), ")\n", NIL); } else { Printv(f_shadow, - tab8, "this = ", funcCallHelper(Swig_name_construct(symname), allow_kwargs), "\n", + tab8, "this = ", funcCall(Swig_name_construct(symname), callParms), "\n", tab8, "try: self.this.append(this)\n", tab8, "except: self.this = this\n", NIL); } if (have_pythonappend(n)) @@ -3020,13 +3296,15 @@ public: Printv(f_shadow_stubs, pycode, "\n", NIL); Delete(pycode); } else { + String *parms = make_pyParmList(n, true, false, allow_kwargs); + String *callParms = make_pyParmList(n, true, true, allow_kwargs); - Printv(f_shadow_stubs, "\ndef ", symname, "(*args", (allow_kwargs ? ", **kwargs" : ""), "):\n", NIL); + Printv(f_shadow_stubs, "\ndef ", symname, "(", parms, ")", returnTypeAnnotation(n), ":\n", NIL); if (have_docstring(n)) Printv(f_shadow_stubs, tab4, docstring(n, AUTODOC_CTOR, tab4), "\n", NIL); if (have_pythonprepend(n)) Printv(f_shadow_stubs, tab4, pythonprepend(n), "\n", NIL); - Printv(f_shadow_stubs, tab4, "val = ", funcCallHelper(Swig_name_construct(symname), allow_kwargs), "\n", NIL); + Printv(f_shadow_stubs, tab4, "val = ", funcCall(Swig_name_construct(symname), callParms), "\n", NIL); #ifdef USE_THISOWN Printv(f_shadow_stubs, tab4, "val.thisown = 1\n", NIL); #endif @@ -3605,15 +3883,15 @@ int PYTHON::classDirectorMethod(Node *n, Node *parent, String *super) { if (use_parse || !modernargs) { Printf(w->code, "swig::PyObject_var result = PyObject_CallMethod(swig_get_self(), (char *)\"%s\", (char *)\"(%s)\" %s);\n", pyname, parse_args, arglist); - } else { - Printf(w->code, "swig::PyObject_var swig_method_name = PyString_FromString((char *)\"%s\");\n", pyname); + } else { + Printf(w->code, "swig::PyObject_var swig_method_name = SWIG_Python_str_FromChar((char *)\"%s\");\n", pyname); Printf(w->code, "swig::PyObject_var result = PyObject_CallMethodObjArgs(swig_get_self(), (PyObject *) swig_method_name %s, NULL);\n", arglist); } } else { if (!modernargs) { Printf(w->code, "swig::PyObject_var result = PyObject_CallMethod(swig_get_self(), (char *) \"%s\", NULL);\n", pyname); } else { - Printf(w->code, "swig::PyObject_var swig_method_name = PyString_FromString((char *)\"%s\");\n", pyname); + Printf(w->code, "swig::PyObject_var swig_method_name = SWIG_Python_str_FromChar((char *)\"%s\");\n", pyname); Append(w->code, "swig::PyObject_var result = PyObject_CallMethodObjArgs(swig_get_self(), (PyObject *) swig_method_name, NULL);\n"); } } diff --git a/configure.in b/configure.in index 77ff25aee..8a09cd6f7 100644 --- a/configure.in +++ b/configure.in @@ -573,7 +573,7 @@ else # First figure out the name of the Python executable if test "x$PYBIN" = xyes; then -AC_CHECK_PROGS(PYTHON, python python2.8 python2.7 python2.6 python2.5 python2.4 python2.3 python2.2 python2.1 python2.0 python1.6 python1.5 python1.4 python) +AC_CHECK_PROGS(PYTHON, [python python2.8 python2.7 python2.6 python2.5 python2.4 python2.3 python2.2 python2.1 python2.0 python1.6 python1.5 python1.4 python]) else PYTHON="$PYBIN" fi @@ -657,6 +657,103 @@ AC_SUBST(PYLIB) AC_SUBST(PYLINK) AC_SUBST(PYTHONDYNAMICLINKING) + +#---------------------------------------------------------------- +# Look for Python 3.x +#---------------------------------------------------------------- + +# mostly copy & pasted from "Look for Python" section, +# did some trim, fix and rename + +PY3INCLUDE= +PY3LIB= +PY3PACKAGE= + +AC_ARG_WITH(python3, AS_HELP_STRING([--without-python3], [Disable Python 3.x support]) +AS_HELP_STRING([--with-python3=path], [Set location of Python 3.x executable]),[ PY3BIN="$withval"], [PY3BIN=yes]) + +# First, check for "--without-python3" or "--with-python3=no". +if test x"${PY3BIN}" = xno -o x"${with_alllang}" = xno ; then +AC_MSG_NOTICE([Disabling Python 3.x support]) +else +# First figure out the name of the Python3 executable + +if test "x$PY3BIN" = xyes; then +AC_CHECK_PROGS(PYTHON3, [python3 python3.0]) +else +PYTHON3="$PY3BIN" +fi + +# Check for Python 3.x development tools (header files, static library and python3-config) +AC_CHECK_PROGS(PY3CONFIG, [$PYTHON3-config python3-config python3.0-config]) + +if test -n "$PYTHON3" -a -n "$PY3CONFIG"; then + AC_MSG_CHECKING([for Python 3.x prefix]) + PY3PREFIX=`($PY3CONFIG --prefix) 2>/dev/null` + AC_MSG_RESULT($PY3PREFIX) + AC_MSG_CHECKING(for Python 3.x exec-prefix) + PY3EPREFIX=`($PY3CONFIG --exec-prefix) 2>/dev/null` + AC_MSG_RESULT($PY3EPREFIX) + + # Note: I could not think of a standard way to get the version string from different versions. + # This trick pulls it out of the file location for a standard library file. + + AC_MSG_CHECKING([for Python 3.x version]) + + # Need to do this hack since autoconf replaces __file__ with the name of the configure file + filehack="file__" + PY3VERSION=`($PYTHON3 -c "import string,operator,os.path; print(operator.getitem(os.path.split(operator.getitem(os.path.split(string.__$filehack),0)),1))")` + AC_MSG_RESULT($PY3VERSION) + + # Find the directory for libraries this is necessary to deal with + # platforms that can have apps built for multiple archs: e.g. x86_64 + AC_MSG_CHECKING([for Python 3.x lib dir]) + PY3LIBDIR=`($PYTHON3 -c "import sys; print(sys.lib)") 2>/dev/null` + if test -z "$PY3LIBDIR"; then + # some dists don't have sys.lib so the best we can do is assume lib + PY3LIBDIR="lib" + fi + AC_MSG_RESULT($PY3LIBDIR) + + # Set the include directory + + AC_MSG_CHECKING([for Python 3.x header files]) + PY3INCLUDE=`($PY3CONFIG --includes) 2>/dev/null` + AC_MSG_RESULT($PY3INCLUDE) + + # Set the library directory blindly. This probably won't work with older versions + AC_MSG_CHECKING([for Python 3.x library]) + dirs="$PY3VERSION/config $PY3VERSION/$PY3LIBDIR python/$PY3LIBDIR" + for i in $dirs; do + if test -d $PY3EPREFIX/$PY3LIBDIR/$i; then + PY3LIB="$PY3EPREFIX/$PY3LIBDIR/$i" + break + fi + done + if test -z "$PY3LIB"; then + AC_MSG_RESULT([Not found]) + else + AC_MSG_RESULT($PY3LIB) + fi + + PY3LINK="-l$PY3VERSION" +fi + +# Cygwin (Windows) needs the library for dynamic linking +case $host in +*-*-cygwin* | *-*-mingw*) PYTHON3DYNAMICLINKING="-L$PYLIB $PY3LINK" + DEFS="-DUSE_DL_IMPORT $DEFS" PY3INCLUDE="$PY3INCLUDE" + ;; +*)PYTHON3DYNAMICLINKING="";; +esac +fi + +AC_SUBST(PY3INCLUDE) +AC_SUBST(PY3LIB) +AC_SUBST(PY3LINK) +AC_SUBST(PYTHON3DYNAMICLINKING) + + #---------------------------------------------------------------- # Look for Perl5 #---------------------------------------------------------------- @@ -1856,11 +1953,17 @@ AC_SUBST(SKIP_OCTAVE) SKIP_PYTHON= -if test -z "$PYINCLUDE" || test -z "$PYLIB" ; then +if (test -z "$PYINCLUDE" || test -z "$PYLIB") && + (test -z "$PY3INCLUDE" || test -z "PY3LIB") ; then SKIP_PYTHON="1" fi AC_SUBST(SKIP_PYTHON) +SKIP_PYTHON3= +if test -z "$PY3INCLUDE" || test -z "$PY3LIB" ; then + SKIP_PYTHON3="1" +fi +AC_SUBST(SKIP_PYTHON3) SKIP_JAVA= if test -z "$JAVA" || test -z "$JAVAC" || test -z "$JAVAINC" ; then -- cgit v1.2.1