As an Amazon Associate I earn from qualifying purchases from amazon.com

Get Ooey GUI with PyQt6 Zeep and AXL


You’re a Python aficionado. Need to construct a Python AXL administration and configuration app with a GUI? Have I obtained the answer for you. No, it’s not Tkinter or wxWidgets, which is predicated on the Gimp Toolkit (GTK). We’re speaking Qt, probably the most widespread frameworks for a number of platforms. wxWidgets has related options, however I’ve by no means been a fan of GTK.

Why not simply construct an app with an internet interface?

Good query. Manner again after I was editor-in-chief of Linux Journal, there was an enormous push for an Outlook clone known as Evolution. Evolution is a C# app on Mono, a Linux clone of .NET. I thought-about this a misguided effort and stated as a lot. It’s a idiot’s errand to perpetually chase function parity with Microsoft’s choices. And again then when Web dinosaurs roamed the earth, the world was already shifting towards Software program as a Service (SaaS) for user-facing purposes. In case you like Evolution, extra energy to you, however even Microsoft has come round to SaaS. The Workplace 365 web-based suite is superb. I can use my work Outlook account on the internet. And I exploit my private Workplace 365 Outlook account from inside an internet browser on Home windows and Linux. On the spot platform-neutral entry to Outlook and no want for Mono’s nucleosis.

A useful Python SOAP AXL interface with a contemporary Qt UI

As a lot as I pushed SaaS again then, right here’s the place I half methods. AXL is an administration and configuration API for Cisco UCM, not an API for user-facing apps. The best way I see it, if you wish to do administration of CUCM on the internet, there’s the online GUI that comes with CUCM. If you need a customized administration app, I choose an AXL software with a GUI native to the OS. Qt is a GUI framework that works on Home windows, Mac, and Linux. Better of all, Monty’s pinnacle of feat, Python, runs on all these platforms, and there’s a Python model of Qt known as PyQt. Throw in just a little Zeep, and also you’ve obtained a useful Python SOAP AXL interface with a contemporary Qt UI.

Right here’s how I begin

All the following examples are on Home windows. A number of the instructions might be totally different on a Mac or Linux, nevertheless it all works. If you wish to take a gander on the completed pattern app, you will get it from GitHub. I selected model 6, PyQt6 for this app, however you need to use earlier variations and modify the code accordingly. I’m utilizing a generic “>” command line immediate. Your immediate might be totally different. If coding in Python with Zeep is new to you, otherwise you need extra particulars on variations between platforms, try this studying lab.

First, I create a digital Python setting.

>python -m venv PyQtAXL

I create a Venture listing, change to the listing and activate the setting. Then I set up the libraries we want.

>cd PyQtAXL
>mkdir Venture
>cd Venture
>..Scriptsactivate
>pip set up zeep
>pip set up PyQt6

I get a message that pip isn’t the newest model, so I replace it.

>python -m pip set up --upgrade pip

Now I’m prepared to begin coding a easy getUser app, which I’ll name GetUser.py.

Right here’s what the app seems like if you first launch it (I entered my userid):

The PyQt6 App able to seek for a person

I click on “Search Username” and see this:

The Search Outcomes

Click on “Reset” and poof, the information disappears. (You might resize the window, too, however I didn’t trouble.)

Again to the Search display screen

The good factor about PyQt6 is that every one I closed with the Reset button is the “Outcomes” group field. That object goes away, together with all of the little one objects contained in the field, together with even the reset button. So, you possibly can click on “Search Username” and “Reset” as many occasions as you want and never expertise any in poor health results.

Now let’s take a look at the code. Don’t copy and paste something that follows. There’s much more to this app than I’m exhibiting right here. We’ll see all the app later. This part is an abbreviated rationalization of the way it works.

The AXL request seems like this:

    standards = {
        'userid' : userid
    }
    response = self.service.getUser(**standards)

If you wish to see all the JSON response, add a print(response) in your code and all the response will present within the CMD window the place you run the app. For our functions, I’ll present solely the info we plan to make use of:

