Categories
Python

Auto Update for your Frozen Python Applications using Esky

Let’s assume you have a desktop application built with Python. It could be a traditional GUI app built with PyQT/wxPython/Kivy or any other GUI framework. Or it could be a web server that serves a browser based HTML GUI for the user. Either way, you have “frozen” the app using cx_freeze, py2app/py2exe or pyinstaller and now you want to add “auto update” to the app, so when there’s a new version of the application is available, the app can download and install the update, automatically. For this particular task, I found esky to be a good viable option. In this article, I am going to demonstrate how we can use esky to deliver updates to our apps.

Quick Introduction to Esky

If we want to use Esky to deliver updates, we need to freeze the app first. But this time, we will ask Esky to freeze the app for us, using our freezer of choice. For example, if we used py2app before, we will still use py2app but instead of directly using it, we will pass it to Esky and Esky will use the py2app to freeze the app for us. This step is necessary so that Esky can inject the necessary parts to handle updates/patches and install them gracefully.

For the apps to locate and download the updates, we need to serve the updates from a location on the internet/local network. Esky produces a zip archive. We can directly put it on our webserver. The apps we freeze needs to know the URL of the webserver and must have access to it.

On the other hand, inside our app, we need to write some codes which will scan the URL of the above mentioned webserver, find any newer updates and install them. Esky provides nice APIs to do these.

So now that we know the steps to follow, let’s start.

Creating a setup file

If you have frozen an app before, you probably know what a setup file is and how to write one. Here’s a sample that uses py2app to freeze an app:

Now we can generate the frozen app using:

This should generate a zip archive in the dist directory.

Hosting the app

Collect the zip file from the dist directory and put it somewhere accessible on the internet. For local testing, you can probably use Python’s built in HTTP server to distribute it.

Finding, Downloading and Installing Updates

Now we will see the client side code that we need to write to locate and install the updates.

Here’s some codes taken from a PyQT app. The find_esky_update method is part of a QMainWindow class. It is called inside the onQApplicationStarted method. So it checks the update as soon as the application starts.

We first check if the app is frozen. If it’s not, then there’s no way we can install updates. sys.frozen will contain information about the app if it’s frozen. Otherwise it will not be available. So we first ensure that it is indeed a frozen app.

Then we create an Esky app instance by providing it the URL of our webserver (where the updates are available). We only pass the root URL (without the zip file name). The find_update() method on the Esky app will find newer update and return some information if a new update is available. Otherwise it will be falsy.

If an update is available, we ask our user if s/he wants to update. Here we used QMessageBox for that. If they agree, we call the auto_update method with a callback. We will see the callback soon. The auto_update downloads the update and installs it. The callback we pass – it gets called every time something happens during the process. It can be a good way to display download progress using this callback.

Let’s see our example code here:

As you can see from the code, the callback gets a dictionary which has a key status and if it is “downloading”, we also have the amount of data we have received so far and the total size. We can use this to calculate the progress and print it. We can also display a nice progress bar if we wish.

So basically, this is all we need to find and install updates.

Rolling a new update

We have learned to use Esky, we have seen how to add auto update to our app. Now it’s time to build a new update. That is easy, we go back to the setup.py file we defined earlier. We had version="0.1", inside the setup() function. We need to bump it. So let’s make it 0.2 and build it. We will get a new zip file (the file contains the version if you notice carefully). Drop it on the webserver (the URL where we put our app). Run an older copy of the app (which includes the update checking codes described above). It should ask you for an update 🙂

Please note, you need to call the find_esky_update() method for the prompt to trigger. As I mentioned above, I run it in onQApplicationStarted method for PyQt. You need to find the appropriate place to call it from in your application.

Further Reading

You can find a nice tutorial with step by step instructions and code samples here: https://github.com/cloudmatrix/esky/tree/master/tutorial

Categories
Django Python

Django: Limiting User Access to Views

In this post, we would like to see how we can limit user accesses to our Django views.

Login Required & Permission Required Decorators

If you have worked with Django, you probably have used the login_required decorator already. Adding the decorator to a view limits access only to the logged in users. If the user is not logged in, s/he is redirected to the default login page. Or we can pass a custom login url to the decorator for that purpose.

Let’s see an example:

There’s another nice decorator – permission_required which works in a similar fashion:

Awesome but let’s learn how do they work internally.

How do they work?

We saw the magic of the login_required and permission_required decorators. But we’re the men of science and we don’t like to believe in magic. So let’s unravel the mystery of these useful decorators.

Here’s the code for the login_required decorator:

By reading the code, we can see that the login_required decorator uses another decorator – user_passes_test which takes/uses a callable to determine whether the user should have access to this view. The callable must accept an user instance and return a boolean value. user_passes_test returns a decorator which is applied to our view.

If we see the source of permission_required, we would see something quite similar. It also uses the same user_passes_test decorator.

Building Our Own Decorators

Now that we know how to limit access to a view based on whether the logged in user passes a test, it’s quite simple for us to build our own decorators for various purposes. Let’s say we want to allow access only to those users who have verified their emails.

Now we can use the decorator to a view like:

Users who have verified their email addresses will be able to access this view. And if they didn’t, they will be redirected to the login view. Using the reason query string, we can display a nice message explaining what’s happening.

Please note, we have used two decorators on the same view. We can use multiple decorators like this to make sure the user passes all the tests we require them to.

Categories
Bangla Data Science

āĻšāĻŋāĻ¸ā§āĻŸā§‹āĻ—ā§āĻ°āĻžāĻŽ āĻ¨āĻžāĻ•āĻŋ āĻŦāĻžāĻ° āĻšāĻžāĻ°ā§āĻŸ?

āĻĄāĻžāĻŸāĻž āĻ­āĻŋāĻœā§ā§ŸāĻžāĻ˛āĻžāĻ‡āĻœā§‡āĻļāĻ¨ā§‡āĻ° āĻ¸āĻŽā§Ÿ āĻ†āĻŽāĻ°āĻž āĻĒā§āĻ°āĻžā§ŸāĻļāĻ‡ āĻšāĻŋāĻ¸ā§āĻŸā§‹āĻ—ā§āĻ°āĻžāĻŽ āĻ“ āĻŦāĻžāĻ° āĻšāĻžāĻ°ā§āĻŸ āĻāĻ° āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ° āĻĻā§‡āĻ–āĻŦā§‹ āĨ¤ āĻŦāĻžāĻ° āĻšāĻžāĻ°ā§āĻŸ āĻāĻŦāĻ‚ āĻšāĻŋāĻ¸ā§āĻŸā§‹āĻ—ā§āĻ°āĻžāĻŽ āĻĻā§‡āĻ–āĻ¤ā§‡ āĻ…āĻ¨ā§‡āĻ•āĻŸāĻž āĻāĻ•āĻ‡ āĻ°āĻ•āĻŽ āĨ¤ āĻĻā§āĻŸā§‹āĻ¤ā§‡āĻ‡ āĻ†āĻŽāĻ°āĻž āĻ˛āĻŽā§āĻŦāĻž āĻ˛āĻŽā§āĻŦāĻž āĻŦāĻžāĻ° āĻ†āĻ•āĻŋāĻ āĨ¤ x-axis āĻ āĻ‡āĻ¨ā§āĻĄāĻŋāĻĒā§‡āĻ¨ā§āĻĄā§‡āĻ¨ā§āĻŸ āĻ­ā§āĻ¯āĻžāĻ°āĻŋā§Ÿā§‡āĻŦāĻ˛ āĻ“ y-axis āĻ āĻĄāĻŋāĻĒā§‡āĻ¨ā§āĻĄā§‡āĻ¨ā§āĻŸ āĻ­ā§āĻ¯āĻžāĻ°āĻŋā§Ÿā§‡āĻŦāĻ˛ āĻāĻ° āĻŽāĻžāĻ¨ āĻŦāĻ¸āĻŋā§Ÿā§‡ āĻĻāĻŋā§Ÿā§‡ āĻ†āĻŽāĻ°āĻž āĻ¸ā§āĻ¨ā§āĻĻāĻ° āĻ•āĻ°ā§‡ āĻšāĻŋāĻ¸ā§āĻŸā§‹āĻ—ā§āĻ°āĻžāĻŽ āĻ“ āĻŦāĻžāĻ° āĻšāĻžāĻ°ā§āĻŸ āĻāĻ•ā§‡āĻ āĻĢā§‡āĻ˛āĻŋ āĨ¤

