I'm using win32com.client to read data from custom COM Object developed in VB.Net.
With the following code I'm able to read a string result
>>> import win32com.client
>>> cstApp = win32com.client.Dispatch("CustomLib.CSTApp")
>>> string = cstApp.GiveMeTestString()
>>> print(type(string))
<class 'str'>
>>> print("Test String: {0}".format(string))
Test String: Well done! I come from COM Object
I've now a method that give as result a VB.Net Dictionary type, but when I try to read it from my python script I get a PyIUknown type and I'm not able to read its values
>>> username = 'artur'
>>> resultset = cstApp.OpenTaskforUser(username)
>>> print(type(resultset))
<class 'PyIUnknown'>
>>> print(resultset)
<PyIUnknown at 0x0000003C47ABAC30 with obj at 0x0000003C47EAFF18>
How can I read it's data?
Otherwise, which type I need to use in VB.Net to be able to read a Python list containing dictionaries from win32com?
Thank you for your help.
After a week of working I've better understood how works win32com and Python support of COM interface, so I wanna share the workaround I've used to avoid the situation for which I posted this question.
1. First of all PyIUnknown is not an error. IUnknown Interface is the root Interface from which derive all other Interface. IUnknown (and so PyIUnknown) could be used through QueryInterface method. [1]
2. On the other hand , not all Python Types are mapped in a COM Interface. So IDictionary is one of them. This is why I get the PyIUnknown result. [2]
3. To use easly a COM Interface in Python is useful to generate a static proxy class that maps all the interfaces available in the library. There are different ways to do this activity. In the early steps I've used makepy method . Then I've used EnsureDispatch one. [3]
The final workaround, to avoid the problems at point 1. and 2., was to ask to custom API COM developer to change the returned type from a IDictionary to JSON string.
In this way I get a easily to use Python dictionary.
>>> import win32com.client
>>> import json
>>> cstApp = win32com.client..gencache.EnsureDispatch("CustomLib.CSTApp")
>>> resultset_json = cstApp.OpenTaskforUser('artur')
>>> type(resultset_json)
<class 'str'>
>>> resultset = json.loads(resultset_json)
>>> type(resultset)
<class 'dict'>
I hope this answer could help other people.
Related
I have to build, in python, an address book of contacts using a json file. So, I have to define a class Contact which has as attributes hust the name, surname and mail. In the solution there is a function that I never would have thought of: jsonify(self). I don't understand what it does and why I need it. Someone can help me figure it out?
def jsonify(self):
contact = {'name':self.name,'surname':self.surname,'mail':self.mail}
return contact
Using the json library, you can convert objects into JSON really easily, but it needs to know how to go about converting them. The library doesn't know how to interpret your custom class:
>>> import json
>>> contact = Contact("Hello", "World", "hello#world.com")
>>> contact_json = json.dumps(contact)
TypeError: Object of type 'Contact' is not JSON serializable
(json.dumps(obj) converts its input to JSON and returns it as a string. You can also do json.dump(obj, file_handle) to save it to a file).
A dictionary is a known type in Python, so the json library knows how to convert it into json format:
>>> import json
>>> contact = Contact("Hello", "World", "hello#world.com")
>>> contact_json = json.dumps(contact.jsonify())
{
"name": "Hello",
"surname": "World",
"mail": "hello#world.com"
}
Using that jsonify method, you're converting the fields from your class into something that the json library can understand and knows how to translate.
This is a quick and easy way to serialise your object into JSON, but isn't necessarily the best way to do it - ideally you'd tell the JSON library how to interpret your class (see this related question: How to make a class JSON serializable).
Edit: Seeing the comment discussion - I'm assuming here you have an understanding of Python data structures and classes. If this is not the case it's worth reading up on those first.
Using pyqt4 and python 2.6, I am using a qcombobox to provide a list of options. I am having problems with using the selected option. I have been able to use a signal to trigger a method when the option is selected, but the problem is that when the user clicks run, the contents of several of these comboboxes need to be taken into account. So basically I need to get the selected contents of a combobox as a string. Thus far I have only been able use this:
print combobox1.currentText()
to get this:
PyQt4.QtCore.QString(u'Test Selection2')
when all I really want is the 'Test Selection' bit, any ideas?
My combo box was made like this:
combobox1 = qt.QComboBox()
combobox1.addItems(['Test Selection1', 'Test Selection2'])
mainLayout.addWidget(combobox1, 0, 0)
You can convert the QString type to python string by just using the str
function. Assuming you are not using any Unicode characters you can get a python
string as below:
text = str(combobox1.currentText())
If you are using any unicode characters, you can do:
text = unicode(combobox1.currentText())
Getting the Text of ComboBox when the item is changed
self.ui.comboBox.activated.connect(self.pass_Net_Adap)
def pass_Net_Adap(self):
print str(self.ui.comboBox.currentText())
PyQt4 can be forced to use a new API in which QString is automatically converted to and from a Python object:
import sip
sip.setapi('QString', 2)
With this API, QtCore.QString class is no longer available and self.ui.comboBox.currentText() will return a Python string or unicode object.
See Selecting Incompatible APIs from the doc.
If you want the text value of a QString object you can use the __str__ property, like this:
>>> a = QtCore.QString("Happy Happy, Joy Joy!")
>>> a
PyQt4.QtCore.QString(u'Happy Happy, Joy Joy!')
>>> a.__str__()
u'Happy Happy, Joy Joy!'
Hope that helps.
I have a module english.py which contains a dictionary monograms. The value associated with each key is of type str and I would like to permanently change the type of the value associated with each key to int from a separate script.
I have tried to mimic the response to this question with the following:
import english
english.monograms['the'] = int(english.monograms['the'])
print(type(english.monograms['the']))
yielding the expected: <class 'int'>
However, when I rerun the code with the 2nd line commented out:
import english
#english.monograms['the'] = int(english.monograms['the'])
print(type(english.monograms['the']))
I recieve <class 'str'>
How can I make this change permanant without a complicated function that would read, parse and re-write the module?
I have a problem that I would like to know how to efficiently tackle.
I have data that is JSON-formatted (used with dumps / loads) and contains unicode.
This is part of a protocol implemented with JSON to send messages. So messages will be sent as strings and then loaded into python dictionaries. This means that the representation, as a python dictionary, afterwards will look something like:
{u"mykey": u"myVal"}
It is no problem in itself for the system to handle such structures, but the thing happens when I'm going to make a database query to store this structure.
I'm using pyOrient towards OrientDB. The command ends up something like:
"CREATE VERTEX TestVertex SET data = {u'mykey': u'myVal'}"
Which will end up in the data field getting the following values in OrientDB:
{'_NOT_PARSED_': '_NOT_PARSED_'}
I'm assuming this problem relates to other cases as well when you wish to make a query or somehow represent a data object containing unicode.
How could I efficiently get a representation of this data, of arbitrary depth, to be able to use it in a query?
To clarify even more, this is the string the db expects:
"CREATE VERTEX TestVertex SET data = {'mykey': 'myVal'}"
If I'm simply stating the wrong problem/question and should handle it some other way, I'm very much open to suggestions. But what I want to achieve is to have an efficient way to use python2.7 to build a db-query towards orientdb (using pyorient) that specifies an arbitrary data structure. The data property being set is of the OrientDB type EMBEDDEDMAP.
Any help greatly appreciated.
EDIT1:
More explicitly stating that the first code block shows the object as a dict AFTER being dumped / loaded with json to avoid confusion.
Dargolith:
ok based on your last response it seems you are simply looking for code that will dump python expression in a way that you can control how unicode and other data types print. Here is a very simply function that provides this control. There are ways to make this function more efficient (for example, by using a string buffer rather than doing all of the recursive string concatenation happening here). Still this is a very simple function, and as it stands its execution is probably still dominated by your DB lookup.
As you can see in each of the 'if' statements, you have full control of how each data type prints.
def expr_to_str(thing):
if hasattr(thing, 'keys'):
pairs = ['%s:%s' % (expr_to_str(k),expr_to_str(v)) for k,v in thing.iteritems()]
return '{%s}' % ', '.join(pairs)
if hasattr(thing, '__setslice__'):
parts = [expr_to_str(ele) for ele in thing]
return '[%s]' % (', '.join(parts),)
if isinstance(thing, basestring):
return "'%s'" % (str(thing),)
return str(thing)
print "dumped: %s" % expr_to_str({'one': 33, 'two': [u'unicode', 'just a str', 44.44, {'hash': 'here'}]})
outputs:
dumped: {'two':['unicode', 'just a str', 44.44, {'hash':'here'}], 'one':33}
I went on to use json.dumps() as sobolevn suggested in the comment. I didn't think of that one at first since I wasn't really using json in the driver. It turned out however that json.dumps() provided exactly the formats I needed on all the data types I use. Some examples:
>>> json.dumps('test')
'"test"'
>>> json.dumps(['test1', 'test2'])
'["test1", "test2"]'
>>> json.dumps([u'test1', u'test2'])
'["test1", "test2"]'
>>> json.dumps({u'key1': u'val1', u'key2': [u'val21', 'val22', 1]})
'{"key2": ["val21", "val22", 1], "key1": "val1"}'
If you need to take more control of the format, quotes or other things regarding this conversion, see the reply by Dan Oblinger.
I’m trying to write a response from a Solr server to a CSV file. I’m pretty new to python and have been given code to modify. Originally the code looked like this ...
for doc in response.results:
status = json.loads(doc['status'])
The script runs and prints the correct information. But it only every prints one result (last one). I think this is because the loop constantly writes over the varible 'status' until its worked through the response.
After some reading I decided to store the information in a list. That way i could print the information to seprate lines in a list. I created an empty list and changed the code below -
for doc in response.results:
list.append = json.loads(doc['status'])
I got this response back after trying to run the code -
`AttributeError: 'list' object attribute 'append' is read-only`.
Where am I going wrong? Is a list not the best approach?
>>> list.append
<method 'append' of 'list' objects>
You're trying to modify the append method of the built-in list class!
Just do
docstats = []
for doc in response.results:
docstats.append(json.loads(doc['status']))
or equivalently:
docstats = [json.loads(doc['status']) for doc in response.results]
I'm not sure what you are trying to do.
I guess you haven't created a list variable. list is a python's builtin class for lists, so if there's no variable to mask it, you'll access that. And you tried to modify one of it's propterties, which is not allowed (it's not like ruby where you can monkey-patch anything).
Is this what you want? :
l=[]
for doc in response.results:
l.append(json.loads(doc[‘status’]))
Try
list.append(json.loads(doc['status']))