mirror of
https://github.com/ModOrganizer2/pystubs-generation.git
synced 2026-07-27 14:07:13 -07:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
886a50770f | ||
|
|
2ee1505336 | ||
|
|
92dec5b19a | ||
|
|
b33b8bceb1 | ||
|
|
dd80b67a0a | ||
|
|
8789b59f23 | ||
|
|
72c652daaa | ||
|
|
80a365f19a | ||
|
|
1b8d6840e2 | ||
|
|
d7c1ecd6f2 | ||
|
|
6a76dda9d7 | ||
|
|
0c807ad974 | ||
|
|
a3542ca1c4 | ||
|
|
d6760273a2 |
@@ -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.0/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:
|
||||
@@ -34,7 +34,7 @@ jobs:
|
||||
poetry version ${TAG#v}
|
||||
poetry build
|
||||
- name: Store the distribution packages
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: python-package-distributions
|
||||
path: stubs/setup/dist/
|
||||
@@ -49,7 +49,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Download all the dists
|
||||
uses: actions/download-artifact@v3
|
||||
uses: actions/download-artifact@v7
|
||||
with:
|
||||
name: python-package-distributions
|
||||
path: dist/
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
+350
-28
File diff suppressed because it is too large
Load Diff
@@ -1,4 +0,0 @@
|
||||
sphinx-rtd-theme
|
||||
sphinx-autodoc-typehints
|
||||
sphinx-automodapi
|
||||
PyQt6
|
||||
+5
-1
@@ -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 -------------------------------------------------
|
||||
|
||||
|
||||
@@ -18,7 +18,6 @@ This documentation is dedicated to writting MO2 **Python** plugins.
|
||||
plugin-types
|
||||
writing-plugins
|
||||
faq
|
||||
mobase
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
``mobase`` API
|
||||
==============
|
||||
|
||||
.. currentmodule:: mobase
|
||||
|
||||
.. automodapi:: mobase
|
||||
:no-inheritance-diagram:
|
||||
:no-heading:
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 4
|
||||
@@ -1,7 +0,0 @@
|
||||
mobase
|
||||
======
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 4
|
||||
|
||||
mobase
|
||||
@@ -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
+520
-397
File diff suppressed because it is too large
Load Diff
+26
-25
@@ -1,35 +1,39 @@
|
||||
[tool.poetry]
|
||||
[project]
|
||||
name = "mo2-pystubs-generation"
|
||||
version = "0.1.0"
|
||||
description = ""
|
||||
authors = ["Holt59 <capelle.mikael@gmail.com>"]
|
||||
license = "MIT"
|
||||
version = "0.1.0"
|
||||
readme = "README.md"
|
||||
packages = [{ include = "mo2", from = "src" }]
|
||||
authors = [{ name = "Holt59", email = "capelle.mikael@gmail.com" }]
|
||||
requires-python = ">=3.12,<4.0"
|
||||
dependencies = [
|
||||
"pyqt6 (==6.11.0)",
|
||||
"pyyaml (>=6.0.3,<7.0.0)",
|
||||
"typing-extensions (>=4.15.0,<5.0.0)",
|
||||
]
|
||||
|
||||
[tool.poetry.scripts]
|
||||
[project.scripts]
|
||||
mo2-stubs-generator = "mo2.stubs.generator.__main__:main"
|
||||
|
||||
[tool.poetry.dependencies]
|
||||
python = "^3.12"
|
||||
pyqt6 = "^6.7.0"
|
||||
pyyaml = "^6.0.1"
|
||||
[build-system]
|
||||
requires = ['poetry-core (>=2.0,<3.0)']
|
||||
build-backend = "poetry.core.masonry.api"
|
||||
|
||||
[tool.poetry]
|
||||
packages = [{ include = "mo2", from = "src" }]
|
||||
|
||||
[tool.poetry.group.dev.dependencies]
|
||||
pyright = "^1.1.365"
|
||||
ruff = "^0.4.7"
|
||||
types-pyyaml = "^6.0.12.20240311"
|
||||
poethepoet = "^0.26.1"
|
||||
pyright = "^1.1.409"
|
||||
ruff = "^0.15.12"
|
||||
types-pyyaml = "^6.0.12.20260508"
|
||||
poethepoet = "^0.45.0"
|
||||
|
||||
[tool.poetry.group.doc.dependencies]
|
||||
sphinx-rtd-theme = "^2.0.0"
|
||||
sphinx-autodoc-typehints = "^2.1.0"
|
||||
sphinx-automodapi = "^0.16.0"
|
||||
sphinx = "^7.3.7"
|
||||
|
||||
[build-system]
|
||||
requires = ["poetry-core"]
|
||||
build-backend = "poetry.core.masonry.api"
|
||||
sphinx-rtd-theme = "^3.0.2"
|
||||
sphinx-autodoc-typehints = "^3.2.0"
|
||||
sphinx-automodapi = "^0.20.0"
|
||||
sphinx = "^8.2.3"
|
||||
sphinx-autoapi = "^3.6.0"
|
||||
|
||||
[tool.poe.tasks]
|
||||
format-imports = "ruff check --select I src --fix"
|
||||
@@ -42,14 +46,11 @@ lint.sequence = ["lint-ruff", "lint-ruff-format", "lint-pyright"]
|
||||
lint.ignore_fail = "return_non_zero"
|
||||
|
||||
[tool.ruff]
|
||||
target-version = "py310"
|
||||
target-version = "py312"
|
||||
|
||||
[tool.ruff.lint]
|
||||
extend-select = ["B", "Q", "I"]
|
||||
|
||||
[tool.ruff.lint.isort]
|
||||
known-first-party = ['tas']
|
||||
|
||||
[tool.pyright]
|
||||
typeCheckingMode = "strict"
|
||||
reportMissingTypeStubs = true
|
||||
|
||||
@@ -8,19 +8,19 @@ from pathlib import Path
|
||||
from typing import Callable
|
||||
|
||||
from .loader import load_mobase
|
||||
from .mtypes import Class, PyTyping
|
||||
from .mtypes import Class, Constant, Enum, Function, PyTyping
|
||||
from .parser import is_enum
|
||||
from .register import MobaseRegister
|
||||
from .utils import Settings, clean_class
|
||||
from .writer import Writer, is_list_of_functions
|
||||
from .writer import Writer, is_list_of
|
||||
|
||||
LOGGER = logging.getLogger(__package__)
|
||||
|
||||
|
||||
def extract_objects(
|
||||
module: object, skips: Sequence[str] = []
|
||||
) -> list[tuple[str, type]]:
|
||||
objects: list[tuple[str, type]] = []
|
||||
) -> list[tuple[str, object]]:
|
||||
objects: list[tuple[str, object]] = []
|
||||
|
||||
assert hasattr(module, "__name__")
|
||||
module_name: str = module.__name__ # type: ignore
|
||||
@@ -140,7 +140,7 @@ def main() -> None:
|
||||
}
|
||||
|
||||
# list of objects directly in mobase
|
||||
module_objects: dict[str, list[tuple[str, type]]] = {
|
||||
module_objects: dict[str, list[tuple[str, object]]] = {
|
||||
"mobase": extract_objects(
|
||||
mobase,
|
||||
[
|
||||
@@ -178,10 +178,10 @@ def main() -> None:
|
||||
# Path the class using the configuration:
|
||||
settings.patch_class(c)
|
||||
|
||||
elif isinstance(c, PyTyping):
|
||||
elif isinstance(c, (PyTyping, Constant)):
|
||||
...
|
||||
|
||||
elif is_list_of_functions(c):
|
||||
elif is_list_of(c, Function):
|
||||
settings.patch_functions(c)
|
||||
|
||||
else:
|
||||
@@ -198,6 +198,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,25 +223,22 @@ 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(
|
||||
[
|
||||
"ruff",
|
||||
"--silent",
|
||||
"format",
|
||||
"--silent",
|
||||
output_folder.joinpath("__init__.pyi").as_posix(),
|
||||
]
|
||||
)
|
||||
subprocess.run(
|
||||
[
|
||||
"ruff",
|
||||
"--silent",
|
||||
"check",
|
||||
"--silent",
|
||||
"--select",
|
||||
"I",
|
||||
"--fix",
|
||||
|
||||
@@ -4,7 +4,7 @@ import re
|
||||
import types
|
||||
from collections import OrderedDict, defaultdict
|
||||
from itertools import chain
|
||||
from typing import Any, Iterable, cast
|
||||
from typing import Any, Callable, Iterable, cast
|
||||
|
||||
from .mtypes import (
|
||||
Argument,
|
||||
@@ -118,7 +118,7 @@ def parse_python_signature(s: str, name: str) -> tuple[PyType, list[Argument]]:
|
||||
return PyType(return_type), arguments
|
||||
|
||||
|
||||
def is_enum(e: type) -> bool:
|
||||
def is_enum(e: object) -> bool:
|
||||
"""Check if the given class is an enumeration.
|
||||
|
||||
Args:
|
||||
@@ -144,17 +144,18 @@ class Overload:
|
||||
self.arguments = arguments
|
||||
|
||||
|
||||
def parse_pybind11_function_docstring(e: type) -> list[Overload]:
|
||||
def parse_pybind11_function_docstring(name: str, doc: str | None) -> list[Overload]:
|
||||
"""
|
||||
Parse the docstring of the given element.
|
||||
Parse the docstring of a Pybind11 function.
|
||||
|
||||
Args:
|
||||
e: The function to "parse".
|
||||
name: Name of the function.
|
||||
doc: The docstring of the function generated by Pybind11.
|
||||
|
||||
Returns:
|
||||
A list of overloads for the given function.
|
||||
"""
|
||||
lines = (e.__doc__ or "").strip().split("\n")
|
||||
lines = (doc or "").strip().split("\n")
|
||||
|
||||
signatures: list[str]
|
||||
if len(lines) == 1:
|
||||
@@ -162,7 +163,7 @@ def parse_pybind11_function_docstring(e: type) -> list[Overload]:
|
||||
else:
|
||||
signatures = []
|
||||
for line in lines:
|
||||
m = re.match(rf"^[0-9]+[.]\s+({e.__name__}.*)$", line)
|
||||
m = re.match(rf"^[0-9]+[.]\s+({name}.*)$", line)
|
||||
if m:
|
||||
signatures.append(m.group(1).strip())
|
||||
|
||||
@@ -174,16 +175,16 @@ def parse_pybind11_function_docstring(e: type) -> list[Overload]:
|
||||
signature = signature.replace("MOBase::", "mobase.").replace("::", ".")
|
||||
|
||||
try:
|
||||
return_type, arguments = parse_python_signature(signature, e.__name__)
|
||||
return_type, arguments = parse_python_signature(signature, name)
|
||||
except ValueError as err:
|
||||
raise ValueError(f"invalid signature: {e.__name__}, {e.__doc__}") from err
|
||||
raise ValueError(f"invalid signature: {name}, {doc}") from err
|
||||
overloads.append(Overload(return_type=return_type, arguments=arguments))
|
||||
|
||||
return overloads
|
||||
|
||||
|
||||
def make_functions(e: type) -> list[Function]:
|
||||
overloads = parse_pybind11_function_docstring(e)
|
||||
def make_functions(e: Callable[..., Any]) -> list[Function]:
|
||||
overloads = parse_pybind11_function_docstring(e.__name__, e.__doc__)
|
||||
|
||||
return [
|
||||
Function(
|
||||
@@ -295,7 +296,9 @@ def make_class(e: type, register: MobaseRegister) -> Class:
|
||||
|
||||
# otherwise we parse the docstring
|
||||
else:
|
||||
overloads = parse_pybind11_function_docstring(method)
|
||||
overloads = parse_pybind11_function_docstring(
|
||||
method.__name__, method.__doc__
|
||||
)
|
||||
|
||||
for overload in overloads:
|
||||
args = overload.arguments
|
||||
|
||||
@@ -4,7 +4,7 @@ from __future__ import annotations
|
||||
|
||||
from collections import OrderedDict
|
||||
|
||||
from .mtypes import Class, Function, PyTyping
|
||||
from .mtypes import Class, Constant, Function, PyType, PyTyping
|
||||
|
||||
|
||||
class MobaseRegister:
|
||||
@@ -12,20 +12,20 @@ class MobaseRegister:
|
||||
Class that register classes.
|
||||
"""
|
||||
|
||||
objects: dict[str, Class | list[Function] | PyTyping]
|
||||
objects: dict[str, Class | Constant | list[Function] | PyTyping]
|
||||
|
||||
def __init__(self) -> None:
|
||||
self.raw_objects: dict[str, type] = OrderedDict()
|
||||
self.raw_objects: dict[str, object] = OrderedDict()
|
||||
self.objects = {}
|
||||
|
||||
def add_object(self, name: str, object: type) -> None:
|
||||
self.raw_objects[name] = object
|
||||
def add_object(self, n: str, o: object, /) -> None:
|
||||
self.raw_objects[n] = o
|
||||
|
||||
def make_object(
|
||||
self, name: str, e: type | None = None
|
||||
) -> Class | list[Function] | PyTyping:
|
||||
self, name: str, e: object | None = None
|
||||
) -> Class | list[Function] | Constant | PyTyping:
|
||||
"""
|
||||
Construct a Function, Class or Enum for the given object.
|
||||
Construct a Function, Class, Constant or Enum for the given object.
|
||||
|
||||
Args:
|
||||
name: The name of the object to inspect.
|
||||
@@ -47,14 +47,14 @@ class MobaseRegister:
|
||||
self.objects[name] = make_class(e, self)
|
||||
elif callable(e):
|
||||
self.objects[name] = make_functions(e)
|
||||
|
||||
# typing stuff
|
||||
elif type(e).__module__ == "types" or type(e).__module__ == "typing":
|
||||
self.objects[name] = PyTyping(name, e)
|
||||
else:
|
||||
self.objects[name] = Constant(name, type=PyType(type(e)), value=e)
|
||||
|
||||
return self.objects[name]
|
||||
|
||||
def get_object(self, name: str) -> Class | list[Function] | PyTyping:
|
||||
def get_object(self, name: str) -> Class | Constant | list[Function] | PyTyping:
|
||||
"""
|
||||
Retrieve the object if the given name. Fails if no object with this
|
||||
name exists (if `make_object(name, ...)` has never been called).
|
||||
|
||||
@@ -215,7 +215,7 @@ class Settings:
|
||||
# Check the args:
|
||||
if function_settings.args is not None:
|
||||
if len(function_settings.args) != len(fn.args):
|
||||
LOGGER.warn(
|
||||
LOGGER.warning(
|
||||
f"Mismatch number of arguments for function "
|
||||
f"mobase.{setting_name}."
|
||||
)
|
||||
@@ -243,7 +243,7 @@ class Settings:
|
||||
fn.deprecated = function_settings.deprecated
|
||||
|
||||
else:
|
||||
LOGGER.warn(
|
||||
LOGGER.warning(
|
||||
"Missing settings for function mobase.{}.".format(setting_name)
|
||||
)
|
||||
|
||||
@@ -268,7 +268,7 @@ class Settings:
|
||||
class_settings = self._get_class_settings(cls.canonical_name)
|
||||
|
||||
if class_settings is None:
|
||||
LOGGER.warn("Class {} not found in settings.".format(cls.canonical_name))
|
||||
LOGGER.warning("Class {} not found in settings.".format(cls.canonical_name))
|
||||
return
|
||||
|
||||
if "__doc__" in class_settings and class_settings["__doc__"] is not None:
|
||||
@@ -306,7 +306,7 @@ class Settings:
|
||||
if "type" in settings_property:
|
||||
prop.type = PyType(settings_property["type"])
|
||||
else:
|
||||
LOGGER.warn(
|
||||
LOGGER.warning(
|
||||
"Missing type for property {}.{}.".format(
|
||||
cls.canonical_name, prop.name
|
||||
)
|
||||
@@ -320,7 +320,7 @@ class Settings:
|
||||
prop.doc = settings_property["desc"]
|
||||
|
||||
else:
|
||||
LOGGER.warn(
|
||||
LOGGER.warning(
|
||||
"Missing description for property {}.{}.".format(
|
||||
cls.canonical_name, prop.name
|
||||
)
|
||||
@@ -366,7 +366,7 @@ class Settings:
|
||||
if function_settings.args is not None:
|
||||
method_arguments = m.args if m.is_static() else m.args[1:]
|
||||
if len(function_settings.args) != len(method_arguments):
|
||||
LOGGER.warn(
|
||||
LOGGER.warning(
|
||||
"Mismatch number of arguments for method {}.{}.".format(
|
||||
cls.canonical_name, settings_name
|
||||
)
|
||||
@@ -380,7 +380,7 @@ class Settings:
|
||||
not method_arg.name.startswith("arg")
|
||||
and method_arg.name != settings_arg.name
|
||||
):
|
||||
LOGGER.warn(
|
||||
LOGGER.warning(
|
||||
(
|
||||
"Mismatch argument name for method {}.{}: "
|
||||
"{} {}, using {}."
|
||||
@@ -429,7 +429,7 @@ class Settings:
|
||||
|
||||
if n_overloads > 0 and missing_settings:
|
||||
for settings_name in missing_settings:
|
||||
LOGGER.warn(
|
||||
LOGGER.warning(
|
||||
"Missing settings for method {}.{}.".format(
|
||||
cls.canonical_name, settings_name
|
||||
)
|
||||
@@ -447,7 +447,7 @@ class Settings:
|
||||
# Print items missing in mobase
|
||||
missing_items = [k for k, v in keys.items() if not v]
|
||||
if missing_items:
|
||||
LOGGER.warn(
|
||||
LOGGER.warning(
|
||||
"The following members were found in settings but not in the actual"
|
||||
" class {}: {}.".format(cls.canonical_name, ", ".join(missing_items))
|
||||
)
|
||||
|
||||
@@ -1,16 +1,20 @@
|
||||
import logging
|
||||
from typing import Any, Iterable, TextIO, TypeGuard
|
||||
from typing import Any, TextIO
|
||||
|
||||
from .mtypes import Class, Enum, Function, Method, Property, PyTyping
|
||||
from typing_extensions import TypeIs
|
||||
|
||||
from .mtypes import Class, Constant, Enum, Function, Method, Property, PyTyping
|
||||
from .utils import Settings
|
||||
|
||||
LOGGER = logging.getLogger(__package__)
|
||||
|
||||
|
||||
def is_list_of_functions(e: Any | Iterable[Any]) -> TypeGuard[list[Function]]:
|
||||
if not isinstance(e, list):
|
||||
return False
|
||||
return all(isinstance(x, Function) for x in e)
|
||||
def is_list_of_any(e: Any) -> TypeIs[list[Any]]:
|
||||
return isinstance(e, list)
|
||||
|
||||
|
||||
def is_list_of[T](e: Any, t: type[T]) -> TypeIs[list[T]]:
|
||||
return is_list_of_any(e) and all(isinstance(x, t) for x in e)
|
||||
|
||||
|
||||
class Writer:
|
||||
@@ -256,13 +260,24 @@ class Writer:
|
||||
def print_typing(self, typ: PyTyping):
|
||||
self._print(f"{typ.name} = {typ.typing}")
|
||||
|
||||
def print_object(self, e: object):
|
||||
def print_constent(self, constant: Constant):
|
||||
assert constant.type is not None
|
||||
self._print(
|
||||
"{}: {} = ...".format(
|
||||
constant.name, self._fix_typing(constant.type.typing())
|
||||
)
|
||||
)
|
||||
|
||||
def print_object(self, e: Class | Constant | list[Function] | PyTyping):
|
||||
if isinstance(e, Class):
|
||||
self.print_class(e)
|
||||
|
||||
elif is_list_of_functions(e):
|
||||
elif is_list_of(e, Function):
|
||||
for fn in e:
|
||||
self.print_function(fn)
|
||||
|
||||
elif isinstance(e, PyTyping):
|
||||
self.print_typing(e)
|
||||
|
||||
else:
|
||||
self.print_constent(e)
|
||||
|
||||
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.
|
||||
"""
|
||||
...
|
||||
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user