Using Ctypes to Configure DLL functions - ctypes

I have a shared library file (windows DLL) that contains about 50 functions. The functions in the DLL have return values and arguments that need to be configured using .argtypes and .restype. I want to create a module that I can import into my python programs that does the configuration. For example -- the following code works fine in my program (Open, Close, Save are example functions of "mydll":
import ctypes as ct
mylib = ct.cdll.LoadLibrary("mydll")
mylib.Open.argtypes = [ct.c_char_p]
mylib.Open.restype = ct.c_int
mylib.Close.argtypes = [ct.c_int]
mylib.Close.restype = ct.c_int
mylib.Save.argtypes = [ct.c_int]
mylib.Save.restype = ct.c_int
#continue for 50 or so more functions
I would like to create a package or module that I can import for this code, instead of including it at the beginning of each program that will use "mydll". What is the correct approach in Python?

I was able to resolve this by writing a binding.py file that includes a function for each function in the library, mydll.
So binding.py looks like this:
import ctypes as ct
mylib = ct.cdll.LoadLibrary("mydll")
def func1():
mylib.func1().argtypes = [ct.c_char_p]
mylib.func1().restype = ct.c_int
return mylib.func1()
def func2():
mylib.func2().argtypes = [ct.c_int, ct.c_char_p, ct.POINTER(ct.c_double)]
mylib.func2().restype = ct.c_int
return mylib.func2()
def func3():
mylib.func3().argtypes = []
mylib.func3().restype = ct.c_int
return mylib.func3()
The fundamental data types for the argument and return values can be found here:
[cytpes fundamental data types][1]
[1]: https://docs.python.org/3/library/ctypes.html

Related

How to call a function inside a function that is created in seperate python files?

I have written the two functions below in the same python file. If I print the answer function it returns the answer of 7 which is expected.
The second function is calling the first function to get the answer.
If I create two python files as below and run it there is an error NameError: name 'math' is not defined.
Why am I not able to create the function that is required to run answer() in the second python file?
I have tried referencing math = 0 to give it a starting variable. My goal is to be able to build functions that I can import into the main python file where that function uses functions created in the main file. The two files are p1.py and p2.py
def math(x,y):
answer = x + y
return answer
def answer():
answer = math(5,2)
return answer
print(answer())
# Returns the answer of 7
def answer():
answer = math(5,2)
return answer
import p1
def math(x,y):
answer = x + y
return answer
print(answer())
# Returns NameError: name 'math' is not defined.
There are a few ways to make it work, you can make answer take a function as an argument:
def answer(math):
answer = math(5,2)
return answer
and call it with answer(math), or you could import it in p1.py by adding from p2 import math.

Count the number of people having a property bounded by two numbers

The following code goes over the 10 pages of JSON returned by GET request to the URL.
and checks how many records satisfy the condition that bloodPressureDiastole is between the specified limits. It does the job, but I was wondering if there was a better or cleaner way to achieve this in python
import urllib.request
import urllib.parse
import json
baseUrl = 'https://jsonmock.hackerrank.com/api/medical_records?page='
count = 0
for i in range(1, 11):
url = baseUrl+str(i)
f = urllib.request.urlopen(url)
response = f.read().decode('utf-8')
response = json.loads(response)
lowerlimit = 110
upperlimit = 120
for elem in response['data']:
bd = elem['vitals']['bloodPressureDiastole']
if bd >= lowerlimit and bd <= upperlimit:
count = count+1
print(count)
There is no access through fields to json content because you get dict object from json.loads (see translation scheme here). It realises access via __getitem__ method (dict[key]) instead of __getattr__ (object.field) as keys may be any hashible objects not only strings. Moreover, even strings cannot serve as fields if they starts with digits or are the same with built-in dictionary methods.
Despite this, you can define your own custom class realising desired behavior with acceptable key names. json.loads has an argument object_hook wherein you may put any callable object (function or class) that take a dict as the sole argument (not only the resulted one but every one in json recursively) & return something as the result. If your jsons match some template, you can define a class with predefined fields for the json content & even with methods in order to get a robust Python-object, a part of your domain logic.
For instance, let's realise the access through fields. I get json content from response.json method from requests but it has the same arguments as in json package. Comments in code contain remarks about how to make your code more pythonic.
from collections import Counter
from requests import get
class CustomJSON(dict):
def __getattr__(self, key):
return self[key]
def __setattr__(self, key, value):
self[key] = value
LOWER_LIMIT = 110 # Constants should be in uppercase.
UPPER_LIMIT = 120
base_url = 'https://jsonmock.hackerrank.com/api/medical_records'
# It is better use special tools for handling URLs
# in order to evade possible exceptions in the future.
# By the way, your option could look clearer with f-strings
# that can put values from variables (not only) in-place:
# url = f'https://jsonmock.hackerrank.com/api/medical_records?page={i}'
counter = Counter(normal_pressure=0)
# It might be left as it was. This option is useful
# in case of additional counting any other information.
for page_number in range(1, 11):
records = get(
base_url, data={"page": page_number}
).json(object_hook=CustomJSON)
# Python has a pile of libraries for handling url requests & responses.
# urllib is a standard library rewritten from scratch for Python 3.
# However, there is a more featured (connection pooling, redirections, proxi,
# SSL verification &c.) & convenient third-party
# (this is the only disadvantage) library: urllib3.
# Based on it, requests provides an easier, more convenient & friendlier way
# to work with url-requests. So I highly recommend using it
# unless you are aiming for complex connections & url-processing.
for elem in records.data:
if LOWER_LIMIT <= elem.vitals.bloodPressureDiastole <= UPPER_LIMIT:
counter["normal_pressure"] += 1
print(counter)

How to receive data from buildin function of another class in another module

I am programming a case manager (administration system). To build it constructively, I program in separate modules to keep an overview. Some modules contain a class-object where I build an small search engine including its own functions. The main program is the case form itself. Obviously, when the search engine finds an entry, it should fill in the case form. I am able to call the search engine (and the search engine works to), however I don't know how to return the results back to the main program/case form/module.
To give you a picture, I have added a image of the GUI, so you can see the case form and the search engine (which is a different module and class (inheriting tk.Toplevel)
The relevant code (case_form/main program):
import ReferenceSearch as rs #Own module
def search_ref(self):
#Function to call search engine
search_engine = rs.ReferenceSearch(self, self.csv_file.get(), self.references_list)
#Reveive data from search_engine and show it in case_form
self.title_var.set(search_engine) #DOES NOT WORK BECAUSE search_engine IS THE ACTUAL ENGINE NOT THE
DATA returned from its buildin function
Relevant code in ReferenceSearch module:
class ReferenceSearch(tk.Toplevel):
def __init__(self, parent, csv_file,references_list=[]):
super().__init__()
self.parent = parent
self.csv_file = csv_file
self.references_list = references_list
self.ref_search_entry = ttk.Entry(self.search_frame)
self.search_but = tk.Button(self.search_frame,
text=" Search ",
command=lambda:self.search_for_ref(self.ref_search_entry.get())
def search_for_ref(self, reference, csv_file="Cases.csv"):
#Function to read specific entry by reference
if reference in self.references_list:
with open(csv_file, "r", newline="") as file:
reader = csv.DictReader(file, delimiter="|")
for entry in reader:
if reference == entry["Reference"]:
data = entry["Title"] #By example
return data
How do I receive the data from the buildin function of the ReferenceSearch class and use it in the main module the case_form?
Keep in mind that the ReferenceSearch module is calling this function when the search button is pressed (and not the case_form module). However, the data is needed in the case_form module.
Change the ReferenceSearch module contents to:
class ReferenceSearch(tk.Toplevel):
def __init__(self, parent, csv_file,references_list=[]):
super().__init__()
self.data = ""
self.parent = parent
self.csv_file = csv_file
self.references_list = references_list
self.ref_search_entry = ttk.Entry(self.search_frame)
self.search_but = tk.Button(self.search_frame,
text=" Search ",
command=lambda:self.search_for_ref(self.ref_search_entry.get())
def search_for_ref(self, reference, csv_file="Cases.csv"):
#Function to read specific entry by reference
if reference in self.references_list:
with open(csv_file, "r", newline="") as file:
reader = csv.DictReader(file, delimiter="|")
for entry in reader:
if reference == entry["Reference"]:
data = entry["Title"] #By example
self.parent.title_var.set(data)
and case_form contents to:
import ReferenceSearch as rs
def search_ref(self):
#Function to call search engine
search_engine = rs.ReferenceSearch(self, self.csv_file.get(), self.references_list)

Python3 tkinter label value

I need some help, I trying to update the etcprice label value after I push the button and after every 5 seconds, in terminal works, but in tk window not. I stucked here :( please, help me.
I tried to setup the "price" to "StringVar()" but in that case I got a lot of errors.
Many thanks
import urllib.request
from urllib.request import *
import json
import six
from tkinter import *
import tkinter as tk
import threading
price = '0'
def timer():
threading.Timer(5.0, timer).start()
currentPrice()
def currentPrice():
url = 'https://api.cryptowat.ch/markets/bitfinex/ethusd/price'
json_obj = urllib.request.urlopen(url)
data = json.load(json_obj)
for item, v in six.iteritems(data['result']):
# print("ETC: $", v)
price = str(v)
# print(type(etcar))
print(price)
return price
def windows():
root = Tk()
root.geometry("500x200")
kryptoname = Label(root, text="ETC price: ")
kryptoname.grid(column=0, row=0)
etcprice = Label(root, textvariable=price)
etcprice.grid(column=1, row=0)
updatebtn = Button(root, text="update", command=timer)
updatebtn.grid(column=0, row=1)
root.mainloop()
windows()
The solution was: I created a new String variable called “b” and I changed the etcprice Label variable to this.
After I added this b.set(price) in currentPrice() def: and is working.
The price variable is a global - if you're trying to change it, you need to do so explicitly:
def currentPrice():
global price
url = 'https://api.cryptowat.ch/markets/bitfinex/ethusd/price'
json_obj = urllib.request.urlopen(url)
data = json.load(json_obj)
for item, v in six.iteritems(data['result']):
# print("ETC: $", v)
price = str(v)
# print(type(etcar))
print(price)
return price
otherwise, Python will 'mirror' it as a local variable inside the function, and not modify the global.
It's not a good idea to keep on launching more and more threads each time you click the button - so:
updatebtn = Button(root, text="update", command=currentPrice)
probably makes more sense.
You don't need to use threads here, just to call functions 'in the background'. You can use tkinter's own .after function instead to delay caling functions. (it uses milliseconds, not float second values, btw)
def timer(delay_ms, root, func):
func()
root.after(delay_ms, timer, root, func)
might be a helpful kind of function.
Then before you launch your mainloop, or whenever you want the getting to start, call it once:
timer(5000, root, currentPrice)
If you want the currentPrice function to run in a separate thread, and so not block your main GUI thread if there is network lag, for instance, then you can use threads more like this:
Thread(target=currentPrice, daemon=True).start()
which will run it in a daemon-thread - which will automatically get killed if you close the program, or ctrl-c it, or whatever. So you could put that line in a getCurrentPriceBG or similar function.

save list to CSV - python

I try to save my output as csv using the "import csv" and only get errors. Any reason why?
Since I can not make it run will it also notify if the file already exists?
Thanks a lot
from tkinter import *
from tkinter.filedialog import asksaveasfilename
from tkinter import ttk
import csv
def data():
...
output= <class 'list'> #just an example
...
def savefile():
name= asksaveasfilename()
create = csv.writer(open(name, "wb"))
create.writerow(output)
for x in output:
create.writerow(x)
root = Tk()
Mframe = ttk.Frame(root)
Mframe.grid(column=0, row=0, sticky=(N, W, E, S))
bSave=ttk.Button(Mframe, text='Save File', command=savefile)
bSave.grid(column=1, row=0)
root.mainloop()
You are opening the file, but not closing it. A good practise is to use a with statement make sure you close it. By the way, I don't know how is the output list, but if it isn't a list of lists, it makes more sense to me to call writerow once.
Besides, make sure this list is also a global variable, otherwise it won't be available within the scope of savefile. However, global variables are not a very good solution, so consider to pass it as an argument to savefile or use a class to hold all this data:
def savefile():
name = asksaveasfilename()
with open(name, 'w', newline='') as csvfile:
create = csv.writer(csvfile)
create.writerow(output)