Skip to content

Commit 042a682

Browse files
committed
If no barcode is detected, return a False-y BarCode object instead of None
This should be better for principle of lease surprise, and will address the underlying issue of #18. Also adds tests to verify that this works.
1 parent e941beb commit 042a682

File tree

5 files changed

+19
-9
lines changed

5 files changed

+19
-9
lines changed

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,8 @@ The attributes of the decoded `BarCode` object are `raw`, `parsed`, `path`, `for
3232
[here](https://zxing.github.io/zxing/apidocs/com/google/zxing/BarcodeFormat.html).
3333

3434
The `decode()` method accepts an image path (or list of paths) and takes optional parameters `try_harder` (boolean), `possible_formats` (list of formats to consider), and `pure_barcode` (boolean).
35-
If no barcode is found, it returns `None`, and if it encounters any other recognizable error from the Java ZXing library, it raises `BarCodeReaderException`.
35+
If no barcode is found, it returns a `False`-y `BarCode` object with all fields except `uri` set to `None`.
36+
If it encounters any other recognizable error from the Java ZXing library, it raises `BarCodeReaderException`.
3637

3738
## Command-line interface
3839

test/barcodes/empty.png

71 Bytes
Loading

test/test_all.py

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,12 @@
2020
('QR_CODE-screen_scraping_torture_test.png', 'QR_CODE', '\n\\n¡Atención ☹! UTF-8 characters,\n\r embedded newlines,\r &&am&p;& trailing whitespace\t \r '),
2121
]
2222

23+
test_non_barcodes = [
24+
('empty.png', None, None),
25+
]
26+
27+
test_valid_images = test_barcodes + test_non_barcodes
28+
2329
test_reader = None
2430

2531

@@ -43,7 +49,7 @@ def _check_decoding(filename, expected_format, expected_raw, extra={}):
4349
logging.debug('Trying to parse {}, expecting {!r}.'.format(path, expected_raw))
4450
dec = test_reader.decode(path, pure_barcode=True, **extra)
4551
if expected_raw is None:
46-
if dec is not None:
52+
if dec.raw is not None:
4753
raise AssertionError('Expected failure, but got result in {} format'.format(expected_format, dec.format))
4854
else:
4955
if dec.raw != expected_raw:
@@ -54,7 +60,7 @@ def _check_decoding(filename, expected_format, expected_raw, extra={}):
5460

5561
def test_decoding():
5662
global test_reader
57-
yield from ((_check_decoding, filename, expected_format, expected_raw) for filename, expected_format, expected_raw in test_barcodes)
63+
yield from ((_check_decoding, filename, expected_format, expected_raw) for filename, expected_format, expected_raw in test_valid_images)
5864

5965

6066
def test_possible_formats():
@@ -64,9 +70,9 @@ def test_possible_formats():
6470

6571
@with_setup(setup_reader)
6672
def test_decoding_multiple():
67-
reader = zxing.BarCodeReader()
68-
filenames = [os.path.join(test_barcode_dir, filename) for filename, expected_format, expected_raw in test_barcodes]
69-
for dec, (filename, expected_format, expected_raw) in zip(reader.decode(filenames, pure_barcode=True), test_barcodes):
73+
global test_reader
74+
filenames = [os.path.join(test_barcode_dir, filename) for filename, expected_format, expected_raw in test_valid_images]
75+
for dec, (filename, expected_format, expected_raw) in zip(test_reader.decode(filenames, pure_barcode=True), test_valid_images):
7076
if dec.raw != expected_raw:
7177
raise AssertionError('{}: Expected {!r} but got {!r}'.format(filename, expected_raw, dec.parsed))
7278
if dec.format != expected_format:

zxing/__init__.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ def parse(cls, zxing_output):
135135
for l in zxing_output.splitlines(True):
136136
if block == CLROutputBlock.UNKNOWN:
137137
if l.endswith(b': No barcode found\n'):
138-
return None
138+
return cls(l.rsplit(b':', 1)[0].decode(), None, None, None, None, None)
139139
m = re.match(rb"(\S+) \(format:\s*([^,]+),\s*type:\s*([^)]+)\)", l)
140140
if m:
141141
uri, format, type = m.group(1).decode(), m.group(2).decode(), m.group(3).decode()
@@ -160,7 +160,10 @@ def parse(cls, zxing_output):
160160
parsed = parsed[:-1].decode()
161161
return cls(uri, format, type, raw, parsed, points)
162162

163-
def __init__(self, uri, format, type, raw, parsed, points):
163+
def __bool__(self):
164+
return bool(self.raw)
165+
166+
def __init__(self, uri, format=None, type=None, raw=None, parsed=None, points=None):
164167
self.raw = raw
165168
self.parsed = parsed
166169
self.uri = uri

zxing/__main__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ def main():
3131
wr.writerow((fn, bc.format, bc.type, bc.raw, bc.parsed) if bc else (fn, 'ERROR', None, None, None))
3232
else:
3333
print("%s\n%s" % (fn, '=' * len(fn)))
34-
if bc is None:
34+
if not bc:
3535
print(" ERROR: Failed to decode barcode.")
3636
else:
3737
print(" Decoded %s barcode in %s format." % (bc.type, bc.format))

0 commit comments

Comments
 (0)