def test_hash_not_there(): "Make sure an exception is thrown when a module is not hashed." try: Nimporter.get_hash(Path('tests/lib4/lib4.nim')) assert False, 'Exception should have been thrown.' except NimporterException: "Expected case"
def test_hash(): "Make sure when a module is modified it's hash is also." module = Path('tests/pkg1/mod2.nim') Nimporter.update_hash(module) original_hash = Nimporter.get_hash(module) original_text = module.read_text() module.write_text(original_text.replace('World', 'Pebaz')) assert Nimporter.hash_file(module) != original_hash module.write_text(original_text.replace('Pebaz', 'World')) assert Nimporter.hash_file(module) == original_hash
def test_should_compile(): "Make sure that modules should be (re)compiled or not." filename = Path('tests/pkg4/mod4.nim') assert not Nimporter.is_hashed(filename) assert Nimporter.hash_changed(filename) assert not Nimporter.is_built(filename) assert not Nimporter.is_cache(filename) assert not NimCompiler.pycache_dir(filename).exists() assert not Nimporter.IGNORE_CACHE assert Nimporter.should_compile(filename)
def main(args=None): parser = argparse.ArgumentParser(description='Nimporter CLI') subs = parser.add_subparsers(dest='cmd', required=True) subs.add_parser('clean') build = subs.add_parser('build') build.add_argument('source', type=pathlib.Path, help='the Nim module/library to compile') build.add_argument('--dest', type=pathlib.Path, help='the folder to store the build artifact') args = parser.parse_args(args or sys.argv[1:]) if args.cmd == 'clean': cwd = pathlib.Path() print('Cleaning Directory:', cwd.resolve()) clean(cwd) elif args.cmd == 'build': args.source = args.source.absolute() if not args.dest: args.dest = NimCompiler.build_artifact(args.source).parent else: assert args.dest.is_dir(), ( 'Cannot specify output filename since extensions change per ' 'platform. Please specify an output directory such as ".".') args.dest.mkdir(exist_ok=True) module = args.source if args.source.is_dir(): is_library = bool([*module.glob('*.nimble')]) assert is_library, 'Library dir must contain <libname>.nimble file' elif args.source.is_file(): is_library = bool([*module.parent.glob('*.nimble')]) if is_library: module = module.parent temp_build_dir = pathlib.Path('build').absolute() temp_build_dir.mkdir(exist_ok=True) artifact = temp_build_dir / (args.source.stem + NimCompiler.EXT) try: NimCompiler.compile_nim_code(module, artifact, library=is_library) shutil.copy(artifact, args.dest) module_name = args.source.stem + '.nim' Nimporter.update_hash(args.dest.parent / module_name) finally: shutil.rmtree(temp_build_dir)
def test_find_extensions(): "Make sure that all Nim modules and libraries can be found." gold = { Path('tests/proj1/proj1/lib1'), Path('tests/proj1/proj1/performance.nim') } for ext in Nimporter._find_extensions(Path('tests/proj1')): assert ext in gold
def test_build_extension_module(): "Make sure A Nim module compiles to C and an Extension object is built." module = Path('tests/proj1/proj1/performance.nim') ext = Nimporter._build_nim_extension(module, Path('tests/proj1')) assert isinstance(ext, Extension) assert ext.name == 'proj1.performance' includes = set(Path(i) for i in ext.include_dirs) for source in ext.sources: src = Path(source).absolute() assert src.suffix == '.c'
def test_build_extension_library(): "Make sure a Nim library compiles to C and an Extension object is built." library = Path('tests/proj1/proj1/lib1') ext = Nimporter._build_nim_extension(library, Path('tests/proj1')) assert isinstance(ext, Extension) assert ext.name == 'proj1.lib1' includes = set(Path(i) for i in ext.include_dirs) for source in ext.sources: src = Path(source).absolute() assert src.suffix == '.c'
def test_build_all_extensions(): "Make sure all extensions within a project are compiled correctly." extension_names = {'proj2.lib1', 'proj2.performance'} extensions = Nimporter.build_nim_extensions(Path('tests/proj2')) assert len(extensions) == 2 for ext in extensions: assert ext.name in extension_names assert isinstance(ext, Extension) includes = set(Path(i) for i in ext.include_dirs) for source in ext.sources: src = Path(source).absolute() assert src.suffix == '.c'
def test_hash_coincides(): "Make sure an imported Nim module's hash matches the actual source file." from pkg1 import mod1 assert not Nimporter.hash_changed(Path('tests/pkg1/mod1.nim'))
def test_hash_filename(): "Make sure that the file used to store the hash is the correct path." module = Path('tests/pkg1/mod2.nim') proper_hash = Path('tests/pkg1/__pycache__/mod2.nim.hash').resolve() assert Nimporter.hash_filename(module) == proper_hash
def main(cli_args=None): parser = argparse.ArgumentParser(description='Nimporter CLI') subs = parser.add_subparsers(dest='cmd', required=True) # Clean command subs.add_parser( 'clean', help=( 'Run in project root to recursively remove all Nimporter-specific ' 'build artifacts and hash files')) # Build command build = subs.add_parser( 'build', help=( 'Builds a Nim module/library into an importable Python extension')) build.add_argument('source', type=pathlib.Path, help='the Nim module/library to compile') build.add_argument('--dest', type=pathlib.Path, help='the folder to store the build artifact') # Bundle command bundle_parser = subs.add_parser( 'bundle', help=( 'Convenience command for running: python setup.py sdist/bdist_wheel' )) bundle = bundle_parser.add_subparsers(dest='exp', required=True) bin_ = bundle.add_parser('bin') src = bundle.add_parser('src') # Compile command compile_ = subs.add_parser( 'compile', help=('Clean project and then recurse through and build all Nim ' 'modules/libraries')) args = parser.parse_args(cli_args or sys.argv[1:]) if args.cmd == 'clean': cwd = pathlib.Path() print('Cleaning Directory:', cwd.resolve()) clean(cwd) elif args.cmd == 'build': args.source = args.source.absolute() if not args.dest: args.dest = NimCompiler.build_artifact(args.source).parent else: assert args.dest.is_dir(), ( 'Cannot specify output filename since extensions change per ' 'platform. Please specify an output directory such as ".".') args.dest.mkdir(exist_ok=True) module = args.source if args.source.is_dir(): is_library = bool([*module.glob('*.nimble')]) assert is_library, 'Library dir must contain <libname>.nimble file' elif args.source.is_file(): is_library = bool([*module.parent.glob('*.nimble')]) if is_library: module = module.parent temp_build_dir = pathlib.Path('build').absolute() temp_build_dir.mkdir(exist_ok=True) artifact = temp_build_dir / (args.source.stem + NimCompiler.EXT) try: NimCompiler.compile_nim_code(module, artifact, library=is_library) shutil.copy(artifact, args.dest) module_name = args.source.stem + '.nim' Nimporter.update_hash(args.dest.parent / module_name) finally: shutil.rmtree(temp_build_dir) elif args.cmd == 'bundle': setup = pathlib.Path('setup.py') if not setup.exists(): print('No setup.py found in dir, would you like to generate one?') answer = 'a' while answer not in 'YN': answer = input(' Y/N: ').upper() or 'a' if answer == 'Y': setup.write_text(SETUPPY_TEMPLATE) print('Generated reference setup.py') print('Modify setup.py to point to your modules/packages.') bundle_type = 'source' if args.exp == 'src' else 'binary' print( f'Once you have finished, run `{" ".join(cli_args)}` again ' f'to create a {bundle_type} distribution package.') else: pyexe = 'python' if sys.platform == 'win32' else 'python3' if args.exp == 'bin': subprocess.Popen( f'{pyexe} setup.py bdist_wheel'.split()).wait() elif args.exp == 'src': subprocess.Popen(f'{pyexe} setup.py sdist'.split()).wait() elif args.cmd == 'compile': clean() CTM = lambda: round(time.time() * 1000) start = CTM() extensions = Nimporter._find_extensions(pathlib.Path()) for extension in extensions: is_lib = extension.is_dir() print(f'Building Extension {"Lib" if is_lib else "Mod"}: ' f'{extension.name}') NimCompiler.compile_nim_code(extension.absolute(), NimCompiler.build_artifact( extension.absolute()), library=is_lib) if is_lib: Nimporter.update_hash(extension / (extension.name + '.nim')) else: Nimporter.update_hash(extension) print('Done.') print(f'Built {len(extensions)} Extensions In ' f'{(CTM() - start) / 1000.0} secs') return 0
def main(cli_args=None): parser = argparse.ArgumentParser(description='Nimporter CLI') subs = parser.add_subparsers(dest='cmd', required=True) subs.add_parser('clean') build = subs.add_parser('build') build.add_argument( 'source', type=pathlib.Path, help='the Nim module/library to compile' ) build.add_argument( '--dest', type=pathlib.Path, help='the folder to store the build artifact' ) bundle_parser = subs.add_parser('bundle') bundle = bundle_parser.add_subparsers(dest='exp', required=True) bin_ = bundle.add_parser('bin') src = bundle.add_parser('src') args = parser.parse_args(cli_args or sys.argv[1:]) if args.cmd == 'clean': cwd = pathlib.Path() print('Cleaning Directory:', cwd.resolve()) clean(cwd) elif args.cmd == 'build': args.source = args.source.absolute() if not args.dest: args.dest = NimCompiler.build_artifact(args.source).parent else: assert args.dest.is_dir(), ( 'Cannot specify output filename since extensions change per ' 'platform. Please specify an output directory such as ".".' ) args.dest.mkdir(exist_ok=True) module = args.source if args.source.is_dir(): is_library = bool([*module.glob('*.nimble')]) assert is_library, 'Library dir must contain <libname>.nimble file' elif args.source.is_file(): is_library = bool([*module.parent.glob('*.nimble')]) if is_library: module = module.parent temp_build_dir = pathlib.Path('build').absolute() temp_build_dir.mkdir(exist_ok=True) artifact = temp_build_dir / (args.source.stem + NimCompiler.EXT) try: NimCompiler.compile_nim_code( module, artifact, library=is_library ) shutil.copy(artifact, args.dest) module_name = args.source.stem + '.nim' Nimporter.update_hash(args.dest.parent / module_name) finally: shutil.rmtree(temp_build_dir) elif args.cmd == 'bundle': setup = pathlib.Path('setup.py') if not setup.exists(): print('No setup.py found in dir, would you like to generate one?') answer = 'a' while answer not in 'YN': answer = input(' Y/N: ').upper() or 'a' if answer == 'Y': setup.write_text( f'# Setup.py tutorial:\n' f'# https://github.com/navdeep-G/setup.py\n' f'# Edit `packages=` to fit your requirements\n' f'import setuptools, nimporter\n\n' f'setuptools.setup(\n' f' name="{pathlib.Path().absolute().name}",\n' f' packages=[..], # Please read the above tutorial\n' f' ext_modules=nimporter.build_nim_extensions()\n' f')\n' ) print('Generated reference setup.py') print('Modify setup.py to point to your modules/packages.') bundle_type = 'source' if args.exp == 'src' else 'binary' print( f'Once you have finished, run `{" ".join(cli_args)}` again ' f'to create a {bundle_type} distribution package.' ) else: pyexe = 'python' if sys.platform == 'win32' else 'python3' if args.exp == 'bin': subprocess.Popen(f'{pyexe} setup.py bdist_wheel'.split()).wait() elif args.exp == 'src': subprocess.Popen(f'{pyexe} setup.py sdist'.split()).wait() return 0