<commit_before>#------------------------------------------------------------------------------
#
#  Copyright (c) 2005, Enthought, Inc.
#  All rights reserved.
#
#  This software is provided without warranty under the terms of the BSD
#  license included in enthought/LICENSE.txt and may be redistributed only
#  under the conditions described in the aforementioned license.  The license
#  is also available online at http://www.enthought.com/licenses/BSD.txt
#
#  Thanks for using Enthought open source!
#
#  Author: Enthought, Inc.
#
#------------------------------------------------------------------------------

""" Enthought pyface package component
"""

# Major package imports.
from IPython.frontend.wx.wx_frontend import WxController
from IPython.kernel.core.interpreter import Interpreter
import wx
import re
import sys

# Enthought library imports.
from enthought.traits.api import Event, implements, Instance, Str

# Private Enthought library imports.
from enthought.util.clean_strings import python_name
from enthought.util.wx.drag_and_drop import PythonDropTarget
from enthought.io.file import File as EnthoughtFile

# Local imports.
from enthought.pyface.i_python_shell import IPythonShell
from enthought.pyface.key_pressed_event import KeyPressedEvent
from widget import Widget

################################################################################
class IPythonController(WxController):
    """ Subclass the IPython WxController

        This class should probably be moved in the IPython codebase.
    """
    # In the parent class, this is a property that expects the
    # container to be a frame, thus it fails when modified.
    # The title of the IPython windows (not displayed in Envisage)
    title = Str

    # Cached value of the banner for the IPython shell.
    # NOTE: The WxController object (declared in wx_frontend module) contains
    # a 'banner' attribute. If this is None, WxController sets the
    # banner = IPython banner + an additional string ("This is the wx
    # frontend, by Gael Varoquaux. This is EXPERIMENTAL code."). We want to
    # set banner = the IPython banner. This means 'banner' needs to be
    # a property, since in the __init__ method of WxController, the IPython
    # shell object is created AND started (meaning the banner is written to
    # stdout).
    _banner = None

    def _get_banner(self):
        """ Returns the IPython banner.
        """
        if self._banner is None:
            # 'ipython0' gets set in the __init__ method of the base class.
            if getattr(self, 'ipython0', None):
                self._banner = self.ipython0.BANNER
        return self._banner

    def _set_banner(self, value):
        self._banner = value
        return

    banner = property(_get_banner, _set_banner)

    def __init__(self, *args, **kwargs):
        WxController.__init__(self, *args, **kwargs)

        # Add a magic to clear the screen
        def cls(args):
            """ Clear the screen.
            """
            self.ClearAll()
        self.ipython0.magic_cls = cls

        # XXX: This is bugware for IPython bug:
        # https://bugs.launchpad.net/ipython/+bug/270998
        # Fix all the magics with no docstrings:
        for funcname in dir(self.ipython0):
            if not funcname.startswith('magic'):
                continue
            func = getattr(self.ipython0, funcname)
            if func.__doc__ is None:
                func.__doc__ = ''

    def complete(self, line):
        """ Returns a list of possible completions for line.
        Overridden from the base class implementation to fix bugs in retrieving
        the completion text from line.

        """

        completion_text = self._get_completion_text(line)
        suggestion, completions = super(IPythonController, self).complete(
                                                            completion_text)
        new_line = line[:-len(completion_text)] + suggestion
        return new_line, completions

    def execute_command(self, command, hidden=False):
        """ Execute a command, not only in the model, but also in the
            view.
        """
        # XXX: This needs to be moved to the IPython codebase.
        if hidden:
            return self.shell.execute(command)
        else:
            # XXX: we are not storing the input buffer previous to the
            # execution, as this forces us to run the execution
            # input_buffer a yield, which is not good.
            ##current_buffer = self.shell.control.input_buffer
            command = command.rstrip()
            if len(command.split('\n')) > 1:
                # The input command is several lines long, we need to
                # force the execution to happen
                command += '\n'
            cleaned_command = self.prefilter_input(command)
            self.input_buffer = command
            # Do not use wx.Yield() (aka GUI.process_events()) to avoid
            # recursive yields.
            self.ProcessEvent(wx.PaintEvent())
            self.write('\n')
            if not self.is_complete(cleaned_command + '\n'):
                self._colorize_input_buffer()
                self.render_error('Incomplete or invalid input')
                self.new_prompt(self.input_prompt_template.substitute(
                                number=(self.last_result['number'] + 1)))
                return False
            self._on_enter()
            return True

    def clear_screen(self):
        """ Empty completely the widget.
        """
        self.ClearAll()
        self.new_prompt(self.input_prompt_template.substitute(
                                number=(self.last_result['number'] + 1)))

    def _popup_completion(self, create=False):
        """ Updates the popup completion menu if it exists. If create is
            true, open the menu.
            Overridden from the base class implementation to filter out
            delimiters from the input buffer.
        """

        # FIXME: The implementation in the base class (wx_frontend.py in
        # IPython/wx/frontend) is faulty in that it doesn't filter out
        # special characters (such as parentheses, '=') in the input buffer
        # correctly.
        # For example, (a): typing 's=re.' does not pop up the menu.
        # (b): typing 'x[0].' brings up a menu for x[0] but the offset is
        # incorrect and so, upon selection from the menu, the text is pasted
        # incorrectly.
        # I am patching this here instead of in the IPython module, but at some
        # point, this needs to be merged in.
        if self.debug:
            print >>sys.__stdout__, "_popup_completion" , self.input_buffer

        line = self.input_buffer
        if (self.AutoCompActive() and line and not line[-1] == '.') \
                    or create==True:
            suggestion, completions = self.complete(line)
            if completions:
                offset = len(self._get_completion_text(line))
                self.pop_completion(completions, offset=offset)
                if self.debug:
                    print >>sys.__stdout__, completions

    def _get_completion_text(self, line):
        """ Returns the text to be completed by breaking the line at specified
        delimiters.
        """
        # Break at: spaces, '=', all parentheses (except if balanced).
        # FIXME2: In the future, we need to make the implementation similar to
        # that in the 'pyreadline' module (modes/basemode.py) where we break at
        # each delimiter and try to complete the residual line, until we get a
        # successful list of completions.
        expression = '\s|=|,|:|\((?!.*\))|\[(?!.*\])|\{(?!.*\})'
        complete_sep = re.compile(expression)
        text = complete_sep.split(line)[-1]
        return text

################################################################################
class IPythonWidget(Widget):
    """ The toolkit specific implementation of a PythonShell.  See the
    IPythonShell interface for the API documentation.
    """

    implements(IPythonShell)

    #### 'IPythonShell' interface #############################################

    command_executed = Event

    key_pressed = Event(KeyPressedEvent)

    #### 'IPythonWidget' interface ############################################

    interp = Instance(Interpreter, ())

    ###########################################################################
    # 'object' interface.
    ###########################################################################

    # FIXME v3: Either make this API consistent with other Widget sub-classes
    # or make it a sub-class of HasTraits.
    def __init__(self, parent, **traits):
        """ Creates a new pager. """

        # Base class constructor.
        super(IPythonWidget, self).__init__(**traits)

        # Create the toolkit-specific control that represents the widget.
        self.control = self._create_control(parent)

    ###########################################################################
    # 'IPythonShell' interface.
    ###########################################################################

    def interpreter(self):
        return self.interp

    def execute_command(self, command, hidden=False):
        self.control.execute_command(command, hidden=hidden)
        self.command_executed = True

    ###########################################################################
    # Protected 'IWidget' interface.
    ###########################################################################

    def _create_control(self, parent):
        shell = IPythonController(parent, -1, shell=self.interp)

        # Listen for key press events.
        wx.EVT_CHAR(shell, self._wx_on_char)

        # Enable the shell as a drag and drop target.
        shell.SetDropTarget(PythonDropTarget(self))

        return shell

    ###########################################################################
    # 'PythonDropTarget' handler interface.
    ###########################################################################

    def on_drop(self, x, y, obj, default_drag_result):
        """ Called when a drop occurs on the shell. """

        # If this is a file, we'll just print the file name
        if isinstance(obj, EnthoughtFile):
            self.control.write(obj.absolute_path)

        elif ( isinstance(obj, list) and len(obj) ==1
                        and isinstance(obj[0], EnthoughtFile)):
            self.control.write(obj[0].absolute_path)

        else:
            # Not a file, we'll inject the object in the namespace
            # If we can't create a valid Python identifier for the name of an
            # object we use this instead.
            name = 'dragged'

            if hasattr(obj, 'name') \
                    and isinstance(obj.name, basestring) and len(obj.name) > 0:
                py_name = python_name(obj.name)

                # Make sure that the name is actually a valid Python identifier.
                try:
                    if eval(py_name, {py_name : True}):
                        name = py_name

                except:
                    pass

            self.interp.user_ns[name] = obj
            self.execute_command(name, hidden=False)
        self.control.SetFocus()

        # We always copy into the shell since we don't want the data
        # removed from the source
        return wx.DragCopy

    def on_drag_over(self, x, y, obj, default_drag_result):
        """ Always returns wx.DragCopy to indicate we will be doing a copy."""
        return wx.DragCopy

    ###########################################################################
    # Private handler interface.
    ###########################################################################

    def _wx_on_char(self, event):
        """ Called whenever a change is made to the text of the document. """

        self.key_pressed = KeyPressedEvent(
            alt_down     = event.m_altDown == 1,
            control_down = event.m_controlDown == 1,
            shift_down   = event.m_shiftDown == 1,
            key_code     = event.m_keyCode,
            event        = event
        )

        # Give other event handlers a chance.
        event.Skip()

        return

