pybarcodes 1.2.1__tar.gz → 1.2.2__tar.gz
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.
- {pybarcodes-1.2.1 → pybarcodes-1.2.2}/PKG-INFO +1 -1
- {pybarcodes-1.2.1 → pybarcodes-1.2.2}/pybarcodes/__init__.py +1 -1
- {pybarcodes-1.2.1 → pybarcodes-1.2.2}/pybarcodes/barcode.py +51 -40
- {pybarcodes-1.2.1 → pybarcodes-1.2.2}/pybarcodes/codes.py +12 -12
- {pybarcodes-1.2.1 → pybarcodes-1.2.2}/pybarcodes/ean.py +9 -9
- pybarcodes-1.2.2/pybarcodes/py.typed +1 -0
- {pybarcodes-1.2.1 → pybarcodes-1.2.2}/pybarcodes.egg-info/PKG-INFO +1 -1
- {pybarcodes-1.2.1 → pybarcodes-1.2.2}/pybarcodes.egg-info/SOURCES.txt +3 -1
- {pybarcodes-1.2.1 → pybarcodes-1.2.2}/pyproject.toml +4 -1
- {pybarcodes-1.2.1 → pybarcodes-1.2.2}/tests/test_codes.py +1 -0
- pybarcodes-1.2.2/tests/test_spec_fixtures.py +55 -0
- {pybarcodes-1.2.1 → pybarcodes-1.2.2}/LICENSE +0 -0
- {pybarcodes-1.2.1 → pybarcodes-1.2.2}/README.rst +0 -0
- {pybarcodes-1.2.1 → pybarcodes-1.2.2}/pybarcodes/codings/__init__.py +0 -0
- {pybarcodes-1.2.1 → pybarcodes-1.2.2}/pybarcodes/codings/codex.py +0 -0
- {pybarcodes-1.2.1 → pybarcodes-1.2.2}/pybarcodes/codings/ean.py +0 -0
- {pybarcodes-1.2.1 → pybarcodes-1.2.2}/pybarcodes/exceptions.py +0 -0
- {pybarcodes-1.2.1 → pybarcodes-1.2.2}/pybarcodes.egg-info/dependency_links.txt +0 -0
- {pybarcodes-1.2.1 → pybarcodes-1.2.2}/pybarcodes.egg-info/requires.txt +0 -0
- {pybarcodes-1.2.1 → pybarcodes-1.2.2}/pybarcodes.egg-info/top_level.txt +0 -0
- {pybarcodes-1.2.1 → pybarcodes-1.2.2}/setup.cfg +0 -0
- {pybarcodes-1.2.1 → pybarcodes-1.2.2}/tests/test_ean.py +0 -0
- {pybarcodes-1.2.1 → pybarcodes-1.2.2}/tests/test_images.py +0 -0
|
@@ -1,22 +1,33 @@
|
|
|
1
1
|
from collections import namedtuple
|
|
2
2
|
from io import BytesIO
|
|
3
|
-
from
|
|
3
|
+
from os import PathLike
|
|
4
|
+
from typing import Any, Optional, Union
|
|
4
5
|
|
|
5
6
|
from PIL import Image, ImageDraw, ImageFont
|
|
6
7
|
|
|
8
|
+
BarcodeInput = Union[str, int]
|
|
9
|
+
PathInput = Union[str, PathLike[str]]
|
|
10
|
+
RenderSize = tuple[int, int]
|
|
11
|
+
RenderOptions = tuple[int, int, int, int, int]
|
|
12
|
+
|
|
7
13
|
|
|
8
14
|
class Barcode:
|
|
9
15
|
"""A base class for all barcode types"""
|
|
10
16
|
|
|
11
|
-
|
|
17
|
+
BARCODE_SIZE: RenderSize
|
|
18
|
+
BARCODE_FONT_SIZE: int
|
|
19
|
+
BARCODE_COLUMN_NUMBER: int
|
|
20
|
+
BARCODE_PADDING: Any
|
|
21
|
+
|
|
22
|
+
def __init__(self, barcode: BarcodeInput):
|
|
12
23
|
self.code = self.normalize(barcode)
|
|
13
24
|
|
|
14
25
|
@classmethod
|
|
15
|
-
def validate(cls, barcode:
|
|
26
|
+
def validate(cls, barcode: BarcodeInput) -> None:
|
|
16
27
|
"""Validate barcode input."""
|
|
17
28
|
|
|
18
29
|
@classmethod
|
|
19
|
-
def normalize(cls, barcode:
|
|
30
|
+
def normalize(cls, barcode: BarcodeInput) -> str:
|
|
20
31
|
"""Return the normalized barcode value used by the instance."""
|
|
21
32
|
|
|
22
33
|
cls.validate(barcode)
|
|
@@ -36,11 +47,11 @@ class Barcode:
|
|
|
36
47
|
|
|
37
48
|
def render(
|
|
38
49
|
self,
|
|
39
|
-
size:
|
|
40
|
-
module_width: int = None,
|
|
41
|
-
bar_height: int = None,
|
|
42
|
-
quiet_zone: int = None,
|
|
43
|
-
font_size: int = None,
|
|
50
|
+
size: Optional[RenderSize] = None,
|
|
51
|
+
module_width: Optional[int] = None,
|
|
52
|
+
bar_height: Optional[int] = None,
|
|
53
|
+
quiet_zone: Optional[int] = None,
|
|
54
|
+
font_size: Optional[int] = None,
|
|
44
55
|
draw_text: bool = True,
|
|
45
56
|
) -> Image.Image:
|
|
46
57
|
"""Create a PIL Image object for the barcode."""
|
|
@@ -59,14 +70,14 @@ class Barcode:
|
|
|
59
70
|
|
|
60
71
|
def save(
|
|
61
72
|
self,
|
|
62
|
-
path:
|
|
63
|
-
size:
|
|
64
|
-
module_width: int = None,
|
|
65
|
-
bar_height: int = None,
|
|
66
|
-
quiet_zone: int = None,
|
|
67
|
-
font_size: int = None,
|
|
73
|
+
path: PathInput,
|
|
74
|
+
size: Optional[RenderSize] = None,
|
|
75
|
+
module_width: Optional[int] = None,
|
|
76
|
+
bar_height: Optional[int] = None,
|
|
77
|
+
quiet_zone: Optional[int] = None,
|
|
78
|
+
font_size: Optional[int] = None,
|
|
68
79
|
draw_text: bool = True,
|
|
69
|
-
**save_kwargs,
|
|
80
|
+
**save_kwargs: Any,
|
|
70
81
|
) -> Image.Image:
|
|
71
82
|
"""Create a PIL Image object and save it to the path given.
|
|
72
83
|
|
|
@@ -124,13 +135,13 @@ class Barcode:
|
|
|
124
135
|
def to_image_bytesio(
|
|
125
136
|
self,
|
|
126
137
|
format: str = "PNG",
|
|
127
|
-
size:
|
|
128
|
-
module_width: int = None,
|
|
129
|
-
bar_height: int = None,
|
|
130
|
-
quiet_zone: int = None,
|
|
131
|
-
font_size: int = None,
|
|
138
|
+
size: Optional[RenderSize] = None,
|
|
139
|
+
module_width: Optional[int] = None,
|
|
140
|
+
bar_height: Optional[int] = None,
|
|
141
|
+
quiet_zone: Optional[int] = None,
|
|
142
|
+
font_size: Optional[int] = None,
|
|
132
143
|
draw_text: bool = True,
|
|
133
|
-
**save_kwargs,
|
|
144
|
+
**save_kwargs: Any,
|
|
134
145
|
) -> BytesIO:
|
|
135
146
|
"""Return the rendered barcode image in a BytesIO object."""
|
|
136
147
|
|
|
@@ -149,13 +160,13 @@ class Barcode:
|
|
|
149
160
|
def to_image_bytes(
|
|
150
161
|
self,
|
|
151
162
|
format: str = "PNG",
|
|
152
|
-
size:
|
|
153
|
-
module_width: int = None,
|
|
154
|
-
bar_height: int = None,
|
|
155
|
-
quiet_zone: int = None,
|
|
156
|
-
font_size: int = None,
|
|
163
|
+
size: Optional[RenderSize] = None,
|
|
164
|
+
module_width: Optional[int] = None,
|
|
165
|
+
bar_height: Optional[int] = None,
|
|
166
|
+
quiet_zone: Optional[int] = None,
|
|
167
|
+
font_size: Optional[int] = None,
|
|
157
168
|
draw_text: bool = True,
|
|
158
|
-
**save_kwargs,
|
|
169
|
+
**save_kwargs: Any,
|
|
159
170
|
) -> bytes:
|
|
160
171
|
"""Return the rendered barcode image as bytes."""
|
|
161
172
|
|
|
@@ -170,7 +181,7 @@ class Barcode:
|
|
|
170
181
|
**save_kwargs,
|
|
171
182
|
).getvalue()
|
|
172
183
|
|
|
173
|
-
def write(self, path:
|
|
184
|
+
def write(self, path: PathInput, encoding: str = "ascii") -> None:
|
|
174
185
|
"""
|
|
175
186
|
Tries to save the barcode to a text file
|
|
176
187
|
|
|
@@ -191,12 +202,12 @@ class Barcode:
|
|
|
191
202
|
|
|
192
203
|
def _get_render_options(
|
|
193
204
|
self,
|
|
194
|
-
module_width: int = None,
|
|
195
|
-
bar_height: int = None,
|
|
196
|
-
quiet_zone: int = None,
|
|
197
|
-
font_size: int = None,
|
|
205
|
+
module_width: Optional[int] = None,
|
|
206
|
+
bar_height: Optional[int] = None,
|
|
207
|
+
quiet_zone: Optional[int] = None,
|
|
208
|
+
font_size: Optional[int] = None,
|
|
198
209
|
draw_text: bool = True,
|
|
199
|
-
):
|
|
210
|
+
) -> RenderOptions:
|
|
200
211
|
padding = self.BARCODE_PADDING
|
|
201
212
|
selected_size, default_font_size = self.BARCODE_SIZE, self.BARCODE_FONT_SIZE
|
|
202
213
|
|
|
@@ -232,10 +243,10 @@ class Barcode:
|
|
|
232
243
|
|
|
233
244
|
def _get_barcode_image(
|
|
234
245
|
self,
|
|
235
|
-
module_width: int = None,
|
|
236
|
-
bar_height: int = None,
|
|
237
|
-
quiet_zone: int = None,
|
|
238
|
-
font_size: int = None,
|
|
246
|
+
module_width: Optional[int] = None,
|
|
247
|
+
bar_height: Optional[int] = None,
|
|
248
|
+
quiet_zone: Optional[int] = None,
|
|
249
|
+
font_size: Optional[int] = None,
|
|
239
250
|
draw_text: bool = True,
|
|
240
251
|
) -> Image.Image:
|
|
241
252
|
"""Creates a PIL Image from the binary string of the barcode
|
|
@@ -296,7 +307,7 @@ class Barcode:
|
|
|
296
307
|
draw.text((x, y), self.code, (0, 0, 0), font=font)
|
|
297
308
|
return base
|
|
298
309
|
|
|
299
|
-
def __eq__(self, other):
|
|
310
|
+
def __eq__(self, other: object) -> bool:
|
|
300
311
|
if isinstance(other, self.__class__):
|
|
301
312
|
return self.code == other.code
|
|
302
313
|
elif isinstance(other, str):
|
|
@@ -307,5 +318,5 @@ class Barcode:
|
|
|
307
318
|
def __str__(self) -> str:
|
|
308
319
|
return f"<{self.__class__.__name__}(code={self.code})>"
|
|
309
320
|
|
|
310
|
-
def __repr__(self):
|
|
321
|
+
def __repr__(self) -> str:
|
|
311
322
|
return self.__str__()
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
from collections import namedtuple
|
|
2
|
-
from typing import Union
|
|
2
|
+
from typing import Optional, Union
|
|
3
3
|
|
|
4
4
|
from PIL import Image, ImageDraw
|
|
5
5
|
|
|
6
|
-
from .barcode import Barcode
|
|
6
|
+
from .barcode import Barcode, BarcodeInput
|
|
7
7
|
from .codings import codex as CODEXCoding
|
|
8
8
|
from .exceptions import IncorrectFormat
|
|
9
9
|
|
|
@@ -11,7 +11,7 @@ Size = namedtuple("Size", "width height")
|
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
class Code(Barcode):
|
|
14
|
-
def __init__(self, barcode:
|
|
14
|
+
def __init__(self, barcode: BarcodeInput):
|
|
15
15
|
super().__init__(barcode)
|
|
16
16
|
|
|
17
17
|
self.checksum = self.code[-1]
|
|
@@ -36,7 +36,7 @@ class Code(Barcode):
|
|
|
36
36
|
self.BARCODE_COLUMN_NUMBER = column_size
|
|
37
37
|
|
|
38
38
|
@classmethod
|
|
39
|
-
def validate(cls, barcode:
|
|
39
|
+
def validate(cls, barcode: BarcodeInput) -> None:
|
|
40
40
|
code = str(barcode).upper()
|
|
41
41
|
|
|
42
42
|
for char in code:
|
|
@@ -46,7 +46,7 @@ class Code(Barcode):
|
|
|
46
46
|
)
|
|
47
47
|
|
|
48
48
|
@classmethod
|
|
49
|
-
def normalize(cls, barcode:
|
|
49
|
+
def normalize(cls, barcode: BarcodeInput) -> str:
|
|
50
50
|
cls.validate(barcode)
|
|
51
51
|
code = str(barcode).upper()
|
|
52
52
|
reference = cls._calculate_checksum(code)
|
|
@@ -93,7 +93,7 @@ class Code(Barcode):
|
|
|
93
93
|
|
|
94
94
|
return self._convert_to_binary(code)
|
|
95
95
|
|
|
96
|
-
def calculate_checksum(self, barcode: Union[str, "CODE39"] = None) -> int:
|
|
96
|
+
def calculate_checksum(self, barcode: Optional[Union[str, "CODE39"]] = None) -> int:
|
|
97
97
|
"""Calculate the checksum of the barcode
|
|
98
98
|
|
|
99
99
|
Parameters
|
|
@@ -126,10 +126,10 @@ class Code(Barcode):
|
|
|
126
126
|
|
|
127
127
|
def _get_barcode_image(
|
|
128
128
|
self,
|
|
129
|
-
module_width: int = None,
|
|
130
|
-
bar_height: int = None,
|
|
131
|
-
quiet_zone: int = None,
|
|
132
|
-
font_size: int = None,
|
|
129
|
+
module_width: Optional[int] = None,
|
|
130
|
+
bar_height: Optional[int] = None,
|
|
131
|
+
quiet_zone: Optional[int] = None,
|
|
132
|
+
font_size: Optional[int] = None,
|
|
133
133
|
draw_text: bool = True,
|
|
134
134
|
) -> Image.Image:
|
|
135
135
|
"""Creates a PIL Image from the binary string of the barcode.
|
|
@@ -291,5 +291,5 @@ class CODE39(Code):
|
|
|
291
291
|
BARCODE_FONT_SIZE = 30
|
|
292
292
|
BARCODE_PADDING = Size(50, 100)
|
|
293
293
|
|
|
294
|
-
def __init__(self, barcode:
|
|
295
|
-
super().__init__(barcode
|
|
294
|
+
def __init__(self, barcode: BarcodeInput):
|
|
295
|
+
super().__init__(barcode)
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
from collections import namedtuple
|
|
2
2
|
from typing import Union
|
|
3
3
|
|
|
4
|
-
from .barcode import Barcode
|
|
4
|
+
from .barcode import Barcode, BarcodeInput
|
|
5
5
|
from .codings import ean as EANCoding
|
|
6
6
|
from .exceptions import IncorrectFormat
|
|
7
7
|
|
|
@@ -15,11 +15,11 @@ class EAN(Barcode):
|
|
|
15
15
|
Shouldn't be used directly and it's subclasses are preferred
|
|
16
16
|
"""
|
|
17
17
|
|
|
18
|
-
def __init__(self, barcode:
|
|
18
|
+
def __init__(self, barcode: BarcodeInput):
|
|
19
19
|
super().__init__(barcode)
|
|
20
20
|
|
|
21
21
|
@classmethod
|
|
22
|
-
def validate(cls, barcode:
|
|
22
|
+
def validate(cls, barcode: BarcodeInput) -> None:
|
|
23
23
|
code = str(barcode)
|
|
24
24
|
|
|
25
25
|
if not code.isdigit():
|
|
@@ -34,7 +34,7 @@ class EAN(Barcode):
|
|
|
34
34
|
raise IncorrectFormat(error)
|
|
35
35
|
|
|
36
36
|
@classmethod
|
|
37
|
-
def normalize(cls, barcode:
|
|
37
|
+
def normalize(cls, barcode: BarcodeInput) -> str:
|
|
38
38
|
cls.validate(barcode)
|
|
39
39
|
code = str(barcode)[: cls.BARCODE_LENGTH]
|
|
40
40
|
check_digit = cls.calculate_checksum(code)
|
|
@@ -187,7 +187,7 @@ class EAN14(EAN):
|
|
|
187
187
|
WEIGHTS = Weights(1, 3)
|
|
188
188
|
HAS_STRUCTURE = True
|
|
189
189
|
|
|
190
|
-
def __init__(self, barcode:
|
|
190
|
+
def __init__(self, barcode: BarcodeInput):
|
|
191
191
|
super().__init__(barcode)
|
|
192
192
|
|
|
193
193
|
|
|
@@ -218,7 +218,7 @@ class EAN13(EAN):
|
|
|
218
218
|
WEIGHTS = Weights(3, 1)
|
|
219
219
|
HAS_STRUCTURE = True
|
|
220
220
|
|
|
221
|
-
def __init__(self, barcode:
|
|
221
|
+
def __init__(self, barcode: BarcodeInput):
|
|
222
222
|
super().__init__(barcode)
|
|
223
223
|
|
|
224
224
|
|
|
@@ -249,7 +249,7 @@ class EAN8(EAN):
|
|
|
249
249
|
WEIGHTS = Weights(1, 3)
|
|
250
250
|
HAS_STRUCTURE = False
|
|
251
251
|
|
|
252
|
-
def __init__(self, barcode:
|
|
252
|
+
def __init__(self, barcode: BarcodeInput):
|
|
253
253
|
super().__init__(barcode)
|
|
254
254
|
|
|
255
255
|
|
|
@@ -271,7 +271,7 @@ class JAN(EAN13, EAN):
|
|
|
271
271
|
"""
|
|
272
272
|
|
|
273
273
|
@classmethod
|
|
274
|
-
def validate(cls, barcode:
|
|
274
|
+
def validate(cls, barcode: BarcodeInput) -> None:
|
|
275
275
|
super().validate(barcode)
|
|
276
276
|
|
|
277
277
|
code = str(barcode)
|
|
@@ -280,7 +280,7 @@ class JAN(EAN13, EAN):
|
|
|
280
280
|
"JAN type barcodes need to start with country code 45 or 49."
|
|
281
281
|
)
|
|
282
282
|
|
|
283
|
-
def __init__(self, barcode:
|
|
283
|
+
def __init__(self, barcode: BarcodeInput):
|
|
284
284
|
super().__init__(barcode)
|
|
285
285
|
|
|
286
286
|
if self.code[:2] not in ("45", "49"):
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# Marker file for PEP 561 typed packages.
|
|
@@ -6,6 +6,7 @@ pybarcodes/barcode.py
|
|
|
6
6
|
pybarcodes/codes.py
|
|
7
7
|
pybarcodes/ean.py
|
|
8
8
|
pybarcodes/exceptions.py
|
|
9
|
+
pybarcodes/py.typed
|
|
9
10
|
pybarcodes.egg-info/PKG-INFO
|
|
10
11
|
pybarcodes.egg-info/SOURCES.txt
|
|
11
12
|
pybarcodes.egg-info/dependency_links.txt
|
|
@@ -16,4 +17,5 @@ pybarcodes/codings/codex.py
|
|
|
16
17
|
pybarcodes/codings/ean.py
|
|
17
18
|
tests/test_codes.py
|
|
18
19
|
tests/test_ean.py
|
|
19
|
-
tests/test_images.py
|
|
20
|
+
tests/test_images.py
|
|
21
|
+
tests/test_spec_fixtures.py
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "pybarcodes"
|
|
3
|
-
version = "1.2.
|
|
3
|
+
version = "1.2.2"
|
|
4
4
|
description = "A Python package for barcode generation"
|
|
5
5
|
authors = [{ name = "atbuy", email = "buy@atbuy.dev" }]
|
|
6
6
|
license = "MIT"
|
|
@@ -51,6 +51,9 @@ addopts = "--cov-fail-under=90"
|
|
|
51
51
|
[tool.setuptools.packages.find]
|
|
52
52
|
include = ["pybarcodes*"]
|
|
53
53
|
|
|
54
|
+
[tool.setuptools.package-data]
|
|
55
|
+
pybarcodes = ["py.typed"]
|
|
56
|
+
|
|
54
57
|
[build-system]
|
|
55
58
|
requires = ["setuptools"]
|
|
56
59
|
build-backend = "setuptools.build_meta"
|
|
@@ -18,6 +18,7 @@ def test_code39():
|
|
|
18
18
|
assert barcode.calculate_checksum(code) == 40
|
|
19
19
|
assert barcode.calculate_checksum() == 40
|
|
20
20
|
assert CODE39.normalize("abc123") == CODE39("abc123").code
|
|
21
|
+
assert CODE39(123).code == CODE39.normalize(123)
|
|
21
22
|
assert CODE39.validate("abc123") is None
|
|
22
23
|
|
|
23
24
|
with pytest.raises(IncorrectFormat):
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
|
|
3
|
+
from pybarcodes import CODE39, EAN8, EAN13, EAN14
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
# GS1 check digit algorithm reference:
|
|
7
|
+
# https://www.gs1.org/services/how-calculate-check-digit-manually
|
|
8
|
+
@pytest.mark.parametrize(
|
|
9
|
+
("barcode_type", "payload", "expected_code"),
|
|
10
|
+
[
|
|
11
|
+
(EAN8, "9638507", "96385074"),
|
|
12
|
+
(EAN13, "629104150021", "6291041500213"),
|
|
13
|
+
(EAN14, "1061414145678", "10614141456786"),
|
|
14
|
+
],
|
|
15
|
+
)
|
|
16
|
+
def test_gs1_check_digit_fixtures(barcode_type, payload, expected_code):
|
|
17
|
+
assert barcode_type.normalize(payload) == expected_code
|
|
18
|
+
assert barcode_type(payload).code == expected_code
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def test_ean8_binary_pattern_fixture():
|
|
22
|
+
barcode = EAN8("9638507")
|
|
23
|
+
|
|
24
|
+
assert barcode.get_binary_string == (
|
|
25
|
+
"1010001011010111101111010110111010101001110111001010001001011100101"
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def test_ean13_binary_pattern_fixture():
|
|
30
|
+
barcode = EAN13("629104150021")
|
|
31
|
+
|
|
32
|
+
assert barcode.get_binary_string == (
|
|
33
|
+
"101"
|
|
34
|
+
"0010011"
|
|
35
|
+
"0010111"
|
|
36
|
+
"0110011"
|
|
37
|
+
"0100111"
|
|
38
|
+
"0100011"
|
|
39
|
+
"0011001"
|
|
40
|
+
"01010"
|
|
41
|
+
"1001110"
|
|
42
|
+
"1110010"
|
|
43
|
+
"1110010"
|
|
44
|
+
"1101100"
|
|
45
|
+
"1100110"
|
|
46
|
+
"1000010"
|
|
47
|
+
"101"
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
# Code 39 MOD43 reference:
|
|
52
|
+
# https://docshield.tungstenautomation.com/ControlSuite/en_US/1.5.0-uh5vow9jo0/help/QCP/Dita/ACSCChecksum.html
|
|
53
|
+
def test_code39_mod43_check_digit_fixture():
|
|
54
|
+
assert CODE39.normalize("+1110001111") == "+11100011115"
|
|
55
|
+
assert CODE39("+1110001111").calculate_checksum("+1110001111") == 5
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|