Re: Python iterator / SWIG newbie

<[email protected]> Sun, 20 Jun 2021 09:49:17 -0700
Newsgroups gmane.comp.programming.swig
Message-ID <[email protected]>
Dear William,

 

Thank you, this was very helpful.  I did have to change your $result to $actionresult as $result was a Python object that wasn’t set yet (the error was confusing, but it was obvious to see in the generated wrap code).  I ended up moving all of the Python code out of the C++ iterator and using the following which works perfectly:

 

%exception DbXml::XmlResultsIterator::__next__() %{

  $action

  if (! $actionresult) {

      PyErr_SetString(PyExc_StopIteration, "No more results");

      SWIG_fail;

  }

%}

 

All my best,

Marie

 

From: William S Fulton <[email protected]> 
Sent: Sunday, June 20, 2021 1:44 AM
To: [email protected]
Cc: swig-user <[email protected]>
Subject: Re: [Swig-user] Python iterator / SWIG newbie

 

 

 

On Sat, 19 Jun 2021 at 01:28, <[email protected] <mailto:[email protected]> > wrote:

Dear Swig Users,

 

I am trying to wrap an Oracle library for Python.  They have a C++ iterator that expects a reference for the next value and returns a boolean.  I thought it would be as easy as writing a new C++ class that contained an instance of the object in question and extending the class to create a new instance of my iterator class.  I implemented the new iterator class as a C++ inline class (header) below:

 

namespace DbXml {

 

  class XmlResultsIterator

  {

  public:

 

    XmlValue current;  // holds current value of iterator

    XmlResults *iterable;  // object over which we will iterate

  

    inline XmlResultsIterator(XmlResults *results) {

      iterable = results;  // store the object over which we will iterate

    }

 

    inline XmlValue *__next__() {

      // __next__  [comments deleted for brevity]

 

      XmlValue *retval;

      bool ok = iterable->next(current);  // get next

      if (ok)

              retval = &current;

      else {

              PyErr_SetNone(PyExc_StopIteration); // no more values, stop iteration error

              retval = nullptr;

      }

      return retval;

    }

  }; 

}

 

I %include the header, and the iteration starts fine.  However, when I hit the ok == false case, I see the following error in Python 3.9:

 

  File "u:\Users\...\Python39\lib\site-packages\dbxml.py", line 1662, in __next__

    return _dbxml.XmlResultsIterator___next__(self)

SystemError: <built-in function XmlResultsIterator___next__> returned a result with an error set

 

During handling of the above exception, another exception occurred:

Traceback (most recent call last):

  File "c:\apps\develop\dbxml-6.1.4\dbxml\examples\python3\examples.py", line 496, in <module>

    do_example(number)

  File "c:\apps\develop\dbxml-6.1.4\dbxml\examples\python3\examples.py", line 474, in do_example

    globals()["example%02d" % number]()

  File "c:\apps\develop\dbxml-6.1.4\dbxml\examples\python3\examples.py", line 69, in example02

    for value in results:

TypeError: catching classes that do not inherit from BaseException is not allowed

 

I suspect that I am doing something stupid like not including a %except or %typemap that I need, but I’ve been going over the documentation as well as examples in user groups and it is not clear to me what I am doing wrong.  Directors are enabled (%module(directors=”1”,…)).

 

 

Look in the docs at %exception and add this before __next__ is parsed:

 

%exception DbXml::XmlResultsIterator::__next__() %{
$action
if (!$result) SWIG_fail;
%}

It allows you to check for nullptr return from __next__ before calling any Python APIs.

 

William

_______________________________________________
Swig-user mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/swig-user