<commit_before># -*- coding: utf-8 -*-
# Copyright 2013 Novo Nordisk Foundation Center for Biosustainability, DTU.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from __future__ import absolute_import, print_function

from functools import partial
import hashlib
import cobra as _cobrapy

import cameo
from cameo import flux_analysis
from cameo.parallel import SequentialView

import logging
import six
from cameo.util import doc_inherit

logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)

class Reaction(_cobrapy.core.Reaction):
    """This class extends the cobrapy Reaction class to work with SolverBasedModel.

    Notes
    -----
    See also documentation for cobra.core.Reaction.Reaction for an extensive list of inherited attributes.
    """

    @classmethod
    def clone(cls, reaction, model=None):
        """Clone a reaction.

        Parameters
        ----------
        reaction : Reaction, cobra.core.Reaction.Reaction
        model : model, optional

        Returns
        -------
        Reaction

        """
        new_reaction = cls(reaction.id, name=reaction.name)
        for attribute, value in six.iteritems(reaction.__dict__):
            if attribute == '_model':  # _model needs to be set after all other attributes have been set.
                continue
            try:
                setattr(new_reaction, attribute, value)
            except AttributeError:
                logger.info(
                    "Can't set attribute %s for reaction %s (while cloning it to a cameo style reaction). Skipping it ..." % (
                        attribute, reaction))
        if not isinstance(reaction.model, cameo.core.solver_based_model.SolverBasedModel):
            new_reaction._model = None
        if model is not None:
            new_reaction._model = model
        # for gene in new_reaction.genes:
        #     gene._reaction.remove(reaction)
        #     gene._reaction.add(new_reaction)
        # for metabolite in new_reaction.metabolites:
        #     metabolite._reaction.remove(reaction)
        #     metabolite._reaction.add(new_reaction)
        return new_reaction

    def __init__(self, id=None, name='', subsystem="", lower_bound=0, upper_bound=1000):
        """
        Parameters
        ----------
        name : str, optional
            The name of the reaction.
        """
        super(Reaction, self).__init__(id=id, name=name, subsystem=subsystem)
        self._lower_bound = lower_bound
        self._upper_bound = upper_bound
        self._model = None

    def __str__(self):
        return ''.join((self.id, ": ", self.build_reaction_string()))

    @property
    def reversibility(self):
        return self._lower_bound < 0 < self._upper_bound

    def _get_reverse_id(self):
        """Generate the id of reverse_variable from the reaction's id."""
        return '_'.join((self.id, 'reverse', hashlib.md5(self.id.encode('utf-8')).hexdigest()[0:5]))

    def _get_forward_id(self):
        """Generate the id of forward_variable from the reaction's id."""
        return self.id
        # return '_'.join((self.id, 'forward', hashlib.md5(self.id.encode('utf-8')).hexdigest()[0:5]))

    @property
    def flux_expression(self):
        """An optlang variable representing the forward flux (if associated with model), otherwise None.
        Representing the net flux if model.reversible_encoding == 'unsplit'"""
        model = self.model
        if model is not None:
            return 1. * self.forward_variable - 1. * self.reverse_variable
        else:
            return None

    @property
    def forward_variable(self):
        """An optlang variable representing the forward flux (if associated with model), otherwise None."""
        model = self.model
        if model is not None:
            aux_id = self._get_forward_id()
            return model.solver.variables[aux_id]
        else:
            return None

    @property
    def reverse_variable(self):
        """An optlang variable representing the reverse flux (if associated with model), otherwise None."""
        model = self.model
        if model is not None:
            aux_id = self._get_reverse_id()
            return model.solver.variables[aux_id]
        else:
            return None

    @property
    def lower_bound(self):
        return self._lower_bound

    @lower_bound.setter
    def lower_bound(self, value):
        model = self.model

        if model is not None:

            forward_variable, reverse_variable = self.forward_variable, self.reverse_variable
            if self._lower_bound < 0 < self._upper_bound:  # reversible
                if value < 0:
                    reverse_variable.ub = -1 * value
                elif value >= 0:
                    reverse_variable.ub = 0
                    try:
                        forward_variable.lb = value
                    except ValueError:
                        forward_variable.ub = value
                        self._upper_bound = value
                        forward_variable.lb = value
            elif self._lower_bound == 0 and self._upper_bound == 0:  # knockout
                if value < 0:
                    reverse_variable.ub = -1 * value
                elif value >= 0:
                    forward_variable.ub = value
                    forward_variable.lb = value
            elif self._lower_bound >= 0:  # forward irreversible
                if value < 0:
                    reverse_variable.ub = -1 * value
                    forward_variable.lb = 0
                else:
                    try:
                        forward_variable.lb = value
                    except ValueError:
                        forward_variable.ub = value
                        self._upper_bound = value
                        forward_variable.lb = value

            elif self._upper_bound <= 0:  # reverse irreversible
                if value > 0:
                    reverse_variable.lb = 0
                    reverse_variable.ub = 0
                    forward_variable.ub = value
                    self._upper_bound = value
                    forward_variable.lb = value
                else:
                    try:
                        reverse_variable.ub = -1 * value
                    except ValueError:
                        reverse_variable.lb = -1 * value
                        self._upper_bound = value
                        reverse_variable.ub = -1 * value
            else:
                print({'value': value, 'self._lower_bound': self._lower_bound, 'self._upper_bound': self._upper_bound})
                raise ValueError('lower_bound issue')

        self._lower_bound = value

    @property
    def upper_bound(self):
        return self._upper_bound

    @upper_bound.setter
    def upper_bound(self, value):
        model = self.model
        if model is not None:

            forward_variable, reverse_variable = self.forward_variable, self.reverse_variable
            if self._lower_bound < 0 < self._upper_bound:  # reversible
                if value > 0:
                    forward_variable.ub = value
                elif value <= 0:
                    forward_variable.ub = 0
                    try:
                        reverse_variable.lb = -1 * value
                    except ValueError:
                        reverse_variable.ub = -1 * value
                        self._lower_bound = value
                        reverse_variable.lb = -1 * value
            elif self._lower_bound == 0 and self._upper_bound == 0:  # knockout
                if value > 0:
                    forward_variable.ub = value
                elif value <= 0:
                    reverse_variable.ub = -1 * value
            elif self._lower_bound >= 0:  # forward irreversible
                if value > 0:
                    try:
                        forward_variable.ub = value
                    except ValueError:
                        forward_variable.lb = value
                        self._lower_bound = value
                        forward_variable.ub = value
                else:
                    forward_variable.lb = 0
                    forward_variable.ub = 0
                    reverse_variable.ub = -1 * value
                    self._lower_bound = value
                    reverse_variable.lb = -1 * value

            elif self._upper_bound <= 0:  # reverse irreversible
                if value < 0:
                    try:
                        reverse_variable.lb = -1 * value
                    except ValueError:
                        reverse_variable.ub = -1 * value
                        self._lower_bound = value
                        reverse_variable.lb = -1 * value
                else:
                    forward_variable.ub = value
                    reverse_variable.lb = 0
            else:
                print({'value': value, 'self._lower_bound': self._lower_bound, 'self._upper_bound': self._upper_bound})
                raise ValueError('upper_bound issue')

        self._upper_bound = value

    @property
    def model(self):
        return self._model

    @model.setter
    def model(self, value):
        if value is None:
            self.objective_coefficient  # Get objective coefficient from model
        elif not isinstance(value, cameo.core.SolverBasedModel):
            raise ValueError("Must be an instance of cameo.core.SolverBasedModel, not %s" % type(value))
        self._model = value

    @property
    def objective_coefficient(self):
        if self.model is not None and self.model.objective is not None:
            coefficients_dict = self.model.objective.expression.as_coefficients_dict()
            forw_coef = coefficients_dict.get(self.forward_variable, 0)
            rev_coef = coefficients_dict.get(self.reverse_variable, 0)
            if forw_coef == -rev_coef:
                self._objective_coefficient = float(forw_coef)
            else:
                self._objective_coefficient = 0
        return self._objective_coefficient

    @objective_coefficient.setter
    def objective_coefficient(self, value):
        model = self.model
        if model is not None:
            coef_difference = value - self.objective_coefficient
            model.objective += coef_difference * self.flux_expression
        self._objective_coefficient = value

    @property
    def effective_lower_bound(self):
        model = self.model
        fva_result = flux_analysis.flux_variability_analysis(model, reactions=[self], view=SequentialView(),
                                                             remove_cycles=False)
        return fva_result['lower_bound'][self.id]

    @property
    def effective_upper_bound(self):
        model = self.model
        fva_result = flux_analysis.flux_variability_analysis(model, reactions=[self], view=SequentialView(),
                                                             remove_cycles=False)
        return fva_result['upper_bound'][self.id]

    @property
    def flux(self):
        if self.model is not None:
            return self.forward_variable.primal - self.reverse_variable.primal
        else:
            return None

    @property
    def reduced_cost(self):
        if self.model is not None:
            return self.forward_variable.dual - self.reverse_variable.dual
        else:
            return None

    @doc_inherit
    def add_metabolites(self, metabolites, combine=True, **kwargs):
        if not combine:
            old_coefficients = self.metabolites
        super(Reaction, self).add_metabolites(metabolites, combine=combine, **kwargs)
        model = self.model
        if model is not None:
            for metabolite, coefficient in six.iteritems(metabolites):
                if isinstance(metabolite, six.string_types):  # support metabolites added as strings.
                    metabolite = model.metabolites.get_by_id(metabolite)
                if not combine:
                    try:
                        old_coefficient = old_coefficients[metabolite]
                    except KeyError:
                        pass
                    else:
                        coefficient = coefficient - old_coefficient
                model.solver.constraints[metabolite.id] += coefficient * self.flux_expression

    @property
    def id(self):
        return getattr(self, "_id", None)  # Returns None if _id is not set

    @id.setter
    def id(self, value):
        if value == self.id:
            pass
        elif not isinstance(value, six.string_types):
            raise TypeError("ID must be a string")
        elif getattr(self, "_model", None) is not None:  # (= if hasattr(self, "_model") and self._model is not None)
            if value in self.model.reactions:
                raise ValueError("The model already contains a reaction with the id:", value)
            forward_variable = self.forward_variable
            reverse_variable = self.reverse_variable

            self._id = value
            self.model.reactions._generate_index()

            forward_variable.name = self._get_forward_id()
            reverse_variable.name = self._get_reverse_id()
        else:
            self._id = value

    def knock_out(self, time_machine=None):
        """Knockout reaction by setting its bounds to zero.

        Parameters
        ----------
        time_machine = TimeMachine
            A time TimeMachine instance can be provided to undo the knockout eventually.

        Returns
        -------
        None
        """

        def _(reaction, lb, ub):
            reaction.upper_bound = ub
            reaction.lower_bound = lb

        if time_machine is not None:
            time_machine(do=super(Reaction, self).knock_out, undo=partial(_, self, self.lower_bound, self.upper_bound))
        else:
            super(Reaction, self).knock_out()

    def pop(self, metabolite_id):
        """Removes a given metabolite from the reaction stoichiometry, and returns the coefficient.
        """
        if self._model is None:
            return super(Reaction, self).pop(metabolite_id)
        else:
            if isinstance(metabolite_id, six.string_types):
                met = self.model.metabolites.get_by_id(metabolite_id)
            else:
                met = metabolite_id
            coef = self.metabolites[met]
            self.add_metabolites({met: -coef}, combine=True)
            return coef

    def remove_from_model(self, model=None, remove_orphans=False):
        reaction_model = self.model
        forward = self.forward_variable
        reverse = self.reverse_variable
        super(Reaction, self).remove_from_model(model, remove_orphans)
        reaction_model.solver.remove([forward, reverse])

    def delete(self, remove_orphans=False):
        model = self.model
        forward = self.forward_variable
        reverse = self.reverse_variable
        super(Reaction, self).delete(remove_orphans)
        model.solver.remove([forward, reverse])

    def _repr_html_(self):
        return """

                Id	%s

                Name	%s

                Stoichiometry	%s

                Lower bound	%f

                Upper bound	%f

        """ % (self.id, self.name, self.reaction, self.lower_bound, self.upper_bound)
<commit_msg>feat: cache internal forward and reverse variables<commit_after># -*- coding: utf-8 -*-
# Copyright 2013 Novo Nordisk Foundation Center for Biosustainability, DTU.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from __future__ import absolute_import, print_function

from functools import partial
import hashlib
import cobra as _cobrapy

import cameo
from cameo import flux_analysis
from cameo.parallel import SequentialView

import logging
import six
from cameo.util import doc_inherit

logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)

class Reaction(_cobrapy.core.Reaction):
    """This class extends the cobrapy Reaction class to work with SolverBasedModel.

    Notes
    -----
    See also documentation for cobra.core.Reaction.Reaction for an extensive list of inherited attributes.
    """

    @classmethod
    def clone(cls, reaction, model=None):
        """Clone a reaction.

        Parameters
        ----------
        reaction : Reaction, cobra.core.Reaction.Reaction
        model : model, optional

        Returns
        -------
        Reaction

        """
        new_reaction = cls(reaction.id, name=reaction.name)
        for attribute, value in six.iteritems(reaction.__dict__):
            if attribute == '_model':  # _model needs to be set after all other attributes have been set.
                continue
            try:
                setattr(new_reaction, attribute, value)
            except AttributeError:
                logger.info(
                    "Can't set attribute %s for reaction %s (while cloning it to a cameo style reaction). Skipping it ..." % (
                        attribute, reaction))
        if not isinstance(reaction.model, cameo.core.solver_based_model.SolverBasedModel):
            new_reaction._model = None
        if model is not None:
            new_reaction._model = model
        # for gene in new_reaction.genes:
        #     gene._reaction.remove(reaction)
        #     gene._reaction.add(new_reaction)
        # for metabolite in new_reaction.metabolites:
        #     metabolite._reaction.remove(reaction)
        #     metabolite._reaction.add(new_reaction)
        return new_reaction

    def __init__(self, id=None, name='', subsystem="", lower_bound=0, upper_bound=1000):
        """
        Parameters
        ----------
        name : str, optional
            The name of the reaction.
        """
        super(Reaction, self).__init__(id=id, name=name, subsystem=subsystem)
        self._lower_bound = lower_bound
        self._upper_bound = upper_bound
        self._model = None
        self._reverse_variable = None
        self._forward_variable = None

    def __str__(self):
        return ''.join((self.id, ": ", self.build_reaction_string()))

    @property
    def reversibility(self):
        return self._lower_bound < 0 < self._upper_bound

    def _get_reverse_id(self):
        """Generate the id of reverse_variable from the reaction's id."""
        return '_'.join((self.id, 'reverse', hashlib.md5(self.id.encode('utf-8')).hexdigest()[0:5]))

    def _get_forward_id(self):
        """Generate the id of forward_variable from the reaction's id."""
        return self.id
        # return '_'.join((self.id, 'forward', hashlib.md5(self.id.encode('utf-8')).hexdigest()[0:5]))

    @property
    def flux_expression(self):
        """An optlang variable representing the forward flux (if associated with model), otherwise None.
        Representing the net flux if model.reversible_encoding == 'unsplit'"""
        model = self.model
        if model is not None:
            return 1. * self.forward_variable - 1. * self.reverse_variable
        else:
            return None

    @property
    def forward_variable(self):
        """An optlang variable representing the forward flux (if associated with model), otherwise None."""
        model = self.model
        if model is not None:
            if self._forward_variable is None:
                aux_id = self._get_forward_id()
                self._forward_variable = model.solver.variables[aux_id]
                return self._forward_variable
            else:
                return self._forward_variable
        else:
            return None

    @property
    def reverse_variable(self):
        """An optlang variable representing the reverse flux (if associated with model), otherwise None."""
        model = self.model
        if model is not None:
            if self._reverse_variable is None:
                aux_id = self._get_reverse_id()
                self._reverse_variable = model.solver.variables[aux_id]
                return self._reverse_variable
            else:
                return self._reverse_variable
        else:
            return None

    @property
    def lower_bound(self):
        return self._lower_bound

    @lower_bound.setter
    def lower_bound(self, value):
        model = self.model

        if model is not None:

            forward_variable, reverse_variable = self.forward_variable, self.reverse_variable
            if self._lower_bound < 0 < self._upper_bound:  # reversible
                if value < 0:
                    reverse_variable.ub = -1 * value
                elif value >= 0:
                    reverse_variable.ub = 0
                    try:
                        forward_variable.lb = value
                    except ValueError:
                        forward_variable.ub = value
                        self._upper_bound = value
                        forward_variable.lb = value
            elif self._lower_bound == 0 and self._upper_bound == 0:  # knockout
                if value < 0:
                    reverse_variable.ub = -1 * value
                elif value >= 0:
                    forward_variable.ub = value
                    forward_variable.lb = value
            elif self._lower_bound >= 0:  # forward irreversible
                if value < 0:
                    reverse_variable.ub = -1 * value
                    forward_variable.lb = 0
                else:
                    try:
                        forward_variable.lb = value
                    except ValueError:
                        forward_variable.ub = value
                        self._upper_bound = value
                        forward_variable.lb = value

            elif self._upper_bound <= 0:  # reverse irreversible
                if value > 0:
                    reverse_variable.lb = 0
                    reverse_variable.ub = 0
                    forward_variable.ub = value
                    self._upper_bound = value
                    forward_variable.lb = value
                else:
                    try:
                        reverse_variable.ub = -1 * value
                    except ValueError:
                        reverse_variable.lb = -1 * value
                        self._upper_bound = value
                        reverse_variable.ub = -1 * value
            else:
                print({'value': value, 'self._lower_bound': self._lower_bound, 'self._upper_bound': self._upper_bound})
                raise ValueError('lower_bound issue')

        self._lower_bound = value

    @property
    def upper_bound(self):
        return self._upper_bound

    @upper_bound.setter
    def upper_bound(self, value):
        model = self.model
        if model is not None:

            forward_variable, reverse_variable = self.forward_variable, self.reverse_variable
            if self._lower_bound < 0 < self._upper_bound:  # reversible
                if value > 0:
                    forward_variable.ub = value
                elif value <= 0:
                    forward_variable.ub = 0
                    try:
                        reverse_variable.lb = -1 * value
                    except ValueError:
                        reverse_variable.ub = -1 * value
                        self._lower_bound = value
                        reverse_variable.lb = -1 * value
            elif self._lower_bound == 0 and self._upper_bound == 0:  # knockout
                if value > 0:
                    forward_variable.ub = value
                elif value <= 0:
                    reverse_variable.ub = -1 * value
            elif self._lower_bound >= 0:  # forward irreversible
                if value > 0:
                    try:
                        forward_variable.ub = value
                    except ValueError:
                        forward_variable.lb = value
                        self._lower_bound = value
                        forward_variable.ub = value
                else:
                    forward_variable.lb = 0
                    forward_variable.ub = 0
                    reverse_variable.ub = -1 * value
                    self._lower_bound = value
                    reverse_variable.lb = -1 * value

            elif self._upper_bound <= 0:  # reverse irreversible
                if value < 0:
                    try:
                        reverse_variable.lb = -1 * value
                    except ValueError:
                        reverse_variable.ub = -1 * value
                        self._lower_bound = value
                        reverse_variable.lb = -1 * value
                else:
                    forward_variable.ub = value
                    reverse_variable.lb = 0
            else:
                print({'value': value, 'self._lower_bound': self._lower_bound, 'self._upper_bound': self._upper_bound})
                raise ValueError('upper_bound issue')

        self._upper_bound = value

    @property
    def model(self):
        return self._model

    @model.setter
    def model(self, value):
        if value is None:
            self.objective_coefficient  # Get objective coefficient from model
        elif not isinstance(value, cameo.core.SolverBasedModel):
            raise ValueError("Must be an instance of cameo.core.SolverBasedModel, not %s" % type(value))
        self._model = value

    @property
    def objective_coefficient(self):
        if self.model is not None and self.model.objective is not None:
            coefficients_dict = self.model.objective.expression.as_coefficients_dict()
            forw_coef = coefficients_dict.get(self.forward_variable, 0)
            rev_coef = coefficients_dict.get(self.reverse_variable, 0)
            if forw_coef == -rev_coef:
                self._objective_coefficient = float(forw_coef)
            else:
                self._objective_coefficient = 0
        return self._objective_coefficient

    @objective_coefficient.setter
    def objective_coefficient(self, value):
        model = self.model
        if model is not None:
            coef_difference = value - self.objective_coefficient
            model.objective += coef_difference * self.flux_expression
        self._objective_coefficient = value

    @property
    def effective_lower_bound(self):
        model = self.model
        fva_result = flux_analysis.flux_variability_analysis(model, reactions=[self], view=SequentialView(),
                                                             remove_cycles=False)
        return fva_result['lower_bound'][self.id]

    @property
    def effective_upper_bound(self):
        model = self.model
        fva_result = flux_analysis.flux_variability_analysis(model, reactions=[self], view=SequentialView(),
                                                             remove_cycles=False)
        return fva_result['upper_bound'][self.id]

    @property
    def flux(self):
        if self.model is not None:
            return self.forward_variable.primal - self.reverse_variable.primal
        else:
            return None

    @property
    def reduced_cost(self):
        if self.model is not None:
            return self.forward_variable.dual - self.reverse_variable.dual
        else:
            return None

    @doc_inherit
    def add_metabolites(self, metabolites, combine=True, **kwargs):
        if not combine:
            old_coefficients = self.metabolites
        super(Reaction, self).add_metabolites(metabolites, combine=combine, **kwargs)
        model = self.model
        if model is not None:
            for metabolite, coefficient in six.iteritems(metabolites):
                if isinstance(metabolite, six.string_types):  # support metabolites added as strings.
                    metabolite = model.metabolites.get_by_id(metabolite)
                if not combine:
                    try:
                        old_coefficient = old_coefficients[metabolite]
                    except KeyError:
                        pass
                    else:
                        coefficient = coefficient - old_coefficient
                model.solver.constraints[metabolite.id] += coefficient * self.flux_expression

    @property
    def id(self):
        return getattr(self, "_id", None)  # Returns None if _id is not set

    @id.setter
    def id(self, value):
        if value == self.id:
            pass
        elif not isinstance(value, six.string_types):
            raise TypeError("ID must be a string")
        elif getattr(self, "_model", None) is not None:  # (= if hasattr(self, "_model") and self._model is not None)
            if value in self.model.reactions:
                raise ValueError("The model already contains a reaction with the id:", value)
            forward_variable = self.forward_variable
            reverse_variable = self.reverse_variable

            self._id = value
            self.model.reactions._generate_index()

            forward_variable.name = self._get_forward_id()
            reverse_variable.name = self._get_reverse_id()
        else:
            self._id = value

    def knock_out(self, time_machine=None):
        """Knockout reaction by setting its bounds to zero.

        Parameters
        ----------
        time_machine = TimeMachine
            A time TimeMachine instance can be provided to undo the knockout eventually.

        Returns
        -------
        None
        """

        def _(reaction, lb, ub):
            reaction.upper_bound = ub
            reaction.lower_bound = lb

        if time_machine is not None:
            time_machine(do=super(Reaction, self).knock_out, undo=partial(_, self, self.lower_bound, self.upper_bound))
        else:
            super(Reaction, self).knock_out()

    def pop(self, metabolite_id):
        """Removes a given metabolite from the reaction stoichiometry, and returns the coefficient.
        """
        if self._model is None:
            return super(Reaction, self).pop(metabolite_id)
        else:
            if isinstance(metabolite_id, six.string_types):
                met = self.model.metabolites.get_by_id(metabolite_id)
            else:
                met = metabolite_id
            coef = self.metabolites[met]
            self.add_metabolites({met: -coef}, combine=True)
            return coef

    def remove_from_model(self, model=None, remove_orphans=False):
        reaction_model = self.model
        forward = self.forward_variable
        reverse = self.reverse_variable
        super(Reaction, self).remove_from_model(model, remove_orphans)
        reaction_model.solver.remove([forward, reverse])

    def delete(self, remove_orphans=False):
        model = self.model
        forward = self.forward_variable
        reverse = self.reverse_variable
        super(Reaction, self).delete(remove_orphans)
        model.solver.remove([forward, reverse])

    def _repr_html_(self):
        return """

                Id	%s

                Name	%s

                Stoichiometry	%s

                Lower bound	%f

                Upper bound	%f

        """ % (self.id, self.name, self.reaction, self.lower_bound, self.upper_bound)
