<commit_before>import os

from datetime import datetime, timedelta

from django.db import models
from django.core.exceptions import PermissionDenied, ValidationError
from mezzanine.conf import settings

from hs_core.signals import pre_check_bag_flag

class ResourceIRODSMixin(models.Model):
    """ This contains iRODS methods to be included as options for resources """
    class Meta:
        abstract = True

    @property
    def irods_home_path(self):
        """ Return the home path for local iRODS resources """
        return settings.IRODS_CWD

    def irods_full_path(self, path):
        """ return fully qualified path for local paths """
        if path.startswith('/'):
            return path
        else:
            return os.path.join(self.irods_home_path, path)

    def update_bag(self):
        """
        Update a bag if necessary.

        This uses the Django signal pre_check_bag_flag to prepare collections,
        and then checks the AVUs 'metadata_dirty' and 'bag_modified' to determine
        whether to regenerate the metadata files and/or bag.

        This is a synchronous update. The call waits until the update is finished.
        """
        from hs_core.tasks import create_bag_by_irods
        from hs_core.hydroshare.resource import check_resource_type
        from hs_core.hydroshare.hs_bagit import create_bag_files

        # send signal for pre_check_bag_flag
        resource_cls = check_resource_type(self.resource_type)
        pre_check_bag_flag.send(sender=resource_cls, resource=self)

        metadata_dirty = self.getAVU('metadata_dirty')
        bag_modified = self.getAVU('bag_modified')

        if metadata_dirty:  # automatically cast to Bool
            create_bag_files(self)
            self.setAVU('metadata_dirty', False)

        # the ticket system does synchronous bag creation.
        # async bag creation isn't supported.
        if bag_modified:  # automatically cast to Bool
            create_bag_by_irods(self.short_id)
            self.setAVU('bag_modified', False)

    def update_metadata_files(self):
        """
        Make the metadata files resourcemetadata.xml and resourcemap.xml up to date.

        This checks the "metadata dirty" AVU before updating files if necessary.
        """
        from hs_core.hydroshare.hs_bagit import create_bag_files

        metadata_dirty = self.getAVU('metadata_dirty')
        if metadata_dirty:
            create_bag_files(self)
            self.setAVU('metadata_dirty', False)

    def create_ticket(self, user, path=None, write=False, allowed_uses=1):
        """
        create an iRODS ticket for reading or modifying a resource

        :param user: user to authorize
        :param path: path in iRODS to the object being requested.
        :param allowed_uses: number of possible uses of the ticket; default is one use.
        :return:

        :raises PermissionDenied: if user is not allowed to create the ticket.
        :raises SessionException: if ticket fails to be created for some reason.
        :raises SuspiciousFileOperation: if path uses .. illegally

        WARNING: This creates a ticket that expires in one hour in UTC. If the
        iRODS and django servers are in different time zones and not set for UTC,
        this results in a useless ticket. This includes federated servers.

        THERE IS NO STRAIGHTFORWARD MECHANISM IN IRODS for determining the time zone
        or local time of an iRODS server.

        Also, note that there is no mechanism for asynchronous bag creation in the
        ticketing system. The bag is created *synchronously* if required. The
        ticket is not issued until the bag exists.

        """
        from hs_core.models import path_is_allowed

        # raises SuspiciousFileOperation if path is not allowed
        path_is_allowed(path)

        # authorize user
        if write:
            if not user.uaccess.can_change_resource(self):
                raise PermissionDenied("user {} cannot change resource {}"
                                       .format(user.username, self.short_id))
        else:
            if not user.uaccess.can_view_resource(self):
                raise PermissionDenied("user {} cannot view resource {}"
                                       .format(user.username, self.short_id))
        if path is None:
            path = self.file_path  # default = all data files

        # can only write resource files
        if write:
            if not path.startswith(self.file_path):
                raise PermissionDenied("{} can only write data files to {}"
                                       .format(user.username, self.short_id))
        # can read anything inside this particular resource
        else:
            if path == self.bag_path:
                self.update_bag()
            elif not path.startswith(self.root_path):
                raise PermissionDenied("invalid resource file path {}".format(path))
            elif path == self.resmap_path or path == self.scimeta_path:
                self.update_metadata_files()

        istorage = self.get_irods_storage()
        read_or_write = 'write' if write else 'read'
        if path.startswith(self.short_id) or path.startswith('bags/'):  # local path
            path = os.path.join(self.irods_home_path, path)
        stdout, stderr = istorage.session.run("iticket", None, 'create', read_or_write, path)
        if not stdout.startswith('ticket:'):
            raise ValidationError("ticket creation failed: {}", stderr)
        ticket = stdout.split('\n')[0]
        ticket = ticket[len('ticket:'):]
        istorage.session.run('iticket', None, 'mod', ticket,
                             'uses', str(allowed_uses))

        # This creates a timestamp with a one-hour timeout.
        # Note that this is a timeout on when the ticket is first used, and
        # not on the completion of the use, which can take considerably longer.
        # TODO: this will fail unless Django and iRODS are both running in UTC.
        # There is no current mechanism for determining the timezone of a remote iRODS
        # server from within iRODS; shell access is required.
        timeout = datetime.now() + timedelta(hours=1)
        formatted = timeout.strftime("%Y-%m-%d.%H:%M")
        istorage.session.run('iticket', None, 'mod', ticket,
                             'expires', formatted)

        return ticket, self.irods_full_path(path)

    def list_ticket(self, ticket):
        """ List a ticket's attributes """
        istorage = self.get_irods_storage()
        stdout, stderr = istorage.session.run("iticket", None, 'ls', ticket)
        if stdout.startswith('id:'):
            stuff = stdout.split('\n')
            output = {}
            for s in stuff:
                try:
                    line = s.split(': ')
                    key = line[0]
                    value = line[1]
                    if key == 'collection name' or key == 'data collection':
                        output['full_path'] = value
                        if self.is_federated:
                            if __debug__:
                                assert(value.startswith(self.resource_federation_path))
                            output['long_path'] = value[len(self.resource_federation_path):]
                            output['home_path'] = self.resource_federation_path
                        else:
                            location = value.search(self.short_id)
                            if __debug__:
                                assert(location >= 0)
                            if location == 0:
                                output['long_path'] = value
                                output['home_path'] = self.irods_home_path
                            else:
                                output['long_path'] = value[location:]
                                output['home_path'] = value[:(location-1)]

                        if __debug__:
                            assert(output['long_path'].startswith(self.short_id))

                    if key == 'string':
                        output['ticket'] = value
                    elif key == 'data-object name':
                        output['filename'] = value
                    elif key == 'ticket type':
                        output['type'] = value
                    elif key == 'owner name':
                        output['owner'] = value
                    elif key == 'owner zone':
                        output['zone'] = value
                    elif key == 'expire time':
                        output['expires'] = value
                    else:
                        output[line[0]] = line[1]
                except Exception:  # no ':' in line
                    pass

            # put in actual file path including folder and filename
            if 'filename' in output:
                output['full_path'] = os.path.join(output['full_path'], output['filename'])
            return output

        elif stdout == '':
            raise ValidationError("ticket {} not found".format(ticket))
        else:
            raise ValidationError("ticket {} error: {}".format(ticket, stderr))

    def delete_ticket(self, user, ticket):
        """
        delete an existing ticket

        :param ticket: ticket string

        :raises SessionException: if ticket does not exist.

        This checks that the user at least has the privilege the ticket grants,
        before deleting it. This is not quite as comprehensive as keeping a
        ticket history, but provides a small amount of safety nonetheless.

        It remains possible for one user to delete the ticket of another user without
        that user's knowledge, provided that the users have the same privilege.
        However, tickets are not broadcast, so this is unlikely to happen.

        The usual mechanism -- of checking that the user owns the ticket -- is not
        practical, because the ticket owner is always the proxy user.
        """
        meta = self.list_ticket(ticket)

        if self.root_path not in meta['full_path']:
            raise PermissionDenied("user {} cannot delete ticket for a different resource"
                                   .format(user.username))
        # get kind of ticket
        write = meta['type'] == 'write'

        # authorize user
        if write:
            if not user.uaccess.can_change_resource(self):
                raise PermissionDenied("user {} cannot delete change ticket for {}"
                                       .format(user.username, self.short_id))
        else:
            if not user.uaccess.can_view_resource(self):
                raise PermissionDenied("user {} cannot delete view ticket for {}"
                                       .format(user.username, self.short_id))
        istorage = self.get_irods_storage()
        istorage.session.run('iticket', None, 'delete', ticket)
        return meta

class ResourceFileIRODSMixin(models.Model):
    """ This contains iRODS functions related to resource files """
    class Meta:
        abstract = True

    def create_ticket(self, user, write=False):
        """ This creates a ticket to read or modify this file """
        return self.resource.create_ticket(user, path=self.storage_path, write=write)
<commit_msg>Allow anonymous user to issue ticket for public resource<commit_after>import os

from datetime import datetime, timedelta

from django.db import models
from django.core.exceptions import PermissionDenied, ValidationError
from mezzanine.conf import settings

from hs_core.signals import pre_check_bag_flag

