Move the private modules into tango._internal

TL;DR

  • The four private implementation modules that sat beside the API modules move into a tango/_internal/ package: _attribute_access, _instrumentation and _telemetry keep their names under it, and _warnings becomes _internal/warn.
  • Nothing is re-exported and nothing else changes. The top level is left to the modules users import.

Follow-up to #789. Draft: opened for agreement on the shape.

Key Facts

  • _warnings is renamed to warn, not kept as warnings. Three of its new siblings in _internal do import warnings for the standard library. Absolute imports mean a sibling named warnings.py would still resolve correctly, but a reader of _internal/telemetry.py would have to know that, so the name is avoided.
  • No facade. tango/_internal/__init__.py is a docstring with no imports, so every importer names the module it needs and the origin of a helper stays visible at the point of use. This is the opposite of the tango/utils/ choice in the MR below, and deliberately so: tango.utils had a published surface to preserve, this has none.
  • All four files are recorded as renames. Two are byte-identical to their old selves; the other two differ only in their own import lines.
  • tango._internal is added to wheel.packages, which lists subpackages explicitly.
  • Three documentation files named the old module paths and are updated. The generated .pyi stubs also reference them, but they are gitignored and regenerate from source.

Not API

None of this was ever part of the API. These modules are reached through the public modules that use them — tango.telemetry, tango.server, tango.device_proxy and the executors — and those are unchanged. Anyone who had reached past them into tango._telemetry or tango._warnings directly was relying on a leading underscore to mean the opposite of what it says.

How this was checked

  • Every import site repointed: 46 lines across 18 files, verified by searching for any surviving reference to the old paths (none).
  • tango._tango._telemetry, a C++ binding submodule that shares a name with the moved Python module, is untouched. Every rewrite pattern anchors on the full old module path for exactly this reason, and tests/test_telemetry.py still imports it as before.
  • All four modules import cleanly, and tango.utils, tango.telemetry and the rest resolve as before.
  • Full suite: 1512 passed, 98 skipped, 54 xfailed, 1 xpassed, 1 failed. The failure is test_test_context.py::test_nested_single_device_in_same_process_failure ("Device server failed to exit cleanly"), which is a known flaky shutdown test: the whole file passes in isolation (98 passed, 2 xfailed), and the same test failed on unmodified develop earlier in this work. A confirmation run was in progress when this was opened; the numbers will be updated.

Caveats

  • Two defects were found and fixed during the move, both of a kind that only shows up at import time: _internal/instrumentation.py carried from .utils import ..., a relative import whose meaning silently changed from tango.utils to tango._internal.utils; and tests/test_event.py used from tango import _warnings, an import shape that does not match from tango._warnings import ... and so was missed by the first pass. Both are worth a reviewer's attention as the two places where a mechanical move can go wrong.
  • Builds on !1080 (merged) and targets its branch, because both change the same import line in tango/utils. Retarget to develop once that merges.

🤖 Generated with Claude Code

Edited by Yury Matveev

Merge request reports

Loading
Loading