<commit_before># Copyright (c) 2009-2021 The Regents of the University of Michigan
# This file is part of the HOOMD-blue project, released under the BSD 3-Clause
# License.

# Maintainer: joaander / All Developers are free to add commands for new
# features

"""Update particle properties.

When an updater is specified, it acts on the particle system each time step it
is triggered to change its state.
"""

from hoomd import _hoomd
from hoomd.md import _md
import hoomd
from hoomd.operation import Updater
from hoomd.data.parameterdicts import ParameterDict

class ZeroMomentum(Updater):
    """Zeroes system momentum.

    Args:
        trigger (hoomd.trigger.Trigger): Select the timesteps to zero momentum.

    During the time steps specified by *trigger*, particle velocities are
    modified such that the total linear momentum of the system is set to zero.

    Examples::

        zeroer = hoomd.md.update.ZeroMomentum(hoomd.trigger.Periodic(100))

    """

    def __init__(self, trigger):
        # initialize base class
        super().__init__(trigger)

    def _attach(self):
        # create the c++ mirror class
        self._cpp_obj = _md.ZeroMomentumUpdater(
            self._simulation.state._cpp_sys_def)
        super()._attach()

class constraint_ellipsoid:
    """Constrain particles to the surface of a ellipsoid.

    Args:
        group (``hoomd.group``): Group for which the update will be set
        P (tuple): (x,y,z) tuple indicating the position of the center of the
            ellipsoid (in distance units).
        rx (float): radius of an ellipsoid in the X direction (in distance
            units).
        ry (float): radius of an ellipsoid in the Y direction (in distance
            units).
        rz (float): radius of an ellipsoid in the Z direction (in distance
            units).
        r (float): radius of a sphere (in distance units), such that r=rx=ry=rz.

    `constraint_ellipsoid` specifies that all particles are constrained to the
    surface of an ellipsoid. Each time step particles are projected onto the
    surface of the ellipsoid. Method from:
    http://www.geometrictools.com/Documentation/\
            DistancePointEllipseEllipsoid.pdf

    .. attention::
        For the algorithm to work, we must have :math:`rx >= rz,~ry >= rz,~rz >
        0`.

    Note:
        This method does not properly conserve virial coefficients.

    Note:
        random thermal forces from the integrator are applied in 3D not 2D,
        therefore they aren't fully accurate.  Suggested use is therefore only
        for T=0.

    Examples::

        update.constraint_ellipsoid(P=(-1,5,0), r=9)
        update.constraint_ellipsoid(rx=7, ry=5, rz=3)

    """

    def __init__(self, group, r=None, rx=None, ry=None, rz=None, P=(0, 0, 0)):
        period = 1

        # Error out in MPI simulations
        if (hoomd.version.mpi_enabled):
            if hoomd.context.current.system_definition.getParticleData(
            ).getDomainDecomposition():
                hoomd.context.current.device.cpp_msg.error(
                    "constrain.ellipsoid is not supported in multi-processor "
                    "simulations.\n\n")
                raise RuntimeError("Error initializing updater.")

        # Error out if no radii are set
        if (r is None and rx is None and ry is None and rz is None):
            hoomd.context.current.device.cpp_msg.error(
                "no radii were defined in update.constraint_ellipsoid.\n\n")
            raise RuntimeError("Error initializing updater.")

        # initialize the base class
        # _updater.__init__(self)

        # Set parameters
        P = _hoomd.make_scalar3(P[0], P[1], P[2])
        if (r is not None):
            rx = ry = rz = r

        # create the c++ mirror class
        if not hoomd.context.current.device.cpp_exec_conf.isCUDAEnabled():
            self.cpp_updater = _md.ConstraintEllipsoid(
                hoomd.context.current.system_definition, group.cpp_group, P, rx,
                ry, rz)
        else:
            self.cpp_updater = _md.ConstraintEllipsoidGPU(
                hoomd.context.current.system_definition, group.cpp_group, P, rx,
                ry, rz)

        self.setupUpdater(period)

        # store metadata
        self.group = group
        self.P = P
        self.rx = rx
        self.ry = ry
        self.rz = rz
        self.metadata_fields = ['group', 'P', 'rx', 'ry', 'rz']

class ReversePerturbationFlow(Updater):
    """ Reverse Perturbation (Müller-Plathe) method to establish shear flow.

     "Florian Mueller-Plathe. Reversing the perturbation in nonequilibrium
     molecular dynamics: An easy way to calculate the shear viscosity of fluids.
     Phys. Rev. E, 59:4894-4898, May 1999."

    The simulation box is divided in a number of slabs.  Two distinct slabs of
    those are chosen. The "max" slab searched for the max.  velocity component
    in flow direction, the "min" is searched for the min.  velocity component.
    Afterward, both velocity components are swapped.

    This introduces a momentum flow, which drives the flow. The strength of this
    flow, can be controlled by the flow_target variant, which defines the
    integrated target momentum flow. The searching and swapping is repeated
    until the target is reached. Depending on the target sign, the "max" and
    "min" slap might be swapped.

    Args:
        filter (`hoomd.filter.ParticleFilter`): Subset of particles on which to
            apply this updater.

        flow_target (`hoomd.variant.Variant`): Integrated target flow. The unit
            is in the natural units of the simulation: [flow_target] = [timesteps] x :math:`\mathcal{M}` x :math:`\frac{\mathcal{D}}{\tau}`.
            The unit of [timesteps] is your discretization dt x :math:`\mathcal{\tau}`.

        slab_direction (str): Direction perpendicular to the slabs. Can be "X",
            "Y", or "Z"

        flow_direction (str): Direction of the flow. Can be "X",
            "Y", or "Z"

        n_slabs (int): Number of slabs used to divide the simulation box along
            the shear gradient. Using too few slabs will lead to a larger volume
            being disturbed by the momentum exchange, while using too many slabs
            may mean that there are not enough particles to exchange the target
            momentum.

        max_slab (int): Id < n_slabs where the max velocity component is search
            for. If set < 0 the value is set to its default n_slabs/2.

        min_slab (int): Id < n_slabs where the min velocity component is search
            for. If set < 0 the value is set to its default 0.

    Attention:
        * This updater has to be always applied every timestep.
        * This updater works currently only with orthorhombic boxes.

    Examples::

        # const integrated flow with 0.1 slope for max 1e8 timesteps
        ramp = hoomd.variant.Ramp(0.0, 0.1e8, 0, int(1e8))
        # velocity gradient in z direction and shear flow in x direction.
        mpf = hoomd.md.update.ReversePerturbationFlow(filter=hoomd.filter.All(), flow_target=ramp, slab_direction="Z", flow_direction="X", n_slabs=20)

        self._flow_target = hoomd.variant._setup_variant_input(flow_target)

    Attributes:
        filter (hoomd.filter.ParticleFilter): Subset of particles on which to
            apply this updater.

        flow_target (hoomd.variant.Variant): Integrated target flow in the
            natural units of the simulation.

        slab_direction (str): Direction perpendicular to the
            slabs.

        flow_direction (str): Direction of the flow.

        n_slabs (int): Number of slabs.

        max_slab (int): Id < n_slabs where the max velocity component is
            searched for.

        min_slab (int): Id < n_slabs where the min velocity component is
            searched for.
    """

    def __init__(self,
                 filter,
                 flow_target,
                 slab_direction,
                 flow_direction,
                 n_slabs,
                 max_slab=-1,
                 min_slab=-1):

        assert (n_slabs > 0), "Invalid negative number of slabs."
        if min_slab < 0:
            min_slab = 0
        if max_slab < 0:
            max_slab = n_slabs / 2
        assert (max_slab > -1 and max_slab < n_slabs
                ), "Invalid max_slab in [0," + str(n_slabs) + ")."
        assert (min_slab > -1 and min_slab < n_slabs
                ), "Invalid min_slab in [0," + str(n_slabs) + ")."
        assert (min_slab !=
                max_slab), "Invalid min/max slabs. Both have the same value."

        params = ParameterDict(filter=hoomd.filter.ParticleFilter,
                               flow_target=hoomd.variant.Variant,
                               slab_direction=str,
                               flow_direction=str,
                               n_slabs=int(n_slabs),
                               max_slab=int(max_slab),
                               min_slab=int(min_slab),
                               flow_epsilon=float(1e-2))
        params.update(
            dict(filter=filter,
                 flow_target=flow_target,
                 slab_direction=slab_direction,
                 flow_direction=flow_direction))
        self._param_dict.update(params)

        # This updater has to be applied every timestep
        super().__init__(hoomd.trigger.Periodic(1))

    def _attach(self):
        group = self._simulation.state._get_group(self.filter)
        sys_def = self._simulation.state._cpp_sys_def
        if isinstance(self._simulation.device, hoomd.device.CPU):
            self._cpp_obj = _md.MuellerPlatheFlow(
                sys_def, group, self.flow_target, self.slab_direction,
                self.flow_direction, self.n_slabs, self.min_slab, self.max_slab,
                self.flow_epsilon)
        else:
            self._cpp_obj = _md.MuellerPlatheFlowGPU(
                sys_def, group, self.flow_target, self.slab_direction,
                self.flow_direction, self.n_slabs, self.min_slab, self.max_slab,
                self.flow_epsilon)
        super()._attach()

    @property
    def summed_exchanged_momentum(self):
        R"""Returned the summed up exchanged velocity of the full simulation."""
        if self._attached:
            return self._cpp_obj.summed_exchanged_momentum
        else:
            return None
<commit_msg>State that the updater uses Periodic(1) as a trigger in the documentation<commit_after># Copyright (c) 2009-2021 The Regents of the University of Michigan
# This file is part of the HOOMD-blue project, released under the BSD 3-Clause
# License.

# Maintainer: joaander / All Developers are free to add commands for new
# features

"""Update particle properties.

When an updater is specified, it acts on the particle system each time step it
is triggered to change its state.
"""

from hoomd import _hoomd
from hoomd.md import _md
import hoomd
from hoomd.operation import Updater
from hoomd.data.parameterdicts import ParameterDict

class ZeroMomentum(Updater):
    """Zeroes system momentum.

    Args:
        trigger (hoomd.trigger.Trigger): Select the timesteps to zero momentum.

    During the time steps specified by *trigger*, particle velocities are
    modified such that the total linear momentum of the system is set to zero.

    Examples::

        zeroer = hoomd.md.update.ZeroMomentum(hoomd.trigger.Periodic(100))

    """

    def __init__(self, trigger):
        # initialize base class
        super().__init__(trigger)

    def _attach(self):
        # create the c++ mirror class
        self._cpp_obj = _md.ZeroMomentumUpdater(
            self._simulation.state._cpp_sys_def)
        super()._attach()

