QGIS Plugin – Workflow to Convert Python Script Without UI File

convertpyqgis-3pythonqgis-3qgis-plugins

There is a 'startup.py' file with Python script (1200 rows) written by somebody. It works like a QGIS Plugin, see image below.

input

What are the steps needed to convert this script into a proper QGIS Plugin? Otherwise, how to get the UI files out of Python code?

My initial idea is to start with the pb_tool and then break the 'startup.py' file into modules and insert into the plugin skeleton. However, it works with the '…_dialog_base.ui' file which I do not have.

Perhaps it is better to deploy the Plugin Builder, but it is similar to what the pb_tool does.

The person who created the script used the QtDesigner, however, the UI files were heavily modified by hand. Only an old version of the current layout exists.

There is also left a 'uic.exe' file in the QtCompiler dir. Some information on how to run the is described here : QT designer didn't install uic program for view the code from the application. In my case it must be placed under C:\Program Files\QGIS 3.20.3\apps\qt5\bin\bin.

uic.exe

The 'startup.py' file consists of the following parts:

imports

    import sys
    from PyQt5.QtWidgets import *
    from PyQt5.QtCore import *
    from PyQt5.QtGui import *
    from qgis.core import *
    from qgis.utils import *
    from qgspasswordlineedit import QgsPasswordLineEdit

----------------------------
configuration files
----------------------------
functions
----------------------------
layouts / pages

    ###Layouts

    #Page1
    class IntroPage(QWizardPage):

        def __init__(self, parent=None): 
            super(IntroPage, self).__init__(parent)
            ...
    #Page2
    class LayerPage(QWizardPage):

         def __init__(self, parent=None): 
            super(LayerPage, self).__init__(parent)
            ...

    #page 3
    class AuthPage(QWizardPage):
        
        def __init__(self, parent=None): 
            super(AuthPage, self).__init__(parent)
            ...

    #QWizard Class
    class Window(QWizard): 

        def __init__(self):
            super(Window, self).__init__()
            #adds Pages to Wizard
            self.IntroPage = IntroPage()
            self.LayerPage = LayerPage()
            self.AuthPage = AuthPage()
            self.addPage(self.IntroPage)
            self.addPage(self.LayerPage)
            self.addPage(self.AuthPage)
            #Button check if Oracle or Postgre Data selected
            self.button(QWizard.NextButton).clicked.connect(lambda x:OraclePostgreCheck(self.AuthPage.frame_2, self.AuthPage.frame_4))
            #Readjust GUI size at buttonclick
            self.button(QWizard.NextButton).clicked.connect(self.adjustSize)
            self.button(QWizard.BackButton).clicked.connect(self.adjustSize)

----------------------------
code that runs the program

    ### 
    #Programm starts
    
    #loadConfigCSV(URI,";")
    loadPaketConfigJSON(PURI)
    loadConfigJSON(URI)
    kategoriesJSON()
    #loadConfigtoQGIS() #load config for export during development
    
    
    #GUI
    window = Window()
    window.setWizardStyle(1)
    window.show()
    
    #Programm ends
    ###

Best Answer

Inspiration for this answer was found in @J.Monticolo's comment

So, for me, put the startup.py file into a your_plugin_name_or_whatever.py, do a function called def launch_code and put the startup.py "code that runs the program" part into it, and then, in you plugin generated by pb_tool, put a call to launch_code in the def run, function called by plugin menu button click.

and in this article : Customizing QGIS with Python | 14.1 A Minimal Plugin.

This steps helped me to achieve the aim

Step 1. Put the content of the startup.py file inside of one function e.g. launch_code() in a new Python file

main.py :

def launch_code():
    imports

        import sys
        from PyQt5.QtWidgets import *
        from PyQt5.QtCore import *
        from PyQt5.QtGui import *
        from qgis.core import *
        from qgis.utils import *
        from qgspasswordlineedit import QgsPasswordLineEdit

    ----------------------------
    configuration files
    ----------------------------
    functions
    ----------------------------
    layouts / pages

        ###Layouts

        #Page1
        class IntroPage(QWizardPage):

            def __init__(self, parent=None): 
                super(IntroPage, self).__init__(parent)
                ...
        #Page2
        class LayerPage(QWizardPage):

             def __init__(self, parent=None): 
                super(LayerPage, self).__init__(parent)
                ...

        #page 3
        class AuthPage(QWizardPage):
            
            def __init__(self, parent=None): 
                super(AuthPage, self).__init__(parent)
                ...

        #QWizard Class
        class Window(QWizard): 

            def __init__(self):
                super(Window, self).__init__()
                #adds Pages to Wizard
                self.IntroPage = IntroPage()
                self.LayerPage = LayerPage()
                self.AuthPage = AuthPage()
                self.addPage(self.IntroPage)
                self.addPage(self.LayerPage)
                self.addPage(self.AuthPage)
                #Button check if Oracle or Postgre Data selected
                self.button(QWizard.NextButton).clicked.connect(lambda x:OraclePostgreCheck(self.AuthPage.frame_2, self.AuthPage.frame_4))
                #Readjust GUI size at buttonclick
                self.button(QWizard.NextButton).clicked.connect(self.adjustSize)
                self.button(QWizard.BackButton).clicked.connect(self.adjustSize)

    ----------------------------
    code that runs the program

        ### 
        #Programm starts
        
        #loadConfigCSV(URI,";")
        loadPaketConfigJSON(PURI)
        loadConfigJSON(URI)
        kategoriesJSON()
        #loadConfigtoQGIS() #load config for export during development
        
        
        #GUI
        window = Window()
        window.setWizardStyle(1)
        window.show()
        
        #Programm ends
        ###

Step 2. Create two Python files qgsdata.py and __init__.py that will bring this Plugin into action

qgsdata.py :

import os
import inspect

from PyQt5.QtGui import *
from PyQt5.QtWidgets import *

from qgis.core import *
from qgis.utils import *

from .main import launch_code

cmd_folder = os.path.split(inspect.getfile(inspect.currentframe()))[0]

class QgsDataPlugin:
    def __init__(self, iface):
        self.iface = iface

    def initGui(self):
        icon = os.path.join(os.path.join(cmd_folder, 'icon.png'))
        self.action = QAction(QIcon(icon), 'QgsData', self.iface.mainWindow())
        self.action.triggered.connect(self.run)
        self.iface.addPluginToMenu('&My Plugins', self.action)
        self.iface.addToolBarIcon(self.action)

    def unload(self):
        self.iface.removeToolBarIcon(self.action)
        self.iface.removePluginMenu('&My Plugins', self.action)
        del self.action

    def run(self):
        launch_code()

__init__.py :

# noinspection PyPep8Naming
def classFactory(iface):  # pylint: disable=invalid-name
    """
    Load QgsData class from file QgsData.
    :param iface: A QGIS interface instance.
    :type iface: QgsInterface
    """
    from .qgsdata import QgsDataPlugin
    return DataPlugin(iface)

Step 3. Edit/Create corresponding metadata.txt and pb_tool.cfg files

Step 4. Run the pbt deploy command in the CMD and get a working QGIS Plugin under C:\Users\taras\AppData\Roaming\QGIS\QGIS3\profiles\default\python\plugins\QgsDataPlugin

Related Question