From d1f42647c0844d628126bf74de02cc7b825d9409 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mika=C3=ABl=20Capelle?= Date: Thu, 27 Jun 2024 18:49:17 +0200 Subject: [PATCH 1/3] Expose INVALID_HANDLE_VALUE as mobase.INVALID_HANDLE_VALUE. --- src/mobase/wrappers/basic_classes.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/mobase/wrappers/basic_classes.cpp b/src/mobase/wrappers/basic_classes.cpp index b23a891..c594362 100644 --- a/src/mobase/wrappers/basic_classes.cpp +++ b/src/mobase/wrappers/basic_classes.cpp @@ -429,6 +429,9 @@ namespace mo2::python { void add_iorganizer_classes(py::module_ m) { + // define INVALID_HANDLE_VALUE for startApplication, etc. + m.attr("INVALID_HANDLE_VALUE") = py::int_((std::uintptr_t)INVALID_HANDLE_VALUE); + py::class_(m, "FileInfo") .def(py::init<>()) .def_readwrite("filePath", &IOrganizer::FileInfo::filePath) From 6319272ae664dcdd3904c43af119d6a00fe88379 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mika=C3=ABl=20Capelle?= Date: Thu, 27 Jun 2024 19:57:17 +0200 Subject: [PATCH 2/3] Add tests for startApplication() returning INVALID_HANDLE_VALUE. --- tests/python/test_organizer.cpp | 11 ++++++++--- tests/python/test_organizer.py | 6 ++++-- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/tests/python/test_organizer.cpp b/tests/python/test_organizer.cpp index 55b6e9b..3f1878d 100644 --- a/tests/python/test_organizer.cpp +++ b/tests/python/test_organizer.cpp @@ -13,6 +13,10 @@ using ::testing::NiceMock; PYBIND11_MODULE(organizer, m) { + using ::testing::_; + using ::testing::Eq; + using ::testing::Return; + m.def( "organizer", []() -> IOrganizer* { @@ -21,9 +25,10 @@ PYBIND11_MODULE(organizer, m) return "profile"; }); const auto handle = (HANDLE)std::uintptr_t{4654}; - ON_CALL(*mock, startApplication).WillByDefault([&mock, handle](auto&&...) { - return handle; - }); + EXPECT_CALL(*mock, startApplication(Eq("valid.exe"), _, _, _, _, _)) + .WillRepeatedly(Return(handle)); + EXPECT_CALL(*mock, startApplication(Eq("invalid.exe"), _, _, _, _, _)) + .WillRepeatedly(Return(INVALID_HANDLE_VALUE)); ON_CALL(*mock, waitForApplication) .WillByDefault([&mock, original_handle = handle]( HANDLE handle, bool refresh, LPDWORD exitCode) { diff --git a/tests/python/test_organizer.py b/tests/python/test_organizer.py index 9fcdcc9..a75f934 100644 --- a/tests/python/test_organizer.py +++ b/tests/python/test_organizer.py @@ -1,3 +1,4 @@ +import mobase import pytest from PyQt6.QtWidgets import QWidget @@ -5,8 +6,9 @@ def test_getters(): - o = m.organizer() + o: mobase.IOrganizer = m.organizer() assert o.profileName() == "profile" - assert o.startApplication("") == 4654 + assert o.startApplication("valid.exe") == 4654 + assert o.startApplication("invalid.exe") == mobase.INVALID_HANDLE_VALUE assert o.waitForApplication(42) == (False, -1) assert o.waitForApplication(4654) == (True, 0) From 1e74765b3717decb36e8644a88974a6e4ad4af5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mika=C3=ABl=20Capelle?= Date: Fri, 28 Jun 2024 09:17:18 +0200 Subject: [PATCH 3/3] Clean tests and generate stub files for them. --- .github/workflows/linting.yml | 14 +- poetry.lock | 254 ++++++++++++++++++++++ pyproject.toml | 53 +++++ setup.cfg | 12 - tests/python/CMakeLists.txt | 1 - tests/python/conftest.py | 7 +- tests/python/test_argument_wrapper.py | 16 +- tests/python/test_filetree.py | 4 +- tests/python/test_functional.py | 32 ++- tests/python/test_guessed_string.py | 11 +- tests/python/test_organizer.py | 4 +- tests/python/test_path_wrappers.py | 2 +- tests/python/test_qt.py | 3 +- tests/python/test_qt_widgets.py | 7 +- tests/python/test_shared_cpp_owner.py | 9 +- tests/runner/plugins/dummy-diagnose.py | 4 +- tests/runner/plugins/dummy-filemapper.py | 4 +- tests/runner/plugins/dummy-game.py | 4 +- tests/runner/plugins/dummy-iplugin.py | 2 - typings/generate.py | 38 ++++ typings/mobase_tests/argument_wrapper.pyi | 27 +++ typings/mobase_tests/filetree.pyi | 9 + typings/mobase_tests/functional.pyi | 19 ++ typings/mobase_tests/guessed_string.pyi | 16 ++ typings/mobase_tests/organizer.pyi | 7 + typings/mobase_tests/qt.pyi | 109 ++++++++++ typings/mobase_tests/qt_widgets.pyi | 34 +++ typings/mobase_tests/shared_cpp_owner.pyi | 22 ++ 28 files changed, 648 insertions(+), 76 deletions(-) create mode 100644 poetry.lock create mode 100644 pyproject.toml delete mode 100644 setup.cfg create mode 100644 typings/generate.py create mode 100644 typings/mobase_tests/argument_wrapper.pyi create mode 100644 typings/mobase_tests/filetree.pyi create mode 100644 typings/mobase_tests/functional.pyi create mode 100644 typings/mobase_tests/guessed_string.pyi create mode 100644 typings/mobase_tests/organizer.pyi create mode 100644 typings/mobase_tests/qt.pyi create mode 100644 typings/mobase_tests/qt_widgets.pyi create mode 100644 typings/mobase_tests/shared_cpp_owner.pyi diff --git a/.github/workflows/linting.yml b/.github/workflows/linting.yml index 22d7f40..70b5bca 100644 --- a/.github/workflows/linting.yml +++ b/.github/workflows/linting.yml @@ -10,13 +10,15 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - - name: Run clang-format - uses: jidicula/clang-format-action@v4.11.0 + - name: Check format + uses: ModOrganizer2/check-formatting-action@master 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 + python-version: "3.12" + - uses: abatilo/actions-poetry@v2 + - name: Check format Python tests + run: | + poetry install --no-root + poetry run poe lint diff --git a/poetry.lock b/poetry.lock new file mode 100644 index 0000000..0ceb7f6 --- /dev/null +++ b/poetry.lock @@ -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" diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..71bb9df --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,53 @@ +[tool.poetry] +name = "modorganizer-plugin_python" +version = "3.0.0" +description = "" +authors = ["Mikaƫl Capelle "] + +[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" diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index f96172b..0000000 --- a/setup.cfg +++ /dev/null @@ -1,12 +0,0 @@ -[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/CMakeLists.txt b/tests/python/CMakeLists.txt index 69d3dea..3e80a54 100644 --- a/tests/python/CMakeLists.txt +++ b/tests/python/CMakeLists.txt @@ -18,7 +18,6 @@ add_test(NAME pytest COMMAND ${CMAKE_CURRENT_BINARY_DIR}/pylibs/bin/pytest.exe ${CMAKE_CURRENT_SOURCE_DIR} -s ) -set(extra_paths "${UIBASE_PATH}\\;${MO2_INSTALL_PATH}/bin/dlls") set_tests_properties(pytest PROPERTIES DEPENDS python-tests diff --git a/tests/python/conftest.py b/tests/python/conftest.py index 19830e5..34ca988 100644 --- a/tests/python/conftest.py +++ b/tests/python/conftest.py @@ -1,15 +1,14 @@ -# -*- encoding: utf-8 -*- - import os import sys from pathlib import Path +from typing import cast def pytest_configure(): global app - os.add_dll_directory(Path(os.getenv("QT_ROOT")).joinpath("bin")) - os.add_dll_directory(Path(os.getenv("UIBASE_PATH"))) + os.add_dll_directory(str(Path(cast(str, os.getenv("QT_ROOT"))).joinpath("bin"))) + os.add_dll_directory(str(os.getenv("UIBASE_PATH"))) from PyQt6.QtWidgets import QApplication diff --git a/tests/python/test_argument_wrapper.py b/tests/python/test_argument_wrapper.py index e474996..08b4a1b 100644 --- a/tests/python/test_argument_wrapper.py +++ b/tests/python/test_argument_wrapper.py @@ -1,15 +1,13 @@ import pytest -import mobase - -m = pytest.importorskip("mobase_tests.argument_wrapper") +import mobase_tests.argument_wrapper as m def test_argument_wrapper_fn1(): assert m.fn1_raw("hello") == "hello-hello" with pytest.raises(TypeError): - m.fn1_raw(1) + m.fn1_raw(1) # pyright: ignore[reportArgumentType] assert m.fn1_wrap("hello") == "hello-hello" assert m.fn1_wrap(32) == "32-32" @@ -22,7 +20,7 @@ def test_argument_wrapper_fn2(): assert m.fn2_raw(33) == 66 with pytest.raises(TypeError): - m.fn2_raw("12") + m.fn2_raw("12") # pyright: ignore[reportArgumentType] assert m.fn2_wrap("15") == 30 assert m.fn2_wrap(32) == 64 @@ -36,10 +34,10 @@ def test_argument_wrapper_fn3(): assert m.fn3_raw(33, [1, 2], "hello") == "hello-35" with pytest.raises(TypeError): - m.fn3_raw("12", [], "hello") + m.fn3_raw("12", [], "hello") # pyright: ignore[reportArgumentType] with pytest.raises(TypeError): - m.fn3_raw(36, [], 136) + m.fn3_raw(36, [], 136) # pyright: ignore[reportArgumentType] assert m.fn3_wrap(14, [1, 2], "world") == "world-16" assert m.fn3_wrap("15", [0], "woot") == "woot-16" @@ -55,10 +53,10 @@ def test_argument_wrapper_fn3(): assert m.fn3_wrap_0("15", [], "w00t") == "w00t-15" with pytest.raises(TypeError): - m.fn3_wrap_0(14, [], 12) + m.fn3_wrap_0(14, [], 12) # pyright: ignore[reportArgumentType] assert m.fn3_wrap_2(14, [1, 2], "world") == "world-16" assert m.fn3_wrap_2(15, [], 18) == "18-15" with pytest.raises(TypeError): - m.fn3_wrap_2("14", [], 12) + m.fn3_wrap_2("14", [], 12) # pyright: ignore[reportArgumentType] diff --git a/tests/python/test_filetree.py b/tests/python/test_filetree.py index ccd6fc9..d062591 100644 --- a/tests/python/test_filetree.py +++ b/tests/python/test_filetree.py @@ -1,8 +1,6 @@ -import pytest - import mobase -m = pytest.importorskip("mobase_tests.filetree") +import mobase_tests.filetree as m def test_filetype(): diff --git a/tests/python/test_functional.py b/tests/python/test_functional.py index 39fa4cb..f8da087 100644 --- a/tests/python/test_functional.py +++ b/tests/python/test_functional.py @@ -1,8 +1,8 @@ -import pytest +from typing import Any -import mobase +import pytest -m = pytest.importorskip("mobase_tests.functional") +import mobase_tests.functional as m def test_guessed_string(): @@ -10,21 +10,33 @@ def test_guessed_string(): # - fn_0_arg, fn_1_arg, fn_2_arg # - fn_0_or_1_arg, fn_1_or_2_or_3_arg + def no_args() -> int: + return 0 + + def len_of_args(*args: int) -> int: + return len(args) + + def len_of_args_tweaked(x: int, *args: int, **kwargs: Any) -> int: + return x + len(args) + + def sum_of_args(*args: int) -> int: + return sum(args) + assert m.fn_0_arg(lambda: 0) == 0 assert m.fn_0_arg(lambda: 5) == 5 assert m.fn_0_arg(lambda x=2: x) == 2 - assert m.fn_0_arg(lambda *args: len(args)) == 0 + assert m.fn_0_arg(len_of_args) == 0 assert m.fn_1_arg(lambda x: x, 4) == 4 - assert m.fn_1_arg(lambda *args: sum(args), 8) == 8 + assert m.fn_1_arg(sum_of_args, 8) == 8 assert m.fn_1_arg(lambda x=2, y=4: x + y, 3) == 7 - assert m.fn_1_arg(lambda x, *args, **kwargs: x + len(args), 5) == 5 + assert m.fn_1_arg(len_of_args_tweaked, 5) == 5 assert m.fn_2_arg(lambda x, y: x * y, 4, 5) == 20 assert m.fn_2_arg(lambda x, y=3: x * y, 4, 2) == 8 - assert m.fn_2_arg(lambda *args: sum(args), 8, 9) == 17 + assert m.fn_2_arg(sum_of_args, 8, 9) == 17 assert m.fn_2_arg(lambda x=2, y=4: x + y, 3, 3) == 6 - assert m.fn_2_arg(lambda x, *args, **kwargs: x + len(args), 5, 2) == 6 + assert m.fn_2_arg(len_of_args_tweaked, 5, 2) == 6 assert m.fn_0_or_1_arg(lambda: 3) == 3 assert m.fn_0_or_1_arg(lambda x: x) == 1 @@ -33,11 +45,11 @@ def test_guessed_string(): assert m.fn_0_or_1_arg(lambda x=2: x) == 2 with pytest.raises(TypeError): - m.fn_1_or_2_or_3_arg(lambda: 0) + m.fn_1_or_2_or_3_arg(no_args) # pyright: ignore[reportArgumentType, reportCallIssue] assert m.fn_1_or_2_or_3_arg(lambda x=4: x) == 1 assert m.fn_1_or_2_or_3_arg(lambda x, y: x + y) == 3 # 1 + 2 assert m.fn_1_or_2_or_3_arg(lambda x, y, z: x * y * z) == 6 # 1 * 2 * 3 # the 1 arg is bound first - assert m.fn_1_or_2_or_3_arg(lambda *args: sum(args)) == 1 + assert m.fn_1_or_2_or_3_arg(sum_of_args) == 1 diff --git a/tests/python/test_guessed_string.py b/tests/python/test_guessed_string.py index ad04932..204e1f1 100644 --- a/tests/python/test_guessed_string.py +++ b/tests/python/test_guessed_string.py @@ -1,8 +1,6 @@ -import pytest - import mobase -m = pytest.importorskip("mobase_tests.guessed_string") +import mobase_tests.guessed_string as m def test_guessed_string(): @@ -29,7 +27,10 @@ def test_guessed_string(): gs = mobase.GuessedString() assert str(gs) == "" - m.set_from_callback(gs, lambda gs: gs.update("test")) + def _update(gs: mobase.GuessedString): + gs.update("test") + + m.set_from_callback(gs, _update) assert str(gs) == "test" - assert m.get_from_callback(lambda gs: gs.update("test")) == "test" + assert m.get_from_callback(_update) == "test" diff --git a/tests/python/test_organizer.py b/tests/python/test_organizer.py index a75f934..3ac42d2 100644 --- a/tests/python/test_organizer.py +++ b/tests/python/test_organizer.py @@ -1,6 +1,6 @@ -import mobase import pytest -from PyQt6.QtWidgets import QWidget + +import mobase m = pytest.importorskip("mobase_tests.organizer") diff --git a/tests/python/test_path_wrappers.py b/tests/python/test_path_wrappers.py index ee65297..5a0d701 100644 --- a/tests/python/test_path_wrappers.py +++ b/tests/python/test_path_wrappers.py @@ -19,7 +19,7 @@ def test_filepath_wrappers(): # from QDir, ko with pytest.raises(TypeError): - mobase.getProductVersion(QDir(sys.executable)) + mobase.getProductVersion(QDir(sys.executable)) # pyright: ignore[reportArgumentType] def test_executableinfo(): diff --git a/tests/python/test_qt.py b/tests/python/test_qt.py index 5bbfd49..991e33c 100644 --- a/tests/python/test_qt.py +++ b/tests/python/test_qt.py @@ -1,7 +1,6 @@ -import pytest from PyQt6.QtCore import QDateTime, Qt -m = pytest.importorskip("mobase_tests.qt") +import mobase_tests.qt as m def test_qstring(): diff --git a/tests/python/test_qt_widgets.py b/tests/python/test_qt_widgets.py index 110c438..057f34e 100644 --- a/tests/python/test_qt_widgets.py +++ b/tests/python/test_qt_widgets.py @@ -1,12 +1,11 @@ -import pytest from PyQt6.QtWidgets import QWidget -m = pytest.importorskip("mobase_tests.qt_widgets") +import mobase_tests.qt_widgets as m class PyWidget(QWidget): - def heightForWidth(self, value: int) -> int: - return value * 3 + 4 + def heightForWidth(self, a0: int) -> int: + return a0 * 3 + 4 class PyCustomWidget(m.CustomWidget): diff --git a/tests/python/test_shared_cpp_owner.py b/tests/python/test_shared_cpp_owner.py index 4b38cdc..0bcecf7 100644 --- a/tests/python/test_shared_cpp_owner.py +++ b/tests/python/test_shared_cpp_owner.py @@ -1,9 +1,4 @@ -from re import A - -import pytest -from PyQt6.QtCore import QDateTime, Qt - -m = pytest.importorskip("mobase_tests.shared_cpp_owner") +import mobase_tests.shared_cpp_owner as m class PyBase(m.Base): @@ -54,7 +49,7 @@ def test_shared_cpp_owner_3(): assert not m.is_alive("foo") -def test_shared_cpp_owner_3(): +def test_shared_cpp_owner_4(): # create from Python, owned by C++ p = PyBase("foo", 2) diff --git a/tests/runner/plugins/dummy-diagnose.py b/tests/runner/plugins/dummy-diagnose.py index f9972f6..6f25ef0 100644 --- a/tests/runner/plugins/dummy-diagnose.py +++ b/tests/runner/plugins/dummy-diagnose.py @@ -1,5 +1,3 @@ -# -*- encoding: utf-8 -*- - import mobase @@ -36,4 +34,4 @@ def hasGuidedFix(self, key: int) -> bool: def createPlugins() -> list[mobase.IPlugin]: - return [DummyDiagnose(), DummyDiagnoseAndGame()] + return [DummyDiagnose(), DummyDiagnoseAndGame()] # type: ignore diff --git a/tests/runner/plugins/dummy-filemapper.py b/tests/runner/plugins/dummy-filemapper.py index cadf8af..1993b55 100644 --- a/tests/runner/plugins/dummy-filemapper.py +++ b/tests/runner/plugins/dummy-filemapper.py @@ -1,5 +1,3 @@ -# -*- encoding: utf-8 -*- - import mobase @@ -31,4 +29,4 @@ def mappings(self) -> list[mobase.Mapping]: def createPlugins() -> list[mobase.IPlugin]: - return [DummyFileMapper(), DummyFileMapperAndGame()] + return [DummyFileMapper(), DummyFileMapperAndGame()] # type: ignore diff --git a/tests/runner/plugins/dummy-game.py b/tests/runner/plugins/dummy-game.py index d4fe0bb..e17c9b8 100644 --- a/tests/runner/plugins/dummy-game.py +++ b/tests/runner/plugins/dummy-game.py @@ -1,4 +1,4 @@ -# -*- encoding: utf-8 -*- +from collections.abc import Sequence from PyQt6.QtWidgets import QWidget @@ -16,7 +16,7 @@ def fix(self, filetree: mobase.IFileTree) -> mobase.IFileTree: class DummySaveGameInfo(mobase.SaveGameInfo): - def getMissingAssets(self, save: mobase.ISaveGame) -> dict[str, list[str]]: + def getMissingAssets(self, save: mobase.ISaveGame) -> dict[str, Sequence[str]]: return {} def getSaveGameWidget(self, parent: QWidget) -> mobase.ISaveGameInfoWidget | None: diff --git a/tests/runner/plugins/dummy-iplugin.py b/tests/runner/plugins/dummy-iplugin.py index 0d85001..eaaf6c0 100644 --- a/tests/runner/plugins/dummy-iplugin.py +++ b/tests/runner/plugins/dummy-iplugin.py @@ -1,5 +1,3 @@ -# -*- encoding: utf-8 -*- - import mobase diff --git a/typings/generate.py b/typings/generate.py new file mode 100644 index 0000000..1983186 --- /dev/null +++ b/typings/generate.py @@ -0,0 +1,38 @@ +import os +import site +import sys +from pathlib import Path +from typing import cast + +import pybind11_stubgen as py11stubs + +typings_dir = Path(__file__).parent +mobase_tests_dir = Path(__file__).parent.parent.joinpath( + "vsbuild", "tests", "python", "pylibs", "mobase_tests" +) + +site.addsitedir(str(mobase_tests_dir.parent)) + +os.add_dll_directory(str(Path(cast(str, os.getenv("QT_ROOT"))).joinpath("bin"))) +os.add_dll_directory(str(os.getenv("UIBASE_PATH"))) + +from PyQt6.QtWidgets import QApplication # noqa: E402 + +app = QApplication(sys.argv) + +args = py11stubs.arg_parser().parse_args(["dummy"], namespace=py11stubs.CLIArgs()) + +parser = py11stubs.stub_parser_from_args(args) +printer = py11stubs.Printer(invalid_expr_as_ellipses=True) # type: ignore + +for path in mobase_tests_dir.glob("*.pyd"): + name = path.name.split(".")[0] + py11stubs.run( + parser, + printer, + f"mobase_tests.{name}", + typings_dir.joinpath("mobase_tests"), + sub_dir=None, + dry_run=False, + writer=py11stubs.Writer(stub_ext="pyi"), # type: ignore + ) diff --git a/typings/mobase_tests/argument_wrapper.pyi b/typings/mobase_tests/argument_wrapper.pyi new file mode 100644 index 0000000..a96e49a --- /dev/null +++ b/typings/mobase_tests/argument_wrapper.pyi @@ -0,0 +1,27 @@ +from __future__ import annotations + +__all__ = [ + "fn1_raw", + "fn1_wrap", + "fn1_wrap_0", + "fn2_raw", + "fn2_wrap", + "fn2_wrap_0", + "fn3_raw", + "fn3_wrap", + "fn3_wrap_0", + "fn3_wrap_0_2", + "fn3_wrap_2", +] + +def fn1_raw(arg0: str) -> str: ... +def fn1_wrap(arg0: int | str) -> str: ... +def fn1_wrap_0(arg0: int | str) -> str: ... +def fn2_raw(arg0: int) -> int: ... +def fn2_wrap(arg0: int | str) -> int: ... +def fn2_wrap_0(arg0: int | str) -> int: ... +def fn3_raw(arg0: int, arg1: list[int], arg2: str) -> str: ... +def fn3_wrap(arg0: int | str, arg1: list[int], arg2: int | str) -> str: ... +def fn3_wrap_0(arg0: int | str, arg1: list[int], arg2: str) -> str: ... +def fn3_wrap_0_2(arg0: int | str, arg1: list[int], arg2: int | str) -> str: ... +def fn3_wrap_2(arg0: int, arg1: list[int], arg2: int | str) -> str: ... diff --git a/typings/mobase_tests/filetree.pyi b/typings/mobase_tests/filetree.pyi new file mode 100644 index 0000000..93eab63 --- /dev/null +++ b/typings/mobase_tests/filetree.pyi @@ -0,0 +1,9 @@ +from __future__ import annotations + +import mobase + +__all__ = ["is_directory", "is_file", "value"] + +def is_directory(arg0: mobase.IFileTree.FileTypes) -> bool: ... +def is_file(arg0: mobase.IFileTree.FileTypes) -> bool: ... +def value(arg0: mobase.IFileTree.FileTypes) -> int: ... diff --git a/typings/mobase_tests/functional.pyi b/typings/mobase_tests/functional.pyi new file mode 100644 index 0000000..7e58f0e --- /dev/null +++ b/typings/mobase_tests/functional.pyi @@ -0,0 +1,19 @@ +from __future__ import annotations + +import typing + +__all__ = ["fn_0_arg", "fn_0_or_1_arg", "fn_1_arg", "fn_1_or_2_or_3_arg", "fn_2_arg"] + +def fn_0_arg(arg0: typing.Callable[[], int]) -> int: ... +@typing.overload +def fn_0_or_1_arg(arg0: typing.Callable[[], int]) -> int: ... +@typing.overload +def fn_0_or_1_arg(arg0: typing.Callable[[int], int]) -> int: ... +def fn_1_arg(arg0: typing.Callable[[int], int], arg1: int) -> int: ... +@typing.overload +def fn_1_or_2_or_3_arg(arg0: typing.Callable[[int], int]) -> int: ... +@typing.overload +def fn_1_or_2_or_3_arg(arg0: typing.Callable[[int, int], int]) -> int: ... +@typing.overload +def fn_1_or_2_or_3_arg(arg0: typing.Callable[[int, int, int], int]) -> int: ... +def fn_2_arg(arg0: typing.Callable[[int, int], int], arg1: int, arg2: int) -> int: ... diff --git a/typings/mobase_tests/guessed_string.pyi b/typings/mobase_tests/guessed_string.pyi new file mode 100644 index 0000000..a03d9b6 --- /dev/null +++ b/typings/mobase_tests/guessed_string.pyi @@ -0,0 +1,16 @@ +from __future__ import annotations + +import typing + +import mobase + +__all__ = ["get_from_callback", "get_value", "get_variants", "set_from_callback"] + +def get_from_callback( + arg0: typing.Callable[[mobase.GuessedString], None], +) -> str: ... +def get_value(arg0: str | mobase.GuessedString) -> str: ... +def get_variants(arg0: str | mobase.GuessedString) -> set[str]: ... +def set_from_callback( + arg0: mobase.GuessedString, arg1: typing.Callable[[mobase.GuessedString], None] +) -> None: ... diff --git a/typings/mobase_tests/organizer.pyi b/typings/mobase_tests/organizer.pyi new file mode 100644 index 0000000..dd5136a --- /dev/null +++ b/typings/mobase_tests/organizer.pyi @@ -0,0 +1,7 @@ +from __future__ import annotations + +import mobase + +__all__ = ["organizer"] + +def organizer() -> mobase.IOrganizer: ... diff --git a/typings/mobase_tests/qt.pyi b/typings/mobase_tests/qt.pyi new file mode 100644 index 0000000..088ef2a --- /dev/null +++ b/typings/mobase_tests/qt.pyi @@ -0,0 +1,109 @@ +from __future__ import annotations + +import typing + +import PyQt6.QtCore + +from mobase import MoVariant + +__all__ = [ + "SimpleEnum", + "consume_qstring_with_emoji", + "create_qstring_with_emoji", + "datetime_from_string", + "datetime_to_string", + "int_to_qstring", + "qflags_create", + "qflags_explode", + "qmap_to_length", + "qstring_to_int", + "qstring_to_stdstring", + "qstringlist_at", + "qstringlist_join", + "qvariant_bool", + "qvariant_from_bool", + "qvariant_from_int", + "qvariant_from_list", + "qvariant_from_map", + "qvariant_from_none", + "qvariant_from_str", + "qvariant_int", + "qvariant_list", + "qvariant_map", + "qvariant_none", + "qvariant_str", + "stdstring_to_qstring", +] + +class SimpleEnum: + """ + Members: + + Value0 + + Value1 + + Value2 + """ + + Value0: typing.ClassVar[SimpleEnum] # value = + Value1: typing.ClassVar[SimpleEnum] # value = + Value2: typing.ClassVar[SimpleEnum] # value = + __members__: typing.ClassVar[ + dict[str, SimpleEnum] + ] # value = {'Value0': , 'Value1': , 'Value2': } + def __and__(self, other: typing.Any) -> typing.Any: ... + def __eq__(self, other: typing.Any) -> bool: ... + def __ge__(self, other: typing.Any) -> bool: ... + def __getstate__(self) -> int: ... + def __gt__(self, other: typing.Any) -> bool: ... + def __hash__(self) -> int: ... + def __index__(self) -> int: ... + def __init__(self, value: int) -> None: ... + def __int__(self) -> int: ... + def __invert__(self) -> typing.Any: ... + def __le__(self, other: typing.Any) -> bool: ... + def __lt__(self, other: typing.Any) -> bool: ... + def __ne__(self, other: typing.Any) -> bool: ... + def __or__(self, other: typing.Any) -> typing.Any: ... + def __rand__(self, other: typing.Any) -> typing.Any: ... + def __repr__(self) -> str: ... + def __ror__(self, other: typing.Any) -> typing.Any: ... + def __rxor__(self, other: typing.Any) -> typing.Any: ... + def __setstate__(self, state: int) -> None: ... + def __str__(self) -> str: ... + def __xor__(self, other: typing.Any) -> typing.Any: ... + @property + def name(self) -> str: ... + @property + def value(self) -> int: ... + +def consume_qstring_with_emoji(arg0: str) -> int: ... +def create_qstring_with_emoji() -> str: ... +def datetime_from_string( + string: str, format: PyQt6.QtCore.Qt.DateFormat = ... +) -> PyQt6.QtCore.QDateTime: ... +def datetime_to_string( + datetime: PyQt6.QtCore.QDateTime, format: PyQt6.QtCore.Qt.DateFormat = ... +) -> str: ... +def int_to_qstring(arg0: int) -> str: ... +def qflags_create(arg0: bool, arg1: bool, arg2: bool) -> int: ... +def qflags_explode(arg0: int) -> tuple[int, bool, bool, bool]: ... +def qmap_to_length(arg0: dict[str, str]) -> dict[str, int]: ... +def qstring_to_int(arg0: str) -> int: ... +def qstring_to_stdstring(arg0: str) -> str: ... +def qstringlist_at(arg0: typing.Sequence[str], arg1: int) -> str: ... +def qstringlist_join(arg0: typing.Sequence[str], arg1: str) -> str: ... +def qvariant_bool() -> MoVariant: ... +def qvariant_from_bool(arg0: MoVariant) -> tuple[bool, bool]: ... +def qvariant_from_int(arg0: MoVariant) -> tuple[bool, int]: ... +def qvariant_from_list(arg0: MoVariant) -> tuple[bool, typing.Sequence[MoVariant]]: ... +def qvariant_from_map(arg0: MoVariant) -> tuple[bool, dict[str, MoVariant]]: ... +def qvariant_from_none(arg0: MoVariant) -> tuple[bool, bool]: ... +def qvariant_from_str(arg0: MoVariant) -> tuple[bool, str]: ... +def qvariant_int() -> MoVariant: ... +def qvariant_list() -> MoVariant: ... +def qvariant_map() -> dict[str, MoVariant]: ... +def qvariant_none() -> MoVariant: ... +def qvariant_str() -> MoVariant: ... +def stdstring_to_qstring(arg0: str) -> str: ... diff --git a/typings/mobase_tests/qt_widgets.pyi b/typings/mobase_tests/qt_widgets.pyi new file mode 100644 index 0000000..dfda4f9 --- /dev/null +++ b/typings/mobase_tests/qt_widgets.pyi @@ -0,0 +1,34 @@ +from __future__ import annotations + +import typing + +import PyQt6.QtWidgets + +__all__ = [ + "CustomWidget", + "get", + "heightForWidth", + "is_alive", + "is_owned_cpp", + "make_widget_own_cpp", + "make_widget_own_py", + "send_to_cpp", + "set_parent", +] + +class CustomWidget: + def __getattr__(self, arg0: str) -> typing.Any: ... + def __init__( + self, name: str, parent: PyQt6.QtWidgets.QWidget | None = None + ) -> None: ... + def _widget(self) -> PyQt6.QtWidgets.QWidget: ... + def set_parent_cpp(self) -> None: ... + +def get(arg0: str) -> PyQt6.QtWidgets.QWidget: ... +def heightForWidth(arg0: str, arg1: int) -> int: ... +def is_alive(arg0: str) -> bool: ... +def is_owned_cpp(arg0: str) -> bool: ... +def make_widget_own_cpp(arg0: str) -> PyQt6.QtWidgets.QWidget: ... +def make_widget_own_py(arg0: str) -> PyQt6.QtWidgets.QWidget: ... +def send_to_cpp(arg0: str, arg1: PyQt6.QtWidgets.QWidget) -> None: ... +def set_parent(arg0: PyQt6.QtWidgets.QWidget) -> None: ... diff --git a/typings/mobase_tests/shared_cpp_owner.pyi b/typings/mobase_tests/shared_cpp_owner.pyi new file mode 100644 index 0000000..789632e --- /dev/null +++ b/typings/mobase_tests/shared_cpp_owner.pyi @@ -0,0 +1,22 @@ +from __future__ import annotations + +__all__ = [ + "Base", + "call_fn", + "clear", + "create", + "create_and_store", + "is_alive", + "store", +] + +class Base: + def __init__(self, arg0: str) -> None: ... + def fn(self) -> str: ... + +def call_fn(arg0: str) -> str: ... +def clear() -> None: ... +def create(arg0: str) -> Base: ... +def create_and_store(arg0: str) -> Base: ... +def is_alive(arg0: str) -> bool: ... +def store(arg0: Base) -> None: ...