diff options
author | shadchin <shadchin@yandex-team.ru> | 2022-02-10 16:44:30 +0300 |
---|---|---|
committer | Daniil Cherednik <dcherednik@yandex-team.ru> | 2022-02-10 16:44:30 +0300 |
commit | 2598ef1d0aee359b4b6d5fdd1758916d5907d04f (patch) | |
tree | 012bb94d777798f1f56ac1cec429509766d05181 /contrib/python/six/tests/test_six.py | |
parent | 6751af0b0c1b952fede40b19b71da8025b5d8bcf (diff) | |
download | ydb-2598ef1d0aee359b4b6d5fdd1758916d5907d04f.tar.gz |
Restoring authorship annotation for <shadchin@yandex-team.ru>. Commit 1 of 2.
Diffstat (limited to 'contrib/python/six/tests/test_six.py')
-rw-r--r-- | contrib/python/six/tests/test_six.py | 2082 |
1 files changed, 1041 insertions, 1041 deletions
diff --git a/contrib/python/six/tests/test_six.py b/contrib/python/six/tests/test_six.py index 7b8b03b5e6..f2247a3973 100644 --- a/contrib/python/six/tests/test_six.py +++ b/contrib/python/six/tests/test_six.py @@ -1,1041 +1,1041 @@ -# Copyright (c) 2010-2020 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 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.startswith("dbm_gnu") and not have_gdbm: - pytest.skip("requires gdbm") - raise - 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.""" - 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.""" - 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.""" - 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.""" - 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.""" - 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) - - -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() - - -def test_dictionary_views(): - 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 - # 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 - - -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) - - -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"} - w.xyzzy = {"qux": "quux"} - return six.wraps(g, assign, update)(w) - k.glue = {"melon": "egg"} - k.turnip = 43 - k = f(k, ["turnip", "baz"], ["glue", "xyzzy"]) - assert k.__name__ == "w" - assert k.turnip == 43 - assert not hasattr(k, "baz") - assert k.glue == {"melon": "egg", "foo": "bar"} - assert k.xyzzy == {"qux": "quux"} - - -def test_wraps_raises_on_missing_updated_field_on_wrapper(): - """Ensure six.wraps doesn't ignore missing attrs wrapper. - - Because that's what happens in Py3's functools.update_wrapper. - """ - def wrapped(): - pass - - def wrapper(): - pass - - with pytest.raises(AttributeError, match='has no attribute.*xyzzy'): - six.wraps(wrapped, [], ['xyzzy'])(wrapper) - - - -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 - - -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() - - -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() - - -def test_assertNotRegex(): - class TestAssertNotRegex(unittest.TestCase): - def test(self): - with self.assertRaises(AssertionError): - six.assertNotRegex(self, 'test', r'^t') - - six.assertNotRegex(self, 'test', r'^a') - - TestAssertNotRegex('test').test() - - -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) +# Copyright (c) 2010-2020 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 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.startswith("dbm_gnu") and not have_gdbm: + pytest.skip("requires gdbm") + raise + 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.""" + 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.""" + 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.""" + 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.""" + 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.""" + 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) + + +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() + + +def test_dictionary_views(): + 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 + # 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 + + +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) + + +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"} + w.xyzzy = {"qux": "quux"} + return six.wraps(g, assign, update)(w) + k.glue = {"melon": "egg"} + k.turnip = 43 + k = f(k, ["turnip", "baz"], ["glue", "xyzzy"]) + assert k.__name__ == "w" + assert k.turnip == 43 + assert not hasattr(k, "baz") + assert k.glue == {"melon": "egg", "foo": "bar"} + assert k.xyzzy == {"qux": "quux"} + + +def test_wraps_raises_on_missing_updated_field_on_wrapper(): + """Ensure six.wraps doesn't ignore missing attrs wrapper. + + Because that's what happens in Py3's functools.update_wrapper. + """ + def wrapped(): + pass + + def wrapper(): + pass + + with pytest.raises(AttributeError, match='has no attribute.*xyzzy'): + six.wraps(wrapped, [], ['xyzzy'])(wrapper) + + + +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 + + +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() + + +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() + + +def test_assertNotRegex(): + class TestAssertNotRegex(unittest.TestCase): + def test(self): + with self.assertRaises(AssertionError): + six.assertNotRegex(self, 'test', r'^t') + + six.assertNotRegex(self, 'test', r'^a') + + TestAssertNotRegex('test').test() + + +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) |