예제 #1
0
def test_promise_thread():
    def run(resolve, _):
        sleep(0.25)
        resolve(3)
    run = Mock(wraps=run)
    p = Promise(run, T.THREAD)

    assert p._state == S.PENDING
    assert p._value is None
    assert p._timeout is None
    assert p._thread is not None
    sleep(0.05)
    run.assert_called_once_with(p._resolve, p._reject)
    run.reset_mock()
    assert not p._event.is_set()

    assert not p.wait(0.05)
    assert run.call_count == 0
    assert p._state == S.PENDING
    assert p._value is None
    assert p._timeout is None
    assert p._thread is not None
    assert not p._event.is_set()

    assert p.wait()
    assert run.call_count == 0
    assert p._state == S.RESOLVED
    assert p._value == 3
    assert p._thread is None
    assert p._event.is_set()

    assert p.wait()
예제 #2
0
def test_promise_immediate():
    run = Mock(wraps=lambda resolve, reject: resolve(2))
    p = Promise(run, ptype=T.IMMEDIATE)
    run.assert_called_once_with(p._resolve, p._reject)
    assert p._state == S.RESOLVED
    assert p._value == 2
    assert p._event.is_set()
    assert p.wait()
예제 #3
0
def test_promise_timeout():
    p = Promise(lambda resolve, _: resolve(0), ptype=T.MANUAL, timeout=0.01)
    p2 = p.then(lambda value: value + 1, timeout=None)
    p2.wait(0.1)
    assert p._state == S.PENDING
    assert p2._state == S.REJECTED
    assert p._value is None
    assert isinstance(p2._value, PromiseTimeout)
예제 #4
0
def test_promise_on_reject_2():
    on_resolve = Mock(wraps=lambda _: int('x'))
    on_reject = Mock(wraps=lambda _: Promise.reject(2))
    p = Promise.resolve(0).then(on_resolve, on_reject)
    p.wait()
    on_resolve.assert_called_once_with(0)
    assert on_reject.call_count == 0
    assert isinstance(p._value, Exception)
    assert p._state == S.REJECTED
예제 #5
0
def test_promise_on_reject():
    on_resolve = Mock(wraps=lambda _: 1)
    on_reject = Mock(wraps=lambda _: Promise.reject(2))
    p = Promise.reject(0).then(on_resolve, on_reject)
    p.wait()
    on_reject.assert_called_once_with(0)
    assert on_resolve.call_count == 0
    assert p._value == 2
    assert p._state == S.REJECTED
예제 #6
0
 def run(_=None):
     nonlocal i
     if i == reject_i:
         if error:
             raise error()
         return Promise.reject(-i)
     i += 1
     if i < length:
         return Promise.resolve(i).then(run)
     return i
예제 #7
0
def test_promise_chain_length(length, reject_i, error):
    i = 0
    def run(_=None):
        nonlocal i
        if i == reject_i:
            if error:
                raise error()
            return Promise.reject(-i)
        i += 1
        return i
    run = Mock(wraps=run)
    chain = [Promise.resolve(0)]
    for i_ in range(length):
        chain.append(chain[i_].then(run))
    assert i == 0
    assert run.call_count == 0
    assert [p._state for p in chain[1:]] == [S.PENDING] * length
    assert chain[len(chain) - 1].wait(0.2)
    assert i == reject_i
    assert run.call_count == i if reject_i >= length else i + 1
    assert [p._state for p in chain[1:i + 1]] == [S.RESOLVED] * reject_i
    assert [p._state for p in chain[i + 1:]] == [S.REJECTED] * (length - reject_i)
    assert [p._value for p in chain[1:i + 1]] == list(range(1, reject_i + 1))
    reject_n = length - reject_i
    if error is not None:
        assert [type(p._value) for p in chain[i + 1:]] == [error] * reject_n
    else:
        assert [p._value for p in chain[i + 1:]] == [-i] * reject_n
예제 #8
0
def test_promise_resolve():
    p = Promise.resolve(0)
    assert p._state == S.RESOLVED
    assert p._value == 0
    assert p._timeout is None
    assert p._thread is None
    assert p._event.is_set()
예제 #9
0
def test_promise_reject():
    p = Promise.reject(1)
    assert p._state == S.REJECTED
    assert p._value == 1
    assert p._timeout is None
    assert p._thread is None
    assert p._event.is_set()
예제 #10
0
 def run(_=None):
     nonlocal i
     if i == reject_i:
         if error:
             raise error()
         return Promise.reject(-i)
     i += 1
     return i
예제 #11
0
def test_promise_default():
    run = Mock(wraps=lambda resolve, reject: resolve(2))
    p = Promise(run)
    assert p._state == S.PENDING
    assert p._value is None
    assert p._timeout is None
    assert p._thread is None
    assert run.call_count == 0
    assert not p._event.is_set()

    assert p.wait()
    run.assert_called_once_with(p._resolve, p._reject)
    assert p._state == S.RESOLVED
    assert p._value == 2
    assert p._event.is_set()

    run.reset_mock()
    assert p.wait()
    assert run.call_count == 0
예제 #12
0
def check_permission(bot, user, min_value=Permission.USER):
    try:
        value = get_permission(user)
    except sqlite3.ProgrammingError:
        get_permission_ = Promise.wrap(get_permission, ptype=PT.MANUAL)
        bot.queue.put(get_permission_)
        get_permission_.wait()
        value = get_permission_.value
    if not isinstance(value, int):
        bot.logger.error('check_permission: %r', value)
        return False, True
    return value >= min_value, value > Permission.IGNORED
예제 #13
0
    def cmd_ocr(self, _, update):
        msg = update.message
        args = strip_command(msg.text)

        if args and not re.match(r'^[a-z]{3}([+_][a-z]{3})*$', args):
            update.message.reply_text('invalid language %r' % args)
            return

        if msg.photo:
            pass
        elif msg.reply_to_message and msg.reply_to_message.photo:
            msg = msg.reply_to_message
        else:
            update.message.reply_text('no input image')
            return

        deferred = Promise.defer()
        self.state.bot.download_file(msg, self.state.file_dir, deferred)
        self.state.run_async(self._run_script, update,
                             'ocr', [args], deferred.promise, 'no text found')
예제 #14
0
def test_promise_chain_depth(length, reject_i, error):
    i = 0
    def run(_=None):
        nonlocal i
        if i == reject_i:
            if error:
                raise error()
            return Promise.reject(-i)
        i += 1
        if i < length:
            return Promise.resolve(i).then(run)
        return i
    run = Mock(wraps=run)
    start = Promise.resolve(0)
    chain = start.then(run)
    end = chain.then(lambda _: 10)
    assert i == 0
    assert run.call_count == 0
    assert start._state == S.RESOLVED
    assert chain._state == S.PENDING
    assert end._state == S.PENDING
    assert end.wait(0.2)
    if reject_i >= length:
        assert chain._value == length
        assert end._value == 10
        assert chain._state == S.RESOLVED
        assert end._state == S.RESOLVED
    else:
        if error is not None:
            assert isinstance(chain._value, error)
            assert isinstance(chain._value, error)
        else:
            assert chain._value == -reject_i
            assert end._value == -reject_i
        assert chain._state == S.REJECTED
        assert end._state == S.REJECTED
    assert i == reject_i
    assert run.call_count == i if reject_i >= length else i + 1
    assert start._state == S.RESOLVED
예제 #15
0
    def cmd_makesticker(self, _, update):
        msg = update.message
        if msg.photo or msg.document:
            pass
        elif msg.reply_to_message and (
                msg.reply_to_message.photo
                or msg.reply_to_message.document
        ):
            msg = msg.reply_to_message
        else:
            update.message.reply_text('no input image')
            return

        deferred = Promise.defer()
        self.state.bot.download_file(msg, self.state.file_dir, deferred)
        self.state.run_async(
            self._run_script, update,
            'make_sticker', ['{{TMP}}'],
            deferred.promise,
            return_file='png',
            timeout=self.state.query_timeout
        )
예제 #16
0
    def cmd_getfile(self, _, update):
        msg = update.message
        try:
            ftype, _ = get_file(msg)
        except ValueError:
            try:
                msg = msg.reply_to_message
                ftype, _ = get_file(msg)
            except (AttributeError, ValueError):
                update.message.reply_text('no input file', quote=True)
                return

        if ftype == 'sticker':
            convert = 'unmake_sticker'
            ext = 'png'
        #elif ftype == 'video_note':
        #    convert = 'unmake_video'
        #    ext = ''
        #elif ftype == 'voice':
        #    convert = 'unmake_voice'
        #    ext = ''
        else:
            update.message.reply_text(
                'file type "%s" is not supported' % ftype,
                quote=True
            )
            return

        deferred = Promise.defer()
        self.state.bot.download_file(msg, self.state.file_dir, deferred)
        self.state.run_async(
            self._run_script, update,
            convert, ['{{TMP}}'],
            deferred.promise,
            return_file=ext,
            timeout=self.state.query_timeout
        )
예제 #17
0
def test_promise_state_not_set():
    p = Promise(lambda *_: None, ptype=T.IMMEDIATE)
    assert p._state == S.REJECTED
    assert isinstance(p._value, PromiseStateNotSet)
    assert p._timeout is None
    assert p._thread is None
