<commit_before># vim: tabstop=4 shiftwidth=4 softtabstop=4

#    Copyright (C) 2012 Yahoo! Inc. All Rights Reserved.
#
#    Licensed under the Apache License, Version 2.0 (the "License"); you may
#    not use this file except in compliance with the License. You may obtain
#    a copy of the License at
#
#         http://www.apache.org/licenses/LICENSE-2.0
#
#    Unless required by applicable law or agreed to in writing, software
#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
#    License for the specific language governing permissions and limitations
#    under the License..

import abc
import collections
import copy
import functools
import os

from anvil import cfg
from anvil import colorizer
from anvil import env
from anvil import exceptions as excp
from anvil import importer
from anvil import log as logging
from anvil import packager
from anvil import passwords as pw
from anvil import phase
from anvil import settings
from anvil import shell as sh
from anvil import utils

LOG = logging.getLogger(__name__)

class PhaseFunctors(object):
    def __init__(self, start, run, end):
        self.start = start
        self.run = run
        self.end = end

class Action(object):
    __meta__ = abc.ABCMeta

    def __init__(self, name, distro, root_dir, **kwargs):
        self.distro = distro
        self.root_dir = root_dir
        self.name = name
        self.interpolator = cfg.YamlInterpolator(settings.COMPONENT_CONF_DIR)
        self.passwords = pw.ProxyPassword()
        self.password_files = [
            sh.joinpths(root_dir, 'passwords.yaml'),
        ]
        self.default_password_file = sh.joinpths(os.getcwd(), 'passwords.yaml')
        self.password_files.append(self.default_password_file)
        if kwargs.get('prompt_for_passwords'):
            self.passwords.resolvers.append(pw.InputPassword())
        self.passwords.resolvers.append(pw.RandomPassword())
        self.store_passwords = kwargs.get('store_passwords')

    def _establish_passwords(self):
        pw_read = []
        for fn in self.password_files:
            if sh.isfile(fn):
                self.passwords.cache.update(utils.load_yaml(fn))
                pw_read.append(fn)
        if pw_read:
            utils.log_iterable(pw_read,
                               header="Updated passwords to be used from %s files" % len(pw_read),
                               logger=LOG)

    @property
    def lookup_name(self):
        raise NotImplementedError()

    @abc.abstractmethod
    def _run(self, persona, component_order, instances):
        """Run the phases of processing for this action.

        Subclasses are expected to override this method to
        do something useful.
        """

    def _order_components(self, components):
        """Returns the components in the order they should be processed.
        """
        # Duplicate the list to avoid problems if it is updated later.
        return list(components)

    def _get_component_dirs(self, component):
        component_dir = sh.joinpths(self.root_dir, component)
        trace_dir = sh.joinpths(component_dir, 'traces')
        app_dir = sh.joinpths(component_dir, 'app')
        cfg_dir = sh.joinpths(component_dir, 'config')
        return {
            'app_dir': app_dir,
            'cfg_dir': cfg_dir,
            'component_dir': component_dir,
            'root_dir': self.root_dir,
            'trace_dir': trace_dir,
        }

    def _merge_options(self, name, base_opts, component_opts, persona_opts):
        opts = {}
        opts.update(self._get_component_dirs(name))
        if base_opts:
            opts.update(base_opts)
        if component_opts:
            opts.update(component_opts)
        if persona_opts:
            opts.update(persona_opts)
        return opts

    def _update_passwords(self):
        if not self.store_passwords:
            return
        if not self.passwords.cache:
            return
        who_update = []
        for fn in self.password_files:
            if sh.isfile(fn):
                contents = utils.load_yaml(fn)
                contents.update(self.passwords.cache)
                sh.write_file(fn, "# Updated on %s\n%s\n" % (utils.rcf8222date(), utils.prettify_yaml(contents)))
                who_update.append(fn)
        if not who_update:
            contents = {}
            contents.update(self.passwords.cache)
            sh.write_file(self.default_password_file,
                          "# Updated on %s\n%s\n" % (utils.rcf8222date(), utils.prettify_yaml(contents)))
            who_update.append(self.default_password_file)
        if who_update:
            utils.log_iterable(who_update,
                               header="Updated/created %s password files" % len(who_update),
                               logger=LOG)

    def _merge_subsystems(self, component_subsys, desired_subsys):
        joined_subsys = {}
        if not component_subsys:
            component_subsys = {}
        if not desired_subsys:
            return joined_subsys
        for subsys in desired_subsys:
            if subsys in component_subsys:
                joined_subsys[subsys] = component_subsys[subsys]
            else:
                joined_subsys[subsys] = {}
        return joined_subsys

    def _construct_siblings(self, siblings, kvs):
        my_siblings = {}
        for (action, cls_name) in siblings.items():
            cls = importer.import_entry_point(cls_name)
            my_siblings[action] = cls(**kvs)
        return my_siblings

    def _get_sibling_options(self, name, base_opts):
        opts = {}
        opts.update(base_opts)
        opts.update(self._get_component_dirs(name))
        return opts

    def _get_interp_options(self, name):
        base = {}
        for c in ['general', name]:
            base.update(self.interpolator.extract(c))
        return base

    def _construct_instances(self, persona):
        """
        Create component objects for each component in the persona.
        """
        persona_subsystems = persona.wanted_subsystems or {}
        persona_opts = persona.component_options or {}
        instances = {}
        package_registries = {}
        for c in persona.wanted_components:
            ((cls, distro_opts), siblings) = self.distro.extract_component(c, self.lookup_name)
            LOG.debug("Constructing component %r (%s)", c, utils.obj_name(cls))
            kvs = {}
            kvs['name'] = c
            kvs['package_registries'] = package_registries
            # First create its siblings with a 'minimal' set of options
            # This is done, so that they will work in a minimal state
            kvs['instances'] = {}
            kvs['subsystems'] = {}
            kvs['siblings'] = {}
            kvs['passwords'] = self.passwords
            kvs['distro'] = self.distro
            kvs['options'] = self._get_sibling_options(c, self._get_interp_options(c))
            LOG.debug("Constructing %s siblings:", c)
            utils.log_object(siblings, logger=LOG, level=logging.DEBUG)
            LOG.debug("Using params:")
            utils.log_object(kvs, logger=LOG, level=logging.DEBUG)
            siblings = self._construct_siblings(siblings, dict(kvs))
            # Now inject the full options
            kvs['instances'] = instances
            kvs['options'] = self._merge_options(c, self._get_interp_options(c),
                                                 distro_opts, (persona_opts.get(c) or {}))
            kvs['subsystems'] = self._merge_subsystems((distro_opts.pop('subsystems', None) or {}),
                                                       (persona_subsystems.get(c) or {}))
            kvs['siblings'] = siblings
            LOG.debug("Construction of %r params are:", c)
            utils.log_object(kvs, logger=LOG, level=logging.DEBUG)
            instances[c] = cls(**kvs)
        return instances

    def _verify_components(self, component_order, instances):
        LOG.info("Verifying that the components are ready to rock-n-roll.")
        for c in component_order:
            instances[c].verify()

    def _warm_components(self, component_order, instances):
        LOG.info("Warming up component configurations.")
        for c in component_order:
            instances[c].warm_configs()

    def _on_start(self, persona, component_order, instances):
        LOG.info("Booting up your components.")
        LOG.debug("Starting environment settings:")
        utils.log_object(env.get(), logger=LOG, level=logging.DEBUG, item_max_len=64)
        self._establish_passwords()
        self._verify_components(component_order, instances)
        self._warm_components(component_order, instances)
        self._update_passwords()

    def _write_exports(self, component_order, instances, filename):
        pass

    def _on_finish(self, persona, component_order, instances):
        LOG.info("Tearing down your components.")
        LOG.debug("Final environment settings:")
        utils.log_object(env.get(), logger=LOG, level=logging.DEBUG, item_max_len=64)
        self._write_exports(component_order, instances, filename="%s.rc" % (self.name))
        self._update_passwords()

    def _get_phase_directory(self, name=None):
        if not name:
            name = self.name
        return sh.joinpths(self.root_dir, "phases", name)

    def _get_phase_filename(self, phase_name, base_name=None):
        dir_path = self._get_phase_directory(base_name)
        if not sh.isdir(dir_path):
            sh.mkdirslist(dir_path)
        return sh.joinpths(dir_path, "%s.phases" % (phase_name.lower()))

    def _run_phase(self, functors, component_order, instances, phase_name):
        """
        Run a given 'functor' across all of the components, in order.
        """
        component_results = dict()
        if phase_name:
            phase_recorder = phase.PhaseRecorder(self._get_phase_filename(phase_name))
        else:
            phase_recorder = phase.NullPhaseRecorder()
        # Reset all activations
        for c in component_order:
            instance = instances[c]
            instance.activated = False
        # Run all components which have not been activated
        try:
            for c in component_order:
                instance = instances[c]
                if c in phase_recorder:
                    LOG.debug("Skipping phase named %r for component %r since it already happened.", phase_name, c)
                    instance.activated = True
                    component_results[c] = None
                else:
                    try:
                        result = None
                        with phase_recorder.mark(c):
                            if functors.start:
                                functors.start(instance)
                            if functors.run:
                                result = functors.run(instance)
                            if functors.end:
                                functors.end(instance, result)
                        component_results[instance] = result
                        instance.activated = True
                    except (excp.NoTraceException) as e:
                        pass
            self._on_completion(phase_name, component_results)
        finally:
            # Reset all activations
            for c in component_order:
                instance = instances[c]
                instance.activated = False
        return component_results

    def _get_opposite_stages(self, phase_name):
        return ('', [])

    def _on_completion(self, phase_name, results):
       (base_name, to_destroy) = self._get_opposite_stages(phase_name)
       for name in to_destroy:
           fn = self._get_phase_filename(name, base_name)
           if sh.isfile(fn):
               sh.unlink(fn)

    def run(self, persona):
        instances = self._construct_instances(persona)
        component_order = self._order_components(persona.wanted_components)
        LOG.info("Processing components for action %s.", colorizer.quote(self.name))
        utils.log_iterable(component_order,
                           header="Activating in the following order",
                           logger=LOG)
        self._on_start(persona, component_order, instances)
        self._run(persona, component_order, instances)
        self._on_finish(persona, component_order, instances)
        return component_order
<commit_msg>Make password file updating simpler.<commit_after># vim: tabstop=4 shiftwidth=4 softtabstop=4

#    Copyright (C) 2012 Yahoo! Inc. All Rights Reserved.
#
#    Licensed under the Apache License, Version 2.0 (the "License"); you may
#    not use this file except in compliance with the License. You may obtain
#    a copy of the License at
#
#         http://www.apache.org/licenses/LICENSE-2.0
#
#    Unless required by applicable law or agreed to in writing, software
#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
#    License for the specific language governing permissions and limitations
#    under the License..

