Compare commits

..

12 Commits

Author SHA1 Message Date
Gud Boi b5a33e1217 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-06 22:13:06 -05:00
Gud Boi 796a831c6e Enable console log (from passed down `loglevel`) in `.tsp._history.manage_history()` 2026-03-06 09:26:34 -05:00
Gud Boi de81d1e905 Drop `Flume.feed`, it's unused yet causes import cycles.. 2026-03-06 09:26:34 -05:00
Gud Boi 170dd9794c 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-06 09:26:34 -05:00
Gud Boi 599c36aba6 Lul, drop long unused poetry lock file 2026-03-06 09:26:34 -05:00
Gud Boi f174f79a1a 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-06 09:26:34 -05:00
Gud Boi 9b284c2256 .ui._editors: log multiline styling and re-leveling 2026-03-06 09:26:34 -05:00
Gud Boi 59f2d46a97 .ui._lines: drop unused graphics-item import 2026-03-06 09:26:34 -05:00
Gud Boi c1b1e99693 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-06 09:26:34 -05:00
Gud Boi 24651d2326 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-06 09:26:34 -05:00
Gud Boi 2d00bb1024 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-06 09:26:34 -05:00
Gud Boi dd40ad603f Bump to latest official `pyqtgraph` release 2026-03-06 09:26:34 -05:00
3 changed files with 52 additions and 73 deletions

View File

