Example #1
0
class BotifyTestCase(unittest.TestCase):
    def setUp(self):
        self.flag = 0
        self.bot = Botify(self.is_data_callback, self.clean_data_callback)

    def is_data_callback(self, value):
        return False

    def clean_data_callback(self, value):
        return value

    def task1(self):
        self.flag = 1

    def add_task(self):
        context = Context(self.task1, 0)
        rule = (-1, )
        keywords = ('keyword1', 'keyword2')
        self.bot.add_task(keywords, context, rule)

    def add_modifier(self):
        modifier = 'hello'
        keywords = ('keyword1', 'keyword2')
        relative_pos = 1
        action = Botify.ACTION_UPDATE_RULE
        parameter = ()
        self.bot.add_modifier(modifier, keywords, relative_pos, action,
                              parameter)

    def test_add_task(self):
        self.add_task()
        for keyword in ('keyword1', 'keyword2'):
            self.assertEqual(self.bot._tasks[keyword]['context'],
                             Context(self.task1, 0))
            self.assertEqual(self.bot._tasks[keyword]['rule'], (-1, ))

    def test_add_modifier(self):
        self.add_modifier()
        self.assertTrue('hello' in self.bot._modifiers)
        for keyword in ('keyword1', 'keyword2'):
            self.assertTrue(keyword in self.bot._modifiers['hello'])
            value = (Botify.ACTION_UPDATE_RULE, (), 1)
            self.assertTrue(value in self.bot._modifiers['hello'][keyword])

    def test_parse(self):
        self.add_task()
        #self.add_modifier()
        result = self.bot.parse("hello keyword1")
        self.assertEqual(len(result), 0)
        self.assertEqual(self.flag, 1)
Example #2
0
    def test_special_characters(self):
        user_agent = "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)"
        botify = Botify(
            {
                "HTTP_HOST": "http://example.test",
                "PATH_INFO": "/Français",
                "HTTP_USER_AGENT": user_agent,
                "REMOTE_ADDR": "127.0.0.1",
            }
        )

        bot = "<ip>%s</ip><ua>%s</ua>" % (botify.ip, botify.user_agent)

        with nested(patch.object(Botify, "send_data"), patch.object(time, "time")) as (send_data_method, time_method):
            send_data_method.return_value = True
            current_time = 1319812537
            time_method.return_value = current_time

            botify.set_code(200)

            data = botify.record()
Example #3
0
 def setUp(self):
     self.flag = 0
     self.bot = Botify(self.is_data_callback, self.clean_data_callback)
Example #4
0
    def test_format_data(self):
        user_agent = "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)"
        botify = Botify(
            {
                "HTTP_HOST": "http://example.test",
                "PATH_INFO": "/example",
                "HTTP_USER_AGENT": user_agent,
                "REMOTE_ADDR": "127.0.0.1",
            }
        )

        bot = "<ip>%s</ip><ua>%s</ua>" % (botify.ip, botify.user_agent)

        with nested(patch.object(Botify, "send_data"), patch.object(time, "time")) as (send_data_method, time_method):
            send_data_method.return_value = True
            current_time = 1319812537
            time_method.return_value = current_time

            botify.set_code(200)

            data = botify.record()

            self.assertEquals(
                data,
                '<?xml version="2.0"?><crawl><load>0</load><code>200</code><time>%(time)s</time><url>%(url)s</url><api_key>%(api_key)s</api_key><bot>%(bot_id)s</bot><id>%(client_id)s</id></crawl>'
                % {
                    "time": current_time,
                    "url": urllib.quote(botify.get_url()),
                    "api_key": settings.BOTIFY_API_KEY,
                    "client_id": settings.BOTIFY_CLIENT_ID,
                    "bot_id": bot,
                },
            )

            botify.add_tracker("example")

            self.assertRaises(ValueError, botify.add_tracker, ({"test": "test"}))

            data = botify.record()

            self.assertEquals(
                data,
                '<?xml version="2.0"?><crawl><load>0</load><code>200</code><time>%(time)s</time><url>%(url)s</url><api_key>%(api_key)s</api_key><bot>%(bot_id)s</bot><id>%(client_id)s</id><trackers><t>example</t></trackers></crawl>'
                % {
                    "time": current_time,
                    "url": urllib.quote(botify.get_url()),
                    "api_key": settings.BOTIFY_API_KEY,
                    "client_id": settings.BOTIFY_CLIENT_ID,
                    "bot_id": bot,
                },
            )

            botify.canonical = "http://example.test/home"

            data = botify.record()

            self.assertEquals(
                data,
                '<?xml version="2.0"?><crawl><load>0</load><code>200</code><time>%(time)s</time><url>%(url)s</url><api_key>%(api_key)s</api_key><bot>%(bot_id)s</bot><id>%(client_id)s</id><trackers><t>example</t></trackers><canonical>http%%3A//example.test/home</canonical></crawl>'
                % {
                    "time": current_time,
                    "url": urllib.quote(botify.get_url()),
                    "api_key": settings.BOTIFY_API_KEY,
                    "client_id": settings.BOTIFY_CLIENT_ID,
                    "bot_id": bot,
                },
            )
