Add per-actor `setproctitle` via `devx._proctitle`
New `tractor.devx._proctitle` mod sets each
sub-actor's `argv[0]` (and kernel `comm`) to
`tractor[<aid.reprol()>]` — e.g.
`tractor[doggy@1027301b]` — so `ps`/`top`/`htop`
and `acli.pytree`/reaper tooling can identify
actors at a glance without parsing full cmdlines.
Deats,
- `set_actor_proctitle()` wraps the `setproctitle`
pkg with `ImportError` guard; optional at runtime
but listed in `pyproject.toml` so default installs
benefit.
- called early in `_child._actor_child_main()` after
`Actor` construction, before `_trio_main()` entry.
- tests in `tests/devx/test_proctitle.py`: format
unit test, `/proc/{cmdline,comm}` integration
test, negative detection test.
Resolves #457
(this patch was generated in some part by [`claude-code`][claude-code-gh])
[claude-code-gh]: https://github.com/anthropics/claude-code
subint_forkserver_backend
parent
caebf60f4e
commit
d60245777e
|
|
@ -44,15 +44,20 @@ dependencies = [
|
|||
"tricycle>=0.4.1,<0.5",
|
||||
"wrapt>=1.16.0,<2",
|
||||
"colorlog>=6.8.2,<7",
|
||||
|
||||
# built-in multi-actor `pdb` REPL
|
||||
"pdbp>=1.8.2,<2", # windows only (from `pdbp`)
|
||||
|
||||
# typed IPC msging
|
||||
"msgspec>=0.20.0",
|
||||
"bidict>=0.23.1",
|
||||
"multiaddr>=0.2.0",
|
||||
"platformdirs>=4.4.0",
|
||||
# per-actor `argv[0]` proc-title for OS-level diag tools
|
||||
# (`ps`, `top`, `psutil`-backed tooling like `acli.pytree`).
|
||||
# Optional at runtime — guarded by `try/except ImportError` in
|
||||
# `tractor.devx._proctitle` — but listed here so default
|
||||
# installs benefit from it. See tracking issue for follow-ups
|
||||
# (e.g. richer formats, per-backend overrides).
|
||||
"setproctitle>=1.3,<2",
|
||||
]
|
||||
|
||||
# ------ project ------
|
||||
|
|
|
|||
|
|
@ -0,0 +1,170 @@
|
|||
'''
|
||||
Tests for `tractor.devx._proctitle` (per-actor `setproctitle`)
|
||||
and the intrinsic-signal sub-actor detection in
|
||||
`tractor._testing._reap`.
|
||||
|
||||
The proctitle is set in `tractor._child._actor_child_main()`
|
||||
after `Actor` construction, so any spawned sub-actor process
|
||||
should:
|
||||
|
||||
- have `argv[0]` (== `/proc/<pid>/cmdline`) start with
|
||||
`tractor[<aid.reprol()>]`
|
||||
- have `/proc/<pid>/comm` start with `tractor[` (kernel
|
||||
truncates to ~15 bytes)
|
||||
- be detected as a tractor sub-actor by
|
||||
`_is_tractor_subactor(pid)` via the cmdline marker.
|
||||
|
||||
`set_actor_proctitle()` itself is also unit-tested in-process
|
||||
to verify the format string.
|
||||
|
||||
'''
|
||||
from __future__ import annotations
|
||||
import platform
|
||||
|
||||
import psutil
|
||||
import pytest
|
||||
import trio
|
||||
import tractor
|
||||
|
||||
from tractor.runtime._runtime import Actor
|
||||
from tractor.devx._proctitle import set_actor_proctitle
|
||||
from tractor._testing._reap import (
|
||||
_is_tractor_subactor,
|
||||
_read_cmdline,
|
||||
_read_comm,
|
||||
)
|
||||
|
||||
|
||||
_non_linux: bool = platform.system() != 'Linux'
|
||||
|
||||
|
||||
def test_set_actor_proctitle_format():
|
||||
'''
|
||||
`set_actor_proctitle()` returns the canonical
|
||||
`tractor[<aid.reprol()>]` form and actually mutates
|
||||
the running proc's title.
|
||||
|
||||
'''
|
||||
pytest.importorskip(
|
||||
'setproctitle',
|
||||
reason='`setproctitle` is an optional runtime dep',
|
||||
)
|
||||
import setproctitle
|
||||
|
||||
# save + restore so we don't pollute pytest's own title
|
||||
saved: str = setproctitle.getproctitle()
|
||||
try:
|
||||
actor = Actor(
|
||||
name='unit_test_actor',
|
||||
uuid='1027301b-a0e3-430e-8806-a5279f21abe6',
|
||||
)
|
||||
title: str = set_actor_proctitle(actor)
|
||||
|
||||
# canonical wrapping: `tractor[<aid.reprol()>]`. We
|
||||
# compare against the runtime-computed `reprol()`
|
||||
# rather than a hard-coded value so the test stays
|
||||
# decoupled from `Aid.reprol()`'s internal format
|
||||
# (currently `<name>@<pid>`, but could evolve).
|
||||
expected: str = f'tractor[{actor.aid.reprol()}]'
|
||||
assert title == expected
|
||||
# sanity: the actor's name must be in the title
|
||||
# somewhere (so a future `reprol()` change that
|
||||
# drops the name is also caught).
|
||||
assert 'unit_test_actor' in title
|
||||
|
||||
# actually set on the running proc
|
||||
assert setproctitle.getproctitle() == title
|
||||
|
||||
finally:
|
||||
setproctitle.setproctitle(saved)
|
||||
|
||||
|
||||
@pytest.mark.skipif(
|
||||
_non_linux,
|
||||
reason=(
|
||||
'detection helpers read `/proc/<pid>/{cmdline,comm}` '
|
||||
'which is Linux-specific'
|
||||
),
|
||||
)
|
||||
def test_subactor_proctitle_visible_via_proc():
|
||||
'''
|
||||
Spawn a sub-actor and verify its proc-title is visible
|
||||
via both `/proc/<pid>/cmdline` AND `/proc/<pid>/comm`,
|
||||
AND that `_is_tractor_subactor()` correctly identifies
|
||||
it.
|
||||
|
||||
'''
|
||||
pytest.importorskip('setproctitle')
|
||||
|
||||
async def main() -> dict:
|
||||
async with tractor.open_nursery() as an:
|
||||
portal = await an.start_actor('proctitle_boi')
|
||||
# let the child finish setproctitle in
|
||||
# `_actor_child_main`
|
||||
await trio.sleep(0.3)
|
||||
|
||||
# the sub-actor's pid is on the portal's chan
|
||||
# repr; psutil-walk `me.children()` is simpler.
|
||||
me = psutil.Process()
|
||||
sub_pids: list[int] = [
|
||||
p.pid for p in me.children(recursive=True)
|
||||
]
|
||||
assert sub_pids, (
|
||||
'expected at least one spawned sub-actor pid'
|
||||
)
|
||||
|
||||
results: dict = {}
|
||||
for pid in sub_pids:
|
||||
results[pid] = {
|
||||
'cmdline': _read_cmdline(pid),
|
||||
'comm': _read_comm(pid),
|
||||
'is_tractor': _is_tractor_subactor(pid),
|
||||
}
|
||||
|
||||
await portal.cancel_actor()
|
||||
return results
|
||||
|
||||
found: dict = trio.run(main)
|
||||
|
||||
# at least one of the spawned procs should match the
|
||||
# `proctitle_boi` actor we started; assert the proc-
|
||||
# title shape on it specifically.
|
||||
matched: list[tuple[int, dict]] = [
|
||||
(pid, info)
|
||||
for pid, info in found.items()
|
||||
if 'proctitle_boi' in info['cmdline']
|
||||
]
|
||||
assert matched, (
|
||||
f'no sub-actor pid had a `proctitle_boi` cmdline; '
|
||||
f'all={found}'
|
||||
)
|
||||
|
||||
pid, info = matched[0]
|
||||
# canonical proctitle prefix in cmdline (full form)
|
||||
assert info['cmdline'].startswith('tractor[proctitle_boi@'), (
|
||||
f'cmdline missing `tractor[proctitle_boi@…]` prefix: '
|
||||
f'{info["cmdline"]!r}'
|
||||
)
|
||||
# comm is kernel-truncated to ~15 bytes — just check the
|
||||
# `tractor[` prefix made it.
|
||||
assert info['comm'].startswith('tractor['), (
|
||||
f'comm missing `tractor[` prefix: {info["comm"]!r}'
|
||||
)
|
||||
# intrinsic-signal detector should match.
|
||||
assert info['is_tractor'] is True
|
||||
|
||||
|
||||
@pytest.mark.skipif(
|
||||
_non_linux,
|
||||
reason='reads /proc/<pid>/{cmdline,comm}',
|
||||
)
|
||||
def test_is_tractor_subactor_negative():
|
||||
'''
|
||||
`_is_tractor_subactor()` returns False for non-tractor
|
||||
procs (e.g. the pytest test-runner pid itself, which
|
||||
is `python -m pytest …` — no `tractor[` proctitle, no
|
||||
`tractor._child` cmdline).
|
||||
|
||||
'''
|
||||
import os
|
||||
assert _is_tractor_subactor(os.getpid()) is False
|
||||
|
|
@ -77,6 +77,35 @@ def _actor_child_main(
|
|||
loglevel=loglevel,
|
||||
spawn_method=spawn_method,
|
||||
)
|
||||
|
||||
# XXX, set a stable OS-level proc-title BEFORE entering
|
||||
# the trio runtime so `ps`/`top`/`acli.pytree` and
|
||||
# orphan-reapers can identify this actor for its full
|
||||
# lifetime — e.g.
|
||||
# `tractor[doggy@1027301b]`
|
||||
# vs. the default uninformative
|
||||
# `python -m tractor._child --uid (...)`
|
||||
#
|
||||
# `setproctitle` mutates `argv[0]` (visible in
|
||||
# `/proc/<pid>/cmdline`) AND the kernel `comm`
|
||||
# (visible in `/proc/<pid>/comm`, kernel-truncated to
|
||||
# ~15 bytes, but preserved through zombie state). Both
|
||||
# surfaces are enough for `_testing._reap` /
|
||||
# `acli.reap` orphan- and zombie-detection to identify
|
||||
# tractor sub-actors via intrinsic signals — no cwd,
|
||||
# venv path, or env-var coincidence-of-implementation
|
||||
# matching needed.
|
||||
#
|
||||
# NB: an earlier draft also wrote `TRACTOR_AID` to
|
||||
# `os.environ` here for `pgrep --env`-style discovery,
|
||||
# but Linux snapshots `/proc/<pid>/environ` at exec/fork
|
||||
# time, so post-fork runtime mutations don't propagate
|
||||
# to the kernel-visible env. The proc-title path
|
||||
# provides equivalent ergonomics
|
||||
# (`pgrep -f 'tractor\['`) without that gotcha.
|
||||
from .devx._proctitle import set_actor_proctitle
|
||||
set_actor_proctitle(subactor)
|
||||
|
||||
_trio_main(
|
||||
subactor,
|
||||
parent_addr=parent_addr,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,74 @@
|
|||
# tractor: structured concurrent "actors".
|
||||
# Copyright 2018-eternity Tyler Goodlet.
|
||||
|
||||
# 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 <https://www.gnu.org/licenses/>.
|
||||
|
||||
'''
|
||||
Per-actor proc-title via `py-setproctitle`.
|
||||
|
||||
Sets a stable, OS-level identifier for each `tractor` actor
|
||||
process so diag tools (`ps`, `top`, `htop`, `psutil`) and our
|
||||
own `acli.pytree`/`acli.hung_dump` can show "which actor is
|
||||
which" at a glance without needing to read full
|
||||
`/proc/<pid>/cmdline`.
|
||||
|
||||
Format:
|
||||
``tractor[<aid.reprol()>]`` e.g. ``tractor[doggy@1027301b]``
|
||||
|
||||
Uses the canonical `Aid.reprol()` form
|
||||
(``<name>@<uuid_short>``) so the proc-title matches the
|
||||
identifier shape used in tractor's logs, the `TRACTOR_AID`
|
||||
env-var, and orphan-reaper scans — one identity across
|
||||
all surfaces.
|
||||
|
||||
Optional dep: silently no-op when `setproctitle` is missing.
|
||||
|
||||
'''
|
||||
from __future__ import annotations
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from tractor.runtime._runtime import Actor
|
||||
|
||||
|
||||
# `setproctitle` is an optional dep — tractor's runtime path
|
||||
# treats this as best-effort diag, so missing import is a
|
||||
# no-op rather than a hard error.
|
||||
try:
|
||||
import setproctitle as _stp
|
||||
except ImportError:
|
||||
_stp = None
|
||||
|
||||
|
||||
def set_actor_proctitle(actor: 'Actor') -> str | None:
|
||||
'''
|
||||
Set the calling process's proc-title to identify it as a
|
||||
tractor sub-actor.
|
||||
|
||||
Returns the title string set, or `None` if `setproctitle`
|
||||
isn't available.
|
||||
|
||||
Should be called early in the actor's process lifetime
|
||||
(after `Actor` construction, before `_trio_main`) so the
|
||||
new title is visible to OS-level tooling for the entire
|
||||
runtime.
|
||||
|
||||
'''
|
||||
if _stp is None:
|
||||
return None
|
||||
|
||||
title: str = f'tractor[{actor.aid.reprol()}]'
|
||||
_stp.setproctitle(title)
|
||||
return title
|
||||
50
uv.lock
50
uv.lock
|
|
@ -616,6 +616,54 @@ wheels = [
|
|||
{ url = "https://files.pythonhosted.org/packages/9e/6a/40fee331a52339926a92e17ae748827270b288a35ef4a15c9c8f2ec54715/ruff-0.14.14-py3-none-win_arm64.whl", hash = "sha256:56e6981a98b13a32236a72a8da421d7839221fa308b223b9283312312e5ac76c", size = 10920448, upload-time = "2026-01-22T22:30:15.417Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "setproctitle"
|
||||
version = "1.3.7"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/8d/48/49393a96a2eef1ab418b17475fb92b8fcfad83d099e678751b05472e69de/setproctitle-1.3.7.tar.gz", hash = "sha256:bc2bc917691c1537d5b9bca1468437176809c7e11e5694ca79a9ca12345dcb9e", size = 27002, upload-time = "2025-09-05T12:51:25.278Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/5d/2f/fcedcade3b307a391b6e17c774c6261a7166aed641aee00ed2aad96c63ce/setproctitle-1.3.7-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:c3736b2a423146b5e62230502e47e08e68282ff3b69bcfe08a322bee73407922", size = 18047, upload-time = "2025-09-05T12:49:50.271Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/23/ae/afc141ca9631350d0a80b8f287aac79a76f26b6af28fd8bf92dae70dc2c5/setproctitle-1.3.7-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:3384e682b158d569e85a51cfbde2afd1ab57ecf93ea6651fe198d0ba451196ee", size = 13073, upload-time = "2025-09-05T12:49:51.46Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/87/ed/0a4f00315bc02510395b95eec3d4aa77c07192ee79f0baae77ea7b9603d8/setproctitle-1.3.7-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:0564a936ea687cd24dffcea35903e2a20962aa6ac20e61dd3a207652401492dd", size = 33284, upload-time = "2025-09-05T12:49:52.741Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/fc/e4/adf3c4c0a2173cb7920dc9df710bcc67e9bcdbf377e243b7a962dc31a51a/setproctitle-1.3.7-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a5d1cb3f81531f0eb40e13246b679a1bdb58762b170303463cb06ecc296f26d0", size = 34104, upload-time = "2025-09-05T12:49:54.416Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/52/4f/6daf66394152756664257180439d37047aa9a1cfaa5e4f5ed35e93d1dc06/setproctitle-1.3.7-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a7d159e7345f343b44330cbba9194169b8590cb13dae940da47aa36a72aa9929", size = 35982, upload-time = "2025-09-05T12:49:56.295Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/1b/62/f2c0595403cf915db031f346b0e3b2c0096050e90e0be658a64f44f4278a/setproctitle-1.3.7-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0b5074649797fd07c72ca1f6bff0406f4a42e1194faac03ecaab765ce605866f", size = 33150, upload-time = "2025-09-05T12:49:58.025Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a0/29/10dd41cde849fb2f9b626c846b7ea30c99c81a18a5037a45cc4ba33c19a7/setproctitle-1.3.7-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:61e96febced3f61b766115381d97a21a6265a0f29188a791f6df7ed777aef698", size = 34463, upload-time = "2025-09-05T12:49:59.424Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/71/3c/cedd8eccfaf15fb73a2c20525b68c9477518917c9437737fa0fda91e378f/setproctitle-1.3.7-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:047138279f9463f06b858e579cc79580fbf7a04554d24e6bddf8fe5dddbe3d4c", size = 32848, upload-time = "2025-09-05T12:50:01.107Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d1/3e/0a0e27d1c9926fecccfd1f91796c244416c70bf6bca448d988638faea81d/setproctitle-1.3.7-cp313-cp313-win32.whl", hash = "sha256:7f47accafac7fe6535ba8ba9efd59df9d84a6214565108d0ebb1199119c9cbbd", size = 12544, upload-time = "2025-09-05T12:50:15.81Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/36/1b/6bf4cb7acbbd5c846ede1c3f4d6b4ee52744d402e43546826da065ff2ab7/setproctitle-1.3.7-cp313-cp313-win_amd64.whl", hash = "sha256:fe5ca35aeec6dc50cabab9bf2d12fbc9067eede7ff4fe92b8f5b99d92e21263f", size = 13235, upload-time = "2025-09-05T12:50:16.89Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/e6/a4/d588d3497d4714750e3eaf269e9e8985449203d82b16b933c39bd3fc52a1/setproctitle-1.3.7-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:10e92915c4b3086b1586933a36faf4f92f903c5554f3c34102d18c7d3f5378e9", size = 18058, upload-time = "2025-09-05T12:50:02.501Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/05/77/7637f7682322a7244e07c373881c7e982567e2cb1dd2f31bd31481e45500/setproctitle-1.3.7-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:de879e9c2eab637f34b1a14c4da1e030c12658cdc69ee1b3e5be81b380163ce5", size = 13072, upload-time = "2025-09-05T12:50:03.601Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/52/09/f366eca0973cfbac1470068d1313fa3fe3de4a594683385204ec7f1c4101/setproctitle-1.3.7-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:c18246d88e227a5b16248687514f95642505000442165f4b7db354d39d0e4c29", size = 34490, upload-time = "2025-09-05T12:50:04.948Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/71/36/611fc2ed149fdea17c3677e1d0df30d8186eef9562acc248682b91312706/setproctitle-1.3.7-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7081f193dab22df2c36f9fc6d113f3793f83c27891af8fe30c64d89d9a37e152", size = 35267, upload-time = "2025-09-05T12:50:06.015Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/88/a4/64e77d0671446bd5a5554387b69e1efd915274686844bea733714c828813/setproctitle-1.3.7-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:9cc9b901ce129350637426a89cfd650066a4adc6899e47822e2478a74023ff7c", size = 37376, upload-time = "2025-09-05T12:50:07.484Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/89/bc/ad9c664fe524fb4a4b2d3663661a5c63453ce851736171e454fa2cdec35c/setproctitle-1.3.7-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:80e177eff2d1ec172188d0d7fd9694f8e43d3aab76a6f5f929bee7bf7894e98b", size = 33963, upload-time = "2025-09-05T12:50:09.056Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ab/01/a36de7caf2d90c4c28678da1466b47495cbbad43badb4e982d8db8167ed4/setproctitle-1.3.7-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:23e520776c445478a67ee71b2a3c1ffdafbe1f9f677239e03d7e2cc635954e18", size = 35550, upload-time = "2025-09-05T12:50:10.791Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/dd/68/17e8aea0ed5ebc17fbf03ed2562bfab277c280e3625850c38d92a7b5fcd9/setproctitle-1.3.7-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:5fa1953126a3b9bd47049d58c51b9dac72e78ed120459bd3aceb1bacee72357c", size = 33727, upload-time = "2025-09-05T12:50:12.032Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b2/33/90a3bf43fe3a2242b4618aa799c672270250b5780667898f30663fd94993/setproctitle-1.3.7-cp313-cp313t-win32.whl", hash = "sha256:4a5e212bf438a4dbeece763f4962ad472c6008ff6702e230b4f16a037e2f6f29", size = 12549, upload-time = "2025-09-05T12:50:13.074Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/0b/0e/50d1f07f3032e1f23d814ad6462bc0a138f369967c72494286b8a5228e40/setproctitle-1.3.7-cp313-cp313t-win_amd64.whl", hash = "sha256:cf2727b733e90b4f874bac53e3092aa0413fe1ea6d4f153f01207e6ce65034d9", size = 13243, upload-time = "2025-09-05T12:50:14.146Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/89/c7/43ac3a98414f91d1b86a276bc2f799ad0b4b010e08497a95750d5bc42803/setproctitle-1.3.7-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:80c36c6a87ff72eabf621d0c79b66f3bdd0ecc79e873c1e9f0651ee8bf215c63", size = 18052, upload-time = "2025-09-05T12:50:17.928Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/cd/2c/dc258600a25e1a1f04948073826bebc55e18dbd99dc65a576277a82146fa/setproctitle-1.3.7-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:b53602371a52b91c80aaf578b5ada29d311d12b8a69c0c17fbc35b76a1fd4f2e", size = 13071, upload-time = "2025-09-05T12:50:19.061Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ab/26/8e3bb082992f19823d831f3d62a89409deb6092e72fc6940962983ffc94f/setproctitle-1.3.7-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:fcb966a6c57cf07cc9448321a08f3be6b11b7635be502669bc1d8745115d7e7f", size = 33180, upload-time = "2025-09-05T12:50:20.395Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f1/af/ae692a20276d1159dd0cf77b0bcf92cbb954b965655eb4a69672099bb214/setproctitle-1.3.7-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:46178672599b940368d769474fe13ecef1b587d58bb438ea72b9987f74c56ea5", size = 34043, upload-time = "2025-09-05T12:50:22.454Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/34/b2/6a092076324dd4dac1a6d38482bedebbff5cf34ef29f58585ec76e47bc9d/setproctitle-1.3.7-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:7f9e9e3ff135cbcc3edd2f4cf29b139f4aca040d931573102742db70ff428c17", size = 35892, upload-time = "2025-09-05T12:50:23.937Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/1c/1a/8836b9f28cee32859ac36c3df85aa03e1ff4598d23ea17ca2e96b5845a8f/setproctitle-1.3.7-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:14c7eba8d90c93b0e79c01f0bd92a37b61983c27d6d7d5a3b5defd599113d60e", size = 32898, upload-time = "2025-09-05T12:50:25.617Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ef/22/8fabdc24baf42defb599714799d8445fe3ae987ec425a26ec8e80ea38f8e/setproctitle-1.3.7-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:9e64e98077fb30b6cf98073d6c439cd91deb8ebbf8fc62d9dbf52bd38b0c6ac0", size = 34308, upload-time = "2025-09-05T12:50:26.827Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/15/1b/b9bee9de6c8cdcb3b3a6cb0b3e773afdb86bbbc1665a3bfa424a4294fda2/setproctitle-1.3.7-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:b91387cc0f02a00ac95dcd93f066242d3cca10ff9e6153de7ee07069c6f0f7c8", size = 32536, upload-time = "2025-09-05T12:50:28.5Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/37/0c/75e5f2685a5e3eda0b39a8b158d6d8895d6daf3ba86dec9e3ba021510272/setproctitle-1.3.7-cp314-cp314-win32.whl", hash = "sha256:52b054a61c99d1b72fba58b7f5486e04b20fefc6961cd76722b424c187f362ed", size = 12731, upload-time = "2025-09-05T12:50:43.955Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d2/ae/acddbce90d1361e1786e1fb421bc25baeb0c22ef244ee5d0176511769ec8/setproctitle-1.3.7-cp314-cp314-win_amd64.whl", hash = "sha256:5818e4080ac04da1851b3ec71e8a0f64e3748bf9849045180566d8b736702416", size = 13464, upload-time = "2025-09-05T12:50:45.057Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/01/6d/20886c8ff2e6d85e3cabadab6aab9bb90acaf1a5cfcb04d633f8d61b2626/setproctitle-1.3.7-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:6fc87caf9e323ac426910306c3e5d3205cd9f8dcac06d233fcafe9337f0928a3", size = 18062, upload-time = "2025-09-05T12:50:29.78Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/9a/60/26dfc5f198715f1343b95c2f7a1c16ae9ffa45bd89ffd45a60ed258d24ea/setproctitle-1.3.7-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:6134c63853d87a4897ba7d5cc0e16abfa687f6c66fc09f262bb70d67718f2309", size = 13075, upload-time = "2025-09-05T12:50:31.604Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/21/9c/980b01f50d51345dd513047e3ba9e96468134b9181319093e61db1c47188/setproctitle-1.3.7-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:1403d2abfd32790b6369916e2313dffbe87d6b11dca5bbd898981bcde48e7a2b", size = 34744, upload-time = "2025-09-05T12:50:32.777Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/86/b4/82cd0c86e6d1c4538e1a7eb908c7517721513b801dff4ba3f98ef816a240/setproctitle-1.3.7-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e7c5bfe4228ea22373e3025965d1a4116097e555ee3436044f5c954a5e63ac45", size = 35589, upload-time = "2025-09-05T12:50:34.13Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/8a/4f/9f6b2a7417fd45673037554021c888b31247f7594ff4bd2239918c5cd6d0/setproctitle-1.3.7-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:585edf25e54e21a94ccb0fe81ad32b9196b69ebc4fc25f81da81fb8a50cca9e4", size = 37698, upload-time = "2025-09-05T12:50:35.524Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/20/92/927b7d4744aac214d149c892cb5fa6dc6f49cfa040cb2b0a844acd63dcaf/setproctitle-1.3.7-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:96c38cdeef9036eb2724c2210e8d0b93224e709af68c435d46a4733a3675fee1", size = 34201, upload-time = "2025-09-05T12:50:36.697Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/0a/0c/fd4901db5ba4b9d9013e62f61d9c18d52290497f956745cd3e91b0d80f90/setproctitle-1.3.7-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:45e3ef48350abb49cf937d0a8ba15e42cee1e5ae13ca41a77c66d1abc27a5070", size = 35801, upload-time = "2025-09-05T12:50:38.314Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/e7/e3/54b496ac724e60e61cc3447f02690105901ca6d90da0377dffe49ff99fc7/setproctitle-1.3.7-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:1fae595d032b30dab4d659bece20debd202229fce12b55abab978b7f30783d73", size = 33958, upload-time = "2025-09-05T12:50:39.841Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ea/a8/c84bb045ebf8c6fdc7f7532319e86f8380d14bbd3084e6348df56bdfe6fd/setproctitle-1.3.7-cp314-cp314t-win32.whl", hash = "sha256:02432f26f5d1329ab22279ff863c83589894977063f59e6c4b4845804a08f8c2", size = 12745, upload-time = "2025-09-05T12:50:41.377Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/08/b6/3a5a4f9952972791a9114ac01dfc123f0df79903577a3e0a7a404a695586/setproctitle-1.3.7-cp314-cp314t-win_amd64.whl", hash = "sha256:cbc388e3d86da1f766d8fc2e12682e446064c01cea9f88a88647cfe7c011de6a", size = 13469, upload-time = "2025-09-05T12:50:42.67Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "six"
|
||||
version = "1.17.0"
|
||||
|
|
@ -675,6 +723,7 @@ dependencies = [
|
|||
{ name = "multiaddr" },
|
||||
{ name = "pdbp" },
|
||||
{ name = "platformdirs" },
|
||||
{ name = "setproctitle" },
|
||||
{ name = "tricycle" },
|
||||
{ name = "trio" },
|
||||
{ name = "wrapt" },
|
||||
|
|
@ -730,6 +779,7 @@ requires-dist = [
|
|||
{ name = "multiaddr", specifier = ">=0.2.0" },
|
||||
{ name = "pdbp", specifier = ">=1.8.2,<2" },
|
||||
{ name = "platformdirs", specifier = ">=4.4.0" },
|
||||
{ name = "setproctitle", specifier = ">=1.3,<2" },
|
||||
{ name = "tricycle", specifier = ">=0.4.1,<0.5" },
|
||||
{ name = "trio", specifier = ">0.27" },
|
||||
{ name = "wrapt", specifier = ">=1.16.0,<2" },
|
||||
|
|
|
|||
Loading…
Reference in New Issue