Python C Api check if PyObject points to a specific PyCFunction - python

I have a module written using the Python C API:
static PyObject* my_func1(PyObject* /*self*/, PyObject* args)
{
Py_RETURN_NONE;
}
static PyObject* my_func2(PyObject* /*self*/, PyObject* args)
{
Py_RETURN_NONE;
}
static PyMethodDef methods[] = {
{"my_func1", (PyCFunction)my_func1, METH_VARARGS, ""},
{"my_func2", (PyCFunction)my_func2, METH_VARARGS, ""},
{NULL, NULL, 0, NULL} /* sentinel */
};
static struct PyModuleDef moduledef = {
PyModuleDef_HEAD_INIT, my_module, NULL, -1, methods, NULL, NULL, NULL, NULL
};
PyMODINIT_FUNC PyInit_my_module(void){
return PyModule_Create(&moduledef);
}
as one of the arguments a user can pass a function e.g.:
my_func1(my_func2)
How can I detect inside my_func1, that the argument the user passed is a function, that points to my_func2 using the Python C API?

You can use PyCFunction_Check to test if an object is a C function and PyCFunction_GetFunction to get the C function pointer. You can then just compare the C function pointers. Relevant header is at https://github.com/python/cpython/blob/4c9ea093cd752a6687864674d34250653653f743/Include/methodobject.h if you want to look at the signatures.
This looks to date back to at least Python 3.6 (probably further) although it's slightly hard to track because they've moved what headers these are defined in a bit.
Note that this is all looks fairly undocumented so you shouldn't rely completely on it not changing.

Related

How to extract class variables and class methods from a java file using Python?

private int OutsideFUnction(){
int yoho;
}
public class Blog implements Subject {
private List<Observer> observers;
private String article;
private boolean changed;int Manaky; int Chahal; String letssee;
public Blog() {
this.observers = new ArrayList<>();
}
#Override
public void register(Observer obj) {
int insideRegister;
if(obj == null) throw new NullPointerException("Null Observer");
if(!observers.contains(obj)) observers.add(obj);
}
#Override
public void unregister(Observer obj) {
observers.remove(obj);
}
public String IAMNotAtStart;
#Override
public void notifyObservers() {
List<Observer> observersLocal = null;
System.out.println("HOOOOOO")
if(!changed) return;
observersLocal = new ArrayList<>(this.observers);
this.changed = false;
for(Observer obj: observersLocal){
obj.update();
}
}
#Override
public Object getUpdate(Observer obj) {
return this.article;
}
public void postBlog(String words){
System.out.println("New Article Posted:"+words);
this.article = words;
this.changed = true;
notifyObservers();
}
}
private nicheWalaFunction OutsideFUnction(){
int lettestNicheWala;
}
I have the above java file. I am reading from this file using Python. My goal is to extract class variables and methods from this file. How can I do that? I don't want variables defined inside a method to be labeled as class variables or methods defined outside the class to be termed class methods. Please guide anyone, how can I do this via a Python snippet.
Use a Python parser for Java, I recommend javalang.

Apache Ignite C++ struct to Pyignite object not working

I am using an Apache Ignite docker container and I want to write data to the cache using C++ and then access it using Pyignite in Python. I have been able to add key-value pairs to the cache in C++ using the Apache Ignite C++ Thin Client and then read them from Python using Pyignite if they key and value are recognized types in both languages, e.g. int, float, string, etc. I want to create key-value pairs where the key is a std::string and the value is a std::map, but I couldn't get that to work in C++, so I decided to follow the directions here to create my C++ struct containing a std::map. I can get/put key-value pairs into the cache in C++, but I haven't been able to get them using Python.
Here's the C++ struct that works:
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <ignite/binary/binary.h>
#include <ignite/thin/ignite_client.h>
#include <ignite/thin/cache/cache_client.h>
using namespace ignite;
using namespace thin;
using namespace cache;
class MyMap
{
friend struct binary::BinaryType<MyMap>;
public:
MyMap() { }
MyMap(std::map<std::string, float> mp) :
mp(mp) { }
std::map<std::string, float> GetMap() const
{
return mp;
}
std::string ToString()
{
std::ostringstream oss;
for(std::map<std::string, float>::const_iterator it = mp.begin();
it != mp.end(); ++it)
{
oss << it->first << ": " << it->second << "\n";
}
return oss.str();
}
std::map<std::string, float> mp;
};
typedef struct MyMap MyMap;
template<>
struct binary::BinaryType<MyMap>
{
static int32_t GetTypeId()
{
return GetBinaryStringHashCode("MyMap");
}
static void GetTypeName(std::string& name)
{
name = "MyMap";
}
static int32_t GetFieldId(const char* name)
{
return GetBinaryStringHashCode(name);
}
static bool IsNull(const MyMap& obj)
{
return obj.GetMap().empty();
}
static void GetNull(MyMap& mymap)
{
mymap = MyMap();
}
static void Write(BinaryWriter& writer, const MyMap& obj)
{
BinaryMapWriter<std::string, float> bmap_writer = writer.WriteMap<std::string, float>("mp");
for(std::map<std::string, float>::const_iterator it = obj.mp.begin(); it != obj.mp.end(); ++it)
{
bmap_writer.Write(it->first, it->second);
}
bmap_writer.Close();
}
static void Read(BinaryReader& reader, MyMap& mymap)
{
BinaryMapReader<std::string, float> bmap_reader = reader.ReadMap<std::string, float>("mp");
std::string key;
float val;
std::map<std::string, float> tmp_map;
while (bmap_reader.HasNext()){
bmap_reader.GetNext(key, val);
tmp_map[key] = val;
}
mymap.mp = tmp_map;
}
};
And here's how I populate the cache:
IgniteClientConfiguration cfg;
cfg.SetEndPoints("ignite_cache");
IgniteClient client = IgniteClient::Start(cfg);
CacheClient<std::string, MyMap> cache = client.GetOrCreateCache<std::string, MyMap>("ignite_cache");
std::string key("my_test_key");
std::map<std::string, float> data_map;
data_map["a"] = 1.0;
data_map["b"] = 2.5;
MyMap mymap (data_map);
cache.Put(key, mymap);
Here's what I'm trying to get working, but haven't been able to in Python:
import pyignite
client = pyignite.Client()
client.connect("ignite_cache", 10800)
my_cache = client.get_or_create_cache("ignite_cache")
key = "my_test_key"
# This returns True
my_cache.contains_key(key)
# I was unable to get pyignite.register_binary_type to work so I tried this
res = pyignite.api.binary.put_binary_type(client, "MyMap", schema={'mp': pyignite.datatypes.MapObject})
# res.message = 'Success'
# This is where it doesn't work - it doesn't break, it just hangs.
my_cache.get(key)
I think my issue is how I am trying to access the cache in Python. If the value is an integer, float, string, or something built-in, then I can do cache.get(key) in Python and it works. And since the C++ code works for both cache.Get and cache.Put (in C++), I think it's something about going between the two languages.
Does anyone have an idea of what I'm doing wrong or how I need to modify either the C++ struct or how I define the binary type in Python?
I'm not sure why it hangs, but try playing around with the client's compact_footer parameter, it might be needed for C++ node.
You may also scan the node's console log for the clues.
As a side note, you don't have to register any types here. Just my_cache.get(key) should be enough.

Python: SWIG: Wrap Access to a Struct

Assume I've got a simple structure with a single field:
typedef struct {
MY_UNICODE value[512];
} TEST_STRUCTURE
Where MY_UNICODE is a custom unicode implementation.
Additionally I've got two methods:
int UTF8ToMyUnicode(char *utf8, MY_UNICODE *unicode);
int MyUnicodeToUTF8(MY_UNICODE *unicode, char *utf8);
To convert from and to this custom type.
Now I can generate a Python interface for this using SWIG.
But when I try to access TESTSTRUCTURE.value in Python. I always get a point to an MY_UNICODE object.
My question is: How do I wrap the access to the member of the struct such that I do get python strings and can set the value using python strings?
I know the documentation of SWIG says something about the memberin typemap.
But my example does not work:
%module test
%include "typemaps.i"
// This is the header file, where the structure and the functions are defined
%include "test.h"
%typemap(memberin) MY_UNICODE [512] {
if(UTF8ToMyUnicode($1, $input) != 0) {
return NULL;
}
}
%typemap(memberout) MY_UNICODE [512] {
if(MyUnicodeToUTF8($1, $input) != 0) {
return NULL;
}
}
In the generated wrapper file, the map has not been applied.
Any help would be appreciated! Thanks!
PS: I'm using swig 2.0.10
I've solved the problem myself. The important thing is that the typemaps need to be defined BEFORE the structures are defined in the interface. The documentation is not clear about that (or I have not seen it). Additionally the "in" and "out" typemaps can than be used to transform the values.
This example works for me:
%module test
%include "typemaps.i"
%typemap(in) MY_UNICODE [512] {
if(UTF8ToMyUnicode($1, $input) != 0) {
return NULL;
}
}
%typemap(out) MY_UNICODE [512] {
if(MyUnicodeToUTF8($1, $result) != 0) {
return NULL;
}
}
// Now include the header file
%include "test.h"

