- Fixed instances of unspecified-encoding, super-with-arguments, raise-missing-from, consider-using-dict-items, consider-iterating-dictionary

- Refactored connect() from api.py to use requests
This commit is contained in:
Alexander Ravenheart 2021-10-24 23:04:27 +03:00 committed by Mathieu Comandon
parent f5e8e007b3
commit 7cff0a0301
74 changed files with 181 additions and 180 deletions

View file

@ -2,11 +2,12 @@
import json
import os
import re
import socket
import urllib.error
import urllib.parse
import urllib.request
import requests
from lutris import settings
from lutris.util import http, system
from lutris.util.log import logger
@ -20,7 +21,7 @@ def read_api_key():
"""Read the API token from disk"""
if not system.path_exists(API_KEY_FILE_PATH):
return None
with open(API_KEY_FILE_PATH, "r") as token_file:
with open(API_KEY_FILE_PATH, "r", encoding='utf-8') as token_file:
api_string = token_file.read()
try:
username, token = api_string.split(":")
@ -32,21 +33,22 @@ def read_api_key():
def connect(username, password):
"""Connect to the Lutris API"""
credentials = urllib.parse.urlencode({"username": username, "password": password}).encode("utf-8")
login_url = settings.SITE_URL + "/api/accounts/token"
credentials = {"username": username, "password": password}
try:
request = urllib.request.urlopen(login_url, credentials, 10)
except (socket.timeout, urllib.error.URLError) as ex:
response = requests.post(url=login_url, data=credentials, timeout=10)
response.raise_for_status()
json_dict = response.json()
if "token" in json_dict:
token = json_dict["token"]
with open(API_KEY_FILE_PATH, "w", encoding='utf-8') as token_file:
token_file.write(f"{username}:{token}")
get_user_info()
return token
except (requests.RequestException, requests.ConnectionError, requests.HTTPError, requests.TooManyRedirects,
requests.Timeout) as ex:
logger.error("Unable to connect to server (%s): %s", login_url, ex)
return False
response = json.loads(request.read().decode())
if "token" in response:
token = response["token"]
with open(API_KEY_FILE_PATH, "w") as token_file:
token_file.write(":".join((username, token)))
get_user_info()
return response["token"]
return False
def disconnect():
@ -67,7 +69,7 @@ def get_user_info():
account_info = response.json
if not account_info:
logger.warning("Unable to fetch user info for %s", credentials["username"])
with open(USER_INFO_FILE_PATH, "w") as token_file:
with open(USER_INFO_FILE_PATH, "w", encoding='utf-8') as token_file:
json.dump(account_info, token_file, indent=2)

View file

@ -175,7 +175,7 @@ class MonitoredCommand:
"""Get the return code from the file written by the wrapper"""
return_code_path = "/tmp/lutris-%s" % self.env["LUTRIS_GAME_UUID"]
if os.path.exists(return_code_path):
with open(return_code_path) as return_code_file:
with open(return_code_path, encoding='utf-8') as return_code_file:
return_code = return_code_file.read()
os.unlink(return_code_path)
else:

View file

@ -22,7 +22,7 @@ def write_game_config(game_slug, config):
configpath = make_game_config_id(game_slug)
config_filename = os.path.join(settings.CONFIG_DIR, "games/%s.yml" % configpath)
yaml_config = yaml.safe_dump(config, default_flow_style=False)
with open(config_filename, "w") as config_file:
with open(config_filename, "w", encoding='utf-8') as config_file:
logger.debug("Writing game config to %s", config_filename)
config_file.write(yaml_config)
return configpath

View file

@ -222,5 +222,5 @@ def migrate(table, schema):
def syncdb():
"""Update the database to the current version, making necessary changes
for backwards compatibility."""
for table in DATABASE:
migrate(table, DATABASE[table])
for table_name, table_data in DATABASE.items():
migrate(table_name, table_data)

View file

@ -694,13 +694,13 @@ class Game(GObject.Object):
logger.info("Previous location wasn't set. Cannot continue moving")
return target_directory
with open(self.config.game_config_path) as config_file:
with open(self.config.game_config_path, encoding='utf-8') as config_file:
for line in config_file.readlines():
if target_directory in line:
new_config += line
else:
new_config += line.replace(old_location, target_directory)
with open(self.config.game_config_path, "w") as config_file:
with open(self.config.game_config_path, "w", encoding='utf-8') as config_file:
config_file.write(new_config)
if not system.path_exists(old_location):

View file

@ -84,7 +84,7 @@ class IssueReportWindow(BaseApplicationWindow):
return
issue_path = os.path.join(target_path, "lutris-issue-report.json")
issue_info = self.get_issue_info()
with open(issue_path, "w") as issue_file:
with open(issue_path, "w", encoding='utf-8') as issue_file:
json.dump(issue_info, issue_file, indent=2)
dialog.destroy()
NoticeDialog(_("Issue saved in %s") % issue_path)

View file

@ -64,5 +64,5 @@ class LogWindow(GObject.Object):
self.buffer.get_end_iter(),
True
)
with open(log_path, "w") as log_file:
with open(log_path, "w", encoding='utf-8') as log_file:
log_file.write(text)

View file

@ -85,7 +85,7 @@ class WebPopupDialog(Dialog):
def __init__(self, webview, parent=None):
# pylint: disable=no-member
self.parent = parent
super(WebPopupDialog, self).__init__(title=_('Loading...'), parent=parent)
super().__init__(title=_('Loading...'), parent=parent)
self.webview = webview
self.webview.connect("ready-to-show", self.on_ready_webview)
self.webview.connect("notify::title", self.on_available_webview_title)

View file