class ResourceIRODSMixin(models.Model):
    """ This contains iRODS methods to be included as options for resources """
    class Meta:
        abstract = True

    @property
    def irods_home_path(self):
        """ Return the home path for local iRODS resources """
        return settings.IRODS_CWD

    def irods_full_path(self, path):
        """ return fully qualified path for local paths """
        if path.startswith('/'):
            return path
        else:
            return os.path.join(self.irods_home_path, path)

    def update_bag(self):
        """
        Update a bag if necessary.

        This uses the Django signal pre_check_bag_flag to prepare collections,
        and then checks the AVUs 'metadata_dirty' and 'bag_modified' to determine
        whether to regenerate the metadata files and/or bag.

        This is a synchronous update. The call waits until the update is finished.
        """
        from hs_core.tasks import create_bag_by_irods
        from hs_core.hydroshare.resource import check_resource_type
        from hs_core.hydroshare.hs_bagit import create_bag_files

        # send signal for pre_check_bag_flag
        resource_cls = check_resource_type(self.resource_type)
        pre_check_bag_flag.send(sender=resource_cls, resource=self)

        metadata_dirty = self.getAVU('metadata_dirty')
        bag_modified = self.getAVU('bag_modified')

        if metadata_dirty:  # automatically cast to Bool
            create_bag_files(self)
            self.setAVU('metadata_dirty', False)

        # the ticket system does synchronous bag creation.
        # async bag creation isn't supported.
        if bag_modified:  # automatically cast to Bool
            create_bag_by_irods(self.short_id)
            self.setAVU('bag_modified', False)

    def update_metadata_files(self):
        """
        Make the metadata files resourcemetadata.xml and resourcemap.xml up to date.

        This checks the "metadata dirty" AVU before updating files if necessary.
        """
        from hs_core.hydroshare.hs_bagit import create_bag_files

        metadata_dirty = self.getAVU('metadata_dirty')
        if metadata_dirty:
            create_bag_files(self)
            self.setAVU('metadata_dirty', False)

    def create_ticket(self, user, path=None, write=False, allowed_uses=1):
        """
        create an iRODS ticket for reading or modifying a resource

        :param user: user to authorize
        :param path: path in iRODS to the object being requested.
        :param allowed_uses: number of possible uses of the ticket; default is one use.
        :return:

        :raises PermissionDenied: if user is not allowed to create the ticket.
        :raises SessionException: if ticket fails to be created for some reason.
        :raises SuspiciousFileOperation: if path uses .. illegally

        WARNING: This creates a ticket that expires in one hour in UTC. If the
        iRODS and django servers are in different time zones and not set for UTC,
        this results in a useless ticket. This includes federated servers.

        THERE IS NO STRAIGHTFORWARD MECHANISM IN IRODS for determining the time zone
        or local time of an iRODS server.

        Also, note that there is no mechanism for asynchronous bag creation in the
        ticketing system. The bag is created *synchronously* if required. The
        ticket is not issued until the bag exists.

        """
        from hs_core.models import path_is_allowed

        # raises SuspiciousFileOperation if path is not allowed
        path_is_allowed(path)

        # authorize user
        if write:
            if user.username == 'anonymous' or not user.uaccess.can_change_resource(self):
                raise PermissionDenied("user {} cannot change resource {}"
                                       .format(user.username, self.short_id))
        else:
            if not self.raccess.public and not user.uaccess.can_view_resource(self):
                raise PermissionDenied("user {} cannot view resource {}"
                                       .format(user.username, self.short_id))
        if path is None:
            path = self.file_path  # default = all data files

        # can only write resource files
        if write:
            if not path.startswith(self.file_path):
                raise PermissionDenied("{} can only write data files to {}"
                                       .format(user.username, self.short_id))
        # can read anything inside this particular resource
        else:
            if path == self.bag_path:
                self.update_bag()
            elif not path.startswith(self.root_path):
                raise PermissionDenied("invalid resource file path {}".format(path))
            elif path == self.resmap_path or path == self.scimeta_path:
                self.update_metadata_files()

        istorage = self.get_irods_storage()
        read_or_write = 'write' if write else 'read'
        if path.startswith(self.short_id) or path.startswith('bags/'):  # local path
            path = os.path.join(self.irods_home_path, path)
        stdout, stderr = istorage.session.run("iticket", None, 'create', read_or_write, path)
        if not stdout.startswith('ticket:'):
            raise ValidationError("ticket creation failed: {}", stderr)
        ticket = stdout.split('\n')[0]
        ticket = ticket[len('ticket:'):]
        istorage.session.run('iticket', None, 'mod', ticket,
                             'uses', str(allowed_uses))

        # This creates a timestamp with a one-hour timeout.
        # Note that this is a timeout on when the ticket is first used, and
        # not on the completion of the use, which can take considerably longer.
        # TODO: this will fail unless Django and iRODS are both running in UTC.
        # There is no current mechanism for determining the timezone of a remote iRODS
        # server from within iRODS; shell access is required.
        timeout = datetime.now() + timedelta(hours=1)
        formatted = timeout.strftime("%Y-%m-%d.%H:%M")
        istorage.session.run('iticket', None, 'mod', ticket,
                             'expires', formatted)

        return ticket, self.irods_full_path(path)

    def list_ticket(self, ticket):
        """ List a ticket's attributes """
        istorage = self.get_irods_storage()
        stdout, stderr = istorage.session.run("iticket", None, 'ls', ticket)
        if stdout.startswith('id:'):
            stuff = stdout.split('\n')
            output = {}
            for s in stuff:
                try:
                    line = s.split(': ')
                    key = line[0]
                    value = line[1]
                    if key == 'collection name' or key == 'data collection':
                        output['full_path'] = value
                        if self.is_federated:
                            if __debug__:
                                assert(value.startswith(self.resource_federation_path))
                            output['long_path'] = value[len(self.resource_federation_path):]
                            output['home_path'] = self.resource_federation_path
                        else:
                            location = value.search(self.short_id)
                            if __debug__:
                                assert(location >= 0)
                            if location == 0:
                                output['long_path'] = value
                                output['home_path'] = self.irods_home_path
                            else:
                                output['long_path'] = value[location:]
                                output['home_path'] = value[:(location-1)]

                        if __debug__:
                            assert(output['long_path'].startswith(self.short_id))

                    if key == 'string':
                        output['ticket'] = value
                    elif key == 'data-object name':
                        output['filename'] = value
                    elif key == 'ticket type':
                        output['type'] = value
                    elif key == 'owner name':
                        output['owner'] = value
                    elif key == 'owner zone':
                        output['zone'] = value
                    elif key == 'expire time':
                        output['expires'] = value
                    else:
                        output[line[0]] = line[1]
                except Exception:  # no ':' in line
                    pass

            # put in actual file path including folder and filename
            if 'filename' in output:
                output['full_path'] = os.path.join(output['full_path'], output['filename'])
            return output

        elif stdout == '':
            raise ValidationError("ticket {} not found".format(ticket))
        else:
            raise ValidationError("ticket {} error: {}".format(ticket, stderr))

    def delete_ticket(self, user, ticket):
        """
        delete an existing ticket

        :param ticket: ticket string

        :raises SessionException: if ticket does not exist.

        This checks that the user at least has the privilege the ticket grants,
        before deleting it. This is not quite as comprehensive as keeping a
        ticket history, but provides a small amount of safety nonetheless.

        It remains possible for one user to delete the ticket of another user without
        that user's knowledge, provided that the users have the same privilege.
        However, tickets are not broadcast, so this is unlikely to happen.

        The usual mechanism -- of checking that the user owns the ticket -- is not
        practical, because the ticket owner is always the proxy user.
        """
        meta = self.list_ticket(ticket)

        if self.root_path not in meta['full_path']:
            raise PermissionDenied("user {} cannot delete ticket for a different resource"
                                   .format(user.username))
        # get kind of ticket
        write = meta['type'] == 'write'

        # authorize user
        if write:
            if not user.uaccess.can_change_resource(self):
                raise PermissionDenied("user {} cannot delete change ticket for {}"
                                       .format(user.username, self.short_id))
        else:
            if not user.uaccess.can_view_resource(self):
                raise PermissionDenied("user {} cannot delete view ticket for {}"
                                       .format(user.username, self.short_id))
        istorage = self.get_irods_storage()
        istorage.session.run('iticket', None, 'delete', ticket)
        return meta

class ResourceFileIRODSMixin(models.Model):
    """ This contains iRODS functions related to resource files """
    class Meta:
        abstract = True

    def create_ticket(self, user, write=False):
        """ This creates a ticket to read or modify this file """
        return self.resource.create_ticket(user, path=self.storage_path, write=write)
<|endoftext|>


<commit_before># Highly Optimized Object-Oriented Molecular Dynamics (HOOMD) Open
# Source Software License
# Copyright (c) 2008 Ames Laboratory Iowa State University
# All rights reserved.

# Redistribution and use of HOOMD, in source and binary forms, with or
# without modification, are permitted, provided that the following
# conditions are met:

# * Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.

# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.

# * Neither the name of the copyright holder nor the names HOOMD's
# contributors may be used to endorse or promote products derived from this
# software without specific prior written permission.

# Disclaimer

# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND
# CONTRIBUTORS ``AS IS''  AND ANY EXPRESS OR IMPLIED WARRANTIES,
# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
# AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.

# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS  BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
# THE POSSIBILITY OF SUCH DAMAGE.

# $Id$
# $URL$

import force;
import globals;
import math;
import hoomd;
import sys;
import util;

## \package hoomd_script.bond
# \brief Commands that specify %bond forces
#
# Bonds add forces between specified pairs of particles and are typically used to
# model chemical bonds. Bonds between particles are set when an input XML file is read
# (init.read_xml) or when an another initializer creates them (like init.create_random_polymers)
#
# By themselves, bonds that have been specified in an input file do nothing. Only when you
# specify a bond force (i.e. bond.harmonic), are forces actually calculated between the
# listed particles.

## Harmonic %bond forces
#
# The command bond.harmonic specifies a %harmonic potential energy between every bonded %pair of particles
# in the simulation.
# \f[ V(r) = \frac{1}{2} k \left( r - r_0 \right)^2 \f]
# where \f$ \vec{r} \f$ is the vector pointing from one particle to the other in the %pair.
#
# Coefficients \f$ k \f$ and \f$ r_0 \f$ must be set for each type of %bond in the simulation using
# set_coeff().
#
# \note Specifying the bond.harmonic command when no bonds are defined in the simulation results in an error.
class harmonic(force._force):
	## Specify the %harmonic %bond %force
	#
	# \b Example:
	# \code
	# harmonic = bond.harmonic()
	# \endcode
	def __init__(self):
		util.print_status_line();

		# check that some bonds are defined
		if globals.particle_data.getBondData().getNumBonds() == 0:
			print >> sys.stderr, "\n***Error! No bonds are defined.\n";
			raise RuntimeError("Error creating bond forces");

		# initialize the base class
		force._force.__init__(self);

		# create the c++ mirror class
		if globals.particle_data.getExecConf().exec_mode == hoomd.ExecutionConfiguration.executionMode.CPU:
			self.cpp_force = hoomd.HarmonicBondForceCompute(globals.particle_data);
		elif globals.particle_data.getExecConf().exec_mode == hoomd.ExecutionConfiguration.executionMode.GPU:
			self.cpp_force = hoomd.HarmonicBondForceComputeGPU(globals.particle_data);
		else:
			print >> sys.stderr, "\n***Error! Invalid execution mode\n";
			raise RuntimeError("Error creating bond forces");

		globals.bond_compute = self.cpp_force;

		globals.system.addCompute(self.cpp_force, self.force_name);

		# variable for tracking which bond type coefficients have been set
		self.bond_types_set = [];

	## Sets the %harmonic %bond coefficients for a particular %bond type
	#
	# \param bond_type Bond type to set coefficients for
	# \param k Coefficient \f$ k \f$ in the %force
	# \param r0 Coefficient \f$ r_0 \f$ in the %force
	#
	# Using set_coeff() requires that the specified %bond %force has been saved in a variable. i.e.
	# \code
	# harmonic = bond.harmonic()
	# \endcode
	#
	# \b Examples:
	# \code
	# harmonic.set_coeff('polymer', k=330.0, r0=0.84)
	# harmonic.set_coeff('backbone', k=100.0, r0=1.0)
	# \endcode
	#
	# The coefficients for every %bond type in the simulation must be set
	# before the run() can be started.
	def set_coeff(self, bond_type, k, r0):
		util.print_status_line();

		# set the parameters for the appropriate type
		self.cpp_force.setParams(globals.particle_data.getBondData().getTypeByName(bond_type), k, r0);

		# track which particle types we have set
		if not bond_type in self.bond_types_set:
			self.bond_types_set.append(bond_type);

	def update_coeffs(self):
		# get a list of all bond types in the simulation
		ntypes = globals.particle_data.getBondData().getNBondTypes();
		type_list = [];
		for i in xrange(0,ntypes):
			type_list.append(globals.particle_data.getBondData().getNameByType(i));

		# check to see if all particle types have been set
		for cur_type in type_list:
			if not cur_type in self.bond_types_set:
				print >> sys.stderr, "\n***Error:", cur_type, " coefficients missing in bond.harmonic\n";
				raise RuntimeError("Error updating coefficients");

## FENE %bond forces
#
# The command bond.fene specifies a %fene potential energy between every bonded %pair of particles
# in the simulation.
# \f[ V(r) = - k r_0^2 \ln \left( 1 - \left( \frac{r}{r_0} \right)^2 \right) \f]
# where \f$ \vec{r} \f$ is the vector pointing from one particle to the other in the %pair.
#
# Coefficients \f$ k \f$ and \f$ r_0 \f$ must be set for each type of %bond in the simulation using
# set_coeff().
#
# \note Specifying the bond.fene command when no bonds are defined in the simulation results in an error.
class fene(force._force):
	## Specify the %fene %bond %force
	#
	# \b Example:
	# \code
	# fene = bond.fene()
	# \endcode
	def __init__(self):
		util.print_status_line();

		# check that some bonds are defined
		if globals.particle_data.getBondData().getNumBonds() == 0:
			print >> sys.stderr, "\n***Error! No bonds are defined.\n";
			raise RuntimeError("Error creating bond forces");

		# initialize the base class
		force._force.__init__(self);

		# create the c++ mirror class
		if globals.particle_data.getExecConf().exec_mode == hoomd.ExecutionConfiguration.executionMode.CPU:
			self.cpp_force = hoomd.FENEBondForceCompute(globals.particle_data);
		elif globals.particle_data.getExecConf().exec_mode == hoomd.ExecutionConfiguration.executionMode.GPU:
			self.cpp_force = hoomd.FENEBondForceComputeGPU(globals.particle_data);
		else:
			print >> sys.stderr, "\n***Error! Invalid execution mode\n";
			raise RuntimeError("Error creating bond forces");

		globals.bond_compute = self.cpp_force;

		globals.system.addCompute(self.cpp_force, self.force_name);

		# variable for tracking which bond type coefficients have been set
		self.bond_types_set = [];

	## Sets the %fene %bond coefficients for a particular %bond type
	#
	# \param bond_type Bond type to set coefficients for
	# \param k Coefficient \f$ k \f$ in the %force
	# \param r0 Coefficient \f$ r_0 \f$ in the %force
	# \param sigma Coefficient \f$ sigma \f$ in the %force
	# \param epsilon Coefficient \f$ epsilon \f$ in the %force
	#
	# Using set_coeff() requires that the specified %bond %force has been saved in a variable. i.e.
	# \code
	# fene = bond.fene()
	# \endcode
	#
	# \b Examples:
	# \code
	# fene.set_coeff('polymer', k=30.0, r0=1.5, sigma=1.0, epsilon= 2.0)
	# fene.set_coeff('backbone', k=100.0, r0=1.0, sigma=1.0, epsilon= 2.0)
	# \endcode
	#
	# The coefficients for every %bond type in the simulation must be set
	# before the run() can be started.
	def set_coeff(self, bond_type, k, r0, sigma, epsilon):
		util.print_status_line();

		self.cpp_force.setParams(globals.particle_data.getBondData().getTypeByName(bond_type), k, r0, sigma, epsilon);
		# track which particle types we have set
		if not bond_type in self.bond_types_set:
			self.bond_types_set.append(bond_type);

	def update_coeffs(self):
		# get a list of all bond types in the simulation
		ntypes = globals.particle_data.getBondData().getNBondTypes();
		type_list = [];
		for i in xrange(0,ntypes):
			type_list.append(globals.particle_data.getBondData().getNameByType(i));

		# check to see if all particle types have been set
		for cur_type in type_list:
			if not cur_type in self.bond_types_set:
				print >> sys.stderr, "\n***Error:", cur_type, " coefficients missing in bond.fene\n";
				raise RuntimeError("Error updating coefficients");

<commit_msg>Updated documentation for bond.fene ticket #184<commit_after># Highly Optimized Object-Oriented Molecular Dynamics (HOOMD) Open
# Source Software License
# Copyright (c) 2008 Ames Laboratory Iowa State University
# All rights reserved.

# Redistribution and use of HOOMD, in source and binary forms, with or
# without modification, are permitted, provided that the following
# conditions are met:

# * Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.

# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.

# * Neither the name of the copyright holder nor the names HOOMD's
# contributors may be used to endorse or promote products derived from this
# software without specific prior written permission.

# Disclaimer

# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND
# CONTRIBUTORS ``AS IS''  AND ANY EXPRESS OR IMPLIED WARRANTIES,
# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
# AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.

# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS  BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
# THE POSSIBILITY OF SUCH DAMAGE.

# $Id$
# $URL$

import force;
import globals;
import math;
import hoomd;
import sys;
import util;

## \package hoomd_script.bond
# \brief Commands that specify %bond forces
#
# Bonds add forces between specified pairs of particles and are typically used to
# model chemical bonds. Bonds between particles are set when an input XML file is read
# (init.read_xml) or when an another initializer creates them (like init.create_random_polymers)
#
# By themselves, bonds that have been specified in an input file do nothing. Only when you
# specify a bond force (i.e. bond.harmonic), are forces actually calculated between the
# listed particles.

## Harmonic %bond forces
#
# The command bond.harmonic specifies a %harmonic potential energy between every bonded %pair of particles
# in the simulation.
# \f[ V(r) = \frac{1}{2} k \left( r - r_0 \right)^2 \f]
# where \f$ \vec{r} \f$ is the vector pointing from one particle to the other in the %pair.
#
# Coefficients \f$ k \f$ and \f$ r_0 \f$ must be set for each type of %bond in the simulation using
# set_coeff().
#
# \note Specifying the bond.harmonic command when no bonds are defined in the simulation results in an error.
class harmonic(force._force):
	## Specify the %harmonic %bond %force
	#
	# \b Example:
	# \code
	# harmonic = bond.harmonic()
	# \endcode
	def __init__(self):
		util.print_status_line();

		# check that some bonds are defined
		if globals.particle_data.getBondData().getNumBonds() == 0:
			print >> sys.stderr, "\n***Error! No bonds are defined.\n";
			raise RuntimeError("Error creating bond forces");

		# initialize the base class
		force._force.__init__(self);

		# create the c++ mirror class
		if globals.particle_data.getExecConf().exec_mode == hoomd.ExecutionConfiguration.executionMode.CPU:
			self.cpp_force = hoomd.HarmonicBondForceCompute(globals.particle_data);
		elif globals.particle_data.getExecConf().exec_mode == hoomd.ExecutionConfiguration.executionMode.GPU:
			self.cpp_force = hoomd.HarmonicBondForceComputeGPU(globals.particle_data);
		else:
			print >> sys.stderr, "\n***Error! Invalid execution mode\n";
			raise RuntimeError("Error creating bond forces");

		globals.bond_compute = self.cpp_force;

		globals.system.addCompute(self.cpp_force, self.force_name);

		# variable for tracking which bond type coefficients have been set
		self.bond_types_set = [];

	## Sets the %harmonic %bond coefficients for a particular %bond type
	#
	# \param bond_type Bond type to set coefficients for
	# \param k Coefficient \f$ k \f$ in the %force
	# \param r0 Coefficient \f$ r_0 \f$ in the %force
	#
	# Using set_coeff() requires that the specified %bond %force has been saved in a variable. i.e.
	# \code
	# harmonic = bond.harmonic()
	# \endcode
	#
	# \b Examples:
	# \code
	# harmonic.set_coeff('polymer', k=330.0, r0=0.84)
	# harmonic.set_coeff('backbone', k=100.0, r0=1.0)
	# \endcode
	#
	# The coefficients for every %bond type in the simulation must be set
	# before the run() can be started.
	def set_coeff(self, bond_type, k, r0):
		util.print_status_line();

		# set the parameters for the appropriate type
		self.cpp_force.setParams(globals.particle_data.getBondData().getTypeByName(bond_type), k, r0);

		# track which particle types we have set
		if not bond_type in self.bond_types_set:
			self.bond_types_set.append(bond_type);

	def update_coeffs(self):
		# get a list of all bond types in the simulation
		ntypes = globals.particle_data.getBondData().getNBondTypes();
		type_list = [];
		for i in xrange(0,ntypes):
			type_list.append(globals.particle_data.getBondData().getNameByType(i));

		# check to see if all particle types have been set
		for cur_type in type_list:
			if not cur_type in self.bond_types_set:
				print >> sys.stderr, "\n***Error:", cur_type, " coefficients missing in bond.harmonic\n";
				raise RuntimeError("Error updating coefficients");

## FENE %bond forces
#
# The command bond.fene specifies a %fene potential energy between every bonded %pair of particles
# in the simulation.
# \f[ V(r) = - k r_0^2 \ln \left( 1 - \left( \frac{r}{r_0} \right)^2 \right) + V_{\mathrm{WCA}}(r)\f]
# where \f$ \vec{r} \f$ is the vector pointing from one particle to the other in the %pair and
# \f{eqnarray*}
#   V_{\mathrm{WCA}}(r)  = & 4 \varepsilon \left[ \left( \frac{\sigma}{r} \right)^{12} - \left( \frac{\sigma}{r} \right)^{6} \right] & r < 2^{\frac{1}{6}}\sigma \\
#            = & 0          & r \ge 2^{\frac{1}{6}}\sigma    \\
#   \f}
#
# Coefficients \f$ k \f$, \f$ r_0 \f$, \f$ \varepsilon \f$ and \f$ \sigma \f$  must be set for
# each type of %bond in the simulation using set_coeff().
#
# \note Specifying the bond.fene command when no bonds are defined in the simulation results in an error.
class fene(force._force):
	## Specify the %fene %bond %force
	#
	# \b Example:
	# \code
	# fene = bond.fene()
	# \endcode
	def __init__(self):
		util.print_status_line();

		# check that some bonds are defined
		if globals.particle_data.getBondData().getNumBonds() == 0:
			print >> sys.stderr, "\n***Error! No bonds are defined.\n";
			raise RuntimeError("Error creating bond forces");

		# initialize the base class
		force._force.__init__(self);

		# create the c++ mirror class
		if globals.particle_data.getExecConf().exec_mode == hoomd.ExecutionConfiguration.executionMode.CPU:
			self.cpp_force = hoomd.FENEBondForceCompute(globals.particle_data);
		elif globals.particle_data.getExecConf().exec_mode == hoomd.ExecutionConfiguration.executionMode.GPU:
			self.cpp_force = hoomd.FENEBondForceComputeGPU(globals.particle_data);
		else:
			print >> sys.stderr, "\n***Error! Invalid execution mode\n";
			raise RuntimeError("Error creating bond forces");

		globals.bond_compute = self.cpp_force;

		globals.system.addCompute(self.cpp_force, self.force_name);

		# variable for tracking which bond type coefficients have been set
		self.bond_types_set = [];

	## Sets the %fene %bond coefficients for a particular %bond type
	#
	# \param bond_type Bond type to set coefficients for
	# \param k Coefficient \f$ k \f$ in the %force
	# \param r0 Coefficient \f$ r_0 \f$ in the %force
	# \param sigma Coefficient \f$ \sigma \f$ in the %force
	# \param epsilon Coefficient \f$ \epsilon \f$ in the %force
	#
	# Using set_coeff() requires that the specified %bond %force has been saved in a variable. i.e.
	# \code
	# fene = bond.fene()
	# \endcode
	#
	# \b Examples:
	# \code
	# fene.set_coeff('polymer', k=30.0, r0=1.5, sigma=1.0, epsilon= 2.0)
	# fene.set_coeff('backbone', k=100.0, r0=1.0, sigma=1.0, epsilon= 2.0)
	# \endcode
	#
	# The coefficients for every %bond type in the simulation must be set
	# before the run() can be started.
	def set_coeff(self, bond_type, k, r0, sigma, epsilon):
		util.print_status_line();

		self.cpp_force.setParams(globals.particle_data.getBondData().getTypeByName(bond_type), k, r0, sigma, epsilon);
		# track which particle types we have set
		if not bond_type in self.bond_types_set:
			self.bond_types_set.append(bond_type);

	def update_coeffs(self):
		# get a list of all bond types in the simulation
		ntypes = globals.particle_data.getBondData().getNBondTypes();
		type_list = [];
		for i in xrange(0,ntypes):
			type_list.append(globals.particle_data.getBondData().getNameByType(i));

		# check to see if all particle types have been set
		for cur_type in type_list:
			if not cur_type in self.bond_types_set:
				print >> sys.stderr, "\n***Error:", cur_type, " coefficients missing in bond.fene\n";
				raise RuntimeError("Error updating coefficients");

<|endoftext|>


<commit_before>"""
Use Naive Bayesian classification techniques to determine if a tweet is "abusive" (in this case talking about horses)
"""

import numpy as np
from sklearn.datasets import dump_svmlight_file
from sklearn.feature_extraction.text import CountVectorizer, TfidfTransformer
from sklearn.naive_bayes import MultinomialNB

class TweetClassifier(object):
    """
    Classifies tweets into good or bad depending on their horse quota.  Usage:

        from clean_tweet import TweetClassifier as TC
        t = TC("test_data.txt")
        t.train()
    """

    def __init__(self, file_path=None):
        self.path = file_path
        self.results = []
        self.tweets = []
        self.vocab = {}
        self.classifier = None
        self.probabilities = []

    def load_dataset(self, path=None):
        """
        Loads a data set from a text file.  The data set should have one tweet per line, with the last character
        being a `0` for "good" or `1` for bad.  Each tweet should start on a new line.  For instance:

            A horse is a horse of course1
            Jack and the beanstalk0

        :param path: The path to the text file that results are kept in (or None if the default should be used)
        """
        with open(path if path is not None else self.path) as f:
            for line in f:
                line = line[:-1] # remove trailing newline
                self.results.append(int(line[-1]))
                yield line[:-1]

    def train(self, dump_inputs=False):
        """
        Teaches the classifier based on the data set passed in the constructor

        :param dump_inputs: Set to True if you want the input file to be written to input.txt in svmlight format
        """

        # vectorise the text
        self.vectoriser = CountVectorizer(lowercase=True, strip_accents='unicode')
        res = self.vectoriser.fit_transform(self.load_dataset())

        # Apply "Term Frequency times Inverse Document Frequency" methodology.  The term frequency part is
        # not really required given the fixed tweet length but very common words should be ignored so inverse document
        # frequency is relevant
        self.transformer = TfidfTransformer()
        res = self.transformer.fit_transform(res)

        # create a numpy array of expected results
        expected = np.asarray(self.results)

        # write the output to SVM if desired
        if dump_inputs:
            dump_svmlight_file(res, expected, f="input.txt")

        self.vocab = self.vectoriser.get_feature_names()

        # use a multinomial classifier to generate probabilities
        self.classifier = MultinomialNB()
        self.classifier.fit(res, expected)
        self.probabilities = self.classifier.feature_log_prob_

    def predict(self, tweet):
        """
        Predicts whether a tweet is horsey using the trained classifier
        """
        tweets = [tweet]
        tweet_vec = self.vectoriser.transform([tweet])
        tweet_tf = self.transformer.transform(tweet_vec)
        return self.classifier.predict(tweet_tf)[0]
<commit_msg>Initialise objects to None<commit_after>"""
Use Naive Bayesian classification techniques to determine if a tweet is "abusive" (in this case talking about horses)
"""

import numpy as np
from sklearn.datasets import dump_svmlight_file
from sklearn.feature_extraction.text import CountVectorizer, TfidfTransformer
from sklearn.naive_bayes import MultinomialNB

class TweetClassifier(object):
    """
    Classifies tweets into good or bad depending on their horse quota.  Usage:

        from clean_tweet import TweetClassifier as TC
        t = TC("test_data.txt")
        t.train()
    """

    def __init__(self, file_path=None):
        self.path = file_path
        self.results = []
        self.tweets = []
        self.vocab = {}
        self.probabilities = []
        self.vectoriser = None
        self.transformer = None
        self.classifier = None

    def load_dataset(self, path=None):
        """
        Loads a data set from a text file.  The data set should have one tweet per line, with the last character
        being a `0` for "good" or `1` for bad.  Each tweet should start on a new line.  For instance:

            A horse is a horse of course1
            Jack and the beanstalk0

        :param path: The path to the text file that results are kept in (or None if the default should be used)
        """
        with open(path if path is not None else self.path) as f:
            for line in f:
                line = line[:-1] # remove trailing newline
                self.results.append(int(line[-1]))
                yield line[:-1]

    def train(self, dump_inputs=False):
        """
        Teaches the classifier based on the data set passed in the constructor

        :param dump_inputs: Set to True if you want the input file to be written to input.txt in svmlight format
        """

        # vectorise the text
        self.vectoriser = CountVectorizer(lowercase=True, strip_accents='unicode')
        res = self.vectoriser.fit_transform(self.load_dataset())

        # Apply "Term Frequency times Inverse Document Frequency" methodology.  The term frequency part is
        # not really required given the fixed tweet length but very common words should be ignored so inverse document
        # frequency is relevant
        self.transformer = TfidfTransformer()
        res = self.transformer.fit_transform(res)

        # create a numpy array of expected results
        expected = np.asarray(self.results)

        # write the output to SVM if desired
        if dump_inputs:
            dump_svmlight_file(res, expected, f="input.txt")

        self.vocab = self.vectoriser.get_feature_names()

        # use a multinomial classifier to generate probabilities
        self.classifier = MultinomialNB()
        self.classifier.fit(res, expected)
        self.probabilities = self.classifier.feature_log_prob_

    def predict(self, tweet):
        """
        Predicts whether a tweet is horsey using the trained classifier
        """
        tweets = [tweet]
        tweet_vec = self.vectoriser.transform([tweet])
        tweet_tf = self.transformer.transform(tweet_vec)
        return self.classifier.predict(tweet_tf)[0]
<|endoftext|>


<commit_before>"""
Copyright 2011 Ryan Fobel

This file is part of Microdrop.

Microdrop is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

Microdrop is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with Microdrop.  If not, see <http://www.gnu.org/licenses/>.
"""

import logging
from copy import deepcopy

import gtk
from pygtkhelpers.ui.objectlist.combined_fields import (CombinedFields,
                                                        CombinedRow, RowFields)
from textbuffer_with_undo import UndoableBuffer
from microdrop_utility.gui import register_shortcuts

from microdrop.plugin_manager import (ExtensionPoint, IPlugin, SingletonPlugin,
                              implements, PluginGlobals, ScheduleRequest,
                              emit_signal)
from microdrop.app_context import get_app

class ProtocolGridView(CombinedFields):
    def __init__(self, forms, enabled_attrs, *args, **kwargs):
        super(ProtocolGridView, self).__init__(forms, enabled_attrs, *args,
                **kwargs)
        self.connect('row-changed', self.on_row_changed)
        self.connect('rows-changed', self.on_rows_changed)
        self.connect('selection-changed', self.on_selection_changed)

    def _on_step_options_changed(self, form_name, step_number):
        observers = ExtensionPoint(IPlugin)
        # Get the instance of the specified plugin
        service = observers.service(form_name)
        if hasattr(service, 'get_step_values'):
            # Get the step option values from the plugin instance
            attrs = service.get_step_values(step_number=step_number)
            self._update_row_fields(form_name, step_number, attrs)
            logging.debug('[ProtocolGridView] _on_step_options_changed(): '\
                    'plugin_name=%s step_number=%s attrs=%s' % (form_name,
                            step_number, attrs))

    def _get_popup_menu(self, item, column_title, value, row_ids, menu_items=None):
        app = get_app()
        if menu_items is None:
            # Use list of tuples (menu label, callback) rather than a dict to
            # allow ordering.
            menu_items = []
        def request_field_filter(*args, **kwargs):
            from .field_filter_controller import FieldFilterController

            ffc = FieldFilterController()
            response = ffc.run(self.forms, self.enabled_fields_by_form_name)
            if response == gtk.RESPONSE_OK:
                self.emit('fields-filter-request',
                        ffc.enabled_fields_by_plugin)
        # Add menu entry to select enabled fields for each plugin
        menu_items += [('Select fields...', request_field_filter)]
        # Add seperator
        menu_items += [(None, None)]
        menu_items += [('Insert', lambda x: app.protocol.insert_step())]
        menu_items += [('Delete', self.delete_rows)]
        menu_items += [('Cut', self.cut_rows)]
        menu_items += [('Copy', self.copy_rows)]
        menu_items += [('Paste before', self.paste_rows_before)]
        menu_items += [('Paste after', self.paste_rows_after)]
        # Add seperator
        menu_items += [(None, None)]

        # Uncomment lines below to add menu item for running pudb
        #def run_pudb(*args, **kwargs):
            #import pudb; pudb.set_trace()
        #menu_items += [('Run pudb...', run_pudb)]

        return super(ProtocolGridView, self)._get_popup_menu(item, column_title, value,
                row_ids, menu_items)

    def paste_rows_before(self, *args, **kwargs):
        app = get_app()
        app.paste_steps(app.protocol.current_step_number)

    def paste_rows_after(self, *args, **kwargs):
        app = get_app()
        app.paste_steps()

    def copy_rows(self, *args, **kwargs):
        app = get_app()
        app.copy_steps(self.selected_ids)

    def delete_rows(self, *args, **kwargs):
        app = get_app()
        app.delete_steps(self.selected_ids)

    def cut_rows(self, *args, **kwargs):
        app = get_app()
        app.cut_steps(self.selected_ids)

    def select_row(self, row):
        if row not in self.selected_ids:
            self.set_cursor(row)

    def on_row_changed(self, list_, row_id, row, field_name, value):
        for form_name, uuid_code in self.uuid_mapping.iteritems():
            field_set_prefix = self.field_set_prefix % uuid_code
            if field_name.startswith(field_set_prefix):
                form_step = row.get_row_fields(form_name)
                observers = ExtensionPoint(IPlugin)
                service = observers.service(form_name)
                try:
                    service.set_step_values(form_step.attrs, step_number=row_id)
                except ValueError, e:
                    logging.error('Invalid value.%s' % str(e))

    def on_rows_changed(self, list_, row_ids, rows, attr):
        app = get_app()
        for step_number, step in [(i, self[i]) for i in row_ids]:
            for form_name, uuid_code in self.uuid_mapping.iteritems():
                field_set_prefix = self.field_set_prefix % uuid_code
                if attr.startswith(field_set_prefix):
                    form_step = step.get_row_fields(form_name)
                    observers = ExtensionPoint(IPlugin)
                    service = observers.service(form_name)
                    service.set_step_values(form_step.attrs, step_number=step_number)

    def on_selection_changed(self, grid_view):
        if self.selected_ids:
            logging.debug('[ProtocolGridView].on_selection_changed: '
                         'selected_ids=%s' % str(self.selected_ids))
            app = get_app()
            logging.debug('\tcurrent_step_number=%d' % \
                         (app.protocol.current_step_number))
            if app.protocol.current_step_number not in self.selected_ids:
                app.protocol.goto_step(self.selected_ids[0])

PluginGlobals.push_env('microdrop')

class ProtocolGridController(SingletonPlugin):
    implements(IPlugin)

    def __init__(self):
        self.name = "microdrop.gui.protocol_grid_controller"
        self.builder = None
        self.widget = None
        self._enabled_fields = None
        # e.g., 'wheelerlab.dmf_control_board_1.2':\
                #set(['duration', 'voltage'])}

    @property
    def enabled_fields(self):
        return self._enabled_fields

    @enabled_fields.setter
    def enabled_fields(self, data):
        self._enabled_fields = deepcopy(data)
        self.update_grid()

    def on_plugin_enable(self):
        app = get_app()
        self.parent = app.builder.get_object("vbox2")
        self.window = gtk.ScrolledWindow()
        self.window.show_all()
        self.parent.add(self.window)

    def on_plugin_enabled(self, env, plugin):
        self.update_grid()

    def on_plugin_disabled(self, env, plugin):
        self.update_grid()

    def test(self, *args, **kwargs):
        print 'args=%s, kwargs=%s' % (args, kwargs)
        print 'attrs=%s' % args[1].attrs

    def on_step_options_changed(self, plugin, step_number):
        if self.widget is None:
            return
        self.widget._on_step_options_changed(plugin, step_number)

    def on_protocol_swapped(self, old_protocol, protocol):
        self.update_grid(protocol)

    def set_fields_filter(self, combined_fields, enabled_fields_by_plugin):
        app = get_app()
        self.enabled_fields = enabled_fields_by_plugin
        self.widget.select_row(app.protocol.current_step_number)
        logging.debug('[ProtocolGridController] set_fields_filter: %s' % self.enabled_fields)

    def update_grid(self, protocol=None):
        app = get_app()
        if protocol is None:
            protocol = app.protocol
        if protocol is None:
            return
        logging.debug('[ProtocolGridController].update_grid:')
        logging.debug('[ProtocolGridController]   plugin_fields=%s' % protocol.plugin_fields)
        forms = emit_signal('get_step_form_class')

        steps = protocol.steps
        logging.debug('[ProtocolGridController]   forms=%s steps=%s' % (forms, steps))

        if self.enabled_fields is None:
            # Assign directly to _enabled_fields to avoid recursive call into
            # update_grid()
            self._enabled_fields = dict([(form_name,
                    set(form.field_schema_mapping.keys()))
                            for form_name, form in forms.items()])
        # The step ID column can be hidden by changing show_ids to False
        combined_fields = ProtocolGridView(forms, self.enabled_fields, show_ids=True)
        combined_fields.connect('fields-filter-request', self.set_fields_filter)

        for i, step in enumerate(steps):
            values = emit_signal('get_step_values', [i])
            logging.debug('[ProtocolGridController]   Step[%d]=%s values=%s' % (i, step, values))

            attributes = dict()
            for form_name, form in combined_fields.forms.iteritems():
                attr_values = values[form_name]
                logging.debug('[CombinedRow] attr_values=%s' % attr_values)
                attributes[form_name] = RowFields(**attr_values)
            c = CombinedRow(combined_fields, attributes=attributes)
            combined_fields.append(c)
        if self.widget:
            self.window.remove(self.widget)
            del self.widget
        self.widget = combined_fields
        if self.widget:
            self.widget.show_all()
            self.widget.select_row(app.protocol.current_step_number)
            self._register_shortcuts()
            self.window.add(self.widget)

    def _register_shortcuts(self):
        class FocusWrapper(object):
            '''
            This class allows for a function to be executed, restoring the
            focused state of the protocol grid view if necessary.
            '''
            def __init__(self, controller, func):
                self.controller = controller
                self.func = func

            def __call__(self):
                focused = self.controller.widget.has_focus()
                self.func()
                if focused:
                    self.controller.widget.grab_focus()

        app = get_app()
        view = app.main_window_controller.view
        shortcuts = {
            '<Control>c': self.widget.copy_rows,
            '<Control>x': FocusWrapper(self, self.widget.cut_rows),
            'Delete': FocusWrapper(self, self.widget.delete_rows),
            '<Control>v': FocusWrapper(self, self.widget.paste_rows_after),
            '<Control><Shift>v': FocusWrapper(self,
                    self.widget.paste_rows_before),
            '<Control><Shift>i': FocusWrapper(self,
                    lambda: app.protocol.insert_step()),
        }
        register_shortcuts(view, shortcuts, enabled_widgets=[self.widget])

    def get_schedule_requests(self, function_name):
        """
        Returns a list of scheduling requests (i.e., ScheduleRequest
        instances) for the function specified by function_name.
        """
        if function_name == 'on_plugin_enable':
            return [ScheduleRequest('microdrop.gui.main_window_controller', self.name)]
        elif function_name == 'on_protocol_swapped':
            # ensure that the app's reference to the new protocol gets set
            return [ScheduleRequest('microdrop.app', self.name)]
        return []

    def on_step_created(self, step_number):
        logging.debug('[ProtocolGridController] on_step_created[%d]', step_number)
        self.update_grid()

    def on_step_swapped(self, original_step_number, step_number):
        logging.debug('[ProtocolGridController] on_step_swapped[%d->%d]',
                original_step_number, step_number)
        self.widget.select_row(get_app().protocol.current_step_number)

    def on_step_removed(self, step_number, step):
        app = get_app()
        logging.debug('[ProtocolGridController] on_step_removed[%d]',
                step_number)
        self.update_grid()

