<commit_before># -*- coding: utf-8 -*-
"""
Shared functions and classes for contrail_api_cli_extra commands.
"""

from __future__ import unicode_literals

from six import text_type
import argparse
import netaddr
import re
import abc
from six import add_metaclass
import textwrap

from kazoo.client import KazooClient
from kazoo.handlers.gevent import SequentialGeventHandler

from prettytable import PrettyTable

from contrail_api_cli.command import Command, Arg, Option, expand_paths
from contrail_api_cli.exceptions import CommandError
from contrail_api_cli.resource import Collection
from contrail_api_cli.utils import continue_prompt

def ip_type(string):
    """argparse type to validate IP adresses.
    """
    try:
        return text_type(netaddr.IPAddress(string))
    except netaddr.AddrFormatError:
        raise argparse.ArgumentTypeError('%s is not an ip address' % string)

def network_type(string):
    """argparse type to validate network adresses.
    """
    try:
        return text_type(netaddr.IPNetwork(string))
    except netaddr.AddrFormatError:
        raise argparse.ArgumentTypeError('%s is not a network' % string)

def port_type(value):
    """argparse type to validate port numbers.
    """
    try:
        value = int(value)
        if not 1 <= value <= 65535:
            raise argparse.ArgumentTypeError("Port number must be contained between 1 and 65535")
        return value
    except ValueError as e:
        raise argparse.ArgumentTypeError(str(e))

def server_type(value):
    """argparse type to validate a server:port option.
    """
    server = value.split(':')
    if len(server) > 2:
        raise argparse.ArgumentTypeError("Server can be composed to the hostname and port separated by the ':' character")
    if len(server) == 2:
        port = server[1]
        port_type(port)
    return value

def md5_type(value):
    """argparse type to validate a md5 hash.
    """
    if value and not re.match(r"([a-fA-F\d]{32})", value):
        raise argparse.ArgumentTypeError("MD5 hash %s is not valid" % value)
    return value

def format_column(column, width, depth=0):
    result = ""
    i = 0
    if isinstance(column, list):
        item = "* "
        for val in column:
            if i == 0:
                result += item + format_column(val, width, depth + 1) + "\n"
            else:
                result += "  " * depth + item + format_column(val, width, depth + 1) + "\n"
            i = i + 1
    elif isinstance(column, tuple):
        item = "- "
        for val in column:
            if i == 0:
                result += item + format_column(val, width, depth + 1) + "\n"
            else:
                result += "  " * depth + item + format_column(val, width, depth + 1) + "\n"
            i = i + 1
    else:
        result += "\n".join(textwrap.wrap(str(column), width))
    return result

def format_row(header, widths, row):
    size = len(header)
    result = []
    for i in range(size):
        fcell = format_column(row[i], widths[i])
        result.append(fcell)
    return result

def format_table_ascii_delimiters(header, widths, data):
    """ format_table_ascii_delimiters: return ascii table with delimitation and lines
        wrapped.

        Usage:

        header = ["name", "age", "job", "bag"]
        widths = [20, 4, 10, 40]
        data = [["foo", 54, "policeman", ("pen", "knife", "glasses")],
               ["bar", 28, "fireman", ("socket", "hat")],
                       ["joe", 36, "anthropologist", ("computer", "keyboard")]]

        format_table2(header, widths, data)

        Return:

        +------+-----+------------+------------+
        | name | age | job        | bag        |
        +------+-----+------------+------------+
        | foo  | 54  | policeman  | - pen      |
        |      |     |            | - knife    |
        |      |     |            | - glasses  |
        |      |     |            |            |
        | bar  | 28  | fireman    | - socket   |
        |      |     |            | - hat      |
        |      |     |            |            |
        | joe  | 36  | anthropolo | - computer |
        |      |     | gist       | - keyboard |
        |      |     |            |            |
        +------+-----+------------+------------+
    """
    table = PrettyTable()
    table.field_names = header
    table.align = "l"
    for row in data:
        row = format_row(header, widths, row)
        table.add_row(row)
    return table

class RouteTargetAction(argparse.Action):
    def __call__(self, parser, namespace, values, option_string=None):
        unique_values = set(values)
        ret_values = []
        for value in unique_values:
            ret_values.append(RouteTargetAction.route_target_type(value))
        setattr(namespace, self.dest, ret_values)

    @staticmethod
    def asn_type(value):
        try:
            value = int(value)
            if not 1 <= value <= 65534:
                raise argparse.ArgumentTypeError("AS number must be contained between 1 and 65534")
            return value
        except ValueError:
            pass
        try:
            return text_type(netaddr.IPNetwork(value, version=4).ip)
        except netaddr.AddrFormatError as e:
            raise argparse.ArgumentTypeError(str(e))

    @staticmethod
    def route_target_type(value):
        try:
            asn, rt_num = value.split(':')
        except ValueError:
            raise argparse.ArgumentTypeError("A router target must be composed by an ASN and a number separated by the ':' character")

        asn = RouteTargetAction.asn_type(asn)

        try:
            rt_num = int(rt_num)
        except ValueError:
            raise argparse.ArgumentTypeError("Route target number must be an integer")
        if isinstance(asn, int) and not 1 <= rt_num < pow(2, 32):
            raise argparse.ArgumentTypeError("With ASN as integer, the route target number must be contained between 1 and %d" % pow(2, 32))
        elif isinstance(asn, unicode) and not 1 <= rt_num < pow(2, 16):
            raise argparse.ArgumentTypeError("With ASN as IPv4, the route target number must be contained between 1 and %d" % pow(2, 16))

        return 'target:%s' % value

class ZKCommand(Command):
    """Inherit from this class when a connection to the Zookeeper cluster
    is needed.

    This will add a `--zk-server` option to the command.

    The ZK client is available in `self.zk_client`.
    """
    zk_server = Option(help="zookeeper server (default: %(default)s)",
                       type=server_type,
                       default='localhost:2181')

    def __call__(self, zk_server=None, **kwargs):
        if not hasattr(self, 'zk_client'):
            handler = SequentialGeventHandler()
            self.zk_client = KazooClient(hosts=zk_server, timeout=1.0,
                                         handler=handler)
            try:
                self.zk_client.start()
            except handler.timeout_exception:
                raise CommandError("Can't connect to Zookeeper at %s" % zk_server)
        elif not self.zk_client.connected:
            self.zk_client.restart()

        super(ZKCommand, self).__call__(**kwargs)

class CheckCommand(Command):
    """Inherit from this class to add `--check` and `--dry-run` options.

    Options values are stored in `self.check` and `self.dry_run` (True or False).
    """
    check = Option('-c',
                   default=False,
                   action="store_true")
    dry_run = Option('-n',
                     default=False,
                     action="store_true",
                     help='run this command in dry-run mode')

    def __call__(self, dry_run=None, check=None, **kwargs):
        self.dry_run = dry_run
        self.check = check
        super(CheckCommand, self).__call__(**kwargs)

@add_metaclass(abc.ABCMeta)
class PathCommand(Command):
    """Inherit from this class for a command that expect a list of
    resource paths.

    This will add a `path` argument to the command (nargs=*).

    The selected resources are available in `self.resources`.
    """

    @abc.abstractproperty
    def resource_type(self):
        """Type of resource the command
        is about.
        """
        return "resource_type"

    def __new__(cls, *args):
        cmd = super(PathCommand, cls).__new__(cls, *args)
        cls.paths = Arg(nargs="*",
                        help="{type} path(s). "
                             "When no path is provided "
                             "all {type}s are considered.".format(type=cmd.resource_type),
                        metavar='path',
                        complete="resources:%s:path" % cmd.resource_type)
        return cmd

    def __call__(self, paths=None, **kwargs):
        if not paths:
            self.resources = Collection(self.resource_type, fetch=True)
        else:
            self.resources = expand_paths(paths,
                                          predicate=lambda r: r.type == self.resource_type)
        super(PathCommand, self).__call__(**kwargs)

@add_metaclass(abc.ABCMeta)
class ConfirmCommand(Command):
    """Inherit from this class for a command that expect a confirmation.

    This will add a --yes flag to skip the confirmation. `self.yes` can
    be used by the command to show the confirmation or not.
    """
    yes = Option('-y', action='store_true', help='Assume yes to all queries and do not prompt')

    @property
    def confirm_message(self):
        """Confirmation message to run the command
        """
        return "Are you sure ?"

    def __call__(self, yes=None, **kwargs):
        dry_run = getattr(self, 'dry_run', kwargs.get('dry_run', False))
        check = getattr(self, 'check', kwargs.get('check', False))
        if not yes and not dry_run and not check and \
                not continue_prompt(self.confirm_message):
            raise CommandError("Exiting.")
        super(ConfirmCommand, self).__call__(**kwargs)
<commit_msg>Doc fixes<commit_after># -*- coding: utf-8 -*-
"""
Shared functions and classes for contrail_api_cli_extra commands.
"""

from __future__ import unicode_literals

from six import text_type
import argparse
import netaddr
import re
import abc
from six import add_metaclass
import textwrap

from kazoo.client import KazooClient
from kazoo.handlers.gevent import SequentialGeventHandler

from prettytable import PrettyTable

from contrail_api_cli.command import Command, Arg, Option, expand_paths
from contrail_api_cli.exceptions import CommandError
from contrail_api_cli.resource import Collection
from contrail_api_cli.utils import continue_prompt

def ip_type(string):
    """argparse type to validate IP adresses.
    """
    try:
        return text_type(netaddr.IPAddress(string))
    except netaddr.AddrFormatError:
        raise argparse.ArgumentTypeError('%s is not an ip address' % string)

def network_type(string):
    """argparse type to validate network adresses.
    """
    try:
        return text_type(netaddr.IPNetwork(string))
    except netaddr.AddrFormatError:
        raise argparse.ArgumentTypeError('%s is not a network' % string)

def port_type(value):
    """argparse type to validate port numbers.
    """
    try:
        value = int(value)
        if not 1 <= value <= 65535:
            raise argparse.ArgumentTypeError("Port number must be contained between 1 and 65535")
        return value
    except ValueError as e:
        raise argparse.ArgumentTypeError(str(e))

def server_type(value):
    """argparse type to validate a server:port option.
    """
    server = value.split(':')
    if len(server) > 2:
        raise argparse.ArgumentTypeError("Server can be composed to the hostname and port separated by the ':' character")
    if len(server) == 2:
        port = server[1]
        port_type(port)
    return value

def md5_type(value):
    """argparse type to validate a md5 hash.
    """
    if value and not re.match(r"([a-fA-F\d]{32})", value):
        raise argparse.ArgumentTypeError("MD5 hash %s is not valid" % value)
    return value

def format_column(column, width, depth=0):
    result = ""
    i = 0
    if isinstance(column, list):
        item = "* "
        for val in column:
            if i == 0:
                result += item + format_column(val, width, depth + 1) + "\n"
            else:
                result += "  " * depth + item + format_column(val, width, depth + 1) + "\n"
            i = i + 1
    elif isinstance(column, tuple):
        item = "- "
        for val in column:
            if i == 0:
                result += item + format_column(val, width, depth + 1) + "\n"
            else:
                result += "  " * depth + item + format_column(val, width, depth + 1) + "\n"
            i = i + 1
    else:
        result += "\n".join(textwrap.wrap(str(column), width))
    return result

def format_row(header, widths, row):
    size = len(header)
    result = []
    for i in range(size):
        fcell = format_column(row[i], widths[i])
        result.append(fcell)
    return result

