<commit_before>"""
Some utilities for work with units of physical quantities.
"""
from __future__ import absolute_import
import six
from six.moves import range
try:
    import sympy as sm
except ImportError:
    sm = None

import numpy as nm

from sfepy.base.base import get_default, invert_dict, Struct

default_units_of_basic_quantities = {
    'length' : 'm',
    'time' : 's',
    'mass' : 'kg',
    'temperature' : 'C',
}

# Cannot use N for Newton as it is a sympy function...
derived_units = {
    'Newton' : '(kg * m) / s**2',
    'Pa' : 'kg / (m * s**2)', # N / m**2
    'J' : '(kg * m**2) / s**2', # N m
}

units_of_quantities = {
    'density' : 'g / m**3',
    'force' : 'Newton',
    'stress' : 'Pa',
    'energy' : 'J',
    'thermal_expandability' : 'Pa / C',
}

prefixes = {
    'p'  : 1e-12,
    'n'  : 1e-9,
    'mu' : 1e-6,
    'm'  : 1e-3,
    'c'  : 1e-2,
    ''   : 1e0,
    'd'  : 1e1,
    'k'  : 1e3,
    'M'  : 1e6,
    'G'  : 1e9,
    'T'  : 1e12,
}

inv_prefixes = invert_dict(prefixes)

num_prefixes = [str(ii) for ii in range(-12, 13)]
prefixes.update(dict(((key, 10**int(key)) for key in num_prefixes)))

class Unit(Struct):
    """
    A unit of a physical quantity. The prefix and coefficient of the unit
    are determined from to its name.

    Examples
    --------
    Construct some units:

    >>> from sfepy.mechanics.units import Unit
    >>> unit = Unit('mm')
    >>> print unit
    Unit:mm
      coef:
        0.001
      name:
        mm
      prefix:
        m
      prefix_length:
        1
      unit:
        m
    >>> unit = Unit('kg')
    >>> print unit
    Unit:kg
      coef:
        1000.0
      name:
        kg
      prefix:
        k
      prefix_length:
        1
      unit:
        g

    Get prefixes for a coefficient:

    >>> Unit.get_prefix(100.0)
    ('d', 10.0)
    >>> Unit.get_prefix(100.0, omit=('d',))
    ('k', 0.10000000000000001)
    """

    @staticmethod
    def get_prefix(coef, bias=0.1, omit=None):
        """
        Get the prefix and numerical multiplier corresponding to a numerical
        coefficient, omitting prefixes in omit tuple.
        """
        if omit is None:
            omit = num_prefixes

        values = [val for key, val in six.iteritems(prefixes) if key not in omit]
        coefs = nm.array(values, dtype=nm.float64)
        coefs.sort()
        ii = nm.searchsorted(coefs, bias*coef, side='left')

        if ii == len(coefs):
            ii = ii - 1

        cc = coefs[ii]
        prefix = inv_prefixes[cc]
        mul = coef / cc

        return prefix, mul

    def __init__(self, name):
        self.name = name

        aux = sorted(list(prefixes.keys()), reverse=True)
        for prefix in aux:
            lp = len(prefix)
            if (prefix == name[:lp]) and (lp < len(name)): break

        self.prefix = prefix
        self.prefix_length = len(prefix)
        self.unit = name[self.prefix_length:]

        self.coef = prefixes[self.prefix]

class Quantity(Struct):
    """
    A physical quantity in a given set of basic units.

    Examples
    --------

    Construct the stress quantity:

    >>> from sfepy.mechanics.units import Unit, Quantity
    >>> units = ['m', 's', 'kg', 'C']
    >>> unit_set = [Unit(key) for key in units]
    >>> q1 = Quantity('stress', unit_set)
    >>> q1()
    '1.0 Pa'

    Show its unit using various prefixes:

    >>> q1('m')
    '1000.0 mPa'
    >>> q1('')
    '1.0 Pa'
    >>> q1('k')
    '0.001 kPa'
    >>> q1('M')
    '1e-06 MPa'

    Construct the stress quantity in another unit set:

    >>> units = ['mm', 's', 'kg', 'C']
    >>> unit_set = [Unit(key) for key in units]
    >>> q2 = Quantity('stress', unit_set)
    >>> q2()
    '1.0 kPa'

    Show its unit using various prefixes:

    >>> q2('m')
    '1000000.0 mPa'
    >>> q2('')
    '1000.0 Pa'
    >>> q2('k')
    '1.0 kPa'
    >>> q2('M')
    '0.001 MPa'
    """

    def __init__(self, name, unit_set):
        """
        Create a quantity in the given unit set. The name must be listed in the
        units_of_quantities dictionary."""
        self.name = name
        self.unit_set = unit_set

        self.unit_name = units_of_quantities[self.name]

        unit_expr = sm.sympify(self.unit_name)
        unit_expr = unit_expr.subs(derived_units)

        self.symbolic_value = sm.sympify(unit_expr)
        atoms = self.symbolic_value.atoms(sm.Symbol)
        self.def_units = [Unit(atom.name) for atom in atoms]

        self.def_names, self.def_units = self._get_dicts(self.def_units)
        self.names, self.units = self._get_dicts(self.unit_set)

        self.def_coef = float(self.symbolic_value.subs(self.def_names))

        coef_dict = {}
        for key, val in six.iteritems(self.def_units):
            coef_dict[val.name] = self.units[key].coef
        self.coef_dict = coef_dict

        self.raw_coef = float(self.symbolic_value.subs(self.coef_dict))
        self.coef = self.raw_coef / self.def_coef

    def _get_dicts(self, unit_set):
        """Get auxiliary dictionaries for a unit set."""
        name_dict = {}
        unit_dict = {}
        for unit in unit_set:
            name_dict[unit.name] = unit.coef
            unit_dict[unit.unit] = unit

        return name_dict, unit_dict

    def __call__(self, prefix=None, omit=None):
        """Get the quantity units."""
        if prefix is None:
            if omit is None:
                omit = ['c', 'd'] + num_prefixes
            prefix, mul = Unit.get_prefix(self.coef, omit=omit)

        else:
            coef = prefixes[prefix]
            mul = self.coef / coef

        return '%s %s%s' % (mul, prefix, self.unit_name)

def get_consistent_unit_set(length=None, time=None, mass=None, temperature=None):
    """Given a set of basic units, return a consistent set of derived units for
    quantities listed in the units_of_quantities dictionary."""
    defaults = default_units_of_basic_quantities
    length = get_default(length, defaults['length'])
    time = get_default(time, defaults['time'])
    mass = get_default(mass, defaults['mass'])
    temperature = get_default(temperature, defaults['temperature'])

    unit_set = [Unit(length), Unit(time), Unit(mass), Unit(temperature)]

    derived_units = {}

    for quantity_name in units_of_quantities.keys():
        quantity = Quantity(quantity_name, unit_set)

        derived_units[quantity_name] = quantity()

    return derived_units
<commit_msg>fix Quantity.__init__() for sympy 1.1<commit_after>"""
Some utilities for work with units of physical quantities.
"""
from __future__ import absolute_import
import six
from six.moves import range
try:
    import sympy as sm
except ImportError:
    sm = None

import numpy as nm

from sfepy.base.base import get_default, invert_dict, Struct

default_units_of_basic_quantities = {
    'length' : 'm',
    'time' : 's',
    'mass' : 'kg',
    'temperature' : 'C',
}

# Cannot use N for Newton as it is a sympy function...
derived_units = {
    'Newton' : '(kg * m) / s**2',
    'Pa' : 'kg / (m * s**2)', # N / m**2
    'J' : '(kg * m**2) / s**2', # N m
}

units_of_quantities = {
    'density' : 'g / m**3',
    'force' : 'Newton',
    'stress' : 'Pa',
    'energy' : 'J',
    'thermal_expandability' : 'Pa / C',
}

prefixes = {
    'p'  : 1e-12,
    'n'  : 1e-9,
    'mu' : 1e-6,
    'm'  : 1e-3,
    'c'  : 1e-2,
    ''   : 1e0,
    'd'  : 1e1,
    'k'  : 1e3,
    'M'  : 1e6,
    'G'  : 1e9,
    'T'  : 1e12,
}

inv_prefixes = invert_dict(prefixes)

num_prefixes = [str(ii) for ii in range(-12, 13)]
prefixes.update(dict(((key, 10**int(key)) for key in num_prefixes)))

class Unit(Struct):
    """
    A unit of a physical quantity. The prefix and coefficient of the unit
    are determined from to its name.

    Examples
    --------
    Construct some units:

    >>> from sfepy.mechanics.units import Unit
    >>> unit = Unit('mm')
    >>> print unit
    Unit:mm
      coef:
        0.001
      name:
        mm
      prefix:
        m
      prefix_length:
        1
      unit:
        m
    >>> unit = Unit('kg')
    >>> print unit
    Unit:kg
      coef:
        1000.0
      name:
        kg
      prefix:
        k
      prefix_length:
        1
      unit:
        g

    Get prefixes for a coefficient:

    >>> Unit.get_prefix(100.0)
    ('d', 10.0)
    >>> Unit.get_prefix(100.0, omit=('d',))
    ('k', 0.10000000000000001)
    """

    @staticmethod
    def get_prefix(coef, bias=0.1, omit=None):
        """
        Get the prefix and numerical multiplier corresponding to a numerical
        coefficient, omitting prefixes in omit tuple.
        """
        if omit is None:
            omit = num_prefixes

        values = [val for key, val in six.iteritems(prefixes) if key not in omit]
        coefs = nm.array(values, dtype=nm.float64)
        coefs.sort()
        ii = nm.searchsorted(coefs, bias*coef, side='left')

        if ii == len(coefs):
            ii = ii - 1

        cc = coefs[ii]
        prefix = inv_prefixes[cc]
        mul = coef / cc

        return prefix, mul

    def __init__(self, name):
        self.name = name

        aux = sorted(list(prefixes.keys()), reverse=True)
        for prefix in aux:
            lp = len(prefix)
            if (prefix == name[:lp]) and (lp < len(name)): break

        self.prefix = prefix
        self.prefix_length = len(prefix)
        self.unit = name[self.prefix_length:]

        self.coef = prefixes[self.prefix]

class Quantity(Struct):
    """
    A physical quantity in a given set of basic units.

    Examples
    --------

    Construct the stress quantity:

    >>> from sfepy.mechanics.units import Unit, Quantity
    >>> units = ['m', 's', 'kg', 'C']
    >>> unit_set = [Unit(key) for key in units]
    >>> q1 = Quantity('stress', unit_set)
    >>> q1()
    '1.0 Pa'

    Show its unit using various prefixes:

    >>> q1('m')
    '1000.0 mPa'
    >>> q1('')
    '1.0 Pa'
    >>> q1('k')
    '0.001 kPa'
    >>> q1('M')
    '1e-06 MPa'

    Construct the stress quantity in another unit set:

    >>> units = ['mm', 's', 'kg', 'C']
    >>> unit_set = [Unit(key) for key in units]
    >>> q2 = Quantity('stress', unit_set)
    >>> q2()
    '1.0 kPa'

    Show its unit using various prefixes:

    >>> q2('m')
    '1000000.0 mPa'
    >>> q2('')
    '1000.0 Pa'
    >>> q2('k')
    '1.0 kPa'
    >>> q2('M')
    '0.001 MPa'
    """

    def __init__(self, name, unit_set):
        """
        Create a quantity in the given unit set. The name must be listed in the
        units_of_quantities dictionary."""
        self.name = name
        self.unit_set = unit_set

        self.unit_name = units_of_quantities[self.name]

        unit_expr = sm.sympify(self.unit_name)
        unit_expr = unit_expr.subs(derived_units)

        self.symbolic_value = sm.sympify(str(unit_expr))
        atoms = self.symbolic_value.atoms(sm.Symbol)
        self.def_units = [Unit(atom.name) for atom in atoms]

        self.def_names, self.def_units = self._get_dicts(self.def_units)
        self.names, self.units = self._get_dicts(self.unit_set)

        self.def_coef = float(self.symbolic_value.subs(self.def_names))

        coef_dict = {}
        for key, val in six.iteritems(self.def_units):
            coef_dict[val.name] = self.units[key].coef
        self.coef_dict = coef_dict

        self.raw_coef = float(self.symbolic_value.subs(self.coef_dict))
        self.coef = self.raw_coef / self.def_coef

    def _get_dicts(self, unit_set):
        """Get auxiliary dictionaries for a unit set."""
        name_dict = {}
        unit_dict = {}
        for unit in unit_set:
            name_dict[unit.name] = unit.coef
            unit_dict[unit.unit] = unit

        return name_dict, unit_dict

    def __call__(self, prefix=None, omit=None):
        """Get the quantity units."""
        if prefix is None:
            if omit is None:
                omit = ['c', 'd'] + num_prefixes
            prefix, mul = Unit.get_prefix(self.coef, omit=omit)

        else:
            coef = prefixes[prefix]
            mul = self.coef / coef

        return '%s %s%s' % (mul, prefix, self.unit_name)

def get_consistent_unit_set(length=None, time=None, mass=None, temperature=None):
    """Given a set of basic units, return a consistent set of derived units for
    quantities listed in the units_of_quantities dictionary."""
    defaults = default_units_of_basic_quantities
    length = get_default(length, defaults['length'])
    time = get_default(time, defaults['time'])
    mass = get_default(mass, defaults['mass'])
    temperature = get_default(temperature, defaults['temperature'])

    unit_set = [Unit(length), Unit(time), Unit(mass), Unit(temperature)]

    derived_units = {}

    for quantity_name in units_of_quantities.keys():
        quantity = Quantity(quantity_name, unit_set)

        derived_units[quantity_name] = quantity()

    return derived_units
<|endoftext|>


<commit_before>
from sans.models.BaseComponent import BaseComponent
import numpy, math
import copy
from sans.models.pluginmodel import Model1DPlugin
from sans.models.DiamCylFunc import  DiamCylFunc
from sans.models.DiamEllipFunc import  DiamEllipFunc
class MultiplicationModel(BaseComponent):
    """
        Use for P(Q)*S(Q); function call maut be in order of P(Q) and then S(Q).
        Perform multplication of two models.
        Contains the models parameters combined.
    """
    def __init__(self, model1, model2 ):
        BaseComponent.__init__(self)

        ## Setting  model name model description
        self.description=""
        if  model1.name != "NoStructure"and  model2.name != "NoStructure":
             self.name = model1.name +" * "+ model2.name
             self.description= self.name+"\n"
             self.description +="see %s description and %s description"%( model1.name,
                                                                         model2.name )
        elif  model2.name != "NoStructure":
            self.name = model2.name
            self.description= model2.description
        else :
            self.name = model1.name
            self.description= model1.description

        #For virial coefficients for only two P(Q) models,"CylinderModel","EllipsoidModel". SphereModel works w/o it.
        modelDiam = None
        if model1.__class__.__name__ == "CylinderModel":
            Model1DPlugin("DiamCylFunc")
            modelDiam = DiamCylFunc()
            para1 = 'radius'
            para2 = 'length'

        elif model1.__class__.__name__  == "EllipsoidModel":
            Model1DPlugin("DiamEllipFunc")
            modelDiam = DiamEllipFunc()
            para1 = 'radius_a'
            para2 = 'radius_b'

        self.modelD = modelDiam

        if model1.__class__.__name__ == "CylinderModel" \
            or model1.__class__.__name__  == "EllipsoidModel":

            self.para1 = para1
            self.para2 = para2

        self.model1= model1
        self.model2= model2

        ## dispersion
        self._set_dispersion()
        ## Define parameters
        self._set_params()
        ## Parameter details [units, min, max]
        self._set_details()
        #list of parameter that can be fitted
        self._set_fixed_params()
        ## parameters with orientation
        for item in self.model1.orientation_params:
            self.orientation_params.append(item)

        for item in self.model2.orientation_params:
            if not item in self.orientation_params:
                self.orientation_params.append(item)

    def _clone(self, obj):
        """
            Internal utility function to copy the internal
            data members to a fresh copy.
        """
        obj.params     = copy.deepcopy(self.params)
        obj.description     = copy.deepcopy(self.description)
        obj.details    = copy.deepcopy(self.details)
        obj.dispersion = copy.deepcopy(self.dispersion)
        obj.model1  = self.model1.clone()
        obj.model2  = self.model2.clone()

        return obj

    def _set_dispersion(self):
        """
           combined the two models dispersions
        """
        for name , value in self.model1.dispersion.iteritems():
            self.dispersion[name]= value

        for name , value in self.model2.dispersion.iteritems():
            # S(Q) has only 'radius' for dispersion.
            if not name in self.dispersion.keys()and name !='radius':
                self.dispersion[name]= value

    def _set_params(self):
        """
            Concatenate the parameters of the two models to create
            this model parameters
        """

        for name , value in self.model1.params.iteritems():
            self.params[name]= value

            if self.modelD !=None:
                if name == self.para1 or name == self.para2:
                    self.modelD.params[name]= value
                elif name in self.model2.getParamList() and name !='radius':
                    self.model2.setParam( name, value)

            elif name in self.model2.getParamList():
                self.model2.setParam(name, value)
        if self.modelD !=None:
            self.model2.setParam('radius', self.modelD.run())

        for name , value in self.model2.params.iteritems():
            if not name in self.params.keys()and name != 'radius':
                self.params[name]= value

    def _set_details(self):
        """
            Concatenate details of the two models to create
            this model details
        """
        for name ,detail in self.model1.details.iteritems():
            self.details[name]= detail

        for name , detail in self.model2.details.iteritems():
            if not name in self.details.keys()and name != 'radius':
                self.details[name]= detail

    def setParam(self, name, value):
        """
            Set the value of a model parameter

            @param name: name of the parameter
            @param value: value of the parameter
        """

        self._setParamHelper( name, value)

        if name in self.model1.getParamList():
            self.model1.setParam( name, value)
        if self.modelD !=None:
            if name==self.para1 or name == self.para2:
                    self.modelD.params[name]= value
                    self.model2.setParam('radius', self.modelD.run())
            elif name in self.model2.getParamList():
                        self.model2.setParam( name, value)
        else:
            if name in self.model2.getParamList():
                self.model2.setParam( name, value)

        self._setParamHelper( name, value)

    def _setParamHelper(self, name, value):
        """
            Helper function to setparam
        """
        # Look for dispersion parameters
        toks = name.split('.')
        if len(toks)==2:
            for item in self.dispersion.keys():
                if item.lower()==toks[0].lower():
                    for par in self.dispersion[item]:
                        if par.lower() == toks[1].lower():
                            self.dispersion[item][par] = value
                            return
        else:
            # Look for standard parameter
            for item in self.params.keys():
                if item.lower()==name.lower():
                    self.params[item] = value
                    return

        raise ValueError, "Model does not contain parameter %s" % name

    def _set_fixed_params(self):
        """
             fill the self.fixed list with the two models fixed list
        """
        for item in self.model1.fixed:
            self.fixed.append(item)

        for item in self.model2.fixed:
            if not item in self.fixed:
                self.fixed.append(item)
        self.fixed.sort()

    def run(self, x = 0.0):
        """ Evaluate the model
            @param x: input q-value (float or [float, float] as [r, theta])
            @return: (DAB value)
        """
        return self.model1.run(x)*self.model2.run(x)

    def runXY(self, x = 0.0):
        """ Evaluate the model
            @param x: input q-value (float or [float, float] as [qx, qy])
            @return: DAB value
        """
        return self.model1.runXY(x)* self.model2.runXY(x)

    def set_dispersion(self, parameter, dispersion):
        """
            Set the dispersion object for a model parameter
            @param parameter: name of the parameter [string]
            @dispersion: dispersion object of type DispersionModel
        """
        value= None
        try:
            if parameter in self.model1.dispersion.keys():
                value= self.model1.set_dispersion(parameter, dispersion)
            #There is no dispersion for the structure factors(S(Q)).
            #ToDo: need to decide whether or not the dispersion for S(Q) has to be considered for P*S.
            elif parameter in self.model2.dispersion.keys()and name !='radius':
                value= self.model2.set_dispersion(parameter, dispersion)
            self._set_dispersion()
            return value
        except:
            raise

    <commit_msg>Just for recode for the last version of old P*S code before effective radius implementation in model function: Newer one is coming<commit_after>