<|endoftext|>


<commit_before># No shebang line, this module is meant to be imported
#
# Copyright 2013 Oliver Palmer
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#    http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""
Special column types used by PyFarm's models.
"""

from textwrap import dedent
from uuid import uuid4, UUID
from UserDict import UserDict
from UserList import UserList

try:
    from json import dumps, loads
except ImportError:
    from simplejson import dumps, loads

from sqlalchemy.types import TypeDecorator, CHAR, String
from sqlalchemy.dialects.postgresql import UUID as PGUuid

from pyfarm.flaskapp import db

JSON_NONE = dumps(None)
NoneType = type(None) # from stdlib types module

class GUID(TypeDecorator):
    """
    Platform-independent GUID type.

    Uses Postgresql's UUID type, otherwise uses
    CHAR(32), storing as stringified hex values.

    .. note::
        This code is copied from sqlalchemy's standard documentation
    """
    impl = CHAR

    def load_dialect_impl(self, dialect):
        if dialect.name == "postgresql":
            return dialect.type_descriptor(PGUuid())
        else:
            return dialect.type_descriptor(CHAR(32))

    def process_bind_param(self, value, dialect):
        if value is None:
            return value
        elif dialect.name == "postgresql":
            return str(value)
        else:
            if not isinstance(value, UUID):
                return "%.32x" % UUID(value)
            else:
                # hexstring
                return "%.32x" % value

    def process_result_value(self, value, dialect):
        if value is None:
            return value
        else:
            return UUID(value)

class JSONSerializable(TypeDecorator):
    """
    Base of all custom types which process json data
    to and from the database.

    :cvar serialize_types:
        the kinds of objects we expect to serialize to
        and from the database

    :cvar serialize_none:
        if True then return None instead of converting it to
        its json value

    :cvar allow_blank:
        if True, do not raise a :class:`ValueError` for empty data

    :cvar allow_empty:
        if True, do not raise :class:`ValueError` if the input data
        itself is empty
    """
    impl = String
    serialize_types = None
    serialize_none = False

    def __init__(self, *args, **kwargs):
        super(JSONSerializable, self).__init__(*args, **kwargs)

        # make sure the subclass is doing something we expect
        if self.serialize_types is None:
            raise NotImplementedError("`serialize_types` is not defined")

    def dumps(self, value):
        """
        Performs the process of dumping `value` to json.  For classes
        such as :class:`UserDict` or :class:`UserList` this will dump the
        underlying data instead of the object itself.
        """
        if isinstance(value, (UserDict, UserList)):
            value = value.data

        return dumps(value)

    def process_bind_param(self, value, dialect):
        """Converts the value being assigned into a json blob"""
        if value is None:
            return self.dumps(value) if self.serialize_none else value

        elif isinstance(value, self.serialize_types):
            return self.dumps(value)

        else:
            args = (value, self.__class__.__name__)
            raise ValueError("unexpected input %s for `%s`" % args)

    def process_result_value(self, value, dialect):
        """Converts data from the database into a Python object"""
        return value if value is None else loads(value)

class JSONList(JSONSerializable):
    """Special column type for storing list objects as json"""
    serialize_types = (list, tuple, UserList)

class JSONDict(JSONSerializable):
    """Special column type for storing dictionary objects as json"""
    serialize_types = (dict, UserDict)

def IDColumn():
    """
    Produces a column used for `id` on each table.  Typically this is done
    using a class in :mod:`pyfarm.models.mixins` however because of the ORM
    and the table relationships it's cleaner to have a function produce
    the column.
    """
    return db.Column(IDType, primary_key=True, unique=True, default=IDDefault,
                     doc=dedent("""
                     Provides an id for the current row.  This value should
                     never be directly relied upon and it's intended for use
                     by relationships."""))

# the universal mapping which can be used, even if the underlying
# type changes in the future
IDType = GUID
IDDefault = uuid4
<commit_msg>added IPv4Address<commit_after># No shebang line, this module is meant to be imported
#
# Copyright 2013 Oliver Palmer
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#    http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""
Special column types used by PyFarm's models.
"""

from textwrap import dedent
from uuid import uuid4, UUID
from UserDict import UserDict
from UserList import UserList

from netaddr import IPAddress

try:
    from json import dumps, loads
except ImportError:
    from simplejson import dumps, loads

from sqlalchemy.types import TypeDecorator, CHAR, String
from sqlalchemy.dialects.postgresql import UUID as PGUuid

from pyfarm.flaskapp import db

