37 Commits
Author SHA1 Message Date
Oliver Hamlet cab63886d3 Set version number to 4.0.1 2019-01-27 14:53:14 +00:00
Oliver Hamlet 8a61701855 Update libloot to v0.14.3 2019-01-27 14:52:03 +00:00
Oliver Hamlet 8c75e83374 Update a few references to MSVC 2015 redist to be 2017 2019-01-27 14:50:34 +00:00
Oliver Hamlet 5450709ebe Update docs 2019-01-12 17:16:43 +00:00
Oliver Hamlet 3a9ff95de2 Update wrapper version to 4.0.0 2019-01-12 17:14:12 +00:00
Oliver Hamlet 1298fce6fd Update libloot to v0.14.1 2019-01-12 15:55:22 +00:00
Oliver Hamlet 21242f359d Update readme 2018-12-13 17:46:21 +00:00
Oliver Hamlet 6579eb5178 Build for Python 2.7 and 3.7 on AppVeyor 2018-12-13 17:20:57 +00:00
Oliver Hamlet 61a74b6984 Build 32-bit and 64-bit binaries on AppVeyor 2018-12-13 08:08:58 +00:00
Oliver Hamlet 66f84d4848 Support 64-bit builds 2018-12-13 08:05:01 +00:00
Oliver Hamlet 5f5c0e3949 Update pybind11 to fix AppVeyor build
Utumno experienced issues with Python modules built with more recent
versions of pybind11, which is why I tried to avoid this, but it looks
like it's necessary.
2018-12-12 19:59:14 +00:00
Oliver Hamlet ab926c8755 Use masterlist with fixed syntax
The older masterlist had parentheses between not and a function, which
has never been valid, but which only caused an error starting with
v0.14.0.
2018-12-12 19:57:34 +00:00
Oliver Hamlet 35475b292f Update to libloot v0.14.0
libloot is the renamed LOOT API. This adds a requirement on C++17,
and so MSVC 2017 on Windows.

pybind11 doesn't provide handling for std::filesystem::path, so wrapper
functions are used to perform the necessary one-way conversion without
having to expose the complexity on the Python side.
2018-12-12 19:33:21 +00:00
Oliver Hamlet 51e2e4e4fa Remove Travis badge
Travis hasn't been used for a while now.
2018-11-07 17:26:39 +00:00
Oliver Hamlet c17437a579 Fix AppVeyor CI link
Also update a GitHub URL, replacing WrinklyNinja with Ortham.
2018-11-07 16:58:07 +00:00
Oliver Hamlet 49204621c5 Fix typo in bintray delete script call 2018-08-12 22:26:55 +01:00
Oliver Hamlet 3098ffa692 Update Bintray delete script to fix deleting old builds 2018-08-12 21:47:54 +01:00
Oliver Hamlet 392a090823 Re-encrypt Bintray and GitHub auth tokens
Using the values encrypted by AppVeyor when I'm logged in as myself for
the LOOT account.
2018-08-12 21:47:02 +01:00
Oliver Hamlet e98b43a4b1 Remove old builds from LOOT's Bintray org 2018-08-08 21:39:24 +01:00
Oliver Hamlet a957ece62b Upload artifacts to repo in LOOT's Bintray org 2018-08-06 21:07:20 +01:00
Oliver Hamlet f97de90e02 Update wrapper version to 3.1.1 2018-05-12 21:50:30 +01:00
Oliver Hamlet d00c59b7b2 Update LOOT API to v0.13.2 2018-05-12 21:15:17 +01:00
Oliver Hamlet e06227f437 Build with debug info and package PDB 2018-05-12 19:26:21 +01:00
Oliver Hamlet bcc536d4b0 Downgrade to pybind11 v2.1.1
Updating to v2.2.1 introduced a runtime issue that's
environment-specific but it's not clear what the issue is, so
just downgrade for now.
2018-05-12 19:12:47 +01:00
Oliver Hamlet a564f230be Update wrapper version to 3.1.0
Although the LOOT API update includes breaking changes, none of them are
exposed by the Python wrapper, so this is just a minor update.
2018-04-15 13:16:49 +01:00
Oliver Hamlet 27c8f58494 Update pybind11 to v2.2.2 2018-04-15 13:16:49 +01:00
Oliver Hamlet 179125f006 Expose GameType::tes5vr and GameType::fo4vr 2018-04-15 13:16:49 +01:00
Oliver Hamlet 671ca81beb Update to LOOT API v0.13.1 2018-04-15 13:16:49 +01:00
Oliver Hamlet 7faa360790 Update outdated usage example 2017-12-30 15:29:21 +00:00
Oliver Hamlet 0c9d014174 Remove default value for create_game_handle's game_path argument
The LOOT API incorrectly allows it, it causes a runtime exception.
2017-12-30 15:29:03 +00:00
Oliver Hamlet a8e2b11280 Allow initialise_locale() to be called with no args
Use a blank string as the default argument, as it's the most commonly desired value.
2017-12-30 15:27:48 +00:00
Oliver Hamlet 1275a11be7 Expose load_current_load_order_state() via GameInterface 2017-11-04 17:27:15 +00:00
Oliver Hamlet 5357858069 Update documentation 2017-11-04 13:52:19 +00:00
Oliver Hamlet 04088ac8f4 Update wrapper version to 3.0.0 2017-11-04 12:29:27 +00:00
Oliver Hamlet 7098671ad5 Update to LOOT API v0.12.0
Significant changes include:

- The logging interface has changed, a callback can now be set
  instead of an output file and verbosity, giving clients more
  control.
