Core: Add additional Python bindings for Metadata

This commit is contained in:
Chris Hennes
2022-02-10 15:25:07 -06:00
parent 1fecd4fb33
commit e8699b1c45
2 changed files with 258 additions and 154 deletions

View File

@@ -1,162 +1,195 @@
<?xml version="1.0" encoding="UTF-8"?>
<GenerateModel xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="generateMetaModel_Module.xsd">
<PythonExport
Father="PyObjectBase"
Name="MetadataPy"
Twin="Metadata"
TwinPointer="Metadata"
Include="App/Metadata.h"
FatherInclude="Base/PyObjectBase.h"
Namespace="App"
Constructor="true"
Delete="true"
NumberProtocol="false"
RichCompare="false"
FatherNamespace="Base">
<PythonExport
Father="PyObjectBase"
Name="MetadataPy"
Twin="Metadata"
TwinPointer="Metadata"
Include="App/Metadata.h"
FatherInclude="Base/PyObjectBase.h"
Namespace="App"
Constructor="true"
Delete="true"
NumberProtocol="false"
RichCompare="false"
FatherNamespace="Base">
<Documentation>
<Author Licence="LGPL" Name="Chris Hennes" EMail="chennes@pioneerlibrarysystem.org" />
<UserDocu>
Metadata
A Metadata object reads an XML-formatted package metadata file and provides read-only access to its contents.
<Documentation>
<Author Licence="LGPL" Name="Chris Hennes" EMail="chennes@pioneerlibrarysystem.org" />
<UserDocu>
Metadata
A Metadata object reads an XML-formatted package metadata file and provides read-only access to its contents.
A single constructor is supported:
Metadata(file) -- Reads the XML file and provides access to the metadata it specifies.
</UserDocu>
<DeveloperDocu>Metadata</DeveloperDocu>
</Documentation>
A single constructor is supported:
Metadata(file) -- Reads the XML file and provides access to the metadata it specifies.
</UserDocu>
<DeveloperDocu>Metadata</DeveloperDocu>
</Documentation>
<Attribute Name="Name" ReadOnly="true">
<Documentation>
<UserDocu>String: the name of this item</UserDocu>
</Documentation>
<Parameter Name="Name" Type="Object" />
</Attribute>
<Attribute Name="Version" ReadOnly="true">
<Documentation>
<UserDocu>String: the version of this item in semantic triplet format</UserDocu>
</Documentation>
<Parameter Name="Version" Type="Object" />
</Attribute>
<Attribute Name="Description" ReadOnly="true">
<Documentation>
<UserDocu>String: the description of this item (text only, no markup allowed)</UserDocu>
</Documentation>
<Parameter Name="Description" Type="Object" />
</Attribute>
<Attribute Name="Maintainer" ReadOnly="true">
<Documentation>
<UserDocu>List of maintainer objects with 'name' and 'email' string attributes</UserDocu>
</Documentation>
<Parameter Name="Maintainer" Type="Object" />
</Attribute>
<Attribute Name="License" ReadOnly="true">
<Documentation>
<UserDocu>List of applicable licenses as objects with 'name' and 'file' string attributes</UserDocu>
</Documentation>
<Parameter Name="License" Type="Object" />
</Attribute>
<Attribute Name="Urls" ReadOnly="true">
<Documentation>
<UserDocu>
List of URLs as objects with 'location' and 'urltype' string attributes, where urltype is one of:
* website
* repository
* bugtracker
* readme
* documentation
</UserDocu>
</Documentation>
<Parameter Name="Urls" Type="Object" />
</Attribute>
<Attribute Name="Author" ReadOnly="true">
<Documentation>
<UserDocu>List of author objects, each with a 'name' and a (potentially empty) 'email' string attribute</UserDocu>
</Documentation>
<Parameter Name="Author" Type="Object" />
</Attribute>
<Attribute Name="Depend" ReadOnly="true">
<Documentation>
<UserDocu>
List of dependencies, as objects with the following attributes:
* package -- Required: must exactly match the contents of the 'name' element in the referenced package's package.xml file
* version_lt -- Optional: The dependency to the package is restricted to versions less than the stated version number
* version_lte -- Optional: The dependency to the package is restricted to versions less or equal than the stated version number
* version_eq -- Optional: The dependency to the package is restricted to a version equal than the stated version number
* version_gte -- Optional: The dependency to the package is restricted to versions greater or equal than the stated version number
* version_gt -- Optional: The dependency to the package is restricted to versions greater than the stated version number
* condition -- Optional: Conditional expression as documented in REP149
</UserDocu>
</Documentation>
<Parameter Name="Depend" Type="Object" />
</Attribute>
<Attribute Name="Conflict" ReadOnly="true">
<Documentation>
<UserDocu>List of conflicts, format identical to dependencies</UserDocu>
</Documentation>
<Parameter Name="Conflict" Type="Object" />
</Attribute>
<Attribute Name="Replace" ReadOnly="true">
<Documentation>
<UserDocu>List of things this item is considered by its author to replace: format identical to dependencies</UserDocu>
</Documentation>
<Parameter Name="Replace" Type="Object" />
</Attribute>
<Attribute Name="Tag" ReadOnly="true">
<Documentation>
<UserDocu>List of strings</UserDocu>
</Documentation>
<Parameter Name="Tag" Type="Object" />
</Attribute>
<Attribute Name="Icon" ReadOnly="true">
<Documentation>
<UserDocu>Relative path to an icon file</UserDocu>
</Documentation>
<Parameter Name="Icon" Type="Object" />
</Attribute>
<Attribute Name="Classname" ReadOnly="true">
<Documentation>
<UserDocu>String: the name of the main Python class this item creates/represents</UserDocu>
</Documentation>
<Parameter Name="Classname" Type="Object" />
</Attribute>
<Attribute Name="Subdirectory" ReadOnly="true">
<Documentation>
<UserDocu>String: the name of the subdirectory this content item is located in. If empty, the item is in a directory named the same as the content item.</UserDocu>
</Documentation>
<Parameter Name="Classname" Type="Object" />
</Attribute>
<Attribute Name="File" ReadOnly="true">
<Documentation>
<UserDocu>A list of files associated with this item -- the meaning of each file is implementation-defined</UserDocu>
</Documentation>
<Parameter Name="File" Type="Object" />
</Attribute>
<Attribute Name="Content" ReadOnly="true">
<Documentation>
<UserDocu>A dictionary of lists of content items: defined recursively, each item is itself a Metadata object -- see package.xml file format documentation for details</UserDocu>
</Documentation>
<Parameter Name="Content" Type="Object" />
</Attribute>
<Attribute Name="Name" ReadOnly="true">
<Documentation>
<UserDocu>String: the name of this item</UserDocu>
</Documentation>
<Parameter Name="Name" Type="Object" />
</Attribute>
<Attribute Name="Version" ReadOnly="true">
<Documentation>
<UserDocu>String: the version of this item in semantic triplet format</UserDocu>
</Documentation>
<Parameter Name="Version" Type="Object" />
</Attribute>
<Attribute Name="Description" ReadOnly="true">
<Documentation>
<UserDocu>String: the description of this item (text only, no markup allowed)</UserDocu>
</Documentation>
<Parameter Name="Description" Type="Object" />
</Attribute>
<Attribute Name="Maintainer" ReadOnly="true">
<Documentation>
<UserDocu>List of maintainer objects with 'name' and 'email' string attributes</UserDocu>
</Documentation>
<Parameter Name="Maintainer" Type="Object" />
</Attribute>
<Attribute Name="License" ReadOnly="true">
<Documentation>
<UserDocu>List of applicable licenses as objects with 'name' and 'file' string attributes</UserDocu>
</Documentation>
<Parameter Name="License" Type="Object" />
</Attribute>
<Attribute Name="Urls" ReadOnly="true">
<Documentation>
<UserDocu>
List of URLs as objects with 'location' and 'urltype' string attributes, where urltype is one of:
* website
* repository
* bugtracker
* readme
* documentation
</UserDocu>
</Documentation>
<Parameter Name="Urls" Type="Object" />
</Attribute>
<Attribute Name="Author" ReadOnly="true">
<Documentation>
<UserDocu>List of author objects, each with a 'name' and a (potentially empty) 'email' string attribute</UserDocu>
</Documentation>
<Parameter Name="Author" Type="Object" />
</Attribute>
<Attribute Name="Depend" ReadOnly="true">
<Documentation>
<UserDocu>
List of dependencies, as objects with the following attributes:
* package -- Required: must exactly match the contents of the 'name' element in the referenced package's package.xml file
* version_lt -- Optional: The dependency to the package is restricted to versions less than the stated version number
* version_lte -- Optional: The dependency to the package is restricted to versions less or equal than the stated version number
* version_eq -- Optional: The dependency to the package is restricted to a version equal than the stated version number
* version_gte -- Optional: The dependency to the package is restricted to versions greater or equal than the stated version number
* version_gt -- Optional: The dependency to the package is restricted to versions greater than the stated version number
* condition -- Optional: Conditional expression as documented in REP149
</UserDocu>
</Documentation>
<Parameter Name="Depend" Type="Object" />
</Attribute>
<Attribute Name="Conflict" ReadOnly="true">
<Documentation>
<UserDocu>List of conflicts, format identical to dependencies</UserDocu>
</Documentation>
<Parameter Name="Conflict" Type="Object" />
</Attribute>
<Attribute Name="Replace" ReadOnly="true">
<Documentation>
<UserDocu>List of things this item is considered by its author to replace: format identical to dependencies</UserDocu>
</Documentation>
<Parameter Name="Replace" Type="Object" />
</Attribute>
<Attribute Name="Tag" ReadOnly="true">
<Documentation>
<UserDocu>List of strings</UserDocu>
</Documentation>
<Parameter Name="Tag" Type="Object" />
</Attribute>
<Attribute Name="Icon" ReadOnly="true">
<Documentation>
<UserDocu>Relative path to an icon file</UserDocu>
</Documentation>
<Parameter Name="Icon" Type="Object" />
</Attribute>
<Attribute Name="Classname" ReadOnly="true">
<Documentation>
<UserDocu>String: the name of the main Python class this item creates/represents</UserDocu>
</Documentation>
<Parameter Name="Classname" Type="Object" />
</Attribute>
<Attribute Name="Subdirectory" ReadOnly="true">
<Documentation>
<UserDocu>String: the name of the subdirectory this content item is located in. If empty, the item is in a directory named the same as the content item.</UserDocu>
</Documentation>
<Parameter Name="Subdirectory" Type="Object" />
</Attribute>
<Attribute Name="File" ReadOnly="true">
<Documentation>
<UserDocu>A list of files associated with this item -- the meaning of each file is implementation-defined</UserDocu>
</Documentation>
<Parameter Name="File" Type="Object" />
</Attribute>
<Attribute Name="Content" ReadOnly="true">
<Documentation>
<UserDocu>A dictionary of lists of content items: defined recursively, each item is itself a Metadata object -- see package.xml file format documentation for details</UserDocu>
</Documentation>
<Parameter Name="Content" Type="Object" />
</Attribute>
<Attribute Name="FreeCADMin">
<Documentation>
<UserDocu>A string representing the minimum version of FreeCAD needed for this item. If unset it will be 0.0.0.</UserDocu>
</Documentation>
<Parameter Name="FreeCADMin" Type="Object" />
</Attribute>
<Methode Name="getGenericMetadata">
<Documentation>
<UserDocu>
getGenericMetadata(name)
Get the list of GenericMetadata objects with key 'name'. Generic metadata objects are Python objects with
a string 'contents' and a dictionary of strings, 'attributes'. They represent unrecognized simple XML tags
in the metadata file.
</UserDocu>
</Documentation>
</Methode>
<Attribute Name="FreeCADMax">
<Documentation>
<UserDocu>A string representing the maximum version of FreeCAD needed for this item. If unset it will be 0.0.0.</UserDocu>
</Documentation>
<Parameter Name="FreeCADMax" Type="Object" />
</Attribute>
<ClassDeclarations>
public:
MetadataPy(const Metadata &amp; pla, PyTypeObject *T = &amp;Type)
:PyObjectBase(new Metadata(pla),T){}
Metadata value() const
{ return *(getMetadataPtr()); }
</ClassDeclarations>
</PythonExport>
<Methode Name="getLastSupportedFreeCADVersion">
<Documentation>
<UserDocu>getLastSupportedFreeCADVersion()
Search through all content package items, and determine if a maximum supported version of FreeCAD
is set. Returns None if no maximum version is set, or if *any* content item fails to provide a
maximum version (implying that that content item will work with all known versions).
</UserDocu>
</Documentation>
</Methode>
<Methode Name="getFirstSupportedFreeCADVersion">
<Documentation>
<UserDocu>getFirstSupportedFreeCADVersion()
Search through all content package items, and determine if a minimum supported version of FreeCAD
is set. Returns 0.0 if no minimum version is set, or if *any* content item fails to provide a
minimum version (implying that that content item will work with all known versions -- technically
limited to 0.20 as the lowest known version since the metadata standard was added then).
</UserDocu>
</Documentation>
</Methode>
<Methode Name="getGenericMetadata">
<Documentation>
<UserDocu>getGenericMetadata(name)
Get the list of GenericMetadata objects with key 'name'. Generic metadata objects are Python objects with
a string 'contents' and a dictionary of strings, 'attributes'. They represent unrecognized simple XML tags
in the metadata file.
</UserDocu>
</Documentation>
</Methode>
<ClassDeclarations>
public:
MetadataPy(const Metadata &amp; pla, PyTypeObject *T = &amp;Type)
:PyObjectBase(new Metadata(pla),T){}
Metadata value() const
{ return *(getMetadataPtr()); }
</ClassDeclarations>
</PythonExport>
</GenerateModel>