JSON_NONE = dumps(None)
NoneType = type(None) # from stdlib types module

class GUID(TypeDecorator):
    """
    Platform-independent GUID type.

    Uses Postgresql's UUID type, otherwise uses
    CHAR(32), storing as stringified hex values.

    .. note::
        This code is copied from sqlalchemy's standard documentation
    """
    impl = CHAR

    def load_dialect_impl(self, dialect):
        if dialect.name == "postgresql":
            return dialect.type_descriptor(PGUuid())
        else:
            return dialect.type_descriptor(CHAR(32))

    def process_bind_param(self, value, dialect):
        if value is None:
            return value
        elif dialect.name == "postgresql":
            return str(value)
        else:
            if not isinstance(value, UUID):
                return "%.32x" % UUID(value)
            else:
                # hexstring
                return "%.32x" % value

    def process_result_value(self, value, dialect):
        if value is None:
            return value
        else:
            return UUID(value)

class JSONSerializable(TypeDecorator):
    """
    Base of all custom types which process json data
    to and from the database.

    :cvar serialize_types:
        the kinds of objects we expect to serialize to
        and from the database

    :cvar serialize_none:
        if True then return None instead of converting it to
        its json value

    :cvar allow_blank:
        if True, do not raise a :class:`ValueError` for empty data

    :cvar allow_empty:
        if True, do not raise :class:`ValueError` if the input data
        itself is empty
    """
    impl = String
    serialize_types = None
    serialize_none = False

    def __init__(self, *args, **kwargs):
        super(JSONSerializable, self).__init__(*args, **kwargs)

        # make sure the subclass is doing something we expect
        if self.serialize_types is None:
            raise NotImplementedError("`serialize_types` is not defined")

    def dumps(self, value):
        """
        Performs the process of dumping `value` to json.  For classes
        such as :class:`UserDict` or :class:`UserList` this will dump the
        underlying data instead of the object itself.
        """
        if isinstance(value, (UserDict, UserList)):
            value = value.data

        return dumps(value)

    def process_bind_param(self, value, dialect):
        """Converts the value being assigned into a json blob"""
        if value is None:
            return self.dumps(value) if self.serialize_none else value

        elif isinstance(value, self.serialize_types):
            return self.dumps(value)

        else:
            args = (value, self.__class__.__name__)
            raise ValueError("unexpected input %s for `%s`" % args)

    def process_result_value(self, value, dialect):
        """Converts data from the database into a Python object"""
        return value if value is None else loads(value)

class JSONList(JSONSerializable):
    """Column type for storing list objects as json"""
    serialize_types = (list, tuple, UserList)

class JSONDict(JSONSerializable):
    """Column type for storing dictionary objects as json"""
    serialize_types = (dict, UserDict)

class IPv4Address(TypeDecorator):
    """
    Column type which can store and retrieve IPv4 addresses in a more
    efficient manner
    """
    def process_bind_param(self, value, dialect):
        if isinstance(value, int):
            return value
        elif isinstance(value, basestring):
            return int(IPAddress(value))
        elif isinstance(value, IPAddress):
            return int(value)
        else:
            raise ValueError("unexpected type %s for value" % type(value))

    def process_result_value(self, value, dialect):
        return IPAddress(value)

def IDColumn():
    """
    Produces a column used for `id` on each table.  Typically this is done
    using a class in :mod:`pyfarm.models.mixins` however because of the ORM
    and the table relationships it's cleaner to have a function produce
    the column.
    """
    return db.Column(IDType, primary_key=True, unique=True, default=IDDefault,
                     doc=dedent("""
                     Provides an id for the current row.  This value should
                     never be directly relied upon and it's intended for use
                     by relationships."""))

# the universal mapping which can be used, even if the underlying
# type changes in the future
IDType = GUID
IDDefault = uuid4
<|endoftext|>


<commit_before>#!/usr/bin/env python
# -*- coding: utf-8 -*-
###############################################################################
#
# Copyright (C) 2013-Today  Carlos Eduardo Vercelino - CLVsol
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
###############################################################################

from __future__ import print_function

import sqlite3
import psycopg2

def ir_sequence_export_sqlite(client, args, db_path, table_name, conn_string):

    conn = sqlite3.connect(db_path)
    conn.text_factory = str

    cursor = conn.cursor()
    try:
        cursor.execute('''DROP TABLE ''' + table_name + ''';''')
    except Exception as e:
        print('------->', e)
    cursor.execute(
        '''
        CREATE TABLE ''' + table_name + ''' (
            id INTEGER NOT NULL PRIMARY KEY,
            name,
            implementation,
            code,
            active,
            company_id,
            prefix,
            suffix,
            use_date_range,
            padding,
            number_increment,
            number_next,
            postgres_last_value,
            new_id INTEGER
            );
        '''
    )

    pg_conn = psycopg2.connect(conn_string)
    pg_cursor = pg_conn.cursor()

    client.context = {'active_test': False}
    ir_sequence_model = client.model('ir.sequence')
    ir_sequence_browse = ir_sequence_model.browse(args)

    ir_sequence_count = 0
    for ir_sequence_reg in ir_sequence_browse:
        ir_sequence_count += 1

        query = "SELECT last_value, increment_by, is_called FROM ir_sequence_%03d" % ir_sequence_reg.id
        pg_cursor.execute(query)
        row = pg_cursor.fetchone()
        postgres_last_value = row[0]

        print(
            ir_sequence_count, ir_sequence_reg.id, ir_sequence_reg.name.encode("utf-8"), ir_sequence_reg.code,
            postgres_last_value,
        )

        prefix = None
        if ir_sequence_reg.prefix:
            prefix = ir_sequence_reg.prefix

        suffix = None
        if ir_sequence_reg.suffix:
            suffix = ir_sequence_reg.suffix

        suffix = None
        if ir_sequence_reg.suffix:
            suffix = ir_sequence_reg.suffix

        cursor.execute('''
            INSERT INTO ''' + table_name + '''(
                id,
                name,
                implementation,
                code,
                active,
                company_id,
                prefix,
                suffix,
                use_date_range,
                padding,
                number_increment,
                number_next,
                postgres_last_value
                )
            VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?)
            ''', (ir_sequence_reg.id,
                  ir_sequence_reg.name,
                  ir_sequence_reg.implementation,
                  ir_sequence_reg.code,
                  ir_sequence_reg.active,
                  ir_sequence_reg.company_id.id,
                  prefix,
                  suffix,
                  ir_sequence_reg.use_date_range,
                  ir_sequence_reg.padding,
                  ir_sequence_reg.number_increment,
                  ir_sequence_reg.number_next,
                  postgres_last_value,
                  )
        )

    conn.commit()
    conn.close()

    print()
    print('--> ir_sequence_count: ', ir_sequence_count)

def ir_sequence_import_sqlite(client, args, db_path, table_name, conn_string):

    # ir_sequence_model = client.model('ir.sequence')

    conn = sqlite3.connect(db_path)
    # conn.text_factory = str
    conn.row_factory = sqlite3.Row

    cursor = conn.cursor()

    data = cursor.execute('''
        SELECT
            id,
            name,
            implementation,
            code,
            active,
            company_id,
            prefix,
            suffix,
            use_date_range,
            padding,
            number_increment,
            number_next,
            postgres_last_value,
            new_id
        FROM ''' + table_name + ''';
    ''')

    print(data)
    print([field[0] for field in cursor.description])

    pg_conn = psycopg2.connect(conn_string)
    pg_cursor = pg_conn.cursor()

    ir_sequence_count = 0
    for row in cursor:
        ir_sequence_count += 1

        print(
            ir_sequence_count, row['id'], row['name'], row['implementation'], row['code'],
            row['prefix'], row['padding'], row['number_increment'], row['number_next'], row['postgres_last_value']
        )

        query = "SELECT last_value, increment_by, is_called FROM ir_sequence_%03d" % row['id']
        pg_cursor.execute(query)
        row2 = pg_cursor.fetchone()
        postgres_last_value = row2[0]

        my_table = row['code'][:-5].replace('.', '_')
        query2 = "SELECT MAX(id) FROM %s;" % my_table
        pg_cursor.execute(query2)
        row3 = pg_cursor.fetchone()
        max_id = row3[0]

        print('>>>>>', my_table, row['postgres_last_value'], postgres_last_value, max_id)

        if postgres_last_value < max_id:
            if row['postgres_last_value'] > max_id:
                query3 = "SELECT setval('ir_sequence_%03d', %d);" % (row['id'], row['postgres_last_value'])
                print('>>>>>>>>>>>>>>>', query3)
                pg_cursor.execute(query3)
                row4 = pg_cursor.fetchone()
                print('>>>>>>>>>>>>>>>', row4[0])
            else:
                query3 = "SELECT setval('ir_sequence_%03d', %d);" % (row['id'], max_id)
                print('>>>>>>>>>>>>>>>', query3)
                pg_cursor.execute(query3)
                row4 = pg_cursor.fetchone()
                print('>>>>>>>>>>>>>>>', row4[0])

    conn.commit()
    conn.close()

    print()
    print('--> ir_sequence_count: ', ir_sequence_count)