class constraint_ellipsoid:
    """Constrain particles to the surface of a ellipsoid.

    Args:
        group (``hoomd.group``): Group for which the update will be set
        P (tuple): (x,y,z) tuple indicating the position of the center of the
            ellipsoid (in distance units).
        rx (float): radius of an ellipsoid in the X direction (in distance
            units).
        ry (float): radius of an ellipsoid in the Y direction (in distance
            units).
        rz (float): radius of an ellipsoid in the Z direction (in distance
            units).
        r (float): radius of a sphere (in distance units), such that r=rx=ry=rz.

    `constraint_ellipsoid` specifies that all particles are constrained to the
    surface of an ellipsoid. Each time step particles are projected onto the
    surface of the ellipsoid. Method from:
    http://www.geometrictools.com/Documentation/\
            DistancePointEllipseEllipsoid.pdf

    .. attention::
        For the algorithm to work, we must have :math:`rx >= rz,~ry >= rz,~rz >
        0`.

    Note:
        This method does not properly conserve virial coefficients.

    Note:
        random thermal forces from the integrator are applied in 3D not 2D,
        therefore they aren't fully accurate.  Suggested use is therefore only
        for T=0.

    Examples::

        update.constraint_ellipsoid(P=(-1,5,0), r=9)
        update.constraint_ellipsoid(rx=7, ry=5, rz=3)

    """

    def __init__(self, group, r=None, rx=None, ry=None, rz=None, P=(0, 0, 0)):
        period = 1

        # Error out in MPI simulations
        if (hoomd.version.mpi_enabled):
            if hoomd.context.current.system_definition.getParticleData(
            ).getDomainDecomposition():
                hoomd.context.current.device.cpp_msg.error(
                    "constrain.ellipsoid is not supported in multi-processor "
                    "simulations.\n\n")
                raise RuntimeError("Error initializing updater.")

        # Error out if no radii are set
        if (r is None and rx is None and ry is None and rz is None):
            hoomd.context.current.device.cpp_msg.error(
                "no radii were defined in update.constraint_ellipsoid.\n\n")
            raise RuntimeError("Error initializing updater.")

        # initialize the base class
        # _updater.__init__(self)

        # Set parameters
        P = _hoomd.make_scalar3(P[0], P[1], P[2])
        if (r is not None):
            rx = ry = rz = r

        # create the c++ mirror class
        if not hoomd.context.current.device.cpp_exec_conf.isCUDAEnabled():
            self.cpp_updater = _md.ConstraintEllipsoid(
                hoomd.context.current.system_definition, group.cpp_group, P, rx,
                ry, rz)
        else:
            self.cpp_updater = _md.ConstraintEllipsoidGPU(
                hoomd.context.current.system_definition, group.cpp_group, P, rx,
                ry, rz)

        self.setupUpdater(period)

        # store metadata
        self.group = group
        self.P = P
        self.rx = rx
        self.ry = ry
        self.rz = rz
        self.metadata_fields = ['group', 'P', 'rx', 'ry', 'rz']

class ReversePerturbationFlow(Updater):
    """ Reverse Perturbation (Müller-Plathe) method to establish shear flow.

     "Florian Mueller-Plathe. Reversing the perturbation in nonequilibrium
     molecular dynamics: An easy way to calculate the shear viscosity of fluids.
     Phys. Rev. E, 59:4894-4898, May 1999."

    The simulation box is divided in a number of slabs.  Two distinct slabs of
    those are chosen. The "max" slab searched for the max.  velocity component
    in flow direction, the "min" is searched for the min.  velocity component.
    Afterward, both velocity components are swapped.

    This introduces a momentum flow, which drives the flow. The strength of this
    flow, can be controlled by the flow_target variant, which defines the
    integrated target momentum flow. The searching and swapping is repeated
    until the target is reached. Depending on the target sign, the "max" and
    "min" slap might be swapped.

    Args:
        filter (`hoomd.filter.ParticleFilter`): Subset of particles on which to
            apply this updater.

        flow_target (`hoomd.variant.Variant`): Integrated target flow. The unit
            is in the natural units of the simulation: [flow_target] = [timesteps] x :math:`\mathcal{M}` x :math:`\frac{\mathcal{D}}{\tau}`.
            The unit of [timesteps] is your discretization dt x :math:`\mathcal{\tau}`.

        slab_direction (str): Direction perpendicular to the slabs. Can be "X",
            "Y", or "Z"

        flow_direction (str): Direction of the flow. Can be "X",
            "Y", or "Z"

        n_slabs (int): Number of slabs used to divide the simulation box along
            the shear gradient. Using too few slabs will lead to a larger volume
            being disturbed by the momentum exchange, while using too many slabs
            may mean that there are not enough particles to exchange the target
            momentum.

        max_slab (int): Id < n_slabs where the max velocity component is search
            for. If set < 0 the value is set to its default n_slabs/2.

        min_slab (int): Id < n_slabs where the min velocity component is search
            for. If set < 0 the value is set to its default 0.

    Attention:
        * This updater uses `hoomd.trigger.Periodic(1)` as a trigger, meaning it is applied every timestep.
        * This updater works currently only with orthorhombic boxes.

    Examples::

        # const integrated flow with 0.1 slope for max 1e8 timesteps
        ramp = hoomd.variant.Ramp(0.0, 0.1e8, 0, int(1e8))
        # velocity gradient in z direction and shear flow in x direction.
        mpf = hoomd.md.update.ReversePerturbationFlow(filter=hoomd.filter.All(), flow_target=ramp, slab_direction="Z", flow_direction="X", n_slabs=20)

        self._flow_target = hoomd.variant._setup_variant_input(flow_target)

    Attributes:
        filter (hoomd.filter.ParticleFilter): Subset of particles on which to
            apply this updater.

        flow_target (hoomd.variant.Variant): Integrated target flow in the
            natural units of the simulation.

        slab_direction (str): Direction perpendicular to the
            slabs.

        flow_direction (str): Direction of the flow.

        n_slabs (int): Number of slabs.

        max_slab (int): Id < n_slabs where the max velocity component is
            searched for.

        min_slab (int): Id < n_slabs where the min velocity component is
            searched for.
    """

    def __init__(self,
                 filter,
                 flow_target,
                 slab_direction,
                 flow_direction,
                 n_slabs,
                 max_slab=-1,
                 min_slab=-1):

        assert (n_slabs > 0), "Invalid negative number of slabs."
        if min_slab < 0:
            min_slab = 0
        if max_slab < 0:
            max_slab = n_slabs / 2
        assert (max_slab > -1 and max_slab < n_slabs
                ), "Invalid max_slab in [0," + str(n_slabs) + ")."
        assert (min_slab > -1 and min_slab < n_slabs
                ), "Invalid min_slab in [0," + str(n_slabs) + ")."
        assert (min_slab !=
                max_slab), "Invalid min/max slabs. Both have the same value."

        params = ParameterDict(filter=hoomd.filter.ParticleFilter,
                               flow_target=hoomd.variant.Variant,
                               slab_direction=str,
                               flow_direction=str,
                               n_slabs=int(n_slabs),
                               max_slab=int(max_slab),
                               min_slab=int(min_slab),
                               flow_epsilon=float(1e-2))
        params.update(
            dict(filter=filter,
                 flow_target=flow_target,
                 slab_direction=slab_direction,
                 flow_direction=flow_direction))
        self._param_dict.update(params)

        # This updater has to be applied every timestep
        super().__init__(hoomd.trigger.Periodic(1))

    def _attach(self):
        group = self._simulation.state._get_group(self.filter)
        sys_def = self._simulation.state._cpp_sys_def
        if isinstance(self._simulation.device, hoomd.device.CPU):
            self._cpp_obj = _md.MuellerPlatheFlow(
                sys_def, group, self.flow_target, self.slab_direction,
                self.flow_direction, self.n_slabs, self.min_slab, self.max_slab,
                self.flow_epsilon)
        else:
            self._cpp_obj = _md.MuellerPlatheFlowGPU(
                sys_def, group, self.flow_target, self.slab_direction,
                self.flow_direction, self.n_slabs, self.min_slab, self.max_slab,
                self.flow_epsilon)
        super()._attach()

    @property
    def summed_exchanged_momentum(self):
        R"""Returned the summed up exchanged velocity of the full simulation."""
        if self._attached:
            return self._cpp_obj.summed_exchanged_momentum
        else:
            return None
<|endoftext|>


<commit_before># Copyright (c) 2012-2013, Mark Peek <mark@peek.org>
# All rights reserved.
#
# See LICENSE file for full license.

import json
import re
import types

from . import validators

__version__ = "0.3.2"

# constants for DeletionPolicy
Delete = 'Delete'
Retain = 'Retain'
Snapshot = 'Snapshot'

valid_names = re.compile(r'^[a-zA-Z0-9]+$')

class BaseAWSObject(object):
    def __init__(self, name, **kwargs):
        self.name = name
        # Cache the keys for validity checks
        self.propnames = self.props.keys()
        self.attributes = ['DependsOn', 'DeletionPolicy',
                           'Metadata', 'UpdatePolicy']

        # unset/None is also legal
        if name and not valid_names.match(name):
            raise ValueError('Name not alphanumeric')

        # Create the list of properties set on this object by the user
        self.properties = {}
        dictname = getattr(self, 'dictname', None)
        if dictname:
            self.resource = {
                dictname: self.properties,
            }
        else:
            self.resource = self.properties
        if hasattr(self, 'type') and self.type is not None:
            self.resource['Type'] = self.type
        self.__initialized = True

        # Now that it is initialized, populate it with the kwargs
        for k, v in kwargs.items():
            # Special case Resource Attributes
            if k in self.attributes:
                self.resource[k] = v
            else:
                self.__setattr__(k, v)

    def __getattr__(self, name):
        try:
            return self.properties.__getitem__(name)
        except KeyError:
            raise AttributeError(name)

    def __setattr__(self, name, value):
        if '_BaseAWSObject__initialized' not in self.__dict__:
            return dict.__setattr__(self, name, value)
        elif name in self.propnames:
            # Check the type of the object and compare against what we were
            # expecting.
            expected_type = self.props[name][0]

            # If the value is a AWSHelperFn we can't do much validation
            # we'll have to leave that to Amazon.  Maybe there's another way
            # to deal with this that we'll come up with eventually
            if isinstance(value, AWSHelperFn):
                return self.properties.__setitem__(name, value)

            # If it's a function, call it...
            elif isinstance(expected_type, types.FunctionType):
                value = expected_type(value)
                return self.properties.__setitem__(name, value)

            # If it's a list of types, check against those types...
            elif isinstance(expected_type, list):
                # If we're expecting a list, then make sure it is a list
                if not isinstance(value, list):
                    self._raise_type(name, value, expected_type)

                # Iterate over the list and make sure it matches our
                # type checks
                for v in value:
                    if not isinstance(v, tuple(expected_type)):
                        self._raise_type(name, v, expected_type)
                # Validated so assign it
                return self.properties.__setitem__(name, value)

            # Single type so check the type of the object and compare against
            # what we were expecting. Special case AWS helper functions.
            elif isinstance(value, expected_type):
                return self.properties.__setitem__(name, value)
            else:
                self._raise_type(name, value, expected_type)

        raise AttributeError("%s object does not support attribute %s" %
                            (self.type, name))

    def _raise_type(self, name, value, expected_type):
        raise TypeError('%s is %s, expected %s' %
                        (name, type(value), expected_type))

    def validate(self):
        pass

    def JSONrepr(self):
        for k, (prop_type, required) in self.props.items():
            if required and k not in self.properties:
                type = getattr(self, 'type', "<unknown type>")
                raise ValueError("Resource %s required in type %s" % (k, type))
        self.validate()
        # If no other properties are set, only return the Type.
        # Mainly used to not have an empty "Properties".
        if self.properties:
            return self.resource
        else:
            return {'Type': self.type}

class AWSObject(BaseAWSObject):
    dictname = 'Properties'

class AWSDeclaration(BaseAWSObject):
    """
    Used for CloudFormation Resource Property objects
    http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/
    aws-product-property-reference.html
    """

    def __init__(self, name, **kwargs):
        super(AWSDeclaration, self).__init__(name, **kwargs)

class AWSProperty(BaseAWSObject):
    """
    Used for CloudFormation Resource Property objects
    http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/
    aws-product-property-reference.html
    """

    def __init__(self, name=None, **kwargs):
        super(AWSProperty, self).__init__(name, **kwargs)

def validate_pausetime(pausetime):
    if not pausetime.startswith('PT'):
        raise ValueError('PauseTime should look like PT#H#M#S')
    return pausetime

class UpdatePolicy(BaseAWSObject):
    props = {
        'MaxBatchSize': (basestring, False),
        'MinInstancesInService': (basestring, False),
        'PauseTime': (validate_pausetime, False),
    }

    valid_update_policies = (
        'AutoScalingRollingUpdate',
    )

    def __init__(self, name, **kwargs):
        if name not in self.valid_update_policies:
            raise ValueError('UpdatePolicy name must be one of %r' % (
                self.valid_update_policies,))
        self.dictname = name
        super(UpdatePolicy, self).__init__(None, **kwargs)

class AWSHelperFn(object):
    def getdata(self, data):
        if isinstance(data, AWSObject):
            return data.name
        else:
            return data

class Base64(AWSHelperFn):
    def __init__(self, data):
        self.data = {'Fn::Base64': data}

    def JSONrepr(self):
        return self.data

class FindInMap(AWSHelperFn):
    def __init__(self, map, key, value):
        self.data = {'Fn::FindInMap': [self.getdata(map), key, value]}

    def JSONrepr(self):
        return self.data

class GetAtt(AWSHelperFn):
    def __init__(self, logicalName, attrName):
        self.data = {'Fn::GetAtt': [self.getdata(logicalName), attrName]}

    def JSONrepr(self):
        return self.data

class GetAZs(AWSHelperFn):
    def __init__(self, region):
        self.data = {'Fn::GetAZs': region}

    def JSONrepr(self):
        return self.data

class Join(AWSHelperFn):
    def __init__(self, delimiter, values):
        self.data = {'Fn::Join': [delimiter, values]}

    def JSONrepr(self):
        return self.data

class Name(AWSHelperFn):
    def __init__(self, data):
        self.data = self.getdata(data)

    def JSONrepr(self):
        return self.data

class Select(AWSHelperFn):
    def __init__(self, indx, objects):
        self.data = {'Fn::Select': [indx, objects]}

    def JSONrepr(self):
        return self.data

class Ref(AWSHelperFn):
    def __init__(self, data):
        self.data = {'Ref': self.getdata(data)}

    def JSONrepr(self):
        return self.data

class awsencode(json.JSONEncoder):
    def default(self, obj):
        if hasattr(obj, 'JSONrepr'):
            return obj.JSONrepr()
        return json.JSONEncoder.default(self, obj)

class Tags(AWSHelperFn):
    def __init__(self, **kwargs):
        self.tags = []
        for k, v in kwargs.iteritems():
            self.tags.append({
                'Key': k,
                'Value': v,
            })

    def JSONrepr(self):
        return self.tags

class Template(object):
    props = {
        'AWSTemplateFormatVersion': (basestring, False),
        'Description': (basestring, False),
        'Parameters': (dict, False),
        'Mappings': (dict, False),
        'Resources': (dict, False),
        'Outputs': (dict, False),
    }

    def __init__(self):
        self.description = None
        self.mappings = {}
        self.outputs = {}
        self.parameters = {}
        self.resources = {}
        self.version = None

    def add_description(self, description):
        self.description = description

    def handle_duplicate_key(self, key):
        raise ValueError('duplicate key "%s" detected' % key)

    def _update(self, d, values):
        if isinstance(values, list):
            for v in values:
                if v.name in d:
                    self.handle_duplicate_key(values.name)
                d[v.name] = v
        else:
            if values.name in d:
                self.handle_duplicate_key(values.name)
            d[values.name] = values
        return values

    def add_output(self, output):
        return self._update(self.outputs, output)

    def add_mapping(self, name, mapping):
        self.mappings[name] = mapping

    def add_parameter(self, parameter):
        return self._update(self.parameters, parameter)

    def add_resource(self, resource):
        return self._update(self.resources, resource)

    def add_version(self, version=None):
        if version:
            self.version = version
        else:
            self.version = "2010-09-09"

    def to_json(self, indent=4, sort_keys=True):
        t = {}
        if self.description:
            t['Description'] = self.description
        if self.mappings:
            t['Mappings'] = self.mappings
        if self.outputs:
            t['Outputs'] = self.outputs
        if self.parameters:
            t['Parameters'] = self.parameters
        if self.version:
            t['AWSTemplateFormatVersion'] = self.version
        t['Resources'] = self.resources

        return json.dumps(t, cls=awsencode, indent=indent, sort_keys=sort_keys)

    def JSONrepr(self):
        return [self.parameters, self.mappings, self.resources]

class Output(AWSDeclaration):
    props = {
        'Description': (basestring, False),
        'Value': (basestring, True),
    }

class Parameter(AWSDeclaration):
    props = {
        'Type': (basestring, True),
        'Default': (basestring, False),
        'NoEcho': (bool, False),
        'AllowedValues': (list, False),
        'AllowedPattern': (basestring, False),
        'MaxLength': (validators.positive_integer, False),
        'MinLength': (validators.positive_integer, False),
        'MaxValue': (validators.integer, False),
        'MinValue': (validators.integer, False),
        'Description': (basestring, False),
        'ConstraintDescription': (basestring, False),
    }
<commit_msg>Adding separators options to print to json function<commit_after># Copyright (c) 2012-2013, Mark Peek <mark@peek.org>
# All rights reserved.
#
# See LICENSE file for full license.

import json
import re
import types

from . import validators

__version__ = "0.3.2"

# constants for DeletionPolicy
Delete = 'Delete'
Retain = 'Retain'
Snapshot = 'Snapshot'

valid_names = re.compile(r'^[a-zA-Z0-9]+$')

class BaseAWSObject(object):
    def __init__(self, name, **kwargs):
        self.name = name
        # Cache the keys for validity checks
        self.propnames = self.props.keys()
        self.attributes = ['DependsOn', 'DeletionPolicy',
                           'Metadata', 'UpdatePolicy']

        # unset/None is also legal
        if name and not valid_names.match(name):
            raise ValueError('Name not alphanumeric')

        # Create the list of properties set on this object by the user
        self.properties = {}
        dictname = getattr(self, 'dictname', None)
        if dictname:
            self.resource = {
                dictname: self.properties,
            }
        else:
            self.resource = self.properties
        if hasattr(self, 'type') and self.type is not None:
            self.resource['Type'] = self.type
        self.__initialized = True

        # Now that it is initialized, populate it with the kwargs
        for k, v in kwargs.items():
            # Special case Resource Attributes
            if k in self.attributes:
                self.resource[k] = v
            else:
                self.__setattr__(k, v)

    def __getattr__(self, name):
        try:
            return self.properties.__getitem__(name)
        except KeyError:
            raise AttributeError(name)

    def __setattr__(self, name, value):
        if '_BaseAWSObject__initialized' not in self.__dict__:
            return dict.__setattr__(self, name, value)
        elif name in self.propnames:
            # Check the type of the object and compare against what we were
            # expecting.
            expected_type = self.props[name][0]

            # If the value is a AWSHelperFn we can't do much validation
            # we'll have to leave that to Amazon.  Maybe there's another way
            # to deal with this that we'll come up with eventually
            if isinstance(value, AWSHelperFn):
                return self.properties.__setitem__(name, value)

            # If it's a function, call it...
            elif isinstance(expected_type, types.FunctionType):
                value = expected_type(value)
                return self.properties.__setitem__(name, value)

            # If it's a list of types, check against those types...
            elif isinstance(expected_type, list):
                # If we're expecting a list, then make sure it is a list
                if not isinstance(value, list):
                    self._raise_type(name, value, expected_type)

                # Iterate over the list and make sure it matches our
                # type checks
                for v in value:
                    if not isinstance(v, tuple(expected_type)):
                        self._raise_type(name, v, expected_type)
                # Validated so assign it
                return self.properties.__setitem__(name, value)

            # Single type so check the type of the object and compare against
            # what we were expecting. Special case AWS helper functions.
            elif isinstance(value, expected_type):
                return self.properties.__setitem__(name, value)
            else:
                self._raise_type(name, value, expected_type)

        raise AttributeError("%s object does not support attribute %s" %
                            (self.type, name))

    def _raise_type(self, name, value, expected_type):
        raise TypeError('%s is %s, expected %s' %
                        (name, type(value), expected_type))

    def validate(self):
        pass

    def JSONrepr(self):
        for k, (prop_type, required) in self.props.items():
            if required and k not in self.properties:
                type = getattr(self, 'type', "<unknown type>")
                raise ValueError("Resource %s required in type %s" % (k, type))
        self.validate()
        # If no other properties are set, only return the Type.
        # Mainly used to not have an empty "Properties".
        if self.properties:
            return self.resource
        else:
            return {'Type': self.type}

class AWSObject(BaseAWSObject):
    dictname = 'Properties'

class AWSDeclaration(BaseAWSObject):
    """
    Used for CloudFormation Resource Property objects
    http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/
    aws-product-property-reference.html
    """

    def __init__(self, name, **kwargs):
        super(AWSDeclaration, self).__init__(name, **kwargs)

class AWSProperty(BaseAWSObject):
    """
    Used for CloudFormation Resource Property objects
    http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/
    aws-product-property-reference.html
    """

    def __init__(self, name=None, **kwargs):
        super(AWSProperty, self).__init__(name, **kwargs)

def validate_pausetime(pausetime):
    if not pausetime.startswith('PT'):
        raise ValueError('PauseTime should look like PT#H#M#S')
    return pausetime

class UpdatePolicy(BaseAWSObject):
    props = {
        'MaxBatchSize': (basestring, False),
        'MinInstancesInService': (basestring, False),
        'PauseTime': (validate_pausetime, False),
    }

    valid_update_policies = (
        'AutoScalingRollingUpdate',
    )

    def __init__(self, name, **kwargs):
        if name not in self.valid_update_policies:
            raise ValueError('UpdatePolicy name must be one of %r' % (
                self.valid_update_policies,))
        self.dictname = name
        super(UpdatePolicy, self).__init__(None, **kwargs)

class AWSHelperFn(object):
    def getdata(self, data):
        if isinstance(data, AWSObject):
            return data.name
        else:
            return data

class Base64(AWSHelperFn):
    def __init__(self, data):
        self.data = {'Fn::Base64': data}

    def JSONrepr(self):
        return self.data

class FindInMap(AWSHelperFn):
    def __init__(self, map, key, value):
        self.data = {'Fn::FindInMap': [self.getdata(map), key, value]}

    def JSONrepr(self):
        return self.data

class GetAtt(AWSHelperFn):
    def __init__(self, logicalName, attrName):
        self.data = {'Fn::GetAtt': [self.getdata(logicalName), attrName]}

    def JSONrepr(self):
        return self.data

