PK!4 Everyone is permitted to copy and distribute verbatim or modified copies of this license document, and changing it is allowed as long as the name is changed. DO WHAT THE FUCK YOU WANT TO BUT IT'S NOT MY FAULT PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. You just DO WHAT THE FUCK YOU WANT TO. 1. Do not hold the author(s), creator(s), developer(s) or distributor(s) liable for anything that happens or goes wrong with your use of the work. PK!//(simple_test_default_reporter/__init__.pyfrom .report import report __all__ = [report] PK! S^,simple_test_default_reporter/fns/__init__.pyfrom .assign import assign from .discardWhen import discardWhen from .forEach import forEach from .iif import iif from .isEmpty import isEmpty from .isLaden import isLaden from .joinWith import joinWith from .mAppendAll import mAppendAll from .mAppendAllTo import mAppendAllTo from .mAssign import mAssign from .mSet import mSet from .map_ import map_ from .noop import noop from .passThrough import passThrough from .reduce import reduce from .set_ import set_ __all__ = [ "assign", "discardWhen", "forEach", "iif", "isEmpty", "isLaden", "joinWith", "mAppendAll", "mAppendAllTo", "mAssign", "mSet", "map_", "noop", "passThrough", "reduce", "set_", ] PK!: A*simple_test_default_reporter/fns/assign.py# ------- # # Imports # # ------- # from .internal.getTypedResult import getTypedResult from types import SimpleNamespace from copy import copy # ---- # # Main # # ---- # def assign(collection): fnName = assign.__name__ assignFn = getTypedResult(collection, typeToAssign, fnName) return assignFn(collection) # ------- # # Helpers # # ------- # def assign_simpleNamespace(primary): def assign_simpleNamespace_inner(secondary): result = copy(primary) for k, v in secondary.__dict__.items(): if k not in result.__dict__: setattr(result, k, v) return result return assign_simpleNamespace_inner def assign_dict(primary): def assign_dict_inner(secondary): result = copy(primary) for k, v in secondary.items(): if k not in result: result[k] = v return result return assign_dict_inner typeToAssign = {dict: assign_dict, SimpleNamespace: assign_simpleNamespace} PK!7simple_test_default_reporter/fns/decorators/__init__.pyPK![`)gEE<simple_test_default_reporter/fns/decorators/argIsCallable.pyfrom inspect import signature import wrapt @wrapt.decorator def argIsCallable(fn, _instance, args, kwargs): if not callable(args[0]): argName = list(signature(fn).parameters)[0] fnName = fn.__name__ raise ValueError(f"{fnName} requires {argName} to be callable") return fn(*args, **kwargs) PK!waII9simple_test_default_reporter/fns/decorators/argIsClass.pyfrom inspect import isclass, signature import wrapt @wrapt.decorator def argIsClass(fn, _instance, args, kwargs): if not isclass(args[0]): argName = list(signature(fn).parameters)[0] fnName = fn.__name__ raise ValueError(f"{fnName} requires {argName} to be a class") return fn(*args, **kwargs) PK!dZT<simple_test_default_reporter/fns/decorators/argIsInstance.pyfrom inspect import signature from ..internal.raise_ import raise_ import wrapt def argIsInstance(aType, fnName=None): @wrapt.decorator def wrapper(fn, _instance, args, kwargs): nonlocal fnName if not isinstance(args[0], aType): argName = list(signature(fn).parameters)[0] fnName = fnName or fn.__name__ typePassed = type(args[0]) typeName = aType.__name__ raise_( ValueError, f""" {fnName} requires {argName} to be an instance of {typeName} type passed: {typePassed.__name__} """, ) return fn(*args, **kwargs) return wrapper PK!>simple_test_default_reporter/fns/decorators/argIsListOfType.pyfrom ordered_set import OrderedSet import wrapt from ..internal.discardWhen import discardWhen from ..internal.get import get from ..internal.getArgName import getArgName from ..internal.isLaden import isLaden from ..internal.isType import isType from ..internal.joinWith import joinWith from ..internal.map_ import map_ from ..internal.passThrough import passThrough from ..internal.raise_ import raise_ from ..internal.sort import sort from ..internal.toType import toType def argIsListOfType(aType): @wrapt.decorator def wrapper(fn, _instance, args, kwargs): typePassed = type(args[0]) fnName = fn.__name__ typeName = aType.__name__ if typePassed is not list: argName = getArgName(fn) raise_( ValueError, f"""\ {fnName} requires {argName} to have the type list type passed: {typePassed.__name__} """, ) invalidTypes = discardWhen(isType(aType))(args[0]) if isLaden(invalidTypes): argName = getArgName(fn) invalidTypeNames = passThrough( invalidTypes, [ map_(toType), OrderedSet, list, map_(get("__name__")), sort, joinWith(", "), ], ) raise_( ValueError, f"""\ {fnName} requires {argName} to be a list of {typeName} invalid types passed: {invalidTypeNames} """, ) return fn(*args, **kwargs) return wrapper PK!E8simple_test_default_reporter/fns/decorators/argIsType.pyfrom inspect import signature from ..internal.raise_ import raise_ import wrapt def argIsType(aType): @wrapt.decorator def wrapper(fn, _instance, args, kwargs): typePassed = type(args[0]) if typePassed is not aType: argName = list(signature(fn).parameters)[0] fnName = fn.__name__ typeName = aType.__name__ raise_( ValueError, f""" {fnName} requires {argName} to have the type {typeName} type passed: {typePassed.__name__} """, ) return fn(*args, **kwargs) return wrapper PK!| ;;/simple_test_default_reporter/fns/discardWhen.pyfrom .internal.discardWhen import discardWhen # noqa f401 PK!`c??+simple_test_default_reporter/fns/forEach.py# ------- # # Imports # # ------- # from types import SimpleNamespace from .internal.makeGenericCallFn import makeGenericCallFn from .internal.getTypedResult import getTypedResult from .decorators.argIsCallable import argIsCallable # ---- # # Main # # ---- # @argIsCallable def forEach(fn): fnName = forEach.__name__ callFn = makeGenericCallFn(fn, 3, fnName) def forEach_inner(collection): typedForEach = getTypedResult(collection, typeToForEach, fnName) return typedForEach(callFn, collection) return forEach_inner # ------- # # Helpers # # ------- # def forEach_dict(callFn, aDict): for key, val in aDict.items(): callFn(val, key, aDict) return aDict def forEach_list(callFn, aList): for idx, el in enumerate(aList): callFn(el, idx, aList) return aList def forEach_simpleNamespace(callFn, aSimpleNamespace): forEach_dict(callFn, aSimpleNamespace.__dict__) return aSimpleNamespace typeToForEach = { dict: forEach_dict, list: forEach_list, SimpleNamespace: forEach_simpleNamespace, } PK!R++'simple_test_default_reporter/fns/iif.pyfrom .internal.iif import iif # noqa f401 PK!B u8simple_test_default_reporter/fns/internal/NotCallable.pyfrom types import SimpleNamespace from .mAssignToSelf import mAssignToSelf from .raise_ import raise_ import os class NotCallable(SimpleNamespace): def __init__(self, fnName, **typeToFn): self._fnName = fnName self._typeToFn = typeToFn mAssignToSelf(typeToFn, self) def __call__(self, *args, **kwargs): availableKeys = list(self._typeToFn.keys()) fnName = self._fnName raise_( TypeError, f""" The utility '{fnName}' is not callable because it needs to know what to return in the case of an empty list. example usage: {fnName}.{availableKeys[0]}([...]) available keys: {os.linesep.join(availableKeys)} """, ) PK!5simple_test_default_reporter/fns/internal/__init__.pyPK!F8simple_test_default_reporter/fns/internal/discardWhen.py# ------- # # Imports # # ------- # from .getTypedResult import getTypedResult from .makeGenericCallFn import makeGenericCallFn from ..decorators.argIsCallable import argIsCallable # ---- # # Main # # ---- # @argIsCallable def discardWhen(predicate): fnName = discardWhen.__name__ shouldDiscard = makeGenericCallFn(predicate, 3, fnName) def discardWhen_inner(collection): typedDiscardWhen = getTypedResult(collection, typeToDiscardWhen, fnName) return typedDiscardWhen(shouldDiscard, collection) return discardWhen_inner # ------- # # Helpers # # ------- # def discardWhen_list(shouldDiscard, aList): result = [] for idx, el in enumerate(aList): if not shouldDiscard(el, idx, aList): result.append(el) return result def discardWhen_dict(shouldDiscard, aDict): result = {} for key, val in aDict.items(): if shouldDiscard(val, key, aDict): result[key] = val return result typeToDiscardWhen = {list: discardWhen_list, dict: discardWhen_dict} PK!ss0simple_test_default_reporter/fns/internal/get.pydef get(attrName): def get_inner(something): return getattr(something, attrName) return get_inner PK!)jj7simple_test_default_reporter/fns/internal/getArgName.pyfrom inspect import signature def getArgName(fn, idx=0): return list(signature(fn).parameters)[idx] PK!X;simple_test_default_reporter/fns/internal/getFnSignature.pyfrom inspect import signature from .raise_ import raise_ def getFnSignature(fn, callerName): try: return signature(fn) except Exception as e: raise_( ValueError, f"""\ '{callerName}' is unable to get the signature of the passed callable callable passed: {fn.__name__} one reason this could occur is the callable is written in c (e.g. the builtin 'str' callable). """, fromException=e, ) PK!kCsimple_test_default_reporter/fns/internal/getNumPositionalParams.py# ------- # # Imports # # ------- # from inspect import Parameter from math import inf from .getFnSignature import getFnSignature from .iif import iif # ---- # # Init # # ---- # _nonVarPositionalParamKinds = { Parameter.POSITIONAL_ONLY, Parameter.POSITIONAL_OR_KEYWORD, } # ---- # # Main # # ---- # # # Returns a tuple # numRequired: number of required positional params # numAllowed: number of allowed positional params # def getNumPositionalParams(fn, callerName): sig = getFnSignature(fn, callerName) numAllowed = iif(_hasVarPositionalParam(sig), inf, 0) numRequired = 0 for p in sig.parameters.values(): if p.kind in _nonVarPositionalParamKinds: numAllowed += 1 if p.default is Parameter.empty: numRequired += 1 return (numRequired, numAllowed) # ------- # # Helpers # # ------- # def _hasVarPositionalParam(sig): for p in sig.parameters.values(): if p.kind is Parameter.VAR_POSITIONAL: return True PK!w<;simple_test_default_reporter/fns/internal/getTypedResult.py# # README # - I'm not sure what to call this. Its purpose is to centralize the type # validation, minimizing copy/paste. # # ------- # # Imports # # ------- # from .raise_ import raise_ from .get import get # ---- # # Init # # ---- # getName = get("__name__") # # we need a unique object here to ensure the 'typeToSomething' doesn't lead us # to a 'None' value # nothing = object() # ---- # # Main # # ---- # def getTypedResult(value, typeToSomething, fnName): valueType = type(value) result = typeToSomething.get(valueType, nothing) if _isSomething(result): return result supportedTypes = ", ".join(map(getName, typeToSomething.keys())) raise_( ValueError, f"""\ {fnName} doesn't support the type '{valueType.__name__}' supported types: {supportedTypes} """, ) # ------- # # Helpers # # ------- # def _isSomething(x): return x is not nothing PK!;||0simple_test_default_reporter/fns/internal/iif.pydef iif(condition, whenTruthy, whenFalsey): if condition: return whenTruthy else: return whenFalsey PK!ws{334simple_test_default_reporter/fns/internal/isLaden.pydef isLaden(aList): return len(aList) is not 0 PK!Ȋ=simple_test_default_reporter/fns/internal/isOnlyWhitespace.pyimport re onlyWhitespaceRe = re.compile(r"\s*$") def isOnlyWhitespace(aString): return onlyWhitespaceRe.match(aString) is not None PK!f3simple_test_default_reporter/fns/internal/isType.pyfrom inspect import isclass def isType(aType): if not isclass(aType): raise ValueError("isType requires argument 'aType' to pass isclass") def isType_inner(something): return type(something) is aType return isType_inner PK!v_R*++5simple_test_default_reporter/fns/internal/joinWith.py# ------- # # Imports # # ------- # from ordered_set import OrderedSet from .getTypedResult import getTypedResult # ---- # # Main # # ---- # def joinWith(separator): def joinWith_inner(collection): typedJoinWith = getTypedResult(collection, typeToJoinWith, "joinWith") return typedJoinWith(separator, collection) return joinWith_inner # ------- # # Helpers # # ------- # def joinWith_iterable(separator, aList): return separator.join(aList) typeToJoinWith = {list: joinWith_iterable, OrderedSet: joinWith_iterable} PK!K:simple_test_default_reporter/fns/internal/mAssignToSelf.py# # assigns dict key-values onto self as attributes # return secondaryObj # ** mutates secondaryObj # def mAssignToSelf(aDict, aSelf): for k, v in aDict.items(): setattr(aSelf, k, v) return aSelf PK!K7simple_test_default_reporter/fns/internal/makeCallFn.py# ------- # # Imports # # ------- # from math import inf from .returnFirstArgument import returnFirstArgument as identity from .getNumPositionalParams import getNumPositionalParams # ---- # # Main # # ---- # def makeCallFn(fn, callerName, *, modifyResult=identity): (_, allowed) = getNumPositionalParams(fn, callerName) if allowed is inf: return lambda *args, **kwargs: modifyResult(fn(*args, **kwargs)) else: return lambda *args, **kwargs: modifyResult( fn(*args[:allowed], **kwargs) ) PK!T->simple_test_default_reporter/fns/internal/makeGenericCallFn.py# ------- # # Imports # # ------- # from math import inf from .getNumPositionalParams import getNumPositionalParams from .raise_ import raise_ # ---- # # Main # # ---- # def makeGenericCallFn(fn, maxParams, callerName): required, allowed = getNumPositionalParams(fn, callerName) if allowed is inf: allowed = maxParams if required > maxParams: raise_( ValueError, f""" {callerName} can only take functions with up to {maxParams} positional params. The function '{fn.__name__}' requires {required} """, ) return lambda *args, **kwargs: fn(*args[:allowed], **kwargs) PK!G~1simple_test_default_reporter/fns/internal/map_.py# ------- # # Imports # # ------- # from .makeGenericCallFn import makeGenericCallFn from .getTypedResult import getTypedResult from ..decorators.argIsCallable import argIsCallable # ---- # # Main # # ---- # @argIsCallable def map_(mapperFn): fnName = map_.__name__ callMapperFn = makeGenericCallFn(mapperFn, 3, fnName) def map_inner(collection): typedMap = getTypedResult(collection, typeToMap, fnName) return typedMap(callMapperFn, collection) return map_inner # ------- # # Helpers # # ------- # def map_list(callMapperFn, aList): result = [] for idx, el in enumerate(aList): result.append(callMapperFn(el, idx, aList)) return result typeToMap = {list: map_list} PK!yy8simple_test_default_reporter/fns/internal/passThrough.pyfrom .reduce import reduce def passThrough(arg, fnList): return reduce(lambda result, fn: fn(result), arg)(fnList) PK!W3simple_test_default_reporter/fns/internal/raise_.pyfrom tedent import tedent from .isOnlyWhitespace import isOnlyWhitespace import os def raise_(errorClass, message, *, fromException=None): allLines = message.split(os.linesep) if isOnlyWhitespace(allLines[0]) and isOnlyWhitespace(allLines[-1]): message = tedent(message) err = errorClass(message) if fromException is None: raise err else: raise err from fromException PK!Et3simple_test_default_reporter/fns/internal/reduce.py# ------- # # Imports # # ------- # from .makeGenericCallFn import makeGenericCallFn from .getTypedResult import getTypedResult from ..decorators.argIsCallable import argIsCallable # ---- # # Main # # ---- # @argIsCallable def reduce(fn, initial): reducerFn = makeGenericCallFn(fn, 4, "reduce") def reduce_inner(collection): typedReduce = getTypedResult(collection, typeToReduce, "reduce") return typedReduce(reducerFn, initial, collection) return reduce_inner # ------- # # Helpers # # ------- # def reduce_list(reducerFn, initial, aList): result = initial for idx, el in enumerate(aList): result = reducerFn(result, el, idx, aList) return result typeToReduce = {list: reduce_list} PK!pjj@simple_test_default_reporter/fns/internal/returnFirstArgument.pyfrom .iif import iif def returnFirstArgument(*args, **kwargs): return iif(len(args), args[0], None) PK!\xx<simple_test_default_reporter/fns/internal/sanitizeAscDesc.pyfrom .raise_ import raise_ ascDescSet = {"asc", "desc"} def sanitizeAscDesc(ascOrDesc): sanitized = ascOrDesc.lower() if sanitized not in ascDescSet: raise_( ValueError, f""" ascOrDesc must be either 'asc' or 'desc' (case insensitive) value given: {ascOrDesc} """, ) return sanitized PK!0oo1simple_test_default_reporter/fns/internal/sort.py# ------- # # Imports # # ------- # from .getTypedResult import getTypedResult # ---- # # Main # # ---- # def sort(collection): typedSort = getTypedResult(collection, typeToSort, "sort") return typedSort(collection) # ------- # # Helpers # # ------- # def sort_viaSorted(something): return sorted(something) typeToSort = {list: sort_viaSorted} PK!V;223simple_test_default_reporter/fns/internal/toType.pydef toType(something): return type(something) PK!¢[+simple_test_default_reporter/fns/isEmpty.pyfrom types import SimpleNamespace # TODO: make 'isEmpty' generic like the other utils def isEmpty(lenAble): if isinstance(lenAble, SimpleNamespace): return len(lenAble.__dict__) is 0 else: return len(lenAble) is 0 PK!X33+simple_test_default_reporter/fns/isLaden.pyfrom .internal.isLaden import isLaden # noqa f401 PK!955,simple_test_default_reporter/fns/joinWith.pyfrom .internal.joinWith import joinWith # noqa f401 PK!x::.simple_test_default_reporter/fns/mAppendAll.py# ------- # # Imports # # ------- # from .internal.getTypedResult import getTypedResult # ---- # # Main # # ---- # def mAppendAll(collectionToAppend): def mAppendAll_inner(collection): typedMAppendAll = getTypedResult( collection, typeToMAppendAll, mAppendAll.__name__ ) return typedMAppendAll(collectionToAppend, collection) return mAppendAll_inner # ------- # # Helpers # # ------- # def mAppendAll_list(listToAppend, aList): aList += listToAppend return aList typeToMAppendAll = {list: mAppendAll_list} PK!@\0simple_test_default_reporter/fns/mAppendAllTo.py# ------- # # Imports # # ------- # from .internal.getTypedResult import getTypedResult from .mAppendAll import typeToMAppendAll # ---- # # Main # # ---- # def mAppendAllTo(collection): def mAppendAllTo_inner(collectionToAppend): typedMAppendAllTo = getTypedResult( collection, typeToMAppendAll, mAppendAllTo.__name__ ) return typedMAppendAllTo(collectionToAppend, collection) return mAppendAllTo_inner PK!86XX+simple_test_default_reporter/fns/mAssign.py# ------- # # Imports # # ------- # from .internal.getTypedResult import getTypedResult from types import SimpleNamespace # ---- # # Main # # ---- # def mAssign(collection): fnName = mAssign.__name__ assignFn = getTypedResult(collection, typeToAssign, fnName) return assignFn(collection) # ------- # # Helpers # # ------- # def mAssign_simpleNamespace(primary): def mAssign_simpleNamespace_inner(secondary): for k, v in primary.__dict__.items(): setattr(secondary, k, v) return secondary return mAssign_simpleNamespace_inner def mAssign_dict(primary): def mAssign_dict_inner(secondary): for k, v in primary.items(): secondary[k] = v return secondary return mAssign_dict_inner typeToAssign = {dict: mAssign_dict, SimpleNamespace: mAssign_simpleNamespace} PK!a||(simple_test_default_reporter/fns/mSet.pydef mSet(name, value): def mSet_inner(obj): setattr(obj, name, value) return obj return mSet_inner PK!}--(simple_test_default_reporter/fns/map_.pyfrom .internal.map_ import map_ # noqa f401 PK!!$$(simple_test_default_reporter/fns/noop.pydef noop(*args, **kwargs): pass PK!F;;/simple_test_default_reporter/fns/passThrough.pyfrom .internal.passThrough import passThrough # noqa f401 PK!^{11*simple_test_default_reporter/fns/reduce.pyfrom .internal.reduce import reduce # noqa f401 PK!8,(simple_test_default_reporter/fns/set_.pyfrom copy import copy def set_(name, value): def set_inner(obj): result = copy(obj) setattr(result, name, value) return result return set_inner PK! \00/simple_test_default_reporter/report/__init__.pyfrom .index import report __all__ = ["report"] PK!3_4simple_test_default_reporter/report/explainErrors.py# ------- # # Imports # # ------- # from copy import copy from ..fns import discardWhen, joinWith, map_, mAppendAllTo, passThrough, reduce import os # ---- # # Init # # ---- # border = "-" * 20 twoLineSeps = os.linesep + os.linesep separator = twoLineSeps + border + twoLineSeps # ---- # # Main # # ---- # def explainErrors(state): rootTestsCopy = passThrough(state.tests, [discardWhen(didSucceed), copy]) flatTests = passThrough( state.suites, [discardWhen(didSucceed), reduce(flattenTests, rootTestsCopy)], ) return passThrough( flatTests, [map_(toExplanation), joinWith(separator), wrapInBorder] ) # ------- # # Helpers # # ------- # def toExplanation(aTest): explanation = [] if aTest.parentSuite: explanation.append("suite: " + aTest.parentSuite.label) explanation.append("test: " + aTest.label) explanation.append("") explanation.append(str(aTest.error).strip()) return os.linesep.join(explanation) def flattenTests(result, aSuite): if hasattr(aSuite, "suites"): result = reduce(flattenTests, result)(aSuite.suites) return passThrough( aSuite.tests, [discardWhen(didSucceed), mAppendAllTo(result)] ) def didSucceed(testOrSuite): return testOrSuite.succeeded def wrapInBorder(content): return ( twoLineSeps + border + twoLineSeps + content + twoLineSeps + border + os.linesep ) PK!~C:LL,simple_test_default_reporter/report/index.py# ------- # # Imports # # ------- # from . import minimal from ..fns import forEach, isLaden from .explainErrors import explainErrors from .initRootState import initRootState # ---- # # Main # # ---- # def report(state, *, showErrorDetails=True): state = initRootState(state) rootTests = state.tests rootSuites = state.suites forEach(minimal.reportTest)(rootTests) if isLaden(rootTests) and isLaden(rootSuites): print() forEach(minimal.reportSuite)(rootSuites) if showErrorDetails and not state.succeeded: print(explainErrors(state)) PK!4>>=simple_test_default_reporter/report/initRootState/__init__.pyfrom .index import initRootState __all__ = ["initRootState"] PK!wEi4Fsimple_test_default_reporter/report/initRootState/applyIndentLevels.py# ------- # # Imports # # ------- # from types import SimpleNamespace as o from ...fns import assign, map_, mAssign, mSet # ---- # # Main # # ---- # def applyIndentLevels(state): rootTests = map_(addIndentLevelToTest(0))(state.tests) rootSuites = map_(addIndentLevelToSuite(0))(state.suites) return assign(o(tests=rootTests, suites=rootSuites))(state) # ------- # # Helpers # # ------- # def addIndentLevelToTest(lvl): def applyIndentLevel_inner(aTest): return mSet("indentLevel", lvl)(aTest) return applyIndentLevel_inner def addIndentLevelToSuite(lvl): def addIndentLevelToSuite_inner(aSuite): indentLevel = lvl tests = map_(addIndentLevelToTest(lvl + 1))(aSuite.tests) suites = map_(addIndentLevelToSuite(lvl + 1))(aSuite.suites) return mAssign(o(indentLevel=indentLevel, tests=tests, suites=suites))( aSuite ) return addIndentLevelToSuite_inner PK!}b++:simple_test_default_reporter/report/initRootState/index.py# ------- # # Imports # # ------- # from ...fns import passThrough from .applyIndentLevels import applyIndentLevels from .removeSucceededTestsInSuites import removeSucceededTestsInSuites # ---- # # Main # # ---- # def initRootState(state): return passThrough( state, [ removeSucceededTestsInSuites, applyIndentLevels, initializeHasBlankLineAfter, initializeParentState, ], ) # ------- # # Helpers # # ------- # def initializeHasBlankLineAfter(state): for suite in state.suites: suite.hasBlankLineAfter = False return state def initializeParentState(state): for suite in state.suites: suite.parentState = state for test in state.tests: test.parentState = state return state PK! RRQsimple_test_default_reporter/report/initRootState/removeSucceededTestsInSuites.py# ------- # # Imports # # ------- # from types import SimpleNamespace as o from ...fns import mAssign, discardWhen, map_, set_ # ---- # # Main # # ---- # def removeSucceededTestsInSuites(state): rootSuites = map_(removeSucceededTests)(state.suites) return set_("suites", rootSuites)(state) # ------- # # Helpers # # ------- # def isSucceeded(aTest): return aTest.succeeded def removeSucceededTests(aSuite): tests = discardWhen(isSucceeded)(aSuite.tests) suites = map_(removeSucceededTests)(aSuite.suites) return mAssign(o(tests=tests, suites=suites))(aSuite) PK! .simple_test_default_reporter/report/minimal.py# ------- # # Imports # # ------- # from ..fns import forEach from .utils import o, x # ---- # # Main # # ---- # def reportTest(aTest, idx, tests): indent = " " * 4 * aTest.indentLevel if aTest.succeeded: print(f"{indent}{aTest.label} {o}") else: print(f"{indent}{aTest.label} {x}") if ( aTest.parentSuite and isLast(idx, tests) and not isFinalSuite(aTest.parentSuite) ): propagateBlankLineAfter(aTest.parentSuite) print() def reportSuite(aSuite, idx, suites): if ( aSuite.parentSuite is None and idx != 0 and not suites[idx - 1].hasBlankLineAfter ): print() indent = " " * 4 * aSuite.indentLevel if aSuite.succeeded: print(f"{indent}{aSuite.label} {o}") # we only want to report failing tests, and if a suite succeeded then # it doesn't contain any failing tests forEach(reportSuite)(aSuite.suites) else: print(f"{indent}{aSuite.label} {x}") forEach(reportTest)(aSuite.tests) forEach(reportSuite)(aSuite.suites) # ------- # # Helpers # # ------- # # # TODO: initialize this state separate from the reporting logic similar to # applyIndentLevels. That way the reporter can just check the properties on # the state instead of modifying it mid-run. # # this method is necessary due to two formatting preferences # 1. root suites should be separated by one blank line # 2. there should be a blank line between a test and the following suite # # these two preferences conflict when a blank line follows a failed test where # the following suite is a root suite. By propagating the "hasBlankLineAfter" # state we can check that on root suites to prevent two blank lines. # def propagateBlankLineAfter(aSuite): if not aSuite.parentSuite: aSuite.hasBlankLineAfter = True return if isLastSiblingSuite(aSuite): propagateBlankLineAfter(aSuite.parentSuite) def isLastSiblingSuite(suite): parentSuite = suite.parentSuite if parentSuite: siblingSuites = parentSuite.suites else: siblingSuites = suite.parentState.suites indexOfSuite = siblingSuites.index(suite) return isLast(indexOfSuite, siblingSuites) def isLast(idx, collection): return idx == len(collection) - 1 def isFinalSuite(aSuite): if not aSuite.parentSuite: return isLastSiblingSuite(aSuite) elif isLastSiblingSuite(aSuite): return isFinalSuite(aSuite.parentSuite) PK!4 EE,simple_test_default_reporter/report/utils.pyfrom simple_chalk import green, red x = red("✘") o = green("✔") PK!HڽTU2simple_test_default_reporter-0.2.0.dist-info/WHEEL A н#Z;/"d&F[xzw@Zpy3Fv]\fi4WZ^EgM_-]#0(q7PK!HҴ5simple_test_default_reporter-0.2.0.dist-info/METADATAAo1s)&-RUA"Uhc.) H-{oٶ)Sj83+kC͘YX'!1&_3T65'aB:'5:xĤgq_>&*8aC Y4oU>nzrz9j\ q2Gυf}3 )x~n.Ϥ9SG8pH{áH~|~67?ܯ(s !gdx2YAʝ=LҬrq9o0c?b?adL #Z3"Ecna'!+M2>zlv8•CRoHA >!P|c:Z ]3뒒FnAKKfaaJ=yVI0$ItI !~ɇ ]> )}U0Mm5rME64{Pv~B_!\KdX$4WZE5+H{e!g}ߛ{CPX>{QF_l <0 8@"D- k&>,k򤵊%B>][׃-jEQHǪOr){aA +!!3mW_Etqhtbڲt64 vgAGcߌ ~~HB,"Xit=4FL5=a7@zY}X獂xb$k1 An@(_j#0;kV=o;B"%wP0*Ebo> ͒WQúc-dN=EX);*ܯ|) @U({!sm)s0;K)_([<,"95pb+c_!dH7^3`Ƅv7=]Q'"mdM,]2!f՗E$?|ͳT7{ ]zw/XiφԞ}  'r }'t$e#r2fLQƁPj_<('#‚A$n&/Ԥͯ&@7Fk=pD@ 'Q'5`MUۢs~Pٛ-.H/smW>Oܳ'[Cigb纋Xx2+|7dl M矈 >y--%\9jK2OAp$V2R6E%/2RB.q9 F_e\&8ObrxM|.c4"qssv^@+/LJW';_nKL>>zj'"1U/TP(kęՔClEɀ}RRt[-]Iβ.0)cMS}XfpID۵ KsVHCݺZMӎb LlK?`<)n*fH4{Fk^9霙h6Hɋ5+ԍ*LLOI$Eb +R4yEeI*:vh{#;oR͵m\U@pQO7X֪_ɋ4s.Aяָ _ ^8pӽs?^o`8YTn{9XN]SԹT)5=z~8b7R[?ۤӵ]lh$b/1xbe;1YNE f*G%42%5k$~ˍ5^B"QI;rn"Zϳ27FNjۛk2^L+)eyE~<(}ثMqC)[.gap+ϺڽJ]6BQv -ΛDQhQOW@ZTB]'H[+simple_test_default_reporter/fns/decorators/argIsListOfType.pyPK!E8simple_test_default_reporter/fns/decorators/argIsType.pyPK!| ;;/simple_test_default_reporter/fns/discardWhen.pyPK!`c??+simple_test_default_reporter/fns/forEach.pyPK!R++' simple_test_default_reporter/fns/iif.pyPK!B u8 simple_test_default_reporter/fns/internal/NotCallable.pyPK!5#simple_test_default_reporter/fns/internal/__init__.pyPK!F8=$simple_test_default_reporter/fns/internal/discardWhen.pyPK!ss0(simple_test_default_reporter/fns/internal/get.pyPK!)jj7p)simple_test_default_reporter/fns/internal/getArgName.pyPK!X;/*simple_test_default_reporter/fns/internal/getFnSignature.pyPK!kC,simple_test_default_reporter/fns/internal/getNumPositionalParams.pyPK!w<;0simple_test_default_reporter/fns/internal/getTypedResult.pyPK!;||04simple_test_default_reporter/fns/internal/iif.pyPK!ws{3345simple_test_default_reporter/fns/internal/isLaden.pyPK!Ȋ=F6simple_test_default_reporter/fns/internal/isOnlyWhitespace.pyPK!f3+7simple_test_default_reporter/fns/internal/isType.pyPK!v_R*++5x8simple_test_default_reporter/fns/internal/joinWith.pyPK!K::simple_test_default_reporter/fns/internal/mAssignToSelf.pyPK!K7'<simple_test_default_reporter/fns/internal/makeCallFn.pyPK!T->>simple_test_default_reporter/fns/internal/makeGenericCallFn.pyPK!G~1Asimple_test_default_reporter/fns/internal/map_.pyPK!yy8Dsimple_test_default_reporter/fns/internal/passThrough.pyPK!W3Esimple_test_default_reporter/fns/internal/raise_.pyPK!Et3Gsimple_test_default_reporter/fns/internal/reduce.pyPK!pjj@Jsimple_test_default_reporter/fns/internal/returnFirstArgument.pyPK!\xx<Ksimple_test_default_reporter/fns/internal/sanitizeAscDesc.pyPK!0oo1VMsimple_test_default_reporter/fns/internal/sort.pyPK!V;223Osimple_test_default_reporter/fns/internal/toType.pyPK!¢[+Osimple_test_default_reporter/fns/isEmpty.pyPK!X33+Psimple_test_default_reporter/fns/isLaden.pyPK!955,NQsimple_test_default_reporter/fns/joinWith.pyPK!x::.Qsimple_test_default_reporter/fns/mAppendAll.pyPK!@\0STsimple_test_default_reporter/fns/mAppendAllTo.pyPK!86XX+fVsimple_test_default_reporter/fns/mAssign.pyPK!a||(Zsimple_test_default_reporter/fns/mSet.pyPK!}--(Zsimple_test_default_reporter/fns/map_.pyPK!!$$(<[simple_test_default_reporter/fns/noop.pyPK!F;;/[simple_test_default_reporter/fns/passThrough.pyPK!^{11*.\simple_test_default_reporter/fns/reduce.pyPK!8,(\simple_test_default_reporter/fns/set_.pyPK! \00/]simple_test_default_reporter/report/__init__.pyPK!3_4^simple_test_default_reporter/report/explainErrors.pyPK!~C:LL,5dsimple_test_default_reporter/report/index.pyPK!4>>=fsimple_test_default_reporter/report/initRootState/__init__.pyPK!wEi4Fdgsimple_test_default_reporter/report/initRootState/applyIndentLevels.pyPK!}b++:~ksimple_test_default_reporter/report/initRootState/index.pyPK! RRQosimple_test_default_reporter/report/initRootState/removeSucceededTestsInSuites.pyPK! .qsimple_test_default_reporter/report/minimal.pyPK!4 EE,{simple_test_default_reporter/report/utils.pyPK!HڽTU2|simple_test_default_reporter-0.2.0.dist-info/WHEELPK!HҴ5%}simple_test_default_reporter-0.2.0.dist-info/METADATAPK!H?u$ @3simple_test_default_reporter-0.2.0.dist-info/RECORDPK==K