def ir_sequence_import_sqlite_named(client, args, db_path, table_name, conn_string, input_code, output_code):

    # ir_sequence_model = client.model('ir.sequence')

    conn = sqlite3.connect(db_path)
    # conn.text_factory = str
    conn.row_factory = sqlite3.Row

    cursor = conn.cursor()

    data = cursor.execute('''
        SELECT
            id,
            name,
            implementation,
            code,
            active,
            company_id,
            prefix,
            suffix,
            use_date_range,
            padding,
            number_increment,
            number_next,
            postgres_last_value,
            new_id
        FROM ''' + table_name + ''';
    ''')

    print(data)
    print([field[0] for field in cursor.description])

    pg_conn = psycopg2.connect(conn_string)
    pg_cursor = pg_conn.cursor()

    ir_sequence_model = client.model('ir.sequence')

    ir_sequence_count = 0
    for row in cursor:
        ir_sequence_count += 1

        if input_code == row['code']:

            print(
                ir_sequence_count, row['id'], row['name'], row['implementation'], row['code'],
                row['prefix'], row['padding'], row['number_increment'], row['number_next'], row['postgres_last_value']
            )

            ir_sequence_browse = ir_sequence_model.browse(args)

            ir_sequence_count = 0
            for ir_sequence_reg in ir_sequence_browse:
                ir_sequence_count += 1

                if ir_sequence_reg.code == output_code:

                    query = "SELECT last_value, increment_by, is_called FROM ir_sequence_%03d" % ir_sequence_reg.id
                    pg_cursor.execute(query)
                    row5 = pg_cursor.fetchone()
                    postgres_last_value = row5[0]

                    print(
                        ir_sequence_count, ir_sequence_reg.id, ir_sequence_reg.name.encode("utf-8"),
                        ir_sequence_reg.code,
                        postgres_last_value,
                    )

                    my_table = ir_sequence_reg.code[:-5].replace('.', '_')
                    query2 = "SELECT MAX(id) FROM %s;" % my_table
                    pg_cursor.execute(query2)
                    row3 = pg_cursor.fetchone()
                    max_id = row3[0]

                    print('>>>>>', my_table, row['postgres_last_value'], postgres_last_value, max_id,
                          ir_sequence_reg.number_next_actual)

                    if postgres_last_value < max_id:
                        if row['postgres_last_value'] > max_id:
                            query3 = "SELECT setval('ir_sequence_%03d', %d);" % \
                                (ir_sequence_reg.id, row['postgres_last_value'])
                            print('>>>>>>>>>>>>>>>', query3)
                            pg_cursor.execute(query3)
                            row4 = pg_cursor.fetchone()
                            print('>>>>>>>>>>>>>>>', row4[0])
                        else:
                            query3 = "SELECT setval('ir_sequence_%03d', %d);" % (ir_sequence_reg.id, max_id)
                            print('>>>>>>>>>>>>>>>', query3)
                            pg_cursor.execute(query3)
                            row4 = pg_cursor.fetchone()
                            print('>>>>>>>>>>>>>>>', row4[0])
                    else:
                        query3 = "SELECT setval('ir_sequence_%03d', %d);" % (ir_sequence_reg.id, postgres_last_value)
                        print('>>>>>>>>>>>>>>>', query3)
                        pg_cursor.execute(query3)
                        row4 = pg_cursor.fetchone()
                        print('>>>>>>>>>>>>>>>', row4[0])

    conn.commit()
    conn.close()

    print()
    print('--> ir_sequence_count: ', ir_sequence_count)
<commit_msg>[IMP] ir_sequence_export_sqlite_10 (ADD ir_sequence_export_sqlite_10)<commit_after>#!/usr/bin/env python
# -*- coding: utf-8 -*-
###############################################################################
#
# Copyright (C) 2013-Today  Carlos Eduardo Vercelino - CLVsol
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
###############################################################################

from __future__ import print_function

import sqlite3
import psycopg2

def ir_sequence_export_sqlite(client, args, db_path, table_name, conn_string):

    conn = sqlite3.connect(db_path)
    conn.text_factory = str

    cursor = conn.cursor()
    try:
        cursor.execute('''DROP TABLE ''' + table_name + ''';''')
    except Exception as e:
        print('------->', e)
    cursor.execute(
        '''
        CREATE TABLE ''' + table_name + ''' (
            id INTEGER NOT NULL PRIMARY KEY,
            name,
            implementation,
            code,
            active,
            company_id,
            prefix,
            suffix,
            use_date_range,
            padding,
            number_increment,
            number_next,
            postgres_last_value,
            new_id INTEGER
            );
        '''
    )

    pg_conn = psycopg2.connect(conn_string)
    pg_cursor = pg_conn.cursor()

    client.context = {'active_test': False}
    ir_sequence_model = client.model('ir.sequence')
    ir_sequence_browse = ir_sequence_model.browse(args)

    ir_sequence_count = 0
    for ir_sequence_reg in ir_sequence_browse:
        ir_sequence_count += 1

        query = "SELECT last_value, increment_by, is_called FROM ir_sequence_%03d" % ir_sequence_reg.id
        pg_cursor.execute(query)
        row = pg_cursor.fetchone()
        postgres_last_value = row[0]

        print(
            ir_sequence_count, ir_sequence_reg.id, ir_sequence_reg.name.encode("utf-8"), ir_sequence_reg.code,
            postgres_last_value,
        )

        prefix = None
        if ir_sequence_reg.prefix:
            prefix = ir_sequence_reg.prefix

        suffix = None
        if ir_sequence_reg.suffix:
            suffix = ir_sequence_reg.suffix

        suffix = None
        if ir_sequence_reg.suffix:
            suffix = ir_sequence_reg.suffix

        cursor.execute('''
            INSERT INTO ''' + table_name + '''(
                id,
                name,
                implementation,
                code,
                active,
                company_id,
                prefix,
                suffix,
                use_date_range,
                padding,
                number_increment,
                number_next,
                postgres_last_value
                )
            VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?)
            ''', (ir_sequence_reg.id,
                  ir_sequence_reg.name,
                  ir_sequence_reg.implementation,
                  ir_sequence_reg.code,
                  ir_sequence_reg.active,
                  ir_sequence_reg.company_id.id,
                  prefix,
                  suffix,
                  ir_sequence_reg.use_date_range,
                  ir_sequence_reg.padding,
                  ir_sequence_reg.number_increment,
                  ir_sequence_reg.number_next,
                  postgres_last_value,
                  )
        )

    conn.commit()
    conn.close()

    print()
    print('--> ir_sequence_count: ', ir_sequence_count)

def ir_sequence_export_sqlite_10(client, args, db_path, table_name, conn_string):

    conn = sqlite3.connect(db_path)
    conn.text_factory = str

    cursor = conn.cursor()
    try:
        cursor.execute('''DROP TABLE ''' + table_name + ''';''')
    except Exception as e:
        print('------->', e)
    cursor.execute(
        '''
        CREATE TABLE ''' + table_name + ''' (
            id INTEGER NOT NULL PRIMARY KEY,
            name,
            implementation,
            code,
            active,
            company_id,
            prefix,
            suffix,
            use_date_range,
            padding,
            number_increment,
            number_next,
            postgres_last_value,
            new_id INTEGER
            );
        '''
    )

    pg_conn = psycopg2.connect(conn_string)
    pg_cursor = pg_conn.cursor()

    # client.context = {'active_test': False}
    ir_sequence_model = client.model('ir.sequence')
    ir_sequence_browse = ir_sequence_model.browse(args)

    ir_sequence_count = 0
    for ir_sequence_reg in ir_sequence_browse:
        ir_sequence_count += 1

        query = "SELECT last_value, increment_by, is_called FROM ir_sequence_%03d" % ir_sequence_reg.id
        pg_cursor.execute(query)
        row = pg_cursor.fetchone()
        postgres_last_value = row[0]

        print(
            ir_sequence_count, ir_sequence_reg.id, ir_sequence_reg.name.encode("utf-8"), ir_sequence_reg.code,
            postgres_last_value,
        )

        prefix = None
        if ir_sequence_reg.prefix:
            prefix = ir_sequence_reg.prefix

        suffix = None
        if ir_sequence_reg.suffix:
            suffix = ir_sequence_reg.suffix

        use_date_range = None
        if ir_sequence_reg.use_date_range:
            use_date_range = ir_sequence_reg.use_date_range

        cursor.execute('''
            INSERT INTO ''' + table_name + '''(
                id,
                name,
                implementation,
                code,
                active,
                company_id,
                prefix,
                suffix,
                use_date_range,
                padding,
                number_increment,
                number_next,
                postgres_last_value
                )
            VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?)
            ''', (ir_sequence_reg.id,
                  ir_sequence_reg.name,
                  ir_sequence_reg.implementation,
                  ir_sequence_reg.code,
                  ir_sequence_reg.active,
                  ir_sequence_reg.company_id.id,
                  prefix,
                  suffix,
                  use_date_range,
                  ir_sequence_reg.padding,
                  ir_sequence_reg.number_increment,
                  ir_sequence_reg.number_next,
                  postgres_last_value,
                  )
        )

    conn.commit()
    conn.close()

    print()
    print('--> ir_sequence_count: ', ir_sequence_count)