class GetAZs(AWSHelperFn):
    def __init__(self, region):
        self.data = {'Fn::GetAZs': region}

    def JSONrepr(self):
        return self.data

class Join(AWSHelperFn):
    def __init__(self, delimiter, values):
        self.data = {'Fn::Join': [delimiter, values]}

    def JSONrepr(self):
        return self.data

class Name(AWSHelperFn):
    def __init__(self, data):
        self.data = self.getdata(data)

    def JSONrepr(self):
        return self.data

class Select(AWSHelperFn):
    def __init__(self, indx, objects):
        self.data = {'Fn::Select': [indx, objects]}

    def JSONrepr(self):
        return self.data

class Ref(AWSHelperFn):
    def __init__(self, data):
        self.data = {'Ref': self.getdata(data)}

    def JSONrepr(self):
        return self.data

class awsencode(json.JSONEncoder):
    def default(self, obj):
        if hasattr(obj, 'JSONrepr'):
            return obj.JSONrepr()
        return json.JSONEncoder.default(self, obj)

class Tags(AWSHelperFn):
    def __init__(self, **kwargs):
        self.tags = []
        for k, v in kwargs.iteritems():
            self.tags.append({
                'Key': k,
                'Value': v,
            })

    def JSONrepr(self):
        return self.tags

class Template(object):
    props = {
        'AWSTemplateFormatVersion': (basestring, False),
        'Description': (basestring, False),
        'Parameters': (dict, False),
        'Mappings': (dict, False),
        'Resources': (dict, False),
        'Outputs': (dict, False),
    }

    def __init__(self):
        self.description = None
        self.mappings = {}
        self.outputs = {}
        self.parameters = {}
        self.resources = {}
        self.version = None

    def add_description(self, description):
        self.description = description

    def handle_duplicate_key(self, key):
        raise ValueError('duplicate key "%s" detected' % key)

    def _update(self, d, values):
        if isinstance(values, list):
            for v in values:
                if v.name in d:
                    self.handle_duplicate_key(values.name)
                d[v.name] = v
        else:
            if values.name in d:
                self.handle_duplicate_key(values.name)
            d[values.name] = values
        return values

    def add_output(self, output):
        return self._update(self.outputs, output)

    def add_mapping(self, name, mapping):
        self.mappings[name] = mapping

    def add_parameter(self, parameter):
        return self._update(self.parameters, parameter)

    def add_resource(self, resource):
        return self._update(self.resources, resource)

    def add_version(self, version=None):
        if version:
            self.version = version
        else:
            self.version = "2010-09-09"

    def to_json(self, indent=4, sort_keys=True, separators=(',',' ',':')):
        t = {}
        if self.description:
            t['Description'] = self.description
        if self.mappings:
            t['Mappings'] = self.mappings
        if self.outputs:
            t['Outputs'] = self.outputs
        if self.parameters:
            t['Parameters'] = self.parameters
        if self.version:
            t['AWSTemplateFormatVersion'] = self.version
        t['Resources'] = self.resources

        return json.dumps(t, cls=awsencode, indent=indent, sort_keys=sort_keys, separators=separators)

    def JSONrepr(self):
        return [self.parameters, self.mappings, self.resources]

class Output(AWSDeclaration):
    props = {
        'Description': (basestring, False),
        'Value': (basestring, True),
    }

class Parameter(AWSDeclaration):
    props = {
        'Type': (basestring, True),
        'Default': (basestring, False),
        'NoEcho': (bool, False),
        'AllowedValues': (list, False),
        'AllowedPattern': (basestring, False),
        'MaxLength': (validators.positive_integer, False),
        'MinLength': (validators.positive_integer, False),
        'MaxValue': (validators.integer, False),
        'MinValue': (validators.integer, False),
        'Description': (basestring, False),
        'ConstraintDescription': (basestring, False),
    }
<|endoftext|>


<commit_before>import tkinter as tk
import tk_tools

root = tk.Tk()

handle = tk_tools.SpreadSheetReader(root,
                                    path='./ref/test_data.xlsx',
                                    sheetname='Data entry')
handle.grid()

root.mainloop()
<commit_msg>add if __name__ == '__main__':, renamed one variable.<commit_after>import tkinter as tk
import tk_tools

if __name__ == '__main__':

    root = tk.Tk()

    sheet_handle = tk_tools.SpreadSheetReader(root,
                                              path='./ref/test_data.xlsx',
                                              sheetname='Data entry')
    sheet_handle.grid()

    root.mainloop()
<|endoftext|>


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

"""Hostman.

Usage:
  hostman add [-fqbvq] [--force] [--path=PATH]
              ( [ENTRY ...] | [--input-file=FILE] | [--input-url=URL] )
  hostman remove [-qbvq] ([--address=<address>] [--names=<names>]) [--path=PATH]
                 [--input-file=FILE] [--input-url=URL]
  hostman --version

Options:
  -h --help                    show this help message and exit
  --version                    show version and exit
  -f --force                   replace matching entries
  --address=ADDRESS            ipv6 or ipv4 address
  --names=NAMES                host names
  -q --quiet                   report only failures
  -p --path=PATH               location of hosts file (attempts to detect default)
  -i --input-file=FILE         file containing hosts to import
  -u --input-url=URL           url of file containing hosts to import
  -b --backup                  create a backup before writing any changes
  --exclude=VALUE              comma separated list of names or addresses
                               to exclude from operation [default: 127.0.0.1]
  -v --verbose                 print verbose output
"""
from docopt import docopt
from hosts import Hosts, utils, HostsEntry
import sys
import os
import datetime
import shutil
from colorama import Fore, init
init(autoreset=True)

def backup_hosts(source=None, extension=None):
    if not extension:
        now = datetime.datetime.now()
        ext = now.strftime('%Y%m%d%H%M%S')
    else:
        ext = extension
    dest_split = source.split('/')
    new_filename = ".{0}.{1}".format(dest_split[-1], ext)
    dest_split[-1] = new_filename
    dest = "/".join(dest_split)
    try:
        shutil.copy(source, dest)
        return {'result': 'success', 'message': 'Backup written to: {0}'.format(dest)}
    except IOError:
        return {'result': 'failed', 'message': 'Cannot create backup file: {0}'.format(dest)}

def output_message(message=None):
    """
    :param message: A dict containing the result and a user notification message
    :return: Exit with 0 or 1, or True if this is not the final output
    """
    res = message.get('result')
    if res == 'success':
        print (Fore.GREEN + message.get('message'))
        sys.exit(0)
    elif res == 'failed':
        print (Fore.RED + message.get('message'))
        sys.exit(1)
    elif res == 'continue':
        print message.get('message')
        return True

def add(entry_line=None, hosts_path=None, force_add=False):
    """
    Add the specified entry
    :param entry_line: The entry to add
    :param hosts_path: The path of the hosts file
    :param force_add: Replace matching any matching entries with new entry
    :return:
    """
    hosts_entry = HostsEntry.str_to_hostentry(entry_line)
    if not hosts_entry:
        output_message({'result': 'failed', 'message': '"{0}": is not a valid entry.'.format(entry_line)})

    duplicate_entry = False
    entry_to_add = False

    hosts = Hosts(hosts_path)
    add_result = hosts.add(entries=[hosts_entry], force=force_add)
    if add_result.get('replaced_count'):
        hosts.write()
        return {'result': 'success',
                'message': 'Entry added. Matching entries replaced.'}
    if add_result.get('ipv4_count') or add_result.get('ipv6_count'):
        entry_to_add = True
    if add_result.get('duplicate_count'):
        duplicate_entry = True
    if entry_to_add and not duplicate_entry:
        hosts.write()
        return {'result': 'success',
                'message': 'New entry added.'}
    if not force_add and duplicate_entry:
        return {'result': 'failed',
                'message': 'New entry matches one or more existing.'
                           '\nUse -f to replace similar entries.'}

def import_from_file(hosts_path=None, file_path=None):
    if hosts_path and not os.path.exists(hosts_path):
        return {'result': 'failed', 'message': 'Cannot read hosts file: {0}'.format(hosts_path)}
    if not os.path.exists(file_path):
        return {'result': 'failed', 'message': 'Cannot read import file: {0}'.format(file_path)}
    else:
        hosts = Hosts(path=hosts_path)
        pre_count = len(hosts.entries)
        import_file_output = hosts.import_file(import_file_path=file_path)
        post_count = len(hosts.entries)
        write_result = import_file_output.get('write_result')
        message = 'New entries:\t{0}\nTotal entries:\t{1}\n'.format(
            post_count - pre_count,
            write_result.get('total_written')
        )
    return {'result': import_file_output.get('result'),
            'message': message}

def import_from_url(hosts_path=None, url=None):
    if hosts_path and not os.path.exists(hosts_path):
        return {'result': 'failed', 'message': 'Cannot read hosts file: {0}'.format(hosts_path)}
    else:
        hosts = Hosts(path=hosts_path)
        pre_count = len(hosts.entries)
        import_url_output = hosts.import_url(url=url)
        post_count = len(hosts.entries)
        write_result = import_url_output.get('write_result')
        message = 'New entries:\t{0}\nTotal entries:\t{1}\n'.format(
            post_count - pre_count,
            write_result.get('total_written')
        )
    return {'result': import_url_output.get('result'),
            'message': message}

def remove(address_to_remove=None, names_to_remove=None, remove_from_path=None):
    """
    Remove entries matching address and/or names
    """
    hosts = Hosts(path=remove_from_path)
    remove_result = None
    write_result = False
    if address_to_remove or names_to_remove:
        remove_result = hosts.remove_all_matching(address=address_to_remove, name=names_to_remove)
        write_result = hosts.write()

    if not write_result:
        return {'result': 'failed', 'message': 'Unable to write to path: {0}'.format(hosts.hosts_path)}
    if remove_result:
        str_entry = "entry"
        if remove_result > 1:
            str_entry = 'entries'
        return {'result': 'success', 'message': 'Removed {0} {1}.'.format(remove_result, str_entry)}
    else:
        return {'result': 'failed', 'message': 'No matching entries.'.format(remove_result)}

def strip_entry_value(entry_value):
    """
    :param entry_value: value to strip spaces from
    :return: value minus the leading and trailing spaces
    """
    if isinstance(entry_value, list):
        new_list = []
        for value in entry_value:
            new_list.append(value.strip())
        return ' '.join(new_list)
    if isinstance(entry_value, str):
        return entry_value.strip()

if __name__ == '__main__':
    arguments = docopt(__doc__, version='0.1.0')
    entry = arguments.get('ENTRY')
    path = arguments.get('--path')
    force = arguments.get('--force')
    backup = arguments.get('--backup')
    address = arguments.get('--address')
    names = arguments.get('--names')
    input_file = arguments.get('--input-file')
    input_url = arguments.get('--input-url')

    if not path:
        if sys.platform.startswith('win'):
            path = r'c:\windows\system32\drivers\etc\hosts'
        else:
            path = '/etc/hosts'

    if not utils.is_readable(path):
        output_message({'result': 'failed',
                        'message': 'Unable to read path: {0}.'.format(path)})

    new_entry = None
    if entry:
        new_entry = strip_entry_value(entry)

    if backup:
        result = backup_hosts(source=path)
        if result.get('result') == 'success':
            result['result'] = 'continue'
        output_message(result)

    if arguments.get('add'):
        final_message = None
        if not utils.is_writeable(path):
            output_message({'result': 'failed',
                            'message': 'Unable to write to: {0}'.format(path)})
        if new_entry:
            result = add(entry_line=new_entry, hosts_path=path, force_add=force)
            output_message(result)
        if input_file:
            result = import_from_file(hosts_path=path, file_path=input_file)
            output_message(result)
        if input_url:
            result = import_from_url(hosts_path=path, url=input_url)
            output_message(result)
    else:
        if arguments.get('remove'):
            result = remove(address_to_remove=address, names_to_remove=names, remove_from_path=path)
            output_message(result)
