Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Drop support for Python 2 & upgrade code style #4

Merged
merged 4 commits into from
Nov 8, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ jobs:
strategy:
matrix:
os: [ubuntu-latest, windows-latest]
python-version: [2.7, 3.5, 3.6, 3.7, 3.8, 3.9]
python-version: [3.7, 3.8, 3.9]

steps:
- uses: actions/checkout@v1
Expand Down
3 changes: 0 additions & 3 deletions compare_locales/checks/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,6 @@
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.

from __future__ import absolute_import
from __future__ import unicode_literals

from .base import Checker, EntityPos
from .android import AndroidChecker
from .dtd import DTDChecker
Expand Down
17 changes: 4 additions & 13 deletions compare_locales/checks/android.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,6 @@
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.

from __future__ import absolute_import
from __future__ import unicode_literals

import re
from xml.dom import minidom

Expand All @@ -23,10 +20,7 @@ def check(self, refEnt, l10nEnt):
- tuple of line, column info for the error within the string
- description string to be shown in the report
'''
for encoding_trouble in super(
AndroidChecker, self
).check(refEnt, l10nEnt):
yield encoding_trouble
yield from super().check(refEnt, l10nEnt)
refNode = refEnt.node
l10nNode = l10nEnt.node
# Apples and oranges, error out.
Expand All @@ -38,8 +32,7 @@ def check(self, refEnt, l10nEnt):
if refNode.nodeName != "string":
yield ("warning", 0, "Unsupported resource type", "android")
return
for report_tuple in self.check_string([refNode], l10nEnt):
yield report_tuple
yield from self.check_string([refNode], l10nEnt)

def check_string(self, refs, l10nEnt):
'''Check a single string literal against a list of references.
Expand Down Expand Up @@ -79,8 +72,7 @@ def check_string(self, refs, l10nEnt):
"android"
)
return
for report_tuple in check_apostrophes(l10nEnt.val):
yield report_tuple
yield from check_apostrophes(l10nEnt.val)

params, errors = get_params(refs)
for error, pos in errors:
Expand All @@ -91,8 +83,7 @@ def check_string(self, refs, l10nEnt):
"android"
)
if params:
for report_tuple in check_params(params, l10nEnt.val):
yield report_tuple
yield from check_params(params, l10nEnt.val)

