6bc5671491
Apply: git diff --full-index --binary anaconda-23.19.10-1..anaconda-25.20.9-1 And resolve conflicts. QubesOS/qubes-issues#2574
183 lines
6.9 KiB
Python
183 lines
6.9 KiB
Python
#
|
|
# Copyright (C) 2015 Red Hat, Inc.
|
|
#
|
|
# This program is free software; you can redistribute it and/or modify
|
|
# it under the terms of the GNU Lesser General Public License as published
|
|
# by the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU Lesser General Public License
|
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
"""
|
|
Common classes and functions for checking glade files.
|
|
|
|
Glade file tests should provide a python file containing a subclass of
|
|
GladeTest, below. When nose is run with GladePlugin, each GladeTest
|
|
implementation will be run against each glade file.
|
|
"""
|
|
|
|
# Print more helpful messages before raising ImportError
|
|
try:
|
|
from lxml import etree
|
|
except ImportError:
|
|
print("No module named lxml, you need to install the python3-lxml package")
|
|
raise
|
|
|
|
try:
|
|
from pocketlint.translatepo import translate_all
|
|
except ImportError:
|
|
print("Unable to load po translation module. You may need to install python3-polib")
|
|
raise
|
|
|
|
from abc import ABCMeta, abstractmethod
|
|
import os
|
|
import unittest
|
|
import copy
|
|
import nose
|
|
|
|
from filelist import testfilelist
|
|
|
|
import logging
|
|
log = logging.getLogger('nose.plugins.glade')
|
|
|
|
class GladeTest(unittest.TestCase, metaclass=ABCMeta):
|
|
"""A framework for checking glade files.
|
|
|
|
Subclasses must implement the checkGlade method, which will be run for
|
|
each glade file that is part of the test. The unittest assert* methods
|
|
are available. If checkGlade returns without raising an exception it
|
|
is considered to pass.
|
|
|
|
If the translatable property is True and --translate was provided on the
|
|
command line, checkGlade will also be called with translated versions of
|
|
each glade file.
|
|
"""
|
|
|
|
translatable = False
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
super().__init__(*args, **kwargs)
|
|
|
|
# Set by the plugin in prepareTestCase, since that's easier than
|
|
# trying to override how this object is created.
|
|
self.glade_trees = []
|
|
self.translated_trees = {}
|
|
|
|
@abstractmethod
|
|
def checkGlade(self, tree):
|
|
"""Check a parsed glade file.
|
|
|
|
:param etree.ElementTree tree: The parsed glade file
|
|
"""
|
|
pass
|
|
|
|
def test_glade_file(self):
|
|
"""Run checkGlade for each glade file."""
|
|
for tree in self.glade_trees:
|
|
with self.subTest(glade_file=tree.getroot().base):
|
|
self.checkGlade(tree)
|
|
|
|
if self.translatable:
|
|
for lang, trees in self.translated_trees.items():
|
|
for tree in trees:
|
|
with self.subTest(glade_file=tree.getroot().base, lang=lang):
|
|
self.checkGlade(tree)
|
|
|
|
class GladePlugin(nose.plugins.Plugin):
|
|
name = "glade"
|
|
enabled = True
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
super().__init__(*args, **kwargs)
|
|
|
|
# These are filled during configure(), after we've decided what files
|
|
# to check and whether to translate them.
|
|
# Translations are a dict of {'lang': [list of trees]}
|
|
self.glade_trees = []
|
|
self.translated_trees = {}
|
|
|
|
def options(self, parser, env):
|
|
# Do not call the superclass options() to skip setting up the
|
|
# enable/disable options.
|
|
|
|
parser.add_option("--glade-file", action="append",
|
|
help="Glade file(s) to test. If none specified, all files will be tested")
|
|
parser.add_option("--notranslate", dest="translate", action="store_false", default=False,
|
|
help="Do not test translations of glade files")
|
|
parser.add_option("--translate", action="store_true",
|
|
help="Test glade files with translations")
|
|
parser.add_option("--podir", action="store", type=str,
|
|
default=os.environ.get('top_srcdir', '.') + "/po",
|
|
metavar="PODIR", help="Directory containing .po files")
|
|
|
|
def configure(self, options, conf):
|
|
super().configure(options, conf)
|
|
|
|
# If no glade files were specified, find all of them
|
|
if options.glade_file:
|
|
glade_files = options.glade_file
|
|
else:
|
|
glade_files = testfilelist(lambda x: x.endswith('.glade'))
|
|
|
|
# Parse all of the glade files
|
|
log.info("Parsing glade files...")
|
|
for glade_file in glade_files:
|
|
self.glade_trees.append(etree.parse(glade_file))
|
|
|
|
if options.translate:
|
|
log.info("Loading translations...")
|
|
podicts = translate_all(options.podir)
|
|
|
|
# Loop over each available language
|
|
for lang, langmap in podicts.items():
|
|
self.translated_trees[lang] = []
|
|
|
|
# For each language, loop over the parsed glade files
|
|
for tree in self.glade_trees:
|
|
# Make a copy of the tree to translate and save it to
|
|
# the list for this language
|
|
tree = copy.deepcopy(tree)
|
|
self.translated_trees[lang].append(tree)
|
|
|
|
# Save the language as an attribute of the root of the tree
|
|
tree.getroot().set("lang", lang)
|
|
|
|
# Look for all properties with translatable=yes and translate them
|
|
for translatable in tree.xpath('//property[@translatable="yes"]'):
|
|
try:
|
|
xlated_text = langmap.get(translatable.text, context=translatable.get('context'))[0]
|
|
|
|
# Add the untranslated text as an attribute to this node
|
|
translatable.set("original_text", translatable.text)
|
|
|
|
# Replace the actual text
|
|
translatable.text = xlated_text
|
|
except KeyError:
|
|
# No translation available for this string in this language
|
|
pass
|
|
|
|
def prepareTestCase(self, testcase):
|
|
# Add the glade files to the GladeTest object
|
|
testcase.test.glade_trees = self.glade_trees
|
|
testcase.test.translated_trees = self.translated_trees
|
|
|
|
def describeTest(self, testcase):
|
|
# Return the first line of the doc string on checkGlade instead
|
|
# of the string for test_glade_file. If there is no doc string,
|
|
# return the name of the class.
|
|
doc = testcase.test.checkGlade.__doc__
|
|
if doc:
|
|
return doc.strip().split("\n")[0].strip()
|
|
else:
|
|
return testcase.test.__class__.__name__
|
|
|
|
def wantClass(self, cls):
|
|
# Make sure we grab all the GladeTest subclasses, and only GladeTest
|
|
# subclasses, regardless of name.
|
|
return issubclass(cls, GladeTest) and cls != GladeTest
|