From 01a8567ed850cedda0f9930c52701bd8bc6ecb7d Mon Sep 17 00:00:00 2001 From: Oliver Hamlet Date: Sat, 4 Jan 2020 14:59:13 +0000 Subject: [PATCH] Move most reference docs into source as docstrings It's easier to maintain, though there seems to be a bug in pybind11, as it doesn't use the docstrings I've provided for some static read-only properties, so Version and WrapperVersion are still documented separately. It's not related, but I've noticed that for some reason intersphinx is unable to turn :cpp: domain references into hyperlinks, but no related information is logged to say why. --- docs/conf.py | 6 +- docs/reference.rst | 198 ++------------------------------------------- src/main.cpp | 135 ++++++++++++++++++------------- 3 files changed, 92 insertions(+), 247 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index f473a66..cd27c13 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -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', ] @@ -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.14.7/', None), + 'loot': ('https://loot.readthedocs.io/en/0.15.0/', None), + 'python': ('https://docs.python.org/3', None) } diff --git a/docs/reference.rst b/docs/reference.rst index c27960c..5e1f6ca 100644 --- a/docs/reference.rst +++ b/docs/reference.rst @@ -5,188 +5,13 @@ API Reference 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.GameType - - Wraps :cpp:type:`loot::GameType` to expose libloot's game codes. - - .. py:attribute:: fo3 - .. py:attribute:: fo4 - .. py:attribute:: fonv - .. py:attribute:: tes4 - .. py:attribute:: tes5 - .. py:attribute:: tes5se - -.. py:class:: loot.LogLevel - - Wraps :cpp:type:`loot::LogLevel` to expose libloot's log level codes. - - .. py:attribute:: trace - .. py:attribute:: debug - .. py:attribute:: info - .. py:attribute:: warning - .. py:attribute:: error - .. py:attribute:: fatal - -.. py:class:: loot.MessageType - - Wraps :cpp:type:`loot::MessageType` to expose libloot's message type - codes. - - .. py:attribute:: error - .. py:attribute:: say - .. py:attribute:: warn - -.. py:class:: loot.PluginCleanliness - - 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 -============================ - -Classes with public fields and no member functions. - -.. py:class:: loot.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.SimpleMessage - - Wraps :cpp:class:`loot::SimpleMessage`. - - .. py:attribute:: type - - A :py:class:`loot.MessageType` giving the message type. - - .. py:attribute:: 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.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.set_logging_callback(callback) -> NoneType - - Set the callback function that is called when logging. Wraps - :cpp:func:`loot::SetLoggingCallback`. - -.. py:function:: loot.is_compatible(int, int, int) -> bool - - Checks for API compatibility. Wraps :cpp:func:`loot::IsCompatible`. - -.. py:function:: loot.create_game_handle(game : loot.GameType, game_path : unicode, [game_local_path : unicode = u'']) -> loot.GameInterface - - Initialise a new game handle. Wraps :cpp:func:`loot::CreateGameHandle`. - -Classes -======= - -.. py:class:: loot.GameInterface - - Wraps :cpp:class:`loot::GameInterface`. - - .. py:function:: loot.get_database() -> loot.DatabaseInterface - - Get a database handle. Wraps :cpp:func:`loot::GetDatabase`. - - .. py:function:: loot.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.DatabaseInterface - - Wraps :cpp:class:`loot::DatabaseInterface`. - - .. py:method:: get_masterlist_revision(loot.DatabaseInterface, unicode, bool) -> loot.MasterlistInfo - - Gets the give masterlist’s source control revision. Wraps :cpp:func:`GetMasterlistRevision`. - - .. py:method:: get_plugin_metadata(loot.DatabaseInterface, plugin : unicode, [includeUserMetadata : bool = True, [evaluateConditions : bool = False]]) -> loot.PluginMetadata - - Get all a plugin’s loaded metadata. Wraps :cpp:func:`GetPluginMetadata`. - - .. py:method:: get_plugin_cleanliness(loot.DatabaseInterface, plugin : unicode, [evaluateConditions : bool = False]) -> loot.PluginCleanliness - - 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.DatabaseInterface, plugin : unicode, [evaluateConditions : bool = False]) -> loot.PluginTags - - Outputs the Bash Tags suggested for addition and removal by the database for the given plugin. - - .. py:method:: load_lists(loot.DatabaseInterface, masterlist_path : unicode, [userlist_path : unicode = u'']) -> NoneType - - Loads the masterlist and userlist from the paths specified. Wraps :cpp:func:`LoadLists`. - - .. py:method:: update_masterlist(loot.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.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`. +.. automodule:: loot + :members: + :exclude-members: Version, WrapperVersion .. py:class:: loot.Version @@ -208,7 +33,7 @@ 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`` @@ -232,15 +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`` - -.. py:class:: loot.PluginMetadata - - Wraps :cpp:class:`loot::PluginMetadata`. - - .. py:method:: get_simple_messages(loot.PluginMetadata, unicode) -> list - - Get the plugin’s messages as SimpleMessage objects for the given language. - Wraps :cpp:func:`GetPluginMessages`. diff --git a/src/main.cpp b/src/main.cpp index 6645215..4b0aadb 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -69,7 +69,10 @@ void SetLoggingCallback(std::function callback) { } void bindEnums(pybind11::module& module) { - enum_(module, "GameType") + pybind11::options options; + options.disable_function_signatures(); + + enum_(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) @@ -79,7 +82,7 @@ void bindEnums(pybind11::module& module) { .value("fo4", GameType::fo4) .value("fo4vr", GameType::fo4vr); - enum_(module, "LogLevel") + enum_(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) @@ -87,121 +90,140 @@ void bindEnums(pybind11::module& module) { .value("error", LogLevel::error) .value("fatal", LogLevel::fatal); - enum_(module, "MessageType") + enum_(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_(module, "PluginCleanliness") - .value("clean", PluginCleanliness::clean) - .value("dirty", PluginCleanliness::dirty) - .value("do_not_clean", PluginCleanliness::do_not_clean) - .value("unknown", PluginCleanliness::unknown); + enum_(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."); } void bindMetadataClasses(pybind11::module& module) { - class_(module, "MasterlistInfo") - .def_readwrite("revision_id", &MasterlistInfo::revision_id) - .def_readwrite("revision_date", &MasterlistInfo::revision_date) - .def_readwrite("is_modified", &MasterlistInfo::is_modified); + class_(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_(module, "SimpleMessage") - .def_readwrite("type", &SimpleMessage::type) - .def_readwrite("language", &SimpleMessage::language) - .def_readwrite("text", &SimpleMessage::text) - .def_readwrite("condition", &SimpleMessage::condition); + class_(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_(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_(module, "PluginMetadata") + class_(module, "PluginMetadata", "Wraps :cpp:class:`loot::PluginMetadata`.") .def("get_simple_messages", &PluginMetadata::GetSimpleMessages, - pybind11::call_guard()); + pybind11::call_guard(), + "Get the plugin's messages as SimpleMessage objects for the given language. Wraps :cpp:func:`GetSimpleMessages`."); } void bindVersionClasses(pybind11::module& module) { - class_(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) + // FIXME: For some reason the static properties have their docstrings ignored. + class_(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::call_guard(), + "Returns the libloot version as a string of the form ``major.minor.patch``."); - class_(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) + class_(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::call_guard(), + "Returns the module version as a string of the form ``major.minor.patch``."); } void bindInterfaceClasses(pybind11::module& module) { - class_>(module, "GameInterface") + class_>(module, "GameInterface", "Wraps :cpp:class:`loot::GameInterface`.") .def("load_current_load_order_state", &GameInterface::LoadCurrentLoadOrderState, - pybind11::call_guard()) + pybind11::call_guard(), + "Load the current load order state, discarding any previously held state. Wraps :cpp:func:`LoadCurrentLoadOrderState`.") .def("get_database", &GameInterface::GetDatabase, - pybind11::call_guard()) + pybind11::call_guard(), + "Get a database handle. Wraps :cpp:func:`GetDatabase`.") .def("load_plugins", &GameInterface::LoadPlugins, - pybind11::call_guard()) + pybind11::call_guard(), + "Load the given plugins. Wraps :cpp:func:`LoadPlugins`.") .def("get_plugin", &GameInterface::GetPlugin, - pybind11::call_guard()); + pybind11::call_guard(), + "Get the given loaded plugin. Wraps :cpp:func:`GetPlugin`."); - class_>(module, "DatabaseInterface") + class_>(module, "DatabaseInterface", "Wraps :cpp:class:`loot::DatabaseInterface`.") .def("load_lists", &py::LoadLists, arg("masterlist_path"), arg("userlist_path") = "", - pybind11::call_guard()) + pybind11::call_guard(), + "Loads the masterlist and userlist from the paths specified. Wraps :cpp:func:`LoadLists`.") .def("update_masterlist", &py::UpdateMasterlist, - pybind11::call_guard()) + pybind11::call_guard(), + "Updates the given masterlist using the given Git repository details. Wraps :cpp:func:`UpdateMasterlist`.") .def("get_masterlist_revision", &py::GetMasterlistRevision, - pybind11::call_guard()) + pybind11::call_guard(), + "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::call_guard(), + "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::call_guard(), + "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::call_guard(), + "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::call_guard(), + "Writes a minimal metadata file containing only Bash Tag suggestions and/or cleanliness info from the loaded metadata. Wraps :cpp:func:`WriteMinimalList`."); class_>(module, "PluginInterface") .def_property_readonly("name", &PluginInterface::GetName, - pybind11::call_guard()) + pybind11::call_guard(), + "The plugin's name. Read-only. Wraps :cpp:func:`GetName`.") .def("is_master", &PluginInterface::IsMaster, - pybind11::call_guard()) + pybind11::call_guard(), + "Check if the plugin is a master. Wraps :cpp:func:`IsMaster`.") .def("is_light_master", &PluginInterface::IsLightMaster, - pybind11::call_guard()) + pybind11::call_guard(), + "Check if the plugin is a light master. Wraps :cpp:func:`IsLightMaster`.") .def("is_valid_as_light_master", &PluginInterface::IsValidAsLightMaster, - pybind11::call_guard()); + pybind11::call_guard(), + "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) { @@ -211,7 +233,10 @@ void bindClasses(pybind11::module& module) { } void bindFunctions(pybind11::module& module) { - module.def("set_logging_callback", &py::SetLoggingCallback); + 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. @@ -222,14 +247,16 @@ void bindFunctions(pybind11::module& module) { module.def("is_compatible", &IsCompatible, - pybind11::call_guard()); + pybind11::call_guard(), + "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::call_guard(), + "Initialise a new game handle. Wraps :cpp:func:`loot::CreateGameHandle`."); } }