delete a pointer in std::vector exposed by boost::python

I have these two classes:
typedef std::vector<Entity *> EntityPtrVector;
class A
{
private:
EntityPtrVector entity_vector;
public:
void AddEntity(Entity *);
void RemoveEntity(std::string);
};
class Entity
{
private:
std::string name_;
public:
Entity();
Entity(std::string);
std::string GetName(void) const { return name_; }
void SetName(const std::string& name) { name_ = name; }
};
I expose them by boost::python like this:
BOOST_PYTHON_MODULE(my_lib)
{
using namespace boost::python;
class_<EntityPtrVector>("EntityPtrVector")
.def(vector_indexing_suite<EntityPtrVector>());
class_<A>("A", init<std::string>())
.def("AddEntity", &A::AddEntity)
.def("RemoveEntity", &A::RemoveEntity)
;
class_<Entity>("Entity", init<std::string>())
.add_property("name", &Entity::GetName, &Entity::SetName)
;
}
The implementations of AddEntity and RemoveEntity are:
void Game::AddEntity(Entity *E)
{
entity_vector.push_back(E);
}
void Game::RemoveEntity(std::string entity_name)
{
EntityPtrVector::iterator entity_ptr;
// Find the entity with the input name
for(entity_ptr = entity_vector.begin(); entity_ptr != entity_vector.end(); ++entity_ptr)
{
if((*entity_ptr)->GetName() == entity_name)
{
break;
}
}
// Remove the target entity
if(entity_ptr != entity_vector.end())
{
delete *entity_ptr;
entity_vector.erase(entity_ptr);
}
}
I have already checked that it works under C++ without exposed to python. In python, the parts of AddEntity and finding target entity are success, but it crashes at the delete * instruction of RemoveEntity (I check these by adding log instructions after each line of the codes). This is my test code in python:
import my_lib
test_a = my_lib.A("Test A")
test_e = my_lib.Entity("Test Entity")
test_a.AddEntity(test_e)
test_a.RemoveEntity("Test Entity")
I think maybe I do the exposing of std::vector<Entity *> Incorrectly, but how can I correct this?
test_e = my_lib.Entity("Test Entity")
creates a Python object that owns the C++ Entity. It manages the lifetime.
test_a.AddEntity(test_e)
here we pass the C++ object wrapped by test_e to the C++ object wrapped by test_a. The C++ object is stored within the vector of the A.
test_a.RemoveEntity("Test Entity")
this deletes the Entity you added above. However, the test_e class *still thinks it owns the Entity, as there is no way for it to be told you passed ownership away. But now it owns an invalid pointer.
The crash happens at the delete because C++ isn't managing that memory -- python is. It doesn't use the C++ heap.
You need to have a firmer design for ownership and lifetime management in the C++ code. Never delete what you did not new, and the C++ code in the python case never newed that Entity.

python compile error (binding c++)

