Compare commits

..
4 Commits
18 changed files with 10665 additions and 1576 deletions
@@ -18,12 +18,13 @@ jobs:
python-version: 3.12
- uses: abatilo/actions-poetry@v2
- name: Install
run: |
poetry install
run: poetry install
- name: Install libgl1
run: sudo apt install -y libgl1 libegl1 libglib2.0-0 libxkbcommon0 libdbus-1-3
- name: Copy stubs
run: cp stubs/2.5.2/mobase-stubs/__init__.pyi docs/mobase.py
run: |
mkdir -p docs/src
cp -r stubs/2.5.2/mobase-stubs docs/src/mobase
- name: Build
run: poetry run sphinx-build -b html docs/source docs/build
env:
-1
View File
@@ -109,7 +109,6 @@ import mobase
import mobase.widgets
```
**Note:** Most classes in `mobase` cannot be instantiated, so this is mostly intended
for MO2 developers.
File diff suppressed because it is too large Load Diff
-4
View File
@@ -1,4 +0,0 @@
sphinx-rtd-theme
sphinx-autodoc-typehints
sphinx-automodapi
PyQt6
+5 -1
View File
@@ -27,8 +27,9 @@ extensions = [
"sphinx.ext.autodoc",
"sphinx_autodoc_typehints",
"sphinx.ext.napoleon",
"autoapi.extension",
# "sphinx.ext.autosummary",
"sphinx_automodapi.automodapi",
# "sphinx_automodapi.automodapi",
]
# Add any paths that contain templates here, relative to this directory.
@@ -39,6 +40,9 @@ templates_path = ["_templates"]
# This pattern also affects html_static_path and html_extra_path.
exclude_patterns = []
autoapi_dirs = ["../src"]
autoapi_member_order = "groupwise"
# -- Options for HTML output -------------------------------------------------
-1
View File
@@ -18,7 +18,6 @@ This documentation is dedicated to writting MO2 **Python** plugins.
plugin-types
writing-plugins
faq
mobase
-11
View File
@@ -1,11 +0,0 @@
``mobase`` API
==============
.. currentmodule:: mobase
.. automodapi:: mobase
:no-inheritance-diagram:
:no-heading:
.. toctree::
:maxdepth: 4
-7
View File
@@ -1,7 +0,0 @@
mobase
======
.. toctree::
:maxdepth: 4
mobase
+3 -5
View File
@@ -64,10 +64,8 @@ These plugins (shall eventually) implement all the game specific features and fu
able to add support for further games.
The plugin is also responsible to help MO determine if (and where) the game is installed in the first place.
Since supporting a game properly requires extensions in many places of the UI.
To allow this without creating one huge plugin interface that involves every aspect of MO, game plugins
expose a *feature list*.
The list of possible features can be found in the "game_features" project and each feature can itself be
considered a plugin interface.
To allow this without creating one huge plugin interface that involves every aspect of MO,
game plugins can register only the features they need to MO2 using :meth:`registerFeature<mobase.IGameFeatures.registerFeature>`
As an example for a game feature take BSA invalidation: If the game requires BSA invalidation it will implement
this feature.
@@ -147,4 +145,4 @@ File Mappings
This interface allows plugins to add virtual file (or directory) links to the virtual file system in addition to the
mod files.
Profile-local save games, ini-files and load-orders are all implemented this way in MO2.
Profile-local save games, ini-files and load-orders are all implemented this way in MO2.
Generated
+32 -1
View File
@@ -11,6 +11,17 @@ files = [
{file = "alabaster-0.7.16.tar.gz", hash = "sha256:75a8b99c28a5dad50dd7f8ccdd447a121ddb3892da9e53d1ca5cca3106d58d65"},
]
[[package]]
name = "astroid"
version = "3.3.1"
description = "An abstract syntax tree for Python with inference support."
optional = false
python-versions = ">=3.9.0"
files = [
{file = "astroid-3.3.1-py3-none-any.whl", hash = "sha256:a1a30b911ef8d74988c2a3a59d55ddf9cb973382f115479e213752a4fad36c7c"},
{file = "astroid-3.3.1.tar.gz", hash = "sha256:98eb59d8b92d141d618f92435407cbcd5c12dc9f5f4f0c5570fc2e4ba4ddc6aa"},
]
[[package]]
name = "babel"
version = "2.16.0"
@@ -567,6 +578,26 @@ docs = ["sphinxcontrib-websupport"]
lint = ["flake8 (>=6.0)", "importlib-metadata (>=6.0)", "mypy (==1.10.1)", "pytest (>=6.0)", "ruff (==0.5.2)", "sphinx-lint (>=0.9)", "tomli (>=2)", "types-docutils (==0.21.0.20240711)", "types-requests (>=2.30.0)"]
test = ["cython (>=3.0)", "defusedxml (>=0.7.1)", "pytest (>=8.0)", "setuptools (>=70.0)", "typing_extensions (>=4.9)"]
[[package]]
name = "sphinx-autoapi"
version = "3.2.1"
description = "Sphinx API documentation generator"
optional = false
python-versions = ">=3.8"
files = [
{file = "sphinx_autoapi-3.2.1-py2.py3-none-any.whl", hash = "sha256:72fe556abc579528a46494f4fcbeaeaaf3e0b031f6514f7b496f6c36754c5430"},
{file = "sphinx_autoapi-3.2.1.tar.gz", hash = "sha256:1f9d56b3a98d5653d1fad5644abeed2c042cec304a126ef72c236dae4af16b90"},
]
[package.dependencies]
astroid = {version = ">=3.0.0a1", markers = "python_version >= \"3.12\""}
Jinja2 = "*"
PyYAML = "*"
sphinx = ">=6.1.0"
[package.extras]
docs = ["furo", "sphinx", "sphinx-design"]
[[package]]
name = "sphinx-autodoc-typehints"
version = "2.2.3"
@@ -784,4 +815,4 @@ zstd = ["zstandard (>=0.18.0)"]
[metadata]
lock-version = "2.0"
python-versions = "^3.12"
content-hash = "a84158bffbc4f7ac0d6e8c9f8009d42abeb97bf648db79efd613c1bd9d455b69"
content-hash = "97106de296f79cfdd92e616a411bccc7677d7dbe6f84be55e85093e9550b80fa"
+1
View File
@@ -27,6 +27,7 @@ sphinx-rtd-theme = "^2.0.0"
sphinx-autodoc-typehints = "^2.2.3"
sphinx-automodapi = "^0.17.0"
sphinx = "<8"
sphinx-autoapi = "^3.2.1"
[build-system]
requires = ["poetry-core"]
+24 -5
View File
@@ -8,7 +8,7 @@ from pathlib import Path
from typing import Callable
from .loader import load_mobase
from .mtypes import Class, Constant, PyTyping
from .mtypes import Class, Constant, Enum, Function, PyTyping
from .parser import is_enum
from .register import MobaseRegister
from .utils import Settings, clean_class
@@ -146,6 +146,9 @@ def main() -> None:
[
# the "real" IPlugin is IPluginBase
"IPlugin",
# this is deprecated
"PluginSetting"
],
),
"mobase.widgets": extract_objects(mobase.widgets), # type: ignore
@@ -171,6 +174,10 @@ def main() -> None:
# Create the corresponding object:
c = register.make_object(n, o)
for n, o in objects:
c = register.get_object(n)
if isinstance(c, Class):
# Clean the class (e.g., remove duplicates methods due to wrappers):
clean_class(c)
@@ -198,6 +205,21 @@ def main() -> None:
# create directory if required
output_folder.mkdir(parents=True, exist_ok=True)
# sort the stubs
def _key_fn(o: Class | Constant | list[Function] | PyTyping) -> tuple[int, ...]:
# order is PyTyping -> Constant -> Function -> Enum -> Top-Level Class -> Child Level Classes
return (
not isinstance(o, PyTyping),
not isinstance(o, Constant),
not isinstance(o, list),
not isinstance(o, Enum),
isinstance(o, Class) and len(o.all_bases),
)
stub_objects = sorted(
(register.get_object(n) for n, _o in objects), key=_key_fn
)
# write everything
with open(output_folder.joinpath("__init__.pyi"), "w") as output:
writer = Writer(package=name, output=output, settings=settings)
@@ -208,10 +230,7 @@ def main() -> None:
module_headers[name](writer)
for n, _o in objects:
# Get the corresponding object:
c = register.get_object(n)
for c in stub_objects:
writer.print_object(c)
subprocess.run(
+1 -1
View File
@@ -33,7 +33,7 @@ def load_mobase(path: os.PathLike[Any]) -> Module:
os.add_dll_directory(str(path.joinpath("dlls"))) # type: ignore
# We need to add plugins/data to sys.path, mainly for PyQt6
sys.path.insert(1, path.joinpath("plugins", "plugin_python", "libs").as_posix())
sys.path.insert(1, path.joinpath("proxies", "python", "libs").as_posix())
import mobase # type: ignore
+3 -1
View File
@@ -234,6 +234,8 @@ def make_class(e: type, register: MobaseRegister) -> Class:
# members to exclude
EXCLUDED_MEMBERS = [
"__init_subclass__",
"__dict__",
"__doc__",
"__module__",
"__subclasshook__",
"__hash__",
@@ -346,7 +348,7 @@ def make_class(e: type, register: MobaseRegister) -> Class:
direct_bases: list[Class] = []
for c in e.__bases__:
if c.__module__ != "pybind11_builtins":
if c.__module__ not in ("pybind11_builtins", "builtins"):
b = register.get_object(c.__name__)
assert isinstance(b, Class)
direct_bases.append(b)
File diff suppressed because it is too large Load Diff
+23 -10
View File
@@ -13,7 +13,17 @@ class TaskDialog:
Customizable choice dialog.
"""
def __init__(self: TaskDialog, parent: PyQt6.QtWidgets.QWidget | None = None, title: str = '', main: str = '', content: str = '', details: str = '', icon: PyQt6.QtWidgets.QMessageBox.Icon = PyQt6.QtWidgets.QMessageBox.Icon.NoIcon, buttons: list[TaskDialogButton] = [], remember: Union[str, tuple[str, str]] = '') -> None:
def __init__(
self: TaskDialog,
parent: PyQt6.QtWidgets.QWidget | None = None,
title: str = "",
main: str = "",
content: str = "",
details: str = "",
icon: PyQt6.QtWidgets.QMessageBox.Icon = PyQt6.QtWidgets.QMessageBox.Icon.NoIcon,
buttons: list[TaskDialogButton] = [],
remember: Union[str, tuple[str, str]] = "",
) -> None:
"""
Construct a new TaskDialog.
@@ -91,7 +101,7 @@ class TaskDialog:
main: Main message of the dialog.
"""
...
def setRemember(self: TaskDialog, action: str, file: str = '') -> TaskDialog:
def setRemember(self: TaskDialog, action: str, file: str = "") -> TaskDialog:
"""
Configure the dialog to remember user-choice.
"""
@@ -113,7 +123,6 @@ class TaskDialog:
"""
...
class TaskDialogButton:
"""
Special button to be used inside TaskDialog widgets.
@@ -123,19 +132,21 @@ class TaskDialogButton:
def button(self) -> PyQt6.QtWidgets.QMessageBox.StandardButton: ...
@button.setter
def button(self, arg0: PyQt6.QtWidgets.QMessageBox.StandardButton) -> None: ...
@property
def description(self) -> str: ...
@description.setter
def description(self, arg0: str) -> None: ...
@property
def text(self) -> str: ...
@text.setter
def text(self, arg0: str) -> None: ...
@overload
def __init__(self: TaskDialogButton, text: str, description: str, button: PyQt6.QtWidgets.QMessageBox.StandardButton) -> None:
def __init__(
self: TaskDialogButton,
text: str,
description: str,
button: PyQt6.QtWidgets.QMessageBox.StandardButton,
) -> None:
"""
Create a TaskDialogButton.
@@ -146,7 +157,11 @@ class TaskDialogButton:
"""
...
@overload
def __init__(self: TaskDialogButton, text: str, button: PyQt6.QtWidgets.QMessageBox.StandardButton) -> None:
def __init__(
self: TaskDialogButton,
text: str,
button: PyQt6.QtWidgets.QMessageBox.StandardButton,
) -> None:
"""
Create a TaskDialogButton without description.
@@ -155,5 +170,3 @@ class TaskDialogButton:
button: Value returned by TaskDialog.exec() if this button is clicked.
"""
...
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,172 @@
from __future__ import annotations
__version__ = "2.5.2"
from typing import List, Tuple, Union, overload
import PyQt6.QtCore
import PyQt6.QtGui
import PyQt6.QtWidgets
class TaskDialog:
"""
Customizable choice dialog.
"""
def __init__(
self: TaskDialog,
parent: PyQt6.QtWidgets.QWidget | None = None,
title: str = "",
main: str = "",
content: str = "",
details: str = "",
icon: PyQt6.QtWidgets.QMessageBox.Icon = PyQt6.QtWidgets.QMessageBox.Icon.NoIcon,
buttons: list[TaskDialogButton] = [],
remember: Union[str, tuple[str, str]] = "",
) -> None:
"""
Construct a new TaskDialog.
Args:
parent: Parent widget of the dialog.
title: Title of the dialog.
main: Header of the dialog (big text at the top).
content: Main message of the dialog (text below main).
details: Details for the dialog, initially collapsed (bottom of the dialog).
icon: Icon for the dialog.
buttons: List of buttons for the dialog.
remember: Remember the choice for this dialog.
"""
...
def addButton(self: TaskDialog, button: TaskDialogButton) -> TaskDialog:
"""
Add a custom button to this TaskDialog.
Args:
button: Button to add to the dialog.
"""
...
def addContent(self: TaskDialog, widget: PyQt6.QtWidgets.QWidget) -> None:
"""
Add a custom widget content to this TaskDialog. Widget content are put between
content and buttons (above buttons).
Args:
widget: Widget to add.
"""
...
def exec(self: TaskDialog) -> PyQt6.QtWidgets.QMessageBox.StandardButton:
"""
Display this dialog and wait for user-interaction to return. This is a blocking
function.
Returns:
The button clicked by the user. Without custom buttons, this return Ok,
otherwise it returns the button set in the TaskDialogButton.
"""
...
def setContent(self: TaskDialog, content: str) -> TaskDialog:
"""
Set the top-level message of this dialog.
Args:
content: Top-level message to set.
"""
...
def setDetails(self: TaskDialog, details: str) -> TaskDialog:
"""
Set the details for this TaskDialog.
The details are hidden by default and the user can display them by clicking
the "Details" button at the bottom of the TaskDialog.
Args:
details: Details content to display. Can be a multi-line string.
"""
...
def setIcon(self: TaskDialog, icon: PyQt6.QtWidgets.QMessageBox.Icon) -> TaskDialog:
"""
Set the icon of the dialog.
Args:
icon: Icon of the dialog.
"""
...
def setMain(self: TaskDialog, main: str) -> TaskDialog:
"""
Set the main message of the dialog. The main message is displayed at the top of
the dialog in large font.
Args:
main: Main message of the dialog.
"""
...
def setRemember(self: TaskDialog, action: str, file: str = "") -> TaskDialog:
"""
Configure the dialog to remember user-choice.
"""
...
def setTitle(self: TaskDialog, title: str) -> TaskDialog:
"""
Set the title of the dialog.
Args:
title: Title of the dialog.
"""
...
def setWidth(self: TaskDialog, width: int) -> None:
"""
Set the width of the dialog.
Args:
width: Width of the dialog.
"""
...
class TaskDialogButton:
"""
Special button to be used inside TaskDialog widgets.
"""
@property
def button(self) -> PyQt6.QtWidgets.QMessageBox.StandardButton: ...
@button.setter
def button(self, arg0: PyQt6.QtWidgets.QMessageBox.StandardButton) -> None: ...
@property
def description(self) -> str: ...
@description.setter
def description(self, arg0: str) -> None: ...
@property
def text(self) -> str: ...
@text.setter
def text(self, arg0: str) -> None: ...
@overload
def __init__(
self: TaskDialogButton,
text: str,
description: str,
button: PyQt6.QtWidgets.QMessageBox.StandardButton,
) -> None:
"""
Create a TaskDialogButton.
Args:
text: Label of the button.
description: Description of the button.
button: Value returned by TaskDialog.exec() if this button is clicked.
"""
...
@overload
def __init__(
self: TaskDialogButton,
text: str,
button: PyQt6.QtWidgets.QMessageBox.StandardButton,
) -> None:
"""
Create a TaskDialogButton without description.
Args:
text: Label of the button.
button: Value returned by TaskDialog.exec() if this button is clicked.
"""
...