Skip to content

Fix source package builds failing with hatchling circular build error#68864

Open
dwoz wants to merge 2 commits intosaltstack:3006.xfrom
dwoz:builfix
Open

Fix source package builds failing with hatchling circular build error#68864
dwoz wants to merge 2 commits intosaltstack:3006.xfrom
dwoz:builfix

Conversation

@dwoz
Copy link
Copy Markdown
Contributor

@dwoz dwoz commented Mar 29, 2026

Add hatchling to --only-binary in onedir_dependencies() so pip installs it from its universal wheel instead of attempting a source build. When --no-binary :all: is active (Linux builds), pip 25.2 tries to source-build hatchling but hatchling lists itself as its own PEP 517 build backend, causing pip's build tracker to raise:

LookupError: hatchling is already being built

Fixes #68858

Made-with: Cursor

Fix locale.set_locale failing on containers without systemd-localed

On updated Amazon Linux 2023 and Photon OS 5 containers, localectl set-locale fails with a non-zero exit code because systemd-localed is not running (D-Bus write access unavailable), while localectl status continues to work by reading /etc/locale.conf directly.

_localectl_set() now falls back to writing /etc/locale.conf directly when localectl set-locale returns non-zero. Modern systemd's localectl status reads that file without D-Bus, so a subsequent get_locale() call immediately reflects the change.

_check_systemctl() in the integration test is hardened to skip the test for the full range of D-Bus connection error messages (Connection refused, Failed to connect to bus, Failed to get D-Bus connection) and guards against FileNotFoundError when localectl is absent.

Fixes test_localemod.py::LocaleModuleTest::test_set_locale on:

  • Amazon Linux 2023 Arm64
  • Photon OS 5 Arm64 (fips)
  • Photon OS 5

Made-with: Cursor

Provide a generous timeout for traceroute

Fix pre-commit whoops

The "Parallel cache failure" test failure

this had two root causes, both related to Python 3.14's new default multiprocessing start method (forkserver, via PEP 741):

Root Cause 1: spawning_platform() didn't recognize forkserver

salt/utils/platform.py only checked for "spawn", not "forkserver". This caused AttributeError: 'Process' object has no attribute '_args_for_getstate' because Process.new didn't set up pickling support for forkserver-spawned children. Fix: Changed spawning_platform() to return True for both "spawn" and "forkserver".

Root Cause 2: Circular import when extmods/utils/platform.py shadows stdlib

In Python 3.14, the forkserver itself is a fresh Python process (spawned via exec). When it creates child processes:

  1. It sets sys.path from the parent salt-call process via preparation_data
  2. The parent's sys.path had extmods/utils/ at index 0 (inserted by insert_system_path)
  3. In the fresh child, import platform found extmods/utils/platform.py (salt's platform util) before stdlib's platform.py
  4. extmods/utils/platform.py does from salt.utils.decorators import memoize which creates a circular import: • salt.utils.decorators → salt.utils.versions → salt.version → import platform → (itself) → salt.utils.decorators ♻️

Fix 1 (targeted): Replaced from salt.utils.decorators import memoize as real_memoize in salt/utils/platform.py with
functools.lru_cache(maxsize=None) — a stdlib-only alternative that breaks the circular dependency. Fix 2 (defensive): Changed insert_system_path() in salt/config/init.py from sys.path.insert(0, ...) to sys.path.append(...), so extension module directories never appear before stdlib paths.

Use functools.cache for real_momoize

Update traceroute test

What does this PR do?

What issues does this PR fix or reference?

Fixes

Previous Behavior

Remove this section if not relevant

New Behavior

Remove this section if not relevant

Merge requirements satisfied?

[NOTICE] Bug fixes or features added to Salt require tests.

Commits signed with GPG?

Yes/No

Add hatchling to --only-binary in onedir_dependencies() so pip installs
it from its universal wheel instead of attempting a source build.
When --no-binary :all: is active (Linux builds), pip 25.2 tries to
source-build hatchling but hatchling lists itself as its own PEP 517
build backend, causing pip's build tracker to raise:

  LookupError: hatchling is already being built

Fixes saltstack#68858

Made-with: Cursor

Fix locale.set_locale failing on containers without systemd-localed

On updated Amazon Linux 2023 and Photon OS 5 containers, localectl
set-locale fails with a non-zero exit code because systemd-localed is
not running (D-Bus write access unavailable), while localectl status
continues to work by reading /etc/locale.conf directly.

_localectl_set() now falls back to writing /etc/locale.conf directly
when localectl set-locale returns non-zero.  Modern systemd's localectl
status reads that file without D-Bus, so a subsequent get_locale() call
immediately reflects the change.

_check_systemctl() in the integration test is hardened to skip the test
for the full range of D-Bus connection error messages (Connection refused,
Failed to connect to bus, Failed to get D-Bus connection) and guards
against FileNotFoundError when localectl is absent.

Fixes test_localemod.py::LocaleModuleTest::test_set_locale on:
  - Amazon Linux 2023 Arm64
  - Photon OS 5 Arm64 (fips)
  - Photon OS 5

Made-with: Cursor

Provide a generous timeout for traceroute

Fix pre-commit whoops

The "Parallel cache failure" test failure

this had two root causes, both related to Python 3.14's new default
multiprocessing start method (forkserver, via PEP 741):

Root Cause 1: `spawning_platform()` didn't recognize `forkserver`

salt/utils/platform.py only checked for "spawn", not "forkserver". This
caused AttributeError: 'Process' object has no attribute
'_args_for_getstate' because Process.__new__ didn't set up pickling
support for forkserver-spawned children.  Fix: Changed
spawning_platform() to return True for both "spawn" and "forkserver".

Root Cause 2: Circular import when `extmods/utils/platform.py` shadows
stdlib

In Python 3.14, the forkserver itself is a fresh Python process (spawned
via exec). When it creates child processes:
1. It sets sys.path from the parent salt-call process via
   preparation_data
2. The parent's sys.path had extmods/utils/ at index 0 (inserted by
   insert_system_path)
3. In the fresh child, import platform found extmods/utils/platform.py
   (salt's platform util) before stdlib's platform.py
4. extmods/utils/platform.py does from salt.utils.decorators import
   memoize which creates a circular import: • salt.utils.decorators →
   salt.utils.versions → salt.version → import platform → (itself) →
   salt.utils.decorators ♻️

Fix 1 (targeted): Replaced from salt.utils.decorators import memoize as
real_memoize in salt/utils/platform.py with
functools.lru_cache(maxsize=None) — a stdlib-only alternative that
breaks the circular dependency.  Fix 2 (defensive): Changed
insert_system_path() in salt/config/__init__.py from sys.path.insert(0,
...) to sys.path.append(...), so extension module directories never
appear before stdlib paths.

Use functools.cache for real_momoize

Update traceroute test
@dwoz dwoz requested a review from a team as a code owner March 29, 2026 08:53
@dwoz dwoz added the test:full Run the full test suite label Mar 29, 2026
@twangboy twangboy added this to the Sulpher v3006.24 milestone Mar 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

test:full Run the full test suite

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants