Fixing ImportError: cannot import name defaultciphers from urllib3.util.ssl

Introduction

When working with Python, you may encounter a frustrating error ImportError: cannot import name default_ciphers when importing urllib3. This fails because of a missing default_ciphers module that got removed in a recent urllib3 update.

This comprehensive guide explains what’s causing this import error and how to properly fix it in Python 3 and 2.7. We’ll cover specific solutions like downgrading urllib3 or installing a patched version so you can correctly import and utilize urllib3 going forward.

Follow these key steps to resolve ImportError default_ciphers in Python once and for all.

Understanding the Default_ciphers Error

Before fixing the error, it helps to examine what’s triggering it under the hood.

The default_ciphers module referenced originally lived in urllib3’s ssl_util module. It contained default SSL cipher suites used for Python 2.7 environments. But in urllib3 version 1.26.0, this module got removed as Python 2.7 reached end-of-life.

Now when importing urllib3 in Python 2.7, the missing default_ciphers dependency causes the ImportError. Python 3 environments encounter the error as well if you have leftover Python 2.7 import code referencing default ciphers.

Here is the full error:

ImportError: cannot import name default_ciphers

This surfaces anytime code tries importing default_ciphers specifically from the now nonexistent ssl_util module path:

from urllib3.util.ssl_ import default_ciphers

So how do we fix this so Python can properly import urllib3 again?

Fixing the Error in Python 3

For Python 3 environments, the simplest fix involves removing any Python 2.7 import code referencing default_ciphers.

Python 3 handled SSL ciphers differently and has no need for the default_ciphers module. Deleting references to it eliminates the error.

Review your code for import statements like:

from urllib3.util.ssl_ import default_ciphers

Or usage of default_ciphers such as:

import ssl
from urllib3.util.ssl_ import default ciphers

ssl._DEFAULT_CIPHERS = default_ciphers

Remove these leftover Python 2.7 references.

You may also opt to downgrade to an earlier urllib3 version still including default_ciphers support if unable to fully remove and patch all references across a large, older codebase.

See the Python 2.7 section next for details on downgrading urllib3 versions to resolve the error.

Fixing the Error in Python 2.7

For Python 2.7 projects still requiring default_ciphers, several solutions exist:

1. Downgrade urllib3 Version

Downgrading to an older version of urllib3 still containing default_ciphers in ssl_util enables Python 2.7 compatibility.

Run:

pip install urllib3==1.25.11

This installs urllib3 version 1.25.11, the last before default_ciphers removal.

2. Install Urllib3 Version with Default Ciphers Patch

An alternative is installing a patched urllib3 version maintaining default_ciphers but on the main urllib3 namespace.

This GitHub fork contains the needed fix:

pip install git+https://github.com/piotrb5e3/urllib3

It patches default ciphers back into the main SSL module rather than needing the SSL util path.

So you can then import default ciphers directly:

from urllib3.util import ssl  
from ssl import default_ciphers

This simplifies importing without referencing the retired ssl_ module.

3. Manually Define Default Cipher Suite

You can also manually define a default cipher suite to use instead of relying on the now-removed module.

Add this to initialize a default set after importing urllib3:

import urllib3

DEFAULT_CIPHERS = [
    'ECDHE+AESGCM',
    'ECDHE+CHACHA20',
    'DHE+AESGCM',
    'DHE+CHACHA20',
    'ECDH+AESGCM',
    'DH+AESGCM',
    'ECDH+AES',
    'DH+AES',
    'RSA+AESGCM',
    'RSA+AES',
    '!aNULL',
    '!eNULL',
    '!MD5',
]

With this constant defined, any references to default_ciphers can use your new DEFAULT_CIPHERS list instead.

Verifying Import Error Resolution in Python

Once implementing a solution, verify you’ve eliminated the import error by importing urllib3 in Python again:

import urllib3

No error indicates resolved default cipher issues.

Also check any part of your code previously triggering the error such as:

from urllib3.util import ssl

With a proper fix in place, import statements should now function again without errors.

Troubleshooting Guide

If you are still struggling with lingering errors, utilize this troubleshooting checklist:

  • Double-check all code for references to the removed default_ciphers module or ssl_ path. The error surfaces when code actively tries accessing these missing pieces.
  • For Python 3, examine for any remnants of Python 2.7 cipher configuration code. Remove all default_cipher references.
  • In Python 2.7, verify successful installation of a urllib3 version containing default_ciphers support via downgrading or patches.
  • If using a cipher patch, check import statements reference the proper path where default ciphers got added, typically urllib3.util.ssl.
  • Try manually defining a cipher suite for usage instead of relying on default_ciphers.
  • Confirm urllib3 and SSL-related dependencies all show the expected versions.
  • As a last resort, perform a fresh Python environment install upgrading all packages which may resolve odd interactions.

See the following table for a quick reference on applying fixes based on your Python version:

Python VersionRecommended Fixes
Python 3Remove all references to default_ciphers moduleDouble check for Python 2.7 cipher configuration code
Python 2.7Downgrade urllib3 version below 1.26.0Install urllib3 patch adding default_ciphers module backManually define cipher suite constant to use

Conclusion

The ImportError: cannot import name default_ciphers in Python arises due to the removed default SSL ciphers module in urllib3 version 1.26.0. For Python 3, eliminating leftover references fixes the issue. In Python 2.7, downgrading urllib3 or applying patches to restore default_ciphers resolves it.

Carefully check your code and environment against the solutions outlined to squash this import error for good. Let us know if any tricky cipher issues remain! With the proper fix, you can continue leveraging urllib3 to make requests and transfer data without any blocking import troubles.

Leave a Comment