From 7ee008e150bc5bcf76082d726f719ee0fdfda982 Mon Sep 17 00:00:00 2001 From: SulfurNitride Date: Wed, 11 Feb 2026 02:37:39 -0600 Subject: Fluorine Manager: full Linux port of Mod Organizer 2 Complete native Linux port with FUSE-based virtual filesystem, Proton/umu-run integration, and Flatpak packaging. Key features: - FUSE VFS replacing Windows USVFS (in-process + standalone helper for Flatpak) - Proton/GE-Proton/umu-run launcher with env var forwarding - Flatpak support (sandbox-aware VFS, NXM handler, umu-run) - Wine prefix management UI - Case-insensitive path resolution for Linux filesystems - QSettings-safe INI handling (avoids Bethesda INI corruption) - Portable instance support with auto-generated launcher scripts Co-Authored-By: Claude Opus 4.6 --- libs/plugin_python/typings/generate.py | 38 +++++++ .../typings/mobase_tests/argument_wrapper.pyi | 27 +++++ .../typings/mobase_tests/filetree.pyi | 9 ++ .../typings/mobase_tests/functional.pyi | 19 ++++ .../typings/mobase_tests/guessed_string.pyi | 16 +++ .../typings/mobase_tests/organizer.pyi | 7 ++ libs/plugin_python/typings/mobase_tests/qt.pyi | 109 +++++++++++++++++++++ .../typings/mobase_tests/qt_widgets.pyi | 34 +++++++ .../typings/mobase_tests/shared_cpp_owner.pyi | 22 +++++ 9 files changed, 281 insertions(+) create mode 100644 libs/plugin_python/typings/generate.py create mode 100644 libs/plugin_python/typings/mobase_tests/argument_wrapper.pyi create mode 100644 libs/plugin_python/typings/mobase_tests/filetree.pyi create mode 100644 libs/plugin_python/typings/mobase_tests/functional.pyi create mode 100644 libs/plugin_python/typings/mobase_tests/guessed_string.pyi create mode 100644 libs/plugin_python/typings/mobase_tests/organizer.pyi create mode 100644 libs/plugin_python/typings/mobase_tests/qt.pyi create mode 100644 libs/plugin_python/typings/mobase_tests/qt_widgets.pyi create mode 100644 libs/plugin_python/typings/mobase_tests/shared_cpp_owner.pyi (limited to 'libs/plugin_python/typings') diff --git a/libs/plugin_python/typings/generate.py b/libs/plugin_python/typings/generate.py new file mode 100644 index 0000000..1983186 --- /dev/null +++ b/libs/plugin_python/typings/generate.py @@ -0,0 +1,38 @@ +import os +import site +import sys +from pathlib import Path +from typing import cast + +import pybind11_stubgen as py11stubs + +typings_dir = Path(__file__).parent +mobase_tests_dir = Path(__file__).parent.parent.joinpath( + "vsbuild", "tests", "python", "pylibs", "mobase_tests" +) + +site.addsitedir(str(mobase_tests_dir.parent)) + +os.add_dll_directory(str(Path(cast(str, os.getenv("QT_ROOT"))).joinpath("bin"))) +os.add_dll_directory(str(os.getenv("UIBASE_PATH"))) + +from PyQt6.QtWidgets import QApplication # noqa: E402 + +app = QApplication(sys.argv) + +args = py11stubs.arg_parser().parse_args(["dummy"], namespace=py11stubs.CLIArgs()) + +parser = py11stubs.stub_parser_from_args(args) +printer = py11stubs.Printer(invalid_expr_as_ellipses=True) # type: ignore + +for path in mobase_tests_dir.glob("*.pyd"): + name = path.name.split(".")[0] + py11stubs.run( + parser, + printer, + f"mobase_tests.{name}", + typings_dir.joinpath("mobase_tests"), + sub_dir=None, + dry_run=False, + writer=py11stubs.Writer(stub_ext="pyi"), # type: ignore + ) diff --git a/libs/plugin_python/typings/mobase_tests/argument_wrapper.pyi b/libs/plugin_python/typings/mobase_tests/argument_wrapper.pyi new file mode 100644 index 0000000..a96e49a --- /dev/null +++ b/libs/plugin_python/typings/mobase_tests/argument_wrapper.pyi @@ -0,0 +1,27 @@ +from __future__ import annotations + +__all__ = [ + "fn1_raw", + "fn1_wrap", + "fn1_wrap_0", + "fn2_raw", + "fn2_wrap", + "fn2_wrap_0", + "fn3_raw", + "fn3_wrap", + "fn3_wrap_0", + "fn3_wrap_0_2", + "fn3_wrap_2", +] + +def fn1_raw(arg0: str) -> str: ... +def fn1_wrap(arg0: int | str) -> str: ... +def fn1_wrap_0(arg0: int | str) -> str: ... +def fn2_raw(arg0: int) -> int: ... +def fn2_wrap(arg0: int | str) -> int: ... +def fn2_wrap_0(arg0: int | str) -> int: ... +def fn3_raw(arg0: int, arg1: list[int], arg2: str) -> str: ... +def fn3_wrap(arg0: int | str, arg1: list[int], arg2: int | str) -> str: ... +def fn3_wrap_0(arg0: int | str, arg1: list[int], arg2: str) -> str: ... +def fn3_wrap_0_2(arg0: int | str, arg1: list[int], arg2: int | str) -> str: ... +def fn3_wrap_2(arg0: int, arg1: list[int], arg2: int | str) -> str: ... diff --git a/libs/plugin_python/typings/mobase_tests/filetree.pyi b/libs/plugin_python/typings/mobase_tests/filetree.pyi new file mode 100644 index 0000000..93eab63 --- /dev/null +++ b/libs/plugin_python/typings/mobase_tests/filetree.pyi @@ -0,0 +1,9 @@ +from __future__ import annotations + +import mobase + +__all__ = ["is_directory", "is_file", "value"] + +def is_directory(arg0: mobase.IFileTree.FileTypes) -> bool: ... +def is_file(arg0: mobase.IFileTree.FileTypes) -> bool: ... +def value(arg0: mobase.IFileTree.FileTypes) -> int: ... diff --git a/libs/plugin_python/typings/mobase_tests/functional.pyi b/libs/plugin_python/typings/mobase_tests/functional.pyi new file mode 100644 index 0000000..7e58f0e --- /dev/null +++ b/libs/plugin_python/typings/mobase_tests/functional.pyi @@ -0,0 +1,19 @@ +from __future__ import annotations + +import typing + +__all__ = ["fn_0_arg", "fn_0_or_1_arg", "fn_1_arg", "fn_1_or_2_or_3_arg", "fn_2_arg"] + +def fn_0_arg(arg0: typing.Callable[[], int]) -> int: ... +@typing.overload +def fn_0_or_1_arg(arg0: typing.Callable[[], int]) -> int: ... +@typing.overload +def fn_0_or_1_arg(arg0: typing.Callable[[int], int]) -> int: ... +def fn_1_arg(arg0: typing.Callable[[int], int], arg1: int) -> int: ... +@typing.overload +def fn_1_or_2_or_3_arg(arg0: typing.Callable[[int], int]) -> int: ... +@typing.overload +def fn_1_or_2_or_3_arg(arg0: typing.Callable[[int, int], int]) -> int: ... +@typing.overload +def fn_1_or_2_or_3_arg(arg0: typing.Callable[[int, int, int], int]) -> int: ... +def fn_2_arg(arg0: typing.Callable[[int, int], int], arg1: int, arg2: int) -> int: ... diff --git a/libs/plugin_python/typings/mobase_tests/guessed_string.pyi b/libs/plugin_python/typings/mobase_tests/guessed_string.pyi new file mode 100644 index 0000000..a03d9b6 --- /dev/null +++ b/libs/plugin_python/typings/mobase_tests/guessed_string.pyi @@ -0,0 +1,16 @@ +from __future__ import annotations + +import typing + +import mobase + +__all__ = ["get_from_callback", "get_value", "get_variants", "set_from_callback"] + +def get_from_callback( + arg0: typing.Callable[[mobase.GuessedString], None], +) -> str: ... +def get_value(arg0: str | mobase.GuessedString) -> str: ... +def get_variants(arg0: str | mobase.GuessedString) -> set[str]: ... +def set_from_callback( + arg0: mobase.GuessedString, arg1: typing.Callable[[mobase.GuessedString], None] +) -> None: ... diff --git a/libs/plugin_python/typings/mobase_tests/organizer.pyi b/libs/plugin_python/typings/mobase_tests/organizer.pyi new file mode 100644 index 0000000..dd5136a --- /dev/null +++ b/libs/plugin_python/typings/mobase_tests/organizer.pyi @@ -0,0 +1,7 @@ +from __future__ import annotations + +import mobase + +__all__ = ["organizer"] + +def organizer() -> mobase.IOrganizer: ... diff --git a/libs/plugin_python/typings/mobase_tests/qt.pyi b/libs/plugin_python/typings/mobase_tests/qt.pyi new file mode 100644 index 0000000..088ef2a --- /dev/null +++ b/libs/plugin_python/typings/mobase_tests/qt.pyi @@ -0,0 +1,109 @@ +from __future__ import annotations + +import typing + +import PyQt6.QtCore + +from mobase import MoVariant + +__all__ = [ + "SimpleEnum", + "consume_qstring_with_emoji", + "create_qstring_with_emoji", + "datetime_from_string", + "datetime_to_string", + "int_to_qstring", + "qflags_create", + "qflags_explode", + "qmap_to_length", + "qstring_to_int", + "qstring_to_stdstring", + "qstringlist_at", + "qstringlist_join", + "qvariant_bool", + "qvariant_from_bool", + "qvariant_from_int", + "qvariant_from_list", + "qvariant_from_map", + "qvariant_from_none", + "qvariant_from_str", + "qvariant_int", + "qvariant_list", + "qvariant_map", + "qvariant_none", + "qvariant_str", + "stdstring_to_qstring", +] + +class SimpleEnum: + """ + Members: + + Value0 + + Value1 + + Value2 + """ + + Value0: typing.ClassVar[SimpleEnum] # value = + Value1: typing.ClassVar[SimpleEnum] # value = + Value2: typing.ClassVar[SimpleEnum] # value = + __members__: typing.ClassVar[ + dict[str, SimpleEnum] + ] # value = {'Value0': , 'Value1': , 'Value2': } + def __and__(self, other: typing.Any) -> typing.Any: ... + def __eq__(self, other: typing.Any) -> bool: ... + def __ge__(self, other: typing.Any) -> bool: ... + def __getstate__(self) -> int: ... + def __gt__(self, other: typing.Any) -> bool: ... + def __hash__(self) -> int: ... + def __index__(self) -> int: ... + def __init__(self, value: int) -> None: ... + def __int__(self) -> int: ... + def __invert__(self) -> typing.Any: ... + def __le__(self, other: typing.Any) -> bool: ... + def __lt__(self, other: typing.Any) -> bool: ... + def __ne__(self, other: typing.Any) -> bool: ... + def __or__(self, other: typing.Any) -> typing.Any: ... + def __rand__(self, other: typing.Any) -> typing.Any: ... + def __repr__(self) -> str: ... + def __ror__(self, other: typing.Any) -> typing.Any: ... + def __rxor__(self, other: typing.Any) -> typing.Any: ... + def __setstate__(self, state: int) -> None: ... + def __str__(self) -> str: ... + def __xor__(self, other: typing.Any) -> typing.Any: ... + @property + def name(self) -> str: ... + @property + def value(self) -> int: ... + +def consume_qstring_with_emoji(arg0: str) -> int: ... +def create_qstring_with_emoji() -> str: ... +def datetime_from_string( + string: str, format: PyQt6.QtCore.Qt.DateFormat = ... +) -> PyQt6.QtCore.QDateTime: ... +def datetime_to_string( + datetime: PyQt6.QtCore.QDateTime, format: PyQt6.QtCore.Qt.DateFormat = ... +) -> str: ... +def int_to_qstring(arg0: int) -> str: ... +def qflags_create(arg0: bool, arg1: bool, arg2: bool) -> int: ... +def qflags_explode(arg0: int) -> tuple[int, bool, bool, bool]: ... +def qmap_to_length(arg0: dict[str, str]) -> dict[str, int]: ... +def qstring_to_int(arg0: str) -> int: ... +def qstring_to_stdstring(arg0: str) -> str: ... +def qstringlist_at(arg0: typing.Sequence[str], arg1: int) -> str: ... +def qstringlist_join(arg0: typing.Sequence[str], arg1: str) -> str: ... +def qvariant_bool() -> MoVariant: ... +def qvariant_from_bool(arg0: MoVariant) -> tuple[bool, bool]: ... +def qvariant_from_int(arg0: MoVariant) -> tuple[bool, int]: ... +def qvariant_from_list(arg0: MoVariant) -> tuple[bool, typing.Sequence[MoVariant]]: ... +def qvariant_from_map(arg0: MoVariant) -> tuple[bool, dict[str, MoVariant]]: ... +def qvariant_from_none(arg0: MoVariant) -> tuple[bool, bool]: ... +def qvariant_from_str(arg0: MoVariant) -> tuple[bool, str]: ... +def qvariant_int() -> MoVariant: ... +def qvariant_list() -> MoVariant: ... +def qvariant_map() -> dict[str, MoVariant]: ... +def qvariant_none() -> MoVariant: ... +def qvariant_str() -> MoVariant: ... +def stdstring_to_qstring(arg0: str) -> str: ... diff --git a/libs/plugin_python/typings/mobase_tests/qt_widgets.pyi b/libs/plugin_python/typings/mobase_tests/qt_widgets.pyi new file mode 100644 index 0000000..dfda4f9 --- /dev/null +++ b/libs/plugin_python/typings/mobase_tests/qt_widgets.pyi @@ -0,0 +1,34 @@ +from __future__ import annotations + +import typing + +import PyQt6.QtWidgets + +__all__ = [ + "CustomWidget", + "get", + "heightForWidth", + "is_alive", + "is_owned_cpp", + "make_widget_own_cpp", + "make_widget_own_py", + "send_to_cpp", + "set_parent", +] + +class CustomWidget: + def __getattr__(self, arg0: str) -> typing.Any: ... + def __init__( + self, name: str, parent: PyQt6.QtWidgets.QWidget | None = None + ) -> None: ... + def _widget(self) -> PyQt6.QtWidgets.QWidget: ... + def set_parent_cpp(self) -> None: ... + +def get(arg0: str) -> PyQt6.QtWidgets.QWidget: ... +def heightForWidth(arg0: str, arg1: int) -> int: ... +def is_alive(arg0: str) -> bool: ... +def is_owned_cpp(arg0: str) -> bool: ... +def make_widget_own_cpp(arg0: str) -> PyQt6.QtWidgets.QWidget: ... +def make_widget_own_py(arg0: str) -> PyQt6.QtWidgets.QWidget: ... +def send_to_cpp(arg0: str, arg1: PyQt6.QtWidgets.QWidget) -> None: ... +def set_parent(arg0: PyQt6.QtWidgets.QWidget) -> None: ... diff --git a/libs/plugin_python/typings/mobase_tests/shared_cpp_owner.pyi b/libs/plugin_python/typings/mobase_tests/shared_cpp_owner.pyi new file mode 100644 index 0000000..789632e --- /dev/null +++ b/libs/plugin_python/typings/mobase_tests/shared_cpp_owner.pyi @@ -0,0 +1,22 @@ +from __future__ import annotations + +__all__ = [ + "Base", + "call_fn", + "clear", + "create", + "create_and_store", + "is_alive", + "store", +] + +class Base: + def __init__(self, arg0: str) -> None: ... + def fn(self) -> str: ... + +def call_fn(arg0: str) -> str: ... +def clear() -> None: ... +def create(arg0: str) -> Base: ... +def create_and_store(arg0: str) -> Base: ... +def is_alive(arg0: str) -> bool: ... +def store(arg0: Base) -> None: ... -- cgit v1.3.1