diff --git a/lib/ramble/external/archspec/cpu/detect.py b/lib/ramble/external/archspec/cpu/detect.py index 3df04585c..56bc22960 100644 --- a/lib/ramble/external/archspec/cpu/detect.py +++ b/lib/ramble/external/archspec/cpu/detect.py @@ -11,8 +11,6 @@ import subprocess import warnings -import six - from .microarchitecture import generic_microarchitecture, TARGETS from .schema import TARGETS_JSON @@ -83,7 +81,7 @@ def _check_output(args, env): output = subprocess.Popen( # pylint: disable=consider-using-with args, stdout=subprocess.PIPE, env=env ).communicate()[0] - return six.text_type(output.decode("utf-8")) + return str(output.decode("utf-8")) def _machine(): @@ -267,7 +265,7 @@ def compatibility_check(architecture_family): this test can be used, e.g. x86_64 or ppc64le etc. """ # Turn the argument into something iterable - if isinstance(architecture_family, six.string_types): + if isinstance(architecture_family, str): architecture_family = (architecture_family,) def decorator(func): diff --git a/lib/ramble/external/archspec/cpu/microarchitecture.py b/lib/ramble/external/archspec/cpu/microarchitecture.py index 410d83c3d..207721b2f 100644 --- a/lib/ramble/external/archspec/cpu/microarchitecture.py +++ b/lib/ramble/external/archspec/cpu/microarchitecture.py @@ -11,8 +11,6 @@ import re import warnings -import six - import archspec import archspec.cpu.alias import archspec.cpu.schema @@ -27,7 +25,7 @@ def coerce_target_names(func): @functools.wraps(func) def _impl(self, other): - if isinstance(other, six.string_types): + if isinstance(other, str): if other not in TARGETS: msg = '"{0}" is not a valid target name' raise ValueError(msg.format(other)) @@ -150,7 +148,7 @@ def __str__(self): def __contains__(self, feature): # Feature must be of a string type, so be defensive about that - if not isinstance(feature, six.string_types): + if not isinstance(feature, str): msg = "only objects of string types are accepted [got {0}]" raise TypeError(msg.format(str(type(feature)))) diff --git a/lib/ramble/external/ctest_log_parser.py b/lib/ramble/external/ctest_log_parser.py index 072c10d7a..cb629e305 100644 --- a/lib/ramble/external/ctest_log_parser.py +++ b/lib/ramble/external/ctest_log_parser.py @@ -71,12 +71,10 @@ import re import math import multiprocessing +import io import time from contextlib import contextmanager -from six import StringIO -from six import string_types - class prefilter(object): """Make regular expressions faster with a simple prefiltering predicate. @@ -282,7 +280,7 @@ def __getitem__(self, line_no): def __str__(self): """Returns event lines and context.""" - out = StringIO() + out = io.StringIO() for i in range(self.start, self.end): if i == self.line_no: out.write(' >> %-6d%s' % (i, self[i])) @@ -423,7 +421,7 @@ def parse(self, stream, context=6, jobs=None): (tuple): two lists containing ``BuildError`` and ``BuildWarning`` objects. """ - if isinstance(stream, string_types): + if isinstance(stream, str): with open(stream) as f: return self.parse(f, context, jobs) diff --git a/lib/ramble/external/py/__init__.py b/lib/ramble/external/py/__init__.py index 85af650f5..b892ce1a2 100644 --- a/lib/ramble/external/py/__init__.py +++ b/lib/ramble/external/py/__init__.py @@ -8,21 +8,27 @@ (c) Holger Krekel and others, 2004-2014 """ -__version__ = '1.4.34' +from py._error import error -from py import _apipkg +try: + from py._vendored_packages import apipkg + lib_not_mangled_by_packagers = True + vendor_prefix = '._vendored_packages.' +except ImportError: + import apipkg + lib_not_mangled_by_packagers = False + vendor_prefix = '' -# so that py.error.* instances are picklable -import sys -sys.modules['py.error'] = _apipkg.AliasModule("py.error", "py._error", 'error') -import py.error # "Dereference" it now just to be safe (issue110) +try: + from ._version import version as __version__ +except ImportError: + # broken installation, we don't even try + __version__ = "unknown" -_apipkg.initpkg(__name__, attr={'_apipkg': _apipkg}, exportdefs={ +apipkg.initpkg(__name__, attr={'_apipkg': apipkg, 'error': error}, exportdefs={ # access to all standard lib modules 'std': '._std:std', - # access to all posix errno's as classes - 'error': '._error:error', '_pydir' : '.__metainfo:pydir', 'version': 'py:__version__', # backward compatibility @@ -30,8 +36,6 @@ # pytest-2.0 has a flat namespace, we use alias modules # to keep old references compatible 'test' : 'pytest', - 'test.collect' : 'pytest', - 'test.cmdline' : 'pytest', # hook into the top-level standard library 'process' : { @@ -42,13 +46,13 @@ }, 'apipkg' : { - 'initpkg' : '._apipkg:initpkg', - 'ApiModule' : '._apipkg:ApiModule', + 'initpkg' : vendor_prefix + 'apipkg:initpkg', + 'ApiModule' : vendor_prefix + 'apipkg:ApiModule', }, 'iniconfig' : { - 'IniConfig' : '._iniconfig:IniConfig', - 'ParseError' : '._iniconfig:ParseError', + 'IniConfig' : vendor_prefix + 'iniconfig:IniConfig', + 'ParseError' : vendor_prefix + 'iniconfig:ParseError', }, 'path' : { diff --git a/lib/ramble/external/py/__init__.pyi b/lib/ramble/external/py/__init__.pyi new file mode 100644 index 000000000..96859e310 --- /dev/null +++ b/lib/ramble/external/py/__init__.pyi @@ -0,0 +1,20 @@ +from typing import Any + +# py allows to use e.g. py.path.local even without importing py.path. +# So import implicitly. +from . import error +from . import iniconfig +from . import path +from . import io +from . import xml + +__version__: str + +# Untyped modules below here. +std: Any +test: Any +process: Any +apipkg: Any +code: Any +builtin: Any +log: Any diff --git a/lib/ramble/external/py/_builtin.py b/lib/ramble/external/py/_builtin.py index 52ee9d79c..ddc89fc7b 100644 --- a/lib/ramble/external/py/_builtin.py +++ b/lib/ramble/external/py/_builtin.py @@ -1,120 +1,21 @@ import sys -try: - reversed = reversed -except NameError: - def reversed(sequence): - """reversed(sequence) -> reverse iterator over values of the sequence - - Return a reverse iterator - """ - if hasattr(sequence, '__reversed__'): - return sequence.__reversed__() - if not hasattr(sequence, '__getitem__'): - raise TypeError("argument to reversed() must be a sequence") - return reversed_iterator(sequence) - - class reversed_iterator(object): - - def __init__(self, seq): - self.seq = seq - self.remaining = len(seq) - - def __iter__(self): - return self - - def next(self): - i = self.remaining - if i > 0: - i -= 1 - item = self.seq[i] - self.remaining = i - return item - raise StopIteration - - def __length_hint__(self): - return self.remaining - -try: - any = any -except NameError: - def any(iterable): - for x in iterable: - if x: - return True - return False - -try: - all = all -except NameError: - def all(iterable): - for x in iterable: - if not x: - return False - return True - -try: - sorted = sorted -except NameError: - builtin_cmp = cmp # need to use cmp as keyword arg - - def sorted(iterable, cmp=None, key=None, reverse=0): - use_cmp = None - if key is not None: - if cmp is None: - def use_cmp(x, y): - return builtin_cmp(x[0], y[0]) - else: - def use_cmp(x, y): - return cmp(x[0], y[0]) - l = [(key(element), element) for element in iterable] - else: - if cmp is not None: - use_cmp = cmp - l = list(iterable) - if use_cmp is not None: - l.sort(use_cmp) - else: - l.sort() - if reverse: - l.reverse() - if key is not None: - return [element for (_, element) in l] - return l - -try: - set, frozenset = set, frozenset -except NameError: - from sets import set, frozenset - -# pass through -enumerate = enumerate - -try: - BaseException = BaseException -except NameError: - BaseException = Exception - -try: - GeneratorExit = GeneratorExit -except NameError: - class GeneratorExit(Exception): - """ This exception is never raised, it is there to make it possible to - write code compatible with CPython 2.5 even in lower CPython - versions.""" - pass - GeneratorExit.__module__ = 'exceptions' +# Passthrough for builtins supported with py27. +BaseException = BaseException +GeneratorExit = GeneratorExit _sysex = (KeyboardInterrupt, SystemExit, MemoryError, GeneratorExit) +all = all +any = any +callable = callable +enumerate = enumerate +reversed = reversed +set, frozenset = set, frozenset +sorted = sorted -try: - callable = callable -except NameError: - def callable(obj): - return hasattr(obj, "__call__") if sys.version_info >= (3, 0): - exec ("print_ = print ; exec_=exec") + exec("print_ = print ; exec_=exec") import builtins # some backward compatibility helpers @@ -131,13 +32,13 @@ def _totext(obj, encoding=None, errors=None): def _isbytes(x): return isinstance(x, bytes) + def _istext(x): return isinstance(x, str) text = str bytes = bytes - def _getimself(function): return getattr(function, '__self__', None) diff --git a/lib/ramble/external/py/_code/_assertionnew.py b/lib/ramble/external/py/_code/_assertionnew.py index afb1b31ff..d03f29d87 100644 --- a/lib/ramble/external/py/_code/_assertionnew.py +++ b/lib/ramble/external/py/_code/_assertionnew.py @@ -10,27 +10,10 @@ from py._code.assertion import _format_explanation, BuiltinAssertionError -if sys.platform.startswith("java") and sys.version_info < (2, 5, 2): - # See http://bugs.jython.org/issue1497 - _exprs = ("BoolOp", "BinOp", "UnaryOp", "Lambda", "IfExp", "Dict", - "ListComp", "GeneratorExp", "Yield", "Compare", "Call", - "Repr", "Num", "Str", "Attribute", "Subscript", "Name", - "List", "Tuple") - _stmts = ("FunctionDef", "ClassDef", "Return", "Delete", "Assign", - "AugAssign", "Print", "For", "While", "If", "With", "Raise", - "TryExcept", "TryFinally", "Assert", "Import", "ImportFrom", - "Exec", "Global", "Expr", "Pass", "Break", "Continue") - _expr_nodes = set(getattr(ast, name) for name in _exprs) - _stmt_nodes = set(getattr(ast, name) for name in _stmts) - def _is_ast_expr(node): - return node.__class__ in _expr_nodes - def _is_ast_stmt(node): - return node.__class__ in _stmt_nodes -else: - def _is_ast_expr(node): - return isinstance(node, ast.expr) - def _is_ast_stmt(node): - return isinstance(node, ast.stmt) +def _is_ast_expr(node): + return isinstance(node, ast.expr) +def _is_ast_stmt(node): + return isinstance(node, ast.stmt) class Failure(Exception): diff --git a/lib/ramble/external/py/_code/_assertionold.py b/lib/ramble/external/py/_code/_assertionold.py index 4e81fb3ef..1bb70a875 100644 --- a/lib/ramble/external/py/_code/_assertionold.py +++ b/lib/ramble/external/py/_code/_assertionold.py @@ -2,6 +2,7 @@ import sys, inspect from compiler import parse, ast, pycodegen from py._code.assertion import BuiltinAssertionError, _format_explanation +import types passthroughex = py.builtin._sysex @@ -470,7 +471,7 @@ def check(s, frame=None): def interpret(source, frame, should_fail=False): module = Interpretable(parse(source, 'exec').node) #print "got module", module - if isinstance(frame, py.std.types.FrameType): + if isinstance(frame, types.FrameType): frame = py.code.Frame(frame) try: module.run(frame) diff --git a/lib/ramble/external/py/_code/assertion.py b/lib/ramble/external/py/_code/assertion.py index 4ce80c75b..ff1643799 100644 --- a/lib/ramble/external/py/_code/assertion.py +++ b/lib/ramble/external/py/_code/assertion.py @@ -87,8 +87,4 @@ def __init__(self, *args): reinterpret_old = "old reinterpretation not available for py3" else: from py._code._assertionold import interpret as reinterpret_old -if sys.version_info >= (2, 6) or (sys.platform.startswith("java")): - from py._code._assertionnew import interpret as reinterpret -else: - reinterpret = reinterpret_old - +from py._code._assertionnew import interpret as reinterpret diff --git a/lib/ramble/external/py/_code/code.py b/lib/ramble/external/py/_code/code.py index 20fd965c9..dad796283 100644 --- a/lib/ramble/external/py/_code/code.py +++ b/lib/ramble/external/py/_code/code.py @@ -1,6 +1,6 @@ import py import sys -from inspect import CO_VARARGS, CO_VARKEYWORDS +from inspect import CO_VARARGS, CO_VARKEYWORDS, isclass builtin_repr = repr @@ -11,6 +11,9 @@ else: from py._code._py2traceback import format_exception_only +import traceback + + class Code(object): """ wrapper around Python code objects """ def __init__(self, rawcode): @@ -21,7 +24,7 @@ def __init__(self, rawcode): self.firstlineno = rawcode.co_firstlineno - 1 self.name = rawcode.co_name except AttributeError: - raise TypeError("not a code object: %r" %(rawcode,)) + raise TypeError("not a code object: %r" % (rawcode,)) self.raw = rawcode def __eq__(self, other): @@ -106,7 +109,7 @@ def exec_(self, code, **vars): """ f_locals = self.f_locals.copy() f_locals.update(vars) - py.builtin.exec_(code, self.f_globals, f_locals ) + py.builtin.exec_(code, self.f_globals, f_locals) def repr(self, object): """ return a 'safe' (non-recursive, one-line) string repr for 'object' @@ -130,6 +133,7 @@ def getargs(self, var=False): pass # this can occur when using Psyco return retval + class TracebackEntry(object): """ a single entry in a traceback """ @@ -153,7 +157,7 @@ def relline(self): return self.lineno - self.frame.code.firstlineno def __repr__(self): - return "" %(self.frame.code.path, self.lineno+1) + return "" % (self.frame.code.path, self.lineno+1) @property def statement(self): @@ -237,17 +241,19 @@ def __str__(self): raise except: line = "???" - return " File %r:%d in %s\n %s\n" %(fn, self.lineno+1, name, line) + return " File %r:%d in %s\n %s\n" % (fn, self.lineno+1, name, line) def name(self): return self.frame.code.raw.co_name name = property(name, None, None, "co_name of underlaying code") + class Traceback(list): """ Traceback objects encapsulate and offer higher level access to Traceback entries. """ Entry = TracebackEntry + def __init__(self, tb): """ initialize from given python traceback object. """ if hasattr(tb, 'tb_next'): @@ -362,7 +368,8 @@ def __init__(self, tup=None, exprinfo=None): self.traceback = py.code.Traceback(self.tb) def __repr__(self): - return "" % (self.typename, len(self.traceback)) + return "" % ( + self.typename, len(self.traceback)) def exconly(self, tryshort=False): """ return the exception as a string @@ -391,7 +398,7 @@ def _getreprcrash(self): return ReprFileLocation(path, lineno+1, exconly) def getrepr(self, showlocals=False, style="long", - abspath=False, tbfilter=True, funcargs=False): + abspath=False, tbfilter=True, funcargs=False): """ return str()able representation of this exception info. showlocals: show locals per traceback entry style: long|short|no|native traceback style @@ -401,13 +408,14 @@ def getrepr(self, showlocals=False, style="long", """ if style == 'native': return ReprExceptionInfo(ReprTracebackNative( - py.std.traceback.format_exception( + traceback.format_exception( self.type, self.value, self.traceback[0]._rawentry, )), self._getreprcrash()) - fmt = FormattedExcinfo(showlocals=showlocals, style=style, + fmt = FormattedExcinfo( + showlocals=showlocals, style=style, abspath=abspath, tbfilter=tbfilter, funcargs=funcargs) return fmt.repr_excinfo(self) @@ -428,7 +436,8 @@ class FormattedExcinfo(object): flow_marker = ">" fail_marker = "E" - def __init__(self, showlocals=False, style="long", abspath=True, tbfilter=True, funcargs=False): + def __init__(self, showlocals=False, style="long", + abspath=True, tbfilter=True, funcargs=False): self.showlocals = showlocals self.style = style self.tbfilter = tbfilter @@ -521,7 +530,7 @@ def repr_locals(self, locals): #else: # self._line("%-10s =\\" % (name,)) # # XXX - # py.std.pprint.pprint(value, stream=self.excinfowriter) + # pprint.pprint(value, stream=self.excinfowriter) return ReprLocals(lines) def repr_traceback_entry(self, entry, excinfo=None): @@ -779,7 +788,7 @@ def getrawcode(obj, trycall=True): obj = getattr(obj, 'f_code', obj) obj = getattr(obj, '__code__', obj) if trycall and not hasattr(obj, 'co_firstlineno'): - if hasattr(obj, '__call__') and not py.std.inspect.isclass(obj): + if hasattr(obj, '__call__') and not isclass(obj): x = getrawcode(obj.__call__, trycall=False) if hasattr(x, 'co_firstlineno'): return x diff --git a/lib/ramble/external/py/_code/source.py b/lib/ramble/external/py/_code/source.py index c8b668b2f..7fc7b23a9 100644 --- a/lib/ramble/external/py/_code/source.py +++ b/lib/ramble/external/py/_code/source.py @@ -193,7 +193,8 @@ def compile(self, filename=None, mode='exec', if flag & _AST_FLAG: return co lines = [(x + "\n") for x in self.lines] - py.std.linecache.cache[filename] = (1, None, lines, filename) + import linecache + linecache.cache[filename] = (1, None, lines, filename) return co # @@ -224,8 +225,8 @@ def getfslineno(obj): code = py.code.Code(obj) except TypeError: try: - fn = (py.std.inspect.getsourcefile(obj) or - py.std.inspect.getfile(obj)) + fn = (inspect.getsourcefile(obj) or + inspect.getfile(obj)) except TypeError: return "", -1 @@ -248,7 +249,7 @@ def getfslineno(obj): def findsource(obj): try: - sourcelines, lineno = py.std.inspect.findsource(obj) + sourcelines, lineno = inspect.findsource(obj) except py.builtin._sysex: raise except: @@ -334,8 +335,6 @@ def get_statement_startend2(lineno, node): def getstatementrange_ast(lineno, source, assertion=False, astnode=None): if astnode is None: content = str(source) - if sys.version_info < (2,7): - content += "\n" try: astnode = compile(content, "source", "exec", 1024) # 1024 for AST except ValueError: diff --git a/lib/ramble/external/py/_error.py b/lib/ramble/external/py/_error.py index 8ca339beb..a6375de9f 100644 --- a/lib/ramble/external/py/_error.py +++ b/lib/ramble/external/py/_error.py @@ -2,6 +2,7 @@ create errno-specific classes for IO or os calls. """ +from types import ModuleType import sys, os, errno class Error(EnvironmentError): @@ -31,7 +32,7 @@ def __str__(self): 5: errno.EACCES, # anything better? } -class ErrorMaker(object): +class ErrorMaker(ModuleType): """ lazily provides Exception classes for each possible POSIX errno (as defined per the 'errno' module). All such instances subclass EnvironmentError. @@ -86,4 +87,5 @@ def checked_call(self, func, *args, **kwargs): __tracebackhide__ = True -error = ErrorMaker() +error = ErrorMaker('py.error') +sys.modules[error.__name__] = error \ No newline at end of file diff --git a/lib/ramble/external/py/_io/capture.py b/lib/ramble/external/py/_io/capture.py index bc157ed97..cacf2fa71 100644 --- a/lib/ramble/external/py/_io/capture.py +++ b/lib/ramble/external/py/_io/capture.py @@ -13,7 +13,7 @@ class TextIO(StringIO): def write(self, data): if not isinstance(data, unicode): data = unicode(data, getattr(self, '_encoding', 'UTF-8'), 'replace') - StringIO.write(self, data) + return StringIO.write(self, data) else: TextIO = StringIO @@ -24,7 +24,7 @@ class BytesIO(StringIO): def write(self, data): if isinstance(data, unicode): raise TypeError("not a byte value: %r" %(data,)) - StringIO.write(self, data) + return StringIO.write(self, data) patchsysdict = {0: 'stdin', 1: 'stdout', 2: 'stderr'} @@ -266,7 +266,7 @@ def readouterr(self): err = self._readsnapshot(self.err.tmpfile) else: err = "" - return [out, err] + return out, err def _readsnapshot(self, f): f.seek(0) diff --git a/lib/ramble/external/py/_io/terminalwriter.py b/lib/ramble/external/py/_io/terminalwriter.py index 390e8ca7b..442ca2395 100644 --- a/lib/ramble/external/py/_io/terminalwriter.py +++ b/lib/ramble/external/py/_io/terminalwriter.py @@ -5,9 +5,10 @@ """ -import sys, os +import sys, os, unicodedata import py py3k = sys.version_info[0] >= 3 +py33 = sys.version_info >= (3, 3) from py.builtin import text, bytes win32_and_ctypes = False @@ -24,16 +25,21 @@ def _getdimensions(): - import termios,fcntl,struct - call = fcntl.ioctl(1,termios.TIOCGWINSZ,"\000"*8) - height,width = struct.unpack( "hhhh", call ) [:2] - return height, width + if py33: + import shutil + size = shutil.get_terminal_size() + return size.lines, size.columns + else: + import termios, fcntl, struct + call = fcntl.ioctl(1, termios.TIOCGWINSZ, "\000" * 8) + height, width = struct.unpack("hhhh", call)[:2] + return height, width def get_terminal_width(): - height = width = 0 + width = 0 try: - height, width = _getdimensions() + _, width = _getdimensions() except py.builtin._sysex: raise except: @@ -53,6 +59,21 @@ def get_terminal_width(): terminal_width = get_terminal_width() +char_width = { + 'A': 1, # "Ambiguous" + 'F': 2, # Fullwidth + 'H': 1, # Halfwidth + 'N': 1, # Neutral + 'Na': 1, # Narrow + 'W': 2, # Wide +} + + +def get_line_width(text): + text = unicodedata.normalize('NFC', text) + return sum(char_width.get(unicodedata.east_asian_width(c), 1) for c in text) + + # XXX unify with _escaped func below def ansi_print(text, esc, file=None, newline=True, flush=False): if file is None: @@ -112,6 +133,8 @@ def should_do_markup(file): return True if os.environ.get('PY_COLORS') == '0': return False + if 'NO_COLOR' in os.environ: + return False return hasattr(file, 'isatty') and file.isatty() \ and os.environ.get('TERM') != 'dumb' \ and not (sys.platform.startswith('java') and os._name == 'nt') @@ -129,7 +152,7 @@ def __init__(self, file=None, stringio=False, encoding=None): if stringio: self.stringio = file = py.io.TextIO() else: - file = py.std.sys.stdout + from sys import stdout as file elif py.builtin.callable(file) and not ( hasattr(file, "write") and hasattr(file, "flush")): file = WriteFile(file, encoding=encoding) @@ -139,6 +162,8 @@ def __init__(self, file=None, stringio=False, encoding=None): self._file = file self.hasmarkup = should_do_markup(file) self._lastlen = 0 + self._chars_on_current_line = 0 + self._width_of_current_line = 0 @property def fullwidth(self): @@ -150,6 +175,29 @@ def fullwidth(self): def fullwidth(self, value): self._terminal_width = value + @property + def chars_on_current_line(self): + """Return the number of characters written so far in the current line. + + Please note that this count does not produce correct results after a reline() call, + see #164. + + .. versionadded:: 1.5.0 + + :rtype: int + """ + return self._chars_on_current_line + + @property + def width_of_current_line(self): + """Return an estimate of the width so far in the current line. + + .. versionadded:: 1.6.0 + + :rtype: int + """ + return self._width_of_current_line + def _escaped(self, text, esc): if esc and self.hasmarkup: text = (''.join(['\x1b[%sm' % cod for cod in esc]) + @@ -181,7 +229,7 @@ def sep(self, sepchar, title=None, fullwidth=None, **kw): # i.e. 2 + 2*len(sepchar)*N + len(title) <= fullwidth # 2*len(sepchar)*N <= fullwidth - len(title) - 2 # N <= (fullwidth - len(title) - 2) // (2*len(sepchar)) - N = (fullwidth - len(title) - 2) // (2*len(sepchar)) + N = max((fullwidth - len(title) - 2) // (2*len(sepchar)), 1) fill = sepchar * N line = "%s %s %s" % (fill, title, fill) else: @@ -200,12 +248,27 @@ def write(self, msg, **kw): if msg: if not isinstance(msg, (bytes, text)): msg = text(msg) + + self._update_chars_on_current_line(msg) + if self.hasmarkup and kw: markupmsg = self.markup(msg, **kw) else: markupmsg = msg write_out(self._file, markupmsg) + def _update_chars_on_current_line(self, text_or_bytes): + newline = b'\n' if isinstance(text_or_bytes, bytes) else '\n' + current_line = text_or_bytes.rsplit(newline, 1)[-1] + if isinstance(current_line, bytes): + current_line = current_line.decode('utf-8', errors='replace') + if newline in text_or_bytes: + self._chars_on_current_line = len(current_line) + self._width_of_current_line = get_line_width(current_line) + else: + self._chars_on_current_line += len(current_line) + self._width_of_current_line += get_line_width(current_line) + def line(self, s='', **kw): self.write(s, **kw) self._checkfill(s) @@ -229,6 +292,9 @@ def write(self, msg, **kw): if msg: if not isinstance(msg, (bytes, text)): msg = text(msg) + + self._update_chars_on_current_line(msg) + oldcolors = None if self.hasmarkup and kw: handle = GetStdHandle(STD_OUTPUT_HANDLE) diff --git a/lib/ramble/external/py/_log/log.py b/lib/ramble/external/py/_log/log.py index ce47e8c75..56969bcb5 100644 --- a/lib/ramble/external/py/_log/log.py +++ b/lib/ramble/external/py/_log/log.py @@ -14,7 +14,9 @@ debug=py.log.STDOUT, command=None) """ -import py, sys +import py +import sys + class Message(object): def __init__(self, keywords, args): @@ -70,6 +72,7 @@ def __init__(self): def getstate(self): return self.keywords2consumer.copy() + def setstate(self, state): self.keywords2consumer.clear() self.keywords2consumer.update(state) @@ -104,17 +107,22 @@ def setconsumer(self, keywords, consumer): consumer = File(consumer) self.keywords2consumer[keywords] = consumer + def default_consumer(msg): """ the default consumer, prints the message to stdout (using 'print') """ sys.stderr.write(str(msg)+"\n") default_keywordmapper = KeywordMapper() + def setconsumer(keywords, consumer): default_keywordmapper.setconsumer(keywords, consumer) + def setstate(state): default_keywordmapper.setstate(state) + + def getstate(): return default_keywordmapper.getstate() @@ -122,11 +130,12 @@ def getstate(): # Consumers # + class File(object): """ log consumer wrapping a file(-like) object """ def __init__(self, f): assert hasattr(f, 'write') - #assert isinstance(f, file) or not hasattr(f, 'open') + # assert isinstance(f, file) or not hasattr(f, 'open') self._file = f def __call__(self, msg): @@ -135,6 +144,7 @@ def __call__(self, msg): if hasattr(self._file, 'flush'): self._file.flush() + class Path(object): """ log consumer that opens and writes to a Path """ def __init__(self, filename, append=False, @@ -158,29 +168,39 @@ def __call__(self, msg): if not self._buffering: self._file.flush() + def STDOUT(msg): """ consumer that writes to sys.stdout """ sys.stdout.write(str(msg)+"\n") + def STDERR(msg): """ consumer that writes to sys.stderr """ sys.stderr.write(str(msg)+"\n") + class Syslog: """ consumer that writes to the syslog daemon """ - def __init__(self, priority = None): + def __init__(self, priority=None): if priority is None: priority = self.LOG_INFO self.priority = priority def __call__(self, msg): """ write a message to the log """ - py.std.syslog.syslog(self.priority, str(msg)) - -for _prio in "EMERG ALERT CRIT ERR WARNING NOTICE INFO DEBUG".split(): - _prio = "LOG_" + _prio - try: - setattr(Syslog, _prio, getattr(py.std.syslog, _prio)) - except AttributeError: - pass + import syslog + syslog.syslog(self.priority, str(msg)) + + +try: + import syslog +except ImportError: + pass +else: + for _prio in "EMERG ALERT CRIT ERR WARNING NOTICE INFO DEBUG".split(): + _prio = "LOG_" + _prio + try: + setattr(Syslog, _prio, getattr(syslog, _prio)) + except AttributeError: + pass diff --git a/lib/ramble/external/py/_log/warning.py b/lib/ramble/external/py/_log/warning.py index 722e31e91..6ef20d98a 100644 --- a/lib/ramble/external/py/_log/warning.py +++ b/lib/ramble/external/py/_log/warning.py @@ -32,9 +32,11 @@ def _apiwarn(startversion, msg, stacklevel=2, function=None): msg = "%s (since version %s)" %(msg, startversion) warn(msg, stacklevel=stacklevel+1, function=function) + def warn(msg, stacklevel=1, function=None): if function is not None: - filename = py.std.inspect.getfile(function) + import inspect + filename = inspect.getfile(function) lineno = py.code.getrawcode(function).co_firstlineno else: try: @@ -67,10 +69,11 @@ def warn(msg, stacklevel=1, function=None): filename = module path = py.path.local(filename) warning = DeprecationWarning(msg, path, lineno) - py.std.warnings.warn_explicit(warning, category=Warning, + import warnings + warnings.warn_explicit(warning, category=Warning, filename=str(warning.path), lineno=warning.lineno, - registry=py.std.warnings.__dict__.setdefault( + registry=warnings.__dict__.setdefault( "__warningsregistry__", {}) ) diff --git a/lib/ramble/external/py/_path/common.py b/lib/ramble/external/py/_path/common.py index 5512e51ef..2364e5fef 100644 --- a/lib/ramble/external/py/_path/common.py +++ b/lib/ramble/external/py/_path/common.py @@ -1,12 +1,21 @@ """ """ -import os, sys, posixpath +import warnings +import os +import sys +import posixpath import fnmatch import py # Moved from local.py. iswin32 = sys.platform == "win32" or (getattr(os, '_name', False) == 'nt') +try: + # FileNotFoundError might happen in py34, and is not available with py27. + import_errors = (ImportError, FileNotFoundError) +except NameError: + import_errors = (ImportError,) + try: from os import fspath except ImportError: @@ -32,7 +41,7 @@ def fspath(path): raise try: import pathlib - except ImportError: + except import_errors: pass else: if isinstance(path, pathlib.PurePath): @@ -189,14 +198,16 @@ def load(self): """ (deprecated) return object unpickled from self.read() """ f = self.open('rb') try: - return py.error.checked_call(py.std.pickle.load, f) + import pickle + return py.error.checked_call(pickle.load, f) finally: f.close() def move(self, target): """ move this path to target. """ if target.relto(self): - raise py.error.EINVAL(target, + raise py.error.EINVAL( + target, "cannot move path into a subdirectory of itself") try: self.rename(target) @@ -226,7 +237,7 @@ def check(self, **kw): path.check(file=1, link=1) # a link pointing to a file """ if not kw: - kw = {'exists' : 1} + kw = {'exists': 1} return self.Checkers(self)._evaluate(kw) def fnmatch(self, pattern): @@ -375,6 +386,9 @@ def visit(self, fil=None, rec=None, ignore=NeverRaised, bf=False, sort=False): def _sortlist(self, res, sort): if sort: if hasattr(sort, '__call__'): + warnings.warn(DeprecationWarning( + "listdir(sort=callable) is deprecated and breaks on python3" + ), stacklevel=3) res.sort(sort) else: res.sort() diff --git a/lib/ramble/external/py/_path/local.py b/lib/ramble/external/py/_path/local.py index 2ffdaddf0..1385a0398 100644 --- a/lib/ramble/external/py/_path/local.py +++ b/lib/ramble/external/py/_path/local.py @@ -4,13 +4,13 @@ from __future__ import with_statement from contextlib import contextmanager -import sys, os, re, atexit, io +import sys, os, atexit, io, uuid import py from py._path import common from py._path.common import iswin32, fspath from stat import S_ISLNK, S_ISDIR, S_ISREG -from os.path import abspath, normcase, normpath, isabs, exists, isdir, isfile, islink, dirname +from os.path import abspath, normpath, isabs, exists, isdir, isfile, islink, dirname if sys.version_info > (3,0): def map_as_list(func, iter): @@ -18,6 +18,11 @@ def map_as_list(func, iter): else: map_as_list = map +ALLOW_IMPORTLIB_MODE = sys.version_info > (3,5) +if ALLOW_IMPORTLIB_MODE: + import importlib + + class Stat(object): def __getattr__(self, name): return getattr(self._osstatresult, "st_" + name) @@ -158,7 +163,10 @@ def __init__(self, path=None, expanduser=False): self.strpath = abspath(path) def __hash__(self): - return hash(self.strpath) + s = self.strpath + if iswin32: + s = s.lower() + return hash(s) def __eq__(self, other): s1 = fspath(self) @@ -191,8 +199,8 @@ def samefile(self, other): other = abspath(other) if self == other: return True - if iswin32: - return False # there is no samefile + if not hasattr(os.path, "samefile"): + return False return py.error.checked_call( os.path.samefile, self.strpath, other) @@ -206,7 +214,9 @@ def remove(self, rec=1, ignore_errors=False): # force remove of readonly files on windows if iswin32: self.chmod(0o700, rec=1) - py.error.checked_call(py.std.shutil.rmtree, self.strpath, + import shutil + py.error.checked_call( + shutil.rmtree, self.strpath, ignore_errors=ignore_errors) else: py.error.checked_call(os.rmdir, self.strpath) @@ -333,13 +343,16 @@ def join(self, *args, **kwargs): strargs = newargs break newargs.insert(0, arg) + # special case for when we have e.g. strpath == "/" + actual_sep = "" if strpath.endswith(sep) else sep for arg in strargs: arg = arg.strip(sep) if iswin32: # allow unix style paths even on windows. arg = arg.strip('/') arg = arg.replace('/', sep) - strpath = strpath + sep + arg + strpath = strpath + actual_sep + arg + actual_sep = sep obj = object.__new__(self.__class__) obj.strpath = normpath(strpath) return obj @@ -448,8 +461,9 @@ def rename(self, target): def dump(self, obj, bin=1): """ pickle object into path location""" f = self.open('wb') + import pickle try: - py.error.checked_call(py.std.pickle.dump, obj, f, bin) + py.error.checked_call(pickle.dump, obj, f, bin) finally: f.close() @@ -568,14 +582,17 @@ def chdir(self): @contextmanager def as_cwd(self): - """ return context manager which changes to current dir during the - managed "with" context. On __enter__ it returns the old dir. + """ + Return a context manager, which changes to the path's dir during the + managed "with" context. + On __enter__ it returns the old dir, which might be ``None``. """ old = self.chdir() try: yield old finally: - old.chdir() + if old is not None: + old.chdir() def realpath(self): """ return a new path which contains no symbolic links.""" @@ -641,10 +658,35 @@ def pyimport(self, modname=None, ensuresyspath=True): If ensuresyspath=="append" the root dir will be appended if it isn't already contained in sys.path. if ensuresyspath is False no modification of syspath happens. + + Special value of ensuresyspath=="importlib" is intended + purely for using in pytest, it is capable only of importing + separate .py files outside packages, e.g. for test suite + without any __init__.py file. It effectively allows having + same-named test modules in different places and offers + mild opt-in via this option. Note that it works only in + recent versions of python. """ if not self.check(): raise py.error.ENOENT(self) + if ensuresyspath == 'importlib': + if modname is None: + modname = self.purebasename + if not ALLOW_IMPORTLIB_MODE: + raise ImportError( + "Can't use importlib due to old version of Python") + spec = importlib.util.spec_from_file_location( + modname, str(self)) + if spec is None: + raise ImportError( + "Can't find module %s at location %s" % + (modname, str(self)) + ) + mod = importlib.util.module_from_spec(spec) + spec.loader.exec_module(mod) + return mod + pkgpath = None if modname is None: pkgpath = self.pypkgpath() @@ -663,7 +705,7 @@ def pyimport(self, modname=None, ensuresyspath=True): mod = sys.modules[modname] if self.basename == "__init__.py": return mod # we don't check anything as we might - # we in a namespace package ... too icky to check + # be in a namespace package ... too icky to check modfile = mod.__file__ if modfile[-4:] in ('.pyc', '.pyo'): modfile = modfile[:-1] @@ -677,14 +719,17 @@ def pyimport(self, modname=None, ensuresyspath=True): except py.error.ENOENT: issame = False if not issame: - raise self.ImportMismatchError(modname, modfile, self) + ignore = os.getenv('PY_IGNORE_IMPORTMISMATCH') + if ignore != '1': + raise self.ImportMismatchError(modname, modfile, self) return mod else: try: return sys.modules[modname] except KeyError: # we have a custom modname, do a pseudo-import - mod = py.std.types.ModuleType(modname) + import types + mod = types.ModuleType(modname) mod.__file__ = str(self) sys.modules[modname] = mod try: @@ -729,7 +774,7 @@ def sysfind(cls, name, checker=None, paths=None): else: if paths is None: if iswin32: - paths = py.std.os.environ['Path'].split(';') + paths = os.environ['Path'].split(';') if '' not in paths and '.' not in paths: paths.append('.') try: @@ -737,10 +782,10 @@ def sysfind(cls, name, checker=None, paths=None): except KeyError: pass else: - paths = [re.sub('%SystemRoot%', systemroot, path) + paths = [path.replace('%SystemRoot%', systemroot) for path in paths] else: - paths = py.std.os.environ['PATH'].split(':') + paths = os.environ['PATH'].split(':') tryadd = [] if iswin32: tryadd += os.environ['PATHEXT'].split(os.pathsep) @@ -771,16 +816,18 @@ def _gethomedir(cls): return cls(x) _gethomedir = classmethod(_gethomedir) - #""" - #special class constructors for local filesystem paths - #""" + # """ + # special class constructors for local filesystem paths + # """ + @classmethod def get_temproot(cls): """ return the system's temporary directory (where tempfiles are usually created in) """ - return py.path.local(py.std.tempfile.gettempdir()) - get_temproot = classmethod(get_temproot) + import tempfile + return py.path.local(tempfile.gettempdir()) + @classmethod def mkdtemp(cls, rootdir=None): """ return a Path object pointing to a fresh new temporary directory (which we created ourself). @@ -789,59 +836,43 @@ def mkdtemp(cls, rootdir=None): if rootdir is None: rootdir = cls.get_temproot() return cls(py.error.checked_call(tempfile.mkdtemp, dir=str(rootdir))) - mkdtemp = classmethod(mkdtemp) def make_numbered_dir(cls, prefix='session-', rootdir=None, keep=3, - lock_timeout = 172800): # two days + lock_timeout=172800): # two days """ return unique directory with a number greater than the current maximum one. The number is assumed to start directly after prefix. if keep is true directories with a number less than (maxnum-keep) - will be removed. + will be removed. If .lock files are used (lock_timeout non-zero), + algorithm is multi-process safe. """ if rootdir is None: rootdir = cls.get_temproot() - nprefix = normcase(prefix) + nprefix = prefix.lower() def parse_num(path): """ parse the number out of a path (if it matches the prefix) """ - nbasename = normcase(path.basename) + nbasename = path.basename.lower() if nbasename.startswith(nprefix): try: return int(nbasename[len(nprefix):]) except ValueError: pass - # compute the maximum number currently in use with the - # prefix - lastmax = None - while True: - maxnum = -1 - for path in rootdir.listdir(): - num = parse_num(path) - if num is not None: - maxnum = max(maxnum, num) - - # make the new directory - try: - udir = rootdir.mkdir(prefix + str(maxnum+1)) - except py.error.EEXIST: - # race condition: another thread/process created the dir - # in the meantime. Try counting again - if lastmax == maxnum: - raise - lastmax = maxnum - continue - break - - # put a .lock file in the new directory that will be removed at - # process exit - if lock_timeout: - lockfile = udir.join('.lock') + def create_lockfile(path): + """ exclusively create lockfile. Throws when failed """ mypid = os.getpid() + lockfile = path.join('.lock') if hasattr(lockfile, 'mksymlinkto'): lockfile.mksymlinkto(str(mypid)) else: - lockfile.write(str(mypid)) + fd = py.error.checked_call(os.open, str(lockfile), os.O_WRONLY | os.O_CREAT | os.O_EXCL, 0o644) + with os.fdopen(fd, 'w') as f: + f.write(str(mypid)) + return lockfile + + def atexit_remove_lockfile(lockfile): + """ ensure lockfile is removed at process exit """ + mypid = os.getpid() def try_remove_lockfile(): # in a fork() situation, only the last process should # remove the .lock, otherwise the other processes run the @@ -856,19 +887,82 @@ def try_remove_lockfile(): pass atexit.register(try_remove_lockfile) + # compute the maximum number currently in use with the prefix + lastmax = None + while True: + maxnum = -1 + for path in rootdir.listdir(): + num = parse_num(path) + if num is not None: + maxnum = max(maxnum, num) + + # make the new directory + try: + udir = rootdir.mkdir(prefix + str(maxnum+1)) + if lock_timeout: + lockfile = create_lockfile(udir) + atexit_remove_lockfile(lockfile) + except (py.error.EEXIST, py.error.ENOENT, py.error.EBUSY): + # race condition (1): another thread/process created the dir + # in the meantime - try again + # race condition (2): another thread/process spuriously acquired + # lock treating empty directory as candidate + # for removal - try again + # race condition (3): another thread/process tried to create the lock at + # the same time (happened in Python 3.3 on Windows) + # https://ci.appveyor.com/project/pytestbot/py/build/1.0.21/job/ffi85j4c0lqwsfwa + if lastmax == maxnum: + raise + lastmax = maxnum + continue + break + + def get_mtime(path): + """ read file modification time """ + try: + return path.lstat().mtime + except py.error.Error: + pass + + garbage_prefix = prefix + 'garbage-' + + def is_garbage(path): + """ check if path denotes directory scheduled for removal """ + bn = path.basename + return bn.startswith(garbage_prefix) + # prune old directories - if keep: + udir_time = get_mtime(udir) + if keep and udir_time: for path in rootdir.listdir(): num = parse_num(path) if num is not None and num <= (maxnum - keep): - lf = path.join('.lock') try: - t1 = lf.lstat().mtime - t2 = lockfile.lstat().mtime - if not lock_timeout or abs(t2-t1) < lock_timeout: - continue # skip directories still locked - except py.error.Error: - pass # assume that it means that there is no 'lf' + # try acquiring lock to remove directory as exclusive user + if lock_timeout: + create_lockfile(path) + except (py.error.EEXIST, py.error.ENOENT, py.error.EBUSY): + path_time = get_mtime(path) + if not path_time: + # assume directory doesn't exist now + continue + if abs(udir_time - path_time) < lock_timeout: + # assume directory with lockfile exists + # and lock timeout hasn't expired yet + continue + + # path dir locked for exclusive use + # and scheduled for removal to avoid another thread/process + # treating it as a new directory or removal candidate + garbage_path = rootdir.join(garbage_prefix + str(uuid.uuid4())) + try: + path.rename(garbage_path) + garbage_path.remove(rec=1) + except KeyboardInterrupt: + raise + except: # this might be py.error.Error, WindowsError ... + pass + if is_garbage(path): try: path.remove(rec=1) except KeyboardInterrupt: @@ -902,14 +996,19 @@ def try_remove_lockfile(): def copymode(src, dest): """ copy permission from src to dst. """ - py.std.shutil.copymode(src, dest) + import shutil + shutil.copymode(src, dest) + def copystat(src, dest): - """ copy permission, last modification time, last access time, and flags from src to dst.""" - py.std.shutil.copystat(str(src), str(dest)) + """ copy permission, last modification time, + last access time, and flags from src to dst.""" + import shutil + shutil.copystat(str(src), str(dest)) + def copychunked(src, dest): - chunksize = 524288 # half a meg of bytes + chunksize = 524288 # half a meg of bytes fsrc = src.open('rb') try: fdest = dest.open('wb') @@ -924,6 +1023,7 @@ def copychunked(src, dest): finally: fsrc.close() + def isimportable(name): if name and (name[0].isalpha() or name[0] == '_'): name = name.replace("_", '') diff --git a/lib/ramble/external/py/_path/svnwc.py b/lib/ramble/external/py/_path/svnwc.py index 992223c04..b5b9d8d54 100644 --- a/lib/ramble/external/py/_path/svnwc.py +++ b/lib/ramble/external/py/_path/svnwc.py @@ -94,7 +94,7 @@ def _getsvnversion(ver=[]): def _escape_helper(text): text = str(text) - if py.std.sys.platform != 'win32': + if sys.platform != 'win32': text = str(text).replace('$', '\\$') return text @@ -354,7 +354,7 @@ def path_to_fspath(path, addat=True): def url_from_path(path): fspath = path_to_fspath(path, False) - quote = py.std.urllib.quote + from urllib import quote if ISWINDOWS: match = _reg_allow_disk.match(fspath) fspath = fspath.replace('\\', '/') @@ -396,7 +396,7 @@ def makecmdoptions(self): def __str__(self): return "" %(self.username,) -rex_blame = re.compile(r'\s*(\d+)\s*(\S+) (.*)') +rex_blame = re.compile(r'\s*(\d+)\s+(\S+) (.*)') class SvnWCCommandPath(common.PathBase): """ path implementation offering access/modification to svn working copies. @@ -504,7 +504,7 @@ def checkout(self, url=None, rev=None): if url is None: url = self.url if rev is None or rev == -1: - if (py.std.sys.platform != 'win32' and + if (sys.platform != 'win32' and _getsvnversion() == '1.3'): url += "@HEAD" else: @@ -785,7 +785,7 @@ def info(self, usecache=1): info = InfoSvnWCCommand(output) # Can't reliably compare on Windows without access to win32api - if py.std.sys.platform != 'win32': + if sys.platform != 'win32': if info.path != self.localpath: raise py.error.ENOENT(self, "not a versioned resource:" + " %s != %s" % (info.path, self.localpath)) diff --git a/lib/ramble/external/py/_std.py b/lib/ramble/external/py/_std.py index 97a985332..66adb7b02 100644 --- a/lib/ramble/external/py/_std.py +++ b/lib/ramble/external/py/_std.py @@ -1,4 +1,10 @@ import sys +import warnings + + +class PyStdIsDeprecatedWarning(DeprecationWarning): + pass + class Std(object): """ makes top-level python modules available as an attribute, @@ -9,6 +15,9 @@ def __init__(self): self.__dict__ = sys.modules def __getattr__(self, name): + warnings.warn("py.std is deprecated, please import %s directly" % name, + category=PyStdIsDeprecatedWarning, + stacklevel=2) try: m = __import__(name) except ImportError: diff --git a/lib/ramble/external/py/_vendored_packages/__init__.py b/lib/ramble/external/py/_vendored_packages/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/lib/ramble/external/py/_vendored_packages/apipkg-2.0.0.dist-info/INSTALLER b/lib/ramble/external/py/_vendored_packages/apipkg-2.0.0.dist-info/INSTALLER new file mode 100644 index 000000000..a1b589e38 --- /dev/null +++ b/lib/ramble/external/py/_vendored_packages/apipkg-2.0.0.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/lib/ramble/external/py/_vendored_packages/apipkg-2.0.0.dist-info/LICENSE b/lib/ramble/external/py/_vendored_packages/apipkg-2.0.0.dist-info/LICENSE new file mode 100644 index 000000000..ff33b8f7c --- /dev/null +++ b/lib/ramble/external/py/_vendored_packages/apipkg-2.0.0.dist-info/LICENSE @@ -0,0 +1,18 @@ + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. diff --git a/lib/ramble/external/py/_vendored_packages/apipkg-2.0.0.dist-info/METADATA b/lib/ramble/external/py/_vendored_packages/apipkg-2.0.0.dist-info/METADATA new file mode 100644 index 000000000..7eea770a0 --- /dev/null +++ b/lib/ramble/external/py/_vendored_packages/apipkg-2.0.0.dist-info/METADATA @@ -0,0 +1,125 @@ +Metadata-Version: 2.1 +Name: apipkg +Version: 2.0.0 +Summary: apipkg: namespace control and lazy-import mechanism +Home-page: https://github.com/pytest-dev/apipkg +Author: holger krekel +Maintainer: Ronny Pfannschmidt +Maintainer-email: opensource@ronnypfannschmidt.de +License: MIT +Platform: unix +Platform: linux +Platform: osx +Platform: cygwin +Platform: win32 +Classifier: Development Status :: 4 - Beta +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: MIT License +Classifier: Operating System :: MacOS :: MacOS X +Classifier: Operating System :: Microsoft :: Windows +Classifier: Operating System :: POSIX +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 2 +Classifier: Programming Language :: Python :: 2.7 +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.4 +Classifier: Programming Language :: Python :: 3.5 +Classifier: Programming Language :: Python :: 3.6 +Classifier: Programming Language :: Python :: 3.7 +Classifier: Programming Language :: Python :: 3.8 +Classifier: Programming Language :: Python :: 3.9 +Classifier: Programming Language :: Python :: Implementation :: CPython +Classifier: Topic :: Software Development :: Libraries +Requires-Python: !=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7 +Description-Content-Type: text/x-rst +License-File: LICENSE + +Welcome to apipkg ! +------------------- + +With apipkg you can control the exported namespace of a Python package and +greatly reduce the number of imports for your users. +It is a `small pure Python module`_ that works on CPython 2.7 and 3.4+, +Jython and PyPy. It cooperates well with Python's ``help()`` system, +custom importers (PEP302) and common command-line completion tools. + +Usage is very simple: you can require 'apipkg' as a dependency or you +can copy paste the ~200 lines of code into your project. + + +Tutorial example +------------------- + +Here is a simple ``mypkg`` package that specifies one namespace +and exports two objects imported from different modules:: + + + # mypkg/__init__.py + import apipkg + apipkg.initpkg(__name__, { + 'path': { + 'Class1': "_mypkg.somemodule:Class1", + 'clsattr': "_mypkg.othermodule:Class2.attr", + } + } + +The package is initialized with a dictionary as namespace. + +You need to create a ``_mypkg`` package with a ``somemodule.py`` +and ``othermodule.py`` containing the respective classes. +The ``_mypkg`` is not special - it's a completely +regular Python package. + +Namespace dictionaries contain ``name: value`` mappings +where the value may be another namespace dictionary or +a string specifying an import location. On accessing +an namespace attribute an import will be performed:: + + >>> import mypkg + >>> mypkg.path + + >>> mypkg.path.Class1 # '_mypkg.somemodule' gets imported now + + >>> mypkg.path.clsattr # '_mypkg.othermodule' gets imported now + 4 # the value of _mypkg.othermodule.Class2.attr + +The ``mypkg.path`` namespace and its two entries are +loaded when they are accessed. This means: + +* lazy loading - only what is actually needed is ever loaded + +* only the root "mypkg" ever needs to be imported to get + access to the complete functionality + +* the underlying modules are also accessible, for example:: + + from mypkg.sub import Class1 + + +Including apipkg in your package +-------------------------------------- + +If you don't want to add an ``apipkg`` dependency to your package you +can copy the `apipkg.py`_ file somewhere to your own package, +for example ``_mypkg/apipkg.py`` in the above example. You +then import the ``initpkg`` function from that new place and +are good to go. + +.. _`small pure Python module`: +.. _`apipkg.py`: https://github.com/pytest-dev/apipkg/blob/master/src/apipkg/__init__.py + +Feedback? +----------------------- + +If you have questions you are welcome to + +* join the **#pytest** channel on irc.libera.chat_ + (using an IRC client, via webchat_, or via Matrix_). +* create an issue on the bugtracker_ + +.. _irc.libera.chat: ircs://irc.libera.chat:6697/#pytest +.. _webchat: https://web.libera.chat/#pytest +.. _matrix: https://matrix.to/#/%23pytest:libera.chat +.. _bugtracker: https://github.com/pytest-dev/apipkg/issues + + diff --git a/lib/ramble/external/py/_vendored_packages/apipkg-2.0.0.dist-info/RECORD b/lib/ramble/external/py/_vendored_packages/apipkg-2.0.0.dist-info/RECORD new file mode 100644 index 000000000..357b8b9c7 --- /dev/null +++ b/lib/ramble/external/py/_vendored_packages/apipkg-2.0.0.dist-info/RECORD @@ -0,0 +1,11 @@ +apipkg-2.0.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +apipkg-2.0.0.dist-info/LICENSE,sha256=6J7tEHTTqUMZi6E5uAhE9bRFuGC7p0qK6twGEFZhZOo,1054 +apipkg-2.0.0.dist-info/METADATA,sha256=GqNwkxraK5UTxObLVXTLc2UqktOPwZnKqdk2ThzHX0A,4292 +apipkg-2.0.0.dist-info/RECORD,, +apipkg-2.0.0.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +apipkg-2.0.0.dist-info/WHEEL,sha256=WzZ8cwjh8l0jtULNjYq1Hpr-WCqCRgPr--TX4P5I1Wo,110 +apipkg-2.0.0.dist-info/top_level.txt,sha256=3TGS6nmN7kjxhUK4LpPCB3QkQI34QYGrT0ZQGWajoZ8,7 +apipkg/__init__.py,sha256=gpbD3O57S9f-LsO2e-XwI6IGISayicfnCq3B5y_8frg,6978 +apipkg/__pycache__/__init__.cpython-39.pyc,, +apipkg/__pycache__/version.cpython-39.pyc,, +apipkg/version.py,sha256=bgZFg-f3UKhgE-z2w8RoFrwqRBzJBZkM4_jKFiYB9eU,142 diff --git a/lib/ramble/external/py/_vendored_packages/apipkg-2.0.0.dist-info/REQUESTED b/lib/ramble/external/py/_vendored_packages/apipkg-2.0.0.dist-info/REQUESTED new file mode 100644 index 000000000..e69de29bb diff --git a/lib/ramble/external/py/_vendored_packages/apipkg-2.0.0.dist-info/WHEEL b/lib/ramble/external/py/_vendored_packages/apipkg-2.0.0.dist-info/WHEEL new file mode 100644 index 000000000..b733a60d3 --- /dev/null +++ b/lib/ramble/external/py/_vendored_packages/apipkg-2.0.0.dist-info/WHEEL @@ -0,0 +1,6 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.37.0) +Root-Is-Purelib: true +Tag: py2-none-any +Tag: py3-none-any + diff --git a/lib/ramble/external/py/_apipkg.py b/lib/ramble/external/py/_vendored_packages/apipkg/__init__.py similarity index 55% rename from lib/ramble/external/py/_apipkg.py rename to lib/ramble/external/py/_vendored_packages/apipkg/__init__.py index a73b8f6d0..350d8c4b0 100644 --- a/lib/ramble/external/py/_apipkg.py +++ b/lib/ramble/external/py/_vendored_packages/apipkg/__init__.py @@ -1,7 +1,7 @@ """ -apipkg: control the exported namespace of a python package. +apipkg: control the exported namespace of a Python package. -see http://pypi.python.org/pypi/apipkg +see https://pypi.python.org/pypi/apipkg (c) holger krekel, 2009 - MIT license """ @@ -9,43 +9,70 @@ import sys from types import ModuleType -__version__ = '1.3.dev' +from .version import version as __version__ # NOQA:F401 + def _py_abspath(path): """ special version of abspath that will leave paths from jython jars alone """ - if path.startswith('__pyclasspath__'): + if path.startswith("__pyclasspath__"): return path else: return os.path.abspath(path) -def initpkg(pkgname, exportdefs, attr=dict()): + +def distribution_version(name): + """try to get the version of the named distribution, + returs None on failure""" + from pkg_resources import get_distribution, DistributionNotFound + + try: + dist = get_distribution(name) + except DistributionNotFound: + pass + else: + return dist.version + + +def initpkg(pkgname, exportdefs, attr=None, eager=False): """ initialize given package from the export definitions. """ + attr = attr or {} oldmod = sys.modules.get(pkgname) d = {} - f = getattr(oldmod, '__file__', None) + f = getattr(oldmod, "__file__", None) if f: f = _py_abspath(f) - d['__file__'] = f - if hasattr(oldmod, '__version__'): - d['__version__'] = oldmod.__version__ - if hasattr(oldmod, '__loader__'): - d['__loader__'] = oldmod.__loader__ - if hasattr(oldmod, '__path__'): - d['__path__'] = [_py_abspath(p) for p in oldmod.__path__] - if '__doc__' not in exportdefs and getattr(oldmod, '__doc__', None): - d['__doc__'] = oldmod.__doc__ + d["__file__"] = f + if hasattr(oldmod, "__version__"): + d["__version__"] = oldmod.__version__ + if hasattr(oldmod, "__loader__"): + d["__loader__"] = oldmod.__loader__ + if hasattr(oldmod, "__path__"): + d["__path__"] = [_py_abspath(p) for p in oldmod.__path__] + if hasattr(oldmod, "__package__"): + d["__package__"] = oldmod.__package__ + if "__doc__" not in exportdefs and getattr(oldmod, "__doc__", None): + d["__doc__"] = oldmod.__doc__ + d["__spec__"] = getattr(oldmod, "__spec__", None) d.update(attr) if hasattr(oldmod, "__dict__"): oldmod.__dict__.update(d) mod = ApiModule(pkgname, exportdefs, implprefix=pkgname, attr=d) sys.modules[pkgname] = mod + # eagerload in bypthon to avoid their monkeypatching breaking packages + if "bpython" in sys.modules or eager: + for module in list(sys.modules.values()): + if isinstance(module, ApiModule): + module.__dict__ + return mod + def importobj(modpath, attrname): - module = __import__(modpath, None, None, ['__doc__']) + """imports a module, then resolves the attrname on it""" + module = __import__(modpath, None, None, ["__doc__"]) if not attrname: return module @@ -55,20 +82,25 @@ def importobj(modpath, attrname): retval = getattr(retval, x) return retval + class ApiModule(ModuleType): + """the magical lazy-loading module standing""" + def __docget(self): try: return self.__doc except AttributeError: - if '__doc__' in self.__map__: - return self.__makeattr('__doc__') + if "__doc__" in self.__map__: + return self.__makeattr("__doc__") + def __docset(self, value): self.__doc = value + __doc__ = property(__docget, __docset) def __init__(self, name, importspec, implprefix=None, attr=None): self.__name__ = name - self.__all__ = [x for x in importspec if x != '__onfirstaccess__'] + self.__all__ = [x for x in importspec if x != "__onfirstaccess__"] self.__map__ = {} self.__implprefix__ = implprefix or name if attr: @@ -77,47 +109,47 @@ def __init__(self, name, importspec, implprefix=None, attr=None): setattr(self, name, val) for name, importspec in importspec.items(): if isinstance(importspec, dict): - subname = '%s.%s' % (self.__name__, name) + subname = "{}.{}".format(self.__name__, name) apimod = ApiModule(subname, importspec, implprefix) sys.modules[subname] = apimod setattr(self, name, apimod) else: - parts = importspec.split(':') + parts = importspec.split(":") modpath = parts.pop(0) attrname = parts and parts[0] or "" - if modpath[0] == '.': + if modpath[0] == ".": modpath = implprefix + modpath if not attrname: - subname = '%s.%s' % (self.__name__, name) + subname = "{}.{}".format(self.__name__, name) apimod = AliasModule(subname, modpath) sys.modules[subname] = apimod - if '.' not in name: + if "." not in name: setattr(self, name, apimod) else: self.__map__[name] = (modpath, attrname) def __repr__(self): - l = [] - if hasattr(self, '__version__'): - l.append("version=" + repr(self.__version__)) - if hasattr(self, '__file__'): - l.append('from ' + repr(self.__file__)) - if l: - return '' % (self.__name__, " ".join(l)) - return '' % (self.__name__,) + repr_list = [] + if hasattr(self, "__version__"): + repr_list.append("version=" + repr(self.__version__)) + if hasattr(self, "__file__"): + repr_list.append("from " + repr(self.__file__)) + if repr_list: + return "".format(self.__name__, " ".join(repr_list)) + return "".format(self.__name__) def __makeattr(self, name): """lazily compute value for name or raise AttributeError if unknown.""" # print "makeattr", self.__name__, name target = None - if '__onfirstaccess__' in self.__map__: - target = self.__map__.pop('__onfirstaccess__') + if "__onfirstaccess__" in self.__map__: + target = self.__map__.pop("__onfirstaccess__") importobj(*target)() try: modpath, attrname = self.__map__[name] except KeyError: - if target is not None and name != '__onfirstaccess__': + if target is not None and name != "__onfirstaccess__": # retry, onfirstaccess might have set attrs return getattr(self, name) raise AttributeError(name) @@ -132,19 +164,20 @@ def __makeattr(self, name): __getattr__ = __makeattr + @property def __dict__(self): - # force all the content of the module to be loaded when __dict__ is read - dictdescr = ModuleType.__dict__['__dict__'] + # force all the content of the module + # to be loaded when __dict__ is read + dictdescr = ModuleType.__dict__["__dict__"] dict = dictdescr.__get__(self) if dict is not None: - hasattr(self, 'some') + hasattr(self, "some") for name in self.__all__: try: self.__makeattr(name) except AttributeError: pass return dict - __dict__ = property(__dict__) def AliasModule(modname, modpath, attrname=None): @@ -158,19 +191,22 @@ def getmod(): mod.append(x) return mod[0] - class AliasModule(ModuleType): + x = modpath + ("." + attrname if attrname else "") + repr_result = "".format(modname, x) + class AliasModule(ModuleType): def __repr__(self): - x = modpath - if attrname: - x += "." + attrname - return '' % (modname, x) + return repr_result def __getattribute__(self, name): try: return getattr(getmod(), name) except ImportError: - return None + if modpath == "pytest" and attrname is None: + # hack for pylibs py.test + return None + else: + raise def __setattr__(self, name, value): setattr(getmod(), name, value) diff --git a/lib/ramble/external/py/_vendored_packages/apipkg/version.py b/lib/ramble/external/py/_vendored_packages/apipkg/version.py new file mode 100644 index 000000000..c5b4e0e79 --- /dev/null +++ b/lib/ramble/external/py/_vendored_packages/apipkg/version.py @@ -0,0 +1,5 @@ +# coding: utf-8 +# file generated by setuptools_scm +# don't change, don't track in version control +version = '2.0.0' +version_tuple = (2, 0, 0) diff --git a/lib/ramble/external/py/_vendored_packages/iniconfig-1.1.1.dist-info/INSTALLER b/lib/ramble/external/py/_vendored_packages/iniconfig-1.1.1.dist-info/INSTALLER new file mode 100644 index 000000000..a1b589e38 --- /dev/null +++ b/lib/ramble/external/py/_vendored_packages/iniconfig-1.1.1.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/lib/ramble/external/py/_vendored_packages/iniconfig-1.1.1.dist-info/LICENSE b/lib/ramble/external/py/_vendored_packages/iniconfig-1.1.1.dist-info/LICENSE new file mode 100644 index 000000000..31ecdfb1d --- /dev/null +++ b/lib/ramble/external/py/_vendored_packages/iniconfig-1.1.1.dist-info/LICENSE @@ -0,0 +1,19 @@ + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + diff --git a/lib/ramble/external/py/_vendored_packages/iniconfig-1.1.1.dist-info/METADATA b/lib/ramble/external/py/_vendored_packages/iniconfig-1.1.1.dist-info/METADATA new file mode 100644 index 000000000..c078a7532 --- /dev/null +++ b/lib/ramble/external/py/_vendored_packages/iniconfig-1.1.1.dist-info/METADATA @@ -0,0 +1,78 @@ +Metadata-Version: 2.1 +Name: iniconfig +Version: 1.1.1 +Summary: iniconfig: brain-dead simple config-ini parsing +Home-page: http://github.com/RonnyPfannschmidt/iniconfig +Author: Ronny Pfannschmidt, Holger Krekel +Author-email: opensource@ronnypfannschmidt.de, holger.krekel@gmail.com +License: MIT License +Platform: unix +Platform: linux +Platform: osx +Platform: cygwin +Platform: win32 +Classifier: Development Status :: 4 - Beta +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: MIT License +Classifier: Operating System :: POSIX +Classifier: Operating System :: Microsoft :: Windows +Classifier: Operating System :: MacOS :: MacOS X +Classifier: Topic :: Software Development :: Libraries +Classifier: Topic :: Utilities +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 2 +Classifier: Programming Language :: Python :: 3 + +iniconfig: brain-dead simple parsing of ini files +======================================================= + +iniconfig is a small and simple INI-file parser module +having a unique set of features: + +* tested against Python2.4 across to Python3.2, Jython, PyPy +* maintains order of sections and entries +* supports multi-line values with or without line-continuations +* supports "#" comments everywhere +* raises errors with proper line-numbers +* no bells and whistles like automatic substitutions +* iniconfig raises an Error if two sections have the same name. + +If you encounter issues or have feature wishes please report them to: + + http://github.com/RonnyPfannschmidt/iniconfig/issues + +Basic Example +=================================== + +If you have an ini file like this:: + + # content of example.ini + [section1] # comment + name1=value1 # comment + name1b=value1,value2 # comment + + [section2] + name2= + line1 + line2 + +then you can do:: + + >>> import iniconfig + >>> ini = iniconfig.IniConfig("example.ini") + >>> ini['section1']['name1'] # raises KeyError if not exists + 'value1' + >>> ini.get('section1', 'name1b', [], lambda x: x.split(",")) + ['value1', 'value2'] + >>> ini.get('section1', 'notexist', [], lambda x: x.split(",")) + [] + >>> [x.name for x in list(ini)] + ['section1', 'section2'] + >>> list(list(ini)[0].items()) + [('name1', 'value1'), ('name1b', 'value1,value2')] + >>> 'section1' in ini + True + >>> 'inexistendsection' in ini + False + + diff --git a/lib/ramble/external/py/_vendored_packages/iniconfig-1.1.1.dist-info/RECORD b/lib/ramble/external/py/_vendored_packages/iniconfig-1.1.1.dist-info/RECORD new file mode 100644 index 000000000..168233330 --- /dev/null +++ b/lib/ramble/external/py/_vendored_packages/iniconfig-1.1.1.dist-info/RECORD @@ -0,0 +1,11 @@ +iniconfig-1.1.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +iniconfig-1.1.1.dist-info/LICENSE,sha256=KvaAw570k_uCgwNW0dPfGstaBgM8ui3sehniHKp3qGY,1061 +iniconfig-1.1.1.dist-info/METADATA,sha256=_4-oFKpRXuZv5rzepScpXRwhq6DzqsgbnA5ZpgMUMcs,2405 +iniconfig-1.1.1.dist-info/RECORD,, +iniconfig-1.1.1.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +iniconfig-1.1.1.dist-info/WHEEL,sha256=ADKeyaGyKF5DwBNE0sRE5pvW-bSkFMJfBuhzZ3rceP4,110 +iniconfig-1.1.1.dist-info/top_level.txt,sha256=7KfM0fugdlToj9UW7enKXk2HYALQD8qHiyKtjhSzgN8,10 +iniconfig/__init__.py,sha256=-pBe5AF_6aAwo1CxJQ8i_zJq6ejc6IxHta7qk2tNJhY,5208 +iniconfig/__init__.pyi,sha256=-4KOctzq28ohRmTZsqlH6aylyFqsNKxYqtk1dteypi4,1205 +iniconfig/__pycache__/__init__.cpython-39.pyc,, +iniconfig/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 diff --git a/lib/ramble/external/py/_vendored_packages/iniconfig-1.1.1.dist-info/REQUESTED b/lib/ramble/external/py/_vendored_packages/iniconfig-1.1.1.dist-info/REQUESTED new file mode 100644 index 000000000..e69de29bb diff --git a/lib/ramble/external/py/_vendored_packages/iniconfig-1.1.1.dist-info/WHEEL b/lib/ramble/external/py/_vendored_packages/iniconfig-1.1.1.dist-info/WHEEL new file mode 100644 index 000000000..6d38aa060 --- /dev/null +++ b/lib/ramble/external/py/_vendored_packages/iniconfig-1.1.1.dist-info/WHEEL @@ -0,0 +1,6 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.35.1) +Root-Is-Purelib: true +Tag: py2-none-any +Tag: py3-none-any + diff --git a/lib/ramble/external/py/_iniconfig.py b/lib/ramble/external/py/_vendored_packages/iniconfig/__init__.py similarity index 92% rename from lib/ramble/external/py/_iniconfig.py rename to lib/ramble/external/py/_vendored_packages/iniconfig/__init__.py index 92b50bd85..6ad9eaf86 100644 --- a/lib/ramble/external/py/_iniconfig.py +++ b/lib/ramble/external/py/_vendored_packages/iniconfig/__init__.py @@ -1,12 +1,11 @@ """ brain-dead simple parser for ini-style files. (C) Ronny Pfannschmidt, Holger Krekel -- MIT licensed """ -__version__ = "0.2.dev2" - __all__ = ['IniConfig', 'ParseError'] COMMENTCHARS = "#;" + class ParseError(Exception): def __init__(self, path, lineno, msg): Exception.__init__(self, path, lineno, msg) @@ -15,7 +14,8 @@ def __init__(self, path, lineno, msg): self.msg = msg def __str__(self): - return "%s:%s: %s" %(self.path, self.lineno+1, self.msg) + return "%s:%s: %s" % (self.path, self.lineno+1, self.msg) + class SectionWrapper(object): def __init__(self, config, name): @@ -26,13 +26,15 @@ def lineof(self, name): return self.config.lineof(self.name, name) def get(self, key, default=None, convert=str): - return self.config.get(self.name, key, convert=convert, default=default) + return self.config.get(self.name, key, + convert=convert, default=default) def __getitem__(self, key): return self.config.sections[self.name][key] def __iter__(self): section = self.config.sections.get(self.name, []) + def lineof(key): return self.config.lineof(self.name, key) for name in sorted(section, key=lineof): @@ -45,7 +47,7 @@ def items(self): class IniConfig(object): def __init__(self, path, data=None): - self.path = str(path) # convenience + self.path = str(path) # convenience if data is None: f = open(self.path) try: @@ -64,11 +66,11 @@ def __init__(self, path, data=None): self._sources[section, name] = lineno if name is None: if section in self.sections: - self._raise(lineno, 'duplicate section %r'%(section, )) + self._raise(lineno, 'duplicate section %r' % (section, )) self.sections[section] = {} else: if name in self.sections[section]: - self._raise(lineno, 'duplicate name %r'%(name, )) + self._raise(lineno, 'duplicate name %r' % (name, )) self.sections[section][name] = value def _raise(self, lineno, msg): @@ -157,6 +159,7 @@ def __iter__(self): def __contains__(self, arg): return arg in self.sections + def iscommentline(line): c = line.lstrip()[:1] return c in COMMENTCHARS diff --git a/lib/ramble/external/py/_vendored_packages/iniconfig/__init__.pyi b/lib/ramble/external/py/_vendored_packages/iniconfig/__init__.pyi new file mode 100644 index 000000000..b6284bec3 --- /dev/null +++ b/lib/ramble/external/py/_vendored_packages/iniconfig/__init__.pyi @@ -0,0 +1,31 @@ +from typing import Callable, Iterator, Mapping, Optional, Tuple, TypeVar, Union +from typing_extensions import Final + +_D = TypeVar('_D') +_T = TypeVar('_T') + +class ParseError(Exception): + # Private __init__. + path: Final[str] + lineno: Final[int] + msg: Final[str] + +class SectionWrapper: + # Private __init__. + config: Final[IniConfig] + name: Final[str] + def __getitem__(self, key: str) -> str: ... + def __iter__(self) -> Iterator[str]: ... + def get(self, key: str, default: _D = ..., convert: Callable[[str], _T] = ...) -> Union[_T, _D]: ... + def items(self) -> Iterator[Tuple[str, str]]: ... + def lineof(self, name: str) -> Optional[int]: ... + +class IniConfig: + path: Final[str] + sections: Final[Mapping[str, Mapping[str, str]]] + def __init__(self, path: str, data: Optional[str] = None): ... + def __contains__(self, arg: str) -> bool: ... + def __getitem__(self, name: str) -> SectionWrapper: ... + def __iter__(self) -> Iterator[SectionWrapper]: ... + def get(self, section: str, name: str, default: _D = ..., convert: Callable[[str], _T] = ...) -> Union[_T, _D]: ... + def lineof(self, section: str, name: Optional[str] = ...) -> Optional[int]: ... diff --git a/lib/ramble/external/py/_vendored_packages/iniconfig/py.typed b/lib/ramble/external/py/_vendored_packages/iniconfig/py.typed new file mode 100644 index 000000000..e69de29bb diff --git a/lib/ramble/external/py/error.pyi b/lib/ramble/external/py/error.pyi new file mode 100644 index 000000000..034eba609 --- /dev/null +++ b/lib/ramble/external/py/error.pyi @@ -0,0 +1,129 @@ +from typing import Any, Callable, TypeVar + +_T = TypeVar('_T') + +def checked_call(func: Callable[..., _T], *args: Any, **kwargs: Any) -> _T: ... +class Error(EnvironmentError): ... +class EPERM(Error): ... +class ENOENT(Error): ... +class ESRCH(Error): ... +class EINTR(Error): ... +class EIO(Error): ... +class ENXIO(Error): ... +class E2BIG(Error): ... +class ENOEXEC(Error): ... +class EBADF(Error): ... +class ECHILD(Error): ... +class EAGAIN(Error): ... +class ENOMEM(Error): ... +class EACCES(Error): ... +class EFAULT(Error): ... +class ENOTBLK(Error): ... +class EBUSY(Error): ... +class EEXIST(Error): ... +class EXDEV(Error): ... +class ENODEV(Error): ... +class ENOTDIR(Error): ... +class EISDIR(Error): ... +class EINVAL(Error): ... +class ENFILE(Error): ... +class EMFILE(Error): ... +class ENOTTY(Error): ... +class ETXTBSY(Error): ... +class EFBIG(Error): ... +class ENOSPC(Error): ... +class ESPIPE(Error): ... +class EROFS(Error): ... +class EMLINK(Error): ... +class EPIPE(Error): ... +class EDOM(Error): ... +class ERANGE(Error): ... +class EDEADLCK(Error): ... +class ENAMETOOLONG(Error): ... +class ENOLCK(Error): ... +class ENOSYS(Error): ... +class ENOTEMPTY(Error): ... +class ELOOP(Error): ... +class EWOULDBLOCK(Error): ... +class ENOMSG(Error): ... +class EIDRM(Error): ... +class ECHRNG(Error): ... +class EL2NSYNC(Error): ... +class EL3HLT(Error): ... +class EL3RST(Error): ... +class ELNRNG(Error): ... +class EUNATCH(Error): ... +class ENOCSI(Error): ... +class EL2HLT(Error): ... +class EBADE(Error): ... +class EBADR(Error): ... +class EXFULL(Error): ... +class ENOANO(Error): ... +class EBADRQC(Error): ... +class EBADSLT(Error): ... +class EDEADLOCK(Error): ... +class EBFONT(Error): ... +class ENOSTR(Error): ... +class ENODATA(Error): ... +class ETIME(Error): ... +class ENOSR(Error): ... +class ENONET(Error): ... +class ENOPKG(Error): ... +class EREMOTE(Error): ... +class ENOLINK(Error): ... +class EADV(Error): ... +class ESRMNT(Error): ... +class ECOMM(Error): ... +class EPROTO(Error): ... +class EMULTIHOP(Error): ... +class EDOTDOT(Error): ... +class EBADMSG(Error): ... +class EOVERFLOW(Error): ... +class ENOTUNIQ(Error): ... +class EBADFD(Error): ... +class EREMCHG(Error): ... +class ELIBACC(Error): ... +class ELIBBAD(Error): ... +class ELIBSCN(Error): ... +class ELIBMAX(Error): ... +class ELIBEXEC(Error): ... +class EILSEQ(Error): ... +class ERESTART(Error): ... +class ESTRPIPE(Error): ... +class EUSERS(Error): ... +class ENOTSOCK(Error): ... +class EDESTADDRREQ(Error): ... +class EMSGSIZE(Error): ... +class EPROTOTYPE(Error): ... +class ENOPROTOOPT(Error): ... +class EPROTONOSUPPORT(Error): ... +class ESOCKTNOSUPPORT(Error): ... +class ENOTSUP(Error): ... +class EOPNOTSUPP(Error): ... +class EPFNOSUPPORT(Error): ... +class EAFNOSUPPORT(Error): ... +class EADDRINUSE(Error): ... +class EADDRNOTAVAIL(Error): ... +class ENETDOWN(Error): ... +class ENETUNREACH(Error): ... +class ENETRESET(Error): ... +class ECONNABORTED(Error): ... +class ECONNRESET(Error): ... +class ENOBUFS(Error): ... +class EISCONN(Error): ... +class ENOTCONN(Error): ... +class ESHUTDOWN(Error): ... +class ETOOMANYREFS(Error): ... +class ETIMEDOUT(Error): ... +class ECONNREFUSED(Error): ... +class EHOSTDOWN(Error): ... +class EHOSTUNREACH(Error): ... +class EALREADY(Error): ... +class EINPROGRESS(Error): ... +class ESTALE(Error): ... +class EUCLEAN(Error): ... +class ENOTNAM(Error): ... +class ENAVAIL(Error): ... +class EISNAM(Error): ... +class EREMOTEIO(Error): ... +class EDQUOT(Error): ... diff --git a/lib/ramble/external/py/iniconfig.pyi b/lib/ramble/external/py/iniconfig.pyi new file mode 100644 index 000000000..b6284bec3 --- /dev/null +++ b/lib/ramble/external/py/iniconfig.pyi @@ -0,0 +1,31 @@ +from typing import Callable, Iterator, Mapping, Optional, Tuple, TypeVar, Union +from typing_extensions import Final + +_D = TypeVar('_D') +_T = TypeVar('_T') + +class ParseError(Exception): + # Private __init__. + path: Final[str] + lineno: Final[int] + msg: Final[str] + +class SectionWrapper: + # Private __init__. + config: Final[IniConfig] + name: Final[str] + def __getitem__(self, key: str) -> str: ... + def __iter__(self) -> Iterator[str]: ... + def get(self, key: str, default: _D = ..., convert: Callable[[str], _T] = ...) -> Union[_T, _D]: ... + def items(self) -> Iterator[Tuple[str, str]]: ... + def lineof(self, name: str) -> Optional[int]: ... + +class IniConfig: + path: Final[str] + sections: Final[Mapping[str, Mapping[str, str]]] + def __init__(self, path: str, data: Optional[str] = None): ... + def __contains__(self, arg: str) -> bool: ... + def __getitem__(self, name: str) -> SectionWrapper: ... + def __iter__(self) -> Iterator[SectionWrapper]: ... + def get(self, section: str, name: str, default: _D = ..., convert: Callable[[str], _T] = ...) -> Union[_T, _D]: ... + def lineof(self, section: str, name: Optional[str] = ...) -> Optional[int]: ... diff --git a/lib/ramble/external/py/io.pyi b/lib/ramble/external/py/io.pyi new file mode 100644 index 000000000..d377e2405 --- /dev/null +++ b/lib/ramble/external/py/io.pyi @@ -0,0 +1,130 @@ +from io import StringIO as TextIO +from io import BytesIO as BytesIO +from typing import Any, AnyStr, Callable, Generic, IO, List, Optional, Text, Tuple, TypeVar, Union, overload +from typing_extensions import Final +import sys + +_T = TypeVar("_T") + +class FDCapture(Generic[AnyStr]): + def __init__(self, targetfd: int, tmpfile: Optional[IO[AnyStr]] = ..., now: bool = ..., patchsys: bool = ...) -> None: ... + def start(self) -> None: ... + def done(self) -> IO[AnyStr]: ... + def writeorg(self, data: AnyStr) -> None: ... + +class StdCaptureFD: + def __init__( + self, + out: Union[bool, IO[str]] = ..., + err: Union[bool, IO[str]] = ..., + mixed: bool = ..., + in_: bool = ..., + patchsys: bool = ..., + now: bool = ..., + ) -> None: ... + @classmethod + def call(cls, func: Callable[..., _T], *args: Any, **kwargs: Any) -> Tuple[_T, str, str]: ... + def reset(self) -> Tuple[str, str]: ... + def suspend(self) -> Tuple[str, str]: ... + def startall(self) -> None: ... + def resume(self) -> None: ... + def done(self, save: bool = ...) -> Tuple[IO[str], IO[str]]: ... + def readouterr(self) -> Tuple[str, str]: ... + +class StdCapture: + def __init__( + self, + out: Union[bool, IO[str]] = ..., + err: Union[bool, IO[str]] = ..., + in_: bool = ..., + mixed: bool = ..., + now: bool = ..., + ) -> None: ... + @classmethod + def call(cls, func: Callable[..., _T], *args: Any, **kwargs: Any) -> Tuple[_T, str, str]: ... + def reset(self) -> Tuple[str, str]: ... + def suspend(self) -> Tuple[str, str]: ... + def startall(self) -> None: ... + def resume(self) -> None: ... + def done(self, save: bool = ...) -> Tuple[IO[str], IO[str]]: ... + def readouterr(self) -> Tuple[IO[str], IO[str]]: ... + +# XXX: The type here is not exactly right. If f is IO[bytes] and +# encoding is not None, returns some weird hybrid, not exactly IO[bytes]. +def dupfile( + f: IO[AnyStr], + mode: Optional[str] = ..., + buffering: int = ..., + raising: bool = ..., + encoding: Optional[str] = ..., +) -> IO[AnyStr]: ... +def get_terminal_width() -> int: ... +def ansi_print( + text: Union[str, Text], + esc: Union[Union[str, Text], Tuple[Union[str, Text], ...]], + file: Optional[IO[Any]] = ..., + newline: bool = ..., + flush: bool = ..., +) -> None: ... +def saferepr(obj, maxsize: int = ...) -> str: ... + +class TerminalWriter: + stringio: TextIO + encoding: Final[str] + hasmarkup: bool + def __init__(self, file: Optional[IO[str]] = ..., stringio: bool = ..., encoding: Optional[str] = ...) -> None: ... + @property + def fullwidth(self) -> int: ... + @fullwidth.setter + def fullwidth(self, value: int) -> None: ... + @property + def chars_on_current_line(self) -> int: ... + @property + def width_of_current_line(self) -> int: ... + def markup( + self, + text: str, + *, + black: int = ..., red: int = ..., green: int = ..., yellow: int = ..., blue: int = ..., purple: int = ..., + cyan: int = ..., white: int = ..., Black: int = ..., Red: int = ..., Green: int = ..., Yellow: int = ..., + Blue: int = ..., Purple: int = ..., Cyan: int = ..., White: int = ..., bold: int = ..., light: int = ..., + blink: int = ..., invert: int = ..., + ) -> str: ... + def sep( + self, + sepchar: str, + title: Optional[str] = ..., + fullwidth: Optional[int] = ..., + *, + black: int = ..., red: int = ..., green: int = ..., yellow: int = ..., blue: int = ..., purple: int = ..., + cyan: int = ..., white: int = ..., Black: int = ..., Red: int = ..., Green: int = ..., Yellow: int = ..., + Blue: int = ..., Purple: int = ..., Cyan: int = ..., White: int = ..., bold: int = ..., light: int = ..., + blink: int = ..., invert: int = ..., + ) -> None: ... + def write( + self, + msg: str, + *, + black: int = ..., red: int = ..., green: int = ..., yellow: int = ..., blue: int = ..., purple: int = ..., + cyan: int = ..., white: int = ..., Black: int = ..., Red: int = ..., Green: int = ..., Yellow: int = ..., + Blue: int = ..., Purple: int = ..., Cyan: int = ..., White: int = ..., bold: int = ..., light: int = ..., + blink: int = ..., invert: int = ..., + ) -> None: ... + def line( + self, + s: str = ..., + *, + black: int = ..., red: int = ..., green: int = ..., yellow: int = ..., blue: int = ..., purple: int = ..., + cyan: int = ..., white: int = ..., Black: int = ..., Red: int = ..., Green: int = ..., Yellow: int = ..., + Blue: int = ..., Purple: int = ..., Cyan: int = ..., White: int = ..., bold: int = ..., light: int = ..., + blink: int = ..., invert: int = ..., + ) -> None: ... + def reline( + self, + line: str, + *, + black: int = ..., red: int = ..., green: int = ..., yellow: int = ..., blue: int = ..., purple: int = ..., + cyan: int = ..., white: int = ..., Black: int = ..., Red: int = ..., Green: int = ..., Yellow: int = ..., + Blue: int = ..., Purple: int = ..., Cyan: int = ..., White: int = ..., bold: int = ..., light: int = ..., + blink: int = ..., invert: int = ..., + ) -> None: ... diff --git a/lib/ramble/external/py/path.pyi b/lib/ramble/external/py/path.pyi new file mode 100644 index 000000000..1ddab9601 --- /dev/null +++ b/lib/ramble/external/py/path.pyi @@ -0,0 +1,197 @@ +from typing import Any, AnyStr, Callable, ContextManager, Generic, IO, Iterable, Iterator, List, Optional, Text, Type, Union +from typing_extensions import Final, Literal +import os +import sys + +class _FNMatcher(Generic[AnyStr]): + pattern: AnyStr = ... + def __init__(self, pattern: AnyStr) -> None: ... + def __call__(self, path: local) -> bool: ... + +class _Stat: + path: Final[local] = ... + mode: Final[int] + ino: Final[int] + dev: Final[int] + nlink: Final[int] + uid: Final[int] + gid: Final[int] + size: Final[int] + atime: Final[float] + mtime: Final[float] + ctime: Final[float] + atime_ns: Final[int] + mtime_ns: Final[int] + ctime_ns: Final[int] + if sys.version_info >= (3, 8) and sys.platform == "win32": + reparse_tag: Final[int] + blocks: Final[int] + blksize: Final[int] + rdev: Final[int] + flags: Final[int] + gen: Final[int] + birthtime: Final[int] + rsize: Final[int] + creator: Final[int] + type: Final[int] + if sys.platform != 'win32': + @property + def owner(self) -> str: ... + @property + def group(self) -> str: ... + def isdir(self) -> bool: ... + def isfile(self) -> bool: ... + def islink(self) -> bool: ... + + +if sys.version_info >= (3, 6): + _PathLike = os.PathLike +else: + class _PathLike(Generic[AnyStr]): + def __fspath__(self) -> AnyStr: ... +_PathType = Union[bytes, Text, _PathLike[str], _PathLike[bytes], local] + +class local(_PathLike[str]): + class ImportMismatchError(ImportError): ... + + sep: Final[str] + strpath: Final[str] + + def __init__(self, path: _PathType = ..., expanduser: bool = ...) -> None: ... + def __hash__(self) -> int: ... + def __eq__(self, other: object) -> bool: ... + def __ne__(self, other: object) -> bool: ... + def __lt__(self, other: object) -> bool: ... + def __gt__(self, other: object) -> bool: ... + def __add__(self, other: object) -> local: ... + def __cmp__(self, other: object) -> int: ... + def __div__(self, other: _PathType) -> local: ... + def __truediv__(self, other: _PathType) -> local: ... + def __fspath__(self) -> str: ... + + @classmethod + def get_temproot(cls) -> local: ... + @classmethod + def make_numbered_dir( + cls, + prefix: str = ..., + rootdir: Optional[local] = ..., + keep: Optional[int] = ..., + lock_timeout: int = ..., + ) -> local: ... + @classmethod + def mkdtemp(cls, rootdir: Optional[local] = ...) -> local: ... + @classmethod + def sysfind( + cls, + name: _PathType, + checker: Optional[Callable[[local], bool]] = ..., + paths: Optional[Iterable[_PathType]] = ..., + ) -> Optional[local]: ... + + @property + def basename(self) -> str: ... + @property + def dirname(self) -> str: ... + @property + def purebasename(self) -> str: ... + @property + def ext(self) -> str: ... + + def as_cwd(self) -> ContextManager[Optional[local]]: ... + def atime(self) -> float: ... + def bestrelpath(self, dest: local) -> str: ... + def chdir(self) -> local: ... + def check( + self, + *, + basename: int = ..., notbasename: int = ..., + basestarts: int = ..., notbasestarts: int = ..., + dir: int = ..., notdir: int = ..., + dotfile: int = ..., notdotfile: int = ..., + endswith: int = ..., notendswith: int = ..., + exists: int = ..., notexists: int = ..., + ext: int = ..., notext: int = ..., + file: int = ..., notfile: int = ..., + fnmatch: int = ..., notfnmatch: int = ..., + link: int = ..., notlink: int = ..., + relto: int = ..., notrelto: int = ..., + ) -> bool: ... + def chmod(self, mode: int, rec: Union[int, str, Text, Callable[[local], bool]] = ...) -> None: ... + if sys.platform != 'win32': + def chown(self, user: Union[int, str], group: Union[int, str], rec: int = ...) -> None: ... + def common(self, other: local) -> Optional[local]: ... + def computehash(self, hashtype: str = ..., chunksize: int = ...) -> str: ... + def copy(self, target: local, mode: bool = ..., stat: bool = ...) -> None: ... + def dirpath(self, *args: _PathType, abs: int = ...) -> local: ... + def dump(self, obj: Any, bin: Optional[int] = ...) -> None: ... + def ensure(self, *args: _PathType, dir: int = ...) -> local: ... + def ensure_dir(self, *args: _PathType) -> local: ... + def exists(self) -> bool: ... + def fnmatch(self, pattern: str): _FNMatcher + def isdir(self) -> bool: ... + def isfile(self) -> bool: ... + def islink(self) -> bool: ... + def join(self, *args: _PathType, abs: int = ...) -> local: ... + def listdir( + self, + fil: Optional[Union[str, Text, Callable[[local], bool]]] = ..., + sort: Optional[bool] = ..., + ) -> List[local]: ... + def load(self) -> Any: ... + def lstat(self) -> _Stat: ... + def mkdir(self, *args: _PathType) -> local: ... + if sys.platform != 'win32': + def mklinkto(self, oldname: Union[str, local]) -> None: ... + def mksymlinkto(self, value: local, absolute: int = ...) -> None: ... + def move(self, target: local) -> None: ... + def mtime(self) -> float: ... + def new( + self, + *, + drive: str = ..., + dirname: str = ..., + basename: str = ..., + purebasename: str = ..., + ext: str = ..., + ) -> local: ... + def open(self, mode: str = ..., ensure: bool = ..., encoding: Optional[str] = ...) -> IO[Any]: ... + def parts(self, reverse: bool = ...) -> List[local]: ... + def pyimport( + self, + modname: Optional[str] = ..., + ensuresyspath: Union[bool, Literal["append", "importlib"]] = ..., + ) -> Any: ... + def pypkgpath(self) -> Optional[local]: ... + def read(self, mode: str = ...) -> Union[Text, bytes]: ... + def read_binary(self) -> bytes: ... + def read_text(self, encoding: str) -> Text: ... + def readlines(self, cr: int = ...) -> List[str]: ... + if sys.platform != 'win32': + def readlink(self) -> str: ... + def realpath(self) -> local: ... + def relto(self, relpath: Union[str, local]) -> str: ... + def remove(self, rec: int = ..., ignore_errors: bool = ...) -> None: ... + def rename(self, target: _PathType) -> None: ... + def samefile(self, other: _PathType) -> bool: ... + def setmtime(self, mtime: Optional[float] = ...) -> None: ... + def size(self) -> int: ... + def stat(self, raising: bool = ...) -> _Stat: ... + def sysexec(self, *argv: Any, **popen_opts: Any) -> Text: ... + def visit( + self, + fil: Optional[Union[str, Text, Callable[[local], bool]]] = ..., + rec: Optional[Union[Literal[1, True], str, Text, Callable[[local], bool]]] = ..., + ignore: Type[Exception] = ..., + bf: bool = ..., + sort: bool = ..., + ) -> Iterator[local]: ... + def write(self, data: Any, mode: str = ..., ensure: bool = ...) -> None: ... + def write_binary(self, data: bytes, ensure: bool = ...) -> None: ... + def write_text(self, data: Union[str, Text], encoding: str, ensure: bool = ...) -> None: ... + + +# Untyped types below here. +svnwc: Any +svnurl: Any +SvnAuth: Any diff --git a/lib/ramble/external/py/py.typed b/lib/ramble/external/py/py.typed new file mode 100644 index 000000000..e69de29bb diff --git a/lib/ramble/external/py/xml.pyi b/lib/ramble/external/py/xml.pyi new file mode 100644 index 000000000..9c44480a5 --- /dev/null +++ b/lib/ramble/external/py/xml.pyi @@ -0,0 +1,25 @@ +from typing import ClassVar, Generic, Iterable, Text, Type, Union +from typing_extensions import Final + +class raw: + uniobj: Final[Text] + def __init__(self, uniobj: Text) -> None: ... + +class _NamespaceMetaclass(type): + def __getattr__(self, name: str) -> Type[Tag]: ... + +class Namespace(metaclass=_NamespaceMetaclass): ... + +class Tag(list): + class Attr: + def __getattr__(self, attr: str) -> Text: ... + attr: Final[Attr] + def __init__(self, *args: Union[Text, raw, Tag, Iterable[Tag]], **kwargs: Union[Text, raw]) -> None: ... + def unicode(self, indent: int = ...) -> Text: ... + +class html(Namespace): + class Style: + def __init__(self, **kw: Union[str, Text]) -> None: ... + style: ClassVar[Style] + +def escape(ustring: Union[str, Text]) -> Text: ... diff --git a/lib/ramble/llnl/util/argparsewriter.py b/lib/ramble/llnl/util/argparsewriter.py index 39313c38d..80be621f5 100644 --- a/lib/ramble/llnl/util/argparsewriter.py +++ b/lib/ramble/llnl/util/argparsewriter.py @@ -10,11 +10,10 @@ import argparse import errno +import io import re import sys -from six import StringIO - class Command(object): """Parsed representation of a command from argparse. @@ -186,7 +185,7 @@ def __init__(self, prog, out=None, aliases=False, self.rst_levels = rst_levels def format(self, cmd): - string = StringIO() + string = io.StringIO() string.write(self.begin_command(cmd.prog)) if cmd.description: diff --git a/lib/ramble/llnl/util/filesystem.py b/lib/ramble/llnl/util/filesystem.py index c57a5d3e9..cf00e91d9 100644 --- a/lib/ramble/llnl/util/filesystem.py +++ b/lib/ramble/llnl/util/filesystem.py @@ -20,8 +20,6 @@ from contextlib import contextmanager from sys import platform as _platform -import six - from llnl.util import tty from llnl.util.compat import Sequence from llnl.util.lang import dedupe, memoized @@ -375,7 +373,7 @@ def chgrp(path, group, follow_symlinks=True): if is_windows: raise OSError("Function 'chgrp' is not supported on Windows") - if isinstance(group, six.string_types): + if isinstance(group, str): gid = grp.getgrnam(group).gr_gid else: gid = group @@ -870,7 +868,7 @@ def open_if_filename(str_or_file, mode='r'): If it's a file object, just yields the file object. """ - if isinstance(str_or_file, six.string_types): + if isinstance(str_or_file, str): with open(str_or_file, mode) as f: yield f else: @@ -1392,7 +1390,7 @@ def find(root, files, recursive=True): Returns: list: The files that have been found """ - if isinstance(files, six.string_types): + if isinstance(files, str): files = [files] if recursive: @@ -1456,7 +1454,7 @@ class FileList(Sequence): """ def __init__(self, files): - if isinstance(files, six.string_types): + if isinstance(files, str): files = [files] self.files = list(dedupe(files)) @@ -1554,7 +1552,7 @@ def directories(self): def directories(self, value): value = value or [] # Accept a single directory as input - if isinstance(value, six.string_types): + if isinstance(value, str): value = [value] self._directories = [path_to_os_path(os.path.normpath(x))[0] for x in value] @@ -1690,7 +1688,7 @@ def find_headers(headers, root, recursive=False): Returns: HeaderList: The headers that have been found """ - if isinstance(headers, six.string_types): + if isinstance(headers, str): headers = [headers] elif not isinstance(headers, Sequence): message = '{0} expects a string or sequence of strings as the ' @@ -1846,7 +1844,7 @@ def find_system_libraries(libraries, shared=True): Returns: LibraryList: The libraries that have been found """ - if isinstance(libraries, six.string_types): + if isinstance(libraries, str): libraries = [libraries] elif not isinstance(libraries, Sequence): message = '{0} expects a string or sequence of strings as the ' @@ -1900,7 +1898,7 @@ def find_libraries(libraries, root, shared=True, recursive=False): Returns: LibraryList: The libraries that have been found """ - if isinstance(libraries, six.string_types): + if isinstance(libraries, str): libraries = [libraries] elif not isinstance(libraries, Sequence): message = '{0} expects a string or sequence of strings as the ' diff --git a/lib/ramble/llnl/util/lang.py b/lib/ramble/llnl/util/lang.py index 5fadc5d85..592bfacc4 100644 --- a/lib/ramble/llnl/util/lang.py +++ b/lib/ramble/llnl/util/lang.py @@ -18,9 +18,6 @@ from datetime import datetime, timedelta from typing import List, Tuple -import six -from six import string_types - from llnl.util.compat import MutableMapping, MutableSequence, zip_longest # Ignore emacs backups when listing modules @@ -202,12 +199,9 @@ def _memoized_function(*args, **kwargs): return ret except TypeError as e: # TypeError is raised when indexing into a dict if the key is unhashable. - raise six.raise_from( - UnhashableArguments( - "args + kwargs '{}' was not hashable for function '{}'" - .format(key, func.__name__), - ), - e) + raise UnhashableArguments( + "args + kwargs '{}' was not hashable for function '{}'".format(key, func.__name__), + ) from e return _memoized_function diff --git a/lib/ramble/llnl/util/tty/__init__.py b/lib/ramble/llnl/util/tty/__init__.py index 893819699..9c8627ad3 100644 --- a/lib/ramble/llnl/util/tty/__init__.py +++ b/lib/ramble/llnl/util/tty/__init__.py @@ -9,6 +9,7 @@ from __future__ import unicode_literals import contextlib +import io import os import struct import sys @@ -17,10 +18,6 @@ from datetime import datetime from sys import platform as _platform -import six -from six import StringIO -from six.moves import input - if _platform != "win32": import fcntl import termios @@ -202,7 +199,7 @@ def msg(message, *args, **kwargs): ) ) for arg in args: - print(indent + _output_filter(six.text_type(arg))) + print(indent + _output_filter(str(arg))) def info(message, *args, **kwargs): @@ -223,14 +220,14 @@ def info(message, *args, **kwargs): format, st_text, get_timestamp(), - cescape(_output_filter(six.text_type(message))) + cescape(_output_filter(str(message))) ), stream=stream ) for arg in args: if wrap: lines = textwrap.wrap( - _output_filter(six.text_type(arg)), + _output_filter(str(arg)), initial_indent=indent, subsequent_indent=indent, break_long_words=break_long_words @@ -239,7 +236,7 @@ def info(message, *args, **kwargs): stream.write(line + '\n') else: stream.write( - indent + _output_filter(six.text_type(arg)) + '\n' + indent + _output_filter(str(arg)) + '\n' ) @@ -263,7 +260,7 @@ def error(message, *args, **kwargs): kwargs.setdefault('format', '*r') kwargs.setdefault('stream', sys.stderr) - info("Error: " + six.text_type(message), *args, **kwargs) + info("Error: " + str(message), *args, **kwargs) def warn(message, *args, **kwargs): @@ -272,7 +269,7 @@ def warn(message, *args, **kwargs): kwargs.setdefault('format', '*Y') kwargs.setdefault('stream', sys.stderr) - info("Warning: " + six.text_type(message), *args, **kwargs) + info("Warning: " + str(message), *args, **kwargs) def die(message, *args, **kwargs): @@ -295,8 +292,7 @@ def get_number(prompt, **kwargs): number = None while number is None: msg(prompt, newline=False) - ans = input() - if ans == six.text_type(abort): + if ans == str(abort): return None if ans: @@ -328,7 +324,6 @@ def get_yes_or_no(prompt, **kwargs): result = None while result is None: msg(prompt, newline=False) - ans = input().lower() if not ans: result = default_value if result is None: @@ -362,11 +357,11 @@ def hline(label=None, **kwargs): cols -= 2 cols = min(max_width, cols) - label = six.text_type(label) + label = str(label) prefix = char * 2 + " " suffix = " " + (cols - len(prefix) - clen(label)) * char - out = StringIO() + out = io.StringIO() out.write(prefix) out.write(label) out.write(suffix) diff --git a/lib/ramble/llnl/util/tty/colify.py b/lib/ramble/llnl/util/tty/colify.py index b2cbecf1a..defdfd62e 100644 --- a/lib/ramble/llnl/util/tty/colify.py +++ b/lib/ramble/llnl/util/tty/colify.py @@ -11,11 +11,10 @@ """ from __future__ import division, unicode_literals +import io import os import sys -from six import StringIO, text_type - from llnl.util.tty import terminal_size from llnl.util.tty.color import cextra, clen @@ -139,7 +138,7 @@ def colify(elts, **options): % next(options.iterkeys())) # elts needs to be an array of strings so we can count the elements - elts = [text_type(elt) for elt in elts] + elts = [str(elt) for elt in elts] if not elts: return (0, ()) @@ -237,7 +236,7 @@ def transpose(): def colified(elts, **options): """Invokes the ``colify()`` function but returns the result as a string instead of writing it to an output string.""" - sio = StringIO() + sio = io.StringIO() options['output'] = sio colify(elts, **options) return sio.getvalue() diff --git a/lib/ramble/llnl/util/tty/color.py b/lib/ramble/llnl/util/tty/color.py index c7a167611..8c02b0a81 100644 --- a/lib/ramble/llnl/util/tty/color.py +++ b/lib/ramble/llnl/util/tty/color.py @@ -68,8 +68,6 @@ import sys from contextlib import contextmanager -import six - class ColorParseError(Exception): """Raised when a color format fails to parse.""" @@ -253,7 +251,7 @@ def cescape(string): Returns: (str): the string with color codes escaped """ - string = six.text_type(string) + string = str(string) string = string.replace('@', '@@') string = string.replace('}', '}}') return string diff --git a/lib/ramble/llnl/util/tty/log.py b/lib/ramble/llnl/util/tty/log.py index 7a5bb8089..d7b5a45f1 100644 --- a/lib/ramble/llnl/util/tty/log.py +++ b/lib/ramble/llnl/util/tty/log.py @@ -27,8 +27,6 @@ from types import ModuleType # novm from typing import Optional # novm -from six import StringIO, string_types - import llnl.util.tty as tty termios = None # type: Optional[ModuleType] @@ -313,7 +311,7 @@ def __init__(self, file_like): self.file_like = file_like - if isinstance(file_like, string_types): + if isinstance(file_like, str): self.open = True elif _file_descriptors_work(file_like): self.open = False @@ -332,7 +330,7 @@ def unwrap(self): else: self.file = open(self.file_like, 'w', encoding='utf-8') # novm else: - self.file = StringIO() + self.file = io.StringIO() return self.file else: # We were handed an already-open file object. In this case we also @@ -793,7 +791,7 @@ def __enter__(self): "file argument must be set by __init__ ") # Open both write and reading on logfile - if type(self.logfile) == StringIO: + if type(self.logfile) == io.StringIO: self._ioflag = True # cannot have two streams on tempfile, so we must make our own sys.stdout = self.logfile @@ -1015,7 +1013,7 @@ def _writer_daemon(stdin_multiprocess_fd, read_multiprocess_fd, write_fd, echo, finally: # send written data back to parent if we used a StringIO - if isinstance(log_file, StringIO): + if isinstance(log_file, io.StringIO): control_pipe.send(log_file.getvalue()) log_file_wrapper.close() close_connection_and_file(read_multiprocess_fd, in_pipe) diff --git a/lib/ramble/ramble/application.py b/lib/ramble/ramble/application.py index 5897bb405..576ffb70b 100644 --- a/lib/ramble/ramble/application.py +++ b/lib/ramble/ramble/application.py @@ -7,10 +7,10 @@ # except according to those terms. """Define base classes for application definitions""" +import io import os import stat import re -import six import textwrap import string import shutil @@ -498,7 +498,7 @@ def format_doc(self, **kwargs): doc = re.sub(r"\s+", " ", self.__doc__) lines = textwrap.wrap(doc, 72) - results = six.StringIO() + results = io.StringIO() for line in lines: results.write((" " * indent) + line + "\n") return results.getvalue() @@ -1250,7 +1250,7 @@ def _clean_hash_variables(self, workspace, variables): # Remove the workspace path from variable definitions before hashing for var in variables: - if isinstance(variables[var], six.string_types): + if isinstance(variables[var], str): variables[var] = variables[var].replace(workspace.root + os.path.sep, "") def populate_inventory(self, workspace, force_compute=False, require_exist=False): @@ -1444,7 +1444,7 @@ def _analyze_experiments(self, workspace, app_inst=None): def format_context(context_match, context_format): context_val = {} - if isinstance(context_format, six.string_types): + if isinstance(context_format, str): for group in string.Formatter().parse(context_format): if group[1]: context_val[group[1]] = context_match[group[1]] diff --git a/lib/ramble/ramble/application_types/spack.py b/lib/ramble/ramble/application_types/spack.py index 77c52bb00..c5c8bbe55 100644 --- a/lib/ramble/ramble/application_types/spack.py +++ b/lib/ramble/ramble/application_types/spack.py @@ -7,7 +7,6 @@ # except according to those terms. import os -import six import shutil import llnl.util.filesystem as fs @@ -475,7 +474,7 @@ def _clean_hash_variables(self, workspace, variables): self.spack_runner.activate() for var in variables: - if isinstance(variables[var], six.string_types): + if isinstance(variables[var], str): variables[var] = variables[var].replace( "\n".join(self.spack_runner.generate_source_command()), "spack_source" ) diff --git a/lib/ramble/ramble/cmd/unit_test.py b/lib/ramble/ramble/cmd/unit_test.py index aa0fdf30b..939a0e3df 100644 --- a/lib/ramble/ramble/cmd/unit_test.py +++ b/lib/ramble/ramble/cmd/unit_test.py @@ -10,10 +10,10 @@ from __future__ import division import collections +import io import sys import re import argparse -from six import StringIO import llnl.util.tty.color as color from llnl.util.filesystem import working_dir @@ -108,7 +108,7 @@ def do_list(args, extra_args): # Run test collection and get the tree out. old_output = sys.stdout try: - sys.stdout = output = StringIO() + sys.stdout = output = io.StringIO() try: import pytest diff --git a/lib/ramble/ramble/config.py b/lib/ramble/ramble/config.py index c96b6545e..303b07714 100644 --- a/lib/ramble/ramble/config.py +++ b/lib/ramble/ramble/config.py @@ -40,9 +40,7 @@ from contextlib import contextmanager import ruamel.yaml as yaml -import six from ruamel.yaml.error import MarkedYAMLError -from six import iteritems import llnl.util.lang from llnl.util.filesystem import mkdirp, rename @@ -391,7 +389,7 @@ def clear(self): def _process_dict_keyname_overrides(data): """Turn a trailing `:' in a key name into an override attribute.""" result = {} - for sk, sv in iteritems(data): + for sk, sv in data.items(): if sk.endswith(":"): key = syaml.syaml_str(sk[:-1]) key.override = True @@ -982,7 +980,7 @@ def validate(data, schema, filename=None): line_number = e.instance.lc.line + 1 else: line_number = None - raise six.raise_from(ConfigFormatError(e, data, filename, line_number), e) + raise ConfigFormatError(e, data, filename, line_number) from e # return the validated data so that we can access the raw data # mostly relevant for workspaces return test_data @@ -1140,7 +1138,7 @@ def they_are(t): # come *before* dest in OrderedDicts dest_keys = [dk for dk in dest.keys() if dk not in source] - for sk, sv in iteritems(source): + for sk, sv in source.items(): # always remove the dest items. Python dicts do not overwrite # keys on insert, so this ensures that source keys are copied # into dest along with mark provenance (i.e., file/line info). diff --git a/lib/ramble/ramble/expander.py b/lib/ramble/ramble/expander.py index 082ea7333..063784056 100644 --- a/lib/ramble/ramble/expander.py +++ b/lib/ramble/ramble/expander.py @@ -8,7 +8,6 @@ import string import ast -import six import operator import math import random @@ -226,7 +225,7 @@ def define_value( self.value = replaced_contents # Replace escaped curly braces with curly braces - if isinstance(self.value, six.string_types): + if isinstance(self.value, str): self.value = self.value.replace("\\{", "{").replace("\\}", "}") @@ -572,7 +571,7 @@ def evaluate_predicate(self, in_str, extra_vars=None): evaluated = self.expand_var(in_str, extra_vars=extra_vars, allow_passthrough=False) - if not isinstance(evaluated, six.string_types): + if not isinstance(evaluated, str): logger.die("Logical compute failed to return a string") if evaluated == "True": @@ -602,7 +601,7 @@ def _partial_expand(self, expansion_vars, in_str, allow_passthrough=True): in_str (str): Expanded version of input string """ - if isinstance(in_str, six.string_types): + if isinstance(in_str, str): str_graph = ExpansionGraph(in_str) for node in str_graph.walk(): node.define_value( @@ -830,7 +829,7 @@ def _eval_binary_ops(self, node): left_eval = self.eval_math(node.left) right_eval = self.eval_math(node.right) op = supported_math_operators[type(node.op)] - if isinstance(left_eval, six.string_types) or isinstance(right_eval, six.string_types): + if isinstance(left_eval, str) or isinstance(right_eval, str): raise SyntaxError("Unsupported operand type in binary operator") return op(left_eval, right_eval) except TypeError: @@ -845,7 +844,7 @@ def _eval_unary_ops(self, node): """ try: operand = self.eval_math(node.operand) - if isinstance(operand, six.string_types): + if isinstance(operand, str): raise SyntaxError("Unsupported operand type in unary operator") op = supported_math_operators[type(node.op)] return op(operand) diff --git a/lib/ramble/ramble/fetch_strategy.py b/lib/ramble/ramble/fetch_strategy.py index 23ac6855b..ce1aa67ee 100644 --- a/lib/ramble/ramble/fetch_strategy.py +++ b/lib/ramble/ramble/fetch_strategy.py @@ -34,8 +34,7 @@ import llnl.util.tty as tty -import six -import six.moves.urllib.parse as urllib_parse +import urllib.parse import spack.error import spack.util.crypto as crypto import spack.util.pattern as pattern @@ -311,7 +310,7 @@ def candidate_urls(self): # This must be skipped on Windows due to URL encoding # of ':' characters on filepaths on Windows if sys.platform != "win32" and url.startswith("file://"): - path = urllib_parse.quote(url[len("file://") :]) + path = urllib.parse.quote(url[len("file://") :]) url = "file://" + path urls.append(url) @@ -712,7 +711,7 @@ def archive(self, destination, **kwargs): patterns = kwargs.get("exclude", None) if patterns is not None: - if isinstance(patterns, six.string_types): + if isinstance(patterns, str): patterns = [patterns] for p in patterns: tar.add_default_arg("--exclude=%s" % p) @@ -1652,7 +1651,7 @@ def from_url_scheme(url, *args, **kwargs): in the given url.""" url = kwargs.get("url", url) - parsed_url = urllib_parse.urlparse(url, scheme="file") + parsed_url = urllib.parse.urlparse(url, scheme="file") scheme_mapping = kwargs.get("scheme_mapping") or { "file": "url", diff --git a/lib/ramble/ramble/language/language_base.py b/lib/ramble/ramble/language/language_base.py index 2baaa7dcb..a4d2e1b8c 100644 --- a/lib/ramble/ramble/language/language_base.py +++ b/lib/ramble/ramble/language/language_base.py @@ -13,8 +13,6 @@ import functools import sys -from six import string_types - import llnl.util.lang import llnl.util.tty.color @@ -160,7 +158,7 @@ class Foo(ApplicationBase): the core. """ - if isinstance(dicts, string_types): + if isinstance(dicts, str): dicts = (dicts,) if not isinstance(dicts, Sequence): diff --git a/lib/ramble/ramble/language/language_helpers.py b/lib/ramble/ramble/language/language_helpers.py index e247c0ba6..982a58f90 100644 --- a/lib/ramble/ramble/language/language_helpers.py +++ b/lib/ramble/ramble/language/language_helpers.py @@ -7,7 +7,6 @@ # except according to those terms. import fnmatch -import six from ramble.language.language_base import DirectiveError @@ -29,7 +28,7 @@ def check_definition( Returns: List of all type names (Merged if both single_type and multiple_type definitions are valid) """ - if single_type and not isinstance(single_type, six.string_types): + if single_type and not isinstance(single_type, str): raise DirectiveError( f"Directive {directive_name} was given an invalid type " f"for the {single_arg_name} argument. " diff --git a/lib/ramble/ramble/main.py b/lib/ramble/ramble/main.py index 51069d1fd..8d73da757 100644 --- a/lib/ramble/ramble/main.py +++ b/lib/ramble/ramble/main.py @@ -15,6 +15,7 @@ import argparse import inspect +import io import operator import os import os.path @@ -27,8 +28,6 @@ import jsonschema import ruamel -from six import StringIO - import llnl.util.lang import llnl.util.tty as tty import llnl.util.tty.colify @@ -706,7 +705,7 @@ def __call__(self, *argv, **kwargs): else: ramble.workspace.shell.deactivate() - out = StringIO() + out = io.StringIO() try: with log_output(out): self.returncode = _invoke_command(self.command, self.parser, args, unknown) diff --git a/lib/ramble/ramble/mirror.py b/lib/ramble/ramble/mirror.py index 822f41b47..b5d15369a 100644 --- a/lib/ramble/ramble/mirror.py +++ b/lib/ramble/ramble/mirror.py @@ -23,7 +23,6 @@ import traceback import ruamel.yaml.error as yaml_error -import six from llnl.util.compat import Mapping from llnl.util.filesystem import mkdirp @@ -41,7 +40,7 @@ def _is_string(url): - return isinstance(url, six.string_types) + return isinstance(url, str) def _display_mirror_entry(size, name, url, type_=None): @@ -81,10 +80,7 @@ def from_yaml(stream, name=None): data = spack.util.spack_yaml.load(stream) return Mirror.from_dict(data, name) except yaml_error.MarkedYAMLError as e: - raise six.raise_from( - spack.util.spack_yaml.SpackYAMLError("error parsing YAML mirror:", str(e)), - e, - ) + raise spack.util.spack_yaml.SpackYAMLError("error parsing YAML mirror:", str(e)) from e @staticmethod def from_json(stream, name=None): @@ -92,10 +88,7 @@ def from_json(stream, name=None): d = spack.util.spack_json.load(stream) return Mirror.from_dict(d, name) except Exception as e: - raise six.raise_from( - spack.util.spack_json.SpackJSONError("error parsing JSON mirror:", str(e)), - e, - ) + raise spack.util.spack_json.SpackJSONError("error parsing JSON mirror:", str(e)) from e def to_dict(self): return syaml_dict( @@ -104,7 +97,7 @@ def to_dict(self): @staticmethod def from_dict(d, name=None): - if isinstance(d, six.string_types): + if isinstance(d, str): return Mirror(d, name=name) else: return Mirror(d["fetch"], d["push"], name=name) diff --git a/lib/ramble/ramble/modifier.py b/lib/ramble/ramble/modifier.py index 6d8460bd8..37146ec44 100644 --- a/lib/ramble/ramble/modifier.py +++ b/lib/ramble/ramble/modifier.py @@ -7,8 +7,8 @@ # except according to those terms. """Define base classes for modifier definitions""" +import io import re -import six import textwrap import fnmatch from typing import List @@ -229,7 +229,7 @@ def format_doc(self, **kwargs): doc = re.sub(r"\s+", " ", self.__doc__) lines = textwrap.wrap(doc, 72) - results = six.StringIO() + results = io.StringIO() for line in lines: results.write((" " * indent) + line + "\n") return results.getvalue() diff --git a/lib/ramble/ramble/repository.py b/lib/ramble/ramble/repository.py index c5b2e6038..a2ec11dac 100644 --- a/lib/ramble/ramble/repository.py +++ b/lib/ramble/ramble/repository.py @@ -30,7 +30,6 @@ from enum import Enum -import six import ruamel.yaml as yaml @@ -373,8 +372,7 @@ def update_object(self, obj_name): self._tag_dict[tag].append(obj.name) -@six.add_metaclass(abc.ABCMeta) -class Indexer(object): +class Indexer(metaclass=abc.ABCMeta): """Adaptor for indexes that need to be generated when repos are updated.""" def __init__(self, object_type=default_type): @@ -550,7 +548,7 @@ def __init__(self, *repos, object_type=default_type): # Add each repo to this path. for repo in repos: try: - if isinstance(repo, six.string_types): + if isinstance(repo, str): repo = Repo(repo, object_type=object_type) self.put_last(repo) except RepoError as e: diff --git a/lib/ramble/ramble/schema/__init__.py b/lib/ramble/ramble/schema/__init__.py index 34c5644c2..e78b15ac7 100644 --- a/lib/ramble/ramble/schema/__init__.py +++ b/lib/ramble/ramble/schema/__init__.py @@ -7,8 +7,6 @@ # except according to those terms. """This module contains jsonschema files for all of Ramble's YAML formats.""" -import six - import llnl.util.lang import llnl.util.tty @@ -30,7 +28,7 @@ def _deprecated_properties(validator, deprecated, instance, schema): # Retrieve the template message msg_str_or_func = deprecated["message"] - if isinstance(msg_str_or_func, six.string_types): + if isinstance(msg_str_or_func, str): msg = msg_str_or_func.format(properties=deprecated_properties) else: msg = msg_str_or_func(instance, deprecated_properties) diff --git a/lib/ramble/ramble/spec.py b/lib/ramble/ramble/spec.py index 86a6d1a50..a29df4e46 100644 --- a/lib/ramble/ramble/spec.py +++ b/lib/ramble/ramble/spec.py @@ -6,8 +6,8 @@ # option. This file may not be copied, modified, or distributed # except according to those terms. +import io import os -import six import llnl.util.tty.color as clr @@ -142,7 +142,7 @@ def __init__(self, spec_like=None): self._application_class = None self.workloads = {} - if isinstance(spec_like, six.string_types): + if isinstance(spec_like, str): namespace, dot, spec_name = spec_like.rpartition(".") if not namespace: namespace = None @@ -183,7 +183,7 @@ def format(self, format_string=default_format, **kwargs): color = kwargs.get("color", False) transform = kwargs.get("transform", {}) - out = six.StringIO() + out = io.StringIO() def write(s, c=None): f = clr.cescape(s) diff --git a/lib/ramble/ramble/stage.py b/lib/ramble/ramble/stage.py index 34eb2d599..621b1343a 100644 --- a/lib/ramble/ramble/stage.py +++ b/lib/ramble/ramble/stage.py @@ -17,8 +17,6 @@ import shutil import stat import sys -from six import string_types -from six import iteritems import llnl.util.lang import llnl.util.tty as tty @@ -264,7 +262,7 @@ def __init__( """ # TODO: fetch/stage coupling needs to be reworked -- the logic # TODO: here is convoluted and not modular enough. - if isinstance(url_or_fetch_strategy, string_types): + if isinstance(url_or_fetch_strategy, str): self.fetcher = fs.from_url_scheme(url_or_fetch_strategy) elif isinstance(url_or_fetch_strategy, fs.FetchStrategy): self.fetcher = url_or_fetch_strategy @@ -673,7 +671,7 @@ def _add_to_root_stage(self): else: raise - for key, value in iteritems(placement): + for key, value in placement.items(): destination_path = os.path.join(target_path, value) source_path = os.path.join(self.source_path, key) diff --git a/lib/ramble/ramble/util/executable.py b/lib/ramble/ramble/util/executable.py index 843014130..c5ee71b8d 100644 --- a/lib/ramble/ramble/util/executable.py +++ b/lib/ramble/ramble/util/executable.py @@ -6,7 +6,6 @@ # option. This file may not be copied, modified, or distributed # except according to those terms. -import six import shlex import ramble.error @@ -88,7 +87,7 @@ def __init__( - output_capture: Operator to use when capturing output """ - if isinstance(template, six.string_types): + if isinstance(template, str): self.template = [template] elif isinstance(template, list): self.template = template.copy() diff --git a/lib/ramble/ramble/util/naming.py b/lib/ramble/ramble/util/naming.py index b5938f98d..9d087c1f9 100644 --- a/lib/ramble/ramble/util/naming.py +++ b/lib/ramble/ramble/util/naming.py @@ -8,10 +8,10 @@ # Need this because of ramble.util.string from __future__ import absolute_import +import io import string import itertools import re -from six import StringIO import ramble.error @@ -264,6 +264,6 @@ def _str_helper(self, stream, level=0): stream.write(self._subspaces[name]._str_helper(stream, level + 1)) def __str__(self): - stream = StringIO() + stream = io.StringIO() self._str_helper(stream) return stream.getvalue() diff --git a/lib/ramble/ramble/util/web.py b/lib/ramble/ramble/util/web.py index f19cfb543..72adca78b 100644 --- a/lib/ramble/ramble/util/web.py +++ b/lib/ramble/ramble/util/web.py @@ -19,9 +19,8 @@ import sys import traceback -import six -from six.moves.urllib.error import URLError -from six.moves.urllib.request import Request, urlopen +from urllib.error import URLError +from urllib.request import Request, urlopen import llnl.util.lang from llnl.util.filesystem import mkdirp, rename @@ -507,7 +506,7 @@ def _spider(url, collect_nested): return pages, links, subcalls - if isinstance(root_urls, six.string_types): + if isinstance(root_urls, str): root_urls = [root_urls] # Clear the local cache of visited pages before starting the search diff --git a/lib/ramble/ramble/workspace/workspace.py b/lib/ramble/ramble/workspace/workspace.py index e694fcc2c..738a1188c 100644 --- a/lib/ramble/ramble/workspace/workspace.py +++ b/lib/ramble/ramble/workspace/workspace.py @@ -13,8 +13,6 @@ import shutil import datetime -import six - import llnl.util.filesystem as fs import llnl.util.tty as tty import llnl.util.tty.log as log @@ -1514,7 +1512,7 @@ def yaml_equivalent(first, second): elif isinstance(first, list): return isinstance(second, list) and _equiv_list(first, second) else: # it's a string - return isinstance(second, six.string_types) and first == second + return isinstance(second, str) and first == second def _equiv_list(first, second): diff --git a/lib/ramble/spack/audit.py b/lib/ramble/spack/audit.py index 1075822de..542e8df9c 100644 --- a/lib/ramble/spack/audit.py +++ b/lib/ramble/spack/audit.py @@ -39,7 +39,7 @@ def _search_duplicate_compilers(error_cls): import itertools import re -from six.moves.urllib.request import urlopen +from urllib.request import urlopen import llnl.util.lang from llnl.util.compat import Sequence diff --git a/lib/ramble/spack/binary_distribution.py b/lib/ramble/spack/binary_distribution.py index a0b0e75b8..adf1bff67 100644 --- a/lib/ramble/spack/binary_distribution.py +++ b/lib/ramble/spack/binary_distribution.py @@ -15,9 +15,9 @@ import traceback import warnings from contextlib import closing +from urllib.error import HTTPError, URLError import ruamel.yaml as yaml -from six.moves.urllib.error import HTTPError, URLError import llnl.util.lang import llnl.util.tty as tty diff --git a/lib/ramble/spack/bootstrap.py b/lib/ramble/spack/bootstrap.py index 20668cf07..b251a1ea5 100644 --- a/lib/ramble/spack/bootstrap.py +++ b/lib/ramble/spack/bootstrap.py @@ -16,8 +16,6 @@ import sys import sysconfig -import six - import archspec.cpu import llnl.util.filesystem as fs @@ -72,7 +70,7 @@ def _try_import_from_store(module, query_spec, query_info=None): command found and the concrete spec providing it """ # If it is a string assume it's one of the root specs by this module - if isinstance(query_spec, six.string_types): + if isinstance(query_spec, str): # We have to run as part of this python interpreter query_spec += ' ^' + spec_for_current_python() @@ -877,7 +875,7 @@ def _missing(name, purpose, system_only=True): def _required_system_executable(exes, msg): """Search for an executable is the system path only.""" - if isinstance(exes, six.string_types): + if isinstance(exes, str): exes = (exes,) if spack.util.executable.which_string(*exes): return True, None @@ -895,7 +893,7 @@ def _required_python_module(module, query_spec, msg): def _required_executable(exes, query_spec, msg): """Search for an executable in the system path or in the bootstrap store.""" - if isinstance(exes, six.string_types): + if isinstance(exes, str): exes = (exes,) if (spack.util.executable.which_string(*exes) or _executables_in_store(exes, query_spec)): diff --git a/lib/ramble/spack/build_environment.py b/lib/ramble/spack/build_environment.py index 6b461cf67..6ec84aa32 100644 --- a/lib/ramble/spack/build_environment.py +++ b/lib/ramble/spack/build_environment.py @@ -41,8 +41,6 @@ import traceback import types -from six import StringIO - import llnl.util.tty as tty from llnl.util.filesystem import install, install_tree, mkdirp from llnl.util.lang import dedupe @@ -1327,7 +1325,7 @@ def __init__(self, msg, module, classname, traceback_string, log_name, @property def long_message(self): - out = StringIO() + out = io.StringIO() out.write(self._long_message if self._long_message else '') have_log = self.log_name and os.path.exists(self.log_name) diff --git a/lib/ramble/spack/build_systems/cmake.py b/lib/ramble/spack/build_systems/cmake.py index 105e9d5ab..5637ffeb7 100644 --- a/lib/ramble/spack/build_systems/cmake.py +++ b/lib/ramble/spack/build_systems/cmake.py @@ -11,8 +11,6 @@ import sys from typing import List -import six - from llnl.util.compat import Sequence from llnl.util.filesystem import working_dir @@ -234,7 +232,7 @@ def define(cmake_var, value): value = "ON" if value else "OFF" else: kind = 'STRING' - if isinstance(value, Sequence) and not isinstance(value, six.string_types): + if isinstance(value, Sequence) and not isinstance(value, str): value = ";".join(str(v) for v in value) else: value = str(value) diff --git a/lib/ramble/spack/ci.py b/lib/ramble/spack/ci.py index 254821cb3..976e362c6 100644 --- a/lib/ramble/spack/ci.py +++ b/lib/ramble/spack/ci.py @@ -13,10 +13,9 @@ import tempfile import zipfile -from six import iteritems -from six.moves.urllib.error import HTTPError, URLError -from six.moves.urllib.parse import urlencode -from six.moves.urllib.request import HTTPHandler, Request, build_opener +from urllib.error import HTTPError, URLError +from urllib.parse import urlencode +from urllib.request import HTTPHandler, Request, build_opener import llnl.util.filesystem as fs import llnl.util.tty as tty @@ -293,7 +292,7 @@ def stage_spec_jobs(specs, check_index_only=False, mirrors_to_check=None): def _remove_satisfied_deps(deps, satisfied_list): new_deps = {} - for key, value in iteritems(deps): + for key, value in deps.items(): new_value = set([v for v in value if v not in satisfied_list]) if new_value: new_deps[key] = new_value diff --git a/lib/ramble/spack/cmd/__init__.py b/lib/ramble/spack/cmd/__init__.py index ff6c3d7bf..c612fd0f6 100644 --- a/lib/ramble/spack/cmd/__init__.py +++ b/lib/ramble/spack/cmd/__init__.py @@ -11,7 +11,6 @@ import sys import ruamel.yaml as yaml -import six from ruamel.yaml.error import MarkedYAMLError import llnl.util.tty as tty @@ -156,7 +155,7 @@ def parse_specs(args, **kwargs): tests = kwargs.get('tests', False) sargs = args - if not isinstance(args, six.string_types): + if not isinstance(args, str): sargs = ' '.join(spack.util.string.quote(args)) specs = spack.spec.parse(sargs) for spec in specs: diff --git a/lib/ramble/spack/cmd/ci.py b/lib/ramble/spack/cmd/ci.py index fc30c1c1b..5d807d8bd 100644 --- a/lib/ramble/spack/cmd/ci.py +++ b/lib/ramble/spack/cmd/ci.py @@ -11,7 +11,7 @@ import sys import tempfile -from six.moves.urllib.parse import urlencode +from urllib.parse import urlencode import llnl.util.tty as tty diff --git a/lib/ramble/spack/cmd/compiler.py b/lib/ramble/spack/cmd/compiler.py index e8d5301f3..1b85a3674 100644 --- a/lib/ramble/spack/cmd/compiler.py +++ b/lib/ramble/spack/cmd/compiler.py @@ -8,8 +8,6 @@ import argparse import sys -from six import iteritems - import llnl.util.tty as tty from llnl.util.lang import index_by from llnl.util.tty.colify import colify @@ -129,13 +127,13 @@ def compiler_info(args): print("\t\t%s = %s" % (cpath, getattr(c, cpath, None))) if c.flags: print("\tflags:") - for flag, flag_value in iteritems(c.flags): + for flag, flag_value in c.flags.items(): print("\t\t%s = %s" % (flag, flag_value)) if len(c.environment) != 0: if len(c.environment.get('set', {})) != 0: print("\tenvironment:") print("\t set:") - for key, value in iteritems(c.environment['set']): + for key, value in c.environment['set'].items(): print("\t %s = %s" % (key, value)) if c.extra_rpaths: print("\tExtra rpaths:") diff --git a/lib/ramble/spack/cmd/env.py b/lib/ramble/spack/cmd/env.py index f33d98bd2..192e40326 100644 --- a/lib/ramble/spack/cmd/env.py +++ b/lib/ramble/spack/cmd/env.py @@ -3,13 +3,12 @@ # # SPDX-License-Identifier: (Apache-2.0 OR MIT) +import io import os import shutil import sys import tempfile -import six - import llnl.util.filesystem as fs import llnl.util.tty as tty from llnl.util.tty.colify import colify @@ -591,7 +590,7 @@ def get_fetch_target(name): # Fetch targets for all packages in the environment, not just roots. all_fetch_targets = [get_fetch_target(h) for h in hash_to_spec.keys()] - buf = six.StringIO() + buf = io.StringIO() buf.write("""SPACK ?= spack diff --git a/lib/ramble/spack/cmd/info.py b/lib/ramble/spack/cmd/info.py index 7a086dc41..a9bfc978b 100644 --- a/lib/ramble/spack/cmd/info.py +++ b/lib/ramble/spack/cmd/info.py @@ -8,7 +8,7 @@ import inspect import textwrap -from six.moves import zip_longest +from itertools import zip_longest import llnl.util.tty as tty import llnl.util.tty.color as color diff --git a/lib/ramble/spack/cmd/providers.py b/lib/ramble/spack/cmd/providers.py index 97111a4a8..4b89e8715 100644 --- a/lib/ramble/spack/cmd/providers.py +++ b/lib/ramble/spack/cmd/providers.py @@ -3,10 +3,9 @@ # # SPDX-License-Identifier: (Apache-2.0 OR MIT) +import io import sys -import six - import llnl.util.tty.colify as colify import spack.cmd @@ -30,7 +29,7 @@ def setup_parser(subparser): def providers(parser, args): valid_virtuals = sorted(spack.repo.path.provider_index.providers.keys()) - buffer = six.StringIO() + buffer = io.StringIO() isatty = sys.stdout.isatty() if isatty: buffer.write('Virtual packages:\n') diff --git a/lib/ramble/spack/cmd/tags.py b/lib/ramble/spack/cmd/tags.py index f7189f5b9..de2f052ee 100644 --- a/lib/ramble/spack/cmd/tags.py +++ b/lib/ramble/spack/cmd/tags.py @@ -3,10 +3,9 @@ # # SPDX-License-Identifier: (Apache-2.0 OR MIT) +import io import sys -import six - import llnl.util.tty as tty import llnl.util.tty.colify as colify @@ -20,7 +19,7 @@ def report_tags(category, tags): - buffer = six.StringIO() + buffer = io.StringIO() isatty = sys.stdout.isatty() if isatty: @@ -86,7 +85,7 @@ def tags(parser, args): return # Report packages associated with tags - buffer = six.StringIO() + buffer = io.StringIO() isatty = sys.stdout.isatty() tags = args.tag if args.tag else available_tags diff --git a/lib/ramble/spack/cmd/unit_test.py b/lib/ramble/spack/cmd/unit_test.py index eb78ad893..856f32b25 100644 --- a/lib/ramble/spack/cmd/unit_test.py +++ b/lib/ramble/spack/cmd/unit_test.py @@ -7,6 +7,7 @@ import argparse import collections +import io import os.path import re import sys @@ -16,8 +17,6 @@ except ImportError: pytest = None # type: ignore -from six import StringIO - import llnl.util.filesystem import llnl.util.tty.color as color from llnl.util.tty.colify import colify @@ -95,7 +94,7 @@ def colorize(c, prefix): old_output = sys.stdout try: - sys.stdout = output = StringIO() + sys.stdout = output = io.StringIO() pytest.main(['--collect-only'] + extra_args) finally: sys.stdout = old_output diff --git a/lib/ramble/spack/cmd/url.py b/lib/ramble/spack/cmd/url.py index d7710d684..5b2ac195d 100644 --- a/lib/ramble/spack/cmd/url.py +++ b/lib/ramble/spack/cmd/url.py @@ -5,10 +5,9 @@ from __future__ import division, print_function +import urllib.parse from collections import defaultdict -import six.moves.urllib.parse as urllib_parse - import llnl.util.tty.color as color from llnl.util import tty @@ -297,7 +296,7 @@ def add(self, pkg_name, fetcher): md5_hashes[pkg_name].append(fetcher.url) # parse out the URL scheme (https/http/ftp/etc.) - urlinfo = urllib_parse.urlparse(fetcher.url) + urlinfo = urllib.parse.urlparse(fetcher.url) self.schemes[urlinfo.scheme] += 1 if urlinfo.scheme == "http": diff --git a/lib/ramble/spack/compilers/__init__.py b/lib/ramble/spack/compilers/__init__.py index 17f65e640..bb2c7ebb9 100644 --- a/lib/ramble/spack/compilers/__init__.py +++ b/lib/ramble/spack/compilers/__init__.py @@ -12,8 +12,6 @@ import os from typing import Dict # novm -import six - import archspec.cpu import llnl.util.filesystem as fs @@ -640,7 +638,7 @@ def _default(fn_args): try: version = callback(path) - if version and six.text_type(version).strip() \ + if version and str(version).strip() \ and version != 'unknown': value = fn_args._replace( id=compiler_id._replace(version=version) @@ -650,13 +648,13 @@ def _default(fn_args): error = "Couldn't get version for compiler {0}".format(path) except spack.util.executable.ProcessError as e: error = "Couldn't get version for compiler {0}\n".format(path) + \ - six.text_type(e) + str(e) except Exception as e: # Catching "Exception" here is fine because it just # means something went wrong running a candidate executable. error = "Error while executing candidate compiler {0}" \ "\n{1}: {2}".format(path, e.__class__.__name__, - six.text_type(e)) + str(e)) return None, error operating_system = detect_version_args.id.os diff --git a/lib/ramble/spack/config.py b/lib/ramble/spack/config.py index ce90ed231..faf8e0095 100644 --- a/lib/ramble/spack/config.py +++ b/lib/ramble/spack/config.py @@ -39,9 +39,7 @@ from typing import List # novm import ruamel.yaml as yaml -import six from ruamel.yaml.error import MarkedYAMLError -from six import iteritems import llnl.util.lang import llnl.util.tty as tty @@ -363,7 +361,7 @@ def clear(self): def _process_dict_keyname_overrides(data): """Turn a trailing `:' in a key name into an override attribute.""" result = {} - for sk, sv in iteritems(data): + for sk, sv in data.items(): if sk.endswith(':'): key = syaml.syaml_str(sk[:-1]) key.override = True @@ -986,7 +984,7 @@ def validate(data, schema, filename=None): line_number = e.instance.lc.line + 1 else: line_number = None - raise six.raise_from(ConfigFormatError(e, data, filename, line_number), e) + raise ConfigFormatError(e, data, filename, line_number) from e # return the validated data so that we can access the raw data # mostly relevant for environments return test_data @@ -1146,7 +1144,7 @@ def they_are(t): # come *before* dest in OrderdDicts dest_keys = [dk for dk in dest.keys() if dk not in source] - for sk, sv in iteritems(source): + for sk, sv in source.items(): # always remove the dest items. Python dicts do not overwrite # keys on insert, so this ensures that source keys are copied # into dest along with mark provenance (i.e., file/line info). diff --git a/lib/ramble/spack/cray_manifest.py b/lib/ramble/spack/cray_manifest.py index b78888d25..f83681019 100644 --- a/lib/ramble/spack/cray_manifest.py +++ b/lib/ramble/spack/cray_manifest.py @@ -6,7 +6,6 @@ import json import jsonschema -import six import llnl.util.tty as tty @@ -101,7 +100,7 @@ def spec_from_entry(entry): continue # Value could be a list (of strings), boolean, or string - if isinstance(value, six.string_types): + if isinstance(value, str): variant_strs.append('{0}={1}'.format(name, value)) else: try: diff --git a/lib/ramble/spack/database.py b/lib/ramble/spack/database.py index 6a6daf67f..425bd18d3 100644 --- a/lib/ramble/spack/database.py +++ b/lib/ramble/spack/database.py @@ -28,8 +28,6 @@ import time from typing import Dict # novm -import six - try: import uuid _use_uuid = True @@ -754,10 +752,7 @@ def _read_from_file(self, filename): with open(filename, 'r') as f: fdata = sjson.load(f) except Exception as e: - raise six.raise_from( - CorruptDatabaseError("error parsing database:", str(e)), - e, - ) + raise CorruptDatabaseError("error parsing database:", str(e)) from e if fdata is None: return diff --git a/lib/ramble/spack/dependency.py b/lib/ramble/spack/dependency.py index ca0da0666..d76c8c37e 100644 --- a/lib/ramble/spack/dependency.py +++ b/lib/ramble/spack/dependency.py @@ -5,7 +5,6 @@ """Data structures that represent Spack's dependency relationships. """ -from six import string_types import spack.spec @@ -48,7 +47,7 @@ def canonical_deptype(deptype): if deptype in ('all', all): return all_deptypes - elif isinstance(deptype, string_types): + elif isinstance(deptype, str): if deptype not in all_deptypes: raise ValueError('Invalid dependency type: %s' % deptype) return (deptype,) diff --git a/lib/ramble/spack/detection/common.py b/lib/ramble/spack/detection/common.py index a8f0e82a8..4fd1cd102 100644 --- a/lib/ramble/spack/detection/common.py +++ b/lib/ramble/spack/detection/common.py @@ -20,8 +20,6 @@ import re import sys -import six - import llnl.util.tty import spack.config @@ -118,7 +116,7 @@ def _convert_to_iterable(single_val_or_multiple): x = single_val_or_multiple if x is None: return [] - elif isinstance(x, six.string_types): + elif isinstance(x, str): return [x] elif isinstance(x, spack.spec.Spec): # Specs are iterable, but a single spec should be converted to a list diff --git a/lib/ramble/spack/directives.py b/lib/ramble/spack/directives.py index 2de6552a8..84968c612 100644 --- a/lib/ramble/spack/directives.py +++ b/lib/ramble/spack/directives.py @@ -32,8 +32,6 @@ class OpenMpi(Package): import re from typing import List, Set # novm -import six - import llnl.util.lang import llnl.util.tty.color from llnl.util.compat import Sequence @@ -222,7 +220,7 @@ class Foo(Package): """ global directive_names - if isinstance(dicts, six.string_types): + if isinstance(dicts, str): dicts = (dicts, ) if not isinstance(dicts, Sequence): @@ -369,7 +367,7 @@ def _depends_on(pkg, spec, when=None, type=default_deptype, patches=None): patches = [patches] # auto-call patch() directive on any strings in patch list - patches = [patch(p) if isinstance(p, six.string_types) else p + patches = [patch(p) if isinstance(p, str) else p for p in patches] assert all(callable(p) for p in patches) diff --git a/lib/ramble/spack/directory_layout.py b/lib/ramble/spack/directory_layout.py index 3ccec788d..3a23c8caa 100644 --- a/lib/ramble/spack/directory_layout.py +++ b/lib/ramble/spack/directory_layout.py @@ -14,7 +14,6 @@ from contextlib import contextmanager import ruamel.yaml as yaml -import six import llnl.util.filesystem as fs import llnl.util.tty as tty @@ -344,12 +343,12 @@ def remove_install_directory(self, spec, deprecated=False): os.unlink(path) os.remove(metapath) except OSError as e: - raise six.raise_from(RemoveFailedError(spec, path, e), e) + raise RemoveFailedError(spec, path, e) from e elif os.path.exists(path): try: shutil.rmtree(path, **kwargs) except OSError as e: - raise six.raise_from(RemoveFailedError(spec, path, e), e) + raise RemoveFailedError(spec, path, e) from e path = os.path.dirname(path) while path != self.root: diff --git a/lib/ramble/spack/environment/environment.py b/lib/ramble/spack/environment/environment.py index 7366468f7..13e08e50e 100644 --- a/lib/ramble/spack/environment/environment.py +++ b/lib/ramble/spack/environment/environment.py @@ -13,7 +13,6 @@ import time import ruamel.yaml as yaml -import six import llnl.util.filesystem as fs import llnl.util.tty as tty @@ -659,7 +658,7 @@ def __init__(self, path, init_file=None, with_view=None, keep_relative=False): self.views = { default_view_name: ViewDescriptor(self.path, self.view_path_default)} - elif isinstance(with_view, six.string_types): + elif isinstance(with_view, str): self.views = {default_view_name: ViewDescriptor(self.path, with_view)} # If with_view is None, then defer to the view settings determined by @@ -760,7 +759,7 @@ def _read_manifest(self, f, raw_yaml=None): self.views = { default_view_name: ViewDescriptor(self.path, self.view_path_default)} - elif isinstance(enable_view, six.string_types): + elif isinstance(enable_view, str): self.views = {default_view_name: ViewDescriptor(self.path, enable_view)} elif enable_view: @@ -2001,12 +2000,12 @@ def _update_and_write_manifest(self, raw_yaml_dict, yaml_dict): # If it is a string that starts with '$', it's a reference. # Those also can't have changed. ayl[name][:] = [s for s in ayl.setdefault(name, []) - if (not isinstance(s, six.string_types)) or + if (not isinstance(s, str)) or s.startswith('$') or Spec(s) in speclist.specs] # Put the new specs into the first active list from the yaml new_specs = [entry for entry in speclist.yaml_list - if isinstance(entry, six.string_types) and + if isinstance(entry, str) and not any(entry in ayl[name] for ayl in active_yaml_lists)] list_for_new_specs = active_yaml_lists[0].setdefault(name, []) @@ -2087,7 +2086,7 @@ def yaml_equivalent(first, second): elif isinstance(first, list): return isinstance(second, list) and _equiv_list(first, second) else: # it's a string - return isinstance(second, six.string_types) and first == second + return isinstance(second, str) and first == second def _equiv_list(first, second): diff --git a/lib/ramble/spack/fetch_strategy.py b/lib/ramble/spack/fetch_strategy.py index 378209308..a654cdf0c 100644 --- a/lib/ramble/spack/fetch_strategy.py +++ b/lib/ramble/spack/fetch_strategy.py @@ -31,8 +31,7 @@ import sys from typing import List, Optional # novm -import six -import six.moves.urllib.parse as urllib_parse +import urllib.parse import llnl.util import llnl.util.tty as tty @@ -308,7 +307,7 @@ def candidate_urls(self): # This must be skipped on Windows due to URL encoding # of ':' characters on filepaths on Windows if sys.platform != "win32" and url.startswith('file://'): - path = urllib_parse.quote(url[len('file://'):]) + path = urllib.parse.quote(url[len('file://'):]) url = 'file://' + path urls.append(url) @@ -705,7 +704,7 @@ def archive(self, destination, **kwargs): patterns = kwargs.get('exclude', None) if patterns is not None: - if isinstance(patterns, six.string_types): + if isinstance(patterns, str): patterns = [patterns] for p in patterns: tar.add_default_arg('--exclude=%s' % p) @@ -1650,7 +1649,7 @@ def from_url_scheme(url, *args, **kwargs): in the given url.""" url = kwargs.get('url', url) - parsed_url = urllib_parse.urlparse(url, scheme='file') + parsed_url = urllib.parse.urlparse(url, scheme='file') scheme_mapping = ( kwargs.get('scheme_mapping') or diff --git a/lib/ramble/spack/gcs_handler.py b/lib/ramble/spack/gcs_handler.py index de35511ce..83fbdc07d 100644 --- a/lib/ramble/spack/gcs_handler.py +++ b/lib/ramble/spack/gcs_handler.py @@ -3,7 +3,7 @@ # # SPDX-License-Identifier: (Apache-2.0 OR MIT) -import six.moves.urllib.response as urllib_response +import urllib.response import spack.util.url as url_util import spack.util.web as web_util @@ -23,4 +23,4 @@ def gcs_open(req, *args, **kwargs): stream = gcsblob.get_blob_byte_stream() headers = gcsblob.get_blob_headers() - return urllib_response.addinfourl(stream, headers, url) + return urllib.response.addinfourl(stream, headers, url) diff --git a/lib/ramble/spack/install_test.py b/lib/ramble/spack/install_test.py index 71561d28a..65843aaa8 100644 --- a/lib/ramble/spack/install_test.py +++ b/lib/ramble/spack/install_test.py @@ -9,8 +9,6 @@ import shutil import sys -import six - import llnl.util.filesystem as fs import spack.error @@ -315,10 +313,7 @@ def from_file(filename): test_suite._hash = content_hash return test_suite except Exception as e: - raise six.raise_from( - sjson.SpackJSONError("error parsing JSON TestSuite:", str(e)), - e, - ) + raise sjson.SpackJSONError("error parsing JSON TestSuite:", str(e)) from e def _add_msg_to_file(filename, msg): diff --git a/lib/ramble/spack/installer.py b/lib/ramble/spack/installer.py index 2e430b8a0..8f4acdd09 100644 --- a/lib/ramble/spack/installer.py +++ b/lib/ramble/spack/installer.py @@ -31,14 +31,13 @@ import glob import heapq import itertools +import io import os import shutil import sys import time from collections import defaultdict -import six - import llnl.util.filesystem as fs import llnl.util.lock as lk import llnl.util.tty as tty @@ -564,7 +563,7 @@ def log(pkg): # Finally, archive files that are specific to each package with fs.working_dir(pkg.stage.path): - errors = six.StringIO() + errors = io.StringIO() target_dir = os.path.join( spack.store.layout.metadata_path(pkg.spec), 'archived-files') diff --git a/lib/ramble/spack/main.py b/lib/ramble/spack/main.py index b66c67c80..e8bd4560e 100644 --- a/lib/ramble/spack/main.py +++ b/lib/ramble/spack/main.py @@ -12,6 +12,7 @@ import argparse import inspect +import io import operator import os import os.path @@ -22,8 +23,6 @@ import traceback import warnings -from six import StringIO - import archspec.cpu import llnl.util.lang @@ -586,7 +585,7 @@ def __call__(self, *argv, **kwargs): fail_on_error = kwargs.get('fail_on_error', True) - out = StringIO() + out = io.StringIO() try: with log_output(out): self.returncode = _invoke_command( diff --git a/lib/ramble/spack/mirror.py b/lib/ramble/spack/mirror.py index 0085d920b..cb129342c 100644 --- a/lib/ramble/spack/mirror.py +++ b/lib/ramble/spack/mirror.py @@ -19,7 +19,6 @@ import traceback import ruamel.yaml.error as yaml_error -import six import llnl.util.tty as tty from llnl.util.compat import Mapping @@ -38,7 +37,7 @@ def _is_string(url): - return isinstance(url, six.string_types) + return isinstance(url, str) def _display_mirror_entry(size, name, url, type_=None): @@ -81,10 +80,7 @@ def from_yaml(stream, name=None): data = syaml.load(stream) return Mirror.from_dict(data, name) except yaml_error.MarkedYAMLError as e: - raise six.raise_from( - syaml.SpackYAMLError("error parsing YAML mirror:", str(e)), - e, - ) + raise syaml.SpackYAMLError("error parsing YAML mirror:", str(e)) from e @staticmethod def from_json(stream, name=None): @@ -92,10 +88,7 @@ def from_json(stream, name=None): d = sjson.load(stream) return Mirror.from_dict(d, name) except Exception as e: - raise six.raise_from( - sjson.SpackJSONError("error parsing JSON mirror:", str(e)), - e, - ) + raise sjson.SpackJSONError("error parsing JSON mirror:", str(e)) from e def to_dict(self): if self._push_url is None: @@ -109,7 +102,7 @@ def to_dict(self): @staticmethod def from_dict(d, name=None): - if isinstance(d, six.string_types): + if isinstance(d, str): return Mirror(d, name=name) else: return Mirror(d['fetch'], d['push'], name=name) @@ -263,10 +256,7 @@ def from_yaml(stream, name=None): data = syaml.load(stream) return MirrorCollection(data) except yaml_error.MarkedYAMLError as e: - raise six.raise_from( - syaml.SpackYAMLError("error parsing YAML mirror collection:", str(e)), - e, - ) + raise syaml.SpackYAMLError("error parsing YAML mirror collection:", str(e)) from e @staticmethod def from_json(stream, name=None): @@ -274,10 +264,7 @@ def from_json(stream, name=None): d = sjson.load(stream) return MirrorCollection(d) except Exception as e: - raise six.raise_from( - sjson.SpackJSONError("error parsing JSON mirror collection:", str(e)), - e, - ) + raise sjson.SpackJSONError("error parsing JSON mirror collection:", str(e)) from e def to_dict(self, recursive=False): return syaml_dict(sorted( diff --git a/lib/ramble/spack/package.py b/lib/ramble/spack/package.py index 549c71f52..6ac7ef375 100644 --- a/lib/ramble/spack/package.py +++ b/lib/ramble/spack/package.py @@ -29,8 +29,6 @@ import warnings from typing import Any, Callable, Dict, List, Optional # novm -import six - import llnl.util.filesystem as fsys import llnl.util.tty as tty from llnl.util.lang import memoized, nullcontext @@ -249,7 +247,7 @@ def determine_spec_details(cls, prefix, objs_in_prefix): variants = [variants] for variant in variants: - if isinstance(variant, six.string_types): + if isinstance(variant, str): variant = (variant, {}) variant_str, extra_attributes = variant spec_str = '{0}@{1} {2}'.format( @@ -555,7 +553,7 @@ def test_log_pathname(test_stage, spec): 'test-{0}-out.txt'.format(TestSuite.test_pkg_id(spec))) -class PackageBase(six.with_metaclass(PackageMeta, PackageViewMixin, object)): +class PackageBase(PackageViewMixin, metaclass=PackageMeta): """This is the superclass for all spack packages. ***The Package class*** @@ -1948,7 +1946,7 @@ def cache_extra_test_sources(self, srcs): be copied to the corresponding location(s) under the install testing directory. """ - paths = [srcs] if isinstance(srcs, six.string_types) else srcs + paths = [srcs] if isinstance(srcs, str) else srcs for path in paths: src_path = os.path.join(self.stage.source_path, path) @@ -2075,7 +2073,7 @@ def run_test(self, exe, options=[], expected=[], status=0, print(line.rstrip('\n')) if exc_type is spack.util.executable.ProcessError: - out = six.StringIO() + out = io.StringIO() spack.build_environment.write_log_summary( out, 'test', self.test_log_file, last=1) m = out.getvalue() @@ -2099,10 +2097,10 @@ def run_test(self, exe, options=[], expected=[], status=0, def _run_test_helper(self, runner, options, expected, status, installed, purpose): - status = [status] if isinstance(status, six.integer_types) else status - expected = [expected] if isinstance(expected, six.string_types) else \ + status = [status] if isinstance(status, int) else status + expected = [expected] if isinstance(expected, str) else \ expected - options = [options] if isinstance(options, six.string_types) else \ + options = [options] if isinstance(options, str) else \ options if purpose: @@ -2154,7 +2152,7 @@ def sanity_check_prefix(self): """This function checks whether install succeeded.""" def check_paths(path_list, filetype, predicate): - if isinstance(path_list, six.string_types): + if isinstance(path_list, str): path_list = [path_list] for path in path_list: @@ -2685,7 +2683,7 @@ def format_doc(self, **kwargs): doc = re.sub(r'\s+', ' ', self.__doc__) lines = textwrap.wrap(doc, 72) - results = six.StringIO() + results = io.StringIO() for line in lines: results.write((" " * indent) + line + "\n") return results.getvalue() diff --git a/lib/ramble/spack/package_prefs.py b/lib/ramble/spack/package_prefs.py index f49d6940d..ded0f228d 100644 --- a/lib/ramble/spack/package_prefs.py +++ b/lib/ramble/spack/package_prefs.py @@ -4,8 +4,6 @@ # SPDX-License-Identifier: (Apache-2.0 OR MIT) import stat -from six import string_types - import spack.error import spack.repo from spack.config import ConfigError @@ -145,7 +143,7 @@ def preferred_variants(cls, pkg_name): break # allow variants to be list or string - if not isinstance(variants, string_types): + if not isinstance(variants, str): variants = " ".join(variants) # Only return variants that are actually supported by the package diff --git a/lib/ramble/spack/parse.py b/lib/ramble/spack/parse.py index e06338e0c..533d7b98f 100644 --- a/lib/ramble/spack/parse.py +++ b/lib/ramble/spack/parse.py @@ -8,8 +8,6 @@ import shlex import sys -from six import string_types - import spack.error import spack.util.path as sp @@ -144,7 +142,7 @@ def expect(self, id): sys.exit(1) def setup(self, text): - if isinstance(text, string_types): + if isinstance(text, str): # shlex does not handle Windows path # separators, so we must normalize to posix text = sp.convert_to_posix_path(text) diff --git a/lib/ramble/spack/provider_index.py b/lib/ramble/spack/provider_index.py index 5cdfff8a5..02add8357 100644 --- a/lib/ramble/spack/provider_index.py +++ b/lib/ramble/spack/provider_index.py @@ -5,8 +5,6 @@ """Classes and functions to manage providers of virtual dependencies""" import itertools -import six - import spack.error import spack.util.spack_json as sjson @@ -66,7 +64,7 @@ def providers_for(self, virtual_spec): """ result = set() # Allow string names to be passed as input, as well as specs - if isinstance(virtual_spec, six.string_types): + if isinstance(virtual_spec, str): virtual_spec = spack.spec.Spec(virtual_spec) # Add all the providers that satisfy the vpkg spec. @@ -176,7 +174,7 @@ def update(self, spec): assert not spec.virtual, "cannot update an index using a virtual spec" pkg_provided = spec.package_class.provided - for provided_spec, provider_specs in six.iteritems(pkg_provided): + for provided_spec, provider_specs in pkg_provided.items(): for provider_spec in provider_specs: # TODO: fix this comment. # We want satisfaction other than flags @@ -312,7 +310,7 @@ def _transform(providers, transform_fun, out_mapping_type=dict): """ def mapiter(mappings): if isinstance(mappings, dict): - return six.iteritems(mappings) + return mappings.items() else: return iter(mappings) diff --git a/lib/ramble/spack/repo.py b/lib/ramble/spack/repo.py index 50f0b8a9f..47d9c5805 100644 --- a/lib/ramble/spack/repo.py +++ b/lib/ramble/spack/repo.py @@ -22,7 +22,6 @@ from typing import Dict # novm import ruamel.yaml as yaml -import six import llnl.util.filesystem as fs import llnl.util.lang @@ -571,8 +570,7 @@ def __len__(self): return len(self._packages_to_stats) -@six.add_metaclass(abc.ABCMeta) -class Indexer(object): +class Indexer(metaclass=abc.ABCMeta): """Adaptor for indexes that need to be generated when repos are updated.""" def create(self): @@ -786,7 +784,7 @@ def __init__(self, *repos): # Add each repo to this path. for repo in repos: try: - if isinstance(repo, six.string_types): + if isinstance(repo, str): repo = Repo(repo) self.put_last(repo) except RepoError as e: diff --git a/lib/ramble/spack/reporters/cdash.py b/lib/ramble/spack/reporters/cdash.py index d947becde..65080e9ec 100644 --- a/lib/ramble/spack/reporters/cdash.py +++ b/lib/ramble/spack/reporters/cdash.py @@ -13,9 +13,8 @@ import time import xml.sax.saxutils -from six import iteritems, text_type -from six.moves.urllib.parse import urlencode -from six.moves.urllib.request import HTTPHandler, Request, build_opener +from urllib.parse import urlencode +from urllib.request import HTTPHandler, Request, build_opener import llnl.util.tty as tty from llnl.util.filesystem import working_dir @@ -144,7 +143,7 @@ def build_report_for_package(self, directory_name, package, duration): if cdash_phase not in phases_encountered: phases_encountered.append(cdash_phase) report_data[cdash_phase]['loglines'].append( - text_type("{0} output for {1}:".format( + str("{0} output for {1}:".format( cdash_phase, package['name']))) elif cdash_phase: report_data[cdash_phase]['loglines'].append( @@ -288,7 +287,7 @@ def test_report_for_package(self, directory_name, package, duration): # Generate a report for this package. # The first line just says "Testing package name-hash" report_data['test']['loglines'].append( - text_type("{0} output for {1}:".format( + str("{0} output for {1}:".format( 'test', package['name']))) for line in package['stdout'].splitlines()[1:]: report_data['test']['loglines'].append( @@ -444,7 +443,7 @@ def upload(self, filename): def finalize_report(self): if self.buildIds: print("View your build results here:") - for package_name, buildid in iteritems(self.buildIds): + for package_name, buildid in self.buildIds.items(): # Construct and display a helpful link if CDash responded with # a buildId. build_url = self.cdash_upload_url diff --git a/lib/ramble/spack/s3_handler.py b/lib/ramble/spack/s3_handler.py index 9f775abaf..c68ec77af 100644 --- a/lib/ramble/spack/s3_handler.py +++ b/lib/ramble/spack/s3_handler.py @@ -3,13 +3,11 @@ # # SPDX-License-Identifier: (Apache-2.0 OR MIT) +import urllib.error +import urllib.request +import urllib.response from io import BufferedReader -import six -import six.moves.urllib.error as urllib_error -import six.moves.urllib.request as urllib_request -import six.moves.urllib.response as urllib_response - import spack.util.s3 as s3_util import spack.util.url as url_util @@ -60,13 +58,13 @@ def _s3_open(url): return url, headers, stream -class UrllibS3Handler(urllib_request.HTTPSHandler): +class UrllibS3Handler(urllib.request.HTTPSHandler): def s3_open(self, req): orig_url = req.get_full_url() from botocore.exceptions import ClientError # type: ignore[import] try: url, headers, stream = _s3_open(orig_url) - return urllib_response.addinfourl(stream, headers, url) + return urllib.response.addinfourl(stream, headers, url) except ClientError as err: # if no such [KEY], but [KEY]/index.html exists, # return that, instead. @@ -74,19 +72,19 @@ def s3_open(self, req): try: _, headers, stream = _s3_open( url_util.join(orig_url, 'index.html')) - return urllib_response.addinfourl( + return urllib.response.addinfourl( stream, headers, orig_url) except ClientError as err2: if err.response['Error']['Code'] == 'NoSuchKey': # raise original error - raise six.raise_from(urllib_error.URLError(err), err) + raise urllib.error.URLError(err) from err - raise six.raise_from(urllib_error.URLError(err2), err2) + raise urllib.error.URLError(err) from err2 - raise six.raise_from(urllib_error.URLError(err), err) + raise urllib.error.URLError(err) from err -S3OpenerDirector = urllib_request.build_opener(UrllibS3Handler()) +S3OpenerDirector = urllib.request.build_opener(UrllibS3Handler()) open = S3OpenerDirector.open diff --git a/lib/ramble/spack/schema/config.py b/lib/ramble/spack/schema/config.py index 2de54a617..a794022da 100644 --- a/lib/ramble/spack/schema/config.py +++ b/lib/ramble/spack/schema/config.py @@ -8,8 +8,6 @@ .. literalinclude:: _spack_root/lib/spack/spack/schema/config.py :lines: 13- """ -import six - from llnl.util.lang import union_dicts import spack.schema.projections @@ -131,7 +129,7 @@ def update(data): changed = False install_tree = data.get('install_tree', None) - if isinstance(install_tree, six.string_types): + if isinstance(install_tree, str): # deprecated short-form install tree # add value as `root` in updated install_tree data['install_tree'] = {'root': install_tree} diff --git a/lib/ramble/spack/solver/asp.py b/lib/ramble/spack/solver/asp.py index 1b3eb8b1a..2d52dac98 100644 --- a/lib/ramble/spack/solver/asp.py +++ b/lib/ramble/spack/solver/asp.py @@ -13,8 +13,6 @@ import types import warnings -from six import string_types - import archspec.cpu from llnl.util.compat import Sequence @@ -185,7 +183,7 @@ def build_criteria_names(costs, tuples): def issequence(obj): - if isinstance(obj, string_types): + if isinstance(obj, str): return False return isinstance(obj, (Sequence, types.GeneratorType)) @@ -197,7 +195,7 @@ def listify(args): def packagize(pkg): - if isinstance(pkg, string_types): + if isinstance(pkg, str): return spack.repo.path.get_pkg_class(pkg) else: return pkg diff --git a/lib/ramble/spack/spec.py b/lib/ramble/spack/spec.py index 1952ed1a5..4ba872847 100644 --- a/lib/ramble/spack/spec.py +++ b/lib/ramble/spack/spec.py @@ -78,6 +78,7 @@ """ import collections import itertools +import io import operator import os import re @@ -85,7 +86,6 @@ import warnings import ruamel.yaml as yaml -import six import llnl.util.filesystem as fs import llnl.util.lang as lang @@ -261,11 +261,11 @@ def _string_or_none(s): other = spec_or_platform_tuple platform_tuple = other.platform, other.os, other.target - elif isinstance(spec_or_platform_tuple, (six.string_types, tuple)): + elif isinstance(spec_or_platform_tuple, (str, tuple)): spec_fields = spec_or_platform_tuple # Normalize the string to a tuple - if isinstance(spec_or_platform_tuple, six.string_types): + if isinstance(spec_or_platform_tuple, str): spec_fields = spec_or_platform_tuple.split("-") if len(spec_fields) != 3: msg = 'cannot construct an ArchSpec from {0!s}' @@ -509,7 +509,6 @@ def copy(self): @property def concrete(self): """True if the spec is concrete, False otherwise""" - # return all(v for k, v in six.iteritems(self.to_cmp_dict())) return (self.platform and self.os and self.target and self.target_concrete) @@ -555,7 +554,7 @@ def __init__(self, *args): arg = args[0] # If there is one argument, it's either another CompilerSpec # to copy or a string to parse - if isinstance(arg, six.string_types): + if isinstance(arg, str): c = SpecParser().parse_compiler(arg) self.name = c.name self.versions = c.versions @@ -1230,7 +1229,7 @@ def __init__(self, spec_like=None, normal=False, # Build spec should be the actual build spec unless marked dirty. self._build_spec = None - if isinstance(spec_like, six.string_types): + if isinstance(spec_like, str): spec_list = SpecParser(self).parse(spec_like) if len(spec_list) > 1: raise ValueError("More than one spec in string: " + spec_like) @@ -1422,7 +1421,7 @@ def _set_architecture(self, **kwargs): new_vals = tuple(kwargs.get(arg, None) for arg in arch_attrs) self.architecture = ArchSpec(new_vals) else: - new_attrvals = [(a, v) for a, v in six.iteritems(kwargs) + new_attrvals = [(a, v) for a, v in kwargs.items() if a in arch_attrs] for new_attr, new_value in new_attrvals: if getattr(self.architecture, new_attr): @@ -1657,7 +1656,7 @@ def traverse_edges(self, visited=None, d=0, deptype='all', # get initial values for kwargs depth = kwargs.get('depth', False) key_fun = kwargs.get('key', id) - if isinstance(key_fun, six.string_types): + if isinstance(key_fun, str): key_fun = operator.attrgetter(key_fun) yield_root = kwargs.get('root', True) cover = kwargs.get('cover', 'nodes') @@ -1948,8 +1947,8 @@ def to_node_dict(self, hash=ht.dag_hash): package_hash = self._package_hash # Full hashes are in bytes - if (not isinstance(package_hash, six.text_type) - and isinstance(package_hash, six.binary_type)): + if (not isinstance(package_hash, str) + and isinstance(package_hash, bytes)): package_hash = package_hash.decode('utf-8') d['package_hash'] = package_hash @@ -2226,7 +2225,7 @@ def read_yaml_dep_specs(deps, hash_type=ht.dag_hash.name): else: elt = dep dep_name = dep['name'] - if isinstance(elt, six.string_types): + if isinstance(elt, str): # original format, elt is just the dependency hash. dep_hash, deptypes = elt, ['build', 'link'] elif isinstance(elt, tuple): @@ -2386,7 +2385,7 @@ def spec_and_dependency_types(s): # Recurse on dependencies for s, s_dependencies in dep_like.items(): - if isinstance(s, six.string_types): + if isinstance(s, str): dag_node, dependency_types = name_and_dependency_types(s) else: dag_node, dependency_types = spec_and_dependency_types(s) @@ -2419,10 +2418,7 @@ def from_yaml(stream): data = yaml.load(stream) return Spec.from_dict(data) except yaml.error.MarkedYAMLError as e: - raise six.raise_from( - syaml.SpackYAMLError("error parsing YAML spec:", str(e)), - e, - ) + raise syaml.SpackYAMLError("error parsing YAML spec:", str(e)) from e @staticmethod def from_json(stream): @@ -2435,10 +2431,7 @@ def from_json(stream): data = sjson.load(stream) return Spec.from_dict(data) except Exception as e: - raise six.raise_from( - sjson.SpackJSONError("error parsing JSON spec:", str(e)), - e, - ) + raise sjson.SpackJSONError("error parsing JSON spec:", str(e)) from e @staticmethod def extract_json_from_clearsig(data): @@ -3054,10 +3047,7 @@ def flat_dependencies(self, **kwargs): # with inconsistent constraints. Users cannot produce # inconsistent specs like this on the command line: the # parser doesn't allow it. Spack must be broken! - raise six.raise_from( - InconsistentSpecError("Invalid Spec DAG: %s" % e.message), - e, - ) + raise InconsistentSpecError("Invalid Spec DAG: %s" % e.message) from e def index(self, deptype='all'): """Return a dictionary that points to all the dependencies in this @@ -4141,7 +4131,7 @@ def format(self, format_string=default_format, **kwargs): color = kwargs.get('color', False) transform = kwargs.get('transform', {}) - out = six.StringIO() + out = io.StringIO() def write(s, c=None): f = clr.cescape(s) @@ -4375,7 +4365,7 @@ def old_format(self, format_string='$_$@$%@+$+$=', **kwargs): (k.upper(), v) for k, v in kwargs.get('transform', {}).items()) length = len(format_string) - out = six.StringIO() + out = io.StringIO() named = escape = compiler = False named_str = fmt = '' @@ -5139,7 +5129,7 @@ def do_parse(self): self.unexpected_token() except spack.parse.ParseError as e: - raise six.raise_from(SpecParseError(e), e) + raise SpecParseError(e) from e # Generate lookups for git-commit-based versions for spec in specs: diff --git a/lib/ramble/spack/spec_list.py b/lib/ramble/spack/spec_list.py index 2582921e3..db2e615a4 100644 --- a/lib/ramble/spack/spec_list.py +++ b/lib/ramble/spack/spec_list.py @@ -4,8 +4,6 @@ # SPDX-License-Identifier: (Apache-2.0 OR MIT) import itertools -from six import string_types - import spack.variant from spack.error import SpackError from spack.spec import Spec @@ -22,7 +20,7 @@ def __init__(self, name='specs', yaml_list=None, reference=None): self._reference = reference # TODO: Do we need defensive copy here? # Validate yaml_list before assigning - if not all(isinstance(s, string_types) or isinstance(s, (list, dict)) + if not all(isinstance(s, str) or isinstance(s, (list, dict)) for s in yaml_list): raise ValueError( "yaml_list can contain only valid YAML types! Found:\n %s" @@ -83,7 +81,7 @@ def add(self, spec): def remove(self, spec): # Get spec to remove from list remove = [s for s in self.yaml_list - if (isinstance(s, string_types) and not s.startswith('$')) + if (isinstance(s, str) and not s.startswith('$')) and Spec(s) == Spec(spec)] if not remove: msg = 'Cannot remove %s from SpecList %s\n' % (spec, self.name) @@ -137,7 +135,7 @@ def _expand_references(self, yaml): for item in yaml: # if it's a reference, expand it - if isinstance(item, string_types) and item.startswith('$'): + if isinstance(item, str) and item.startswith('$'): # replace the reference and apply the sigil if needed name, sigil = self._parse_reference(item) referent = [ diff --git a/lib/ramble/spack/stage.py b/lib/ramble/spack/stage.py index f28930539..b9c0b85d5 100644 --- a/lib/ramble/spack/stage.py +++ b/lib/ramble/spack/stage.py @@ -16,8 +16,6 @@ import tempfile from typing import Dict # novm -from six import iteritems, string_types - import llnl.util.lang import llnl.util.tty as tty from llnl.util.filesystem import ( @@ -163,7 +161,7 @@ def get_stage_root(): if _stage_root is None: candidates = spack.config.get('config:build_stage') - if isinstance(candidates, string_types): + if isinstance(candidates, str): candidates = [candidates] resolved_candidates = _resolve_paths(candidates) @@ -273,7 +271,7 @@ def __init__( """ # TODO: fetch/stage coupling needs to be reworked -- the logic # TODO: here is convoluted and not modular enough. - if isinstance(url_or_fetch_strategy, string_types): + if isinstance(url_or_fetch_strategy, str): self.fetcher = fs.from_url_scheme(url_or_fetch_strategy) elif isinstance(url_or_fetch_strategy, fs.FetchStrategy): self.fetcher = url_or_fetch_strategy @@ -691,7 +689,7 @@ def _add_to_root_stage(self): else: raise - for key, value in iteritems(placement): + for key, value in placement.items(): destination_path = os.path.join(target_path, value) source_path = os.path.join(self.source_path, key) diff --git a/lib/ramble/spack/store.py b/lib/ramble/spack/store.py index eeb183e5b..b062af346 100644 --- a/lib/ramble/spack/store.py +++ b/lib/ramble/spack/store.py @@ -21,8 +21,6 @@ import os import re -import six - import llnl.util.lang import llnl.util.tty as tty @@ -69,7 +67,7 @@ def parse_install_tree(config_dict): install_tree = config_dict.get('install_tree', {}) padded_length = False - if isinstance(install_tree, six.string_types): + if isinstance(install_tree, str): tty.warn("Using deprecated format for configuring install_tree") unpadded_root = install_tree unpadded_root = spack.util.path.canonicalize_path(unpadded_root) @@ -309,7 +307,7 @@ def find(constraints, multiple=False, query_fn=None, **kwargs): List of matching specs """ # Normalize input to list of specs - if isinstance(constraints, six.string_types): + if isinstance(constraints, str): constraints = [spack.spec.Spec(constraints)] matching_specs, errors = [], [] diff --git a/lib/ramble/spack/target.py b/lib/ramble/spack/target.py index c7a166b9f..d559e4625 100644 --- a/lib/ramble/spack/target.py +++ b/lib/ramble/spack/target.py @@ -4,8 +4,6 @@ # SPDX-License-Identifier: (Apache-2.0 OR MIT) import functools -import six - import archspec.cpu import llnl.util.tty as tty @@ -22,7 +20,7 @@ def _ensure_other_is_target(method): """ @functools.wraps(method) def _impl(self, other): - if isinstance(other, six.string_types): + if isinstance(other, str): other = Target(other) if not isinstance(other, Target): @@ -81,7 +79,7 @@ def __hash__(self): def from_dict_or_value(dict_or_value): # A string here represents a generic target (like x86_64 or ppc64) or # a custom micro-architecture - if isinstance(dict_or_value, six.string_types): + if isinstance(dict_or_value, str): return Target(dict_or_value) # TODO: From a dict we actually retrieve much more information than diff --git a/lib/ramble/spack/tengine.py b/lib/ramble/spack/tengine.py index 0be15dd23..1847bdbcc 100644 --- a/lib/ramble/spack/tengine.py +++ b/lib/ramble/spack/tengine.py @@ -6,8 +6,6 @@ import textwrap from typing import List # novm -import six - import llnl.util.lang import spack.config @@ -55,7 +53,7 @@ def context_property(cls, func): context_property = ContextMeta.context_property -class Context(six.with_metaclass(ContextMeta, object)): +class Context(metaclass=ContextMeta): """Base class for context classes that are used with the template engine. """ diff --git a/lib/ramble/spack/test/cmd/build_env.py b/lib/ramble/spack/test/cmd/build_env.py index 954598cfb..ea322fc30 100644 --- a/lib/ramble/spack/test/cmd/build_env.py +++ b/lib/ramble/spack/test/cmd/build_env.py @@ -2,9 +2,9 @@ # Spack Project Developers. See the top-level COPYRIGHT file for details. # # SPDX-License-Identifier: (Apache-2.0 OR MIT) +import pickle import pytest -from six.moves import cPickle from spack.main import SpackCommand @@ -52,6 +52,6 @@ def test_dump(tmpdir): def test_pickle(tmpdir): with tmpdir.as_cwd(): build_env('--pickle', _out_file, 'zlib') - environment = cPickle.load(open(_out_file, 'rb')) + environment = pickle.load(open(_out_file, 'rb')) assert(type(environment) == dict) assert('PATH' in environment) diff --git a/lib/ramble/spack/test/cmd/env.py b/lib/ramble/spack/test/cmd/env.py index b686d5abb..edee84eff 100644 --- a/lib/ramble/spack/test/cmd/env.py +++ b/lib/ramble/spack/test/cmd/env.py @@ -4,13 +4,13 @@ # SPDX-License-Identifier: (Apache-2.0 OR MIT) import filecmp import glob +import io import os import shutil import sys from argparse import Namespace import pytest -from six import StringIO import llnl.util.filesystem as fs import llnl.util.link_tree @@ -459,7 +459,7 @@ def test_env_repo(): def test_user_removed_spec(): """Ensure a user can remove from any position in the spack.yaml file.""" - initial_yaml = StringIO("""\ + initial_yaml = io.StringIO("""\ env: specs: - mpileaks @@ -493,7 +493,7 @@ def test_user_removed_spec(): def test_init_from_lockfile(tmpdir): """Test that an environment can be instantiated from a lockfile.""" - initial_yaml = StringIO("""\ + initial_yaml = io.StringIO("""\ env: specs: - mpileaks @@ -519,7 +519,7 @@ def test_init_from_lockfile(tmpdir): def test_init_from_yaml(tmpdir): """Test that an environment can be instantiated from a lockfile.""" - initial_yaml = StringIO("""\ + initial_yaml = io.StringIO("""\ env: specs: - mpileaks @@ -548,14 +548,14 @@ def test_env_view_external_prefix( fake_bin = fake_prefix.join('bin') fake_bin.ensure(dir=True) - initial_yaml = StringIO("""\ + initial_yaml = io.StringIO("""\ env: specs: - a view: true """) - external_config = StringIO("""\ + external_config = io.StringIO("""\ packages: a: externals: @@ -621,7 +621,7 @@ def test_env_with_config(): mpileaks: version: [2.2] """ - _env_create('test', StringIO(test_config)) + _env_create('test', io.StringIO(test_config)) e = ev.read('test') with e: @@ -639,7 +639,7 @@ def test_with_config_bad_include(capfd): - /no/such/directory - no/such/file.yaml """ - _env_create(env_name, StringIO(test_config)) + _env_create(env_name, io.StringIO(test_config)) e = ev.read(env_name) with pytest.raises(SystemExit): @@ -664,7 +664,7 @@ def test_env_with_include_config_files_same_basename(): [libelf, mpileaks] """ - _env_create('test', StringIO(test_config)) + _env_create('test', io.StringIO(test_config)) e = ev.read('test') fs.mkdirp(os.path.join(e.path, 'path', 'to')) @@ -704,7 +704,7 @@ def test_env_with_included_config_file(): specs: - mpileaks """ - _env_create('test', StringIO(test_config)) + _env_create('test', io.StringIO(test_config)) e = ev.read('test') with open(os.path.join(e.path, 'included-config.yaml'), 'w') as f: @@ -731,7 +731,7 @@ def test_env_with_included_config_scope(): - mpileaks """ % config_scope_path - _env_create('test', StringIO(test_config)) + _env_create('test', io.StringIO(test_config)) e = ev.read('test') @@ -760,7 +760,7 @@ def test_env_with_included_config_var_path(): - mpileaks """ % config_var_path - _env_create('test', StringIO(test_config)) + _env_create('test', io.StringIO(test_config)) e = ev.read('test') config_real_path = substitute_path_variables(config_var_path) @@ -790,7 +790,7 @@ def test_env_config_precedence(): specs: - mpileaks """ - _env_create('test', StringIO(test_config)) + _env_create('test', io.StringIO(test_config)) e = ev.read('test') with open(os.path.join(e.path, 'included-config.yaml'), 'w') as f: @@ -823,7 +823,7 @@ def test_included_config_precedence(): specs: - mpileaks """ - _env_create('test', StringIO(test_config)) + _env_create('test', io.StringIO(test_config)) e = ev.read('test') with open(os.path.join(e.path, 'high-config.yaml'), 'w') as f: @@ -1149,7 +1149,7 @@ def test_env_config_view_default( specs: - mpileaks """ - _env_create('test', StringIO(test_config)) + _env_create('test', io.StringIO(test_config)) with ev.read('test'): install('--fake') @@ -2578,7 +2578,7 @@ def test_modules_relative_to_views(tmpdir, install_mockery, mock_fetch): roots: tcl: modules """ - _env_create('test', StringIO(spack_yaml)) + _env_create('test', io.StringIO(spack_yaml)) with ev.read('test') as e: install() @@ -2613,7 +2613,7 @@ def test_multiple_modules_post_env_hook(tmpdir, install_mockery, mock_fetch): roots: tcl: full_modules """ - _env_create('test', StringIO(spack_yaml)) + _env_create('test', io.StringIO(spack_yaml)) with ev.read('test') as e: install() diff --git a/lib/ramble/spack/test/cmd/install.py b/lib/ramble/spack/test/cmd/install.py index 4b9f578c3..649f6ce40 100644 --- a/lib/ramble/spack/test/cmd/install.py +++ b/lib/ramble/spack/test/cmd/install.py @@ -4,6 +4,7 @@ # SPDX-License-Identifier: (Apache-2.0 OR MIT) import argparse +import builtins import filecmp import os import re @@ -11,7 +12,6 @@ import time import pytest -from six.moves import builtins import llnl.util.filesystem as fs diff --git a/lib/ramble/spack/test/compilers/basics.py b/lib/ramble/spack/test/compilers/basics.py index 4d4794663..4735be166 100644 --- a/lib/ramble/spack/test/compilers/basics.py +++ b/lib/ramble/spack/test/compilers/basics.py @@ -9,7 +9,6 @@ from copy import copy import pytest -from six import iteritems import llnl.util.filesystem as fs @@ -77,7 +76,7 @@ def test_get_compiler_duplicates(config): 'gcc@4.5.0', spack.spec.ArchSpec('cray-CNL-xeon')) assert len(cfg_file_to_duplicates) == 1 - cfg_file, duplicates = next(iteritems(cfg_file_to_duplicates)) + cfg_file, duplicates = next(iter(cfg_file_to_duplicates.items())) assert len(duplicates) == 1 diff --git a/lib/ramble/spack/test/config.py b/lib/ramble/spack/test/config.py index eae3afa26..436f7a8ee 100644 --- a/lib/ramble/spack/test/config.py +++ b/lib/ramble/spack/test/config.py @@ -5,12 +5,12 @@ import collections import getpass +import io import os import sys import tempfile import pytest -from six import StringIO from llnl.util.filesystem import getuid, mkdirp, touch @@ -1000,7 +1000,7 @@ def test_write_empty_single_file_scope(tmpdir): def check_schema(name, file_contents): """Check a Spack YAML schema against some data""" - f = StringIO(file_contents) + f = io.StringIO(file_contents) data = syaml.load_config(f) spack.config.validate(data, name) diff --git a/lib/ramble/spack/test/graph.py b/lib/ramble/spack/test/graph.py index f3a7db1ea..8530408bd 100644 --- a/lib/ramble/spack/test/graph.py +++ b/lib/ramble/spack/test/graph.py @@ -2,10 +2,10 @@ # Spack Project Developers. See the top-level COPYRIGHT file for details. # # SPDX-License-Identifier: (Apache-2.0 OR MIT) +import io import sys import pytest -import six import spack.graph import spack.repo @@ -25,7 +25,7 @@ def test_static_graph_mpileaks(config, mock_packages): """Test a static spack graph for a simple package.""" s = spack.spec.Spec('mpileaks').normalized() - stream = six.StringIO() + stream = io.StringIO() spack.graph.graph_dot([s], static=True, out=stream) dot = stream.getvalue() @@ -53,7 +53,7 @@ def test_static_graph_mpileaks(config, mock_packages): def test_dynamic_dot_graph_mpileaks(mock_packages, config): """Test dynamically graphing the mpileaks package.""" s = spack.spec.Spec('mpileaks').concretized() - stream = six.StringIO() + stream = io.StringIO() spack.graph.graph_dot([s], static=False, out=stream) dot = stream.getvalue() @@ -90,7 +90,7 @@ def test_ascii_graph_mpileaks(config, mock_packages, monkeypatch): ) s = spack.spec.Spec('mpileaks').concretized() - stream = six.StringIO() + stream = io.StringIO() graph = spack.graph.AsciiGraph() graph.write(s, out=stream, color=False) graph_str = stream.getvalue() diff --git a/lib/ramble/spack/test/llnl/util/file_list.py b/lib/ramble/spack/test/llnl/util/file_list.py index 036cea500..c2a0404c7 100644 --- a/lib/ramble/spack/test/llnl/util/file_list.py +++ b/lib/ramble/spack/test/llnl/util/file_list.py @@ -7,7 +7,6 @@ import os.path import pytest -import six from llnl.util.filesystem import ( HeaderList, @@ -252,7 +251,7 @@ def test_searching_order(search_fn, search_list, root, kwargs): rlist = list(reversed(result)) # At this point make sure the search list is a sequence - if isinstance(search_list, six.string_types): + if isinstance(search_list, str): search_list = [search_list] # Discard entries in the order they appear in search list diff --git a/lib/ramble/spack/test/provider_index.py b/lib/ramble/spack/test/provider_index.py index 609f0a059..365a4f407 100644 --- a/lib/ramble/spack/test/provider_index.py +++ b/lib/ramble/spack/test/provider_index.py @@ -18,7 +18,7 @@ mpi@:10.0: set([zmpi])}, 'stuff': {stuff: set([externalvirtual])}} """ -from six import StringIO +import io import spack.repo from spack.provider_index import ProviderIndex @@ -28,10 +28,10 @@ def test_provider_index_round_trip(mock_packages): p = ProviderIndex(spack.repo.all_package_names()) - ostream = StringIO() + ostream = io.StringIO() p.to_json(ostream) - istream = StringIO(ostream.getvalue()) + istream = io.StringIO(ostream.getvalue()) q = ProviderIndex.from_json(istream) assert p == q diff --git a/lib/ramble/spack/test/tag.py b/lib/ramble/spack/test/tag.py index 92445dd5c..b0ec44b91 100644 --- a/lib/ramble/spack/test/tag.py +++ b/lib/ramble/spack/test/tag.py @@ -4,8 +4,9 @@ # SPDX-License-Identifier: (Apache-2.0 OR MIT) """Tests for tag index cache files.""" +import io + import pytest -from six import StringIO import spack.cmd.install import spack.tag @@ -42,7 +43,7 @@ def test_tag_copy(mock_packages): - index = spack.tag.TagIndex.from_json(StringIO(tags_json)) + index = spack.tag.TagIndex.from_json(io.StringIO(tags_json)) new_index = index.copy() assert index.tags == new_index.tags @@ -100,25 +101,25 @@ def test_tag_index_round_trip(mock_packages): mock_index = spack.repo.path.tag_index assert mock_index.tags - ostream = StringIO() + ostream = io.StringIO() mock_index.to_json(ostream) - istream = StringIO(ostream.getvalue()) + istream = io.StringIO(ostream.getvalue()) new_index = spack.tag.TagIndex.from_json(istream) assert mock_index == new_index def test_tag_equal(): - first_index = spack.tag.TagIndex.from_json(StringIO(tags_json)) - second_index = spack.tag.TagIndex.from_json(StringIO(tags_json)) + first_index = spack.tag.TagIndex.from_json(io.StringIO(tags_json)) + second_index = spack.tag.TagIndex.from_json(io.StringIO(tags_json)) assert first_index == second_index def test_tag_merge(): - first_index = spack.tag.TagIndex.from_json(StringIO(tags_json)) - second_index = spack.tag.TagIndex.from_json(StringIO(more_tags_json)) + first_index = spack.tag.TagIndex.from_json(io.StringIO(tags_json)) + second_index = spack.tag.TagIndex.from_json(io.StringIO(more_tags_json)) assert first_index != second_index @@ -139,14 +140,14 @@ def test_tag_merge(): def test_tag_not_dict(): list_json = "[]" with pytest.raises(spack.tag.TagIndexError) as e: - spack.tag.TagIndex.from_json(StringIO(list_json)) + spack.tag.TagIndex.from_json(io.StringIO(list_json)) assert "not a dict" in str(e) def test_tag_no_tags(): pkg_json = "{\"packages\": []}" with pytest.raises(spack.tag.TagIndexError) as e: - spack.tag.TagIndex.from_json(StringIO(pkg_json)) + spack.tag.TagIndex.from_json(io.StringIO(pkg_json)) assert "does not start with" in str(e) diff --git a/lib/ramble/spack/test/util/unparse/unparse.py b/lib/ramble/spack/test/util/unparse/unparse.py index f3a74aa9b..93d30c904 100644 --- a/lib/ramble/spack/test/util/unparse/unparse.py +++ b/lib/ramble/spack/test/util/unparse/unparse.py @@ -6,14 +6,9 @@ import codecs import os import sys +import tokenize import pytest -import six - -if six.PY3: - import tokenize -else: - from lib2to3.pgen2 import tokenize import spack.util.unparse @@ -24,14 +19,10 @@ def read_pyfile(filename): """Read and return the contents of a Python source file (as a string), taking into account the file encoding.""" - if six.PY3: - with open(filename, "rb") as pyfile: - encoding = tokenize.detect_encoding(pyfile.readline)[0] - with codecs.open(filename, "r", encoding=encoding) as pyfile: - source = pyfile.read() - else: - with open(filename, "r") as pyfile: - source = pyfile.read() + with open(filename, "rb") as pyfile: + encoding = tokenize.detect_encoding(pyfile.readline)[0] + with codecs.open(filename, "r", encoding=encoding) as pyfile: + source = pyfile.read() return source @@ -286,13 +277,6 @@ def test_huge_float(): check_ast_roundtrip("-1e1000j") -@pytest.mark.skipif(not six.PY2, reason="Only works for Python 2") -def test_min_int27(): - check_ast_roundtrip(str(-sys.maxint - 1)) - check_ast_roundtrip("-(%s)" % (sys.maxint + 1)) - - -@pytest.mark.skipif(not six.PY3, reason="Only works for Python 3") def test_min_int30(): check_ast_roundtrip(str(-2**31)) check_ast_roundtrip(str(-2**63)) @@ -303,9 +287,6 @@ def test_imaginary_literals(): check_ast_roundtrip("-7j") check_ast_roundtrip("0j") check_ast_roundtrip("-0j") - if six.PY2: - check_ast_roundtrip("-(7j)") - check_ast_roundtrip("-(0j)") def test_negative_zero(): @@ -336,12 +317,11 @@ def test_function_arguments(): check_ast_roundtrip("def f(a, b = 2): pass") check_ast_roundtrip("def f(a = 5, b = 2): pass") check_ast_roundtrip("def f(*args, **kwargs): pass") - if six.PY3: - check_ast_roundtrip("def f(*, a = 1, b = 2): pass") - check_ast_roundtrip("def f(*, a = 1, b): pass") - check_ast_roundtrip("def f(*, a, b = 2): pass") - check_ast_roundtrip("def f(a, b = None, *, c, **kwds): pass") - check_ast_roundtrip("def f(a=2, *args, c=5, d, **kwds): pass") + check_ast_roundtrip("def f(*, a = 1, b = 2): pass") + check_ast_roundtrip("def f(*, a = 1, b): pass") + check_ast_roundtrip("def f(*, a, b = 2): pass") + check_ast_roundtrip("def f(a, b = None, *, c, **kwds): pass") + check_ast_roundtrip("def f(a=2, *args, c=5, d, **kwds): pass") def test_relative_import(): @@ -352,12 +332,10 @@ def test_import_many(): check_ast_roundtrip(import_many) -@pytest.mark.skipif(not six.PY3, reason="Only for Python 3") def test_nonlocal(): check_ast_roundtrip(nonlocal_ex) -@pytest.mark.skipif(not six.PY3, reason="Only for Python 3") def test_raise_from(): check_ast_roundtrip(raise_from) @@ -394,11 +372,6 @@ def test_joined_str_361(): check_ast_roundtrip('f"{key:4}={value!a:#06x}"') -@pytest.mark.skipif(not six.PY2, reason="Only for Python 2") -def test_repr(): - check_ast_roundtrip(a_repr) - - @pytest.mark.skipif( sys.version_info[:2] < (3, 6), reason="Only for Python 3.6 or greater" @@ -407,7 +380,6 @@ def test_complex_f_string(): check_ast_roundtrip(complex_f_string) -@pytest.mark.skipif(not six.PY3, reason="Only for Python 3") def test_annotations(): check_ast_roundtrip("def f(a : int): pass") check_ast_roundtrip("def f(a: int = 5): pass") @@ -459,7 +431,6 @@ def test_class_decorators(): check_ast_roundtrip(class_decorator) -@pytest.mark.skipif(not six.PY3, reason="Only for Python 3") def test_class_definition(): check_ast_roundtrip("class A(metaclass=type, *[], **{}): pass") @@ -473,7 +444,6 @@ def test_try_except_finally(): check_ast_roundtrip(try_except_finally) -@pytest.mark.skipif(not six.PY3, reason="Only for Python 3") def test_starred_assignment(): check_ast_roundtrip("a, *b, c = seq") check_ast_roundtrip("a, (*b, c) = seq") diff --git a/lib/ramble/spack/url.py b/lib/ramble/spack/url.py index 8ad7b196a..f83fdfa8b 100644 --- a/lib/ramble/spack/url.py +++ b/lib/ramble/spack/url.py @@ -28,8 +28,7 @@ import os import re -from six import StringIO -from six.moves.urllib.parse import urlsplit, urlunsplit +from urllib.parse import urlsplit, urlunsplit import llnl.util.tty as tty from llnl.util.tty.color import cescape, colorize @@ -932,7 +931,7 @@ def color_url(path, **kwargs): vends = [vo + vl - 1 for vo in voffs] nerr = verr = 0 - out = StringIO() + out = io.StringIO() for i in range(len(path)): if i == vs: out.write('@c') diff --git a/lib/ramble/spack/util/environment.py b/lib/ramble/spack/util/environment.py index c2870c17b..e3b5fbdf4 100644 --- a/lib/ramble/spack/util/environment.py +++ b/lib/ramble/spack/util/environment.py @@ -9,14 +9,12 @@ import json import os import os.path +import pickle import platform import re import socket import sys -import six -from six.moves import cPickle - import llnl.util.tty as tty from llnl.util.lang import dedupe @@ -170,7 +168,7 @@ def dump_environment(path, environment=None): @system_path_filter(arg_slice=slice(1)) def pickle_environment(path, environment=None): """Pickle an environment dictionary to a file.""" - cPickle.dump(dict(environment if environment else os.environ), + pickle.dump(dict(environment if environment else os.environ), open(path, 'wb'), protocol=2) @@ -1067,7 +1065,7 @@ def _source_single_file(file_and_args, environment): current_environment = kwargs.get('env', dict(os.environ)) for f in files: # Normalize the input to the helper function - if isinstance(f, six.string_types): + if isinstance(f, str): f = [f] current_environment = _source_single_file( diff --git a/lib/ramble/spack/util/executable.py b/lib/ramble/spack/util/executable.py index c424b9cdb..aec00e8ad 100644 --- a/lib/ramble/spack/util/executable.py +++ b/lib/ramble/spack/util/executable.py @@ -9,8 +9,6 @@ import subprocess import sys -from six import string_types, text_type - import llnl.util.tty as tty import spack.error @@ -166,7 +164,7 @@ def __call__(self, *args, **kwargs): raise ValueError('Cannot use `str` as input stream.') def streamify(arg, mode): - if isinstance(arg, string_types): + if isinstance(arg, str): return open(arg, mode), True elif arg in (str, str.split): return subprocess.PIPE, False @@ -211,17 +209,17 @@ def streamify(arg, mode): result = '' if output in (str, str.split): if sys.platform == 'win32': - outstr = text_type(out.decode('ISO-8859-1')) + outstr = str(out.decode('ISO-8859-1')) else: - outstr = text_type(out.decode('utf-8')) + outstr = str(out.decode('utf-8')) result += outstr if output is str.split: sys.stdout.write(outstr) if error in (str, str.split): if sys.platform == 'win32': - errstr = text_type(err.decode('ISO-8859-1')) + errstr = str(err.decode('ISO-8859-1')) else: - errstr = text_type(err.decode('utf-8')) + errstr = str(err.decode('utf-8')) result += errstr if error is str.split: sys.stderr.write(errstr) @@ -281,7 +279,7 @@ def which_string(*args, **kwargs): path = kwargs.get('path', os.environ.get('PATH', '')) required = kwargs.get('required', False) - if isinstance(path, string_types): + if isinstance(path, str): path = path.split(os.pathsep) for name in args: diff --git a/lib/ramble/spack/util/log_parse.py b/lib/ramble/spack/util/log_parse.py index b344de43a..4aa0755a6 100644 --- a/lib/ramble/spack/util/log_parse.py +++ b/lib/ramble/spack/util/log_parse.py @@ -5,10 +5,10 @@ from __future__ import print_function +import io import sys from ctest_log_parser import BuildError, BuildWarning, CTestLogParser -from six import StringIO import llnl.util.tty as tty from llnl.util.tty.color import cescape, colorize @@ -86,7 +86,7 @@ def make_log_context(log_events, width=None): width = sys.maxsize wrap_width = width - num_width - 6 - out = StringIO() + out = io.StringIO() next_line = 1 for event in log_events: start = event.start diff --git a/lib/ramble/spack/util/naming.py b/lib/ramble/spack/util/naming.py index 624bd6ed7..5fc32b8af 100644 --- a/lib/ramble/spack/util/naming.py +++ b/lib/ramble/spack/util/naming.py @@ -7,11 +7,10 @@ from __future__ import absolute_import import itertools +import io import re import string -from six import StringIO - import spack.error __all__ = [ @@ -262,6 +261,6 @@ def _str_helper(self, stream, level=0): stream.write(self._subspaces[name]._str_helper(stream, level + 1)) def __str__(self): - stream = StringIO() + stream = io.StringIO() self._str_helper(stream) return stream.getvalue() diff --git a/lib/ramble/spack/util/path.py b/lib/ramble/spack/util/path.py index cd14cb433..a8135b2b0 100644 --- a/lib/ramble/spack/util/path.py +++ b/lib/ramble/spack/util/path.py @@ -15,7 +15,7 @@ import sys import tempfile -from six.moves.urllib.parse import urlparse +from urllib.parse import urlparse import llnl.util.tty as tty from llnl.util.lang import memoized diff --git a/lib/ramble/spack/util/py2.py b/lib/ramble/spack/util/py2.py deleted file mode 100644 index b92a6d66d..000000000 --- a/lib/ramble/spack/util/py2.py +++ /dev/null @@ -1,16 +0,0 @@ -# Copyright 2013-2022 Lawrence Livermore National Security, LLC and other -# Spack Project Developers. See the top-level COPYRIGHT file for details. -# -# SPDX-License-Identifier: (Apache-2.0 OR MIT) - -import base64 - -from six import PY3, binary_type, text_type - - -def b32encode(digest): - # type: (binary_type) -> text_type - b32 = base64.b32encode(digest) - if PY3: - return b32.decode() - return b32 diff --git a/lib/ramble/spack/util/s3.py b/lib/ramble/spack/util/s3.py index b52a879e2..c1ac80b43 100644 --- a/lib/ramble/spack/util/s3.py +++ b/lib/ramble/spack/util/s3.py @@ -5,7 +5,7 @@ import os -import six.moves.urllib.parse as urllib_parse +import urllib.parse import spack import spack.util.url as url_util @@ -21,7 +21,7 @@ def get_mirror_connection(url, url_type="push"): def _parse_s3_endpoint_url(endpoint_url): - if not urllib_parse.urlparse(endpoint_url, scheme='').scheme: + if not urllib.parse.urlparse(endpoint_url, scheme='').scheme: endpoint_url = '://'.join(('https', endpoint_url)) return endpoint_url diff --git a/lib/ramble/spack/util/spack_json.py b/lib/ramble/spack/util/spack_json.py index 7083b3c80..b1a5671af 100644 --- a/lib/ramble/spack/util/spack_json.py +++ b/lib/ramble/spack/util/spack_json.py @@ -7,8 +7,6 @@ import json from typing import Any, Dict, Optional # novm -from six import PY3, iteritems, string_types - import spack.error __all__ = ['load', 'dump', 'SpackJSONError', 'encode_json_dict', 'decode_json_dict'] @@ -22,7 +20,7 @@ def load(stream): # type: (Any) -> Dict """Spack JSON needs to be ordered to support specs.""" - if isinstance(stream, string_types): + if isinstance(stream, str): load = json.loads # type: ignore[assignment] else: load = json.load # type: ignore[assignment] @@ -58,25 +56,6 @@ def _strify(data, ignore_dicts=False): Converts python 2 unicodes to str in JSON data, or the other way around.""" # this is a no-op in python 3 - if PY3: - return data - - # if this is a unicode string in python 2, return its string representation - if isinstance(data, string_types): - return data.encode('utf-8') - - # if this is a list of values, return list of byteified values - if isinstance(data, list): - return [_strify(item, ignore_dicts=True) for item in data] - - # if this is a dictionary, return dictionary of byteified keys and values - # but only if we haven't already byteified it - if isinstance(data, dict) and not ignore_dicts: - return dict((_strify(key, ignore_dicts=True), - _strify(value, ignore_dicts=True)) for key, value in - iteritems(data)) - - # if it's anything else, return it in its original form return data diff --git a/lib/ramble/spack/util/spack_yaml.py b/lib/ramble/spack/util/spack_yaml.py index 227b9d744..fae0f6cc4 100644 --- a/lib/ramble/spack/util/spack_yaml.py +++ b/lib/ramble/spack/util/spack_yaml.py @@ -14,12 +14,12 @@ """ import collections import ctypes +import io import re from typing import List # novm import ruamel.yaml as yaml from ruamel.yaml import RoundTripDumper, RoundTripLoader -from six import StringIO, string_types from llnl.util.compat import Mapping from llnl.util.tty.color import cextra, clen, colorize @@ -52,7 +52,7 @@ class syaml_int(int): #: mapping from syaml type -> primitive type syaml_types = { - syaml_str: string_types, + syaml_str: str, syaml_int: int, syaml_dict: dict, syaml_list: list, @@ -262,7 +262,7 @@ def represent_data(self, data): result = super(LineAnnotationDumper, self).represent_data(data) if data is None: result.value = syaml_str("null") - elif isinstance(result.value, string_types): + elif isinstance(result.value, str): result.value = syaml_str(data) if markable(result.value): mark(result.value, data) @@ -317,7 +317,7 @@ def dump_config(*args, **kwargs): def dump_annotated(data, stream=None, *args, **kwargs): kwargs['Dumper'] = LineAnnotationDumper - sio = StringIO() + sio = io.StringIO() yaml.dump(data, sio, *args, **kwargs) # write_line_break() is not called by YAML for empty lines, so we @@ -326,7 +326,7 @@ def dump_annotated(data, stream=None, *args, **kwargs): getvalue = None if stream is None: - stream = StringIO() + stream = io.StringIO() getvalue = stream.getvalue # write out annotations and lines, accounting for color diff --git a/lib/ramble/spack/util/unparse/__init__.py b/lib/ramble/spack/util/unparse/__init__.py index da75271fb..aa68ac575 100644 --- a/lib/ramble/spack/util/unparse/__init__.py +++ b/lib/ramble/spack/util/unparse/__init__.py @@ -5,7 +5,7 @@ from __future__ import absolute_import -from six.moves import cStringIO +import io from .unparser import Unparser @@ -13,7 +13,6 @@ def unparse(tree, py_ver_consistent=False): - v = cStringIO() - unparser = Unparser(py_ver_consistent=py_ver_consistent) - unparser.visit(tree, v) + v = io.StringIO() + Unparser(py_ver_consistent=py_ver_consistent).visit(tree, v) return v.getvalue().strip() + "\n" diff --git a/lib/ramble/spack/util/unparse/unparser.py b/lib/ramble/spack/util/unparse/unparser.py index 27197bd69..3ab6dd27c 100644 --- a/lib/ramble/spack/util/unparse/unparser.py +++ b/lib/ramble/spack/util/unparse/unparser.py @@ -8,9 +8,7 @@ import ast import sys from contextlib import contextmanager - -import six -from six import StringIO +from io import StringIO # TODO: if we require Python 3.7, use its `nullcontext()` @@ -77,12 +75,7 @@ def is_simple_tuple(slice_value): return ( isinstance(slice_value, ast.Tuple) and slice_value.elts - and ( - # Python 2 doesn't allow starred elements in tuples like Python 3 - six.PY2 or not any( - isinstance(elt, ast.Starred) for elt in slice_value.elts - ) - ) + and not any(isinstance(elt, ast.Starred) for elt in slice_value.elts) ) @@ -147,7 +140,7 @@ def fill(self, text=""): def write(self, text): "Append a piece of text to the current line." - self.f.write(six.text_type(text)) + self.f.write(str(text)) class _Block: """A context manager for preparing the source for blocks. It adds @@ -397,25 +390,14 @@ def visit_YieldFrom(self, node): def visit_Raise(self, node): self.fill("raise") - if six.PY3: - if not node.exc: - assert not node.cause - return - self.write(" ") - self.dispatch(node.exc) - if node.cause: - self.write(" from ") - self.dispatch(node.cause) - else: - self.write(" ") - if node.type: - self.dispatch(node.type) - if node.inst: - self.write(", ") - self.dispatch(node.inst) - if node.tback: - self.write(", ") - self.dispatch(node.tback) + if not node.exc: + assert not node.cause + return + self.write(" ") + self.dispatch(node.exc) + if node.cause: + self.write(" from ") + self.dispatch(node.cause) def visit_Try(self, node): self.fill("try") @@ -464,10 +446,7 @@ def visit_ExceptHandler(self, node): self.dispatch(node.type) if node.name: self.write(" as ") - if six.PY3: - self.write(node.name) - else: - self.dispatch(node.name) + self.write(node.name) with self.block(): self.dispatch(node.body) @@ -477,42 +456,35 @@ def visit_ClassDef(self, node): self.fill("@") self.dispatch(deco) self.fill("class " + node.name) - if six.PY3: - with self.delimit_if("(", ")", condition=node.bases or node.keywords): - comma = False - for e in node.bases: + with self.delimit_if("(", ")", condition=node.bases or node.keywords): + comma = False + for e in node.bases: + if comma: + self.write(", ") + else: + comma = True + self.dispatch(e) + for e in node.keywords: + if comma: + self.write(", ") + else: + comma = True + self.dispatch(e) + if sys.version_info[:2] < (3, 5): + if node.starargs: if comma: self.write(", ") else: comma = True - self.dispatch(e) - for e in node.keywords: + self.write("*") + self.dispatch(node.starargs) + if node.kwargs: if comma: self.write(", ") else: comma = True - self.dispatch(e) - if sys.version_info[:2] < (3, 5): - if node.starargs: - if comma: - self.write(", ") - else: - comma = True - self.write("*") - self.dispatch(node.starargs) - if node.kwargs: - if comma: - self.write(", ") - else: - comma = True - self.write("**") - self.dispatch(node.kwargs) - elif node.bases: - with self.delimit("(", ")"): - for a in node.bases[:-1]: - self.dispatch(a) - self.write(", ") - self.dispatch(node.bases[-1]) + self.write("**") + self.dispatch(node.kwargs) with self.block(): self.dispatch(node.body) @@ -654,26 +626,11 @@ def visit_Bytes(self, node): self.write(repr(node.s)) def visit_Str(self, tree): - if six.PY3: - # Python 3.5, 3.6, and 3.7 can't tell if something was written as a - # unicode constant. Try to make that consistent with 'u' for '\u- literals - if self._py_ver_consistent and repr(tree.s).startswith("'\\u"): - self.write("u") - self._write_constant(tree.s) - elif self._py_ver_consistent: - self.write(repr(tree.s)) # just do a python 2 repr for consistency - else: - # if from __future__ import unicode_literals is in effect, - # then we want to output string literals using a 'b' prefix - # and unicode literals with no prefix. - if "unicode_literals" not in self.future_imports: - self.write(repr(tree.s)) - elif isinstance(tree.s, str): - self.write("b" + repr(tree.s)) - elif isinstance(tree.s, unicode): # noqa - self.write(repr(tree.s).lstrip("u")) - else: - assert False, "shouldn't get here" + # Python 3.5, 3.6, and 3.7 can't tell if something was written as a + # unicode constant. Try to make that consistent with 'u' for '\u- literals + if self._py_ver_consistent and repr(tree.s).startswith("'\\u"): + self.write("u") + self._write_constant(tree.s) def visit_JoinedStr(self, node): # JoinedStr(expr* values) @@ -804,15 +761,7 @@ def visit_Constant(self, node): def visit_Num(self, node): repr_n = repr(node.n) - if six.PY3: - self.write(repr_n.replace("inf", INFSTR)) - else: - # Parenthesize negative numbers, to avoid turning (-1)**2 into -1**2. - with self.require_parens(pnext(_Precedence.FACTOR), node): - if "inf" in repr_n and repr_n.endswith("*j"): - repr_n = repr_n.replace("*j", "j") - # Substitute overflowing decimal literal for AST infinities. - self.write(repr_n.replace("inf", INFSTR)) + self.write(repr_n.replace("inf", INFSTR)) def visit_List(self, node): with self.delimit("[", "]"): @@ -926,17 +875,7 @@ def visit_UnaryOp(self, node): self.write(" ") self.set_precedence(operator_precedence, node.operand) - if (six.PY2 and - isinstance(node.op, ast.USub) and isinstance(node.operand, ast.Num)): - # If we're applying unary minus to a number, parenthesize the number. - # This is necessary: -2147483648 is different from -(2147483648) on - # a 32-bit machine (the first is an int, the second a long), and - # -7j is different from -(7j). (The first has real part 0.0, the second - # has real part -0.0.) - with self.delimit("(", ")"): - self.dispatch(node.operand) - else: - self.dispatch(node.operand) + self.dispatch(node.operand) binop = { "Add": "+", diff --git a/lib/ramble/spack/util/url.py b/lib/ramble/spack/util/url.py index 824b5fed5..8c5900d57 100644 --- a/lib/ramble/spack/util/url.py +++ b/lib/ramble/spack/util/url.py @@ -12,8 +12,7 @@ import re import sys -import six.moves.urllib.parse as urllib_parse -from six import string_types +import urllib.parse from spack.util.path import ( canonicalize_path, @@ -50,7 +49,7 @@ def local_file_path(url): If url is a file:// URL, return the absolute path to the local file or directory referenced by it. Otherwise, return None. """ - if isinstance(url, string_types): + if isinstance(url, str): url = parse(url) if url.scheme == 'file': @@ -75,12 +74,12 @@ def parse(url, scheme='file'): """ # guarantee a value passed in is of proper url format. Guarantee # allows for easier string manipulation accross platforms - if isinstance(url, string_types): + if isinstance(url, str): require_url_format(url) url = escape_file_url(url) url_obj = ( - urllib_parse.urlparse(url, scheme=scheme, allow_fragments=False) - if isinstance(url, string_types) else url) + urllib.parse.urlparse(url, scheme=scheme, allow_fragments=False) + if isinstance(url, str) else url) (scheme, netloc, path, params, query, _) = url_obj @@ -106,7 +105,7 @@ def parse(url, scheme='file'): if sys.platform == "win32": path = convert_to_posix_path(path) - return urllib_parse.ParseResult(scheme=scheme, + return urllib.parse.ParseResult(scheme=scheme, netloc=netloc, path=path, params=params, @@ -119,7 +118,7 @@ def format(parsed_url): Returns a canonicalized format of the given URL as a string. """ - if isinstance(parsed_url, string_types): + if isinstance(parsed_url, str): parsed_url = parse(parsed_url) return parsed_url.geturl() @@ -180,7 +179,7 @@ def join(base_url, path, *extra, **kwargs): 'file:///opt/spack' """ paths = [ - (x) if isinstance(x, string_types) + (x) if isinstance(x, str) else x.geturl() for x in itertools.chain((base_url, path), extra)] @@ -189,7 +188,7 @@ def join(base_url, path, *extra, **kwargs): last_abs_component = None scheme = '' for i in range(n - 1, -1, -1): - obj = urllib_parse.urlparse( + obj = urllib.parse.urlparse( paths[i], scheme='', allow_fragments=False) scheme = obj.scheme @@ -200,7 +199,7 @@ def join(base_url, path, *extra, **kwargs): # Without a scheme, we have to go back looking for the # next-last component that specifies a scheme. for j in range(i - 1, -1, -1): - obj = urllib_parse.urlparse( + obj = urllib.parse.urlparse( paths[j], scheme='', allow_fragments=False) if obj.scheme: @@ -218,14 +217,14 @@ def join(base_url, path, *extra, **kwargs): if last_abs_component is not None: paths = paths[last_abs_component:] if len(paths) == 1: - result = urllib_parse.urlparse( + result = urllib.parse.urlparse( paths[0], scheme='file', allow_fragments=False) # another subtlety: If the last argument to join() is an absolute # file:// URL component with a relative path, the relative path # needs to be resolved. if result.scheme == 'file' and result.netloc: - result = urllib_parse.ParseResult( + result = urllib.parse.ParseResult( scheme=result.scheme, netloc='', path=posixpath.abspath(result.netloc + result.path), @@ -281,7 +280,7 @@ def _join(base_url, path, *extra, **kwargs): if sys.platform == "win32": base_path = convert_to_posix_path(base_path) - return format(urllib_parse.ParseResult(scheme=scheme, + return format(urllib.parse.ParseResult(scheme=scheme, netloc=netloc, path=base_path, params=params, diff --git a/lib/ramble/spack/util/web.py b/lib/ramble/spack/util/web.py index 4bd0d9258..bbd5f332e 100644 --- a/lib/ramble/spack/util/web.py +++ b/lib/ramble/spack/util/web.py @@ -16,9 +16,8 @@ import sys import traceback -import six -from six.moves.urllib.error import URLError -from six.moves.urllib.request import Request, urlopen +from urllib.error import URLError +from urllib.request import Request, urlopen import llnl.util.lang import llnl.util.tty as tty @@ -507,7 +506,7 @@ def _spider(url, collect_nested): return pages, links, subcalls - if isinstance(root_urls, six.string_types): + if isinstance(root_urls, str): root_urls = [root_urls] # Clear the local cache of visited pages before starting the search diff --git a/lib/ramble/spack/variant.py b/lib/ramble/spack/variant.py index 4ec016830..d5e8fd5d1 100644 --- a/lib/ramble/spack/variant.py +++ b/lib/ramble/spack/variant.py @@ -12,9 +12,6 @@ import itertools import re -import six -from six import StringIO - import llnl.util.lang as lang import llnl.util.tty.color from llnl.util.compat import Sequence @@ -658,7 +655,7 @@ def __str__(self): else kv_keys.append(key) # add spaces before and after key/value variants. - string = StringIO() + string = io.StringIO() for key in bool_keys: string.write(str(self[key])) @@ -886,12 +883,12 @@ def __hash__(self): return hash(self.value) def __eq__(self, other): - if isinstance(other, six.string_types): + if isinstance(other, str): return self.value == other return self.value == other.value def __lt__(self, other): - if isinstance(other, six.string_types): + if isinstance(other, str): return self.value < other return self.value < other.value diff --git a/lib/ramble/spack/version.py b/lib/ramble/spack/version.py index 495cfee6e..88888f442 100644 --- a/lib/ramble/spack/version.py +++ b/lib/ramble/spack/version.py @@ -30,8 +30,6 @@ from bisect import bisect_left from functools import wraps -from six import string_types - import llnl.util.tty as tty from llnl.util.filesystem import mkdirp, working_dir @@ -501,9 +499,9 @@ def generate_commit_lookup(self, pkg_name): class VersionRange(object): def __init__(self, start, end): - if isinstance(start, string_types): + if isinstance(start, str): start = Version(start) - if isinstance(end, string_types): + if isinstance(end, str): end = Version(end) self.start = start @@ -703,7 +701,7 @@ class VersionList(object): def __init__(self, vlist=None): self.versions = [] if vlist is not None: - if isinstance(vlist, string_types): + if isinstance(vlist, str): vlist = _string_to_version(vlist) if type(vlist) == VersionList: self.versions = vlist.versions @@ -963,7 +961,7 @@ def ver(obj): """ if isinstance(obj, (list, tuple)): return VersionList(obj) - elif isinstance(obj, string_types): + elif isinstance(obj, str): return _string_to_version(obj) elif isinstance(obj, (int, float)): return _string_to_version(str(obj)) diff --git a/var/ramble/repos/builtin/modifiers/conditional-psm3/modifier.py b/var/ramble/repos/builtin/modifiers/conditional-psm3/modifier.py index be017f85a..bccde326a 100644 --- a/var/ramble/repos/builtin/modifiers/conditional-psm3/modifier.py +++ b/var/ramble/repos/builtin/modifiers/conditional-psm3/modifier.py @@ -25,31 +25,34 @@ class ConditionalPsm3(BasicModifier): These environment variables are removed after the command finishes. """ + name = "conditional-psm3" - tags('mpi-provider') + tags("mpi-provider") - maintainers('douglasjacobsen') + maintainers("douglasjacobsen") - mode('standard', description='Standard execution mode for conditional PSM3') + mode( + "standard", description="Standard execution mode for conditional PSM3" + ) - executable_modifier('apply_psm3') + executable_modifier("apply_psm3") - required_variable('psm3_mpi') - required_package('intel-oneapi-mpi') + required_variable("psm3_mpi") + required_package("intel-oneapi-mpi") modifier_variable( - 'apply_psm3_exec_regex', - default='', - description='When the non-empty regex matches with the executable_name, apply psm3 even if mpi is not explicitly used', - mode='standard' + "apply_psm3_exec_regex", + default="", + description="When the non-empty regex matches with the executable_name, apply psm3 even if mpi is not explicitly used", + mode="standard", ) modifier_variable( - 'psm3_log_file', - default='{log_file}', - description='Log file where PSM3 info writes to, this varies based on applications', - mode='standard', + "psm3_log_file", + default="{log_file}", + description="Log file where PSM3 info writes to, this varies based on applications", + mode="standard", ) def apply_psm3(self, executable_name, executable, app_inst=None): @@ -58,64 +61,66 @@ def apply_psm3(self, executable_name, executable, app_inst=None): pre_cmds = [] post_cmds = [] - exec_regex = self.expander.expand_var_name('apply_psm3_exec_regex') + exec_regex = self.expander.expand_var_name("apply_psm3_exec_regex") should_apply = executable.mpi or ( exec_regex and re.match(exec_regex, executable_name) ) if should_apply: pre_cmds.append( - CommandExecutable(f'add-psm3-{executable_name}', - template=[ - 'grep "{psm3_mpi}" {env_path}/spack.yaml &> /dev/null', - 'if [ $? -eq 0 ]; then', - 'spack load {psm3_mpi}', - 'export FI_PROVIDER="psm3"', - 'export PSM3_ALLOW_ROUTERS=1', - 'export PSM3_HAL="sockets"', - 'export PSM3_IDENTIFY=1', - 'fi' - ], - mpi=False, - redirect='', - output_capture='', - ) + CommandExecutable( + f"add-psm3-{executable_name}", + template=[ + 'grep "{psm3_mpi}" {env_path}/spack.yaml &> /dev/null', + "if [ $? -eq 0 ]; then", + "spack load {psm3_mpi}", + 'export FI_PROVIDER="psm3"', + "export PSM3_ALLOW_ROUTERS=1", + 'export PSM3_HAL="sockets"', + "export PSM3_IDENTIFY=1", + "fi", + ], + mpi=False, + redirect="", + output_capture="", + ) ) post_cmds.append( - CommandExecutable(f'remove-psm3-{executable_name}', - template=[ - 'grep "{psm3_mpi}" {env_path}/spack.yaml &> /dev/null', - 'if [ $? -eq 0 ]; then', - 'spack unload {psm3_mpi}', - 'unset FI_PROVIDER', - 'unset PSM3_ALLOW_ROUTERS', - 'unset PSM3_HAL', - 'unset PSM3_IDENTIFY', - 'fi' - ], - mpi=False, - redirect='', - output_capture='', - ) + CommandExecutable( + f"remove-psm3-{executable_name}", + template=[ + 'grep "{psm3_mpi}" {env_path}/spack.yaml &> /dev/null', + "if [ $? -eq 0 ]; then", + "spack unload {psm3_mpi}", + "unset FI_PROVIDER", + "unset PSM3_ALLOW_ROUTERS", + "unset PSM3_HAL", + "unset PSM3_IDENTIFY", + "fi", + ], + mpi=False, + redirect="", + output_capture="", + ) ) return pre_cmds, post_cmds - psm3_build_info_regex = r'.*\sPSM3_IDENTIFY PSM3\s+(?Pv[\d.]+)\s+built for\s+(?P.*)$' + psm3_build_info_regex = r".*\sPSM3_IDENTIFY PSM3\s+(?Pv[\d.]+)\s+built for\s+(?P.*)$" figure_of_merit( - 'PSM3 version', + "PSM3 version", fom_regex=psm3_build_info_regex, - group_name='version', - units='', - log_file='{psm3_log_file}', + group_name="version", + units="", + log_file="{psm3_log_file}", ) figure_of_merit( - 'PSM3 build target', + "PSM3 build target", fom_regex=psm3_build_info_regex, - group_name='target', - units='', - log_file='{psm3_log_file}', + group_name="target", + units="", + log_file="{psm3_log_file}", )