From 323290d20bbf8102914887d8013bcd843348ebf1 Mon Sep 17 00:00:00 2001 From: Tyler Goodlet Date: Thu, 13 Feb 2025 11:04:59 -0500 Subject: [PATCH 01/13] Teensie `piker.data` styling tweaks - use more compact optional value style with `|`-union - fix `.flows` typing-only import since we need `MktPair` to be immediately defined for use on a `msgspec.Struct` field. - more "tree-like" warning msg in `.validate()` reporting. --- piker/data/feed.py | 6 ++---- piker/data/flows.py | 6 +++--- piker/data/validate.py | 6 +++--- 3 files changed, 8 insertions(+), 10 deletions(-) diff --git a/piker/data/feed.py b/piker/data/feed.py index 7264c8e6..d47d8df9 100644 --- a/piker/data/feed.py +++ b/piker/data/feed.py @@ -786,7 +786,6 @@ async def install_brokerd_search( @acm async def maybe_open_feed( - fqmes: list[str], loglevel: str | None = None, @@ -840,13 +839,12 @@ async def maybe_open_feed( @acm async def open_feed( - fqmes: list[str], - loglevel: str | None = None, + loglevel: str|None = None, allow_overruns: bool = True, start_stream: bool = True, - tick_throttle: float | None = None, # Hz + tick_throttle: float|None = None, # Hz allow_remote_ctl_ui: bool = False, diff --git a/piker/data/flows.py b/piker/data/flows.py index 677b2f69..573180b9 100644 --- a/piker/data/flows.py +++ b/piker/data/flows.py @@ -36,10 +36,10 @@ from ._sharedmem import ( ShmArray, _Token, ) +from piker.accounting import MktPair if TYPE_CHECKING: - from ..accounting import MktPair - from .feed import Feed + from piker.data.feed import Feed class Flume(Struct): @@ -82,7 +82,7 @@ class Flume(Struct): # TODO: do we need this really if we can pull the `Portal` from # ``tractor``'s internals? - feed: Feed | None = None + feed: Feed|None = None @property def rt_shm(self) -> ShmArray: diff --git a/piker/data/validate.py b/piker/data/validate.py index cefa0f1f..c5317ede 100644 --- a/piker/data/validate.py +++ b/piker/data/validate.py @@ -113,9 +113,9 @@ def validate_backend( ) if ep is None: log.warning( - f'Provider backend {mod.name} is missing ' - f'{daemon_name} support :(\n' - f'The following endpoint is missing: {name}' + f'Provider backend {mod.name!r} is missing ' + f'{daemon_name!r} support?\n' + f'|_module endpoint-func missing: {name!r}\n' ) inits: list[ From 2158e27a666dbd03e7e0e82939d3af2f3de1ab22 Mon Sep 17 00:00:00 2001 From: Tyler Goodlet Date: Mon, 9 Jun 2025 10:27:01 -0400 Subject: [PATCH 02/13] Add missing f-str prefix to log line --- piker/data/_sampling.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/piker/data/_sampling.py b/piker/data/_sampling.py index e5b87a2a..cc32af91 100644 --- a/piker/data/_sampling.py +++ b/piker/data/_sampling.py @@ -740,7 +740,7 @@ async def sample_and_broadcast( log.warning( f'Feed OVERRUN {sub_key}' - '@{bus.brokername} -> \n' + f'@{bus.brokername} -> \n' f'feed @ {chan.uid}\n' f'throttle = {throttle} Hz' ) From cbe0cbd29cb6c45ce345089d3badd6a581765580 Mon Sep 17 00:00:00 2001 From: Tyler Goodlet Date: Mon, 9 Jun 2025 10:43:52 -0400 Subject: [PATCH 03/13] Add a couple new grays to the pallete --- piker/ui/_style.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/piker/ui/_style.py b/piker/ui/_style.py index 302d9d30..196d6fd8 100644 --- a/piker/ui/_style.py +++ b/piker/ui/_style.py @@ -269,6 +269,8 @@ def hcolor(name: str) -> str: # default ohlc-bars/curve gray 'bracket': '#666666', # like the logo + 'pikers': '#616161', # a trader shade of.. + 'beast': '#161616', # in the dark alone. # bluish 'charcoal': '#36454F', From 57a5903ccfdeece08f3c966795b90d85db02b786 Mon Sep 17 00:00:00 2001 From: Tyler Goodlet Date: Fri, 20 Jun 2025 16:00:14 -0400 Subject: [PATCH 04/13] Start a manual `tags` file for internal refs --- tags | 1 + 1 file changed, 1 insertion(+) create mode 100644 tags diff --git a/tags b/tags new file mode 100644 index 00000000..5b077243 --- /dev/null +++ b/tags @@ -0,0 +1 @@ +TAG_feed_status_update ./piker/data/feed.py /TAG_feed_status_update/ From 2d44a9afaa61826b29172ff3501415799f594392 Mon Sep 17 00:00:00 2001 From: Tyler Goodlet Date: Fri, 18 Jul 2025 19:35:54 -0400 Subject: [PATCH 05/13] Drop old/masked ahab-docker daemon starting --- piker/cli/__init__.py | 23 ++--------------------- 1 file changed, 2 insertions(+), 21 deletions(-) diff --git a/piker/cli/__init__.py b/piker/cli/__init__.py index dde7f83c..bf26d5ab 100644 --- a/piker/cli/__init__.py +++ b/piker/cli/__init__.py @@ -189,28 +189,9 @@ def pikerd( # AsyncExitStack() as stack, ): - # TODO: spawn all other sub-actor daemons according to - # multiaddress endpoint spec defined by user config assert service_mngr - - # if tsdb: - # dname, conf = await stack.enter_async_context( - # service.marketstore.start_ahab_daemon( - # service_mngr, - # loglevel=loglevel, - # ) - # ) - # log.info(f'TSDB `{dname}` up with conf:\n{conf}') - - # if es: - # dname, conf = await stack.enter_async_context( - # service.elastic.start_ahab_daemon( - # service_mngr, - # loglevel=loglevel, - # ) - # ) - # log.info(f'DB `{dname}` up with conf:\n{conf}') - + # ?TODO? spawn all other sub-actor daemons according to + # multiaddress endpoint spec defined by user config await trio.sleep_forever() trio.run(main) From 60df863a6a65d5842bc2dbea668b5e7acc1cc7f6 Mon Sep 17 00:00:00 2001 From: Tyler Goodlet Date: Mon, 21 Jul 2025 18:42:57 -0400 Subject: [PATCH 06/13] Mk a `notes_to_self/` move orig file `ideas.rst' --- notes_to_self.rst => notes_to_self/ideas.rst | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename notes_to_self.rst => notes_to_self/ideas.rst (100%) diff --git a/notes_to_self.rst b/notes_to_self/ideas.rst similarity index 100% rename from notes_to_self.rst rename to notes_to_self/ideas.rst From dbe2567fe818243c028105a345916fa58a73278a Mon Sep 17 00:00:00 2001 From: Tyler Goodlet Date: Mon, 22 Sep 2025 09:05:51 -0400 Subject: [PATCH 07/13] Flip screen-info script to qt6, refine it to heck. Buncha updates and improvements, - adjust sub-namespace imports according to console warnings. - iterate all detected screens in a loop and instead report which is the primary and the current. - type annotate all vars where non-obvious, particularly the`Qt` refs. --- snippets/qt_screen_info.py | 131 +++++++++++++++++++++---------------- 1 file changed, 73 insertions(+), 58 deletions(-) diff --git a/snippets/qt_screen_info.py b/snippets/qt_screen_info.py index 238367c0..9862a9b8 100644 --- a/snippets/qt_screen_info.py +++ b/snippets/qt_screen_info.py @@ -1,4 +1,22 @@ -""" +# 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 . + +''' +A per-display, DPI (scaling) info dumper. + Resource list for mucking with DPIs on multiple screens: - https://stackoverflow.com/questions/42141354/convert-pixel-size-to-point-size-for-fonts-on-multiple-platforms @@ -12,89 +30,86 @@ Resource list for mucking with DPIs on multiple screens: - https://stackoverflow.com/questions/16561879/what-is-the-difference-between-logicaldpix-and-physicaldpix-in-qt - https://doc.qt.io/qt-5/qguiapplication.html#screenAt -""" +''' from pyqtgraph import QtGui -from PyQt5.QtCore import ( - Qt, QCoreApplication +from PyQt6 import ( + QtCore, + QtWidgets, +) +from PyQt6.QtCore import ( + Qt, + QCoreApplication, + QSize, + QRect, ) # Proper high DPI scaling is available in Qt >= 5.6.0. This attibute # must be set before creating the application if hasattr(Qt, 'AA_EnableHighDpiScaling'): - QCoreApplication.setAttribute(Qt.AA_EnableHighDpiScaling, True) + QCoreApplication.setAttribute( + Qt.AA_EnableHighDpiScaling, + True, + ) if hasattr(Qt, 'AA_UseHighDpiPixmaps'): - QCoreApplication.setAttribute(Qt.AA_UseHighDpiPixmaps, True) + QCoreApplication.setAttribute( + Qt.AA_UseHighDpiPixmaps, + True, + ) - -app = QtGui.QApplication([]) -window = QtGui.QMainWindow() -main_widget = QtGui.QWidget() +app = QtWidgets.QApplication([]) +window = QtWidgets.QMainWindow() +main_widget = QtWidgets.QWidget() window.setCentralWidget(main_widget) window.show() -pxr = main_widget.devicePixelRatioF() +pxr: float = main_widget.devicePixelRatioF() -# screen_num = app.desktop().screenNumber() -# screen = app.screens()[screen_num] - -screen = app.screenAt(main_widget.geometry().center()) - -name = screen.name() -size = screen.size() -geo = screen.availableGeometry() -phydpi = screen.physicalDotsPerInch() -logdpi = screen.logicalDotsPerInch() - -print( - # f'screen number: {screen_num}\n', - f'screen name: {name}\n' - f'screen size: {size}\n' - f'screen geometry: {geo}\n\n' - f'devicePixelRationF(): {pxr}\n' - f'physical dpi: {phydpi}\n' - f'logical dpi: {logdpi}\n' +# explicitly get main widget and primary displays +current_screen: QtGui.QScreen = app.screenAt( + main_widget.geometry().center() ) +primary_screen: QtGui.QScreen = app.primaryScreen() -print('-'*50) +screen: QtGui.QScreen +for screen in app.screens(): + name: str = screen.name() + model: str = screen.model().rstrip() + size: QSize = screen.size() + geo: QRect = screen.availableGeometry() + phydpi: float = screen.physicalDotsPerInch() + logdpi: float = screen.logicalDotsPerInch() + is_primary: bool = screen is primary_screen + is_current: bool = screen is current_screen -screen = app.primaryScreen() + print( + f'------ screen name: {name} ------\n' + f'|_primary: {is_primary}\n' + f' _current: {is_current}\n' + f' _model: {model}\n' + f' _screen size: {size}\n' + f' _screen geometry: {geo}\n' + f' _devicePixelRationF(): {pxr}\n' + f' _physical dpi: {phydpi}\n' + f' _logical dpi: {logdpi}\n' + ) -name = screen.name() -size = screen.size() -geo = screen.availableGeometry() -phydpi = screen.physicalDotsPerInch() -logdpi = screen.logicalDotsPerInch() - -print( - # f'screen number: {screen_num}\n', - f'screen name: {name}\n' - f'screen size: {size}\n' - f'screen geometry: {geo}\n\n' - f'devicePixelRationF(): {pxr}\n' - f'physical dpi: {phydpi}\n' - f'logical dpi: {logdpi}\n' -) - - -# app-wide font +# app-wide font info font = QtGui.QFont("Hack") # use pixel size to be cross-resolution compatible? font.setPixelSize(6) - fm = QtGui.QFontMetrics(font) -fontdpi = fm.fontDpi() -font_h = fm.height() - -string = '10000' -str_br = fm.boundingRect(string) -str_w = str_br.width() +fontdpi: float = fm.fontDpi() +font_h: int = fm.height() +string: str = '10000' +str_br: QtCore.QRect = fm.boundingRect(string) +str_w: int = str_br.width() print( - # f'screen number: {screen_num}\n', + f'------ global font settings ------\n' f'font dpi: {fontdpi}\n' f'font height: {font_h}\n' f'string bounding rect: {str_br}\n' From 7e600b3901ab9ea34d263290672679f351bc52d9 Mon Sep 17 00:00:00 2001 From: Tyler Goodlet Date: Mon, 29 Sep 2025 13:44:57 -0400 Subject: [PATCH 08/13] Avoid `msgspec` eval-err on `Asset` in symcache? --- piker/data/_symcache.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/piker/data/_symcache.py b/piker/data/_symcache.py index bcaa5844..80272231 100644 --- a/piker/data/_symcache.py +++ b/piker/data/_symcache.py @@ -77,7 +77,7 @@ class SymbologyCache(Struct): # all asset-money-systems descriptions as minimally defined by # in `.accounting.Asset` - assets: dict[str, Asset] = field(default_factory=dict) + assets: dict[str, 'Asset'] = field(default_factory=dict) # backend-system pairs loaded in provider (schema) specific # structs. From 0282e632f981cf0f89d86d4fe189267558174847 Mon Sep 17 00:00:00 2001 From: Tyler Goodlet Date: Mon, 29 Sep 2025 15:00:14 -0400 Subject: [PATCH 09/13] `data._symcache`, impl a summary `.__repr__()`, avoids `Asset` causality issues --- piker/data/_symcache.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/piker/data/_symcache.py b/piker/data/_symcache.py index 80272231..1f1cb9ec 100644 --- a/piker/data/_symcache.py +++ b/piker/data/_symcache.py @@ -77,7 +77,7 @@ class SymbologyCache(Struct): # all asset-money-systems descriptions as minimally defined by # in `.accounting.Asset` - assets: dict[str, 'Asset'] = field(default_factory=dict) + assets: dict[str, Asset] = field(default_factory=dict) # backend-system pairs loaded in provider (schema) specific # structs. @@ -91,6 +91,18 @@ class SymbologyCache(Struct): # provided by the backend pkg. mktmaps: dict[str, MktPair] = field(default_factory=dict) + def pformat(self) -> str: + return ( + f'<{type(self).__name__}(\n' + f' .mod: {self.mod!r}\n' + f' .assets: {len(self.assets)!r}\n' + f' .pairs: {len(self.pairs)!r}\n' + f' .mktmaps: {len(self.mktmaps)!r}\n' + f')>' + ) + + __repr__ = pformat + def write_config(self) -> None: # put the backend's pair-struct type ref at the top From b3d345fc410923716463cc46690eafbdc3cb1379 Mon Sep 17 00:00:00 2001 From: Tyler Goodlet Date: Thu, 2 Oct 2025 20:07:23 -0400 Subject: [PATCH 10/13] Wow, update root `conf.toml` to new multiaddr style I don't know how this wasn't already committed but.. drops the legacy `marketstore` tsdb socket info vars since we're going all in on `nativedb` BP --- config/conf.toml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/config/conf.toml b/config/conf.toml index a14f6bdd..1f2a64bc 100644 --- a/config/conf.toml +++ b/config/conf.toml @@ -1,7 +1,9 @@ [network] -tsdb.backend = 'marketstore' -tsdb.host = 'localhost' -tsdb.grpc_port = 5995 +pikerd = [ + '/ipv4/127.0.0.1/tcp/6116', # std localhost daemon-actor tree + # '/uds/6116', # TODO std uds socket file +] + [ui] # set custom font + size which will scale entire UI From 4b1fa2173ba54d94844b7bf0f5c5a6165accb64b Mon Sep 17 00:00:00 2001 From: Tyler Goodlet Date: Tue, 16 Dec 2025 12:42:11 -0500 Subject: [PATCH 11/13] Touch `conf.toml` by default when dne? --- piker/config.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/piker/config.py b/piker/config.py index 97eb4881..eae39e81 100644 --- a/piker/config.py +++ b/piker/config.py @@ -261,7 +261,7 @@ def load( MutableMapping, ] = tomllib.loads, - touch_if_dne: bool = False, + touch_if_dne: bool = True, **tomlkws, @@ -270,7 +270,7 @@ def load( Load config file by name. If desired config is not in the top level piker-user config path then - pass the ``path: Path`` explicitly. + pass the `path: Path` explicitly. ''' # create the $HOME/.config/piker dir if dne @@ -285,7 +285,8 @@ def load( if ( not path.is_file() - and touch_if_dne + and + touch_if_dne ): # only do a template if no path provided, # just touch an empty file with same name. From b2b0e4c40d744e18094ac02855d8c0237324dfca Mon Sep 17 00:00:00 2001 From: Tyler Goodlet Date: Tue, 30 Dec 2025 11:03:42 -0500 Subject: [PATCH 12/13] `.config.get_app_dir()`: link to `click`'s orig impl on GH --- piker/config.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/piker/config.py b/piker/config.py index eae39e81..e6d3e60a 100644 --- a/piker/config.py +++ b/piker/config.py @@ -41,10 +41,13 @@ from .log import get_logger log = get_logger('broker-config') -# XXX NOTE: taken from ``click`` since apparently they have some -# super weirdness with sigint and sudo..no clue -# we're probably going to slowly just modify it to our own version over -# time.. +# 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 +# sudo.. no clue we're probably going to slowly just modify it to our +# own version over time..) +# def get_app_dir( app_name: str, roaming: bool = True, From dc61e6fc4fd6300d777ffc343f903c4f997005a5 Mon Sep 17 00:00:00 2001 From: Tyler Goodlet Date: Tue, 30 Dec 2025 11:06:43 -0500 Subject: [PATCH 13/13] Report with `{fqme!r}` in feed allocator for type clarity --- piker/data/feed.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/piker/data/feed.py b/piker/data/feed.py index d47d8df9..df4106e0 100644 --- a/piker/data/feed.py +++ b/piker/data/feed.py @@ -352,7 +352,9 @@ async def allocate_persistent_feed( # yield back control to starting nursery once we receive either # some history or a real-time quote. - log.info(f'loading OHLCV history: {fqme}') + log.info( + f'loading OHLCV history: {fqme!r}\n' + ) await some_data_ready.wait() flume = Flume(