PK!*Ilfastest/__init__.pyname = "fastest" PK!*ddfastest/__main__.pyimport os import time from fastest.file_handler.read_file import read_file from fastest.code_assets.function import get_functions from fastest.test_compiler import test_writer from watchdog.observers import Observer from watchdog.events import PatternMatchingEventHandler from fastest.logger.logger import logger from fastest.cli.args import cli_args from fastest.file_handler import make_test_module, execute_coverage, \ execute_tests, is_path_to_be_ignored monitor_path = cli_args.path if cli_args.path is not None else os.getcwd() poll_duration = int(cli_args.poll_duration) \ if type(cli_args.poll_duration) is str and \ cli_args.poll_duration.isdigit() \ else 1 make_test_module() def main(): logger.info('Monitoring started...') class PyFileHandler(PatternMatchingEventHandler): patterns = ['*.py'] exclude_files = cli_args.exclude if cli_args.exclude is not None else '' ignore_patterns = [path.strip() for path in exclude_files.split(',')] ignore_patterns += ['test/*', '__pycache__', '*.pyc', '*__test.py'] def process(self, event): if is_path_to_be_ignored(event.src_path, monitor_path, self.ignore_patterns): return None page = read_file(monitor_path, event.src_path) functions = get_functions(page) test_writer.build(functions, event.src_path, monitor_path) execute_tests(monitor_path) execute_coverage(monitor_path) def on_modified(self, event): self.process(event) def on_created(self, event): self.process(event) observer = Observer() observer.schedule(PyFileHandler(), monitor_path, recursive=True) observer.start() try: while True: time.sleep(poll_duration) except KeyboardInterrupt: observer.stop() observer.join() PK!fastest/bodies/__init__.pyname = "bodies_pkg"PK!)$)>>,fastest/bodies/test_case_template_builder.pyimport re import uuid from fastest.constants import Keys, Content def case_generator(uuid_val=None): """ ---- examples: 1) case_generator('a55eff11-ed51-ecb37-ccba') -> 'A55EFF11ED' ---- Use uuid to create test-case unique name :return: """ uuid_val = uuid_val if uuid_val is not None else str(uuid.uuid4()) return str(uuid_val).upper().replace("-", "")[0:10] def get_empty_of_type(input_type): """ Return an empty form of a given type ---- examples: 1) get_empty_of_type('str') -> "''" 2) get_empty_of_type('???') -> None ---- :param input_type: str :return: str """ empty_type = { 'str': '\'\'', 'int': '0', 'list': '[]', 'dict': '{}', '': '\'\'' } return empty_type.get(input_type) def get_params_list(params): """ ---- examples: 1) get_params_list(['str', 'str', 'list', 'dict']) -> ["''", "''", '[]', '{}'] 2) get_params_list(['str', '???']) -> ["''"] ---- :param params: list :return: list """ return [ get_empty_of_type(param) for param in params if param in ['str', 'int', 'list', 'dict'] ] def create_type_test_case(function_object, params): """ Create test case for checking types of function ----- examples: @need from fastest.constants import TestBodies @end @let function_object = { 'tests': { 'return': 'str' }, 'name': 'function_1' } params = ['str', 'str'] @end 1) create_type_test_case(function_object, params) -> TestBodies.TYPE_TEST_CASE_1 ----- :param function_object: dict :param params: list :return: str """ empty_param_call = '{}({})'.format(function_object.get(Keys.NAME), ', '.join(params)) return Content.TYPE_ASSERT_TEMPLATE.format( function=empty_param_call, value=function_object.get(Keys.TESTS, {}).get(Keys.RETURN) ) def create_type_test_case_if_params(function_object, params): """ Create type test case if there is info over params and return ---- examples: @need from fastest.constants import TestBodies @end @let function_object = { 'tests': { 'return': 'str' }, 'name': 'function_1' } params = ['str', 'str'] @end 1) create_type_test_case_if_params(function_object, params) -> TestBodies.TYPE_TEST_CASE_2 ---- :param function_object: dict :param params: list :return: str """ return create_type_test_case(function_object, params)\ if is_type_test_ready(function_object, params)\ else '' def is_type_test_ready(function_object, params): """ if a function has params and return type specified, return True else False ---- examples: @let function_object_1 = { 'tests': { 'return': 'str' } } function_object_2 = {'tests': {}} params = ['str', 'str'] @end 1) is_type_test_ready(function_object_1, params) -> True 2) is_type_test_ready(function_object_2, params) -> False 3) is_type_test_ready(function_object_1, []) -> False ---- :param function_object: dict :param params: list :return: bool """ return_type = function_object.get(Keys.TESTS, {}).get(Keys.RETURN) return bool(return_type and len(params) > 0) def create_assertion_test(function_object): """ Create assertion test cases by embedding into the template strings if examples are present in the docstrings ----- examples: @need from fastest.constants import TestBodies @end @let function_object_1 = { 'tests': { 'variables': ['a = 5'] } } function_object_2 = {'tests': {'variables': []}} params = ['str', 'str'] @end 1) create_assertion_test(function_object_1) -> TestBodies.ASSERTION_TEST_1 2) create_assertion_test(function_object_2) -> '' ----- :param function_object: dict :return: str """ template = '' if function_object.get(Keys.TESTS, {}).get(Keys.VARIABLES): for variable in function_object.get(Keys.TESTS, {}).get(Keys.VARIABLES, []): template += Content.VARIABLES_TEMPLATE.format(variables=variable) return template def create_naive_test_case(function_object, test, test_id=None): """ Create test cases from the assertions, docstring params and return types ---- examples: @need from fastest.constants import TestBodies @end @let function_object = { 'tests': { 'return': 'str', 'variables': ['a = 5'] }, 'name': 'function_1' } test = { 'from': 'function_1', 'expect': '2' } exception_test = { 'from': 'function_2(None)', 'exception': 'TypeError' } test_id = 'a55eff11-ed51-ecb37-ccba' @end 1) create_naive_test_case(function_object, test, test_id) -> TestBodies.NAIVE_TEST_RESULT 2) create_naive_test_case(function_object, exception_test, test_id) -> TestBodies.EXCEPTION_TEST_RESULT ---- :param function_object: dict :param test: dict :param test_id: str :return: str """ test_template = Content.TEST_CASE_TEMPLATE.format( function_name=function_object.get(Keys.NAME), case_id=case_generator(test_id), ) params = get_params_list(function_object.get(Keys.TESTS, {}).get(Keys.PARAMS, [])) test_template += create_type_test_case_if_params(function_object, params) test_template += create_assertion_test(function_object) if test.get(Keys.EXPECT): test_template += Content.ASSERTION_TEMPLATE.format(function=test.get(Keys.FROM), value=test.get(Keys.EXPECT)) elif test.get(Keys.EXCEPTION): args = re.search(r'\((.*)\)', test.get(Keys.FROM)) args = [arg.strip() for arg in args.group(1).split(',')] test_template += Content.EXCEPTION_TEMPLATE.format( function=function_object.get(Keys.NAME), value=test.get(Keys.EXCEPTION), args=args ) return test_template PK!fastest/cli/__init__.pyPK!;L}fastest/cli/args.pyimport argparse parser = argparse.ArgumentParser(description='Create test cases automatically') parser.add_argument('--path', help='Project root, use $(pwd) to be sure') parser.add_argument('--source', help='Modules to check coverage for') parser.add_argument('--poll-duration', default='1', help='Modules to check coverage for') parser.add_argument( '--exclude', help='Comma separated names of files/dirs that should NOT be watched', ) cli_args = parser.parse_args() PK!XE}fastest/code_assets/__init__.pyname = "code_assets_pkg" PK!2Efastest/code_assets/function.pyimport ast from fastest.code_assets.naive_case_detector import get_test_from_example_passage from fastest.logger.logger import logger def get_functions_from_node(node): """ Extract functions from ast node :param node: :return: list """ return [{ 'name': n.name, 'tests': get_test_from_example_passage(ast.get_docstring(n)) } for n in node.body if isinstance(n, ast.FunctionDef)] def get_functions(page): """ Read a python script and extract functions and class methods and add them to a list ------ examples: @need from fastest.constants import TestBodies @end @let page = TestBodies.GET_FUNCTIONS_TEST_CASE_1 page_with_syntax_error = TestBodies.PAGE_WITH_SYNTAX_ERRORS @end 1) get_functions(page) -> TestBodies.GET_FUNCTIONS_TEST_CASE_1_EXPECT 2) get_functions(page_with_syntax_error) -> [] ------ :param page: str :return: list """ try: node = ast.parse(page) functions = get_functions_from_node(node) classes = [n for n in node.body if isinstance(n, ast.ClassDef)] methods = [get_functions_from_node(class_) for class_ in classes] return functions + methods except SyntaxError as error: logger.error(error) return [] PK!b]]fastest/code_assets/keywords.pyFALSE = 'False' CLASS = 'class' FINALLY = 'finally' IS = 'is' RETURN = 'return' NONE = 'None' CONTINUE = 'continue' FOR = 'for' LAMBDA = 'lambda' TRY = 'try' TRUE = 'True' DEF = 'def' FROM = 'from' NONLOCAL = 'nonlocal' WHILE = 'while' AND = 'and' DEL = 'del' GLOBAL = 'global' NOT = 'not' WITH = 'with' AS = 'as' ELIF = 'elif' IF = 'if' OR = 'or' YIELD = 'yield' ASSERT = 'assert' ELSE = 'else' IMPORT = 'import' PASS = 'pass' BREAK = 'break' EXCEPT = 'except' IN = 'in' RAISE = 'raise' RESERVED = [ FALSE, CLASS, FINALLY, IS, RETURN, NONE, CONTINUE, FOR, LAMBDA, TRY, TRUE, DEF, FROM, NONLOCAL, WHILE, AND, DEL, GLOBAL, NOT, WITH, AS, ELIF, IF, OR, YIELD, ASSERT, ELSE, IMPORT, PASS, BREAK, EXCEPT, IN, RAISE, "+", "-", "/", "*", "+=", "-=", "/=", "*=", "**", "%", "!", "@", "^", "&", "(", ")", "=", "'", "\"", "|", ">", ">=", "<", "<=", ",", "!=", "==", ":", '.' ] PK!*fastest/code_assets/naive_case_detector.pyimport re from fastest.constants import Keys, Patterns from fastest.logger.logger import logger FUNCTION_CALL = 0 OUTPUT = 1 def format_imports(import_statements): """ ----- examples: @need from fastest.constants import TestBodies @end @let import_input = TestBodies.TEST_STACK_IMPORTS_INPUT output = TestBodies.TEST_STACK_IMPORTS_OUTPUT @end 1) format_imports(import_input) -> output ----- :param import_statements: list :return: list """ return [ '{}\n'.format(import_statement.strip()) for import_statement in import_statements if len(import_statement) > 0 ] def get_exception_case_from_examples(example_strings): """ --- examples: @need from fastest.constants import TestBodies @end @let exception_example_happy_case = TestBodies.EXCEPTION_EXAMPLE_HAPPY_CASE exception_example_sep_missing = TestBodies.EXCEPTION_EXAMPLE_SEP_MISSING happy_case_output = TestBodies.EXCEPTION_HAPPY_CASE_OUTPUT @end 1) get_exception_case_from_examples(exception_example_happy_case) -> happy_case_output 2) get_exception_case_from_examples(exception_example_sep_missing) -> [] !! get_exception_case_from_examples(None) -> TypeError --- :param example_strings: str :return: list """ exception_example_stack = [] exception_cases = re.findall(Patterns.EXCEPTION_CASE_EXAMPLE, example_strings, re.M) for example in exception_cases: function_call_array = re.sub(r'!!\s*', '', example, 1) \ .rsplit(Patterns.TEST_SEP, 1) if len(function_call_array) != 2: return [] test_function, expectation = function_call_array exception_example_stack.append({ Keys.FROM: test_function, Keys.EXCEPTION: expectation }) return exception_example_stack def get_imports_from_docstring(example_passage): """ ---- examples: @need from fastest.constants import TestBodies @end @let example_passage = TestBodies.EXAMPLE_WITH_IMPORTS import_statements = TestBodies.TEST_IMPORT_EXTRACTION empty_example_passage = '' @end 1) get_imports_from_docstring(example_passage) -> import_statements 1) get_imports_from_docstring(empty_example_passage) -> [] ---- :param example_passage: str :return: list """ needed_imports = re.findall(Patterns.NEED_IMPORT, example_passage, re.M) needed_imports = needed_imports if len(needed_imports) > 0 else None if needed_imports is None: return [] needed_imports = ''.join(needed_imports).replace(Patterns.IMPORT_DEC, '').split('\n') return format_imports(needed_imports) def get_variables_from_docstring(example_passage): """ ---- examples: @need from fastest.constants import TestBodies @end @let example_passage = TestBodies.TEST_VARIABLES_FROM_DOCSTRING empty_example_passage = '' expected_output = TestBodies.TEST_VARIABLES_FROM_DOCSTRING_RESULT @end 1) get_variables_from_docstring(empty_example_passage) -> [] 2) get_variables_from_docstring(example_passage) -> expected_output ---- :param example_passage: str :return: list """ needed_variables = re.findall(Patterns.NEEDED_VARIABLES, example_passage) if len(needed_variables) == 0: return [] needed_variables = needed_variables[0] needed_variables = needed_variables.replace('@let', '') return needed_variables.split('\n') def stack_examples(examples_strings): """ ---- examples: @need from fastest.constants import TestBodies @end @let example_strings = TestBodies.STACK_EXAMPLES_TEST @end 1) stack_examples('') -> [] 2) stack_examples(example_strings) -> [{'expect': '25', 'from': 'square(5)'}] 3) stack_examples(['1) func_do_work()']) -> [] ---- :param examples_strings: list :return: list """ example_stack = [] for example in examples_strings: function_call_array = re.sub(Patterns.NUMBER_BULLET, '', example, 1) \ .rsplit(Patterns.TEST_SEP, 1) if len(function_call_array) != 2: return [] test_function, expectation = function_call_array example_stack.append({ Keys.FROM: test_function, Keys.EXPECT: expectation }) return example_stack def get_params_from_docstring(statements): """ ---- examples: @need from fastest.constants import TestBodies @end @let statements = TestBodies.GET_PARAMS_FROM_DOCSTRING_TEST @end 1) get_params_from_docstring('') -> [] 2) get_params_from_docstring(statements) -> TestBodies.EXPECT_PARAMS ---- :param statements: str :return: list """ params = re.findall(r':param .*:(.*)', statements) return [ param.replace(' ', '') for param in params ] def get_return_from_docstring(statements): """ ---- examples: @need from fastest.constants import TestBodies @end @let statements = TestBodies.RETURN_TYPE_TEST @end 1) get_return_from_docstring('') -> '' 2) get_return_from_docstring(statements) -> 'int' ---- :param statements: str :return: str """ return_statement = re.search(r':return: (.*)', statements) return return_statement.group(1) if return_statement is not None else '' def get_test_case_examples(example_passage): """ ---- examples: @need from fastest.constants import TestBodies @end @let example_passage = TestBodies.TEST_EXAMPLE_PASSAGE @end 1) get_test_case_examples(example_passage) -> TestBodies.TEST_EXAMPLE_PASSAGE_RESULT ---- :param example_passage: str :return: list """ examples_strings = re.findall(Patterns.TEST_CASE_EXAMPLE, example_passage, re.M) examples_strings = examples_strings if len(examples_strings) > 0 else [] return stack_examples(examples_strings) + get_exception_case_from_examples(example_passage) def get_test_from_example_passage(statements): """ ---- examples: @need from fastest.constants import TestBodies @end @let statements = TestBodies.NAIVE_CASE_TEST_STATEMENT @end 1) get_test_from_example_passage(statements) -> TestBodies.NAIVE_CASE_TEST_RESULT 2) get_test_from_example_passage(None) -> {} 3) get_test_from_example_passage('lorem ipsum') -> {} ---- :param statements: [] :return: dict """ if statements is None: return {} example_passage = re.findall(Patterns.EXAMPLE_PASSAGE, statements, re.I) example_passage = example_passage[0] if len(example_passage) > 0 else None if example_passage is None: return {} import_statements = get_imports_from_docstring(example_passage) variables = get_variables_from_docstring(example_passage) examples = get_test_case_examples(example_passage) params = get_params_from_docstring(statements) return_statement = get_return_from_docstring(statements) return {} \ if examples is None \ else { Keys.IMPORTS: import_statements, Keys.VARIABLES: variables, Keys.EXAMPLES: examples, Keys.PARAMS: params, Keys.RETURN: return_statement } PK!@;$..fastest/constants.pyimport platform class Sys: __UNIX_SLASH = '/' __WINDOWS_SLASH = '\\' PY = '.py' SLASH = __WINDOWS_SLASH if platform.system == 'Windows' else __UNIX_SLASH TEST_FILE_ENDING = '__test.py' class Keys: IMPORTS = 'imports' NAME = 'name' TESTS = 'tests' TEST = 'test' STR = 'str' EXAMPLES = 'examples' FROM = 'from' EXPECT = 'expect' VARIABLES = 'variables' PARAMS = 'params' RETURN = 'return' EXCEPTION = 'exception' class Content: CLASS_CREATE_TEMPLATE = '\nclass Test{}{}(unittest.TestCase):\n' IMPORT_UNITTEST = 'import unittest\n' DEPS_IMPORT_TEMPLATE = 'from {} import {}\n' TEST_CASE_TEMPLATE = ' def test__{function_name}__{case_id}(self):' TESTERS_NOTES_TEMPLATE = ' {testers_notes}' VARIABLES_TEMPLATE = ' {variables}\n' TYPE_ASSERT_TEMPLATE = '\n self.assertIsInstance({function}, {value})' ASSERTION_TEMPLATE = '\n self.assertEqual({function}, {value})\n' EXCEPTION_TEMPLATE = '\n self.assertRaises({value}, {function}, {args})\n\n' class Patterns: FUNCTION_CALL = r'example: [\s\S]+?(?=->)' IMPORT_DEC = '@need\n' VAR_DEC = r'@let ' NEED_IMPORT = r'@need[\s\S]+?(?=@end)' NEEDED_VARIABLES = r'@let[\s\S]+?(?=@end)' NUMBER_BULLET = r'\d\) ' TEST_CASE_EXAMPLE = r'\d\) [\s\S]+?(?=\n)' EXAMPLE_PASSAGE = r'-{3,}[\s\S]+?(?=---)' TEST_SEP = ' -> ' EXCEPTION_CASE_EXAMPLE = r'!! [\s\S]+?(?=\n)' class TestBodies: GET_FUNCTIONS_TEST_CASE_1 = """ def function_1(): return 1 """ GET_FUNCTIONS_TEST_CASE_1_EXPECT = [{'name': 'function_1', 'tests': {}}] TYPE_TEST_CASE_1 = '\n self.assertIsInstance(function_1(str, str), str)' TYPE_TEST_CASE_2 = '\n self.assertIsInstance(function_1(str, str), str)' ASSERTION_TEST_1 = ' a = 5\n' NAIVE_TEST_RESULT = """ def test__function_1__A55EFF11ED(self): a = 5 self.assertEqual(function_1, 2)\n""" EXCEPTION_TEST_RESULT = """ def test__function_1__A55EFF11ED(self): a = 5 self.assertRaises(TypeError, function_1, ['None'])\n """ TEST_STACK_IMPORTS_OUTPUT = ['from datetime import datetime\n', 'import numpy as np\n'] TEST_STACK_IMPORTS_INPUT = ['from datetime import datetime ', ' import numpy as np '] EXAMPLE_WITH_IMPORTS = """ @need from datetime import datetime import numpy as np @end """ TEST_IMPORT_EXTRACTION = [ 'from datetime import datetime\n', 'import numpy as np\n', '\n' ] TEST_VARIABLES_FROM_DOCSTRING = """ @let a = 4 @end """ TEST_VARIABLES_FROM_DOCSTRING_RESULT = ['', ' a = 4', ' '] STACK_EXAMPLES_TEST = ['1) square(5) -> 25'] GET_PARAMS_FROM_DOCSTRING_TEST = """ :param item: int :param store: dict """ EXPECT_PARAMS = ['int', 'dict'] RETURN_TYPE_TEST = """ :return: int """ TEST_EXAMPLE_PASSAGE = """ 1) square(4) -> 16 2) page(20) -> [] """ TEST_EXAMPLE_PASSAGE_RESULT = [ {'expect': '16', 'from': 'square(4)'}, {'expect': '[]', 'from': 'page(20)'} ] NAIVE_CASE_TEST_STATEMENT = """ ---- example: @need from datetime import datetime @end @let a = 2 x = 2 @end 1) pow(a, x) -> 4 ---- :param x: int :return: int """ NAIVE_CASE_TEST_RESULT = { 'examples': [{'expect': '4', 'from': 'pow(a, x)'}], 'imports': ['from datetime import datetime\n', '\n'], 'params': ['int'], 'return': 'int', 'variables': ['', ' a = 2', ' x = 2', ' '] } CREATE_TEST_CLASS_RESULT = ({'from fastest/__main__ import add_imports_for_test_case\n', 'import random', 'import unittest\n'}, ['', '\nclass TestFastestAddImportsForTestCase(unittest.TestCase):\n']) TEST_CASE_CONTENT_RESULT = ({'from fastest.constants import TestBodies\n', 'import random'}, ['', ' def test__add_imports_for_test_case__0A856D9D76(self): \n' " empty_test = { 'imports': None }\n" " test = { 'imports': ['from datetime import datetime'] }\n" " imports = {'import numpy as np'}\n" " updated_imports = {'import numpy as np', 'from datetime import " "datetime'}\n" ' \n' '\n' ' self.assertEqual(add_imports_for_test_case(empty_test, imports), ' 'imports)\n', ' def test__add_imports_for_test_case__B502446AEB(self): \n' " empty_test = { 'imports': None }\n" " test = { 'imports': ['from datetime import datetime'] }\n" " imports = {'import numpy as np'}\n" " updated_imports = {'import numpy as np', 'from datetime import " "datetime'}\n" ' \n' '\n' ' self.assertEqual(add_imports_for_test_case(test, imports), ' 'updated_imports)\n']) MOCK_FUNCTION_OBJECT = { 'name': 'add_imports_for_test_case', 'tests': { 'examples': [{ 'expect': 'imports', 'from': 'add_imports_for_test_case(empty_test, ' 'imports)' }, { 'expect': 'updated_imports', 'from': 'add_imports_for_test_case(test, ' 'imports)' }], 'imports': ['from fastest.constants import TestBodies\n'], 'params': ['dict', 'set'], 'return': 'set', 'variables': ['', "empty_test = { 'imports': None }", "test = { 'imports': ['from datetime import " "datetime'] }", "imports = {'import numpy as np'}", "updated_imports = {'import numpy as np', 'from " "datetime import datetime'}", ''] } } PAGE_WITH_SYNTAX_ERRORS = 'def f(' SEPARATOR_ERR_EXAMPLE = '' EXCEPTION_EXAMPLE_HAPPY_CASE = '!! exception_fn(None) -> TypeError\n' EXCEPTION_EXAMPLE_SEP_MISSING = '!! func_do_work(None)\n' EXCEPTION_HAPPY_CASE_OUTPUT = [{ 'from': 'exception_fn(None)', 'exception': 'TypeError' }] PK!$D}} fastest/file_handler/__init__.pyfrom fastest.file_handler.coverage_path import get_report_path from fastest.file_handler.make_test_dir import make_test_module from fastest.file_handler.create_test_command import test_command from fastest.file_handler.run_tests import execute_tests from fastest.file_handler.run_coverage import execute_coverage from fastest.file_handler.ignore_paths import is_path_to_be_ignored PK!8%fastest/file_handler/coverage_path.pyimport os def get_report_path(project_path): """ Returns the path to coverage report :param project_path: str :return: str """ return os.path.abspath(os.path.join(project_path, 'htmlcov/index.html')) PK!t=+fastest/file_handler/create_test_command.pyimport os def get_test_files(): """ Create a list of test files in the test directory excluding .pyc and __pycache__ :return: list """ test_files = os.listdir('./test') return [ create_test_file_name(test_file) for test_file in test_files if is_valid_test_file(test_files) ] def is_valid_test_file(test_file): """ Checks if file is a .pyc or from __pycache__ :param test_file: str :return: str """ return '.pyc' not in test_file and '__pycache__' not in test_file def create_test_file_name(test_file): """ Append `test.` over file names to run all tests via `unittest` :param test_file: str :return: str """ 'test.{}'.format(test_file.replace('.py', '')) def test_command(source): """ Creates a command to be run via subprocess :param source: str|None :return: list """ command = ['pytest', '--cov', source] if source is not None else ['pytest', '--cov'] return command PK!rO  $fastest/file_handler/ignore_paths.pyimport fnmatch def is_path_to_be_ignored(event_path, report_path, ignore_patterns): """ answers: Is event_path one among the ignore_patterns? strips report path from the event_path :param event_path: str :param report_path: str :param ignore_patterns: list :return: bool """ for ignored_pattern in ignore_patterns: _, current_file_path = event_path.split(report_path + '/') if fnmatch.fnmatch(current_file_path, ignored_pattern): return True return False PK!>%fastest/file_handler/make_test_dir.pyimport os def make_test_module(): """ A function with side-effect of creating a python module for containing tests at the root of a project. """ if os.path.exists('./test'): return None # If there is a test module present # at the target location, exit. os.mkdir('./test') # If there is no `test` module, create one open('./test/__init__.py', 'a').close() # Create an __init__.py so that # the dir is identified as a python module PK! *"NN!fastest/file_handler/read_file.pyimport os def read_file(dir_path, file_path): """ Read contents of a .py file and return as text :param dir_path: str :param file_path: str :return: str """ goal_dir = os.path.join(dir_path, file_path) with open(os.path.abspath(goal_dir), 'r') as fp: contents = fp.read() return contents PK!B$fastest/file_handler/run_coverage.pyimport subprocess import os import pathlib from fastest.logger.logger import logger def execute_coverage(report_path): """ Function with a side-effect to create coverage report and prints to stdout :param report_path: str :return: None """ subprocess.call(['coverage', 'report']) subprocess.call(['coverage', 'html']) coverage_path = os.path.join(report_path, 'htmlcov', 'index.html') logger.info(pathlib.Path(coverage_path).as_uri()) PK!x=FW!fastest/file_handler/run_tests.pyimport subprocess from fastest.file_handler import test_command def execute_tests(source): """ Runs all tests within the tests directory :param source: str :return: None """ subprocess.call(test_command(source)) PK!jG!!fastest/logger/__init__.pyfrom fastest.logger import loggerPK! fastest/logger/logger.pyimport coloredlogs, logging # Create a logger object. logger = logging.getLogger(__name__) # By default the install() function installs a handler on the root logger, # this means that log messages from your code and log messages from the # libraries that you use will all show up on the terminal. coloredlogs.install(fmt='%(hostname)s %(asctime)s %(levelname)s %(message)s', level='DEBUG', logger=logger) PK!W!fastest/test_compiler/__init__.pyname = "compiler_pkg" PK!`&fastest/test_compiler/compile_tests.pyfrom fastest.constants import Content, Keys from fastest.utils import to_camel_case def add_imports_for_test_case(test, imports): """ --- examples: @need from fastest.constants import TestBodies @end @let empty_test = { 'imports': None } test = { 'imports': ['from datetime import datetime'] } imports = {'import numpy as np'} updated_imports = {'import numpy as np', 'from datetime import datetime'} @end 1) add_imports_for_test_case(empty_test, imports) -> imports 2) add_imports_for_test_case(test, imports) -> updated_imports --- :param test: dict :param imports: set :return: set """ if test[Keys.IMPORTS] is None: return imports for import_statement in test[Keys.IMPORTS]: imports.add(import_statement) return imports def create_test_class(imports, contents, deps_import, function_object, root_module_name): """ ---- examples: @need from fastest.constants import TestBodies @end @let imports = {'import random'} contents = [''] deps_import = 'fastest/__main__' function_object = TestBodies.MOCK_FUNCTION_OBJECT root_module_name = 'fastest' @end 1) create_test_class(imports, contents, deps_import, function_object, root_module_name) -> TestBodies.CREATE_TEST_CLASS_RESULT ---- :param imports: set :param contents: list :param deps_import: str :param function_object: dict :param root_module_name: str :return: tuple """ imports.add(Content.IMPORT_UNITTEST) imports.add(Content.DEPS_IMPORT_TEMPLATE.format(deps_import, function_object[Keys.NAME])) camel_cased_root_module_name = to_camel_case(root_module_name) camel_cased_function_name = to_camel_case(function_object[Keys.NAME]) contents.append(Content.CLASS_CREATE_TEMPLATE.format( camel_cased_root_module_name, camel_cased_function_name )) return imports, contents PK!4EjGG$fastest/test_compiler/test_writer.pyimport os from fastest.constants import Keys, Sys from fastest.test_compiler.compile_tests import add_imports_for_test_case, create_test_class from fastest.bodies.test_case_template_builder import create_naive_test_case def create_test_case_content(function_object, imports, contents): """ :param function_object: dict :param imports: set :param contents: list :return: tuple """ for example in function_object[Keys.TESTS][Keys.EXAMPLES]: contents.append(create_naive_test_case(function_object, example)) imports = add_imports_for_test_case(function_object[Keys.TESTS], imports) return imports, contents def create_test_case(function_objects, deps_import, root_module_name): imports = set() contents = [] for function_object in function_objects: if not isinstance(function_object, dict): continue if function_object[Keys.TESTS] is None: continue imports, contents = create_test_class(imports, contents, deps_import, function_object, root_module_name) imports, contents = create_test_case_content(function_object, imports, contents) return imports, contents def write_tests_to_file(fp, imports, contents): return fp.write(''.join(sorted(list(imports)) + contents)) def build(function_objects, src_file_path, base_path): last_file = -1 test_file_name = 'test__' + src_file_path.split(Sys.SLASH)[last_file] deps_import = src_file_path.replace(base_path + Sys.SLASH, '').replace(Sys.SLASH, '.').replace('.py', '') root_module_name = deps_import.split('.')[-1] test_file_path = os.path.join(base_path, Keys.TEST, test_file_name) with open(test_file_path, 'w+') as fp: imports, contents = create_test_case(function_objects, deps_import, root_module_name) write_tests_to_file(fp, imports, contents) PK!_RSfastest/type/__init__.pyname = "type_pkg" PK!fastest/type/type_inference.pyfrom fastest.type import type_usage_patterns INT = 0 STR = 1 LIST = 2 TUPLE = 3 DICT = 4 type_map = ['int', 'str', 'list', 'tuple', 'dict'] def infer(variable, statements): """ example: infer("list_var", "def fn():\n\tlist_var = [1]") -> ['list'] # example: infer("some_var", "def fn():\n\tsome_var + some_other") -> ['int', 'str'] # :param variable: :param statements: :return: """ statements = statements.split('\n') statements = statements[1:] type_chances = [0] * 5 for statement in statements: type_chances[INT] += type_usage_patterns.used_as_int(statement, variable) type_chances[STR] += type_usage_patterns.used_as_str(statement, variable) type_chances[LIST] += type_usage_patterns.used_as_list(statement, variable) type_chances[TUPLE] += type_usage_patterns.used_as_tuple(statement, variable) type_chances[DICT] += type_usage_patterns.used_as_dict(statement, variable) max_prob_type = max(type_chances) if type_chances.count(max_prob_type) > 1: return [type_map[i] for i, type_chance in enumerate(type_chances) if type_chance == max_prob_type] else: return [type_map[type_chances.index(max_prob_type)]] PK!rwL#fastest/type/type_usage_patterns.pyimport re from fastest.utils import count_truthy def used_as_int(statement, variable): """ example: used_as_int("a = 4", "a") -> 1 # example: used_as_int("a + 4", "a") -> 1 # example: used_as_int("a * 4", "a") -> 1 # example: used_as_int("a - 4", "a") -> 1 # :param statement: :param variable: :return: """ statement = statement.strip() assignment = re.search(r'{variable}\s*=\s*\d+'.format(variable=variable), statement) addition = re.search(r'{variable}\s*\+\s*'.format(variable=variable), statement) addition_inc = re.search(r'{variable}\s*\+=\s*\d+'.format(variable=variable), statement) multiplication = re.search(r'{variable}\s*\*\s*'.format(variable=variable), statement) subtraction = re.search(r'{variable}\s*-\s*'.format(variable=variable), statement) division = re.search(r'{variable}\s*/\s*'.format(variable=variable), statement) return count_truthy([assignment, addition, subtraction,multiplication, division, addition_inc]) def used_as_str(statement, variable): """ example: used_as_str("string_var = 'something'", "string_var") -> 1 # example: used_as_str("string_var + 'something'", "string_var") -> 1 # example: used_as_str("string_var * 5", "string_var") -> 1 # :param statement: :param variable: :return: """ statement = statement.strip() assignment = re.match('{variable}\s*=\s*"|\'\w*"|\''.format(variable=variable), statement) addition = re.match(r'{variable}\s*\+\s*'.format(variable=variable), statement) multiplication = re.match(r'{variable}\s*\*\d*'.format(variable=variable), statement) return count_truthy([assignment, addition, multiplication]) def used_as_iterable(statement, variable): """ example: used_as_iterable("for word in words", "words") -> 1 # :param statement: :param variable: :return: """ statement = statement.strip() loop = re.match(r'for \w+ in {variable}'.format(variable=variable), statement) map_fn = re.search(r'map\(.*[^,)],\s*{variable}'.format(variable=variable), statement) filter_fn = re.search(r'filter\(.*[^,)],\s*{variable}'.format(variable=variable), statement) reduce_fn = re.search(r'reduce\(.*[^,)],\s*{variable}'.format(variable=variable), statement) item_index = re.match(r'{variable}\[\d+\]'.format(variable=variable), statement) return count_truthy([loop, map_fn, filter_fn, reduce_fn, item_index]) def used_as_list(statement, variable): """ example: used_as_list("apples.append(10)", "apples") -> 1 # example: used_as_list("apples = [11, 12]", "apples") -> 1 # :param statement: :param variable: :return: """ statement = statement.strip() assignment = re.match(r'{variable}\s*=\s*\['.format(variable=variable), statement) assignment_as_instance = re.match(r'{variable}\s*=\s*list\('.format(variable=variable), statement) append = re.search(r'{variable}.append\('.format(variable=variable), statement) return count_truthy([assignment_as_instance, assignment, append]) + used_as_iterable(statement, variable) def used_as_tuple(statement, variable): """ example: used_as_tuple("words = (11, 2)", "words") -> 1 # :param statement: :param variable: :return: """ statement = statement.strip() assignment = re.match(r'{variable}\s*=\s*\('.format(variable=variable), statement) assignment_as_instance = re.match(r'{variable}\s*=\s*tuple\('.format(variable=variable), statement) insert = re.match(r'{variable}.insert\('.format(variable=variable), statement) return count_truthy([assignment_as_instance, assignment, insert]) + used_as_iterable(statement, variable) def used_as_dict(statement, variable): """ example: used_as_dict("dict_input['val']", "dict_input") -> 1 # :param statement: :param variable: :return: """ statement = statement.strip() assignment = re.search(r'{variable}\s*=\s*\{{'.format(variable=variable), statement) key_ref_str = re.search(r'{variable}\[\"|\'\w+\"|\'\]'.format(variable=variable), statement) key_ref_var = re.search(r'{variable}\[\w+\]'.format(variable=variable), statement) get_access = re.search(r'{variable}.get\('.format(variable=variable), statement) return count_truthy([assignment, key_ref_str, key_ref_var, get_access]) PK!"fastest/utils.pydef count_truthy(items): """ Count non None values viz, but includes 0 ---- examples: 1) count_truthy([1, 2, None, 'a']) -> 3 2) count_truthy([1, 2, 0, 'a']) -> 4 ---- :param items: list :return: int """ counter = 0 for item in items: if item is not None: counter += 1 return counter def to_camel_case(snake_str): """ Convert snake case to CamelCase ----- examples: 1) to_camel_case('snake_cased_string') -> 'SnakeCasedString' ----- :param snake_str: str :return: str """ components = snake_str.split('_') return components[0].title() + ''.join(x.title() for x in components[1:]) PK!H<+1(fastest-0.1.5.dist-info/entry_points.txtN+I/N.,()JK,.I-.z񹉙yV PK!HڽTUfastest-0.1.5.dist-info/WHEEL A н#Z;/"d&F[xzw@Zpy3Fv]\fi4WZ^EgM_-]#0(q7PK!H7pmk  fastest-0.1.5.dist-info/METADATAXr۸ϧ@ⴖ\bK'8ۍgLlɈ I Cg.Osb;TG&sO[>Eh#U9cI3/Č-ؠ[A. 73V0eJrX-0^&PZU!O!12(6aыB ":UG72hʔ(gp.{÷+Np l6c{^TV+3h*ռ(4{˴kߎu?'~G۠Xr+{v2$\ M"mJa|pæ5q6'$ NOwof읨V[JXSUZQ`# 2Q2_#Zե fZL\ʱ Kf3q0.\'km啄쭼oy"F\'d' 1~(.t8JvS @[nk呛&j y ־nhhVL2ή'ҾAe̿jUV_jUk d̛6!44y\6v﨣E^>|co3߮*88`gFDQv{j۽H n]w- }΅Ն-%u j qJNT!1+ KeCNuSSf^΅W hgĤq=~L+eΌ D# fFe4t䏆-{Pg@{+P f Zޡ RudƯ{5x8q?rn3iԣ1!>c5'|6FK' Q'.r!ki"Z"hph6X9D=G-:R4ذD,ySoNaRkN.uֻZ7E44 FS{âDV ; Cgnr&f`Q2dU4DxL>%Avp,$df0˽^Ȳ%Lyhqf숡)jTHCayٲ.c \2{t,cg`F\̽??㟯9*ڀA83$g{~i ˓;p<`ST3h%ba rRg<}8wW1GDQi=e7`Qa(܍~Jgj"gDG,`=iI%F]%V Mb\dGkeӐ#R7s(%P?o!ML-Xj7 \0İ*K\.w"Fr*tZ "=BBTTDDГfgq^R*0PeF G ]sE: -$It1,~ &T)a@pK5uOW,WM ˡ /1fbENI>3<9j u4:K$&`J+ :ffZi$q1d9?kL/>椿 {%`FG#A(b &e)V:G:~*{ &E^'qmpCq4G^V9%Lk]޶Rj{596=]/Q>N@:11/ÕmK+2/|\+} dT:"x ?At;7CQM~ZO|HNSjz8J<:S]2yDLf7;./D@N7jk+ FPQ P髣7J}"FH>}aGGgJh Cz D,7s6>Mg iU]>:tsËE/sǙDOD-cALآ]أtCr{ =z?_Pڑ0V[LܞE']a׹9(quQ*4PgԉfL2TMQC7b8d]݉i$Wݍ跤+nDVw{*wjʛ2Y86loNoE={E.`3T m%;BV\D'|#)T6ۛNrE=\`v}C37dqtA;&3_,x_: T_7vbR83}OG0j3<"~dn'!踦k.씊nL"':Κ+U:N1͑v[V2 y~g9}:Q[5LE U8E WS̎b;56 8*ט[x _6&{ /PK!HI fastest-0.1.5.dist-info/RECORDuKk.!4N#.!  %w~&z>FFhx%+8/`}yMl* M2zj\Gwo a/]f(@z" FұCQm/ =*j(؛`\תVGRoic \OJMJLx{\;C6tj e󣮔61^=X#[M/mBcg#,p?Φg8vS[wB07!p_xu8Eq)U !L{V?"e/bPkvz,f CnjJp4kM}%Mr`۷+aռ!ؘ`/ږхm yx$3"[ `)$y\T=f6>CZM- )Qt,P so_/W_Wߠ٫J1>nvSh9T<{{ۙ4||Rfټے >2^ 4`V{#V 2\sfMeu{ŮuMytVa29 _W_$i}/<_PK!*Ilfastest/__init__.pyPK!*ddBfastest/__main__.pyPK!fastest/bodies/__init__.pyPK!)$)>>,"fastest/bodies/test_case_template_builder.pyPK! fastest/cli/__init__.pyPK!;L} fastest/cli/args.pyPK!XE}"fastest/code_assets/__init__.pyPK!2EE#fastest/code_assets/function.pyPK!b]](fastest/code_assets/keywords.pyPK!*8-fastest/code_assets/naive_case_detector.pyPK!@;$..GJfastest/constants.pyPK!$D}} efastest/file_handler/__init__.pyPK!8%bgfastest/file_handler/coverage_path.pyPK!t=+hfastest/file_handler/create_test_command.pyPK!rO  $lfastest/file_handler/ignore_paths.pyPK!>%ofastest/file_handler/make_test_dir.pyPK! *"NN!Aqfastest/file_handler/read_file.pyPK!B$rfastest/file_handler/run_coverage.pyPK!x=FW!tfastest/file_handler/run_tests.pyPK!jG!!vfastest/logger/__init__.pyPK! svfastest/logger/logger.pyPK!W!@xfastest/test_compiler/__init__.pyPK!`&xfastest/test_compiler/compile_tests.pyPK!4EjGG$fastest/test_compiler/test_writer.pyPK!_RS fastest/type/__init__.pyPK!Tfastest/type/type_inference.pyPK!rwL#fastest/type/type_usage_patterns.pyPK!"ğfastest/utils.pyPK!H<+1(fastest-0.1.5.dist-info/entry_points.txtPK!HڽTUfastest-0.1.5.dist-info/WHEELPK!H7pmk  fastest-0.1.5.dist-info/METADATAPK!HI fastest-0.1.5.dist-info/RECORDPK