Source code for pyuseocl.evaluation

# coding=utf-8

"""
Model the result of the evaluation of a USE OCL state (a soil file) against
a USE OCL model. This module represents the output of the evaluation
while the module 'evaluator' actually perform the computation from
a state (a '.soil') and a model (a '.use')) using a ``check`` command.
Simply put this module represents the information contained in the output of
this command which might look like::

        checking invariant (NUM) `CLASS::INVARIANT': OK.

        checking invariant (NUM) `CLASS::INVARIANT': FAILED.
          -> false : Boolean
        Instances of CLASS violating the invariant:
          -> Set{@bedroom201,@bedroom202, ...} : Set(Bedroom)

The evaluation is modeled at two levels of granularity.

- At the *model* level there are 3 classes:

    - 'ModelEvaluation' is the top-level result. This is an abstract class.
    - 'ModelValidation' is a 'ModelEvaluation' representing the fact that *ALL*
      invariants have been validated.
    - 'ModelViolation' is a 'ModelEvaluation' representing the fact that at
      least one invariant has not been validated.

- At the *feature* level (e.g. 'invariant' or a 'cardinality') there are
  also 3 classes:

    - 'InvariantEvaluation' is an abstract class representing the outcome of
      the evaluation of an invariant against a state.
    - 'InvariantValidation' is a 'InvariantEvaluation' representing the fact
      that the invariant has been validated.
    - 'InvariantViolation' is a 'InvariantEvaluation' representing the fact
      that the invariant has been violated.
    - 'CardinalityViolation' represents the fact that a cardinality has been
      violated.

All these objects are created by the module 'evaluator'.
"""

from collections import OrderedDict
from abc import ABCMeta
import os.path



#------------------------------------------------------------------------------
#   Model level
#------------------------------------------------------------------------------

[docs]class ModelEvaluation(object): """ Result of the evaluation of a USE OCL state against a USE OCL model. This is an abstract class. In practice this could either be a ModelValidation if the state is valid, that is there is absolutely no errors. If there is at least one error, then this will be a ModelViolation. A ModelEvaluation contains a map of InvariantEvaluation as well as a map of CardinalityEvaluation. """ __metaclass__ = ABCMeta def __init__(self, model, state = None): self.model = model self.state = state """ str """ self.stateShortName = os.path.splitext(os.path.basename(self.state))[0] self.isValidated = None # abstract attribute. Filled by subclasses. self.invariantEvaluations = OrderedDict() """ dict[Invariant, InvariantEvaluation] """ self.cardinalityViolations = OrderedDict() """ dict[Role, list[CardinalityViolation] ] """
[docs] def getInvariantEvaluation(self, classOrAssociationClassName, invariantName): inv = self.model.findInvariant( classOrAssociationClassName, invariantName ) return self.invariantEvaluations[inv]
[docs]class ModelValidation(ModelEvaluation): """ Result of the positive evaluation of a USE OCL state against a USE OCL model. Nothing particular to be stored as there is no error. """ def __init__(self, model, state): ModelEvaluation.__init__(self, model, state) self.isValidated = True def __str__(self): return 'Model validated' def __repr__(self): return 'Valid(%s)' % self.stateShortName
[docs]class ModelViolation(ModelEvaluation): """ Result of the negative evaluation of a USE OCL state against a USE OCL model. Store invariants violations and/or cardinality violations. """ def __init__(self, model, state): ModelEvaluation.__init__(self, model, state) self.isValidated = True def __repr__(self): return 'Violation(%s,INV(%s),ROLE(%s))' % ( self.stateShortName, ','.join(map(str, self.invariantEvaluations.values())), ','.join(map(str, self.cardinalityViolations.keys())))
#------------------------------------------------------------------------------ # Invariant and Cardinality level #------------------------------------------------------------------------------
[docs]class InvariantEvaluation(object): """ Result of the evaluation of an invariant. This is an abstract class. """ __metaclass__ = ABCMeta def __init__(self, modelEvaluation, invariant): self.modelEvaluation = modelEvaluation self.invariant = invariant self.modelEvaluation.invariantEvaluations[invariant] = self self.isOK = None # set in subclasses. A bool.
[docs]class InvariantValidation(InvariantEvaluation): """ Invariant validation. Looks like this in USE OCL:: checking invariant (NUM) `CLASS::INVARIANT': OK. """ def __init__(self, modelEvaluation, invariant): InvariantEvaluation.__init__(self, modelEvaluation, invariant) self.isOK = True def __repr__(self): return '%s=OK'% self.invariant.name
[docs]class InvariantViolation(InvariantEvaluation): """ Invariant violation. Looks like this in USE OCL:: checking invariant (NUM) `CLASS::INVARIANT': FAILED. -> false : Boolean Instances of CLASS violating the invariant: -> Set{@bedroom201,@bedroom202, ...} : Set(Bedroom) """ def __init__(self, modelViolation, invariant, violatingObjects): InvariantEvaluation.__init__(self, modelViolation, invariant) self.violatingObjects = violatingObjects self.isOK = False def __repr__(self): return '%s=KO' % self.invariant.name
[docs]class CardinalityViolation(object): """ Cardinality violation. Looks like this in USE OCL:: Multiplicity constraint violation in association `ASSOC': Object `OBJECT' of class `CLASS' is connected to NUM objects of class `CLASS' at association end `END' but the multiplicity is specified as `NUM'. """ def __init__(self, modelViolation, role, violatingObject, cardinalityFound): self.modelViolation = modelViolation if role not in modelViolation.cardinalityViolations: modelViolation.cardinalityViolations[role] = [] modelViolation.cardinalityViolations[role].append(self) self.role = role self.violatingObject = violatingObject self.cardinalityFound = cardinalityFound
del ABCMeta, OrderedDict