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 all commits
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
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
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 +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
Carreau marked this conversation as resolved.
Show resolved Hide resolved


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)

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

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

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

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
Loading