@ -39,15 +39,15 @@ class InstallerFilesBox(Gtk.ListBox):
"""Iterates through installer files while keeping the number
of simultaneously downloaded files down to a maximum number"""
started_downloads = 0
for file_id in self.installer_files_boxes:
if self.installer_files_boxes[file_id].provider == "download":
for file_id, file_entry in self.installer_files_boxes.items():
if file_entry.provider == "download":
started_downloads += 1
if started_downloads <= self.max_downloads:
self.installer_files_boxes[file_id].start()
file_entry.start()
else:
self._file_queue.append(file_id)
else:
self.installer_files_boxes[file_id].start()
file_entry.start()
def stop_all(self):
"""Stops all ongoing files gathering.

View file

@ -293,7 +293,7 @@ class InstallerWindow(BaseApplicationWindow): # pylint: disable=too-many-public
try:
self.interpreter.installer.prepare_game_files()
except UnavailableGame as ex:
raise ScriptingError(str(ex))
raise ScriptingError(str(ex)) from ex
if not self.interpreter.installer.files:
logger.debug("Installer doesn't require files")
@ -407,7 +407,7 @@ class InstallerWindow(BaseApplicationWindow): # pylint: disable=too-many-public
self.continue_button.disconnect(self.continue_handler)
except PermissionError as ex:
self.continue_button.set_sensitive(True)
raise ScriptingError("Unable to get files: %s" % ex)
raise ScriptingError("Unable to get files: %s" % ex) from ex
def on_files_available(self, widget):
"""All files are available, continue the install"""

View file

@ -5,7 +5,7 @@ class GridViewCellRendererText(Gtk.CellRendererText):
"""CellRendererText adjusted for grid view display, removes extra padding"""
def __init__(self, width, *args, **kwargs):
super(GridViewCellRendererText, self).__init__(*args, **kwargs)
super().__init__(*args, **kwargs)
self.props.alignment = Pango.Alignment.CENTER
self.props.wrap_mode = Pango.WrapMode.WORD
self.props.xalign = 0.5

View file

@ -35,7 +35,7 @@ def fetch_script(game_slug, revision=None):
def read_script(filename):
"""Return scripts from a local file"""
logger.debug("Loading script(s) from %s", filename)
script = yaml.safe_load(open(filename, "r").read())
script = yaml.safe_load(open(filename, "r", encoding='utf-8').read())
if isinstance(script, list):
return script
if "results" in script:

View file

@ -297,8 +297,8 @@ class CommandsMixin:
else:
action = shutil.move
self._killable_process(action, src, dst)
except shutil.Error:
raise ScriptingError("Can't move %s \nto destination %s" % (src, dst))
except shutil.Error as err:
raise ScriptingError("Can't move %s \nto destination %s" % (src, dst)) from err
def rename(self, params):
"""Rename file or folder."""
@ -327,8 +327,8 @@ class CommandsMixin:
"""Process raw 'src' and 'dst' data."""
try:
src_ref = params["src"]
except KeyError:
raise ScriptingError("Missing parameter src")
except KeyError as err:
raise ScriptingError("Missing parameter src") from err
src = self.game_files.get(src_ref) or self._substitute(src_ref)
if not src:
raise ScriptingError("Wrong value for 'src' param", src_ref)
@ -344,8 +344,8 @@ class CommandsMixin:
filename = self._substitute(data["file"])
logger.debug("Substituting variables for file %s", filename)
tmp_filename = filename + ".tmp"
with open(filename, "r") as source_file:
with open(tmp_filename, "w") as dest_file:
with open(filename, "r", encoding='utf-8') as source_file:
with open(tmp_filename, "w", encoding='utf-8') as dest_file:
line = "."
while line:
line = source_file.readline()
@ -438,7 +438,7 @@ class CommandsMixin:
if not mode.startswith(("a", "w")):
raise ScriptingError("Wrong value for write_file mode: '%s'" % mode)
with open(dest_file_path, mode) as dest_file:
with open(dest_file_path, mode, encoding='utf-8') as dest_file:
dest_file.write(self._substitute(params["content"]))
def write_json(self, params):
@ -457,10 +457,10 @@ class CommandsMixin:
if not os.path.exists(filename):
# create an empty file
with open(filename, "a+"):
with open(filename, "a+", encoding='utf-8'):
pass
with open(filename, "r+" if merge else "w") as json_file:
with open(filename, "r+" if merge else "w", encoding='utf-8') as json_file:
json_data = {}
if merge:
try:
@ -546,7 +546,7 @@ class CommandsMixin:
def _get_scummvm_arguments(self, gog_config_path):
"""Return a ScummVM configuration from the GOG config files"""
with open(gog_config_path) as gog_config_file:
with open(gog_config_path, encoding='utf-8') as gog_config_file:
gog_config = json.loads(gog_config_file.read())
game_tasks = [task for task in gog_config["playTasks"] if task["category"] == "game"]
arguments = game_tasks[0]["arguments"]

View file

@ -14,7 +14,7 @@ class ScriptingError(Exception):
def __init__(self, message, faulty_data=None):
self.message = message
self.faulty_data = faulty_data
super(ScriptingError, self).__init__()
super().__init__()
logger.error(self.__str__())
def __str__(self):

View file

@ -202,8 +202,8 @@ class LutrisInstaller: # pylint: disable=too-many-instance-attributes
if "game" in self.script:
try:
config["game"].update(self.script["game"])
except ValueError:
raise ScriptingError("Invalid 'game' section", self.script["game"])
except ValueError as err:
raise ScriptingError("Invalid 'game' section", self.script["game"]) from err
config["game"] = self._substitute_config(config["game"])
if AUTO_ELF_EXE in config["game"].get("exe", ""):
config["game"]["exe"] = find_linux_game_executable(self.interpreter.target_path,

View file

@ -173,8 +173,8 @@ class InstallerFile:
return
try:
hash_type, expected_hash = self.checksum.split(':', 1)
except ValueError:
raise ScriptingError("Invalid checksum, expected format (type:hash) ", self.checksum)
except ValueError as err:
raise ScriptingError("Invalid checksum, expected format (type:hash) ", self.checksum) from err
if system.get_file_checksum(self.dest_file, hash_type) != expected_hash:
raise ScriptingError(hash_type.capitalize() + " checksum mismatch ", self.checksum)

View file

@ -173,11 +173,11 @@ class ScriptInterpreter(GObject.Object, CommandsMixin):
logger.debug("Creating destination path %s", self.target_path)
os.makedirs(self.target_path)
self.game_dir_created = True
except PermissionError:
except PermissionError as err:
raise ScriptingError(
"Lutris does not have the necessary permissions to install to path:",
self.target_path,
)
) from err
def get_runners_to_install(self):
"""Check if the runner is installed before starting the installation
@ -251,15 +251,15 @@ class ScriptInterpreter(GObject.Object, CommandsMixin):
)
except (NonInstallableRunnerError, RunnerInstallationError) as ex:
logger.error(ex.message)
raise ScriptingError(ex.message)
raise ScriptingError(ex.message) from ex
def get_runner_class(self, runner_name):
"""Runner the runner class from its name"""
try:
runner = import_runner(runner_name)
except InvalidRunner:
except InvalidRunner as err:
GLib.idle_add(self.parent.cancel_button.set_sensitive, True)
raise ScriptingError("Invalid runner provided %s" % runner_name)
raise ScriptingError("Invalid runner provided %s" % runner_name) from err
return runner
def launch_installer_commands(self):
@ -290,8 +290,8 @@ class ScriptInterpreter(GObject.Object, CommandsMixin):
elif self.current_command < len(commands):
try:
command = commands[self.current_command]
except KeyError:
raise ScriptingError("Installer commands are not formatted correctly")
except KeyError as err:
raise ScriptingError("Installer commands are not formatted correctly") from err
self.current_command += 1
method, params = self._map_command(command)
if isinstance(params, dict):

