Menu

"call" not Returning Anything

Help
2019-11-19
2019-11-21
  • Flower lady

    Flower lady - 2019-11-19

    Hello all,

    I've been wrestling with this issue for a while, and I'm at my wit's end, so here we go. I'm trying to follow Florian's instructions to instantiate a class, as per this thread from many years ago: https://sourceforge.net/p/pythonqt/discussion/631393/thread/6a851191/. I would then like to call methods of this class.

    To do this, I am trying to return an instance of the class as ssuch:

    QVariant instance = PythonQt::self()->getMainModule().call("HelloWorld", QVariantList(), QVariantMap());
        PythonQtObjectPtr instancePtr = PythonQtConv::QVariantToPyObject(instance);
    

    This instantiates the class properly, but my PythonQtObjectPtr "instancePtr" is null, and my QVariant "instance" variable is invalid. Has this behavior changed in since the thread I'm referring to was posted? Since I'm not getting a PythonQtObjectPtr back, I haven't been able to figure out a way to call any methods of this class instance.

    For reference, here is my python script

    """
    Test script
    """
    from PythonQt.scriptedBehaviors import PythonBehavior
    
    class HelloWorld(PythonBehavior):
        def __init__(self):
            super().__init__()
            self.log_info("CONSTRUCTED PYTHON BEHAVIOR")
    
        def initialize(self):
            self.log_info("INITIALIZED BEHAVIOR")
            return
    
        def update(self):
            self.log_info("UPDATING BEHAVIOR")
            return
    

    I register the class as such:

        PythonQt::init();
    
        // Register types that are python-compatible
        PythonQt::self()->registerCPPClass("PythonBehavior", 
            "Object", 
            "scriptedBehaviors",
            PythonQtCreateObject<PythonBehaviorWrapper>);
    

    And the class (with wrapper) looks like this:

    class PythonBehavior: public Object {
    public:
    
        PythonBehavior();
    
        virtual void initialize(){}
    
    };
    
    class PythonBehaviorWrapper : public QObject, public Object {
        Q_OBJECT
    public:
    
        PythonBehaviorWrapper():
        QObject(){}
    
    public slots:
        /// @brief Add a constructor
        PythonBehavior* new_PythonBehavior();
    
        /// @brief Add a destructor
        void delete_PythonBehavior(PythonBehavior* o) { delete o; }
    
        /// @brief Script routines
        void initialize(PythonBehavior* o);
    
    };
    
     

    Last edit: Flower lady 2019-11-19
  • Florian Link

    Florian Link - 2019-11-20

    probably you get a C++ pointer back, because your Python object inherits from a C++ class.
    I think you should reconsider your design and not derive your Python objects from C++ objects.
    I would create a Python base class and derive from that. If you want to access C++ parts of your application from it, I would create a Qobject that exposes my application Api and pass it to the constructor of the base class.

    Deriving from C++ objects in Python only makes sense when having full wrappers with virtual method dispatch, like the ones generated for Qt (where you want to used derived classes at places where only C++ is known, e.g. deriving from Qwidget)

     
  • Flower lady

    Flower lady - 2019-11-20

    Hi Florian, thanks for the response. I tried what you said, and now my class is simply:

    class HelloWorld():
        def __init__(self):
            pass
    
        def initialize(self):
            return
    
        def update(self):
            return
    

    As before, I am trying to create a class instance via:

    QVariant instance = PythonQt::self()->getMainModule().call("HelloWorld", QVariantList(), QVariantMap());
        QString type = instance.typeName();
        PythonQtObjectPtr instancePtr = PythonQtConv::QVariantToPyObject(instance)
    

    The instance I get back doesn't seem to be invalid anymore, but it seems like the type string I try to return points to invalid place in memory. I am also still getting a nullptr when I try to obtain my instancePtr variable. Is there something else I could be messing up?

    Update, replacing my previous type check with:

    int type = instance.userType();
    QString types = QVariant::typeToName(type);
    

    Shows that my QVariant is of the type "PythonQtSafeObjectPtr". So this seems above board. And in fact, this pointer looks valid in the inspector before I leave the function that is calling the block. It seems like the contents of the instancePtr are being cleared when I leave the function scope, even though the instancePtr is an output of my method:

       PythonQtObjectPtr PythonClassScript::instantiate()
    {
        QVariant instance = PythonQt::self()->getMainModule().call("HelloWorld");
    ...
        PythonQtObjectPtr instancePtr = PythonQtConv::QVariantToPyObject(instance);
        //QString name = instance.typeName();
        return instancePtr;
    }
    

    Is this some strangeness in the behavior of PythonQtObjectPtr objects? I wouldn't expect instancePtr to go out of scope here.

     

    Last edit: Flower lady 2019-11-20
  • Flower lady

    Flower lady - 2019-11-20

    Hello again, I've been thinking about this, and I'm wondering if this object is disappearing because it's not actually getting assigned to an explicit variable with a name? Is there an elegant way of achieving this? I could try by calling PythonQt::self->mainModule()->evalScript(...), but I'm thinking there must be a better way than that.

    Update:

    Running:
    QVariant instance = PythonQt::self()->getMainModule().evalScript("test=HelloWorld()");

    Does not work either, I get an invalid QVariant returned.

     

    Last edit: Flower lady 2019-11-20
  • Flower lady

    Flower lady - 2019-11-21

    Okay all, I got this working via:

    PythonQt::self()->getMainModule().evalScript("test=HelloWorld()");
    QVariant instance = PythonQt::self()->getMainModule().getVariable("test");
    PythonQtObjectPtr instancePtr = PythonQtConv::QVariantToPyObject(instance);
    

    One side problem that I've had was that PythonQt's parseFile() was failing on fflush sporadically. I have no idea why, but I replaced those routines with my own parser, and things are behaving nicely. Thanks!

     

Log in to post a comment.

Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.