def production_envelope(model, reactions, objective=None, carbon_sources=None,<EOL>points=<NUM_LIT:20>, threshold=None):

reactions = model.reactions.get_by_any(reactions)<EOL>objective = model.solver.objective if objective is None else objective<EOL>data = dict()<EOL>if carbon_sources is None:<EOL><INDENT>c_input = find_carbon_sources(model)<EOL><DEDENT>else:<EOL><INDENT>c_input = model.reactions.get_by_any(carbon_sources)<EOL><DEDENT>if c_input is None:<EOL><INDENT>data['<STR_LIT>'] = None<EOL><DEDENT>elif hasattr(c_input, '<STR_LIT:id>'):<EOL><INDENT>data['<STR_LIT>'] = c_input.id<EOL><DEDENT>else:<EOL><INDENT>data['<STR_LIT>'] = '<STR_LIT:U+002CU+0020>'.join(rxn.id for rxn in c_input)<EOL><DEDENT>threshold = normalize_cutoff(model, threshold)<EOL>size = points ** len(reactions)<EOL>for direction in ('<STR_LIT>', '<STR_LIT>'):<EOL><INDENT>data['<STR_LIT>'.format(direction)] = full(size, nan, dtype=float)<EOL>data['<STR_LIT>'.format(direction)] = full(<EOL>size, nan, dtype=float)<EOL>data['<STR_LIT>'.format(direction)] = full(<EOL>size, nan, dtype=float)<EOL><DEDENT>grid = pd.DataFrame(data)<EOL>with model:<EOL><INDENT>model.objective = objective<EOL>objective_reactions = list(sutil.linear_reaction_coefficients(model))<EOL>if len(objective_reactions) != <NUM_LIT:1>:<EOL><INDENT>raise ValueError('<STR_LIT>'<EOL>'<STR_LIT>')<EOL><DEDENT>c_output = objective_reactions[<NUM_LIT:0>]<EOL>min_max = fva(model, reactions, fraction_of_optimum=<NUM_LIT:0>)<EOL>min_max[min_max.abs() < threshold] = <NUM_LIT:0.0><EOL>points = list(product(*[<EOL>linspace(min_max.at[rxn.id, "<STR_LIT>"],<EOL>min_max.at[rxn.id, "<STR_LIT>"],<EOL>points, endpoint=True) for rxn in reactions]))<EOL>tmp = pd.DataFrame(points, columns=[rxn.id for rxn in reactions])<EOL>grid = pd.concat([grid, tmp], axis=<NUM_LIT:1>, copy=False)<EOL>add_envelope(model, reactions, grid, c_input, c_output, threshold)<EOL><DEDENT>return grid<EOL>

Calculate the objective value conditioned on all combinations of
    fluxes for a set of chosen reactions

    The production envelope can be used to analyze a model's ability to
    produce a given compound conditional on the fluxes for another set of
    reactions, such as the uptake rates. The model is alternately optimized
    with respect to minimizing and maximizing the objective and the
    obtained fluxes are recorded. Ranges to compute production is set to the
    effective
    bounds, i.e., the minimum / maximum fluxes that can be obtained given
    current reaction bounds.

    Parameters
    ----------
    model : cobra.Model
        The model to compute the production envelope for.
    reactions : list or string
        A list of reactions, reaction identifiers or a single reaction.
    objective : string, dict, model.solver.interface.Objective, optional
        The objective (reaction) to use for the production envelope. Use the
        model's current objective if left missing.
    carbon_sources : list or string, optional
       One or more reactions or reaction identifiers that are the source of
       carbon for computing carbon (mol carbon in output over mol carbon in
       input) and mass yield (gram product over gram output). Only objectives
       with a carbon containing input and output metabolite is supported.
       Will identify active carbon sources in the medium if none are specified.
    points : int, optional
       The number of points to calculate production for.
    threshold : float, optional
        A cut-off under which flux values will be considered to be zero
        (default model.tolerance).

    Returns
    -------
    pandas.DataFrame
        A data frame with one row per evaluated point and

        - reaction id : one column per input reaction indicating the flux at
          each given point,
        - carbon_source: identifiers of carbon exchange reactions

        A column for the maximum and minimum each for the following types:

        - flux: the objective flux
        - carbon_yield: if carbon source is defined and the product is a
          single metabolite (mol carbon product per mol carbon feeding source)
        - mass_yield: if carbon source is defined and the product is a
          single metabolite (gram product per 1 g of feeding source)

    Examples
    --------
    >>> import cobra.test
    >>> from cobra.flux_analysis import production_envelope
    >>> model = cobra.test.create_test_model("textbook")
    >>> production_envelope(model, ["EX_glc__D_e", "EX_o2_e"])


if len(reaction.metabolites) != <NUM_LIT:1>:<EOL><INDENT>raise ValueError('<STR_LIT>'<EOL>'<STR_LIT>')<EOL><DEDENT>met, coeff = next(iteritems(reaction.metabolites))<EOL>return [coeff * met.formula_weight]<EOL>

Return the metabolite weight times its stoichiometric coefficient.


def assess(model, reaction, flux_coefficient_cutoff=<NUM_LIT>, solver=None):

reaction = model.reactions.get_by_any(reaction)[<NUM_LIT:0>]<EOL>with model as m:<EOL><INDENT>m.objective = reaction<EOL>if _optimize_or_value(m, solver=solver) >= flux_coefficient_cutoff:<EOL><INDENT>return True<EOL><DEDENT>else:<EOL><INDENT>results = dict()<EOL>results['<STR_LIT>'] = assess_component(<EOL>model, reaction, '<STR_LIT>', flux_coefficient_cutoff)<EOL>results['<STR_LIT>'] = assess_component(<EOL>model, reaction, '<STR_LIT>', flux_coefficient_cutoff)<EOL>return results<EOL><DEDENT><DEDENT>

Assesses production capacity.

    Assesses the capacity of the model to produce the precursors for the
    reaction and absorb the production of the reaction while the reaction is
    operating at, or above, the specified cutoff.

    Parameters
    ----------
    model : cobra.Model
        The cobra model to assess production capacity for

    reaction : reaction identifier or cobra.Reaction
        The reaction to assess

    flux_coefficient_cutoff :  float
        The minimum flux that reaction must carry to be considered active.

    solver : basestring
        Solver name. If None, the default solver will be used.

    Returns
    -------
    bool or dict
        True if the model can produce the precursors and absorb the products
        for the reaction operating at, or above, flux_coefficient_cutoff.
        Otherwise, a dictionary of {'precursor': Status, 'product': Status}.
        Where Status is the results from assess_precursors and
        assess_products, respectively.


def geometric_fba(model, epsilon=<NUM_LIT>, max_tries=<NUM_LIT:200>, processes=None):

with model:<EOL><INDENT>consts = []<EOL>obj_vars = []<EOL>updating_vars_cons = []<EOL>prob = model.problem<EOL>add_pfba(model)  <EOL>model.optimize()<EOL>fva_sol = flux_variability_analysis(model, processes=processes)<EOL>mean_flux = (fva_sol["<STR_LIT>"] + fva_sol["<STR_LIT>"]).abs() / <NUM_LIT:2><EOL>for rxn in model.reactions:<EOL><INDENT>var = prob.Variable("<STR_LIT>" + rxn.id,<EOL>lb=<NUM_LIT:0>,<EOL>ub=mean_flux[rxn.id])<EOL>upper_const = prob.Constraint(rxn.flux_expression - var,<EOL>ub=mean_flux[rxn.id],<EOL>name="<STR_LIT>" +<EOL>rxn.id)<EOL>lower_const = prob.Constraint(rxn.flux_expression + var,<EOL>lb=fva_sol.at[rxn.id, "<STR_LIT>"],<EOL>name="<STR_LIT>" +<EOL>rxn.id)<EOL>updating_vars_cons.append((rxn.id, var, upper_const, lower_const))<EOL>consts.extend([var, upper_const, lower_const])<EOL>obj_vars.append(var)<EOL><DEDENT>model.add_cons_vars(consts)<EOL>model.objective = prob.Objective(Zero, sloppy=True, direction="<STR_LIT>")<EOL>model.objective.set_linear_coefficients({v: <NUM_LIT:1.0> for v in obj_vars})<EOL>sol = model.optimize()<EOL>fva_sol = flux_variability_analysis(model, processes=processes)<EOL>mean_flux = (fva_sol["<STR_LIT>"] + fva_sol["<STR_LIT>"]).abs() / <NUM_LIT:2><EOL>delta = (fva_sol["<STR_LIT>"] - fva_sol["<STR_LIT>"]).max()<EOL>count = <NUM_LIT:1><EOL>LOGGER.debug("<STR_LIT>",<EOL>count, delta, sol.status)<EOL>while delta > epsilon and count < max_tries:<EOL><INDENT>for rxn_id, var, u_c, l_c in updating_vars_cons:<EOL><INDENT>var.ub = mean_flux[rxn_id]<EOL>u_c.ub = mean_flux[rxn_id]<EOL>l_c.lb = fva_sol.at[rxn_id, "<STR_LIT>"]<EOL><DEDENT>sol = model.optimize()<EOL>fva_sol = flux_variability_analysis(model, processes=processes)<EOL>mean_flux = (fva_sol["<STR_LIT>"] + fva_sol["<STR_LIT>"]).abs() / <NUM_LIT:2><EOL>delta = (fva_sol["<STR_LIT>"] - fva_sol["<STR_LIT>"]).max()<EOL>count += <NUM_LIT:1><EOL>LOGGER.debug("<STR_LIT>",<EOL>count, delta, sol.status)<EOL><DEDENT>if count == max_tries:<EOL><INDENT>raise RuntimeError(<EOL>"<STR_LIT>"<EOL>"<STR_LIT>"<EOL>"<STR_LIT>"<EOL>"<STR_LIT>"<EOL>"<STR_LIT>".format(max_tries)<EOL>)<EOL><DEDENT><DEDENT>return sol<EOL>

Perform geometric FBA to obtain a unique, centered flux distribution.

Geometric FBA [1]_ formulates the problem as a polyhedron and
then solves it by bounding the convex hull of the polyhedron.
The bounding forms a box around the convex hull which reduces
with every iteration and extracts a unique solution in this way.

Parameters
----------
model: cobra.Model
    The model to perform geometric FBA on.
epsilon: float, optional
    The convergence tolerance of the model (default 1E-06).
max_tries: int, optional
    Maximum number of iterations (default 200).
processes : int, optional
    The number of parallel processes to run. If not explicitly passed,
    will be set from the global configuration singleton.

Returns
-------
cobra.Solution
    The solution object containing all the constraints required
    for geometric FBA.

References
----------
.. [1] Smallbone, Kieran & Simeonidis, Vangelis. (2009).
       Flux balance analysis: A geometric perspective.
       Journal of theoretical biology.258. 311-5.
       10.1016/j.jtbi.2009.01.027.


def _init_worker(model, loopless, sense):

global _model<EOL>global _loopless<EOL>_model = model<EOL>_model.solver.objective.direction = sense<EOL>_loopless = loopless<EOL>

Initialize a global model object for multiprocessing.


zero_cutoff = normalize_cutoff(model, zero_cutoff)<EOL>with model:<EOL><INDENT>if open_exchanges:<EOL><INDENT>for reaction in model.exchanges:<EOL><INDENT>reaction.bounds = (min(reaction.lower_bound, -<NUM_LIT:1000>),<EOL>max(reaction.upper_bound, <NUM_LIT:1000>))<EOL><DEDENT><DEDENT>if reaction_list is None:<EOL><INDENT>reaction_list = model.reactions<EOL><DEDENT>model.slim_optimize()<EOL>solution = get_solution(model, reactions=reaction_list)<EOL>reaction_list = solution.fluxes[<EOL>solution.fluxes.abs() < zero_cutoff].index.tolist()<EOL>flux_span = flux_variability_analysis(<EOL>model, fraction_of_optimum=<NUM_LIT:0.>, reaction_list=reaction_list,<EOL>processes=processes<EOL>)<EOL>return flux_span[<EOL>flux_span.abs().max(axis=<NUM_LIT:1>) < zero_cutoff].index.tolist()<EOL><DEDENT>

Find reactions that cannot carry any flux.

The question whether or not a reaction is blocked is highly dependent
on the current exchange reaction settings for a COBRA model. Hence an
argument is provided to open all exchange reactions.

Notes
-----
Sink and demand reactions are left untouched. Please modify them manually.

Parameters
----------
model : cobra.Model
    The model to analyze.
reaction_list : list, optional
    List of reactions to consider, the default includes all model
    reactions.
zero_cutoff : float, optional
    Flux value which is considered to effectively be zero
    (default model.tolerance).
open_exchanges : bool, optional
    Whether or not to open all exchange reactions to very high flux ranges.
processes : int, optional
    The number of parallel processes to run. Can speed up the computations
    if the number of reactions is large. If not explicitly
    passed, it will be set from the global configuration singleton.

Returns
-------
list
    List with the identifiers of blocked reactions.


def find_essential_genes(model, threshold=None, processes=None):

if threshold is None:<EOL><INDENT>threshold = model.slim_optimize(error_value=None) * <NUM_LIT><EOL><DEDENT>deletions = single_gene_deletion(model, method='<STR_LIT>', processes=processes)<EOL>essential = deletions.loc[deletions['<STR_LIT>'].isna() |<EOL>(deletions['<STR_LIT>'] < threshold), :].index<EOL>return {model.genes.get_by_id(g) for ids in essential for g in ids}<EOL>

Return a set of essential genes.

A gene is considered essential if restricting the flux of all reactions
that depend on it to zero causes the objective, e.g., the growth rate,
to also be zero, below the threshold, or infeasible.

Parameters
----------
model : cobra.Model
    The model to find the essential genes for.
threshold : float, optional
    Minimal objective flux to be considered viable. By default this is
    1% of the maximal objective.
processes : int, optional
    The number of parallel processes to run. If not passed,
    will be set to the number of CPUs found.
processes : int, optional
    The number of parallel processes to run. Can speed up the computations
    if the number of knockouts to perform is large. If not explicitly
    passed, it will be set from the global configuration singleton.

Returns
-------
set
    Set of essential genes


def model_summary(model, solution=None, threshold=<NUM_LIT>, fva=None, names=False,<EOL>floatfmt='<STR_LIT>'):

if names:<EOL><INDENT>emit = attrgetter('<STR_LIT:name>')<EOL><DEDENT>else:<EOL><INDENT>emit = attrgetter('<STR_LIT:id>')<EOL><DEDENT>objective_reactions = linear_reaction_coefficients(model)<EOL>boundary_reactions = model.exchanges<EOL>summary_rxns = set(objective_reactions.keys()).union(boundary_reactions)<EOL>if solution is None:<EOL><INDENT>model.slim_optimize(error_value=None)<EOL>solution = get_solution(model, reactions=summary_rxns)<EOL><DEDENT>obj_fluxes = pd.DataFrame({key: solution[key.id] * value for key,<EOL>value in iteritems(objective_reactions)},<EOL>index=['<STR_LIT>']).T<EOL>obj_fluxes['<STR_LIT:id>'] = obj_fluxes.apply(<EOL>lambda x: format_long_string(x.name.id, <NUM_LIT:15>), <NUM_LIT:1>)<EOL>metabolites = {m for r in boundary_reactions for m in r.metabolites}<EOL>index = sorted(metabolites, key=attrgetter('<STR_LIT:id>'))<EOL>metabolite_fluxes = pd.DataFrame({<EOL>'<STR_LIT:id>': [format_long_string(emit(m), <NUM_LIT:15>) for m in index],<EOL>'<STR_LIT>': zeros(len(index), dtype=float)<EOL>}, index=[m.id for m in index])<EOL>for rxn in boundary_reactions:<EOL><INDENT>for met, stoich in iteritems(rxn.metabolites):<EOL><INDENT>metabolite_fluxes.at[met.id, '<STR_LIT>'] += stoich * solution[rxn.id]<EOL><DEDENT><DEDENT>if fva is not None:<EOL><INDENT>if len(index) != len(boundary_reactions):<EOL><INDENT>LOGGER.warning(<EOL>"<STR_LIT>"<EOL>"<STR_LIT>")<EOL><DEDENT>metabolite_fluxes['<STR_LIT>'] = zeros(len(index), dtype=float)<EOL>metabolite_fluxes['<STR_LIT>'] = zeros(len(index), dtype=float)<EOL>if hasattr(fva, '<STR_LIT>'):<EOL><INDENT>fva_results = fva<EOL><DEDENT>else:<EOL><INDENT>fva_results = flux_variability_analysis(<EOL>model, reaction_list=boundary_reactions,<EOL>fraction_of_optimum=fva)<EOL><DEDENT>for rxn in boundary_reactions:<EOL><INDENT>for met, stoich in iteritems(rxn.metabolites):<EOL><INDENT>fmin = stoich * fva_results.at[rxn.id, '<STR_LIT>']<EOL>fmax = stoich * fva_results.at[rxn.id, '<STR_LIT>']<EOL>if abs(fmin) <= abs(fmax):<EOL><INDENT>metabolite_fluxes.at[met.id, '<STR_LIT>'] += fmin<EOL>metabolite_fluxes.at[met.id, '<STR_LIT>'] += fmax<EOL><DEDENT>else:<EOL><INDENT>metabolite_fluxes.at[met.id, '<STR_LIT>'] += fmax<EOL>metabolite_fluxes.at[met.id, '<STR_LIT>'] += fmin<EOL><DEDENT><DEDENT><DEDENT><DEDENT>metabolite_fluxes = _process_flux_dataframe(<EOL>metabolite_fluxes, fva, threshold, floatfmt)<EOL>def get_str_table(species_df, fva=False):<EOL><INDENT>"""<STR_LIT>"""<EOL>if fva:<EOL><INDENT>return tabulate(<EOL>species_df.loc[:, ['<STR_LIT:id>', '<STR_LIT>', '<STR_LIT>']].values,<EOL>floatfmt=floatfmt, tablefmt='<STR_LIT>',<EOL>headers=['<STR_LIT:id>', '<STR_LIT>', '<STR_LIT>']).split('<STR_LIT:\n>')<EOL><DEDENT>else:<EOL><INDENT>return tabulate(species_df.loc[:, ['<STR_LIT:id>', '<STR_LIT>']].values,<EOL>floatfmt=floatfmt, tablefmt='<STR_LIT>').split('<STR_LIT:\n>')<EOL><DEDENT><DEDENT>in_table = get_str_table(<EOL>metabolite_fluxes[metabolite_fluxes['<STR_LIT>']], fva=fva is not None)<EOL>out_table = get_str_table(<EOL>metabolite_fluxes[~metabolite_fluxes['<STR_LIT>']], fva=fva is not None)<EOL>obj_table = get_str_table(obj_fluxes, fva=False)<EOL>print_(tabulate(<EOL>[entries for entries in zip_longest(in_table, out_table, obj_table)],<EOL>headers=['<STR_LIT>', '<STR_LIT>', '<STR_LIT>'], tablefmt='<STR_LIT>'))<EOL>

Print a summary of the input and output fluxes of the model.

Parameters
----------
solution: cobra.Solution, optional
    A previously solved model solution to use for generating the
    summary. If none provided (default), the summary method will
    resolve the model. Note that the solution object must match the
    model, i.e., changes to the model such as changed bounds,
    added or removed reactions are not taken into account by this
    method.
threshold : float, optional
    Threshold below which fluxes are not reported.
fva : pandas.DataFrame, float or None, optional
    Whether or not to include flux variability analysis in the output.
    If given, fva should either be a previous FVA solution matching
    the model or a float between 0 and 1 representing the
    fraction of the optimum objective to be searched.
names : bool, optional
    Emit reaction and metabolite names rather than identifiers (default
    False).
floatfmt : string, optional
    Format string for floats (default '.3g').


def fastcc(model, flux_threshold=<NUM_LIT:1.0>, zero_cutoff=None):

zero_cutoff = normalize_cutoff(model, zero_cutoff)<EOL>with model:<EOL><INDENT>obj_vars = []<EOL>vars_and_cons = []<EOL>prob = model.problem<EOL>for rxn in model.reactions:<EOL><INDENT>var = prob.Variable("<STR_LIT>".format(rxn.id),<EOL>lb=<NUM_LIT:0.0>, ub=flux_threshold)<EOL>const = prob.Constraint(rxn.forward_variable +<EOL>rxn.reverse_variable -<EOL>var, name="<STR_LIT>".format(rxn.id),<EOL>lb=<NUM_LIT:0.0>)<EOL>vars_and_cons.extend([var, const])<EOL>obj_vars.append(var)<EOL><DEDENT>model.add_cons_vars(vars_and_cons)<EOL>model.objective = prob.Objective(Zero, sloppy=True, direction="<STR_LIT>")<EOL>model.objective.set_linear_coefficients({v: <NUM_LIT:1.0> for v in obj_vars})<EOL>sol = model.optimize()<EOL><DEDENT>rxns_to_remove = sol.fluxes[sol.fluxes.abs() < zero_cutoff].index<EOL>consistent_model = model.copy()<EOL>consistent_model.remove_reactions(rxns_to_remove, remove_orphans=True)<EOL>return consistent_model<EOL>

r"""
    Check consistency of a metabolic network using FASTCC [1]_.

    FASTCC (Fast Consistency Check) is an algorithm for rapid and
    efficient consistency check in metabolic networks. FASTCC is
    a pure LP implementation and is low on computation resource
    demand. FASTCC also circumvents the problem associated with
    reversible reactions for the purpose. Given a global model,
    it will generate a consistent global model i.e., remove
    blocked reactions. For more details on FASTCC, please
    check [1]_.

    Parameters
    ----------
    model: cobra.Model
        The constraint-based model to operate on.
    flux_threshold: float, optional (default 1.0)
        The flux threshold to consider.
    zero_cutoff: float, optional
        The cutoff to consider for zero flux (default model.tolerance).

    Returns
    -------
    cobra.Model
        The consistent constraint-based model.

    Notes
    -----
    The LP used for FASTCC is like so:
    maximize: \sum_{i \in J} z_i
    s.t.    : z_i \in [0, \varepsilon] \forall i \in J, z_i \in \mathbb{R}_+
              v_i \ge z_i \forall i \in J
              Sv = 0 v \in B

    References
    ----------
    .. [1] Vlassis N, Pacheco MP, Sauter T (2014)
           Fast Reconstruction of Compact Context-Specific Metabolic Network
           Models.
           PLoS Comput Biol 10(1): e1003424. doi:10.1371/journal.pcbi.1003424


def add_room(model, solution=None, linear=False, delta=<NUM_LIT>, epsilon=<NUM_LIT>):

if '<STR_LIT>' in model.solver.variables:<EOL><INDENT>raise ValueError('<STR_LIT>')<EOL><DEDENT>if solution is None:<EOL><INDENT>solution = pfba(model)<EOL><DEDENT>prob = model.problem<EOL>variable = prob.Variable("<STR_LIT>", ub=solution.objective_value)<EOL>constraint = prob.Constraint(<EOL>model.solver.objective.expression - variable,<EOL>ub=<NUM_LIT:0.0>,<EOL>lb=<NUM_LIT:0.0>,<EOL>name="<STR_LIT>"<EOL>)<EOL>model.objective = prob.Objective(Zero, direction="<STR_LIT>", sloppy=True)<EOL>vars_and_cons = [variable, constraint]<EOL>obj_vars = []<EOL>for rxn in model.reactions:<EOL><INDENT>flux = solution.fluxes[rxn.id]<EOL>if linear:<EOL><INDENT>y = prob.Variable("<STR_LIT>" + rxn.id, lb=<NUM_LIT:0>, ub=<NUM_LIT:1>)<EOL>delta = epsilon = <NUM_LIT:0.0><EOL><DEDENT>else:<EOL><INDENT>y = prob.Variable("<STR_LIT>" + rxn.id, type="<STR_LIT>")<EOL><DEDENT>w_u = flux + (delta * abs(flux)) + epsilon<EOL>upper_const = prob.Constraint(<EOL>rxn.flux_expression - y * (rxn.upper_bound - w_u),<EOL>ub=w_u, name="<STR_LIT>" + rxn.id)<EOL>w_l = flux - (delta * abs(flux)) - epsilon<EOL>lower_const = prob.Constraint(<EOL>rxn.flux_expression - y * (rxn.lower_bound - w_l),<EOL>lb=w_l, name="<STR_LIT>" + rxn.id)<EOL>vars_and_cons.extend([y, upper_const, lower_const])<EOL>obj_vars.append(y)<EOL><DEDENT>model.add_cons_vars(vars_and_cons)<EOL>model.objective.set_linear_coefficients({v: <NUM_LIT:1.0> for v in obj_vars})<EOL>

r"""
    Add constraints and objective for ROOM.

    This function adds variables and constraints for applying regulatory
    on/off minimization (ROOM) to the model.

    Parameters
    ----------
    model : cobra.Model
        The model to add ROOM constraints and objective to.
    solution : cobra.Solution, optional
        A previous solution to use as a reference. If no solution is given,
        one will be computed using pFBA.
    linear : bool, optional
        Whether to use the linear ROOM formulation or not (default False).
    delta: float, optional
        The relative tolerance range which is additive in nature
        (default 0.03).
    epsilon: float, optional
        The absolute range of tolerance which is multiplicative
        (default 0.001).

    Notes
    -----
    The formulation used here is the same as stated in the original paper [1]_.
    The mathematical expression is given below:

    minimize \sum_{i=1}^m y^i
    s.t. Sv = 0
         v_min <= v <= v_max
         v_j = 0
         j ∈ A
         for 1 <= i <= m
         v_i - y_i(v_{max,i} - w_i^u) <= w_i^u      (1)
         v_i - y_i(v_{min,i} - w_i^l) <= w_i^l      (2)
         y_i ∈ {0,1}                                (3)
         w_i^u = w_i + \delta|w_i| + \epsilon
         w_i^l = w_i - \delta|w_i| - \epsilon

    So, for the linear version of the ROOM , constraint (3) is relaxed to
    0 <= y_i <= 1.

    See Also
    --------
    pfba : parsimonious FBA

    References
    ----------
    .. [1] Tomer Shlomi, Omer Berkman and Eytan Ruppin, "Regulatory on/off
     minimization of metabolic flux changes after genetic perturbations",
     PNAS 2005 102 (21) 7695-7700; doi:10.1073/pnas.0406346102


def _multi_deletion(model, entity, element_lists, method="<STR_LIT>",<EOL>solution=None, processes=None, **kwargs):

solver = sutil.interface_to_str(model.problem.__name__)<EOL>if method == "<STR_LIT>" and solver not in sutil.qp_solvers:<EOL><INDENT>raise RuntimeError(<EOL>"<STR_LIT>"<EOL>"<STR_LIT>".format(solver))<EOL><DEDENT>if processes is None:<EOL><INDENT>processes = CONFIGURATION.processes<EOL><DEDENT>with model:<EOL><INDENT>if "<STR_LIT>" in method:<EOL><INDENT>add_moma(model, solution=solution, linear="<STR_LIT>" in method)<EOL><DEDENT>elif "<STR_LIT>" in method:<EOL><INDENT>add_room(model, solution=solution, linear="<STR_LIT>" in method,<EOL>**kwargs)<EOL><DEDENT>args = set([frozenset(comb) for comb in product(*element_lists)])<EOL>processes = min(processes, len(args))<EOL>def extract_knockout_results(result_iter):<EOL><INDENT>result = pd.DataFrame([<EOL>(frozenset(ids), growth, status)<EOL>for (ids, growth, status) in result_iter<EOL>], columns=['<STR_LIT>', '<STR_LIT>', '<STR_LIT:status>'])<EOL>result.set_index('<STR_LIT>', inplace=True)<EOL>return result<EOL><DEDENT>if processes > <NUM_LIT:1>:<EOL><INDENT>worker = dict(gene=_gene_deletion_worker,<EOL>reaction=_reaction_deletion_worker)[entity]<EOL>chunk_size = len(args) // processes<EOL>pool = multiprocessing.Pool(<EOL>processes, initializer=_init_worker, initargs=(model,)<EOL>)<EOL>results = extract_knockout_results(pool.imap_unordered(<EOL>worker,<EOL>args,<EOL>chunksize=chunk_size<EOL>))<EOL>pool.close()<EOL>pool.join()<EOL><DEDENT>else:<EOL><INDENT>worker = dict(gene=_gene_deletion,<EOL>reaction=_reaction_deletion)[entity]<EOL>results = extract_knockout_results(map(<EOL>partial(worker, model), args))<EOL><DEDENT>return results<EOL><DEDENT>

Provide a common interface for single or multiple knockouts.

