mirror of
https://github.com/lutris/lutris.git
synced 2026-07-30 07:05:55 -04:00
umu and typing fixes
This commit is contained in:
@@ -96,7 +96,7 @@ class LutrisApplication(Gtk.Application):
|
||||
self.tray = None
|
||||
|
||||
self.quit_on_game_exit = False
|
||||
self.style_manager = None
|
||||
self.style_manager = StyleManager()
|
||||
|
||||
if os.geteuid() == 0:
|
||||
NoticeDialog(_("Do not run Lutris as root."))
|
||||
@@ -340,8 +340,6 @@ class LutrisApplication(Gtk.Application):
|
||||
self.add_action(action)
|
||||
self.add_accelerator("<Primary>q", "app.quit")
|
||||
|
||||
self.style_manager = StyleManager()
|
||||
|
||||
def do_activate(self): # pylint: disable=arguments-differ
|
||||
if not self.window:
|
||||
self.window = LutrisWindow(application=self)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
from gettext import gettext as _
|
||||
from typing import Any, Dict, Optional
|
||||
|
||||
from gi.repository import Gio, Gtk
|
||||
from gi.repository import Gio, Gtk # type: ignore
|
||||
|
||||
from lutris import settings
|
||||
from lutris.gui.config.base_config_box import BaseConfigBox
|
||||
|
||||
@@ -4,9 +4,9 @@ import os
|
||||
from abc import ABC, abstractmethod
|
||||
from gettext import gettext as _
|
||||
from inspect import Parameter, signature
|
||||
from typing import Any, Callable, Dict, List, Optional, Union
|
||||
from typing import Any, Callable, Dict, List, Optional
|
||||
|
||||
from gi.repository import Gdk, Gtk
|
||||
from gi.repository import Gdk, Gtk # type: ignore
|
||||
|
||||
from lutris.config import LutrisConfig
|
||||
from lutris.gui.widgets import NotificationSource
|
||||
@@ -50,7 +50,7 @@ class WidgetGenerator(ABC):
|
||||
|
||||
# These are outputs set by generate_widget() or generate_container()
|
||||
# and they are reset on each call.
|
||||
self.wrapper: Optional[Gtk.Widget] = None
|
||||
self.wrapper: Optional[Gtk.Box] = None
|
||||
self.default_value = None
|
||||
self.tooltip_default: Optional[str] = None
|
||||
self.options: Dict[str, Dict[str, Any]] = {}
|
||||
@@ -59,9 +59,9 @@ class WidgetGenerator(ABC):
|
||||
self.warning_messages: List[Gtk.Widget] = []
|
||||
|
||||
# These accumulate results across all widgets
|
||||
self.wrappers: Dict[str, Gtk.Widget] = {}
|
||||
self.wrappers: Dict[str, Gtk.Container] = {}
|
||||
self.section_frames: List[SectionFrame] = []
|
||||
self.option_containers: Dict[str, Gtk.Widget] = {}
|
||||
self.option_containers: Dict[str, Gtk.Container] = {}
|
||||
|
||||
self._generators: Dict[str, WidgetGenerator.GeneratorFunction] = {
|
||||
"label": self._generate_label,
|
||||
@@ -98,7 +98,7 @@ class WidgetGenerator(ABC):
|
||||
|
||||
# Widget Construction
|
||||
|
||||
def add_container(self, option: Dict[str, Any], wrapper: Gtk.Box = None) -> Optional[Gtk.Widget]:
|
||||
def add_container(self, option: Dict[str, Any], wrapper: Optional[Gtk.Box] = None) -> Optional[Gtk.Widget]:
|
||||
"""Generates the option's widget, wrapper and container, and adds the container to the parent;
|
||||
if the option uses 'section', then the container is actually placed inside a SectionFrame,
|
||||
or in the previous frame if it is for the same section."""
|
||||
@@ -122,7 +122,7 @@ class WidgetGenerator(ABC):
|
||||
self._current_parent.pack_start(option_container, False, False, 0)
|
||||
return option_container
|
||||
|
||||
def generate_container(self, option: Dict[str, Any], wrapper: Gtk.Box = None) -> Optional[Gtk.Widget]:
|
||||
def generate_container(self, option: Dict[str, Any], wrapper: Optional[Gtk.Box] = None) -> Optional[Gtk.Widget]:
|
||||
"""Creates the widget, wrapper, and container; this returns the container
|
||||
(or the wrapper if there's no container)."""
|
||||
option_widget = self.generate_widget(option, wrapper)
|
||||
@@ -145,7 +145,7 @@ class WidgetGenerator(ABC):
|
||||
else:
|
||||
return None
|
||||
|
||||
def generate_widget(self, option: Dict[str, Any], wrapper: Gtk.Box = None) -> Optional[Gtk.Widget]:
|
||||
def generate_widget(self, option: Dict[str, Any], wrapper: Optional[Gtk.Box] = None) -> Optional[Gtk.Widget]:
|
||||
"""This creates a wrapper box and a label and widget within it according to the options dict
|
||||
given. The option widget itself, is returned, but this method also sets attributes on the
|
||||
generator. You get 'wrapper', 'default_value', 'tooltip_default' and 'option_widget' which restates
|
||||
@@ -232,7 +232,7 @@ class WidgetGenerator(ABC):
|
||||
|
||||
return Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=12, margin_bottom=6, visible=True)
|
||||
|
||||
def create_option_container(self, option: Dict[str, Any], wrapper: Gtk.Widget) -> Gtk.Widget:
|
||||
def create_option_container(self, option: Dict[str, Any], wrapper: Gtk.Container) -> Gtk.Container:
|
||||
"""This creates a wrapper box around the widget wrapper, to support additional controls. The
|
||||
base implementation wraps 'wrapper' in a Box with the error and warning widgets; if
|
||||
there are none it just returns 'wrapper'."""
|
||||
@@ -292,15 +292,15 @@ class WidgetGenerator(ABC):
|
||||
frame.set_visible(visible)
|
||||
frame.set_no_show_all(not visible)
|
||||
|
||||
def update_option_container(self, option, container: Gtk.Box, wrapper: Gtk.Box):
|
||||
def update_option_container(self, option, container: Gtk.Container, wrapper: Gtk.Container):
|
||||
"""This method updates an option container and its wrapper; this re-evaluates the
|
||||
relevant options in case they contain callables and those callables return different
|
||||
results."""
|
||||
|
||||
# Update messages in message boxes that support it
|
||||
for ch in container.get_children():
|
||||
if hasattr(ch, "update_message"):
|
||||
ch.update_message(option, self)
|
||||
for child in container.get_children():
|
||||
if hasattr(child, "update_message"):
|
||||
child.update_message(option, self)
|
||||
|
||||
# Hide entire container if the option is not visible
|
||||
visible = self.get_visibility(option)
|
||||
@@ -308,7 +308,7 @@ class WidgetGenerator(ABC):
|
||||
container.set_no_show_all(not visible)
|
||||
|
||||
# Grey out option if condition unmet, or if a second setting is False
|
||||
condition = self.get_condition(option)
|
||||
condition: bool = self.get_condition(option)
|
||||
wrapper.set_sensitive(condition)
|
||||
|
||||
# Widget factories
|
||||
@@ -600,7 +600,7 @@ class WidgetGenerator(ABC):
|
||||
vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
|
||||
label = Label(label + ":")
|
||||
label.set_halign(Gtk.Align.START)
|
||||
button = Gtk.Button(_("Add Files"))
|
||||
button = Gtk.Button(label=_("Add Files"))
|
||||
button.connect("clicked", on_add_files_clicked)
|
||||
button.set_margin_left(10)
|
||||
vbox.pack_start(label, False, False, 5)
|
||||
@@ -619,7 +619,7 @@ class WidgetGenerator(ABC):
|
||||
for filename in files:
|
||||
files_list_store.append([filename])
|
||||
cell_renderer = Gtk.CellRendererText()
|
||||
files_treeview = Gtk.TreeView(files_list_store)
|
||||
files_treeview = Gtk.TreeView(model=files_list_store)
|
||||
files_column = Gtk.TreeViewColumn(_("Files"), cell_renderer, text=0)
|
||||
files_treeview.append_column(files_column)
|
||||
files_treeview.connect("key-press-event", on_files_treeview_keypress)
|
||||
@@ -709,7 +709,7 @@ class WidgetGenerator(ABC):
|
||||
True, and if it is callable this calls it. Subclasses can add further conditions."""
|
||||
return self._evaluate_flag_option("visible", option)
|
||||
|
||||
def get_condition(self, option: Dict[str, Any]) -> Union[None, bool, Callable]:
|
||||
def get_condition(self, option: Dict[str, Any]) -> bool:
|
||||
"""Extracts the 'condition' option; but also the 'conditional_on' option, and if both
|
||||
are present, then if either indicates the control should be disabled this will be false.."""
|
||||
condition = self._evaluate_flag_option("condition", option)
|
||||
@@ -722,8 +722,8 @@ class WidgetGenerator(ABC):
|
||||
|
||||
container = self.option_containers[option["option"]]
|
||||
|
||||
for ch in container.get_children():
|
||||
if hasattr(ch, "blocks_sensitivity") and ch.blocks_sensitivity:
|
||||
for child in container.get_children():
|
||||
if hasattr(child, "blocks_sensitivity") and child.blocks_sensitivity:
|
||||
return False
|
||||
|
||||
return condition
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
from gettext import gettext as _
|
||||
from typing import Optional
|
||||
|
||||
from gi.repository import Gdk, Gtk
|
||||
from gi.repository import Gdk, Gtk # type: ignore
|
||||
|
||||
from lutris.exceptions import UnavailableRunnerError
|
||||
from lutris.game import Game
|
||||
@@ -79,7 +79,7 @@ class InstallUIDelegate(Delegate):
|
||||
"""
|
||||
return None
|
||||
|
||||
def download_install_file(self, url: str, destination: str) -> Downloader:
|
||||
def download_install_file(self, url: str, destination: str) -> bool:
|
||||
"""Downloads a file from a URL to a destination, overwriting any
|
||||
file at that path.
|
||||
|
||||
@@ -137,7 +137,7 @@ class DialogInstallUIDelegate(InstallUIDelegate):
|
||||
dlg = dialogs.FileDialog(message)
|
||||
return dlg.filename
|
||||
|
||||
def download_install_file(self, url, destination):
|
||||
def download_install_file(self, url: str, destination: str) -> bool:
|
||||
dialog = DownloadDialog(url, destination, parent=self)
|
||||
dialog.run()
|
||||
return dialog.downloader.state == Downloader.COMPLETED
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
# pylint: disable=no-member
|
||||
import os
|
||||
from typing import Any, Callable, Dict, Iterable, List, Set
|
||||
from typing import Any, Callable, Dict, Iterable, List, Optional, Set
|
||||
|
||||
from gi.repository import GObject, Gtk
|
||||
from gi.repository import GObject, Gtk # type: ignore
|
||||
|
||||
from lutris.gui.widgets.gi_composites import GtkTemplate
|
||||
from lutris.gui.widgets.progress_box import ProgressBox
|
||||
@@ -22,7 +22,7 @@ class DownloadQueue(Gtk.ScrolledWindow):
|
||||
|
||||
__gtype_name__ = "DownloadQueue"
|
||||
|
||||
download_box: Gtk.Box = GtkTemplate.Child()
|
||||
download_box: Gtk.Box = GtkTemplate.Child() # type: ignore
|
||||
|
||||
CompletionFunction = Callable[[Any], None]
|
||||
ErrorFunction = Callable[[Exception], None]
|
||||
@@ -99,9 +99,9 @@ class DownloadQueue(Gtk.ScrolledWindow):
|
||||
self,
|
||||
operation: Callable[[], Any],
|
||||
progress_function: ProgressBox.ProgressFunction,
|
||||
completion_function: CompletionFunction = None,
|
||||
error_function: ErrorFunction = None,
|
||||
operation_name: str = None,
|
||||
completion_function: Optional[CompletionFunction] = None,
|
||||
error_function: Optional[ErrorFunction] = None,
|
||||
operation_name: Optional[str] = None,
|
||||
) -> bool:
|
||||
"""Runs 'operation' on a thread, while displaying a progress bar. The 'progress_function'
|
||||
controls this progress bar, and it is removed when the 'operation' completes.
|
||||
@@ -129,9 +129,9 @@ class DownloadQueue(Gtk.ScrolledWindow):
|
||||
self,
|
||||
operation: Callable[[], Any],
|
||||
progress_functions: Iterable[ProgressBox.ProgressFunction],
|
||||
completion_function: CompletionFunction = None,
|
||||
error_function: ErrorFunction = None,
|
||||
operation_names: List[str] = None,
|
||||
completion_function: Optional[CompletionFunction] = None,
|
||||
error_function: Optional[ErrorFunction] = None,
|
||||
operation_names: Optional[List[str]] = None,
|
||||
) -> bool:
|
||||
"""Runs 'operation' on a thread, while displaying a set of progress bars. The
|
||||
'progress_functions' control these progress bars, and they are removed when the
|
||||
@@ -152,6 +152,8 @@ class DownloadQueue(Gtk.ScrolledWindow):
|
||||
if not self.running_operation_names.isdisjoint(operation_names):
|
||||
return False
|
||||
self.running_operation_names.update(operation_names)
|
||||
else:
|
||||
operation_names = []
|
||||
|
||||
# Must capture the functions, since in earlier (<3.8) Pythons functions do not provide
|
||||
# value equality, so we need to make sure we're always using what we started with.
|
||||
|
||||
@@ -96,7 +96,7 @@ class LutrisWindow(Gtk.ApplicationWindow, DialogLaunchUIDelegate, DialogInstallU
|
||||
version_notification_label: Gtk.Revealer = GtkTemplate.Child()
|
||||
show_hidden_games_button: Gtk.ModelButton = GtkTemplate.Child()
|
||||
|
||||
def __init__(self, application, **kwargs) -> None:
|
||||
def __init__(self, application=None, **kwargs) -> None:
|
||||
width = int(settings.read_setting("width") or self.default_width)
|
||||
height = int(settings.read_setting("height") or self.default_height)
|
||||
super().__init__(
|
||||
@@ -150,7 +150,7 @@ class LutrisWindow(Gtk.ApplicationWindow, DialogLaunchUIDelegate, DialogInstallU
|
||||
# Since system-search-symbolic is already *right there* we'll try to pick some
|
||||
# other icon for the button that shows the search popover.
|
||||
fallback_filter_icons_names = ["filter-symbolic", "edit-find-replace-symbolic", "system-search-symbolic"]
|
||||
filter_button_image = self.search_filters_button.get_child()
|
||||
filter_button_image: Gtk.Image = self.search_filters_button.get_child()
|
||||
for n in fallback_filter_icons_names:
|
||||
if has_stock_icon(n):
|
||||
filter_button_image.set_from_icon_name(n, Gtk.IconSize.BUTTON)
|
||||
|
||||
@@ -27,15 +27,12 @@ See: https://gitlab.gnome.org/GNOME/pygobject/merge_requests/52
|
||||
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
|
||||
# USA
|
||||
|
||||
# Standard Library
|
||||
import inspect
|
||||
import os
|
||||
import warnings
|
||||
from os.path import abspath, join
|
||||
|
||||
# Third Party Libraries
|
||||
from gi.repository import Gio, GLib, GObject, Gtk
|
||||
from gi.repository import Gio, GLib, GObject, Gtk # type: ignore
|
||||
|
||||
# Lutris Modules
|
||||
from lutris.gui.dialogs import ErrorDialog
|
||||
|
||||
__all__ = ["GtkTemplate"]
|
||||
@@ -58,12 +55,13 @@ def _connect_func(builder, obj, signal_name, handler_name, connect_object, flags
|
||||
template_inst = builder.get_object(cls.__gtype_name__)
|
||||
|
||||
if template_inst is None: # This should never happen
|
||||
errmsg = (
|
||||
warnings.warn(
|
||||
"Internal error: cannot find template instance! obj: %s; "
|
||||
"signal: %s; handler: %s; connect_obj: %s; class: %s"
|
||||
% (obj, signal_name, handler_name, connect_object, cls)
|
||||
% (obj, signal_name, handler_name, connect_object, cls),
|
||||
GtkTemplateWarning,
|
||||
stacklevel=2,
|
||||
)
|
||||
warnings.warn(errmsg, GtkTemplateWarning)
|
||||
return
|
||||
|
||||
handler = getattr(template_inst, handler_name)
|
||||
@@ -145,8 +143,11 @@ def _init_template(self, cls, base_init_template):
|
||||
)
|
||||
|
||||
for name in self.__gtemplate_methods__.difference(connected_signals):
|
||||
errmsg = ("Signal '%s' was declared with @GtkTemplate.Callback " + "but was not present in template") % name
|
||||
warnings.warn(errmsg, GtkTemplateWarning)
|
||||
warnings.warn(
|
||||
"Signal '%s' was declared with @GtkTemplate.Callback but was not present in template" % name,
|
||||
GtkTemplateWarning,
|
||||
stacklevel=2,
|
||||
)
|
||||
|
||||
|
||||
# TODO: Make it easier for IDE to introspect this
|
||||
@@ -242,7 +243,7 @@ class _GtkTemplate:
|
||||
TODO: Alternatively, could wait until first class instantiation
|
||||
before registering templates? Would need a metaclass...
|
||||
"""
|
||||
_GtkTemplate.__ui_path__ = abspath(join(*path)) # pylint: disable=no-value-for-parameter
|
||||
_GtkTemplate.__ui_path__ = os.path.abspath(os.path.join(*path))
|
||||
|
||||
def __init__(self, ui):
|
||||
self.ui = ui
|
||||
@@ -260,13 +261,13 @@ class _GtkTemplate:
|
||||
|
||||
try:
|
||||
template_bytes = Gio.resources_lookup_data(self.ui, Gio.ResourceLookupFlags.NONE)
|
||||
except GLib.GError:
|
||||
except GLib.GError: # type: ignore
|
||||
ui = self.ui
|
||||
if isinstance(ui, (list, tuple)):
|
||||
ui = join(ui)
|
||||
ui = " ".join(ui)
|
||||
|
||||
if _GtkTemplate.__ui_path__ is not None:
|
||||
ui = join(_GtkTemplate.__ui_path__, ui)
|
||||
ui = os.path.join(_GtkTemplate.__ui_path__, ui)
|
||||
|
||||
with open(ui, "rb") as fp:
|
||||
template_bytes = GLib.Bytes.new(fp.read())
|
||||
|
||||
@@ -4,8 +4,10 @@
|
||||
import os
|
||||
import shlex
|
||||
import time
|
||||
from typing import Dict, Optional, Tuple
|
||||
|
||||
from lutris import runtime, settings
|
||||
from lutris.config import LutrisConfig
|
||||
from lutris.monitored_command import MonitoredCommand
|
||||
from lutris.runners import import_runner
|
||||
from lutris.util import linux, system
|
||||
@@ -63,7 +65,7 @@ def set_regedit_file(filename, wine_path=None, prefix=None, arch=WINE_DEFAULT_AR
|
||||
# a bug in Wine. see: https://github.com/lutris/lutris/issues/804
|
||||
wine_path = wine_path + "64"
|
||||
|
||||
if proton.is_proton_path(wine_path):
|
||||
if not wine_path or proton.is_proton_path(wine_path):
|
||||
proton_verb = "run"
|
||||
|
||||
wineexec(
|
||||
@@ -80,7 +82,7 @@ def set_regedit_file(filename, wine_path=None, prefix=None, arch=WINE_DEFAULT_AR
|
||||
def delete_registry_key(key, wine_path=None, prefix=None, arch=WINE_DEFAULT_ARCH, proton_verb=None):
|
||||
"""Deletes a registry key from a Wine prefix"""
|
||||
|
||||
if proton.is_proton_path(wine_path):
|
||||
if not wine_path or proton.is_proton_path(wine_path):
|
||||
proton_verb = "run"
|
||||
|
||||
wineexec(
|
||||
@@ -98,7 +100,6 @@ def create_prefix(
|
||||
prefix, wine_path=None, arch=WINE_DEFAULT_ARCH, overrides=None, install_gecko=None, install_mono=None, runner=None
|
||||
):
|
||||
"""Create a new Wine prefix."""
|
||||
# pylint: disable=too-many-locals
|
||||
if overrides is None:
|
||||
overrides = {}
|
||||
if not prefix:
|
||||
@@ -175,17 +176,21 @@ def create_prefix(
|
||||
prefix_manager.setup_defaults()
|
||||
|
||||
|
||||
def winekill(prefix, arch=WINE_DEFAULT_ARCH, wine_path=None, env=None, initial_pids=None, runner=None):
|
||||
def winekill(prefix, arch=WINE_DEFAULT_ARCH, wine_path="", env=None, initial_pids=None, runner=None):
|
||||
"""Kill processes in Wine prefix."""
|
||||
|
||||
initial_pids = initial_pids or []
|
||||
if not env:
|
||||
env = {"WINEARCH": arch, "WINEPREFIX": prefix}
|
||||
if proton.is_proton_path(wine_path):
|
||||
env = {
|
||||
"WINEARCH": arch,
|
||||
"WINEPREFIX": prefix,
|
||||
"GAMEID": proton.DEFAULT_GAMEID,
|
||||
"PROTON_VERB": "runinprefix",
|
||||
}
|
||||
if proton.is_umu_path(wine_path):
|
||||
command = [wine_path, "wineboot", "-k"]
|
||||
elif proton.is_proton_path(wine_path):
|
||||
command = [proton.get_umu_path(), "wineboot", "-k"]
|
||||
env["GAMEID"] = proton.DEFAULT_GAMEID
|
||||
env["WINEPREFIX"] = prefix
|
||||
env["PROTON_VERB"] = "runinprefix"
|
||||
env["PROTONPATH"] = proton.get_proton_path_by_path(wine_path)
|
||||
else:
|
||||
if not wine_path:
|
||||
@@ -232,33 +237,32 @@ def use_lutris_runtime(wine_path, force_disable=False):
|
||||
return True
|
||||
|
||||
|
||||
# pragma pylint: disable=too-many-locals
|
||||
def wineexec(
|
||||
executable,
|
||||
args="",
|
||||
wine_path=None,
|
||||
prefix=None,
|
||||
arch=None,
|
||||
working_dir=None,
|
||||
winetricks_wine="",
|
||||
blocking=False,
|
||||
config=None,
|
||||
include_processes=None,
|
||||
exclude_processes=None,
|
||||
disable_runtime=False,
|
||||
env=None,
|
||||
executable: str,
|
||||
prefix: str,
|
||||
args: str = "",
|
||||
wine_path: Optional[str] = None,
|
||||
arch: str = WINE_DEFAULT_ARCH,
|
||||
working_dir: Optional[str] = None,
|
||||
winetricks_wine: str = "",
|
||||
blocking: bool = False,
|
||||
config: Optional[LutrisConfig] = None,
|
||||
include_processes: Optional[list] = None,
|
||||
exclude_processes: Optional[list] = None,
|
||||
disable_runtime: bool = False,
|
||||
env: Optional[dict] = None,
|
||||
overrides=None,
|
||||
runner=None,
|
||||
proton_verb=None,
|
||||
proton_verb: Optional[str] = None,
|
||||
):
|
||||
"""
|
||||
Execute a Wine command.
|
||||
|
||||
Args:
|
||||
executable (str): wine program to run, pass None to run wine itself
|
||||
prefix (str): path to the wine prefix to use
|
||||
args (str): program arguments
|
||||
wine_path (str): path to the wine version to use
|
||||
prefix (str): path to the wine prefix to use
|
||||
arch (str): wine architecture of the prefix
|
||||
working_dir (str): path to the working dir for the process
|
||||
winetricks_wine (str): path to the wine version used by winetricks
|
||||
@@ -271,12 +275,9 @@ def wineexec(
|
||||
Process results if the process is running in blocking mode or
|
||||
MonitoredCommand instance otherwise.
|
||||
"""
|
||||
if env is None:
|
||||
env = {}
|
||||
if exclude_processes is None:
|
||||
exclude_processes = []
|
||||
if include_processes is None:
|
||||
include_processes = []
|
||||
env = env or {}
|
||||
exclude_processes = exclude_processes or []
|
||||
include_processes = include_processes or []
|
||||
executable = str(executable) if executable else ""
|
||||
if isinstance(include_processes, str):
|
||||
include_processes = shlex.split(include_processes)
|
||||
@@ -300,7 +301,7 @@ def wineexec(
|
||||
wineenv = {"WINEARCH": arch}
|
||||
if winetricks_wine and winetricks_wine is not wine_path and not proton.is_proton_path(wine_path):
|
||||
wineenv["WINE"] = winetricks_wine
|
||||
else:
|
||||
elif wine_path:
|
||||
wineenv["WINE"] = wine_path
|
||||
|
||||
if prefix:
|
||||
@@ -376,7 +377,9 @@ def wineexec(
|
||||
# pragma pylint: enable=too-many-locals
|
||||
|
||||
|
||||
def find_winetricks(env=None, system_winetricks=False):
|
||||
def find_winetricks(
|
||||
env: Optional[dict[str, str]] = None, system_winetricks=False
|
||||
) -> Tuple[str, Optional[str], Dict[str, str]]:
|
||||
"""Find winetricks path."""
|
||||
winetricks_path = os.path.join(settings.RUNTIME_DIR, "winetricks/winetricks")
|
||||
if system_winetricks or not system.path_exists(winetricks_path):
|
||||
@@ -388,9 +391,7 @@ def find_winetricks(env=None, system_winetricks=False):
|
||||
# working_dir, so it will find the data file.
|
||||
working_dir = os.path.join(settings.RUNTIME_DIR, "winetricks")
|
||||
|
||||
if not env:
|
||||
env = {}
|
||||
|
||||
env = env or {}
|
||||
path = env.get("PATH", os.environ["PATH"])
|
||||
env["PATH"] = "%s:%s" % (working_dir, path)
|
||||
|
||||
@@ -398,11 +399,11 @@ def find_winetricks(env=None, system_winetricks=False):
|
||||
|
||||
|
||||
def winetricks(
|
||||
app,
|
||||
prefix=None,
|
||||
arch=None,
|
||||
silent=True,
|
||||
wine_path=None,
|
||||
app: Optional[str],
|
||||
prefix: str,
|
||||
arch: str = WINE_DEFAULT_ARCH,
|
||||
silent: bool = True,
|
||||
wine_path: Optional[str] = None,
|
||||
config=None,
|
||||
env=None,
|
||||
disable_runtime=False,
|
||||
@@ -411,39 +412,39 @@ def winetricks(
|
||||
proton_verb=None,
|
||||
):
|
||||
"""Execute winetricks."""
|
||||
winetricks_path, working_dir, env = find_winetricks(env, system_winetricks)
|
||||
if not app:
|
||||
silent = False
|
||||
app = "--gui"
|
||||
args = app
|
||||
if not wine_path or proton.is_umu_path(wine_path):
|
||||
winetricks_wine = proton.get_umu_path()
|
||||
proton_verb = "waitforexitandrun"
|
||||
|
||||
if wine_path:
|
||||
winetricks_wine = wine_path
|
||||
if proton.is_proton_path(wine_path):
|
||||
protonfixes_path = os.path.join(proton.get_proton_path_by_path(wine_path), "protonfixes")
|
||||
if os.path.exists(protonfixes_path):
|
||||
winetricks_wine = os.path.join(protonfixes_path, "winetricks")
|
||||
winetricks_path = wine_path
|
||||
if not app:
|
||||
silent = False
|
||||
app = "--gui"
|
||||
else:
|
||||
logger.info("winetricks: Valve official Proton builds do not support winetricks.")
|
||||
return
|
||||
elif proton.is_proton_path(wine_path):
|
||||
proton_verb = "waitforexitandrun"
|
||||
protonfixes_path = os.path.join(proton.get_proton_path_by_path(wine_path), "protonfixes")
|
||||
if os.path.exists(protonfixes_path):
|
||||
winetricks_wine = os.path.join(protonfixes_path, "winetricks")
|
||||
winetricks_path = wine_path
|
||||
if not app:
|
||||
silent = False
|
||||
app = "--gui"
|
||||
else:
|
||||
logger.error("winetricks: Valve official Proton builds do not support winetricks.")
|
||||
return
|
||||
else:
|
||||
winetricks_path, working_dir, env = find_winetricks(env, system_winetricks)
|
||||
if not runner:
|
||||
runner = import_runner("wine")()
|
||||
winetricks_wine = runner.get_executable()
|
||||
|
||||
if arch not in ("win32", "win64"):
|
||||
arch = detect_arch(prefix, winetricks_wine)
|
||||
args = app
|
||||
|
||||
if str(silent).lower() in ("yes", "on", "true") and not proton.is_proton_path(wine_path):
|
||||
args = "-q " + args
|
||||
else:
|
||||
if proton.is_proton_path(wine_path):
|
||||
proton_verb = "waitforexitandrun"
|
||||
if arch not in ("win32", "win64"):
|
||||
arch = detect_arch(prefix, winetricks_wine)
|
||||
if str(silent).lower() in ("yes", "on", "true"):
|
||||
args = "-q " + args
|
||||
|
||||
# Execute wineexec
|
||||
return wineexec(
|
||||
None,
|
||||
"",
|
||||
prefix=prefix,
|
||||
winetricks_wine=winetricks_wine,
|
||||
wine_path=winetricks_path,
|
||||
@@ -483,7 +484,7 @@ def winecfg(wine_path=None, prefix=None, arch=WINE_DEFAULT_ARCH, config=None, en
|
||||
)
|
||||
|
||||
|
||||
def eject_disc(wine_path, prefix, proton_verb=None):
|
||||
def eject_disc(wine_path: str, prefix: str, proton_verb=None):
|
||||
"""Use Wine to eject a drive"""
|
||||
|
||||
if proton.is_proton_path(wine_path):
|
||||
@@ -491,7 +492,7 @@ def eject_disc(wine_path, prefix, proton_verb=None):
|
||||
wineexec("eject", prefix=prefix, wine_path=wine_path, args="-a", proton_verb=proton_verb)
|
||||
|
||||
|
||||
def install_cab_component(cabfile, component, wine_path=None, prefix=None, arch=None, proton_verb=None):
|
||||
def install_cab_component(cabfile, component, wine_path: str, prefix=None, arch=None, proton_verb=None):
|
||||
"""Install a component from a cabfile in a prefix"""
|
||||
|
||||
if proton.is_proton_path(wine_path):
|
||||
@@ -504,7 +505,9 @@ def install_cab_component(cabfile, component, wine_path=None, prefix=None, arch=
|
||||
cab_installer.cleanup()
|
||||
|
||||
|
||||
def open_wine_terminal(terminal, wine_path, prefix, env, system_winetricks):
|
||||
def open_wine_terminal(
|
||||
terminal: Optional[str], wine_path: str, prefix: str, env: Optional[Dict[str, str]], system_winetricks: bool
|
||||
):
|
||||
winetricks_path, _working_dir, env = find_winetricks(env, system_winetricks)
|
||||
path_paths = [os.path.dirname(wine_path)]
|
||||
if proton.is_proton_path(wine_path):
|
||||
|
||||
@@ -913,7 +913,7 @@ class wine(Runner):
|
||||
|
||||
def run_wine_terminal(self, *args):
|
||||
terminal = self.system_config.get("terminal_app")
|
||||
system_winetricks = self.runner_config.get("system_winetricks")
|
||||
system_winetricks: bool = self.runner_config.get("system_winetricks", False)
|
||||
open_wine_terminal(
|
||||
terminal=terminal,
|
||||
wine_path=self.get_executable(),
|
||||
@@ -1213,10 +1213,10 @@ class wine(Runner):
|
||||
except Exception as ex:
|
||||
logger.exception("Failed to setup desktop integration, the prefix may not be valid: %s", ex)
|
||||
|
||||
def play(self): # pylint: disable=too-many-return-statements # noqa: C901
|
||||
def play(self): # pylint: disable=too-many-return-statements
|
||||
game_exe = self.game_exe
|
||||
arguments = self.game_config.get("args", "")
|
||||
launch_info = {"env": self.get_env(os_env=False)}
|
||||
arguments: str = self.game_config.get("args", "")
|
||||
launch_info: dict = {"env": self.get_env(os_env=False)}
|
||||
using_dxvk = self.runner_config.get("dxvk") and LINUX_SYSTEM.is_vulkan_supported
|
||||
|
||||
if using_dxvk:
|
||||
|
||||
@@ -160,7 +160,10 @@ class SteamID:
|
||||
match = COMMUNITY32_REGEX.match(url.path)
|
||||
if match:
|
||||
if match.group("path") not in TYPE_URL_PATH_MAP[LETTER_TYPE_MAP[match.group("type")]]:
|
||||
warnings.warn("Community URL ({}) path doesn't match type character".format(url.path))
|
||||
warnings.warn(
|
||||
"Community URL ({}) path doesn't match type character".format(url.path),
|
||||
stacklevel=2,
|
||||
)
|
||||
steamid = int(match.group("steamid"))
|
||||
instance = steamid & 1
|
||||
account_number = (steamid - instance) / 2
|
||||
|
||||
@@ -13,7 +13,7 @@ from gettext import gettext as _
|
||||
from pathlib import Path
|
||||
from typing import Dict, List, Optional, Tuple
|
||||
|
||||
from gi.repository import Gio, GLib
|
||||
from gi.repository import Gio, GLib # type: ignore
|
||||
|
||||
from lutris import settings
|
||||
from lutris.exceptions import MissingExecutableError
|
||||
@@ -41,11 +41,11 @@ def get_environment():
|
||||
|
||||
def execute(
|
||||
command: List[str],
|
||||
env: Dict[str, str] = None,
|
||||
cwd: str = None,
|
||||
env: Optional[Dict[str, str]] = None,
|
||||
cwd: Optional[str] = None,
|
||||
quiet: bool = False,
|
||||
shell: bool = False,
|
||||
timeout: float = None,
|
||||
timeout: Optional[float] = None,
|
||||
) -> str:
|
||||
"""
|
||||
Execute a system command and return its standard output; standard error is discarded.
|
||||
@@ -66,11 +66,11 @@ def execute(
|
||||
|
||||
def execute_with_error(
|
||||
command: List[str],
|
||||
env: Dict[str, str] = None,
|
||||
cwd: str = None,
|
||||
env: Optional[Dict[str, str]] = None,
|
||||
cwd: Optional[str] = None,
|
||||
quiet: bool = False,
|
||||
shell: bool = False,
|
||||
timeout: float = None,
|
||||
timeout: Optional[float] = None,
|
||||
) -> Tuple[str, str]:
|
||||
"""
|
||||
Execute a system command and return its standard output and; standard error in a tuple.
|
||||
@@ -90,12 +90,12 @@ def execute_with_error(
|
||||
|
||||
def _execute(
|
||||
command: List[str],
|
||||
env: Dict[str, str] = None,
|
||||
cwd: str = None,
|
||||
env: Optional[Dict[str, str]] = None,
|
||||
cwd: Optional[str] = None,
|
||||
capture_stderr: bool = False,
|
||||
quiet: bool = False,
|
||||
shell: bool = False,
|
||||
timeout: float = None,
|
||||
timeout: Optional[float] = None,
|
||||
) -> Tuple[str, str]:
|
||||
# Check if the executable exists
|
||||
if not command:
|
||||
@@ -292,11 +292,8 @@ def kill_pid(pid):
|
||||
logger.error("Could not kill process %s", pid)
|
||||
|
||||
|
||||
def python_identifier(unsafe_string):
|
||||
def python_identifier(unsafe_string: str):
|
||||
"""Converts a string to something that can be used as a python variable"""
|
||||
if not isinstance(unsafe_string, str):
|
||||
logger.error("Cannot convert %s to a python identifier", type(unsafe_string))
|
||||
return
|
||||
|
||||
def _dashrepl(matchobj):
|
||||
return matchobj.group(0).replace("-", "_")
|
||||
@@ -304,7 +301,7 @@ def python_identifier(unsafe_string):
|
||||
return re.sub(r"(\${)([\w-]*)(})", _dashrepl, unsafe_string)
|
||||
|
||||
|
||||
def substitute(string_template, variables):
|
||||
def substitute(string_template: str, variables):
|
||||
"""Expand variables on a string template
|
||||
|
||||
Args:
|
||||
@@ -355,8 +352,8 @@ def merge_folders(source, destination):
|
||||
|
||||
def remove_folder(
|
||||
path: str,
|
||||
completion_function: TrashPortal.CompletionFunction = None,
|
||||
error_function: TrashPortal.ErrorFunction = None,
|
||||
completion_function: Optional[TrashPortal.CompletionFunction] = None,
|
||||
error_function: Optional[TrashPortal.ErrorFunction] = None,
|
||||
) -> None:
|
||||
"""Trashes a folder specified by path, asynchronously. The folder
|
||||
likely exists after this returns, since it's using DBus to ask
|
||||
|
||||
@@ -34,7 +34,7 @@ except Exception as ex:
|
||||
logger.exception("Unable to enumerate system Wine versions: %s", ex)
|
||||
|
||||
|
||||
def detect_arch(prefix_path: str = "", wine_path: str = "") -> str:
|
||||
def detect_arch(prefix_path: Optional[str] = None, wine_path: Optional[str] = None) -> str:
|
||||
"""Given a Wine prefix path, return its architecture"""
|
||||
if wine_path:
|
||||
if proton.is_proton_path(wine_path) or system.path_exists(wine_path + "64"):
|
||||
@@ -237,7 +237,7 @@ def get_system_wine_version(wine_path: str = "wine") -> str:
|
||||
return version
|
||||
|
||||
|
||||
def get_real_executable(windows_executable: str, working_dir: str) -> Tuple[str, List[str], str]:
|
||||
def get_real_executable(windows_executable: str, working_dir: Optional[str]) -> Tuple[str, List[str], Optional[str]]:
|
||||
"""Given a Windows executable, return the real program
|
||||
capable of launching it along with necessary arguments."""
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
[tool.mypy]
|
||||
python_version = "3.8"
|
||||
python_version = "3.12"
|
||||
packages = [
|
||||
"lutris",
|
||||
"tests",
|
||||
@@ -18,7 +18,6 @@ disable_error_code = [
|
||||
allow_redefinition = true
|
||||
follow_imports = "silent"
|
||||
ignore_missing_imports = true
|
||||
implicit_optional = true
|
||||
|
||||
[tool.mypy-baseline]
|
||||
# --baseline-path: the file where the baseline should be stored
|
||||
|
||||
@@ -5,7 +5,6 @@ select = ["A", "ARG", "B", "E", "F", "I", "W", "PERF", "RUF"]
|
||||
ignore = [
|
||||
# Ignores that is not worth/too hard to fix
|
||||
"RUF001", # String contains ambiguous `!` (FULLWIDTH EXCLAMATION MARK). Did you mean `!` (EXCLAMATION MARK)? - used ,mostly on tests
|
||||
"B028", # No explicit `stacklevel` keyword argument found - not sure why this is needed
|
||||
"E402", # Module level import not at top of file - gtk stuff
|
||||
|
||||
# Ignores that should be fixed and removed
|
||||
|
||||
Reference in New Issue
Block a user