<commit_before>__author__ = 'calvin'
from functools import partial
import weakref
import copy
import collections

from_meter_conversions = {'km': 1 / 1000., 'm': 1, 'cm': 100., 'mm': 1000.,
                          'ft': 3.28084, 'yards': 1.09361, 'miles': 0.000621371, 'inches': 39.3701}
ConversionFactors = {}

for v, v_per_meter in from_meter_conversions.iteritems():
    # For each entry, add the conversion to and from meters
    fmt1 = "m_to_{}".format(v)
    inv1 = "{}_to_m".format(v)
    ConversionFactors[fmt1] = v_per_meter
    ConversionFactors[inv1] = 1. / v_per_meter

    for q, q_per_meter in from_meter_conversions.items():
        # for each entry, add the conversion to and from other entries
        v_per_q = v_per_meter / q_per_meter
        fmt2 = "{}_to_{}".format(q, v)
        inv2 = "{}_to_{}".format(v, q)
        ConversionFactors[fmt2] = v_per_q
        ConversionFactors[inv2] = 1. / v_per_q

class BaseProperty(object):
    "Emulate PyProperty_Type() in Objects/descrobject.c"
    all_properties = weakref.WeakKeyDictionary()

    def __init__(self, default_value, fdel=None, doc=None):
        self.fdel = fdel
        self.default_value = default_value
        self.value = copy.deepcopy(default_value)
        if doc is None:
            doc = self.fget.__doc__
        self.__doc__ = doc

    def fget(self, obj):
        return self.instances[obj]['value']

    def fset(self, obj, value):
        self.instances[obj]['value'] = value

    def __get__(self, obj, objtype=None):
        return self.instances[obj]['value']

    def __set__(self, obj, value):
        prev_value = self.instances[obj]['value']
        if value != prev_value:
            self.instances[obj]['value'] = value
            obj.dispatch(self.name, obj, value)

    def __delete__(self, obj):
        if self.fdel is None:
            raise AttributeError("can't delete attribute")
        self.fdel(obj)

    def getter(self, fget):
        return type(self)(fget, self.fset, self.fdel, self.__doc__)

    def setter(self, fset):
        return type(self)(self.fget, fset, self.fdel, self.__doc__)

    def deleter(self, fdel):
        return type(self)(self.fget, self.fset, fdel, self.__doc__)

    def register(self, instance, property_name, default_value, **kwargs):
        # Keep a reference to the property as a class attribute so that we can get the property by calling
        # BaseProperty.get_property(instance, name)
        # all_properties keeps track of the properties of an EventDispatcher by it's property names.
        if instance in self.all_properties:
            self.all_properties[instance].update({property_name: self})
        else:
            self.all_properties[instance] = {property_name: self}

        info = {'value': self.value, 'name': property_name, 'callbacks': []}
        info.update(kwargs)
        try:
            self.instances[instance] = info
        except AttributeError:
            # Create the instances dictionary at registration so that each class has it's own instance of it.
            self.instances = weakref.WeakKeyDictionary()
            self.instances[instance] = info

    @staticmethod
    def get_property(instance, property_name):
        prop = BaseProperty.all_properties[instance][property_name]
        return prop

class Property(BaseProperty):

    def __init__(self, default_value):
        super(Property, self).__init__(default_value, None, doc=None)
        self.default_value = default_value

class ObservableDict(object):

    def __init__(self, dictionary, dispatch_method, **kwargs):
        self.dictionary = dictionary.copy()
        self.dispatch = dispatch_method
        self._property = property

    def __get__(self, instance, owner):
        return self.dictionary

    def __getitem__(self, item):
        return self.dictionary[item]

    def __setitem__(self, key, value):
        try:
            prev = self.dictionary[key]
            check = prev != value
        except KeyError:
            check = True
        self.dictionary[key] = value
        if check:
            self.dispatch(self.dictionary)

    def copy(self):
        return self.__class__(self.dictionary, self.dispatch)

    def update(self, E=None, **F):
        self.dictionary.update(E, **F)
        self.dispatch(self.dictionary)

    def keys(self):
        return self.dictionary.keys()

    def values(self):
        return self.dictionary.values()

    def items(self):
        return self.dictionary.items()

    def iteritems(self):
        return self.dictionary.iteritems()

class DictProperty(BaseProperty):

    def __init__(self, default_value, **kwargs):
        super(DictProperty, self).__init__(default_value, **kwargs)

        if isinstance(default_value, dict):
            pass
            # self.default_value = ObservableDict(default_value, self)
        else:
            raise ValueError('DictProperty takes dict only.')

    def register(self, instance, property_name, value, **kwargs):
        self.value = ObservableDict(value,
                                    dispatch_method=partial(instance.dispatch, property_name, instance))
        super(DictProperty, self).register(instance, property_name, weakref.ref(self.value), **kwargs)

    def __set__(self, obj, value):
        cb = self.instances[obj]['callbacks'][:]
        self.register(obj, self.name, value)
        self.instances[obj]['callbacks'] = cb
        obj.dispatch(self.name, obj, value)

class UnitProperty(BaseProperty):
    unit_properties = weakref.WeakKeyDictionary()

    def __init__(self, default_value, units, fdel=None, doc=None):
        self.units = units
        super(UnitProperty, self).__init__(default_value)

    @staticmethod
    def convert_all(units):
        """
        Iterate through all instances of UnitProperty, performing conversions
        :param units:
        """
        for unitproperty, instance in UnitProperty.unit_properties.iteritems():
            if unitproperty.units == units:
                continue
            c = ConversionFactors["{}_to_{}".format(unitproperty.units, units)]
            setattr(instance, unitproperty.name, c * unitproperty.instances[instance]['value'])
            unitproperty.units = units

    def convert_to(self, units):
        if self.units == units:
            return
        c = ConversionFactors["{}_to_{}".format(self.units, units)]
        for instance in self.instances:
            setattr(instance, self.name, c * self.instances[instance]['value'])
            self.units = units

    def register(self, instance, property_name, default_value, **kwargs):
        kwargs['units'] = self.units
        super(UnitProperty, self).register(instance, property_name, default_value, **kwargs)
        # Keep track of all the UnitProperties so that we can change them all when the unit system changes
        self.unit_properties[self] = instance

class ObservableList(collections.MutableSequence):

    def __init__(self, l, dispatch_method):
        if not type(l) == list and not type(l) == tuple and not isinstance(l, ObservableList):
            raise ValueError('Observable list must only be initialized with lists as arguments')
        self._list = l[:]
        self.dispatch = dispatch_method

    def __get__(self, instance, owner):
        return self._list

    def __getitem__(self, item):
        return self._list[item]

    def __setitem__(self, key, value):
        if self._list[key] != value:
            self._list[key] = value
            self.dispatch(self._list)

    def __reversed__(self):
        return reversed(self._list)

    def __delitem__(self, key):
        del self._list[key]
        self.dispatch(self._list)

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

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

    def insert(self, index, value):
        self._list.insert(index, value)
        self.dispatch(self._list)

    def append(self, value):
        self._list.append(value)
        self.dispatch(self._list)

    def extend(self, values):
        self._list.extend(values)
        self.dispatch(self._list)

    def pop(self, index=-1):
        value = self._list.pop(index)
        self.dispatch(self._list)
        return value

    def __eq__(self, other):
        return self._list == other

    def __ne__(self, other):
        return self._list != other

class ListProperty(BaseProperty):

    def register(self, instance, property_name, value, **kwargs):
        self.value = ObservableList(value, dispatch_method=partial(instance.dispatch, property_name, instance))
        super(ListProperty, self).register(instance, property_name, self.value, **kwargs)

    def __set__(self, obj, value):
        cb = self.instances[obj]['callbacks'][:]
        self.register(obj, self.name, value)
        self.instances[obj]['callbacks'] = cb
        obj.dispatch(self.name, obj, self.value._list)
<commit_msg>fixes issue with tuples not being converted to list in ObservableList<commit_after>__author__ = 'calvin'
from functools import partial
import weakref
import copy
import collections

from_meter_conversions = {'km': 1 / 1000., 'm': 1, 'cm': 100., 'mm': 1000.,
                          'ft': 3.28084, 'yards': 1.09361, 'miles': 0.000621371, 'inches': 39.3701}
ConversionFactors = {}

for v, v_per_meter in from_meter_conversions.iteritems():
    # For each entry, add the conversion to and from meters
    fmt1 = "m_to_{}".format(v)
    inv1 = "{}_to_m".format(v)
    ConversionFactors[fmt1] = v_per_meter
    ConversionFactors[inv1] = 1. / v_per_meter

    for q, q_per_meter in from_meter_conversions.items():
        # for each entry, add the conversion to and from other entries
        v_per_q = v_per_meter / q_per_meter
        fmt2 = "{}_to_{}".format(q, v)
        inv2 = "{}_to_{}".format(v, q)
        ConversionFactors[fmt2] = v_per_q
        ConversionFactors[inv2] = 1. / v_per_q

class BaseProperty(object):
    "Emulate PyProperty_Type() in Objects/descrobject.c"
    all_properties = weakref.WeakKeyDictionary()

    def __init__(self, default_value, fdel=None, doc=None):
        self.fdel = fdel
        self.default_value = default_value
        self.value = copy.deepcopy(default_value)
        if doc is None:
            doc = self.fget.__doc__
        self.__doc__ = doc

    def fget(self, obj):
        return self.instances[obj]['value']

    def fset(self, obj, value):
        self.instances[obj]['value'] = value

    def __get__(self, obj, objtype=None):
        return self.instances[obj]['value']

    def __set__(self, obj, value):
        prev_value = self.instances[obj]['value']
        if value != prev_value:
            self.instances[obj]['value'] = value
            obj.dispatch(self.name, obj, value)

    def __delete__(self, obj):
        if self.fdel is None:
            raise AttributeError("can't delete attribute")
        self.fdel(obj)

    def getter(self, fget):
        return type(self)(fget, self.fset, self.fdel, self.__doc__)

    def setter(self, fset):
        return type(self)(self.fget, fset, self.fdel, self.__doc__)

    def deleter(self, fdel):
        return type(self)(self.fget, self.fset, fdel, self.__doc__)

    def register(self, instance, property_name, default_value, **kwargs):
        # Keep a reference to the property as a class attribute so that we can get the property by calling
        # BaseProperty.get_property(instance, name)
        # all_properties keeps track of the properties of an EventDispatcher by it's property names.
        if instance in self.all_properties:
            self.all_properties[instance].update({property_name: self})
        else:
            self.all_properties[instance] = {property_name: self}

        info = {'value': self.value, 'name': property_name, 'callbacks': []}
        info.update(kwargs)
        try:
            self.instances[instance] = info
        except AttributeError:
            # Create the instances dictionary at registration so that each class has it's own instance of it.
            self.instances = weakref.WeakKeyDictionary()
            self.instances[instance] = info

    @staticmethod
    def get_property(instance, property_name):
        prop = BaseProperty.all_properties[instance][property_name]
        return prop

class Property(BaseProperty):

    def __init__(self, default_value):
        super(Property, self).__init__(default_value, None, doc=None)
        self.default_value = default_value

class ObservableDict(object):

    def __init__(self, dictionary, dispatch_method, **kwargs):
        self.dictionary = dictionary.copy()
        self.dispatch = dispatch_method
        self._property = property

    def __get__(self, instance, owner):
        return self.dictionary

    def __getitem__(self, item):
        return self.dictionary[item]

    def __setitem__(self, key, value):
        try:
            prev = self.dictionary[key]
            check = prev != value
        except KeyError:
            check = True
        self.dictionary[key] = value
        if check:
            self.dispatch(self.dictionary)

    def copy(self):
        return self.__class__(self.dictionary, self.dispatch)

    def update(self, E=None, **F):
        self.dictionary.update(E, **F)
        self.dispatch(self.dictionary)

    def keys(self):
        return self.dictionary.keys()

    def values(self):
        return self.dictionary.values()

    def items(self):
        return self.dictionary.items()

    def iteritems(self):
        return self.dictionary.iteritems()

class DictProperty(BaseProperty):

    def __init__(self, default_value, **kwargs):
        super(DictProperty, self).__init__(default_value, **kwargs)

        if isinstance(default_value, dict):
            pass
            # self.default_value = ObservableDict(default_value, self)
        else:
            raise ValueError('DictProperty takes dict only.')

    def register(self, instance, property_name, value, **kwargs):
        self.value = ObservableDict(value,
                                    dispatch_method=partial(instance.dispatch, property_name, instance))
        super(DictProperty, self).register(instance, property_name, weakref.ref(self.value), **kwargs)

    def __set__(self, obj, value):
        cb = self.instances[obj]['callbacks'][:]
        self.register(obj, self.name, value)
        self.instances[obj]['callbacks'] = cb
        obj.dispatch(self.name, obj, value)

class UnitProperty(BaseProperty):
    unit_properties = weakref.WeakKeyDictionary()

    def __init__(self, default_value, units, fdel=None, doc=None):
        self.units = units
        super(UnitProperty, self).__init__(default_value)

    @staticmethod
    def convert_all(units):
        """
        Iterate through all instances of UnitProperty, performing conversions
        :param units:
        """
        for unitproperty, instance in UnitProperty.unit_properties.iteritems():
            if unitproperty.units == units:
                continue
            c = ConversionFactors["{}_to_{}".format(unitproperty.units, units)]
            setattr(instance, unitproperty.name, c * unitproperty.instances[instance]['value'])
            unitproperty.units = units

    def convert_to(self, units):
        if self.units == units:
            return
        c = ConversionFactors["{}_to_{}".format(self.units, units)]
        for instance in self.instances:
            setattr(instance, self.name, c * self.instances[instance]['value'])
            self.units = units

    def register(self, instance, property_name, default_value, **kwargs):
        kwargs['units'] = self.units
        super(UnitProperty, self).register(instance, property_name, default_value, **kwargs)
        # Keep track of all the UnitProperties so that we can change them all when the unit system changes
        self.unit_properties[self] = instance

class ObservableList(collections.MutableSequence):

    def __init__(self, l, dispatch_method):
        if not type(l) == list and not type(l) == tuple and not isinstance(l, ObservableList):
            raise ValueError('Observable list must only be initialized with lists as arguments')
        self._list = list(l[:])
        self.dispatch = dispatch_method

    def __get__(self, instance, owner):
        return self._list

    def __getitem__(self, item):
        return self._list[item]

    def __setitem__(self, key, value):
        if self._list[key] != value:
            self._list[key] = value
            self.dispatch(self._list)

    def __reversed__(self):
        return reversed(self._list)

    def __delitem__(self, key):
        del self._list[key]
        self.dispatch(self._list)

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

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

    def insert(self, index, value):
        self._list.insert(index, value)
        self.dispatch(self._list)

    def append(self, value):
        self._list.append(value)
        self.dispatch(self._list)

    def extend(self, values):
        self._list.extend(values)
        self.dispatch(self._list)

    def pop(self, index=-1):
        value = self._list.pop(index)
        self.dispatch(self._list)
        return value

    def __eq__(self, other):
        return self._list == other

    def __ne__(self, other):
        return self._list != other

class ListProperty(BaseProperty):

    def register(self, instance, property_name, value, **kwargs):
        self.value = ObservableList(value, dispatch_method=partial(instance.dispatch, property_name, instance))
        super(ListProperty, self).register(instance, property_name, self.value, **kwargs)

    def __set__(self, obj, value):
        cb = self.instances[obj]['callbacks'][:]
        self.register(obj, self.name, value)
        self.instances[obj]['callbacks'] = cb
        obj.dispatch(self.name, obj, self.value._list)
<|endoftext|>


<commit_before>"""Tests for polymodel.py.

See issue 35.  http://goo.gl/iHkCm
"""

import pickle
import unittest

from .google_imports import namespace_manager
from .google_imports import datastore_types

from . import polymodel
from . import model
from . import query
from . import test_utils

PolyModel = polymodel.PolyModel

class PolyModelTests(test_utils.NDBTest):

  def setUp(self):
    super(PolyModelTests, self).setUp()

  the_module = polymodel

  def testBasics(self):
    # Test basic PolyModel functionality.
    class Shoe(PolyModel):
      color = model.StringProperty()
    class Moccasin(Shoe):
      leather = model.StringProperty()
    class Sneaker(Shoe):
      pump = model.BooleanProperty()

    self.assertEqual(Shoe._class_name(), 'Shoe')
    self.assertEqual(Shoe._class_key(), ['Shoe'])
    self.assertEqual(Moccasin._class_name(), 'Moccasin')
    self.assertEqual(Moccasin._class_key(), ['Shoe', 'Moccasin'])
    self.assertEqual(Sneaker._class_name(), 'Sneaker')
    self.assertEqual(Sneaker._class_key(), ['Shoe', 'Sneaker'])

    s_key = model.Key('Shoe', 1)
    self.assertEqual(Shoe().put(), s_key)
    s = s_key.get()
    self.assertEqual(s._get_kind(), 'Shoe')
    self.assertEqual(s._class_key(), ['Shoe'])
    self.assertEqual(s.class_, ['Shoe'])

    m_key = model.Key('Shoe', 2)
    self.assertEqual(Moccasin(color='brown', leather='cattlehide').put(),
                     m_key)
    m = m_key.get()
    self.assertEqual(m._get_kind(), 'Shoe')
    self.assertEqual(m.class_, ['Shoe', 'Moccasin'])

    snkr_key = model.Key('Shoe', 3)
    self.assertEqual(Sneaker(color='red', pump=False).put(), snkr_key)
    snkr = snkr_key.get()
    self.assertEqual(snkr._get_kind(), 'Shoe')
    self.assertEqual(snkr.class_, ['Shoe', 'Sneaker'])

    self.assertEqual(Shoe.query().fetch(), [s, m, snkr])
    self.assertEqual(Shoe.query(Sneaker.pump == False).fetch(), [snkr])
    self.assertEqual(Moccasin.query().fetch(), [m])
    self.assertEqual(Sneaker.query().fetch(), [snkr])

  def testBlobKeyProperty(self):
    class MyModel(PolyModel):
      pass
    class MyDerivedModel(MyModel):
      image = model.BlobKeyProperty()

    test_blobkey = datastore_types.BlobKey('testkey123')
    m = MyDerivedModel()
    m.image = test_blobkey
    m.put()

    m = m.key.get()
    m.image = test_blobkey
    m.put()

    self.assertTrue(isinstance(m.image, datastore_types.BlobKey))
    self.assertEqual(str(m.image), str(test_blobkey))

  def testClassKeyProperty(self):
    # Tests for the class_ property.
    class Animal(PolyModel):
      pass
    class Dog(Animal):
      pass
    fido = Dog()
    self.assertEqual(fido.class_, ['Animal', 'Dog'])
    self.assertRaises(TypeError, setattr, fido, 'class_', ['Animal', 'Dog'])

  def testPolyExpando(self):
    # Test that PolyModel can be combined with Expando.
    # (See also testExpandoPoly, and the Ghoul class in testInheritance.)
    class Animal(PolyModel, model.Expando):
      pass
    class Mammal(Animal):
      pass
    cat = Mammal(name='Tom', naps=18, sound='purr')
    cat1 = cat.put().get()
    self.assertFalse(cat1 is cat)
    self.assertEqual(cat1, cat)
    self.assertEqual(cat1.name, 'Tom')
    self.assertEqual(cat1.naps, 18)
    self.assertEqual(cat1.sound, 'purr')

  def testExpandoPoly(self):
    # Like testPolyExpando, but switch the order of the base classes.
    # It should work either way.
    class Animal(model.Expando, PolyModel):
      pass
    class Mammal(Animal):
      pass
    cat = Mammal(name='Tom', naps=18, sound='purr')
    cat1 = cat.put().get()
    self.assertFalse(cat1 is cat)
    self.assertEqual(cat1, cat)
    self.assertEqual(cat1.name, 'Tom')
    self.assertEqual(cat1.naps, 18)
    self.assertEqual(cat1.sound, 'purr')

  def testInheritance(self):
    # Tests focused on the inheritance model, including diamond inheritance.
    class NamedThing(model.Model):
      name = model.StringProperty()
    class Animal(PolyModel, NamedThing):
      legs = model.IntegerProperty(default=4)
    class Canine(Animal):
      pass
    class Dog(Canine):
      breed = model.StringProperty(default='mutt')
    class Wolf(Canine):
      mythical = model.BooleanProperty(default=False)
    class Feline(Animal):
      sound = model.StringProperty()
    class Cat(Feline):
      naps = model.IntegerProperty()
    class Panther(Feline):
      pass
    class Monster(Dog, Cat):
      ancestry = model.StringProperty()
    class Ghoul(Monster, model.Expando):
      pass

    k9 = Canine(name='Reynard')
    self.assertEqual(k9.legs, 4)
    self.assertEqual(k9._get_kind(), 'Animal')
    self.assertEqual(k9._class_name(), 'Canine')
    self.assertEqual(k9._class_key(), ['Animal', 'Canine'])

    tom = Cat(name='Tom', naps=12, sound='purr')
    self.assertTrue(isinstance(tom, Cat))
    self.assertTrue(isinstance(tom, Feline))
    self.assertTrue(isinstance(tom, Animal))
    self.assertTrue(isinstance(tom, PolyModel))
    self.assertEqual(tom.naps, 12)
    self.assertEqual(tom.sound, 'purr')
    self.assertEqual(tom.legs, 4)
    self.assertEqual(tom._get_kind(), 'Animal')
    self.assertEqual(tom._class_name(), 'Cat')
    self.assertEqual(tom._class_key(), ['Animal', 'Feline', 'Cat'])

    fido = Wolf(name='Warg')
    self.assertEqual(fido._get_kind(), 'Animal')
    self.assertEqual(fido._class_name(), 'Wolf')
    self.assertEqual(fido._class_key(), ['Animal', 'Canine', 'Wolf'])
    self.assertRaises(AttributeError, lambda: fido.breed)

    scary = Ghoul(name='Westminster', book='The Graveyard Book')
    self.assertEqual(scary.ancestry, None)
    self.assertEqual(scary._get_kind(), 'Animal')
    self.assertEqual(scary._class_name(), 'Ghoul')
    self.assertEqual(scary._class_key(), ['Animal',
                                         'Feline', 'Cat',
                                         'Canine', 'Dog',
                                         'Monster', 'Ghoul'])

    k91 = k9.put().get()
    self.assertTrue(isinstance(k9, Canine))
    self.assertEqual(k9.name, 'Reynard')
    self.assertEqual(k9._get_kind(), 'Animal')
    self.assertEqual(k9._class_name(), 'Canine')
    self.assertEqual(k9._class_key(), ['Animal', 'Canine'])
    self.assertTrue(isinstance(k91, Canine))
    self.assertEqual(k91.name, 'Reynard')
    self.assertEqual(k91._get_kind(), 'Animal')
    self.assertEqual(k91._class_name(), 'Canine')
    self.assertEqual(k91._class_key(), ['Animal', 'Canine'])
    self.assertEqual(k91, k9)

    tom1 = tom.put().get()
    self.assertEqual(tom1, tom)
    fido1 = fido.put().get()
    self.assertEqual(fido1, fido)
    scary1 = scary.put().get()
    self.assertEqual(scary1, scary)
    self.assertEqual(scary1.book, 'The Graveyard Book')

  def testPickling(self):
    # Test that PolyModel instances are pickled and unpickled properly.
    global Animal, Dog
    class Animal(PolyModel):
      name = model.StringProperty()
    class Dog(Animal):
      breed = model.StringProperty()
    for proto in 0, 1, 2:
      fido = Dog(name='Fido', breed='chihuahua')
      s = pickle.dumps(fido, proto)
      fido1 = pickle.loads(s)
      self.assertEqual(fido1.name, 'Fido')
      self.assertEqual(fido1.breed, 'chihuahua')
      self.assertEqual(fido1.class_, ['Animal', 'Dog'])
      self.assertEqual(fido, fido1)

  def testClassNameOverride(self):
    # Test that overriding _class_name() works.
    class Animal(PolyModel):
      pass
    class Feline(Animal):
      pass
    class Cat(Feline):
      @classmethod
      def _class_name(cls):
        return 'Pussycat'
    tom = Cat()
    self.assertEqual(tom.class_, ['Animal', 'Feline', 'Pussycat'])
    tom.put()
    self.assertEqual(Cat.query().fetch(), [tom])

  def testEdgeCases(self):
    # Test some edge cases.
    self.assertEqual(PolyModel._get_kind(), 'PolyModel')

  def testMixins(self):
    class Mixin(object):
      pass
    class Entity(polymodel.PolyModel):
      pass
    class ChildEntity(Entity):
      pass
    class RightMixinEntity(Entity, Mixin):
      pass
    class LeftMixinEntity(Mixin, Entity):
      pass
    self.assertEqual(Entity._get_kind(), 'Entity')
    self.assertEqual(ChildEntity._get_kind(), 'Entity')
    self.assertEqual(RightMixinEntity._get_kind(), 'Entity')
    self.assertEqual(LeftMixinEntity._get_kind(), 'Entity')

  def testGql(self):
    # See issue 199.
    class A(polymodel.PolyModel): pass
    class B(A): pass
    class C(A): pass
    B().put()
    C().put()
    self.assertEqual(query.gql('SELECT * FROM A').count(), 2)
    self.assertEqual(B.gql('').count(), 1)
    self.assertEqual(query.gql('SELECT * FROM B').count(), 1)

TOM_PB = """\
key <
  app: "_"
  path <
    Element {
      type: "Animal"
      id: 0
    }
  >
>
entity_group <
>
property <
  name: "class"
  value <
    stringValue: "Animal"
  >
  multiple: true
>
property <
  name: "class"
  value <
    stringValue: "Feline"
  >
  multiple: true
>
property <
  name: "class"
  value <
    stringValue: "Cat"
  >
  multiple: true
>
property <
  name: "name"
  value <
    stringValue: "Tom"
  >
  multiple: false
>
property <
  name: "purr"
  value <
    stringValue: "loud"
  >
  multiple: false
>
property <
  name: "whiskers"
  value <
    booleanValue: true
  >
  multiple: false
>
"""

class CompatibilityTests(test_utils.NDBTest):

  def testCompatibility(self):
    class Animal(PolyModel):
      name = model.StringProperty()
    class Feline(Animal):
      whiskers = model.BooleanProperty()
    class Cat(Feline):
      purr = model.StringProperty()
    tom = Cat(name='Tom', purr='loud', whiskers=True)
    tom._prepare_for_put()
    self.assertEqual(str(tom._to_pb()), TOM_PB)

def main():
  unittest.main()

if __name__ == '__main__':
  main()
<commit_msg>Tighten polymodel/gql test.<commit_after>"""Tests for polymodel.py.

See issue 35.  http://goo.gl/iHkCm
"""

import pickle
import unittest

from .google_imports import namespace_manager
from .google_imports import datastore_types

from . import polymodel
from . import model
from . import query
from . import test_utils

PolyModel = polymodel.PolyModel

class PolyModelTests(test_utils.NDBTest):

  def setUp(self):
    super(PolyModelTests, self).setUp()

  the_module = polymodel

  def testBasics(self):
    # Test basic PolyModel functionality.
    class Shoe(PolyModel):
      color = model.StringProperty()
    class Moccasin(Shoe):
      leather = model.StringProperty()
    class Sneaker(Shoe):
      pump = model.BooleanProperty()

    self.assertEqual(Shoe._class_name(), 'Shoe')
    self.assertEqual(Shoe._class_key(), ['Shoe'])
    self.assertEqual(Moccasin._class_name(), 'Moccasin')
    self.assertEqual(Moccasin._class_key(), ['Shoe', 'Moccasin'])
    self.assertEqual(Sneaker._class_name(), 'Sneaker')
    self.assertEqual(Sneaker._class_key(), ['Shoe', 'Sneaker'])

    s_key = model.Key('Shoe', 1)
    self.assertEqual(Shoe().put(), s_key)
    s = s_key.get()
    self.assertEqual(s._get_kind(), 'Shoe')
    self.assertEqual(s._class_key(), ['Shoe'])
    self.assertEqual(s.class_, ['Shoe'])

    m_key = model.Key('Shoe', 2)
    self.assertEqual(Moccasin(color='brown', leather='cattlehide').put(),
                     m_key)
    m = m_key.get()
    self.assertEqual(m._get_kind(), 'Shoe')
    self.assertEqual(m.class_, ['Shoe', 'Moccasin'])

    snkr_key = model.Key('Shoe', 3)
    self.assertEqual(Sneaker(color='red', pump=False).put(), snkr_key)
    snkr = snkr_key.get()
    self.assertEqual(snkr._get_kind(), 'Shoe')
    self.assertEqual(snkr.class_, ['Shoe', 'Sneaker'])

    self.assertEqual(Shoe.query().fetch(), [s, m, snkr])
    self.assertEqual(Shoe.query(Sneaker.pump == False).fetch(), [snkr])
    self.assertEqual(Moccasin.query().fetch(), [m])
    self.assertEqual(Sneaker.query().fetch(), [snkr])

  def testBlobKeyProperty(self):
    class MyModel(PolyModel):
      pass
    class MyDerivedModel(MyModel):
      image = model.BlobKeyProperty()

    test_blobkey = datastore_types.BlobKey('testkey123')
    m = MyDerivedModel()
    m.image = test_blobkey
    m.put()

    m = m.key.get()
    m.image = test_blobkey
    m.put()

    self.assertTrue(isinstance(m.image, datastore_types.BlobKey))
    self.assertEqual(str(m.image), str(test_blobkey))

  def testClassKeyProperty(self):
    # Tests for the class_ property.
    class Animal(PolyModel):
      pass
    class Dog(Animal):
      pass
    fido = Dog()
    self.assertEqual(fido.class_, ['Animal', 'Dog'])
    self.assertRaises(TypeError, setattr, fido, 'class_', ['Animal', 'Dog'])

  def testPolyExpando(self):
    # Test that PolyModel can be combined with Expando.
    # (See also testExpandoPoly, and the Ghoul class in testInheritance.)
    class Animal(PolyModel, model.Expando):
      pass
    class Mammal(Animal):
      pass
    cat = Mammal(name='Tom', naps=18, sound='purr')
    cat1 = cat.put().get()
    self.assertFalse(cat1 is cat)
    self.assertEqual(cat1, cat)
    self.assertEqual(cat1.name, 'Tom')
    self.assertEqual(cat1.naps, 18)
    self.assertEqual(cat1.sound, 'purr')

  def testExpandoPoly(self):
    # Like testPolyExpando, but switch the order of the base classes.
    # It should work either way.
    class Animal(model.Expando, PolyModel):
      pass
    class Mammal(Animal):
      pass
    cat = Mammal(name='Tom', naps=18, sound='purr')
    cat1 = cat.put().get()
    self.assertFalse(cat1 is cat)
    self.assertEqual(cat1, cat)
    self.assertEqual(cat1.name, 'Tom')
    self.assertEqual(cat1.naps, 18)
    self.assertEqual(cat1.sound, 'purr')

  def testInheritance(self):
    # Tests focused on the inheritance model, including diamond inheritance.
    class NamedThing(model.Model):
      name = model.StringProperty()
    class Animal(PolyModel, NamedThing):
      legs = model.IntegerProperty(default=4)
    class Canine(Animal):
      pass
    class Dog(Canine):
      breed = model.StringProperty(default='mutt')
    class Wolf(Canine):
      mythical = model.BooleanProperty(default=False)
    class Feline(Animal):
      sound = model.StringProperty()
    class Cat(Feline):
      naps = model.IntegerProperty()
    class Panther(Feline):
      pass
    class Monster(Dog, Cat):
      ancestry = model.StringProperty()
    class Ghoul(Monster, model.Expando):
      pass

    k9 = Canine(name='Reynard')
    self.assertEqual(k9.legs, 4)
    self.assertEqual(k9._get_kind(), 'Animal')
    self.assertEqual(k9._class_name(), 'Canine')
    self.assertEqual(k9._class_key(), ['Animal', 'Canine'])

    tom = Cat(name='Tom', naps=12, sound='purr')
    self.assertTrue(isinstance(tom, Cat))
    self.assertTrue(isinstance(tom, Feline))
    self.assertTrue(isinstance(tom, Animal))
    self.assertTrue(isinstance(tom, PolyModel))
    self.assertEqual(tom.naps, 12)
    self.assertEqual(tom.sound, 'purr')
    self.assertEqual(tom.legs, 4)
    self.assertEqual(tom._get_kind(), 'Animal')
    self.assertEqual(tom._class_name(), 'Cat')
    self.assertEqual(tom._class_key(), ['Animal', 'Feline', 'Cat'])

    fido = Wolf(name='Warg')
    self.assertEqual(fido._get_kind(), 'Animal')
    self.assertEqual(fido._class_name(), 'Wolf')
    self.assertEqual(fido._class_key(), ['Animal', 'Canine', 'Wolf'])
    self.assertRaises(AttributeError, lambda: fido.breed)

    scary = Ghoul(name='Westminster', book='The Graveyard Book')
    self.assertEqual(scary.ancestry, None)
    self.assertEqual(scary._get_kind(), 'Animal')
    self.assertEqual(scary._class_name(), 'Ghoul')
    self.assertEqual(scary._class_key(), ['Animal',
                                         'Feline', 'Cat',
                                         'Canine', 'Dog',
                                         'Monster', 'Ghoul'])

    k91 = k9.put().get()
    self.assertTrue(isinstance(k9, Canine))
    self.assertEqual(k9.name, 'Reynard')
    self.assertEqual(k9._get_kind(), 'Animal')
    self.assertEqual(k9._class_name(), 'Canine')
    self.assertEqual(k9._class_key(), ['Animal', 'Canine'])
    self.assertTrue(isinstance(k91, Canine))
    self.assertEqual(k91.name, 'Reynard')
    self.assertEqual(k91._get_kind(), 'Animal')
    self.assertEqual(k91._class_name(), 'Canine')
    self.assertEqual(k91._class_key(), ['Animal', 'Canine'])
    self.assertEqual(k91, k9)

    tom1 = tom.put().get()
    self.assertEqual(tom1, tom)
    fido1 = fido.put().get()
    self.assertEqual(fido1, fido)
    scary1 = scary.put().get()
    self.assertEqual(scary1, scary)
    self.assertEqual(scary1.book, 'The Graveyard Book')

  def testPickling(self):
    # Test that PolyModel instances are pickled and unpickled properly.
    global Animal, Dog
    class Animal(PolyModel):
      name = model.StringProperty()
    class Dog(Animal):
      breed = model.StringProperty()
    for proto in 0, 1, 2:
      fido = Dog(name='Fido', breed='chihuahua')
      s = pickle.dumps(fido, proto)
      fido1 = pickle.loads(s)
      self.assertEqual(fido1.name, 'Fido')
      self.assertEqual(fido1.breed, 'chihuahua')
      self.assertEqual(fido1.class_, ['Animal', 'Dog'])
      self.assertEqual(fido, fido1)

  def testClassNameOverride(self):
    # Test that overriding _class_name() works.
    class Animal(PolyModel):
      pass
    class Feline(Animal):
      pass
    class Cat(Feline):
      @classmethod
      def _class_name(cls):
        return 'Pussycat'
    tom = Cat()
    self.assertEqual(tom.class_, ['Animal', 'Feline', 'Pussycat'])
    tom.put()
    self.assertEqual(Cat.query().fetch(), [tom])

  def testEdgeCases(self):
    # Test some edge cases.
    self.assertEqual(PolyModel._get_kind(), 'PolyModel')

  def testMixins(self):
    class Mixin(object):
      pass
    class Entity(polymodel.PolyModel):
      pass
    class ChildEntity(Entity):
      pass
    class RightMixinEntity(Entity, Mixin):
      pass
    class LeftMixinEntity(Mixin, Entity):
      pass
    self.assertEqual(Entity._get_kind(), 'Entity')
    self.assertEqual(ChildEntity._get_kind(), 'Entity')
    self.assertEqual(RightMixinEntity._get_kind(), 'Entity')
    self.assertEqual(LeftMixinEntity._get_kind(), 'Entity')

  def testGql(self):
    # See issue 199.
    class A(polymodel.PolyModel): pass
    class B(A): pass
    class C(A): pass
    b = B()
    b.put()
    c = C()
    c.put()
    self.assertEqual(query.gql('SELECT * FROM A').fetch(), [b, c])
    self.assertEqual(B.gql('').fetch(), [b])
    self.assertEqual(query.gql('SELECT * FROM B').fetch(), [b])

TOM_PB = """\
key <
  app: "_"
  path <
    Element {
      type: "Animal"
      id: 0
    }
  >
>
entity_group <
>
property <
  name: "class"
  value <
    stringValue: "Animal"
  >
  multiple: true
>
property <
  name: "class"
  value <
    stringValue: "Feline"
  >
  multiple: true
>
property <
  name: "class"
  value <
    stringValue: "Cat"
  >
  multiple: true
>
property <
  name: "name"
  value <
    stringValue: "Tom"
  >
  multiple: false
>
property <
  name: "purr"
  value <
    stringValue: "loud"
  >
  multiple: false
>
property <
  name: "whiskers"
  value <
    booleanValue: true
  >
  multiple: false
>
"""

class CompatibilityTests(test_utils.NDBTest):

  def testCompatibility(self):
    class Animal(PolyModel):
      name = model.StringProperty()
    class Feline(Animal):
      whiskers = model.BooleanProperty()
    class Cat(Feline):
      purr = model.StringProperty()
    tom = Cat(name='Tom', purr='loud', whiskers=True)
    tom._prepare_for_put()
    self.assertEqual(str(tom._to_pb()), TOM_PB)

def main():
  unittest.main()

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


<commit_before># This file is part of DmpBbo, a set of libraries and programs for the
# black-box optimization of dynamical movement primitives.
# Copyright (C) 2014 Freek Stulp, ENSTA-ParisTech
#
# DmpBbo is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 2 of the License, or
# (at your option) any later version.
#
# DmpBbo 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with DmpBbo.  If not, see <http://www.gnu.org/licenses/>.

## \file demoDmp.py
## \author Freek Stulp
## \brief  Visualizes results of demoDmp.cpp
##
## \ingroup Demos
## \ingroup Dmps

import numpy
import argparse
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import os, sys