Parameters
----------
model : cobra.Model
    The metabolic model to perform deletions in.
entity : 'gene' or 'reaction'
    The entity to knockout (``cobra.Gene`` or ``cobra.Reaction``).
element_lists : list
    List of iterables ``cobra.Reaction``s or ``cobra.Gene``s (or their IDs)
    to be deleted.
method: {"fba", "moma", "linear moma", "room", "linear room"}, optional
    Method used to predict the growth rate.
solution : cobra.Solution, optional
    A previous solution to use as a reference for (linear) MOMA or ROOM.
processes : int, optional
    The number of parallel processes to run. Can speed up the computations
    if the number of knockouts to perform is large. If not passed,
    will be set to the number of CPUs found.
kwargs :
    Passed on to underlying simulation functions.

Returns
-------
pandas.DataFrame
    A representation of all combinations of entity deletions. The
    columns are 'growth' and 'status', where

    index : frozenset([str])
        The gene or reaction identifiers that were knocked out.
    growth : float
        The growth rate of the adjusted model.
    status : str
        The solution's status.


if zero_cutoff is None:<EOL><INDENT>return model.tolerance<EOL><DEDENT>else:<EOL><INDENT>if zero_cutoff < model.tolerance:<EOL><INDENT>raise ValueError(<EOL>"<STR_LIT>"<EOL>"<STR_LIT>"<EOL>)<EOL><DEDENT>else:<EOL><INDENT>return zero_cutoff<EOL><DEDENT><DEDENT>


zero_cutoff = normalize_cutoff(model, zero_cutoff)<EOL>internal = [i for i, r in enumerate(model.reactions) if not r.boundary]<EOL>s_int = create_stoichiometric_matrix(model)[:, numpy.array(internal)]<EOL>n_int = nullspace(s_int).T<EOL>max_bound = max(max(abs(b) for b in r.bounds) for r in model.reactions)<EOL>prob = model.problem<EOL>to_add = []<EOL>for i in internal:<EOL><INDENT>rxn = model.reactions[i]<EOL>indicator = prob.Variable("<STR_LIT>" + rxn.id, type="<STR_LIT>")<EOL>on_off_constraint = prob.Constraint(<EOL>rxn.flux_expression - max_bound * indicator,<EOL>lb=-max_bound, ub=<NUM_LIT:0>, name="<STR_LIT>" + rxn.id)<EOL>delta_g = prob.Variable("<STR_LIT>" + rxn.id)<EOL>delta_g_range = prob.Constraint(<EOL>delta_g + (max_bound + <NUM_LIT:1>) * indicator,<EOL>lb=<NUM_LIT:1>, ub=max_bound, name="<STR_LIT>" + rxn.id)<EOL>to_add.extend([indicator, on_off_constraint, delta_g, delta_g_range])<EOL><DEDENT>model.add_cons_vars(to_add)<EOL>for i, row in enumerate(n_int):<EOL><INDENT>name = "<STR_LIT>" + str(i)<EOL>nullspace_constraint = prob.Constraint(Zero, lb=<NUM_LIT:0>, ub=<NUM_LIT:0>, name=name)<EOL>model.add_cons_vars([nullspace_constraint])<EOL>coefs = {model.variables[<EOL>"<STR_LIT>" + model.reactions[ridx].id]: row[i]<EOL>for i, ridx in enumerate(internal) if<EOL>abs(row[i]) > zero_cutoff}<EOL>model.constraints[name].set_linear_coefficients(coefs)<EOL><DEDENT>

Modify a model so all feasible flux distributions are loopless.

    In most cases you probably want to use the much faster `loopless_solution`.
    May be used in cases where you want to add complex constraints and
    objecives (for instance quadratic objectives) to the model afterwards
    or use an approximation of Gibbs free energy directions in you model.
    Adds variables and constraints to a model which will disallow flux
    distributions with loops. The used formulation is described in [1]_.
    This function *will* modify your model.

    Parameters
    ----------
    model : cobra.Model
        The model to which to add the constraints.
    zero_cutoff : positive float, optional
        Cutoff used for null space. Coefficients with an absolute value smaller
        than `zero_cutoff` are considered to be zero (default model.tolerance).

    Returns
    -------
    Nothing

    References
    ----------
    .. [1] Elimination of thermodynamically infeasible loops in steady-state
       metabolic models. Schellenberger J, Lewis NE, Palsson BO. Biophys J.
       2011 Feb 2;100(3):544-53. doi: 10.1016/j.bpj.2010.12.3707. Erratum
       in: Biophys J. 2011 Mar 2;100(5):1381.


def add_cons_vars_to_problem(model, what, **kwargs):

context = get_context(model)<EOL>model.solver.add(what, **kwargs)<EOL>if context:<EOL><INDENT>context(partial(model.solver.remove, what))<EOL><DEDENT>

Add variables and constraints to a Model's solver object.

    Useful for variables and constraints that can not be expressed with
    reactions and lower/upper bounds. Will integrate with the Model's context
    manager in order to revert changes upon leaving the context.

    Parameters
    ----------
    model : a cobra model
       The model to which to add the variables and constraints.
    what : list or tuple of optlang variables or constraints.
       The variables or constraints to add to the model. Must be of class
       `model.problem.Variable` or
       `model.problem.Constraint`.
    **kwargs : keyword arguments
        passed to solver.add()


if isinstance(interface, ModuleType):<EOL><INDENT>interface = interface.__name__<EOL><DEDENT>return re.sub(r"<STR_LIT>", "<STR_LIT>", interface)<EOL>

Give a string representation for an optlang interface.

    Parameters
    ----------
    interface : string, ModuleType
        Full name of the interface in optlang or cobra representation.
        For instance 'optlang.glpk_interface' or 'optlang-glpk'.

    Returns
    -------
    string
       The name of the interface as a string


if status == OPTIMAL:<EOL><INDENT>return<EOL><DEDENT>elif (status in has_primals) and not raise_error:<EOL><INDENT>warn("<STR_LIT>".format(status), UserWarning)<EOL><DEDENT>elif status is None:<EOL><INDENT>raise OptimizationError(<EOL>"<STR_LIT>")<EOL><DEDENT>else:<EOL><INDENT>raise OptimizationError("<STR_LIT>".format(status))<EOL><DEDENT>

Perform standard checks on a solver's status.


if len(solvers) == <NUM_LIT:0>:<EOL><INDENT>raise SolverNotFound("<STR_LIT>")<EOL><DEDENT>mip_order = ["<STR_LIT>", "<STR_LIT>", "<STR_LIT>"]<EOL>lp_order = ["<STR_LIT>", "<STR_LIT>", "<STR_LIT>"]<EOL>qp_order = ["<STR_LIT>", "<STR_LIT>"]<EOL>if mip is False and qp is False:<EOL><INDENT>for solver_name in lp_order:<EOL><INDENT>if solver_name in solvers:<EOL><INDENT>return solver_name<EOL><DEDENT><DEDENT>return list(solvers)[<NUM_LIT:0>]<EOL><DEDENT>elif qp:  <EOL><INDENT>for solver_name in qp_order:<EOL><INDENT>if solver_name in solvers:<EOL><INDENT>return solver_name<EOL><DEDENT><DEDENT>raise SolverNotFound("<STR_LIT>")<EOL><DEDENT>else:<EOL><INDENT>for solver_name in mip_order:<EOL><INDENT>if solver_name in solvers:<EOL><INDENT>return solver_name<EOL><DEDENT><DEDENT><DEDENT>raise SolverNotFound("<STR_LIT>")<EOL>

Select a solver for a given optimization problem.

    Parameters
    ----------
    mip : bool
        Does the solver require mixed integer linear programming capabilities?
    qp : bool
        Does the solver require quadratic programming capabilities?

    Returns
    -------
    string
        The name of feasible solver.

    Raises
    ------
    SolverNotFound
        If no suitable solver could be found.


def add_absolute_expression(model, expression, name="<STR_LIT>", ub=None,<EOL>difference=<NUM_LIT:0>, add=True):

Components = namedtuple('<STR_LIT>', ['<STR_LIT>', '<STR_LIT>',<EOL>'<STR_LIT>'])<EOL>variable = model.problem.Variable(name, lb=<NUM_LIT:0>, ub=ub)<EOL>upper_constraint = model.problem.Constraint(expression - variable,<EOL>ub=difference,<EOL>name="<STR_LIT>" + name),<EOL>lower_constraint = model.problem.Constraint(expression + variable,<EOL>lb=difference,<EOL>name="<STR_LIT>" + name)<EOL>to_add = Components(variable, upper_constraint, lower_constraint)<EOL>if add:<EOL><INDENT>add_cons_vars_to_problem(model, to_add)<EOL><DEDENT>return to_add<EOL>

Add the absolute value of an expression to the model.

    Also defines a variable for the absolute value that can be used in other
    objectives or constraints.

    Parameters
    ----------
    model : a cobra model
       The model to which to add the absolute expression.
    expression : A sympy expression
       Must be a valid expression within the Model's solver object. The
       absolute value is applied automatically on the expression.
    name : string
       The name of the newly created variable.
    ub : positive float
       The upper bound for the variable.
    difference : positive float
        The difference between the expression and the variable.
    add : bool
        Whether to add the variable to the model at once.

    Returns
    -------
    namedtuple
        A named tuple with variable and two constraints (upper_constraint,
        lower_constraint) describing the new variable and the constraints
        that assign the absolute value of the expression to it.


def choose_solver(model, solver=None, qp=False):

if solver is None:<EOL><INDENT>solver = model.problem<EOL><DEDENT>else:<EOL><INDENT>model.solver = solver<EOL><DEDENT>if qp and interface_to_str(solver) not in qp_solvers:<EOL><INDENT>solver = solvers[get_solver_name(qp=True)]<EOL><DEDENT>return solver<EOL>

Choose a solver given a solver name and model.

    This will choose a solver compatible with the model and required
    capabilities. Also respects model.solver where it can.

    Parameters
    ----------
    model : a cobra model
        The model for which to choose the solver.
    solver : str, optional
        The name of the solver to be used.
    qp : boolean, optional
        Whether the solver needs Quadratic Programming capabilities.

    Returns
    -------
    solver : an optlang solver interface
        Returns a valid solver for the problem.

    Raises
    ------
    SolverNotFound
        If no suitable solver could be found.


def wrapper(self, new_value):<EOL><INDENT>context = get_context(self)<EOL>if context:<EOL><INDENT>old_value = getattr(self, f.__name__)<EOL>if old_value == new_value:<EOL><INDENT>return<EOL><DEDENT>context(partial(f, self, old_value))<EOL><DEDENT>f(self, new_value)<EOL><DEDENT>return wrapper<EOL>

A decorator to simplify the context management of simple object
    attributes. Gets the value of the attribute prior to setting it, and stores
    a function to set the value to the old value in the HistoryManager.


Add the corresponding method to the history stack.

        Parameters
        ----------
        operation : `function`
            A function to be called at a later time


try:<EOL><INDENT>return obj._contexts[-<NUM_LIT:1>]<EOL><DEDENT>except (AttributeError, IndexError):<EOL><INDENT>pass<EOL><DEDENT>try:<EOL><INDENT>return obj._model._contexts[-<NUM_LIT:1>]<EOL><DEDENT>except (AttributeError, IndexError):<EOL><INDENT>pass<EOL><DEDENT>return None<EOL>


def constraint_matrices(model, array_type='<STR_LIT>', include_vars=False,<EOL>zero_tol=<NUM_LIT>):

if array_type not in ('<STR_LIT>', '<STR_LIT>') and not dok_matrix:<EOL><INDENT>raise ValueError('<STR_LIT>')<EOL><DEDENT>array_builder = {<EOL>'<STR_LIT>': np.array, '<STR_LIT>': dok_matrix, '<STR_LIT>': lil_matrix,<EOL>'<STR_LIT>': pd.DataFrame,<EOL>}[array_type]<EOL>Problem = namedtuple("<STR_LIT>",<EOL>["<STR_LIT>", "<STR_LIT:b>", "<STR_LIT>", "<STR_LIT>",<EOL>"<STR_LIT>", "<STR_LIT>"])<EOL>equality_rows = []<EOL>inequality_rows = []<EOL>inequality_bounds = []<EOL>b = []<EOL>for const in model.constraints:<EOL><INDENT>lb = -np.inf if const.lb is None else const.lb<EOL>ub = np.inf if const.ub is None else const.ub<EOL>equality = (ub - lb) < zero_tol<EOL>coefs = const.get_linear_coefficients(model.variables)<EOL>coefs = [coefs[v] for v in model.variables]<EOL>if equality:<EOL><INDENT>b.append(lb if abs(lb) > zero_tol else <NUM_LIT:0.0>)<EOL>equality_rows.append(coefs)<EOL><DEDENT>else:<EOL><INDENT>inequality_rows.append(coefs)<EOL>inequality_bounds.append([lb, ub])<EOL><DEDENT><DEDENT>var_bounds = np.array([[v.lb, v.ub] for v in model.variables])<EOL>fixed = var_bounds[:, <NUM_LIT:1>] - var_bounds[:, <NUM_LIT:0>] < zero_tol<EOL>results = Problem(<EOL>equalities=array_builder(equality_rows),<EOL>b=np.array(b),<EOL>inequalities=array_builder(inequality_rows),<EOL>bounds=array_builder(inequality_bounds),<EOL>variable_fixed=np.array(fixed),<EOL>variable_bounds=array_builder(var_bounds))<EOL>return results<EOL>

Create a matrix representation of the problem.

    This is used for alternative solution approaches that do not use optlang.
    The function will construct the equality matrix, inequality matrix and
    bounds for the complete problem.

    Notes
    -----
    To accomodate non-zero equalities the problem will add the variable
    "const_one" which is a variable that equals one.

    Arguments
    ---------
    model : cobra.Model
        The model from which to obtain the LP problem.
    array_type : string
        The type of array to construct. if 'dense', return a standard
        numpy.array, 'dok', or 'lil' will construct a sparse array using
        scipy of the corresponding type and 'DataFrame' will give a
        pandas `DataFrame` with metabolite indices and reaction columns.
    zero_tol : float
        The zero tolerance used to judge whether two bounds are the same.

    Returns
    -------
    collections.namedtuple
        A named tuple consisting of 6 matrices and 2 vectors:
        - "equalities" is a matrix S such that S*vars = b. It includes a row
          for each constraint and one column for each variable.
        - "b" the right side of the equality equation such that S*vars = b.
        - "inequalities" is a matrix M such that lb <= M*vars <= ub.
          It contains a row for each inequality and as many columns as
          variables.
        - "bounds" is a compound matrix [lb ub] containing the lower and
          upper bounds for the inequality constraints in M.
        - "variable_fixed" is a boolean vector indicating whether the variable
          at that index is fixed (lower bound == upper_bound) and
          is thus bounded by an equality constraint.
        - "variable_bounds" is a compound matrix [lb ub] containing the
          lower and upper bounds for all variables.


def create_stoichiometric_matrix(model, array_type='<STR_LIT>', dtype=None):

if array_type not in ('<STR_LIT>', '<STR_LIT>') and not dok_matrix:<EOL><INDENT>raise ValueError('<STR_LIT>')<EOL><DEDENT>if dtype is None:<EOL><INDENT>dtype = np.float64<EOL><DEDENT>array_constructor = {<EOL>'<STR_LIT>': np.zeros, '<STR_LIT>': dok_matrix, '<STR_LIT>': lil_matrix,<EOL>'<STR_LIT>': np.zeros,<EOL>}<EOL>n_metabolites = len(model.metabolites)<EOL>n_reactions = len(model.reactions)<EOL>array = array_constructor[array_type]((n_metabolites, n_reactions),<EOL>dtype=dtype)<EOL>m_ind = model.metabolites.index<EOL>r_ind = model.reactions.index<EOL>for reaction in model.reactions:<EOL><INDENT>for metabolite, stoich in iteritems(reaction.metabolites):<EOL><INDENT>array[m_ind(metabolite), r_ind(reaction)] = stoich<EOL><DEDENT><DEDENT>if array_type == '<STR_LIT>':<EOL><INDENT>metabolite_ids = [met.id for met in model.metabolites]<EOL>reaction_ids = [rxn.id for rxn in model.reactions]<EOL>return pd.DataFrame(array, index=metabolite_ids, columns=reaction_ids)<EOL><DEDENT>else:<EOL><INDENT>return array<EOL><DEDENT>

Return a stoichiometric array representation of the given model.

    The the columns represent the reactions and rows represent
    metabolites. S[i,j] therefore contains the quantity of metabolite `i`
    produced (negative for consumed) by reaction `j`.

    Parameters
    ----------
    model : cobra.Model
        The cobra model to construct the matrix for.
    array_type : string
        The type of array to construct. if 'dense', return a standard
        numpy.array, 'dok', or 'lil' will construct a sparse array using
        scipy of the corresponding type and 'DataFrame' will give a
        pandas `DataFrame` with metabolite indices and reaction columns
    dtype : data-type
        The desired data-type for the array. If not given, defaults to float.

    Returns
    -------
    matrix of class `dtype`
        The stoichiometric matrix for the given model.


def minimal_medium(model, min_objective_value=<NUM_LIT:0.1>, exports=False,<EOL>minimize_components=False, open_exchanges=False):

exchange_rxns = find_boundary_types(model, "<STR_LIT>")<EOL>if isinstance(open_exchanges, bool):<EOL><INDENT>open_bound = <NUM_LIT:1000><EOL><DEDENT>else:<EOL><INDENT>open_bound = open_exchanges<EOL><DEDENT>with model as mod:<EOL><INDENT>if open_exchanges:<EOL><INDENT>LOGGER.debug("<STR_LIT>",<EOL>len(exchange_rxns))<EOL>for rxn in exchange_rxns:<EOL><INDENT>rxn.bounds = (-open_bound, open_bound)<EOL><DEDENT><DEDENT>LOGGER.debug("<STR_LIT>")<EOL>obj_const = mod.problem.Constraint(<EOL>mod.objective.expression, lb=min_objective_value,<EOL>name="<STR_LIT>")<EOL>mod.add_cons_vars([obj_const])<EOL>mod.solver.update()<EOL>mod.objective = Zero<EOL>LOGGER.debug("<STR_LIT>")<EOL>tol = mod.solver.configuration.tolerances.feasibility<EOL>if minimize_components:<EOL><INDENT>add_mip_obj(mod)<EOL>if isinstance(minimize_components, bool):<EOL><INDENT>minimize_components = <NUM_LIT:1><EOL><DEDENT>seen = set()<EOL>best = num_components = mod.slim_optimize()<EOL>if mod.solver.status != OPTIMAL:<EOL><INDENT>LOGGER.warning("<STR_LIT>")<EOL>return None<EOL><DEDENT>exclusion = mod.problem.Constraint(Zero, ub=<NUM_LIT:0>)<EOL>mod.add_cons_vars([exclusion])<EOL>mod.solver.update()<EOL>media = []<EOL>for i in range(minimize_components):<EOL><INDENT>LOGGER.info("<STR_LIT>", (i + <NUM_LIT:1>))<EOL>vars = [mod.variables["<STR_LIT>" + s] for s in seen]<EOL>if len(seen) > <NUM_LIT:0>:<EOL><INDENT>exclusion.set_linear_coefficients(<EOL>dict.fromkeys(vars, <NUM_LIT:1>))<EOL>exclusion.ub = best - <NUM_LIT:1><EOL><DEDENT>num_components = mod.slim_optimize()<EOL>if mod.solver.status != OPTIMAL or num_components > best:<EOL><INDENT>break<EOL><DEDENT>medium = _as_medium(exchange_rxns, tol, exports=exports)<EOL>media.append(medium)<EOL>seen.update(medium[medium > <NUM_LIT:0>].index)<EOL><DEDENT>if len(media) > <NUM_LIT:1>:<EOL><INDENT>medium = pd.concat(media, axis=<NUM_LIT:1>, sort=True).fillna(<NUM_LIT:0.0>)<EOL>medium.sort_index(axis=<NUM_LIT:1>, inplace=True)<EOL><DEDENT>else:<EOL><INDENT>medium = media[<NUM_LIT:0>]<EOL><DEDENT><DEDENT>else:<EOL><INDENT>add_linear_obj(mod)<EOL>mod.slim_optimize()<EOL>if mod.solver.status != OPTIMAL:<EOL><INDENT>LOGGER.warning("<STR_LIT>")<EOL>return None<EOL><DEDENT>medium = _as_medium(exchange_rxns, tol, exports=exports)<EOL><DEDENT><DEDENT>return medium<EOL>

Find the minimal growth medium for the model.

Finds the minimal growth medium for the model which allows for
model as well as individual growth. Here, a minimal medium can either
be the medium requiring the smallest total import flux or the medium
requiring the least components (ergo ingredients), which will be much
slower due to being a mixed integer problem (MIP).

Arguments
---------
model : cobra.model
    The model to modify.
min_objective_value : positive float or array-like object
    The minimum growth rate (objective) that has to be achieved.
exports : boolean
    Whether to include export fluxes in the returned medium. Defaults to
    False which will only return import fluxes.
minimize_components : boolean or positive int
    Whether to minimize the number of components instead of the total
    import flux. Might be more intuitive if set to True but may also be
    slow to calculate for large communities. If set to a number `n` will
    return up to `n` alternative solutions all with the same number of
    components.
open_exchanges : boolean or number
    Whether to ignore currently set bounds and make all exchange reactions
    in the model possible. If set to a number all exchange reactions will
    be opened with (-number, number) as bounds.

Returns
-------
pandas.Series, pandas.DataFrame or None
    A series giving the import flux for each required import
    reaction and (optionally) the associated export fluxes. All exchange
    fluxes are oriented into the import reaction e.g. positive fluxes
    denote imports and negative fluxes exports. If `minimize_components`
    is a number larger 1 may return a DataFrame where each column is a
    minimal medium. Returns None if the minimization is infeasible
    (for instance if min_growth > maximum growth rate).

Notes
-----
Due to numerical issues the `minimize_components` option will usually only
minimize the number of "large" import fluxes. Specifically, the detection
limit is given by ``integrality_tolerance * max_bound`` where ``max_bound``
is the largest bound on an import reaction. Thus, if you are interested
in small import fluxes as well you may have to adjust the integrality
tolerance at first with
`model.solver.configuration.tolerances.integrality = 1e-7` for instance.
However, this will be *very* slow for large models especially with GLPK.


def is_boundary_type(reaction, boundary_type, external_compartment):

<EOL>sbo_term = reaction.annotation.get("<STR_LIT>", "<STR_LIT>")<EOL>if isinstance(sbo_term, list):<EOL><INDENT>sbo_term = sbo_term[<NUM_LIT:0>]<EOL><DEDENT>sbo_term = sbo_term.upper()<EOL>if sbo_term == sbo_terms[boundary_type]:<EOL><INDENT>return True<EOL><DEDENT>if sbo_term in [sbo_terms[k] for k in sbo_terms if k != boundary_type]:<EOL><INDENT>return False<EOL><DEDENT>correct_compartment = external_compartment in reaction.compartments<EOL>if boundary_type != "<STR_LIT>":<EOL><INDENT>correct_compartment = not correct_compartment<EOL><DEDENT>rev_type = True<EOL>if boundary_type == "<STR_LIT>":<EOL><INDENT>rev_type = not reaction.reversibility<EOL><DEDENT>elif boundary_type == "<STR_LIT>":<EOL><INDENT>rev_type = reaction.reversibility<EOL><DEDENT>return (reaction.boundary and not<EOL>any(ex in reaction.id for ex in excludes[boundary_type]) and<EOL>correct_compartment and rev_type)<EOL>

Check whether a reaction is an exchange reaction.

    Arguments
    ---------
    reaction : cobra.Reaction
        The reaction to check.
    boundary_type : str
        What boundary type to check for. Must be one of
        "exchange", "demand", or "sink".
    external_compartment : str
        The id for the external compartment.

    Returns
    -------
    boolean
        Whether the reaction looks like the requested type. Might be based
        on a heuristic.


recompute_reactions = set()  <EOL>remove_genes = []<EOL>for old_name, new_name in iteritems(rename_dict):<EOL><INDENT>try:<EOL><INDENT>gene_index = cobra_model.genes.index(old_name)<EOL><DEDENT>except ValueError:<EOL><INDENT>gene_index = None<EOL><DEDENT>old_gene_present = gene_index is not None<EOL>new_gene_present = new_name in cobra_model.genes<EOL>if old_gene_present and new_gene_present:<EOL><INDENT>old_gene = cobra_model.genes.get_by_id(old_name)<EOL>if old_gene is not cobra_model.genes.get_by_id(new_name):<EOL><INDENT>remove_genes.append(old_gene)<EOL>recompute_reactions.update(old_gene._reaction)<EOL><DEDENT><DEDENT>elif old_gene_present and not new_gene_present:<EOL><INDENT>gene = cobra_model.genes[gene_index]<EOL>cobra_model.genes._dict.pop(gene.id)  <EOL>gene.id = new_name<EOL>cobra_model.genes[gene_index] = gene<EOL><DEDENT>elif not old_gene_present and new_gene_present:<EOL><INDENT>pass<EOL><DEDENT>else:  <EOL><INDENT>pass<EOL><DEDENT><DEDENT>cobra_model.repair()<EOL>class Renamer(NodeTransformer):<EOL><INDENT>def visit_Name(self, node):<EOL><INDENT>node.id = rename_dict.get(node.id, node.id)<EOL>return node<EOL><DEDENT><DEDENT>gene_renamer = Renamer()<EOL>for rxn, rule in iteritems(get_compiled_gene_reaction_rules(cobra_model)):<EOL><INDENT>if rule is not None:<EOL><INDENT>rxn._gene_reaction_rule = ast2str(gene_renamer.visit(rule))<EOL><DEDENT><DEDENT>for rxn in recompute_reactions:<EOL><INDENT>rxn.gene_reaction_rule = rxn._gene_reaction_rule<EOL><DEDENT>for i in remove_genes:<EOL><INDENT>cobra_model.genes.remove(i)<EOL><DEDENT>

renames genes in a model from the rename_dict


for c in ("<STR_LIT:'>", '<STR_LIT:">'):<EOL><INDENT>if id_str.startswith(c) and id_str.endswith(c)and id_str.count(c) == <NUM_LIT:2>:<EOL><INDENT>id_str = id_str.strip(c)<EOL><DEDENT><DEDENT>for char, escaped_char in _renames:<EOL><INDENT>id_str = id_str.replace(char, escaped_char)<EOL><DEDENT>return id_str<EOL>


for r in model.reactions:<EOL><INDENT>if r.annotation.get("<STR_LIT>"):<EOL><INDENT>continue<EOL><DEDENT>if len(r.metabolites) != <NUM_LIT:1>:<EOL><INDENT>continue<EOL><DEDENT>met_id = list(r._metabolites)[<NUM_LIT:0>].id<EOL>if r.id.startswith("<STR_LIT>") and r.id == "<STR_LIT>" + met_id:<EOL><INDENT>r.annotation["<STR_LIT>"] = "<STR_LIT>"<EOL><DEDENT>elif r.id.startswith("<STR_LIT>") and r.id == "<STR_LIT>" + met_id:<EOL><INDENT>r.annotation["<STR_LIT>"] = "<STR_LIT>"<EOL><DEDENT><DEDENT>

adds SBO terms for demands and exchanges

    This works for models which follow the standard convention for
    constructing and naming these reactions.

    The reaction should only contain the single metabolite being exchanged,
    and the id should be EX_metid or DM_metid


if cobra_model._trimmed_genes is not None:<EOL><INDENT>for x in cobra_model._trimmed_genes:<EOL><INDENT>x.functional = True<EOL><DEDENT><DEDENT>if cobra_model._trimmed_reactions is not None:<EOL><INDENT>for the_reaction, (lower_bound, upper_bound) incobra_model._trimmed_reactions.items():<EOL><INDENT>the_reaction.lower_bound = lower_bound<EOL>the_reaction.upper_bound = upper_bound<EOL><DEDENT><DEDENT>cobra_model._trimmed_genes = []<EOL>cobra_model._trimmed_reactions = {}<EOL>cobra_model._trimmed = False<EOL>

Undoes the effects of a call to delete_model_genes in place.

    cobra_model:  A cobra.Model which will be modified in place


output_model = cobra_model.copy()<EOL>inactive_metabolites = [m for m in output_model.metabolites<EOL>if len(m.reactions) == <NUM_LIT:0>]<EOL>output_model.remove_metabolites(inactive_metabolites)<EOL>return output_model, inactive_metabolites<EOL>

