pyqt5: return QObject from slot - pyqt

I'm trying to expose a method to QML in pyqt 5, and I need it to return a custom QObject. I can't seem to work out anyway to do this. The snippet below shows roughly what I'm trying to do. I've tried changed the result parameter to QObject, "QObject", and various other types. Each either gives me a different error message, or if no error, the QML receives null instead of the object. I've also tried registering Bar as a type, but still no help.
What is the right way to return a custom object like this? (Note: we've had this working in C++ previously.)
class Bar(QObject):
# etc.
bar = Bar()
class Foo(QObject):
#pyqtSlot(int, result=QObject)
def foo(self, arg1):
return bar

class Foo(QObject):
#pyqtSlot(int, result=QObject)
def foo(self, arg1):
sip.transferto(bar, bar)
return bar

Related

How to type hint a function, added to class by class decorator in Python

I have a class decorator, which adds a few functions and fields to decorated class.
#mydecorator
#dataclass
class A:
a: str = ""
Added (via setattr()) is a .save() function and a set of info for dataclass fields as a separate dict.
I'd like VScode and mypy to properly recognize that, so that when I use:
a=A()
a.save()
or a.my_fields_dict those 2 are properly recognized.
Is there any way to do that? Maybe modify class A type annotations at runtime?
TL;DR
What you are trying to do is not possible with the current type system.
1. Intersection types
If the attributes and methods you are adding to the class via your decorator are static (in the sense that they are not just known at runtime), then what you are describing is effectively the extension of any given class T by mixing in a protocol P. That protocol defines the method save and so on.
To annotate this you would need an intersection of T & P. It would look something like this:
from typing import Protocol, TypeVar
T = TypeVar("T")
class P(Protocol):
#staticmethod
def bar() -> str: ...
def dec(cls: type[T]) -> type[Intersection[T, P]]:
setattr(cls, "bar", lambda: "x")
return cls # type: ignore[return-value]
#dec
class A:
#staticmethod
def foo() -> int:
return 1
You might notice that the import of Intersection is conspicuously missing. That is because despite being one of the most requested features for the Python type system, it is still missing as of today. There is currently no way to express this concept in Python typing.
2. Class decorator problems
The only workaround right now is a custom implementation alongside a corresponding plugin for the type checker(s) of your choice. I just stumbled across the typing-protocol-intersection package, which does just that for mypy.
If you install that and add plugins = typing_protocol_intersection.mypy_plugin to your mypy configuration, you could write your code like this:
from typing import Protocol, TypeVar
from typing_protocol_intersection import ProtocolIntersection
T = TypeVar("T")
class P(Protocol):
#staticmethod
def bar() -> str: ...
def dec(cls: type[T]) -> type[ProtocolIntersection[T, P]]:
setattr(cls, "bar", lambda: "x")
return cls # type: ignore[return-value]
#dec
class A:
#staticmethod
def foo() -> int:
return 1
But here we run into the next problem. Testing this with reveal_type(A.bar()) via mypy will yield the following:
error: "Type[A]" has no attribute "bar" [attr-defined]
note: Revealed type is "Any"
Yet if we do this instead:
class A:
#staticmethod
def foo() -> int:
return 1
B = dec(A)
reveal_type(B.bar())
we get no complaints from mypy and note: Revealed type is "builtins.str". Even though what we did before was equivalent!
This is not a bug of the plugin, but of the mypy internals. It is another long-standing issue, that mypy does not handle class decorators correctly.
A person in that issue thread even mentioned your use case in conjunction with the desired intersection type.
DIY
In other words, you'll just have to wait until those two holes are patched. Or you can hope that at least the decorator issue by mypy is fixed soon-ish and write your own VSCode plugin for intersection types in the meantime. Maybe you can get together with the person behind that mypy plugin I mentioned above.

Is a python `abstract property` that returns an abstract class an example of the Factory Pattern

I need to document my design, in particular, the design patterns used, and would like to use the standard terminology.
From Refactoring Guru, "Factory Method defines a method, which should be used for creating objects instead of direct constructor call. Subclasses can override this method to change the class of objects that will be created".
I have a CraneInterface class with an abstract method, and the signature of this method enforces that its return type is an implementation of an AxisInterface. Essentially, subclasses of CraneInterface "override this method to change the class of objects that will be created". The only diference with my version is that it does not necessarily "create" a new instance, it could also return one that already exists. Is this still the Factory Pattern? And if not, does this design pattern have a common name?
i.e: A traditional factory looks like this:
class IAnimal(ABC):
#abstractmethod
def speak(self):
pass
class Dog(IAnimal):
#overide
def speak(self):
print('Woof')
class Cat(IAnimal):
#overide
def speak(self):
print('Meow')
class AnimalFactory(ABC):
#abstractmethod
def make_animal(self) -> IAnimal:
pass
class CatFactory(AnimalFactory):
#overide
def make_animal(self) -> IAnimal:
return Cat()
class DogFactory(AnimalFactory):
#overide
def make_animal(self) -> IAnimal:
return Dog()
My code looks more like this:
class AnimalFactory2(ABC):
#property
#abstractmethod
def animal(self) -> IAnimal:
pass
class CatFactory2(AnimalFactory2):
def __init__(self):
self.__cat = Cat()
#overide
#property
def animal(self) -> IAnimal:
return self.__cat
class DogFactory2(AnimalFactory2):
def __init__(self):
self.__dog = Dog()
#overide
#property
def animal(self) -> IAnimal:
return self.__dog
Does the second example use the Factory Pattern? Does it have a different name or even have a name at all? The main difference is that it does not create a new instance each time it is called.
Extra info:
In my actual code, I have a 3 axis CraneInterface class that has abstract methods for all the ways you can interact with a crane. It is implemented by a CraneSimulator and a CraneOpcuaClient that actually talks to a real crane. The original design of the simulator implemented the abstract method inside the CraneSimulator class, however, this had lots of duplicated code, as every function of the crane was repeated for each of the 3 axes. To solve this, I created an AxisSimulation class which had methods to interact with it, and then there are 3 instantiations inside the CraneSimulator, and the implementations of the CraneInterface abstract methods simply forward the request to one of the 3 axis objects.
The problem was that the CraneInterface also needed the ability to notify "observers" whenever the state of the crane changed, for example, a position or temperature change. I.e the CraneInterface needed to have a function add_on_x_position_changed_callback(self, callback: Callable[[Position],None]). To do this, the CraneInterface had properties with custom setters that notified a list of observers whenever the value was set. By putting the AxisSimulation inside the CraneSimulator the properties had moved out of the CraneInterface, and the add_on_changed_callback methods of the CraneInterface would no longer work.
So to solve this, the CraneInterface had an abstract property to return an abstract AxisInterface class (like the AnimalFactory2 example). The AxisInterface then had the observable properties with a custom setter (and methods to add observers), so that users of the CraneInterface can add observers to the data.
I know that the "observable" part is an example of the Observer pattern, but is the deferring of the type of Axis implementation returned, an example of the Factory Pattern?
Thanks.

Python - can call same class twice(or more) in thread?

I don't very understand the classes logic in python but cannot answer on web.
I have create a class to generate person info:
class person:
def fristnameGen(gender):
...
def emailGen(firstname,surname):
...
i create a bot to call it like this:
from person import *
class bots:
def __init__(self):
self.person = person()
def createDB(self):
print(self.person.name)
#do something...
finally i call it by a button with thread
from bots import *
import threading
class Panel:
def __init__(self):
self.top = tk.Tk()
self.bot = bots()
self.buildUI()
def foo(self):
self.bot.createDB(self.stringPhone.get())
def threadTheAction(func, *args):
t = threading.Thread(target=func, args=args)
t.setDaemon(True)
t.start()
def buildUI(self):
Button = tk.Button(self.top, text ="Start", command = lambda :self.threadTheAction(self.foo))
I get this error:
TypeError: 'Panel' object is not callable
However, i call it directly, its work
Button = tk.Button(self.top, text ="Start", command = lambda :self.foo())
How to fix the error?
...
2. Moreover, i tried create p1 = person() and p2= person() and print it. Found p1 and p2 is a same person, i prefer each new a class have a new one. How to generate "new person" using classes?
Thank you
You seem to have a lot of confusion about Object Oriented Programming in Python. Some of your methods have self parameters and some do not, seemingly at random. That's the source of your current error.
The threadTheAction method in your Panel class is getting the Panel instance passed in as its first argument, but that's named func in the method (since you omitted self). The real function you're passing as an argument gets caught in the variable argument *args. When the thread tries unsuccessfully to call it, you get an exception. Adding self before func would fix the immediate problem:
def threadTheAction(self, func, *args):
I suspect if your code got further along, you'd run into other errors with other methods without self in their parameter lists. For instance, none of the methods you've shown in person are likely to work correctly.
As for your second question, you haven't shown enough of person to know what's happening, but you're probably doing instance variables wrong somehow. With no self parameter in the methods, that's almost inevitable (since you assign to self.whatever to set a whatever attribute on the current instance). If you need help squaring that away, I suggest you ask a separate question (Stack Overflow is best when each question is self-contained) and provide the full code for your person class.

How do I bind to a function inside a class and still use the event variable?

class Player():
def __init__():
...
def moveHandle(self, event):
self.anything = ...
box.bind("<Key>", Player.moveHandle)
The bind function sets self as the event variable and ignores/throws up an error for event. I can't find a way to pass the event argument to the correct variable and maintain self for that function, even if I use args*. I can do one or the other, but not both.
I'm probably just lacking some basic knowledge about classes to be honest, I taught them to myself and didn't do it very thoroughly.
If I made a syntax mistake, it's because of me rewriting out the code incorrectly; in my program, the code works until the variables get passed.
the problem is that you are trying to use an instance method as a class method.
consider the following:
class Player():
def __init__():
...
def moveHandle(self, event):
self.anything = ...
box.bind("<Key>", Player.moveHandle)
where box is an instance of something, but Player is not.
instead this:
class Player():
def __init__(self):
...
def moveHandle(self, event):
self.anything = ...
p = Player()
box.bind("<Key>", p.moveHandle)
creates an instance of the player class, and then binds to the instances method, not the class method.

Pyramid view class inheritance with #view_defaults and #view_config decorators

I have written up a view class that has multiple #view_config's with predicates set for a single route. I then have a subclass that overwrites a couple of the sub-functions, which affects how the view is made. Below is something similar, but with simplified code.
When visiting the view_a route, everything works fine. When visiting the view_b route, it shows "404 Not Found The resource could not be found".
It seems the #view_configs aren't 'inherited' and linked to the new #view_default. Is there a simple way to fix this, or will I have to switch to manually doing config.add_view()?
#view_defaults(route_name='view_a', renderer='templates/views.mak')
class View_A(object):
def message(self):
return 'This is view a'
#view_config(request_method='GET')
def get(self):
return {'message': self.message()}
#view_defaults(route_name='view_b')
class View_B(View_A):
def message(self):
return 'This is view b'
#view_config is a venusian decorator, and not a strictly traditional decorator. Not until .scan() is called will anything take effect.
This also means that they are not inherited, however venusian provides a class decorator named lift() that will do exactly as you wish.
The venusian API documentation shows that something like the following should work for your use case:
from venusian import lift
#view_defaults(route_name='view_a', renderer='templates/views.mak')
class View_A(object):
def message(self):
return 'This is view a'
#view_config(request_method='GET')
def get(self):
return {'message': self.message()}
#view_defaults(route_name='view_b')
#lift()
class View_B(View_A):
def message(self):
return 'This is view b'
At this point all your inherited functions will correctly have the #view_config applied. Now upon running .scan() your application will behave as expected.
Do note, that the inheritance of #view_defaults may change in the future: https://github.com/Pylons/pyramid/issues/1382.
This may or may not change your views as listed, depending on whether you expect the renderer to carry over from the super class.

Resources