diff --git a/source/PyMaterialX/PyMaterialXFormat/PyFile.cpp b/source/PyMaterialX/PyMaterialXFormat/PyFile.cpp index c451037566..5e2b8ca1a4 100644 --- a/source/PyMaterialX/PyMaterialXFormat/PyFile.cpp +++ b/source/PyMaterialX/PyMaterialXFormat/PyFile.cpp @@ -12,13 +12,21 @@ namespace mx = MaterialX; void bindPyFile(py::module& mod) { - py::enum_(mod, "Type") + py::enum_(mod, "Type", R"docstring( + Enumeration of `FilePath` types. + + :see: https://materialx.org/docs/api/class_file_path.html#pub-types +)docstring") .value("TypeRelative", mx::FilePath::Type::TypeRelative) .value("TypeAbsolute", mx::FilePath::Type::TypeAbsolute) .value("TypeNetwork", mx::FilePath::Type::TypeNetwork) .export_values(); - py::enum_(mod, "Format") + py::enum_(mod, "Format", R"docstring( + Enumeration of `FilePath` formats. + + :see: https://materialx.org/docs/api/class_file_path.html#pub-types +)docstring") .value("FormatWindows", mx::FilePath::Format::FormatWindows) .value("FormatPosix", mx::FilePath::Format::FormatPosix) .value("FormatNative", mx::FilePath::Format::FormatNative) @@ -47,7 +55,13 @@ void bindPyFile(py::module& mod) .def("getSubDirectories", &mx::FilePath::getSubDirectories) .def("createDirectory", &mx::FilePath::createDirectory) .def_static("getCurrentPath", &mx::FilePath::getCurrentPath) - .def_static("getModulePath", &mx::FilePath::getModulePath); + .def_static("getModulePath", &mx::FilePath::getModulePath) + .doc() = R"docstring( + Class representing a generic file path, supporting both syntactic and file + system operations. + + :see: https://materialx.org/docs/api/class_file_path.html +)docstring"; py::class_(mod, "FileSearchPath") .def(py::init<>()) @@ -61,7 +75,14 @@ void bindPyFile(py::module& mod) .def("clear", &mx::FileSearchPath::clear) .def("size", &mx::FileSearchPath::size) .def("isEmpty", &mx::FileSearchPath::isEmpty) - .def("find", &mx::FileSearchPath::find); + .def("find", &mx::FileSearchPath::find) + .doc() = R"docstring( + Class representing a sequence of file paths, which may be queried to find + the first instance of a given filename on the file system. + + :see: https://materialx.org/docs/api/class_file_search_path.html +)docstring"; + ; py::implicitly_convertible(); py::implicitly_convertible(); diff --git a/source/PyMaterialX/PyMaterialXFormat/PyModule.cpp b/source/PyMaterialX/PyMaterialXFormat/PyModule.cpp index d75164f343..1264d14517 100644 --- a/source/PyMaterialX/PyMaterialXFormat/PyModule.cpp +++ b/source/PyMaterialX/PyMaterialXFormat/PyModule.cpp @@ -13,7 +13,50 @@ void bindPyUtil(py::module& mod); PYBIND11_MODULE(PyMaterialXFormat, mod) { - mod.doc() = "Cross-platform support for working with files, paths, and environment variables"; + mod.doc() = R"docstring( + Cross-platform support for file and search paths, and XML serialization. + + File and Search Paths + --------------------- + + .. autofunction:: flattenFilenames + .. autofunction:: getEnvironmentPath + .. autofunction:: getSourceSearchPath + .. autofunction:: getSubdirectories + .. autofunction:: loadDocuments + .. autofunction:: loadLibraries + .. autofunction:: loadLibrary + .. autofunction:: prependXInclude + + **Classes and Enumerations** + + .. autosummary:: + :toctree: file-and-search-paths + + FilePath + FileSearchPath + Format + Type + + XML Serialization + ----------------- + + .. autofunction:: readFile + .. autofunction:: readFromXmlFile + .. autofunction:: readFromXmlString + .. autofunction:: writeToXmlFile + .. autofunction:: writeToXmlString + + **Classes and Exceptions** + + .. autosummary:: + :toctree: xml-serialization + + XmlReadOptions + XmlWriteOptions + ExceptionParseError + ExceptionFileMissing +)docstring"; // PyMaterialXFormat depends on types defined in PyMaterialXCore pybind11::module::import("PyMaterialXCore"); diff --git a/source/PyMaterialX/PyMaterialXFormat/PyUtil.cpp b/source/PyMaterialX/PyMaterialXFormat/PyUtil.cpp index dcd78bbcb5..2980459d58 100644 --- a/source/PyMaterialX/PyMaterialXFormat/PyUtil.cpp +++ b/source/PyMaterialX/PyMaterialXFormat/PyUtil.cpp @@ -14,16 +14,77 @@ namespace mx = MaterialX; void bindPyUtil(py::module& mod) { - mod.def("readFile", &mx::readFile); - mod.def("getSubdirectories", &mx::getSubdirectories); + mod.def("readFile", &mx::readFile, + py::arg("path"), + R"docstring( + Read the file with the given `path`, and return its contents. + + :param path: The path of the file to read. + :type path: FilePath | str + :return: The contents of the specified file, or an empty string if the file + could not be read. +)docstring"); + + mod.def("getSubdirectories", &mx::getSubdirectories, + py::arg("rootDirectories"), + py::arg("searchPath"), + py::arg("subDirectories"), + R"docstring( + Get all subdirectories for a given set of directories and search paths. +)docstring"); + mod.def("loadDocuments", &mx::loadDocuments, - py::arg("rootPath"), py::arg("searchPath"), py::arg("skipFiles"), py::arg("includeFiles"), py::arg("documents"), py::arg("documentsPaths"), - py::arg("readOptions") = (mx::XmlReadOptions*) nullptr, py::arg("errors") = (mx::StringVec*) nullptr); + py::arg("rootPath"), + py::arg("searchPath"), + py::arg("skipFiles"), + py::arg("includeFiles"), + py::arg("documents"), + py::arg("documentsPaths"), + py::arg("readOptions") = (mx::XmlReadOptions*) nullptr, + py::arg("errors") = (mx::StringVec*) nullptr, + R"docstring( + Scan for all documents under the given `rootPath` and return documents + which can be loaded. +)docstring"); + mod.def("loadLibrary", &mx::loadLibrary, - py::arg("file"), py::arg("doc"), py::arg("searchPath") = mx::FileSearchPath(), py::arg("readOptions") = (mx::XmlReadOptions*) nullptr); + py::arg("path"), + py::arg("doc"), + py::arg("searchPath") = mx::FileSearchPath(), + py::arg("readOptions") = (mx::XmlReadOptions*) nullptr, + R"docstring( + Load a MaterialX library specified by the given `path` into the given + document. +)docstring"); + mod.def("loadLibraries", &mx::loadLibraries, - py::arg("libraryFolders"), py::arg("searchPath"), py::arg("doc"), py::arg("excludeFiles") = mx::StringSet(), py::arg("readOptions") = (mx::XmlReadOptions*) nullptr); + py::arg("libraryFolders"), + py::arg("searchPath"), + py::arg("doc"), + py::arg("excludeFiles") = mx::StringSet(), + py::arg("readOptions") = (mx::XmlReadOptions*) nullptr, + R"docstring( + Load all MaterialX files within the given library folders into a document, + using the given search path to locate the folders on the file system. +)docstring"); + mod.def("flattenFilenames", &mx::flattenFilenames, - py::arg("doc"), py::arg("searchPath") = mx::FileSearchPath(), py::arg("customResolver") = (mx::StringResolverPtr) nullptr); - mod.def("getSourceSearchPath", &mx::getSourceSearchPath); + py::arg("doc"), + py::arg("searchPath") = mx::FileSearchPath(), + py::arg("customResolver") = (mx::StringResolverPtr) nullptr, + R"docstring( + Flatten all filenames in the given document, applying string resolvers at + the scope of each element and removing all fileprefix attributes. + + :param doc: The document to modify. + :param searchPath: An optional search path for relative to absolute path conversion. + :param customResolver: An optional custom resolver to apply. +)docstring"); + + mod.def("getSourceSearchPath", &mx::getSourceSearchPath, + py::arg("doc"), + R"docstring( + Return a file search path containing the parent folder of each source URI + in the given document. +)docstring"); } diff --git a/source/PyMaterialX/PyMaterialXFormat/PyXmlIo.cpp b/source/PyMaterialX/PyMaterialXFormat/PyXmlIo.cpp index 9b4b32cf6a..232de05d06 100644 --- a/source/PyMaterialX/PyMaterialXFormat/PyXmlIo.cpp +++ b/source/PyMaterialX/PyMaterialXFormat/PyXmlIo.cpp @@ -19,29 +19,137 @@ void bindPyXmlIo(py::module& mod) .def_readwrite("readComments", &mx::XmlReadOptions::readComments) .def_readwrite("readNewlines", &mx::XmlReadOptions::readNewlines) .def_readwrite("upgradeVersion", &mx::XmlReadOptions::upgradeVersion) - .def_readwrite("parentXIncludes", &mx::XmlReadOptions::parentXIncludes); + .def_readwrite("parentXIncludes", &mx::XmlReadOptions::parentXIncludes) + .doc() = R"docstring( + Class providing a set of options for controlling the behavior of XML read + functions. + + :see: https://materialx.org/docs/api/class_xml_read_options.html +)docstring"; py::class_(mod, "XmlWriteOptions") .def(py::init()) .def_readwrite("writeXIncludeEnable", &mx::XmlWriteOptions::writeXIncludeEnable) - .def_readwrite("elementPredicate", &mx::XmlWriteOptions::elementPredicate); + .def_readwrite("elementPredicate", &mx::XmlWriteOptions::elementPredicate) + .doc() = R"docstring( + Class providing a set of options for controlling the behavior of XML write + functions. + + :see: https://materialx.org/docs/api/class_xml_write_options.html +)docstring"; + + mod.def("readFromXmlFile", &mx::readFromXmlFile, + py::arg("doc"), + py::arg("filename"), + py::arg("searchPath") = mx::FileSearchPath(), + py::arg("readOptions") = (mx::XmlReadOptions*) nullptr, + R"docstring( + Read a `Document` as XML from the given filename. + + :param doc: The `Document` into which data is read. + :type doc: Document + :param filename: The filename from which data is read. + :type filename: FilePath | str + :param searchPath: An optional sequence of file paths that will be applied + in order when searching for the given file and its includes. If given + as a `str`, is expected to contain paths separated by the + `PATH_SEPARATOR` character. + :type searchPath: FileSearchPath | str + :param readOptions: An optional `XmlReadOptions` object to affect the + behavior of the read function. + :type readOptions: XmlReadOptions + :raises ExceptionParseError: If the document cannot be parsed. + :raises ExceptionFileMissing: If the file cannot be opened. +)docstring"); - mod.def("readFromXmlFileBase", &mx::readFromXmlFile, - py::arg("doc"), py::arg("filename"), py::arg("searchPath") = mx::FileSearchPath(), py::arg("readOptions") = (mx::XmlReadOptions*) nullptr); mod.def("readFromXmlString", &mx::readFromXmlString, - py::arg("doc"), py::arg("str"), py::arg("searchPath") = mx::FileSearchPath(), py::arg("readOptions") = (mx::XmlReadOptions*) nullptr); + py::arg("doc"), + py::arg("string"), + py::arg("searchPath") = mx::FileSearchPath(), + py::arg("readOptions") = (mx::XmlReadOptions*) nullptr, + R"docstring( + Read a `Document` as XML from the given string. + + :param doc: The `Document` into which data is read. + :type doc: Document + :param string: The string from which data is read. + :type string: str + :param searchPath: An optional sequence of file paths that will be applied + in order when searching for the given file and its includes. If given + as a `str`, is expected to contain paths separated by the + `PATH_SEPARATOR` character. + :type searchPath: FileSearchPath | str + :param readOptions: An optional `XmlReadOptions` object to affect the + behavior of the read function. + :type readOptions: XmlReadOptions + :raises ExceptionParseError: If the document cannot be parsed. +)docstring"); + mod.def("writeToXmlFile", mx::writeToXmlFile, - py::arg("doc"), py::arg("filename"), py::arg("writeOptions") = (mx::XmlWriteOptions*) nullptr); + py::arg("doc"), + py::arg("filename"), + py::arg("writeOptions") = (mx::XmlWriteOptions*) nullptr, + R"docstring( + Write a `Document` as XML to the given filename. + + :param doc: The `Document` to write. + :type doc: Document + :param filename: The filename to which data is written. + :type filename: FilePath | str + :param writeOptions: An optional `XmlWriteOptions` object to affect the + behavior of the write function. + :type writeOptions: XmlWriteOptions, optional +)docstring"); + mod.def("writeToXmlString", mx::writeToXmlString, - py::arg("doc"), py::arg("writeOptions") = nullptr); - mod.def("prependXInclude", mx::prependXInclude); + py::arg("doc"), + py::arg("writeOptions") = nullptr, + R"docstring( + Write a `Document` as XML to a string and return it. + + :param doc: The `Document` to write. + :type doc: Document + :param writeOptions: An optional `XmlWriteOptions` object to affect the + behavior of the write function. + :type writeOptions: XmlWriteOptions, optional + :return: The output string. +)docstring"); + + mod.def("prependXInclude", mx::prependXInclude, + py::arg("doc"), + py::arg("filename"), + R"docstring( + Add an `XInclude` reference to the top of the given `Document`, creating a + `GenericElement` to hold the reference filename. + + :param doc: The `Document` to be modified. + :type doc: Document + :param filename: The filename of the `XInclude` reference to be added. + :type filename: FilePath +)docstring"); mod.def("getEnvironmentPath", &mx::getEnvironmentPath, - py::arg("sep") = mx::PATH_LIST_SEPARATOR); + py::arg("sep") = mx::PATH_LIST_SEPARATOR, + R"docstring( + Return a `FileSearchPath` object from the search path environment variable + `MATERIALX_SEARCH_PATH`. +)docstring"); mod.attr("PATH_LIST_SEPARATOR") = mx::PATH_LIST_SEPARATOR; mod.attr("MATERIALX_SEARCH_PATH_ENV_VAR") = mx::MATERIALX_SEARCH_PATH_ENV_VAR; - py::register_exception(mod, "ExceptionParseError"); - py::register_exception(mod, "ExceptionFileMissing"); + py::register_exception(mod, "ExceptionParseError") + .doc() = R"docstring( + A type of exception that is raised when a requested document cannot be + parsed. + + :see: https://materialx.org/docs/api/class_exception_parse_error.html +)docstring"; + + py::register_exception(mod, "ExceptionFileMissing") + .doc() = R"docstring( + A type of exception that is raised when a requested file cannot be opened. + + :see: https://materialx.org/docs/api/class_exception_file_missing.html +)docstring"; }