Bug 1653662: Update mozilla-version; r=aki
authorTom Prince <mozilla@hocat.ca>
Sat, 18 Jul 2020 01:42:25 +0000
changeset 541014 d3740f55f2ffd6f3e7f22726c05f7b303d4837b1
parent 541013 65418a2fb34497160402d09acadeab78974994d3
child 541015 c7ab0fccb72af2aba4c9ded7032bd4f369886303
push id37613
push userbtara@mozilla.com
push dateSat, 18 Jul 2020 09:26:25 +0000
treeherdermozilla-central@08cd64cdbc3b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersaki
bugs1653662
milestone80.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1653662: Update mozilla-version; r=aki This updates to the latest version that does not add the python-future dependency. Differential Revision: https://phabricator.services.mozilla.com/D84041
third_party/python/mozilla-version/PKG-INFO
third_party/python/mozilla-version/mozilla_version/balrog.py
third_party/python/mozilla-version/mozilla_version/gecko.py
third_party/python/mozilla-version/mozilla_version/maven.py
third_party/python/mozilla-version/mozilla_version/parser.py
third_party/python/mozilla-version/mozilla_version/test/__init__.py
third_party/python/mozilla-version/mozilla_version/test/test_balrog.py
third_party/python/mozilla-version/mozilla_version/test/test_gecko.py
third_party/python/mozilla-version/mozilla_version/test/test_maven.py
third_party/python/mozilla-version/mozilla_version/test/test_version.py
third_party/python/mozilla-version/mozilla_version/version.py
third_party/python/mozilla-version/requirements-coveralls.txt
third_party/python/mozilla-version/requirements-docs.txt
third_party/python/mozilla-version/requirements-test.txt
third_party/python/mozilla-version/requirements.txt
third_party/python/mozilla-version/version.txt
third_party/python/requirements.in
third_party/python/requirements.txt
--- a/third_party/python/mozilla-version/PKG-INFO
+++ b/third_party/python/mozilla-version/PKG-INFO
@@ -1,11 +1,11 @@
 Metadata-Version: 1.1
 Name: mozilla-version
-Version: 0.3.0
+Version: 0.3.4
 Summary: Process Firefox versions numbers. Tells whether they are valid or not, whether they are nightlies or regular releases, whether this version precedes that other.
     
 Home-page: https://github.com/mozilla-releng/mozilla-version
 Author: Mozilla Release Engineering
 Author-email: release+python@mozilla.com
 License: MPL2
 Description: UNKNOWN
 Platform: UNKNOWN
--- a/third_party/python/mozilla-version/mozilla_version/balrog.py
+++ b/third_party/python/mozilla-version/mozilla_version/balrog.py
@@ -58,17 +58,17 @@ def _supported_product(string):
 def _products_must_be_identical(method):
     def checker(this, other):
         if this.product != other.product:
             raise ValueError('Cannot compare "{}" and "{}"'.format(this.product, other.product))
         return method(this, other)
     return checker
 
 
-@attr.s(frozen=True, cmp=False)
+@attr.s(frozen=True, cmp=False, hash=True)
 class BalrogReleaseName(object):
     """Class that validates and handles Balrog release names.
 
     Raises:
         PatternNotMatchedError: if a parsed string doesn't match the pattern of a valid release
         MissingFieldError: if a mandatory field is missing in the string. Mandatory fields are
             `product`, `major_number`, `minor_number`, and `build_number`
         ValueError: if an integer can't be cast or is not (strictly) positive
--- a/third_party/python/mozilla-version/mozilla_version/gecko.py
+++ b/third_party/python/mozilla-version/mozilla_version/gecko.py
@@ -45,49 +45,20 @@ Examples:
         FirefoxVersion(60, 0, 1, is_esr=True))      # '60.0.1esr'
 
 """
 
 import attr
 import re
 
 from mozilla_version.errors import (
-    PatternNotMatchedError, MissingFieldError, TooManyTypesError, NoVersionTypeError
+    PatternNotMatchedError, TooManyTypesError, NoVersionTypeError
 )
-from mozilla_version.parser import get_value_matched_by_regex
-from mozilla_version.version import VersionType
-
-
-def _positive_int(val):
-    if isinstance(val, float):
-        raise ValueError('"{}" must not be a float'.format(val))
-    val = int(val)
-    if val >= 0:
-        return val
-    raise ValueError('"{}" must be positive'.format(val))
-
-
-def _positive_int_or_none(val):
-    if val is None:
-        return val
-    return _positive_int(val)
-
-
-def _strictly_positive_int_or_none(val):
-    val = _positive_int_or_none(val)
-    if val is None or val > 0:
-        return val
-    raise ValueError('"{}" must be strictly positive'.format(val))
-
-
-def _does_regex_have_group(regex_matches, group_name):
-    try:
-        return regex_matches.group(group_name) is not None
-    except IndexError:
-        return False
+from mozilla_version.parser import strictly_positive_int_or_none
+from mozilla_version.version import BaseVersion, VersionType
 
 
 def _find_type(version):
     version_type = None
 
     def ensure_version_type_is_not_already_defined(previous_type, candidate_type):
         if previous_type is not None:
             raise TooManyTypesError(
@@ -112,18 +83,18 @@ def _find_type(version):
         version_type = VersionType.RELEASE
 
     if version_type is None:
         raise NoVersionTypeError(str(version))
 
     return version_type
 
 
-@attr.s(frozen=True, cmp=False)
-class GeckoVersion(object):
+@attr.s(frozen=True, cmp=False, hash=True)
+class GeckoVersion(BaseVersion):
     """Class that validates and handles version numbers for Gecko-based products.
 
     You may want to use specific classes like FirefoxVersion. These classes define edge cases
     that were shipped.
 
     Raises:
         PatternNotMatchedError: if the string doesn't match the pattern of a valid version number
         MissingFieldError: if a mandatory field is missing in the string. Mandatory fields are
@@ -148,62 +119,57 @@ class GeckoVersion(object):
             |(?P<is_esr>esr)
         )?
         -?(build(?P<build_number>\d+))?$""", re.VERBOSE)
 
     _ALL_VERSION_NUMBERS_TYPES = (
         'major_number', 'minor_number', 'patch_number', 'beta_number',
     )
 
-    major_number = attr.ib(type=int, converter=_positive_int)
-    minor_number = attr.ib(type=int, converter=_positive_int)
-    patch_number = attr.ib(type=int, converter=_positive_int_or_none, default=None)
-    build_number = attr.ib(type=int, converter=_strictly_positive_int_or_none, default=None)
-    beta_number = attr.ib(type=int, converter=_strictly_positive_int_or_none, default=None)
+    _OPTIONAL_NUMBERS = BaseVersion._OPTIONAL_NUMBERS + ('beta_number', 'build_number')
+
+    build_number = attr.ib(type=int, converter=strictly_positive_int_or_none, default=None)
+    beta_number = attr.ib(type=int, converter=strictly_positive_int_or_none, default=None)
     is_nightly = attr.ib(type=bool, default=False)
     is_aurora_or_devedition = attr.ib(type=bool, default=False)
     is_esr = attr.ib(type=bool, default=False)
     version_type = attr.ib(init=False, default=attr.Factory(_find_type, takes_self=True))
 
     def __attrs_post_init__(self):
         """Ensure attributes are sane all together."""
-        if (
-            (self.minor_number == 0 and self.patch_number == 0) or
-            (self.minor_number != 0 and self.patch_number is None) or
-            (self.beta_number is not None and self.patch_number is not None) or
-            (self.patch_number is not None and self.is_nightly) or
-            (self.patch_number is not None and self.is_aurora_or_devedition)
-        ):
-            raise PatternNotMatchedError(self, pattern='hard coded checks')
+        if self.minor_number == 0 and self.patch_number == 0:
+            raise PatternNotMatchedError(
+                self, pattern='Minor number and patch number cannot be both equal to 0'
+            )
+
+        if self.minor_number != 0 and self.patch_number is None:
+            raise PatternNotMatchedError(
+                self, pattern='Patch number cannot be undefined if minor number is greater than 0'
+            )
+
+        if self.beta_number is not None and self.patch_number is not None:
+            raise PatternNotMatchedError(
+                self, pattern='Beta number and patch number cannot be both defined'
+            )
+
+        if self.patch_number is not None and self.is_nightly:
+            raise PatternNotMatchedError(
+                self, pattern='Patch number cannot be defined on a nightly version'
+            )
+
+        if self.patch_number is not None and self.is_aurora_or_devedition:
+            raise PatternNotMatchedError(
+                self, pattern='Patch number cannot be defined on an aurora version'
+            )
 
     @classmethod
     def parse(cls, version_string):
         """Construct an object representing a valid Firefox version number."""
-        regex_matches = cls._VALID_ENOUGH_VERSION_PATTERN.match(version_string)
-
-        if regex_matches is None:
-            raise PatternNotMatchedError(version_string, cls._VALID_ENOUGH_VERSION_PATTERN)
-
-        args = {}
-
-        for field in ('major_number', 'minor_number'):
-            args[field] = get_value_matched_by_regex(field, regex_matches, version_string)
-        for field in ('patch_number', 'beta_number', 'build_number'):
-            try:
-                args[field] = get_value_matched_by_regex(field, regex_matches, version_string)
-            except MissingFieldError:
-                pass
-
-        return cls(
-            is_nightly=_does_regex_have_group(regex_matches, 'is_nightly'),
-            is_aurora_or_devedition=_does_regex_have_group(
-                regex_matches, 'is_aurora_or_devedition'
-            ),
-            is_esr=_does_regex_have_group(regex_matches, 'is_esr'),
-            **args
+        return super(GeckoVersion, cls).parse(
+            version_string, regex_groups=('is_nightly', 'is_aurora_or_devedition', 'is_esr')
         )
 
     @property
     def is_beta(self):
         """Return `True` if `FirefoxVersion` was built with a string matching a beta version."""
         return self.beta_number is not None
 
     @property
@@ -211,21 +177,17 @@ class GeckoVersion(object):
         """Return `True` if `FirefoxVersion` was built with a string matching a release version."""
         return not (self.is_nightly or self.is_aurora_or_devedition or self.is_beta or self.is_esr)
 
     def __str__(self):
         """Implement string representation.
 
         Computes a new string based on the given attributes.
         """
-        semvers = [str(self.major_number), str(self.minor_number)]
-        if self.patch_number is not None:
-            semvers.append(str(self.patch_number))
-
-        string = '.'.join(semvers)
+        string = super(GeckoVersion, self).__str__()
 
         if self.is_nightly:
             string = '{}a1'.format(string)
         elif self.is_aurora_or_devedition:
             string = '{}a2'.format(string)
         elif self.is_beta:
             string = '{}b{}'.format(string, self.beta_number)
         elif self.is_esr:
@@ -256,62 +218,35 @@ class GeckoVersion(object):
                 assert GeckoVersion.parse('60.0') != GeckoVersion.parse('60.1.0')
                 assert GeckoVersion.parse('60.0') != GeckoVersion.parse('60.0.1')
                 assert GeckoVersion.parse('60.0') != GeckoVersion.parse('60.0a1')
                 assert GeckoVersion.parse('60.0') != GeckoVersion.parse('60.0a2')
                 assert GeckoVersion.parse('60.0') != GeckoVersion.parse('60.0b1')
                 assert GeckoVersion.parse('60.0build1') != GeckoVersion.parse('60.0build2')
 
         """
-        return self._compare(other) == 0
-
-    def __ne__(self, other):
-        """Implement `!=` operator."""
-        return self._compare(other) != 0
-
-    def __lt__(self, other):
-        """Implement `<` operator."""
-        return self._compare(other) < 0
-
-    def __le__(self, other):
-        """Implement `<=` operator."""
-        return self._compare(other) <= 0
-
-    def __gt__(self, other):
-        """Implement `>` operator."""
-        return self._compare(other) > 0
-
-    def __ge__(self, other):
-        """Implement `>=` operator."""
-        return self._compare(other) >= 0
+        return super(GeckoVersion, self).__eq__(other)
 
     def _compare(self, other):
         """Compare this release with another.
 
         Returns:
             0 if equal
             < 0 is this precedes the other
             > 0 if the other precedes this
 
         """
         if isinstance(other, str):
             other = GeckoVersion.parse(other)
         elif not isinstance(other, GeckoVersion):
             raise ValueError('Cannot compare "{}", type not supported!'.format(other))
 
-        for field in ('major_number', 'minor_number', 'patch_number'):
-            this_number = getattr(self, field)
-            this_number = 0 if this_number is None else this_number
-            other_number = getattr(other, field)
-            other_number = 0 if other_number is None else other_number
-
-            difference = this_number - other_number
-
-            if difference != 0:
-                return difference
+        difference = super(GeckoVersion, self)._compare(other)
+        if difference != 0:
+            return difference
 
         channel_difference = self._compare_version_type(other)
         if channel_difference != 0:
             return channel_difference
 
         if self.is_beta and other.is_beta:
             beta_difference = self.beta_number - other.beta_number
             if beta_difference != 0:
@@ -419,16 +354,32 @@ class FennecVersion(_VersionWithEdgeCase
     }, {
         'major_number': 38,
         'minor_number': 0,
         'patch_number': 5,
         'beta_number': 4,
         'build_number': 1,
     })
 
+    def __attrs_post_init__(self):
+        """Ensure attributes are sane all together."""
+        # Versions matching 68.Xa1, 68.XbN, or simply 68.X are expected since bug 1523402. The
+        # latter is needed because of the version.txt of beta
+        if (
+            self.major_number == 68 and
+            self.minor_number > 0 and
+            self.patch_number is None
+        ):
+            return
+
+        if self.major_number >= 69:
+            raise PatternNotMatchedError(self, pattern='Last Fennec version is 68')
+
+        super(FennecVersion, self).__attrs_post_init__()
+
 
 class ThunderbirdVersion(_VersionWithEdgeCases):
     """Class that validates and handles Thunderbird version numbers."""
 
     _RELEASED_EDGE_CASES = ({
         'major_number': 45,
         'minor_number': 1,
         'beta_number': 1,
new file mode 100644
--- /dev/null
+++ b/third_party/python/mozilla-version/mozilla_version/maven.py
@@ -0,0 +1,56 @@
+"""Defines characteristics of a Maven version at Mozilla."""
+
+import attr
+import re
+
+from mozilla_version.version import BaseVersion
+
+
+@attr.s(frozen=True, cmp=False, hash=True)
+class MavenVersion(BaseVersion):
+    """Class that validates and handles Maven version numbers.
+
+    At Mozilla, Maven packages are used in projects like "GeckoView" or "Android-Components".
+    """
+
+    is_snapshot = attr.ib(type=bool, default=False)
+
+    _VALID_ENOUGH_VERSION_PATTERN = re.compile(r"""
+        ^(?P<major_number>\d+)
+        \.(?P<minor_number>\d+)
+        (\.(?P<patch_number>\d+))?
+        (?P<is_snapshot>-SNAPSHOT)?$""", re.VERBOSE)
+
+    @classmethod
+    def parse(cls, version_string):
+        """Construct an object representing a valid Maven version number."""
+        return super(MavenVersion, cls).parse(version_string, regex_groups=('is_snapshot', ))
+
+    def __str__(self):
+        """Implement string representation.
+
+        Computes a new string based on the given attributes.
+        """
+        string = super(MavenVersion, self).__str__()
+
+        if self.is_snapshot:
+            string = '{}-SNAPSHOT'.format(string)
+
+        return string
+
+    def _compare(self, other):
+        if isinstance(other, str):
+            other = MavenVersion.parse(other)
+        elif not isinstance(other, MavenVersion):
+            raise ValueError('Cannot compare "{}", type not supported!'.format(other))
+
+        difference = super(MavenVersion, self)._compare(other)
+        if difference != 0:
+            return difference
+
+        if not self.is_snapshot and other.is_snapshot:
+            return 1
+        elif self.is_snapshot and not other.is_snapshot:
+            return -1
+        else:
+            return 0
--- a/third_party/python/mozilla-version/mozilla_version/parser.py
+++ b/third_party/python/mozilla-version/mozilla_version/parser.py
@@ -8,8 +8,41 @@ def get_value_matched_by_regex(field_nam
     try:
         value = regex_matches.group(field_name)
         if value is not None:
             return value
     except IndexError:
         pass
 
     raise MissingFieldError(string, field_name)
+
+
+def does_regex_have_group(regex_matches, group_name):
+    """Return a boolean depending on whether a regex group is matched."""
+    try:
+        return regex_matches.group(group_name) is not None
+    except IndexError:
+        return False
+
+
+def positive_int(val):
+    """Parse `val` into a positive integer."""
+    if isinstance(val, float):
+        raise ValueError('"{}" must not be a float'.format(val))
+    val = int(val)
+    if val >= 0:
+        return val
+    raise ValueError('"{}" must be positive'.format(val))
+
+
+def positive_int_or_none(val):
+    """Parse `val` into either `None` or a positive integer."""
+    if val is None:
+        return val
+    return positive_int(val)
+
+
+def strictly_positive_int_or_none(val):
+    """Parse `val` into either `None` or a strictly positive integer."""
+    val = positive_int_or_none(val)
+    if val is None or val > 0:
+        return val
+    raise ValueError('"{}" must be strictly positive'.format(val))
--- a/third_party/python/mozilla-version/mozilla_version/test/__init__.py
+++ b/third_party/python/mozilla-version/mozilla_version/test/__init__.py
@@ -0,0 +1,5 @@
+from contextlib import contextmanager
+
+@contextmanager
+def does_not_raise():
+    yield
--- a/third_party/python/mozilla-version/mozilla_version/test/test_balrog.py
+++ b/third_party/python/mozilla-version/mozilla_version/test/test_balrog.py
@@ -159,8 +159,14 @@ def test_balrog_release_implements_remai
     assert BalrogReleaseName.parse('firefox-33.0-build1') >= BalrogReleaseName.parse('firefox-33.0-build1')
 
     assert BalrogReleaseName.parse('firefox-33.0-build1') > BalrogReleaseName.parse('firefox-32.0-build1')
     assert not BalrogReleaseName.parse('firefox-33.0-build1') > BalrogReleaseName.parse('firefox-33.0-build1')
 
     assert not BalrogReleaseName.parse('firefox-32.0-build1') < BalrogReleaseName.parse('firefox-32.0-build1')
 
     assert BalrogReleaseName.parse('firefox-33.0-build1') != BalrogReleaseName.parse('firefox-32.0-build1')
+
+def test_balrog_release_hashable():
+    """
+    It is possible to hash `BalrogReleaseNmae`.
+    """
+    hash(BalrogReleaseName.parse('firefox-63.0-build1'))
--- a/third_party/python/mozilla-version/mozilla_version/test/test_gecko.py
+++ b/third_party/python/mozilla-version/mozilla_version/test/test_gecko.py
@@ -2,18 +2,20 @@ import pytest
 import re
 
 from distutils.version import StrictVersion, LooseVersion
 
 import mozilla_version.gecko
 
 from mozilla_version.errors import PatternNotMatchedError, TooManyTypesError, NoVersionTypeError
 from mozilla_version.gecko import (
-    FirefoxVersion, DeveditionVersion, ThunderbirdVersion, FennecVersion, GeckoSnapVersion
+    GeckoVersion, FirefoxVersion, DeveditionVersion,
+    ThunderbirdVersion, FennecVersion, GeckoSnapVersion,
 )
+from mozilla_version.test import does_not_raise
 
 
 VALID_VERSIONS = {
     '32.0a1': 'nightly',
     '32.0a2': 'aurora_or_devedition',
     '32.0b2': 'beta',
     '32.0b10': 'beta',
     '32.0': 'release',
@@ -324,16 +326,54 @@ def test_fennec_version_supports_release
     for Class in (FirefoxVersion, DeveditionVersion, ThunderbirdVersion):
         if Class == FirefoxVersion and version_string in ('33.1', '33.1build1', '33.1build2'):
             # These edge cases also exist in Firefox
             continue
         with pytest.raises(PatternNotMatchedError):
             Class.parse(version_string)
 
 
+@pytest.mark.parametrize('version_string, expectation', (
+    ('68.0a1', does_not_raise()),
+    ('68.0b3', does_not_raise()),
+    ('68.0b17', does_not_raise()),
+    ('68.0', does_not_raise()),
+    ('68.0.1', does_not_raise()),
+    ('68.1a1', does_not_raise()),
+    ('68.1b2', does_not_raise()),
+    ('68.1.0', does_not_raise()),
+    ('68.1', does_not_raise()),
+    ('68.1b3', does_not_raise()),
+    ('68.1.1', does_not_raise()),
+    ('68.2a1', does_not_raise()),
+    ('68.2b1', does_not_raise()),
+    ('68.2', does_not_raise()),
+
+    ('67.1', pytest.raises(PatternNotMatchedError)),
+    ('68.0.1a1', pytest.raises(PatternNotMatchedError)),
+    ('68.1a1b1', pytest.raises(PatternNotMatchedError)),
+    ('68.0.1b1', pytest.raises(PatternNotMatchedError)),
+    ('68.1.0a1', pytest.raises(PatternNotMatchedError)),
+    ('68.1.0b1', pytest.raises(PatternNotMatchedError)),
+    ('68.1.1a1', pytest.raises(PatternNotMatchedError)),
+    ('68.1.1b2', pytest.raises(PatternNotMatchedError)),
+
+    ('69.0a1', pytest.raises(PatternNotMatchedError)),
+    ('69.0b3', pytest.raises(PatternNotMatchedError)),
+    ('69.0', pytest.raises(PatternNotMatchedError)),
+    ('69.0.1', pytest.raises(PatternNotMatchedError)),
+    ('69.1', pytest.raises(PatternNotMatchedError)),
+
+    ('70.0', pytest.raises(PatternNotMatchedError)),
+))
+def test_fennec_version_ends_at_68(version_string, expectation):
+    with expectation:
+        FennecVersion.parse(version_string)
+
+
 @pytest.mark.parametrize('version_string', (
     '45.1b1', '45.1b1build1',
     '45.2', '45.2build1', '45.2build2',
     '45.2b1', '45.2b1build2',
 ))
 def test_thunderbird_version_supports_released_edge_cases(version_string):
     assert str(ThunderbirdVersion.parse(version_string)) == version_string
     for Class in (FirefoxVersion, DeveditionVersion, FennecVersion):
@@ -356,9 +396,16 @@ def test_gecko_snap_version(version_stri
     '32.0a2', '32.0esr1', '32.0-build1',
 ))
 def test_gecko_snap_version_bails_on_wrong_version(version_string):
     with pytest.raises(PatternNotMatchedError):
         GeckoSnapVersion.parse(version_string)
 
 
 def test_gecko_snap_version_implements_its_own_string():
-    str(GeckoSnapVersion.parse('63.0b7-1')) == '63.0b7-1'
+    assert str(GeckoSnapVersion.parse('63.0b7-1')) == '63.0b7-1'
+
+
+def test_gecko_version_hashable():
+    """
+    It is possible to hash `GeckoVersion`.
+    """
+    hash(GeckoVersion.parse('63.0'))
new file mode 100644
--- /dev/null
+++ b/third_party/python/mozilla-version/mozilla_version/test/test_maven.py
@@ -0,0 +1,87 @@
+import pytest
+
+from distutils.version import LooseVersion, StrictVersion
+
+from mozilla_version.errors import PatternNotMatchedError
+from mozilla_version.maven import MavenVersion
+
+@pytest.mark.parametrize('major_number, minor_number, patch_number, is_snapshot, expected_output_string', ((
+    32, 0, None, False, '32.0'
+), (
+    32, 0, 1, False, '32.0.1'
+), (
+    32, 0, None, True, '32.0-SNAPSHOT'
+), (
+    32, 0, 1, True, '32.0.1-SNAPSHOT'
+)))
+def test_maven_version_constructor_and_str(major_number, minor_number, patch_number, is_snapshot, expected_output_string):
+    assert str(MavenVersion(
+        major_number=major_number,
+        minor_number=minor_number,
+        patch_number=patch_number,
+        is_snapshot=is_snapshot,
+    )) == expected_output_string
+
+
+def test_maven_version_constructor_minimum_kwargs():
+    assert str(MavenVersion(32, 0)) == '32.0'
+    assert str(MavenVersion(32, 0, 1)) == '32.0.1'
+    assert str(MavenVersion(32, 1, 0)) == '32.1.0'
+    assert str(MavenVersion(32, 1, 0, False)) == '32.1.0'
+    assert str(MavenVersion(32, 1, 0, True)) == '32.1.0-SNAPSHOT'
+
+
+@pytest.mark.parametrize('version_string, ExpectedErrorType', (
+    ('32.0SNAPSHOT', PatternNotMatchedError),
+    ('32.1.0SNAPSHOT', PatternNotMatchedError),
+))
+def test_maven_version_raises_when_invalid_version_is_given(version_string, ExpectedErrorType):
+    with pytest.raises(ExpectedErrorType):
+        MavenVersion.parse(version_string)
+
+
+@pytest.mark.parametrize('previous, next', (
+    ('32.0-SNAPSHOT', '32.0'),
+    ('31.0', '32.0-SNAPSHOT'),
+    ('32.0', '32.0.1-SNAPSHOT'),
+    ('32.0.1-SNAPSHOT', '32.1.0'),
+    ('32.0.1-SNAPSHOT', '33.0'),
+))
+def test_maven_version_implements_lt_operator(previous, next):
+    assert MavenVersion.parse(previous) < MavenVersion.parse(next)
+
+
+@pytest.mark.parametrize('previous, next', (
+    ('32.0', '32.0-SNAPSHOT'),
+    ('32.0-SNAPSHOT', '31.0'),
+    ('32.0.1-SNAPSHOT', '32.0'),
+    ('32.1.0', '32.0.1-SNAPSHOT'),
+))
+def test_maven_version_implements_gt_operator(previous, next):
+    assert MavenVersion.parse(previous) > MavenVersion.parse(next)
+
+
+@pytest.mark.parametrize('wrong_type', (
+    32,
+    32.0,
+    ('32', '0', '1'),
+    ['32', '0', '1'],
+    LooseVersion('32.0'),
+    StrictVersion('32.0'),
+))
+def test_base_version_raises_eq_operator(wrong_type):
+    with pytest.raises(ValueError):
+        assert MavenVersion.parse('32.0') == wrong_type
+    # AttributeError is raised by LooseVersion and StrictVersion
+    with pytest.raises((ValueError, AttributeError)):
+        assert wrong_type == MavenVersion.parse('32.0')
+
+
+def test_maven_version_implements_eq_operator():
+    assert MavenVersion.parse('32.0-SNAPSHOT') == MavenVersion.parse('32.0-SNAPSHOT')
+    # raw strings are also converted
+    assert MavenVersion.parse('32.0-SNAPSHOT') == '32.0-SNAPSHOT'
+
+
+def test_maven_version_hashable():
+    hash(MavenVersion.parse('32.0.1'))
--- a/third_party/python/mozilla-version/mozilla_version/test/test_version.py
+++ b/third_party/python/mozilla-version/mozilla_version/test/test_version.py
@@ -1,11 +1,128 @@
 import pytest
 
-from mozilla_version.version import VersionType
+from distutils.version import LooseVersion, StrictVersion
+
+from mozilla_version.errors import PatternNotMatchedError
+from mozilla_version.version import BaseVersion, VersionType
+
+
+@pytest.mark.parametrize('major_number, minor_number, patch_number, expected_output_string', ((
+    32, 0, None, '32.0'
+), (
+    32, 0, 1, '32.0.1'
+)))
+def test_base_version_constructor_and_str(major_number, minor_number, patch_number, expected_output_string):
+    assert str(BaseVersion(
+        major_number=major_number,
+        minor_number=minor_number,
+        patch_number=patch_number,
+    )) == expected_output_string
+
+
+@pytest.mark.parametrize('major_number, minor_number, patch_number, ExpectedErrorType', ((
+    -1, 0, None, ValueError
+), (
+    32, -1, None, ValueError
+), (
+    32, 0, -1, ValueError
+), (
+    2.2, 0, 0, ValueError
+), (
+    'some string', 0, 0, ValueError
+)))
+def test_fail_base_version_constructor(major_number, minor_number, patch_number, ExpectedErrorType):
+    with pytest.raises(ExpectedErrorType):
+        BaseVersion(
+            major_number=major_number,
+            minor_number=minor_number,
+            patch_number=patch_number,
+        )
+
+
+def test_base_version_constructor_minimum_kwargs():
+    assert str(BaseVersion(32, 0)) == '32.0'
+    assert str(BaseVersion(32, 0, 1)) == '32.0.1'
+    assert str(BaseVersion(32, 1, 0)) == '32.1.0'
+
+
+@pytest.mark.parametrize('version_string, ExpectedErrorType', (
+    ('32', PatternNotMatchedError),
+    ('.1', PatternNotMatchedError),
+))
+def test_base_version_raises_when_invalid_version_is_given(version_string, ExpectedErrorType):
+    with pytest.raises(ExpectedErrorType):
+        BaseVersion.parse(version_string)
+
+
+@pytest.mark.parametrize('previous, next', (
+    ('32.0', '33.0'),
+    ('32.0', '32.1.0'),
+    ('32.0', '32.0.1'),
+
+    ('32.0.1', '33.0'),
+    ('32.0.1', '32.1.0'),
+    ('32.0.1', '32.0.2'),
+
+    ('32.1.0', '33.0'),
+    ('32.1.0', '32.2.0'),
+    ('32.1.0', '32.1.1'),
+
+    ('2.0', '10.0'),
+    ('10.2.0', '10.10.0'),
+    ('10.0.2', '10.0.10'),
+    ('10.10.1', '10.10.10'),
+))
+def test_base_version_implements_lt_operator(previous, next):
+    assert BaseVersion.parse(previous) < BaseVersion.parse(next)
+
+
+@pytest.mark.parametrize('equivalent_version_string', (
+    '32.0', '032.0', '32.00'
+))
+def test_base_version_implements_eq_operator(equivalent_version_string):
+    assert BaseVersion.parse('32.0') == BaseVersion.parse(equivalent_version_string)
+    # raw strings are also converted
+    assert BaseVersion.parse('32.0') == equivalent_version_string
+
+
+@pytest.mark.parametrize('wrong_type', (
+    32,
+    32.0,
+    ('32', '0', '1'),
+    ['32', '0', '1'],
+    LooseVersion('32.0'),
+    StrictVersion('32.0'),
+))
+def test_base_version_raises_eq_operator(wrong_type):
+    with pytest.raises(ValueError):
+        assert BaseVersion.parse('32.0') == wrong_type
+    # AttributeError is raised by LooseVersion and StrictVersion
+    with pytest.raises((ValueError, AttributeError)):
+        assert wrong_type == BaseVersion.parse('32.0')
+
+
+def test_base_version_implements_remaining_comparision_operators():
+    assert BaseVersion.parse('32.0') <= BaseVersion.parse('32.0')
+    assert BaseVersion.parse('32.0') <= BaseVersion.parse('33.0')
+
+    assert BaseVersion.parse('33.0') >= BaseVersion.parse('32.0')
+    assert BaseVersion.parse('33.0') >= BaseVersion.parse('33.0')
+
+    assert BaseVersion.parse('33.0') > BaseVersion.parse('32.0')
+    assert not BaseVersion.parse('33.0') > BaseVersion.parse('33.0')
+
+    assert not BaseVersion.parse('32.0') < BaseVersion.parse('32.0')
+
+    assert BaseVersion.parse('33.0') != BaseVersion.parse('32.0')
+
+
+def test_base_version_hashable():
+    hash(BaseVersion.parse('63.0'))
 
 
 @pytest.mark.parametrize('previous, next', (
     (VersionType.NIGHTLY, VersionType.AURORA_OR_DEVEDITION),
     (VersionType.NIGHTLY, VersionType.BETA),
     (VersionType.NIGHTLY, VersionType.RELEASE),
     (VersionType.NIGHTLY, VersionType.ESR),
 
--- a/third_party/python/mozilla-version/mozilla_version/version.py
+++ b/third_party/python/mozilla-version/mozilla_version/version.py
@@ -1,12 +1,126 @@
 """Defines common characteristics of a version at Mozilla."""
 
+import attr
+import re
+
 from enum import Enum
 
+from mozilla_version.errors import MissingFieldError, PatternNotMatchedError
+from mozilla_version.parser import (
+    get_value_matched_by_regex,
+    does_regex_have_group,
+    positive_int,
+    positive_int_or_none
+)
+
+
+@attr.s(frozen=True, cmp=False, hash=True)
+class BaseVersion(object):
+    """Class that validates and handles general version numbers."""
+
+    major_number = attr.ib(type=int, converter=positive_int)
+    minor_number = attr.ib(type=int, converter=positive_int)
+    patch_number = attr.ib(type=int, converter=positive_int_or_none, default=None)
+
+    _MANDATORY_NUMBERS = ('major_number', 'minor_number')
+    _OPTIONAL_NUMBERS = ('patch_number', )
+    _ALL_NUMBERS = _MANDATORY_NUMBERS + _OPTIONAL_NUMBERS
+
+    _VALID_ENOUGH_VERSION_PATTERN = re.compile(r"""
+        ^(?P<major_number>\d+)
+        \.(?P<minor_number>\d+)
+        (\.(?P<patch_number>\d+))?$""", re.VERBOSE)
+
+    @classmethod
+    def parse(cls, version_string, regex_groups=()):
+        """Construct an object representing a valid version number."""
+        regex_matches = cls._VALID_ENOUGH_VERSION_PATTERN.match(version_string)
+
+        if regex_matches is None:
+            raise PatternNotMatchedError(version_string, cls._VALID_ENOUGH_VERSION_PATTERN)
+
+        kwargs = {}
+
+        for field in cls._MANDATORY_NUMBERS:
+            kwargs[field] = get_value_matched_by_regex(field, regex_matches, version_string)
+        for field in cls._OPTIONAL_NUMBERS:
+            try:
+                kwargs[field] = get_value_matched_by_regex(field, regex_matches, version_string)
+            except MissingFieldError:
+                pass
+
+        for regex_group in regex_groups:
+            kwargs[regex_group] = does_regex_have_group(regex_matches, regex_group)
+
+        return cls(**kwargs)
+
+    def __str__(self):
+        """Implement string representation.
+
+        Computes a new string based on the given attributes.
+        """
+        semvers = [str(self.major_number), str(self.minor_number)]
+        if self.patch_number is not None:
+            semvers.append(str(self.patch_number))
+
+        return '.'.join(semvers)
+
+    def __eq__(self, other):
+        """Implement `==` operator."""
+        return self._compare(other) == 0
+
+    def __ne__(self, other):
+        """Implement `!=` operator."""
+        return self._compare(other) != 0
+
+    def __lt__(self, other):
+        """Implement `<` operator."""
+        return self._compare(other) < 0
+
+    def __le__(self, other):
+        """Implement `<=` operator."""
+        return self._compare(other) <= 0
+
+    def __gt__(self, other):
+        """Implement `>` operator."""
+        return self._compare(other) > 0
+
+    def __ge__(self, other):
+        """Implement `>=` operator."""
+        return self._compare(other) >= 0
+
+    def _compare(self, other):
+        """Compare this release with another.
+
+        Returns:
+            0 if equal
+            < 0 is this precedes the other
+            > 0 if the other precedes this
+
+        """
+        if isinstance(other, str):
+            other = BaseVersion.parse(other)
+        elif not isinstance(other, BaseVersion):
+            raise ValueError('Cannot compare "{}", type not supported!'.format(other))
+
+        for field in ('major_number', 'minor_number', 'patch_number'):
+            this_number = getattr(self, field)
+            this_number = 0 if this_number is None else this_number
+            other_number = getattr(other, field)
+            other_number = 0 if other_number is None else other_number
+
+            difference = this_number - other_number
+
+            if difference != 0:
+                return difference
+
+        return 0
+
 
 class VersionType(Enum):
     """Enum that sorts types of versions (e.g.: nightly, beta, release, esr).
 
     Supports comparison. `ESR` is considered higher than `RELEASE` (even if they technically have
     the same codebase). For instance: 60.0.1 < 60.0.1esr but 61.0 > 60.0.1esr.
     This choice has a practical use case: if you have a list of Release and ESR version, you can
     easily extract one kind or the other thanks to the VersionType.
@@ -54,8 +168,10 @@ class VersionType(Enum):
 
         Returns:
             0 if equal
             < 0 is this precedes the other
             > 0 if the other precedes this
 
         """
         return self.value - other.value
+
+    __hash__ = Enum.__hash__
--- a/third_party/python/mozilla-version/requirements-coveralls.txt
+++ b/third_party/python/mozilla-version/requirements-coveralls.txt
@@ -1,61 +1,140 @@
-# Generated from dephash.py + hashin.py
-certifi==2018.8.24 \
-    --hash=sha512:bb0af24570dd4806bc80cd438cae42db82f820de815a6148b184f58c19cd91a03f9275815559817a84220dcbd7c87a4a7d12e35cf4a95a1dbad286a1dfecf907 \
-    --hash=sha512:e6a6272bac21007738a0e694da3ab4480f9e522cc6b71ce61a12eb21545c9417c87baea4e2eec6df1be9bd3ac2de8403583f8b7d3efcd7ed9a6b53f53cfb1072
+#
+# This file is autogenerated by pip-compile
+# To update, run:
+#
+#    pip-compile --generate-hashes --output-file requirements-coveralls.txt requirements-coveralls.txt.in
+#
+asn1crypto==0.24.0 \
+    --hash=sha256:2f1adbb7546ed199e3c90ef23ec95c5cf3585bac7d11fb7eb562a3fe89c64e87 \
+    --hash=sha256:9d5c20441baf0cb60a4ac34cc447c6c189024b6b4c6cd7877034f4965c464e49 \
+    # via cryptography
+certifi==2018.11.29 \
+    --hash=sha256:47f9c83ef4c0c621eaef743f133f09fa8a74a9b75f037e8624f83bd1b6626cb7 \
+    --hash=sha256:993f830721089fef441cdfeb4b2c8c9df86f0c63239f06bd025a76a7daddb033 \
+    # via requests, urllib3
+cffi==1.12.1 \
+    --hash=sha256:0b5f895714a7a9905148fc51978c62e8a6cbcace30904d39dcd0d9e2265bb2f6 \
+    --hash=sha256:27cdc7ba35ee6aa443271d11583b50815c4bb52be89a909d0028e86c21961709 \
+    --hash=sha256:2d4a38049ea93d5ce3c7659210393524c1efc3efafa151bd85d196fa98fce50a \
+    --hash=sha256:3262573d0d60fc6b9d0e0e6e666db0e5045cbe8a531779aa0deb3b425ec5a282 \
+    --hash=sha256:358e96cfffc185ab8f6e7e425c7bb028931ed08d65402fbcf3f4e1bff6e66556 \
+    --hash=sha256:37c7db824b5687fbd7ea5519acfd054c905951acc53503547c86be3db0580134 \
+    --hash=sha256:39b9554dfe60f878e0c6ff8a460708db6e1b1c9cc6da2c74df2955adf83e355d \
+    --hash=sha256:42b96a77acf8b2d06821600fa87c208046decc13bd22a4a0e65c5c973443e0da \
+    --hash=sha256:5b37dde5035d3c219324cac0e69d96495970977f310b306fa2df5910e1f329a1 \
+    --hash=sha256:5d35819f5566d0dd254f273d60cf4a2dcdd3ae3003dfd412d40b3fe8ffd87509 \
+    --hash=sha256:5df73aa465e53549bd03c819c1bc69fb85529a5e1a693b7b6cb64408dd3970d1 \
+    --hash=sha256:7075b361f7a4d0d4165439992d0b8a3cdfad1f302bf246ed9308a2e33b046bd3 \
+    --hash=sha256:7678b5a667b0381c173abe530d7bdb0e6e3b98e062490618f04b80ca62686d96 \
+    --hash=sha256:7dfd996192ff8a535458c17f22ff5eb78b83504c34d10eefac0c77b1322609e2 \
+    --hash=sha256:8a3be5d31d02c60f84c4fd4c98c5e3a97b49f32e16861367f67c49425f955b28 \
+    --hash=sha256:9812e53369c469506b123aee9dcb56d50c82fad60c5df87feb5ff59af5b5f55c \
+    --hash=sha256:9b6f7ba4e78c52c1a291d0c0c0bd745d19adde1a9e1c03cb899f0c6efd6f8033 \
+    --hash=sha256:a85bc1d7c3bba89b3d8c892bc0458de504f8b3bcca18892e6ed15b5f7a52ad9d \
+    --hash=sha256:aa6b9c843ad645ebb12616de848cc4e25a40f633ccc293c3c9fe34107c02c2ea \
+    --hash=sha256:bae1aa56ee00746798beafe486daa7cfb586cd395c6ce822ba3068e48d761bc0 \
+    --hash=sha256:bae96e26510e4825d5910a196bf6b5a11a18b87d9278db6d08413be8ea799469 \
+    --hash=sha256:bd78df3b594013b227bf31d0301566dc50ba6f40df38a70ded731d5a8f2cb071 \
+    --hash=sha256:c2711197154f46d06f73542c539a0ff5411f1951fab391e0a4ac8359badef719 \
+    --hash=sha256:d998c20e3deed234fca993fd6c8314cb7cbfda05fd170f1bd75bb5d7421c3c5a \
+    --hash=sha256:df4f840d77d9e37136f8e6b432fecc9d6b8730f18f896e90628712c793466ce6 \
+    --hash=sha256:f5653c2581acb038319e6705d4e3593677676df14b112f13e0b5b44b6a18df1a \
+    --hash=sha256:f7c7aa485a2e2250d455148470ffd0195eecc3d845122635202d7467d6f7b4cf \
+    --hash=sha256:f9e2c66a6493147de835f207f198540a56b26745ce4f272fbc7c2f2cfebeb729    # via cryptography
 chardet==3.0.4 \
-    --hash=sha512:61a03b23447a2bfe52ceed4dd1b9afdb5784da1933a623776883ee9f297e341f633e27f0ce0230bd5fdc5fdb5382105ab42736a74a417ddeb9f83af57455dba5 \
-    --hash=sha512:bfae58c8ea19c87cc9c9bf3d0b6146bfdb3630346bd954fe8e9f7da1f09da1fc0d6943ff04802798a665ea3b610ee2d65658ce84fe5a89f9e93625ea396a17f4
-coverage==4.5.1 \
-    --hash=sha512:0d656cb22528744a8ef0853f2fa7b96f20fdd49f3c439c3211076e6aac1509c216138e31e24ba92e3945ad4dc81d58ef4b147c092e888a1acbc840d8187617e8 \
-    --hash=sha512:1bed7f91763ae47fc7a0548766029328f059c25fbdd292f2b313d867b93f161cb35b9e612894682b1f486d52c91e06ff7173a2274d6d098657e69de35768f854 \
-    --hash=sha512:2520e0ba3adf1485e7d583ff1f14643bdbe531b4062353780b80737d08330adddb7ab6ad869a2542a261760b4be1d050182fe0f91061610463ee972298fe518e \
-    --hash=sha512:2b5ad59f6570e22021ab96a9cba9bfad78469a248dec032a227a2fccd1b110ab7f38a5076a44a1a471b37077e7100b0f9c51fe370b8467f9dbedae498a042581 \
-    --hash=sha512:309fe4c70de41671afc4fefbc959f0d16d54df3ca95c80b11f9ac8b86b6ea117a714f1c36f6f9976c1951a6760747e9b2de9de60943adc8b39482892f5ce5f7b \
-    --hash=sha512:338a31e1a1856073501a02eaefaae2c18df27140598472d34a8432c9c25225296eab81567729a2cc165a4c9d8faeabb1e3bbb52ce840d394ba0f0c5f6baf2528 \
-    --hash=sha512:3d84ef3f2078ced6010f7192fb5fbe1c0f12c11118cb756ff8b46c453327ec61639f47799b8338a0565033641abbcc6e3c5f394020cab2ffdddec04bb489bf1f \
-    --hash=sha512:45126acc107f5a7fcb015c9b866a3b0d0101e9211fdecc5843f334fea28a2d80db1048e752d1d6f860687c9f289e03678cf2d92a77779a355b9b186a772d3353 \
-    --hash=sha512:45abe32fa09505e436c8cae010e3866399dee551c13fb5a35da57cd296502b9f266332d278671ebdb7ccab941326daeb1e27118821862e249ee985ef4a6d0d35 \
-    --hash=sha512:4757a11361a9d4f757082f885512e6b4de24b60344646ad09741c84e4fb4f08813f05aa18a7acb3451a331a91fb9d27ef411bf9348b54d3d7cd3074e4645f41b \
-    --hash=sha512:4ae653511277a5bb984142286e01157e1a068c01a16c825adf06287e569cc516ca056e6fefcb05b2038f31ca261b5fa8ef345a6c0274650b3de175a694188b95 \
-    --hash=sha512:55decd6e6d369682b67c9a82ccf5772538e004279a657d6d9f75482ff20896360b37b4841d08d79996ce16956bb863d2a2bb33e2ee7d5b06fd3e79adf96548df \
-    --hash=sha512:5ad7ec5b9be01298957c22704a2689e2e9c9c3dc12e11570fbc4a5f382432a854bcea75e4419e953175da3aa2ee1d2ec2f244886db5188f7cc8d9e231b29cc2e \
-    --hash=sha512:7927c89140e844f56917746f41a866755ffcb72d8028bd23ab055446f90231d0c1f4ccc29d67fada8155a5c927b4559f3e263e49659755dc847ebd4b7aa6e392 \
-    --hash=sha512:798fd2eb99a17cdcfd7b2f2d95fc319fb860e041b982b4e7c9d1ccbff41c35f19d5ca16e3605e2222cd30a4ed3cddfe94149b1b2ec27a54efd1ea6474b9ccb1b \
-    --hash=sha512:82742a572549400778cad99057b1ced4c36b61e917983148eccc86bfa6340de8cfefc4f743e79ff876b641e0b9d21307dd6bde78638a6b20dd8ad215068dda25 \
-    --hash=sha512:8510d0846aa24b5fbbdd74c0e38ab29c8fce7cc96ff473f4b52fa8044fcafcfb54449e8aaab29efe7c73a3530167231412b14ccf10e6cb34c9838adf63826019 \
-    --hash=sha512:89e12e4b7ee82e2f2f92c75697ac30bdbc214d9b8fb0bd5aa21e657eac1800f8fb1b44ae9c1d8ae07666d0b0d9a5a1f681b555fcc2d141f1ad15ab589e005243 \
-    --hash=sha512:980260b63b49b697a543184e0233996ba6fa4df8c6976227ae6c20dd650f1a094f4115a3e999222e73806f191bf7ce2a2848bd60a690dd1737b102928f25f3bc \
-    --hash=sha512:9b24bda59e374374dbd48973d118e039fdeeff3d193411533aed90e3d425ddd5ad5419903e2cc7a719a4ff04bbd066eb3e11e153ee8df339dae03dcc8c25b9c0 \
-    --hash=sha512:9c0b13abc5376eaff78c4e7f2a945bb86965969ea1ab3571d2209f91df078c1a779ee42f47bf96e62fe9bd63668e49edfaa0b00525c18d2cbbd155781fa2201b \
-    --hash=sha512:9dd03ce95b1a107337b226d46dcd9e6fdf3b388426ac0508cb1b6c5c43423f22b8b35828e9d89dcc08483525b3bc2de1334fe7e85bfaae9d64f64933ef9fe3ce \
-    --hash=sha512:a5cbfd1cd7e5212285c28dec4e8b8354b6b189cde501f078746e5dc45216f4d24479eef18a612c00bfe94192ab48deb79150cd261ff42254ab83205dc58ff77b \
-    --hash=sha512:a7892f7106be5ab0670d32b4e8d10ec9e1336e4706d94666c084be17f4519672aa84c2dbfa4028b43433ea51ed29ffe175ab3908b91f5329578c7a6bbde7df91 \
-    --hash=sha512:ac9dc454f928a9e7fbd8e4a98bfce0511415cac69e80cf0a098afa504d9c6585c2eeac0553f20d3edd297770f5744e8f03ddb0a17f62bde70caf3779d11e32b9 \
-    --hash=sha512:b0b004871cfd6f1b949a4ddc37544a73c1446602109b671c6752baa3776e4f08dfe340c1c75299c62612c43fba652ee92e3481bb39ecb7e9b02643a041becac4 \
-    --hash=sha512:b202a7278ebb3c87d6fcd2f1cff7dc88d78fa7eae709a73e6207c6212f962e706f84f22c14dad6c5c3e8be7eef7c1806c3f66e8f1e557c6127aea0a97a797b0f \
-    --hash=sha512:b388092fe437bfc8bc10205ffaa5a43e418e39e1f0e3509ef03721149c5904455142eadfc28d414007f93e5d0deb39231b59b35cba82ea884809c60020b1cfa3 \
-    --hash=sha512:c718f78a365a5b610cb2f1fe8ca646b83d6439912cfb9f787e57cc84dc84eea6f3150660231acd093dfa84d2f4f8135f7f2512fb05a1978e1b12c3fd8b23f505 \
-    --hash=sha512:d0662ad14ebb76454571ed5b083e62bd35e57cd801f627dd1d286ccfce7c271109a814f73e26fb402d60c23ae08ac96f29ca62a43cbbcb027e72b349ec9f296f \
-    --hash=sha512:d329341278272c48270cb8eb712257ce9970c665606351064d02ce37424c42407e833e4688e938c3e88804451e15cb5287dedc91e0fe5a66cb5cc201f791ab1c \
-    --hash=sha512:d4b9569efa13c9a316a0bc99e7c163a474ed7022df0445ed5811e0ad4e53f0316472e3c8b8540f995d0d6abaae5025796d876f5322e63819fb469a7f1a5419a9 \
-    --hash=sha512:d6788611162a863a8a274473b6dcdaefadccd0f42f6732431cdb12ebd5300987eb3db29df0f305528bbe9766b87baba9a6dca0460089cab5aa11b1ca727d3af8 \
-    --hash=sha512:d987c1fee355cfc7d6bdc89234295b7dd35941449f14dc5c8efac28bb98894f9a78d558dd02a05457a97916de070ae386127be7197efc3b511c4f7a7f056f189 \
-    --hash=sha512:dba0935c4079bfce694866d6598408db305b82063ed4b0dcaf5d4260a70b25118aa3d72ff81ba3326dcb6377734c4fa5811740543331ce6eb1c9886e621217ac \
-    --hash=sha512:e01685335bd44d0c767429568adc5fb3669417354b62d634bb06fcdfaa959102ff1105f3b108046047a4dffd24bbce5bf81fcdd61b49a45f2aad32a83034dc9c \
-    --hash=sha512:f673f86b32764a023d32626939217d56c53029a4de83f7ef018f8a76e5ee2d0090f3395e6c79098c73f3dbe66ae14355ca3e3bb799275b7229bf198dc4864236 \
-    --hash=sha512:f96a049d5dda5b2ca4e135a561d8ad9a1a511603e553996e07ee6e46a3573afea1ffe895d2897e3c2347ecf186588b62b6d3d821d1f87109319081777d1c0fd8 \
-    --hash=sha512:fee28f472b893d8531b7b6b65681cc59e39627de4c9c6d91c043943793eb586f1427a8b18f8b50cc507fab30c5652ddad5d01d9c368e5488254e36bae1627ac4
-coveralls==1.5.0 \
-    --hash=sha512:6379e9f493b0711c1290f1e4ed535dc4e97c6c6f3ecaee78c3d04efb978232eb78ffcac4ab4122e2a2b8c9d81c33c7a48421765939c84acae25ead1d10bd216f \
-    --hash=sha512:8cbe7a258b5b0800968a11cb4bcfa37f2317b676841ad4026de795f005854de898103cf810bfd8a23356319e7c0168a558454f15701261fdcd9a3e5735b55be2
+    --hash=sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae \
+    --hash=sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691 \
+    # via requests
+coverage==4.5.2 \
+    --hash=sha256:09e47c529ff77bf042ecfe858fb55c3e3eb97aac2c87f0349ab5a7efd6b3939f \
+    --hash=sha256:0a1f9b0eb3aa15c990c328535655847b3420231af299386cfe5efc98f9c250fe \
+    --hash=sha256:0cc941b37b8c2ececfed341444a456912e740ecf515d560de58b9a76562d966d \
+    --hash=sha256:10e8af18d1315de936d67775d3a814cc81d0747a1a0312d84e27ae5610e313b0 \
+    --hash=sha256:1b4276550b86caa60606bd3572b52769860a81a70754a54acc8ba789ce74d607 \
+    --hash=sha256:1e8a2627c48266c7b813975335cfdea58c706fe36f607c97d9392e61502dc79d \
+    --hash=sha256:2b224052bfd801beb7478b03e8a66f3f25ea56ea488922e98903914ac9ac930b \
+    --hash=sha256:447c450a093766744ab53bf1e7063ec82866f27bcb4f4c907da25ad293bba7e3 \
+    --hash=sha256:46101fc20c6f6568561cdd15a54018bb42980954b79aa46da8ae6f008066a30e \
+    --hash=sha256:4710dc676bb4b779c4361b54eb308bc84d64a2fa3d78e5f7228921eccce5d815 \
+    --hash=sha256:510986f9a280cd05189b42eee2b69fecdf5bf9651d4cd315ea21d24a964a3c36 \
+    --hash=sha256:5535dda5739257effef56e49a1c51c71f1d37a6e5607bb25a5eee507c59580d1 \
+    --hash=sha256:5a7524042014642b39b1fcae85fb37556c200e64ec90824ae9ecf7b667ccfc14 \
+    --hash=sha256:5f55028169ef85e1fa8e4b8b1b91c0b3b0fa3297c4fb22990d46ff01d22c2d6c \
+    --hash=sha256:6694d5573e7790a0e8d3d177d7a416ca5f5c150742ee703f3c18df76260de794 \
+    --hash=sha256:6831e1ac20ac52634da606b658b0b2712d26984999c9d93f0c6e59fe62ca741b \
+    --hash=sha256:77f0d9fa5e10d03aa4528436e33423bfa3718b86c646615f04616294c935f840 \
+    --hash=sha256:828ad813c7cdc2e71dcf141912c685bfe4b548c0e6d9540db6418b807c345ddd \
+    --hash=sha256:85a06c61598b14b015d4df233d249cd5abfa61084ef5b9f64a48e997fd829a82 \
+    --hash=sha256:8cb4febad0f0b26c6f62e1628f2053954ad2c555d67660f28dfb1b0496711952 \
+    --hash=sha256:a5c58664b23b248b16b96253880b2868fb34358911400a7ba39d7f6399935389 \
+    --hash=sha256:aaa0f296e503cda4bc07566f592cd7a28779d433f3a23c48082af425d6d5a78f \
+    --hash=sha256:ab235d9fe64833f12d1334d29b558aacedfbca2356dfb9691f2d0d38a8a7bfb4 \
+    --hash=sha256:b3b0c8f660fae65eac74fbf003f3103769b90012ae7a460863010539bb7a80da \
+    --hash=sha256:bab8e6d510d2ea0f1d14f12642e3f35cefa47a9b2e4c7cea1852b52bc9c49647 \
+    --hash=sha256:c45297bbdbc8bb79b02cf41417d63352b70bcb76f1bbb1ee7d47b3e89e42f95d \
+    --hash=sha256:d19bca47c8a01b92640c614a9147b081a1974f69168ecd494687c827109e8f42 \
+    --hash=sha256:d64b4340a0c488a9e79b66ec9f9d77d02b99b772c8b8afd46c1294c1d39ca478 \
+    --hash=sha256:da969da069a82bbb5300b59161d8d7c8d423bc4ccd3b410a9b4d8932aeefc14b \
+    --hash=sha256:ed02c7539705696ecb7dc9d476d861f3904a8d2b7e894bd418994920935d36bb \
+    --hash=sha256:ee5b8abc35b549012e03a7b1e86c09491457dba6c94112a2482b18589cc2bdb9 \
+    # via coveralls
+coveralls==1.6.0 \
+    --hash=sha256:6f213e461390973f4a97fb9e9d4ebd4956af296ff0a4d868e622108145835cb7 \
+    --hash=sha256:a7d0078c9e9b5692c03dcd3884647e837836c265c01e98094632feadef767d36
+cryptography==2.5 \
+    --hash=sha256:05b3ded5e88747d28ee3ef493f2b92cbb947c1e45cf98cfef22e6d38bb67d4af \
+    --hash=sha256:06826e7f72d1770e186e9c90e76b4f84d90cdb917b47ff88d8dc59a7b10e2b1e \
+    --hash=sha256:08b753df3672b7066e74376f42ce8fc4683e4fd1358d34c80f502e939ee944d2 \
+    --hash=sha256:2cd29bd1911782baaee890544c653bb03ec7d95ebeb144d714b0f5c33deb55c7 \
+    --hash=sha256:31e5637e9036d966824edaa91bf0aa39dc6f525a1c599f39fd5c50340264e079 \
+    --hash=sha256:42fad67d7072216a49e34f923d8cbda9edacbf6633b19a79655e88a1b4857063 \
+    --hash=sha256:4946b67235b9d2ea7d31307be9d5ad5959d6c4a8f98f900157b47abddf698401 \
+    --hash=sha256:522fdb2809603ee97a4d0ef2f8d617bc791eb483313ba307cb9c0a773e5e5695 \
+    --hash=sha256:6f841c7272645dd7c65b07b7108adfa8af0aaea57f27b7f59e01d41f75444c85 \
+    --hash=sha256:7d335e35306af5b9bc0560ca39f740dfc8def72749645e193dd35be11fb323b3 \
+    --hash=sha256:8504661ffe324837f5c4607347eeee4cf0fcad689163c6e9c8d3b18cf1f4a4ad \
+    --hash=sha256:9260b201ce584d7825d900c88700aa0bd6b40d4ebac7b213857bd2babee9dbca \
+    --hash=sha256:9a30384cc402eac099210ab9b8801b2ae21e591831253883decdb4513b77a3cd \
+    --hash=sha256:9e29af877c29338f0cab5f049ccc8bd3ead289a557f144376c4fbc7d1b98914f \
+    --hash=sha256:ab50da871bc109b2d9389259aac269dd1b7c7413ee02d06fe4e486ed26882159 \
+    --hash=sha256:b13c80b877e73bcb6f012813c6f4a9334fcf4b0e96681c5a15dac578f2eedfa0 \
+    --hash=sha256:bfe66b577a7118e05b04141f0f1ed0959552d45672aa7ecb3d91e319d846001e \
+    --hash=sha256:e091bd424567efa4b9d94287a952597c05d22155a13716bf5f9f746b9dc906d3 \
+    --hash=sha256:fa2b38c8519c5a3aa6e2b4e1cf1a549b54acda6adb25397ff542068e73d1ed00 \
+    # via pyopenssl, urllib3
 docopt==0.6.2 \
-    --hash=sha512:af138feccf8c37b374ee44fcda4938a88107d434df13c173214021b1a3348b152a595095a86982b66ac03a11db8e0f1e9e6a3a65c98deea92330311daeb831a3
-idna==2.7 \
-    --hash=sha512:34ba985862e386243f43616586e53830177cf4ba0925b6054198dfa63c085ec5c6c5b54c2b3c0989bc768aacceeef76b84471e58a16183b960dc4b8812cd1c61 \
-    --hash=sha512:ed1fe279142f8fc9604b12fadc6e7cda78b822194d481dcb23c4474e9d584d170b45a410c553a1625c319c3d1b242e29aca86c7c2f13b73f19bbf0607e9fdcbd
-requests==2.19.1 \
-    --hash=sha512:bb4ba9411a3ab7e81169ada77c9f6fe89913418f8f249e4a1e36839dcc2728422517101e12e02fe3ec454c56f2e7bf6f1599b2901c08f88b86185fb52b925f00 \
-    --hash=sha512:deef2662227497b472f6e7eb7f0ee468c772069fc66552f71d80e5a12af62a187f8bc6a8a78531915e824c7f277d0db61c1534c89d13d473f68504f0bd6edf47
-urllib3==1.23 \
-    --hash=sha512:10d6c15f41e5e6738bec8ac167f7138123f4396205bc9bc556cac4246e13e943e6f4d569d63d5a9acab899580b1df680012efa42b9d2c16b28cbb6babdbabe26 \
-    --hash=sha512:6baa76ad3bebc639d7ec0a042d809fba7ef3110de6164a321756389c250e218728d178708611049d91f39d17f24b8b08585edb2f2c260c987bd4c7204e0c0b5f
+    --hash=sha256:49b3a825280bd66b3aa83585ef59c4a8c82f2c8a522dbe754a8bc8d08c85c491 \
+    # via coveralls
+enum34==1.1.6 \
+    --hash=sha256:2d81cbbe0e73112bdfe6ef8576f2238f2ba27dd0d55752a776c41d38b7da2850 \
+    --hash=sha256:644837f692e5f550741432dd3f223bbb9852018674981b1664e5dc339387588a \
+    --hash=sha256:6bd0f6ad48ec2aa117d3d141940d484deccda84d4fcd884f5c3d93c23ecd8c79 \
+    --hash=sha256:8ad8c4783bf61ded74527bffb48ed9b54166685e4230386a9ed9b1279e2df5b1 \
+    # via cryptography
+idna==2.8 \
+    --hash=sha256:c357b3f628cf53ae2c4c05627ecc484553142ca23264e593d327bcde5e9c3407 \
+    --hash=sha256:ea8b7f6188e6fa117537c3df7da9fc686d485087abf6ac197f9c46432f7e4a3c \
+    # via requests, urllib3
+ipaddress==1.0.22 \
+    --hash=sha256:64b28eec5e78e7510698f6d4da08800a5c575caa4a286c93d651c5d3ff7b6794 \
+    --hash=sha256:b146c751ea45cad6188dd6cf2d9b757f6f4f8d6ffb96a023e6f2e26eea02a72c \
+    # via cryptography, urllib3
+pycparser==2.19 \
+    --hash=sha256:a988718abfad80b6b157acce7bf130a30876d27603738ac39f140993246b25b3 \
+    # via cffi
+pyopenssl==19.0.0 \
+    --hash=sha256:aeca66338f6de19d1aa46ed634c3b9ae519a64b458f8468aec688e7e3c20f200 \
+    --hash=sha256:c727930ad54b10fc157015014b666f2d8b41f70c0d03e83ab67624fd3dd5d1e6 \
+    # via urllib3
+requests==2.21.0 \
+    --hash=sha256:502a824f31acdacb3a35b6690b5fbf0bc41d63a24a45c4004352b0242707598e \
+    --hash=sha256:7bf2a778576d825600030a110f3c0e3e8edc51dfaafe1c146e39a2027784957b \
+    # via coveralls
+six==1.12.0 \
+    --hash=sha256:3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c \
+    --hash=sha256:d16a0141ec1a18405cd4ce8b4613101da75da0e9a7aec5bdd4fa804d0e0eba73 \
+    # via cryptography, pyopenssl
+urllib3[secure]==1.24.2 \
+    --hash=sha256:4c291ca23bbb55c76518905869ef34bdd5f0e46af7afe6861e8375643ffee1a0 \
+    --hash=sha256:9a247273df709c4fedb38c711e44292304f73f39ab01beda9f6b9fc375669ac3 \
+    # via coveralls, requests
--- a/third_party/python/mozilla-version/requirements-docs.txt
+++ b/third_party/python/mozilla-version/requirements-docs.txt
@@ -1,66 +1,122 @@
-# Generated from dephash.py + hashin.py
-Babel==2.6.0 \
-    --hash=sha512:2633c7782cc9ed54383a2d054c8be2c52bee1e6c0b0ecce10e61ec95cf68e0a8cf265f063089c31901aedb87835ade643b618d8604812ddf694ee9a599c4c41b \
-    --hash=sha512:a87f26c25f1e48a64d1e7ee112bc0c325a6268e0e716a81cb6814a53f0add8f3d579babd2ba064f160298ebe3ac9711aa5d28f112582ee287767b6ed8427b6e0
-Jinja2==2.10 \
-    --hash=sha512:0ea7371be67ffcf19e46dfd06523a45a0806e678a407d54f5f2f3e573982f0959cf82ec5d07b203670309928a62ef71109701ab16547a9bba2ebcdc178cb67f2 \
-    --hash=sha512:672c1a112f76f399600a069c5ee882d5fdf065ff25f6b729ec12a266d7ef6f638c26d5cc680db7b3a375d9e1ae7323aed3c2a49eb03fc39dd1a1ca8b0d658b63
-MarkupSafe==1.0 \
-    --hash=sha512:7437a02cb1b9c1d6d6c20b13d394f24a1cd1cb8c743f832d8b1cbb6ab8846f70f54d924dd693423b33c4d592e772983ae38fd4a35961e233457c48bd3584ecb8
-Pygments==2.2.0 \
-    --hash=sha512:2ecf535b32d727473cfb8b15b73f67dbe15189ed0319b99cc6e9ae222ceee5fffe32b4b6dee8e0aae91338bd5add27bbb3cb1429977ec120ab341818526993c0 \
-    --hash=sha512:cc0a4f73e19fa6cbf46314de2e809460c807c631e39ba05cbe5edb5f40db1a687aafcd9715585a0ed45f791710eb6038305e273f282f8682df76f30e63710b29
-Sphinx==1.8.0 \
-    --hash=sha256:c091dbdd5cc5aac6eb95d591a819fd18bccec90ffb048ec465b165a48b839b45 \
-    --hash=sha256:95acd6648902333647a0e0564abdb28a74b0a76d2333148aa35e5ed1f56d3c4b
-alabaster==0.7.11 \
-    --hash=sha512:0dc70eacacab471f7bfe28fd18ff22edb0059dc3ac46d1c42b24783fcc863da5bace4654dc5dbd2e5b420a0ed9230a1aaf0e7c9df9363196f84645c759f50a00 \
-    --hash=sha512:3b3762cc9f0a04296d07bdadeb7e77ae007e307bfad81d8ddfa8e883dcf7577bf544957b3664ec4cc354749fa249627071474466dc771c5883c75571c86d8f3b
-certifi==2018.8.24 \
-    --hash=sha256:456048c7e371c089d0a77a5212fb37a2c2dce1e24146e3b7e0261736aaeaa22a \
-    --hash=sha256:376690d6f16d32f9d1fe8932551d80b23e9d393a8578c5633a2ed39a64861638
+#
+# This file is autogenerated by pip-compile
+# To update, run:
+#
+#    pip-compile --generate-hashes --output-file requirements-docs.txt requirements-docs.txt.in
+#
+alabaster==0.7.12 \
+    --hash=sha256:446438bdcca0e05bd45ea2de1668c1d9b032e1a9154c2c259092d77031ddd359 \
+    --hash=sha256:a661d72d58e6ea8a57f7a86e37d86716863ee5e92788398526d58b26a4e4dc02 \
+    # via sphinx
+babel==2.6.0 \
+    --hash=sha256:6778d85147d5d85345c14a26aada5e478ab04e39b078b0745ee6870c2b5cf669 \
+    --hash=sha256:8cba50f48c529ca3fa18cf81fa9403be176d374ac4d60738b839122dfaaa3d23 \
+    # via sphinx
+certifi==2018.11.29 \
+    --hash=sha256:47f9c83ef4c0c621eaef743f133f09fa8a74a9b75f037e8624f83bd1b6626cb7 \
+    --hash=sha256:993f830721089fef441cdfeb4b2c8c9df86f0c63239f06bd025a76a7daddb033 \
+    # via requests
 chardet==3.0.4 \
-    --hash=sha512:61a03b23447a2bfe52ceed4dd1b9afdb5784da1933a623776883ee9f297e341f633e27f0ce0230bd5fdc5fdb5382105ab42736a74a417ddeb9f83af57455dba5 \
-    --hash=sha512:bfae58c8ea19c87cc9c9bf3d0b6146bfdb3630346bd954fe8e9f7da1f09da1fc0d6943ff04802798a665ea3b610ee2d65658ce84fe5a89f9e93625ea396a17f4
+    --hash=sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae \
+    --hash=sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691 \
+    # via requests
 docutils==0.14 \
-    --hash=sha512:1ed72c2ef7d2ca38d1c6f3154b7986ea46f599d9bd826405a5257fdd7740c8626957d6298aa95fb0edea8a24515de22f1ad9b2ecbd59341a1ab7a2bab30f500c \
-    --hash=sha512:391177f1f87d837463b9bc135805ef102c8221b52eabf7c2309ac8d9635db3698f6d43e79d2ce9a53c8a2fa2ed1b21dafdad98d5ba1a8d1672b68741854caa9a \
-    --hash=sha512:c3b303121066fb1a67c5984f7e00edda81f3e3a47e84729e4480c86777df7bb236c2965bf6d3f15c72c17de329137a3d20ce35ecef410801539ca9a9328f9260
-idna==2.7 \
-    --hash=sha512:34ba985862e386243f43616586e53830177cf4ba0925b6054198dfa63c085ec5c6c5b54c2b3c0989bc768aacceeef76b84471e58a16183b960dc4b8812cd1c61 \
-    --hash=sha512:ed1fe279142f8fc9604b12fadc6e7cda78b822194d481dcb23c4474e9d584d170b45a410c553a1625c319c3d1b242e29aca86c7c2f13b73f19bbf0607e9fdcbd
+    --hash=sha256:02aec4bd92ab067f6ff27a38a38a41173bf01bed8f89157768c1573f53e474a6 \
+    --hash=sha256:51e64ef2ebfb29cae1faa133b3710143496eca21c530f3f71424d77687764274 \
+    --hash=sha256:7a4bd47eaf6596e1295ecb11361139febe29b084a87bf005bf899f9a42edc3c6 \
+    # via m2r, sphinx
+idna==2.8 \
+    --hash=sha256:c357b3f628cf53ae2c4c05627ecc484553142ca23264e593d327bcde5e9c3407 \
+    --hash=sha256:ea8b7f6188e6fa117537c3df7da9fc686d485087abf6ac197f9c46432f7e4a3c \
+    # via requests
 imagesize==1.1.0 \
     --hash=sha256:3f349de3eb99145973fefb7dbe38554414e5c30abd0c8e4b970a7c9d09f3a1d8 \
-    --hash=sha256:f3832918bc3c66617f92e35f5d70729187676313caa60c187eb0f28b8fe5e3b5
-m2r==0.2.0 \
-    --hash=sha512:165e20c68dc4dadad3fa5ebb7c4ebfd9e8971e3529e30aa964cbc820bf8f01c7cf9bfbfedd35ffe7e9651d20e5e5a4e09a4a3f130cdd07b5524edebce88618b1
-mistune==0.8.3 \
-    --hash=sha512:f3691c1b940d827164e110f0ddf366e881625c96d7b3cc353e8805b07205496fd1e37cef3a55557b490d3d5257f86e8515c4155b192fb4b9297159bc609e3c2d \
-    --hash=sha512:fc0b6d53e7a62712b752bff77c2529750628e9e1eeec02603bd2c793f9b0a46efe31fe7a749c5d6aae3c591d74e43c45e450179650bfb57128fb0ec366de6aa3
-packaging==17.1 \
-    --hash=sha512:49b15957d84e0b42ae83c88b1397871ad49c34f72f61e5fc34579165dffe5cd243494285ae89f14a496b94f3b715f135deba4044bf496c9c8a5124121442a0e0 \
-    --hash=sha512:52d2f482ae5cd0f8e7b3ac35c4b270ca736bc4f7ebaa569631d1dcb8ea024ee6f75127ca2aa3c95e686ebbd427de2ef4bc01bcd839591f7b4c1e26f9b8d9acb0
-pyparsing==2.2.1 \
-    --hash=sha256:905d8090c335314568b5faee0025b1829f27bb974604a5762a6cdef3a7dfc3b7 \
-    --hash=sha256:f493ee323be1e94929416b3585eefcc04943115cecbaaa35a8c86d1a2368af19
-pytz==2018.5 \
-    --hash=sha512:35b6bdd25b8e57c693da4379c2032401ef3cf290a57d8448c67dcaf1491a21d27ff25d932ef3ec3a51e31fbb7541e081073f292867a7d1ad47904b69dc7e4863 \
-    --hash=sha512:655836fe203e5aaf066e85133d7e3aa680201651a80f887bebeadb46a0ac8c0aaf0ee2f717d6203e438b14ec49b35f346ed0bdea7ed81cec9447f46f94d5423d
-readthedocs-sphinx-ext==0.5.14 \
-    --hash=sha512:0462bcd7408ee6483823014f1c77bd7e46f5908e793c1b115ea5a3861e8072b96f46f183deb5083057bca8dd6684b6520e04c84a69b1892a13e86c2ef7826d26 \
-    --hash=sha512:6480cb5967a7c192d2f3a27613320ebf37fe7f161ddd437a6bfdec88de708e88c0f294fcf04e41b814ef284a74d6f8d56f75824ade8d74c8a39f6f403f3a2fd3
-requests==2.19.1 \
-    --hash=sha512:bb4ba9411a3ab7e81169ada77c9f6fe89913418f8f249e4a1e36839dcc2728422517101e12e02fe3ec454c56f2e7bf6f1599b2901c08f88b86185fb52b925f00 \
-    --hash=sha512:deef2662227497b472f6e7eb7f0ee468c772069fc66552f71d80e5a12af62a187f8bc6a8a78531915e824c7f277d0db61c1534c89d13d473f68504f0bd6edf47
-six==1.11.0 \
-    --hash=sha512:33f246a2e987141e17e5edad9d3537cf3aba0cbdd0bc2a907ea52ce0d674b1474f29c3dd5cc26605fd960396054b189ca5f501708333cad234c223131483fe24 \
-    --hash=sha512:b71248ef493ac12b115fdf06206090078fac147ec6ab6efb67b87e2b9c07a69d55bf8e70fde713d81735a99e560a17da714274e2ecbd7b0200d2e9a0f39970a7
+    --hash=sha256:f3832918bc3c66617f92e35f5d70729187676313caa60c187eb0f28b8fe5e3b5 \
+    # via sphinx
+jinja2==2.10 \
+    --hash=sha256:74c935a1b8bb9a3947c50a54766a969d4846290e1e788ea44c1392163723c3bd \
+    --hash=sha256:f84be1bb0040caca4cea721fcbbbbd61f9be9464ca236387158b0feea01914a4 \
+    # via sphinx
+m2r==0.2.1 \
+    --hash=sha256:bf90bad66cda1164b17e5ba4a037806d2443f2a4d5ddc9f6a5554a0322aaed99
+markupsafe==1.1.0 \
+    --hash=sha256:048ef924c1623740e70204aa7143ec592504045ae4429b59c30054cb31e3c432 \
+    --hash=sha256:130f844e7f5bdd8e9f3f42e7102ef1d49b2e6fdf0d7526df3f87281a532d8c8b \
+    --hash=sha256:19f637c2ac5ae9da8bfd98cef74d64b7e1bb8a63038a3505cd182c3fac5eb4d9 \
+    --hash=sha256:1b8a7a87ad1b92bd887568ce54b23565f3fd7018c4180136e1cf412b405a47af \
+    --hash=sha256:1c25694ca680b6919de53a4bb3bdd0602beafc63ff001fea2f2fc16ec3a11834 \
+    --hash=sha256:1f19ef5d3908110e1e891deefb5586aae1b49a7440db952454b4e281b41620cd \
+    --hash=sha256:1fa6058938190ebe8290e5cae6c351e14e7bb44505c4a7624555ce57fbbeba0d \
+    --hash=sha256:31cbb1359e8c25f9f48e156e59e2eaad51cd5242c05ed18a8de6dbe85184e4b7 \
+    --hash=sha256:3e835d8841ae7863f64e40e19477f7eb398674da6a47f09871673742531e6f4b \
+    --hash=sha256:4e97332c9ce444b0c2c38dd22ddc61c743eb208d916e4265a2a3b575bdccb1d3 \
+    --hash=sha256:525396ee324ee2da82919f2ee9c9e73b012f23e7640131dd1b53a90206a0f09c \
+    --hash=sha256:52b07fbc32032c21ad4ab060fec137b76eb804c4b9a1c7c7dc562549306afad2 \
+    --hash=sha256:52ccb45e77a1085ec5461cde794e1aa037df79f473cbc69b974e73940655c8d7 \
+    --hash=sha256:5c3fbebd7de20ce93103cb3183b47671f2885307df4a17a0ad56a1dd51273d36 \
+    --hash=sha256:5e5851969aea17660e55f6a3be00037a25b96a9b44d2083651812c99d53b14d1 \
+    --hash=sha256:5edfa27b2d3eefa2210fb2f5d539fbed81722b49f083b2c6566455eb7422fd7e \
+    --hash=sha256:7d263e5770efddf465a9e31b78362d84d015cc894ca2c131901a4445eaa61ee1 \
+    --hash=sha256:83381342bfc22b3c8c06f2dd93a505413888694302de25add756254beee8449c \
+    --hash=sha256:857eebb2c1dc60e4219ec8e98dfa19553dae33608237e107db9c6078b1167856 \
+    --hash=sha256:98e439297f78fca3a6169fd330fbe88d78b3bb72f967ad9961bcac0d7fdd1550 \
+    --hash=sha256:bf54103892a83c64db58125b3f2a43df6d2cb2d28889f14c78519394feb41492 \
+    --hash=sha256:d9ac82be533394d341b41d78aca7ed0e0f4ba5a2231602e2f05aa87f25c51672 \
+    --hash=sha256:e982fe07ede9fada6ff6705af70514a52beb1b2c3d25d4e873e82114cf3c5401 \
+    --hash=sha256:edce2ea7f3dfc981c4ddc97add8a61381d9642dc3273737e756517cc03e84dd6 \
+    --hash=sha256:efdc45ef1afc238db84cb4963aa689c0408912a0239b0721cb172b4016eb31d6 \
+    --hash=sha256:f137c02498f8b935892d5c0172560d7ab54bc45039de8805075e19079c639a9c \
+    --hash=sha256:f82e347a72f955b7017a39708a3667f106e6ad4d10b25f237396a7115d8ed5fd \
+    --hash=sha256:fb7c206e01ad85ce57feeaaa0bf784b97fa3cad0d4a5737bc5295785f5c613a1 \
+    # via jinja2
+mistune==0.8.4 \
+    --hash=sha256:59a3429db53c50b5c6bcc8a07f8848cb00d7dc8bdb431a4ab41920d201d4756e \
+    --hash=sha256:88a1051873018da288eee8538d476dffe1262495144b33ecb586c4ab266bb8d4 \
+    # via m2r
+packaging==19.0 \
+    --hash=sha256:0c98a5d0be38ed775798ece1b9727178c4469d9c3b4ada66e8e6b7849f8732af \
+    --hash=sha256:9e1cbf8c12b1f1ce0bb5344b8d7ecf66a6f8a6e91bcb0c84593ed6d3ab5c4ab3 \
+    # via sphinx
+pygments==2.3.1 \
+    --hash=sha256:5ffada19f6203563680669ee7f53b64dabbeb100eb51b61996085e99c03b284a \
+    --hash=sha256:e8218dd399a61674745138520d0d4cf2621d7e032439341bc3f647bff125818d \
+    # via sphinx
+pyparsing==2.3.1 \
+    --hash=sha256:66c9268862641abcac4a96ba74506e594c884e3f57690a696d21ad8210ed667a \
+    --hash=sha256:f6c5ef0d7480ad048c054c37632c67fca55299990fff127850181659eea33fc3 \
+    # via packaging
+pytz==2018.9 \
+    --hash=sha256:32b0891edff07e28efe91284ed9c31e123d84bea3fd98e1f72be2508f43ef8d9 \
+    --hash=sha256:d5f05e487007e29e03409f9398d074e158d920d36eb82eaf66fb1136b0c5374c \
+    # via babel
+readthedocs-sphinx-ext==0.5.16 \
+    --hash=sha256:42b1c63d63dd483a188b541599bd08a540b2d08ec2b166660179618b6ccc3bb0 \
+    --hash=sha256:e73770f53a226f6db8199916a12bcee1808e0c0cbe028422668e8c1c7f2fa80c
+requests==2.21.0 \
+    --hash=sha256:502a824f31acdacb3a35b6690b5fbf0bc41d63a24a45c4004352b0242707598e \
+    --hash=sha256:7bf2a778576d825600030a110f3c0e3e8edc51dfaafe1c146e39a2027784957b \
+    # via readthedocs-sphinx-ext, sphinx
+six==1.12.0 \
+    --hash=sha256:3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c \
+    --hash=sha256:d16a0141ec1a18405cd4ce8b4613101da75da0e9a7aec5bdd4fa804d0e0eba73 \
+    # via packaging, sphinx
 snowballstemmer==1.2.1 \
-    --hash=sha512:09f860f383d84d12a83c87ef6654fba4ac10bca07e8d2ce88dd428c72754110d56a4b698e125a18818699a289455bf61cf67ea68e349ee8a12d6dfff0a3fbed9 \
-    --hash=sha512:c97bb3d293ffbe16d4c553f8a8ad1dbb5f659441cde93e407f71419f82b8e16b3090df2c0294d64f73382a648cd8cc62bca407124a8e2d60e4c424b78e10b6b8
+    --hash=sha256:919f26a68b2c17a7634da993d91339e288964f93c274f1343e3bbbe2096e1128 \
+    --hash=sha256:9f3bcd3c401c3e862ec0ebe6d2c069ebc012ce142cce209c098ccb5b09136e89 \
+    # via sphinx
+sphinx==1.8.4 \
+    --hash=sha256:b53904fa7cb4b06a39409a492b949193a1b68cc7241a1a8ce9974f86f0d24287 \
+    --hash=sha256:c1c00fc4f6e8b101a0d037065043460dffc2d507257f2f11acaed71fd2b0c83c
 sphinxcontrib-websupport==1.1.0 \
-    --hash=sha512:5c13433d9804feadb0783116648731a21d44f803e73b88bd0ec7a46948bae68284111d33e44bab1723f8224ea06c1efa5afb88fa390fbb127821761f0a990076 \
-    --hash=sha512:adbd7db06150a4424a881a22442c2535ed823c7adcc295ef9c3af5ae38d823349830a114e8a7af2138498d0e68b37189707c1bb5a28b45c76031bcf94210fb89
-urllib3==1.23 \
-    --hash=sha512:10d6c15f41e5e6738bec8ac167f7138123f4396205bc9bc556cac4246e13e943e6f4d569d63d5a9acab899580b1df680012efa42b9d2c16b28cbb6babdbabe26 \
---hash=sha512:6baa76ad3bebc639d7ec0a042d809fba7ef3110de6164a321756389c250e218728d178708611049d91f39d17f24b8b08585edb2f2c260c987bd4c7204e0c0b5f
+    --hash=sha256:68ca7ff70785cbe1e7bccc71a48b5b6d965d79ca50629606c7861a21b206d9dd \
+    --hash=sha256:9de47f375baf1ea07cdb3436ff39d7a9c76042c10a769c52353ec46e4e8fc3b9 \
+    # via sphinx
+typing==3.6.6 \
+    --hash=sha256:4027c5f6127a6267a435201981ba156de91ad0d1d98e9ddc2aa173453453492d \
+    --hash=sha256:57dcf675a99b74d64dacf6fba08fb17cf7e3d5fdff53d4a30ea2a5e7e52543d4 \
+    --hash=sha256:a4c8473ce11a65999c8f59cb093e70686b6c84c98df58c1dae9b3b196089858a \
+    # via sphinx
+urllib3==1.24.2 \
+    --hash=sha256:4c291ca23bbb55c76518905869ef34bdd5f0e46af7afe6861e8375643ffee1a0 \
+    --hash=sha256:9a247273df709c4fedb38c711e44292304f73f39ab01beda9f6b9fc375669ac3 \
+    # via requests
--- a/third_party/python/mozilla-version/requirements-test.txt
+++ b/third_party/python/mozilla-version/requirements-test.txt
@@ -1,122 +1,140 @@
-# Generated from dephash.py + hashin.py
+#
+# This file is autogenerated by pip-compile
+# To update, run:
+#
+#    pip-compile --generate-hashes --output-file requirements-test.txt requirements-test.txt.in
+#
+atomicwrites==1.3.0 \
+    --hash=sha256:03472c30eb2c5d1ba9227e4c2ca66ab8287fbfbbda3888aa93dc2e28fc6811b4 \
+    --hash=sha256:75a9445bac02d8d058d5e1fe689654ba5a6556a1dfd8ce6ec55a0ed79866cfa6 \
+    # via pytest
 attrs==18.2.0 \
-    --hash=sha256:ca4be454458f9dec299268d472aaa5a11f67a4ff70093396e1ceae9c76cf4bbb \
-    --hash=sha256:10cbf6e27dbce8c30807caf056c8eb50917e0eaafe86347671b57254006c3e69
-atomicwrites==1.2.0 \
-    --hash=sha256:6b5282987b21cd79151f51caccead7a09d0a32e89c568bd9e3c4aaa7bbdf3f3a \
-    --hash=sha256:e16334d50fe0f90919ef7339c24b9b62e6abaa78cd2d226f3d94eb067eb89043
-configparser==3.5.0 \
-    --hash=sha512:490b9f7807bce02667f41a48389b51f550818d2bd4296b528833d65d4b04bdbe5b906e7584e55eee4495405267a697ba26a056e6504fe6b3f8cf07ea8f55f7d3 \
-    ; python_version < "3.2"
-coverage==4.5.1 \
-    --hash=sha512:0d656cb22528744a8ef0853f2fa7b96f20fdd49f3c439c3211076e6aac1509c216138e31e24ba92e3945ad4dc81d58ef4b147c092e888a1acbc840d8187617e8 \
-    --hash=sha512:1bed7f91763ae47fc7a0548766029328f059c25fbdd292f2b313d867b93f161cb35b9e612894682b1f486d52c91e06ff7173a2274d6d098657e69de35768f854 \
-    --hash=sha512:2520e0ba3adf1485e7d583ff1f14643bdbe531b4062353780b80737d08330adddb7ab6ad869a2542a261760b4be1d050182fe0f91061610463ee972298fe518e \
-    --hash=sha512:2b5ad59f6570e22021ab96a9cba9bfad78469a248dec032a227a2fccd1b110ab7f38a5076a44a1a471b37077e7100b0f9c51fe370b8467f9dbedae498a042581 \
-    --hash=sha512:309fe4c70de41671afc4fefbc959f0d16d54df3ca95c80b11f9ac8b86b6ea117a714f1c36f6f9976c1951a6760747e9b2de9de60943adc8b39482892f5ce5f7b \
-    --hash=sha512:338a31e1a1856073501a02eaefaae2c18df27140598472d34a8432c9c25225296eab81567729a2cc165a4c9d8faeabb1e3bbb52ce840d394ba0f0c5f6baf2528 \
-    --hash=sha512:3d84ef3f2078ced6010f7192fb5fbe1c0f12c11118cb756ff8b46c453327ec61639f47799b8338a0565033641abbcc6e3c5f394020cab2ffdddec04bb489bf1f \
-    --hash=sha512:45126acc107f5a7fcb015c9b866a3b0d0101e9211fdecc5843f334fea28a2d80db1048e752d1d6f860687c9f289e03678cf2d92a77779a355b9b186a772d3353 \
-    --hash=sha512:45abe32fa09505e436c8cae010e3866399dee551c13fb5a35da57cd296502b9f266332d278671ebdb7ccab941326daeb1e27118821862e249ee985ef4a6d0d35 \
-    --hash=sha512:4757a11361a9d4f757082f885512e6b4de24b60344646ad09741c84e4fb4f08813f05aa18a7acb3451a331a91fb9d27ef411bf9348b54d3d7cd3074e4645f41b \
-    --hash=sha512:4ae653511277a5bb984142286e01157e1a068c01a16c825adf06287e569cc516ca056e6fefcb05b2038f31ca261b5fa8ef345a6c0274650b3de175a694188b95 \
-    --hash=sha512:55decd6e6d369682b67c9a82ccf5772538e004279a657d6d9f75482ff20896360b37b4841d08d79996ce16956bb863d2a2bb33e2ee7d5b06fd3e79adf96548df \
-    --hash=sha512:5ad7ec5b9be01298957c22704a2689e2e9c9c3dc12e11570fbc4a5f382432a854bcea75e4419e953175da3aa2ee1d2ec2f244886db5188f7cc8d9e231b29cc2e \
-    --hash=sha512:7927c89140e844f56917746f41a866755ffcb72d8028bd23ab055446f90231d0c1f4ccc29d67fada8155a5c927b4559f3e263e49659755dc847ebd4b7aa6e392 \
-    --hash=sha512:798fd2eb99a17cdcfd7b2f2d95fc319fb860e041b982b4e7c9d1ccbff41c35f19d5ca16e3605e2222cd30a4ed3cddfe94149b1b2ec27a54efd1ea6474b9ccb1b \
-    --hash=sha512:82742a572549400778cad99057b1ced4c36b61e917983148eccc86bfa6340de8cfefc4f743e79ff876b641e0b9d21307dd6bde78638a6b20dd8ad215068dda25 \
-    --hash=sha512:8510d0846aa24b5fbbdd74c0e38ab29c8fce7cc96ff473f4b52fa8044fcafcfb54449e8aaab29efe7c73a3530167231412b14ccf10e6cb34c9838adf63826019 \
-    --hash=sha512:89e12e4b7ee82e2f2f92c75697ac30bdbc214d9b8fb0bd5aa21e657eac1800f8fb1b44ae9c1d8ae07666d0b0d9a5a1f681b555fcc2d141f1ad15ab589e005243 \
-    --hash=sha512:980260b63b49b697a543184e0233996ba6fa4df8c6976227ae6c20dd650f1a094f4115a3e999222e73806f191bf7ce2a2848bd60a690dd1737b102928f25f3bc \
-    --hash=sha512:9b24bda59e374374dbd48973d118e039fdeeff3d193411533aed90e3d425ddd5ad5419903e2cc7a719a4ff04bbd066eb3e11e153ee8df339dae03dcc8c25b9c0 \
-    --hash=sha512:9c0b13abc5376eaff78c4e7f2a945bb86965969ea1ab3571d2209f91df078c1a779ee42f47bf96e62fe9bd63668e49edfaa0b00525c18d2cbbd155781fa2201b \
-    --hash=sha512:9dd03ce95b1a107337b226d46dcd9e6fdf3b388426ac0508cb1b6c5c43423f22b8b35828e9d89dcc08483525b3bc2de1334fe7e85bfaae9d64f64933ef9fe3ce \
-    --hash=sha512:a5cbfd1cd7e5212285c28dec4e8b8354b6b189cde501f078746e5dc45216f4d24479eef18a612c00bfe94192ab48deb79150cd261ff42254ab83205dc58ff77b \
-    --hash=sha512:a7892f7106be5ab0670d32b4e8d10ec9e1336e4706d94666c084be17f4519672aa84c2dbfa4028b43433ea51ed29ffe175ab3908b91f5329578c7a6bbde7df91 \
-    --hash=sha512:ac9dc454f928a9e7fbd8e4a98bfce0511415cac69e80cf0a098afa504d9c6585c2eeac0553f20d3edd297770f5744e8f03ddb0a17f62bde70caf3779d11e32b9 \
-    --hash=sha512:b0b004871cfd6f1b949a4ddc37544a73c1446602109b671c6752baa3776e4f08dfe340c1c75299c62612c43fba652ee92e3481bb39ecb7e9b02643a041becac4 \
-    --hash=sha512:b202a7278ebb3c87d6fcd2f1cff7dc88d78fa7eae709a73e6207c6212f962e706f84f22c14dad6c5c3e8be7eef7c1806c3f66e8f1e557c6127aea0a97a797b0f \
-    --hash=sha512:b388092fe437bfc8bc10205ffaa5a43e418e39e1f0e3509ef03721149c5904455142eadfc28d414007f93e5d0deb39231b59b35cba82ea884809c60020b1cfa3 \
-    --hash=sha512:c718f78a365a5b610cb2f1fe8ca646b83d6439912cfb9f787e57cc84dc84eea6f3150660231acd093dfa84d2f4f8135f7f2512fb05a1978e1b12c3fd8b23f505 \
-    --hash=sha512:d0662ad14ebb76454571ed5b083e62bd35e57cd801f627dd1d286ccfce7c271109a814f73e26fb402d60c23ae08ac96f29ca62a43cbbcb027e72b349ec9f296f \
-    --hash=sha512:d329341278272c48270cb8eb712257ce9970c665606351064d02ce37424c42407e833e4688e938c3e88804451e15cb5287dedc91e0fe5a66cb5cc201f791ab1c \
-    --hash=sha512:d4b9569efa13c9a316a0bc99e7c163a474ed7022df0445ed5811e0ad4e53f0316472e3c8b8540f995d0d6abaae5025796d876f5322e63819fb469a7f1a5419a9 \
-    --hash=sha512:d6788611162a863a8a274473b6dcdaefadccd0f42f6732431cdb12ebd5300987eb3db29df0f305528bbe9766b87baba9a6dca0460089cab5aa11b1ca727d3af8 \
-    --hash=sha512:d987c1fee355cfc7d6bdc89234295b7dd35941449f14dc5c8efac28bb98894f9a78d558dd02a05457a97916de070ae386127be7197efc3b511c4f7a7f056f189 \
-    --hash=sha512:dba0935c4079bfce694866d6598408db305b82063ed4b0dcaf5d4260a70b25118aa3d72ff81ba3326dcb6377734c4fa5811740543331ce6eb1c9886e621217ac \
-    --hash=sha512:e01685335bd44d0c767429568adc5fb3669417354b62d634bb06fcdfaa959102ff1105f3b108046047a4dffd24bbce5bf81fcdd61b49a45f2aad32a83034dc9c \
-    --hash=sha512:f673f86b32764a023d32626939217d56c53029a4de83f7ef018f8a76e5ee2d0090f3395e6c79098c73f3dbe66ae14355ca3e3bb799275b7229bf198dc4864236 \
-    --hash=sha512:f96a049d5dda5b2ca4e135a561d8ad9a1a511603e553996e07ee6e46a3573afea1ffe895d2897e3c2347ecf186588b62b6d3d821d1f87109319081777d1c0fd8 \
-    --hash=sha512:fee28f472b893d8531b7b6b65681cc59e39627de4c9c6d91c043943793eb586f1427a8b18f8b50cc507fab30c5652ddad5d01d9c368e5488254e36bae1627ac4
+    --hash=sha256:10cbf6e27dbce8c30807caf056c8eb50917e0eaafe86347671b57254006c3e69 \
+    --hash=sha256:ca4be454458f9dec299268d472aaa5a11f67a4ff70093396e1ceae9c76cf4bbb
+configparser==3.7.1 \
+    --hash=sha256:5bd5fa2a491dc3cfe920a3f2a107510d65eceae10e9c6e547b90261a4710df32 \
+    --hash=sha256:c114ff90ee2e762db972fa205f02491b1f5cf3ff950decd8542c62970c9bedac \
+    --hash=sha256:df28e045fbff307a28795b18df6ac8662be3219435560ddb068c283afab1ea7a ; python_version < "3.2"
+coverage==4.5.2 \
+    --hash=sha256:09e47c529ff77bf042ecfe858fb55c3e3eb97aac2c87f0349ab5a7efd6b3939f \
+    --hash=sha256:0a1f9b0eb3aa15c990c328535655847b3420231af299386cfe5efc98f9c250fe \
+    --hash=sha256:0cc941b37b8c2ececfed341444a456912e740ecf515d560de58b9a76562d966d \
+    --hash=sha256:10e8af18d1315de936d67775d3a814cc81d0747a1a0312d84e27ae5610e313b0 \
+    --hash=sha256:1b4276550b86caa60606bd3572b52769860a81a70754a54acc8ba789ce74d607 \
+    --hash=sha256:1e8a2627c48266c7b813975335cfdea58c706fe36f607c97d9392e61502dc79d \
+    --hash=sha256:2b224052bfd801beb7478b03e8a66f3f25ea56ea488922e98903914ac9ac930b \
+    --hash=sha256:447c450a093766744ab53bf1e7063ec82866f27bcb4f4c907da25ad293bba7e3 \
+    --hash=sha256:46101fc20c6f6568561cdd15a54018bb42980954b79aa46da8ae6f008066a30e \
+    --hash=sha256:4710dc676bb4b779c4361b54eb308bc84d64a2fa3d78e5f7228921eccce5d815 \
+    --hash=sha256:510986f9a280cd05189b42eee2b69fecdf5bf9651d4cd315ea21d24a964a3c36 \
+    --hash=sha256:5535dda5739257effef56e49a1c51c71f1d37a6e5607bb25a5eee507c59580d1 \
+    --hash=sha256:5a7524042014642b39b1fcae85fb37556c200e64ec90824ae9ecf7b667ccfc14 \
+    --hash=sha256:5f55028169ef85e1fa8e4b8b1b91c0b3b0fa3297c4fb22990d46ff01d22c2d6c \
+    --hash=sha256:6694d5573e7790a0e8d3d177d7a416ca5f5c150742ee703f3c18df76260de794 \
+    --hash=sha256:6831e1ac20ac52634da606b658b0b2712d26984999c9d93f0c6e59fe62ca741b \
+    --hash=sha256:77f0d9fa5e10d03aa4528436e33423bfa3718b86c646615f04616294c935f840 \
+    --hash=sha256:828ad813c7cdc2e71dcf141912c685bfe4b548c0e6d9540db6418b807c345ddd \
+    --hash=sha256:85a06c61598b14b015d4df233d249cd5abfa61084ef5b9f64a48e997fd829a82 \
+    --hash=sha256:8cb4febad0f0b26c6f62e1628f2053954ad2c555d67660f28dfb1b0496711952 \
+    --hash=sha256:a5c58664b23b248b16b96253880b2868fb34358911400a7ba39d7f6399935389 \
+    --hash=sha256:aaa0f296e503cda4bc07566f592cd7a28779d433f3a23c48082af425d6d5a78f \
+    --hash=sha256:ab235d9fe64833f12d1334d29b558aacedfbca2356dfb9691f2d0d38a8a7bfb4 \
+    --hash=sha256:b3b0c8f660fae65eac74fbf003f3103769b90012ae7a460863010539bb7a80da \
+    --hash=sha256:bab8e6d510d2ea0f1d14f12642e3f35cefa47a9b2e4c7cea1852b52bc9c49647 \
+    --hash=sha256:c45297bbdbc8bb79b02cf41417d63352b70bcb76f1bbb1ee7d47b3e89e42f95d \
+    --hash=sha256:d19bca47c8a01b92640c614a9147b081a1974f69168ecd494687c827109e8f42 \
+    --hash=sha256:d64b4340a0c488a9e79b66ec9f9d77d02b99b772c8b8afd46c1294c1d39ca478 \
+    --hash=sha256:da969da069a82bbb5300b59161d8d7c8d423bc4ccd3b410a9b4d8932aeefc14b \
+    --hash=sha256:ed02c7539705696ecb7dc9d476d861f3904a8d2b7e894bd418994920935d36bb \
+    --hash=sha256:ee5b8abc35b549012e03a7b1e86c09491457dba6c94112a2482b18589cc2bdb9
+entrypoints==0.3 \
+    --hash=sha256:589f874b313739ad35be6e0cd7efde2a4e9b6fea91edcc34e58ecbb8dbe56d19 \
+    --hash=sha256:c70dd71abe5a8c85e55e12c19bd91ccfeec11a6e99044204511f9ed547d48451 \
+    # via flake8
 enum34==1.1.6 \
-    --hash=sha512:3671dc8c0c3cf2a3cbafd22feb85bcc66f4262722b59683429af0865642929622fd3213113703c0b811f7e3bf9cee0e30c7403f6971585150fc013ec01333873 \
-    --hash=sha512:4f916143fe35d41b28efb7958ffa7e10d430d66697f8150b98aae3797a058378fd9a4c201969c155f30f88c962f78e4e75e684889d5138cd2fe60406924363e9 \
-    --hash=sha512:51652525adc37bd1af1d81933f965dba9c508838d9f759c80ca1392991515a29c2c0263264a4e175b37a6ba11dca68c354774e448b19ef1bdba96be5474d93ec \
-    --hash=sha512:ac5eedcd9425b06f44c3e9029cfc3e93a266a5b797c1b8bd3ed81cbbe6c90a163245c15f1ab5ebedf03f885edeb61ebc6b341c61e31789072f29f2a3e1b4bece \
-    ; python_version < '3.4'
-flake8==3.5.0 \
-    --hash=sha512:3eae909818050481e37a701d33ac4efc0c573233ae533b7d72414696f522e115e13945cc52bba22b0172d6e815d1dc34b369f2853cbc60328024c0851161184f \
-    --hash=sha512:ac5d1bd9c44ed76c9e5cbd941b24bb552aa76e156b24ccda6cc8440ee90f3a574fdb393665adc75298e4f57111d7ab3115ef21ef9088fb327d0a9703d442450c
+    --hash=sha256:2d81cbbe0e73112bdfe6ef8576f2238f2ba27dd0d55752a776c41d38b7da2850 \
+    --hash=sha256:644837f692e5f550741432dd3f223bbb9852018674981b1664e5dc339387588a \
+    --hash=sha256:6bd0f6ad48ec2aa117d3d141940d484deccda84d4fcd884f5c3d93c23ecd8c79 \
+    --hash=sha256:8ad8c4783bf61ded74527bffb48ed9b54166685e4230386a9ed9b1279e2df5b1
 flake8-docstrings==1.3.0 \
-    --hash=sha512:b2807bd0b68071f5ea8f1de545826692d8c97c14f5f27132a2c5348a4f0599773345305208d80e6302d6ae7c714e1575c30012d50e0996ec86549df7c3278a1c \
-    --hash=sha512:c90bdcafc84f2940c401c8b22a9cfb96007e6c0b63465e611f5031735a85f1fa7f65f5d9ca898bb98e69966758e9e3ef5b907577ea0b1e925285572ed6f2f954
+    --hash=sha256:4e0ce1476b64e6291520e5570cf12b05016dd4e8ae454b8a8a9a48bc5f84e1cd \
+    --hash=sha256:8436396b5ecad51a122a2c99ba26e5b4e623bf6e913b0fea0cb6c2c4050f91eb
 flake8-polyfill==1.0.2 \
-    --hash=sha512:5d5d9c487e3fcfa3a51d226ca81b8c559e2dffaa657f902d4afc47551677c0e889bf168297a56e816eead2aa45e8a9f4ca1674e8f7c9dc653bb2a01a95132e28 \
-    --hash=sha512:767a599aacbe87328b3e36bd85e0841870760ed9bd95dd3a4a9084edc6f0ae89f8203d565c2b075f16f1db21b647c17b2aa59b08e4702109d7e5f79f36d9f3fa
+    --hash=sha256:12be6a34ee3ab795b19ca73505e7b55826d5f6ad7230d31b18e106400169b9e9 \
+    --hash=sha256:e44b087597f6da52ec6393a709e7108b2905317d0c0b744cdca6208e670d8eda \
+    # via flake8-docstrings
+flake8==3.7.6 \
+    --hash=sha256:6d8c66a65635d46d54de59b027a1dda40abbe2275b3164b634835ac9c13fd048 \
+    --hash=sha256:6eab21c6e34df2c05416faa40d0c59963008fff29b6f0ccfe8fa28152ab3e383
 funcsigs==1.0.2 \
-    --hash=sha512:4e583bb7081bb1d6c0fe5a6935ca03032d562b93ef5c11b51a72ce9e7ac12902451cc2233c7e6f70440629d88d8e6e9625965ee408100b80b0024f3a6204afda \
-    --hash=sha512:8f3d521413af262085cecbe12a41cf1ad36d42efe4c7c892aca58240e1412c9380da72ec159a499a8eaa18bf5013a5892cff58b240b49f3cf4d9428caca9cfe2 \
-    ; python_version < "3.0"
+    --hash=sha256:330cc27ccbf7f1e992e69fef78261dc7c6569012cf397db8d3de0234e6c937ca \
+    --hash=sha256:a7bb0f2cf3a3fd1ab2732cb49eba4252c2af4240442415b4abce3b87022a8f50 ; python_version < "3.0"
+# For an unknown reason, putting the python_version statement at the end doesn't work
+functools32==3.2.3.post2 ; python_version < "3.0" \
+    --hash=sha256:89d824aa6c358c421a234d7f9ee0bd75933a67c29588ce50aaa3acdf4d403fa0 \
+    --hash=sha256:f6253dfbe0538ad2e387bd8fdfd9293c925d63553f5813c4e587745416501e6d
 mccabe==0.6.1 \
-    --hash=sha512:9cebc6bd1c8c0201072c8c18fac5e250544ec61d6421e75e7db31a526e3f5daa5e9afae8e1ac85ed7df23d3e3216950ee311051230c685044432dabd81a3e14a \
-    --hash=sha512:d8fc251a29790887c14c5932c5172b4cd578cd37ccf14cb96e80f0b97f27023427ea032d14e1e2a99d72627b055eb285f60db69e679ecd79d90a34b0255703d8
-more-itertools==4.3.0 \
-    --hash=sha512:5fee3d99fd796b0f0f6b5aa99a8db22e219d3dced71fef6f4b16286fe67061dce280389b3638c55c6e5f6c828ef1286cee845d76a6861d2af66d90e995d5aa4e \
-    --hash=sha512:6b551ae04729c6b6531121384efcc9e3db9de028d121da27cf10fae862ea28e8e73e8bcb1e3d4f6f5f0bfac5a4774bdd731f877639a4dc685bf64b207d6b69ab \
-    --hash=sha512:a01f0070312c1cfdfbd5ff56c2e98779b7cd67b824885a49a4cd9ea99b6dc1462bacb56f2ac6132aa8febb0ef9263546ecb5f57566f091d84d69a821af7faaa1
-pathlib2==2.3.2 \
-    --hash=sha512:2bc072ab13d311f54ad8b1bcfb826f56ba62572dcb3b1788594429e5e47e08488f69d3ddae99b5278306d90717565ac75bd2bfb3e4b8c5cd82b1fe359649c9cd \
-    --hash=sha512:46ba0cc8b26006bc4cb914118b7c453dc49cc8a80147ea7a4b3d5a17e97d5538c5d73a3029bd7e5b59f42f256baba30ea273382e57468df1a459ac6f7c237ddc \
-    ; python_version < "3.6"
-pluggy==0.7.1 \
-    --hash=sha512:8d111f37894239974af6daff28d3fadc0f5b8c25cf9544391538e1992341720de056c23a98754c5646447020f2adbf974b9524954c57c93558d232d9de67c078 \
-    --hash=sha512:e19f6c1b3f2e711df1c8b075a2b802751afd218f1b692f08b2434c01d71c402331ff8c937550fbdfece2098f6d6856422d485f193e188916b365ded2e4087697
-py==1.6.0 \
-    --hash=sha256:50402e9d1c9005d759426988a492e0edaadb7f4e68bcddfea586bc7432d009c6 \
-    --hash=sha256:06a30435d058473046be836d3fc4f27167fd84c45b99704f2fb5509ef61f9af1
-pycodestyle==2.3.1  \
-    --hash=sha512:276bc21b4e6898e379be88f3582135a21314460ad20d4b6c3e12825ac1a72082b2c08bb62099e704c3222f879a1098d0b305132fac1095aaa60ca239b9763a2d \
-    --hash=sha512:e58e10d1514edacfa5a844935a0c4643614dc8b656c9b900d8a56928659cc06c30b2b25ad231261d90837bd53495f8d7ba9748b5480902eadd83124cd262e0ac \
-    # pyup: <2.4.0
-pydocstyle==2.1.1 \
-    --hash=sha512:7bf9e7f35af02cf2da7090316e4c42bd21015604ef6388e88feae7322843b407097bbbb7d12eadbdf179f94db2f7502a8eafc17464e27e5262ccb310be5ef2cf \
-    --hash=sha512:815c604c81e6cf7824dd29af24797534e078860d4bbbaa35962beebc7284fe27e2c4238fa806a57225680f0d96c2bef544e0243a98efdc61ac59253aba7d5e5c \
-    --hash=sha512:e3cc922df3fa2c581d9086dbfc7fc2618dc4b2ea5d9b41b7b15625c02a1110e6390b771f696086b32f2c0635f2c0d4ced779211dcaf960d9660e0f52d9269c1d 
-pyflakes==1.6.0 \
-    --hash=sha512:340f63ed287bfc0bcbe924a5692b7dad1694c874ffe9ce279f744db0726efe42c57573b4416cd5d4cd1fb1a5b3262fb76ba7b8cfab1f00b65771cdb67b7c0062 \
-    --hash=sha512:7e9c2aad6ebed638a1354cef51c7e1f68b25e59f8caf4694997a9afecd7cd8baa629a9363297ac0d961430f007fd22dcae7dae1bcbd7838a3b5d4285063bc7c5
-    # pyup: <1.7.0
-pytest==3.8.0 \
-    --hash=sha256:453cbbbe5ce6db38717d282b758b917de84802af4288910c12442984bde7b823 \
-    --hash=sha256:a8a07f84e680482eb51e244370aaf2caa6301ef265f37c2bdefb3dd3b663f99d
-pytest-cov==2.6.0 \
-    --hash=sha256:513c425e931a0344944f84ea47f3956be0e416d95acbd897a44970c8d926d5d7 \
-    --hash=sha256:e360f048b7dae3f2f2a9a4d067b2dd6b6a015d384d1577c994a43f3f7cbad762
+    --hash=sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42 \
+    --hash=sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f \
+    # via flake8
+more-itertools==5.0.0 \
+    --hash=sha256:38a936c0a6d98a38bcc2d03fdaaedaba9f412879461dd2ceff8d37564d6522e4 \
+    --hash=sha256:c0a5785b1109a6bd7fac76d6837fd1feca158e54e521ccd2ae8bfe393cc9d4fc \
+    --hash=sha256:fe7a7cae1ccb57d33952113ff4fa1bc5f879963600ed74918f1236e212ee50b9 \
+    # via pytest
+pathlib2==2.3.3 \
+    --hash=sha256:25199318e8cc3c25dcb45cbe084cc061051336d5a9ea2a12448d3d8cb748f742 \
+    --hash=sha256:5887121d7f7df3603bca2f710e7219f3eca0eb69e0b7cc6e0a022e155ac931a7 ; python_version < "3.6"
+pluggy==0.8.1 \
+    --hash=sha256:8ddc32f03971bfdf900a81961a48ccf2fb677cf7715108f85295c67405798616 \
+    --hash=sha256:980710797ff6a041e9a73a5787804f848996ecaa6f8a1b1e08224a5894f2074a \
+    # via pytest
+py==1.7.0 \
+    --hash=sha256:bf92637198836372b520efcba9e020c330123be8ce527e535d185ed4b6f45694 \
+    --hash=sha256:e76826342cefe3c3d5f7e8ee4316b80d1dd8a300781612ddbc765c17ba25a6c6 \
+    # via pytest
+pycodestyle==2.5.0 \
+    --hash=sha256:95a2219d12372f05704562a14ec30bc76b05a5b297b21a5dfe3f6fac3491ae56 \
+    --hash=sha256:e40a936c9a450ad81df37f549d676d127b1b66000a6c500caa2b085bc0ca976c \
+    # via flake8
+pydocstyle==3.0.0 \
+    --hash=sha256:2258f9b0df68b97bf3a6c29003edc5238ff8879f1efb6f1999988d934e432bd8 \
+    --hash=sha256:5741c85e408f9e0ddf873611085e819b809fca90b619f5fd7f34bd4959da3dd4 \
+    --hash=sha256:ed79d4ec5e92655eccc21eb0c6cf512e69512b4a97d215ace46d17e4990f2039 \
+    # via flake8-docstrings
+pyflakes==2.1.0 \
+    --hash=sha256:5e8c00e30c464c99e0b501dc160b13a14af7f27d4dffb529c556e30a159e231d \
+    --hash=sha256:f277f9ca3e55de669fba45b7393a1449009cff5a37d1af10ebb76c52765269cd \
+    # via flake8
+pytest-cov==2.6.1 \
+    --hash=sha256:0ab664b25c6aa9716cbf203b17ddb301932383046082c081b9848a0edf5add33 \
+    --hash=sha256:230ef817450ab0699c6cc3c9c8f7a829c34674456f2ed8df1fe1d39780f7c87f
+pytest==4.3.0 \
+    --hash=sha256:067a1d4bf827ffdd56ad21bd46674703fce77c5957f6c1eef731f6146bfcef1c \
+    --hash=sha256:9687049d53695ad45cf5fdc7bbd51f0c49f1ea3ecfc4b7f3fde7501b541f17f4
 scandir==1.9.0 \
-    --hash=sha512:0b673afcd993095a3a5b56f501b533f5ca5732362b200551faa7d9a26b22814c288082747b548752b98588ca20f131cbfaf52eeada3e8054c4c70084176a868a \
-    --hash=sha512:1d1ae30e4adbe07c4f54c2319c71e782f07a64bc3f59b620f6d43ef71e0e12a012f33bcd8de6bada06131e0be5185a930502919093adb12c42f4798084dec410 \
-    --hash=sha512:3ae68b5e6d9e22c354cc587cf62afb971601dd76168f7e8d701ce37de28579dd68f4e1958dc61ae18759d03238b795036130b1968088838ff13ad5c02b31cf35 \
-    --hash=sha512:41dacf42734ac9a53bb5bd5d783023236d68bb4883c853fb2ee34224206c577a4a277d4a8cf8f9be6fd5a8b59d9b4fe4568a0c815a62ec84ce99ded933961ec3 \
-    --hash=sha512:a34fc8b5a28711f796bd806210ce8fc5d72c604f84c8cbf20bc62c916105932152cb627b875b0b2b9127f930c5cad7d628f9c4ee061d126339a84aaad9fd810a \
-    --hash=sha512:a6d927cb63a3f39e10493428e1bde0f73b7f0716ef9d014e9cfc6c3e68934dbac98825bc3965de803f05abdb4e685942a0fbc3a962c511bbbbc19765f96749f8 \
-    --hash=sha512:bbeeb756a65d0cf43cb742e7b3bcde9cfb697b86ca48f803f497d3cb99f448ea8714bb50e69abcf17a0049bad0c399e03949f7bc52d13a13b6d673a824b3fc94 \
-    --hash=sha512:c29009141ae5353d485500c4bb33b66c1e2164b333ddcdf7c4b72da67063844f15a2a02c30d30507b6bb1b04b79761045073fd1d243b459bf5108db923bf4d96 \
-    --hash=sha512:c36caf67b3703d83be53d4351957b17fcf3bc8eef8e0326ef800840985a18f5370babd8ac3cb26d21a62fa2d5fb4abda014c59de4f35904b7c596a22501bd118 \
-    --hash=sha512:d73cad3a09fcc5dd3dcecacd4cc77d5571c9d593f96331c028870e7c5130c81773a6e32b7cfdc1ff666e6819694b538262fe786b88c1a46277aa3b2892f0e35c \
-    --hash=sha512:ea7fb1d9488450ac0cd6e640582a90089a3d7fcf9844abecb4f37f253732f295cb628913e3aec147173b7019317cfafe4791b3b04a3759f7c0474f7f2c214c2a
-six==1.11.0 \
-    --hash=sha512:33f246a2e987141e17e5edad9d3537cf3aba0cbdd0bc2a907ea52ce0d674b1474f29c3dd5cc26605fd960396054b189ca5f501708333cad234c223131483fe24 \
-    --hash=sha512:b71248ef493ac12b115fdf06206090078fac147ec6ab6efb67b87e2b9c07a69d55bf8e70fde713d81735a99e560a17da714274e2ecbd7b0200d2e9a0f39970a7
+    --hash=sha256:04b8adb105f2ed313a7c2ef0f1cf7aff4871aa7a1883fa4d8c44b5551ab052d6 \
+    --hash=sha256:1444134990356c81d12f30e4b311379acfbbcd03e0bab591de2696a3b126d58e \
+    --hash=sha256:1b5c314e39f596875e5a95dd81af03730b338c277c54a454226978d5ba95dbb6 \
+    --hash=sha256:346619f72eb0ddc4cf355ceffd225fa52506c92a2ff05318cfabd02a144e7c4e \
+    --hash=sha256:44975e209c4827fc18a3486f257154d34ec6eaec0f90fef0cca1caa482db7064 \
+    --hash=sha256:61859fd7e40b8c71e609c202db5b0c1dbec0d5c7f1449dec2245575bdc866792 \
+    --hash=sha256:a5e232a0bf188362fa00123cc0bb842d363a292de7126126df5527b6a369586a \
+    --hash=sha256:c14701409f311e7a9b7ec8e337f0815baf7ac95776cc78b419a1e6d49889a383 \
+    --hash=sha256:c7708f29d843fc2764310732e41f0ce27feadde453261859ec0fca7865dfc41b \
+    --hash=sha256:c9009c527929f6e25604aec39b0a43c3f831d2947d89d6caaab22f057b7055c8 \
+    --hash=sha256:f5c71e29b4e2af7ccdc03a020c626ede51da471173b4a6ad1e904f2b2e04b4bd \
+    # via pathlib2
+six==1.12.0 \
+    --hash=sha256:3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c \
+    --hash=sha256:d16a0141ec1a18405cd4ce8b4613101da75da0e9a7aec5bdd4fa804d0e0eba73 \
+    # via more-itertools, pathlib2, pydocstyle, pytest
 snowballstemmer==1.2.1 \
-    --hash=sha512:09f860f383d84d12a83c87ef6654fba4ac10bca07e8d2ce88dd428c72754110d56a4b698e125a18818699a289455bf61cf67ea68e349ee8a12d6dfff0a3fbed9 \
-    --hash=sha512:c97bb3d293ffbe16d4c553f8a8ad1dbb5f659441cde93e407f71419f82b8e16b3090df2c0294d64f73382a648cd8cc62bca407124a8e2d60e4c424b78e10b6b8
+    --hash=sha256:919f26a68b2c17a7634da993d91339e288964f93c274f1343e3bbbe2096e1128 \
+    --hash=sha256:9f3bcd3c401c3e862ec0ebe6d2c069ebc012ce142cce209c098ccb5b09136e89 \
+    # via pydocstyle
+typing==3.6.6 \
+    --hash=sha256:4027c5f6127a6267a435201981ba156de91ad0d1d98e9ddc2aa173453453492d \
+    --hash=sha256:57dcf675a99b74d64dacf6fba08fb17cf7e3d5fdff53d4a30ea2a5e7e52543d4 \
+    --hash=sha256:a4c8473ce11a65999c8f59cb093e70686b6c84c98df58c1dae9b3b196089858a \
+    # via flake8
--- a/third_party/python/mozilla-version/requirements.txt
+++ b/third_party/python/mozilla-version/requirements.txt
@@ -1,10 +1,14 @@
-# Generated from dephash.py + hashin.py
+#
+# This file is autogenerated by pip-compile
+# To update, run:
+#
+#    pip-compile --generate-hashes --output-file requirements.txt requirements.txt.in
+#
 attrs==18.2.0 \
-    --hash=sha256:ca4be454458f9dec299268d472aaa5a11f67a4ff70093396e1ceae9c76cf4bbb \
-    --hash=sha256:10cbf6e27dbce8c30807caf056c8eb50917e0eaafe86347671b57254006c3e69
+    --hash=sha256:10cbf6e27dbce8c30807caf056c8eb50917e0eaafe86347671b57254006c3e69 \
+    --hash=sha256:ca4be454458f9dec299268d472aaa5a11f67a4ff70093396e1ceae9c76cf4bbb
 enum34==1.1.6 \
-    --hash=sha512:3671dc8c0c3cf2a3cbafd22feb85bcc66f4262722b59683429af0865642929622fd3213113703c0b811f7e3bf9cee0e30c7403f6971585150fc013ec01333873 \
-    --hash=sha512:4f916143fe35d41b28efb7958ffa7e10d430d66697f8150b98aae3797a058378fd9a4c201969c155f30f88c962f78e4e75e684889d5138cd2fe60406924363e9 \
-    --hash=sha512:51652525adc37bd1af1d81933f965dba9c508838d9f759c80ca1392991515a29c2c0263264a4e175b37a6ba11dca68c354774e448b19ef1bdba96be5474d93ec \
-    --hash=sha512:ac5eedcd9425b06f44c3e9029cfc3e93a266a5b797c1b8bd3ed81cbbe6c90a163245c15f1ab5ebedf03f885edeb61ebc6b341c61e31789072f29f2a3e1b4bece \
-    ; python_version < '3.4'
+    --hash=sha256:2d81cbbe0e73112bdfe6ef8576f2238f2ba27dd0d55752a776c41d38b7da2850 \
+    --hash=sha256:644837f692e5f550741432dd3f223bbb9852018674981b1664e5dc339387588a \
+    --hash=sha256:6bd0f6ad48ec2aa117d3d141940d484deccda84d4fcd884f5c3d93c23ecd8c79 \
+    --hash=sha256:8ad8c4783bf61ded74527bffb48ed9b54166685e4230386a9ed9b1279e2df5b1 ; python_version < "3.4"
--- a/third_party/python/mozilla-version/version.txt
+++ b/third_party/python/mozilla-version/version.txt
@@ -1,1 +1,1 @@
-0.3.0
+0.3.4
--- a/third_party/python/requirements.in
+++ b/third_party/python/requirements.in
@@ -23,17 +23,17 @@ compare-locales==8.0.0
 cookies==2.2.1
 coverage==5.1
 distro==1.4.0
 ecdsa==0.15
 esprima==4.0.1
 fluent.migrate==0.9
 jsmin==2.1.0
 json-e==2.7.0
-mozilla-version==0.3.0
+mozilla-version==0.3.4
 pathlib2==2.3.2
 pathspec==0.8
 pip-tools==4.5.1
 pipenv==2020.06.02
 ply==3.10
 psutil==5.7.0
 pyasn1==0.4.8
 pyflakes==2.2.0
--- a/third_party/python/requirements.txt
+++ b/third_party/python/requirements.txt
@@ -88,18 +88,19 @@ jsmin==2.1.0 \
 json-e==2.7.0 \
     --hash=sha256:d8c1ec3f5bbc7728c3a504ebe58829f283c64eca230871e4eefe974b4cdaae4a \
     # via -r requirements-mach-vendor-python.in
 more-itertools==4.3.0 \
     --hash=sha256:c187a73da93e7a8acc0001572aebc7e3c69daf7bf6881a2cea10650bd4420092 \
     --hash=sha256:c476b5d3a34e12d40130bc2f935028b5f636df8f372dc2c1c01dc19681b2039e \
     --hash=sha256:fcbfeaea0be121980e15bc97b3817b5202ca73d0eae185b4550cbfce2a3ebb3d \
     # via pytest
-mozilla-version==0.3.0 \
-    --hash=sha256:97f428f6a87f1a0569e03c39e446eeed87c3ec5d8300319d41e8348ef832e8ea \
+mozilla-version==0.3.4 \
+    --hash=sha256:3ed4deb7a6fb25c83a5346ef4de08ddff9b2ddc4d16dd8fafb4a84978cc71255 \
+    --hash=sha256:ce5741c2e7d12c30b53de9f79e30d6ac2a8bd4c93be711d30c7a7a08e32a094f \
     # via -r requirements-mach-vendor-python.in
 pathlib2==2.3.2 \
     --hash=sha256:8eb170f8d0d61825e09a95b38be068299ddeda82f35e96c3301a8a5e7604cb83 \
     --hash=sha256:d1aa2a11ba7b8f7b21ab852b1fb5afb277e1bb99d5dfc663380b5015c0d80c5a \
     # via -r requirements-mach-vendor-python.in
 pathspec==0.8 \
     --hash=sha256:7d91249d21749788d07a2d0f94147accd8f845507400749ea19c1ec9054a12b0 \
     --hash=sha256:da45173eb3a6f2a5a487efba21f050af2b41948be6ab52b6a1e3ff22bb8b7061 \