{
    'return': {
        'person': {
            'firstName': 'nicholas',
            'displayName': 'nicholas petreley',
            'middleName': None,
            'lastName': 'petreley',
            'userid': 'nicholas',
            'associatedDevices': {
                'system': [
                    'CSFNicholas',
                    'SEP2C31246D2458',
                    'SEP5475D0785AD4'
                ]
            }…

Let’s do some Python to get the person values we wish to present (we’ll get fancy with this later once we use PyQt6 – that is simply straight Python, extracting information from the dictionary and record within the above JSON):

        d = response['return']['user']
        fname = d['firstName']
        lname = d['lastName']
        dname = d['displayName']

        advert = response['return']['user']['associatedDevices']['device']
        for worth in advert:
            values[ad.index(value)] = worth

Now we want some solution to show all this information in a GUI app utilizing the Qt framework. We’ll create a window with an enter subject the place you’ll kind a username, and a button that tells the app to seek for that person. Like every good platform-neutral framework, Qt makes use of layouts. Layouts make it potential for an app to look good with out having to specify the placement of objects in X,Y coordinates or specify sizes. On this case, we’ll use a horizontal format, with the search button to the left of the enter subject.

class MainWindow(QWidget):
    def __init__(self, *args, **kwargs):
        tremendous(MainWindow, self).__init__(*args, **kwargs)

        self.initUI()

    def initUI(self):
        button = QPushButton("Search Username")
        self.enter = QLineEdit()

        hbox = QHBoxLayout()
        hbox.addWidget(button)
        hbox.addWidget(self.enter)
        self.enter.setText('nicholas')
        hbox.addStretch(1)

        button.clicked.join(self.search_user)

As you possibly can see, I preload the QLineEdit subject, self.enter.setText('nicholas'), with my identify so I don’t should kind it after I run the app. The pattern app doesn’t have that line of code.

Observe that I join the button clicked occasion to a technique known as self.search_user. Extra on that later. Proper now, we want a spot to place the search outcomes and a solution to wrap this up with a window title. Let’s create a vertical field format for the outcomes, add the title, after which do the compulsory “present” command so you possibly can see what we’ve accomplished.

        self.vbox = QVBoxLayout()
        self.vbox.addLayout(hbox)
        self.vbox.addStretch(1)

        self.setLayout(self.vbox)
        self.setWindowTitle("getUser")
        self.present()

We’re going to point out the search leads to the strategy known as “self.search_user”. To make the outcomes fancy pants, we’ll put them in a single “outcomes” group field that accommodates two extra group bins; one for the identify information, the opposite for the related gadgets.

        self.resBox = QGroupBox("Outcomes")
…
        self.groupBox = QGroupBox("Consumer")
…
        self.adGroup = QGroupBox("Related Units")

Every field has its personal format. The outcomes field might be a easy format that places its youngsters in a vertical stack.

        self.resBox = QGroupBox("Outcomes")
        self.vresBox = QVBoxLayout()
        self.resBox.setLayout(self.vresBox)

We wish labels to the left of values within the identify information, so we’ll use a grid format with two columns for that. We specify the columns once we add the info, not once we outline the grid.

        self.groupBox = QGroupBox("Consumer")
        self.gridBox = QGridLayout()
        self.groupBox.setLayout(self.gridBox)

Once we put the info in that grid, we specify the row and column for labels and information. The primary label, self.fl, goes in row 0, column 0. The primary information subject self.fe goes in row 0, column 1. And so forth.

        self.fl = QLabel('First Identify')
        self.fe = QLineEdit(d['firstName'])
        self.ll = QLabel('Final Identify')
        self.le = QLineEdit(d['lastName'])
        self.dl = QLabel('Show Identify')
        self.de = QLineEdit(d['displayName'])

        self.groupBox.setLayout(self.gridBox)
        self.gridBox.addWidget(self.fl,0,0)
        self.gridBox.addWidget(self.fe,0,1)
        self.gridBox.addWidget(self.ll,1,0)
        self.gridBox.addWidget(self.le,1,1)
        self.gridBox.addWidget(self.dl,2,0)
        self.gridBox.addWidget(self.de,2,1)

The record of related gadgets is a merely vertical record field. We’ll make all of them QLineEdit fields.

        self.adGroup = QGroupBox("Related Units")
        self.advbox = QVBoxLayout()
        self.adGroup.setLayout(self.advbox)

        for worth in advert:
            values[ad.index(value)] = QLineEdit(worth)
            self.advbox.addWidget(values[ad.index(value)])

Now let’s add the reset button and join it to the self.resetBox technique.

        self.resetButton = QPushButton("Reset")
        self.resetButton.clicked.join(self.resetBox)

Now we embed all of the widgets the place they go. We add the identify information field self.groupBox to the vertically oriented outcomes field, self.vresBox, which we outlined above. We add the related gadgets field self.adGroup to the identical self.vresBox. We add the reset button to the outcomes field self.vresBox. And to wrap issues up, we add the outcomes field self.resBox to the primary UI vertical field we outlined a lot earlier, self.vbox. Inform the app to point out what now we have, and voila, we see the outcomes display screen.

        self.vresBox.addWidget(self.groupBox)
        self.vresBox.addWidget(self.adGroup)
        self.vresBox.addWidget(self.resetButton)
        self.vbox.addWidget(self.resBox)
        self.present()

Now we simply want so as to add the strategy that resets the outcomes:

    def resetBox(self):
        self.resBox.shut()

As you possibly can see, all now we have to shut is the outcomes group field that accommodates all the outcomes information youngsters.

Now it’s time to see the entire enchilada, together with the Zeep SOAP code. You’ll see that issues aren’t precisely within the above order. The above examples are supposed to present how PyQt6 works. In precise follow, the code might be shuffled round as desired. Additionally, utilizing “import *” is frowned upon in Python, however I used it with PyQt6 on this code to make it easier to learn. If you write your individual app, you must specify the widgets and objects you plan to make use of from the libraries.

from PyQt6.QtGui import *
from PyQt6.QtWidgets import *
from PyQt6.QtCore import *
from lxml import etree
from requests import Session
from requests.auth import HTTPBasicAuth
from zeep import Shopper, Settings, Plugin
from zeep.transports import Transport
from zeep.cache import SqliteCache

import argparse

import sys

# Parse command line arguments. 
# Overwrite them with values on your personal CUCM utilizing or use command line args

def parse_args():

    parser = argparse.ArgumentParser()
    parser.add_argument('-u', dest="username", assist="AXL username", required=False, default="administrator_username")
    parser.add_argument('-p', dest="password", assist="AXL person password", required=False, default="administrator_password")
    parser.add_argument('-s', dest="server", assist="CUCM hostname or IP deal with", required=False,default="your_ucm_server")
    args = parser.parse_args()
    return vars(args)

class MainWindow(QWidget):
    def __init__(self, *args, **kwargs):
        tremendous(MainWindow, self).__init__(*args, **kwargs)

        self.initUI()

        # The WSDL is an area file
        WSDL_URL = 'AXLAPI.wsdl'

        # Parse command line arguments
        cmdargs = parse_args()
        USERNAME, PASSWORD, SERVER = (
            cmdargs['username'], cmdargs['password'], cmdargs['server'] )
        CUCM_URL = 'https://' + SERVER + ':8443/axl/'

        # That is the place the meat of the applying begins
        # Step one is to create a SOAP shopper session
        session = Session()

        # We keep away from certificates verification by default, however you possibly can set your certificates path
        # right here as a substitute of the False setting
        session.confirm = False
        session.auth = HTTPBasicAuth(USERNAME, PASSWORD)

        transport = Transport(session=session, timeout=10, cache=SqliteCache())

        # strict=False shouldn't be all the time essential, nevertheless it permits zeep to parse imperfect XML
        settings = Settings(strict=False, xml_huge_tree=True)

        shopper = Shopper(WSDL_URL, settings=settings, transport=transport)

        self.service = shopper.create_service("{http://www.cisco.com/AXLAPIService/}AXLAPIBinding", CUCM_URL)

    def initUI(self):

        button = QPushButton("Search Username")
        self.enter = QLineEdit()

        hbox = QHBoxLayout()
        hbox.addWidget(button)
        hbox.addWidget(self.enter)
        self.enter.setText('nicholas')

        button.clicked.join(self.search_user)

        self.vbox = QVBoxLayout()
        self.vbox.addLayout(hbox)
        self.vbox.addStretch(1)

        self.setLayout(self.vbox)
        self.setWindowTitle("getUser")
        self.present()

    def search_user(self):
        userid = self.enter.textual content()
        standards = {
            'userid' : userid
        }
        response = self.service.getUser(**standards)

        self.resBox = QGroupBox("Outcomes")
        self.vresBox = QVBoxLayout()
        self.resBox.setLayout(self.vresBox)

        d = response['return']['user']
        self.fl = QLabel('First Identify')
        self.fe = QLineEdit(d['firstName'])
        self.ll = QLabel('Final Identify')
        self.le = QLineEdit(d['lastName'])
        self.dl = QLabel('Show Identify')
        self.de = QLineEdit(d['displayName'])

        self.groupBox = QGroupBox("Consumer")
        self.gridBox = QGridLayout()
        self.groupBox.setLayout(self.gridBox)
        self.gridBox.addWidget(self.fl,0,0)
        self.gridBox.addWidget(self.fe,0,1)
        self.gridBox.addWidget(self.ll,1,0)
        self.gridBox.addWidget(self.le,1,1)
        self.gridBox.addWidget(self.dl,2,0)
        self.gridBox.addWidget(self.de,2,1)

        self.adGroup = QGroupBox("Related Units")
        self.advbox = QVBoxLayout()
        self.adGroup.setLayout(self.advbox)

        advert = response['return']['user']['associatedDevices']['device']
        values = dict()
        for worth in advert:
            values[ad.index(value)] = QLineEdit(worth)
            self.advbox.addWidget(values[ad.index(value)])

        self.resetButton = QPushButton("Reset")
        self.resetButton.clicked.join(self.resetBox)

        self.vresBox.addWidget(self.groupBox)
        self.vresBox.addWidget(self.adGroup)
        self.vresBox.addWidget(self.resetButton)
        self.vbox.addWidget(self.resBox)
        self.present()

    def resetBox(self):
        self.resBox.shut()

def most important():

    app = QApplication(sys.argv)
    su = MainWindow()
    sys.exit(app.exec())

if __name__ == '__main__':
    most important()

app.exec()

You possibly can seize the above pattern code right here. Ensure to obtain the AXL SQL toolkit from UCM and put the suitable WSDL and XSD information in the identical listing because the app. Directions on how to do this are included within the Python/Zeep Studying Lab.

When you get the cling of utilizing PyQt6, it’s a really pleasing API to work with. You’ll rapidly develop advanced prototype purposes that you may promote to manufacturing apps nearly as quick.

Assets:

PyQt6 Documentation

Python/Zeep Studying Lab

GetUser.py pattern app on GitHub

Share:

We will be happy to hear your thoughts

Leave a reply

Dealssoreal
Logo
Enable registration in settings - general
Compare items
  • Total (0)
Compare
0
Shopping cart