Remove metabolites that are not involved in any reactions and
    returns pruned model

    Parameters
    ----------
    cobra_model: class:`~cobra.core.Model.Model` object
        the model to remove unused metabolites from

    Returns
    -------
    output_model: class:`~cobra.core.Model.Model` object
        input model with unused metabolites removed
    inactive_metabolites: list of class:`~cobra.core.reaction.Reaction`
        list of metabolites that were removed


potential_reactions = set()<EOL>for gene in gene_list:<EOL><INDENT>if isinstance(gene, string_types):<EOL><INDENT>gene = cobra_model.genes.get_by_id(gene)<EOL><DEDENT>potential_reactions.update(gene._reaction)<EOL><DEDENT>gene_set = {str(i) for i in gene_list}<EOL>if compiled_gene_reaction_rules is None:<EOL><INDENT>compiled_gene_reaction_rules = {r: parse_gpr(r.gene_reaction_rule)[<NUM_LIT:0>]<EOL>for r in potential_reactions}<EOL><DEDENT>return [r for r in potential_reactions<EOL>if not eval_gpr(compiled_gene_reaction_rules[r], gene_set)]<EOL>

identify reactions which will be disabled when the genes are knocked out

    cobra_model: :class:`~cobra.core.Model.Model`

    gene_list: iterable of :class:`~cobra.core.Gene.Gene`

    compiled_gene_reaction_rules: dict of {reaction_id: compiled_string}
        If provided, this gives pre-compiled gene_reaction_rule strings.
        The compiled rule strings can be evaluated much faster. If a rule
        is not provided, the regular expression evaluation will be used.
        Because not all gene_reaction_rule strings can be evaluated, this
        dict must exclude any rules which can not be used with eval.


output_model = cobra_model.copy()<EOL>reactions_to_prune = [r for r in output_model.reactions<EOL>if len(r.metabolites) == <NUM_LIT:0>]<EOL>output_model.remove_reactions(reactions_to_prune)<EOL>return output_model, reactions_to_prune<EOL>

Remove reactions with no assigned metabolites, returns pruned model

    Parameters
    ----------
    cobra_model: class:`~cobra.core.Model.Model` object
        the model to remove unused reactions from

    Returns
    -------
    output_model: class:`~cobra.core.Model.Model` object
        input model with unused reactions removed
    reactions_to_prune: list of class:`~cobra.core.reaction.Reaction`
        list of reactions that were removed


def step(sampler, x, delta, fraction=None, tries=<NUM_LIT:0>):

prob = sampler.problem<EOL>valid = ((np.abs(delta) > sampler.feasibility_tol) &<EOL>np.logical_not(prob.variable_fixed))<EOL>valphas = ((<NUM_LIT:1.0> - sampler.bounds_tol) * prob.variable_bounds -<EOL>x)[:, valid]<EOL>valphas = (valphas / delta[valid]).flatten()<EOL>if prob.bounds.shape[<NUM_LIT:0>] > <NUM_LIT:0>:<EOL><INDENT>ineqs = prob.inequalities.dot(delta)<EOL>valid = np.abs(ineqs) > sampler.feasibility_tol<EOL>balphas = ((<NUM_LIT:1.0> - sampler.bounds_tol) * prob.bounds -<EOL>prob.inequalities.dot(x))[:, valid]<EOL>balphas = (balphas / ineqs[valid]).flatten()<EOL>alphas = np.hstack([valphas, balphas])<EOL><DEDENT>else:<EOL><INDENT>alphas = valphas<EOL><DEDENT>pos_alphas = alphas[alphas > <NUM_LIT:0.0>]<EOL>neg_alphas = alphas[alphas <= <NUM_LIT:0.0>]<EOL>alpha_range = np.array([neg_alphas.max() if len(neg_alphas) > <NUM_LIT:0> else <NUM_LIT:0>,<EOL>pos_alphas.min() if len(pos_alphas) > <NUM_LIT:0> else <NUM_LIT:0>])<EOL>if fraction:<EOL><INDENT>alpha = alpha_range[<NUM_LIT:0>] + fraction * (alpha_range[<NUM_LIT:1>] - alpha_range[<NUM_LIT:0>])<EOL><DEDENT>else:<EOL><INDENT>alpha = np.random.uniform(alpha_range[<NUM_LIT:0>], alpha_range[<NUM_LIT:1>])<EOL><DEDENT>p = x + alpha * delta<EOL>if (np.any(sampler._bounds_dist(p) < -sampler.bounds_tol) or<EOL>np.abs(np.abs(alpha_range).max() * delta).max() <<EOL>sampler.bounds_tol):<EOL><INDENT>if tries > MAX_TRIES:<EOL><INDENT>raise RuntimeError("<STR_LIT>"<EOL>"<STR_LIT>"<EOL>"<STR_LIT>"<EOL>"<STR_LIT>"<EOL>"<STR_LIT>")<EOL><DEDENT>LOGGER.info("<STR_LIT>"<EOL>"<STR_LIT>")<EOL>newdir = sampler.warmup[np.random.randint(sampler.n_warmup)]<EOL>sampler.retries += <NUM_LIT:1><EOL>return step(sampler, sampler.center, newdir - sampler.center, None,<EOL>tries + <NUM_LIT:1>)<EOL><DEDENT>return p<EOL>

Sample a new feasible point from the point `x` in direction `delta`.


samples = np.atleast_2d(samples)<EOL>prob = self.problem<EOL>if samples.shape[<NUM_LIT:1>] == len(self.model.reactions):<EOL><INDENT>S = create_stoichiometric_matrix(self.model)<EOL>b = np.array([self.model.constraints[m.id].lb for m in<EOL>self.model.metabolites])<EOL>bounds = np.array([r.bounds for r in self.model.reactions]).T<EOL><DEDENT>elif samples.shape[<NUM_LIT:1>] == len(self.model.variables):<EOL><INDENT>S = prob.equalities<EOL>b = prob.b<EOL>bounds = prob.variable_bounds<EOL><DEDENT>else:<EOL><INDENT>raise ValueError("<STR_LIT>"<EOL>"<STR_LIT>"<EOL>"<STR_LIT>")<EOL><DEDENT>feasibility = np.abs(S.dot(samples.T).T - b).max(axis=<NUM_LIT:1>)<EOL>lb_error = (samples - bounds[<NUM_LIT:0>, ]).min(axis=<NUM_LIT:1>)<EOL>ub_error = (bounds[<NUM_LIT:1>, ] - samples).min(axis=<NUM_LIT:1>)<EOL>if (samples.shape[<NUM_LIT:1>] == len(self.model.variables) and<EOL>prob.inequalities.shape[<NUM_LIT:0>]):<EOL><INDENT>consts = prob.inequalities.dot(samples.T)<EOL>lb_error = np.minimum(<EOL>lb_error,<EOL>(consts - prob.bounds[<NUM_LIT:0>, ]).min(axis=<NUM_LIT:1>))<EOL>ub_error = np.minimum(<EOL>ub_error,<EOL>(prob.bounds[<NUM_LIT:1>, ] - consts).min(axis=<NUM_LIT:1>)<EOL>)<EOL><DEDENT>valid = (<EOL>(feasibility < self.feasibility_tol) &<EOL>(lb_error > -self.bounds_tol) &<EOL>(ub_error > -self.bounds_tol))<EOL>codes = np.repeat("<STR_LIT>", valid.shape[<NUM_LIT:0>]).astype(np.dtype((str, <NUM_LIT:3>)))<EOL>codes[valid] = "<STR_LIT:v>"<EOL>codes[lb_error <= -self.bounds_tol] = np.char.add(<EOL>codes[lb_error <= -self.bounds_tol], "<STR_LIT:l>")<EOL>codes[ub_error <= -self.bounds_tol] = np.char.add(<EOL>codes[ub_error <= -self.bounds_tol], "<STR_LIT:u>")<EOL>codes[feasibility > self.feasibility_tol] = np.char.add(<EOL>codes[feasibility > self.feasibility_tol], "<STR_LIT:e>")<EOL>return codes<EOL>

Validate a set of samples for equality and inequality feasibility.

        Can be used to check whether the generated samples and warmup points
        are feasible.

        Parameters
        ----------
        samples : numpy.matrix
            Must be of dimension (n_samples x n_reactions). Contains the
            samples to be validated. Samples must be from fluxes.

        Returns
        -------
        numpy.array
            A one-dimensional numpy array of length containing
            a code of 1 to 3 letters denoting the validation result:

            - 'v' means feasible in bounds and equality constraints
            - 'l' means a lower bound violation
            - 'u' means a lower bound validation
            - 'e' means and equality constraint violation


def batch(self, batch_size, batch_num, fluxes=True):

for i in range(batch_num):<EOL><INDENT>yield self.sample(batch_size, fluxes=fluxes)<EOL><DEDENT>

Create a batch generator.

        This is useful to generate n batches of m samples each.

        Parameters
        ----------
        batch_size : int
            The number of samples contained in each batch (m).
        batch_num : int
            The number of batches in the generator (n).
        fluxes : boolean
            Whether to return fluxes or the internal solver variables. If set
            to False will return a variable for each forward and backward flux
            as well as all additional variables you might have defined in the
            model.

        Yields
        ------
        pandas.DataFrame
            A DataFrame with dimensions (batch_size x n_r) containing
            a valid flux sample for a total of n_r reactions (or variables if
            fluxes=False) in each row.


prob = self.problem<EOL>lb_dist = (p - prob.variable_bounds[<NUM_LIT:0>, ]).min()<EOL>ub_dist = (prob.variable_bounds[<NUM_LIT:1>, ] - p).min()<EOL>if prob.bounds.shape[<NUM_LIT:0>] > <NUM_LIT:0>:<EOL><INDENT>const = prob.inequalities.dot(p)<EOL>const_lb_dist = (const - prob.bounds[<NUM_LIT:0>, ]).min()<EOL>const_ub_dist = (prob.bounds[<NUM_LIT:1>, ] - const).min()<EOL>lb_dist = min(lb_dist, const_lb_dist)<EOL>ub_dist = min(ub_dist, const_ub_dist)<EOL><DEDENT>return np.array([lb_dist, ub_dist])<EOL>

Get the lower and upper bound distances. Negative is bad.