#### EOF ######################################################################
<commit_msg>Add continuation prompts ('...') to input buffers. Fix bug with using '\' in multi-line commands.<commit_after>#------------------------------------------------------------------------------
#
#  Copyright (c) 2005, Enthought, Inc.
#  All rights reserved.
#
#  This software is provided without warranty under the terms of the BSD
#  license included in enthought/LICENSE.txt and may be redistributed only
#  under the conditions described in the aforementioned license.  The license
#  is also available online at http://www.enthought.com/licenses/BSD.txt
#
#  Thanks for using Enthought open source!
#
#  Author: Enthought, Inc.
#
#------------------------------------------------------------------------------

""" Enthought pyface package component
"""

# Major package imports.
from IPython.frontend.wx.wx_frontend import WxController
from IPython.kernel.core.interpreter import Interpreter
import wx
import re
import sys
import codeop

# Enthought library imports.
from enthought.traits.api import Event, implements, Instance, Str

# Private Enthought library imports.
from enthought.util.clean_strings import python_name
from enthought.util.wx.drag_and_drop import PythonDropTarget
from enthought.io.file import File as EnthoughtFile

# Local imports.
from enthought.pyface.i_python_shell import IPythonShell
from enthought.pyface.key_pressed_event import KeyPressedEvent
from widget import Widget

################################################################################
class IPythonController(WxController):
    """ Subclass the IPython WxController

        This class should probably be moved in the IPython codebase.
    """
    # In the parent class, this is a property that expects the
    # container to be a frame, thus it fails when modified.
    # The title of the IPython windows (not displayed in Envisage)
    title = Str

    # Cached value of the banner for the IPython shell.
    # NOTE: The WxController object (declared in wx_frontend module) contains
    # a 'banner' attribute. If this is None, WxController sets the
    # banner = IPython banner + an additional string ("This is the wx
    # frontend, by Gael Varoquaux. This is EXPERIMENTAL code."). We want to
    # set banner = the IPython banner. This means 'banner' needs to be
    # a property, since in the __init__ method of WxController, the IPython
    # shell object is created AND started (meaning the banner is written to
    # stdout).
    _banner = None

    def _get_banner(self):
        """ Returns the IPython banner.
        """
        if self._banner is None:
            # 'ipython0' gets set in the __init__ method of the base class.
            if getattr(self, 'ipython0', None):
                self._banner = self.ipython0.BANNER
        return self._banner

    def _set_banner(self, value):
        self._banner = value
        return

    banner = property(_get_banner, _set_banner)

    def __init__(self, *args, **kwargs):
        WxController.__init__(self, *args, **kwargs)

        # Add a magic to clear the screen
        def cls(args):
            """ Clear the screen.
            """
            self.ClearAll()
        self.ipython0.magic_cls = cls

        # XXX: This is bugware for IPython bug:
        # https://bugs.launchpad.net/ipython/+bug/270998
        # Fix all the magics with no docstrings:
        for funcname in dir(self.ipython0):
            if not funcname.startswith('magic'):
                continue
            func = getattr(self.ipython0, funcname)
            if func.__doc__ is None:
                func.__doc__ = ''

    def complete(self, line):
        """ Returns a list of possible completions for line.
        Overridden from the base class implementation to fix bugs in retrieving
        the completion text from line.

        """

        completion_text = self._get_completion_text(line)
        suggestion, completions = super(IPythonController, self).complete(
                                                            completion_text)
        new_line = line[:-len(completion_text)] + suggestion
        return new_line, completions

    def is_complete(self, string):
        """ Check if a string forms a complete, executable set of
        commands.

        For the line-oriented frontend, multi-line code is not executed
        as soon as it is complete: the users has to enter two line
        returns.

        Overridden from the base class (linefrontendbase.py in IPython\frontend
        to handle a bug with using the '\' symbol in multi-line inputs.
        """

        # FIXME: There has to be a nicer way to do this. Th code is
        # identical to the base class implementation, except for the if ..
        # statement on line 146.
        if string in ('', '\n'):
            # Prefiltering, eg through ipython0, may return an empty
            # string although some operations have been accomplished. We
            # thus want to consider an empty string as a complete
            # statement.
            return True
        elif ( len(self.input_buffer.split('\n'))>2
                        and not re.findall(r"\n[\t ]*\n[\t ]*$", string)):
            return False
        else:
            self.capture_output()
            try:
                # Add line returns here, to make sure that the statement is
                # complete (except if '\' was used).
                # This should probably be done in a different place (like
                # maybe 'prefilter_input' method? For now, this works.
                clean_string = string.rstrip('\n')
                if not clean_string.endswith('\\'): clean_string +='\n\n'
                is_complete = codeop.compile_command(clean_string,
                            "<string>", "exec")
                self.release_output()
            except Exception, e:
                # XXX: Hack: return True so that the
                # code gets executed and the error captured.
                is_complete = True
            return is_complete

    def execute_command(self, command, hidden=False):
        """ Execute a command, not only in the model, but also in the
            view.
        """
        # XXX: This needs to be moved to the IPython codebase.
        if hidden:
            return self.shell.execute(command)
        else:
            # XXX: we are not storing the input buffer previous to the
            # execution, as this forces us to run the execution
            # input_buffer a yield, which is not good.
            ##current_buffer = self.shell.control.input_buffer
            command = command.rstrip()
            if len(command.split('\n')) > 1:
                # The input command is several lines long, we need to
                # force the execution to happen
                command += '\n'
            cleaned_command = self.prefilter_input(command)
            self.input_buffer = command
            # Do not use wx.Yield() (aka GUI.process_events()) to avoid
            # recursive yields.
            self.ProcessEvent(wx.PaintEvent())
            self.write('\n')
            if not self.is_complete(cleaned_command + '\n'):
                self._colorize_input_buffer()
                self.render_error('Incomplete or invalid input')
                self.new_prompt(self.input_prompt_template.substitute(
                                number=(self.last_result['number'] + 1)))
                return False
            self._on_enter()
            return True

    def clear_screen(self):
        """ Empty completely the widget.
        """
        self.ClearAll()
        self.new_prompt(self.input_prompt_template.substitute(
                                number=(self.last_result['number'] + 1)))

    def continuation_prompt(self):
        """Returns the current continuation prompt.
        Overridden to generate a continuation prompt matching the length of the
        current prompt."""

        # FIXME: This is a bad hack.. I need to find a way to use the 'Prompt2'
        # class in IPython/kernel/prompts.py. Basically, I am trying to get the
        # length of the current prompt ("In ['number']").
        return ("."*(6+self.last_result['number']/10) + ':')

    def _popup_completion(self, create=False):
        """ Updates the popup completion menu if it exists. If create is
            true, open the menu.
            Overridden from the base class implementation to filter out
            delimiters from the input buffer.
        """

        # FIXME: The implementation in the base class (wx_frontend.py in
        # IPython/wx/frontend) is faulty in that it doesn't filter out
        # special characters (such as parentheses, '=') in the input buffer
        # correctly.
        # For example, (a): typing 's=re.' does not pop up the menu.
        # (b): typing 'x[0].' brings up a menu for x[0] but the offset is
        # incorrect and so, upon selection from the menu, the text is pasted
        # incorrectly.
        # I am patching this here instead of in the IPython module, but at some
        # point, this needs to be merged in.
        if self.debug:
            print >>sys.__stdout__, "_popup_completion" , self.input_buffer

        line = self.input_buffer
        if (self.AutoCompActive() and line and not line[-1] == '.') \
                    or create==True:
            suggestion, completions = self.complete(line)
            if completions:
                offset = len(self._get_completion_text(line))
                self.pop_completion(completions, offset=offset)
                if self.debug:
                    print >>sys.__stdout__, completions

    def _get_completion_text(self, line):
        """ Returns the text to be completed by breaking the line at specified
        delimiters.
        """
        # Break at: spaces, '=', all parentheses (except if balanced).
        # FIXME2: In the future, we need to make the implementation similar to
        # that in the 'pyreadline' module (modes/basemode.py) where we break at
        # each delimiter and try to complete the residual line, until we get a
        # successful list of completions.
        expression = '\s|=|,|:|\((?!.*\))|\[(?!.*\])|\{(?!.*\})'
        complete_sep = re.compile(expression)
        text = complete_sep.split(line)[-1]
        return text

    def _on_enter(self):
        """ Called when the return key is pressed in a line editing
            buffer.
            Overridden from the base class implementation (in
            IPython/frontend/linefrontendbase.py) to include a continuation
            prompt.
        """
        current_buffer = self.input_buffer
        cleaned_buffer = self.prefilter_input(current_buffer.replace(
                                            self.continuation_prompt(),
                                            ''))
        if self.is_complete(cleaned_buffer):
            self.execute(cleaned_buffer, raw_string=current_buffer)
        else:
            self.input_buffer = current_buffer + \
                                self.continuation_prompt() + \
                                self._get_indent_string(current_buffer.replace(
                                            self.continuation_prompt(),
                                            '')[:-1])
            if len(current_buffer.split('\n')) == 2:
                self.input_buffer += '\t\t'
            if current_buffer[:-1].split('\n')[-1].rstrip().endswith(':'):
                self.input_buffer += '\t'

