ean-tools 0.1.0__tar.gz

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,62 @@
1
+ Metadata-Version: 2.3
2
+ Name: ean-tools
3
+ Version: 0.1.0
4
+ Summary: Collection of tools for validating and getting information about EAN (UPC, GTIN) and ISBN barcodes.
5
+ Home-page: https://github.com/ean-db/ean-tools
6
+ License: MIT
7
+ Keywords: barcode,ean,upc,isbn,gtin
8
+ Author: EAN-DB
9
+ Author-email: support@ean-db.com
10
+ Requires-Python: >=3.12
11
+ Classifier: License :: OSI Approved :: MIT License
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Programming Language :: Python :: 3.12
14
+ Classifier: Programming Language :: Python :: 3.13
15
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
16
+ Requires-Dist: PyYaml (>=6)
17
+ Requires-Dist: affix-tree (>=0.1.1)
18
+ Project-URL: Repository, https://github.com/ean-db/ean-tools
19
+ Description-Content-Type: text/markdown
20
+
21
+ # ean-tools
22
+
23
+ Collection of tools for validating and getting information about EAN (UPC, GTIN) and ISBN barcodes.
24
+
25
+ ## Installation
26
+
27
+ ```commandline
28
+ pip install affix-tree
29
+ ```
30
+
31
+ ## Usage
32
+
33
+ ### Barcode normalization
34
+
35
+ ```pycon
36
+ >>> from ean_tools.normalization import normalize_barcode
37
+
38
+ >>> normalize_barcode('978-84865-4608-3')
39
+
40
+ '9788486546083'
41
+ ```
42
+
43
+ ### Check digit validation
44
+
45
+ ```pycon
46
+ >>> from ean_tools.check_digits import has_correct_check_digit
47
+
48
+ >>> has_correct_check_digit('8510000076279')
49
+
50
+ False
51
+ ```
52
+
53
+ ### Getting additional barcode information
54
+
55
+ ```pycon
56
+ >>> from ean_tools.barcode_info import get_barcode_info, BarcodeType
57
+
58
+ >>> get_barcode_info('4000000001140')
59
+
60
+ BarcodeInfo(barcode_type=BarcodeType.REGULAR, description='GS1 Germany', country='de')
61
+ ```
62
+
@@ -0,0 +1,41 @@
1
+ # ean-tools
2
+
3
+ Collection of tools for validating and getting information about EAN (UPC, GTIN) and ISBN barcodes.
4
+
5
+ ## Installation
6
+
7
+ ```commandline
8
+ pip install affix-tree
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ### Barcode normalization
14
+
15
+ ```pycon
16
+ >>> from ean_tools.normalization import normalize_barcode
17
+
18
+ >>> normalize_barcode('978-84865-4608-3')
19
+
20
+ '9788486546083'
21
+ ```
22
+
23
+ ### Check digit validation
24
+
25
+ ```pycon
26
+ >>> from ean_tools.check_digits import has_correct_check_digit
27
+
28
+ >>> has_correct_check_digit('8510000076279')
29
+
30
+ False
31
+ ```
32
+
33
+ ### Getting additional barcode information
34
+
35
+ ```pycon
36
+ >>> from ean_tools.barcode_info import get_barcode_info, BarcodeType
37
+
38
+ >>> get_barcode_info('4000000001140')
39
+
40
+ BarcodeInfo(barcode_type=BarcodeType.REGULAR, description='GS1 Germany', country='de')
41
+ ```
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'