Exemplo n.º 1
0
class ModelAccess(IterativeTreeChecker):

    pyomo.util.plugin.alias(
        'model.rule.model_access',
        'Check that a rule does not reference a global model instance.')

    ModelTrackerHook()

    def checkerDoc(self):
        return """\
        Within model rules, you should access the instance of the model that
        is passed in to the function, rather than the global model instance.
        For example:
            def rule(m, i):
                return m.x[i] >= 10.0 # not model.x[i]
        """

    def check(self, runner, script, info):
        if isinstance(info, ast.FunctionDef):
            attrNodes = [
                x for x in list(ast.walk(info))
                if isinstance(x, ast.Attribute)
            ]
            for attrNode in attrNodes:
                if attrNode.value.id in script.modelVars:
                    args = getattr(script, 'functionArgs', [])
                    if len(args) > 0 and not attrNode.value.id in list(
                            arg_name(arg) for arg in args[-1].args):
                        # NOTE: this probably will not catch arguments defined as keyword arguments.
                        self.problem(
                            "Expression '{0}.{1}' may access a model variable that is outside of the function scope"
                            .format(attrNode.value.id, attrNode.attr),
                            lineno=attrNode.lineno)
Exemplo n.º 2
0
class ArrayValue(IterativeTreeChecker):

    pyomo.util.plugin.alias(
        'model.array_value',
        'Check if assigning a value to an array of variables')

    ModelTrackerHook()

    varArrays = {}

    def checkerDoc(self):
        return """\
        Assigning a value to an array of variables does nothing.
        """

    def checkVarArray(self, script, node):
        """Check for the creation of a new VarArray; store name if created"""

        if isinstance(node.value, ast.Call):
            if isinstance(node.value.func, ast.Name):
                if node.value.func.id == 'Var':
                    if len(node.value.args) > 0:
                        for target in node.targets:
                            if isinstance(target, ast.Attribute):
                                if isinstance(target.value, ast.Name):
                                    if target.value.id in script.modelVars:
                                        if target.value.id not in self.varArrays:
                                            self.varArrays[
                                                target.value.id] = []
                                        self.varArrays[target.value.id].append(
                                            target.attr)

    def checkArrayValue(self, script, node):
        for target in node.targets:
            if isinstance(target, ast.Attribute):
                if isinstance(target.value, ast.Attribute):
                    if isinstance(target.value.value, ast.Name):
                        if target.value.value.id in script.modelVars:
                            if target.value.value.id in self.varArrays:
                                if target.value.attr in self.varArrays[
                                        target.value.value.id]:
                                    if target.attr == 'value':
                                        self.problem(
                                            "Assigning value to variable array {0}.{1}"
                                            .format(target.value.value.id,
                                                    target.value.attr),
                                            lineno=node.lineno)

    def check(self, runner, script, info):
        if isinstance(info, ast.Assign):
            self.checkVarArray(script, info)
            self.checkArrayValue(script, info)
Exemplo n.º 3
0
  class ModelShadowing(IterativeTreeChecker):

    pyomo.util.plugin.alias('model.rule.shadowing', 'Ignoring for now')

    ModelTrackerHook()

    def checkerDoc(self):
        return """\
        Reusing the name of your model variable in a rule may lead to problems where
        the variable shadows the global value.  In your rule definitions,
        consider changing the name of the model argument.
        """

    def check(self, runner, script, info):
        if isinstance(info, ast.FunctionDef):
            for arg in info.args.args:
                if isinstance(arg, ast.Name):
                    if arg.id in script.modelVars:
                        self.problem("Function {0} may shadow model variable {1}".format(info.name, arg.id), lineno=info.lineno)
Exemplo n.º 4
0
class ModelValue(_ModelRuleChecker):

    pyomo.common.plugin.alias('model.value', 'Check if comparisons are done using the "value()" function.')

    ModelTrackerHook()
    
    def checkerDoc(self):
        return """\
        Comparisons done on model objects should generally be wrapped in
        a call to value(). The comparison alone will not produce a True/False
        result, but instead generate an expression for later use in a model.
        """

    def check(self, runner, script, info):
        # call superclass to execute checkBody() as necessary
        _ModelRuleChecker.check(self, runner, script, info)

        # also check global If statements
        if isinstance(info, ast.If):
            self.checkCompare(info.test, script = script)

    def checkBody(self, funcdef):
        """Check the body of a function definition for model comparisons local
           to its scope (i.e. using its model argument)."""

        if not isinstance(funcdef.args.args[0], ast.Name):
            return
        modelArg = funcdef.args.args[0].id

        for bodyNode in funcdef.body:
            for node in ast.walk(bodyNode):
                if isinstance(node, ast.If):
                    self.checkCompare(node.test, modelName = modelArg)

    def checkCompare(self, compare, modelName = None, script = None):
        """Check an AST Compare node - iterate for Attribute nodes and match
           against modelName argument. Recurse for script's model defs."""

        if modelName is None and script is None:
            return
        
        if modelName is not None:
            valueCallArgs = []
            generatorExps = []
            for node in ast.walk(compare):
                if isinstance(node, ast.Attribute):
                    if isinstance(node.value, ast.Name):
                        if node.value.id == modelName:
                            wrapped = self.checkWrapped(node, valueCallArgs, generatorExps)
                            if not wrapped:
                                self.problem("Comparison on attribute {0}.{1} not wrapped in value()".format(modelName, node.attr), lineno=compare.lineno)
                elif isinstance(node, ast.Call):
                    if isinstance(node.func, ast.Name):
                        if node.func.id == 'value':
                            valueCallArgs.append(node.args)
                elif isinstance(node, ast.GeneratorExp):
                    generatorExps.append(node)

        if script is not None:
            for name in script.modelVars:
                self.checkCompare(compare, modelName = name)

    def checkWrapped(self, attrNode, valueCallArgs, generatorExps):
        """check if the given attribute node has been 'wrapped', either
           in a value() call or as part of the iterator in a generator
           expression"""
        for i in range(len(valueCallArgs)):
            for j in range(len(valueCallArgs[i])):
                # i = call idx (to return), j = arg idx
                argNode = valueCallArgs[i][j]
                for subnode in ast.walk(argNode):
                    if subnode is attrNode:
                        return True
        for genExp in generatorExps:
            for generator in genExp.generators:
                for subnode in ast.walk(generator.iter):
                    if subnode is attrNode:
                        return True
        return False