<commit_msg>modify import to reflect dependency package rename.<commit_after>#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""Hostman.

Usage:
  hostman add [-fqbvq] [--force] [--path=PATH]
              ( [ENTRY ...] | [--input-file=FILE] | [--input-url=URL] )
  hostman remove [-qbvq] ([--address=<address>] [--names=<names>]) [--path=PATH]
                 [--input-file=FILE] [--input-url=URL]
  hostman --version

Options:
  -h --help                    show this help message and exit
  --version                    show version and exit
  -f --force                   replace matching entries
  --address=ADDRESS            ipv6 or ipv4 address
  --names=NAMES                host names
  -q --quiet                   report only failures
  -p --path=PATH               location of hosts file (attempts to detect default)
  -i --input-file=FILE         file containing hosts to import
  -u --input-url=URL           url of file containing hosts to import
  -b --backup                  create a backup before writing any changes
  --exclude=VALUE              comma separated list of names or addresses
                               to exclude from operation [default: 127.0.0.1]
  -v --verbose                 print verbose output
"""
from docopt import docopt
from python_hosts import Hosts, utils, HostsEntry
import sys
import os
import datetime
import shutil
from colorama import Fore, init
init(autoreset=True)

def backup_hosts(source=None, extension=None):
    if not extension:
        now = datetime.datetime.now()
        ext = now.strftime('%Y%m%d%H%M%S')
    else:
        ext = extension
    dest_split = source.split('/')
    new_filename = ".{0}.{1}".format(dest_split[-1], ext)
    dest_split[-1] = new_filename
    dest = "/".join(dest_split)
    try:
        shutil.copy(source, dest)
        return {'result': 'success', 'message': 'Backup written to: {0}'.format(dest)}
    except IOError:
        return {'result': 'failed', 'message': 'Cannot create backup file: {0}'.format(dest)}

def output_message(message=None):
    """
    :param message: A dict containing the result and a user notification message
    :return: Exit with 0 or 1, or True if this is not the final output
    """
    res = message.get('result')
    if res == 'success':
        print (Fore.GREEN + message.get('message'))
        sys.exit(0)
    elif res == 'failed':
        print (Fore.RED + message.get('message'))
        sys.exit(1)
    elif res == 'continue':
        print message.get('message')
        return True

def add(entry_line=None, hosts_path=None, force_add=False):
    """
    Add the specified entry
    :param entry_line: The entry to add
    :param hosts_path: The path of the hosts file
    :param force_add: Replace matching any matching entries with new entry
    :return:
    """
    hosts_entry = HostsEntry.str_to_hostentry(entry_line)
    if not hosts_entry:
        output_message({'result': 'failed', 'message': '"{0}": is not a valid entry.'.format(entry_line)})

    duplicate_entry = False
    entry_to_add = False

    hosts = Hosts(hosts_path)
    add_result = hosts.add(entries=[hosts_entry], force=force_add)
    if add_result.get('replaced_count'):
        hosts.write()
        return {'result': 'success',
                'message': 'Entry added. Matching entries replaced.'}
    if add_result.get('ipv4_count') or add_result.get('ipv6_count'):
        entry_to_add = True
    if add_result.get('duplicate_count'):
        duplicate_entry = True
    if entry_to_add and not duplicate_entry:
        hosts.write()
        return {'result': 'success',
                'message': 'New entry added.'}
    if not force_add and duplicate_entry:
        return {'result': 'failed',
                'message': 'New entry matches one or more existing.'
                           '\nUse -f to replace similar entries.'}

def import_from_file(hosts_path=None, file_path=None):
    if hosts_path and not os.path.exists(hosts_path):
        return {'result': 'failed', 'message': 'Cannot read hosts file: {0}'.format(hosts_path)}
    if not os.path.exists(file_path):
        return {'result': 'failed', 'message': 'Cannot read import file: {0}'.format(file_path)}
    else:
        hosts = Hosts(path=hosts_path)
        pre_count = len(hosts.entries)
        import_file_output = hosts.import_file(import_file_path=file_path)
        post_count = len(hosts.entries)
        write_result = import_file_output.get('write_result')
        message = 'New entries:\t{0}\nTotal entries:\t{1}\n'.format(
            post_count - pre_count,
            write_result.get('total_written')
        )
    return {'result': import_file_output.get('result'),
            'message': message}

def import_from_url(hosts_path=None, url=None):
    if hosts_path and not os.path.exists(hosts_path):
        return {'result': 'failed', 'message': 'Cannot read hosts file: {0}'.format(hosts_path)}
    else:
        hosts = Hosts(path=hosts_path)
        pre_count = len(hosts.entries)
        import_url_output = hosts.import_url(url=url)
        post_count = len(hosts.entries)
        write_result = import_url_output.get('write_result')
        message = 'New entries:\t{0}\nTotal entries:\t{1}\n'.format(
            post_count - pre_count,
            write_result.get('total_written')
        )
    return {'result': import_url_output.get('result'),
            'message': message}

def remove(address_to_remove=None, names_to_remove=None, remove_from_path=None):
    """
    Remove entries matching address and/or names
    """
    hosts = Hosts(path=remove_from_path)
    remove_result = None
    write_result = False
    if address_to_remove or names_to_remove:
        remove_result = hosts.remove_all_matching(address=address_to_remove, name=names_to_remove)
        write_result = hosts.write()

    if not write_result:
        return {'result': 'failed', 'message': 'Unable to write to path: {0}'.format(hosts.hosts_path)}
    if remove_result:
        str_entry = "entry"
        if remove_result > 1:
            str_entry = 'entries'
        return {'result': 'success', 'message': 'Removed {0} {1}.'.format(remove_result, str_entry)}
    else:
        return {'result': 'failed', 'message': 'No matching entries.'.format(remove_result)}

def strip_entry_value(entry_value):
    """
    :param entry_value: value to strip spaces from
    :return: value minus the leading and trailing spaces
    """
    if isinstance(entry_value, list):
        new_list = []
        for value in entry_value:
            new_list.append(value.strip())
        return ' '.join(new_list)
    if isinstance(entry_value, str):
        return entry_value.strip()

if __name__ == '__main__':
    arguments = docopt(__doc__, version='0.1.0')
    entry = arguments.get('ENTRY')
    path = arguments.get('--path')
    force = arguments.get('--force')
    backup = arguments.get('--backup')
    address = arguments.get('--address')
    names = arguments.get('--names')
    input_file = arguments.get('--input-file')
    input_url = arguments.get('--input-url')

    if not path:
        if sys.platform.startswith('win'):
            path = r'c:\windows\system32\drivers\etc\hosts'
        else:
            path = '/etc/hosts'

    if not utils.is_readable(path):
        output_message({'result': 'failed',
                        'message': 'Unable to read path: {0}.'.format(path)})

    new_entry = None
    if entry:
        new_entry = strip_entry_value(entry)

    if backup:
        result = backup_hosts(source=path)
        if result.get('result') == 'success':
            result['result'] = 'continue'
        output_message(result)

    if arguments.get('add'):
        final_message = None
        if not utils.is_writeable(path):
            output_message({'result': 'failed',
                            'message': 'Unable to write to: {0}'.format(path)})
        if new_entry:
            result = add(entry_line=new_entry, hosts_path=path, force_add=force)
            output_message(result)
        if input_file:
            result = import_from_file(hosts_path=path, file_path=input_file)
            output_message(result)
        if input_url:
            result = import_from_url(hosts_path=path, url=input_url)
            output_message(result)
    else:
        if arguments.get('remove'):
            result = remove(address_to_remove=address, names_to_remove=names, remove_from_path=path)
            output_message(result)
<|endoftext|>


<commit_before># Copyright (c) 2012-2021, Mark Peek <mark@peek.org>
# All rights reserved.
#
# See LICENSE file for full license.
#
# *** Do not modify - this file is autogenerated ***
# Resource specification version: 49.0.0

from . import AWSObject, AWSProperty

class FederationParameters(AWSProperty):
    props = {
        "ApplicationCallBackURL": (str, False),
        "AttributeMap": (dict, False),
        "FederationProviderName": (str, False),
        "FederationURN": (str, False),
        "SamlMetadataDocument": (str, False),
        "SamlMetadataURL": (str, False),
    }

class SuperuserParameters(AWSProperty):
    props = {
        "EmailAddress": (str, False),
        "FirstName": (str, False),
        "LastName": (str, False),
    }

class Environment(AWSObject):
    resource_type = "AWS::FinSpace::Environment"

    props = {
        "DataBundles": ([str], False),
        "Description": (str, False),
        "FederationMode": (str, False),
        "FederationParameters": (FederationParameters, False),
        "KmsKeyId": (str, False),
        "Name": (str, True),
        "SuperuserParameters": (SuperuserParameters, False),
    }
<commit_msg>Auto-generate FinSpace<commit_after># Copyright (c) 2012-2022, Mark Peek <mark@peek.org>
# All rights reserved.
#
# See LICENSE file for full license.
#
# *** Do not modify - this file is autogenerated ***
# Resource specification version: 51.0.0

from . import AWSObject, AWSProperty, PropsDictType

class FederationParameters(AWSProperty):
    """
    `FederationParameters <http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-finspace-environment-federationparameters.html>`__
    """

    props: PropsDictType = {
        "ApplicationCallBackURL": (str, False),
        "AttributeMap": (dict, False),
        "FederationProviderName": (str, False),
        "FederationURN": (str, False),
        "SamlMetadataDocument": (str, False),
        "SamlMetadataURL": (str, False),
    }

class SuperuserParameters(AWSProperty):
    """
    `SuperuserParameters <http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-finspace-environment-superuserparameters.html>`__
    """

    props: PropsDictType = {
        "EmailAddress": (str, False),
        "FirstName": (str, False),
        "LastName": (str, False),
    }

class Environment(AWSObject):
    """
    `Environment <http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-finspace-environment.html>`__
    """

    resource_type = "AWS::FinSpace::Environment"

    props: PropsDictType = {
        "DataBundles": ([str], False),
        "Description": (str, False),
        "FederationMode": (str, False),
        "FederationParameters": (FederationParameters, False),
        "KmsKeyId": (str, False),
        "Name": (str, True),
        "SuperuserParameters": (SuperuserParameters, False),
    }
<|endoftext|>


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

"""
Copyright 2015 Zalando SE

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the
License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific
language governing permissions and limitations under the License.
"""

from __future__ import print_function, absolute_import

from git.exc import InvalidGitRepositoryError
import git
import os

def get_repository(directory=None):
    """
    git.Repo() fails if it's not in the root of the repository so wee need to try the parents to see if we are inside
    a repository

    :rtype: Optional[git.Repo]
    """
    directory = directory or os.getcwd()
    repo = None
    while repo is None and directory != '/':
        print(directory)
        try:
            repo = git.Repo(directory)
        except InvalidGitRepositoryError:
            directory = os.path.dirname(directory)
    return repo
<commit_msg>https://github.com/zalando/turnstile/issues/37 Remove debugging print<commit_after>#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
Copyright 2015 Zalando SE

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the
License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific
language governing permissions and limitations under the License.
"""