################################################################################
class IPythonWidget(Widget):
    """ The toolkit specific implementation of a PythonShell.  See the
    IPythonShell interface for the API documentation.
    """

    implements(IPythonShell)

    #### 'IPythonShell' interface #############################################

    command_executed = Event

    key_pressed = Event(KeyPressedEvent)

    #### 'IPythonWidget' interface ############################################

    interp = Instance(Interpreter, ())

    ###########################################################################
    # 'object' interface.
    ###########################################################################

    # FIXME v3: Either make this API consistent with other Widget sub-classes
    # or make it a sub-class of HasTraits.
    def __init__(self, parent, **traits):
        """ Creates a new pager. """

        # Base class constructor.
        super(IPythonWidget, self).__init__(**traits)

        # Create the toolkit-specific control that represents the widget.
        self.control = self._create_control(parent)

    ###########################################################################
    # 'IPythonShell' interface.
    ###########################################################################

    def interpreter(self):
        return self.interp

    def execute_command(self, command, hidden=False):
        self.control.execute_command(command, hidden=hidden)
        self.command_executed = True

    ###########################################################################
    # Protected 'IWidget' interface.
    ###########################################################################

    def _create_control(self, parent):
        shell = IPythonController(parent, -1, shell=self.interp)

        # Listen for key press events.
        wx.EVT_CHAR(shell, self._wx_on_char)

        # Enable the shell as a drag and drop target.
        shell.SetDropTarget(PythonDropTarget(self))

        return shell

    ###########################################################################
    # 'PythonDropTarget' handler interface.
    ###########################################################################

    def on_drop(self, x, y, obj, default_drag_result):
        """ Called when a drop occurs on the shell. """

        # If this is a file, we'll just print the file name
        if isinstance(obj, EnthoughtFile):
            self.control.write(obj.absolute_path)

        elif ( isinstance(obj, list) and len(obj) ==1
                        and isinstance(obj[0], EnthoughtFile)):
            self.control.write(obj[0].absolute_path)

        else:
            # Not a file, we'll inject the object in the namespace
            # If we can't create a valid Python identifier for the name of an
            # object we use this instead.
            name = 'dragged'

            if hasattr(obj, 'name') \
                    and isinstance(obj.name, basestring) and len(obj.name) > 0:
                py_name = python_name(obj.name)

                # Make sure that the name is actually a valid Python identifier.
                try:
                    if eval(py_name, {py_name : True}):
                        name = py_name

                except:
                    pass

            self.interp.user_ns[name] = obj
            self.execute_command(name, hidden=False)
        self.control.SetFocus()

        # We always copy into the shell since we don't want the data
        # removed from the source
        return wx.DragCopy

    def on_drag_over(self, x, y, obj, default_drag_result):
        """ Always returns wx.DragCopy to indicate we will be doing a copy."""
        return wx.DragCopy

    ###########################################################################
    # Private handler interface.
    ###########################################################################

    def _wx_on_char(self, event):
        """ Called whenever a change is made to the text of the document. """

        self.key_pressed = KeyPressedEvent(
            alt_down     = event.m_altDown == 1,
            control_down = event.m_controlDown == 1,
            shift_down   = event.m_shiftDown == 1,
            key_code     = event.m_keyCode,
            event        = event
        )

        # Give other event handlers a chance.
        event.Skip()

        return

#### EOF ######################################################################
<|endoftext|>


<commit_before>import json
import unittest

from alerta.app import app, db

class AppTestCase(unittest.TestCase):

    def setUp(self):

        app.config['TESTING'] = True
        app.config['AUTH_REQUIRED'] = True
        self.app = app.test_client()

        self.alert = {
            'event': 'Foo',
            'resource': 'Bar',
            'environment': 'Production',
            'service': ['Quux']
        }

        self.api_key = db.create_key('demo-key', type='read-write', text='demo-key')

    def tearDown(self):

        pass

    def test_401_error(self):

        response = self.app.get('/alerts')
        self.assertEqual(response.status_code, 401)

    def test_readwrite_key(self):

        headers = {
            'Authorization': 'Key %s' % self.api_key,
            'Content-type': 'application/json'
        }
        payload = {
            'user': 'rw-demo-key',
            'type': 'read-write'
        }

        response = self.app.post('/key', data=json.dumps(payload), headers=headers)
        self.assertEqual(response.status_code, 201)
        data = json.loads(response.data)
        self.assertIsNotNone(data['key'], 'Failed to create read-only key')

        read_write_key = data['key']

        response = self.app.post('/alert', data=json.dumps(self.alert), headers={'Authorization': 'Key ' + read_write_key})
        self.assertEqual(response.status_code, 201)

        response = self.app.get('/alerts', headers={'Authorization': 'Key ' + read_write_key})
        self.assertEqual(response.status_code, 200)
        data = json.loads(response.data)
        self.assertGreater(data['total'], 1, "total alerts > 1")

        response = self.app.delete('/key/' + read_write_key, headers={'Authorization': 'Key ' + self.api_key})
        self.assertEqual(response.status_code, 200)

    def test_readonly_key(self):

        headers = {
            'Authorization': 'Key %s' % self.api_key,
            'Content-type': 'application/json'
        }
        payload = {
            'user': 'ro-demo-key',
            'type': 'read-only'
        }

        response = self.app.post('/key', data=json.dumps(payload), headers=headers)
        self.assertEqual(response.status_code, 201)
        data = json.loads(response.data)
        self.assertIsNotNone(data['key'], 'Failed to create read-only key')

        read_only_key = data['key']

        response = self.app.post('/alert', data=json.dumps(self.alert), headers={'Authorization': 'Key ' + read_only_key})
        self.assertEqual(response.status_code, 403)

        response = self.app.get('/alerts', headers={'Authorization': 'Key ' + read_only_key})
        self.assertEqual(response.status_code, 200)
        data = json.loads(response.data)
        self.assertGreater(data['total'], 1, "total alerts > 1")

        response = self.app.delete('/key/' + read_only_key, headers={'Authorization': 'Key ' + self.api_key})
        self.assertEqual(response.status_code, 200)

<commit_msg>fix name<commit_after>import json
import unittest

from alerta.app import app, db

class AuthTestCase(unittest.TestCase):

    def setUp(self):

        app.config['TESTING'] = True
        app.config['AUTH_REQUIRED'] = True
        self.app = app.test_client()

        self.alert = {
            'event': 'Foo',
            'resource': 'Bar',
            'environment': 'Production',
            'service': ['Quux']
        }

        self.api_key = db.create_key('demo-key', type='read-write', text='demo-key')

    def tearDown(self):

        pass

    def test_401_error(self):

        response = self.app.get('/alerts')
        self.assertEqual(response.status_code, 401)

    def test_readwrite_key(self):

        headers = {
            'Authorization': 'Key %s' % self.api_key,
            'Content-type': 'application/json'
        }
        payload = {
            'user': 'rw-demo-key',
            'type': 'read-write'
        }

        response = self.app.post('/key', data=json.dumps(payload), headers=headers)
        self.assertEqual(response.status_code, 201)
        data = json.loads(response.data)
        self.assertIsNotNone(data['key'], 'Failed to create read-only key')

        read_write_key = data['key']

        response = self.app.post('/alert', data=json.dumps(self.alert), headers={'Authorization': 'Key ' + read_write_key})
        self.assertEqual(response.status_code, 201)

        response = self.app.get('/alerts', headers={'Authorization': 'Key ' + read_write_key})
        self.assertEqual(response.status_code, 200)
        data = json.loads(response.data)
        self.assertGreater(data['total'], 1, "total alerts > 1")

        response = self.app.delete('/key/' + read_write_key, headers={'Authorization': 'Key ' + self.api_key})
        self.assertEqual(response.status_code, 200)

    def test_readonly_key(self):

        headers = {
            'Authorization': 'Key %s' % self.api_key,
            'Content-type': 'application/json'
        }
        payload = {
            'user': 'ro-demo-key',
            'type': 'read-only'
        }

        response = self.app.post('/key', data=json.dumps(payload), headers=headers)
        self.assertEqual(response.status_code, 201)
        data = json.loads(response.data)
        self.assertIsNotNone(data['key'], 'Failed to create read-only key')

        read_only_key = data['key']

        response = self.app.post('/alert', data=json.dumps(self.alert), headers={'Authorization': 'Key ' + read_only_key})
        self.assertEqual(response.status_code, 403)

        response = self.app.get('/alerts', headers={'Authorization': 'Key ' + read_only_key})
        self.assertEqual(response.status_code, 200)
        data = json.loads(response.data)
        self.assertGreater(data['total'], 1, "total alerts > 1")

        response = self.app.delete('/key/' + read_only_key, headers={'Authorization': 'Key ' + self.api_key})
        self.assertEqual(response.status_code, 200)

<|endoftext|>


<commit_before>import emcee
import numpy as np
import math
import naxion
from quasi_observable_data import *

debugging = True

if debugging:
	import time
	print 'starting'
	#np.random.seed(121)

##############################
# 	Set up your model		 #
##############################

# You must be careful here selecting the right
# parameters for the model, and priors, and match them up
# in the prior and likelihood functions below.
# This is not idiot proof!

# Model selection
run_name='Mtheory_wide_nax20_DM_run1'
nax=20
model=3

# Sampler parameters
# ndim must be correct for the model!
# nsteps is the number of steps before each save
ndim, nwalkers, nsteps = 5, 20, 1
# repeat numiter times
numiter=25000 # iterate the sampler
# total steps = nwalkers*nsteps*numiter

# Priors
lFmin,lFmax=90.,120.
lLmin,lLmax=-10.,0.
sminl,sminu=10.,100.
smaxl,smaxu=20.,150.
Nmin,Nmax=0.5,10.

# Starting position
startFile=True
startChainFile='Chains/Mtheory_nax20_DM_run1.npy'

##################################
# Starting position of walkers
##################################

if startFile:
	startChain=np.load(startChainFile)
	# Take last sample from each walker as new starting position
	pos=startChain[:,-1,:]
else:
	# Uniform starts
	# Match these to the prior if using e.g. log-flat
	pos = [[np.random.uniform(lFmin,lFmax),np.random.uniform(lLmin,lLmax),np.random.uniform(sminl,sminu)
		,np.random.uniform(smaxl,smaxu),np.random.uniform(Nmin,Nmax)] for i in range(nwalkers)]

##############################
# Likelihood and prior functions
##############################

def lnprior(theta):
	lF,lL,smin,smax,N = theta

	# Flat priors on parameters
	if lFmin<lF<lFmax and lLmin<lL<lLmax and sminl<smin<sminu and smaxl<smax<smaxu and Nmin<N<Nmax:
		if debugging:
			print 'lnprior = ', 0.0
		return 0.0
	if debugging:
		print 'lnprior = ', 'inf'
	return -np.inf

##########################################
# 		The Likelihood					#
#########################################

def lnlike(theta, H0,sigH, Om,sigOm):

	lF,lL,smin,smax,N = theta
	if debugging:
		start = time.time()
		print 'in likelihood, params   ',lF,lL,smin,smax,N
	# Initialise the naxion model
	# Hypervec must be correct for the model number, and match the params in theta
	# There is probably an idiot proof way to do this, but for now you have to think!
	my_calculator = naxion.hubble_calculator(ifsampling=True,
		fname='configuration_card_DM.ini',mnum=model,hypervec=(nax,10.**lF,10.**lL,smin,smax,N))

	###############################################################################
	# Apply a "prior" to the log10(masses)
	# Done inside the likelihood to assure it is same random seed as for solver
	# If mass cut failed return zero likelihood, lnlik=-np.inf

	masses=my_calculator.ma_array*MH
	masses=np.log10(masses)
	#if debugging:
	#	print 'phivals/Mpl   ',my_calculator.phiin_array
	#	print 'log10(masses/mmax)  ',masses-mcut

	for i in range(nax):
		if masses[i]>mcut:
			if debugging:
				print 'MASSES OUTSIDE PRIOR'
			return -np.inf

	#############################################################################

	# Solve e.o.m.'s for outputs only if mass cut is passed
	my_calculator.solver()
	# Output quasi-observables
	Hout,Omout,add0,zout=my_calculator.quasiObs()
	# Define Gaussian likelihood on derived quasi observables
	lnlikH = -0.5*((Hout-H0)**2./(sigH**2.) +np.log(2.*math.pi*sigH**2.) )
	lnlikOm = -0.5*((Omout-Om)**2./(sigOm**2.) +np.log(2.*math.pi*sigOm**2.) )
	lnlikZ = -0.5*((zout-zeq)**2./(sigZ**2.) +np.log(2.*math.pi*sigZ**2.) )

	# Do a cut for "is the Universe accelerating"
	if add0>0:
		lnlikacc = 0.0
	else:
		lnlikacc = -np.inf

	#############################################################################

	# Return the product likelihood for Hubble, Om, acc, zeq
	if debugging:
		print 'in likelihood, obs=   ',	Hout,Omout,add0,zout
		end = time.time()
		print 'elapsed time in  lik =   ',end-start
		print 'lnlik = ', lnlikH+lnlikOm+lnlikacc+lnlikZ

	return lnlikH+lnlikOm+lnlikacc+lnlikZ

#############################################################################

def lnprob(theta, H0,sigH, Om,sigOm):
	lp = lnprior(theta)

	if not np.isfinite(lp):
		# do not call the likelihood if the prior is infinite
		return -np.inf

	return lp + lnlike(theta, H0,sigH, Om,sigOm)

#########################################
# 	      Do the MCMC				   #
########################################

print 'running, iteration =  ',0.,'  of  ',numiter
sampler = emcee.EnsembleSampler(nwalkers, ndim, lnprob, args=(H0,sigH, Om,sigOm))
if debugging:
	print 'running MCMC'
sampler.run_mcmc(pos, nsteps, rstate0=np.random.get_state())
if debugging:
	print 'making chain'
chain=sampler.chain[:,:,:]
if debugging:
	print 'saving'
np.save('Chains/'+run_name+'.npy',chain)

