[reportlab-users] Intermittent failure to find font, followed by IOError

Robin Becker robin at reportlab.com
Thu Oct 29 07:46:56 EDT 2009


Stevens, Ian wrote:

> Thanks for taking the time to think about this issue, Robin. I admit it's an odd behaviour, especially seeing as though we never make use of that font or any fonts included with Reportlab. We also don't use the reportlab.graphics.testshapes module. It feels like a symptom of a larger problem.

>

> The fonts are owned by root, but readable by everyone. If something were altering the rights for those files, then presumably the error would not have gone away when we changed MaxRequestsPerChild to 1.

>

> With respect to multi-threading, I spoke to our operations dept. I had thought we were using Apache prefork, but they have it set up for worker instead. They had it set up with prefork at one point but apparently the errors still occurred, and were more frequent. I instructed them to switch back to prefork. The font errors immediately started coming through with increased frequency. That is odd as I would expect the errors to occur more under worker than prefork.

>

> I'll check out the WSGI with flup option and see if that fixes things.

>

> Thanks,

> Ian.

........
If as you suggest the code is currently running single threaded then this cannot
be a threading issue.

Thinking about this more clearly for a second I came to the conclusion that it's
not required for your code actually to want to use this font. What's happening
is that some other font is being requested that is not known about and the brute
force search code is attempting to read afm files to try and figure out if the
name embedded therein corresponds to the requested font name. Of course we
expect that DarkGarden is not the required font and the brute force search
should open the file, read it and reject and then continue to look for other fonts.

Apparantly the bruteforce search program was able to locate the file
DarkGardenMK.afm and is attempting to read it, but when that fails the error is
propagated up the tree. What is annoying is that the traceback doesn't give
information about exactly what font is being requested.

It should be possible to instrument brute force search to indicate which font is
being requested ie change the code in pdfmetrics.py to look like

#######################
def bruteForceSearchForAFM(faceName):
"""Looks in all AFM files on path for face with given name.

Returns AFM file name or None. Ouch!"""
from reportlab.rl_config import T1SearchPath

for dirname in T1SearchPath:
if not rl_isdir(dirname): continue
possibles = rl_glob(dirname + os.sep + '*.[aA][fF][mM]')
for possible in possibles:
try:
topDict, glyphDict = parseAFMFile(possible)
except:
import sys
t,v,b=sys.exc_info()
v.args = v.args + (' while looking for faceName=%r' % faceName)
raise

if topDict['FontName'] == faceName:
return possible
#######################

that should at least enable you to figure out why the brute force is being done.

However, that doesn't answer the question why the brute force search fails to
read this file. In fact it could be argued that a simple failure to parse the
file shouldn't result in a failure at all, but we wouldn't want to ignore all
errors here any how.

To see exactly why that happens, I suspect you need to dump out quite a lot of
stuff about the running process when the error actually occurs. It so happens
that reportlab contains a utility class for this purpose. So if your experts
concur you can try putting this extra code in place at the error site


def open_for_read(name,mode='b', urlopen=urllib.urlopen):
'''attempt to open a file or URL for reading'''
if hasattr(name,'read'): return name
try:
return open_for_read_by_name(name,mode)
except:
try:
return getStringIO(urlopen(name).read())
except:


################### start extra code
if
name=="/usr/lib/python2.5/site-packages/reportlab/fonts/DarkGardenMK.afm":
dbg = DebugMemo(fn='/tmp/dbgmemo.dbg')
dbg.dump()
################### end extra code
raise IOError('Cannot open resource "%s"' % name)


hopefully this will create a file called /tmp/dbgmemo.dbg when the error occurs
(The DebugMemo class is in utils.py already so shouldn't need importing etc etc).

In order to decode the result you need a tiny script that looks like

#!/usr/bin/python
def main():
from reportlab.lib.utils import DebugMemo
dbg = DebugMemo(fn='/tmp/dbgmemo.dbg',mode='r')
dbg.load()
dbg.show()

if __name__=='__main__':
main()

perhaps that will give some clue as to why the running process cannot actually
read these files.
--
Robin Becker


More information about the reportlab-users mailing list