View file

@ -42,8 +42,8 @@ class SteamInstaller(GObject.Object):
self.file_id = file_id
try:
_steam, appid, path = self.steam_uri.split(":", 2)
except ValueError:
raise ScriptingError("Malformed steam path: %s" % self.steam_uri)
except ValueError as err:
raise ScriptingError("Malformed steam path: %s" % self.steam_uri) from err
self.appid = appid
self.path = path

View file

@ -132,11 +132,11 @@ def export_bash_script(runner, gameplay_info, script_path):
env["TERM"] = "xterm"
script_content = "#!/bin/bash\n\n\n"
script_content += "# Environment variables\n"
for env_var in env:
script_content += "export %s=\"%s\"\n" % (env_var, env[env_var])
for name, value in env.items():
script_content += f'export {name}="{value}"\n'
script_content += "\n# Command\n"
script_content += " ".join([shlex.quote(c) for c in command])
with open(script_path, "w") as script_file:
with open(script_path, "w", encoding='utf-8') as script_file:
script_file.write(script_content)
os.chmod(script_path, os.stat(script_path).st_mode | stat.S_IEXEC)

View file

@ -111,7 +111,7 @@ class atari800(Runner):
if callback:
callback()
super(atari800, self).install(version, downloader, on_runner_installed)
super().install(version, downloader, on_runner_installed)
def find_good_bioses(self, bios_path):
""" Check for correct bios files """

View file

@ -41,7 +41,7 @@ def dosexec(config_file=None, executable=None, args=None, close_on_exit=True, wo
def makeconfig(path, drives, commands):
system.create_folder(os.path.dirname(path))
with open(path, "w") as config_file:
with open(path, "w", encoding='utf-8') as config_file:
config_file.write("[autoexec]\n")
for drive in drives:
config_file.write('mount {} "{}"\n'.format(drive, drives[drive]))

View file

@ -42,7 +42,7 @@ def set_regedit(
}
# Make temporary reg file
reg_path = os.path.join(settings.CACHE_DIR, "winekeys.reg")
with open(reg_path, "w") as reg_file:
with open(reg_path, "w", encoding='utf-8') as reg_file:
reg_file.write('REGEDIT4\n\n[%s]\n"%s"=%s\n' % (path, key, formatted_value[type]))
logger.debug("Setting [%s]:%s=%s", path, key, formatted_value[type])
set_regedit_file(reg_path, wine_path=wine_path, prefix=prefix, arch=arch)

View file

@ -131,7 +131,7 @@ class dosbox(Runner):
return os.path.expanduser(option)
if self.main_file:
return os.path.dirname(self.main_file)
return super(dosbox, self).working_dir
return super().working_dir
def play(self):
main_file = self.main_file

View file

@ -151,7 +151,7 @@ class hatari(Runner):
if callback:
callback()
super(hatari, self).install(version=version, downloader=downloader, callback=on_runner_installed)
super().install(version=version, downloader=downloader, callback=on_runner_installed)
def play(self): # pylint: disable=too-many-branches
params = [self.get_executable()]

View file

@ -19,7 +19,7 @@ class JsonRunner(Runner):
super().__init__(config)
if not self.json_path:
raise RuntimeError("Create subclasses of JsonRunner with the json_path attribute set")
with open(self.json_path) as json_file:
with open(self.json_path, encoding='utf-8') as json_file:
self._json_data = json.load(json_file)
self.game_options = self._json_data["game_options"]

View file

@ -140,12 +140,12 @@ class libretro(Runner):
if callback:
callback()
else:
super(libretro, self).install(version, downloader, callback)
super().install(version, downloader, callback)
if not self.is_retroarch_installed():
super(libretro, self).install(version=None, downloader=downloader, callback=install_core)
super().install(version=None, downloader=downloader, callback=install_core)
else:
super(libretro, self).install(version, downloader, callback)
super().install(version, downloader, callback)
def get_run_data(self):
return {
@ -170,7 +170,7 @@ class libretro(Runner):
# TODO: review later
# Create retroarch.cfg if it doesn't exist.
if not system.path_exists(config_file):
f = open(config_file, "w")
f = open(config_file, "w", encoding='utf-8')
f.write("# Lutris RetroArch Configuration")
f.close()
@ -281,11 +281,11 @@ class libretro(Runner):
# Checks whether the retroarch or libretro directories can be uninstalled.
def can_uninstall(self):
retroarch_path = os.path.join(settings.RUNNER_DIR, 'retroarch')
return os.path.isdir(retroarch_path) or super(libretro, self).can_uninstall()
return os.path.isdir(retroarch_path) or super().can_uninstall()
# Remove the `retroarch` directory.
def uninstall(self):
retroarch_path = os.path.join(settings.RUNNER_DIR, 'retroarch')
if os.path.isdir(retroarch_path):
system.remove_folder(retroarch_path)
super(libretro, self).uninstall()
super().uninstall()

View file

@ -69,7 +69,7 @@ class linux(Runner):
]
def __init__(self, config=None):
super(linux, self).__init__(config)
super().__init__(config)
self.ld_preload = None
@property
@ -104,7 +104,7 @@ class linux(Runner):
return os.path.expanduser(option)
if self.game_exe:
return os.path.dirname(self.game_exe)
return super(linux, self).working_dir
return super().working_dir
def is_installed(self):
"""Well of course Linux is installed, you're using Linux right ?"""

View file

@ -247,7 +247,7 @@ class mame(Runner): # pylint: disable=invalid-name
env=runtime.get_env()
)
if output:
with open(self.xml_path, "w") as xml_file:
with open(self.xml_path, "w", encoding='utf-8') as xml_file:
xml_file.write(output)
logger.info("MAME XML list written to %s", self.xml_path)
else:

View file

@ -101,7 +101,7 @@ class o2em(Runner):
if callback:
callback()
super(o2em, self).install(version, downloader, on_runner_installed)
super().install(version, downloader, on_runner_installed)
def play(self):
arguments = ["-biosdir=%s" % self.bios_path]

View file

@ -74,7 +74,7 @@ class pico8(Runner):
runner_executable = "pico8/web.py"
def __init__(self, config=None):
super(pico8, self).__init__(config)
super().__init__(config)
self.runnable_alone = self.is_native

View file

@ -113,7 +113,7 @@ class redream(Runner):
license_filename, os.path.join(settings.RUNNER_DIR, "redream")
)
super(redream, self).install(
super().install(
version=version, downloader=downloader, callback=on_runner_installed
)

View file

@ -33,7 +33,7 @@ class reicast(Runner):
]
def __init__(self, config=None):
super(reicast, self).__init__(config)
super().__init__(config)
self.runner_options = [
{
@ -83,7 +83,7 @@ class reicast(Runner):
system.create_folder("~/.reicast/data")
NoticeDialog(_("You have to copy valid BIOS files to ~/.reicast/data before playing"))
super(reicast, self).install(version, downloader, on_runner_installed)
super().install(version, downloader, on_runner_installed)
def get_joypads(self):
"""Return list of joypad in a format usable in the options"""
@ -119,7 +119,7 @@ class reicast(Runner):
config_path = os.path.expanduser("~/.reicast/emu.cfg")
if system.path_exists(config_path):
with open(config_path, "r") as config_file:
with open(config_path, "r", encoding='utf-8') as config_file:
parser.read_file(config_file)
for section in config:
@ -128,7 +128,7 @@ class reicast(Runner):
for (key, value) in config[section].items():
parser.set(section, key, str(value))
with open(config_path, "w") as config_file:
with open(config_path, "w", encoding='utf-8') as config_file:
parser.write(config_file)
def play(self):

View file

@ -152,7 +152,7 @@ class Runner: # pylint: disable=too-many-public-methods
if sdl_gamecontrollerconfig:
path = os.path.expanduser(sdl_gamecontrollerconfig)
if system.path_exists(path):
with open(path, "r") as controllerdb_file:
with open(path, "r", encoding='utf-8') as controllerdb_file:
sdl_gamecontrollerconfig = controllerdb_file.read()
env["SDL_GAMECONTROLLERCONFIG"] = sdl_gamecontrollerconfig
@ -389,7 +389,7 @@ class Runner: # pylint: disable=too-many-public-methods
extract_archive(archive, dest, merge_single=merge_single)
except ExtractFailure as ex:
logger.error("Failed to extract the archive %s file may be corrupt", archive)
raise RunnerInstallationError("Failed to extract {}: {}".format(archive, ex))
raise RunnerInstallationError("Failed to extract {}: {}".format(archive, ex)) from ex
os.remove(archive)
if self.name == "wine":

View file

@ -127,7 +127,7 @@ class steam(Runner):
system_options_override = [{"option": "disable_runtime", "default": True}]
def __init__(self, config=None):
super(steam, self).__init__(config)
super().__init__(config)
self.own_game_remove_method = _("Remove game data (through Steam)")
self.no_game_remove_warning = True
self.original_steampid = None
@ -278,7 +278,7 @@ class steam(Runner):
if not steamapps_path:
raise RuntimeError("Could not find Steam path, is Steam installed?")
acf_path = os.path.join(steamapps_path, "appmanifest_%s.acf" % appid)
with open(acf_path, "w") as acf_file:
with open(acf_path, "w", encoding='utf-8') as acf_file:
acf_file.write(acf_content)
if is_running():
shutdown()

View file

@ -112,8 +112,8 @@ class vice(Runner):
}
try:
executable = executables[machine]
except KeyError:
raise ValueError("Invalid machine '%s'" % machine)
except KeyError as ex:
raise ValueError("Invalid machine '%s'" % machine) from ex
return os.path.join(settings.RUNNER_DIR, "vice/bin/%s" % executable)
def install(self, version=None, downloader=None, callback=None):
@ -130,7 +130,7 @@ class vice(Runner):
if callback:
callback()
super(vice, self).install(version, downloader, on_runner_installed)
super().install(version, downloader, on_runner_installed)
def get_roms_path(self, machine=None):
if not machine:

View file

@ -176,7 +176,7 @@ class web(Runner):
runner_executable = "web/electron/electron"
def get_env(self, os_env=True):
env = super(web, self).get_env(os_env)
env = super().get_env(os_env)
enable_flash_player = self.runner_config.get("enable_flash")
env["ENABLE_FLASH_PLAYER"] = "1" if enable_flash_player else "0"

View file

@ -104,7 +104,7 @@ class wine(Runner):
)
def __init__(self, config=None): # noqa: C901
super(wine, self).__init__(config)
super().__init__(config)
self.dll_overrides = DEFAULT_DLL_OVERRIDES
def get_wine_version_choices():
@ -117,7 +117,7 @@ class wine(Runner):
}
versions = get_wine_versions()
for version in versions:
if version in labels.keys():
if version in labels:
version_number = get_wine_version(WINE_PATHS[version])
label = labels[version].format(version_number)
else:
@ -506,7 +506,7 @@ class wine(Runner):
return option
if self.game_exe:
return os.path.dirname(self.game_exe)
return super(wine, self).working_dir
return super().working_dir
@property
def wine_arch(self):
@ -530,7 +530,7 @@ class wine(Runner):
def get_path_for_version(self, version):
"""Return the absolute path of a wine executable for a given version"""
# logger.debug("Getting path for Wine %s", version)
if version in WINE_PATHS.keys():
if version in WINE_PATHS:
return system.find_executable(WINE_PATHS[version])
if "Proton" in version:
for proton_path in get_proton_paths():
@ -695,10 +695,10 @@ class wine(Runner):
for key, path in self.reg_keys.items():
value = self.runner_config.get(key) or "auto"
if not value or value == "auto" and key not in managed_keys.keys():
if not value or value == "auto" and key not in managed_keys:
prefix_manager.clear_registry_subkeys(path, key)
elif key in self.runner_config:
if key in managed_keys.keys():
if key in managed_keys:
# Do not pass fallback 'auto' value to managed keys
if value == "auto":
value = None
@ -782,7 +782,7 @@ class wine(Runner):
# Always false to runner.get_env, the default value
# of os_env is inverted in the wine class,
# the OS env is read later.
env = super(wine, self).get_env(False)
env = super().get_env(False)
if os_env:
env.update(os.environ.copy())
show_debug = self.runner_config.get("show_debug", "-all")

View file

@ -123,7 +123,7 @@ class winesteam(wine.wine):
]
def __init__(self, config=None):
super(winesteam, self).__init__(config)
super().__init__(config)
self.own_game_remove_method = _("Remove game data (through Wine Steam)")
self.no_game_remove_warning = True
winesteam_options = [

View file

@ -95,7 +95,7 @@ class zdoom(Runner):
]
def get_executable(self):
executable = super(zdoom, self).get_executable()
executable = super().get_executable()
executable_dir = os.path.dirname(executable)
if not system.path_exists(executable_dir):
return executable