def format_table_ascii_delimiters(header, widths, data):
    """
    Return ascii table with delimitation and lines wrapped.

    usage::

        header = ["name", "age", "job", "bag"]
        widths = [20, 4, 10, 40]
        data = [
                 ["foo", 54, "policeman", ("pen", "knife", "glasses")],
                 ["bar", 28, "fireman", ("socket", "hat")],
                 ["joe", 36, "anthropologist", ("computer", "keyboard")]
               ]

        format_table2(header, widths, data)

    return::

        +------+-----+------------+------------+
        | name | age | job        | bag        |
        +------+-----+------------+------------+
        | foo  | 54  | policeman  | - pen      |
        |      |     |            | - knife    |
        |      |     |            | - glasses  |
        |      |     |            |            |
        | bar  | 28  | fireman    | - socket   |
        |      |     |            | - hat      |
        |      |     |            |            |
        | joe  | 36  | anthropolo | - computer |
        |      |     | gist       | - keyboard |
        |      |     |            |            |
        +------+-----+------------+------------+

    """
    table = PrettyTable()
    table.field_names = header
    table.align = "l"
    for row in data:
        row = format_row(header, widths, row)
        table.add_row(row)
    return table

class RouteTargetAction(argparse.Action):
    def __call__(self, parser, namespace, values, option_string=None):
        unique_values = set(values)
        ret_values = []
        for value in unique_values:
            ret_values.append(RouteTargetAction.route_target_type(value))
        setattr(namespace, self.dest, ret_values)

    @staticmethod
    def asn_type(value):
        try:
            value = int(value)
            if not 1 <= value <= 65534:
                raise argparse.ArgumentTypeError("AS number must be contained between 1 and 65534")
            return value
        except ValueError:
            pass
        try:
            return text_type(netaddr.IPNetwork(value, version=4).ip)
        except netaddr.AddrFormatError as e:
            raise argparse.ArgumentTypeError(str(e))

    @staticmethod
    def route_target_type(value):
        try:
            asn, rt_num = value.split(':')
        except ValueError:
            raise argparse.ArgumentTypeError("A router target must be composed by an ASN and a number separated by the ':' character")

        asn = RouteTargetAction.asn_type(asn)

        try:
            rt_num = int(rt_num)
        except ValueError:
            raise argparse.ArgumentTypeError("Route target number must be an integer")
        if isinstance(asn, int) and not 1 <= rt_num < pow(2, 32):
            raise argparse.ArgumentTypeError("With ASN as integer, the route target number must be contained between 1 and %d" % pow(2, 32))
        elif isinstance(asn, unicode) and not 1 <= rt_num < pow(2, 16):
            raise argparse.ArgumentTypeError("With ASN as IPv4, the route target number must be contained between 1 and %d" % pow(2, 16))

        return 'target:%s' % value

class ZKCommand(Command):
    """Inherit from this class when a connection to the Zookeeper cluster
    is needed.

    This will add a `--zk-server` option to the command.

    The ZK client is available in `self.zk_client`.
    """
    zk_server = Option(help="zookeeper server (default: %(default)s)",
                       type=server_type,
                       default='localhost:2181')

    def __call__(self, zk_server=None, **kwargs):
        if not hasattr(self, 'zk_client'):
            handler = SequentialGeventHandler()
            self.zk_client = KazooClient(hosts=zk_server, timeout=1.0,
                                         handler=handler)
            try:
                self.zk_client.start()
            except handler.timeout_exception:
                raise CommandError("Can't connect to Zookeeper at %s" % zk_server)
        elif not self.zk_client.connected:
            self.zk_client.restart()

        super(ZKCommand, self).__call__(**kwargs)

class CheckCommand(Command):
    """Inherit from this class to add `--check` and `--dry-run` options.

    Options values are stored in `self.check` and `self.dry_run` (True or False).
    """
    check = Option('-c',
                   default=False,
                   action="store_true")
    dry_run = Option('-n',
                     default=False,
                     action="store_true",
                     help='run this command in dry-run mode')

    def __call__(self, dry_run=None, check=None, **kwargs):
        self.dry_run = dry_run
        self.check = check
        super(CheckCommand, self).__call__(**kwargs)

@add_metaclass(abc.ABCMeta)
class PathCommand(Command):
    """Inherit from this class for a command that expect a list of
    resource paths.

    This will add a `path` argument to the command (nargs=*).

    The selected resources are available in `self.resources`.
    """

    @abc.abstractproperty
    def resource_type(self):
        """Type of resource the command
        is about.
        """
        return "resource_type"

    def __new__(cls, *args):
        cmd = super(PathCommand, cls).__new__(cls, *args)
        cls.paths = Arg(nargs="*",
                        help="{type} path(s). "
                             "When no path is provided "
                             "all {type}s are considered.".format(type=cmd.resource_type),
                        metavar='path',
                        complete="resources:%s:path" % cmd.resource_type)
        return cmd

    def __call__(self, paths=None, **kwargs):
        if not paths:
            self.resources = Collection(self.resource_type, fetch=True)
        else:
            self.resources = expand_paths(paths,
                                          predicate=lambda r: r.type == self.resource_type)
        super(PathCommand, self).__call__(**kwargs)

@add_metaclass(abc.ABCMeta)
class ConfirmCommand(Command):
    """Inherit from this class for a command that expect a confirmation.

    This will add a --yes flag to skip the confirmation. `self.yes` can
    be used by the command to show the confirmation or not.
    """
    yes = Option('-y', action='store_true', help='Assume yes to all queries and do not prompt')

    @property
    def confirm_message(self):
        """Confirmation message to run the command
        """
        return "Are you sure ?"

    def __call__(self, yes=None, **kwargs):
        dry_run = getattr(self, 'dry_run', kwargs.get('dry_run', False))
        check = getattr(self, 'check', kwargs.get('check', False))
        if not yes and not dry_run and not check and \
                not continue_prompt(self.confirm_message):
            raise CommandError("Exiting.")
        super(ConfirmCommand, self).__call__(**kwargs)
<|endoftext|>


<commit_before>__version__ = '0.3.2'
<commit_msg>MIN This is not version 0.3.2 anymore<commit_after>__version__ = '0.3.2+git'
<|endoftext|>


<commit_before># -*- coding: utf-8-*-

"""
Author: Marco Dinacci <dev@dinointeractive.com>
Copyright © 2008-2009
"""
from mdlib.log import ConsoleLogger, DEBUG
logger = ConsoleLogger("data", DEBUG)

from mdlib.patterns import singleton
from mdlib.panda.physics import POM

from pandac.PandaModules import Point3, Quat, BitMask32, Vec4
from pandac.PandaModules import TexturePool
from pandac.PandaModules import NodePath, Filename, LoaderOptions, ActorNode
from direct.showbase.Loader import PandaLoader
from direct.directtools.DirectGeometry import LineNodePath

from UserDict import DictMixin

__all__ = ["KeyValueObject", "ResourceLoader", "GOM"]

def bitMaskToInt(bitmask):
    # [1:-1] to remove first white space and latest \n
    s = "".join(str(bitmask)[1:-1].split(" "))
    num = 0
    for c in s:
        if c is "1":
            num += 2**int(c)

    return num

# TODO move from here
class EntityType:
    NONE  = 0x0   # non renderable objects (triggers, lights, cameras etc..)
    STATIC = 0x1  # environments and level geometry
    ACTOR = 0x2   # things that have a physic geometry and eventually a body
    BACKGROUND = 0x3 # the background "behind" everything
    ALPHA = 0x4   # alpha objects
    PLAYER = 0x5 # player object

class ResourceLoader(object):
    """
    The ResourceLoader loads and cache resources from disk or network.
    A Resource can be a 3D model, a texture, a sound, an URL etc...
    """
    def __init__(self):
        self.loader = PandaLoader()

    def loadTexture(self, path):
        return TexturePool.loadTexture(path)

    def loadModel(self, path, scale=1, pos=None, **kwargs):
        """ SYNCHRONOUSLY load a model from disk """
        options = LoaderOptions()
        if kwargs.has_key("noCache"):
            noCache = kwargs["noCache"]
            if noCache:
                options.setFlags(options.getFlags() | LoaderOptions.LFNoCache)
            else:
                options.setFlags(options.getFlags() & ~LoaderOptions.LFNoCache)
        node = self.loader.loadSync(Filename(path), options)
        if node != None:
            model = NodePath(node)
        else:
            raise ModelNotFoundException()

        model.setScale(scale)

        if pos is not None:
            model.setPos(pos)

        return model

    def loadModelAndReparent(self, path, parentNode, scale=1, pos=None, noCache=False):
        np = self.loadModel(path, scale, pos, noCache=noCache)
        np.reparentTo(parentNode)

        return np

class ModelNotFoundException(Exception):
    def __init__(self, modelPath):
        super(ModelNotFoundException, self).__init__("Model %s not found" % modelPath)

class KeyValueObject(object, DictMixin):
    """
    Instance attributes of this class can be accessed either using the dict
    notation or using the attribute notation.
    Ex. data = {"a":1,"b":{"x":1,"y":2}} ("b" must be a kvo too !)
    >> kvo = keyValueObject(data)
    >> kvo.a
    1
    >> kvo["b"[
    {"x":1,"y":2}
    >> kvo.b["x"] = 3
    >> kvo["b"].x
    3
    """
    def __init__(self, data):
        self.__dict__ = {}
        self.__dict__.update(data)

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

    def __setitem__(self, key, value):
        self.__dict__[key] = value

    def __delitem__(self, item):
        del self.__dict__[item]

    def __str__(self):
        return self.__dict__.__str__()

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

    def setPropertyFromKeyPath(self, keypath, newValue):
        tokens = keypath.split(".")
        if len(tokens) > 1:
            prev = self[tokens[0]]
            for token in tokens[1:]:
                if token == tokens[-1]:
                    prev[token] = newValue
                else:
                    prev = prev.get(token)
        else:
            self[keypath] = newValue

class GameEntity(KeyValueObject):
    """
    GameEntity is the class that represents an object in the game.
    An object can be animated, like a ball, static, like a tree or even
    invisible, like a trigger.
    """
    def __init__(self, uid, data):
        super(GameEntity, self).__init__(data)
        self._uid = uid

    def __str__(self):
        return "%s (%d)" % (self.prettyName, self.UID)

    def update(self):
        if self.has_key("odephysics") and self.odephysics.has_key("geom"):
            # the position is updated by the physics manager
            pos = self.odephysics.geom.getPosition()
            self.render.nodepath.setPos(pos)

    def serialise(self):
        import copy

        attrs = copy.deepcopy(self)

        if self.has_key("render"):
            if self.render.has_key("nodepath"):
                attrs["render"]["nodepath"] = None
            if self.render.has_key("parentNode"):
                # as the nodepath is unpicklable, I store the UID instead
                # however, if the parent node is one of the root nodes defined
                # only in the scene, as the UID is empty I get rid of the property
                # Maybe the root node in the scene should be entities too...
                uid = self.render.parentNode.getTag("UID")
                if uid == '':
                    del attrs["render"]["parentNode"]
                else:
                    attrs["render"]["parentNode"] = int(uid)
            if self.render.has_key("color"):
                # color is stored as a Vec4 which causes pickling problems so
                # I store it as a 4-elements tuple
                c = self.render.color
                attrs["render"]["color"] = (c[0], c[1], c[2], c[3])

        if self.has_key("odephysics"):
            if self.odephysics.has_key("geom"):
                attrs["odephysics"]["geom"] = None
            if self.odephysics.has_key("collisionBitMask"):
                attrs["odephysics"]["collisionBitMask"] = \
                    bitMaskToInt(self.odephysics.collisionBitMask)
            if self.odephysics.has_key("categoryBitMask"):
                attrs["odephysics"]["categoryBitMask"] = \
                    bitMaskToInt(self.odephysics.categoryBitMask)

        return attrs

    UID = property(fget=lambda self: self._uid, fset=None, fdel=None)
    nodepath = property(fget=lambda self: self.render.nodepath)

def transformToKeyValue(data, result={}):
    """ Given a dict returns the inner dicts converted to KeyValueObject(s)"""
    if type(data) is dict:
        for k,v in data.items():
            if type(v) is dict:
                kvo = KeyValueObject(v)
                result[k] = kvo
                transformToKeyValue(v, result[k])
            else:
                result[k] = v
    elif isinstance(data, KeyValueObject):
        return data
    else:
        raise TypeError("transformToKeyValue requires dict or KeyValueObject")
    return KeyValueObject(result)

previous_id = 0
class GameEntityManager(object):
    """
    This class creates and manage the objects used in the game.
    Given a name, it creates a GameEntity instance with an unique id, it loads
    the assets files using the ResourceLoader and initialise all the object
    parameters using the other classes of the framework. For instance the
    geometry is calculated by the Physics engine.
    """
    def __init__(self):
        # assure there is only one instance of this class
        singleton(self)

        self._resourceLoader = ResourceLoader()

    def createEntityFromNodepath(self, nodepath, params):
        """
        Create a new entity given the input params and an already existing
        nodepath. The priority will be given to nodepath properties.
        """
        logger.debug("Creating a new game entity from nodepath")

        data = transformToKeyValue(params, {})

        dataIsValid = True #self._sanityCheckData(data)

        ge = None
        if dataIsValid:
            uid = self.generateUID()
            if data.has_key("_uid"):
                uid = data._uid
            # ge has a custom class
            if data.has_key("python") and data.python.has_key("clazz"):
                ge = data.python.clazz(uid, data)
            else:
                ge = GameEntity(uid, data)

            # now apply only properties that are not written in the egg file
            if ge.render.has_key("scale"):
                nodepath.setScale(ge.render.scale)

            # add tags
            if ge.render.has_key("tags"):
                for tagName, tagValue in ge.render.tags.items():
                    nodepath.setTag(tagName, tagValue)
            else:
                # TODO iterate over tags and fill ge.render.tags
                pass

            # set the position to the one owned by the node
            ge.position.x = nodepath.getX()
            ge.position.y = nodepath.getY()
            ge.position.z = nodepath.getZ()

            # install UID tag, unfortunately must obligatory be a string
            nodepath.setTag("UID", str(ge.UID))

            # finally install the nodepath in the game object
            ge.render.nodepath = nodepath

            if ge.has_key("odephysics") and ge.odephysics.has_key("geomType"):
                # replace bitmask numbers with appropriate objects
                catBitmask = BitMask32.bit(ge.odephysics.categoryBitMask)
                collBitmask = BitMask32.bit(ge.odephysics.collisionBitMask)
                ge.odephysics.categoryBitMask = catBitmask
                ge.odephysics.collisionBitMask = collBitmask

                # install geom property
                ge.odephysics.geom = POM.createGeomForObject(ge.odephysics,
                                              ge.position, ge.render.nodepath)

            logger.debug("Game object %s succesfully created" % ge)
        else:
            logger.warning("Data was not valid, cannot create game object")
            if logger.isEnabledFor(DEBUG):
                logger.debug("Data was: %s", data)

        return ge

    def createEntity(self, params):
        """
        Create a new entity given the input data and the additional keyword
        arguments passed as parameters. Data must conform to the schema in
        the objects module.
        """
        logger.debug("Creating a new game entity")

        # The empty dictionary is VERY important as otherwise it will be
        # cached with all the previous values !
        data = transformToKeyValue(params, {})

        dataIsValid = True #self._sanityCheckData(data)

        ge = None
        if dataIsValid:
            # check uid existance. As parentNode is serialised as an ID to a
            # referring node, it is important to recreate the entity with the
            # same id as when it was serialised.
            # FIXME Unfortunately this may cause UID collisions !!
            uid = self.generateUID()
            if data.has_key("_uid"):
                uid = data._uid
            # ge has a custom class
            if data.has_key("python") and data.python.has_key("clazz"):
                ge = data.python.clazz(uid, data)
            else:
                ge = GameEntity(uid, data)

            # setup nodepath
            if ge.render.has_key("modelPath"):
                nodepath = self._resourceLoader.loadModel(
                                        ge.render.modelPath,
                                        ge.render.scale,
                                        Point3(ge.position.x,
                                               ge.position.y,
                                               ge.position.z))
            else:
                nodepath = NodePath(ge.prettyName)
                if ge.render.has_key("scale"):
                    nodepath.setScale(ge.render.scale)
                if ge.has_key("position"):
                    nodepath.setPos(Point3(ge.position.x,
                                               ge.position.y,
                                               ge.position.z))
                    rot = ge.position.rotation
                    # TODO
                    #nodepath.setQuat(Quat(rot[0],rot[1],rot[2],rot[3]))

            # NOTE: attaching the node to the parent node is delegated to the
            # scene as there may not be enough informations here (gettin entity
            # from UID) to succesfully bind the entity to its parent.

            # reparent node if parentNode is set
            #if ge.render.has_key("parentNode") \
            #                    and ge.render.parentNode is not None:
            #    if type(ge.render.parentNode) is type: # a nodepath
            #        nodepath.reparentTo(ge.render.parentNode)

            if ge.render.has_key("texture"):
                tex = self._resourceLoader.loadTexture(ge.render.texture)
                nodepath.setTexture(tex)

            # got color ?
            if ge.render.has_key("color"):
                # needs conversion from tuple to Vec4
                c = ge.render.color
                nodepath.setColor(Vec4(c[0], c[1], c[2], c[3]))

            # add tags
            if ge.render.has_key("tags"):
                for tagName, tagValue in ge.render.tags.items():
                    nodepath.setTag(tagName, tagValue)
            else:
                ge.render.tags = {}

            # install UID tag, unfortunately must obligatory be a string
            nodepath.setTag("UID", str(ge.UID))

            # finally install the nodepath in the game object
            ge.render.nodepath = nodepath

            # if geometry is enabled, I need to create a geometry and eventually
            # a body for the game object. The task is delegated to the Physic
            # Object Manager
            if ge.has_key("odephysics") and ge.odephysics.has_key("geomType"):
                # replace bitmask numbers with appropriate objects
                catBitmask = BitMask32.bit(ge.odephysics.categoryBitMask)
                collBitmask = BitMask32.bit(ge.odephysics.collisionBitMask)
                ge.odephysics.categoryBitMask = catBitmask
                ge.odephysics.collisionBitMask = collBitmask

                # install geom property
                ge.odephysics.geom = POM.createGeomForObject(ge.odephysics, \
                                                      ge.position, ge.nodepath)

            logger.debug("Game object %s succesfully created" % ge)
        else:
            logger.warning("Data was not valid, cannot create game object")
            if logger.isEnabledFor(DEBUG):
                logger.debug("Data was: %s", data)

        return ge

    def generateUID(self):
        """ Generate a unique id for an object TODO improve me ... """
        global previous_id

        id = previous_id
        previous_id += 1

        return id

    def _sanityCheckData(self, data):
        isValid = True
        if data.has_key("python") and data.python.has_key("clazz"):
            isValid = isValid and isinstance(data.python.clazz, GameEntity)

        return isValid

GOM = GameEntityManager()
<commit_msg>ResourceLoader now inherits from base.loader<commit_after># -*- coding: utf-8-*-

"""
Author: Marco Dinacci <dev@dinointeractive.com>
Copyright © 2008-2009
"""
from mdlib.log import ConsoleLogger, DEBUG
logger = ConsoleLogger("data", DEBUG)

from mdlib.patterns import singleton
from mdlib.panda.physics import POM

from pandac.PandaModules import Point3, Quat, BitMask32, Vec4, Material
from pandac.PandaModules import NodePath, Filename, ActorNode
from direct.showbase.Loader import Loader
from direct.directtools.DirectGeometry import LineNodePath

from UserDict import DictMixin

__all__ = ["KeyValueObject", "ResourceLoader", "GOM"]

def bitMaskToInt(bitmask):
    # [1:-1] to remove first white space and latest \n
    s = "".join(str(bitmask)[1:-1].split(" "))
    num = 0
    for c in s:
        if c is "1":
            num += 2**int(c)

    return num

# TODO move from here
class EntityType:
    NONE  = 0x0   # non renderable objects (triggers, lights, cameras etc..)
    STATIC = 0x1  # environments and level geometry
    ACTOR = 0x2   # things that have a physic geometry and eventually a body
    BACKGROUND = 0x3 # the background "behind" everything
    ALPHA = 0x4   # alpha objects
    PLAYER = 0x5 # player object

class ResourceLoader(Loader):
    """
    The ResourceLoader loads and cache resources from disk or network.
    A Resource can be a 3D model, a texture, a sound, an URL etc...
    """

    def __init__(self):
        Loader.__init__(self, None)

    def loadModel(self, path, scale=1, pos=None, loaderOptions = None,
                  noCache = None,allowInstance = False, callback = None,
                  extraArgs = []):

        model = Loader.loadModel(self, path, loaderOptions, noCache,
                                 allowInstance, callback, extraArgs)

        if model is not None:
            model.setScale(scale)

            if pos is not None:
                model.setPos(pos)

        return model

    def loadModelAndReparent(self, path, parentNode, scale=1, pos=None,
                     loaderOptions = None, noCache = None,
                     allowInstance = False, callback = None, extraArgs = []):

        np = self.loadModel(path, scale, pos, loaderOptions, noCache,
                            allowInstance, callback, extraArgs)
        np.reparentTo(parentNode)

        return np

class ModelNotFoundException(Exception):
    def __init__(self, modelPath):
        super(ModelNotFoundException, self).__init__("Model %s not found" % modelPath)

class KeyValueObject(object, DictMixin):
    """
    Instance attributes of this class can be accessed either using the dict
    notation or using the attribute notation.
    Ex. data = {"a":1,"b":{"x":1,"y":2}} ("b" must be a kvo too !)
    >> kvo = keyValueObject(data)
    >> kvo.a
    1
    >> kvo["b"[
    {"x":1,"y":2}
    >> kvo.b["x"] = 3
    >> kvo["b"].x
    3
    """
    def __init__(self, data):
        self.__dict__ = {}
        self.__dict__.update(data)

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

    def __setitem__(self, key, value):
        self.__dict__[key] = value

    def __delitem__(self, item):
        del self.__dict__[item]

    def __str__(self):
        return self.__dict__.__str__()

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

    def setPropertyFromKeyPath(self, keypath, newValue):
        tokens = keypath.split(".")
        if len(tokens) > 1:
            prev = self[tokens[0]]
            for token in tokens[1:]:
                if token == tokens[-1]:
                    prev[token] = newValue
                else:
                    prev = prev.get(token)
        else:
            self[keypath] = newValue

class GameEntity(KeyValueObject):
    """
    GameEntity is the class that represents an object in the game.
    An object can be animated, like a ball, static, like a tree or even
    invisible, like a trigger.
    """
    def __init__(self, uid, data):
        super(GameEntity, self).__init__(data)
        self._uid = uid

    def __str__(self):
        return "%s (%d)" % (self.prettyName, self.UID)

    def update(self):
        if self.has_key("odephysics") and self.odephysics.has_key("geom"):
            # the position is updated by the physics manager
            pos = self.odephysics.geom.getPosition()
            self.render.nodepath.setPos(pos)

    def serialise(self):
        import copy

        attrs = copy.deepcopy(self)

        if self.has_key("render"):
            if self.render.has_key("nodepath"):
                attrs["render"]["nodepath"] = None
            if self.render.has_key("parentNode"):
                # as the nodepath is unpicklable, I store the UID instead
                # however, if the parent node is one of the root nodes defined
                # only in the scene, as the UID is empty I get rid of the property
                # Maybe the root node in the scene should be entities too...
                uid = self.render.parentNode.getTag("UID")
                if uid == '':
                    del attrs["render"]["parentNode"]
                else:
                    attrs["render"]["parentNode"] = int(uid)
            if self.render.has_key("color"):
                # color is stored as a Vec4 which causes pickling problems so
                # I store it as a 4-elements tuple
                c = self.render.color
                attrs["render"]["color"] = (c[0], c[1], c[2], c[3])

        if self.has_key("odephysics"):
            if self.odephysics.has_key("geom"):
                attrs["odephysics"]["geom"] = None
            if self.odephysics.has_key("collisionBitMask"):
                attrs["odephysics"]["collisionBitMask"] = \
                    bitMaskToInt(self.odephysics.collisionBitMask)
            if self.odephysics.has_key("categoryBitMask"):
                attrs["odephysics"]["categoryBitMask"] = \
                    bitMaskToInt(self.odephysics.categoryBitMask)

        return attrs

    UID = property(fget=lambda self: self._uid, fset=None, fdel=None)
    nodepath = property(fget=lambda self: self.render.nodepath)

def transformToKeyValue(data, result={}):
    """ Given a dict returns the inner dicts converted to KeyValueObject(s)"""
    if type(data) is dict:
        for k,v in data.items():
            if type(v) is dict:
                kvo = KeyValueObject(v)
                result[k] = kvo
                transformToKeyValue(v, result[k])
            else:
                result[k] = v
    elif isinstance(data, KeyValueObject):
        return data
    else:
        raise TypeError("transformToKeyValue requires dict or KeyValueObject")
    return KeyValueObject(result)

previous_id = 0
class GameEntityManager(object):
    """
    This class creates and manage the objects used in the game.
    Given a name, it creates a GameEntity instance with an unique id, it loads
    the assets files using the ResourceLoader and initialise all the object
    parameters using the other classes of the framework. For instance the
    geometry is calculated by the Physics engine.
    """

    cache_size = 20

    def __init__(self):
        # assure there is only one instance of this class
        singleton(self)

        self._resourceLoader = ResourceLoader()

        self._cache = {}

    def createEntityFromNodepath(self, nodepath, params):
        """
        Create a new entity given the input params and an already existing
        nodepath. The priority will be given to nodepath properties.
        """
        logger.debug("Creating a new game entity from nodepath")

        data = transformToKeyValue(params, {})

        dataIsValid = True #self._sanityCheckData(data)

        ge = None
        if dataIsValid:
            uid = self.generateUID()
            if data.has_key("_uid"):
                uid = data._uid
            # ge has a custom class
            if data.has_key("python") and data.python.has_key("clazz"):
                ge = data.python.clazz(uid, data)
            else:
                ge = GameEntity(uid, data)

            # now apply only properties that are not written in the egg file
            if ge.render.has_key("scale"):
                nodepath.setScale(ge.render.scale)

            # add tags
            if ge.render.has_key("tags"):
                for tagName, tagValue in ge.render.tags.items():
                    nodepath.setTag(tagName, tagValue)
            else:
                # TODO iterate over tags and fill ge.render.tags
                pass

            # set the position to the one owned by the node
            ge.position.x = nodepath.getX()
            ge.position.y = nodepath.getY()
            ge.position.z = nodepath.getZ()

            # install UID tag, unfortunately must obligatory be a string
            nodepath.setTag("UID", str(ge.UID))

            # finally install the nodepath in the game object
            ge.render.nodepath = nodepath

            if ge.has_key("odephysics") and ge.odephysics.has_key("geomType"):
                # replace bitmask numbers with appropriate objects
                catBitmask = BitMask32.bit(ge.odephysics.categoryBitMask)
                collBitmask = BitMask32.bit(ge.odephysics.collisionBitMask)
                ge.odephysics.categoryBitMask = catBitmask
                ge.odephysics.collisionBitMask = collBitmask

                # install geom property
                ge.odephysics.geom = POM.createGeomForObject(ge.odephysics,
                                              ge.position, ge.render.nodepath)

            logger.debug("Game object %s succesfully created" % ge)
        else:
            logger.warning("Data was not valid, cannot create game object")
            if logger.isEnabledFor(DEBUG):
                logger.debug("Data was: %s", data)

        return ge

    def getEntity(self, params):
        """
        Create a new entity given the input data and the additional keyword
        arguments passed as parameters. Data must conform to the schema in
        the objects module.
        """

        # returns immediately if the entity is in the cache
        name = params["prettyName"]
        if name in self._cache:
            logger.debug("Cache hit for %s" % name)

            ge = self._cache[name]
            if ge.render.nodepath.isEmpty():
                logger.debug("Cache invalid for %s, recreating object" % name)
            else:
                return self._cache[name]
        else:
            logger.debug("Cache miss for %s" % name)

        logger.debug("Creating game entity %s" % name)

        # The empty dictionary is VERY important as otherwise it will be
        # cached with all the previous values !
        data = transformToKeyValue(params, {})

        dataIsValid = True #self._sanityCheckData(data)

        ge = None
        if dataIsValid:
            # check uid existance. As parentNode is serialised as an ID to a
            # referring node, it is important to recreate the entity with the
            # same id as when it was serialised.
            # FIXME Unfortunately this may cause UID collisions !!
            uid = self.generateUID()
            if data.has_key("_uid"):
                uid = data._uid
            # ge has a custom class
            if data.has_key("python") and data.python.has_key("clazz"):
                ge = data.python.clazz(uid, data)
            else:
                ge = GameEntity(uid, data)

            # setup nodepath
            if ge.render.has_key("modelPath"):
                nodepath = self._resourceLoader.loadModel(
                                        ge.render.modelPath,
                                        ge.render.scale,
                                        Point3(ge.position.x,
                                               ge.position.y,
                                               ge.position.z))
            else:
                nodepath = NodePath(ge.prettyName)
                if ge.render.has_key("scale"):
                    nodepath.setScale(ge.render.scale)
                if ge.has_key("position"):
                    nodepath.setPos(Point3(ge.position.x,
                                               ge.position.y,
                                               ge.position.z))
                    rot = ge.position.rotation
                    # TODO
                    #nodepath.setQuat(Quat(rot[0],rot[1],rot[2],rot[3]))

            if ge.render.has_key("texture"):
                tex = self._resourceLoader.loadTexture(ge.render.texture)
                nodepath.setTexture(tex)

            # got color ?
            if ge.render.has_key("color"):
                # needs conversion from tuple to Vec4
                c = ge.render.color
                nodepath.setColor(Vec4(c[0], c[1], c[2], c[3]))

            # got material )
            if ge.render.has_key("material"):
                m = Material()
                m.setShininess(ge.render.material.shininess)
                m.setSpecular(ge.render.material.specular)

                nodepath.setMaterial(m,1)

            # add tags
            if ge.render.has_key("tags"):
                for tagName, tagValue in ge.render.tags.items():
                    nodepath.setTag(tagName, tagValue)
            else:
                ge.render.tags = {}

            # install UID tag, unfortunately must obligatory be a string
            nodepath.setTag("UID", str(ge.UID))

            # finally install the nodepath in the game object
            ge.render.nodepath = nodepath

            # if geometry is enabled, I need to create a geometry and eventually
            # a body for the game object. The task is delegated to the Physic
            # Object Manager
            if ge.has_key("odephysics") and ge.odephysics.has_key("geomType"):
                # replace bitmask numbers with appropriate objects
                catBitmask = BitMask32.bit(ge.odephysics.categoryBitMask)
                collBitmask = BitMask32.bit(ge.odephysics.collisionBitMask)
                ge.odephysics.categoryBitMask = catBitmask
                ge.odephysics.collisionBitMask = collBitmask

                # install geom property
                ge.odephysics.geom = POM.createGeomForObject(ge.odephysics, \
                                                      ge.position, ge.nodepath)

            logger.debug("Game object %s succesfully created" % ge)
        else:
            logger.warning("Data was not valid, cannot create game object")
            if logger.isEnabledFor(DEBUG):
                logger.debug("Data was: %s", data)

        logger.debug("Caching entity: %s" % params["prettyName"])
        if len(self._cache) == self.cache_size:
            first = self._cache.keys()[0]
            logger.debug("Cache full, popping %s" % first)
            self._cache.pop(first)
        self._cache[params["prettyName"]] = ge

        return ge

    def generateUID(self):
        """ Generate a unique id for an object TODO improve me ... """
        global previous_id

        id = previous_id
        previous_id += 1

        return id

    def _sanityCheckData(self, data):
        isValid = True
        if data.has_key("python") and data.python.has_key("clazz"):
            isValid = isValid and isinstance(data.python.clazz, GameEntity)

        return isValid

GOM = GameEntityManager()
<|endoftext|>


<commit_before>import sys
import logging

from website.app import setup_django
setup_django()

from scripts import utils as script_utils
from website.search.elastic_search import client, NOT_ANALYZED_PROPERTY, ENGLISH_ANALYZER_PROPERTY
from website.settings import ELASTIC_INDEX as INDEX

logger = logging.getLogger(__name__)

def main(dry=True):
    doc_type = 'collectionSubmission'
    mapping = {
        'properties': {
            'collectedType': NOT_ANALYZED_PROPERTY,
            'subjects': NOT_ANALYZED_PROPERTY,
            'status': NOT_ANALYZED_PROPERTY,
            'provider': NOT_ANALYZED_PROPERTY,
            'abstract': ENGLISH_ANALYZER_PROPERTY
        }
    }
    res = client().indices.put_mapping(index=INDEX, doc_type=doc_type, body=mapping, ignore=[400, 404])
    logger.info('{}'.format(res))

if __name__ == '__main__':
    dry = '--dry' in sys.argv
    if not dry:
        script_utils.add_file_logger(logger, __file__)
    main(dry=dry)
<commit_msg>Remove script<commit_after><|endoftext|>


<commit_before>"""Phase induced amplitude apodisation (PIAA) is the technique of apodising a pupil
without loss, so that the beam better matches e.g. a coronagraph or a fiber input.
This module contains a collection of routines to help with PIAA calculations

e.g.:

(r_surface,surface1,surface2,r_slope,slope_1,slope_2) = piaa.s_annulus_gauss(2.0, 0.35, 0.01)
plot(r_surface, surface1)
plot(r_surface, surface2)
"""

import numpy as np
from scipy import integrate

