diff options
Diffstat (limited to 'third_party/python/six/test_six.py')
-rw-r--r-- | third_party/python/six/test_six.py | 1060 |
1 files changed, 1060 insertions, 0 deletions
diff --git a/third_party/python/six/test_six.py b/third_party/python/six/test_six.py new file mode 100644 index 0000000000..0b72067416 --- /dev/null +++ b/third_party/python/six/test_six.py @@ -0,0 +1,1060 @@ +# Copyright (c) 2010-2019 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 the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +import operator +import sys +import types +import unittest +import abc + +import pytest + +import six + + +def test_add_doc(): + def f(): + """Icky doc""" + pass + six._add_doc(f, """New doc""") + assert f.__doc__ == "New doc" + + +def test_import_module(): + from logging import handlers + m = six._import_module("logging.handlers") + assert m is handlers + + +def test_integer_types(): + assert isinstance(1, six.integer_types) + assert isinstance(-1, six.integer_types) + assert isinstance(six.MAXSIZE + 23, six.integer_types) + assert not isinstance(.1, six.integer_types) + + +def test_string_types(): + assert isinstance("hi", six.string_types) + assert isinstance(six.u("hi"), six.string_types) + assert issubclass(six.text_type, six.string_types) + + +def test_class_types(): + class X: + pass + class Y(object): + pass + assert isinstance(X, six.class_types) + assert isinstance(Y, six.class_types) + assert not isinstance(X(), six.class_types) + + +def test_text_type(): + assert type(six.u("hi")) is six.text_type + + +def test_binary_type(): + assert type(six.b("hi")) is six.binary_type + + +def test_MAXSIZE(): + try: + # This shouldn't raise an overflow error. + six.MAXSIZE.__index__() + except AttributeError: + # Before Python 2.6. + pass + pytest.raises( + (ValueError, OverflowError), + operator.mul, [None], six.MAXSIZE + 1) + + +def test_lazy(): + if six.PY3: + html_name = "html.parser" + else: + html_name = "HTMLParser" + assert html_name not in sys.modules + mod = six.moves.html_parser + assert sys.modules[html_name] is mod + assert "htmlparser" not in six._MovedItems.__dict__ + + +try: + import _tkinter +except ImportError: + have_tkinter = False +else: + have_tkinter = True + +have_gdbm = True +try: + import gdbm +except ImportError: + try: + import dbm.gnu + except ImportError: + have_gdbm = False + +@pytest.mark.parametrize("item_name", + [item.name for item in six._moved_attributes]) +def test_move_items(item_name): + """Ensure that everything loads correctly.""" + try: + item = getattr(six.moves, item_name) + if isinstance(item, types.ModuleType): + __import__("six.moves." + item_name) + except AttributeError: + if item_name == "zip_longest" and sys.version_info < (2, 6): + pytest.skip("zip_longest only available on 2.6+") + except ImportError: + if item_name == "winreg" and not sys.platform.startswith("win"): + pytest.skip("Windows only module") + if item_name.startswith("tkinter"): + if not have_tkinter: + pytest.skip("requires tkinter") + if item_name == "tkinter_ttk" and sys.version_info[:2] <= (2, 6): + pytest.skip("ttk only available on 2.7+") + if item_name.startswith("dbm_gnu") and not have_gdbm: + pytest.skip("requires gdbm") + raise + if sys.version_info[:2] >= (2, 6): + assert item_name in dir(six.moves) + + +@pytest.mark.parametrize("item_name", + [item.name for item in six._urllib_parse_moved_attributes]) +def test_move_items_urllib_parse(item_name): + """Ensure that everything loads correctly.""" + if item_name == "ParseResult" and sys.version_info < (2, 5): + pytest.skip("ParseResult is only found on 2.5+") + if item_name in ("parse_qs", "parse_qsl") and sys.version_info < (2, 6): + pytest.skip("parse_qs[l] is new in 2.6") + if sys.version_info[:2] >= (2, 6): + assert item_name in dir(six.moves.urllib.parse) + getattr(six.moves.urllib.parse, item_name) + + +@pytest.mark.parametrize("item_name", + [item.name for item in six._urllib_error_moved_attributes]) +def test_move_items_urllib_error(item_name): + """Ensure that everything loads correctly.""" + if sys.version_info[:2] >= (2, 6): + assert item_name in dir(six.moves.urllib.error) + getattr(six.moves.urllib.error, item_name) + + +@pytest.mark.parametrize("item_name", + [item.name for item in six._urllib_request_moved_attributes]) +def test_move_items_urllib_request(item_name): + """Ensure that everything loads correctly.""" + if sys.version_info[:2] >= (2, 6): + assert item_name in dir(six.moves.urllib.request) + getattr(six.moves.urllib.request, item_name) + + +@pytest.mark.parametrize("item_name", + [item.name for item in six._urllib_response_moved_attributes]) +def test_move_items_urllib_response(item_name): + """Ensure that everything loads correctly.""" + if sys.version_info[:2] >= (2, 6): + assert item_name in dir(six.moves.urllib.response) + getattr(six.moves.urllib.response, item_name) + + +@pytest.mark.parametrize("item_name", + [item.name for item in six._urllib_robotparser_moved_attributes]) +def test_move_items_urllib_robotparser(item_name): + """Ensure that everything loads correctly.""" + if sys.version_info[:2] >= (2, 6): + assert item_name in dir(six.moves.urllib.robotparser) + getattr(six.moves.urllib.robotparser, item_name) + + +def test_import_moves_error_1(): + from six.moves.urllib.parse import urljoin + from six import moves + # In 1.4.1: AttributeError: 'Module_six_moves_urllib_parse' object has no attribute 'urljoin' + assert moves.urllib.parse.urljoin + + +def test_import_moves_error_2(): + from six import moves + assert moves.urllib.parse.urljoin + # In 1.4.1: ImportError: cannot import name urljoin + from six.moves.urllib.parse import urljoin + + +def test_import_moves_error_3(): + from six.moves.urllib.parse import urljoin + # In 1.4.1: ImportError: cannot import name urljoin + from six.moves.urllib_parse import urljoin + + +def test_from_imports(): + from six.moves.queue import Queue + assert isinstance(Queue, six.class_types) + from six.moves.configparser import ConfigParser + assert isinstance(ConfigParser, six.class_types) + + +def test_filter(): + from six.moves import filter + f = filter(lambda x: x % 2, range(10)) + assert six.advance_iterator(f) == 1 + + +def test_filter_false(): + from six.moves import filterfalse + f = filterfalse(lambda x: x % 3, range(10)) + assert six.advance_iterator(f) == 0 + assert six.advance_iterator(f) == 3 + assert six.advance_iterator(f) == 6 + +def test_map(): + from six.moves import map + assert six.advance_iterator(map(lambda x: x + 1, range(2))) == 1 + + +def test_getoutput(): + from six.moves import getoutput + output = getoutput('echo "foo"') + assert output == 'foo' + + +def test_zip(): + from six.moves import zip + assert six.advance_iterator(zip(range(2), range(2))) == (0, 0) + + +@pytest.mark.skipif("sys.version_info < (2, 6)") +def test_zip_longest(): + from six.moves import zip_longest + it = zip_longest(range(2), range(1)) + + assert six.advance_iterator(it) == (0, 0) + assert six.advance_iterator(it) == (1, None) + + +class TestCustomizedMoves: + + def teardown_method(self, meth): + try: + del six._MovedItems.spam + except AttributeError: + pass + try: + del six.moves.__dict__["spam"] + except KeyError: + pass + + + def test_moved_attribute(self): + attr = six.MovedAttribute("spam", "foo", "bar") + if six.PY3: + assert attr.mod == "bar" + else: + assert attr.mod == "foo" + assert attr.attr == "spam" + attr = six.MovedAttribute("spam", "foo", "bar", "lemma") + assert attr.attr == "lemma" + attr = six.MovedAttribute("spam", "foo", "bar", "lemma", "theorm") + if six.PY3: + assert attr.attr == "theorm" + else: + assert attr.attr == "lemma" + + + def test_moved_module(self): + attr = six.MovedModule("spam", "foo") + if six.PY3: + assert attr.mod == "spam" + else: + assert attr.mod == "foo" + attr = six.MovedModule("spam", "foo", "bar") + if six.PY3: + assert attr.mod == "bar" + else: + assert attr.mod == "foo" + + + def test_custom_move_module(self): + attr = six.MovedModule("spam", "six", "six") + six.add_move(attr) + six.remove_move("spam") + assert not hasattr(six.moves, "spam") + attr = six.MovedModule("spam", "six", "six") + six.add_move(attr) + from six.moves import spam + assert spam is six + six.remove_move("spam") + assert not hasattr(six.moves, "spam") + + + def test_custom_move_attribute(self): + attr = six.MovedAttribute("spam", "six", "six", "u", "u") + six.add_move(attr) + six.remove_move("spam") + assert not hasattr(six.moves, "spam") + attr = six.MovedAttribute("spam", "six", "six", "u", "u") + six.add_move(attr) + from six.moves import spam + assert spam is six.u + six.remove_move("spam") + assert not hasattr(six.moves, "spam") + + + def test_empty_remove(self): + pytest.raises(AttributeError, six.remove_move, "eggs") + + +def test_get_unbound_function(): + class X(object): + def m(self): + pass + assert six.get_unbound_function(X.m) is X.__dict__["m"] + + +def test_get_method_self(): + class X(object): + def m(self): + pass + x = X() + assert six.get_method_self(x.m) is x + pytest.raises(AttributeError, six.get_method_self, 42) + + +def test_get_method_function(): + class X(object): + def m(self): + pass + x = X() + assert six.get_method_function(x.m) is X.__dict__["m"] + pytest.raises(AttributeError, six.get_method_function, hasattr) + + +def test_get_function_closure(): + def f(): + x = 42 + def g(): + return x + return g + cell = six.get_function_closure(f())[0] + assert type(cell).__name__ == "cell" + + +def test_get_function_code(): + def f(): + pass + assert isinstance(six.get_function_code(f), types.CodeType) + if not hasattr(sys, "pypy_version_info"): + pytest.raises(AttributeError, six.get_function_code, hasattr) + + +def test_get_function_defaults(): + def f(x, y=3, b=4): + pass + assert six.get_function_defaults(f) == (3, 4) + + +def test_get_function_globals(): + def f(): + pass + assert six.get_function_globals(f) is globals() + + +def test_dictionary_iterators(monkeypatch): + def stock_method_name(iterwhat): + """Given a method suffix like "lists" or "values", return the name + of the dict method that delivers those on the version of Python + we're running in.""" + if six.PY3: + return iterwhat + return 'iter' + iterwhat + + class MyDict(dict): + if not six.PY3: + def lists(self, **kw): + return [1, 2, 3] + def iterlists(self, **kw): + return iter([1, 2, 3]) + f = MyDict.iterlists + del MyDict.iterlists + setattr(MyDict, stock_method_name('lists'), f) + + d = MyDict(zip(range(10), reversed(range(10)))) + for name in "keys", "values", "items", "lists": + meth = getattr(six, "iter" + name) + it = meth(d) + assert not isinstance(it, list) + assert list(it) == list(getattr(d, name)()) + pytest.raises(StopIteration, six.advance_iterator, it) + record = [] + def with_kw(*args, **kw): + record.append(kw["kw"]) + return old(*args) + old = getattr(MyDict, stock_method_name(name)) + monkeypatch.setattr(MyDict, stock_method_name(name), with_kw) + meth(d, kw=42) + assert record == [42] + monkeypatch.undo() + + +@pytest.mark.skipif("sys.version_info[:2] < (2, 7)", + reason="view methods on dictionaries only available on 2.7+") +def test_dictionary_views(): + def stock_method_name(viewwhat): + """Given a method suffix like "keys" or "values", return the name + of the dict method that delivers those on the version of Python + we're running in.""" + if six.PY3: + return viewwhat + return 'view' + viewwhat + + d = dict(zip(range(10), (range(11, 20)))) + for name in "keys", "values", "items": + meth = getattr(six, "view" + name) + view = meth(d) + assert set(view) == set(getattr(d, name)()) + + +def test_advance_iterator(): + assert six.next is six.advance_iterator + l = [1, 2] + it = iter(l) + assert six.next(it) == 1 + assert six.next(it) == 2 + pytest.raises(StopIteration, six.next, it) + pytest.raises(StopIteration, six.next, it) + + +def test_iterator(): + class myiter(six.Iterator): + def __next__(self): + return 13 + assert six.advance_iterator(myiter()) == 13 + class myitersub(myiter): + def __next__(self): + return 14 + assert six.advance_iterator(myitersub()) == 14 + + +def test_callable(): + class X: + def __call__(self): + pass + def method(self): + pass + assert six.callable(X) + assert six.callable(X()) + assert six.callable(test_callable) + assert six.callable(hasattr) + assert six.callable(X.method) + assert six.callable(X().method) + assert not six.callable(4) + assert not six.callable("string") + + +def test_create_bound_method(): + class X(object): + pass + def f(self): + return self + x = X() + b = six.create_bound_method(f, x) + assert isinstance(b, types.MethodType) + assert b() is x + + +def test_create_unbound_method(): + class X(object): + pass + + def f(self): + return self + u = six.create_unbound_method(f, X) + pytest.raises(TypeError, u) + if six.PY2: + assert isinstance(u, types.MethodType) + x = X() + assert f(x) is x + + +if six.PY3: + + def test_b(): + data = six.b("\xff") + assert isinstance(data, bytes) + assert len(data) == 1 + assert data == bytes([255]) + + + def test_u(): + s = six.u("hi \u0439 \U00000439 \\ \\\\ \n") + assert isinstance(s, str) + assert s == "hi \u0439 \U00000439 \\ \\\\ \n" + +else: + + def test_b(): + data = six.b("\xff") + assert isinstance(data, str) + assert len(data) == 1 + assert data == "\xff" + + + def test_u(): + s = six.u("hi \u0439 \U00000439 \\ \\\\ \n") + assert isinstance(s, unicode) + assert s == "hi \xd0\xb9 \xd0\xb9 \\ \\\\ \n".decode("utf8") + + +def test_u_escapes(): + s = six.u("\u1234") + assert len(s) == 1 + + +def test_unichr(): + assert six.u("\u1234") == six.unichr(0x1234) + assert type(six.u("\u1234")) is type(six.unichr(0x1234)) + + +def test_int2byte(): + assert six.int2byte(3) == six.b("\x03") + pytest.raises(Exception, six.int2byte, 256) + + +def test_byte2int(): + assert six.byte2int(six.b("\x03")) == 3 + assert six.byte2int(six.b("\x03\x04")) == 3 + pytest.raises(IndexError, six.byte2int, six.b("")) + + +def test_bytesindex(): + assert six.indexbytes(six.b("hello"), 3) == ord("l") + + +def test_bytesiter(): + it = six.iterbytes(six.b("hi")) + assert six.next(it) == ord("h") + assert six.next(it) == ord("i") + pytest.raises(StopIteration, six.next, it) + + +def test_StringIO(): + fp = six.StringIO() + fp.write(six.u("hello")) + assert fp.getvalue() == six.u("hello") + + +def test_BytesIO(): + fp = six.BytesIO() + fp.write(six.b("hello")) + assert fp.getvalue() == six.b("hello") + + +def test_exec_(): + def f(): + l = [] + six.exec_("l.append(1)") + assert l == [1] + f() + ns = {} + six.exec_("x = 42", ns) + assert ns["x"] == 42 + glob = {} + loc = {} + six.exec_("global y; y = 42; x = 12", glob, loc) + assert glob["y"] == 42 + assert "x" not in glob + assert loc["x"] == 12 + assert "y" not in loc + + +def test_reraise(): + def get_next(tb): + if six.PY3: + return tb.tb_next.tb_next + else: + return tb.tb_next + e = Exception("blah") + try: + raise e + except Exception: + tp, val, tb = sys.exc_info() + try: + six.reraise(tp, val, tb) + except Exception: + tp2, value2, tb2 = sys.exc_info() + assert tp2 is Exception + assert value2 is e + assert tb is get_next(tb2) + try: + six.reraise(tp, val) + except Exception: + tp2, value2, tb2 = sys.exc_info() + assert tp2 is Exception + assert value2 is e + assert tb2 is not tb + try: + six.reraise(tp, val, tb2) + except Exception: + tp2, value2, tb3 = sys.exc_info() + assert tp2 is Exception + assert value2 is e + assert get_next(tb3) is tb2 + try: + six.reraise(tp, None, tb) + except Exception: + tp2, value2, tb2 = sys.exc_info() + assert tp2 is Exception + assert value2 is not val + assert isinstance(value2, Exception) + assert tb is get_next(tb2) + + +def test_raise_from(): + try: + try: + raise Exception("blah") + except Exception: + ctx = sys.exc_info()[1] + f = Exception("foo") + six.raise_from(f, None) + except Exception: + tp, val, tb = sys.exc_info() + if sys.version_info[:2] > (3, 0): + # We should have done a raise f from None equivalent. + assert val.__cause__ is None + assert val.__context__ is ctx + if sys.version_info[:2] >= (3, 3): + # And that should suppress the context on the exception. + assert val.__suppress_context__ + # For all versions the outer exception should have raised successfully. + assert str(val) == "foo" + + +def test_print_(): + save = sys.stdout + out = sys.stdout = six.moves.StringIO() + try: + six.print_("Hello,", "person!") + finally: + sys.stdout = save + assert out.getvalue() == "Hello, person!\n" + out = six.StringIO() + six.print_("Hello,", "person!", file=out) + assert out.getvalue() == "Hello, person!\n" + out = six.StringIO() + six.print_("Hello,", "person!", file=out, end="") + assert out.getvalue() == "Hello, person!" + out = six.StringIO() + six.print_("Hello,", "person!", file=out, sep="X") + assert out.getvalue() == "Hello,Xperson!\n" + out = six.StringIO() + six.print_(six.u("Hello,"), six.u("person!"), file=out) + result = out.getvalue() + assert isinstance(result, six.text_type) + assert result == six.u("Hello, person!\n") + six.print_("Hello", file=None) # This works. + out = six.StringIO() + six.print_(None, file=out) + assert out.getvalue() == "None\n" + class FlushableStringIO(six.StringIO): + def __init__(self): + six.StringIO.__init__(self) + self.flushed = False + def flush(self): + self.flushed = True + out = FlushableStringIO() + six.print_("Hello", file=out) + assert not out.flushed + six.print_("Hello", file=out, flush=True) + assert out.flushed + + +@pytest.mark.skipif("sys.version_info[:2] >= (2, 6)") +def test_print_encoding(monkeypatch): + # Fool the type checking in print_. + monkeypatch.setattr(six, "file", six.BytesIO, raising=False) + out = six.BytesIO() + out.encoding = "utf-8" + out.errors = None + six.print_(six.u("\u053c"), end="", file=out) + assert out.getvalue() == six.b("\xd4\xbc") + out = six.BytesIO() + out.encoding = "ascii" + out.errors = "strict" + pytest.raises(UnicodeEncodeError, six.print_, six.u("\u053c"), file=out) + out.errors = "backslashreplace" + six.print_(six.u("\u053c"), end="", file=out) + assert out.getvalue() == six.b("\\u053c") + + +def test_print_exceptions(): + pytest.raises(TypeError, six.print_, x=3) + pytest.raises(TypeError, six.print_, end=3) + pytest.raises(TypeError, six.print_, sep=42) + + +def test_with_metaclass(): + class Meta(type): + pass + class X(six.with_metaclass(Meta)): + pass + assert type(X) is Meta + assert issubclass(X, object) + class Base(object): + pass + class X(six.with_metaclass(Meta, Base)): + pass + assert type(X) is Meta + assert issubclass(X, Base) + class Base2(object): + pass + class X(six.with_metaclass(Meta, Base, Base2)): + pass + assert type(X) is Meta + assert issubclass(X, Base) + assert issubclass(X, Base2) + assert X.__mro__ == (X, Base, Base2, object) + class X(six.with_metaclass(Meta)): + pass + class MetaSub(Meta): + pass + class Y(six.with_metaclass(MetaSub, X)): + pass + assert type(Y) is MetaSub + assert Y.__mro__ == (Y, X, object) + + +@pytest.mark.skipif("sys.version_info[:2] < (2, 7)") +def test_with_metaclass_typing(): + try: + import typing + except ImportError: + pytest.skip("typing module required") + class Meta(type): + pass + if sys.version_info[:2] < (3, 7): + # Generics with custom metaclasses were broken on older versions. + class Meta(Meta, typing.GenericMeta): + pass + T = typing.TypeVar('T') + class G(six.with_metaclass(Meta, typing.Generic[T])): + pass + class GA(six.with_metaclass(abc.ABCMeta, typing.Generic[T])): + pass + assert isinstance(G, Meta) + assert isinstance(GA, abc.ABCMeta) + assert G[int] is not G[G[int]] + assert GA[int] is not GA[GA[int]] + assert G.__bases__ == (typing.Generic,) + assert G.__orig_bases__ == (typing.Generic[T],) + + +@pytest.mark.skipif("sys.version_info[:2] < (3, 7)") +def test_with_metaclass_pep_560(): + class Meta(type): + pass + class A: + pass + class B: + pass + class Fake: + def __mro_entries__(self, bases): + return (A, B) + fake = Fake() + class G(six.with_metaclass(Meta, fake)): + pass + class GA(six.with_metaclass(abc.ABCMeta, fake)): + pass + assert isinstance(G, Meta) + assert isinstance(GA, abc.ABCMeta) + assert G.__bases__ == (A, B) + assert G.__orig_bases__ == (fake,) + + +@pytest.mark.skipif("sys.version_info[:2] < (3, 0)") +def test_with_metaclass_prepare(): + """Test that with_metaclass causes Meta.__prepare__ to be called with the correct arguments.""" + + class MyDict(dict): + pass + + class Meta(type): + + @classmethod + def __prepare__(cls, name, bases): + namespace = MyDict(super().__prepare__(name, bases), cls=cls, bases=bases) + namespace['namespace'] = namespace + return namespace + + class Base(object): + pass + + bases = (Base,) + + class X(six.with_metaclass(Meta, *bases)): + pass + + assert getattr(X, 'cls', type) is Meta + assert getattr(X, 'bases', ()) == bases + assert isinstance(getattr(X, 'namespace', {}), MyDict) + + +def test_wraps(): + def f(g): + @six.wraps(g) + def w(): + return 42 + return w + def k(): + pass + original_k = k + k = f(f(k)) + assert hasattr(k, '__wrapped__') + k = k.__wrapped__ + assert hasattr(k, '__wrapped__') + k = k.__wrapped__ + assert k is original_k + assert not hasattr(k, '__wrapped__') + + def f(g, assign, update): + def w(): + return 42 + w.glue = {"foo" : "bar"} + return six.wraps(g, assign, update)(w) + k.glue = {"melon" : "egg"} + k.turnip = 43 + k = f(k, ["turnip"], ["glue"]) + assert k.__name__ == "w" + assert k.turnip == 43 + assert k.glue == {"melon" : "egg", "foo" : "bar"} + + +def test_add_metaclass(): + class Meta(type): + pass + class X: + "success" + X = six.add_metaclass(Meta)(X) + assert type(X) is Meta + assert issubclass(X, object) + assert X.__module__ == __name__ + assert X.__doc__ == "success" + class Base(object): + pass + class X(Base): + pass + X = six.add_metaclass(Meta)(X) + assert type(X) is Meta + assert issubclass(X, Base) + class Base2(object): + pass + class X(Base, Base2): + pass + X = six.add_metaclass(Meta)(X) + assert type(X) is Meta + assert issubclass(X, Base) + assert issubclass(X, Base2) + + # Test a second-generation subclass of a type. + class Meta1(type): + m1 = "m1" + class Meta2(Meta1): + m2 = "m2" + class Base: + b = "b" + Base = six.add_metaclass(Meta1)(Base) + class X(Base): + x = "x" + X = six.add_metaclass(Meta2)(X) + assert type(X) is Meta2 + assert issubclass(X, Base) + assert type(Base) is Meta1 + assert "__dict__" not in vars(X) + instance = X() + instance.attr = "test" + assert vars(instance) == {"attr": "test"} + assert instance.b == Base.b + assert instance.x == X.x + + # Test a class with slots. + class MySlots(object): + __slots__ = ["a", "b"] + MySlots = six.add_metaclass(Meta1)(MySlots) + + assert MySlots.__slots__ == ["a", "b"] + instance = MySlots() + instance.a = "foo" + pytest.raises(AttributeError, setattr, instance, "c", "baz") + + # Test a class with string for slots. + class MyStringSlots(object): + __slots__ = "ab" + MyStringSlots = six.add_metaclass(Meta1)(MyStringSlots) + assert MyStringSlots.__slots__ == "ab" + instance = MyStringSlots() + instance.ab = "foo" + pytest.raises(AttributeError, setattr, instance, "a", "baz") + pytest.raises(AttributeError, setattr, instance, "b", "baz") + + class MySlotsWeakref(object): + __slots__ = "__weakref__", + MySlotsWeakref = six.add_metaclass(Meta)(MySlotsWeakref) + assert type(MySlotsWeakref) is Meta + + +@pytest.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 + + +@pytest.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): + def test(self): + with self.assertRaises(AssertionError): + six.assertCountEqual(self, (1, 2), [3, 4, 5]) + + six.assertCountEqual(self, (1, 2), [2, 1]) + + TestAssertCountEqual('test').test() + + +@pytest.mark.skipif("sys.version_info[:2] < (2, 7)") +def test_assertRegex(): + class TestAssertRegex(unittest.TestCase): + def test(self): + with self.assertRaises(AssertionError): + six.assertRegex(self, 'test', r'^a') + + six.assertRegex(self, 'test', r'^t') + + TestAssertRegex('test').test() + + +@pytest.mark.skipif("sys.version_info[:2] < (2, 7)") +def test_assertRaisesRegex(): + class TestAssertRaisesRegex(unittest.TestCase): + def test(self): + with six.assertRaisesRegex(self, AssertionError, '^Foo'): + raise AssertionError('Foo') + + with self.assertRaises(AssertionError): + with six.assertRaisesRegex(self, AssertionError, r'^Foo'): + raise AssertionError('Bar') + + TestAssertRaisesRegex('test').test() + + +def test_python_2_unicode_compatible(): + @six.python_2_unicode_compatible + class MyTest(object): + def __str__(self): + return six.u('hello') + + def __bytes__(self): + return six.b('hello') + + my_test = MyTest() + + if six.PY2: + assert str(my_test) == six.b("hello") + assert unicode(my_test) == six.u("hello") + elif six.PY3: + assert bytes(my_test) == six.b("hello") + 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 pytest.raises(TypeError): + six.ensure_str(8) + + def test_errors_and_encoding(self): + six.ensure_binary(self.UNICODE_EMOJI, encoding='latin-1', errors='ignore') + with pytest.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) |