Python 3.13: ModuleNotFoundError: No module named 'distutils' + some packages crash with ssl.wrap_socket

Upgraded a project to Python 3.13 and now installs/runtime are messy.

I’m seeing two kinds of failures depending on what I try to install/import:

  • ModuleNotFoundError: No module named 'distutils'
  • AttributeError: module 'ssl' has no attribute 'wrap_socket'

This used to work on 3.11. I’m on a clean machine now, created a new virtual environment, then installed requirements (some of them are older and I can’t replace all immediately).

What’s the pragmatic way to get this running on 3.13? I’m fine with “update toolchain / recreate venv / pin Python”, but I want to understand what’s actually going on and what the correct fix path is.

Answers

  • Gravatar — онлайн-сервис, позволяющий пользователям Интернета поддерживать постоянную картинку на большинстве сайтов.

    Nina Klein

    (Edited)

    Don’t try to “pip install distutils”. That’s the wrong direction.

    0
  • Gravatar — онлайн-сервис, позволяющий пользователям Интернета поддерживать постоянную картинку на большинстве сайтов.

    Martin Hoffmann

    (Edited)

    The ssl.wrap_socket part is a separate issue: some older libraries call ssl.wrap_socket(...) directly. That API is removed in Python 3.12+, so you get AttributeError.

    The fix is usually one of these:

    • Update the library (preferred). Most network/DB client libraries switched to creating an SSLContext and calling the context’s wrap_socket instead.
    • If it’s your own code (or a tiny internal wrapper): stop calling the removed function. Create an SSLContext, configure it (verification mode, CA store, hostname checking), then wrap the socket via the context.

    The important point is: the “context” owns the TLS configuration now; you don’t wrap raw sockets via a top-level helper.

    If you can’t update the dependency and it hard-codes ssl.wrap_socket, Python 3.11 is the realistic short-term workaround. Monkey-patching ssl is possible but brittle and not something you want in production.

    0
    • Gravatar — онлайн-сервис, позволяющий пользователям Интернета поддерживать постоянную картинку на большинстве сайтов.

      Hannah Müller

      (Edited)

      +1 on “update the library”. I’ve seen this with older DB connectors and some HTTP clients. Once updated, the wrap_socket error just disappears.

    • Gravatar — онлайн-сервис, позволяющий пользователям Интернета поддерживать постоянную картинку на большинстве сайтов.

      Stefan Wagner

      (Edited)

      The ssl.wrap_socket error came from a different old dependency. Updating it fixed the issue; it now uses the context-based wrapping internally.

      So the final state is: updated a couple of packages + pinned one remaining problematic package to a newer major. No local hacks.

  • Gravatar — онлайн-сервис, позволяющий пользователям Интернета поддерживать постоянную картинку на большинстве сайтов.

    Katrin Becker

    (Edited)

    Recreate the venv after upgrading pip/setuptools/wheel. Don’t reuse the old one.

    0
  • Gravatar — онлайн-сервис, позволяющий пользователям Интернета поддерживать постоянную картинку на большинстве сайтов.

    Julia Schneider

    (Edited)

    distutils is gone starting with Python 3.12. It’s not “missing from your venv”, it’s removed from the standard library. So any package that still does import distutils... will break on 3.12/3.13.

    The most reliable fix path is:

    1. Make sure your packaging toolchain is current for 3.13
    On a “fresh” 3.13 install, you can still end up with an old pip/setuptools in a venv (or no usable pip if the bootstrap went sideways). Use Python’s built-in bootstrap to install/refresh pip for that interpreter, then upgrade pip, setuptools, and wheel inside the venv.
    (Don’t overthink it: if pip is old, it will happily pull sdists and run setup logic that assumes distutils exists.)

    2. Recreate the virtual environment after you fix pip
    People skip this and keep chasing ghosts. If the venv was created while your toolchain was inconsistent, rebuilding it is faster than patching it.

    3. If a dependency still imports distutils, you don’t “install distutils”
    The options are:

    • upgrade that dependency to a release that removed distutils usage, or
    • temporarily run the project on Python 3.11 until the dependency is updated.

    In short: upgrade packaging tools first; then either update the offending library or downgrade Python. There isn’t a supported “bring distutils back” route on 3.13.

    0
    • Gravatar — онлайн-сервис, позволяющий пользователям Интернета поддерживать постоянную картинку на большинстве сайтов.

      Felix Neumann

      (Edited)

      One extra symptom: even if your code doesn’t use distutils, an old build backend can pull in legacy setup logic and fail at build time. Upgrading the packaging stack first avoids a lot of noise.

    • Gravatar — онлайн-сервис, позволяющий пользователям Интернета поддерживать постоянную картинку на большинстве сайтов.

      Tobias Schmidt

      (Edited)

      This is what we did. 3.13 is nice, but not worth fighting one abandoned dependency.

    • Gravatar — онлайн-сервис, позволяющий пользователям Интернета поддерживать постоянную картинку на большинстве сайтов.

      Stefan Wagner

      (Edited)

      Confirmed: one dependency still imports distutils during install. I first tried to “fix” it by adding random system packages, wasted an hour.

      What worked:

      • bootstrapped a fresh pip for the 3.13 interpreter
      • upgraded pip/setuptools/wheel in the venv
      • nuked and recreated the venv
      • upgraded the problematic dependency to a newer release (it stopped importing distutils)

      After that, the distutils error is gone.

  • Gravatar — онлайн-сервис, позволяющий пользователям Интернета поддерживать постоянную картинку на большинстве сайтов.

    Daniel Fischer

    (Edited)

    If you must run it today: pin Python to 3.11. distutils removal is not something you fix in your app.

    0