import abc
import collections
import copy
import functools
import os

from anvil import cfg
from anvil import colorizer
from anvil import env
from anvil import exceptions as excp
from anvil import importer
from anvil import log as logging
from anvil import packager
from anvil import passwords as pw
from anvil import phase
from anvil import settings
from anvil import shell as sh
from anvil import utils

LOG = logging.getLogger(__name__)

class PhaseFunctors(object):
    def __init__(self, start, run, end):
        self.start = start
        self.run = run
        self.end = end

class Action(object):
    __meta__ = abc.ABCMeta

    def __init__(self, name, distro, root_dir, **kwargs):
        self.distro = distro
        self.root_dir = root_dir
        self.name = name
        self.interpolator = cfg.YamlInterpolator(settings.COMPONENT_CONF_DIR)
        self.passwords = pw.ProxyPassword()
        self.password_files = [
            sh.joinpths(root_dir, 'passwords.yaml'),
        ]
        self.default_password_file = sh.joinpths(os.getcwd(), 'passwords.yaml')
        self.password_files.append(self.default_password_file)
        if kwargs.get('prompt_for_passwords'):
            self.passwords.resolvers.append(pw.InputPassword())
        self.passwords.resolvers.append(pw.RandomPassword())
        self.store_passwords = kwargs.get('store_passwords')

    def _establish_passwords(self):
        pw_read = []
        for fn in self.password_files:
            if sh.isfile(fn):
                self.passwords.cache.update(utils.load_yaml(fn))
                pw_read.append(fn)
        if pw_read:
            utils.log_iterable(pw_read,
                               header="Updated passwords to be used from %s files" % len(pw_read),
                               logger=LOG)

    @property
    def lookup_name(self):
        raise NotImplementedError()

    @abc.abstractmethod
    def _run(self, persona, component_order, instances):
        """Run the phases of processing for this action.

        Subclasses are expected to override this method to
        do something useful.
        """

    def _order_components(self, components):
        """Returns the components in the order they should be processed.
        """
        # Duplicate the list to avoid problems if it is updated later.
        return list(components)

    def _get_component_dirs(self, component):
        component_dir = sh.joinpths(self.root_dir, component)
        trace_dir = sh.joinpths(component_dir, 'traces')
        app_dir = sh.joinpths(component_dir, 'app')
        cfg_dir = sh.joinpths(component_dir, 'config')
        return {
            'app_dir': app_dir,
            'cfg_dir': cfg_dir,
            'component_dir': component_dir,
            'root_dir': self.root_dir,
            'trace_dir': trace_dir,
        }

    def _merge_options(self, name, base_opts, component_opts, persona_opts):
        opts = {}
        opts.update(self._get_component_dirs(name))
        if base_opts:
            opts.update(base_opts)
        if component_opts:
            opts.update(component_opts)
        if persona_opts:
            opts.update(persona_opts)
        return opts

    def _update_passwords(self):
        if not self.store_passwords:
            return
        if not self.passwords.cache:
            return
        who_update = []
        for fn in self.password_files:
            if sh.isfile(fn):
                who_update.append(fn)
        if not who_update:
            who_update.append(self.default_password_file)
        for fn in who_update:
            if sh.isfile(fn):
                contents = utils.load_yaml(fn)
            else:
                contents = {}
            contents.update(self.passwords.cache)
            sh.write_file(fn, utils.add_header(fn, utils.prettify_yaml(contents)))
            who_update.append(fn)
        utils.log_iterable(who_update,
                           header="Updated/created %s password files" % len(who_update),
                           logger=LOG)

    def _merge_subsystems(self, component_subsys, desired_subsys):
        joined_subsys = {}
        if not component_subsys:
            component_subsys = {}
        if not desired_subsys:
            return joined_subsys
        for subsys in desired_subsys:
            if subsys in component_subsys:
                joined_subsys[subsys] = component_subsys[subsys]
            else:
                joined_subsys[subsys] = {}
        return joined_subsys

    def _construct_siblings(self, siblings, kvs):
        my_siblings = {}
        for (action, cls_name) in siblings.items():
            cls = importer.import_entry_point(cls_name)
            my_siblings[action] = cls(**kvs)
        return my_siblings

    def _get_sibling_options(self, name, base_opts):
        opts = {}
        opts.update(base_opts)
        opts.update(self._get_component_dirs(name))
        return opts

    def _get_interp_options(self, name):
        base = {}
        for c in ['general', name]:
            base.update(self.interpolator.extract(c))
        return base

    def _construct_instances(self, persona):
        """
        Create component objects for each component in the persona.
        """
        persona_subsystems = persona.wanted_subsystems or {}
        persona_opts = persona.component_options or {}
        instances = {}
        package_registries = {}
        for c in persona.wanted_components:
            ((cls, distro_opts), siblings) = self.distro.extract_component(c, self.lookup_name)
            LOG.debug("Constructing component %r (%s)", c, utils.obj_name(cls))
            kvs = {}
            kvs['name'] = c
            kvs['package_registries'] = package_registries
            # First create its siblings with a 'minimal' set of options
            # This is done, so that they will work in a minimal state
            kvs['instances'] = {}
            kvs['subsystems'] = {}
            kvs['siblings'] = {}
            kvs['passwords'] = self.passwords
            kvs['distro'] = self.distro
            kvs['options'] = self._get_sibling_options(c, self._get_interp_options(c))
            LOG.debug("Constructing %s siblings:", c)
            utils.log_object(siblings, logger=LOG, level=logging.DEBUG)
            LOG.debug("Using params:")
            utils.log_object(kvs, logger=LOG, level=logging.DEBUG)
            siblings = self._construct_siblings(siblings, dict(kvs))
            # Now inject the full options
            kvs['instances'] = instances
            kvs['options'] = self._merge_options(c, self._get_interp_options(c),
                                                 distro_opts, (persona_opts.get(c) or {}))
            kvs['subsystems'] = self._merge_subsystems((distro_opts.pop('subsystems', None) or {}),
                                                       (persona_subsystems.get(c) or {}))
            kvs['siblings'] = siblings
            LOG.debug("Construction of %r params are:", c)
            utils.log_object(kvs, logger=LOG, level=logging.DEBUG)
            instances[c] = cls(**kvs)
        return instances

    def _verify_components(self, component_order, instances):
        LOG.info("Verifying that the components are ready to rock-n-roll.")
        for c in component_order:
            instances[c].verify()

    def _warm_components(self, component_order, instances):
        LOG.info("Warming up component configurations.")
        for c in component_order:
            instances[c].warm_configs()

    def _on_start(self, persona, component_order, instances):
        LOG.info("Booting up your components.")
        LOG.debug("Starting environment settings:")
        utils.log_object(env.get(), logger=LOG, level=logging.DEBUG, item_max_len=64)
        self._establish_passwords()
        self._verify_components(component_order, instances)
        self._warm_components(component_order, instances)
        self._update_passwords()

    def _write_exports(self, component_order, instances, filename):
        pass

    def _on_finish(self, persona, component_order, instances):
        LOG.info("Tearing down your components.")
        LOG.debug("Final environment settings:")
        utils.log_object(env.get(), logger=LOG, level=logging.DEBUG, item_max_len=64)
        self._write_exports(component_order, instances, filename="%s.rc" % (self.name))
        self._update_passwords()

    def _get_phase_directory(self, name=None):
        if not name:
            name = self.name
        return sh.joinpths(self.root_dir, "phases", name)

    def _get_phase_filename(self, phase_name, base_name=None):
        dir_path = self._get_phase_directory(base_name)
        if not sh.isdir(dir_path):
            sh.mkdirslist(dir_path)
        return sh.joinpths(dir_path, "%s.phases" % (phase_name.lower()))

    def _run_phase(self, functors, component_order, instances, phase_name):
        """
        Run a given 'functor' across all of the components, in order.
        """
        component_results = dict()
        if phase_name:
            phase_recorder = phase.PhaseRecorder(self._get_phase_filename(phase_name))
        else:
            phase_recorder = phase.NullPhaseRecorder()
        # Reset all activations
        for c in component_order:
            instance = instances[c]
            instance.activated = False
        # Run all components which have not been activated
        try:
            for c in component_order:
                instance = instances[c]
                if c in phase_recorder:
                    LOG.debug("Skipping phase named %r for component %r since it already happened.", phase_name, c)
                    instance.activated = True
                    component_results[c] = None
                else:
                    try:
                        result = None
                        with phase_recorder.mark(c):
                            if functors.start:
                                functors.start(instance)
                            if functors.run:
                                result = functors.run(instance)
                            if functors.end:
                                functors.end(instance, result)
                        component_results[instance] = result
                        instance.activated = True
                    except (excp.NoTraceException) as e:
                        pass
            self._on_completion(phase_name, component_results)
        finally:
            # Reset all activations
            for c in component_order:
                instance = instances[c]
                instance.activated = False
        return component_results

    def _get_opposite_stages(self, phase_name):
        return ('', [])

    def _on_completion(self, phase_name, results):
       (base_name, to_destroy) = self._get_opposite_stages(phase_name)
       for name in to_destroy:
           fn = self._get_phase_filename(name, base_name)
           if sh.isfile(fn):
               sh.unlink(fn)

    def run(self, persona):
        instances = self._construct_instances(persona)
        component_order = self._order_components(persona.wanted_components)
        LOG.info("Processing components for action %s.", colorizer.quote(self.name))
        utils.log_iterable(component_order,
                           header="Activating in the following order",
                           logger=LOG)
        self._on_start(persona, component_order, instances)
        self._run(persona, component_order, instances)
        self._on_finish(persona, component_order, instances)
        return component_order
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
"""
Node Classes.

* :any:`Node`: a simple tree node
* :any:`NodeMixin`: extends any python class to a tree node.
"""

from __future__ import print_function
from .iterators import PreOrderIter

