port_to_latest_tractor #45
			
				
			
		
		
		
	
							
								
								
									
										31
									
								
								README.rst
								
								
								
								
							
							
						
						
									
										31
									
								
								README.rst
								
								
								
								
							|  | @ -88,15 +88,23 @@ a sane install with `uv` | |||
| ************************ | ||||
| bc why install with `python` when you can faster with `rust` :: | ||||
| 
 | ||||
|     uv lock | ||||
|     uv sync | ||||
| 
 | ||||
| with all GUI support as well:: | ||||
|     # ^ astral's docs, | ||||
|     # https://docs.astral.sh/uv/concepts/projects/sync/ | ||||
| 
 | ||||
|     uv lock --extra uis | ||||
| include all GUIs :: | ||||
| 
 | ||||
| AND with all dev (hacking) tools:: | ||||
|     uv sync --extra uis | ||||
| 
 | ||||
|     uv lock --dev --extra uis | ||||
| AND with all our hacking tools:: | ||||
| 
 | ||||
|     uv sync --dev --extra uis | ||||
| 
 | ||||
| 
 | ||||
| Ensure you can run the root-daemon:: | ||||
| 
 | ||||
|     uv run pikerd [-l info --pdb] | ||||
| 
 | ||||
| 
 | ||||
| hacky install on nixos | ||||
|  | @ -111,7 +119,18 @@ start a chart | |||
| ************* | ||||
| run a realtime OHLCV chart stand-alone:: | ||||
| 
 | ||||
|     piker -l info chart btcusdt.spot.binance xmrusdt.spot.kraken | ||||
|     [uv run] piker -l info chart btcusdt.spot.binance xmrusdt.spot.kraken | ||||
| 
 | ||||
|     # ^^^ iff you haven't activated the py-env, | ||||
|     # - https://docs.astral.sh/uv/concepts/projects/run/ | ||||
|     # | ||||
|     # in order to create an explicit virt-env see, | ||||
|     # - https://docs.astral.sh/uv/concepts/projects/layout/#the-project-environment | ||||
|     # - https://docs.astral.sh/uv/pip/environments/ | ||||
|     # | ||||
|     # use $UV_PROJECT_ENVIRONMENT to select any non-`.venv/` | ||||
|     # as the venv sudir in the repo's root. | ||||
|     # - https://docs.astral.sh/uv/reference/environment/#uv_project_environment | ||||
| 
 | ||||