PluginGlobals.pop_env()
<commit_msg>Reset value to previous value on error in grid<commit_after>"""
Copyright 2011 Ryan Fobel

This file is part of Microdrop.

Microdrop is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

Microdrop is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with Microdrop.  If not, see <http://www.gnu.org/licenses/>.
"""

import logging
from copy import deepcopy

import gtk
from pygtkhelpers.ui.objectlist.combined_fields import (CombinedFields,
                                                        CombinedRow, RowFields)
from textbuffer_with_undo import UndoableBuffer
from microdrop_utility.gui import register_shortcuts

from microdrop.plugin_manager import (ExtensionPoint, IPlugin, SingletonPlugin,
                              implements, PluginGlobals, ScheduleRequest,
                              emit_signal)
from microdrop.app_context import get_app

class ProtocolGridView(CombinedFields):
    def __init__(self, forms, enabled_attrs, *args, **kwargs):
        super(ProtocolGridView, self).__init__(forms, enabled_attrs, *args,
                **kwargs)
        self.connect('row-changed', self.on_row_changed)
        self.connect('rows-changed', self.on_rows_changed)
        self.connect('selection-changed', self.on_selection_changed)

    def _on_step_options_changed(self, form_name, step_number):
        observers = ExtensionPoint(IPlugin)
        # Get the instance of the specified plugin
        service = observers.service(form_name)
        if hasattr(service, 'get_step_values'):
            # Get the step option values from the plugin instance
            attrs = service.get_step_values(step_number=step_number)
            self._update_row_fields(form_name, step_number, attrs)
            logging.debug('[ProtocolGridView] _on_step_options_changed(): '\
                    'plugin_name=%s step_number=%s attrs=%s' % (form_name,
                            step_number, attrs))

    def _get_popup_menu(self, item, column_title, value, row_ids, menu_items=None):
        app = get_app()
        if menu_items is None:
            # Use list of tuples (menu label, callback) rather than a dict to
            # allow ordering.
            menu_items = []
        def request_field_filter(*args, **kwargs):
            from .field_filter_controller import FieldFilterController

            ffc = FieldFilterController()
            response = ffc.run(self.forms, self.enabled_fields_by_form_name)
            if response == gtk.RESPONSE_OK:
                self.emit('fields-filter-request',
                        ffc.enabled_fields_by_plugin)
        # Add menu entry to select enabled fields for each plugin
        menu_items += [('Select fields...', request_field_filter)]
        # Add seperator
        menu_items += [(None, None)]
        menu_items += [('Insert', lambda x: app.protocol.insert_step())]
        menu_items += [('Delete', self.delete_rows)]
        menu_items += [('Cut', self.cut_rows)]
        menu_items += [('Copy', self.copy_rows)]
        menu_items += [('Paste before', self.paste_rows_before)]
        menu_items += [('Paste after', self.paste_rows_after)]
        # Add seperator
        menu_items += [(None, None)]

        # Uncomment lines below to add menu item for running pudb
        #def run_pudb(*args, **kwargs):
            #import pudb; pudb.set_trace()
        #menu_items += [('Run pudb...', run_pudb)]

        return super(ProtocolGridView, self)._get_popup_menu(item, column_title, value,
                row_ids, menu_items)

    def paste_rows_before(self, *args, **kwargs):
        app = get_app()
        app.paste_steps(app.protocol.current_step_number)

    def paste_rows_after(self, *args, **kwargs):
        app = get_app()
        app.paste_steps()

    def copy_rows(self, *args, **kwargs):
        app = get_app()
        app.copy_steps(self.selected_ids)

    def delete_rows(self, *args, **kwargs):
        app = get_app()
        app.delete_steps(self.selected_ids)

    def cut_rows(self, *args, **kwargs):
        app = get_app()
        app.cut_steps(self.selected_ids)

    def select_row(self, row):
        if row not in self.selected_ids:
            self.set_cursor(row)

    def on_row_changed(self, list_, row_id, row, field_name, value):
        for form_name, uuid_code in self.uuid_mapping.iteritems():
            field_set_prefix = self.field_set_prefix % uuid_code
            if field_name.startswith(field_set_prefix):
                form_step = row.get_row_fields(form_name)
                observers = ExtensionPoint(IPlugin)
                service = observers.service(form_name)
                try:
                    service.set_step_values(form_step.attrs,
                                            step_number=row_id)
                except ValueError:
                    logging.error('Invalid value. %s', value)
                    self._on_step_options_changed(form_name, row_id)

    def on_rows_changed(self, list_, row_ids, rows, attr):
        for step_number, step in [(i, self[i]) for i in row_ids]:
            for form_name, uuid_code in self.uuid_mapping.iteritems():
                field_set_prefix = self.field_set_prefix % uuid_code
                if attr.startswith(field_set_prefix):
                    form_step = step.get_row_fields(form_name)
                    observers = ExtensionPoint(IPlugin)
                    service = observers.service(form_name)
                    service.set_step_values(form_step.attrs, step_number=step_number)

    def on_selection_changed(self, grid_view):
        if self.selected_ids:
            logging.debug('[ProtocolGridView].on_selection_changed: '
                         'selected_ids=%s' % str(self.selected_ids))
            app = get_app()
            logging.debug('\tcurrent_step_number=%d' % \
                         (app.protocol.current_step_number))
            if app.protocol.current_step_number not in self.selected_ids:
                app.protocol.goto_step(self.selected_ids[0])

PluginGlobals.push_env('microdrop')

class ProtocolGridController(SingletonPlugin):
    implements(IPlugin)

    def __init__(self):
        self.name = "microdrop.gui.protocol_grid_controller"
        self.builder = None
        self.widget = None
        self._enabled_fields = None
        # e.g., 'wheelerlab.dmf_control_board_1.2':\
                #set(['duration', 'voltage'])}

    @property
    def enabled_fields(self):
        return self._enabled_fields

    @enabled_fields.setter
    def enabled_fields(self, data):
        self._enabled_fields = deepcopy(data)
        self.update_grid()

    def on_plugin_enable(self):
        app = get_app()
        self.parent = app.builder.get_object("vbox2")
        self.window = gtk.ScrolledWindow()
        self.window.show_all()
        self.parent.add(self.window)

    def on_plugin_enabled(self, env, plugin):
        self.update_grid()

    def on_plugin_disabled(self, env, plugin):
        self.update_grid()

    def test(self, *args, **kwargs):
        print 'args=%s, kwargs=%s' % (args, kwargs)
        print 'attrs=%s' % args[1].attrs

    def on_step_options_changed(self, plugin, step_number):
        if self.widget is None:
            return
        self.widget._on_step_options_changed(plugin, step_number)

    def on_protocol_swapped(self, old_protocol, protocol):
        self.update_grid(protocol)

    def set_fields_filter(self, combined_fields, enabled_fields_by_plugin):
        app = get_app()
        self.enabled_fields = enabled_fields_by_plugin
        self.widget.select_row(app.protocol.current_step_number)
        logging.debug('[ProtocolGridController] set_fields_filter: %s' % self.enabled_fields)

    def update_grid(self, protocol=None):
        app = get_app()
        if protocol is None:
            protocol = app.protocol
        if protocol is None:
            return
        logging.debug('[ProtocolGridController].update_grid:')
        logging.debug('[ProtocolGridController]   plugin_fields=%s' % protocol.plugin_fields)
        forms = emit_signal('get_step_form_class')

        steps = protocol.steps
        logging.debug('[ProtocolGridController]   forms=%s steps=%s' % (forms, steps))

        if self.enabled_fields is None:
            # Assign directly to _enabled_fields to avoid recursive call into
            # update_grid()
            self._enabled_fields = dict([(form_name,
                    set(form.field_schema_mapping.keys()))
                            for form_name, form in forms.items()])
        # The step ID column can be hidden by changing show_ids to False
        combined_fields = ProtocolGridView(forms, self.enabled_fields, show_ids=True)
        combined_fields.connect('fields-filter-request', self.set_fields_filter)

        for i, step in enumerate(steps):
            values = emit_signal('get_step_values', [i])
            logging.debug('[ProtocolGridController]   Step[%d]=%s values=%s' % (i, step, values))

            attributes = dict()
            for form_name, form in combined_fields.forms.iteritems():
                attr_values = values[form_name]
                logging.debug('[CombinedRow] attr_values=%s' % attr_values)
                attributes[form_name] = RowFields(**attr_values)
            c = CombinedRow(combined_fields, attributes=attributes)
            combined_fields.append(c)
        if self.widget:
            self.window.remove(self.widget)
            del self.widget
        self.widget = combined_fields
        if self.widget:
            self.widget.show_all()
            self.widget.select_row(app.protocol.current_step_number)
            self._register_shortcuts()
            self.window.add(self.widget)

    def _register_shortcuts(self):
        class FocusWrapper(object):
            '''
            This class allows for a function to be executed, restoring the
            focused state of the protocol grid view if necessary.
            '''
            def __init__(self, controller, func):
                self.controller = controller
                self.func = func

            def __call__(self):
                focused = self.controller.widget.has_focus()
                self.func()
                if focused:
                    self.controller.widget.grab_focus()

        app = get_app()
        view = app.main_window_controller.view
        shortcuts = {
            '<Control>c': self.widget.copy_rows,
            '<Control>x': FocusWrapper(self, self.widget.cut_rows),
            'Delete': FocusWrapper(self, self.widget.delete_rows),
            '<Control>v': FocusWrapper(self, self.widget.paste_rows_after),
            '<Control><Shift>v': FocusWrapper(self,
                    self.widget.paste_rows_before),
            '<Control><Shift>i': FocusWrapper(self,
                    lambda: app.protocol.insert_step()),
        }
        register_shortcuts(view, shortcuts, enabled_widgets=[self.widget])

    def get_schedule_requests(self, function_name):
        """
        Returns a list of scheduling requests (i.e., ScheduleRequest
        instances) for the function specified by function_name.
        """
        if function_name == 'on_plugin_enable':
            return [ScheduleRequest('microdrop.gui.main_window_controller', self.name)]
        elif function_name == 'on_protocol_swapped':
            # ensure that the app's reference to the new protocol gets set
            return [ScheduleRequest('microdrop.app', self.name)]
        return []

    def on_step_created(self, step_number):
        logging.debug('[ProtocolGridController] on_step_created[%d]', step_number)
        self.update_grid()

    def on_step_swapped(self, original_step_number, step_number):
        logging.debug('[ProtocolGridController] on_step_swapped[%d->%d]',
                original_step_number, step_number)
        self.widget.select_row(get_app().protocol.current_step_number)

    def on_step_removed(self, step_number, step):
        app = get_app()
        logging.debug('[ProtocolGridController] on_step_removed[%d]',
                step_number)
        self.update_grid()

PluginGlobals.pop_env()
<|endoftext|>


<commit_before>#!/usr/bin/env python3
"""
bulb.py
~~~~~~~

This module is for communicating with the MagicHome LED bulb over the network.

Wire protocol:

-------------------------------------
|header(1)|data(5-70)|0f|checksum(1)|
-------------------------------------

header:
    31 color & white
    41 camera
    51 custom
    61 function

color, white, camera (8 bytes):
    00-ff red
    00-ff green
    00-ff blue
    00-ff white
    mode:
        0f white
        f0 color

functions (5 bytes):
    25-38 modes
    1f-01 speed (decreasing)
    0f who knows

custom (70 bytes):
    64 bytes of r, g, b, 0 (empty color is 0x01020300)
    1f-01 speed (decreasing)
    3a,3b,3c gradual, jumping, strobe
    ff tail

tail:
    0f
    checksum (sum of data fields)
"""
import socket
import sys
from datetime import datetime
from time import sleep

import pytz
from astral import Astral
from typing import Dict

from home import settings
from home.core.utils import num

SUPPORTED_MODES = ['31', '41', '61']
SUPPORTED_FUNCTIONS = list(range(25, 39))
TAIL = '0f'

seven_color_cross_fade = 0x25
red_gradual_change = 0x26
green_gradual_change = 0x27
blue_gradual_change = 0x28
yellow_gradual_change = 0x29
cyan_gradual_change = 0x2a
purple_gradual_change = 0x2b
white_gradual_change = 0x2c
red_green_cross_fade = 0x2d
red_blue_cross_fade = 0x2e
green_blue_cross_fade = 0x2f
seven_color_strobe_flash = 0x30
red_strobe_flash = 0x31
green_strobe_flash = 0x32
blue_stobe_flash = 0x33
yellow_strobe_flash = 0x34
cyan_strobe_flash = 0x35
purple_strobe_flash = 0x36
white_strobe_flash = 0x37
seven_color_jumping = 0x38

CONTROL_PORT = 5577
# The HFLPB100's control/debug module
HF_COMMAND_PORT = 48899
HF_COMMAND = 'HF-A11ASSISTHREAD'.encode()
HF_COMMAND_OK = '+ok'.encode()

prepare_hex = lambda x: format(x, 'x').zfill(2)
socket.setdefaulttimeout(20)

def calc_sunlight() -> int:
    """
    Calculate an appropriate brightness for the bulb depending on
    current sunlight.
    :return: White brightness
    """
    a = Astral()
    a.solar_depression = 'civil'
    city = a[settings.LOCATION]
    sun = city.sun(date=datetime.now(), local=True)
    dt = datetime.utcnow().replace(tzinfo=pytz.UTC)
    white = 255
    if dt < sun['sunrise']:
        white = 255 - (sun['sunrise'] - dt).total_seconds() / 3600 * 200 / 6
    elif dt > sun['sunset']:
        white = 255 - (dt - sun['sunset']).total_seconds() / 3600 * 200 / 6
    return white

class Bulb:
    """
    A class representing a single MagicHome LED Bulb.
    """

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

    def auth(self) -> None:
        s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        s.sendto(HF_COMMAND, (self.host, HF_COMMAND_PORT))
        s.sendto(HF_COMMAND_OK, (self.host, HF_COMMAND_PORT))

    def change_color(self, red: int = 0, green: int = 0, blue: int = 0, white: int = 0, brightness: int = 255,
                     mode: str = '31', function: str = None, speed: str = '1f') -> None:
        """
        Provided RGB values and a brightness, change the color of the
        bulb with a TCP socket.
        """
        if mode not in SUPPORTED_MODES:
            raise NotImplementedError

        if function:
            if num(function) not in SUPPORTED_FUNCTIONS:
                raise NotImplementedError
            data = bytearray.fromhex(mode + function + speed + TAIL)
        else:
            red, green, blue, white, brightness = num(red, green, blue, white, brightness)
            red = num(red * brightness / 255)
            green = num(green * brightness / 255)
            blue = num(blue * brightness / 255)
            white = num(white * brightness / 255)
            color_hex = (prepare_hex(red) + prepare_hex(green) + prepare_hex(blue)
                         + prepare_hex(white))
            if white:
                color_mode = '0f'
            else:
                color_mode = 'f0'
            # Build packet
            data = bytearray.fromhex(mode + color_hex
                                     + color_mode + TAIL)
        try:
            # Compute checksum
            data.append(sum(data) % 256)
            sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            sock.connect((self.host, CONTROL_PORT))
            sock.send(data)
            sock.close()
        except Exception as e:
            print(e)

    def sunlight(self) -> None:
        while True:
            self.change_color(white=calc_sunlight())
            sleep(60)

    def fade(self, start: Dict = None, stop: Dict = None, bright: int = None, speed: int = 1) -> None:
        speed = abs(speed)
        if start:
            bright = bright or 255
            while bright > 0:
                self.change_color(**start, brightness=bright, mode='41')
                bright -= speed
        if stop:
            bright = bright or 0
            while bright < 255:
                self.change_color(**stop, brightness=bright, mode='41')
                bright += speed

    def fade_sunlight(self, speed: int = 1) -> None:
        self.fade(stop={'white': calc_sunlight()}, speed=speed)

if __name__ == '__main__':
    if len(sys.argv) < 4:
        sys.exit('Nope')
    colors = list(map(lambda x: int(x), sys.argv[2:]))
    print(colors)
    b = Bulb(sys.argv[1])
    b.change_color(*colors)
<commit_msg>That should never have been committed<commit_after>#!/usr/bin/env python3
"""
bulb.py
~~~~~~~

This module is for communicating with the MagicHome LED bulb over the network.

Wire protocol:

-------------------------------------
|header(1)|data(5-70)|0f|checksum(1)|
-------------------------------------

header:
    31 color & white
    41 camera
    51 custom
    61 function

color, white, camera (8 bytes):
    00-ff red
    00-ff green
    00-ff blue
    00-ff white
    mode:
        0f white
        f0 color

functions (5 bytes):
    25-38 modes
    1f-01 speed (decreasing)
    0f who knows

custom (70 bytes):
    64 bytes of r, g, b, 0 (empty color is 0x01020300)
    1f-01 speed (decreasing)
    3a,3b,3c gradual, jumping, strobe
    ff tail

tail:
    0f
    checksum (sum of data fields)
"""
import socket
import sys
from datetime import datetime
from time import sleep

import pytz
from astral import Astral
from typing import Dict

from home import settings
from home.core.utils import num

SUPPORTED_MODES = ['31', '41', '61']
SUPPORTED_FUNCTIONS = list(range(25, 39))
TAIL = '0f'

seven_color_cross_fade = 0x25
red_gradual_change = 0x26
green_gradual_change = 0x27
blue_gradual_change = 0x28
yellow_gradual_change = 0x29
cyan_gradual_change = 0x2a
purple_gradual_change = 0x2b
white_gradual_change = 0x2c
red_green_cross_fade = 0x2d
red_blue_cross_fade = 0x2e
green_blue_cross_fade = 0x2f
seven_color_strobe_flash = 0x30
red_strobe_flash = 0x31
green_strobe_flash = 0x32
blue_stobe_flash = 0x33
yellow_strobe_flash = 0x34
cyan_strobe_flash = 0x35
purple_strobe_flash = 0x36
white_strobe_flash = 0x37
seven_color_jumping = 0x38

CONTROL_PORT = 5577
# The HFLPB100's control/debug module
HF_COMMAND_PORT = 48899
HF_COMMAND = 'HF-A11ASSISTHREAD'.encode()
HF_COMMAND_OK = '+ok'.encode()

prepare_hex = lambda x: format(x, 'x').zfill(2)
socket.setdefaulttimeout(20)