def not_translatable(self, *nodes):
return any(
Expand Down
15 changes: 5 additions & 10 deletions compare_locales/checks/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,7 @@
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.

from __future__ import absolute_import
from __future__ import unicode_literals

import re
import six


class EntityPos(int):
Expand All @@ -16,7 +12,7 @@ class EntityPos(int):
mochibake = re.compile('\ufffd')


class Checker(object):
class Checker:
'''Abstract class to implement checks per file type.
'''
pattern = None
Expand Down Expand Up @@ -46,7 +42,7 @@ def check(self, refEnt, l10nEnt):
yield (
"warning",
EntityPos(m.start()),
"\ufffd in: {}".format(l10nEnt.key),
f"\ufffd in: {l10nEnt.key}",
"encodings"
)

Expand All @@ -57,14 +53,13 @@ def set_reference(self, reference):
self.reference = reference


class CSSCheckMixin(object):
class CSSCheckMixin:
def maybe_style(self, ref_value, l10n_value):
ref_map, _ = self.parse_css_spec(ref_value)
if not ref_map:
return
l10n_map, errors = self.parse_css_spec(l10n_value)
for t in self.check_style(ref_map, l10n_map, errors):
yield t
yield from self.check_style(ref_map, l10n_map, errors)

def check_style(self, ref_map, l10n_map, errors):
if not l10n_map:
Expand All @@ -83,7 +78,7 @@ def check_style(self, ref_map, l10n_map, errors):
if unit != ref_unit:
msgs.append("units for %s don't match "
"(%s != %s)" % (prop, unit, ref_unit))
for prop in six.iterkeys(ref_map):
for prop in ref_map.keys():
msgs.insert(0, '%s only in reference' % prop)
if msgs:
yield ('warning', 0, ', '.join(msgs), 'css')
Expand Down
46 changes: 19 additions & 27 deletions compare_locales/checks/dtd.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,9 @@
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.

from __future__ import absolute_import
from __future__ import unicode_literals
from io import BytesIO
import re
from xml import sax
import six

from compare_locales.parser import DTDParser
from .base import Checker, CSSCheckMixin
Expand All @@ -30,10 +28,10 @@ class DTDChecker(Checker, CSSCheckMixin):
tmpl = b'''<!DOCTYPE elem [%s]>
<elem>%s</elem>
'''
xmllist = set(('amp', 'lt', 'gt', 'apos', 'quot'))
xmllist = {'amp', 'lt', 'gt', 'apos', 'quot'}

def __init__(self, extra_tests, locale=None):
super(DTDChecker, self).__init__(extra_tests, locale=locale)
super().__init__(extra_tests, locale=locale)
self.processContent = False
if self.extra_tests is not None and 'android-dtd' in self.extra_tests:
self.processContent = True
Expand All @@ -49,8 +47,7 @@ def known_entities(self, refValue):
else self.entities_for_value(refValue)

def entities_for_value(self, value):
reflist = set(m.group(1)
for m in self.eref.finditer(value))
reflist = {m.group(1) for m in self.eref.finditer(value)}
reflist -= self.xmllist
return reflist

Expand All @@ -75,10 +72,7 @@ def check(self, refEnt, l10nEnt):

Return a checker that offers just those entities.
"""
for encoding_trouble in super(
DTDChecker, self
).check(refEnt, l10nEnt):
yield encoding_trouble
yield from super().check(refEnt, l10nEnt)
refValue, l10nValue = refEnt.raw_val, l10nEnt.raw_val
# find entities the refValue references,
# reusing markup from DTDParser.
Expand All @@ -91,14 +85,14 @@ def check(self, refEnt, l10nEnt):
parser.setContentHandler(self.defaulthandler)
try:
parser.parse(
six.BytesIO(self.tmpl %
(entities.encode('utf-8'),
refValue.encode('utf-8'))))
BytesIO(self.tmpl %
(entities.encode('utf-8'),
refValue.encode('utf-8'))))
# also catch stray %
parser.parse(
six.BytesIO(self.tmpl %
((refEnt.all + entities).encode('utf-8'),
b'&%s;' % refEnt.key.encode('utf-8'))))
BytesIO(self.tmpl %
((refEnt.all + entities).encode('utf-8'),
b'&%s;' % refEnt.key.encode('utf-8'))))
except sax.SAXParseException as e:
e # noqa
yield ('warning',
Expand All @@ -114,15 +108,15 @@ def check(self, refEnt, l10nEnt):
self.texthandler.textcontent = ''
parser.setContentHandler(self.texthandler)
try:
parser.parse(six.BytesIO(self.tmpl % (_entities.encode('utf-8'),
parser.parse(BytesIO(self.tmpl % (_entities.encode('utf-8'),
l10nValue.encode('utf-8'))))
# also catch stray %
# if this fails, we need to substract the entity definition
parser.setContentHandler(self.defaulthandler)
parser.parse(
six.BytesIO(self.tmpl %
((l10nEnt.all + _entities).encode('utf-8'),
b'&%s;' % l10nEnt.key.encode('utf-8'))))
BytesIO(self.tmpl %
((l10nEnt.all + _entities).encode('utf-8'),
b'&%s;' % l10nEnt.key.encode('utf-8'))))
except sax.SAXParseException as e:
# xml parse error, yield error
# sometimes, the error is reported on our fake closing
Expand All @@ -141,7 +135,7 @@ def check(self, refEnt, l10nEnt):
col -= len("<!DOCTYPE elem [") # first line is DOCTYPE
yield ('error', (lnr, col), ' '.join(e.args), 'xmlparse')

warntmpl = u'Referencing unknown entity `%s`'
warntmpl = 'Referencing unknown entity `%s`'
if reflist:
if inContext:
elsewhere = reflist - inContext
Expand All @@ -160,7 +154,7 @@ def check(self, refEnt, l10nEnt):
mismatch = sorted(l10nlist - inContext - set(missing))
for key in mismatch:
yield ('warning', (0, 0),
'Entity %s referenced, but %s used in context' % (
'Entity {} referenced, but {} used in context'.format(
key,
', '.join(sorted(inContext))
), 'xmlparse')
Expand All @@ -173,12 +167,10 @@ def check(self, refEnt, l10nEnt):
if self.length.match(refValue) and not self.length.match(l10nValue):
yield ('error', 0, 'reference is a CSS length', 'css')
# Check for actual CSS style attribute values
for t in self.maybe_style(refValue, l10nValue):
yield t
yield from self.maybe_style(refValue, l10nValue)

if self.extra_tests is not None and 'android-dtd' in self.extra_tests:
for t in self.processAndroidContent(self.texthandler.textcontent):
yield t
yield from self.processAndroidContent(self.texthandler.textcontent)

quoted = re.compile("(?P<q>[\"']).*(?P=q)$")

Expand Down
33 changes: 14 additions & 19 deletions compare_locales/checks/fluent.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.

from __future__ import absolute_import
from __future__ import unicode_literals
import re
from collections import defaultdict

Expand Down Expand Up @@ -69,18 +67,18 @@ def generic_visit(self, node):
(ftl.Span, ftl.Annotation, ftl.BaseComment)
):
return
super(ReferenceMessageVisitor, self).generic_visit(node)
super().generic_visit(node)

def visit_Message(self, node):
if node.value is not None:
self.message_has_value = True
super(ReferenceMessageVisitor, self).generic_visit(node)
super().generic_visit(node)

def visit_Attribute(self, node):
self.attribute_positions[node.id.name] = node.span.start
old_refs = self.refs
self.refs = self.entry_refs[node.id.name]
super(ReferenceMessageVisitor, self).generic_visit(node)
super().generic_visit(node)
self.refs = old_refs
if node.id.name != 'style':
return
Expand Down Expand Up @@ -108,7 +106,7 @@ def visit_TermReference(self, node):
self.refs['-' + node.id.name] = 'term-ref'


class GenericL10nChecks(object):
class GenericL10nChecks:
'''Helper Mixin for checks shared between Terms and Messages.'''
def check_duplicate_attributes(self, node):
warned = set()
Expand Down Expand Up @@ -177,7 +175,7 @@ def check_variants(self, variants):
# `other` is used for all kinds of things.
check_plurals = known_plurals.copy()
check_plurals.discard('other')
given_plurals = set(serialize_variant_key(v.key) for v in variants)
given_plurals = {serialize_variant_key(v.key) for v in variants}
if given_plurals & check_plurals:
missing_plurals = sorted(known_plurals - given_plurals)
if missing_plurals:
Expand All @@ -193,7 +191,7 @@ def check_variants(self, variants):

class L10nMessageVisitor(GenericL10nChecks, ReferenceMessageVisitor):
def __init__(self, locale, reference):
super(L10nMessageVisitor, self).__init__()
super().__init__()
self.locale = locale
# Overload refs to map to sets, just store what we found
# References to Messages, their Attributes, and Terms
Expand All @@ -209,7 +207,7 @@ def __init__(self, locale, reference):

def visit_Message(self, node):
self.check_duplicate_attributes(node)
super(L10nMessageVisitor, self).visit_Message(node)
super().visit_Message(node)
if self.message_has_value and not self.reference.message_has_value:
self.messages.append(
('error', node.value.span.start, MSGS['obsolete-value'])
Expand Down Expand Up @@ -241,7 +239,7 @@ def visit_Term(self, node):
def visit_Attribute(self, node):
old_reference_refs = self.reference_refs
self.reference_refs = self.reference.entry_refs[node.id.name]
super(L10nMessageVisitor, self).visit_Attribute(node)
super().visit_Attribute(node)
self.reference_refs = old_reference_refs
if node.id.name != 'style' or self.css_styles == 'skip':
return
Expand All @@ -258,7 +256,7 @@ def visit_Attribute(self, node):
self.messages.append((cat, msg, pos))

def visit_SelectExpression(self, node):
super(L10nMessageVisitor, self).visit_SelectExpression(node)
super().visit_SelectExpression(node)
self.check_variants(node.variants)

def visit_MessageReference(self, node):
Expand Down Expand Up @@ -287,7 +285,7 @@ def check_obsolete_ref(self, node, ref, ref_type):

class TermVisitor(GenericL10nChecks, Visitor):
def __init__(self, locale):
super(TermVisitor, self).__init__()
super().__init__()
self.locale = locale
self.messages = []

Expand All @@ -297,17 +295,17 @@ def generic_visit(self, node):
(ftl.Span, ftl.Annotation, ftl.BaseComment)
):
return
super(TermVisitor, self).generic_visit(node)
super().generic_visit(node)

def visit_Message(self, node):
raise RuntimeError("Should not use TermVisitor for Messages")

def visit_Term(self, node):
self.check_duplicate_attributes(node)
super(TermVisitor, self).generic_visit(node)
super().generic_visit(node)

def visit_SelectExpression(self, node):
super(TermVisitor, self).generic_visit(node)
super().generic_visit(node)
self.check_variants(node.variants)


Expand Down Expand Up @@ -338,10 +336,7 @@ def check_term(self, l10n_entry):
return l10n_data.messages

def check(self, refEnt, l10nEnt):
for encoding_trouble in super(
FluentChecker, self
).check(refEnt, l10nEnt):
yield encoding_trouble
yield from super().check(refEnt, l10nEnt)
l10n_entry = l10nEnt.entry
if isinstance(l10n_entry, ftl.Message):
ref_entry = refEnt.entry
Expand Down
Loading