def parse(cls, version_string): """Construct an object representing a valid Firefox version number.""" regex_matches = _VALID_ENOUGH_VERSION_PATTERN.match(version_string) if regex_matches is None: raise PatternNotMatchedError(version_string, _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=regex_matches.group('is_nightly') is not None, is_aurora_or_devedition=regex_matches.group('is_aurora_or_devedition') is not None, is_esr=regex_matches.group('is_esr') is not None, **args )
def __attrs_post_init__(self): """Ensure attributes are sane all together.""" # General checks error_messages = [ pattern_message for condition, pattern_message in (( not self.is_four_digit_scheme and self.old_fourth_number is not None, 'The old fourth number can only be defined on Gecko 1.5.x.y or 2.0.x.y', ), ( self.beta_number is not None and self.patch_number is not None, 'Beta number and patch number cannot be both defined', )) if condition ] # Firefox 5 is the first version to implement the rapid release model, which defines # the scheme used so far. if self.is_rapid_release_scheme: error_messages.extend([ pattern_message for condition, pattern_message in (( self.release_candidate_number is not None, 'Release candidate number cannot be defined starting Gecko 5', ), ( self.minor_number == 0 and self.patch_number == 0, 'Minor number and patch number cannot be both equal to 0', ), ( self.minor_number != 0 and self.patch_number is None, 'Patch number cannot be undefined if minor number is greater than 0', ), ( self.patch_number is not None and self.is_nightly, 'Patch number cannot be defined on a nightly version', ), ( self.patch_number is not None and self.is_aurora_or_devedition, 'Patch number cannot be defined on an aurora version', ), ( self.major_number > self._LAST_AURORA_DEVEDITION_AS_VERSION_TYPE and self.is_aurora_or_devedition, 'Last aurora/devedition version was 54.0a2. Please use the DeveditionVersion ' 'class, past this version.', ), (self.major_number not in self._KNOWN_ESR_MAJOR_NUMBERS and self.is_esr, '"{}" is not a valid ESR major number. Valid ones are: {}'. format(self.major_number, self._KNOWN_ESR_MAJOR_NUMBERS))) if condition ]) else: if self.release_candidate_number is not None: error_messages.extend([ pattern_message for condition, pattern_message in (( self.patch_number is not None, 'Release candidate and patch number cannot be both defined', ), ( self.old_fourth_number is not None, 'Release candidate and the old fourth number cannot be both defined', ), ( self.beta_number is not None, 'Release candidate and beta number cannot be both defined', )) if condition ]) if self.old_fourth_number is not None and self.patch_number != 0: error_messages.append( 'The old fourth number cannot be defined if the patch number is not 0 ' '(we have never shipped a release that did so)') if error_messages: raise PatternNotMatchedError(self, patterns=error_messages)
def __attrs_post_init__(self): """Ensure attributes are sane all together.""" if self.version.build_number is None: raise PatternNotMatchedError(self, pattern='build_number must exist')
def _supported_product(string): product = string.lower() if product not in _SUPPORTED_PRODUCTS: raise PatternNotMatchedError(string, pattern='unknown product') return product
def test_pattern_not_matched_error_raises_if_badly_initialized(): with pytest.raises(ValueError) as exc_info: raise PatternNotMatchedError('some string', patterns=()) assert exc_info.value.args == ('At least one pattern must be provided', )
def test_pattern_not_matched_error_changes_its_error_message( string, patterns, expected_message): with pytest.raises(PatternNotMatchedError) as exc_info: raise PatternNotMatchedError(string, patterns) assert exc_info.value.args == (expected_message, )