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 = ¤t;
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