Setting and getting "data" from PyQt widget items? - python

This is not so much a question as it is a request for an explanation. I'm following Mark Summerfield's "Rapid GUI Programming with Python and Qt", and I must've missed something because I cannot make sense of the following mechanism to link together a real "instance_item" which I am using and is full of various types of data, and a "widget_item" which represents it in a QTreeWidget model for convenience.
Setting:
widget_item.setData(0, Qt.UserRole, QVariant(long(id(instance_item))))
Getting
widget_item.data(0, Qt.UserRole).toLongLong()[0]
Stuff like toLongLong() doesn't seem "Pythonic" at all, and why are we invoking Qt.UserRole and QVariant? are the "setData" and "data" functions part of the Qt framework or is it a more general Python command?

There are at least 2 better solutions. In order of increasing pythonicity:
1) You don't need quite so much data type packing
widget_item.setData(0, Qt.UserRole, QVariant(instance_item))
widget_item.data(0, Qt.UserRole).toPyObject()
2) There is an alternate API to PyQt4 where QVariant is done away with, and the conversion to-from QVariant happens transparently. To enable it, you need to add the following lines before any PyQt4 import statements:
import sip
sip.setapi('QVariant', 2)
Then, your code looks like this:
widget_item.setData(0, Qt.UserRole, instance_item)
widget_item.data(0, Qt.UserRole) # original python object
Note that there is also an option sip.setapi('QString', 2) where QString is done away with, and you can use unicode instead.

All of these methods -- setData(), data(), toLongLong() are all part of Qt and were originally intended to be used in C++, where they make a lot more sense. I'm not really sure what the author is trying to do here, but if you find yourself doing something terribly un-pythonic, there is probably a better way:
## The setter:
widget_item.instance_item = instance_item
## The getter:
instance_item = widget_item.instance_item
The Qt docs can't recommend this, of course, because there are no dynamic attribute assignments in C++. There are a few very specific instances when you may have to deal with QVariant and other such nonsense (for example, when dealing with databases via QtSQL), but they are quite rare.

Related

How to combine Python logic and Qt C++ GUI