def ds_annulus_gauss(r, s, alpha, r0):
    """An annulus morphing into a (truncated) Gaussian. Only
    the first slope is given. The equations are:
    I_1 = exp(-alpha(r+s)**2) / (pi/alpha [1-exp(-alpha)])
    I_0 = 1.0 / [pi (1-r_0^2)] for r0<r<1

    With a second radial co-ordinate u, we have:
    u = r + s
    s'(r) = [ I_0 * x / I_1 * y ]  -  1

    The second slope is found directly
    from interpolation. For a second radial co-ordinate u and a
    second slope v, we have:

    v(u) = -s(r), with
    u(r) = r + s(r)
    """

    return (1 - np.exp(-alpha)) * np.exp(alpha*(r + s)**2) * r / alpha / (1-r0**2) / (r+s) - 1

def s_annulus_gauss(alpha,r0,frac_to_focus,delta=1e-2,dt=1e-3, n_med=1.5, thickness=15.0, radius_in_mm=1.0, real_heights=True):
    """Everything is scaled so that a slope of 1 unit corresponds to an angle
    of 1 radius per length. To convert to real units of slope, this has to be multiplied
    by (radius/(thickness / n_med)). To convert to real heights, we then have to divide
    by (n-1).

    Parameters
    ----------
    alpha: The
    frac_to_focus: float
        The fractional distance of the distance between surfaces and the first surface
        to focus
    delta: float
        As the slope can not be infinite... delta describes
        the radius of the annular dead zone in the second pupil.
    n_med: float
        Refractive index of the medium. This is used to compensate for the glass
        (and give extra power to the new optic) as well as to estimate the height.

    Returns
    -------
    (r_surface,surface1,surface2,r_slope,slope_1,slope_2): float arrays
        um is the radial
    """
    aa = integrate.ode(ds_annulus_gauss).set_integrator('vode', method='bdf', with_jacobian=False)
    aa.set_initial_value(-r0 + delta, r0).set_f_params( alpha,r0 )
    rs = np.array([])
    ss = np.array([])
    while aa.successful() and aa.t < 1.0:
        aa.integrate(aa.t+dt)
        rs = np.append(rs,aa.t)
        ss = np.append(ss,aa.y)
    us = np.linspace(0,1,1.0/dt + 1)
    vs = np.interp(us,rs + ss,-ss,left=np.nan, right=0)

    #Now fill in the remaining slopes in a smooth way.
    ss_full = np.interp(us,rs,ss, left=np.nan, right=0)
    wbad = np.where(vs != vs)[0]
    wgood = np.where(vs == vs)[0]
    vs[wbad] = vs[wgood[0]]*np.arange(wgood[0])/wgood[0]
    wbad = np.where(ss_full != ss_full)[0]
    wgood = np.where(ss_full == ss_full)[0]
    ss_full[wbad] = ss_full[wgood[0]]*np.arange(wgood[0])/wgood[0]

    #Inserting a glass section frac_to_focus thick changes the target
    #focus position behind the second surface from
    # (1.0-frac_to_focus)/frac_to_focus to
    #(1.0-frac_to_focus/frac_to_focus) + (n_med-1)
    power1 = frac_to_focus/(1.0-frac_to_focus) - 1.0/( (1.0-frac_to_focus)/frac_to_focus + (n_med-1.0))

    #Also integrate the slopes.
    s1 = integrate.cumtrapz(ss_full + frac_to_focus*us,us)
    s2 = integrate.cumtrapz(vs - (frac_to_focus/(1-frac_to_focus) + power1)*us,us)

    #Convert to real heights
    s1 *= radius_in_mm/(thickness/n_med) / (n_med - 1)
    s2 *= radius_in_mm/(thickness/n_med) / (n_med - 1)

    return 0.5*(us[1:]+us[:-1]), s1,s2,us,ss_full, vs<commit_msg>Added a Fresnel diffraction example to the piaa module.<commit_after>"""Phase induced amplitude apodisation (PIAA) is the technique of apodising a pupil
without loss, so that the beam better matches e.g. a coronagraph or a fiber input.
This module contains a collection of routines to help with PIAA calculations

e.g.:

(r_surface,surface1,surface2,r_slope,slope_1,slope_2) = piaa.s_annulus_gauss(2.0, 0.35, 0.01)
plot(r_surface, surface1)
plot(r_surface, surface2)
"""

import numpy as np
import optics
import pdb
from scipy import integrate
import matplotlib.pyplot as plt

def ds_annulus_gauss(r, s, alpha, r0):
    """An annulus morphing into a (truncated) Gaussian. Only
    the first slope is given. The equations are:

    I_1(u) = exp(-alpha * u**2) / (pi/alpha [1-exp(-alpha)])
    I_0(r) = 1.0 / [pi (1-r_0^2)] for r0<r<1

    With a second radial co-ordinate u, we have for a "slope" s:

    u = r + s
    s'(r) = [ I_0 * r / I_1 * (r + s) ]  -  1

    The second slope is found directly
    from interpolation. For a second radial co-ordinate u and a
    second slope v, we have:

    v(u) = -s(r), with
    u(r) = r + s(r)

    Parameters
    ----------
    alpha: float
        In the formula for I_1 - the exponent of the Gaussian intensity.
    r0: float
        The fractional radius of the telescope "secondary obstruction" in the
        annulus. e.g. for a 40% obstruction, this would be 0.4.
    r: float
        The radial co-ordinate of the input wavefront.
    s: float
        The slope of the wavefront at r.

    Returns
    -------
    ds: float
        ds/dr at the input co-ordinate r

    """

    return (1 - np.exp(-alpha)) * np.exp(alpha*(r + s)**2) * r / alpha / (1-r0**2) / (r+s) - 1

def s_annulus_gauss(alpha,r0,frac_to_focus,delta=1e-2,dt=1e-3, n_med=1.5, thickness=15.0, radius_in_mm=1.0, real_heights=True):
    """Everything is scaled so that a slope of 1 unit corresponds to an angle
    of 1 radius per length. To convert to real units of slope, this has to be multiplied
    by (radius/(thickness / n_med)). To convert to real heights, we then have to divide
    by (n-1).

    Parameters
    ----------
    alpha: float
        The
    frac_to_focus: float
        The fraction (2nd surface z coord - 1st surface z coord)/
                     (focus z coord       - 1st surface z coord)
    delta: float
        As the slope can not be infinite... delta describes
        the radius of the annular dead zone in the second pupil.
    n_med: float
        Refractive index of the medium. This is used to compensate for the glass
        (and give extra power to the new optic) as well as to estimate the height.

    Returns
    -------
    (r_surface,surface1,surface2,r_slope,slope_1,slope_2): float arrays
        um is the radial
    """
    #Set up an "integrator" to integrate the differential equation defined by ds_annulus_gauss
    s_integrator = integrate.ode(ds_annulus_gauss).set_integrator('vode', method='bdf', with_jacobian=False)
    #At the inner edge of the annulus (r = r0), the slope is -r0 + delta.
    s_integrator.set_initial_value(-r0 + delta, r0).set_f_params( alpha,r0 )
    #By Mike's conventional shorthand, rs is and array of r value, and
    #ss is an array of s values.
    rs = np.array([])
    ss = np.array([])
    while s_integrator.successful() and s_integrator.t < 1.0:
        s_integrator.integrate(s_integrator.t+dt)
        rs = np.append(rs,s_integrator.t)
        ss = np.append(ss,s_integrator.y)
    us = np.linspace(0,1,1.0/dt + 1)
    #The slope at the 2nd survace is "v", which is something that un-does
    #the slope "s".
    vs = np.interp(us,rs + ss,-ss,left=np.nan, right=0)

    #Now fill in the remaining slopes in a smooth way.
    ss_full = np.interp(us,rs,ss, left=np.nan, right=0)
    wbad = np.where(vs != vs)[0]
    wgood = np.where(vs == vs)[0]
    vs[wbad] = vs[wgood[0]]*np.arange(wgood[0])/wgood[0]
    wbad = np.where(ss_full != ss_full)[0]
    wgood = np.where(ss_full == ss_full)[0]
    ss_full[wbad] = ss_full[wgood[0]]*np.arange(wgood[0])/wgood[0]

    #Inserting a glass section frac_to_focus thick changes the target
    #focus position behind the second surface from
    # (1.0-frac_to_focus)/frac_to_focus to
    #(1.0-frac_to_focus/frac_to_focus) + (n_med-1)
    power1 = frac_to_focus/(1.0-frac_to_focus) - 1.0/( (1.0-frac_to_focus)/frac_to_focus + (n_med-1.0))

    #Also integrate the slopes.
    s1 = integrate.cumtrapz(ss_full + frac_to_focus*us,us)
    s2 = integrate.cumtrapz(vs - (frac_to_focus/(1-frac_to_focus) + power1)*us,us)

    #Convert to real heights
    s1 *= radius_in_mm/(thickness/n_med) / (n_med - 1)
    s2 *= radius_in_mm/(thickness/n_med) / (n_med - 1)

    return 0.5*(us[1:]+us[:-1]), s1,s2,us,ss_full, vs

def annulus_gauss_fresnel(alpha,r0,ignore_piaa=False):
    """Use Fresnel diffraction to verify that s_annulus_gauss does roughly the right thing.
    NB Parameters are HARDWIRED so this is for TESTING only.

    Adam's notes 2 though 6. Note that to apply an atmosphere, you need to go:
    electric_field = exp(1j * wf),
    with the wf normalised so that it is in radians of phase. See web pages:
    http://www.ing.iac.es/Astronomy/development/hap/dimm.html
    http://community.dur.ac.uk/james.osborn/thesis/thesisse3.html

    e.g. Scale a wavefront like this (with "seeing" in radians):
    r_0 = seeing / 0.98 / wavelength
    wf_in_radians = kmf(STUFF) * np.sqrt(6.88*(pixel_size/r_0)**(5.0/3.0))
    """
    n_med = 1.5
    thickness = 15.0

    wavelength_in_mm = 0.5/1000.0
    #Simulate something not going to focus.
    frac_to_focus = 1e-6

    r_surface,surface1,surface2,dummy1,dummy2,dummy3 = s_annulus_gauss(alpha,r0,frac_to_focus,n_med=n_med,thickness=thickness)
    dx = 5.0/1000.0           #Single pixel sampling in mm
    pupil_diam = 2.0           #Diameter in mm.
    secondary_obstruction = 0.8 #Obstruction in mm

    npix = 1024

    x_in_pix = np.arange(npix,dtype=int)
    xy = np.meshgrid(x_in_pix,x_in_pix)
    r = np.sqrt((xy[0] - npix/2.0)**2 + (xy[1] - npix/2.0)**2)
    r_normalised = r*dx/(pupil_diam/2) #R going from 0 to 1
    #Fill in the lens heights. The negative sign in front of "surface1" and
    #"surface2" are needed to match the fresnel diffraction sign convention.
    piaa_lens1 = np.zeros( (npix,npix) )
    piaa_lens2 = np.zeros( (npix,npix) )
    piaa_lens1[xy] = np.interp(r_normalised, r_surface, -surface1)
    piaa_lens2[xy] = np.interp(r_normalised, r_surface, -surface2)

    #Convert these to radians of phase at 500nm. As the surface of a lens was returned,
    #we have to multiply by (n-1) to get the wavefront.
    piaa_lens1 *= 2*np.pi/wavelength_in_mm*(n_med - 1.0)
    piaa_lens2 *= 2*np.pi/wavelength_in_mm*(n_med - 1.0)

    #For a test, try to ignore the PIAA and see what happens.
    if (ignore_piaa):
        piaa_lens1 *= 0
        piaa_lens2 *= 0

    #Compute the input electric fields...
    efield_in = optics.circle(npix,pupil_diam/dx) - optics.circle(npix,secondary_obstruction/dx)
    efield_lens1 = efield_in * np.exp(1j * piaa_lens1)
    #Propagate...
    efield_lens2_before = optics.fresnel(efield_lens1, dx, thickness/n_med, wavelength_in_mm)
    efield_lens2_after = efield_lens2_before * np.exp(1j * piaa_lens2)

    #Show the electric field at the second lens
    plt.clf()
    plt.imshow(np.abs(efield_lens2_before)**0.5 )
    plt.draw()
    plt.title('E field at 2nd lens (click to continue)')
    dummy = plt.ginput(1)

    #Propagate to a distant focus...
    efield_lens2_to_focus = efield_lens2_after*optics.curved_wf(npix,dx,200,wavelength_in_mm)
    efield_200mm_focus = optics.fresnel(efield_lens2_to_focus, dx, 200, wavelength_in_mm)
    plt.imshow(np.abs(efield_200mm_focus))