View file

@ -46,11 +46,11 @@ def clean_rom_name(name):
def scan_directory(dirname):
"""Add a directory of ROMs as Lutris games"""
files = os.listdir(dirname)
folder_extentions = {os.path.splitext(filename)[1] for filename in files}
folder_extensions = {os.path.splitext(filename)[1] for filename in files}
core_matches = {}
for core in RECOMMENDED_CORES:
for ext in RECOMMENDED_CORES[core].get("extensions", []):
if ext in folder_extentions:
for core, core_data in RECOMMENDED_CORES.items():
for ext in core_data.get("extensions", []):
if ext in folder_extensions:
core_matches[ext] = core
added_games = []
for filename in files:

View file

@ -170,7 +170,7 @@ class EpicGamesStoreService(OnlineService):
self.session = requests.session()
self.session.headers['User-Agent'] = self.user_agent
if os.path.exists(self.token_path):
with open(self.token_path) as token_file:
with open(self.token_path, encoding='utf-8') as token_file:
self.session_data = json.loads(token_file.read())
else:
self.session_data = {}
@ -250,7 +250,7 @@ class EpicGamesStoreService(OnlineService):
response_content = response.json()
if 'error' in response_content:
raise RuntimeError(response_content)
with open(self.token_path, "w") as auth_file:
with open(self.token_path, "w", encoding='utf-8') as auth_file:
auth_file.write(json.dumps(response_content, indent=2))
self.session_data = response_content

View file

@ -185,7 +185,7 @@ class GOGService(OnlineService):
return
token = request.json
with open(self.token_path, "w") as token_file:
with open(self.token_path, "w", encoding='utf-8') as token_file:
token_file.write(json.dumps(token))
if not refresh_token:
self.emit("service-login")
@ -194,7 +194,7 @@ class GOGService(OnlineService):
"""Load token from disk"""
if not os.path.exists(self.token_path):
raise AuthenticationError("No GOG token available")
with open(self.token_path) as token_file:
with open(self.token_path, encoding='utf-8') as token_file:
token_content = json.loads(token_file.read())
return token_content
@ -246,7 +246,7 @@ class GOGService(OnlineService):
"""Return the user's library of GOG games"""
if system.path_exists(self.cache_path):
logger.debug("Returning cached GOG library")
with open(self.cache_path, "r") as gog_cache:
with open(self.cache_path, "r", encoding='utf-8') as gog_cache:
return json.load(gog_cache)
total_pages = 1
@ -257,7 +257,7 @@ class GOGService(OnlineService):
page += 1
total_pages = products_response["totalPages"]
games += products_response["products"]
with open(self.cache_path, "w") as gog_cache:
with open(self.cache_path, "w", encoding='utf-8') as gog_cache:
json.dump(games, gog_cache)
return games
@ -291,7 +291,7 @@ class GOGService(OnlineService):
response = self.make_api_request(downlink)
except HTTPError as ex:
logger.error("HTTP error: %s", ex)
raise UnavailableGame
raise UnavailableGame from ex
if not response:
raise UnavailableGame
for field in ("checksum", "downlink"):
@ -398,8 +398,8 @@ class GOGService(OnlineService):
logger.warning("More than 1 GOG installer found, picking first.")
_installer = gog_installers[0]
links = self.query_download_links(_installer)
except HTTPError:
raise UnavailableGame("Couldn't load the download links for this game")
except HTTPError as err:
raise UnavailableGame("Couldn't load the download links for this game") from err
if not links:
raise UnavailableGame("Could not fing GOG game")
_installer_files = defaultdict(dict) # keyed by filename
@ -445,7 +445,7 @@ class GOGService(OnlineService):
"""
if not file_path.endswith(".xml"):
raise ValueError("Pass a XML file to return the checksum")
with open(file_path) as checksum_file:
with open(file_path, encoding='utf-8') as checksum_file:
checksum_content = checksum_file.read()
root_elem = etree.fromstring(checksum_content)
return (root_elem.attrib["name"], root_elem.attrib["md5"])

View file

@ -132,12 +132,12 @@ class HumbleBundleService(OnlineService):
# logger.debug("Getting Humble Bundle order %s", gamekey)
cache_filename = self.order_path(gamekey)
if os.path.exists(cache_filename):
with open(cache_filename) as cache_file:
with open(cache_filename, encoding='utf-8') as cache_file:
return json.load(cache_file)
response = self.make_api_request(self.api_url + "api/v1/order/%s?all_tpkds=true" % gamekey)
if not os.path.exists(self.cache_path):
os.makedirs(self.cache_path)
with open(cache_filename, "w") as cache_file:
with open(cache_filename, "w", encoding='utf-8') as cache_file:
json.dump(response, cache_file)
return response
@ -221,7 +221,7 @@ class HumbleBundleService(OnlineService):
link = get_humble_download_link(installer.service_appid, installer.runner)
except Exception as ex:
logger.exception("Failed to get Humble Bundle game: %s", ex)
raise UnavailableGame
raise UnavailableGame from ex
if not link:
raise UnavailableGame("No game found on Humble Bundle")
filename = link.split("?")[0].split("/")[-1]

View file

@ -57,7 +57,7 @@ class OriginService(OnlineService):
token = self.get_access_token()
if not token:
raise RuntimeError("Failed to get access token")
with open(self.token_path, "w") as token_file:
with open(self.token_path, "w", encoding='utf-8') as token_file:
token_file.write(json.dumps(token, indent=2))
self.emit("service-login")

View file

@ -84,7 +84,7 @@ class ServiceMedia:
return download_file(url, cache_path, raise_errors=True)
except HTTPError as ex:
if ex.code == 404:
open(cache_path, "a").close()
open(cache_path, "a", encoding='utf-8').close()
else:
logger.error(ex.code)
return None

View file

@ -166,11 +166,11 @@ def init_lutris():
init_dirs()
try:
syncdb()
except sqlite3.DatabaseError:
except sqlite3.DatabaseError as err:
raise RuntimeError(
"Failed to open database file in %s. Try renaming this file and relaunch Lutris" %
settings.PGA_DB
)
) from err
for service in DEFAULT_SERVICES:
if not settings.read_setting(service, section="services"):
settings.write_setting(service, True, section="services")

View file

@ -75,6 +75,6 @@ class WebkitCookieJar(MozillaCookieJar):
except OSError:
raise
except Exception:
except Exception as err:
_warn_unhandled_exception()
raise OSError("invalid Netscape format cookies file %r: %r" % (filename, line))
raise OSError("invalid Netscape format cookies file %r: %r" % (filename, line)) from err

View file

@ -30,7 +30,7 @@ def rom_read_data(location):
return a dict with "data" and "config", to be applied to a game in Lutris """
# TODO: extract the image of the rom
data = {}
with open(location, "r+") as rom:
with open(location, "r+", encoding='utf-8') as rom:
mm = mmap(rom.fileno(), 0)
# the most of the scan of the game
if mm[0:4] == b"WBFS": # wii WBFS file

View file

@ -19,7 +19,7 @@ class EGSLauncher:
for manifest in os.listdir(manifests_path):
if not manifest.endswith(".item"):
continue
with open(os.path.join(manifests_path, manifest)) as manifest_file:
with open(os.path.join(manifests_path, manifest), encoding='utf-8') as manifest_file:
manifest_content = json.loads(manifest_file.read())
if manifest_content["MainGameAppName"] != manifest_content["AppName"]:
continue

View file

@ -128,7 +128,7 @@ def extract_archive(path, to_directory=".", merge_single=True, extractor=None):
_do_extract(path, temp_path, opener, mode, extractor)
except (OSError, zlib.error, tarfile.ReadError, EOFError) as ex:
logger.error("Extraction failed: %s", ex)
raise ExtractFailure(str(ex))
raise ExtractFailure(str(ex)) from ex
if merge_single:
extracted = os.listdir(temp_path)
if len(extracted) == 1:
@ -164,7 +164,7 @@ def extract_archive(path, to_directory=".", merge_single=True, extractor=None):
destination_path,
ex,
)
raise ExtractFailure(str(ex))
raise ExtractFailure(str(ex)) from ex
else:
shutil.move(source_path, destination_path)
system.remove_folder(temp_dir)

View file

@ -56,4 +56,4 @@ class MultiOrderedDict(OrderedDict):
if isinstance(value, list) and key in self:
self[key].extend(value)
else:
super(MultiOrderedDict, self).__setitem__(key, value)
super().__setitem__(key, value)

View file

@ -57,8 +57,8 @@ def find_linux_game_executable(path, make_executable=False):
candidates["32bit"] = abspath
if candidates:
if make_executable:
for file_type in candidates:
system.make_executable(candidates[file_type])
for candidate in candidates.values():
system.make_executable(candidate)
return (
candidates.get("shell")
or candidates.get("bash")

View file

@ -71,7 +71,7 @@ class GameControllerDB:
return self.controllers[value]
def parsedb(self):
with open(self.db_path, "r") as db:
with open(self.db_path, "r", encoding='utf-8') as db:
for line in db.readlines():
line = line.strip()
if not line or line.startswith("#"):

View file

@ -17,7 +17,7 @@ def get_nvidia_driver_info():
version_file_path = "/proc/driver/nvidia/version"
if not os.path.exists(version_file_path):
return
with open(version_file_path) as version_file:
with open(version_file_path, encoding='utf-8') as version_file:
content = version_file.readlines()
nvrm_version = content[0].split(': ')[1].strip().split()
return {
@ -39,7 +39,7 @@ def get_nvidia_gpu_ids():
def get_nvidia_gpu_info(gpu_id):
"""Return details about a GPU"""
with open("/proc/driver/nvidia/gpus/%s/information" % gpu_id) as info_file:
with open("/proc/driver/nvidia/gpus/%s/information" % gpu_id, encoding='utf-8') as info_file:
content = info_file.readlines()
infos = {}
for line in content:
@ -67,7 +67,7 @@ def get_gpu_info(card):
"""Return information about a GPU"""
infos = {"DRIVER": "", "PCI_ID": "", "PCI_SUBSYS_ID": ""}
try:
with open("/sys/class/drm/%s/device/uevent" % card) as card_uevent:
with open("/sys/class/drm/%s/device/uevent" % card, encoding='utf-8') as card_uevent:
content = card_uevent.readlines()
except FileNotFoundError:
logger.error("Unable to read driver information for card %s", card)

View file

@ -82,7 +82,7 @@ class Request:
try:
req = urllib.request.Request(url=self.url, data=data, headers=self.headers)
except ValueError as ex:
raise HTTPError("Failed to create HTTP request to %s: %s" % (self.url, ex))
raise HTTPError("Failed to create HTTP request to %s: %s" % (self.url, ex)) from ex
try:
if self.opener:
request = self.opener.open(req, timeout=self.timeout)
@ -90,10 +90,10 @@ class Request:
request = urllib.request.urlopen(req, timeout=self.timeout)
except (urllib.error.HTTPError, CertificateError) as error:
if error.code == 401:
raise UnauthorizedAccess("Access to %s denied" % self.url)
raise HTTPError("%s" % error, code=error.code)
raise UnauthorizedAccess("Access to %s denied" % self.url) from error
raise HTTPError("%s" % error, code=error.code) from error
except (socket.timeout, urllib.error.URLError) as error:
raise HTTPError("Unable to connect to server %s: %s" % (self.url, error))
raise HTTPError("Unable to connect to server %s: %s" % (self.url, error)) from error
try:
self.total_size = int(request.info().get("Content-Length").strip())
except AttributeError:
@ -116,8 +116,8 @@ class Request:
return self
try:
chunk = request.read(self.buffer_size)
except (socket.timeout, ConnectionResetError):
raise HTTPError("Request timed out")
except (socket.timeout, ConnectionResetError) as err:
raise HTTPError("Request timed out") from err
self.downloaded_size += len(chunk)
if not chunk:
return
@ -144,8 +144,8 @@ class Request:
if _raw_json:
try:
return json.loads(_raw_json)
except json.decoder.JSONDecodeError:
raise ValueError("JSON response from %s could not be decoded: '%s'" % (self.url, _raw_json[:80]))
except json.decoder.JSONDecodeError as err:
raise ValueError(f"JSON response from {self.url} could not be decoded: '{_raw_json[:80]}'") from err
return {}
@property

View file

@ -19,7 +19,7 @@ class AsyncCall(threading.Thread):
self.source_id = None
self.stop_request = threading.Event()
super(AsyncCall, self).__init__(target=self.target, args=args, kwargs=kwargs)
super().__init__(target=self.target, args=args, kwargs=kwargs)
self.function = func
self.callback = callback if callback else lambda r, e: None
self.daemon = kwargs.pop("daemon", True)

View file

@ -33,7 +33,7 @@ class RetroConfig:
self._config = []
if not os.path.isfile(self.config_path):
raise OSError("Specified config file {} does not exist".format(self.config_path))
with open(self.config_path, "r") as config_file:
with open(self.config_path, "r", encoding='utf-8') as config_file:
for line in config_file.readlines():
if not line:
continue
@ -49,7 +49,7 @@ class RetroConfig:
self._config.append((key, value))
def save(self):
with open(self.config_path, "w") as config_file:
with open(self.config_path, "w", encoding='utf-8') as config_file:
for (key, value) in self.config:
config_file.write('{} = "{}"\n'.format(key, value))

View file

@ -146,7 +146,7 @@ class LinuxSystem: # pylint: disable=too-many-public-methods
"""Parse the output of /proc/cpuinfo"""
cpus = [{}]
cpu_index = 0
with open("/proc/cpuinfo") as cpuinfo:
with open("/proc/cpuinfo", encoding='utf-8') as cpuinfo:
for line in cpuinfo.readlines():
if not line.strip():
cpu_index += 1
@ -170,7 +170,7 @@ class LinuxSystem: # pylint: disable=too-many-public-methods
def get_ram_info():
"""Parse the output of /proc/meminfo and return RAM information in kB"""
mem = {}
with open("/proc/meminfo") as meminfo:
with open("/proc/meminfo", encoding='utf-8') as meminfo:
for line in meminfo.readlines():
key, value = line.split(":", 1)
mem[key.strip()] = value.strip('kB \n')
@ -200,7 +200,7 @@ class LinuxSystem: # pylint: disable=too-many-public-methods
@staticmethod
def get_kernel_version():
"""Get kernel info from /proc/version"""
with open("/proc/version") as kernel_info:
with open("/proc/version", encoding='utf-8') as kernel_info:
info = kernel_info.readlines()[0]
version = info.split(" ")[2]
return version
@ -476,12 +476,11 @@ def gather_system_info_str():
system_info_readable["Graphics"] = graphics_dict
output = ''
for section in system_info_readable:
output += '[{}]\n'.format(section)
dictionary = system_info_readable[section]
for key in dictionary:
for section, dictionary in system_info_readable.items():
output += f'[{section}]\n'
for key, value in dictionary.items():
tabs = " " * (16 - len(key))
output += '{}{}{}\n'.format(key + ":", tabs, dictionary[key])
output += f'{key}:{tabs}{value}\n'
output += '\n'
return output

View file

@ -109,7 +109,7 @@ def get_supported_systems(xml_path, force=False):
"""
systems_cache_path = os.path.join(CACHE_DIR, "systems.json")
if os.path.exists(systems_cache_path) and not force:
with open(systems_cache_path, "r") as systems_cache_file:
with open(systems_cache_path, "r", encoding='utf-8') as systems_cache_file:
try:
systems = json.load(systems_cache_file)
except json.JSONDecodeError:
@ -123,7 +123,7 @@ def get_supported_systems(xml_path, force=False):
}
if not systems:
return {}
with open(systems_cache_path, "w") as systems_cache_file:
with open(systems_cache_path, "w", encoding='utf-8') as systems_cache_file:
json.dump(systems, systems_cache_file, indent=2)
return systems

View file

@ -26,7 +26,7 @@ class MameIni:
def read(self):
"""Reads the content of the ini file"""
with open(self.ini_path, "r") as ini_file:
with open(self.ini_path, "r", encoding='utf-8') as ini_file:
for line in ini_file.readlines():
self.lines.append(line)
print(line)
@ -36,7 +36,7 @@ class MameIni:
def write(self):
"""Writes the file to disk"""
with open(self.ini_path, "w") as ini_file:
with open(self.ini_path, "w", encoding='utf-8') as ini_file:
for line in self.lines:
config_key, _value = self.parse(line)
if config_key and self.config[config_key]:

View file

@ -22,8 +22,8 @@ class Process:
def __init__(self, pid):
try:
self.pid = int(pid)
except ValueError:
raise InvalidPid("'%s' is not a valid pid" % pid)
except ValueError as err:
raise InvalidPid("'%s' is not a valid pid" % pid) from err
def __repr__(self):
return "Process {}".format(self.pid)
@ -34,7 +34,7 @@ class Process:
def _read_content(self, file_path):
"""Return the contents from a file in /proc"""
try:
with open(file_path) as proc_file:
with open(file_path, encoding='utf-8') as proc_file:
content = proc_file.read()
except (ProcessLookupError, FileNotFoundError, PermissionError):
return ""
@ -43,7 +43,7 @@ class Process:
def get_stat(self, parsed=True):
stat_filename = "/proc/{}/stat".format(self.pid)
try:
with open(stat_filename) as stat_file:
with open(stat_filename, encoding='utf-8') as stat_file:
_stat = stat_file.readline()
except (ProcessLookupError, FileNotFoundError):
return None
@ -66,7 +66,7 @@ class Process:
"""Return pids of child processes opened by thread `tid` of process."""
children_path = "/proc/{}/task/{}/children".format(self.pid, tid)
try:
with open(children_path) as children_file:
with open(children_path, encoding='utf-8') as children_file:
children_content = children_file.read()
except (FileNotFoundError, ProcessLookupError):
children_content = ""

View file

@ -39,5 +39,5 @@ class SettingsIO:
self.config.add_section(section)
self.config.set(section, key, str(value))
with open(self.config_file, "w") as config_file:
with open(self.config_file, "w", encoding='utf-8') as config_file:
self.config.write(config_file)

View file

@ -17,7 +17,7 @@ def get_terminal_script(command, cwd, env):
env["TERM"] = "xterm"
exported_environment = "\n".join('export %s="%s" ' % (key, value) for key, value in env.items())
command = " ".join(['"%s"' % token for token in command])
with open(script_path, "w") as script_file:
with open(script_path, "w", encoding='utf-8') as script_file:
script_file.write(
dedent(
"""#!/bin/sh
@ -40,7 +40,7 @@ def get_bash_rc_file(cwd, env, aliases=None):
aliases = aliases or {}
alias_commands = "\n".join('alias %s="%s"' % (key, value) for key, value in aliases.items())
current_bashrc = os.path.expanduser("~/.bashrc")
with open(script_path, "w") as script_file:
with open(script_path, "w", encoding='utf-8') as script_file:
script_file.write(
dedent(
"""

View file

@ -46,7 +46,7 @@ class AppManifest:
self.appmanifest_data = {}
if path_exists(appmanifest_path):
with open(appmanifest_path, "r") as appmanifest_file:
with open(appmanifest_path, "r", encoding='utf-8') as appmanifest_file:
self.appmanifest_data = vdf_parse(appmanifest_file, {})
else:
logger.error("Path to AppManifest file %s doesn't exist", appmanifest_path)

View file

@ -59,7 +59,7 @@ def read_user_config():
config_filename = search_in_steam_dirs("config/loginusers.vdf")
if not system.path_exists(config_filename):
return None
with open(config_filename, "r") as steam_config_file:
with open(config_filename, "r", encoding='utf-8') as steam_config_file:
config = vdf_parse(steam_config_file, {})
return config
@ -133,7 +133,7 @@ def read_config(steam_data_dir):
config_filename = os.path.join(steam_data_dir, "config/config.vdf")
if not system.path_exists(config_filename):
return None
with open(config_filename, "r") as steam_config_file:
with open(config_filename, "r", encoding='utf-8') as steam_config_file:
config = vdf_parse(steam_config_file, {})
try:
return get_entry_case_insensitive(config, ["InstallConfigStore", "Software", "Valve", "Steam"])
@ -155,7 +155,7 @@ def read_library_folders(steam_data_dir):
library_filename = os.path.join(steam_data_dir, "config/libraryfolders.vdf")
if not system.path_exists(library_filename):
return None
with open(library_filename, "r") as steam_library_file:
with open(library_filename, "r", encoding='utf-8') as steam_library_file:
library = vdf_parse(steam_library_file, {})
# The contentstatsid key is unused and causes problems when looking for library paths.
library["libraryfolders"].pop("contentstatsid")

View file

@ -11,7 +11,7 @@ def _get_last_content_log(steam_data_dir):
path = os.path.join(steam_data_dir, "logs/content_log.txt")
log = []
try:
with open(path, "r") as logfile:
with open(path, "r", encoding='utf-8') as logfile:
line = logfile.readline()
while line:
# Strip old logs

View file

@ -55,5 +55,5 @@ def to_vdf(dict_data, level=0):
def vdf_write(vdf_path, config):
"""Write a Steam configuration to a vdf file"""
vdf_data = to_vdf(config)
with open(vdf_path, "w") as vdf_file:
with open(vdf_path, "w", encoding='utf-8') as vdf_file:
vdf_file.write(vdf_data)

View file

@ -132,7 +132,7 @@ class CabInstaller:
return (out, arch)
def get_wineprefix_arch(self):
with open(os.path.join(self.prefix, "system.reg")) as reg_file:
with open(os.path.join(self.prefix, "system.reg"), encoding='utf-8') as reg_file:
for line in reg_file.readlines():
if line.startswith("#arch=win32"):
return "win32"
@ -173,7 +173,7 @@ class CabInstaller:
outdata, arch = self.get_registry_from_manifest(file_path)
if outdata:
out += outdata
with open(os.path.join(self.tmpdir, file_path + ".reg"), "w") as reg_file:
with open(os.path.join(self.tmpdir, file_path + ".reg"), "w", encoding='utf-8') as reg_file:
reg_file.write(out)
reg_files.append((file_path + ".reg", arch))
if file_path.endswith(".dll"):

View file

@ -64,7 +64,7 @@ class DLLManager:
def load_versions(self):
if not system.path_exists(self.versions_path):
return []
with open(self.versions_path, "r") as version_file:
with open(self.versions_path, "r", encoding='utf-8') as version_file:
try:
versions = [v["tag_name"] for v in json.load(version_file)]
except (KeyError, json.decoder.JSONDecodeError):
@ -99,7 +99,7 @@ class DLLManager:
def get_download_url(self):
"""Fetch the download URL from the JSON version file"""
with open(self.versions_path, "r") as version_file:
with open(self.versions_path, "r", encoding='utf-8') as version_file:
releases = json.load(version_file)
for release in releases:
if release["tag_name"] != self.version:

View file

@ -155,11 +155,11 @@ class WinePrefixManager:
if desktop_dir != user_dir:
try:
src_path = os.path.join(desktop_dir, item)
except TypeError:
except TypeError as ex:
# There is supposedly a None value in there
# The current code shouldn't allow that
# Just raise a exception with the values
raise RuntimeError("Missing value desktop_dir=%s or item=%s" % (desktop_dir, item))
raise RuntimeError("Missing value desktop_dir=%s or item=%s" % (desktop_dir, item)) from ex
os.makedirs(src_path, exist_ok=True)
os.symlink(src_path, path)

View file

@ -97,7 +97,7 @@ class WineRegistry:
"""Return an array of the unprocessed contents of a registry file"""
if not system.path_exists(reg_filename):
return []
with open(reg_filename, "r") as reg_file:
with open(reg_filename, "r", encoding='utf-8') as reg_file:
try:
registry_content = reg_file.readlines()
@ -158,7 +158,7 @@ class WineRegistry:
"Invalid Wine prefix path %s, make sure to "
"create the prefix before saving to a registry" % prefix_path
)
with open(path, "w") as registry_file:
with open(path, "w", encoding='utf-8') as registry_file:
registry_file.write(self.render())
def query(self, path, subkey):

View file

@ -80,7 +80,7 @@ def detect_prefix_arch(prefix_path=None):
# No prefix_path exists or invalid prefix
logger.debug("Prefix not found: %s", prefix_path)
return None
with open(registry_path, "r") as registry:
with open(registry_path, "r", encoding='utf-8') as registry:
for _line_no in range(5):
line = registry.readline()
if "win64" in line:

View file

@ -61,7 +61,7 @@ def create_launcher(game_slug, game_id, game_name, desktop=False, menu=False):
launcher_filename = get_xdg_basename(game_slug, game_id)
tmp_launcher_path = os.path.join(CACHE_DIR, launcher_filename)
tmp_launcher = open(tmp_launcher_path, "w")
tmp_launcher = open(tmp_launcher_path, "w", encoding='utf-8')
tmp_launcher.write(launcher_content)
tmp_launcher.close()
os.chmod(

View file

@ -13,7 +13,7 @@ def read_yaml_from_file(filename):
if not path_exists(filename):
return {}
with open(filename, "r") as yaml_file:
with open(filename, "r", encoding='utf-8') as yaml_file:
try:
yaml_content = yaml.safe_load(yaml_file) or {}
except (yaml.scanner.ScannerError, yaml.parser.ParserError):
@ -25,5 +25,5 @@ def read_yaml_from_file(filename):
def write_yaml_to_file(config, filepath):
yaml_config = yaml.dump(config, default_flow_style=False)
with open(filepath, "w") as filehandler:
with open(filepath, "w", encoding='utf-8') as filehandler:
filehandler.write(yaml_config)