ean-tools 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
ean_tools/__init__.py ADDED
File without changes
@@ -0,0 +1,57 @@
1
+ from dataclasses import dataclass
2
+ from enum import Enum
3
+ from typing import Optional
4
+
5
+ from ean_tools.barcode_prefixes import get_raw_ean8_prefix_info, get_raw_ean13_prefix_info, get_raw_isbn_prefix_info
6
+
7
+
8
+ class BarcodeType(Enum):
9
+ COUPON_ID = 'COUPON_ID'
10
+ DEMO = 'DEMO'
11
+ GENERAL_MANAGER_NUMBER = 'GENERAL_MANAGER_NUMBER'
12
+ REFUND_RECEIPT = 'REFUND_RECEIPT'
13
+ REGULAR = 'REGULAR'
14
+ RESERVED_FOR_FUTURE = 'RESERVED_FOR_FUTURE'
15
+ RESTRICTED_CIRCULATION = 'RESTRICTED_CIRCULATION'
16
+ UNUSED = 'UNUSED'
17
+
18
+
19
+ @dataclass
20
+ class BarcodeInfo:
21
+ barcode_type: BarcodeType
22
+ description: str
23
+ country: Optional[str]
24
+
25
+
26
+ def get_barcode_info(normalized_barcode: str) -> BarcodeInfo:
27
+ """Retrieves information about a given barcode.
28
+
29
+ Args:
30
+ normalized_barcode (str): The normalized barcode string.
31
+
32
+ Returns:
33
+ BarcodeInfo: An object containing barcode information.
34
+ """
35
+ if len(normalized_barcode) == 13 and (normalized_barcode.startswith('978') or normalized_barcode.startswith('979')):
36
+ barcode_info = get_raw_isbn_prefix_info(normalized_barcode)
37
+ if not barcode_info:
38
+ return BarcodeInfo(BarcodeType.REGULAR, 'ISBN', None)
39
+
40
+ return BarcodeInfo(BarcodeType.REGULAR, barcode_info['description'], barcode_info.get('country'))
41
+
42
+ if len(normalized_barcode) == 8:
43
+ barcode_info = get_raw_ean8_prefix_info(normalized_barcode)
44
+ elif len(normalized_barcode) == 14:
45
+ barcode_info = get_raw_ean13_prefix_info(normalized_barcode[1:])
46
+ else:
47
+ barcode_info = get_raw_ean13_prefix_info(normalized_barcode)
48
+
49
+ if not barcode_info:
50
+ return BarcodeInfo(BarcodeType.RESERVED_FOR_FUTURE, 'Reserved for future use', None)
51
+
52
+ if 'type' in barcode_info:
53
+ barcode_type = BarcodeType[barcode_info['type']]
54
+ else:
55
+ barcode_type = BarcodeType.REGULAR
56
+
57
+ return BarcodeInfo(barcode_type, barcode_info['description'], barcode_info.get('country'))
@@ -0,0 +1,61 @@
1
+ import os
2
+ from typing import Optional
3
+
4
+ import yaml
5
+
6
+ from affix_tree import AffixTree
7
+
8
+ _CURRENT_DIR = os.path.dirname(__file__)
9
+
10
+
11
+ def init_gs1_prefixes() -> AffixTree[dict]:
12
+ with open(os.path.join(_CURRENT_DIR, 'data/gs1-prefixes.yaml')) as gs1_prefixes_file:
13
+ _gs1_prefixes = yaml.load(gs1_prefixes_file.read(), yaml.CBaseLoader)
14
+
15
+ gs1_prefixes = AffixTree()
16
+ for prefix_group in _gs1_prefixes:
17
+ for p in prefix_group.pop('prefixes'):
18
+ gs1_prefixes.add(p, prefix_group)
19
+
20
+ return gs1_prefixes
21
+
22
+
23
+ def init_gs1_8_prefixes() -> AffixTree[dict]:
24
+ with open(os.path.join(_CURRENT_DIR, 'data/gs1-8-prefixes.yaml')) as gs1_8_prefixes_file:
25
+ _gs1_8_prefixes = yaml.load(gs1_8_prefixes_file.read(), yaml.CBaseLoader)
26
+
27
+ gs1_8_prefixes = AffixTree()
28
+ for prefix_group in _gs1_8_prefixes:
29
+ for p in prefix_group.pop('prefixes'):
30
+ gs1_8_prefixes.add(p, prefix_group)
31
+
32
+ return gs1_8_prefixes
33
+
34
+
35
+ def init_isbn_prefixes() -> AffixTree[dict]:
36
+ with open(os.path.join(_CURRENT_DIR, 'data/isbn-prefixes.yaml')) as isbn_prefixes_file:
37
+ _isbn_prefixes = yaml.load(isbn_prefixes_file.read(), yaml.CBaseLoader)
38
+
39
+ isbn_prefixes = AffixTree()
40
+ for prefix_group in _isbn_prefixes:
41
+ for p in prefix_group.pop('prefixes'):
42
+ isbn_prefixes.add(p, prefix_group)
43
+
44
+ return isbn_prefixes
45
+
46
+
47
+ _GS1_8_PREFIXES: AffixTree[dict] = init_gs1_8_prefixes()
48
+ _GS1_PREFIXES: AffixTree[dict] = init_gs1_prefixes()
49
+ _ISBN_PREFIXES: AffixTree[dict] = init_isbn_prefixes()
50
+
51
+
52
+ def get_raw_ean8_prefix_info(barcode: str) -> Optional[dict]:
53
+ return _GS1_8_PREFIXES.find(barcode)
54
+
55
+
56
+ def get_raw_ean13_prefix_info(barcode: str) -> Optional[dict]:
57
+ return _GS1_PREFIXES.find(barcode)
58
+
59
+
60
+ def get_raw_isbn_prefix_info(barcode: str) -> Optional[dict]:
61
+ return _ISBN_PREFIXES.find(barcode)
@@ -0,0 +1,44 @@
1
+ def has_correct_check_digit(normalized_barcode: str) -> bool:
2
+ """Checks if the given barcode has the correct check digit.
3
+
4
+ Args:
5
+ normalized_barcode (str): Normalized barcode string.
6
+
7
+ Returns:
8
+ bool: True if the check digit is correct, False otherwise.
9
+ """
10
+ return get_correct_check_digit(normalized_barcode) == normalized_barcode[-1]
11
+
12
+
13
+ def get_correct_check_digit(normalized_barcode: str) -> str:
14
+ """Calculates the correct check digit for a barcode.
15
+
16
+ Args:
17
+ normalized_barcode (str): Normalized barcode string.
18
+
19
+ Returns:
20
+ str: The correct check digit.
21
+ """
22
+ check_digit = 0
23
+ barcode_length = len(normalized_barcode)
24
+
25
+ i = barcode_length - 2
26
+ while i >= 0:
27
+ weight = 3 if (barcode_length - i) % 2 == 0 else 1
28
+ check_digit += int(normalized_barcode[i]) * weight
29
+ i -= 1
30
+
31
+ return str((10 - (check_digit % 10)) % 10)
32
+
33
+
34
+ def isbn10_has_correct_check_digit(isbn10: str) -> bool:
35
+ """Checks if an ISBN-10 barcode has the correct check digit.
36
+
37
+ Args:
38
+ isbn10 (str): The ISBN-10 barcode string.
39
+
40
+ Returns:
41
+ bool: True if the check digit is correct, False otherwise.
42
+ """
43
+ s = sum((10 - i) * int(c) for i, c in enumerate(isbn10))
44
+ return s % 11 == 0
@@ -0,0 +1,28 @@
1
+ - description: Used to issue Restricted Circulation Numbers within a company
2
+ type: RESTRICTED_CIRCULATION
3
+ prefixes:
4
+ - '0'
5
+ - '2'
6
+ - description: Used to issue GTIN-8s
7
+ prefixes:
8
+ - '1'
9
+ - '3'
10
+ - '4'
11
+ - '5'
12
+ - '6'
13
+ - '7'
14
+ - '8'
15
+ - '90'
16
+ - '91'
17
+ - '92'
18
+ - '93'
19
+ - '94'
20
+ - '95'
21
+ - '96'
22
+ - '970'
23
+ - '971'
24
+ - '972'
25
+ - '973'
26
+ - '974'
27
+ - '975'
28
+ - '976'