<|endoftext|>


<commit_before># vim: tabstop=4 shiftwidth=4 softtabstop=4
#
# Copyright 2013 New Dream Network, LLC (DreamHost)
#
#    Licensed under the Apache License, Version 2.0 (the "License"); you may
#    not use this file except in compliance with the License. You may obtain
#    a copy of the License at
#
#         http://www.apache.org/licenses/LICENSE-2.0
#
#    Unless required by applicable law or agreed to in writing, software
#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
#    License for the specific language governing permissions and limitations
#    under the License.
#
# @author: Mark McClain, DreamHost

import contextlib
import mock
from oslo.config import cfg

from neutron.services.loadbalancer.drivers.haproxy import agent
from neutron.tests import base

class TestLbaasService(base.BaseTestCase):
    def setUp(self):
        super(TestLbaasService, self).setUp()
        self.addCleanup(cfg.CONF.reset)

    def test_start(self):
        with mock.patch.object(
            agent.rpc_service.Service, 'start'
        ) as mock_start:

            mgr = mock.Mock()
            agent_service = agent.LbaasAgentService('host', 'topic', mgr)
            agent_service.start()

            self.assertTrue(mock_start.called)

    def test_main(self):
        logging_str = 'neutron.agent.common.config.setup_logging'
        with contextlib.nested(
            mock.patch(logging_str),
            mock.patch.object(agent.service, 'launch'),
            mock.patch.object(agent, 'eventlet'),
            mock.patch('sys.argv'),
            mock.patch.object(agent.manager, 'LbaasAgentManager'),
            mock.patch.object(cfg.CONF, 'register_opts')
        ) as (mock_logging, mock_launch, mock_eventlet, sys_argv, mgr_cls, ro):
            agent.main()

            self.assertTrue(mock_eventlet.monkey_patch.called)
            mock_launch.assert_called_once_with(mock.ANY)
<commit_msg>Fix NoSuchOptError in lbaas agent test<commit_after># vim: tabstop=4 shiftwidth=4 softtabstop=4
#
# Copyright 2013 New Dream Network, LLC (DreamHost)
#
#    Licensed under the Apache License, Version 2.0 (the "License"); you may
#    not use this file except in compliance with the License. You may obtain
#    a copy of the License at
#
#         http://www.apache.org/licenses/LICENSE-2.0
#
#    Unless required by applicable law or agreed to in writing, software
#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
#    License for the specific language governing permissions and limitations
#    under the License.
#
# @author: Mark McClain, DreamHost

import contextlib
import mock
from oslo.config import cfg

from neutron.services.loadbalancer.drivers.haproxy import agent
from neutron.tests import base

class TestLbaasService(base.BaseTestCase):
    def setUp(self):
        super(TestLbaasService, self).setUp()
        self.addCleanup(cfg.CONF.reset)

    def test_start(self):
        with mock.patch.object(
            agent.rpc_service.Service, 'start'
        ) as mock_start:

            mgr = mock.Mock()
            cfg.CONF.periodic_interval = mock.Mock(return_value=10)
            agent_service = agent.LbaasAgentService('host', 'topic', mgr)
            agent_service.start()

            self.assertTrue(mock_start.called)

    def test_main(self):
        logging_str = 'neutron.agent.common.config.setup_logging'
        with contextlib.nested(
            mock.patch(logging_str),
            mock.patch.object(agent.service, 'launch'),
            mock.patch.object(agent, 'eventlet'),
            mock.patch('sys.argv'),
            mock.patch.object(agent.manager, 'LbaasAgentManager'),
            mock.patch.object(cfg.CONF, 'register_opts')
        ) as (mock_logging, mock_launch, mock_eventlet, sys_argv, mgr_cls, ro):
            agent.main()

            self.assertTrue(mock_eventlet.monkey_patch.called)
            mock_launch.assert_called_once_with(mock.ANY)
<|endoftext|>


<commit_before>import xbmc

from devhelper import pykodi
from devhelper import quickjson

from devhelper.pykodi import log

import mediatypes
import providers

MODE_AUTO = 'auto'
MODE_GUI = 'gui'

class ArtworkProcessor(object):
    def __init__(self):
        self.monitor = xbmc.Monitor()
        self.dryrun = True
        self.language = None
        self.autolanguages = None

    def process_allartwork(self, mediatype):
        pass

    def process_itemartwork(self, mediatype, dbid, mode):
        mediaitem = None
        if mediatype == mediatypes.TVSHOW:
            mediaitem = quickjson.get_tvshow_details(dbid, ['art', 'imdbnumber'])
        elif mediatype == mediatypes.MOVIE:
            mediaitem = quickjson.get_movie_details(dbid, ['art', 'imdbnumber'])
        elif mediatype == mediatypes.EPISODE:
            mediaitem = quickjson.get_episode_details(dbid, ['art', 'uniqueid'])
        if not mediaitem:
            return
        mediaitem = self.process_mediaitem(mediaitem, mode)
        if not mediaitem:
            return
        if mode == MODE_GUI:
            pass # prompt with 'available art'
        else:
            mediaitem['selected art'] = self.get_top_missing_art(mediaitem)

        self.add_art_to_library(mediaitem)

    def process_medialist(self, medialist):
        resultlist = []
        self.setlanguages()
        for mediaitem in medialist:
            mediaitem = self._process_mediaitem(mediaitem, MODE_AUTO)
            if not mediaitem:
                continue
            mediaitem['selected art'] = self.get_top_missing_art(mediaitem)
            resultlist.append(mediaitem)
            self.add_art_to_library(mediaitem)
            if self.monitor.waitForAbort(0.5):
                break
        return resultlist

    def process_mediaitem(self, mediaitem, mode):
        self.setlanguages()
        return self._process_mediaitem(mediaitem, mode)

    def _process_mediaitem(self, mediaitem, mode):
        if 'tvshowid' in mediaitem:
            mediaitem['mediatype'] = mediatypes.TVSHOW
        elif 'movieid' in mediaitem:
            mediaitem['mediatype'] = mediatypes.MOVIE
        elif 'episodeid' in mediaitem:
            mediaitem['mediatype'] = mediatypes.EPISODE
        else:
            log('Not sure what mediatype this is.')
            log(mediaitem)
            return
        self.add_additional_iteminfo(mediaitem)
        if mode == MODE_AUTO:
            if next(self.list_missing_arttypes(mediaitem), False):
                mediaitem['available art'] = self.get_available_artwork(mediaitem)
        else:
            mediaitem['available art'] = self.get_available_artwork(mediaitem)
        return mediaitem

    def setlanguages(self):
        self.language = pykodi.get_language(xbmc.ISO_639_1)
        if self.language == 'en':
            self.autolanguages = (self.language, '')
        else:
            self.autolanguages = (self.language, 'en', '')

    def add_additional_iteminfo(self, mediaitem):
        if mediaitem['mediatype'] == mediatypes.TVSHOW:
            mediaitem['seasons'], art = self._get_seasons_artwork(quickjson.get_seasons(mediaitem['tvshowid']))
            mediaitem['art'].update(art)
        elif mediaitem['mediatype'] == mediatypes.EPISODE:
            mediaitem['imdbnumber'] = self._get_episodeid(mediaitem)

        return mediaitem

    def get_available_artwork(self, mediaitem):
        if mediaitem['mediatype'] not in (mediatypes.TVSHOW, mediatypes.MOVIE, mediatypes.EPISODE):
            return
        images = {}
        for provider in providers.get_providers()[mediaitem['mediatype']]:
            for arttype, artlist in provider.get_images(mediaitem['imdbnumber']).iteritems():
                if arttype not in images:
                    images[arttype] = []
                images[arttype].extend(artlist)
        for arttype, imagelist in images.iteritems():
            self.sort_images(arttype, imagelist)
        return images

    def sort_images(self, arttype, imagelist):
        # 1. Match the primary language, for everything but fanart
        # 2. Separate on status, like goofy images
        # 3. Rating
        # 4. Size
        imagelist.sort(key=lambda image: image['size'].sort, reverse=True)
        imagelist.sort(key=lambda image: image['rating'].sort, reverse=True)
        imagelist.sort(key=lambda image: image.get('status', providers.HAPPY_IMAGE).sort)
        if not arttype.endswith('fanart'):
            imagelist.sort(key=lambda image: (0 if image['language'] == self.language else 1, image['language']))

    def get_top_missing_art(self, mediaitem):
        if not mediaitem.get('available art'):
            return {}
        newartwork = {}
        for missingart in self.list_missing_arttypes(mediaitem):
            if missingart.startswith(mediatypes.SEASON):
                mediatype = mediatypes.SEASON
                artkey = missingart.rsplit('.', 1)[1]
            else:
                mediatype = mediaitem['mediatype']
                artkey = missingart
            if missingart not in mediaitem['available art']:
                continue
            if mediatypes.artinfo[mediatype][artkey]['multiselect']:
                existingurls = []
                existingartnames = []
                for art, url in mediaitem['art'].iteritems():
                    if art.startswith(missingart) and url:
                        existingurls.append(pykodi.unquoteimage(url))
                        existingartnames.append(art)

                missingartnames = []
                for i in range(0, mediatypes.artinfo[mediatype][artkey]['autolimit']):
                    multikey = '%s%s' % (artkey, i if i else '')
                    if multikey not in existingartnames:
                        missingartnames.append(multikey)

                newart = [art for art in mediaitem['available art'][missingart] if self._auto_filter(missingart, art, existingurls)]
                if not newart:
                    continue
                newartcount = 0
                for name in missingartnames:
                    if newartcount >= len(newart):
                        break
                    if name not in newartwork:
                        newartwork[name] = []
                    newartwork[name] = newart[newartcount]['url']
                    newartcount += 1
            else:
                newart = next((art for art in mediaitem['available art'][missingart] if self._auto_filter(missingart, art)), None)
                if newart:
                    newartwork[missingart] = newart['url']
        return newartwork

    def list_missing_arttypes(self, mediaitem):
        fullartinfo = mediatypes.artinfo[mediaitem['mediatype']]
        for arttype, artinfo in fullartinfo.iteritems():
            if not artinfo['autolimit']:
                continue
            elif artinfo['autolimit'] == 1:
                if arttype not in mediaitem['art'].keys():
                    yield arttype
            else:
                artcount = sum(1 for art in mediaitem['art'].keys() if art.startswith(arttype))
                if artcount < artinfo['autolimit']:
                    yield arttype

        if mediaitem['mediatype'] == mediatypes.TVSHOW:
            seasonartinfo = mediatypes.artinfo.get(mediatypes.SEASON)
            for season in mediaitem['seasons'].iteritems():
                for arttype, artinfo in seasonartinfo.iteritems():
                    arttype = '%s.%s.%s' % (mediatypes.SEASON, season[0], arttype)
                    if not artinfo['autolimit']:
                        continue
                    elif artinfo['autolimit'] == 1:
                        if arttype not in mediaitem['art'].keys():
                            yield arttype
                    else:
                        artcount = sum(1 for art in mediaitem['art'].keys() if art.startswith(arttype))
                        if artcount < artinfo['autolimit']:
                            yield arttype

    def _get_seasons_artwork(self, seasons):
        resultseasons = {}
        resultart = {}
        for season in seasons:
            resultseasons[season['season']] = season['seasonid']
            for arttype, url in season['art'].iteritems():
                if not arttype.startswith(('tvshow', 'season')):
                    resultart['%s.%s.%s' % (mediatypes.SEASON, season['season'], arttype)] = url
        return resultseasons, resultart

    def _get_episodeid(self, episode):
        if 'unknown' in episode['uniqueid']:
            return episode['uniqueid']['unknown']
        else:
            idsource, result = episode['uniqueid'].iteritems()[0] if episode['uniqueid'] else '', ''
            if result:
                # I don't know what this might be, I'm not even sure Kodi can do anything else at the moment, but just in case
                log("Didn't find 'unknown' uniqueid for episode, just picked the first, from '%s'." % idsource, xbmc.LOGINFO)
            else:
                log("Didn't find a uniqueid for episode '%s', can't look it up. I expect the ID from TheTVDB, which generally comes from the scraper." % episode['label'], xbmc.LOGINFO)
            return result

    def add_art_to_library(self, mediaitem):
        if mediaitem['mediatype'] == mediatypes.TVSHOW:
            seriesart = {}
            allseasonart = {}
            for arttype, url in mediaitem['selected art'].iteritems():
                if arttype.startswith(mediatypes.SEASON + '.'):
                    season, arttype = arttype.rsplit('.', 2)[1:3]
                    season = mediaitem['seasons'][int(season)]
                    if season not in allseasonart:
                        allseasonart[season] = {}
                    allseasonart[season][arttype] = url
                else:
                    seriesart[arttype] = url

            if self.dryrun:
                log((seriesart, allseasonart))
                return
            if seriesart:
                quickjson.set_tvshow_details(mediaitem['tvshowid'], art=seriesart)
            for seasonid, seasonart in allseasonart.iteritems():
                quickjson.set_season_details(seasonid, art=seasonart)

        elif mediaitem['mediatype'] == mediatypes.MOVIE:
            movieart = {arttype: url for arttype, url in mediaitem['selected art'].iteritems()}
            if self.dryrun:
                log(movieart)
                return
            if movieart:
                quickjson.set_movie_details(mediaitem['movieid'], art=movieart)

        elif mediaitem['mediatype'] == mediatypes.EPISODE:
            episodeart = {arttype: url for arttype, url in mediaitem['selected art'].iteritems()}
            if self.dryrun:
                log(episodeart)
                return
            if episodeart:
                quickjson.set_episode_details(mediaitem['episodeid'], art=episodeart)

    def _auto_filter(self, arttype, art, ignoreurls=()):
        if art['rating'].sort < 5:
            return False
        if arttype.endswith('fanart') and art['size'].sort < 1276:
            return False
        return art['language'] in self.autolanguages and art.get('status', providers.HAPPY_IMAGE) == providers.HAPPY_IMAGE and art['url'] not in ignoreurls