def ir_sequence_import_sqlite(client, args, db_path, table_name, conn_string):

    # ir_sequence_model = client.model('ir.sequence')

    conn = sqlite3.connect(db_path)
    # conn.text_factory = str
    conn.row_factory = sqlite3.Row

    cursor = conn.cursor()

    data = cursor.execute('''
        SELECT
            id,
            name,
            implementation,
            code,
            active,
            company_id,
            prefix,
            suffix,
            use_date_range,
            padding,
            number_increment,
            number_next,
            postgres_last_value,
            new_id
        FROM ''' + table_name + ''';
    ''')

    print(data)
    print([field[0] for field in cursor.description])

    pg_conn = psycopg2.connect(conn_string)
    pg_cursor = pg_conn.cursor()

    ir_sequence_count = 0
    for row in cursor:
        ir_sequence_count += 1

        print(
            ir_sequence_count, row['id'], row['name'], row['implementation'], row['code'],
            row['prefix'], row['padding'], row['number_increment'], row['number_next'], row['postgres_last_value']
        )

        query = "SELECT last_value, increment_by, is_called FROM ir_sequence_%03d" % row['id']
        pg_cursor.execute(query)
        row2 = pg_cursor.fetchone()
        postgres_last_value = row2[0]

        my_table = row['code'][:-5].replace('.', '_')
        query2 = "SELECT MAX(id) FROM %s;" % my_table
        pg_cursor.execute(query2)
        row3 = pg_cursor.fetchone()
        max_id = row3[0]

        print('>>>>>', my_table, row['postgres_last_value'], postgres_last_value, max_id)

        if postgres_last_value < max_id:
            if row['postgres_last_value'] > max_id:
                query3 = "SELECT setval('ir_sequence_%03d', %d);" % (row['id'], row['postgres_last_value'])
                print('>>>>>>>>>>>>>>>', query3)
                pg_cursor.execute(query3)
                row4 = pg_cursor.fetchone()
                print('>>>>>>>>>>>>>>>', row4[0])
            else:
                query3 = "SELECT setval('ir_sequence_%03d', %d);" % (row['id'], max_id)
                print('>>>>>>>>>>>>>>>', query3)
                pg_cursor.execute(query3)
                row4 = pg_cursor.fetchone()
                print('>>>>>>>>>>>>>>>', row4[0])

    conn.commit()
    conn.close()

    print()
    print('--> ir_sequence_count: ', ir_sequence_count)

def ir_sequence_import_sqlite_named(client, args, db_path, table_name, conn_string, input_code, output_code):

    # ir_sequence_model = client.model('ir.sequence')

    conn = sqlite3.connect(db_path)
    # conn.text_factory = str
    conn.row_factory = sqlite3.Row

    cursor = conn.cursor()

    data = cursor.execute('''
        SELECT
            id,
            name,
            implementation,
            code,
            active,
            company_id,
            prefix,
            suffix,
            use_date_range,
            padding,
            number_increment,
            number_next,
            postgres_last_value,
            new_id
        FROM ''' + table_name + ''';
    ''')

    print(data)
    print([field[0] for field in cursor.description])

    pg_conn = psycopg2.connect(conn_string)
    pg_cursor = pg_conn.cursor()

    ir_sequence_model = client.model('ir.sequence')

    ir_sequence_count = 0
    for row in cursor:
        ir_sequence_count += 1

        if input_code == row['code']:

            print(
                ir_sequence_count, row['id'], row['name'], row['implementation'], row['code'],
                row['prefix'], row['padding'], row['number_increment'], row['number_next'], row['postgres_last_value']
            )

            ir_sequence_browse = ir_sequence_model.browse(args)

            ir_sequence_count = 0
            for ir_sequence_reg in ir_sequence_browse:
                ir_sequence_count += 1

                if ir_sequence_reg.code == output_code:

                    query = "SELECT last_value, increment_by, is_called FROM ir_sequence_%03d" % ir_sequence_reg.id
                    pg_cursor.execute(query)
                    row5 = pg_cursor.fetchone()
                    postgres_last_value = row5[0]

                    print(
                        ir_sequence_count, ir_sequence_reg.id, ir_sequence_reg.name.encode("utf-8"),
                        ir_sequence_reg.code,
                        postgres_last_value,
                    )

                    my_table = ir_sequence_reg.code[:-5].replace('.', '_')
                    query2 = "SELECT MAX(id) FROM %s;" % my_table
                    pg_cursor.execute(query2)
                    row3 = pg_cursor.fetchone()
                    max_id = row3[0]

                    print('>>>>>', my_table, row['postgres_last_value'], postgres_last_value, max_id,
                          ir_sequence_reg.number_next_actual)

                    if postgres_last_value < max_id:
                        if row['postgres_last_value'] > max_id:
                            query3 = "SELECT setval('ir_sequence_%03d', %d);" % \
                                (ir_sequence_reg.id, row['postgres_last_value'])
                            print('>>>>>>>>>>>>>>>', query3)
                            pg_cursor.execute(query3)
                            row4 = pg_cursor.fetchone()
                            print('>>>>>>>>>>>>>>>', row4[0])
                        else:
                            query3 = "SELECT setval('ir_sequence_%03d', %d);" % (ir_sequence_reg.id, max_id)
                            print('>>>>>>>>>>>>>>>', query3)
                            pg_cursor.execute(query3)
                            row4 = pg_cursor.fetchone()
                            print('>>>>>>>>>>>>>>>', row4[0])
                    else:
                        query3 = "SELECT setval('ir_sequence_%03d', %d);" % (ir_sequence_reg.id, postgres_last_value)
                        print('>>>>>>>>>>>>>>>', query3)
                        pg_cursor.execute(query3)
                        row4 = pg_cursor.fetchone()
                        print('>>>>>>>>>>>>>>>', row4[0])

    conn.commit()
    conn.close()

    print()
    print('--> ir_sequence_count: ', ir_sequence_count)

def ir_sequence_import_sqlite_named_10(client, args, db_path, table_name, conn_string, input_code, output_code):

    conn = sqlite3.connect(db_path)
    conn.row_factory = sqlite3.Row

    cursor = conn.cursor()

    data = cursor.execute('''
        SELECT
            id,
            name,
            implementation,
            code,
            active,
            company_id,
            prefix,
            suffix,
            use_date_range,
            padding,
            number_increment,
            number_next,
            postgres_last_value,
            new_id
        FROM ''' + table_name + ''';
    ''')

    print(data)
    print([field[0] for field in cursor.description])

    pg_conn = psycopg2.connect(conn_string)
    pg_cursor = pg_conn.cursor()

    ir_sequence_model = client.model('ir.sequence')

    ir_sequence_count = 0
    for row in cursor:
        ir_sequence_count += 1

        if input_code == row['code']:

            print(
                ir_sequence_count, row['id'], row['name'], row['implementation'], row['code'],
                row['prefix'], row['padding'], row['number_increment'], row['number_next'], row['postgres_last_value']
            )

            ir_sequence_browse = ir_sequence_model.browse(args)

            ir_sequence_count = 0
            for ir_sequence_reg in ir_sequence_browse:
                ir_sequence_count += 1

                if ir_sequence_reg.code == output_code:

                    query = "SELECT last_value, increment_by, is_called FROM ir_sequence_%03d" % ir_sequence_reg.id
                    pg_cursor.execute(query)
                    row5 = pg_cursor.fetchone()
                    postgres_last_value = row5[0]

                    print(
                        ir_sequence_count, ir_sequence_reg.id, ir_sequence_reg.name.encode("utf-8"),
                        ir_sequence_reg.code,
                        postgres_last_value,
                    )

                    my_table = ir_sequence_reg.code[:-5].replace('.', '_')
                    query2 = "SELECT MAX(id) FROM %s;" % my_table
                    pg_cursor.execute(query2)
                    row3 = pg_cursor.fetchone()
                    max_id = row3[0]

                    print('>>>>>', my_table, row['postgres_last_value'], postgres_last_value, max_id,
                          ir_sequence_reg.number_next_actual)

                    if postgres_last_value < max_id:
                        if row['postgres_last_value'] > max_id:
                            query3 = "SELECT setval('ir_sequence_%03d', %d);" % \
                                (ir_sequence_reg.id, row['postgres_last_value'])
                            print('>>>>>>>>>>>>>>>', query3)
                            pg_cursor.execute(query3)
                            row4 = pg_cursor.fetchone()
                            print('>>>>>>>>>>>>>>>', row4[0])
                        else:
                            query3 = "SELECT setval('ir_sequence_%03d', %d);" % (ir_sequence_reg.id, max_id)
                            print('>>>>>>>>>>>>>>>', query3)
                            pg_cursor.execute(query3)
                            row4 = pg_cursor.fetchone()
                            print('>>>>>>>>>>>>>>>', row4[0])
                    else:
                        query3 = "SELECT setval('ir_sequence_%03d', %d);" % (ir_sequence_reg.id, postgres_last_value)
                        print('>>>>>>>>>>>>>>>', query3)
                        pg_cursor.execute(query3)
                        row4 = pg_cursor.fetchone()
                        print('>>>>>>>>>>>>>>>', row4[0])

    conn.commit()
    conn.close()

    print()
    print('--> ir_sequence_count: ', ir_sequence_count)
<|endoftext|>


<commit_before>import json

from django.test import TestCase
from django.test.utils import override_settings
from django.core.urlresolvers import reverse

from lazy_tags.templatetags import lazy_tags

