@@ -94,8 +94,13 @@ def __del__(self):
9494 # Note that this is only to suppress warnings, as __del__ is not
9595 # guaranteed to be called (especially for any objects that still
9696 # exist when the Python process terminates)
97- if self .neos is not None :
98- self .transport .close ()
97+ if getattr (self , 'neos' , None ) is not None :
98+ try :
99+ if hasattr (self , 'transport' ) and hasattr (self .transport , 'close' ):
100+ self .transport .close ()
101+ except Exception :
102+ # never raise from a destructor
103+ pass
99104
100105 def setup_connection (self ):
101106 import http .client
@@ -127,14 +132,16 @@ def setup_connection(self):
127132 xmlrpclib .ProtocolError ,
128133 http .client .BadStatusLine ,
129134 NotImplementedError ,
130- ):
131- e = sys .exc_info ()[1 ]
135+ Exception ,
136+ ) as e :
137+ self .connect_error = e
132138 self .neos = None
133139 logger .info ("Fail: %s" % (e ,))
134140 logger .warning ("NEOS is temporarily unavailable:\n \t (%s)" % (e ,))
135141
136142 def tempfile (self ):
137- return os .path .join (tempfile .gettempdir (), 'at%s.jobs' % os .getenv ('ampl_id' ))
143+ ampl_id = os .getenv ('ampl_id' , 'unknown' )
144+ return os .path .join (tempfile .gettempdir (), f'at{ ampl_id } .jobs' )
138145
139146 def kill (self , jobNumber , password ):
140147 response = self .neos .killJob (jobNumber , password )
@@ -148,7 +155,7 @@ def solvers(self):
148155 while attempt < 3 :
149156 try :
150157 return self .neos .listSolversInCategory ("kestrel" )
151- except socket .timeout :
158+ except ( socket .timeout , Exception ) :
152159 attempt += 1
153160 return []
154161
@@ -157,13 +164,14 @@ def retrieve(self, stub, jobNumber, password):
157164 results = self .neos .getFinalResults (jobNumber , password )
158165 if isinstance (results , xmlrpclib .Binary ):
159166 results = results .data
167+ if isinstance (results , str ):
168+ results = results .encode ()
160169 # decode results to kestrel.sol; well try to anyway, any errors
161170 # will result in error strings in .sol file instead of solution.
162171 if stub [- 4 :] == '.sol' :
163172 stub = stub [:- 4 ]
164- solfile = open (stub + ".sol" , "wb" )
165- solfile .write (results )
166- solfile .close ()
173+ with open (stub + ".sol" , "wb" ) as solfile :
174+ solfile .write (results )
167175
168176 def submit (self , xml ):
169177 # LOGNAME and USER should map to the effective user (i.e., the
@@ -214,7 +222,13 @@ def getJobAndPassword(self):
214222
215223 def getAvailableSolvers (self ):
216224 """Return a list of all NEOS solvers that this interface supports"""
217- allKestrelSolvers = self .neos .listSolversInCategory ("kestrel" )
225+ if self .neos is None :
226+ return []
227+ try :
228+ allKestrelSolvers = self .neos .listSolversInCategory ("kestrel" )
229+ except Exception as e :
230+ logger .warning ("Failed to retrieve solver list from NEOS: %s" , e )
231+ return []
218232 _ampl = ':AMPL'
219233 return sorted (s [: - len (_ampl )] for s in allKestrelSolvers if s .endswith (_ampl ))
220234
@@ -226,34 +240,36 @@ def getSolverName(self):
226240
227241 - we don't want to be case sensitive, but NEOS is.
228242 - we need to read in options variable
229-
230243 """
231244 # Get a list of available kestrel solvers from NEOS
232245 kestrelAmplSolvers = self .getAvailableSolvers ()
233- self .options = None
246+
247+ NEOS_solver_name = None
248+ m = None
249+
234250 # Read kestrel_options to get solver name
235251 if "kestrel_options" in os .environ :
236252 self .options = os .getenv ("kestrel_options" )
237253 elif "KESTREL_OPTIONS" in os .environ :
238254 self .options = os .getenv ("KESTREL_OPTIONS" )
239- #
255+ else :
256+ self .options = None
257+
240258 if self .options is not None :
241259 m = re .search (r'solver\s*=*\s*(\S+)' , self .options , re .IGNORECASE )
242- NEOS_solver_name = None
243260 if m :
244261 solver_name = m .groups ()[0 ]
245262 for s in kestrelAmplSolvers :
246263 if s .upper () == solver_name .upper ():
247264 NEOS_solver_name = s
248265 break
249- #
250266 if not NEOS_solver_name :
251267 raise RuntimeError (
252268 "%s is not available on NEOS. Choose from:\n \t %s"
253269 % (solver_name , "\n \t " .join (kestrelAmplSolvers ))
254270 )
255- #
256- if self . options is None or m is None :
271+
272+ if NEOS_solver_name is None :
257273 raise RuntimeError (
258274 "%s is not available on NEOS. Choose from:\n \t %s"
259275 % (solver_name , "\n \t " .join (kestrelAmplSolvers ))
@@ -274,19 +290,16 @@ def formXML(self, stub):
274290 ampl_files = {}
275291 for key in ['adj' , 'col' , 'env' , 'fix' , 'spc' , 'row' , 'slc' , 'unv' ]:
276292 if os .access (stub + "." + key , os .R_OK ):
277- f = open (stub + "." + key , "r" )
278- val = ""
279- buf = f .read ()
280- while buf :
281- val += buf
282- buf = f .read ()
283- f .close ()
284- ampl_files [key ] = val
293+ with open (stub + "." + key , "r" ) as f :
294+ ampl_files [key ] = f .read ()
295+
285296 # Get priority
286297 priority = ""
287- m = re .search (r'priority[\s=]+(\S+)' , self .options )
288- if m :
289- priority = "<priority>%s</priority>\n " % (m .groups ()[0 ])
298+ if self .options :
299+ m = re .search (r'priority[\s=]+(\S+)' , self .options )
300+ if m :
301+ priority = "<priority>%s</priority>\n " % (m .groups ()[0 ])
302+
290303 # Add any AMPL-created environment variables to dictionary
291304 solver_options = "kestrel_options:solver=%s\n " % solver .lower ()
292305 solver_options_key = "%s_options" % solver
@@ -298,7 +311,7 @@ def formXML(self, stub):
298311 solver_options_value = os .getenv (solver_options_key .lower ())
299312 elif solver_options_key .upper () in os .environ :
300313 solver_options_value = os .getenv (solver_options_key .upper ())
301- if not solver_options_value == "" :
314+ if solver_options_value :
302315 solver_options += "%s_options:%s\n " % (solver .lower (), solver_options_value )
303316 #
304317 nl_string = (base64 .encodebytes (zipped_nl_file .getvalue ())).decode ('utf-8' )
0 commit comments