<commit_msg>Check language against None rather than ''<commit_after>import xbmc

from devhelper import pykodi
from devhelper import quickjson

from devhelper.pykodi import log

import mediatypes
import providers

MODE_AUTO = 'auto'
MODE_GUI = 'gui'

class ArtworkProcessor(object):
    def __init__(self):
        self.monitor = xbmc.Monitor()
        self.dryrun = True
        self.language = None
        self.autolanguages = None

    def process_allartwork(self, mediatype):
        pass

    def process_itemartwork(self, mediatype, dbid, mode):
        mediaitem = None
        if mediatype == mediatypes.TVSHOW:
            mediaitem = quickjson.get_tvshow_details(dbid, ['art', 'imdbnumber'])
        elif mediatype == mediatypes.MOVIE:
            mediaitem = quickjson.get_movie_details(dbid, ['art', 'imdbnumber'])
        elif mediatype == mediatypes.EPISODE:
            mediaitem = quickjson.get_episode_details(dbid, ['art', 'uniqueid'])
        if not mediaitem:
            return
        mediaitem = self.process_mediaitem(mediaitem, mode)
        if not mediaitem:
            return
        if mode == MODE_GUI:
            pass # prompt with 'available art'
        else:
            mediaitem['selected art'] = self.get_top_missing_art(mediaitem)

        self.add_art_to_library(mediaitem)

    def process_medialist(self, medialist):
        resultlist = []
        self.setlanguages()
        for mediaitem in medialist:
            mediaitem = self._process_mediaitem(mediaitem, MODE_AUTO)
            if not mediaitem:
                continue
            mediaitem['selected art'] = self.get_top_missing_art(mediaitem)
            resultlist.append(mediaitem)
            self.add_art_to_library(mediaitem)
            if self.monitor.waitForAbort(0.5):
                break
        return resultlist

    def process_mediaitem(self, mediaitem, mode):
        self.setlanguages()
        return self._process_mediaitem(mediaitem, mode)

    def _process_mediaitem(self, mediaitem, mode):
        if 'tvshowid' in mediaitem:
            mediaitem['mediatype'] = mediatypes.TVSHOW
        elif 'movieid' in mediaitem:
            mediaitem['mediatype'] = mediatypes.MOVIE
        elif 'episodeid' in mediaitem:
            mediaitem['mediatype'] = mediatypes.EPISODE
        else:
            log('Not sure what mediatype this is.')
            log(mediaitem)
            return
        self.add_additional_iteminfo(mediaitem)
        if mode == MODE_AUTO:
            if next(self.list_missing_arttypes(mediaitem), False):
                mediaitem['available art'] = self.get_available_artwork(mediaitem)
        else:
            mediaitem['available art'] = self.get_available_artwork(mediaitem)
        return mediaitem

    def setlanguages(self):
        self.language = pykodi.get_language(xbmc.ISO_639_1)
        if self.language == 'en':
            self.autolanguages = (self.language, None)
        else:
            self.autolanguages = (self.language, 'en', None)

    def add_additional_iteminfo(self, mediaitem):
        if mediaitem['mediatype'] == mediatypes.TVSHOW:
            mediaitem['seasons'], art = self._get_seasons_artwork(quickjson.get_seasons(mediaitem['tvshowid']))
            mediaitem['art'].update(art)
        elif mediaitem['mediatype'] == mediatypes.EPISODE:
            mediaitem['imdbnumber'] = self._get_episodeid(mediaitem)

        return mediaitem

    def get_available_artwork(self, mediaitem):
        if mediaitem['mediatype'] not in (mediatypes.TVSHOW, mediatypes.MOVIE, mediatypes.EPISODE):
            return
        images = {}
        for provider in providers.get_providers()[mediaitem['mediatype']]:
            for arttype, artlist in provider.get_images(mediaitem['imdbnumber']).iteritems():
                if arttype not in images:
                    images[arttype] = []
                images[arttype].extend(artlist)
        for arttype, imagelist in images.iteritems():
            self.sort_images(arttype, imagelist)
        return images

    def sort_images(self, arttype, imagelist):
        # 1. Match the primary language, for everything but fanart
        # 2. Separate on status, like goofy images
        # 3. Rating
        # 4. Size
        imagelist.sort(key=lambda image: image['size'].sort, reverse=True)
        imagelist.sort(key=lambda image: image['rating'].sort, reverse=True)
        imagelist.sort(key=lambda image: image.get('status', providers.HAPPY_IMAGE).sort)
        if not arttype.endswith('fanart'):
            imagelist.sort(key=lambda image: (0 if image['language'] == self.language else 1, image['language']))

    def get_top_missing_art(self, mediaitem):
        if not mediaitem.get('available art'):
            return {}
        newartwork = {}
        for missingart in self.list_missing_arttypes(mediaitem):
            if missingart.startswith(mediatypes.SEASON):
                mediatype = mediatypes.SEASON
                artkey = missingart.rsplit('.', 1)[1]
            else:
                mediatype = mediaitem['mediatype']
                artkey = missingart
            if missingart not in mediaitem['available art']:
                continue
            if mediatypes.artinfo[mediatype][artkey]['multiselect']:
                existingurls = []
                existingartnames = []
                for art, url in mediaitem['art'].iteritems():
                    if art.startswith(missingart) and url:
                        existingurls.append(pykodi.unquoteimage(url))
                        existingartnames.append(art)

                missingartnames = []
                for i in range(0, mediatypes.artinfo[mediatype][artkey]['autolimit']):
                    multikey = '%s%s' % (artkey, i if i else '')
                    if multikey not in existingartnames:
                        missingartnames.append(multikey)

                newart = [art for art in mediaitem['available art'][missingart] if self._auto_filter(missingart, art, existingurls)]
                if not newart:
                    continue
                newartcount = 0
                for name in missingartnames:
                    if newartcount >= len(newart):
                        break
                    if name not in newartwork:
                        newartwork[name] = []
                    newartwork[name] = newart[newartcount]['url']
                    newartcount += 1
            else:
                newart = next((art for art in mediaitem['available art'][missingart] if self._auto_filter(missingart, art)), None)
                if newart:
                    newartwork[missingart] = newart['url']
        return newartwork

    def list_missing_arttypes(self, mediaitem):
        fullartinfo = mediatypes.artinfo[mediaitem['mediatype']]
        for arttype, artinfo in fullartinfo.iteritems():
            if not artinfo['autolimit']:
                continue
            elif artinfo['autolimit'] == 1:
                if arttype not in mediaitem['art'].keys():
                    yield arttype
            else:
                artcount = sum(1 for art in mediaitem['art'].keys() if art.startswith(arttype))
                if artcount < artinfo['autolimit']:
                    yield arttype

        if mediaitem['mediatype'] == mediatypes.TVSHOW:
            seasonartinfo = mediatypes.artinfo.get(mediatypes.SEASON)
            for season in mediaitem['seasons'].iteritems():
                for arttype, artinfo in seasonartinfo.iteritems():
                    arttype = '%s.%s.%s' % (mediatypes.SEASON, season[0], arttype)
                    if not artinfo['autolimit']:
                        continue
                    elif artinfo['autolimit'] == 1:
                        if arttype not in mediaitem['art'].keys():
                            yield arttype
                    else:
                        artcount = sum(1 for art in mediaitem['art'].keys() if art.startswith(arttype))
                        if artcount < artinfo['autolimit']:
                            yield arttype

    def _get_seasons_artwork(self, seasons):
        resultseasons = {}
        resultart = {}
        for season in seasons:
            resultseasons[season['season']] = season['seasonid']
            for arttype, url in season['art'].iteritems():
                if not arttype.startswith(('tvshow', 'season')):
                    resultart['%s.%s.%s' % (mediatypes.SEASON, season['season'], arttype)] = url
        return resultseasons, resultart

    def _get_episodeid(self, episode):
        if 'unknown' in episode['uniqueid']:
            return episode['uniqueid']['unknown']
        else:
            idsource, result = episode['uniqueid'].iteritems()[0] if episode['uniqueid'] else '', ''
            if result:
                # I don't know what this might be, I'm not even sure Kodi can do anything else at the moment, but just in case
                log("Didn't find 'unknown' uniqueid for episode, just picked the first, from '%s'." % idsource, xbmc.LOGINFO)
            else:
                log("Didn't find a uniqueid for episode '%s', can't look it up. I expect the ID from TheTVDB, which generally comes from the scraper." % episode['label'], xbmc.LOGINFO)
            return result

    def add_art_to_library(self, mediaitem):
        if mediaitem['mediatype'] == mediatypes.TVSHOW:
            seriesart = {}
            allseasonart = {}
            for arttype, url in mediaitem['selected art'].iteritems():
                if arttype.startswith(mediatypes.SEASON + '.'):
                    season, arttype = arttype.rsplit('.', 2)[1:3]
                    season = mediaitem['seasons'][int(season)]
                    if season not in allseasonart:
                        allseasonart[season] = {}
                    allseasonart[season][arttype] = url
                else:
                    seriesart[arttype] = url

            if self.dryrun:
                log((seriesart, allseasonart))
                return
            if seriesart:
                quickjson.set_tvshow_details(mediaitem['tvshowid'], art=seriesart)
            for seasonid, seasonart in allseasonart.iteritems():
                quickjson.set_season_details(seasonid, art=seasonart)

        elif mediaitem['mediatype'] == mediatypes.MOVIE:
            movieart = {arttype: url for arttype, url in mediaitem['selected art'].iteritems()}
            if self.dryrun:
                log(movieart)
                return
            if movieart:
                quickjson.set_movie_details(mediaitem['movieid'], art=movieart)

        elif mediaitem['mediatype'] == mediatypes.EPISODE:
            episodeart = {arttype: url for arttype, url in mediaitem['selected art'].iteritems()}
            if self.dryrun:
                log(episodeart)
                return
            if episodeart:
                quickjson.set_episode_details(mediaitem['episodeid'], art=episodeart)

    def _auto_filter(self, arttype, art, ignoreurls=()):
        if art['rating'].sort < 5:
            return False
        if arttype.endswith('fanart') and art['size'].sort < 1276:
            return False
        return art['language'] in self.autolanguages and art.get('status', providers.HAPPY_IMAGE) == providers.HAPPY_IMAGE and art['url'] not in ignoreurls
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
from openerp import models, fields