from __future__ import print_function, absolute_import

from git.exc import InvalidGitRepositoryError
import git
import os

def get_repository(directory=None):
    """
    git.Repo() fails if it's not in the root of the repository so wee need to try the parents to see if we are inside
    a repository

    :rtype: Optional[git.Repo]
    """
    directory = directory or os.getcwd()
    repo = None
    while repo is None and directory != '/':
        try:
            repo = git.Repo(directory)
        except InvalidGitRepositoryError:
            directory = os.path.dirname(directory)
    return repo
<|endoftext|>


<commit_before>"""
Output some statistics for the real graph datasets.

"""
import os
import sys
import logging
import numpy
import itertools
from exp.clusterexp.CitationIterGenerator import CitationIterGenerator
from exp.clusterexp.HIVIterGenerator import HIVIterGenerator
from apgl.graph import GraphStatistics
from apgl.graph import SparseGraph, GraphUtils
from apgl.util.PathDefaults import PathDefaults
from exp.clusterexp.BemolData import BemolData
import matplotlib.pyplot as plt
import scipy.sparse.linalg

logging.basicConfig(stream=sys.stdout, level=logging.DEBUG)

plotHIV = False
plotCitation = False
plotBemol = True

saveResults = True
findEigs = False

if plotHIV:
    def getIterator():
        generator = HIVIterGenerator()
        return generator.getIterator()

    resultsDir = PathDefaults.getOutputDir() + "cluster/HIV/Stats/"

if plotCitation:

    def getIterator():
        maxGraphSize = 3000
        generator = CitationIterGenerator(maxGraphSize=maxGraphSize)
        return generator.getIterator()

    resultsDir = PathDefaults.getOutputDir() + "cluster/Citation/Stats/"
if plotBemol:
    def getIterator():
        dataDir = PathDefaults.getDataDir() + "cluster/"

        nbUser = 20000 # set to 'None' to have all users
        nbPurchasesPerIt = 100 # set to 'None' to take all the purchases per date
        startingIteration = 1000
        endingIteration = None # set to 'None' to have all iterations
        stepSize = 30

        return itertools.islice(BemolData.getGraphIterator(dataDir, nbUser, nbPurchasesPerIt), startingIteration, endingIteration, stepSize)
    resultsDir = PathDefaults.getOutputDir() + "cluster/Bemol/Stats/"

if saveResults:
    if not os.path.exists(resultsDir):
       logging.warn("Directory did not exist: " + resultsDir + ", creating ...")
       os.mkdir(resultsDir)

    iterator = getIterator()

    subgraphIndicesList = []
    for W in iterator:
        logging.debug("Graph size " + str(W.shape[0]))
        subgraphIndicesList.append(range(W.shape[0]))

    #Try to find number of clusters at end of sequence by looking at eigengap
    k = 2

    if findEigs:
        L = GraphUtils.normalisedLaplacianSym(W)

        logging.debug("Computing eigenvalues")
        omega, Q = scipy.sparse.linalg.eigsh(L, min(k, L.shape[0]-1), which="SM", ncv = min(20*k, L.shape[0]))

        omegaDiff = numpy.diff(omega)
    else:
        omega = numpy.zeros(k)
        omegaDiff = numpy.zeros(k-1)

    #No obvious number of clusters and there are many edges
    graph = SparseGraph(W.shape[0], W=W)

    logging.debug("Computing graph statistics")
    graphStats = GraphStatistics()
    statsMatrix = graphStats.sequenceScalarStats(graph, subgraphIndicesList, slowStats=False)

    numpy.savez(resultsDir + "GraphStats", statsMatrix, omega, omegaDiff)
    logging.debug("Saved results as " + resultsDir + "GraphStats.npz")
else:
    arr = numpy.load(resultsDir + "GraphStats.npz")
    statsMatrix, omega, omegaDiff = arr["arr_0"], arr["arr_1"], arr["arr_2"]

    graphStats = GraphStatistics()
    plotInd = 0

    if findEigs:
        plt.figure(plotInd)
        plt.plot(numpy.arange(omega.shape[0]), omega)
        plt.xlabel("Eigenvalue index")
        plt.ylabel("Eigenvalue")
        plt.savefig(resultsDir + "Spectrum.eps")
        plotInd+=1

        plt.figure(plotInd)
        plt.plot(numpy.arange(omegaDiff.shape[0]), omegaDiff)
        plt.xlabel("Eigenvalue index")
        plt.ylabel("Eigenvalue diff")
        plt.savefig(resultsDir + "SpectrumDiff.eps")
        plotInd +=1

    plt.figure(plotInd)
    plt.plot(numpy.arange(statsMatrix.shape[0]), statsMatrix[:, graphStats.numVerticesIndex])
    plt.xlabel("Graph index")
    plt.ylabel("Num vertices")
    plt.savefig(resultsDir + "Vertices.eps")
    plotInd+=1

    plt.figure(plotInd)
    plt.plot(numpy.arange(statsMatrix.shape[0]), statsMatrix[:, graphStats.numEdgesIndex])
    plt.xlabel("Graph index")
    plt.ylabel("Num edges")
    plt.savefig(resultsDir + "Edges.eps")
    plotInd+=1

    plt.figure(plotInd)
    plt.plot(numpy.arange(statsMatrix.shape[0]), statsMatrix[:, graphStats.maxComponentSizeIndex])
    plt.xlabel("Graph index")
    plt.ylabel("Max component size")
    plotInd+=1

    plt.figure(plotInd)
    plt.plot(numpy.arange(statsMatrix.shape[0]), statsMatrix[:, graphStats.numComponentsIndex])
    plt.xlabel("Graph index")
    plt.ylabel("Num components")
    plt.savefig(resultsDir + "Components.eps")
    plotInd+=1

    plt.show()
<commit_msg>Fix for missing dir <commit_after>"""
Output some statistics for the real graph datasets.

"""
import os
import sys
import logging
import numpy
import itertools
from exp.clusterexp.CitationIterGenerator import CitationIterGenerator
from exp.clusterexp.HIVIterGenerator import HIVIterGenerator
from apgl.graph import GraphStatistics
from apgl.graph import SparseGraph, GraphUtils
from apgl.util.PathDefaults import PathDefaults
from exp.clusterexp.BemolData import BemolData
import matplotlib.pyplot as plt
import scipy.sparse.linalg

logging.basicConfig(stream=sys.stdout, level=logging.DEBUG)

plotHIV = False
plotCitation = False
plotBemol = True

saveResults = False
findEigs = False

if plotHIV:
    def getIterator():
        generator = HIVIterGenerator()
        return generator.getIterator()

    resultsDir = PathDefaults.getOutputDir() + "cluster/HIV/Stats/"

if plotCitation:

    def getIterator():
        maxGraphSize = None
        generator = CitationIterGenerator(maxGraphSize=maxGraphSize)
        return generator.getIterator()

    resultsDir = PathDefaults.getOutputDir() + "cluster/Citation/Stats/"
if plotBemol:
    def getIterator():
        dataDir = PathDefaults.getDataDir() + "cluster/"

        nbUser = 10000 # set to 'None' to have all users
        nbPurchasesPerIt = 500 # set to 'None' to take all the purchases per date
        startingIteration = 300
        endingIteration = 600 # set to 'None' to have all iterations
        stepSize = 1

        return itertools.islice(BemolData.getGraphIterator(dataDir, nbUser, nbPurchasesPerIt), startingIteration, endingIteration, stepSize)
    resultsDir = PathDefaults.getOutputDir() + "cluster/Bemol/Stats/"

if saveResults:
    if not os.path.exists(resultsDir):
       logging.warn("Directory did not exist: " + resultsDir + ", created.")
       os.makedirs(resultsDir)

    iterator = getIterator()

    subgraphIndicesList = []
    for W in iterator:
        logging.debug("Graph size " + str(W.shape[0]))
        subgraphIndicesList.append(range(W.shape[0]))

    #Try to find number of clusters at end of sequence by looking at eigengap
    k = 2

    if findEigs:
        L = GraphUtils.normalisedLaplacianSym(W)

        logging.debug("Computing eigenvalues")
        omega, Q = scipy.sparse.linalg.eigsh(L, min(k, L.shape[0]-1), which="SM", ncv = min(20*k, L.shape[0]))

        omegaDiff = numpy.diff(omega)
    else:
        omega = numpy.zeros(k)
        omegaDiff = numpy.zeros(k-1)

    #No obvious number of clusters and there are many edges
    graph = SparseGraph(W.shape[0], W=W)

    logging.debug("Computing graph statistics")
    graphStats = GraphStatistics()
    statsMatrix = graphStats.sequenceScalarStats(graph, subgraphIndicesList, slowStats=False)

    numpy.savez(resultsDir + "GraphStats", statsMatrix, omega, omegaDiff)
    logging.debug("Saved results as " + resultsDir + "GraphStats.npz")
else:
    arr = numpy.load(resultsDir + "GraphStats.npz")
    statsMatrix, omega, omegaDiff = arr["arr_0"], arr["arr_1"], arr["arr_2"]

    graphStats = GraphStatistics()
    plotInd = 0

    if findEigs:
        plt.figure(plotInd)
        plt.plot(numpy.arange(omega.shape[0]), omega)
        plt.xlabel("Eigenvalue index")
        plt.ylabel("Eigenvalue")
        plt.savefig(resultsDir + "Spectrum.eps")
        plotInd+=1

        plt.figure(plotInd)
        plt.plot(numpy.arange(omegaDiff.shape[0]), omegaDiff)
        plt.xlabel("Eigenvalue index")
        plt.ylabel("Eigenvalue diff")
        plt.savefig(resultsDir + "SpectrumDiff.eps")
        plotInd +=1

    plt.figure(plotInd)
    plt.plot(numpy.arange(statsMatrix.shape[0]), statsMatrix[:, graphStats.numVerticesIndex])
    plt.xlabel("Graph index")
    plt.ylabel("Num vertices")
    plt.savefig(resultsDir + "Vertices.eps")
    plotInd+=1

    print(statsMatrix[:, graphStats.numEdgesIndex])

    plt.figure(plotInd)
    plt.plot(numpy.arange(statsMatrix.shape[0]), statsMatrix[:, graphStats.numEdgesIndex])
    plt.xlabel("Graph index")
    plt.ylabel("Num edges")
    plt.savefig(resultsDir + "Edges.eps")
    plotInd+=1

    plt.figure(plotInd)
    plt.plot(numpy.arange(statsMatrix.shape[0]), statsMatrix[:, graphStats.maxComponentSizeIndex])
    plt.xlabel("Graph index")
    plt.ylabel("Max component size")
    plotInd+=1

    plt.figure(plotInd)
    plt.plot(numpy.arange(statsMatrix.shape[0]), statsMatrix[:, graphStats.numComponentsIndex])
    plt.xlabel("Graph index")
    plt.ylabel("Num components")
    plt.savefig(resultsDir + "Components.eps")
    plotInd+=1

    plt.figure(plotInd)
    plt.plot(numpy.arange(statsMatrix.shape[0]), statsMatrix[:, graphStats.meanDegreeIndex])
    plt.xlabel("Graph index")
    plt.ylabel("Mean degree")
    plt.savefig(resultsDir + "MeanDegrees.eps")
    plotInd+=1

    plt.show()
