def test_extract_fails_with_invalid_date(ai_code: str, bad_value: str) -> None: ai = GS1ApplicationIdentifier.extract(ai_code) with pytest.raises(ParseError) as exc_info: GS1ElementString.extract(f"{ai_code}{bad_value}") assert (str(exc_info.value) == f"Failed to parse GS1 AI {ai} date from {bad_value!r}.")
def test_extract_fails_when_not_matching_pattern(ai_code: str, bad_value: str) -> None: ai = GS1ApplicationIdentifier.extract(ai_code) with pytest.raises(ParseError) as exc_info: GS1ElementString.extract(bad_value) assert ( str(exc_info.value) == f"Failed to match {bad_value!r} with GS1 AI {ai} pattern '{ai.pattern}'." )
def test_extract_amount_payable_and_currency( value: str, expected_currency: str, expected_decimal: Decimal) -> None: element_string = GS1ElementString.extract(value) assert element_string.decimal == expected_decimal # Optional: If py-moneyed is installed, create Money instances assert element_string.money is not None assert element_string.money.amount == expected_decimal assert element_string.money.currency.code == expected_currency
def parse( cls, value: str, *, rcn_region: Optional[RcnRegion] = None, separator_chars: Iterable[str] = DEFAULT_SEPARATOR_CHARS, ) -> GS1Message: """Parse a string from a barcode scan as a GS1 message with AIs. Args: value: The string to parse. rcn_region: The geographical region whose rules should be used to interpret Restricted Circulation Numbers (RCN). Needed to extract e.g. variable weight/price from GTIN. separator_chars: Characters used in place of the FNC1 symbol. Defaults to `<GS>` (ASCII value 29). If variable-length fields in the middle of the message are not terminated with a separator character, the parser might greedily consume the rest of the message. Returns: A message object with one or more element strings. Raises: ParseError: If a fixed-length field ends with a separator character. """ value = value.strip() element_strings = [] rest = value[:] while rest: element_string = GS1ElementString.extract( rest, rcn_region=rcn_region, separator_chars=separator_chars) element_strings.append(element_string) rest = rest[len(element_string):] if rest.startswith(tuple(separator_chars)): if element_string.ai.fnc1_required: rest = rest[1:] else: separator_char = rest[0] raise ParseError( f"Element String {element_string.as_hri()!r} has fixed length " "and should not end with a separator character. " f"Separator character {separator_char!r} found in {value!r}." ) return cls(value=value, element_strings=element_strings)
def test_extract(value: str, expected: GS1ElementString) -> None: assert GS1ElementString.extract(value) == expected
def test_as_hri(value: str, expected: str) -> None: assert GS1ElementString.extract(value).as_hri() == expected
def test_extract_percentage_discount(value: str, expected: Decimal) -> None: assert GS1ElementString.extract(value).decimal == expected
def test_extract_amount_payable(value: str, expected: Decimal) -> None: assert GS1ElementString.extract(value).decimal == expected
def test_extract_variable_measures(value: str, expected: Decimal) -> None: assert GS1ElementString.extract(value).decimal == expected
def test_extract_handles_zero_day_as_last_day_of_month(value: str, expected: date) -> None: assert GS1ElementString.extract(value).date == expected
def test_extract_handles_min_and_max_year_correctly( value: str, expected: GS1ElementString) -> None: assert GS1ElementString.extract(value) == expected