6 Commits
Author SHA1 Message Date
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
7 changed files with 143 additions and 91 deletions
+10 -4
View File
@@ -30,9 +30,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.1")
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,10 +49,15 @@ add_subdirectory(${PYBIND11_EXTRACTED_PATH})
# LOOT API
#######################################
if (CMAKE_SYSTEM_NAME MATCHES "Windows")
set(LOOT_API_URL "https://github.com/loot/loot-api/releases/download/0.12.0/loot_api-0.12.0-0-g42cacca_dev-win32.7z")
else()
set(LOOT_API_URL "https://github.com/loot/loot-api/releases/download/0.12.0/loot-api.tar.xz")
endif()
ExternalProject_Add(loot-api-c++
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 ${LOOT_API_URL}
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
INSTALL_COMMAND "")
+71 -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,64 @@ 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) -> NoneType
Initialise a new database handle. Wraps :cpp:func:`loot::IsCompatible`.
Initialise the current global locale using the given ID. Wraps
:cpp:func:`loot::InitialiseLocale`.
.. py:function:: loot_api.create_game_handle(game : loot_api.GameType, [game_path : unicode = u'', [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 +241,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`.
+5 -10
View File
@@ -27,15 +27,10 @@ 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);
auto metadata = db->GetPluginMetadata(plugin, false, evaluateConditions);
for (const auto &tag : metadata.GetTags()) {
if (tag.IsAddition())
tags.added.insert(tag.GetName());
@@ -43,7 +38,7 @@ PluginTags GetPluginTags(const std::shared_ptr<DatabaseInterface> db, const std:
tags.removed.insert(tag.GetName());
}
metadata = db->GetPluginUserMetadata(plugin, false);
metadata = db->GetPluginUserMetadata(plugin, evaluateConditions);
tags.userlist_modified = !metadata.GetTags().empty();
for (const auto &tag : metadata.GetTags()) {
if (tag.IsAddition())
@@ -55,8 +50,8 @@ PluginTags GetPluginTags(const std::shared_ptr<DatabaseInterface> db, const std:
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()) {
+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
+32 -21
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"
@@ -44,10 +45,13 @@ void bindEnums(pybind11::module& module) {
.value("fonv", GameType::fonv)
.value("fo4", GameType::fo4);
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 +74,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 +87,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);
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,17 +103,24 @@ 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("get_plugin_metadata", &DatabaseInterface::GetPluginMetadata,
arg("plugin"),
arg("includeUserMetadata") = true,
arg("evaluateConditions") = false)
.def("get_plugin_tags", &GetPluginTags)
.def("get_plugin_cleanliness", &GetPluginCleanliness)
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", &DatabaseInterface::WriteMinimalList);
}
@@ -119,24 +131,23 @@ 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("create_database", &CreateDatabase, arg("game"), arg("game_path") = "", arg("game_local_path") = "");
module.def("create_game_handle", &CreateGameHandle,
arg("game"),
arg("game_path") = "",
arg("game_local_path") = "");
}
}
PYBIND11_PLUGIN(loot_api) {
pybind11::module module("loot_api", "A Python module that wraps the LOOT API, generated by pybind11.");
PYBIND11_MODULE(loot_api, module) {
module.doc() = "A Python module that wraps the LOOT API, generated by pybind11.";
loot::bindEnums(module);
loot::bindClasses(module);
loot::bindFunctions(module);
return module.ptr();
}
+17 -11
View File
@@ -7,15 +7,17 @@ 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)
def logging_callback(level, message):
pass
set_logging_callback(logging_callback)
initialise_locale("")
class GameFixture(unittest.TestCase):
@@ -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, 12, 0))
def test_version(self):
self.assertEqual(Version.major, 0)
self.assertEqual(Version.minor, 11)
self.assertEqual(Version.minor, 12)
self.assertEqual(Version.patch, 0)
self.assertNotEqual(Version.revision, u'')
self.assertEqual(Version.string(), "0.11.0")
self.assertEqual(Version.string(), "0.12.0")
def test_wrapper_version(self):
self.assertEqual(WrapperVersion.major, 2)
self.assertEqual(WrapperVersion.major, 3)
self.assertEqual(WrapperVersion.minor, 0)
self.assertEqual(WrapperVersion.patch, 0)
self.assertNotEqual(WrapperVersion.revision, u'')
self.assertNotEqual(WrapperVersion.revision, Version.revision)
self.assertEqual(WrapperVersion.string(), "2.0.0")
self.assertEqual(WrapperVersion.string(), "3.0.0")
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'')
+1 -1
View File
@@ -25,7 +25,7 @@
#include "wrapper_version.h"
namespace loot {
const unsigned int WrapperVersion::major = 2;
const unsigned int WrapperVersion::major = 3;
const unsigned int WrapperVersion::minor = 0;
const unsigned int WrapperVersion::patch = 0;
const std::string WrapperVersion::revision = "@GIT_COMMIT_STRING@";