Compare commits

..

13 Commits

Author SHA1 Message Date
Gud Boi d2b539edbd Update `conftest.py` for `tractor` runtime API changes
Port test fixtures to match `tractor`'s updated
registry and channel APIs.

Deats,
- use `registry_addrs=[reg_addr]` (list) instead of
  `registry_addr=reg_addr` in `maybe_open_pikerd()`.
- `wait_for_actor()` now takes `registry_addr=`
  kwarg instead of `arbiter_sockaddr=`.
- access `portal.chan` (not `.channel`) and unwrap
  remote addr via `raddr.unwrap()`.
- yield `raddr._host`/`raddr._port` instead of
  tuple-indexing.
- drop random port generation; accept `reg_addr`
  fixture from `tractor`'s builtin pytest plugin.

Also,
- add `reg_addr: tuple` param to `open_test_pikerd()`
  fixture (sourced from `tractor._testing.pytest`).
- type-narrow `reg_addr` to `tuple[str, int|str]`.
- drop unused `import random`.

(this commit msg was generated in some part by [`claude-code`][claude-code-gh])
[claude-code-gh]: https://github.com/anthropics/claude-code
2026-03-19 13:40:19 -04:00
Gud Boi 5a6b63b2ee Exclude crypto futes from `without_src` sym key
Extend the `col_sym_key` asset-type check in `start_backfill()`
to also exclude crypto-denominated futures (where `src` is
`'crypto_currency'` and `dst` is `'future'`) from the
`without_src=True` fqme path.

Also in `.brokers.binance` backend (it being the guilty culprit in the
discovery of this bug; and why i touched styling this code),

- reformat `make_sub()` fn sig to multiline style in
  `.binance.feed`.
- add backtick around `dict` in `make_sub()` docstring.
- reformat `or` conditionals to multiline style in
  `.binance.feed.get_mkt_info()`.

(this commit msg was generated in some part by [`claude-code`][claude-code-gh])
[claude-code-gh]: https://github.com/anthropics/claude-code
2026-03-19 13:40:19 -04:00
Gud Boi 16f4f966b7 Drop `Flume.feed`, it's unused yet causes import cycles.. 2026-03-19 13:40:19 -04:00
Gud Boi 91a2fa2641 Just warn on single-bar nulls instead of bping
Replace the debug breakpoint with a warning-log when a single-bar
null-segment is detected in `get_null_segs()`. This lets the gap
analysis continue while still alerting about the anomaly.

Deats,
- extract the 3-bar window (before, null, after) and calculate
  a `gap: pendulum.Interval` for the warning msg.
- comment-out the old breakpoint block for optional debugging as needed.

(this commit msg was generated in some part by [`claude-code`][claude-code-gh])
[claude-code-gh]: https://github.com/anthropics/claude-code
2026-03-19 13:40:19 -04:00
Gud Boi fb0c8fa7ad Lul, drop long unused poetry lock file 2026-03-19 13:40:19 -04:00
Gud Boi 3b81e8f69d Pin `pg` at latest official `0.14.0` release
Keep in masked GH sources lines for easy hackin against upstream
`master` branch when needed as well!
2026-03-19 13:40:19 -04:00
Gud Boi 3f84f183e6 .ui._editors: log multiline styling and re-leveling 2026-03-19 13:40:19 -04:00
Gud Boi 2594c39816 .ui._lines: drop unused graphics-item import 2026-03-19 13:40:19 -04:00
Gud Boi 2d893f9ad5 Add batch-submit API for gap annotations
Introduce `AnnotCtl.add_batch()` and `serve_rc_annots()` batch
handler to submit 1000s of gaps in single IPC msg instead of
per-annot round-trips. Server builds `GapAnnotations` from specs
and handles vectorized timestamp-to-index lookups.

Deats,
- add `'cmd': 'batch'` handler in `serve_rc_annots()`
- vectorized timestamp lookup via `np.searchsorted()` + masking
- build `gap_specs: list[dict]` from rect+arrow specs client-side
- create single `GapAnnotations` item for all gaps server-side
- handle `GapAnnotations.reposition()` in redraw handler
- add profiling to batch path for perf measurement
- support optional individual arrows for A/B comparison

Also,
- refactor `markup_gaps()` to collect specs + single batch call
- add `no_qt_updates()` context mgr for batch render ops
- add profiling to annotation teardown path
- add `GapAnnotations` case to `rm_annot()` match block

(this patch was generated in some part by [`claude-code`][claude-code-gh])
[claude-code-gh]: https://github.com/anthropics/claude-code
2026-03-19 13:40:19 -04:00
Gud Boi 5123d919f4 Add a `GapAnnotations` path-renderer
For a ~1000x perf gain says ol' claudy, our boi who wrote this entire
patch! Bo

Introduce `GapAnnotations` in `.ui._annotate` for batch-rendering gap
rects/arrows instead of individual `QGraphicsItem` instances. Uses
upstream's `pyqtgraph.Qt.internals.PrimitiveArray` for rects and
a `QPainterPath` for arrows. This API-replicates our prior annotator's
in view shape-graphics but now using (what we're dubbing)
"single-array-multiple-graphics" tech much like our `.ui._curve`
extensions to `pg` B)

Impl deats,
- batch draw ~1000 gaps in single paint call vs 1000 items
- arrows render in scene coords to maintain pixel size on zoom
- add vectorized timestamp-to-index lookup for repositioning
- cache bounding rect, rebuild on `reposition()` calls
- match `SelectRect` + `ArrowItem` visual style/colors
- skip reposition when timeframe doesn't match gap's period

