Install & Compatibility
Where this runs
tested against v1.17.0 · pip install
no network on importno background threads
Install × environment matrix
Each cell = how many times install + import succeeded across repeated harness runs. Partial = flaky.
glibc = Debian/Ubuntu slim · musl = Alpine Linux
muslpy 3.10–3.95 runs
installs and imports cleanly · install 0.0s · import 0.012s · 17.8MB
glibcpy 3.10–3.95 runs
installs and imports cleanly · install 1.7s · import 0.008s · 18MB
16MB installed
● package 16MB
Code
Verified usage
Verified import paths — ran on the pinned version, not inferred.
six
✓ import six
Top-level import; all constants, helpers, and the moves virtual module are accessed as attributes of the six module object.
string_types / text_type / binary_type
✓ import six
isinstance(value, six.string_types)
✗ isinstance(value, str)
On Python 2 string_types is (basestring,); on Python 3 it is (str,). Using bare str misses unicode on Py2.
six.moves (stdlib remaps)
✓ from six.moves import urllib
from six.moves import range
from six.moves import configparser
✗ import six.moves
six.moves is a virtual module implemented via a PEP 302 meta path hook inside six.py — there is no moves.py on disk. Direct 'import six.moves' can fail with ModuleNotFoundError in some environments (frozen importers, vendored copies, Python 3.12+). Always use 'from six.moves import <name>'.
with_metaclass
✓ from six import with_metaclass
class MyClass(with_metaclass(Meta, Base)): pass
✗ class MyClass(object, metaclass=Meta): pass # Py3-only syntax
Use with_metaclass() or the @add_metaclass decorator only when the codebase must remain Py2-compatible; on Py3-only code use the native metaclass= keyword directly.
add_metaclass
✓ from six import add_metaclass
@add_metaclass(Meta)
class MyClass(object): pass
Decorator alternative to with_metaclass; produces an equivalent class but applied post-construction.
reraise
✓ from six import reraise
reraise(tp, value, tb=None)
Wraps Python 3's 'raise value.with_traceback(tb)' syntax which is a SyntaxError on Python 2.
six.moves.urllib
✓ from six.moves.urllib.parse import urlencode
from six.moves.urllib.request import urlopen
✗ from six.moves import urllib
urllib.parse.urlencode(…)
six.moves.urllib sub-namespaces (parse, request, response, error, robotparser) must be imported individually; accessing them as attributes of the moves.urllib object is unreliable without first importing the sub-module.
Demonstrate the most common six patterns: version guards, type checks, and stdlib moves.
import six
from six.moves import urllib
from six.moves.urllib.parse import urlencode
# Version guard
if six.PY2:
print("Running on Python 2")
else:
print("Running on Python 3")
# Cross-version type check
value = u"hello"
assert isinstance(value, six.text_type) # unicode on Py2, str on Py3
assert isinstance(b"bytes", six.binary_type) # str on Py2, bytes on Py3
assert isinstance(value, six.string_types) # catches both str/unicode on Py2
# Stdlib move: urllib.parse.urlencode works on both versions
params = urlencode({"key": "value", "foo": "bar"})
print("Encoded:", params)
# Integer types (int + long on Py2, int only on Py3)
assert isinstance(42, six.integer_types)
# Metaclass compatibility
from six import with_metaclass
class Meta(type):
pass
class MyBase(with_metaclass(Meta, object)):
pass
print("Metaclass:", type(MyBase))
Debug
Known issues
deprecatedsix exists solely to support Python 2/3 dual-compatibility. Python 2 reached end-of-life in January 2020. New projects targeting Python 3 only should not use six — use native Python 3 syntax instead (e.g. 'class Foo(metaclass=Meta)', 'from urllib.parse import urlencode', f-strings, etc.).fixRemove six and use Python 3 native equivalents. Tools like 'pyupgrade' and 'ruff --select UP' can automate the removal of six patterns.
affects: all
breakingsix.moves is a virtual module backed by a meta path hook in six.py — there is no moves.py file on disk. In environments with frozen importers, custom loaders, or when a vendored/stale copy of six is present (e.g. inside a third-party library's vendor folder), 'import six.moves' or 'from six.moves import X' can raise ModuleNotFoundError even though 'import six' succeeds.fixAlways use the current PyPI release (1.17.0). If a dependency vendors its own stale six, override it in sys.modules before importing that library: import six; import sys; sys.modules['lib.vendor.six'] = six
affects: < 1.16.0 (vendored copies); also surfaces on Python 3.12+
gotchaNaming any of your own files 'six.py' or any variable 'six' shadows the installed library and causes confusing ImportError or AttributeError failures downstream.fixRename your file or variable. Check with: python -c "import six; print(six.__file__)" to verify the correct module is being loaded.
affects: all
gotchasix.moves.urllib sub-modules (parse, request, error, response, robotparser) must each be explicitly imported before use. Accessing them as attributes of a previously imported 'urllib' alias from six.moves is not reliably populated until the sub-module is imported.fixUse 'from six.moves.urllib.parse import urlencode' etc., rather than 'from six.moves import urllib' followed by 'urllib.parse.urlencode()'.
affects: all
gotchasix.add_metaclass() with __slots__ containing '__weakref__' or '__dict__' was silently broken before 1.8.0 — the decorator re-created the class without preserving slot semantics correctly.fixUse six >= 1.8.0. Prefer with_metaclass() over add_metaclass() when __slots__ are involved, or switch to Python 3 native metaclass= syntax.
affects: < 1.8.0
gotchasix.moves aliases follow Python 3 naming conventions with dots replaced by underscores (e.g. html.parser → html_parser, http.client → http_client). Importing the Python 2 module name directly (e.g. 'from six.moves import HTMLParser') will raise ImportError.fixUse the underscore-separated Python 3 name: 'from six.moves import html_parser'. Refer to https://six.readthedocs.io/#module-six.moves for the full mapping table.
affects: all
gotchasix.PY34 (a constant that was True when running on Python 3.4+) was present in some versions and relied upon by downstream libraries but is not part of the documented public API. It was removed in later releases, breaking code that imported it directly.fixUse 'import sys; sys.version_info >= (3, 4)' for version gating instead of six.PY34.
affects: mixed; PY34 was undocumented and has been removed
Errors
Common errors & fixes
ModuleNotFoundError: No module named 'six'
The `six` library is not installed in the Python environment being used.
ImportError: cannot import name 'cStringIO' from 'six.moves'
`six.moves` provides a Python 2/3 compatible `StringIO` class, but does not expose `cStringIO` directly, which was a Python 2-specific module.
fixfrom six.moves import StringIO
TypeError: a bytes-like object is required, not 'str'
Code intended for Python 2 (where `str` was bytes) is run in Python 3 (where `str` is Unicode), and a function expects actual bytes.
fixUse `six.ensure_binary(your_string)` or `six.b(your_string)` to explicitly convert the string to a bytes object for Python 2/3 compatibility.
AttributeError: 'dict' object has no attribute 'iteritems'
In Python 3, dictionary methods like `iteritems()` were removed, replaced by `items()`, which return view objects.
fixUse `six.iteritems(my_dict)` for Python 2/3 compatible iteration, or `my_dict.items()` if the codebase is Python 3 only.
Upgrade
Version history
1.17.0latest on PyPI · released Dec 4, 2024
Audit
Dependencies
No dependency data recorded yet.