Learning to Learn

The fast pace of change in today’s world means we must understand and quickly respond to changes. Hence, in order to survive and be successful in today’s VUCA world, we need to constantly scan for growth opportunities and be willing to learn new skills.

Working in software industry helps me to realise that with all the disruptions in the modern world, especially technology, ongoing skill acquisition is critical to persistent professional relevance. We shall always look for ways to stretch ourselves to get ahead.

Even though I have been dealing with cloud computing, especially Microsoft Azure, for more than 10 years in my career and study, I still would like to find out how well I compare with my peers instead of thinking that I’m already fine at this area. Hence, with that in mind, I focus on learning Microsoft Azure development related skills on Microsoft Learn during the holiday.

Make the Most of Our Limited Learning Time

So much to learn, so little time.

We all have very little time for learning outside of our work. Combine time we have for learning and the importance of the skills, we can get a simple 2×2 matrix with four quadrants.

2×2 matrix to help prioritizing skills to learn (Reference: Marc Zao-Sanders)

I don’t have much time to keep my cloud computing knowledge relevant because nowadays I focus more on desktop application development. Hence, I decided to give myself a one-week break from work and schedule 6-7 hours each day for learning in the holiday.

In order to make sure we’re investing our time wisely, we shall focus on learning what is needed. Unless we need the skill for our job or a future position, it’s better not to spend time and money for training on that skill because learning is an investment and we shall figure out what the return will be. This is why I choose to learn more about developing cloud apps on Microsoft Azure because that has been what I’m doing at work in the past decade.

To better achieve my goals in self learning, I’ve also identified the right learning materials before I get started. Since I already have the experience of developing modern cloud applications early in my career, I choose to focus only on going through all the 43 relevant modules available on the Microsoft Learn.

Make Learning a Lifelong Habit

No matter which technology era we are in, the world will always belong to people who are always keeping themselves up to date. Hence, lifelong learning is a habit many of us would like to emulate.

Before we start our learning journey, we need to set realistic goals, i.e. goals that are attainable, because there are limits to what we can learn. In addition, as we discussed earlier, we need to ask ourselves how much time and energy we can give to our self learning. We have to understand that learning a skill takes extreme commitment, so we can’t get very far on the journey of self learning if we don’t plan it properly.

Learning is hard work but it also can be fun, especially when we are learning together with like-minded people. Don’t try to learn alone, otherwise self learning can feel over-whelming. For example, besides learning from online tutorials, I also join local software development groups where members are mostly developers who love to share and learn from each other.

Azure Community Singapore, for all who are interested in cloud technology.

Finally, to improve our ability to learn, we also have to unlearn, i.e. choose an alternative mental model or paradigm. We should acknowledge that old mental model is not always relevant or effective. When we fail, we also should avoid defending ourselves and capture the lessons we’ve learned.

Certification and Exam

I’m now a Microsoft certified Azure Developer Associate after I passed their exam AZ-204 in November 2021.

The exam is not difficult but it’s definitely not easy as well.

The exam tests not only our knowledge in developing cloud solutions with Azure services such as Azure Compute and Storage Account, but also our understanding of cloud security and Azure services troubleshooting.

Clearing all the relevant modules on Microsoft Learn does not guarantee that one will pass the exam easily. In fact, it’s the skills and knowledge I gain from work and personal projects help me a lot in the exam, for example the service bus implementation that I learnt last year when I was building a POC for a container trailer tracking system.

How Microsoft Learn helps in my self learning is that it provides an opportunity for me to learn in a free sandbox environment. In addition, the learning materials on the platform are normally best practices to follow. Hence, by learning on Microsoft Learn, I find out some of the mistakes I’ve made in the past and things that I can improve, for example resource management with tags, RBAC, VNet setup, etc.

Notes taken when I was going through the learning materials on Microsoft Learn.

I use Notion to take notes. Notion is a great tool to keep our notes clean and organised. Taking notes helps me to do a last-minute quick revision.

Conclusion

In a fast-moving world, being able to learn new skills helps in our life. There are many ways to learn continuously in our life. Earning certificates by going through challenging exams is just one of the methods. You know what works for yourself, do more of it.

