Constructor error using mXparser with Pythonnet - python

I am trying to use mXparser from Python. It loads without problem, but as soon as try to call the expression function with a string (as in the help examples), I get an error, TypeError: no constructor matches given arguments.
import clr
dllpath = r'C:\...\GitHub\MathParser.org-mXparser\CURRENT\c-sharp\bin\Release\MathParser.org-mXparser.dll'
import org.mariuszgromada.math.mxparser as mx
expr_01 = mx.Expression('2 + 1')
Initially I took this to mean that I needed to specify the type of the string I was passing, but I don't think this is it. Any ideas? I compiled the mXparser dll with .NET Framework 4.5.2 (I did not choose the option to make it COM-visible).

you can run
mx.Expression.Overloads to see what argument type it needs. The type can be imported by from System import String, etc
Explicitly, construct the c# type
from System import String
str3 = String('2 + 1')
expr_01 = mx.Expression(str3)

Related

How to build CDK Assembly using Python aws_cdk.cx_api

I'm desperate so any help is appreciated.
I'm trying to modify my current CDK out using cloud assembly in Python.
I can't find any examples, nor proper documentation for python, only reference guide.
This is my code:
import os
import subprocess
import aws_cdk.cx_api as cxapi
import aws_cdk.cloud_assembly_schema as cxschema
class my_class():
def synth():
ASSEMBLY_PATH = 'igor_cdk'
result = subprocess.run(['cdk', 'synth', '-o', ASSEMBLY_PATH], stdout=subprocess.PIPE)
my_stuff = result.stdout.decode('utf-8')
new_stack_name = original_stack_name+TEMP_OUT
print(new_stack_name)
cloud_assembly = cxapi.CloudAssembly(ASSEMBLY_PATH);
orig_stack_assembly = cloud_assembly.get_stack_by_name(original_stack_name)
logical_Ids = orig_stack_assembly.find_metadata_by_type("aws:cdk:logicalId")
cab = cxapi.CloudAssemblyBuilder(ASSEMBLY_PATH)
cab.add_artifact(new_stack_name, type = cxschema.ArtifactType.ASSET_MANIFEST, properties = orig_stack_assembly.manifest)
Then, In my dummy test, I call this:
print(stack_info.synth("Test", "Targeta"))
And that's executed with pytest.
Just for comparison, I got it working in Typescript:
const cab: CloudAssemblyBuilder = new CloudAssemblyBuilder(ASSEMBLY_PATH);
cab.addArtifact(new_stack_name, stack.manifest);
cab.buildAssembly();
I expected similar/same behavior, but I just can't figure out how to do it in python, and since my whole code base is in python, I'd just love to have it all done in one place, rather than reworking the whole thing in TS.
Edit:
If I pass the stack.manifest, I'm getting the following error:
jsii.errors.JSIIError: Value did not match any type in union:
Wire struct type '#aws-cdk/cloud-assembly-schema.ArtifactManifest' does not match expected '#aws-cdk/cloud-assembly-schema.AwsCloudFormationStackProperties', Wire struct type '#aws-cdk/cloud-assembly-schema.ArtifactManifest' does not match expected '#aws-cdk/cloud-assembly-schema.AssetManifestProperties',
Wire struct type '#aws-cdk/cloud-assembly-schema.ArtifactManifest' does not match expected '#aws-cdk/cloud-assembly-schema.TreeArtifactProperties',
Wire struct type '#aws-cdk/cloud-assembly-schema.ArtifactManifest' does not match expected '#aws-cdk/cloud-assembly-schema.NestedCloudAssemblyProperties'
And if I pass the whole stack assembly object, I run in even weirder problem:
jsii.errors.JavaScriptError:
RangeError: Maximum call stack size exceeded
at /private/var/folders/z6/c91mcs6j4g93t2856_p_51nr0000gn/T/jsii-kernel-35iS5M/node_modules/#aws-cdk/cx-api/lib/cloud-assembly.js:307:53

TypeError calling .NET method using Pythonnet