āĻĻā§‡āĻ–āĻ¤ā§‡ āĻāĻ•āĻ‡ āĻ°āĻ•āĻŽ āĻšāĻ˛ā§‡āĻ“ āĻĻā§āĻŸā§‹āĻ° āĻŽāĻ§ā§āĻ¯ā§‡ āĻ°ā§Ÿā§‡āĻ›ā§‡ āĻŽā§ŒāĻ˛āĻŋāĻ• āĻĒāĻžāĻ°ā§āĻĨāĻ•ā§āĻ¯ āĨ¤ āĻšāĻŋāĻ¸ā§āĻŸā§‹āĻ—ā§āĻ°āĻžāĻŽ āĻŸāĻž āĻ†āĻŽāĻ°āĻž āĻ°ā§‡āĻ¨ā§āĻœ āĻŦāĻž āĻĄāĻŋāĻ¸ā§āĻŸā§āĻ°āĻŋāĻŦāĻŋāĻ‰āĻļāĻžāĻ¨ā§‡āĻ° āĻ•ā§āĻˇā§‡āĻ¤ā§āĻ°ā§‡ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ° āĻ•āĻ°āĻŋ āĨ¤ āĻ¯ā§‡āĻŽāĻ¨ āĻ¨āĻŋāĻšā§‡āĻ° āĻšāĻŋāĻ¸ā§āĻŸā§‹āĻ—ā§āĻ°āĻžāĻŽāĻŸāĻž āĻĻā§‡āĻ–āĻŋ:

āĻāĻ–āĻžāĻ¨ā§‡ āĻ†āĻŽāĻ°āĻž āĻĻā§‡āĻ–āĻ›āĻŋ āĻŦāĻŋāĻ­āĻŋāĻ¨ā§āĻ¨ āĻŦā§ŸāĻ¸ā§‡āĻ° āĻŽāĻžāĻ¨ā§āĻˇ, āĻ¯āĻžāĻ°āĻž āĻ›ā§āĻŸāĻŋ āĻ•āĻžāĻŸāĻžāĻ¤ā§‡ āĻ¯āĻžā§Ÿ āĻ¤āĻžāĻĻā§‡āĻ° āĻŽāĻ§ā§āĻ¯ā§‡ āĻ•āĻ¤āĻœāĻ¨ āĻšā§‹āĻŸā§‡āĻ˛ā§‡ āĻĨāĻžāĻ•ā§‡ āĨ¤ āĻ†āĻŽāĻ°āĻž āĻ–ā§‡ā§ŸāĻžāĻ˛ āĻ•āĻ°āĻ˛ā§‡ āĻĻā§‡āĻ–āĻŦā§‹, āĻāĻ–āĻžāĻ¨ā§‡ ā§¨ā§Ļ āĻŦāĻ›āĻ°ā§‡āĻ° āĻ¨āĻŋāĻšā§‡ āĻ¯āĻžāĻ°āĻž, āĻ¤āĻžāĻĻā§‡āĻ° āĻŽāĻ§ā§āĻ¯ā§‡ ā§Ģ āĻœāĻ¨ āĻšā§‹āĻŸā§‡āĻ˛ā§‡ āĻĨāĻžāĻ•ā§‡, ā§¨ā§§-ā§Šā§Ļ āĻāĻ° āĻŽāĻ§ā§āĻ¯ā§‡ ā§§ā§Ģ āĻœāĻ¨, ā§Šā§§-ā§Ēā§Ļ āĻāĻ° āĻŽāĻ§ā§āĻ¯ā§‡ āĻ†āĻ›ā§‡ ā§§ā§Ļ āĻœāĻ¨ āĻāĻŦāĻ‚ ā§Ēā§§-ā§Ģā§Ļ āĻŦā§ŸāĻ¸ā§€āĻĻā§‡āĻ° āĻŽāĻ§ā§āĻ¯ā§‡ ā§Ģ āĻœāĻ¨ āĻāĻ° āĻ•āĻŽ āĨ¤