Stay hungry. Stay foolish.

References

Celebrate My 3rd Year of Working in NUS

This month marks the beginning of my 3rd year of working as a software engineer in National University of Singapore (NUS). Hence, at this juncture, I would like to give myself an opportunity to broaden my horizon so that I can live up to the expectations of the team and continue to grow professionally.

Coincidentally, it’s NUS Well-Being Day in the beginning of the month. All the staff and students can have a long holiday to rest and re-energise.

7 PitStop Principles for Mental Wellbeing

In the beginning of Well-Being Day, NUS introduced the 7 PitStop Principles to aid everyone in the campus in stress management and self care. The seven principles are as listed below.

  1. Personal Skills;
  2. Interactions;
  3. Time Out;
  4. Sleep;
  5. Thoughtful Eating;
  6. On the Move;
  7. Purpose.

In order to make my life better by enhancing my mental wellbeing, I have tried to adopt the principles as a part of my lifestyle during the long holiday.

Personal Skills

As Eduardo Briceño shared in his Ted talk, in our life, there are two key zones, i.e. the Performance Zone and the Learning Zone.

The Performance Zone is where we apply our knowledge and skills to carry out our tasks. The Learning Zone on the other hand is all about improving our current skills and learning new skills.

The problem why many people don’t improve much is that they spend all of their time in their performance zone. They simply do, do, do but seldom reflect on it. Hence, in his talk, Eduardo Briceño suggested that we should frequently switch between the two zones.

During the NUS Well-Being Day long holiday, it’s also coincidentally the launch of Visual Studio 2022 and .NET 6. Both of them are the key tools in my career. Hence, I took the opportunity to learn what’s new during the launch event.

Joining the Microsoft team for the launch of Visual Studio 2022 to learn about what’s new. (Image Source: Microsoft Visual Studio)

I have been focusing more on desktop and mobile app development in my past two years of working in NUS. Before that, I had always been working on web development projects which required skills in cloud computing.

Hence, in order to keep my skill relevant, I also took 6 to 7 hours per day to take some modules on Microsoft Learn to enhance my knowledge in designing, building, testing, and maintaining cloud applications and services on Microsoft Azure.

Interactions

Social isolation and loneliness can affect one’s physical and mental health. Hence, family and friends play an important role in our healthy life.

Having a cup of coffee with friend in a quiet evening is enjoyable. (Image Source: PxHere)

I’m glad to have the opportunity to have a talk with Riza Marhaban, my friend and my mentor, in one of the evenings. This is a type of happiness especially in the current situation of pandemic because meeting friends is not as easy as the good old days.

In addition, during the holiday, I attended Dato Yeo Kok Hwa’s session about Disrupting Negative Thoughts organised by NUSHeart. Dato Yeo shared with us the symptoms and causes of negative thoughts as well as how we can apply strategies to disrupt those negative thoughts.

Dato Yeo talked about how some of us have Automatic Negative Thoughts (ANTs). For example, it could be because some people over-generalise things in their life in such a way that they view a negative event as a never-ending pattern of defeat. It also could be because some people dwell on the negatives and ignore the positives. Hence, it’s important to have alternative thinking which helps us to change the way we think.

Dato Yeo Kok Hwa’s session about Disrupting Negative Thoughts.

Time Out

I’m not sure about the rest of NUS staff, but I find that the working life in NUS research centre is challenging. Hence, it’s important for me to take time out for myself.

Before the holiday, Riza was telling me that Queen’s Gambit is a must-watch miniseries on Netflix. So I took the chance to watch it during the holiday. I haven’t stopped thinking about the series since finishing it because it was just that good.

Besides watching movie, I also played Command and Conquer 3 which is one of my favourite RTS games during the holiday. This video game was released in 2007. After 14 years have passed, I finally got the time to play it.

Pew pew.

Coincidentally, HoYo FEST was happening in Singapore during the holiday as well. So, I took the opportunity to visit their café.

Mei senpai!

Sleep

