Compare commits
4 Commits
451e0acf8a
...
02022d6487
| Author | SHA1 | Date |
|---|---|---|
|
|
02022d6487 | |
|
|
9a6229453d | |
|
|
16f92a0c75 | |
|
|
13c56e9c72 |
|
|
@ -1,83 +0,0 @@
|
||||||
---
|
|
||||||
model: claude-fable-5
|
|
||||||
service: claude
|
|
||||||
session: b6b42e23-0454-4d9b-be1c-0a89d65aed1b
|
|
||||||
timestamp: 2026-07-02T15:56:26Z
|
|
||||||
git_ref: 65bf9df5
|
|
||||||
scope: code
|
|
||||||
substantive: true
|
|
||||||
raw_file: 20260702T155626Z_65bf9df5_prompt_io.raw.md
|
|
||||||
---
|
|
||||||
|
|
||||||
## Prompt
|
|
||||||
|
|
||||||
From `ai/prompt-io/prompts/issue_470.md`:
|
|
||||||
|
|
||||||
> attempt to resolve
|
|
||||||
> https://github.com/goodboy/tractor/issues/470
|
|
||||||
> do it with /open-wkt, ensure you /run-tests on all
|
|
||||||
> changes
|
|
||||||
|
|
||||||
(plus a hard pause-for-human-review deadline of
|
|
||||||
12:50PM EST.)
|
|
||||||
|
|
||||||
Issue #470 asks to trim the ~0.42s `import tractor`
|
|
||||||
cost — which dominates per-actor spawn latency on the
|
|
||||||
`trio` backend — by lazy-importing heavy/optional deps
|
|
||||||
(`pdbp`, `stackscope`, `multiaddr`, + audit of
|
|
||||||
`colorlog`/`bidict`/`wrapt`/`setproctitle`).
|
|
||||||
|
|
||||||
## Response summary
|
|
||||||
|
|
||||||
Profiling showed the issue's dep-list only accounted
|
|
||||||
for ~20ms; the dominant cost (~244ms) was
|
|
||||||
`log.get_logger()`'s `get_caller_mod()` calling
|
|
||||||
`inspect.stack()` at module level in ~39 modules —
|
|
||||||
each call walks every stack frame (deep during nested
|
|
||||||
imports) and scans `sys.modules` per frame via
|
|
||||||
`inspect.getmodule()`.
|
|
||||||
|
|
||||||
Changes, in impact order:
|
|
||||||
|
|
||||||
1. `get_caller_mod()` -> `sys._getframe()` +
|
|
||||||
`f_globals['__name__']` `sys.modules` lookup
|
|
||||||
(~240ms saved).
|
|
||||||
2. Issue's lazy-import checklist: `bidict`,
|
|
||||||
`multiaddr`, `colorlog`, `wrapt` moved to
|
|
||||||
`TYPE_CHECKING`/function-local imports;
|
|
||||||
`platformdirs` function-local; `asyncio` +
|
|
||||||
`.to_asyncio` deferred out of the `devx.debug` +
|
|
||||||
`spawn._entry` eager paths (~15ms saved).
|
|
||||||
3. PEP 562 `__getattr__` on `tractor/__init__.py`
|
|
||||||
preserving public `tractor.to_asyncio` attr access.
|
|
||||||
|
|
||||||
Results: `import tractor` 0.42s -> ~0.145s (~65%);
|
|
||||||
sequential `start_actor` latency 0.40-0.44s ->
|
|
||||||
~0.179s/actor. `pdbp` (needs `_repl.py` class-base
|
|
||||||
restructure) + `platformdirs` (needs
|
|
||||||
`UDSAddress.def_bindspace` protocol rework) documented
|
|
||||||
as follow-ups.
|
|
||||||
|
|
||||||
## Files changed
|
|
||||||
|
|
||||||
- `tractor/log.py` — `get_caller_mod()` perf fix +
|
|
||||||
lazy `colorlog`
|
|
||||||
- `tractor/__init__.py` — PEP 562 lazy `to_asyncio`
|
|
||||||
- `tractor/discovery/_addr.py` — `bidict` ->
|
|
||||||
`TYPE_CHECKING`
|
|
||||||
- `tractor/discovery/_multiaddr.py` — lazy `multiaddr`
|
|
||||||
- `tractor/ipc/_tcp.py`, `tractor/ipc/_uds.py` —
|
|
||||||
`Multiaddr` -> `TYPE_CHECKING`
|
|
||||||
- `tractor/runtime/_state.py` — lazy `platformdirs`
|
|
||||||
- `tractor/devx/_frame_stack.py` — lazy `pdbp` +
|
|
||||||
`wrapt`
|
|
||||||
- `tractor/devx/debug/_trace.py`,
|
|
||||||
`tractor/devx/debug/_tty_lock.py` — lazy `asyncio` +
|
|
||||||
`.to_asyncio`
|
|
||||||
- `tractor/spawn/_entry.py` — lazy
|
|
||||||
`run_as_asyncio_guest`
|
|
||||||
|
|
||||||
## Human edits
|
|
||||||
|
|
||||||
None yet — pending user review at the 12:50PM EST
|
|
||||||
pause gate (test-suite results reported in-session).
|
|
||||||
|
|
@ -1,122 +0,0 @@
|
||||||
---
|
|
||||||
model: claude-fable-5
|
|
||||||
service: claude
|
|
||||||
timestamp: 2026-07-02T15:56:26Z
|
|
||||||
git_ref: 65bf9df5
|
|
||||||
diff_cmd: git diff main..wkt/boot_latency_470
|
|
||||||
---
|
|
||||||
|
|
||||||
# Raw AI output — gh #470 `import tractor` latency trim
|
|
||||||
|
|
||||||
All generated code is committed on the
|
|
||||||
`wkt/boot_latency_470` branch; per diff-ref mode each
|
|
||||||
file's content is referenced via its diff instead of
|
|
||||||
copied verbatim.
|
|
||||||
|
|
||||||
## Profiling findings (verbatim analysis output)
|
|
||||||
|
|
||||||
Baseline: `import tractor` ~0.39-0.42s wall.
|
|
||||||
|
|
||||||
`python -X importtime` + `cProfile` traced the cost NOT
|
|
||||||
primarily to third-party deps (the issue's hypothesis)
|
|
||||||
but to `tractor/log.py:get_logger()` calling
|
|
||||||
`get_caller_mod()` -> `inspect.stack()` at module level
|
|
||||||
in ~39 tractor modules:
|
|
||||||
|
|
||||||
- `inspect.stack()` builds `FrameInfo` (incl. src-file
|
|
||||||
and line-context resolution) for EVERY frame on the
|
|
||||||
stack; during nested imports the stack is dozens of
|
|
||||||
importlib frames deep.
|
|
||||||
- each `FrameInfo` resolution calls
|
|
||||||
`inspect.getmodule()` which scans all of
|
|
||||||
`sys.modules` per frame (1.4M `ismodule()` calls in
|
|
||||||
one profiled import).
|
|
||||||
- aggregate: ~244ms of tractor-own module "self" time
|
|
||||||
vs ~20ms for ALL the issue-listed third-party deps
|
|
||||||
(`pdbp` ~10ms, `bidict` ~4.5ms, `multiaddr` ~3.5ms,
|
|
||||||
`wrapt`/`colorlog` ~1ms each); `trio` itself is
|
|
||||||
~70-100ms and unavoidable.
|
|
||||||
|
|
||||||
## Generated changes
|
|
||||||
|
|
||||||
> `git diff main..wkt/boot_latency_470 -- tractor/log.py`
|
|
||||||
|
|
||||||
`get_caller_mod()` rewritten from `inspect.stack()` +
|
|
||||||
`inspect.getmodule()` to `sys._getframe(frames_up)` +
|
|
||||||
`frame.f_globals['__name__']` -> `sys.modules` lookup
|
|
||||||
(O(1) vs O(stack x sys.modules)). Unused `inspect`
|
|
||||||
imports dropped; `FrameType` imported from `types`.
|
|
||||||
Also `colorlog` lazy-imported inside
|
|
||||||
`get_console_log()`.
|
|
||||||
|
|
||||||
> `git diff main..wkt/boot_latency_470 -- tractor/discovery/_addr.py`
|
|
||||||
|
|
||||||
`bidict` import moved under `TYPE_CHECKING`
|
|
||||||
(annotation-only use; `_address_types` is a plain dict
|
|
||||||
literal).
|
|
||||||
|
|
||||||
> `git diff main..wkt/boot_latency_470 -- tractor/discovery/_multiaddr.py`
|
|
||||||
|
|
||||||
`from __future__ import annotations` added; `multiaddr`
|
|
||||||
import moved under `TYPE_CHECKING` + function-local
|
|
||||||
imports in `mk_maddr()`/`parse_maddr()`.
|
|
||||||
|
|
||||||
> `git diff main..wkt/boot_latency_470 -- tractor/ipc/_tcp.py tractor/ipc/_uds.py`
|
|
||||||
|
|
||||||
`Multiaddr` imports moved under `TYPE_CHECKING`
|
|
||||||
(annotation-only in both transports).
|
|
||||||
|
|
||||||
> `git diff main..wkt/boot_latency_470 -- tractor/runtime/_state.py`
|
|
||||||
|
|
||||||
`platformdirs` lazy-imported inside `get_rt_dir()`
|
|
||||||
(NOTE: still imported eagerly via
|
|
||||||
`UDSAddress.def_bindspace` class-var eval; see
|
|
||||||
follow-ups).
|
|
||||||
|
|
||||||
> `git diff main..wkt/boot_latency_470 -- tractor/devx/_frame_stack.py`
|
|
||||||
|
|
||||||
`pdbp` + `wrapt` lazy-imported inside
|
|
||||||
`hide_runtime_frames()` / `api_frame()` respectively.
|
|
||||||
|
|
||||||
> `git diff main..wkt/boot_latency_470 -- tractor/devx/debug/_trace.py tractor/devx/debug/_tty_lock.py`
|
|
||||||
|
|
||||||
`asyncio` moved to `TYPE_CHECKING` + call-site local
|
|
||||||
imports (`asyncio.current_task()` sites);
|
|
||||||
`tractor.to_asyncio.run_trio_task_in_future` imports
|
|
||||||
moved into the infected-aio runtime branches.
|
|
||||||
|
|
||||||
> `git diff main..wkt/boot_latency_470 -- tractor/spawn/_entry.py`
|
|
||||||
|
|
||||||
`run_as_asyncio_guest` import moved into the
|
|
||||||
`infect_asyncio=True` branches of `_mp_main()` /
|
|
||||||
`_trio_main()`.
|
|
||||||
|
|
||||||
> `git diff main..wkt/boot_latency_470 -- tractor/__init__.py`
|
|
||||||
|
|
||||||
PEP 562 module `__getattr__` added so
|
|
||||||
`tractor.to_asyncio` attr-access still works (required
|
|
||||||
by `tests/test_child_manages_service_nursery.py` and
|
|
||||||
any downstream user) while keeping `asyncio` off the
|
|
||||||
eager import path.
|
|
||||||
|
|
||||||
## Measured results (verbatim)
|
|
||||||
|
|
||||||
- `import tractor`: 0.39-0.42s -> ~0.145s (~65% cut)
|
|
||||||
- `start_actor` spawn+boot+reg+cancel: ~0.40-0.44s ->
|
|
||||||
~0.179s/actor (n=5 sequential, warm parent)
|
|
||||||
- post-change eager-module check: only `pdbp` +
|
|
||||||
`platformdirs` of the issue's list remain eager.
|
|
||||||
|
|
||||||
## Known follow-ups (not implemented, deadline-bound)
|
|
||||||
|
|
||||||
- `pdbp` (~10ms): still eager via
|
|
||||||
`devx/debug/_repl.py` class bases
|
|
||||||
(`class PdbREPL(pdbp.Pdb)`) + `_tty_lock.py`
|
|
||||||
module-level `@pdbp.hideframe`; needs `_repl`
|
|
||||||
restructure + PEP 562 in `devx.debug.__init__`.
|
|
||||||
- `platformdirs` (~1.5ms): eager via
|
|
||||||
`UDSAddress.def_bindspace: ClassVar = get_rt_dir()`
|
|
||||||
class-body call; needs `Address`-protocol rework of
|
|
||||||
`def_bindspace` to a lazy accessor.
|
|
||||||
- `stackscope` + `setproctitle`: already lazy/absent —
|
|
||||||
no change needed.
|
|
||||||
|
|
@ -23,10 +23,18 @@ async def endpoint(
|
||||||
await trio.sleep_forever()
|
await trio.sleep_forever()
|
||||||
|
|
||||||
|
|
||||||
async def open_ep(
|
async def spawn_and_open_ep(
|
||||||
ptl: tractor.Portal,
|
an: tractor.ActorNursery,
|
||||||
i: int,
|
i: int,
|
||||||
) -> None:
|
) -> None:
|
||||||
|
'''
|
||||||
|
Spawn a subactor, start a remote `endpoint()`-task in it.
|
||||||
|
|
||||||
|
'''
|
||||||
|
ptl: tractor.Portal = await an.start_actor(
|
||||||
|
name=f'worker_{i}',
|
||||||
|
enable_modules=[__name__],
|
||||||
|
)
|
||||||
ctx: tractor.Context
|
ctx: tractor.Context
|
||||||
async with ptl.open_context(endpoint) as (
|
async with ptl.open_context(endpoint) as (
|
||||||
ctx,
|
ctx,
|
||||||
|
|
@ -39,33 +47,7 @@ async def open_ep(
|
||||||
await ctx.wait_for_result()
|
await ctx.wait_for_result()
|
||||||
|
|
||||||
|
|
||||||
async def spawn_and_open_ep(
|
async def main():
|
||||||
an: tractor.ActorNursery,
|
|
||||||
i: int,
|
|
||||||
maybe_ptl: tractor.Portal|None = None,
|
|
||||||
) -> None:
|
|
||||||
'''
|
|
||||||
Spawn a subactor, start a remote `endpoint()`-task in it.
|
|
||||||
|
|
||||||
'''
|
|
||||||
if maybe_ptl is None:
|
|
||||||
maybe_ptl: tractor.Portal = await an.start_actor(
|
|
||||||
name=f'worker_{i}',
|
|
||||||
enable_modules=[__name__],
|
|
||||||
)
|
|
||||||
await open_ep(
|
|
||||||
ptl=maybe_ptl,
|
|
||||||
i=i,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
async def main(
|
|
||||||
# spawn subs concurrently (in bg `trio.Task`s) so each
|
|
||||||
# actor's cold `import tractor` (~0.4s, see #470) overlaps
|
|
||||||
# instead of stacking; once forkserver (#463) lands, spawn
|
|
||||||
# is cheap enough to just loop sequentially.
|
|
||||||
spawn_subs_in_bg_tasks: bool = True,
|
|
||||||
):
|
|
||||||
'''
|
'''
|
||||||
Spawn a subactor-per-CPU then self-destruct the cluster.
|
Spawn a subactor-per-CPU then self-destruct the cluster.
|
||||||
|
|
||||||
|
|
@ -78,21 +60,17 @@ async def main(
|
||||||
# https://github.com/goodboy/tractor/pull/463
|
# https://github.com/goodboy/tractor/pull/463
|
||||||
# start_method='main_thread_forkserver',
|
# start_method='main_thread_forkserver',
|
||||||
) as an,
|
) as an,
|
||||||
|
# spawn subs concurrently (in bg `trio.Task`s) so each
|
||||||
|
# actor's cold `import tractor` (~0.4s, see #470) overlaps
|
||||||
|
# instead of stacking; once forkserver (#463) lands, spawn
|
||||||
|
# is cheap enough to just loop sequentially.
|
||||||
trio.open_nursery() as tn,
|
trio.open_nursery() as tn,
|
||||||
):
|
):
|
||||||
for i in range(cpu_count()):
|
for i in range(cpu_count()):
|
||||||
|
|
||||||
maybe_ptl: tractor.Portal|None = None
|
|
||||||
if not spawn_subs_in_bg_tasks:
|
|
||||||
maybe_ptl: tractor.Portal = await an.start_actor(
|
|
||||||
name=f'worker_{i}',
|
|
||||||
enable_modules=[__name__],
|
|
||||||
)
|
|
||||||
tn.start_soon(
|
tn.start_soon(
|
||||||
spawn_and_open_ep,
|
spawn_and_open_ep,
|
||||||
an,
|
an,
|
||||||
i,
|
i,
|
||||||
maybe_ptl,
|
|
||||||
)
|
)
|
||||||
destruct_in: int = 2
|
destruct_in: int = 2
|
||||||
print(
|
print(
|
||||||
|
|
|
||||||
|
|
@ -1,160 +0,0 @@
|
||||||
'''
|
|
||||||
Regression tests for the cold package import surface.
|
|
||||||
|
|
||||||
'''
|
|
||||||
import json
|
|
||||||
import os
|
|
||||||
from statistics import median
|
|
||||||
import subprocess
|
|
||||||
import sys
|
|
||||||
from typing import (
|
|
||||||
Any,
|
|
||||||
get_type_hints,
|
|
||||||
)
|
|
||||||
|
|
||||||
from tractor.discovery import (
|
|
||||||
_addr,
|
|
||||||
_multiaddr,
|
|
||||||
)
|
|
||||||
from tractor.ipc import (
|
|
||||||
_tcp,
|
|
||||||
_uds,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def run_cold_import(code: str) -> dict[str, object]:
|
|
||||||
result = subprocess.run(
|
|
||||||
[
|
|
||||||
sys.executable,
|
|
||||||
'-c',
|
|
||||||
code,
|
|
||||||
],
|
|
||||||
check=True,
|
|
||||||
capture_output=True,
|
|
||||||
text=True,
|
|
||||||
)
|
|
||||||
return json.loads(result.stdout)
|
|
||||||
|
|
||||||
|
|
||||||
def test_lazy_to_asyncio_package_api():
|
|
||||||
'''
|
|
||||||
Keep the public lazy submodule discoverable without eagerly
|
|
||||||
importing it.
|
|
||||||
|
|
||||||
Before the lazy conversion, package import side effects exposed
|
|
||||||
`to_asyncio` to `dir()` and wildcard imports. Exercise those APIs
|
|
||||||
in cold interpreters so this test proves normal `import tractor`
|
|
||||||
leaves `asyncio` unloaded, while discovery and wildcard access
|
|
||||||
still advertise and resolve the public submodule.
|
|
||||||
|
|
||||||
'''
|
|
||||||
cold = run_cold_import(
|
|
||||||
'import json, sys, tractor; '
|
|
||||||
'print(json.dumps({'
|
|
||||||
'"advertised": "to_asyncio" in dir(tractor), '
|
|
||||||
'"asyncio_loaded": "asyncio" in sys.modules}))'
|
|
||||||
)
|
|
||||||
assert cold == {
|
|
||||||
'advertised': True,
|
|
||||||
'asyncio_loaded': False,
|
|
||||||
}
|
|
||||||
|
|
||||||
wildcard = run_cold_import(
|
|
||||||
'import json; '
|
|
||||||
'from tractor import *; '
|
|
||||||
'print(json.dumps({'
|
|
||||||
'"module": to_asyncio.__name__}))'
|
|
||||||
)
|
|
||||||
assert wildcard == {
|
|
||||||
'module': 'tractor.to_asyncio',
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def test_cold_import_budget():
|
|
||||||
'''
|
|
||||||
Keep cold package import below the pre-optimization regression.
|
|
||||||
|
|
||||||
The original `inspect.stack()` caller lookup made a fresh
|
|
||||||
`import tractor` take about 0.42s and dominate actor startup.
|
|
||||||
Run seven independent interpreters and gate their median at a
|
|
||||||
deliberately broad 0.35s: over twice the measured ~0.145s
|
|
||||||
baseline, but low enough to catch restoration of that hot path.
|
|
||||||
|
|
||||||
Taking the median absorbs process-start and shared-runner noise.
|
|
||||||
The child measures only its import, rather than parent-side
|
|
||||||
process creation. `TRACTOR_IMPORT_BUDGET_S` provides an explicit,
|
|
||||||
reviewable override for platforms that establish a different
|
|
||||||
baseline instead of silently weakening the project default.
|
|
||||||
|
|
||||||
Each child also reports the modules whose eager loading this PR
|
|
||||||
intentionally removes, proving a timing pass cannot hide a
|
|
||||||
dependency-import regression.
|
|
||||||
|
|
||||||
'''
|
|
||||||
budget_s = float(
|
|
||||||
os.environ.get(
|
|
||||||
'TRACTOR_IMPORT_BUDGET_S',
|
|
||||||
'0.35',
|
|
||||||
)
|
|
||||||
)
|
|
||||||
optional_mods = (
|
|
||||||
'asyncio',
|
|
||||||
'bidict',
|
|
||||||
'colorlog',
|
|
||||||
'multiaddr',
|
|
||||||
'wrapt',
|
|
||||||
)
|
|
||||||
code = (
|
|
||||||
'import json, sys, time; '
|
|
||||||
'started = time.perf_counter(); '
|
|
||||||
'import tractor; '
|
|
||||||
'elapsed = time.perf_counter() - started; '
|
|
||||||
f'optional = {optional_mods!r}; '
|
|
||||||
'print(json.dumps({'
|
|
||||||
'"elapsed": elapsed, '
|
|
||||||
'"loaded": [name for name in optional '
|
|
||||||
'if name in sys.modules]}))'
|
|
||||||
)
|
|
||||||
samples = [
|
|
||||||
run_cold_import(code)
|
|
||||||
for _ in range(7)
|
|
||||||
]
|
|
||||||
elapsed = [
|
|
||||||
float(sample['elapsed'])
|
|
||||||
for sample in samples
|
|
||||||
]
|
|
||||||
loaded = {
|
|
||||||
name
|
|
||||||
for sample in samples
|
|
||||||
for name in sample['loaded']
|
|
||||||
}
|
|
||||||
|
|
||||||
assert not loaded
|
|
||||||
assert median(elapsed) < budget_s, (
|
|
||||||
f'cold import median exceeded {budget_s:.3f}s budget: '
|
|
||||||
f'{elapsed!r}'
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def test_lazy_annotation_names_resolve():
|
|
||||||
'''
|
|
||||||
Resolve annotations without importing optional dependencies.
|
|
||||||
|
|
||||||
Moving annotation-only third-party names under `TYPE_CHECKING`
|
|
||||||
left their runtime globals undefined, causing
|
|
||||||
`typing.get_type_hints()` to raise `NameError`. Resolve every
|
|
||||||
affected API and prove the lazy aliases retain import-free runtime
|
|
||||||
introspection.
|
|
||||||
|
|
||||||
'''
|
|
||||||
assert get_type_hints(_multiaddr.mk_maddr)['return'] is Any
|
|
||||||
assert get_type_hints(_tcp.MsgpackTCPStream.maddr.fget)[
|
|
||||||
'return'
|
|
||||||
] is Any
|
|
||||||
assert get_type_hints(_uds.MsgpackUDSStream.maddr.fget)[
|
|
||||||
'return'
|
|
||||||
] == Any|str
|
|
||||||
assert get_type_hints(_addr.Address.get_random)[
|
|
||||||
'current_actor'
|
|
||||||
] is Any
|
|
||||||
assert _addr.__annotations__['_address_types'].startswith('dict')
|
|
||||||
|
|
@ -2,11 +2,9 @@
|
||||||
`tractor.log`-wrapping unit tests.
|
`tractor.log`-wrapping unit tests.
|
||||||
|
|
||||||
'''
|
'''
|
||||||
import importlib
|
|
||||||
import logging
|
import logging
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
import shutil
|
import shutil
|
||||||
import sys
|
|
||||||
from types import ModuleType
|
from types import ModuleType
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
@ -167,53 +165,6 @@ def test_implicit_mod_name_applied_for_child(
|
||||||
assert submod.log.logger in sub_logs
|
assert submod.log.logger in sub_logs
|
||||||
|
|
||||||
|
|
||||||
def test_implicit_mod_name_from_unregistered_namespace(
|
|
||||||
tmp_path: Path,
|
|
||||||
):
|
|
||||||
'''
|
|
||||||
Preserve implicit logger naming for dynamic module namespaces.
|
|
||||||
|
|
||||||
The fast `sys.modules` caller lookup cannot resolve `runpy`,
|
|
||||||
plugin-loader, or `exec()` namespaces that are not registered.
|
|
||||||
Compile a real package file under an unregistered module name so
|
|
||||||
the rare filename fallback must recover its imported package and
|
|
||||||
retain the same package-level logger name.
|
|
||||||
|
|
||||||
'''
|
|
||||||
pkg_name = 'dynamic_logger_pkg'
|
|
||||||
pkg_dir = tmp_path / pkg_name
|
|
||||||
pkg_dir.mkdir()
|
|
||||||
init_path = pkg_dir / '__init__.py'
|
|
||||||
init_path.write_text('')
|
|
||||||
mod_path = pkg_dir / 'plugin.py'
|
|
||||||
mod_path.write_text('')
|
|
||||||
|
|
||||||
sys.path.insert(0, str(tmp_path))
|
|
||||||
try:
|
|
||||||
importlib.import_module(pkg_name)
|
|
||||||
namespace = {
|
|
||||||
'__name__': f'{pkg_name}.unregistered',
|
|
||||||
'__package__': pkg_name,
|
|
||||||
'tractor': tractor,
|
|
||||||
}
|
|
||||||
exec(
|
|
||||||
compile(
|
|
||||||
'log = tractor.log.get_logger('
|
|
||||||
f'pkg_name={pkg_name!r})',
|
|
||||||
str(mod_path),
|
|
||||||
'exec',
|
|
||||||
),
|
|
||||||
namespace,
|
|
||||||
)
|
|
||||||
dynamic_log = namespace.get('log')
|
|
||||||
finally:
|
|
||||||
sys.path.remove(str(tmp_path))
|
|
||||||
sys.modules.pop(pkg_name, None)
|
|
||||||
|
|
||||||
assert dynamic_log is not None
|
|
||||||
assert dynamic_log.name == pkg_name
|
|
||||||
|
|
||||||
|
|
||||||
def test_io_custom_level_registered():
|
def test_io_custom_level_registered():
|
||||||
'''
|
'''
|
||||||
The `IO`(21) level (registered via `add_log_level()` at
|
The `IO`(21) level (registered via `add_log_level()` at
|
||||||
|
|
|
||||||
|
|
@ -74,39 +74,3 @@ from .discovery._registry import (
|
||||||
Arbiter as Arbiter,
|
Arbiter as Arbiter,
|
||||||
)
|
)
|
||||||
# from . import hilevel as hilevel
|
# from . import hilevel as hilevel
|
||||||
|
|
||||||
|
|
||||||
__all__: tuple[str, ...] = tuple(
|
|
||||||
name
|
|
||||||
for name in globals()
|
|
||||||
if not name.startswith('_')
|
|
||||||
) + (
|
|
||||||
'to_asyncio',
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def __dir__() -> list[str]:
|
|
||||||
return sorted(set(globals()) | set(__all__))
|
|
||||||
|
|
||||||
|
|
||||||
def __getattr__(name: str):
|
|
||||||
'''
|
|
||||||
PEP 562 lazy sub-module loading, presently only for
|
|
||||||
`.to_asyncio` which (transitively) imports `asyncio`
|
|
||||||
itself: a non-trivial multi-ms chunk of the eager
|
|
||||||
`import tractor` cost (gh #470) unneeded by
|
|
||||||
`trio`-only apps.
|
|
||||||
|
|
||||||
Any `tractor.to_asyncio.<attr>` access (or a
|
|
||||||
`from tractor import to_asyncio`) still works, the
|
|
||||||
sub-mod is simply imported on first-access instead
|
|
||||||
of at pkg-import time.
|
|
||||||
|
|
||||||
'''
|
|
||||||
if name == 'to_asyncio':
|
|
||||||
from importlib import import_module
|
|
||||||
return import_module('.to_asyncio', __name__)
|
|
||||||
|
|
||||||
raise AttributeError(
|
|
||||||
f'module {__name__!r} has no attribute {name!r}'
|
|
||||||
)
|
|
||||||
|
|
|
||||||
|
|
@ -39,15 +39,14 @@ from typing import (
|
||||||
Type,
|
Type,
|
||||||
)
|
)
|
||||||
|
|
||||||
# NOTE, `pdbp` + `wrapt` are lazy-imported at their
|
import pdbp
|
||||||
# single use-sites below to keep them off the eager
|
|
||||||
# `import tractor` path (gh #470).
|
|
||||||
from tractor.log import get_logger
|
from tractor.log import get_logger
|
||||||
import trio
|
import trio
|
||||||
from tractor.msg import (
|
from tractor.msg import (
|
||||||
pretty_struct,
|
pretty_struct,
|
||||||
NamespacePath,
|
NamespacePath,
|
||||||
)
|
)
|
||||||
|
import wrapt
|
||||||
|
|
||||||
|
|
||||||
log = get_logger()
|
log = get_logger()
|
||||||
|
|
@ -258,7 +257,6 @@ def api_frame(
|
||||||
caller_frames_up: int = 1,
|
caller_frames_up: int = 1,
|
||||||
|
|
||||||
) -> Callable:
|
) -> Callable:
|
||||||
import wrapt
|
|
||||||
|
|
||||||
# handle the decorator called WITHOUT () case,
|
# handle the decorator called WITHOUT () case,
|
||||||
# i.e. just @api_frame, NOT @api_frame(extra=<blah>)
|
# i.e. just @api_frame, NOT @api_frame(extra=<blah>)
|
||||||
|
|
@ -322,8 +320,6 @@ def hide_runtime_frames() -> dict[FunctionType, CodeType]:
|
||||||
as possible, particularly from inside a `PdbREPL`.
|
as possible, particularly from inside a `PdbREPL`.
|
||||||
|
|
||||||
'''
|
'''
|
||||||
import pdbp
|
|
||||||
|
|
||||||
# XXX HACKZONE XXX
|
# XXX HACKZONE XXX
|
||||||
# hide exit stack frames on nurseries and cancel-scopes!
|
# hide exit stack frames on nurseries and cancel-scopes!
|
||||||
# |_ so avoid seeing it when the `pdbp` REPL is first engaged from
|
# |_ so avoid seeing it when the `pdbp` REPL is first engaged from
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ mult-process support within a single actor tree.
|
||||||
|
|
||||||
'''
|
'''
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
import asyncio
|
||||||
import bdb
|
import bdb
|
||||||
from contextlib import (
|
from contextlib import (
|
||||||
AbstractContextManager,
|
AbstractContextManager,
|
||||||
|
|
@ -52,6 +53,7 @@ from trio import (
|
||||||
)
|
)
|
||||||
import tractor
|
import tractor
|
||||||
from tractor.log import get_logger
|
from tractor.log import get_logger
|
||||||
|
from tractor.to_asyncio import run_trio_task_in_future
|
||||||
from tractor._context import Context
|
from tractor._context import Context
|
||||||
from tractor.runtime import _state
|
from tractor.runtime import _state
|
||||||
from tractor._exceptions import (
|
from tractor._exceptions import (
|
||||||
|
|
@ -83,10 +85,6 @@ from ..pformat import (
|
||||||
)
|
)
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
# NOTE, `asyncio` (and `.to_asyncio`) are
|
|
||||||
# lazy-imported at their use-sites to keep them off
|
|
||||||
# the eager `import tractor` path (gh #470).
|
|
||||||
import asyncio
|
|
||||||
from trio.lowlevel import Task
|
from trio.lowlevel import Task
|
||||||
from threading import Thread
|
from threading import Thread
|
||||||
from tractor.runtime._runtime import (
|
from tractor.runtime._runtime import (
|
||||||
|
|
@ -166,7 +164,6 @@ async def _pause(
|
||||||
'An `asyncio` task should not be calling this!?'
|
'An `asyncio` task should not be calling this!?'
|
||||||
) from rte
|
) from rte
|
||||||
else:
|
else:
|
||||||
import asyncio
|
|
||||||
task = asyncio.current_task()
|
task = asyncio.current_task()
|
||||||
|
|
||||||
if debug_func is not None:
|
if debug_func is not None:
|
||||||
|
|
@ -949,7 +946,6 @@ def pause_from_sync(
|
||||||
|
|
||||||
asyncio_task: asyncio.Task|None = None
|
asyncio_task: asyncio.Task|None = None
|
||||||
if is_infected_aio:
|
if is_infected_aio:
|
||||||
import asyncio
|
|
||||||
asyncio_task = asyncio.current_task()
|
asyncio_task = asyncio.current_task()
|
||||||
|
|
||||||
# TODO: we could also check for a non-`.to_thread` context
|
# TODO: we could also check for a non-`.to_thread` context
|
||||||
|
|
@ -1063,9 +1059,6 @@ def pause_from_sync(
|
||||||
greenback: ModuleType = maybe_import_greenback()
|
greenback: ModuleType = maybe_import_greenback()
|
||||||
|
|
||||||
if greenback.has_portal():
|
if greenback.has_portal():
|
||||||
from tractor.to_asyncio import (
|
|
||||||
run_trio_task_in_future,
|
|
||||||
)
|
|
||||||
DebugStatus.shield_sigint()
|
DebugStatus.shield_sigint()
|
||||||
fute: asyncio.Future = run_trio_task_in_future(
|
fute: asyncio.Future = run_trio_task_in_future(
|
||||||
partial(
|
partial(
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ Root-actor TTY mutex-locking machinery.
|
||||||
|
|
||||||
'''
|
'''
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
import asyncio
|
||||||
from contextlib import (
|
from contextlib import (
|
||||||
AbstractContextManager,
|
AbstractContextManager,
|
||||||
asynccontextmanager as acm,
|
asynccontextmanager as acm,
|
||||||
|
|
@ -51,6 +52,7 @@ from trio import (
|
||||||
TaskStatus,
|
TaskStatus,
|
||||||
)
|
)
|
||||||
import tractor
|
import tractor
|
||||||
|
from tractor.to_asyncio import run_trio_task_in_future
|
||||||
from tractor.log import get_logger
|
from tractor.log import get_logger
|
||||||
from tractor._context import Context
|
from tractor._context import Context
|
||||||
from tractor.runtime import _state
|
from tractor.runtime import _state
|
||||||
|
|
@ -64,10 +66,6 @@ from tractor.runtime._state import (
|
||||||
)
|
)
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
# NOTE, `asyncio` (and `.to_asyncio`) are
|
|
||||||
# lazy-imported at their use-sites to keep them off
|
|
||||||
# the eager `import tractor` path (gh #470).
|
|
||||||
import asyncio
|
|
||||||
from trio.lowlevel import Task
|
from trio.lowlevel import Task
|
||||||
from threading import Thread
|
from threading import Thread
|
||||||
from tractor.ipc import (
|
from tractor.ipc import (
|
||||||
|
|
@ -912,9 +910,6 @@ class DebugStatus:
|
||||||
async def _set_repl_release():
|
async def _set_repl_release():
|
||||||
repl_release.set()
|
repl_release.set()
|
||||||
|
|
||||||
from tractor.to_asyncio import (
|
|
||||||
run_trio_task_in_future,
|
|
||||||
)
|
|
||||||
fute: asyncio.Future = run_trio_task_in_future(
|
fute: asyncio.Future = run_trio_task_in_future(
|
||||||
_set_repl_release
|
_set_repl_release
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -16,13 +16,13 @@
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
from uuid import uuid4
|
from uuid import uuid4
|
||||||
from typing import (
|
from typing import (
|
||||||
Any,
|
|
||||||
Protocol,
|
Protocol,
|
||||||
ClassVar,
|
ClassVar,
|
||||||
Type,
|
Type,
|
||||||
TYPE_CHECKING,
|
TYPE_CHECKING,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
from bidict import bidict
|
||||||
from trio import (
|
from trio import (
|
||||||
SocketListener,
|
SocketListener,
|
||||||
)
|
)
|
||||||
|
|
@ -35,11 +35,7 @@ from ..ipc._tcp import TCPAddress
|
||||||
from ..ipc._uds import UDSAddress
|
from ..ipc._uds import UDSAddress
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
# ONLY type-annots, the eager import costs ~4.5ms
|
|
||||||
# of `import tractor` wall-time (gh #470).
|
|
||||||
from ..runtime._runtime import Actor
|
from ..runtime._runtime import Actor
|
||||||
else:
|
|
||||||
Actor = Any
|
|
||||||
|
|
||||||
log = get_logger()
|
log = get_logger()
|
||||||
|
|
||||||
|
|
@ -174,7 +170,7 @@ class Address(Protocol):
|
||||||
...
|
...
|
||||||
|
|
||||||
|
|
||||||
_address_types: dict[str, Type[Address]] = {
|
_address_types: bidict[str, Type[Address]] = {
|
||||||
'tcp': TCPAddress,
|
'tcp': TCPAddress,
|
||||||
'uds': UDSAddress
|
'uds': UDSAddress
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,23 +24,14 @@ Multiaddress support using the upstream `py-multiaddr` lib
|
||||||
- https://github.com/multiformats/multiaddr/blob/master/protocols/unix.md
|
- https://github.com/multiformats/multiaddr/blob/master/protocols/unix.md
|
||||||
|
|
||||||
'''
|
'''
|
||||||
from __future__ import annotations
|
|
||||||
import ipaddress
|
import ipaddress
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import (
|
from typing import TYPE_CHECKING
|
||||||
Any,
|
|
||||||
TYPE_CHECKING,
|
from multiaddr import Multiaddr
|
||||||
)
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
# NOTE, `multiaddr` is lazy-imported at first use
|
|
||||||
# (in the fns below) to keep it off the eager
|
|
||||||
# `import tractor` path (gh #470).
|
|
||||||
from multiaddr import Multiaddr
|
|
||||||
from tractor.discovery._addr import Address
|
from tractor.discovery._addr import Address
|
||||||
else:
|
|
||||||
Multiaddr = Any
|
|
||||||
Address = Any
|
|
||||||
|
|
||||||
# map from tractor-internal `proto_key` identifiers
|
# map from tractor-internal `proto_key` identifiers
|
||||||
# to the standard multiaddr protocol name strings.
|
# to the standard multiaddr protocol name strings.
|
||||||
|
|
@ -65,8 +56,6 @@ def mk_maddr(
|
||||||
multiaddr-spec-compliant protocol path.
|
multiaddr-spec-compliant protocol path.
|
||||||
|
|
||||||
'''
|
'''
|
||||||
from multiaddr import Multiaddr
|
|
||||||
|
|
||||||
proto_key: str = addr.proto_key
|
proto_key: str = addr.proto_key
|
||||||
maddr_proto: str|None = _tpt_proto_to_maddr.get(proto_key)
|
maddr_proto: str|None = _tpt_proto_to_maddr.get(proto_key)
|
||||||
if maddr_proto is None:
|
if maddr_proto is None:
|
||||||
|
|
@ -109,7 +98,6 @@ def parse_maddr(
|
||||||
|
|
||||||
'''
|
'''
|
||||||
# lazy imports to avoid circular deps
|
# lazy imports to avoid circular deps
|
||||||
from multiaddr import Multiaddr
|
|
||||||
from tractor.ipc._tcp import TCPAddress
|
from tractor.ipc._tcp import TCPAddress
|
||||||
from tractor.ipc._uds import UDSAddress
|
from tractor.ipc._uds import UDSAddress
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,9 +20,7 @@ TCP implementation of tractor.ipc._transport.MsgTransport protocol
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
import ipaddress
|
import ipaddress
|
||||||
from typing import (
|
from typing import (
|
||||||
Any,
|
|
||||||
ClassVar,
|
ClassVar,
|
||||||
TYPE_CHECKING,
|
|
||||||
)
|
)
|
||||||
# from contextlib import (
|
# from contextlib import (
|
||||||
# asynccontextmanager as acm,
|
# asynccontextmanager as acm,
|
||||||
|
|
@ -35,6 +33,7 @@ from trio import (
|
||||||
open_tcp_listeners,
|
open_tcp_listeners,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
from multiaddr import Multiaddr
|
||||||
from tractor.msg import MsgCodec
|
from tractor.msg import MsgCodec
|
||||||
from tractor.log import get_logger
|
from tractor.log import get_logger
|
||||||
from tractor.discovery._multiaddr import mk_maddr
|
from tractor.discovery._multiaddr import mk_maddr
|
||||||
|
|
@ -43,13 +42,6 @@ from tractor.ipc._transport import (
|
||||||
MsgpackTransport,
|
MsgpackTransport,
|
||||||
)
|
)
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
|
||||||
# ONLY type-annots, the eager import costs
|
|
||||||
# `import tractor` wall-time (gh #470).
|
|
||||||
from multiaddr import Multiaddr
|
|
||||||
else:
|
|
||||||
Multiaddr = Any
|
|
||||||
|
|
||||||
|
|
||||||
log = get_logger()
|
log = get_logger()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,6 @@ from socket import (
|
||||||
)
|
)
|
||||||
import struct
|
import struct
|
||||||
from typing import (
|
from typing import (
|
||||||
Any,
|
|
||||||
Type,
|
Type,
|
||||||
TYPE_CHECKING,
|
TYPE_CHECKING,
|
||||||
ClassVar,
|
ClassVar,
|
||||||
|
|
@ -50,6 +49,7 @@ from trio._highlevel_open_unix_stream import (
|
||||||
has_unix,
|
has_unix,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
from multiaddr import Multiaddr
|
||||||
from tractor.msg import MsgCodec
|
from tractor.msg import MsgCodec
|
||||||
from tractor.log import get_logger
|
from tractor.log import get_logger
|
||||||
from tractor.discovery._multiaddr import mk_maddr
|
from tractor.discovery._multiaddr import mk_maddr
|
||||||
|
|
@ -63,13 +63,7 @@ from tractor.runtime._state import (
|
||||||
)
|
)
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
# ONLY type-annots, the eager import costs
|
|
||||||
# `import tractor` wall-time (gh #470).
|
|
||||||
from multiaddr import Multiaddr
|
|
||||||
from tractor.runtime._runtime import Actor
|
from tractor.runtime._runtime import Actor
|
||||||
else:
|
|
||||||
Multiaddr = Any
|
|
||||||
Actor = Any
|
|
||||||
|
|
||||||
|
|
||||||
# Platform-specific credential passing constants
|
# Platform-specific credential passing constants
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,11 @@ built on `tractor`.
|
||||||
'''
|
'''
|
||||||
from collections.abc import Mapping
|
from collections.abc import Mapping
|
||||||
from functools import partial
|
from functools import partial
|
||||||
|
from inspect import (
|
||||||
|
FrameInfo,
|
||||||
|
getmodule,
|
||||||
|
stack,
|
||||||
|
)
|
||||||
import sys
|
import sys
|
||||||
import logging
|
import logging
|
||||||
from logging import (
|
from logging import (
|
||||||
|
|
@ -33,16 +38,10 @@ from logging import (
|
||||||
Logger,
|
Logger,
|
||||||
StreamHandler,
|
StreamHandler,
|
||||||
)
|
)
|
||||||
from types import (
|
from types import ModuleType
|
||||||
FrameType,
|
|
||||||
ModuleType,
|
|
||||||
)
|
|
||||||
import warnings
|
import warnings
|
||||||
|
|
||||||
# NOTE, `colorlog` is lazy-imported in
|
import colorlog # type: ignore
|
||||||
# `get_console_log()` to keep it off the eager
|
|
||||||
# `import tractor` path (gh #470).
|
|
||||||
#
|
|
||||||
# ?TODO, some other (modern) alt libs?
|
# ?TODO, some other (modern) alt libs?
|
||||||
# import coloredlogs
|
# import coloredlogs
|
||||||
# import colored_traceback.auto # ?TODO, need better config?
|
# import colored_traceback.auto # ?TODO, need better config?
|
||||||
|
|
@ -437,40 +436,16 @@ def get_logger(
|
||||||
pkg_name: str = _root_name
|
pkg_name: str = _root_name
|
||||||
|
|
||||||
def get_caller_mod(
|
def get_caller_mod(
|
||||||
frames_up: int = 2,
|
frames_up:int = 2
|
||||||
) -> ModuleType|None:
|
):
|
||||||
'''
|
'''
|
||||||
Attempt to get the module which called
|
Attempt to get the module which called `tractor.get_logger()`.
|
||||||
`tractor.get_logger()`.
|
|
||||||
|
|
||||||
Resolve the caller's frame with `sys._getframe()` and
|
|
||||||
map its `__name__` through `sys.modules`; `inspect.stack()`
|
|
||||||
(the previous impl) builds src-file info for EVERY frame
|
|
||||||
on the stack, scanning all of `sys.modules` per frame via
|
|
||||||
`inspect.getmodule()`, which made module-level
|
|
||||||
`get_logger()` calls dominate `import tractor` time
|
|
||||||
(see gh #470).
|
|
||||||
|
|
||||||
'''
|
'''
|
||||||
try:
|
callstack: list[FrameInfo] = stack()
|
||||||
caller_frame: FrameType = sys._getframe(frames_up)
|
caller_fi: FrameInfo = callstack[frames_up]
|
||||||
except ValueError:
|
caller_mod: ModuleType = getmodule(caller_fi.frame)
|
||||||
return None
|
return caller_mod
|
||||||
|
|
||||||
mod_name: str|None = caller_frame.f_globals.get(
|
|
||||||
'__name__',
|
|
||||||
)
|
|
||||||
if mod_name is None:
|
|
||||||
return None
|
|
||||||
|
|
||||||
if caller_mod := sys.modules.get(mod_name):
|
|
||||||
return caller_mod
|
|
||||||
|
|
||||||
# Preserve caller discovery for `runpy`, plugin loaders,
|
|
||||||
# and `exec()` namespaces not registered in `sys.modules`.
|
|
||||||
# Import `inspect` only on this rare fallback path.
|
|
||||||
from inspect import getmodule
|
|
||||||
return getmodule(caller_frame)
|
|
||||||
|
|
||||||
# --- Auto--naming-CASE ---
|
# --- Auto--naming-CASE ---
|
||||||
# -------------------------
|
# -------------------------
|
||||||
|
|
@ -805,10 +780,6 @@ def get_console_log(
|
||||||
None,
|
None,
|
||||||
)
|
)
|
||||||
):
|
):
|
||||||
# lazy-imported to keep it off the eager
|
|
||||||
# `import tractor` path (gh #470).
|
|
||||||
import colorlog # type: ignore
|
|
||||||
|
|
||||||
fmt: str = LOG_FORMAT # always apply our format?
|
fmt: str = LOG_FORMAT # always apply our format?
|
||||||
handler = StreamHandler()
|
handler = StreamHandler()
|
||||||
formatter = colorlog.ColoredFormatter(
|
formatter = colorlog.ColoredFormatter(
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,7 @@ from typing import (
|
||||||
TYPE_CHECKING,
|
TYPE_CHECKING,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
import platformdirs
|
||||||
from trio.lowlevel import current_task
|
from trio.lowlevel import current_task
|
||||||
|
|
||||||
from msgspec import (
|
from msgspec import (
|
||||||
|
|
@ -331,10 +332,6 @@ def get_rt_dir(
|
||||||
the lovely `platformdirs` lib.
|
the lovely `platformdirs` lib.
|
||||||
|
|
||||||
'''
|
'''
|
||||||
# lazy-imported to keep it off the eager
|
|
||||||
# `import tractor` path (gh #470).
|
|
||||||
import platformdirs
|
|
||||||
|
|
||||||
rt_dir: Path = Path(
|
rt_dir: Path = Path(
|
||||||
platformdirs.user_runtime_dir(
|
platformdirs.user_runtime_dir(
|
||||||
appname=appname,
|
appname=appname,
|
||||||
|
|
|
||||||
|
|
@ -38,11 +38,7 @@ from ..devx import (
|
||||||
pformat,
|
pformat,
|
||||||
)
|
)
|
||||||
# from ..msg import pretty_struct
|
# from ..msg import pretty_struct
|
||||||
#
|
from ..to_asyncio import run_as_asyncio_guest
|
||||||
# NOTE, `.to_asyncio` (and thus `asyncio` itself) is
|
|
||||||
# lazy-imported at the `infect_asyncio=True` use-sites
|
|
||||||
# below to keep it off the eager `import tractor` path
|
|
||||||
# (gh #470).
|
|
||||||
from ..discovery._addr import UnwrappedAddress
|
from ..discovery._addr import UnwrappedAddress
|
||||||
from ..runtime._runtime import (
|
from ..runtime._runtime import (
|
||||||
async_main,
|
async_main,
|
||||||
|
|
@ -100,7 +96,6 @@ def _mp_main(
|
||||||
)
|
)
|
||||||
try:
|
try:
|
||||||
if infect_asyncio:
|
if infect_asyncio:
|
||||||
from ..to_asyncio import run_as_asyncio_guest
|
|
||||||
actor._infected_aio = True
|
actor._infected_aio = True
|
||||||
run_as_asyncio_guest(trio_main)
|
run_as_asyncio_guest(trio_main)
|
||||||
else:
|
else:
|
||||||
|
|
@ -161,7 +156,6 @@ def _trio_main(
|
||||||
)
|
)
|
||||||
try:
|
try:
|
||||||
if infect_asyncio:
|
if infect_asyncio:
|
||||||
from ..to_asyncio import run_as_asyncio_guest
|
|
||||||
actor._infected_aio = True
|
actor._infected_aio = True
|
||||||
run_as_asyncio_guest(trio_main)
|
run_as_asyncio_guest(trio_main)
|
||||||
else:
|
else:
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue