I'm a beginner i Python and I want to make an application that automatically updates a game, downloading the files and then installing it, using GTK 3 and Python 3.8.
I made a class with a method that automatically gets the latest release, picks the correct file for the OS Python is running on and then downloads it on another method. Here's that class:
import requests
import platform
import asyncio
class ReleaseManager:
def __init__(self, package_name, author_name):
self.package_name = package_name
self.author_name = author_name
self.selected_url = ""
self.selected_filename = ""
async def get_asset_download_url_and_name(self):
url = f"https://api.github.com/repos/{self.author_name}/{self.package_name}/releases/latest"
response = requests.get(
url,
headers={"User-Agent": "OpenRCT2 Silent Launcher"}
)
json_response = response.json()
assets = json_response["assets"]
for file in assets:
if file["content_type"] == "application/x-ms-dos-executable":
# ...
# Code that outputs the correct URL and filename into the
# 'selected_url' and 'selected_filename' variables
async def download_latest_asset(self, download_path, progress_bar):
if self.selected_url == "":
await self.get_asset_download_url_and_name()
response = requests.get(
self.selected_url,
headers={"User-Agent": "OpenRCT2 Silent Launcher", "Accept": "application/octet-stream"},
stream=True
)
response_size = int(response.headers['content-length'])
if response.status_code == 200:
with open(os.path.join(download_path, self.selected_filename), "wb") as file:
bytes_read = 0
print("Downloading...")
for chunk in response.iter_content(512):
file.write(chunk)
bytes_read += 512
progress = bytes_read / response_size
# progress_bar.set_fraction(progress)
# ^ This is how I wanted to update the progress bar,
# and I commented it out to make sure this wasn't causing the problem.
print("Successfully finished downloading")
This is my main.py
file that is executed:
import asyncio
import asyncio_glib
import gi
from github import releases
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk
asyncio.set_event_loop_policy(asyncio_glib.GLibEventLoopPolicy())
builder = Gtk.Builder()
builder.add_from_file("layouts/mainWindow.glade")
def call_download(button):
loop = asyncio.get_event_loop()
loop.run_until_complete(download_openrct2())
async def download_openrct2():
manager = releases.ReleaseManager("OpenRCT2", "OpenRCT2")
await manager.download_latest_asset("/home/samuel/Downloads/OpenRCT2/", builder.get_object("PgrDownload"))
handlers = {
"onDestroy": Gtk.main_quit,
"onDownloadClick": call_download
}
builder.connect_signals(handlers)
win = builder.get_object("MainWindow")
win.show_all()
Gtk.main()
This code works as intended. Files are downloaded properly and no errors return. However, the GUI freezes the moment I press the "Download OpenRCT2" button. You can see I tried solving this using asyncio
and asyncio_glib
, based on this question on StackOverflow, and since the only documentation (from its GitHub) for asyncio_glib
is to insert asyncio.set_event_loop_policy(asyncio_glib.GLibEventLoopPolicy())
before asyncio.get_loop_event()
I assumed this is the only thing I needed to do.
This did not solve the problem though, the UI still freezes until the last line of the download_latest_asset
method is finished executing, while no errors are thrown. How to make the download method not freeze the UI while it's downloading a file?
Thanks in advance.