Skip to content

Commit

Permalink
Remove Python 2 testing infrastructure (#1064)
Browse files Browse the repository at this point in the history
* remove remnants of Python 2/3 distinction from test infrastructure

* check for Python version is already done in Autotools

* fix regex escaping in tests/testsuite_default_Links.py

* remove impossible InstanceType branch for Python 3
  • Loading branch information
berquist authored Mar 23, 2024
1 parent 9bfe411 commit ae02be2
Show file tree
Hide file tree
Showing 10 changed files with 48 additions and 279 deletions.
46 changes: 0 additions & 46 deletions src/sst/core/testingframework/sst_test_engine_loader.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,51 +33,8 @@
TEST_ELEMENTS = 0
TEST_SST_CORE = 1

REQUIRED_PY_MAJ_VER_2 = 2 # Required Python2 Major Version
REQUIRED_PY_MAJ_VER_2_MINOR_VER = 7 # Required PY2 Minor Version
REQUIRED_PY_MAJ_VER_2_SUB_MINOR_VER = 5 # Required PY2 Sub-Minor Version
REQUIRED_PY_MAJ_VER_3 = 3 # Required Python 3 Major Version
REQUIRED_PY_MAJ_VER_3_MINOR_VER = 4 # Required PY3 Minor Version
REQUIRED_PY_MAJ_VER_3_SUB_MINOR_VER = 0 # Required PY3 Sub-Minor Version
REQUIRED_PY_MAJ_VER_MAX = REQUIRED_PY_MAJ_VER_3 # Highest supported Major Version

################################################################################

def check_python_version():
# Validate Python Versions
ver = sys.version_info

# Check for Py2.x or Py3.x Versions
if (ver[0] < REQUIRED_PY_MAJ_VER_2) or (ver[0] > REQUIRED_PY_MAJ_VER_3):
print(("SST Test Engine requires Python major version {0} or {1}\n" +
"Found Python version is:\n{2}").format(REQUIRED_PY_MAJ_VER_2,
REQUIRED_PY_MAJ_VER_MAX,
sys.version))
sys.exit(1)

# Check to ensure minimum Py2 version
if ((ver[0] == REQUIRED_PY_MAJ_VER_2) and (ver[1] < REQUIRED_PY_MAJ_VER_2_MINOR_VER)) or \
((ver[0] == REQUIRED_PY_MAJ_VER_2) and (ver[1] == REQUIRED_PY_MAJ_VER_2_MINOR_VER) and
(ver[2] < REQUIRED_PY_MAJ_VER_2_SUB_MINOR_VER)):
print(("SST Test Engine requires Python 2 version {0}.{1}.{2} or greater\n" +
"Found Python version is:\n{3}").format(REQUIRED_PY_MAJ_VER_2,
REQUIRED_PY_MAJ_VER_2_MINOR_VER,
REQUIRED_PY_MAJ_VER_2_SUB_MINOR_VER,
sys.version))
sys.exit(1)

# Check to ensure minimum Py3 version
if ((ver[0] == REQUIRED_PY_MAJ_VER_3) and (ver[1] < REQUIRED_PY_MAJ_VER_3_MINOR_VER)) or \
((ver[0] == REQUIRED_PY_MAJ_VER_3) and (ver[1] == REQUIRED_PY_MAJ_VER_3_MINOR_VER) and
(ver[2] < REQUIRED_PY_MAJ_VER_3_SUB_MINOR_VER)):
print(("SST Test Engine requires Python 3 version {0}.{1}.{2} or greater\n" +
"Found Python version is:\n{3}").format(REQUIRED_PY_MAJ_VER_3,
REQUIRED_PY_MAJ_VER_3_MINOR_VER,
REQUIRED_PY_MAJ_VER_3_SUB_MINOR_VER,
sys.version))
sys.exit(1)
####

def startup_and_run(sst_core_bin_dir, test_mode):
""" This is the main entry point for loading and running the SST Test Frameworks
Engine.
Expand All @@ -97,9 +54,6 @@ def startup_and_run(sst_core_bin_dir, test_mode):
test_mode: 1 for Core Testing, 0 for Elements testing.
"""
try:
# Check the python version and make sure we can run
check_python_version()

if test_mode not in (TEST_SST_CORE, TEST_ELEMENTS):
print((("FATAL: Unsupported test_mode {0} in ") +
("startup_and_run()")).format(test_mode))
Expand Down
7 changes: 0 additions & 7 deletions src/sst/core/testingframework/sst_unittest.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,6 @@
from test_engine_junit import junit_to_xml_report_file
#from test_engine_junit import junit_to_xml_report_string

################################################################################

PY2 = sys.version_info[0] == 2
PY3 = sys.version_info[0] == 3

################################################################################

class SSTTestCase(unittest.TestCase):
""" This class is main SSTTestCase class for the SST Testing Frameworks
Expand Down
67 changes: 15 additions & 52 deletions src/sst/core/testingframework/sst_unittest_parameterized.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,38 +54,18 @@
class SkipTest(Exception):
pass

PY3 = sys.version_info[0] == 3
PY2 = sys.version_info[0] == 2


if PY3:
# Python 3 doesn't have an InstanceType, so just use a dummy type.
class InstanceType():
pass
lzip = lambda *a: list(zip(*a))
text_type = str
string_types = str,
bytes_type = bytes
def make_method(func, instance, type):
if instance is None:
return func
return MethodType(func, instance)
else:
from types import InstanceType
lzip = zip
text_type = unicode
bytes_type = str
string_types = basestring,
def make_method(func, instance, type):
return MethodType(func, instance, type)
lzip = lambda *a: list(zip(*a))
def make_method(func, instance, type):
if instance is None:
return func
return MethodType(func, instance)


CompatArgSpec = namedtuple("CompatArgSpec", "args varargs keywords defaults")


def getargspec(func):
if PY2:
return CompatArgSpec(*inspect.getargspec(func))
args = inspect.getfullargspec(func)
if args.kwonlyargs:
raise TypeError((
Expand Down Expand Up @@ -170,7 +150,7 @@ def from_decorator(cls, args):
"""
if isinstance(args, param):
return args
elif isinstance(args, string_types):
elif isinstance(args, str):
args = (args, )
try:
return cls(*args)
Expand Down Expand Up @@ -256,11 +236,11 @@ def short_repr(x, n=64):
"""

x_repr = repr(x)
if isinstance(x_repr, bytes_type):
if isinstance(x_repr, bytes):
try:
x_repr = text_type(x_repr, "utf-8")
x_repr = str(x_repr, encoding="utf-8")
except UnicodeDecodeError:
x_repr = text_type(x_repr, "latin1")
x_repr = str(x_repr, encoding="latin1")
if len(x_repr) > n:
x_repr = x_repr[:n//2] + "..." + x_repr[len(x_repr) - n//2:]
return x_repr
Expand Down Expand Up @@ -291,7 +271,7 @@ def default_name_func(func, num, p):
base_name = func.__name__
name_suffix = "_%s" %(num, )

if len(p.args) > 0 and isinstance(p.args[0], string_types):
if len(p.args) > 0 and isinstance(p.args[0], str):
name_suffix += "_" + parameterized.to_safe_name(p.args[0])
return base_name + name_suffix

Expand Down Expand Up @@ -370,16 +350,6 @@ def __call__(self, test_func):
@wraps(test_func)
def wrapper(test_self=None):
test_cls = test_self and type(test_self)
if test_self is not None:
if issubclass(test_cls, InstanceType):
raise TypeError((
"@parameterized can't be used with old-style classes, but "
"%r has an old-style class. Consider using a new-style "
"class, or '@parameterized.expand' "
"(see http://stackoverflow.com/q/54867/71522 for more "
"information on old-style classes)."
) %(test_self, ))

original_doc = wrapper.__doc__
for num, args in enumerate(wrapper.parameterized_input):
p = param.from_decorator(args)
Expand Down Expand Up @@ -427,10 +397,7 @@ def param_as_nose_tuple(self, test_self, func, num, p):
# sure that the `self` in the method is properly shared with the
# `self` used in `setUp` and `tearDown`. But only there. Everyone
# else needs a bound method.
func_self = (
None if PY2 and detect_runner() == "nose" else
test_self
)
func_self = test_self
nose_func = make_method(nose_func, func_self, type(test_self))
return unbound_func, (nose_func, ) + p.args + (p.kwargs or {}, )

Expand Down Expand Up @@ -586,7 +553,7 @@ class TestUserAccessLevel(TestCase):
...
"""

if isinstance(attrs, string_types):
if isinstance(attrs, str):
attrs = [attrs]

input_dicts = (
Expand Down Expand Up @@ -633,13 +600,9 @@ def get_class_name_suffix(params_dict):
if "name" in params_dict:
return parameterized.to_safe_name(params_dict["name"])

params_vals = (
params_dict.values() if PY3 else
(v for (_, v) in sorted(params_dict.items()))
)
return parameterized.to_safe_name(next((
v for v in params_vals
if isinstance(v, string_types)
v for v in params_dict.values()
if isinstance(v, str)
), ""))


Expand All @@ -649,4 +612,4 @@ def default_class_name_func(cls, num, params_dict):
cls.__name__,
num,
suffix and "_" + suffix,
)
)
37 changes: 4 additions & 33 deletions src/sst/core/testingframework/sst_unittest_support.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,7 @@
import tarfile
import shutil
import difflib

PY2 = sys.version_info[0] == 2
PY3 = sys.version_info[0] == 3

# ConfigParser module changes name between Py2->Py3
if PY3:
import configparser
else:
import ConfigParser as configparser
import configparser

import test_engine_globals
from test_engine_support import OSCommand
Expand Down Expand Up @@ -179,24 +171,6 @@ def testing_is_PIN3_used():
# System Information Functions
################################################################################

def testing_check_is_py_2():
""" Check if Test Frameworks is running via Python Version 2
Returns:
(bool) True if test frameworks is being run by Python Version 2
"""
return PY2

def testing_check_is_py_3():
""" Check if Test Frameworks is running via Python Version 3
Returns:
(bool) True if test frameworks is being run by Python Version 3
"""
return PY3

###

def host_os_get_system_node_name():
""" Get the node name of the system
Expand Down Expand Up @@ -1478,13 +1452,10 @@ def os_awk_print(in_str, fields_index_list):
Returns:
(str) Space separated string of extracted fields.
"""
if PY2:
check_param_type("in_str", in_str, unicode)
if isinstance(in_str, bytes):
check_param_type("in_str", in_str, bytes)
else:
if isinstance(in_str, bytes):
check_param_type("in_str", in_str, bytes)
else:
check_param_type("in_str", in_str, str)
check_param_type("in_str", in_str, str)
check_param_type("fields_index_list", fields_index_list, list)
for index, field_index in enumerate(fields_index_list):
check_param_type("field_index - {0}".format(index), field_index, int)
Expand Down
10 changes: 1 addition & 9 deletions src/sst/core/testingframework/test_engine.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,7 @@
import unittest
import argparse
import shutil

