Skip to content

Commit

Permalink
Merge pull request #586 from Carreau/ipython-genutils
Browse files Browse the repository at this point in the history
Remove `ipython_genutils` as a dependency
  • Loading branch information
ccordoba12 authored Oct 19, 2023
2 parents ecb3aa8 + 7b8754e commit 9e7a97b
Show file tree
Hide file tree
Showing 9 changed files with 183 additions and 36 deletions.
4 changes: 2 additions & 2 deletions 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 qtconsole.util import MetaQObjectHasTraits, SuperQObject, import_item


class CommManager(MetaQObjectHasTraits(
Expand Down
8 changes: 4 additions & 4 deletions qtconsole/completion_html.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@
# 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
#--------------------------------------------------------------------------
Expand Down Expand Up @@ -311,9 +312,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
5 changes: 3 additions & 2 deletions qtconsole/completion_plain.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
# 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):
Expand Down Expand Up @@ -53,7 +54,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
24 changes: 1 addition & 23 deletions 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 Expand Up @@ -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.
"""
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
20 changes: 18 additions & 2 deletions qtconsole/rich_jupyter_widget.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -22,6 +21,23 @@
latex_to_png = None


def _ensure_dir_exists(path, mode=0o755):
"""ensure that a directory exists
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.
"""
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"""

Expand Down Expand Up @@ -310,7 +326,7 @@ def _get_image_tag(self, match, path = None, format = "png"):
return "<b>Couldn't find image %s</b>" % 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"):
Expand Down
154 changes: 154 additions & 0 deletions qtconsole/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,3 +106,157 @@ 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 _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 {
"columns_numbers": ncols,
"rows_numbers": nrow,
"columns_width": chk,
}


def _get_or_default(mylist, i, *, default):
"""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, empty=None, *, separator_size=2, displaywith=80):
"""Returns a nested list, and info to columnize items
Parameters
----------
items
list of strings to columnize
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 column.
displaywidth : int (default=80)
The width of the area onto which the columns should enter
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 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:
columns_numbers
number of 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']
...: 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(
[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.
Returns
-------
The formatted string.
"""
separator = " "
displaywidth = 80
if not items:
return "\n"
matrix, info = compute_item_matrix(
items, separator_size=len(separator), displaywidth=displaywidth
)
fmatrix = [filter(None, x) for x in matrix]
sjoin = lambda x: separator.join(
[y.ljust(w, " ") for y, w in zip(x, info["columns_width"])]
)
return "\n".join(map(sjoin, fmatrix)) + "\n"


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])
1 change: 0 additions & 1 deletion requirements/environment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ dependencies:
- pyqt
- qtpy >=2.0.1
- traitlets
- ipython_genutils
- jupyter_core
- jupyter_client
- pygments
Expand Down
1 change: 0 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down

0 comments on commit 9e7a97b

Please sign in to comment.