class LazyTagsViewTests(TestCase):

    def test_tag_with_no_args_or_kwargs(self):
        url = reverse('lazy_tag')

        response = self.client.get(url, {'tag': 'test_tags.test'})

        self.assertEqual(str(response.content), '
hello world
')

    def test_tag_with_just_args(self):
        url = reverse('lazy_tag')
        data = {
            'tag': 'test_tags.test_with_args',
            'args': json.dumps(['hello']),
        }

        response = self.client.get(url, data)

        expected_html = '
hello
'
        self.assertHTMLEqual(str(response.content), expected_html)

    def test_tag_with_args_and_kwargs(self):
        url = reverse('lazy_tag')
        data = {
            'tag': 'test_tags.test_with_args',
            'args': json.dumps(['hello']),
            'kwargs': json.dumps({'kwarg': 'world'}),
        }

        response = self.client.get(url, data)

        expected_html = '
hello world
'
        self.assertHTMLEqual(str(response.content), expected_html)

    def test_inclusion_tag(self):
        url = reverse('lazy_tag')

        response = self.client.get(url, {'tag': 'test_tags.inclusion'})

        expected_html = '
hello world
'
        self.assertHTMLEqual(str(response.content), expected_html)

class LazyTagsTests(TestCase):

    def setUp(self):
        self.context = {
            'lazy_tag_data': {
                'tag': 'test_tags.tag',
                'args': json.dumps([]),
                'kwargs': json.dumps({}),
            },
        }

    def test_default_error_message(self):
        html = lazy_tags.lazy_tags_js(self.context)

        self.assertIn('An error occurred.', html)

    @override_settings(LAZY_TAGS_ERROR_MESSAGE='
Custom error message!
')
    def test_custom_error_message(self):
        html = lazy_tags.lazy_tags_js(self.context)

        self.assertIn('
Custom error message!
', html)
<commit_msg>Python 3 compat<commit_after>import json

from django.test import TestCase
from django.test.utils import override_settings
from django.core.urlresolvers import reverse

from lazy_tags.templatetags import lazy_tags

class LazyTagsViewTests(TestCase):

    def test_tag_with_no_args_or_kwargs(self):
        url = reverse('lazy_tag')

        response = self.client.get(url, {'tag': 'test_tags.test'})

        self.assertEqual(response.content.decode(), '
hello world
')

    def test_tag_with_just_args(self):
        url = reverse('lazy_tag')
        data = {
            'tag': 'test_tags.test_with_args',
            'args': json.dumps(['hello']),
        }

        response = self.client.get(url, data)

        self.assertHTMLEqual(response.content.decode(), '
hello
')

    def test_tag_with_args_and_kwargs(self):
        url = reverse('lazy_tag')
        data = {
            'tag': 'test_tags.test_with_args',
            'args': json.dumps(['hello']),
            'kwargs': json.dumps({'kwarg': 'world'}),
        }

        response = self.client.get(url, data)

        self.assertHTMLEqual(response.content.decode(), '
hello world
')

    def test_inclusion_tag(self):
        url = reverse('lazy_tag')

        response = self.client.get(url, {'tag': 'test_tags.inclusion'})

        self.assertHTMLEqual(response.content.decode(), '
hello world
')

class LazyTagsTests(TestCase):

    def setUp(self):
        self.context = {
            'lazy_tag_data': {
                'tag': 'test_tags.tag',
                'args': json.dumps([]),
                'kwargs': json.dumps({}),
            },
        }

    def test_default_error_message(self):
        html = lazy_tags.lazy_tags_js(self.context)

        self.assertIn('An error occurred.', html)

    @override_settings(LAZY_TAGS_ERROR_MESSAGE='
Custom error message!
')
    def test_custom_error_message(self):
        html = lazy_tags.lazy_tags_js(self.context)

        self.assertIn('
Custom error message!
', html)
<|endoftext|>


<commit_before>"""
Management command to send program reminder emails.
"""

import logging

from textwrap import dedent
from datetime import datetime, timedelta

from django.conf import settings
from django.core.management import BaseCommand
from django.contrib.auth.models import User  # lint-amnesty, pylint: disable=imported-auth-user

from lms.djangoapps.save_for_later.helper import send_email
from lms.djangoapps.save_for_later.models import SavedProgram
from lms.djangoapps.program_enrollments.api import get_program_enrollment
from openedx.core.djangoapps.catalog.utils import get_programs
from common.djangoapps.util.query import use_read_replica_if_available

LOGGER = logging.getLogger(__name__)

USER_SEND_SAVE_FOR_LATER_REMINDER_EMAIL = 'user.send.save.for.later.reminder.email'

class Command(BaseCommand):
    """
    Command to send reminder emails to those users who saved
    program by email but not enroll program within 15 days.

    Examples:

        ./manage.py lms send_program_reminder_emails --batch-size=100
    """
    help = dedent(__doc__)

    def add_arguments(self, parser):
        parser.add_argument(
            '--batch-size',
            type=int,
            default=1000,
            help='Maximum number of users to send reminder email in one chunk')

    def handle(self, *args, **options):
        """
        Handle the send save for later reminder emails.
        """
        reminder_email_threshold_date = datetime.now() - timedelta(
            days=settings.SAVE_FOR_LATER_REMINDER_EMAIL_THRESHOLD)
        saved_program_ids = SavedProgram.objects.filter(
            reminder_email_sent=False, modified__lt=reminder_email_threshold_date
        ).values_list('id', flat=True)
        total = saved_program_ids.count()
        batch_size = max(1, options.get('batch_size'))
        num_batches = ((total - 1) / batch_size + 1) if total > 0 else 0

        for batch_num in range(int(num_batches)):
            reminder_email_sent_ids = []
            start = batch_num * batch_size
            end = min(start + batch_size, total) - 1
            saved_program_batch_ids = list(saved_program_ids)[start:end + 1]

            query = SavedProgram.objects.filter(id__in=saved_program_batch_ids).order_by('-modified')
            saved_programs = use_read_replica_if_available(query)
            for saved_program in saved_programs:
                user = User.objects.filter(email=saved_program.email).first()
                program = get_programs(uuid=saved_program.program_uuid)
                if program:
                    program_data = {
                        'program': program,
                        'send_to_self': None,
                        'user_id': saved_program.user_id,
                        'type': 'program',
                        'reminder': True,
                        'braze_event': USER_SEND_SAVE_FOR_LATER_REMINDER_EMAIL,
                    }
                    if user and get_program_enrollment(program_uuid=saved_program.program_uuid, user=user):
                        continue
                    email_sent = send_email(saved_program.email, program_data)
                    if email_sent:
                        reminder_email_sent_ids.append(saved_program.id)
                    else:
                        logging.info("Unable to send reminder email to {user} for {program} program"
                                     .format(user=str(saved_program.email), program=str(saved_program.program_uuid)))
            SavedProgram.objects.filter(id__in=reminder_email_sent_ids).update(reminder_email_sent=True)
<commit_msg>fix: handle ObjectDoesNotExist exception (#30378)<commit_after>"""
Management command to send program reminder emails.
"""

import logging

from textwrap import dedent
from datetime import datetime, timedelta

from django.conf import settings
from django.core.management import BaseCommand
from django.core.exceptions import ObjectDoesNotExist
from django.contrib.auth.models import User  # lint-amnesty, pylint: disable=imported-auth-user

from lms.djangoapps.save_for_later.helper import send_email
from lms.djangoapps.save_for_later.models import SavedProgram
from lms.djangoapps.program_enrollments.api import get_program_enrollment
from openedx.core.djangoapps.catalog.utils import get_programs
from common.djangoapps.util.query import use_read_replica_if_available

LOGGER = logging.getLogger(__name__)

USER_SEND_SAVE_FOR_LATER_REMINDER_EMAIL = 'user.send.save.for.later.reminder.email'

class Command(BaseCommand):
    """
    Command to send reminder emails to those users who saved
    program by email but not enroll program within 15 days.

    Examples:

        ./manage.py lms send_program_reminder_emails --batch-size=100
    """
    help = dedent(__doc__)

    def add_arguments(self, parser):
        parser.add_argument(
            '--batch-size',
            type=int,
            default=1000,
            help='Maximum number of users to send reminder email in one chunk')

    def handle(self, *args, **options):
        """
        Handle the send save for later reminder emails.
        """
        reminder_email_threshold_date = datetime.now() - timedelta(
            days=settings.SAVE_FOR_LATER_REMINDER_EMAIL_THRESHOLD)
        saved_program_ids = SavedProgram.objects.filter(
            reminder_email_sent=False, modified__lt=reminder_email_threshold_date
        ).values_list('id', flat=True)
        total = saved_program_ids.count()
        batch_size = max(1, options.get('batch_size'))
        num_batches = ((total - 1) / batch_size + 1) if total > 0 else 0

        for batch_num in range(int(num_batches)):
            reminder_email_sent_ids = []
            start = batch_num * batch_size
            end = min(start + batch_size, total) - 1
            saved_program_batch_ids = list(saved_program_ids)[start:end + 1]

            query = SavedProgram.objects.filter(id__in=saved_program_batch_ids).order_by('-modified')
            saved_programs = use_read_replica_if_available(query)
            for saved_program in saved_programs:
                user = User.objects.filter(email=saved_program.email).first()
                program = get_programs(uuid=saved_program.program_uuid)
                if program:
                    program_data = {
                        'program': program,
                        'send_to_self': None,
                        'user_id': saved_program.user_id,
                        'type': 'program',
                        'reminder': True,
                        'braze_event': USER_SEND_SAVE_FOR_LATER_REMINDER_EMAIL,
                    }
                    try:
                        if user and get_program_enrollment(program_uuid=saved_program.program_uuid, user=user):
                            continue
                    except ObjectDoesNotExist:
                        pass
                    email_sent = send_email(saved_program.email, program_data)
                    if email_sent:
                        reminder_email_sent_ids.append(saved_program.id)
                    else:
                        logging.info("Unable to send reminder email to {user} for {program} program"
                                     .format(user=str(saved_program.email), program=str(saved_program.program_uuid)))
            SavedProgram.objects.filter(id__in=reminder_email_sent_ids).update(reminder_email_sent=True)
<|endoftext|>


<commit_before>from unittest import skip

from django.template import Context
from django.test import override_settings, TestCase
from django.utils import six

from render_block import render_block_to_string, BlockNotFound, UnsupportedEngine

class TestDjango(TestCase):
    """Test the Django templating engine."""
    def assertExceptionMessageEquals(self, exception, expected):
        result = exception.message if six.PY2 else exception.args[0]
        self.assertEqual(expected, result)

    def test_block(self):
        """Test rendering an individual block."""
        result = render_block_to_string('test1.html', 'block1')
        self.assertEqual(result, u'block1 from test1')

        # No reason this shouldn't work, but just in case.
        result = render_block_to_string('test1.html', 'block2')
        self.assertEqual(result, u'block2 from test1')

    def test_override(self):
        """This block is overridden in test2."""
        result = render_block_to_string('test2.html', 'block1')
        self.assertEqual(result, u'block1 from test2')

    def test_inherit(self):
        """This block is inherited from test1."""
        result = render_block_to_string('test2.html', 'block2')
        self.assertEqual(result, u'block2 from test1')

    def test_inherit2(self):
        """This block is inherited from test1."""
        result = render_block_to_string('test_sub.html', 'base')
        self.assertEqual(result, u'bar')

    def test_no_block(self):
        """Check if there's no block available an exception is raised."""
        with self.assertRaises(BlockNotFound) as exc:
            render_block_to_string('test1.html', 'noblock')
        self.assertExceptionMessageEquals(exc.exception,
                                          "block with name 'noblock' does not exist")

    def test_include(self):
        """Ensure that an include tag in a block still works."""
        result = render_block_to_string('test3_django.html', 'block1')
        self.assertEqual(result, u'included template')

    def test_super(self):
        """Test that block.super works."""
        result = render_block_to_string('test3_django.html', 'block2')
        self.assertEqual(result, u'block2 from test3 - block2 from test1')

    def test_subblock(self):
        """Test that a block within a block works."""
        result = render_block_to_string('test5.html', 'block1')
        self.assertEqual(result, u'block3 from test5')

        result = render_block_to_string('test5.html', 'block3')
        self.assertEqual(result, u'block3 from test5')

    def test_context(self):
        """Test that a context is properly rendered in a template."""
        data = u'block2 from test5'
        result = render_block_to_string('test5.html', 'block2', {'foo': data})
        self.assertEqual(result, data)

    @override_settings(
        TEMPLATES=[{
            'BACKEND': 'django.template.backends.dummy.TemplateStrings',
            'DIRS': ['tests/templates'],
            'APP_DIRS': True,
        },]
    )
    def test_different_backend(self):
        """
        Ensure an exception is thrown if a different backed from the Django
        backend is used.
        """
        with self.assertRaises(UnsupportedEngine) as exc:
            render_block_to_string('test1.html', 'noblock')
        self.assertExceptionMessageEquals(exc.exception,
                                          "Can only render blocks from the Django template backend.")

@override_settings(
    TEMPLATES=[{
        'BACKEND': 'django.template.backends.jinja2.Jinja2',
        'DIRS': ['tests/templates'],
        'APP_DIRS': True,
    },]
)
class TestJinja2(TestCase):
    """Test the Django templating engine."""
    def assertExceptionMessageEquals(self, exception, expected):
        result = exception.message if six.PY2 else exception.args[0]
        self.assertEqual(expected, result)

    def test_block(self):
        """Test rendering an individual block."""
        result = render_block_to_string('test1.html', 'block1')
        self.assertEqual(result, u'block1 from test1')

        # No reason this shouldn't work, but just in case.
        result = render_block_to_string('test1.html', 'block2')
        self.assertEqual(result, u'block2 from test1')

    def test_override(self):
        """This block is overridden in test2."""
        result = render_block_to_string('test2.html', 'block1')
        self.assertEqual(result, u'block1 from test2')

    @skip('Not currently supported.')
    def test_inherit(self):
        """This block is inherited from test1."""
        result = render_block_to_string('test2.html', 'block2')
        self.assertEqual(result, u'block2 from test1')

    def test_no_block(self):
        """Check if there's no block available an exception is raised."""
        with self.assertRaises(BlockNotFound) as exc:
            render_block_to_string('test1.html', 'noblock')
        self.assertExceptionMessageEquals(exc.exception,
                                          "block with name 'noblock' does not exist")

    def test_include(self):
        """Ensure that an include tag in a block still works."""
        result = render_block_to_string('test3_jinja2.html', 'block1')
        self.assertEqual(result, u'included template')

    @skip('Not currently supported.')
    def test_super(self):
        """Test that super() works."""
        result = render_block_to_string('test3_jinja2.html', 'block2')
        self.assertEqual(result, u'block2 from test3 - block2 from test1')

    def test_subblock(self):
        """Test that a block within a block works."""
        result = render_block_to_string('test5.html', 'block1')
        self.assertEqual(result, u'block3 from test5')

        result = render_block_to_string('test5.html', 'block3')
        self.assertEqual(result, u'block3 from test5')

    def test_context(self):
        """Test that a context is properly rendered in a template."""
        data = u'block2 from test5'
        result = render_block_to_string('test5.html', 'block2', {'foo': data})
        self.assertEqual(result, data)
<commit_msg>Rework test, add some comments.<commit_after>from unittest import skip

from django.template import Context
from django.test import override_settings, TestCase
from django.utils import six

from render_block import render_block_to_string, BlockNotFound, UnsupportedEngine

class TestDjango(TestCase):
    """Test the Django templating engine."""
    def assertExceptionMessageEquals(self, exception, expected):
        result = exception.message if six.PY2 else exception.args[0]
        self.assertEqual(expected, result)

    def test_block(self):
        """Test rendering an individual block."""
        result = render_block_to_string('test1.html', 'block1')
        self.assertEqual(result, u'block1 from test1')

        # No reason this shouldn't work, but just in case.
        result = render_block_to_string('test1.html', 'block2')
        self.assertEqual(result, u'block2 from test1')

    def test_override(self):
        """This block is overridden in test2."""
        result = render_block_to_string('test2.html', 'block1')
        self.assertEqual(result, u'block1 from test2')

    def test_inherit(self):
        """This block is inherited from test1."""
        result = render_block_to_string('test2.html', 'block2')
        self.assertEqual(result, u'block2 from test1')

    def test_no_block(self):
        """Check if there's no block available an exception is raised."""
        with self.assertRaises(BlockNotFound) as exc:
            render_block_to_string('test1.html', 'noblock')
        self.assertExceptionMessageEquals(exc.exception,
                                          "block with name 'noblock' does not exist")

    def test_include(self):
        """Ensure that an include tag in a block still works."""
        result = render_block_to_string('test3_django.html', 'block1')
        self.assertEqual(result, u'included template')

    def test_super(self):
        """Test that block.super works."""
        result = render_block_to_string('test3_django.html', 'block2')
        self.assertEqual(result, u'block2 from test3 - block2 from test1')

    def test_subblock(self):
        """Test that a block within a block works."""
        result = render_block_to_string('test5.html', 'block1')
        self.assertEqual(result, u'block3 from test5')

        result = render_block_to_string('test5.html', 'block3')
        self.assertEqual(result, u'block3 from test5')

    def test_subblock_no_parent(self):
        """
        Test that a block within a block works if the parent block is only found
        in the base template.

        This is very similar to test_subblock, but the templates differ. In this
        test the sub-template does not replace the entire block from the parent
        template.
        """
        result = render_block_to_string('test_sub.html', 'base')
        self.assertEqual(result, u'\n\nbar\n\n')

        result = render_block_to_string('test_sub.html', 'first')
        self.assertEqual(result, u'\nbar\n')

    def test_context(self):
        """Test that a context is properly rendered in a template."""
        data = u'block2 from test5'
        result = render_block_to_string('test5.html', 'block2', {'foo': data})
        self.assertEqual(result, data)

    @override_settings(
        TEMPLATES=[{
            'BACKEND': 'django.template.backends.dummy.TemplateStrings',
            'DIRS': ['tests/templates'],
            'APP_DIRS': True,
        },]
    )
    def test_different_backend(self):
        """
        Ensure an exception is thrown if a different backed from the Django
        backend is used.
        """
        with self.assertRaises(UnsupportedEngine) as exc:
            render_block_to_string('test1.html', 'noblock')
        self.assertExceptionMessageEquals(exc.exception,
                                          "Can only render blocks from the Django template backend.")

@override_settings(
    TEMPLATES=[{
        'BACKEND': 'django.template.backends.jinja2.Jinja2',
        'DIRS': ['tests/templates'],
        'APP_DIRS': True,
    },]
)
class TestJinja2(TestCase):
    """Test the Django templating engine."""
    def assertExceptionMessageEquals(self, exception, expected):
        result = exception.message if six.PY2 else exception.args[0]
        self.assertEqual(expected, result)

    def test_block(self):
        """Test rendering an individual block."""
        result = render_block_to_string('test1.html', 'block1')
        self.assertEqual(result, u'block1 from test1')

        # No reason this shouldn't work, but just in case.
        result = render_block_to_string('test1.html', 'block2')
        self.assertEqual(result, u'block2 from test1')

    def test_override(self):
        """This block is overridden in test2."""
        result = render_block_to_string('test2.html', 'block1')
        self.assertEqual(result, u'block1 from test2')

    @skip('Not currently supported.')
    def test_inherit(self):
        """This block is inherited from test1."""
        result = render_block_to_string('test2.html', 'block2')
        self.assertEqual(result, u'block2 from test1')

    def test_no_block(self):
        """Check if there's no block available an exception is raised."""
        with self.assertRaises(BlockNotFound) as exc:
            render_block_to_string('test1.html', 'noblock')
        self.assertExceptionMessageEquals(exc.exception,
                                          "block with name 'noblock' does not exist")

    def test_include(self):
        """Ensure that an include tag in a block still works."""
        result = render_block_to_string('test3_jinja2.html', 'block1')
        self.assertEqual(result, u'included template')

    @skip('Not currently supported.')
    def test_super(self):
        """Test that super() works."""
        result = render_block_to_string('test3_jinja2.html', 'block2')
        self.assertEqual(result, u'block2 from test3 - block2 from test1')

    def test_subblock(self):
        """Test that a block within a block works."""
        result = render_block_to_string('test5.html', 'block1')
        self.assertEqual(result, u'block3 from test5')

        result = render_block_to_string('test5.html', 'block3')
        self.assertEqual(result, u'block3 from test5')

    def test_context(self):
        """Test that a context is properly rendered in a template."""
        data = u'block2 from test5'
        result = render_block_to_string('test5.html', 'block2', {'foo': data})
        self.assertEqual(result, data)
<|endoftext|>