from sans.models.BaseComponent import BaseComponent
import numpy, math
import copy
from sans.models.pluginmodel import Model1DPlugin
from sans.models.DiamCylFunc import  DiamCylFunc
from sans.models.DiamEllipFunc import  DiamEllipFunc
class MultiplicationModel(BaseComponent):
    """
        Use for P(Q)*S(Q); function call maut be in order of P(Q) and then S(Q).
        Perform multplication of two models.
        Contains the models parameters combined.
    """
    def __init__(self, model1, model2 ):
        BaseComponent.__init__(self)

        ## Setting  model name model description
        self.description=""
        if  model1.name != "NoStructure" and  model2.name != "NoStructure":
             self.name = model1.name +" * "+ model2.name
             self.description= self.name+"\n"
             self.description +="see %s description and %s description"%( model1.name,
                                                                         model2.name )
        elif  model2.name != "NoStructure":
            self.name = model2.name
            self.description= model2.description
        else :
            self.name = model1.name
            self.description= model1.description

        self.model1= model1
        self.model2= model2

        ## Define diaparams
        self._set_diaparams()
        ## dispersion
        self._set_dispersion()
        ## Define parameters
        self._set_params()
        ## Parameter details [units, min, max]
        self._set_details()
        #list of parameter that can be fitted
        self._set_fixed_params()
        ## parameters with orientation
        for item in self.model1.orientation_params:
            self.orientation_params.append(item)

        for item in self.model2.orientation_params:
            if not item in self.orientation_params:
                self.orientation_params.append(item)

    def _clone(self, obj):
        """
            Internal utility function to copy the internal
            data members to a fresh copy.
        """
        obj.params     = copy.deepcopy(self.params)
        obj.description     = copy.deepcopy(self.description)
        obj.details    = copy.deepcopy(self.details)
        obj.dispersion = copy.deepcopy(self.dispersion)
        obj.model1  = self.model1.clone()
        obj.model2  = self.model2.clone()

        return obj

    def _set_dispersion(self):
        """
           combined the two models dispersions
        """
        for name , value in self.model1.dispersion.iteritems():
            self.dispersion[name]= value

        for name , value in self.model2.dispersion.iteritems():
            # S(Q) has only 'radius' for dispersion.
            if not name in self.dispersion.keys()and name !='radius':
                self.dispersion[name]= value

    def _set_params(self):
        """
            Concatenate the parameters of the two models to create
            this model parameters
        """
        #Prepare for radius calculation for Diam** functions
        #Only allows two case of radius modifications (radius = core_radius + thickness or just radius =radius).
        dia_rad = 0

        for name , value in self.model1.params.iteritems():
            self.params[name]= value

            if self.model2.name != 'NoStructure':
                if len(self.diapara[self.para[0]])>1 and \
                        (name == self.diapara[self.para[0]][0] or \
                         name == self.diapara[self.para[0]][1]):
                    dia_rad += value

                    if self.modelD !=None:
                        self.modelD.params[self.para[0]]= dia_rad
                    else:
                        self.model2.setParam("radius", dia_rad)

                elif self.modelD !=None:
                    if name == self.diapara[self.para[0]]:
                        self.modelD.params[self.para[0]]= value
                    elif name == self.diapara[self.para[1]]:
                        self.modelD.params[self.para[1]]= value
                elif name in self.model2.getParamList():
                    self.model2.setParam( name, value)

            print "value=",dia_rad
        if self.modelD !=None:
            self.model2.setParam('radius', self.modelD.run())

        for name , value in self.model2.params.iteritems():
            if not name in self.params.keys()and name != 'radius':
                self.params[name]= value

    def _set_details(self):
        """
            Concatenate details of the two models to create
            this model details
        """
        for name ,detail in self.model1.details.iteritems():
            self.details[name]= detail

        for name , detail in self.model2.details.iteritems():
            if not name in self.details.keys()and name != 'radius':
                self.details[name]= detail

    def setParam(self, name, value):
        """
            Set the value of a model parameter

            @param name: name of the parameter
            @param value: value of the parameter
        """

        self._setParamHelper( name, value)

        if name in self.model1.getParamList():
            self.model1.setParam( name, value)

        if self.model2.name != 'NoStructure':
            if len(self.diapara[self.para[0]])>1 and \
                    (name == self.diapara[self.para[0]][0] or \
                     name == self.diapara[self.para[0]][1]):
                self._set_params()
            elif self.modelD !=None:
                if name == self.diapara[self.para[0]]:
                    self.modelD.params[self.para[0]]= value
                    self.model2.setParam('radius', self.modelD.run())
                elif name == self.diapara[self.para[1]]:
                    self.modelD.params[self.para[1]]= value
                    self.model2.setParam('radius', self.modelD.run())
            elif name in self.model2.getParamList():
                self.model2.setParam( name, value)

        #print "val2=",name,self.model2.params['radius']

        self._setParamHelper( name, value)

    def _setParamHelper(self, name, value):
        """
            Helper function to setparam
        """
        # Look for dispersion parameters
        toks = name.split('.')
        if len(toks)==2:
            for item in self.dispersion.keys():
                if item.lower()==toks[0].lower():
                    for par in self.dispersion[item]:
                        if par.lower() == toks[1].lower():
                            self.dispersion[item][par] = value
                            return
        else:
            # Look for standard parameter
            for item in self.params.keys():
                if item.lower()==name.lower():
                    self.params[item] = value
                    return

        raise ValueError, "Model does not contain parameter %s" % name

    def _set_fixed_params(self):
        """
             fill the self.fixed list with the two models fixed list
        """
        for item in self.model1.fixed:
            self.fixed.append(item)

        for item in self.model2.fixed:
            if not item in self.fixed:
                self.fixed.append(item)
        self.fixed.sort()

    def _set_diaparams(self):
        """
            Assign diamfunction parameters from model1.
        """
        #For virial coefficients for only two P(Q) models,"CylinderModel","EllipsoidModel". SphereModel works w/o it.
        modelDiam = None

        #List of models by type that can be multiplied of  P(Q)*S(Q)
        #Parameters of model1 that need apply to the modelDiam corresponding to the models above
        list_sph_model_param = {'SphereModel':[['radius']],\
                                'CoreShellModel':[['radius','thickness']],\
                                'VesicleModel':[['radius','thickness']], \
                                 'BinaryHSModel':[['l_radius']], \
                                'MultiShellModel':[['core_radius','s_thickness']]}
        list_cyl_model_param = {'CylinderModel':[['radius'],['length']],\
                                'CoreShellCylinderModel':[['radius','thickness'],['length']],\
                                'HollowCylinderModel':[['radius'],['length']],\
                                'FlexibleCylinderModel':[['radius'],['length']]}
        list_ell_model_param = {'EllipsoidModel':[['radius_a'],['radius_b']],\
                                'CoreShellEllipsoidModel':[['polar_shell'],['equat_shell']]}

        #This is where the list of the input parameters for ModelDiam will be.
        self.diapara = {}
        for key in list_sph_model_param:
            print "list_sph_models.param[]",len(list_sph_model_param['SphereModel'])
        #Find the input parameters for ModelDiam depending on model1.
        para = {}
        self.para = {}

        #Determine the type of the model1
        if self.model1.__class__.__name__ in list_cyl_model_param.keys():
            Model1DPlugin("DiamCylFunc")
            basename = 'CylinderModel'
            modelDiam = DiamCylFunc()
            #loop for the # of parameters of DiamCylFunc()
            for idx in (0,len(list_cyl_model_param[basename])-1):
                #Parameter names of DiamCYlFunc
                para[idx] = list_cyl_model_param[basename][idx][0]
                #Find the  equivalent parameters of model1 function .
                self.diapara[para[idx]] = list_cyl_model_param[self.model1.__class__.__name__][idx]
                self.para[idx] = para[idx]

        elif self.model1.__class__.__name__  in list_ell_model_param.keys():
            Model1DPlugin("DiamEllipFunc")
            basename = 'EllipsoidModel'
            modelDiam = DiamEllipFunc()
            for idx in (0,len(list_ell_model_param[basename])-1):
                para[idx ] = list_ell_model_param[basename][idx ][0]
                self.diapara[para[idx]] = list_ell_model_param[self.model1.__class__.__name__][idx]
                self.para[idx] = para[idx]

        elif self.model1.__class__.__name__  in list_sph_model_param.keys() :
            basename = 'SphereModel'
            for idx in (0,len(list_sph_model_param[basename])-1):
                para[idx] = list_sph_model_param[basename][idx][0]
                self.diapara[para[idx]] = list_sph_model_param[self.model1.__class__.__name__][idx]
                self.para[idx] = para[idx]

        #print "self.diapara1",para[0],self.diapara[para[0]]

        self.modelD = modelDiam

    def run(self, x = 0.0):
        """ Evaluate the model
            @param x: input q-value (float or [float, float] as [r, theta])
            @return: (DAB value)
        """
        return self.model1.run(x)*self.model2.run(x)

    def runXY(self, x = 0.0):
        """ Evaluate the model
            @param x: input q-value (float or [float, float] as [qx, qy])
            @return: DAB value
        """
        print "model1.effecitve_radius",self.model1.calculate_ER()
        return self.model1.runXY(x)* self.model2.runXY(x)

    def set_dispersion(self, parameter, dispersion):
        """
            Set the dispersion object for a model parameter
            @param parameter: name of the parameter [string]
            @dispersion: dispersion object of type DispersionModel
        """
        value= None
        try:
            if parameter in self.model1.dispersion.keys():
                value= self.model1.set_dispersion(parameter, dispersion)
            #There is no dispersion for the structure factors(S(Q)) for now.
            #ToDo: need to decide whether or not the dispersion for S(Q) has to be considered for P*S.
            elif parameter in self.model2.dispersion.keys()and name !='radius':
                value= self.model2.set_dispersion(parameter, dispersion)
            self._set_dispersion()
            return value
        except:
            raise

    <|endoftext|>


<commit_before>import itertools
import json

__version__ = "0.0.5"

'''
PunditBase Parent Class
Arguments : name
'''

class PunditBase():

	def __init__(self):
		self.mine = 'asd'

	'''
	Input preprocessor
	'''
	def input_preprocess(self, id, function):

		def lower(self, id):

			self.processed_input = []
			for x in self.input_set:
				if x['id'] == id:
					self.processed_input.append({'id': x['id'],'value': x['value'].lower(), 'type': x['type']})
				else:
					self.processed_input.append(x)
			return

		def upper(self, id):
			self.processed_input = []
			for x in self.input_set:
				if x['id'] == id:
					self.processed_input.append({{'id': x['id'],'value': x['value'].upper(), 'type': x['type']}})
				else:
					self.processed_input.append(x)
			return

		if function == 'lower':
			lower(self, id)
		elif function == 'upper':
			upper(self, id)
		else:
			pass

	def evaluate(self, input):
		import ipdb;ipdb.set_trace()
		# input stuff
		input_json = {'id': id, 'value':value, 'type': type}
		self.input_set.append(input_json)

		#check setup
		type_condition = [x for x in condition.condition if x['type'] == type]
		process_data = [x['value'] for x in self.processed_input if x['id'] == type]

		for x in type_condition:
			if x['condition'] == 'IN':
				return True if True in [x['value'] in pd for pd in process_data] else False
			else:
				pass

'''
Pundit class where structure is defined
'''
class Pundit(PunditBase):

	def __init__(self, arg):
		self.parent = arg
		self.structure = []

	def add_structure(self, arg1, arg2):
		self.structure.append({arg1:{}, arg2:{}})

'''
Condition group where conditions are set
'''
class ConditionGroup(PunditBase):

	def __init__(self, name):
		self.name = name
		self.condition = ["asd"]

	def add_condition(self, condition, optn, then, else_value):
		input_json = {'condition': condition, 'optn':optn, 'then': then, 'else_value':else_value}
		self.condition.append(input_json)

# class Pundit():
# 	"""Pundit rule engine to process condisions"""

# 	def __init__(self, name):
# 		self.title = name
# 		self.input_set = []
# 		self.processed_input = []
# 		self.condition = []

# 	def add_input(self, id, value, type):
# 		input_json = {'id': id, 'value':value, 'type': type}
# 		self.input_set.append(input_json)

# 	def input_preprocess(self, id, function):

# 		def lower(self, id):

# 			self.processed_input = []
# 			for x in self.input_set:
# 				if x['id'] == id:
# 					self.processed_input.append({'id': x['id'],'value': x['value'].lower(), 'type': x['type']})
# 				else:
# 					self.processed_input.append(x)
# 			return

# 		def upper(self, id):
# 			self.processed_input = []
# 			for x in self.input_set:
# 				if x['id'] == id:
# 					self.processed_input.append({{'id': x['id'],'value': x['value'].upper(), 'type': x['type']}})
# 				else:
# 					self.processed_input.append(x)
# 			return

# 		if function == 'lower':
# 			lower(self, id)
# 		elif function == 'upper':
# 			upper(self, id)
# 		else:
# 			pass

# 	def evaluate(self, type, condition):
# 		type_condition = [x for x in condition.condition if x['type'] == type]
# 		process_data = [x['value'] for x in self.processed_input if x['id'] == type]

# 		for x in type_condition:
# 			if x['condition'] == 'IN':
# 				return True if True in [x['value'] in pd for pd in process_data] else False
# 			else:
# 				pass

# class ConditionGroup():
# 	"""create conditiongroup for pundit object"""

# 	def __init__(self, name):
# 		self.name = name
# 		self.condition = []

# 	def add_condition(self, value, condition, type):
# 		input_json = {'condition': condition, 'value':value, 'type': type}
# 		self.condition.append(input_json)

class MathRuler():
	"""Mathemaical rule operatons"""

	def __init__(self, for_this, then_that):
		self.condition = for_this;
		self.then = then_that

	def math(self, con):
		then_that = self.then
		for_this = self.condition
		exp_converter = then_that.replace(for_this, str(con))
		return eval(exp_converter)

class ListRuler():

	def __init__(self, arg_list):
		self.list = arg_list
		self.reduced = []
		for li in self.list:
			if type(li) == list:
				for cc in list(itertools.chain(li)):
					self.reduced.append(cc)
			else:
				self.reduced.append(li)

	def fullfill(self, arg):
		return True if arg in self.reduced else False

<commit_msg>structure<commit_after>import itertools
import json

__version__ = "0.0.5"

'''
PunditBase Parent Class
Arguments : name
'''

class PunditBase():

	def __init__(self):
		self.mine = 'asd'

	'''
	Input preprocessor
	'''
	def input_preprocess(self, id, function):

		def lower(self, id):

			self.processed_input = []
			for x in self.input_set:
				if x['id'] == id:
					self.processed_input.append({'id': x['id'],'value': x['value'].lower(), 'type': x['type']})
				else:
					self.processed_input.append(x)
			return

		def upper(self, id):
			self.processed_input = []
			for x in self.input_set:
				if x['id'] == id:
					self.processed_input.append({{'id': x['id'],'value': x['value'].upper(), 'type': x['type']}})
				else:
					self.processed_input.append(x)
			return

		if function == 'lower':
			lower(self, id)
		elif function == 'upper':
			upper(self, id)
		else:
			pass

	def add_structure(self, arg1, arg2):
		self.structure.append({arg1:{}, arg2:{}})

'''
Condition group where conditions are set
'''

class ConditionGroup():

	def __init__(self, name):
		self.name = name
		self.condition = ["asd"]

	def add_condition(self, condition, optn, then, else_value):
		input_json = {'condition': condition, 'optn':optn, 'then': then, 'else_value':else_value}
		self.condition.append(input_json)

'''
Pundit class where structure is defined and inherited features of pundit base and condition groups
'''
class Pundit(PunditBase, ConditionGroup):

	def __init__(self, pundit, conditions):
		self.pundit = pundit
		self.conditions = conditions
		self.structure = []

	def evaluate(self, input):
		import ipdb;ipdb.set_trace()
		# input stuff
		input_json = {'id': id, 'value':value, 'type': type}
		self.input_set.append(input_json)

		#check setup
		type_condition = [x for x in condition.condition if x['type'] == type]
		process_data = [x['value'] for x in self.processed_input if x['id'] == type]

		for x in type_condition:
			if x['condition'] == 'IN':
				return True if True in [x['value'] in pd for pd in process_data] else False
			else:
				pass

class MathRuler():
	"""Mathemaical rule operatons"""

	def __init__(self, for_this, then_that):
		self.condition = for_this;
		self.then = then_that

	def math(self, con):
		then_that = self.then
		for_this = self.condition
		exp_converter = then_that.replace(for_this, str(con))
		return eval(exp_converter)

class ListRuler():

	def __init__(self, arg_list):
		self.list = arg_list
		self.reduced = []
		for li in self.list:
			if type(li) == list:
				for cc in list(itertools.chain(li)):
					self.reduced.append(cc)
			else:
				self.reduced.append(li)

	def fullfill(self, arg):
		return True if arg in self.reduced else False

<|endoftext|>


<commit_before>#!/usr/bin/python
# -*- coding: utf-8 -*-

import collections
import logging
import heapq
import time

class LRUCache(collections.MutableMapping):
    """This class is not thread safe"""

    def __init__(self, timeout=60, close_callback=None, *args, **kwargs):
        self.timeout = timeout
        self.close_callback = close_callback
        self._store = {}
        self._time_to_keys = collections.defaultdict(list)
        self._keys_to_last_time = {}
        self._last_visits = []
        self.update(dict(*args, **kwargs))  # use the free update to set keys

    def __getitem__(self, key):
        # O(logm)
        t = time.time()
        self._keys_to_last_time[key] = t
        self._time_to_keys[t].append(key)
        heapq.heappush(self._last_visits, t)
        return self._store[key]

    def __setitem__(self, key, value):
        # O(logm)
        t = time.time()
        self._keys_to_last_time[key] = t
        self._store[key] = value
        self._time_to_keys[t].append(key)
        heapq.heappush(self._last_visits, t)

    def __delitem__(self, key):
        # O(1)
        del self._store[key]
        del self._keys_to_last_time[key]

    def __iter__(self):
        return iter(self._store)

    def __len__(self):
        return len(self._store)

    def sweep(self):
        # O(m)
        now = time.time()
        c = 0
        while len(self._last_visits) > 0:
            least = self._last_visits[0]
            if now - least <= self.timeout:
                break
            if self.close_callback is not None:
                for key in self._time_to_keys[least]:
                    if self._store.__contains__(key):
                        if now - self._keys_to_last_time[key] > self.timeout:
                            value = self._store[key]
                            self.close_callback(value)
            for key in self._time_to_keys[least]:
                heapq.heappop(self._last_visits)
                if self._store.__contains__(key):
                    if now - self._keys_to_last_time[key] > self.timeout:
                        del self._store[key]
                        c += 1
            del self._time_to_keys[least]
        if c:
            logging.debug('%d keys swept' % c)

def test():
    c = LRUCache(timeout=0.3)

    c['a'] = 1
    assert c['a'] == 1

    time.sleep(0.5)
    c.sweep()
    assert 'a' not in c

    c['a'] = 2
    c['b'] = 3
    time.sleep(0.2)
    c.sweep()
    assert c['a'] == 2
    assert c['b'] == 3

    time.sleep(0.2)
    c.sweep()
    c['b']
    time.sleep(0.2)
    c.sweep()
    assert 'a' not in c
    assert c['b'] == 3

    time.sleep(0.5)
    c.sweep()
    assert 'a' not in c
    assert 'b' not in c

if __name__ == '__main__':
    test()
<commit_msg>fix memory leak<commit_after>#!/usr/bin/python
# -*- coding: utf-8 -*-

import collections
import logging
import heapq
import time

class LRUCache(collections.MutableMapping):
    """This class is not thread safe"""

    def __init__(self, timeout=60, close_callback=None, *args, **kwargs):
        self.timeout = timeout
        self.close_callback = close_callback
        self._store = {}
        self._time_to_keys = collections.defaultdict(list)
        self._keys_to_last_time = {}
        self._last_visits = []
        self.update(dict(*args, **kwargs))  # use the free update to set keys

    def __getitem__(self, key):
        # O(logm)
        t = time.time()
        self._keys_to_last_time[key] = t
        self._time_to_keys[t].append(key)
        heapq.heappush(self._last_visits, t)
        return self._store[key]

    def __setitem__(self, key, value):
        # O(logm)
        t = time.time()
        self._keys_to_last_time[key] = t
        self._store[key] = value
        self._time_to_keys[t].append(key)
        heapq.heappush(self._last_visits, t)

    def __delitem__(self, key):
        # O(1)
        del self._store[key]
        del self._keys_to_last_time[key]

    def __iter__(self):
        return iter(self._store)

    def __len__(self):
        return len(self._store)

    def sweep(self):
        # O(m)
        now = time.time()
        c = 0
        while len(self._last_visits) > 0:
            least = self._last_visits[0]
            if now - least <= self.timeout:
                break
            if self.close_callback is not None:
                for key in self._time_to_keys[least]:
                    if self._store.__contains__(key):
                        if now - self._keys_to_last_time[key] > self.timeout:
                            value = self._store[key]
                            self.close_callback(value)
            for key in self._time_to_keys[least]:
                heapq.heappop(self._last_visits)
                if self._store.__contains__(key):
                    if now - self._keys_to_last_time[key] > self.timeout:
                        del self._store[key]
                        del self._keys_to_last_time[key]
                        c += 1
            del self._time_to_keys[least]
        if c:
            logging.debug('%d keys swept' % c)

def test():
    c = LRUCache(timeout=0.3)

    c['a'] = 1
    assert c['a'] == 1

    time.sleep(0.5)
    c.sweep()
    assert 'a' not in c

    c['a'] = 2
    c['b'] = 3
    time.sleep(0.2)
    c.sweep()
    assert c['a'] == 2
    assert c['b'] == 3

    time.sleep(0.2)
    c.sweep()
    c['b']
    time.sleep(0.2)
    c.sweep()
    assert 'a' not in c
    assert c['b'] == 3

    time.sleep(0.5)
    c.sweep()
    assert 'a' not in c
    assert 'b' not in c

if __name__ == '__main__':
    test()
<|endoftext|>


<commit_before>from .base_settings import *

# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
import os

if os.getenv("ENV", "localdev") == "localdev":
    DEBUG = True
else:
    DEBUG = False

ALLOWED_HOSTS += [
    "test.mobile.washington.edu",
]

INSTALLED_APPS += [
    # 'rest_framework',
    # 'mdot_rest',
    "django_user_agents",
    "mdot",
    "compressor",
]

MIDDLEWARE += (
    "django.middleware.security.SecurityMiddleware",
    "django_user_agents.middleware.UserAgentMiddleware",
    "htmlmin.middleware.HtmlMinifyMiddleware",
    "htmlmin.middleware.MarkRequestMiddleware",
)

if DEBUG:
    EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend"
    MEDIA_ROOT = "/app/data/"
    MEDIA_URL = "/media/"
else:
    EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend"

RESTCLIENTS_MDOT_DAO_CLASS = os.getenv("RESTCLIENTS_MDOT_DAO_CLASS", "Mock")
RESTCLIENTS_MDOT_HOST = os.getenv("RESTCLIENTS_MDOT_HOST", None)

EMAIL_HOST = os.getenv("EMAIL_HOST")
EMAIL_PORT = 587
EMAIL_TIMEOUT = 15
EMAIL_USE_TLS = True
EMAIL_SSL_CERTFILE = os.getenv("CERT_PATH", "")
EMAIL_SSL_KEYFILE = os.getenv("KEY_PATH", "")

MDOT_HELP_EMAIL = os.getenv(
    "MDOT_HELP_EMAIL", "help@example.edu"
)  # help desk email address
MDOT_SERVICE_EMAIL = os.getenv(
    "MDOT_SERVICE_EMAIL", "serviceteam@example.edu"
)  # app publishing request email
MDOT_UX_CONTACT = os.getenv("MDOT_UX_CONTACT", "")  # String for UX team contact url

STATICFILES_FINDERS += ("compressor.finders.CompressorFinder",)

TEMPLATES[0]["OPTIONS"]["context_processors"].extend(
    [
        "mdot.context_processors.less_compiled",
        "mdot.context_processors.google_analytics",
        "mdot.context_processors.devtools_bar",
        "mdot.context_processors.get_emails",
    ]
)

# django_compressor
COMPRESS_ROOT = "compress_files"
COMPRESS_PRECOMPILERS = (("text/less", "/app/bin/lesscpy {infile} {outfile}"),)
<commit_msg>Add allowed hosts to settings<commit_after>from .base_settings import *

# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
import os

if os.getenv("ENV", "localdev") == "localdev":
    DEBUG = True
else:
    DEBUG = False

ALLOWED_HOSTS += [
    "test.mobile.washington.edu",  # for testing purposes
    "mobile.uw.edu",  # Extraneous after DNS switch
    "m.uw.edu",  # Extraneous after DNS switch unless 301
    "mobile.washington.edu",  # Extraneous after DNS switch unless 301
    "m.washington.edu",  # Extraneous after DNS switch unless 301
]

INSTALLED_APPS += [
    # 'rest_framework',
    # 'mdot_rest',
    "django_user_agents",
    "mdot",
    "compressor",
]

MIDDLEWARE += (
    "django.middleware.security.SecurityMiddleware",
    "django_user_agents.middleware.UserAgentMiddleware",
    "htmlmin.middleware.HtmlMinifyMiddleware",
    "htmlmin.middleware.MarkRequestMiddleware",
)

if DEBUG:
    EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend"
    MEDIA_ROOT = "/app/data/"
    MEDIA_URL = "/media/"
else:
    EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend"

RESTCLIENTS_MDOT_DAO_CLASS = os.getenv("RESTCLIENTS_MDOT_DAO_CLASS", "Mock")
RESTCLIENTS_MDOT_HOST = os.getenv("RESTCLIENTS_MDOT_HOST", None)

EMAIL_HOST = os.getenv("EMAIL_HOST")
EMAIL_PORT = 587
EMAIL_TIMEOUT = 15
EMAIL_USE_TLS = True
EMAIL_SSL_CERTFILE = os.getenv("CERT_PATH", "")
EMAIL_SSL_KEYFILE = os.getenv("KEY_PATH", "")

MDOT_HELP_EMAIL = os.getenv(
    "MDOT_HELP_EMAIL", "help@example.edu"
)  # help desk email address
MDOT_SERVICE_EMAIL = os.getenv(
    "MDOT_SERVICE_EMAIL", "serviceteam@example.edu"
)  # app publishing request email
MDOT_UX_CONTACT = os.getenv("MDOT_UX_CONTACT", "")  # String for UX team contact url

STATICFILES_FINDERS += ("compressor.finders.CompressorFinder",)

TEMPLATES[0]["OPTIONS"]["context_processors"].extend(
    [
        "mdot.context_processors.less_compiled",
        "mdot.context_processors.google_analytics",
        "mdot.context_processors.devtools_bar",
        "mdot.context_processors.get_emails",
    ]
)

# django_compressor
COMPRESS_ROOT = "compress_files"
COMPRESS_PRECOMPILERS = (("text/less", "/app/bin/lesscpy {infile} {outfile}"),)
<|endoftext|>


<commit_before># vim:ts=4:sts=4:sw=4:expandtab

from django.db import models

from satori.core.dbev import Events

class OpenAttribute(models.Model):
    """Model. Base for all kinds of open attributes.
    """
    entity   = models.ForeignKey('Entity', related_name='attributes', on_delete=models.CASCADE)
    name     = models.CharField(max_length=64)
    is_blob  = models.BooleanField()
    value    = models.TextField()
    filename = models.CharField(max_length=64)

    class Meta:                                                # pylint: disable-msg=C0111
        unique_together = (('entity', 'name'),)

    def save(self, *args, **kwargs):
        if not self.is_blob:
            self.filename = ''
        super(OpenAttribute, self).save(*args, **kwargs)

class OpenAttributeEvents(Events):
    model = OpenAttribute
    on_insert = on_update = on_delete = []
<commit_msg>filename checking in OpenAttribute<commit_after># vim:ts=4:sts=4:sw=4:expandtab

from django.core.exceptions import ValidationError
from django.db import models

from satori.core.dbev import Events

def validate_filename(value):
    try:
        value.decode('ascii')
    except:
        raise ValidationError(u'filename \'%s\' contains invalid characters' % value)
    for l in value:
        if not (l.isalpha() or l.isdigit() or l == '_' or l == "."):
            raise ValidationError(u'filename \'%s\' contains invalid characters' % value)

class OpenAttribute(models.Model):
    """Model. Base for all kinds of open attributes.
    """
    entity   = models.ForeignKey('Entity', related_name='attributes', on_delete=models.CASCADE)
    name     = models.CharField(max_length=64)
    is_blob  = models.BooleanField()
    value    = models.TextField()
    filename = models.CharField(max_length=64, validators=[validate_filename])

    class Meta:                                                # pylint: disable-msg=C0111
        unique_together = (('entity', 'name'),)

    def save(self, *args, **kwargs):
        if not self.is_blob:
            self.filename = ''
        self.full_clean()
        super(OpenAttribute, self).save(*args, **kwargs)

class OpenAttributeEvents(Events):
    model = OpenAttribute
    on_insert = on_update = on_delete = []
<|endoftext|>


<commit_before># Examples of valid version strings
# __version__ = '1.2.3.dev1'  # Development release 1
# __version__ = '1.2.3a1'     # Alpha Release 1
# __version__ = '1.2.3b1'     # Beta Release 1
# __version__ = '1.2.3rc1'    # RC Release 1
# __version__ = '1.2.3'       # Final Release
# __version__ = '1.2.3.post1' # Post Release 1

__version__ = '0.1.1'
<commit_msg>Bumped version number for release.<commit_after># Examples of valid version strings
# __version__ = '1.2.3.dev1'  # Development release 1
# __version__ = '1.2.3a1'     # Alpha Release 1
# __version__ = '1.2.3b1'     # Beta Release 1
# __version__ = '1.2.3rc1'    # RC Release 1
# __version__ = '1.2.3'       # Final Release
# __version__ = '1.2.3.post1' # Post Release 1

__version__ = '0.1.2'
<|endoftext|>


<commit_before>from __future__ import division, absolute_import, print_function

__all__ = ['punic_cli', 'main']

import logging
import logging.handlers
import punic.shshutil as shutil
from pathlib2 import Path
import sys
import click
from click_didyoumean import DYMGroup
import networkx as nx
import punic
from .copy_frameworks import *
from .errors import *
from .logger import *
from .model import *
from .runner import *
from .semantic_version import *
from .utilities import *
from .version_check import *
from .config_init import *
from .carthage_cache import *
from .platform import *

