I am trying to call a c function or c program from python using cffi, but I find most examples too complex for me to easily learn from. One of the best examples I have found is this example and I have copied that and made a slightly simpler version that I want to post here.
I would greatly appreciate any feedback on this example or I am hoping someone could make an even shorter and simpler example of using cffi in python for API out of line and inline and maybe even a super simple ABI example. I am impressed with how easy this is to call a simple adding function, a lot easier than calling c from Lua.
So it seems to work, but I am still not really sure why and not sure how well my more complex real example will work because I don't really know what I am doing. Incidentally this was the very first python program I have written or run. My 'hello world'. My purpose is to call a 1000 line c program I wrote from a python script to be run with the openlightspeed web server.
I am using Ubuntu 19.10. First I installed Pip with apt install python-pip. Then I installed cffi with pip install cffi which also pulled in pycparser. Then I made 4 files in my home directory: add.c, add.h, build.py, and add.py which are as follows:
add.c:
#include "add.h" //if you don't have a header file you will get a warning
int addme(int a, int b)
{
return (a + b);
}
add.h
int addme(int a, int b);
build.py:
from cffi import FFI
ffibuilder = FFI()
ffibuilder.cdef("int addme(int a, int b);")
ffibuilder.set_source("pyadd",'#include "add.h"',sources=["add.c"])
ffibuilder.compile()
add.py:
from pyadd.lib import addme
print(addme(2,6))
I entered python build.py which created pyadd.so which I was then able to import into my python script. Then I entered python add.py which returned 8. The first argument in set_source() is the name of the shared object that you will then import in your python script. Both "from pyadd.lib import addme" and "from pyadd import lib" seem to work but with the latter you have to refer to addme as "lib.addme". This must just be a python thing.
Related
I'm using pyinstaller to distribute my code as executable within my team as most of them are not coding/scripting people and do not have Python Interpreter installed.
For some advanced usage of my tool, I want to make it possible for the user to implement a small custom function to adjust functionality slightly (for the few experienced people). Hence I want to let them input a python file which defines a function with a fixed name and a string as return.
Is that possible?
I mean the py-file could be drag/dropped for example, and I'd tell them that their user-defined function needs to have a certain name, e.g. "analyze()" - is it now possible to import that from the drag/dropped pythonfile within my PyInstaller Script and use it as this?
I know, it certainly will not be safe/secure and they could do evil things, delete files and so one... But that are things which we don#t care at this point, please no discussions about it. Thanks!
To answer my own question: yes it does actually work to import a module/function from a given path/pythonfile at runtime (that I knew already) even in PyInstaller (that was new for me).
I used this for my Py2.7 program:
f = r'C:\path\to\userdefined\filewithfunction.py'
if os.path.exists(f):
import imp
userdefined = imp.load_source('', f) # Only Python 2.x, for 3.x see: https://stackoverflow.com/a/67692/701049
print userdefined # just a debugging print
userdefined.imported() # here you should use try/catch; or check whether the function with the desired name really exists in the object "userdefined". This is only a small demo as example how to import, so didnt do it here.
filewithfunction.py:
--------------------
def imported():
print 'yes it worked :-)'
As written in the comments of the example code, you'll need a slightly different approach in Python 3.x. See this link: https://stackoverflow.com/a/67692/701049
I'm really new to python and I have made the following program:
class AddressBook:
def __init__(self):
self.b = {}
def insert(self,name, phone):
self.b[name]=phone
print "I am confused"
def get(self,name):
return self.b[name]
def has_name(self,name):
return self.b.has_key(name)
def list(self):
for n,p in self.b.iteritems():
print n,p
def delete(self, name):
del self.b[name]
def orderedList(self):
orderedkeys = self.b.keys()
orderedkeys.sort()
for n in orderedkeys:
print n, self.b[n]
I now want to compile it test it out in terminal to see if it all works.
I went to the directory and compiled it with
python address.py
Now I want to add things to the list, print the contents of the list, delete them (pretty much play around with my program) but I don't know how...
After compiling, how do I manually test (play around) with my python program?
Thanks in advance.
Python is an interpreted language, and .py files do not require direct compilation. There are a few ways to run Python code, but for "playing around" you can simply activate the Python interpreter and import the class.
In a command prompt:
> python
In Python:
>>> from address import AddressBook
>>> a = Addressbook()
>>> a.insert("Jenny", "867-5309")
>>> a.get("Jenny")
'867-5309'
The python script is not compiled. At least not in ways as other languages, like Fortran and C. From this answer:
Python has a compiler! You just don't notice it because it runs automatically. You can tell it's there, though: look at the .pyc (or .pyo if you have the optimizer turned on) files that are generated for modules that you import.
Also, it does not compile to the native machine's code. Instead, it compiles to a byte code that is used by a virtual machine. The virtual machine is itself a compiled program. This is very similar to how Java works; so similar, in fact, that there is a Python variant (Jython) that compiles to the Java Virtual Machine's byte code instead! There's also IronPython, which compiles to Microsoft's CLR (used by .NET). (The normal Python byte code compiler is sometimes called CPython to disambiguate it from these alternatives.)
You have two ways to test it out:
type python -i address.py in the terminal. This will run the script and enter the python shell.
You enter the python shell and then type from address.py import AddressBook.
On both ways, you can
play around with your code.
Can I use Python code and libraries in Racket? I have installed PyonR (https://github.com/pedropramos/PyonR) in DrRacket so I can choose "#lang python" and run Python code. But how can I combine Racket and Python language codes for my application?
There is also a limited Python to Lisp translator at https://github.com/nurv/pnil . Is there something similar for Racket?
Edit: As advised in comments, I tried following. This python code in file "pysamples.rkt" works well in DrRacket:
#lang python
def greet(name):
print 'Hello', name
greet('Alfred')
Output:
Hello Alfred
I tried using above definition in Racket code, but it did not work. Following is the Racket code:
#lang racket
; (require python/config) (enable-cpyimport!) ; ran this once; worked.
(#%require "pysamples.rkt")
(greet "Racket_code")
The error is:
greet: unbound identifier in module in: greet
The PyonR project is the closest ready-to-use way of using Python libraries from Racket that I know of. However note that there is a difference between Python libraries written in Python and Python libraries that are a thin Python layer on top of a C library. As you have experienced the latter type is not working (to my knowledge at least - but Pedro is the one to ask).
If you need to use a library written in language X (for X could be Python) you can always write a "listener" program in language X that waits for messages from a Racket program, and when a message is received, computes an answer and sends it back to the Racket program. How to send and receive messages is up to you, but a simple option is to have two files, one "R-to-X" which Racket writes to and X reads from, and another "X-to-R" where Racket receives the messages.
This approach has some overhead, but if the computation takes longer than sending the message, then it is a viable solution.
Accoring to the readme you can import python 2.7 packages, but you need to use cpyimport. One of the examples looks like this:
#lang python
cpyimport numpy as np
from "racket" import time
def add_arrays(n):
result = np.zeros((100,100))
for i in range(n):
result += np.random.randint(0, 100000, (100,100))
return result
print time(add_arrays(10000))
Looking at the code, a pure python library you could just import give that it's in rackets paths and was given #lang python top line. all defined are always exported.
The previous answers and comments addressed difficulties with certain Python libraries, but if you're just interested in using a function from a pure Python file in a Racket module, try something like this:
In file "greetings.py":
#lang python
def greet(name):
print 'Hello', name
In Racket:
#lang racket
(require python)
(py-import "greetings" as python-module)
(py-method-call python-module "greet" "Racket")
Given a string, I'd like to be able to send a set of keystrokes to type that string and I'd like to be able to do it in python on OSX (in python because it's part of a larger project already written in python, on OSX because I am trying to port it to OSX).
I'm able to do this now using pyobj like so (this is somewhat simplified):
from Quartz import *
CHAR_TO_SEQUENCE = {
'a':[(0, True), (0, False)]
}
def send_string(string):
for c in string:
sequence = CHAR_TO_SEQUENCE[c]
for keycode, key_down in sequence:
CGEventPost(kCGSessionEventTap, CGEventCreateKeyboardEvent(None, keycode, key_down))
and I've fleshed out CHAR_TO_SEQUENCE to include most of what I can type on my keyboard, which took a while and was tedious.
The problems with this are:
- It only works while the keyboard has the ANSII standard layout. If someone uses a french keyboard, for example, it will type the wrong things.
- It requires this ridiculous table.
I found this general solution for OSX but couldn't figure out how to apply it to python:
How to convert ASCII character to CGKeyCode?
The API mentioned there doesn't seem to be available via pyobj (or maybe I just couldn't figure out the import path).
I've seen some suggestions to set CGEventKeyboardSetUnicodeString to the desired string and not worry about the keycode. But I wasn't able to figure out how to call CGEventKeyboardSetUnicodeString from python (I can't get the arguments right) and it's not clear that this will work because the documentation says that applications can choose to ignore this in favor of the keycode.
Is there a way to do this in python on OSX?
It looks like the Carbon modules don't wrap the TIS* functions, and neither does anything else.
You could extend PyObjC, but it's much simpler to just build a trivial extension module that wraps the two functions you actually need.
Since it was faster to just do it than to explain how to do it, you can get it from https://github.com/abarnert/pykeycode and just do the usual "python setup.py build_ext --inplace" or "sudo python setup.py install", then look at test.py to see how to use it.
I want to use the UDT library in Python, so I need a wrapper. I found this one: pyudt, but I dont know exactly how to use this to send files from a peer to peer. Can anybody point me in the right direction?
after so many time I've found this question and its solution:
The steps to install pyudt-0.1a are:
install:
libboost-python1.46-dev or equivalent
(for instance, in linux-ubuntu12.04 it's in the reps.)
install udt.h (from: http://sourceforge.net/projects/udt/) into a system directory,
OR
(put the udt.h file in the same path as the pyudt-0.1a files, and then change a line of the "pyudt.cpp", from:
#include <udt.h>
to:
#include "udt.h"
).
update the version of boost_python library, in "setup.py" to the one you're
using,
eg.:
... libraries=['udt', 'boost_python-py27'])
change the following line(s) in "pyudt.cpp":
you must correct a bug, changing from:
int r = UDT::send(_sock, data.c_str(), data.length(), 0);
to:
int r = UDT::send(_sock, data.c_str(), data.length()+1, 0);
because the character "\0" meaning the end of string must also be sent, otherwise junk would be appended to your string.
optionally, you may choose between:
_sock = UDT::socket(AF_INET, SOCK_DGRAM, 0); --» default
or:
_sock = UDT::socket(AF_INET, SOCK_STREAM, 0); --» optional
finally, run,
in the corresponding folder:
python2.7 ./setup.py build
sudo python2.7 ./setup.py install
OR, (if you don't have admin permissions to install it for all the users, and just wanna try it for you:
python2.7 ./setup.py build
python2.7 ./setup.py install --prefix=~/pyudt-0.1a/installation_dir/ #in this case, pyudt would only work if called from that directory
)
Then, the code for a simple client can be:
import pyudt
socket = pyudt.pyudt_socket()
socket.connect(("127.0.0.1", 7000))
socket.send("hello_world!")
and it works, it talks with my cpp server!
notice: if you need more help you can write in the python's console:
import pyudt
dir(pyudt.pyudt_socket) # to list the available functions
help(pyudt) # to get more help
PS. the files created with this installation tutorial are:
/usr/local/lib/python2.7/dist-packages/pyudt.so, and /usr/local/lib/python2.7/dist-packages/pyudt-0.1a.egg-info
You can give my udt_py fork a try. It includes a sample recvfile.py now and can retrieve files from the sendfile daemon in udt's app directory.