summaryrefslogtreecommitdiff
path: root/passlib/tests/utils.py
diff options
context:
space:
mode:
Diffstat (limited to 'passlib/tests/utils.py')
-rw-r--r--passlib/tests/utils.py154
1 files changed, 64 insertions, 90 deletions
diff --git a/passlib/tests/utils.py b/passlib/tests/utils.py
index 79a9f9f..9ade9de 100644
--- a/passlib/tests/utils.py
+++ b/passlib/tests/utils.py
@@ -2,7 +2,6 @@
#=============================================================================
# imports
#=============================================================================
-from __future__ import with_statement
# core
from binascii import unhexlify
import contextlib
@@ -16,8 +15,9 @@ import sys
import tempfile
import threading
import time
+import unittest
from passlib.exc import PasslibHashWarning, PasslibConfigWarning
-from passlib.utils.compat import PY3, JYTHON
+from passlib.utils.compat import JYTHON
import warnings
from warnings import warn
# site
@@ -25,11 +25,9 @@ from warnings import warn
from passlib import exc
from passlib.exc import MissingBackendError
import passlib.registry as registry
-from passlib.tests.backports import TestCase as _TestCase, skip, skipIf, skipUnless, SkipTest
from passlib.utils import has_rounds_info, has_salt_info, rounds_cost_values, \
rng as sys_rng, getrandstr, is_ascii_safe, to_native_str, \
repeat_string, tick, batch
-from passlib.utils.compat import iteritems, irange, u, unicode, PY2, nullcontext
from passlib.utils.decor import classproperty
import passlib.utils.handlers as uh
# local
@@ -219,7 +217,7 @@ def patch_calc_min_rounds(handler):
#=============================================================================
def set_file(path, content):
"""set file to specified bytes"""
- if isinstance(content, unicode):
+ if isinstance(content, str):
content = content.encode("utf-8")
with open(path, "wb") as fh:
fh.write(content)
@@ -231,15 +229,10 @@ def get_file(path):
def tonn(source):
"""convert native string to non-native string"""
- if not isinstance(source, str):
- return source
- elif PY3:
+ if isinstance(source, str):
return source.encode("utf-8")
else:
- try:
- return source.decode("utf-8")
- except UnicodeDecodeError:
- return source.decode("latin-1")
+ return source
def hb(source):
"""
@@ -288,7 +281,7 @@ def run_with_fixed_seeds(count=128, master_seed=0x243F6A8885A308D3):
@wraps(func)
def wrapper(*args, **kwds):
rng = random.Random(master_seed)
- for _ in irange(count):
+ for _ in range(count):
kwds['seed'] = rng.getrandbits(32)
func(*args, **kwds)
return wrapper
@@ -298,7 +291,7 @@ def run_with_fixed_seeds(count=128, master_seed=0x243F6A8885A308D3):
# custom test harness
#=============================================================================
-class TestCase(_TestCase):
+class TestCase(unittest.TestCase):
"""passlib-specific test case class
this class adds a number of features to the standard TestCase...
@@ -321,7 +314,7 @@ class TestCase(_TestCase):
def shortDescription(self):
"""wrap shortDescription() method to prepend descriptionPrefix"""
- desc = super(TestCase, self).shortDescription()
+ desc = super().shortDescription()
prefix = self.descriptionPrefix
if prefix:
desc = "%s: %s" % (prefix, desc or str(self))
@@ -333,7 +326,7 @@ class TestCase(_TestCase):
#---------------------------------------------------------------
@classproperty
def __unittest_skip__(cls):
- # NOTE: this attr is technically a unittest2 internal detail.
+ # NOTE: this attr is technically a unittest internal detail.
name = cls.__name__
return name.startswith("_") or \
getattr(cls, "_%s__unittest_skip" % name, False)
@@ -354,7 +347,7 @@ class TestCase(_TestCase):
resetWarningState = True
def setUp(self):
- super(TestCase, self).setUp()
+ super().setUp()
self.setUpWarnings()
# have uh.debug_only_repr() return real values for duration of test
self.patchAttr(exc, "ENABLE_DEBUG_ONLY_REPR", True)
@@ -375,7 +368,6 @@ class TestCase(_TestCase):
# should be kept until then, so we test the legacy paths.
warnings.filterwarnings("ignore", r"the method .*\.(encrypt|genconfig|genhash)\(\) is deprecated")
warnings.filterwarnings("ignore", r"the 'vary_rounds' option is deprecated")
- warnings.filterwarnings("ignore", r"Support for `(py-bcrypt|bcryptor)` is deprecated")
#---------------------------------------------------------------
# tweak message formatting so longMessage mode is only enabled
@@ -397,7 +389,7 @@ class TestCase(_TestCase):
msg = kwds.pop("__msg__", None)
if _callable is None:
# FIXME: this ignores 'msg'
- return super(TestCase, self).assertRaises(_exc_type, None,
+ return super().assertRaises(_exc_type, None,
*args, **kwds)
try:
result = _callable(*args, **kwds)
@@ -411,7 +403,7 @@ class TestCase(_TestCase):
# forbid a bunch of deprecated aliases so I stop using them
#---------------------------------------------------------------
def assertEquals(self, *a, **k):
- raise AssertionError("this alias is deprecated by unittest2")
+ raise AssertionError("this alias is deprecated by stdlib unittest")
assertNotEquals = assertRegexMatches = assertEquals
#===================================================================
@@ -470,14 +462,13 @@ class TestCase(_TestCase):
def __init__(self, case, **kwds):
self.case = case
self.kwds = kwds
- self.__super = super(TestCase._AssertWarningList, self)
- self.__super.__init__(record=True)
+ super().__init__(record=True)
def __enter__(self):
- self.log = self.__super.__enter__()
+ self.log = super().__enter__()
def __exit__(self, *exc_info):
- self.__super.__exit__(*exc_info)
+ super().__exit__(*exc_info)
if exc_info[0] is None:
self.case.assertWarningList(self.log, **self.kwds)
@@ -631,20 +622,14 @@ class TestCase(_TestCase):
# subtests
#===================================================================
- has_real_subtest = hasattr(_TestCase, "subTest")
-
@contextlib.contextmanager
def subTest(self, *args, **kwds):
"""
- wrapper/backport for .subTest() which also traps SkipTest errors.
+ wrapper for .subTest() which traps SkipTest errors.
(see source for details)
"""
- # this function works around two things:
- # * TestCase.subTest() wasn't added until Py34; so for older python versions,
- # we either need unittest2 installed, or provide stub of our own.
- # this method provides a stub if needed (based on .has_real_subtest check)
- #
- # * as 2020-10-08, .subTest() doesn't play nicely w/ .skipTest();
+ # this function works around issue that as 2020-10-08,
+ # .subTest() doesn't play nicely w/ .skipTest();
# and also makes it hard to debug which subtest had a failure.
# (see https://bugs.python.org/issue25894 and https://bugs.python.org/issue35327)
# this method traps skipTest exceptions, and adds some logging to help debug
@@ -663,13 +648,8 @@ class TestCase(_TestCase):
test_log = self.getLogger()
title = _render_title(*args, **kwds)
- # use real subtest manager if available
- if self.has_real_subtest:
- ctx = super(TestCase, self).subTest(*args, **kwds)
- else:
- ctx = nullcontext()
-
# run the subtest
+ ctx = super().subTest(*args, **kwds)
with ctx:
test_log.info("running subtest: %s", title)
try:
@@ -677,7 +657,9 @@ class TestCase(_TestCase):
except SkipTest:
# silence "SkipTest" exceptions, want to keep running next subtest.
test_log.info("subtest skipped: %s", title)
- pass
+ # XXX: should revisit whether latest py3 version of UTs handle this ok,
+ # meaning it's safe to re-raise this.
+ return
except Exception as err:
# log unhandled exception occurred
# (assuming traceback will be reported up higher, so not bothering here)
@@ -734,8 +716,7 @@ class TestCase(_TestCase):
return logger named after current test.
"""
cls = type(self)
- # NOTE: conditional on qualname for PY2 compat
- path = cls.__module__ + "." + getattr(cls, "__qualname__", cls.__name__)
+ path = cls.__module__ + "." + cls.__qualname__
name = self._testMethodName
if name:
path = path + "." + name
@@ -778,8 +759,7 @@ class HandlerCase(TestCase):
.. note::
- This is subclass of :class:`unittest.TestCase`
- (or :class:`unittest2.TestCase` if available).
+ This is subclass of :class:`unittest.TestCase`.
"""
#===================================================================
# class attrs - should be filled in by subclass
@@ -831,8 +811,8 @@ class HandlerCase(TestCase):
# passwords used to test basic hash behavior - generally
# don't need to be overidden.
stock_passwords = [
- u("test"),
- u("\u20AC\u00A5$"),
+ u"test",
+ u"\u20AC\u00A5$",
b'\xe2\x82\xac\xc2\xa5$'
]
@@ -1065,7 +1045,7 @@ class HandlerCase(TestCase):
if test_requires_backend and self._skip_backend_reason:
raise self.skipTest(self._skip_backend_reason)
- super(HandlerCase, self).setUp()
+ super().setUp()
# if needed, select specific backend for duration of test
# NOTE: skipping this if create_backend_case() signalled we're skipping backend
@@ -1384,7 +1364,7 @@ class HandlerCase(TestCase):
def sampler(func):
value1 = func()
- for _ in irange(samples):
+ for _ in range(samples):
value2 = func()
if value1 != value2:
return
@@ -1500,7 +1480,7 @@ class HandlerCase(TestCase):
self.do_stub_encrypt(salt=salt)
# check some invalid salt chars, make sure they're rejected
- source = u('\x00\xff')
+ source = u'\x00\xff'
if raw:
source = source.encode("latin-1")
chunk = max(mn, 1)
@@ -1516,7 +1496,7 @@ class HandlerCase(TestCase):
if getattr(self.handler, "_salt_is_bytes", False):
return bytes
else:
- return unicode
+ return str
def test_15_salt_type(self):
"""test non-string salt values"""
@@ -1530,12 +1510,11 @@ class HandlerCase(TestCase):
self.assertRaises(TypeError, self.do_encrypt, 'stub', salt=fake())
# unicode should be accepted only if salt_type is unicode.
- if salt_type is not unicode:
- self.assertRaises(TypeError, self.do_encrypt, 'stub', salt=u('x') * salt_size)
+ if salt_type is not str:
+ self.assertRaises(TypeError, self.do_encrypt, 'stub', salt=u'x' * salt_size)
- # bytes should be accepted only if salt_type is bytes,
- # OR if salt type is unicode and running PY2 - to allow native strings.
- if not (salt_type is bytes or (PY2 and salt_type is unicode)):
+ # bytes should be accepted only if salt_type is bytes
+ if salt_type is not bytes:
self.assertRaises(TypeError, self.do_encrypt, 'stub', salt=b'x' * salt_size)
def test_using_salt_size(self):
@@ -1936,7 +1915,7 @@ class HandlerCase(TestCase):
handler, subcls, small, medium, large, adj = self._create_using_rounds_helper()
def get_effective_range(cls):
- seen = set(get_effective_rounds(cls) for _ in irange(1000))
+ seen = set(get_effective_rounds(cls) for _ in range(1000))
return min(seen), max(seen)
def assert_rounds_range(vary_rounds, lower, upper):
@@ -2011,24 +1990,24 @@ class HandlerCase(TestCase):
# check ident_values list
for value in cls.ident_values:
- self.assertIsInstance(value, unicode,
- "cls.ident_values must be unicode:")
+ self.assertIsInstance(value, str,
+ "cls.ident_values must be str:")
self.assertTrue(len(cls.ident_values)>1,
"cls.ident_values must have 2+ elements:")
# check default_ident value
- self.assertIsInstance(cls.default_ident, unicode,
- "cls.default_ident must be unicode:")
+ self.assertIsInstance(cls.default_ident, str,
+ "cls.default_ident must be str:")
self.assertTrue(cls.default_ident in cls.ident_values,
"cls.default_ident must specify member of cls.ident_values")
# check optional aliases list
if cls.ident_aliases:
- for alias, ident in iteritems(cls.ident_aliases):
- self.assertIsInstance(alias, unicode,
- "cls.ident_aliases keys must be unicode:") # XXX: allow ints?
- self.assertIsInstance(ident, unicode,
- "cls.ident_aliases values must be unicode:")
+ for alias, ident in cls.ident_aliases.items():
+ self.assertIsInstance(alias, str,
+ "cls.ident_aliases keys must be str:") # XXX: allow ints?
+ self.assertIsInstance(ident, str,
+ "cls.ident_aliases values must be str:")
self.assertTrue(ident in cls.ident_values,
"cls.ident_aliases must map to cls.ident_values members: %r" % (ident,))
@@ -2347,7 +2326,7 @@ class HandlerCase(TestCase):
chars = self.forbidden_characters
if not chars:
raise self.skipTest("none listed")
- base = u('stub')
+ base = u'stub'
if isinstance(chars, bytes):
from passlib.utils.compat import iter_byte_chars
chars = iter_byte_chars(chars)
@@ -2366,7 +2345,7 @@ class HandlerCase(TestCase):
"""
check if we're expecting potential verify failure due to crypt.crypt() encoding limitation
"""
- if PY3 and self.backend == "os_crypt" and isinstance(secret, bytes):
+ if self.backend == "os_crypt" and isinstance(secret, bytes):
try:
secret.decode("utf-8")
except UnicodeDecodeError:
@@ -2578,7 +2557,7 @@ class HandlerCase(TestCase):
#
# test hash='' is rejected for all but the plaintext hashes
#
- for hash in [u(''), b'']:
+ for hash in [u'', b'']:
if self.accepts_all_hashes:
# then it accepts empty string as well.
self.assertTrue(self.do_identify(hash))
@@ -2609,7 +2588,7 @@ class HandlerCase(TestCase):
def require_parsehash(self):
if not hasattr(self.handler, "parsehash"):
- raise SkipTest("parsehash() not implemented")
+ raise self.skipTest("parsehash() not implemented")
def test_70_parsehash(self):
"""
@@ -2638,11 +2617,6 @@ class HandlerCase(TestCase):
# but all else should be the same
result3 = handler.parsehash(hash, sanitize=True)
correct3 = result.copy()
- if PY2:
- # silence warning about bytes & unicode not comparing
- # (sanitize may convert bytes into base64 text)
- warnings.filterwarnings("ignore", ".*unequal comparison failed to convert.*",
- category=UnicodeWarning)
for key in ("salt", "checksum"):
if key in result3:
self.assertNotEqual(result3[key], correct3[key])
@@ -2656,7 +2630,7 @@ class HandlerCase(TestCase):
"""
if value is None:
return
- self.assertIsInstance(value, unicode)
+ self.assertIsInstance(value, str)
# assumes mask_value() defaults will never show more than <show> chars (4);
# and show nothing if size less than 1/<pct> (8).
ref = value if len(value) < 8 else value[4:]
@@ -2797,7 +2771,7 @@ class HandlerCase(TestCase):
def wrapper():
try:
self.test_77_fuzz_input(threaded=True)
- except SkipTest:
+ except unittest.SkipTest:
pass
except:
with failed_lock:
@@ -2811,7 +2785,7 @@ class HandlerCase(TestCase):
thread.setDaemon(True)
thread.start()
return thread
- threads = [launch(n) for n in irange(thread_count)]
+ threads = [launch(n) for n in range(thread_count)]
# wait until all threads exit
timeout = self.max_fuzz_time * thread_count * 4
@@ -2874,7 +2848,7 @@ class HandlerCase(TestCase):
used by fuzz testing.
verifiers should be callable with signature
- ``func(password: unicode, hash: ascii str) -> ok: bool``.
+ ``func(password: str, hash: ascii str) -> ok: bool``.
"""
handler = self.handler
verifiers = []
@@ -2929,7 +2903,7 @@ class HandlerCase(TestCase):
#==========================================================
# alphabet for randomly generated passwords
- password_alphabet = u('qwertyASDF1234<>.@*#! \u00E1\u0259\u0411\u2113')
+ password_alphabet = u'qwertyASDF1234<>.@*#! \u00E1\u0259\u0411\u2113'
# encoding when testing bytes
password_encoding = "utf-8"
@@ -3039,7 +3013,7 @@ class HandlerCase(TestCase):
# occasionally try an empty password
rng = self.rng
if rng.random() < .0001:
- return u('')
+ return u''
# check if truncate size needs to be considered
handler = self.handler
@@ -3058,7 +3032,7 @@ class HandlerCase(TestCase):
result = getrandstr(rng, self.password_alphabet, size)
# trim ones that encode past truncate point.
- if truncate_size and isinstance(result, unicode):
+ if truncate_size and isinstance(result, str):
while len(result.encode("utf-8")) > truncate_size:
result = result[:-1]
@@ -3210,7 +3184,7 @@ class OsCryptMixin(HandlerCase):
if not self.handler.has_backend("os_crypt"):
# XXX: currently, any tests that use this are skipped entirely! (see issue 120)
self._patch_safe_crypt()
- super(OsCryptMixin, self).setUp()
+ super().setUp()
@classmethod
def _get_safe_crypt_handler_backend(cls):
@@ -3267,7 +3241,7 @@ class OsCryptMixin(HandlerCase):
when it's known os_crypt will be faked by _patch_safe_crypt()
"""
assert backend == "os_crypt"
- reason = super(OsCryptMixin, cls)._get_skip_backend_reason(backend)
+ reason = super()._get_skip_backend_reason(backend)
from passlib.utils import has_crypt
if reason == cls._BACKEND_NOT_AVAILABLE and has_crypt:
@@ -3515,7 +3489,7 @@ class UserHandlerMixin(HandlerCase):
context_map = HandlerCase.FuzzHashGenerator.context_map.copy()
context_map.update(user="random_user")
- user_alphabet = u("asdQWE123")
+ user_alphabet = u"asdQWE123"
def random_user(self):
rng = self.rng
@@ -3543,14 +3517,14 @@ class EncodingHandlerMixin(HandlerCase):
# restrict stock passwords & fuzz alphabet to latin-1,
# so different encodings can be tested safely.
stock_passwords = [
- u("test"),
+ u"test",
b"test",
- u("\u00AC\u00BA"),
+ u"\u00AC\u00BA",
]
class FuzzHashGenerator(HandlerCase.FuzzHashGenerator):
- password_alphabet = u('qwerty1234<>.@*#! \u00AC')
+ password_alphabet = u'qwerty1234<>.@*#! \u00AC'
def populate_context(self, secret, kwds):
"""insert encoding into kwds"""
@@ -3569,13 +3543,13 @@ class reset_warnings(warnings.catch_warnings):
"""catch_warnings() wrapper which clears warning registry & filters"""
def __init__(self, reset_filter="always", reset_registry=".*", **kwds):
- super(reset_warnings, self).__init__(**kwds)
+ super().__init__(**kwds)
self._reset_filter = reset_filter
self._reset_registry = re.compile(reset_registry) if reset_registry else None
def __enter__(self):
# let parent class archive filter state
- ret = super(reset_warnings, self).__enter__()
+ ret = super().__enter__()
# reset the filter to list everything
if self._reset_filter:
@@ -3614,7 +3588,7 @@ class reset_warnings(warnings.catch_warnings):
setattr(mod, "__warningregistry__", orig)
else:
reg.update(orig)
- super(reset_warnings, self).__exit__(*exc_info)
+ super().__exit__(*exc_info)
#=============================================================================
# eof