PY2 = sys.version_info[0] == 2
PY3 = sys.version_info[0] == 3

# ConfigParser module changes name between Py2->Py3
if PY3:
import configparser
else:
import ConfigParser as configparser
import configparser

import test_engine_globals
from sst_unittest import *
Expand Down
43 changes: 6 additions & 37 deletions src/sst/core/testingframework/test_engine_junit.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,28 +48,9 @@
import xml.etree.ElementTree as ET
import xml.dom.minidom

#from six import u, iteritems, PY2
# The orig code uses 3rd party module "six".
# We dont want any external modules, so
# here are equivalent functions
PY2 = sys.version_info[0] == 2
PY3 = sys.version_info[0] == 3
if PY3:
unichr = chr
def _iteritems(_d, **kw):
""" Py3 iteritems() """
return iter(_d.items(**kw))
def _u(_s):
""" Py3 u() """
return _s
else:
unichr
def _iteritems(_d, **kw):
""" Py2 iteritems() """
return _d.iteritems(**kw)
def _u(_s):
""" Py2 u() """
return unicode(_s.replace(r'\\', r'\\\\'), "unicode_escape")
def _iteritems(_d, **kw):
""" Py3 iteritems() """
return iter(_d.items(**kw))

################################################################################

Expand Down Expand Up @@ -443,19 +424,7 @@ def _junit_decode(var, encoding):
"""
If not already unicode, decode it.
"""
if PY2:
if isinstance(var, unicode): # noqa: F821
ret = var
elif isinstance(var, str):
if encoding:
ret = var.decode(encoding)
else:
ret = unicode(var) # noqa: F821
else:
ret = unicode(var) # noqa: F821
else:
ret = str(var)
return ret
return str(var)

####

Expand Down Expand Up @@ -492,8 +461,8 @@ def _junit_clean_illegal_xml_chars(string_to_clean):
(0x10FFFE, 0x10FFFF),
]

illegal_ranges = ["%s-%s" % (unichr(low), unichr(high)) for \
illegal_ranges = ["%s-%s" % (chr(low), chr(high)) for \
(low, high) in illegal_unichrs if low < sys.maxunicode]

illegal_xml_re = re.compile(_u("[%s]") % _u("").join(illegal_ranges))
illegal_xml_re = re.compile("[%s]" % "".join(illegal_ranges))
return illegal_xml_re.sub("", string_to_clean)
21 changes: 6 additions & 15 deletions src/sst/core/testingframework/test_engine_support.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,6 @@
import ast
import inspect

PY2 = sys.version_info[0] == 2
PY3 = sys.version_info[0] == 3

import test_engine_globals

################################################################################
Expand Down Expand Up @@ -226,24 +223,18 @@ def result(self):
def output(self):
""" return the run output result """
# Sometimes the output can be a unicode or a byte string - convert it
if PY3:
if type(self._run_output) is bytes:
self._run_output = self._run_output.decode(encoding='UTF-8')
return self._run_output
else:
return self._run_output.decode('utf-8')
if isinstance(self._run_output, bytes):
self._run_output = self._run_output.decode(encoding='UTF-8')
return self._run_output

####

def error(self):
""" return the run error output result """
# Sometimes the output can be a unicode or a byte string - convert it
if PY3:
if type(self._run_error) is bytes:
self._run_error = self._run_error.decode(encoding='UTF-8')
return self._run_error
else:
return self._run_error.decode('utf-8')
if isinstance(self._run_error, bytes):
self._run_error = self._run_error.decode(encoding='UTF-8')
return self._run_error

####

Expand Down
Loading

0 comments on commit ae02be2

Please sign in to comment.