tor-commits
Threads by month
- ----- 2026 -----
- January
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
January 2020
- 19 participants
- 1597 discussions
commit 551fbde4845a78d3b0f885202dbd171d54d660aa
Author: Damian Johnson <atagar(a)torproject.org>
Date: Fri Jan 3 14:40:55 2020 -0800
Drop is_python_26 checks
Python 2.6 specific code paths are now obsolete. This is most notable within
our tests because we can now use skipTest() without an extra return statement.
No doubt these tests can simplify more, but beginning with the low hanging
fruit.
---
stem/client/datatype.py | 23 --------------
stem/descriptor/export.py | 2 +-
stem/prereq.py | 16 ----------
stem/util/__init__.py | 6 +---
stem/util/test_tools.py | 44 ++-------------------------
test/integ/connection/authentication.py | 1 -
test/integ/control/base_controller.py | 2 --
test/integ/control/controller.py | 4 ---
test/integ/descriptor/collector.py | 1 -
test/integ/descriptor/extrainfo_descriptor.py | 2 +-
test/integ/descriptor/microdescriptor.py | 2 +-
test/integ/descriptor/networkstatus.py | 8 ++---
test/integ/descriptor/server_descriptor.py | 2 +-
test/integ/directory/fallback.py | 1 -
test/integ/installation.py | 4 +--
test/integ/interpreter.py | 4 ---
test/integ/manual.py | 23 +++++---------
test/integ/util/connection.py | 2 --
test/integ/util/proc.py | 1 -
test/integ/util/system.py | 8 -----
test/unit/descriptor/collector.py | 3 --
test/unit/descriptor/compression.py | 1 -
test/unit/descriptor/export.py | 8 -----
test/unit/descriptor/reader.py | 3 --
test/unit/descriptor/remote.py | 2 --
test/unit/installation.py | 2 --
test/unit/manual.py | 4 ---
test/unit/tutorial_examples.py | 7 -----
28 files changed, 21 insertions(+), 165 deletions(-)
diff --git a/stem/client/datatype.py b/stem/client/datatype.py
index 5de5e445..367074b2 100644
--- a/stem/client/datatype.py
+++ b/stem/client/datatype.py
@@ -390,29 +390,6 @@ class Size(Field):
raise NotImplementedError("Use our constant's unpack() and pop() instead")
def pack(self, content):
- # TODO: Python 2.6's struct module behaves a little differently in a couple
- # respsects...
- #
- # * Invalid types raise a TypeError rather than a struct.error.
- #
- # * Negative values are happily packed despite being unsigned fields with
- # a message printed to stdout (!) that says...
- #
- # stem/client/datatype.py:362: DeprecationWarning: struct integer overflow masking is deprecated
- # packed = struct.pack(self.format, content)
- # stem/client/datatype.py:362: DeprecationWarning: 'B' format requires 0 <= number <= 255
- # packed = struct.pack(self.format, content)
- #
- # Rather than adjust this method to account for these differences doing
- # duplicate upfront checks just for python 2.6. When we drop 2.6 support
- # this can obviously be dropped.
-
- if stem.prereq._is_python_26():
- if not stem.util._is_int(content):
- raise ValueError('Size.pack encodes an integer, but was a %s' % type(content).__name__)
- elif content < 0:
- raise ValueError('Packed values must be positive (attempted to pack %i as a %s)' % (content, self.name))
-
# TODO: When we drop python 2.x support this can be simplified via
# integer's to_bytes() method. For example...
#
diff --git a/stem/descriptor/export.py b/stem/descriptor/export.py
index 48699ca4..fea681be 100644
--- a/stem/descriptor/export.py
+++ b/stem/descriptor/export.py
@@ -103,7 +103,7 @@ def export_csv_file(output_file, descriptors, included_fields = (), excluded_fie
writer = csv.DictWriter(output_file, included_fields, dialect = _ExportDialect(), extrasaction='ignore')
- if header and not stem.prereq._is_python_26():
+ if header:
writer.writeheader()
for desc in descriptors:
diff --git a/stem/prereq.py b/stem/prereq.py
index 0de2191e..d748c2ab 100644
--- a/stem/prereq.py
+++ b/stem/prereq.py
@@ -50,22 +50,6 @@ def check_requirements():
raise ImportError('stem requires python version 3.6 or greater')
-def _is_python_26():
- """
- Checks if we're running python 2.6. This isn't for users as it'll be removed
- in stem 2.0 (when python 2.6 support goes away).
-
- .. deprecated:: 1.8.0
- Stem 2.x will remove this method along with Python 2.x support.
-
- :returns: **True** if we're running python 2.6, **False** otherwise
- """
-
- major_version, minor_version = sys.version_info[0:2]
-
- return major_version == 2 and minor_version == 6
-
-
def is_python_27():
"""
Checks if we're running python 2.7 or above (including the 3.x series).
diff --git a/stem/util/__init__.py b/stem/util/__init__.py
index 5be29777..226f5fbf 100644
--- a/stem/util/__init__.py
+++ b/stem/util/__init__.py
@@ -120,11 +120,7 @@ def datetime_to_unix(timestamp):
:returns: **float** for the unix timestamp of the given datetime object
"""
- if stem.prereq._is_python_26():
- delta = (timestamp - datetime.datetime(1970, 1, 1))
- return delta.days * 86400 + delta.seconds
- else:
- return (timestamp - datetime.datetime(1970, 1, 1)).total_seconds()
+ return (timestamp - datetime.datetime(1970, 1, 1)).total_seconds()
def _pubkey_bytes(key):
diff --git a/stem/util/test_tools.py b/stem/util/test_tools.py
index c7dce7ce..02d3dd89 100644
--- a/stem/util/test_tools.py
+++ b/stem/util/test_tools.py
@@ -56,15 +56,6 @@ ASYNC_TESTS = {}
AsyncStatus = stem.util.enum.UppercaseEnum('PENDING', 'RUNNING', 'FINISHED')
AsyncResult = collections.namedtuple('AsyncResult', 'type msg')
-# TODO: Providing a copy of SkipTest that works with python 2.6. This will be
-# dropped when we remove python 2.6 support.
-
-if stem.prereq._is_python_26():
- class SkipTest(Exception):
- 'Notes that the test was skipped.'
-else:
- SkipTest = unittest.case.SkipTest
-
def assert_equal(expected, actual, msg = None):
"""
@@ -111,7 +102,7 @@ def skip(msg):
:raises: **unittest.case.SkipTest** for this reason
"""
- raise SkipTest(msg)
+ raise unittest.case.SkipTest(msg)
def asynchronous(func):
@@ -159,9 +150,6 @@ class AsyncTest(object):
self._status = AsyncStatus.PENDING
def run(self, *runner_args, **kwargs):
- if stem.prereq._is_python_26():
- return # not supported under python 2.6
-
def _wrapper(conn, runner, args):
os.nice(12)
@@ -170,7 +158,7 @@ class AsyncTest(object):
conn.send(AsyncResult('success', None))
except AssertionError as exc:
conn.send(AsyncResult('failure', str(exc)))
- except SkipTest as exc:
+ except unittest.case.SkipTest as exc:
conn.send(AsyncResult('skipped', str(exc)))
except:
conn.send(AsyncResult('error', traceback.format_exc()))
@@ -209,9 +197,6 @@ class AsyncTest(object):
self.result(None)
def result(self, test):
- if stem.prereq._is_python_26():
- return # not supported under python 2.6
-
with self._process_lock:
if self._status == AsyncStatus.PENDING:
self.run()
@@ -259,21 +244,6 @@ class TimedTestRunner(unittest.TextTestRunner):
TEST_RUNTIMES[self.id()] = time.time() - start_time
return result
- # TODO: remove and drop unnecessary 'returns' when dropping python 2.6
- # support
-
- def skipTest(self, message):
- if not stem.prereq._is_python_26():
- return super(original_type, self).skipTest(message)
-
- # TODO: remove when dropping python 2.6 support
-
- def assertItemsEqual(self, expected, actual):
- if stem.prereq._is_python_26():
- self.assertEqual(set(expected), set(actual))
- else:
- return super(original_type, self).assertItemsEqual(expected, actual)
-
def assertRaisesWith(self, exc_type, exc_msg, func, *args, **kwargs):
"""
Asserts the given invokation raises the expected excepiton. This is
@@ -287,16 +257,6 @@ class TimedTestRunner(unittest.TextTestRunner):
return self.assertRaisesRegexp(exc_type, '^%s$' % re.escape(exc_msg), func, *args, **kwargs)
- def assertRaisesRegexp(self, exc_type, exc_msg, func, *args, **kwargs):
- if stem.prereq._is_python_26():
- try:
- func(*args, **kwargs)
- self.fail('Expected a %s to be raised but nothing was' % exc_type)
- except exc_type as exc:
- self.assertTrue(re.search(exc_msg, str(exc), re.MULTILINE))
- else:
- return super(original_type, self).assertRaisesRegexp(exc_type, exc_msg, func, *args, **kwargs)
-
def id(self):
return '%s.%s.%s' % (original_type.__module__, original_type.__name__, self._testMethodName)
diff --git a/test/integ/connection/authentication.py b/test/integ/connection/authentication.py
index 1ab6aae0..cd562e7b 100644
--- a/test/integ/connection/authentication.py
+++ b/test/integ/connection/authentication.py
@@ -280,7 +280,6 @@ class TestAuthenticate(unittest.TestCase):
if test.runner.Torrc.PASSWORD not in runner.get_options() or test.runner.Torrc.COOKIE in runner.get_options():
self.skipTest('(requires only password auth)')
- return
for i in range(10):
with runner.get_tor_controller(False) as controller:
diff --git a/test/integ/control/base_controller.py b/test/integ/control/base_controller.py
index 294eaee3..323b57c7 100644
--- a/test/integ/control/base_controller.py
+++ b/test/integ/control/base_controller.py
@@ -47,7 +47,6 @@ class TestBaseController(unittest.TestCase):
if stem.util.system.is_mac():
self.skipTest('(ticket #6235)')
- return
with test.runner.get_runner().get_tor_socket() as control_socket:
controller = stem.control.BaseController(control_socket)
@@ -97,7 +96,6 @@ class TestBaseController(unittest.TestCase):
if stem.util.system.is_mac():
self.skipTest('(ticket #6235)')
- return
with test.runner.get_runner().get_tor_socket() as control_socket:
controller = stem.control.BaseController(control_socket)
diff --git a/test/integ/control/controller.py b/test/integ/control/controller.py
index a32f66f0..f87c0817 100644
--- a/test/integ/control/controller.py
+++ b/test/integ/control/controller.py
@@ -1296,7 +1296,6 @@ class TestController(unittest.TestCase):
if not os.path.exists(runner.get_test_dir('cached-microdescs')):
self.skipTest('(no cached microdescriptors)')
- return
with runner.get_tor_controller() as controller:
count = 0
@@ -1318,7 +1317,6 @@ class TestController(unittest.TestCase):
if test.tor_version() >= Requirement.MICRODESCRIPTOR_IS_DEFAULT:
self.skipTest('(requires server descriptors)')
- return
with runner.get_tor_controller() as controller:
# we should balk at invalid content
@@ -1349,7 +1347,6 @@ class TestController(unittest.TestCase):
if test.tor_version() >= Requirement.MICRODESCRIPTOR_IS_DEFAULT:
self.skipTest('(requires server descriptors)')
- return
with runner.get_tor_controller() as controller:
count = 0
@@ -1534,6 +1531,5 @@ class TestController(unittest.TestCase):
if TEST_ROUTER_STATUS_ENTRY is None:
# this is only likely to occure if we can't get descriptors
self.skipTest('(no named relays)')
- return
return TEST_ROUTER_STATUS_ENTRY
diff --git a/test/integ/descriptor/collector.py b/test/integ/descriptor/collector.py
index 3af25c29..53f45ae5 100644
--- a/test/integ/descriptor/collector.py
+++ b/test/integ/descriptor/collector.py
@@ -93,7 +93,6 @@ class TestCollector(unittest.TestCase):
def _test_index(self, compression):
if compression and not compression.available:
self.skipTest('(%s unavailable)' % compression)
- return
collector = stem.descriptor.collector.CollecTor()
index = collector.index(compression = compression)
diff --git a/test/integ/descriptor/extrainfo_descriptor.py b/test/integ/descriptor/extrainfo_descriptor.py
index c0a4d30c..4bfb8f3f 100644
--- a/test/integ/descriptor/extrainfo_descriptor.py
+++ b/test/integ/descriptor/extrainfo_descriptor.py
@@ -28,7 +28,7 @@ class TestExtraInfoDescriptor(unittest.TestCase):
descriptor_path = os.path.join(test_dir, 'cached-extrainfo')
if not os.path.exists(descriptor_path):
- raise stem.util.test_tools.SkipTest('(no cached descriptors)')
+ raise unittest.case.SkipTest('(no cached descriptors)')
with open(descriptor_path, 'rb') as descriptor_file:
for desc in stem.descriptor.parse_file(descriptor_file, 'extra-info 1.0', validate = True):
diff --git a/test/integ/descriptor/microdescriptor.py b/test/integ/descriptor/microdescriptor.py
index 3f2b20cb..4e67e15b 100644
--- a/test/integ/descriptor/microdescriptor.py
+++ b/test/integ/descriptor/microdescriptor.py
@@ -28,7 +28,7 @@ class TestMicrodescriptor(unittest.TestCase):
descriptor_path = os.path.join(test_dir, 'cached-microdescs')
if not os.path.exists(descriptor_path):
- raise stem.util.test_tools.SkipTest('(no cached descriptors)')
+ raise unittest.case.SkipTest('(no cached descriptors)')
with open(descriptor_path, 'rb') as descriptor_file:
for desc in stem.descriptor.parse_file(descriptor_file, 'microdescriptor 1.0', validate = True):
diff --git a/test/integ/descriptor/networkstatus.py b/test/integ/descriptor/networkstatus.py
index b9684e6f..efe646f9 100644
--- a/test/integ/descriptor/networkstatus.py
+++ b/test/integ/descriptor/networkstatus.py
@@ -43,12 +43,12 @@ class TestNetworkStatus(unittest.TestCase):
consensus_path = os.path.join(test_dir, 'cached-consensus')
if not os.path.exists(consensus_path):
- raise stem.util.test_tools.SkipTest('(no cached-consensus)')
+ raise unittest.case.SkipTest('(no cached-consensus)')
elif stem.util.system.is_windows():
# Unable to check memory usage on windows, so can't prevent hanging the
# system if things go bad.
- raise stem.util.test_tools.SkipTest('(unavailable on windows)')
+ raise unittest.case.SkipTest('(unavailable on windows)')
count, reported_flags = 0, []
@@ -79,9 +79,9 @@ class TestNetworkStatus(unittest.TestCase):
consensus_path = os.path.join(test_dir, 'cached-microdesc-consensus')
if not os.path.exists(consensus_path):
- raise stem.util.test_tools.SkipTest('(no cached-microdesc-consensus)')
+ raise unittest.case.SkipTest('(no cached-microdesc-consensus)')
elif stem.util.system.is_windows():
- raise stem.util.test_tools.SkipTest('(unavailable on windows)')
+ raise unittest.case.SkipTest('(unavailable on windows)')
count, reported_flags = 0, []
diff --git a/test/integ/descriptor/server_descriptor.py b/test/integ/descriptor/server_descriptor.py
index a62ee8f6..8aa4388c 100644
--- a/test/integ/descriptor/server_descriptor.py
+++ b/test/integ/descriptor/server_descriptor.py
@@ -28,7 +28,7 @@ class TestServerDescriptor(unittest.TestCase):
descriptor_path = os.path.join(test_dir, 'cached-descriptors')
if not os.path.exists(descriptor_path):
- raise stem.util.test_tools.SkipTest('(no cached descriptors)')
+ raise unittest.case.SkipTest('(no cached descriptors)')
with open(descriptor_path, 'rb') as descriptor_file:
for desc in stem.descriptor.parse_file(descriptor_file, 'server-descriptor 1.0', validate = True):
diff --git a/test/integ/directory/fallback.py b/test/integ/directory/fallback.py
index e12b2659..83c87a8d 100644
--- a/test/integ/directory/fallback.py
+++ b/test/integ/directory/fallback.py
@@ -33,7 +33,6 @@ class TestFallback(unittest.TestCase):
# added so many fallbacks now that this takes a looong time. :(
self.skipTest('(skipped by default)')
- return
unsuccessful = {}
downloader = stem.descriptor.remote.DescriptorDownloader()
diff --git a/test/integ/installation.py b/test/integ/installation.py
index 2ac655aa..627f0314 100644
--- a/test/integ/installation.py
+++ b/test/integ/installation.py
@@ -110,9 +110,9 @@ class TestInstallation(unittest.TestCase):
git_dir = os.path.join(test.STEM_BASE, '.git')
if not stem.util.system.is_available('git'):
- raise stem.util.test_tools.SkipTest('(git unavailable)')
+ raise unittest.case.SkipTest('(git unavailable)')
elif not os.path.exists(git_dir):
- raise stem.util.test_tools.SkipTest('(not a git checkout)')
+ raise unittest.case.SkipTest('(not a git checkout)')
if os.path.exists(DIST_PATH):
raise AssertionError("%s already exists, maybe you manually ran 'python setup.py sdist'?" % DIST_PATH)
diff --git a/test/integ/interpreter.py b/test/integ/interpreter.py
index 65d03fd3..32c52c28 100644
--- a/test/integ/interpreter.py
+++ b/test/integ/interpreter.py
@@ -38,10 +38,8 @@ class TestInterpreter(unittest.TestCase):
if test.runner.Torrc.PASSWORD in test.runner.get_runner().get_options():
self.skipTest('password auth unsupported')
- return
elif not READLINE_AVAILABLE:
self.skipTest('readline unavailable')
- return
expected = ['250-config-file=%s' % test.runner.get_runner().get_torrc_path(), '250 OK']
self.assertEqual(expected, _run_prompt('--run', 'GETINFO config-file'))
@@ -50,10 +48,8 @@ class TestInterpreter(unittest.TestCase):
def test_running_file(self):
if test.runner.Torrc.PASSWORD in test.runner.get_runner().get_options():
self.skipTest('password auth unsupported')
- return
elif not READLINE_AVAILABLE:
self.skipTest('readline unavailable')
- return
expected = [
'250-config-file=%s' % test.runner.get_runner().get_torrc_path(),
diff --git a/test/integ/manual.py b/test/integ/manual.py
index ae0b2b16..86811917 100644
--- a/test/integ/manual.py
+++ b/test/integ/manual.py
@@ -91,15 +91,14 @@ class TestManual(unittest.TestCase):
if self.man_path and os.path.exists(self.man_path):
os.remove(self.man_path)
+ # TODO: replace with a 'require' annotation
+
def requires_downloaded_manual(self):
if self.skip_reason:
self.skipTest(self.skip_reason)
- return True
elif self.download_error:
self.fail(self.download_error)
- return False
-
def test_escapes_non_ascii(self):
"""
Check that our manual parser escapes all non-ascii characters. If this
@@ -108,8 +107,7 @@ class TestManual(unittest.TestCase):
stem/manual.py's _get_categories().
"""
- if self.requires_downloaded_manual():
- return
+ self.requires_downloaded_manual()
def check(content):
try:
@@ -131,8 +129,7 @@ class TestManual(unittest.TestCase):
it has indented lines within it. Ensure we parse this correctly.
"""
- if self.requires_downloaded_manual():
- return
+ self.requires_downloaded_manual()
manual = stem.manual.Manual.from_man(self.man_path)
self.assertTrue(manual.config_options['ExitPolicy'].description.startswith(EXPECTED_EXIT_POLICY_DESCRIPTION_START))
@@ -143,8 +140,7 @@ class TestManual(unittest.TestCase):
Check if the cached manual information bundled with Stem is up to date or not.
"""
- if self.requires_downloaded_manual():
- return
+ self.requires_downloaded_manual()
cached_manual = stem.manual.Manual.from_cache()
latest_manual = stem.manual.Manual.from_man(self.man_path)
@@ -158,8 +154,7 @@ class TestManual(unittest.TestCase):
then go ahead and simply update these assertions.
"""
- if self.requires_downloaded_manual():
- return
+ self.requires_downloaded_manual()
def assert_equal(category, expected, actual):
if expected != actual:
@@ -208,8 +203,7 @@ class TestManual(unittest.TestCase):
class to match.
"""
- if self.requires_downloaded_manual():
- return
+ self.requires_downloaded_manual()
categories = stem.manual._get_categories(self.man_content)
@@ -230,8 +224,7 @@ class TestManual(unittest.TestCase):
Check that all the configuration options tor supports are in the man page.
"""
- if self.requires_downloaded_manual():
- return
+ self.requires_downloaded_manual()
with test.runner.get_runner().get_tor_controller() as controller:
config_options_in_tor = set([line.split()[0] for line in controller.get_info('config/names').splitlines() if line.split()[1] != 'Virtual'])
diff --git a/test/integ/util/connection.py b/test/integ/util/connection.py
index ed55ad89..e31ee865 100644
--- a/test/integ/util/connection.py
+++ b/test/integ/util/connection.py
@@ -27,10 +27,8 @@ class TestConnection(unittest.TestCase):
if test.runner.Torrc.PORT not in runner.get_options():
self.skipTest('(no control port)')
- return
elif resolver not in stem.util.connection.system_resolvers():
self.skipTest('(resolver unavailable on this platform)')
- return
with runner.get_tor_socket():
connections = stem.util.connection.get_connections(resolver, process_pid = runner.get_pid())
diff --git a/test/integ/util/proc.py b/test/integ/util/proc.py
index da4d6efc..315082d5 100644
--- a/test/integ/util/proc.py
+++ b/test/integ/util/proc.py
@@ -76,7 +76,6 @@ class TestProc(unittest.TestCase):
return
elif not os.access('/proc/net/tcp', os.R_OK) or not os.access('/proc/net/udp', os.R_OK):
self.skipTest('(proc lacks read permissions)')
- return
# making a controller connection so that we have something to query for
with runner.get_tor_socket():
diff --git a/test/integ/util/system.py b/test/integ/util/system.py
index 89019685..3b48433d 100644
--- a/test/integ/util/system.py
+++ b/test/integ/util/system.py
@@ -287,15 +287,12 @@ class TestSystem(unittest.TestCase):
if stem.util.system.is_windows():
self.skipTest('(unavailable on windows)')
- return
elif stem.util.system.is_mac() or stem.util.system.is_gentoo():
self.skipTest('(resolvers unavailable)')
- return
elif not stem.util.system.is_available('netstat') or \
stem.util.system.is_available('sockstat') or \
stem.util.system.is_available('lsof'):
self.skipTest('(connection resolvers unavailable)')
- return
runner = test.runner.get_runner()
tor_pid, tor_port = runner.get_pid(), test.runner.CONTROL_PORT
@@ -313,7 +310,6 @@ class TestSystem(unittest.TestCase):
if stem.util.system.is_gentoo():
self.skipTest('(unavailable on gentoo)')
- return
netstat_prefix = stem.util.system.GET_PID_BY_PORT_NETSTAT
@@ -353,7 +349,6 @@ class TestSystem(unittest.TestCase):
if stem.util.system.is_mac() or stem.util.system.is_gentoo():
self.skipTest('(resolvers unavailable)')
- return
lsof_prefix = stem.util.system.GET_PID_BY_PORT_LSOF
@@ -397,7 +392,6 @@ class TestSystem(unittest.TestCase):
if stem.util.system.is_windows():
self.skipTest('(unavailable on windows)')
- return
runner = test.runner.get_runner()
runner_pid, tor_cwd = runner.get_pid(), runner.get_tor_cwd()
@@ -537,7 +531,6 @@ class TestSystem(unittest.TestCase):
if getpass.getuser() == 'root':
self.skipTest('(running as root)')
- return
self.assertEqual(os.getcwd(), stem.util.system.expand_path('.'))
self.assertEqual(os.getcwd(), stem.util.system.expand_path('./'))
@@ -568,7 +561,6 @@ class TestSystem(unittest.TestCase):
if stem.prereq.is_pypy():
self.skipTest('(unimplemented for pypy)')
- return
initial_name = stem.util.system.get_process_name()
self.assertTrue('run_tests.py' in initial_name)
diff --git a/test/unit/descriptor/collector.py b/test/unit/descriptor/collector.py
index b4ff7636..3d6b2da0 100644
--- a/test/unit/descriptor/collector.py
+++ b/test/unit/descriptor/collector.py
@@ -72,7 +72,6 @@ class TestCollector(unittest.TestCase):
def test_index_gzip(self, urlopen_mock):
if not Compression.GZIP.available:
self.skipTest('(gzip compression unavailable)')
- return
import zlib
urlopen_mock.return_value = io.BytesIO(zlib.compress(EXAMPLE_INDEX_JSON))
@@ -85,7 +84,6 @@ class TestCollector(unittest.TestCase):
def test_index_bz2(self, urlopen_mock):
if not Compression.BZ2.available:
self.skipTest('(bz2 compression unavailable)')
- return
import bz2
urlopen_mock.return_value = io.BytesIO(bz2.compress(EXAMPLE_INDEX_JSON))
@@ -98,7 +96,6 @@ class TestCollector(unittest.TestCase):
def test_index_lzma(self, urlopen_mock):
if not Compression.LZMA.available:
self.skipTest('(lzma compression unavailable)')
- return
import lzma
urlopen_mock.return_value = io.BytesIO(lzma.compress(EXAMPLE_INDEX_JSON))
diff --git a/test/unit/descriptor/compression.py b/test/unit/descriptor/compression.py
index 3945bc9c..a51bba62 100644
--- a/test/unit/descriptor/compression.py
+++ b/test/unit/descriptor/compression.py
@@ -32,7 +32,6 @@ class TestCompression(unittest.TestCase):
if not compression.available:
self.skipTest('(%s unavailable)' % compression)
- return
with open(get_resource(filename), 'rb') as compressed_file:
content = compression.decompress(compressed_file.read())
diff --git a/test/unit/descriptor/export.py b/test/unit/descriptor/export.py
index a33c1d42..bf7d054a 100644
--- a/test/unit/descriptor/export.py
+++ b/test/unit/descriptor/export.py
@@ -21,10 +21,6 @@ class TestExport(unittest.TestCase):
Exports a single minimal tor server descriptor.
"""
- if stem.prereq._is_python_26():
- self.skipTest('(header added in python 2.7)')
- return
-
desc = RelayDescriptor.create({
'router': 'caerSidi 71.35.133.197 9001 0 0',
'published': '2012-03-01 17:15:27',
@@ -73,10 +69,6 @@ class TestExport(unittest.TestCase):
Checks that the default attributes for our csv output doesn't include private fields.
"""
- if stem.prereq._is_python_26():
- self.skipTest('(header added in python 2.7)')
- return
-
desc = RelayDescriptor.create()
desc_csv = export_csv(desc)
diff --git a/test/unit/descriptor/reader.py b/test/unit/descriptor/reader.py
index 76d1d8f3..589b4641 100644
--- a/test/unit/descriptor/reader.py
+++ b/test/unit/descriptor/reader.py
@@ -192,7 +192,6 @@ class TestDescriptorReader(unittest.TestCase):
if getpass.getuser() == 'root':
self.skipTest('(running as root)')
- return
# Skip the test on windows, since you can only set the file's
# read-only flag with os.chmod(). For more information see...
@@ -558,10 +557,8 @@ class TestDescriptorReader(unittest.TestCase):
if getpass.getuser() == 'root':
self.skipTest('(running as root)')
- return
elif stem.util.system.is_windows():
self.skipTest('(chmod not functional)')
- return
test_path = os.path.join(self.temp_directory, 'secret_file')
diff --git a/test/unit/descriptor/remote.py b/test/unit/descriptor/remote.py
index ab0ad3d7..7703c62c 100644
--- a/test/unit/descriptor/remote.py
+++ b/test/unit/descriptor/remote.py
@@ -241,7 +241,6 @@ class TestDescriptorDownloader(unittest.TestCase):
if not stem.prereq.is_zstd_available():
self.skipTest('(requires zstd module)')
- return
descriptors = list(stem.descriptor.remote.get_server_descriptors(
'9695DFC35FFEB861329B9F1AB04C46397020CE31',
@@ -260,7 +259,6 @@ class TestDescriptorDownloader(unittest.TestCase):
if not stem.prereq.is_lzma_available():
self.skipTest('(requires lzma module)')
- return
descriptors = list(stem.descriptor.remote.get_server_descriptors(
'9695DFC35FFEB861329B9F1AB04C46397020CE31',
diff --git a/test/unit/installation.py b/test/unit/installation.py
index fd8709ba..a91f0362 100644
--- a/test/unit/installation.py
+++ b/test/unit/installation.py
@@ -25,7 +25,6 @@ class TestInstallation(unittest.TestCase):
def test_installs_all_modules(self):
if self.skip_reason:
self.skipTest(self.skip_reason)
- return True
# Modules cited my our setup.py looks like...
#
@@ -49,7 +48,6 @@ class TestInstallation(unittest.TestCase):
def test_installs_all_data_files(self):
if self.skip_reason:
self.skipTest(self.skip_reason)
- return True
# Checking that we have all non-source files. Data looks like...
#
diff --git a/test/unit/manual.py b/test/unit/manual.py
index b7a2de6f..c108af19 100644
--- a/test/unit/manual.py
+++ b/test/unit/manual.py
@@ -149,7 +149,6 @@ class TestManual(unittest.TestCase):
if not stem.manual.HAS_ENCODING_ARG:
self.skipTest('(man lacks --encoding arg on OSX, BSD, and Slackware #18660)')
- return
manual = stem.manual.Manual.from_man(EXAMPLE_MAN_PATH)
@@ -170,7 +169,6 @@ class TestManual(unittest.TestCase):
if not stem.manual.HAS_ENCODING_ARG:
self.skipTest('(man lacks --encoding arg on OSX and BSD and Slackware, #18660)')
- return
manual = stem.manual.Manual.from_man(UNKNOWN_OPTIONS_MAN_PATH)
@@ -198,7 +196,6 @@ class TestManual(unittest.TestCase):
if not stem.manual.HAS_ENCODING_ARG:
self.skipTest('(man lacks --encoding arg on OSX, BSD and Slackware, #18660)')
- return
manual = stem.manual.Manual.from_man(EXAMPLE_MAN_PATH)
@@ -215,7 +212,6 @@ class TestManual(unittest.TestCase):
if not stem.manual.HAS_ENCODING_ARG:
self.skipTest('(man lacks --encoding arg on OSX, BSD, and Slackware #18660)')
- return
manual = stem.manual.Manual.from_man(EXAMPLE_MAN_PATH)
diff --git a/test/unit/tutorial_examples.py b/test/unit/tutorial_examples.py
index c4b26ad0..de00a2b8 100644
--- a/test/unit/tutorial_examples.py
+++ b/test/unit/tutorial_examples.py
@@ -235,13 +235,6 @@ class TestTutorialExamples(unittest.TestCase):
@patch('stem.descriptor.remote.Query')
@patch('stem.directory.Authority.from_cache')
def test_compare_flags(self, authorities_mock, query_mock, stdout_mock):
- if stem.prereq._is_python_26():
- # example imports OrderedDict from collections which doesn't work under
- # python 2.6
-
- self.skipTest("(example doesn't support python 2.6)")
- return
-
authorities_mock().items.return_value = [('moria1', DIRECTORY_AUTHORITIES['moria1']), ('maatuska', DIRECTORY_AUTHORITIES['maatuska'])]
fingerprint = [
1
0
commit a1eaf853775316e20649e49115a4e9839dfa4393
Author: Damian Johnson <atagar(a)torproject.org>
Date: Fri Jan 3 13:46:48 2020 -0800
Drop OrderedDict copy
Python added OrderedDict as a builtin in Python 2.7. We included a copy for
Python 2.6 compatibity and as such is no longer required.
---
stem/control.py | 10 +-
stem/descriptor/__init__.py | 12 +-
stem/descriptor/bandwidth_file.py | 11 +-
stem/directory.py | 11 +-
stem/manual.py | 33 +++---
stem/util/conf.py | 15 +--
stem/util/ordereddict.py | 133 ----------------------
test/unit/descriptor/bandwidth_file.py | 13 +--
test/unit/descriptor/hidden_service_v3.py | 9 +-
test/unit/descriptor/networkstatus/document_v3.py | 11 +-
test/unit/descriptor/router_status_entry.py | 9 +-
test/unit/descriptor/server_descriptor.py | 9 +-
test/unit/directory/fallback.py | 11 +-
test/unit/manual.py | 11 +-
14 files changed, 49 insertions(+), 249 deletions(-)
diff --git a/stem/control.py b/stem/control.py
index 56567467..25a65f43 100644
--- a/stem/control.py
+++ b/stem/control.py
@@ -257,12 +257,6 @@ import threading
import time
try:
- # Added in 2.7
- from collections import OrderedDict
-except ImportError:
- from stem.util.ordereddict import OrderedDict
-
-try:
# Added in 3.x
import queue
except ImportError:
@@ -2623,7 +2617,7 @@ class Controller(BaseController):
log.debug('GETCONF HiddenServiceOptions (failed: %s)' % exc)
raise
- service_dir_map = OrderedDict()
+ service_dir_map = collections.OrderedDict()
directory = None
for status_code, divider, content in response.content():
@@ -2779,7 +2773,7 @@ class Controller(BaseController):
if path in conf and (port, target_address, target_port) in conf[path]['HiddenServicePort']:
return None
- conf.setdefault(path, OrderedDict()).setdefault('HiddenServicePort', []).append((port, target_address, target_port))
+ conf.setdefault(path, collections.OrderedDict()).setdefault('HiddenServicePort', []).append((port, target_address, target_port))
if auth_type and client_names:
hsac = "%s %s" % (auth_type, ','.join(client_names))
diff --git a/stem/descriptor/__init__.py b/stem/descriptor/__init__.py
index c97db183..bab339ac 100644
--- a/stem/descriptor/__init__.py
+++ b/stem/descriptor/__init__.py
@@ -106,12 +106,6 @@ import stem.util.enum
import stem.util.str_tools
import stem.util.system
-try:
- # added in python 2.7
- from collections import OrderedDict
-except ImportError:
- from stem.util.ordereddict import OrderedDict
-
__all__ = [
'bandwidth_file',
'certificate',
@@ -589,7 +583,7 @@ def _descriptor_content(attr = None, exclude = (), header_template = (), footer_
"""
header_content, footer_content = [], []
- attr = {} if attr is None else OrderedDict(attr) # shallow copy since we're destructive
+ attr = {} if attr is None else collections.OrderedDict(attr) # shallow copy since we're destructive
for content, template in ((header_content, header_template),
(footer_content, footer_template)):
@@ -707,7 +701,7 @@ def _parse_protocol_line(keyword, attribute):
# parses 'protocol' entries like: Cons=1-2 Desc=1-2 DirCache=1 HSDir=1
value = _value(keyword, entries)
- protocols = OrderedDict()
+ protocols = collections.OrderedDict()
for k, v in _mappings_for(keyword, value):
versions = []
@@ -1468,7 +1462,7 @@ def _descriptor_components(raw_contents, validate, extra_keywords = (), non_asci
if isinstance(raw_contents, bytes):
raw_contents = stem.util.str_tools._to_unicode(raw_contents)
- entries = OrderedDict()
+ entries = collections.OrderedDict()
extra_entries = [] # entries with a keyword in extra_keywords
remaining_lines = raw_contents.split('\n')
diff --git a/stem/descriptor/bandwidth_file.py b/stem/descriptor/bandwidth_file.py
index 658f02b8..43c43aff 100644
--- a/stem/descriptor/bandwidth_file.py
+++ b/stem/descriptor/bandwidth_file.py
@@ -14,6 +14,7 @@ Parsing for Bandwidth Authority metrics as described in Tor's
.. versionadded:: 1.8.0
"""
+import collections
import datetime
import io
import time
@@ -25,12 +26,6 @@ from stem.descriptor import (
Descriptor,
)
-try:
- # added in python 2.7
- from collections import OrderedDict
-except ImportError:
- from stem.util.ordereddict import OrderedDict
-
# Four character dividers are allowed for backward compatability, but five is
# preferred.
@@ -175,7 +170,7 @@ def _parse_file(descriptor_file, validate = False, **kwargs):
def _parse_header(descriptor, entries):
- header = OrderedDict()
+ header = collections.OrderedDict()
content = io.BytesIO(descriptor.get_bytes())
content.readline() # skip the first line, which should be the timestamp
@@ -332,7 +327,7 @@ class BandwidthFile(Descriptor):
if sign:
raise NotImplementedError('Signing of %s not implemented' % cls.__name__)
- header = OrderedDict(attr) if attr is not None else OrderedDict()
+ header = collections.OrderedDict(attr) if attr is not None else collections.OrderedDict()
timestamp = header.pop('timestamp', str(int(time.time())))
content = header.pop('content', [])
version = header.get('version', HEADER_DEFAULT.get('version'))
diff --git a/stem/directory.py b/stem/directory.py
index b93b49a2..0ca089c3 100644
--- a/stem/directory.py
+++ b/stem/directory.py
@@ -38,6 +38,7 @@ as follows...
.. versionadded:: 1.7.0
"""
+import collections
import os
import re
import sys
@@ -49,12 +50,6 @@ import stem.util.conf
from stem.util import connection, str_tools, tor_tools
try:
- # added in python 2.7
- from collections import OrderedDict
-except ImportError:
- from stem.util.ordereddict import OrderedDict
-
-try:
# account for urllib's change between python 2.x and 3.x
import urllib.request as urllib
except ImportError:
@@ -369,13 +364,13 @@ class Fallback(Directory):
def __init__(self, address = None, or_port = None, dir_port = None, fingerprint = None, nickname = None, has_extrainfo = False, orport_v6 = None, header = None):
super(Fallback, self).__init__(address, or_port, dir_port, fingerprint, nickname, orport_v6)
self.has_extrainfo = has_extrainfo
- self.header = OrderedDict(header) if header else OrderedDict()
+ self.header = collections.OrderedDict(header) if header else collections.OrderedDict()
@staticmethod
def from_cache(path = FALLBACK_CACHE_PATH):
conf = stem.util.conf.Config()
conf.load(path)
- headers = OrderedDict([(k.split('.', 1)[1], conf.get(k)) for k in conf.keys() if k.startswith('header.')])
+ headers = collections.OrderedDict([(k.split('.', 1)[1], conf.get(k)) for k in conf.keys() if k.startswith('header.')])
results = {}
diff --git a/stem/manual.py b/stem/manual.py
index 25d435d4..b94d4e0b 100644
--- a/stem/manual.py
+++ b/stem/manual.py
@@ -48,6 +48,7 @@ us what our torrc options do...
.. versionadded:: 1.5.0
"""
+import collections
import os
import shutil
import sys
@@ -61,12 +62,6 @@ import stem.util.enum
import stem.util.log
import stem.util.system
-try:
- # added in python 2.7
- from collections import OrderedDict
-except ImportError:
- from stem.util.ordereddict import OrderedDict
-
if stem.prereq._is_lru_cache_available():
from functools import lru_cache
else:
@@ -96,7 +91,7 @@ SCHEMA = (
'CREATE TABLE torrc(key TEXT PRIMARY KEY, name TEXT, category TEXT, usage TEXT, summary TEXT, description TEXT, position INTEGER)',
)
-CATEGORY_SECTIONS = OrderedDict((
+CATEGORY_SECTIONS = collections.OrderedDict((
('GENERAL OPTIONS', Category.GENERAL),
('CLIENT OPTIONS', Category.CLIENT),
('SERVER OPTIONS', Category.RELAY),
@@ -374,10 +369,10 @@ class Manual(object):
self.name = name
self.synopsis = synopsis
self.description = description
- self.commandline_options = OrderedDict(commandline_options)
- self.signals = OrderedDict(signals)
- self.files = OrderedDict(files)
- self.config_options = OrderedDict(config_options)
+ self.commandline_options = collections.OrderedDict(commandline_options)
+ self.signals = collections.OrderedDict(signals)
+ self.files = collections.OrderedDict(files)
+ self.config_options = collections.OrderedDict(config_options)
self.man_commit = None
self.stem_commit = None
self.schema = None
@@ -442,7 +437,7 @@ class Manual(object):
signals = dict(conn.execute('SELECT name, description FROM signals').fetchall())
files = dict(conn.execute('SELECT name, description FROM files').fetchall())
- config_options = OrderedDict()
+ config_options = collections.OrderedDict()
for entry in conn.execute('SELECT name, category, usage, summary, description FROM torrc ORDER BY position').fetchall():
option, category, usage, summary, option_description = entry
@@ -460,7 +455,7 @@ class Manual(object):
conf = stem.util.conf.Config()
conf.load(path, commenting = False)
- config_options = OrderedDict()
+ config_options = collections.OrderedDict()
for key in conf.keys():
if key.startswith('config_options.'):
@@ -479,9 +474,9 @@ class Manual(object):
conf.get('name', ''),
conf.get('synopsis', ''),
conf.get('description', ''),
- conf.get('commandline_options', OrderedDict()),
- conf.get('signals', OrderedDict()),
- conf.get('files', OrderedDict()),
+ conf.get('commandline_options', collections.OrderedDict()),
+ conf.get('signals', collections.OrderedDict()),
+ conf.get('files', collections.OrderedDict()),
config_options,
)
@@ -514,7 +509,7 @@ class Manual(object):
except OSError as exc:
raise IOError("Unable to run '%s': %s" % (man_cmd, exc))
- categories, config_options = _get_categories(man_output), OrderedDict()
+ categories, config_options = _get_categories(man_output), collections.OrderedDict()
for category_header, category_enum in CATEGORY_SECTIONS.items():
_add_config_options(config_options, category_enum, categories.get(category_header, []))
@@ -677,7 +672,7 @@ def _get_categories(content):
if content and content[-1].startswith('Tor'):
content = content[:-1]
- categories = OrderedDict()
+ categories = collections.OrderedDict()
category, lines = None, []
for line in content:
@@ -727,7 +722,7 @@ def _get_indented_descriptions(lines):
ignoring those.
"""
- options, last_arg = OrderedDict(), None
+ options, last_arg = collections.OrderedDict(), None
for line in lines:
if line == ' Note':
diff --git a/stem/util/conf.py b/stem/util/conf.py
index b4580ed9..7dffe95a 100644
--- a/stem/util/conf.py
+++ b/stem/util/conf.py
@@ -157,6 +157,7 @@ Here's an expanation of what happened...
+- get_value - provides the value for a given key as a string
"""
+import collections
import inspect
import os
import threading
@@ -165,12 +166,6 @@ import stem.prereq
from stem.util import log
-try:
- # added in python 2.7
- from collections import OrderedDict
-except ImportError:
- from stem.util.ordereddict import OrderedDict
-
CONFS = {} # mapping of identifier to singleton instances of configs
@@ -453,9 +448,9 @@ class Config(object):
"""
def __init__(self):
- self._path = None # location we last loaded from or saved to
- self._contents = OrderedDict() # configuration key/value pairs
- self._listeners = [] # functors to be notified of config changes
+ self._path = None # location we last loaded from or saved to
+ self._contents = collections.OrderedDict() # configuration key/value pairs
+ self._listeners = [] # functors to be notified of config changes
# used for accessing _contents
self._contents_lock = threading.RLock()
@@ -735,7 +730,7 @@ class Config(object):
elif isinstance(default, tuple):
val = tuple(val)
elif isinstance(default, dict):
- val_map = OrderedDict()
+ val_map = collections.OrderedDict()
for entry in val:
if '=>' in entry:
entry_key, entry_val = entry.split('=>', 1)
diff --git a/stem/util/ordereddict.py b/stem/util/ordereddict.py
deleted file mode 100644
index ec228f31..00000000
--- a/stem/util/ordereddict.py
+++ /dev/null
@@ -1,133 +0,0 @@
-# Drop in replacement for python 2.7's OrderedDict, from...
-# https://pypi.org/project/ordereddict/
-#
-# Stem users should *not* rely upon this module. It will be removed when we
-# drop support for python 2.6 and below.
-
-# Copyright (c) 2009 Raymond Hettinger
-#
-# 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.
-
-from UserDict import DictMixin
-
-
-class OrderedDict(dict, DictMixin):
- def __init__(self, *args, **kwds):
- if len(args) > 1:
- raise TypeError('expected at most 1 arguments, got %d' % len(args))
- try:
- self.__end
- except AttributeError:
- self.clear()
- self.update(*args, **kwds)
-
- def clear(self):
- self.__end = end = []
- end += [None, end, end] # sentinel node for doubly linked list
- self.__map = {} # key --> [key, prev, next]
- dict.clear(self)
-
- def __setitem__(self, key, value):
- if key not in self:
- end = self.__end
- curr = end[1]
- curr[2] = end[1] = self.__map[key] = [key, curr, end]
- dict.__setitem__(self, key, value)
-
- def __delitem__(self, key):
- dict.__delitem__(self, key)
- key, prev, next = self.__map.pop(key)
- prev[2] = next
- next[1] = prev
-
- def __iter__(self):
- end = self.__end
- curr = end[2]
- while curr is not end:
- yield curr[0]
- curr = curr[2]
-
- def __reversed__(self):
- end = self.__end
- curr = end[1]
- while curr is not end:
- yield curr[0]
- curr = curr[1]
-
- def popitem(self, last=True):
- if not self:
- raise KeyError('dictionary is empty')
- if last:
- key = reversed(self).next()
- else:
- key = iter(self).next()
- value = self.pop(key)
- return key, value
-
- def __reduce__(self):
- items = [[k, self[k]] for k in self]
- tmp = self.__map, self.__end
- del self.__map, self.__end
- inst_dict = vars(self).copy()
- self.__map, self.__end = tmp
- if inst_dict:
- return (self.__class__, (items,), inst_dict)
- return self.__class__, (items,)
-
- def keys(self):
- return list(self)
-
- setdefault = DictMixin.setdefault
- update = DictMixin.update
- pop = DictMixin.pop
- values = DictMixin.values
- items = DictMixin.items
- iterkeys = DictMixin.iterkeys
- itervalues = DictMixin.itervalues
- iteritems = DictMixin.iteritems
-
- def __repr__(self):
- if not self:
- return '%s()' % (self.__class__.__name__,)
- return '%s(%r)' % (self.__class__.__name__, self.items())
-
- def copy(self):
- return self.__class__(self)
-
- @classmethod
- def fromkeys(cls, iterable, value=None):
- d = cls()
- for key in iterable:
- d[key] = value
- return d
-
- def __eq__(self, other):
- if isinstance(other, OrderedDict):
- if len(self) != len(other):
- return False
- for p, q in zip(self.items(), other.items()):
- if p != q:
- return False
- return True
- return dict.__eq__(self, other)
-
- def __ne__(self, other):
- return not self == other
diff --git a/test/unit/descriptor/bandwidth_file.py b/test/unit/descriptor/bandwidth_file.py
index 3040c38b..bb1eeffa 100644
--- a/test/unit/descriptor/bandwidth_file.py
+++ b/test/unit/descriptor/bandwidth_file.py
@@ -2,6 +2,7 @@
Unit tests for stem.descriptor.bandwidth_file.
"""
+import collections
import datetime
import unittest
@@ -11,12 +12,6 @@ from stem.descriptor.bandwidth_file import BandwidthFile
from test.unit.descriptor import get_resource
try:
- # added in python 2.7
- from collections import OrderedDict
-except ImportError:
- from stem.util.ordereddict import OrderedDict
-
-try:
# added in python 3.3
from unittest.mock import Mock, patch
except ImportError:
@@ -272,7 +267,7 @@ class TestBandwidthFile(unittest.TestCase):
Exercise the example in our content method's pydoc.
"""
- content = BandwidthFile.content(OrderedDict([
+ content = BandwidthFile.content(collections.OrderedDict([
('timestamp', '12345'),
('version', '1.2.0'),
('content', []),
@@ -286,7 +281,7 @@ class TestBandwidthFile(unittest.TestCase):
Include an unrecognized header field.
"""
- desc = BandwidthFile.create(OrderedDict([('version', '1.1.0'), ('new_header', 'neat stuff')]))
+ desc = BandwidthFile.create(collections.OrderedDict([('version', '1.1.0'), ('new_header', 'neat stuff')]))
self.assertEqual(EXPECTED_NEW_HEADER_CONTENT, str(desc))
self.assertEqual('1.1.0', desc.version)
self.assertEqual({'version': '1.1.0', 'new_header': 'neat stuff'}, desc.header)
@@ -309,7 +304,7 @@ class TestBandwidthFile(unittest.TestCase):
self.assertRaisesWith(ValueError, "The 'version' header must be in the second position", BandwidthFile.from_str, WRONG_VERSION_POSITION, validate = True)
- content = BandwidthFile.content(OrderedDict([
+ content = BandwidthFile.content(collections.OrderedDict([
('timestamp', '1410723598'),
('file_created', '2019-01-14T05:35:06'),
('version', '1.1.0'),
diff --git a/test/unit/descriptor/hidden_service_v3.py b/test/unit/descriptor/hidden_service_v3.py
index 33507314..0c172fcb 100644
--- a/test/unit/descriptor/hidden_service_v3.py
+++ b/test/unit/descriptor/hidden_service_v3.py
@@ -3,6 +3,7 @@ Unit tests for stem.descriptor.hidden_service for version 3.
"""
import base64
+import collections
import functools
import unittest
@@ -28,12 +29,6 @@ from test.unit.descriptor import (
)
try:
- # added in python 2.7
- from collections import OrderedDict
-except ImportError:
- from stem.util.ordereddict import OrderedDict
-
-try:
# added in python 3.3
from unittest.mock import patch, Mock
except ImportError:
@@ -328,7 +323,7 @@ class TestHiddenServiceDescriptorV3(unittest.TestCase):
# include optional parameters
- desc = InnerLayer.create(OrderedDict((
+ desc = InnerLayer.create(collections.OrderedDict((
('intro-auth-required', 'ed25519'),
('single-onion-service', ''),
)))
diff --git a/test/unit/descriptor/networkstatus/document_v3.py b/test/unit/descriptor/networkstatus/document_v3.py
index ce7cfdb7..93f98d77 100644
--- a/test/unit/descriptor/networkstatus/document_v3.py
+++ b/test/unit/descriptor/networkstatus/document_v3.py
@@ -2,6 +2,7 @@
Unit tests for the NetworkStatusDocumentV3 of stem.descriptor.networkstatus.
"""
+import collections
import datetime
import io
import unittest
@@ -31,12 +32,6 @@ from stem.descriptor.router_status_entry import (
from test.unit.descriptor import get_resource
-try:
- # added in python 2.7
- from collections import OrderedDict
-except ImportError:
- from stem.util.ordereddict import OrderedDict
-
BANDWIDTH_WEIGHT_ENTRIES = (
'Wbd', 'Wbe', 'Wbg', 'Wbm',
'Wdb',
@@ -869,7 +864,7 @@ DnN5aFtYKiTc19qIC7Nmo+afPdDEf0MlJvEOP5EWl3w=
Parses the parameters attributes.
"""
- document = NetworkStatusDocumentV3.create(OrderedDict([
+ document = NetworkStatusDocumentV3.create(collections.OrderedDict([
('vote-status', 'vote'),
('recommended-client-protocols', 'HSDir=1 HSIntro=3'),
('recommended-relay-protocols', 'Cons=1 Desc=1'),
@@ -1231,7 +1226,7 @@ DnN5aFtYKiTc19qIC7Nmo+afPdDEf0MlJvEOP5EWl3w=
COMMITMENT_1 = '1 sha3-256 4CAEC248004A0DC6CE86EBD5F608C9B05500C70C AAAAAFd4/kAaklgYr4ijHZjXXy/B354jQfL31BFhhE46nuOHSPITyw== AAAAAFd4/kCpZeis3yJyr//rz8hXCeeAhHa4k3lAcAiMJd1vEMTPuw=='
COMMITMENT_2 = '1 sha3-256 598536A9DD4E6C0F18B4AD4B88C7875A0A29BA31 AAAAAFd4/kC7S920awC5/HF5RfX4fKZtYqjm6qMh9G91AcjZm13DQQ=='
- authority = DirectoryAuthority.create(OrderedDict([
+ authority = DirectoryAuthority.create(collections.OrderedDict([
('shared-rand-participate', ''),
('shared-rand-commit', '%s\nshared-rand-commit %s' % (COMMITMENT_1, COMMITMENT_2)),
('shared-rand-previous-value', '8 hAQLxyt0U3gu7QR2owixRCbIltcyPrz3B0YBfUshOkE='),
diff --git a/test/unit/descriptor/router_status_entry.py b/test/unit/descriptor/router_status_entry.py
index c428d6b2..7ee942e0 100644
--- a/test/unit/descriptor/router_status_entry.py
+++ b/test/unit/descriptor/router_status_entry.py
@@ -2,6 +2,7 @@
Unit tests for stem.descriptor.router_status_entry.
"""
+import collections
import datetime
import functools
import unittest
@@ -27,12 +28,6 @@ from stem.descriptor.router_status_entry import (
_base64_to_hex,
)
-try:
- # Added in 2.7
- from collections import OrderedDict
-except ImportError:
- from stem.util.ordereddict import OrderedDict
-
ENTRY_WITHOUT_ED25519 = """\
r seele AAoQ1DAR6kkoo19hBAX5K0QztNw m0ynPuwzSextzsiXYJYA0Hce+Cs 2015-08-23 00:26:35 73.15.150.172 9001 0
s Running Stable Valid
@@ -258,7 +253,7 @@ class TestRouterStatusEntry(unittest.TestCase):
Parse a router status entry with an IPv6 address.
"""
- expected_protocols = OrderedDict((
+ expected_protocols = collections.OrderedDict((
('Cons', [1]),
('Desc', [1]),
('DirCache', [1]),
diff --git a/test/unit/descriptor/server_descriptor.py b/test/unit/descriptor/server_descriptor.py
index d87d51e9..3878c8af 100644
--- a/test/unit/descriptor/server_descriptor.py
+++ b/test/unit/descriptor/server_descriptor.py
@@ -2,6 +2,7 @@
Unit tests for stem.descriptor.server_descriptor.
"""
+import collections
import datetime
import functools
import hashlib
@@ -32,12 +33,6 @@ from test.unit.descriptor import (
)
try:
- # Added in 2.7
- from collections import OrderedDict
-except ImportError:
- from stem.util.ordereddict import OrderedDict
-
-try:
# added in python 3.3
from unittest.mock import Mock, patch
except ImportError:
@@ -288,7 +283,7 @@ Qlx9HNCqCY877ztFRC624ja2ql6A2hBcuoYMbkHjcQ4=
exc_msg = 'Server descriptor lacks a fingerprint. This is an optional field, but required to make a router status entry.'
self.assertRaisesWith(ValueError, exc_msg, desc_without_fingerprint.make_router_status_entry)
- desc = RelayDescriptor.create(OrderedDict((
+ desc = RelayDescriptor.create(collections.OrderedDict((
('router', 'caerSidi 71.35.133.197 9001 0 0'),
('published', '2012-02-29 04:03:19'),
('fingerprint', '4F0C 867D F0EF 6816 0568 C826 838F 482C EA7C FE44'),
diff --git a/test/unit/directory/fallback.py b/test/unit/directory/fallback.py
index 06b4510d..00965187 100644
--- a/test/unit/directory/fallback.py
+++ b/test/unit/directory/fallback.py
@@ -2,6 +2,7 @@
Unit tests for stem.directory.Fallback.
"""
+import collections
import io
import re
import tempfile
@@ -12,12 +13,6 @@ import stem.directory
import stem.util.conf
try:
- # added in python 2.7
- from collections import OrderedDict
-except ImportError:
- from stem.util.ordereddict import OrderedDict
-
-try:
# added in python 3.3
from unittest.mock import patch, Mock
except ImportError:
@@ -58,7 +53,7 @@ URL: https:onionoo.torproject.orguptime?first_seen_days=30-&flag=V2Dir&type=rela
/* ===== */
"""
-HEADER = OrderedDict((
+HEADER = collections.OrderedDict((
('type', 'fallback'),
('version', '2.0.0'),
('timestamp', '20170526090242'),
@@ -75,7 +70,7 @@ class TestFallback(unittest.TestCase):
'nickname': 'rueckgrat',
'has_extrainfo': True,
'orport_v6': ('2a01:4f8:162:51e2::2', 9001),
- 'header': OrderedDict((
+ 'header': collections.OrderedDict((
('type', 'fallback'),
('version', '2.0.0'),
('timestamp', '20170526090242'),
diff --git a/test/unit/manual.py b/test/unit/manual.py
index 72f847e5..b7a2de6f 100644
--- a/test/unit/manual.py
+++ b/test/unit/manual.py
@@ -2,6 +2,7 @@
Unit testing for the stem.manual module.
"""
+import collections
import io
import os
import sqlite3
@@ -25,12 +26,6 @@ try:
except ImportError:
from mock import Mock, patch
-try:
- # added in python 2.7
- from collections import OrderedDict
-except ImportError:
- from stem.util.ordereddict import OrderedDict
-
URL_OPEN = 'urllib.request.urlopen' if stem.prereq.is_python_3() else 'urllib2.urlopen'
EXAMPLE_MAN_PATH = os.path.join(os.path.dirname(__file__), 'tor_man_example')
UNKNOWN_OPTIONS_MAN_PATH = os.path.join(os.path.dirname(__file__), 'tor_man_with_unknown')
@@ -59,7 +54,7 @@ EXPECTED_FILES = {
'$HOME/.torrc': 'Fallback location for torrc, if @CONFDIR@/torrc is not found.',
}
-EXPECTED_CONFIG_OPTIONS = OrderedDict()
+EXPECTED_CONFIG_OPTIONS = collections.OrderedDict()
EXPECTED_CONFIG_OPTIONS['BandwidthRate'] = stem.manual.ConfigOption(
name = 'BandwidthRate',
@@ -315,4 +310,4 @@ class TestManual(unittest.TestCase):
self.assertEqual({}, manual.commandline_options)
self.assertEqual({}, manual.signals)
self.assertEqual({}, manual.files)
- self.assertEqual(OrderedDict(), manual.config_options)
+ self.assertEqual(collections.OrderedDict(), manual.config_options)
1
0
commit 2e0fb02f938c6c2da3b31780753df908655a6ba8
Author: Damian Johnson <atagar(a)torproject.org>
Date: Fri Jan 3 13:56:14 2020 -0800
Drop lru_cache copy
Python added lru_cache as a builtin in Python 3.2. We included a copy for
Python 2.x compatibity and as such is no longer required.
---
stem/descriptor/extrainfo_descriptor.py | 7 +-
stem/descriptor/hidden_service.py | 8 +-
stem/descriptor/microdescriptor.py | 8 +-
stem/descriptor/server_descriptor.py | 13 +--
stem/exit_policy.py | 20 ++--
stem/interpreter/autocomplete.py | 9 +-
stem/interpreter/help.py | 9 +-
stem/manual.py | 8 +-
stem/prereq.py | 15 ---
stem/util/lru_cache.py | 182 --------------------------------
stem/util/proc.py | 12 +--
stem/version.py | 8 +-
12 files changed, 31 insertions(+), 268 deletions(-)
diff --git a/stem/descriptor/extrainfo_descriptor.py b/stem/descriptor/extrainfo_descriptor.py
index 17082f88..f53d9502 100644
--- a/stem/descriptor/extrainfo_descriptor.py
+++ b/stem/descriptor/extrainfo_descriptor.py
@@ -100,11 +100,6 @@ from stem.descriptor import (
_random_crypto_blob,
)
-if stem.prereq._is_lru_cache_available():
- from functools import lru_cache
-else:
- from stem.util.lru_cache import lru_cache
-
# known statuses for dirreq-v2-resp and dirreq-v3-resp...
DirResponse = stem.util.enum.Enum(
('OK', 'ok'),
@@ -950,7 +945,7 @@ class RelayExtraInfoDescriptor(ExtraInfoDescriptor):
def create(cls, attr = None, exclude = (), validate = True, sign = False, signing_key = None):
return cls(cls.content(attr, exclude, sign, signing_key), validate = validate)
- @lru_cache()
+ @functools.lru_cache()
def digest(self, hash_type = DigestHash.SHA1, encoding = DigestEncoding.HEX):
if hash_type == DigestHash.SHA1:
# our digest is calculated from everything except our signature
diff --git a/stem/descriptor/hidden_service.py b/stem/descriptor/hidden_service.py
index e5f82861..7994bffb 100644
--- a/stem/descriptor/hidden_service.py
+++ b/stem/descriptor/hidden_service.py
@@ -35,6 +35,7 @@ import base64
import binascii
import collections
import datetime
+import functools
import hashlib
import io
import os
@@ -70,11 +71,6 @@ from stem.descriptor import (
_random_crypto_blob,
)
-if stem.prereq._is_lru_cache_available():
- from functools import lru_cache
-else:
- from stem.util.lru_cache import lru_cache
-
try:
from cryptography.hazmat.backends.openssl.backend import backend
X25519_AVAILABLE = hasattr(backend, 'x25519_supported') and backend.x25519_supported()
@@ -745,7 +741,7 @@ class HiddenServiceDescriptorV2(BaseHiddenServiceDescriptor):
else:
self._entries = entries
- @lru_cache()
+ @functools.lru_cache()
def introduction_points(self, authentication_cookie = None):
"""
Provided this service's introduction points.
diff --git a/stem/descriptor/microdescriptor.py b/stem/descriptor/microdescriptor.py
index 81bcb43c..17d06d90 100644
--- a/stem/descriptor/microdescriptor.py
+++ b/stem/descriptor/microdescriptor.py
@@ -64,6 +64,7 @@ Doing the same is trivial with server descriptors...
Microdescriptor - Tor microdescriptor.
"""
+import functools
import hashlib
import stem.exit_policy
@@ -88,11 +89,6 @@ from stem.descriptor.router_status_entry import (
_parse_p_line,
)
-if stem.prereq._is_lru_cache_available():
- from functools import lru_cache
-else:
- from stem.util.lru_cache import lru_cache
-
REQUIRED_FIELDS = (
'onion-key',
)
@@ -305,7 +301,7 @@ class Microdescriptor(Descriptor):
else:
raise NotImplementedError('Microdescriptor digests are only available in sha1 and sha256, not %s' % hash_type)
- @lru_cache()
+ @functools.lru_cache()
def get_annotations(self):
"""
Provides content that appeared prior to the descriptor. If this comes from
diff --git a/stem/descriptor/server_descriptor.py b/stem/descriptor/server_descriptor.py
index 1d9adf32..84ba8b65 100644
--- a/stem/descriptor/server_descriptor.py
+++ b/stem/descriptor/server_descriptor.py
@@ -92,11 +92,6 @@ from stem.descriptor import (
_random_crypto_blob,
)
-if stem.prereq._is_lru_cache_available():
- from functools import lru_cache
-else:
- from stem.util.lru_cache import lru_cache
-
# relay descriptors must have exactly one of the following
REQUIRED_FIELDS = (
'router',
@@ -668,7 +663,7 @@ class ServerDescriptor(Descriptor):
raise NotImplementedError('Unsupported Operation: this should be implemented by the ServerDescriptor subclass')
- @lru_cache()
+ @functools.lru_cache()
def get_annotations(self):
"""
Provides content that appeared prior to the descriptor. If this comes from
@@ -910,7 +905,7 @@ class RelayDescriptor(ServerDescriptor):
def create(cls, attr = None, exclude = (), validate = True, sign = False, signing_key = None, exit_policy = None):
return cls(cls.content(attr, exclude, sign, signing_key, exit_policy), validate = validate, skip_crypto_validation = not sign)
- @lru_cache()
+ @functools.lru_cache()
def digest(self, hash_type = DigestHash.SHA1, encoding = DigestEncoding.HEX):
"""
Provides the digest of our descriptor's content.
@@ -967,7 +962,7 @@ class RelayDescriptor(ServerDescriptor):
return RouterStatusEntryV3.create(attr)
- @lru_cache()
+ @functools.lru_cache()
def _onion_key_crosscert_digest(self):
"""
Provides the digest of the onion-key-crosscert data. This consists of the
@@ -1051,7 +1046,7 @@ class BridgeDescriptor(ServerDescriptor):
return self.get_scrubbing_issues() == []
- @lru_cache()
+ @functools.lru_cache()
def get_scrubbing_issues(self):
"""
Provides issues with our scrubbing.
diff --git a/stem/exit_policy.py b/stem/exit_policy.py
index ddaf719c..f9d7e6e0 100644
--- a/stem/exit_policy.py
+++ b/stem/exit_policy.py
@@ -67,6 +67,7 @@ exiting to a destination is permissible or not. For instance...
from __future__ import absolute_import
+import functools
import re
import socket
import zlib
@@ -77,11 +78,6 @@ import stem.util.connection
import stem.util.enum
import stem.util.str_tools
-if stem.prereq._is_lru_cache_available():
- from functools import lru_cache
-else:
- from stem.util.lru_cache import lru_cache
-
AddressType = stem.util.enum.Enum(('WILDCARD', 'Wildcard'), ('IPv4', 'IPv4'), ('IPv6', 'IPv6'))
# Addresses aliased by the 'private' policy. From the tor man page...
@@ -271,7 +267,7 @@ class ExitPolicy(object):
self._is_allowed_default = True
- @lru_cache()
+ @functools.lru_cache()
def can_exit_to(self, address = None, port = None, strict = False):
"""
Checks if this policy allows exiting to a given destination or not. If the
@@ -295,7 +291,7 @@ class ExitPolicy(object):
return self._is_allowed_default
- @lru_cache()
+ @functools.lru_cache()
def is_exiting_allowed(self):
"""
Provides **True** if the policy allows exiting whatsoever, **False**
@@ -317,7 +313,7 @@ class ExitPolicy(object):
return self._is_allowed_default
- @lru_cache()
+ @functools.lru_cache()
def summary(self):
"""
Provides a short description of our policy chain, similar to a
@@ -520,7 +516,7 @@ class ExitPolicy(object):
for rule in self._get_rules():
yield rule
- @lru_cache()
+ @functools.lru_cache()
def __str__(self):
return ', '.join([str(rule) for rule in self._get_rules()])
@@ -873,7 +869,7 @@ class ExitPolicyRule(object):
return self._is_default_suffix
- @lru_cache()
+ @functools.lru_cache()
def __str__(self):
"""
Provides the string representation of our policy. This does not
@@ -917,13 +913,13 @@ class ExitPolicyRule(object):
return label
- @lru_cache()
+ @functools.lru_cache()
def _get_mask_bin(self):
# provides an integer representation of our mask
return int(stem.util.connection._address_to_binary(self.get_mask(False)), 2)
- @lru_cache()
+ @functools.lru_cache()
def _get_address_bin(self):
# provides an integer representation of our address
diff --git a/stem/interpreter/autocomplete.py b/stem/interpreter/autocomplete.py
index b6c5354c..05585b48 100644
--- a/stem/interpreter/autocomplete.py
+++ b/stem/interpreter/autocomplete.py
@@ -5,15 +5,12 @@
Tab completion for our interpreter prompt.
"""
+import functools
+
import stem.prereq
from stem.interpreter import uses_settings
-if stem.prereq._is_lru_cache_available():
- from functools import lru_cache
-else:
- from stem.util.lru_cache import lru_cache
-
@uses_settings
def _get_commands(controller, config):
@@ -84,7 +81,7 @@ class Autocompleter(object):
def __init__(self, controller):
self._commands = _get_commands(controller)
- @lru_cache()
+ @functools.lru_cache()
def matches(self, text):
"""
Provides autocompletion matches for the given text.
diff --git a/stem/interpreter/help.py b/stem/interpreter/help.py
index d2e08d5c..5fde9246 100644
--- a/stem/interpreter/help.py
+++ b/stem/interpreter/help.py
@@ -5,6 +5,8 @@
Provides our /help responses.
"""
+import functools
+
import stem.prereq
from stem.interpreter import (
@@ -17,11 +19,6 @@ from stem.interpreter import (
from stem.util.term import format
-if stem.prereq._is_lru_cache_available():
- from functools import lru_cache
-else:
- from stem.util.lru_cache import lru_cache
-
def response(controller, arg):
"""
@@ -55,7 +52,7 @@ def _normalize(arg):
return arg
-@lru_cache()
+(a)functools.lru_cache()
@uses_settings
def _response(controller, arg, config):
if not arg:
diff --git a/stem/manual.py b/stem/manual.py
index b94d4e0b..2176067c 100644
--- a/stem/manual.py
+++ b/stem/manual.py
@@ -49,6 +49,7 @@ us what our torrc options do...
"""
import collections
+import functools
import os
import shutil
import sys
@@ -62,11 +63,6 @@ import stem.util.enum
import stem.util.log
import stem.util.system
-if stem.prereq._is_lru_cache_available():
- from functools import lru_cache
-else:
- from stem.util.lru_cache import lru_cache
-
try:
# account for urllib's change between python 2.x and 3.x
import urllib.request as urllib
@@ -194,7 +190,7 @@ class ConfigOption(object):
return not self == other
-@lru_cache()
+(a)functools.lru_cache()
def _config(lowercase = True):
"""
Provides a dictionary for our settings.cfg. This has a couple categories...
diff --git a/stem/prereq.py b/stem/prereq.py
index 480f070c..0de2191e 100644
--- a/stem/prereq.py
+++ b/stem/prereq.py
@@ -249,21 +249,6 @@ def is_mock_available():
return False
-def _is_lru_cache_available():
- """
- Functools added lru_cache to the standard library in Python 3.2. Prior to
- this using a bundled implementation. We're also using this with Python 3.5
- due to a buggy implementation. (:trac:`26412`)
- """
-
- major_version, minor_version = sys.version_info[0:2]
-
- if major_version == 3 and minor_version == 5:
- return False
- else:
- return hasattr(functools, 'lru_cache')
-
-
def _is_sha3_available():
"""
Check if hashlib has sha3 support. This requires Python 3.6+ *or* the `pysha3
diff --git a/stem/util/lru_cache.py b/stem/util/lru_cache.py
deleted file mode 100644
index 011d4456..00000000
--- a/stem/util/lru_cache.py
+++ /dev/null
@@ -1,182 +0,0 @@
-# Drop in replace for python 3.2's collections.lru_cache, from...
-# http://code.activestate.com/recipes/578078-py26-and-py30-backport-of-python…
-#
-# ... which is under the MIT license. Stem users should *not* rely upon this
-# module. It will be removed when we drop support for python 3.2 and below.
-
-"""
-Memoization decorator that caches a function's return value. If later called
-with the same arguments then the cached value is returned rather than
-reevaluated.
-
-This is a a python 2.x port of `functools.lru_cache
-<http://docs.python.org/3/library/functools.html#functools.lru_cache>`_. If
-using python 3.2 or later you should use that instead.
-"""
-
-from collections import namedtuple
-from functools import update_wrapper
-from threading import RLock
-
-_CacheInfo = namedtuple('CacheInfo', ['hits', 'misses', 'maxsize', 'currsize'])
-
-
-class _HashedSeq(list):
- __slots__ = 'hashvalue'
-
- def __init__(self, tup, hash=hash):
- self[:] = tup
- self.hashvalue = hash(tup)
-
- def __hash__(self):
- return self.hashvalue
-
-
-def _make_key(args, kwds, typed,
- kwd_mark = (object(),),
- fasttypes = set([int, str, frozenset, type(None)]),
- sorted=sorted, tuple=tuple, type=type, len=len):
- 'Make a cache key from optionally typed positional and keyword arguments'
- key = args
- if kwds:
- sorted_items = sorted(kwds.items())
- key += kwd_mark
- for item in sorted_items:
- key += item
- if typed:
- key += tuple(type(v) for v in args)
- if kwds:
- key += tuple(type(v) for k, v in sorted_items)
- elif len(key) == 1 and type(key[0]) in fasttypes:
- return key[0]
- return _HashedSeq(key)
-
-
-def lru_cache(maxsize=100, typed=False):
- """Least-recently-used cache decorator.
-
- If *maxsize* is set to None, the LRU features are disabled and the cache
- can grow without bound.
-
- If *typed* is True, arguments of different types will be cached separately.
- For example, f(3.0) and f(3) will be treated as distinct calls with
- distinct results.
-
- Arguments to the cached function must be hashable.
-
- View the cache statistics named tuple (hits, misses, maxsize, currsize) with
- f.cache_info(). Clear the cache and statistics with f.cache_clear().
- Access the underlying function with f.__wrapped__.
-
- See: http://en.wikipedia.org/wiki/Cache_algorithms#Least_Recently_Used
-
- """
-
- # Users should only access the lru_cache through its public API:
- # cache_info, cache_clear, and f.__wrapped__
- # The internals of the lru_cache are encapsulated for thread safety and
- # to allow the implementation to change (including a possible C version).
-
- def decorating_function(user_function):
-
- cache = dict()
- stats = [0, 0] # make statistics updateable non-locally
- HITS, MISSES = 0, 1 # names for the stats fields
- make_key = _make_key
- cache_get = cache.get # bound method to lookup key or return None
- _len = len # localize the global len() function
- lock = RLock() # because linkedlist updates aren't threadsafe
- root = [] # root of the circular doubly linked list
- root[:] = [root, root, None, None] # initialize by pointing to self
- nonlocal_root = [root] # make updateable non-locally
- PREV, NEXT, KEY, RESULT = 0, 1, 2, 3 # names for the link fields
-
- if maxsize == 0:
-
- def wrapper(*args, **kwds):
- # no caching, just do a statistics update after a successful call
- result = user_function(*args, **kwds)
- stats[MISSES] += 1
- return result
-
- elif maxsize is None:
-
- def wrapper(*args, **kwds):
- # simple caching without ordering or size limit
- key = make_key(args, kwds, typed)
- result = cache_get(key, root) # root used here as a unique not-found sentinel
- if result is not root:
- stats[HITS] += 1
- return result
- result = user_function(*args, **kwds)
- cache[key] = result
- stats[MISSES] += 1
- return result
-
- else:
-
- def wrapper(*args, **kwds):
- # size limited caching that tracks accesses by recency
- key = make_key(args, kwds, typed) if kwds or typed else args
- with lock:
- link = cache_get(key)
- if link is not None:
- # record recent use of the key by moving it to the front of the list
- root, = nonlocal_root
- link_prev, link_next, key, result = link
- link_prev[NEXT] = link_next
- link_next[PREV] = link_prev
- last = root[PREV]
- last[NEXT] = root[PREV] = link
- link[PREV] = last
- link[NEXT] = root
- stats[HITS] += 1
- return result
- result = user_function(*args, **kwds)
- with lock:
- root, = nonlocal_root
- if key in cache:
- # getting here means that this same key was added to the
- # cache while the lock was released. since the link
- # update is already done, we need only return the
- # computed result and update the count of misses.
- pass
- elif _len(cache) >= maxsize:
- # use the old root to store the new key and result
- oldroot = root
- oldroot[KEY] = key
- oldroot[RESULT] = result
- # empty the oldest link and make it the new root
- root = nonlocal_root[0] = oldroot[NEXT]
- oldkey = root[KEY]
- root[KEY] = root[RESULT] = None
- # now update the cache dictionary for the new links
- del cache[oldkey]
- cache[key] = oldroot
- else:
- # put result in a new link at the front of the list
- last = root[PREV]
- link = [last, root, key, result]
- last[NEXT] = root[PREV] = cache[key] = link
- stats[MISSES] += 1
- return result
-
- def cache_info():
- """Report cache statistics"""
- with lock:
- return _CacheInfo(stats[HITS], stats[MISSES], maxsize, len(cache))
-
- def cache_clear():
- """Clear the cache and cache statistics"""
- with lock:
- cache.clear()
- root = nonlocal_root[0]
- root[:] = [root, root, None, None]
- stats[:] = [0, 0]
-
- wrapper.__wrapped__ = user_function
- wrapper.cache_info = cache_info
- wrapper.cache_clear = cache_clear
- return update_wrapper(wrapper, user_function)
-
- return decorating_function
diff --git a/stem/util/proc.py b/stem/util/proc.py
index f0e0104f..ecb7f3f7 100644
--- a/stem/util/proc.py
+++ b/stem/util/proc.py
@@ -48,6 +48,7 @@ future, use them at your own risk.**
"""
import base64
+import functools
import os
import platform
import socket
@@ -68,11 +69,6 @@ try:
except ImportError:
IS_PWD_AVAILABLE = False
-if stem.prereq._is_lru_cache_available():
- from functools import lru_cache
-else:
- from stem.util.lru_cache import lru_cache
-
# os.sysconf is only defined on unix
try:
CLOCK_TICKS = os.sysconf(os.sysconf_names['SC_CLK_TCK'])
@@ -88,7 +84,7 @@ Stat = stem.util.enum.Enum(
)
-@lru_cache()
+(a)functools.lru_cache()
def is_available():
"""
Checks if proc information is available on this platform.
@@ -109,7 +105,7 @@ def is_available():
return True
-@lru_cache()
+(a)functools.lru_cache()
def system_start_time():
"""
Provides the unix time (seconds since epoch) when the system started.
@@ -132,7 +128,7 @@ def system_start_time():
raise exc
-@lru_cache()
+(a)functools.lru_cache()
def physical_memory():
"""
Provides the total physical memory on the system in bytes.
diff --git a/stem/version.py b/stem/version.py
index 6bf0befe..71f16e2c 100644
--- a/stem/version.py
+++ b/stem/version.py
@@ -84,6 +84,7 @@ easily parsed and compared, for instance...
===================================== ===========
"""
+import functools
import os
import re
@@ -92,11 +93,6 @@ import stem.util
import stem.util.enum
import stem.util.system
-if stem.prereq._is_lru_cache_available():
- from functools import lru_cache
-else:
- from stem.util.lru_cache import lru_cache
-
# cache for the get_system_tor_version function
VERSION_CACHE = {}
@@ -150,7 +146,7 @@ def get_system_tor_version(tor_cmd = 'tor'):
return VERSION_CACHE[tor_cmd]
-@lru_cache()
+(a)functools.lru_cache()
def _get_version(version_str):
return Version(version_str)
1
0
05 Jan '20
commit 4e21371e88662992fa21bc1f845c05c16ccee4f4
Author: Damian Johnson <atagar(a)torproject.org>
Date: Fri Jan 3 15:55:42 2020 -0800
Resume 'GETINFO status/fresh-relay-descs' test
To work around these failures Nick suggested adding an Address line to our
torrc...
https://trac.torproject.org/projects/tor/ticket/32873
Specifying localhost ('Address 127.0.0.1') didn't work, but anecdotally seems
as though supplying a dummy address like this does.
This reverts commit 983afa8a67e8ef013ff8c03afbd75d0219ea1188.
---
test/integ/control/controller.py | 22 ++++++++++++++++++++++
test/settings.cfg | 1 +
2 files changed, 23 insertions(+)
diff --git a/test/integ/control/controller.py b/test/integ/control/controller.py
index 428f516e..a32f66f0 100644
--- a/test/integ/control/controller.py
+++ b/test/integ/control/controller.py
@@ -256,6 +256,28 @@ class TestController(unittest.TestCase):
self.assertEqual({}, controller.get_info([], {}))
@test.require.controller
+ def test_getinfo_freshrelaydescs(self):
+ """
+ Exercises 'GETINFO status/fresh-relay-descs'.
+ """
+
+ with test.runner.get_runner().get_tor_controller() as controller:
+ response = controller.get_info('status/fresh-relay-descs')
+ div = response.find('\nextra-info ')
+ nickname = controller.get_conf('Nickname')
+
+ if div == -1:
+ self.fail('GETINFO response should have both a server and extrainfo descriptor:\n%s' % response)
+
+ server_desc = stem.descriptor.server_descriptor.ServerDescriptor(response[:div], validate = True)
+ extrainfo_desc = stem.descriptor.extrainfo_descriptor.ExtraInfoDescriptor(response[div:], validate = True)
+
+ self.assertEqual(nickname, server_desc.nickname)
+ self.assertEqual(nickname, extrainfo_desc.nickname)
+ self.assertEqual(controller.get_info('address'), server_desc.address)
+ self.assertEqual(test.runner.ORPORT, server_desc.or_port)
+
+ @test.require.controller
@test.require.online
def test_getinfo_dir_status(self):
"""
diff --git a/test/settings.cfg b/test/settings.cfg
index 2c18110f..9c746234 100644
--- a/test/settings.cfg
+++ b/test/settings.cfg
@@ -25,6 +25,7 @@ integ.torrc
|SocksPort [SOCKS_PORT]
|ORPort [OR_PORT]
|
+|Address 1.2.3.4
|DataDirectory [DATA_DIR]
|Log notice stdout
|Log debug file [DATA_DIR]/tor_log
1
0
commit 1f2cc309a0785d2d5885cf16fb739707ead195c2
Author: Damian Johnson <atagar(a)torproject.org>
Date: Fri Jan 3 15:10:07 2020 -0800
Drop is_python_3 checks
These checks now always evaluate to 'true'. Dropping these checks and their
alternate code paths.
---
stem/client/cell.py | 4 ++--
stem/client/datatype.py | 4 ++--
stem/control.py | 10 ++++-----
stem/descriptor/__init__.py | 9 +++-----
stem/descriptor/reader.py | 2 +-
stem/descriptor/router_status_entry.py | 4 +---
stem/exit_policy.py | 8 +++----
stem/interpreter/__init__.py | 4 ++--
stem/manual.py | 3 +--
stem/prereq.py | 29 ------------------------
stem/response/__init__.py | 13 +++++------
stem/response/events.py | 20 +++++++----------
stem/response/getinfo.py | 3 +--
stem/response/protocolinfo.py | 4 +---
stem/socket.py | 5 ++---
stem/util/__init__.py | 38 ++-----------------------------
stem/util/conf.py | 4 +---
stem/util/connection.py | 4 ++--
stem/util/enum.py | 2 +-
stem/util/log.py | 3 +--
stem/util/str_tools.py | 39 +++++++++++---------------------
stem/util/system.py | 2 +-
test/integ/process.py | 10 +++------
test/task.py | 2 +-
test/unit/descriptor/collector.py | 23 +++++++------------
test/unit/descriptor/remote.py | 41 +++++++++++++---------------------
test/unit/directory/authority.py | 6 ++---
test/unit/directory/fallback.py | 12 +++++-----
test/unit/manual.py | 7 +++---
test/unit/tutorial_examples.py | 16 +++++--------
test/unit/util/connection.py | 7 +++---
31 files changed, 105 insertions(+), 233 deletions(-)
diff --git a/stem/client/cell.py b/stem/client/cell.py
index 57a71749..83888556 100644
--- a/stem/client/cell.py
+++ b/stem/client/cell.py
@@ -354,10 +354,10 @@ class RelayCell(CircuitCell):
digest_packed = digest.digest()[:RELAY_DIGEST_SIZE.size]
digest = RELAY_DIGEST_SIZE.unpack(digest_packed)
- elif stem.util._is_str(digest):
+ elif isinstance(digest, (bytes, str)):
digest_packed = digest[:RELAY_DIGEST_SIZE.size]
digest = RELAY_DIGEST_SIZE.unpack(digest_packed)
- elif stem.util._is_int(digest):
+ elif isinstance(digest, int):
pass
else:
raise ValueError('RELAY cell digest must be a hash, string, or int but was a %s' % type(digest).__name__)
diff --git a/stem/client/datatype.py b/stem/client/datatype.py
index 367074b2..0b39d1b5 100644
--- a/stem/client/datatype.py
+++ b/stem/client/datatype.py
@@ -183,7 +183,7 @@ class _IntegerEnum(stem.util.enum.Enum):
Provides the (enum, int_value) tuple for a given value.
"""
- if stem.util._is_int(val):
+ if isinstance(val, int):
return self._int_to_enum.get(val, self.UNKNOWN), val
elif val in self:
return val, self._enum_to_int.get(val, val)
@@ -402,7 +402,7 @@ class Size(Field):
try:
packed = struct.pack(self.format, content)
except struct.error:
- if not stem.util._is_int(content):
+ if not isinstance(content, int):
raise ValueError('Size.pack encodes an integer, but was a %s' % type(content).__name__)
elif content < 0:
raise ValueError('Packed values must be positive (attempted to pack %i as a %s)' % (content, self.name))
diff --git a/stem/control.py b/stem/control.py
index 25a65f43..c046755c 100644
--- a/stem/control.py
+++ b/stem/control.py
@@ -1160,7 +1160,7 @@ class Controller(BaseController):
start_time = time.time()
reply = {}
- if stem.util._is_str(params):
+ if isinstance(params, (bytes, str)):
is_multiple = False
params = set([params])
else:
@@ -1205,7 +1205,7 @@ class Controller(BaseController):
# usually we want unicode values under python 3.x
- if stem.prereq.is_python_3() and not get_bytes:
+ if not get_bytes:
response.entries = dict((k, stem.util.str_tools._to_unicode(v)) for (k, v) in response.entries.items())
reply.update(response.entries)
@@ -2308,7 +2308,7 @@ class Controller(BaseController):
start_time = time.time()
reply = {}
- if stem.util._is_str(params):
+ if isinstance(params, (bytes, str)):
params = [params]
# remove strings which contain only whitespace
@@ -3476,7 +3476,7 @@ class Controller(BaseController):
* :class:`stem.InvalidArguments` if features passed were invalid
"""
- if stem.util._is_str(features):
+ if isinstance(features, (bytes, str)):
features = [features]
response = self.msg('USEFEATURE %s' % ' '.join(features))
@@ -3631,7 +3631,7 @@ class Controller(BaseController):
args = [circuit_id]
- if stem.util._is_str(path):
+ if isinstance(path, (bytes, str)):
path = [path]
if path:
diff --git a/stem/descriptor/__init__.py b/stem/descriptor/__init__.py
index bab339ac..ec299289 100644
--- a/stem/descriptor/__init__.py
+++ b/stem/descriptor/__init__.py
@@ -357,7 +357,7 @@ def parse_file(descriptor_file, descriptor_type = None, validate = False, docume
handler = None
- if stem.util._is_str(descriptor_file):
+ if isinstance(descriptor_file, (bytes, str)):
if stem.util.system.is_tarfile(descriptor_file):
handler = _parse_file_for_tar_path
else:
@@ -1157,10 +1157,7 @@ class Descriptor(object):
return super(Descriptor, self).__getattribute__(name)
def __str__(self):
- if stem.prereq.is_python_3():
- return stem.util.str_tools._to_unicode(self._raw_contents)
- else:
- return self._raw_contents
+ return stem.util.str_tools._to_unicode(self._raw_contents)
def _compare(self, other, method):
if type(self) != type(other):
@@ -1234,7 +1231,7 @@ def _read_until_keywords(keywords, descriptor_file, inclusive = False, ignore_fi
content = None if skip else []
ending_keyword = None
- if stem.util._is_str(keywords):
+ if isinstance(keywords, (bytes, str)):
keywords = (keywords,)
if ignore_first:
diff --git a/stem/descriptor/reader.py b/stem/descriptor/reader.py
index b4cc4279..ebd41c73 100644
--- a/stem/descriptor/reader.py
+++ b/stem/descriptor/reader.py
@@ -270,7 +270,7 @@ class DescriptorReader(object):
"""
def __init__(self, target, validate = False, follow_links = False, buffer_size = 100, persistence_path = None, document_handler = stem.descriptor.DocumentHandler.ENTRIES, **kwargs):
- self._targets = [target] if stem.util._is_str(target) else target
+ self._targets = [target] if isinstance(target, (bytes, str)) else target
# expand any relative paths we got
diff --git a/stem/descriptor/router_status_entry.py b/stem/descriptor/router_status_entry.py
index cf1c52f5..d248774a 100644
--- a/stem/descriptor/router_status_entry.py
+++ b/stem/descriptor/router_status_entry.py
@@ -374,9 +374,7 @@ def _base64_to_hex(identity, check_if_fingerprint = True):
raise ValueError("Unable to decode identity string '%s'" % identity)
fingerprint = binascii.hexlify(identity_decoded).upper()
-
- if stem.prereq.is_python_3():
- fingerprint = stem.util.str_tools._to_unicode(fingerprint)
+ fingerprint = stem.util.str_tools._to_unicode(fingerprint)
if check_if_fingerprint:
if not stem.util.tor_tools.is_valid_fingerprint(fingerprint):
diff --git a/stem/exit_policy.py b/stem/exit_policy.py
index f9d7e6e0..0d1e7e42 100644
--- a/stem/exit_policy.py
+++ b/stem/exit_policy.py
@@ -124,7 +124,7 @@ def get_config_policy(rules, ip_address = None):
elif ip_address and stem.util.connection.is_valid_ipv6_address(ip_address, allow_brackets = True) and not (ip_address[0] == '[' and ip_address[-1] == ']'):
ip_address = '[%s]' % ip_address # ExitPolicy validation expects IPv6 addresses to be bracketed
- if stem.util._is_str(rules):
+ if isinstance(rules, (bytes, str)):
rules = rules.split(',')
result = []
@@ -238,7 +238,7 @@ class ExitPolicy(object):
# sanity check the types
for rule in rules:
- if not stem.util._is_str(rule) and not isinstance(rule, ExitPolicyRule):
+ if not isinstance(rule, (bytes, str)) and not isinstance(rule, ExitPolicyRule):
raise TypeError('Exit policy rules can only contain strings or ExitPolicyRules, got a %s (%s)' % (type(rule), rules))
# Unparsed representation of the rules we were constructed with. Our
@@ -249,7 +249,7 @@ class ExitPolicy(object):
is_all_str = True
for rule in rules:
- if not stem.util._is_str(rule):
+ if not isinstance(rule, (bytes, str)):
is_all_str = False
if rules and is_all_str:
@@ -466,7 +466,7 @@ class ExitPolicy(object):
if isinstance(rule, bytes):
rule = stem.util.str_tools._to_unicode(rule)
- if stem.util._is_str(rule):
+ if isinstance(rule, (bytes, str)):
if not rule.strip():
continue
diff --git a/stem/interpreter/__init__.py b/stem/interpreter/__init__.py
index 30af3f62..fc0c2cf3 100644
--- a/stem/interpreter/__init__.py
+++ b/stem/interpreter/__init__.py
@@ -171,14 +171,14 @@ def main():
while True:
try:
prompt = '... ' if interpreter.is_multiline_context else PROMPT
- user_input = input(prompt) if stem.prereq.is_python_3() else raw_input(prompt)
+ user_input = input(prompt)
interpreter.run_command(user_input, print_response = True)
except stem.SocketClosed:
if showed_close_confirmation:
print(format('Unable to run tor commands. The control connection has been closed.', *ERROR_OUTPUT))
else:
prompt = format("Tor's control port has closed. Do you want to continue this interpreter? (y/n) ", *HEADER_BOLD_OUTPUT)
- user_input = input(prompt) if stem.prereq.is_python_3() else raw_input(prompt)
+ user_input = input(prompt)
print('') # blank line
if user_input.lower() in ('y', 'yes'):
diff --git a/stem/manual.py b/stem/manual.py
index 2176067c..d9ad5aa7 100644
--- a/stem/manual.py
+++ b/stem/manual.py
@@ -678,8 +678,7 @@ def _get_categories(content):
# \u2014 - extra long dash
# \xb7 - centered dot
- char_for = chr if stem.prereq.is_python_3() else unichr
- line = line.replace(char_for(0x2019), "'").replace(char_for(0x2014), '-').replace(char_for(0xb7), '*')
+ line = line.replace(chr(0x2019), "'").replace(chr(0x2014), '-').replace(chr(0xb7), '*')
if line and not line.startswith(' '):
if category:
diff --git a/stem/prereq.py b/stem/prereq.py
index d748c2ab..bd006bd0 100644
--- a/stem/prereq.py
+++ b/stem/prereq.py
@@ -12,7 +12,6 @@ stem will still read descriptors - just without signature checks.
::
check_requirements - checks for minimum requirements for running stem
- is_python_3 - checks if python 3.0 or later is available
is_sqlite_available - checks if the sqlite3 module is available
is_crypto_available - checks if the cryptography module is available
is_zstd_available - checks if the zstd module is available
@@ -50,34 +49,6 @@ def check_requirements():
raise ImportError('stem requires python version 3.6 or greater')
-def is_python_27():
- """
- Checks if we're running python 2.7 or above (including the 3.x series).
-
- .. deprecated:: 1.5.0
- Stem 2.x will remove this method along with Python 2.x support.
-
- :returns: **True** if we meet this requirement and **False** otherwise
- """
-
- major_version, minor_version = sys.version_info[0:2]
-
- return major_version > 2 or (major_version == 2 and minor_version >= 7)
-
-
-def is_python_3():
- """
- Checks if we're in the 3.0 - 3.x range.
-
- .. deprecated:: 1.8.0
- Stem 2.x will remove this method along with Python 2.x support.
-
- :returns: **True** if we meet this requirement and **False** otherwise
- """
-
- return sys.version_info[0] == 3
-
-
def is_pypy():
"""
Checks if we're running PyPy.
diff --git a/stem/response/__init__.py b/stem/response/__init__.py
index 1a5b2b45..2fbb9c48 100644
--- a/stem/response/__init__.py
+++ b/stem/response/__init__.py
@@ -229,7 +229,7 @@ class ControlMessage(object):
:returns: **list** of (str, str, str) tuples for the components of this message
"""
- if stem.prereq.is_python_3() and not get_bytes:
+ if not get_bytes:
return [(code, div, stem.util.str_tools._to_unicode(content)) for (code, div, content) in self._parsed_content]
else:
return list(self._parsed_content)
@@ -246,7 +246,7 @@ class ControlMessage(object):
:returns: **str** of the socket data used to generate this message
"""
- if stem.prereq.is_python_3() and not get_bytes:
+ if not get_bytes:
return stem.util.str_tools._to_unicode(self._raw_content)
else:
return self._raw_content
@@ -286,8 +286,7 @@ class ControlMessage(object):
"""
for _, _, content in self._parsed_content:
- if stem.prereq.is_python_3():
- content = stem.util.str_tools._to_unicode(content)
+ content = stem.util.str_tools._to_unicode(content)
yield ControlLine(content)
@@ -304,9 +303,7 @@ class ControlMessage(object):
"""
content = self._parsed_content[index][2]
-
- if stem.prereq.is_python_3():
- content = stem.util.str_tools._to_unicode(content)
+ content = stem.util.str_tools._to_unicode(content)
return ControlLine(content)
@@ -534,7 +531,7 @@ def _parse_entry(line, quoted, escaped, get_bytes):
next_entry = codecs.escape_decode(next_entry)[0]
- if stem.prereq.is_python_3() and not get_bytes:
+ if not get_bytes:
next_entry = stem.util.str_tools._to_unicode(next_entry) # normalize back to str
if get_bytes:
diff --git a/stem/response/events.py b/stem/response/events.py
index e634a5d6..9b6d8393 100644
--- a/stem/response/events.py
+++ b/stem/response/events.py
@@ -23,10 +23,6 @@ QUOTED_KW_ARG = re.compile('^(.*) ([A-Za-z0-9_]+)="(.*)"$')
CELL_TYPE = re.compile('^[a-z0-9_]+$')
PARSE_NEWCONSENSUS_EVENTS = True
-# TODO: We can remove the following when we drop python2.6 support.
-
-INT_TYPE = int if stem.prereq.is_python_3() else long
-
class Event(stem.response.ControlMessage):
"""
@@ -163,7 +159,7 @@ class Event(stem.response.ControlMessage):
attr_values = getattr(self, attr)
if attr_values:
- if stem.util._is_str(attr_values):
+ if isinstance(attr_values, (bytes, str)):
attr_values = [attr_values]
for value in attr_values:
@@ -284,8 +280,8 @@ class BandwidthEvent(Event):
elif not self.read.isdigit() or not self.written.isdigit():
raise stem.ProtocolError("A BW event's bytes sent and received should be a positive numeric value, received: %s" % self)
- self.read = INT_TYPE(self.read)
- self.written = INT_TYPE(self.written)
+ self.read = int(self.read)
+ self.written = int(self.written)
class BuildTimeoutSetEvent(Event):
@@ -1095,8 +1091,8 @@ class StreamBwEvent(Event):
elif not self.read.isdigit() or not self.written.isdigit():
raise stem.ProtocolError("A STREAM_BW event's bytes sent and received should be a positive numeric value, received: %s" % self)
- self.read = INT_TYPE(self.read)
- self.written = INT_TYPE(self.written)
+ self.read = int(self.read)
+ self.written = int(self.written)
self.time = self._iso_timestamp(self.time)
@@ -1174,8 +1170,8 @@ class ConnectionBandwidthEvent(Event):
elif not tor_tools.is_valid_connection_id(self.id):
raise stem.ProtocolError("Connection IDs must be one to sixteen alphanumeric characters, got '%s': %s" % (self.id, self))
- self.read = INT_TYPE(self.read)
- self.written = INT_TYPE(self.written)
+ self.read = int(self.read)
+ self.written = int(self.written)
self._log_if_unrecognized('conn_type', stem.ConnectionType)
@@ -1247,7 +1243,7 @@ class CircuitBandwidthEvent(Event):
value = getattr(self, attr)
if value:
- setattr(self, attr, INT_TYPE(value))
+ setattr(self, attr, int(value))
class CellStatsEvent(Event):
diff --git a/stem/response/getinfo.py b/stem/response/getinfo.py
index 0b9766ba..27442ffd 100644
--- a/stem/response/getinfo.py
+++ b/stem/response/getinfo.py
@@ -53,8 +53,7 @@ class GetInfoResponse(stem.response.ControlMessage):
except ValueError:
raise stem.ProtocolError('GETINFO replies should only contain parameter=value mappings:\n%s' % self)
- if stem.prereq.is_python_3():
- key = stem.util.str_tools._to_unicode(key)
+ key = stem.util.str_tools._to_unicode(key)
# if the value is a multiline value then it *must* be of the form
# '<key>=\n<value>'
diff --git a/stem/response/protocolinfo.py b/stem/response/protocolinfo.py
index 1763e59f..46f6ab4f 100644
--- a/stem/response/protocolinfo.py
+++ b/stem/response/protocolinfo.py
@@ -108,9 +108,7 @@ class ProtocolInfoResponse(stem.response.ControlMessage):
if line.is_next_mapping('COOKIEFILE', True, True):
self.cookie_path = line.pop_mapping(True, True, get_bytes = True)[1].decode(sys.getfilesystemencoding())
-
- if stem.prereq.is_python_3():
- self.cookie_path = stem.util.str_tools._to_unicode(self.cookie_path) # normalize back to str
+ self.cookie_path = stem.util.str_tools._to_unicode(self.cookie_path) # normalize back to str
elif line_type == 'VERSION':
# Line format:
# VersionLine = "250-VERSION" SP "Tor=" TorVersion OptArguments CRLF
diff --git a/stem/socket.py b/stem/socket.py
index 26e8f22e..275a55d4 100644
--- a/stem/socket.py
+++ b/stem/socket.py
@@ -710,9 +710,8 @@ def recv_message(control_file, arrived_at = None):
status_code, divider, content = line[:3], line[3:4], line[4:-2] # strip CRLF off content
- if stem.prereq.is_python_3():
- status_code = stem.util.str_tools._to_unicode(status_code)
- divider = stem.util.str_tools._to_unicode(divider)
+ status_code = stem.util.str_tools._to_unicode(status_code)
+ divider = stem.util.str_tools._to_unicode(divider)
# Most controller responses are single lines, in which case we don't need
# so much overhead.
diff --git a/stem/util/__init__.py b/stem/util/__init__.py
index 226f5fbf..c6b9ce34 100644
--- a/stem/util/__init__.py
+++ b/stem/util/__init__.py
@@ -56,7 +56,7 @@ def _hash_value(val):
#
# This hack will go away when we drop Python 2.x support.
- if _is_str(val):
+ if isinstance(val, (bytes, str)):
my_hash = hash('str')
else:
# Hashing common builtins (ints, bools, etc) provide consistant values but many others vary their value on interpreter invokation.
@@ -75,40 +75,6 @@ def _hash_value(val):
return my_hash
-def _is_str(val):
- """
- Check if a value is a string. This will be removed when we no longer provide
- backward compatibility for the Python 2.x series.
-
- :param object val: value to be checked
-
- :returns: **True** if the value is some form of string (unicode or bytes),
- and **False** otherwise
- """
-
- if stem.prereq.is_python_3():
- return isinstance(val, (bytes, str))
- else:
- return isinstance(val, (bytes, unicode))
-
-
-def _is_int(val):
- """
- Check if a value is an integer. This will be removed when we no longer
- provide backward compatibility for the Python 2.x series.
-
- :param object val: value to be checked
-
- :returns: **True** if the value is some form of integer (int or long),
- and **False** otherwise
- """
-
- if stem.prereq.is_python_3():
- return isinstance(val, int)
- else:
- return isinstance(val, (int, long))
-
-
def datetime_to_unix(timestamp):
"""
Converts a utc datetime object to a unix timestamp.
@@ -128,7 +94,7 @@ def _pubkey_bytes(key):
Normalizes X25509 and ED25519 keys into their public key bytes.
"""
- if _is_str(key):
+ if isinstance(key, (bytes, str)):
return key
if not stem.prereq.is_crypto_available():
diff --git a/stem/util/conf.py b/stem/util/conf.py
index 7dffe95a..1dbcc243 100644
--- a/stem/util/conf.py
+++ b/stem/util/conf.py
@@ -635,14 +635,12 @@ class Config(object):
"""
with self._contents_lock:
- unicode_type = str if stem.prereq.is_python_3() else unicode
-
if value is None:
if overwrite and key in self._contents:
del self._contents[key]
else:
pass # no value so this is a no-op
- elif isinstance(value, (bytes, unicode_type)):
+ elif isinstance(value, (bytes, str)):
if not overwrite and key in self._contents:
self._contents[key].append(value)
else:
diff --git a/stem/util/connection.py b/stem/util/connection.py
index bd1fb5a2..7c8e864b 100644
--- a/stem/util/connection.py
+++ b/stem/util/connection.py
@@ -458,7 +458,7 @@ def is_valid_ipv4_address(address):
if isinstance(address, bytes):
address = str_tools._to_unicode(address)
- elif not stem.util._is_str(address):
+ elif not isinstance(address, (bytes, str)):
return False
# checks if theres four period separated values
@@ -488,7 +488,7 @@ def is_valid_ipv6_address(address, allow_brackets = False):
if isinstance(address, bytes):
address = str_tools._to_unicode(address)
- elif not stem.util._is_str(address):
+ elif not isinstance(address, (bytes, str)):
return False
if allow_brackets:
diff --git a/stem/util/enum.py b/stem/util/enum.py
index 76a52a55..abaf2490 100644
--- a/stem/util/enum.py
+++ b/stem/util/enum.py
@@ -76,7 +76,7 @@ class Enum(object):
keys, values = [], []
for entry in args:
- if stem.util._is_str(entry):
+ if isinstance(entry, (bytes, str)):
key, val = entry, _to_camel_case(entry)
elif isinstance(entry, tuple) and len(entry) == 2:
key, val = entry
diff --git a/stem/util/log.py b/stem/util/log.py
index e8d61c1d..ccf6b4ae 100644
--- a/stem/util/log.py
+++ b/stem/util/log.py
@@ -153,8 +153,7 @@ def escape(message):
:returns: str that is escaped
"""
- if stem.prereq.is_python_3():
- message = stem.util.str_tools._to_unicode(message)
+ message = stem.util.str_tools._to_unicode(message)
for pattern, replacement in (('\n', '\\n'), ('\r', '\\r'), ('\t', '\\t')):
message = message.replace(pattern, replacement)
diff --git a/stem/util/str_tools.py b/stem/util/str_tools.py
index 58effbee..6b852f3d 100644
--- a/stem/util/str_tools.py
+++ b/stem/util/str_tools.py
@@ -61,30 +61,17 @@ TIME_UNITS = (
_timestamp_re = re.compile(r'(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})')
-if stem.prereq.is_python_3():
- def _to_bytes_impl(msg):
- if isinstance(msg, str):
- return codecs.latin_1_encode(msg, 'replace')[0]
- else:
- return msg
-
- def _to_unicode_impl(msg):
- if msg is not None and not isinstance(msg, str):
- return msg.decode('utf-8', 'replace')
- else:
- return msg
-else:
- def _to_bytes_impl(msg):
- if msg is not None and isinstance(msg, unicode):
- return codecs.latin_1_encode(msg, 'replace')[0]
- else:
- return msg
+def _to_bytes_impl(msg):
+ if isinstance(msg, str):
+ return codecs.latin_1_encode(msg, 'replace')[0]
+ else:
+ return msg
- def _to_unicode_impl(msg):
- if msg is not None and not isinstance(msg, unicode):
- return msg.decode('utf-8', 'replace')
- else:
- return msg
+def _to_unicode_impl(msg):
+ if msg is not None and not isinstance(msg, str):
+ return msg.decode('utf-8', 'replace')
+ else:
+ return msg
def _to_bytes(msg):
@@ -137,7 +124,7 @@ def _to_int(msg):
:returns: **int** representation of the string
"""
- if stem.prereq.is_python_3() and isinstance(msg, bytes):
+ if isinstance(msg, bytes):
# iterating over bytes in python3 provides ints rather than characters
return sum([pow(256, (len(msg) - i - 1)) * c for (i, c) in enumerate(msg)])
else:
@@ -508,7 +495,7 @@ def _parse_timestamp(entry):
:raises: **ValueError** if the timestamp is malformed
"""
- if not stem.util._is_str(entry):
+ if not isinstance(entry, (bytes, str)):
raise ValueError('parse_timestamp() input must be a str, got a %s' % type(entry))
try:
@@ -534,7 +521,7 @@ def _parse_iso_timestamp(entry):
:raises: **ValueError** if the timestamp is malformed
"""
- if not stem.util._is_str(entry):
+ if not isinstance(entry, (bytes, str)):
raise ValueError('parse_iso_timestamp() input must be a str, got a %s' % type(entry))
# based after suggestions from...
diff --git a/stem/util/system.py b/stem/util/system.py
index 0d2262f5..e514c3a4 100644
--- a/stem/util/system.py
+++ b/stem/util/system.py
@@ -454,7 +454,7 @@ def is_running(command):
if command_listing:
command_listing = [c.strip() for c in command_listing]
- if stem.util._is_str(command):
+ if isinstance(command, (bytes, str)):
command = [command]
for cmd in command:
diff --git a/test/integ/process.py b/test/integ/process.py
index 26346ece..88230805 100644
--- a/test/integ/process.py
+++ b/test/integ/process.py
@@ -106,7 +106,7 @@ def run_tor(tor_cmd, *args, **kwargs):
elif not exit_status and expect_failure:
raise AssertionError("Didn't expect tor to be able to start when we run: %s\n%s" % (' '.join(args), stdout))
- return stem.util.str_tools._to_unicode(stdout) if stem.prereq.is_python_3() else stdout
+ return stem.util.str_tools._to_unicode(stdout)
class TestProcess(unittest.TestCase):
@@ -177,12 +177,8 @@ class TestProcess(unittest.TestCase):
# I'm not gonna even pretend to understand the following. Ported directly
# from tor's test_cmdline_args.py.
- if stem.prereq.is_python_3():
- output_hex = binascii.a2b_hex(stem.util.str_tools._to_bytes(output).strip()[3:])
- salt, how, hashed = output_hex[:8], output_hex[8], output_hex[9:]
- else:
- output_hex = binascii.a2b_hex(output.strip()[3:])
- salt, how, hashed = output_hex[:8], ord(output_hex[8]), output_hex[9:]
+ output_hex = binascii.a2b_hex(stem.util.str_tools._to_bytes(output).strip()[3:])
+ salt, how, hashed = output_hex[:8], output_hex[8], output_hex[9:]
count = (16 + (how & 15)) << ((how >> 4) + 6)
stuff = salt + b'my_password'
diff --git a/test/task.py b/test/task.py
index 1fbcf9a4..31c7d628 100644
--- a/test/task.py
+++ b/test/task.py
@@ -273,7 +273,7 @@ class Task(object):
self.is_successful = True
output_msg = 'running' if self._is_background_task else 'done'
- if self.result and self.print_result and stem.util._is_str(self.result):
+ if self.result and self.print_result and isinstance(self.result, (bytes, str)):
output_msg = self.result
elif self.print_runtime:
output_msg += ' (%0.1fs)' % (time.time() - start_time)
diff --git a/test/unit/descriptor/collector.py b/test/unit/descriptor/collector.py
index 3d6b2da0..acdcc0d4 100644
--- a/test/unit/descriptor/collector.py
+++ b/test/unit/descriptor/collector.py
@@ -19,9 +19,6 @@ try:
except ImportError:
from mock import Mock, patch
-URL_OPEN = 'urllib.request.urlopen' if stem.prereq.is_python_3() else 'urllib2.urlopen'
-
-
with open(get_resource('collector/index.json'), 'rb') as index_file:
EXAMPLE_INDEX_JSON = index_file.read()
@@ -60,7 +57,7 @@ class TestCollector(unittest.TestCase):
# tests for the CollecTor class
- @patch(URL_OPEN)
+ @patch('urllib.request.urlopen')
def test_index_plaintext(self, urlopen_mock):
urlopen_mock.return_value = io.BytesIO(EXAMPLE_INDEX_JSON)
@@ -68,7 +65,7 @@ class TestCollector(unittest.TestCase):
self.assertEqual(EXAMPLE_INDEX, collector.index(Compression.PLAINTEXT))
urlopen_mock.assert_called_with('https://collector.torproject.org/index/index.json', timeout = None)
- @patch(URL_OPEN)
+ @patch('urllib.request.urlopen')
def test_index_gzip(self, urlopen_mock):
if not Compression.GZIP.available:
self.skipTest('(gzip compression unavailable)')
@@ -80,7 +77,7 @@ class TestCollector(unittest.TestCase):
self.assertEqual(EXAMPLE_INDEX, collector.index(Compression.GZIP))
urlopen_mock.assert_called_with('https://collector.torproject.org/index/index.json.gz', timeout = None)
- @patch(URL_OPEN)
+ @patch('urllib.request.urlopen')
def test_index_bz2(self, urlopen_mock):
if not Compression.BZ2.available:
self.skipTest('(bz2 compression unavailable)')
@@ -92,7 +89,7 @@ class TestCollector(unittest.TestCase):
self.assertEqual(EXAMPLE_INDEX, collector.index(Compression.BZ2))
urlopen_mock.assert_called_with('https://collector.torproject.org/index/index.json.bz2', timeout = None)
- @patch(URL_OPEN)
+ @patch('urllib.request.urlopen')
def test_index_lzma(self, urlopen_mock):
if not Compression.LZMA.available:
self.skipTest('(lzma compression unavailable)')
@@ -104,7 +101,7 @@ class TestCollector(unittest.TestCase):
self.assertEqual(EXAMPLE_INDEX, collector.index(Compression.LZMA))
urlopen_mock.assert_called_with('https://collector.torproject.org/index/index.json.xz', timeout = None)
- @patch(URL_OPEN)
+ @patch('urllib.request.urlopen')
def test_index_retries(self, urlopen_mock):
urlopen_mock.side_effect = IOError('boom')
@@ -118,21 +115,17 @@ class TestCollector(unittest.TestCase):
self.assertRaisesRegexp(IOError, 'boom', collector.index)
self.assertEqual(5, urlopen_mock.call_count)
- @patch(URL_OPEN, Mock(return_value = io.BytesIO(b'not json')))
+ @patch('urllib.request.urlopen', Mock(return_value = io.BytesIO(b'not json')))
def test_index_malformed_json(self):
collector = CollecTor()
-
- if stem.prereq.is_python_3():
- self.assertRaisesRegexp(ValueError, 'Expecting value: line 1 column 1', collector.index, Compression.PLAINTEXT)
- else:
- self.assertRaisesRegexp(ValueError, 'No JSON object could be decoded', collector.index, Compression.PLAINTEXT)
+ self.assertRaisesRegexp(ValueError, 'Expecting value: line 1 column 1', collector.index, Compression.PLAINTEXT)
def test_index_malformed_compression(self):
for compression in (Compression.GZIP, Compression.BZ2, Compression.LZMA):
if not compression.available:
continue
- with patch(URL_OPEN, Mock(return_value = io.BytesIO(b'not compressed'))):
+ with patch('urllib.request.urlopen', Mock(return_value = io.BytesIO(b'not compressed'))):
collector = CollecTor()
self.assertRaisesRegexp(IOError, 'Failed to decompress as %s' % compression, collector.index, compression)
diff --git a/test/unit/descriptor/remote.py b/test/unit/descriptor/remote.py
index 7703c62c..f8421757 100644
--- a/test/unit/descriptor/remote.py
+++ b/test/unit/descriptor/remote.py
@@ -27,12 +27,6 @@ try:
except ImportError:
from mock import patch, Mock, MagicMock
-# The urlopen() method is in a different location depending on if we're using
-# python 2.x or 3.x. The 2to3 converter accounts for this in imports, but not
-# mock annotations.
-
-URL_OPEN = 'urllib.request.urlopen' if stem.prereq.is_python_3() else 'urllib2.urlopen'
-
TEST_RESOURCE = '/tor/server/fp/9695DFC35FFEB861329B9F1AB04C46397020CE31'
# Output from requesting moria1's descriptor from itself...
@@ -104,16 +98,13 @@ def _dirport_mock(data, encoding = 'identity'):
dirport_mock = Mock()
dirport_mock().read.return_value = data
- if stem.prereq.is_python_3():
- headers = HTTPMessage()
+ headers = HTTPMessage()
- for line in HEADER.splitlines():
- key, value = line.split(': ', 1)
- headers.add_header(key, encoding if key == 'Content-Encoding' else value)
+ for line in HEADER.splitlines():
+ key, value = line.split(': ', 1)
+ headers.add_header(key, encoding if key == 'Content-Encoding' else value)
- dirport_mock().headers = headers
- else:
- dirport_mock().headers = HTTPMessage(io.BytesIO(HEADER % encoding))
+ dirport_mock().headers = headers
return dirport_mock
@@ -165,7 +156,7 @@ class TestDescriptorDownloader(unittest.TestCase):
self.assertRaisesRegexp(stem.ProtocolError, "^Response should begin with HTTP success, but was 'HTTP/1.0 500 Kaboom'", request.run)
- @patch(URL_OPEN, _dirport_mock(TEST_DESCRIPTOR))
+ @patch('urllib.request.urlopen', _dirport_mock(TEST_DESCRIPTOR))
def test_using_dirport(self):
"""
Download a descriptor through the DirPort.
@@ -203,7 +194,7 @@ class TestDescriptorDownloader(unittest.TestCase):
query = stem.descriptor.remote.Query(TEST_RESOURCE, compression = Compression.LZMA, start = False)
self.assertEqual([stem.descriptor.Compression.PLAINTEXT], query.compression)
- @patch(URL_OPEN, _dirport_mock(read_resource('compressed_identity'), encoding = 'identity'))
+ @patch('urllib.request.urlopen', _dirport_mock(read_resource('compressed_identity'), encoding = 'identity'))
def test_compression_plaintext(self):
"""
Download a plaintext descriptor.
@@ -218,7 +209,7 @@ class TestDescriptorDownloader(unittest.TestCase):
self.assertEqual(1, len(descriptors))
self.assertEqual('moria1', descriptors[0].nickname)
- @patch(URL_OPEN, _dirport_mock(read_resource('compressed_gzip'), encoding = 'gzip'))
+ @patch('urllib.request.urlopen', _dirport_mock(read_resource('compressed_gzip'), encoding = 'gzip'))
def test_compression_gzip(self):
"""
Download a gip compressed descriptor.
@@ -233,7 +224,7 @@ class TestDescriptorDownloader(unittest.TestCase):
self.assertEqual(1, len(descriptors))
self.assertEqual('moria1', descriptors[0].nickname)
- @patch(URL_OPEN, _dirport_mock(read_resource('compressed_zstd'), encoding = 'x-zstd'))
+ @patch('urllib.request.urlopen', _dirport_mock(read_resource('compressed_zstd'), encoding = 'x-zstd'))
def test_compression_zstd(self):
"""
Download a zstd compressed descriptor.
@@ -251,7 +242,7 @@ class TestDescriptorDownloader(unittest.TestCase):
self.assertEqual(1, len(descriptors))
self.assertEqual('moria1', descriptors[0].nickname)
- @patch(URL_OPEN, _dirport_mock(read_resource('compressed_lzma'), encoding = 'x-tor-lzma'))
+ @patch('urllib.request.urlopen', _dirport_mock(read_resource('compressed_lzma'), encoding = 'x-tor-lzma'))
def test_compression_lzma(self):
"""
Download a lzma compressed descriptor.
@@ -269,7 +260,7 @@ class TestDescriptorDownloader(unittest.TestCase):
self.assertEqual(1, len(descriptors))
self.assertEqual('moria1', descriptors[0].nickname)
- @patch(URL_OPEN)
+ @patch('urllib.request.urlopen')
def test_each_getter(self, dirport_mock):
"""
Surface level exercising of each getter method for downloading descriptors.
@@ -286,7 +277,7 @@ class TestDescriptorDownloader(unittest.TestCase):
downloader.get_bandwidth_file()
downloader.get_detached_signatures()
- @patch(URL_OPEN, _dirport_mock(TEST_DESCRIPTOR))
+ @patch('urllib.request.urlopen', _dirport_mock(TEST_DESCRIPTOR))
def test_reply_headers(self):
query = stem.descriptor.remote.get_server_descriptors('9695DFC35FFEB861329B9F1AB04C46397020CE31', start = False)
self.assertEqual(None, query.reply_headers) # initially we don't have a reply
@@ -309,7 +300,7 @@ class TestDescriptorDownloader(unittest.TestCase):
self.assertEqual(1, len(descriptors))
self.assertEqual('moria1', descriptors[0].nickname)
- @patch(URL_OPEN, _dirport_mock(TEST_DESCRIPTOR))
+ @patch('urllib.request.urlopen', _dirport_mock(TEST_DESCRIPTOR))
def test_query_download(self):
"""
Check Query functionality when we successfully download a descriptor.
@@ -334,7 +325,7 @@ class TestDescriptorDownloader(unittest.TestCase):
self.assertEqual('9695DFC35FFEB861329B9F1AB04C46397020CE31', desc.fingerprint)
self.assertEqual(TEST_DESCRIPTOR, desc.get_bytes())
- @patch(URL_OPEN, _dirport_mock(b'some malformed stuff'))
+ @patch('urllib.request.urlopen', _dirport_mock(b'some malformed stuff'))
def test_query_with_malformed_content(self):
"""
Query with malformed descriptor content.
@@ -361,7 +352,7 @@ class TestDescriptorDownloader(unittest.TestCase):
self.assertRaises(ValueError, query.run)
- @patch(URL_OPEN)
+ @patch('urllib.request.urlopen')
def test_query_with_timeout(self, dirport_mock):
def urlopen_call(*args, **kwargs):
time.sleep(0.06)
@@ -396,7 +387,7 @@ class TestDescriptorDownloader(unittest.TestCase):
expected_error = 'Endpoints must be an stem.ORPort, stem.DirPort, or two value tuple. ' + error_suffix
self.assertRaisesWith(ValueError, expected_error, stem.descriptor.remote.Query, TEST_RESOURCE, 'server-descriptor 1.0', endpoints = endpoints)
- @patch(URL_OPEN, _dirport_mock(TEST_DESCRIPTOR))
+ @patch('urllib.request.urlopen', _dirport_mock(TEST_DESCRIPTOR))
def test_can_iterate_multiple_times(self):
query = stem.descriptor.remote.Query(
TEST_RESOURCE,
diff --git a/test/unit/directory/authority.py b/test/unit/directory/authority.py
index 1c2a86b4..c2ebd322 100644
--- a/test/unit/directory/authority.py
+++ b/test/unit/directory/authority.py
@@ -15,8 +15,6 @@ try:
except ImportError:
from mock import patch, Mock
-URL_OPEN = 'urllib.request.urlopen' if stem.prereq.is_python_3() else 'urllib2.urlopen'
-
AUTHORITY_GITWEB_CONTENT = b"""\
"moria1 orport=9101 "
"v3ident=D586D18309DED4CD6D57C18FDB97EFA96D330566 "
@@ -53,7 +51,7 @@ class TestAuthority(unittest.TestCase):
self.assertTrue(len(authorities) > 4)
self.assertEqual('128.31.0.39', authorities['moria1'].address)
- @patch(URL_OPEN, Mock(return_value = io.BytesIO(AUTHORITY_GITWEB_CONTENT)))
+ @patch('urllib.request.urlopen', Mock(return_value = io.BytesIO(AUTHORITY_GITWEB_CONTENT)))
def test_from_remote(self):
expected = {
'moria1': stem.directory.Authority(
@@ -77,6 +75,6 @@ class TestAuthority(unittest.TestCase):
self.assertEqual(expected, stem.directory.Authority.from_remote())
- @patch(URL_OPEN, Mock(return_value = io.BytesIO(b'')))
+ @patch('urllib.request.urlopen', Mock(return_value = io.BytesIO(b'')))
def test_from_remote_empty(self):
self.assertRaisesRegexp(stem.DownloadFailed, 'no content', stem.directory.Authority.from_remote)
diff --git a/test/unit/directory/fallback.py b/test/unit/directory/fallback.py
index 00965187..f999943f 100644
--- a/test/unit/directory/fallback.py
+++ b/test/unit/directory/fallback.py
@@ -18,8 +18,6 @@ try:
except ImportError:
from mock import patch, Mock
-URL_OPEN = 'urllib.request.urlopen' if stem.prereq.is_python_3() else 'urllib2.urlopen'
-
FALLBACK_GITWEB_CONTENT = b"""\
/* type=fallback */
/* version=2.0.0 */
@@ -90,7 +88,7 @@ class TestFallback(unittest.TestCase):
self.assertTrue(len(fallbacks) > 10)
self.assertEqual('185.13.39.197', fallbacks['001524DD403D729F08F7E5D77813EF12756CFA8D'].address)
- @patch(URL_OPEN, Mock(return_value = io.BytesIO(FALLBACK_GITWEB_CONTENT)))
+ @patch('urllib.request.urlopen', Mock(return_value = io.BytesIO(FALLBACK_GITWEB_CONTENT)))
def test_from_remote(self):
expected = {
'0756B7CD4DFC8182BE23143FAC0642F515182CEB': stem.directory.Fallback(
@@ -117,15 +115,15 @@ class TestFallback(unittest.TestCase):
self.assertEqual(expected, stem.directory.Fallback.from_remote())
- @patch(URL_OPEN, Mock(return_value = io.BytesIO(b'')))
+ @patch('urllib.request.urlopen', Mock(return_value = io.BytesIO(b'')))
def test_from_remote_empty(self):
self.assertRaisesRegexp(stem.DownloadFailed, 'no content', stem.directory.Fallback.from_remote)
- @patch(URL_OPEN, Mock(return_value = io.BytesIO(b'\n'.join(FALLBACK_GITWEB_CONTENT.splitlines()[1:]))))
+ @patch('urllib.request.urlopen', Mock(return_value = io.BytesIO(b'\n'.join(FALLBACK_GITWEB_CONTENT.splitlines()[1:]))))
def test_from_remote_no_header(self):
self.assertRaisesRegexp(IOError, 'does not have a type field indicating it is fallback directory metadata', stem.directory.Fallback.from_remote)
- @patch(URL_OPEN, Mock(return_value = io.BytesIO(FALLBACK_GITWEB_CONTENT.replace(b'version=2.0.0', b'version'))))
+ @patch('urllib.request.urlopen', Mock(return_value = io.BytesIO(FALLBACK_GITWEB_CONTENT.replace(b'version=2.0.0', b'version'))))
def test_from_remote_malformed_header(self):
self.assertRaisesRegexp(IOError, 'Malformed fallback directory header line: /\\* version \\*/', stem.directory.Fallback.from_remote)
@@ -140,7 +138,7 @@ class TestFallback(unittest.TestCase):
}
for entry, expected in test_values.items():
- with patch(URL_OPEN, Mock(return_value = io.BytesIO(entry))):
+ with patch('urllib.request.urlopen', Mock(return_value = io.BytesIO(entry))):
self.assertRaisesRegexp(IOError, re.escape(expected), stem.directory.Fallback.from_remote)
def test_persistence(self):
diff --git a/test/unit/manual.py b/test/unit/manual.py
index c108af19..b10ce2a0 100644
--- a/test/unit/manual.py
+++ b/test/unit/manual.py
@@ -26,7 +26,6 @@ try:
except ImportError:
from mock import Mock, patch
-URL_OPEN = 'urllib.request.urlopen' if stem.prereq.is_python_3() else 'urllib2.urlopen'
EXAMPLE_MAN_PATH = os.path.join(os.path.dirname(__file__), 'tor_man_example')
UNKNOWN_OPTIONS_MAN_PATH = os.path.join(os.path.dirname(__file__), 'tor_man_with_unknown')
@@ -252,7 +251,7 @@ class TestManual(unittest.TestCase):
@patch('shutil.rmtree', Mock())
@patch('stem.manual.open', Mock(return_value = io.BytesIO()), create = True)
@patch('stem.util.system.is_available', Mock(return_value = True))
- @patch(URL_OPEN, Mock(side_effect = urllib.URLError('<urlopen error [Errno -2] Name or service not known>')))
+ @patch('urllib.request.urlopen', Mock(side_effect = urllib.URLError('<urlopen error [Errno -2] Name or service not known>')))
def test_download_man_page_when_download_fails(self):
exc_msg = "Unable to download tor's manual from https://www.atagar.com/foo/bar to /no/such/path/tor.1.txt: <urlopen error <urlopen error [Errno -2] Name or service not known>>"
self.assertRaisesWith(IOError, exc_msg, stem.manual.download_man_page, '/tmp/no_such_file', url = 'https://www.atagar.com/foo/bar')
@@ -262,7 +261,7 @@ class TestManual(unittest.TestCase):
@patch('stem.manual.open', Mock(return_value = io.BytesIO()), create = True)
@patch('stem.util.system.call', Mock(side_effect = stem.util.system.CallError('call failed', 'a2x -f manpage /no/such/path/tor.1.txt', 1, None, None, 'call failed')))
@patch('stem.util.system.is_available', Mock(return_value = True))
- @patch(URL_OPEN, Mock(return_value = io.BytesIO(b'test content')))
+ @patch('urllib.request.urlopen', Mock(return_value = io.BytesIO(b'test content')))
def test_download_man_page_when_a2x_fails(self):
exc_msg = "Unable to run 'a2x -f manpage /no/such/path/tor.1.txt': call failed"
self.assertRaisesWith(IOError, exc_msg, stem.manual.download_man_page, '/tmp/no_such_file', url = 'https://www.atagar.com/foo/bar')
@@ -273,7 +272,7 @@ class TestManual(unittest.TestCase):
@patch('stem.util.system.call')
@patch('stem.util.system.is_available', Mock(return_value = True))
@patch('os.path.exists', Mock(return_value = True))
- @patch(URL_OPEN, Mock(return_value = io.BytesIO(b'test content')))
+ @patch('urllib.request.urlopen', Mock(return_value = io.BytesIO(b'test content')))
def test_download_man_page_when_successful(self, call_mock, open_mock):
open_mock.side_effect = lambda path, *args: {
'/no/such/path/tor.1.txt': io.BytesIO(),
diff --git a/test/unit/tutorial_examples.py b/test/unit/tutorial_examples.py
index de00a2b8..67a688b8 100644
--- a/test/unit/tutorial_examples.py
+++ b/test/unit/tutorial_examples.py
@@ -129,12 +129,6 @@ def _get_router_status(address = None, port = None, nickname = None, fingerprint
class TestTutorialExamples(unittest.TestCase):
- def assert_equal_unordered(self, expected, actual):
- if stem.prereq.is_python_3():
- self.assertCountEqual(expected.splitlines(), actual.splitlines())
- else:
- self.assertItemsEqual(expected.splitlines(), actual.splitlines())
-
@patch('sys.stdout', new_callable = StringIO)
@patch('stem.control.Controller.from_port', spec = Controller)
def test_list_circuits(self, from_port_mock, stdout_mock):
@@ -164,7 +158,7 @@ class TestTutorialExamples(unittest.TestCase):
}[fingerprint]
exec_documentation_example('list_circuits.py')
- self.assert_equal_unordered(LIST_CIRCUITS_OUTPUT, stdout_mock.getvalue())
+ self.assertCountEqual(LIST_CIRCUITS_OUTPUT.splitlines(), stdout_mock.getvalue().splitlines())
@patch('sys.stdout', new_callable = StringIO)
@patch('stem.control.Controller.from_port', spec = Controller)
@@ -215,7 +209,7 @@ class TestTutorialExamples(unittest.TestCase):
controller.get_info.return_value = 'unknown'
tutorial_example(event)
- self.assert_equal_unordered(EXIT_USED_OUTPUT, stdout_mock.getvalue())
+ self.assertCountEqual(EXIT_USED_OUTPUT.splitlines(), stdout_mock.getvalue().splitlines())
@patch('sys.stdout', new_callable = StringIO)
@patch('stem.descriptor.remote.DescriptorDownloader')
@@ -229,7 +223,7 @@ class TestTutorialExamples(unittest.TestCase):
exec_documentation_example('outdated_relays.py')
- self.assert_equal_unordered(OUTDATED_RELAYS_OUTPUT, stdout_mock.getvalue())
+ self.assertCountEqual(OUTDATED_RELAYS_OUTPUT.splitlines(), stdout_mock.getvalue().splitlines())
@patch('sys.stdout', new_callable = StringIO)
@patch('stem.descriptor.remote.Query')
@@ -270,7 +264,7 @@ class TestTutorialExamples(unittest.TestCase):
exec_documentation_example('compare_flags.py')
- self.assert_equal_unordered(COMPARE_FLAGS_OUTPUT, stdout_mock.getvalue())
+ self.assertCountEqual(COMPARE_FLAGS_OUTPUT.splitlines(), stdout_mock.getvalue().splitlines())
@patch('sys.stdout', new_callable = StringIO)
@patch('stem.directory.Authority.from_cache')
@@ -303,7 +297,7 @@ class TestTutorialExamples(unittest.TestCase):
query_mock.side_effect = [query1, query2, query3]
exec_documentation_example('votes_by_bandwidth_authorities.py')
- self.assert_equal_unordered(VOTES_BY_BANDWIDTH_AUTHORITIES_OUTPUT, stdout_mock.getvalue())
+ self.assertCountEqual(VOTES_BY_BANDWIDTH_AUTHORITIES_OUTPUT.splitlines(), stdout_mock.getvalue().splitlines())
@patch('sys.stdout', new_callable = StringIO)
@patch('stem.descriptor.parse_file')
diff --git a/test/unit/util/connection.py b/test/unit/util/connection.py
index 8721ff6d..73cb3c38 100644
--- a/test/unit/util/connection.py
+++ b/test/unit/util/connection.py
@@ -23,7 +23,6 @@ try:
except ImportError:
from mock import Mock, patch
-URL_OPEN = 'urllib.request.urlopen' if stem.prereq.is_python_3() else 'urllib2.urlopen'
URL = 'https://example.unit.test.url'
NETSTAT_OUTPUT = """\
@@ -177,14 +176,14 @@ _tor tor 15843 20* internet stream tcp 0x0 192.168.1.100:36174 -->
class TestConnection(unittest.TestCase):
- @patch(URL_OPEN)
+ @patch('urllib.request.urlopen')
def test_download(self, urlopen_mock):
urlopen_mock.return_value = io.BytesIO(b'hello')
self.assertEqual(b'hello', stem.util.connection.download(URL))
urlopen_mock.assert_called_with(URL, timeout = None)
- @patch(URL_OPEN)
+ @patch('urllib.request.urlopen')
def test_download_failure(self, urlopen_mock):
urlopen_mock.side_effect = urllib.URLError('boom')
@@ -198,7 +197,7 @@ class TestConnection(unittest.TestCase):
self.assertEqual(urllib.URLError, type(exc.error))
self.assertTrue('return urllib.urlopen(url, timeout = timeout).read()' in exc.stacktrace_str)
- @patch(URL_OPEN)
+ @patch('urllib.request.urlopen')
def test_download_retries(self, urlopen_mock):
urlopen_mock.side_effect = urllib.URLError('boom')
1
0
commit 5691ff000a40059a2a9812e627574ac88cc7c754
Author: Damian Johnson <atagar(a)torproject.org>
Date: Fri Jan 3 15:54:22 2020 -0800
Drop mock fallback
Python 3.3 added mock as a builtin. As such we no longer need to use python
2.x's standalone mock module as a fallback.
---
run_tests.py | 15 -----------
stem/prereq.py | 43 -------------------------------
test/integ/connection/connect.py | 8 ++----
test/integ/process.py | 8 ++----
test/integ/response/protocolinfo.py | 6 +----
test/integ/util/system.py | 8 ++----
test/task.py | 2 --
test/unit/connection/authentication.py | 8 ++----
test/unit/connection/connect.py | 15 +++++------
test/unit/control/controller.py | 8 ++----
test/unit/descriptor/bandwidth_file.py | 8 ++----
test/unit/descriptor/collector.py | 8 ++----
test/unit/descriptor/hidden_service_v3.py | 8 ++----
test/unit/descriptor/reader.py | 6 +----
test/unit/descriptor/remote.py | 8 ++----
test/unit/descriptor/server_descriptor.py | 8 ++----
test/unit/directory/authority.py | 6 +----
test/unit/directory/fallback.py | 6 +----
test/unit/doctest.py | 8 ++----
test/unit/exit_policy/policy.py | 6 +----
test/unit/interpreter/__init__.py | 6 +----
test/unit/interpreter/autocomplete.py | 9 ++-----
test/unit/interpreter/commands.py | 8 ++----
test/unit/manual.py | 8 ++----
test/unit/response/events.py | 8 ++----
test/unit/response/protocolinfo.py | 8 ++----
test/unit/tutorial.py | 8 ++----
test/unit/tutorial_examples.py | 8 ++----
test/unit/util/connection.py | 8 ++----
test/unit/util/proc.py | 7 ++---
test/unit/util/system.py | 8 ++----
test/unit/version.py | 8 ++----
32 files changed, 56 insertions(+), 231 deletions(-)
diff --git a/run_tests.py b/run_tests.py
index 8d7ea45e..fc67af3c 100755
--- a/run_tests.py
+++ b/run_tests.py
@@ -194,20 +194,6 @@ def main():
println('Nothing to run (for usage provide --help)\n')
sys.exit()
- if not stem.prereq.is_mock_available():
- try:
- import mock
- println(MOCK_OUT_OF_DATE_MSG % mock.__version__)
- except ImportError:
- println(MOCK_UNAVAILABLE_MSG)
-
- if stem.util.system.is_available('pip'):
- println("You can get it by running 'sudo pip install mock'.")
- elif stem.util.system.is_available('apt-get'):
- println("You can get it by running 'sudo apt-get install python-mock'.")
-
- sys.exit(1)
-
test.task.run(
'INITIALISING',
test.task.STEM_VERSION,
@@ -215,7 +201,6 @@ def main():
test.task.PYTHON_VERSION,
test.task.PLATFORM_VERSION,
test.task.CRYPTO_VERSION,
- test.task.MOCK_VERSION,
test.task.PYFLAKES_VERSION,
test.task.PYCODESTYLE_VERSION,
test.task.CLEAN_PYC,
diff --git a/stem/prereq.py b/stem/prereq.py
index bd006bd0..74584165 100644
--- a/stem/prereq.py
+++ b/stem/prereq.py
@@ -16,7 +16,6 @@ stem will still read descriptors - just without signature checks.
is_crypto_available - checks if the cryptography module is available
is_zstd_available - checks if the zstd module is available
is_lzma_available - checks if the lzma module is available
- is_mock_available - checks if the mock module is available
"""
import functools
@@ -162,48 +161,6 @@ def is_lzma_available():
return False
-def is_mock_available():
- """
- Checks if the mock module is available. In python 3.3 and up it is a builtin
- unittest module, but before this it needed to be `installed separately
- <https://pypi.org/project/mock/>`_. Imports should be as follows....
-
- ::
-
- try:
- # added in python 3.3
- from unittest.mock import Mock
- except ImportError:
- from mock import Mock
-
- :returns: **True** if the mock module is available and **False** otherwise
- """
-
- try:
- # checks for python 3.3 version
- import unittest.mock
- return True
- except ImportError:
- pass
-
- try:
- import mock
-
- # check for mock's patch.dict() which was introduced in version 0.7.0
-
- if not hasattr(mock.patch, 'dict'):
- raise ImportError()
-
- # check for mock's new_callable argument for patch() which was introduced in version 0.8.0
-
- if 'new_callable' not in inspect.getargspec(mock.patch).args:
- raise ImportError()
-
- return True
- except ImportError:
- return False
-
-
def _is_sha3_available():
"""
Check if hashlib has sha3 support. This requires Python 3.6+ *or* the `pysha3
diff --git a/test/integ/connection/connect.py b/test/integ/connection/connect.py
index f4df233f..bfeefb19 100644
--- a/test/integ/connection/connect.py
+++ b/test/integ/connection/connect.py
@@ -8,17 +8,13 @@ import stem.connection
import test.require
import test.runner
+from unittest.mock import patch
+
try:
from StringIO import StringIO
except ImportError:
from io import StringIO
-try:
- # added in python 3.3
- from unittest.mock import patch
-except ImportError:
- from mock import patch
-
class TestConnect(unittest.TestCase):
@test.require.controller
diff --git a/test/integ/process.py b/test/integ/process.py
index 88230805..e7d2cae3 100644
--- a/test/integ/process.py
+++ b/test/integ/process.py
@@ -28,13 +28,9 @@ import test
import test.require
from contextlib import contextmanager
-from stem.util.test_tools import asynchronous, assert_equal, assert_in, skip
+from unittest.mock import patch, Mock
-try:
- # added in python 3.3
- from unittest.mock import patch, Mock
-except ImportError:
- from mock import patch, Mock
+from stem.util.test_tools import asynchronous, assert_equal, assert_in, skip
BASIC_RELAY_TORRC = """\
SocksPort 9089
diff --git a/test/integ/response/protocolinfo.py b/test/integ/response/protocolinfo.py
index 5d8c74f6..917b87c3 100644
--- a/test/integ/response/protocolinfo.py
+++ b/test/integ/response/protocolinfo.py
@@ -14,11 +14,7 @@ import test.integ.util.system
import test.require
import test.runner
-try:
- # added in python 3.3
- from unittest.mock import Mock, patch
-except ImportError:
- from mock import Mock, patch
+from unittest.mock import Mock, patch
class TestProtocolInfo(unittest.TestCase):
diff --git a/test/integ/util/system.py b/test/integ/util/system.py
index 3b48433d..4d83d695 100644
--- a/test/integ/util/system.py
+++ b/test/integ/util/system.py
@@ -14,13 +14,9 @@ import stem.util.system
import test.require
import test.runner
-from stem.util.system import State, DaemonTask
+from unittest.mock import Mock, patch
-try:
- # added in python 3.3
- from unittest.mock import Mock, patch
-except ImportError:
- from mock import Mock, patch
+from stem.util.system import State, DaemonTask
def filter_system_call(prefixes):
diff --git a/test/task.py b/test/task.py
index 31c7d628..70ab5e4b 100644
--- a/test/task.py
+++ b/test/task.py
@@ -14,7 +14,6 @@
|- PYTHON_VERSION - checks our python version
|- PLATFORM_VERSION - checks our operating system version
|- CRYPTO_VERSION - checks our version of cryptography
- |- MOCK_VERSION - checks our version of mock
|- PYFLAKES_VERSION - checks our version of pyflakes
|- PYCODESTYLE_VERSION - checks our version of pycodestyle
|- CLEAN_PYC - removes any *.pyc without a corresponding *.py
@@ -333,7 +332,6 @@ TOR_VERSION = Task('tor version', _check_tor_version)
PYTHON_VERSION = Task('python version', _check_python_version)
PLATFORM_VERSION = Task('operating system', _check_platform_version)
CRYPTO_VERSION = ModuleVersion('cryptography version', 'cryptography', stem.prereq.is_crypto_available)
-MOCK_VERSION = ModuleVersion('mock version', ['unittest.mock', 'mock'], stem.prereq.is_mock_available)
PYFLAKES_VERSION = ModuleVersion('pyflakes version', 'pyflakes')
PYCODESTYLE_VERSION = ModuleVersion('pycodestyle version', ['pycodestyle', 'pep8'])
CLEAN_PYC = Task('checking for orphaned .pyc files', _clean_orphaned_pyc, (SRC_PATHS,), print_runtime = True)
diff --git a/test/unit/connection/authentication.py b/test/unit/connection/authentication.py
index 117b39d9..f6241e0e 100644
--- a/test/unit/connection/authentication.py
+++ b/test/unit/connection/authentication.py
@@ -14,15 +14,11 @@ import unittest
import stem.connection
import test
+from unittest.mock import Mock, patch
+
from stem.response import ControlMessage
from stem.util import log
-try:
- # added in python 3.3
- from unittest.mock import Mock, patch
-except ImportError:
- from mock import Mock, patch
-
class TestAuthenticate(unittest.TestCase):
@patch('stem.connection.get_protocolinfo')
diff --git a/test/unit/connection/connect.py b/test/unit/connection/connect.py
index 37ded2f5..ec82f19f 100644
--- a/test/unit/connection/connect.py
+++ b/test/unit/connection/connect.py
@@ -4,20 +4,17 @@ Unit tests for the stem.connection.connect function.
import unittest
+import stem
+import stem.connection
+import stem.socket
+
+from unittest.mock import Mock, patch
+
try:
from StringIO import StringIO
except ImportError:
from io import StringIO
-try:
- from mock import Mock, patch
-except ImportError:
- from unittest.mock import Mock, patch
-
-import stem
-import stem.connection
-import stem.socket
-
class TestConnect(unittest.TestCase):
@patch('sys.stdout', new_callable = StringIO)
diff --git a/test/unit/control/controller.py b/test/unit/control/controller.py
index 94c1b65f..9628c913 100644
--- a/test/unit/control/controller.py
+++ b/test/unit/control/controller.py
@@ -14,17 +14,13 @@ import stem.socket
import stem.util.system
import stem.version
+from unittest.mock import Mock, patch
+
from stem import ControllerError, DescriptorUnavailable, InvalidArguments, InvalidRequest, ProtocolError, UnsatisfiableRequest
from stem.control import MALFORMED_EVENTS, _parse_circ_path, Listener, Controller, EventType
from stem.response import ControlMessage
from stem.exit_policy import ExitPolicy
-try:
- # added in python 3.3
- from unittest.mock import Mock, patch
-except ImportError:
- from mock import Mock, patch
-
NS_DESC = 'r %s %s u5lTXJKGsLKufRLnSyVqT7TdGYw 2012-12-30 22:02:49 77.223.43.54 9001 0\ns Fast Named Running Stable Valid\nw Bandwidth=75'
TEST_TIMESTAMP = 12345
diff --git a/test/unit/descriptor/bandwidth_file.py b/test/unit/descriptor/bandwidth_file.py
index bb1eeffa..9bee5f95 100644
--- a/test/unit/descriptor/bandwidth_file.py
+++ b/test/unit/descriptor/bandwidth_file.py
@@ -8,15 +8,11 @@ import unittest
import stem.descriptor
+from unittest.mock import Mock, patch
+
from stem.descriptor.bandwidth_file import BandwidthFile
from test.unit.descriptor import get_resource
-try:
- # added in python 3.3
- from unittest.mock import Mock, patch
-except ImportError:
- from mock import Mock, patch
-
EXPECTED_MEASUREMENT_1 = {
'scanner': '/scanner.1/scan-data/bws-0.0:0.8-done-2019-01-13-22:55:22',
'measured_at': '1547441722',
diff --git a/test/unit/descriptor/collector.py b/test/unit/descriptor/collector.py
index acdcc0d4..99e19d7c 100644
--- a/test/unit/descriptor/collector.py
+++ b/test/unit/descriptor/collector.py
@@ -8,17 +8,13 @@ import unittest
import stem.prereq
+from unittest.mock import Mock, patch
+
from stem.descriptor import Compression, DocumentHandler
from stem.descriptor.collector import CollecTor, File
from test.unit.descriptor import get_resource
from test.unit.descriptor.data.collector.index import EXAMPLE_INDEX
-try:
- # added in python 3.3
- from unittest.mock import Mock, patch
-except ImportError:
- from mock import Mock, patch
-
with open(get_resource('collector/index.json'), 'rb') as index_file:
EXAMPLE_INDEX_JSON = index_file.read()
diff --git a/test/unit/descriptor/hidden_service_v3.py b/test/unit/descriptor/hidden_service_v3.py
index 0c172fcb..4004a94d 100644
--- a/test/unit/descriptor/hidden_service_v3.py
+++ b/test/unit/descriptor/hidden_service_v3.py
@@ -14,6 +14,8 @@ import stem.prereq
import test.require
+from unittest.mock import patch, Mock
+
from stem.descriptor.hidden_service import (
IntroductionPointV3,
HiddenServiceDescriptorV3,
@@ -28,12 +30,6 @@ from test.unit.descriptor import (
base_expect_invalid_attr_for_text,
)
-try:
- # added in python 3.3
- from unittest.mock import patch, Mock
-except ImportError:
- from mock import patch, Mock
-
require_sha3 = test.require.needs(stem.prereq._is_sha3_available, 'requires sha3')
require_x25519 = test.require.needs(lambda: stem.descriptor.hidden_service.X25519_AVAILABLE, 'requires openssl x5509')
diff --git a/test/unit/descriptor/reader.py b/test/unit/descriptor/reader.py
index 589b4641..39a5d669 100644
--- a/test/unit/descriptor/reader.py
+++ b/test/unit/descriptor/reader.py
@@ -19,11 +19,7 @@ import stem.util.system
import test.unit.descriptor
-try:
- # added in python 3.3
- from unittest.mock import patch
-except ImportError:
- from mock import patch
+from unittest.mock import patch
BASIC_LISTING = """
/tmp 123
diff --git a/test/unit/descriptor/remote.py b/test/unit/descriptor/remote.py
index f8421757..98bb734b 100644
--- a/test/unit/descriptor/remote.py
+++ b/test/unit/descriptor/remote.py
@@ -13,6 +13,8 @@ import stem.descriptor.remote
import stem.prereq
import stem.util.str_tools
+from unittest.mock import patch, Mock, MagicMock
+
from stem.descriptor.remote import Compression
from test.unit.descriptor import read_resource
@@ -21,12 +23,6 @@ try:
except ImportError:
from httplib import HTTPMessage # python2
-try:
- # added in python 3.3
- from unittest.mock import patch, Mock, MagicMock
-except ImportError:
- from mock import patch, Mock, MagicMock
-
TEST_RESOURCE = '/tor/server/fp/9695DFC35FFEB861329B9F1AB04C46397020CE31'
# Output from requesting moria1's descriptor from itself...
diff --git a/test/unit/descriptor/server_descriptor.py b/test/unit/descriptor/server_descriptor.py
index 3878c8af..2f448404 100644
--- a/test/unit/descriptor/server_descriptor.py
+++ b/test/unit/descriptor/server_descriptor.py
@@ -21,6 +21,8 @@ import stem.version
import stem.util.str_tools
import test.require
+from unittest.mock import Mock, patch
+
from stem.client.datatype import CertType
from stem.descriptor import DigestHash, DigestEncoding
from stem.descriptor.certificate import ExtensionType
@@ -32,12 +34,6 @@ from test.unit.descriptor import (
base_expect_invalid_attr_for_text,
)
-try:
- # added in python 3.3
- from unittest.mock import Mock, patch
-except ImportError:
- from mock import Mock, patch
-
TARFILE_FINGERPRINTS = set([
'B6D83EC2D9E18B0A7A33428F8CFA9C536769E209',
'E0BD57A11F00041A9789577C53A1B784473669E4',
diff --git a/test/unit/directory/authority.py b/test/unit/directory/authority.py
index c2ebd322..1574bea3 100644
--- a/test/unit/directory/authority.py
+++ b/test/unit/directory/authority.py
@@ -9,11 +9,7 @@ import stem
import stem.directory
import stem.prereq
-try:
- # added in python 3.3
- from unittest.mock import patch, Mock
-except ImportError:
- from mock import patch, Mock
+from unittest.mock import patch, Mock
AUTHORITY_GITWEB_CONTENT = b"""\
"moria1 orport=9101 "
diff --git a/test/unit/directory/fallback.py b/test/unit/directory/fallback.py
index f999943f..a7c54efb 100644
--- a/test/unit/directory/fallback.py
+++ b/test/unit/directory/fallback.py
@@ -12,11 +12,7 @@ import stem
import stem.directory
import stem.util.conf
-try:
- # added in python 3.3
- from unittest.mock import patch, Mock
-except ImportError:
- from mock import patch, Mock
+from unittest.mock import patch, Mock
FALLBACK_GITWEB_CONTENT = b"""\
/* type=fallback */
diff --git a/test/unit/doctest.py b/test/unit/doctest.py
index 28eef0cf..84712dc2 100644
--- a/test/unit/doctest.py
+++ b/test/unit/doctest.py
@@ -15,13 +15,9 @@ import stem.util.system
import stem.version
import test
-from stem.response import ControlMessage
+from unittest.mock import Mock, patch
-try:
- # added in python 3.3
- from unittest.mock import Mock, patch
-except ImportError:
- from mock import Mock, patch
+from stem.response import ControlMessage
EXPECTED_CIRCUIT_STATUS = """\
20 EXTENDED $718BCEA286B531757ACAFF93AE04910EA73DE617=KsmoinOK,$649F2D0ACF418F7CFC6539AB2257EB2D5297BAFA=Eskimo BUILD_FLAGS=NEED_CAPACITY PURPOSE=GENERAL TIME_CREATED=2012-12-06T13:51:11.433755
diff --git a/test/unit/exit_policy/policy.py b/test/unit/exit_policy/policy.py
index f6cf9957..0cb755ae 100644
--- a/test/unit/exit_policy/policy.py
+++ b/test/unit/exit_policy/policy.py
@@ -5,11 +5,7 @@ Unit tests for the stem.exit_policy.ExitPolicy class.
import pickle
import unittest
-try:
- # added in python 3.3
- from unittest.mock import Mock, patch
-except ImportError:
- from mock import Mock, patch
+from unittest.mock import Mock, patch
from stem.exit_policy import (
DEFAULT_POLICY_RULES,
diff --git a/test/unit/interpreter/__init__.py b/test/unit/interpreter/__init__.py
index 7c107687..a48a19bc 100644
--- a/test/unit/interpreter/__init__.py
+++ b/test/unit/interpreter/__init__.py
@@ -9,11 +9,7 @@ __all__ = [
'help',
]
-try:
- # added in python 3.3
- from unittest.mock import Mock
-except ImportError:
- from mock import Mock
+from unittest.mock import Mock
GETINFO_NAMES = """
info/names -- List of GETINFO options, types, and documentation.
diff --git a/test/unit/interpreter/autocomplete.py b/test/unit/interpreter/autocomplete.py
index 40bcab48..8971ddc7 100644
--- a/test/unit/interpreter/autocomplete.py
+++ b/test/unit/interpreter/autocomplete.py
@@ -1,15 +1,10 @@
import unittest
-from stem.interpreter.autocomplete import _get_commands, Autocompleter
+from unittest.mock import Mock
+from stem.interpreter.autocomplete import _get_commands, Autocompleter
from test.unit.interpreter import CONTROLLER
-try:
- # added in python 3.3
- from unittest.mock import Mock
-except ImportError:
- from mock import Mock
-
class TestAutocompletion(unittest.TestCase):
def test_autocomplete_results_from_config(self):
diff --git a/test/unit/interpreter/commands.py b/test/unit/interpreter/commands.py
index 59ceadfe..412178e6 100644
--- a/test/unit/interpreter/commands.py
+++ b/test/unit/interpreter/commands.py
@@ -5,16 +5,12 @@ import stem
import stem.response
import stem.version
+from unittest.mock import Mock, patch
+
from stem.interpreter.commands import ControlInterpreter, _get_fingerprint
from stem.response import ControlMessage
from test.unit.interpreter import CONTROLLER
-try:
- # added in python 3.3
- from unittest.mock import Mock, patch
-except ImportError:
- from mock import Mock, patch
-
EXPECTED_EVENTS_RESPONSE = """\
\x1b[34mBW 15 25\x1b[0m
\x1b[34mBW 758 570\x1b[0m
diff --git a/test/unit/manual.py b/test/unit/manual.py
index b10ce2a0..6e80543e 100644
--- a/test/unit/manual.py
+++ b/test/unit/manual.py
@@ -14,18 +14,14 @@ import stem.manual
import stem.util.system
import test.require
+from unittest.mock import Mock, patch
+
try:
# account for urllib's change between python 2.x and 3.x
import urllib.request as urllib
except ImportError:
import urllib2 as urllib
-try:
- # added in python 3.3
- from unittest.mock import Mock, patch
-except ImportError:
- from mock import Mock, patch
-
EXAMPLE_MAN_PATH = os.path.join(os.path.dirname(__file__), 'tor_man_example')
UNKNOWN_OPTIONS_MAN_PATH = os.path.join(os.path.dirname(__file__), 'tor_man_with_unknown')
diff --git a/test/unit/response/events.py b/test/unit/response/events.py
index 82506e6d..27862054 100644
--- a/test/unit/response/events.py
+++ b/test/unit/response/events.py
@@ -10,16 +10,12 @@ import stem.response
import stem.response.events
import stem.util.log
+from unittest.mock import Mock
+
from stem import * # enums and exceptions
from stem.response import ControlMessage
from stem.descriptor.router_status_entry import RouterStatusEntryV3
-try:
- # added in python 3.3
- from unittest.mock import Mock
-except ImportError:
- from mock import Mock
-
# ADDRMAP event
ADDRMAP = '650 ADDRMAP www.atagar.com 75.119.206.243 "2012-11-19 00:50:13" \
diff --git a/test/unit/response/protocolinfo.py b/test/unit/response/protocolinfo.py
index ab6dd0eb..dd8d2160 100644
--- a/test/unit/response/protocolinfo.py
+++ b/test/unit/response/protocolinfo.py
@@ -11,15 +11,11 @@ import stem.util.proc
import stem.util.system
import stem.version
+from unittest.mock import Mock, patch
+
from stem.response import ControlMessage
from stem.response.protocolinfo import AuthMethod
-try:
- # added in python 3.3
- from unittest.mock import Mock, patch
-except ImportError:
- from mock import Mock, patch
-
NO_AUTH = """250-PROTOCOLINFO 1
250-AUTH METHODS=NULL
250-VERSION Tor="0.2.1.30"
diff --git a/test/unit/tutorial.py b/test/unit/tutorial.py
index e866f3ca..58abde9b 100644
--- a/test/unit/tutorial.py
+++ b/test/unit/tutorial.py
@@ -7,6 +7,8 @@ import unittest
import stem.descriptor.remote
+from unittest.mock import Mock, patch
+
from stem.control import Controller
from stem.descriptor.router_status_entry import RouterStatusEntryV2, RouterStatusEntryV3
from stem.descriptor.networkstatus import NetworkStatusDocumentV3
@@ -19,12 +21,6 @@ try:
except ImportError:
from io import StringIO
-try:
- # added in python 3.3
- from unittest.mock import Mock, patch
-except ImportError:
- from mock import Mock, patch
-
OVER_THE_RIVER_OUTPUT = """\
* Connecting to tor
diff --git a/test/unit/tutorial_examples.py b/test/unit/tutorial_examples.py
index 67a688b8..c3359d1e 100644
--- a/test/unit/tutorial_examples.py
+++ b/test/unit/tutorial_examples.py
@@ -15,6 +15,8 @@ import stem.response
import stem.descriptor.remote
import stem.prereq
+from unittest.mock import Mock, patch
+
from stem.control import Controller
from stem.descriptor.networkstatus import NetworkStatusDocumentV3
from stem.descriptor.router_status_entry import RouterStatusEntryV3
@@ -24,12 +26,6 @@ from stem.response import ControlMessage
from test.unit import exec_documentation_example
-try:
- # added in python 3.3
- from unittest.mock import Mock, patch
-except ImportError:
- from mock import Mock, patch
-
OPEN_FUNCTION = open # make a reference so mocking open() won't mess with us
CIRC_CONTENT = '650 CIRC %d %s \
diff --git a/test/unit/util/connection.py b/test/unit/util/connection.py
index 73cb3c38..047dced7 100644
--- a/test/unit/util/connection.py
+++ b/test/unit/util/connection.py
@@ -9,6 +9,8 @@ import unittest
import stem
import stem.util.connection
+from unittest.mock import Mock, patch
+
from stem.util.connection import Resolver, Connection
try:
@@ -17,12 +19,6 @@ try:
except ImportError:
import urllib2 as urllib
-try:
- # added in python 3.3
- from unittest.mock import Mock, patch
-except ImportError:
- from mock import Mock, patch
-
URL = 'https://example.unit.test.url'
NETSTAT_OUTPUT = """\
diff --git a/test/unit/util/proc.py b/test/unit/util/proc.py
index 6ee29136..2316f669 100644
--- a/test/unit/util/proc.py
+++ b/test/unit/util/proc.py
@@ -7,14 +7,11 @@ import unittest
import test
+from unittest.mock import Mock, patch
+
from stem.util import proc
from stem.util.connection import Connection
-try:
- from unittest.mock import Mock, patch
-except ImportError:
- from mock import Mock, patch
-
TITLE_LINE = b'sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout'
TCP6_CONTENT = b"""\
diff --git a/test/unit/util/system.py b/test/unit/util/system.py
index b4fb81ea..32be337c 100644
--- a/test/unit/util/system.py
+++ b/test/unit/util/system.py
@@ -14,13 +14,9 @@ import unittest
import stem.prereq
-from stem.util import system
+from unittest.mock import Mock, patch
-try:
- # added in python 3.3
- from unittest.mock import Mock, patch
-except ImportError:
- from mock import Mock, patch
+from stem.util import system
# Base responses for the pid_by_name tests. The 'success' and
# 'multiple_results' entries are filled in by tests.
diff --git a/test/unit/version.py b/test/unit/version.py
index 3c21855c..abdb65c0 100644
--- a/test/unit/version.py
+++ b/test/unit/version.py
@@ -7,13 +7,9 @@ import unittest
import stem.util.system
import stem.version
-from stem.version import Version
+from unittest.mock import Mock, patch
-try:
- # added in python 3.3
- from unittest.mock import Mock, patch
-except ImportError:
- from mock import Mock, patch
+from stem.version import Version
VERSION_CMD_OUTPUT = """Mar 22 23:09:37.088 [notice] Tor v0.2.2.35 \
(git-73ff13ab3cc9570d). This is experimental software. Do not rely on it for \
1
0
commit cc20b182cd2c4deaee0b793d2fbf05d550af280d
Author: Damian Johnson <atagar(a)torproject.org>
Date: Fri Jan 3 16:15:26 2020 -0800
Drop urllib fallback
Python 3.x renamed the urllib2 module to urllib.request.
---
cache_fallback_directories.py | 9 ++-------
cache_manual.py | 9 ++-------
stem/__init__.py | 2 +-
stem/descriptor/remote.py | 11 +++--------
stem/directory.py | 11 +++--------
stem/manual.py | 9 ++-------
stem/util/connection.py | 9 ++-------
test/integ/util/connection.py | 9 ++-------
test/unit/manual.py | 9 ++-------
test/unit/util/connection.py | 15 +++++----------
10 files changed, 24 insertions(+), 69 deletions(-)
diff --git a/cache_fallback_directories.py b/cache_fallback_directories.py
index cb413c07..91ad40c0 100755
--- a/cache_fallback_directories.py
+++ b/cache_fallback_directories.py
@@ -8,22 +8,17 @@ Caches tor's latest fallback directories.
import re
import sys
+import urllib.request
import stem.directory
import stem.util.system
-try:
- # account for urllib's change between python 2.x and 3.x
- import urllib.request as urllib
-except ImportError:
- import urllib2 as urllib
-
GITWEB_FALLBACK_LOG = 'https://gitweb.torproject.org/tor.git/log/src/app/config/fallback_dirs.inc'
FALLBACK_DIR_LINK = "href='/tor.git/commit/src/app/config/fallback_dirs.inc\\?id=([^']*)'"
if __name__ == '__main__':
try:
- fallback_dir_page = urllib.urlopen(GITWEB_FALLBACK_LOG).read()
+ fallback_dir_page = urllib.request.urlopen(GITWEB_FALLBACK_LOG).read()
fallback_dir_commit = re.search(FALLBACK_DIR_LINK, fallback_dir_page).group(1)
except:
print("Unable to determine the latest commit to edit tor's fallback directories: %s" % sys.exc_info()[1])
diff --git a/cache_manual.py b/cache_manual.py
index 7fe6ea70..5bc68b57 100755
--- a/cache_manual.py
+++ b/cache_manual.py
@@ -8,22 +8,17 @@ Caches tor's latest manual content. Run this to pick new man page changes.
import re
import sys
+import urllib.request
import stem.manual
import stem.util.system
-try:
- # account for urllib's change between python 2.x and 3.x
- import urllib.request as urllib
-except ImportError:
- import urllib2 as urllib
-
GITWEB_MAN_LOG = 'https://gitweb.torproject.org/tor.git/log/doc/tor.1.txt'
MAN_LOG_LINK = "href='/tor.git/commit/doc/tor.1.txt\\?id=([^']*)'"
if __name__ == '__main__':
try:
- man_log_page = urllib.urlopen(GITWEB_MAN_LOG).read()
+ man_log_page = urllib.request.urlopen(GITWEB_MAN_LOG).read()
man_commit = re.search(MAN_LOG_LINK, man_log_page).group(1)
except:
print("Unable to determine the latest commit to edit tor's man page: %s" % sys.exc_info()[1])
diff --git a/stem/__init__.py b/stem/__init__.py
index 66bc24b5..3600e920 100644
--- a/stem/__init__.py
+++ b/stem/__init__.py
@@ -722,7 +722,7 @@ class SocketClosed(SocketError):
class DownloadFailed(IOError):
"""
Inability to download a resource. Python's urllib module raises
- a wide variety of undocumented exceptions (urllib2.URLError,
+ a wide variety of undocumented exceptions (urllib.request.URLError,
socket.timeout, and others).
This wraps lower level failures in a common exception type that
diff --git a/stem/descriptor/remote.py b/stem/descriptor/remote.py
index c88b338e..c7132a38 100644
--- a/stem/descriptor/remote.py
+++ b/stem/descriptor/remote.py
@@ -104,6 +104,7 @@ import socket
import sys
import threading
import time
+import urllib.request
import stem
import stem.client
@@ -116,12 +117,6 @@ import stem.util.tor_tools
from stem.util import log, str_tools
-try:
- # account for urllib's change between python 2.x and 3.x
- import urllib.request as urllib
-except ImportError:
- import urllib2 as urllib
-
# TODO: remove in stem 2.x, replaced with stem.descriptor.Compression
Compression = stem.util.enum.Enum(
@@ -1070,8 +1065,8 @@ def _download_from_dirport(url, compression, timeout):
"""
try:
- response = urllib.urlopen(
- urllib.Request(
+ response = urllib.request.urlopen(
+ urllib.request.Request(
url,
headers = {
'Accept-Encoding': ', '.join(map(lambda c: c.encoding, compression)),
diff --git a/stem/directory.py b/stem/directory.py
index 0ca089c3..7a1ce7b8 100644
--- a/stem/directory.py
+++ b/stem/directory.py
@@ -42,6 +42,7 @@ import collections
import os
import re
import sys
+import urllib.request
import stem
import stem.util
@@ -49,12 +50,6 @@ import stem.util.conf
from stem.util import connection, str_tools, tor_tools
-try:
- # account for urllib's change between python 2.x and 3.x
- import urllib.request as urllib
-except ImportError:
- import urllib2 as urllib
-
GITWEB_AUTHORITY_URL = 'https://gitweb.torproject.org/tor.git/plain/src/app/config/auth_dirs.inc'
GITWEB_FALLBACK_URL = 'https://gitweb.torproject.org/tor.git/plain/src/app/config/fallback_dirs.inc'
FALLBACK_CACHE_PATH = os.path.join(os.path.dirname(__file__), 'cached_fallbacks.cfg')
@@ -260,7 +255,7 @@ class Authority(Directory):
@staticmethod
def from_remote(timeout = 60):
try:
- lines = str_tools._to_unicode(urllib.urlopen(GITWEB_AUTHORITY_URL, timeout = timeout).read()).splitlines()
+ lines = str_tools._to_unicode(urllib.request.urlopen(GITWEB_AUTHORITY_URL, timeout = timeout).read()).splitlines()
if not lines:
raise IOError('no content')
@@ -408,7 +403,7 @@ class Fallback(Directory):
@staticmethod
def from_remote(timeout = 60):
try:
- lines = str_tools._to_unicode(urllib.urlopen(GITWEB_FALLBACK_URL, timeout = timeout).read()).splitlines()
+ lines = str_tools._to_unicode(urllib.request.urlopen(GITWEB_FALLBACK_URL, timeout = timeout).read()).splitlines()
if not lines:
raise IOError('no content')
diff --git a/stem/manual.py b/stem/manual.py
index d9ad5aa7..fe49e3de 100644
--- a/stem/manual.py
+++ b/stem/manual.py
@@ -54,6 +54,7 @@ import os
import shutil
import sys
import tempfile
+import urllib.request
import stem
import stem.prereq
@@ -63,12 +64,6 @@ import stem.util.enum
import stem.util.log
import stem.util.system
-try:
- # account for urllib's change between python 2.x and 3.x
- import urllib.request as urllib
-except ImportError:
- import urllib2 as urllib
-
Category = stem.util.enum.Enum('GENERAL', 'CLIENT', 'RELAY', 'DIRECTORY', 'AUTHORITY', 'HIDDEN_SERVICE', 'DENIAL_OF_SERVICE', 'TESTING', 'UNKNOWN')
GITWEB_MANUAL_URL = 'https://gitweb.torproject.org/tor.git/plain/doc/tor.1.txt'
CACHE_PATH = os.path.join(os.path.dirname(__file__), 'cached_manual.sqlite')
@@ -300,7 +295,7 @@ def download_man_page(path = None, file_handle = None, url = GITWEB_MANUAL_URL,
try:
try:
with open(asciidoc_path, 'wb') as asciidoc_file:
- request = urllib.urlopen(url, timeout = timeout)
+ request = urllib.request.urlopen(url, timeout = timeout)
shutil.copyfileobj(request, asciidoc_file)
except:
exc, stacktrace = sys.exc_info()[1:3]
diff --git a/stem/util/connection.py b/stem/util/connection.py
index 7c8e864b..f88b3f85 100644
--- a/stem/util/connection.py
+++ b/stem/util/connection.py
@@ -62,6 +62,7 @@ import re
import socket
import sys
import time
+import urllib.request
import stem
import stem.util
@@ -70,12 +71,6 @@ import stem.util.system
from stem.util import conf, enum, log, str_tools
-try:
- # account for urllib's change between python 2.x and 3.x
- import urllib.request as urllib
-except ImportError:
- import urllib2 as urllib
-
# Connection resolution is risky to log about since it's highly likely to
# contain sensitive information. That said, it's also difficult to get right in
# a platform independent fashion. To opt into the logging requried to
@@ -197,7 +192,7 @@ def download(url, timeout = None, retries = None):
start_time = time.time()
try:
- return urllib.urlopen(url, timeout = timeout).read()
+ return urllib.request.urlopen(url, timeout = timeout).read()
except socket.timeout as exc:
raise stem.DownloadTimeout(url, exc, sys.exc_info()[2], timeout)
except:
diff --git a/test/integ/util/connection.py b/test/integ/util/connection.py
index e31ee865..861b8ba9 100644
--- a/test/integ/util/connection.py
+++ b/test/integ/util/connection.py
@@ -4,6 +4,7 @@ that we're running.
"""
import unittest
+import urllib.request
import stem
import stem.util.connection
@@ -13,12 +14,6 @@ import test.runner
from stem.util.connection import Resolver
-try:
- # account for urllib's change between python 2.x and 3.x
- import urllib.request as urllib
-except ImportError:
- import urllib2 as urllib
-
class TestConnection(unittest.TestCase):
@test.require.ptrace
@@ -58,7 +53,7 @@ class TestConnection(unittest.TestCase):
self.assertEqual('Failed to download from https://no.such.testing.url (URLError): Name or service not known', str(exc))
self.assertEqual('https://no.such.testing.url', exc.url)
self.assertEqual('Name or service not known', exc.error.reason.strerror)
- self.assertEqual(urllib.URLError, type(exc.error))
+ self.assertEqual(urllib.request.URLError, type(exc.error))
def test_connections_by_proc(self):
self.check_resolver(Resolver.PROC)
diff --git a/test/unit/manual.py b/test/unit/manual.py
index 6e80543e..eb76d6e9 100644
--- a/test/unit/manual.py
+++ b/test/unit/manual.py
@@ -8,6 +8,7 @@ import os
import sqlite3
import tempfile
import unittest
+import urllib.request
import stem.prereq
import stem.manual
@@ -16,12 +17,6 @@ import test.require
from unittest.mock import Mock, patch
-try:
- # account for urllib's change between python 2.x and 3.x
- import urllib.request as urllib
-except ImportError:
- import urllib2 as urllib
-
EXAMPLE_MAN_PATH = os.path.join(os.path.dirname(__file__), 'tor_man_example')
UNKNOWN_OPTIONS_MAN_PATH = os.path.join(os.path.dirname(__file__), 'tor_man_with_unknown')
@@ -247,7 +242,7 @@ class TestManual(unittest.TestCase):
@patch('shutil.rmtree', Mock())
@patch('stem.manual.open', Mock(return_value = io.BytesIO()), create = True)
@patch('stem.util.system.is_available', Mock(return_value = True))
- @patch('urllib.request.urlopen', Mock(side_effect = urllib.URLError('<urlopen error [Errno -2] Name or service not known>')))
+ @patch('urllib.request.urlopen', Mock(side_effect = urllib.request.URLError('<urlopen error [Errno -2] Name or service not known>')))
def test_download_man_page_when_download_fails(self):
exc_msg = "Unable to download tor's manual from https://www.atagar.com/foo/bar to /no/such/path/tor.1.txt: <urlopen error <urlopen error [Errno -2] Name or service not known>>"
self.assertRaisesWith(IOError, exc_msg, stem.manual.download_man_page, '/tmp/no_such_file', url = 'https://www.atagar.com/foo/bar')
diff --git a/test/unit/util/connection.py b/test/unit/util/connection.py
index 047dced7..d848c40b 100644
--- a/test/unit/util/connection.py
+++ b/test/unit/util/connection.py
@@ -5,6 +5,7 @@ Unit tests for the stem.util.connection functions.
import io
import platform
import unittest
+import urllib.request
import stem
import stem.util.connection
@@ -13,12 +14,6 @@ from unittest.mock import Mock, patch
from stem.util.connection import Resolver, Connection
-try:
- # account for urllib's change between python 2.x and 3.x
- import urllib.request as urllib
-except ImportError:
- import urllib2 as urllib
-
URL = 'https://example.unit.test.url'
NETSTAT_OUTPUT = """\
@@ -181,7 +176,7 @@ class TestConnection(unittest.TestCase):
@patch('urllib.request.urlopen')
def test_download_failure(self, urlopen_mock):
- urlopen_mock.side_effect = urllib.URLError('boom')
+ urlopen_mock.side_effect = urllib.request.URLError('boom')
try:
stem.util.connection.download(URL)
@@ -190,12 +185,12 @@ class TestConnection(unittest.TestCase):
self.assertEqual('Failed to download from https://example.unit.test.url (URLError): boom', str(exc))
self.assertEqual(URL, exc.url)
self.assertEqual('boom', exc.error.reason)
- self.assertEqual(urllib.URLError, type(exc.error))
- self.assertTrue('return urllib.urlopen(url, timeout = timeout).read()' in exc.stacktrace_str)
+ self.assertEqual(urllib.request.URLError, type(exc.error))
+ self.assertTrue('return urllib.request.urlopen(url, timeout = timeout).read()' in exc.stacktrace_str)
@patch('urllib.request.urlopen')
def test_download_retries(self, urlopen_mock):
- urlopen_mock.side_effect = urllib.URLError('boom')
+ urlopen_mock.side_effect = urllib.request.URLError('boom')
self.assertRaisesRegexp(IOError, 'boom', stem.util.connection.download, URL)
self.assertEqual(1, urlopen_mock.call_count)
1
0
commit 902ce4186be618f6597baf7e57aee2c74852df09
Author: Damian Johnson <atagar(a)torproject.org>
Date: Fri Jan 3 16:23:14 2020 -0800
Drop StringIO fallback
Python 3.x moved StringIO into its io module.
---
run_tests.py | 8 ++------
stem/descriptor/export.py | 8 ++------
stem/interpreter/commands.py | 8 ++------
test/integ/connection/connect.py | 14 +++++---------
test/unit/connection/connect.py | 12 ++++--------
test/unit/descriptor/export.py | 8 ++------
test/unit/tutorial.py | 19 +++++++------------
test/unit/tutorial_examples.py | 18 +++++++-----------
8 files changed, 31 insertions(+), 64 deletions(-)
diff --git a/run_tests.py b/run_tests.py
index fc67af3c..d6ced384 100755
--- a/run_tests.py
+++ b/run_tests.py
@@ -7,6 +7,7 @@ Runs unit and integration tests. For usage information run this with '--help'.
"""
import errno
+import io
import importlib
import logging
import multiprocessing
@@ -18,11 +19,6 @@ import time
import traceback
import unittest
-try:
- from StringIO import StringIO
-except ImportError:
- from io import StringIO
-
import stem.prereq
import stem.util.conf
import stem.util.log
@@ -427,7 +423,7 @@ def _run_test(args, test_class, output_filters):
traceback.print_exc(exc)
return None
- test_results = StringIO()
+ test_results = io.StringIO()
run_result = stem.util.test_tools.TimedTestRunner(test_results, verbosity = 2).run(suite)
if args.verbose:
diff --git a/stem/descriptor/export.py b/stem/descriptor/export.py
index fea681be..4b909c97 100644
--- a/stem/descriptor/export.py
+++ b/stem/descriptor/export.py
@@ -17,13 +17,9 @@ Toolkit for exporting descriptors to other formats.
use this modle please `let me know <https://www.atagar.com/contact/>`_.
"""
+import io
import csv
-try:
- from cStringIO import StringIO
-except ImportError:
- from io import StringIO
-
import stem.descriptor
import stem.prereq
@@ -50,7 +46,7 @@ def export_csv(descriptors, included_fields = (), excluded_fields = (), header =
:raises: **ValueError** if descriptors contain more than one descriptor type
"""
- output_buffer = StringIO()
+ output_buffer = io.StringIO()
export_csv_file(output_buffer, descriptors, included_fields, excluded_fields, header)
return output_buffer.getvalue()
diff --git a/stem/interpreter/commands.py b/stem/interpreter/commands.py
index 0f8f333c..6e61fdda 100644
--- a/stem/interpreter/commands.py
+++ b/stem/interpreter/commands.py
@@ -7,6 +7,7 @@ Handles making requests and formatting the responses.
import code
import contextlib
+import io
import socket
import sys
@@ -21,11 +22,6 @@ import stem.util.tor_tools
from stem.interpreter import STANDARD_OUTPUT, BOLD_OUTPUT, ERROR_OUTPUT, uses_settings, msg
from stem.util.term import format
-try:
- from cStringIO import StringIO
-except ImportError:
- from io import StringIO
-
MAX_EVENTS = 100
@@ -359,7 +355,7 @@ class ControlInterpreter(code.InteractiveConsole):
is_tor_command = cmd in config.get('help.usage', {}) and cmd.lower() != 'events'
if self._run_python_commands and not is_tor_command:
- console_output = StringIO()
+ console_output = io.StringIO()
with redirect(console_output, console_output):
self.is_multiline_context = code.InteractiveConsole.push(self, command)
diff --git a/test/integ/connection/connect.py b/test/integ/connection/connect.py
index bfeefb19..84b4a8fc 100644
--- a/test/integ/connection/connect.py
+++ b/test/integ/connection/connect.py
@@ -2,6 +2,7 @@
Integration tests for the connect_* convenience functions.
"""
+import io
import unittest
import stem.connection
@@ -10,15 +11,10 @@ import test.runner
from unittest.mock import patch
-try:
- from StringIO import StringIO
-except ImportError:
- from io import StringIO
-
class TestConnect(unittest.TestCase):
@test.require.controller
- @patch('sys.stdout', new_callable = StringIO)
+ @patch('sys.stdout', new_callable = io.StringIO)
def test_connect(self, stdout_mock):
"""
Basic sanity checks for the connect function.
@@ -37,7 +33,7 @@ class TestConnect(unittest.TestCase):
self.assertEqual('', stdout_mock.getvalue())
@test.require.controller
- @patch('sys.stdout', new_callable = StringIO)
+ @patch('sys.stdout', new_callable = io.StringIO)
def test_connect_port(self, stdout_mock):
"""
Basic sanity checks for the connect_port function.
@@ -59,7 +55,7 @@ class TestConnect(unittest.TestCase):
self.assertEqual(control_socket, None)
@test.require.controller
- @patch('sys.stdout', new_callable = StringIO)
+ @patch('sys.stdout', new_callable = io.StringIO)
def test_connect_socket_file(self, stdout_mock):
"""
Basic sanity checks for the connect_socket_file function.
@@ -81,7 +77,7 @@ class TestConnect(unittest.TestCase):
self.assertEqual(control_socket, None)
@test.require.controller
- @patch('sys.stdout', new_callable = StringIO)
+ @patch('sys.stdout', new_callable = io.StringIO)
def test_connect_to_socks_port(self, stdout_mock):
"""
Common user gotcha is connecting to the SocksPort or ORPort rather than the
diff --git a/test/unit/connection/connect.py b/test/unit/connection/connect.py
index ec82f19f..175a1ebd 100644
--- a/test/unit/connection/connect.py
+++ b/test/unit/connection/connect.py
@@ -2,6 +2,7 @@
Unit tests for the stem.connection.connect function.
"""
+import io
import unittest
import stem
@@ -10,14 +11,9 @@ import stem.socket
from unittest.mock import Mock, patch
-try:
- from StringIO import StringIO
-except ImportError:
- from io import StringIO
-
class TestConnect(unittest.TestCase):
- @patch('sys.stdout', new_callable = StringIO)
+ @patch('sys.stdout', new_callable = io.StringIO)
@patch('stem.util.system.is_running')
@patch('os.path.exists', Mock(return_value = True))
@patch('stem.socket.ControlSocketFile', Mock(side_effect = stem.SocketError('failed')))
@@ -30,7 +26,7 @@ class TestConnect(unittest.TestCase):
is_running_mock.return_value = True
self._assert_connect_fails_with({}, stdout_mock, "Unable to connect to tor. Maybe it's running without a ControlPort?")
- @patch('sys.stdout', new_callable = StringIO)
+ @patch('sys.stdout', new_callable = io.StringIO)
@patch('os.path.exists')
@patch('stem.util.system.is_running', Mock(return_value = True))
@patch('stem.socket.ControlSocketFile', Mock(side_effect = stem.SocketError('failed')))
@@ -118,7 +114,7 @@ class TestConnect(unittest.TestCase):
authenticate_mock.assert_any_call(control_socket, None, None)
authenticate_mock.assert_any_call(control_socket, 'my_password', None)
- @patch('sys.stdout', new_callable = StringIO)
+ @patch('sys.stdout', new_callable = io.StringIO)
@patch('stem.connection.authenticate')
def test_auth_failure(self, authenticate_mock, stdout_mock):
control_socket = stem.socket.ControlPort(connect = False)
diff --git a/test/unit/descriptor/export.py b/test/unit/descriptor/export.py
index bf7d054a..d27ed241 100644
--- a/test/unit/descriptor/export.py
+++ b/test/unit/descriptor/export.py
@@ -2,13 +2,9 @@
Unit tests for stem.descriptor.export.
"""
+import io
import unittest
-try:
- from StringIO import StringIO
-except ImportError:
- from io import StringIO
-
import stem.prereq
from stem.descriptor.server_descriptor import RelayDescriptor, BridgeDescriptor
@@ -59,7 +55,7 @@ class TestExport(unittest.TestCase):
desc = RelayDescriptor.create()
desc_csv = export_csv(desc)
- csv_buffer = StringIO()
+ csv_buffer = io.StringIO()
export_csv_file(csv_buffer, desc)
self.assertEqual(desc_csv, csv_buffer.getvalue())
diff --git a/test/unit/tutorial.py b/test/unit/tutorial.py
index 58abde9b..91a70a32 100644
--- a/test/unit/tutorial.py
+++ b/test/unit/tutorial.py
@@ -16,11 +16,6 @@ from stem.descriptor.server_descriptor import RelayDescriptor
from stem.exit_policy import ExitPolicy
from test.unit import exec_documentation_example
-try:
- from StringIO import StringIO
-except ImportError:
- from io import StringIO
-
OVER_THE_RIVER_OUTPUT = """\
* Connecting to tor
@@ -43,7 +38,7 @@ class TestTutorial(unittest.TestCase):
stem.descriptor.remote.SINGLETON_DOWNLOADER = None
- @patch('sys.stdout', new_callable = StringIO)
+ @patch('sys.stdout', new_callable = io.StringIO)
@patch('stem.control.Controller.from_port', spec = Controller)
def test_the_little_relay_that_could(self, from_port_mock, stdout_mock):
controller = from_port_mock().__enter__()
@@ -55,7 +50,7 @@ class TestTutorial(unittest.TestCase):
exec_documentation_example('hello_world.py')
self.assertEqual('My Tor relay has read 33406 bytes and written 29649.\n', stdout_mock.getvalue())
- @patch('sys.stdout', new_callable = StringIO)
+ @patch('sys.stdout', new_callable = io.StringIO)
@patch('shutil.rmtree')
@patch('stem.control.Controller.from_port', spec = Controller)
def test_over_the_river(self, from_port_mock, rmtree_mock, stdout_mock):
@@ -121,7 +116,7 @@ class TestTutorial(unittest.TestCase):
self.assertEqual(OVER_THE_RIVER_OUTPUT, stdout_mock.getvalue())
- @patch('sys.stdout', new_callable = StringIO)
+ @patch('sys.stdout', new_callable = io.StringIO)
@patch('stem.descriptor.remote.DescriptorDownloader')
def test_mirror_mirror_on_the_wall_1(self, downloader_mock, stdout_mock):
downloader_mock().get_consensus.return_value = [RouterStatusEntryV2.create({
@@ -131,7 +126,7 @@ class TestTutorial(unittest.TestCase):
exec_documentation_example('current_descriptors.py')
self.assertEqual('found relay caerSidi (A7569A83B5706AB1B1A9CB52EFF7D2D32E4553EB)\n', stdout_mock.getvalue())
- @patch('sys.stdout', new_callable = StringIO)
+ @patch('sys.stdout', new_callable = io.StringIO)
@patch('stem.control.Controller.from_port', spec = Controller)
def test_mirror_mirror_on_the_wall_2(self, from_port_mock, stdout_mock):
controller = from_port_mock().__enter__()
@@ -142,7 +137,7 @@ class TestTutorial(unittest.TestCase):
exec_documentation_example('descriptor_from_tor_control_socket.py')
self.assertEqual('found relay caerSidi (A7569A83B5706AB1B1A9CB52EFF7D2D32E4553EB)\n', stdout_mock.getvalue())
- @patch('sys.stdout', new_callable = StringIO)
+ @patch('sys.stdout', new_callable = io.StringIO)
@patch('%s.open' % __name__, create = True)
def test_mirror_mirror_on_the_wall_3(self, open_mock, stdout_mock):
def tutorial_example():
@@ -160,7 +155,7 @@ class TestTutorial(unittest.TestCase):
tutorial_example()
self.assertEqual('found relay caerSidi (A7569A83B5706AB1B1A9CB52EFF7D2D32E4553EB)\n', stdout_mock.getvalue())
- @patch('sys.stdout', new_callable = StringIO)
+ @patch('sys.stdout', new_callable = io.StringIO)
@patch('stem.descriptor.collector.get_server_descriptors')
def test_mirror_mirror_on_the_wall_4(self, get_desc_mock, stdout_mock):
get_desc_mock.return_value = iter([RelayDescriptor.create({
@@ -171,7 +166,7 @@ class TestTutorial(unittest.TestCase):
exec_documentation_example('collector_reading.py')
self.assertEqual('1 relays published an exiting policy today...\n\n caerSidi (2C3C46625698B6D67DF32BC1918AD3EE1F9906B1)\n', stdout_mock.getvalue())
- @patch('sys.stdout', new_callable = StringIO)
+ @patch('sys.stdout', new_callable = io.StringIO)
@patch('stem.descriptor.remote.DescriptorDownloader')
@patch('stem.prereq.is_crypto_available', Mock(return_value = False))
def test_mirror_mirror_on_the_wall_5(self, downloader_mock, stdout_mock):
diff --git a/test/unit/tutorial_examples.py b/test/unit/tutorial_examples.py
index c3359d1e..d96ff71b 100644
--- a/test/unit/tutorial_examples.py
+++ b/test/unit/tutorial_examples.py
@@ -2,15 +2,11 @@
Tests for the examples given in stem's tutorial.
"""
+import io
import itertools
import os
import unittest
-try:
- from StringIO import StringIO
-except ImportError:
- from io import StringIO
-
import stem.response
import stem.descriptor.remote
import stem.prereq
@@ -125,7 +121,7 @@ def _get_router_status(address = None, port = None, nickname = None, fingerprint
class TestTutorialExamples(unittest.TestCase):
- @patch('sys.stdout', new_callable = StringIO)
+ @patch('sys.stdout', new_callable = io.StringIO)
@patch('stem.control.Controller.from_port', spec = Controller)
def test_list_circuits(self, from_port_mock, stdout_mock):
path_1 = ('B1FA7D51B8B6F0CB585D944F450E7C06EDE7E44C', 'ByTORAndTheSnowDog')
@@ -156,7 +152,7 @@ class TestTutorialExamples(unittest.TestCase):
exec_documentation_example('list_circuits.py')
self.assertCountEqual(LIST_CIRCUITS_OUTPUT.splitlines(), stdout_mock.getvalue().splitlines())
- @patch('sys.stdout', new_callable = StringIO)
+ @patch('sys.stdout', new_callable = io.StringIO)
@patch('stem.control.Controller.from_port', spec = Controller)
def test_exit_used(self, from_port_mock, stdout_mock):
def tutorial_example(mock_event):
@@ -207,7 +203,7 @@ class TestTutorialExamples(unittest.TestCase):
tutorial_example(event)
self.assertCountEqual(EXIT_USED_OUTPUT.splitlines(), stdout_mock.getvalue().splitlines())
- @patch('sys.stdout', new_callable = StringIO)
+ @patch('sys.stdout', new_callable = io.StringIO)
@patch('stem.descriptor.remote.DescriptorDownloader')
def test_outdated_relays(self, downloader_mock, stdout_mock):
downloader_mock().get_server_descriptors.return_value = [
@@ -221,7 +217,7 @@ class TestTutorialExamples(unittest.TestCase):
self.assertCountEqual(OUTDATED_RELAYS_OUTPUT.splitlines(), stdout_mock.getvalue().splitlines())
- @patch('sys.stdout', new_callable = StringIO)
+ @patch('sys.stdout', new_callable = io.StringIO)
@patch('stem.descriptor.remote.Query')
@patch('stem.directory.Authority.from_cache')
def test_compare_flags(self, authorities_mock, query_mock, stdout_mock):
@@ -262,7 +258,7 @@ class TestTutorialExamples(unittest.TestCase):
self.assertCountEqual(COMPARE_FLAGS_OUTPUT.splitlines(), stdout_mock.getvalue().splitlines())
- @patch('sys.stdout', new_callable = StringIO)
+ @patch('sys.stdout', new_callable = io.StringIO)
@patch('stem.directory.Authority.from_cache')
@patch('stem.descriptor.remote.DescriptorDownloader.query')
def test_votes_by_bandwidth_authorities(self, query_mock, authorities_mock, stdout_mock):
@@ -295,7 +291,7 @@ class TestTutorialExamples(unittest.TestCase):
exec_documentation_example('votes_by_bandwidth_authorities.py')
self.assertCountEqual(VOTES_BY_BANDWIDTH_AUTHORITIES_OUTPUT.splitlines(), stdout_mock.getvalue().splitlines())
- @patch('sys.stdout', new_callable = StringIO)
+ @patch('sys.stdout', new_callable = io.StringIO)
@patch('stem.descriptor.parse_file')
@patch('stem.descriptor.remote.Query')
def test_persisting_a_consensus(self, query_mock, parse_file_mock, stdout_mock):
1
0
commit ab83d8ded24d83005834d4f0d1d9fd40bbd38e96
Author: Damian Johnson <atagar(a)torproject.org>
Date: Fri Jan 3 16:17:14 2020 -0800
Drop http.client fallback
Just a single normalization of HTTPMessage.
---
test/unit/descriptor/remote.py | 8 ++------
1 file changed, 2 insertions(+), 6 deletions(-)
diff --git a/test/unit/descriptor/remote.py b/test/unit/descriptor/remote.py
index 98bb734b..d9893535 100644
--- a/test/unit/descriptor/remote.py
+++ b/test/unit/descriptor/remote.py
@@ -2,6 +2,7 @@
Unit tests for stem.descriptor.remote.
"""
+import http.client
import io
import socket
import time
@@ -18,11 +19,6 @@ from unittest.mock import patch, Mock, MagicMock
from stem.descriptor.remote import Compression
from test.unit.descriptor import read_resource
-try:
- from http.client import HTTPMessage # python3
-except ImportError:
- from httplib import HTTPMessage # python2
-
TEST_RESOURCE = '/tor/server/fp/9695DFC35FFEB861329B9F1AB04C46397020CE31'
# Output from requesting moria1's descriptor from itself...
@@ -94,7 +90,7 @@ def _dirport_mock(data, encoding = 'identity'):
dirport_mock = Mock()
dirport_mock().read.return_value = data
- headers = HTTPMessage()
+ headers = http.client.HTTPMessage()
for line in HEADER.splitlines():
key, value = line.split(': ', 1)
1
0
05 Jan '20
commit 85c81eea7fdad016384e734791cccf0e97132fc1
Author: Damian Johnson <atagar(a)torproject.org>
Date: Sat Jan 4 15:25:14 2020 -0800
Replace mkdtemp() with TemporaryDirectory()
Minor python 3.x simplification now that we can use this builtin.
---
stem/descriptor/collector.py | 13 ++---
stem/manual.py | 9 ++--
test/integ/control/controller.py | 105 +++++++++++++++++++--------------------
test/integ/process.py | 31 ++++--------
test/integ/util/system.py | 11 ++--
test/unit/manual.py | 16 +++---
6 files changed, 82 insertions(+), 103 deletions(-)
diff --git a/stem/descriptor/collector.py b/stem/descriptor/collector.py
index c2bf8179..7aeb298b 100644
--- a/stem/descriptor/collector.py
+++ b/stem/descriptor/collector.py
@@ -55,7 +55,6 @@ import hashlib
import json
import os
import re
-import shutil
import tempfile
import time
@@ -264,15 +263,9 @@ class File(object):
if self._downloaded_to and os.path.exists(self._downloaded_to):
directory = os.path.dirname(self._downloaded_to)
else:
- # TODO: The following can be replaced with simpler usage of
- # tempfile.TemporaryDirectory when we drop python 2.x support.
-
- tmp_directory = tempfile.mkdtemp()
-
- for desc in self.read(tmp_directory, descriptor_type, start, end, document_handler, timeout, retries):
- yield desc
-
- shutil.rmtree(tmp_directory)
+ with tempfile.TemporaryDirectory() as tmp_directory:
+ for desc in self.read(tmp_directory, descriptor_type, start, end, document_handler, timeout, retries):
+ yield desc
return
diff --git a/stem/manual.py b/stem/manual.py
index fe49e3de..c1b4bd8f 100644
--- a/stem/manual.py
+++ b/stem/manual.py
@@ -288,11 +288,10 @@ def download_man_page(path = None, file_handle = None, url = GITWEB_MANUAL_URL,
elif not stem.util.system.is_available('a2x'):
raise IOError('We require a2x from asciidoc to provide a man page')
- dirpath = tempfile.mkdtemp()
- asciidoc_path = os.path.join(dirpath, 'tor.1.txt')
- manual_path = os.path.join(dirpath, 'tor.1')
+ with tempfile.TemporaryDirectory() as dirpath:
+ asciidoc_path = os.path.join(dirpath, 'tor.1.txt')
+ manual_path = os.path.join(dirpath, 'tor.1')
- try:
try:
with open(asciidoc_path, 'wb') as asciidoc_file:
request = urllib.request.urlopen(url, timeout = timeout)
@@ -325,8 +324,6 @@ def download_man_page(path = None, file_handle = None, url = GITWEB_MANUAL_URL,
with open(manual_path, 'rb') as manual_file:
shutil.copyfileobj(manual_file, file_handle)
file_handle.flush()
- finally:
- shutil.rmtree(dirpath)
class Manual(object):
diff --git a/test/integ/control/controller.py b/test/integ/control/controller.py
index f87c0817..257d9fbc 100644
--- a/test/integ/control/controller.py
+++ b/test/integ/control/controller.py
@@ -754,71 +754,70 @@ class TestController(unittest.TestCase):
"""
runner = test.runner.get_runner()
- tmpdir = tempfile.mkdtemp()
- with runner.get_tor_controller() as controller:
- try:
- # successfully set a single option
- connlimit = int(controller.get_conf('ConnLimit'))
- controller.set_conf('connlimit', str(connlimit - 1))
- self.assertEqual(connlimit - 1, int(controller.get_conf('ConnLimit')))
-
- # successfully set a single list option
- exit_policy = ['accept *:7777', 'reject *:*']
- controller.set_conf('ExitPolicy', exit_policy)
- self.assertEqual(exit_policy, controller.get_conf('ExitPolicy', multiple = True))
+ with tempfile.TemporaryDirectory() as tmpdir:
- # fail to set a single option
+ with runner.get_tor_controller() as controller:
try:
- controller.set_conf('invalidkeyboo', 'abcde')
- self.fail()
- except stem.InvalidArguments as exc:
- self.assertEqual(['invalidkeyboo'], exc.arguments)
+ # successfully set a single option
+ connlimit = int(controller.get_conf('ConnLimit'))
+ controller.set_conf('connlimit', str(connlimit - 1))
+ self.assertEqual(connlimit - 1, int(controller.get_conf('ConnLimit')))
- # resets configuration parameters
- controller.reset_conf('ConnLimit', 'ExitPolicy')
- self.assertEqual(connlimit, int(controller.get_conf('ConnLimit')))
- self.assertEqual(None, controller.get_conf('ExitPolicy'))
+ # successfully set a single list option
+ exit_policy = ['accept *:7777', 'reject *:*']
+ controller.set_conf('ExitPolicy', exit_policy)
+ self.assertEqual(exit_policy, controller.get_conf('ExitPolicy', multiple = True))
- # successfully sets multiple config options
- controller.set_options({
- 'connlimit': str(connlimit - 2),
- 'contactinfo': 'stem@testing',
- })
+ # fail to set a single option
+ try:
+ controller.set_conf('invalidkeyboo', 'abcde')
+ self.fail()
+ except stem.InvalidArguments as exc:
+ self.assertEqual(['invalidkeyboo'], exc.arguments)
- self.assertEqual(connlimit - 2, int(controller.get_conf('ConnLimit')))
- self.assertEqual('stem@testing', controller.get_conf('contactinfo'))
+ # resets configuration parameters
+ controller.reset_conf('ConnLimit', 'ExitPolicy')
+ self.assertEqual(connlimit, int(controller.get_conf('ConnLimit')))
+ self.assertEqual(None, controller.get_conf('ExitPolicy'))
- # fail to set multiple config options
- try:
+ # successfully sets multiple config options
controller.set_options({
+ 'connlimit': str(connlimit - 2),
'contactinfo': 'stem@testing',
- 'bombay': 'vadapav',
})
- self.fail()
- except stem.InvalidArguments as exc:
- self.assertEqual(['bombay'], exc.arguments)
- # context-sensitive keys (the only retched things for which order matters)
- controller.set_options((
- ('HiddenServiceDir', tmpdir),
- ('HiddenServicePort', '17234 127.0.0.1:17235'),
- ))
+ self.assertEqual(connlimit - 2, int(controller.get_conf('ConnLimit')))
+ self.assertEqual('stem@testing', controller.get_conf('contactinfo'))
- self.assertEqual(tmpdir, controller.get_conf('HiddenServiceDir'))
- self.assertEqual('17234 127.0.0.1:17235', controller.get_conf('HiddenServicePort'))
- finally:
- # reverts configuration changes
-
- controller.set_options((
- ('ExitPolicy', 'reject *:*'),
- ('ConnLimit', None),
- ('ContactInfo', None),
- ('HiddenServiceDir', None),
- ('HiddenServicePort', None),
- ), reset = True)
-
- shutil.rmtree(tmpdir)
+ # fail to set multiple config options
+ try:
+ controller.set_options({
+ 'contactinfo': 'stem@testing',
+ 'bombay': 'vadapav',
+ })
+ self.fail()
+ except stem.InvalidArguments as exc:
+ self.assertEqual(['bombay'], exc.arguments)
+
+ # context-sensitive keys (the only retched things for which order matters)
+ controller.set_options((
+ ('HiddenServiceDir', tmpdir),
+ ('HiddenServicePort', '17234 127.0.0.1:17235'),
+ ))
+
+ self.assertEqual(tmpdir, controller.get_conf('HiddenServiceDir'))
+ self.assertEqual('17234 127.0.0.1:17235', controller.get_conf('HiddenServicePort'))
+ finally:
+ # reverts configuration changes
+
+ controller.set_options((
+ ('ExitPolicy', 'reject *:*'),
+ ('ConnLimit', None),
+ ('ContactInfo', None),
+ ('HiddenServiceDir', None),
+ ('HiddenServicePort', None),
+ ), reset = True)
@test.require.controller
def test_set_conf_for_usebridges(self):
diff --git a/test/integ/process.py b/test/integ/process.py
index e7d2cae3..e40c501a 100644
--- a/test/integ/process.py
+++ b/test/integ/process.py
@@ -9,7 +9,6 @@ import hashlib
import os
import random
import re
-import shutil
import subprocess
import tempfile
import threading
@@ -53,18 +52,8 @@ def random_port():
@contextmanager
-def tmp_directory():
- tmp_dir = tempfile.mkdtemp()
-
- try:
- yield tmp_dir
- finally:
- shutil.rmtree(tmp_dir)
-
-
-@contextmanager
def torrc():
- with tmp_directory() as data_directory:
+ with tempfile.TemporaryDirectory() as data_directory:
torrc_path = os.path.join(data_directory, 'torrc')
with open(torrc_path, 'w') as torrc_file:
@@ -228,7 +217,7 @@ class TestProcess(unittest.TestCase):
output = run_tor(tor_cmd, '--list-fingerprint', with_torrc = True, expect_failure = True)
assert_in("Clients don't have long-term identity keys. Exiting.", output, 'Should fail to start due to lacking an ORPort')
- with tmp_directory() as data_directory:
+ with tempfile.TemporaryDirectory() as data_directory:
torrc_path = os.path.join(data_directory, 'torrc')
with open(torrc_path, 'w') as torrc_file:
@@ -324,7 +313,7 @@ class TestProcess(unittest.TestCase):
if test.tor_version() < stem.version.Requirement.TORRC_VIA_STDIN:
skip('(requires %s)' % stem.version.Requirement.TORRC_VIA_STDIN)
- with tmp_directory() as data_directory:
+ with tempfile.TemporaryDirectory() as data_directory:
torrc = BASIC_RELAY_TORRC % data_directory
output = run_tor(tor_cmd, '-f', '-', '--dump-config', 'short', stdin = torrc)
assert_equal(sorted(torrc.splitlines()), sorted(output.splitlines()))
@@ -382,7 +371,7 @@ class TestProcess(unittest.TestCase):
it isn't.
"""
- with tmp_directory() as data_directory:
+ with tempfile.TemporaryDirectory() as data_directory:
# Tries running tor in another thread with the given timeout argument. This
# issues an invalid torrc so we terminate right away if we get to the point
# of actually invoking tor.
@@ -435,7 +424,7 @@ class TestProcess(unittest.TestCase):
Exercises launch_tor_with_config when we write a torrc to disk.
"""
- with tmp_directory() as data_directory:
+ with tempfile.TemporaryDirectory() as data_directory:
control_port = random_port()
control_socket, tor_process = None, None
@@ -479,7 +468,7 @@ class TestProcess(unittest.TestCase):
if test.tor_version() < stem.version.Requirement.TORRC_VIA_STDIN:
skip('(requires %s)' % stem.version.Requirement.TORRC_VIA_STDIN)
- with tmp_directory() as data_directory:
+ with tempfile.TemporaryDirectory() as data_directory:
control_port = random_port()
control_socket, tor_process = None, None
@@ -521,7 +510,7 @@ class TestProcess(unittest.TestCase):
# [warn] Failed to parse/validate config: Failed to bind one of the listener ports.
# [err] Reading config failed--see warnings above.
- with tmp_directory() as data_directory:
+ with tempfile.TemporaryDirectory() as data_directory:
both_ports = random_port()
try:
@@ -543,7 +532,7 @@ class TestProcess(unittest.TestCase):
Runs launch_tor where it times out before completing.
"""
- with tmp_directory() as data_directory:
+ with tempfile.TemporaryDirectory() as data_directory:
start_time = time.time()
try:
@@ -575,7 +564,7 @@ class TestProcess(unittest.TestCase):
elif test.tor_version() < stem.version.Requirement.TAKEOWNERSHIP:
skip('(requires %s)' % stem.version.Requirement.TAKEOWNERSHIP)
- with tmp_directory() as data_directory:
+ with tempfile.TemporaryDirectory() as data_directory:
sleep_process = subprocess.Popen(['sleep', '60'])
tor_process = stem.process.launch_tor_with_config(
@@ -619,7 +608,7 @@ class TestProcess(unittest.TestCase):
if test.tor_version() < stem.version.Requirement.TAKEOWNERSHIP:
skip('(requires %s)' % stem.version.Requirement.TAKEOWNERSHIP)
- with tmp_directory() as data_directory:
+ with tempfile.TemporaryDirectory() as data_directory:
control_port = random_port()
tor_process = stem.process.launch_tor_with_config(
diff --git a/test/integ/util/system.py b/test/integ/util/system.py
index 4d83d695..2a7ac07a 100644
--- a/test/integ/util/system.py
+++ b/test/integ/util/system.py
@@ -361,13 +361,14 @@ class TestSystem(unittest.TestCase):
Checks the stem.util.system.pid_by_open_file function.
"""
+ # check a directory that doesn't exist
+
+ self.assertEqual(None, stem.util.system.pid_by_open_file('/no/such/path'))
+
# check a directory that exists, but isn't claimed by any application
- tmpdir = tempfile.mkdtemp()
- self.assertEqual(None, stem.util.system.pid_by_open_file(tmpdir))
- # check a directory that doesn't exist
- os.rmdir(tmpdir)
- self.assertEqual(None, stem.util.system.pid_by_open_file(tmpdir))
+ with tempfile.TemporaryDirectory() as tmpdir:
+ self.assertEqual(None, stem.util.system.pid_by_open_file(tmpdir))
@require_path
def test_pids_by_user(self):
diff --git a/test/unit/manual.py b/test/unit/manual.py
index eb76d6e9..e1891ca4 100644
--- a/test/unit/manual.py
+++ b/test/unit/manual.py
@@ -76,6 +76,10 @@ EXPECTED_CONFIG_OPTIONS['Bridge'] = stem.manual.ConfigOption(
CACHED_MANUAL = None
+TEMP_DIR_MOCK = Mock()
+TEMP_DIR_MOCK.__enter__ = Mock(return_value = '/no/such/path')
+TEMP_DIR_MOCK.__exit__ = Mock(return_value = False)
+
def _cached_manual():
global CACHED_MANUAL
@@ -230,16 +234,14 @@ class TestManual(unittest.TestCase):
exc_msg = 'We require a2x from asciidoc to provide a man page'
self.assertRaisesWith(IOError, exc_msg, stem.manual.download_man_page, '/tmp/no_such_file')
- @patch('tempfile.mkdtemp', Mock(return_value = '/no/such/path'))
- @patch('shutil.rmtree', Mock())
+ @patch('tempfile.TemporaryDirectory', Mock(return_value = TEMP_DIR_MOCK))
@patch('stem.manual.open', Mock(side_effect = IOError('unable to write to file')), create = True)
@patch('stem.util.system.is_available', Mock(return_value = True))
def test_download_man_page_when_unable_to_write(self):
exc_msg = "Unable to download tor's manual from https://gitweb.torproject.org/tor.git/plain/doc/tor.1.txt to /no/such/path/tor.1.txt: unable to write to file"
self.assertRaisesWith(IOError, exc_msg, stem.manual.download_man_page, '/tmp/no_such_file')
- @patch('tempfile.mkdtemp', Mock(return_value = '/no/such/path'))
- @patch('shutil.rmtree', Mock())
+ @patch('tempfile.TemporaryDirectory', Mock(return_value = TEMP_DIR_MOCK))
@patch('stem.manual.open', Mock(return_value = io.BytesIO()), create = True)
@patch('stem.util.system.is_available', Mock(return_value = True))
@patch('urllib.request.urlopen', Mock(side_effect = urllib.request.URLError('<urlopen error [Errno -2] Name or service not known>')))
@@ -247,8 +249,7 @@ class TestManual(unittest.TestCase):
exc_msg = "Unable to download tor's manual from https://www.atagar.com/foo/bar to /no/such/path/tor.1.txt: <urlopen error <urlopen error [Errno -2] Name or service not known>>"
self.assertRaisesWith(IOError, exc_msg, stem.manual.download_man_page, '/tmp/no_such_file', url = 'https://www.atagar.com/foo/bar')
- @patch('tempfile.mkdtemp', Mock(return_value = '/no/such/path'))
- @patch('shutil.rmtree', Mock())
+ @patch('tempfile.TemporaryDirectory', Mock(return_value = TEMP_DIR_MOCK))
@patch('stem.manual.open', Mock(return_value = io.BytesIO()), create = True)
@patch('stem.util.system.call', Mock(side_effect = stem.util.system.CallError('call failed', 'a2x -f manpage /no/such/path/tor.1.txt', 1, None, None, 'call failed')))
@patch('stem.util.system.is_available', Mock(return_value = True))
@@ -257,8 +258,7 @@ class TestManual(unittest.TestCase):
exc_msg = "Unable to run 'a2x -f manpage /no/such/path/tor.1.txt': call failed"
self.assertRaisesWith(IOError, exc_msg, stem.manual.download_man_page, '/tmp/no_such_file', url = 'https://www.atagar.com/foo/bar')
- @patch('tempfile.mkdtemp', Mock(return_value = '/no/such/path'))
- @patch('shutil.rmtree', Mock())
+ @patch('tempfile.TemporaryDirectory', Mock(return_value = TEMP_DIR_MOCK))
@patch('stem.manual.open', create = True)
@patch('stem.util.system.call')
@patch('stem.util.system.is_available', Mock(return_value = True))
1
0