Compare commits
No commits in common. "c210c286a581574bef5d8431d151be56ccbffd46" and "c5fa2624746a92bd763a4cfe93f329920bb4481e" have entirely different histories.
c210c286a5
...
c5fa262474
|
|
@ -168,7 +168,7 @@ async def _reconnect_forever(
|
||||||
nobsws: NoBsWs,
|
nobsws: NoBsWs,
|
||||||
reset_after: int, # msg recv timeout before reset attempt
|
reset_after: int, # msg recv timeout before reset attempt
|
||||||
|
|
||||||
fixture: AsyncContextManager|None = None,
|
fixture: AsyncContextManager | None = None,
|
||||||
task_status: TaskStatus = trio.TASK_STATUS_IGNORED,
|
task_status: TaskStatus = trio.TASK_STATUS_IGNORED,
|
||||||
|
|
||||||
) -> None:
|
) -> None:
|
||||||
|
|
@ -185,7 +185,7 @@ async def _reconnect_forever(
|
||||||
async def proxy_msgs(
|
async def proxy_msgs(
|
||||||
ws: WebSocketConnection,
|
ws: WebSocketConnection,
|
||||||
rent_cs: trio.CancelScope, # parent cancel scope
|
rent_cs: trio.CancelScope, # parent cancel scope
|
||||||
) -> None:
|
):
|
||||||
'''
|
'''
|
||||||
Receive (under `timeout` deadline) all msgs from from underlying
|
Receive (under `timeout` deadline) all msgs from from underlying
|
||||||
websocket and relay them to (calling) parent task via ``trio``
|
websocket and relay them to (calling) parent task via ``trio``
|
||||||
|
|
@ -206,7 +206,7 @@ async def _reconnect_forever(
|
||||||
except nobsws.recon_errors:
|
except nobsws.recon_errors:
|
||||||
log.exception(
|
log.exception(
|
||||||
f'{src_mod}\n'
|
f'{src_mod}\n'
|
||||||
f'{url!r} connection failed\n'
|
f'{url} connection bail with:'
|
||||||
)
|
)
|
||||||
with trio.CancelScope(shield=True):
|
with trio.CancelScope(shield=True):
|
||||||
await trio.sleep(0.5)
|
await trio.sleep(0.5)
|
||||||
|
|
@ -269,7 +269,7 @@ async def _reconnect_forever(
|
||||||
nobsws._ws = ws
|
nobsws._ws = ws
|
||||||
log.info(
|
log.info(
|
||||||
f'{src_mod}\n'
|
f'{src_mod}\n'
|
||||||
f'Connection success: {url!r}'
|
f'Connection success: {url}'
|
||||||
)
|
)
|
||||||
|
|
||||||
# begin relay loop to forward msgs
|
# begin relay loop to forward msgs
|
||||||
|
|
@ -341,7 +341,7 @@ async def _reconnect_forever(
|
||||||
async def open_autorecon_ws(
|
async def open_autorecon_ws(
|
||||||
url: str,
|
url: str,
|
||||||
|
|
||||||
fixture: AsyncContextManager|None = None,
|
fixture: AsyncContextManager | None = None,
|
||||||
|
|
||||||
# time in sec between msgs received before
|
# time in sec between msgs received before
|
||||||
# we presume connection might need a reset.
|
# we presume connection might need a reset.
|
||||||
|
|
@ -361,7 +361,7 @@ async def open_autorecon_ws(
|
||||||
and restarts the full http(s) handshake on catches of certain
|
and restarts the full http(s) handshake on catches of certain
|
||||||
connetivity errors, or some user defined recv timeout.
|
connetivity errors, or some user defined recv timeout.
|
||||||
|
|
||||||
You can provide a `fixture` async-context-manager which will be
|
You can provide a ``fixture`` async-context-manager which will be
|
||||||
entered/exitted around each connection reset; eg. for
|
entered/exitted around each connection reset; eg. for
|
||||||
(re)requesting subscriptions without requiring streaming setup
|
(re)requesting subscriptions without requiring streaming setup
|
||||||
code to rerun.
|
code to rerun.
|
||||||
|
|
@ -402,8 +402,7 @@ async def open_autorecon_ws(
|
||||||
except NoBsWs.recon_errors as con_err:
|
except NoBsWs.recon_errors as con_err:
|
||||||
log.warning(
|
log.warning(
|
||||||
f'Entire ws-channel disconnect due to,\n'
|
f'Entire ws-channel disconnect due to,\n'
|
||||||
f'\n'
|
f'con_err: {con_err!r}\n'
|
||||||
f'{con_err!r}\n'
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -425,7 +424,7 @@ class JSONRPCResult(Struct):
|
||||||
async def open_jsonrpc_session(
|
async def open_jsonrpc_session(
|
||||||
url: str,
|
url: str,
|
||||||
start_id: int = 0,
|
start_id: int = 0,
|
||||||
response_type: Type[Struct] = JSONRPCResult,
|
response_type: type = JSONRPCResult,
|
||||||
msg_recv_timeout: float = float('inf'),
|
msg_recv_timeout: float = float('inf'),
|
||||||
# ^NOTE, since only `deribit` is using this jsonrpc stuff atm
|
# ^NOTE, since only `deribit` is using this jsonrpc stuff atm
|
||||||
# and options mkts are generally "slow moving"..
|
# and options mkts are generally "slow moving"..
|
||||||
|
|
@ -436,10 +435,7 @@ async def open_jsonrpc_session(
|
||||||
# broken and never restored with wtv init sequence is required to
|
# broken and never restored with wtv init sequence is required to
|
||||||
# re-establish a working req-resp session.
|
# re-establish a working req-resp session.
|
||||||
|
|
||||||
) -> Callable[
|
) -> Callable[[str, dict], dict]:
|
||||||
[str, dict],
|
|
||||||
dict,
|
|
||||||
]:
|
|
||||||
'''
|
'''
|
||||||
Init a json-RPC-over-websocket connection to the provided `url`.
|
Init a json-RPC-over-websocket connection to the provided `url`.
|
||||||
|
|
||||||
|
|
@ -535,18 +531,14 @@ async def open_jsonrpc_session(
|
||||||
'id': mid,
|
'id': mid,
|
||||||
} if not rpc_results.get(mid):
|
} if not rpc_results.get(mid):
|
||||||
log.warning(
|
log.warning(
|
||||||
f'Unexpected ws msg?\n'
|
f'Unexpected ws msg: {json.dumps(msg, indent=4)}'
|
||||||
f'{json.dumps(msg, indent=4)}'
|
|
||||||
)
|
)
|
||||||
|
|
||||||
case {
|
case {
|
||||||
'method': _,
|
'method': _,
|
||||||
'params': _,
|
'params': _,
|
||||||
}:
|
}:
|
||||||
log.debug(
|
log.debug(f'Recieved\n{msg}')
|
||||||
f'Recieved\n'
|
|
||||||
f'{msg!r}'
|
|
||||||
)
|
|
||||||
|
|
||||||
case {
|
case {
|
||||||
'error': error
|
'error': error
|
||||||
|
|
@ -562,15 +554,12 @@ async def open_jsonrpc_session(
|
||||||
result['event'].set()
|
result['event'].set()
|
||||||
log.error(
|
log.error(
|
||||||
f'JSONRPC request failed\n'
|
f'JSONRPC request failed\n'
|
||||||
f'req: {req_msg!r}\n'
|
f'req: {req_msg}\n'
|
||||||
f'resp: {error!r}\n'
|
f'resp: {error}\n'
|
||||||
)
|
)
|
||||||
|
|
||||||
case _:
|
case _:
|
||||||
log.warning(
|
log.warning(f'Unhandled JSON-RPC msg!?\n{msg}')
|
||||||
f'Unhandled JSON-RPC msg!?\n'
|
|
||||||
f'{msg!r}'
|
|
||||||
)
|
|
||||||
|
|
||||||
tn.start_soon(recv_task)
|
tn.start_soon(recv_task)
|
||||||
yield json_rpc
|
yield json_rpc
|
||||||
|
|
|
||||||
|
|
@ -342,10 +342,7 @@ class MainWindow(QMainWindow):
|
||||||
log.debug('Saved window geometry for next session')
|
log.debug('Saved window geometry for next session')
|
||||||
|
|
||||||
# raising KBI seems to get intercepted by by Qt so just use the system.
|
# raising KBI seems to get intercepted by by Qt so just use the system.
|
||||||
os.kill(
|
os.kill(os.getpid(), signal.SIGINT)
|
||||||
os.getpid(),
|
|
||||||
signal.SIGINT,
|
|
||||||
)
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def status_bar(self) -> QStatusBar:
|
def status_bar(self) -> QStatusBar:
|
||||||
|
|
@ -552,9 +549,9 @@ class MainWindow(QMainWindow):
|
||||||
|
|
||||||
# update godwidget and its children
|
# update godwidget and its children
|
||||||
if self.godwidget:
|
if self.godwidget:
|
||||||
# update search bg if it exists
|
# update search widget if it exists
|
||||||
if search := getattr(self.godwidget, 'search', None):
|
if hasattr(self.godwidget, 'search') and self.godwidget.search:
|
||||||
search.update_fonts()
|
self.godwidget.search.update_fonts()
|
||||||
|
|
||||||
# update order mode panes in all chart views
|
# update order mode panes in all chart views
|
||||||
self._update_chart_order_panes()
|
self._update_chart_order_panes()
|
||||||
|
|
@ -574,10 +571,7 @@ class MainWindow(QMainWindow):
|
||||||
return
|
return
|
||||||
|
|
||||||
# iterate through all linked splits (hist and rt)
|
# iterate through all linked splits (hist and rt)
|
||||||
for splits_name in [
|
for splits_name in ['hist_linked', 'rt_linked']:
|
||||||
'hist_linked',
|
|
||||||
'rt_linked',
|
|
||||||
]:
|
|
||||||
splits = getattr(self.godwidget, splits_name, None)
|
splits = getattr(self.godwidget, splits_name, None)
|
||||||
if not splits:
|
if not splits:
|
||||||
continue
|
continue
|
||||||
|
|
@ -589,14 +583,12 @@ class MainWindow(QMainWindow):
|
||||||
self._update_chart_axes(chart)
|
self._update_chart_axes(chart)
|
||||||
|
|
||||||
# update order pane
|
# update order pane
|
||||||
if (
|
if hasattr(chart, 'view'):
|
||||||
(view := getattr(chart, 'view', None))
|
view = chart.view
|
||||||
and
|
if hasattr(view, 'order_mode') and view.order_mode:
|
||||||
(order_mode := getattr(view, 'order_mode', None))
|
order_mode = view.order_mode
|
||||||
and
|
if hasattr(order_mode, 'pane') and order_mode.pane:
|
||||||
(pane := getattr(order_mode, 'pane', None))
|
order_mode.pane.update_fonts()
|
||||||
):
|
|
||||||
pane.update_fonts()
|
|
||||||
|
|
||||||
# also check subplots
|
# also check subplots
|
||||||
subplots = getattr(splits, 'subplots', {})
|
subplots = getattr(splits, 'subplots', {})
|
||||||
|
|
@ -605,90 +597,54 @@ class MainWindow(QMainWindow):
|
||||||
self._update_chart_axes(subplot_chart)
|
self._update_chart_axes(subplot_chart)
|
||||||
|
|
||||||
# update subplot order pane
|
# update subplot order pane
|
||||||
if (
|
if hasattr(subplot_chart, 'view'):
|
||||||
(view := getattr(subplot_chart, 'view', None))
|
subplot_view = subplot_chart.view
|
||||||
and
|
if hasattr(subplot_view, 'order_mode') and subplot_view.order_mode:
|
||||||
(order_mode := getattr(
|
subplot_order_mode = subplot_view.order_mode
|
||||||
view, 'order_mode', None,
|
if hasattr(subplot_order_mode, 'pane') and subplot_order_mode.pane:
|
||||||
))
|
subplot_order_mode.pane.update_fonts()
|
||||||
and
|
|
||||||
(pane := getattr(order_mode, 'pane', None))
|
|
||||||
):
|
|
||||||
pane.update_fonts()
|
|
||||||
|
|
||||||
# resize all sidepanes to match the
|
# resize all sidepanes to match main chart's sidepane width
|
||||||
# main chart's sidepane width; ensures
|
# this ensures volume/subplot sidepanes match the main chart
|
||||||
# volume/subplot sidepanes match.
|
if splits and hasattr(splits, 'resize_sidepanes'):
|
||||||
if (
|
splits.resize_sidepanes()
|
||||||
splits
|
|
||||||
and
|
|
||||||
(resize := getattr(
|
|
||||||
splits, 'resize_sidepanes', None,
|
|
||||||
))
|
|
||||||
):
|
|
||||||
resize()
|
|
||||||
|
|
||||||
def _update_chart_axes(self, chart) -> None:
|
def _update_chart_axes(self, chart) -> None:
|
||||||
'''
|
'''Update axis fonts and sizing for a chart.'''
|
||||||
Update axis fonts and sizing for a chart.
|
|
||||||
|
|
||||||
'''
|
|
||||||
from . import _style
|
from . import _style
|
||||||
|
|
||||||
# update price axis (right side)
|
# update price axis (right side)
|
||||||
if plot_item := getattr(chart, 'pi', None):
|
if hasattr(chart, 'pi') and chart.pi:
|
||||||
|
plot_item = chart.pi
|
||||||
# get all axes from plot item
|
# get all axes from plot item
|
||||||
for axis_name in [
|
for axis_name in ['left', 'right', 'bottom', 'top']:
|
||||||
'left',
|
axis = plot_item.getAxis(axis_name)
|
||||||
'right',
|
if axis and hasattr(axis, 'update_fonts'):
|
||||||
'bottom',
|
axis.update_fonts(_style._font)
|
||||||
'top',
|
|
||||||
]:
|
|
||||||
if (
|
|
||||||
(axis := plot_item.getAxis(axis_name))
|
|
||||||
and
|
|
||||||
(update_fonts := getattr(
|
|
||||||
axis, 'update_fonts', None,
|
|
||||||
))
|
|
||||||
):
|
|
||||||
update_fonts(_style._font)
|
|
||||||
|
|
||||||
# force plot item to recalculate
|
# force plot item to recalculate its entire layout
|
||||||
# its entire layout
|
|
||||||
plot_item.updateGeometry()
|
plot_item.updateGeometry()
|
||||||
|
|
||||||
# force chart widget to update
|
# force chart widget to update
|
||||||
if update_geom := getattr(chart, 'updateGeometry', None):
|
if hasattr(chart, 'updateGeometry'):
|
||||||
update_geom()
|
chart.updateGeometry()
|
||||||
|
|
||||||
# trigger a full scene update
|
# trigger a full scene update
|
||||||
if update := getattr(chart, 'update', None):
|
if hasattr(chart, 'update'):
|
||||||
update()
|
chart.update()
|
||||||
|
|
||||||
def _refresh_widget_fonts(
|
def _refresh_widget_fonts(self, widget: QWidget) -> None:
|
||||||
self,
|
|
||||||
widget: QWidget,
|
|
||||||
) -> None:
|
|
||||||
'''
|
'''
|
||||||
Recursively update font sizes in all
|
Recursively update font sizes in all child widgets.
|
||||||
child widgets.
|
|
||||||
|
|
||||||
Handles widgets that have font-size
|
|
||||||
hardcoded in their stylesheets.
|
|
||||||
|
|
||||||
|
This handles widgets that have font-size hardcoded in their stylesheets.
|
||||||
'''
|
'''
|
||||||
from . import _style
|
from . import _style
|
||||||
|
|
||||||
# recursively process all children
|
# recursively process all children
|
||||||
for child in widget.findChildren(QWidget):
|
for child in widget.findChildren(QWidget):
|
||||||
# skip widgets that have custom update
|
# skip widgets that have their own update_fonts method (handled separately)
|
||||||
# methods; handled separately below.
|
if hasattr(child, 'update_fonts'):
|
||||||
if getattr(child, 'update_fonts', None):
|
|
||||||
log.debug(
|
|
||||||
f'Skipping sub-widget with'
|
|
||||||
f' custom font-update meth..\n'
|
|
||||||
f'{child!r}\n'
|
|
||||||
)
|
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# update child's stylesheet if it has font-size
|
# update child's stylesheet if it has font-size
|
||||||
|
|
@ -698,35 +654,23 @@ class MainWindow(QMainWindow):
|
||||||
# this is a heuristic - may need refinement
|
# this is a heuristic - may need refinement
|
||||||
try:
|
try:
|
||||||
child.setFont(_style._font.font)
|
child.setFont(_style._font.font)
|
||||||
except (
|
except (AttributeError, RuntimeError):
|
||||||
AttributeError,
|
pass
|
||||||
RuntimeError,
|
|
||||||
):
|
|
||||||
log.exception(
|
|
||||||
'Failed to update sub-widget font?\n'
|
|
||||||
)
|
|
||||||
|
|
||||||
# update child's font
|
# update child's font
|
||||||
try:
|
try:
|
||||||
child.setFont(_style._font.font)
|
child.setFont(_style._font.font)
|
||||||
except (
|
except (AttributeError, RuntimeError):
|
||||||
AttributeError,
|
pass
|
||||||
RuntimeError,
|
|
||||||
):
|
|
||||||
log.exception(
|
|
||||||
'Failed to update sub-widget font?\n'
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
# singleton app per actor
|
# singleton app per actor
|
||||||
_qt_win: QMainWindow|None = None
|
_qt_win: QMainWindow = None
|
||||||
|
|
||||||
|
|
||||||
def main_window() -> MainWindow:
|
def main_window() -> MainWindow:
|
||||||
'''
|
'Return the actor-global Qt window.'
|
||||||
Return the actor-global Qt window.
|
|
||||||
|
|
||||||
'''
|
|
||||||
global _qt_win
|
global _qt_win
|
||||||
assert _qt_win
|
assert _qt_win
|
||||||
return _qt_win
|
return _qt_win
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue