@@ -125,11 +125,39 @@ def _command(self, path=None):
125125 def command (self , path = None ):
126126 return list (self ._command (path ))
127127
128+ @staticmethod
129+ def handle_error (exit_code , stderr ):
130+ if exit_code == 0 :
131+ return
132+
133+ # Sometimes wkhtmltopdf will exit with non-zero
134+ # even if it finishes generation.
135+ # If will display 'Done' in the second last line
136+ if stderr .splitlines ()[- 2 ].strip () == 'Done' :
137+ return
138+
139+ if 'cannot connect to X server' in stderr :
140+ raise IOError ('%s\n '
141+ 'You will need to run wkhtmltopdf within a "virtual" X server.\n '
142+ 'Go to the link below for more information\n '
143+ 'https://github.com/JazzCore/python-pdfkit/wiki/Using-wkhtmltopdf-without-X-server' % stderr )
144+
145+ if 'Error' in stderr :
146+ raise IOError ('wkhtmltopdf reported an error:\n ' + stderr )
147+
148+ error_msg = stderr or 'Unknown Error'
149+ raise IOError ("wkhtmltopdf exited with non-zero code {0}. error:\n {1}" .format (exit_code , error_msg ))
150+
128151 def to_pdf (self , path = None ):
129152 args = self .command (path )
130-
131- result = subprocess .Popen (args , stdin = subprocess .PIPE , stdout = subprocess .PIPE ,
132- stderr = subprocess .PIPE , env = self .environ )
153+
154+ result = subprocess .Popen (
155+ args ,
156+ stdin = subprocess .PIPE ,
157+ stdout = subprocess .PIPE ,
158+ stderr = subprocess .PIPE ,
159+ env = self .environ
160+ )
133161
134162 # If the source is a string then we will pipe it into wkhtmltopdf.
135163 # If we want to add custom CSS to file then we read input file to
@@ -141,46 +169,34 @@ def to_pdf(self, path=None):
141169 input = self .source .source .read ().encode ('utf-8' )
142170 else :
143171 input = None
172+
144173 stdout , stderr = result .communicate (input = input )
145174 stderr = stderr or stdout
146-
175+ stderr = stderr . decode ( 'utf-8' , errors = 'replace' )
147176 exit_code = result .returncode
148- if exit_code != 0 :
149- stderr = stderr .decode ('utf-8' , errors = 'replace' )
150-
151- if 'cannot connect to X server' in stderr :
152- raise IOError ('%s\n '
153- 'You will need to run wkhtmltopdf within a "virtual" X server.\n '
154- 'Go to the link below for more information\n '
155- 'https://github.com/JazzCore/python-pdfkit/wiki/Using-wkhtmltopdf-without-X-server' % stderr )
156-
157- if 'Error' in stderr :
158- raise IOError ('wkhtmltopdf reported an error:\n ' + stderr )
159-
160- error_msg = stderr or 'Unknown Error'
161- raise IOError ("wkhtmltopdf exited with non-zero code {0}. error:\n {1}" .format (exit_code , error_msg ))
177+ self .handle_error (exit_code , stderr )
162178
163179 # Since wkhtmltopdf sends its output to stderr we will capture it
164180 # and properly send to stdout
165181 if '--quiet' not in args :
166- sys .stdout .write (stderr . decode ( 'utf-8' , errors = 'replace' ) )
182+ sys .stdout .write (stderr )
167183
168184 if not path :
169185 return stdout
170- else :
171- try :
172- with codecs .open (path , encoding = 'utf-8' ) as f :
173- # read 4 bytes to get PDF signature '%PDF'
174- text = f .read (4 )
175- if text == '' :
176- raise IOError ('Command failed: %s\n '
177- 'Check whhtmltopdf output without \' quiet\' '
178- 'option' % ' ' .join (args ))
179- return True
180- except (IOError , OSError ) as e :
181- raise IOError ('Command failed: %s\n '
182- 'Check whhtmltopdf output without \' quiet\' option\n '
183- '%s ' % (' ' .join (args ), e ))
186+
187+ try :
188+ with codecs .open (path , encoding = 'utf-8' ) as f :
189+ # read 4 bytes to get PDF signature '%PDF'
190+ text = f .read (4 )
191+ if text == '' :
192+ raise IOError ('Command failed: %s\n '
193+ 'Check whhtmltopdf output without \' quiet\' '
194+ 'option' % ' ' .join (args ))
195+ return True
196+ except (IOError , OSError ) as e :
197+ raise IOError ('Command failed: %s\n '
198+ 'Check whhtmltopdf output without \' quiet\' option\n '
199+ '%s ' % (' ' .join (args ), e ))
184200
185201 def _normalize_options (self , options ):
186202 """ Generator of 2-tuples (option-key, option-value).
@@ -206,7 +222,6 @@ def _normalize_options(self, options):
206222 else :
207223 yield (normalized_key , unicode (value ) if value else value )
208224
209-
210225 def _normalize_arg (self , arg ):
211226 return arg .lower ()
212227
0 commit comments