@ -20,7 +20,6 @@ runnable script-programs.
'''
from __future__ import annotations
import asyncio
from datetime import ( # noqa
datetime,
date,
@ -141,8 +140,7 @@ async def data_reset_hack(
except (
OSError, # no VNC server avail..
PermissionError, # asyncvnc pw fail..
) as _vnc_err:
vnc_err = _vnc_err
):
try:
import i3ipc # noqa (since a deps dynamic check)
except ModuleNotFoundError:
@ -168,22 +166,14 @@ async def data_reset_hack(
# localhost but no vnc-client or it borked..
else:
log.error(
'VNC CLICK HACK FAILE with,\n'
f'{vnc_err!r}\n'
)
# breakpoint()
# try_xdo_manual(client)
try_xdo_manual(client)
case 'i3ipc_xdotool':
try_xdo_manual(client)
# i3ipc_xdotool_manual_click_hack()
case _ as tech:
raise RuntimeError(
f'{tech!r} is not supported for reset tech!?'
)
raise RuntimeError(f'{tech} is not supported for reset tech!?')
# we don't really need the ``xdotool`` approach any more B)
return True
@ -275,39 +265,14 @@ async def vnc_click_hack(
# 640x1800
await client.move(
Point(
500, # x from left
400, # y from top
500,
500,
)
)
# in case a prior dialog win is open/active.
await client.press('ISO_Enter')
# ensure the ib-gw window is active
await client.click(MOUSE_BUTTON_LEFT)
# send the hotkeys combo B)
await client.press(
'Ctrl',
'Alt',
key,
) # NOTE, keys are stacked
# XXX, sometimes a dialog asking if you want to "simulate
# a reset" will show, in which case we want to select
# "Yes" (by tabbing) and then hit enter.
iters: int = 1
delay: float = 0.3
await asyncio.sleep(delay)
for i in range(iters):
log.info(f'Sending TAB {i}')
await client.press('Tab')
await asyncio.sleep(delay)
for i in range(iters):
log.info(f'Sending ENTER {i}')
await client.press('KP_Enter')
await asyncio.sleep(delay)
await client.press('Ctrl', 'Alt', key) # keys are stacked
def i3ipc_fin_wins_titled(

View File

@ -561,7 +561,7 @@ class Client:
# f'Recursing for more bars:\n'
)
# XXX, debug!
# breakpoint()
breakpoint()
# XXX ? TODO? recursively try to re-request?
# => i think *NO* right?
#

View File

@ -19,6 +19,7 @@ Platform configuration (files) mgmt.
"""
import platform
import sys
import os
import shutil
from typing import (
@ -28,7 +29,6 @@ from typing import (
from pathlib import Path
from bidict import bidict
import platformdirs
import tomlkit
try:
import tomllib
@ -41,7 +41,7 @@ from .log import get_logger
log = get_logger('broker-config')
# XXX NOTE: orig impl was taken from `click`
# XXX NOTE: taken from `click`
# |_https://github.com/pallets/click/blob/main/src/click/utils.py#L449
#
# (since apparently they have some super weirdness with SIGINT and
@ -54,21 +54,44 @@ def get_app_dir(
force_posix: bool = False,
) -> str:
'''
Returns the config folder for the application. The default behavior
r"""Returns the config folder for the application. The default behavior
is to return whatever is most appropriate for the operating system.
----
NOTE, below is originally from `click` impl fn, we can prolly remove?
----
To give you an idea, for an app called ``"Foo Bar"``, something like
the following folders could be returned:
Mac OS X:
``~/Library/Application Support/Foo Bar``
Mac OS X (POSIX):
``~/.foo-bar``
Unix:
``~/.config/foo-bar``
Unix (POSIX):
``~/.foo-bar``
Win XP (roaming):
``C:\Documents and Settings\<user>\Local Settings\Application Data\Foo``
Win XP (not roaming):
``C:\Documents and Settings\<user>\Application Data\Foo Bar``
Win 7 (roaming):
``C:\Users\<user>\AppData\Roaming\Foo Bar``
Win 7 (not roaming):
``C:\Users\<user>\AppData\Local\Foo Bar``
.. versionadded:: 2.0
:param app_name: the application name. This should be properly capitalized
and can contain whitespace.
:param roaming: controls if the folder should be roaming or not on Windows.
Has no affect otherwise.
:param force_posix: if this is set to `True` then on any POSIX system the
folder will be stored in the home folder with a leading
dot instead of the XDG config home or darwin's
application support folder.
'''
"""
def _posixify(name):
return "-".join(name.split()).lower()
# NOTE: for testing with `pytest` we leverage the `tmp_dir`
# fixture to generate (and clean up) a test-request-specific
# directory for isolated configuration files such that,
@ -94,30 +117,23 @@ def get_app_dir(
# assert testdirpath.exists(), 'piker test harness might be borked!?'
# app_name = str(testdirpath)
os_name: str = platform.system()
conf_dir: Path = platformdirs.user_config_path()
app_dir: Path = conf_dir / app_name
# ?TODO, from `click`; can remove?
if platform.system() == 'Windows':
key = "APPDATA" if roaming else "LOCALAPPDATA"
folder = os.environ.get(key)
if folder is None:
folder = os.path.expanduser("~")
return os.path.join(folder, app_name)
if force_posix:
def _posixify(name):
return "-".join(name.split()).lower()
return os.path.join(
os.path.expanduser(
"~/.{}".format(
_posixify(app_name)
os.path.expanduser("~/.{}".format(_posixify(app_name))))
if sys.platform == "darwin":
return os.path.join(
os.path.expanduser("~/Library/Application Support"), app_name
)
return os.path.join(
os.environ.get("XDG_CONFIG_HOME", os.path.expanduser("~/.config")),
_posixify(app_name),
)
)
log.info(
f'Using user config directory,\n'
f'platform.system(): {os_name!r}\n'
f'conf_dir: {conf_dir!r}\n'
f'app_dir: {conf_dir!r}\n'
)
return app_dir
_click_config_dir: Path = Path(get_app_dir('piker'))
@ -234,9 +250,7 @@ def repodir() -> Path:
repodir: Path = Path(os.environ.get('GITHUB_WORKSPACE'))
confdir: Path = repodir / 'config'
assert confdir.is_dir(), (
f'{confdir} DNE, {repodir} is likely incorrect!'
)
assert confdir.is_dir(), f'{confdir} DNE, {repodir} is likely incorrect!'
return repodir