I am trying to expose a C++ library to python using boost-python. The library actually wraps an underlying C api, so uses raw pointers a lot.
// implementation of function that creates a Request object
inline Request Service::createRequest(const char* operation) const
{
blpapi_Request_t *request;
ExceptionUtil::throwOnError(
blpapi_Service_createRequest(d_handle, &request, operation)
);
return Request(request);
}
// request.h
class Request {
blpapi_Request_t *d_handle;
Element d_elements;
Request& operator=(const Request& rhs); // not implemented
public:
explicit Request(blpapi_Request_t *handle);
Request(RequestRef ref);
Request(Request &src);
};
// request.cpp
BOOST_PYTHON_MODULE(request)
{
class_<blpapi_Request_t>;
class_<Request, boost::noncopyable>("Request", init<blpapi_Request_t *>())
.def(init<Request&>())
;
}
Although request.cpp compiles successfully, when I try and use the object I get the following error:
// error output
TypeError: No to_python (by-value) converter found for C++ type: class Request
In-order to call this the python code looks like:
from session import *
from service import *
from request import *
so = SessionOptions()
so.setServerHost('localhost')
so.setServerPort(8194)
session = Session(so)
# start sesssion
if not session.start():
print 'Failed to start session'
raise Exception
if not session.openService('//blp/refdata'):
print 'Failed to open service //blp/refdata'
raise Exception
service = session.getService('//blp/refdata')
request = service.createRequest('ReferenceDataRequest')
The other objects (SessionOptions, Session, Service) etc are also c++ objects that I have successfully created boost-python wrappers for.
As I understand from the boost-python docs this has something to do with passing a raw pointer around, but I don't really understand what else I should do ...
Your class_<blpapi_Request_t>; does not declare anything; is that code the correct version?
If so, then update it:
class_<blpapi_Request_t>("blpapi_Request_t");
That said, what that error indicates is that you are trying to use the Request object with an automatic conversion to a python object which has not been defined.
The reason you get this error is because you have wrapped Request as boost::noncopyable, then provided a factory method which returns a Request object by value; the boost::noncopyable means no copy constructors are generated and therefore there's no automatic to-python converter.
Two ways out of this: one is to remove the noncopyable hint; the other would be to register a converter which takes a C++ Request and returns a Python Request object. Do you really need the noncopyable semantics for Request?
Related
On my generated protobuf classes, I see only set_allocated_something.
Example:
syntax = "proto3";
import "uuid.proto";
import "openvpn.proto";
package message;
message VPN {
UUID uuid = 1;
oneof vpn {
OpenVPN openVPN = 2;
}
}
then I have:
OpenVPN openVPN;
//fill openVPN
auto vpnAny = someObject.add_vpns();
vpnAny->set_allocated_openvpn(&openVPN);
The following code crashes because I'm adding an object for which I own the data, and then set_allocated_openvpn is going to delete it first, then the scope is going to delete it a second time.
The alternative would be to do
OpenVPN* openVPN = new OpenVPN();
but I want to avoid raw pointers + new.
Why simply won't protobuf generate a method that copies the data? Why I can only pass allocated data pointer? And how should I deal with this situation?
Protobuf generates copy constructors and copy assignment operators for every type. So the most normal way to copy a message into another would be something like
OpenVPN openVPN;
// (...)
*someObject.add_vpns() = openVPN;
I have implemented a service in C++ using gSoap. I have created it from a multiple existing WSDL files.
And now I need to give a definition to every virtual method of the service.
Let's take a look at one generated method declaration in the file soapMyServiceService.h:
///
/// Service operations (you should define these):
/// Note: compile with -DWITH_PURE_VIRTUAL for pure virtual methods
///
/// Web service operation 'Initialize' (returns error code or SOAP_OK)
virtual int Initialize(_ns5__Initialize *ns5__Initialize, _ns5__InitializeResponse *ns5__InitializeResponse);
Actually, I was expecting to get :
virtial string Initialize(int var_a , int var_b , string var_c);
But now, I need to implement it what I got generated and return the SOAP code :
int MyService::Initialize(_ns5__Initialize *ns5__Initialize, _ns5__InitializeResponse *ns5__InitializeResponse)
{
// HOW can I get here the received values for that I can able to implement my logic?
return SOAP_OK;
}
How can I get the received values ( the values sent by the client for var_a, var_b, and var_c) and then set for him the returned for the string and in the same time return the error code...
How do you normally implement the logic of the services?
Thank you.
In your service method implementation MyService::Initialize(_ns5__Initialize *ns5__Initialize, _ns5__InitializeResponse *ns5__InitializeResponse)
the last argument is the response argument all the rest are input argument, here you have only one input parameter that is of type _ns5__Initialize which probably wud be a structure, if you access its member, you will get all the input parameters of the request.
I have Junit test that is testing jms message sending. I am using Spring jmsTemplate to to do this. Here I as in the following code I want to check whether the JMS template has called send message regardless what is it in the values of actuall parameters that are passed.
my publisher method the uses the jmsTemplate to send method looks like following inside..
jmsTemplate.send(jmsQueueProperties.getProperty(key), new MessageCreator()
{
public Message createMessage(Session session) throws JMSException
{
ObjectMessage obj = session.createObjectMessage(dialogueServiceResponse);
return obj;
}
});
in My tests..
JmsTemplate mockTemplate = Mockito.mock(JmsTemplate.class);
...
publisher.publishServiceMessage(response);
....
Mockito.verify(mockTemplate,
Mockito.times(1)).send("appointment.queue",
Mockito.any(MessageCreator.class));
But when in the execution i get
org.mockito.exceptions.misusing.InvalidUseOfMatchersException: Invalid use of argument matchers!
....
Cause is due to Mockito.any(MessageCreator.class) , but isn't there a way to test my send method is getting executed without creating an actual object in the MessageCreator.
Update
And is there a way to check my session.createObjectMessage(dialogueServiceResponse) is getting called as well
I think the rest of the message tells you what the problem is. When you use an argument matcher for one of the arguments, all the other arguments must also use an argument matcher:
Mockito.verify(mockTemplate, Mockito.times(1)).send(
Mockito.eq("appointment.queue"),
Mockito.any(MessageCreator.class));
For future readers. This will save you a lot of time.
We cannot use argument matcher and primitive/raw values together.
when(fooService.getResult("string",any(MyClass.class))).thenReturn(1); // will give error
when(fooService.getResult(anyString(),any(MyClass.class))).thenReturn(1); // correct
I think you cannot use argument matchers outside stubbing. I also got the same error but when I return, I had to do new string() instead of Mockito.anyString() and the error goes away.
Example:
Mockito.when(mockedBean.mockedMethod(Mockito.anyString(),
Mockito.anyInt(),
Mockito.anyInt(),
Mockito.anyInt(),
Mockito.anyBoolean())).thenReturn(new String());
I can see that this question is about Java code, but I will share this because we use Mockito in Scala as well.
I had this exception thrown from the following code that mocks Play.api configurations
"Configurations Service" should {
"return all dataset configurations" in {
val configs = mock[Configuration]
val testData = Seq("SOME VALUE")
val loader = any[ConfigLoader[Seq[String]]]
when(configs.get[Seq[String]](any[String])).thenReturn(testData) // EXCEPTIONN HERE !
val configuration: ConfigurationsService = new ConfigurationsService(configs)
assert(configuration.getSupportedDatasets() == testData)
}
}
In Scala methods can have Implicit parameters configs.get method has one explicit param and an Implicit one I passed a mock object and when an exception was thrown I was wondering what is going on as I didn't MIX params and mocks, it turned out that I had to pass mocks to implicit parameters as well, and this solved the problem.
val loader = any[ConfigLoader[Seq[String]]] // configs.get has one implicit parameter that accepts ConfigLoader[Seq[String]]
when(configs.get[Seq[String]](any[String])(loader)).thenReturn(testData)
I was seeing this error about a mismatched # of arguments, despite having the correct number...
I realized this was because method being stubbed was static. When I converted it to non-static, it worked as expected.
I would like to use a simple libxml2 parser in a C++ program the following way:
default sax handler is fine (actually I'd like to avoid the effort of writing my own. I understand that I can do what I want with a custom sax handler)
the parser should be embedded in a C++ class that can be instantiated arbitrarily (possibly multi-threaded), the libxml2 parser context as member var
there are other components also using libxml2 but out of my control (I cannot
exactly tell what they do and how they use libxml2)
in the C++ class I want to use a custom error handler that does not just prints to stderr but I want to collect the errors and throw an exception
Example:
class XmlParser
{
public:
XmlDoc * parseText(const char * txt, ...);
private:
xmlParserCtxtPtr ctx;
static void xmlErrorHandler(void * userData, xmlErrorPtr err);
}
Here is what does NOT work (to my testing and understanding):
use xmlSetStructuredErrorFunc() or xmlSetGenericErrorFunc() and set the current C++ instance as user data because these funcs just set a global var (not thread-safe)
use xmlNewParserCtxt() and set ctx->sax->serror to a regular C++ method - error handler must be static
same as previous but with a static class method - actually that does work but at the same time I want to set ctx->user_data (to 'this' of the current C++ instance) - that makes the parser crash, it looks as if inside of libxml2 ctx->user_data is passed through the functions where there should be just ctx ... however that happens consistently, i.e. looks rather like a feature than a bug :-)
Now, has anybody an idea how to get this to work?
Many thx!!!
So I'm working on a little project in which I'm using Python as an embedded scripting engine. So far I've not had much trouble with it using boost.python, but there's something I'd like to do with it if it's possible.
Basically, Python can be used to extend my C++ classes by adding functions and even data values to the class. I'd like to be able to have these persist in the C++ side, so one python function can add data members to a class, and then later the same instance passed to a different function will still have them. The goal here being to write a generic core engine in C++, and let users extend it in Python in any way they need without ever having to touch the C++.
So what I thought would work was that I would store a boost::python::object in the C++ class as a value self, and when calling the python from the C++, I'd send that python object through boost::python::ptr(), so that modifications on the python side would persist back to the C++ class. Unfortunately when I try this, I get the following error:
TypeError: No to_python (by-value) converter found for C++ type: boost::python::api::object
Is there any way of passing an object directly to a python function like that, or any other way I can go about this to achieve my desired result?
Thanks in advance for any help. :)
Got this fantastic solution from the c++sig mailing list.
Implement a std::map<std::string, boost::python::object> in the C++ class, then overload __getattr__() and __setattr__() to read from and write to that std::map. Then just send it to the python with boost::python::ptr() as usual, no need to keep an object around on the C++ side or send one to the python. It works perfectly.
Edit: I also found I had to override the __setattr__() function in a special way as it was breaking things I added with add_property(). Those things worked fine when getting them, since python checks a class's attributes before calling __getattr__(), but there's no such check with __setattr__(). It just calls it directly. So I had to make some changes to turn this into a full solution. Here's the full implementation of the solution:
First create a global variable:
boost::python::object PyMyModule_global;
Create a class as follows (with whatever other information you want to add to it):
class MyClass
{
public:
//Python checks the class attributes before it calls __getattr__ so we don't have to do anything special here.
boost::python::object Py_GetAttr(std::string str)
{
if(dict.find(str) == dict.end())
{
PyErr_SetString(PyExc_AttributeError, JFormat::format("MyClass instance has no attribute '{0}'", str).c_str());
throw boost::python::error_already_set();
}
return dict[str];
}
//However, with __setattr__, python doesn't do anything with the class attributes first, it just calls __setattr__.
//Which means anything that's been defined as a class attribute won't be modified here - including things set with
//add_property(), def_readwrite(), etc.
void Py_SetAttr(std::string str, boost::python::object val)
{
try
{
//First we check to see if the class has an attribute by this name.
boost::python::object obj = PyMyModule_global["MyClass"].attr(str.c_str());
//If so, we call the old cached __setattr__ function.
PyMyModule_global["MyClass"].attr("__setattr_old__")(ptr(this), str, val);
}
catch(boost::python::error_already_set &e)
{
//If it threw an exception, that means that there is no such attribute.
//Put it on the persistent dict.
PyErr_Clear();
dict[str] = val;
}
}
private:
std::map<std::string, boost::python::object> dict;
};
Then define the python module as follows, adding whatever other defs and properties you want:
BOOST_PYTHON_MODULE(MyModule)
{
boost::python::class_<MyClass>("MyClass", boost::python::no_init)
.def("__getattr__", &MyClass::Py_GetAttr)
.def("__setattr_new__", &MyClass::Py_SetAttr);
}
Then initialize python:
void PyInit()
{
//Initialize module
PyImport_AppendInittab( "MyModule", &initMyModule );
//Initialize Python
Py_Initialize();
//Grab __main__ and its globals
boost::python::object main = boost::python::import("__main__");
boost::python::object global = main.attr("__dict__");
//Import the module and grab its globals
boost::python::object PyMyModule = boost::python::import("MyModule");
global["MyModule"] = PyMyModule;
PyMyModule_global = PyMyModule.attr("__dict__");
//Overload MyClass's setattr, so that it will work with already defined attributes while persisting new ones
PyMyModule_global["MyClass"].attr("__setattr_old__") = PyMyModule_global["MyClass"].attr("__setattr__");
PyMyModule_global["MyClass"].attr("__setattr__") = PyMyModule_global["MyClass"].attr("__setattr_new__");
}
Once you've done all of this, you'll be able to persist changes to the instance made in python over to the C++. Anything that's defined in C++ as an attribute will be handled properly, and anything that's not will be appended to dict instead of the class's __dict__.