Skip to content

Commit

Permalink
bump version, merge branch 'slack'
Browse files Browse the repository at this point in the history
  • Loading branch information
casperdcl committed Apr 4, 2022
2 parents 87d253f + 1d29dec commit 4f208e7
Show file tree
Hide file tree
Showing 7 changed files with 148 additions and 9 deletions.
6 changes: 4 additions & 2 deletions .meta/.readme.rst
Expand Up @@ -473,11 +473,12 @@ The ``tqdm.contrib`` package also contains experimental modules:

- ``tqdm.contrib.itertools``: Thin wrappers around ``itertools``
- ``tqdm.contrib.concurrent``: Thin wrappers around ``concurrent.futures``
- ``tqdm.contrib.slack``: Posts to `Slack <https://slack.com>`__ bots
- ``tqdm.contrib.discord``: Posts to `Discord <https://discord.com>`__ bots
- ``tqdm.contrib.telegram``: Posts to `Telegram <https://telegram.org>`__ bots
- ``tqdm.contrib.bells``: Automagically enables all optional features

* ``auto``, ``pandas``, ``discord``, ``telegram``
* ``auto``, ``pandas``, ``slack``, ``discord``, ``telegram``

Examples and Advanced Usage
---------------------------
Expand Down Expand Up @@ -965,8 +966,9 @@ Some submodule examples of inheritance:
- `tqdm/notebook.py <https://github.com/tqdm/tqdm/blob/master/tqdm/notebook.py>`__
- `tqdm/gui.py <https://github.com/tqdm/tqdm/blob/master/tqdm/gui.py>`__
- `tqdm/tk.py <https://github.com/tqdm/tqdm/blob/master/tqdm/tk.py>`__
- `tqdm/contrib/telegram.py <https://github.com/tqdm/tqdm/blob/master/tqdm/contrib/telegram.py>`__
- `tqdm/contrib/slack.py <https://github.com/tqdm/tqdm/blob/master/tqdm/contrib/slack.py>`__
- `tqdm/contrib/discord.py <https://github.com/tqdm/tqdm/blob/master/tqdm/contrib/discord.py>`__
- `tqdm/contrib/telegram.py <https://github.com/tqdm/tqdm/blob/master/tqdm/contrib/telegram.py>`__

Dynamic Monitor/Meter
~~~~~~~~~~~~~~~~~~~~~
Expand Down
6 changes: 4 additions & 2 deletions README.rst
Expand Up @@ -692,11 +692,12 @@ The ``tqdm.contrib`` package also contains experimental modules:

- ``tqdm.contrib.itertools``: Thin wrappers around ``itertools``
- ``tqdm.contrib.concurrent``: Thin wrappers around ``concurrent.futures``
- ``tqdm.contrib.slack``: Posts to `Slack <https://slack.com>`__ bots
- ``tqdm.contrib.discord``: Posts to `Discord <https://discord.com>`__ bots
- ``tqdm.contrib.telegram``: Posts to `Telegram <https://telegram.org>`__ bots
- ``tqdm.contrib.bells``: Automagically enables all optional features

* ``auto``, ``pandas``, ``discord``, ``telegram``
* ``auto``, ``pandas``, ``slack``, ``discord``, ``telegram``

Examples and Advanced Usage
---------------------------
Expand Down Expand Up @@ -1184,8 +1185,9 @@ Some submodule examples of inheritance:
- `tqdm/notebook.py <https://github.com/tqdm/tqdm/blob/master/tqdm/notebook.py>`__
- `tqdm/gui.py <https://github.com/tqdm/tqdm/blob/master/tqdm/gui.py>`__
- `tqdm/tk.py <https://github.com/tqdm/tqdm/blob/master/tqdm/tk.py>`__
- `tqdm/contrib/telegram.py <https://github.com/tqdm/tqdm/blob/master/tqdm/contrib/telegram.py>`__
- `tqdm/contrib/slack.py <https://github.com/tqdm/tqdm/blob/master/tqdm/contrib/slack.py>`__
- `tqdm/contrib/discord.py <https://github.com/tqdm/tqdm/blob/master/tqdm/contrib/discord.py>`__
- `tqdm/contrib/telegram.py <https://github.com/tqdm/tqdm/blob/master/tqdm/contrib/telegram.py>`__

