def failed_solve_test(self): # Create the model test class model_class = test_case.model() # Create the model instance model_class.generate_model(test_case.testcase.import_suffixes) model_class.warmstart_model() # solve load_solutions = True symbolic_labels = False out = StringIO() with LoggingIntercept(out, 'pyomo.solvers'): with LoggingIntercept(out, 'pyomo.opt'): opt, results = model_class.solve(solver, io, test_case.testcase.io_options, test_case.testcase.options, symbolic_labels, load_solutions) if len(results.solution) == 0: self.assertIn("No solution is available", out.getvalue()) else: # Note ASL solvers might still return a solution # file with garbage values in it for a failed solve self.assertEqual(len(results.solution), 1)
def test_update_block_derived_override_construct_nofcn2(self): class Foo(Block): def construct(self, data=None): Block.construct(self, data) m = ConcreteModel() m.t = ContinuousSet(bounds=(0, 10)) m.s = Set(initialize=[1, 2, 3]) def _block_rule(b, t, s): m = b.model() def _init(m, j): return j * 2 b.p1 = Param(m.t, default=_init) b.v1 = Var(m.t, initialize=5) m.foo = Foo(m.t, m.s, rule=_block_rule) generate_finite_elements(m.t, 5) OUTPUT = StringIO() with LoggingIntercept(OUTPUT, 'pyomo.core'): update_contset_indexed_component(m.foo) self.assertIn('transformation to the Block-derived component', OUTPUT.getvalue()) self.assertEqual(len(m.foo), 18) self.assertEqual(len(m.foo[0, 1].p1), 6) self.assertEqual(len(m.foo[2, 2].v1), 6) self.assertEqual(m.foo[0, 3].p1[6], 12)
def test_err_for_bogus_kwds(self): m = self.makeModel() OUTPUT = StringIO() with LoggingIntercept(OUTPUT, 'pyomo.core'): TransformationFactory('core.add_slack_variables').apply_to( m, notakwd="I want a feasible model") self.assertIn( "Unrecognized keyword arguments in add slack variable " "transformation:\nnotakwd", OUTPUT.getvalue())
def test_err2_kwds(self): #"""Expect an error when variable length keyword arguments are supported""" buf = StringIO() with LoggingIntercept(buf, 'pyomo.util'): @pyomo_api def err2(**kwargs): pass self.assertIn( "Attempting to declare Pyomo task with function 'err2' " "that contains variable keyword arguments", buf.getvalue())
def test_err10b_duplicate_namespace_function(self): #"""Expect an error when the same functor is defined twice""" buf = StringIO() with LoggingIntercept(buf, 'pyomo.util'): @pyomo_api(namespace='foo') def err10b(data): pass @pyomo_api(namespace='foo') def err10b(data): pass self.assertIn("Cannot define API foo.err10b, since this API name " "is already defined", buf.getvalue())
def test_with_custom_message(self): @deprecated('This is a custom message, too.') def foo(bar='yeah'): """Show that I am a good person. Because I document my public functions. """ logger.warn(bar) self.assertIn('DEPRECATION WARNING: This is a custom message', foo.__doc__) self.assertIn('I am a good person.', foo.__doc__) # Test the default argument DEP_OUT = StringIO() FCN_OUT = StringIO() with LoggingIntercept(DEP_OUT, 'pyomo.core'): with LoggingIntercept(FCN_OUT, 'pyomo.util'): foo() # Test that the function produces output self.assertIn('yeah', FCN_OUT.getvalue()) self.assertNotIn('DEPRECATED', FCN_OUT.getvalue()) # Test that the deprecation warning was logged self.assertIn('DEPRECATED: This is a custom message', DEP_OUT.getvalue()) # Test that the function argument gets passed in DEP_OUT = StringIO() FCN_OUT = StringIO() with LoggingIntercept(DEP_OUT, 'pyomo.core'): with LoggingIntercept(FCN_OUT, 'pyomo.util'): foo("custom") # Test that the function produces output self.assertNotIn('yeah', FCN_OUT.getvalue()) self.assertIn('custom', FCN_OUT.getvalue()) self.assertNotIn('DEPRECATED', FCN_OUT.getvalue()) # Test that the deprecation warning was logged self.assertIn('DEPRECATED: This is a custom message', DEP_OUT.getvalue())
def test_err7b_arg_missing_from_docstring(self): #"""Argument missing from docstring""" buf = StringIO() with LoggingIntercept(buf, 'pyomo.util'): @pyomo_api def err7b(data, x=1, y=2): """ Required: x: integer """ pass self.assertIn("Argument 'y' is not specified in the docstring", buf.getvalue())
def test_err7c_return_missing_from_docstring(self): #"""Argument missing from docstring""" buf = StringIO() with LoggingIntercept(buf, 'pyomo.util'): @pyomo_api(outputs=('z')) def err7c(data, x=1, y=2): """ Required: x: integer Optional: y: integer """ return PyomoAPIData(z=1) self.assertIn("Return value 'z' is not specified", buf.getvalue())
def test_no_doc_string(self): # Note: No docstring, else nose replaces the function name with # the docstring in output. #"""Test for deprecated function decorator.""" @deprecated() def foo(bar='yeah'): logger.warn(bar) self.assertIn('DEPRECATION WARNING: This function has been deprecated', foo.__doc__) # Test the default argument DEP_OUT = StringIO() FCN_OUT = StringIO() with LoggingIntercept(DEP_OUT, 'pyomo.core'): with LoggingIntercept(FCN_OUT, 'pyomo.util'): foo() # Test that the function produces output self.assertIn('yeah', FCN_OUT.getvalue()) self.assertNotIn('DEPRECATED', FCN_OUT.getvalue()) # Test that the deprecation warning was logged self.assertIn('DEPRECATED: This function has been deprecated', DEP_OUT.getvalue()) # Test that the function argument gets passed in DEP_OUT = StringIO() FCN_OUT = StringIO() with LoggingIntercept(DEP_OUT, 'pyomo.core'): with LoggingIntercept(FCN_OUT, 'pyomo.util'): foo("custom") # Test that the function produces output self.assertNotIn('yeah', FCN_OUT.getvalue()) self.assertIn('custom', FCN_OUT.getvalue()) self.assertNotIn('DEPRECATED', FCN_OUT.getvalue()) # Test that the deprecation warning was logged self.assertIn('DEPRECATED: This function has been deprecated', DEP_OUT.getvalue())
def test_err7B_extra_optional_arg(self): #"""Argument missing from docstring""" buf = StringIO() with LoggingIntercept(buf, 'pyomo.util'): @pyomo_api def err7B(data, x=1, y=2): """ Required: x: integer Optional: y: integer bad: integer """ pass self.assertIn("Unexpected name 'bad' in list of optional inputs", buf.getvalue())
def test_err7A_extra_required_arg(self): #"""Unexpected required argument""" buf = StringIO() with LoggingIntercept(buf, 'pyomo.util'): @pyomo_api def err7A(data, x=1, y=2): """ Required: x: integer bad: integer Optional: y: integer """ pass self.assertIn("Unexpected name 'bad' in list of required inputs", buf.getvalue())
def test_err6_missing_input_data(self): #"""Expect an error when no data argument is specified""" buf = StringIO() with LoggingIntercept(buf, 'pyomo.util'): @pyomo_api def err6(): pass self.assertIn("A Pyomo functor 'err6' must have a 'data argument", buf.getvalue()) # Note: the TypeError message changes in Python 3.6, so we need # a weaker regexp. with self.assertRaisesRegexp( TypeError, "err6\(\) takes .* arguments .* given" ): err6(PyomoAPIData())
def test_err7C_extra_return_arg(self): #"""Argument missing from docstring""" buf = StringIO() with LoggingIntercept(buf, 'pyomo.util'): @pyomo_api(outputs=('z')) def err7C(data, x=1, y=2): """ Required: x: integer Optional: y: integer Return: z: integer bad: integer """ return PyomoAPIData(z=1) self.assertIn("Unexpected name 'bad' in list of outputs", buf.getvalue())
def expand_components(block): """ Loop over block components and try expanding them. If expansion fails then save the component and try again later. This function has some built-in robustness for block-hierarchical models with circular references but will not work for all cases. """ # expansion_map is used to map components to the functions used to # expand them so that the update_contset_indexed_component function # logic only has to be called once even in the case where we have to # re-try expanding components due to circular references expansion_map = ComponentMap() redo_expansion = list() # Record the missing BlockData before expanding components. This is for # the case where a ContinuousSet indexed Block is used in a Constraint. # If the Constraint is expanded before the Block then the missing # BlockData will be added to the indexed Block but will not be # constructed correctly. for blk in block.component_objects(Block, descend_into=True): missing_idx = set(blk._index) - set(iterkeys(blk._data)) if missing_idx: blk._dae_missing_idx = missing_idx # Wrap this whole process in a try block in order to ensure that errors # swallowed by the LoggingIntercept context below are re-raised if the # discretization encounters an error it isn't expecting. try: # Intercept logging to suppress Error messages arising from failed # constraint rules. These error messages get logged even though the # AttributeError causing the error is caught and handled by this # function when expanding discretized models. We maintain a stream # of the intercepted logging messages which will be printed if an # unexpected exception is raised. buf = StringIO() with LoggingIntercept(buf, 'pyomo.core', logging.ERROR): # Identify components that need to be expanded and try expanding # them for c in block.component_objects(descend_into=True, sort=SortComponents.declOrder): try: update_contset_indexed_component(c, expansion_map) except AttributeError: redo_expansion.append(c) # Re-try expansion on any components that failed the first time. # This is indicative of circular component references and not # expanding components in the correct order the first time # through. N = len(redo_expansion) while N: for i in range(N): c = redo_expansion.pop() try: expansion_map[c](c) except AttributeError: redo_expansion.append(c) if len(redo_expansion) == N: raise DAE_Error("Unable to fully discretize %s. Possible " "circular references detected between " "components %s. Reformulate your model to" " remove circular references or apply a " "discretization transformation before " "linking blocks together." % (block, str(redo_expansion))) N = len(redo_expansion) except Exception as e: logger.error(buf.getvalue()) raise