lib_path = os.path.abspath('../../python')
sys.path.append(lib_path)
from functionapproximators.functionapproximators_plotting import *
from dmp.dmp_plotting import *

if __name__=='__main__':
    # Call the executable with the directory to which results should be written
    parser = argparse.ArgumentParser()
    parser.add_argument("directory", help="directory to read data from")
    args = parser.parse_args()

    directory = args.directory

    print("Plotting")

    fig = plt.figure(1)
    axs = [ fig.add_subplot(131), fig.add_subplot(132), fig.add_subplot(133) ]

    traj_demonstration = numpy.loadtxt(directory+"/traj_demonstration.txt")
    lines = plotTrajectory(traj_demonstration,axs)
    plt.setp(lines, linestyle='-',  linewidth=4, color=(0.8,0.8,0.8), label='demonstration')

    traj_reproduced = numpy.loadtxt(directory+"/traj_reproduced.txt")
    lines = plotTrajectory(traj_reproduced,axs)
    plt.setp(lines, linestyle='--', linewidth=2, color=(0.0,0.0,0.5), label='reproduced')

    n_dims = (traj_demonstration.shape[1]-1)//3 # -1 for time, /3 for x/xd/xdd

    fig = plt.figure(2,figsize=(n_dims*5,5))
    for i_dim in range(n_dims):
        ax = fig.add_subplot(1, n_dims, i_dim+1)
        plotFunctionApproximatorTrainingFromDirectory(directory+"dim"+str(i_dim),ax)

    #plt.legend()
    #fig.canvas.set_window_title('Comparison between demonstration and reproduced')

    # Read data
    #ts_xs_xds     = numpy.loadtxt(directory+'/reproduced_ts_xs_xds.txt')
    #forcing_terms = numpy.loadtxt(directory+'/reproduced_forcing_terms.txt')
    #fa_output     = numpy.loadtxt(directory+'/reproduced_fa_output.txt')

    #fig = plt.figure(2)
    #plotDmp(ts_xs_xds,fig,forcing_terms,fa_output)
    #fig.canvas.set_window_title('Analytical integration')

    #ts_xs_xds     = numpy.loadtxt(directory+'/reproduced_step_ts_xs_xds.txt')
    #fig = plt.figure(3)
    #plotDmp(ts_xs_xds,fig)
    #fig.canvas.set_window_title('Step-by-step integration')

    plt.show()
<commit_msg>Improved plotting<commit_after># This file is part of DmpBbo, a set of libraries and programs for the
# black-box optimization of dynamical movement primitives.
# Copyright (C) 2014 Freek Stulp, ENSTA-ParisTech
#
# DmpBbo is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 2 of the License, or
# (at your option) any later version.
#
# DmpBbo 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with DmpBbo.  If not, see <http://www.gnu.org/licenses/>.

## \file demoDmp.py
## \author Freek Stulp
## \brief  Visualizes results of demoDmp.cpp
##
## \ingroup Demos
## \ingroup Dmps

import numpy
import argparse
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import os, sys

lib_path = os.path.abspath('../../python')
sys.path.append(lib_path)
from functionapproximators.functionapproximators_plotting import *
from dmp.dmp_plotting import *

def legendWithoutDuplicates(ax):
    handles, labels = ax.get_legend_handles_labels()
    lgd = dict(zip(labels, handles))
    ax.legend(lgd.values(), lgd.keys())
#    plt.legend()

if __name__=='__main__':
    # Call the executable with the directory to which results should be written
    parser = argparse.ArgumentParser()
    parser.add_argument("directory", help="directory to read data from")
    args = parser.parse_args()

    directory = args.directory

    # Plot trajectories
    golden_ratio = 1.618 # graphs have nice proportions with this ratio
    n_subplots = 3
    fig3 = plt.figure(3,figsize=(golden_ratio*n_subplots*3,3))
    axs = [ fig3.add_subplot(1,n_subplots,ii+1) for ii in range(n_subplots) ]

    traj_demonstration = numpy.loadtxt(directory+"/traj_demonstration.txt")
    lines = plotTrajectory(traj_demonstration,axs)
    plt.setp(lines, linestyle='-',  linewidth=4, color=(0.8,0.8,0.8), label='demonstration')

    traj_reproduced = numpy.loadtxt(directory+"/traj_reproduced.txt")
    lines = plotTrajectory(traj_reproduced,axs)
    plt.setp(lines, linestyle='--', linewidth=2, color=(0.0,0.0,0.5), label='reproduced')

    legendWithoutDuplicates(axs[-1])

    fig3.canvas.set_window_title('Comparison between demonstration and reproduced')
    plt.tight_layout()

    # Plot results of integrating the DMP
    tau           = numpy.loadtxt(directory+'/tau.txt')
    ts_xs_xds     = numpy.loadtxt(directory+'/reproduced_ts_xs_xds.txt')
    forcing_terms = numpy.loadtxt(directory+'/reproduced_forcing_terms.txt')
    fa_output     = numpy.loadtxt(directory+'/reproduced_fa_output.txt')

    fig2 = plt.figure(2,figsize=(golden_ratio*5*3,3*3))
    plotDmp(ts_xs_xds,fig2,forcing_terms,fa_output,[],tau)
    fig2.canvas.set_window_title('DMP integration')
    plt.tight_layout()

    # Plot the results of training the function approximation
    n_dims = (traj_demonstration.shape[1]-1)//3 # -1 for time, /3 for x/xd/xdd
    fig1 = plt.figure(1,figsize=(golden_ratio*n_dims*4,4))
    for i_dim in range(n_dims):
        ax = fig1.add_subplot(1, n_dims, i_dim+1)
        plotFunctionApproximatorTrainingFromDirectory(directory+"dim"+str(i_dim),ax)

    fig1.canvas.set_window_title('Results of function approximation')
    plt.tight_layout()

    fig1.savefig(directory+'/function_approximation.png')
    fig2.savefig(directory+'/dmp_integration.png')
    fig3.savefig(directory+'/trajectory_comparison.png')

    plt.show()
<|endoftext|>


<commit_before>import chess
import random

WHITE = True
BLACK = False

''' prints which player's turn it is '''
def print_turn(board):
    if board.turn is WHITE:
        print("white's turn")
    else:
        print("black's turn")
    pass

''' converts player (boolean) to string '''
def player_str(player):
    if player is WHITE:
        return "WHITE"
    else:
        return "BLACK"

''' prints list of legal moves for current player '''
def print_legal_moves(board):
    moves = list(board.legal_moves)
    for move in moves:
        board.push(move)
        print(board)
        board.pop()
    pass

''' returns winner from endgame state '''
def get_winner(board):
    if(not board.is_game_over):
        raise ValueError("game is not over!")
    return not board.turn

'''
Runs random game until game is over
Each player switches off making random legal moves
Returns losing player
'''
def run_random_game():
    board = chess.Board();
    num_turns = 0
    print("initial board")
    print_turn(board)
    print(board)
    print("")

    while(not board.is_game_over()):
        num_turns += 1

        moves = list(board.legal_moves)
        num_moves = len(moves)
        move_index = random.randrange(0, num_moves)
        print_turn(board)
        print(board)
        print("")
        board.push(moves[move_index])
        print(board)
        print("")
        print("")

    print("fivefold repitition: %r" % board.is_fivefold_repetition())
    print("seventy five moves: %r" %board.is_seventyfive_moves())
    print("checkmate: %r" % board.is_checkmate())
    print("stalemate: %r" % board.is_stalemate())
    print("insufficient material: %r" % board.is_insufficient_material())
    print_turn(board) # loser
    return get_winner(board)

if __name__=='__main__':
    winner = run_random_game()
    print("winner is %s" % player_str(winner))
<commit_msg>refactored a bit<commit_after>import chess
import random

WHITE = True
BLACK = False

''' prints which player's turn it is '''
def print_turn(board):
    if board.turn is WHITE:
        print("white's turn")
    else:
        print("black's turn")
    pass

''' converts player (boolean) to string '''
def player_str(player):
    if player is WHITE:
        return "WHITE"
    else:
        return "BLACK"

''' prints list of legal moves for current player '''
def print_legal_moves(board):
    moves = list(board.legal_moves)
    for move in moves:
        board.push(move)
        print(board)
        board.pop()
    pass

''' returns winner from endgame state '''
def get_winner(board):
    if(not board.is_game_over):
        raise ValueError("game is not over!")
    return not board.turn

''' prints out information about how game ended '''
def print_game_enders(board):
    print("fivefold repitition: %r" % board.is_fivefold_repetition())
    print("seventy five moves: %r" %board.is_seventyfive_moves())
    print("checkmate: %r" % board.is_checkmate())
    print("stalemate: %r" % board.is_stalemate())
    print("insufficient material: %r" % board.is_insufficient_material())

'''
Runs random game until game is over
Each player switches off making random legal moves
Returns losing player
'''
def run_random_game():
    board = chess.Board();
    num_turns = 0
    print("initial board")
    print_turn(board)
    print(board)
    print("")

    while(not board.is_game_over()):
        num_turns += 1
        moves = list(board.legal_moves)
        num_moves = len(moves)
        move_index = random.randrange(0, num_moves)

        print_turn(board)
        print(board)
        print("")
        board.push(moves[move_index])
        print(board)
        print("")
        print("")

    print_game_enders(board)
    print_turn(board) # loser
    return get_winner(board)

if __name__=='__main__':
    winner = run_random_game()
    print("winner is %s" % player_str(winner))
<|endoftext|>


<commit_before>#!/usr/bin/env python3
"""Test Controlfile discovery and normalization"""

import json
import os
from os.path import join
import tempfile
import unittest

from control.controlfile import Controlfile