for i in range(1,numiter):
	print 'running, iteration =  ',i,'  of  ',numiter
	pos=chain[:,-1,:]
	sampler = emcee.EnsembleSampler(nwalkers, ndim, lnprob, args=(H0,sigH, Om,sigOm))
	if debugging:
		print 'running MCMC'
	sampler.run_mcmc(pos, nsteps, rstate0=np.random.get_state())
	if debugging:
		print 'making chain'
	temp=sampler.chain[:,:,:]
	chain=np.concatenate((chain,temp),axis=1)
	if debugging:
		print 'saving'
	np.save('Chains/'+run_name+'.npy',chain)

<commit_msg>changed debug messages, temp<commit_after>import emcee
import numpy as np
import math
import naxion
from quasi_observable_data import *

debugging = True

if debugging:
	import time
	print 'starting'
	#np.random.seed(121)

##############################
# 	Set up your model		 #
##############################

# You must be careful here selecting the right
# parameters for the model, and priors, and match them up
# in the prior and likelihood functions below.
# This is not idiot proof!

# Model selection
run_name='Mtheory_wide_nax20_DM_run1'
nax=20
model=3

# Sampler parameters
# ndim must be correct for the model!
# nsteps is the number of steps before each save
ndim, nwalkers, nsteps = 5, 20, 1
# repeat numiter times
numiter=25000 # iterate the sampler
# total steps = nwalkers*nsteps*numiter

# Priors
lFmin,lFmax=90.,120.
lLmin,lLmax=-10.,0.
sminl,sminu=10.,100.
smaxl,smaxu=20.,150.
Nmin,Nmax=0.5,10.

# Starting position
startFile=True
startChainFile='Chains/Mtheory_nax20_DM_run1.npy'

##################################
# Starting position of walkers
##################################

if startFile:
	startChain=np.load(startChainFile)
	# Take last sample from each walker as new starting position
	pos=startChain[:,-1,:]
else:
	# Uniform starts
	# Match these to the prior if using e.g. log-flat
	pos = [[np.random.uniform(lFmin,lFmax),np.random.uniform(lLmin,lLmax),np.random.uniform(sminl,sminu)
		,np.random.uniform(smaxl,smaxu),np.random.uniform(Nmin,Nmax)] for i in range(nwalkers)]

##############################
# Likelihood and prior functions
##############################

def lnprior(theta):
	lF,lL,smin,smax,N = theta

	# Flat priors on parameters
	if lFmin<lF<lFmax and lLmin<lL<lLmax and sminl<smin<sminu and smaxl<smax<smaxu and Nmin<N<Nmax:
		#if debugging:
		#	print 'lnprior = ', 0.0
		return 0.0
	#if debugging:
	#	print 'lnprior = ', 'inf'
	return -np.inf

##########################################
# 		The Likelihood					#
#########################################

def lnlike(theta, H0,sigH, Om,sigOm):

	lF,lL,smin,smax,N = theta
	if debugging:
		start = time.time()
		print 'in likelihood, params   ',lF,lL,smin,smax,N
	# Initialise the naxion model
	# Hypervec must be correct for the model number, and match the params in theta
	# There is probably an idiot proof way to do this, but for now you have to think!
	my_calculator = naxion.hubble_calculator(ifsampling=True,
		fname='configuration_card_DM.ini',mnum=model,hypervec=(nax,10.**lF,10.**lL,smin,smax,N))

	###############################################################################
	# Apply a "prior" to the log10(masses)
	# Done inside the likelihood to assure it is same random seed as for solver
	# If mass cut failed return zero likelihood, lnlik=-np.inf

	masses=my_calculator.ma_array*MH
	masses=np.log10(masses)
	#if debugging:
	#	print 'phivals/Mpl   ',my_calculator.phiin_array
	#	print 'log10(masses/mmax)  ',masses-mcut

	for i in range(nax):
		if masses[i]>mcut:
			#if debugging:
			#	print 'MASSES OUTSIDE PRIOR'
			return -np.inf

	#############################################################################

	# Solve e.o.m.'s for outputs only if mass cut is passed
	my_calculator.solver()
	# Output quasi-observables
	Hout,Omout,add0,zout=my_calculator.quasiObs()
	# Define Gaussian likelihood on derived quasi observables
	lnlikH = -0.5*((Hout-H0)**2./(sigH**2.) +np.log(2.*math.pi*sigH**2.) )
	lnlikOm = -0.5*((Omout-Om)**2./(sigOm**2.) +np.log(2.*math.pi*sigOm**2.) )
	lnlikZ = -0.5*((zout-zeq)**2./(sigZ**2.) +np.log(2.*math.pi*sigZ**2.) )

	# Do a cut for "is the Universe accelerating"
	if add0>0:
		lnlikacc = 0.0
	else:
		lnlikacc = -np.inf

	#############################################################################

	# Return the product likelihood for Hubble, Om, acc, zeq
	if debugging:
		print 'in likelihood, obs=   ',	Hout,Omout,add0,zout
		end = time.time()
		#print 'elapsed time in  lik =   ',end-start
		print 'lnlik = ', lnlikH+lnlikOm+lnlikacc+lnlikZ

	return lnlikH+lnlikOm+lnlikacc+lnlikZ

#############################################################################

def lnprob(theta, H0,sigH, Om,sigOm):
	lp = lnprior(theta)

	if not np.isfinite(lp):
		# do not call the likelihood if the prior is infinite
		return -np.inf

	return lp + lnlike(theta, H0,sigH, Om,sigOm)

#########################################
# 	      Do the MCMC				   #
########################################

#print 'running, iteration =  ',0.,'  of  ',numiter
sampler = emcee.EnsembleSampler(nwalkers, ndim, lnprob, args=(H0,sigH, Om,sigOm))
#if debugging:
#	print 'running MCMC'
sampler.run_mcmc(pos, nsteps, rstate0=np.random.get_state())
#if debugging:
#	print 'making chain'
chain=sampler.chain[:,:,:]
#if debugging:
#	print 'saving'
np.save('Chains/'+run_name+'.npy',chain)

for i in range(1,numiter):
	#print 'running, iteration =  ',i,'  of  ',numiter
	pos=chain[:,-1,:]
	sampler = emcee.EnsembleSampler(nwalkers, ndim, lnprob, args=(H0,sigH, Om,sigOm))
	#if debugging:
	#	print 'running MCMC'
	sampler.run_mcmc(pos, nsteps, rstate0=np.random.get_state())
	#if debugging:
	#	print 'making chain'
	temp=sampler.chain[:,:,:]
	chain=np.concatenate((chain,temp),axis=1)
	#if debugging:
	#	print 'saving'
	np.save('Chains/'+run_name+'.npy',chain)

<|endoftext|>


<commit_before>"""
Tests for geojson/base.py
"""

import unittest

import geojson

class TypePropertyTestCase(unittest.TestCase):
    def test_type_property(self):
        json_str = '{"type": "Feature", "geometry": null, "id": 1, "properties": {"type": "é"}}'
        geojson_obj = geojson.loads(json_str)
        self.assertIsInstance(geojson_obj, geojson.GeoJSON)

        json_str = '{"type": "Feature", "geometry": null, "id": 1, "properties": {"type": null}}'
        geojson_obj = geojson.loads(json_str)
        self.assertIsInstance(geojson_obj, geojson.GeoJSON)

class OperatorOverloadingTestCase(unittest.TestCase):
    """
    Tests for operator overloading
    """

    def setUp(self):
        self.coords = (12, -5)
        self.point = geojson.Point(self.coords)

    def test_setattr(self):
        new_coords = (27, 42)
        self.point.coordinates = new_coords
        self.assertEqual(self.point['coordinates'], new_coords)

    def test_getattr(self):
        self.assertEqual(self.point['coordinates'], self.point.coordinates)

    def test_delattr(self):
        del self.point.coordinates
        self.assertFalse(hasattr(self.point, 'coordinates'))
<commit_msg>Specify unicode encoding<commit_after># -*- coding: utf-8 -*-
"""
Tests for geojson/base.py
"""

import unittest

import geojson

class TypePropertyTestCase(unittest.TestCase):
    def test_type_property(self):
        json_str = '{"type": "Feature", "geometry": null, "id": 1, "properties": {"type": "é"}}'
        geojson_obj = geojson.loads(json_str)
        self.assertIsInstance(geojson_obj, geojson.GeoJSON)

        json_str = '{"type": "Feature", "geometry": null, "id": 1, "properties": {"type": null}}'
        geojson_obj = geojson.loads(json_str)
        self.assertIsInstance(geojson_obj, geojson.GeoJSON)

