mirror of
https://github.com/loot/libloot-python.git
synced 2026-07-27 14:14:13 -07:00
Compare commits
59
Commits
1.2.0
...
fix-logging-gil
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
01a8567ed8 | ||
|
|
7ccfe6d7f4 | ||
|
|
2106ab4f01 | ||
|
|
dcf9b8b96b | ||
|
|
263322a75c | ||
|
|
b52cd9bd6b | ||
|
|
580bf87802 | ||
|
|
c144f7a66c | ||
|
|
ffd62f9e0c | ||
|
|
937a36a5ae | ||
|
|
915c002ca6 | ||
|
|
c19a9be579 | ||
|
|
b393507657 | ||
|
|
d356ac2445 | ||
|
|
fe4c3ab6b5 | ||
|
|
b17b531073 | ||
|
|
06a6d9ceb6 | ||
|
|
a35abab104 | ||
|
|
646a8d02e0 | ||
|
|
cab63886d3 | ||
|
|
8a61701855 | ||
|
|
8c75e83374 | ||
|
|
5450709ebe | ||
|
|
3a9ff95de2 | ||
|
|
1298fce6fd | ||
|
|
21242f359d | ||
|
|
6579eb5178 | ||
|
|
61a74b6984 | ||
|
|
66f84d4848 | ||
|
|
5f5c0e3949 | ||
|
|
ab926c8755 | ||
|
|
35475b292f | ||
|
|
51e2e4e4fa | ||
|
|
c17437a579 | ||
|
|
49204621c5 | ||
|
|
3098ffa692 | ||
|
|
392a090823 | ||
|
|
e98b43a4b1 | ||
|
|
a957ece62b | ||
|
|
f97de90e02 | ||
|
|
d00c59b7b2 | ||
|
|
e06227f437 | ||
|
|
bcc536d4b0 | ||
|
|
a564f230be | ||
|
|
27c8f58494 | ||
|
|
179125f006 | ||
|
|
671ca81beb | ||
|
|
7faa360790 | ||
|
|
0c9d014174 | ||
|
|
a8e2b11280 | ||
|
|
1275a11be7 | ||
|
|
5357858069 | ||
|
|
04088ac8f4 | ||
|
|
7098671ad5 | ||
|
|
212f899396 | ||
|
|
1e0dbe8dc2 | ||
|
|
abbc0892fd | ||
|
|
a94fb19bde | ||
|
|
2823db915a |
@@ -50,3 +50,5 @@ $RECYCLE.BIN/
|
||||
|
||||
# Windows shortcuts
|
||||
*.lnk
|
||||
|
||||
.vscode/
|
||||
|
||||
+89
-49
@@ -1,15 +1,23 @@
|
||||
|
||||
cmake_minimum_required (VERSION 2.8.12)
|
||||
project (loot_api_python)
|
||||
cmake_minimum_required (VERSION 3.1)
|
||||
project (libloot-python)
|
||||
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
|
||||
##############################
|
||||
|
||||
set(LIBLOOT_PY_VERSION_MAJOR 4)
|
||||
set(LIBLOOT_PY_VERSION_MINOR 0)
|
||||
set(LIBLOOT_PY_VERSION_PATCH 2)
|
||||
|
||||
find_package(Git)
|
||||
|
||||
IF (GIT_FOUND)
|
||||
@@ -21,18 +29,21 @@ ELSE()
|
||||
SET (GIT_COMMIT_STRING "unknown")
|
||||
ENDIF ()
|
||||
|
||||
message(STATUS "libloot-python version: ${LIBLOOT_PY_VERSION_MAJOR}.${LIBLOOT_PY_VERSION_MINOR}.${LIBLOOT_PY_VERSION_PATCH}")
|
||||
message(STATUS "Git revision: ${GIT_COMMIT_STRING}")
|
||||
|
||||
# Write to file.
|
||||
configure_file("${CMAKE_SOURCE_DIR}/src/wrapper_version.cpp.in" "${CMAKE_BINARY_DIR}/generated/wrapper_version.cpp" @ONLY)
|
||||
configure_file("${CMAKE_SOURCE_DIR}/python/setup.py" "${CMAKE_BINARY_DIR}/generated/setup.py" @ONLY)
|
||||
|
||||
#######################################
|
||||
# pybind11
|
||||
#######################################
|
||||
|
||||
set(PYBIND11_URL "https://github.com/pybind/pybind11/archive/v1.8.1.tar.gz")
|
||||
set(PYBIND11_DOWNLOAD_PATH "${EXTERNAL_PROJECTS_PATH}/pybind11-1.8.1.tar.gz")
|
||||
set(PYBIND11_EXTRACTED_PATH "${EXTERNAL_PROJECTS_PATH}/pybind11-1.8.1")
|
||||
set(PYBIND11_VERSION "2.4.2")
|
||||
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})
|
||||
@@ -45,32 +56,44 @@ execute_process(COMMAND ${CMAKE_COMMAND} -E tar xfz ${PYBIND11_DOWNLOAD_PATH}
|
||||
add_subdirectory(${PYBIND11_EXTRACTED_PATH})
|
||||
|
||||
#######################################
|
||||
# LOOT API
|
||||
# libloot
|
||||
#######################################
|
||||
|
||||
if (CMAKE_SYSTEM_NAME MATCHES "Windows")
|
||||
if (NOT "${CMAKE_GENERATOR_PLATFORM}" MATCHES "x64")
|
||||
set(LIBLOOT_URL "https://github.com/loot/libloot/releases/download/0.15.0/libloot-0.15.0-0-g629fdab_master-win32.7z")
|
||||
else()
|
||||
set(LIBLOOT_URL "https://github.com/loot/libloot/releases/download/0.15.0/libloot-0.15.0-0-g629fdab_master-win64.7z")
|
||||
endif()
|
||||
else()
|
||||
set(LIBLOOT_URL "https://github.com/loot/libloot/releases/download/0.15.0/libloot.tar.xz")
|
||||
endif()
|
||||
|
||||
ExternalProject_Add(loot-api-c++
|
||||
ExternalProject_Add(libloot
|
||||
PREFIX "external"
|
||||
URL "https://github.com/loot/loot/releases/download/0.10.2/loot-api_0.10.2-0-g9eb7d26_dev.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
|
||||
# testing-plugins
|
||||
#######################################
|
||||
|
||||
ExternalProject_Add(test-masterlist
|
||||
# This is a bit messy because the testing-plugins aren't actually required to
|
||||
# build libloot-python, but having them as a dependency is the easiest way to
|
||||
# manage downloading and moving them to the expected location.
|
||||
ExternalProject_Add(testing-plugins
|
||||
PREFIX "external"
|
||||
URL "https://github.com/loot/oblivion/archive/09286601739c11a3a3e4552c6ddbdcaeffd1a8d3.zip"
|
||||
URL "https://github.com/Ortham/testing-plugins/archive/1.4.1.tar.gz"
|
||||
CONFIGURE_COMMAND ""
|
||||
BUILD_COMMAND ""
|
||||
INSTALL_COMMAND "")
|
||||
@@ -79,14 +102,20 @@ ExternalProject_Add(test-masterlist
|
||||
# Python Module
|
||||
#######################################
|
||||
|
||||
pybind11_add_module(loot_api "${CMAKE_SOURCE_DIR}/src/main.cpp" "${CMAKE_BINARY_DIR}/generated/wrapper_version.cpp")
|
||||
pybind11_add_module(libloot-python "${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)
|
||||
# Set the target output name to loot to follow common Python library naming
|
||||
# conventions (no lib, no -python).
|
||||
set_target_properties(libloot-python PROPERTIES OUTPUT_NAME loot)
|
||||
|
||||
add_dependencies(libloot-python libloot testing-plugins)
|
||||
|
||||
if (CMAKE_SYSTEM_NAME MATCHES "Windows")
|
||||
target_link_libraries(loot_api PRIVATE ${LOOT_API_STATIC_LIBRARY})
|
||||
target_link_libraries(libloot-python PRIVATE ${LIBLOOT_STATIC_LIBRARY})
|
||||
else()
|
||||
target_link_libraries(loot_api PRIVATE ${LOOT_API_SHARED_LIBRARY})
|
||||
target_link_libraries(libloot-python PRIVATE ${LIBLOOT_SHARED_LIBRARY})
|
||||
endif()
|
||||
|
||||
########################################
|
||||
@@ -95,37 +124,51 @@ endif()
|
||||
|
||||
find_package(PythonInterp REQUIRED)
|
||||
|
||||
# Copy the API binary to the build directory.
|
||||
add_custom_command(TARGET loot_api POST_BUILD
|
||||
# Copy the libloot binary to the build directory.
|
||||
add_custom_command(TARGET libloot-python 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:libloot-python>/${LIBLOOT_SHARED_LIBRARY}")
|
||||
|
||||
# Copy the test masterlist to the build directory.
|
||||
ExternalProject_Get_Property(test-masterlist SOURCE_DIR)
|
||||
add_custom_command(TARGET loot_api POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
||||
"${SOURCE_DIR}/masterlist.yaml"
|
||||
"$<TARGET_FILE_DIR:loot_api>/masterlist.yaml")
|
||||
# Copy testing plugins
|
||||
ExternalProject_Get_Property(testing-plugins SOURCE_DIR)
|
||||
add_custom_command(TARGET libloot-python POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_directory
|
||||
${SOURCE_DIR}
|
||||
$<TARGET_FILE_DIR:libloot-python>)
|
||||
|
||||
# Also copy the test Python script to the build directory.
|
||||
add_custom_command(TARGET loot_api POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
||||
"${CMAKE_SOURCE_DIR}/src/test.py"
|
||||
"$<TARGET_FILE_DIR:loot_api>/test.py")
|
||||
enable_testing()
|
||||
|
||||
add_test(NAME python
|
||||
WORKING_DIRECTORY $<TARGET_FILE_DIR:libloot-python>
|
||||
COMMAND "${PYTHON_EXECUTABLE}" ${CMAKE_SOURCE_DIR}/test/test.py)
|
||||
|
||||
########################################
|
||||
# Install
|
||||
########################################
|
||||
|
||||
install(TARGETS loot_api
|
||||
DESTINATION "."
|
||||
CONFIGURATIONS Release)
|
||||
install(TARGETS libloot-python
|
||||
DESTINATION "loot"
|
||||
CONFIGURATIONS Release RelWithDebInfo)
|
||||
|
||||
install(FILES "${LOOT_API_EXTRACTED_PATH}/${LOOT_API_SHARED_LIBRARY}"
|
||||
"${CMAKE_SOURCE_DIR}/docs/README.md"
|
||||
install(FILES "${LIBLOOT_EXTRACTED_PATH}/${LIBLOOT_SHARED_LIBRARY}"
|
||||
"${CMAKE_SOURCE_DIR}/python/loot/__init__.py"
|
||||
DESTINATION "loot"
|
||||
CONFIGURATIONS Release RelWithDebInfo)
|
||||
|
||||
install(FILES "${CMAKE_SOURCE_DIR}/docs/README.md"
|
||||
"${CMAKE_BINARY_DIR}/generated/setup.py"
|
||||
"${CMAKE_SOURCE_DIR}/LICENSE"
|
||||
DESTINATION "."
|
||||
CONFIGURATIONS Release)
|
||||
CONFIGURATIONS Release RelWithDebInfo)
|
||||
|
||||
IF (MSVC)
|
||||
install(FILES $<TARGET_PDB_FILE:libloot-python>
|
||||
DESTINATION "loot"
|
||||
OPTIONAL
|
||||
CONFIGURATIONS RelWithDebInfo
|
||||
RENAME libloot-python.pdb)
|
||||
ENDIF ()
|
||||
|
||||
########################################
|
||||
# CPack
|
||||
@@ -145,17 +188,14 @@ IF (GIT_FOUND)
|
||||
ELSEIF (DEFINED ENV{TRAVIS_BRANCH})
|
||||
set(GIT_DESCRIBE_STRING "${GIT_DESCRIBE_STRING}_$ENV{TRAVIS_BRANCH}")
|
||||
ENDIF()
|
||||
|
||||
string(REPLACE "/" "-" GIT_DESCRIBE_STRING ${GIT_DESCRIBE_STRING})
|
||||
ELSE()
|
||||
SET (GIT_DESCRIBE_STRING "unknown-version")
|
||||
ENDIF ()
|
||||
|
||||
if (CMAKE_SYSTEM_NAME MATCHES "Windows")
|
||||
set(CPACK_GENERATOR "7Z")
|
||||
else()
|
||||
set(CPACK_GENERATOR "TXZ")
|
||||
endif()
|
||||
|
||||
set(CPACK_PACKAGE_VERSION ${GIT_DESCRIBE_STRING})
|
||||
set(CPACK_GENERATOR "ZIP")
|
||||
set(CPACK_PACKAGE_VERSION "${GIT_DESCRIBE_STRING}-python$ENV{PYTHON_VERSION}")
|
||||
set(CPACK_PACKAGE_DIRECTORY "${CMAKE_BINARY_DIR}/package")
|
||||
|
||||
include(CPack)
|
||||
|
||||
@@ -1,21 +1,20 @@
|
||||
LOOT API Python Module
|
||||
=======================
|
||||
libloot-python
|
||||
==============
|
||||
|
||||
[](https://ci.appveyor.com/project/WrinklyNinja/loot-api-python)
|
||||
[](https://travis-ci.org/loot/loot-api-python)
|
||||
[](https://ci.appveyor.com/project/LOOT/libloot-python/branch/master)
|
||||
[](http://loot-api-python.readthedocs.io/)
|
||||
|
||||
A Python module that wraps the LOOT API, generated by [pybind11](https://github.com/pybind/pybind11).
|
||||
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/libloot-python). The snapshot build archives are named like so:
|
||||
|
||||
```
|
||||
loot_api_python-<short revision ID>-win32.7z
|
||||
libloot-python-<short revision ID>-python<python version>-win<architecture>.zip
|
||||
```
|
||||
|
||||
For example `loot_api_python-94de368-win32.7z` was built using the revision with shortened commit ID `94de368`.
|
||||
For example `libloot-python-94de368-python2.7-win32.zip` 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.
|
||||
|
||||
+43
-24
@@ -1,64 +1,83 @@
|
||||
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")
|
||||
- ps: (New-Object Net.WebClient).DownloadFile('https://github.com/WrinklyNinja/testing-plugins/archive/1.4.1.zip', "$PWD/1.4.1.zip")
|
||||
- 7z x 1.4.1.zip
|
||||
- mv testing-plugins-1.4.1 testing-plugins
|
||||
|
||||
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" -A x64 -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'
|
||||
project: 'c:\projects\libloot-python\build\libloot-python.sln'
|
||||
|
||||
test_script:
|
||||
- cd %APPVEYOR_BUILD_FOLDER%\build\Release
|
||||
- python -m unittest test
|
||||
- cd %APPVEYOR_BUILD_FOLDER%\build
|
||||
- ctest -C %CONFIGURATION%
|
||||
|
||||
after_test:
|
||||
- cd %APPVEYOR_BUILD_FOLDER%\build
|
||||
- cpack
|
||||
# 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.
|
||||
- cpack -C %CONFIGURATION%
|
||||
- ps: $env:GIT_DESCRIBE = ((git describe --tags --long --always) | Out-String) -replace "`n|`r", ""
|
||||
- ps: $env:PACKAGE_VERSION = $env:GIT_DESCRIBE + "_" + ($env:APPVEYOR_REPO_BRANCH.replace("/", "-"))
|
||||
- ps: $env:ARCHITECTURE = $env:PLATFORM.substring($env:PLATFORM.length - 2)
|
||||
|
||||
artifacts:
|
||||
- path: build\package\loot_api_python-$(GIT_DESCRIBE)_$(APPVEYOR_REPO_BRANCH)-win32.7z
|
||||
name: loot_api_python
|
||||
- path: build\package\libloot-python-$(PACKAGE_VERSION)-python$(PYTHON_VERSION)-win$(ARCHITECTURE).zip
|
||||
name: libloot-python
|
||||
|
||||
deploy:
|
||||
- provider: BinTray
|
||||
username: wrinklyninja
|
||||
api_key:
|
||||
secure: fBQJmUDK/EgEUWjjbo6bWcitczeFTJZT4OZ3ZZ4FoUT6soBsTWPQJnr8YEVMFhGP
|
||||
subject: wrinklyninja
|
||||
repo: loot
|
||||
package: loot-api-python
|
||||
version: $(GIT_DESCRIBE)_$(APPVEYOR_REPO_BRANCH)
|
||||
secure: PgsEA6TjHVf718zMnK7J/fT1hUAVNKBeWhpYgYaeCyeZk37VT4Ics6j7+B7ElLEr
|
||||
subject: loot
|
||||
repo: snapshots
|
||||
package: libloot-python
|
||||
version: $(PACKAGE_VERSION)
|
||||
publish: true
|
||||
artifact: loot_api_python
|
||||
artifact: libloot-python
|
||||
|
||||
- provider: GitHub
|
||||
tag: $(APPVEYOR_REPO_TAG_NAME)
|
||||
release: LOOT API Python Module v$(APPVEYOR_REPO_TAG_NAME)
|
||||
release: libloot-python 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
|
||||
artifact: loot_api_python
|
||||
secure: yDqT5l/e5MntbW99V6+MHlfFgNv+UIogFfeyUVqtFk5lFRB/dAraLLwKCLl6y+DH
|
||||
artifact: libloot-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/libloot-python -b loot/snapshots/libloot-python -u wrinklyninja -k $env:bintray_auth_token -t $env:github_auth_token -n 30
|
||||
|
||||
+5
-5
@@ -1,13 +1,13 @@
|
||||
LOOT API Python Wrapper
|
||||
=======================
|
||||
libloot-python
|
||||
==============
|
||||
|
||||
This archive contains a build of the LOOT API Python wrapper module and its corresponding 32-bit Windows build of the LOOT API.
|
||||
This archive contains a build of the libloot-python wrapper module and its corresponding 32-bit Windows build of libloot.
|
||||
|
||||
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.
|
||||
The library source code is available [on GitHub](https://github.com/loot/loot-api-python).
|
||||
The library source code is available [on GitHub](https://github.com/loot/libloot-python).
|
||||
|
||||
---
|
||||
|
||||
|
||||
+12
-10
@@ -1,6 +1,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# LOOT API Python Module documentation build configuration file, created by
|
||||
# libloot-python documentation build configuration file, created by
|
||||
# sphinx-quickstart on Mon Aug 15 07:11:32 2016.
|
||||
#
|
||||
# This file is execfile()d with the current directory set to its
|
||||
@@ -22,7 +22,7 @@
|
||||
|
||||
import os
|
||||
import sys
|
||||
sys.path.insert(0, os.path.abspath('../build/Release'))
|
||||
sys.path.insert(0, os.path.abspath('../build/RelWithDebInfo'))
|
||||
|
||||
# -- General configuration ------------------------------------------------
|
||||
|
||||
@@ -34,6 +34,7 @@ sys.path.insert(0, os.path.abspath('../build/Release'))
|
||||
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
||||
# ones.
|
||||
extensions = [
|
||||
'sphinx.ext.autodoc',
|
||||
'sphinx.ext.intersphinx',
|
||||
]
|
||||
|
||||
@@ -54,8 +55,8 @@ source_suffix = '.rst'
|
||||
master_doc = 'index'
|
||||
|
||||
# General information about the project.
|
||||
project = u'LOOT API Python Module'
|
||||
copyright = u'2016, WrinklyNinja'
|
||||
project = u'libloot-python'
|
||||
copyright = u'2019, WrinklyNinja'
|
||||
author = u'WrinklyNinja'
|
||||
|
||||
# The version info for the project you're documenting, acts as replacement for
|
||||
@@ -139,7 +140,7 @@ html_theme = 'sphinx_rtd_theme'
|
||||
# The name for this set of Sphinx documents.
|
||||
# "<project> v<release> documentation" by default.
|
||||
#
|
||||
# html_title = u'LOOT API Python Module v;atest'
|
||||
# html_title = u'libloot-python v;atest'
|
||||
|
||||
# A shorter title for the navigation bar. Default is the same as html_title.
|
||||
#
|
||||
@@ -265,7 +266,7 @@ latex_elements = {
|
||||
# (source start file, target name, title,
|
||||
# author, documentclass [howto, manual, or own class]).
|
||||
latex_documents = [
|
||||
(master_doc, 'LOOTAPIPythonModule.tex', u'LOOT API Python Module Documentation',
|
||||
(master_doc, 'libloot-python.tex', u'libloot-python Documentation',
|
||||
u'WrinklyNinja', 'manual'),
|
||||
]
|
||||
|
||||
@@ -307,7 +308,7 @@ latex_documents = [
|
||||
# One entry per manual page. List of tuples
|
||||
# (source start file, name, description, authors, manual section).
|
||||
man_pages = [
|
||||
(master_doc, 'lootapipythonmodule', u'LOOT API Python Module Documentation',
|
||||
(master_doc, 'libloot-python', u'libloot-python Documentation',
|
||||
[author], 1)
|
||||
]
|
||||
|
||||
@@ -322,8 +323,8 @@ man_pages = [
|
||||
# (source start file, target name, title, author,
|
||||
# dir menu entry, description, category)
|
||||
texinfo_documents = [
|
||||
(master_doc, 'LOOTAPIPythonModule', u'LOOT API Python Module Documentation',
|
||||
author, 'LOOTAPIPythonModule', 'One line description of project.',
|
||||
(master_doc, 'libloot-python', u'libloot-python Documentation',
|
||||
author, 'libloot-python', 'One line description of project.',
|
||||
'Miscellaneous'),
|
||||
]
|
||||
|
||||
@@ -346,5 +347,6 @@ 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': ('https://loot.readthedocs.io/en/0.15.0/', None),
|
||||
'python': ('https://docs.python.org/3', None)
|
||||
}
|
||||
|
||||
+3
-3
@@ -1,10 +1,10 @@
|
||||
.. LOOT API Python Module documentation master file, created by
|
||||
.. libloot-python documentation master file, created by
|
||||
sphinx-quickstart on Mon Aug 15 07:11:32 2016.
|
||||
You can adapt this file completely to your liking, but it should at least
|
||||
contain the root `toctree` directive.
|
||||
|
||||
LOOT API Python Module
|
||||
======================
|
||||
libloot-python
|
||||
==============
|
||||
|
||||
Contents:
|
||||
|
||||
|
||||
+12
-168
@@ -2,173 +2,18 @@
|
||||
API Reference
|
||||
*************
|
||||
|
||||
As this API is just a wrapper for LOOT's C++ API, its documentation is linked to
|
||||
for all non-Python-specific information.
|
||||
As this API is just a wrapper for libloot's C++ API, its documentation is linked
|
||||
to for all non-Python-specific information.
|
||||
|
||||
Enumerations
|
||||
============
|
||||
|
||||
The wrapped enumeration types below are classes in Python, but the distinction
|
||||
The wrapped enumeration types are classes in Python, but the distinction
|
||||
makes no difference in practice, so they're grouped here for semantics. All
|
||||
values are unsigned integer constants.
|
||||
their values are unsigned integer constants.
|
||||
|
||||
.. py:class:: loot_api.GameType
|
||||
.. automodule:: loot
|
||||
:members:
|
||||
:exclude-members: Version, WrapperVersion
|
||||
|
||||
Wraps :cpp:type:`loot::GameType` to expose the LOOT API's game
|
||||
codes.
|
||||
|
||||
.. py:attribute:: fo3
|
||||
.. py:attribute:: fo4
|
||||
.. py:attribute:: fonv
|
||||
.. py:attribute:: tes4
|
||||
.. py:attribute:: tes5
|
||||
.. py:attribute:: tes5se
|
||||
|
||||
.. py:class:: loot_api.LanguageCode
|
||||
|
||||
Wraps :cpp:type:`loot::LanguageCode` to expose the LOOT API's
|
||||
language 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:class:: loot_api.MessageType
|
||||
|
||||
Wraps :cpp:type:`loot::MessageType` to expose the LOOT API's
|
||||
message type codes.
|
||||
|
||||
.. py:attribute:: error
|
||||
.. py:attribute:: say
|
||||
.. py:attribute:: warn
|
||||
|
||||
.. py:class:: loot_api.PluginCleanliness
|
||||
|
||||
Wraps :cpp:type:`loot::PluginCleanliness` to expose the LOOT API's plugin cleanliness state codes.
|
||||
|
||||
.. py:attribute:: clean
|
||||
.. py:attribute:: dirty
|
||||
.. py:attribute:: do_not_clean
|
||||
.. py:attribute:: unknown
|
||||
|
||||
Public-Field Data Structures
|
||||
============================
|
||||
|
||||
Classes with public fields and no member functions.
|
||||
|
||||
.. py:class:: loot_api.MasterlistInfo
|
||||
|
||||
Wraps :cpp:class:`loot::MasterlistInfo`.
|
||||
|
||||
.. py:attribute:: revision_id
|
||||
|
||||
A Unicode string containing a Git commit's SHA-1 checksum.
|
||||
|
||||
.. py:attribute:: revision_date
|
||||
|
||||
A Unicode string containing the date of the commit given by :py:attr:`revision_id`, in ISO 8601 format (YYYY-MM-DD).
|
||||
|
||||
.. py:attribute:: is_modified
|
||||
|
||||
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
|
||||
|
||||
Wraps :cpp:class:`loot::SimpleMessage`.
|
||||
|
||||
.. py:attribute:: type
|
||||
|
||||
A :py:class:`loot_api.MessageType` giving the message type.
|
||||
|
||||
.. py:attribute:: language
|
||||
|
||||
A :py:class:`loot_api.LanguageCode` giving the message text language.
|
||||
|
||||
.. py:attribute:: text
|
||||
|
||||
A Unicode string containing the message text.
|
||||
|
||||
.. py:class:: loot_api.PluginTags
|
||||
|
||||
Wraps :cpp:class:`loot::PluginTags`.
|
||||
|
||||
.. py:attribute:: added
|
||||
|
||||
A set of Unicode strings giving Bash Tags suggested for addition.
|
||||
|
||||
.. py:attribute:: removed
|
||||
|
||||
A set of Unicode strings giving Bash Tags suggested for removal.
|
||||
|
||||
.. py:attribute:: userlist_modified
|
||||
|
||||
A boolean that is true if the suggestions contain metadata obtained from a loaded userlist.
|
||||
|
||||
|
||||
Functions
|
||||
=========
|
||||
|
||||
.. 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
|
||||
|
||||
Initialise a new database handle. Wraps :cpp:func:`loot::IsCompatible`.
|
||||
|
||||
Classes
|
||||
=======
|
||||
|
||||
.. 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
|
||||
|
||||
Determines the database’s knowledge of a plugin’s cleanliness. Wraps :cpp:func:`GetPluginCleanliness`.
|
||||
|
||||
.. py:method:: get_plugin_messages(loot_api.DatabaseInterface, unicode, loot_api.LanguageCode) -> list<loot_api.Message>
|
||||
|
||||
Outputs the messages associated with the given plugin in the database. Wraps :cpp:func:`GetPluginMessages`.
|
||||
|
||||
.. py:method:: get_plugin_tags(loot_api.DatabaseInterface, unicode) -> loot_api.PluginTags
|
||||
|
||||
Outputs the Bash Tags suggested for addition and removal by the database for the given plugin. Wraps :cpp:func:`GetPluginTags`.
|
||||
|
||||
.. 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`.
|
||||
|
||||
.. py:method:: write_minimal_list(loot_api.DatabaseInterface, unicode, bool) -> NoneType
|
||||
|
||||
Writes a minimal metadata file containing only Bash Tag suggestions and/or cleanliness info from the loaded metadata. Wraps :cpp:func:`WriteMinimalList`.
|
||||
|
||||
.. py:class:: loot_api.Version
|
||||
.. py:class:: loot.Version
|
||||
|
||||
Wraps :cpp:class:`loot::LootVersion`.
|
||||
|
||||
@@ -188,14 +33,13 @@ Classes
|
||||
|
||||
A Unicode string containing the SHA-1 of the Git revision that the wrapped C++ API was built from.
|
||||
|
||||
.. py:staticmethod:: string() -> unicode
|
||||
.. py:staticmethod:: string() -> str
|
||||
|
||||
Returns the API version as a string of the form ``major.minor.patch``
|
||||
|
||||
.. py:class:: loot_api.WrapperVersion
|
||||
.. py:class:: loot.WrapperVersion
|
||||
|
||||
Provides information about the version of the LOOT API Python wrapper that is
|
||||
being run.
|
||||
Provides information about the version of libloot-python that is being run.
|
||||
|
||||
.. py:attribute:: major
|
||||
|
||||
@@ -213,6 +57,6 @@ Classes
|
||||
|
||||
A Unicode string containing the SHA-1 of the Git revision that the wrapped C++ API was built from.
|
||||
|
||||
.. py:staticmethod:: string() -> unicode
|
||||
.. py:staticmethod:: string() -> str
|
||||
|
||||
Returns the API version as a string of the form ``major.minor.patch``
|
||||
|
||||
+10
-10
@@ -7,16 +7,16 @@ Installing the wrapper
|
||||
|
||||
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.
|
||||
* ``loot.*.pyd`` is the Python wrapper
|
||||
* ``loot.dll`` is the C++ library 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
|
||||
=================
|
||||
@@ -27,10 +27,10 @@ Checking Compatibility
|
||||
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)
|
||||
>>> import loot
|
||||
>>> loot.is_compatible(0,14,0)
|
||||
True
|
||||
>>> loot_api.is_compatible(0,9,0)
|
||||
>>> loot.is_compatible(0,9,0)
|
||||
False
|
||||
|
||||
Getting a Plugin's Bash Tag Suggestions
|
||||
@@ -38,9 +38,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', '')
|
||||
>>> import loot
|
||||
>>> db = loot.create_game_handle(loot.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'])
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
from .loot import *
|
||||
@@ -0,0 +1,89 @@
|
||||
import itertools
|
||||
import os
|
||||
import platform
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
import threading
|
||||
import time
|
||||
from contextlib import contextmanager
|
||||
|
||||
from setuptools import Distribution, find_packages, setup
|
||||
|
||||
try: # python 3
|
||||
import winreg
|
||||
from urllib.request import urlretrieve
|
||||
except ImportError: # python 2
|
||||
import _winreg as winreg
|
||||
from urllib import urlretrieve
|
||||
|
||||
|
||||
MSVC_MIN_VERSION = (14, 0, 24215)
|
||||
|
||||
|
||||
class BinaryDistribution(Distribution):
|
||||
def has_ext_modules(foo):
|
||||
return True
|
||||
|
||||
|
||||
def is_msvc_redist_installed(major, minor, build):
|
||||
if platform.machine().endswith("64"): # check if os is 64bit
|
||||
sub_key = "SOFTWARE\\Microsoft\\VisualStudio\\14.0\\VC\\Runtimes\\x64"
|
||||
else:
|
||||
sub_key = "SOFTWARE\\Microsoft\\VisualStudio\\14.0\\VC\\Runtimes\\x86"
|
||||
try:
|
||||
key_handle = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, sub_key)
|
||||
runtime_installed = winreg.QueryValueEx(key_handle, "Installed")[0]
|
||||
installed_major = winreg.QueryValueEx(key_handle, "Major")[0]
|
||||
installed_minor = winreg.QueryValueEx(key_handle, "Minor")[0]
|
||||
installed_build = winreg.QueryValueEx(key_handle, "Bld")[0]
|
||||
return (
|
||||
runtime_installed != 0
|
||||
and installed_major >= major
|
||||
and installed_minor >= minor
|
||||
and installed_build >= build
|
||||
)
|
||||
except WindowsError as exc:
|
||||
return False
|
||||
|
||||
with open("README.md", "r") as fh:
|
||||
long_description = fh.read()
|
||||
|
||||
def install_msvc_redist():
|
||||
url = (
|
||||
"https://download.microsoft.com/download/6/A/A/"
|
||||
"6AA4EDFF-645B-48C5-81CC-ED5963AEAD48/vc_redist.x86.exe"
|
||||
)
|
||||
dl_dir = tempfile.mkdtemp()
|
||||
dl_file = os.path.join(dl_dir, "vc_redist.exe")
|
||||
urlretrieve(url, dl_file)
|
||||
subprocess.call([dl_file, "/quiet"])
|
||||
# trying to remove the temp folder triggers
|
||||
# an error during py2 pip install
|
||||
|
||||
|
||||
if not is_msvc_redist_installed(*MSVC_MIN_VERSION):
|
||||
install_msvc_redist()
|
||||
|
||||
# The version string is substituted in by CMake.
|
||||
setup(
|
||||
name="libloot-python",
|
||||
version="@LIBLOOT_PY_VERSION_MAJOR@.@LIBLOOT_PY_VERSION_MINOR@.@LIBLOOT_PY_VERSION_PATCH@",
|
||||
description="A Python module that wraps libloot.",
|
||||
long_description=long_description,
|
||||
long_description_content_type="text/markdown",
|
||||
url="https://github.com/loot/libloot-python",
|
||||
packages=find_packages(),
|
||||
include_package_data=True,
|
||||
package_data={"loot": ["loot*.pyd", "loot.dll"]},
|
||||
distclass=BinaryDistribution,
|
||||
classifiers=[
|
||||
'License :: OSI Approved :: GNU General Public License v3 (GPLv3)',
|
||||
'Programming Language :: Python :: 2.7',
|
||||
'Programming Language :: Python :: 3',
|
||||
'Programming Language :: C++'
|
||||
'Operating System :: Microsoft :: Windows',
|
||||
'Intended Audience :: Developers',
|
||||
],
|
||||
python_requires='>=2.7',
|
||||
)
|
||||
@@ -0,0 +1,83 @@
|
||||
/* LOOT
|
||||
|
||||
A load order optimisation tool for Oblivion, Skyrim, Fallout 3 and
|
||||
Fallout: New Vegas.
|
||||
|
||||
Copyright (C) 2014-2017 Oliver Hamlet
|
||||
|
||||
This file is part of LOOT.
|
||||
|
||||
LOOT is free software: you can redistribute
|
||||
it and/or modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
LOOT is distributed in the hope that it will
|
||||
be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with LOOT. If not, see
|
||||
<https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "convenience.h"
|
||||
|
||||
#include <loot/api.h>
|
||||
|
||||
namespace loot {
|
||||
PluginTags GetPluginTags(const std::shared_ptr<DatabaseInterface> db, const std::string& plugin, bool evaluateConditions) {
|
||||
PluginTags tags;
|
||||
|
||||
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, 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, bool evaluateConditions) {
|
||||
auto metadata = db->GetPluginMetadata(plugin, true, evaluateConditions);
|
||||
|
||||
if (!metadata.has_value()) {
|
||||
return PluginCleanliness::unknown;
|
||||
}
|
||||
|
||||
auto dirtyInfo = metadata.value().GetDirtyInfo();
|
||||
auto cleanInfo = metadata.value().GetCleanInfo();
|
||||
|
||||
if (dirtyInfo.empty() == cleanInfo.empty()) {
|
||||
return PluginCleanliness::unknown;
|
||||
}
|
||||
|
||||
if (!cleanInfo.empty()) {
|
||||
return PluginCleanliness::clean;
|
||||
}
|
||||
|
||||
for (const auto& info : dirtyInfo) {
|
||||
if (info.ChooseInfo("en").GetText().find("Do not clean") != std::string::npos) {
|
||||
return PluginCleanliness::do_not_clean;
|
||||
}
|
||||
}
|
||||
|
||||
return PluginCleanliness::dirty;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/* LOOT
|
||||
|
||||
A load order optimisation tool for Oblivion, Skyrim, Fallout 3 and
|
||||
Fallout: New Vegas.
|
||||
|
||||
Copyright (C) 2014-2017 Oliver Hamlet
|
||||
|
||||
This file is part of LOOT.
|
||||
|
||||
LOOT is free software: you can redistribute
|
||||
it and/or modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
LOOT is distributed in the hope that it will
|
||||
be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with LOOT. If not, see
|
||||
<https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef LIBLOOT_PYTHON_CONVENIENCE
|
||||
#define LIBLOOT_PYTHON_CONVENIENCE
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <loot/enum/game_type.h>
|
||||
#include <loot/database_interface.h>
|
||||
|
||||
#include "plugin_cleanliness.h"
|
||||
#include "plugin_tags.h"
|
||||
|
||||
namespace loot {
|
||||
PluginTags GetPluginTags(const std::shared_ptr<DatabaseInterface> db,
|
||||
const std::string& plugin,
|
||||
bool evaluateConditions = false);
|
||||
|
||||
PluginCleanliness GetPluginCleanliness(const std::shared_ptr<DatabaseInterface> db,
|
||||
const std::string& plugin,
|
||||
bool evaluateConditions = false);
|
||||
}
|
||||
|
||||
#endif
|
||||
+217
-80
@@ -25,108 +25,245 @@
|
||||
#include <loot/api.h>
|
||||
#include <pybind11/pybind11.h>
|
||||
#include <pybind11/stl.h>
|
||||
#include <pybind11/functional.h>
|
||||
|
||||
#include "convenience.h"
|
||||
#include "wrapper_version.h"
|
||||
|
||||
PYBIND11_DECLARE_HOLDER_TYPE(T, std::shared_ptr<T>);
|
||||
using pybind11::arg;
|
||||
using pybind11::enum_;
|
||||
using pybind11::class_;
|
||||
using pybind11::metaclass;
|
||||
using std::filesystem::path;
|
||||
using std::filesystem::u8path;
|
||||
|
||||
PYBIND11_PLUGIN(loot_api) {
|
||||
using loot::CreateDatabase;
|
||||
using loot::DatabaseInterface;
|
||||
using loot::IsCompatible;
|
||||
using loot::GameType;
|
||||
using loot::LanguageCode;
|
||||
using loot::LootVersion;
|
||||
using loot::MessageType;
|
||||
using loot::MasterlistInfo;
|
||||
using loot::PluginCleanliness;
|
||||
using loot::SimpleMessage;
|
||||
using loot::PluginTags;
|
||||
using loot::WrapperVersion;
|
||||
namespace loot {
|
||||
namespace py {
|
||||
std::shared_ptr<GameInterface> CreateGameHandle(GameType gameType, std::string gamePath, std::string gameLocalPath) {
|
||||
return CreateGameHandle(gameType, u8path(gamePath), u8path(gameLocalPath));
|
||||
}
|
||||
|
||||
using pybind11::arg;
|
||||
using pybind11::enum_;
|
||||
using pybind11::class_;
|
||||
void LoadLists(std::shared_ptr<DatabaseInterface> db, std::string masterlistPath, std::string userlistPath) {
|
||||
return db->LoadLists(u8path(masterlistPath), u8path(userlistPath));
|
||||
}
|
||||
|
||||
const std::string emptyString;
|
||||
void WriteMinimalList(std::shared_ptr<DatabaseInterface> db, std::string outputFile, bool overwrite) {
|
||||
return db->WriteMinimalList(u8path(outputFile), overwrite);
|
||||
}
|
||||
|
||||
pybind11::module module("loot_api", "A Python module that wraps the LOOT API, generated by pybind11.");
|
||||
bool UpdateMasterlist(std::shared_ptr<DatabaseInterface> db, std::string masterlistPath, std::string remoteUrl, std::string remoteBranch) {
|
||||
return db->UpdateMasterlist(u8path(masterlistPath), remoteUrl, remoteBranch);
|
||||
}
|
||||
|
||||
enum_<GameType>(module, "GameType")
|
||||
MasterlistInfo GetMasterlistRevision(std::shared_ptr<DatabaseInterface> db, std::string masterlistPath, bool getShortId) {
|
||||
return db->GetMasterlistRevision(u8path(masterlistPath), getShortId);
|
||||
}
|
||||
|
||||
void SetLoggingCallback(std::function<void(LogLevel, const char*)> callback) {
|
||||
callback = [callback](LogLevel level, const char* message) {
|
||||
pybind11::gil_scoped_acquire acquire;
|
||||
callback(level, message);
|
||||
};
|
||||
loot::SetLoggingCallback(callback);
|
||||
}
|
||||
}
|
||||
|
||||
void bindEnums(pybind11::module& module) {
|
||||
pybind11::options options;
|
||||
options.disable_function_signatures();
|
||||
|
||||
enum_<GameType>(module, "GameType", "Wraps :cpp:enum:`loot::GameType` to expose libloot's game codes.")
|
||||
.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_<LanguageCode>(module, "LanguageCode")
|
||||
.value("english", LanguageCode::english)
|
||||
.value("spanish", LanguageCode::spanish)
|
||||
.value("russian", LanguageCode::russian)
|
||||
.value("french", LanguageCode::french)
|
||||
.value("chinese", LanguageCode::chinese)
|
||||
.value("polish", LanguageCode::polish)
|
||||
.value("brazilian_portuguese", LanguageCode::brazilian_portuguese)
|
||||
.value("finnish", LanguageCode::finnish)
|
||||
.value("german", LanguageCode::german)
|
||||
.value("danish", LanguageCode::danish)
|
||||
.value("korean", LanguageCode::korean);
|
||||
enum_<LogLevel>(module, "LogLevel", "Wraps :cpp:enum:`loot::LogLevel` to expose libloot's log level codes.")
|
||||
.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")
|
||||
enum_<MessageType>(module, "MessageType", "Wraps :cpp:enum:`loot::MessageType` to expose libloot's message type codes.")
|
||||
.value("say", MessageType::say)
|
||||
.value("warn", MessageType::warn)
|
||||
.value("error", MessageType::error);
|
||||
|
||||
enum_<PluginCleanliness>(module, "PluginCleanliness")
|
||||
.value("clean", PluginCleanliness::clean)
|
||||
.value("dirty", PluginCleanliness::dirty)
|
||||
.value("do_not_clean", PluginCleanliness::do_not_clean)
|
||||
.value("unknown", PluginCleanliness::unknown);
|
||||
enum_<PluginCleanliness>(module, "PluginCleanliness", "Codes used to indicate the cleanliness of a plugin according to the information contained within the loaded masterlist / userlist.")
|
||||
.value("clean", PluginCleanliness::clean, "Indicates that the plugin is clean.")
|
||||
.value("dirty", PluginCleanliness::dirty, "Indicates that the plugin is dirty.")
|
||||
.value("do_not_clean", PluginCleanliness::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.")
|
||||
.value("unknown", PluginCleanliness::unknown, "Indicates that no data is available on whether the plugin is dirty or not.");
|
||||
}
|
||||
|
||||
class_<MasterlistInfo>(module, "MasterlistInfo")
|
||||
.def_readwrite("revision_id", &MasterlistInfo::revision_id)
|
||||
.def_readwrite("revision_date", &MasterlistInfo::revision_date)
|
||||
.def_readwrite("is_modified", &MasterlistInfo::is_modified);
|
||||
void bindMetadataClasses(pybind11::module& module) {
|
||||
class_<MasterlistInfo>(module, "MasterlistInfo", "Wraps :cpp:class:`loot::MasterlistInfo`.")
|
||||
.def_readwrite("revision_id", &MasterlistInfo::revision_id, "A Unicode string containing a Git commit's SHA-1 checksum.")
|
||||
.def_readwrite("revision_date", &MasterlistInfo::revision_date, "A Unicode string containing the date of the commit given by :py:attr:`~loot.MasterlistInfo.revision_id`, in ISO 8601 format (YYYY-MM-DD).")
|
||||
.def_readwrite("is_modified", &MasterlistInfo::is_modified, "A boolean that is true if the masterlist has been modified from its state at the commit given by :py:attr:`~loot.MasterlistInfo.revision_id`.");
|
||||
|
||||
class_<SimpleMessage>(module, "Message")
|
||||
.def_readwrite("type", &SimpleMessage::type)
|
||||
.def_readwrite("language", &SimpleMessage::language)
|
||||
.def_readwrite("text", &SimpleMessage::text);
|
||||
class_<SimpleMessage>(module, "SimpleMessage", "Wraps :cpp:class:`loot::SimpleMessage`.")
|
||||
.def_readwrite("type", &SimpleMessage::type, "A :py:class:`loot.MessageType` giving the message type.")
|
||||
.def_readwrite("language", &SimpleMessage::language, "A Unicode string giving the message text language.")
|
||||
.def_readwrite("text", &SimpleMessage::text, "A Unicode string containing the message text.")
|
||||
.def_readwrite("condition", &SimpleMessage::condition, "A Unicode string containing the message condition.");
|
||||
|
||||
class_<PluginTags>(module, "PluginTags")
|
||||
.def_readwrite("added", &PluginTags::added)
|
||||
.def_readwrite("removed", &PluginTags::removed)
|
||||
.def_readwrite("userlist_modified", &PluginTags::userlist_modified);
|
||||
.def_readwrite("added", &PluginTags::added, "A set of Unicode strings giving Bash Tags suggested for addition.")
|
||||
.def_readwrite("removed", &PluginTags::removed, "A set of Unicode strings giving Bash Tags suggested for removal.")
|
||||
.def_readwrite("userlist_modified", &PluginTags::userlist_modified, "A boolean that is true if the suggestions contain metadata obtained from a loaded userlist.");
|
||||
|
||||
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);
|
||||
|
||||
class_<WrapperVersion>(module, "WrapperVersion")
|
||||
.def_readonly_static("major", &WrapperVersion::major)
|
||||
.def_readonly_static("minor", &WrapperVersion::minor)
|
||||
.def_readonly_static("patch", &WrapperVersion::patch)
|
||||
.def_readonly_static("revision", &WrapperVersion::revision)
|
||||
.def_static("string", WrapperVersion::string);
|
||||
|
||||
class_<DatabaseInterface, std::shared_ptr<DatabaseInterface>>(module, "DatabaseInterface")
|
||||
.def("load_lists", &DatabaseInterface::LoadLists, arg("masterlist_path"), arg("userlist_path") = emptyString)
|
||||
.def("eval_lists", &DatabaseInterface::EvalLists)
|
||||
.def("sort_plugins", &DatabaseInterface::SortPlugins)
|
||||
.def("update_masterlist", &DatabaseInterface::UpdateMasterlist)
|
||||
.def("get_masterlist_revision", &DatabaseInterface::GetMasterlistRevision)
|
||||
.def("get_plugin_tags", &DatabaseInterface::GetPluginTags)
|
||||
.def("get_plugin_messages", &DatabaseInterface::GetPluginMessages)
|
||||
.def("get_plugin_cleanliness", &DatabaseInterface::GetPluginCleanliness)
|
||||
.def("write_minimal_list", &DatabaseInterface::WriteMinimalList);
|
||||
|
||||
module.def("is_compatible", &IsCompatible);
|
||||
|
||||
module.def("create_database", &CreateDatabase, arg("game"), arg("game_path") = emptyString, arg("game_local_path") = emptyString);
|
||||
|
||||
return module.ptr();
|
||||
class_<PluginMetadata>(module, "PluginMetadata", "Wraps :cpp:class:`loot::PluginMetadata`.")
|
||||
.def("get_simple_messages",
|
||||
&PluginMetadata::GetSimpleMessages,
|
||||
pybind11::call_guard<pybind11::gil_scoped_release>(),
|
||||
"Get the plugin's messages as SimpleMessage objects for the given language. Wraps :cpp:func:`GetSimpleMessages`.");
|
||||
}
|
||||
|
||||
void bindVersionClasses(pybind11::module& module) {
|
||||
// FIXME: For some reason the static properties have their docstrings ignored.
|
||||
class_<LootVersion>(module, "Version", "Wraps :cpp:class:`loot::LootVersion`.")
|
||||
.def_readonly_static("major", &LootVersion::major, "An unsigned integer giving the major version number. Read-only.")
|
||||
.def_readonly_static("minor", &LootVersion::minor, "An unsigned integer giving the minor version number. Read-only.")
|
||||
.def_readonly_static("patch", &LootVersion::patch, "An unsigned integer giving the patch version number. Read-only.")
|
||||
.def_readonly_static("revision", &LootVersion::revision, "A Unicode string containing the Git commit hash that the wrapped libloot was built from.")
|
||||
.def_static("string",
|
||||
LootVersion::GetVersionString,
|
||||
pybind11::call_guard<pybind11::gil_scoped_release>(),
|
||||
"Returns the libloot version as a string of the form ``major.minor.patch``.");
|
||||
|
||||
class_<WrapperVersion>(module, "WrapperVersion", "Provides information about the version of libloot-python that is being run.")
|
||||
.def_readonly_static("major", &WrapperVersion::major, "An unsigned integer giving the major version number. Read-only.")
|
||||
.def_readonly_static("minor", &WrapperVersion::minor, "An unsigned integer giving the minor version number. Read-only.")
|
||||
.def_readonly_static("patch", &WrapperVersion::patch, "An unsigned integer giving the patch version number. Read-only.")
|
||||
.def_readonly_static("revision", &WrapperVersion::revision, "A Unicode string containing the Git commit hash that the Python module was built from.")
|
||||
.def_static("string",
|
||||
WrapperVersion::string,
|
||||
pybind11::call_guard<pybind11::gil_scoped_release>(),
|
||||
"Returns the module version as a string of the form ``major.minor.patch``.");
|
||||
}
|
||||
|
||||
void bindInterfaceClasses(pybind11::module& module) {
|
||||
class_<GameInterface, std::shared_ptr<GameInterface>>(module, "GameInterface", "Wraps :cpp:class:`loot::GameInterface`.")
|
||||
.def("load_current_load_order_state",
|
||||
&GameInterface::LoadCurrentLoadOrderState,
|
||||
pybind11::call_guard<pybind11::gil_scoped_release>(),
|
||||
"Load the current load order state, discarding any previously held state. Wraps :cpp:func:`LoadCurrentLoadOrderState`.")
|
||||
.def("get_database",
|
||||
&GameInterface::GetDatabase,
|
||||
pybind11::call_guard<pybind11::gil_scoped_release>(),
|
||||
"Get a database handle. Wraps :cpp:func:`GetDatabase`.")
|
||||
.def("load_plugins",
|
||||
&GameInterface::LoadPlugins,
|
||||
pybind11::call_guard<pybind11::gil_scoped_release>(),
|
||||
"Load the given plugins. Wraps :cpp:func:`LoadPlugins`.")
|
||||
.def("get_plugin",
|
||||
&GameInterface::GetPlugin,
|
||||
pybind11::call_guard<pybind11::gil_scoped_release>(),
|
||||
"Get the given loaded plugin. Wraps :cpp:func:`GetPlugin`.");
|
||||
|
||||
class_<DatabaseInterface, std::shared_ptr<DatabaseInterface>>(module, "DatabaseInterface", "Wraps :cpp:class:`loot::DatabaseInterface`.")
|
||||
.def("load_lists",
|
||||
&py::LoadLists,
|
||||
arg("masterlist_path"),
|
||||
arg("userlist_path") = "",
|
||||
pybind11::call_guard<pybind11::gil_scoped_release>(),
|
||||
"Loads the masterlist and userlist from the paths specified. Wraps :cpp:func:`LoadLists`.")
|
||||
.def("update_masterlist",
|
||||
&py::UpdateMasterlist,
|
||||
pybind11::call_guard<pybind11::gil_scoped_release>(),
|
||||
"Updates the given masterlist using the given Git repository details. Wraps :cpp:func:`UpdateMasterlist`.")
|
||||
.def("get_masterlist_revision",
|
||||
&py::GetMasterlistRevision,
|
||||
pybind11::call_guard<pybind11::gil_scoped_release>(),
|
||||
"Gets the give masterlist's source control revision. Wraps :cpp:func:`GetMasterlistRevision`.")
|
||||
.def("get_plugin_metadata",
|
||||
&DatabaseInterface::GetPluginMetadata,
|
||||
arg("plugin"),
|
||||
arg("includeUserMetadata") = true,
|
||||
arg("evaluateConditions") = false,
|
||||
pybind11::call_guard<pybind11::gil_scoped_release>(),
|
||||
"Get all a plugin's loaded metadata. Wraps :cpp:func:`GetPluginMetadata`.")
|
||||
.def("get_plugin_tags",
|
||||
&GetPluginTags,
|
||||
arg("plugin"),
|
||||
arg("evaluateConditions") = false,
|
||||
pybind11::call_guard<pybind11::gil_scoped_release>(),
|
||||
"Outputs the Bash Tags suggested for addition and removal by the database for the given plugin.")
|
||||
.def("get_plugin_cleanliness",
|
||||
&GetPluginCleanliness,
|
||||
arg("plugin"),
|
||||
arg("evaluateConditions") = false,
|
||||
pybind11::call_guard<pybind11::gil_scoped_release>(),
|
||||
"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.")
|
||||
.def("write_minimal_list",
|
||||
&py::WriteMinimalList,
|
||||
pybind11::call_guard<pybind11::gil_scoped_release>(),
|
||||
"Writes a minimal metadata file containing only Bash Tag suggestions and/or cleanliness info from the loaded metadata. Wraps :cpp:func:`WriteMinimalList`.");
|
||||
|
||||
class_<PluginInterface, std::shared_ptr<PluginInterface>>(module, "PluginInterface")
|
||||
.def_property_readonly("name",
|
||||
&PluginInterface::GetName,
|
||||
pybind11::call_guard<pybind11::gil_scoped_release>(),
|
||||
"The plugin's name. Read-only. Wraps :cpp:func:`GetName`.")
|
||||
.def("is_master",
|
||||
&PluginInterface::IsMaster,
|
||||
pybind11::call_guard<pybind11::gil_scoped_release>(),
|
||||
"Check if the plugin is a master. Wraps :cpp:func:`IsMaster`.")
|
||||
.def("is_light_master",
|
||||
&PluginInterface::IsLightMaster,
|
||||
pybind11::call_guard<pybind11::gil_scoped_release>(),
|
||||
"Check if the plugin is a light master. Wraps :cpp:func:`IsLightMaster`.")
|
||||
.def("is_valid_as_light_master",
|
||||
&PluginInterface::IsValidAsLightMaster,
|
||||
pybind11::call_guard<pybind11::gil_scoped_release>(),
|
||||
"Check if the plugin contains only records with FormIDs that are valid in a light master. Wraps :cpp:func:`IsValidAsLightMaster`.");
|
||||
}
|
||||
|
||||
void bindClasses(pybind11::module& module) {
|
||||
bindMetadataClasses(module);
|
||||
bindVersionClasses(module);
|
||||
bindInterfaceClasses(module);
|
||||
}
|
||||
|
||||
void bindFunctions(pybind11::module& module) {
|
||||
module.def("set_logging_callback",
|
||||
&py::SetLoggingCallback,
|
||||
arg("callback"),
|
||||
"Set the callback function that is called when logging. Wraps :cpp:func:`loot::SetLoggingCallback`.");
|
||||
|
||||
// Need to clear the stored logging callback when exiting, or Python will
|
||||
// hang because the callback pointer is still stored by libloot.
|
||||
auto atexit = pybind11::module::import("atexit");
|
||||
atexit.attr("register")(pybind11::cpp_function([]() {
|
||||
SetLoggingCallback(nullptr);
|
||||
}));
|
||||
|
||||
module.def("is_compatible",
|
||||
&IsCompatible,
|
||||
pybind11::call_guard<pybind11::gil_scoped_release>(),
|
||||
"Checks for API compatibility. Wraps :cpp:func:`loot::IsCompatible`.");
|
||||
|
||||
module.def("create_game_handle",
|
||||
&py::CreateGameHandle,
|
||||
arg("game"),
|
||||
arg("game_path"),
|
||||
arg("game_local_path") = "",
|
||||
pybind11::call_guard<pybind11::gil_scoped_release>(),
|
||||
"Initialise a new game handle. Wraps :cpp:func:`loot::CreateGameHandle`.");
|
||||
}
|
||||
}
|
||||
|
||||
PYBIND11_MODULE(loot, module) {
|
||||
module.doc() = "A Python module that wraps libloot, generated by pybind11.";
|
||||
|
||||
loot::bindEnums(module);
|
||||
loot::bindClasses(module);
|
||||
loot::bindFunctions(module);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
/* LOOT
|
||||
|
||||
A load order optimisation tool for Oblivion, Skyrim, Fallout 3 and
|
||||
Fallout: New Vegas.
|
||||
|
||||
Copyright (C) 2012-2016 WrinklyNinja
|
||||
|
||||
This file is part of LOOT.
|
||||
|
||||
LOOT is free software: you can redistribute
|
||||
it and/or modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
LOOT is distributed in the hope that it will
|
||||
be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with LOOT. If not, see
|
||||
<https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef LIBLOOT_PYTHON_PLUGIN_CLEANLINESS
|
||||
#define LIBLOOT_PYTHON_PLUGIN_CLEANLINESS
|
||||
|
||||
/**
|
||||
* The namespace used by libloot.
|
||||
*/
|
||||
namespace loot {
|
||||
/**
|
||||
* @brief Codes used to indicate the cleanliness of a plugin according to the
|
||||
* information contained within the loaded masterlist/userlist.
|
||||
*/
|
||||
enum struct PluginCleanliness : unsigned int {
|
||||
/** Indicates that the plugin is clean. */
|
||||
clean,
|
||||
/** Indicates that the plugin is dirty. */
|
||||
dirty,
|
||||
/**
|
||||
* Indicates that the plugin contains dirty edits, but that they are
|
||||
* part of the plugin's intended functionality and should not be removed.
|
||||
*/
|
||||
do_not_clean,
|
||||
/**
|
||||
* Indicates that no data is available on whether the plugin is dirty or not.
|
||||
*/
|
||||
unknown,
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,58 @@
|
||||
/* LOOT
|
||||
|
||||
A load order optimisation tool for Oblivion, Skyrim, Fallout 3 and
|
||||
Fallout: New Vegas.
|
||||
|
||||
Copyright (C) 2012-2016 WrinklyNinja
|
||||
|
||||
This file is part of LOOT.
|
||||
|
||||
LOOT is free software: you can redistribute
|
||||
it and/or modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
LOOT is distributed in the hope that it will
|
||||
be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with LOOT. If not, see
|
||||
<https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef LIBLOOT_PYTHON_PLUGIN_TAGS
|
||||
#define LIBLOOT_PYTHON_PLUGIN_TAGS
|
||||
|
||||
#include <set>
|
||||
#include <string>
|
||||
|
||||
namespace loot {
|
||||
/**
|
||||
* @brief A structure that holds data about the Bash Tag suggestions made by
|
||||
* LOOT for a plugin.
|
||||
*/
|
||||
struct PluginTags {
|
||||
inline PluginTags() : userlist_modified(false) {}
|
||||
|
||||
/**
|
||||
* @brief A set of Bash Tag names suggested for addition to the specified
|
||||
* plugin. Empty if no Bash Tag additions are suggested.
|
||||
*/
|
||||
std::set<std::string> added;
|
||||
|
||||
/**
|
||||
* @brief A set of Bash Tag names suggested for removal from the specified
|
||||
* plugin. Empty if no Bash Tag removals are suggested.
|
||||
*/
|
||||
std::set<std::string> removed;
|
||||
|
||||
/**
|
||||
* @brief `true` if the Bash Tag suggestions were modified by data in the
|
||||
* userlist, `false` otherwise.
|
||||
*/
|
||||
bool userlist_modified;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
-118
@@ -1,118 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import cProfile
|
||||
import os.path
|
||||
import shutil
|
||||
import unittest
|
||||
from loot_api import Version
|
||||
from loot_api import WrapperVersion
|
||||
from loot_api import GameType
|
||||
from loot_api import LanguageCode
|
||||
from loot_api import Message
|
||||
from loot_api import MessageType
|
||||
from loot_api import create_database
|
||||
from loot_api import is_compatible
|
||||
|
||||
class GameFixture(unittest.TestCase):
|
||||
game_path = os.path.join(u'.', u'Oblivion')
|
||||
local_path = os.path.join(u'.', u'local')
|
||||
|
||||
def setUp(self):
|
||||
data_path = os.path.join(self.game_path, 'Data')
|
||||
master_file = os.path.join(data_path, 'Oblivion.esm')
|
||||
|
||||
os.makedirs(data_path)
|
||||
open(master_file, 'a').close()
|
||||
|
||||
os.makedirs(self.local_path)
|
||||
|
||||
def tearDown(self):
|
||||
shutil.rmtree(self.game_path)
|
||||
shutil.rmtree(self.local_path)
|
||||
|
||||
class TestLootApi(GameFixture):
|
||||
def test_is_compatible(self):
|
||||
self.assertFalse(is_compatible(0, 9, 0))
|
||||
self.assertTrue(is_compatible(0, 10, 0))
|
||||
|
||||
def test_version(self):
|
||||
self.assertEqual(Version.major, 0)
|
||||
self.assertEqual(Version.minor, 10)
|
||||
self.assertEqual(Version.patch, 2)
|
||||
self.assertNotEqual(Version.revision, u'')
|
||||
self.assertEqual(Version.string(), "0.10.2")
|
||||
|
||||
def test_wrapper_version(self):
|
||||
self.assertEqual(WrapperVersion.major, 1)
|
||||
self.assertEqual(WrapperVersion.minor, 2)
|
||||
self.assertEqual(WrapperVersion.patch, 0)
|
||||
self.assertNotEqual(WrapperVersion.revision, u'')
|
||||
self.assertNotEqual(WrapperVersion.revision, Version.revision)
|
||||
self.assertEqual(WrapperVersion.string(), "1.2.0")
|
||||
|
||||
def test_create_db(self):
|
||||
db = create_database(GameType.tes4, self.game_path, self.local_path)
|
||||
self.assertNotEqual(db, None)
|
||||
|
||||
class TestDatabaseInterface(GameFixture):
|
||||
masterlist_path = u'masterlist.yaml'
|
||||
|
||||
def setUp(self):
|
||||
super(TestDatabaseInterface, self).setUp()
|
||||
|
||||
self.db = create_database(GameType.tes4, self.game_path, self.local_path)
|
||||
|
||||
def test_load_lists(self):
|
||||
self.db.load_lists(self.masterlist_path, u'')
|
||||
|
||||
def test_get_plugin_tags(self):
|
||||
self.db.load_lists(self.masterlist_path, u'')
|
||||
tags = self.db.get_plugin_tags(u'Unofficial Oblivion Patch.esp')
|
||||
|
||||
self.assertNotEqual(tags, None)
|
||||
self.assertFalse(tags.userlist_modified)
|
||||
self.assertEqual(tags.added, set([
|
||||
u'Actors.ACBS',
|
||||
u'Actors.AIData',
|
||||
u'Actors.AIPackages',
|
||||
u'Actors.CombatStyle',
|
||||
u'Actors.DeathItem',
|
||||
u'Actors.Stats',
|
||||
u'C.Climate',
|
||||
u'C.Light',
|
||||
u'C.Music',
|
||||
u'C.Name',
|
||||
u'C.Owner',
|
||||
u'Creatures.Blood',
|
||||
u'Delev',
|
||||
u'Factions',
|
||||
u'Invent',
|
||||
u'Names',
|
||||
u'NPC.Class',
|
||||
u'Relations',
|
||||
u'Relev',
|
||||
u'Scripts',
|
||||
u'Stats'
|
||||
]))
|
||||
self.assertEqual(tags.removed, set([u'C.Water']))
|
||||
|
||||
# cProfile.runctx('self.test_get_plugin_tags_performance()', globals(), locals(), sort='cumtime')
|
||||
|
||||
# def test_get_plugin_tags_performance(self):
|
||||
# self.db.load_lists(self.masterlist_path, u'')
|
||||
#
|
||||
# for i in xrange(200000):
|
||||
# tags = self.db.get_plugin_tags(u'Unofficial Oblivion Patch.esp')
|
||||
|
||||
def test_get_plugin_messages(self):
|
||||
self.db.load_lists(self.masterlist_path, u'')
|
||||
|
||||
messages = self.db.get_plugin_messages(u'Oblivion.esm', LanguageCode.english)
|
||||
|
||||
self.assertEqual(len(messages), 1)
|
||||
self.assertEqual(messages[0].type, MessageType.error)
|
||||
self.assertEqual(messages[0].text, u'This must not be activated. However, it can be useful when porting Oblivion mods to Nehrim.')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -25,9 +25,9 @@
|
||||
#include "wrapper_version.h"
|
||||
|
||||
namespace loot {
|
||||
const unsigned int WrapperVersion::major = 1;
|
||||
const unsigned int WrapperVersion::minor = 2;
|
||||
const unsigned int WrapperVersion::patch = 0;
|
||||
const unsigned int WrapperVersion::major = @LIBLOOT_PY_VERSION_MAJOR@;
|
||||
const unsigned int WrapperVersion::minor = @LIBLOOT_PY_VERSION_MINOR@;
|
||||
const unsigned int WrapperVersion::patch = @LIBLOOT_PY_VERSION_PATCH@;
|
||||
const std::string WrapperVersion::revision = "@GIT_COMMIT_STRING@";
|
||||
|
||||
std::string WrapperVersion::string() {
|
||||
|
||||
@@ -22,8 +22,8 @@ along with LOOT. If not, see
|
||||
<https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef LOOT_API_PYTHON_WRAPPER_VERSION
|
||||
#define LOOT_API_PYTHON_WRAPPER_VERSION
|
||||
#ifndef LIBLOOT_PYTHON_WRAPPER_VERSION
|
||||
#define LIBLOOT_PYTHON_WRAPPER_VERSION
|
||||
|
||||
#include <string>
|
||||
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
plugins:
|
||||
- name: Oblivion.esm
|
||||
msg:
|
||||
- type: error
|
||||
content: 'This must not be activated. However, it can be useful when porting Oblivion mods to Nehrim.'
|
||||
|
||||
- name: Unofficial Oblivion Patch.esp
|
||||
tag:
|
||||
- Actors.ACBS
|
||||
- Actors.AIData
|
||||
- Actors.AIPackages
|
||||
- Actors.CombatStyle
|
||||
- Actors.DeathItem
|
||||
- Actors.Stats
|
||||
- C.Climate
|
||||
- C.Light
|
||||
- C.Music
|
||||
- C.Name
|
||||
- C.Owner
|
||||
- Creatures.Blood
|
||||
- Delev
|
||||
- Factions
|
||||
- Invent
|
||||
- Names
|
||||
- NPC.Class
|
||||
- Relations
|
||||
- Relev
|
||||
- Scripts
|
||||
- Stats
|
||||
- -C.Water
|
||||
|
||||
- name: clean_and_dirty.esp
|
||||
dirty:
|
||||
- crc: 0xDEADBEEF
|
||||
util: '[TES4Edit v4.0.0](https://www.nexusmods.com/oblivion/mods/11536)'
|
||||
clean:
|
||||
- crc: 0xFEEDFACE
|
||||
util: 'TES4Edit v4.0.0'
|
||||
|
||||
- name: clean.esp
|
||||
clean:
|
||||
- crc: 0xFEEDFACE
|
||||
util: 'TES4Edit v4.0.0'
|
||||
|
||||
- name: dirty.esp
|
||||
dirty:
|
||||
- crc: 0xDEADBEEF
|
||||
util: '[TES4Edit v4.0.0](https://www.nexusmods.com/oblivion/mods/11536)'
|
||||
|
||||
- name: do_not_clean.esp
|
||||
dirty:
|
||||
- crc: 0xDEADBEEF
|
||||
util: '[TES4Edit v4.0.0](https://www.nexusmods.com/oblivion/mods/11536)'
|
||||
info: 'Do not clean. This plugin is intentionally left dirty.'
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user