āĻ˛āĻ•ā§āĻˇā§āĻ¯ āĻ•āĻ°āĻŋ, āĻāĻ–āĻžāĻ¨ā§‡ āĻ†āĻŽāĻžāĻĻā§‡āĻ° āĻĄāĻžāĻŸāĻž āĻ¨āĻŋāĻ‰āĻŽā§‡āĻ°āĻŋāĻ•ā§āĻ¯āĻžāĻ˛ āĻāĻŦāĻ‚ āĻ†āĻŽāĻ°āĻž āĻ°ā§‡āĻ¨ā§āĻœ āĻ¨āĻŋā§Ÿā§‡ āĻ•āĻžāĻœ āĻ•āĻ°āĻ›āĻŋ – āĻŦā§ŸāĻ¸ā§‡āĻ° āĻ°ā§‡āĻ¨ā§āĻœ āĨ¤ āĻŦāĻŋāĻ­āĻŋāĻ¨ā§āĻ¨ āĻŦā§ŸāĻ¸ā§‡āĻ° āĻŽāĻžāĻ¨ā§āĻˇāĻ•ā§‡ āĻ¨āĻŋāĻ°ā§āĻĻāĻŋāĻˇā§āĻŸ āĻ•āĻŋāĻ›ā§ āĻ°ā§‡āĻ¨ā§āĻœā§‡ āĻ†āĻŽāĻ°āĻž āĻĄāĻŋāĻ¸ā§āĻŸā§āĻ°āĻŋāĻŦāĻŋāĻ‰āĻŸ āĻ•āĻ°ā§‡āĻ›āĻŋ āĨ¤ āĻāĻ–āĻžāĻ¨ā§‡ āĻĄāĻžāĻŸāĻžāĻ° āĻāĻ‡ āĻ°ā§‡āĻ¨ā§āĻœā§‡ āĻ•ā§‹āĻ¨ āĻ—ā§āĻ¯āĻžāĻĒ āĻ¨ā§‡āĻ‡ āĨ¤ āĻāĻŦāĻ‚ āĻšāĻŋāĻ¸ā§āĻŸā§‹āĻ—ā§āĻ°āĻžāĻŽā§‡āĻ° āĻĒāĻžāĻ°ā§āĻŸāĻ—ā§āĻ˛ā§‹āĻ•ā§‡ āĻŦāĻž āĻŦāĻžāĻ° āĻ—ā§āĻ˛ā§‹āĻ•ā§‡ āĻ…āĻ¨ā§āĻ¯ āĻ•ā§‹āĻ¨ āĻ…āĻ°ā§āĻĄāĻžāĻ°ā§‡ āĻ°āĻŋ-āĻā§āĻ¯āĻžāĻ°ā§‡āĻ¨ā§āĻœ āĻ•āĻ°āĻžāĻ° āĻ¸ā§āĻ¯ā§‹āĻ— āĻ¨ā§‡āĻ‡ āĨ¤

āĻāĻŦāĻžāĻ° āĻĻā§‡āĻ–āĻŋ āĻāĻ•āĻŸāĻŋ āĻŦāĻžāĻ° āĻšāĻžāĻ°ā§āĻŸ:

