Skip to content

Docker image: "No module named 'pkg_resources'" at start-up, silently disabling --framework #58

Description

@RamsesRodenburg

Split out of #57 as suggested there.

Symptom

Every run of the current published image starts with:

$ docker run --rm gofwd/analyze_hosts 2>&1 | head -2
[-] Please install required modules, e.g. pip3 install -r requirements.txt: No module named 'pkg_resources'
analyze_hosts version 1.16.0 starting

The visible cost is a misleading warning on every run (the modules are installed). The invisible cost is that --framework is then silently dropped in preflight_checks():

if options["framework"]:
    try:
        import requests
        import Wappalyzer
        ...
    except ImportError:
        logging.error("Disabling --framework due to missing Python libraries")
        options["framework"] = False

which is the same end state as the long-closed #41.

Cause

Four things line up:

  1. The guarded import block imports Wappalyzer.
  2. python-Wappalyzer 0.3.1 — the latest release — does import pkg_resources and pkg_resources.resource_string(__name__, "data/technologies.json").
  3. pkg_resources ships with setuptools, and since Python 3.12 python -m venv no longer seeds setuptools into a virtualenv. The image is on Python 3.14.6 (PYTHON_VERSION in the published image config), so /opt/venv has none.
  4. setuptools 82.0.0 removed pkg_resources outright, so pip install setuptools does not fix it. I checked the wheels: 81.0.0 still ships 19 pkg_resources/* files, 82.0.0 ships zero.

And chorsley/python-Wappalyzer has been archived since 2024-04, with 0.3.1 the final release — so there is no upstream fix to wait for, and bumping the pin (#50) will not help.

One nuance worth noting: because Wappalyzer is imported last in that block, requests and yaml are already bound and everything else keeps working. If the failing import were earlier in the block the program would continue with those names unbound and fail later with a NameError — e.g. read_settings() uses yaml.

Suggested fix

What we run in production, as a build-time patch on top of your image — two lines, no new dependencies, and it drops the dead dependency rather than pinning around it:

# in <site-packages>/Wappalyzer/Wappalyzer.py
-import pkg_resources
+import importlib.resources

-        obj = json.loads(pkg_resources.resource_string(__name__, "data/technologies.json"))
+        obj = json.loads(
+            importlib.resources.files("Wappalyzer").joinpath("data/technologies.json").read_bytes()
+        )

importlib.resources.files() has been available since Python 3.9. Verified against a venv with setuptools 84.0.0 installed (i.e. no pkg_resources anywhere): Wappalyzer.latest() loads all 1270 technologies, and pkg_resources is never imported.

Alternatives, for completeness:

  • Pin setuptools<82 in requirements.txt. Works today, but pins an obsolete setuptools and will rot.
  • Vendor or replace python-Wappalyzer, given it is archived. Cleanest long term, much larger change.

Happy to send a PR for whichever you prefer — the sed/patch form in the Dockerfile is the smallest change, but it does mean editing an installed third-party file, so I did not want to presume.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions