From 65f046e67652e5c7c064fae1505bad9510c468c2 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Fri, 29 Sep 2023 21:53:31 +0200 Subject: [PATCH 1/7] remove some of the last vestiges of ipython_genutils --- qtconsole/comms.py | 2 +- qtconsole/completion_html.py | 7 +- qtconsole/completion_plain.py | 4 +- qtconsole/console_widget.py | 2 +- qtconsole/frontend_widget.py | 2 +- qtconsole/util.py | 212 ++++++++++++++++++++++++++++++++++ 6 files changed, 220 insertions(+), 9 deletions(-) diff --git a/qtconsole/comms.py b/qtconsole/comms.py index 74f8ce5c..6ea9a693 100644 --- a/qtconsole/comms.py +++ b/qtconsole/comms.py @@ -11,12 +11,12 @@ from traitlets.config import LoggingConfigurable -from ipython_genutils.importstring import import_item import uuid from qtpy import QtCore from qtconsole.util import MetaQObjectHasTraits, SuperQObject +from .util import import_item class CommManager(MetaQObjectHasTraits( diff --git a/qtconsole/completion_html.py b/qtconsole/completion_html.py index 62391112..11250894 100644 --- a/qtconsole/completion_html.py +++ b/qtconsole/completion_html.py @@ -3,9 +3,9 @@ # Copyright (c) Jupyter Development Team. # Distributed under the terms of the Modified BSD License. -import ipython_genutils.text as text from qtpy import QtCore, QtGui, QtWidgets +from .util import compute_item_matrix #-------------------------------------------------------------------------- # Return an HTML table with selected item in a special class @@ -311,9 +311,8 @@ def show_items(self, cursor, items, prefix_length=0): width = self._text_edit.document().textWidth() char_width = self._console_widget._get_font_width() displaywidth = int(max(10, (width / char_width) - 1)) - items_m, ci = text.compute_item_matrix(items, empty=' ', - displaywidth=displaywidth) - self._sliding_interval = SlidingInterval(len(items_m)-1, width=self._rows) + items_m, ci = compute_item_matrix(items, empty=" ", displaywidth=displaywidth) + self._sliding_interval = SlidingInterval(len(items_m) - 1, width=self._rows) self._items = items_m self._size = (ci['rows_numbers'], ci['columns_numbers']) diff --git a/qtconsole/completion_plain.py b/qtconsole/completion_plain.py index 6596c907..0f19cfb4 100644 --- a/qtconsole/completion_plain.py +++ b/qtconsole/completion_plain.py @@ -4,7 +4,7 @@ # Distributed under the terms of the Modified BSD License. from qtpy import QtCore, QtGui, QtWidgets -import ipython_genutils.text as text +from .util import columnize class CompletionPlain(QtWidgets.QWidget): @@ -53,7 +53,7 @@ def show_items(self, cursor, items, prefix_length=0): if not items : return self.cancel_completion() - strng = text.columnize(items) + strng = columnize(items) # Move cursor to start of the prefix to replace it # when a item is selected cursor.movePosition(QtGui.QTextCursor.Left, n=prefix_length) diff --git a/qtconsole/console_widget.py b/qtconsole/console_widget.py index 447be581..a4cdff6a 100644 --- a/qtconsole/console_widget.py +++ b/qtconsole/console_widget.py @@ -19,7 +19,6 @@ from qtconsole.rich_text import HtmlExporter from qtconsole.util import MetaQObjectHasTraits, get_font, superQ -from ipython_genutils.text import columnize from traitlets.config.configurable import LoggingConfigurable from traitlets import Bool, Enum, Integer, Unicode @@ -28,6 +27,7 @@ from .completion_html import CompletionHtml from .completion_plain import CompletionPlain from .kill_ring import QtKillRing +from .util import columnize def is_letter_or_number(char): diff --git a/qtconsole/frontend_widget.py b/qtconsole/frontend_widget.py index d7d1134d..9cc96a59 100644 --- a/qtconsole/frontend_widget.py +++ b/qtconsole/frontend_widget.py @@ -9,7 +9,6 @@ import re from qtpy import QtCore, QtGui, QtWidgets -from ipython_genutils.importstring import import_item from qtconsole.base_frontend_mixin import BaseFrontendMixin from traitlets import Any, Bool, Instance, Unicode, DottedObjectName, default @@ -17,6 +16,7 @@ from .call_tip_widget import CallTipWidget from .history_console_widget import HistoryConsoleWidget from .pygments_highlighter import PygmentsHighlighter +from .util import import_item class FrontendHighlighter(PygmentsHighlighter): diff --git a/qtconsole/util.py b/qtconsole/util.py index 7c1a116d..ce55e74f 100644 --- a/qtconsole/util.py +++ b/qtconsole/util.py @@ -106,3 +106,215 @@ def get_font(family, fallback=None): if fallback is not None and font_info.family() != family: font = QtGui.QFont(fallback) return font + + +# ----------------------------------------------------------------------------- +# Vendored from ipython_genutils +# ----------------------------------------------------------------------------- +def _col_chunks(l, max_rows, row_first=False): + """Yield successive max_rows-sized column chunks from l.""" + if row_first: + ncols = (len(l) // max_rows) + (len(l) % max_rows > 0) + for i in range(ncols): + yield [l[j] for j in range(i, len(l), ncols)] + else: + for i in range(0, len(l), max_rows): + yield l[i : (i + max_rows)] + + +def _find_optimal(rlist, row_first=False, separator_size=2, displaywidth=80): + """Calculate optimal info to columnize a list of string""" + for max_rows in range(1, len(rlist) + 1): + col_widths = list(map(max, _col_chunks(rlist, max_rows, row_first))) + sumlength = sum(col_widths) + ncols = len(col_widths) + if sumlength + separator_size * (ncols - 1) <= displaywidth: + break + return { + "num_columns": ncols, + "optimal_separator_width": (displaywidth - sumlength) // (ncols - 1) + if (ncols - 1) + else 0, + "max_rows": max_rows, + "column_widths": col_widths, + } + + +def _get_or_default(mylist, i, default=None): + """return list item number, or default if don't exist""" + if i >= len(mylist): + return default + else: + return mylist[i] + + +def compute_item_matrix(items, row_first=False, empty=None, *args, **kwargs): + """Returns a nested list, and info to columnize items + + Parameters + ---------- + items + list of strings to columize + row_first : (default False) + Whether to compute columns for a row-first matrix instead of + column-first (default). + empty : (default None) + default value to fill list if needed + separator_size : int (default=2) + How much characters will be used as a separation between each columns. + displaywidth : int (default=80) + The width of the area onto which the columns should enter + + Returns + ------- + strings_matrix + nested list of string, the outer most list contains as many list as + rows, the innermost lists have each as many element as columns. If the + total number of elements in `items` does not equal the product of + rows*columns, the last element of some lists are filled with `None`. + dict_info + some info to make columnize easier: + + num_columns + number of columns + max_rows + maximum number of rows (final number may be less) + column_widths + list of with of each columns + optimal_separator_width + best separator width between columns + + Examples + -------- + :: + + In [1]: l = ['aaa','b','cc','d','eeeee','f','g','h','i','j','k','l'] + In [2]: list, info = compute_item_matrix(l, displaywidth=12) + In [3]: list + Out[3]: [['aaa', 'f', 'k'], ['b', 'g', 'l'], ['cc', 'h', None], ['d', 'i', None], ['eeeee', 'j', None]] + In [4]: ideal = {'num_columns': 3, 'column_widths': [5, 1, 1], 'optimal_separator_width': 2, 'max_rows': 5} + In [5]: all((info[k] == ideal[k] for k in ideal.keys())) + Out[5]: True + """ + info = _find_optimal(list(map(len, items)), row_first, *args, **kwargs) + nrow, ncol = info["max_rows"], info["num_columns"] + if row_first: + return ( + [ + [ + _get_or_default(items, r * ncol + c, default=empty) + for c in range(ncol) + ] + for r in range(nrow) + ], + info, + ) + else: + return ( + [ + [ + _get_or_default(items, c * nrow + r, default=empty) + for c in range(ncol) + ] + for r in range(nrow) + ], + info, + ) + + +def columnize(items, row_first=False, separator=" ", displaywidth=80, spread=False): + """Transform a list of strings into a single string with columns. + + Parameters + ---------- + items : sequence of strings + The strings to process. + row_first : (default False) + Whether to compute columns for a row-first matrix instead of + column-first (default). + separator : str, optional [default is two spaces] + The string that separates columns. + displaywidth : int, optional [default is 80] + Width of the display in number of characters. + + Returns + ------- + The formatted string. + """ + if not items: + return "\n" + matrix, info = compute_item_matrix( + items, + row_first=row_first, + separator_size=len(separator), + displaywidth=displaywidth, + ) + if spread: + separator = separator.ljust(int(info["optimal_separator_width"])) + fmatrix = [filter(None, x) for x in matrix] + sjoin = lambda x: separator.join( + [y.ljust(w, " ") for y, w in zip(x, info["column_widths"])] + ) + return "\n".join(map(sjoin, fmatrix)) + "\n" + + +def get_text_list(list_, last_sep=" and ", sep=", ", wrap_item_with=""): + """ + Return a string with a natural enumeration of items + + >>> get_text_list(['a', 'b', 'c', 'd']) + 'a, b, c and d' + >>> get_text_list(['a', 'b', 'c'], ' or ') + 'a, b or c' + >>> get_text_list(['a', 'b', 'c'], ', ') + 'a, b, c' + >>> get_text_list(['a', 'b'], ' or ') + 'a or b' + >>> get_text_list(['a']) + 'a' + >>> get_text_list([]) + '' + >>> get_text_list(['a', 'b'], wrap_item_with="`") + '`a` and `b`' + >>> get_text_list(['a', 'b', 'c', 'd'], " = ", sep=" + ") + 'a + b + c = d' + """ + if len(list_) == 0: + return "" + if wrap_item_with: + list_ = ["%s%s%s" % (wrap_item_with, item, wrap_item_with) for item in list_] + if len(list_) == 1: + return list_[0] + return "%s%s%s" % (sep.join(i for i in list_[:-1]), last_sep, list_[-1]) + + +def import_item(name): + """Import and return ``bar`` given the string ``foo.bar``. + + Calling ``bar = import_item("foo.bar")`` is the functional equivalent of + executing the code ``from foo import bar``. + + Parameters + ---------- + name : string + The fully qualified name of the module/package being imported. + + Returns + ------- + mod : module object + The module that was imported. + """ + + parts = name.rsplit(".", 1) + if len(parts) == 2: + # called with 'foo.bar....' + package, obj = parts + module = __import__(package, fromlist=[obj]) + try: + pak = getattr(module, obj) + except AttributeError: + raise ImportError("No module named %s" % obj) + return pak + else: + # called with un-dotted string + return __import__(parts[0]) From 18f7d6467287fae75125bef4a8450c1955655b31 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Sun, 1 Oct 2023 09:15:36 -0700 Subject: [PATCH 2/7] Apply suggestions from code review Co-authored-by: Carlos Cordoba --- qtconsole/comms.py | 4 ++-- qtconsole/completion_html.py | 1 + qtconsole/completion_plain.py | 1 + qtconsole/util.py | 17 +++++++++++------ 4 files changed, 15 insertions(+), 8 deletions(-) diff --git a/qtconsole/comms.py b/qtconsole/comms.py index 6ea9a693..7280e60d 100644 --- a/qtconsole/comms.py +++ b/qtconsole/comms.py @@ -15,8 +15,8 @@ import uuid from qtpy import QtCore -from qtconsole.util import MetaQObjectHasTraits, SuperQObject -from .util import import_item + +from qtconsole.util import MetaQObjectHasTraits, SuperQObject, import_item class CommManager(MetaQObjectHasTraits( diff --git a/qtconsole/completion_html.py b/qtconsole/completion_html.py index 11250894..8881b8a4 100644 --- a/qtconsole/completion_html.py +++ b/qtconsole/completion_html.py @@ -5,6 +5,7 @@ from qtpy import QtCore, QtGui, QtWidgets + from .util import compute_item_matrix #-------------------------------------------------------------------------- diff --git a/qtconsole/completion_plain.py b/qtconsole/completion_plain.py index 0f19cfb4..367ceacd 100644 --- a/qtconsole/completion_plain.py +++ b/qtconsole/completion_plain.py @@ -4,6 +4,7 @@ # Distributed under the terms of the Modified BSD License. from qtpy import QtCore, QtGui, QtWidgets + from .util import columnize diff --git a/qtconsole/util.py b/qtconsole/util.py index ce55e74f..26133fdf 100644 --- a/qtconsole/util.py +++ b/qtconsole/util.py @@ -123,13 +123,14 @@ def _col_chunks(l, max_rows, row_first=False): def _find_optimal(rlist, row_first=False, separator_size=2, displaywidth=80): - """Calculate optimal info to columnize a list of string""" + """Calculate optimal info to columnize a list of strings.""" for max_rows in range(1, len(rlist) + 1): col_widths = list(map(max, _col_chunks(rlist, max_rows, row_first))) sumlength = sum(col_widths) ncols = len(col_widths) if sumlength + separator_size * (ncols - 1) <= displaywidth: break + return { "num_columns": ncols, "optimal_separator_width": (displaywidth - sumlength) // (ncols - 1) @@ -159,21 +160,21 @@ def compute_item_matrix(items, row_first=False, empty=None, *args, **kwargs): Whether to compute columns for a row-first matrix instead of column-first (default). empty : (default None) - default value to fill list if needed + Default value to fill list if needed separator_size : int (default=2) - How much characters will be used as a separation between each columns. + How much characters will be used as a separation between each column. displaywidth : int (default=80) The width of the area onto which the columns should enter Returns ------- strings_matrix - nested list of string, the outer most list contains as many list as + Nested list of strings, the outer most list contains as many list as rows, the innermost lists have each as many element as columns. If the total number of elements in `items` does not equal the product of rows*columns, the last element of some lists are filled with `None`. dict_info - some info to make columnize easier: + Some info to make columnize easier: num_columns number of columns @@ -243,18 +244,21 @@ def columnize(items, row_first=False, separator=" ", displaywidth=80, spread=Fa """ if not items: return "\n" + matrix, info = compute_item_matrix( items, row_first=row_first, separator_size=len(separator), displaywidth=displaywidth, ) + if spread: separator = separator.ljust(int(info["optimal_separator_width"])) fmatrix = [filter(None, x) for x in matrix] sjoin = lambda x: separator.join( [y.ljust(w, " ") for y, w in zip(x, info["column_widths"])] ) + return "\n".join(map(sjoin, fmatrix)) + "\n" @@ -285,6 +289,7 @@ def get_text_list(list_, last_sep=" and ", sep=", ", wrap_item_with=""): list_ = ["%s%s%s" % (wrap_item_with, item, wrap_item_with) for item in list_] if len(list_) == 1: return list_[0] + return "%s%s%s" % (sep.join(i for i in list_[:-1]), last_sep, list_[-1]) @@ -304,8 +309,8 @@ def import_item(name): mod : module object The module that was imported. """ - parts = name.rsplit(".", 1) + if len(parts) == 2: # called with 'foo.bar....' package, obj = parts From adf95908558702a56215ef85c23c4d6020cd202b Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Sun, 1 Oct 2023 18:21:48 +0200 Subject: [PATCH 3/7] vendor correctly --- qtconsole/console_widget.py | 22 ----- qtconsole/util.py | 176 ++++++++++++------------------------ 2 files changed, 57 insertions(+), 141 deletions(-) diff --git a/qtconsole/console_widget.py b/qtconsole/console_widget.py index a4cdff6a..62d20377 100644 --- a/qtconsole/console_widget.py +++ b/qtconsole/console_widget.py @@ -1680,28 +1680,6 @@ def _flush_pending_stream(self): int(max(100, (time.time() - t) * 1000)) ) - def _format_as_columns(self, items, separator=' '): - """ Transform a list of strings into a single string with columns. - - Parameters - ---------- - items : sequence of strings - The strings to process. - - separator : str, optional [default is two spaces] - The string that separates columns. - - Returns - ------- - The formatted string. - """ - # Calculate the number of characters available. - width = self._control.document().textWidth() - char_width = self._get_font_width() - displaywidth = max(10, (width / char_width) - 1) - - return columnize(items, separator, displaywidth) - def _get_cursor(self): """ Get a cursor at the current insert position. """ diff --git a/qtconsole/util.py b/qtconsole/util.py index 26133fdf..6669112f 100644 --- a/qtconsole/util.py +++ b/qtconsole/util.py @@ -111,37 +111,29 @@ def get_font(family, fallback=None): # ----------------------------------------------------------------------------- # Vendored from ipython_genutils # ----------------------------------------------------------------------------- -def _col_chunks(l, max_rows, row_first=False): - """Yield successive max_rows-sized column chunks from l.""" - if row_first: - ncols = (len(l) // max_rows) + (len(l) % max_rows > 0) - for i in range(ncols): - yield [l[j] for j in range(i, len(l), ncols)] - else: - for i in range(0, len(l), max_rows): - yield l[i : (i + max_rows)] - - -def _find_optimal(rlist, row_first=False, separator_size=2, displaywidth=80): - """Calculate optimal info to columnize a list of strings.""" - for max_rows in range(1, len(rlist) + 1): - col_widths = list(map(max, _col_chunks(rlist, max_rows, row_first))) - sumlength = sum(col_widths) - ncols = len(col_widths) +def _chunks(l, n): + """Yield successive n-sized chunks from l.""" + for i in range(0, len(l), n): + yield l[i : i + n] + + +def _find_optimal(rlist, *, separator_size, displaywidth): + """Calculate optimal info to columnize a list of strings""" + for nrow in range(1, len(rlist) + 1): + chk = list(map(max, _chunks(rlist, nrow))) + sumlength = sum(chk) + ncols = len(chk) if sumlength + separator_size * (ncols - 1) <= displaywidth: break return { - "num_columns": ncols, - "optimal_separator_width": (displaywidth - sumlength) // (ncols - 1) - if (ncols - 1) - else 0, - "max_rows": max_rows, - "column_widths": col_widths, + "columns_numbers": ncols, + "rows_numbers": nrow, + "columns_width": chk, } -def _get_or_default(mylist, i, default=None): +def _get_or_default(mylist, i, *, default): """return list item number, or default if don't exist""" if i >= len(mylist): return default @@ -149,16 +141,14 @@ def _get_or_default(mylist, i, default=None): return mylist[i] -def compute_item_matrix(items, row_first=False, empty=None, *args, **kwargs): +def compute_item_matrix(items, empty=None, *, separator_size=2, displaywith=80): """Returns a nested list, and info to columnize items Parameters ---------- + items - list of strings to columize - row_first : (default False) - Whether to compute columns for a row-first matrix instead of - column-first (default). + list of strings to columnize empty : (default None) Default value to fill list if needed separator_size : int (default=2) @@ -168,131 +158,79 @@ def compute_item_matrix(items, row_first=False, empty=None, *args, **kwargs): Returns ------- + strings_matrix - Nested list of strings, the outer most list contains as many list as - rows, the innermost lists have each as many element as columns. If the + + nested list of strings, the outer most list contains as many list as + rows, the innermost lists have each as many element as column. If the total number of elements in `items` does not equal the product of rows*columns, the last element of some lists are filled with `None`. + dict_info Some info to make columnize easier: - num_columns + columns_numbers number of columns - max_rows - maximum number of rows (final number may be less) - column_widths - list of with of each columns - optimal_separator_width - best separator width between columns + rows_numbers + number of rows + columns_width + list of width of each columns Examples -------- :: In [1]: l = ['aaa','b','cc','d','eeeee','f','g','h','i','j','k','l'] - In [2]: list, info = compute_item_matrix(l, displaywidth=12) - In [3]: list - Out[3]: [['aaa', 'f', 'k'], ['b', 'g', 'l'], ['cc', 'h', None], ['d', 'i', None], ['eeeee', 'j', None]] - In [4]: ideal = {'num_columns': 3, 'column_widths': [5, 1, 1], 'optimal_separator_width': 2, 'max_rows': 5} - In [5]: all((info[k] == ideal[k] for k in ideal.keys())) - Out[5]: True + ...: compute_item_matrix(l,displaywidth=12) + Out[1]: + ([['aaa', 'f', 'k'], + ['b', 'g', 'l'], + ['cc', 'h', None], + ['d', 'i', None], + ['eeeee', 'j', None]], + {'columns_numbers': 3, + 'columns_width': [5, 1, 1], + 'rows_numbers': 5}) """ - info = _find_optimal(list(map(len, items)), row_first, *args, **kwargs) - nrow, ncol = info["max_rows"], info["num_columns"] - if row_first: - return ( - [ - [ - _get_or_default(items, r * ncol + c, default=empty) - for c in range(ncol) - ] - for r in range(nrow) - ], - info, - ) - else: - return ( - [ - [ - _get_or_default(items, c * nrow + r, default=empty) - for c in range(ncol) - ] - for r in range(nrow) - ], - info, - ) - - -def columnize(items, row_first=False, separator=" ", displaywidth=80, spread=False): + info = _find_optimal( + [len(it) for it in items], separator_size=separator_size, displaywidth=displaywidth + ) + nrow, ncol = info["rows_numbers"], info["columns_numbers"] + return ( + [ + [_get_or_default(items, c * nrow + i, default=empty) for c in range(ncol)] + for i in range(nrow) + ], + info, + ) + + +def columnize(items): """Transform a list of strings into a single string with columns. Parameters ---------- items : sequence of strings The strings to process. - row_first : (default False) - Whether to compute columns for a row-first matrix instead of - column-first (default). - separator : str, optional [default is two spaces] - The string that separates columns. - displaywidth : int, optional [default is 80] - Width of the display in number of characters. Returns ------- The formatted string. """ + separator = " " + displaywidth = 80 if not items: return "\n" - matrix, info = compute_item_matrix( - items, - row_first=row_first, - separator_size=len(separator), - displaywidth=displaywidth, + items, separator_size=len(separator), displaywidth=displaywidth ) - - if spread: - separator = separator.ljust(int(info["optimal_separator_width"])) fmatrix = [filter(None, x) for x in matrix] sjoin = lambda x: separator.join( - [y.ljust(w, " ") for y, w in zip(x, info["column_widths"])] + [y.ljust(w, " ") for y, w in zip(x, info["columns_width"])] ) - return "\n".join(map(sjoin, fmatrix)) + "\n" -def get_text_list(list_, last_sep=" and ", sep=", ", wrap_item_with=""): - """ - Return a string with a natural enumeration of items - - >>> get_text_list(['a', 'b', 'c', 'd']) - 'a, b, c and d' - >>> get_text_list(['a', 'b', 'c'], ' or ') - 'a, b or c' - >>> get_text_list(['a', 'b', 'c'], ', ') - 'a, b, c' - >>> get_text_list(['a', 'b'], ' or ') - 'a or b' - >>> get_text_list(['a']) - 'a' - >>> get_text_list([]) - '' - >>> get_text_list(['a', 'b'], wrap_item_with="`") - '`a` and `b`' - >>> get_text_list(['a', 'b', 'c', 'd'], " = ", sep=" + ") - 'a + b + c = d' - """ - if len(list_) == 0: - return "" - if wrap_item_with: - list_ = ["%s%s%s" % (wrap_item_with, item, wrap_item_with) for item in list_] - if len(list_) == 1: - return list_[0] - - return "%s%s%s" % (sep.join(i for i in list_[:-1]), last_sep, list_[-1]) - - def import_item(name): """Import and return ``bar`` given the string ``foo.bar``. From 9f7703c3c7ad728fa27e3c98f5365c0bb9373f72 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Sun, 1 Oct 2023 19:00:37 +0200 Subject: [PATCH 4/7] vendor ensure_dir_exists --- qtconsole/rich_jupyter_widget.py | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/qtconsole/rich_jupyter_widget.py b/qtconsole/rich_jupyter_widget.py index 885033d8..f6ad52f9 100644 --- a/qtconsole/rich_jupyter_widget.py +++ b/qtconsole/rich_jupyter_widget.py @@ -8,7 +8,6 @@ from qtpy import QtCore, QtGui, QtWidgets -from ipython_genutils.path import ensure_dir_exists from traitlets import Bool from pygments.util import ClassNotFound @@ -22,6 +21,23 @@ latex_to_png = None +def _ensure_dir_exists(path, mode=0o755): + """ensure that a directory exists + + If it doesn't exist, try to create it and protect against a race condition + if another process is doing the same. + + The default permissions are 755, which differ from os.makedirs default of 777. + """ + if not os.path.exists(path): + try: + os.makedirs(path, mode=mode) + except OSError as e: + if e.errno != errno.EEXIST: + raise + elif not os.path.isdir(path): + raise IOError("%r exists but is not a directory" % path) + class LatexError(Exception): """Exception for Latex errors""" @@ -310,7 +326,7 @@ def _get_image_tag(self, match, path = None, format = "png"): return "Couldn't find image %s" % match.group("name") if path is not None: - ensure_dir_exists(path) + _ensure_dir_exists(path) relpath = os.path.basename(path) if image.save("%s/qt_img%s.%s" % (path, match.group("name"), format), "PNG"): From e7e622edd0e9c68ef22356e343d1a36e94aca87b Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Sun, 1 Oct 2023 19:03:38 +0200 Subject: [PATCH 5/7] typo --- qtconsole/rich_jupyter_widget.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qtconsole/rich_jupyter_widget.py b/qtconsole/rich_jupyter_widget.py index f6ad52f9..879b3cfa 100644 --- a/qtconsole/rich_jupyter_widget.py +++ b/qtconsole/rich_jupyter_widget.py @@ -24,7 +24,7 @@ def _ensure_dir_exists(path, mode=0o755): """ensure that a directory exists - If it doesn't exist, try to create it and protect against a race condition + If it doesn't exists, try to create it and protect against a race condition if another process is doing the same. The default permissions are 755, which differ from os.makedirs default of 777. From 9c70374a7ec10b88e724096c6d01b0917acd8e7b Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Sun, 1 Oct 2023 10:04:38 -0700 Subject: [PATCH 6/7] Apply suggestions from code review --- qtconsole/util.py | 1 - 1 file changed, 1 deletion(-) diff --git a/qtconsole/util.py b/qtconsole/util.py index 6669112f..c3827a4a 100644 --- a/qtconsole/util.py +++ b/qtconsole/util.py @@ -146,7 +146,6 @@ def compute_item_matrix(items, empty=None, *, separator_size=2, displaywith=80): Parameters ---------- - items list of strings to columnize empty : (default None) From 7b8754e8c957344bfd7e61a0627f98b45060cf06 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Thu, 19 Oct 2023 12:28:08 +0200 Subject: [PATCH 7/7] remove dependency on ipython_genutils --- requirements/environment.yml | 1 - setup.py | 1 - 2 files changed, 2 deletions(-) diff --git a/requirements/environment.yml b/requirements/environment.yml index 17a3b8aa..a3d7a5dc 100644 --- a/requirements/environment.yml +++ b/requirements/environment.yml @@ -5,7 +5,6 @@ dependencies: - pyqt - qtpy >=2.0.1 - traitlets -- ipython_genutils - jupyter_core - jupyter_client - pygments diff --git a/setup.py b/setup.py index aa6a1a8e..59f5f0db 100644 --- a/setup.py +++ b/setup.py @@ -67,7 +67,6 @@ python_requires = '>= 3.7', install_requires = [ 'traitlets!=5.2.1,!=5.2.2', - 'ipython_genutils', 'jupyter_core', 'jupyter_client>=4.1', 'pygments',