[Zope-Checkins] CVS: Zope/utilities - ExtensionBuilder.py:1.7 FS.py:1.9 bbb.py:1.15 check_catalog.py:1.5 fixbbbts.py:1.3 load_site.py:1.10 requestprofiler.py:1.17 testrunner.py:1.27
Martijn Pieters
mj@zope.com
Wed, 14 Aug 2002 17:23:27 -0400
Update of /cvs-repository/Zope/utilities
In directory cvs.zope.org:/tmp/cvs-serv10249
Modified Files:
ExtensionBuilder.py FS.py bbb.py check_catalog.py fixbbbts.py
load_site.py requestprofiler.py testrunner.py
Log Message:
Clean up indentation and trailing whitespace.
=== Zope/utilities/ExtensionBuilder.py 1.6 => 1.7 ===
--- Zope/utilities/ExtensionBuilder.py:1.6 Wed Jun 12 19:48:22 2002
+++ Zope/utilities/ExtensionBuilder.py Wed Aug 14 17:22:57 2002
@@ -202,7 +202,7 @@
if 'Setup.in' in os.listdir(current_dir):
self.doCommand('copy Setup.in Setup')
-
+
# Parse the Setup file. We have to do a lot of work because
# NMAKE is very stupid about relative paths :( The only way
# to get things to work relatively reliably is to turn all
@@ -246,10 +246,10 @@
args = tmplist
source = string.replace(source, '/', '\\')
-
+
srcdir = filepath(source)
srcdir = os.path.normpath(os.path.join(os.getcwd(), srcdir))
-
+
source = os.path.split(source)[-1]
os.chdir(srcdir)
=== Zope/utilities/FS.py 1.8 => 1.9 ===
--- Zope/utilities/FS.py:1.8 Wed Nov 28 10:51:24 2001
+++ Zope/utilities/FS.py Wed Aug 14 17:22:57 2002
@@ -1,14 +1,14 @@
##############################################################################
#
# Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved.
-#
+#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE
-#
+#
##############################################################################
import struct, tempfile, string, time, pickle, os, sys
@@ -343,4 +343,3 @@
p=newp.getvalue()
return p
-
=== Zope/utilities/bbb.py 1.14 => 1.15 ===
--- Zope/utilities/bbb.py:1.14 Wed Nov 28 10:51:24 2001
+++ Zope/utilities/bbb.py Wed Aug 14 17:22:57 2002
@@ -1,14 +1,14 @@
##############################################################################
#
# Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved.
-#
+#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE
-#
+#
##############################################################################
"""Read and (re-)format BoboPOS 2 database files
"""
@@ -57,12 +57,12 @@
"This script only works with ZODB 2 (BoboPOS) "
"data or export files."
,1)
-
+
gmtime=time.gmtime
if fromEnd: pos=file_size
else: pos=newpos=(not export) and len(packed_version)
-
+
tlast=0
err=0
tnamelast=None
@@ -79,7 +79,7 @@
l=unpack(">i", read(4))[0]
pos=p+4
- error("nulls skipped from %s to %s" % (pos,b))
+ error("nulls skipped from %s to %s" % (pos,b))
p=pos-l
if p < 0:
error('Corrupted data before %s' % pos)
@@ -100,7 +100,7 @@
if not h: break
if len(h) != 24: break
oid,prev,start,tlen,plen=unpack(">iidii",h)
-
+
if prev < 0 or (prev and (prev >= pos)):
error('Bad previous record pointer (%s) at %s' % (prev, pos))
if show > 0: error(read(show))
@@ -149,7 +149,7 @@
seek(pos+24)
if plen > 0:
p=read(plen)
- if p[-1:] != '.':
+ if p[-1:] != '.':
error('Corrupted pickle at %s %s %s' % (pos,plen,len(p)))
if show > 0:
seek(pos+24)
@@ -177,10 +177,10 @@
def none(*ignored): pass
-def positions(pos, *ignored):
+def positions(pos, *ignored):
if pos is not None: sys.stdout.write("%s\n" % pos)
-def oids(pos, oid, *ignored):
+def oids(pos, oid, *ignored):
if pos is not None: sys.stdout.write("%s\n" % oid)
def tab_delimited(*args):
@@ -188,10 +188,10 @@
def undo_log(pos, oid, start, tname, user, t, p, first, newtrans):
if not newtrans: return
-
+
sys.stdout.write("%s:\t%s\t%s\t%s\n" % (pos, start, user, t))
-
+
reports={
'none': (none,
('Read a database file checking for errors',
@@ -225,7 +225,7 @@
items=reports.items()
items.sort()
-
+
usage="""Usage: python %s [options] filename
where filename is the name of the database file.
@@ -268,7 +268,7 @@
The input file is a ZODB 2 export file.
-
+
""" % (sys.argv[0],
string.join(map(
lambda i:
@@ -285,7 +285,7 @@
try: file=open(filename,'rb')
except: error('Coud not open %s' % filename,1,1)
-
+
rpt=none
fromEnd=0
both=0
@@ -330,4 +330,3 @@
forgive=1, export=export)
if __name__=='__main__': main(sys.argv[1:])
-
=== Zope/utilities/check_catalog.py 1.4 => 1.5 ===
--- Zope/utilities/check_catalog.py:1.4 Wed Nov 28 10:51:24 2001
+++ Zope/utilities/check_catalog.py Wed Aug 14 17:22:57 2002
@@ -3,21 +3,21 @@
##############################################################################
#
# Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved.
-#
+#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE
-#
+#
##############################################################################
""" script to consistency of a ZCatalog """
__version__='$Revision$'[11:-2]
-import Zope
+import Zope
import os,sys,re,getopt
from types import IntType
from BTrees.IIBTree import IISet,difference,intersection
@@ -58,7 +58,7 @@
print "\tOK: Mapping data equals Maaping paths"
else:
print "\tERR: Mapping data does not equal Maaping paths"
-
+
# check BTrees of indexes
@@ -71,18 +71,18 @@
if idx.meta_type in ['FieldIndex','KeywordIndex']:
# check forward entries
- RIDS = IISet()
+ RIDS = IISet()
for key, rids in idx._index.items():
- if isinstance(rids,IntType):
+ if isinstance(rids,IntType):
RIDS.insert( rids )
else:
map(RIDS.insert , rids.keys())
diff = difference(RIDS, IISet(_cat.data.keys()))
if len(diff)!=0:
- print '\tERR: Problem with forward entries'
+ print '\tERR: Problem with forward entries'
print '\tERR: too much forward entries:', diff
- else:
+ else:
print '\tOK: Forward entries (%d entries)' % (len(RIDS))
@@ -95,11 +95,11 @@
diff = difference(RIDS, IISet(_cat.data.keys()))
if len(diff)!=0:
- print '\tERR: Problem with forward entries'
+ print '\tERR: Problem with forward entries'
print '\tERR: too much forward entries:', diff
- else:
+ else:
print '\tOK: Forward entries (%d entries)' % (len(RIDS))
-
+
if idx.meta_type in ['FieldIndex','KeywordIndex','PathIndex']:
@@ -107,7 +107,7 @@
RIDS = IISet(idx._unindex.keys())
diff = difference(RIDS, IISet(_cat.data.keys()))
if len(diff)!=0:
- print '\tERR: Problem with backward entries'
+ print '\tERR: Problem with backward entries'
print '\tERR: too much backward entries:', diff
else:
print '\tOK: Backward entries (%d entries)' % (len(RIDS))
@@ -121,11 +121,11 @@
def usage():
print "Usage: %s [--FieldIndex|KeywordIndex|PathIndex] /path/to/ZCatalog" % \
os.path.basename(sys.argv[0])
- print
+ print
print "This scripts checks the consistency of the internal"
print "BTrees of a ZCatalog and its indexes."
sys.exit(1)
-
+
def main():
@@ -137,7 +137,7 @@
for o,v in opts:
if o in ['-h','--help']: usage()
- if o in ['--FieldIndex','--KeywordIndex','--PathIndex']:
+ if o in ['--FieldIndex','--KeywordIndex','--PathIndex']:
indexes.append(o[2:])
checkCatalog(args,indexes)
=== Zope/utilities/fixbbbts.py 1.2 => 1.3 ===
--- Zope/utilities/fixbbbts.py:1.2 Tue Jan 16 04:09:21 2001
+++ Zope/utilities/fixbbbts.py Wed Aug 14 17:22:57 2002
@@ -55,7 +55,7 @@
write=output.write
pack=struct.pack
unpack=struct.unpack
-
+
h=read(len(packed_version))
if h != packed_version:
raise InvalidFormat, 'This is not a BoboPOS file'
@@ -73,7 +73,7 @@
next=next+0.001
start=None
if plen > tlen or tlen < 28: raise Corrupted, pos
-
+
write(pack(">iidii", oid, prev, t, tlen, plen))
l=tlen-28
s=8196
@@ -89,4 +89,3 @@
pos=pos+tlen
if __name__=='__main__': main()
-
=== Zope/utilities/load_site.py 1.9 => 1.10 ===
--- Zope/utilities/load_site.py:1.9 Wed Nov 28 10:51:24 2001
+++ Zope/utilities/load_site.py Wed Aug 14 17:22:57 2002
@@ -1,14 +1,14 @@
##############################################################################
#
# Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved.
-#
+#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE
-#
+#
##############################################################################
"""Load a Zope site from a collection of files or directories
"""
@@ -89,7 +89,7 @@
here=os.path.join(here,'lib','python')
if os.path.exists(os.path.join(here,'ZPublisher')):
sys.path.insert(0,here)
-
+
url=args[0]
files=args[1:]
@@ -139,100 +139,100 @@
from sgmllib import SGMLParser
def join_attrs(attrs):
- attr_list = []
- for attrname, value in attrs:
- attr_list.append('%s="%s"' % (attrname, string.strip(value)))
-
- if attr_list:
- s = " " + string.join(attr_list, " ")
- else:
- s = ""
+ attr_list = []
+ for attrname, value in attrs:
+ attr_list.append('%s="%s"' % (attrname, string.strip(value)))
+
+ if attr_list:
+ s = " " + string.join(attr_list, " ")
+ else:
+ s = ""
- return s
+ return s
class HeadParser(SGMLParser):
- def __init__(self):
- SGMLParser.__init__(self)
+ def __init__(self):
+ SGMLParser.__init__(self)
- self.seen_starthead = 0
- self.seen_endhead = 0
- self.seen_startbody = 0
+ self.seen_starthead = 0
+ self.seen_endhead = 0
+ self.seen_startbody = 0
- self.head = ""
- self.title = ""
- self.accumulator = ""
+ self.head = ""
+ self.title = ""
+ self.accumulator = ""
- def handle_data(self, data):
- if data:
- self.accumulator = self.accumulator + data
+ def handle_data(self, data):
+ if data:
+ self.accumulator = self.accumulator + data
- def handle_charref(self, ref):
- self.handle_data("&#%s;" % ref)
+ def handle_charref(self, ref):
+ self.handle_data("&#%s;" % ref)
- def handle_entityref(self, ref):
- self.handle_data("&%s;" % ref)
+ def handle_entityref(self, ref):
+ self.handle_data("&%s;" % ref)
- def handle_comment(self, data):
- if data:
- self.accumulator = self.accumulator + "<!--%s-->" % data
+ def handle_comment(self, data):
+ if data:
+ self.accumulator = self.accumulator + "<!--%s-->" % data
- def start_head(self, attrs):
- if not self.seen_starthead:
- self.seen_starthead = 1
- self.head = ""
- self.title = ""
- self.accumulator = ""
+ def start_head(self, attrs):
+ if not self.seen_starthead:
+ self.seen_starthead = 1
+ self.head = ""
+ self.title = ""
+ self.accumulator = ""
- def end_head(self):
- if not self.seen_endhead:
- self.seen_endhead = 1
- self.head = self.head + self.accumulator
- self.accumulator = ""
+ def end_head(self):
+ if not self.seen_endhead:
+ self.seen_endhead = 1
+ self.head = self.head + self.accumulator
+ self.accumulator = ""
- def start_title(self, attrs):
- self.head = self.head + self.accumulator
- self.accumulator = ""
+ def start_title(self, attrs):
+ self.head = self.head + self.accumulator
+ self.accumulator = ""
- def end_title(self):
- self.title = self.accumulator
- self.accumulator = ""
+ def end_title(self):
+ self.title = self.accumulator
+ self.accumulator = ""
- def start_body(self, attrs):
- if not self.seen_startbody:
- self.seen_startbody = 1
- self.accumulator = ""
+ def start_body(self, attrs):
+ if not self.seen_startbody:
+ self.seen_startbody = 1
+ self.accumulator = ""
- def end_body(self): pass # Do not put </BODY> and </HTML>
- def end_html(self): pass # into output stream
+ def end_body(self): pass # Do not put </BODY> and </HTML>
+ def end_html(self): pass # into output stream
- # Pass other tags unmodified
- def unknown_starttag(self, tag, attrs):
- self.accumulator = self.accumulator + "<%s%s>" % (string.upper(tag), join_attrs(attrs))
+ # Pass other tags unmodified
+ def unknown_starttag(self, tag, attrs):
+ self.accumulator = self.accumulator + "<%s%s>" % (string.upper(tag), join_attrs(attrs))
- def unknown_endtag(self, tag):
- self.accumulator = self.accumulator + "</%s>" % string.upper(tag)
+ def unknown_endtag(self, tag):
+ self.accumulator = self.accumulator + "</%s>" % string.upper(tag)
def parse_html(infile):
- parser = HeadParser()
+ parser = HeadParser()
- while 1:
- line = infile.readline()
- if not line: break
- parser.feed(line)
+ while 1:
+ line = infile.readline()
+ if not line: break
+ parser.feed(line)
- parser.close()
- infile.close()
+ parser.close()
+ infile.close()
- return (string.strip(parser.title), string.strip(parser.head),
- string.strip(parser.accumulator))
+ return (string.strip(parser.title), string.strip(parser.head),
+ string.strip(parser.accumulator))
def upload_html(object, f):
@@ -271,14 +271,14 @@
# Now add META and other tags as property
if head:
- object=object.__class__(object.url+'/'+name,
- username=object.username,
- password=object.password)
- call(object.manage_addProperty,
- id="loadsite-head", type="text", value=head)
+ object=object.__class__(object.url+'/'+name,
+ username=object.username,
+ password=object.password)
+ call(object.manage_addProperty,
+ id="loadsite-head", type="text", value=head)
# ----- /phd -----
-
+
upload_htm=upload_html
def upload_dtml(object, f):
@@ -290,7 +290,7 @@
call(object.manage_addDocument, id=name, file=f)
else:
call(object.manage_addDTMLMethod, id=name, file=f)
-
+
def upload_gif(object, f):
dir, name = os.path.split(f)
@@ -300,5 +300,3 @@
upload_png=upload_gif
if __name__=='__main__': main()
-
-
=== Zope/utilities/requestprofiler.py 1.16 => 1.17 ===
--- Zope/utilities/requestprofiler.py:1.16 Fri Mar 1 11:35:00 2002
+++ Zope/utilities/requestprofiler.py Wed Aug 14 17:22:57 2002
@@ -3,14 +3,14 @@
##############################################################################
#
# Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved.
-#
+#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE
-#
+#
##############################################################################
""" Request log profiler script """
@@ -36,7 +36,7 @@
self.t_end = None
self.elapsed = "I"
self.active = 0
-
+
def put(self, code, t, desc):
if code not in ('A', 'B', 'I', 'E'):
raise "unknown request code %s" % code
@@ -52,7 +52,7 @@
elif code == 'E':
self.t_end = t
self.elapsed = int(self.t_end - self.start)
-
+
def isfinished(self):
return not self.elapsed == "I"
@@ -69,13 +69,13 @@
return time.strftime('%H:%M:%S', t)
else:
return "NA"
-
+
def win(self):
if self.t_recdinput is not None and self.start is not None:
return self.t_recdinput - self.start
else:
return "NA"
-
+
def wout(self):
if self.t_recdoutput is not None and self.t_recdinput is not None:
return self.t_recdoutput - self.t_recdinput
@@ -130,7 +130,7 @@
self.total(), self.endstage(), self.prettyosize(),
self.prettyhttpcode(), self.active, self.url
)
- return self.fmt % body
+ return self.fmt % body
fmt = "%19s %4s %4s %4s %3s %1s %7s %4s %4s %s"
@@ -142,7 +142,7 @@
class StartupRequest(Request):
def endstage(self):
return "U"
-
+
def total(self):
return 0
@@ -152,12 +152,12 @@
self.times = []
self.hangs = 0
self.allelapsed = None
-
+
def put(self, request):
elapsed = request.elapsed
if elapsed == "I": self.hangs = self.hangs + 1
self.times.append(elapsed)
-
+
def all(self):
if self.allelapsed == None:
self.allelapsed = []
@@ -176,18 +176,18 @@
def getheader(self):
return self.fmt % ('Hangs', 'Hits', 'Total', 'Max', 'Min', 'Median',
'Mean', 'URL')
-
+
fmt = "%5s %5s %5s %5s %5s %6s %5s %s"
def hits(self):
return len(self.times)
-
+
def max(self):
return max(self.all())
-
+
def min(self):
return min(self.all())
-
+
def mean(self):
l = len(self.times)
if l == 0:
@@ -196,7 +196,7 @@
t = self.total()
if t == "I": return "I"
return t/l
-
+
def median(self):
all = self.all()
l = len(all)
@@ -215,7 +215,7 @@
v2 = all[i2]
if type(v1) is type('') or type(v2) is type(''): return "I"
else: return (v1 + v2) / 2
-
+
def total(self):
t = 0
all = self.all()
@@ -335,7 +335,7 @@
requests = cumulative.values()
requests.sort(sortf)
write(requests, top)
-
+
elif mode=='timed':
computed_start = requests[0].start
computed_end = requests[-1].t_end
@@ -351,7 +351,7 @@
elif mode == 'urlfocus':
requests.sort(sortf)
urlfocuswrite(requests, urlfocusurl, urlfocustime)
-
+
else:
requests.sort(sortf)
write(requests, top)
@@ -472,7 +472,7 @@
num = d.get(slice, 0)
if num>max_requests: max_requests = num
hits = hits + num
-
+
if avg_requests is None:
avg_requests = num
else:
@@ -480,24 +480,24 @@
s = tick2str(slice)
s = s + " %6d %4.2lf" % (num,num*1.0/resolution)
- print s
+ print s
- print '='*78
+ print '='*78
print " Peak: %6d %4.2lf" % \
(max_requests,max_requests*1.0/resolution)
print " Avg: %6d %4.2lf" % \
(avg_requests,avg_requests*1.0/resolution)
print "Total: %6d n/a " % (hits)
-
+
def tick2str(t):
return time.strftime('%Y-%m-%dT%H:%M:%S', time.localtime(t))
-
+
def codesort(v1, v2):
v1 = v1.endstage()
v2 = v2.endstage()
if v1 == v2:
return 0
-
+
if v1 == "B":
return -1 # v1 is smaller than v2
if v1 == "I":
@@ -527,7 +527,7 @@
else:
if self.ascending: return 1
else: return -1
-
+
def detailedusage():
details = usage(0)
pname = sys.argv[0]
@@ -601,7 +601,7 @@
If the 'daysago' argument is specified, limit results to hits received n days ago.
The 'resolution' argument is used only for timed reports and specifies the
-number of seconds between consecutive lines in the report
+number of seconds between consecutive lines in the report
(default is 60 seconds).
The 'urlfocustime' argument is used only for urlfocus reports and specifies the
@@ -648,7 +648,7 @@
Show 'urlfocus' report which displays statistics about requests
surrounding the invocation of '/manage_main'. Focus on the time periods
60 seconds before and after each invocation of the '/manage_main' URL.
-
+
%(pname)s debug.log --detailed --start='2001/05/10 06:00:00'
--end='2001/05/11 23:00:00'
@@ -686,12 +686,12 @@
[--sort=spec]
[--top=n]
[--verbose]
- [--today | [--start=date] [--end=date] | --daysago=n ]
+ [--today | [--start=date] [--end=date] | --daysago=n ]
[--writestats=filename | --readstats=filename]
[--urlfocus=url]
[--urlfocustime=seconds]
[--help]
-
+
Provides a profile of one or more Zope "-M" request log files.
""" % sys.argv[0]
)
@@ -719,7 +719,7 @@
statsfname = None
readstats = 0
writestats = 0
-
+
files = []
i = 1
for arg in sys.argv[1:]:
=== Zope/utilities/testrunner.py 1.26 => 1.27 ===
--- Zope/utilities/testrunner.py:1.26 Wed Aug 14 15:59:18 2002
+++ Zope/utilities/testrunner.py Wed Aug 14 17:22:57 2002
@@ -76,10 +76,10 @@
def smellsLikeATest(self, filepath, find=string.find):
path, name = os.path.split(filepath)
fname, ext = os.path.splitext(name)
-
+
if name[:4]=='test' and name[-3:]=='.py' and \
name != 'testrunner.py':
-
+
file=open(filepath, 'r')
lines=file.readlines()
file.close()
@@ -144,10 +144,10 @@
self.report('No test suite found in file:\n%s\n' % pathname)
if self.verbosity > 1:
traceback.print_exc()
- suite = None
+ suite = None
finally:
os.chdir(working_dir)
-
+
return suite
else: # no test there!
@@ -183,7 +183,7 @@
try: suite=self.getSuiteFromFile(name)
except:
traceback.print_exc()
- suite=None
+ suite=None
if suite is not None:
self.runSuite(suite)
else:
@@ -219,7 +219,7 @@
working directory. This is the default if no options are
specified.
- -m
+ -m
Run all tests in a single, giant suite (consolidates error
reporting). [default]
@@ -259,7 +259,7 @@
2 - Verbose (default - produces a line of output for each test)
-q
-
+
Run tests without producing verbose output. The tests are
normally run in verbose mode, which produces a line of
output for each test that includes the name of the test and
@@ -358,7 +358,7 @@
msg += "total errors=%d" % errs
msg += ")"
err_exit(msg, 1)
-
+
sys.exit(0)