From caa0f504fc455f181064fdaf200cc03193737824 Mon Sep 17 00:00:00 2001 From: Matthew Treinish Date: Tue, 2 Apr 2019 13:35:06 -0400 Subject: [PATCH 01/19] Update package metadata for python2 removal Now that python2 isn't supported anymore we shouldn't advertise that it is supported in the package metadata anymore. This commit removes the trove classifiers indicated python2 support and sets the minimum python version at 3.5. --- setup.cfg | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/setup.cfg b/setup.cfg index 5802826b..7aad99b4 100644 --- a/setup.cfg +++ b/setup.cfg @@ -14,8 +14,6 @@ classifier = License :: OSI Approved :: Apache Software License Operating System :: OS Independent Programming Language :: Python - Programming Language :: Python :: 2 - Programming Language :: Python :: 2.7 Programming Language :: Python :: 3 Programming Language :: Python :: 3.5 Programming Language :: Python :: 3.6 @@ -27,7 +25,7 @@ project_urls = Documentation = https://stestr.readthedocs.io Source Code = https://github.com/mtreinish/stestr Bug Tracker = https://github.com/mtreinish/stestr/issues -requires-python = >=2.7 +requires-python = >=3.5 [files] packages = From e2d2fab911a5e696f1092560342aa26b91cbc5ff Mon Sep 17 00:00:00 2001 From: Matthew Treinish Date: Tue, 14 Jan 2020 23:04:02 -0500 Subject: [PATCH 02/19] Remove sys.version switches for python2.7 --- stestr/cli.py | 6 ------ stestr/subunit_runner/run.py | 12 +++--------- 2 files changed, 3 insertions(+), 15 deletions(-) diff --git a/stestr/cli.py b/stestr/cli.py index 598ea94b..58292f50 100644 --- a/stestr/cli.py +++ b/stestr/cli.py @@ -108,12 +108,6 @@ def _set_common_opts(self, parser): def main(argv=sys.argv[1:]): - if sys.version_info[:2] == (2, 7): - msg = ( - "Python 2.7 will reach the end of its life on January 1st, 2020. " - "Support for using python 2.7 with stestr will be removed in the " - "3.0.0 release in early 2020") - warnings.warn(msg, DeprecationWarning, stacklevel=2) cli = StestrCLI() return cli.run(argv) diff --git a/stestr/subunit_runner/run.py b/stestr/subunit_runner/run.py index 95c9cfea..93fae583 100644 --- a/stestr/subunit_runner/run.py +++ b/stestr/subunit_runner/run.py @@ -84,15 +84,9 @@ def _list(self, test): def main(): runner = SubunitTestRunner - if sys.version_info[0] >= 3 and sys.version_info[1] >= 5: - program.TestProgram( - module=None, argv=sys.argv, - testRunner=partial(runner, stdout=sys.stdout)) - else: - from testtools import run as testtools_run - testtools_run.TestProgram(module=None, argv=sys.argv, - testRunner=runner, - stdout=sys.stdout, exit=False) + program.TestProgram( + module=None, argv=sys.argv, + testRunner=partial(runner, stdout=sys.stdout)) if __name__ == '__main__': From 000fa0a2f87ae8af571e1a2def82b0b4215cfd7e Mon Sep 17 00:00:00 2001 From: Matthew Treinish Date: Tue, 14 Jan 2020 23:05:44 -0500 Subject: [PATCH 03/19] Fix typo bug in list_tests() error code --- stestr/test_processor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stestr/test_processor.py b/stestr/test_processor.py index d570f4f9..9c1b92a2 100644 --- a/stestr/test_processor.py +++ b/stestr/test_processor.py @@ -217,7 +217,7 @@ def list_tests(self): sys.stdout.write(out) if err: if six.PY3: - sys.stdout.write(out.decode('utf8')) + sys.stderr.write(err.decode('utf8')) else: sys.stderr.write(err) sys.stdout.write("\n" + "=" * 80 + "\n" From 6680297ec9d9a7905ea3304cc5c82043125911c2 Mon Sep 17 00:00:00 2001 From: Matthew Treinish Date: Tue, 14 Jan 2020 23:14:53 -0500 Subject: [PATCH 04/19] Remove six usage from stestr code This commit removes six from all the stestr code except for tests. As of this commit six is still used in the tests, which will be removed in a follow-on commit. --- stestr/commands/run.py | 5 ++--- stestr/config_file.py | 2 +- stestr/output.py | 19 +++++++++---------- stestr/repository/sql.py | 5 ++--- stestr/results.py | 9 ++++----- stestr/test_processor.py | 16 +++++----------- stestr/testlist.py | 8 ++++---- stestr/utils.py | 4 ++-- 8 files changed, 29 insertions(+), 39 deletions(-) diff --git a/stestr/commands/run.py b/stestr/commands/run.py index 9664c639..f00465d4 100644 --- a/stestr/commands/run.py +++ b/stestr/commands/run.py @@ -21,7 +21,6 @@ import warnings from cliff import command -import six import subunit import testtools @@ -46,7 +45,7 @@ def _to_int(possible, default=0, out=sys.stderr): i = default msg = ('Unable to convert "%s" to an integer. Using %d.\n' % (possible, default)) - out.write(six.text_type(msg)) + out.write(str(msg)) return i @@ -390,7 +389,7 @@ def run_command(config='.stestr.conf', repo_type='file', return 2 if combine: latest_id = repo.latest_id() - combine_id = six.text_type(latest_id) + combine_id = str(latest_id) if no_discover and pdb: msg = ("--no-discover and --pdb are mutually exclusive options, " "only specify one at a time") diff --git a/stestr/config_file.py b/stestr/config_file.py index 733ae084..b7218c01 100644 --- a/stestr/config_file.py +++ b/stestr/config_file.py @@ -14,7 +14,7 @@ import re import sys -from six.moves import configparser +import configparser from stestr.repository import util from stestr import test_processor diff --git a/stestr/output.py b/stestr/output.py index 0f7e3368..d3e867cf 100644 --- a/stestr/output.py +++ b/stestr/output.py @@ -12,7 +12,6 @@ import sys -import six import subunit import testtools @@ -62,7 +61,7 @@ def show_row(row): outputs.append(' ') for row in contents[1:]: show_row(row) - output.write(six.text_type('').join(outputs)) + output.write(''.join(outputs)) def output_tests(tests, output=sys.stdout): @@ -75,8 +74,8 @@ def output_tests(tests, output=sys.stdout): for test in tests: id_str = test.id() - output.write(six.text_type(id_str)) - output.write(six.text_type('\n')) + output.write(str(id_str)) + output.write('\n') def make_result(get_id, output=sys.stdout): @@ -135,7 +134,7 @@ def output_summary(successful, tests, tests_delta, time, time_delta, values, values_strings.append(value_str) a(', '.join(values_strings)) a(')') - output.write(six.text_type(''.join(summary)) + six.text_type('\n')) + output.write(''.join(summary) + '\n') def output_stream(stream, output=sys.stdout): @@ -169,20 +168,20 @@ def __init__(self, process): self.proc = process self.done = False self.source = self.proc.stdout - self.lastoutput = six.binary_type(('\n').encode('utf8')[0]) + self.lastoutput = bytes(('\n').encode('utf8')[0]) def _append_return_code_as_test(self): if self.done is True: return - self.source = six.BytesIO() + self.source = io.BytesIO() returncode = self.proc.wait() if returncode != 0: - if self.lastoutput != six.binary_type(('\n').encode('utf8')[0]): + if self.lastoutput != bytes(('\n').encode('utf8')[0]): # Subunit V1 is line orientated, it has to start on a fresh # line. V2 needs to start on any fresh utf8 character border # - which is not guaranteed in an arbitrary stream endpoint, so # injecting a \n gives us such a guarantee. - self.source.write(six.binary_type('\n')) + self.source.write(bytes('\n')) stream = subunit.StreamResultToBytes(self.source) stream.status(test_id='process-returncode', test_status='fail', file_name='traceback', @@ -194,7 +193,7 @@ def _append_return_code_as_test(self): def read(self, count=-1): if count == 0: - return six.text_type('') + return '' result = self.source.read(count) if result: self.lastoutput = result[-1] diff --git a/stestr/repository/sql.py b/stestr/repository/sql.py index 419c6e26..e286d392 100644 --- a/stestr/repository/sql.py +++ b/stestr/repository/sql.py @@ -20,7 +20,6 @@ import subprocess import sys -import six import sqlalchemy from sqlalchemy import orm import subunit.v2 @@ -55,8 +54,8 @@ def initialise(klass, url): stdout=subprocess.PIPE, stderr=subprocess.PIPE) out, err = proc.communicate() - sys.stdout.write(six.text_type(out)) - sys.stderr.write(six.text_type(err)) + sys.stdout.write(str(out)) + sys.stderr.write(str(err)) return result diff --git a/stestr/results.py b/stestr/results.py index 5e630271..33d1831a 100644 --- a/stestr/results.py +++ b/stestr/results.py @@ -10,7 +10,6 @@ # License for the specific language governing permissions and limitations # under the License. -import six import subunit import testtools @@ -98,10 +97,10 @@ def _format_error(self, label, test, error_text, test_tags=None): test_tags = test_tags or () tags = ' '.join(test_tags) if tags: - tags = six.text_type(('tags: %s\n' % tags)) - return six.text_type(''.join([ + tags = str(('tags: %s\n' % tags)) + return str(''.join([ self.sep1, - six.text_type('%s: %s\n' % (label, test.id())), + str('%s: %s\n' % (label, test.id())), tags, self.sep2, error_text, @@ -114,7 +113,7 @@ def status(self, **kwargs): test_tags = kwargs.get('test_tags') if test_status == 'fail': self.stream.write( - self._format_error(six.text_type('FAIL'), + self._format_error(str('FAIL'), *(self._summary.errors[-1]), test_tags=test_tags)) if test_status not in self.filterable_states: diff --git a/stestr/test_processor.py b/stestr/test_processor.py index 9c1b92a2..628ae971 100644 --- a/stestr/test_processor.py +++ b/stestr/test_processor.py @@ -10,6 +10,7 @@ # License for the specific language governing permissions and limitations # under the License. +import io import os import re import signal @@ -18,7 +19,6 @@ import tempfile import fixtures -import six from subunit import v2 from stestr import results @@ -205,21 +205,15 @@ def list_tests(self): sys.stdout.write("\n=========================\n" "Failures during discovery" "\n=========================\n") - new_out = six.BytesIO() + new_out = io.BytesIO() v2.ByteStreamToStreamResult( - six.BytesIO(out), 'stdout').run( + io.BytesIO(out), 'stdout').run( results.CatFiles(new_out)) out = new_out.getvalue() if out: - if six.PY3: - sys.stdout.write(out.decode('utf8')) - else: - sys.stdout.write(out) + sys.stdout.write(out.decode('utf8')) if err: - if six.PY3: - sys.stderr.write(err.decode('utf8')) - else: - sys.stderr.write(err) + sys.stderr.write(err.decode('utf8')) sys.stdout.write("\n" + "=" * 80 + "\n" "The above traceback was encountered during " "test discovery which imports all the found test" diff --git a/stestr/testlist.py b/stestr/testlist.py index a68052cb..53eddf1a 100644 --- a/stestr/testlist.py +++ b/stestr/testlist.py @@ -12,7 +12,7 @@ """Handling of lists of tests - common code to --load-list etc.""" -import six +import io from extras import try_import bytestream_to_streamresult = try_import('subunit.ByteStreamToStreamResult') @@ -26,7 +26,7 @@ def write_list(stream, test_ids): :param test_ids: An iterable of test ids. """ # May need utf8 explicitly? - stream.write(six.binary_type(( + stream.write(bytes(( '\n'.join(list(test_ids) + [''])).encode('utf8'))) @@ -46,11 +46,11 @@ def parse_enumeration(enumeration_bytes): def _v1(list_bytes): return [id.strip() for id in list_bytes.decode('utf8').split( - six.text_type('\n')) if id.strip()] + str('\n')) if id.strip()] def _v2(list_bytes): - parser = bytestream_to_streamresult(six.BytesIO(list_bytes), + parser = bytestream_to_streamresult(io.BytesIO(list_bytes), non_subunit_name='stdout') result = stream_result() parser.run(result) diff --git a/stestr/utils.py b/stestr/utils.py index 261bf892..b609e0f3 100644 --- a/stestr/utils.py +++ b/stestr/utils.py @@ -10,7 +10,7 @@ # License for the specific language governing permissions and limitations # under the License. -import six +import io from stestr import output @@ -70,7 +70,7 @@ def _iter_internal_streams(input_streams, stream_type): elif getattr(stream_value, 'read', None): yield stream_value else: - yield six.BytesIO(stream_value) + yield io.BytesIO(stream_value) def iter_streams(input_streams, stream_type): From e7ae11cbc847bb10c8fc16e285755f8aa77e3d5b Mon Sep 17 00:00:00 2001 From: Matthew Treinish Date: Tue, 14 Jan 2020 23:16:53 -0500 Subject: [PATCH 05/19] Remove 2.7 ci jobs --- .travis.yml | 2 -- azure-pipelines.yml | 4 ---- 2 files changed, 6 deletions(-) diff --git a/.travis.yml b/.travis.yml index b0da764c..4fe1a688 100644 --- a/.travis.yml +++ b/.travis.yml @@ -20,8 +20,6 @@ matrix: env: TOXENV=pep8 - python: "3.6" env: TOXENV=docs - - python: "2.7" - env: TOXENV=py27 - if: tag IS present python: "3.6" env: diff --git a/azure-pipelines.yml b/azure-pipelines.yml index d8ead408..80f866a9 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -11,8 +11,6 @@ jobs: pool: {vmImage: 'vs2017-win2016'} strategy: matrix: - Python27: - python.version: '2.7' Python35: python.version: '3.5' Python36: @@ -42,8 +40,6 @@ jobs: pool: {vmImage: 'macOS-10.14'} strategy: matrix: - Python27: - python.version: '2.7' Python35: python.version: '3.5' Python36: From 75387ec16dd4e4cf0ae14176eaf1314036bf02d6 Mon Sep 17 00:00:00 2001 From: Matthew Treinish Date: Tue, 14 Jan 2020 23:25:23 -0500 Subject: [PATCH 06/19] Fix import issues --- stestr/cli.py | 1 - stestr/output.py | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/stestr/cli.py b/stestr/cli.py index 58292f50..402b5e6f 100644 --- a/stestr/cli.py +++ b/stestr/cli.py @@ -11,7 +11,6 @@ # under the License. import sys -import warnings from cliff import app from cliff import commandmanager diff --git a/stestr/output.py b/stestr/output.py index d3e867cf..21c7b8fb 100644 --- a/stestr/output.py +++ b/stestr/output.py @@ -10,6 +10,7 @@ # License for the specific language governing permissions and limitations # under the License. +import io import sys import subunit From 4375375dad4157e7c14dcb2ab5220bbc831f4243 Mon Sep 17 00:00:00 2001 From: Matthew Treinish Date: Tue, 21 Jan 2020 16:14:21 -0500 Subject: [PATCH 07/19] Run pyupgrade on repo This commit is the result of running pyupgrade [1] on the repo. pyupgrade automates the syntax used in the repo to be native python3. --- stestr/colorizer.py | 2 +- stestr/config_file.py | 2 +- stestr/output.py | 12 ++++++------ stestr/repository/sql.py | 2 +- stestr/results.py | 6 +++--- stestr/subunit_runner/program.py | 6 +++--- stestr/subunit_trace.py | 14 +++++++------- stestr/tests/test_bisect_tests.py | 2 +- stestr/tests/test_return_codes.py | 4 ++-- stestr/tests/test_selection.py | 4 ++-- stestr/tests/test_user_config_return_codes.py | 2 +- stestr/user_config.py | 2 +- 12 files changed, 29 insertions(+), 29 deletions(-) diff --git a/stestr/colorizer.py b/stestr/colorizer.py index 8ecec358..ae74d8e4 100644 --- a/stestr/colorizer.py +++ b/stestr/colorizer.py @@ -82,7 +82,7 @@ def write(self, text, color): @param color: A string label for a color. e.g. 'red', 'white'. """ color = self._colors[color] - self.stream.write('\x1b[%s;1m%s\x1b[0m' % (color, text)) + self.stream.write('\x1b[{};1m{}\x1b[0m'.format(color, text)) class NullColorizer(object): diff --git a/stestr/config_file.py b/stestr/config_file.py index b7218c01..170087ab 100644 --- a/stestr/config_file.py +++ b/stestr/config_file.py @@ -106,7 +106,7 @@ def get_run_command(self, test_ids=None, regexes=None, test_path = self.parser.get('DEFAULT', 'test_path') elif not test_path: sys.exit("No test_path can be found in either the command line " - "options nor in the specified config file {0}. Please " + "options nor in the specified config file {}. Please " "specify a test path either in the config file or via " "the --test-path argument".format(self.config_file)) if not top_dir and self.parser.has_option('DEFAULT', 'top_dir'): diff --git a/stestr/output.py b/stestr/output.py index 21c7b8fb..fa385c93 100644 --- a/stestr/output.py +++ b/stestr/output.py @@ -109,16 +109,16 @@ def output_summary(successful, tests, tests_delta, time, time_delta, values, summary = [] a = summary.append if tests: - a("Ran %s" % (tests,)) + a("Ran {}".format(tests)) if tests_delta: a(" (%+d)" % (tests_delta,)) a(" tests") if time: if not summary: a("Ran tests") - a(" in %0.3fs" % (time,)) + a(" in {:0.3f}s".format(time)) if time_delta: - a(" (%+0.3fs)" % (time_delta,)) + a(" ({:+0.3f}s)".format(time_delta)) if summary: a("\n") if successful: @@ -129,7 +129,7 @@ def output_summary(successful, tests, tests_delta, time, time_delta, values, a(' (') values_strings = [] for name, value, delta in values: - value_str = '%s=%s' % (name, value) + value_str = '{}={}'.format(name, value) if delta: value_str += ' (%+d)' % (delta,) values_strings.append(value_str) @@ -169,7 +169,7 @@ def __init__(self, process): self.proc = process self.done = False self.source = self.proc.stdout - self.lastoutput = bytes(('\n').encode('utf8')[0]) + self.lastoutput = bytes((b'\n')[0]) def _append_return_code_as_test(self): if self.done is True: @@ -177,7 +177,7 @@ def _append_return_code_as_test(self): self.source = io.BytesIO() returncode = self.proc.wait() if returncode != 0: - if self.lastoutput != bytes(('\n').encode('utf8')[0]): + if self.lastoutput != bytes((b'\n')[0]): # Subunit V1 is line orientated, it has to start on a fresh # line. V2 needs to start on any fresh utf8 character border # - which is not guaranteed in an arbitrary stream endpoint, so diff --git a/stestr/repository/sql.py b/stestr/repository/sql.py index e286d392..43004a9c 100644 --- a/stestr/repository/sql.py +++ b/stestr/repository/sql.py @@ -254,7 +254,7 @@ def _update_test(self, test_dict, session, start_time, stop_time): return db_test def _get_attrs(self, test_id): - attr_regex = re.compile('\[(.*)\]') + attr_regex = re.compile(r'\[(.*)\]') matches = attr_regex.search(test_id) attrs = None if matches: diff --git a/stestr/results.py b/stestr/results.py index 33d1831a..85038cac 100644 --- a/stestr/results.py +++ b/stestr/results.py @@ -90,17 +90,17 @@ def __init__(self, get_id, stream, previous_run=None): self.stream = testtools.compat.unicode_output_stream(stream) self.sep1 = testtools.compat._u('=' * 70 + '\n') self.sep2 = testtools.compat._u('-' * 70 + '\n') - self.filterable_states = set(['success', 'uxsuccess', 'xfail', 'skip']) + self.filterable_states = {'success', 'uxsuccess', 'xfail', 'skip'} self.get_id = get_id def _format_error(self, label, test, error_text, test_tags=None): test_tags = test_tags or () tags = ' '.join(test_tags) if tags: - tags = str(('tags: %s\n' % tags)) + tags = str('tags: %s\n' % tags) return str(''.join([ self.sep1, - str('%s: %s\n' % (label, test.id())), + str('{}: {}\n'.format(label, test.id())), tags, self.sep2, error_text, diff --git a/stestr/subunit_runner/program.py b/stestr/subunit_runner/program.py index 92a9512b..c7aef398 100644 --- a/stestr/subunit_runner/program.py +++ b/stestr/subunit_runner/program.py @@ -102,11 +102,11 @@ def list_test(test): :return: A tuple of test ids that would run and error strings describing things that failed to import. """ - unittest_import_strs = set([ + unittest_import_strs = { 'unittest2.loader.ModuleImportFailure.', 'unittest.loader.ModuleImportFailure.', 'discover.ModuleImportFailure.' - ]) + } test_ids = [] errors = [] for test in iterate_tests(test): @@ -178,7 +178,7 @@ def __init__(self, module='__main__', defaultTest=None, argv=None, lines = source.readlines() finally: source.close() - test_ids = set(line.strip().decode('utf-8') for line in lines) + test_ids = {line.strip().decode('utf-8') for line in lines} self.test = filter_by_ids(self.test, test_ids) # XXX: Local edit (see http://bugs.python.org/issue22860) if not self.listtests: diff --git a/stestr/subunit_trace.py b/stestr/subunit_trace.py index d0033d3b..baaf4412 100644 --- a/stestr/subunit_trace.py +++ b/stestr/subunit_trace.py @@ -119,7 +119,7 @@ def print_attachments(stream, test, all_channels=False): detail.content_type.type = 'text' if (all_channels or name in channels) and detail.as_text(): title = "Captured %s:" % name - stream.write("\n%s\n%s\n" % (title, ('~' * len(title)))) + stream.write("\n{}\n{}\n".format(title, ('~' * len(title)))) # indent attachment lines 4 spaces to make them visually # offset for line in detail.as_text().split('\n'): @@ -184,7 +184,7 @@ def show_outcome(stream, test, print_failures=False, failonly=False, if abbreviate: color.write('F', 'red') else: - stream.write('{%s} %s [%s] ... ' % ( + stream.write('{{{}}} {} [{}] ... '.format( worker, name, duration)) color.write('FAILED', 'red') stream.write('\n') @@ -195,7 +195,7 @@ def show_outcome(stream, test, print_failures=False, failonly=False, if abbreviate: color.write('.', 'green') else: - out_string = '{%s} %s [%s' % (worker, name, duration) + out_string = '{{{}}} {} [{}'.format(worker, name, duration) perc_diff = find_test_run_time_diff(test['id'], duration) if enable_diff: if perc_diff and abs(perc_diff) >= abs(float(threshold)): @@ -218,7 +218,7 @@ def show_outcome(stream, test, print_failures=False, failonly=False, reason = test['details'].get('reason', '') if reason: reason = ': ' + reason.as_text() - stream.write('{%s} %s ... ' % ( + stream.write('{{{}}} {} ... '.format( worker, name)) color.write('SKIPPED', 'blue') stream.write('%s' % (reason)) @@ -227,7 +227,7 @@ def show_outcome(stream, test, print_failures=False, failonly=False, if abbreviate: stream.write('%s' % test['status'][0]) else: - stream.write('{%s} %s [%s] ... %s\n' % ( + stream.write('{{{}}} {} [{}] ... {}\n'.format( worker, name, duration, test['status'])) if not print_failures: print_attachments(stream, test, all_channels=True) @@ -289,7 +289,7 @@ def worker_stats(worker): def print_summary(stream, elapsed_time): stream.write("\n======\nTotals\n======\n") - stream.write("Ran: %s tests in %.4f sec.\n" % ( + stream.write("Ran: {} tests in {:.4f} sec.\n".format( count_tests('status', '.*'), total_seconds(elapsed_time))) stream.write(" - Passed: %s\n" % count_tests('status', '^success$')) stream.write(" - Skipped: %s\n" % count_tests('status', '^skip$')) @@ -309,7 +309,7 @@ def print_summary(stream, elapsed_time): " - WARNING: missing Worker %s!\n" % w) else: num, time = worker_stats(w) - out_str = " - Worker %s (%s tests) => %s" % (w, num, time) + out_str = " - Worker {} ({} tests) => {}".format(w, num, time) if time.isdigit(): out_str += 's' out_str += '\n' diff --git a/stestr/tests/test_bisect_tests.py b/stestr/tests/test_bisect_tests.py index adb0f6b4..52c333a6 100644 --- a/stestr/tests/test_bisect_tests.py +++ b/stestr/tests/test_bisect_tests.py @@ -80,7 +80,7 @@ class FakeNoFailing(FakeTestRun): def __init__(self, failure=True): # Generate a subunit stream - stream_buf = io.BytesIO(six.binary_type(''.encode('utf-8'))) + stream_buf = io.BytesIO(six.binary_type(b'')) self._content = stream_buf.getvalue() self.id = None diff --git a/stestr/tests/test_return_codes.py b/stestr/tests/test_return_codes.py index 563074cb..18fd2109 100644 --- a/stestr/tests/test_return_codes.py +++ b/stestr/tests/test_return_codes.py @@ -95,7 +95,7 @@ def assertRunExit(self, cmd, expected, subunit=False, stdin=None): if not subunit: self.assertEqual( p.returncode, expected, - "Stdout: %s; Stderr: %s" % (out, err)) + "Stdout: {}; Stderr: {}".format(out, err)) return (out, err) else: self.assertEqual(p.returncode, expected, @@ -249,7 +249,7 @@ def test_combine_results(self): test_count_split = stdout.split(' ') test_count = test_count_split[1] test_count = int(test_count) - id_regex = re.compile('\(id=(.*?)\)') + id_regex = re.compile(r'\(id=(.*?)\)') test_id = id_regex.search(stdout).group(0) self.assertRunExit('stestr run --combine passing', 0) combine_stdout = self._get_cmd_stdout( diff --git a/stestr/tests/test_selection.py b/stestr/tests/test_selection.py index b1214636..527ca5c5 100644 --- a/stestr/tests/test_selection.py +++ b/stestr/tests/test_selection.py @@ -108,7 +108,7 @@ def test_whitelist(self): result = selection.construct_list(test_lists, whitelist_file='file') self.assertEqual(set(result), - set(('fake_test1[tg]', 'fake_test2[tg]'))) + {'fake_test1[tg]', 'fake_test2[tg]'}) def test_whitelist_invalid_regex(self): whitelist_file = six.StringIO() @@ -133,7 +133,7 @@ def test_whitelist_blacklist_re(self): result = selection.construct_list(test_lists, 'black_file', 'white_file', ['foo']) self.assertEqual(set(result), - set(('fake_test1[tg]', 'fake_test3[tg,foo]'))) + {'fake_test1[tg]', 'fake_test3[tg,foo]'}) def test_overlapping_black_regex(self): diff --git a/stestr/tests/test_user_config_return_codes.py b/stestr/tests/test_user_config_return_codes.py index 95d4a3bc..0e2513f7 100644 --- a/stestr/tests/test_user_config_return_codes.py +++ b/stestr/tests/test_user_config_return_codes.py @@ -77,7 +77,7 @@ def assertRunExit(self, cmd, expected, subunit=False, stdin=None): if not subunit: self.assertEqual( p.returncode, expected, - "Stdout: %s; Stderr: %s" % (out, err)) + "Stdout: {}; Stderr: {}".format(out, err)) return (out, err) else: self.assertEqual(p.returncode, expected, diff --git a/stestr/user_config.py b/stestr/user_config.py index b370b1db..ef8d7ce1 100644 --- a/stestr/user_config.py +++ b/stestr/user_config.py @@ -75,7 +75,7 @@ def __init__(self, path): try: self.schema(self.config) except vp.MultipleInvalid as e: - msg = 'Provided user config file %s is invalid because:\n%s' % ( + msg = 'Provided user config file {} is invalid because:\n{}'.format( path, str(e)) sys.exit(msg) From 36b05c97ef17244326ffb90e45f2fa2d9f5c1256 Mon Sep 17 00:00:00 2001 From: Matthew Treinish Date: Tue, 21 Jan 2020 16:16:29 -0500 Subject: [PATCH 08/19] Remove outdated tox envs --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index d4cdf3a9..82c6d11c 100644 --- a/tox.ini +++ b/tox.ini @@ -1,6 +1,6 @@ [tox] minversion = 1.6 -envlist = py38,py37,py36,py35,py34,py27,pep8 +envlist = py38,py37,py36,py35,pep8 skipsdist = True [testenv] From 97fe81d17e116def021bf49510d4bf962e961545 Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Tue, 24 Dec 2019 15:54:10 +0000 Subject: [PATCH 09/19] Treat bytes and strings differently The 'as_text()' helper function for the 'testtools.content.Content' class fails if it attempts to decode a binary result. The fact that we have a binary result is a bug in itself but we need to log what we're getting to help debug this. Start ignoring these by default but add an option, '--show-binary-attachments', to allow us to emit these if we want it for debug purposes. Signed-off-by: Stephen Finucane Related-bug: #1813147 --- stestr/commands/last.py | 20 ++++++++++++++------ stestr/commands/load.py | 21 +++++++++++++++------ stestr/commands/run.py | 30 ++++++++++++++++++++++-------- stestr/subunit_trace.py | 37 ++++++++++++++++++++++++------------- 4 files changed, 75 insertions(+), 33 deletions(-) diff --git a/stestr/commands/last.py b/stestr/commands/last.py index f4e5abd1..80a58b16 100644 --- a/stestr/commands/last.py +++ b/stestr/commands/last.py @@ -65,6 +65,10 @@ def get_parser(self, prog_name): dest='all_attachments', help='If set print all text attachment contents on' ' a successful test execution') + parser.add_argument('--show-binary-attachments', action='store_true', + dest='show_binary_attachments', + help='If set, show non-text attachments. This is ' + 'generally only useful for debug purposes.') return parser def take_action(self, parsed_args): @@ -108,12 +112,13 @@ def take_action(self, parsed_args): repo_url=self.app_args.repo_url, subunit_out=args.subunit, pretty_out=pretty_out, color=color, suppress_attachments=suppress_attachments, - all_attachments=all_attachments) + all_attachments=all_attachments, + show_binary_attachments=args.show_binary_attachments) def last(repo_type='file', repo_url=None, subunit_out=False, pretty_out=True, color=False, stdout=sys.stdout, suppress_attachments=False, - all_attachments=False): + all_attachments=False, show_binary_attachments=False): """Show the last run loaded into a a repository This function will print the results from the last run in the repository @@ -137,6 +142,8 @@ def last(repo_type='file', repo_url=None, subunit_out=False, pretty_out=True, will not print attachments on successful test execution. :param bool all_attachments: When set true subunit_trace will print all text attachments on successful test execution. + :param bool show_binary_attachments: When set to true, subunit_trace will + print binary attachments in addition to text attachments. :return return_code: The exit code for the command. 0 for success and > 0 for failures. @@ -182,10 +189,11 @@ def last(repo_type='file', repo_url=None, subunit_out=False, pretty_out=True, failed = not results.wasSuccessful(summary) else: stream = latest_run.get_subunit_stream() - failed = subunit_trace.trace(stream, stdout, post_fails=True, - color=color, - suppress_attachments=suppress_attachments, - all_attachments=all_attachments) + failed = subunit_trace.trace( + stream, stdout, post_fails=True, color=color, + suppress_attachments=suppress_attachments, + all_attachments=all_attachments, + show_binary_attachments=show_binary_attachments) if failed: return 1 else: diff --git a/stestr/commands/load.py b/stestr/commands/load.py index a5e0f956..17bc405d 100644 --- a/stestr/commands/load.py +++ b/stestr/commands/load.py @@ -86,6 +86,10 @@ def get_parser(self, prog_name): dest='all_attachments', help='If set print all text attachment contents on' ' a successful test execution') + parser.add_argument('--show-binary-attachments', action='store_true', + dest='show_binary_attachments', + help='If set, show non-text attachments. This is ' + 'generally only useful for debug purposes.') return parser def take_action(self, parsed_args): @@ -134,14 +138,15 @@ def take_action(self, parsed_args): pretty_out=pretty_out, color=color, stdout=stdout, abbreviate=abbreviate, suppress_attachments=suppress_attachments, serial=True, - all_attachments=all_attachments) + all_attachments=all_attachments, + show_binary_attachments=args.show_binary_attachments) def load(force_init=False, in_streams=None, partial=False, subunit_out=False, repo_type='file', repo_url=None, run_id=None, streams=None, pretty_out=False, color=False, stdout=sys.stdout, abbreviate=False, suppress_attachments=False, - serial=False, all_attachments=False): + serial=False, all_attachments=False, show_binary_attachments=False): """Load subunit streams into a repository This function will load subunit streams into the repository. It will @@ -172,6 +177,8 @@ def load(force_init=False, in_streams=None, will not print attachments on successful test execution. :param bool all_attachments: When set true subunit_trace will print all text attachments on successful test execution. + :param bool show_binary_attachments: When set to true, subunit_trace will + print binary attachments in addition to text attachments. :return return_code: The exit code for the command. 0 for success and > 0 for failures. @@ -233,7 +240,8 @@ def make_tests(): stream, non_subunit_name='stdout') result = _load_case(inserter, repo, case, subunit_out, pretty_out, color, stdout, abbreviate, - suppress_attachments, all_attachments) + suppress_attachments, all_attachments, + show_binary_attachments) if result or retval: retval = 1 else: @@ -242,14 +250,14 @@ def make_tests(): case = testtools.ConcurrentStreamTestSuite(make_tests) retval = _load_case(inserter, repo, case, subunit_out, pretty_out, color, stdout, abbreviate, suppress_attachments, - all_attachments) + all_attachments, show_binary_attachments) return retval def _load_case(inserter, repo, case, subunit_out, pretty_out, color, stdout, abbreviate, suppress_attachments, - all_attachments): + all_attachments, show_binary_attachments): if subunit_out: output_result, summary_result = output.make_result(inserter.get_id, output=stdout) @@ -258,7 +266,8 @@ def _load_case(inserter, repo, case, subunit_out, pretty_out, functools.partial(subunit_trace.show_outcome, stdout, enable_color=color, abbreviate=abbreviate, suppress_attachments=suppress_attachments, - all_attachments=all_attachments)) + all_attachments=all_attachments, + show_binary_attachments=show_binary_attachments)) summary_result = testtools.StreamSummary() output_result = testtools.CopyStreamResult([outcomes, summary_result]) output_result = testtools.StreamResultRouter(output_result) diff --git a/stestr/commands/run.py b/stestr/commands/run.py index 9664c639..6c4f7e9d 100644 --- a/stestr/commands/run.py +++ b/stestr/commands/run.py @@ -168,6 +168,10 @@ def get_parser(self, prog_name): dest='all_attachments', help='If set print all text attachment contents on' ' a successful test execution') + parser.add_argument('--show-binary-attachments', action='store_true', + dest='show_binary_attachments', + help='If set, show non-text attachments. This is ' + 'generally only useful for debug purposes.') return parser def take_action(self, parsed_args): @@ -244,7 +248,9 @@ def take_action(self, parsed_args): filters=filters, pretty_out=pretty_out, color=color, stdout=stdout, abbreviate=abbreviate, suppress_attachments=suppress_attachments, - all_attachments=all_attachments, pdb=args.pdb) + all_attachments=all_attachments, + show_binary_attachments=args.show_binary_attachments, + pdb=args.pdb) # Always output slowest test info if requested, regardless of other # test run options @@ -285,7 +291,8 @@ def run_command(config='.stestr.conf', repo_type='file', no_discover=False, random=False, combine=False, filters=None, pretty_out=True, color=False, stdout=sys.stdout, abbreviate=False, suppress_attachments=False, - all_attachments=False, pdb=False): + all_attachments=False, show_binary_attachments=True, + pdb=False): """Function to execute the run command This function implements the run command. It will run the tests specified @@ -348,6 +355,8 @@ def run_command(config='.stestr.conf', repo_type='file', will not print attachments on successful test execution. :param bool all_attachments: When set true subunit_trace will print all text attachments on successful test execution. + :param bool show_binary_attachments: When set to true, subunit_trace will + print binary attachments in addition to text attachments. :param str pdb: Takes in a single test_id to bypasses test discover and just execute the test specified without launching any additional processes. A file name may be used in place of a test name. @@ -430,7 +439,8 @@ def run_tests(): pretty_out=pretty_out, color=color, stdout=stdout, abbreviate=abbreviate, suppress_attachments=suppress_attachments, - all_attachments=all_attachments) + all_attachments=all_attachments, + show_binary_attachments=show_binary_attachments) if not until_failure: return run_tests() @@ -475,7 +485,8 @@ def run_tests(): pretty_out=pretty_out, color=color, stdout=stdout, abbreviate=abbreviate, suppress_attachments=suppress_attachments, - all_attachments=all_attachments) + all_attachments=all_attachments, + show_binary_attachments=show_binary_attachments) if failing or analyze_isolation: ids = _find_failing(repo) @@ -525,7 +536,8 @@ def run_tests(): repo_type=repo_type, repo_url=repo_url, pretty_out=pretty_out, color=color, abbreviate=abbreviate, stdout=stdout, suppress_attachments=suppress_attachments, - all_attachments=all_attachments) + all_attachments=all_attachments, + show_binary_attachments=show_binary_attachments) if run_result > result: result = run_result return result @@ -540,7 +552,8 @@ def run_tests(): stdout=stdout, abbreviate=abbreviate, suppress_attachments=suppress_attachments, - all_attachments=all_attachments) + all_attachments=all_attachments, + show_binary_attachments=show_binary_attachments) else: # Where do we source data about the cause of conflicts. latest_run = repo.get_latest_run() @@ -585,7 +598,7 @@ def _run_tests(cmd, until_failure, subunit_out=False, combine_id=None, repo_type='file', repo_url=None, pretty_out=True, color=False, stdout=sys.stdout, abbreviate=False, suppress_attachments=False, - all_attachments=False): + all_attachments=False, show_binary_attachments=False): """Run the tests cmd was parameterised with.""" cmd.setUp() try: @@ -603,7 +616,8 @@ def run_tests(): pretty_out=pretty_out, color=color, stdout=stdout, abbreviate=abbreviate, suppress_attachments=suppress_attachments, - all_attachments=all_attachments) + all_attachments=all_attachments, + show_binary_attachments=show_binary_attachments) if not until_failure: return run_tests() diff --git a/stestr/subunit_trace.py b/stestr/subunit_trace.py index d0033d3b..108f2322 100644 --- a/stestr/subunit_trace.py +++ b/stestr/subunit_trace.py @@ -103,7 +103,8 @@ def find_worker(test): # Print out stdout/stderr if it exists, always -def print_attachments(stream, test, all_channels=False): +def print_attachments(stream, test, all_channels=False, + show_binary_attachments=False): """Print out subunit attachments. Print out subunit attachments that contain content. This @@ -117,13 +118,18 @@ def print_attachments(stream, test, all_channels=False): name = name.split(':')[0] if detail.content_type.type == 'test': detail.content_type.type = 'text' - if (all_channels or name in channels) and detail.as_text(): + if all_channels or name in channels: title = "Captured %s:" % name stream.write("\n%s\n%s\n" % (title, ('~' * len(title)))) + # indent attachment lines 4 spaces to make them visually # offset - for line in detail.as_text().split('\n'): - stream.write(" %s\n" % line) + if detail.content_type.type == 'text': + for line in detail.iter_text(): + stream.write(" %s\n" % line) + elif show_binary_attachments: # binary + for line in detail.iter_bytes(): + stream.write(" %s\n" % line) def find_test_run_time_diff(test_id, run_time): @@ -152,7 +158,7 @@ def find_test_run_time_diff(test_id, run_time): def show_outcome(stream, test, print_failures=False, failonly=False, enable_diff=False, threshold='0', abbreviate=False, enable_color=False, suppress_attachments=False, - all_attachments=False): + all_attachments=False, show_binary_attachments=True): global RESULTS status = test['status'] # TODO(sdague): ask lifeless why on this? @@ -189,7 +195,9 @@ def show_outcome(stream, test, print_failures=False, failonly=False, color.write('FAILED', 'red') stream.write('\n') if not print_failures: - print_attachments(stream, test, all_channels=True) + print_attachments( + stream, test, all_channels=True, + show_binary_attachments=show_binary_attachments) elif not failonly: if status == 'success' or status == 'xfail': if abbreviate: @@ -207,10 +215,9 @@ def show_outcome(stream, test, print_failures=False, failonly=False, color.write('ok', 'green') stream.write('\n') if not suppress_attachments: - if not all_attachments: - print_attachments(stream, test) - else: - print_attachments(stream, test, all_channels=True) + print_attachments( + stream, test, all_channels=all_attachments, + show_binary_attachments=show_binary_attachments) elif status == 'skip': if abbreviate: color.write('S', 'blue') @@ -230,7 +237,9 @@ def show_outcome(stream, test, print_failures=False, failonly=False, stream.write('{%s} %s [%s] ... %s\n' % ( worker, name, duration, test['status'])) if not print_failures: - print_attachments(stream, test, all_channels=True) + print_attachments( + stream, test, all_channels=True, + show_binary_attachments=show_binary_attachments) stream.flush() @@ -354,7 +363,8 @@ def parse_args(): def trace(stdin, stdout, print_failures=False, failonly=False, enable_diff=False, abbreviate=False, color=False, post_fails=False, - no_summary=False, suppress_attachments=False, all_attachments=False): + no_summary=False, suppress_attachments=False, all_attachments=False, + show_binary_attachments=False): stream = subunit.ByteStreamToStreamResult( stdin, non_subunit_name='stdout') outcomes = testtools.StreamToDict( @@ -365,7 +375,8 @@ def trace(stdin, stdout, print_failures=False, failonly=False, abbreviate=abbreviate, enable_color=color, suppress_attachments=suppress_attachments, - all_attachments=all_attachments)) + all_attachments=all_attachments, + show_binary_attachments=show_binary_attachments)) summary = testtools.StreamSummary() result = testtools.CopyStreamResult([outcomes, summary]) result = testtools.StreamResultRouter(result) From 617f040e92d1a7704e9c2e499a2191c3872f1b8d Mon Sep 17 00:00:00 2001 From: Matthew Treinish Date: Thu, 23 Jan 2020 17:26:09 -0500 Subject: [PATCH 10/19] Fix line length issue from pyupgrade --- stestr/user_config.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stestr/user_config.py b/stestr/user_config.py index ef8d7ce1..fa8e29b1 100644 --- a/stestr/user_config.py +++ b/stestr/user_config.py @@ -75,8 +75,8 @@ def __init__(self, path): try: self.schema(self.config) except vp.MultipleInvalid as e: - msg = 'Provided user config file {} is invalid because:\n{}'.format( - path, str(e)) + msg = ('Provided user config file {} is invalid ' + 'because:\n{}'.format(path, str(e))) sys.exit(msg) @property From dd3308ccb7e6f420305faa18f84d11c6198b1ac1 Mon Sep 17 00:00:00 2001 From: Matthew Treinish Date: Thu, 23 Jan 2020 17:37:26 -0500 Subject: [PATCH 11/19] Remove six from tests and requirements This commit removes the last usage of six from the repo which was only in the tests. With it no longer being imported anywhere six is removed from the requirements list because in a python3 only project it's no longer necessary to bridge the gap between python2 and python3. --- requirements.txt | 1 - stestr/tests/test_bisect_return_codes.py | 4 +- stestr/tests/test_bisect_tests.py | 3 +- stestr/tests/test_return_codes.py | 12 ++-- stestr/tests/test_scheduler.py | 12 ++-- stestr/tests/test_selection.py | 14 ++--- stestr/tests/test_subunit_trace.py | 7 +-- stestr/tests/test_user_config.py | 12 ++-- stestr/tests/test_user_config_return_codes.py | 56 +++++++++---------- 9 files changed, 56 insertions(+), 65 deletions(-) diff --git a/requirements.txt b/requirements.txt index 3aa1d109..901e613e 100644 --- a/requirements.txt +++ b/requirements.txt @@ -6,7 +6,6 @@ pbr!=2.1.0,>=2.0.0,!=4.0.0,!=4.0.1,!=4.0.2,!=4.0.3 # Apache-2.0 cliff>=2.8.0 # Apache-2.0 python-subunit>=1.3.0 # Apache-2.0/BSD fixtures>=3.0.0 # Apache-2.0/BSD -six>=1.10.0 # MIT testtools>=2.2.0 # MIT PyYAML>=3.10.0 # MIT voluptuous>=0.8.9 # BSD License diff --git a/stestr/tests/test_bisect_return_codes.py b/stestr/tests/test_bisect_return_codes.py index 23ad5806..337f0122 100644 --- a/stestr/tests/test_bisect_return_codes.py +++ b/stestr/tests/test_bisect_return_codes.py @@ -15,8 +15,6 @@ import subprocess import tempfile -import six - from stestr.tests import base @@ -65,7 +63,7 @@ def test_bisect_serial_fail_detected(self): out, err = p_analyze.communicate() out = out.decode('utf-8') # For debugging potential failures - lines = six.text_type(out.rstrip()).splitlines() + lines = str(out.rstrip()).splitlines() self.assertEqual(3, p_analyze.returncode, 'Analyze isolation returned an unexpected return code' '\nStdout: %s\nStderr: %s' % (out, err)) diff --git a/stestr/tests/test_bisect_tests.py b/stestr/tests/test_bisect_tests.py index 52c333a6..5cee81a8 100644 --- a/stestr/tests/test_bisect_tests.py +++ b/stestr/tests/test_bisect_tests.py @@ -14,7 +14,6 @@ import operator import mock -import six import subunit import testtools @@ -80,7 +79,7 @@ class FakeNoFailing(FakeTestRun): def __init__(self, failure=True): # Generate a subunit stream - stream_buf = io.BytesIO(six.binary_type(b'')) + stream_buf = io.BytesIO(bytes(b'')) self._content = stream_buf.getvalue() self.id = None diff --git a/stestr/tests/test_return_codes.py b/stestr/tests/test_return_codes.py index 18fd2109..54e10c4b 100644 --- a/stestr/tests/test_return_codes.py +++ b/stestr/tests/test_return_codes.py @@ -21,8 +21,6 @@ import tempfile import fixtures -import six -from six import StringIO import subunit as subunit_lib import testtools @@ -55,8 +53,8 @@ def setUp(self): shutil.copy('stestr/tests/files/__init__.py', self.init_file) shutil.copy('stestr/tests/files/stestr.yaml', self.user_config) - self.stdout = StringIO() - self.stderr = StringIO() + self.stdout = io.StringIO() + self.stderr = io.StringIO() # Change directory, run wrapper and check result self.addCleanup(os.chdir, os.path.abspath(os.curdir)) os.chdir(self.directory) @@ -245,7 +243,7 @@ def test_combine_results(self): self.assertRunExit('stestr run passing', 0) stdout = self._get_cmd_stdout( 'stestr last --no-subunit-trace') - stdout = six.text_type(stdout[0]) + stdout = str(stdout[0]) test_count_split = stdout.split(' ') test_count = test_count_split[1] test_count = int(test_count) @@ -254,7 +252,7 @@ def test_combine_results(self): self.assertRunExit('stestr run --combine passing', 0) combine_stdout = self._get_cmd_stdout( 'stestr last --no-subunit-trace')[0] - combine_stdout = six.text_type(combine_stdout) + combine_stdout = str(combine_stdout) combine_test_count_split = combine_stdout.split(' ') combine_test_count = combine_test_count_split[1] combine_test_count = int(combine_test_count) @@ -303,7 +301,7 @@ def test_load_from_stdin_quiet(self): def test_no_subunit_trace_force_subunit_trace(self): out, err = self.assertRunExit( 'stestr run --no-subunit-trace --force-subunit-trace passing', 0) - out = six.text_type(out) + out = str(out) self.assertNotIn('PASSED (id=0)', out) self.assertIn('Totals', out) self.assertIn('Worker Balance', out) diff --git a/stestr/tests/test_scheduler.py b/stestr/tests/test_scheduler.py index 5959759d..08e446e7 100644 --- a/stestr/tests/test_scheduler.py +++ b/stestr/tests/test_scheduler.py @@ -117,7 +117,7 @@ def group_id(test_id, regex=re.compile('TestCase[0-5]')): if 'testdir.testfile.TestCase5.test' not in partitions[0]: self.assertTrue('testdir.testfile.TestCase5.test' in partitions[1]) - @mock.patch('six.moves.builtins.open', mock.mock_open(), create=True) + @mock.patch('builtins.open', mock.mock_open(), create=True) def test_generate_worker_partitions(self): test_ids = ['test_a', 'test_b', 'your_test'] fake_worker_yaml = [ @@ -132,7 +132,7 @@ def test_generate_worker_partitions(self): ] self.assertEqual(expected_grouping, groups) - @mock.patch('six.moves.builtins.open', mock.mock_open(), create=True) + @mock.patch('builtins.open', mock.mock_open(), create=True) def test_generate_worker_partitions_group_without_list(self): test_ids = ['test_a', 'test_b', 'your_test'] fake_worker_yaml = [ @@ -143,7 +143,7 @@ def test_generate_worker_partitions_group_without_list(self): self.assertRaises(TypeError, scheduler.generate_worker_partitions, test_ids, 'fakepath') - @mock.patch('six.moves.builtins.open', mock.mock_open(), create=True) + @mock.patch('builtins.open', mock.mock_open(), create=True) def test_generate_worker_partitions_no_worker_tag(self): test_ids = ['test_a', 'test_b', 'your_test'] fake_worker_yaml = [ @@ -154,7 +154,7 @@ def test_generate_worker_partitions_no_worker_tag(self): self.assertRaises(TypeError, scheduler.generate_worker_partitions, test_ids, 'fakepath') - @mock.patch('six.moves.builtins.open', mock.mock_open(), create=True) + @mock.patch('builtins.open', mock.mock_open(), create=True) def test_generate_worker_partitions_group_without_match(self): test_ids = ['test_a', 'test_b', 'your_test'] fake_worker_yaml = [ @@ -170,7 +170,7 @@ def test_generate_worker_partitions_group_without_match(self): ] self.assertEqual(expected_grouping, groups) - @mock.patch('six.moves.builtins.open', mock.mock_open(), create=True) + @mock.patch('builtins.open', mock.mock_open(), create=True) def test_generate_worker_partitions_with_count(self): test_ids = ['test_a', 'test_b', 'your_test', 'a_thing1', 'a_thing2'] fake_worker_yaml = [ @@ -189,7 +189,7 @@ def test_generate_worker_partitions_with_count(self): for worker in expected_grouping: self.assertIn(worker, groups) - @mock.patch('six.moves.builtins.open', mock.mock_open(), create=True) + @mock.patch('builtins.open', mock.mock_open(), create=True) def test_generate_worker_partitions_with_count_1(self): test_ids = ['test_a', 'test_b', 'your_test'] fake_worker_yaml = [ diff --git a/stestr/tests/test_selection.py b/stestr/tests/test_selection.py index 527ca5c5..cc2e8e63 100644 --- a/stestr/tests/test_selection.py +++ b/stestr/tests/test_selection.py @@ -10,10 +10,10 @@ # License for the specific language governing permissions and limitations # under the License. +import io import re import mock -import six from stestr import selection from stestr.tests import base @@ -41,12 +41,12 @@ def test_filter_invalid_regex(self): class TestBlackReader(base.TestCase): def test_black_reader(self): - blacklist_file = six.StringIO() + blacklist_file = io.StringIO() for i in range(4): blacklist_file.write('fake_regex_%s\n' % i) blacklist_file.write('fake_regex_with_note_%s # note\n' % i) blacklist_file.seek(0) - with mock.patch('six.moves.builtins.open', + with mock.patch('builtins.open', return_value=blacklist_file): result = selection.black_reader('fake_path') self.assertEqual(2 * 4, len(result)) @@ -60,10 +60,10 @@ def test_black_reader(self): self.assertEqual(note_cnt, 4) def test_invalid_regex(self): - blacklist_file = six.StringIO() + blacklist_file = io.StringIO() blacklist_file.write("fake_regex_with_bad_part[The-BAD-part]") blacklist_file.seek(0) - with mock.patch('six.moves.builtins.open', + with mock.patch('builtins.open', return_value=blacklist_file): with mock.patch('sys.exit') as mock_exit: selection.black_reader('fake_path') @@ -111,10 +111,10 @@ def test_whitelist(self): {'fake_test1[tg]', 'fake_test2[tg]'}) def test_whitelist_invalid_regex(self): - whitelist_file = six.StringIO() + whitelist_file = io.StringIO() whitelist_file.write("fake_regex_with_bad_part[The-BAD-part]") whitelist_file.seek(0) - with mock.patch('six.moves.builtins.open', + with mock.patch('builtins.open', return_value=whitelist_file): with mock.patch('sys.exit') as mock_exit: selection._get_regex_from_whitelist_file('fake_path') diff --git a/stestr/tests/test_subunit_trace.py b/stestr/tests/test_subunit_trace.py index 0f38b3b9..aa6c9756 100644 --- a/stestr/tests/test_subunit_trace.py +++ b/stestr/tests/test_subunit_trace.py @@ -22,7 +22,6 @@ from ddt import ddt from ddt import unpack from mock import patch -import six from stestr import subunit_trace from stestr.tests import base @@ -79,7 +78,7 @@ def test_trace(self): 'sample_streams/successful.subunit') bytes_ = io.BytesIO() with open(regular_stream, 'rb') as stream: - bytes_.write(six.binary_type(stream.read())) + bytes_.write(bytes(stream.read())) bytes_.seek(0) stdin = io.TextIOWrapper(io.BufferedReader(bytes_)) returncode = subunit_trace.trace(stdin, sys.stdout) @@ -91,7 +90,7 @@ def test_trace_with_all_skips(self): 'sample_streams/all_skips.subunit') bytes_ = io.BytesIO() with open(regular_stream, 'rb') as stream: - bytes_.write(six.binary_type(stream.read())) + bytes_.write(bytes(stream.read())) bytes_.seek(0) stdin = io.TextIOWrapper(io.BufferedReader(bytes_)) returncode = subunit_trace.trace(stdin, sys.stdout) @@ -103,7 +102,7 @@ def test_trace_with_failures(self): 'sample_streams/failure.subunit') bytes_ = io.BytesIO() with open(regular_stream, 'rb') as stream: - bytes_.write(six.binary_type(stream.read())) + bytes_.write(bytes(stream.read())) bytes_.seek(0) stdin = io.TextIOWrapper(io.BufferedReader(bytes_)) returncode = subunit_trace.trace(stdin, sys.stdout) diff --git a/stestr/tests/test_user_config.py b/stestr/tests/test_user_config.py index 733b440c..71d0c790 100644 --- a/stestr/tests/test_user_config.py +++ b/stestr/tests/test_user_config.py @@ -100,7 +100,7 @@ def fake_isfile(path): user_mock.assert_called_once_with(self.home_path) @mock.patch('yaml.safe_load', return_value={}) - @mock.patch('six.moves.builtins.open', mock.mock_open()) + @mock.patch('builtins.open', mock.mock_open()) def test_user_config_empty_schema(self, yaml_mock): user_conf = user_config.UserConfig('/path') self.assertEqual({}, user_conf.config) @@ -108,7 +108,7 @@ def test_user_config_empty_schema(self, yaml_mock): @mock.patch('yaml.safe_load', return_value={'init': {'subunit-trace': True}}) @mock.patch('sys.exit') - @mock.patch('six.moves.builtins.open', mock.mock_open()) + @mock.patch('builtins.open', mock.mock_open()) def test_user_config_invalid_command(self, exit_mock, yaml_mock): user_config.UserConfig('/path') error_string = ("Provided user config file /path is invalid because:\n" @@ -118,7 +118,7 @@ def test_user_config_invalid_command(self, exit_mock, yaml_mock): @mock.patch('yaml.safe_load', return_value={'run': {'subunit-trace': True}}) @mock.patch('sys.exit') - @mock.patch('six.moves.builtins.open', mock.mock_open()) + @mock.patch('builtins.open', mock.mock_open()) def test_user_config_invalid_option(self, exit_mock, yaml_mock): user_config.UserConfig('/path') error_string = ("Provided user config file /path is invalid because:\n" @@ -126,7 +126,7 @@ def test_user_config_invalid_option(self, exit_mock, yaml_mock): "data['run']['subunit-trace']") exit_mock.assert_called_once_with(error_string) - @mock.patch('six.moves.builtins.open', + @mock.patch('builtins.open', return_value=io.BytesIO(FULL_YAML.encode('utf-8'))) def test_user_config_full_config(self, open_mock): user_conf = user_config.UserConfig('/path') @@ -158,7 +158,7 @@ def test_user_config_full_config(self, open_mock): self.assertEqual(full_dict, user_conf.config) @mock.patch('sys.exit') - @mock.patch('six.moves.builtins.open', + @mock.patch('builtins.open', return_value=io.BytesIO(INVALID_YAML_FIELD.encode('utf-8'))) def test_user_config_invalid_value_type(self, open_mock, exit_mock): user_config.UserConfig('/path') @@ -168,7 +168,7 @@ def test_user_config_invalid_value_type(self, open_mock, exit_mock): exit_mock.assert_called_once_with(error_string) @mock.patch('sys.exit') - @mock.patch('six.moves.builtins.open', + @mock.patch('builtins.open', return_value=io.BytesIO(YAML_NOT_INT.encode('utf-8'))) def test_user_config_invalid_integer(self, open_mock, exit_mock): user_config.UserConfig('/path') diff --git a/stestr/tests/test_user_config_return_codes.py b/stestr/tests/test_user_config_return_codes.py index 0e2513f7..698e8308 100644 --- a/stestr/tests/test_user_config_return_codes.py +++ b/stestr/tests/test_user_config_return_codes.py @@ -17,8 +17,6 @@ import subprocess import tempfile -import six -from six import StringIO import subunit as subunit_lib import testtools import yaml @@ -48,8 +46,8 @@ def setUp(self): shutil.copy('stestr/tests/files/setup.cfg', self.setup_cfg_file) shutil.copy('stestr/tests/files/__init__.py', self.init_file) - self.stdout = StringIO() - self.stderr = StringIO() + self.stdout = io.StringIO() + self.stderr = io.StringIO() # Change directory, run wrapper and check result self.addCleanup(os.chdir, os.path.abspath(os.curdir)) os.chdir(self.directory) @@ -123,7 +121,7 @@ def test_no_subunit_trace_config_file_passing(self): self.addCleanup(os.remove, path) conf_file = os.fdopen(fd, 'wb', 0) self.addCleanup(conf_file.close) - contents = six.text_type( + contents = str( yaml.dump({ 'run': { 'no-subunit-trace': True, @@ -132,7 +130,7 @@ def test_no_subunit_trace_config_file_passing(self): conf_file.write(contents.encode('utf-8')) out, err = self.assertRunExit( 'stestr --user-config=%s run passing' % path, 0) - out = six.text_type(out) + out = str(out) self.assertIn('PASSED (id=0)', out) self.assertNotIn('Totals', out) self.assertNotIn('Worker Balance', out) @@ -144,7 +142,7 @@ def test_no_subunit_trace_config_file_failing(self): self.addCleanup(os.remove, path) conf_file = os.fdopen(fd, 'wb', 0) self.addCleanup(conf_file.close) - contents = six.text_type( + contents = str( yaml.dump({ 'run': { 'no-subunit-trace': True, @@ -153,7 +151,7 @@ def test_no_subunit_trace_config_file_failing(self): conf_file.write(contents.encode('utf-8')) out, err = self.assertRunExit( 'stestr --user-config=%s run' % path, 1) - out = six.text_type(out) + out = str(out) self.assertIn('FAILED (id=0, failures=2)', out) self.assertNotIn('Totals', out) self.assertNotIn('Worker Balance', out) @@ -164,7 +162,7 @@ def test_no_subunit_trace_config_file_force_subunit_trace(self): self.addCleanup(os.remove, path) conf_file = os.fdopen(fd, 'wb', 0) self.addCleanup(conf_file.close) - contents = six.text_type( + contents = str( yaml.dump({ 'run': { 'no-subunit-trace': True, @@ -174,7 +172,7 @@ def test_no_subunit_trace_config_file_force_subunit_trace(self): out, err = self.assertRunExit( 'stestr --user-config=%s run --force-subunit-trace passing' % path, 0) - out = six.text_type(out) + out = str(out) self.assertNotIn('PASSED (id=0)', out) self.assertIn('Totals', out) self.assertIn('Worker Balance', out) @@ -185,7 +183,7 @@ def test_abbreviate_config_file_passing(self): self.addCleanup(os.remove, path) conf_file = os.fdopen(fd, 'wb', 0) self.addCleanup(conf_file.close) - contents = six.text_type( + contents = str( yaml.dump({ 'run': { 'abbreviate': True, @@ -194,7 +192,7 @@ def test_abbreviate_config_file_passing(self): conf_file.write(contents.encode('utf-8')) out, err = self.assertRunExit( 'stestr --user-config=%s run passing' % path, 0) - out = six.text_type(out) + out = str(out) self.assertIn('..', out) self.assertNotIn('PASSED (id=0)', out) self.assertIn('Totals', out) @@ -206,7 +204,7 @@ def test_abbreviate_config_file_failing(self): self.addCleanup(os.remove, path) conf_file = os.fdopen(fd, 'wb', 0) self.addCleanup(conf_file.close) - contents = six.text_type( + contents = str( yaml.dump({ 'run': { 'abbreviate': True, @@ -217,7 +215,7 @@ def test_abbreviate_config_file_failing(self): # execution order for confirming the abbreviated output. out, err = self.assertRunExit( 'stestr --user-config=%s run --serial' % path, 1) - out = six.text_type(out) + out = str(out) self.assertIn('FF..', out) self.assertNotIn('FAILED (id=0, failures=2)', out) self.assertIn('Totals', out) @@ -229,7 +227,7 @@ def test_no_subunit_trace_slowest_config_file_passing(self): self.addCleanup(os.remove, path) conf_file = os.fdopen(fd, 'wb', 0) self.addCleanup(conf_file.close) - contents = six.text_type( + contents = str( yaml.dump({ 'run': { 'no-subunit-trace': True, @@ -239,7 +237,7 @@ def test_no_subunit_trace_slowest_config_file_passing(self): conf_file.write(contents.encode('utf-8')) out, err = self.assertRunExit( 'stestr --user-config=%s run passing' % path, 0) - out = six.text_type(out) + out = str(out) self.assertIn('PASSED (id=0)', out) self.assertNotIn('Totals', out) self.assertNotIn('Worker Balance', out) @@ -251,7 +249,7 @@ def test_failing_list_config_file(self): self.addCleanup(os.remove, path) conf_file = os.fdopen(fd, 'wb', 0) self.addCleanup(conf_file.close) - contents = six.text_type( + contents = str( yaml.dump({ 'run': { 'no-subunit-trace': True, @@ -265,7 +263,7 @@ def test_failing_list_config_file(self): self.assertRunExit('stestr --user-config=%s run' % path, 1) out, err = self.assertRunExit('stestr --user-config=%s failing' % path, 1) - out = six.text_type(out) + out = str(out) self.assertNotIn('FAILED (id=0, failures=2)', out) self.assertNotIn('FAIL:', out) self.assertIn('tests.test_failing.FakeTestClass.test_pass', out) @@ -276,7 +274,7 @@ def test_no_subunit_trace_last_config_file_passing(self): self.addCleanup(os.remove, path) conf_file = os.fdopen(fd, 'wb', 0) self.addCleanup(conf_file.close) - contents = six.text_type( + contents = str( yaml.dump({ 'run': { 'slowest': True, @@ -293,8 +291,8 @@ def test_no_subunit_trace_last_config_file_passing(self): 'stestr --user-config=%s run passing' % path, 0) out, err = self.assertRunExit('stestr --user-config=%s last' % path, 0) - run_out = six.text_type(run_out) - out = six.text_type(out) + run_out = str(run_out) + out = str(out) self.assertIn('PASSED (id=0)', out) self.assertNotIn('Totals', out) self.assertNotIn('Worker Balance', out) @@ -310,7 +308,7 @@ def test_subunit_trace_load_from_config_passing(self): self.addCleanup(os.remove, path) conf_file = os.fdopen(fd, 'wb', 0) self.addCleanup(conf_file.close) - contents = six.text_type( + contents = str( yaml.dump({ 'run': { 'slowest': True, @@ -332,7 +330,7 @@ def test_subunit_trace_load_from_config_passing(self): 'stestr --user-config=%s last --subunit' % path)[0] out, err = self.assertRunExit('stestr --user-config=%s load' % path, 0, stdin=stream) - out = six.text_type(out) + out = str(out) self.assertNotIn('PASSED (id=0)', out) self.assertIn('Totals', out) self.assertIn('Worker Balance', out) @@ -343,7 +341,7 @@ def test_subunit_trace_load_from_config_failing(self): self.addCleanup(os.remove, path) conf_file = os.fdopen(fd, 'wb', 0) self.addCleanup(conf_file.close) - contents = six.text_type( + contents = str( yaml.dump({ 'run': { 'slowest': True, @@ -365,7 +363,7 @@ def test_subunit_trace_load_from_config_failing(self): 'stestr --user-config=%s last --subunit' % path)[0] out, err = self.assertRunExit('stestr --user-config=%s load' % path, 0, stdin=stream) - out = six.text_type(out) + out = str(out) self.assertNotIn('FAILED (id=0, failures=2)', out) self.assertNotIn('FF..', out) self.assertIn('Totals', out) @@ -378,7 +376,7 @@ def test_abbreviate_load_from_config_passing(self): self.addCleanup(os.remove, path) conf_file = os.fdopen(fd, 'wb', 0) self.addCleanup(conf_file.close) - contents = six.text_type( + contents = str( yaml.dump({ 'run': { 'slowest': True, @@ -400,7 +398,7 @@ def test_abbreviate_load_from_config_passing(self): 'stestr --user-config=%s last --subunit' % path)[0] out, err = self.assertRunExit('stestr --user-config=%s load' % path, 0, stdin=stream) - out = six.text_type(out) + out = str(out) self.assertNotIn('PASSED (id=0)', out) self.assertIn('..', out) self.assertIn('Totals', out) @@ -413,7 +411,7 @@ def test_abbreviate_load_from_config_failing(self): self.addCleanup(os.remove, path) conf_file = os.fdopen(fd, 'wb', 0) self.addCleanup(conf_file.close) - contents = six.text_type( + contents = str( yaml.dump({ 'run': { 'slowest': True, @@ -436,7 +434,7 @@ def test_abbreviate_load_from_config_failing(self): 'stestr --user-config=%s last --subunit' % path)[0] out, err = self.assertRunExit('stestr --user-config=%s load' % path, 0, stdin=stream) - out = six.text_type(out) + out = str(out) self.assertNotIn('FAILED (id=0, failures=2)', out) self.assertIn('FF..', out) self.assertIn('Totals', out) From 5f34f10f984d0ec9de4736e7348f7e179942befb Mon Sep 17 00:00:00 2001 From: Matthew Treinish Date: Tue, 17 Mar 2020 12:28:40 -0400 Subject: [PATCH 12/19] Remove universal wheel tag from setup.cfg --- setup.cfg | 3 --- 1 file changed, 3 deletions(-) diff --git a/setup.cfg b/setup.cfg index 7aad99b4..fa622c60 100644 --- a/setup.cfg +++ b/setup.cfg @@ -47,9 +47,6 @@ stestr.cm = sql = subunit2sql>=1.8.0 -[bdist_wheel] -universal=1 - [build_sphinx] source-dir = doc/source build-dir = doc/build From e5a54e6b91bb2e6e3a552613c6cac9e6342e09d5 Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Wed, 18 Mar 2020 09:55:03 +0000 Subject: [PATCH 13/19] Bump python-subunit minimum to 1.4.0 This version includes an important Python 3 fix [1], without which a Python 3-only stestr doesn't really make sense. [1] https://github.com/testing-cabal/subunit/pull/40 Signed-off-by: Stephen Finucane --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 3aa1d109..ac728ea2 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,7 +4,7 @@ future pbr!=2.1.0,>=2.0.0,!=4.0.0,!=4.0.1,!=4.0.2,!=4.0.3 # Apache-2.0 cliff>=2.8.0 # Apache-2.0 -python-subunit>=1.3.0 # Apache-2.0/BSD +python-subunit>=1.4.0 # Apache-2.0/BSD fixtures>=3.0.0 # Apache-2.0/BSD six>=1.10.0 # MIT testtools>=2.2.0 # MIT From e6ce637a575eb2f58d1df58dcdc93e9b33da8307 Mon Sep 17 00:00:00 2001 From: Matthew Treinish Date: Wed, 18 Mar 2020 10:23:57 -0400 Subject: [PATCH 14/19] Remove six usage from testr_to_stestr --- tools/testr_to_stestr.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/testr_to_stestr.py b/tools/testr_to_stestr.py index 4f3bb092..63892012 100755 --- a/tools/testr_to_stestr.py +++ b/tools/testr_to_stestr.py @@ -12,16 +12,16 @@ # See the License for the specific language governing permissions and # limitations under the License. +import configparser import os import sys -import six if not os.path.isfile('.testr.conf'): sys.exit("Testr config file not found") with open('.testr.conf', 'r') as testr_conf_file: - config = six.moves.configparser.ConfigParser() + config = configparser.ConfigParser() config.readfp(testr_conf_file) test_command = config.get('DEFAULT', 'test_command') From 82fe384b321179402ab92603d8ba739e3385eb62 Mon Sep 17 00:00:00 2001 From: Matthew Treinish Date: Wed, 18 Mar 2020 12:30:50 -0400 Subject: [PATCH 15/19] Update test-requirements to be py3 only This commit updates the test-requirements to remove things no longer needed in a py3 only world. This involves updating the sphinx version so that we don't have to explicitly set a python 2 version. It also means removing the mock library as we can just use mock from stdlib now that we're only supporting python3. --- stestr/tests/repository/test_util.py | 2 +- stestr/tests/test_bisect_tests.py | 2 +- stestr/tests/test_config_file.py | 3 ++- stestr/tests/test_scheduler.py | 2 +- stestr/tests/test_selection.py | 3 +-- stestr/tests/test_subunit_trace.py | 2 +- stestr/tests/test_test_processor.py | 3 +-- stestr/tests/test_user_config.py | 3 +-- test-requirements.txt | 4 +--- 9 files changed, 10 insertions(+), 14 deletions(-) diff --git a/stestr/tests/repository/test_util.py b/stestr/tests/repository/test_util.py index 95c2e5ad..b2993764 100644 --- a/stestr/tests/repository/test_util.py +++ b/stestr/tests/repository/test_util.py @@ -10,10 +10,10 @@ # License for the specific language governing permissions and limitations # under the License. -import mock import os import shutil import tempfile +from unittest import mock from stestr.repository import util from stestr.tests import base diff --git a/stestr/tests/test_bisect_tests.py b/stestr/tests/test_bisect_tests.py index 5cee81a8..02f349ab 100644 --- a/stestr/tests/test_bisect_tests.py +++ b/stestr/tests/test_bisect_tests.py @@ -12,8 +12,8 @@ import io import operator +from unittest import mock -import mock import subunit import testtools diff --git a/stestr/tests/test_config_file.py b/stestr/tests/test_config_file.py index 31e364f4..75f00585 100644 --- a/stestr/tests/test_config_file.py +++ b/stestr/tests/test_config_file.py @@ -10,8 +10,9 @@ # License for the specific language governing permissions and limitations # under the License. +from unittest import mock + import ddt -import mock from stestr import config_file from stestr.tests import base diff --git a/stestr/tests/test_scheduler.py b/stestr/tests/test_scheduler.py index 08e446e7..968f487a 100644 --- a/stestr/tests/test_scheduler.py +++ b/stestr/tests/test_scheduler.py @@ -12,8 +12,8 @@ import datetime import re +from unittest import mock -import mock from subunit import iso8601 from stestr.repository import memory diff --git a/stestr/tests/test_selection.py b/stestr/tests/test_selection.py index cc2e8e63..0de19c32 100644 --- a/stestr/tests/test_selection.py +++ b/stestr/tests/test_selection.py @@ -12,8 +12,7 @@ import io import re - -import mock +from unittest import mock from stestr import selection from stestr.tests import base diff --git a/stestr/tests/test_subunit_trace.py b/stestr/tests/test_subunit_trace.py index aa6c9756..701a86ab 100644 --- a/stestr/tests/test_subunit_trace.py +++ b/stestr/tests/test_subunit_trace.py @@ -17,11 +17,11 @@ import io import os import sys +from unittest.mock import patch from ddt import data from ddt import ddt from ddt import unpack -from mock import patch from stestr import subunit_trace from stestr.tests import base diff --git a/stestr/tests/test_test_processor.py b/stestr/tests/test_test_processor.py index 60288f0a..aea91c7a 100644 --- a/stestr/tests/test_test_processor.py +++ b/stestr/tests/test_test_processor.py @@ -11,8 +11,7 @@ # under the License. import subprocess - -import mock +from unittest import mock from stestr import test_processor from stestr.tests import base diff --git a/stestr/tests/test_user_config.py b/stestr/tests/test_user_config.py index 71d0c790..a6432f3a 100644 --- a/stestr/tests/test_user_config.py +++ b/stestr/tests/test_user_config.py @@ -12,8 +12,7 @@ import io import os - -import mock +from unittest import mock from stestr.tests import base from stestr import user_config diff --git a/test-requirements.txt b/test-requirements.txt index 88b398e5..7e09533d 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -3,9 +3,7 @@ # process, which may cause wedges in the gate later. hacking<1.2.0,>=1.1.0 -sphinx!=1.6.6,!=1.6.7,<2.0.0;python_version=='2.7' # BSD -sphinx!=1.6.6,!=1.6.7,!=2.1.0;python_version>='3.4' # BSD -mock>=2.0 # BSD +sphinx>2.1.0 # BSD subunit2sql>=1.8.0 coverage>=4.0 # Apache-2.0 ddt>=1.0.1 # MIT From a3829a9f52bcea8f0722f6ccde262835e577317a Mon Sep 17 00:00:00 2001 From: Matthew Treinish Date: Thu, 26 Mar 2020 08:08:50 -0400 Subject: [PATCH 16/19] Update README in preparation for release 3.0.0 Now that we've merged the python 2.7 removal to master the last thing that is necessary to do is update the guidance in the README regarding python 2.7 support. This should be the last commit on master prior to the 3.0.0 release. --- README.rst | 3 +-- README_ja.rst | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/README.rst b/README.rst index 7f75d1c0..7352b523 100644 --- a/README.rst +++ b/README.rst @@ -25,8 +25,7 @@ stestr .. _日本語: https://github.com/mtreinish/stestr/blob/master/README_ja.rst .. note:: stestr v2.x.x release series will be the last series that supports - Python 2. Support for Python 2.7 will be dropped in stestr release 3.0.0 - which is being planned for early 2020. + Python 2. Support for Python 2.7 was dropped in stestr release 3.0.0. Overview -------- diff --git a/README_ja.rst b/README_ja.rst index 3ccdd0d6..4812d489 100644 --- a/README_ja.rst +++ b/README_ja.rst @@ -25,8 +25,8 @@ stestr(日本語訳) .. _日本語: https://github.com/mtreinish/stestr/blob/master/README_ja.rst .. note:: stestr v2.x.x リリースシリーズは、Python 2 をサポートする最後のシリ - ーズとなります。Python 2.7のサポートは、2020年の早い時期に予定されている、 - 「stestr リリース 3.0.0」にて打ち切られる予定です。 + ーズとなります。Python 2.7のサポートは「stestr リリース 3.0.0」 + にて打ち切られるでました。 概要 ---- From 63f390c66d3aa584be26594805aa982b278b9378 Mon Sep 17 00:00:00 2001 From: Matthew Treinish Date: Thu, 26 Mar 2020 08:42:24 -0400 Subject: [PATCH 17/19] Update README_ja.rst Co-Authored-By: Masayuki Igawa --- README_ja.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README_ja.rst b/README_ja.rst index 4812d489..d314d498 100644 --- a/README_ja.rst +++ b/README_ja.rst @@ -26,7 +26,7 @@ stestr(日本語訳) .. note:: stestr v2.x.x リリースシリーズは、Python 2 をサポートする最後のシリ ーズとなります。Python 2.7のサポートは「stestr リリース 3.0.0」 - にて打ち切られるでました。 + にて打ち切られました。 概要 ---- From e8ea2424a9c22d46c6241e0c91ff0eac7362f778 Mon Sep 17 00:00:00 2001 From: Matthew Treinish Date: Thu, 26 Mar 2020 10:20:44 -0400 Subject: [PATCH 18/19] Remove universal flag from release job Now that we've dropped support for python 2.7 from stestr we're no longer advertising or building universal wheels. However we never updated the travis job which publishes the release to pypi to drop the --universal flag when it builds the wheel for release. This commit corrects the oversight so that in future releases we don't try to build a universal wheel. --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 4fe1a688..29786fc1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -26,7 +26,7 @@ matrix: - TWINE_USERNAME=stestr-release install: pip install -U twine script: - - python3 setup.py sdist bdist_wheel --universal + - python3 setup.py sdist bdist_wheel - twine upload dist/stestr* cache: From 363f5a3b0956a7b5b4d8cc0ca060ed5a71b21d21 Mon Sep 17 00:00:00 2001 From: Andrey Pavlov Date: Fri, 27 Mar 2020 00:11:33 +0300 Subject: [PATCH 19/19] use python-requires metadata instead of requires-python Here is the doc with right name - https://packaging.python.org/guides/distributing-packages-using-setuptools/#python-requires --- setup.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.cfg b/setup.cfg index fa622c60..588b6705 100644 --- a/setup.cfg +++ b/setup.cfg @@ -25,7 +25,7 @@ project_urls = Documentation = https://stestr.readthedocs.io Source Code = https://github.com/mtreinish/stestr Bug Tracker = https://github.com/mtreinish/stestr/issues -requires-python = >=3.5 +python-requires = >=3.5 [files] packages =