mirror of
https://github.com/ModOrganizer2/pystubs-generation.git
synced 2026-07-27 14:07:13 -07:00
Compare commits
11
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ece93e7cb3 | ||
|
|
4fa50f89a4 | ||
|
|
962a3c2c1f | ||
|
|
7c2581eb0c | ||
|
|
336d80a5c6 | ||
|
|
a1f5ef3a45 | ||
|
|
be6a6761f7 | ||
|
|
52f835dc75 | ||
|
|
9ee5222bbc | ||
|
|
4655e1f3eb | ||
|
|
c4a6e2266d |
@@ -1,36 +1,38 @@
|
|||||||
name: Build Documentation
|
name: Build Documentation
|
||||||
|
|
||||||
on:
|
on:
|
||||||
|
pull_request:
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- master
|
- master
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
|
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v4
|
||||||
with:
|
- name: Set up Python
|
||||||
persist-credentials: false
|
uses: actions/setup-python@v2
|
||||||
# Standard drop-in approach that should work for most people.
|
with:
|
||||||
- uses: ammaraskar/sphinx-action@master
|
python-version: 3.11
|
||||||
env:
|
- uses: abatilo/actions-poetry@v2
|
||||||
PYTHONPATH: .
|
- name: Install
|
||||||
with:
|
run: |
|
||||||
pre-build-command: "apt-get update -y && apt-get install -y libgl1-mesa-glx && cp stubs/2.4.0/mobase.pyi docs/mobase.py"
|
poetry install
|
||||||
docs-folder: "docs/"
|
- name: Install libgl1
|
||||||
|
run: sudo apt install -y libgl1 libegl1 libglib2.0-0 libxkbcommon0 libdbus-1-3
|
||||||
- name: Install SSH Client 🔑
|
- name: Copy stubs
|
||||||
uses: webfactory/ssh-agent@v0.4.1
|
run: cp stubs/2.5.0/mobase-stubs/__init__.pyi docs/mobase.py
|
||||||
with:
|
- name: Build
|
||||||
ssh-private-key: ${{ secrets.DEPLOY_KEY }}
|
run: poetry run sphinx-build -b html docs/source docs/build
|
||||||
|
env:
|
||||||
- name: Deploy 🚀
|
PYTHONPATH: docs
|
||||||
uses: JamesIves/github-pages-deploy-action@3.7.1
|
- if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }}
|
||||||
with:
|
name: Deploy Documentation
|
||||||
SSH: true
|
uses: JamesIves/github-pages-deploy-action@v4
|
||||||
REPOSITORY_NAME: ModOrganizer2/python-plugins-doc
|
with:
|
||||||
BRANCH: master
|
ssh-key: ${{ secrets.DEPLOY_KEY }}
|
||||||
FOLDER: docs/build/html
|
repository-name: ModOrganizer2/python-plugins-doc
|
||||||
|
branch: master
|
||||||
|
folder: docs/build
|
||||||
|
|||||||
@@ -5,20 +5,20 @@ on: [push, pull_request]
|
|||||||
jobs:
|
jobs:
|
||||||
checks:
|
checks:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
strategy:
|
|
||||||
max-parallel: 4
|
|
||||||
matrix:
|
|
||||||
python-version: [3.8]
|
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v4
|
||||||
- name: Set up Python ${{ matrix.python-version }}
|
- name: Set up Python
|
||||||
uses: actions/setup-python@v2
|
uses: actions/setup-python@v2
|
||||||
with:
|
with:
|
||||||
python-version: ${{ matrix.python-version }}
|
python-version: 3.11
|
||||||
- name: Install dependencies
|
- uses: abatilo/actions-poetry@v2
|
||||||
run: |
|
- name: Install
|
||||||
python -m pip install --upgrade pip
|
run: |
|
||||||
pip install tox
|
poetry install
|
||||||
- name: Test with tox
|
- name: Lint
|
||||||
run: tox -e py38-lint
|
run: |
|
||||||
|
poetry run black src --check --diff
|
||||||
|
poetry run isort -c src
|
||||||
|
poetry run mypy src
|
||||||
|
poetry run ruff src
|
||||||
|
poetry run pyright src
|
||||||
|
|||||||
@@ -1,18 +0,0 @@
|
|||||||
name: Check Documentation
|
|
||||||
|
|
||||||
on: [pull_request]
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v1
|
|
||||||
# Standard drop-in approach that should work for most people.
|
|
||||||
- uses: ammaraskar/sphinx-action@master
|
|
||||||
env:
|
|
||||||
PYTHONPATH: .
|
|
||||||
with:
|
|
||||||
pre-build-command: "apt-get update -y && apt-get install -y libgl1-mesa-glx && cp stubs/2.4.0/mobase.pyi docs/mobase.py"
|
|
||||||
docs-folder: "docs/"
|
|
||||||
@@ -1,41 +1,57 @@
|
|||||||
# This workflows will upload a Python Package using Twine when a release is created
|
# This workflows will upload a Python Package using Twine when a release is created
|
||||||
# For more information see: https://help.github.com/en/actions/language-and-framework-guides/using-python-with-github-actions#publishing-to-package-registries
|
# For more information see: https://help.github.com/en/actions/language-and-framework-guides/using-python-with-github-actions#publishing-to-package-registries
|
||||||
|
|
||||||
name: Upload Python Package
|
name: Publish Python 🐍 distribution 📦 to PyPI and TestPyPI
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
tags: ["*"]
|
tags: ["*"]
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
deploy:
|
build:
|
||||||
|
name: Build distribution 📦
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- name: Replace string
|
||||||
|
uses: frabert/replace-string-action@v1.1
|
||||||
|
id: version
|
||||||
|
with:
|
||||||
|
string: ${{ github.ref_name }}
|
||||||
|
pattern: "v?([0-9][.][0-9][.][0-9]).*"
|
||||||
|
replace-with: "$1"
|
||||||
|
- uses: actions/setup-python@v2
|
||||||
|
with:
|
||||||
|
python-version: 3.11
|
||||||
|
- uses: abatilo/actions-poetry@v2
|
||||||
|
- name: Build
|
||||||
|
run: |
|
||||||
|
cd stubs/setup
|
||||||
|
mkdir mobase-stubs
|
||||||
|
cp -r ../${{ steps.version.outputs.replaced }}/mobase-stubs/* mobase-stubs/
|
||||||
|
sed -i 's/__version__ = ".*"/__version__ = "${{ github.ref_name }}"/' mobase-stubs/__init__.pyi
|
||||||
|
TAG=${{ github.ref_name }}
|
||||||
|
poetry version ${TAG#v}
|
||||||
|
poetry build
|
||||||
|
- name: Store the distribution packages
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: python-package-distributions
|
||||||
|
path: stubs/setup/dist/
|
||||||
|
|
||||||
|
publish-to-pypi:
|
||||||
|
name: Publish Python 🐍 distribution 📦 to PyPI
|
||||||
|
needs:
|
||||||
|
- build
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
id-token: write # IMPORTANT: this permission is mandatory for trusted publishing
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- name: Download all the dists
|
||||||
- name: Replace string
|
uses: actions/download-artifact@v3
|
||||||
uses: frabert/replace-string-action@v1.1
|
with:
|
||||||
id: version
|
name: python-package-distributions
|
||||||
with:
|
path: dist/
|
||||||
string: ${{ github.ref_name }}
|
- name: Publish distribution 📦 to PyPI
|
||||||
pattern: "v?([0-9][.][0-9][.][0-9]).*"
|
uses: pypa/gh-action-pypi-publish@release/v1
|
||||||
replace-with: "$1"
|
|
||||||
- name: Set up Python
|
|
||||||
uses: actions/setup-python@v2
|
|
||||||
with:
|
|
||||||
python-version: '3.10'
|
|
||||||
- name: Install dependencies
|
|
||||||
run: |
|
|
||||||
python -m pip install --upgrade pip
|
|
||||||
pip install setuptools wheel twine
|
|
||||||
- name: Build and publish
|
|
||||||
env:
|
|
||||||
TWINE_USERNAME: ${{ secrets.PYPI_USERNAME }}
|
|
||||||
TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }}
|
|
||||||
run: |
|
|
||||||
cd stubs/setup
|
|
||||||
cp -r ../${{ steps.version.outputs.replaced }}/mobase-stubs/* mobase-stubs/
|
|
||||||
sed -i 's/__version__ = ".*"/__version__ = "${{ github.ref_name }}"/' mobase-stubs/__init__.pyi
|
|
||||||
python setup.py sdist bdist_wheel
|
|
||||||
twine upload dist/*
|
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ MO2.
|
|||||||
You can install stubs for a specific version of MO2:
|
You can install stubs for a specific version of MO2:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
pip install mobase-stubs==2.3.2.*
|
pip install mobase-stubs==2.5.*
|
||||||
```
|
```
|
||||||
|
|
||||||
Some words of warning:
|
Some words of warning:
|
||||||
@@ -38,8 +38,8 @@ have a `python310.dll` in your MO2 installation path, then you need **Python 3.1
|
|||||||
To generate the stubs, you can run:
|
To generate the stubs, you can run:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# install the package (-e if you want editable mode)
|
# install the package
|
||||||
pip install [-e] .
|
poetry install
|
||||||
|
|
||||||
# change the output folder to whatever you want
|
# change the output folder to whatever you want
|
||||||
mo2-stubs-generator -c configs/config-2.4.yml -o mobase-stubs ${MO2_INSTALL_PATH}
|
mo2-stubs-generator -c configs/config-2.4.yml -o mobase-stubs ${MO2_INSTALL_PATH}
|
||||||
|
|||||||
+75
-18
@@ -255,7 +255,7 @@ mobase:
|
|||||||
type: str
|
type: str
|
||||||
desc: Full path to the file.
|
desc: Full path to the file.
|
||||||
origins:
|
origins:
|
||||||
type: List[str]
|
type: list[str]
|
||||||
desc: |
|
desc: |
|
||||||
List of origins containing providing this file. The first origin in the list
|
List of origins containing providing this file. The first origin in the list
|
||||||
is the highest priority one (actually providing the file).
|
is the highest priority one (actually providing the file).
|
||||||
@@ -319,7 +319,7 @@ mobase:
|
|||||||
__doc__: |
|
__doc__: |
|
||||||
The parent tree containing this entry, or a `None` if this entry is the root
|
The parent tree containing this entry, or a `None` if this entry is the root
|
||||||
or the parent tree is unreachable.
|
or the parent tree is unreachable.
|
||||||
type: Optional[IFileTree]
|
type: IFileTree | None
|
||||||
|
|
||||||
path:
|
path:
|
||||||
__doc__: |
|
__doc__: |
|
||||||
@@ -356,6 +356,8 @@ mobase:
|
|||||||
returns:
|
returns:
|
||||||
lightPluginsAreSupported:
|
lightPluginsAreSupported:
|
||||||
returns: True if light plugins are supported, False otherwise.
|
returns: True if light plugins are supported, False otherwise.
|
||||||
|
overridePluginsAreSupported:
|
||||||
|
returns: True if override plugins are supported, False otherwise.
|
||||||
readPluginLists:
|
readPluginLists:
|
||||||
__doc__:
|
__doc__:
|
||||||
args:
|
args:
|
||||||
@@ -663,7 +665,7 @@ mobase:
|
|||||||
__doc__: |
|
__doc__: |
|
||||||
The entry at the given location, or `None` if the entry was not found or
|
The entry at the given location, or `None` if the entry was not found or
|
||||||
was not of the correct type.
|
was not of the correct type.
|
||||||
type: Optional[Union[IFileTree, FileTreeEntry]]
|
type: IFileTree | FileTreeEntry | None
|
||||||
|
|
||||||
insert:
|
insert:
|
||||||
__doc__: |
|
__doc__: |
|
||||||
@@ -1226,7 +1228,7 @@ mobase:
|
|||||||
type: MoVariant
|
type: MoVariant
|
||||||
desc: The data that was included in the request.
|
desc: The data that was included in the request.
|
||||||
result_data:
|
result_data:
|
||||||
type: Dict[str, MoVariant]
|
type: dict[str, MoVariant]
|
||||||
desc: The data included in the response.
|
desc: The data included in the response.
|
||||||
|
|
||||||
filesAvailable:
|
filesAvailable:
|
||||||
@@ -1242,7 +1244,7 @@ mobase:
|
|||||||
type: MoVariant
|
type: MoVariant
|
||||||
desc: The data that was included in the request.
|
desc: The data that was included in the request.
|
||||||
result_data:
|
result_data:
|
||||||
type: List[ModRepositoryFileInfo]
|
type: list[ModRepositoryFileInfo]
|
||||||
desc: List of file information objects.
|
desc: List of file information objects.
|
||||||
|
|
||||||
fileInfoAvailable:
|
fileInfoAvailable:
|
||||||
@@ -1269,7 +1271,7 @@ mobase:
|
|||||||
type: MoVariant
|
type: MoVariant
|
||||||
desc: The data that was included in the request.
|
desc: The data that was included in the request.
|
||||||
result_data:
|
result_data:
|
||||||
type: Dict[str, MoVariant]
|
type: dict[str, MoVariant]
|
||||||
desc: The data included in the response.
|
desc: The data included in the response.
|
||||||
|
|
||||||
downloadURLsAvailable:
|
downloadURLsAvailable:
|
||||||
@@ -1291,7 +1293,7 @@ mobase:
|
|||||||
type: MoVariant
|
type: MoVariant
|
||||||
desc: The data that was included in the request.
|
desc: The data that was included in the request.
|
||||||
result_data:
|
result_data:
|
||||||
type: Dict[str, MoVariant]
|
type: dict[str, MoVariant]
|
||||||
desc: The data included in the response.
|
desc: The data included in the response.
|
||||||
|
|
||||||
endorsementsAvailable:
|
endorsementsAvailable:
|
||||||
@@ -1529,17 +1531,36 @@ mobase:
|
|||||||
modsPath:
|
modsPath:
|
||||||
returns: The (absolute) path to the mods directory.
|
returns: The (absolute) path to the mods directory.
|
||||||
|
|
||||||
onAboutToRun:
|
onAboutToRun.1:
|
||||||
__doc__: |
|
__doc__: |
|
||||||
Install a new handler to be called when an application is about to run.
|
Install a new handler to be called when an application is about to run.
|
||||||
|
|
||||||
Multiple handlers can be installed. If any of the handler returns `False`, the application will
|
Multiple handlers can be installed. If any of the handler returns `False`, the
|
||||||
not run.
|
application will not run.
|
||||||
args:
|
args:
|
||||||
callback: |
|
callback: |
|
||||||
The function to call when an application is about to run. The parameter is the absolute path
|
The function to call when an application is about to run. The function
|
||||||
to the application to run. The function can return False to prevent the application from running.
|
receives the absolute path to the application to run, the working directory
|
||||||
returns: True if the handler was installed properly (there are currently no reasons for this to fail).
|
for the run and a string containing the arguments passed to the executable.
|
||||||
|
The function can return False to prevent the application from running.
|
||||||
|
returns: |
|
||||||
|
True if the handler was installed properly (there are currently no
|
||||||
|
reasons for this to fail).
|
||||||
|
|
||||||
|
onAboutToRun.2:
|
||||||
|
__doc__: |
|
||||||
|
Install a new handler to be called when an application is about to run.
|
||||||
|
|
||||||
|
Multiple handlers can be installed. If any of the handler returns `False`, the
|
||||||
|
application will not run.
|
||||||
|
args:
|
||||||
|
callback: |
|
||||||
|
The function to call when an application is about to run. The parameter
|
||||||
|
is the absolute path to the application to run. The function can return False
|
||||||
|
to prevent the application from running.
|
||||||
|
returns: |
|
||||||
|
True if the handler was installed properly (there are currently no reasons for
|
||||||
|
this to fail).
|
||||||
|
|
||||||
onFinishedRun:
|
onFinishedRun:
|
||||||
__doc__: Install a new handler to be called when an application has finished running.
|
__doc__: Install a new handler to be called when an application has finished running.
|
||||||
@@ -1547,7 +1568,19 @@ mobase:
|
|||||||
callback: |
|
callback: |
|
||||||
The function to call when an application has finished running. The first parameter is the absolute
|
The function to call when an application has finished running. The first parameter is the absolute
|
||||||
path to the application, and the second parameter is the exit code of the application.
|
path to the application, and the second parameter is the exit code of the application.
|
||||||
returns: True if the handler was installed properly (there are currently no reasons for this to fail).
|
returns: |
|
||||||
|
True if the handler was installed properly (there are currently no reasons for
|
||||||
|
this to fail).
|
||||||
|
|
||||||
|
onNextRefresh:
|
||||||
|
__doc__: Install a new handler to be called on the next refresh or immediately.
|
||||||
|
args:
|
||||||
|
callback: Function to call on the next refresh (or immediately).
|
||||||
|
immediate_if_possible: |
|
||||||
|
If True, immediately run the callback if no refresh is currently running.
|
||||||
|
returns: |
|
||||||
|
True if the handler was installed properly (there are currently no reasons for
|
||||||
|
this to fail).
|
||||||
|
|
||||||
onPluginDisabled.1:
|
onPluginDisabled.1:
|
||||||
__doc__: Install a new handler to be called when a plugin is disabled.
|
__doc__: Install a new handler to be called when a plugin is disabled.
|
||||||
@@ -1949,9 +1982,11 @@ mobase:
|
|||||||
See `IPlugin.init()` for more.
|
See `IPlugin.init()` for more.
|
||||||
|
|
||||||
CCPlugins:
|
CCPlugins:
|
||||||
|
abstract: false
|
||||||
returns: The current list of active Creation Club plugins.
|
returns: The current list of active Creation Club plugins.
|
||||||
|
|
||||||
DLCPlugins:
|
DLCPlugins:
|
||||||
|
abstract: false
|
||||||
returns: The list of esp/esm files that are part of known DLCs.
|
returns: The list of esp/esm files that are part of known DLCs.
|
||||||
|
|
||||||
binaryName:
|
binaryName:
|
||||||
@@ -1963,10 +1998,15 @@ mobase:
|
|||||||
documentsDirectory:
|
documentsDirectory:
|
||||||
returns: The directory of the documents folder where configuration files and such for this game reside.
|
returns: The directory of the documents folder where configuration files and such for this game reside.
|
||||||
|
|
||||||
|
enabledPlugins:
|
||||||
|
abstract: false
|
||||||
|
returns: A list of plugins enabled by the game but not in a strict load order.
|
||||||
|
|
||||||
executableForcedLoads:
|
executableForcedLoads:
|
||||||
returns: A list of automatically discovered libraries that can be force loaded with executables.
|
returns: A list of automatically discovered libraries that can be force loaded with executables.
|
||||||
|
|
||||||
executables:
|
executables:
|
||||||
|
abstract: false
|
||||||
returns: A list of automatically discovered executables of the game itself and tools surrounding it.
|
returns: A list of automatically discovered executables of the game itself and tools surrounding it.
|
||||||
|
|
||||||
feature:
|
feature:
|
||||||
@@ -1990,7 +2030,7 @@ mobase:
|
|||||||
abstract: false
|
abstract: false
|
||||||
returns:
|
returns:
|
||||||
__doc__: A mapping from feature type to actual game features.
|
__doc__: A mapping from feature type to actual game features.
|
||||||
type: Dict[Type[GameFeatureType], GameFeatureType]
|
type: dict[Type[GameFeatureType], GameFeatureType]
|
||||||
|
|
||||||
gameDirectory:
|
gameDirectory:
|
||||||
returns: The directory containing the game installation.
|
returns: The directory containing the game installation.
|
||||||
@@ -2002,12 +2042,14 @@ mobase:
|
|||||||
returns: The name of the game (as displayed to the user).
|
returns: The name of the game (as displayed to the user).
|
||||||
|
|
||||||
gameNexusName:
|
gameNexusName:
|
||||||
|
abstract: false
|
||||||
returns: The name of the game identifier for Nexus.
|
returns: The name of the game identifier for Nexus.
|
||||||
|
|
||||||
gameShortName:
|
gameShortName:
|
||||||
returns: The short name of the game.
|
returns: The short name of the game.
|
||||||
|
|
||||||
gameVariants:
|
gameVariants:
|
||||||
|
abstract: false
|
||||||
__doc__: |
|
__doc__: |
|
||||||
Retrieve the list of variants for this game.
|
Retrieve the list of variants for this game.
|
||||||
|
|
||||||
@@ -2028,6 +2070,7 @@ mobase:
|
|||||||
returns: An URL for the support page of this game.
|
returns: An URL for the support page of this game.
|
||||||
|
|
||||||
iniFiles:
|
iniFiles:
|
||||||
|
abstract: false
|
||||||
returns: |
|
returns: |
|
||||||
The list of INI files this game uses. The first file in the list should be the
|
The list of INI files this game uses. The first file in the list should be the
|
||||||
'main' INI file.
|
'main' INI file.
|
||||||
@@ -2055,6 +2098,7 @@ mobase:
|
|||||||
returns: The list of game saves in the given folder.
|
returns: The list of game saves in the given folder.
|
||||||
|
|
||||||
loadOrderMechanism:
|
loadOrderMechanism:
|
||||||
|
abstract: false
|
||||||
returns: The load order mechanism used by this game.
|
returns: The load order mechanism used by this game.
|
||||||
|
|
||||||
looksValid:
|
looksValid:
|
||||||
@@ -2071,6 +2115,7 @@ mobase:
|
|||||||
returns: The Nexus game ID for this game.
|
returns: The Nexus game ID for this game.
|
||||||
|
|
||||||
nexusModOrganizerID:
|
nexusModOrganizerID:
|
||||||
|
abstract: false
|
||||||
__doc__: |
|
__doc__: |
|
||||||
Retrieve the Nexus mod ID of Mod Organizer for this game.
|
Retrieve the Nexus mod ID of Mod Organizer for this game.
|
||||||
|
|
||||||
@@ -2079,9 +2124,11 @@ mobase:
|
|||||||
returns: The Nexus mod ID of Mod Organizer for this game.
|
returns: The Nexus mod ID of Mod Organizer for this game.
|
||||||
|
|
||||||
primaryPlugins:
|
primaryPlugins:
|
||||||
|
abstract: false
|
||||||
returns: The list of plugins that are part of the game and not considered optional.
|
returns: The list of plugins that are part of the game and not considered optional.
|
||||||
|
|
||||||
primarySources:
|
primarySources:
|
||||||
|
abstract: false
|
||||||
__doc__: |
|
__doc__: |
|
||||||
Retrieve primary alternative 'short' names for this game.
|
Retrieve primary alternative 'short' names for this game.
|
||||||
|
|
||||||
@@ -2092,6 +2139,14 @@ mobase:
|
|||||||
savesDirectory:
|
savesDirectory:
|
||||||
returns: The directory where save games are stored.
|
returns: The directory where save games are stored.
|
||||||
|
|
||||||
|
secondaryDataDirectories:
|
||||||
|
abstract: false
|
||||||
|
__doc__: |
|
||||||
|
Retrieve the list of secondary data directories. Each directories should be
|
||||||
|
assigned a unique name that differs from "data" which is the name of the main
|
||||||
|
data directory returned by dataDirectory().
|
||||||
|
returns: A mapping from unique name to secondary data directories.
|
||||||
|
|
||||||
setGamePath:
|
setGamePath:
|
||||||
__doc__: |
|
__doc__: |
|
||||||
Set the path to the managed game.
|
Set the path to the managed game.
|
||||||
@@ -2112,9 +2167,11 @@ mobase:
|
|||||||
variant: The game variant selected by the user.
|
variant: The game variant selected by the user.
|
||||||
|
|
||||||
sortMechanism:
|
sortMechanism:
|
||||||
|
abstract: false
|
||||||
returns: The sort mechanism for this game.
|
returns: The sort mechanism for this game.
|
||||||
|
|
||||||
steamAPPId:
|
steamAPPId:
|
||||||
|
abstract: false
|
||||||
__doc__: |
|
__doc__: |
|
||||||
Retrieve the Steam app ID for this game.
|
Retrieve the Steam app ID for this game.
|
||||||
|
|
||||||
@@ -2788,7 +2845,7 @@ mobase:
|
|||||||
filetree: The tree to try to fix. Can be modified during the process.
|
filetree: The tree to try to fix. Can be modified during the process.
|
||||||
returns:
|
returns:
|
||||||
__doc__: The fixed tree, or a null pointer if the tree could not be fixed.
|
__doc__: The fixed tree, or a null pointer if the tree could not be fixed.
|
||||||
type: Optional["IFileTree"]
|
type: IFileTree | None
|
||||||
|
|
||||||
ModDataContent:
|
ModDataContent:
|
||||||
__doc__: |
|
__doc__: |
|
||||||
@@ -2998,7 +3055,7 @@ mobase:
|
|||||||
parent: The parent widget.
|
parent: The parent widget.
|
||||||
returns:
|
returns:
|
||||||
__doc__: A SaveGameInfoWidget to display information about save game.
|
__doc__: A SaveGameInfoWidget to display information about save game.
|
||||||
type: Optional[ISaveGameInfoWidget]
|
type: ISaveGameInfoWidget | None
|
||||||
|
|
||||||
ScriptExtender:
|
ScriptExtender:
|
||||||
__doc__:
|
__doc__:
|
||||||
@@ -3175,7 +3232,7 @@ mobase.widgets:
|
|||||||
Display this dialog and wait for user-interaction to return. This is a blocking
|
Display this dialog and wait for user-interaction to return. This is a blocking
|
||||||
function.
|
function.
|
||||||
|
|
||||||
returns:
|
returns: |
|
||||||
The button clicked by the user. Without custom buttons, this return Ok,
|
The button clicked by the user. Without custom buttons, this return Ok,
|
||||||
otherwise it returns the button set in the TaskDialogButton.
|
otherwise it returns the button set in the TaskDialogButton.
|
||||||
|
|
||||||
|
|||||||
@@ -1,20 +0,0 @@
|
|||||||
# Minimal makefile for Sphinx documentation
|
|
||||||
#
|
|
||||||
|
|
||||||
# You can set these variables from the command line, and also
|
|
||||||
# from the environment for the first two.
|
|
||||||
SPHINXOPTS ?=
|
|
||||||
SPHINXBUILD ?= sphinx-build
|
|
||||||
SOURCEDIR = source
|
|
||||||
BUILDDIR = build
|
|
||||||
|
|
||||||
# Put it first so that "make" without argument is like "make help".
|
|
||||||
help:
|
|
||||||
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
|
||||||
|
|
||||||
.PHONY: help Makefile
|
|
||||||
|
|
||||||
# Catch-all target: route all unknown targets to Sphinx using the new
|
|
||||||
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
|
|
||||||
%: Makefile
|
|
||||||
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
@ECHO OFF
|
|
||||||
|
|
||||||
pushd %~dp0
|
|
||||||
|
|
||||||
REM Command file for Sphinx documentation
|
|
||||||
|
|
||||||
if "%SPHINXBUILD%" == "" (
|
|
||||||
set SPHINXBUILD=sphinx-build
|
|
||||||
)
|
|
||||||
set SOURCEDIR=source
|
|
||||||
set BUILDDIR=build
|
|
||||||
|
|
||||||
if "%1" == "" goto help
|
|
||||||
|
|
||||||
%SPHINXBUILD% >NUL 2>NUL
|
|
||||||
if errorlevel 9009 (
|
|
||||||
echo.
|
|
||||||
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
|
|
||||||
echo.installed, then set the SPHINXBUILD environment variable to point
|
|
||||||
echo.to the full path of the 'sphinx-build' executable. Alternatively you
|
|
||||||
echo.may add the Sphinx directory to PATH.
|
|
||||||
echo.
|
|
||||||
echo.If you don't have Sphinx installed, grab it from
|
|
||||||
echo.http://sphinx-doc.org/
|
|
||||||
exit /b 1
|
|
||||||
)
|
|
||||||
|
|
||||||
%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
|
|
||||||
goto end
|
|
||||||
|
|
||||||
:help
|
|
||||||
%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
|
|
||||||
|
|
||||||
:end
|
|
||||||
popd
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
sphinx-rtd-theme
|
sphinx-rtd-theme
|
||||||
sphinx-autodoc-typehints
|
sphinx-autodoc-typehints
|
||||||
sphinx-automodapi
|
sphinx-automodapi
|
||||||
PyQt5
|
PyQt6
|
||||||
|
|||||||
+2
-10
@@ -10,21 +10,13 @@
|
|||||||
# add these directories to sys.path here. If the directory is relative to the
|
# add these directories to sys.path here. If the directory is relative to the
|
||||||
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||||
#
|
#
|
||||||
import os
|
|
||||||
import sys
|
|
||||||
|
|
||||||
sys.path.insert(0, os.path.abspath("../../stubs/2.4.0/"))
|
|
||||||
|
|
||||||
|
|
||||||
# -- Project information -----------------------------------------------------
|
# -- Project information -----------------------------------------------------
|
||||||
|
|
||||||
project = "MO2 Python Plugin API"
|
project = "MO2 Python Plugin API"
|
||||||
copyright = "2020, Holt59"
|
copyright = "2023, Holt59"
|
||||||
author = "Holt59"
|
author = "Holt59"
|
||||||
|
|
||||||
# The full version, including alpha/beta/rc tags
|
|
||||||
release = "2.3rc1"
|
|
||||||
|
|
||||||
|
|
||||||
# -- General configuration ---------------------------------------------------
|
# -- General configuration ---------------------------------------------------
|
||||||
|
|
||||||
@@ -69,5 +61,5 @@ html_favicon = "mo2.ico"
|
|||||||
# Add any paths that contain custom static files (such as style sheets) here,
|
# Add any paths that contain custom static files (such as style sheets) here,
|
||||||
# relative to this directory. They are copied after the builtin static files,
|
# relative to this directory. They are copied after the builtin static files,
|
||||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||||
html_static_path = ["_static"]
|
# html_static_path = ["_static"]
|
||||||
html_extra_path = [".nojekyll"]
|
html_extra_path = [".nojekyll"]
|
||||||
|
|||||||
@@ -0,0 +1,61 @@
|
|||||||
|
[tool.poetry]
|
||||||
|
name = "mo2-pystubs-generation"
|
||||||
|
version = "0.1.0"
|
||||||
|
description = ""
|
||||||
|
authors = ["Holt59 <capelle.mikael@gmail.com>"]
|
||||||
|
license = "MIT"
|
||||||
|
readme = "README.md"
|
||||||
|
packages = [{ include = "mo2", from = "src" }]
|
||||||
|
|
||||||
|
[tool.poetry.scripts]
|
||||||
|
mo2-stubs-generator = "mo2.stubs.generator.__main__:main"
|
||||||
|
|
||||||
|
[tool.poetry.dependencies]
|
||||||
|
python = "^3.11"
|
||||||
|
pyqt6 = "^6.5.2"
|
||||||
|
pyyaml = "^6.0.1"
|
||||||
|
|
||||||
|
|
||||||
|
[tool.poetry.group.dev.dependencies]
|
||||||
|
black = "^23.9.1"
|
||||||
|
mypy = "^1.5.1"
|
||||||
|
pyright = "^1.1.327"
|
||||||
|
isort = "^5.12.0"
|
||||||
|
ruff = "^0.0.290"
|
||||||
|
flake8 = "^6.1.0"
|
||||||
|
flake8-black = "^0.3.6"
|
||||||
|
flake8-pyproject = "^1.2.3"
|
||||||
|
types-pyyaml = "^6.0.12.11"
|
||||||
|
|
||||||
|
|
||||||
|
[tool.poetry.group.doc.dependencies]
|
||||||
|
sphinx-rtd-theme = "^1.3.0"
|
||||||
|
sphinx-autodoc-typehints = "^1.24.0"
|
||||||
|
sphinx-automodapi = "^0.16.0"
|
||||||
|
sphinx = "^7.2.6"
|
||||||
|
|
||||||
|
[build-system]
|
||||||
|
requires = ["poetry-core"]
|
||||||
|
build-backend = "poetry.core.masonry.api"
|
||||||
|
|
||||||
|
[tool.flake8]
|
||||||
|
max-line-length = 88
|
||||||
|
extend-ignore = ["E203"]
|
||||||
|
|
||||||
|
[tool.isort]
|
||||||
|
profile = "black"
|
||||||
|
multi_line_output = 3
|
||||||
|
|
||||||
|
[tool.ruff]
|
||||||
|
line-length = 88
|
||||||
|
target-version = "py311"
|
||||||
|
|
||||||
|
[tool.mypy]
|
||||||
|
warn_return_any = true
|
||||||
|
warn_unused_configs = true
|
||||||
|
namespace_packages = true
|
||||||
|
|
||||||
|
[tool.pyright]
|
||||||
|
# reportMissingTypeStubs = true
|
||||||
|
# reportUntypedBaseClass = false
|
||||||
|
typeCheckingMode = "strict"
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
[flake8]
|
|
||||||
# Use black line length:
|
|
||||||
max-line-length = 88
|
|
||||||
extend-ignore =
|
|
||||||
# See https://github.com/PyCQA/pycodestyle/issues/373
|
|
||||||
E203,
|
|
||||||
per-file-ignores =
|
|
||||||
*.pyi: E301, E302, E305, E501, E701, E741, F401, F403, F405, F822
|
|
||||||
# Since typing.pyi defines "overload" this is not recognized by flake8 as typing.overload.
|
|
||||||
# Unfortunately, flake8 does not allow to "noqa" just a specific error inside the file itself.
|
|
||||||
typing.pyi: E301, E302, E305, E501, E701, E741, F401, F403, F405, F811, F822
|
|
||||||
|
|
||||||
[mypy]
|
|
||||||
warn_return_any = True
|
|
||||||
warn_unused_configs = True
|
|
||||||
namespace_packages = True
|
|
||||||
|
|
||||||
[isort]
|
|
||||||
profile = black
|
|
||||||
multi_line_output = 3
|
|
||||||
|
|
||||||
[tox:tox]
|
|
||||||
skipsdist = true
|
|
||||||
envlist = py310-lint
|
|
||||||
|
|
||||||
[testenv:py310-lint]
|
|
||||||
skip_install = true
|
|
||||||
deps =
|
|
||||||
black
|
|
||||||
mypy
|
|
||||||
flake8
|
|
||||||
flake8-black
|
|
||||||
git+https://github.com/TilmanK/PyQt6-stubs.git
|
|
||||||
types-PyYAML
|
|
||||||
isort
|
|
||||||
commands =
|
|
||||||
black src --check --diff
|
|
||||||
flake8 src
|
|
||||||
mypy src
|
|
||||||
isort -c src
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
# -*- encoding: utf-8 -*-
|
|
||||||
|
|
||||||
from setuptools import find_namespace_packages, setup
|
|
||||||
|
|
||||||
install_requires = ["black", "isort"]
|
|
||||||
|
|
||||||
dev_requires = [
|
|
||||||
"black",
|
|
||||||
"flake8-black",
|
|
||||||
"flake8",
|
|
||||||
"types-chardet",
|
|
||||||
]
|
|
||||||
|
|
||||||
setup(
|
|
||||||
name="mo2-stubs-generator",
|
|
||||||
version="1.0.0",
|
|
||||||
package_dir={"": "src"},
|
|
||||||
packages=find_namespace_packages(where="src", include=["mo2.*"]),
|
|
||||||
author="Holt59",
|
|
||||||
author_email="capelle.mikael@gmail",
|
|
||||||
description="Python stubs generator for mobase (MO2 Python API).",
|
|
||||||
long_description=open("README.md").read(),
|
|
||||||
url="https://github.com/ModOrganizer2/pystubs-generation",
|
|
||||||
classifiers=[
|
|
||||||
"Programming Language :: Python",
|
|
||||||
"Programming Language :: Python :: 3",
|
|
||||||
"Programming Language :: Python :: 3.10",
|
|
||||||
],
|
|
||||||
license="MIT",
|
|
||||||
install_requires=install_requires,
|
|
||||||
extras_require={"dev": dev_requires},
|
|
||||||
entry_points={
|
|
||||||
"console_scripts": ["mo2-stubs-generator=mo2.stubs.generator.__main__:main"],
|
|
||||||
},
|
|
||||||
)
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
# -*- encoding: utf-8 -*-
|
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
from .loader import load_mobase
|
||||||
|
|
||||||
LOGGER = logging.getLogger(__name__)
|
LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
from .loader import load_mobase # noqa: F401
|
__all__ = ["load_mobase", "LOGGER"]
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
# -*- encoding: utf-8 -*-
|
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
import inspect
|
import inspect
|
||||||
import logging
|
import logging
|
||||||
@@ -10,7 +8,6 @@ from typing import Callable
|
|||||||
import black
|
import black
|
||||||
import isort
|
import isort
|
||||||
|
|
||||||
from . import LOGGER
|
|
||||||
from .loader import load_mobase
|
from .loader import load_mobase
|
||||||
from .mtypes import Class, PyTyping
|
from .mtypes import Class, PyTyping
|
||||||
from .parser import is_enum
|
from .parser import is_enum
|
||||||
@@ -18,10 +15,11 @@ from .register import MobaseRegister
|
|||||||
from .utils import Settings, clean_class
|
from .utils import Settings, clean_class
|
||||||
from .writer import Writer, is_list_of_functions
|
from .writer import Writer, is_list_of_functions
|
||||||
|
|
||||||
|
LOGGER = logging.getLogger(__package__)
|
||||||
|
|
||||||
def extract_objects(module: object, skips: list[str] = []) -> list[tuple[str, object]]:
|
|
||||||
|
|
||||||
objects: list[tuple[str, object]] = []
|
def extract_objects(module: object, skips: list[str] = []) -> list[tuple[str, type]]:
|
||||||
|
objects: list[tuple[str, type]] = []
|
||||||
|
|
||||||
assert hasattr(module, "__name__")
|
assert hasattr(module, "__name__")
|
||||||
module_name: str = module.__name__ # type: ignore
|
module_name: str = module.__name__ # type: ignore
|
||||||
@@ -90,8 +88,7 @@ def add_mobase_widgets_header(writer: Writer):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main() -> None:
|
||||||
|
|
||||||
parser = argparse.ArgumentParser("stubs generator for the MO2 python interface")
|
parser = argparse.ArgumentParser("stubs generator for the MO2 python interface")
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"install_dir",
|
"install_dir",
|
||||||
@@ -145,7 +142,7 @@ def main():
|
|||||||
}
|
}
|
||||||
|
|
||||||
# list of objects directly in mobase
|
# list of objects directly in mobase
|
||||||
module_objects: dict[str, list[tuple[str, object]]] = {
|
module_objects: dict[str, list[tuple[str, type]]] = {
|
||||||
"mobase": extract_objects(
|
"mobase": extract_objects(
|
||||||
mobase,
|
mobase,
|
||||||
[
|
[
|
||||||
@@ -153,11 +150,10 @@ def main():
|
|||||||
"IPlugin",
|
"IPlugin",
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
"mobase.widgets": extract_objects(mobase.widgets),
|
"mobase.widgets": extract_objects(getattr(mobase, "widgets")),
|
||||||
}
|
}
|
||||||
|
|
||||||
for name, objects in module_objects.items():
|
for name, objects in module_objects.items():
|
||||||
|
|
||||||
# load settings from the configuration
|
# load settings from the configuration
|
||||||
settings: Settings = Settings(register)
|
settings: Settings = Settings(register)
|
||||||
if config_path is not None:
|
if config_path is not None:
|
||||||
@@ -174,12 +170,10 @@ def main():
|
|||||||
|
|
||||||
# Process everything:
|
# Process everything:
|
||||||
for n, o in objects:
|
for n, o in objects:
|
||||||
|
|
||||||
# Create the corresponding object:
|
# Create the corresponding object:
|
||||||
c = register.make_object(n, o)
|
c = register.make_object(n, o)
|
||||||
|
|
||||||
if isinstance(c, Class):
|
if isinstance(c, Class):
|
||||||
|
|
||||||
# Clean the class (e.g., remove duplicates methods due to wrappers):
|
# Clean the class (e.g., remove duplicates methods due to wrappers):
|
||||||
clean_class(c)
|
clean_class(c)
|
||||||
|
|
||||||
@@ -208,7 +202,6 @@ def main():
|
|||||||
|
|
||||||
# write everything
|
# write everything
|
||||||
with open(output_folder.joinpath("__init__.pyi"), "w") as output:
|
with open(output_folder.joinpath("__init__.pyi"), "w") as output:
|
||||||
|
|
||||||
writer = Writer(package=name, output=output, settings=settings)
|
writer = Writer(package=name, output=output, settings=settings)
|
||||||
|
|
||||||
# the __future__ import must be at the beginning
|
# the __future__ import must be at the beginning
|
||||||
@@ -218,7 +211,6 @@ def main():
|
|||||||
module_headers[name](writer)
|
module_headers[name](writer)
|
||||||
|
|
||||||
for n, o in objects:
|
for n, o in objects:
|
||||||
|
|
||||||
# Get the corresponding object:
|
# Get the corresponding object:
|
||||||
c = register.get_object(n)
|
c = register.get_object(n)
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,11 @@
|
|||||||
# -*- encoding: utf-8 -*-
|
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
from modulefinder import Module
|
from modulefinder import Module
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
|
||||||
def load_mobase(path: os.PathLike) -> Module:
|
def load_mobase(path: os.PathLike[Any]) -> Module:
|
||||||
"""
|
"""
|
||||||
Load the mobase from the given MO2 installation path and
|
Load the mobase from the given MO2 installation path and
|
||||||
returns it.
|
returns it.
|
||||||
@@ -30,8 +29,8 @@ def load_mobase(path: os.PathLike) -> Module:
|
|||||||
[str(path), str(path.joinpath("dlls")), os.environ.get("PATH", "")]
|
[str(path), str(path.joinpath("dlls")), os.environ.get("PATH", "")]
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
os.add_dll_directory(str(path))
|
os.add_dll_directory(str(path)) # type: ignore
|
||||||
os.add_dll_directory(str(path.joinpath("dlls")))
|
os.add_dll_directory(str(path.joinpath("dlls"))) # type: ignore
|
||||||
|
|
||||||
# We need to add plugins/data to sys.path, mainly for PyQt6
|
# We need to add plugins/data to sys.path, mainly for PyQt6
|
||||||
sys.path.insert(1, path.joinpath("plugins", "plugin_python", "libs").as_posix())
|
sys.path.insert(1, path.joinpath("plugins", "plugin_python", "libs").as_posix())
|
||||||
@@ -42,7 +41,6 @@ def load_mobase(path: os.PathLike) -> Module:
|
|||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
|
|
||||||
parser = argparse.ArgumentParser(
|
parser = argparse.ArgumentParser(
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
# -*- encoding: utf-8 -*-
|
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import re
|
import re
|
||||||
@@ -122,7 +120,6 @@ class Argument:
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def value(self) -> str | None:
|
def value(self) -> str | None:
|
||||||
|
|
||||||
value = self._value
|
value = self._value
|
||||||
|
|
||||||
if value is None:
|
if value is None:
|
||||||
@@ -341,7 +338,7 @@ class Class:
|
|||||||
for ic in self.inner_classes:
|
for ic in self.inner_classes:
|
||||||
ic.outer_class = self
|
ic.outer_class = self
|
||||||
|
|
||||||
def is_abstract(self):
|
def is_abstract(self) -> bool:
|
||||||
"""
|
"""
|
||||||
Returns:
|
Returns:
|
||||||
True if this class is abstract, False otherwise.
|
True if this class is abstract, False otherwise.
|
||||||
@@ -349,7 +346,7 @@ class Class:
|
|||||||
return self.abstract or any(bc.is_abstract() for bc in self.bases)
|
return self.abstract or any(bc.is_abstract() for bc in self.bases)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def canonical_name(self):
|
def canonical_name(self) -> str:
|
||||||
"""
|
"""
|
||||||
Returns:
|
Returns:
|
||||||
The canonical name of this class.
|
The canonical name of this class.
|
||||||
@@ -357,13 +354,13 @@ class Class:
|
|||||||
name = self.name
|
name = self.name
|
||||||
oc = self.outer_class
|
oc = self.outer_class
|
||||||
while oc is not None:
|
while oc is not None:
|
||||||
name = "{}.{}".format(oc.name, name)
|
name = f"{oc.name}.{name}"
|
||||||
oc = oc.outer_class
|
oc = oc.outer_class
|
||||||
|
|
||||||
return name
|
return name
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def full_name(self):
|
def full_name(self) -> str:
|
||||||
"""
|
"""
|
||||||
Returns:
|
Returns:
|
||||||
The full name of this class, i.e., package.canonical_name.
|
The full name of this class, i.e., package.canonical_name.
|
||||||
|
|||||||
@@ -1,13 +1,11 @@
|
|||||||
# -*- encoding: utf-8 -*-
|
|
||||||
|
|
||||||
import inspect
|
import inspect
|
||||||
|
import logging
|
||||||
import re
|
import re
|
||||||
import types
|
import types
|
||||||
from collections import OrderedDict, defaultdict
|
from collections import OrderedDict, defaultdict
|
||||||
from itertools import chain
|
from itertools import chain
|
||||||
from typing import Iterable, cast
|
from typing import Any, Iterable, cast
|
||||||
|
|
||||||
from . import LOGGER
|
|
||||||
from .mtypes import (
|
from .mtypes import (
|
||||||
Argument,
|
Argument,
|
||||||
Class,
|
Class,
|
||||||
@@ -22,8 +20,12 @@ from .mtypes import (
|
|||||||
)
|
)
|
||||||
from .register import MobaseRegister
|
from .register import MobaseRegister
|
||||||
|
|
||||||
|
LOGGER = logging.getLogger(__package__)
|
||||||
|
|
||||||
def magic_split(value: str, sep=",", open="(<[", close=")>]"):
|
|
||||||
|
def magic_split(
|
||||||
|
value: str, sep: str = ",", open: str = "(<[", close: str = ")>]"
|
||||||
|
) -> list[str]:
|
||||||
"""
|
"""
|
||||||
Split the value according to the given separator, but keeps together elements
|
Split the value according to the given separator, but keeps together elements
|
||||||
within the given separator. Useful to split C++ signature function since type names
|
within the given separator. Useful to split C++ signature function since type names
|
||||||
@@ -42,8 +44,8 @@ def magic_split(value: str, sep=",", open="(<[", close=")>]"):
|
|||||||
Returns: The list of split parts from value.
|
Returns: The list of split parts from value.
|
||||||
"""
|
"""
|
||||||
i, j = 0, 0
|
i, j = 0, 0
|
||||||
s: list[str] = []
|
s: list[int] = []
|
||||||
r = []
|
r: list[str] = []
|
||||||
while i < len(value):
|
while i < len(value):
|
||||||
j = i + 1
|
j = i + 1
|
||||||
while j < len(value):
|
while j < len(value):
|
||||||
@@ -96,8 +98,8 @@ def parse_python_signature(s: str, name: str) -> tuple[PyType, list[Argument]]:
|
|||||||
args = magic_split(m.group(1).strip(), ",", open="[", close="]")
|
args = magic_split(m.group(1).strip(), ",", open="[", close="]")
|
||||||
return_type = m.group(2)
|
return_type = m.group(2)
|
||||||
|
|
||||||
arguments = []
|
arguments: list[Argument] = []
|
||||||
for i, pa in enumerate(args):
|
for pa in args:
|
||||||
m = re.search(
|
m = re.search(
|
||||||
r"(?P<name>[^:]+)\s*:\s*(?P<type>[^=]+)\s*(=\s*(?P<value>[^,]+))?",
|
r"(?P<name>[^:]+)\s*:\s*(?P<type>[^=]+)\s*(=\s*(?P<value>[^,]+))?",
|
||||||
pa.strip(),
|
pa.strip(),
|
||||||
@@ -106,9 +108,12 @@ def parse_python_signature(s: str, name: str) -> tuple[PyType, list[Argument]]:
|
|||||||
raise ValueError(f"invalid argument: {pa}, {s}")
|
raise ValueError(f"invalid argument: {pa}, {s}")
|
||||||
|
|
||||||
matches = m.groupdict()
|
matches = m.groupdict()
|
||||||
arguments.append(
|
type_ = matches["type"]
|
||||||
Argument(matches["name"], PyType(matches["type"]), matches["value"])
|
if matches["value"] == "None":
|
||||||
)
|
if "None" not in type_ and "MoVariant" not in type_:
|
||||||
|
type_ = type_ + " | None"
|
||||||
|
|
||||||
|
arguments.append(Argument(matches["name"], PyType(type_), matches["value"]))
|
||||||
|
|
||||||
return PyType(return_type), arguments
|
return PyType(return_type), arguments
|
||||||
|
|
||||||
@@ -140,7 +145,7 @@ class Overload:
|
|||||||
self.arguments = arguments
|
self.arguments = arguments
|
||||||
|
|
||||||
|
|
||||||
def parse_pybind11_function_docstring(e) -> list[Overload]:
|
def parse_pybind11_function_docstring(e: type) -> list[Overload]:
|
||||||
"""
|
"""
|
||||||
Parse the docstring of the given element.
|
Parse the docstring of the given element.
|
||||||
|
|
||||||
@@ -150,7 +155,7 @@ def parse_pybind11_function_docstring(e) -> list[Overload]:
|
|||||||
Returns:
|
Returns:
|
||||||
A list of overloads for the given function.
|
A list of overloads for the given function.
|
||||||
"""
|
"""
|
||||||
lines = e.__doc__.strip().split("\n")
|
lines = (e.__doc__ or "").strip().split("\n")
|
||||||
|
|
||||||
signatures: list[str]
|
signatures: list[str]
|
||||||
if len(lines) == 1:
|
if len(lines) == 1:
|
||||||
@@ -166,7 +171,6 @@ def parse_pybind11_function_docstring(e) -> list[Overload]:
|
|||||||
# them...
|
# them...
|
||||||
overloads: list[Overload] = []
|
overloads: list[Overload] = []
|
||||||
for signature in signatures:
|
for signature in signatures:
|
||||||
|
|
||||||
# fix MOBase:: in some places to get proper Python types
|
# fix MOBase:: in some places to get proper Python types
|
||||||
signature = signature.replace("MOBase::", "mobase.").replace("::", ".")
|
signature = signature.replace("MOBase::", "mobase.").replace("::", ".")
|
||||||
|
|
||||||
@@ -179,7 +183,7 @@ def parse_pybind11_function_docstring(e) -> list[Overload]:
|
|||||||
return overloads
|
return overloads
|
||||||
|
|
||||||
|
|
||||||
def make_functions(e) -> list[Function]:
|
def make_functions(e: type) -> list[Function]:
|
||||||
overloads = parse_pybind11_function_docstring(e)
|
overloads = parse_pybind11_function_docstring(e)
|
||||||
|
|
||||||
return [
|
return [
|
||||||
@@ -310,7 +314,9 @@ def make_class(e: type, register: MobaseRegister) -> Class:
|
|||||||
for base_class in base_classes:
|
for base_class in base_classes:
|
||||||
for biclass in base_class.inner_classes:
|
for biclass in base_class.inner_classes:
|
||||||
if isinstance(biclass, Enum) and biclass.name == base_name:
|
if isinstance(biclass, Enum) and biclass.name == base_name:
|
||||||
arg._value = base_class.name + "." + value
|
arg._value = ( # pyright: ignore[reportPrivateUsage]
|
||||||
|
base_class.name + "." + value
|
||||||
|
)
|
||||||
|
|
||||||
methods.append(
|
methods.append(
|
||||||
Method(
|
Method(
|
||||||
@@ -323,8 +329,8 @@ def make_class(e: type, register: MobaseRegister) -> Class:
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Retrieve the attributes:
|
# Retrieve the attributes:
|
||||||
constants = []
|
constants: list[Constant] = []
|
||||||
properties = []
|
properties: list[Property] = []
|
||||||
for name, attr in all_attrs:
|
for name, attr in all_attrs:
|
||||||
if callable(attr) or isinstance(attr, type):
|
if callable(attr) or isinstance(attr, type):
|
||||||
continue
|
continue
|
||||||
@@ -341,7 +347,9 @@ def make_class(e: type, register: MobaseRegister) -> Class:
|
|||||||
direct_bases: list[Class] = []
|
direct_bases: list[Class] = []
|
||||||
for c in e.__bases__:
|
for c in e.__bases__:
|
||||||
if c.__module__ != "pybind11_builtins":
|
if c.__module__ != "pybind11_builtins":
|
||||||
direct_bases.append(register.get_object(c.__name__))
|
b = register.get_object(c.__name__)
|
||||||
|
assert isinstance(b, Class)
|
||||||
|
direct_bases.append(b)
|
||||||
|
|
||||||
# Forcing QWidget base for XWidget classes since these do not show up
|
# Forcing QWidget base for XWidget classes since these do not show up
|
||||||
# and we use a trick:
|
# and we use a trick:
|
||||||
@@ -356,7 +364,7 @@ def make_class(e: type, register: MobaseRegister) -> Class:
|
|||||||
# check if it an enum
|
# check if it an enum
|
||||||
if is_enum(e):
|
if is_enum(e):
|
||||||
# all pybind11 enums have a .__entries attribute
|
# all pybind11 enums have a .__entries attribute
|
||||||
values = e.__entries # type: ignore
|
values = cast(dict[str, tuple[int, Any]], e.__entries) # type: ignore
|
||||||
|
|
||||||
# drop the __init__
|
# drop the __init__
|
||||||
methods = [m for m in methods if m.name != "__init__"]
|
methods = [m for m in methods if m.name != "__init__"]
|
||||||
|
|||||||
@@ -12,16 +12,18 @@ class MobaseRegister:
|
|||||||
Class that register classes.
|
Class that register classes.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
objects: dict[str, Class | list[Function]]
|
objects: dict[str, Class | list[Function] | PyTyping]
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self) -> None:
|
||||||
self.raw_objects: dict[str, type] = OrderedDict()
|
self.raw_objects: dict[str, type] = OrderedDict()
|
||||||
self.objects = {}
|
self.objects = {}
|
||||||
|
|
||||||
def add_object(self, name, object):
|
def add_object(self, name: str, object: type) -> None:
|
||||||
self.raw_objects[name] = object
|
self.raw_objects[name] = object
|
||||||
|
|
||||||
def make_object(self, name: str, e: type | None = None) -> Class | list[Function]:
|
def make_object(
|
||||||
|
self, name: str, e: type | None = None
|
||||||
|
) -> Class | list[Function] | PyTyping:
|
||||||
"""
|
"""
|
||||||
Construct a Function, Class or Enum for the given object.
|
Construct a Function, Class or Enum for the given object.
|
||||||
|
|
||||||
@@ -52,7 +54,7 @@ class MobaseRegister:
|
|||||||
|
|
||||||
return self.objects[name]
|
return self.objects[name]
|
||||||
|
|
||||||
def get_object(self, name: str):
|
def get_object(self, name: str) -> Class | list[Function] | PyTyping:
|
||||||
"""
|
"""
|
||||||
Retrieve the object if the given name. Fails if no object with this
|
Retrieve the object if the given name. Fails if no object with this
|
||||||
name exists (if `make_object(name, ...)` has never been called).
|
name exists (if `make_object(name, ...)` has never been called).
|
||||||
|
|||||||
@@ -1,13 +1,11 @@
|
|||||||
# -*- encoding: utf-8 -*-
|
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import logging
|
||||||
from collections import OrderedDict, defaultdict
|
from collections import OrderedDict, defaultdict
|
||||||
from typing import TYPE_CHECKING, Final, NamedTuple, TextIO, TypedDict
|
from typing import TYPE_CHECKING, Final, NamedTuple, TextIO, TypedDict, cast
|
||||||
|
|
||||||
import yaml
|
import yaml
|
||||||
|
|
||||||
from . import LOGGER
|
|
||||||
from .mtypes import (
|
from .mtypes import (
|
||||||
Argument,
|
Argument,
|
||||||
Class,
|
Class,
|
||||||
@@ -25,6 +23,8 @@ from .mtypes import (
|
|||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from .register import MobaseRegister
|
from .register import MobaseRegister
|
||||||
|
|
||||||
|
LOGGER = logging.getLogger(__package__)
|
||||||
|
|
||||||
|
|
||||||
class Settings:
|
class Settings:
|
||||||
class YamlFunctionArgument(TypedDict, total=False):
|
class YamlFunctionArgument(TypedDict, total=False):
|
||||||
@@ -41,19 +41,21 @@ class Settings:
|
|||||||
abstract: bool
|
abstract: bool
|
||||||
deprecated: bool
|
deprecated: bool
|
||||||
|
|
||||||
args: dict[str, Settings.YamlFunctionArgument | str | None]
|
args: dict[str, Settings.YamlFunctionArgument | str | None] | None
|
||||||
returns: str | Settings.YamlFunctionReturn
|
returns: str | Settings.YamlFunctionReturn | None
|
||||||
|
|
||||||
raises: dict[str, str]
|
raises: dict[str, str | None] | None
|
||||||
|
|
||||||
class YamlClassProperty(TypedDict):
|
class YamlClassProperty(TypedDict):
|
||||||
type: str
|
type: str
|
||||||
desc: str
|
desc: str | None
|
||||||
|
|
||||||
|
# need to use a functional-styled TypeDict due to the invalid Python
|
||||||
|
# attribute names
|
||||||
YamlClassSettings = TypedDict(
|
YamlClassSettings = TypedDict(
|
||||||
"YamlClassSettings",
|
"YamlClassSettings",
|
||||||
{
|
{
|
||||||
"__doc__": str,
|
"__doc__": str | None,
|
||||||
"__bases__": list[str],
|
"__bases__": list[str],
|
||||||
"__abstract__": bool,
|
"__abstract__": bool,
|
||||||
"properties[]": dict[str, YamlClassProperty],
|
"properties[]": dict[str, YamlClassProperty],
|
||||||
@@ -63,7 +65,6 @@ class Settings:
|
|||||||
)
|
)
|
||||||
|
|
||||||
class PyFunctionSettings(NamedTuple):
|
class PyFunctionSettings(NamedTuple):
|
||||||
|
|
||||||
doc: str
|
doc: str
|
||||||
args: list[Argument] | None = None
|
args: list[Argument] | None = None
|
||||||
ret: Return | None = None
|
ret: Return | None = None
|
||||||
@@ -90,7 +91,6 @@ class Settings:
|
|||||||
fp: TextIO | None = None,
|
fp: TextIO | None = None,
|
||||||
module: str | None = None,
|
module: str | None = None,
|
||||||
):
|
):
|
||||||
|
|
||||||
self.register = register
|
self.register = register
|
||||||
|
|
||||||
if fp is None:
|
if fp is None:
|
||||||
@@ -129,8 +129,8 @@ class Settings:
|
|||||||
return base # type: ignore
|
return base # type: ignore
|
||||||
|
|
||||||
def _parse_function_settings(
|
def _parse_function_settings(
|
||||||
self, settings: str | YamlFunctionSettings
|
self, settings: str | YamlFunctionSettings | None
|
||||||
) -> "PyFunctionSettings":
|
) -> PyFunctionSettings:
|
||||||
"""
|
"""
|
||||||
Parse settings for a function or method.
|
Parse settings for a function or method.
|
||||||
|
|
||||||
@@ -159,7 +159,6 @@ class Settings:
|
|||||||
if "args" in settings:
|
if "args" in settings:
|
||||||
args = []
|
args = []
|
||||||
if settings["args"] is not None:
|
if settings["args"] is not None:
|
||||||
|
|
||||||
# For each argument, we either have a None value (name: ),
|
# For each argument, we either have a None value (name: ),
|
||||||
# or a string (name: Description) or a dictionary that can contain
|
# or a string (name: Description) or a dictionary that can contain
|
||||||
# __doc__ and type.
|
# __doc__ and type.
|
||||||
@@ -198,7 +197,6 @@ class Settings:
|
|||||||
|
|
||||||
def patch_functions(self, fns: list[Function]):
|
def patch_functions(self, fns: list[Function]):
|
||||||
for i, fn in enumerate(fns):
|
for i, fn in enumerate(fns):
|
||||||
|
|
||||||
# Find the name in settings:
|
# Find the name in settings:
|
||||||
if fn.has_overloads():
|
if fn.has_overloads():
|
||||||
setting_name = "{}.{}".format(fn.name, i + 1)
|
setting_name = "{}.{}".format(fn.name, i + 1)
|
||||||
@@ -229,7 +227,6 @@ class Settings:
|
|||||||
|
|
||||||
# Check the return type:
|
# Check the return type:
|
||||||
if function_settings.ret is not None:
|
if function_settings.ret is not None:
|
||||||
|
|
||||||
# Force the doc anyway:
|
# Force the doc anyway:
|
||||||
fn.ret.doc = function_settings.ret.doc
|
fn.ret.doc = function_settings.ret.doc
|
||||||
|
|
||||||
@@ -285,7 +282,9 @@ class Settings:
|
|||||||
PyClass(package=".".join(parts[:-1]), name=parts[-1])
|
PyClass(package=".".join(parts[:-1]), name=parts[-1])
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
cls.bases.append(self.register.get_object(bc))
|
class_ = self.register.get_object(bc)
|
||||||
|
assert isinstance(class_, Class)
|
||||||
|
cls.bases.append(class_)
|
||||||
del class_settings["__bases__"]
|
del class_settings["__bases__"]
|
||||||
|
|
||||||
if "__abstract__" in class_settings and class_settings["__abstract__"]:
|
if "__abstract__" in class_settings and class_settings["__abstract__"]:
|
||||||
@@ -295,7 +294,7 @@ class Settings:
|
|||||||
# Patch properties - Everything should be in config since property are poorly
|
# Patch properties - Everything should be in config since property are poorly
|
||||||
# documented by boost::python.
|
# documented by boost::python.
|
||||||
properties: dict[str, Settings.YamlClassProperty] = class_settings.pop(
|
properties: dict[str, Settings.YamlClassProperty] = class_settings.pop(
|
||||||
"properties[]", {}
|
"properties[]", cast(dict[str, Settings.YamlClassProperty], {})
|
||||||
)
|
)
|
||||||
for prop in cls.properties:
|
for prop in cls.properties:
|
||||||
if prop.name in properties:
|
if prop.name in properties:
|
||||||
@@ -313,7 +312,6 @@ class Settings:
|
|||||||
|
|
||||||
# If we have a description:
|
# If we have a description:
|
||||||
if "desc" in settings_property:
|
if "desc" in settings_property:
|
||||||
|
|
||||||
# If desc is None, we do not warn user, because the entry is in
|
# If desc is None, we do not warn user, because the entry is in
|
||||||
# settings, just empty:
|
# settings, just empty:
|
||||||
if settings_property["desc"] is not None:
|
if settings_property["desc"] is not None:
|
||||||
@@ -328,7 +326,7 @@ class Settings:
|
|||||||
|
|
||||||
# patch signals - Everything should be in config since signals are not really
|
# patch signals - Everything should be in config since signals are not really
|
||||||
# exposed by pybind11.
|
# exposed by pybind11.
|
||||||
signals: list[str] = list(class_settings.pop("signals[]", {}))
|
signals: list[str] = list(class_settings.pop("signals[]", cast(list[str], [])))
|
||||||
for signal in signals:
|
for signal in signals:
|
||||||
cls.constants.append(Constant(signal, PyType("pyqtSignal"), None))
|
cls.constants.append(Constant(signal, PyType("pyqtSignal"), None))
|
||||||
|
|
||||||
@@ -340,17 +338,15 @@ class Settings:
|
|||||||
for m in cls.methods:
|
for m in cls.methods:
|
||||||
methods[m.name].append(m)
|
methods[m.name].append(m)
|
||||||
|
|
||||||
for k, ms in methods.items():
|
for ms in methods.values():
|
||||||
|
missing_settings: set[str] = set()
|
||||||
for i, m in enumerate(ms):
|
for i, m in enumerate(ms):
|
||||||
|
|
||||||
# Find the name in settings:
|
# Find the name in settings:
|
||||||
if m.has_overloads():
|
if m.has_overloads():
|
||||||
settings_name = "{}.{}".format(m.name, i + 1)
|
settings_name = "{}.{}".format(m.name, i + 1)
|
||||||
else:
|
else:
|
||||||
settings_name = m.name
|
settings_name = m.name
|
||||||
|
|
||||||
missing_settings: set[str] = set()
|
|
||||||
|
|
||||||
# If the name is in the settings:
|
# If the name is in the settings:
|
||||||
if settings_name in class_settings:
|
if settings_name in class_settings:
|
||||||
keys[settings_name] = True
|
keys[settings_name] = True
|
||||||
@@ -401,7 +397,6 @@ class Settings:
|
|||||||
|
|
||||||
# Check the return type:
|
# Check the return type:
|
||||||
if function_settings.ret is not None:
|
if function_settings.ret is not None:
|
||||||
|
|
||||||
# Force the doc anyway:
|
# Force the doc anyway:
|
||||||
m.ret.doc = function_settings.ret.doc
|
m.ret.doc = function_settings.ret.doc
|
||||||
|
|
||||||
@@ -466,7 +461,7 @@ def clean_class(cls: Class):
|
|||||||
|
|
||||||
# Remove duplicate methods (based on name and argument types):
|
# Remove duplicate methods (based on name and argument types):
|
||||||
methods: dict[tuple[str, tuple[Argument, ...]], list[Method]] = OrderedDict()
|
methods: dict[tuple[str, tuple[Argument, ...]], list[Method]] = OrderedDict()
|
||||||
methods_by_name = defaultdict(list)
|
methods_by_name: dict[str, list[Method]] = defaultdict(list)
|
||||||
for m in cls.methods:
|
for m in cls.methods:
|
||||||
k = (m.name, tuple(m.args if m.is_static() else m.args[1:]))
|
k = (m.name, tuple(m.args if m.is_static() else m.args[1:]))
|
||||||
if k not in methods:
|
if k not in methods:
|
||||||
@@ -479,7 +474,6 @@ def clean_class(cls: Class):
|
|||||||
ms = methods[name, args]
|
ms = methods[name, args]
|
||||||
method: Method = ms[0]
|
method: Method = ms[0]
|
||||||
if len(ms) > 1:
|
if len(ms) > 1:
|
||||||
|
|
||||||
# If we have more than two methods, there is a problem...
|
# If we have more than two methods, there is a problem...
|
||||||
assert len(methods[name, args]) == 2
|
assert len(methods[name, args]) == 2
|
||||||
assert (
|
assert (
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user