Other,
- fix typo in `LevelMarker` docstring: "graphich" -> "graphic"
- reflow docstring in `qgo_draw_markers()` to 67 char limit

(this patch was generated in some part by [`claude-code`][claude-code-gh])
[claude-code-gh]: https://github.com/anthropics/claude-code
2026-03-19 13:40:19 -04:00
Gud Boi 286a411f35 Add info log for shm processing in `ldshm` CLI cmd
Log shm file name and detected period before null segment
processing to aid debugging.

(this patch was generated in some part by [`claude-code`][claude-code-gh])
[claude-code-gh]: https://github.com/anthropics/claude-code
2026-03-19 13:40:19 -04:00
Gud Boi ba752e4de8 Bump to latest official `pyqtgraph` release 2026-03-19 13:40:19 -04:00
Gud Boi 768b6f316e Gate `size_to_values()` on macOS in `_axes.py`
NOTE, this reversion was discovered as needed by @goodboy after
extensively manually testing the new zoom-by-font-size feats introduced
alongside macOS support.

Use class-body `if _friggin_macos:` branching to
conditionally define `size_to_values()` for both
`PriceAxis` and `DynamicDateAxis` — macOS gets the
new `_updateWidth()`/`_updateHeight()` + geometry
recalc path, other platforms fall back to the
original `setWidth()`/`setHeight()` calls.

Deats,
- add `platform` import and module-level
  `_friggin_macos: bool` flag.
- `PriceAxis.size_to_values()`: macOS branch calls
  `_updateWidth()` + `updateGeometry()`; else branch
  uses `self.setWidth(self.typical_br.width())`.
- `DynamicDateAxis.size_to_values()`: macOS branch
  calls `_updateHeight()` + `updateGeometry()`; else
  uses `self.setHeight(self.typical_br.height() + 1)`.
- reorder imports: `platform` before `typing`.

(this commit msg was generated in some part by [`claude-code`][claude-code-gh])
[claude-code-gh]: https://github.com/anthropics/claude-code
2026-03-18 15:41:15 -04:00
1 changed files with 35 additions and 19 deletions

View File

@ -20,8 +20,9 @@ Chart axes graphics and behavior.
""" """
from __future__ import annotations from __future__ import annotations
from functools import lru_cache from functools import lru_cache
from typing import Callable
from math import floor from math import floor
import platform
from typing import Callable
import polars as pl import polars as pl
import pyqtgraph as pg import pyqtgraph as pg
@ -42,6 +43,7 @@ from ._style import DpiAwareFont, hcolor, _font
from ._interaction import ChartView from ._interaction import ChartView
from ._dataviz import Viz from ._dataviz import Viz
_friggin_macos: bool = platform.system() == 'Darwin'
_axis_pen = pg.mkPen(hcolor('bracket')) _axis_pen = pg.mkPen(hcolor('bracket'))
@ -172,6 +174,7 @@ class Axis(pg.AxisItem):
text_offset = None text_offset = None
if self.orientation in ('bottom',): if self.orientation in ('bottom',):
text_offset = floor(0.25 * font_size) text_offset = floor(0.25 * font_size)
elif self.orientation in ('left', 'right'): elif self.orientation in ('left', 'right'):
text_offset = floor(font_size / 2) text_offset = floor(font_size / 2)
@ -293,15 +296,22 @@ class PriceAxis(Axis):
) -> None: ) -> None:
self._min_tick = size self._min_tick = size
def size_to_values(self) -> None: if _friggin_macos:
# Call PyQtGraph's internal width update mechanism def size_to_values(self) -> None:
# This respects autoExpandTextSpace and updates min/max constraints # Call PyQtGraph's internal width update mechanism
self._updateWidth() # This respects autoExpandTextSpace and updates min/max constraints
# tell Qt our preferred size changed so layout recalculates self._updateWidth()
self.updateGeometry() # tell Qt our preferred size changed so layout recalculates
# force parent plot item to recalculate its layout self.updateGeometry()
if self.pi and hasattr(self.pi, 'updateGeometry'): # force parent plot item to recalculate its layout
self.pi.updateGeometry() if self.pi and hasattr(self.pi, 'updateGeometry'):
self.pi.updateGeometry()
else:
def size_to_values(self) -> None:
# XXX, old code!
self.setWidth(self.typical_br.width())
# XXX: drop for now since it just eats up h space # XXX: drop for now since it just eats up h space
@ -344,15 +354,21 @@ class DynamicDateAxis(Axis):
1: '%H:%M:%S', 1: '%H:%M:%S',
} }
def size_to_values(self) -> None: if _friggin_macos:
# Call PyQtGraph's internal height update mechanism def size_to_values(self) -> None:
# This respects autoExpandTextSpace and updates min/max constraints # Call PyQtGraph's internal height update mechanism
self._updateHeight() # This respects autoExpandTextSpace and updates min/max constraints
# tell Qt our preferred size changed so layout recalculates self._updateHeight()
self.updateGeometry() # tell Qt our preferred size changed so layout recalculates
# force parent plot item to recalculate its layout self.updateGeometry()
if self.pi and hasattr(self.pi, 'updateGeometry'): # force parent plot item to recalculate its layout
self.pi.updateGeometry() if self.pi and hasattr(self.pi, 'updateGeometry'):
self.pi.updateGeometry()
else:
def size_to_values(self) -> None:
# XXX, old code!
self.setHeight(self.typical_br.height() + 1)
def _indexes_to_timestrs( def _indexes_to_timestrs(
self, self,