When I was working in startups, I lost a night or two of sleep especially when there is a deadline to meet. This is normal because sleep is undervalued in a startup culture where being busy and working beyond capacity is celebrated. Now in my current work life, I decide to sleep more.

During the holiday, I had 10 hours of sleep/rest per day on average.

Thoughtful Eating

Even though I’m not allowed to cook in the place I rent, I still try my best to avoid unhealthy food. It has been more than one year I stop consuming fast food.

In addition, eating slower also helps. The benefits of slow eating include better digestion, better hydration, easier weight loss or maintenance, and greater satisfaction with our meals.

There is a lot of good food available in the campus.

On the Move

In 2018, a WHO report estimates that more than a quarter of people worldwide – 1.4 billion – are not doing enough physical exercise, a figure that has barely improved since 2001.

Currently, I am still trying to exercise for at least 20-minutes, 3 times a week.

My friend Jon introduced me a home workout video for beginner like me. You can refer to the video below if you are also finding ways to stay healthy during the lockdown period.

Purpose

Research suggests that people who volunteer actually experience a boost in their mental health.

I have been volunteering in National Library Board until the volunteering opportunity was cancelled in May 2021 due to the Covid-19 situation. So, there is nothing much to share about this until the volunteering programme is back.

The new library at Harbour Front that I was always volunteering at.

That’s all for how I celebrate both my 3rd year of working in NUS and the NUS Well-Being Day. I hope reading this brought you some inspiration.

References

Publishing New Xamarin.Forms App with AAB to Play Store

In the past, we published our Android app with APK, or Android Package file format, to the Google Play Store. However, starting from August 2021, if we have new apps to be published to the Google Play Store, we must use the AAB format, or Android App Bundle, instead.

AAB was first introduced in May 2018. AAB is a publishing format that includes all the compiled code and resources of our app, and defers APK generation and signing to Google Play. AAB also makes our app smaller (on average, 15% smaller than a universal APK) and faster to download.

Hence, today in this article, we will see how we can publish our Android app which is newly built using Xamarin.Forms in AAB format to the Google Play Store.

Step 0: Configure MainActivity And Android Manifest

In the Android project, we will see a class called MainActivity which is used to powered our Android app. It has an attribute called Activity which lets Android know that the class is part of the app managed by the Android Manifest.

There are many properties in the Activity attribute. One of them is called MainLauncher. By default, MainLauncher will be set to true for MainActivity class to state that the MainActivity is where our app starts up.

Step 0.1: App Name, Icon, and MainActivity

We also can customise our app name by updating the Label property in MainActivity Activity attribute. However, please take note that the value of Label here will override the app name value in the Android Manifest. Hence, it is preferable to delete the Label property here and set the name in the Android Manifest instead with strings.xml.

Relative sizes for bitmaps at different density sizes. (Image Source: Android Developers)

The Icon property here specifies the application icon. By default, it is set to be “@mipmap/icon”. Hence, we simply need to update the icon.png files in all the mipmap folders. We don’t use drawable folder because our app icon may need to be scaled differently on different UIs. The launcher app will then pick the best resolution icon to display on the screen. An alternative to creating multiple density-specific versions of an image is to create just one vector graphic.

Finally, if you are using Xamarin plugins, such as Rg.Plugins.Popup, you will be asked to configure the ConfigurationChanges property. This is to declare that our app handles the configuration change itself which prevents the system from restarting our activity.

Step 0.2: App Manifest

Updating Android Manifest of the Android project in Visual Studio. (Screenshot A)

Android Manifest allows us to describe the functionality and requirements of our Android app. We can either directly edit the AndroidManifest.xml file or edit it through the Properties window of the Android project.

Step 0.2.1: Android API Level

In the manifest, we can specify the minimum and target Android versions.

By November 2021, all apps that are being updated must target at least API Level 30, as shown in the announcement in Google Play Policies screenshot below.

Apps now must target API Level 30.

In addition, in order to not make our app to run on Android devices which are still using the discontinued Dalvik VM, we shall set minimum Android API Level to be 21 at least. According to the chart provided in Android Studio, we can see that 94.1% of the Android devices are already using API Level 21 and above as of October 2021. So it is safe to set the minimum Android API Level to be 21.

API Version distribution chart in Android Studio (as of October 2021).
Step 0.2.2: Permissions

In the manifest, we also need to specify the permissions our app requires to run. We should only request necessary permissions because users will be prompted to allow these permissions when they download our app from the Google Play Store.

By the way, if we find that switching to a Release build causes our app to lose a permission that was available in the Debug build, verify that the permission is explicitly set in the Android Manifest in Properties window, as shown in the Screenshot A above.

Step 0.2.3: App Version

Finally, in the manifest, we need to version our app release. Android recognises two different types of version information:

  • Version Number: A positive integer value (used internally by Android and the application, and thus not displayed to users) that represents the version of the application. Normally it starts with 1;
  • Version Name: A string about the app version and it’s displayed to users in Google Play Store.

Step 1: Change To AAB

As mentioned earlier, Google requires us to publish our apps with the Android App Bundle (AAB). Hence, we need to first update the Android Package Format for our app in Android Options to use bundle instead of apk, as shown in the following screenshot.

Change to use Android App Bundle.

Step 2: Configure Linker

In order to have an efficient app deployment, we need to build and release small app packages. To do so, we execute a process, known as Linking, that examines the application and removes any code that is not directly used.

The Linker in Xamarin.Android uses static analysis to determine which assemblies, types, and type members are used or referenced by a Xamarin.Android application. The linker will then discard all the unused assemblies, types, and members that are not used or referenced.

There are three linking options available:

  • None: No linking will be executed;
  • SDK Assembly Only: Linking will be performed on the assemblies required by Xamarin.Android only, NOT user’s assemblies;
  • SDK and User Assemblies: Linking will be performed on ALL assemblies, including user’s assemblies.

Normally, we will pick “SDK Assembly Only”. If we choose the “SDK and User Assemblies” option, the Linker may sometimes remove classes that are not seemed to be used by our code, especially if they are in the Xamarin shared project (or PCL library project).

Please take note that linking can produce some unintended side effects, so it is important that an application be re-tested in Release mode on a physical device.

Step 3: Dex Compilation

In order to have our app run on Android Runtime (ART), which is the successor of Dalvik VM, there is a process known as Dex (Dalvik Executable) Compilation which will transform .class bytecode into .dex bytecode. Inevitably, Xamarin.Android also has to compile Java source code into Dex format as part of the build.

In 2017, Google introduced a new Dex compiler know as D8 and one year later Google made it as the default Dex compiler in Android Studio. Soon, in Visual Studio 2019 Preview 2, D8 was allowed to be set in csproj.

ART, D8, and R8 in Google I/O 2018. (Image Source: Android Developers YouTube)

As an extension to D8, R8 is a Java code shrinker. R8 will remove unused code and resources from our app release so that the released is shrank. According to Google, in R8, we can also benefit from obfuscation, which shortens the names of classes and members in our app, and optimization, which applies more aggressive strategies to further reduce the size of our app. However, R8 doesn’t obfuscate when used with Xamarin.

Setting D8 and R8 as the Dex Compiler and Code Shrinker, respectively.

Step 4: Disable Debugging

In the Android Options shown above, we need to make sure we have disabled the “Enable developer instrumentation (debugging and profiling)” option for Release mode.

In addition, we should disable the debug state in a released application as it is possible to gain full access to the Java process and execute arbitrary code in the context of the app via JDWP (Java Debug Wire Protocol, which is turned on by default) if this debug state is not disabled. To disable it, we need to add the following lines into AssemblyInfo.cs file.

#if DEBUG
[assembly: Application(Debuggable=true)]
#else
[assembly: Application(Debuggable=false)]
#endif

Step 5: Set Supported Architecture

Currently, all our apps published on Google Play must support 64-bit architectures because starting from August 2021, Google Play stops serving non-64-bit capable devices. This means that apps with 32-bit native code will need to have an additional 64-bit version as well.

Fortunately, Xamarin.Android having supported 64-bit CPU architectures for some time and is the default in Visual Studio 2019.

We can pick the supported architectures for our app in Android Options.

Take note that with AAB, Google Play now can use our app bundle to generate and serve optimized APKs for each device configuration. Hence, only the code and resources that are needed for a specific device are downloaded to run our app. This means that including additional architectures will no longer have any impact on the binary size when using AAB.

Step 6: Compile and Archive

After all of the above steps are completed, we can now proceed to compile our app in Release mode. We need to make sure that our app can be built successfully in Release mode.

Next, we will right-click on the Android project and choose the “Archive…” option. Then the Archive Manager will be displayed, as shown below. We just need wait for the packaging process to finish.

The Archive Manager.

Sometimes, the archive process will fail with an error message saying “Cannot create the archive file because the copy of mdbs files failed.” or “Could not find part of the path”. According to the discussion on MSDN, this is because the Xamarin Android Archive Location path is too long. Hence, the solution is to update it to a shorter path under Tools -> Options in Visual Studio, as shown below.

Update Xamarin Android Archive Location in Visual Studio.

Step 7: Configure Distribution Channel

After the archive has been successfully built, we can proceed to choose the distribution channel. Here, we will choose Ad Hoc instead of Google Play as our distribution channel. This is because to Ad Hoc approach does not restrict our app to be published to Google Play only and thus gives us more freedom. In addition, to use Google Play as the channel, we will need to obtain OAuth 2.0 client credentials from the Google Cloud Console. So, to keep thing simple, we will use the Ad Hoc approach here.

Choosing Ad Hoc as the distribution channel of our aab.

Step 8: Generate Signed Bundle

Before we can publish our app on the Google Play, we need to sign our aab with a certificate (aka upload key). We sign our aab so users know the app is really from us. Hence, after Ad Hoc is selected, Visual Studio will display the Signing Identity page.

If we already have an existing certificate, we can simply import it (password is needed). Otherwise, we can choose to create a new signing certificate.

Created certificated will be saved and listed under Signing Identity.

When we upload our signed package to Google Play, it remembers the key that was used to upload the initial package and makes sure subsequent packages are signed with the same key.

We must back up the resulting keystore file and password in a safe place. To retrieve the keystore, we can simply double click on the certificate in the list shown in the screenshot above. From there we can choose to view the keystore file in the Windows Explorer.

Signing an app with Play App Signing. (Image Source: Android Developers)

Once we have signed our aab, Play App Signing will take care of the rest. With Play App Signing, Google manages and protects our app signing key for us and uses it to sign optimized, distribution APKs that are generated from our aab, as illustrated in the chart above.

Currently, when our app is updated to a new version, Android will first makes sure the certificate of new version is same as the one in the previous version. Hence, when the app signing key expires, users will no longer be able to seamlessly upgrade to new versions of our app. Now, with Play App Signing, Google helps to keep our app signing key safe, and ensures our apps are correctly signed and able to receive updates throughout their lifespans.

In addition, when we use Play App Signing, if we lose our upload key, we can request for Upload Key Rest by contacting Play Store support. Since our app signing key is secured by Google, we can then continue to upload new versions of our app as updates to the original app, even if the upload keys have been changed.

For more information about Play App Signing, please watch the video below.

Wojtek Kaliciński talks about Play App Signing.

After we have signed and save our app bundle as aab file locally, we can move on to create and setup our new app on Google Play Store.

Step 9: Setup App on Google Play Console

In June 2020, new Google Play Console was introduced.

There are many steps involved to setup our app on Google Play Console. Fortunately, there is a very good YouTube tutorial from MJSD Coding about how to create and setup a new app on the new Google Play Console. You can simply refer to the video below.

How to Publish an Android App to Google Play in 2021.

Step 10: Release our App

In the video above, we learnt about the step to create production release. After we have confirmed to use the Play App Signing, we can proceed to upload our aab file generated in Step 8, as shown in the screenshot below. Once it is successfully uploaded to the Google Play Console, we can proceed to rollout our app release.

Uploading our signed app bundle to Google Play Console.

References

Packaging PyQt5 app with PyInstaller on Windows