| this runs a chart UI (with 1m sampled OHLCV) and shows 2 spot markets from 2 diff cexes | ||||
| overlayed on the same graph. Use of `piker` without first starting | ||||
|  |  | |||
|  | @ -96,7 +96,10 @@ async def _setup_persistent_brokerd( | |||
|     # - `open_symbol_search()` | ||||
|     # NOTE: see ep invocation details inside `.data.feed`. | ||||
|     try: | ||||
|         async with trio.open_nursery() as service_nursery: | ||||
|         async with ( | ||||
|             tractor.trionics.collapse_eg(), | ||||
|             trio.open_nursery() as service_nursery | ||||
|         ): | ||||
|             bus: _FeedsBus = feed.get_feed_bus( | ||||
|                 brokername, | ||||
|                 service_nursery, | ||||
|  |  | |||
|  | @ -34,6 +34,7 @@ import urllib.parse | |||
| import hashlib | ||||
| import hmac | ||||
| import base64 | ||||
| import tractor | ||||
| import trio | ||||
| 
 | ||||
| from piker import config | ||||
|  | @ -372,8 +373,7 @@ class Client: | |||
|         #     1658347714, 'status': 'Success'}]} | ||||
| 
 | ||||
|         if xfers: | ||||
|             import tractor | ||||
|             await tractor.pp() | ||||
|             await tractor.pause() | ||||
| 
 | ||||
|         trans: dict[str, Transaction] = {} | ||||
|         for entry in xfers: | ||||
|  | @ -501,6 +501,7 @@ class Client: | |||
|             for xkey, data in resp['result'].items(): | ||||
| 
 | ||||
|                 # NOTE: always cache in pairs tables for faster lookup | ||||
|                 with tractor.devx.maybe_open_crash_handler(): # as bxerr: | ||||
|                     pair = Pair(xname=xkey, **data) | ||||
| 
 | ||||
|                 # register the above `Pair` structs for all | ||||
|  |  | |||
|  | @ -21,7 +21,6 @@ Symbology defs and search. | |||
| from decimal import Decimal | ||||
| 
 | ||||
| import tractor | ||||
| from rapidfuzz import process as fuzzy | ||||
| 
 | ||||
| from piker._cacheables import ( | ||||
|     async_lifo_cache, | ||||
|  | @ -41,8 +40,13 @@ from piker.accounting._mktinfo import ( | |||
| ) | ||||
| 
 | ||||
| 
 | ||||
| # https://www.kraken.com/features/api#get-tradable-pairs | ||||
| class Pair(Struct): | ||||
|     ''' | ||||
|     A tradable asset pair as schema-defined by, | ||||
| 
 | ||||
|     https://docs.kraken.com/api/docs/rest-api/get-tradable-asset-pairs | ||||
| 
 | ||||
|     ''' | ||||
|     xname: str  # idiotic bs_mktid equiv i guess? | ||||
|     altname: str  # alternate pair name | ||||
|     wsname: str  # WebSocket pair name (if available) | ||||
|  | @ -53,7 +57,6 @@ class Pair(Struct): | |||
|     lot: str  # volume lot size | ||||
| 
 | ||||
|     cost_decimals: int | ||||
|     costmin: float | ||||
|     pair_decimals: int  # scaling decimal places for pair | ||||
|     lot_decimals: int  # scaling decimal places for volume | ||||
| 
 | ||||
|  | @ -79,6 +82,7 @@ class Pair(Struct): | |||
|     tick_size: float  # min price step size | ||||
|     status: str | ||||
| 
 | ||||
|     costmin: str|None = None  # XXX, only some mktpairs? | ||||
|     short_position_limit: float = 0 | ||||
|     long_position_limit: float = float('inf') | ||||
| 
 | ||||
|  |  | |||
|  | @ -25,7 +25,10 @@ from typing import TYPE_CHECKING | |||
| 
 | ||||
| import trio | ||||
| import tractor | ||||
| from tractor.trionics import broadcast_receiver | ||||
| from tractor.trionics import ( | ||||
|     broadcast_receiver, | ||||
|     collapse_eg, | ||||
| ) | ||||
| 
 | ||||
| from ._util import ( | ||||
|     log,  # sub-sys logger | ||||
|  | @ -281,8 +284,11 @@ async def open_ems( | |||
|             client._ems_stream = trades_stream | ||||
| 
 | ||||
|             # start sync code order msg delivery task | ||||
|             async with trio.open_nursery() as n: | ||||
|                 n.start_soon( | ||||
|             async with ( | ||||
|                 collapse_eg(), | ||||
|                 trio.open_nursery() as tn, | ||||
|             ): | ||||
|                 tn.start_soon( | ||||
|                     relay_orders_from_sync_code, | ||||
|                     client, | ||||
|                     fqme, | ||||
|  | @ -298,4 +304,4 @@ async def open_ems( | |||
|                 ) | ||||
| 
 | ||||
|                 # stop the sync-msg-relay task on exit. | ||||
|                 n.cancel_scope.cancel() | ||||
|                 tn.cancel_scope.cancel() | ||||
|  |  | |||
|  | @ -39,6 +39,7 @@ from typing import ( | |||
|     AsyncContextManager, | ||||
|     Awaitable, | ||||
|     Sequence, | ||||
|     TYPE_CHECKING, | ||||
| ) | ||||
| 
 | ||||
| import trio | ||||
|  | @ -75,6 +76,10 @@ from ._sampling import ( | |||
|     uniform_rate_send, | ||||
| ) | ||||
| 
 | ||||
| if TYPE_CHECKING: | ||||
|     from tractor._addr import Address | ||||
|     from tractor.msg.types import Aid | ||||
| 
 | ||||
| 
 | ||||
| class Sub(Struct, frozen=True): | ||||
|     ''' | ||||
|  | @ -899,19 +904,19 @@ async def open_feed( | |||
|             feed.portals[brokermod] = portal | ||||
| 
 | ||||
|             # fill out "status info" that the UI can show | ||||
|             host, port = portal.channel.raddr | ||||
|             if host == '127.0.0.1': | ||||
|                 host = 'localhost' | ||||
| 
 | ||||
|             chan: tractor.Channel = portal.chan | ||||
|             raddr: Address = chan.raddr | ||||
|             aid: Aid = chan.aid | ||||
|             # TAG_feed_status_update | ||||
|             feed.status.update({ | ||||
|                 'actor_name': portal.channel.uid[0], | ||||
|                 'host': host, | ||||
|                 'port': port, | ||||
|                 'actor_id': aid, | ||||
|                 'actor_short_id': f'{aid.name}@{aid.pid}', | ||||
|                 'ipc': chan.raddr.proto_key, | ||||
|                 'ipc_addr': raddr, | ||||
|                 'hist_shm': 'NA', | ||||
|                 'rt_shm': 'NA', | ||||
|                 'throttle_rate': tick_throttle, | ||||
|                 'throttle_hz': tick_throttle, | ||||
|             }) | ||||
|             # feed.status.update(init_msg.pop('status', {})) | ||||
| 
 | ||||
|             # (allocate and) connect to any feed bus for this broker | ||||
|             bus_ctxs.append( | ||||
|  |  | |||
|  | @ -498,6 +498,7 @@ async def cascade( | |||
| 
 | ||||
|         func_name: str = func.__name__ | ||||
|         async with ( | ||||
|             tractor.trionics.collapse_eg(),  # avoid multi-taskc tb in console | ||||
|             trio.open_nursery() as tn, | ||||
|         ): | ||||
|             # TODO: might be better to just make a "restart" method where | ||||
|  |  | |||
|  | @ -200,7 +200,8 @@ async def open_pikerd( | |||
|             reg_addrs, | ||||
|         ), | ||||
|         tractor.open_nursery() as actor_nursery, | ||||
|         trio.open_nursery() as service_nursery, | ||||
|         tractor.trionics.collapse_eg(), | ||||
|         trio.open_nursery() as service_tn, | ||||
|     ): | ||||
|         for addr in reg_addrs: | ||||
|             if addr not in root_actor.accept_addrs: | ||||
|  | @ -211,7 +212,7 @@ async def open_pikerd( | |||
| 
 | ||||
|         # assign globally for future daemon/task creation | ||||
|         Services.actor_n = actor_nursery | ||||
|         Services.service_n = service_nursery | ||||
|         Services.service_n = service_tn | ||||
|         Services.debug_mode = debug_mode | ||||
| 
 | ||||
|         try: | ||||
|  | @ -221,7 +222,7 @@ async def open_pikerd( | |||
|             # TODO: is this more clever/efficient? | ||||
|             # if 'samplerd' in Services.service_tasks: | ||||
|             #     await Services.cancel_service('samplerd') | ||||
|             service_nursery.cancel_scope.cancel() | ||||
|             service_tn.cancel_scope.cancel() | ||||
| 
 | ||||
| 
 | ||||
| # TODO: do we even need this? | ||||
|  |  | |||
|  | @ -517,7 +517,7 @@ def with_dts( | |||
| 
 | ||||
|     ''' | ||||
|     return df.with_columns([ | ||||
|         pl.col(time_col).shift(1).suffix('_prev'), | ||||
|         pl.col(time_col).shift(1).name.suffix('_prev'), | ||||
|         pl.col(time_col).diff().alias('s_diff'), | ||||
|         pl.from_epoch(pl.col(time_col)).alias('dt'), | ||||
|     ]).with_columns([ | ||||
|  | @ -623,7 +623,7 @@ def detect_vlm_gaps( | |||
| 
 | ||||
| ) -> pl.DataFrame: | ||||
| 
 | ||||
|     vnull: pl.DataFrame = w_dts.filter( | ||||
|     vnull: pl.DataFrame = df.filter( | ||||
|         pl.col(col) == 0 | ||||
|     ) | ||||
|     return vnull | ||||
|  |  | |||
|  | @ -21,6 +21,7 @@ Main app startup and run. | |||
| from functools import partial | ||||
| from types import ModuleType | ||||
| 
 | ||||
| import tractor | ||||
| import trio | ||||
| 
 | ||||
| from piker.ui.qt import ( | ||||
|  | @ -116,6 +117,7 @@ async def _async_main( | |||
|         needed_brokermods[brokername] = brokers[brokername] | ||||
| 
 | ||||
|     async with ( | ||||
|         tractor.trionics.collapse_eg(), | ||||
|         trio.open_nursery() as root_n, | ||||
|     ): | ||||
|         # set root nursery and task stack for spawning other charts/feeds | ||||
|  |  | |||
|  | @ -33,7 +33,6 @@ import trio | |||
| 
 | ||||
| from piker.ui.qt import ( | ||||
|     QtCore, | ||||
|     QtWidgets, | ||||
|     Qt, | ||||
|     QLineF, | ||||
|     QFrame, | ||||
|  |  | |||
|  | @ -1445,7 +1445,10 @@ async def display_symbol_data( | |||
|         # for pause/resume on mouse interaction | ||||
|         rt_chart.feed = feed | ||||
| 
 | ||||
|         async with trio.open_nursery() as ln: | ||||
|         async with ( | ||||
|             tractor.trionics.collapse_eg(), | ||||
|             trio.open_nursery() as ln, | ||||
|         ): | ||||
|             # if available load volume related built-in display(s) | ||||
|             vlm_charts: dict[ | ||||
|                 str, | ||||
|  |  | |||
|  | @ -22,7 +22,10 @@ from contextlib import asynccontextmanager as acm | |||
| from typing import Callable | ||||
| 
 | ||||
| import trio | ||||
| from tractor.trionics import gather_contexts | ||||
| from tractor.trionics import ( | ||||
|     gather_contexts, | ||||
|     collapse_eg, | ||||
| ) | ||||
| 
 | ||||
| from piker.ui.qt import ( | ||||
|     QtCore, | ||||
|  | @ -207,7 +210,10 @@ async def open_signal_handler( | |||
|         async for args in recv: | ||||
|             await async_handler(*args) | ||||
| 
 | ||||
|     async with trio.open_nursery() as tn: | ||||
|     async with ( | ||||
|         collapse_eg(), | ||||
|         trio.open_nursery() as tn | ||||
|     ): | ||||
|         tn.start_soon(proxy_to_handler) | ||||
|         async with send: | ||||
|             yield | ||||
|  | @ -242,6 +248,7 @@ async def open_handlers( | |||
|     widget: QWidget | ||||
|     streams: list[trio.abc.ReceiveChannel] | ||||
|     async with ( | ||||
|         collapse_eg(), | ||||
|         trio.open_nursery() as tn, | ||||
|         gather_contexts([ | ||||
|             open_event_stream( | ||||
|  |  | |||
|  | @ -18,10 +18,11 @@ | |||
| Feed status and controls widget(s) for embedding in a UI-pane. | ||||
| 
 | ||||
| """ | ||||
| 
 | ||||
| from __future__ import annotations | ||||
| from textwrap import dedent | ||||
| from typing import TYPE_CHECKING | ||||
| from typing import ( | ||||
|     Any, | ||||
|     TYPE_CHECKING, | ||||
| ) | ||||
| 
 | ||||
| # from PyQt5.QtCore import Qt | ||||
| 
 | ||||
|  | @ -49,35 +50,55 @@ def mk_feed_label( | |||
|     a feed control protocol. | ||||
| 
 | ||||
|     ''' | ||||
|     status = feed.status | ||||
|     status: dict[str, Any] = feed.status | ||||
|     assert status | ||||
| 
 | ||||
|     msg = dedent(""" | ||||
|         actor: **{actor_name}**\n | ||||
|         |_ @**{host}:{port}**\n | ||||
|     """) | ||||
|     # SO tips on ws/nls, | ||||
|     # https://stackoverflow.com/a/15721400 | ||||
|     ws: str = ' ' | ||||
|     # nl: str = '<br>'  # dun work? | ||||
|     actor_info_repr: str = ( | ||||
|         f')> **{status["actor_short_id"]}**\n' | ||||
|         '\n'  # bc md? | ||||
|     ) | ||||
| 
 | ||||
|     for key, val in status.items(): | ||||
|         if key in ('host', 'port', 'actor_name'): | ||||
|             continue | ||||
|         msg += f'\n|_ {key}: **{{{key}}}**\n' | ||||
|     # fields to select *IN* for display | ||||
|     # (see `.data.feed.open_feed()` status | ||||
|     #  update -> TAG_feed_status_update) | ||||
|     for key in [ | ||||
|         'ipc', | ||||
|         'hist_shm', | ||||
|         'rt_shm', | ||||
|         'throttle_hz', | ||||
|     ]: | ||||
|         # NOTE, the 2nd key is filled via `.format()` updates. | ||||
|         actor_info_repr += ( | ||||
|             f'\n'  # bc md? | ||||
|             f'{ws}|_{key}: **{{{key}}}**\n' | ||||
|         ) | ||||
|         # ^TODO? formatting and content.. | ||||
|         # -[ ] showing which fqme is "forward" on the | ||||
|         #    chart/fsp/order-mode? | ||||
|         #  '|_ flows: **{symbols}**\n' | ||||
|         # | ||||
|         # -[x] why isn't the indent working? | ||||
|         #  => markdown, now solved.. | ||||
| 
 | ||||
|     feed_label = FormatLabel( | ||||
|         fmt_str=msg, | ||||
|         # |_ streams: **{symbols}**\n | ||||
|         fmt_str=actor_info_repr, | ||||
|         font=_font.font, | ||||
|         font_size=_font_small.px_size, | ||||
|         font_color='default_lightest', | ||||
|     ) | ||||
| 
 | ||||
|     # ?TODO, remove this? | ||||
|     # form.vbox.setAlignment(feed_label, Qt.AlignBottom) | ||||
|     # form.vbox.setAlignment(Qt.AlignBottom) | ||||
|     _ = chart.height() - ( | ||||
|         form.height() + | ||||
|         form.fill_bar.height() | ||||
|         # feed_label.height() | ||||
|     ) | ||||
|     # _ = chart.height() - ( | ||||
|     #     form.height() + | ||||
|     #     form.fill_bar.height() | ||||
|     #     # feed_label.height() | ||||
|     # ) | ||||
| 
 | ||||
|     feed_label.format(**feed.status) | ||||
| 
 | ||||
|     return feed_label | ||||
|  |  | |||
|  | @ -600,6 +600,7 @@ async def open_fsp_admin( | |||
|             kwargs=kwargs, | ||||
|         ) as (cache_hit, cluster_map), | ||||
| 
 | ||||
|         tractor.trionics.collapse_eg(), | ||||
|         trio.open_nursery() as tn, | ||||
|     ): | ||||
|         if cache_hit: | ||||
|  | @ -613,6 +614,8 @@ async def open_fsp_admin( | |||
|         ) | ||||
|         try: | ||||
|             yield admin | ||||
| 
 | ||||
|         # ??TODO, does this *need* to be inside a finally? | ||||
|         finally: | ||||
|             # terminate all tasks via signals | ||||
|             for key, entry in admin._registry.items(): | ||||
|  |  | |||
|  | @ -285,18 +285,20 @@ class FormatLabel(QLabel): | |||
|         font_size: int, | ||||
|         font_color: str, | ||||
| 
 | ||||
|         use_md: bool = True, | ||||
| 
 | ||||
|         parent=None, | ||||
| 
 | ||||
|     ) -> None: | ||||
| 
 | ||||
|         super().__init__(parent) | ||||
| 
 | ||||
|         # by default set the format string verbatim and expect user to | ||||
|         # call ``.format()`` later (presumably they'll notice the | ||||
|         # by default set the format string verbatim and expect user | ||||
|         # to call ``.format()`` later (presumably they'll notice the | ||||
|         # unformatted content if ``fmt_str`` isn't meant to be | ||||
|         # unformatted). | ||||
|         self.fmt_str = fmt_str | ||||
|         self.setText(fmt_str) | ||||
|         # self.setText(fmt_str)  # ?TODO, why here? | ||||
| 
 | ||||
|         self.setStyleSheet( | ||||
|             f"""QLabel {{ | ||||
|  | @ -306,6 +308,7 @@ class FormatLabel(QLabel): | |||
|             """ | ||||
|         ) | ||||
|         self.setFont(_font.font) | ||||
|         if use_md: | ||||
|             self.setTextFormat( | ||||
|                 Qt.TextFormat.MarkdownText | ||||
|             ) | ||||
|  | @ -316,7 +319,10 @@ class FormatLabel(QLabel): | |||
|             size_policy.Expanding, | ||||
|         ) | ||||
|         self.setAlignment( | ||||
|             Qt.AlignVCenter | Qt.AlignLeft | ||||
|             Qt.AlignLeft | ||||
|             | | ||||
|             Qt.AlignBottom | ||||
|             # Qt.AlignVCenter | ||||
|         ) | ||||
|         self.setText(self.fmt_str) | ||||
| 
 | ||||
|  |  | |||
|  | @ -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', | ||||
|  |  | |||
|  | @ -792,6 +792,7 @@ async def open_order_mode( | |||
|             brokerd_accounts, | ||||
|             ems_dialog_msgs, | ||||
|         ), | ||||
|         tractor.trionics.collapse_eg(), | ||||
|         trio.open_nursery() as tn, | ||||
| 
 | ||||
|     ): | ||||
|  |  | |||
|  | @ -23,7 +23,7 @@ name = "piker" | |||
| version = "0.1.0a0dev0" | ||||
| description = "trading gear for hackers" | ||||
| authors = [{ name = "Tyler Goodlet", email = "goodboy_foss@protonmail.com" }] | ||||
| requires-python = ">=3.12, <3.13" | ||||
| requires-python = ">=3.12" | ||||
| license = "AGPL-3.0-or-later" | ||||
| readme = "README.rst" | ||||
| keywords = [ | ||||
|  | @ -39,8 +39,8 @@ classifiers = [ | |||
|     "Operating System :: POSIX :: Linux", | ||||
|     "Programming Language :: Python :: Implementation :: CPython", | ||||
|     "Programming Language :: Python :: 3 :: Only", | ||||
|     "Programming Language :: Python :: 3.11", | ||||
|     "Programming Language :: Python :: 3.12", | ||||
|     "Programming Language :: Python :: 3.13", | ||||
|     "Intended Audience :: Financial and Insurance Industry", | ||||
|     "Intended Audience :: Science/Research", | ||||
|     "Intended Audience :: Developers", | ||||
|  | @ -49,13 +49,13 @@ classifiers = [ | |||
| dependencies = [ | ||||
|     "async-generator >=1.10, <2.0.0", | ||||
|     "attrs >=23.1.0, <24.0.0", | ||||
|     "bidict >=0.22.1, <0.23.0", | ||||
|     "bidict >=0.23.1", | ||||
|     "colorama >=0.4.6, <0.5.0", | ||||
|     "colorlog >=6.7.0, <7.0.0", | ||||
|     "ib-insync >=0.9.86, <0.10.0", | ||||
|     "numba >=0.59.0, <0.60.0", | ||||
|     "numpy >=1.25, <2.0", | ||||
|     "polars >=0.18.13, <0.19.0", | ||||
|     "numpy>=2.0", | ||||
|     "polars >=0.20.6", | ||||
|     "polars-fuzzy-match>=0.1.5", | ||||
|     "pygments >=2.16.1, <3.0.0", | ||||
|     "rich >=13.5.2, <14.0.0", | ||||
|     "tomli >=2.0.1, <3.0.0", | ||||
|  | @ -65,16 +65,18 @@ dependencies = [ | |||
|     "typer >=0.9.0, <1.0.0", | ||||
|     "rapidfuzz >=3.5.2, <4.0.0", | ||||
|     "pdbp >=1.5.0, <2.0.0", | ||||
|     "trio >=0.24, <0.25", | ||||
|     "trio >=0.27", | ||||
|     "pendulum >=3.0.0, <4.0.0", | ||||
|     "httpx >=0.27.0, <0.28.0", | ||||
|     "cryptofeed >=2.4.0, <3.0.0", | ||||
|     "pyarrow >=17.0.0, <18.0.0", | ||||
|     "pyarrow>=18.0.0", | ||||
|     "websockets ==12.0", | ||||
|     "msgspec", | ||||
|     "msgspec>=0.19.0,<0.20", | ||||
|     "tractor", | ||||
|     "asyncvnc", | ||||
|     "tomlkit", | ||||
|     "trio-typing>=0.10.0", | ||||
|     "numba>=0.61.0", | ||||
| ] | ||||
| 
 | ||||
| [project.optional-dependencies] | ||||
|  | @ -125,9 +127,18 @@ include = ["piker"] | |||
| [tool.hatch.build.targets.wheel] | ||||
| include = ["piker"] | ||||
| 
 | ||||
| 
 | ||||
| # TODO? move to a `uv.toml`? | ||||
| [tool.uv] | ||||
| python-preference = 'system' | ||||
| python-downloads = 'manual' | ||||
| 
 | ||||
| 
 | ||||
| [tool.uv.sources] | ||||
| pyqtgraph = { git = "https://github.com/pikers/pyqtgraph.git" } | ||||
| asyncvnc = { git = "https://github.com/pikers/asyncvnc.git", branch = "main" } | ||||
| tomlkit = { git = "https://github.com/pikers/tomlkit.git", branch ="piker_pin" } | ||||
| msgspec = { git = "https://github.com/jcrist/msgspec.git" } | ||||
| 
 | ||||
| # tractor = { git = "https://pikers.dev/goodboy/tractor", branch = "main" } | ||||
| # XXX, since i'm hacking 3.13 support atm.. | ||||
| tractor = { path = "../tractor", editable = true } | ||||
|  |  | |||
|  | @ -0,0 +1 @@ | |||
| TAG_feed_status_update	./piker/data/feed.py	/TAG_feed_status_update/ | ||||
		Loading…
	
		Reference in New Issue