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

  1. 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.
  2. If an older interpreter must be used, pip install importlib_metadata into ccm's virtualenv so the fallback import succeeds.
  3. 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.
  4. 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

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.