diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 05:31:45 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 05:31:45 +0000 |
commit | 74aa0bc6779af38018a03fd2cf4419fe85917904 (patch) | |
tree | 9cb0681aac9a94a49c153d5823e7a55d1513d91f /src/sbus/codegen/sbus_Introspection.py | |
parent | Initial commit. (diff) | |
download | sssd-74aa0bc6779af38018a03fd2cf4419fe85917904.tar.xz sssd-74aa0bc6779af38018a03fd2cf4419fe85917904.zip |
Adding upstream version 2.9.4.upstream/2.9.4
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/sbus/codegen/sbus_Introspection.py')
-rw-r--r-- | src/sbus/codegen/sbus_Introspection.py | 287 |
1 files changed, 287 insertions, 0 deletions
diff --git a/src/sbus/codegen/sbus_Introspection.py b/src/sbus/codegen/sbus_Introspection.py new file mode 100644 index 0000000..17a255a --- /dev/null +++ b/src/sbus/codegen/sbus_Introspection.py @@ -0,0 +1,287 @@ +# +# Authors: +# Pavel Brezina <pbrezina@redhat.com> +# +# Copyright (C) 2017 Red Hat +# +# This program 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. +# +# This program 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 this program. If not, see <http://www.gnu.org/licenses/>. +# + +from collections import OrderedDict +import xml.etree.ElementTree as etree + + +class Introspectable: + class Element(object): + """ This is a basic introspectable object. This class will make + sure that the given xml element is of correct type and provide + some helper functions to simplify work of the children. + + Children objects must implement TagName attribute, which contains + the name of the expected xml tag. + + All introspectable objects contain the following properties: + - name : str -- name of the object + - annotations : OrderedDict -- available annotations + """ + def __init__(self, element): + self.check(element, self.TagName) + + self.element = element + self.name = element.attrib["name"] + self.annotations = self.find(SBus.Annotation) + + def find(self, object_class): + return Introspectable.FindElements(self.element, object_class) + + def check(self, element, tagname): + if element.tag != tagname: + raise ValueError('Unexpected tag name "%s" (%s expected)!' + % (element.tag, tagname)) + if "name" not in element.attrib: + raise ValueError('Missing attribute name!') + + def getAttr(self, name, default_value): + return self.element.attrib.get(name, default_value) + + def getExistingAttr(self, name): + if name not in self.element.attrib: + raise ValueError('Element %s name="%s" is missing attribute %s' + % (self.TagName, self.name, name)) + + return self.element.attrib[name] + + class Invokable(Element): + """ This is a base class for invokable objects -- methods and signals. + Invokable objects has available additional attributes: + + - input OrderedDict -- input signature and arguments + - output : OrderedDict -- output signature and arguments + """ + def __init__(self, element): + super(Introspectable.Invokable, self).__init__(element) + + self.key = self.getAttr("key", None) + + self.arguments = self.find(SBus.Argument) + input = self.getInputArguments() + output = self.getOutputArguments() + + self.input = SBus.Signature(input, self.annotations) + self.output = SBus.Signature(output, self.annotations) + return + + def getInputArguments(self): + return self.getArguments("in") + + def getOutputArguments(self): + return self.getArguments("out") + + def getArguments(self, type): + args = OrderedDict() + + for name, arg in self.arguments.items(): + if type == "in" and arg.isInput(): + args[name] = arg + continue + if type == "out" and arg.isOutput(): + args[name] = arg + continue + + return args + + @staticmethod + def Introspect(path): + root = etree.parse(path).getroot() + return Introspectable.FindElements(root, SBus.Interface) + + @staticmethod + def FindElements(parent, object_class): + dict = OrderedDict() + for child in parent: + if child.tag != object_class.TagName: + continue + object = object_class(child) + + if object.name in dict: + raise ValueError('%s name="%s" is already present ' + 'in the same parent element\n' + % (object_class.TagName, object.name)) + + dict[object.name] = object + + """ + Arguments can't be sorted and annotations order should be left on + the author of introspection. Otherwise we want to sort the dictionary + alphabetically based on keys. + """ + if object_class in [SBus.Argument, SBus.Annotation]: + return dict + + return OrderedDict(sorted(dict.items())) + + +class SBus: + class Interface(Introspectable.Element): + TagName = "interface" + + def __init__(self, element): + super(SBus.Interface, self).__init__(element) + + self.methods = self.find(SBus.Method) + self.signals = self.find(SBus.Signal) + self.properties = self.find(SBus.Property) + return + + class Method(Introspectable.Invokable): + TagName = "method" + + def __init__(self, element): + super(SBus.Method, self).__init__(element) + + class Signal(Introspectable.Invokable): + TagName = "signal" + + def __init__(self, element): + super(SBus.Signal, self).__init__(element) + + class Property(Introspectable.Invokable): + TagName = "property" + + def __init__(self, element): + self.name = element.attrib["name"] + self.element = element + self.access = self.getExistingAttr("access") + self.type = self.getExistingAttr("type") + + super(SBus.Property, self).__init__(element) + + if self.key is not None: + raise ValueError('Keying is not supported on properties: %s ' + % self.name) + + def getInputArguments(self): + if not self.isWritable(): + return {} + + return {"value": SBus.Argument.Create("value", self.type, "in")} + + def getOutputArguments(self): + if not self.isReadable(): + return {} + + return {"value": SBus.Argument.Create("value", self.type, "out")} + + def isReadable(self): + return self.access == "read" or self.access == "readwrite" + + def isWritable(self): + return self.access == "write" or self.access == "readwrite" + + class Annotation(Introspectable.Element): + TagName = "annotation" + + def __init__(self, element): + super(SBus.Annotation, self).__init__(element) + + self.value = self.getAttr("value", None) + return + + @staticmethod + def Find(annotations, name, default_value): + if name in annotations: + annotation = annotations[name] + if annotation.value is None: + return default_value + return annotation.value + return default_value + + @staticmethod + def FindBool(annotations, name, Assume=False): + assume = "true" if Assume else "false" + value = SBus.Annotation.Find(annotations, name, assume) + if value.lower() == "true": + return True + else: + return False + + @staticmethod + def CheckIfTrue(names, annotations): + for name in names: + if SBus.Annotation.FindBool(annotations, name, False): + return True + + return False + + @staticmethod + def CheckIfFalse(names, annotations): + for name in names: + if not SBus.Annotation.FindBool(annotations, name, True): + return False + + return True + + @staticmethod + def AtleastOneIsSet(names, annotations): + for name in names: + value = SBus.Annotation.Find(annotations, name, None) + if value is not None: + return True + + return False + + class Argument(Introspectable.Element): + TagName = "arg" + + def __init__(self, element, Name=None, Type=None, Direction=None, + Key=None): + if element is None: + self.element = None + self.name = Name + self.signature = Type + self.direction = Direction + self.key = Key + return + + super(SBus.Argument, self).__init__(element) + + self.signature = self.getExistingAttr("type") + self.direction = self.getAttr("direction", "in") + self.key = self.getAttr("key", None) + + def isInput(self): + return self.direction == "in" + + def isOutput(self): + return not self.isInput() + + @staticmethod + def Create(name, type, direction): + return SBus.Argument(element=None, + Name=name, + Type=type, + Direction=direction) + + class Signature: + def __init__(self, args, annotations): + self.annotations = annotations + self.signature = self.getSignature(args) + self.arguments = args + + def getSignature(self, args): + signature = "" + for arg in args.values(): + signature += arg.signature + + return signature |