Skip to content

Commit 561fa4b

Browse files
committed
Correctly identify offending file in multi-decoding error messages, and use Exception.__cause__
Identify the offending file in ZXing CommandLineRunner output requires parsing some really fugly Java tracebooks, but it addresses the FIXME from e7974a9 "re-add add multi-decoding". Also, we should use Exception.__cause__ rather than rolling our own BarCodeReaderException.underlying.
1 parent 6b2fa44 commit 561fa4b

File tree

2 files changed

+36
-23
lines changed

2 files changed

+36
-23
lines changed

zxing/__init__.py

Lines changed: 35 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,24 @@
1010
import pathlib
1111
import re
1212
import subprocess as sp
13+
import urllib.parse
1314
import zipfile
1415
from enum import Enum
1516

1617
from .version import __version__ # noqa: F401
1718

1819

20+
def file_uri_to_path(s):
21+
uri = urllib.parse.urlparse(s)
22+
if (uri.scheme, uri.netloc, uri.query, uri.fragment) != ('file', '', '', ''):
23+
raise ValueError(uri)
24+
return urllib.parse.unquote_plus(uri.path)
25+
26+
1927
class BarCodeReaderException(Exception):
20-
def __init__(self, message, filename=None, underlying=None):
21-
self.message, self.filename, self.underlying = message, filename, underlying
22-
super().__init__(message, filename, underlying)
28+
def __init__(self, message, filename=None):
29+
self.message, self.filename = message, filename
30+
super().__init__(message, filename)
2331

2432

2533
class BarCodeReader(object):
@@ -65,35 +73,40 @@ def decode(self, filenames, try_harder=False, possible_formats=None, pure_barcod
6573

6674
try:
6775
p = sp.Popen(cmd, stdout=sp.PIPE, stderr=sp.STDOUT, universal_newlines=False)
68-
except FileNotFoundError as e:
69-
raise BarCodeReaderException("Java binary specified (%s) does not exist" % self.java, self.java, e)
70-
except PermissionError as e:
71-
raise BarCodeReaderException("Java binary specified (%s) is not executable" % self.java, self.java, e)
76+
except OSError as e:
77+
raise BarCodeReaderException("Could not execute specified Java binary", self.java) from e
7278
stdout, stderr = p.communicate()
7379

7480
if stdout.startswith((b'Error: Could not find or load main class com.google.zxing.client.j2se.CommandLineRunner',
7581
b'Exception in thread "main" java.lang.NoClassDefFoundError:')):
7682
raise BarCodeReaderException("Java JARs not found in classpath (%s)" % self.classpath, self.classpath)
7783
elif stdout.startswith((b'''Exception in thread "main" javax.imageio.IIOException: Can't get input stream from URL!''',
7884
b'''Exception in thread "main" java.util.concurrent.ExecutionException: javax.imageio.IIOException: Can't get input stream from URL!''')):
79-
raise BarCodeReaderException("Could not find image path: %s" % filenames, filenames)
85+
# Find the line that looks like: "Caused by: java.io.FileNotFoundException: $FILENAME ({No such file or directory,Permission denied,*)"
86+
fn, err = next((map(bytes.decode, l[42:].rsplit(b' (', 1)) for l in stdout.splitlines() if l.startswith(b"Caused by: java.io.FileNotFoundException: ")), ('', ''))
87+
if err == 'No such file or directory)':
88+
err = FileNotFoundError(fn)
89+
elif err == 'Permission denied)':
90+
err = PermissionError(fn)
91+
else:
92+
err = OSError(err[:-1])
93+
raise BarCodeReaderException("Java library could not read image", fn) from err
8094
elif stdout.startswith(b'''Exception in thread "main" java.io.IOException: Could not load '''):
81-
raise BarCodeReaderException("Java library could not read image; is it in a supported format?", filenames)
95+
# First line ends with file:// URI
96+
fn = file_uri_to_path(stdout.splitlines()[0][63:].decode())
97+
raise BarCodeReaderException("Java library could not read image (is it in a supported format?)", fn)
8298
elif stdout.startswith(b'''Exception '''):
83-
raise BarCodeReaderException("Unknown Java exception: %s" % stdout)
99+
raise BarCodeReaderException("Unknown Java exception", self.java) from RuntimeError(stdout)
84100
elif p.returncode:
85-
raise BarCodeReaderException("Unexpected Java subprocess return code %d" % p.returncode, self.java)
86-
87-
if p.returncode:
88-
codes = [None for fn in filenames]
89-
else:
90-
file_results = []
91-
for line in stdout.splitlines(True):
92-
if line.startswith((b'file:///', b'Exception')):
93-
file_results.append(line)
94-
else:
95-
file_results[-1] += line
96-
codes = [BarCode.parse(result) for result in file_results]
101+
raise BarCodeReaderException("Unexpected Java subprocess return code", self.java) from sp.CalledProcessError(p.returncode, cmd, stdout)
102+
103+
file_results = []
104+
for line in stdout.splitlines(True):
105+
if line.startswith((b'file:///', b'Exception')):
106+
file_results.append(line)
107+
else:
108+
file_results[-1] += line
109+
codes = [BarCode.parse(result) for result in file_results]
97110

98111
if one_file:
99112
return codes[0]

zxing/__main__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ def main():
2626
try:
2727
bc = bcr.decode(fn, try_harder=args.try_harder)
2828
except BarCodeReaderException as e:
29-
p.error(e.message + (('\n\t' + e.filename) if e.filename else ''))
29+
p.error(e.message + ((': ' + e.filename) if e.filename else '') + (('\n\tCaused by: ' + repr(e.__cause__) if e.__cause__ else '')))
3030
if args.csv:
3131
wr.writerow((fn, bc.format, bc.type, bc.raw, bc.parsed) if bc else (fn, 'ERROR', None, None, None))
3232
else:

0 commit comments

Comments
 (0)