class OperatorOverloadingTestCase(unittest.TestCase):
    """
    Tests for operator overloading
    """

    def setUp(self):
        self.coords = (12, -5)
        self.point = geojson.Point(self.coords)

    def test_setattr(self):
        new_coords = (27, 42)
        self.point.coordinates = new_coords
        self.assertEqual(self.point['coordinates'], new_coords)

    def test_getattr(self):
        self.assertEqual(self.point['coordinates'], self.point.coordinates)

    def test_delattr(self):
        del self.point.coordinates
        self.assertFalse(hasattr(self.point, 'coordinates'))
<|endoftext|>


<commit_before>#!/usr/bin/env python3
#
# Copyright (c) 2019 Roberto Riggio
#
# 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.

"""Base service class."""

import uuid
import pkgutil
import logging

import tornado.ioloop

from empower.core.serialize import serializable_dict

@serializable_dict
class EService:
    """Base service class."""

    HANDLERS = []

    def __init__(self, context, service_id, **kwargs):

        # Declaration
        self._service_id = None

        # Pointer to an Env or a Project object (can be None)
        self.context = context

        # Set the service id
        self.service_id = service_id

        # If every is not specified then disable periodic loop
        if 'every' not in kwargs:
            kwargs['every'] = -1

        # Service's callbacks
        self.callbacks = set()

        # Human readable name
        self.name = "%s" % self.__class__.__module__

        # Set logger
        self.log = logging.getLogger(self.name)

        # Worker process, set only if every > 0
        self.worker = None

        # Persistent dict
        self.storage = {}

        # Service parameters
        self.params = {}

        # Set service parameters
        for param in kwargs:
            setattr(self, param, kwargs[param])

    def set_storage(self, storage=None):
        """Set persistent attributes."""

        if not storage:
            return

        for attribute in storage:
            setattr(self, attribute, storage[attribute])

    def save_service_state(self):
        """Save service state."""

        if not self.context:
            return

        self.context.save_service_state(self.service_id)

    def register_service(self, name, **kwargs):
        """Get a service.

        Return a service with the same name and parameters if already running
        or start a new one."""

        if not self.context:
            return None

        return self.context.register_service(name, **kwargs)

    def handle_callbacks(self):
        """Invoke registered callbacks."""

        for callback in self.callbacks:
            callback(self)

    def add_callback(self, method):
        """Add a new callback."""

        self.callbacks.add(method)

    def remove_callback(self, method):
        """Remove a callback."""

        self.callbacks.remove(method)

    def to_dict(self):
        """Return JSON-serializable representation of the object."""

        output = {}

        output['service_id'] = self.service_id
        output['name'] = self.name
        output['params'] = self.params

        if self.context:
            output['project_id'] = self.context.project_id

        return output

    @property
    def service_id(self):
        """Get service_id."""

        return self._service_id

    @service_id.setter
    def service_id(self, value):
        """Set service_id."""

        if isinstance(value, uuid.UUID):
            self._service_id = value
        else:
            self._service_id = uuid.UUID(value)

    @property
    def every(self):
        """Return loop period."""

        return self.params["every"]

    @every.setter
    def every(self, value):
        """Set loop period."""

        self.params["every"] = int(value)

        if self.worker:
            self.stop()
            self.start()

    def write_points(self, points):
        """Write points to InfluxDB."""

        self.context.ts_manager.write_points(points)

    def start(self):
        """Start control loop."""

        # Not supposed to run a loop
        if self.every == -1:
            return

        # Start the control loop
        self.worker = \
            tornado.ioloop.PeriodicCallback(self.loop, self.every)

        self.worker.start()

    def stop(self):
        """Stop control loop."""

        # save state
        self.save_service_state()

        # Not supposed to run a loop
        if self.every == -1:
            return

        # stop the control loop
        self.worker.stop()
        self.worker = None

    def loop(self):
        """Control loop."""

        self.log.info("Empty loop")

    @classmethod
    def walk_module(cls, package):
        """Inspect the specified module for services."""

        results = {}

        pkgs = pkgutil.walk_packages(package.__path__)

        for _, module_name, is_pkg in pkgs:

            __import__(package.__name__ + "." + module_name)

            if not is_pkg:
                continue

            if not hasattr(package, module_name):
                continue

            module = getattr(package, module_name)

            if not hasattr(module, "MANIFEST"):
                continue

            manifest = getattr(module, "MANIFEST")

            name = package.__name__ + "." + module_name + "." + module_name

            if 'name' not in manifest:
                manifest['name'] = module_name

            if 'desc' not in manifest:
                manifest['desc'] = "No description available"

            results[name] = manifest

        return results

    def to_str(self):
        """Return an ASCII representation of the object."""

        return "%s" % self.name

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

    def __hash__(self):
        return hash(self.name)

    def __eq__(self, other):
        if isinstance(other, EService):
            return self.name == other.name and self.every == other.every
        return False

    def __ne__(self, other):
        return not self.__eq__(other)

    def __repr__(self):
        return self.__class__.__name__ + "('" + self.to_str() + "')"
<commit_msg>Make Service to_dict consistent between active and catalog.<commit_after>#!/usr/bin/env python3
#
# Copyright (c) 2019 Roberto Riggio
#
# 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.

"""Base service class."""

import uuid
import pkgutil
import logging

import tornado.ioloop

from empower.core.serialize import serializable_dict

@serializable_dict
class EService:
    """Base service class."""

    HANDLERS = []

    def __init__(self, context, service_id, **kwargs):

        # Declaration
        self._service_id = None

        # Pointer to an Env or a Project object (can be None)
        self.context = context

        # Set the service id
        self.service_id = service_id

        # If every is not specified then disable periodic loop
        if 'every' not in kwargs:
            kwargs['every'] = -1

        # Service's callbacks
        self.callbacks = set()

        # Set logger
        self.log = logging.getLogger(self.name)

        # Worker process, set only if every > 0
        self.worker = None

        # Persistent dict
        self.storage = {}

        # Service parameters
        self.params = {}

        # Set service parameters
        for param in kwargs:
            setattr(self, param, kwargs[param])

    def set_storage(self, storage=None):
        """Set persistent attributes."""

        if not storage:
            return

        for attribute in storage:
            setattr(self, attribute, storage[attribute])

    def save_service_state(self):
        """Save service state."""

        if not self.context:
            return

        self.context.save_service_state(self.service_id)

    def register_service(self, name, **kwargs):
        """Get a service.

        Return a service with the same name and parameters if already running
        or start a new one."""

        if not self.context:
            return None

        return self.context.register_service(name, **kwargs)

    def handle_callbacks(self):
        """Invoke registered callbacks."""

        for callback in self.callbacks:
            callback(self)

    def add_callback(self, method):
        """Add a new callback."""

        self.callbacks.add(method)

    def remove_callback(self, method):
        """Remove a callback."""

        self.callbacks.remove(method)

    def to_dict(self):
        """Return JSON-serializable representation of the object."""

        output = {}

        output['service_id'] = self.service_id
        output['name'] = self.name
        output['desc'] = self.desc
        output['params'] = self.params

        if self.context:
            output['project_id'] = self.context.project_id

        return output

    @property
    def name(self):
        """Get name."""

        return "%s" % self.__class__.__module__

    @property
    def desc(self):
        """Get desc."""

        return "n/a"

    @property
    def service_id(self):
        """Get service_id."""

        return self._service_id

    @service_id.setter
    def service_id(self, value):
        """Set service_id."""

        if isinstance(value, uuid.UUID):
            self._service_id = value
        else:
            self._service_id = uuid.UUID(value)

    @property
    def every(self):
        """Return loop period."""

        return self.params["every"]

    @every.setter
    def every(self, value):
        """Set loop period."""

        self.params["every"] = int(value)

        if self.worker:
            self.stop()
            self.start()

    def write_points(self, points):
        """Write points to InfluxDB."""

        self.context.ts_manager.write_points(points)

    def start(self):
        """Start control loop."""

        # Not supposed to run a loop
        if self.every == -1:
            return

        # Start the control loop
        self.worker = \
            tornado.ioloop.PeriodicCallback(self.loop, self.every)

        self.worker.start()

    def stop(self):
        """Stop control loop."""

        # save state
        self.save_service_state()

        # Not supposed to run a loop
        if self.every == -1:
            return

        # stop the control loop
        self.worker.stop()
        self.worker = None

    def loop(self):
        """Control loop."""

        self.log.info("Empty loop")

    @classmethod
    def walk_module(cls, package):
        """Inspect the specified module for services."""

        results = {}

        pkgs = pkgutil.walk_packages(package.__path__)

        for _, module_name, is_pkg in pkgs:

            __import__(package.__name__ + "." + module_name)

            if not is_pkg:
                continue

            if not hasattr(package, module_name):
                continue

            module = getattr(package, module_name)

            if not hasattr(module, "MANIFEST"):
                continue

            manifest = getattr(module, "MANIFEST")

            name = package.__name__ + "." + module_name + "." + module_name

            if 'name' not in manifest:
                manifest['name'] = module_name

            if 'desc' not in manifest:
                manifest['desc'] = "No description available"

            results[name] = manifest

        return results

    def to_str(self):
        """Return an ASCII representation of the object."""

        return "%s" % self.name

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

    def __hash__(self):
        return hash(self.name)

    def __eq__(self, other):
        if isinstance(other, EService):
            return self.name == other.name and self.every == other.every
        return False

    def __ne__(self, other):
        return not self.__eq__(other)

    def __repr__(self):
        return self.__class__.__name__ + "('" + self.to_str() + "')"
<|endoftext|>


<commit_before>"""tests/test_base.py.

Tests the base blox to ensure they provide solid functionality for a Python dom representation
Copyright (C) 2015 Timothy Edmund Crosley

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
documentation files (the "Software"), to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.

"""
import pytest

from blox.base import Blok, Invalid, Text, Blox, Tag, NamedTag, TagWithChildren
from io import StringIO

class TestBlok(object):
    testing = Blok
    expected_output = ''

    def __init__(self):
        self.blok = self.testing()
        self.modify()

    def modify(self):
        '''Sub test classes can modify the blok here for testing, before all tests are ran'''
        pass

    def test_output(self):
        output = StringIO()
        self.blok.output(output)
        assert str(output) == self.expected_output

    def test_render(self):
        output = StringIO()
        self.blok.output(output)
        assert self.blok.render() == str(output)

    def test_str(self):
        str(self.blok) == self.blok.render(formatted=True)

class TestInvalid(TestBlok):
    testing = Invalid
    expected_output = '
Invalid
'

class TestText(TestBlok):
    testing = Text
    expected_output = 'test text'

    def modify(self):
        self.blok.value = 'test text'

class TestBlox(TestBlok):
    testing = Blox
    expected_output = 'hi bacon'

    def modify(self):
        self.hi = Text('hi')
        self.bacon = Text(' bacon')
        self.blok += self.hi
        self.blok += self.bacon

class TestTag(TestBlok):
    expected_output = '<testing />'
    class testing(Tag):
        tag = 'testing'

class TestTagWithChildren(TestBlox):
    expected_output = '<testing>hi bacon</testing>'
    class testing(TagWithChildren):
        tag = 'testing'
<commit_msg>Initial work toward ensuring blox are list like<commit_after>"""tests/test_base.py.

Tests the base blox to ensure they provide solid functionality for a Python dom representation
Copyright (C) 2015 Timothy Edmund Crosley

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
documentation files (the "Software"), to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.

"""
import pytest

from blox.base import Blok, Invalid, Text, Blox, Tag, NamedTag, TagWithChildren
from io import StringIO

class TestBlok(object):
    testing = Blok
    expected_output = ''

    def __init__(self):
        self.blok = self.testing()
        self.modify()

    def modify(self):
        '''Sub test classes can modify the blok here for testing, before all tests are ran'''
        pass

    def test_output(self):
        output = StringIO()
        self.blok.output(output)
        assert str(output) == self.expected_output

    def test_render(self):
        output = StringIO()
        self.blok.output(output)
        assert self.blok.render() == str(output)

    def test_str(self):
        str(self.blok) == self.blok.render(formatted=True)

class TestInvalid(TestBlok):
    testing = Invalid
    expected_output = '
Invalid
'

class TestText(TestBlok):
    testing = Text
    expected_output = 'test text'

    def modify(self):
        self.blok.value = 'test text'

class TestBlox(TestBlok):
    testing = Blox
    expected_output = 'hi bacon'

    def modify(self):
        self.hi = Text('hi')
        self.bacon = Text(' bacon')
        self.blok += self.hi
        self.blok += self.bacon

    def test_list_like(self):
        assert self.hi in self.blok
        assert self.bacon in self.blok

class TestTag(TestBlok):
    expected_output = '<testing />'
    class testing(Tag):
        tag = 'testing'

class TestTagWithChildren(TestBlox):
    expected_output = '<testing>hi bacon</testing>'
    class testing(TagWithChildren):
        tag = 'testing'
<|endoftext|>


<commit_before>#!/usr/bin/env python
# -*- coding: utf-8 -*-
# type: ignore

"""Unit tests for BaseTextRank."""
from spacy.language import Language  # pylint: disable=E0401
from spacy.tokens import Span, Doc  # pylint: disable=E0401
import spacy  # pylint: disable=E0401

import sys
sys.path.insert(0, "../pytextrank")

from pytextrank.base import BaseTextRankFactory  # pylint: disable=E0401

def test_base_text_rank (doc: Doc):
    """
Ranks unique keywords in a document correctly, sorted decreasing by
centrality.
    """
    # given
    base_text_rank = BaseTextRankFactory()

    # when
    processed_doc = base_text_rank(doc)
    phrases = processed_doc._.phrases

    # then
    assert len(phrases) > 0
    assert len(set(p.text for p in phrases)) == len(phrases)
    assert phrases[0].rank == max(p.rank for p in phrases)

def test_add_pipe (nlp: Language):
    """
Works as a pipeline component and can be disabled.
    """
    # given
    # base_text_rank = BaseTextRankFactory()
    nlp.add_pipe("textrank", last=True)

    # works as a pipeline component
    # when
    text = "linear constraints over the"
    doc = nlp(text)
    phrases = [ p.text for p in doc._.phrases ]

    # then
    assert len(doc._.phrases) > 0
    assert any(map(lambda x: "constraints" in x, phrases))

    # identifies phrases not in noun chunks
    # when
    text = """
everything you need to know about student loan interest rates variable
and fixed rates capitalization amortization student loan refinancing
and more.
"""

    doc = nlp(text)
    phrases = [ p.text for p in doc._.phrases ]

    # then
    assert len(doc._.phrases) >= 2

    # resolves Py 3.5 dict KeyError
    # when
    text = "linear constraints over the set of natural numbers"
    doc = nlp(text)
    phrases = [ p.text for p in doc._.phrases ]

    # then
    assert any(map(lambda x: "constraints" in x, phrases))

    # pipeline can be disabled
    # when
    with nlp.select_pipes(disable=["textrank"]):
        doc = nlp(text)

        # then
        assert len(doc._.phrases) == 0

def test_summary (nlp: Language):
    """
Summarization produces the expected results.
    """
    # given
    expected_trace = [
        [0, [0, 2, 6, 7, 8]],
        [1, [8]],
        [2, [2]],
        [7, [8, 4]],
        [8, [8]],
        [11, [2]],
        [12, [1]],
        [14, [2, 5]],
        [15, [9, 3, 7]],
        [17, [2]],
        ]

    with open("dat/lee.txt", "r") as f:
        text = f.read()
        doc = nlp(text)
        tr = doc._.textrank

        # calculates *unit vector* and sentence distance measures
        # when
        trace = [
            [ sent_dist.sent_id, list(sent_dist.phrases) ]
            for sent_dist in tr.calc_sent_dist(limit_phrases=10)
            if not sent_dist.empty()
            ]

        # then
        assert trace == expected_trace

def test_multiple_summary (nlp: Language):
    """
Summarization produces consistent results when called across multiple
docs.
    """
    texts = []

    with open("dat/lee.txt", "r") as f:
        text = f.read()
        texts.append(text)

    with open("dat/mih.txt", "r") as f:
        text = f.read()
        texts.append(text)

    docs = [nlp(text) for text in texts]

    trace1 = [
        [sent_dist.sent_id, list(sent_dist.phrases)]
        for sent_dist in docs[0]._.textrank.calc_sent_dist(limit_phrases=10)
        if not sent_dist.empty()
    ]

    trace2 = [
        [sent_dist.sent_id, list(sent_dist.phrases)]
        for sent_dist in docs[1]._.textrank.calc_sent_dist(limit_phrases=10)
        if not sent_dist.empty()
    ]

    assert trace1 != trace2

def test_stop_words ():
    """
Works as a pipeline component and can be disabled.
    """
    # given
    nlp = spacy.load("en_core_web_sm")
    nlp.add_pipe("textrank", config={ "stopwords": { "word": ["NOUN"] } })

    # when
    _expected_phrases = [
        "sentences",
        "Mihalcea et al",
        "text summarization",
        "gensim implements",
        "Okapi BM25 function",
        ]

    # add `"word": ["NOUN"]` to the *stop words*, to remove instances
    # of `"word"` or `"words"` then see how the ranked phrases differ?

    # then
    with open("dat/gen.txt", "r") as f:
        doc = nlp(f.read())

        phrases = [
            phrase.text
            for phrase in doc._.phrases[:5]
            ]

        assert phrases == _expected_phrases

def test_scrubber ():
    """
Works as a pipeline component and can be disabled.
    """
    # given

    text = "This is a test for scrubber."

    nlp1 = spacy.load("en_core_web_sm")
    nlp1.add_pipe("textrank", last=True)

    doc = nlp1(text)

    phrases = [
        phrase.text
        for phrase in doc._.phrases
    ]

    assert "a test" in phrases

    @spacy.registry.misc("articles_scrubber")
    def articles_scrubber():  # pylint: disable=E0401
        def scrubber_func(text_span: Span) -> str:
            for token in text_span:
                if token.pos_ != "DET":
                    break
                text_span = text_span[1:]
            return text_span.text

        return scrubber_func

    # add "articles_scrubber" to config
    # then see if phrases have `articles` in it?

    nlp2 = spacy.load("en_core_web_sm")
    nlp2.add_pipe("textrank", config={"stopwords": {"test": ["NOUN"]}, "scrubber": {"@misc": "articles_scrubber"}}, last=True)

    # then
    doc = nlp2(text)

    phrases = [
        phrase.text
        for phrase in doc._.phrases
    ]

    assert "test" in phrases and "a test" in phrases
<commit_msg>fix pylint exception<commit_after>#!/usr/bin/env python
# -*- coding: utf-8 -*-
# type: ignore

"""Unit tests for BaseTextRank."""
from spacy.language import Language  # pylint: disable=E0401
from spacy.tokens import Span, Doc  # pylint: disable=E0401
import spacy  # pylint: disable=E0401

import sys
sys.path.insert(0, "../pytextrank")

from pytextrank.base import BaseTextRankFactory  # pylint: disable=E0401

def test_base_text_rank (doc: Doc):
    """
Ranks unique keywords in a document correctly, sorted decreasing by
centrality.
    """
    # given
    base_text_rank = BaseTextRankFactory()

    # when
    processed_doc = base_text_rank(doc)
    phrases = processed_doc._.phrases

    # then
    assert len(phrases) > 0
    assert len(set(p.text for p in phrases)) == len(phrases)
    assert phrases[0].rank == max(p.rank for p in phrases)

def test_add_pipe (nlp: Language):
    """
Works as a pipeline component and can be disabled.
    """
    # given
    # base_text_rank = BaseTextRankFactory()
    nlp.add_pipe("textrank", last=True)

    # works as a pipeline component
    # when
    text = "linear constraints over the"
    doc = nlp(text)
    phrases = [ p.text for p in doc._.phrases ]

    # then
    assert len(doc._.phrases) > 0
    assert any(map(lambda x: "constraints" in x, phrases))

    # identifies phrases not in noun chunks
    # when
    text = """
everything you need to know about student loan interest rates variable
and fixed rates capitalization amortization student loan refinancing
and more.
"""

    doc = nlp(text)
    phrases = [ p.text for p in doc._.phrases ]

    # then
    assert len(doc._.phrases) >= 2

    # resolves Py 3.5 dict KeyError
    # when
    text = "linear constraints over the set of natural numbers"
    doc = nlp(text)
    phrases = [ p.text for p in doc._.phrases ]

    # then
    assert any(map(lambda x: "constraints" in x, phrases))

    # pipeline can be disabled
    # when
    with nlp.select_pipes(disable=["textrank"]):
        doc = nlp(text)

        # then
        assert len(doc._.phrases) == 0

def test_summary (nlp: Language):
    """
Summarization produces the expected results.
    """
    # given
    expected_trace = [
        [0, [0, 2, 6, 7, 8]],
        [1, [8]],
        [2, [2]],
        [7, [8, 4]],
        [8, [8]],
        [11, [2]],
        [12, [1]],
        [14, [2, 5]],
        [15, [9, 3, 7]],
        [17, [2]],
        ]

    with open("dat/lee.txt", "r") as f:
        text = f.read()
        doc = nlp(text)
        tr = doc._.textrank

        # calculates *unit vector* and sentence distance measures
        # when
        trace = [
            [ sent_dist.sent_id, list(sent_dist.phrases) ]
            for sent_dist in tr.calc_sent_dist(limit_phrases=10)
            if not sent_dist.empty()
            ]

        # then
        assert trace == expected_trace

def test_multiple_summary (nlp: Language):
    """
Summarization produces consistent results when called across multiple
docs.
    """
    texts = []

    with open("dat/lee.txt", "r") as f:
        text = f.read()
        texts.append(text)

    with open("dat/mih.txt", "r") as f:
        text = f.read()
        texts.append(text)

    docs = [nlp(text) for text in texts]

    trace1 = [
        [sent_dist.sent_id, list(sent_dist.phrases)]
        for sent_dist in docs[0]._.textrank.calc_sent_dist(limit_phrases=10)
        if not sent_dist.empty()
    ]

    trace2 = [
        [sent_dist.sent_id, list(sent_dist.phrases)]
        for sent_dist in docs[1]._.textrank.calc_sent_dist(limit_phrases=10)
        if not sent_dist.empty()
    ]

    assert trace1 != trace2

def test_stop_words ():
    """
Works as a pipeline component and can be disabled.
    """
    # given
    nlp = spacy.load("en_core_web_sm")
    nlp.add_pipe("textrank", config={ "stopwords": { "word": ["NOUN"] } })

    # when
    _expected_phrases = [
        "sentences",
        "Mihalcea et al",
        "text summarization",
        "gensim implements",
        "Okapi BM25 function",
        ]

    # add `"word": ["NOUN"]` to the *stop words*, to remove instances
    # of `"word"` or `"words"` then see how the ranked phrases differ?

    # then
    with open("dat/gen.txt", "r") as f:
        doc = nlp(f.read())

        phrases = [
            phrase.text
            for phrase in doc._.phrases[:5]
            ]

        assert phrases == _expected_phrases

def test_scrubber ():
    """
Works as a pipeline component and can be disabled.
    """
    # given

    text = "This is a test for scrubber."

    nlp1 = spacy.load("en_core_web_sm")
    nlp1.add_pipe("textrank", last=True)

    doc = nlp1(text)

    phrases = [
        phrase.text
        for phrase in doc._.phrases
    ]

    assert "a test" in phrases

    @spacy.registry.misc("articles_scrubber")
    def articles_scrubber():  # pylint: disable=W0612
        def scrubber_func(text_span: Span) -> str:
            for token in text_span:
                if token.pos_ != "DET":
                    break
                text_span = text_span[1:]
            return text_span.text

        return scrubber_func

    # add "articles_scrubber" to config
    # then see if phrases have `articles` in it?

    nlp2 = spacy.load("en_core_web_sm")
    nlp2.add_pipe("textrank", config={"stopwords": {"test": ["NOUN"]}, "scrubber": {"@misc": "articles_scrubber"}}, last=True)

    # then
    doc = nlp2(text)

    phrases = [
        phrase.text
        for phrase in doc._.phrases
    ]

    assert "test" in phrases and "a test" in phrases
<|endoftext|>