class res_partner_country_code(models.Model):
    _inherit = 'res.partner'

    def get_country_name(self):
        email = self.env.context.get('default_email', False)
        if email:
            top_level_domain = email.split(".")[-1]
            country_name = self.env['res.country'].search([('code', '=', top_level_domain.upper())])[0]
            return country_name

    country_id = fields.Many2one('res.country', 'Country', ondelete='restrict', default=get_country_name)

<commit_msg>[FIX] delete non-changed attributes from field definition<commit_after># -*- coding: utf-8 -*-
from openerp import models, fields

class res_partner_country_code(models.Model):
    _inherit = 'res.partner'

    def get_country_name(self):
        email = self.env.context.get('default_email', False)
        if email:
            top_level_domain = email.split(".")[-1]
            if len(top_level_domain) == 2:
                country_name = self.env['res.country'].search([('code', '=', top_level_domain.upper())])[0]
                return country_name

    country_id = fields.Many2one(default=get_country_name)

<|endoftext|>


<commit_before>#!/usr/bin/env python
import os
import sys
import re
import subprocess
import time

import pygtk
import gtk
import gobject
pygtk.require('2.0')
gtk.gdk.threads_init()

IWCONFIG_PATH = '/sbin/iwconfig'

def matching_wifi_network(good_ssids=()):
    try:
        p = subprocess.Popen(IWCONFIG_PATH, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    except OSError, e:
        print "Problem calling iwconfig at %s: %r" % (IWCONFIG_PATH, e)
        return False
    comms = p.communicate()
    conn_data = comms[0]
    return any(('ESSID:"%s"' % ssid) in conn_data for ssid in good_ssids)

class Ping(object):
    UNKNOWN, DISCONNECTED, CONNECTED = range(3)
    icon_filename = {
        UNKNOWN: 'unknown.png',
        DISCONNECTED: 'disconnected.png',
        CONNECTED: 'connected.png',
    }

    def __init__(self):
        self.location = os.path.dirname(os.path.realpath(__file__))
        self.state = self.UNKNOWN
        self.update_icon()
        self.icon.set_tooltip("Waiting for data...")
        self.icon.set_visible(True)
        self.tick_interval = 5000 #number of ms between each poll
        self.down_timestamp = time.time()
        self.last_down_duration = 0 #secs

    def test_connection(self):
        p = subprocess.Popen(
            ('ping', '-c 1', '-n', '8.8.8.8'),
            stdout=subprocess.PIPE)
        stdout = p.communicate()[0]
        if not p.returncode:
            ptime = re.findall(r' (time=[\d.]+ ms)', stdout)
            if ptime:
                return ptime[0].replace('time', 'ping')
        return False

    def update_icon(self):
        fn = self.icon_filename[self.state]
        path = os.path.join(self.location, fn)
        assert os.path.exists(path), 'File not found: %s' % path
        if hasattr(self, 'icon'):
            self.icon.set_from_file(path)
        else:
            self.icon = gtk.status_icon_new_from_file(path)

    def update(self):
        """This method is called everytime a tick interval occurs"""
        res = self.test_connection()
        if res:
            # if moving from DIS to CONNECTED, store how long connection was down
            if self.state == self.DISCONNECTED:
                self.last_down_duration = time.time()-self.down_timestamp

            self.state = self.CONNECTED

            # don't show downtime length if it was more than 5 mins ago
            if time.time()-self.down_timestamp > 5*60:
                self.down_timestamp = 0

            if self.last_down_duration:
                res += ' (last downtime lasted=%.0f secs)' % self.last_down_duration
            self.icon.set_tooltip(res)
            print res
        else:
            # if moving from CONN to DISCONNECTED, store timestamp of loss
            if self.state == self.CONNECTED:
                self.down_timestamp = time.time()

            self.state = self.DISCONNECTED

            print 'Net Not Found'
            self.icon.set_tooltip('Lost %.0f secs ago' % (time.time()-self.down_timestamp))

        self.update_icon()
        gobject.timeout_add(self.tick_interval, self.update)

    def main(self):
        # All PyGTK applications must have a gtk.main(). Control ends here
        # and waits for an event to occur (like a key press or mouse event).
        gobject.timeout_add(self.tick_interval, self.update)
        gtk.main()

if __name__ == "__main__":
    # TODO cope with moving between wifi networks while already running
    # TODO implement exponential backoff for states: conn, disconn, bad ssid.
    # TODO add a click handler to allow quiting
    if sys.argv[1:]:
        good_ssids = sys.argv[1:]
        if not matching_wifi_network(good_ssids):
            print "Not on a chosen wifi network so exiting"
            sys.exit()

    app = Ping()
    app.main()
<commit_msg>start of backoff code, method with doctest. not connected up yet<commit_after>#!/usr/bin/env python
import os
import sys
import re
import subprocess
import time

import pygtk
import gtk
import gobject
pygtk.require('2.0')
gtk.gdk.threads_init()

IWCONFIG_PATH = '/sbin/iwconfig'

def matching_wifi_network(good_ssids=()):
    try:
        p = subprocess.Popen(IWCONFIG_PATH, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    except OSError, e:
        print "Problem calling iwconfig at %s: %r" % (IWCONFIG_PATH, e)
        return False
    comms = p.communicate()
    conn_data = comms[0]
    return any(('ESSID:"%s"' % ssid) in conn_data for ssid in good_ssids)

class Ping(object):
    UNKNOWN, DISCONNECTED, CONNECTED = range(3)
    icon_filename = {
        UNKNOWN: 'unknown.png',
        DISCONNECTED: 'disconnected.png',
        CONNECTED: 'connected.png',
    }

    @staticmethod
    def backoff(t, direction, factor=2, mn=5*1000, mx=5*60*1000):
        """
        >>> p = Ping()
        >>> p.backoff(10*1000, 1)
        20000
        >>> p.backoff(10*1000, -1)
        5000
        >>> p.backoff(7*1000, -1)
        5000
        >>> p.backoff(3*60*1000, 1)
        300000
        """
        def within(x, mn, mx):
            return max(min(x, mx), mn)
        assert direction in (-1, 1), "Please suply a direction either -1 or 1, you supplied %s" % direction
        new_t = t * factor ** direction
        return int(within(new_t, mn, mx))

    def __init__(self, good_ssids=()):
        self.good_ssids = good_ssids
        self.location = os.path.dirname(os.path.realpath(__file__))
        self.state = self.UNKNOWN
        self.update_icon()
        self.icon.set_tooltip("Waiting for data...")
        self.icon.set_visible(True)
        self.tick_interval = 5000 #number of ms between each poll
        self.down_timestamp = time.time()
        self.last_down_duration = 0 #secs

    def test_connection(self):
        p = subprocess.Popen(
            ('ping', '-c 1', '-n', '8.8.8.8'),
            stdout=subprocess.PIPE)
        stdout = p.communicate()[0]
        if not p.returncode:
            ptime = re.findall(r' (time=[\d.]+ ms)', stdout)
            if ptime:
                return ptime[0].replace('time', 'ping')
        return False

    def update_icon(self):
        fn = self.icon_filename[self.state]
        path = os.path.join(self.location, fn)
        assert os.path.exists(path), 'File not found: %s' % path
        if hasattr(self, 'icon'):
            self.icon.set_from_file(path)
        else:
            self.icon = gtk.status_icon_new_from_file(path)

    def update(self):
        """This method is called everytime a tick interval occurs"""
        res = self.test_connection()
        if res:
            # if moving from DIS to CONNECTED, store how long connection was down
            if self.state == self.DISCONNECTED:
                self.last_down_duration = time.time()-self.down_timestamp

            self.state = self.CONNECTED

            # don't show downtime length if it was more than 5 mins ago
            if time.time()-self.down_timestamp > 5*60:
                self.down_timestamp = 0

            if self.last_down_duration:
                res += ' (last downtime lasted=%.0f secs)' % self.last_down_duration
            self.icon.set_tooltip(res)
            print res
        else:
            # if moving from CONN to DISCONNECTED, store timestamp of loss
            if self.state == self.CONNECTED:
                self.down_timestamp = time.time()

            self.state = self.DISCONNECTED

            print 'Net Not Found'
            self.icon.set_tooltip('Lost %.0f secs ago' % (time.time()-self.down_timestamp))

        self.update_icon()
        gobject.timeout_add(self.tick_interval, self.update)

    def main(self):
        # All PyGTK applications must have a gtk.main(). Control ends here
        # and waits for an event to occur (like a key press or mouse event).
        gobject.timeout_add(self.tick_interval, self.update)
        gtk.main()

if __name__ == "__main__":
    if sys.argv[1:2] == ['test']:
        import doctest
        doctest.testmod()
        sys.exit()
    # TODO cope with moving between wifi networks while already running
    # TODO implement exponential backoff for states: conn, disconn, bad ssid.
    # TODO add a click handler to allow quiting
    good_ssids = sys.argv[1:]

    app = Ping(good_ssids)
    app.main()
<|endoftext|>