Example #5
0
    def test_is_crawlable(self):
        for user_agent in USER_AGENTS:
            is_crawlable = Botify.is_crawlable(None, user_agent)
            self.assertTrue(bool(is_crawlable))

        self.assertFalse(Botify.is_crawlable("http://example.test", USER_AGENTS[0][0]))
Example #6
0
class NLCalculator:
    """Natural Language Mathematical Calculator.

    This class can be used to parse mathematical statements in natural
    language.

    Attributes
    ----------
    strict_mode_enabled
    """
    def __init__(self):
        self._parser = Botify(is_token_data_callback=is_numeric,
                              clean_data_callback=convert_to_numeric)
        self._init_tasks()
        self._init_modifiers()

    @property
    def strict_mode_enabled(self):
        """Whether strict mode is enabled for the calculator instance."""
        return self._parser.strict_mode_enabled

    @strict_mode_enabled.setter
    def strict_mode_enabled(self, value):
        self._parser.strict_mode_enabled = value

    def _init_tasks(self):
        # Addition
        self._parser.add_task(keywords=('sum', 'summation', 'add',
                                        'addition', 'total'),
                              context=CONTEXT_SUM,
                              rule=(1, 2))
        self._parser.add_task(keywords=('added',),
                              context=CONTEXT_SUM,
                              rule=(-2, -1))
        self._parser.add_task(keywords=('plus', '+'),
                              context=CONTEXT_SUM,
                              rule=(-1, 1))

        # Subtraction
        self._parser.add_task(keywords=('difference', 'subtract', 'subtraction'),
                              context=CONTEXT_DIFF,
                              rule=(1, 2))
        self._parser.add_task(keywords=('subtracted',),
                              context=CONTEXT_DIFF,
                              rule=(-2, -1))
        self._parser.add_task(keywords=('minus', '-'),
                              context=CONTEXT_DIFF,
                              rule=(-1, 1))

        # Multiplication
        self._parser.add_task(keywords=('product', 'multiply', 'multiplication'),
                              context=CONTEXT_MUL,
                              rule=(1, 2))
        self._parser.add_task(keywords=('into', 'times', '*'),
                              context=CONTEXT_MUL,
                              rule=(-1, 1))
        self._parser.add_task(keywords=('multiplied',),
                              context=CONTEXT_MUL,
                              rule=(-2, -1))

        # Division
        self._parser.add_task(keywords=('divide', 'division'),
                              context=CONTEXT_DIV,
                              rule=(1, 2))
        self._parser.add_task(keywords=('divided', 'over', '/'),
                              context=CONTEXT_DIV,
                              rule=(-1, 1))

        # Factorial
        self._parser.add_task(keywords=('factorial',),
                              context=CONTEXT_FACT,
                              rule=(-1,))

        # Exponent
        self._parser.add_task(keywords=('power', '^', '**'),
                              context=CONTEXT_POW,
                              rule=(-1, 1))

        # Square
        self._parser.add_task(keywords=('square', 'squared'),
                              context=CONTEXT_SQR,
                              rule=(-1,))

        # Cube
        self._parser.add_task(keywords=('cube', 'cubed'),
                              context=CONTEXT_CUBE,
                              rule=(-1,))

        # Root
        self._parser.add_task(keywords=('root',),
                              context=CONTEXT_SQRT,
                              rule=(1,))

        # Special Constants
        self._parser.add_task(keywords=('pi',),     # pi
                              context=CONTEXT_PI,
                              rule=())
        self._parser.add_task(keywords=('e',),      # e
                              context=CONTEXT_E,
                              rule=())

    def _init_modifiers(self):
        self._parser.add_modifier(modifier='to',
                                  keywords=('added', 'multiplied'),
                                  relative_pos=-1,
                                  action=Botify.ACTION_UPDATE_RULE,
                                  parameter=(-1, 1))
        self._parser.add_modifier(modifier='with',
                                  keywords=('added', 'multiplied'),
                                  relative_pos=-1,
                                  action=Botify.ACTION_UPDATE_RULE,
                                  parameter=(-1, 1))
        self._parser.add_modifier(modifier='of',
                                  keywords=('factorial', 'square', 'cube'),
                                  relative_pos=-1,
                                  action=Botify.ACTION_UPDATE_RULE,
                                  parameter=(1,))
        self._parser.add_modifier(modifier='by',
                                  keywords=('divide', 'divided', 'multiply', 'multiplied'),
                                  relative_pos=-1,
                                  action=Botify.ACTION_UPDATE_RULE,
                                  parameter=(-1, 1))
        self._parser.add_modifier(modifier='from',
                                  keywords=('subtract',),
                                  relative_pos=-2,
                                  action=Botify.ACTION_UPDATE_RULE,
                                  parameter=(2, 1))
        self._parser.add_modifier(modifier='from',
                                  keywords=('subtracted',),
                                  relative_pos=-1,
                                  action=Botify.ACTION_UPDATE_RULE,
                                  parameter=(1, -1))
        self._parser.add_modifier(modifier='root',
                                  keywords=('square', 'cube'),
                                  relative_pos=-2,
                                  action=Botify.ACTION_UPDATE_RULE,
                                  parameter=(1,))

        self._parser.add_modifier(modifier='root',
                                  keywords=('square',),
                                  relative_pos=-2,
                                  action=Botify.ACTION_UPDATE_CONTEXT,
                                  parameter=CONTEXT_SQRT)
        self._parser.add_modifier(modifier='root',
                                  keywords=('cube',),
                                  relative_pos=-2,
                                  action=Botify.ACTION_UPDATE_CONTEXT,
                                  parameter=CONTEXT_CUBE_ROOT)

        self._parser.add_modifier(modifier='root',
                                  keywords=('square', 'cube'),
                                  relative_pos=-2,
                                  action=Botify.ACTION_DELETE,
                                  parameter=1)

    def calculate(self, text):
        """Calculate the output after parsing input.

        Parameters
        ----------
        text : str
            A string value which should be parsed

        Returns
        -------
        int or float:
            The final result

        Raises
        ------
        ValueError
            If the text cannot be succesfully parsed and evaluated to get
            a result.
        """
        res = self._parser.parse(text2int(text))
        if len(res) == 1:
            return res[0]
        else:
            raise ValueError("Unable to Parse")
Example #7
0
 def __init__(self):
     self._parser = Botify(is_token_data_callback=is_numeric,
                           clean_data_callback=convert_to_numeric)
     self._init_tasks()
     self._init_modifiers()