Dynamic Monitor/Meter
~~~~~~~~~~~~~~~~~~~~~
Expand Down
5 changes: 3 additions & 2 deletions environment.yml
Expand Up @@ -29,17 +29,18 @@ dependencies:
- numpy # pandas, keras, contrib.tenumerate
- pandas
- tensorflow # keras
- slack-sdk # contrib.slack
- requests # contrib.telegram
- rich # rich
- argopt # `cd wiki && pymake`
- twine # `pymake pypi`
- wheel # `setup.py bdist_wheel`
# `cd docs && pymake`
- mkdocs-material
- pydoc-markdown >=4.6.0
- pydoc-markdown
- pygments
- pymdown-extensions
- pip:
- py-make >=0.1.0 # `setup.py make/pymake`
- mkdocs-minify-plugin # `cd docs && pymake`
- mkdocs-minify-plugin # `cd docs && pymake`
- git+https://github.com/tqdm/jsmin@python3-only#egg=jsmin # `cd docs && pymake`
2 changes: 2 additions & 0 deletions setup.cfg
Expand Up @@ -84,6 +84,7 @@ include_package_data=True
packages=find:
[options.extras_require]
dev=py-make>=0.1.0; twine; wheel
slack=slack-sdk
telegram=requests
notebook=ipywidgets>=6
[options.entry_points]
Expand Down Expand Up @@ -137,6 +138,7 @@ branch=True
include=tqdm/*
omit=
tqdm/contrib/bells.py
tqdm/contrib/slack.py
tqdm/contrib/discord.py
tqdm/contrib/telegram.py
tqdm/contrib/utils_worker.py
Expand Down
4 changes: 3 additions & 1 deletion tqdm/contrib/bells.py
Expand Up @@ -12,7 +12,9 @@
import warnings
from os import getenv

if getenv("TQDM_TELEGRAM_TOKEN") and getenv("TQDM_TELEGRAM_CHAT_ID"):
if getenv("TQDM_SLACK_TOKEN") and getenv("TQDM_SLACK_CHANNEL"):
from .slack import tqdm, trange
elif getenv("TQDM_TELEGRAM_TOKEN") and getenv("TQDM_TELEGRAM_CHAT_ID"):
from .telegram import tqdm, trange
elif getenv("TQDM_DISCORD_TOKEN") and getenv("TQDM_DISCORD_CHANNEL_ID"):
from .discord import tqdm, trange
Expand Down
8 changes: 6 additions & 2 deletions tqdm/contrib/discord.py
Expand Up @@ -3,7 +3,7 @@
Usage:
>>> from tqdm.contrib.discord import tqdm, trange
>>> for i in tqdm(iterable, token='{token}', channel_id='{channel_id}'):
>>> for i in trange(10, token='{token}', channel_id='{channel_id}'):
... ...
![screenshot](https://img.tqdm.ml/screenshot-discord.png)
Expand Down Expand Up @@ -39,6 +39,7 @@ def __init__(self, token, channel_id):
self.message = client.api.channels_messages_create(channel_id, self.text)
except Exception as e:
tqdm_auto.write(str(e))
self.message = None

def write(self, s):
"""Replaces internal `message`'s text with `s`."""
Expand All @@ -47,9 +48,12 @@ def write(self, s):
s = s.replace('\r', '').strip()
if s == self.text:
return # skip duplicate message
message = self.message
if message is None:
return
self.text = s
try:
future = self.submit(self.message.edit, '`' + s + '`')
future = self.submit(message.edit, '`' + s + '`')
except Exception as e:
tqdm_auto.write(str(e))
else:
Expand Down
126 changes: 126 additions & 0 deletions tqdm/contrib/slack.py
@@ -0,0 +1,126 @@
"""
Sends updates to a Slack app.
Usage:
>>> from tqdm.contrib.slack import tqdm, trange
>>> for i in trange(10, token='{token}', channel='{channel}'):
... ...
![screenshot](https://img.tqdm.ml/screenshot-slack.png)
"""
from __future__ import absolute_import

import logging
from os import getenv

try:
from slack_sdk import WebClient
except ImportError:
raise ImportError("Please `pip install slack-sdk`")

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

__author__ = {"github.com/": ["0x2b3bfa0", "casperdcl"]}
__all__ = ['SlackIO', 'tqdm_slack', 'tsrange', 'tqdm', 'trange']


class SlackIO(MonoWorker):
"""Non-blocking file-like IO using a Slack app."""
def __init__(self, token, channel):
"""Creates a new message in the given `channel`."""
super(SlackIO, self).__init__()
self.client = WebClient(token=token)
self.text = self.__class__.__name__
try:
self.message = self.client.chat_postMessage(channel=channel, text=self.text)
except Exception as e:
tqdm_auto.write(str(e))
self.message = None

def write(self, s):
"""Replaces internal `message`'s text with `s`."""
if not s:
s = "..."
s = s.replace('\r', '').strip()
if s == self.text:
return # skip duplicate message
message = self.message
if message is None:
return
self.text = s
try:
future = self.submit(self.client.chat_update, channel=message['channel'],
ts=message['ts'], text='`' + s + '`')
except Exception as e:
tqdm_auto.write(str(e))
else:
return future


class tqdm_slack(tqdm_auto):
"""
Standard `tqdm.auto.tqdm` but also sends updates to a Slack app.
May take a few seconds to create (`__init__`).
- create a Slack app with the `chat:write` scope & invite it to a
channel: <https://api.slack.com/authentication/basics>
- copy the bot `{token}` & `{channel}` and paste below
>>> from tqdm.contrib.slack import tqdm, trange
>>> for i in tqdm(iterable, token='{token}', channel='{channel}'):
... ...
"""
def __init__(self, *args, **kwargs):
"""
Parameters
----------
token : str, required. Slack token
[default: ${TQDM_SLACK_TOKEN}].
channel : int, required. Slack channel
[default: ${TQDM_SLACK_CHANNEL}].
mininterval : float, optional.
Minimum of [default: 1.5] to avoid rate limit.
See `tqdm.auto.tqdm.__init__` for other parameters.
"""
if not kwargs.get('disable'):
kwargs = kwargs.copy()
logging.getLogger("HTTPClient").setLevel(logging.WARNING)
self.sio = SlackIO(
kwargs.pop('token', getenv("TQDM_SLACK_TOKEN")),
kwargs.pop('channel', getenv("TQDM_SLACK_CHANNEL")))
kwargs['mininterval'] = max(1.5, kwargs.get('mininterval', 1.5))
super(tqdm_slack, self).__init__(*args, **kwargs)

def display(self, **kwargs):
super(tqdm_slack, self).display(**kwargs)
fmt = self.format_dict
if fmt.get('bar_format', None):
fmt['bar_format'] = fmt['bar_format'].replace(
'<bar/>', '`{bar:10}`').replace('{bar}', '`{bar:10u}`')
else:
fmt['bar_format'] = '{l_bar}`{bar:10}`{r_bar}'
if fmt['ascii'] is False:
fmt['ascii'] = [":black_square:", ":small_blue_diamond:", ":large_blue_diamond:",
":large_blue_square:"]
fmt['ncols'] = 336
self.sio.write(self.format_meter(**fmt))

def clear(self, *args, **kwargs):
super(tqdm_slack, self).clear(*args, **kwargs)
if not self.disable:
self.sio.write("")


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


# Aliases
tqdm = tqdm_slack
trange = tsrange

0 comments on commit 4f208e7

Please sign in to comment.