def calc_sunlight() -> int:
    """
    Calculate an appropriate brightness for the bulb depending on
    current sunlight.
    :return: White brightness
    """
    a = Astral()
    a.solar_depression = 'civil'
    city = a[settings.LOCATION]
    sun = city.sun(date=datetime.now(), local=True)
    dt = datetime.utcnow().replace(tzinfo=pytz.UTC)
    white = 255
    if dt < sun['sunrise']:
        white = 255 - (sun['sunrise'] - dt).total_seconds() / 3600 * 200 / 6
    elif dt > sun['sunset']:
        white = 255 - (dt - sun['sunset']).total_seconds() / 3600 * 200 / 6
    return white

class Bulb:
    """
    A class representing a single MagicHome LED Bulb.
    """

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

    def auth(self) -> None:
        s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        s.sendto(HF_COMMAND, (self.host, HF_COMMAND_PORT))
        s.sendto(HF_COMMAND_OK, (self.host, HF_COMMAND_PORT))

    def change_color(self, red: int = 0, green: int = 0, blue: int = 0, white: int = 0, brightness: int = 255,
                     mode: str = '31', function: str = None, speed: str = '1f') -> None:
        """
        Provided RGB values and a brightness, change the color of the
        bulb with a TCP socket.
        """
        if mode not in SUPPORTED_MODES:
            raise NotImplementedError

        if function:
            if num(function) not in SUPPORTED_FUNCTIONS:
                raise NotImplementedError
            data = bytearray.fromhex(mode + function + speed + TAIL)
        else:
            red, green, blue, white, brightness = num(red, green, blue, white, brightness)
            red = num(red * brightness / 255)
            green = num(green * brightness / 255)
            blue = num(blue * brightness / 255)
            white = num(white * brightness / 255)
            color_hex = (prepare_hex(red) + prepare_hex(green) + prepare_hex(blue)
                         + prepare_hex(white))
            if white:
                color_mode = '0f'
            else:
                color_mode = 'f0'
            # Build packet
            data = bytearray.fromhex(mode + color_hex
                                     + color_mode + TAIL)
        try:
            # Compute checksum
            data.append(sum(data) % 256)
            sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            sock.connect((self.host, CONTROL_PORT))
            sock.send(data)
            sock.close()
        except Exception as e:
            print(e)

    def sunlight(self) -> None:
        self.change_color(white=calc_sunlight())

    def fade(self, start: Dict = None, stop: Dict = None, bright: int = None, speed: int = 1) -> None:
        speed = abs(speed)
        if start:
            bright = bright or 255
            while bright > 0:
                self.change_color(**start, brightness=bright, mode='41')
                bright -= speed
        if stop:
            bright = bright or 0
            while bright < 255:
                self.change_color(**stop, brightness=bright, mode='41')
                bright += speed

    def fade_sunlight(self, speed: int = 1) -> None:
        self.fade(stop={'white': calc_sunlight()}, speed=speed)

if __name__ == '__main__':
    if len(sys.argv) < 4:
        sys.exit('Nope')
    colors = list(map(lambda x: int(x), sys.argv[2:]))
    print(colors)
    b = Bulb(sys.argv[1])
    b.change_color(*colors)
<|endoftext|>


<commit_before>#!/usr/bin/env python
# Created by Camio.com - Copyright 2017
# License MIT

from __future__ import print_function
from bottle import route, run, request, response, default_app
import pymongo
import base64
import json
import os
import StringIO
import requests
import time
import logging
import traceback
try:
    from PIL import Image
except ImportError:
    import Image

API_KEY = '123456789'

connection = pymongo.MongoClient()
db = connection['mydb']
tasks = db['tasks']

# a basic URL route to test whether Bottle is responding properly
@route('/')
def index():
    return "it works!"

@route('/tasks/<secret>',method='POST')
def post_task(secret):
    body = request.body.read()
    logging.info('payload size %s' % len(body))
    if secret != API_KEY:
        response.status = 400
        return "Invalid API Key"
    if body:
        payload = json.loads(body.decode('utf8'))
        tasks.insert({'request': payload, 'status':'pending'})
        logging.info('done')
        images = payload.get('images')
    return 'ok'

@route('/tasks/<secret>',method='GET')
def get_tasks(secret):
    if secret != API_KEY:
        response.status = 400
        return "Invalid API Key"
    all_tasks = tasks.find({'status':'pending'})
    return repr([task['request']['user_id']+'/'+task['request']['camera'] for task in all_tasks])

###########################################################################
# This is the function that you modify to perform your particular labeling.
# The payload images is a list
# [
#   {
#      type: "image/jpeg",
#      size: [640, 480],
#      timestamp: "2017-05-05T01:31:13.738647",
#      image_b64: "... base 64 binary data ..."
#   },
#   ...
# ]
#
# The custom code in compute_labels should loop and label each one of them and
# return a dictionary of the form
#
# {
# "labels: {
#   "2017-01-01T12:00:00.000": {
#      "cat": {"probability: 0.93, "polygon": []},
#      "dog": {"probability: 0.88, "polygon": []},
#   }
#  }
# }
#
# i.e. a dictionary of labels for each image timestamp
# each label is a dictionary key associated to a
# probability and an optional polygon (as list of x,y
# coordinates expressed in % of the original image
# with (0,0) being the bottom-left corner and (1,1)
# the top-right corner,
#
###########################################################################
def compute_labels(images):
    labels = {}
    for image in images:
        image_type = image['type'] # example 'image/jpeg'
        image_size = image['size'] # (width, height)
        image_timestamp = image['timestamp'] # in iso format string
        image_bytes = base64.b64decode(image['image_b64']) # the bytes
        image = Image.open(StringIO.StringIO(image_bytes)) # a PIL image
        labels[image_timestamp] = {
            "cat":{"probability":0.93, "polygon":[]},
            "dog":{"probability":0.88, "polygon":[]},
            }
    return labels

def runtasks():
    t = 0
    while True:
        task = tasks.find_one({'status':'pending'})
        if task:
            t = 0
            print('processing task')
            request = task['request']
            try:
                images = request['images']
                callback_url = request['callback_url']
                labels = compute_labels(images)
                payload = {'status':'success', 'labels':labels}
                print('    posting payload')
                requests.post(callback_url, json=payload)
                print('    done!')
                task['status'] = 'completed'
            except:
                task['status'] = 'error'
                task['traceback'] = traceback.format_exc()
            tasks.update({'_id':task['_id']}, task)
        else:
            print('... %i ...' % t)
            t += 10
            time.sleep(10)

# these two lines are only used for python app.py
if __name__ == '__main__':
    runtasks()

# this is the hook for Gunicorn to run Bottle
app = default_app()
<commit_msg>Flush stdout/err in loop to populate log file in real time<commit_after>#!/usr/bin/env python
# Created by Camio.com - Copyright 2017
# License MIT

from __future__ import print_function
from bottle import route, run, request, response, default_app
import pymongo
import sys
import base64
import json
import os
import StringIO
import requests
import time
import logging
import traceback
try:
    from PIL import Image
except ImportError:
    import Image

API_KEY = '123456789'

connection = pymongo.MongoClient()
db = connection['mydb']
tasks = db['tasks']

# a basic URL route to test whether Bottle is responding properly
@route('/')
def index():
    return "it works!"

@route('/tasks/<secret>',method='POST')
def post_task(secret):
    body = request.body.read()
    logging.info('payload size %s' % len(body))
    if secret != API_KEY:
        response.status = 400
        return "Invalid API Key"
    if body:
        payload = json.loads(body.decode('utf8'))
        tasks.insert({'request': payload, 'status':'pending'})
        logging.info('done')
        images = payload.get('images')
    return 'ok'

@route('/tasks/<secret>',method='GET')
def get_tasks(secret):
    if secret != API_KEY:
        response.status = 400
        return "Invalid API Key"
    all_tasks = tasks.find({'status':'pending'})
    return repr([task['request']['user_id']+'/'+task['request']['camera'] for task in all_tasks])

###########################################################################
# This is the function that you modify to perform your particular labeling.
# The payload images is a list
# [
#   {
#      type: "image/jpeg",
#      size: [640, 480],
#      timestamp: "2017-05-05T01:31:13.738647",
#      image_b64: "... base 64 binary data ..."
#   },
#   ...
# ]
#
# The custom code in compute_labels should loop and label each one of them and
# return a dictionary of the form
#
# {
# "labels: {
#   "2017-01-01T12:00:00.000": {
#      "cat": {"probability: 0.93, "polygon": []},
#      "dog": {"probability: 0.88, "polygon": []},
#   }
#  }
# }
#
# i.e. a dictionary of labels for each image timestamp
# each label is a dictionary key associated to a
# probability and an optional polygon (as list of x,y
# coordinates expressed in % of the original image
# with (0,0) being the bottom-left corner and (1,1)
# the top-right corner,
#
###########################################################################
def compute_labels(images):
    labels = {}
    for image in images:
        image_type = image['type'] # example 'image/jpeg'
        image_size = image['size'] # (width, height)
        image_timestamp = image['timestamp'] # in iso format string
        image_bytes = base64.b64decode(image['image_b64']) # the bytes
        image = Image.open(StringIO.StringIO(image_bytes)) # a PIL image
        labels[image_timestamp] = {
            "cat":{"probability":0.93, "polygon":[]},
            "dog":{"probability":0.88, "polygon":[]},
            }
    return labels

def runtasks():
    t = 0
    while True:
        task = tasks.find_one({'status':'pending'})
        sys.stdout.flush()
        sys.stderr.flush()
        if task:
            t = 0
            print('processing task')
            request = task['request']
            try:
                images = request['images']
                callback_url = request['callback_url']
                labels = compute_labels(images)
                payload = {'status':'success', 'labels':labels}
                print('    posting payload')
                requests.post(callback_url, json=payload)
                print('    done!')
                task['status'] = 'completed'
            except:
                task['status'] = 'error'
                task['traceback'] = traceback.format_exc()
            tasks.update({'_id':task['_id']}, task)
        else:
            print('... %i ...' % t)
            t += 10
            time.sleep(10)

# these two lines are only used for python app.py
if __name__ == '__main__':
    runtasks()

# this is the hook for Gunicorn to run Bottle
app = default_app()
<|endoftext|>