<commit_before># vim: tabstop=4 shiftwidth=4 softtabstop=4
#
# Copyright 2012 Cisco Systems, 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.
#
# @author: Sumit Naiksatam, Cisco Systems, Inc.
# @author: Rohit Agarwalla, Cisco Systems, Inc.

from copy import deepcopy
import inspect
import logging

from quantum.db import l3_db
from quantum.manager import QuantumManager
from quantum.openstack.common import importutils
from quantum.plugins.cisco.common import cisco_constants as const
from quantum.plugins.cisco.common import cisco_credentials_v2 as cred
from quantum.plugins.cisco.db import network_db_v2 as cdb
from quantum.plugins.cisco import l2network_plugin_configuration as conf
from quantum.plugins.openvswitch import ovs_db_v2 as odb
from quantum import quantum_plugin_base_v2

LOG = logging.getLogger(__name__)

class VirtualPhysicalSwitchModelV2(quantum_plugin_base_v2.QuantumPluginBaseV2):
    """
    This implementation works with OVS and Nexus plugin for the
    following topology:
    One or more servers to a nexus switch.
    """
    MANAGE_STATE = True
    __native_bulk_support = True
    supported_extension_aliases = []
    _plugins = {}
    _inventory = {}
    _methods_to_delegate = ['get_network', 'get_networks',
                            'create_port', 'create_port_bulk', 'delete_port',
                            'update_port', 'get_port', 'get_ports',
                            'create_subnet', 'create_subnet_bulk',
                            'delete_subnet', 'update_subnet', 'get_subnet',
                            'get_subnets', ]

    def __init__(self):
        """
        Initialize the segmentation manager, check which device plugins are
        configured, and load the inventories those device plugins for which the
        inventory is configured
        """
        cdb.initialize()
        cred.Store.initialize()
        for key in conf.PLUGINS[const.PLUGINS].keys():
            plugin_obj = conf.PLUGINS[const.PLUGINS][key]
            self._plugins[key] = importutils.import_object(plugin_obj)
            LOG.debug("Loaded device plugin %s\n" %
                      conf.PLUGINS[const.PLUGINS][key])
            if key in conf.PLUGINS[const.INVENTORY].keys():
                inventory_obj = conf.PLUGINS[const.INVENTORY][key]
                self._inventory[key] = importutils.import_object(inventory_obj)
                LOG.debug("Loaded device inventory %s\n" %
                          conf.PLUGINS[const.INVENTORY][key])

        if hasattr(self._plugins[const.VSWITCH_PLUGIN],
                   "supported_extension_aliases"):
            self.supported_extension_aliases.extend(
                self._plugins[const.VSWITCH_PLUGIN].
                supported_extension_aliases)

        LOG.debug("%s.%s init done" % (__name__, self.__class__.__name__))

    def __getattribute__(self, name):
        """
        This delegates the calls to the methods implemented only by the OVS
        sub-plugin.
        """
        super_getattr = super(VirtualPhysicalSwitchModelV2,
                              self).__getattribute__
        methods = super_getattr('_methods_to_delegate')

        if name in methods:
            plugin = super_getattr('_plugins')[const.VSWITCH_PLUGIN]
            return getattr(plugin, name)

        try:
            return super_getattr(name)
        except AttributeError:
            plugin = super_getattr('_plugins')[const.VSWITCH_PLUGIN]
            return getattr(plugin, name)

    def _func_name(self, offset=0):
        """Get the name of the calling function"""
        frame_record = inspect.stack()[1 + offset]
        func_name = frame_record[3]
        return func_name

    def _invoke_plugin_per_device(self, plugin_key, function_name, args):
        """
        Invokes a device plugin's relevant functions (on the it's
        inventory and plugin implementation) for completing this operation.
        """
        if not plugin_key in self._plugins.keys():
            LOG.info("No %s Plugin loaded" % plugin_key)
            LOG.info("%s: %s with args %s ignored" %
                     (plugin_key, function_name, args))
            return
        device_params = self._invoke_inventory(plugin_key, function_name,
                                               args)
        device_ips = device_params[const.DEVICE_IP]
        if not device_ips:
            return [self._invoke_plugin(plugin_key, function_name, args,
                                        device_params)]
        else:
            output = []
            for device_ip in device_ips:
                new_device_params = deepcopy(device_params)
                new_device_params[const.DEVICE_IP] = device_ip
                output.append(self._invoke_plugin(plugin_key, function_name,
                                                  args, new_device_params))
            return output

    def _invoke_inventory(self, plugin_key, function_name, args):
        """
        Invokes the relevant function on a device plugin's
        inventory for completing this operation.
        """
        if not plugin_key in self._inventory.keys():
            LOG.info("No %s inventory loaded" % plugin_key)
            LOG.info("%s: %s with args %s ignored" %
                     (plugin_key, function_name, args))
            return {const.DEVICE_IP: []}
        else:
            return getattr(self._inventory[plugin_key], function_name)(args)

    def _invoke_plugin(self, plugin_key, function_name, args, kwargs):
        """
        Invokes the relevant function on a device plugin's
        implementation for completing this operation.
        """
        func = getattr(self._plugins[plugin_key], function_name)
        func_args_len = int(inspect.getargspec(func).args.__len__()) - 1
        fargs, varargs, varkw, defaults = inspect.getargspec(func)
        if args.__len__() > func_args_len:
            func_args = args[:func_args_len]
            extra_args = args[func_args_len:]
            for dict_arg in extra_args:
                for k, v in dict_arg.iteritems():
                    kwargs[k] = v
            return func(*func_args, **kwargs)
        else:
            if (varkw == 'kwargs'):
                return func(*args, **kwargs)
            else:
                return func(*args)

    def _get_segmentation_id(self, network_id):
        binding_seg_id = odb.get_network_binding(None, network_id)
        return binding_seg_id.segmentation_id

    def create_network(self, context, network):
        """
        Perform this operation in the context of the configured device
        plugins.
        """
        LOG.debug("create_network() called\n")
        try:
            args = [context, network]
            ovs_output = self._invoke_plugin_per_device(const.VSWITCH_PLUGIN,
                                                        self._func_name(),
                                                        args)
            vlan_id = self._get_segmentation_id(ovs_output[0]['id'])
            vlan_name = conf.VLAN_NAME_PREFIX + str(vlan_id)
            vlan_ids = cdb.get_ovs_vlans()
            vlanids = ''
            for v_id in vlan_ids:
                vlanids = str(v_id) + ',' + vlanids
            vlanids = vlanids.strip(',')
            args = [ovs_output[0]['tenant_id'], ovs_output[0]['name'],
                    ovs_output[0]['id'], vlan_name, vlan_id,
                    {'vlan_ids':vlanids}]
            nexus_output = self._invoke_plugin_per_device(const.NEXUS_PLUGIN,
                                                          self._func_name(),
                                                          args)
            return ovs_output[0]
        except:
            # TODO (Sumit): Check if we need to perform any rollback here
            raise

    def create_network_bulk(self, context, networks):
        """
        Perform this operation in the context of the configured device
        plugins.
        """
        LOG.debug("create_network_bulk() called\n")
        try:
            args = [context, networks]
            ovs_output = self._plugins[
                const.VSWITCH_PLUGIN].create_network_bulk(context, networks)
            vlan_ids = cdb.get_ovs_vlans()
            vlanids = ''
            for v_id in vlan_ids:
                vlanids = str(v_id[0]) + ',' + vlanids
            vlanids = vlanids.strip(',')
            LOG.debug("ovs_output: %s\n " % ovs_output)
            ovs_networks = ovs_output
            for ovs_network in ovs_networks:
                vlan_id = self._get_segmentation_id(ovs_network['id'])
                vlan_name = conf.VLAN_NAME_PREFIX + str(vlan_id)
                args = [ovs_network['tenant_id'], ovs_network['name'],
                        ovs_network['id'], vlan_name, vlan_id,
                        {'vlan_ids':vlanids}]
                nexus_output = self._invoke_plugin_per_device(
                    const.NEXUS_PLUGIN, "create_network", args)
            return ovs_output
        except:
            # TODO (Sumit): Check if we need to perform any rollback here
            raise

    def update_network(self, context, id, network):
        """
        Perform this operation in the context of the configured device
        plugins.
        """
        LOG.debug("update_network() called\n")
        args = [context, id, network]
        ovs_output = self._invoke_plugin_per_device(const.VSWITCH_PLUGIN,
                                                    self._func_name(),
                                                    args)
        vlan_id = self._get_segmentation_id(ovs_output[0]['id'])
        vlan_ids = ','.join(str(vlan[0]) for vlan in cdb.get_ovs_vlans())
        args = [ovs_output[0]['tenant_id'], id, {'vlan_id': vlan_id},
                {'net_admin_state': ovs_output[0]['admin_state_up']},
                {'vlan_ids': vlan_ids}]
        nexus_output = self._invoke_plugin_per_device(const.NEXUS_PLUGIN,
                                                      self._func_name(),
                                                      args)
        return ovs_output[0]

    def delete_network(self, context, id):
        """
        Perform this operation in the context of the configured device
        plugins.
        """
        try:
            base_plugin_ref = QuantumManager.get_plugin()
            n = base_plugin_ref.get_network(context, id)
            tenant_id = n['tenant_id']
            vlan_id = self._get_segmentation_id(id)
            output = []
            args = [tenant_id, id, {const.VLANID:vlan_id},
                    {const.CONTEXT:context},
                    {const.BASE_PLUGIN_REF:base_plugin_ref}]
            nexus_output = self._invoke_plugin_per_device(const.NEXUS_PLUGIN,
                                                          self._func_name(),
                                                          args)
            args = [context, id]
            ovs_output = self._invoke_plugin_per_device(const.VSWITCH_PLUGIN,
                                                        self._func_name(),
                                                        args)
            return ovs_output[0]
        except:
            raise

    def get_network(self, context, id, fields=None):
        """For this model this method will be delegated to vswitch plugin"""
        pass

    def get_networks(self, context, filters=None, fields=None):
        """For this model this method will be delegated to vswitch plugin"""
        pass

    def create_port(self, context, port):
        """For this model this method will be delegated to vswitch plugin"""
        pass

    def get_port(self, context, id, fields=None):
        """For this model this method will be delegated to vswitch plugin"""
        pass

    def get_ports(self, context, filters=None, fields=None):
        """For this model this method will be delegated to vswitch plugin"""
        pass

    def update_port(self, context, id, port):
        """For this model this method will be delegated to vswitch plugin"""
        pass

    def delete_port(self, context, id, kwargs):
        """For this model this method will be delegated to vswitch plugin"""
        pass

    def create_subnet(self, context, subnet):
        """For this model this method will be delegated to vswitch plugin"""
        pass

    def update_subnet(self, context, id, subnet):
        """For this model this method will be delegated to vswitch plugin"""
        pass

    def get_subnet(self, context, id, fields=None):
        """For this model this method will be delegated to vswitch plugin"""
        pass

    def delete_subnet(self, context, id, kwargs):
        """For this model this method will be delegated to vswitch plugin"""
        pass

    def get_subnets(self, context, filters=None, fields=None):
        """For this model this method will be delegated to vswitch plugin"""
        pass
