mirror of
https://github.com/ModOrganizer2/modorganizer-plugin_python.git
synced 2026-07-27 14:03:33 -07:00
Compare commits
148
Commits
2_4_x
...
dev/extensions
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
79f585f483 | ||
|
|
e85e69a7a1 | ||
|
|
4c6ed4adc0 | ||
|
|
691a9a2f62 | ||
|
|
e155907d21 | ||
|
|
54e05d31ef | ||
|
|
bf05ac1593 | ||
|
|
e4576f67a6 | ||
|
|
a4338db554 | ||
|
|
9b1793c726 | ||
|
|
c658b396bc | ||
|
|
8fa0d0ade8 | ||
|
|
2d151d0f66 | ||
|
|
7cca7018b3 | ||
|
|
e11d5ec00d | ||
|
|
6623e19754 | ||
|
|
7cfc761e40 | ||
|
|
5bb4de039e | ||
|
|
8c044e28c5 | ||
|
|
790d0a1097 | ||
|
|
a966db7d19 | ||
|
|
86505f19ce | ||
|
|
a839d36235 | ||
|
|
bb0a24a00d | ||
|
|
ac7009d17f | ||
|
|
cc1bc4cb7f | ||
|
|
ebede37865 | ||
|
|
7a885ad014 | ||
|
|
ff3c601164 | ||
|
|
655e60acb7 | ||
|
|
e52163eb29 | ||
|
|
431caa9992 | ||
|
|
a644546b41 | ||
|
|
404fd3f4a3 | ||
|
|
0be763f3d2 | ||
|
|
7452df8bbb | ||
|
|
c6c7e5ef73 | ||
|
|
328b6e7710 | ||
|
|
eb2c874a39 | ||
|
|
5501814e00 | ||
|
|
d1609a79ae | ||
|
|
58737acf0e | ||
|
|
d3fec9c230 | ||
|
|
b99a5115cb | ||
|
|
923d600bc0 | ||
|
|
ba80ce9e20 | ||
|
|
57b30be723 | ||
|
|
f1e5d65868 | ||
|
|
5a8d3e1a72 | ||
|
|
809157115f | ||
|
|
be9b614a5e | ||
|
|
0ee795ac6a | ||
|
|
d7c109c344 | ||
|
|
7108d59267 | ||
|
|
1bffcfa8bf | ||
|
|
6c20f001ff | ||
|
|
0fff26df0c | ||
|
|
a5d84297fc | ||
|
|
1bc51b6626 | ||
|
|
e6190bf4f7 | ||
|
|
788f982eab | ||
|
|
cb750e72d1 | ||
|
|
1cdeb081b2 | ||
|
|
1effc57990 | ||
|
|
26d7de23f3 | ||
|
|
967f1d327b | ||
|
|
2430e85968 | ||
|
|
2eabaf1774 | ||
|
|
40c6119515 | ||
|
|
efaea1edfe | ||
|
|
e204c003ae | ||
|
|
29fc11dfd8 | ||
|
|
cc11a1a4f7 | ||
|
|
465059181a | ||
|
|
cb35c950cf | ||
|
|
e6c5923bb1 | ||
|
|
604c50d3b3 | ||
|
|
5b32c4f024 | ||
|
|
e788f44b85 | ||
|
|
28210d3d7a | ||
|
|
450bfa821a | ||
|
|
b17a1a3b07 | ||
|
|
19da0a9d8c | ||
|
|
b7e08ad862 | ||
|
|
d0a0ac0f0d | ||
|
|
4b0890e679 | ||
|
|
6268fe6d7b | ||
|
|
cf76d34cdf | ||
|
|
9bc343c944 | ||
|
|
72750ab4de | ||
|
|
7c6bbc2980 | ||
|
|
65ccc4af9c | ||
|
|
b42ce25b6e | ||
|
|
fa33e42e22 | ||
|
|
94bd8b82b4 | ||
|
|
639c3cf71d | ||
|
|
6030b443f7 | ||
|
|
08430a5df1 | ||
|
|
8a886733d4 | ||
|
|
2ef5dedfc0 | ||
|
|
97e9876987 | ||
|
|
e89616d695 | ||
|
|
cc0be7469a | ||
|
|
62f4a9679d | ||
|
|
958cf9de37 | ||
|
|
30a01cf783 | ||
|
|
6ea9d92b26 | ||
|
|
225c86d258 | ||
|
|
051c0589b5 | ||
|
|
907bbf3117 | ||
|
|
e5d4a4133c | ||
|
|
21aeebdcc8 | ||
|
|
275acba6dd | ||
|
|
68060b0e6b | ||
|
|
b2767887a9 | ||
|
|
d4f515ade1 | ||
|
|
64af744c8c | ||
|
|
dff9bd2404 | ||
|
|
4c7b452219 | ||
|
|
d0e883fd90 | ||
|
|
f904e25e76 | ||
|
|
55e8ce326a | ||
|
|
92a2429d58 | ||
|
|
5ec456f880 | ||
|
|
b92e3de535 | ||
|
|
c97724a98f | ||
|
|
3798370283 | ||
|
|
b2e1cb490c | ||
|
|
8e714f2eb6 | ||
|
|
9ad6c7f6ac | ||
|
|
4937fe9cc9 | ||
|
|
67ea7deb00 | ||
|
|
8bd7d08d1a | ||
|
|
4be4bc2a55 | ||
|
|
94ecbe2c16 | ||
|
|
ddaff7d03d | ||
|
|
3957187e0a | ||
|
|
03989ae0f1 | ||
|
|
cc129e4895 | ||
|
|
7e8748abf0 | ||
|
|
11c2bcac9a | ||
|
|
56de0fb4d1 | ||
|
|
a53d3fe5d3 | ||
|
|
d6a7efc266 | ||
|
|
574f79117e | ||
|
|
4d018999cd | ||
|
|
d678a22f99 | ||
|
|
4e8800b4d6 |
@@ -0,0 +1,21 @@
|
||||
---
|
||||
# We'll use defaults from the LLVM style, but with 4 columns indentation.
|
||||
BasedOnStyle: LLVM
|
||||
IndentWidth: 4
|
||||
---
|
||||
Language: Cpp
|
||||
# Force pointers to the type for C++.
|
||||
DerivePointerAlignment: false
|
||||
PointerAlignment: Left
|
||||
AlignConsecutiveAssignments: true
|
||||
AllowShortFunctionsOnASingleLine: Inline
|
||||
AllowShortIfStatementsOnASingleLine: Never
|
||||
AllowShortLambdasOnASingleLine: Empty
|
||||
AlwaysBreakTemplateDeclarations: Yes
|
||||
AccessModifierOffset: -4
|
||||
AlignTrailingComments: true
|
||||
SpacesBeforeTrailingComments: 2
|
||||
NamespaceIndentation: All
|
||||
MaxEmptyLinesToKeep: 1
|
||||
BreakBeforeBraces: Stroustrup
|
||||
ColumnLimit: 88
|
||||
@@ -0,0 +1,2 @@
|
||||
1bffcfa8bfba93a9505692b11fdd3f0903983542
|
||||
7108d59267b0fe4e9442f9bb146ea5d70e7704a8
|
||||
@@ -0,0 +1,8 @@
|
||||
# Set the default behavior, in case people don't have core.autocrlf set.
|
||||
* text=auto
|
||||
|
||||
# Explicitly declare text files you want to always be normalized and converted
|
||||
# to native line endings on checkout.
|
||||
*.cpp text eol=crlf
|
||||
*.h text eol=crlf
|
||||
*.py text eol=crlf
|
||||
@@ -0,0 +1,55 @@
|
||||
name: Build & Test Plugin Python
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: master
|
||||
pull_request:
|
||||
types: [opened, synchronize, reopened]
|
||||
|
||||
env:
|
||||
VCPKG_BINARY_SOURCES: "clear;x-gha,readwrite"
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: windows-2022
|
||||
steps:
|
||||
# https://learn.microsoft.com/en-us/vcpkg/consume/binary-caching-github-actions-cache
|
||||
- name: Export GitHub Actions cache environment variables
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
core.exportVariable('ACTIONS_CACHE_URL', process.env.ACTIONS_CACHE_URL || '');
|
||||
core.exportVariable('ACTIONS_RUNTIME_TOKEN', process.env.ACTIONS_RUNTIME_TOKEN || '');
|
||||
|
||||
- uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: "3.12"
|
||||
|
||||
- name: Install Qt
|
||||
uses: jurplel/install-qt-action@v3
|
||||
with:
|
||||
setup-python: false
|
||||
version: 6.7.1
|
||||
modules:
|
||||
cache: true
|
||||
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: "Set environmental variables"
|
||||
shell: bash
|
||||
run: |
|
||||
echo "VCPKG_ROOT=$VCPKG_INSTALLATION_ROOT" >> $GITHUB_ENV
|
||||
|
||||
- name: Configure Plugin Python build
|
||||
shell: pwsh
|
||||
run: |
|
||||
cmake --preset vs2022-windows-standalone `
|
||||
"-DCMAKE_PREFIX_PATH=${env:QT_ROOT_DIR}\msvc2019_64" `
|
||||
-DPLUGIN_PYTHON_TESTING=ON
|
||||
|
||||
- name: Build Plugin Python
|
||||
run: cmake --build vsbuild --config RelWithDebInfo --verbose `
|
||||
--target python-tests --target runner-tests --target proxy
|
||||
|
||||
- name: Test Plugin Python
|
||||
run: ctest --test-dir vsbuild -C RelWithDebInfo --output-on-failure
|
||||
@@ -0,0 +1,24 @@
|
||||
name: Lint Plugin Python
|
||||
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
types: [opened, synchronize, reopened]
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Check format
|
||||
uses: ModOrganizer2/check-formatting-action@master
|
||||
with:
|
||||
check-path: "."
|
||||
- uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: "3.12"
|
||||
- uses: abatilo/actions-poetry@v2
|
||||
- name: Check format Python tests
|
||||
run: |
|
||||
poetry install --no-root
|
||||
poetry run poe lint
|
||||
@@ -1,5 +1,12 @@
|
||||
# build
|
||||
edit
|
||||
CMakeLists.txt.user
|
||||
/msbuild.log
|
||||
/*std*.log
|
||||
/*build
|
||||
|
||||
# python
|
||||
tests/**/__pycache__
|
||||
|
||||
# IDE
|
||||
.vscode
|
||||
|
||||
+29
-11
@@ -1,15 +1,33 @@
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
project(plugin_python)
|
||||
set(project_type plugin)
|
||||
set(enable_warnings OFF)
|
||||
set(create_translations OFF)
|
||||
cmake_policy(SET CMP0144 NEW)
|
||||
|
||||
if(DEFINED DEPENDENCIES_DIR)
|
||||
include(${DEPENDENCIES_DIR}/modorganizer_super/cmake_common/project.cmake)
|
||||
else()
|
||||
include(../cmake_common/project.cmake)
|
||||
project(plugin_python CXX)
|
||||
|
||||
set(Python_FIND_VIRTUALENV STANDARD)
|
||||
|
||||
# find Python before include mo2-cmake, otherwise this will trigger a bunch of CMP0111
|
||||
# due to the imported configuration mapping variables defined in mo2.cmake
|
||||
find_package(Python ${MO2_PYTHON_VERSION} COMPONENTS Interpreter Development REQUIRED)
|
||||
find_package(pybind11 CONFIG REQUIRED)
|
||||
|
||||
find_package(mo2-cmake CONFIG REQUIRED)
|
||||
|
||||
get_filename_component(Python_HOME ${Python_EXECUTABLE} PATH)
|
||||
set(Python_DLL_DIR "${Python_HOME}/DLLs")
|
||||
set(Python_LIB_DIR "${Python_HOME}/Lib")
|
||||
|
||||
mo2_python_install_pyqt()
|
||||
|
||||
# useful for naming DLL, zip, etc. (3.10 -> 310)
|
||||
set(Python_VERSION_SHORT ${Python_VERSION_MAJOR}${Python_VERSION_MINOR})
|
||||
|
||||
# projects
|
||||
add_subdirectory(src)
|
||||
|
||||
# tests (if requested)
|
||||
set(PLUGIN_PYTHON_TESTING ${BUILD_TESTING} CACHE BOOL "build tests for plugin_python")
|
||||
if (PLUGIN_PYTHON_TESTING)
|
||||
enable_testing()
|
||||
add_subdirectory(tests)
|
||||
endif()
|
||||
add_subdirectory(src/proxy)
|
||||
|
||||
add_subdirectory(src/runner)
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
{
|
||||
"configurePresets": [
|
||||
{
|
||||
"errors": {
|
||||
"deprecated": true
|
||||
},
|
||||
"hidden": true,
|
||||
"name": "cmake-dev",
|
||||
"warnings": {
|
||||
"deprecated": true,
|
||||
"dev": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"cacheVariables": {
|
||||
"VCPKG_MANIFEST_NO_DEFAULT_FEATURES": {
|
||||
"type": "BOOL",
|
||||
"value": "ON"
|
||||
}
|
||||
},
|
||||
"toolchainFile": "$env{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake",
|
||||
"hidden": true,
|
||||
"name": "vcpkg"
|
||||
},
|
||||
{
|
||||
"cacheVariables": {
|
||||
"VCPKG_MANIFEST_FEATURES": {
|
||||
"type": "STRING",
|
||||
"value": "testing"
|
||||
}
|
||||
},
|
||||
"hidden": true,
|
||||
"inherits": ["vcpkg"],
|
||||
"name": "vcpkg-dev"
|
||||
},
|
||||
{
|
||||
"binaryDir": "${sourceDir}/vsbuild",
|
||||
"architecture": {
|
||||
"strategy": "set",
|
||||
"value": "x64"
|
||||
},
|
||||
"cacheVariables": {
|
||||
"CMAKE_CXX_FLAGS": "/EHsc /MP /W4",
|
||||
"VCPKG_TARGET_TRIPLET": {
|
||||
"type": "STRING",
|
||||
"value": "x64-windows-static-md"
|
||||
}
|
||||
},
|
||||
"generator": "Visual Studio 17 2022",
|
||||
"inherits": ["cmake-dev", "vcpkg-dev"],
|
||||
"name": "vs2022-windows",
|
||||
"toolset": "v143"
|
||||
},
|
||||
{
|
||||
"cacheVariables": {
|
||||
"VCPKG_MANIFEST_FEATURES": {
|
||||
"type": "STRING",
|
||||
"value": "standalone;testing"
|
||||
}
|
||||
},
|
||||
"inherits": "vs2022-windows",
|
||||
"name": "vs2022-windows-standalone"
|
||||
}
|
||||
],
|
||||
"buildPresets": [
|
||||
{
|
||||
"name": "vs2022-windows",
|
||||
"resolvePackageReferences": "on",
|
||||
"configurePreset": "vs2022-windows"
|
||||
}
|
||||
],
|
||||
"version": 4
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
# ModOrganizer2 - Python Proxy
|
||||
|
||||
This repository contains the Python proxy plugin for ModOrganizer2.
|
||||
The proxy plugin allow developers to write Python plugins for ModOrganizer2.
|
||||
|
||||
## Setup, build, tests
|
||||
|
||||
This repository is part of MO2 main repositories and should usually be build using
|
||||
[`mob`](https://github.com/ModOrganizer2/mob).
|
||||
|
||||
## Organization
|
||||
|
||||
This repositories contains 5 sub-projects in `src`.
|
||||
The interface between Python and C++ is done using the
|
||||
[`pybind11`](https://github.com/pybind/pybind11) library.
|
||||
See the `README` in the subfolder (when there is one) for more details.
|
||||
|
||||
- [`src/proxy`](src/proxy/) contains the actual proxy plugin.
|
||||
This project is a simple interface between MO2 and the runner (see below).
|
||||
The CMake code:
|
||||
- generates the `plugin_python.dll` library,
|
||||
- generates the translation file (under `src/`),
|
||||
- installs necessary files for the plugin (Python DLL, Python libraries, etc),
|
||||
including `mobase`.
|
||||
- [`src/runner`](src/runner/) contains the Python runner. This is the project that
|
||||
instantiates a Python interpreter and load/unload Python plugins.
|
||||
- [`src/pybind11-qt`](src/pybind11-qt/) contains many utility stuff to interface
|
||||
pybind11 with Qt and PyQt.
|
||||
- [`src/pybind11-utils`](src/pybind11-utils/) contains some utility stuff pybind11.
|
||||
This project is header-only.
|
||||
- [`src/mobase`](src/mobase) contains the Python plugin interface.
|
||||
- This projects generates the `mobase` Python library.
|
||||
|
||||
Some (woefully incomplete) tests are available under `tests`, split in three
|
||||
sub-directories:
|
||||
|
||||
- [`tests/mocks`](tests/mocks/) simply contains mocks of `uibase` interfaces to be used
|
||||
in the two other test projects.
|
||||
- [`tests/python`](tests/python/) contains Python tests for `pytest`.
|
||||
This project generates a bunch of Python test libraries that are then imported in
|
||||
Python test files (`test_*.py`) and tested using `pytest`.
|
||||
These tests mostly cover the pybind11 Qt and utility stuff, and some standalone
|
||||
MO2 classes and functions (`IFileTree`, `GuessedString`, etc).
|
||||
- [`tests/runner`](tests/runner/) contains C++ tests, using GTest
|
||||
Tests in this project instantiate a Python runner and then use it to check that
|
||||
plugins implemented in Python can be used properly on the C++ side.
|
||||
|
||||
## Building & Running tests
|
||||
|
||||
Tests are not built by default with `mob`, so you will need to run `cmake` manually
|
||||
with the proper arguments.
|
||||
|
||||
You need to define `PLUGIN_PYTHON_TESTS` with `-DPLUGIN_PYTHON_TESTS` when running
|
||||
the configure step of cmake.
|
||||
|
||||
You can then build the tests
|
||||
|
||||
```bash
|
||||
# replace vsbuild with your build folder
|
||||
cmake --build vsbuild --config RelWithDebInfo --target "python-tests" "runner-tests"
|
||||
```
|
||||
|
||||
To run the tests, use `ctest`
|
||||
|
||||
```bash
|
||||
# replace vsbuild with your build folder
|
||||
ctest.exe --test-dir vsbuild -C RelWithDebInfo
|
||||
```
|
||||
@@ -1,48 +0,0 @@
|
||||
version: 1.0.{build}
|
||||
skip_branch_with_pr: true
|
||||
image: Visual Studio 2019
|
||||
environment:
|
||||
WEBHOOK_URL:
|
||||
secure: gOKbXaZM9ImtMD5XrYITvdyZUW/az082G9OIN1EC1Vbg57wBaeLhi49uGjxPw5GVujHku6kxN6ab89zhbS5GVeluR76GM83IbKV4Sh7udXzoYZZdg6YudtYHzdhCgUeiedpswbuczTq9ceIkkfSEWZuh/lMAAVVwvcGsJAnoPFw=
|
||||
build:
|
||||
parallel: true
|
||||
build_script:
|
||||
- pwsh: >-
|
||||
$ErrorActionPreference = 'Stop'
|
||||
|
||||
git clone --depth=1 --no-single-branch https://github.com/ModOrganizer2/modorganizer-umbrella.git c:\projects\modorganizer-umbrella
|
||||
|
||||
New-Item -ItemType Directory -Path c:\projects\modorganizer-build
|
||||
|
||||
cd c:\projects\modorganizer-umbrella
|
||||
|
||||
($env:APPVEYOR_PULL_REQUEST_HEAD_REPO_BRANCH -eq $null) ? ($branch = $env:APPVEYOR_REPO_BRANCH) : ($branch = $env:APPVEYOR_PULL_REQUEST_HEAD_REPO_BRANCH)
|
||||
|
||||
git checkout $(git show-ref --verify --quiet refs/remotes/origin/${branch} || echo '-b') ${branch}
|
||||
|
||||
C:\Python37-x64\python.exe unimake.py -d c:\projects\modorganizer-build -s Appveyor_Build=True ${env:APPVEYOR_PROJECT_NAME}
|
||||
|
||||
if($LastExitCode -ne 0) { $host.SetShouldExit($LastExitCode ) }
|
||||
artifacts:
|
||||
- path: build\src\proxy\plugin_python.dll
|
||||
name: plugin_python_dll
|
||||
- path: build\src\proxy\plugin_python.pdb
|
||||
name: plugin_python_pdb
|
||||
- path: build\src\proxy\plugin_python.lib
|
||||
name: plugin_python_lib
|
||||
- path: build\src\runner\pythonrunner.dll
|
||||
name: pythonrunner_dll
|
||||
- path: build\src\runner\pythonrunner.pdb
|
||||
name: pythonrunner_pdb
|
||||
- path: build\src\runner\pythonrunner.lib
|
||||
name: pythonrunner_lib
|
||||
on_success:
|
||||
- ps: Set-Location -Path $env:APPVEYOR_BUILD_FOLDER
|
||||
- ps: Invoke-RestMethod https://raw.githubusercontent.com/DiscordHooks/appveyor-discord-webhook/master/send.ps1 -o send.ps1
|
||||
- ps: ./send.ps1 success $env:WEBHOOK_URL
|
||||
on_failure:
|
||||
- ps: Set-Location -Path $env:APPVEYOR_BUILD_FOLDER
|
||||
- ps: Push-AppveyorArtifact ${env:APPVEYOR_BUILD_FOLDER}\stdout.log
|
||||
- ps: Push-AppveyorArtifact ${env:APPVEYOR_BUILD_FOLDER}\stderr.log
|
||||
- ps: Invoke-RestMethod https://raw.githubusercontent.com/DiscordHooks/appveyor-discord-webhook/master/send.ps1 -o send.ps1
|
||||
- ps: ./send.ps1 failure $env:WEBHOOK_URL
|
||||
Generated
+254
@@ -0,0 +1,254 @@
|
||||
# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand.
|
||||
|
||||
[[package]]
|
||||
name = "colorama"
|
||||
version = "0.4.6"
|
||||
description = "Cross-platform colored terminal text."
|
||||
optional = false
|
||||
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7"
|
||||
files = [
|
||||
{file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"},
|
||||
{file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "iniconfig"
|
||||
version = "2.0.0"
|
||||
description = "brain-dead simple config-ini parsing"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"},
|
||||
{file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mobase-stubs"
|
||||
version = "2.5.1a0"
|
||||
description = "PEP561 stub files for the mobase Python API."
|
||||
optional = false
|
||||
python-versions = "<4.0,>=3.12"
|
||||
files = [
|
||||
{file = "mobase_stubs-2.5.1a0-py3-none-any.whl", hash = "sha256:bcaecfae038b890d82280fc518f7e44f38d22d35801a8ba7ffa480f7756d6823"},
|
||||
{file = "mobase_stubs-2.5.1a0.tar.gz", hash = "sha256:a8dc5574336ed3b1f673288447781f705a078472cf8808e05a36f129c81c8e20"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nodeenv"
|
||||
version = "1.9.1"
|
||||
description = "Node.js virtual environment builder"
|
||||
optional = false
|
||||
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7"
|
||||
files = [
|
||||
{file = "nodeenv-1.9.1-py2.py3-none-any.whl", hash = "sha256:ba11c9782d29c27c70ffbdda2d7415098754709be8a7056d79a737cd901155c9"},
|
||||
{file = "nodeenv-1.9.1.tar.gz", hash = "sha256:6ec12890a2dab7946721edbfbcd91f3319c6ccc9aec47be7c7e6b7011ee6645f"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "packaging"
|
||||
version = "24.1"
|
||||
description = "Core utilities for Python packages"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "packaging-24.1-py3-none-any.whl", hash = "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124"},
|
||||
{file = "packaging-24.1.tar.gz", hash = "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pastel"
|
||||
version = "0.2.1"
|
||||
description = "Bring colors to your terminal."
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
||||
files = [
|
||||
{file = "pastel-0.2.1-py2.py3-none-any.whl", hash = "sha256:4349225fcdf6c2bb34d483e523475de5bb04a5c10ef711263452cb37d7dd4364"},
|
||||
{file = "pastel-0.2.1.tar.gz", hash = "sha256:e6581ac04e973cac858828c6202c1e1e81fee1dc7de7683f3e1ffe0bfd8a573d"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pluggy"
|
||||
version = "1.5.0"
|
||||
description = "plugin and hook calling mechanisms for python"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669"},
|
||||
{file = "pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
dev = ["pre-commit", "tox"]
|
||||
testing = ["pytest", "pytest-benchmark"]
|
||||
|
||||
[[package]]
|
||||
name = "poethepoet"
|
||||
version = "0.23.0"
|
||||
description = "A task runner that works well with poetry."
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "poethepoet-0.23.0-py3-none-any.whl", hash = "sha256:d573ff31d7678e62b6f9bc9a1291ae2009ac14e0eead0a450598f9f05abb27a3"},
|
||||
{file = "poethepoet-0.23.0.tar.gz", hash = "sha256:62a0a6a518df5985c191aee0c1fcd2bb6a0a04eb102997786fcdf118e4147d22"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
pastel = ">=0.2.1,<0.3.0"
|
||||
tomli = ">=1.2.2"
|
||||
|
||||
[package.extras]
|
||||
poetry-plugin = ["poetry (>=1.0,<2.0)"]
|
||||
|
||||
[[package]]
|
||||
name = "pybind11-stubgen"
|
||||
version = "2.5.1"
|
||||
description = "PEP 561 type stubs generator for pybind11 modules"
|
||||
optional = false
|
||||
python-versions = "~=3.7"
|
||||
files = [
|
||||
{file = "pybind11-stubgen-2.5.1.tar.gz", hash = "sha256:4427a67038a00c5ac1637ffa6c65728c67c5b1251ecc23c7704152be0b14cc0b"},
|
||||
{file = "pybind11_stubgen-2.5.1-py3-none-any.whl", hash = "sha256:544d49df57da827c8761e7f6ef6bca996df80a33c9fd21c2521d694d4e72fe8d"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pyqt6"
|
||||
version = "6.7.0"
|
||||
description = "Python bindings for the Qt cross platform application toolkit"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "PyQt6-6.7.0-1-cp38-abi3-macosx_10_14_universal2.whl", hash = "sha256:656734112853fde1be0963f0ad362e5efd87ba6c6ff234cb1f9fe8003ee254e6"},
|
||||
{file = "PyQt6-6.7.0-1-cp38-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:fa2d27fc2f5340f3f1e145c815101ef4550771a9e4bfafd4c7c2479fe83d9488"},
|
||||
{file = "PyQt6-6.7.0-1-cp38-abi3-win_amd64.whl", hash = "sha256:6a1f6dfe03752f888b5e628c208f9fd1a03bda7ebda59ffed8c13580289a1892"},
|
||||
{file = "PyQt6-6.7.0-cp38-abi3-macosx_10_14_universal2.whl", hash = "sha256:919ffb01020ece42209228bf94b4f2c156a6b77cc5a69a90a05e358b0333750b"},
|
||||
{file = "PyQt6-6.7.0-cp38-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:e294f025f94493ee12b66efd6893fab309c9063172bb8a5b184f84dfc1ebcc49"},
|
||||
{file = "PyQt6-6.7.0-cp38-abi3-win_amd64.whl", hash = "sha256:9d8865fb6357dba032002c4554a9648e88f2b4706c929cc51fba58edafad91fc"},
|
||||
{file = "PyQt6-6.7.0.tar.gz", hash = "sha256:3d31b2c59dc378ee26e16586d9469842483588142fc377280aad22aaf2fa6235"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
PyQt6-Qt6 = ">=6.7.0,<6.8.0"
|
||||
PyQt6-sip = ">=13.6,<14"
|
||||
|
||||
[[package]]
|
||||
name = "pyqt6-qt6"
|
||||
version = "6.7.2"
|
||||
description = "The subset of a Qt installation needed by PyQt6."
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
{file = "PyQt6_Qt6-6.7.2-py3-none-macosx_10_14_x86_64.whl", hash = "sha256:065415589219a2f364aba29d6a98920bb32810286301acbfa157e522d30369e3"},
|
||||
{file = "PyQt6_Qt6-6.7.2-py3-none-macosx_11_0_arm64.whl", hash = "sha256:7f817efa86a0e8eda9152c85b73405463fbf3266299090f32bbb2266da540ead"},
|
||||
{file = "PyQt6_Qt6-6.7.2-py3-none-manylinux_2_28_x86_64.whl", hash = "sha256:fc93945eaef4536d68bd53566535efcbe78a7c05c2a533790a8fd022bac8bfaa"},
|
||||
{file = "PyQt6_Qt6-6.7.2-py3-none-win_amd64.whl", hash = "sha256:b2d7e5ddb1b9764cd60f1d730fa7bf7a1f0f61b2630967c81761d3d0a5a8a2e0"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pyqt6-sip"
|
||||
version = "13.6.0"
|
||||
description = "The sip module support for PyQt6"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "PyQt6_sip-13.6.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d6b5f699aaed0ac1fcd23e8fbca70d8a77965831b7c1ce474b81b1678817a49d"},
|
||||
{file = "PyQt6_sip-13.6.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:8c282062125eea5baf830c6998587d98c50be7c3a817a057fb95fef647184012"},
|
||||
{file = "PyQt6_sip-13.6.0-cp310-cp310-win32.whl", hash = "sha256:fa759b6339ff7e25f9afe2a6b651b775f0a36bcb3f5fa85e81a90d3b033c83f4"},
|
||||
{file = "PyQt6_sip-13.6.0-cp310-cp310-win_amd64.whl", hash = "sha256:8f9df9f7ccd8a9f0f1d36948c686f03ce1a1281543a3e636b7b7d5e086e1a436"},
|
||||
{file = "PyQt6_sip-13.6.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:5b9c6b6f9cfccb48cbb78a59603145a698fb4ffd176764d7083e5bf47631d8df"},
|
||||
{file = "PyQt6_sip-13.6.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:86a7b67c64436e32bffa9c28c9f21bf14a9faa54991520b12c3f6f435f24df7f"},
|
||||
{file = "PyQt6_sip-13.6.0-cp311-cp311-win32.whl", hash = "sha256:58f68a48400e0b3d1ccb18090090299bad26e3aed7ccb7057c65887b79b8aeea"},
|
||||
{file = "PyQt6_sip-13.6.0-cp311-cp311-win_amd64.whl", hash = "sha256:0dfd22cfedd87e96f9d51e0778ca2ba3dc0be83e424e9e0f98f6994d8d9c90f0"},
|
||||
{file = "PyQt6_sip-13.6.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:3bf03e130fbfd75c9c06e687b86ba375410c7a9e835e4e03285889e61dd4b0c4"},
|
||||
{file = "PyQt6_sip-13.6.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:43fb8551796030aae3d66d6e35e277494071ec6172cd182c9569ab7db268a2f5"},
|
||||
{file = "PyQt6_sip-13.6.0-cp312-cp312-win32.whl", hash = "sha256:13885361ca2cb2f5085d50359ba61b3fabd41b139fb58f37332acbe631ef2357"},
|
||||
{file = "PyQt6_sip-13.6.0-cp312-cp312-win_amd64.whl", hash = "sha256:24441032a29791e82beb7dfd76878339058def0e97fdb7c1cea517f3a0e6e96b"},
|
||||
{file = "PyQt6_sip-13.6.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:3075d8b325382750829e6cde6971c943352309d35768a4d4da0587459606d562"},
|
||||
{file = "PyQt6_sip-13.6.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:a6ce80bc24618d8a41be8ca51ad9f10e8bc4296dd90ab2809573df30a23ae0e5"},
|
||||
{file = "PyQt6_sip-13.6.0-cp38-cp38-win32.whl", hash = "sha256:fa7b10af7488efc5e53b41dd42c0f421bde6c2865a107af7ae259aff9d841da9"},
|
||||
{file = "PyQt6_sip-13.6.0-cp38-cp38-win_amd64.whl", hash = "sha256:9adf672f9114687533a74d5c2d4c03a9a929ad5ad9c3e88098a7da1a440ab916"},
|
||||
{file = "PyQt6_sip-13.6.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:98bf954103b087162fa63b3a78f30b0b63da22fd6450b610ec1b851dbb798228"},
|
||||
{file = "PyQt6_sip-13.6.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:39854dba35f8e5a4288da26ecb5f40b4c5ec1932efffb3f49d5ea435a7f37fb3"},
|
||||
{file = "PyQt6_sip-13.6.0-cp39-cp39-win32.whl", hash = "sha256:747f6ca44af81777a2c696bd501bc4815a53ec6fc94d4e25830e10bc1391f8ab"},
|
||||
{file = "PyQt6_sip-13.6.0-cp39-cp39-win_amd64.whl", hash = "sha256:33ea771fe777eb0d1a2c3ef35bcc3f7a286eb3ff09cd5b2fdd3d87d1f392d7e8"},
|
||||
{file = "PyQt6_sip-13.6.0.tar.gz", hash = "sha256:2486e1588071943d4f6657ba09096dc9fffd2322ad2c30041e78ea3f037b5778"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pyright"
|
||||
version = "1.1.369"
|
||||
description = "Command line wrapper for pyright"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "pyright-1.1.369-py3-none-any.whl", hash = "sha256:06d5167a8d7be62523ced0265c5d2f1e022e110caf57a25d92f50fb2d07bcda0"},
|
||||
{file = "pyright-1.1.369.tar.gz", hash = "sha256:ad290710072d021e213b98cc7a2f90ae3a48609ef5b978f749346d1a47eb9af8"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
nodeenv = ">=1.6.0"
|
||||
|
||||
[package.extras]
|
||||
all = ["twine (>=3.4.1)"]
|
||||
dev = ["twine (>=3.4.1)"]
|
||||
|
||||
[[package]]
|
||||
name = "pytest"
|
||||
version = "8.2.2"
|
||||
description = "pytest: simple powerful testing with Python"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "pytest-8.2.2-py3-none-any.whl", hash = "sha256:c434598117762e2bd304e526244f67bf66bbd7b5d6cf22138be51ff661980343"},
|
||||
{file = "pytest-8.2.2.tar.gz", hash = "sha256:de4bb8104e201939ccdc688b27a89a7be2079b22e2bd2b07f806b6ba71117977"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
colorama = {version = "*", markers = "sys_platform == \"win32\""}
|
||||
iniconfig = "*"
|
||||
packaging = "*"
|
||||
pluggy = ">=1.5,<2.0"
|
||||
|
||||
[package.extras]
|
||||
dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"]
|
||||
|
||||
[[package]]
|
||||
name = "ruff"
|
||||
version = "0.2.2"
|
||||
description = "An extremely fast Python linter and code formatter, written in Rust."
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "ruff-0.2.2-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:0a9efb032855ffb3c21f6405751d5e147b0c6b631e3ca3f6b20f917572b97eb6"},
|
||||
{file = "ruff-0.2.2-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:d450b7fbff85913f866a5384d8912710936e2b96da74541c82c1b458472ddb39"},
|
||||
{file = "ruff-0.2.2-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ecd46e3106850a5c26aee114e562c329f9a1fbe9e4821b008c4404f64ff9ce73"},
|
||||
{file = "ruff-0.2.2-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5e22676a5b875bd72acd3d11d5fa9075d3a5f53b877fe7b4793e4673499318ba"},
|
||||
{file = "ruff-0.2.2-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1695700d1e25a99d28f7a1636d85bafcc5030bba9d0578c0781ba1790dbcf51c"},
|
||||
{file = "ruff-0.2.2-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:b0c232af3d0bd8f521806223723456ffebf8e323bd1e4e82b0befb20ba18388e"},
|
||||
{file = "ruff-0.2.2-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f63d96494eeec2fc70d909393bcd76c69f35334cdbd9e20d089fb3f0640216ca"},
|
||||
{file = "ruff-0.2.2-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6a61ea0ff048e06de273b2e45bd72629f470f5da8f71daf09fe481278b175001"},
|
||||
{file = "ruff-0.2.2-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5e1439c8f407e4f356470e54cdecdca1bd5439a0673792dbe34a2b0a551a2fe3"},
|
||||
{file = "ruff-0.2.2-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:940de32dc8853eba0f67f7198b3e79bc6ba95c2edbfdfac2144c8235114d6726"},
|
||||
{file = "ruff-0.2.2-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:0c126da55c38dd917621552ab430213bdb3273bb10ddb67bc4b761989210eb6e"},
|
||||
{file = "ruff-0.2.2-py3-none-musllinux_1_2_i686.whl", hash = "sha256:3b65494f7e4bed2e74110dac1f0d17dc8e1f42faaa784e7c58a98e335ec83d7e"},
|
||||
{file = "ruff-0.2.2-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:1ec49be4fe6ddac0503833f3ed8930528e26d1e60ad35c2446da372d16651ce9"},
|
||||
{file = "ruff-0.2.2-py3-none-win32.whl", hash = "sha256:d920499b576f6c68295bc04e7b17b6544d9d05f196bb3aac4358792ef6f34325"},
|
||||
{file = "ruff-0.2.2-py3-none-win_amd64.whl", hash = "sha256:cc9a91ae137d687f43a44c900e5d95e9617cb37d4c989e462980ba27039d239d"},
|
||||
{file = "ruff-0.2.2-py3-none-win_arm64.whl", hash = "sha256:c9d15fc41e6054bfc7200478720570078f0b41c9ae4f010bcc16bd6f4d1aacdd"},
|
||||
{file = "ruff-0.2.2.tar.gz", hash = "sha256:e62ed7f36b3068a30ba39193a14274cd706bc486fad521276458022f7bccb31d"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tomli"
|
||||
version = "2.0.1"
|
||||
description = "A lil' TOML parser"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"},
|
||||
{file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"},
|
||||
]
|
||||
|
||||
[metadata]
|
||||
lock-version = "2.0"
|
||||
python-versions = "^3.12"
|
||||
content-hash = "4a3746f1080ab40c4cfde6777517db502e124fe088e971895bd7f7c245c3fa3e"
|
||||
@@ -0,0 +1,53 @@
|
||||
[tool.poetry]
|
||||
name = "modorganizer-plugin_python"
|
||||
version = "3.0.0"
|
||||
description = ""
|
||||
authors = ["Mikaël Capelle <capelle.mikael@gmail.com>"]
|
||||
|
||||
[tool.poetry.dependencies]
|
||||
python = "^3.12"
|
||||
|
||||
[tool.poetry.group.dev.dependencies]
|
||||
pyright = "^1.1.369"
|
||||
ruff = "^0.2.1"
|
||||
poethepoet = "^0.23.0"
|
||||
mobase-stubs = { version = "^2.5.1a0", allow-prereleases = true }
|
||||
pyqt6 = "^6.7.0"
|
||||
pytest = "^8.2.2"
|
||||
pybind11-stubgen = "^2.5.1"
|
||||
|
||||
[tool.poe.tasks]
|
||||
format-imports = "ruff check --select I tests typings --fix"
|
||||
format-ruff = "ruff format tests typings"
|
||||
format.sequence = ["format-imports", "format-ruff"]
|
||||
lint-ruff = "ruff check tests typings"
|
||||
lint-ruff-format = "ruff format --check tests typings"
|
||||
lint.sequence = ["lint-ruff", "lint-ruff-format"]
|
||||
lint.ignore_fail = "return_non_zero"
|
||||
|
||||
[tool.ruff]
|
||||
target-version = "py312"
|
||||
|
||||
[tool.ruff.lint]
|
||||
extend-select = ["B", "Q", "I"]
|
||||
|
||||
[tool.ruff.lint.isort.sections]
|
||||
mobase = ["mobase"]
|
||||
mobase_tests = ["mobase_tests"]
|
||||
|
||||
[tool.ruff.lint.isort]
|
||||
section-order = [
|
||||
"future",
|
||||
"standard-library",
|
||||
"third-party",
|
||||
"first-party",
|
||||
"mobase",
|
||||
"mobase_tests",
|
||||
"local-folder",
|
||||
]
|
||||
|
||||
[tool.pyright]
|
||||
typeCheckingMode = "strict"
|
||||
reportMissingTypeStubs = true
|
||||
reportMissingModuleSource = false
|
||||
pythonPlatform = "Windows"
|
||||
@@ -0,0 +1,8 @@
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
# order matters
|
||||
add_subdirectory(pybind11-qt)
|
||||
add_subdirectory(pybind11-utils)
|
||||
add_subdirectory(mobase)
|
||||
add_subdirectory(runner)
|
||||
add_subdirectory(proxy)
|
||||
@@ -0,0 +1,38 @@
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
find_package(Qt6 COMPONENTS Core)
|
||||
find_package(mo2-uibase CONFIG REQUIRED)
|
||||
|
||||
pybind11_add_module(mobase MODULE)
|
||||
mo2_default_source_group()
|
||||
mo2_configure_target(mobase
|
||||
NO_SOURCES
|
||||
WARNINGS 4
|
||||
EXTERNAL_WARNINGS 4
|
||||
AUTOMOC ON
|
||||
TRANSLATIONS OFF
|
||||
)
|
||||
mo2_target_sources(mobase
|
||||
FOLDER src
|
||||
PRIVATE
|
||||
deprecation.cpp
|
||||
deprecation.h
|
||||
mobase.cpp
|
||||
pybind11_all.h
|
||||
)
|
||||
mo2_target_sources(mobase
|
||||
FOLDER src/wrappers
|
||||
PRIVATE
|
||||
./wrappers/basic_classes.cpp
|
||||
./wrappers/game_features.cpp
|
||||
./wrappers/known_folders.h
|
||||
./wrappers/pyfiletree.cpp
|
||||
./wrappers/pyfiletree.h
|
||||
./wrappers/pyplugins.cpp
|
||||
./wrappers/pyplugins.h
|
||||
./wrappers/utils.cpp
|
||||
./wrappers/widgets.cpp
|
||||
./wrappers/wrappers.cpp
|
||||
./wrappers/wrappers.h
|
||||
)
|
||||
target_link_libraries(mobase PRIVATE pybind11::qt pybind11::utils mo2::uibase Qt6::Core)
|
||||
@@ -0,0 +1,110 @@
|
||||
# mobase
|
||||
|
||||
`mobase` is a ModOrganizer2 Python API.
|
||||
It provides access to the part of
|
||||
[`uibase`](https://github.com/ModOrganizer2/modorganizer-uibase) C++ API from
|
||||
Python through [`pybind11`](https://github.com/pybind/pybind11).
|
||||
|
||||
## Organization
|
||||
|
||||
**Important:** All (most) files should include `pybind11_all.h` (either directly
|
||||
or through another header) to get proper `type_caster` available.
|
||||
|
||||
- `mobase.cpp` contains the `PYBIND11_MODULE` definition of `mobase` but is otherwise
|
||||
the entrypoint for other functions.
|
||||
- `wrappers.h` contains the declaration of most functions implemented under
|
||||
`wrappers/`.
|
||||
- The other files under `wrappers/` contains bindings and trampoline classes (see
|
||||
below) for `uibase` classes.
|
||||
- `basic_classes.cpp` contains the bindings for most classes that cannot be extended
|
||||
in Python (`IOrganizer`, `IModInterface`, etc.)
|
||||
- `game_features.cpp` contains the bindings and trampoline classes for game features.
|
||||
- `pyfiletree.h` and `pyfiletree.cpp` contains bindings for the `IFileTree`-related
|
||||
classes.
|
||||
- `pyplugins.h` contains the trampoline classes for the `IPluginXXX` classes and
|
||||
`pyplugins.cpp` the bindings.
|
||||
- `pyplugins.h` is required since the trampoline classes are tagged with `Q_OBJECT`,
|
||||
and MOC does not work if the classes are declared in a C++ file.
|
||||
- `pyplugins.cpp` also contains the `extract_plugins` function in `mobase.private`
|
||||
that is used to extract plugins from Python object in the runner.
|
||||
- `widgets.cpp` contains the bindings for the widget classes.
|
||||
- `wrappers.cpp` contains the trampoline and bindings for non-plugin classes that can
|
||||
be extended through Python.
|
||||
|
||||
## Updating mobase
|
||||
|
||||
### Classes that cannot be extended through Python
|
||||
|
||||
Updating or adding classes that cannot be extended through Python is quite easily.
|
||||
One simply needs to declare the appropriate `py::class_` or add new `.def()`.
|
||||
|
||||
See below for things to remember when creating pybind11 bindings.
|
||||
|
||||
### Free functions
|
||||
|
||||
Similar to classes that cannot be extended through Python, see above.
|
||||
|
||||
### Classes that can be extended through Python: Plugins
|
||||
|
||||
To extend plugins, simply update the trampoline classes in `pyplugins.h` and the
|
||||
bindings in `pyplugins.cpp`.
|
||||
|
||||
**Note:** For new plugins, simply look at the existing one.
|
||||
|
||||
### Classes that can be extended through Python: Game Features
|
||||
|
||||
To extend or expose game features:
|
||||
|
||||
- Create (if there is not already one) a trampoline class for the feature in
|
||||
`game_features.cpp`.
|
||||
- Add implementation of missing functions if required.
|
||||
- Add the bindings in `add_game_feature_bindings` in `game_features.cpp`.
|
||||
- For new feature, add the feature type to `GameFeaturesHelper::GameFeatures` in
|
||||
`game_features.cpp`.
|
||||
|
||||
### Classes that can be extended through Python: Others
|
||||
|
||||
Non-plugin classes should be added to the `wrappers.cpp` file and should be exposed
|
||||
with `std::shared_ptr<>` or `qobject_holder<>` holders.
|
||||
|
||||
- If the classes extends `QObject`, use a `qobject_holder`.
|
||||
- Otherwise use a `std::shared_ptr<>` holder and add a `MO2_PYBIND11_SHARED_CPP_HOLDER`
|
||||
declaration in `pybind11_all.h`.
|
||||
|
||||
Trampoline can be defined directly in `wrappers.cpp`, and bindings in the appropriate
|
||||
function.
|
||||
See the existing classes for example.
|
||||
|
||||
**Important:**
|
||||
You need to make sure that `uibase` manipulates such classes through
|
||||
`std::shared_ptr<>` (unless those inherit `QObject`).
|
||||
Using `std::unique_ptr<>` is not possible since `std::unique_ptr<>` cannot have custom
|
||||
runtime-specified deleters.
|
||||
|
||||
## Things to remember
|
||||
|
||||
Here are a few things to remember when creating bindings:
|
||||
|
||||
- If a function has multiple overloads that can conflict in Python, the more complex
|
||||
one must be defined first as pybind11 will try calling them in order.
|
||||
- If a C++ function expect a `QString`, `QFileInfo` or `QDir` that represents a file or
|
||||
a directory, wrapping the function with `wrap_for_filepath` or `wrap_for_directory` is
|
||||
a good idea. This allows Python to call the function with `pathlib.Path`.
|
||||
- Most of the C++ function taking a reference to modify in C++ cannot be directly
|
||||
exposed in Python since Python cannot modify reference to simple type (e.g.
|
||||
`QString&` or `int&`).
|
||||
The best way to expose such function is to bind a lambda that returns a variant from
|
||||
Python, e.g.
|
||||
|
||||
```cpp
|
||||
// assume the C++ function is QString fn(QString& foo, QString const& bar, int& maz);
|
||||
|
||||
m.def("function", [](QString& foo, QString const& bar, int& maz) {
|
||||
// call the function
|
||||
auto ret = function(foo, bar, maz);
|
||||
|
||||
// make a tuple containing the return value (if there is one), and the modified
|
||||
// values passed by reference
|
||||
return std::make_tuple(ret, foo, maz);
|
||||
});
|
||||
```
|
||||
@@ -0,0 +1,55 @@
|
||||
#include "deprecation.h"
|
||||
|
||||
#include <filesystem>
|
||||
#include <set>
|
||||
|
||||
#include <pybind11/pybind11.h>
|
||||
|
||||
#include <QCoreApplication>
|
||||
|
||||
#include <uibase/log.h>
|
||||
|
||||
namespace py = pybind11;
|
||||
|
||||
namespace mo2::python {
|
||||
|
||||
void show_deprecation_warning(std::string_view name, std::string_view message,
|
||||
bool show_once)
|
||||
{
|
||||
|
||||
// Contains the list of filename / line number for which a deprecation
|
||||
// warning has already been shown.
|
||||
static std::set<std::pair<std::string, int>> DeprecatedLines;
|
||||
|
||||
// Find the caller:
|
||||
auto inspect = py::module_::import("inspect");
|
||||
auto current_frame = inspect.attr("currentframe")();
|
||||
py::sequence callable_frame = inspect.attr("getouterframes")(current_frame, 2);
|
||||
auto last_frame = callable_frame[py::int_(-1)];
|
||||
auto filename = last_frame.attr("filename").cast<std::string>();
|
||||
auto function = last_frame.attr("function").cast<std::string>();
|
||||
auto lineno = last_frame.attr("lineno").cast<int>();
|
||||
|
||||
// Only show once if requested:
|
||||
if (show_once && DeprecatedLines.contains({filename, lineno})) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Register the deprecation:
|
||||
DeprecatedLines.emplace(filename, lineno);
|
||||
|
||||
auto path = relative(std::filesystem::path(filename),
|
||||
QCoreApplication::applicationDirPath().toStdWString());
|
||||
|
||||
// Show the message:
|
||||
if (message.empty()) {
|
||||
MOBase::log::warn("[deprecated] {} in {} [{}:{}].", name, function,
|
||||
path.native(), lineno);
|
||||
}
|
||||
else {
|
||||
MOBase::log::warn("[deprecated] {} in {} [{}:{}]: {}", name, function,
|
||||
path.native(), lineno, message);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace mo2::python
|
||||
@@ -0,0 +1,27 @@
|
||||
#ifndef PYTHONRUNNER_UTILS_H
|
||||
#define PYTHONRUNNER_UTILS_H
|
||||
|
||||
#include <string_view>
|
||||
|
||||
#include <pybind11/pybind11.h>
|
||||
|
||||
namespace mo2::python {
|
||||
|
||||
/**
|
||||
* @brief Show a deprecation warning.
|
||||
*
|
||||
* This methods will print a warning in MO2 log containing the location of
|
||||
* the call to the deprecated function. If show_once is true, the
|
||||
* deprecation warning will only be logged the first time the function is
|
||||
* called at this location.
|
||||
*
|
||||
* @param name Name of the deprecated function.
|
||||
* @param message Deprecation message.
|
||||
* @param show_once Only show the message once per call location.
|
||||
*/
|
||||
void show_deprecation_warning(std::string_view name, std::string_view message = "",
|
||||
bool show_once = true);
|
||||
|
||||
} // namespace mo2::python
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,97 @@
|
||||
#pragma warning(disable : 4100)
|
||||
#pragma warning(disable : 4996)
|
||||
|
||||
#include <format>
|
||||
#include <tuple>
|
||||
#include <variant>
|
||||
|
||||
#include <uibase/exceptions.h>
|
||||
#include <uibase/versioning.h>
|
||||
|
||||
#include <pybind11/embed.h>
|
||||
|
||||
#include "pybind11_all.h"
|
||||
|
||||
#include "wrappers/pyfiletree.h"
|
||||
#include "wrappers/wrappers.h"
|
||||
|
||||
using namespace MOBase;
|
||||
namespace py = pybind11;
|
||||
|
||||
PYBIND11_MODULE(mobase, m)
|
||||
{
|
||||
using namespace mo2::python;
|
||||
|
||||
m.add_object("PyQt6", py::module_::import("PyQt6"));
|
||||
m.add_object("PyQt6.QtCore", py::module_::import("PyQt6.QtCore"));
|
||||
m.add_object("PyQt6.QtGui", py::module_::import("PyQt6.QtGui"));
|
||||
m.add_object("PyQt6.QtWidgets", py::module_::import("PyQt6.QtWidgets"));
|
||||
|
||||
// exceptions
|
||||
//
|
||||
py::register_exception<Exception>(m, "MO2Exception");
|
||||
py::register_exception<InvalidNXMLinkException>(m, "InvalidNXMLinkException");
|
||||
py::register_exception<IncompatibilityException>(m, "IncompatibilityException");
|
||||
py::register_exception<InvalidVersionException>(m, "InvalidVersionException");
|
||||
|
||||
// bindings
|
||||
//
|
||||
mo2::python::add_basic_bindings(m);
|
||||
mo2::python::add_wrapper_bindings(m);
|
||||
|
||||
// game features must be added before plugins
|
||||
mo2::python::add_game_feature_bindings(m);
|
||||
mo2::python::add_igamefeatures_classes(m);
|
||||
|
||||
mo2::python::add_plugins_bindings(m);
|
||||
|
||||
// widgets
|
||||
//
|
||||
py::module_ widgets = m.def_submodule("widgets");
|
||||
mo2::python::add_widget_bindings(widgets);
|
||||
|
||||
// utils
|
||||
//
|
||||
py::module_ utils = m.def_submodule("utils");
|
||||
mo2::python::add_utils_bindings(utils);
|
||||
|
||||
// functions
|
||||
//
|
||||
m.def("getFileVersion", wrap_for_filepath(&MOBase::getFileVersion),
|
||||
py::arg("filepath"));
|
||||
m.def("getProductVersion", wrap_for_filepath(&MOBase::getProductVersion),
|
||||
py::arg("executable"));
|
||||
m.def("getIconForExecutable", wrap_for_filepath(&MOBase::iconForExecutable),
|
||||
py::arg("executable"));
|
||||
|
||||
// typing stuff to be consistent with stubs and allow plugin developers to properly
|
||||
// type their code if they want
|
||||
{
|
||||
m.add_object("TypeVar", py::module_::import("typing").attr("TypeVar"));
|
||||
|
||||
auto s = m.attr("__dict__");
|
||||
|
||||
// expose MoVariant
|
||||
//
|
||||
// this needs to be defined, otherwise MoVariant is not found when actually
|
||||
// running plugins through MO2, making them crash (if plugins use MoVariant in
|
||||
// their own code)
|
||||
//
|
||||
m.add_object(
|
||||
"MoVariant",
|
||||
py::eval(
|
||||
"None | bool | int | str | float | list[object] | dict[str, object]"));
|
||||
|
||||
// same thing for GameFeatureType
|
||||
//
|
||||
m.add_object("GameFeatureType", py::eval("TypeVar('GameFeatureType')", s));
|
||||
}
|
||||
|
||||
// private stuff for debugging/test
|
||||
py::module_ moprivate = m.def_submodule("private");
|
||||
|
||||
// expose a function to create a particular tree, only for debugging
|
||||
// purpose, not in mobase.
|
||||
mo2::python::add_make_tree_function(moprivate);
|
||||
moprivate.def("extract_plugins", &mo2::python::extract_plugins);
|
||||
}
|
||||
@@ -0,0 +1,145 @@
|
||||
#ifndef PYTHON_PYBIND11_ALL_H
|
||||
#define PYTHON_PYBIND11_ALL_H
|
||||
|
||||
#include <filesystem>
|
||||
|
||||
#include <QDir>
|
||||
|
||||
#include <pybind11/operators.h>
|
||||
#include <pybind11/pybind11.h>
|
||||
#include <pybind11/stl.h>
|
||||
#include <pybind11/stl/filesystem.h>
|
||||
|
||||
#include "pybind11_qt/pybind11_qt.h"
|
||||
|
||||
#include "pybind11_utils/functional.h"
|
||||
#include "pybind11_utils/shared_cpp_owner.h"
|
||||
#include "pybind11_utils/smart_variant_wrapper.h"
|
||||
|
||||
#include <uibase/game_features/game_feature.h>
|
||||
#include <uibase/isavegame.h>
|
||||
#include <uibase/pluginrequirements.h>
|
||||
|
||||
namespace mo2::python {
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <>
|
||||
struct smart_variant_converter<QString> {
|
||||
|
||||
static QString from(std::filesystem::path const& path)
|
||||
{
|
||||
return QString::fromStdWString(path.native());
|
||||
}
|
||||
|
||||
static QString from(QFileInfo const& fileInfo)
|
||||
{
|
||||
return fileInfo.filePath();
|
||||
}
|
||||
|
||||
static QString from(QDir const& dir) { return dir.path(); }
|
||||
};
|
||||
|
||||
template <>
|
||||
struct smart_variant_converter<std::filesystem::path> {
|
||||
|
||||
static std::filesystem::path from(QString const& value)
|
||||
{
|
||||
return {value.toStdWString()};
|
||||
}
|
||||
|
||||
static std::filesystem::path from(QFileInfo const& fileInfo)
|
||||
{
|
||||
return fileInfo.filesystemFilePath();
|
||||
}
|
||||
|
||||
static std::filesystem::path from(QDir const& dir)
|
||||
{
|
||||
return dir.filesystemPath();
|
||||
}
|
||||
};
|
||||
|
||||
// we do not need specialization for QFileInfo and QDir because both of them can
|
||||
// be constructed from std::filesystem::path and QString already
|
||||
|
||||
} // namespace detail
|
||||
|
||||
using FileWrapper = smart_variant<QString, std::filesystem::path, QFileInfo>;
|
||||
using DirectoryWrapper = smart_variant<QString, std::filesystem::path, QDir>;
|
||||
|
||||
// wrap the given function to accept FileWrapper (str | PathLike | QFileInfo) at the
|
||||
// given argument positions (or any valid positions if Is... is empty)
|
||||
//
|
||||
template <std::size_t... Is, class Fn>
|
||||
auto wrap_for_filepath(Fn&& fn)
|
||||
{
|
||||
return mo2::python::wrap_arguments<FileWrapper, Is...>(std::forward<Fn>(fn));
|
||||
}
|
||||
|
||||
// wrap the given function to accept DirectoryWrapper (str | PathLike | QDir)
|
||||
// at the given argument positions (or any valid positions if Is... is empty)
|
||||
//
|
||||
template <std::size_t... Is, class Fn>
|
||||
auto wrap_for_directory(Fn&& fn)
|
||||
{
|
||||
return mo2::python::wrap_arguments<DirectoryWrapper, Is...>(
|
||||
std::forward<Fn>(fn));
|
||||
}
|
||||
|
||||
// wrap a function-like object to return a FileWrapper instead of its return type,
|
||||
// useful to generate proper typing in Python
|
||||
//
|
||||
// note that QFileInfo has a __fspath__ in Python, so it is quite easy to convert
|
||||
// from "FileWrapper", a.k.a., str | os.PathLike | QFileInfo to Path by simply
|
||||
// calling Path() on the return type if necessary
|
||||
//
|
||||
// this should be combined with custom return-value in PYBIND11_OVERRIDE(_PURE), see
|
||||
// ISaveGame binding for an example
|
||||
//
|
||||
template <class Fn>
|
||||
auto wrap_return_for_filepath(Fn&& fn)
|
||||
{
|
||||
return mo2::python::wrap_return<FileWrapper>(std::forward<Fn>(fn));
|
||||
}
|
||||
|
||||
// similar to wrap_return_for_filepath, except it returns a DirectoryWrapper instead
|
||||
// of its return type
|
||||
//
|
||||
// this is much less practical than wrap_return_for_filepath since QDir does not
|
||||
// expose __fspath__, so more complex things need to be done in Python, which is why
|
||||
// this should be used carefully (e.g., should not be used if the return type is
|
||||
// already QDir)
|
||||
//
|
||||
template <class Fn>
|
||||
auto wrap_return_for_directory(Fn&& fn)
|
||||
{
|
||||
return mo2::python::wrap_return<DirectoryWrapper>(std::forward<Fn>(fn));
|
||||
}
|
||||
|
||||
// convert a QList to QStringList - QString must be constructible from QString
|
||||
//
|
||||
template <class T>
|
||||
QStringList toQStringList(QList<T> const& list)
|
||||
{
|
||||
static_assert(std::is_constructible_v<QString, T>,
|
||||
"QString must be constructible from T.");
|
||||
return {list.begin(), list.end()};
|
||||
}
|
||||
|
||||
// convert a QStringList to a QList - T must be constructible from QString
|
||||
//
|
||||
template <class T>
|
||||
QList<T> toQList(QStringList const& list)
|
||||
{
|
||||
static_assert(std::is_constructible_v<T, QString>,
|
||||
"T must be constructible from QString.");
|
||||
return {list.begin(), list.end()};
|
||||
}
|
||||
|
||||
} // namespace mo2::python
|
||||
|
||||
MO2_PYBIND11_SHARED_CPP_HOLDER(MOBase::IPluginRequirement)
|
||||
MO2_PYBIND11_SHARED_CPP_HOLDER(MOBase::ISaveGame)
|
||||
MO2_PYBIND11_SHARED_CPP_HOLDER(MOBase::GameFeature)
|
||||
|
||||
#endif
|
||||
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