class TestServicefile(unittest.TestCase):
    """Test reading in a single service Controlfile"""
    def setUp(self):
        self.temp_dir = tempfile.TemporaryDirectory()
        self.controlfile = '{}/Controlfile'.format(self.temp_dir.name)
        self.conf = {
            "image": "busybox",
            "container": {
                "name": "example",
                "hostname": "example",
                "volumes": [
                    "namevolume:/var/log"
                ],
                "dns_search": [
                    "example"
                ]
            }
        }
        with open(self.controlfile, 'w') as f:
            f.write(json.dumps(self.conf))

    def tearDown(self):
        self.temp_dir.cleanup()

    def test_single_service_controlfile(self):
        """Make sure that we don't break single service controlfiles"""
        ctrlfile = Controlfile(self.controlfile)
        self.assertIn('example', ctrlfile.services.keys())
        self.assertEqual(ctrlfile.services['example'].image,
                         self.conf['image'])
        self.assertEqual(ctrlfile.services['example'].controlfile,
                         self.controlfile)
        self.assertEqual(ctrlfile.services['example'].volumes,
                         self.conf['container']['volumes'])
        self.assertEqual(ctrlfile.services['example']['dns_search'],
                         self.conf['container']['dns_search'])

class TestGeneratingServiceList(unittest.TestCase):
    """
    Make sure that the service list is generated correctly, when a
    metaservice exists
    """
    def setUp(self):
        self.temp_dir = tempfile.TemporaryDirectory()
        self.controlfile = join(self.temp_dir.name, 'Controlfile')
        self.conf = {
            "services": {
                "foo": {
                    "image": "busybox",
                    "container": {
                        "name": "foo",
                        "hostname": "foo"
                    }
                },
                "bar": {
                    "image": "busybox",
                    "container": {
                        "name": "bar",
                        "hostname": "bar"
                    }
                },
                "named": {
                    "services": ["bar", "baz"]
                },
                "baz": {
                    "image": "busybox",
                    "required": False,
                    "container": {
                        "name": "baz"
                    }
                }
            }
        }
        with open(self.controlfile, 'w') as f:
            f.write(json.dumps(self.conf))

    def tearDown(self):
        self.temp_dir.cleanup()

    def test_generating_service_list(self):
        """
        Need to make sure that the service list is generated correctly even
        if a service doesn't define a service name.
        """
        ctrlfile = Controlfile(self.controlfile)
        self.assertEqual(
            ctrlfile.get_list_of_services(),
            frozenset([
                "foo",
                "bar",
                "baz",
                "named",
                "required",
                "all",
                "optional"]))

    def test_optional_services(self):
        """
        Make sure that containers that aren't required to be started are put
        in the optional services list.
        """
        ctrlfile = Controlfile(self.controlfile)
        self.assertIn(
            'baz',
            ctrlfile.services['all'])
        self.assertIn(
            'baz',
            ctrlfile.services['optional'])
        self.assertNotIn(
            'baz',
            ctrlfile.services['required'])

class TestIncludingControlfiles(unittest.TestCase):
    """Make sure that controlfiles to a service are read in correctly"""
    def setUp(self):
        self.temp_dir = tempfile.TemporaryDirectory()
        self.controlfile = join(self.temp_dir.name, 'Controlfile')
        self.testfile = join(self.temp_dir.name, 'test', 'Controlfile')
        self.conf = {
            "services": {
                "test": {
                    "controlfile": "test/Controlfile"
                }
            }
        }
        self.service_conf = {
            "image": "busybox",
            "container": {
                "name": "example",
                "hostname": "example",
                "volumes": ["namevolume:/var/log"],
                "dns_search": ["example"]
            }
        }
        with open(self.controlfile, 'w') as f:
            f.write(json.dumps(self.conf))
        os.mkdir(join(self.temp_dir.name, 'test'))
        with open(self.testfile, 'w') as f:
            f.write(json.dumps(self.service_conf))
        # self.service_conf.update({"service": "test", "controlfile": "test/Controlfile"})

    def tearDown(self):
        self.temp_dir.cleanup()

    def test_including_controlfiles(self):
        """
        Make sure that single level Controlfile inclusion works correctly,
        it also checks if relative path includes are correctly dereferenced
        from the Controlfile location.
        """
        # TODO: this test is failing because of a bug, not because you're an idiot
        ctrlfile = Controlfile(self.controlfile)
        self.assertEqual(ctrlfile.services['test'].volumes,
                         self.service_conf['volumes'])
        self.assertEqual(
            ctrlfile.get_list_of_services(),
            frozenset(['test']))

    @unittest.skip("Not Implemented")
    def test_updated_relative_paths(self):
        """
        Volumes and controlfile references need to be updated when Controlfiles
        are discovered and read in
        """
        # TODO: test this stuff

class TestDeeplyNestedControlfiles(unittest.TestCase):
    """
    Make sure that many recursive inclusions are handled correctly
    """
    def setUp(self):
        self.temp_dir = tempfile.TemporaryDirectory()
        self.controlfile_location = '{}/Controlfile'.format(self.temp_dir.name)
        self.conf = {
            "services": [
                {
                    "service": "test",
                    "controlfile": "test/Controlfile"
                }
            ]
        }
        self.foo_conf = {
            "services": [
                {
                    "service": "foo",
                    "controlfile": "foo/Controlfile"
                }
            ]
        }
        self.service_conf = {
            "image": "busybox",
            "container": {
                "name": "example",
                "hostname": "example",
                "volumes": ["namevolume:/var/log"],
                "dns_search": ["example"]
            }
        }
        with open(self.controlfile_location, 'w') as f:
            f.write(json.dumps(self.conf))
        os.mkdir('{}/test'.format(self.temp_dir.name))
        with open('{}/test/Controlfile'.format(self.temp_dir.name), 'w') as f:
            f.write(json.dumps(self.foo_conf))
        os.mkdir('{}/test/foo'.format(self.temp_dir.name))
        with open('{}/test/foo/Controlfile'.format(self.temp_dir.name), 'w') as f:
            f.write(json.dumps(self.service_conf))

    def tearDown(self):
        self.temp_dir.cleanup()

    @unittest.skip("this test doesn't demonstrate the behaviour I want yet")
    def test_nested_controlfile(self):
        """Reference a Controlfile that references other Controlfiles"""

if __name__ == '__main__':
    unittest.main()
<commit_msg>reworking tests to have purpose<commit_after>"""Test Controlfile discovery and normalization"""

import json
from os.path import join
import tempfile
import unittest

from control.controlfile import Controlfile, satisfy_nested_options

class TestServicefile(unittest.TestCase):
    """Test reading in a single service Controlfile"""
    def setUp(self):
        self.temp_dir = tempfile.TemporaryDirectory()
        self.controlfile = '{}/Controlfile'.format(self.temp_dir.name)
        self.conf = {
            "image": "busybox",
            "container": {
                "name": "example",
                "hostname": "example",
                "volumes": [
                    "namevolume:/var/log"
                ],
                "dns_search": [
                    "example"
                ]
            }
        }
        with open(self.controlfile, 'w') as f:
            f.write(json.dumps(self.conf))

    def tearDown(self):
        self.temp_dir.cleanup()

    def test_single_service_controlfile(self):
        """Make sure that we don't break single service controlfiles"""
        ctrlfile = Controlfile(self.controlfile)
        self.assertIn('example', ctrlfile.services.keys())
        self.assertEqual(ctrlfile.services['example'].image,
                         self.conf['image'])
        self.assertEqual(ctrlfile.services['example'].controlfile,
                         self.controlfile)
        self.assertEqual(ctrlfile.services['example'].volumes,
                         self.conf['container']['volumes'])
        self.assertEqual(ctrlfile.services['example']['dns_search'],
                         self.conf['container']['dns_search'])

class TestGeneratingServiceList(unittest.TestCase):
    """
    Make sure that the service list is generated correctly, when a
    metaservice exists
    """
    def setUp(self):
        self.temp_dir = tempfile.TemporaryDirectory()
        self.controlfile = join(self.temp_dir.name, 'Controlfile')
        self.conf = {
            "services": {
                "foo": {
                    "image": "busybox",
                    "container": {
                        "name": "foo",
                        "hostname": "foo"
                    }
                },
                "bar": {
                    "image": "busybox",
                    "container": {
                        "name": "bar",
                        "hostname": "bar"
                    }
                },
                "named": {
                    "services": ["bar", "baz"]
                },
                "baz": {
                    "image": "busybox",
                    "required": False,
                    "container": {
                        "name": "baz"
                    }
                }
            }
        }
        with open(self.controlfile, 'w') as f:
            f.write(json.dumps(self.conf))

    def tearDown(self):
        self.temp_dir.cleanup()

    def test_generating_service_list(self):
        """
        Need to make sure that the service list is generated correctly even
        if a service doesn't define a service name.
        """
        ctrlfile = Controlfile(self.controlfile)
        self.assertEqual(
            ctrlfile.get_list_of_services(),
            frozenset([
                "foo",
                "bar",
                "baz",
                "named",
                "required",
                "all",
                "optional"]))

    def test_optional_services(self):
        """
        Make sure that containers that aren't required to be started are put
        in the optional services list.
        """
        ctrlfile = Controlfile(self.controlfile)
        self.assertIn(
            'baz',
            ctrlfile.services['all'])
        self.assertIn(
            'baz',
            ctrlfile.services['optional'])
        self.assertNotIn(
            'baz',
            ctrlfile.services['required'])

class TestNestedMetaServices(unittest.TestCase):
    """
    Provide test coverage for option 2 of create_service, where a metaservice
    contains the definitions of more services. Make sure that calls to
    satisfy_nested_options are made correctly.
    """

    def test_suffix(self):
        """Make sure that suffixing works for strings and lists"""
        temp_dir = tempfile.TemporaryDirectory()
        controlfile = join(temp_dir.name, 'Controlfile')
        conf = {
            "services": {
                "testmeta": {
                    "services": {
                        "test": {
                            "image": "busybox",
                            "container": {
                                "name": "test"
                            }
                        }
                    }
                }
            },
            "options": {
                "name": {"suffix": ".{FOO}"}
            },
            "vars": {
                "FOO": "example"
            }
        }
        with open(controlfile, 'w') as f:
            f.write(json.dumps(conf))
        ctrlfile = Controlfile(controlfile)
        self.assertEqual(ctrlfile.services['test']['name'],
                         'test.example')

    def test_prefix(self):
        """Make sure that prefixing works for strings and lists"""
        temp_dir = tempfile.TemporaryDirectory()
        controlfile = join(temp_dir.name, 'Controlfile')
        conf = {
            "services": {
                "testmeta": {
                    "services": {
                        "test": {
                            "image": "busybox",
                            "container": {
                                "name": "test"
                            }
                        }
                    }
                }
            },
            "options": {
                "image": {"prefix": "registry.example.com/"},
                "name": {"prefix": "{FOO}."}
            },
            "vars": {
                "FOO": "example"
            }
        }
        with open(controlfile, 'w') as f:
            f.write(json.dumps(conf))
        ctrlfile = Controlfile(controlfile)
        self.assertEqual(ctrlfile.services['test'].image,
                         'registry.example.com/busybox')
        self.assertEqual(ctrlfile.services['test']['name'],
                         'example.test')

    def test_union(self):
        """Make sure that prefixing works for strings and lists"""
        temp_dir = tempfile.TemporaryDirectory()
        controlfile = join(temp_dir.name, 'Controlfile')
        conf = {
            "services": {
                "testmeta": {
                    "services": {
                        "test": {
                            "image": "busybox",
                            "container": {
                                "name": "test",
                                "volumes": ["vardata:/var/lib/{FOO}"]
                            }
                        }
                    }
                }
            },
            "options": {
                "volumes": {"union": ["{FOO}:/home"]}
            },
            "vars": {
                "FOO": "example"
            }
        }
        with open(controlfile, 'w') as f:
            f.write(json.dumps(conf))
        ctrlfile = Controlfile(controlfile)
        self.assertEqual(ctrlfile.services['test']['volumes'],
                         ['example:/home', 'vardata:/var/lib/example'])

    def test_replace(self):
        """Make sure that prefixing works for strings and lists"""
        temp_dir = tempfile.TemporaryDirectory()
        controlfile = join(temp_dir.name, 'Controlfile')
        conf = {
            "services": {
                "testmeta": {
                    "services": {
                        "test": {
                            "image": "busybox",
                            "container": {
                                "name": "test",
                            }
                        }
                    }
                }
            },
            "options": {
                "image": {"replace": "registry.{FOO}.com/alpine"}
            },
            "vars": {
                "FOO": "example"
            }
        }
        with open(controlfile, 'w') as f:
            f.write(json.dumps(conf))
        ctrlfile = Controlfile(controlfile)
        self.assertEqual(ctrlfile.services['test'].image,
                         'registry.example.com/alpine')
<|endoftext|>


<commit_before>from numpy import array, matrix, inf, nan, ones, zeros, arctan, isinf

import matplotlib

matplotlib.use('nbAgg')

import matplotlib.pyplot as plt

class OPE(object):
    def __init__(self, a=inf, d=None, f=None, name=''):
        """
        Optical path element used for ray tracing.

        Arguments
        ---------
        a : inf or float
            Aperture of the element.
        d : float or None
            Distance travelled through optical element.
        f : flaot or None
            Focal length of optical element.
        name : str
            Name of the element.
        """
        self.aperture = a
        self.name = name

        if f:
            self.c = -1 / f
        else:
            self.c = 0

        if d:
            self.b = d
        else:
            self.b = 0

    def is_lens(self):
        if self.get_matrix()[1, 0] != 0:
            return True
        else:
            return False

    def get_matrix(self):
        return matrix([[1, self.b], [self.c, 1]])

    def passes_aperture(self, r, verbose=False):
        """
        Does an input ray r pass the optical element.
        """
        h = r.flatten()[0]
        if abs(h) > self.aperture:
            if verbose:
                print('{0:s}: stopped at aperture with height {1:1.3f}'.format(
                    self.name, h))
            return False
        else:
            if verbose:
                print('{0:s}: passed aperture with height {1:1.3f}'.format(
                    self.name, h))
            return True

    def pass_aperture(self, r, verbose=False):
        """ Return nan vector if ray cannot pass aperture."""
        if self.passes_aperture(r, verbose=verbose):
            return r
        else:
            return matrix(ones(r.shape) * nan)

    def transmit(self, r, verbose=False):
        """ Calculate output ray. """
        M = self.get_matrix()
        r_ = M * matrix(self.pass_aperture(r, verbose=verbose)).T
        return array(r_).flatten()

    def get_travel_length(self):
        """ Length the optical element takes. """
        return self.b

def trace_ray(r, sequence):
    """
    Take r as input vector and trace the ray through the sequence of
    optical path elements OLEs.
    """
    ray0 = zeros((2, len(sequence) + 1))
    ray0[:, 0] = r

    # Do the calculations
    distances = [0.0]
    for idx, el in enumerate(sequence):
        ray0[:, idx + 1] = el.transmit(ray0[:, idx])
        distances.append(distances[idx] + el.get_travel_length())

    dist = array(distances)

    return (dist, ray0)

def get_first_aperture(sequence):
    """
    get aperture of first lens in path and calculate distance to it.

    Arguments
    ---------
    sequence : list of OPE
        List of optical path elements

    Returns
    -------
    tuple(idx, distance, aperture)
    """
    d = 0.0
    a = inf
    for idx, m in enumerate(sequence):
        if isinf(m.aperture):
            d += m.get_travel_length()
        else:
            a = m.aperture
            break
    return (idx, d, a)

def get_lens_pos(sequence):
    """
    Calculate positions of lenses.

    Returns
    -------
    List of tuples with position and index of OPE in sequence.
    """
    d = 0.0
    d_ = []
    for idx, m in enumerate(sequence):
        if m.is_lens():
            d_.append((idx, d))
        else:
            d += m.get_travel_length()

    return d_

def get_angle_lim(h, d, a):
    """
    Calculate the upper and lower angles of a source that is at
    distance d to an aperture a.
    """
    # return (arctan((a - h) / d), arctan(-(a + h) / d))
    return ((a - h) / d, -(a + h) / d)

def trace_parser(s):
    '''
    Convert a string into a seqeunce of optical path elements.

    Example
    -------
    s = 'd15 | l15/5.5 | d15'
    would result in a seqeunce of a distance element of 15 lu
    (lu=length units), followed by a Lens with focal length 15 lu
    with aperture 5.5 lu and another distance of 15 lu.
    '''
    sequence = []

    for idx, si in enumerate(s.lower().replace(' ', '').split('|')):
        if si.startswith('d'):
            s_ = si.split('/')
            d = float(s_[0][1:])
            if len(s_) == 2:
                a = float(s_[1])
                ope = OPE(d=d, a=a, name='D' + str(idx))
            else:
                ope = OPE(d=d, name='D' + str(idx))
        elif si.startswith('l'):
            s_ = si.split('/')
            f = float(s_[0][1:])
            if len(s_) == 2:
                a = float(s_[1])
                ope = OPE(f=f, a=a, name='L' + str(idx))
            else:
                ope = OPE(f=f, name='L' + str(idx))
        else:
            print('unknown element {}'.format(si))
        sequence.append(ope)

    return sequence

def plot_ray(h, sequence, parallel=False, d=None,
             axis=None, label=None, **pltkws):
    """
    Plot the ray trace through the sequence of OPEs.

    Arguments
    ---------
    h : float
        height of ray.
    sequence : list of OPE
        sequence of optical path elements.
    parallel : bool
        Whether the source ray is a parallel beam.
    d : float
        Diameter of an incoming parallel beam.
    axis : matplotlib.Axis
    label : str
        Label of the plotted line

    Keyword Arguments
    -----------------
    kws passed to plt.plot(**pltkws)

    Returns
    -------
    maplotlib.figure
    """
    if axis:
        fig = axis.figure
        ax = axis
    else:
        fig = plt.figure()
        ax = fig.add_subplot(111)

    if not any([a in pltkws for a in ['c', 'col', 'color']]):
        pltkws['color'] = next(ax._get_lines.prop_cycler)['color']

    ax.axhline(color='k', linewidth=0.5, linestyle='--')

    if parallel:
        d = d or 1.0
        rin_0 = [h + d/2, 0.0]
        rin_1 = [h - d/2, 0.0]
    else:
        # get distance and aperture of first aperture
        _, d, aperture = get_first_aperture(sequence)

        a1, a2 = get_angle_lim(h, d, aperture)
        rin_0 = [h, a1]
        rin_1 = [h, a2]

    dist, r0 = trace_ray(rin_0, sequence)
    dist, r1 = trace_ray(rin_1, sequence)

    #pltkws = {'linewidth': 0.5}.update(pltkws)

    ax.plot(dist, r0[0, :], label=label or 'h={:1.2f}'.format(h), **pltkws)
    ax.plot(dist, r1[0, :], **pltkws)

    for idx, x in get_lens_pos(sequence):
        ax.axvline(x=x, ymin=0.02, ymax=0.98, linewidth=0.5, linestyle='--')

    draw_apertures(sequence, axis=ax)

    return fig

def draw_apertures(sequence, axis=None):
    """
    Draw the apertures in the sequence
    """
    if not axis:
        ax = plt.gca()
    else:
        ax = axis

        plt_kws = dict(linewidth=2, linestyle='-', color='darkslategrey')

    a_max = get_max_aperture(sequence)

    ylims = ax.get_ylim()
    for idx, x in get_lens_pos(sequence):
        a = sequence[idx].aperture
        ax.plot([x, x], [-2*a_max, -a], **plt_kws)
        ax.plot([x, x], [a, 2*a_max], **plt_kws)
    ax.set_ylim(ylims)

def get_max_aperture(sequence):
    """
    Return largest aperture in sequence.
    """
    apertures = [ope.aperture for ope in sequence if ope.aperture != inf]

    if not apertures:
        out = None
    else:
        out = max(apertures)

    return out
<commit_msg>changed plotting sequence to make multiple plotting of lenses etc. avoidable<commit_after>from numpy import array, matrix, inf, nan, ones, zeros, arctan, isinf

import matplotlib

matplotlib.use('nbAgg')

import matplotlib.pyplot as plt

class OPE(object):
    def __init__(self, a=inf, d=None, f=None, name=''):
        """
        Optical path element used for ray tracing.

        Arguments
        ---------
        a : inf or float
            Aperture of the element.
        d : float or None
            Distance travelled through optical element.
        f : flaot or None
            Focal length of optical element.
        name : str
            Name of the element.
        """
        self.aperture = a
        self.name = name

        if f:
            self.c = -1 / f
        else:
            self.c = 0

        if d:
            self.b = d
        else:
            self.b = 0

    def is_lens(self):
        if self.get_matrix()[1, 0] != 0:
            return True
        else:
            return False

    def get_matrix(self):
        return matrix([[1, self.b], [self.c, 1]])

    def passes_aperture(self, r, verbose=False):
        """
        Does an input ray r pass the optical element.
        """
        h = r.flatten()[0]
        if abs(h) > self.aperture:
            if verbose:
                print('{0:s}: stopped at aperture with height {1:1.3f}'.format(
                    self.name, h))
            return False
        else:
            if verbose:
                print('{0:s}: passed aperture with height {1:1.3f}'.format(
                    self.name, h))
            return True

    def pass_aperture(self, r, verbose=False):
        """ Return nan vector if ray cannot pass aperture."""
        if self.passes_aperture(r, verbose=verbose):
            return r
        else:
            return matrix(ones(r.shape) * nan)

    def transmit(self, r, verbose=False):
        """ Calculate output ray. """
        M = self.get_matrix()
        r_ = M * matrix(self.pass_aperture(r, verbose=verbose)).T
        return array(r_).flatten()

    def get_travel_length(self):
        """ Length the optical element takes. """
        return self.b

def trace_ray(r, sequence):
    """
    Take r as input vector and trace the ray through the sequence of
    optical path elements OLEs.
    """
    ray0 = zeros((2, len(sequence) + 1))
    ray0[:, 0] = r

    # Do the calculations
    distances = [0.0]
    for idx, el in enumerate(sequence):
        ray0[:, idx + 1] = el.transmit(ray0[:, idx])
        distances.append(distances[idx] + el.get_travel_length())

    dist = array(distances)

    return (dist, ray0)

def get_first_aperture(sequence):
    """
    get aperture of first lens in path and calculate distance to it.

    Arguments
    ---------
    sequence : list of OPE
        List of optical path elements

    Returns
    -------
    tuple(idx, distance, aperture)
    """
    d = 0.0
    a = inf
    for idx, m in enumerate(sequence):
        if isinf(m.aperture):
            d += m.get_travel_length()
        else:
            a = m.aperture
            break
    return (idx, d, a)

def get_lens_pos(sequence):
    """
    Calculate positions of lenses.

    Returns
    -------
    List of tuples with position and index of OPE in sequence.
    """
    d = 0.0
    d_ = []
    for idx, m in enumerate(sequence):
        if m.is_lens():
            d_.append((idx, d))
        else:
            d += m.get_travel_length()

    return d_

def get_angle_lim(h, d, a):
    """
    Calculate the upper and lower angles of a source that is at
    distance d to an aperture a.
    """
    # return (arctan((a - h) / d), arctan(-(a + h) / d))
    return ((a - h) / d, -(a + h) / d)

def trace_parser(s):
    '''
    Convert a string into a seqeunce of optical path elements.

    Example
    -------
    s = 'd15 | l15/5.5 | d15'
    would result in a seqeunce of a distance element of 15 lu
    (lu=length units), followed by a Lens with focal length 15 lu
    with aperture 5.5 lu and another distance of 15 lu.
    '''
    sequence = []

    for idx, si in enumerate(s.lower().replace(' ', '').split('|')):
        if si.startswith('d'):
            s_ = si.split('/')
            d = float(s_[0][1:])
            if len(s_) == 2:
                a = float(s_[1])
                ope = OPE(d=d, a=a, name='D' + str(idx))
            else:
                ope = OPE(d=d, name='D' + str(idx))
        elif si.startswith('l'):
            s_ = si.split('/')
            f = float(s_[0][1:])
            if len(s_) == 2:
                a = float(s_[1])
                ope = OPE(f=f, a=a, name='L' + str(idx))
            else:
                ope = OPE(f=f, name='L' + str(idx))
        else:
            print('unknown element {}'.format(si))
        sequence.append(ope)

    return sequence

def plot_ray(h, sequence, parallel=False, d=None,
             axis=None, label=None, plot_statics=True, **pltkws):
    """
    Plot the ray trace through the sequence of OPEs.

    Arguments
    ---------
    h : float
        height of ray.
    sequence : list of OPE
        sequence of optical path elements.
    parallel : bool
        Whether the source ray is a parallel beam.
    d : float
        Diameter of an incoming parallel beam.
    axis : matplotlib.Axis
    label : str
        Label of the plotted line

    Keyword Arguments
    -----------------
    kws passed to plt.plot(**pltkws)

    Returns
    -------
    maplotlib.figure
    """
    if axis:
        fig = axis.figure
        ax = axis
    else:
        fig = plt.figure()
        ax = fig.add_subplot(111)

    if not any([a in pltkws for a in ['c', 'col', 'color']]):
        pltkws['color'] = next(ax._get_lines.prop_cycler)['color']

    if plot_statics:
        # draw optical axis
        ax.axhline(color='k', linewidth=0.5, linestyle='--')
        # draw lenses
        for idx, x in get_lens_pos(sequence):
            ax.axvline(x=x, ymin=0.02, ymax=0.98,
                       linewidth=0.5, linestyle='--')
        # draw apertures
        draw_apertures(sequence, axis=ax)

    if parallel:
        d = d or 1.0
        rin_0 = [h + d/2, 0.0]
        rin_1 = [h - d/2, 0.0]
    else:
        # get distance and aperture of first aperture
        _, d, aperture = get_first_aperture(sequence)

        a1, a2 = get_angle_lim(h, d, aperture)
        rin_0 = [h, a1]
        rin_1 = [h, a2]

    dist, r0 = trace_ray(rin_0, sequence)
    dist, r1 = trace_ray(rin_1, sequence)

    #pltkws = {'linewidth': 0.5}.update(pltkws)

    ax.plot(dist, r0[0, :], label=label or 'h={:1.2f}'.format(h), **pltkws)
    ax.plot(dist, r1[0, :], **pltkws)

    return fig

def draw_apertures(sequence, axis=None):
    """
    Draw the apertures in the sequence
    """
    if not axis:
        ax = plt.gca()
    else:
        ax = axis

        plt_kws = dict(linewidth=2, linestyle='-', color='darkslategrey')

    a_max = get_max_aperture(sequence)

    # ylims = ax.get_ylim()
    for idx, x in get_lens_pos(sequence):
        a = sequence[idx].aperture
        ax.plot([x, x], [-2*a_max, -a], **plt_kws)
        ax.plot([x, x], [a, 2*a_max], **plt_kws)
    # ax.set_ylim(ylims)

def get_max_aperture(sequence):
    """
    Return largest aperture in sequence.
    """
    apertures = [ope.aperture for ope in sequence if ope.aperture != inf]

    if not apertures:
        out = None
    else:
        out = max(apertures)

    return out
<|endoftext|>


<commit_before><commit_msg>Course Caching: Remove unused file<commit_after><|endoftext|>


<commit_before>import signal

from rcpy._buttons import pressed as _pressed
from rcpy._buttons import released as _released

# definitions

# BUTTONs
PAUSE  = 0
MODE = 1

# class for timeout
class TimeoutException(Exception):
    pass

# timeout handler
def timeout_handler(signum, frame):
    raise TimeoutException()

# pressed?
def pressed(button, timeout = 0):

    # set a timeout
    if timeout > 0:
        signal.signal(signal.SIGALRM, timeout_handler)
        signal.alarm(timeout)

    try:
        return _pressed(button)
    except TimeoutException:
        return False

# released?
def released(button, timeout = 0):

    # set a timeout
    if timeout > 0:
        signal.signal(signal.SIGALRM, timeout_handler)
        signal.alarm(timeout)

    try:
        return _released(button)
    except TimeoutException:
        return False
<commit_msg>Blink demo<commit_after>import threading

from rcpy._buttons import pressed as _pressed
from rcpy._buttons import released as _released

# definitions

# BUTTONs
PAUSE  = 0
MODE = 1

# class for timeout
class TimeoutException(Exception):
    pass

# timeout handler
def timeout_handler(signum, frame):
    raise TimeoutException()

# pressed?
def pressed(button, timeout = 0):

    # set a timeout
    if timeout > 0:
        threading.Timer(timeout, timeout_handler)

    try:
        return _pressed(button)
    except TimeoutException:
        return False

# released?
def released(button, timeout = 0):

    # set a timeout
    if timeout > 0:
        threading.Timer(timeout, timeout_handler)

    try:
        return _released(button)
    except TimeoutException:
        return False
<|endoftext|>