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_build_library(): "Test that a given Nim module can produce a Python extension library." with nimporter.cd('tests'): module = Path('lib1') output = NimCompiler.build_artifact(module) artifact = NimCompiler.compile_nim_code(module, output, library=True) assert artifact.exists() assert artifact.parent == output.parent assert artifact.suffix == output.suffix
def test_build_library_fails(): "Test NimInvokeException" # Build library using Nim module try: NimCompiler.compile_nim_code(Path('tests/mod_b.nim'), None, library=True) assert False, 'Should throw exception.' except NimporterException: "Expected result" # Build a library that has an error try: module = Path('tests/lib4') output = NimCompiler.build_artifact(module) NimCompiler.compile_nim_code(module, output, library=True) assert False, 'Should throw exception.' except NimInvokeException as e: assert str(e) assert e.get_output() # Build a library that doesn't have a Nimble file try: NimCompiler.compile_nim_code(Path('tests/lib3'), None, library=True) assert False, 'Should throw exception.' except NimporterException: "Expected result"
def test_build_module_fails(): "Test NimCompileException" # Build nonexistent file try: fake = Path('nonesense.nim') NimCompiler.compile_nim_code(fake, None, library=True) assert False, "Should throw exception. File doesn't exist: " + str( fake) except NimporterException: "Expected result" # Build module using library path try: NimCompiler.compile_nim_code(Path('tests/lib1'), None, library=False) assert False, 'Should throw exception.' except NimporterException: "Expected result" # Build a module that has an error try: module = Path('tests/pkg1/error.nim') output = NimCompiler.build_artifact(module) NimCompiler.compile_nim_code(module, output, library=False) assert False, 'Should throw exception.' except NimCompileException as e: assert str(e)
def test_build_module(): "Test that a given Nim module can produce a Python extension module." with nimporter.cd('tests'): module = Path('mod_a.nim') output = NimCompiler.build_artifact(module) f = io.StringIO() with redirect_stdout(f): artifact = NimCompiler.compile_nim_code(module, output, library=False) assert artifact.exists() assert artifact.parent == output.parent assert 'Warning:' in f.getvalue()
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