Skip to content

Commit 3814a60

Browse files
Merge pull request #1200 from sstsimulator/devel
Automatically Merged using SST Master Branch Merger
2 parents 595d990 + 969f846 commit 3814a60

File tree

2 files changed

+49
-124
lines changed

2 files changed

+49
-124
lines changed

src/sst/core/model/xmlToPython.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -79,16 +79,16 @@ def processParamSets(groups: ET.Element) -> None:
7979
for group in groups:
8080
params = dict()
8181
for p in group:
82-
params[getParamName(p)] = processString(p.text.strip()) # type: ignore
82+
params[getParamName(p)] = processString(p.text.strip()) # type: ignore [union-attr]
8383
sstParams[group.tag] = params
8484

8585

8686
def processVars(varNode: ET.Element) -> None:
8787
for var in varNode:
88-
sstVars[var.tag] = processString(var.text.strip()) # type: ignore
88+
sstVars[var.tag] = processString(var.text.strip()) # type: ignore [union-attr]
8989

9090
def processConfig(cfg: ET.Element) -> None:
91-
for line in cfg.text.strip().splitlines(): # type: ignore
91+
for line in cfg.text.strip().splitlines(): # type: ignore [union-attr]
9292
var, val = line.split('=')
9393
sst.setProgramOption(var, processString(val)) # strip quotes
9494

@@ -107,7 +107,7 @@ def buildComp(compNode: ET.Element) -> None:
107107
for paramInc in paramsNode.attrib['include'].split(','):
108108
params.update(sstParams[processString(paramInc)])
109109
for p in paramsNode:
110-
params[getParamName(p)] = processString(p.text.strip()) # type: ignore
110+
params[getParamName(p)] = processString(p.text.strip()) # type: ignore [union-attr]
111111

112112
comp.addParams(params)
113113

@@ -147,7 +147,7 @@ def build(root: ET.Element) -> None:
147147
if paramSets is not None:
148148
processParamSets(paramSets)
149149
if timebase is not None:
150-
sst.setProgramOption('timebase', timebase.text.strip()) # type: ignore
150+
sst.setProgramOption('timebase', timebase.text.strip()) # type: ignore [union-attr]
151151
if cfg is not None:
152152
processConfig(cfg)
153153
if graph is not None:

src/sst/core/testingframework/test_engine_support.py

Lines changed: 44 additions & 119 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
import inspect
2626
import signal
2727
from subprocess import TimeoutExpired
28-
from typing import Any, Dict, List, Optional
28+
from typing import Any, Dict, List, Optional, Type
2929

3030
import test_engine_globals
3131

