Homebrew/homebrew-core · warning · UserWarning
importlib.metadata not available; skipping ccm_extension ent
Error message
importlib.metadata not available; skipping ccm_extension entry points
What it means
UserWarning emitted by the patched ccm launcher (Formula/c/ccm.rb:115, backport of apache/cassandra-ccm commit 0b19c8e) when the module-level import of importlib.metadata (stdlib, Python 3.8+) and the importlib_metadata backport both failed, leaving entry_points set to None. The warning fires from _iter_ccm_extension_entry_points() and the function returns an empty list, so every ccm_extension entry-point plugin is silently skipped for the whole run. It exists as graceful degradation so ccm still works on old interpreters, at the cost of disabling third-party extensions.
Source
Thrown at Formula/c/ccm.rb:115
+try: # Python 3.8+
+ from importlib.metadata import entry_points
+except ImportError: # pragma: no cover - fallback for older Pythons
+ try:
+ from importlib_metadata import entry_points # type: ignore
+ except ImportError:
+ entry_points = None
+
def get_command(kind, cmd):
cmd_name = kind.lower().capitalize() + cmd.lower().capitalize() + "Cmd"
@@ -52,7 +59,23 @@ def print_global_usage():
exit(1)
-for entry_point in pkg_resources.iter_entry_points(group='ccm_extension'):
+def _iter_ccm_extension_entry_points():
+ if entry_points is None:
+ warnings.warn("importlib.metadata not available; skipping ccm_extension entry points")
+ return []
+
+ eps = entry_points()
+
+ if hasattr(eps, 'select'): # modern importlib.metadata
+ return eps.select(group='ccm_extension')
+
+ if isinstance(eps, dict): # older importlib_metadata returns dict
+ return eps.get('ccm_extension', [])
+
+ return [ep for ep in eps if getattr(ep, 'group', None) == 'ccm_extension']
+
+
+for entry_point in _iter_ccm_extension_entry_points():
entry_point.load()()
common.check_win_requirements()
View on GitHub (pinned to c0cb250747)
Solutions
- Run ccm under Python >= 3.8 where importlib.metadata is stdlib (python3 --version); under Homebrew's virtualenv_install_with_resources this is already the normal case and the warning disappears.
- If an older interpreter must be used, pip install importlib_metadata into ccm's virtualenv so the fallback import succeeds.
- Fix the interpreter selection: check the installed script's shebang (head -1 $(which ccm)) and point it at the venv's modern python instead of a legacy system python.
- Confirm extensions actually load after fixing: python3 -c "from importlib.metadata import entry_points; print([e.name for e in entry_points().select(group='ccm_extension')])" — the warning plus an empty result means plugins are being skipped.
Example fix
# before
try:
from importlib.metadata import entry_points
except ImportError:
try:
from importlib_metadata import entry_points # type: ignore
except ImportError:
entry_points = None
# after (fail fast instead of silently skipping extensions)
import sys
if sys.version_info < (3, 8):
sys.exit("ccm requires Python >= 3.8 for entry-point plugin support")
from importlib.metadata import entry_points Defensive patterns
Strategy: validation
Validate before calling
# Preflight before invoking ccm: confirm entry-point machinery is importable
import importlib.util, sys
if sys.version_info >= (3, 8):
ok = importlib.util.find_spec("importlib.metadata") is not None
else:
ok = importlib.util.find_spec("importlib_metadata") is not None
if not ok:
raise SystemExit("ccm extensions disabled: install Python >= 3.8 or pip install importlib_metadata") Type guard
from typing import Any, Callable, Optional
def get_entry_points() -> Optional[Callable[[], Any]]:
"""Narrowing helper: returns the callable if plugin loading is possible, else None."""
try:
from importlib.metadata import entry_points
return entry_points
except ImportError:
return None
# usage
ep_factory = get_entry_points()
if ep_factory is None:
... # known-disabled state, no warning surprise
else:
eps = ep_factory()
group = eps.select(group='ccm_extension') if hasattr(eps, 'select') else eps.get('ccm_extension', [])
for ep in group:
ep.load()() Try / catch
# The warning itself is not an exception; if you want silent plugin loss to be loud,
# promote the underlying ImportError to a hard failure instead of falling back:
try:
from importlib.metadata import entry_points
except ImportError as e:
raise SystemExit(
f"ccm requires Python >= 3.8 or the importlib_metadata backport: {e}"
) from e
# Or surface the degradation in tests:
# python -W error::UserWarning -m ccm ... Prevention
- Declare python_requires = '>=3.8' in packaging so old interpreters are rejected at install time instead of degraded at runtime.
- List importlib_metadata as a conditional dependency for environments that may run Python < 3.8.
- Check plugins actually registered after install (entry_points().select(group='ccm_extension') is non-empty) rather than trusting ccm's exit code.
- Run CI on the oldest supported interpreter with -W error::UserWarning so import-fallback degradation fails the build.
- Keep the interpreter contract explicit: verify the installed script's shebang points at the venv python you tested with.
When it happens
Trigger: Launching the installed ccm binary under an interpreter where both imports fail: Python < 3.8 without the importlib_metadata backport installed in ccm's virtualenv, a venv whose site-packages lost the backport, or a broken stdlib import. Each ccm invocation triggers the warning once (module-level loop in the launcher), then iterates zero plugins.
Common situations: Migration pressure from pkg_resources (removed in setuptools 81+) pushed ccm to importlib.metadata, which only exists as stdlib from Python 3.8; legacy macOS/system Python 2.7 or 3.7 interpreters picked up by the shebang; manually built virtualenvs that omit the backport; plugin authors puzzled why their ccm_extension plugins stopped registering after a reinstall on an old interpreter.
Related errors
AI-assisted analysis of Homebrew/homebrew-core@c0cb250747 (2026-08-21).
Data as JSON: /api/errors/3ff555577e04c13a.
Report an issue: GitHub.