From 1bffcfa8bfba93a9505692b11fdd3f0903983542 Mon Sep 17 00:00:00 2001 From: Mikael CAPELLE Date: Mon, 10 Jul 2023 09:10:30 +0200 Subject: [PATCH 1/5] Fix line-ending and force them through gitattributes. --- .gitattributes | 8 + src/proxy/proxypython.cpp | 582 +++++++++++++++++++------------------- src/proxy/proxypython.h | 152 +++++----- src/proxy/resource.h | 12 +- 4 files changed, 381 insertions(+), 373 deletions(-) create mode 100644 .gitattributes diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..e613fd7 --- /dev/null +++ b/.gitattributes @@ -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 diff --git a/src/proxy/proxypython.cpp b/src/proxy/proxypython.cpp index c7c9747..31d84f7 100644 --- a/src/proxy/proxypython.cpp +++ b/src/proxy/proxypython.cpp @@ -1,291 +1,291 @@ -/* -Copyright (C) 2022 Sebastian Herbord & MO2 Team. All rights reserved. - -This file is part of python proxy plugin for MO - -python proxy plugin is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Python proxy plugin is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with python proxy plugin. If not, see . -*/ -#include "proxypython.h" - -#include - -#include - -#include -#include -#include -#include -#include - -#include -#include -#include - -namespace fs = std::filesystem; -using namespace MOBase; - -// retrieve the path to the folder containing the proxy DLL -fs::path getPluginFolder() -{ - wchar_t path[MAX_PATH]; - HMODULE hm = NULL; - - if (GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | - GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, - (LPCWSTR)&getPluginFolder, &hm) == 0) { - return {}; - } - if (GetModuleFileName(hm, path, sizeof(path)) == 0) { - return {}; - } - - return fs::path(path).parent_path(); -} - -ProxyPython::ProxyPython() - : m_MOInfo{nullptr}, m_RunnerLib{nullptr}, m_Runner{nullptr}, - m_LoadFailure(FailureType::NONE) -{ -} - -bool ProxyPython::init(IOrganizer* moInfo) -{ - m_MOInfo = moInfo; - - if (m_MOInfo && !m_MOInfo->isPluginEnabled(this)) { - return false; - } - - if (QCoreApplication::applicationDirPath().contains(';')) { - m_LoadFailure = FailureType::SEMICOLON; - return true; - } - - const auto pluginFolder = getPluginFolder(); - - if (pluginFolder.empty()) { - DWORD error = ::GetLastError(); - m_LoadFailure = FailureType::DLL_NOT_FOUND; - log::error("failed to resolve Python proxy directory ({}): {}", error, - qUtf8Printable(windowsErrorString(::GetLastError()))); - return false; - } - - if (m_MOInfo && m_MOInfo->persistent(name(), "tryInit", false).toBool()) { - m_LoadFailure = FailureType::INITIALIZATION; - if (QMessageBox::question( - parentWidget(), tr("Python Initialization failed"), - tr("On a previous start the Python Plugin failed to initialize.\n" - "Do you want to try initializing python again (at the risk of " - "another crash)?\n " - "Suggestion: Select \"no\", and click the warning sign for further " - "help.Afterwards you have to re-enable the python plugin."), - QMessageBox::Yes | QMessageBox::No, - QMessageBox::No) == QMessageBox::No) { - // we force enabled here (note: this is a persistent settings since MO2 2.4 - // or something), plugin - // usually should not handle enabled/disabled themselves but this is a base - // plugin so... - m_MOInfo->setPersistent(name(), "enabled", false, true); - return true; - } - } - - if (m_MOInfo) { - m_MOInfo->setPersistent(name(), "tryInit", true); - } - - // load the pythonrunner library, this is done in multiple steps: - // - // 1. we set the dlls/ subfolder (from the plugin) as the DLL directory so Windows - // will look for DLLs in it, this is required to find the Python and libffi DLL, but - // also the runner DLL - // - const auto dllPaths = pluginFolder / "dlls"; - if (SetDllDirectoryW(dllPaths.c_str()) == 0) { - DWORD error = ::GetLastError(); - m_LoadFailure = FailureType::DLL_NOT_FOUND; - log::error("failed to add python DLL directory ({}): {}", error, - qUtf8Printable(windowsErrorString(::GetLastError()))); - return false; - } - - // 2. we create the Python runner, we do not need to use ::LinkLibrary and - // ::GetProcAddress because we use delayed load for the runner DLL (see the - // CMakeLists.txt) - // - m_Runner = mo2::python::createPythonRunner(); - - if (m_Runner) { - const auto libpath = pluginFolder / "libs"; - const std::vector paths{ - libpath / "pythoncore.zip", libpath, - std::filesystem::path{IOrganizer::getPluginDataPath().toStdWString()}}; - m_Runner->initialize(paths); - } - - if (m_MOInfo) { - m_MOInfo->setPersistent(name(), "tryInit", false); - } - - // reset DLL directory - SetDllDirectoryW(NULL); - - if (!m_Runner || !m_Runner->isInitialized()) { - m_LoadFailure = FailureType::INITIALIZATION; - } - else { - m_Runner->addDllSearchPath(pluginFolder / "dlls"); - } - - return true; -} - -QString ProxyPython::name() const -{ - return "Python Proxy"; -} - -QString ProxyPython::localizedName() const -{ - return tr("Python Proxy"); -} - -QString ProxyPython::author() const -{ - return "AnyOldName3, Holt59, Silarn, Tannin"; -} - -QString ProxyPython::description() const -{ - return tr("Proxy Plugin to allow plugins written in python to be loaded"); -} - -VersionInfo ProxyPython::version() const -{ - return VersionInfo(2, 3, 0, VersionInfo::RELEASE_FINAL); -} - -QList ProxyPython::settings() const -{ - return {}; -} - -QStringList ProxyPython::pluginList(const QDir& pluginPath) const -{ - QDir dir(pluginPath); - dir.setFilter(dir.filter() | QDir::NoDotAndDotDot); - QDirIterator iter(dir); - - // Note: We put python script (.py) and directory names, not the __init__.py - // files in those since it is easier for the runner to import them. - QStringList result; - while (iter.hasNext()) { - QString name = iter.next(); - QFileInfo info = iter.fileInfo(); - - if (info.isFile() && name.endsWith(".py")) { - result.append(name); - } - else if (info.isDir() && QDir(info.absoluteFilePath()).exists("__init__.py")) { - result.append(name); - } - } - - return result; -} - -QList ProxyPython::load(const QString& identifier) -{ - if (!m_Runner) { - return {}; - } - return m_Runner->load(identifier); -} - -void ProxyPython::unload(const QString& identifier) -{ - if (m_Runner) { - return m_Runner->unload(identifier); - } -} - -std::vector ProxyPython::activeProblems() const -{ - auto failure = m_LoadFailure; - - // don't know how this could happen but wth - if (m_Runner && !m_Runner->isInitialized()) { - failure = FailureType::INITIALIZATION; - } - - if (failure != FailureType::NONE) { - return {static_cast>(failure)}; - } - - return {}; -} - -QString ProxyPython::shortDescription(unsigned int key) const -{ - switch (static_cast(key)) { - case FailureType::SEMICOLON: - return tr("ModOrganizer path contains a semicolon"); - case FailureType::DLL_NOT_FOUND: - return tr("Python DLL not found"); - case FailureType::INVALID_DLL: - return tr("Invalid Python DLL"); - case FailureType::INITIALIZATION: - return tr("Initializing Python failed"); - default: - return tr("invalid problem key %1").arg(key); - } -} - -QString ProxyPython::fullDescription(unsigned int key) const -{ - switch (static_cast(key)) { - case FailureType::SEMICOLON: - return tr("The path to Mod Organizer (%1) contains a semicolon.
" - "While this is legal on NTFS drives, many softwares do not handle it " - "correctly.
" - "Unfortunately MO depends on libraries that seem to fall into that " - "group.
" - "As a result the python plugin cannot be loaded, and the only " - "solution we can" - "offer is to remove the semicolon or move MO to a path without a " - "semicolon.") - .arg(QCoreApplication::applicationDirPath()); - case FailureType::DLL_NOT_FOUND: - return tr("The Python plugin DLL was not found, maybe your antivirus deleted " - "it. Re-installing MO2 might fix the problem."); - case FailureType::INVALID_DLL: - return tr( - "The Python plugin DLL is invalid, maybe your antivirus is blocking it. " - "Re-installing MO2 and adding exclusions for it to your AV might fix the " - "problem."); - case FailureType::INITIALIZATION: - return tr("The initialization of the Python plugin DLL failed, unfortunately " - "without any details."); - default: - return tr("invalid problem key %1").arg(key); - } -} - -bool ProxyPython::hasGuidedFix(unsigned int) const -{ - return false; -} - -void ProxyPython::startGuidedFix(unsigned int) const {} +/* +Copyright (C) 2022 Sebastian Herbord & MO2 Team. All rights reserved. + +This file is part of python proxy plugin for MO + +python proxy plugin is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Python proxy plugin is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with python proxy plugin. If not, see . +*/ +#include "proxypython.h" + +#include + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +namespace fs = std::filesystem; +using namespace MOBase; + +// retrieve the path to the folder containing the proxy DLL +fs::path getPluginFolder() +{ + wchar_t path[MAX_PATH]; + HMODULE hm = NULL; + + if (GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | + GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, + (LPCWSTR)&getPluginFolder, &hm) == 0) { + return {}; + } + if (GetModuleFileName(hm, path, sizeof(path)) == 0) { + return {}; + } + + return fs::path(path).parent_path(); +} + +ProxyPython::ProxyPython() + : m_MOInfo{nullptr}, m_RunnerLib{nullptr}, m_Runner{nullptr}, + m_LoadFailure(FailureType::NONE) +{ +} + +bool ProxyPython::init(IOrganizer* moInfo) +{ + m_MOInfo = moInfo; + + if (m_MOInfo && !m_MOInfo->isPluginEnabled(this)) { + return false; + } + + if (QCoreApplication::applicationDirPath().contains(';')) { + m_LoadFailure = FailureType::SEMICOLON; + return true; + } + + const auto pluginFolder = getPluginFolder(); + + if (pluginFolder.empty()) { + DWORD error = ::GetLastError(); + m_LoadFailure = FailureType::DLL_NOT_FOUND; + log::error("failed to resolve Python proxy directory ({}): {}", error, + qUtf8Printable(windowsErrorString(::GetLastError()))); + return false; + } + + if (m_MOInfo && m_MOInfo->persistent(name(), "tryInit", false).toBool()) { + m_LoadFailure = FailureType::INITIALIZATION; + if (QMessageBox::question( + parentWidget(), tr("Python Initialization failed"), + tr("On a previous start the Python Plugin failed to initialize.\n" + "Do you want to try initializing python again (at the risk of " + "another crash)?\n " + "Suggestion: Select \"no\", and click the warning sign for further " + "help.Afterwards you have to re-enable the python plugin."), + QMessageBox::Yes | QMessageBox::No, + QMessageBox::No) == QMessageBox::No) { + // we force enabled here (note: this is a persistent settings since MO2 2.4 + // or something), plugin + // usually should not handle enabled/disabled themselves but this is a base + // plugin so... + m_MOInfo->setPersistent(name(), "enabled", false, true); + return true; + } + } + + if (m_MOInfo) { + m_MOInfo->setPersistent(name(), "tryInit", true); + } + + // load the pythonrunner library, this is done in multiple steps: + // + // 1. we set the dlls/ subfolder (from the plugin) as the DLL directory so Windows + // will look for DLLs in it, this is required to find the Python and libffi DLL, but + // also the runner DLL + // + const auto dllPaths = pluginFolder / "dlls"; + if (SetDllDirectoryW(dllPaths.c_str()) == 0) { + DWORD error = ::GetLastError(); + m_LoadFailure = FailureType::DLL_NOT_FOUND; + log::error("failed to add python DLL directory ({}): {}", error, + qUtf8Printable(windowsErrorString(::GetLastError()))); + return false; + } + + // 2. we create the Python runner, we do not need to use ::LinkLibrary and + // ::GetProcAddress because we use delayed load for the runner DLL (see the + // CMakeLists.txt) + // + m_Runner = mo2::python::createPythonRunner(); + + if (m_Runner) { + const auto libpath = pluginFolder / "libs"; + const std::vector paths{ + libpath / "pythoncore.zip", libpath, + std::filesystem::path{IOrganizer::getPluginDataPath().toStdWString()}}; + m_Runner->initialize(paths); + } + + if (m_MOInfo) { + m_MOInfo->setPersistent(name(), "tryInit", false); + } + + // reset DLL directory + SetDllDirectoryW(NULL); + + if (!m_Runner || !m_Runner->isInitialized()) { + m_LoadFailure = FailureType::INITIALIZATION; + } + else { + m_Runner->addDllSearchPath(pluginFolder / "dlls"); + } + + return true; +} + +QString ProxyPython::name() const +{ + return "Python Proxy"; +} + +QString ProxyPython::localizedName() const +{ + return tr("Python Proxy"); +} + +QString ProxyPython::author() const +{ + return "AnyOldName3, Holt59, Silarn, Tannin"; +} + +QString ProxyPython::description() const +{ + return tr("Proxy Plugin to allow plugins written in python to be loaded"); +} + +VersionInfo ProxyPython::version() const +{ + return VersionInfo(2, 3, 0, VersionInfo::RELEASE_FINAL); +} + +QList ProxyPython::settings() const +{ + return {}; +} + +QStringList ProxyPython::pluginList(const QDir& pluginPath) const +{ + QDir dir(pluginPath); + dir.setFilter(dir.filter() | QDir::NoDotAndDotDot); + QDirIterator iter(dir); + + // Note: We put python script (.py) and directory names, not the __init__.py + // files in those since it is easier for the runner to import them. + QStringList result; + while (iter.hasNext()) { + QString name = iter.next(); + QFileInfo info = iter.fileInfo(); + + if (info.isFile() && name.endsWith(".py")) { + result.append(name); + } + else if (info.isDir() && QDir(info.absoluteFilePath()).exists("__init__.py")) { + result.append(name); + } + } + + return result; +} + +QList ProxyPython::load(const QString& identifier) +{ + if (!m_Runner) { + return {}; + } + return m_Runner->load(identifier); +} + +void ProxyPython::unload(const QString& identifier) +{ + if (m_Runner) { + return m_Runner->unload(identifier); + } +} + +std::vector ProxyPython::activeProblems() const +{ + auto failure = m_LoadFailure; + + // don't know how this could happen but wth + if (m_Runner && !m_Runner->isInitialized()) { + failure = FailureType::INITIALIZATION; + } + + if (failure != FailureType::NONE) { + return {static_cast>(failure)}; + } + + return {}; +} + +QString ProxyPython::shortDescription(unsigned int key) const +{ + switch (static_cast(key)) { + case FailureType::SEMICOLON: + return tr("ModOrganizer path contains a semicolon"); + case FailureType::DLL_NOT_FOUND: + return tr("Python DLL not found"); + case FailureType::INVALID_DLL: + return tr("Invalid Python DLL"); + case FailureType::INITIALIZATION: + return tr("Initializing Python failed"); + default: + return tr("invalid problem key %1").arg(key); + } +} + +QString ProxyPython::fullDescription(unsigned int key) const +{ + switch (static_cast(key)) { + case FailureType::SEMICOLON: + return tr("The path to Mod Organizer (%1) contains a semicolon.
" + "While this is legal on NTFS drives, many softwares do not handle it " + "correctly.
" + "Unfortunately MO depends on libraries that seem to fall into that " + "group.
" + "As a result the python plugin cannot be loaded, and the only " + "solution we can" + "offer is to remove the semicolon or move MO to a path without a " + "semicolon.") + .arg(QCoreApplication::applicationDirPath()); + case FailureType::DLL_NOT_FOUND: + return tr("The Python plugin DLL was not found, maybe your antivirus deleted " + "it. Re-installing MO2 might fix the problem."); + case FailureType::INVALID_DLL: + return tr( + "The Python plugin DLL is invalid, maybe your antivirus is blocking it. " + "Re-installing MO2 and adding exclusions for it to your AV might fix the " + "problem."); + case FailureType::INITIALIZATION: + return tr("The initialization of the Python plugin DLL failed, unfortunately " + "without any details."); + default: + return tr("invalid problem key %1").arg(key); + } +} + +bool ProxyPython::hasGuidedFix(unsigned int) const +{ + return false; +} + +void ProxyPython::startGuidedFix(unsigned int) const {} diff --git a/src/proxy/proxypython.h b/src/proxy/proxypython.h index fb352dd..5165fae 100644 --- a/src/proxy/proxypython.h +++ b/src/proxy/proxypython.h @@ -1,76 +1,76 @@ -/* -Copyright (C) 2022 Sebastian Herbord & MO2 Team. All rights reserved. - -This file is part of python proxy plugin for MO - -python proxy plugin is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Python proxy plugin is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with python proxy plugin. If not, see . -*/ - -#ifndef PROXYPYTHON_H -#define PROXYPYTHON_H - -#include -#include - -#include -#include - -#include - -class ProxyPython : public QObject, - public MOBase::IPluginProxy, - public MOBase::IPluginDiagnose { - Q_OBJECT - Q_INTERFACES(MOBase::IPlugin MOBase::IPluginProxy MOBase::IPluginDiagnose) - Q_PLUGIN_METADATA(IID "org.mo2.ProxyPython") - -public: - ProxyPython(); - - virtual bool init(MOBase::IOrganizer* moInfo); - virtual QString name() const override; - virtual QString localizedName() const override; - virtual QString author() const override; - virtual QString description() const override; - virtual MOBase::VersionInfo version() const override; - virtual QList settings() const override; - - QStringList pluginList(const QDir& pluginPath) const override; - QList load(const QString& identifier) override; - void unload(const QString& identifier) override; - -public: // IPluginDiagnose - virtual std::vector activeProblems() const override; - virtual QString shortDescription(unsigned int key) const override; - virtual QString fullDescription(unsigned int key) const override; - virtual bool hasGuidedFix(unsigned int key) const override; - virtual void startGuidedFix(unsigned int key) const override; - -private: - MOBase::IOrganizer* m_MOInfo; - HMODULE m_RunnerLib; - std::unique_ptr m_Runner; - - enum class FailureType : unsigned int { - NONE = 0, - SEMICOLON = 1, - DLL_NOT_FOUND = 2, - INVALID_DLL = 3, - INITIALIZATION = 4 - }; - - FailureType m_LoadFailure; -}; - -#endif // PROXYPYTHON_H +/* +Copyright (C) 2022 Sebastian Herbord & MO2 Team. All rights reserved. + +This file is part of python proxy plugin for MO + +python proxy plugin is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Python proxy plugin is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with python proxy plugin. If not, see . +*/ + +#ifndef PROXYPYTHON_H +#define PROXYPYTHON_H + +#include +#include + +#include +#include + +#include + +class ProxyPython : public QObject, + public MOBase::IPluginProxy, + public MOBase::IPluginDiagnose { + Q_OBJECT + Q_INTERFACES(MOBase::IPlugin MOBase::IPluginProxy MOBase::IPluginDiagnose) + Q_PLUGIN_METADATA(IID "org.mo2.ProxyPython") + +public: + ProxyPython(); + + virtual bool init(MOBase::IOrganizer* moInfo); + virtual QString name() const override; + virtual QString localizedName() const override; + virtual QString author() const override; + virtual QString description() const override; + virtual MOBase::VersionInfo version() const override; + virtual QList settings() const override; + + QStringList pluginList(const QDir& pluginPath) const override; + QList load(const QString& identifier) override; + void unload(const QString& identifier) override; + +public: // IPluginDiagnose + virtual std::vector activeProblems() const override; + virtual QString shortDescription(unsigned int key) const override; + virtual QString fullDescription(unsigned int key) const override; + virtual bool hasGuidedFix(unsigned int key) const override; + virtual void startGuidedFix(unsigned int key) const override; + +private: + MOBase::IOrganizer* m_MOInfo; + HMODULE m_RunnerLib; + std::unique_ptr m_Runner; + + enum class FailureType : unsigned int { + NONE = 0, + SEMICOLON = 1, + DLL_NOT_FOUND = 2, + INVALID_DLL = 3, + INITIALIZATION = 4 + }; + + FailureType m_LoadFailure; +}; + +#endif // PROXYPYTHON_H diff --git a/src/proxy/resource.h b/src/proxy/resource.h index 52c87a6..1f33c5c 100644 --- a/src/proxy/resource.h +++ b/src/proxy/resource.h @@ -1,6 +1,6 @@ -#ifndef RESOURCE_H -#define RESOURCE_H - -#define IDR_LOADER_DLL 100 - -#endif // RESOURCE_H +#ifndef RESOURCE_H +#define RESOURCE_H + +#define IDR_LOADER_DLL 100 + +#endif // RESOURCE_H From 7108d59267b0fe4e9442f9bb146ea5d70e7704a8 Mon Sep 17 00:00:00 2001 From: Mikael CAPELLE Date: Mon, 10 Jul 2023 09:10:45 +0200 Subject: [PATCH 2/5] Apply black/isort to Python files. --- setup.cfg | 12 ++++++++++++ tests/python/test_argument_wrapper.py | 3 ++- tests/python/test_filetree.py | 3 ++- tests/python/test_functional.py | 4 ++-- tests/python/test_guessed_string.py | 4 ++-- tests/python/test_path_wrappers.py | 4 ++-- tests/python/test_qt.py | 1 - tests/runner/plugins/dummy-game.py | 4 ++-- 8 files changed, 24 insertions(+), 11 deletions(-) create mode 100644 setup.cfg diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 0000000..f96172b --- /dev/null +++ b/setup.cfg @@ -0,0 +1,12 @@ +[flake8] +# Use black line length: +max-line-length = 88 +extend-ignore = + # See https://github.com/PyCQA/pycodestyle/issues/373 + E203, E266 + +[isort] +profile = black +multi_line_output = 3 +known_mobase = mobase +sections=FUTURE,STDLIB,THIRDPARTY,MOBASE,FIRSTPARTY,LOCALFOLDER diff --git a/tests/python/test_argument_wrapper.py b/tests/python/test_argument_wrapper.py index 37868e5..e474996 100644 --- a/tests/python/test_argument_wrapper.py +++ b/tests/python/test_argument_wrapper.py @@ -1,6 +1,7 @@ -import mobase import pytest +import mobase + m = pytest.importorskip("mobase_tests.argument_wrapper") diff --git a/tests/python/test_filetree.py b/tests/python/test_filetree.py index 8248bf9..ccd6fc9 100644 --- a/tests/python/test_filetree.py +++ b/tests/python/test_filetree.py @@ -1,6 +1,7 @@ -import mobase import pytest +import mobase + m = pytest.importorskip("mobase_tests.filetree") diff --git a/tests/python/test_functional.py b/tests/python/test_functional.py index a5cb30a..39fa4cb 100644 --- a/tests/python/test_functional.py +++ b/tests/python/test_functional.py @@ -1,11 +1,11 @@ -import mobase import pytest +import mobase + m = pytest.importorskip("mobase_tests.functional") def test_guessed_string(): - # available functions: # - fn_0_arg, fn_1_arg, fn_2_arg # - fn_0_or_1_arg, fn_1_or_2_or_3_arg diff --git a/tests/python/test_guessed_string.py b/tests/python/test_guessed_string.py index 3f335f2..ad04932 100644 --- a/tests/python/test_guessed_string.py +++ b/tests/python/test_guessed_string.py @@ -1,11 +1,11 @@ -import mobase import pytest +import mobase + m = pytest.importorskip("mobase_tests.guessed_string") def test_guessed_string(): - # empty string gs = mobase.GuessedString() diff --git a/tests/python/test_path_wrappers.py b/tests/python/test_path_wrappers.py index 1975656..ee65297 100644 --- a/tests/python/test_path_wrappers.py +++ b/tests/python/test_path_wrappers.py @@ -1,13 +1,13 @@ import sys from pathlib import Path -import mobase import pytest from PyQt6.QtCore import QDir, QFileInfo +import mobase + def test_filepath_wrappers(): - # TBC that this works everywhere version = ".".join(map(str, sys.version_info[:3])) diff --git a/tests/python/test_qt.py b/tests/python/test_qt.py index 004267b..cb35db5 100644 --- a/tests/python/test_qt.py +++ b/tests/python/test_qt.py @@ -50,7 +50,6 @@ def test_qdatetime(): def test_qvariant(): - # Python -> C++ assert m.qvariant_from_none(None) == (True, False) diff --git a/tests/runner/plugins/dummy-game.py b/tests/runner/plugins/dummy-game.py index b11e060..d4fe0bb 100644 --- a/tests/runner/plugins/dummy-game.py +++ b/tests/runner/plugins/dummy-game.py @@ -1,8 +1,9 @@ # -*- encoding: utf-8 -*- -import mobase from PyQt6.QtWidgets import QWidget +import mobase + class DummyModDataChecker(mobase.ModDataChecker): def dataLooksValid( @@ -26,7 +27,6 @@ class DummySaveGameInfo(mobase.SaveGameInfo): # from the C++ side # class DummyGame(mobase.IPluginGame): - _features: dict[type, object] def __init__(self): From d7c109c34480dd58b008d4c991f702376ee7681b Mon Sep 17 00:00:00 2001 From: Mikael CAPELLE Date: Mon, 10 Jul 2023 09:13:21 +0200 Subject: [PATCH 3/5] Add .git-blame-ignore-revs. --- .git-blame-ignore-revs | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .git-blame-ignore-revs diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs new file mode 100644 index 0000000..6f8a3f9 --- /dev/null +++ b/.git-blame-ignore-revs @@ -0,0 +1,2 @@ +1bffcfa8bfba93a9505692b11fdd3f0903983542 +7108d59267b0fe4e9442f9bb146ea5d70e7704a8 From 0ee795ac6ae113a9e50f189ccc24c001d52039d7 Mon Sep 17 00:00:00 2001 From: Mikael CAPELLE Date: Mon, 10 Jul 2023 09:18:10 +0200 Subject: [PATCH 4/5] Add black and isort to linting action. --- .github/workflows/linting.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/linting.yml b/.github/workflows/linting.yml index ffb0c19..6f20ecc 100644 --- a/.github/workflows/linting.yml +++ b/.github/workflows/linting.yml @@ -10,3 +10,8 @@ jobs: with: clang-format-version: "15" check-path: "." + - uses: actions/setup-python@v4 + with: + python-version: '3.10' + - uses: isort/isort-action@master + - uses: psf/black@stable From be9b614a5ee5e527cbd792ff790c4329c24f9a11 Mon Sep 17 00:00:00 2001 From: Mikael CAPELLE Date: Mon, 10 Jul 2023 09:32:09 +0200 Subject: [PATCH 5/5] Fix build workflow. --- .github/workflows/build-and-test.yml | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 8c93181..84a3e14 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -1,9 +1,14 @@ name: Build Plugin Python + on: push: branches: master pull_request: types: [opened, synchronize, reopened] + +env: + MO_BRANCH: ${{ github.head_ref || github.ref_name }} + jobs: build: runs-on: windows-2022 @@ -23,7 +28,7 @@ jobs: key: ${{ runner.OS }}-mob-cache-${{ hashFiles('mob/.git/refs/heads/master') }} restore-keys: | ${{ runner.OS }}-mob-cache- - - if: ${{ steps.cache-mob.outputs.cache-hit != 'true' }} + - if: steps.cache-mob.outputs.cache-hit != 'true' name: Build mob run: .\mob\bootstrap.ps1 - name: Install Qt @@ -44,7 +49,7 @@ jobs: key: ${{ runner.OS }}-mo2-dependencies-${{ hashFiles('mob/.git/refs/heads/master') }} restore-keys: | ${{ runner.OS }}-mo2-dependencies- - - if: ${{ steps.cache-dependencies.outputs.cache-hit != 'true' }} + - if: steps.cache-dependencies.outputs.cache-hit != 'true' name: Build dependencies with mob run: .\mob\mob.exe -l 4 -d . @@ -58,7 +63,9 @@ jobs: mob.log # TODO: cache this? - name: Build cmake_common and uibase - run: .\mob\mob.exe -l 4 -d . build + run: .\mob\mob.exe -l 4 -d . + -s task/mo_fallback=master -s task/mo_branch=${{ env.MO_BRANCH }} + build --ignore-uncommitted-changes --redownload --reextract --reconfigure --rebuild cmake_common uibase