diff --git a/.travis.yml b/.travis.yml index 66198c977..443ed5abe 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,9 +1,15 @@ language: python -python: -- '2.7' +matrix: + include: + - python: 2.7 + env: TOXENV=py27 + - python: 3.6 + env: TOXENV=py36 addons: apt: packages: + - python3 + - python3-pip - swig - libusb-1.0-0-dev - libprotobuf-dev @@ -12,8 +18,6 @@ cache: apt: true directories: - $HOME/.cache/pip -env: -- TOXENV=py27 install: - pip install tox coveralls - pip install -e . diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 627d0b5cf..34be478ce 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -213,8 +213,8 @@ accordingly. git clone https://github.com/google/openhtf.git # Install system-level third-party dependencies. -sudo apt-get install python-pip swig libssl-dev python-dev libffi-dev \ -protobuf-compiler libprotobuf-dev +sudo apt-get install python-pip swig libssl-dev python-dev python3-dev \ +libffi-dev protobuf-compiler libprotobuf-dev # Make sure pip is up-to-date. sudo pip install --upgrade pip diff --git a/bin/units_from_xls.py b/bin/units_from_xls.py index 2d38636b4..334700e36 100644 --- a/bin/units_from_xls.py +++ b/bin/units_from_xls.py @@ -158,10 +158,10 @@ def __call__(self, name_or_suffix): '15': 'FIFTEEN', '30': 'THIRTY', '\\': '_', - unichr(160): '_', - unichr(176): 'DEG_', - unichr(186): 'DEG_', - unichr(8211): '_', + chr(160): '_', + chr(176): 'DEG_', + chr(186): 'DEG_', + chr(8211): '_', } @@ -182,7 +182,7 @@ def main(): args = parser.parse_args() if not os.path.exists(args.xlsfile): - print 'Unable to locate the file "%s".' % args.xlsfile + print('Unable to locate the file "%s".' % args.xlsfile) parser.print_help() sys.exit() @@ -217,7 +217,7 @@ def unit_defs_from_sheet(sheet, column_names): rows = sheet.get_rows() # Find the indices for the columns we care about. - for idx, cell in enumerate(rows.next()): + for idx, cell in enumerate(next(rows)): if cell.value in column_names: col_indices[cell.value] = idx @@ -245,7 +245,7 @@ def unit_key_from_name(name): """Return a legal python name for the given name for use as a unit key.""" result = name - for old, new in UNIT_KEY_REPLACEMENTS.iteritems(): + for old, new in UNIT_KEY_REPLACEMENTS.items(): result = result.replace(old, new) # Collapse redundant underscores and convert to uppercase. diff --git a/contrib/poll_stations.py b/contrib/poll_stations.py index dd2e62c7b..31c921603 100644 --- a/contrib/poll_stations.py +++ b/contrib/poll_stations.py @@ -30,9 +30,10 @@ """ +from __future__ import print_function import logging import os -import Queue +import queue import socket import sys import threading @@ -111,7 +112,7 @@ class StationList(object): """ def __init__(self): - self.update_queue = Queue.Queue() + self.update_queue = queue.Queue() self.stations = set() # Really, these threads should be tracked on a per-station basis, because # two stations *could* have RemoteTest instances that would compare equal @@ -168,7 +169,7 @@ def watch_test(self, remote_test): def print_station(self, station): print(station) try: - for remote_test in station.tests.itervalues(): + for remote_test in station.tests.values(): # Trigger an update of the local history cache and state. remote_test.state remote_test.history @@ -182,7 +183,7 @@ def print_station(self, station): self.update_threads[remote_test] = update_thread except socket.error as e: print(' |-- Connection Error: %s' % e) - print + print() def check_for_stations(self): """Discover for new stations, doesn't remove any stations.""" @@ -199,7 +200,7 @@ def mainloop(self): station_list.check_for_stations() try: self.update(self.update_queue.get(timeout=5)) - except Queue.Empty: + except queue.Empty: pass diff --git a/examples/all_the_things.py b/examples/all_the_things.py index a7a86204a..abbbcb470 100644 --- a/examples/all_the_things.py +++ b/examples/all_the_things.py @@ -28,7 +28,7 @@ from openhtf.output import callbacks from openhtf.output.callbacks import json_factory -import example_plugs +from examples import example_plugs @htf.plug(example=example_plugs.ExamplePlug) @@ -107,7 +107,7 @@ def measures_with_args(test, min, max): def attachments(test): - test.attach('test_attachment', 'This is test attachment data.') + test.attach('test_attachment', 'This is test attachment data.'.encode('utf-8')) test.attach_from_file( os.path.join(os.path.dirname(__file__), 'example_attachment.txt')) diff --git a/examples/repeat.py b/examples/repeat.py index 7f612dea9..89f7c216b 100644 --- a/examples/repeat.py +++ b/examples/repeat.py @@ -27,6 +27,7 @@ phase can be limited specifying a PhaseOptions.repeat_limit. """ +from __future__ import print_function import openhtf import openhtf.plugs as plugs @@ -40,7 +41,7 @@ def __init__(self): def run(self): """Increments counter and raises an exception for first two runs.""" self.count += 1 - print 'FailTwicePlug: Run number %s' % (self.count) + print('FailTwicePlug: Run number %s' % (self.count)) if self.count < 3: raise RuntimeError('Fails a couple times') @@ -56,7 +57,7 @@ def __init__(self): def run(self): """Increments counter and returns False indicating failure""" self.count += 1 - print "FailAlwaysPlug: Run number %s" % (self.count) + print("FailAlwaysPlug: Run number %s" % (self.count)) return False @@ -70,10 +71,10 @@ def phase_repeat(test, test_plug): test_plug.run() except: - print "Error in phase_repeat, will retry" + print("Error in phase_repeat, will retry") return openhtf.PhaseResult.REPEAT - print "Completed phase_repeat" + print("Completed phase_repeat") # This phase demonstrates repeating a phase based upon a result returned from a @@ -86,7 +87,7 @@ def phase_repeat_with_limit(test, test_plug): result = test_plug.run() if not result: - print "Invalid result in phase_repeat_with_limit, will retry" + print("Invalid result in phase_repeat_with_limit, will retry") return openhtf.PhaseResult.REPEAT if __name__ == '__main__': diff --git a/examples/with_plugs.py b/examples/with_plugs.py index fc3a06b7e..4168d39e1 100644 --- a/examples/with_plugs.py +++ b/examples/with_plugs.py @@ -25,6 +25,7 @@ end up with the 4 phases you want. """ +from __future__ import print_function import subprocess import time @@ -52,7 +53,7 @@ def _get_command(self, count): def run(self, count): command = self._get_command(count) - print "running: %s" % ' '.join(command) + print("running: %s" % ' '.join(command)) return subprocess.call(command) diff --git a/openhtf/__init__.py b/openhtf/__init__.py index 344941046..604df143b 100644 --- a/openhtf/__init__.py +++ b/openhtf/__init__.py @@ -192,7 +192,7 @@ def configure(self, **kwargs): # side effects. create_arg_parser(add_help=True).parse_known_args() logs.setup_logger() - for key, value in kwargs.iteritems(): + for key, value in kwargs.items(): setattr(self._test_options, key, value) @classmethod @@ -390,7 +390,7 @@ def format_strings(self, **kwargs): self, name=util.format_string(self.name, kwargs)) def update(self, **kwargs): - for key, value in kwargs.iteritems(): + for key, value in kwargs.items(): if key not in self.__slots__: raise AttributeError('Type %s does not have attribute %s' % ( type(self).__name__, key)) @@ -481,7 +481,7 @@ def with_plugs(self, **subplugs): plugs_by_name = {plug.name: plug for plug in self.plugs} new_plugs = dict(plugs_by_name) - for name, sub_class in subplugs.iteritems(): + for name, sub_class in subplugs.items(): original_plug = plugs_by_name.get(name) accept_substitute = True if original_plug is None: @@ -503,7 +503,7 @@ def with_plugs(self, **subplugs): return mutablerecords.CopyRecord( self, - plugs=new_plugs.values(), + plugs=list(new_plugs.values()), options=self.options.format_strings(**subplugs), measurements=[m.with_args(**subplugs) for m in self.measurements]) diff --git a/openhtf/core/__init__.py b/openhtf/core/__init__.py index 78e71fb4a..07bb41af7 100644 --- a/openhtf/core/__init__.py +++ b/openhtf/core/__init__.py @@ -1 +1 @@ -from test_executor import TestExecutionError, TestStopError, TestExecutor +from .test_executor import TestExecutionError, TestStopError, TestExecutor diff --git a/openhtf/core/measurements.py b/openhtf/core/measurements.py index 8900a0abb..0ceb77bdc 100644 --- a/openhtf/core/measurements.py +++ b/openhtf/core/measurements.py @@ -325,7 +325,7 @@ def is_value_set(self): def __iter__(self): # pylint: disable=invalid-name """Iterate over items, allows easy conversion to a dict.""" - return self.value_dict.iteritems() + return iter(self.value_dict.items()) def __setitem__(self, coordinates, value): # pylint: disable=invalid-name coordinates_len = len(coordinates) if hasattr(coordinates, '__len__') else 1 @@ -366,7 +366,7 @@ def value(self): if not self.is_value_set: raise MeasurementNotSetError('Measurement not yet set', self.name) return [dimensions + (value,) for dimensions, value in - self.value_dict.iteritems()] + self.value_dict.items()] class Collection(mutablerecords.Record('Collection', ['_measurements'])): @@ -421,7 +421,7 @@ def _assert_valid_key(self, name): def __iter__(self): # pylint: disable=invalid-name """Extract each MeasurementValue's value.""" return ((key, meas.measured_value.value) - for key, meas in self._measurements.iteritems()) + for key, meas in self._measurements.items()) def __setattr__(self, name, value): # pylint: disable=invalid-name self[name] = value @@ -469,7 +469,7 @@ def _maybe_make(meas): """Turn strings into Measurement objects if necessary.""" if isinstance(meas, Measurement): return meas - elif isinstance(meas, basestring): + elif isinstance(meas, str): return Measurement(meas, **kwargs) raise InvalidMeasurementType('Expected Measurement or string', meas) diff --git a/openhtf/core/phase_executor.py b/openhtf/core/phase_executor.py index a0b00b2bc..aa83aafb1 100644 --- a/openhtf/core/phase_executor.py +++ b/openhtf/core/phase_executor.py @@ -91,12 +91,13 @@ class PhaseExecutionOutcome(collections.namedtuple( other value will raise an InvalidPhaseResultError. """ - def __init__(self, phase_result): + def __new__(cls, phase_result): if (phase_result is not None and not isinstance(phase_result, (openhtf.PhaseResult, ExceptionInfo)) and not isinstance(phase_result, threads.ThreadTerminationError)): raise InvalidPhaseResultError('Invalid phase result', phase_result) - super(PhaseExecutionOutcome, self).__init__(phase_result) + self = super(PhaseExecutionOutcome, cls).__new__(cls, phase_result) + return self @property def is_fail_and_continue(self): @@ -208,7 +209,7 @@ def execute_phase(self, phase): hit its limit for repetitions. """ repeat_count = 1 - repeat_limit = phase.options.repeat_limit or sys.maxint + repeat_limit = phase.options.repeat_limit or sys.maxsize while not self._stopping.is_set(): is_last_repeat = repeat_count >= repeat_limit phase_execution_outcome = self._execute_phase_once(phase, is_last_repeat) @@ -260,7 +261,7 @@ def stop(self, timeout_s=None): if phase_thread.is_alive(): phase_thread.kill() - + _LOG.debug('Waiting for cancelled phase to exit: %s', phase_thread) timeout = timeouts.PolledTimeout.from_seconds(timeout_s) while phase_thread.is_alive() and not timeout.has_expired(): diff --git a/openhtf/core/station_api.py b/openhtf/core/station_api.py index e2f6934bf..b683600f9 100644 --- a/openhtf/core/station_api.py +++ b/openhtf/core/station_api.py @@ -69,7 +69,7 @@ import socket import threading import time -import xmlrpclib +import xmlrpc.client import mutablerecords @@ -83,10 +83,11 @@ from openhtf.util import threads from openhtf.util import timeouts from openhtf.util import xmlrpcutil +from past.builtins import long # Fix for xmlrpclib to use for longs and ints instead of , because our # timestamps are in millis, which are too big for 4-byte ints. -xmlrpclib.Marshaller.dispatch[long] = xmlrpclib.Marshaller.dispatch[int] = ( +xmlrpc.client.Marshaller.dispatch[long] = xmlrpc.client.Marshaller.dispatch[int] = ( lambda _, v, w: w('%d' % v)) _LOG = logging.getLogger(__name__) @@ -408,7 +409,7 @@ def wait_for_update(self, timeout_s=1): try: remote_state_dict = self.proxy_factory(timeout_s + 1).wait_for_update( self.test_uid, summary_dict, timeout_s) - except xmlrpclib.Fault as fault: + except xmlrpc.client.Fault as fault: # TODO(madsci): This is a super kludge, eventually implement the # ReraisingMixin for ServerProxy, but that's hard, so do this for now. if 'openhtf.io.station_api.UpdateTimeout' in fault.faultString: @@ -770,7 +771,7 @@ def wait_for_plug_update(self, test_uid, plug_name, current_state, timeout_s): def _summary_for_state_dict(state_dict): """Return a dict for state with counts swapped in for phase/log records.""" state_dict_summary = { - k: v for k, v in state_dict.iteritems() if k != 'plugs'} + k: v for k, v in state_dict.items() if k != 'plugs'} state_dict_summary['test_record'] = data.convert_to_base_types( state_dict_summary['test_record']) state_dict_summary['test_record']['phases'] = len( diff --git a/openhtf/core/test_executor.py b/openhtf/core/test_executor.py index 1a3c5f1ab..864a1b435 100644 --- a/openhtf/core/test_executor.py +++ b/openhtf/core/test_executor.py @@ -109,7 +109,8 @@ def finalize(self): def wait(self): """Waits until death.""" try: - self.join(sys.float_info.max) # Timeout needed for SIGINT handling. + # Timeout needed for SIGINT handling. Timeout is not actually used. + self.join(60) except KeyboardInterrupt: self.test_state.logger.info('KeyboardInterrupt caught, aborting test.') raise diff --git a/openhtf/core/test_record.py b/openhtf/core/test_record.py index 846b08477..b7e5ce771 100644 --- a/openhtf/core/test_record.py +++ b/openhtf/core/test_record.py @@ -125,7 +125,7 @@ def _get_source_safely(obj): return '' -class CodeInfo(mutablerecords.Record( +class CodeInfo(mutablerecords.HashableRecord( 'CodeInfo', ['name', 'docstring', 'sourcecode'])): """Information regarding the running tester code.""" diff --git a/openhtf/core/test_state.py b/openhtf/core/test_state.py index 3b9da6afa..3ebd65e62 100644 --- a/openhtf/core/test_state.py +++ b/openhtf/core/test_state.py @@ -45,6 +45,7 @@ from openhtf.core import test_record from openhtf.util import conf from openhtf.util import logs +from past.builtins import long conf.declare('allow_unset_measurements', default_value=False, description='If True, unset measurements do not cause Tests to ' @@ -117,6 +118,7 @@ def __init__(self, test_desc, execution_uid): self.test_record = test_record.TestRecord( dut_id=None, station_id=conf.station_id, code_info=test_desc.code_info, + start_time_millis=0, # Copy metadata so we don't modify test_desc. metadata=copy.deepcopy(test_desc.metadata)) self.logger = logs.initialize_record_logger( @@ -297,13 +299,12 @@ def finalize_from_phase_outcome(self, phase_execution_outcome): result = phase_execution_outcome.phase_result if isinstance(result, phase_executor.ExceptionInfo): code = result.exc_type.__name__ - description = str(result.exc_val).decode('utf8', 'replace') + description = str(result.exc_val) else: # openhtf.util.threads.ThreadTerminationError gets str'd directly. code = str(type(phase_execution_outcome.phase_result).__name__) - description = str(phase_execution_outcome.phase_result).decode( - 'utf8', 'replace') - self.test_record.add_outcome_details(code, description) + description = str(phase_execution_outcome.phase_result) + self.test_record.add_outcome_details(code, description) self._finalize(test_record.Outcome.ERROR) elif phase_execution_outcome.is_timeout: self.logger.error('Finishing test execution early due to phase ' @@ -490,7 +491,7 @@ def _finalize_measurements(self): Any UNSET measurements will cause the Phase to FAIL unless conf.allow_unset_measurements is set True. """ - for measurement in self.measurements.itervalues(): + for measurement in self.measurements.values(): # Clear notification callbacks for later serialization. measurement.set_notification_callback(None) # Validate multi-dimensional measurements now that we have all values. @@ -506,7 +507,7 @@ def _measurements_pass(self): allowed_outcomes.add(measurements.Outcome.UNSET) if any(meas.outcome not in allowed_outcomes - for meas in self.phase_record.measurements.itervalues()): + for meas in self.phase_record.measurements.values()): return False return True diff --git a/openhtf/output/callbacks/__init__.py b/openhtf/output/callbacks/__init__.py index 8b2782652..40a83c9fa 100644 --- a/openhtf/output/callbacks/__init__.py +++ b/openhtf/output/callbacks/__init__.py @@ -22,7 +22,10 @@ import base64 import contextlib -import cPickle as pickle +try: + import cPickle as pickle +except: + import pickle import os import shutil import tempfile @@ -40,7 +43,9 @@ def __init__(self, filename): self.temp = tempfile.NamedTemporaryFile(delete=False) def write(self, write_data): - return self.temp.write(write_data) + if hasattr(write_data, 'decode'): + return self.temp.write(write_data) + return self.temp.write(write_data.encode()) def close(self): self.temp.close() @@ -81,7 +86,7 @@ def open_output_file(self, test_record): record_dict = data.convert_to_base_types( test_record, ignore_keys=('code_info', 'phases', 'log_records')) pattern = self.filename_pattern - if isinstance(pattern, basestring) or callable(pattern): + if isinstance(pattern, str) or callable(pattern): output_file = self.open_file(util.format_string(pattern, record_dict)) try: yield output_file diff --git a/openhtf/output/callbacks/console_summary.py b/openhtf/output/callbacks/console_summary.py index 9c7410ad6..390532a02 100644 --- a/openhtf/output/callbacks/console_summary.py +++ b/openhtf/output/callbacks/console_summary.py @@ -45,7 +45,7 @@ def __call__(self, record): new_phase = True phase_time_sec = (float(phase.end_time_millis) - float(phase.start_time_millis)) / 1000.0 - for name, measurement in phase.measurements.iteritems(): + for name, measurement in phase.measurements.items(): if measurement.outcome == meas_module.Outcome.FAIL: if new_phase: output_lines.append('failed phase: %s [ran for %.2f sec]' % diff --git a/openhtf/output/callbacks/json_factory.py b/openhtf/output/callbacks/json_factory.py index b6960863a..aac007794 100644 --- a/openhtf/output/callbacks/json_factory.py +++ b/openhtf/output/callbacks/json_factory.py @@ -44,7 +44,7 @@ def convert_to_dict(self, test_record): json_safe=(not self.allow_nan)) if self.inline_attachments: for phase, original_phase in zip(as_dict['phases'], test_record.phases): - for name, attachment in phase['attachments'].iteritems(): + for name, attachment in phase['attachments'].items(): original_data = original_phase.attachments[name].data - attachment['data'] = base64.standard_b64encode(original_data) + attachment['data'] = base64.standard_b64encode(original_data).decode('utf-8') return as_dict diff --git a/openhtf/output/callbacks/mfg_inspector.py b/openhtf/output/callbacks/mfg_inspector.py index b206dbd6f..0249bc525 100644 --- a/openhtf/output/callbacks/mfg_inspector.py +++ b/openhtf/output/callbacks/mfg_inspector.py @@ -67,7 +67,7 @@ UOM_CODE_MAP = { u.GetOptions().Extensions[units_pb2.uom_code]: num for num, u in - units_pb2.Units.UnitCode.DESCRIPTOR.values_by_number.iteritems() + units_pb2.Units.UnitCode.DESCRIPTOR.values_by_number.items() } # pylint: enable=no-member @@ -121,7 +121,7 @@ def _populate_header(record, testrun): attachment = testrun.info_parameters.add() attachment.name = 'config' attachment.value_binary = json.dumps( - record.metadata['config'], sort_keys=True, indent=4) + record.metadata['config'], sort_keys=True, indent=4).encode('utf-8') def _ensure_unique_parameter_name(name, used_parameter_names): @@ -143,7 +143,7 @@ def _attach_json(record, testrun): sort_keys=True, indent=2).serialize_test_record(record) testrun_param = testrun.info_parameters.add() testrun_param.name = 'OpenHTF_record.json' - testrun_param.value_binary = record_json + testrun_param.value_binary = record_json.encode('utf-8') # pylint: disable=no-member testrun_param.type = test_runs_pb2.TEXT_UTF8 # pylint: enable=no-member @@ -155,7 +155,7 @@ def _extract_attachments(phase, testrun, used_parameter_names): name = _ensure_unique_parameter_name(name, used_parameter_names) testrun_param = testrun.info_parameters.add() testrun_param.name = name - if isinstance(attachment_data, unicode): + if isinstance(attachment_data, str): attachment_data = attachment_data.encode('utf8') testrun_param.value_binary = attachment_data if mimetype in MIMETYPE_MAP: @@ -173,8 +173,8 @@ def _mangle_measurement(name, measured_value, measurement, mangled_parameters, We generate these by doing some name mangling, using some sane limits for very large multidimensional measurements. """ - for coord, val in measured_value.value_dict.items( - )[:MAX_PARAMS_PER_MEASUREMENT]: + for coord, val in list(measured_value.value_dict.items( + ))[:MAX_PARAMS_PER_MEASUREMENT]: # Mangle names so they look like 'myparameter_Xsec_Ynm_ZHz' mangled_name = '_'.join([name] + [ '%s%s' % ( @@ -258,7 +258,7 @@ def _extract_parameters(record, testrun, used_parameter_names): attachment = testrun.info_parameters.add() attachment.name = 'multidim_%s' % name dims = [{ - 'uom_suffix': d.suffix and d.suffix.encode('utf8'), + 'uom_suffix': d.suffix, 'uom_code': d.code} for d in measurement.dimensions] # Refer to the module docstring for the expected schema. @@ -266,7 +266,7 @@ def _extract_parameters(record, testrun, used_parameter_names): 'outcome': str(testrun_param.status), 'name': name, 'dimensions': dims, 'value': value - }, sort_keys=True) + }, sort_keys=True).encode('utf-8') attachment.type = test_runs_pb2.MULTIDIM_JSON _mangle_measurement( name, measurement.measured_value, measurement, mangled_parameters, diff --git a/openhtf/output/proto/test_runs.proto b/openhtf/output/proto/test_runs.proto index a51e8e75e..888bb8d95 100644 --- a/openhtf/output/proto/test_runs.proto +++ b/openhtf/output/proto/test_runs.proto @@ -21,7 +21,7 @@ syntax = "proto2"; package openhtf; // import "assembly.proto"; -import "units.proto"; +import "openhtf/output/proto/units.proto"; // Tag identifying the type of informational data encoded in the info parameter. enum InformationTag { diff --git a/openhtf/output/web_gui/__init__.py b/openhtf/output/web_gui/__init__.py index 60ea2c5c0..75d749c4a 100644 --- a/openhtf/output/web_gui/__init__.py +++ b/openhtf/output/web_gui/__init__.py @@ -158,7 +158,7 @@ def handle_state_update(self, state=None): return plug_names = set(self._test.get_frontend_aware_plug_names()) - watched_names = set(self._plug_watchers.iterkeys()) + watched_names = set(self._plug_watchers.keys()) for plug_name in plug_names - watched_names: self._plug_watchers[plug_name] = PlugWatcher( @@ -239,12 +239,12 @@ def run(self): if self._disable_discovery: _LOG.debug('Station discovery is disabled; only using static stations.') - self._handle_stations(self.stations.iterkeys()) + self._handle_stations(self.stations.keys()) while not self._stop_event.is_set(): if not self._disable_discovery: self._discover() - self._handle_stations(self.stations.iterkeys()) + self._handle_stations(iter(self.stations.keys())) self._stop_event.wait(self._discovery_interval_s) def stop(self): @@ -253,7 +253,7 @@ def stop(self): self.join() def watch_tests(self, hostport): - for test_uid, remote_test in self.stations[hostport].tests.iteritems(): + for test_uid, remote_test in self.stations[hostport].tests.items(): if (hostport, test_uid) not in self._watchers: self._watchers[hostport, test_uid] = TestWatcher( hostport, remote_test, self._on_update_callback) @@ -322,7 +322,7 @@ class DashboardPubSub(PubSub): def publish_discovery_update(cls, stations): """Look for changes in high-level station info and publish if changed.""" new_stations = {} - for (host, port), station in stations.iteritems(): + for (host, port), station in stations.items(): new_stations['%s:%s' % (host, port)] = { 'station_id': station.station_id, 'host': host, @@ -377,7 +377,7 @@ def on_subscribe(self, info): try: self._store.watch_tests(hostport) - for test_uid, remote_test in self._store[hostport].tests.iteritems(): + for test_uid, remote_test in self._store[hostport].tests.items(): self.send(self.make_msg(test_uid, remote_test.state)) except station_api.StationUnreachableError: _LOG.debug('Station %s unreachable during on_subscribe.', hostport) @@ -472,7 +472,7 @@ def post(self, host, port, test_uid, plug_name): if plug is None: self.set_status(500) self.write('Plug "%s" not found in "%s"' % ( - self.request.path, self._plugs.keys())) + self.request.path, list(self._plugs.keys()))) return try: response = plug.respond(self.request.body) diff --git a/openhtf/output/web_gui/__main__.py b/openhtf/output/web_gui/__main__.py index 53703a401..464d9e3c3 100644 --- a/openhtf/output/web_gui/__main__.py +++ b/openhtf/output/web_gui/__main__.py @@ -15,7 +15,6 @@ """Entry point to run OpenHTF's built-in web gui server.""" - from __future__ import print_function import argparse import logging diff --git a/openhtf/output/web_gui/src/other_modules/get_other_modules.py b/openhtf/output/web_gui/src/other_modules/get_other_modules.py index fa2f1de65..00f4eee36 100644 --- a/openhtf/output/web_gui/src/other_modules/get_other_modules.py +++ b/openhtf/output/web_gui/src/other_modules/get_other_modules.py @@ -18,7 +18,7 @@ import argparse import os -import urllib +import urllib.request, urllib.parse, urllib.error TARGETS = [ 'http://cdn.jsdelivr.net/sockjs/1/sockjs.min.js', # sockjs @@ -38,7 +38,7 @@ def main(): filename = src.split('/')[-1].split('#')[0].split('?')[0] dst = os.path.join(os.path.dirname(os.path.abspath(__file__)), filename) if args.force or not os.path.exists(dst): - urllib.urlretrieve(src, dst) + urllib.request.urlretrieve(src, dst) if __name__ == '__main__': diff --git a/openhtf/plugs/__init__.py b/openhtf/plugs/__init__.py index 2c3ba7f7e..abb7640df 100644 --- a/openhtf/plugs/__init__.py +++ b/openhtf/plugs/__init__.py @@ -223,7 +223,7 @@ def plug(update_kwargs=True, **plugs): Raises: InvalidPlugError: If a type is provided that is not a subclass of BasePlug. """ - for a_plug in plugs.itervalues(): + for a_plug in plugs.values(): if not (isinstance(a_plug, PlugPlaceholder) or issubclass(a_plug, BasePlug)): raise InvalidPlugError( 'Plug %s is not a subclass of plugs.BasePlug nor a placeholder ' @@ -250,7 +250,7 @@ def result(func): 'Plugs %s required multiple times on phase %s' % (duplicates, func)) phase_desc.plugs.extend([ openhtf.PhasePlug(name, a_plug, update_kwargs=update_kwargs) - for name, a_plug in plugs.iteritems()]) + for name, a_plug in plugs.items()]) return phase_desc return result @@ -307,7 +307,7 @@ def _asdict(self): return { 'plug_descriptors': self._plug_descriptors, 'plug_states': {name: plug._asdict() - for name, plug in self._plugs_by_name.iteritems()}, + for name, plug in self._plugs_by_name.items()}, 'xmlrpc_port': self._xmlrpc_server and self._xmlrpc_server.socket.getsockname()[1] } @@ -325,7 +325,7 @@ def _create_or_update_rpc_server(self): # Create a list of (method, method_name) pairs. plug_methods = [] - for name, plug in self._plugs_by_name.iteritems(): + for name, plug in self._plugs_by_name.items(): if not plug.enable_remote: continue @@ -482,7 +482,7 @@ def tear_down_plugs(self): self._xmlrpc_server = None _LOG.debug('Tearing down all plugs.') - for a_plug in self._plugs_by_type.itervalues(): + for a_plug in self._plugs_by_type.values(): thread = _PlugTearDownThread(a_plug) thread.start() timeout_s = (conf.plug_teardown_timeout_s @@ -528,5 +528,5 @@ def wait_for_plug_update(self, plug_name, remote_state, timeout_s): def get_frontend_aware_plug_names(self): """Returns the names of frontend-aware plugs.""" - return [name for name, plug in self._plugs_by_name.iteritems() + return [name for name, plug in self._plugs_by_name.items() if isinstance(plug, FrontendAwareBasePlug)] diff --git a/openhtf/plugs/usb/__init__.py b/openhtf/plugs/usb/__init__.py index eacf391a1..2956967a6 100644 --- a/openhtf/plugs/usb/__init__.py +++ b/openhtf/plugs/usb/__init__.py @@ -28,7 +28,6 @@ def MyPhase(test, adb): adb.Shell('ls') """ import argparse -import commands import logging import time diff --git a/openhtf/plugs/usb/adb_device.py b/openhtf/plugs/usb/adb_device.py index a3a2c1e75..d92ef5802 100644 --- a/openhtf/plugs/usb/adb_device.py +++ b/openhtf/plugs/usb/adb_device.py @@ -30,7 +30,7 @@ class, subclass, and protocol. """ -import cStringIO +import io import logging import os.path @@ -142,7 +142,7 @@ def push(self, source_file, device_filename, timeout_ms=None): timeout_ms: Expected timeout for any part of the push. """ mtime = 0 - if isinstance(source_file, basestring): + if isinstance(source_file, str): mtime = os.path.getmtime(source_file) source_file = open(source_file) @@ -161,15 +161,15 @@ def pull(self, device_filename, dest_file=None, timeout_ms=None): Returns: The file data if dest_file is not set, None otherwise. """ - if isinstance(dest_file, basestring): + if isinstance(dest_file, str): dest_file = open(dest_file, 'w') elif not dest_file: - dest_file = cStringIO.StringIO() + dest_file = io.StringIO() self.filesync_service.recv(device_filename, dest_file, timeouts.PolledTimeout.from_millis(timeout_ms)) # An empty call to cStringIO.StringIO returns an instance of # cStringIO.OutputType. - if isinstance(dest_file, cStringIO.OutputType): + if isinstance(dest_file, io.OutputType): return dest_file.getvalue() def list(self, device_path, timeout_ms=None): diff --git a/openhtf/plugs/usb/adb_message.py b/openhtf/plugs/usb/adb_message.py index 99e71213d..c2d636f2f 100644 --- a/openhtf/plugs/usb/adb_message.py +++ b/openhtf/plugs/usb/adb_message.py @@ -56,7 +56,7 @@ def make_wire_commands(*ids): cmd_to_wire = { cmd: sum(ord(c) << (i * 8) for i, c in enumerate(cmd)) for cmd in ids } - wire_to_cmd = {wire: cmd for cmd, wire in cmd_to_wire.iteritems()} + wire_to_cmd = {wire: cmd for cmd, wire in cmd_to_wire.items()} return cmd_to_wire, wire_to_cmd diff --git a/openhtf/plugs/usb/adb_protocol.py b/openhtf/plugs/usb/adb_protocol.py index 4dceaad76..129c880f0 100644 --- a/openhtf/plugs/usb/adb_protocol.py +++ b/openhtf/plugs/usb/adb_protocol.py @@ -79,7 +79,7 @@ import collections import itertools import logging -import Queue +import queue import threading from enum import Enum @@ -567,7 +567,7 @@ def __init__(self, transport, maxdata, remote_banner): def _make_stream_transport(self): """Create an AdbStreamTransport with a newly allocated local_id.""" - msg_queue = Queue.Queue() + msg_queue = queue.Queue() with self._stream_transport_map_lock: # Start one past the last id we used, and grab the first available one. # This mimics the ADB behavior of 'increment an unsigned and let it @@ -579,9 +579,9 @@ def _make_stream_transport(self): self._last_id_used = (self._last_id_used % STREAM_ID_LIMIT) + 1 for local_id in itertools.islice( itertools.chain( - xrange(self._last_id_used, STREAM_ID_LIMIT), - xrange(1, self._last_id_used)), 64): - if local_id not in self._stream_transport_map.keys(): + range(self._last_id_used, STREAM_ID_LIMIT), + range(1, self._last_id_used)), 64): + if local_id not in list(self._stream_transport_map.keys()): self._last_id_used = local_id break else: @@ -785,7 +785,7 @@ def read_for_stream(self, stream_transport, timeout_ms=None): try: # Block for up to 10ms to rate-limit how fast we spin. return stream_transport.message_queue.get(True, .01) - except Queue.Empty: + except queue.Empty: pass # If someone else has the Lock, just keep checking our queue. @@ -799,7 +799,7 @@ def read_for_stream(self, stream_transport, timeout_ms=None): # Lock ourselves, we're sure there are no potentially in-flight reads. try: return stream_transport.message_queue.get_nowait() - except Queue.Empty: + except queue.Empty: pass while not timeout.has_expired(): @@ -818,7 +818,7 @@ def read_for_stream(self, stream_transport, timeout_ms=None): # queued messages. try: return stream_transport.message_queue.get_nowait() - except Queue.Empty: + except queue.Empty: raise usb_exceptions.AdbStreamClosedError( 'Attempt to read from closed or unknown %s', stream_transport) diff --git a/openhtf/plugs/usb/fastboot_device.py b/openhtf/plugs/usb/fastboot_device.py index c9653be76..dbd828d64 100644 --- a/openhtf/plugs/usb/fastboot_device.py +++ b/openhtf/plugs/usb/fastboot_device.py @@ -21,6 +21,7 @@ from openhtf.plugs.usb import fastboot_protocol from openhtf.plugs.usb import usb_exceptions from openhtf.util import timeouts +import collections # From fastboot.c VENDORS = {0x18D1, 0x0451, 0x0502, 0x0FCE, 0x05C6, 0x22B8, 0x0955, diff --git a/openhtf/plugs/usb/fastboot_protocol.py b/openhtf/plugs/usb/fastboot_protocol.py index eceea04cc..f933e1109 100644 --- a/openhtf/plugs/usb/fastboot_protocol.py +++ b/openhtf/plugs/usb/fastboot_protocol.py @@ -17,7 +17,7 @@ import binascii import collections -import cStringIO +import io import logging import os import struct @@ -70,7 +70,7 @@ def send_command(self, command, arg=None): """ if arg is not None: command = '%s:%s' % (command, arg) - self._write(cStringIO.StringIO(command), len(command)) + self._write(io.StringIO(command), len(command)) def handle_simple_responses( self, timeout_ms=None, info_cb=DEFAULT_MESSAGE_CALLBACK): @@ -175,7 +175,7 @@ def _write(self, data, length, progress_callback=None): """Sends the data to the device, tracking progress with the callback.""" if progress_callback: progress = self._handle_progress(length, progress_callback) - progress.next() + next(progress) while length: tmp = data.read(FASTBOOT_DOWNLOAD_CHUNK_SIZE_KB * 1024) length -= len(tmp) @@ -259,14 +259,14 @@ def download(self, source_file, source_len=0, Returns: Response to a download request, normally nothing. """ - if isinstance(source_file, basestring): + if isinstance(source_file, str): source_len = os.stat(source_file).st_size source_file = open(source_file) if source_len == 0: # Fall back to storing it all in memory :( data = source_file.read() - source_file = cStringIO.StringIO(data) + source_file = io.StringIO(data) source_len = len(data) self._protocol.send_command('download', '%08x' % source_len) diff --git a/openhtf/plugs/usb/filesync_service.py b/openhtf/plugs/usb/filesync_service.py index d3aa2255e..bc8106d38 100644 --- a/openhtf/plugs/usb/filesync_service.py +++ b/openhtf/plugs/usb/filesync_service.py @@ -223,7 +223,7 @@ def _check_for_fail_message(self, transport, exc_info, timeout): # pylint: disa if sys.exc_info()[0] is usb_exceptions.AdbRemoteError: raise # Otherwise reraise the original exception. - raise exc_info[0], exc_info[1], exc_info[2] + raise exc_info[0](exc_info[1]).raise_with_traceback(exc_info[2]) # pylint: disable=too-many-arguments def send(self, src_file, filename, st_mode=DEFAULT_PUSH_MODE, mtime=None, diff --git a/openhtf/plugs/usb/shell_service.py b/openhtf/plugs/usb/shell_service.py index 6d5c506ee..0df4a595c 100644 --- a/openhtf/plugs/usb/shell_service.py +++ b/openhtf/plugs/usb/shell_service.py @@ -68,7 +68,7 @@ # output.getvalue() now contains the output of the arecord command. """ -import cStringIO +import io import threading import time @@ -112,7 +112,7 @@ def __init__(self, stream, stdin, stdout, timeout, is_raw): #pylint: disable=to """ self.stream = stream self.stdin = stdin - self.stdout = stdout or cStringIO.StringIO() + self.stdout = stdout or io.StringIO() self.force_closed_or_timeout = False self.reader_thread = threading.Thread(target=self._reader_thread_proc, diff --git a/openhtf/plugs/usb/usb_handle.py b/openhtf/plugs/usb/usb_handle.py index 4f18da46a..d68187750 100644 --- a/openhtf/plugs/usb/usb_handle.py +++ b/openhtf/plugs/usb/usb_handle.py @@ -21,6 +21,7 @@ A UsbHandle object represents a single USB Interface, *not* an entire device. """ +from future.utils import with_metaclass import abc import functools import logging @@ -58,7 +59,7 @@ def wrapper_requiring_open_handle(self, *args, **kwargs): return wrapper_requiring_open_handle -class UsbHandle(object): +class UsbHandle(with_metaclass(object)): """UsbHandle objects provide read/write access to USB Interfaces. Subclasses must implement this interface to provide actual Read/Write/Close @@ -98,7 +99,6 @@ class UsbHandle(object): name: Name assigned to this handle, used for logging purposes. serial_number: Serial number of the device this handle refers to. """ - __metaclass__ = abc.ABCMeta def __init__(self, serial_number, name=None, default_timeout_ms=None): """Create a UsbHandle to refer to a particular USB Interface. diff --git a/openhtf/plugs/user_input.py b/openhtf/plugs/user_input.py index 7f96b1d16..b2d37023c 100644 --- a/openhtf/plugs/user_input.py +++ b/openhtf/plugs/user_input.py @@ -21,6 +21,8 @@ prompt state should use the openhtf.prompts pseudomodule. """ +from __future__ import print_function +from builtins import input import collections import functools import logging @@ -73,7 +75,7 @@ def Stop(self): """Mark this ConsolePrompt as stopped.""" self._stopped = True if not self._answered: - print "Nevermind; prompt was answered from elsewhere." + print("Nevermind; prompt was answered from elsewhere.") def run(self): """Main logic for this thread to execute.""" @@ -81,12 +83,12 @@ def run(self): if platform.system() == 'Windows': # Windows doesn't support file-like objects for select(), so fall back # to raw_input(). - response = raw_input(self._message + '\n\r') + response = input(self._message + '\n\r') self._answered = True self._callback(response) else: # First, display the prompt to the console. - print self._message + print(self._message) # Before reading, clear any lingering buffered terminal input. if sys.stdin.isatty(): @@ -104,14 +106,14 @@ def run(self): # We're running in the background somewhere, so the only way # to respond to this prompt is the UI. Let's just wait for # that to happen now. We'll give them a week :) - print "Waiting for a non-console response." + print("Waiting for a non-console response.") time.sleep(60*60*24*7) else: # They hit ^D (to insert EOF). Tell them to hit ^C if they # want to actually quit. - print "Hit ^C (Ctrl+c) to exit." + print("Hit ^C (Ctrl+c) to exit.") break - line += new + line += new.decode('utf-8') if '\n' in line: response = line[:line.find('\n')] self._answered = True @@ -212,7 +214,7 @@ def respond(self, prompt_id, response): Returns: True if the prompt was used, otherwise False. """ - if isinstance(prompt_id, basestring): + if isinstance(prompt_id, str): prompt_id = uuid.UUID(prompt_id) _LOG.debug('Responding to prompt (%s): "%s"', prompt_id.hex, response) with self._cond: diff --git a/openhtf/util/__init__.py b/openhtf/util/__init__.py index e2de8ff62..cb43cd5b5 100644 --- a/openhtf/util/__init__.py +++ b/openhtf/util/__init__.py @@ -26,6 +26,7 @@ import mutablerecords from openhtf.util import threads +import collections def _log_every_n_to_logger(n, logger, level, message, *args): # pylint: disable=invalid-name @@ -43,7 +44,7 @@ def _log_every_n_to_logger(n, logger, level, message, *args): # pylint: disable logger = logger or logging.getLogger() def _gen(): # pylint: disable=missing-docstring while True: - for _ in xrange(n): + for _ in range(n): yield False logger.log(level, message, *args) yield True @@ -145,7 +146,7 @@ def format_string(target, kwargs): return target if callable(target): return target(**kwargs) - if not isinstance(target, basestring): + if not isinstance(target, str): return target if '{' in target: return partial_format(target, **kwargs) diff --git a/openhtf/util/conf.py b/openhtf/util/conf.py index 1e997f799..6eb519a18 100644 --- a/openhtf/util/conf.py +++ b/openhtf/util/conf.py @@ -166,8 +166,8 @@ def do_stuff(): import mutablerecords -import argv -import threads +from . import argv +from . import threads # If provided, --config-file will cause the given file to be load()ed when the # conf module is initially imported. @@ -408,7 +408,7 @@ def load_from_dict(self, dictionary, _override=True, _allow_undeclared=False): files before declarations have been evaluated. """ undeclared_keys = [] - for key, value in dictionary.iteritems(): + for key, value in dictionary.items(): # Warn in this case. We raise if you try to access a config key that # hasn't been declared, but we don't raise here so that you can use # configuration files that are supersets of required configuration for @@ -441,7 +441,7 @@ def _asdict(self): retval.update(self._loaded_values) # Only update keys that are declared so we don't allow injecting # un-declared keys via commandline flags. - for key, value in self._flag_values.iteritems(): + for key, value in self._flag_values.items(): if key in self._declarations: retval[key] = value return retval @@ -564,7 +564,7 @@ def method_wrapper(**kwargs): final_kwargs.update(kwargs) if inspect.ismethod(method): - name = '%s.%s' % (method.im_class.__name__, method.__name__) + name = '%s.%s' % (method.__self__.__class__.__name__, method.__name__) else: name = method.__name__ self._logger.debug('Invoking %s with %s', name, final_kwargs) diff --git a/openhtf/util/data.py b/openhtf/util/data.py index b95fb067e..8225f5648 100644 --- a/openhtf/util/data.py +++ b/openhtf/util/data.py @@ -29,11 +29,12 @@ import sys from mutablerecords import records +from past.builtins import long from enum import Enum # Used by convert_to_base_types(). -PASSTHROUGH_TYPES = {bool, bytes, int, long, type(None), unicode} +PASSTHROUGH_TYPES = {bool, bytes, int, long, type(None), str} def pprint_diff(first, second, first_name='first', second_name='second'): @@ -68,8 +69,8 @@ def assert_records_equal_nonvolatile(first, second, volatile_fields, indent=0): if isinstance(first, dict) and isinstance(second, dict): if set(first) != set(second): logging.error('%sMismatching keys:', ' ' * indent) - logging.error('%s %s', ' ' * indent, first.keys()) - logging.error('%s %s', ' ' * indent, second.keys()) + logging.error('%s %s', ' ' * indent, list(first.keys())) + logging.error('%s %s', ' ' * indent, list(second.keys())) assert set(first) == set(second) for key in first: if key in volatile_fields: @@ -132,7 +133,7 @@ def convert_to_base_types(obj, ignore_keys=tuple(), tuple_type=tuple, such as NaN which are not valid JSON. """ # Because it's *really* annoying to pass a single string accidentally. - assert not isinstance(ignore_keys, basestring), 'Pass a real iterable!' + assert not isinstance(ignore_keys, str), 'Pass a real iterable!' if type(obj) in PASSTHROUGH_TYPES: return obj @@ -149,9 +150,9 @@ def convert_to_base_types(obj, ignore_keys=tuple(), tuple_type=tuple, # Recursively convert values in dicts, lists, and tuples. if isinstance(obj, dict): - return {convert_to_base_types(k, ignore_keys, tuple_type, json_safe): - convert_to_base_types(v, ignore_keys, tuple_type, json_safe) - for k, v in obj.iteritems() if k not in ignore_keys} + return {convert_to_base_types(k, ignore_keys, tuple_type): + convert_to_base_types(v, ignore_keys, tuple_type) + for k, v in obj.items() if k not in ignore_keys} elif isinstance(obj, list): return [convert_to_base_types(val, ignore_keys, tuple_type, json_safe) for val in obj] @@ -193,9 +194,9 @@ def _sizeof(current_obj): if isinstance(current_obj, dict): size += sum(map(sizeof, itertools.chain.from_iterable( - current_obj.iteritems()))) + current_obj.items()))) elif (isinstance(current_obj, collections.Iterable) and - not isinstance(current_obj, basestring)): + not isinstance(current_obj, str)): size += sum(sizeof(item) for item in current_obj) elif isinstance(current_obj, records.RecordClass): size += sum(sizeof(getattr(current_obj, attr)) diff --git a/openhtf/util/exceptions.py b/openhtf/util/exceptions.py index 667e6140b..6aca117bc 100644 --- a/openhtf/util/exceptions.py +++ b/openhtf/util/exceptions.py @@ -71,4 +71,4 @@ def main(): line_msg = 'line %s: ' % last_lineno if message: line_msg += str(message) - raise exc_type(line_msg, *args, **kwargs), None, sys.exc_info()[2] + raise exc_type(line_msg, *args, **kwargs).raise_with_traceback(sys.exc_info()[2]) diff --git a/openhtf/util/logs.py b/openhtf/util/logs.py index ae53e2d5a..02acdfc71 100644 --- a/openhtf/util/logs.py +++ b/openhtf/util/logs.py @@ -63,6 +63,7 @@ def MyPhase(test, helper): no way to change this, if you don't like it redirect stdout to /dev/null. """ +from past.builtins import basestring import argparse import collections import logging @@ -181,7 +182,6 @@ def emit(self, record): if record.exc_info: message += '\n' + ''.join(traceback.format_exception( *record.exc_info)) - message = message.decode('utf8', 'replace') log_record = LogRecord( record.levelno, record.name, os.path.basename(record.pathname), @@ -212,7 +212,7 @@ def setup_logger(): file_handler.addFilter(MAC_FILTER) logger.addHandler(file_handler) except IOError as exception: - print ('Failed to set up log file due to error: %s. ' + print('Failed to set up log file due to error: %s. ' 'Continuing anyway.' % exception) if not QUIET: diff --git a/openhtf/util/multicast.py b/openhtf/util/multicast.py index 11826f3df..11cac8af3 100644 --- a/openhtf/util/multicast.py +++ b/openhtf/util/multicast.py @@ -22,7 +22,7 @@ import logging -import Queue +import queue import socket import struct import sys @@ -156,10 +156,10 @@ def send(query, socket.IP_MULTICAST_IF, struct.pack('!L', LOCALHOST_ADDRESS)) sock.settimeout(timeout_s) - sock.sendto(query, (address, port)) + sock.sendto(query.encode('utf-8'), (address, port)) # Set up our thread-safe Queue for handling responses. - recv_queue = Queue.Queue() + recv_queue = queue.Queue() def _handle_responses(): while True: try: diff --git a/openhtf/util/test.py b/openhtf/util/test.py index 392d31bce..8e4fc277d 100644 --- a/openhtf/util/test.py +++ b/openhtf/util/test.py @@ -112,6 +112,7 @@ def test_multiple(self, mock_my_plug): assertMeasurementFail(phase_or_test_rec, measurement) """ +from past.builtins import basestring import collections import functools import inspect @@ -171,7 +172,7 @@ def _initialize_plugs(self, plug_types): plug_types = list(plug_types) self.plug_manager.initialize_plugs(plug_cls for plug_cls in plug_types if plug_cls not in self.mock_plugs) - for plug_type, plug_value in self.mock_plugs.iteritems(): + for plug_type, plug_value in self.mock_plugs.items(): self.plug_manager.update_plug(plug_type, plug_value) @conf.save_and_restore(station_api_port=None, enable_station_discovery=False) @@ -196,7 +197,7 @@ def _handle_phase(self, phase_desc): def _handle_test(self, test): self._initialize_plugs(test.descriptor.plug_types) # Make sure we inject our mock plug instances. - for plug_type, plug_value in self.mock_plugs.iteritems(): + for plug_type, plug_value in self.mock_plugs.items(): self.plug_manager.update_plug(plug_type, plug_value) # We'll need a place to stash the resulting TestRecord. @@ -211,11 +212,24 @@ def _handle_test(self, test): return record_saver.result + def __next__(self): + phase_or_test = self.iterator.send(self.last_result) + if isinstance(phase_or_test, openhtf.Test): + self.last_result = self._handle_test(phase_or_test) + elif not isinstance(phase_or_test, collections.Callable): + raise InvalidTestError( + 'methods decorated with patch_plugs must yield Test instances or ' + 'individual test phases', phase_or_test) + else: + self.last_result = self._handle_phase( + openhtf.PhaseDescriptor.wrap_or_copy(phase_or_test)) + return phase_or_test, self.last_result + def next(self): phase_or_test = self.iterator.send(self.last_result) if isinstance(phase_or_test, openhtf.Test): self.last_result = self._handle_test(phase_or_test) - elif not callable(phase_or_test): + elif not isinstance(phase_or_test, collections.Callable): raise InvalidTestError( 'methods decorated with patch_plugs must yield Test instances or ' 'individual test phases', phase_or_test) @@ -285,7 +299,7 @@ def test_wrapper(test_func): # Make MagicMock instances for the plugs. plug_kwargs = {} # kwargs to pass to test func. plug_typemap = {} # typemap for PlugManager, maps type to instance. - for plug_arg_name, plug_fullname in mock_plugs.iteritems(): + for plug_arg_name, plug_fullname in mock_plugs.items(): if isinstance(plug_fullname, basestring): try: plug_module, plug_typename = plug_fullname.rsplit('.', 1) @@ -355,7 +369,7 @@ def assertion_wrapper(self, phase_or_test_record, *args): exc_info = sys.exc_info() else: if exc_info: - raise exc_info[0], exc_info[1], exc_info[2] + raise exc_info[0](exc_info[1]).raise_with_traceback(exc_info[2]) elif isinstance(phase_or_test_record, test_record.PhaseRecord): func(self, phase_or_test_record, *args) else: @@ -365,13 +379,13 @@ def assertion_wrapper(self, phase_or_test_record, *args): ##### TestRecord Assertions ##### def assertTestPass(self, test_rec): - self.assertEquals(test_record.Outcome.PASS, test_rec.outcome) + self.assertEqual(test_record.Outcome.PASS, test_rec.outcome) def assertTestFail(self, test_rec): - self.assertEquals(test_record.Outcome.FAIL, test_rec.outcome) + self.assertEqual(test_record.Outcome.FAIL, test_rec.outcome) def assertTestError(self, test_rec, exc_type=None): - self.assertEquals(test_record.Outcome.ERROR, test_rec.outcome) + self.assertEqual(test_record.Outcome.ERROR, test_rec.outcome) if exc_type: self.assertPhaseError(test_rec.phases[-1], exc_type) @@ -442,7 +456,7 @@ def assertMeasured(self, phase_record, measurement, value=mock.ANY): phase_record.measurements[measurement].measured_value.is_value_set, 'Measurement %s not set' % measurement) if value is not mock.ANY: - self.assertEquals( + self.assertEqual( value, phase_record.measurements[measurement].measured_value.value, 'Measurement %s has wrong value: expected %s, got %s' % (measurement, value, diff --git a/openhtf/util/validators.py b/openhtf/util/validators.py index 2c4cbc9c2..17f8e01ee 100644 --- a/openhtf/util/validators.py +++ b/openhtf/util/validators.py @@ -58,6 +58,8 @@ def MyPhase(test): import numbers import re import sys +from past.builtins import basestring +from future.utils import with_metaclass from openhtf import util _VALIDATORS = {} @@ -81,17 +83,13 @@ def create_validator(name, *args, **kwargs): _identity = lambda x: x -class ValidatorBase(object): - __metaclass__ = abc.ABCMeta - +class ValidatorBase(with_metaclass(abc.ABCMeta, object)): @abc.abstractmethod def __call__(self, value): """Should validate value, returning a boolean result.""" -class RangeValidatorBase(ValidatorBase): - __metaclass__ = abc.ABCMeta - +class RangeValidatorBase(with_metaclass(abc.ABCMeta, ValidatorBase)): @abc.abstractproperty def minimum(self): """Should return the minimum, inclusive value of the range.""" diff --git a/openhtf/util/xmlrpcutil.py b/openhtf/util/xmlrpcutil.py index 37cbccb0a..9640d86b7 100644 --- a/openhtf/util/xmlrpcutil.py +++ b/openhtf/util/xmlrpcutil.py @@ -14,18 +14,27 @@ """Utility helpers for xmlrpclib.""" -import httplib -import SimpleXMLRPCServer -import SocketServer +import http.client +import xmlrpc.server +import os +import socketserver +import sys import threading -import xmlrpclib +import xmlrpc.client +import collections DEFAULT_PROXY_TIMEOUT_S = 3 +# https://github.com/PythonCharmers/python-future/issues/280 +if sys.version_info[0] < 3: + from SimpleXMLRPCServer import SimpleXMLRPCServer +else: + from xmlrpc.server import SimpleXMLRPCServer as SimpleXMLRPCServer -class TimeoutHTTPConnection(httplib.HTTPConnection): + +class TimeoutHTTPConnection(http.client.HTTPConnection): def __init__(self, timeout_s, *args, **kwargs): - httplib.HTTPConnection.__init__(self, *args, **kwargs) + http.client.HTTPConnection.__init__(self, *args, **kwargs) self.timeout_s = timeout_s def settimeout(self, timeout_s): @@ -33,13 +42,13 @@ def settimeout(self, timeout_s): self.sock.settimeout(self.timeout_s) def connect(self): - httplib.HTTPConnection.connect(self) + http.client.HTTPConnection.connect(self) self.sock.settimeout(self.timeout_s) -class TimeoutTransport(xmlrpclib.Transport): +class TimeoutTransport(xmlrpc.client.Transport): def __init__(self, timeout_s, *args, **kwargs): - xmlrpclib.Transport.__init__(self, *args, **kwargs) + xmlrpc.client.Transport.__init__(self, *args, **kwargs) self._connection = None self.timeout_s = timeout_s @@ -54,7 +63,7 @@ def make_connection(self, host): return self._connection[1] -class BaseServerProxy(xmlrpclib.ServerProxy, object): +class BaseServerProxy(xmlrpc.client.ServerProxy, object): """New-style base class for ServerProxy, allows for use of Mixins below.""" @@ -82,7 +91,7 @@ def __init__(self, *args, **kwargs): def __getattr__(self, attr): method = super(LockedProxyMixin, self).__getattr__(attr) - if callable(method): + if isinstance(method, collections.Callable): # xmlrpc doesn't support **kwargs, so only accept *args. def _wrapper(*args): with self._lock: @@ -99,6 +108,6 @@ class LockedTimeoutProxy(TimeoutProxyMixin, LockedProxyMixin, BaseServerProxy): class SimpleThreadedXmlRpcServer( - SocketServer.ThreadingMixIn, SimpleXMLRPCServer.SimpleXMLRPCServer): + socketserver.ThreadingMixIn, SimpleXMLRPCServer): """Helper for handling multiple simultaneous RPCs in threads.""" daemon_threads = True diff --git a/setup.py b/setup.py index 201fc5785..ce2b1c8e0 100644 --- a/setup.py +++ b/setup.py @@ -63,26 +63,26 @@ def initialize_options(self): # Default to /usr/local for Homebrew prefix = '/usr/local' else: - print ('Warning: mfg-inspector output is not fully implemented for ' - 'Windows. OpenHTF will be installed without it.') + print('Warning: mfg-inspector output is not fully implemented for ' + 'Windows. OpenHTF will be installed without it.') self.skip_proto = True - self.protoc = os.path.join(prefix, 'bin', 'protoc') - self.protodir = os.path.join(prefix, 'include') - self.indir = os.path.join(os.getcwd(), 'openhtf', 'output', 'proto') - self.outdir = os.path.join(os.getcwd(), 'openhtf', 'output', 'proto') + self.protoc = os.path.join(prefix, b'bin', b'protoc') + self.protodir = os.path.join(prefix, b'include') + self.indir = os.getcwd() + self.outdir = os.getcwd() def finalize_options(self): pass def run(self): if self.skip_proto: - print 'Skipping building protocol buffers.' + print('Skipping building protocol buffers.') return # Build regular proto files. - protos = glob.glob(os.path.join(self.indir, '*.proto')) + protos = glob.glob(os.path.join(self.indir, 'openhtf', 'output', 'proto', '*.proto')) if protos: - print 'Attempting to build proto files:\n%s' % '\n'.join(protos) + print('Attempting to build proto files:\n%s' % '\n'.join(protos)) cmd = [ self.protoc, '--proto_path', self.indir, @@ -93,18 +93,18 @@ def run(self): subprocess.check_call(cmd) except OSError as e: if e.errno == errno.ENOENT: - print 'Could not find the protobuf compiler at %s' % self.protoc - print ('On many Linux systems, this is fixed by installing the ' + print('Could not find the protobuf compiler at %s' % self.protoc) + print('On many Linux systems, this is fixed by installing the ' '"protobuf-compiler" and "libprotobuf-dev" packages.') raise except subprocess.CalledProcessError: - print 'Could not build proto files.' - print ('This could be due to missing helper files. On many Linux ' - 'systems, this is fixed by installing the ' - '"libprotobuf-dev" package.') + print('Could not build proto files.') + print('This could be due to missing helper files. On many Linux ' + 'systems, this is fixed by installing the ' + '"libprotobuf-dev" package.') raise else: - print 'Found no proto files to build.' + print('Found no proto files to build.') # Make building protos part of building overall. @@ -114,6 +114,7 @@ def run(self): INSTALL_REQUIRES = [ 'contextlib2>=0.5.1,<1.0', 'enum34>=1.1.2,<2.0', + 'future>=0.16.0', 'mutablerecords>=0.4.1,<2.0', 'oauth2client>=1.5.2,<2.0', 'protobuf>=3.0.0,<4.0', diff --git a/test/capture_source_test.py b/test/capture_source_test.py index 730a7e3d5..9e77ecae0 100644 --- a/test/capture_source_test.py +++ b/test/capture_source_test.py @@ -30,12 +30,12 @@ def testCaptured(self): htf.conf.load(capture_source=True) test = htf.Test(phase) phase_descriptor = test.descriptor.phases[0] - self.assertEquals(phase_descriptor.code_info.name, phase.__name__) + self.assertEqual(phase_descriptor.code_info.name, phase.__name__) @htf.conf.save_and_restore def testNotCaptured(self): htf.conf.load(capture_source=False) test = htf.Test(phase) phase_descriptor = test.descriptor.phases[0] - self.assertEquals(phase_descriptor.code_info.name, '') + self.assertEqual(phase_descriptor.code_info.name, '') diff --git a/test/core/exe_test.py b/test/core/exe_test.py index 12d5fdf7e..0b4b81328 100644 --- a/test/core/exe_test.py +++ b/test/core/exe_test.py @@ -39,13 +39,13 @@ def __init__(self): self.count = 0 def setup_cap(self): - print 'Set up the plugs instance.' + print('Set up the plugs instance.') def tear_down_cap(self): - print 'Tear down the plugs instance.' + print('Tear down the plugs instance.') def do_stuff(self): - print 'Plugs-specific functionality.' + print('Plugs-specific functionality.') def increment(self): self.count += 1 @@ -61,7 +61,7 @@ def phase_one(test, test_plug): del test # Unused. del test_plug # Unused. time.sleep(1) - print 'phase_one completed' + print('phase_one completed') @plugs.plug(test_plug=UnittestPlug) @@ -69,7 +69,7 @@ def phase_two(test, test_plug): del test # Unused. del test_plug # Unused. time.sleep(2) - print 'phase_two completed' + print('phase_two completed') @openhtf.PhaseOptions(repeat_limit=4) @@ -78,7 +78,7 @@ def phase_repeat(test, test_plug): del test # Unused. time.sleep(.1) ret = test_plug.increment() - print 'phase_repeat completed for %s time' % test_plug.count + print('phase_repeat completed for %s time' % test_plug.count) return openhtf.PhaseResult.CONTINUE if ret else openhtf.PhaseResult.REPEAT diff --git a/test/core/measurements_test.py b/test/core/measurements_test.py index c2c7c7314..7aed7c39b 100644 --- a/test/core/measurements_test.py +++ b/test/core/measurements_test.py @@ -72,9 +72,9 @@ def test_validator_replacement(self): @htf_test.yields_phases def test_measurement_order(self): record = yield all_the_things.dimensions - self.assertEqual(record.measurements.keys(), + self.assertEqual(list(record.measurements.keys()), ['unset_dims', 'dimensions', 'lots_of_dims']) record = yield all_the_things.measures_with_args.with_args(min=2, max=4) - self.assertEqual(record.measurements.keys(), + self.assertEqual(list(record.measurements.keys()), ['replaced_min_only', 'replaced_max_only', 'replaced_min_max']) diff --git a/test/core/monitors_test.py b/test/core/monitors_test.py index 5ab5069ae..3a6e3fd65 100644 --- a/test/core/monitors_test.py +++ b/test/core/monitors_test.py @@ -15,7 +15,7 @@ import unittest import time import mock -import Queue +import queue import openhtf from openhtf import plugs @@ -38,7 +38,7 @@ def provide_plugs(plugs): def test_basics(self): # Use a queue to ensure that we got at least 1 complete response. An Event # would cause a race condition, so we'd need 2 Events, so a Queue is easier. - q = Queue.Queue() + q = queue.Queue() def monitor_func(test): q.put(1) @@ -66,7 +66,7 @@ def phase(test): msg="And it should be the monitor func's return val") def testPlugs(self): - q = Queue.Queue() + q = queue.Queue() @plugs.plug(empty=EmptyPlug) def monitor(test, empty): diff --git a/test/output/callbacks/callbacks_test.py b/test/output/callbacks/callbacks_test.py index 362bb5148..c3fc1388b 100644 --- a/test/output/callbacks/callbacks_test.py +++ b/test/output/callbacks/callbacks_test.py @@ -18,7 +18,8 @@ actually care for. """ -from cStringIO import StringIO +import sys +from io import BytesIO, StringIO from examples import all_the_things import openhtf as htf @@ -49,7 +50,10 @@ def _save_result(test_record): def test_json(self, user_mock): user_mock.prompt.return_value = 'SomeWidget' record = yield self._test - json_output = StringIO() + if sys.version_info[0] < 3: + json_output = BytesIO() + else: + json_output = StringIO() json_factory.OutputToJSON( json_output, sort_keys=True, indent=2)(record) @@ -57,7 +61,7 @@ def test_json(self, user_mock): def test_testrun(self, user_mock): user_mock.prompt.return_value = 'SomeWidget' record = yield self._test - testrun_output = StringIO() + testrun_output = BytesIO() mfg_inspector.OutputToTestRunProto(testrun_output)(record) diff --git a/test/plugs_test.py b/test/plugs_test.py index db220e68d..929d88244 100644 --- a/test/plugs_test.py +++ b/test/plugs_test.py @@ -72,38 +72,35 @@ def tearDown(self): def test_base_plug(self): plug = plugs.BasePlug() - self.assertEquals({}, plug._asdict()) + self.assertEqual({}, plug._asdict()) plug.tearDown() def test_initialize(self): - self.assertEquals(0, AdderPlug.INSTANCE_COUNT) + self.assertEqual(0, AdderPlug.INSTANCE_COUNT) self.plug_manager.initialize_plugs() - self.assertEquals(1, AdderPlug.INSTANCE_COUNT) + self.assertEqual(1, AdderPlug.INSTANCE_COUNT) self.plug_manager.initialize_plugs() - self.assertEquals(1, AdderPlug.INSTANCE_COUNT) + self.assertEqual(1, AdderPlug.INSTANCE_COUNT) self.plug_manager.initialize_plugs({AdderPlug}) - self.assertEquals(1, AdderPlug.INSTANCE_COUNT) + self.assertEqual(1, AdderPlug.INSTANCE_COUNT) self.assertIs( AdderPlug.LAST_INSTANCE, self.plug_manager.provide_plugs( (('adder_plug', AdderPlug),))['adder_plug']) - self.assertItemsEqual(self.plug_manager._asdict(), { - 'plug_descriptors': { - 'plugs_test.AdderPlug': plugs.PlugDescriptor('plugs_test.AdderPlug'), - }, - 'plug_states': { + self.assertEqual(self.plug_manager._asdict()['plug_descriptors'], { + 'plugs_test.AdderPlug': plugs.PlugDescriptor(['plugs_test.AdderPlug']), + }) + self.assertEqual(self.plug_manager._asdict()['plug_states'], { 'plugs_test.AdderPlug': {'number': 0}, - }, - 'xmlrpc_port': None, - }) - self.assertEquals('CREATED', AdderPlug.LAST_INSTANCE.state) + }) + self.assertEqual('CREATED', AdderPlug.LAST_INSTANCE.state) @test.yields_phases def test_multiple_plugs(self): @plugs.plug(adder_plug=AdderPlug) @plugs.plug(other_plug=AdderPlug) def dummy_phase(test_api, adder_plug, other_plug): - self.assertEquals(1, AdderPlug.INSTANCE_COUNT) + self.assertEqual(1, AdderPlug.INSTANCE_COUNT) self.assertIs(AdderPlug.LAST_INSTANCE, adder_plug) self.assertIs(AdderPlug.LAST_INSTANCE, other_plug) yield dummy_phase @@ -111,7 +108,7 @@ def dummy_phase(test_api, adder_plug, other_plug): @plugs.plug(adder_plug=AdderPlug, other_plug=plugs.BasePlug) def dummy_phase(test_api, adder_plug, other_plug): - self.assertEquals(1, AdderPlug.INSTANCE_COUNT) + self.assertEqual(1, AdderPlug.INSTANCE_COUNT) self.assertIs(AdderPlug.LAST_INSTANCE, adder_plug) yield dummy_phase @@ -145,17 +142,17 @@ def test_plug_updates(self): self.plug_manager.initialize_plugs({AdderPlug}) update = self.plug_manager.wait_for_plug_update( 'plugs_test.AdderPlug', {}, .001) - self.assertEquals({'number': 0}, update) + self.assertEqual({'number': 0}, update) # No update since last time, this should time out (return None). self.assertIsNone(self.plug_manager.wait_for_plug_update( 'plugs_test.AdderPlug', update, .001)) def _delay_then_update(): time.sleep(.5) - self.assertEquals(1, AdderPlug.LAST_INSTANCE.increment()) + self.assertEqual(1, AdderPlug.LAST_INSTANCE.increment()) threading.Thread(target=_delay_then_update).start() start_time = time.time() - self.assertEquals({'number': 1}, self.plug_manager.wait_for_plug_update( + self.assertEqual({'number': 1}, self.plug_manager.wait_for_plug_update( 'plugs_test.AdderPlug', update, 5)) self.assertGreater(time.time() - start_time, .2) diff --git a/test/util/conf_test.py b/test/util/conf_test.py index 670b0e7fe..f1606d40f 100644 --- a/test/util/conf_test.py +++ b/test/util/conf_test.py @@ -64,45 +64,45 @@ def test_yaml_config(self): with open(self.YAML_FILENAME, 'rb') as yamlfile: conf._flags.config_file = yamlfile conf.reset() - self.assertEquals('yaml_test_value', conf.yaml_test_key) + self.assertEqual('yaml_test_value', conf.yaml_test_key) def test_load_override(self): conf.load(overridden_key='overridden_value') conf.load(overridden_key='new_value') - self.assertEquals('new_value', conf.overridden_key) + self.assertEqual('new_value', conf.overridden_key) def test_load_no_override(self): conf.load(overridden_key='overridden_value') conf.load(overridden_key='new_value', _override=False) - self.assertEquals('overridden_value', conf.overridden_key) + self.assertEqual('overridden_value', conf.overridden_key) def test_load_from_dict(self): conf.load_from_dict({'overridden_key': 'new_value'}) - self.assertEquals('new_value', conf.overridden_key) + self.assertEqual('new_value', conf.overridden_key) def test_defaults(self): - self.assertEquals('default', conf.string_default) + self.assertEqual('default', conf.string_default) self.assertIsNone(conf.none_default) with self.assertRaises(conf.UnsetKeyError): conf.no_default def test_flag_values(self): - self.assertEquals('flag_value', conf.flag_key) - self.assertEquals('other_value', conf.other_flag) + self.assertEqual('flag_value', conf.flag_key) + self.assertEqual('other_value', conf.other_flag) # Make sure flag value takes precedence, even if a value is loaded. conf.load(flag_key='loaded_value') - self.assertEquals('flag_value', conf.flag_key) + self.assertEqual('flag_value', conf.flag_key) def test_non_str_flag_values(self): - self.assertEquals(True, conf.true_value) - self.assertEquals(100, conf.num_value) + self.assertEqual(True, conf.true_value) + self.assertEqual(100, conf.num_value) # Make sure flag value takes precedence, even if a value is loaded. conf.load(flag_key='loaded_value') - self.assertEquals(True, conf.true_value) + self.assertEqual(True, conf.true_value) def test_as_dict(self): conf.load(station_id='station_id') - self.assertEquals({ + self.assertEqual({ 'flag_key': 'flag_value', 'true_value': True, 'num_value': 100, @@ -162,27 +162,27 @@ def test_save_and_restore(self): @conf.save_and_restore def modifies_conf(): conf.load(string_default='modified') - self.assertEquals('modified', conf.string_default) + self.assertEqual('modified', conf.string_default) - self.assertEquals('default', conf.string_default) + self.assertEqual('default', conf.string_default) modifies_conf() - self.assertEquals('default', conf.string_default) + self.assertEqual('default', conf.string_default) def test_save_and_restore_kwargs(self): @conf.save_and_restore(string_default='modified') def modifies_conf(): - self.assertEquals('modified', conf.string_default) + self.assertEqual('modified', conf.string_default) - self.assertEquals('default', conf.string_default) + self.assertEqual('default', conf.string_default) modifies_conf() - self.assertEquals('default', conf.string_default) + self.assertEqual('default', conf.string_default) def test_inject_positional_args(self): @conf.inject_positional_args def test_function(string_default, no_default, not_declared): - self.assertEquals('default', string_default) - self.assertEquals('passed_value', no_default) - self.assertEquals('not_declared', not_declared) + self.assertEqual('default', string_default) + self.assertEqual('passed_value', no_default) + self.assertEqual('not_declared', not_declared) test_function(no_default='passed_value', not_declared='not_declared') @@ -190,9 +190,9 @@ def test_inject_positional_args_overrides(self): @conf.inject_positional_args def test_function(string_default, none_default='new_default'): # Make sure when we pass a kwarg, it overrides the config value. - self.assertEquals('overridden', string_default) + self.assertEqual('overridden', string_default) # Make sure kwargs don't come from config, only positional args. - self.assertEquals('new_default', none_default) + self.assertEqual('new_default', none_default) test_function(string_default='overridden') @@ -203,4 +203,4 @@ def __init__(self, string_default): self.string_default = string_default instance = test_class() - self.assertEquals('default', instance.string_default) + self.assertEqual('default', instance.string_default) diff --git a/test/util/data_test.py b/test/util/data_test.py index cfc97d007..74e5d3577 100644 --- a/test/util/data_test.py +++ b/test/util/data_test.py @@ -15,7 +15,9 @@ import unittest import mock +from builtins import int from openhtf.util import data +from past.builtins import long class TestData(unittest.TestCase): @@ -28,7 +30,7 @@ class FloatSubclass(float): 'list': [10], 'tuple': (10,), 'str': '10', - 'unicode': u'10', + 'unicode': '10', 'int': 2 ** 40, 'float': 10.0, 'long': 2 ** 80, @@ -39,13 +41,14 @@ class FloatSubclass(float): } converted = data.convert_to_base_types(example_data) + self.assertIs(type(converted['list']), list) self.assertIs(type(converted['tuple']), tuple) self.assertIs(type(converted['str']), str) - self.assertIs(type(converted['unicode']), unicode) - self.assertIs(type(converted['int']), int) + self.assertIs(type(converted['unicode']), str) + assert isinstance(converted['int'], int) self.assertIs(type(converted['float']), float) - self.assertIs(type(converted['long']), long) + assert isinstance(converted['long'], long) self.assertIs(type(converted['bool']), bool) self.assertIs(converted['none'], None) self.assertIs(type(converted['complex']), str) diff --git a/test/util/functions_test.py b/test/util/functions_test.py index 444b4e9e6..a27075fde 100644 --- a/test/util/functions_test.py +++ b/test/util/functions_test.py @@ -64,7 +64,7 @@ def testCallAtMostEvery(self, mock_time): @functions.call_at_most_every(5) def CallOnceEveryFiveSeconds(): call_times.append(mock_time.time()) - for _ in xrange(100): + for _ in range(100): CallOnceEveryFiveSeconds() # Each call takes "6 seconds", so we get call times up to 600. - self.assertEquals(range(2, 600, 6), call_times) + self.assertEqual(list(range(2, 600, 6)), call_times) diff --git a/test/util/logs_test.py b/test/util/logs_test.py index e3819f77d..95177d5b9 100644 --- a/test/util/logs_test.py +++ b/test/util/logs_test.py @@ -23,7 +23,7 @@ class TestLogs(unittest.TestCase): def test_log_once(self): mock_log = mock.Mock() - for _ in xrange(10): + for _ in range(10): logs.log_once(mock_log, 'Message 1', 'arg1') assert mock_log.call_count == 1 diff --git a/test/util/test_test.py b/test/util/test_test.py index beb999394..c839380ff 100644 --- a/test/util/test_test.py +++ b/test/util/test_test.py @@ -80,7 +80,7 @@ def test_patch_plugs_phase(self, mock_plug): mock_plug.do_stuff.assert_called_with('stuff_args') self.assertPhaseContinue(phase_record) - self.assertEquals('test_phase', phase_record.name) + self.assertEqual('test_phase', phase_record.name) self.assertMeasured(phase_record, 'test_measurement', 0xBEEF) self.assertMeasured(phase_record, 'othr_measurement', 0xDEAD) self.assertMeasurementPass(phase_record, 'passes') diff --git a/test/util/validators_test.py b/test/util/validators_test.py index df1cd8760..675d8508e 100644 --- a/test/util/validators_test.py +++ b/test/util/validators_test.py @@ -2,17 +2,19 @@ import copy import decimal +import six import unittest +from builtins import int from openhtf.util import validators class TestInRange(unittest.TestCase): def test_raises_if_invalid_arguments(self): - with self.assertRaisesRegexp(ValueError, 'Must specify minimum'): + with six.assertRaisesRegex(self, ValueError, 'Must specify minimum'): validators.InRange() - with self.assertRaisesRegexp(ValueError, 'Minimum cannot be greater'): + with six.assertRaisesRegex(self, ValueError, 'Minimum cannot be greater'): validators.InRange(minimum=10, maximum=0) def test_invalidates_non_numbers(self): @@ -84,7 +86,7 @@ def test_comparable_with_equivalent_equals_validator(self): class TestEqualsFactory(unittest.TestCase): def test_with_numbers(self): - for expected in [1, 1.0, decimal.Decimal(1), 1L]: + for expected in [1, 1.0, decimal.Decimal(1), int(1)]: number_validator = validators.equals(expected) self.assertTrue(number_validator(expected)) self.assertFalse(number_validator(0)) @@ -108,7 +110,7 @@ class MyType(object): class TestWithinPercent(unittest.TestCase): def test_raises_for_negative_percentage(self): - with self.assertRaisesRegexp(ValueError, 'percent argument is'): + with six.assertRaisesRegex(self, ValueError, 'percent argument is'): validators.WithinPercent(expected=100, percent=-1) def test_within_percent_less_than_one_hundred(self):