@click.group(cls=DYMGroup)
@click.option('--echo', default=False, is_flag=True, help="""Echo all commands to terminal.""")
@click.option('--verbose', default=False, is_flag=True, help="""Verbose logging.""")
@click.option('--color/--no-color', default=True, is_flag=True, help="""TECHNICOLOR.""")
@click.option('--timing/--no-timing', default=False, is_flag=True, help="""Log timing info""")
@click.pass_context
def punic_cli(context, echo, verbose, timing, color):
    # Configure click
    context.token_normalize_func = lambda x: x if not x else x.lower()

    # Configure logging
    level = logging.DEBUG if verbose else logging.INFO

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

    # create console handler and set level to debug
    stream_handler = logging.StreamHandler()
    stream_handler.setLevel(level)
    stream_handler.setFormatter(HTMLFormatter())
    # add ch to logger
    logger.addHandler(stream_handler)

    logs_path = Path('~/Library/io.schwa.Punic/Application Support/Logs').expanduser()
    if not logs_path.exists():
        logs_path.mkdir(parents=True)

    log_path = logs_path / "punic.log"
    needs_rollover = log_path.exists()

    file_handler = logging.handlers.RotatingFileHandler(str(log_path), backupCount=4)
    if needs_rollover:
        file_handler.doRollover()
    file_handler.setLevel(logging.DEBUG)
    file_handler.setFormatter(HTMLStripperFormatter(logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")))
    logger.addHandler(file_handler)

    for name in ['boto', 'requests.packages.urllib3']:
        named_logger = logging.getLogger(name)
        named_logger.setLevel(logging.WARNING)
        named_logger.propagate = True

    logger.color = color
    runner.echo = echo

    # Set up punic
    punic = Punic()
    punic.config.log_timings = timing
    context.obj = punic

@punic_cli.command()
@click.pass_context
@click.option('--use-submodules', default=None, help="""Add dependencies as Git submodules""")
@click.option('--use-ssh', default=None, help="""Use SSH for downloading GitHub repositories""")
def fetch(context, **kwargs):
    """Fetch the project's dependencies.."""
    logger.info("<cmd>fetch</cmd>")
    punic = context.obj
    punic.config.fetch = True  # obviously
    punic.config.update(**kwargs)

    with timeit('fetch', log=punic.config.log_timings):
        with error_handling():
            punic.fetch()

@punic_cli.command()
@click.pass_context
@click.option('--fetch/--no-fetch', default=True, is_flag=True, help="""Controls whether to fetch dependencies.""")
@click.option('--use-submodules', default=None, help="""Add dependencies as Git submodules""")
@click.option('--use-ssh', default=None, is_flag=True, help="""Use SSH for downloading GitHub repositories""")
def resolve(context, **kwargs):
    """Resolve dependencies and output `Carthage.resolved` file.

    This sub-command does not build dependencies. Use this sub-command when a dependency has changed and you just want to update `Cartfile.resolved`.
    """
    punic = context.obj
    logger.info("<cmd>Resolve</cmd>")
    punic.config.update(**kwargs)

    with timeit('resolve', log=punic.config.log_timings):
        with error_handling():
            punic.resolve()

@punic_cli.command()
@click.pass_context
@click.option('--configuration', default=None, help="""Dependency configurations to build. Usually 'Release' or 'Debug'.""")
@click.option('--platform', default=None, help="""Platform to build. Comma separated list.""")
@click.option('--fetch/--no-fetch', default=True, is_flag=True, help="""Controls whether to fetch dependencies.""")
@click.option('--xcode-version', default=None, help="""Xcode version to use""")
@click.option('--toolchain', default=None, help="""Xcode toolchain to use""")
@click.option('--dry-run', default=None, is_flag=True, help="""Do not actually perform final build""")
@click.option('--use-submodules', default=None, help="""Add dependencies as Git submodules""")
@click.option('--use-ssh', default=None, is_flag=True, help="""Use SSH for downloading GitHub repositories""")
@click.argument('deps', nargs=-1)
def build(context, **kwargs):
    """Fetch and build the project's dependencies."""
    logger.info("<cmd>Build</cmd>")
    punic = context.obj
    punic.config.update(**kwargs)

    deps = kwargs['deps']

    logger.debug('Platforms: {}'.format(punic.config.platforms))
    logger.debug('Configuration: {}'.format(punic.config.configuration))

    with timeit('build', log=punic.config.log_timings):
        with error_handling():
            punic.build(dependencies=deps)

@punic_cli.command()
@click.pass_context
@click.option('--configuration', default=None, help="""Dependency configurations to build. Usually 'Release' or 'Debug'.""")
@click.option('--platform', default=None, help="""Platform to build. Comma separated list.""")
@click.option('--fetch/--no-fetch', default=True, is_flag=True, help="""Controls whether to fetch dependencies.""")
@click.option('--xcode-version', default=None, help="""Xcode version to use""")
@click.option('--toolchain', default=None, help="""Xcode toolchain to use""")
@click.option('--use-submodules', default=None, help="""Add dependencies as Git submodules""")
@click.option('--use-ssh', default=None, is_flag=True, help="""Use SSH for downloading GitHub repositories""")
@click.argument('deps', nargs=-1)
def update(context, **kwargs):
    """Update and rebuild the project's dependencies."""
    logger.info("<cmd>Update</cmd>")
    punic = context.obj
    punic.config.update(**kwargs)

    deps = kwargs['deps']

    with timeit('update', log=punic.config.log_timings):
        with error_handling():
            punic.resolve()
            punic.build(dependencies=deps)

@punic_cli.command()
@click.pass_context
@click.option('--derived-data', default=False, is_flag=True, help="""Clean the punic derived data directory.""")
@click.option('--caches', default=False, is_flag=True, help="""Clean the global punic files.""")
@click.option('--build', default=False, is_flag=True, help="""Clean the locate Carthage/Build directorys.""")
@click.option('--all', default=False, is_flag=True, help="""Clean all.""")
def clean(context, derived_data, caches, build, all):
    """Clean project & punic environment."""
    logger.info("<cmd>Clean</cmd>")
    punic = context.obj

    if build or all:
        logger.info('Erasing Carthage/Build directory')
        if punic.config.build_path.exists():
            shutil.rmtree(punic.config.build_path)

    if derived_data or all:
        logger.info('Erasing derived data directory')
        if punic.config.derived_data_path.exists():
            shutil.rmtree(punic.config.derived_data_path)

    if caches or all:
        if punic.config.repo_cache_directory.exists():
            logger.info('Erasing {}'.format(punic.config.repo_cache_directory))
            shutil.rmtree(punic.config.repo_cache_directory)
        logger.info('Erasing run cache')
        runner.reset()

@punic_cli.command()
@click.pass_context
@click.option('--fetch/--no-fetch', default=True, is_flag=True, help="""Controls whether to fetch dependencies.""")
@click.option('--use-submodules', default=None, help="""Add dependencies as Git submodules""")
@click.option('--use-ssh', default=None, is_flag=True, help="""Use SSH for downloading GitHub repositories""")
@click.option('--open', default=False, is_flag=True, help="""Open the graph image file.""")
def graph(context, fetch, use_submodules, use_ssh, open):
    """Output resolved dependency graph."""
    logger.info("<cmd>Graph</cmd>")
    punic = context.obj
    punic.config.fetch = fetch
    if use_submodules:
        punic.config.use_submodules = use_submodules
    if use_ssh:
        punic.config.use_ssh = use_ssh

    with timeit('graph', log=punic.config.log_timings):
        with error_handling():

            graph = punic.graph()

            logger.info('Writing graph file to "{}".'.format(os.getcwd()))
            nx.drawing.nx_pydot.write_dot(graph, 'graph.dot')

            command = 'dot graph.dot -ograph.png -Tpng'
            if runner.can_run(command):
                logger.info('Rendering dot file to png file.')
                runner.check_run(command)
                if open:
                    click.launch('graph.png')
            else:
                logging.warning('graphviz not installed. Cannot convert graph to a png.')

@punic_cli.command(name='copy-frameworks')
@click.pass_context
def copy_frameworks(context):
    """In a Run Script build phase, copies each framework specified by a SCRIPT_INPUT_FILE environment variable into the built app bundle."""
    copy_frameworks_main()

# noinspection PyUnusedLocal
@punic_cli.command()
@click.pass_context
def version(context):
    """Display the current version of Punic."""
    logger.info('Punic version: {}'.format(punic.__version__), prefix=False)

    sys_version = sys.version_info
    sys_version = SemanticVersion.from_dict(dict(major=sys_version.major, minor=sys_version.minor, micro=sys_version.micro, releaselevel=sys_version.releaselevel, serial=sys_version.serial, ))

    logger.info('Python version: {}'.format(sys_version), prefix=False)
    version_check(verbose=True, timeout=None, failure_is_an_option=False)

@punic_cli.command()
@click.pass_context
@click.option('--configuration', default=None, help="""Dependency configurations to build. Usually 'Release' or 'Debug'.""")
@click.option('--platform', default=None, help="""Platform to build. Comma separated list.""")
@click.option('--xcode', default=None)
def init(context, **kwargs):
    """Generate punic configuration file."""
    config_init(**kwargs)

@punic_cli.command()
@click.pass_context
def readme(context):
    """Opens punic readme in your browser (https://github.com/schwa/punic/blob/HEAD/README.markdown)"""
    click.launch('https://github.com/schwa/punic/blob/HEAD/README.markdown')

@punic_cli.command()
@click.option('--configuration', default=None, help="""Dependency configurations to build. Usually 'Release' or 'Debug'.""")
@click.option('--platform', default=None, help="""Platform to build. Comma separated list.""")
@click.option('--fetch/--no-fetch', default=True, is_flag=True, help="""Controls whether to fetch dependencies.""")
@click.option('--xcode-version', default=None, help="""Xcode version to use""")
@click.option('--toolchain', default=None, help="""Xcode toolchain to use""")
@click.option('--use-submodules', default=None, help="""Add dependencies as Git submodules""")
@click.option('--use-ssh', default=None, is_flag=True, help="""Use SSH for downloading GitHub repositories""")
@click.argument('deps', nargs=-1)
@click.pass_context
def list(context, **kwargs):
    punic = context.obj
    punic.config.update(**kwargs)
    deps = kwargs['deps']

    config = punic.config

    configuration, platforms = config.configuration, config.platforms

    if not config.build_path.exists():
        config.build_path.mkdir(parents=True)

    filtered_dependencies = punic._ordered_dependencies(name_filter=deps)

    checkouts = [Checkout(punic=punic, identifier=identifier, revision=revision) for identifier, revision in filtered_dependencies]

    tree = {}

    for platform in platforms:
        tree[platform.name] = {}
        for checkout in checkouts:
            tree[platform.name][str(checkout.identifier)] = {'projects':{}}
            checkout.prepare()
            for project in checkout.projects:
                tree[platform.name][str(checkout.identifier)]['projects'][project.path.name] = {'schemes':{}}
                schemes = project.schemes
                schemes = [scheme for scheme in schemes if scheme.framework_target]
                schemes = [scheme for scheme in schemes if platform.device_sdk in scheme.framework_target.supported_platform_names]
                tree[platform.name][str(checkout.identifier)]['projects'][project.path.name]['schemes'] = [scheme.name for scheme in schemes]

    # from pprint import pprint
    #
    # pprint(tree)

    import yaml

    yaml.safe_dump(tree, stream = sys.stdout)

@punic_cli.group(cls=DYMGroup)
@click.pass_context
def cache(context):
    """Cache punic build artifacts to Amazon S3"""
    pass

@cache.command()
@click.pass_context
@click.option('--xcode-version', default=None, help="""Xcode version to use""")
def publish(context, xcode_version):
    """Generates and uploads the cache archive for the current Cartfile.resolved"""
    with error_handling():
        logger.info("<cmd>Cache Publish</cmd>")
        punic = context.obj
        if xcode_version:
            punic.config.xcode_version = xcode_version
        carthage_cache = CarthageCache(config=punic.config)
        logger.info("Cache filename: <ref>'{}'</ref>".format(carthage_cache.archive_name_for_project()))
        carthage_cache.publish()

@cache.command()
@click.pass_context
@click.option('--xcode-version', default=None, help="""Xcode version to use""")
def install(context, xcode_version):
    """Installs the cache archive for the current Cartfile.resolved"""
    with error_handling():
        logger.info("<cmd>Cache Publish</cmd>")
        punic = context.obj
        if xcode_version:
            punic.config.xcode_version = xcode_version
        carthage_cache = CarthageCache(config=punic.config)
        logger.info("Cache filename: <ref>'{}'</ref>".format(carthage_cache.archive_name_for_project()))
        carthage_cache.install()

def main():
    punic_cli()
<commit_msg>Fix log path.<commit_after>from __future__ import division, absolute_import, print_function

__all__ = ['punic_cli', 'main']

import logging
import logging.handlers
import punic.shshutil as shutil
from pathlib2 import Path
import sys
import click
from click_didyoumean import DYMGroup
import networkx as nx
import punic
from .copy_frameworks import *
from .errors import *
from .logger import *
from .model import *
from .runner import *
from .semantic_version import *
from .utilities import *
from .version_check import *
from .config_init import *
from .carthage_cache import *
from .platform import *

@click.group(cls=DYMGroup)
@click.option('--echo', default=False, is_flag=True, help="""Echo all commands to terminal.""")
@click.option('--verbose', default=False, is_flag=True, help="""Verbose logging.""")
@click.option('--color/--no-color', default=True, is_flag=True, help="""TECHNICOLOR.""")
@click.option('--timing/--no-timing', default=False, is_flag=True, help="""Log timing info""")
@click.pass_context
def punic_cli(context, echo, verbose, timing, color):
    # Configure click
    context.token_normalize_func = lambda x: x if not x else x.lower()

    # Configure logging
    level = logging.DEBUG if verbose else logging.INFO

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

    # create console handler and set level to debug
    stream_handler = logging.StreamHandler()
    stream_handler.setLevel(level)
    stream_handler.setFormatter(HTMLFormatter())
    # add ch to logger
    logger.addHandler(stream_handler)

    logs_path = Path('~/Library/Application Support/io.schwa.Punic/Logs').expanduser()
    if not logs_path.exists():
        logs_path.mkdir(parents=True)

    log_path = logs_path / "punic.log"
    needs_rollover = log_path.exists()

    file_handler = logging.handlers.RotatingFileHandler(str(log_path), backupCount=4)
    if needs_rollover:
        file_handler.doRollover()
    file_handler.setLevel(logging.DEBUG)
    file_handler.setFormatter(HTMLStripperFormatter(logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")))
    logger.addHandler(file_handler)

    for name in ['boto', 'requests.packages.urllib3']:
        named_logger = logging.getLogger(name)
        named_logger.setLevel(logging.WARNING)
        named_logger.propagate = True

    logger.color = color
    runner.echo = echo

    # Set up punic
    punic = Punic()
    punic.config.log_timings = timing
    context.obj = punic

@punic_cli.command()
@click.pass_context
@click.option('--use-submodules', default=None, help="""Add dependencies as Git submodules""")
@click.option('--use-ssh', default=None, help="""Use SSH for downloading GitHub repositories""")
def fetch(context, **kwargs):
    """Fetch the project's dependencies.."""
    logger.info("<cmd>fetch</cmd>")
    punic = context.obj
    punic.config.fetch = True  # obviously
    punic.config.update(**kwargs)

    with timeit('fetch', log=punic.config.log_timings):
        with error_handling():
            punic.fetch()

@punic_cli.command()
@click.pass_context
@click.option('--fetch/--no-fetch', default=True, is_flag=True, help="""Controls whether to fetch dependencies.""")
@click.option('--use-submodules', default=None, help="""Add dependencies as Git submodules""")
@click.option('--use-ssh', default=None, is_flag=True, help="""Use SSH for downloading GitHub repositories""")
def resolve(context, **kwargs):
    """Resolve dependencies and output `Carthage.resolved` file.

    This sub-command does not build dependencies. Use this sub-command when a dependency has changed and you just want to update `Cartfile.resolved`.
    """
    punic = context.obj
    logger.info("<cmd>Resolve</cmd>")
    punic.config.update(**kwargs)

    with timeit('resolve', log=punic.config.log_timings):
        with error_handling():
            punic.resolve()

@punic_cli.command()
@click.pass_context
@click.option('--configuration', default=None, help="""Dependency configurations to build. Usually 'Release' or 'Debug'.""")
@click.option('--platform', default=None, help="""Platform to build. Comma separated list.""")
@click.option('--fetch/--no-fetch', default=True, is_flag=True, help="""Controls whether to fetch dependencies.""")
@click.option('--xcode-version', default=None, help="""Xcode version to use""")
@click.option('--toolchain', default=None, help="""Xcode toolchain to use""")
@click.option('--dry-run', default=None, is_flag=True, help="""Do not actually perform final build""")
@click.option('--use-submodules', default=None, help="""Add dependencies as Git submodules""")
@click.option('--use-ssh', default=None, is_flag=True, help="""Use SSH for downloading GitHub repositories""")
@click.argument('deps', nargs=-1)
def build(context, **kwargs):
    """Fetch and build the project's dependencies."""
    logger.info("<cmd>Build</cmd>")
    punic = context.obj
    punic.config.update(**kwargs)

    deps = kwargs['deps']

    logger.debug('Platforms: {}'.format(punic.config.platforms))
    logger.debug('Configuration: {}'.format(punic.config.configuration))

    with timeit('build', log=punic.config.log_timings):
        with error_handling():
            punic.build(dependencies=deps)

@punic_cli.command()
@click.pass_context
@click.option('--configuration', default=None, help="""Dependency configurations to build. Usually 'Release' or 'Debug'.""")
@click.option('--platform', default=None, help="""Platform to build. Comma separated list.""")
@click.option('--fetch/--no-fetch', default=True, is_flag=True, help="""Controls whether to fetch dependencies.""")
@click.option('--xcode-version', default=None, help="""Xcode version to use""")
@click.option('--toolchain', default=None, help="""Xcode toolchain to use""")
@click.option('--use-submodules', default=None, help="""Add dependencies as Git submodules""")
@click.option('--use-ssh', default=None, is_flag=True, help="""Use SSH for downloading GitHub repositories""")
@click.argument('deps', nargs=-1)
def update(context, **kwargs):
    """Update and rebuild the project's dependencies."""
    logger.info("<cmd>Update</cmd>")
    punic = context.obj
    punic.config.update(**kwargs)

    deps = kwargs['deps']

    with timeit('update', log=punic.config.log_timings):
        with error_handling():
            punic.resolve()
            punic.build(dependencies=deps)

@punic_cli.command()
@click.pass_context
@click.option('--derived-data', default=False, is_flag=True, help="""Clean the punic derived data directory.""")
@click.option('--caches', default=False, is_flag=True, help="""Clean the global punic files.""")
@click.option('--build', default=False, is_flag=True, help="""Clean the locate Carthage/Build directorys.""")
@click.option('--all', default=False, is_flag=True, help="""Clean all.""")
def clean(context, derived_data, caches, build, all):
    """Clean project & punic environment."""
    logger.info("<cmd>Clean</cmd>")
    punic = context.obj

    if build or all:
        logger.info('Erasing Carthage/Build directory')
        if punic.config.build_path.exists():
            shutil.rmtree(punic.config.build_path)

    if derived_data or all:
        logger.info('Erasing derived data directory')
        if punic.config.derived_data_path.exists():
            shutil.rmtree(punic.config.derived_data_path)

    if caches or all:
        if punic.config.repo_cache_directory.exists():
            logger.info('Erasing {}'.format(punic.config.repo_cache_directory))
            shutil.rmtree(punic.config.repo_cache_directory)
        logger.info('Erasing run cache')
        runner.reset()

@punic_cli.command()
@click.pass_context
@click.option('--fetch/--no-fetch', default=True, is_flag=True, help="""Controls whether to fetch dependencies.""")
@click.option('--use-submodules', default=None, help="""Add dependencies as Git submodules""")
@click.option('--use-ssh', default=None, is_flag=True, help="""Use SSH for downloading GitHub repositories""")
@click.option('--open', default=False, is_flag=True, help="""Open the graph image file.""")
def graph(context, fetch, use_submodules, use_ssh, open):
    """Output resolved dependency graph."""
    logger.info("<cmd>Graph</cmd>")
    punic = context.obj
    punic.config.fetch = fetch
    if use_submodules:
        punic.config.use_submodules = use_submodules
    if use_ssh:
        punic.config.use_ssh = use_ssh

    with timeit('graph', log=punic.config.log_timings):
        with error_handling():

            graph = punic.graph()

            logger.info('Writing graph file to "{}".'.format(os.getcwd()))
            nx.drawing.nx_pydot.write_dot(graph, 'graph.dot')

            command = 'dot graph.dot -ograph.png -Tpng'
            if runner.can_run(command):
                logger.info('Rendering dot file to png file.')
                runner.check_run(command)
                if open:
                    click.launch('graph.png')
            else:
                logging.warning('graphviz not installed. Cannot convert graph to a png.')

@punic_cli.command(name='copy-frameworks')
@click.pass_context
def copy_frameworks(context):
    """In a Run Script build phase, copies each framework specified by a SCRIPT_INPUT_FILE environment variable into the built app bundle."""
    copy_frameworks_main()

# noinspection PyUnusedLocal
@punic_cli.command()
@click.pass_context
def version(context):
    """Display the current version of Punic."""
    logger.info('Punic version: {}'.format(punic.__version__), prefix=False)

    sys_version = sys.version_info
    sys_version = SemanticVersion.from_dict(dict(major=sys_version.major, minor=sys_version.minor, micro=sys_version.micro, releaselevel=sys_version.releaselevel, serial=sys_version.serial, ))

    logger.info('Python version: {}'.format(sys_version), prefix=False)
    version_check(verbose=True, timeout=None, failure_is_an_option=False)

@punic_cli.command()
@click.pass_context
@click.option('--configuration', default=None, help="""Dependency configurations to build. Usually 'Release' or 'Debug'.""")
@click.option('--platform', default=None, help="""Platform to build. Comma separated list.""")
@click.option('--xcode', default=None)
def init(context, **kwargs):
    """Generate punic configuration file."""
    config_init(**kwargs)

@punic_cli.command()
@click.pass_context
def readme(context):
    """Opens punic readme in your browser (https://github.com/schwa/punic/blob/HEAD/README.markdown)"""
    click.launch('https://github.com/schwa/punic/blob/HEAD/README.markdown')

@punic_cli.command()
@click.option('--configuration', default=None, help="""Dependency configurations to build. Usually 'Release' or 'Debug'.""")
@click.option('--platform', default=None, help="""Platform to build. Comma separated list.""")
@click.option('--fetch/--no-fetch', default=True, is_flag=True, help="""Controls whether to fetch dependencies.""")
@click.option('--xcode-version', default=None, help="""Xcode version to use""")
@click.option('--toolchain', default=None, help="""Xcode toolchain to use""")
@click.option('--use-submodules', default=None, help="""Add dependencies as Git submodules""")
@click.option('--use-ssh', default=None, is_flag=True, help="""Use SSH for downloading GitHub repositories""")
@click.argument('deps', nargs=-1)
@click.pass_context
def list(context, **kwargs):
    punic = context.obj
    punic.config.update(**kwargs)
    deps = kwargs['deps']

    config = punic.config

    configuration, platforms = config.configuration, config.platforms

    if not config.build_path.exists():
        config.build_path.mkdir(parents=True)

    filtered_dependencies = punic._ordered_dependencies(name_filter=deps)

    checkouts = [Checkout(punic=punic, identifier=identifier, revision=revision) for identifier, revision in filtered_dependencies]

    tree = {}

    for platform in platforms:
        tree[platform.name] = {}
        for checkout in checkouts:
            tree[platform.name][str(checkout.identifier)] = {'projects':{}}
            checkout.prepare()
            for project in checkout.projects:
                tree[platform.name][str(checkout.identifier)]['projects'][project.path.name] = {'schemes':{}}
                schemes = project.schemes
                schemes = [scheme for scheme in schemes if scheme.framework_target]
                schemes = [scheme for scheme in schemes if platform.device_sdk in scheme.framework_target.supported_platform_names]
                tree[platform.name][str(checkout.identifier)]['projects'][project.path.name]['schemes'] = [scheme.name for scheme in schemes]

    # from pprint import pprint
    #
    # pprint(tree)

    import yaml

    yaml.safe_dump(tree, stream = sys.stdout)

@punic_cli.group(cls=DYMGroup)
@click.pass_context
def cache(context):
    """Cache punic build artifacts to Amazon S3"""
    pass

@cache.command()
@click.pass_context
@click.option('--xcode-version', default=None, help="""Xcode version to use""")
def publish(context, xcode_version):
    """Generates and uploads the cache archive for the current Cartfile.resolved"""
    with error_handling():
        logger.info("<cmd>Cache Publish</cmd>")
        punic = context.obj
        if xcode_version:
            punic.config.xcode_version = xcode_version
        carthage_cache = CarthageCache(config=punic.config)
        logger.info("Cache filename: <ref>'{}'</ref>".format(carthage_cache.archive_name_for_project()))
        carthage_cache.publish()

@cache.command()
@click.pass_context
@click.option('--xcode-version', default=None, help="""Xcode version to use""")
def install(context, xcode_version):
    """Installs the cache archive for the current Cartfile.resolved"""
    with error_handling():
        logger.info("<cmd>Cache Publish</cmd>")
        punic = context.obj
        if xcode_version:
            punic.config.xcode_version = xcode_version
        carthage_cache = CarthageCache(config=punic.config)
        logger.info("Cache filename: <ref>'{}'</ref>".format(carthage_cache.archive_name_for_project()))
        carthage_cache.install()

def main():
    punic_cli()
<|endoftext|>