@@ -40,8 +40,14 @@ class OSCommand:
4040
"""
4141
###
4242

43-
def __init__(self, cmd_str, output_file_path=None, error_file_path=None,
44-
set_cwd=None, use_shell=False):
43+
def __init__(
44+
self,
45+
cmd_str: str,
46+
output_file_path: Optional[str] = None,
47+
error_file_path: Optional[str] = None,
48+
set_cwd: Optional[str] = None,
49+
use_shell: bool = False,
50+
) -> None:
4551
"""
4652
Args:
4753
cmd_str (str): The command to be executed
@@ -55,10 +61,13 @@ def __init__(self, cmd_str, output_file_path=None, error_file_path=None,
5561
"""
5662
self._output_file_path = None
5763
self._error_file_path = None
58-
self._cmd_str = None
59-
self._process = None
64+
self._cmd_str = [""]
65+
self._process: subprocess.Popen[str] = None # type: ignore [assignment]
6066
self._timeout_sec = 60
61-
self._run_status = None
67+
# Use an invalid return code rather than None to identify an
68+
# unintialized value.
69+
self._run_status_sentinel = -999
70+
self._run_status = self._run_status_sentinel
6271
self._run_output = ''
6372
self._run_error = ''
6473
self._run_timeout = False
@@ -71,16 +80,20 @@ def __init__(self, cmd_str, output_file_path=None, error_file_path=None,
7180
self._signal_sec = 3
7281
####
7382

74-
def run(self, timeout_sec=60, send_signal=signal.NSIG, signal_sec=3, **kwargs):
83+
def run(self,
84+
timeout_sec: int = 60,
85+
send_signal: int = signal.NSIG,
86+
signal_sec: int = 3,
87+
**kwargs: Any,
88+
) -> "OSCommandResult":
7589
""" Run a command then return and OSCmdRtn object.
7690
7791
Args:
7892
timeout_sec (int): The maximum runtime in seconds before thread
7993
will be terminated and a timeout error will occur.
8094
kwargs: Extra parameters e.g., timeout_sec to override the default timeout
8195
"""
82-
if not (isinstance(timeout_sec, (int, float)) and not isinstance(timeout_sec, bool)):
83-
raise ValueError("ERROR: Timeout must be an int or a float")
96+
check_param_type("timeout_sec", timeout_sec, int)
8497

8598
self._timeout_sec = timeout_sec
8699
self._signal = send_signal
@@ -92,6 +105,7 @@ def run(self, timeout_sec=60, send_signal=signal.NSIG, signal_sec=3, **kwargs):
92105
thread.join(self._timeout_sec)
93106
if thread.is_alive():
94107
self._run_timeout = True
108+
assert self._process is not None
95109
self._process.kill()
96110
thread.join()
97111

@@ -102,7 +116,7 @@ def run(self, timeout_sec=60, send_signal=signal.NSIG, signal_sec=3, **kwargs):
102116

103117
####
104118

105-
def _run_cmd_in_subprocess(self, **kwargs):
119+
def _run_cmd_in_subprocess(self, **kwargs: Any) -> None:
106120
""" Run the command in a subprocess """
107121
file_out = None
108122
file_err = None
@@ -163,20 +177,17 @@ def _run_cmd_in_subprocess(self, **kwargs):
163177

164178
####
165179

166-
def _validate_cmd_str(self, cmd_str):
180+
def _validate_cmd_str(self, cmd_str: str) -> None:
167181
""" Validate the cmd_str """
168-
if isinstance(cmd_str, str):
169-
if cmd_str != "":
170-
cmd_str = shlex.split(cmd_str)
171-
else:
172-
raise ValueError("ERROR: OSCommand() cmd_str must not be empty")
173-
else:
182+
if not isinstance(cmd_str, str):
174183
raise ValueError("ERROR: OSCommand() cmd_str must be a string")
175-
self._cmd_str = cmd_str
184+
elif not cmd_str:
185+
raise ValueError("ERROR: OSCommand() cmd_str must not be empty")
186+
self._cmd_str = shlex.split(cmd_str)
176187

177188
####
178189

179-
def _validate_output_path(self, file_path):
190+
def _validate_output_path(self, file_path: Optional[str]) -> Optional[str]:
180191
""" Validate the output file path """
181192
if file_path is not None:
182193
dirpath = os.path.abspath(os.path.dirname(file_path))
@@ -188,12 +199,12 @@ def _validate_output_path(self, file_path):
188199

189200
################################################################################
190201

191-
class OSCommandResult():
202+
class OSCommandResult:
192203
""" This class returns result data about the OSCommand that was executed """
193-
def __init__(self, cmd_str, status, output, error, timeout):
204+
def __init__(self, cmd_str: List[str], status: int, output: str, error: str, timeout: bool) -> None:
194205
"""
195206
Args:
196-
cmd_str (str): The command to be executed
207+
cmd_str (list[str]): The command to be executed
197208
status (int): The return status of the command execution.
198209
output (str): The standard output of the command execution.
199210
error (str): The error output of the command execution.
@@ -207,7 +218,7 @@ def __init__(self, cmd_str, status, output, error, timeout):
207218

208219
####
209220

210-
def __repr__(self):
221+
def __repr__(self) -> str:
211222
rtn_str = (("Cmd = {0}; Status = {1}; Timeout = {2}; ") +
212223
("Error = {3}; Output = {4}")).format(self._run_cmd_str, \
213224
self._run_status, self._run_timeout, self._run_error, \
@@ -216,24 +227,24 @@ def __repr__(self):
216227

217228
####
218229

219-
def __str__(self):
230+
def __str__(self) -> str:
220231
return self.__repr__()
221232

222233
####
223234

224-
def cmd(self):
235+
def cmd(self) -> List[str]:
225236
""" return the command that was run """
226237
return self._run_cmd_str
227238

228239
####
229240

230-
def result(self):
241+
def result(self) -> int:
231242
""" return the run status result """
232243
return self._run_status
233244

234245
####
235246

236-
def output(self):
247+
def output(self) -> str:
237248
""" return the run output result """
238249
# Sometimes the output can be a unicode or a byte string - convert it
239250
if isinstance(self._run_output, bytes):
@@ -242,7 +253,7 @@ def output(self):
242253

243254
####
244255

245-
def error(self):
256+
def error(self) -> str:
246257
""" return the run error output result """
247258
# Sometimes the output can be a unicode or a byte string - convert it
248259
if isinstance(self._run_error, bytes):
@@ -251,13 +262,13 @@ def error(self):
251262

252263
####
253264

254-
def timeout(self):
265+
def timeout(self) -> bool:
255266
""" return true if the run timed out """
256267
return self._run_timeout
257268

258269
################################################################################
259270

260-
def check_param_type(varname, vardata, datatype):
271+
def check_param_type(varname: str, vardata: Any, datatype: Type[Any]) -> None:
261272
""" Validate a parameter to ensure it is of the correct type.
262273
263274
Args:
@@ -278,96 +289,10 @@ def check_param_type(varname, vardata, datatype):
278289

279290
################################################################################
280291

281-
def strclass(cls):
292+
def strclass(cls: Type[Any]) -> str:
282293
""" Return the classname of a class"""
283294
return "%s" % (cls.__module__)
284295

285-
def strqual(cls):
296+
def strqual(cls: Type[Any]) -> str:
286297
""" Return the qualname of a class"""
287-
return "%s" % (_qualname(cls))
288-
289-
################################################################################
290-
# qualname from https://github.com/wbolster/qualname to support Py2 and Py3
291-
# LICENSE -> https://github.com/wbolster/qualname/blob/master/LICENSE.rst
292-
#__all__ = ['qualname']
293-
294-
_cache = {}
295-
296-
def _qualname(obj):
297-
"""Find out the qualified name for a class or function."""
298-
299-
# For Python 3.3+, this is straight-forward.
300-
if hasattr(obj, '__qualname__'):
301-
return obj.__qualname__
302-
303-
# For older Python versions, things get complicated.
304-
# Obtain the filename and the line number where the
305-
# class/method/function is defined.
306-
try:
307-
filename = inspect.getsourcefile(obj)
308-
except TypeError:
309-
return obj.__qualname__ # raises a sensible error
310-
if not filename:
311-
return obj.__qualname__ # raises a sensible error
312-
if inspect.isclass(obj):
313-
try:
314-
_, lineno = inspect.getsourcelines(obj)
315-
except (OSError, IOError):
316-
return obj.__qualname__ # raises a sensible error
317-
elif inspect.isfunction(obj) or inspect.ismethod(obj):
318-
if hasattr(obj, 'im_func'):
319-
# Extract function from unbound method (Python 2)
320-
obj = obj.im_func
321-
try:
322-
code = obj.__code__
323-
except AttributeError:
324-
code = obj.func_code
325-
lineno = code.co_firstlineno
326-
else:
327-
return obj.__qualname__ # raises a sensible error
328-
329-
# Re-parse the source file to figure out what the
330-
# __qualname__ should be by analysing the abstract
331-
# syntax tree. Use a cache to avoid doing this more
332-
# than once for the same file.
333-
qualnames = _cache.get(filename)
334-
if qualnames is None:
335-
with open(filename, 'r') as filehandle:
336-
source = filehandle.read()
337-
node = ast.parse(source, filename)
338-
visitor = _Visitor()
339-
visitor.visit(node)
340-
_cache[filename] = qualnames = visitor.qualnames
341-
try:
342-
return qualnames[lineno]
343-
except KeyError:
344-
return obj.__qualname__ # raises a sensible error
345-
346-
347-
class _Visitor(ast.NodeVisitor):
348-
"""Support class for qualname function"""
349-
def __init__(self):
350-
super(_Visitor, self).__init__()
351-
self.stack = []
352-
self.qualnames = {}
353-
354-
def store_qualname(self, lineno):
355-
"""Support method for _Visitor class"""
356-
q_n = ".".join(n for n in self.stack)
357-
self.qualnames[lineno] = q_n
358-
359-
def visit_FunctionDef(self, node):
360-
"""Support method for _Visitor class"""
361-
self.stack.append(node.name)
362-
self.store_qualname(node.lineno)
363-
self.stack.append('<locals>')
364-
self.generic_visit(node)
365-
self.stack.pop()
366-
self.stack.pop()
367-
368-
def visit_ClassDef(self, node):
369-
"""Support method for _Visitor class"""
370-
self.stack.append(node.name)
371-
self.store_qualname(node.lineno)
372-
self.generic_visit(node)
373-
self.stack.pop()
298+
return "%s" % (cls.__qualname__)

0 commit comments

Comments
 (0)