*.pyc
+build
dist
MANIFEST
documentation/_build
- pypy2.7-5.8.0
- pypy3.5-5.8.0
install:
-- pip install --upgrade --force-reinstall "setuptools; python_version != '3.2'" "setuptools < 30; python_version == '3.2'"
+- pip install --upgrade --force-reinstall "setuptools; python_version != '3.2' and python_version != '3.3'" "setuptools < 30; python_version == '3.2'" "setuptools < 40; python_version == '3.3'"
- pip uninstall --yes six || true
- pip install --upgrade --force-reinstall --ignore-installed -e .
- pip install pytest
This file lists the changes in each six version.
+1.12.0
+------
+
+- Issue #259, pull request #260: `six.add_metaclass` now preserves
+ `__qualname__` from the original class.
+
+- Pull request #204: Add `six.ensure_binary`, `six.ensure_text`, and
+ `six.ensure_str`.
+
1.11.0
------
Anselm Kruis
Alexander Lukanin
James Mills
+Jordan Moldow
Berker Peksag
Sridhar Ratnakumar
Erik Rose
Miroslav Shubernetskiy
Anthony Sottile
Lucas Wiman
-Jordan Moldow
+Jingxin Zhu
If you think you belong on this list, please let me know! --Benjamin
-Copyright (c) 2010-2017 Benjamin Peterson
+Copyright (c) 2010-2018 Benjamin Peterson
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
-.. image:: http://img.shields.io/pypi/v/six.svg
- :target: https://pypi.python.org/pypi/six
+.. image:: https://img.shields.io/pypi/v/six.svg
+ :target: https://pypi.org/project/six/
+ :alt: six on PyPI
.. image:: https://travis-ci.org/benjaminp/six.svg?branch=master
- :target: https://travis-ci.org/benjaminp/six
+ :target: https://travis-ci.org/benjaminp/six
+ :alt: six on TravisCI
-.. image:: http://img.shields.io/badge/license-MIT-green.svg
+.. image:: https://readthedocs.org/projects/six/badge/?version=latest
+ :target: https://six.readthedocs.io/
+ :alt: six's documentation on Read the Docs
+
+.. image:: https://img.shields.io/badge/license-MIT-green.svg
:target: https://github.com/benjaminp/six/blob/master/LICENSE
+ :alt: MIT License badge
Six is a Python 2 and 3 compatibility library. It provides utility functions
for smoothing over the differences between the Python versions with the goal of
file, so it can be easily copied into your project. (The copyright and license
notice must be retained.)
-Online documentation is at http://six.rtfd.org.
+Online documentation is at https://six.readthedocs.io/.
Bugs can be reported to https://github.com/benjaminp/six. The code can also
be found there.
# General information about the project.
project = u"six"
-copyright = u"2010-2017, Benjamin Peterson"
+copyright = u"2010-2018, Benjamin Peterson"
sys.path.append(os.path.abspath(os.path.join(".", "..")))
from six import __version__ as six_version
without modification. six consists of only one Python file, so it is painless
to copy into a project.
-Six can be downloaded on `PyPi <https://pypi.python.org/pypi/six/>`_. Its bug
+Six can be downloaded on `PyPI <https://pypi.org/project/six/>`_. Its bug
tracker and code hosting is on `GitHub <https://github.com/benjaminp/six>`_.
The name, "six", comes from the fact that 2*3 equals 6. Why not addition?
.. data:: class_types
- Possible class types. In Python 2, this encompasses old-style and new-style
- classes. In Python 3, this is just new-styles.
+ Possible class types. In Python 2, this encompasses old-style
+ :data:`py2:types.ClassType` and new-style ``type`` classes. In Python 3,
+ this is just ``type``.
.. data:: integer_types
.. function:: b(data)
A "fake" bytes literal. *data* should always be a normal string literal. In
- Python 2, :func:`b` returns a 8-bit string. In Python 3, *data* is encoded
+ Python 2, :func:`b` returns an 8-bit string. In Python 3, *data* is encoded
with the latin-1 encoding to bytes.
a bytes object iterator in Python 3.
+.. function:: ensure_binary(s, encoding='utf-8', errors='strict')
+
+ Coerce *s* to :data:`binary_type`. *encoding*, *errors* are the same as
+ :meth:`py3:str.encode`
+
+
+.. function:: ensure_str(s, encoding='utf-8', errors='strict')
+
+ Coerce *s* to ``str``. ``encoding``, ``errors`` are the same
+ :meth:`py3:str.encode`
+
+
+.. function:: ensure_text(s, encoding='utf-8', errors='strict')
+
+ Coerce *s* to :data:`text_type`. *encoding*, *errors* are the same as
+ :meth:`py3:str.encode`
+
+
.. data:: StringIO
This is a fake file object for textual data. It's an alias for
from six.moves import html_parser
Similarly, to get the function to reload modules, which was moved from the
-builtin module to the ``imp`` module, use::
+builtin module to the ``importlib`` module, use::
from six.moves import reload_module
max-line-length = 100
ignore = F821
+[metadata]
+license_file = LICENSE
+
[tool:pytest]
minversion=2.2.0
pep8ignore =
-# Copyright (c) 2010-2017 Benjamin Peterson
+# Copyright (c) 2010-2018 Benjamin Peterson
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
import six
six_classifiers = [
+ "Development Status :: 5 - Production/Stable",
"Programming Language :: Python :: 2",
"Programming Language :: Python :: 3",
"Intended Audience :: Developers",
version=six.__version__,
author="Benjamin Peterson",
author_email="benjamin@python.org",
- url="http://pypi.python.org/pypi/six/",
+ url="https://github.com/benjaminp/six",
tests_require=["pytest"],
py_modules=["six"],
description="Python 2 and 3 compatibility utilities",
long_description=six_long_description,
license="MIT",
- classifiers=six_classifiers
+ classifiers=six_classifiers,
+ python_requires=">=2.6, !=3.0.*, !=3.1.*",
)
-# Copyright (c) 2010-2017 Benjamin Peterson
+# Copyright (c) 2010-2018 Benjamin Peterson
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
import types
__author__ = "Benjamin Peterson <benjamin@python.org>"
-__version__ = "1.11.0"
+__version__ = "1.12.0"
# Useful for very coarse version differentiation.
orig_vars.pop(slots_var)
orig_vars.pop('__dict__', None)
orig_vars.pop('__weakref__', None)
+ if hasattr(cls, '__qualname__'):
+ orig_vars['__qualname__'] = cls.__qualname__
return metaclass(cls.__name__, cls.__bases__, orig_vars)
return wrapper
+def ensure_binary(s, encoding='utf-8', errors='strict'):
+ """Coerce **s** to six.binary_type.
+
+ For Python 2:
+ - `unicode` -> encoded to `str`
+ - `str` -> `str`
+
+ For Python 3:
+ - `str` -> encoded to `bytes`
+ - `bytes` -> `bytes`
+ """
+ if isinstance(s, text_type):
+ return s.encode(encoding, errors)
+ elif isinstance(s, binary_type):
+ return s
+ else:
+ raise TypeError("not expecting type '%s'" % type(s))
+
+
+def ensure_str(s, encoding='utf-8', errors='strict'):
+ """Coerce *s* to `str`.
+
+ For Python 2:
+ - `unicode` -> encoded to `str`
+ - `str` -> `str`
+
+ For Python 3:
+ - `str` -> `str`
+ - `bytes` -> decoded to `str`
+ """
+ if not isinstance(s, (text_type, binary_type)):
+ raise TypeError("not expecting type '%s'" % type(s))
+ if PY2 and isinstance(s, text_type):
+ s = s.encode(encoding, errors)
+ elif PY3 and isinstance(s, binary_type):
+ s = s.decode(encoding, errors)
+ return s
+
+
+def ensure_text(s, encoding='utf-8', errors='strict'):
+ """Coerce *s* to six.text_type.
+
+ For Python 2:
+ - `unicode` -> `unicode`
+ - `str` -> `unicode`
+
+ For Python 3:
+ - `str` -> `str`
+ - `bytes` -> decoded to `str`
+ """
+ if isinstance(s, binary_type):
+ return s.decode(encoding, errors)
+ elif isinstance(s, text_type):
+ return s
+ else:
+ raise TypeError("not expecting type '%s'" % type(s))
+
+
+
def python_2_unicode_compatible(klass):
"""
A decorator that defines __unicode__ and __str__ methods under Python 2.
-# Copyright (c) 2010-2017 Benjamin Peterson
+# Copyright (c) 2010-2018 Benjamin Peterson
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
assert type(MySlotsWeakref) is Meta
+@py.test.mark.skipif("sys.version_info[:2] < (3, 3)")
+def test_add_metaclass_nested():
+ # Regression test for https://github.com/benjaminp/six/issues/259
+ class Meta(type):
+ pass
+
+ class A:
+ class B: pass
+
+ expected = 'test_add_metaclass_nested.<locals>.A.B'
+
+ assert A.B.__qualname__ == expected
+
+ class A:
+ @six.add_metaclass(Meta)
+ class B: pass
+
+ assert A.B.__qualname__ == expected
+
+
@py.test.mark.skipif("sys.version_info[:2] < (2, 7) or sys.version_info[:2] in ((3, 0), (3, 1))")
def test_assertCountEqual():
class TestAssertCountEqual(unittest.TestCase):
assert str(my_test) == six.u("hello")
assert getattr(six.moves.builtins, 'bytes', str)(my_test) == six.b("hello")
+
+
+class EnsureTests:
+
+ # grinning face emoji
+ UNICODE_EMOJI = six.u("\U0001F600")
+ BINARY_EMOJI = b"\xf0\x9f\x98\x80"
+
+ def test_ensure_binary_raise_type_error(self):
+ with py.test.raises(TypeError):
+ six.ensure_str(8)
+
+ def test_errors_and_encoding(self):
+ six.ensure_binary(self.UNICODE_EMOJI, encoding='latin-1', errors='ignore')
+ with py.test.raises(UnicodeEncodeError):
+ six.ensure_binary(self.UNICODE_EMOJI, encoding='latin-1', errors='strict')
+
+ def test_ensure_binary_raise(self):
+ converted_unicode = six.ensure_binary(self.UNICODE_EMOJI, encoding='utf-8', errors='strict')
+ converted_binary = six.ensure_binary(self.BINARY_EMOJI, encoding="utf-8", errors='strict')
+ if six.PY2:
+ # PY2: unicode -> str
+ assert converted_unicode == self.BINARY_EMOJI and isinstance(converted_unicode, str)
+ # PY2: str -> str
+ assert converted_binary == self.BINARY_EMOJI and isinstance(converted_binary, str)
+ else:
+ # PY3: str -> bytes
+ assert converted_unicode == self.BINARY_EMOJI and isinstance(converted_unicode, bytes)
+ # PY3: bytes -> bytes
+ assert converted_binary == self.BINARY_EMOJI and isinstance(converted_binary, bytes)
+
+ def test_ensure_str(self):
+ converted_unicode = six.ensure_str(self.UNICODE_EMOJI, encoding='utf-8', errors='strict')
+ converted_binary = six.ensure_str(self.BINARY_EMOJI, encoding="utf-8", errors='strict')
+ if six.PY2:
+ # PY2: unicode -> str
+ assert converted_unicode == self.BINARY_EMOJI and isinstance(converted_unicode, str)
+ # PY2: str -> str
+ assert converted_binary == self.BINARY_EMOJI and isinstance(converted_binary, str)
+ else:
+ # PY3: str -> str
+ assert converted_unicode == self.UNICODE_EMOJI and isinstance(converted_unicode, str)
+ # PY3: bytes -> str
+ assert converted_binary == self.UNICODE_EMOJI and isinstance(converted_unicode, str)
+
+ def test_ensure_text(self):
+ converted_unicode = six.ensure_text(self.UNICODE_EMOJI, encoding='utf-8', errors='strict')
+ converted_binary = six.ensure_text(self.BINARY_EMOJI, encoding="utf-8", errors='strict')
+ if six.PY2:
+ # PY2: unicode -> unicode
+ assert converted_unicode == self.UNICODE_EMOJI and isinstance(converted_unicode, unicode)
+ # PY2: str -> unicode
+ assert converted_binary == self.UNICODE_EMOJI and isinstance(converted_unicode, unicode)
+ else:
+ # PY3: str -> str
+ assert converted_unicode == self.UNICODE_EMOJI and isinstance(converted_unicode, str)
+ # PY3: bytes -> str
+ assert converted_binary == self.UNICODE_EMOJI and isinstance(converted_unicode, str)
[tox]
envlist=py26,py27,py31,py32,py33,py34,pypy,flake8
-indexserver=
- default = https://pypi.python.org/simple
- testrun = http://pypi.testrun.org
[testenv]
deps= pytest
-commands= py.test -rfsxX {posargs}
+commands= python -m pytest -rfsxX {posargs}
[testenv:flake8]
basepython=python
deps=flake8
commands= flake8 six.py
-