class NodeMixin(object):

    separator = "/"

    u"""
    The :any:`NodeMixin` class extends any Python class to a tree node.

    The only tree relevant information is the `parent` attribute.
    If `None` the :any:`NodeMixin` is root node.
    If set to another node, the :any:`NodeMixin` becomes the child of it.

    >>> from anytree import Node, RenderTree
    >>> class MyBaseClass(object):
    ...     foo = 4
    >>> class MyClass(MyBaseClass, NodeMixin):  # Add Node feature
    ...     def __init__(self, name, length, width, parent=None):
    ...         super(MyClass, self).__init__()
    ...         self.name = name
    ...         self.length = length
    ...         self.width = width
    ...         self.parent = parent

    >>> my0 = MyClass('my0', 0, 0)
    >>> my1 = MyClass('my1', 1, 0, parent=my0)
    >>> my2 = MyClass('my2', 0, 2, parent=my0)

    >>> for pre, _, node in RenderTree(my0):
    ...     treestr = u"%s%s" % (pre, node.name)
    ...     print(treestr.ljust(8), node.length, node.width)
    my0      0 0
    ├── my1  1 0
    └── my2  0 2
    """

    @property
    def parent(self):
        u"""
        Parent Node.

        On set, the node is detached from any previous parent node and attached
        to the new node.

        >>> from anytree import Node, RenderTree
        >>> udo = Node("Udo")
        >>> marc = Node("Marc")
        >>> lian = Node("Lian", parent=marc)
        >>> print(RenderTree(udo))
        Node('/Udo')
        >>> print(RenderTree(marc))
        Node('/Marc')
        └── Node('/Marc/Lian')

        **Attach**

        >>> marc.parent = udo
        >>> print(RenderTree(udo))
        Node('/Udo')
        └── Node('/Udo/Marc')
            └── Node('/Udo/Marc/Lian')

        **Detach**

        To make a node to a root node, just set this attribute to `None`.

        >>> marc.is_root
        False
        >>> marc.parent = None
        >>> marc.is_root
        True
        """
        try:
            return self._parent
        except AttributeError:
            return None

    @parent.setter
    def parent(self, value):
        try:
            parent = self._parent
        except AttributeError:
            parent = None
        if value is None:
            # make this node to root node
            self.__detach(parent)
        elif parent is not value:
            # change parent node
            self.__check_loop(value)
            self.__detach(parent)
            self.__attach(value)
        else:
            # keep parent
            pass
        # apply
        self._parent = value

    def __check_loop(self, node):
        if node is self:
            msg = "Cannot set parent. %r cannot be parent of itself."
            raise LoopError(msg % self)
        if self in node.path:
            msg = "Cannot set parent. %r is parent of %r."
            raise LoopError(msg % (self, node))

    def __detach(self, parent):
        if parent:
            self._pre_detach(parent)
            parentchildren = parent._children
            assert self in parentchildren, "Tree internal data is corrupt."
            parentchildren.remove(self)
            self._post_detach(parent)

    def __attach(self, parent):
        self._pre_attach(parent)
        parentchildren = parent._children
        assert self not in parentchildren, "Tree internal data is corrupt."
        parentchildren.append(self)
        self._post_attach(parent)

    @property
    def _children(self):
        try:
            return self.__children
        except AttributeError:
            self.__children = []
            return self.__children

    @property
    def children(self):
        """
        All child nodes.

        >>> dan = Node("Dan")
        >>> jet = Node("Jet", parent=dan)
        >>> jan = Node("Jan", parent=dan)
        >>> joe = Node("Joe", parent=dan)
        >>> dan.children
        (Node('/Dan/Jet'), Node('/Dan/Jan'), Node('/Dan/Joe'))
        """
        return tuple(self._children)

    @children.setter
    def children(self, children):
        """Function to simultaneously set all children of a node."""

        try:
            for child in children:
                break
        except TypeError:
            children = [children]

        self._pre_attach_children(children)

        old_children = self.children
        del self.children

        try:
            for child in children:
                assert isinstance(child, NodeMixin), "Failed to add non-node object."
                child.parent = self
            assert len(self.children) == len(children)
            self._post_attach_children(children)
        except LoopError as le:
            self.children = old_children
            raise LoopError(str(le))

    @children.deleter
    def children(self):
        """Function to detach all children of a node."""
        children = self.children
        self._pre_detach_children(children)
        for child in self.children:
            child.parent = None
        assert len(self.children) == 0
        self._post_detach_children(children)

    def _pre_detach_children(self, children):
        """Method call before detaching from `parent`."""
        pass

    def _post_detach_children(self, children):
        """Method call after detaching from `parent`."""
        pass

    def _pre_attach_children(self, children):
        """Method call before attaching to `parent`."""
        pass

    def _post_attach_children(self, children):
        """Method call after attaching to `parent`."""
        pass

    @property
    def path(self):
        """
        Path of this `Node`.

        >>> udo = Node("Udo")
        >>> marc = Node("Marc", parent=udo)
        >>> lian = Node("Lian", parent=marc)
        >>> udo.path
        (Node('/Udo'),)
        >>> marc.path
        (Node('/Udo'), Node('/Udo/Marc'))
        >>> lian.path
        (Node('/Udo'), Node('/Udo/Marc'), Node('/Udo/Marc/Lian'))
        """
        return self._path

    @property
    def _path(self):
        path = []
        node = self
        while node:
            path.insert(0, node)
            node = node.parent
        return tuple(path)

    @property
    def anchestors(self):
        """
        All parent nodes and their parent nodes.

        >>> udo = Node("Udo")
        >>> marc = Node("Marc", parent=udo)
        >>> lian = Node("Lian", parent=marc)
        >>> udo.anchestors
        ()
        >>> marc.anchestors
        (Node('/Udo'),)
        >>> lian.anchestors
        (Node('/Udo'), Node('/Udo/Marc'))
        """
        return self._path[:-1]

    @property
    def ancestors(self):
        """
        All parent nodes and their parent nodes.

        This is simply a fix for the `anchestors` typo.
        """
        return self.anchestors

    @property
    def descendants(self):
        """
        All child nodes and all their child nodes.

        >>> udo = Node("Udo")
        >>> marc = Node("Marc", parent=udo)
        >>> lian = Node("Lian", parent=marc)
        >>> loui = Node("Loui", parent=marc)
        >>> soe = Node("Soe", parent=lian)
        >>> udo.descendants
        (Node('/Udo/Marc'), Node('/Udo/Marc/Lian'), Node('/Udo/Marc/Lian/Soe'), Node('/Udo/Marc/Loui'))
        >>> marc.descendants
        (Node('/Udo/Marc/Lian'), Node('/Udo/Marc/Lian/Soe'), Node('/Udo/Marc/Loui'))
        >>> lian.descendants
        (Node('/Udo/Marc/Lian/Soe'),)
        """
        return tuple(PreOrderIter(self))[1:]

    @property
    def root(self):
        """
        Tree Root Node.

        >>> udo = Node("Udo")
        >>> marc = Node("Marc", parent=udo)
        >>> lian = Node("Lian", parent=marc)
        >>> udo.root
        Node('/Udo')
        >>> marc.root
        Node('/Udo')
        >>> lian.root
        Node('/Udo')
        """
        if self.parent:
            return self._path[0]
        else:
            return self

    @property
    def siblings(self):
        """
        Tuple of nodes with the same parent.

        >>> udo = Node("Udo")
        >>> marc = Node("Marc", parent=udo)
        >>> lian = Node("Lian", parent=marc)
        >>> loui = Node("Loui", parent=marc)
        >>> lazy = Node("Lazy", parent=marc)
        >>> udo.siblings
        ()
        >>> marc.siblings
        ()
        >>> lian.siblings
        (Node('/Udo/Marc/Loui'), Node('/Udo/Marc/Lazy'))
        >>> loui.siblings
        (Node('/Udo/Marc/Lian'), Node('/Udo/Marc/Lazy'))
        """
        parent = self.parent
        if parent is None:
            return tuple()
        else:
            return tuple([node for node in parent._children if node != self])

    @property
    def is_leaf(self):
        """
        `Node` has no childrean (External Node).

        >>> udo = Node("Udo")
        >>> marc = Node("Marc", parent=udo)
        >>> lian = Node("Lian", parent=marc)
        >>> udo.is_leaf
        False
        >>> marc.is_leaf
        False
        >>> lian.is_leaf
        True
        """
        return len(self._children) == 0

    @property
    def is_root(self):
        """
        `Node` is tree root.

        >>> udo = Node("Udo")
        >>> marc = Node("Marc", parent=udo)
        >>> lian = Node("Lian", parent=marc)
        >>> udo.is_root
        True
        >>> marc.is_root
        False
        >>> lian.is_root
        False
        """
        return self.parent is None

    @property
    def height(self):
        """
        Number of edges on the longest path to a leaf `Node`.

        >>> udo = Node("Udo")
        >>> marc = Node("Marc", parent=udo)
        >>> lian = Node("Lian", parent=marc)
        >>> udo.height
        2
        >>> marc.height
        1
        >>> lian.height
        0
        """
        if self._children:
            return max([child.height for child in self._children]) + 1
        else:
            return 0

    @property
    def depth(self):
        """
        Number of edges to the root `Node`.

        >>> udo = Node("Udo")
        >>> marc = Node("Marc", parent=udo)
        >>> lian = Node("Lian", parent=marc)
        >>> udo.depth
        0
        >>> marc.depth
        1
        >>> lian.depth
        2
        """
        return len(self._path) - 1

    def _pre_detach(self, parent):
        """Method call before detaching from `parent`."""
        pass

    def _post_detach(self, parent):
        """Method call after detaching from `parent`."""
        pass

    def _pre_attach(self, parent):
        """Method call before attaching to `parent`."""
        pass

    def _post_attach(self, parent):
        """Method call after attaching to `parent`."""
        pass

class Node(NodeMixin, object):

    def __init__(self, name, parent=None, **kwargs):
        u"""
        A simple tree node with a `name` and any `kwargs`.

        >>> from anytree import Node, RenderTree
        >>> root = Node("root")
        >>> s0 = Node("sub0", parent=root)
        >>> s0b = Node("sub0B", parent=s0, foo=4, bar=109)
        >>> s0a = Node("sub0A", parent=s0)
        >>> s1 = Node("sub1", parent=root)
        >>> s1a = Node("sub1A", parent=s1)
        >>> s1b = Node("sub1B", parent=s1, bar=8)
        >>> s1c = Node("sub1C", parent=s1)
        >>> s1ca = Node("sub1Ca", parent=s1c)

        >>> print(RenderTree(root))
        Node('/root')
        ├── Node('/root/sub0')
        │   ├── Node('/root/sub0/sub0B', bar=109, foo=4)
        │   └── Node('/root/sub0/sub0A')
        └── Node('/root/sub1')
            ├── Node('/root/sub1/sub1A')
            ├── Node('/root/sub1/sub1B', bar=8)
            └── Node('/root/sub1/sub1C')
                └── Node('/root/sub1/sub1C/sub1Ca')
        """
        self.name = name
        self.parent = parent
        self.__dict__.update(kwargs)

    @property
    def name(self):
        """Name."""
        return self._name

    @name.setter
    def name(self, value):
        self._name = value

    def __repr__(self):
        classname = self.__class__.__name__
        args = ["%r" % self.separator.join([""] + [str(node.name) for node in self.path])]
        for key, value in filter(lambda item: not item[0].startswith("_"),
                                 sorted(self.__dict__.items(),
                                        key=lambda item: item[0])):
            args.append("%s=%r" % (key, value))
        return "%s(%s)" % (classname, ", ".join(args))

class LoopError(RuntimeError):

    """Tree contains infinite loop."""

    pass
<commit_msg>Docstring changes<commit_after># -*- coding: utf-8 -*-
"""
Node Classes.

* :any:`Node`: a simple tree node
* :any:`NodeMixin`: extends any python class to a tree node.
"""

from __future__ import print_function
from .iterators import PreOrderIter

class NodeMixin(object):

    separator = "/"

    u"""
    The :any:`NodeMixin` class extends any Python class to a tree node.

    The only tree relevant information is the `parent` attribute.
    If `None` the :any:`NodeMixin` is root node.
    If set to another node, the :any:`NodeMixin` becomes the child of it.

    >>> from anytree import Node, RenderTree
    >>> class MyBaseClass(object):
    ...     foo = 4
    >>> class MyClass(MyBaseClass, NodeMixin):  # Add Node feature
    ...     def __init__(self, name, length, width, parent=None):
    ...         super(MyClass, self).__init__()
    ...         self.name = name
    ...         self.length = length
    ...         self.width = width
    ...         self.parent = parent

    >>> my0 = MyClass('my0', 0, 0)
    >>> my1 = MyClass('my1', 1, 0, parent=my0)
    >>> my2 = MyClass('my2', 0, 2, parent=my0)

    >>> for pre, _, node in RenderTree(my0):
    ...     treestr = u"%s%s" % (pre, node.name)
    ...     print(treestr.ljust(8), node.length, node.width)
    my0      0 0
    ├── my1  1 0
    └── my2  0 2
    """

    @property
    def parent(self):
        u"""
        Parent Node.

        On set, the node is detached from any previous parent node and attached
        to the new node.

        >>> from anytree import Node, RenderTree
        >>> udo = Node("Udo")
        >>> marc = Node("Marc")
        >>> lian = Node("Lian", parent=marc)
        >>> print(RenderTree(udo))
        Node('/Udo')
        >>> print(RenderTree(marc))
        Node('/Marc')
        └── Node('/Marc/Lian')

        **Attach**

        >>> marc.parent = udo
        >>> print(RenderTree(udo))
        Node('/Udo')
        └── Node('/Udo/Marc')
            └── Node('/Udo/Marc/Lian')

        **Detach**

        To make a node to a root node, just set this attribute to `None`.

        >>> marc.is_root
        False
        >>> marc.parent = None
        >>> marc.is_root
        True
        """
        try:
            return self._parent
        except AttributeError:
            return None

    @parent.setter
    def parent(self, value):
        try:
            parent = self._parent
        except AttributeError:
            parent = None
        if value is None:
            # make this node to root node
            self.__detach(parent)
        elif parent is not value:
            # change parent node
            self.__check_loop(value)
            self.__detach(parent)
            self.__attach(value)
        else:
            # keep parent
            pass
        # apply
        self._parent = value

    def __check_loop(self, node):
        if node is self:
            msg = "Cannot set parent. %r cannot be parent of itself."
            raise LoopError(msg % self)
        if self in node.path:
            msg = "Cannot set parent. %r is parent of %r."
            raise LoopError(msg % (self, node))

    def __detach(self, parent):
        if parent:
            self._pre_detach(parent)
            parentchildren = parent._children
            assert self in parentchildren, "Tree internal data is corrupt."
            parentchildren.remove(self)
            self._post_detach(parent)

    def __attach(self, parent):
        self._pre_attach(parent)
        parentchildren = parent._children
        assert self not in parentchildren, "Tree internal data is corrupt."
        parentchildren.append(self)
        self._post_attach(parent)

    @property
    def _children(self):
        try:
            return self.__children
        except AttributeError:
            self.__children = []
            return self.__children

    @property
    def children(self):
        """
        All child nodes.

        >>> dan = Node("Dan")
        >>> jet = Node("Jet", parent=dan)
        >>> jan = Node("Jan", parent=dan)
        >>> joe = Node("Joe", parent=dan)
        >>> dan.children
        (Node('/Dan/Jet'), Node('/Dan/Jan'), Node('/Dan/Joe'))
        """
        return tuple(self._children)

    @children.setter
    def children(self, children):
        """Function to simultaneously set all children of a node."""

        try:
            for child in children:
                break
        except TypeError:
            children = [children]

        self._pre_attach_children(children)

        old_children = self.children
        del self.children

        try:
            for child in children:
                assert isinstance(child, NodeMixin), "Failed to add non-node object."
                child.parent = self
            assert len(self.children) == len(children)
            self._post_attach_children(children)
        except LoopError as le:
            self.children = old_children
            raise LoopError(str(le))

    @children.deleter
    def children(self):
        """Function to detach all children of a node."""
        children = self.children
        self._pre_detach_children(children)
        for child in self.children:
            child.parent = None
        assert len(self.children) == 0
        self._post_detach_children(children)

    def _pre_detach_children(self, children):
        """Method call before detaching `children`."""
        pass

    def _post_detach_children(self, children):
        """Method call after detaching `children`."""
        pass

    def _pre_attach_children(self, children):
        """Method call before attaching `children`."""
        pass

    def _post_attach_children(self, children):
        """Method call after attaching `children`."""
        pass

    @property
    def path(self):
        """
        Path of this `Node`.

        >>> udo = Node("Udo")
        >>> marc = Node("Marc", parent=udo)
        >>> lian = Node("Lian", parent=marc)
        >>> udo.path
        (Node('/Udo'),)
        >>> marc.path
        (Node('/Udo'), Node('/Udo/Marc'))
        >>> lian.path
        (Node('/Udo'), Node('/Udo/Marc'), Node('/Udo/Marc/Lian'))
        """
        return self._path

    @property
    def _path(self):
        path = []
        node = self
        while node:
            path.insert(0, node)
            node = node.parent
        return tuple(path)

    @property
    def anchestors(self):
        """
        All parent nodes and their parent nodes.

        >>> udo = Node("Udo")
        >>> marc = Node("Marc", parent=udo)
        >>> lian = Node("Lian", parent=marc)
        >>> udo.anchestors
        ()
        >>> marc.anchestors
        (Node('/Udo'),)
        >>> lian.anchestors
        (Node('/Udo'), Node('/Udo/Marc'))
        """
        return self._path[:-1]

    @property
    def ancestors(self):
        """
        All parent nodes and their parent nodes.

        This is simply a fix for the `anchestors` typo.
        """
        return self.anchestors

    @property
    def descendants(self):
        """
        All child nodes and all their child nodes.

        >>> udo = Node("Udo")
        >>> marc = Node("Marc", parent=udo)
        >>> lian = Node("Lian", parent=marc)
        >>> loui = Node("Loui", parent=marc)
        >>> soe = Node("Soe", parent=lian)
        >>> udo.descendants
        (Node('/Udo/Marc'), Node('/Udo/Marc/Lian'), Node('/Udo/Marc/Lian/Soe'), Node('/Udo/Marc/Loui'))
        >>> marc.descendants
        (Node('/Udo/Marc/Lian'), Node('/Udo/Marc/Lian/Soe'), Node('/Udo/Marc/Loui'))
        >>> lian.descendants
        (Node('/Udo/Marc/Lian/Soe'),)
        """
        return tuple(PreOrderIter(self))[1:]

    @property
    def root(self):
        """
        Tree Root Node.

        >>> udo = Node("Udo")
        >>> marc = Node("Marc", parent=udo)
        >>> lian = Node("Lian", parent=marc)
        >>> udo.root
        Node('/Udo')
        >>> marc.root
        Node('/Udo')
        >>> lian.root
        Node('/Udo')
        """
        if self.parent:
            return self._path[0]
        else:
            return self

    @property
    def siblings(self):
        """
        Tuple of nodes with the same parent.

        >>> udo = Node("Udo")
        >>> marc = Node("Marc", parent=udo)
        >>> lian = Node("Lian", parent=marc)
        >>> loui = Node("Loui", parent=marc)
        >>> lazy = Node("Lazy", parent=marc)
        >>> udo.siblings
        ()
        >>> marc.siblings
        ()
        >>> lian.siblings
        (Node('/Udo/Marc/Loui'), Node('/Udo/Marc/Lazy'))
        >>> loui.siblings
        (Node('/Udo/Marc/Lian'), Node('/Udo/Marc/Lazy'))
        """
        parent = self.parent
        if parent is None:
            return tuple()
        else:
            return tuple([node for node in parent._children if node != self])

    @property
    def is_leaf(self):
        """
        `Node` has no childrean (External Node).

        >>> udo = Node("Udo")
        >>> marc = Node("Marc", parent=udo)
        >>> lian = Node("Lian", parent=marc)
        >>> udo.is_leaf
        False
        >>> marc.is_leaf
        False
        >>> lian.is_leaf
        True
        """
        return len(self._children) == 0

    @property
    def is_root(self):
        """
        `Node` is tree root.

        >>> udo = Node("Udo")
        >>> marc = Node("Marc", parent=udo)
        >>> lian = Node("Lian", parent=marc)
        >>> udo.is_root
        True
        >>> marc.is_root
        False
        >>> lian.is_root
        False
        """
        return self.parent is None

    @property
    def height(self):
        """
        Number of edges on the longest path to a leaf `Node`.

        >>> udo = Node("Udo")
        >>> marc = Node("Marc", parent=udo)
        >>> lian = Node("Lian", parent=marc)
        >>> udo.height
        2
        >>> marc.height
        1
        >>> lian.height
        0
        """
        if self._children:
            return max([child.height for child in self._children]) + 1
        else:
            return 0

    @property
    def depth(self):
        """
        Number of edges to the root `Node`.

        >>> udo = Node("Udo")
        >>> marc = Node("Marc", parent=udo)
        >>> lian = Node("Lian", parent=marc)
        >>> udo.depth
        0
        >>> marc.depth
        1
        >>> lian.depth
        2
        """
        return len(self._path) - 1

    def _pre_detach(self, parent):
        """Method call before detaching from `parent`."""
        pass

    def _post_detach(self, parent):
        """Method call after detaching from `parent`."""
        pass

    def _pre_attach(self, parent):
        """Method call before attaching to `parent`."""
        pass

    def _post_attach(self, parent):
        """Method call after attaching to `parent`."""
        pass

class Node(NodeMixin, object):

    def __init__(self, name, parent=None, **kwargs):
        u"""
        A simple tree node with a `name` and any `kwargs`.

        >>> from anytree import Node, RenderTree
        >>> root = Node("root")
        >>> s0 = Node("sub0", parent=root)
        >>> s0b = Node("sub0B", parent=s0, foo=4, bar=109)
        >>> s0a = Node("sub0A", parent=s0)
        >>> s1 = Node("sub1", parent=root)
        >>> s1a = Node("sub1A", parent=s1)
        >>> s1b = Node("sub1B", parent=s1, bar=8)
        >>> s1c = Node("sub1C", parent=s1)
        >>> s1ca = Node("sub1Ca", parent=s1c)

        >>> print(RenderTree(root))
        Node('/root')
        ├── Node('/root/sub0')
        │   ├── Node('/root/sub0/sub0B', bar=109, foo=4)
        │   └── Node('/root/sub0/sub0A')
        └── Node('/root/sub1')
            ├── Node('/root/sub1/sub1A')
            ├── Node('/root/sub1/sub1B', bar=8)
            └── Node('/root/sub1/sub1C')
                └── Node('/root/sub1/sub1C/sub1Ca')
        """
        self.name = name
        self.parent = parent
        self.__dict__.update(kwargs)

    @property
    def name(self):
        """Name."""
        return self._name

    @name.setter
    def name(self, value):
        self._name = value

    def __repr__(self):
        classname = self.__class__.__name__
        args = ["%r" % self.separator.join([""] + [str(node.name) for node in self.path])]
        for key, value in filter(lambda item: not item[0].startswith("_"),
                                 sorted(self.__dict__.items(),
                                        key=lambda item: item[0])):
            args.append("%s=%r" % (key, value))
        return "%s(%s)" % (classname, ", ".join(args))

class LoopError(RuntimeError):

    """Tree contains infinite loop."""

    pass
<|endoftext|>


<commit_before>#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Copyright 2019 GoPro Inc.
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements.  See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership.  The ASF licenses this file
# to you 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.
#

import pynodegl as ngl

def test_backend():
    viewer = ngl.Viewer()
    assert viewer.configure(backend=0x1234) < 0
    del viewer

def test_reconfigure():
    viewer = ngl.Viewer()
    assert viewer.configure(offscreen=1, width=16, height=16) == 0
    scene = ngl.Render(ngl.Quad())
    viewer.set_scene(scene)
    viewer.draw(0)
    assert viewer.configure(offscreen=1, width=16, height=16, samples=4) == 0
    # FIXME: errors should be raised by the draw call so we can assert here
    viewer.draw(1)
    del viewer

def test_ctx_ownership():
    viewer = ngl.Viewer()
    viewer2 = ngl.Viewer()
    assert viewer.configure(offscreen=1, width=16, height=16) == 0
    assert viewer2.configure(offscreen=1, width=16, height=16) == 0
    scene = ngl.Render(ngl.Quad())
    viewer.set_scene(scene)
    viewer.draw(0)
    assert viewer2.set_scene(scene) != 0
    viewer2.draw(0)
    del viewer
    del viewer2

def test_ctx_ownership_subgraph():
    for shared in (True, False):
        viewer = ngl.Viewer()
        viewer2 = ngl.Viewer()
        assert viewer.configure(offscreen=1, width=16, height=16) == 0
        assert viewer2.configure(offscreen=1, width=16, height=16) == 0
        quad = ngl.Quad()
        render1 = ngl.Render(quad)
        if not shared:
            quad = ngl.Quad()
        render2 = ngl.Render(quad)
        scene = ngl.Group([render1, render2])
        viewer.set_scene(render2)
        viewer.draw(0)
        assert viewer2.set_scene(scene) != 0
        viewer2.draw(0)
        del viewer
        del viewer2

if __name__ == '__main__':
    test_backend()
    test_reconfigure()
    test_ctx_ownership()
    test_ctx_ownership_subgraph()
<commit_msg>tests: add capture buffer lifetime test<commit_after>#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Copyright 2019 GoPro Inc.
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements.  See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership.  The ASF licenses this file
# to you 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.
#

import pynodegl as ngl

def test_backend():
    viewer = ngl.Viewer()
    assert viewer.configure(backend=0x1234) < 0
    del viewer

def test_reconfigure():
    viewer = ngl.Viewer()
    assert viewer.configure(offscreen=1, width=16, height=16) == 0
    scene = ngl.Render(ngl.Quad())
    viewer.set_scene(scene)
    viewer.draw(0)
    assert viewer.configure(offscreen=1, width=16, height=16, samples=4) == 0
    # FIXME: errors should be raised by the draw call so we can assert here
    viewer.draw(1)
    del viewer

def test_ctx_ownership():
    viewer = ngl.Viewer()
    viewer2 = ngl.Viewer()
    assert viewer.configure(offscreen=1, width=16, height=16) == 0
    assert viewer2.configure(offscreen=1, width=16, height=16) == 0
    scene = ngl.Render(ngl.Quad())
    viewer.set_scene(scene)
    viewer.draw(0)
    assert viewer2.set_scene(scene) != 0
    viewer2.draw(0)
    del viewer
    del viewer2

def test_ctx_ownership_subgraph():
    for shared in (True, False):
        viewer = ngl.Viewer()
        viewer2 = ngl.Viewer()
        assert viewer.configure(offscreen=1, width=16, height=16) == 0
        assert viewer2.configure(offscreen=1, width=16, height=16) == 0
        quad = ngl.Quad()
        render1 = ngl.Render(quad)
        if not shared:
            quad = ngl.Quad()
        render2 = ngl.Render(quad)
        scene = ngl.Group([render1, render2])
        viewer.set_scene(render2)
        viewer.draw(0)
        assert viewer2.set_scene(scene) != 0
        viewer2.draw(0)
        del viewer
        del viewer2

def test_capture_buffer_lifetime(width=1024, height=1024):
    capture_buffer = bytearray(width * height * 4)
    viewer = ngl.Viewer()
    assert viewer.configure(offscreen=1, width=width, height=height, capture_buffer=capture_buffer) == 0
    del capture_buffer
    scene = ngl.Render(ngl.Quad())
    viewer.set_scene(scene)
    viewer.draw(0)
    del viewer

if __name__ == '__main__':
    test_backend()
    test_reconfigure()
    test_ctx_ownership()
    test_ctx_ownership_subgraph()
    test_capture_buffer_lifetime()
<|endoftext|>


<commit_before>import os
import sys
import StringIO

from spec import eq_, skip, Spec, raises, ok_

from invoke.run import run
from invoke.parser import Parser, Context
from invoke.collection import Collection
from invoke.task import task
from invoke.exceptions import Failure

from _utils import support

class CLI(Spec):
    "Command-line behavior"
    def setup(self):
        os.chdir(support)
        sys.stdout, self.orig_stdout = StringIO.StringIO(), sys.stdout
        sys.stderr, self.orig_stderr = StringIO.StringIO(), sys.stderr
        self.result = run("invoke -c integration print_foo")

    def teardown(self):
        sys.stdout = self.orig_stdout
        sys.stderr = self.orig_stderr

    # Yo dogfood, I heard you like invoking
    def basic_invocation(self):
        eq_(self.result.stdout, "foo\n")

    def implicit_task_module(self):
        # Contains tasks.py
        os.chdir('implicit')
        # Doesn't specify --collection
        result = run("invoke foo")
        eq_(result.stdout, "Hm\n")

    def invocation_with_args(self):
        result = run("invoke -c integration print_name --name whatevs")
        eq_(result.stdout, "whatevs\n")

    def shorthand_binary_name(self):
        eq_(self.result.stdout, "foo\n")

class CLIParsing(Spec):
    """
    High level parsing tests
    """
    def setup(self):
        @task
        def mytask(mystring, s, boolean=False, b=False, v=False):
            pass
        @task
        def mytask2():
            pass
        @task
        def mytask3(mystring):
            pass
        c = Collection()
        c.add_task('mytask', mytask)
        c.add_task('mytask2', mytask2)
        c.add_task('mytask3', mytask3)
        self.c = c

    def _parser(self):
        return Parser(self.c.to_contexts())

    def _parse(self, argstr):
        return self._parser().parse_argv(argstr.split())

    def _compare(self, invoke, flagname, value):
        invoke = "mytask " + invoke
        result = self._parse(invoke)
        eq_(result.to_dict()['mytask'][flagname], value)

    def boolean_args(self):
        "mytask --boolean"
        self._compare("--boolean", 'boolean', True)

    def flag_then_space_then_value(self):
        "mytask --mystring foo"
        self._compare("--mystring foo", 'mystring', 'foo')

    def flag_then_equals_sign_then_value(self):
        "mytask --mystring=foo"
        self._compare("--mystring=foo", 'mystring', 'foo')

    def short_boolean_flag(self):
        "mytask -b"
        self._compare("-b", 'b', True)

    def short_flag_then_space_then_value(self):
        "mytask -s value"
        self._compare("-s value", 's', 'value')

    def short_flag_then_equals_sign_then_value(self):
        "mytask -s=value"
        self._compare("-s=value", 's', 'value')

    def short_flag_with_adjacent_value(self):
        "mytask -svalue"
        r = self._parse("mytask -svalue")
        eq_(r[0].args.s.value, 'value')

    def _flag_value_task(self, value):
        r = self._parse("mytask -s %s mytask2" % value)
        eq_(len(r), 2)
        eq_(r[0].name, 'mytask')
        eq_(r[0].args.s.value, value)
        eq_(r[1].name, 'mytask2')

    def flag_value_then_task(self):
        "mytask -s value mytask2"
        self._flag_value_task('value')

    def flag_value_same_as_task_name(self):
        "mytask -s mytask2 mytask2"
        self._flag_value_task('mytask2')

    def three_tasks_with_args(self):
        "mytask --boolean mytask3 --mystring foo mytask2"
        r = self._parse("mytask --boolean mytask3 --mystring foo mytask2")
        eq_(len(r), 3)
        eq_([x.name for x in r], ['mytask', 'mytask3', 'mytask2'])
        eq_(r[0].args.boolean.value, True)
        eq_(r[1].args.mystring.value, 'foo')

    def tasks_with_duplicately_named_kwargs(self):
        "mytask --mystring foo mytask3 --mystring bar"
        r = self._parse("mytask --mystring foo mytask3 --mystring bar")
        eq_(r[0].name, 'mytask')
        eq_(r[0].args.mystring.value, 'foo')
        eq_(r[1].name, 'mytask3')
        eq_(r[1].args.mystring.value, 'bar')

    def multiple_short_flags_adjacent(self):
        "mytask -bv"
        r = self._parse("mytask -bv")
        a = r[0].args
        eq_(a.b.value, True)
        eq_(a.v.value, True)
