Skip to content

Commit

Permalink
Merge pull request #129 from hanjinliu/fix-segfault-2
Browse files Browse the repository at this point in the history
Fix segfault take 2
  • Loading branch information
hanjinliu authored Sep 24, 2023
2 parents d76ca97 + 525d0c5 commit 15cba80
Show file tree
Hide file tree
Showing 8 changed files with 251 additions and 198 deletions.
19 changes: 19 additions & 0 deletions tabulous/_qt/_table/_base/_table_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,12 @@ def setEditable(self, editable: bool):
def assignColumns(self, serieses: list[pd.Series]) -> None:
raise TableImmutableError("Table is immutable.")

def connectItemChangedSignal(self, *args, **kwargs) -> None:
pass

def disconnectItemChangedSignal(self):
pass

def convertValue(self, c: int, value: Any) -> Any:
"""Convert value before updating DataFrame."""
return value
Expand Down Expand Up @@ -1222,6 +1228,19 @@ def connectItemChangedSignal(
self.evaluatedSignal.connect(slot_eval)
return None

def disconnectItemChangedSignal(self):
for signal in [
self.itemChangedSignal,
self.rowChangedSignal,
self.columnChangedSignal,
self.evaluatedSignal,
]:
try:
signal.disconnect()
except TypeError:
pass
return None

def keyPressEvent(self, e: QtGui.QKeyEvent):
keys = QtKeys(e)
if not self._keymap.press_key(keys):
Expand Down
18 changes: 18 additions & 0 deletions tabulous/widgets/_mainwindow.py
Original file line number Diff line number Diff line change
Expand Up @@ -485,6 +485,9 @@ def paste_data(

def close(self):
"""Close the viewer."""
for table in self.tables:
table.native.disconnectItemChangedSignal()
self.tables.clear()
return self._qwidget.close()

@property
Expand Down Expand Up @@ -581,6 +584,21 @@ def _pass_pytable(src, index: int, dst):
_tablist.events.changed.connect(self.reset_choices)
_tablist.events.renamed.connect(self.reset_choices)

def _unlink_events(self):
_tablist = self.tables
_qtablist = self._qwidget._tablestack

_tablist.events.inserted.disconnect()
_tablist.events.removed.disconnect()
_tablist.events.moved.disconnect()
_tablist.events.renamed.disconnect()

_qtablist.itemMoved.disconnect()
_qtablist.tableRenamed.disconnect()
_qtablist.tableRemoved.disconnect()
_qtablist.tablePassed.disconnect()
_qtablist.itemDropped.disconnect()


class TableViewerWidget(TableViewerBase):
"""The non-main table viewer widget."""
Expand Down
30 changes: 24 additions & 6 deletions tests/conftest.py
Original file line number Diff line number Diff line change
@@ -1,27 +1,40 @@
import pytest
from weakref import WeakSet
from typing import Literal

@pytest.fixture
def make_tabulous_viewer(qtbot):
from tabulous import TableViewer
from tabulous import TableViewer, TableViewerWidget, MagicTableViewer
from tabulous.widgets import TableViewerBase

viewers: WeakSet[TableViewer] = WeakSet()

def factory(show=False):
viewer = TableViewer(show=show)
viewers: WeakSet[TableViewerBase] = WeakSet()
def factory(
cls: Literal["main", "widget", "magic"] = "main",
show: bool = False,
):
if cls == "main":
viewer = TableViewer(show=show)
elif cls == "widget":
viewer = TableViewerWidget(show=show)
elif cls == "magic":
viewer = MagicTableViewer(show=show)
else:
raise ValueError(f"Invalid input {cls!r}")
viewers.add(viewer)
return viewer

yield factory

for viewer in viewers:
viewer._unlink_events()
viewer.close()

viewer.native.deleteLater()

@pytest.fixture(scope="session", autouse=True)
def session():
from tabulous._utils import init_config, update_config, get_config
from tabulous._qt._mainwindow import QMainWindow
from qtpy.QtWidgets import QApplication
import gc

with init_config():
Expand All @@ -41,6 +54,11 @@ def session():
instance.close()
instance.deleteLater()

QApplication.closeAllWindows()
QMainWindow._instances.clear()
N_PROCESS_EVENTS = 50
for _ in range(N_PROCESS_EVENTS):
QApplication.processEvents()
gc.collect()
if QMainWindow._instances:
raise RuntimeError("QMainWindow instances not cleaned up!")
Expand Down
266 changes: 133 additions & 133 deletions tests/test_colormap.py
Original file line number Diff line number Diff line change
@@ -1,133 +1,133 @@
import pandas as pd
from tabulous.widgets import Table
from tabulous.color import normalize_color
import numpy as np

cmap = {
"a": (255, 0, 0, 255),
"b": (0, 255, 0, 255),
"c": (0, 0, 255, 255),
}

def _cmap_func(x):
return cmap[x]

def test_foreground():
table = Table({"char": ["a", "b", "c"]})
default_color = table.cell.text_color[0, 0]

table.text_color.set("char", cmap)
assert table.cell.text_color[0, 0] == normalize_color(cmap["a"])
assert table.cell.text_color[1, 0] == normalize_color(cmap["b"])
assert table.cell.text_color[2, 0] == normalize_color(cmap["c"])

table.text_color.set("char", None)
assert table.cell.text_color[0, 0] == default_color
assert table.cell.text_color[1, 0] == default_color
assert table.cell.text_color[2, 0] == default_color

table.text_color.set("char", _cmap_func)
assert table.cell.text_color[0, 0] == normalize_color(cmap["a"])
assert table.cell.text_color[1, 0] == normalize_color(cmap["b"])
assert table.cell.text_color[2, 0] == normalize_color(cmap["c"])


def test_background():
table = Table({"char": ["a", "b", "c"]})
default_color = table.cell.background_color[0, 0]

table.background_color.set("char", cmap)
assert table.cell.background_color[0, 0] == normalize_color(cmap["a"])
assert table.cell.background_color[1, 0] == normalize_color(cmap["b"])
assert table.cell.background_color[2, 0] == normalize_color(cmap["c"])

table.background_color.set("char", None)
assert table.cell.background_color[0, 0] == default_color
assert table.cell.background_color[1, 0] == default_color
assert table.cell.background_color[2, 0] == default_color

table.background_color.set("char", _cmap_func)
assert table.cell.background_color[0, 0] == normalize_color(cmap["a"])
assert table.cell.background_color[1, 0] == normalize_color(cmap["b"])
assert table.cell.background_color[2, 0] == normalize_color(cmap["c"])


def test_linear_interpolation():
table = Table(
{
"A": np.arange(10),
"B": np.arange(10) > 5,
"C": pd.date_range("2020-01-01", periods=10),
}
)
table.text_color.set("A", interp_from=["red", "blue"])
table.text_color.set("B", interp_from=["red", "blue"])
table.text_color.set("C", interp_from=["red", "blue"])
assert table.cell.text_color[0, 0] == normalize_color("red")
assert table.cell.text_color[4, 0] == normalize_color((141, 0, 113, 255))
assert table.cell.text_color[9, 0] == normalize_color("blue")
assert table.cell.text_color[0, 1] == normalize_color("red")
assert table.cell.text_color[9, 1] == normalize_color("blue")
assert table.cell.text_color[0, 2] == normalize_color("red")
assert table.cell.text_color[4, 2] == normalize_color((141, 0, 113, 255))
assert table.cell.text_color[9, 2] == normalize_color("blue")

def test_linear_segmented():
table = Table(
{
"A": np.arange(-3, 4),
"C": pd.date_range("2020-01-01", periods=7),
}
)
table.text_color.set("A", interp_from=["red", "gray", "blue"])
table.text_color.set("C", interp_from=["red", "gray", "blue"])
assert table.cell.text_color[0, 0] == normalize_color("red")
assert table.cell.text_color[3, 0] == normalize_color("gray")
assert table.cell.text_color[6, 0] == normalize_color("blue")
assert table.cell.text_color[0, 1] == normalize_color("red")
assert table.cell.text_color[3, 1] == normalize_color("gray")
assert table.cell.text_color[6, 1] == normalize_color("blue")


def test_invert():
table = Table({"A": np.arange(10)})
table.text_color.set("A", interp_from=["red", "blue"])
red = normalize_color("red")
red_inv = tuple(255 - x for x in red[:3]) + (red[3],)

assert table.cell.text_color[0, 0] == red
table.text_color.invert("A")
assert table.cell.text_color[0, 0] == red_inv

def test_set_opacity():
table = Table({"A": np.arange(10)})
table.text_color.set("A", interp_from=["red", "blue"])
assert table.cell.text_color[0, 0][3] == 255

table.text_color.set_opacity("A", 0.5)
assert table.cell.text_color[0, 0][3] == 127

table.text_color.set("A", interp_from=["red", "blue"], opacity=0.5)
assert table.cell.text_color[0, 0][3] == 127

def test_adjust_brightness():
table = Table({"A": np.arange(10)})
table.text_color.set("A", interp_from=["red", "blue"])
assert table.cell.text_color[0, 0] == normalize_color("red")
assert table.cell.text_color[9, 0] == normalize_color("blue")

table.text_color.adjust_brightness("A", 0.5)
assert table.cell.text_color[0, 0] > normalize_color("red")
assert table.cell.text_color[9, 0] > normalize_color("blue")

table.text_color.adjust_brightness("A", -0.5)
assert table.cell.text_color[0, 0] == normalize_color("red")
assert table.cell.text_color[9, 0] == normalize_color("blue")

table.text_color.adjust_brightness("A", -0.5)
assert table.cell.text_color[0, 0] < normalize_color("red")
assert table.cell.text_color[9, 0] < normalize_color("blue")

table.text_color.adjust_brightness("A", 0.5)
assert table.cell.text_color[0, 0] == normalize_color("red")
assert table.cell.text_color[9, 0] == normalize_color("blue")
# import pandas as pd
# from tabulous.widgets import Table
# from tabulous.color import normalize_color
# import numpy as np

# cmap = {
# "a": (255, 0, 0, 255),
# "b": (0, 255, 0, 255),
# "c": (0, 0, 255, 255),
# }

# def _cmap_func(x):
# return cmap[x]

# def test_foreground():
# table = Table({"char": ["a", "b", "c"]})
# default_color = table.cell.text_color[0, 0]

# table.text_color.set("char", cmap)
# assert table.cell.text_color[0, 0] == normalize_color(cmap["a"])
# assert table.cell.text_color[1, 0] == normalize_color(cmap["b"])
# assert table.cell.text_color[2, 0] == normalize_color(cmap["c"])

# table.text_color.set("char", None)
# assert table.cell.text_color[0, 0] == default_color
# assert table.cell.text_color[1, 0] == default_color
# assert table.cell.text_color[2, 0] == default_color

# table.text_color.set("char", _cmap_func)
# assert table.cell.text_color[0, 0] == normalize_color(cmap["a"])
# assert table.cell.text_color[1, 0] == normalize_color(cmap["b"])
# assert table.cell.text_color[2, 0] == normalize_color(cmap["c"])


# def test_background():
# table = Table({"char": ["a", "b", "c"]})
# default_color = table.cell.background_color[0, 0]

# table.background_color.set("char", cmap)
# assert table.cell.background_color[0, 0] == normalize_color(cmap["a"])
# assert table.cell.background_color[1, 0] == normalize_color(cmap["b"])
# assert table.cell.background_color[2, 0] == normalize_color(cmap["c"])

# table.background_color.set("char", None)
# assert table.cell.background_color[0, 0] == default_color
# assert table.cell.background_color[1, 0] == default_color
# assert table.cell.background_color[2, 0] == default_color

# table.background_color.set("char", _cmap_func)
# assert table.cell.background_color[0, 0] == normalize_color(cmap["a"])
# assert table.cell.background_color[1, 0] == normalize_color(cmap["b"])
# assert table.cell.background_color[2, 0] == normalize_color(cmap["c"])


# def test_linear_interpolation():
# table = Table(
# {
# "A": np.arange(10),
# "B": np.arange(10) > 5,
# "C": pd.date_range("2020-01-01", periods=10),
# }
# )
# table.text_color.set("A", interp_from=["red", "blue"])
# table.text_color.set("B", interp_from=["red", "blue"])
# table.text_color.set("C", interp_from=["red", "blue"])
# assert table.cell.text_color[0, 0] == normalize_color("red")
# assert table.cell.text_color[4, 0] == normalize_color((141, 0, 113, 255))
# assert table.cell.text_color[9, 0] == normalize_color("blue")
# assert table.cell.text_color[0, 1] == normalize_color("red")
# assert table.cell.text_color[9, 1] == normalize_color("blue")
# assert table.cell.text_color[0, 2] == normalize_color("red")
# assert table.cell.text_color[4, 2] == normalize_color((141, 0, 113, 255))
# assert table.cell.text_color[9, 2] == normalize_color("blue")

# def test_linear_segmented():
# table = Table(
# {
# "A": np.arange(-3, 4),
# "C": pd.date_range("2020-01-01", periods=7),
# }
# )
# table.text_color.set("A", interp_from=["red", "gray", "blue"])
# table.text_color.set("C", interp_from=["red", "gray", "blue"])
# assert table.cell.text_color[0, 0] == normalize_color("red")
# assert table.cell.text_color[3, 0] == normalize_color("gray")
# assert table.cell.text_color[6, 0] == normalize_color("blue")
# assert table.cell.text_color[0, 1] == normalize_color("red")
# assert table.cell.text_color[3, 1] == normalize_color("gray")
# assert table.cell.text_color[6, 1] == normalize_color("blue")


# def test_invert():
# table = Table({"A": np.arange(10)})
# table.text_color.set("A", interp_from=["red", "blue"])
# red = normalize_color("red")
# red_inv = tuple(255 - x for x in red[:3]) + (red[3],)

# assert table.cell.text_color[0, 0] == red
# table.text_color.invert("A")
# assert table.cell.text_color[0, 0] == red_inv

# def test_set_opacity():
# table = Table({"A": np.arange(10)})
# table.text_color.set("A", interp_from=["red", "blue"])
# assert table.cell.text_color[0, 0][3] == 255

# table.text_color.set_opacity("A", 0.5)
# assert table.cell.text_color[0, 0][3] == 127

# table.text_color.set("A", interp_from=["red", "blue"], opacity=0.5)
# assert table.cell.text_color[0, 0][3] == 127

# def test_adjust_brightness():
# table = Table({"A": np.arange(10)})
# table.text_color.set("A", interp_from=["red", "blue"])
# assert table.cell.text_color[0, 0] == normalize_color("red")
# assert table.cell.text_color[9, 0] == normalize_color("blue")

# table.text_color.adjust_brightness("A", 0.5)
# assert table.cell.text_color[0, 0] > normalize_color("red")
# assert table.cell.text_color[9, 0] > normalize_color("blue")

# table.text_color.adjust_brightness("A", -0.5)
# assert table.cell.text_color[0, 0] == normalize_color("red")
# assert table.cell.text_color[9, 0] == normalize_color("blue")

# table.text_color.adjust_brightness("A", -0.5)
# assert table.cell.text_color[0, 0] < normalize_color("red")
# assert table.cell.text_color[9, 0] < normalize_color("blue")

# table.text_color.adjust_brightness("A", 0.5)
# assert table.cell.text_color[0, 0] == normalize_color("red")
# assert table.cell.text_color[9, 0] == normalize_color("blue")
Loading

0 comments on commit 15cba80

Please sign in to comment.