View File

@@ -274,7 +274,7 @@ PyObject* MetadataPy::getGenericMetadata(PyObject* args)
{
const char* name;
if (!PyArg_ParseTuple(args, "s!", &name))
return NULL;
return nullptr;
auto gm = (*getMetadataPtr())[name];
auto pyGenericMetadata = new Py::List;
for (const auto& item : gm) {
@@ -290,6 +290,77 @@ PyObject* MetadataPy::getGenericMetadata(PyObject* args)
return pyGenericMetadata->ptr();
}
Py::Object MetadataPy::getFreeCADMin() const
{
return Py::String(getMetadataPtr()->freecadmin().str());
}
void MetadataPy::setFreeCADMin(Py::Object args)
{
char* version = nullptr;
PyObject* p = args.ptr();
if (!PyArg_ParseTuple(p, "s", &version))
return;
getMetadataPtr()->setFreeCADMin(App::Meta::Version(version));
}
Py::Object MetadataPy::getFreeCADMax() const
{
return Py::String(getMetadataPtr()->freecadmax().str());
}
void MetadataPy::setFreeCADMax(Py::Object args)
{
char* version = nullptr;
PyObject* p = args.ptr();
if (!PyArg_ParseTuple(p, "s", &version))
return;
getMetadataPtr()->setFreeCADMax(App::Meta::Version(version));
}
PyObject* MetadataPy::getFirstSupportedFreeCADVersion(PyObject* args)
{
// Short-circuit: if the toplevel sets a version, then the lower-levels are overridden
if (getMetadataPtr()->freecadmin() != App::Meta::Version())
return Py::new_reference_to(Py::String(getMetadataPtr()->freecadmin().str()));
auto content = getMetadataPtr()->content();
auto result = App::Meta::Version();
for (const auto& item : content) {
auto minVersion = item.second.freecadmin();
if (minVersion != App::Meta::Version())
if (result == App::Meta::Version() || minVersion < result)
result = minVersion;
}
if (result != App::Meta::Version())
return Py::new_reference_to(Py::String(result.str()));
else
Py_INCREF(Py_None);
return Py_None;
}
PyObject* MetadataPy::getLastSupportedFreeCADVersion(PyObject* args)
{
// Short-circuit: if the toplevel sets a version, then the lower-levels are overridden
if (getMetadataPtr()->freecadmax() != App::Meta::Version())
return Py::new_reference_to(Py::String(getMetadataPtr()->freecadmax().str()));
auto content = getMetadataPtr()->content();
auto result = App::Meta::Version();
for (const auto& item : content) {
auto maxVersion = item.second.freecadmax();
if (maxVersion != App::Meta::Version())
if (result == App::Meta::Version() || maxVersion > result)
result = maxVersion;
}
if (result != App::Meta::Version())
return Py::new_reference_to(Py::String(result.str()));
else
Py_INCREF(Py_None);
return Py_None;
}
PyObject* MetadataPy::getCustomAttributes(const char* /*attr*/) const
{
return 0;