From 366b64a24b9db63616500a8942c33b0ebb579ce9 Mon Sep 17 00:00:00 2001 From: Matthias Klumpp Date: Tue, 9 Jul 2024 00:12:55 +0200 Subject: Adjust build to work with Python 3 and modern tooling --- tools/doc-generator.py | 83 ++++++++++++++++++++++++++------------------------ tools/specparser.py | 79 +++++++++++++++++++++++------------------------ tools/xincludator.py | 9 ++---- 3 files changed, 85 insertions(+), 86 deletions(-) (limited to 'tools') diff --git a/tools/doc-generator.py b/tools/doc-generator.py index 95a8011..f713664 100755 --- a/tools/doc-generator.py +++ b/tools/doc-generator.py @@ -1,8 +1,8 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # # doc-generator.py # -# Generates HTML documentation from the parsed spec using Cheetah templates. +# Generates HTML documentation from the parsed spec # # Copyright (C) 2009 Collabora Ltd. # @@ -27,12 +27,13 @@ import sys import os import os.path import shutil +import itertools try: - from Cheetah.Template import Template -except ImportError, e: - print >> sys.stderr, e - print >> sys.stderr, "Install `python-cheetah'?" + from jinja2 import Template +except ImportError as e: + print(e, file=sys.stderr) + print("Install `jinja2'?", file=sys.stderr) sys.exit(-1) import specparser @@ -67,54 +68,58 @@ def load_template(filename): file = open(os.path.join(template_path, filename)) template_def = file.read() file.close() - except IOError, e: - print >> sys.stderr, "Could not load template file `%s'" % filename - print >> sys.stderr, e + except IOError as e: + print("Could not load template file `%s'" % filename, file=sys.stderr) + print(e, file=sys.stderr) sys.exit(-1) return template_def +def render_template(name, context, target=None): + if target is None: + target = name + template_def = load_template(name) + t = Template(template_def).render(context) + with open(os.path.join(output_path, target), 'w') as out: + out.write(t) + spec = specparser.parse(spec_file, namespace, allow_externals=allow_externals) # write out HTML files for each of the interfaces -# Not using render_template here to avoid recompiling it n times. -namespace = { 'spec': spec } -template_def = load_template('interface.html') -t = Template(template_def, namespaces = [namespace]) -for interface in spec.interfaces: - namespace['interface'] = interface +all_values = list(spec.everything.values()) + list(spec.errors.values()) + list(spec.types.values()) - # open the output file - out = open(os.path.join(output_path, '%s.html' - % interface.name_for_bindings), 'w') - print >> out, unicode(t).encode('utf-8') - out.close() +star = [ (item.short_name, item) for item in all_values ] +star.sort(key = lambda t: t[0].title()) +groups = [ (l, list(g)) for l, g in (itertools.groupby(star, key = lambda t: t[0][0].upper())) ] +letters = set(map(lambda t: t[0], groups)) +all_letters = list(map(chr, range(ord('A'), ord('Z')+1))) -def render_template(name, namespaces, target=None): - if target is None: - target = name +context = { 'spec': spec, 'star': star, 'groups': groups, + 'letters': letters, 'all_letters': all_letters } +render_template('fullindex.html', context) - namespace = { 'spec': spec } - template_def = load_template(name) - t = Template(template_def, namespaces=namespaces) - out = open(os.path.join(output_path, target), 'w') - print >> out, unicode(t).encode('utf-8') - out.close() +context = { 'spec': spec, 'name': project, 'all_values': all_values } +render_template('devhelp.devhelp2', context, target=('%s.devhelp2' % project)) -namespaces = { 'spec': spec } +# Not using render_template here to avoid recompiling it n times. +context = { 'spec': spec } +template_def = load_template('interface.html') +t = Template(template_def) +for interface in spec.interfaces: + context['interface'] = interface + # open the output file + with open(os.path.join(output_path, '%s.html' + % interface.name_for_bindings), 'w') as out: + out.write(t.render(context)) +context = { 'spec': spec } if len(spec.generic_types) > 0: - render_template('generic-types.html', namespaces) + render_template('generic-types.html', context) if len(spec.errors) > 0: - render_template('errors.html', namespaces) -render_template('interfaces.html', namespaces) -render_template('fullindex.html', namespaces) - -dh_namespaces = { 'spec': spec, 'name': project } -render_template('devhelp.devhelp2', dh_namespaces, - target=('%s.devhelp2' % project)) + render_template('errors.html', context) +render_template('interfaces.html', context) # write out the TOC last, because this is the file used as the target in the # Makefile. -render_template('index.html', namespaces) +render_template('index.html', context) diff --git a/tools/specparser.py b/tools/specparser.py index 29ee0b5..472d098 100644 --- a/tools/specparser.py +++ b/tools/specparser.py @@ -1,3 +1,4 @@ +#!/usr/bin/env python3 # # specparser.py # @@ -24,6 +25,7 @@ import sys import xml.dom.minidom +import functools import xincludator @@ -51,14 +53,14 @@ class Xzibit(Exception): self.child = child def __str__(self): - print """ + print (""" Nested <%s>s are forbidden. Parent: %s... Child: %s... """ % (self.parent.nodeName, self.parent.toxml()[:100], - self.child.toxml()[:100]) + self.child.toxml()[:100])) def getText(dom): try: @@ -70,17 +72,17 @@ def getText(dom): return '' def getChildrenByName(dom, namespace, name): - return filter(lambda n: n.nodeType == n.ELEMENT_NODE and \ + return list(filter(lambda n: n.nodeType == n.ELEMENT_NODE and \ n.namespaceURI == namespace and \ n.localName == name, - dom.childNodes) + dom.childNodes)) def getChildrenByNameAndAttribute(dom, namespace, name, attribute, value): - return filter(lambda n: n.nodeType == n.ELEMENT_NODE and \ + return list(filter(lambda n: n.nodeType == n.ELEMENT_NODE and \ n.namespaceURI == namespace and \ n.localName == name and \ n.getAttribute(attribute) == value, - dom.childNodes) + dom.childNodes)) def getOnlyChildByName(dom, namespace, name): kids = getChildrenByName(dom, namespace, name) @@ -228,7 +230,7 @@ class Base(object): self._convert_to_html(node) - return node.toxml().encode('ascii', 'xmlcharrefreplace') + return node.toxml() def get_added(self): return self._get_generic_with_ver(self.added, 'added', @@ -264,7 +266,7 @@ class Base(object): self._convert_to_html(node) - return node.toxml().encode('ascii', 'xmlcharrefreplace') + return node.toxml() def _convert_to_html(self, node): spec = self.get_spec() @@ -342,10 +344,10 @@ class Base(object): try: e = spec.errors[error_ns + getText(n)] except KeyError: - print >> sys.stderr, """ + print(""" WARNING: Error '%s' not known in error namespace '%s' ( in %s) - """.strip() % (getText(n), error_ns[:-1], self) + """.strip() % (getText(n), error_ns[:-1], self), file=sys.stderr) continue n.tagName = 'a' @@ -359,10 +361,10 @@ WARNING: Error '%s' not known in error namespace '%s' try: o = spec.lookup(key, namespace=root_namespace) except KeyError: - print >> sys.stderr, """ + print(""" WARNING: Key '%s' not known in namespace '%s' ( in %s) - """.strip() % (key, root_namespace, self) + """.strip() % (key, root_namespace, self), file=sys.stderr) continue n.tagName = 'a' @@ -382,10 +384,10 @@ WARNING: Key '%s' not known in namespace '%s' try: o = spec.lookup(key, namespace=namespace) except KeyError: - print >> sys.stderr, """ + print(""" WARNING: Key '%s' not known in namespace '%s' ( in %s) - """.strip() % (key, namespace, self) + """.strip() % (key, namespace, self), file=sys.stderr) continue n.tagName = 'a' @@ -415,10 +417,10 @@ WARNING: Key '%s' not known in namespace '%s' except KeyError: o = spec.lookup(key, None) except KeyError: - print >> sys.stderr, """ + print(""" WARNING: Key '%s' not known in namespace '%s' ( in %s) - """.strip() % (key, namespace, self) + """.strip() % (key, namespace, self), file=sys.stderr) continue n.tagName = 'a' @@ -498,10 +500,10 @@ class PossibleError(Base): return spec.errors[self.name] except KeyError: if not spec.allow_externals: - print >> sys.stderr, """ + print(""" WARNING: Error not known: '%s' ( in %s) - """.strip() % (self.name, self.parent) + """.strip() % (self.name, self.parent), file=sys.stderr) return External(self.name) @@ -528,8 +530,8 @@ class Method(DBusConstruct): dom.getElementsByTagName('arg')) # separate arguments as input and output arguments - self.in_args = filter(lambda a: a.direction == Arg.DIRECTION_IN, args) - self.out_args = filter(lambda a: a.direction == Arg.DIRECTION_OUT, args) + self.in_args = list(filter(lambda a: a.direction == Arg.DIRECTION_IN, args)) + self.out_args = list(filter(lambda a: a.direction == Arg.DIRECTION_OUT, args)) for arg in args: if arg.direction == Arg.DIRECTION_IN or \ @@ -637,10 +639,11 @@ class HasEmitsChangedAnnotation(object): try: return self.__MAPPING[emits_changed] except KeyError: - print >> sys.stderr, """ + print(""" WARNING: has unknown value '%s' (in %s) - """.strip() % (self.__ANNOTATION, emits_changed, self) + """.strip() % (self.__ANNOTATION, emits_changed, self), + file=sys.stderr) return self.EMITS_CHANGED_UNKNOWN; class Property(DBusConstruct, Typed, HasEmitsChangedAnnotation): @@ -662,8 +665,6 @@ class Property(DBusConstruct, Typed, HasEmitsChangedAnnotation): else: raise UnknownAccess("Unknown access '%s' on %s" % (access, self)) - self.is_optional = (getAnnotationByName(dom, 'org.mpris.MediaPlayer2.property.optional') == 'true') - is_cp = dom.getAttributeNS(XMLNS_TP, 'is-connection-parameter') self.is_connection_parameter = is_cp != '' @@ -705,20 +706,15 @@ class Property(DBusConstruct, Typed, HasEmitsChangedAnnotation): return ', '.join(descriptions) - def get_optional(self): - if self.is_optional: - return '
This property is optional. Clients should handle its absence gracefully.
' - else: - return '' - class AwkwardTelepathyProperty(Typed): def __init__(self, parent, namespace, dom): Typed.__init__(self, parent, namespace, dom) - print >> sys.stderr, """ + print(""" WARNING: Old-style Telepathy properties are deprecated! ( in %s) - """.strip() % (parent) + """.strip() % (parent), + file=sys.stderr) def get_type_name(self): return 'Telepathy Property' @@ -869,10 +865,10 @@ class Interface(Base, HasEmitsChangedAnnotation): return spec.lookup(r) except KeyError: if not spec.allow_externals: - print >> sys.stderr, """ + print(""" WARNING: Interface not known: '%s' ( in %s) - """.strip() % (r, self) + """.strip() % (r, self), file=sys.stderr) return External(r) @@ -920,10 +916,11 @@ WARNING: Interface not known: '%s' ] if unexpected: - print >> sys.stderr, """ + print(""" WARNING: Unknown element(s): %s (in interface '%s') - """.strip() % (', '.join([x.tagName for x in unexpected]), self.name) + """.strip() % (', '.join([x.tagName for x in unexpected]), self.name), + file=sys.stderr) class Error(Base): def get_url(self): @@ -1295,7 +1292,7 @@ class Spec(SectionBase): key=lambda e: e.name) # build a list of generic types - self.generic_types = reduce (lambda a, b: a + b, + self.generic_types = functools.reduce (lambda a, b: a + b, map(lambda l: parse_types(self, l), dom.getElementsByTagNameNS(XMLNS_TP, 'generic-types')), []) @@ -1341,12 +1338,12 @@ class Spec(SectionBase): except IndexError: self.version = None - self.copyrights = map(getText, - getChildrenByName(node, XMLNS_TP, 'copyright')) + self.copyrights = list(map(getText, + getChildrenByName(node, XMLNS_TP, 'copyright'))) try: license = getChildrenByName(node, XMLNS_TP, 'license')[0] - self.license = map(getText, license.getElementsByTagName('p')) + self.license = list(map(getText, license.getElementsByTagName('p'))) except IndexError: self.license = [] @@ -1393,7 +1390,7 @@ def build_dict(parent, type_, namespace, nodes): return dict(build_tuple(n) for n in nodes) def build_list(parent, type_, namespace, nodes): - return map(lambda node: type_(parent, namespace, node), nodes) + return list(map(lambda node: type_(parent, namespace, node), nodes)) def parse_types(parent, dom, namespace = None): """Parse all of the types of type nodes mentioned in 't' from the node diff --git a/tools/xincludator.py b/tools/xincludator.py index 63e106a..9fcbc03 100644 --- a/tools/xincludator.py +++ b/tools/xincludator.py @@ -1,17 +1,14 @@ -#!/usr/bin/python +#!/usr/bin/env python3 -from sys import argv, stdout, stderr -import codecs, locale +from sys import argv, stdout import os import xml.dom.minidom -stdout = codecs.getwriter('utf-8')(stdout) - NS_XI = 'http://www.w3.org/2001/XInclude' def xincludate(dom, base, dropns = []): remove_attrs = [] - for i in xrange(dom.documentElement.attributes.length): + for i in range(dom.documentElement.attributes.length): attr = dom.documentElement.attributes.item(i) if attr.prefix == 'xmlns': if attr.localName in dropns: -- cgit v1.2.3