Skip to content

Conversation

casperdcl
Copy link
Member

@casperdcl casperdcl commented Apr 26, 2020

Example use pushing to Telegram.

To test:

$ pip install 'git+https://github.com/tqdm/tqdm.git@telegram#egg=tqdm'
from time import sleep
from tqdm.contrib.telegram import tqdm, trange
for i in trange(10, token='1234567890:THIS1SSOMETOKEN0BTAINeDfrOmTELEGrAM',
                chat_id='0246813579'):
    sleep(1)

Idea from tg_tqdm:

@JulienMaille
Copy link

I see you've taken inspiration from original tg_tqdm which relies on telepot (a discontinued library). Everything can be done with simple post requests like shown in this fork https://github.com/dpodvyaznikov/tg_tqdm/blob/9d34f3bb779fe4209cc36ce05b0d19662ad69820/tg_tqdm/_tg_tqdm.py
Would it make sense to pass a 'Bot' object (with a write method) to the constructor in order to make it more versatile?

@casperdcl
Copy link
Member Author

write wouldn't get called in a notebook though.

@JulienMaille
Copy link

I'll show you what I have in mind. But before, it seems it breaks nested progressbar, am I correct?

@JulienMaille
Copy link

JulienMaille commented Apr 27, 2020

Something like this

from tqdm.auto import tqdm as tqdm_auto
from tqdm.utils import _range

class tqdm_telegram(tqdm_auto):
    def __new__(cls, *args, **kwargs):
        # workaround to avoid breaking nested progressbars
        try:
            cls._instances = tqdm_auto._instances
        except AttributeError:
            pass

        instance = super().__new__(cls, *args, **kwargs)

        tqdm_auto._instances = cls._instances
        return instance

    def __init__(self, *args, callback=None, **kwargs):
        """
        Parameters
        ----------
        token  : str, required. Telegram token.
        chat_id  : str, required. Telegram chat ID.
        callback  :  method that will receive the progressbar content on display
        See `tqdm.auto.tqdm.__init__` for other parameters.
        """
        self.callback = callback
        super().__init__(*args, **kwargs)

    def display(self, msg=None, **kwargs):
        super().display(msg=msg, **kwargs)
        fmt = self.format_dict
        if 'bar_format' in fmt and fmt['bar_format']:
            fmt['bar_format'] = fmt['bar_format'].replace('<bar/>', '{bar}')
        if self.callback is not None:
            self.callback(self.format_meter(**fmt))


def ttgrange(*args, **kwargs):
    """
    A shortcut for `tqdm.contrib.telegram.tqdm(xrange(*args), **kwargs)`.
    On Python3+, `range` is used instead of `xrange`.
    """
    return tqdm_telegram(_range(*args), **kwargs)


# Aliases
tqdm = tqdm_telegram
trange = ttgrange
class TelegramIO():
    def __init__(self, token, chat_id, show_last_update=True):
        self.token = token
        self.chat_id = chat_id
        self.session = requests.Session()
        self.text = '_Init_'
        self.message_id = self._sendMessage().json()['result']['message_id']
        self.show_last_update = show_last_update

    def _sendMessage(self):
        try:
            return self.session.post('https://api.telegram.org/bot%s/sendMessage' % self.token,
                                     data=dict(text=self.text, chat_id=self.chat_id, parse_mode='MarkdownV2'))
        except Exception as e:
            print(e)
            return None

    def _editMessageText(self, msg_id, text):
        try:
            return self.session.post('https://api.telegram.org/bot%s/editMessageText' % self.token,
                                     data=dict(text=text, chat_id=self.chat_id, message_id=msg_id, parse_mode='MarkdownV2'))
        except Exception as e:
            print(e)
            return None

    def write(self, s):
        if not s: return
        s = s.strip().replace('\r', '')
        if s == self.text: return  # avoid duplicate message Bot error
        self.text = s

        updated_text = '```\n{}```\n_Update: {}_'.format(self.text, datetime.now().strftime("%H:%M:%S")) if self.show_last_update else ''
        self._editMessageText(self.message_id, updated_text)

Which would be called like that:

tg_bot = TelegramIO(TELEGRAM_BOT_TOKEN, TELEGRAM_CHAT_ID)
iterator = ttgrange(nb_epochs, desc='training', unit='epoch', callback=tg_bot.write)

@codecov-io
Copy link

codecov-io commented Apr 28, 2020

Codecov Report

Merging #949 into master will not change coverage.
The diff coverage is n/a.

@@           Coverage Diff           @@
##           master     #949   +/-   ##
=======================================
  Coverage   87.02%   87.02%           
=======================================
  Files          21       21           
  Lines        1249     1249           
  Branches      213      213           
=======================================
  Hits         1087     1087           
  Misses        141      141           
  Partials       21       21           

@casperdcl
Copy link
Member Author

@JulienMaille should be good to try now (much quicker too than any of the other implementations)

@casperdcl casperdcl added to-merge ↰ Imminent p3-enhancement 🔥 Much new such feature and removed p4-enhancement-future 🧨 On the back burner labels Apr 29, 2020
@casperdcl casperdcl added this to the v5.0.0 milestone Apr 29, 2020
@JulienMaille
Copy link

Looks good!

@casperdcl casperdcl mentioned this pull request May 2, 2020
@casperdcl casperdcl closed this in bcfe12c May 2, 2020
@casperdcl casperdcl merged commit bcfe12c into master May 2, 2020
@casperdcl casperdcl deleted the telegram branch May 2, 2020 23:58
@JulienMaille
Copy link

I'll show you what I have in mind. But before, it seems it breaks nested progressbar, am I correct?

@casperdcl unless there's something wrong on my side, it seems that nested progressbar was broken in the past weeks.

@casperdcl
Copy link
Member Author

casperdcl commented Nov 11, 2020

Specifically for tqdm.contrib.telegram.tqdm or also for tqdm.tqdm? Or tqdm.auto.tqdm?

@JulienMaille
Copy link

I'm sorry for the lack of details, I was thinking that maybe you would have recent change in mind and my remark would ring a bell. Right now I've tested only with ttgrange

@casperdcl
Copy link
Member Author

casperdcl commented Nov 11, 2020

I use ttgrange == tqdm.contrib.telegram.trange all the time in notebooks and nesting works fine. No, I can't think of any recent change which could've caused an issue.

@casperdcl
Copy link
Member Author

casperdcl commented Nov 11, 2020

ah broken when using nested contrib.telegram/discord on the the CLI in tqdm==4.49.0... just opened #1074

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
p3-enhancement 🔥 Much new such feature submodule ⊂ Periphery/subclasses to-merge ↰ Imminent
Projects
None yet
Development

Successfully merging this pull request may close these issues.

'reverse' hook to retrieve current progress/postfix
3 participants