<|endoftext|>


<commit_before>##
# Copyright (c) 2005-2007 Apple Inc. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# DRI: David Reid, dreid@apple.com
##

import os
import copy

from twisted.python import log

from twistedcaldav.py.plistlib import readPlist

defaultConfigFile = "/etc/caldavd/caldavd.plist"

serviceDefaultParams = {
    "twistedcaldav.directory.xmlfile.XMLDirectoryService": {
        "xmlFile": "/etc/caldavd/accounts.xml",
    },
    "twistedcaldav.directory.appleopendirectory.OpenDirectoryService": {
        "node": "/Search",
        "requireComputerRecord": True,
    },
}

defaultConfig = {
    #
    # Public network address information
    #
    #    This is the server's public network address, which is provided to
    #    clients in URLs and the like.  It may or may not be the network
    #    address that the server is listening to directly, though it is by
    #    default.  For example, it may be the address of a load balancer or
    #    proxy which forwards connections to the server.
    #
    "ServerHostName": "localhost", # Network host name.
    "HTTPPort": -1,                # HTTP port (None to disable HTTP)
    "SSLPort" : -1,                # SSL port (None to disable HTTPS)

    # Note: we'd use None above, but that confuses the command-line parser.

    #
    # Network address configuration information
    #
    #    This configures the actual network address that the server binds to.
    #
    "BindAddresses": [],   # List of IP addresses to bind to [empty = all]
    "BindHTTPPorts": [],   # List of port numbers to bind to for HTTP [empty = same as "Port"]
    "BindSSLPorts" : [],   # List of port numbers to bind to for SSL [empty = same as "SSLPort"]

    #
    # Data store
    #
    "DataRoot"             : "/Library/CalendarServer/Data",
    "DocumentRoot"         : "/Library/CalendarServer/Documents",
    "UserQuota"            : 104857600, # User quota (in bytes)
    "MaximumAttachmentSize":   1048576, # Attachment size limit (in bytes)

    #
    # Directory service
    #
    #    A directory service provides information about principals (eg.
    #    users, groups, locations and resources) to the server.
    #
    "DirectoryService": {
        "type": "twistedcaldav.directory.xmlfile.XMLDirectoryService",
        "params": serviceDefaultParams["twistedcaldav.directory.xmlfile.XMLDirectoryService"],
    },

    #
    # Special principals
    #
    "AdminPrincipals": [],                       # Principals with "DAV:all" access (relative URLs)
    "SudoersFile": "/etc/caldavd/sudoers.plist", # Principals that can pose as other principals
    "EnableProxyPrincipals": True,               # Create "proxy access" principals

    #
    # Authentication
    #
    "Authentication": {
        "Basic"   : { "Enabled": False },   # Clear text; best avoided
        "Digest"  : {                       # Digest challenge/response
            "Enabled": True,
            "Algorithm": "md5",
            "Qop": "",
        },
        "Kerberos": {                       # Kerberos/SPNEGO
            "Enabled": False,
            "ServicePrincipal": ''
        },
    },

    #
    # Logging
    #
    "Verbose": False,
    "AccessLogFile"  : "/var/log/caldavd/access.log",                   # Apache-style access log
    "ErrorLogFile"   : "/var/log/caldavd/error.log",                    # Server activity log
    "ServerStatsFile": "/Library/CalendarServer/Documents/stats.plist",
    "PIDFile"        : "/var/run/caldavd.pid",
    "RotateAccessLog": False,

    #
    # SSL/TLS
    #
    "SSLCertificate": "/etc/certificates/Default.crt", # Public key
    "SSLPrivateKey": "/etc/certificates/Default.key",  # Private key

    #
    # Process management
    #

    # Username and Groupname to drop privileges to, if empty privileges will
    # not be dropped.

    "UserName": "",
    "GroupName": "",
    "ProcessType": "Combined",
    "MultiProcess": {
        "ProcessCount": 0,
        "LoadBalancer": {
            "Enabled": True,
            "Scheduler": "LeastConnections",
        },
    },

    #
    # Service ACLs
    #
    "EnableSACLs": False,

    #
    # Non-standard CalDAV extensions
    #
    "EnableDropBox"      : False, # Calendar Drop Box
    "EnableNotifications": False, # Drop Box Notifications

    #
    # Implementation details
    #
    #    The following are specific to how the server is built, and useful
    #    for development, but shouldn't be needed by users.
    #

    # Twisted
    "Twisted": {
        "twistd": "/usr/share/caldavd/bin/twistd",
    },

    # Python Director
    "PythonDirector": {
        "pydir": "/usr/share/caldavd/bin/pydir.py",
        "ConfigFile": "/etc/caldavd/pydir.xml",
        "ControlSocket": "/var/run/caldavd-pydir.sock",
    },

    # Umask
    "umask": 0027,

    # A unix socket used for communication between the child and master
    # processes.
    "ControlSocket": "/var/run/caldavd.sock",

    # Support for Content-Encoding compression options as specified in
    # RFC2616 Section 3.5
    "ResponseCompression": True,
}

class Config (object):
    def __init__(self, defaults):
        self.setDefaults(defaults)
        self._data = copy.deepcopy(self._defaults)
        self._configFile = None

    def __str__(self):
        return str(self._data)

    def update(self, items):
        dsType = items.get("DirectoryService", {}).get("type", None)
        if dsType is None:
            dsType = self._data["DirectoryService"]["type"]
        else:
            if dsType == self._data["DirectoryService"]["type"]:
                oldParams = self._data["DirectoryService"]["params"]
                newParams = items["DirectoryService"].get("params", {})
                _mergeData(oldParams, newParams)
            else:
                if dsType in serviceDefaultParams:
                    self._data["DirectoryService"]["params"] = copy.deepcopy(serviceDefaultParams[dsType])
                else:
                    self._data["DirectoryService"]["params"] = {}

        for param in items.get("DirectoryService", {}).get("params", {}):
            if param not in serviceDefaultParams[dsType]:
                raise ConfigurationError("Parameter %s is not supported by service %s" % (param, dsType))

        _mergeData(self._data, items)

        for param in tuple(self._data["DirectoryService"]["params"]):
            if param not in serviceDefaultParams[self._data["DirectoryService"]["type"]]:
                del self._data["DirectoryService"]["params"][param]

        self.updateServerCapabilities()

    def updateServerCapabilities(self):
        """
        Change server capabilities based on the current config parameters.
        Here are the "features" in the config that need special treatment:

        EnableDropBox
        EnableNotifications
        """

        from twistedcaldav.resource import CalendarPrincipalResource
        CalendarPrincipalResource.enableDropBox(self.EnableDropBox)
        CalendarPrincipalResource.enableNotifications(self.EnableNotifications)

    def updateDefaults(self, items):
        _mergeData(self._defaults, items)
        self.update(items)

    def setDefaults(self, defaults):
        self._defaults = copy.deepcopy(defaults)

    def __setattr__(self, attr, value):
        if '_data' in self.__dict__ and attr in self.__dict__['_data']:
            self._data[attr] = value
        else:
            self.__dict__[attr] = value

    def __getattr__(self, attr):
        if attr in self._data:
            return self._data[attr]

        raise AttributeError(attr)

    def reload(self):
        self._data = copy.deepcopy(self._defaults)
        self.loadConfig(self._configFile)

    def loadConfig(self, configFile):
        self._configFile = configFile

        if configFile and os.path.exists(configFile):
            configDict = readPlist(configFile)
            configDict = _cleanup(configDict)
            self.update(configDict)

def _mergeData(oldData, newData):
    for key, value in newData.iteritems():
        if isinstance(value, (dict,)):
            if key in oldData:
                assert isinstance(oldData[key], (dict,))
            else:
                oldData[key] = {}
            _mergeData(oldData[key], value)
        else:
            oldData[key] = value

def _cleanup(configDict):
    cleanDict = copy.deepcopy(configDict)

    def deprecated(oldKey, newKey):
        log.err("Configuration option %r is deprecated in favor of %r." % (oldKey, newKey))

    def renamed(oldKey, newKey):
        deprecated(oldKey, newKey)
        cleanDict[newKey] = configDict[oldKey]
        del cleanDict[oldKey]

    renamedOptions = {
        "BindAddress"                : "BindAddresses",
        "ServerLogFile"              : "AccessLogFile",
        "MaximumAttachmentSizeBytes" : "MaximumAttachmentSize",
        "UserQuotaBytes"             : "UserQuota",
        "DropBoxEnabled"             : "EnableDropBox",
        "NotificationsEnabled"       : "EnableNotifications",
        "CalendarUserProxyEnabled"   : "EnableProxyPrincipals",
        "SACLEnable"                 : "EnableSACLs",
        "ServerType"                 : "ProcessType",
    }

    for key in configDict:
        if key in defaultConfig:
            continue

        if key == "SSLOnly":
            deprecated(key, "HTTPPort")
            if configDict["SSLOnly"]:
                cleanDict["HTTPPort"] = None
            del cleanDict["SSLOnly"]

        elif key == "SSLEnable":
            deprecated(key, "SSLPort")
            if not configDict["SSLEnable"]:
                cleanDict["SSLPort"] = None
            del cleanDict["SSLEnable"]

        elif key == "Port":
            deprecated(key, "HTTPPort")
            if not configDict.get("SSLOnly", False):
                cleanDict["HTTPPort"] = cleanDict["Port"]
            del cleanDict["Port"]

        elif key == "twistdLocation":
            deprecated(key, "Twisted -> twistd")
            if "Twisted" not in cleanDict:
                cleanDict["Twisted"] = {}
            cleanDict["Twisted"]["twistd"] = cleanDict["twistdLocation"]
            del cleanDict["twistdLocation"]

        elif key == "pydirLocation":
            deprecated(key, "PythonDirector -> pydir")
            if "PythonDirector" not in cleanDict:
                cleanDict["PythonDirector"] = {}
            cleanDict["PythonDirector"]["pydir"] = cleanDict["pydirLocation"]
            del cleanDict["pydirLocation"]

        elif key == "pydirConfig":
            deprecated(key, "PythonDirector -> pydir")
            if "PythonDirector" not in cleanDict:
                cleanDict["PythonDirector"] = {}
            cleanDict["PythonDirector"]["ConfigFile"] = cleanDict["pydirConfig"]
            del cleanDict["pydirConfig"]

        elif key in renamedOptions:
            renamed(key, renamedOptions[key])

        elif key == "RunStandalone":
            log.err("Ignoring obsolete configuration option: %s" % (key,))
            del cleanDict[key]

        else:
            log.err("Ignoring unknown configuration option: %s" % (key,))
            del cleanDict[key]

    return cleanDict

class ConfigurationError (RuntimeError):
    """
    Invalid server configuration.
    """