im trying to implement array in my c++ simulation (this coding provided is to have 2 values in one network packet field)
this is my variable declaration (in header)
Ptr<Name> m_names [2];
this is my function declaration (in header)
void SetName (unsigned which, Ptr<Name> name);
void SetName (unsigned which, const Name &name);
in source file
void Interest::SetName (unsigned which, Ptr<Name> name)
{
if (which < 2)
{
m_names[which] = name;
}
}
void Interest::SetName (unsigned which, const Name &name)
{
if (which < 2)
{
m_names[which] = Create<Name> (name);
}
}
The way I call this is like this (in my main file):
interest->SetName (0, nameWithSequence);
interest->SetName (1, nameWithNextSequence);
as a result it give error like this
src/ndnSIM/bindings/ns3module.cc: In function ‘PyObject* _wrap_PyNs3NdnData_SetName__0(PyNs3NdnData*, PyObject*, PyObject*, PyObject**)’:
src/ndnSIM/bindings/ns3module.cc:8418:62: error: no matching function for call to ‘ns3::ndn::Data::SetName(ns3::Ptr<ns3::ndn::Name>)’
src/ndnSIM/bindings/ns3module.cc:8418:62: note: candidates are:
./ns3/ndn-data.h:60:3: note: void ns3::ndn::Data::SetName(unsigned int, ns3::Ptr<ns3::ndn::Name>)
./ns3/ndn-data.h:60:3: note: candidate expects 2 arguments, 1 provided
the question is what is the correct way should i declare the correct statement. Appreciate any kind of help
EDIT
I have found some of the pyhton definition to bind my c++ code (SetName)
def __setattr__(self, name, value):
if name == "_interest":
return object.__setattr__ (self, name, value)
elif name == "name":
if value is None:
return self._interest.SetName (ns.ndnSIM.ndn.Name ())
elif isinstance (value, Name):
return self._interest.SetName (value._name)
elif isinstance (value, ns.ndnSIM.ndn.Name):
return self._interest.SetName (value)
elif isinstance (value, str):
return self._interest.SetName (ns.ndnSIM.ndn.Name (value))
else:
raise ValueError ("Invalid name parameter")
How and what is the correct way to solve this. Thanks
Okay.. let me just give you an example.
I assume Ptr acts something like std::shared_pointer, and Name like a std::string (at least for an example purposes).
First of all, i'd recommend using std::array instead of a c-style array. But that's not really neccesary.
Second. If you plan m_names to be an array of a fidex size, you can throw an exception when accessing to a non-existent member.
Here is some code.
Header (test.h):
#include <string>
#include <memory>
#include <array>
typedef std::shared_ptr<std::string> pString;
struct A{
protected:
static constexpr size_t array_size = 2;
std::array<pString, array_size> m_names;
static void CheckRange(size_t);
public:
void SetName(size_t id, const std::string& name);
void SetName(size_t id, const pString& name);
const std::string& GetName(size_t id) const;
const pString& GetNamePtr(size_t id) const;
};
Source:
#include "test.h"
#include <exception>
void A::SetName(size_t id, const pString &name){
CheckRange(id);
m_names[id] = name;
}
void A::SetName(size_t id, const std::string& name){
CheckRange(id);
m_names[id] = std::make_shared<std::string>(name);
}
const std::string& A::GetName(size_t id) const{
CheckRange(id);
if (!m_names[id])
throw std::logic_error("Pointer is not initialized");
return *(m_names[id].get());
}
const pString& A::GetNamePtr(size_t id) const {
CheckRange(id);
return m_names[id];
}
And here is an example of a CheckRange function:
void A::CheckRange(size_t id){
if (!(id < array_size))
throw std::logic_error("ID should be < " +
std::to_string(array_size));
}
This code with some tests: http://ideone.com/rUvVhH
Hint
if (m_names[id]) checks if m_names[id] contains a valid pointer (e.g. not nullptr). I suppose Ptr has some similar functionality.
And I believe std::make_shared<T>(...) is similar to Create<T>(...).
Well, as for me, this is more or less correct way to retrieve array content :)
If something is too complicated I'll try to make it easier to understand.
You are welcomed to ask if you have any questions!
The error is at compile time in the Python binding code. So,
If the wrote the binding (wrapper) code yourself (using Python C API or boost::python), you must find where you define SetName binding, it is missing a parameter.
If binding is automatically generated by some tool (like SWIG or SIP), you have to find where the SetName binding is defined: this is what the wrapper tool will use to figure out what code to generate, the mistake is in that definition.
The Python code that you added to your post, setattr, indicates clearly that the self._interest.SetName(obj) calls are wrong: your C++ shows that SetName takes two parameters. If setattr is generated by some tool (ns3?) you have to find how it does this to give it the proper definition of SetName so that setattr will have proper call.

Categories

Resources