<commit_msg>Fix for flat network creation in Cisco plugin<commit_after># vim: tabstop=4 shiftwidth=4 softtabstop=4
#
# Copyright 2012 Cisco Systems, 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.
#
# @author: Sumit Naiksatam, Cisco Systems, Inc.
# @author: Rohit Agarwalla, Cisco Systems, Inc.

from copy import deepcopy
import inspect
import logging

from quantum.db import l3_db
from quantum.manager import QuantumManager
from quantum.openstack.common import importutils
from quantum.plugins.cisco.common import cisco_constants as const
from quantum.plugins.cisco.common import cisco_credentials_v2 as cred
from quantum.plugins.cisco.db import network_db_v2 as cdb
from quantum.plugins.cisco import l2network_plugin_configuration as conf
from quantum.plugins.openvswitch import ovs_db_v2 as odb
from quantum import quantum_plugin_base_v2

LOG = logging.getLogger(__name__)

class VirtualPhysicalSwitchModelV2(quantum_plugin_base_v2.QuantumPluginBaseV2):
    """
    This implementation works with OVS and Nexus plugin for the
    following topology:
    One or more servers to a nexus switch.
    """
    MANAGE_STATE = True
    __native_bulk_support = True
    supported_extension_aliases = []
    _plugins = {}
    _inventory = {}
    _methods_to_delegate = ['get_network', 'get_networks',
                            'create_port', 'create_port_bulk', 'delete_port',
                            'update_port', 'get_port', 'get_ports',
                            'create_subnet', 'create_subnet_bulk',
                            'delete_subnet', 'update_subnet', 'get_subnet',
                            'get_subnets', ]

    def __init__(self):
        """
        Initialize the segmentation manager, check which device plugins are
        configured, and load the inventories those device plugins for which the
        inventory is configured
        """
        cdb.initialize()
        cred.Store.initialize()
        for key in conf.PLUGINS[const.PLUGINS].keys():
            plugin_obj = conf.PLUGINS[const.PLUGINS][key]
            self._plugins[key] = importutils.import_object(plugin_obj)
            LOG.debug("Loaded device plugin %s\n" %
                      conf.PLUGINS[const.PLUGINS][key])
            if key in conf.PLUGINS[const.INVENTORY].keys():
                inventory_obj = conf.PLUGINS[const.INVENTORY][key]
                self._inventory[key] = importutils.import_object(inventory_obj)
                LOG.debug("Loaded device inventory %s\n" %
                          conf.PLUGINS[const.INVENTORY][key])

        if hasattr(self._plugins[const.VSWITCH_PLUGIN],
                   "supported_extension_aliases"):
            self.supported_extension_aliases.extend(
                self._plugins[const.VSWITCH_PLUGIN].
                supported_extension_aliases)

        LOG.debug("%s.%s init done" % (__name__, self.__class__.__name__))

    def __getattribute__(self, name):
        """
        This delegates the calls to the methods implemented only by the OVS
        sub-plugin.
        """
        super_getattr = super(VirtualPhysicalSwitchModelV2,
                              self).__getattribute__
        methods = super_getattr('_methods_to_delegate')

        if name in methods:
            plugin = super_getattr('_plugins')[const.VSWITCH_PLUGIN]
            return getattr(plugin, name)

        try:
            return super_getattr(name)
        except AttributeError:
            plugin = super_getattr('_plugins')[const.VSWITCH_PLUGIN]
            return getattr(plugin, name)

    def _func_name(self, offset=0):
        """Get the name of the calling function"""
        frame_record = inspect.stack()[1 + offset]
        func_name = frame_record[3]
        return func_name

    def _invoke_plugin_per_device(self, plugin_key, function_name, args):
        """
        Invokes a device plugin's relevant functions (on the it's
        inventory and plugin implementation) for completing this operation.
        """
        if not plugin_key in self._plugins.keys():
            LOG.info("No %s Plugin loaded" % plugin_key)
            LOG.info("%s: %s with args %s ignored" %
                     (plugin_key, function_name, args))
            return
        device_params = self._invoke_inventory(plugin_key, function_name,
                                               args)
        device_ips = device_params[const.DEVICE_IP]
        if not device_ips:
            return [self._invoke_plugin(plugin_key, function_name, args,
                                        device_params)]
        else:
            output = []
            for device_ip in device_ips:
                new_device_params = deepcopy(device_params)
                new_device_params[const.DEVICE_IP] = device_ip
                output.append(self._invoke_plugin(plugin_key, function_name,
                                                  args, new_device_params))
            return output

    def _invoke_inventory(self, plugin_key, function_name, args):
        """
        Invokes the relevant function on a device plugin's
        inventory for completing this operation.
        """
        if not plugin_key in self._inventory.keys():
            LOG.info("No %s inventory loaded" % plugin_key)
            LOG.info("%s: %s with args %s ignored" %
                     (plugin_key, function_name, args))
            return {const.DEVICE_IP: []}
        else:
            return getattr(self._inventory[plugin_key], function_name)(args)

    def _invoke_plugin(self, plugin_key, function_name, args, kwargs):
        """
        Invokes the relevant function on a device plugin's
        implementation for completing this operation.
        """
        func = getattr(self._plugins[plugin_key], function_name)
        func_args_len = int(inspect.getargspec(func).args.__len__()) - 1
        fargs, varargs, varkw, defaults = inspect.getargspec(func)
        if args.__len__() > func_args_len:
            func_args = args[:func_args_len]
            extra_args = args[func_args_len:]
            for dict_arg in extra_args:
                for k, v in dict_arg.iteritems():
                    kwargs[k] = v
            return func(*func_args, **kwargs)
        else:
            if (varkw == 'kwargs'):
                return func(*args, **kwargs)
            else:
                return func(*args)

    def _get_segmentation_id(self, network_id):
        binding_seg_id = odb.get_network_binding(None, network_id)
        return binding_seg_id.segmentation_id

    def _get_all_segmentation_ids(self):
        vlan_ids = cdb.get_ovs_vlans()
        vlanids = ''
        for v_id in vlan_ids:
            if int(v_id) > 0:
                vlanids = str(v_id) + ',' + vlanids
        return vlanids.strip(',')

    def _validate_vlan_id(self, vlan_id):
        if vlan_id and int(vlan_id) > 1:
            return True
        else:
            return False

    def create_network(self, context, network):
        """
        Perform this operation in the context of the configured device
        plugins.
        """
        LOG.debug("create_network() called\n")
        try:
            args = [context, network]
            ovs_output = self._invoke_plugin_per_device(const.VSWITCH_PLUGIN,
                                                        self._func_name(),
                                                        args)
            vlan_id = self._get_segmentation_id(ovs_output[0]['id'])
            if not self._validate_vlan_id(vlan_id):
                return ovs_output[0]
            vlan_name = conf.VLAN_NAME_PREFIX + str(vlan_id)
            vlanids = self._get_all_segmentation_ids()
            args = [ovs_output[0]['tenant_id'], ovs_output[0]['name'],
                    ovs_output[0]['id'], vlan_name, vlan_id,
                    {'vlan_ids':vlanids}]
            nexus_output = self._invoke_plugin_per_device(const.NEXUS_PLUGIN,
                                                          self._func_name(),
                                                          args)
            return ovs_output[0]
        except:
            # TODO (Sumit): Check if we need to perform any rollback here
            raise

    def create_network_bulk(self, context, networks):
        """
        Perform this operation in the context of the configured device
        plugins.
        """
        LOG.debug("create_network_bulk() called\n")
        try:
            args = [context, networks]
            ovs_output = self._plugins[
                const.VSWITCH_PLUGIN].create_network_bulk(context, networks)
            LOG.debug("ovs_output: %s\n " % ovs_output)
            vlanids = self._get_all_segmentation_ids()
            ovs_networks = ovs_output
            for ovs_network in ovs_networks:
                vlan_id = self._get_segmentation_id(ovs_network['id'])
                vlan_name = conf.VLAN_NAME_PREFIX + str(vlan_id)
                args = [ovs_network['tenant_id'], ovs_network['name'],
                        ovs_network['id'], vlan_name, vlan_id,
                        {'vlan_ids':vlanids}]
                nexus_output = self._invoke_plugin_per_device(
                    const.NEXUS_PLUGIN, "create_network", args)
            return ovs_output
        except:
            # TODO (Sumit): Check if we need to perform any rollback here
            raise

    def update_network(self, context, id, network):
        """
        Perform this operation in the context of the configured device
        plugins.
        """
        LOG.debug("update_network() called\n")
        args = [context, id, network]
        ovs_output = self._invoke_plugin_per_device(const.VSWITCH_PLUGIN,
                                                    self._func_name(),
                                                    args)
        vlan_id = self._get_segmentation_id(ovs_output[0]['id'])
        if not self._validate_vlan_id(vlan_id):
            return ovs_output[0]
        vlanids = self._get_all_segmentation_ids()
        args = [ovs_output[0]['tenant_id'], id, {'vlan_id': vlan_id},
                {'net_admin_state': ovs_output[0]['admin_state_up']},
                {'vlan_ids': vlanids}]
        nexus_output = self._invoke_plugin_per_device(const.NEXUS_PLUGIN,
                                                      self._func_name(),
                                                      args)
        return ovs_output[0]

    def delete_network(self, context, id):
        """
        Perform this operation in the context of the configured device
        plugins.
        """
        try:
            base_plugin_ref = QuantumManager.get_plugin()
            n = base_plugin_ref.get_network(context, id)
            tenant_id = n['tenant_id']
            vlan_id = self._get_segmentation_id(id)
            args = [context, id]
            ovs_output = self._invoke_plugin_per_device(const.VSWITCH_PLUGIN,
                                                        self._func_name(),
                                                        args)
            args = [tenant_id, id, {const.VLANID:vlan_id},
                    {const.CONTEXT:context},
                    {const.BASE_PLUGIN_REF:base_plugin_ref}]
            if self._validate_vlan_id(vlan_id):
                self._invoke_plugin_per_device(const.NEXUS_PLUGIN,
                                               self._func_name(), args)
            return ovs_output[0]
        except:
            raise

    def get_network(self, context, id, fields=None):
        """For this model this method will be delegated to vswitch plugin"""
        pass

    def get_networks(self, context, filters=None, fields=None):
        """For this model this method will be delegated to vswitch plugin"""
        pass

    def create_port(self, context, port):
        """For this model this method will be delegated to vswitch plugin"""
        pass

    def get_port(self, context, id, fields=None):
        """For this model this method will be delegated to vswitch plugin"""
        pass

    def get_ports(self, context, filters=None, fields=None):
        """For this model this method will be delegated to vswitch plugin"""
        pass

    def update_port(self, context, id, port):
        """For this model this method will be delegated to vswitch plugin"""
        pass

    def delete_port(self, context, id, kwargs):
        """For this model this method will be delegated to vswitch plugin"""
        pass

    def create_subnet(self, context, subnet):
        """For this model this method will be delegated to vswitch plugin"""
        pass

    def update_subnet(self, context, id, subnet):
        """For this model this method will be delegated to vswitch plugin"""
        pass

    def get_subnet(self, context, id, fields=None):
        """For this model this method will be delegated to vswitch plugin"""
        pass

    def delete_subnet(self, context, id, kwargs):
        """For this model this method will be delegated to vswitch plugin"""
        pass

    def get_subnets(self, context, filters=None, fields=None):
        """For this model this method will be delegated to vswitch plugin"""
        pass
<|endoftext|>


<commit_before>##############################################################################
#
#    Copyright (C) 2018 Compassion CH (http://www.compassion.ch)
#    @author: Quentin Gigon <gigon.quentin@gmail.com>
#
#    The licence is in the file __manifest__.py
#
##############################################################################
import logging
from datetime import date

from dateutil.relativedelta import relativedelta
from odoo.addons.queue_job.job import job, related_action

from odoo import api, models, fields, _

_logger = logging.getLogger(__name__)

class RecurringContract(models.Model):
    _inherit = "recurring.contract"

    group_id = fields.Many2one(required=False, readonly=False)
    sms_request_id = fields.Many2one(
        "sms.child.request",
        "SMS request",
        compute="_compute_sms_request_id",
        readonly=False,
    )

    @api.multi
    def _compute_sms_request_id(self):
        for contract in self:
            contract.sms_request_id = self.env["sms.child.request"].search(
                [("sponsorship_id", "=", contract.id)], limit=1
            )

    @api.model
    @job
    def create_sms_sponsorship(self, vals, partner, sms_child_request):
        """ Creates sponsorship from REACT webapp data.
        :param vals: form values
        :param partner: res.partner record
        :param sms_child_request: sms.child.request record
        :return: True
        """
        frontend_lang = self.env["res.lang"].search(
            [("code", "like", vals["lang"] + "_")], limit=1
        )

        if partner and (
                partner.firstname != vals["firstname"]
                or partner.lastname != vals["lastname"]
        ):
            partner = False

        if not partner:
            match_obj = self.env["res.partner.match"]
            vals["lang"] = frontend_lang.code
            partner = match_obj.match_partner_to_infos(vals)

        # Update SMS Request
        sms_child_request.write({"partner_id": partner.id, "lang_code": partner.lang})

        # prepare correct medium_id depending on sms_child_request's source
        medium_name = "sms_sponsorship.utm_medium_"
        medium_name += (
            "android"
            if sms_child_request.source == "Android"
            else "ios"
            if sms_child_request.source == "IOS"
            else "sms"
        )

        # Create sponsorship
        lines = self._get_sponsorship_standard_lines(False)
        if not vals["sponsorship_plus"]:
            lines = lines[:-1]
        sponsorship = self.create(
            {
                "partner_id": partner.id,
                "correspondent_id": partner.id,
                "child_id": sms_child_request.child_id.id,
                "type": "S",
                "contract_line_ids": lines,
                "medium_id": self.env.ref(medium_name).id,
                "origin_id": sms_child_request.event_id.origin_id.id,
            }
        )
        sponsorship.on_change_origin()
        sponsorship._set_next_invoice_date_sms()
        sponsorship.with_delay().put_child_on_no_money_hold()
        partner.set_privacy_statement(origin="new_sponsorship")
        sms_child_request.with_context(lang=partner.lang).complete_step1(sponsorship.id)
        return True

    @job(default_channel="root.sms_sponsorship")
    @related_action(action="related_action_contract")
    def finalize_form(self, pay_first_month_ebanking, payment_mode_id):
        """ validate sms sponsorship after step 2 and send confirmation email
        :param pay_first_month_ebanking: has the sponsor paid first month
        :param payment_mode_id: selected payment mode
        :return: True
        """
        self.associate_group(payment_mode_id)

        if not pay_first_month_ebanking:
            # update sms request and send confirmation. this will be done
            # after the payment if the sponsor decides to pay the first month
            self.sms_request_id.complete_step2()

        return True

    @job(default_channel="root.sms_sponsorship")
    @related_action(action="related_action_contract")
    def post_message_from_step2(self, message):
        # Post message in sponsorship
        notify_ids = (
            self.env["res.config.settings"]
                .sudo()
                .get_param("sms_new_partner_notify_ids")
        )
        intro = _("Please verify the following information given by the sponsor:")
        return self.message_post(
            body=intro + message,
            subject=_("New sponsorship information"),
            partner_ids=notify_ids,
            type="comment",
            subtype="mail.mt_comment",
            content_subtype="html",
        )

    def associate_group(self, payment_mode_id):
        """ Create contract group when SMS sponsorship is validated.
        :param payment_mode_id: selected payment mode
        :return: True
        """
        group = self.env["recurring.contract.group"].search(
            [
                ("partner_id", "=", self.partner_id.id),
                ("payment_mode_id", "=", payment_mode_id),
            ],
            order="next_invoice_date desc",
            limit=1,
        )
        if not group:
            group = group.create(
                {"partner_id": self.partner_id.id, "payment_mode_id": payment_mode_id, }
            )
        self.group_id = group
        return True

    @job(default_channel="root.sms_sponsorship")
    @related_action(action="related_action_contract")
    def create_first_sms_invoice(self):
        """In case the sponsor is a new partner, create first invoice
        because the sponsorship won't be validated and invoices are not
        generated. We therefore manually create an invoice that can be paid
        online.
        :return: True
        """
        invoicer = self.env["recurring.invoicer"].create({})
        journal = self.env["account.journal"].search(
            [("type", "=", "sale"), ("company_id", "=", 1)], limit=1
        )
        inv_data = self.group_id._setup_inv_data(journal, invoicer, self)
        self.env["account.invoice"].create(inv_data)
        self.update_next_invoice_date()
        return True

    def contract_waiting(self):
        """
        In case a new sponsor has already paid the first month, we
        automatically pay the first invoice when contract is validated,
        supposing that the staff has verified the partner.
        :return: True
        """
        super().contract_waiting()
        self._post_payment_first_month()
        self.mapped("sms_request_id").write({"state": "step2"})
        return True

    def _post_payment_first_month(self):
        for contract in self.filtered("invoice_line_ids"):
            invoices = contract.invoice_line_ids.mapped("invoice_id")
            payment = self.env["account.payment"].search(
                [("invoice_ids", "in", invoices.ids), ("state", "=", "draft")]
            )
            draft_invoices = invoices.filtered(lambda i: i.state == "draft")
            draft_invoices.action_invoice_open()
            payment.post()

    def _set_next_invoice_date_sms(self):
        """ Just compute the default next_invoice_date for new sponsorship. """
        self.ensure_one()
        current_date = date.today()
        if self.group_id:
            contract_group = self.group_id
            if contract_group.next_invoice_date:
                next_group_date = contract_group.next_invoice_date
                next_invoice_date = current_date.replace(day=next_group_date.day)
            else:
                next_invoice_date = current_date.replace(day=1)
        else:
            next_invoice_date = current_date.replace(day=1)

        next_invoice_date += relativedelta(months=+1)
        self.next_invoice_date = next_invoice_date
<commit_msg>CO-3748 FIX Mobile requests when language is not set<commit_after>##############################################################################
#
#    Copyright (C) 2018 Compassion CH (http://www.compassion.ch)
#    @author: Quentin Gigon <gigon.quentin@gmail.com>
#
#    The licence is in the file __manifest__.py
#
##############################################################################
import logging
from datetime import date

from dateutil.relativedelta import relativedelta
from odoo.addons.queue_job.job import job, related_action

from odoo import api, models, fields, _

_logger = logging.getLogger(__name__)

class RecurringContract(models.Model):
    _inherit = "recurring.contract"

    group_id = fields.Many2one(required=False, readonly=False)
    sms_request_id = fields.Many2one(
        "sms.child.request",
        "SMS request",
        compute="_compute_sms_request_id",
        readonly=False,
    )

    @api.multi
    def _compute_sms_request_id(self):
        for contract in self:
            contract.sms_request_id = self.env["sms.child.request"].search(
                [("sponsorship_id", "=", contract.id)], limit=1
            )

    @api.model
    @job
    def create_sms_sponsorship(self, vals, partner, sms_child_request):
        """ Creates sponsorship from REACT webapp data.
        :param vals: form values
        :param partner: res.partner record
        :param sms_child_request: sms.child.request record
        :return: True
        """
        frontend_lang = self.env["res.lang"].search(
            [("code", "like", vals["lang"][:2])], limit=1
        )

        if partner and (
                partner.firstname != vals["firstname"]
                or partner.lastname != vals["lastname"]
        ):
            partner = False

        if not partner:
            match_obj = self.env["res.partner.match"]
            vals["lang"] = frontend_lang.code
            partner = match_obj.match_partner_to_infos(vals)

        # Update SMS Request
        sms_child_request.write({
            "partner_id": partner.id, "lang_code": partner.lang or frontend_lang.code})

        # prepare correct medium_id depending on sms_child_request's source
        medium_name = "sms_sponsorship.utm_medium_"
        medium_name += (
            "android"
            if sms_child_request.source == "Android"
            else "ios"
            if sms_child_request.source == "IOS"
            else "sms"
        )

        # Create sponsorship
        lines = self._get_sponsorship_standard_lines(False)
        if not vals["sponsorship_plus"]:
            lines = lines[:-1]
        sponsorship = self.create(
            {
                "partner_id": partner.id,
                "correspondent_id": partner.id,
                "child_id": sms_child_request.child_id.id,
                "type": "S",
                "contract_line_ids": lines,
                "medium_id": self.env.ref(medium_name).id,
                "origin_id": sms_child_request.event_id.origin_id.id,
            }
        )
        sponsorship.on_change_origin()
        sponsorship._set_next_invoice_date_sms()
        sponsorship.with_delay().put_child_on_no_money_hold()
        partner.set_privacy_statement(origin="new_sponsorship")
        sms_child_request.with_context(lang=partner.lang).complete_step1(sponsorship.id)
        return True

    @job(default_channel="root.sms_sponsorship")
    @related_action(action="related_action_contract")
    def finalize_form(self, pay_first_month_ebanking, payment_mode_id):
        """ validate sms sponsorship after step 2 and send confirmation email
        :param pay_first_month_ebanking: has the sponsor paid first month
        :param payment_mode_id: selected payment mode
        :return: True
        """
        self.associate_group(payment_mode_id)

        if not pay_first_month_ebanking:
            # update sms request and send confirmation. this will be done
            # after the payment if the sponsor decides to pay the first month
            self.sms_request_id.complete_step2()

        return True

    @job(default_channel="root.sms_sponsorship")
    @related_action(action="related_action_contract")
    def post_message_from_step2(self, message):
        # Post message in sponsorship
        notify_ids = (
            self.env["res.config.settings"]
                .sudo()
                .get_param("sms_new_partner_notify_ids")
        )
        intro = _("Please verify the following information given by the sponsor:")
        return self.message_post(
            body=intro + message,
            subject=_("New sponsorship information"),
            partner_ids=notify_ids,
            type="comment",
            subtype="mail.mt_comment",
            content_subtype="html",
        )

    def associate_group(self, payment_mode_id):
        """ Create contract group when SMS sponsorship is validated.
        :param payment_mode_id: selected payment mode
        :return: True
        """
        group = self.env["recurring.contract.group"].search(
            [
                ("partner_id", "=", self.partner_id.id),
                ("payment_mode_id", "=", payment_mode_id),
            ],
            order="next_invoice_date desc",
            limit=1,
        )
        if not group:
            group = group.create(
                {"partner_id": self.partner_id.id, "payment_mode_id": payment_mode_id, }
            )
        self.group_id = group
        return True

    @job(default_channel="root.sms_sponsorship")
    @related_action(action="related_action_contract")
    def create_first_sms_invoice(self):
        """In case the sponsor is a new partner, create first invoice
        because the sponsorship won't be validated and invoices are not
        generated. We therefore manually create an invoice that can be paid
        online.
        :return: True
        """
        invoicer = self.env["recurring.invoicer"].create({})
        journal = self.env["account.journal"].search(
            [("type", "=", "sale"), ("company_id", "=", 1)], limit=1
        )
        inv_data = self.group_id._setup_inv_data(journal, invoicer, self)
        self.env["account.invoice"].create(inv_data)
        self.update_next_invoice_date()
        return True

    def contract_waiting(self):
        """
        In case a new sponsor has already paid the first month, we
        automatically pay the first invoice when contract is validated,
        supposing that the staff has verified the partner.
        :return: True
        """
        super().contract_waiting()
        self._post_payment_first_month()
        self.mapped("sms_request_id").write({"state": "step2"})
        return True

    def _post_payment_first_month(self):
        for contract in self.filtered("invoice_line_ids"):
            invoices = contract.invoice_line_ids.mapped("invoice_id")
            payment = self.env["account.payment"].search(
                [("invoice_ids", "in", invoices.ids), ("state", "=", "draft")]
            )
            draft_invoices = invoices.filtered(lambda i: i.state == "draft")
            draft_invoices.action_invoice_open()
            payment.post()

    def _set_next_invoice_date_sms(self):
        """ Just compute the default next_invoice_date for new sponsorship. """
        self.ensure_one()
        current_date = date.today()
        if self.group_id:
            contract_group = self.group_id
            if contract_group.next_invoice_date:
                next_group_date = contract_group.next_invoice_date
                next_invoice_date = current_date.replace(day=next_group_date.day)
            else:
                next_invoice_date = current_date.replace(day=1)
        else:
            next_invoice_date = current_date.replace(day=1)

        next_invoice_date += relativedelta(months=+1)
        self.next_invoice_date = next_invoice_date
<|endoftext|>


<commit_before>import random

from django import template

from friends.models import Friendship, FriendshipInvitation

register = template.Library()

@register.inclusion_tag('social/inclusion_tags/twitter_connect_form.html', takes_context=True)
def twitter_connect_form(context, form_id):
    context.update({
        'form_id': form_id,
    })
    return context

@register.inclusion_tag('social/inclusion_tags/facebook_connect_form.html', takes_context=True)
def facebook_connect_form(context, form_id):
    context.update({
        'form_id': form_id,
    })
    return context

@register.inclusion_tag('social/inclusion_tags/twitter_connect_button.html')
def twitter_connect_button(form_id, media_path):
    return {
        'form_id': form_id,
        'media_path': media_path,
    }

@register.inclusion_tag('social/inclusion_tags/facebook_connect_button.html')
def facebook_connect_button(form_id, media_path):
    return {
        'form_id': form_id,
        'media_path': media_path,
    }

@register.inclusion_tag('social/inclusion_tags/friendship_setup_button.html', takes_context=True)
def friendship_setup_button(context, user):
    """
    Renders either an 'add friend', 'remove friend' or 'awaiting confirmation' button based on current friendship state.
    Also includes javascript to request friend or remove friend.
    """
    # Render add friend template by default.
    include_template = 'social/inclusion_tags/friendship_add_button.html'
    requesting_user = context['request'].user

    if requesting_user.is_authenticated():
        # If users are friends already render remove friend template.
        are_friends = Friendship.objects.are_friends(requesting_user, user)
        if are_friends:
            include_template = 'social/inclusion_tags/friendship_remove_button.html'
        else:
            # If users are not friends but an invitation exists, render awaiting confirmation template.
            status = FriendshipInvitation.objects.invitation_status(user1=requesting_user, user2=user)
            if status == 2:
                include_template = 'social/inclusion_tags/friendship_awaiting_confirmation_button.html'

    return {
        'include_template': include_template,
        'object': user,
    }
<commit_msg>added declined<commit_after>import random

from django import template

from friends.models import Friendship, FriendshipInvitation

register = template.Library()

@register.inclusion_tag('social/inclusion_tags/twitter_connect_form.html', takes_context=True)
def twitter_connect_form(context, form_id):
    context.update({
        'form_id': form_id,
    })
    return context

@register.inclusion_tag('social/inclusion_tags/facebook_connect_form.html', takes_context=True)
def facebook_connect_form(context, form_id):
    context.update({
        'form_id': form_id,
    })
    return context

@register.inclusion_tag('social/inclusion_tags/twitter_connect_button.html')
def twitter_connect_button(form_id, media_path):
    return {
        'form_id': form_id,
        'media_path': media_path,
    }

@register.inclusion_tag('social/inclusion_tags/facebook_connect_button.html')
def facebook_connect_button(form_id, media_path):
    return {
        'form_id': form_id,
        'media_path': media_path,
    }

@register.inclusion_tag('social/inclusion_tags/friendship_setup_button.html', takes_context=True)
def friendship_setup_button(context, user):
    """
    Renders either an 'add friend', 'remove friend' or 'awaiting confirmation' button based on current friendship state.
    Also includes javascript to request friend or remove friend.
    """
    # Render add friend template by default.
    include_template = 'social/inclusion_tags/friendship_add_button.html'
    requesting_user = context['request'].user

    if requesting_user.is_authenticated():
        # If users are friends already render remove friend template.
        are_friends = Friendship.objects.are_friends(requesting_user, user)
        if are_friends:
            include_template = 'social/inclusion_tags/friendship_remove_button.html'
        else:
            # If users are not friends but an invitation exists, render awaiting confirmation or declined template.
            status = FriendshipInvitation.objects.invitation_status(user1=requesting_user, user2=user)
            if status == 2:
                include_template = 'social/inclusion_tags/friendship_awaiting_confirmation_button.html'
            if status == 6:
                include_template = 'social/inclusion_tags/friendship_declined_button.html'

    return {
        'include_template': include_template,
        'object': user,
    }
<|endoftext|>


<commit_before>import random

from raiden.constants import MAXIMUM_PENDING_TRANSFERS
from raiden.settings import DEFAULT_NUMBER_OF_BLOCK_CONFIRMATIONS
from raiden.transfer import channel
from raiden.transfer.architecture import TransitionResult
from raiden.transfer.events import EventPaymentSentFailed, EventPaymentSentSuccess
from raiden.transfer.mediated_transfer.events import (
    CHANNEL_IDENTIFIER_GLOBAL_QUEUE,
    EventUnlockSuccess,
    SendLockedTransfer,
    SendSecretReveal,
)
from raiden.transfer.mediated_transfer.state import (
    InitiatorTransferState,
    TransferDescriptionWithSecretState,
)
from raiden.transfer.mediated_transfer.state_change import (
    ReceiveSecretRequest,
    ReceiveSecretReveal,
)
from raiden.transfer.state import (
    CHANNEL_STATE_OPENED,
    NettingChannelState,
    RouteState,
    message_identifier_from_prng,
)
from raiden.transfer.state_change import Block, ContractReceiveSecretReveal
from raiden.utils import typing

def events_for_unlock_lock(
        initiator_state: InitiatorTransferState,
        channel_state: NettingChannelState,
        secret: typing.Secret,
        secrethash: typing.SecretHash,
        pseudo_random_generator: random.Random,
):
    # next hop learned the secret, unlock the token locally and send the
    # lock claim message to next hop
    transfer_description = initiator_state.transfer_description

    message_identifier = message_identifier_from_prng(pseudo_random_generator)
    unlock_lock = channel.send_unlock(
        channel_state=channel_state,
        message_identifier=message_identifier,
        payment_identifier=transfer_description.payment_identifier,
        secret=secret,
        secrethash=secrethash,
    )

    payment_sent_success = EventPaymentSentSuccess(
        payment_network_identifier=channel_state.payment_network_identifier,
        token_network_identifier=channel_state.token_network_identifier,
        identifier=transfer_description.payment_identifier,
        amount=transfer_description.amount,
        target=transfer_description.target,
    )

    unlock_success = EventUnlockSuccess(
        transfer_description.payment_identifier,
        transfer_description.secrethash,
    )

    return [unlock_lock, payment_sent_success, unlock_success]

def handle_block(
        initiator_state: InitiatorTransferState,
        state_change: Block,
        channel_state: NettingChannelState,
        pseudo_random_generator: random.Random,
) -> TransitionResult:
    secrethash = initiator_state.transfer.lock.secrethash
    locked_lock = channel_state.our_state.secrethashes_to_lockedlocks.get(secrethash)

    lock_expiration_threshold = locked_lock.expiration + DEFAULT_NUMBER_OF_BLOCK_CONFIRMATIONS * 2
    lock_has_expired, _ = locked_lock and channel.is_lock_expired(
        end_state=channel_state.our_state,
        lock=locked_lock,
        block_number=state_change.block_number,
        lock_expiration_threshold=lock_expiration_threshold,
    )
    if lock_has_expired:
        expired_lock_events = channel.events_for_expired_lock(
            channel_state,
            secrethash,
            locked_lock,
            pseudo_random_generator,
        )

        iteration = TransitionResult(None, expired_lock_events)
        return iteration

    return TransitionResult(initiator_state, list())

def get_initial_lock_expiration(
        block_number: typing.BlockNumber,
        reveal_timeout: typing.BlockTimeout,
) -> typing.BlockExpiration:
    """ Returns the expiration used for all hash-time-locks in transfer. """
    return block_number + reveal_timeout * 2

def next_channel_from_routes(
        available_routes: typing.List[RouteState],
        channelidentifiers_to_channels: typing.ChannelMap,
        transfer_amount: typing.TokenAmount,
) -> typing.Optional[NettingChannelState]:
    """ Returns the first channel that can be used to start the transfer.
    The routing service can race with local changes, so the recommended routes
    must be validated.
    """
    for route in available_routes:
        channel_identifier = route.channel_identifier
        channel_state = channelidentifiers_to_channels.get(channel_identifier)

        if not channel_state:
            continue

        if channel.get_status(channel_state) != CHANNEL_STATE_OPENED:
            continue

        pending_transfers = channel.get_number_of_pending_transfers(channel_state.our_state)
        if pending_transfers >= MAXIMUM_PENDING_TRANSFERS:
            continue

        distributable = channel.get_distributable(
            channel_state.our_state,
            channel_state.partner_state,
        )
        if transfer_amount > distributable:
            continue

        if channel.is_valid_amount(channel_state.our_state, transfer_amount):
            return channel_state

    return None

def try_new_route(
        channelidentifiers_to_channels: typing.ChannelMap,
        available_routes: typing.List[RouteState],
        transfer_description: TransferDescriptionWithSecretState,
        pseudo_random_generator: random.Random,
        block_number: typing.BlockNumber,
) -> TransitionResult:

    channel_state = next_channel_from_routes(
        available_routes,
        channelidentifiers_to_channels,
        transfer_description.amount,
    )

    events = list()
    if channel_state is None:
        if not available_routes:
            reason = 'there is no route available'
        else:
            reason = 'none of the available routes could be used'

        transfer_failed = EventPaymentSentFailed(
            payment_network_identifier=transfer_description.payment_network_identifier,
            token_network_identifier=transfer_description.token_network_identifier,
            identifier=transfer_description.payment_identifier,
            target=transfer_description.target,
            reason=reason,
        )
        events.append(transfer_failed)

        initiator_state = None

    else:
        message_identifier = message_identifier_from_prng(pseudo_random_generator)
        lockedtransfer_event = send_lockedtransfer(
            transfer_description=transfer_description,
            channel_state=channel_state,
            message_identifier=message_identifier,
            block_number=block_number,
        )
        assert lockedtransfer_event

        initiator_state = InitiatorTransferState(
            transfer_description=transfer_description,
            channel_identifier=channel_state.identifier,
            transfer=lockedtransfer_event.transfer,
            revealsecret=None,
        )
        events.append(lockedtransfer_event)

    return TransitionResult(initiator_state, events)

def send_lockedtransfer(
        transfer_description: TransferDescriptionWithSecretState,
        channel_state: NettingChannelState,
        message_identifier: typing.MessageID,
        block_number: typing.BlockNumber,
) -> SendLockedTransfer:
    """ Create a mediated transfer using channel.

    Raises:
        AssertionError: If the channel does not have enough capacity.
    """
    assert channel_state.token_network_identifier == transfer_description.token_network_identifier

    transfer_description = transfer_description
    lock_expiration = get_initial_lock_expiration(
        block_number,
        channel_state.reveal_timeout,
    )

    lockedtransfer_event = channel.send_lockedtransfer(
        channel_state,
        transfer_description.initiator,
        transfer_description.target,
        transfer_description.amount,
        message_identifier,
        transfer_description.payment_identifier,
        lock_expiration,
        transfer_description.secrethash,
    )
    return lockedtransfer_event

def handle_secretrequest(
        initiator_state: InitiatorTransferState,
        state_change: ReceiveSecretRequest,
        channel_state: NettingChannelState,
        pseudo_random_generator: random.Random,
) -> TransitionResult:

    is_message_from_target = (
        state_change.sender == initiator_state.transfer_description.target and
        state_change.secrethash == initiator_state.transfer_description.secrethash and
        state_change.payment_identifier == initiator_state.transfer_description.payment_identifier
    )

    lock = channel.get_lock(
        channel_state.our_state,
        initiator_state.transfer_description.secrethash,
    )

    is_valid_secretrequest = (
        is_message_from_target and
        state_change.amount == initiator_state.transfer_description.amount and
        state_change.expiration == lock.expiration
    )

    if is_valid_secretrequest:
        # Reveal the secret to the target node and wait for its confirmation.
        # At this point the transfer is not cancellable anymore as either the lock
        # timeouts or a secret reveal is received.
        #
        # Note: The target might be the first hop
        #
        message_identifier = message_identifier_from_prng(pseudo_random_generator)
        transfer_description = initiator_state.transfer_description
        recipient = transfer_description.target
        revealsecret = SendSecretReveal(
            recipient=recipient,
            channel_identifier=CHANNEL_IDENTIFIER_GLOBAL_QUEUE,
            message_identifier=message_identifier,
            secret=transfer_description.secret,
        )

        initiator_state.revealsecret = revealsecret
        iteration = TransitionResult(initiator_state, [revealsecret])

    elif not is_valid_secretrequest and is_message_from_target:
        cancel = EventPaymentSentFailed(
            payment_network_identifier=channel_state.payment_network_identifier,
            token_network_identifier=channel_state.token_network_identifer,
            identifier=initiator_state.transfer_description.payment_identifier,
            target=initiator_state.transfer_description.target,
            reason='bad secret request message from target',
        )
        iteration = TransitionResult(None, [cancel])

    else:
        iteration = TransitionResult(initiator_state, list())

    return iteration

def handle_secretreveal(
        initiator_state: InitiatorTransferState,
        state_change: ReceiveSecretReveal,
        channel_state: NettingChannelState,
        pseudo_random_generator: random.Random,
) -> TransitionResult:
    """ Once the next hop proves it knows the secret, the initiator can unlock
    the mediated transfer.

    This will validate the secret, and if valid a new balance proof is sent to
    the next hop with the current lock removed from the merkle tree and the
    transferred amount updated.
    """
    is_valid_secret_reveal = (
        state_change.sender == channel_state.partner_state.address and
        state_change.secrethash == initiator_state.transfer_description.secrethash
    )
    is_channel_open = channel.get_status(channel_state) == CHANNEL_STATE_OPENED

    if is_valid_secret_reveal and is_channel_open:
        events = events_for_unlock_lock(
            initiator_state,
            channel_state,
            state_change.secret,
            state_change.secrethash,
            pseudo_random_generator,
        )
        iteration = TransitionResult(None, events)
    else:
        events = list()
        iteration = TransitionResult(initiator_state, events)

    return iteration

def handle_onchain_secretreveal(
        initiator_state: InitiatorTransferState,
        state_change: ContractReceiveSecretReveal,
        channel_state: NettingChannelState,
        pseudo_random_generator: random.Random,
) -> TransitionResult:
    """ When a secret is revealed on-chain all nodes learn the secret.

    This check the on-chain secret corresponds to the one used by the
    initiator, and if valid a new balance proof is sent to the next hop with
    the current lock removed from the merkle tree and the transferred amount
    updated.
    """
    is_valid_secret = state_change.secrethash == initiator_state.transfer.lock.secrethash
    is_channel_open = channel.get_status(channel_state) == CHANNEL_STATE_OPENED
    is_lock_expired = state_change.block_number > initiator_state.transfer.lock.expiration

    is_lock_unlocked = (
        is_valid_secret and
        is_channel_open and
        not is_lock_expired
    )

    if is_lock_unlocked:
        events = events_for_unlock_lock(
            initiator_state,
            channel_state,
            state_change.secret,
            state_change.secrethash,
            pseudo_random_generator,
        )
        iteration = TransitionResult(None, events)
    else:
        events = list()
        iteration = TransitionResult(initiator_state, events)

    return iteration
<commit_msg>Remove unnecessary line<commit_after>import random

from raiden.constants import MAXIMUM_PENDING_TRANSFERS
from raiden.settings import DEFAULT_NUMBER_OF_BLOCK_CONFIRMATIONS
from raiden.transfer import channel
from raiden.transfer.architecture import TransitionResult
from raiden.transfer.events import EventPaymentSentFailed, EventPaymentSentSuccess
from raiden.transfer.mediated_transfer.events import (
    CHANNEL_IDENTIFIER_GLOBAL_QUEUE,
    EventUnlockSuccess,
    SendLockedTransfer,
    SendSecretReveal,
)
from raiden.transfer.mediated_transfer.state import (
    InitiatorTransferState,
    TransferDescriptionWithSecretState,
)
from raiden.transfer.mediated_transfer.state_change import (
    ReceiveSecretRequest,
    ReceiveSecretReveal,
)
from raiden.transfer.state import (
    CHANNEL_STATE_OPENED,
    NettingChannelState,
    RouteState,
    message_identifier_from_prng,
)
from raiden.transfer.state_change import Block, ContractReceiveSecretReveal
from raiden.utils import typing

def events_for_unlock_lock(
        initiator_state: InitiatorTransferState,
        channel_state: NettingChannelState,
        secret: typing.Secret,
        secrethash: typing.SecretHash,
        pseudo_random_generator: random.Random,
):
    # next hop learned the secret, unlock the token locally and send the
    # lock claim message to next hop
    transfer_description = initiator_state.transfer_description

    message_identifier = message_identifier_from_prng(pseudo_random_generator)
    unlock_lock = channel.send_unlock(
        channel_state=channel_state,
        message_identifier=message_identifier,
        payment_identifier=transfer_description.payment_identifier,
        secret=secret,
        secrethash=secrethash,
    )

    payment_sent_success = EventPaymentSentSuccess(
        payment_network_identifier=channel_state.payment_network_identifier,
        token_network_identifier=channel_state.token_network_identifier,
        identifier=transfer_description.payment_identifier,
        amount=transfer_description.amount,
        target=transfer_description.target,
    )

    unlock_success = EventUnlockSuccess(
        transfer_description.payment_identifier,
        transfer_description.secrethash,
    )

    return [unlock_lock, payment_sent_success, unlock_success]

def handle_block(
        initiator_state: InitiatorTransferState,
        state_change: Block,
        channel_state: NettingChannelState,
        pseudo_random_generator: random.Random,
) -> TransitionResult:
    secrethash = initiator_state.transfer.lock.secrethash
    locked_lock = channel_state.our_state.secrethashes_to_lockedlocks.get(secrethash)

    lock_expiration_threshold = locked_lock.expiration + DEFAULT_NUMBER_OF_BLOCK_CONFIRMATIONS * 2
    lock_has_expired, _ = locked_lock and channel.is_lock_expired(
        end_state=channel_state.our_state,
        lock=locked_lock,
        block_number=state_change.block_number,
        lock_expiration_threshold=lock_expiration_threshold,
    )
    if lock_has_expired:
        expired_lock_events = channel.events_for_expired_lock(
            channel_state,
            secrethash,
            locked_lock,
            pseudo_random_generator,
        )

        iteration = TransitionResult(None, expired_lock_events)
        return iteration

    return TransitionResult(initiator_state, list())

def get_initial_lock_expiration(
        block_number: typing.BlockNumber,
        reveal_timeout: typing.BlockTimeout,
) -> typing.BlockExpiration:
    """ Returns the expiration used for all hash-time-locks in transfer. """
    return block_number + reveal_timeout * 2

def next_channel_from_routes(
        available_routes: typing.List[RouteState],
        channelidentifiers_to_channels: typing.ChannelMap,
        transfer_amount: typing.TokenAmount,
) -> typing.Optional[NettingChannelState]:
    """ Returns the first channel that can be used to start the transfer.
    The routing service can race with local changes, so the recommended routes
    must be validated.
    """
    for route in available_routes:
        channel_identifier = route.channel_identifier
        channel_state = channelidentifiers_to_channels.get(channel_identifier)

        if not channel_state:
            continue

        if channel.get_status(channel_state) != CHANNEL_STATE_OPENED:
            continue

        pending_transfers = channel.get_number_of_pending_transfers(channel_state.our_state)
        if pending_transfers >= MAXIMUM_PENDING_TRANSFERS:
            continue

        distributable = channel.get_distributable(
            channel_state.our_state,
            channel_state.partner_state,
        )
        if transfer_amount > distributable:
            continue

        if channel.is_valid_amount(channel_state.our_state, transfer_amount):
            return channel_state

    return None

def try_new_route(
        channelidentifiers_to_channels: typing.ChannelMap,
        available_routes: typing.List[RouteState],
        transfer_description: TransferDescriptionWithSecretState,
        pseudo_random_generator: random.Random,
        block_number: typing.BlockNumber,
) -> TransitionResult:

    channel_state = next_channel_from_routes(
        available_routes,
        channelidentifiers_to_channels,
        transfer_description.amount,
    )

    events = list()
    if channel_state is None:
        if not available_routes:
            reason = 'there is no route available'
        else:
            reason = 'none of the available routes could be used'

        transfer_failed = EventPaymentSentFailed(
            payment_network_identifier=transfer_description.payment_network_identifier,
            token_network_identifier=transfer_description.token_network_identifier,
            identifier=transfer_description.payment_identifier,
            target=transfer_description.target,
            reason=reason,
        )
        events.append(transfer_failed)

        initiator_state = None

    else:
        message_identifier = message_identifier_from_prng(pseudo_random_generator)
        lockedtransfer_event = send_lockedtransfer(
            transfer_description=transfer_description,
            channel_state=channel_state,
            message_identifier=message_identifier,
            block_number=block_number,
        )
        assert lockedtransfer_event

        initiator_state = InitiatorTransferState(
            transfer_description=transfer_description,
            channel_identifier=channel_state.identifier,
            transfer=lockedtransfer_event.transfer,
            revealsecret=None,
        )
        events.append(lockedtransfer_event)

    return TransitionResult(initiator_state, events)

def send_lockedtransfer(
        transfer_description: TransferDescriptionWithSecretState,
        channel_state: NettingChannelState,
        message_identifier: typing.MessageID,
        block_number: typing.BlockNumber,
) -> SendLockedTransfer:
    """ Create a mediated transfer using channel.

    Raises:
        AssertionError: If the channel does not have enough capacity.
    """
    assert channel_state.token_network_identifier == transfer_description.token_network_identifier

    lock_expiration = get_initial_lock_expiration(
        block_number,
        channel_state.reveal_timeout,
    )

    lockedtransfer_event = channel.send_lockedtransfer(
        channel_state,
        transfer_description.initiator,
        transfer_description.target,
        transfer_description.amount,
        message_identifier,
        transfer_description.payment_identifier,
        lock_expiration,
        transfer_description.secrethash,
    )
    return lockedtransfer_event

def handle_secretrequest(
        initiator_state: InitiatorTransferState,
        state_change: ReceiveSecretRequest,
        channel_state: NettingChannelState,
        pseudo_random_generator: random.Random,
) -> TransitionResult:

    is_message_from_target = (
        state_change.sender == initiator_state.transfer_description.target and
        state_change.secrethash == initiator_state.transfer_description.secrethash and
        state_change.payment_identifier == initiator_state.transfer_description.payment_identifier
    )

    lock = channel.get_lock(
        channel_state.our_state,
        initiator_state.transfer_description.secrethash,
    )

    is_valid_secretrequest = (
        is_message_from_target and
        state_change.amount == initiator_state.transfer_description.amount and
        state_change.expiration == lock.expiration
    )

    if is_valid_secretrequest:
        # Reveal the secret to the target node and wait for its confirmation.
        # At this point the transfer is not cancellable anymore as either the lock
        # timeouts or a secret reveal is received.
        #
        # Note: The target might be the first hop
        #
        message_identifier = message_identifier_from_prng(pseudo_random_generator)
        transfer_description = initiator_state.transfer_description
        recipient = transfer_description.target
        revealsecret = SendSecretReveal(
            recipient=recipient,
            channel_identifier=CHANNEL_IDENTIFIER_GLOBAL_QUEUE,
            message_identifier=message_identifier,
            secret=transfer_description.secret,
        )

        initiator_state.revealsecret = revealsecret
        iteration = TransitionResult(initiator_state, [revealsecret])

    elif not is_valid_secretrequest and is_message_from_target:
        cancel = EventPaymentSentFailed(
            payment_network_identifier=channel_state.payment_network_identifier,
            token_network_identifier=channel_state.token_network_identifer,
            identifier=initiator_state.transfer_description.payment_identifier,
            target=initiator_state.transfer_description.target,
            reason='bad secret request message from target',
        )
        iteration = TransitionResult(None, [cancel])

    else:
        iteration = TransitionResult(initiator_state, list())

    return iteration

def handle_secretreveal(
        initiator_state: InitiatorTransferState,
        state_change: ReceiveSecretReveal,
        channel_state: NettingChannelState,
        pseudo_random_generator: random.Random,
) -> TransitionResult:
    """ Once the next hop proves it knows the secret, the initiator can unlock
    the mediated transfer.

    This will validate the secret, and if valid a new balance proof is sent to
    the next hop with the current lock removed from the merkle tree and the
    transferred amount updated.
    """
    is_valid_secret_reveal = (
        state_change.sender == channel_state.partner_state.address and
        state_change.secrethash == initiator_state.transfer_description.secrethash
    )
    is_channel_open = channel.get_status(channel_state) == CHANNEL_STATE_OPENED

    if is_valid_secret_reveal and is_channel_open:
        events = events_for_unlock_lock(
            initiator_state,
            channel_state,
            state_change.secret,
            state_change.secrethash,
            pseudo_random_generator,
        )
        iteration = TransitionResult(None, events)
    else:
        events = list()
        iteration = TransitionResult(initiator_state, events)

    return iteration

def handle_onchain_secretreveal(
        initiator_state: InitiatorTransferState,
        state_change: ContractReceiveSecretReveal,
        channel_state: NettingChannelState,
        pseudo_random_generator: random.Random,
) -> TransitionResult:
    """ When a secret is revealed on-chain all nodes learn the secret.

    This check the on-chain secret corresponds to the one used by the
    initiator, and if valid a new balance proof is sent to the next hop with
    the current lock removed from the merkle tree and the transferred amount
    updated.
    """
    is_valid_secret = state_change.secrethash == initiator_state.transfer.lock.secrethash
    is_channel_open = channel.get_status(channel_state) == CHANNEL_STATE_OPENED
    is_lock_expired = state_change.block_number > initiator_state.transfer.lock.expiration

    is_lock_unlocked = (
        is_valid_secret and
        is_channel_open and
        not is_lock_expired
    )

    if is_lock_unlocked:
        events = events_for_unlock_lock(
            initiator_state,
            channel_state,
            state_change.secret,
            state_change.secrethash,
            pseudo_random_generator,
        )
        iteration = TransitionResult(None, events)
    else:
        events = list()
        iteration = TransitionResult(initiator_state, events)

    return iteration
<|endoftext|>


<commit_before>"""
Testing for Isolation Forest algorithm (sklearn.ensemble.iforest).
"""

# Authors: Nicolas Goix <nicolas.goix@telecom-paristech.fr>
#          Alexandre Gramfort <alexandre.gramfort@telecom-paristech.fr>
# License: BSD 3 clause

import pytest
import warnings

import numpy as np

from sklearn.utils._testing import assert_array_equal
from sklearn.utils._testing import assert_array_almost_equal
from sklearn.utils._testing import ignore_warnings
from sklearn.utils._testing import assert_allclose

from sklearn.model_selection import ParameterGrid
from sklearn.ensemble import IsolationForest
from sklearn.ensemble._iforest import _average_path_length
from sklearn.model_selection import train_test_split
from sklearn.datasets import load_diabetes, load_iris, make_classification
from sklearn.utils import check_random_state
from sklearn.metrics import roc_auc_score

from scipy.sparse import csc_matrix, csr_matrix
from unittest.mock import Mock, patch

rng = check_random_state(0)

# load the iris dataset
# and randomly permute it
iris = load_iris()
perm = rng.permutation(iris.target.size)
iris.data = iris.data[perm]
iris.target = iris.target[perm]

# also load the diabetes dataset
# and randomly permute it
diabetes = load_diabetes()
perm = rng.permutation(diabetes.target.size)
diabetes.data = diabetes.data[perm]
diabetes.target = diabetes.target[perm]

def test_iforest():
    """Check Isolation Forest for various parameter settings."""
    X_train = np.array([[0, 1], [1, 2]])
    X_test = np.array([[2, 1], [1, 1]])

    grid = ParameterGrid(
        {"n_estimators": [3], "max_samples": [0.5, 1.0, 3], "bootstrap": [True, False]}
    )

    with ignore_warnings():
        for params in grid:
            IsolationForest(random_state=rng, **params).fit(X_train).predict(X_test)

def test_iforest_sparse():
    """Check IForest for various parameter settings on sparse input."""
    rng = check_random_state(0)
    X_train, X_test, y_train, y_test = train_test_split(
        diabetes.data[:50], diabetes.target[:50], random_state=rng
    )
    grid = ParameterGrid({"max_samples": [0.5, 1.0], "bootstrap": [True, False]})

    for sparse_format in [csc_matrix, csr_matrix]:
        X_train_sparse = sparse_format(X_train)
        X_test_sparse = sparse_format(X_test)

        for params in grid:
            # Trained on sparse format
            sparse_classifier = IsolationForest(
                n_estimators=10, random_state=1, **params
            ).fit(X_train_sparse)
            sparse_results = sparse_classifier.predict(X_test_sparse)

            # Trained on dense format
            dense_classifier = IsolationForest(
                n_estimators=10, random_state=1, **params
            ).fit(X_train)
            dense_results = dense_classifier.predict(X_test)

            assert_array_equal(sparse_results, dense_results)

def test_iforest_error():
    """Test that it gives proper exception on deficient input."""
    X = iris.data

    # Test max_samples
    with pytest.raises(ValueError):
        IsolationForest(max_samples=-1).fit(X)
    with pytest.raises(ValueError):
        IsolationForest(max_samples=0.0).fit(X)
    with pytest.raises(ValueError):
        IsolationForest(max_samples=2.0).fit(X)
    # The dataset has less than 256 samples, explicitly setting
    # max_samples > n_samples should result in a warning. If not set
    # explicitly there should be no warning
    warn_msg = "max_samples will be set to n_samples for estimation"
    with pytest.warns(UserWarning, match=warn_msg):
        IsolationForest(max_samples=1000).fit(X)
    with warnings.catch_warnings():
        warnings.simplefilter("error", UserWarning)
        IsolationForest(max_samples="auto").fit(X)
    with warnings.catch_warnings():
        warnings.simplefilter("error", UserWarning)
        IsolationForest(max_samples=np.int64(2)).fit(X)

    with pytest.raises(ValueError):
        IsolationForest(max_samples="foobar").fit(X)
    with pytest.raises(ValueError):
        IsolationForest(max_samples=1.5).fit(X)

    # test X_test n_features match X_train one:
    with pytest.raises(ValueError):
        IsolationForest().fit(X).predict(X[:, 1:])

def test_recalculate_max_depth():
    """Check max_depth recalculation when max_samples is reset to n_samples"""
    X = iris.data
    clf = IsolationForest().fit(X)
    for est in clf.estimators_:
        assert est.max_depth == int(np.ceil(np.log2(X.shape[0])))

def test_max_samples_attribute():
    X = iris.data
    clf = IsolationForest().fit(X)
    assert clf.max_samples_ == X.shape[0]

    clf = IsolationForest(max_samples=500)
    warn_msg = "max_samples will be set to n_samples for estimation"
    with pytest.warns(UserWarning, match=warn_msg):
        clf.fit(X)
    assert clf.max_samples_ == X.shape[0]

    clf = IsolationForest(max_samples=0.4).fit(X)
    assert clf.max_samples_ == 0.4 * X.shape[0]