예제 #18
0
        def ret(self, bot, update):
            self.logger.info('command %s', method.__name__)

            if update.message is not None:
                if (update.message.text and not match_command_user(
                        update.message.text, self.state.username)):
                    self.logger.info('!match_command_user %s' %
                                     update.message.text)
                    return

                chat = update.message.chat
                if chat.type == chat.PRIVATE:
                    perm = permission_private
                else:
                    perm = permission

                perm, reply = check_permission(self, update.message.from_user,
                                               perm)
                if not perm:
                    if reply:
                        self.logger.warning('permission denied: %s',
                                            update.message)
                        update.message.reply_text('permission denied',
                                                  quote=True)
                    return

            try:
                res = method(self, bot, update)
            except (BotError, dice.DiceBaseException) as ex:
                self.logger.warning(ex)
                update.message.reply_text(str(ex), quote=True)
                return
            except Exception as ex:
                self.logger.error(ex)
                update.message.reply_text(repr(ex), quote=True)
                raise

            on_resolve = lambda msg: reply_text(update, msg, True)
            on_reject = on_resolve

            if type_ == CommandType.NONE:
                return res
            elif type_ == CommandType.REPLY_TEXT:
                pass
            elif type_ == CommandType.REPLY_STICKER:
                on_resolve = lambda msg: reply_sticker(update, msg, True)
            elif type_ == CommandType.GET_OPTIONS:
                on_resolve = lambda res: reply_keyboard(update, res)
            elif type_ == CommandType.SET_OPTION:
                on_resolve = lambda msg: reply_callback_query(update, msg)
                on_reject = on_resolve
            elif type_ == CommandType.REPLY_TEXT_PAGINATED:
                on_resolve = lambda msg: reply_text_paginated(
                    update, msg, True)
            else:
                raise ValueError('invalid command type: %s' % type_)

            if res is None:
                self.logger.info('%s: no command', method.__name__)
                return
            if isinstance(res, Promise):
                promise = res
            elif not callable(res):
                on_resolve(res)
                return
            else:
                promise = Promise.wrap(res, update, ptype=PT.MANUAL)
            self.queue.put(promise)
            promise.then(on_resolve, on_reject).wait()
예제 #19
0
    def _search(self, update, query, reset=False):
        chat = update.effective_chat
        chat_id = chat.id
        settings = self.state.get_chat_settings(chat)

        if update.callback_query:
            user = update.callback_query.from_user
            reply_to = None
        else:
            user = update.message.from_user
            reply_to = update.message.message_id

        primary_bot = self.state.bot.primary.bot
        if chat.type == chat.PRIVATE:
            bot = primary_bot
        else:
            bot = self.state.bot.updaters[-1].bot

        try:
            enabled = settings['search_enabled']
        except KeyError:
            enabled = False
        if not enabled:
            if reply_to is not None:
                primary_bot.send_message(chat_id,
                                         '"search_enabled": false',
                                         quote=True,
                                         reply_to_message_id=reply_to)
            return

        learn = Promise.wrap(self.state.learn_search_query,
                             query,
                             user,
                             reset,
                             ptype=PT.MANUAL)
        self.state.bot.queue.put(learn)
        learn.wait()
        offset = learn.value

        if isinstance(offset, Exception):
            self.logger.error(offset)
            return

        try:
            bot.send_chat_action(chat_id, ChatAction.UPLOAD_PHOTO)
        except (Unauthorized, BadRequest) as ex:
            self.logger.warning('send_chat_action: %r', ex)
            try:
                primary_bot.send_message(chat_id,
                                         'add secondary bot to group',
                                         quote=True,
                                         reply_to_message_id=reply_to)
            except TelegramError as ex:
                self.logger.warning('send error message: %r', ex)
            return
        except TelegramError as ex:
            self.logger.error('send_chat_action: %r', ex)

        try:
            res, is_last = self.state.search(query, offset)
        except SearchError as ex:
            primary_bot.send_message(chat_id,
                                     str(ex),
                                     quote=True,
                                     reply_to_message_id=reply_to)
        except Exception as ex:
            primary_bot.send_message(chat_id,
                                     repr(ex),
                                     quote=True,
                                     reply_to_message_id=reply_to)
            return
        else:
            keyboard = [
                InlineKeyboardButton('\U0001f517 %d' % (offset + 1),
                                     url=res.url)
            ]
            if offset >= 1:
                keyboard.append(
                    InlineKeyboardButton('reset', callback_data='picreset'))
            if not is_last:
                keyboard.append(
                    InlineKeyboardButton('next', callback_data='pic'))
            keyboard = InlineKeyboardMarkup([keyboard])

            if self.RE_VIDEO_LINK.match(res.url):
                bot.send_message(chat_id,
                                 '%s\n%s\n\n%s' % (res.title, res.url, query),
                                 reply_markup=keyboard)
                return

            for url in (res.image, res.thumbnail, None):
                try:
                    self.logger.info('%r %r', query, url)
                    if url is None:
                        bot.send_message(
                            chat_id, '(bad request)\n%s\n%s\n\n%s' %
                            (res.image, res.url, query))
                    else:
                        send_image(bot,
                                   chat_id,
                                   url,
                                   caption=query,
                                   reply_markup=keyboard)
                    return
                except TelegramError as ex:
                    self.logger.info('image post failed: %r: %r', res, ex)