<commit_msg>Remove old import<commit_after>import os
import sys
import StringIO

from spec import eq_, skip, Spec, ok_

from invoke.run import run
from invoke.parser import Parser, Context
from invoke.collection import Collection
from invoke.task import task
from invoke.exceptions import Failure

from _utils import support

class CLI(Spec):
    "Command-line behavior"
    def setup(self):
        os.chdir(support)
        sys.stdout, self.orig_stdout = StringIO.StringIO(), sys.stdout
        sys.stderr, self.orig_stderr = StringIO.StringIO(), sys.stderr
        self.result = run("invoke -c integration print_foo")

    def teardown(self):
        sys.stdout = self.orig_stdout
        sys.stderr = self.orig_stderr

    # Yo dogfood, I heard you like invoking
    def basic_invocation(self):
        eq_(self.result.stdout, "foo\n")

    def implicit_task_module(self):
        # Contains tasks.py
        os.chdir('implicit')
        # Doesn't specify --collection
        result = run("invoke foo")
        eq_(result.stdout, "Hm\n")

    def invocation_with_args(self):
        result = run("invoke -c integration print_name --name whatevs")
        eq_(result.stdout, "whatevs\n")

    def shorthand_binary_name(self):
        eq_(self.result.stdout, "foo\n")

class CLIParsing(Spec):
    """
    High level parsing tests
    """
    def setup(self):
        @task
        def mytask(mystring, s, boolean=False, b=False, v=False):
            pass
        @task
        def mytask2():
            pass
        @task
        def mytask3(mystring):
            pass
        c = Collection()
        c.add_task('mytask', mytask)
        c.add_task('mytask2', mytask2)
        c.add_task('mytask3', mytask3)
        self.c = c

    def _parser(self):
        return Parser(self.c.to_contexts())

    def _parse(self, argstr):
        return self._parser().parse_argv(argstr.split())

    def _compare(self, invoke, flagname, value):
        invoke = "mytask " + invoke
        result = self._parse(invoke)
        eq_(result.to_dict()['mytask'][flagname], value)

    def boolean_args(self):
        "mytask --boolean"
        self._compare("--boolean", 'boolean', True)

    def flag_then_space_then_value(self):
        "mytask --mystring foo"
        self._compare("--mystring foo", 'mystring', 'foo')

    def flag_then_equals_sign_then_value(self):
        "mytask --mystring=foo"
        self._compare("--mystring=foo", 'mystring', 'foo')

    def short_boolean_flag(self):
        "mytask -b"
        self._compare("-b", 'b', True)

    def short_flag_then_space_then_value(self):
        "mytask -s value"
        self._compare("-s value", 's', 'value')

    def short_flag_then_equals_sign_then_value(self):
        "mytask -s=value"
        self._compare("-s=value", 's', 'value')

    def short_flag_with_adjacent_value(self):
        "mytask -svalue"
        r = self._parse("mytask -svalue")
        eq_(r[0].args.s.value, 'value')

    def _flag_value_task(self, value):
        r = self._parse("mytask -s %s mytask2" % value)
        eq_(len(r), 2)
        eq_(r[0].name, 'mytask')
        eq_(r[0].args.s.value, value)
        eq_(r[1].name, 'mytask2')

    def flag_value_then_task(self):
        "mytask -s value mytask2"
        self._flag_value_task('value')

    def flag_value_same_as_task_name(self):
        "mytask -s mytask2 mytask2"
        self._flag_value_task('mytask2')

    def three_tasks_with_args(self):
        "mytask --boolean mytask3 --mystring foo mytask2"
        r = self._parse("mytask --boolean mytask3 --mystring foo mytask2")
        eq_(len(r), 3)
        eq_([x.name for x in r], ['mytask', 'mytask3', 'mytask2'])
        eq_(r[0].args.boolean.value, True)
        eq_(r[1].args.mystring.value, 'foo')

    def tasks_with_duplicately_named_kwargs(self):
        "mytask --mystring foo mytask3 --mystring bar"
        r = self._parse("mytask --mystring foo mytask3 --mystring bar")
        eq_(r[0].name, 'mytask')
        eq_(r[0].args.mystring.value, 'foo')
        eq_(r[1].name, 'mytask3')
        eq_(r[1].args.mystring.value, 'bar')

    def multiple_short_flags_adjacent(self):
        "mytask -bv"
        r = self._parse("mytask -bv")
        a = r[0].args
        eq_(a.b.value, True)
        eq_(a.v.value, True)
<|endoftext|>


<commit_before>#!/usr/bin/env python3
import subprocess
import sys
import os
import platform

# usage: python3.5 run.py [test-set] [prefix]

prefix      = ""
workdir     = "../examples/"
timeout     = 60

# Test syntax ([expected return value], [test status: 0-not executed yet / 1-passed / 2-failed])

# General tests
tests_general = []
tests_general.append([0, 0, workdir + 'client_http_get -u /cgi-bin/he -v 2 bsd10.nplab.de'])
tests_general.append([0, 0, workdir + 'client_http_get -u /cgi-bin/he -v 2 212.201.121.100'])
tests_general.append([0, 0, workdir + 'client_http_get -u /cgi-bin/he -v 2 2a02:c6a0:4015:10::100'])
tests_general.append([1, 0, workdir + 'client_http_get -u /cgi-bin/he -v 2 not.resolvable.neat'])
tests_general.append([1, 0, workdir + 'client_http_get -u /cgi-bin/he -v 2 buildbot.nplab.de'])
tests_general.append([0, 0, workdir + 'client_http_get -n 2 -u /files/4M bsd10.nplab.de'])
tests_general.append([0, 0, workdir + 'tneat -L -n 1024 -P ' + workdir + 'prop_tcp.json'])

if (platform.system() == "FreeBSD") or (platform.system() == "Linux"):
    tests_general.append([1, 0, workdir + 'client_http_get -P ' + workdir + 'prop_tcp_security.json -p 443 -v 2 ec.europa.eu'])
    tests_general.append([0, 0, workdir + 'tneat -v 1 -P ' + workdir + 'prop_sctp_dtls.json interop.fh-muenster.de'])
    tests_general.append([0, 0, workdir + 'tneat -L -n 1024 -P ' + workdir + 'prop_sctp.json'])

#tests_general.append([0, 0, 'python3.5 ../../policy/pmtests.py'])

# USRSCTP specific tests
tests_usrsctp = []
tests_usrsctp.append([0, 0, workdir + 'client_http_get -u /cgi-bin/he -v 2 -P ' + workdir + 'prop_sctp.json  bsd10.nplab.de'])

# Default values
tests       = tests_general

# For PM tests
os.environ['PYTHONIOENCODING'] = 'utf-8'

# First argument: chose between tests
if len(sys.argv) > 1 :
    if sys.argv[1] == "general" :
        tests = tests_general
    elif sys.argv[1] == "usrsctp" :
        tests = tests_usrsctp
    else:
        print("WARN: Unknown testsuite, using default")
        tests = tests_general

# Second argument: command prefix (e.g. valgrind)
if len(sys.argv) > 2 :
    prefix = sys.argv[2]

print("prefix : " + prefix)
print("Starting tests...")

result_global = 0

# Iteratre through tests
for test in tests:
    result = 0
    print("\n\n############################### TEST")
    print("Runnning: " + test[2])
    try:
        result = subprocess.call(prefix + test[2], shell=True, timeout=70)
        if result != test[0]:
            print("Test failed: program returned with error")
            test[1] = 2
            break
    except subprocess.TimeoutExpired:
        print("Test failed: timeout")
        test[1] = 2
        break
    except:
        print("Something went wrong")
        test[1] = 2
        break

    # test succeeded
    test[1] = 1

print("\n\n###############################")
print("Tests finished - summary")
for test in tests:
    if test[1] == 1:
        print("PASSED   --  " + test[2])
    elif test[1] == 2:
        print("FAILED   --  " + test[2])
        result_global = 2
    else:
        print("SKIPPED  --  " + test[2])
        result_global = 2

if result_global > 0:
    sys.exit(-1)
else:
    sys.exit(0)
<commit_msg>Improve testing (#395)<commit_after>#!/usr/bin/env python3
import subprocess
import sys
import os
import platform

# usage: python3.5 run.py [test-set] [prefix]

prefix      = ""
workdir     = "../examples/"
timeout     = 60

# Test syntax ([expected return value], [test status: 0-not executed yet / 1-passed / 2-failed])

# General tests
tests_general = []
tests_general.append([0, 0, workdir + 'client_http_get -u /cgi-bin/he -v 2 bsd10.nplab.de'])
tests_general.append([0, 0, workdir + 'client_http_get -u /cgi-bin/he -v 2 212.201.121.100'])
tests_general.append([0, 0, workdir + 'client_http_get -u /cgi-bin/he -v 2 2a02:c6a0:4015:10::100'])
tests_general.append([1, 0, workdir + 'client_http_get -u /cgi-bin/he -v 2 not.resolvable.neat'])
tests_general.append([1, 0, workdir + 'client_http_get -u /cgi-bin/he -v 2 buildbot.nplab.de'])
tests_general.append([0, 0, workdir + 'client_http_get -n 2 -u /files/4M bsd10.nplab.de'])
tests_general.append([0, 0, workdir + 'tneat -L -n 1024 -P ' + workdir + 'prop_tcp.json'])

if (platform.system() == "FreeBSD") or (platform.system() == "Linux"):
    tests_general.append([0, 0, workdir + 'client_http_get -P ' + workdir + 'prop_tcp_security.json -p 443 -v 2 ec.europa.eu'])
    tests_general.append([0, 0, workdir + 'tneat -v 2 -P ' + workdir + 'prop_sctp_dtls.json interop.fh-muenster.de'])
    tests_general.append([0, 0, workdir + 'tneat -v 2 -L -n 1024 -P ' + workdir + 'prop_sctp.json'])

#tests_general.append([0, 0, 'python3.5 ../../policy/pmtests.py'])

# USRSCTP specific tests
tests_usrsctp = []
tests_usrsctp.append([0, 0, workdir + 'client_http_get -u /cgi-bin/he -v 2 -P ' + workdir + 'prop_sctp.json  bsd10.nplab.de'])

# Default values
tests       = tests_general

# For PM tests
os.environ['PYTHONIOENCODING'] = 'utf-8'

# First argument: chose between tests
if len(sys.argv) > 1 :
    if sys.argv[1] == "general" :
        tests = tests_general
    elif sys.argv[1] == "usrsctp" :
        tests = tests_usrsctp
    else:
        print("WARN: Unknown testsuite, using default")
        tests = tests_general

# Second argument: command prefix (e.g. valgrind)
if len(sys.argv) > 2 :
    prefix = sys.argv[2]

print("prefix : " + prefix)
print("Starting tests...")
sys.stdout.flush()

result_global = 0

# Iteratre through tests
for test in tests:
    result = 0
    print("\n\n############################### TEST")
    print("Runnning: " + test[2])
    sys.stdout.flush()
    try:
        result = subprocess.call(prefix + test[2], shell=True, timeout=timeout)
        if result != test[0]:
            print("Test failed: program returned with error")
            test[1] = 2
            break
    except subprocess.TimeoutExpired:
        print("Test failed: timeout")
        test[1] = 2
        break
    except:
        print("Something went wrong")
        test[1] = 2
        break

    # test succeeded
    test[1] = 1

print("\n\n###############################")
print("Tests finished - summary")
for test in tests:
    if test[1] == 1:
        print("PASSED   --  " + test[2])
    elif test[1] == 2:
        print("FAILED   --  " + test[2])
        result_global = 2
    else:
        print("SKIPPED  --  " + test[2])
        result_global = 2

if result_global > 0:
    sys.exit(-1)
else:
    sys.exit(0)
<|endoftext|>


<commit_before>"""
Django settings for wightinvoices project.

For more information on this file, see
https://docs.djangoproject.com/en/dev/topics/settings/

For the full list of settings and their values, see
https://docs.djangoproject.com/en/dev/ref/settings/
"""

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

# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/dev/howto/deployment/checklist/

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = '0$vyhecyz2=zjrm!@7kbhi-apahn2zr8$)=7*q3u2fpze7yty7'

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True

TEMPLATE_DEBUG = True

ALLOWED_HOSTS = []

# Application definition

INSTALLED_APPS = (
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',

    # Project applications
    'wightinvoices.invoice',

    # 3rd parties
    'debug_toolbar',
    'crispy_forms',
    'guardian',
)

MIDDLEWARE_CLASSES = (
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
)

ROOT_URLCONF = 'wightinvoices.urls'

WSGI_APPLICATION = 'wightinvoices.wsgi.application'

# Database
# https://docs.djangoproject.com/en/dev/ref/settings/#databases

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    }
}