I'm having a problem calling a method from a .NET dll linked to the eBUS SDK. The end goal of the code is to communicated to a GigE connected camera using python.
In C#, the method is:
public void SetStreamDestination( string aIPAddress, ushort aDataPort ) , and is part of a class called PvDeviceGEV.
In Python, I'm using pythonnet to import the dll. I'm then using this code:
from PvDotNet import PvDeviceGEV
from PvDotNet import PvStreamGEV
DeviceGEV = PvDeviceGEV()
Stream = PvStreamGEV()
LocalIP = Stream.LocalIPAddress
LocalPort = Stream.LocalPort
DeviceGEV.SetStreamDestination(LocalIP, LocalPort)
This results in an error:
TypeError: No method matches given arguments for SetStreamDestination: (<class 'str'>, <class 'int>)
Seeing as the types of IPAddress and aDataPort should be string and UInt16 respectively, I don't understand this error. I've been able to call other methods from this class. This is my first time trying to import functions from another language into Python. Any help understanding or correcting this error would be appreciated.
I solved this by changing
SetStreamDestination(LocalIP, LocalPort) to SetStreamDestination(LocalIP, UInt16(LocalPort))

How to read file capabilities using Python?

On Linux systems root privileges can be granted more selectively than adding the setuid bit using file capabilities. See capabilities(7) for details. These are attributes of files and can be read using the getcap program. How can these attributes be retrieved in Python?
Even though running the getcap program using e.g. subprocess for answering such a question is possible it is not desirable when retrieving very many capabilities.
It should be possible to devise a solution using ctypes. Are there alternatives to this approach or even libraries facilitating this task?
Python 3.3 comes with os.getxattr. If not, yeah... one way would be using ctypes, at least to get the raw stuff, or maybe use pyxattr
For pyxattr:
>>> import xattr
>>> xattr.listxattr("/bin/ping")
(u'security.capability',)
>>> xattr.getxattr("/bin/ping", "security.capability")
'\x00\x00\x00\x02\x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
For Python 3.3's version, it's essentially the same, just importing os, instead of xattr. ctypes is a bit more involved, though.
Now, we're getting the raw result, meaning that those two are most useful only retrieving textual attributes. But... we can use the same approach of getcap, through libcap itself:
import ctypes
libcap = ctypes.cdll.LoadLibrary("libcap.so")
cap_t = libcap.cap_get_file('/bin/ping')
libcap.cap_to_text.restype = ctypes.c_char_p
libcap.cap_to_text(cap_t, None)
which gives me:
'= cap_net_raw+p'
probably more useful for you.
PS: note that cap_to_text returns a malloced string. It's your job to deallocate it using cap_free
Hint about the "binary gibberish":
>>> import struct
>>> caps = '\x00\x00\x00\x02\x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
>>> struct.unpack("<IIIII", caps)
(33554432, 8192, 0, 0, 0)
In that 8192, the only active bit is the 13th. If you go to linux/capability.h, you'll see that CAP_NET_RAW is defined at 13.
Now, if you wan to write a module with all those constants, you can decode the info. But I'd say it's much more laborious than just using ctypes + libcap.
I tried the code from Ricardo Cárdenes's answer, but it did not work properly for me, because some details of the ctypes invocation incorrect. This issue caused a truncated path string to be passed to getxattr(...) inside of libcap, which thus returned the wrong capabilities list for the wrong item (the / directory, or other first path character, and not the actual path).
It is very important to remember and account for the difference between str and bytes in Python 3.X. This code works properly on Python 3.5/3.6:
#!/usr/bin/env python3
import ctypes
import os
import sys
# load shared library
libcap = ctypes.cdll.LoadLibrary('libcap.so')
class libcap_auto_c_char_p(ctypes.c_char_p):
def __del__(self):
libcap.cap_free(self)
# cap_t cap_get_file(const char *path_p)
libcap.cap_get_file.argtypes = [ctypes.c_char_p]
libcap.cap_get_file.restype = ctypes.c_void_p
# char* cap_to_text(cap_t caps, ssize_t *length_p)
libcap.cap_to_text.argtypes = [ctypes.c_void_p, ctypes.c_void_p]
libcap.cap_to_text.restype = libcap_auto_c_char_p
def cap_get_file(path):
cap_t = libcap.cap_get_file(path.encode('utf-8'))
if cap_t is None:
return ''
else:
return libcap.cap_to_text(cap_t, None).value.decode('utf-8')
print(cap_get_file('/usr/bin/traceroute6.iputils'))
print(cap_get_file('/usr/bin/systemd-detect-virt'))
print(cap_get_file('/usr/bin/mtr'))
print(cap_get_file('/usr/bin/tar'))
print(cap_get_file('/usr/bin/bogus'))
The output will look like this (anything nonexistent, or with no capabilities set just returns '':
= cap_net_raw+ep
= cap_dac_override,cap_sys_ptrace+ep
= cap_net_raw+ep

AssertionError while generating python wrapper for dll file using comtypes.client.GetModule()

I'm trying to use "PortableDevice.PortableDevice" COM API for my python application. When I try to generate python wrapper as follow:
comtypes.client.GetModule("C:\\Windows\\system32\\PortableDeviceApi.dll")
I get following error message:
assert sizeof(__MIDL_IOleAutomationTypes_0004) == 16, sizeof(__MIDL_IOleAutomationTypes_0004)
AssertionError: 8
Can anyone please help me to troubleshoot this issue?
The main reason why this fails is due to a kludge in comtypes, where the DECIMAL type is not properly defined. As is, it needs 64 bits, or 8 bytes, for a double float, but it should really take 16 bytes, or 128 bits, for the actual struct.
For your current purpose, you can get along with any definition of DECIMAL that has the proper size, so here's one:
# comtypes/automation.py
class tagDEC(Structure):
_fields_ = [("wReserved", c_ushort),
("scale", c_ubyte),
("sign", c_ubyte),
("Hi32", c_ulong),
("Lo64", c_ulonglong)]
DECIMAL = tagDEC
# comtypes/tools/tlbparser.py
DECIMAL_type = typedesc.Structure("DECIMAL",
align=alignment(automation.DECIMAL)*8,
members=[], bases=[],
size=sizeof(automation.DECIMAL)*8)
However, you'll probably stump over the fact that some methods in the Portable Device API are not suitable for automation.
For instance, IPortableDeviceManager::GetDevices has the unique attribute (in the actual PortableDeviceApi.idl file, not in the documentation), which means you can actually pass NULL. However, type libraries don't capture this information.
That same argument can actually be an array which size is determined by the next argument. Again, type libraries don't support this, only single-object top-level pointers. Moreover, the actual IDL doesn't have a size_is attribute, which means either that the method call will not work across apartments or that this interface has a custom marshaler.
A quick look at the Portable Device API in general shows that this pattern is consistently applied in other methods that actually use arrays. It seems as if someone familiar with the Win32 API made these methods, because there are a bunch of Win32 functions that are overloaded to fetch the size of some array when that array argument is NULL. This is not the usual COM way at all, it would be better to have two methods (with the same race condition between knowing the number of elements, allocating enough memory and fetching them), a single method with only out arguments (no race condition, but no control over memory usage) or use enumerators (e.g. IEnumPortableDevice, harder, but much cleaner).
Anyway, you can take the code that comtypes.client.GetModule("…PortableDeviceApi.dll") generates as a first step. Then, follow these instructions to make the Python methods actually call the COM methods in the documented way. For instance, IPortableManager::GetDevices would become:
# comtypes/gen/_1F001332_1A57_4934_BE31_AFFC99F4EE0A_0_1_0.py
class IPortableDeviceManager(comtypes.gen._00020430_0000_0000_C000_000000000046_0_2_0.IUnknown):
# ...
def GetDevices(self):
cPnPDeviceIDs = c_ulong(0)
self.__com_GetDevices(None, byref(cPnPDeviceIDs))
PnPDeviceIDs = (WSTRING * cPnPDeviceIDs.value)()
self.__com_GetDevices(PnPDeviceIDs, byref(cPnPDeviceIDs))
deviceIDs = PnPDeviceIDs[:cPnPDeviceIDs.value]
for i in range(cPnPDeviceIDs.value):
windll.ole32.CoTaskMemFree(cast(PnPDeviceIDs, POINTER(c_void_p))[i])
return deviceIDs
# ...
IPortableDeviceManager._methods_ = [
COMMETHOD([], HRESULT, 'GetDevices',
( ['in'], POINTER(WSTRING), 'pPnPDeviceIDs' ),
( ['in'], POINTER(c_ulong), 'pcPnPDeviceIDs' )),
# ...
The following test runs successfully, although it returns an empty list in my case, since I don't have any connected device right now:
# First run
import os
from comtypes.client import GetModule
GetModule(os.getenv("WINDIR") + "\\system32\\PortableDeviceApi.dll")
# Quit python
# Edit comtypes/gen/_1F001332_1A57_4934_BE31_AFFC99F4EE0A_0_1_0.py
# Subsequent runs
from comtypes.client import CreateObject
from comtypes.gen.PortableDeviceApiLib import *
CreateObject(PortableDeviceManager).GetDevices()
I can't provide more help without scavenging further into comtypes. I suggest you contact its authors or maintainers.
EDIT: Meanwhile, I created a ticket at the SourceForge site. Since the project was transitioning out of SourceForge, it seemed to be forgotten, but it wasn't (here too).
Have you tried to import the module since then?

Python c_types .dll functions (pari library)

Alright, so a couple days ago I decided to try and write a primitive wrapper for the PARI library. Ever since then I've been playing with ctypes library in loading the dll and accessing the functions contained using code similar to the following:
from ctypes import *
libcyg=CDLL("<path/cygwin1.dll") #It needs cygwin to be loaded. Not sure why.
pari=CDLL("<path>/libpari-gmp-2.4.dll")
print pari.fibo #fibonacci function
#prints something like "<_FuncPtr object at 0x00BA5828>"
So the functions are there and they can potentially be accessed, but I always receive an access violation no matter what I try. For example:
pari.fibo(5) #access violation
pari.fibo(c_int(5)) #access violation
pari.fibo.argtypes = [c_long] #setting arguments manually
pari.fibo.restype = long #set the return type
pari.fibo(byref(c_int(5))) #access violation reading 0x04 consistently
and any variation on that, including setting argtypes to receive pointers.
The Pari .dll is written in C and the fibonacci function's syntax within the library is GEN fibo(long x).
Could it be the return type that's causing these errors, as it is not a standard int or long but a GEN type, which is unique to the PARI library? Any help would be appreciated. If anyone is able to successfully load the library and use ANY function from within python, please tell; I've been at this for hours now.
EDIT: Seems as though I was simply forgetting to initialize the library. After a quick pari.pari_init(4000000,500000) it stopped erroring. Now my problem lies in the in the fact that it returns a GEN object; which is fine, but whenever I try to reference the address to which it points, it's always 33554435, which I presume is still an address. I'm trying further commands and I'll update if I succeed in getting the correct value of something.
You have two problems here, one give fibo the correct return type and two convert the GEN return type to the value you are looking for.
Poking around the source code a bit, you'll find that GEN is defined as a pointer to a long. Also, at looks like the library provides some converting/printing GENs. I focused in on GENtostr since it would probably be safer for all the pari functions.
import cytpes
pari = ctypes.CDLL("./libpari.so.2.3.5") #I did this under linux
pari.fibo.restype = ctypes.POINTER(ctypes.c_long)
pari.GENtostr.restype = ctypes.POINTER(ctypes.c_char)
pari.pari_init(4000000,500000)
x = pari.fibo(100)
y = pari.GENtostr(x)
ctypes.string_at(y)
Results in:
'354224848179261915075'

Categories

Resources