samples = np.zeros((n, self.warmup.shape[<NUM_LIT:1>]))<EOL>for i in range(<NUM_LIT:1>, self.thinning * n + <NUM_LIT:1>):<EOL><INDENT>self.__single_iteration()<EOL>if i % self.thinning == <NUM_LIT:0>:<EOL><INDENT>samples[i//self.thinning - <NUM_LIT:1>, ] = self.prev<EOL><DEDENT><DEDENT>if fluxes:<EOL><INDENT>names = [r.id for r in self.model.reactions]<EOL>return pandas.DataFrame(<EOL>samples[:, self.fwd_idx] - samples[:, self.rev_idx],<EOL>columns=names)<EOL><DEDENT>else:<EOL><INDENT>names = [v.name for v in self.model.variables]<EOL>return pandas.DataFrame(samples, columns=names)<EOL><DEDENT>

Generate a set of samples.

        This is the basic sampling function for all hit-and-run samplers.

        Parameters
        ----------
        n : int
            The number of samples that are generated at once.
        fluxes : boolean
            Whether to return fluxes or the internal solver variables. If set
            to False will return a variable for each forward and backward flux
            as well as all additional variables you might have defined in the
            model.

        Returns
        -------
        numpy.matrix
            Returns a matrix with `n` rows, each containing a flux sample.

        Notes
        -----
        Performance of this function linearly depends on the number
        of reactions in your model and the thinning factor.


def __init__(self, model, thinning=<NUM_LIT:100>, nproj=None, seed=None):

super(ACHRSampler, self).__init__(model, thinning, nproj=nproj,<EOL>seed=seed)<EOL>self.generate_fva_warmup()<EOL>self.prev = self.center = self.warmup.mean(axis=<NUM_LIT:0>)<EOL>np.random.seed(self._seed)<EOL>


if self.processes > <NUM_LIT:1>:<EOL><INDENT>n_process = np.ceil(n / self.processes).astype(int)<EOL>n = n_process * self.processes<EOL>args = list(zip(<EOL>[n_process] * self.processes, range(self.processes)))<EOL>mp = Pool(self.processes, initializer=mp_init, initargs=(self,))<EOL>results = mp.map(_sample_chain, args, chunksize=<NUM_LIT:1>)<EOL>mp.close()<EOL>mp.join()<EOL>chains = np.vstack([r[<NUM_LIT:1>] for r in results])<EOL>self.retries += sum(r[<NUM_LIT:0>] for r in results)<EOL><DEDENT>else:<EOL><INDENT>mp_init(self)<EOL>results = _sample_chain((n, <NUM_LIT:0>))<EOL>chains = results[<NUM_LIT:1>]<EOL><DEDENT>self.center = (self.n_samples * self.center +<EOL>np.atleast_2d(chains).sum(<NUM_LIT:0>)) / (self.n_samples + n)<EOL>self.n_samples += n<EOL>if fluxes:<EOL><INDENT>names = [r.id for r in self.model.reactions]<EOL>return pandas.DataFrame(<EOL>chains[:, self.fwd_idx] - chains[:, self.rev_idx],<EOL>columns=names)<EOL><DEDENT>else:<EOL><INDENT>names = [v.name for v in self.model.variables]<EOL>return pandas.DataFrame(chains, columns=names)<EOL><DEDENT>

Generate a set of samples.

        This is the basic sampling function for all hit-and-run samplers.

        Paramters
        ---------
        n : int
            The minimum number of samples that are generated at once
            (see Notes).
        fluxes : boolean
            Whether to return fluxes or the internal solver variables. If set
            to False will return a variable for each forward and backward flux
            as well as all additional variables you might have defined in the
            model.

        Returns
        -------
        numpy.matrix
            Returns a matrix with `n` rows, each containing a flux sample.

        Notes
        -----
        Performance of this function linearly depends on the number
        of reactions in your model and the thinning factor.

        If the number of processes is larger than one, computation is split
        across as the CPUs of your machine. This may shorten computation time.
        However, there is also overhead in setting up parallel computation so
        we recommend to calculate large numbers of samples at once
        (`n` > 1000).


d = dict(self.__dict__)<EOL>del d['<STR_LIT>']<EOL>return d<EOL>


def __init__(self, model, processes=None, thinning=<NUM_LIT:100>, nproj=None,<EOL>seed=None):

super(OptGPSampler, self).__init__(model, thinning, seed=seed)<EOL>self.generate_fva_warmup()<EOL>if processes is None:<EOL><INDENT>self.processes = CONFIGURATION.processes<EOL><DEDENT>else:<EOL><INDENT>self.processes = processes<EOL><DEDENT>self.center = shared_np_array((len(model.variables), ),<EOL>self.warmup.mean(axis=<NUM_LIT:0>))<EOL>


n, idx = args       <EOL>center = sampler.center<EOL>np.random.seed((sampler._seed + idx) % np.iinfo(np.int32).max)<EOL>pi = np.random.randint(sampler.n_warmup)<EOL>prev = sampler.warmup[pi, ]<EOL>prev = step(sampler, center, prev - center, <NUM_LIT>)<EOL>n_samples = max(sampler.n_samples, <NUM_LIT:1>)<EOL>samples = np.zeros((n, center.shape[<NUM_LIT:0>]))<EOL>for i in range(<NUM_LIT:1>, sampler.thinning * n + <NUM_LIT:1>):<EOL><INDENT>pi = np.random.randint(sampler.n_warmup)<EOL>delta = sampler.warmup[pi, ] - center<EOL>prev = step(sampler, prev, delta)<EOL>if sampler.problem.homogeneous and (<EOL>n_samples * sampler.thinning % sampler.nproj == <NUM_LIT:0>):<EOL><INDENT>prev = sampler._reproject(prev)<EOL>center = sampler._reproject(center)<EOL><DEDENT>if i % sampler.thinning == <NUM_LIT:0>:<EOL><INDENT>samples[i//sampler.thinning - <NUM_LIT:1>, ] = prev<EOL><DEDENT>center = ((n_samples * center) / (n_samples + <NUM_LIT:1>) +<EOL>prev / (n_samples + <NUM_LIT:1>))<EOL>n_samples += <NUM_LIT:1><EOL><DEDENT>return (sampler.retries, samples)<EOL>

Sample a single chain for OptGPSampler.

    center and n_samples are updated locally and forgotten afterwards.


tmp = tag.split("<STR_LIT:.>")<EOL>existing = [intify(basename(f)) for f in glob(join(target, "<STR_LIT>"))]<EOL>latest = max(existing)<EOL>if int(tmp[<NUM_LIT:0>]) > latest[<NUM_LIT:0>]:<EOL><INDENT>return "<STR_LIT>"<EOL><DEDENT>elif int(tmp[<NUM_LIT:1>]) > latest[<NUM_LIT:1>]:<EOL><INDENT>return "<STR_LIT>"<EOL><DEDENT>else:<EOL><INDENT>return "<STR_LIT>"<EOL><DEDENT>

Identify the kind of release by comparing to existing ones.


header = [<EOL>'<STR_LIT>',<EOL>'<STR_LIT>'.format(date.today().isoformat()),<EOL>'<STR_LIT>'.format(tag),<EOL>'<STR_LIT>',<EOL>'<STR_LIT>'.format(bump),<EOL>'<STR_LIT>',<EOL>'<STR_LIT:\n>'<EOL>]<EOL>with open(filename, "<STR_LIT:r>") as file_h:<EOL><INDENT>content = insert_break(file_h.readlines())<EOL><DEDENT>header.extend(content)<EOL>with open(filename, "<STR_LIT:w>") as file_h:<EOL><INDENT>file_h.writelines(header)<EOL><DEDENT>

Build the markdown release notes for Hugo.

Inserts the required TOML header with specific values and adds a break
for long release notes.

Parameters
----------
filename : str, path
    The release notes file.
tag : str
    The tag, following semantic versioning, of the current release.
bump : {"major", "minor", "patch", "alpha", "beta"}
    The type of release.


created = kwargs.get("<STR_LIT>", False)<EOL>user_instance = kwargs.get("<STR_LIT>", None)<EOL>if user_instance is None:<EOL><INDENT>return  <EOL><DEDENT>try:<EOL><INDENT>pending_ecu = PendingEnterpriseCustomerUser.objects.get(user_email=user_instance.email)<EOL><DEDENT>except PendingEnterpriseCustomerUser.DoesNotExist:<EOL><INDENT>return  <EOL><DEDENT>if not created:<EOL><INDENT>try:<EOL><INDENT>existing_record = EnterpriseCustomerUser.objects.get(user_id=user_instance.id)<EOL>message_template = "<STR_LIT>""<STR_LIT>""<STR_LIT>"<EOL>logger.info(message_template.format(<EOL>user=user_instance, enterprise_customer=existing_record.enterprise_customer<EOL>))<EOL>pending_ecu.delete()<EOL>return<EOL><DEDENT>except EnterpriseCustomerUser.DoesNotExist:<EOL><INDENT>pass  <EOL><DEDENT><DEDENT>enterprise_customer_user = EnterpriseCustomerUser.objects.create(<EOL>enterprise_customer=pending_ecu.enterprise_customer,<EOL>user_id=user_instance.id<EOL>)<EOL>pending_enrollments = list(pending_ecu.pendingenrollment_set.all())<EOL>if pending_enrollments:<EOL><INDENT>def _complete_user_enrollment():  <EOL><INDENT>for enrollment in pending_enrollments:<EOL><INDENT>enterprise_customer_user.enroll(<EOL>enrollment.course_id, enrollment.course_mode, cohort=enrollment.cohort_name)<EOL>track_enrollment('<STR_LIT>', user_instance.id, enrollment.course_id)<EOL><DEDENT>pending_ecu.delete()<EOL><DEDENT>transaction.on_commit(_complete_user_enrollment)<EOL><DEDENT>else:<EOL><INDENT>pending_ecu.delete()<EOL><DEDENT>

Handle User model changes - checks if pending enterprise customer user record exists and upgrades it to actual link.

If there are pending enrollments attached to the PendingEnterpriseCustomerUser, then this signal also takes the
newly-created users and enrolls them in the relevant courses.


@receiver(post_save, sender=EnterpriseCustomerUser)<EOL>def assign_enterprise_learner_role(sender, instance, **kwargs):

if kwargs['<STR_LIT>'] and instance.user:<EOL><INDENT>enterprise_learner_role, __ = SystemWideEnterpriseRole.objects.get_or_create(name=ENTERPRISE_LEARNER_ROLE)<EOL>SystemWideEnterpriseUserRoleAssignment.objects.get_or_create(<EOL>user=instance.user,<EOL>role=enterprise_learner_role<EOL>)<EOL><DEDENT>

Assign an enterprise learner role to EnterpriseCustomerUser whenever a new record is created.


@receiver(post_delete, sender=EnterpriseCustomerUser)<EOL>def delete_enterprise_learner_role_assignment(sender, instance, **kwargs):

Delete the associated enterprise learner role assignment record when deleting an EnterpriseCustomerUser record.


return mark_safe(strip_html_tags(html_text))<EOL>

Django template filter that strips all HTML tags excepts those degined in ALLOWED_TAGS.

General Usage:
    {{ html_text|only_safe_html }}


@register.filter(needs_autoescape=True)<EOL>def link_to_modal(link_text, index, autoescape=True):

Django template filter that returns an anchor with attributes useful for course modal selection.

General Usage:
    {{ link_text|link_to_modal:index }}

Examples:
    {{ course_title|link_to_modal:forloop.counter0 }}
    {{ course_title|link_to_modal:3 }}
    {{ view_details_text|link_to_modal:0 }}


return {<EOL>'<STR_LIT>': MESSAGE_ICONS.get(message_type, '<STR_LIT>'.format(message_type))<EOL>}<EOL>

Django template tag that returns font awesome icon depending upon message type.

Usage:
    {% fa_icon "success" %}


Switch = apps.get_model('<STR_LIT>', '<STR_LIT>')<EOL>Switch.objects.update_or_create(name=ENTERPRISE_ROLE_BASED_ACCESS_CONTROL_SWITCH, defaults={'<STR_LIT>': False})<EOL>

Create the `role_based_access_control` switch if it does not already exist.


Switch = apps.get_model('<STR_LIT>', '<STR_LIT>')<EOL>Switch.objects.filter(name=ENTERPRISE_ROLE_BASED_ACCESS_CONTROL_SWITCH).delete()<EOL>

Delete the `role_based_access_control` switch.


EnterpriseFeatureRole = apps.get_model('<STR_LIT>', '<STR_LIT>')<EOL>EnterpriseFeatureRole.objects.filter(<EOL>name__in=[ENTERPRISE_CATALOG_ADMIN_ROLE, ENTERPRISE_DASHBOARD_ADMIN_ROLE, ENTERPRISE_ENROLLMENT_API_ADMIN_ROLE]<EOL>).delete()<EOL>


SystemWideEnterpriseRole = apps.get_model('<STR_LIT>', '<STR_LIT>')<EOL>SystemWideEnterpriseRole.objects.update_or_create(name=ENTERPRISE_OPERATOR_ROLE)<EOL>

Create the enterprise roles if they do not already exist.


config = get_app_config()<EOL>ext = os.path.splitext(value.name)[<NUM_LIT:1>]<EOL>if config and not ext.lower() in config.valid_image_extensions:<EOL><INDENT>raise ValidationError(_("<STR_LIT>"))<EOL><DEDENT>

Validate that a particular image extension.


if waffle.switch_is_active('<STR_LIT>') and get_localized_price_text:<EOL><INDENT>return get_localized_price_text(price, request)<EOL><DEDENT>return format_price(price)<EOL>

Return the localized converted price as string (ex. '$150 USD').

If the local_currency switch is enabled and the users location has been determined this will convert the
given price based on conversion rate from the Catalog service and return a localized string


def set_final_prices(self, modes, request):

result = []<EOL>for mode in modes:<EOL><INDENT>if mode['<STR_LIT>']:<EOL><INDENT>mode['<STR_LIT>'] = EcommerceApiClient(request.user).get_course_final_price(<EOL>mode=mode,<EOL>enterprise_catalog_uuid=request.GET.get(<EOL>'<STR_LIT>'<EOL>) if request.method == '<STR_LIT:GET>' else None,<EOL>)<EOL><DEDENT>result.append(mode)<EOL><DEDENT>return result<EOL>

Set the final discounted price on each premium mode.


@method_decorator(enterprise_login_required)<EOL><INDENT>def post(self, request, enterprise_uuid, course_id):<DEDENT>

enterprise_customer, course, course_run, course_modes = self.get_base_details(<EOL>request, enterprise_uuid, course_id<EOL>)<EOL>enterprise_customer_user, __ = EnterpriseCustomerUser.objects.get_or_create(<EOL>enterprise_customer=enterprise_customer,<EOL>user_id=request.user.id<EOL>)<EOL>enterprise_customer_user.update_session(request)<EOL>data_sharing_consent = DataSharingConsent.objects.proxied_get(<EOL>username=enterprise_customer_user.username,<EOL>course_id=course_id,<EOL>enterprise_customer=enterprise_customer<EOL>)<EOL>try:<EOL><INDENT>enterprise_course_enrollment = EnterpriseCourseEnrollment.objects.get(<EOL>enterprise_customer_user__enterprise_customer=enterprise_customer,<EOL>enterprise_customer_user__user_id=request.user.id,<EOL>course_id=course_id<EOL>)<EOL><DEDENT>except EnterpriseCourseEnrollment.DoesNotExist:<EOL><INDENT>enterprise_course_enrollment = None<EOL><DEDENT>enterprise_catalog_uuid = request.POST.get('<STR_LIT>')<EOL>selected_course_mode_name = request.POST.get('<STR_LIT>')<EOL>cohort_name = request.POST.get('<STR_LIT>')<EOL>selected_course_mode = None<EOL>for course_mode in course_modes:<EOL><INDENT>if course_mode['<STR_LIT>'] == selected_course_mode_name:<EOL><INDENT>selected_course_mode = course_mode<EOL>break<EOL><DEDENT><DEDENT>if not selected_course_mode:<EOL><INDENT>return self.get_enterprise_course_enrollment_page(<EOL>request,<EOL>enterprise_customer,<EOL>course,<EOL>course_run,<EOL>course_modes,<EOL>enterprise_course_enrollment,<EOL>data_sharing_consent<EOL>)<EOL><DEDENT>user_consent_needed = get_data_sharing_consent(<EOL>enterprise_customer_user.username,<EOL>enterprise_customer.uuid,<EOL>course_id=course_id<EOL>).consent_required()<EOL>if not selected_course_mode.get('<STR_LIT>') and not user_consent_needed:<EOL><INDENT>if not enterprise_course_enrollment:<EOL><INDENT>enterprise_course_enrollment = EnterpriseCourseEnrollment.objects.create(<EOL>enterprise_customer_user=enterprise_customer_user,<EOL>course_id=course_id,<EOL>)<EOL>track_enrollment('<STR_LIT>', request.user.id, course_id, request.get_full_path())<EOL><DEDENT>client = EnrollmentApiClient()<EOL>client.enroll_user_in_course(<EOL>request.user.username,<EOL>course_id,<EOL>selected_course_mode_name,<EOL>cohort=cohort_name<EOL>)<EOL>return redirect(LMS_COURSEWARE_URL.format(course_id=course_id))<EOL><DEDENT>if user_consent_needed:<EOL><INDENT>query_string_params = {<EOL>'<STR_LIT>': selected_course_mode_name,<EOL>}<EOL>if enterprise_catalog_uuid:<EOL><INDENT>query_string_params.update({'<STR_LIT>': enterprise_catalog_uuid})<EOL><DEDENT>next_url = '<STR_LIT>'.format(<EOL>handle_consent_enrollment_url=reverse(<EOL>'<STR_LIT>', args=[enterprise_customer.uuid, course_id]<EOL>),<EOL>query_string=urlencode(query_string_params)<EOL>)<EOL>failure_url = reverse('<STR_LIT>', args=[enterprise_customer.uuid, course_id])<EOL>if request.META['<STR_LIT>']:<EOL><INDENT>failure_url = '<STR_LIT>'.format(<EOL>course_enrollment_url=reverse(<EOL>'<STR_LIT>', args=[enterprise_customer.uuid, course_id]<EOL>),<EOL>query_string=request.META['<STR_LIT>']<EOL>)<EOL><DEDENT>return redirect(<EOL>'<STR_LIT>'.format(<EOL>grant_data_sharing_url=reverse('<STR_LIT>'),<EOL>params=urlencode(<EOL>{<EOL>'<STR_LIT>': next_url,<EOL>'<STR_LIT>': failure_url,<EOL>'<STR_LIT>': enterprise_customer.uuid,<EOL>'<STR_LIT>': course_id,<EOL>}<EOL>)<EOL>)<EOL>)<EOL><DEDENT>premium_flow = LMS_START_PREMIUM_COURSE_FLOW_URL.format(course_id=course_id)<EOL>if enterprise_catalog_uuid:<EOL><INDENT>premium_flow += '<STR_LIT>'.format(<EOL>catalog_uuid=enterprise_catalog_uuid<EOL>)<EOL><DEDENT>return redirect(premium_flow)<EOL>

Process a submitted track selection form for the enterprise.


def get_context_from_db(self, consent_page, platform_name, item, context):

Make set of variables(populated from db) that will be used in data sharing consent page.


def get_enterprise_program_enrollment_page(self, request, enterprise_customer, program_details):

<EOL>organizations = program_details['<STR_LIT>']<EOL>organization = organizations[<NUM_LIT:0>] if organizations else {}<EOL>platform_name = get_configuration_value('<STR_LIT>', settings.PLATFORM_NAME)<EOL>program_title = program_details['<STR_LIT:title>']<EOL>program_type_details = program_details['<STR_LIT>']<EOL>program_type = program_type_details['<STR_LIT:name>']<EOL>program_courses = program_details['<STR_LIT>']<EOL>course_count = len(program_courses)<EOL>course_count_text = ungettext(<EOL>'<STR_LIT>',<EOL>'<STR_LIT>',<EOL>course_count,<EOL>).format(count=course_count)<EOL>effort_info_text = ungettext_min_max(<EOL>'<STR_LIT>',<EOL>'<STR_LIT>',<EOL>_('<STR_LIT>'),<EOL>program_details.get('<STR_LIT>'),<EOL>program_details.get('<STR_LIT>'),<EOL>)<EOL>length_info_text = ungettext_min_max(<EOL>'<STR_LIT>',<EOL>'<STR_LIT>',<EOL>_('<STR_LIT>'),<EOL>program_details.get('<STR_LIT>'),<EOL>program_details.get('<STR_LIT>'),<EOL>)<EOL>if program_details['<STR_LIT>']:<EOL><INDENT>purchase_action = _('<STR_LIT>')<EOL>item = _('<STR_LIT>')<EOL><DEDENT>else:<EOL><INDENT>purchase_action = _('<STR_LIT>')<EOL>item = _('<STR_LIT>')<EOL><DEDENT>program_data_sharing_consent = get_data_sharing_consent(<EOL>request.user.username,<EOL>enterprise_customer.uuid,<EOL>program_uuid=program_details['<STR_LIT>'],<EOL>)<EOL>if program_data_sharing_consent.exists and not program_data_sharing_consent.granted:<EOL><INDENT>messages.add_consent_declined_message(request, enterprise_customer, program_title)<EOL><DEDENT>discount_data = program_details.get('<STR_LIT>', {})<EOL>one_click_purchase_eligibility = program_details.get('<STR_LIT>', False)<EOL>if not one_click_purchase_eligibility:<EOL><INDENT>messages.add_unenrollable_item_message(request, '<STR_LIT>')<EOL><DEDENT>elif discount_data.get('<STR_LIT>') is None:<EOL><INDENT>messages.add_missing_price_information_message(request, program_title)<EOL><DEDENT>context_data = get_global_context(request, enterprise_customer)<EOL>context_data.update({<EOL>'<STR_LIT>': _('<STR_LIT>'),<EOL>'<STR_LIT>': _('<STR_LIT>'),<EOL>'<STR_LIT>': _("<STR_LIT>"),<EOL>'<STR_LIT>': <NUM_LIT:2>,<EOL>'<STR_LIT>': _('<STR_LIT>'),<EOL>'<STR_LIT>': <NUM_LIT:1>,<EOL>'<STR_LIT>': _('<STR_LIT>'),<EOL>'<STR_LIT>': _('<STR_LIT>'),<EOL>'<STR_LIT>': _('<STR_LIT>'),<EOL>'<STR_LIT>': _('<STR_LIT>'),<EOL>'<STR_LIT>': _('<STR_LIT>'),<EOL>'<STR_LIT>': _('<STR_LIT>'),<EOL>'<STR_LIT>': _('<STR_LIT>'),<EOL>'<STR_LIT>': _('<STR_LIT>'),<EOL>'<STR_LIT>': _('<STR_LIT>'),<EOL>'<STR_LIT>': _('<STR_LIT>'),<EOL>'<STR_LIT>': _('<STR_LIT>'),<EOL>'<STR_LIT>': _('<STR_LIT>'),<EOL>'<STR_LIT>': _('<STR_LIT>').format(<EOL>platform_name=platform_name,<EOL>program_type=program_type,<EOL>),<EOL>'<STR_LIT>': _('<STR_LIT>').format(<EOL>platform_name=platform_name<EOL>),<EOL>'<STR_LIT>': organization.get('<STR_LIT:name>'),<EOL>'<STR_LIT>': organization.get('<STR_LIT>'),<EOL>'<STR_LIT>': _('<STR_LIT>').format(organization=organization.get('<STR_LIT:name>')),<EOL>'<STR_LIT>': _('<STR_LIT>').format(item=item),<EOL>'<STR_LIT>': program_type_details['<STR_LIT>'].get('<STR_LIT>', {}).get('<STR_LIT:url>', '<STR_LIT>'),<EOL>'<STR_LIT>': program_type,<EOL>'<STR_LIT>': get_program_type_description(program_type),<EOL>'<STR_LIT>': program_title,<EOL>'<STR_LIT>': program_details['<STR_LIT>'],<EOL>'<STR_LIT>': program_details['<STR_LIT>'],<EOL>'<STR_LIT>': get_price_text(discount_data.get('<STR_LIT>', <NUM_LIT:0>), request),<EOL>'<STR_LIT>': get_price_text(discount_data.get('<STR_LIT>', <NUM_LIT:0>), request),<EOL>'<STR_LIT>': discount_data.get('<STR_LIT>', False),<EOL>'<STR_LIT>': program_courses,<EOL>'<STR_LIT>': [<EOL>_('<STR_LIT>'),<EOL>_('<STR_LIT>'),<EOL>],<EOL>'<STR_LIT>': _('<STR_LIT>').format(purchase_action=purchase_action),<EOL>'<STR_LIT>': program_details['<STR_LIT>'],<EOL>'<STR_LIT>': program_details['<STR_LIT>'],<EOL>'<STR_LIT>': course_count_text,<EOL>'<STR_LIT>': length_info_text,<EOL>'<STR_LIT>': effort_info_text,<EOL>'<STR_LIT>': one_click_purchase_eligibility,<EOL>})<EOL>return render(request, '<STR_LIT>', context=context_data)<EOL>

Render Enterprise-specific program enrollment page.


@method_decorator(enterprise_login_required)<EOL><INDENT>@method_decorator(force_fresh_session)<EOL>def get(self, request, *args, **kwargs):<DEDENT>

enterprise_customer_uuid, course_run_id, course_key, program_uuid = RouterView.get_path_variables(**kwargs)<EOL>enterprise_customer = get_enterprise_customer_or_404(enterprise_customer_uuid)<EOL>if course_key:<EOL><INDENT>try:<EOL><INDENT>course_run_id = RouterView.get_course_run_id(request.user, enterprise_customer, course_key)<EOL><DEDENT>except Http404:<EOL><INDENT>context_data = get_global_context(request, enterprise_customer)<EOL>error_code = '<STR_LIT>'<EOL>log_message = (<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'.format(<EOL>course_key=course_key,<EOL>course_run_id=course_run_id,<EOL>enterprise_customer_uuid=enterprise_customer_uuid,<EOL>error_code=error_code,<EOL>userid=request.user.id,<EOL>program_uuid=program_uuid,<EOL>)<EOL>)<EOL>return render_page_with_error_code_message(request, context_data, error_code, log_message)<EOL><DEDENT>kwargs['<STR_LIT>'] = course_run_id<EOL><DEDENT>with transaction.atomic():<EOL><INDENT>enterprise_customer_user, __ = EnterpriseCustomerUser.objects.get_or_create(<EOL>enterprise_customer=enterprise_customer,<EOL>user_id=request.user.id<EOL>)<EOL>enterprise_customer_user.update_session(request)<EOL><DEDENT>resource_id = course_run_id or program_uuid<EOL>if self.eligible_for_direct_audit_enrollment(request, enterprise_customer, resource_id, course_key):<EOL><INDENT>try:<EOL><INDENT>enterprise_customer_user.enroll(resource_id, '<STR_LIT>', cohort=request.GET.get('<STR_LIT>', None))<EOL>track_enrollment('<STR_LIT>', request.user.id, resource_id, request.get_full_path())<EOL><DEDENT>except (CourseEnrollmentDowngradeError, CourseEnrollmentPermissionError):<EOL><INDENT>pass<EOL><DEDENT>return redirect(LMS_COURSEWARE_URL.format(course_id=resource_id))<EOL><DEDENT>return self.redirect(request, *args, **kwargs)<EOL>

Run some custom GET logic for Enterprise workflows before routing the user through existing views.

In particular, before routing to existing views:
- If the requested resource is a course, find the current course run for that course,
  and make that course run the requested resource instead.
- Look to see whether a request is eligible for direct audit enrollment, and if so, directly enroll the user.


def get_base_details(self, request, enterprise_uuid, course_run_id):

enterprise_customer = get_enterprise_customer_or_404(enterprise_uuid)<EOL>enterprise_catalog_uuid = request.GET.get('<STR_LIT>')<EOL>enterprise_catalog = None<EOL>if enterprise_catalog_uuid:<EOL><INDENT>try:<EOL><INDENT>enterprise_catalog_uuid = UUID(enterprise_catalog_uuid)<EOL>enterprise_catalog = enterprise_customer.enterprise_customer_catalogs.get(<EOL>uuid=enterprise_catalog_uuid<EOL>)<EOL><DEDENT>except (ValueError, EnterpriseCustomerCatalog.DoesNotExist):<EOL><INDENT>LOGGER.warning(<EOL>'<STR_LIT>'.format(<EOL>enterprise_catalog_uuid=enterprise_catalog_uuid,<EOL>)<EOL>)<EOL>messages.add_generic_info_message_for_error(request)<EOL><DEDENT><DEDENT>course = None<EOL>course_run = None<EOL>course_modes = []<EOL>if enterprise_catalog:<EOL><INDENT>course, course_run = enterprise_catalog.get_course_and_course_run(course_run_id)<EOL><DEDENT>else:<EOL><INDENT>try:<EOL><INDENT>course, course_run = CourseCatalogApiServiceClient(<EOL>enterprise_customer.site<EOL>).get_course_and_course_run(course_run_id)<EOL><DEDENT>except ImproperlyConfigured:<EOL><INDENT>LOGGER.warning('<STR_LIT>')<EOL>messages.add_generic_info_message_for_error(request)<EOL>return enterprise_customer, course, course_run, course_modes<EOL><DEDENT><DEDENT>if not course or not course_run:<EOL><INDENT>course_id = course['<STR_LIT:key>'] if course else "<STR_LIT>"<EOL>course_title = course['<STR_LIT:title>'] if course else "<STR_LIT>"<EOL>course_run_title = course_run['<STR_LIT:title>'] if course_run else "<STR_LIT>"<EOL>enterprise_catalog_title = enterprise_catalog.title if enterprise_catalog else "<STR_LIT>"<EOL>LOGGER.warning(<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'.format(<EOL>course_title=course_title,<EOL>course_id=course_id,<EOL>course_run_title=course_run_title,<EOL>course_run_id=course_run_id,<EOL>enterprise_name=enterprise_customer.name,<EOL>enterprise_uuid=enterprise_customer.uuid,<EOL>enterprise_catalog_title=enterprise_catalog_title,<EOL>enterprise_catalog_uuid=enterprise_catalog_uuid,<EOL>)<EOL>)<EOL>messages.add_generic_info_message_for_error(request)<EOL>return enterprise_customer, course, course_run, course_modes<EOL><DEDENT>if enterprise_catalog_uuid and not enterprise_catalog:<EOL><INDENT>return enterprise_customer, course, course_run, course_modes<EOL><DEDENT>modes = self.get_available_course_modes(request, course_run_id, enterprise_catalog)<EOL>audit_modes = getattr(<EOL>settings,<EOL>'<STR_LIT>',<EOL>['<STR_LIT>', '<STR_LIT>']<EOL>)<EOL>for mode in modes:<EOL><INDENT>if mode['<STR_LIT>']:<EOL><INDENT>price_text = get_price_text(mode['<STR_LIT>'], request)<EOL><DEDENT>else:<EOL><INDENT>price_text = _('<STR_LIT>')<EOL><DEDENT>if mode['<STR_LIT>'] in audit_modes:<EOL><INDENT>description = _('<STR_LIT>')<EOL><DEDENT>else:<EOL><INDENT>description = _('<STR_LIT>')<EOL><DEDENT>course_modes.append({<EOL>'<STR_LIT>': mode['<STR_LIT>'],<EOL>'<STR_LIT>': mode['<STR_LIT>'],<EOL>'<STR_LIT>': mode['<STR_LIT>'],<EOL>'<STR_LIT:title>': mode['<STR_LIT:name>'],<EOL>'<STR_LIT>': price_text,<EOL>'<STR_LIT>': price_text,<EOL>'<STR_LIT:description>': description,<EOL>'<STR_LIT>': mode['<STR_LIT>'] not in audit_modes<EOL>})<EOL><DEDENT>return enterprise_customer, course, course_run, course_modes<EOL>

Retrieve fundamental details used by both POST and GET versions of this view.

Specifically, take an EnterpriseCustomer UUID and a course run ID, and transform those
into an actual EnterpriseCustomer, a set of details about the course, and a list
of the available course modes for that course run.


enterprise_customer_uuid = request.GET.get('<STR_LIT>')<EOL>success_url = request.GET.get('<STR_LIT>')<EOL>failure_url = request.GET.get('<STR_LIT>')<EOL>course_id = request.GET.get('<STR_LIT>', '<STR_LIT>')<EOL>program_uuid = request.GET.get('<STR_LIT>', '<STR_LIT>')<EOL>self.preview_mode = bool(request.GET.get('<STR_LIT>', False))<EOL>enterprise_customer = get_enterprise_customer_or_404(enterprise_customer_uuid)<EOL>context_data = get_global_context(request, enterprise_customer)<EOL>if not self.preview_mode:<EOL><INDENT>if not self.course_or_program_exist(course_id, program_uuid):<EOL><INDENT>error_code = '<STR_LIT>'<EOL>log_message = (<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'.format(<EOL>course_id=course_id,<EOL>program_uuid=program_uuid,<EOL>error_code=error_code,<EOL>userid=request.user.id,<EOL>enterprise_customer_uuid=enterprise_customer_uuid,<EOL>)<EOL>)<EOL>return render_page_with_error_code_message(request, context_data, error_code, log_message)<EOL><DEDENT>try:<EOL><INDENT>consent_record = get_data_sharing_consent(<EOL>request.user.username,<EOL>enterprise_customer_uuid,<EOL>program_uuid=program_uuid,<EOL>course_id=course_id<EOL>)<EOL><DEDENT>except NotConnectedToOpenEdX as error:<EOL><INDENT>error_code = '<STR_LIT>'<EOL>log_message = (<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'.format(<EOL>userid=request.user.id,<EOL>enterprise_customer_uuid=enterprise_customer_uuid,<EOL>error=error,<EOL>error_code=error_code,<EOL>course_id=course_id,<EOL>)<EOL>)<EOL>return render_page_with_error_code_message(request, context_data, error_code, log_message)<EOL><DEDENT>try:<EOL><INDENT>consent_required = consent_record.consent_required()<EOL><DEDENT>except AttributeError:<EOL><INDENT>consent_required = None<EOL><DEDENT>if consent_record is None or not consent_required:<EOL><INDENT>error_code = '<STR_LIT>'<EOL>log_message = (<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'.format(<EOL>userid=request.user.id,<EOL>enterprise_customer_uuid=enterprise_customer_uuid,<EOL>consent_record=consent_record,<EOL>consent_required=consent_required,<EOL>error_code=error_code,<EOL>course_id=course_id,<EOL>)<EOL>)<EOL>return render_page_with_error_code_message(request, context_data, error_code, log_message)<EOL><DEDENT>else:<EOL><INDENT>enterprise_customer = consent_record.enterprise_customer<EOL><DEDENT><DEDENT>elif not request.user.is_staff:<EOL><INDENT>raise PermissionDenied()<EOL><DEDENT>context_data = get_global_context(request, enterprise_customer)<EOL>if not (enterprise_customer_uuid and success_url and failure_url):<EOL><INDENT>error_code = '<STR_LIT>'<EOL>log_message = (<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'.format(<EOL>userid=request.user.id,<EOL>enterprise_customer_uuid=enterprise_customer_uuid,<EOL>success_url=success_url,<EOL>failure_url=failure_url,<EOL>error_code=error_code,<EOL>course_id=course_id,<EOL>)<EOL>)<EOL>return render_page_with_error_code_message(request, context_data, error_code, log_message)<EOL><DEDENT>try:<EOL><INDENT>updated_context_dict = self.get_course_or_program_context(<EOL>enterprise_customer,<EOL>course_id=course_id,<EOL>program_uuid=program_uuid<EOL>)<EOL>context_data.update(updated_context_dict)<EOL><DEDENT>except Http404:<EOL><INDENT>error_code = '<STR_LIT>'<EOL>log_message = (<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'.format(<EOL>error_code=error_code,<EOL>userid=request.user.id,<EOL>enterprise_customer=enterprise_customer.uuid,<EOL>course_id=course_id,<EOL>)<EOL>)<EOL>return render_page_with_error_code_message(request, context_data, error_code, log_message)<EOL><DEDENT>item = '<STR_LIT>' if course_id else '<STR_LIT>'<EOL>context_data.update({<EOL>'<STR_LIT>': _(<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>).format(<EOL>enterprise_customer_name=enterprise_customer.name,<EOL>bold_start='<STR_LIT>',<EOL>bold_end='<STR_LIT>',<EOL>item=item,<EOL>),<EOL>'<STR_LIT>': _(<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>).format(<EOL>enterprise_customer_name=enterprise_customer.name,<EOL>bold_start='<STR_LIT>',<EOL>bold_end='<STR_LIT>',<EOL>item=item,<EOL>),<EOL>'<STR_LIT>': success_url,<EOL>'<STR_LIT>': failure_url,<EOL>'<STR_LIT>': request.GET.get('<STR_LIT>') is not None,<EOL>'<STR_LIT>': [<EOL>_('<STR_LIT>').format(item=item),<EOL>_('<STR_LIT>'),<EOL>_('<STR_LIT>'),<EOL>],<EOL>'<STR_LIT>': '<STR_LIT>',<EOL>})<EOL>platform_name = context_data['<STR_LIT>']<EOL>published_only = False if self.preview_mode else True<EOL>enterprise_consent_page = enterprise_customer.get_data_sharing_consent_text_overrides(<EOL>published_only=published_only<EOL>)<EOL>if enterprise_consent_page:<EOL><INDENT>context_data.update(self.get_context_from_db(enterprise_consent_page, platform_name, item, context_data))<EOL><DEDENT>else:<EOL><INDENT>context_data.update(self.get_default_context(enterprise_customer, platform_name))<EOL><DEDENT>return render(request, '<STR_LIT>', context=context_data)<EOL>

Render a form to collect user input about data sharing consent.


@staticmethod<EOL><INDENT>def get_course_run_id(user, enterprise_customer, course_key):<DEDENT>

try:<EOL><INDENT>course = CourseCatalogApiServiceClient(enterprise_customer.site).get_course_details(course_key)<EOL><DEDENT>except ImproperlyConfigured:<EOL><INDENT>raise Http404<EOL><DEDENT>users_all_enrolled_courses = EnrollmentApiClient().get_enrolled_courses(user.username)<EOL>users_active_course_runs = get_active_course_runs(<EOL>course,<EOL>users_all_enrolled_courses<EOL>) if users_all_enrolled_courses else []<EOL>course_run = get_current_course_run(course, users_active_course_runs)<EOL>if course_run:<EOL><INDENT>course_run_id = course_run['<STR_LIT:key>']<EOL>return course_run_id<EOL><DEDENT>else:<EOL><INDENT>raise Http404<EOL><DEDENT>

User is requesting a course, we need to translate that into the current course run.

:param user:
:param enterprise_customer:
:param course_key:
:return: course_run_id


def get_course_or_program_context(self, enterprise_customer, course_id=None, program_uuid=None):

context_data = {}<EOL>if course_id:<EOL><INDENT>context_data.update({'<STR_LIT>': course_id, '<STR_LIT>': True})<EOL>if not self.preview_mode:<EOL><INDENT>try:<EOL><INDENT>catalog_api_client = CourseCatalogApiServiceClient(enterprise_customer.site)<EOL><DEDENT>except ImproperlyConfigured:<EOL><INDENT>raise Http404<EOL><DEDENT>course_run_details = catalog_api_client.get_course_run(course_id)<EOL>course_start_date = '<STR_LIT>'<EOL>if course_run_details['<STR_LIT:start>']:<EOL><INDENT>course_start_date = parse(course_run_details['<STR_LIT:start>']).strftime('<STR_LIT>')<EOL><DEDENT>context_data.update({<EOL>'<STR_LIT>': course_run_details['<STR_LIT:title>'],<EOL>'<STR_LIT>': course_start_date,<EOL>})<EOL><DEDENT>else:<EOL><INDENT>context_data.update({<EOL>'<STR_LIT>': '<STR_LIT>',<EOL>'<STR_LIT>': datetime.datetime.now().strftime('<STR_LIT>'),<EOL>})<EOL><DEDENT><DEDENT>else:<EOL><INDENT>context_data.update({<EOL>'<STR_LIT>': program_uuid,<EOL>'<STR_LIT>': True,<EOL>})<EOL><DEDENT>return context_data<EOL>

Return a dict having course or program specific keys for data sharing consent page.


@method_decorator(enterprise_login_required)<EOL><INDENT>def post(self, request, enterprise_uuid, program_uuid):<DEDENT>

verify_edx_resources()<EOL>enterprise_customer = get_enterprise_customer_or_404(enterprise_uuid)<EOL>with transaction.atomic():<EOL><INDENT>enterprise_customer_user, __ = EnterpriseCustomerUser.objects.get_or_create(<EOL>enterprise_customer=enterprise_customer,<EOL>user_id=request.user.id<EOL>)<EOL>enterprise_customer_user.update_session(request)<EOL><DEDENT>context_data = get_global_context(request, enterprise_customer)<EOL>program_details, error_code = self.get_program_details(request, program_uuid, enterprise_customer)<EOL>if error_code:<EOL><INDENT>return render(<EOL>request,<EOL>ENTERPRISE_GENERAL_ERROR_PAGE,<EOL>context=context_data,<EOL>status=<NUM_LIT>,<EOL>)<EOL><DEDENT>if program_details['<STR_LIT>']:<EOL><INDENT>return redirect(LMS_PROGRAMS_DASHBOARD_URL.format(uuid=program_uuid))<EOL><DEDENT>basket_page = '<STR_LIT>'.format(<EOL>basket_url=BASKET_URL,<EOL>params=urlencode(<EOL>[tuple(['<STR_LIT>', sku]) for sku in program_details['<STR_LIT>']] +<EOL>[tuple(['<STR_LIT>', program_uuid])]<EOL>)<EOL>)<EOL>if get_data_sharing_consent(<EOL>enterprise_customer_user.username,<EOL>enterprise_customer.uuid,<EOL>program_uuid=program_uuid,<EOL>).consent_required():<EOL><INDENT>return redirect(<EOL>'<STR_LIT>'.format(<EOL>grant_data_sharing_url=reverse('<STR_LIT>'),<EOL>params=urlencode(<EOL>{<EOL>'<STR_LIT>': basket_page,<EOL>'<STR_LIT>': reverse(<EOL>'<STR_LIT>',<EOL>args=[enterprise_customer.uuid, program_uuid]<EOL>),<EOL>'<STR_LIT>': enterprise_customer.uuid,<EOL>'<STR_LIT>': program_uuid,<EOL>}<EOL>)<EOL>)<EOL>)<EOL><DEDENT>return redirect(basket_page)<EOL>


def course_or_program_exist(self, course_id, program_uuid):

course_exists = course_id and CourseApiClient().get_course_details(course_id)<EOL>program_exists = program_uuid and CourseCatalogApiServiceClient().program_exists(program_uuid)<EOL>return course_exists or program_exists<EOL>

Return whether the input course or program exist.


def get_default_context(self, enterprise_customer, platform_name):

Get the set of variables that will populate the template by default.


return json.dumps(COURSE_MODE_SORT_ORDER)<EOL>


def add_consent_declined_message(request, enterprise_customer, item):

Add a message to the Django messages store indicating that the user has declined data sharing consent.

Arguments:
    request (HttpRequest): The current request.
    enterprise_customer (EnterpriseCustomer): The EnterpriseCustomer associated with this request.
    item (str): A string containing information about the item for which consent was declined.


Add a message to the Django message store indicating that the item (i.e. course run, program) is unenrollable.

:param request: The current request.
:param item: The item that is unenrollable (i.e. a course run).


def post(self, request, enterprise_customer_uuid):

transmit_courses_metadata_form = TransmitEnterpriseCoursesForm(request.POST)<EOL>if transmit_courses_metadata_form.is_valid():<EOL><INDENT>channel_worker_username = transmit_courses_metadata_form.cleaned_data['<STR_LIT>']<EOL>call_command(<EOL>'<STR_LIT>',<EOL>'<STR_LIT>', channel_worker_username,<EOL>enterprise_customer=enterprise_customer_uuid<EOL>)<EOL>return HttpResponseRedirect('<STR_LIT>')<EOL><DEDENT>context = self._build_context(request, enterprise_customer_uuid)<EOL>context.update({self.ContextParameters.TRANSMIT_COURSES_METADATA_FORM: transmit_courses_metadata_form})<EOL>return render(request, self.template, context)<EOL>

Handle POST request - handle form submissions.

Arguments:
    request (django.http.request.HttpRequest): Request instance
    enterprise_customer_uuid (str): Enterprise Customer UUID


return request.user.first_name or request.user.username<EOL>


def get_enterprise_customer_user_queryset(self, request, search_keyword, customer_uuid, page_size=PAGE_SIZE):

page = request.GET.get('<STR_LIT>', <NUM_LIT:1>)<EOL>learners = EnterpriseCustomerUser.objects.filter(enterprise_customer__uuid=customer_uuid)<EOL>user_ids = learners.values_list('<STR_LIT>', flat=True)<EOL>matching_users = User.objects.filter(pk__in=user_ids)<EOL>if search_keyword is not None:<EOL><INDENT>matching_users = matching_users.filter(<EOL>Q(email__icontains=search_keyword) | Q(username__icontains=search_keyword)<EOL>)<EOL><DEDENT>matching_user_ids = matching_users.values_list('<STR_LIT>', flat=True)<EOL>learners = learners.filter(user_id__in=matching_user_ids)<EOL>return paginated_list(learners, page, page_size)<EOL>

Get the list of EnterpriseCustomerUsers we want to render.

Arguments:
    request (HttpRequest): HTTP Request instance.
    search_keyword (str): The keyword to search for in users' email addresses and usernames.
    customer_uuid (str): A unique identifier to filter down to only users linked to a
    particular EnterpriseCustomer.
    page_size (int): Number of learners displayed in each paginated set.


@classmethod<EOL><INDENT>def is_user_enrolled(cls, user, course_id, course_mode):<DEDENT>

enrollment_client = EnrollmentApiClient()<EOL>try:<EOL><INDENT>enrollments = enrollment_client.get_course_enrollment(user.username, course_id)<EOL>if enrollments and course_mode == enrollments.get('<STR_LIT>'):<EOL><INDENT>return True<EOL><DEDENT><DEDENT>except HttpClientError as exc:<EOL><INDENT>logging.error(<EOL>'<STR_LIT>',<EOL>dict(user=user.username, message=str(exc))<EOL>)<EOL><DEDENT>except KeyError as exc:<EOL><INDENT>logging.warning(<EOL>'<STR_LIT>',<EOL>dict(user=user.username, message=str(exc))<EOL>)<EOL><DEDENT>return False<EOL>

Query the enrollment API and determine if a learner is enrolled in a given course run track.

Args:
    user: The user whose enrollment needs to be checked
    course_mode: The mode with which the enrollment should be checked
    course_id: course id of the course where enrollment should be checked.

Returns:
    Boolean: Whether or not enrollment exists