def test_iforest_parallel_regression():
    """Check parallel regression."""
    rng = check_random_state(0)

    X_train, X_test, y_train, y_test = train_test_split(
        diabetes.data, diabetes.target, random_state=rng
    )

    ensemble = IsolationForest(n_jobs=3, random_state=0).fit(X_train)

    ensemble.set_params(n_jobs=1)
    y1 = ensemble.predict(X_test)
    ensemble.set_params(n_jobs=2)
    y2 = ensemble.predict(X_test)
    assert_array_almost_equal(y1, y2)

    ensemble = IsolationForest(n_jobs=1, random_state=0).fit(X_train)

    y3 = ensemble.predict(X_test)
    assert_array_almost_equal(y1, y3)

def test_iforest_performance():
    """Test Isolation Forest performs well"""

    # Generate train/test data
    rng = check_random_state(2)
    X = 0.3 * rng.randn(120, 2)
    X_train = np.r_[X + 2, X - 2]
    X_train = X[:100]

    # Generate some abnormal novel observations
    X_outliers = rng.uniform(low=-4, high=4, size=(20, 2))
    X_test = np.r_[X[100:], X_outliers]
    y_test = np.array([0] * 20 + [1] * 20)

    # fit the model
    clf = IsolationForest(max_samples=100, random_state=rng).fit(X_train)

    # predict scores (the lower, the more normal)
    y_pred = -clf.decision_function(X_test)

    # check that there is at most 6 errors (false positive or false negative)
    assert roc_auc_score(y_test, y_pred) > 0.98

@pytest.mark.parametrize("contamination", [0.25, "auto"])
def test_iforest_works(contamination):
    # toy sample (the last two samples are outliers)
    X = [[-2, -1], [-1, -1], [-1, -2], [1, 1], [1, 2], [2, 1], [6, 3], [-4, 7]]

    # Test IsolationForest
    clf = IsolationForest(random_state=rng, contamination=contamination)
    clf.fit(X)
    decision_func = -clf.decision_function(X)
    pred = clf.predict(X)
    # assert detect outliers:
    assert np.min(decision_func[-2:]) > np.max(decision_func[:-2])
    assert_array_equal(pred, 6 * [1] + 2 * [-1])

def test_max_samples_consistency():
    # Make sure validated max_samples in iforest and BaseBagging are identical
    X = iris.data
    clf = IsolationForest().fit(X)
    assert clf.max_samples_ == clf._max_samples

def test_iforest_subsampled_features():
    # It tests non-regression for #5732 which failed at predict.
    rng = check_random_state(0)
    X_train, X_test, y_train, y_test = train_test_split(
        diabetes.data[:50], diabetes.target[:50], random_state=rng
    )
    clf = IsolationForest(max_features=0.8)
    clf.fit(X_train, y_train)
    clf.predict(X_test)

def test_iforest_average_path_length():
    # It tests non-regression for #8549 which used the wrong formula
    # for average path length, strictly for the integer case
    # Updated to check average path length when input is <= 2 (issue #11839)
    result_one = 2.0 * (np.log(4.0) + np.euler_gamma) - 2.0 * 4.0 / 5.0
    result_two = 2.0 * (np.log(998.0) + np.euler_gamma) - 2.0 * 998.0 / 999.0
    assert_allclose(_average_path_length([0]), [0.0])
    assert_allclose(_average_path_length([1]), [0.0])
    assert_allclose(_average_path_length([2]), [1.0])
    assert_allclose(_average_path_length([5]), [result_one])
    assert_allclose(_average_path_length([999]), [result_two])
    assert_allclose(
        _average_path_length(np.array([1, 2, 5, 999])),
        [0.0, 1.0, result_one, result_two],
    )
    # _average_path_length is increasing
    avg_path_length = _average_path_length(np.arange(5))
    assert_array_equal(avg_path_length, np.sort(avg_path_length))

def test_score_samples():
    X_train = [[1, 1], [1, 2], [2, 1]]
    clf1 = IsolationForest(contamination=0.1).fit(X_train)
    clf2 = IsolationForest().fit(X_train)
    assert_array_equal(
        clf1.score_samples([[2.0, 2.0]]),
        clf1.decision_function([[2.0, 2.0]]) + clf1.offset_,
    )
    assert_array_equal(
        clf2.score_samples([[2.0, 2.0]]),
        clf2.decision_function([[2.0, 2.0]]) + clf2.offset_,
    )
    assert_array_equal(
        clf1.score_samples([[2.0, 2.0]]), clf2.score_samples([[2.0, 2.0]])
    )

def test_iforest_warm_start():
    """Test iterative addition of iTrees to an iForest"""

    rng = check_random_state(0)
    X = rng.randn(20, 2)

    # fit first 10 trees
    clf = IsolationForest(
        n_estimators=10, max_samples=20, random_state=rng, warm_start=True
    )
    clf.fit(X)
    # remember the 1st tree
    tree_1 = clf.estimators_[0]
    # fit another 10 trees
    clf.set_params(n_estimators=20)
    clf.fit(X)
    # expecting 20 fitted trees and no overwritten trees
    assert len(clf.estimators_) == 20
    assert clf.estimators_[0] is tree_1

# mock get_chunk_n_rows to actually test more than one chunk (here one
# chunk = 3 rows:
@patch(
    "sklearn.ensemble._iforest.get_chunk_n_rows",
    side_effect=Mock(**{"return_value": 3}),
)
@pytest.mark.parametrize("contamination, n_predict_calls", [(0.25, 3), ("auto", 2)])
def test_iforest_chunks_works1(mocked_get_chunk, contamination, n_predict_calls):
    test_iforest_works(contamination)
    assert mocked_get_chunk.call_count == n_predict_calls

# idem with chunk_size = 5 rows
@patch(
    "sklearn.ensemble._iforest.get_chunk_n_rows",
    side_effect=Mock(**{"return_value": 10}),
)
@pytest.mark.parametrize("contamination, n_predict_calls", [(0.25, 3), ("auto", 2)])
def test_iforest_chunks_works2(mocked_get_chunk, contamination, n_predict_calls):
    test_iforest_works(contamination)
    assert mocked_get_chunk.call_count == n_predict_calls

def test_iforest_with_uniform_data():
    """Test whether iforest predicts inliers when using uniform data"""

    # 2-d array of all 1s
    X = np.ones((100, 10))
    iforest = IsolationForest()
    iforest.fit(X)

    rng = np.random.RandomState(0)

    assert all(iforest.predict(X) == 1)
    assert all(iforest.predict(rng.randn(100, 10)) == 1)
    assert all(iforest.predict(X + 1) == 1)
    assert all(iforest.predict(X - 1) == 1)

    # 2-d array where columns contain the same value across rows
    X = np.repeat(rng.randn(1, 10), 100, 0)
    iforest = IsolationForest()
    iforest.fit(X)

    assert all(iforest.predict(X) == 1)
    assert all(iforest.predict(rng.randn(100, 10)) == 1)
    assert all(iforest.predict(np.ones((100, 10))) == 1)

    # Single row
    X = rng.randn(1, 10)
    iforest = IsolationForest()
    iforest.fit(X)

    assert all(iforest.predict(X) == 1)
    assert all(iforest.predict(rng.randn(100, 10)) == 1)
    assert all(iforest.predict(np.ones((100, 10))) == 1)

# FIXME: remove in 1.2
def test_n_features_deprecation():
    # Check that we raise the proper deprecation warning if accessing
    # `n_features_`.
    X = np.array([[1, 2], [3, 4]])
    y = np.array([1, 0])
    est = IsolationForest().fit(X, y)

    with pytest.warns(FutureWarning, match="`n_features_` was deprecated"):
        est.n_features_

def test_iforest_with_n_jobs_does_not_segfault():
    """Check that Isolation Forest does not segfault with n_jobs=2

    Non-regression test for #23252
    """
    X, _ = make_classification(n_samples=85_000, n_features=100, random_state=0)
    X = csc_matrix(X)
    IsolationForest(n_estimators=10, max_samples=256, n_jobs=2).fit(X)
<commit_msg>TST use global_random_seed in sklearn/ensemble/tests/test_iforest.py (#22901)<commit_after>"""
Testing for Isolation Forest algorithm (sklearn.ensemble.iforest).
"""

# Authors: Nicolas Goix <nicolas.goix@telecom-paristech.fr>
#          Alexandre Gramfort <alexandre.gramfort@telecom-paristech.fr>
# License: BSD 3 clause

import pytest
import warnings

import numpy as np

from sklearn.utils._testing import assert_array_equal
from sklearn.utils._testing import assert_array_almost_equal
from sklearn.utils._testing import ignore_warnings
from sklearn.utils._testing import assert_allclose

from sklearn.model_selection import ParameterGrid
from sklearn.ensemble import IsolationForest
from sklearn.ensemble._iforest import _average_path_length
from sklearn.model_selection import train_test_split
from sklearn.datasets import load_diabetes, load_iris, make_classification
from sklearn.utils import check_random_state
from sklearn.metrics import roc_auc_score

from scipy.sparse import csc_matrix, csr_matrix
from unittest.mock import Mock, patch

# load iris & diabetes dataset
iris = load_iris()
diabetes = load_diabetes()

def test_iforest(global_random_seed):
    """Check Isolation Forest for various parameter settings."""
    X_train = np.array([[0, 1], [1, 2]])
    X_test = np.array([[2, 1], [1, 1]])

    grid = ParameterGrid(
        {"n_estimators": [3], "max_samples": [0.5, 1.0, 3], "bootstrap": [True, False]}
    )

    with ignore_warnings():
        for params in grid:
            IsolationForest(random_state=global_random_seed, **params).fit(
                X_train
            ).predict(X_test)

def test_iforest_sparse(global_random_seed):
    """Check IForest for various parameter settings on sparse input."""
    rng = check_random_state(global_random_seed)
    X_train, X_test = train_test_split(diabetes.data[:50], random_state=rng)
    grid = ParameterGrid({"max_samples": [0.5, 1.0], "bootstrap": [True, False]})

    for sparse_format in [csc_matrix, csr_matrix]:
        X_train_sparse = sparse_format(X_train)
        X_test_sparse = sparse_format(X_test)

        for params in grid:
            # Trained on sparse format
            sparse_classifier = IsolationForest(
                n_estimators=10, random_state=global_random_seed, **params
            ).fit(X_train_sparse)
            sparse_results = sparse_classifier.predict(X_test_sparse)

            # Trained on dense format
            dense_classifier = IsolationForest(
                n_estimators=10, random_state=global_random_seed, **params
            ).fit(X_train)
            dense_results = dense_classifier.predict(X_test)

            assert_array_equal(sparse_results, dense_results)

def test_iforest_error():
    """Test that it gives proper exception on deficient input."""
    X = iris.data

    # Test max_samples
    with pytest.raises(ValueError):
        IsolationForest(max_samples=-1).fit(X)
    with pytest.raises(ValueError):
        IsolationForest(max_samples=0.0).fit(X)
    with pytest.raises(ValueError):
        IsolationForest(max_samples=2.0).fit(X)
    # The dataset has less than 256 samples, explicitly setting
    # max_samples > n_samples should result in a warning. If not set
    # explicitly there should be no warning
    warn_msg = "max_samples will be set to n_samples for estimation"
    with pytest.warns(UserWarning, match=warn_msg):
        IsolationForest(max_samples=1000).fit(X)
    with warnings.catch_warnings():
        warnings.simplefilter("error", UserWarning)
        IsolationForest(max_samples="auto").fit(X)
    with warnings.catch_warnings():
        warnings.simplefilter("error", UserWarning)
        IsolationForest(max_samples=np.int64(2)).fit(X)

    with pytest.raises(ValueError):
        IsolationForest(max_samples="foobar").fit(X)
    with pytest.raises(ValueError):
        IsolationForest(max_samples=1.5).fit(X)

    # test X_test n_features match X_train one:
    with pytest.raises(ValueError):
        IsolationForest().fit(X).predict(X[:, 1:])

def test_recalculate_max_depth():
    """Check max_depth recalculation when max_samples is reset to n_samples"""
    X = iris.data
    clf = IsolationForest().fit(X)
    for est in clf.estimators_:
        assert est.max_depth == int(np.ceil(np.log2(X.shape[0])))

def test_max_samples_attribute():
    X = iris.data
    clf = IsolationForest().fit(X)
    assert clf.max_samples_ == X.shape[0]

    clf = IsolationForest(max_samples=500)
    warn_msg = "max_samples will be set to n_samples for estimation"
    with pytest.warns(UserWarning, match=warn_msg):
        clf.fit(X)
    assert clf.max_samples_ == X.shape[0]

    clf = IsolationForest(max_samples=0.4).fit(X)
    assert clf.max_samples_ == 0.4 * X.shape[0]

def test_iforest_parallel_regression(global_random_seed):
    """Check parallel regression."""
    rng = check_random_state(global_random_seed)

    X_train, X_test = train_test_split(diabetes.data, random_state=rng)

    ensemble = IsolationForest(n_jobs=3, random_state=global_random_seed).fit(X_train)

    ensemble.set_params(n_jobs=1)
    y1 = ensemble.predict(X_test)
    ensemble.set_params(n_jobs=2)
    y2 = ensemble.predict(X_test)
    assert_array_almost_equal(y1, y2)

    ensemble = IsolationForest(n_jobs=1, random_state=global_random_seed).fit(X_train)

    y3 = ensemble.predict(X_test)
    assert_array_almost_equal(y1, y3)

def test_iforest_performance(global_random_seed):
    """Test Isolation Forest performs well"""

    # Generate train/test data
    rng = check_random_state(global_random_seed)
    X = 0.3 * rng.randn(600, 2)
    X = rng.permutation(np.vstack((X + 2, X - 2)))
    X_train = X[:1000]

    # Generate some abnormal novel observations
    X_outliers = rng.uniform(low=-1, high=1, size=(200, 2))
    X_test = np.vstack((X[1000:], X_outliers))
    y_test = np.array([0] * 200 + [1] * 200)

    # fit the model
    clf = IsolationForest(max_samples=100, random_state=rng).fit(X_train)

    # predict scores (the lower, the more normal)
    y_pred = -clf.decision_function(X_test)

    # check that there is at most 6 errors (false positive or false negative)
    assert roc_auc_score(y_test, y_pred) > 0.98

@pytest.mark.parametrize("contamination", [0.25, "auto"])
def test_iforest_works(contamination, global_random_seed):
    # toy sample (the last two samples are outliers)
    X = [[-2, -1], [-1, -1], [-1, -2], [1, 1], [1, 2], [2, 1], [7, 4], [-5, 9]]

    # Test IsolationForest
    clf = IsolationForest(random_state=global_random_seed, contamination=contamination)
    clf.fit(X)
    decision_func = -clf.decision_function(X)
    pred = clf.predict(X)
    # assert detect outliers:
    assert np.min(decision_func[-2:]) > np.max(decision_func[:-2])
    assert_array_equal(pred, 6 * [1] + 2 * [-1])

def test_max_samples_consistency():
    # Make sure validated max_samples in iforest and BaseBagging are identical
    X = iris.data
    clf = IsolationForest().fit(X)
    assert clf.max_samples_ == clf._max_samples

def test_iforest_subsampled_features():
    # It tests non-regression for #5732 which failed at predict.
    rng = check_random_state(0)
    X_train, X_test, y_train, y_test = train_test_split(
        diabetes.data[:50], diabetes.target[:50], random_state=rng
    )
    clf = IsolationForest(max_features=0.8)
    clf.fit(X_train, y_train)
    clf.predict(X_test)

def test_iforest_average_path_length():
    # It tests non-regression for #8549 which used the wrong formula
    # for average path length, strictly for the integer case
    # Updated to check average path length when input is <= 2 (issue #11839)
    result_one = 2.0 * (np.log(4.0) + np.euler_gamma) - 2.0 * 4.0 / 5.0
    result_two = 2.0 * (np.log(998.0) + np.euler_gamma) - 2.0 * 998.0 / 999.0
    assert_allclose(_average_path_length([0]), [0.0])
    assert_allclose(_average_path_length([1]), [0.0])
    assert_allclose(_average_path_length([2]), [1.0])
    assert_allclose(_average_path_length([5]), [result_one])
    assert_allclose(_average_path_length([999]), [result_two])
    assert_allclose(
        _average_path_length(np.array([1, 2, 5, 999])),
        [0.0, 1.0, result_one, result_two],
    )
    # _average_path_length is increasing
    avg_path_length = _average_path_length(np.arange(5))
    assert_array_equal(avg_path_length, np.sort(avg_path_length))

def test_score_samples():
    X_train = [[1, 1], [1, 2], [2, 1]]
    clf1 = IsolationForest(contamination=0.1).fit(X_train)
    clf2 = IsolationForest().fit(X_train)
    assert_array_equal(
        clf1.score_samples([[2.0, 2.0]]),
        clf1.decision_function([[2.0, 2.0]]) + clf1.offset_,
    )
    assert_array_equal(
        clf2.score_samples([[2.0, 2.0]]),
        clf2.decision_function([[2.0, 2.0]]) + clf2.offset_,
    )
    assert_array_equal(
        clf1.score_samples([[2.0, 2.0]]), clf2.score_samples([[2.0, 2.0]])
    )

def test_iforest_warm_start():
    """Test iterative addition of iTrees to an iForest"""

    rng = check_random_state(0)
    X = rng.randn(20, 2)

    # fit first 10 trees
    clf = IsolationForest(
        n_estimators=10, max_samples=20, random_state=rng, warm_start=True
    )
    clf.fit(X)
    # remember the 1st tree
    tree_1 = clf.estimators_[0]
    # fit another 10 trees
    clf.set_params(n_estimators=20)
    clf.fit(X)
    # expecting 20 fitted trees and no overwritten trees
    assert len(clf.estimators_) == 20
    assert clf.estimators_[0] is tree_1

# mock get_chunk_n_rows to actually test more than one chunk (here one
# chunk has 3 rows):
@patch(
    "sklearn.ensemble._iforest.get_chunk_n_rows",
    side_effect=Mock(**{"return_value": 3}),
)
@pytest.mark.parametrize("contamination, n_predict_calls", [(0.25, 3), ("auto", 2)])
def test_iforest_chunks_works1(
    mocked_get_chunk, contamination, n_predict_calls, global_random_seed
):
    test_iforest_works(contamination, global_random_seed)
    assert mocked_get_chunk.call_count == n_predict_calls

# idem with chunk_size = 10 rows
@patch(
    "sklearn.ensemble._iforest.get_chunk_n_rows",
    side_effect=Mock(**{"return_value": 10}),
)
@pytest.mark.parametrize("contamination, n_predict_calls", [(0.25, 3), ("auto", 2)])
def test_iforest_chunks_works2(
    mocked_get_chunk, contamination, n_predict_calls, global_random_seed
):
    test_iforest_works(contamination, global_random_seed)
    assert mocked_get_chunk.call_count == n_predict_calls

def test_iforest_with_uniform_data():
    """Test whether iforest predicts inliers when using uniform data"""

    # 2-d array of all 1s
    X = np.ones((100, 10))
    iforest = IsolationForest()
    iforest.fit(X)

    rng = np.random.RandomState(0)

    assert all(iforest.predict(X) == 1)
    assert all(iforest.predict(rng.randn(100, 10)) == 1)
    assert all(iforest.predict(X + 1) == 1)
    assert all(iforest.predict(X - 1) == 1)

    # 2-d array where columns contain the same value across rows
    X = np.repeat(rng.randn(1, 10), 100, 0)
    iforest = IsolationForest()
    iforest.fit(X)

    assert all(iforest.predict(X) == 1)
    assert all(iforest.predict(rng.randn(100, 10)) == 1)
    assert all(iforest.predict(np.ones((100, 10))) == 1)

    # Single row
    X = rng.randn(1, 10)
    iforest = IsolationForest()
    iforest.fit(X)

    assert all(iforest.predict(X) == 1)
    assert all(iforest.predict(rng.randn(100, 10)) == 1)
    assert all(iforest.predict(np.ones((100, 10))) == 1)

# FIXME: remove in 1.2
def test_n_features_deprecation():
    # Check that we raise the proper deprecation warning if accessing
    # `n_features_`.
    X = np.array([[1, 2], [3, 4]])
    y = np.array([1, 0])
    est = IsolationForest().fit(X, y)

    with pytest.warns(FutureWarning, match="`n_features_` was deprecated"):
        est.n_features_

def test_iforest_with_n_jobs_does_not_segfault():
    """Check that Isolation Forest does not segfault with n_jobs=2

    Non-regression test for #23252
    """
    X, _ = make_classification(n_samples=85_000, n_features=100, random_state=0)
    X = csc_matrix(X)
    IsolationForest(n_estimators=10, max_samples=256, n_jobs=2).fit(X)
<|endoftext|>


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

from __future__ import absolute_import, unicode_literals

import logging

import six

__all__ = ['generated_symbols']

def generated_symbols(code):
    from soapfish import xsd  # import may not be generated.

    locals_ = dict(locals())

    try:
        # Let's trust our own code generation...
        six.exec_(code, {'xsd': xsd}, locals_)
    except Exception:
        logging.warning('Code could not be imported:\n%s', code)
        raise

    variables = set(locals_).difference(locals())

    schemas, symbols = [], {}
    for name in variables:
        symbol = locals_[name]
        symbols[name] = symbol
        if isinstance(symbol, xsd.Schema):
            schemas.append(symbol)
    return schemas, symbols
<commit_msg>testutil: fix non-deterministic test failures.<commit_after># -*- coding: utf-8 -*-

from __future__ import absolute_import, unicode_literals

import logging

import six

__all__ = ['generated_symbols']

def generated_symbols(code):
    from soapfish import xsd  # import may not be generated.

    locals_ = dict(locals())

    try:
        # Let's trust our own code generation...
        six.exec_(code, {'xsd': xsd}, locals_)
    except Exception:
        logging.warning('Code could not be imported:\n%s', code)
        raise

    variables = set(locals_).difference(locals())

    schemas, symbols = [], {}
    for name in sorted(variables):
        symbol = locals_[name]
        symbols[name] = symbol
        if isinstance(symbol, xsd.Schema):
            schemas.append(symbol)
    return schemas, symbols
<|endoftext|>