1717from pyomo .core .base .param import ParamData
1818from pyomo .core .base .block import BlockData
1919from pyomo .core .base .objective import Objective , ObjectiveData
20- from pyomo .common .config import ConfigValue
20+ from pyomo .common .config import ConfigValue , ConfigDict
2121from pyomo .common .enums import IntEnum , SolverAPIVersion
2222from pyomo .common .errors import ApplicationError
2323from pyomo .common .deprecation import deprecation_warning
@@ -408,9 +408,27 @@ class LegacySolverWrapper:
408408 interface. Necessary for backwards compatibility.
409409 """
410410
411+ class _all_true (object ):
412+ # A mockup of Bunch that returns True for all attribute lookups
413+ # or containment tests.
414+ def __getattr__ (self , name ):
415+ return True
416+
417+ def __contains__ (self , name ):
418+ return True
419+
420+ class _UpdatableConfigDict (ConfigDict ):
421+ # The legacy solver interface used Option objects. we will make
422+ # the ConfigDict *look* like an Option by supporting update()
423+ __slots__ = ()
424+
425+ def update (self , value ):
426+ return self .set_value (value )
427+
411428 def __init__ (self , ** kwargs ):
412- if 'solver_io' in kwargs :
413- raise NotImplementedError ('Still working on this' )
429+ solver_io = kwargs .pop ('solver_io' , None )
430+ if solver_io :
431+ raise NotImplementedError (f'Still working on this ({ solver_io = } )' )
414432 # There is no reason for a user to be trying to mix both old
415433 # and new options. That is silly. So we will yell at them.
416434 _options = kwargs .pop ('options' , None )
@@ -425,8 +443,14 @@ def __init__(self, **kwargs):
425443 kwargs ['solver_options' ] = _options
426444 super ().__init__ (** kwargs )
427445 # Make the legacy 'options' attribute an alias of the new
428- # config.solver_options
446+ # config.solver_options; change its class so it behaves more
447+ # like an old Bunch/Options object.
429448 self .options = self .config .solver_options
449+ self .options .__class__ = LegacySolverWrapper ._UpdatableConfigDict
450+ # We will assume the solver interface supports all capabilities
451+ # (unless a derived class actually set something
452+ if not hasattr (self , '_capabilities' ):
453+ self ._capabilities = LegacySolverWrapper ._all_true ()
430454
431455 #
432456 # Support "with" statements
@@ -567,7 +591,7 @@ def _solution_handler(
567591 self , load_solutions , model , results , legacy_results , legacy_soln
568592 ):
569593 """Method to handle the preferred action for the solution"""
570- symbol_map = SymbolMap ()
594+ symbol_map = legacy_soln . symbol_map = SymbolMap ()
571595 symbol_map .default_labeler = NumericLabeler ('x' )
572596 if not hasattr (model , 'solutions' ):
573597 # This logic gets around Issue #2130 in which
@@ -576,6 +600,7 @@ def _solution_handler(
576600
577601 setattr (model , 'solutions' , ModelSolutions (model ))
578602 model .solutions .add_symbol_map (symbol_map )
603+ legacy_results ._smap = symbol_map
579604 legacy_results ._smap_id = id (symbol_map )
580605 delete_legacy_soln = True
581606 if load_solutions :
@@ -597,10 +622,12 @@ def _solution_handler(
597622 legacy_soln .variable ['Rc' ] = val
598623
599624 legacy_results .solution .insert (legacy_soln )
600- # Timing info was not originally on the legacy results, but we want
601- # to make it accessible to folks who are utilizing the backwards
602- # compatible version.
603- legacy_results .timing_info = results .timing_info
625+ # Timing info was not originally on the legacy results, but we
626+ # want to make it accessible to folks who are utilizing the
627+ # backwards compatible version. Note that embedding the
628+ # ConfigDict broke pickling the legacy_results, so we will only
629+ # return raw nested dicts
630+ legacy_results .timing_info = results .timing_info .value ()
604631 if delete_legacy_soln :
605632 legacy_results .solution .delete (0 )
606633 return legacy_results
@@ -711,3 +738,9 @@ def set_options(self, options):
711738 opts = {k : v for k , v in options .value ().items () if v is not None }
712739 if opts :
713740 self ._map_config (** opts )
741+
742+ def warm_start_capable (self ):
743+ return False
744+
745+ def default_variable_value (self ):
746+ return None
0 commit comments