pybarcodes 1.2.1__tar.gz → 1.2.3__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.
Files changed (23) hide show
  1. {pybarcodes-1.2.1 → pybarcodes-1.2.3}/PKG-INFO +1 -1
  2. {pybarcodes-1.2.1 → pybarcodes-1.2.3}/pybarcodes/__init__.py +5 -3
  3. {pybarcodes-1.2.1 → pybarcodes-1.2.3}/pybarcodes/barcode.py +51 -40
  4. {pybarcodes-1.2.1 → pybarcodes-1.2.3}/pybarcodes/codes.py +12 -12
  5. {pybarcodes-1.2.1 → pybarcodes-1.2.3}/pybarcodes/ean.py +9 -9
  6. pybarcodes-1.2.3/pybarcodes/py.typed +1 -0
  7. {pybarcodes-1.2.1 → pybarcodes-1.2.3}/pybarcodes.egg-info/PKG-INFO +1 -1
  8. {pybarcodes-1.2.1 → pybarcodes-1.2.3}/pybarcodes.egg-info/SOURCES.txt +3 -1
  9. {pybarcodes-1.2.1 → pybarcodes-1.2.3}/pyproject.toml +4 -1
  10. {pybarcodes-1.2.1 → pybarcodes-1.2.3}/tests/test_codes.py +1 -0
  11. pybarcodes-1.2.3/tests/test_spec_fixtures.py +55 -0
  12. {pybarcodes-1.2.1 → pybarcodes-1.2.3}/LICENSE +0 -0
  13. {pybarcodes-1.2.1 → pybarcodes-1.2.3}/README.rst +0 -0
  14. {pybarcodes-1.2.1 → pybarcodes-1.2.3}/pybarcodes/codings/__init__.py +0 -0
  15. {pybarcodes-1.2.1 → pybarcodes-1.2.3}/pybarcodes/codings/codex.py +0 -0
  16. {pybarcodes-1.2.1 → pybarcodes-1.2.3}/pybarcodes/codings/ean.py +0 -0
  17. {pybarcodes-1.2.1 → pybarcodes-1.2.3}/pybarcodes/exceptions.py +0 -0
  18. {pybarcodes-1.2.1 → pybarcodes-1.2.3}/pybarcodes.egg-info/dependency_links.txt +0 -0
  19. {pybarcodes-1.2.1 → pybarcodes-1.2.3}/pybarcodes.egg-info/requires.txt +0 -0
  20. {pybarcodes-1.2.1 → pybarcodes-1.2.3}/pybarcodes.egg-info/top_level.txt +0 -0
  21. {pybarcodes-1.2.1 → pybarcodes-1.2.3}/setup.cfg +0 -0
  22. {pybarcodes-1.2.1 → pybarcodes-1.2.3}/tests/test_ean.py +0 -0
  23. {pybarcodes-1.2.1 → pybarcodes-1.2.3}/tests/test_images.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pybarcodes
3
- Version: 1.2.1
3
+ Version: 1.2.3
4
4
  Summary: A Python package for barcode generation
5
5
  Author-email: atbuy <buy@atbuy.dev>
6
6
  License-Expression: MIT
@@ -1,16 +1,18 @@
1
1
  from collections import namedtuple
2
2
 
3
- from pybarcodes.codes import CODE39, Code # noqa: F401
4
- from pybarcodes.ean import EAN, EAN8, EAN13, EAN14, JAN, Size, Weights # noqa: F401
3
+ from pybarcodes.codes import CODE39, Code
4
+ from pybarcodes.ean import EAN, EAN8, EAN13, EAN14, JAN, Size, Weights
5
5
 
6
6
  __title__ = "pybarcodes"
7
7
  __author__ = "atbuy"
8
8
  __license__ = "MIT"
9
9
  __copyright__ = "Copyright 2021-present atbuy"
10
- __version__ = (1, 2, 1)
10
+ __version__ = (1, 2, 3)
11
11
 
12
12
  VersionInfo = namedtuple("VersionInfo", "major minor patch")
13
13
 
14
14
  version_info = VersionInfo(*__version__)
15
15
 
16
16
  SUPPORTED_BARCODES = ["EAN13", "EAN8", "EAN14", "JAN", "CODE39"]
17
+
18
+ __all__ = ("CODE39", "Code", "EAN", "EAN8", "EAN13", "EAN14", "JAN", "Size", "Weights")
@@ -1,22 +1,33 @@
1
1
  from collections import namedtuple
2
2
  from io import BytesIO
3
- from typing import Union
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
- def __init__(self, barcode: Union[str, int]):
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: Union[str, int]) -> None:
26
+ def validate(cls, barcode: BarcodeInput) -> None:
16
27
  """Validate barcode input."""
17
28
 
18
29
  @classmethod
19
- def normalize(cls, barcode: Union[str, int]) -> str:
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: tuple = None,
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: str,
63
- size: tuple = None,
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: tuple = None,
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: tuple = None,
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: str, encoding: str = "ascii") -> None:
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: Union[str, int]):
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: Union[str, int]) -> None:
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: Union[str, int]) -> str:
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: Union[str, int]):
295
- super().__init__(barcode.upper())
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: Union[str, int]):
18
+ def __init__(self, barcode: BarcodeInput):
19
19
  super().__init__(barcode)
20
20
 
21
21
  @classmethod
22
- def validate(cls, barcode: Union[str, int]) -> None:
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: Union[str, int]) -> str:
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: Union[str, int]):
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: Union[str, int]):
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: Union[str, int]):
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: Union[str, int]) -> None:
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: Union[str, int]):
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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pybarcodes
3
- Version: 1.2.1
3
+ Version: 1.2.3
4
4
  Summary: A Python package for barcode generation
5
5
  Author-email: atbuy <buy@atbuy.dev>
6
6
  License-Expression: MIT
@@ -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.1"
3
+ version = "1.2.3"
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