diff --git a/piker/data/_formatters.py b/piker/data/_formatters.py
index 4fbe3151..29d2ac9c 100644
--- a/piker/data/_formatters.py
+++ b/piker/data/_formatters.py
@@ -1,5 +1,5 @@
# piker: trading gear for hackers
-# Copyright (C) 2018-present Tyler Goodlet (in stewardship of piker0)
+# Copyright (C) Tyler Goodlet (in stewardship for pikers)
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
@@ -13,10 +13,10 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
-"""
+'''
Pre-(path)-graphics formatted x/y nd/1d rendering subsystem.
-"""
+'''
from __future__ import annotations
from typing import (
Optional,
@@ -39,7 +39,7 @@ if TYPE_CHECKING:
from ._dataviz import (
Viz,
)
- from .._profile import Profiler
+ from piker.toolz import Profiler
class IncrementalFormatter(msgspec.Struct):
diff --git a/piker/data/_timeseries.py b/piker/data/_timeseries.py
index c812e08a..2d73c263 100644
--- a/piker/data/_timeseries.py
+++ b/piker/data/_timeseries.py
@@ -32,7 +32,7 @@ import numpy as np
import polars as pl
from ._sharedmem import ShmArray
-from .._profile import (
+from ..toolz.profile import (
Profiler,
pg_profile_enabled,
ms_slower_then,
diff --git a/piker/data/flows.py b/piker/data/flows.py
index 652e1e71..86e5370f 100644
--- a/piker/data/flows.py
+++ b/piker/data/flows.py
@@ -37,10 +37,6 @@ from ._sharedmem import (
ShmArray,
_Token,
)
-# from .._profile import (
-# Profiler,
-# pg_profile_enabled,
-# )
if TYPE_CHECKING:
# from pyqtgraph import PlotItem
diff --git a/piker/fsp/_engine.py b/piker/fsp/_engine.py
index 9a6ebddb..b4cccdae 100644
--- a/piker/fsp/_engine.py
+++ b/piker/fsp/_engine.py
@@ -51,7 +51,7 @@ from ._api import (
_load_builtins,
_Token,
)
-from .._profile import Profiler
+from ..toolz import Profiler
log = get_logger(__name__)
diff --git a/piker/storage/__init__.py b/piker/storage/__init__.py
index 465d3e28..c813c48a 100644
--- a/piker/storage/__init__.py
+++ b/piker/storage/__init__.py
@@ -246,7 +246,7 @@ async def open_tsdb_client(
# * the original data feed arch blurb:
# - https://github.com/pikers/piker/issues/98
#
- from .._profile import Profiler
+ from ..toolz import Profiler
profiler = Profiler(
disabled=True, # not pg_profile_enabled(),
delayed=False,
diff --git a/piker/storage/marketstore/__init__.py b/piker/storage/marketstore/__init__.py
index 2f0a7970..7466c06a 100644
--- a/piker/storage/marketstore/__init__.py
+++ b/piker/storage/marketstore/__init__.py
@@ -59,7 +59,6 @@ from anyio_marketstore import ( # noqa
Params,
)
from piker.log import get_logger
-# from .._profile import Profiler
log = get_logger(__name__)
diff --git a/piker/storage/nativedb.py b/piker/storage/nativedb.py
index 274bf039..1f7da9f7 100644
--- a/piker/storage/nativedb.py
+++ b/piker/storage/nativedb.py
@@ -67,7 +67,6 @@ from piker import config
from piker.data import def_iohlcv_fields
from piker.data import ShmArray
from piker.log import get_logger
-# from .._profile import Profiler
log = get_logger('storage.nativedb')
diff --git a/piker/toolz/__init__.py b/piker/toolz/__init__.py
new file mode 100644
index 00000000..4b8a9338
--- /dev/null
+++ b/piker/toolz/__init__.py
@@ -0,0 +1,38 @@
+# piker: trading gear for hackers
+# Copyright (C) Tyler Goodlet (in stewardship for pikers)
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+
+'''
+Toolz for debug, profile and trace of the distributed runtime :surfer:
+
+'''
+from .debug import (
+ open_crash_handler,
+)
+from .profile import (
+ Profiler,
+ pg_profile_enabled,
+ ms_slower_then,
+ timeit,
+)
+
+
+__all__: list[str] = [
+ 'open_crash_handler',
+ 'pg_profile_enabled',
+ 'ms_slower_then',
+ 'Profiler',
+ 'timeit',
+]
diff --git a/piker/toolz/debug.py b/piker/toolz/debug.py
new file mode 100644
index 00000000..3b8a3e3e
--- /dev/null
+++ b/piker/toolz/debug.py
@@ -0,0 +1,40 @@
+# piker: trading gear for hackers
+# Copyright (C) Tyler Goodlet (in stewardship for pikers)
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+
+'''
+Debugger wrappers for `pdbp` as used by `tractor`.
+
+'''
+from contextlib import contextmanager as cm
+
+import pdbp
+
+
+# TODO: better naming and what additionals?
+# - optional runtime plugging?
+# - detection for sync vs. async code?
+# - specialized REPL entry when in distributed mode?
+@cm
+def open_crash_handler():
+ '''
+ Super basic crash handler using `pdbp` debugger.
+
+ '''
+ try:
+ yield
+ except BaseException:
+ pdbp.xpm()
+ raise
diff --git a/piker/_profile.py b/piker/toolz/profile.py
similarity index 100%
rename from piker/_profile.py
rename to piker/toolz/profile.py
diff --git a/piker/ui/_curve.py b/piker/ui/_curve.py
index 5442d347..c8e4c373 100644
--- a/piker/ui/_curve.py
+++ b/piker/ui/_curve.py
@@ -34,10 +34,13 @@ from PyQt5.QtGui import (
QPainter,
QPainterPath,
)
-from .._profile import pg_profile_enabled, ms_slower_then
from ._style import hcolor
from ..log import get_logger
-from .._profile import Profiler
+from ..toolz.profile import (
+ Profiler,
+ pg_profile_enabled,
+ ms_slower_then,
+)
log = get_logger(__name__)
diff --git a/piker/ui/_dataviz.py b/piker/ui/_dataviz.py
index 9da45f44..c011bff0 100644
--- a/piker/ui/_dataviz.py
+++ b/piker/ui/_dataviz.py
@@ -62,7 +62,7 @@ from ._curve import (
)
from ._render import Renderer
from ..log import get_logger
-from .._profile import (
+from ..toolz.profile import (
Profiler,
pg_profile_enabled,
ms_slower_then,
diff --git a/piker/ui/_display.py b/piker/ui/_display.py
index 610b38f3..27e70145 100644
--- a/piker/ui/_display.py
+++ b/piker/ui/_display.py
@@ -79,12 +79,12 @@ from .order_mode import (
open_order_mode,
OrderMode,
)
-from .._profile import (
+from ..toolz import (
pg_profile_enabled,
ms_slower_then,
+ Profiler,
)
from ..log import get_logger
-from .._profile import Profiler
if TYPE_CHECKING:
from ._interaction import ChartView
diff --git a/piker/ui/_fsp.py b/piker/ui/_fsp.py
index 5202ea97..a4deb034 100644
--- a/piker/ui/_fsp.py
+++ b/piker/ui/_fsp.py
@@ -66,7 +66,7 @@ from ..fsp._volume import (
flow_rates,
)
from ..log import get_logger
-from .._profile import Profiler
+from ..toolz import Profiler
log = get_logger(__name__)
diff --git a/piker/ui/_interaction.py b/piker/ui/_interaction.py
index 1219e94e..6cc6bee4 100644
--- a/piker/ui/_interaction.py
+++ b/piker/ui/_interaction.py
@@ -39,8 +39,11 @@ import numpy as np
import trio
from ..log import get_logger
-from .._profile import Profiler
-from .._profile import pg_profile_enabled, ms_slower_then
+from ..toolz import (
+ Profiler,
+ pg_profile_enabled,
+ ms_slower_then,
+)
from .view_mode import overlay_viewlists
# from ._style import _min_points_to_show
from ._editors import SelectRect
diff --git a/piker/ui/_ohlc.py b/piker/ui/_ohlc.py
index 33d7bbda..2bbec253 100644
--- a/piker/ui/_ohlc.py
+++ b/piker/ui/_ohlc.py
@@ -31,9 +31,12 @@ from PyQt5.QtCore import (
from PyQt5.QtGui import QPainterPath
from ._curve import FlowGraphic
-from .._profile import pg_profile_enabled, ms_slower_then
+from ..toolz import (
+ Profiler,
+ pg_profile_enabled,
+ ms_slower_then,
+)
from ..log import get_logger
-from .._profile import Profiler
log = get_logger(__name__)
diff --git a/piker/ui/_render.py b/piker/ui/_render.py
index 2a442e98..bd3d1757 100644
--- a/piker/ui/_render.py
+++ b/piker/ui/_render.py
@@ -39,7 +39,7 @@ from ..data._pathops import (
xy_downsample,
)
from ..log import get_logger
-from .._profile import (
+from ..toolz import (
Profiler,
)
diff --git a/piker/ui/view_mode.py b/piker/ui/view_mode.py
index 82dfbf62..191b62b9 100644
--- a/piker/ui/view_mode.py
+++ b/piker/ui/view_mode.py
@@ -33,7 +33,7 @@ import pyqtgraph as pg
from ..data.types import Struct
from ..data._timeseries import slice_from_time
from ..log import get_logger
-from .._profile import Profiler
+from ..toolz import Profiler
if TYPE_CHECKING:
from ._chart import ChartPlotWidget