āĻāĻ‡ āĻšāĻžāĻ°ā§āĻŸā§‡ āĻ†āĻŽāĻ°āĻž āĻĻā§‡āĻ–āĻ›āĻŋ āĻŦāĻŋāĻ­āĻŋāĻ¨ā§āĻ¨ āĻŦā§āĻ°ā§āĻ¯āĻžāĻ¨ā§āĻĄā§‡āĻ° āĻ—āĻžā§œāĻŋ āĻ¨āĻŋāĻ°ā§āĻŽāĻžāĻ¤āĻžāĻĻā§‡āĻ° āĻœāĻžāĻ¨ā§ā§ŸāĻžāĻ°ā§€ āĻŽāĻžāĻ¸ā§‡ āĻŦāĻŋāĻ•ā§āĻ°āĻŋāĻ¤ āĻ—āĻžā§œāĻŋāĻ° āĻ¸āĻ‚āĻ–ā§āĻ¯āĻž āĨ¤ āĻāĻ–āĻžāĻ¨ā§‡ āĻĒā§āĻ°āĻ§āĻžāĻ¨ āĻ˛āĻ•ā§āĻˇāĻ¨ā§€ā§Ÿ āĻŦāĻŋāĻˇā§Ÿ āĻšāĻ˛ā§‹ āĻāĻ‡āĻŦāĻžāĻ° āĻ†āĻŽāĻžāĻĻā§‡āĻ° āĻĄāĻžāĻŸāĻž āĻ•āĻŋāĻ¨ā§āĻ¤ā§ āĻ¨āĻŋāĻ‰āĻŽā§‡āĻ°āĻŋāĻ•ā§āĻ¯āĻžāĻ˛ āĻ¨āĻž, āĻŦāĻ°āĻ‚ āĻ•ā§āĻ¯āĻžāĻŸā§‡āĻ—āĻ°āĻŋāĻ•ā§āĻ¯āĻžāĻ˛ āĨ¤ āĻŦāĻŋāĻ­āĻŋāĻ¨ā§āĻ¨ āĻŦā§āĻ°ā§āĻ¯āĻžāĻ¨ā§āĻĄā§‡āĻ° āĻŽāĻ§ā§āĻ¯ā§‡ āĻ¤ā§āĻ˛āĻ¨āĻž āĻ•āĻ°āĻ¤ā§‡ āĻ†āĻŽāĻ°āĻž āĻāĻ‡ āĻŦāĻžāĻ° āĻšāĻžāĻ°ā§āĻŸāĻŸāĻŋ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ° āĻ•āĻ°āĻ¤ā§‡ āĻĒāĻžāĻ°āĻŋ āĨ¤ āĻŦāĻžāĻ° āĻšāĻžāĻ°ā§āĻŸā§‡āĻ° āĻ•ā§āĻˇā§‡āĻ¤ā§āĻ°ā§‡ āĻŦāĻžāĻ° āĻ—ā§āĻ˛ā§‹āĻ•ā§‡ āĻ°āĻŋ-āĻā§āĻ¯āĻžāĻ°ā§‡āĻ¨ā§āĻœ āĻ•āĻ°āĻ˛ā§‡āĻ“ āĻ•ā§‹āĻ¨ āĻ¸āĻŽāĻ¸ā§āĻ¯āĻž āĻšā§Ÿ āĻ¨āĻž āĨ¤ āĻāĻŦāĻ‚ āĻŦāĻžāĻ° āĻ—ā§āĻ˛ā§‹ āĻāĻ•āĻŸāĻž āĻ†āĻ°ā§‡āĻ•āĻŸāĻžāĻ° āĻ¸āĻžāĻĨā§‡ āĻ•āĻžāĻ¨ā§‡āĻ•ā§āĻŸā§‡āĻĄ āĻ¨āĻž, āĻŽāĻžāĻ āĻ–āĻžāĻ¨ā§‡ āĻ¤āĻžāĻ‡ āĻ—ā§āĻ¯āĻžāĻĒ āĻĨāĻžāĻ•ā§‡ āĨ¤


TL;DR – āĻšāĻŋāĻ¸ā§āĻŸā§‹āĻ—ā§āĻ°āĻžāĻŽ āĻāĻ•āĻŸāĻž āĻ­ā§āĻ¯āĻžāĻ°āĻŋā§Ÿā§‡āĻŦāĻ˛ā§‡āĻ° āĻĄāĻŋāĻ¸ā§āĻŸā§āĻ°āĻŋāĻŦāĻŋāĻ‰āĻļāĻžāĻ¨ āĻ°āĻŋāĻĒā§āĻ°ā§‡āĻœā§‡āĻ¨ā§āĻŸ āĻ•āĻ°āĻžāĻ° āĻœāĻ¨ā§āĻ¯ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ° āĻ•āĻ°āĻž āĻšā§Ÿ, āĻŦāĻžāĻ° āĻšāĻžāĻ°ā§āĻŸ āĻŦāĻŋāĻ­āĻŋāĻ¨ā§āĻ¨ āĻ­ā§āĻ¯āĻžāĻ°āĻŋā§Ÿā§‡āĻŦāĻ˛ā§‡āĻ° āĻŽāĻ§ā§āĻ¯ā§‡ āĻ¤ā§āĻ˛āĻ¨āĻž āĻ•āĻ°āĻžāĻ° āĻœāĻ¨ā§āĻ¯ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ° āĻ•āĻ°āĻž āĻšā§Ÿ āĨ¤