Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove ipython_genutils as a dependency #586

Merged
merged 7 commits into from
Oct 19, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion qtconsole/comms.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Carreau marked this conversation as resolved.
Show resolved Hide resolved


class CommManager(MetaQObjectHasTraits(
Expand Down
7 changes: 3 additions & 4 deletions qtconsole/completion_html.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Carreau marked this conversation as resolved.
Show resolved Hide resolved

#--------------------------------------------------------------------------
# Return an HTML table with selected item in a special class
Expand Down Expand Up @@ -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'])
Expand Down
4 changes: 2 additions & 2 deletions qtconsole/completion_plain.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Carreau marked this conversation as resolved.
Show resolved Hide resolved


class CompletionPlain(QtWidgets.QWidget):
Expand Down Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion qtconsole/console_widget.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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):
Expand Down
2 changes: 1 addition & 1 deletion qtconsole/frontend_widget.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,14 @@
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
from .bracket_matcher import BracketMatcher
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):
Expand Down
212 changes: 212 additions & 0 deletions qtconsole/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"""
Carreau marked this conversation as resolved.
Show resolved Hide resolved
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
Carreau marked this conversation as resolved.
Show resolved Hide resolved
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
Carreau marked this conversation as resolved.
Show resolved Hide resolved
separator_size : int (default=2)
How much characters will be used as a separation between each columns.
Carreau marked this conversation as resolved.
Show resolved Hide resolved
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
Carreau marked this conversation as resolved.
Show resolved Hide resolved
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:
Carreau marked this conversation as resolved.
Show resolved Hide resolved

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):
ccordoba12 marked this conversation as resolved.
Show resolved Hide resolved
"""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(
Carreau marked this conversation as resolved.
Show resolved Hide resolved
items,
row_first=row_first,
separator_size=len(separator),
displaywidth=displaywidth,
)
if spread:
Carreau marked this conversation as resolved.
Show resolved Hide resolved
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"
Carreau marked this conversation as resolved.
Show resolved Hide resolved


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])
Carreau marked this conversation as resolved.
Show resolved Hide resolved
ccordoba12 marked this conversation as resolved.
Show resolved Hide resolved


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)
Carreau marked this conversation as resolved.
Show resolved Hide resolved
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])
Loading