# Internationalization
# https://docs.djangoproject.com/en/dev/topics/i18n/

LANGUAGE_CODE = 'en-us'

TIME_ZONE = 'UTC'

USE_I18N = True

USE_L10N = True

USE_TZ = True

# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/dev/howto/static-files/

STATIC_URL = '/static/'

# Crispy forms

CRISPY_TEMPLATE_PACK = 'bootstrap3'

# Guardian

AUTHENTICATION_BACKENDS = (
    'django.contrib.auth.backends.ModelBackend', # this is default
    'guardian.backends.ObjectPermissionBackend',
)

ANONYMOUS_USER_ID = None

<commit_msg>Don't let DjDT go on the net to fetch jquery.<commit_after>"""
Django settings for wightinvoices project.

For more information on this file, see
https://docs.djangoproject.com/en/dev/topics/settings/

For the full list of settings and their values, see
https://docs.djangoproject.com/en/dev/ref/settings/
"""

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

# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/dev/howto/deployment/checklist/

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = '0$vyhecyz2=zjrm!@7kbhi-apahn2zr8$)=7*q3u2fpze7yty7'

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True

TEMPLATE_DEBUG = True

ALLOWED_HOSTS = []

# Application definition

INSTALLED_APPS = (
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',

    # Project applications
    'wightinvoices.invoice',

    # 3rd parties
    'debug_toolbar',
    'crispy_forms',
    'guardian',
)

MIDDLEWARE_CLASSES = (
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
)

ROOT_URLCONF = 'wightinvoices.urls'

WSGI_APPLICATION = 'wightinvoices.wsgi.application'

# Database
# https://docs.djangoproject.com/en/dev/ref/settings/#databases

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    }
}

# Internationalization
# https://docs.djangoproject.com/en/dev/topics/i18n/

LANGUAGE_CODE = 'en-us'

TIME_ZONE = 'UTC'

USE_I18N = True

USE_L10N = True

USE_TZ = True

# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/dev/howto/static-files/

STATIC_URL = '/static/'

# Crispy forms

CRISPY_TEMPLATE_PACK = 'bootstrap3'

# Guardian

AUTHENTICATION_BACKENDS = (
    'django.contrib.auth.backends.ModelBackend', # this is default
    'guardian.backends.ObjectPermissionBackend',
)

ANONYMOUS_USER_ID = None

DEBUG_TOOLBAR_CONFIG = {
    'JQUERY_URL': '/static/js/jquery.min.js',
}
<|endoftext|>


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

from __future__ import absolute_import, division, print_function

import six

from cryptography import utils
from cryptography.hazmat.primitives import interfaces

@utils.register_interface(interfaces.AsymmetricPadding)
class PKCS1v15(object):
    name = "EMSA-PKCS1-v1_5"

class MGF1(object):
    MAX_LENGTH = object()

    def __init__(self, algorithm, salt_length):
        if not isinstance(algorithm, interfaces.HashAlgorithm):
            raise TypeError("Expected instance of interfaces.HashAlgorithm.")

        self._algorithm = algorithm

        if (not isinstance(salt_length, six.integer_types) and
                not salt_length is self.MAX_LENGTH):
            raise TypeError("salt_length must be an integer")

        if not salt_length is self.MAX_LENGTH and salt_length < 0:
            raise ValueError("salt_length must be zero or greater")

        self._salt_length = salt_length
<commit_msg>restructure if statements to be less confusing<commit_after># Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#    http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
# implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from __future__ import absolute_import, division, print_function

import six

from cryptography import utils
from cryptography.hazmat.primitives import interfaces

@utils.register_interface(interfaces.AsymmetricPadding)
class PKCS1v15(object):
    name = "EMSA-PKCS1-v1_5"

class MGF1(object):
    MAX_LENGTH = object()

    def __init__(self, algorithm, salt_length):
        if not isinstance(algorithm, interfaces.HashAlgorithm):
            raise TypeError("Expected instance of interfaces.HashAlgorithm.")

        self._algorithm = algorithm

        if (not isinstance(salt_length, six.integer_types) and
                salt_length is not self.MAX_LENGTH):
            raise TypeError("salt_length must be an integer")

        if salt_length is not self.MAX_LENGTH and salt_length < 0:
            raise ValueError("salt_length must be zero or greater")

        self._salt_length = salt_length
<|endoftext|>


<commit_before>import re
from datetime import datetime

import pytest
from freezegun import freeze_time

from const import WILLS_BIRTHDAY
from will import settings
from will.plugin import WillPlugin

@pytest.fixture
def plugin(mocker):
    mocker.patch.object(WillPlugin, "publish", return_value=None)
    return WillPlugin()

@pytest.fixture
def content():
    return "This is a test content"

@pytest.fixture
def source_message(message, io_backend):
    return message({"backend": io_backend})

@pytest.fixture
def outgoing_topic(plugin, source_message):
    backend = plugin.get_backend(source_message, None)
    return "message.outgoing.%s" % backend

@pytest.fixture
@freeze_time(WILLS_BIRTHDAY)
def say_event(event, content, source_message):
    return event({
        'type': "say",
        'content': content,
        'source_message': source_message,
        'kwargs': {}
    })

@pytest.fixture
@freeze_time(WILLS_BIRTHDAY)
def reply_event(plugin, event, content, source_message, outgoing_topic):

    return event({
        'type': "reply",
        'content': content,
        'topic': outgoing_topic,
        'source_message': source_message,
        'kwargs': {}
    })

@pytest.fixture
@freeze_time(WILLS_BIRTHDAY)
def topic_event(plugin, event, content, outgoing_topic, source_message):

    return event({
        'type': "topic_change",
        'content': content,
        'topic': outgoing_topic,
        'source_message': source_message,
        'kwargs': {}
    })

def test__init__(plugin):
    kwargs = {"bot": "test"}
    plugin = WillPlugin(**kwargs)
    assert plugin.bot == "test"

def test__prepared_content(plugin, content):
    assert plugin._prepared_content(content, "",
                                    "") == re.sub(r'>\s+<', '><', content)

def test__trim_for_execution_has_analysis_attribute(plugin, message, analysis):
    m = message({"analysis": analysis})
    assert plugin._trim_for_execution(m) == m

def test__trim_for_execution_has_analysis_attribute_in_source_message(plugin, message, analysis):
    m = message({"source_message": message({"analysis": analysis})})
    assert plugin._trim_for_execution(m) == m

def test_get_backend_has_backend_atrribute(plugin, source_message):
    assert plugin.get_backend(source_message) == source_message.backend

def test_get_backend_message_has_backend_atrribute_in_data(plugin, message, source_message):
    m = message({"data": source_message})
    del m.backend
    assert plugin.get_backend(m) == m.data.backend

def test_get_backend_message_no_backend_or_data_attruibute(plugin, message, io_backend):
    settings.DEFAULT_BACKEND = io_backend
    m = message({})
    del m.backend
    assert plugin.get_backend(m) == settings.DEFAULT_BACKEND

def test_get_message_no_message_passed():
    message = {"message": "This is a test"}
    plugin = WillPlugin(**message)
    assert plugin.get_message(None) == plugin.message

def test_get_message_message_passed_as_parameter(plugin, message):
    m = message({})
    assert plugin.get_message(m) == m

def test_get_backend_service_as_parameter(message, plugin, io_backend, all_io_backends):
    m = message({})
    service = io_backend
    settings.IO_BACKENDS = all_io_backends
    assert plugin.get_backend(m, service) == service

# freeze_time to mock datetime.datetime.now() method which is invoked
# when creating an event or message.
# https://github.com/spulec/freezegun
@freeze_time(WILLS_BIRTHDAY)
def test_say_with_room_arg(plugin, content, say_event, source_message, outgoing_topic):
    room = "test"
    plugin.say(content, message=source_message, room=room)
    say_event.kwargs["channel"] = room
    plugin.publish.assert_called_once_with(outgoing_topic, say_event)

@freeze_time(WILLS_BIRTHDAY)
def test_say_with_channel_arg(plugin, content, say_event, source_message, outgoing_topic):
    channel = "test"
    plugin.say(content, message=source_message, channel=channel)
    say_event.kwargs["channel"] = channel
    plugin.publish.assert_called_once_with(outgoing_topic,
                                           say_event)

@freeze_time(WILLS_BIRTHDAY)
def test_say_package_for_scheduling_is_true(plugin, content, say_event, source_message):
    backend = plugin.get_backend(source_message, None)
    topic, event = plugin.say(content,
                              message=source_message,
                              package_for_scheduling=True)
    assert topic == "message.outgoing.%s" % backend
    assert event == say_event

@freeze_time(WILLS_BIRTHDAY)
def test_say_package_for_scheduling_is_false(plugin, content, source_message, say_event):
    backend = plugin.get_backend(source_message, None)
    plugin.say(content, message=source_message, package_for_scheduling=False)
    plugin.publish.assert_called_once_with("message.outgoing.%s" % backend,
                                           say_event)

@freeze_time(WILLS_BIRTHDAY)
def test_reply_package_for_scheduling_is_true(plugin, content, event,
                                              reply_event, source_message):
    incoming_event = event({"data": source_message})
    plugin_reply = plugin.reply(incoming_event,
                                content,
                                package_for_scheduling=True)
    assert plugin_reply == reply_event

@freeze_time(WILLS_BIRTHDAY)
def test_reply_package_for_scheduling_is_false(plugin, content, event,
                                               reply_event, outgoing_topic,
                                               source_message):
    incoming_event = event({"data": source_message})
    plugin.reply(incoming_event, content, package_for_scheduling=False)
    plugin.publish.assert_called_once_with(outgoing_topic, reply_event)

def test_reply_channel_in_kwargs(plugin, event, content, source_message):
    incoming_event = event({"data": source_message})
    reply = plugin.reply(incoming_event, content, channel="test")
    assert reply is None

def test_reply_service_in_kwargs(plugin, event, content, source_message):
    incoming_event = event({"data": source_message})
    reply = plugin.reply(incoming_event, content, service="test")
    assert reply is None

def test_reply_room_in_kwargs(plugin, event, content, source_message):
    incoming_event = event({"data": source_message})
    reply = plugin.reply(incoming_event, content, room="test")
    assert reply is None

@freeze_time(WILLS_BIRTHDAY)
def test_set_topic(plugin, content, topic_event, source_message, outgoing_topic):
    plugin.set_topic(content, message=source_message)
    plugin.publish.assert_called_once_with(outgoing_topic,
                                           topic_event)

@freeze_time(WILLS_BIRTHDAY)
def test_set_topic_with_room_arg(plugin, content, topic_event, source_message, outgoing_topic):
    room = "test"
    plugin.set_topic(content, message=source_message, room=room)
    plugin.publish.assert_called_once_with(outgoing_topic,
                                           topic_event)

@freeze_time(WILLS_BIRTHDAY)
def test_topic_with_channel_arg(plugin, content, topic_event, source_message, outgoing_topic):
    channel = "test"
    plugin.set_topic(content, message=source_message, channel=channel)
    plugin.publish.assert_called_once_with(outgoing_topic, topic_event)

@freeze_time(WILLS_BIRTHDAY)
def test_schedule_say(mocker, plugin, content, source_message):
    mocker.patch.object(plugin,
                        "add_outgoing_event_to_schedule",
                        return_value=None)
    when = datetime.now()
    topic, event = plugin.say(content,
                              message=source_message,
                              package_for_scheduling=True)
    plugin.schedule_say(content, when, message=source_message)
    plugin.add_outgoing_event_to_schedule.assert_called_once_with(
        when, {
            "type": "message",
            "topic": topic,
            "event": event
        })
<commit_msg>I am bad with whitespace<commit_after>import re
from datetime import datetime

import pytest
from freezegun import freeze_time

from const import WILLS_BIRTHDAY
from will import settings
from will.plugin import WillPlugin

@pytest.fixture
def plugin(mocker):
    mocker.patch.object(WillPlugin, "publish", return_value=None)
    return WillPlugin()

@pytest.fixture
def content():
    return "This is a test content"

@pytest.fixture
def source_message(message, io_backend):
    return message({"backend": io_backend})

@pytest.fixture
def outgoing_topic(plugin, source_message):
    backend = plugin.get_backend(source_message, None)
    return "message.outgoing.%s" % backend

@pytest.fixture
@freeze_time(WILLS_BIRTHDAY)
def say_event(event, content, source_message):
    return event({
        'type': "say",
        'content': content,
        'source_message': source_message,
        'kwargs': {}
    })

@pytest.fixture
@freeze_time(WILLS_BIRTHDAY)
def reply_event(plugin, event, content, source_message, outgoing_topic):

    return event({
        'type': "reply",
        'content': content,
        'topic': outgoing_topic,
        'source_message': source_message,
        'kwargs': {}
    })

@pytest.fixture
@freeze_time(WILLS_BIRTHDAY)
def topic_event(plugin, event, content, outgoing_topic, source_message):

    return event({
        'type': "topic_change",
        'content': content,
        'topic': outgoing_topic,
        'source_message': source_message,
        'kwargs': {}
    })

def test__init__(plugin):
    kwargs = {"bot": "test"}
    plugin = WillPlugin(**kwargs)
    assert plugin.bot == "test"

def test__prepared_content(plugin, content):
    assert plugin._prepared_content(content, "",
                                    "") == re.sub(r'>\s+<', '><', content)

def test__trim_for_execution_has_analysis_attribute(plugin, message, analysis):
    m = message({"analysis": analysis})
    assert plugin._trim_for_execution(m) == m

def test__trim_for_execution_has_analysis_attribute_in_source_message(plugin, message, analysis):
    m = message({"source_message": message({"analysis": analysis})})
    assert plugin._trim_for_execution(m) == m

def test_get_backend_has_backend_atrribute(plugin, source_message):
    assert plugin.get_backend(source_message) == source_message.backend

def test_get_backend_message_has_backend_atrribute_in_data(plugin, message, source_message):
    m = message({"data": source_message})
    del m.backend
    assert plugin.get_backend(m) == m.data.backend

def test_get_backend_message_no_backend_or_data_attruibute(plugin, message, io_backend):
    settings.DEFAULT_BACKEND = io_backend
    m = message({})
    del m.backend
    assert plugin.get_backend(m) == settings.DEFAULT_BACKEND

def test_get_message_no_message_passed():
    message = {"message": "This is a test"}
    plugin = WillPlugin(**message)
    assert plugin.get_message(None) == plugin.message

def test_get_message_message_passed_as_parameter(plugin, message):
    m = message({})
    assert plugin.get_message(m) == m

def test_get_backend_service_as_parameter(message, plugin, io_backend, all_io_backends):
    m = message({})
    service = io_backend
    settings.IO_BACKENDS = all_io_backends
    assert plugin.get_backend(m, service) == service

# freeze_time to mock datetime.datetime.now() method which is invoked
# when creating an event or message.
# https://github.com/spulec/freezegun
@freeze_time(WILLS_BIRTHDAY)
def test_say_with_room_arg(plugin, content, say_event, source_message, outgoing_topic):
    room = "test"
    plugin.say(content, message=source_message, room=room)
    say_event.kwargs["channel"] = room
    plugin.publish.assert_called_once_with(outgoing_topic, say_event)

@freeze_time(WILLS_BIRTHDAY)
def test_say_with_channel_arg(plugin, content, say_event, source_message, outgoing_topic):
    channel = "test"
    plugin.say(content, message=source_message, channel=channel)
    say_event.kwargs["channel"] = channel
    plugin.publish.assert_called_once_with(outgoing_topic,
                                           say_event)

@freeze_time(WILLS_BIRTHDAY)
def test_say_package_for_scheduling_is_true(plugin, content, say_event, source_message):
    backend = plugin.get_backend(source_message, None)
    topic, event = plugin.say(content,
                              message=source_message,
                              package_for_scheduling=True)
    assert topic == "message.outgoing.%s" % backend
    assert event == say_event

@freeze_time(WILLS_BIRTHDAY)
def test_say_package_for_scheduling_is_false(plugin, content, source_message, say_event):
    backend = plugin.get_backend(source_message, None)
    plugin.say(content, message=source_message, package_for_scheduling=False)
    plugin.publish.assert_called_once_with("message.outgoing.%s" % backend,
                                           say_event)

@freeze_time(WILLS_BIRTHDAY)
def test_reply_package_for_scheduling_is_true(plugin, content, event,
                                              reply_event, source_message):
    incoming_event = event({"data": source_message})
    plugin_reply = plugin.reply(incoming_event,
                                content,
                                package_for_scheduling=True)
    assert plugin_reply == reply_event

@freeze_time(WILLS_BIRTHDAY)
def test_reply_package_for_scheduling_is_false(plugin, content, event,
                                               reply_event, outgoing_topic,
                                               source_message):
    incoming_event = event({"data": source_message})
    plugin.reply(incoming_event, content, package_for_scheduling=False)
    plugin.publish.assert_called_once_with(outgoing_topic, reply_event)

def test_reply_channel_in_kwargs(plugin, event, content, source_message):
    incoming_event = event({"data": source_message})
    reply = plugin.reply(incoming_event, content, channel="test")
    assert reply is None

def test_reply_service_in_kwargs(plugin, event, content, source_message):
    incoming_event = event({"data": source_message})
    reply = plugin.reply(incoming_event, content, service="test")
    assert reply is None

def test_reply_room_in_kwargs(plugin, event, content, source_message):
    incoming_event = event({"data": source_message})
    reply = plugin.reply(incoming_event, content, room="test")
    assert reply is None

@freeze_time(WILLS_BIRTHDAY)
def test_set_topic(plugin, content, topic_event, source_message, outgoing_topic):
    plugin.set_topic(content, message=source_message)
    plugin.publish.assert_called_once_with(outgoing_topic,
                                           topic_event)

@freeze_time(WILLS_BIRTHDAY)
def test_set_topic_with_room_arg(plugin, content, topic_event, source_message, outgoing_topic):
    room = "test"
    plugin.set_topic(content, message=source_message, room=room)
    plugin.publish.assert_called_once_with(outgoing_topic,
                                           topic_event)

@freeze_time(WILLS_BIRTHDAY)
def test_topic_with_channel_arg(plugin, content, topic_event, source_message, outgoing_topic):
    channel = "test"
    plugin.set_topic(content, message=source_message, channel=channel)
    plugin.publish.assert_called_once_with(outgoing_topic, topic_event)

@freeze_time(WILLS_BIRTHDAY)
def test_schedule_say(mocker, plugin, content, source_message):
    mocker.patch.object(plugin,
                        "add_outgoing_event_to_schedule",
                        return_value=None)
    when = datetime.now()
    topic, event = plugin.say(content,
                              message=source_message,
                              package_for_scheduling=True)
    plugin.schedule_say(content, when, message=source_message)
    plugin.add_outgoing_event_to_schedule.assert_called_once_with(
        when, {
            "type": "message",
            "topic": topic,
            "event": event
        })
<|endoftext|>