Exemple #1
0
async def test_should_put_in_queue_new_message_tracker(tracker_mock):
    user = utils.build_fake_user()
    ga = GAStatistics(tracking_id='UA-XXXXX-Y')

    ga.new_message(
        story_context.StoryContext(
            {
                'user': user,
                'session': {
                    'data': {
                        'text': {
                            'raw': 'hi!'
                        }
                    }
                },
            }, None))

    await asyncio.sleep(0.1)

    tracker_mock.send.assert_called_once_with(
        'pageview',
        'receive: {}'.format(json.dumps({'text': {
            'raw': 'hi!'
        }})),
    )
Exemple #2
0
async def test_should_put_in_queue_story_tracker(mocker, tracker_mock):
    user = utils.build_fake_user()
    ga = GAStatistics(tracking_id='UA-XXXXX-Y')

    class FakePart:
        @property
        def __name__(self):
            return 'one part'

    ctx = story_context.StoryContext(None, None)

    with mock.patch.object(ctx, 'user', return_value=user):
        with mock.patch.object(ctx,
                               'stack',
                               return_value=[{
                                   'topic': 'one story'
                               }]):
            with mock.patch.object(ctx,
                                   'get_current_story_part',
                                   return_value=FakePart()):
                ga.story(ctx)

    await asyncio.sleep(0.1)

    tracker_mock.send.assert_called_once_with(
        'pageview',
        'one story/one part',
    )
Exemple #3
0
    def factory(msg):
        story = Story()

        @story.on('Hi there!')
        def one_story():
            @story.part()
            async def start(ctx):
                await story.say('Where do you go?', user=ctx['user'])
                return forking.Switch({
                    'location': location.Any(),
                    'text': text.Any(),
                })

            @story.case(match='location')
            def location_case():
                @story.part()
                def store_location(ctx):
                    return text.Equal('hello!')

            @story.case(match='text')
            def text_case():
                @story.part()
                def store_location(ctx):
                    pass

            @story.part()
            def after_switch(ctx):
                return callable.EndOfStory('the end')

        return story_context.StoryContext(msg, story.stories_library)
Exemple #4
0
    async def startpoint(self, *args, **kwargs):
        if len(args) > 0:
            parent_ctx = args[0]
            session = parent_ctx['session']
            user = parent_ctx['user']
        else:
            if {'session', 'user'} > set(kwargs):
                raise AttributeError('Got {} and {}. Should pass session as well'.format(args, kwargs))
            session = kwargs.pop('session')
            user = kwargs.pop('user')

        # we are going deeper so prepare one more item in stack
        logger.debug('  action: extend stack by +1')
        session = {
            **session,
            'data': kwargs,
            'stack': session['stack'] + [stack_utils.build_empty_stack_item(self.ast_node.topic)],
        }

        ctx = story_context.StoryContext(message={
            'session': session,
            # TODO: should get user from context
            'user': user,
        }, library=self.library)
        ctx = await self.processor.process_story(ctx)
        ctx = story_context.reducers.scope_out(ctx)

        logger.debug('# result of callable')
        logger.debug(ctx)

        if isinstance(ctx.waiting_for, EndOfStory):
            return ctx.waiting_for.data

        # because we would like to return to stories from caller
        # we should return our context to callee
        return ctx
Exemple #5
0
    async def match_message(self, message_ctx):
        """

        match bot message to existing stories
        and take into account context of current user

        :param message_ctx:
        :return: mutated message_ctx
        """
        logger.debug('')
        logger.debug('# match_message')
        logger.debug('')
        logger.debug(message_ctx)

        ctx = story_context.StoryContext(
            library=self.library,
            matched=False,
            message=message_ctx,
        )

        self.tracker.new_message(ctx)

        if ctx.is_empty_stack():
            if not ctx.does_it_match_any_story():
                # there is no stories for such message
                return ctx.message

            ctx = story_context.reducers.scope_in(ctx)
            ctx = await self.process_story(ctx)
            ctx = story_context.reducers.scope_out(ctx)

        while ctx.could_scope_out() and not ctx.is_empty_stack():
            logger.debug('# in a loop')
            logger.debug(ctx)

            # looking for first valid matcher
            while True:
                logger.debug('# looking for first valid matcher')
                if ctx.is_empty_stack():
                    # we have reach the bottom of stack
                    logger.debug('# we have reach the bottom of stack')
                    if ctx.does_it_match_any_story():
                        # but sometimes we could jump on other global matcher
                        logger.debug(
                            '# but sometimes we could jump on other global matcher'
                        )
                        ctx = story_context.reducers.scope_in(ctx)
                        ctx = await self.process_story(ctx)
                        ctx = story_context.reducers.scope_out(ctx)
                        if ctx.is_empty_stack():
                            return ctx.message
                    else:
                        logger.debug('  we have reach the bottom of stack '
                                     'so no once has receive this message')
                        return ctx.message

                if ctx.is_scope_level() and \
                        (ctx.has_child_story() or ctx.matched) and \
                        not ctx.is_breaking_a_loop() or \
                                not ctx.is_scope_level() and \
                                not ctx.is_end_of_story():
                    # if we
                    # - haven't reach last step in list of story
                    # - isn't breaking a loop
                    # - inside of child scope and have matching sub-stories
                    # so we can parse result
                    break

                logger.debug('# tuning scope_out')
                ctx = story_context.reducers.scope_out(ctx)

            if ctx.has_child_story():
                logger.debug('# has child story')
                ctx = story_context.reducers.scope_in(ctx)
            ctx = await self.process_story(ctx)
            logger.debug('# match_message scope_out')
            ctx = story_context.reducers.scope_out(ctx)

            if ctx.is_scope_level() and not ctx.is_breaking_a_loop():
                logger.debug('# the end of one story scope')
                break

        return ctx.message