source: coopr.pyomo/trunk/coopr/pyomo/scripting/util.py @ 3681

Last change on this file since 3681 was 3681, checked in by wehart, 9 years ago

Migrating the profiling logic into scripting/util.py.
This allows it to be applied uniformly in the conversion scripts:
pyomo2nl and pyomo2lp.

File size: 25.9 KB
Line 
1#  _________________________________________________________________________
2#
3#  Coopr: A COmmon Optimization Python Repository
4#  Copyright (c) 2008 Sandia Corporation.
5#  This software is distributed under the BSD License.
6#  Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
7#  the U.S. Government retains certain rights in this software.
8#  For more information, see the Coopr README.txt file.
9#  _________________________________________________________________________
10
11import gc
12try:
13    import pyutilib.logging as logging
14except ImportError:
15    import logging
16import os
17import sys
18import textwrap
19import traceback
20import types
21
22try:
23    import cProfile as profile
24except ImportError:
25    import profile
26try:
27    import pstats
28    pstats_available=True
29except ImportError:
30    pstats_available=False
31
32try:
33    import IPython
34    IPython_available=True
35    from IPython.Shell import IPShellEmbed
36    ipshell = IPShellEmbed([''],
37                banner = '\n# Dropping into Python interpreter',
38                exit_msg = '\n# Leaving Interpreter, back to Pyomo\n')
39except ImportError:
40    IPython_available=False
41
42from pyutilib.misc import Options
43try:
44   from pympler.muppy import muppy
45   from pympler.muppy import summary
46   from pympler.muppy import tracker
47   from pympler.asizeof import *
48   pympler_available = True
49except ImportError:
50   pympler_available = False
51memory_tracker = None
52memory_data = Options()
53
54from coopr.pyomo import *
55from coopr.opt import ProblemFormat
56from coopr.opt.base import SolverFactory
57from coopr.opt.parallel import SolverManagerFactory
58import pyutilib.misc
59from pyutilib.component.core import ExtensionPoint, Plugin, implements
60from pyutilib.services import TempfileManager
61
62from coopr.pyomo.expr.linear_repn import linearize_model_expressions
63
64filter_excepthook=False
65modelapi = {    'pyomo_create_model':IPyomoScriptCreateModel,
66                'pyomo_create_modeldata':IPyomoScriptCreateModelData,
67                'pyomo_print_model':IPyomoScriptPrintModel,
68                'pyomo_modify_instance':IPyomoScriptModifyInstance,
69                'pyomo_print_instance':IPyomoScriptPrintInstance,
70                'pyomo_save_instance':IPyomoScriptSaveInstance,
71                'pyomo_print_results':IPyomoScriptPrintResults,
72                'pyomo_save_results':IPyomoScriptSaveResults,
73                'pyomo_postprocess':IPyomoScriptPostprocess}
74
75
76logger = logging.getLogger('coopr.pyomo')
77
78#
79# Print information about modeling components supported by Pyomo
80#
81def print_components(options):
82    print ""
83    print "----------------------------------------------------------------"
84    print "Pyomo Model Components:"
85    print "----------------------------------------------------------------"
86    components = pyomo.model_components()
87    index = pyutilib.misc.sort_index(components)
88    for i in index:
89        print ""
90        print " "+components[i][0]
91        for line in textwrap.wrap(components[i][1], 59):
92            print "    "+line
93    print ""
94    print "----------------------------------------------------------------"
95    print "Pyomo Virtual Sets:"
96    print "----------------------------------------------------------------"
97    pyomo_sets = pyomo.predefined_sets()
98    index = pyutilib.misc.sort_index(pyomo_sets)
99    for i in index:
100        print ""
101        print " "+pyomo_sets[i][0]
102        print "    "+pyomo_sets[i][1]
103
104#
105# Print information about the solvers that are available
106#
107def print_solver_help(options):
108    print "The following solvers are are currently supported:"
109    solver_list = SolverFactory.services()
110    solver_list = sorted( filter(lambda x: '_' != x[0], solver_list) )
111    n = max(map(len, solver_list))
112    wrapper = textwrap.TextWrapper(subsequent_indent=' '*(n+9))
113    for s in solver_list:
114        format = '    %-'+str(n)+'s  %s'
115        print wrapper.fill(format % (s , SolverFactory.doc(s)))
116    print 'The default solver is glpk.'
117    print ""
118    wrapper = textwrap.TextWrapper(replace_whitespace=False)
119    print wrapper.fill('Subsolver options can be specified by with the solver name followed by colon and then the subsolver.  For example, the following specifies that the asl solver will be used:')
120    print '   --asl:PICO'
121    print wrapper.fill('This indicates that the asl solver will launch the PICO executable to perform optimization. Currently, no other solver supports this syntax.')
122
123
124#
125# Setup Pyomo execution environment
126#
127def setup_environment(options):
128    #
129    # Setup memory tracker
130    #
131    if (pympler_available is True) and (options.profile_memory >= 1):
132        global memory_tracker
133        memory_tracker = tracker.SummaryTracker()
134    #
135    # Disable garbage collection
136    #
137    if options.disable_gc:
138        gc.disable()
139    #
140    # Setup management for temporary files
141    #
142    if not options.tempdir is None:
143        if not os.path.exists(options.tempdir):
144            msg =  'Directory for temporary files does not exist: %s'
145            raise ValueError, msg % options.tempdir
146        TempfileManager.tempdir = options.tempdir
147
148    #
149    # Configure exception management
150    #
151    def pyomo_excepthook(etype,value,tb):
152        """
153        This exception hook gets called when debugging is on. Otherwise,
154        run_command in this module is called.
155        """
156        global filter_excepthook
157        if len(options.model_file) > 0:
158            name = "model " + options.model_file
159        else:
160            name = "model"
161
162
163        if filter_excepthook:
164            action = "loading"
165        else:
166            action = "running"
167
168        msg = "Unexpected exception while %s %s\n" % (action, name)
169
170        #
171        # This handles the case where the error is propagated by a KeyError.
172        # KeyError likes to pass raw strings that don't handle newlines
173        # (they translate "\n" to "\\n"), as well as tacking on single
174        # quotes at either end of the error message. This undoes all that.
175        #
176        if etype == KeyError:
177            valueStr = str(value).replace("\\n","\n")[1:-1]
178        else:
179            valueStr = str(value)
180
181        logger.error(msg+valueStr)
182       
183        tb_list = traceback.extract_tb(tb,None)
184        i = 0
185        if not logger.isEnabledFor(logging.DEBUG) and filter_excepthook:
186            while i < len(tb_list):
187                #print "Y",model,tb_list[i][0]
188                if options.model_file in tb_list[i][0]:
189                    break
190                i += 1
191            if i == len(tb_list):
192                i = 0
193        print "\nTraceback (most recent call last):"
194        for item in tb_list[i:]:
195            print "  File \""+item[0]+"\", line "+str(item[1])+", in "+item[2]
196            if item[3] is not None:
197                print "    "+item[3]
198        sys.exit(1)
199    sys.excepthook = pyomo_excepthook
200    return True
201
202
203#
204# Execute preprocessing files
205#
206def apply_preprocessing(options, parser):
207    global filter_excepthook
208    #
209    #
210    # Setup solver and model
211    #
212    #
213    if len(options.model_file) == 0:
214        parser.print_help()
215        return False
216    #
217    if not options.preprocess is None:
218        for file in options.preprocess:
219            preprocess = pyutilib.misc.import_file(file)
220    #
221    for ep in ExtensionPoint(IPyomoScriptPreprocess):
222        ep.apply( options=options )
223    #
224    filter_excepthook=True
225    options.usermodel = pyutilib.misc.import_file(options.model_file)
226    filter_excepthook=False
227
228    usermodel_dir = dir(options.usermodel)
229    options._usermodel_plugins = []
230    for key in modelapi:
231        if key in usermodel_dir:
232            class TMP(Plugin):
233                implements(modelapi[key])
234                def __init__(self):
235                    Plugin.__init__(self)
236                    self.fn = getattr(options.usermodel, key)
237                def apply(self,**kwds):
238                    return self.fn(**kwds)
239            options._usermodel_plugins.append( TMP() )
240
241    if 'pyomo_preprocess' in usermodel_dir:
242        if options.model_name in usermodel_dir:
243            msg = "Preprocessing function 'pyomo_preprocess' defined in file" \
244                  " '%s', but model is already constructed!"
245            raise SystemExit, msg % options.model_file
246        getattr(options.usermodel, 'pyomo_preprocess')( options=options )
247
248    return True
249
250#
251# Create instance of Pyomo model
252#
253def create_model(options):
254    if (pympler_available is True) and (options.profile_memory >= 1):
255        global memory_data
256        objects_before_instance_creation = muppy.get_objects()
257        memory_data.summary_before_instance_creation = summary.summarize(objects_before_instance_creation)
258        print "Initial set of objects:"
259        summary.print_(memory_data.summary_before_instance_creation,limit=50)
260    #
261    # Verify that files exist
262    #
263    for file in [options.model_file]+options.data_files:
264        if not os.path.exists(file):
265            raise IOError, "File "+file+" does not exist!"
266    #
267    # Create Model
268    #
269    ep = ExtensionPoint(IPyomoScriptCreateModel)
270    model_name = 'model'
271    if options.model_name is not None: model_name = options.model_name
272
273    if model_name in dir(options.usermodel):
274        if len(ep) > 0:
275            msg = "Model construction function 'create_model' defined in "    \
276                  "file '%s', but model is already constructed!"
277            raise SystemExit, msg % options.model_file
278        model = getattr(options.usermodel, model_name)
279
280        if model is None:
281            msg = "'%s' object is 'None' in module %s"
282            raise SystemExit, msg % (model_name, options.model_file)
283            sys.exit(0)
284
285    else:
286       if len(ep) == 0:
287           msg = "Neither '%s' nor 'pyomo_create_model' are available in "    \
288                 'module %s'
289           raise SystemExit, msg % ( model_name, options.model_file )
290       elif len(ep) > 1:
291           msg = 'Multiple model construction plugins have been registered!'
292           raise SystemExit, msg
293       else:
294            model_options = options.model_options
295            if model_options is None:
296                model_options = []
297            model = ep.service().apply( options=pyutilib.misc.Container(*model_options) )
298    #
299    for ep in ExtensionPoint(IPyomoScriptPrintModel):
300        ep.apply( options=options, model=model )
301
302    #
303    # Disable canonical repn for ASL solvers, and if the user has specified as such (in which case, we assume they know what they are doing!).
304    #
305    # Likely we need to change the framework so that canonical repn
306    # is not assumed to be required by all solvers?
307    #
308    if not options.solver is None and options.solver.startswith('asl'):
309        model.skip_canonical_repn = True
310    elif options.skip_canonical_repn is True:
311        model.skip_canonical_repn = True
312
313    #
314    # Create Problem Instance
315    #
316    ep = ExtensionPoint(IPyomoScriptCreateModelData)
317    if len(ep) > 1:
318        msg = 'Multiple model data construction plugins have been registered!'
319        raise SystemExit, msg
320
321    if len(ep) == 1:
322        modeldata = ep.service().apply( options=options, model=model )
323    else:
324        modeldata = ModelData()
325
326    if len(options.data_files) > 1:
327        #
328        # Load a list of *.dat files
329        #
330        for file in options.data_files:
331            suffix = (file).split(".")[-1]
332            if suffix != "dat":
333                msg = 'When specifiying multiple data files, they must all '  \
334                      'be *.dat files.  File specified: %s'
335                raise SystemExit, msg % str( file )
336
337            modeldata.add(file)
338
339        modeldata.read(model)
340
341        if not options.profile_memory is None:
342           instance = model.create(modeldata, profile_memory=options.profile_memory)
343        else:
344           instance = model.create(modeldata)
345
346    elif len(options.data_files) == 1:
347       #
348       # Load a *.dat file or process a *.py data file
349       #
350       suffix = (options.data_files[0]).split(".")[-1]
351       if suffix == "dat":
352          if not options.profile_memory is None:
353             instance = model.create(options.data_files[0], profile_memory=options.profile_memory)
354          else:
355             instance = model.create(options.data_files[0])
356       elif suffix == "py":
357          userdata = pyutilib.misc.import_file(options.data_files[0])
358          if "modeldata" in dir(userdata):
359                if len(ep) == 1:
360                    msg = "Cannot apply 'pyomo_create_modeldata' and use the" \
361                          " 'modeldata' object that is provided in the model"
362                    raise SystemExit, msg
363
364                if userdata.modeldata is None:
365                    msg = "'modeldata' object is 'None' in module %s"
366                    raise SystemExit, msg % str( options.data_files[0] )
367
368                modeldata=userdata.modeldata
369
370          else:
371                if len(ep) == 0:
372                    msg = "Neither 'modeldata' nor 'pyomo_create_model_data"  \
373                          'is defined in module %s'
374                    raise SystemExit, msg % str( options.data_files[0] )
375
376          modeldata.read(model)
377          if not options.profile_memory is None:
378             instance = model.create(modeldata, profile_memory=options.profile_memory)
379          else:
380             instance = model.create(modeldata)
381       else:
382          raise ValueError, "Unknown data file type: "+options.data_files[0]
383    else:
384       if not options.profile_memory is None:
385          instance = model.create(modeldata, profile_memory=options.profile_memory)
386       else:
387          instance = model.create(modeldata)
388
389    if options.linearize_expressions is True:
390       linearize_model_expressions(instance)
391
392    #
393    ep = ExtensionPoint(IPyomoScriptModifyInstance)
394    for ep in ExtensionPoint(IPyomoScriptModifyInstance):
395        ep.apply( options=options, model=model, instance=instance )
396    #
397    if logger.isEnabledFor(logging.DEBUG):
398       print "MODEL INSTANCE"
399       instance.pprint()
400       print ""
401
402    for ep in ExtensionPoint(IPyomoScriptPrintInstance):
403        ep.apply( options=options, instance=instance )
404
405    fname=None
406    symbol_map=None
407    if options.save_model is None and options.debug:
408        options.save_model = 'unknown.lp'
409    if not options.save_model is None:
410        if options.save_model == True:
411            if options.format in (ProblemFormat.cpxlp, ProblemFormat.lpxlp):
412                fname = (options.data_files[0])[:-3]+'lp'
413            else:
414                fname = (options.data_files[0])[:-3]+str(options.format)
415            format=options.format
416        else:
417            fname = options.save_model
418            format=None
419        (fname, symbol_map) = instance.write(filename=fname, format=format)
420        if not os.path.exists(fname):
421            print "ERROR: file "+fname+" has not been created!"
422        else:
423            print "Model written to file '"+str(fname)+"'"
424    for ep in ExtensionPoint(IPyomoScriptSaveInstance):
425        ep.apply( options=options, instance=instance )
426
427    if (pympler_available is True) and (options.profile_memory >= 1):
428        objects_after_instance_creation = muppy.get_objects()
429        memory_data.summary_after_instance_creation = summary.summarize(objects_after_instance_creation)
430        print "\nObjects created during Pyomo instance creation:"
431        memory_tracker.print_diff(
432                    summary1=memory_data.summary_before_instance_creation, 
433                    summary2=memory_data.summary_after_instance_creation)
434
435    return pyutilib.misc.Container( 
436                    model=model, instance=instance, 
437                    symbol_map=symbol_map, filename=fname )
438
439#
440# Perform optimization with concrete instance
441#
442def apply_optimizer(options, instance):
443    #
444    # Create Solver and Perform Optimization
445    #
446    solver = options.solver
447    if solver is None:
448       raise ValueError, "Problem constructing solver:  no solver specified"
449
450    subsolver=None
451    if not solver is None and ':' in solver:
452        solver, subsolver = solver.split(':')
453    opt = SolverFactory( solver )
454    if opt is None:
455        solver_list = SolverFactory.services()
456        solver_list = sorted( filter(lambda x: '_' != x[0], solver_list) )
457        raise ValueError, "Problem constructing solver `"+str(solver)+"' (choose from: %s)" % ", ".join(solver_list)
458
459    # let the model know of our chosen solver's capabilities
460    instance.has_capability = opt.has_capability
461
462    opt.keepFiles=options.keepfiles or options.log
463    if options.timelimit == 0:
464       options.timelimit=None
465
466    if options.solver_mipgap is not None:
467       opt.mipgap = options.solver_mipgap
468
469    if not options.solver_suffixes is None:
470        opt.suffixes = options.solver_suffixes
471
472    if not subsolver is None:
473        subsolver=' solver='+subsolver
474    else:
475        subsolver=''
476
477    if not options.solver_options is None:
478        opt.set_options(" ".join(options.solver_options)+subsolver)
479
480    if options.smanager_type is None:
481        solver_mngr = SolverManagerFactory( 'serial' )
482    else:
483        solver_mngr = SolverManagerFactory( options.smanager_type )
484
485    if solver_mngr is None:
486        msg = "Problem constructing solver manager '%s'"
487        raise ValueError, msg % str( options.smanager_type )
488
489    results = solver_mngr.solve( instance, opt=opt, tee=options.tee, timelimit=options.timelimit )
490
491    if results == None:
492       raise ValueError, "opt.solve returned None"
493
494    if (pympler_available is True) and (options.profile_memory >= 1):
495        global memory_data
496        objects_after_optimization = muppy.get_objects()
497        memory_data.summary_after_optimization = summary.summarize(objects_after_optimization)
498        print "\nObjects created during optimization:"
499        memory_tracker.print_diff(
500                    summary1=memory_data.summary_after_instance_creation,
501                    summary2=memory_data.summary_after_optimization)
502
503    return results, opt
504
505#
506# Process results
507#
508def process_results(options, instance, results, opt):
509    #
510    if options.log:
511       print ""
512       print "=========================================================="
513       print "Solver Logfile:",opt.log_file
514       print "=========================================================="
515       print ""
516       INPUT = open(opt.log_file, "r")
517       for line in INPUT:
518         print line,
519       INPUT.close()
520    #
521    if options.save_results:
522        results.write(filename=options.save_results)
523    #
524    ep = ExtensionPoint(IPyomoScriptPrintResults)
525    if len(ep) == 0:
526        try:
527            instance.load(results)
528        except Exception, e:
529            print "Problem loading solver results"
530            raise
531        print ""
532        results.write(num=1)
533    #
534    if options.summary:
535       print ""
536       print "=========================================================="
537       print "Solution Summary"
538       print "=========================================================="
539       if len(results.solution(0).variable) > 0:
540          print ""
541          display(instance)
542       else:
543          print "No solutions reported by solver."
544    #
545    for ep in ExtensionPoint(IPyomoScriptPrintResults):
546        ep.apply( options=options, instance=instance, results=results )
547    #
548    for ep in ExtensionPoint(IPyomoScriptSaveResults):
549        ep.apply( options=options, instance=instance, results=results )
550    #
551    if (pympler_available is True) and (options.profile_memory >= 1):
552        global memory_data
553        objects_after_results_processing = muppy.get_objects()
554        memory_data.summary_after_results_processing = summary.summarize(objects_after_results_processing)
555        #diff_summary = summary.get_diff( memory_data.summary_after_optimization, memory_data.summary_after_results_processing)
556        print "\nObjects created during results processing:"
557        memory_tracker.print_diff(
558                    summary1=memory_data.summary_after_optimization,
559                    summary2=memory_data.summary_after_results_processing)
560
561    return True
562
563
564def apply_postprocessing(options, instance, results):
565    for file in options.postprocess:
566        postprocess = pyutilib.misc.import_file(file)
567        if "postprocess" in dir(postprocess):
568            postprocess.postprocess(instance,results)
569    for ep in ExtensionPoint(IPyomoScriptPostprocess):
570        ep.apply( options=options, instance=instance, results=results )
571    #
572    # Deactivate and delete plugins
573    #
574    for plugin in options._usermodel_plugins:
575        plugin.deactivate()
576    options._usermodel_plugins = []
577    #
578    if (pympler_available is True) and (options.profile_memory >= 1):
579        final_objects = muppy.get_objects()
580        summary_final = summary.summarize(final_objects)
581        final_summary = summary.summarize(final_objects)
582        print "\nFinal set of objects:"
583        summary.print_(final_summary, limit=50)
584    #
585    return True
586
587
588def finalize(options, model=None, instance=None, results=None):
589    model=model
590    instance=instance
591    results=results
592    #
593    if options.interactive:
594        if IPython_available:
595            ipshell()
596        else:
597            import code
598            shell = code.InteractiveConsole(locals())
599            print '\n# Dropping into Python interpreter'
600            shell.interact()
601            print '\n# Leaving Interpreter, back to Pyomo\n'
602
603
604#
605# Execute a function that processes command-line arguments and then
606# calls a command-line driver.  This
607# is segregated from the driver to enable profiling.
608#
609def run_command(command, parser, args=None, name='unknown'):
610    #
611    #
612    # Parse command-line options
613    #
614    #
615    try:
616       _options = parser.parse_args(args=args)
617       # Replace the parser options object with a pyutilib.misc.Options object
618       options = pyutilib.misc.Options()
619       for key in dir(_options):
620            if key[0] != '_':
621                val = getattr(_options, key)
622                if not isinstance(val, types.MethodType):
623                    options[key] = val
624    except SystemExit:
625       # the parser throws a system exit if "-h" is specified - catch
626       # it to exit gracefully.
627       return
628    #
629    # Configure the logger
630    #
631    logging.getLogger('coopr.pyomo').setLevel(logging.ERROR)
632    logging.getLogger('coopr').setLevel(logging.ERROR)
633    logging.getLogger('pyutilib').setLevel(logging.ERROR)
634    #
635    if options.warning:
636        logging.getLogger('coopr.pyomo').setLevel(logging.WARNING)
637        logging.getLogger('coopr').setLevel(logging.WARNING)
638        logging.getLogger('pyutilib').setLevel(logging.WARNING)
639    if options.info:
640        logging.getLogger('coopr.pyomo').setLevel(logging.INFO)
641        logging.getLogger('coopr').setLevel(logging.INFO)
642        logging.getLogger('pyutilib').setLevel(logging.INFO)
643    if options.verbose > 0:
644        if options.verbose >= 1:
645            logger.setLevel(logging.DEBUG)
646        if options.verbose >= 2:
647            logging.getLogger('coopr').setLevel(logging.DEBUG)
648        if options.verbose >= 3:
649            logging.getLogger('pyutilib').setLevel(logging.DEBUG)
650    if options.debug:
651        logging.getLogger('coopr.pyomo').setLevel(logging.DEBUG)
652        logging.getLogger('coopr').setLevel(logging.DEBUG)
653        logging.getLogger('pyutilib').setLevel(logging.DEBUG)
654    #
655    # Setup I/O redirect to a logfile
656    #
657    logfile = getattr(options, 'logfile', None)
658    if not logfile is None:
659        pyutilib.misc.setup_redirect(logfile)
660    #
661    # Call the main Pyomo runner with profiling
662    #
663    if options.profile > 0:
664        if not pstats_available:
665            if not logfile is None:
666                pyutilib.misc.reset_redirect()
667            msg = "Cannot use the 'profile' option.  The Python 'pstats' "    \
668                  'package cannot be imported!'
669            raise ValueError, msg
670        tfile = TempfileManager.create_tempfile(suffix=".profile")
671        tmp = profile.runctx(
672          command.__name__ + '(options=options,parser=parser)', command.__globals__, locals(), tfile
673        )
674        p = pstats.Stats(tfile).strip_dirs()
675        p.sort_stats('time', 'cum')
676        p = p.print_stats(options.profile)
677        p.print_callers(options.profile)
678        p.print_callees(options.profile)
679        p = p.sort_stats('cum','calls')
680        p.print_stats(options.profile)
681        p.print_callers(options.profile)
682        p.print_callees(options.profile)
683        p = p.sort_stats('calls')
684        p.print_stats(options.profile)
685        p.print_callers(options.profile)
686        p.print_callees(options.profile)
687        TempfileManager.clear_tempfiles()
688        ans = [tmp, None]
689    else:
690        #
691        # Call the main Pyomo runner without profiling
692        #
693        try:
694            ans = command(options=options, parser=parser)
695        except SystemExit, err:
696            if __debug__:
697                if options.debug:
698                    sys.exit(0)
699            print 'Exiting %s: %s' % (name, str(err))
700            ans = None
701        except Exception, err:
702            # If debugging is enabled, pass the exception up the chain
703            # (to pyomo_excepthook)
704            if __debug__:
705                if options.debug:
706                    if not logfile is None:
707                        pyutilib.misc.reset_redirect()
708                    raise
709
710            if len(options.model_file) > 0:
711                name = "model " + options.model_file
712            else:
713                name = "model"
714               
715            global filter_excepthook
716            if filter_excepthook:
717                action = "loading"
718            else:
719                action = "running"
720
721            msg = "Unexpected exception while %s %s\n" % (action, name)
722            #
723            # This handles the case where the error is propagated by a KeyError.
724            # KeyError likes to pass raw strings that don't handle newlines
725            # (they translate "\n" to "\\n"), as well as tacking on single
726            # quotes at either end of the error message. This undoes all that.
727            #
728            errStr = str(err)
729            if type(err) == KeyError:
730                errStr = str(err).replace(r"\n","\n")[1:-1]
731
732            logging.getLogger('coopr.pyomo').error(msg+errStr)
733            ans = None
734
735    if not logfile is None:
736        pyutilib.misc.reset_redirect()
737
738    if options.disable_gc:
739        gc.enable()
740    return ans
Note: See TracBrowser for help on using the repository browser.