test_six.py 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041
  1. # Copyright (c) 2010-2020 Benjamin Peterson
  2. #
  3. # Permission is hereby granted, free of charge, to any person obtaining a copy
  4. # of this software and associated documentation files (the "Software"), to deal
  5. # in the Software without restriction, including without limitation the rights
  6. # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  7. # copies of the Software, and to permit persons to whom the Software is
  8. # furnished to do so, subject to the following conditions:
  9. #
  10. # The above copyright notice and this permission notice shall be included in all
  11. # copies or substantial portions of the Software.
  12. #
  13. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  14. # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  15. # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  16. # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  17. # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  18. # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  19. # SOFTWARE.
  20. import operator
  21. import sys
  22. import types
  23. import unittest
  24. import abc
  25. import pytest
  26. import six
  27. def test_add_doc():
  28. def f():
  29. """Icky doc"""
  30. pass
  31. six._add_doc(f, """New doc""")
  32. assert f.__doc__ == "New doc"
  33. def test_import_module():
  34. from logging import handlers
  35. m = six._import_module("logging.handlers")
  36. assert m is handlers
  37. def test_integer_types():
  38. assert isinstance(1, six.integer_types)
  39. assert isinstance(-1, six.integer_types)
  40. assert isinstance(six.MAXSIZE + 23, six.integer_types)
  41. assert not isinstance(.1, six.integer_types)
  42. def test_string_types():
  43. assert isinstance("hi", six.string_types)
  44. assert isinstance(six.u("hi"), six.string_types)
  45. assert issubclass(six.text_type, six.string_types)
  46. def test_class_types():
  47. class X:
  48. pass
  49. class Y(object):
  50. pass
  51. assert isinstance(X, six.class_types)
  52. assert isinstance(Y, six.class_types)
  53. assert not isinstance(X(), six.class_types)
  54. def test_text_type():
  55. assert type(six.u("hi")) is six.text_type
  56. def test_binary_type():
  57. assert type(six.b("hi")) is six.binary_type
  58. def test_MAXSIZE():
  59. try:
  60. # This shouldn't raise an overflow error.
  61. six.MAXSIZE.__index__()
  62. except AttributeError:
  63. # Before Python 2.6.
  64. pass
  65. pytest.raises(
  66. (ValueError, OverflowError),
  67. operator.mul, [None], six.MAXSIZE + 1)
  68. def test_lazy():
  69. if six.PY3:
  70. html_name = "html.parser"
  71. else:
  72. html_name = "HTMLParser"
  73. assert html_name not in sys.modules
  74. mod = six.moves.html_parser
  75. assert sys.modules[html_name] is mod
  76. assert "htmlparser" not in six._MovedItems.__dict__
  77. try:
  78. import _tkinter
  79. except ImportError:
  80. have_tkinter = False
  81. else:
  82. have_tkinter = True
  83. have_gdbm = True
  84. try:
  85. import gdbm
  86. except ImportError:
  87. try:
  88. import dbm.gnu
  89. except ImportError:
  90. have_gdbm = False
  91. @pytest.mark.parametrize("item_name",
  92. [item.name for item in six._moved_attributes])
  93. def test_move_items(item_name):
  94. """Ensure that everything loads correctly."""
  95. try:
  96. item = getattr(six.moves, item_name)
  97. if isinstance(item, types.ModuleType):
  98. __import__("six.moves." + item_name)
  99. except ImportError:
  100. if item_name == "winreg" and not sys.platform.startswith("win"):
  101. pytest.skip("Windows only module")
  102. if item_name.startswith("tkinter"):
  103. if not have_tkinter:
  104. pytest.skip("requires tkinter")
  105. if item_name.startswith("dbm_gnu") and not have_gdbm:
  106. pytest.skip("requires gdbm")
  107. raise
  108. assert item_name in dir(six.moves)
  109. @pytest.mark.parametrize("item_name",
  110. [item.name for item in six._urllib_parse_moved_attributes])
  111. def test_move_items_urllib_parse(item_name):
  112. """Ensure that everything loads correctly."""
  113. assert item_name in dir(six.moves.urllib.parse)
  114. getattr(six.moves.urllib.parse, item_name)
  115. @pytest.mark.parametrize("item_name",
  116. [item.name for item in six._urllib_error_moved_attributes])
  117. def test_move_items_urllib_error(item_name):
  118. """Ensure that everything loads correctly."""
  119. assert item_name in dir(six.moves.urllib.error)
  120. getattr(six.moves.urllib.error, item_name)
  121. @pytest.mark.parametrize("item_name",
  122. [item.name for item in six._urllib_request_moved_attributes])
  123. def test_move_items_urllib_request(item_name):
  124. """Ensure that everything loads correctly."""
  125. assert item_name in dir(six.moves.urllib.request)
  126. getattr(six.moves.urllib.request, item_name)
  127. @pytest.mark.parametrize("item_name",
  128. [item.name for item in six._urllib_response_moved_attributes])
  129. def test_move_items_urllib_response(item_name):
  130. """Ensure that everything loads correctly."""
  131. assert item_name in dir(six.moves.urllib.response)
  132. getattr(six.moves.urllib.response, item_name)
  133. @pytest.mark.parametrize("item_name",
  134. [item.name for item in six._urllib_robotparser_moved_attributes])
  135. def test_move_items_urllib_robotparser(item_name):
  136. """Ensure that everything loads correctly."""
  137. assert item_name in dir(six.moves.urllib.robotparser)
  138. getattr(six.moves.urllib.robotparser, item_name)
  139. def test_import_moves_error_1():
  140. from six.moves.urllib.parse import urljoin
  141. from six import moves
  142. # In 1.4.1: AttributeError: 'Module_six_moves_urllib_parse' object has no attribute 'urljoin'
  143. assert moves.urllib.parse.urljoin
  144. def test_import_moves_error_2():
  145. from six import moves
  146. assert moves.urllib.parse.urljoin
  147. # In 1.4.1: ImportError: cannot import name urljoin
  148. from six.moves.urllib.parse import urljoin
  149. def test_import_moves_error_3():
  150. from six.moves.urllib.parse import urljoin
  151. # In 1.4.1: ImportError: cannot import name urljoin
  152. from six.moves.urllib_parse import urljoin
  153. def test_from_imports():
  154. from six.moves.queue import Queue
  155. assert isinstance(Queue, six.class_types)
  156. from six.moves.configparser import ConfigParser
  157. assert isinstance(ConfigParser, six.class_types)
  158. def test_filter():
  159. from six.moves import filter
  160. f = filter(lambda x: x % 2, range(10))
  161. assert six.advance_iterator(f) == 1
  162. def test_filter_false():
  163. from six.moves import filterfalse
  164. f = filterfalse(lambda x: x % 3, range(10))
  165. assert six.advance_iterator(f) == 0
  166. assert six.advance_iterator(f) == 3
  167. assert six.advance_iterator(f) == 6
  168. def test_map():
  169. from six.moves import map
  170. assert six.advance_iterator(map(lambda x: x + 1, range(2))) == 1
  171. def test_getoutput():
  172. from six.moves import getoutput
  173. output = getoutput('echo "foo"')
  174. assert output == 'foo'
  175. def test_zip():
  176. from six.moves import zip
  177. assert six.advance_iterator(zip(range(2), range(2))) == (0, 0)
  178. def test_zip_longest():
  179. from six.moves import zip_longest
  180. it = zip_longest(range(2), range(1))
  181. assert six.advance_iterator(it) == (0, 0)
  182. assert six.advance_iterator(it) == (1, None)
  183. class TestCustomizedMoves:
  184. def teardown_method(self, meth):
  185. try:
  186. del six._MovedItems.spam
  187. except AttributeError:
  188. pass
  189. try:
  190. del six.moves.__dict__["spam"]
  191. except KeyError:
  192. pass
  193. def test_moved_attribute(self):
  194. attr = six.MovedAttribute("spam", "foo", "bar")
  195. if six.PY3:
  196. assert attr.mod == "bar"
  197. else:
  198. assert attr.mod == "foo"
  199. assert attr.attr == "spam"
  200. attr = six.MovedAttribute("spam", "foo", "bar", "lemma")
  201. assert attr.attr == "lemma"
  202. attr = six.MovedAttribute("spam", "foo", "bar", "lemma", "theorm")
  203. if six.PY3:
  204. assert attr.attr == "theorm"
  205. else:
  206. assert attr.attr == "lemma"
  207. def test_moved_module(self):
  208. attr = six.MovedModule("spam", "foo")
  209. if six.PY3:
  210. assert attr.mod == "spam"
  211. else:
  212. assert attr.mod == "foo"
  213. attr = six.MovedModule("spam", "foo", "bar")
  214. if six.PY3:
  215. assert attr.mod == "bar"
  216. else:
  217. assert attr.mod == "foo"
  218. def test_custom_move_module(self):
  219. attr = six.MovedModule("spam", "six", "six")
  220. six.add_move(attr)
  221. six.remove_move("spam")
  222. assert not hasattr(six.moves, "spam")
  223. attr = six.MovedModule("spam", "six", "six")
  224. six.add_move(attr)
  225. from six.moves import spam
  226. assert spam is six
  227. six.remove_move("spam")
  228. assert not hasattr(six.moves, "spam")
  229. def test_custom_move_attribute(self):
  230. attr = six.MovedAttribute("spam", "six", "six", "u", "u")
  231. six.add_move(attr)
  232. six.remove_move("spam")
  233. assert not hasattr(six.moves, "spam")
  234. attr = six.MovedAttribute("spam", "six", "six", "u", "u")
  235. six.add_move(attr)
  236. from six.moves import spam
  237. assert spam is six.u
  238. six.remove_move("spam")
  239. assert not hasattr(six.moves, "spam")
  240. def test_empty_remove(self):
  241. pytest.raises(AttributeError, six.remove_move, "eggs")
  242. def test_get_unbound_function():
  243. class X(object):
  244. def m(self):
  245. pass
  246. assert six.get_unbound_function(X.m) is X.__dict__["m"]
  247. def test_get_method_self():
  248. class X(object):
  249. def m(self):
  250. pass
  251. x = X()
  252. assert six.get_method_self(x.m) is x
  253. pytest.raises(AttributeError, six.get_method_self, 42)
  254. def test_get_method_function():
  255. class X(object):
  256. def m(self):
  257. pass
  258. x = X()
  259. assert six.get_method_function(x.m) is X.__dict__["m"]
  260. pytest.raises(AttributeError, six.get_method_function, hasattr)
  261. def test_get_function_closure():
  262. def f():
  263. x = 42
  264. def g():
  265. return x
  266. return g
  267. cell = six.get_function_closure(f())[0]
  268. assert type(cell).__name__ == "cell"
  269. def test_get_function_code():
  270. def f():
  271. pass
  272. assert isinstance(six.get_function_code(f), types.CodeType)
  273. if not hasattr(sys, "pypy_version_info"):
  274. pytest.raises(AttributeError, six.get_function_code, hasattr)
  275. def test_get_function_defaults():
  276. def f(x, y=3, b=4):
  277. pass
  278. assert six.get_function_defaults(f) == (3, 4)
  279. def test_get_function_globals():
  280. def f():
  281. pass
  282. assert six.get_function_globals(f) is globals()
  283. def test_dictionary_iterators(monkeypatch):
  284. def stock_method_name(iterwhat):
  285. """Given a method suffix like "lists" or "values", return the name
  286. of the dict method that delivers those on the version of Python
  287. we're running in."""
  288. if six.PY3:
  289. return iterwhat
  290. return 'iter' + iterwhat
  291. class MyDict(dict):
  292. if not six.PY3:
  293. def lists(self, **kw):
  294. return [1, 2, 3]
  295. def iterlists(self, **kw):
  296. return iter([1, 2, 3])
  297. f = MyDict.iterlists
  298. del MyDict.iterlists
  299. setattr(MyDict, stock_method_name('lists'), f)
  300. d = MyDict(zip(range(10), reversed(range(10))))
  301. for name in "keys", "values", "items", "lists":
  302. meth = getattr(six, "iter" + name)
  303. it = meth(d)
  304. assert not isinstance(it, list)
  305. assert list(it) == list(getattr(d, name)())
  306. pytest.raises(StopIteration, six.advance_iterator, it)
  307. record = []
  308. def with_kw(*args, **kw):
  309. record.append(kw["kw"])
  310. return old(*args)
  311. old = getattr(MyDict, stock_method_name(name))
  312. monkeypatch.setattr(MyDict, stock_method_name(name), with_kw)
  313. meth(d, kw=42)
  314. assert record == [42]
  315. monkeypatch.undo()
  316. def test_dictionary_views():
  317. d = dict(zip(range(10), (range(11, 20))))
  318. for name in "keys", "values", "items":
  319. meth = getattr(six, "view" + name)
  320. view = meth(d)
  321. assert set(view) == set(getattr(d, name)())
  322. def test_advance_iterator():
  323. assert six.next is six.advance_iterator
  324. l = [1, 2]
  325. it = iter(l)
  326. assert six.next(it) == 1
  327. assert six.next(it) == 2
  328. pytest.raises(StopIteration, six.next, it)
  329. pytest.raises(StopIteration, six.next, it)
  330. def test_iterator():
  331. class myiter(six.Iterator):
  332. def __next__(self):
  333. return 13
  334. assert six.advance_iterator(myiter()) == 13
  335. class myitersub(myiter):
  336. def __next__(self):
  337. return 14
  338. assert six.advance_iterator(myitersub()) == 14
  339. def test_callable():
  340. class X:
  341. def __call__(self):
  342. pass
  343. def method(self):
  344. pass
  345. assert six.callable(X)
  346. assert six.callable(X())
  347. assert six.callable(test_callable)
  348. assert six.callable(hasattr)
  349. assert six.callable(X.method)
  350. assert six.callable(X().method)
  351. assert not six.callable(4)
  352. assert not six.callable("string")
  353. def test_create_bound_method():
  354. class X(object):
  355. pass
  356. def f(self):
  357. return self
  358. x = X()
  359. b = six.create_bound_method(f, x)
  360. assert isinstance(b, types.MethodType)
  361. assert b() is x
  362. def test_create_unbound_method():
  363. class X(object):
  364. pass
  365. def f(self):
  366. return self
  367. u = six.create_unbound_method(f, X)
  368. pytest.raises(TypeError, u)
  369. if six.PY2:
  370. assert isinstance(u, types.MethodType)
  371. x = X()
  372. assert f(x) is x
  373. if six.PY3:
  374. def test_b():
  375. data = six.b("\xff")
  376. assert isinstance(data, bytes)
  377. assert len(data) == 1
  378. assert data == bytes([255])
  379. def test_u():
  380. s = six.u("hi \u0439 \U00000439 \\ \\\\ \n")
  381. assert isinstance(s, str)
  382. assert s == "hi \u0439 \U00000439 \\ \\\\ \n"
  383. else:
  384. def test_b():
  385. data = six.b("\xff")
  386. assert isinstance(data, str)
  387. assert len(data) == 1
  388. assert data == "\xff"
  389. def test_u():
  390. s = six.u("hi \u0439 \U00000439 \\ \\\\ \n")
  391. assert isinstance(s, unicode)
  392. assert s == "hi \xd0\xb9 \xd0\xb9 \\ \\\\ \n".decode("utf8")
  393. def test_u_escapes():
  394. s = six.u("\u1234")
  395. assert len(s) == 1
  396. def test_unichr():
  397. assert six.u("\u1234") == six.unichr(0x1234)
  398. assert type(six.u("\u1234")) is type(six.unichr(0x1234))
  399. def test_int2byte():
  400. assert six.int2byte(3) == six.b("\x03")
  401. pytest.raises(Exception, six.int2byte, 256)
  402. def test_byte2int():
  403. assert six.byte2int(six.b("\x03")) == 3
  404. assert six.byte2int(six.b("\x03\x04")) == 3
  405. pytest.raises(IndexError, six.byte2int, six.b(""))
  406. def test_bytesindex():
  407. assert six.indexbytes(six.b("hello"), 3) == ord("l")
  408. def test_bytesiter():
  409. it = six.iterbytes(six.b("hi"))
  410. assert six.next(it) == ord("h")
  411. assert six.next(it) == ord("i")
  412. pytest.raises(StopIteration, six.next, it)
  413. def test_StringIO():
  414. fp = six.StringIO()
  415. fp.write(six.u("hello"))
  416. assert fp.getvalue() == six.u("hello")
  417. def test_BytesIO():
  418. fp = six.BytesIO()
  419. fp.write(six.b("hello"))
  420. assert fp.getvalue() == six.b("hello")
  421. def test_exec_():
  422. def f():
  423. l = []
  424. six.exec_("l.append(1)")
  425. assert l == [1]
  426. f()
  427. ns = {}
  428. six.exec_("x = 42", ns)
  429. assert ns["x"] == 42
  430. glob = {}
  431. loc = {}
  432. six.exec_("global y; y = 42; x = 12", glob, loc)
  433. assert glob["y"] == 42
  434. assert "x" not in glob
  435. assert loc["x"] == 12
  436. assert "y" not in loc
  437. def test_reraise():
  438. def get_next(tb):
  439. if six.PY3:
  440. return tb.tb_next.tb_next
  441. else:
  442. return tb.tb_next
  443. e = Exception("blah")
  444. try:
  445. raise e
  446. except Exception:
  447. tp, val, tb = sys.exc_info()
  448. try:
  449. six.reraise(tp, val, tb)
  450. except Exception:
  451. tp2, value2, tb2 = sys.exc_info()
  452. assert tp2 is Exception
  453. assert value2 is e
  454. assert tb is get_next(tb2)
  455. try:
  456. six.reraise(tp, val)
  457. except Exception:
  458. tp2, value2, tb2 = sys.exc_info()
  459. assert tp2 is Exception
  460. assert value2 is e
  461. assert tb2 is not tb
  462. try:
  463. six.reraise(tp, val, tb2)
  464. except Exception:
  465. tp2, value2, tb3 = sys.exc_info()
  466. assert tp2 is Exception
  467. assert value2 is e
  468. assert get_next(tb3) is tb2
  469. try:
  470. six.reraise(tp, None, tb)
  471. except Exception:
  472. tp2, value2, tb2 = sys.exc_info()
  473. assert tp2 is Exception
  474. assert value2 is not val
  475. assert isinstance(value2, Exception)
  476. assert tb is get_next(tb2)
  477. def test_raise_from():
  478. try:
  479. try:
  480. raise Exception("blah")
  481. except Exception:
  482. ctx = sys.exc_info()[1]
  483. f = Exception("foo")
  484. six.raise_from(f, None)
  485. except Exception:
  486. tp, val, tb = sys.exc_info()
  487. if sys.version_info[:2] > (3, 0):
  488. # We should have done a raise f from None equivalent.
  489. assert val.__cause__ is None
  490. assert val.__context__ is ctx
  491. # And that should suppress the context on the exception.
  492. assert val.__suppress_context__
  493. # For all versions the outer exception should have raised successfully.
  494. assert str(val) == "foo"
  495. def test_print_():
  496. save = sys.stdout
  497. out = sys.stdout = six.moves.StringIO()
  498. try:
  499. six.print_("Hello,", "person!")
  500. finally:
  501. sys.stdout = save
  502. assert out.getvalue() == "Hello, person!\n"
  503. out = six.StringIO()
  504. six.print_("Hello,", "person!", file=out)
  505. assert out.getvalue() == "Hello, person!\n"
  506. out = six.StringIO()
  507. six.print_("Hello,", "person!", file=out, end="")
  508. assert out.getvalue() == "Hello, person!"
  509. out = six.StringIO()
  510. six.print_("Hello,", "person!", file=out, sep="X")
  511. assert out.getvalue() == "Hello,Xperson!\n"
  512. out = six.StringIO()
  513. six.print_(six.u("Hello,"), six.u("person!"), file=out)
  514. result = out.getvalue()
  515. assert isinstance(result, six.text_type)
  516. assert result == six.u("Hello, person!\n")
  517. six.print_("Hello", file=None) # This works.
  518. out = six.StringIO()
  519. six.print_(None, file=out)
  520. assert out.getvalue() == "None\n"
  521. class FlushableStringIO(six.StringIO):
  522. def __init__(self):
  523. six.StringIO.__init__(self)
  524. self.flushed = False
  525. def flush(self):
  526. self.flushed = True
  527. out = FlushableStringIO()
  528. six.print_("Hello", file=out)
  529. assert not out.flushed
  530. six.print_("Hello", file=out, flush=True)
  531. assert out.flushed
  532. def test_print_exceptions():
  533. pytest.raises(TypeError, six.print_, x=3)
  534. pytest.raises(TypeError, six.print_, end=3)
  535. pytest.raises(TypeError, six.print_, sep=42)
  536. def test_with_metaclass():
  537. class Meta(type):
  538. pass
  539. class X(six.with_metaclass(Meta)):
  540. pass
  541. assert type(X) is Meta
  542. assert issubclass(X, object)
  543. class Base(object):
  544. pass
  545. class X(six.with_metaclass(Meta, Base)):
  546. pass
  547. assert type(X) is Meta
  548. assert issubclass(X, Base)
  549. class Base2(object):
  550. pass
  551. class X(six.with_metaclass(Meta, Base, Base2)):
  552. pass
  553. assert type(X) is Meta
  554. assert issubclass(X, Base)
  555. assert issubclass(X, Base2)
  556. assert X.__mro__ == (X, Base, Base2, object)
  557. class X(six.with_metaclass(Meta)):
  558. pass
  559. class MetaSub(Meta):
  560. pass
  561. class Y(six.with_metaclass(MetaSub, X)):
  562. pass
  563. assert type(Y) is MetaSub
  564. assert Y.__mro__ == (Y, X, object)
  565. def test_with_metaclass_typing():
  566. try:
  567. import typing
  568. except ImportError:
  569. pytest.skip("typing module required")
  570. class Meta(type):
  571. pass
  572. if sys.version_info[:2] < (3, 7):
  573. # Generics with custom metaclasses were broken on older versions.
  574. class Meta(Meta, typing.GenericMeta):
  575. pass
  576. T = typing.TypeVar('T')
  577. class G(six.with_metaclass(Meta, typing.Generic[T])):
  578. pass
  579. class GA(six.with_metaclass(abc.ABCMeta, typing.Generic[T])):
  580. pass
  581. assert isinstance(G, Meta)
  582. assert isinstance(GA, abc.ABCMeta)
  583. assert G[int] is not G[G[int]]
  584. assert GA[int] is not GA[GA[int]]
  585. assert G.__bases__ == (typing.Generic,)
  586. assert G.__orig_bases__ == (typing.Generic[T],)
  587. @pytest.mark.skipif("sys.version_info[:2] < (3, 7)")
  588. def test_with_metaclass_pep_560():
  589. class Meta(type):
  590. pass
  591. class A:
  592. pass
  593. class B:
  594. pass
  595. class Fake:
  596. def __mro_entries__(self, bases):
  597. return (A, B)
  598. fake = Fake()
  599. class G(six.with_metaclass(Meta, fake)):
  600. pass
  601. class GA(six.with_metaclass(abc.ABCMeta, fake)):
  602. pass
  603. assert isinstance(G, Meta)
  604. assert isinstance(GA, abc.ABCMeta)
  605. assert G.__bases__ == (A, B)
  606. assert G.__orig_bases__ == (fake,)
  607. @pytest.mark.skipif("sys.version_info[:2] < (3, 0)")
  608. def test_with_metaclass_prepare():
  609. """Test that with_metaclass causes Meta.__prepare__ to be called with the correct arguments."""
  610. class MyDict(dict):
  611. pass
  612. class Meta(type):
  613. @classmethod
  614. def __prepare__(cls, name, bases):
  615. namespace = MyDict(super().__prepare__(name, bases), cls=cls, bases=bases)
  616. namespace['namespace'] = namespace
  617. return namespace
  618. class Base(object):
  619. pass
  620. bases = (Base,)
  621. class X(six.with_metaclass(Meta, *bases)):
  622. pass
  623. assert getattr(X, 'cls', type) is Meta
  624. assert getattr(X, 'bases', ()) == bases
  625. assert isinstance(getattr(X, 'namespace', {}), MyDict)
  626. def test_wraps():
  627. def f(g):
  628. @six.wraps(g)
  629. def w():
  630. return 42
  631. return w
  632. def k():
  633. pass
  634. original_k = k
  635. k = f(f(k))
  636. assert hasattr(k, '__wrapped__')
  637. k = k.__wrapped__
  638. assert hasattr(k, '__wrapped__')
  639. k = k.__wrapped__
  640. assert k is original_k
  641. assert not hasattr(k, '__wrapped__')
  642. def f(g, assign, update):
  643. def w():
  644. return 42
  645. w.glue = {"foo": "bar"}
  646. w.xyzzy = {"qux": "quux"}
  647. return six.wraps(g, assign, update)(w)
  648. k.glue = {"melon": "egg"}
  649. k.turnip = 43
  650. k = f(k, ["turnip", "baz"], ["glue", "xyzzy"])
  651. assert k.__name__ == "w"
  652. assert k.turnip == 43
  653. assert not hasattr(k, "baz")
  654. assert k.glue == {"melon": "egg", "foo": "bar"}
  655. assert k.xyzzy == {"qux": "quux"}
  656. def test_wraps_raises_on_missing_updated_field_on_wrapper():
  657. """Ensure six.wraps doesn't ignore missing attrs wrapper.
  658. Because that's what happens in Py3's functools.update_wrapper.
  659. """
  660. def wrapped():
  661. pass
  662. def wrapper():
  663. pass
  664. with pytest.raises(AttributeError, match='has no attribute.*xyzzy'):
  665. six.wraps(wrapped, [], ['xyzzy'])(wrapper)
  666. def test_add_metaclass():
  667. class Meta(type):
  668. pass
  669. class X:
  670. "success"
  671. X = six.add_metaclass(Meta)(X)
  672. assert type(X) is Meta
  673. assert issubclass(X, object)
  674. assert X.__module__ == __name__
  675. assert X.__doc__ == "success"
  676. class Base(object):
  677. pass
  678. class X(Base):
  679. pass
  680. X = six.add_metaclass(Meta)(X)
  681. assert type(X) is Meta
  682. assert issubclass(X, Base)
  683. class Base2(object):
  684. pass
  685. class X(Base, Base2):
  686. pass
  687. X = six.add_metaclass(Meta)(X)
  688. assert type(X) is Meta
  689. assert issubclass(X, Base)
  690. assert issubclass(X, Base2)
  691. # Test a second-generation subclass of a type.
  692. class Meta1(type):
  693. m1 = "m1"
  694. class Meta2(Meta1):
  695. m2 = "m2"
  696. class Base:
  697. b = "b"
  698. Base = six.add_metaclass(Meta1)(Base)
  699. class X(Base):
  700. x = "x"
  701. X = six.add_metaclass(Meta2)(X)
  702. assert type(X) is Meta2
  703. assert issubclass(X, Base)
  704. assert type(Base) is Meta1
  705. assert "__dict__" not in vars(X)
  706. instance = X()
  707. instance.attr = "test"
  708. assert vars(instance) == {"attr": "test"}
  709. assert instance.b == Base.b
  710. assert instance.x == X.x
  711. # Test a class with slots.
  712. class MySlots(object):
  713. __slots__ = ["a", "b"]
  714. MySlots = six.add_metaclass(Meta1)(MySlots)
  715. assert MySlots.__slots__ == ["a", "b"]
  716. instance = MySlots()
  717. instance.a = "foo"
  718. pytest.raises(AttributeError, setattr, instance, "c", "baz")
  719. # Test a class with string for slots.
  720. class MyStringSlots(object):
  721. __slots__ = "ab"
  722. MyStringSlots = six.add_metaclass(Meta1)(MyStringSlots)
  723. assert MyStringSlots.__slots__ == "ab"
  724. instance = MyStringSlots()
  725. instance.ab = "foo"
  726. pytest.raises(AttributeError, setattr, instance, "a", "baz")
  727. pytest.raises(AttributeError, setattr, instance, "b", "baz")
  728. class MySlotsWeakref(object):
  729. __slots__ = "__weakref__",
  730. MySlotsWeakref = six.add_metaclass(Meta)(MySlotsWeakref)
  731. assert type(MySlotsWeakref) is Meta
  732. @pytest.mark.skipif("sys.version_info[:2] < (3, 3)")
  733. def test_add_metaclass_nested():
  734. # Regression test for https://github.com/benjaminp/six/issues/259
  735. class Meta(type):
  736. pass
  737. class A:
  738. class B: pass
  739. expected = 'test_add_metaclass_nested.<locals>.A.B'
  740. assert A.B.__qualname__ == expected
  741. class A:
  742. @six.add_metaclass(Meta)
  743. class B: pass
  744. assert A.B.__qualname__ == expected
  745. def test_assertCountEqual():
  746. class TestAssertCountEqual(unittest.TestCase):
  747. def test(self):
  748. with self.assertRaises(AssertionError):
  749. six.assertCountEqual(self, (1, 2), [3, 4, 5])
  750. six.assertCountEqual(self, (1, 2), [2, 1])
  751. TestAssertCountEqual('test').test()
  752. def test_assertRegex():
  753. class TestAssertRegex(unittest.TestCase):
  754. def test(self):
  755. with self.assertRaises(AssertionError):
  756. six.assertRegex(self, 'test', r'^a')
  757. six.assertRegex(self, 'test', r'^t')
  758. TestAssertRegex('test').test()
  759. def test_assertNotRegex():
  760. class TestAssertNotRegex(unittest.TestCase):
  761. def test(self):
  762. with self.assertRaises(AssertionError):
  763. six.assertNotRegex(self, 'test', r'^t')
  764. six.assertNotRegex(self, 'test', r'^a')
  765. TestAssertNotRegex('test').test()
  766. def test_assertRaisesRegex():
  767. class TestAssertRaisesRegex(unittest.TestCase):
  768. def test(self):
  769. with six.assertRaisesRegex(self, AssertionError, '^Foo'):
  770. raise AssertionError('Foo')
  771. with self.assertRaises(AssertionError):
  772. with six.assertRaisesRegex(self, AssertionError, r'^Foo'):
  773. raise AssertionError('Bar')
  774. TestAssertRaisesRegex('test').test()
  775. def test_python_2_unicode_compatible():
  776. @six.python_2_unicode_compatible
  777. class MyTest(object):
  778. def __str__(self):
  779. return six.u('hello')
  780. def __bytes__(self):
  781. return six.b('hello')
  782. my_test = MyTest()
  783. if six.PY2:
  784. assert str(my_test) == six.b("hello")
  785. assert unicode(my_test) == six.u("hello")
  786. elif six.PY3:
  787. assert bytes(my_test) == six.b("hello")
  788. assert str(my_test) == six.u("hello")
  789. assert getattr(six.moves.builtins, 'bytes', str)(my_test) == six.b("hello")
  790. class EnsureTests:
  791. # grinning face emoji
  792. UNICODE_EMOJI = six.u("\U0001F600")
  793. BINARY_EMOJI = b"\xf0\x9f\x98\x80"
  794. def test_ensure_binary_raise_type_error(self):
  795. with pytest.raises(TypeError):
  796. six.ensure_str(8)
  797. def test_errors_and_encoding(self):
  798. six.ensure_binary(self.UNICODE_EMOJI, encoding='latin-1', errors='ignore')
  799. with pytest.raises(UnicodeEncodeError):
  800. six.ensure_binary(self.UNICODE_EMOJI, encoding='latin-1', errors='strict')
  801. def test_ensure_binary_raise(self):
  802. converted_unicode = six.ensure_binary(self.UNICODE_EMOJI, encoding='utf-8', errors='strict')
  803. converted_binary = six.ensure_binary(self.BINARY_EMOJI, encoding="utf-8", errors='strict')
  804. if six.PY2:
  805. # PY2: unicode -> str
  806. assert converted_unicode == self.BINARY_EMOJI and isinstance(converted_unicode, str)
  807. # PY2: str -> str
  808. assert converted_binary == self.BINARY_EMOJI and isinstance(converted_binary, str)
  809. else:
  810. # PY3: str -> bytes
  811. assert converted_unicode == self.BINARY_EMOJI and isinstance(converted_unicode, bytes)
  812. # PY3: bytes -> bytes
  813. assert converted_binary == self.BINARY_EMOJI and isinstance(converted_binary, bytes)
  814. def test_ensure_str(self):
  815. converted_unicode = six.ensure_str(self.UNICODE_EMOJI, encoding='utf-8', errors='strict')
  816. converted_binary = six.ensure_str(self.BINARY_EMOJI, encoding="utf-8", errors='strict')
  817. if six.PY2:
  818. # PY2: unicode -> str
  819. assert converted_unicode == self.BINARY_EMOJI and isinstance(converted_unicode, str)
  820. # PY2: str -> str
  821. assert converted_binary == self.BINARY_EMOJI and isinstance(converted_binary, str)
  822. else:
  823. # PY3: str -> str
  824. assert converted_unicode == self.UNICODE_EMOJI and isinstance(converted_unicode, str)
  825. # PY3: bytes -> str
  826. assert converted_binary == self.UNICODE_EMOJI and isinstance(converted_unicode, str)
  827. def test_ensure_text(self):
  828. converted_unicode = six.ensure_text(self.UNICODE_EMOJI, encoding='utf-8', errors='strict')
  829. converted_binary = six.ensure_text(self.BINARY_EMOJI, encoding="utf-8", errors='strict')
  830. if six.PY2:
  831. # PY2: unicode -> unicode
  832. assert converted_unicode == self.UNICODE_EMOJI and isinstance(converted_unicode, unicode)
  833. # PY2: str -> unicode
  834. assert converted_binary == self.UNICODE_EMOJI and isinstance(converted_unicode, unicode)
  835. else:
  836. # PY3: str -> str
  837. assert converted_unicode == self.UNICODE_EMOJI and isinstance(converted_unicode, str)
  838. # PY3: bytes -> str
  839. assert converted_binary == self.UNICODE_EMOJI and isinstance(converted_unicode, str)