- DatabaseInterface::EvalLists() has been removed.
- SimpleMessage now has a condition field.
2017-11-04 12:14:26 +00:00
Oliver Hamlet 212f899396 Update to pybind11 v2.2.1 2017-10-17 19:57:42 +01:00
Oliver Hamlet 1e0dbe8dc2 Update to LOOT API v0.11.1 and fix Linux builds 2017-10-17 20:34:45 +01:00
12 changed files with 288 additions and 166 deletions
+43 -21
View File
@@ -6,6 +6,10 @@ include(ExternalProject)
set(EXTERNAL_PROJECTS_PATH "${CMAKE_BINARY_DIR}/external/src")
make_directory(${EXTERNAL_PROJECTS_PATH})
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
##############################
# Get Build Revision
##############################
@@ -30,9 +34,10 @@ configure_file("${CMAKE_SOURCE_DIR}/src/wrapper_version.cpp.in" "${CMAKE_BINARY_
# pybind11
#######################################
set(PYBIND11_URL "https://github.com/pybind/pybind11/archive/v2.1.1.tar.gz")
set(PYBIND11_DOWNLOAD_PATH "${EXTERNAL_PROJECTS_PATH}/pybind11-2.1.1.tar.gz")
set(PYBIND11_EXTRACTED_PATH "${EXTERNAL_PROJECTS_PATH}/pybind11-2.1.1")
set(PYBIND11_VERSION "2.2.4")
set(PYBIND11_URL "https://github.com/pybind/pybind11/archive/v${PYBIND11_VERSION}.tar.gz")
set(PYBIND11_DOWNLOAD_PATH "${EXTERNAL_PROJECTS_PATH}/pybind11-${PYBIND11_VERSION}.tar.gz")
set(PYBIND11_EXTRACTED_PATH "${EXTERNAL_PROJECTS_PATH}/pybind11-${PYBIND11_VERSION}")
if (NOT EXISTS ${PYBIND11_DOWNLOAD_PATH})
file(DOWNLOAD ${PYBIND11_URL} ${PYBIND11_DOWNLOAD_PATH})
@@ -48,21 +53,30 @@ add_subdirectory(${PYBIND11_EXTRACTED_PATH})
# LOOT API
#######################################
if (CMAKE_SYSTEM_NAME MATCHES "Windows")
if (NOT "${CMAKE_GENERATOR}" MATCHES "(Win64|IA64)")
set(LIBLOOT_URL "https://github.com/loot/libloot/releases/download/0.14.3/libloot-0.14.3-0-g56d8f78_dev-win32.7z")
else()
set(LIBLOOT_URL "https://github.com/loot/libloot/releases/download/0.14.3/libloot-0.14.3-0-g56d8f78_dev-win64.7z")
endif()
else()
set(LIBLOOT_URL "https://github.com/loot/libloot/releases/download/0.14.3/libloot.tar.xz")
endif()
ExternalProject_Add(loot-api-c++
ExternalProject_Add(libloot
PREFIX "external"
URL "https://github.com/loot/loot-api/releases/download/0.11.0/loot_api-0.11.0-0-g8864f78_dev-win32.7z"
URL ${LIBLOOT_URL}
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
INSTALL_COMMAND "")
ExternalProject_Get_Property(loot-api-c++ SOURCE_DIR)
set(LOOT_API_EXTRACTED_PATH ${SOURCE_DIR})
ExternalProject_Get_Property(libloot SOURCE_DIR)
set(LIBLOOT_EXTRACTED_PATH ${SOURCE_DIR})
include_directories("${CMAKE_SOURCE_DIR}/src"
"${LOOT_API_EXTRACTED_PATH}/include")
link_directories(${LOOT_API_EXTRACTED_PATH})
set(LOOT_API_STATIC_LIBRARY "${CMAKE_STATIC_LIBRARY_PREFIX}loot_api${CMAKE_STATIC_LIBRARY_SUFFIX}")
set(LOOT_API_SHARED_LIBRARY "${CMAKE_SHARED_LIBRARY_PREFIX}loot_api${CMAKE_SHARED_LIBRARY_SUFFIX}")
"${LIBLOOT_EXTRACTED_PATH}/include")
link_directories(${LIBLOOT_EXTRACTED_PATH})
set(LIBLOOT_STATIC_LIBRARY "${CMAKE_STATIC_LIBRARY_PREFIX}loot${CMAKE_STATIC_LIBRARY_SUFFIX}")
set(LIBLOOT_SHARED_LIBRARY "${CMAKE_SHARED_LIBRARY_PREFIX}loot${CMAKE_SHARED_LIBRARY_SUFFIX}")
#######################################
# Test Masterlist
@@ -70,7 +84,7 @@ set(LOOT_API_SHARED_LIBRARY "${CMAKE_SHARED_LIBRARY_PREFIX}loot_api${CMAKE_SHARE
ExternalProject_Add(test-masterlist
PREFIX "external"
URL "https://github.com/loot/oblivion/archive/09286601739c11a3a3e4552c6ddbdcaeffd1a8d3.zip"
URL "https://github.com/loot/oblivion/archive/7f125ae4464224ff785111c7667c2cff85c896ec.zip"
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
INSTALL_COMMAND "")
@@ -83,12 +97,12 @@ pybind11_add_module(loot_api "${CMAKE_SOURCE_DIR}/src/main.cpp"
"${CMAKE_SOURCE_DIR}/src/convenience.cpp"
"${CMAKE_BINARY_DIR}/generated/wrapper_version.cpp")
add_dependencies(loot_api loot-api-c++ test-masterlist)
add_dependencies(loot_api libloot test-masterlist)
if (CMAKE_SYSTEM_NAME MATCHES "Windows")
target_link_libraries(loot_api PRIVATE ${LOOT_API_STATIC_LIBRARY})
target_link_libraries(loot_api PRIVATE ${LIBLOOT_STATIC_LIBRARY})
else()
target_link_libraries(loot_api PRIVATE ${LOOT_API_SHARED_LIBRARY})
target_link_libraries(loot_api PRIVATE ${LIBLOOT_SHARED_LIBRARY})
endif()
########################################
@@ -100,8 +114,8 @@ find_package(PythonInterp REQUIRED)
# Copy the API binary to the build directory.
add_custom_command(TARGET loot_api POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
"${LOOT_API_EXTRACTED_PATH}/${LOOT_API_SHARED_LIBRARY}"
"$<TARGET_FILE_DIR:loot_api>/${LOOT_API_SHARED_LIBRARY}")
"${LIBLOOT_EXTRACTED_PATH}/${LIBLOOT_SHARED_LIBRARY}"
"$<TARGET_FILE_DIR:loot_api>/${LIBLOOT_SHARED_LIBRARY}")
# Copy the test masterlist to the build directory.
ExternalProject_Get_Property(test-masterlist SOURCE_DIR)
@@ -122,12 +136,20 @@ add_custom_command(TARGET loot_api POST_BUILD
install(TARGETS loot_api
DESTINATION "."
CONFIGURATIONS Release)
CONFIGURATIONS Release RelWithDebInfo)
install(FILES "${LOOT_API_EXTRACTED_PATH}/${LOOT_API_SHARED_LIBRARY}"
install(FILES "${LIBLOOT_EXTRACTED_PATH}/${LIBLOOT_SHARED_LIBRARY}"
"${CMAKE_SOURCE_DIR}/docs/README.md"
DESTINATION "."
CONFIGURATIONS Release)
CONFIGURATIONS Release RelWithDebInfo)
IF (MSVC)
install(FILES $<TARGET_PDB_FILE:loot_api>
DESTINATION .
OPTIONAL
CONFIGURATIONS RelWithDebInfo
RENAME loot_api_python.pdb)
ENDIF ()
########################################
# CPack
@@ -157,7 +179,7 @@ else()
set(CPACK_GENERATOR "TXZ")
endif()
set(CPACK_PACKAGE_VERSION ${GIT_DESCRIBE_STRING})
set(CPACK_PACKAGE_VERSION "${GIT_DESCRIBE_STRING}-python$ENV{PYTHON_VERSION}")
set(CPACK_PACKAGE_DIRECTORY "${CMAKE_BINARY_DIR}/package")
include(CPack)
+6 -7
View File
@@ -1,21 +1,20 @@
LOOT API Python Module
=======================
[![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/github/loot/loot-api-python?branch=master&svg=true)](https://ci.appveyor.com/project/WrinklyNinja/loot-api-python)
[![Travis Build Status](https://travis-ci.org/loot/loot-api-python.svg?branch=master)](https://travis-ci.org/loot/loot-api-python)
[![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/k2ugge3po7254o1o/branch/master?svg=true)](https://ci.appveyor.com/project/LOOT/loot-api-python/branch/master)
[![Documentation Status](https://readthedocs.org/projects/loot-api-python/badge/)](http://loot-api-python.readthedocs.io/)
A Python module that wraps the LOOT API, generated by [pybind11](https://github.com/pybind/pybind11). Not everything in the API is exposed: coverage can be extended on request (or by pull request).
A Python module that wraps libloot, generated by [pybind11](https://github.com/pybind/pybind11). Not everything in the API is exposed: coverage can be extended on request (or by pull request).
## Downloads
Snapshot builds are available on [Bintray](https://bintray.com/wrinklyninja/loot/loot-api-python). The snapshot build archives are named like so:
Snapshot builds are available on [Bintray](https://bintray.com/loot/snapshots/loot-api-python). The snapshot build archives are named like so:
```
loot_api_python-<short revision ID>-win32.7z
loot_api_python-<short revision ID>-python<python version>-win<architecture>.7z
```
For example `loot_api_python-94de368-win32.7z` was built using the revision with shortened commit ID `94de368`.
For example `loot_api_python-94de368-python2.7-win32.7z` was built using the revision with shortened commit ID `94de368`.
## Documentation
@@ -23,6 +22,6 @@ The documentation can be found online at [Read The Docs](http://loot-api-python.
## Build Instructions
The module's build system uses [CMake](https://cmake.org/) and requires [Python](https://www.python.org) (tested with 2.7). Make sure they're installed, then run CMake, and build the generated solution file.
The module's build system uses [CMake](https://cmake.org/) and requires [Python](https://www.python.org). Make sure they're installed, then run CMake, and build the generated solution file.
Only Windows support has been tested, though Linux builds should also be possible.
+32 -15
View File
@@ -1,48 +1,65 @@
os: Visual Studio 2015
os: Visual Studio 2017
version: "{build}-{branch}"
configuration: Release
configuration: RelWithDebInfo
platform:
- Win32
- x64
environment:
bintray_auth_token:
secure: fBQJmUDK/EgEUWjjbo6bWcitczeFTJZT4OZ3ZZ4FoUT6soBsTWPQJnr8YEVMFhGP
secure: PgsEA6TjHVf718zMnK7J/fT1hUAVNKBeWhpYgYaeCyeZk37VT4Ics6j7+B7ElLEr
github_auth_token:
secure: yDqT5l/e5MntbW99V6+MHlfFgNv+UIogFfeyUVqtFk5lFRB/dAraLLwKCLl6y+DH
matrix:
- PYTHON_VERSION: 2.7
- PYTHON_VERSION: 3.7
install:
- ps: (New-Object Net.WebClient).DownloadFile('https://raw.githubusercontent.com/WrinklyNinja/ci-scripts/1.1.0/delete_old_bintray_versions.py', "$env:APPVEYOR_BUILD_FOLDER\delete_old_bintray_versions.py")
- ps: (New-Object Net.WebClient).DownloadFile('https://raw.githubusercontent.com/Ortham/ci-scripts/2.0.0/delete_old_bintray_versions.py', "$env:APPVEYOR_BUILD_FOLDER\delete_old_bintray_versions.py")
before_build:
- ps: $env:PYTHON_DIRECTORY_VERSION=$env:PYTHON_VERSION.Replace(".", "")
- cd %APPVEYOR_BUILD_FOLDER%
- ps: mkdir build
- cd build
- cmake .. -G "Visual Studio 14 2015"
- ps: |
if ($env:PLATFORM -eq 'Win32') {
cmake .. -G "Visual Studio 15 2017" -DPYTHON_EXECUTABLE="C:\Python${env:PYTHON_DIRECTORY_VERSION}\python.exe"
} else {
cmake .. -G "Visual Studio 15 2017 Win64" -DPYTHON_EXECUTABLE="C:\Python${env:PYTHON_DIRECTORY_VERSION}-x64\python.exe"
}
build:
verbosity: minimal
project: 'c:\projects\loot-api-python\build\loot_api_python.sln'
test_script:
- cd %APPVEYOR_BUILD_FOLDER%\build\Release
- python -m unittest test
- cd %APPVEYOR_BUILD_FOLDER%\build\%CONFIGURATION%
- ps: $env:ARCHITECTURE=$env:PLATFORM.Substring($env:PLATFORM.Length - 2)
- py -%PYTHON_VERSION%-%ARCHITECTURE% -m unittest test
after_test:
- cd %APPVEYOR_BUILD_FOLDER%\build
- cpack
- cpack -C %CONFIGURATION%
# AppVeyor checks out a specific commit, but that means the archive script
# can't tell which branch it's on, so rename the 7z archives.
- ps: $env:GIT_DESCRIBE = ((git describe --tags --long --always) | Out-String) -replace "`n|`r", ""
artifacts:
- path: build\package\loot_api_python-$(GIT_DESCRIBE)_$(APPVEYOR_REPO_BRANCH)-win32.7z
- path: build\package\loot_api_python-$(GIT_DESCRIBE)_$(APPVEYOR_REPO_BRANCH)-python$(PYTHON_VERSION)-win$(ARCHITECTURE).7z
name: loot_api_python
deploy:
- provider: BinTray
username: wrinklyninja
api_key:
secure: fBQJmUDK/EgEUWjjbo6bWcitczeFTJZT4OZ3ZZ4FoUT6soBsTWPQJnr8YEVMFhGP
subject: wrinklyninja
repo: loot
secure: PgsEA6TjHVf718zMnK7J/fT1hUAVNKBeWhpYgYaeCyeZk37VT4Ics6j7+B7ElLEr
subject: loot
repo: snapshots
package: loot-api-python
version: $(GIT_DESCRIBE)_$(APPVEYOR_REPO_BRANCH)
publish: true
@@ -52,13 +69,13 @@ deploy:
tag: $(APPVEYOR_REPO_TAG_NAME)
release: LOOT API Python Module v$(APPVEYOR_REPO_TAG_NAME)
description: |
Requires Windows 7 or later and the [MSVC 2015 x86 redistributable](https://download.microsoft.com/download/6/A/A/6AA4EDFF-645B-48C5-81CC-ED5963AEAD48/vc_redist.x86.exe), and [7-Zip](http://www.7-zip.org/) to extract the archive.
Requires Windows 7 or later and the [MSVC 2017 x86 redistributable](https://download.visualstudio.microsoft.com/download/pr/749aa419-f9e4-4578-a417-a43786af205e/d59197078cc425377be301faba7dd87a/vc_redist.x86.exe), and [7-Zip](http://www.7-zip.org/) to extract the archive.
auth_token:
secure: V1GojGQfrAiQtUWtNNXfm3samiH+1yNF5UYhkn8B8mbif20IGTGWNlBS9E4S0SUC
secure: yDqT5l/e5MntbW99V6+MHlfFgNv+UIogFfeyUVqtFk5lFRB/dAraLLwKCLl6y+DH
artifact: loot_api_python
draft: false
on:
appveyor_repo_tag: true
on_success:
- ps: python "$env:APPVEYOR_BUILD_FOLDER\delete_old_bintray_versions.py" -o loot -g loot-api-python -u wrinklyninja -b loot -p loot-api-python -t $env:bintray_auth_token -n 30
- ps: python "$env:APPVEYOR_BUILD_FOLDER\delete_old_bintray_versions.py" -g loot/loot-api-python -b loot/snapshots/loot-api-python -u wrinklyninja -k $env:bintray_auth_token -t $env:github_auth_token -n 30
+1 -1
View File
@@ -3,7 +3,7 @@ LOOT API Python Wrapper
This archive contains a build of the LOOT API Python wrapper module and its corresponding 32-bit Windows build of the LOOT API.
The DLL requires the [MSVC 2015 x86 redistributable](https://download.microsoft.com/download/9/3/F/93FCF1E7-E6A4-478B-96E7-D4B285925B00/vc_redist.x86.exe)
The DLL requires the [MSVC 2017 x86 redistributable](https://download.visualstudio.microsoft.com/download/pr/749aa419-f9e4-4578-a417-a43786af205e/d59197078cc425377be301faba7dd87a/vc_redist.x86.exe)
to be installed.
See the [online documentation](http://loot-api-python.readthedocs.org/) for more information.
+2 -2
View File
@@ -55,7 +55,7 @@ master_doc = 'index'
# General information about the project.
project = u'LOOT API Python Module'
copyright = u'2016, WrinklyNinja'
copyright = u'2019, WrinklyNinja'
author = u'WrinklyNinja'
# The version info for the project you're documenting, acts as replacement for
@@ -346,5 +346,5 @@ texinfo_documents = [
# Example configuration for intersphinx: refer to the Python standard library.
intersphinx_mapping = {
'loot_api': ('http://loot.readthedocs.io/en/0.10.2/', None),
'loot_api': ('http://loot.readthedocs.io/en/0.14.3/', None),
}
+72 -37
View File
@@ -14,8 +14,7 @@ values are unsigned integer constants.
.. py:class:: loot_api.GameType
Wraps :cpp:type:`loot::GameType` to expose the LOOT API's game
codes.
Wraps :cpp:type:`loot::GameType` to expose the LOOT API's game codes.
.. py:attribute:: fo3
.. py:attribute:: fo4
@@ -24,27 +23,21 @@ values are unsigned integer constants.
.. py:attribute:: tes5
.. py:attribute:: tes5se
.. py:class:: loot_api.LanguageCode
.. py:class:: loot_api.LogLevel
Wraps :cpp:type:`loot::LanguageCode` to expose the LOOT API's
language codes.
Wraps :cpp:type:`loot::LogLevel` to expose the LOOT API's log level codes.
.. py:attribute:: english
.. py:attribute:: spanish
.. py:attribute:: russian
.. py:attribute:: french
.. py:attribute:: chinese
.. py:attribute:: polish
.. py:attribute:: brazilian_portuguese
.. py:attribute:: finnish
.. py:attribute:: german
.. py:attribute:: danish
.. py:attribute:: korean
.. py:attribute:: trace
.. py:attribute:: debug
.. py:attribute:: info
.. py:attribute:: warning
.. py:attribute:: error
.. py:attribute:: fatal
.. py:class:: loot_api.MessageType
Wraps :cpp:type:`loot::MessageType` to expose the LOOT API's
message type codes.
Wraps :cpp:type:`loot::MessageType` to expose the LOOT API's message type
codes.
.. py:attribute:: error
.. py:attribute:: say
@@ -52,13 +45,26 @@ values are unsigned integer constants.
.. py:class:: loot_api.PluginCleanliness
Wraps :cpp:type:`loot::PluginCleanliness` to expose the LOOT API's plugin cleanliness state codes.
Codes used to indicate the cleanliness of a plugin according to the
information contained within the loaded masterlist/userlist.
.. py:attribute:: clean
Indicates that the plugin is clean.
.. py:attribute:: dirty
Indicates that the plugin is dirty.
.. py:attribute:: do_not_clean
Indicates that the plugin contains dirty edits, but that they are part of
the plugin’s intended functionality and should not be removed.
.. py:attribute:: unknown
Indicates that no data is available on whether the plugin is dirty or not.
Public-Field Data Structures
============================
@@ -81,7 +87,7 @@ Classes with public fields and no member functions.
A boolean that is true if the masterlist has been modified from its state
at the commit given by :py:attr:`revision_id`.
.. py:class:: loot_api.Message
.. py:class:: loot_api.SimpleMessage
Wraps :cpp:class:`loot::SimpleMessage`.
@@ -91,12 +97,16 @@ Classes with public fields and no member functions.
.. py:attribute:: language
A :py:class:`loot_api.LanguageCode` giving the message text language.
A Unicode string giving the message text language.
.. py:attribute:: text
A Unicode string containing the message text.
.. py:attribute:: condition
A Unicode string containing the message condition.
.. py:class:: loot_api.PluginTags
Wraps :cpp:class:`loot::PluginTags`.
@@ -117,49 +127,65 @@ Classes with public fields and no member functions.
Functions
=========
.. py:function:: loot_api.set_logging_callback(callback) -> NoneType
Set the callback function that is called when logging. Wraps
:cpp:func:`loot::SetLoggingCallback`.
.. py:function:: loot_api.is_compatible(int, int, int) -> bool
Checks for API compatibility. Wraps :cpp:func:`loot::IsCompatible`.
.. py:function:: loot_api.create_database(game : loot_api.GameType, [game_path : unicode = u'', [game_local_path : unicode = u'']]) -> loot_api.DatabaseInterface
.. py:function:: loot_api.InitialiseLocale(unicode = u'') -> NoneType
Initialise a new database handle. Wraps :cpp:func:`loot::IsCompatible`.
Initialise the current global locale using the given ID. A blank value means
that the system default locale will be initialised. Wraps
:cpp:func:`loot::InitialiseLocale`.
.. py:function:: loot_api.create_game_handle(game : loot_api.GameType, game_path : unicode, [game_local_path : unicode = u'']) -> loot_api.GameInterface
Initialise a new game handle. Wraps :cpp:func:`loot::CreateGameHandle`.
Classes
=======
.. py:class:: loot_api.GameInterface
Wraps :cpp:class:`loot::GameInterface`.
.. py:function:: loot_api.get_database() -> loot_api.DatabaseInterface
Get a database handle. Wraps :cpp:func:`loot::GetDatabase`.
.. py:function:: loot_api.load_current_load_order_state() -> NoneType
Load the current load order state, discarding any previously held state.
Wraps :cpp:func:`loot::LoadCurrentLoadOrderState`.
.. py:class:: loot_api.DatabaseInterface
Wraps :cpp:class:`loot::DatabaseInterface`.
.. py:method:: eval_lists(loot_api.DatabaseInterface) -> NoneType
Evaluates all conditions and regular expression metadata entries in the loaded metadata lists. Wraps :cpp:func:`EvalLists`.
.. py:method:: get_masterlist_revision(loot_api.DatabaseInterface, unicode, bool) -> loot_api.MasterlistInfo
Gets the give masterlist’s source control revision. Wraps :cpp:func:`GetMasterlistRevision`.
.. py:method:: get_plugin_cleanliness(loot_api.DatabaseInterface, unicode) -> loot_api.PluginCleanliness
.. py:method:: get_plugin_metadata(loot_api.DatabaseInterface, plugin : unicode, [includeUserMetadata : bool = True, [evaluateConditions : bool = False]]) -> loot_api.PluginMetadata
Determines the database’s knowledge of a plugin’s cleanliness. Wraps :cpp:func:`GetPluginCleanliness`.
Get all a plugin’s loaded metadata. Wraps :cpp:func:`GetPluginMetadata`.
.. py:method:: get_plugin_messages(loot_api.DatabaseInterface, unicode, loot_api.LanguageCode) -> list<loot_api.Message>
.. py:method:: get_plugin_cleanliness(loot_api.DatabaseInterface, plugin : unicode, [evaluateConditions : bool = False]) -> loot_api.PluginCleanliness
Outputs the messages associated with the given plugin in the database. Wraps :cpp:func:`GetPluginMessages`.
Determines the database’s knowledge of a plugin’s cleanliness. Outputs whether the plugin should be cleaned or not, or if no data is available.
.. py:method:: get_plugin_tags(loot_api.DatabaseInterface, unicode) -> loot_api.PluginTags
.. py:method:: get_plugin_tags(loot_api.DatabaseInterface, plugin : unicode, [evaluateConditions : bool = False]) -> loot_api.PluginTags
Outputs the Bash Tags suggested for addition and removal by the database for the given plugin. Wraps :cpp:func:`GetPluginTags`.
Outputs the Bash Tags suggested for addition and removal by the database for the given plugin.
.. py:method:: load_lists(loot_api.DatabaseInterface, masterlist_path : unicode, [userlist_path : unicode = u'']) -> NoneType
Loads the masterlist and userlist from the paths specified. Wraps :cpp:func:`LoadLists`.
.. py:method:: sort_plugins(loot_api.DatabaseInterface, list<unicode>) -> list<unicode>
Calculates a new load order for all a game’s installed plugins and outputs the sorted order. Wraps :cpp:func:`SortPlugins`.
.. py:method:: update_masterlist(loot_api.DatabaseInterface, unicode, unicode, unicode) -> bool
Updates the given masterlist using the given Git repository details. Wraps :cpp:func:`UpdateMasterlist`.
@@ -216,3 +242,12 @@ Classes
.. py:staticmethod:: string() -> unicode
Returns the API version as a string of the form ``major.minor.patch``
.. py:class:: loot_api.PluginMetadata
Wraps :cpp:class:`loot::PluginMetadata`.
.. py:method:: get_simple_messages(loot_api.PluginMetadata, unicode) -> list<loot_api.SimpleMessage>
Get the plugin’s messages as SimpleMessage objects for the given language.
Wraps :cpp:func:`GetPluginMessages`.
+6 -5
View File
@@ -10,13 +10,13 @@ Build archives contain two binaries:
* ``loot_api.pyd`` is the Python wrapper
* ``loot_api.dll`` is the C++ API DLL that the Python wrapper was built against.
The C++ DLL requires the `Visual C++ 2015 Redistributable (x86)`_
The C++ DLL requires the `Visual C++ 2017 Redistributable (x86)`_
to be installed.
To use the wrapper, copy both files to wherever you want to import them from
(they must be in the same folder), and you're done!
.. _Visual C++ 2015 Redistributable (x86): https://download.microsoft.com/download/9/3/F/93FCF1E7-E6A4-478B-96E7-D4B285925B00/vc_redist.x86.exe
.. _Visual C++ 2017 Redistributable (x86): https://download.visualstudio.microsoft.com/download/pr/749aa419-f9e4-4578-a417-a43786af205e/d59197078cc425377be301faba7dd87a/vc_redist.x86.exe
Using the wrapper
=================
@@ -28,7 +28,7 @@ To check if the module loaded is compatible with the version of the API that you
developed against::
>>> import loot_api
>>> loot_api.is_compatible(0,10,0)
>>> loot_api.is_compatible(0,14,0)
True
>>> loot_api.is_compatible(0,9,0)
False
@@ -39,8 +39,9 @@ Getting a Plugin's Bash Tag Suggestions
To get a plugin's Bash Tag suggestions from a ``masterlist.yaml`` metadata file::
>>> import loot_api
>>> db = loot_api.create_database(loot_api.GameType.tes4, '', '')
>>> db.load_lists('masterlist.yaml', '')
>>> loot_api.initialise_locale()
>>> db = loot_api.create_game_handle(loot_api.GameType.tes4, 'C:\\path\\to\\oblivion\\directory')
>>> db.load_lists('masterlist.yaml')
>>> tags = db.get_plugin_tags(u'Unofficial Oblivion Patch.esp')
>>> tags.added
set([u'Scripts', u'Relations', u'C.Owner', u'Actors.AIPackages', u'Actors.Stats', u'Actors.ACBS', u'C.Music', u'Factions', u'Invent', u'Relev', u'Names', u'C.Light', u'Delev', u'C.Name', u'C.Climate', u'NPC.Class', u'Stats', u'Actors.DeathItem', u'Creatures.Blood', u'Actors.CombatStyle', u'Actors.AIData'])
+34 -31
View File
@@ -27,50 +27,53 @@ along with LOOT. If not, see
#include <loot/api.h>
namespace loot {
std::shared_ptr<DatabaseInterface> CreateDatabase(const GameType game, const std::string & game_path, const std::string & game_local_path) {
auto gameHandle = CreateGameHandle(game, game_path, game_local_path);
return gameHandle->GetDatabase();
}
PluginTags GetPluginTags(const std::shared_ptr<DatabaseInterface> db, const std::string& plugin) {
PluginTags GetPluginTags(const std::shared_ptr<DatabaseInterface> db, const std::string& plugin, bool evaluateConditions) {
PluginTags tags;
auto metadata = db->GetPluginMetadata(plugin, false, false);
for (const auto &tag : metadata.GetTags()) {
if (tag.IsAddition())
tags.added.insert(tag.GetName());
else
tags.removed.insert(tag.GetName());
auto metadata = db->GetPluginMetadata(plugin, false, evaluateConditions);
if (metadata.has_value()) {
for (const auto &tag : metadata.value().GetTags()) {
if (tag.IsAddition())
tags.added.insert(tag.GetName());
else
tags.removed.insert(tag.GetName());
}
}
metadata = db->GetPluginUserMetadata(plugin, false);
tags.userlist_modified = !metadata.GetTags().empty();
for (const auto &tag : metadata.GetTags()) {
if (tag.IsAddition())
tags.added.insert(tag.GetName());
else
tags.removed.insert(tag.GetName());
metadata = db->GetPluginUserMetadata(plugin, evaluateConditions);
if (metadata.has_value()) {
tags.userlist_modified = !metadata.value().GetTags().empty();
for (const auto &tag : metadata.value().GetTags()) {
if (tag.IsAddition())
tags.added.insert(tag.GetName());
else
tags.removed.insert(tag.GetName());
}
}
return tags;
}
PluginCleanliness GetPluginCleanliness(const std::shared_ptr<DatabaseInterface> db, const std::string& plugin) {
auto metadata = db->GetPluginMetadata(plugin, true, false);
PluginCleanliness GetPluginCleanliness(const std::shared_ptr<DatabaseInterface> db, const std::string& plugin, bool evaluateConditions) {
auto metadata = db->GetPluginMetadata(plugin, true, evaluateConditions);
if (metadata.GetDirtyInfo().empty()) {
if (metadata.GetCleanInfo().empty()) {
if (metadata.has_value()) {
if (metadata.value().GetDirtyInfo().empty()) {
if (metadata.value().GetCleanInfo().empty()) {
return PluginCleanliness::unknown;
}
else {
return PluginCleanliness::clean;
}
}
else if (!metadata.value().GetCleanInfo().empty()) {
return PluginCleanliness::unknown;
} else {
return PluginCleanliness::clean;
}
} else if (!metadata.GetCleanInfo().empty()) {
return PluginCleanliness::unknown;
}
for (const auto& info : metadata.GetDirtyInfo()) {
if (info.ChooseInfo("en").GetText().find("Do not clean") != std::string::npos) {
return PluginCleanliness::do_not_clean;
for (const auto& info : metadata.value().GetDirtyInfo()) {
if (info.ChooseInfo("en").GetText().find("Do not clean") != std::string::npos) {
return PluginCleanliness::do_not_clean;
}
}
}
+7 -7
View File
@@ -34,13 +34,13 @@ along with LOOT. If not, see
#include "plugin_tags.h"
namespace loot {
std::shared_ptr<DatabaseInterface> CreateDatabase(const GameType game,
const std::string& game_path = "",
const std::string& game_local_path = "");
PluginTags GetPluginTags(const std::shared_ptr<DatabaseInterface> db,
const std::string& plugin,
bool evaluateConditions = false);
PluginTags GetPluginTags(const std::shared_ptr<DatabaseInterface> db, const std::string& plugin);
PluginCleanliness GetPluginCleanliness(const std::shared_ptr<DatabaseInterface> db, const std::string& plugin);
PluginCleanliness GetPluginCleanliness(const std::shared_ptr<DatabaseInterface> db,
const std::string& plugin,
bool evaluateConditions = false);
}
#endif
#endif
+63 -24
View File
@@ -25,6 +25,7 @@
#include <loot/api.h>
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/functional.h>
#include "convenience.h"
#include "wrapper_version.h"
@@ -33,21 +34,50 @@ using pybind11::arg;
using pybind11::enum_;
using pybind11::class_;
using pybind11::metaclass;
using std::filesystem::path;
using std::filesystem::u8path;
namespace loot {
namespace py {
std::shared_ptr<GameInterface> CreateGameHandle(GameType gameType, std::string gamePath, std::string gameLocalPath) {
return CreateGameHandle(gameType, u8path(gamePath), u8path(gameLocalPath));
}
void LoadLists(std::shared_ptr<DatabaseInterface> db, std::string masterlistPath, std::string userlistPath) {
return db->LoadLists(u8path(masterlistPath), u8path(userlistPath));
}
void WriteMinimalList(std::shared_ptr<DatabaseInterface> db, std::string outputFile, bool overwrite) {
return db->WriteMinimalList(u8path(outputFile), overwrite);
}
bool UpdateMasterlist(std::shared_ptr<DatabaseInterface> db, std::string masterlistPath, std::string remoteUrl, std::string remoteBranch) {
return db->UpdateMasterlist(u8path(masterlistPath), remoteUrl, remoteBranch);
}
MasterlistInfo GetMasterlistRevision(std::shared_ptr<DatabaseInterface> db, std::string masterlistPath, bool getShortId) {
return db->GetMasterlistRevision(u8path(masterlistPath), getShortId);
}
}
void bindEnums(pybind11::module& module) {
enum_<GameType>(module, "GameType")
.value("tes4", GameType::tes4)
.value("tes5", GameType::tes5)
.value("tes5se", GameType::tes5se)
.value("tes5vr", GameType::tes5vr)
.value("fo3", GameType::fo3)
.value("fonv", GameType::fonv)
.value("fo4", GameType::fo4);
.value("fo4", GameType::fo4)
.value("fo4vr", GameType::fo4vr);
enum_<LogVerbosity>(module, "LogVerbosity")
.value("off", LogVerbosity::off)
.value("trace", LogVerbosity::trace)
.value("warning", LogVerbosity::warning);
enum_<LogLevel>(module, "LogLevel")
.value("trace", LogLevel::trace)
.value("debug", LogLevel::debug)
.value("info", LogLevel::info)
.value("warning", LogLevel::warning)
.value("error", LogLevel::error)
.value("fatal", LogLevel::fatal);
enum_<MessageType>(module, "MessageType")
.value("say", MessageType::say)
@@ -70,7 +100,8 @@ void bindMetadataClasses(pybind11::module& module) {
class_<SimpleMessage>(module, "SimpleMessage")
.def_readwrite("type", &SimpleMessage::type)
.def_readwrite("language", &SimpleMessage::language)
.def_readwrite("text", &SimpleMessage::text);
.def_readwrite("text", &SimpleMessage::text)
.def_readwrite("condition", &SimpleMessage::condition);
class_<PluginTags>(module, "PluginTags")
.def_readwrite("added", &PluginTags::added)
@@ -82,14 +113,14 @@ void bindMetadataClasses(pybind11::module& module) {
}
void bindVersionClasses(pybind11::module& module) {
class_<LootVersion>(module, "Version", metaclass())
class_<LootVersion>(module, "Version")
.def_readonly_static("major", &LootVersion::major)
.def_readonly_static("minor", &LootVersion::minor)
.def_readonly_static("patch", &LootVersion::patch)
.def_readonly_static("revision", &LootVersion::revision)
.def_static("string", LootVersion::string);
.def_static("string", LootVersion::GetVersionString);
class_<WrapperVersion>(module, "WrapperVersion", metaclass())
class_<WrapperVersion>(module, "WrapperVersion")
.def_readonly_static("major", &WrapperVersion::major)
.def_readonly_static("minor", &WrapperVersion::minor)
.def_readonly_static("patch", &WrapperVersion::patch)
@@ -98,18 +129,25 @@ void bindVersionClasses(pybind11::module& module) {
}
void bindInterfaceClasses(pybind11::module& module) {
class_<GameInterface, std::shared_ptr<GameInterface>>(module, "GameInterface")
.def("load_current_load_order_state", &GameInterface::LoadCurrentLoadOrderState)
.def("get_database", &GameInterface::GetDatabase);
class_<DatabaseInterface, std::shared_ptr<DatabaseInterface>>(module, "DatabaseInterface")
.def("load_lists", &DatabaseInterface::LoadLists, arg("masterlist_path"), arg("userlist_path") = "")
.def("eval_lists", &DatabaseInterface::EvalLists)
.def("update_masterlist", &DatabaseInterface::UpdateMasterlist)
.def("get_masterlist_revision", &DatabaseInterface::GetMasterlistRevision)
.def("load_lists", &py::LoadLists, arg("masterlist_path"), arg("userlist_path") = "")
.def("update_masterlist", &py::UpdateMasterlist)
.def("get_masterlist_revision", &py::GetMasterlistRevision)
.def("get_plugin_metadata", &DatabaseInterface::GetPluginMetadata,
arg("plugin"),
arg("includeUserMetadata") = true,
arg("evaluateConditions") = false)
.def("get_plugin_tags", &GetPluginTags)
.def("get_plugin_cleanliness", &GetPluginCleanliness)
.def("write_minimal_list", &DatabaseInterface::WriteMinimalList);
arg("plugin"),
arg("includeUserMetadata") = true,
arg("evaluateConditions") = false)
.def("get_plugin_tags", &GetPluginTags,
arg("plugin"),
arg("evaluateConditions") = false)
.def("get_plugin_cleanliness", &GetPluginCleanliness,
arg("plugin"),
arg("evaluateConditions") = false)
.def("write_minimal_list", &py::WriteMinimalList);
}
void bindClasses(pybind11::module& module) {
@@ -119,15 +157,16 @@ void bindClasses(pybind11::module& module) {
}
void bindFunctions(pybind11::module& module) {
module.def("set_logging_verbosity", &SetLoggingVerbosity);
module.def("set_log_file", &SetLogFile);
module.def("set_logging_callback", &SetLoggingCallback);
module.def("is_compatible", &IsCompatible);
module.def("initialise_locale", &InitialiseLocale);
module.def("initialise_locale", &InitialiseLocale, arg("id") = "");
module.def("create_database", &CreateDatabase, arg("game"), arg("game_path") = "", arg("game_local_path") = "");
module.def("create_game_handle", &py::CreateGameHandle,
arg("game"),
arg("game_path"),
arg("game_local_path") = "");
}
}
+20 -14
View File
@@ -7,16 +7,18 @@ import unittest
from loot_api import Version
from loot_api import WrapperVersion
from loot_api import GameType
from loot_api import LogVerbosity
from loot_api import SimpleMessage
from loot_api import MessageType
from loot_api import create_database
from loot_api import create_game_handle
from loot_api import is_compatible
from loot_api import set_logging_verbosity
from loot_api import set_logging_callback
from loot_api import initialise_locale
set_logging_verbosity(LogVerbosity.off)
initialise_locale("")
def logging_callback(level, message):
pass
set_logging_callback(logging_callback)
initialise_locale()
class GameFixture(unittest.TestCase):
game_path = os.path.join(u'.', u'Oblivion')
@@ -38,25 +40,26 @@ class GameFixture(unittest.TestCase):
class TestLootApi(GameFixture):
def test_is_compatible(self):
self.assertFalse(is_compatible(0, 9, 0))
self.assertTrue(is_compatible(0, 11, 0))
self.assertTrue(is_compatible(0, 14, 0))
def test_version(self):
self.assertEqual(Version.major, 0)
self.assertEqual(Version.minor, 11)
self.assertEqual(Version.patch, 0)
self.assertEqual(Version.minor, 14)
self.assertEqual(Version.patch, 3)
self.assertNotEqual(Version.revision, u'')
self.assertEqual(Version.string(), "0.11.0")
self.assertEqual(Version.string(), "0.14.3")
def test_wrapper_version(self):
self.assertEqual(WrapperVersion.major, 2)
self.assertEqual(WrapperVersion.major, 4)
self.assertEqual(WrapperVersion.minor, 0)
self.assertEqual(WrapperVersion.patch, 0)
self.assertEqual(WrapperVersion.patch, 1)
self.assertNotEqual(WrapperVersion.revision, u'')
self.assertNotEqual(WrapperVersion.revision, Version.revision)
self.assertEqual(WrapperVersion.string(), "2.0.0")
self.assertEqual(WrapperVersion.string(), "4.0.1")
def test_create_db(self):
db = create_database(GameType.tes4, self.game_path, self.local_path)
game = create_game_handle(GameType.tes4, self.game_path, self.local_path)
db = game.get_database()
self.assertNotEqual(db, None)
class TestDatabaseInterface(GameFixture):
@@ -65,7 +68,10 @@ class TestDatabaseInterface(GameFixture):
def setUp(self):
super(TestDatabaseInterface, self).setUp()
self.db = create_database(GameType.tes4, self.game_path, self.local_path)
game = create_game_handle(GameType.tes4, self.game_path, self.local_path)
game.load_current_load_order_state()
self.db = game.get_database()
def test_load_lists(self):
self.db.load_lists(self.masterlist_path, u'')
+2 -2
View File
@@ -25,9 +25,9 @@
#include "wrapper_version.h"
namespace loot {
const unsigned int WrapperVersion::major = 2;
const unsigned int WrapperVersion::major = 4;
const unsigned int WrapperVersion::minor = 0;
const unsigned int WrapperVersion::patch = 0;
const unsigned int WrapperVersion::patch = 1;
const std::string WrapperVersion::revision = "@GIT_COMMIT_STRING@";
std::string WrapperVersion::string() {