config = Config(defaultConfig)

def parseConfig(configFile):
    config.loadConfig(configFile)
<commit_msg>Make sure quotas are enabled by default.<commit_after>##
# Copyright (c) 2005-2007 Apple Inc. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# DRI: David Reid, dreid@apple.com
##

import os
import copy

from twisted.python import log

from twistedcaldav.py.plistlib import readPlist

defaultConfigFile = "/etc/caldavd/caldavd.plist"

serviceDefaultParams = {
    "twistedcaldav.directory.xmlfile.XMLDirectoryService": {
        "xmlFile": "/etc/caldavd/accounts.xml",
    },
    "twistedcaldav.directory.appleopendirectory.OpenDirectoryService": {
        "node": "/Search",
        "requireComputerRecord": True,
    },
}

defaultConfig = {
    #
    # Public network address information
    #
    #    This is the server's public network address, which is provided to
    #    clients in URLs and the like.  It may or may not be the network
    #    address that the server is listening to directly, though it is by
    #    default.  For example, it may be the address of a load balancer or
    #    proxy which forwards connections to the server.
    #
    "ServerHostName": "localhost", # Network host name.
    "HTTPPort": -1,                # HTTP port (None to disable HTTP)
    "SSLPort" : -1,                # SSL port (None to disable HTTPS)

    # Note: we'd use None above, but that confuses the command-line parser.

    #
    # Network address configuration information
    #
    #    This configures the actual network address that the server binds to.
    #
    "BindAddresses": [],   # List of IP addresses to bind to [empty = all]
    "BindHTTPPorts": [],   # List of port numbers to bind to for HTTP [empty = same as "Port"]
    "BindSSLPorts" : [],   # List of port numbers to bind to for SSL [empty = same as "SSLPort"]

    #
    # Data store
    #
    "DataRoot"             : "/Library/CalendarServer/Data",
    "DocumentRoot"         : "/Library/CalendarServer/Documents",
    "UserQuota"            : 104857600, # User quota (in bytes)
    "MaximumAttachmentSize":   1048576, # Attachment size limit (in bytes)

    #
    # Directory service
    #
    #    A directory service provides information about principals (eg.
    #    users, groups, locations and resources) to the server.
    #
    "DirectoryService": {
        "type": "twistedcaldav.directory.xmlfile.XMLDirectoryService",
        "params": serviceDefaultParams["twistedcaldav.directory.xmlfile.XMLDirectoryService"],
    },

    #
    # Special principals
    #
    "AdminPrincipals": [],                       # Principals with "DAV:all" access (relative URLs)
    "SudoersFile": "/etc/caldavd/sudoers.plist", # Principals that can pose as other principals
    "EnableProxyPrincipals": True,               # Create "proxy access" principals

    #
    # Authentication
    #
    "Authentication": {
        "Basic"   : { "Enabled": False },   # Clear text; best avoided
        "Digest"  : {                       # Digest challenge/response
            "Enabled": True,
            "Algorithm": "md5",
            "Qop": "",
        },
        "Kerberos": {                       # Kerberos/SPNEGO
            "Enabled": False,
            "ServicePrincipal": ''
        },
    },

    #
    # Logging
    #
    "Verbose": False,
    "AccessLogFile"  : "/var/log/caldavd/access.log",                   # Apache-style access log
    "ErrorLogFile"   : "/var/log/caldavd/error.log",                    # Server activity log
    "ServerStatsFile": "/Library/CalendarServer/Documents/stats.plist",
    "PIDFile"        : "/var/run/caldavd.pid",
    "RotateAccessLog": False,

    #
    # SSL/TLS
    #
    "SSLCertificate": "/etc/certificates/Default.crt", # Public key
    "SSLPrivateKey": "/etc/certificates/Default.key",  # Private key

    #
    # Process management
    #

    # Username and Groupname to drop privileges to, if empty privileges will
    # not be dropped.

    "UserName": "",
    "GroupName": "",
    "ProcessType": "Combined",
    "MultiProcess": {
        "ProcessCount": 0,
        "LoadBalancer": {
            "Enabled": True,
            "Scheduler": "LeastConnections",
        },
    },

    #
    # Service ACLs
    #
    "EnableSACLs": False,

    #
    # Non-standard CalDAV extensions
    #
    "EnableDropBox"      : False, # Calendar Drop Box
    "EnableNotifications": False, # Drop Box Notifications

    #
    # Implementation details
    #
    #    The following are specific to how the server is built, and useful
    #    for development, but shouldn't be needed by users.
    #

    # Twisted
    "Twisted": {
        "twistd": "/usr/share/caldavd/bin/twistd",
    },

    # Python Director
    "PythonDirector": {
        "pydir": "/usr/share/caldavd/bin/pydir.py",
        "ConfigFile": "/etc/caldavd/pydir.xml",
        "ControlSocket": "/var/run/caldavd-pydir.sock",
    },

    # Umask
    "umask": 0027,

    # A unix socket used for communication between the child and master
    # processes.
    "ControlSocket": "/var/run/caldavd.sock",

    # Support for Content-Encoding compression options as specified in
    # RFC2616 Section 3.5
    "ResponseCompression": True,
}

class Config (object):
    def __init__(self, defaults):
        self.setDefaults(defaults)
        self._data = copy.deepcopy(self._defaults)
        self._configFile = None

    def __str__(self):
        return str(self._data)

    def update(self, items):
        dsType = items.get("DirectoryService", {}).get("type", None)
        if dsType is None:
            dsType = self._data["DirectoryService"]["type"]
        else:
            if dsType == self._data["DirectoryService"]["type"]:
                oldParams = self._data["DirectoryService"]["params"]
                newParams = items["DirectoryService"].get("params", {})
                _mergeData(oldParams, newParams)
            else:
                if dsType in serviceDefaultParams:
                    self._data["DirectoryService"]["params"] = copy.deepcopy(serviceDefaultParams[dsType])
                else:
                    self._data["DirectoryService"]["params"] = {}

        for param in items.get("DirectoryService", {}).get("params", {}):
            if param not in serviceDefaultParams[dsType]:
                raise ConfigurationError("Parameter %s is not supported by service %s" % (param, dsType))

        _mergeData(self._data, items)

        for param in tuple(self._data["DirectoryService"]["params"]):
            if param not in serviceDefaultParams[self._data["DirectoryService"]["type"]]:
                del self._data["DirectoryService"]["params"][param]

        self.updateServerCapabilities()

    def updateServerCapabilities(self):
        """
        Change server capabilities based on the current config parameters.
        Here are the "features" in the config that need special treatment:

        EnableDropBox
        EnableNotifications
        """

        from twistedcaldav.resource import CalendarPrincipalResource
        CalendarPrincipalResource.enableDropBox(self.EnableDropBox)
        CalendarPrincipalResource.enableNotifications(self.EnableNotifications)

        # Handle global quota value
        from twistedcaldav.directory.calendar import DirectoryCalendarHomeResource
        from twistedcaldav.resource import CalDAVResource
        DirectoryCalendarHomeResource.quotaLimit = self.UserQuota
        CalDAVResource.sizeLimit = self.MaximumAttachmentSize

    def updateDefaults(self, items):
        _mergeData(self._defaults, items)
        self.update(items)

    def setDefaults(self, defaults):
        self._defaults = copy.deepcopy(defaults)

    def __setattr__(self, attr, value):
        if '_data' in self.__dict__ and attr in self.__dict__['_data']:
            self._data[attr] = value
        else:
            self.__dict__[attr] = value

    def __getattr__(self, attr):
        if attr in self._data:
            return self._data[attr]

        raise AttributeError(attr)

    def reload(self):
        self._data = copy.deepcopy(self._defaults)
        self.loadConfig(self._configFile)

    def loadConfig(self, configFile):
        self._configFile = configFile

        if configFile and os.path.exists(configFile):
            configDict = readPlist(configFile)
            configDict = _cleanup(configDict)
            self.update(configDict)

def _mergeData(oldData, newData):
    for key, value in newData.iteritems():
        if isinstance(value, (dict,)):
            if key in oldData:
                assert isinstance(oldData[key], (dict,))
            else:
                oldData[key] = {}
            _mergeData(oldData[key], value)
        else:
            oldData[key] = value

def _cleanup(configDict):
    cleanDict = copy.deepcopy(configDict)

    def deprecated(oldKey, newKey):
        log.err("Configuration option %r is deprecated in favor of %r." % (oldKey, newKey))

    def renamed(oldKey, newKey):
        deprecated(oldKey, newKey)
        cleanDict[newKey] = configDict[oldKey]
        del cleanDict[oldKey]

    renamedOptions = {
        "BindAddress"                : "BindAddresses",
        "ServerLogFile"              : "AccessLogFile",
        "MaximumAttachmentSizeBytes" : "MaximumAttachmentSize",
        "UserQuotaBytes"             : "UserQuota",
        "DropBoxEnabled"             : "EnableDropBox",
        "NotificationsEnabled"       : "EnableNotifications",
        "CalendarUserProxyEnabled"   : "EnableProxyPrincipals",
        "SACLEnable"                 : "EnableSACLs",
        "ServerType"                 : "ProcessType",
    }

    for key in configDict:
        if key in defaultConfig:
            continue

        if key == "SSLOnly":
            deprecated(key, "HTTPPort")
            if configDict["SSLOnly"]:
                cleanDict["HTTPPort"] = None
            del cleanDict["SSLOnly"]

        elif key == "SSLEnable":
            deprecated(key, "SSLPort")
            if not configDict["SSLEnable"]:
                cleanDict["SSLPort"] = None
            del cleanDict["SSLEnable"]

        elif key == "Port":
            deprecated(key, "HTTPPort")
            if not configDict.get("SSLOnly", False):
                cleanDict["HTTPPort"] = cleanDict["Port"]
            del cleanDict["Port"]

        elif key == "twistdLocation":
            deprecated(key, "Twisted -> twistd")
            if "Twisted" not in cleanDict:
                cleanDict["Twisted"] = {}
            cleanDict["Twisted"]["twistd"] = cleanDict["twistdLocation"]
            del cleanDict["twistdLocation"]

        elif key == "pydirLocation":
            deprecated(key, "PythonDirector -> pydir")
            if "PythonDirector" not in cleanDict:
                cleanDict["PythonDirector"] = {}
            cleanDict["PythonDirector"]["pydir"] = cleanDict["pydirLocation"]
            del cleanDict["pydirLocation"]

        elif key == "pydirConfig":
            deprecated(key, "PythonDirector -> pydir")
            if "PythonDirector" not in cleanDict:
                cleanDict["PythonDirector"] = {}
            cleanDict["PythonDirector"]["ConfigFile"] = cleanDict["pydirConfig"]
            del cleanDict["pydirConfig"]

        elif key in renamedOptions:
            renamed(key, renamedOptions[key])

        elif key == "RunStandalone":
            log.err("Ignoring obsolete configuration option: %s" % (key,))
            del cleanDict[key]

        else:
            log.err("Ignoring unknown configuration option: %s" % (key,))
            del cleanDict[key]

    return cleanDict

class ConfigurationError (RuntimeError):
    """
    Invalid server configuration.
    """

config = Config(defaultConfig)

def parseConfig(configFile):
    config.loadConfig(configFile)
<|endoftext|>