After we have developed a GUI desktop application using PyQt5, we need to distribute it to the users to use it. Normally the users are not developers, so giving them the source code of our application is not a good idea. Hence, in this article, we will discuss how we can use PyInstaller to package the application into an exe file on Windows.

Step 0: Setup Hello World Project

Our life will be easy if we start packaging our application in the very beginning. This is because as we add more features and dependencies to the application, we can easily confirm the packaging is still working. If there is anything wrong during the packaging, we can easily debug by just checking the newly added codes instead of debugging the entire app.

So, let’s start with a PyQt5 desktop application which has a label showing “Hello World”.

Currently PyInstaller works only up to Python 3.8. So, I will first create a virtual environment which uses Python 3.8 with the following command. Since I have many versions of Python installed on my machine, I simply use the path to the Python 3.8 in the command.

C:\Users\...\Python38\python.exe -m venv venv

After that, we can activate the virtual environment in VS Code by choosing the interpreter, as shown in the following screenshot.

VS Code will prompt us the recommended interpreter to choose for the project.

After that, we will install PyQt5 5.15.4 and Qt-Material 2.8.8 packages for the GUI. Once the two packages are installed in the virtual environment, we can proceed to design our Hello World app with the following codes in a file called main.py.

import sys

from PyQt5.QtWidgets import *
from qt_material import apply_stylesheet

class Window(QMainWindow):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        self.setWindowTitle("Hello World")
        label = QLabel("Hello World")
        label.setMargin(10)
        self.setCentralWidget(label)
        self.show()

if __name__ == "__main__":
    app = QApplication(sys.argv)
    win = Window()

    apply_stylesheet(app, theme='dark_blue.xml')

    win.show()
    sys.exit(app.exec_())

Now when we run the code above, we will be able to see a simple window with a label saying “Hello World”.

Our simple PyQt desktop application.

Step 1: Package the App

Before we can proceed further, we need to install the PyInstaller, which helps to bundle our Python app and all its dependencies into a single package. We can do so with the following command.

pip install pyinstaller==4.5.1

Once it is installed successfully, we can start the packaging of our app with the command below.

pyinstaller main,py

PyInstaller will now read and analyse our codes in main.py to discover every other module and library our script needs in order to execute. After that, PyInstaller will put all the files and Python interpreter in a single folder for distributing later. This is useful because the end users of our app do not need to have Python installed beforehand in order to run our app.

Hence, running the command above will generate two new folders, i.e. build and dist, as well as a main.spec file in the project directory.

A new file main.spec and two new folders, build and dist, will be generated by PyInstaller.

It is important to take note that the PyInstaller output is specific to the active OS and the active version of Python. In this case, our distribution is for Windows under Python 3.8.

The build folder is used by PyInstaller to collect and and prepare files for packaging. We can ignore its content unless we are trying to debug the packaging issues.

The dist folder will be the folder we can distribute to end users to use our app. The folder has our application, i.e. main.exe, together with other dlls.

End users of our app just need to run the main.exe in the dist/main folder to use our app.

Finally, the main.spec is a SPEC file which contains the PyInstaller packaging configuration and instructions. Hence, for future packaging operations, we shall execute the following command instead.

pyinstaller main.spec

Now, when we run the main.exe, we will be able to see our Hello World application. However, at the same time, there would be a console window shown together by default, as demonstrated below.

A console window will be shown together with our desktop application.

The console window by right should be hidden from the end users. So, in the following step, we will see how we can configure the PyInstaller packaging to hide the console window.

Step 2: Configure the SPEC File

When the “pyinstaller main.py” command is executed, the first thing PyInstaller does is to generate the SPEC file, i.e. main.spec. The file tells PyInstaller how to process our script. Hence, PyInstaller later can build our app by simply executing the content of the SPEC file.

The SPEC file is actually a Python code. It contains the following classes.

  • Analysis: Takes a list of script file names as input and analyses the dependencies;
  • PYZ: PYZ stands for Python Zipped Executable, contains all the Python modules needed by the script(s);
  • EXE: Creates the executable file, i.e. main.exe in our example, based on Analysis and PYZ;
  • COLLECT: Creates the output folder from all the other parts. This class is removed in the one-file mode.