I was presented with a Python logic and a GUI written in C++ Qt and asked to combine them. Before I choose the route of re-implementing the GUI in e.g. PySide, I would like to know which way would be the smoothest to achieve such a combination. Would I rather make the C++ GUI available to the Python logic (and a controlling layer) or the other way around?
I will gladly provide more information, if necessary. My problem is a lack of experience in that matter and that there are so many solutions of how to make code of one language accessible to the other, that I feel a bit smothered in options.
In this case, the Python logic is actually just a (too large, but that's another topic) class which provides some signal processing methods.
This is a crisp rephrasing of a prior question, which I somewhat clumsily posed, and therefore missed its aim.

How do you read and quickly edit python code

I typically work with C++ but off late have to program a lot in Python. Coming from a C++ background, I am finding dynamic typing to be very inconvenient when I have to modify an existing codebase. I know I am missing something very basic and hence turning to the stackoverflow community to understand best practices.
Imagine, there is a class with a number of methods and I need to edit an existing method. Now, in C++, I could explicitly see the datatype of every parameter, check out the .h files of the corresponding class if need be and could quickly understand what's happening. In python on the other hand, all I see are some variable names. I am not sure if it is a list or a dictionary or maybe some custom datastructure with its getters and setters. To figure this out, I need to look at some existing usages of this function or run the code with breakpoints and see what kind of datastructure am I getting. I find either methods to be very time consuming. Is there a faster way to resolve this problem? How should I quickly determine what's the datatype of a particular variable?
The general impression is that code is easier to read/write in Python, but I am not finding it very quick to read python code because of lack of types. What am I missing here?
I feel your pain, too! I frequently switch between Python and C++, so paradigm shifting does give me paranoia.
However, I've been readjusting my codes with:
Type Annotations
It doesn't improve runtime performance, but it provides sense of comfort when reading through tens of thousands line of codes. Also, you can run your python programs with this to further verify your type annotations:
mypy
These are the following things i follow:
Comment clearly what is being returned and what is the input in the docstring
Use a debug(or a Flag) variable, which is by default set to False, and keep a if block as follows.
if debug:
print(type(variable))
So, in that way, you would be sure to see what is the type of the variable.
In Python, you can see the data type of any variable by using
type(variable_name)
It will show you data type of that variable. Such as int, bool, str, etc.

Get types in Python expression using MyPy as library

I have some Python source code, and want to find out the type of a variable. For example given the string
"""
greeting = "Hello"
"""
I want to have get_type('greeting') == str. Or a more complex example:
"""
def test(input: str):
output = len(input)
return str
"""
In pseudocode, I want to be able to do something like:
>>> m = parse_module()
>>> m.functions['test'].locals['output'].get_type()
int
It seems this should be possible with type annotations and MyPy in Python 3, but I can't figure out how. IDEs like VS code have become very good at guessing the types in python code, that is why I'm guessing there must be an exposed way to do this.
There seems to be a module typed-ast, which is also used by MyPy, that gets me part of the way there. However, this does no type inference or propagation, it just gives me the explicit annotations as far as I understand. MyPy as an api, but it only lets you run the checker, and returns the same error messages as the command line tool. I am looking for a way to "reach into" MyPy, and get some of the inferred information out - or some alternative solution I haven't thought of.
Mypy currently has an extremely primitive, bare-bones API, which you can find "documented" within the source code here: https://github.com/python/mypy/blob/master/mypy/api.py. To use it, you essentially need to write your string to a temporary file which you later clean up.
You can perhaps combine this with the reveal_type(...) special directive (and perhaps even the hidden --shadow-file option) to typecheck your string.
The other alternative is to reverse engineer and re-implement pieces of mypy's main.py, essentially hijacking their internal API. I don't really think this will be hard, just somewhat ugly and fragile.
(Note that mypy can theoretically support typechecking arbitrary strings, and the core devs aren't opposed to extending the API for mypy in principle -- it's just that mypy is still under active development which means implementing an API has been very low priority for a while now. And since mypy is still actively being worked on/extended, the devs are somewhat reluctant to commit to implementing a more complex API that they'll subsequently have to support. You can find more context and details regarding the current state of the API in mypy's issue tracker.)

Dynamically add properties and call method on first read

I'm working with building pdf:s via reportlab and I'm currently trying to clean up the code. I want to build a light little class for handling the fonts (accessing and registering appropriately). I would like all available fonts to behave as properties and register themselves (a method call) when they are first accessed.
The list of available-fonts is a simple tuple of strings like so:
available_fonts = (
"Roboto-Regular",
"Roboto-Bold",
"Roboto-Italic",
"Roboto-Light",
"Roboto-LightItalic",
"Roboto-Thin",
"Roboto-ThinItalic"
)
My python sense tells me that there is a neat solution to this :). I'm thinking of methods with the #property decorator but I would prefer not to have to write the methods for each font, it seems non-dry and harder to maintain.
Help would be much appreciated!

Implementing a macro recorder for a python gui?

I'm wondering how to go about implementing a macro recorder for a python gui (probably PyQt, but ideally agnostic). Something much like in Excel but instead of getting VB macros, it would create python code. Previously I made something for Tkinter where all callbacks pass through a single class that logged actions. Unfortunately my class doing the logging was a bit ugly and I'm looking for a nicer one. While this did make a nice separation of the gui from the rest of the code, it seems to be unusual in terms of the usual signals/slots wiring. Is there a better way?
The intention is that a user can work their way through a data analysis procedure in a graphical interface, seeing the effect of their decisions. Later the recorded procedure could be applied to other data with minor modification and without needing the start up the gui.
You could apply the command design pattern: when your user executes an action, generate a command that represents the changes required. You then implement some sort of command pipeline that executes the commands themselves, most likely just calling the methods you already have. Once the commands are executed, you can serialize them or take note of them the way you want and load the series of commands when you need to re-execute the procedure.
Thinking in high level, this is what I'd do:
Develop a decorator function, with which I'd decorate every event-handling functions.
This decorator functions would take note of thee function called, and its parameters (and possibly returning values) in a unified data-structure - taking care, on this data structure, to mark Widget and Control instances as a special type of object. That is because in other runs these widgets won't be the same instances - ah, you can't even serialize a toolkit widget instances, be it Qt or otherwise.
When the time comes to play a macro, you fill-in the gaps replacing the widget-representating object with the instances of the actually running objects, and simply call the original functions with the remaining parameters.
In toolkits that have an specialized "event" parameter that is passed down to event-handling functions, you will have to take care of serializing and de-serializing this event as well.
I hope this can help. I could come up with some proof of concept code for that (although I am in a mood to use tkinter today - would have to read a lot to come up with a Qt4 example).
An example of what you're looking for is in mayavi2. For your purposes, mayavi2's "script record" functionality will generate a Python script that can then be trivially modified for other cases. I hear that it works pretty well.

Categories

Resources