diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-04 15:59:57 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-04 16:00:04 +0000 |
commit | 44291a7469de49e5e1c73449c9928e7e54ff8d67 (patch) | |
tree | f14d7afb233fb6622b728301430b18fbb0020050 | |
parent | Releasing debian version 4.66.2-3. (diff) | |
download | tqdm-44291a7469de49e5e1c73449c9928e7e54ff8d67.tar.xz tqdm-44291a7469de49e5e1c73449c9928e7e54ff8d67.zip |
Merging upstream version 4.66.4:
- any optional non-boolean CLI arguments are passed through python's eval,
allowing arbitrary code execution [CVE-2024-34062] (Closes: #1070372).
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
-rw-r--r-- | .pre-commit-config.yaml | 2 | ||||
-rw-r--r-- | DEMO.ipynb | 2 | ||||
-rw-r--r-- | README.rst | 4 | ||||
-rw-r--r-- | tests/tests_tqdm.py | 6 | ||||
-rw-r--r-- | tqdm/asyncio.py | 2 | ||||
-rw-r--r-- | tqdm/cli.py | 33 | ||||
-rw-r--r-- | tqdm/contrib/__init__.py | 2 | ||||
-rw-r--r-- | tqdm/contrib/discord.py | 8 | ||||
-rw-r--r-- | tqdm/contrib/logging.py | 2 | ||||
-rw-r--r-- | tqdm/contrib/slack.py | 8 | ||||
-rw-r--r-- | tqdm/contrib/telegram.py | 10 | ||||
-rw-r--r-- | tqdm/dask.py | 2 | ||||
-rw-r--r-- | tqdm/gui.py | 2 | ||||
-rw-r--r-- | tqdm/notebook.py | 14 | ||||
-rw-r--r-- | tqdm/rich.py | 7 | ||||
-rw-r--r-- | tqdm/std.py | 2 | ||||
-rw-r--r-- | tqdm/tk.py | 4 | ||||
-rw-r--r-- | tqdm/utils.py | 6 |
18 files changed, 64 insertions, 52 deletions
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 4de1025..5eb5e3c 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -2,7 +2,7 @@ default_language_version: python: python3 repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.5.0 + rev: v4.6.0 hooks: - id: check-added-large-files - id: check-case-conflict @@ -413,7 +413,7 @@ " \"\"\"Provides a `total_time` format parameter\"\"\"\n", " @property\n", " def format_dict(self):\n", - " d = super(TqdmExtraFormat, self).format_dict\n", + " d = super().format_dict\n", " total_time = d[\"elapsed\"] * (d[\"total\"] or 0) / max(d[\"n\"], 1)\n", " d.update(total_time=self.format_interval(total_time) + \" in total\")\n", " return d\n", @@ -766,7 +766,7 @@ Additional ``bar_format`` parameters may also be defined by overriding """Provides a `total_time` format parameter""" @property def format_dict(self): - d = super(TqdmExtraFormat, self).format_dict + d = super().format_dict total_time = d["elapsed"] * (d["total"] or 0) / max(d["n"], 1) d.update(total_time=self.format_interval(total_time) + " in total") return d @@ -982,7 +982,7 @@ custom callback take advantage of this, simply use the return value of class TqdmExt(std_tqdm): def update(self, n=1): - displayed = super(TqdmExt, self).update(n) + displayed = super().update(n) if displayed: external_callback(**self.format_dict) return displayed diff --git a/tests/tests_tqdm.py b/tests/tests_tqdm.py index d0ba14f..25644aa 100644 --- a/tests/tests_tqdm.py +++ b/tests/tests_tqdm.py @@ -107,7 +107,7 @@ def cpu_timify(t, timer=None): class UnicodeIO(IOBase): """Unicode version of StringIO""" def __init__(self, *args, **kwargs): - super(UnicodeIO, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) self.encoding = 'U8' # io.StringIO supports unicode, but no encoding self.text = '' self.cursor = 0 @@ -342,7 +342,7 @@ def test_all_defaults(): class WriteTypeChecker(BytesIO): """File-like to assert the expected type is written""" def __init__(self, expected_type): - super(WriteTypeChecker, self).__init__() + super().__init__() self.expected_type = expected_type def write(self, s): @@ -1095,7 +1095,7 @@ def test_custom_format(): """Provides a `total_time` format parameter""" @property def format_dict(self): - d = super(TqdmExtraFormat, self).format_dict + d = super().format_dict total_time = d["elapsed"] * (d["total"] or 0) / max(d["n"], 1) d.update(total_time=self.format_interval(total_time) + " in total") return d diff --git a/tqdm/asyncio.py b/tqdm/asyncio.py index ddc89b8..2d00a0a 100644 --- a/tqdm/asyncio.py +++ b/tqdm/asyncio.py @@ -21,7 +21,7 @@ class tqdm_asyncio(std_tqdm): Asynchronous-friendly version of tqdm. """ def __init__(self, iterable=None, *args, **kwargs): - super(tqdm_asyncio, self).__init__(iterable, *args, **kwargs) + super().__init__(iterable, *args, **kwargs) self.iterable_awaitable = False if iterable is not None: if hasattr(iterable, "__anext__"): diff --git a/tqdm/cli.py b/tqdm/cli.py index 1223d49..7284f28 100644 --- a/tqdm/cli.py +++ b/tqdm/cli.py @@ -21,23 +21,34 @@ def cast(val, typ): return cast(val, t) except TqdmTypeError: pass - raise TqdmTypeError(val + ' : ' + typ) + raise TqdmTypeError(f"{val} : {typ}") # sys.stderr.write('\ndebug | `val:type`: `' + val + ':' + typ + '`.\n') if typ == 'bool': if (val == 'True') or (val == ''): return True - elif val == 'False': + if val == 'False': return False - else: - raise TqdmTypeError(val + ' : ' + typ) - try: - return eval(typ + '("' + val + '")') - except Exception: - if typ == 'chr': - return chr(ord(eval('"' + val + '"'))).encode() - else: - raise TqdmTypeError(val + ' : ' + typ) + raise TqdmTypeError(val + ' : ' + typ) + if typ == 'chr': + if len(val) == 1: + return val.encode() + if re.match(r"^\\\w+$", val): + return eval(f'"{val}"').encode() + raise TqdmTypeError(f"{val} : {typ}") + if typ == 'str': + return val + if typ == 'int': + try: + return int(val) + except ValueError as exc: + raise TqdmTypeError(f"{val} : {typ}") from exc + if typ == 'float': + try: + return float(val) + except ValueError as exc: + raise TqdmTypeError(f"{val} : {typ}") from exc + raise TqdmTypeError(f"{val} : {typ}") def posix_pipe(fin, fout, delim=b'\\n', buf_size=256, diff --git a/tqdm/contrib/__init__.py b/tqdm/contrib/__init__.py index 7338c96..d059461 100644 --- a/tqdm/contrib/__init__.py +++ b/tqdm/contrib/__init__.py @@ -17,7 +17,7 @@ class DummyTqdmFile(ObjectWrapper): """Dummy file-like that will write to tqdm""" def __init__(self, wrapped): - super(DummyTqdmFile, self).__init__(wrapped) + super().__init__(wrapped) self._buf = [] def write(self, x, nolock=False): diff --git a/tqdm/contrib/discord.py b/tqdm/contrib/discord.py index 1e41308..fd663f9 100644 --- a/tqdm/contrib/discord.py +++ b/tqdm/contrib/discord.py @@ -27,7 +27,7 @@ class DiscordIO(MonoWorker): """Non-blocking file-like IO using a Discord Bot.""" def __init__(self, token, channel_id): """Creates a new message in the given `channel_id`.""" - super(DiscordIO, self).__init__() + super().__init__() config = ClientConfig() config.token = token client = Client(config) @@ -91,10 +91,10 @@ class tqdm_discord(tqdm_auto): kwargs.pop('token', getenv("TQDM_DISCORD_TOKEN")), kwargs.pop('channel_id', getenv("TQDM_DISCORD_CHANNEL_ID"))) kwargs['mininterval'] = max(1.5, kwargs.get('mininterval', 1.5)) - super(tqdm_discord, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) def display(self, **kwargs): - super(tqdm_discord, self).display(**kwargs) + super().display(**kwargs) fmt = self.format_dict if fmt.get('bar_format', None): fmt['bar_format'] = fmt['bar_format'].replace( @@ -104,7 +104,7 @@ class tqdm_discord(tqdm_auto): self.dio.write(self.format_meter(**fmt)) def clear(self, *args, **kwargs): - super(tqdm_discord, self).clear(*args, **kwargs) + super().clear(*args, **kwargs) if not self.disable: self.dio.write("") diff --git a/tqdm/contrib/logging.py b/tqdm/contrib/logging.py index b8eaec5..e06febe 100644 --- a/tqdm/contrib/logging.py +++ b/tqdm/contrib/logging.py @@ -18,7 +18,7 @@ class _TqdmLoggingHandler(logging.StreamHandler): self, tqdm_class=std_tqdm # type: Type[std_tqdm] ): - super(_TqdmLoggingHandler, self).__init__() + super().__init__() self.tqdm_class = tqdm_class def emit(self, record): diff --git a/tqdm/contrib/slack.py b/tqdm/contrib/slack.py index d4c850c..9bca8ee 100644 --- a/tqdm/contrib/slack.py +++ b/tqdm/contrib/slack.py @@ -27,7 +27,7 @@ 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__() + super().__init__() self.client = WebClient(token=token) self.text = self.__class__.__name__ try: @@ -88,10 +88,10 @@ class tqdm_slack(tqdm_auto): 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) + super().__init__(*args, **kwargs) def display(self, **kwargs): - super(tqdm_slack, self).display(**kwargs) + super().display(**kwargs) fmt = self.format_dict if fmt.get('bar_format', None): fmt['bar_format'] = fmt['bar_format'].replace( @@ -105,7 +105,7 @@ class tqdm_slack(tqdm_auto): self.sio.write(self.format_meter(**fmt)) def clear(self, *args, **kwargs): - super(tqdm_slack, self).clear(*args, **kwargs) + super().clear(*args, **kwargs) if not self.disable: self.sio.write("") diff --git a/tqdm/contrib/telegram.py b/tqdm/contrib/telegram.py index cbeadf2..0191518 100644 --- a/tqdm/contrib/telegram.py +++ b/tqdm/contrib/telegram.py @@ -27,7 +27,7 @@ class TelegramIO(MonoWorker): def __init__(self, token, chat_id): """Creates a new message in the given `chat_id`.""" - super(TelegramIO, self).__init__() + super().__init__() self.token = token self.chat_id = chat_id self.session = Session() @@ -118,10 +118,10 @@ class tqdm_telegram(tqdm_auto): self.tgio = TelegramIO( kwargs.pop('token', getenv('TQDM_TELEGRAM_TOKEN')), kwargs.pop('chat_id', getenv('TQDM_TELEGRAM_CHAT_ID'))) - super(tqdm_telegram, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) def display(self, **kwargs): - super(tqdm_telegram, self).display(**kwargs) + super().display(**kwargs) fmt = self.format_dict if fmt.get('bar_format', None): fmt['bar_format'] = fmt['bar_format'].replace( @@ -131,14 +131,14 @@ class tqdm_telegram(tqdm_auto): self.tgio.write(self.format_meter(**fmt)) def clear(self, *args, **kwargs): - super(tqdm_telegram, self).clear(*args, **kwargs) + super().clear(*args, **kwargs) if not self.disable: self.tgio.write("") def close(self): if self.disable: return - super(tqdm_telegram, self).close() + super().close() if not (self.leave or (self.leave is None and self.pos == 0)): self.tgio.delete() diff --git a/tqdm/dask.py b/tqdm/dask.py index af9926a..57f1b66 100644 --- a/tqdm/dask.py +++ b/tqdm/dask.py @@ -20,7 +20,7 @@ class TqdmCallback(Callback): tqdm_kwargs : optional Any other arguments used for all bars. """ - super(TqdmCallback, self).__init__(start=start, pretask=pretask) + super().__init__(start=start, pretask=pretask) if tqdm_kwargs: tqdm_class = partial(tqdm_class, **tqdm_kwargs) self.tqdm_class = tqdm_class diff --git a/tqdm/gui.py b/tqdm/gui.py index 8bab6ac..1a80681 100644 --- a/tqdm/gui.py +++ b/tqdm/gui.py @@ -32,7 +32,7 @@ class tqdm_gui(std_tqdm): # pragma: no cover kwargs = kwargs.copy() kwargs['gui'] = True colour = kwargs.pop('colour', 'g') - super(tqdm_gui, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) if self.disable: return diff --git a/tqdm/notebook.py b/tqdm/notebook.py index 6ee43a6..77b91bd 100644 --- a/tqdm/notebook.py +++ b/tqdm/notebook.py @@ -80,7 +80,7 @@ class TqdmHBox(HBox): def __repr__(self, pretty=False): pbar = getattr(self, 'pbar', None) if pbar is None: - return super(TqdmHBox, self).__repr__() + return super().__repr__() return pbar.format_meter(**self._json_(pretty)) def _repr_pretty_(self, pp, *_, **__): @@ -220,7 +220,7 @@ class tqdm_notebook(std_tqdm): kwargs['disable'] = bool(kwargs.get('disable', False)) colour = kwargs.pop('colour', None) display_here = kwargs.pop('display', True) - super(tqdm_notebook, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) if self.disable or not kwargs['gui']: self.disp = lambda *_, **__: None return @@ -246,7 +246,7 @@ class tqdm_notebook(std_tqdm): def __iter__(self): try: - it = super(tqdm_notebook, self).__iter__() + it = super().__iter__() for obj in it: # return super(tqdm...) will not catch exception yield obj @@ -259,7 +259,7 @@ class tqdm_notebook(std_tqdm): def update(self, n=1): try: - return super(tqdm_notebook, self).update(n=n) + return super().update(n=n) # NB: except ... [ as ...] breaks IPython async KeyboardInterrupt except: # NOQA # cannot catch KeyboardInterrupt when using manual tqdm @@ -272,7 +272,7 @@ class tqdm_notebook(std_tqdm): def close(self): if self.disable: return - super(tqdm_notebook, self).close() + super().close() # Try to detect if there was an error or KeyboardInterrupt # in manual mode: if n < total, things probably got wrong if self.total and self.n < self.total: @@ -297,14 +297,14 @@ class tqdm_notebook(std_tqdm): total : int or float, optional. Total to use for the new bar. """ if self.disable: - return super(tqdm_notebook, self).reset(total=total) + return super().reset(total=total) _, pbar, _ = self.container.children pbar.bar_style = '' if total is not None: pbar.max = total if not self.total and self.ncols is None: # no longer unknown total pbar.layout.width = None # reset width - return super(tqdm_notebook, self).reset(total=total) + return super().reset(total=total) def tnrange(*args, **kwargs): diff --git a/tqdm/rich.py b/tqdm/rich.py index 00e1ddf..3d392ed 100644 --- a/tqdm/rich.py +++ b/tqdm/rich.py @@ -90,7 +90,7 @@ class tqdm_rich(std_tqdm): # pragma: no cover kwargs['disable'] = bool(kwargs.get('disable', False)) progress = kwargs.pop('progress', None) options = kwargs.pop('options', {}).copy() - super(tqdm_rich, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) if self.disable: return @@ -116,7 +116,8 @@ class tqdm_rich(std_tqdm): # pragma: no cover def close(self): if self.disable: return - super(tqdm_rich, self).close() + self.display() # print 100%, vis #1306 + super().close() self._prog.__exit__(None, None, None) def clear(self, *_, **__): @@ -137,7 +138,7 @@ class tqdm_rich(std_tqdm): # pragma: no cover """ if hasattr(self, '_prog'): self._prog.reset(total=total) - super(tqdm_rich, self).reset(total=total) + super().reset(total=total) def trrange(*args, **kwargs): diff --git a/tqdm/std.py b/tqdm/std.py index e58fdca..e91ad30 100644 --- a/tqdm/std.py +++ b/tqdm/std.py @@ -46,7 +46,7 @@ class TqdmWarning(Warning): if fp_write is not None: fp_write("\n" + self.__class__.__name__ + ": " + str(msg).rstrip() + '\n') else: - super(TqdmWarning, self).__init__(msg, *a, **k) + super().__init__(msg, *a, **k) class TqdmExperimentalWarning(TqdmWarning, FutureWarning): @@ -53,7 +53,7 @@ class tqdm_tk(std_tqdm): # pragma: no cover grab = kwargs.pop('grab', False) tk_parent = kwargs.pop('tk_parent', None) self._cancel_callback = kwargs.pop('cancel_callback', None) - super(tqdm_tk, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) if self.disable: return @@ -172,7 +172,7 @@ class tqdm_tk(std_tqdm): # pragma: no cover self._tk_pbar.configure(maximum=100, mode="indeterminate") else: self._tk_pbar.configure(maximum=total, mode="determinate") - super(tqdm_tk, self).reset(total=total) + super().reset(total=total) @staticmethod def _tk_dispatching_helper(): diff --git a/tqdm/utils.py b/tqdm/utils.py index 9883fda..f7060be 100644 --- a/tqdm/utils.py +++ b/tqdm/utils.py @@ -167,7 +167,7 @@ class SimpleTextIOWrapper(ObjectWrapper): """ # pylint: disable=too-few-public-methods def __init__(self, wrapped, encoding): - super(SimpleTextIOWrapper, self).__init__(wrapped) + super().__init__(wrapped) self.wrapper_setattr('encoding', encoding) def write(self, s): @@ -211,7 +211,7 @@ class DisableOnWriteError(ObjectWrapper): return inner def __init__(self, wrapped, tqdm_instance): - super(DisableOnWriteError, self).__init__(wrapped) + super().__init__(wrapped) if hasattr(wrapped, 'write'): self.wrapper_setattr( 'write', self.disable_on_exception(tqdm_instance, wrapped.write)) @@ -229,7 +229,7 @@ class CallbackIOWrapper(ObjectWrapper): Wrap a given `file`-like object's `read()` or `write()` to report lengths to the given `callback` """ - super(CallbackIOWrapper, self).__init__(stream) + super().__init__(stream) func = getattr(stream, method) if method == "write": @wraps(func) |