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!po/__init__.pyPK!MMpo/simple_test/__init__.pyfrom .run import run from .meta import version __all__ = ["run", "version"] PK!Mf(>>po/simple_test/cli/__init__.pyfrom .index import runSimpleTest __all__ = ["runSimpleTest"] PK!Hyypo/simple_test/cli/index.py# ------- # # Imports # # ------- # from traceback import format_exc from types import SimpleNamespace as o from ..meta import version from .usage import usage from .validateAndParseArgs import validateAndParseArgs import os # ---- # # Main # # ---- # def createRunSimpleTest(run): return lambda args: runSimpleTest(run, args) def runSimpleTest(run, args): result = o(stdout=None, stderr=None, code=None) numArgs = len(args) if numArgs == 1: if args[0] == "--help": result.stdout = usage result.code = 0 return result elif args[0] == "--version": result.stdout = version result.code = 0 return result validationResult = validateAndParseArgs(args, result) if validationResult.hasError: return validationResult.cliResult argsObj = validationResult.argsObj isSilent = argsObj.silent try: subprocessReturnCode = run( grepArgs=argsObj.grepArgs, reporter=argsObj.reporter, projectDir=argsObj.projectDir, silent=isSilent, ) result.code = subprocessReturnCode return result except: if not isSilent: result.stderr = ( "An unexpected error occurred" + (os.linesep * 2) + format_exc() ) result.code = 2 return result PK!8gKKpo/simple_test/cli/usage.pyfrom textwrap import dedent # # the 'grep' options are parsed in simple-test-process, but for sake of # usage formatting I'm placing their usage here. This causes a potential # issue where the simple-test-process and this usage are out of sync, # but whatever. # usage = dedent( f""" Usage simple-test [options] simple-test (--help | --version) Options --project-dir the project dir from which tests are found. Defaults to `os.getcwd()` --silent a flag which disables output and prevents the reporter from being called. --reporter module name with a 'report' function. The default reporter is 'simple_test_default_reporter'. Relative modules e.g. "..myModule" are not yet supported. --grep filter which tests *and* suites are run --grep-tests filter just the tests --grep-suites filter just the suites Returns an exit code of 0 for a successful run 1 for a failed run 2 for an error """ ) PK!{eXr r *po/simple_test/cli/validateAndParseArgs.py# ------- # # Imports # # ------- # from case_conversion import camelcase from copy import deepcopy from simple_test_process.parseArgs import _grepArgs, _grepArgsKeys from types import SimpleNamespace as o from ..fns import isLaden from .usage import usage import os # ---- # # Init # # ---- # arguments = set(["--project-dir", "--reporter", "--silent", *_grepArgsKeys]) helpOrVersion = set(["--help", "--version"]) # ---- # # Main # # ---- # def validateAndParseArgs(args, cliResult): argsObj = o( reporter=None, projectDir=None, silent=False, grepArgs=deepcopy(_grepArgs), ) validationResult = o( argsObj=argsObj, cliResult=cliResult, hasError=False, positionalArgs=[] ) i = 0 while i < len(args): if not args[i].startswith("--"): break arg = args[i] if arg not in arguments: if not argsObj.silent: if arg in helpOrVersion: cliResult.stderr = ( f"'{arg}' must be the only argument when passed" ) else: cliResult.stderr = f"invalid option '{arg}'" cliResult.stderr += os.linesep + usage cliResult.code = 2 validationResult.hasError = True return validationResult if arg == "--silent": argsObj.silent = True elif arg == "--reporter": if i == len(args) - 1: if not argsObj.silent: cliResult.stderr = "'--reporter' must be given a value" cliResult.stderr += os.linesep + usage cliResult.code = 2 validationResult.hasError = True return validationResult i += 1 arg = args[i] argsObj.reporter = arg elif arg == "--project-dir": i += 1 if i == len(args): if not argsObj.silent: cliResult.stderr = "'--project-dir' must be given a value" cliResult.stderr += os.linesep + usage cliResult.code = 2 validationResult.hasError = True return validationResult arg = args[i] argsObj.projectDir = arg else: # arg in _grepArgsKeys i += 1 if i == len(args): if not argsObj.silent: cliResult.stderr = f"{arg} must be given a value" cliResult.stderr += os.linesep + usage cliResult.code = 2 validationResult.hasError = True return validationResult grepVals = getattr(argsObj.grepArgs, camelcase(arg)) grepVals.append(args[i]) i += 1 positionalArgs = args[i:] if isLaden(positionalArgs): if not argsObj.silent: cliResult.stderr = "this command doesn't take positional arguments" cliResult.stderr += os.linesep + usage cliResult.code = 2 validationResult.hasError = True return validationResult return validationResult PK!z6Ypo/simple_test/fns/__init__.pyfrom .all_ import all_ from .flattenDeep import flattenDeep from .forEach import forEach from .getListOfCollectionValues import getListOfCollectionValues from .invokeAttr import invokeAttr from .isEmpty import isEmpty from .isLaden import isLaden from .isSomething import isSomething from .joinWith import joinWith from .justReturn import justReturn from .keepWhen import keepWhen from .map_ import map_ from .passThrough import passThrough from .raise_ import raise_ __all__ = [ "all_", "flattenDeep", "forEach", "getListOfCollectionValues", "invokeAttr", "isEmpty", "isLaden", "isSomething", "joinWith", "justReturn", "keepWhen", "map_", "passThrough", "raise_", ] PK!]po/simple_test/fns/all_.py# ------- # # Imports # # ------- # from types import SimpleNamespace from .internal.makeGenericCallFn import makeGenericCallFn from .internal.getTypedResult import getTypedResult from .decorators.argIsCallable import argIsCallable # ---- # # Main # # ---- # @argIsCallable def all_(predicate): fnName = all.__name__ callPredicate = makeGenericCallFn(predicate, 3, fnName) def all_inner(collection): typedAll = getTypedResult(collection, typeToAll, fnName) return typedAll(callPredicate, collection) return all_inner # ------- # # Helpers # # ------- # def all_list(callPredicate, aList): for idx, el in enumerate(aList): if not callPredicate(el, idx, aList): return False return True def all_simpleNamespace(callPredicate, aSimpleNamespace): for key, val in aSimpleNamespace.__dict__.items(): if not callPredicate(val, key, aSimpleNamespace): return False return True typeToAll = {list: all_list, SimpleNamespace: all_simpleNamespace} PK!)po/simple_test/fns/decorators/__init__.pyPK![`)gEE.po/simple_test/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!waII+po/simple_test/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.po/simple_test/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!0po/simple_test/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!E*po/simple_test/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!b!po/simple_test/fns/flattenDeep.py# ------- # # Imports # # ------- # from .internal.getTypedResult import getTypedResult # ---- # # Main # # ---- # def flattenDeep(collection): fnName = flattenDeep.__name__ typedFlattenDeep = getTypedResult(collection, typeToFlattenDeep, fnName) return typedFlattenDeep(collection) # ------- # # Helpers # # ------- # def flattenDeep_list(aList): result = [] def flattenDeep_recursive(aList): for maybeInnerList in aList: if isinstance(maybeInnerList, list): flattenDeep_recursive(maybeInnerList) else: result.append(maybeInnerList) flattenDeep_recursive(aList) return result typeToFlattenDeep = {list: flattenDeep_list} PK!`c??po/simple_test/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!ȇ#/po/simple_test/fns/getListOfCollectionValues.py# ------- # # Imports # # ------- # from types import SimpleNamespace from .internal.getTypedResult import getTypedResult # ---- # # Main # # ---- # def getListOfCollectionValues(collection): fnName = getListOfCollectionValues.__name__ typedValues = getTypedResult(collection, typeToValues, fnName) return typedValues(collection) # ------- # # Helpers # # ------- # def getListOfCollectionValues_dict(aDict): return list(aDict.values()) def getListOfCollectionValues_simpleNamespace(aSimpleNamespace): return list(aSimpleNamespace.__dict__.values()) typeToValues = { dict: getListOfCollectionValues_dict, SimpleNamespace: getListOfCollectionValues_simpleNamespace, } PK!B u*po/simple_test/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!'po/simple_test/fns/internal/__init__.pyPK!F*po/simple_test/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!ss"po/simple_test/fns/internal/get.pydef get(attrName): def get_inner(something): return getattr(something, attrName) return get_inner PK!)jj)po/simple_test/fns/internal/getArgName.pyfrom inspect import signature def getArgName(fn, idx=0): return list(signature(fn).parameters)[idx] PK!X-po/simple_test/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!k5po/simple_test/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<-po/simple_test/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!;||"po/simple_test/fns/internal/iif.pydef iif(condition, whenTruthy, whenFalsey): if condition: return whenTruthy else: return whenFalsey PK!ws{33&po/simple_test/fns/internal/isLaden.pydef isLaden(aList): return len(aList) is not 0 PK!Ȋ/po/simple_test/fns/internal/isOnlyWhitespace.pyimport re onlyWhitespaceRe = re.compile(r"\s*$") def isOnlyWhitespace(aString): return onlyWhitespaceRe.match(aString) is not None PK!f%po/simple_test/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*++'po/simple_test/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,po/simple_test/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!K)po/simple_test/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-0po/simple_test/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!mC#po/simple_test/fns/internal/map_.py# ------- # # Imports # # ------- # from types import SimpleNamespace 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 def map_simpleNamespace(callMapperFn, aSimpleNamespace): result = SimpleNamespace() for key, val in aSimpleNamespace.__dict__.items(): setattr(result, key, callMapperFn(val, key, aSimpleNamespace)) return result typeToMap = {list: map_list, SimpleNamespace: map_simpleNamespace} PK!yy*po/simple_test/fns/internal/passThrough.pyfrom .reduce import reduce def passThrough(arg, fnList): return reduce(lambda result, fn: fn(result), arg)(fnList) PK!W%po/simple_test/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!Et%po/simple_test/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!pjj2po/simple_test/fns/internal/returnFirstArgument.pyfrom .iif import iif def returnFirstArgument(*args, **kwargs): return iif(len(args), args[0], None) PK!\xx.po/simple_test/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!0oo#po/simple_test/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;22%po/simple_test/fns/internal/toType.pydef toType(something): return type(something) PK!%tt po/simple_test/fns/invokeAttr.pydef invokeAttr(key): def invokeAttr_inner(obj): return getattr(obj, key)() return invokeAttr_inner PK!¢[po/simple_test/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!X33po/simple_test/fns/isLaden.pyfrom .internal.isLaden import isLaden # noqa f401 PK!P1--!po/simple_test/fns/isSomething.pydef isSomething(x): return x is not None PK!955po/simple_test/fns/joinWith.pyfrom .internal.joinWith import joinWith # noqa f401 PK!< HH po/simple_test/fns/justReturn.pydef justReturn(something): return lambda *args, **kwargs: something PK!*xNOOpo/simple_test/fns/keepWhen.py# ------- # # Imports # # ------- # from types import SimpleNamespace from .internal.makeGenericCallFn import makeGenericCallFn from .internal.getTypedResult import getTypedResult from .decorators.argIsCallable import argIsCallable # ---- # # Main # # ---- # @argIsCallable def keepWhen(predicate): fnName = keepWhen.__name__ shouldKeep = makeGenericCallFn(predicate, 3, fnName) def keepWhen_inner(collection): typedKeepWhen = getTypedResult(collection, typeToKeepWhen, fnName) return typedKeepWhen(shouldKeep, collection) return keepWhen_inner # ------- # # Helpers # # ------- # def keepWhen_list(shouldKeep, aList): result = [] for idx, el in enumerate(aList): if shouldKeep(el, idx, aList): result.append(el) return result def keepWhen_dict(shouldKeep, aDict): result = {} for key, val in aDict.items(): if shouldKeep(val, key, aDict): result[key] = val return result def keepWhen_simpleNamespace(shouldKeep, aSimpleNamespace): result = SimpleNamespace() for key, val in aSimpleNamespace.__dict__.items(): if shouldKeep(val, key, aSimpleNamespace): setattr(result, key, val) return result typeToKeepWhen = { list: keepWhen_list, dict: keepWhen_dict, SimpleNamespace: keepWhen_simpleNamespace, } PK!}--po/simple_test/fns/map_.pyfrom .internal.map_ import map_ # noqa f401 PK!F;;!po/simple_test/fns/passThrough.pyfrom .internal.passThrough import passThrough # noqa f401 PK!(11po/simple_test/fns/raise_.pyfrom .internal.raise_ import raise_ # noqa f401 PK!po/simple_test/meta.pyversion = "0.1.0" PK!tcaapo/simple_test/run/__init__.pyfrom .run import createRun import subprocess run = createRun(subprocess.run) __all__ = ["run"] PK!po/simple_test/run/run.py# ------- # # Imports # # ------- # from case_conversion import dashcase from copy import deepcopy from os import path from simple_test_process.parseArgs import _grepArgs from .validateRunParams import validateRunParams import os import sys from ..fns import ( flattenDeep, getListOfCollectionValues, isLaden, keepWhen, map_, passThrough, raise_, ) # ---- # # Main # # ---- # def createRun(subprocessRun): return lambda **kwargs: run(subprocessRun, **kwargs) def run( subprocessRun, *, grepArgs=None, projectDir=None, reporter=None, silent=False, ): if grepArgs is None: grepArgs = deepcopy(_grepArgs) validateRunParams(grepArgs, projectDir, reporter, silent) if projectDir is None: projectDir = os.getcwd() else: projectDir = path.normpath(projectDir) if reporter is None: reporter = "simple_test_default_reporter" ensureTestsDirExists(projectDir) cliGrepArgs = toCliGrepArgs(grepArgs) subprocessResult = subprocessRun( [ sys.executable, "-m", "simple_test_process", projectDir, reporter, str(silent), *cliGrepArgs, ], cwd=projectDir, ) return subprocessResult.returncode # ------- # # Helpers # # ------- # def ensureTestsDirExists(projectDir): testsDir = path.join(projectDir, "tests") if not path.isdir(testsDir): raise_( Exception, f""" projectDir must contain a directory 'tests' projectDir: {projectDir} """, ) def eachToKeyValuePair(grepVals, grepKey): cliGrepKey = f"--{dashcase(grepKey)}" return map_(lambda val: [cliGrepKey, val])(grepVals) def toCliGrepArgs(grepArgs): return passThrough( grepArgs, [ keepWhen(isLaden), map_(eachToKeyValuePair), getListOfCollectionValues, flattenDeep, ], ) PK! )Yt t 'po/simple_test/run/validateRunParams.py# ------- # # Imports # # ------- # from os import path from simple_test_process.parseArgs import _grepArgs from types import SimpleNamespace from ..fns import all_, isEmpty, isSomething, raise_ # ---- # # Init # # ---- # setOfGrepArgsKeys = set(_grepArgs.__dict__.keys()) # ---- # # Main # # ---- # def validateRunParams(grepArgs, projectDir, reporter, silent): if not isinstance(grepArgs, SimpleNamespace): raise_( TypeError, f""" 'grepArgs' must be an instance of SimpleNamespace type: {type(grepArgs).__name__} """, ) if not hasAllGrepKeys(grepArgs): raise_( ValueError, f""" 'grepArgs' must contain all (and only) the available keys available keys: {", ".join(_grepArgs.__dict__.keys())} keys given: {", ".join(grepArgs.__dict__.keys())} """, ) if not all_(areStringLists)(grepArgs): raise ValueError("'grepArgs' can only contain lists of strings") if isSomething(projectDir): if not isinstance(projectDir, str): raise_( TypeError, f"""\ 'projectDir' must be an instance of str type: {type(silent).__name__} """, ) if isEmpty(projectDir): raise ValueError("'projectDir' cannot be an empty string") if not path.isabs(projectDir): raise_( ValueError, f""" 'projectDir' must pass 'os.path.isabs' projectDir: {projectDir} """, ) if not path.isdir(projectDir): raise_( ValueError, f""" 'projectDir' must pass 'os.path.isdir' projectDir: {projectDir} """, ) if isSomething(reporter): if not isinstance(reporter, str): raise_( TypeError, f""" 'reporter' must be an instance of str type: {type(reporter).__name__} """, ) if isEmpty(reporter): raise ValueError("'reporter' cannot be an empty string") if reporter.startswith("."): raise_( ValueError, f""" relative reporter modules are not yet supported reporter: {reporter} """, ) if isSomething(silent) and not isinstance(silent, bool): raise_( TypeError, f"""\ 'silent' must be an instance of bool type: {type(silent).__name__} """, ) # ------- # # Helpers # # ------- # def hasAllGrepKeys(grepArgs): if len(grepArgs.__dict__) != len(_grepArgs.__dict__): return False for key in grepArgs.__dict__.keys(): if key not in setOfGrepArgsKeys: return False return True def areStrings(val): return isinstance(val, str) def areStringLists(val): return isinstance(val, list) and all_(areStrings)(val) PK!p:22po/simple_test/script.pyfrom .cli import runSimpleTest from .run import run import sys def printErr(msg): print(msg, file=sys.stderr) def main(): result = runSimpleTest(run, sys.argv[1:]) if result.stdout: print(result.stdout) if result.stderr: printErr(result.stderr) exit(result.code) PK!H\H1:/po.simple_test-0.3.0.dist-info/entry_points.txtN+I/N.,()*-I-I-.-׃pA\=<..PK!HڽTU$po.simple_test-0.3.0.dist-info/WHEEL A н#Z;/"d&F[xzw@Zpy3Fv]\fi4WZ^EgM_-]#0(q7PK!HջB'po.simple_test-0.3.0.dist-info/METADATAOo0siv+UbV-cd,TH=r~|@R"U}˜w5Wk^&m0MZ}Vű+)(F[:@R\4 l]z v鄝n%Unmt"XUp铜+-;uTݎLrˋ<_l8֨tFZS9.>mR^~ЪM=xuy /6\Y;5 p=͝5^eCM#a,•{c&rLe 'BPK!Hp: %po.simple_test-0.3.0.dist-info/RECORDDzXE-" o=#$@xЄ@ WMSh=fs)(۰ 1:/P։jt6, BQAa䏶3:A ۜ3X&ɨ'FQaUD(gU[&;b4lsp^"W6 8u:} QZ MsCd5v B׍i)UA:N"LN""gF?:-Y8,JXp+ yPz옜4P*\'N~ܵŧW)s ,K DƱ7^A䤵bNHgW_Hf`!&8%^j/w԰,Gx pHb/؛l ]-~ $jphg '|ݏ=]!QY%Get,X=GL ~@`ah>cD. 4mQ o јg7}T3$u?u\ùGEکf(OEY ()m9-vC7TݗW@cY$̪&%DU#$"ȬF4 2sQL%B׻ frỊd iCRsIM&OJ&`I#X"^8$fx4hh˨,Wek-0z!-+6TEyt @Lc۬kF Jad{2'lSI4dM(^N̪>Hq94KgG"WV3QO@oCa oz EgNx >؁QIwb≱:8r-< v> }$2:;v%YĜ* iP(d\cnKl٣sbPFδ8m6"<뱶0<Ao]bO,_ }OGmLMh]ɜaO1Z kj5PٽuӘO@ @N4I֒g>V2Awu~7u.M}kXn,ZS2wJIRj<)I{WH'Q EBI "'Ύ!rb$&n(R$B:&׆q WPO"Y;>qԡ ARg9ս k]9G.Q u8M -kul  Rp:Ь(TE&;͊/ҷ5!_'<٥)Nz燮dWǖ{TwD7ʼn=t[d {[e"iL013I ) Cج}r[?XЉ߅'{Gii ;B{F8 6٦}_H>Z3}H'8G/_A{N \h RVE2^\AoJ6o}Yٟ?0%au)l =n$ǹ$>ۘȖ}@Ks8pĹ ZƦ\GX& cU><ӭl[5uvf׵u|] 3 ƂdMة9M{\325hv@6WBѾ{ mNIyZXDRN!_tNipWp[Uߨ4r]nzb/ 9Sv5: ׽64?yQ `b´̉/:I Eű舦@mf-Ha;53P[Ppcn  Svv+n]mGW2X`@bE;r:ɍ/U1 ]CBC'|'R80Ѩ+*7<+U1U _͓ldxd}:DS"ئ\R TwDe !~o&t7nV^S@ΤN~e9d &%P+,Q#f`/򒟡ܡ1XEو "+78 i Ok1SWڙlK3 ?juyP4w>ӓUT[e T;iN }@ v<|ms:[Sd< q'i}ebh0M,;W"Rt_Zq:>镨 Jj@bC+EsEi(d41D9ۋ9t >Ipo/simple_test/cli/__init__.pyPK!Hyypo/simple_test/cli/index.pyPK!8gKKu po/simple_test/cli/usage.pyPK!{eXr r * po/simple_test/cli/validateAndParseArgs.pyPK!z6Ypo/simple_test/fns/__init__.pyPK!]po/simple_test/fns/all_.pyPK!) "po/simple_test/fns/decorators/__init__.pyPK![`)gEE.S"po/simple_test/fns/decorators/argIsCallable.pyPK!waII+#po/simple_test/fns/decorators/argIsClass.pyPK!dZT.v%po/simple_test/fns/decorators/argIsInstance.pyPK!0(po/simple_test/fns/decorators/argIsListOfType.pyPK!E*/po/simple_test/fns/decorators/argIsType.pyPK!b!`2po/simple_test/fns/flattenDeep.pyPK!`c??w5po/simple_test/fns/forEach.pyPK!ȇ#/9po/simple_test/fns/getListOfCollectionValues.pyPK!B u*=po/simple_test/fns/internal/NotCallable.pyPK!'^@po/simple_test/fns/internal/__init__.pyPK!F*@po/simple_test/fns/internal/discardWhen.pyPK!ss"Epo/simple_test/fns/internal/get.pyPK!)jj)Epo/simple_test/fns/internal/getArgName.pyPK!X-kFpo/simple_test/fns/internal/getFnSignature.pyPK!k5Hpo/simple_test/fns/internal/getNumPositionalParams.pyPK!w<-Mpo/simple_test/fns/internal/getTypedResult.pyPK!;||" Qpo/simple_test/fns/internal/iif.pyPK!ws{33&Qpo/simple_test/fns/internal/isLaden.pyPK!Ȋ/