1
- import re
2
-
3
1
from .. import BaseProvider
4
2
3
+ localized = True
4
+
5
5
6
6
class Provider (BaseProvider ):
7
+ # Source of GS1 country codes: https://gs1.org/standards/id-keys/company-prefix
8
+ local_prefixes = ()
7
9
8
- upc_e_base_pattern = re .compile (r'^\d{6}$' )
9
- upc_ae_pattern1 = re .compile (
10
- r'^(?P<number_system_digit>[01])' # The first digit must be 0 or 1
11
- r'(?=\d{11}$)' # followed by 11 digits of which
12
- r'(?P<mfr_code>\d{2})' # the first 2 digits make up the manufacturer code,
13
- r'(?:(?P<extra>[012])0{4})' # if immediately followed by 00000, 10000, or 20000,
14
- r'(?P<product_code>\d{3})' # a 3-digit product code,
15
- r'(?P<check_digit>\d)$' , # and finally a check digit.
16
- )
17
- upc_ae_pattern2 = re .compile (
18
- r'^(?P<number_system_digit>[01])' # The first digit must be 0 or 1
19
- r'(?=\d{11}$)' # followed by 11 digits of which
20
- r'(?P<mfr_code>\d{3,4}?)' # the first 3 or 4 digits make up the manufacturer code,
21
- r'(?:0{5})' # if immediately followed by 00000,
22
- r'(?P<product_code>\d{1,2})' # a 2-digit or single digit product code,
23
- r'(?P<check_digit>\d)$' , # and finally a check digit.
24
- )
25
- upc_ae_pattern3 = re .compile (
26
- r'^(?P<number_system_digit>[01])' # The first digit must be 0 or 1
27
- r'(?=\d{11}$)' # followed by 11 digits of which
28
- r'(?P<mfr_code>\d{5})' # the first 5 digits make up the manufacturer code,
29
- r'(?:0{4}(?P<extra>[5-9]))' # if immediately followed by 0000 and a 5, 6, 7, 8, or 9,
30
- r'(?P<check_digit>\d)$' , # and finally a check digit.
31
- )
32
-
33
- def _ean (self , length = 13 , leading_zero = None ):
10
+ def _ean (self , length = 13 , prefixes = ()):
34
11
if length not in (8 , 13 ):
35
12
raise AssertionError ("length can only be 8 or 13" )
36
13
37
14
code = [self .random_digit () for _ in range (length - 1 )]
38
- if leading_zero is True :
39
- code [ 0 ] = 0
40
- elif leading_zero is False :
41
- code [0 ] = self . random_int ( 1 , 9 )
15
+
16
+ if prefixes :
17
+ prefix = self . random_element ( prefixes )
18
+ code [: len ( prefix ) ] = map ( int , prefix )
42
19
43
20
if length == 8 :
44
21
weights = [3 , 1 , 3 , 1 , 3 , 1 , 3 ]
@@ -51,186 +28,88 @@ def _ean(self, length=13, leading_zero=None):
51
28
52
29
return '' .join (str (x ) for x in code )
53
30
54
- def _convert_upc_a2e (self , upc_a ):
55
- """
56
- Convert a 12-digit UPC-A barcode to its 8-digit UPC-E equivalent.
57
-
58
- Note that not all UPC-A barcodes can be converted.
59
- """
60
- if not isinstance (upc_a , str ):
61
- raise TypeError ('`upc_a` is not a string' )
62
- m1 = self .upc_ae_pattern1 .match (upc_a )
63
- m2 = self .upc_ae_pattern2 .match (upc_a )
64
- m3 = self .upc_ae_pattern3 .match (upc_a )
65
- if not any ([m1 , m2 , m3 ]):
66
- raise ValueError ('`upc_a` has an invalid value' )
67
- upc_e_template = '{number_system_digit}{mfr_code}{product_code}{extra}{check_digit}'
68
- if m1 :
69
- upc_e = upc_e_template .format (** m1 .groupdict ())
70
- elif m2 :
71
- groupdict = m2 .groupdict ()
72
- groupdict ['extra' ] = str (len (groupdict .get ('mfr_code' )))
73
- upc_e = upc_e_template .format (** groupdict )
74
- else :
75
- groupdict = m3 .groupdict ()
76
- groupdict ['product_code' ] = ''
77
- upc_e = upc_e_template .format (** groupdict )
78
- return upc_e
79
-
80
- def _upc_ae (self , base = None , number_system_digit = None ):
81
- """
82
- Create a 12-digit UPC-A barcode that can be converted to UPC-E.
83
-
84
- The expected value of ``base`` is a 6-digit string. If any other value is
85
- provided, this method will use a random 6-digit string instead.
86
-
87
- The expected value of ``number_system_digit`` is the integer ``0`` or ``1``.
88
- If any other value is provided, this method will randomly choose from the two.
89
-
90
- Please also view notes on `upc_a()` and `upc_e()` for more details.
91
- """
92
- if isinstance (base , str ) and self .upc_e_base_pattern .match (base ):
93
- base = [int (x ) for x in base ]
94
- else :
95
- base = [self .random_int (0 , 9 ) for _ in range (6 )]
96
- if number_system_digit not in [0 , 1 ]:
97
- number_system_digit = self .random_int (0 , 1 )
98
-
99
- if base [- 1 ] <= 2 :
100
- code = base [:2 ] + base [- 1 :] + [0 ] * 4 + base [2 :- 1 ]
101
- elif base [- 1 ] <= 4 :
102
- code = base [:base [- 1 ]] + [0 ] * 5 + base [base [- 1 ]:- 1 ]
103
- else :
104
- code = base [:5 ] + [0 ] * 4 + base [- 1 :]
105
-
106
- code .insert (0 , number_system_digit )
107
- weights = [3 , 1 , 3 , 1 , 3 , 1 , 3 , 1 , 3 , 1 , 3 ]
108
- weighted_sum = sum (x * y for x , y in zip (code , weights ))
109
- check_digit = (10 - weighted_sum % 10 ) % 10
110
- code .append (check_digit )
111
- return '' .join (str (x ) for x in code )
112
-
113
- def ean (self , length = 13 ):
31
+ def ean (self , length = 13 , prefixes = ()):
114
32
"""Generate an EAN barcode of the specified ``length``.
115
33
116
34
The value of ``length`` can only be ``8`` or ``13`` (default) which will
117
35
create an EAN-8 or an EAN-13 barcode respectively.
118
36
37
+ If ``prefixes`` are specified, the result will begin with one of the sequence in ``prefixes``
38
+
119
39
:sample: length=13
120
40
:sample: length=8
41
+ :sample: prefixes=('00',)
42
+ :sample: prefixes=('45', '49')
121
43
"""
122
- return self ._ean (length )
44
+ return self ._ean (length , prefixes = prefixes )
123
45
124
- def ean8 (self ):
46
+ def ean8 (self , prefixes = () ):
125
47
"""Generate an EAN-8 barcode.
126
48
127
49
This method uses :meth:`ean() <faker.providers.barcode.Provider.ean>` under the
128
50
hood with the ``length`` argument explicitly set to ``8``.
129
51
52
+ If ``prefixes`` are specified, the result will begin with one of the sequence in ``prefixes``
53
+
130
54
:sample:
55
+ :sample: prefixes=('00',)
56
+ :sample: prefixes=('45', '49')
131
57
"""
132
- return self ._ean (8 )
58
+ return self ._ean (8 , prefixes = prefixes )
133
59
134
- def ean13 (self , leading_zero = None ):
60
+ def ean13 (self , prefixes = () ):
135
61
"""Generate an EAN-13 barcode.
136
62
137
- If ``leading_digit`` is ``True``, the leftmost digit of the barcode will be set
138
- to ``0``. If ``False``, the leftmost digit cannot be ``0``. If ``None`` (default),
139
- the leftmost digit can be any digit.
140
-
141
- Note that an EAN-13 barcode that starts with a zero can be converted to UPC-A
142
- by dropping the leading zero.
63
+ If ``prefixes`` are specified, the result will begin with one of the sequence in ``prefixes``.
143
64
144
65
This method uses :meth:`ean() <faker.providers.barcode.Provider.ean>` under the
145
66
hood with the ``length`` argument explicitly set to ``13``.
146
67
68
+ .. note::
69
+
70
+ Codes starting with a leading zero are treated specially in some barcode readers.
71
+
72
+ For more information about compatibility with UPC-A codes, see
73
+ :meth:`en_US.ean13() <faker.providers.barcode.en_US.Provider.ean13>`
74
+
147
75
:sample:
148
- :sample: leading_zero=False
149
- :sample: leading_zero=True
76
+ :sample: prefixes=('00',)
77
+ :sample: prefixes=('45', '49')
150
78
"""
151
- return self ._ean (13 , leading_zero = leading_zero )
152
79
153
- def upc_a (self , upc_ae_mode = False , base = None , number_system_digit = None ):
154
- """Generate a 12-digit UPC-A barcode.
80
+ return self ._ean (13 , prefixes = prefixes )
155
81
156
- The value of ``upc_ae_mode`` controls how barcodes will be generated. If ``False``
157
- (default), barcodes are not guaranteed to have a UPC-E equivalent. In this mode,
158
- the method uses :meth:`ean13 <faker.providers.barcode.Provider.ean13>` under the hood,
159
- and the values of ``base`` and ``number_system_digit`` will be ignored.
82
+ def localized_ean (self , length = 13 ):
83
+ """Generate a localized EAN barcode of the specified ``length``.
160
84
161
- If ``upc_ae_mode`` is ``True``, the resulting barcodes are guaranteed to have a UPC-E
162
- equivalent, and the values of ``base`` and ``number_system_digit`` will be used to
163
- control what is generated.
85
+ The value of ``length`` can only be ``8`` or ``13`` (default) which will
86
+ create an EAN-8 or an EAN-13 barcode respectively.
164
87
165
- Under this mode, ``base`` is expected to have a 6-digit string value. If any other value
166
- is supplied, a random 6-digit string will be used instead. As for ``number_system_digit``,
167
- the expected value is a ``0`` or a ``1``. If any other value is provided, this method
168
- will randomly choose from the two.
88
+ This method uses :meth:`ean() <faker.providers.barcode.Provider.ean>` under the
89
+ hood with the ``prefixes`` argument explicitly set to ``self.local_prefixes``.
169
90
170
- .. important::
91
+ :sample:
92
+ :sample: length=13
93
+ :sample: length=8
94
+ """
95
+ return self ._ean (length , prefixes = self .local_prefixes )
96
+
97
+ def localized_ean8 (self ):
98
+ """Generate a localized EAN-8 barcode.
171
99
172
- When ``upc_ae_mode`` is enabled, you might encounter instances where different values
173
- of ``base`` (e.g. ``'120003'`` and ``'120004'``) produce the same UPC-A barcode. This
174
- is normal, and the reason lies within the whole conversion process. To learn more about
175
- this and what ``base`` and ``number_system_digit`` actually represent, please refer
176
- to :meth:`upc_e() <faker.providers.barcode.Provider.upc_e>`.
100
+ This method uses :meth:`localized_ean() <faker.providers.barcode.Provider.ean>` under the
101
+ hood with the ``length`` argument explicitly set to ``8``.
177
102
178
103
:sample:
179
- :sample: upc_ae_mode=True, number_system_digit=0
180
- :sample: upc_ae_mode=True, number_system_digit=1
181
- :sample: upc_ae_mode=True, base='123456', number_system_digit=0
182
- :sample: upc_ae_mode=True, base='120003', number_system_digit=0
183
- :sample: upc_ae_mode=True, base='120004', number_system_digit=0
184
104
"""
185
- if upc_ae_mode is True :
186
- return self ._upc_ae (base = base , number_system_digit = number_system_digit )
187
- else :
188
- ean13 = self .ean13 (leading_zero = True )
189
- return ean13 [1 :]
190
-
191
- def upc_e (self , base = None , number_system_digit = None , safe_mode = True ):
192
- """Generate an 8-digit UPC-E barcode.
193
-
194
- UPC-E barcodes can be expressed in 6, 7, or 8-digit formats, but this method uses the
195
- 8 digit format, since it is trivial to convert to the other two formats. The first digit
196
- (starting from the left) is controlled by ``number_system_digit``, and it can only be a
197
- ``0`` or a ``1``. The last digit is the check digit that is inherited from the UPC-E barcode's
198
- UPC-A equivalent. The middle six digits are collectively referred to as the ``base`` (for a
199
- lack of a better term).
200
-
201
- On that note, this method uses ``base`` and ``number_system_digit`` to first generate a
202
- UPC-A barcode for the check digit, and what happens next depends on the value of ``safe_mode``.
203
- The argument ``safe_mode`` exists, because there are some UPC-E values that share the same
204
- UPC-A equivalent. For example, any UPC-E barcode of the form ``abc0000d``, ``abc0003d``, and
205
- ``abc0004d`` share the same UPC-A value ``abc00000000d``, but that UPC-A value will only convert
206
- to ``abc0000d`` because of (a) how UPC-E is just a zero-suppressed version of UPC-A and (b) the
207
- rules around the conversion.
208
-
209
- If ``safe_mode`` is ``True`` (default), this method performs another set of conversions to
210
- guarantee that the UPC-E barcodes generated can be converted to UPC-A, and that UPC-A
211
- barcode can be converted back to the original UPC-E barcode. Using the example above, even
212
- if the bases ``120003`` or ``120004`` are used, the resulting UPC-E barcode will always
213
- use the base ``120000``.
214
-
215
- If ``safe_mode`` is ``False``, then the ``number_system_digit``, ``base``, and the computed
216
- check digit will just be concatenated together to produce the UPC-E barcode, and attempting
217
- to convert the barcode to UPC-A and back again to UPC-E will exhibit the behavior described
218
- above.
105
+ return self .localized_ean (8 )
106
+
107
+ def localized_ean13 (self ):
108
+ """Generate a localized EAN-13 barcode.
109
+
110
+ This method uses :meth:`localized_ean() <faker.providers.barcode.Provider.ean>` under the
111
+ hood with the ``length`` argument explicitly set to ``13``.
219
112
220
113
:sample:
221
- :sample: base='123456'
222
- :sample: base='123456', number_system_digit=0
223
- :sample: base='123456', number_system_digit=1
224
- :sample: base='120000', number_system_digit=0
225
- :sample: base='120003', number_system_digit=0
226
- :sample: base='120004', number_system_digit=0
227
- :sample: base='120000', number_system_digit=0, safe_mode=False
228
- :sample: base='120003', number_system_digit=0, safe_mode=False
229
- :sample: base='120004', number_system_digit=0, safe_mode=False
230
114
"""
231
- if safe_mode is not False :
232
- upc_ae = self ._upc_ae (base = base , number_system_digit = number_system_digit )
233
- return self ._convert_upc_a2e (upc_ae )
234
- else :
235
- upc_ae = self ._upc_ae (base = base , number_system_digit = number_system_digit )
236
- return upc_ae [0 ] + '' .join (str (x ) for x in base ) + upc_ae [- 1 ]
115
+ return self .localized_ean (13 )
0 commit comments