Step 2.1 Setup one-file Build

As we can see earlier, the dist folder does not only contain the executable file, main.exe, but also a long list of DLLs. It’s normally not a good idea to give the end users a huge folder like this as the users may have a hard time figuring out how to launch our app. So, we can create a one-file build for our app instead.

To do so, we can execute the following command. To make things clearer, we can also choose to delete the dist folder generated earlier before running the command.

pyinstaller --onefile main.py

After it is executed successfully, in the dist folder, we can see that there is only one executable file, as shown in the following screenshot. Now, we can just send the end users only this one executable file to run our app.

So, where do all the DLLs that we see in the non-one-file build go? They are actually compressed into the executable. Hence, the one-file build has a side-effect. Every time our app runs, it must create a temporary folder to decompress the content of the executable. This means that one-file built app will have a slower startup.

The outcome of one-file build.

Step 2.2: Remove Console Window

The first change that we can make to the SPEC file is to remove the default console window. To do so, we simply need to set console=False in the EXE, as shown in the screenshot below.

Hid the default console window.

With this being set, the app will not be launched with a console window showing together.

Step 2.3 Bundle Data Files

Let’s say we would like to have an app icon for our app, we can have the following line added in our main.py.

self.setWindowIcon(QIcon('resources/images/logo.png'))

This will load the image file logo.png from the resources/images directory. In this scenario, we thus need to find a way to bundle image files in the build. To do so, we can first update our SPEC files as follows.

Telling PyInstaller to copy the resources folder.

The list of data files is a list of tuples where each tuple has two strings.

  • The first string specifies the file or files as they are in this system now;
  • The second specifies the name of the folder to contain the files at run-time.

If we’re not using the one-file build, we will find out that the data files will be copied to the dist folder accordingly. However, if we are app is built with one-file mode, then we shall change our code accordingly to locate the data files at runtime.

Firstly, we need to check whether our app is running from the source directly or from the packaged executable with the following function.

def resource_path(relative_path):
    """ Get absolute path to resource, works for dev and for PyInstaller """
    if getattr(sys, 'frozen', False) and hasattr(sys, '_MEIPASS'):
        base_path = sys._MEIPASS
    else:
        base_path = os.path.abspath(".")

    return os.path.join(base_path, relative_path)

Secondly, we need to update the code getting the QIcon path to be something as follows.

self.setWindowIcon(QIcon(resource_path('resources/images/logo.png')))

Finally, we will be able to see our app icon displayed correctly, as shown in the following screenshot.

Yay, the app icon is updated!

Step 2.4 Setup EXECUTABLE App Icon

Even though the app icon has been updated, however, the icon of our executable is still not yet updated.

Before we can proceed to update the exe icon, we need to know that, on Windows, only .ico file can be used as icon image. Since our logo is a png file, we shall convert it to an ico file first. To do the conversion, I’m using ICO Convert which is available online for free and mentioned in one of the PyInstaller GitHub issues.

After getting the ICO file, we shall put it in the same directory as the SPEC file. Next, we can customise the SPEC file by adding icon parameter to the EXE as shown below.

Setting app icon for our app executable file.

Once the build is successful, we can refresh our dist folder and will find that our main.exe now has a customised icon, as shown below.

Yay, our exe file has customised icon as well now!

Step 2.5 Name Our App

By default, the executable file generated has the name of our source file. Hence, in this example, the executable file is named as main.exe. By updating our SPEC file, we can also name the executable file with a more user friendly name.

What we need to do is just editing the name of EXE, as shown in the following screenshot.

We will now get the executable file of our app as Face.exe.

Conclusion

That’s all for the quickstart steps to package our PyQt5 desktop GUI application with PyInstaller on Windows 10.

I have made the source code available on GitHub. You can also download the Face.exe under the Releases. After launching the app, you should be able to do facial recognition together with your personal Microsoft Azure Cognitive Services account, as shown in the following screenshot.

Facial recognition done using Face API in Microsoft Azure Cognitive Services.

References