A BAIN Wizard Interpreter based on wizparse that can
be used in various settings to run BAIN Wizard installers.
There are various way to use the interpreter.
The easiest way is to extends the WizardScriptRunner and add the missing
functionalities that are mod-manager or game specific.
You can then use WizardScriptRunner.run() to execute a script, and everything will
be called when required.
from pathlib import Path
from typing import List
from wizard.manager import SelectOption
from wizard.scriptrunner import WizardScriptRunner
from wizard.value import SubPackage, SubPackages
class MySubPackage(SubPackage):
"""
Implement your own SubPackage.
"""
_files: List[str]
def __init__(self, name: str, files: List[str]):
super().__init__(name)
self._files = files
@property
def files(self):
return iter(self._files)
class MyRunner(WizardScriptRunner):
"""
Extends the runner and implement the missing methods.
"""
# these are the methods you need to provide, see manager.ManagerModInterface
# and manager.ManagerUserInterface for the documentation of each method
#
# the WizardRunner class extends both interfaces and already implements many
# functions, but you can always override them
def selectOne(
self, description: str, options: List[SelectOption], default: SelectOption
) -> SelectOption:
...
def selectMany(
self,
description: str,
options: List[SelectOption],
default: List[SelectOption] = [],
) -> List[SelectOption]:
...
def compareGameVersion(self, version: str) -> int:
...
def compareSEVersion(self, version: str) -> int:
...
def compareGEVersion(self, version: str) -> int:
...
def compareWBVersion(self, version: str) -> int:
...
def dataFileExists(self, *filepaths: str) -> bool:
...
def getPluginLoadOrder(self, filename: str, fallback: int = -1) -> int:
...
def getPluginStatus(self, filename) -> int:
...
def getFilename(self, path: str) -> str:
...
def getFolder(self, path: str) -> str:
...
# create the sub-packages
subpackages = SubPackages([MySubPackage(...) for ...])
# create the runner
runner = MyRunner(subpackages)
# run a script - use a Path() object, otherwise the string will be interpreted
# as a script
status, result = runner.run(Path("wizard.txt"))
status # status of the execution
result.subpackages # list of selected sub-packages
result.plugins # list of enabled plugins
result.notes # list of notes
result.tweaks.disabled # list of disabled INI settings
result.tweaks.modified # list of new or modified INI settingsIf an error occurs during the script execution, the interpreter will call
the WizardScriptRunner.error() function with the Python exception. By default, this
method re-raise the error, you can change it:
def error(self, exc: Exception):
# handle the error
...If this method returns, result.status will be WizardScriptRunnerStatus.ERROR.
The WizardScriptRunner exposes a few extra features through methods that you can use
during the execution, e.g. in selectOne, selectMany, error, complete, etc.
runner = WizardRunner(...)
# abort the execution - Equivalent to a 'Cancel' keyword
runner.abort()
# retrieve the current context
context = runner.context()
# rewind to the given context
runner.rewind(context)The runner.abort and runner.rewind method rely on exception to work, so these do
not return.
The code under wizard/antlr4 is generated from wizard/antlr4/wizard.g4
from the wizparse repository.
To generate the file, you need antlr4, and you simply have to run:
# IMPORTANT: use FORWARD SLASH (/) everywhere, otherwise it does not work
java -jar antlr-4.13.1-complete.jar -visitor -Dlanguage=Python3 -o ./src/wizard/antlr4 ./vendor/wizparse/wizards/wizard.g4To run the tests, you need the Python 3 ANTLR4 runtime and pytest:
pip install antlr4-python3-runtime pytestYou can then run the tests using pytest.
Unless otherwise specified, the code in this repository is licensed under the MIT license. See LICENSE for the full text.
Exceptions:
- The code in
wizard/antlr4is generated from thewizparserepository, so thewizparseLICENSE applies to it. - The code in
vendor/wizparseis under thewizparseLICENSE. - The files in
vendor/wizparse/testshave their own accompanying license. See thewizparserepository for more details.