def set_mypy_args(self, mypy_args=None): """Sets MyPy arguments.""" if mypy_args is None: self.mypy_args = None else: self.mypy_errs = [] self.mypy_args = list(mypy_args) for arg in self.mypy_args: if arg == "--py2" or arg == "-2": logger.warn("unnecessary --mypy argument", arg, extra="passed automatically when needed") elif arg == "--python-version": logger.warn( "unnecessary --mypy argument", arg, extra="current --target passed as version automatically" ) if not ("--py2" in self.mypy_args or "-2" in self.mypy_args ) and not self.comp.target.startswith("3"): self.mypy_args.append("--py2") if "--python-version" not in self.mypy_args: self.mypy_args += [ "--python-version", ".".join(str(v) for v in self.comp.target_info_len2) ] logger.log("MyPy args:", self.mypy_args)
def compile_file(self, filepath, write=True, package=False, force=False, **kwargs): """Compile a file and returns the compiled file's path.""" set_ext = False if write is False: destpath = None elif write is True: destpath = filepath set_ext = True elif os.path.splitext(write)[1]: # write is a file; it is the destination filepath destpath = write else: # write is a dir; make the destination filepath by adding the filename destpath = os.path.join(write, os.path.basename(filepath)) set_ext = True if set_ext: base, ext = os.path.splitext(os.path.splitext(destpath)[0]) if not ext: ext = comp_ext destpath = fixpath(base + ext) if filepath == destpath: raise CoconutException("cannot compile " + showpath(filepath) + " to itself", extra="incorrect file extension") if destpath is not None: dest_ext = os.path.splitext(destpath)[1] if dest_ext in code_exts: if force: logger.warn("found destination path with " + dest_ext + " extension; compiling anyway due to --force") else: raise CoconutException( "found destination path with " + dest_ext + " extension; aborting compilation", extra="pass --force to override", ) self.compile(filepath, destpath, package, force=force, **kwargs) return destpath
def start_jupyter(self, args): """Start Jupyter with the Coconut kernel.""" install_func = partial(run_cmd, show_output=logger.verbose) try: install_func(["jupyter", "--version"]) except CalledProcessError: jupyter = "ipython" else: jupyter = "jupyter" # always install kernels if given no args, otherwise only if there's a kernel missing do_install = not args if not do_install: kernel_list = run_cmd([jupyter, "kernelspec", "list"], show_output=False, raise_errs=False) do_install = any(ker not in kernel_list for ker in icoconut_kernel_names) if do_install: success = True for icoconut_kernel_dir in icoconut_kernel_dirs: install_args = [ jupyter, "kernelspec", "install", icoconut_kernel_dir, "--replace" ] try: install_func(install_args) except CalledProcessError: user_install_args = install_args + ["--user"] try: install_func(user_install_args) except CalledProcessError: logger.warn("kernel install failed on command'", " ".join(install_args)) self.register_error(errmsg="Jupyter error") success = False if success: logger.show_sig( "Successfully installed Coconut Jupyter kernel.") if args: if args[0] == "console": ver = "2" if PY2 else "3" try: install_func( ["python" + ver, "-m", "coconut.main", "--version"]) except CalledProcessError: kernel_name = "coconut" else: kernel_name = "coconut" + ver run_args = [jupyter, "console", "--kernel", kernel_name ] + args[1:] else: run_args = [jupyter] + args self.register_error(run_cmd(run_args, raise_errs=False), errmsg="Jupyter error")
def remove_jupyter_kernel(self, jupyter, kernel_name): """Remove the given kernel via the command line and return whether successful.""" remove_args = jupyter + ["kernelspec", "remove", kernel_name, "-f"] try: self.run_silent_cmd(remove_args) except CalledProcessError: logger.warn("kernel removal failed on command", " ".join(remove_args)) self.register_error(errmsg="Jupyter kernel error") return False return True
def set_mypy_args(self, mypy_args=None): """Sets MyPy arguments.""" if mypy_args is None: self.mypy_args = None else: self.mypy_errs = [] self.mypy_args = list(mypy_args) for arg in self.mypy_args: if arg == "--fast-parser": logger.warn("unnecessary --mypy argument", arg, extra="passed automatically if available") elif arg == "--py2" or arg == "-2": logger.warn("unnecessary --mypy argument", arg, extra="passed automatically when needed") elif arg == "--python-version": logger.warn("unnecessary --mypy argument", arg, extra="current --target passed as version automatically") if "--fast-parser" not in self.mypy_args: try: import typed_ast # NOQA except ImportError: if self.comp.target != "3": logger.warn("missing typed_ast; MyPy may not properly analyze type annotations", extra="run 'pip install typed_ast' or pass '--target 3' to fix") else: self.mypy_args.append("--fast-parser") if not ("--py2" in self.mypy_args or "-2" in self.mypy_args) and not self.comp.target.startswith("3"): self.mypy_args.append("--py2") if "--python-version" not in self.mypy_args: self.mypy_args += ["--python-version", ".".join(str(v) for v in self.comp.target_info_len2)]
def install_jupyter_kernel(self, jupyter, kernel_dir): """Install the given kernel via the command line and return whether successful.""" install_args = jupyter + ["kernelspec", "install", kernel_dir, "--replace"] try: self.run_silent_cmd(install_args) except CalledProcessError: user_install_args = install_args + ["--user"] try: self.run_silent_cmd(user_install_args) except CalledProcessError: logger.warn("kernel install failed on command", " ".join(install_args)) self.register_error(errmsg="Jupyter kernel error") return False return True
def start_jupyter(self, args): """Starts Jupyter with the Coconut kernel.""" install_func = functools.partial(run_cmd, show_output=logger.verbose or not args) try: install_func(["jupyter", "--version"]) except CalledProcessError: jupyter = "ipython" else: jupyter = "jupyter" for icoconut_kernel_dir in icoconut_kernel_dirs: install_args = [ jupyter, "kernelspec", "install", icoconut_kernel_dir, "--replace" ] try: install_func(install_args) except CalledProcessError: user_install_args = install_args + ["--user"] try: install_func(user_install_args) except CalledProcessError: logger.warn("kernel install failed on command'", " ".join(install_args)) self.register_error(errmsg="Jupyter error") if args: if args[0] == "console": ver = "2" if PY2 else "3" try: install_func( ["python" + ver, "-m", "coconut.main", "--version"]) except CalledProcessError: kernel_name = "coconut" else: kernel_name = "coconut" + ver run_args = [jupyter, "console", "--kernel", kernel_name ] + args[1:] elif args[0] == "notebook": run_args = [jupyter, "notebook"] + args[1:] else: raise CoconutException( "first argument after --jupyter must be either 'console' or 'notebook'" ) self.register_error(run_cmd(run_args, raise_errs=False), errmsg="Jupyter error")
def kill_children(): """Terminates all child processes.""" try: import psutil except ImportError: logger.warn("missing psutil; --jobs may not properly terminate", extra="run 'pip install coconut[jobs]' to fix") else: master = psutil.Process() children = master.children(recursive=True) while children: for child in children: try: child.terminate() except psutil.NoSuchProcess: pass # process is already dead, so do nothing children = master.children(recursive=True)
def start_jupyter(self, args): """Start Jupyter with the Coconut kernel.""" install_func = partial(run_cmd, show_output=logger.verbose) try: install_func(["jupyter", "--version"]) except CalledProcessError: jupyter = "ipython" else: jupyter = "jupyter" # always install kernels if given no args, otherwise only if there's a kernel missing do_install = not args if not do_install: kernel_list = run_cmd([jupyter, "kernelspec", "list"], show_output=False, raise_errs=False) do_install = any(ker not in kernel_list for ker in icoconut_kernel_names) if do_install: success = True for icoconut_kernel_dir in icoconut_kernel_dirs: install_args = [jupyter, "kernelspec", "install", icoconut_kernel_dir, "--replace"] try: install_func(install_args) except CalledProcessError: user_install_args = install_args + ["--user"] try: install_func(user_install_args) except CalledProcessError: logger.warn("kernel install failed on command'", " ".join(install_args)) self.register_error(errmsg="Jupyter error") success = False if success: logger.show_sig("Successfully installed Coconut Jupyter kernel.") if args: if args[0] == "console": ver = "2" if PY2 else "3" try: install_func(["python" + ver, "-m", "coconut.main", "--version"]) except CalledProcessError: kernel_name = "coconut" else: kernel_name = "coconut" + ver run_args = [jupyter, "console", "--kernel", kernel_name] + args[1:] else: run_args = [jupyter] + args self.register_error(run_cmd(run_args, raise_errs=False), errmsg="Jupyter error")
def kill_children(): """Terminate all child processes.""" try: import psutil except ImportError: logger.warn( "missing psutil; --jobs may not properly terminate", extra="run '{python} -m pip install coconut[jobs]' to fix".format( python=sys.executable), ) else: parent = psutil.Process() children = parent.children(recursive=True) while children: for child in children: try: child.terminate() except psutil.NoSuchProcess: pass # process is already dead, so do nothing children = parent.children(recursive=True)
def get_package_level(self, codepath): """Get the relative level to the base directory of the package.""" package_level = -1 check_dir = os.path.dirname(os.path.abspath(codepath)) while check_dir: has_init = False for ext in code_exts: init_file = os.path.join(check_dir, "__init__" + ext) if os.path.exists(init_file): has_init = True break if has_init: package_level += 1 check_dir = os.path.dirname(check_dir) else: break if package_level < 0: logger.warn("missing __init__" + code_exts[0] + " in package", check_dir) package_level = 0 return package_level return 0
def execute(self, compiled=None, path=None, use_eval=False, allow_show=True): """Execute compiled code.""" self.check_runner() if compiled is not None: if allow_show and self.show: print(compiled) if path is None: # header is not included if not self.mypy: no_str_code = self.comp.remove_strs(compiled) result = mypy_builtin_regex.search(no_str_code) if result: logger.warn("found mypy-only built-in " + repr(result.group(0)) + "; pass --mypy to use mypy-only built-ins at the interpreter") else: # header is included compiled = rem_encoding(compiled) self.runner.run(compiled, use_eval=use_eval, path=path, all_errors_exit=path is not None) self.run_mypy(code=self.runner.was_run_code())
def start_jupyter(self, args): """Starts Jupyter with the Coconut kernel.""" install_func = functools.partial(run_cmd, show_output=logger.verbose or not args) try: install_func(["jupyter", "--version"]) except CalledProcessError: jupyter = "ipython" else: jupyter = "jupyter" for icoconut_kernel_dir in icoconut_kernel_dirs: install_args = [jupyter, "kernelspec", "install", icoconut_kernel_dir, "--replace"] try: install_func(install_args) except CalledProcessError: user_install_args = install_args + ["--user"] try: install_func(user_install_args) except CalledProcessError: logger.warn("kernel install failed on command'", " ".join(install_args)) self.register_error(errmsg="Jupyter error") if args: if args[0] == "console": ver = "2" if PY2 else "3" try: install_func(["python" + ver, "-m", "coconut.main", "--version"]) except CalledProcessError: kernel_name = "coconut" else: kernel_name = "coconut" + ver run_args = [jupyter, "console", "--kernel", kernel_name] + args[1:] elif args[0] == "notebook": run_args = [jupyter, "notebook"] + args[1:] else: raise CoconutException('first argument after --jupyter must be either "console" or "notebook"') self.register_error(run_cmd(run_args, raise_errs=False), errmsg="Jupyter error")
def set_mypy_args(self, mypy_args=None): """Sets MyPy arguments.""" if mypy_args is None: self.mypy_args = None else: self.mypy_errs = [] self.mypy_args = list(mypy_args) for arg in self.mypy_args: if arg == "--fast-parser": logger.warn("unnecessary --mypy argument", arg, extra="passed automatically if available") elif arg == "--py2" or arg == "-2": logger.warn("unnecessary --mypy argument", arg, extra="passed automatically when needed") elif arg == "--python-version": logger.warn( "unnecessary --mypy argument", arg, extra="current --target passed as version automatically" ) if "--fast-parser" not in self.mypy_args: try: import typed_ast # NOQA except ImportError: if self.comp.target != "3": logger.warn( "missing typed_ast; MyPy may not properly analyze type annotations", extra= "run 'pip install typed_ast' or pass '--target 3' to fix" ) else: self.mypy_args.append("--fast-parser") if not ("--py2" in self.mypy_args or "-2" in self.mypy_args ) and not self.comp.target.startswith("3"): self.mypy_args.append("--py2") if "--python-version" not in self.mypy_args: self.mypy_args += [ "--python-version", ".".join(str(v) for v in self.comp.target_info_len2) ]
def use_args(self, args, interact=True): """Handles command-line arguments.""" logger.quiet, logger.verbose = args.quiet, args.verbose if DEVELOP: logger.tracing = args.trace if args.recursion_limit is not None: self.set_recursion_limit(args.recursion_limit) if args.jobs is not None: self.set_jobs(args.jobs) if args.display: self.show = True if args.style is not None: self.prompt.set_style(args.style) if args.documentation: launch_documentation() if args.tutorial: launch_tutorial() self.setup( target=args.target, strict=args.strict, minify=args.minify, line_numbers=args.line_numbers, keep_lines=args.keep_lines, ) if args.mypy is not None: self.set_mypy_args(args.mypy) if args.source is not None: if args.interact and args.run: logger.warn("extraneous --run argument passed; --interact implies --run") if args.package and self.mypy: logger.warn("extraneous --package argument passed; --mypy implies --package") if args.standalone and args.package: raise CoconutException("cannot compile as both --package and --standalone") if args.standalone and self.mypy: raise CoconutException("cannot compile as both --package (implied by --mypy) and --standalone") if (args.run or args.interact) and os.path.isdir(args.source): if args.run: raise CoconutException("source path must point to file not directory when --run is enabled") if args.interact: raise CoconutException("source path must point to file not directory when --run (implied by --interact) is enabled") if args.watch and os.path.isfile(args.source): raise CoconutException("source path must point to directory not file when --watch is enabled") if args.dest is None: if args.nowrite: dest = None # no dest else: dest = True # auto-generate dest elif args.nowrite: raise CoconutException("destination path cannot be given when --nowrite is enabled") elif os.path.isfile(args.dest): raise CoconutException("destination path must point to directory not file") else: dest = args.dest if args.package or self.mypy: package = True elif args.standalone: package = False else: package = None # auto-decide package with self.running_jobs(): filepaths = self.compile_path(args.source, dest, package, args.run or args.interact, args.force) self.run_mypy(filepaths) elif (args.run or args.nowrite or args.force or args.package or args.standalone or args.watch): raise CoconutException("a source file/folder must be specified when options that depend on the source are enabled") if args.code is not None: self.execute(self.comp.parse_block(args.code)) stdin = not sys.stdin.isatty() # check if input was piped in if stdin: self.execute(self.comp.parse_block(sys.stdin.read())) if args.jupyter is not None: self.start_jupyter(args.jupyter) if args.interact or (interact and not ( stdin or args.source or args.code or args.tutorial or args.documentation or args.watch or args.jupyter is not None )): self.start_prompt() if args.watch: self.watch(args.source, dest, package, args.run, args.force)
def use_args(self, args, interact=True, original_args=None): """Handle command-line arguments.""" logger.quiet, logger.verbose = args.quiet, args.verbose if DEVELOP: logger.tracing = args.trace logger.log("Using " + PYPARSING + ".") if original_args is not None: logger.log("Directly passed args:", original_args) logger.log("Parsed args:", args) if args.recursion_limit is not None: set_recursion_limit(args.recursion_limit) if args.jobs is not None: self.set_jobs(args.jobs) if args.display: self.show = True if args.style is not None: self.prompt.set_style(args.style) if args.documentation: launch_documentation() if args.tutorial: launch_tutorial() self.setup( target=args.target, strict=args.strict, minify=args.minify, line_numbers=args.line_numbers, keep_lines=args.keep_lines, no_tco=args.no_tco or args.mypy is not None, ) if args.mypy is not None: if args.no_tco: logger.warn( "extraneous --no-tco argument passed; --mypy implies --no-tco" ) self.set_mypy_args(args.mypy) if args.argv is not None: sys.argv = [args.source if args.source is not None else ""] sys.argv.extend(args.argv) if args.source is not None: if args.interact and args.run: logger.warn( "extraneous --run argument passed; --interact implies --run" ) if args.package and self.mypy: logger.warn( "extraneous --package argument passed; --mypy implies --package" ) if args.standalone and args.package: raise CoconutException( "cannot compile as both --package and --standalone") if args.standalone and self.mypy: raise CoconutException( "cannot compile as both --package (implied by --mypy) and --standalone" ) if args.no_write and self.mypy: raise CoconutException( "cannot compile with --no-write when using --mypy") if (args.run or args.interact) and os.path.isdir(args.source): if args.run: raise CoconutException( "source path must point to file not directory when --run is enabled" ) if args.interact: raise CoconutException( "source path must point to file not directory when --run (implied by --interact) is enabled" ) if args.watch and os.path.isfile(args.source): raise CoconutException( "source path must point to directory not file when --watch is enabled" ) if args.dest is None: if args.no_write: dest = None # no dest else: dest = True # auto-generate dest elif args.no_write: raise CoconutException( "destination path cannot be given when --no-write is enabled" ) elif os.path.isfile(args.dest): raise CoconutException( "destination path must point to directory not file") else: dest = args.dest if args.package or self.mypy: package = True elif args.standalone: package = False else: package = None # auto-decide package with self.running_jobs(exit_on_error=not args.watch): filepaths = self.compile_path(args.source, dest, package, args.run or args.interact, args.force) self.run_mypy(filepaths) elif (args.run or args.no_write or args.force or args.package or args.standalone or args.watch): raise CoconutException( "a source file/folder must be specified when options that depend on the source are enabled" ) if args.code is not None: self.execute(self.comp.parse_block(args.code)) got_stdin = False if stdin_readable(): logger.log("Reading piped input from stdin...") self.execute(self.comp.parse_block(sys.stdin.read())) got_stdin = True if args.jupyter is not None: self.start_jupyter(args.jupyter) if args.interact or (interact and not (got_stdin or args.source or args.code or args.tutorial or args.documentation or args.watch or args.jupyter is not None)): self.start_prompt() if args.watch: self.watch(args.source, dest, package, args.run, args.force)
from coconut.terminal import logger from coconut.compiler import Compiler from coconut.compiler.util import should_indent from coconut.command.util import Runner try: from IPython.core.inputsplitter import IPythonInputSplitter from IPython.core.interactiveshell import InteractiveShellABC from IPython.core.compilerop import CachingCompiler from ipykernel.ipkernel import IPythonKernel from ipykernel.zmqshell import ZMQInteractiveShell except ImportError: LOAD_MODULE = False if os.environ.get(conda_build_env_var): # conda tries to import coconut.icoconut as a test even when IPython isn't available logger.warn("Missing IPython but detected " + conda_build_env_var + "; skipping coconut.icoconut loading") else: raise CoconutException( "--jupyter flag requires Jupyter library", extra="run 'pip install coconut[jupyter]' to fix", ) else: LOAD_MODULE = True # ----------------------------------------------------------------------------------------------------------------------- # GLOBALS: # ----------------------------------------------------------------------------------------------------------------------- COMPILER = Compiler( target="sys", line_numbers=True,
def start_jupyter(self, args): """Start Jupyter with the Coconut kernel.""" # get the correct jupyter command for jupyter in ( [sys.executable, "-m", "jupyter"], [sys.executable, "-m", "ipython"], ["jupyter"], ): try: self.run_silent_cmd(jupyter + ["--help"]) # --help is much faster than --version except CalledProcessError: logger.warn("failed to find Jupyter command at " + repr(" ".join(jupyter))) else: break # get a list of installed kernels kernel_list = self.get_jupyter_kernels(jupyter) newly_installed_kernels = [] # always update the custom kernel, but only reinstall it if it isn't already there or given no args custom_kernel_dir = install_custom_kernel(logger=logger) if custom_kernel_dir is not None and (icoconut_custom_kernel_name not in kernel_list or not args): logger.show_sig("Installing Jupyter kernel {name!r}...".format(name=icoconut_custom_kernel_name)) if self.install_jupyter_kernel(jupyter, custom_kernel_dir): newly_installed_kernels.append(icoconut_custom_kernel_name) if not args: # install default kernels if given no args newly_installed_kernels += self.install_default_jupyter_kernels(jupyter, kernel_list) run_args = None else: # use the custom kernel if it exists if icoconut_custom_kernel_name in kernel_list or icoconut_custom_kernel_name in newly_installed_kernels: kernel = icoconut_custom_kernel_name # otherwise determine which default kernel to use and install them if necessary else: ver = "2" if PY2 else "3" try: self.run_silent_cmd(["python" + ver, "-m", "coconut.main", "--version"]) except CalledProcessError: kernel = "coconut_py" else: kernel = "coconut_py" + ver if kernel not in kernel_list: newly_installed_kernels += self.install_default_jupyter_kernels(jupyter, kernel_list) logger.warn("could not find {name!r} kernel; using {kernel!r} kernel instead".format(name=icoconut_custom_kernel_name, kernel=kernel)) # pass the kernel to the console or otherwise just launch Jupyter now that we know our kernel is available if args[0] == "console": run_args = jupyter + ["console", "--kernel", kernel] + args[1:] else: run_args = jupyter + args if newly_installed_kernels: logger.show_sig("Successfully installed Jupyter kernels: '" + "', '".join(newly_installed_kernels) + "'") # run the Jupyter command if run_args is not None: self.register_error(run_cmd(run_args, raise_errs=False), errmsg="Jupyter error")
def use_args(self, args, interact=True, original_args=None): """Handle command-line arguments.""" logger.quiet, logger.verbose = args.quiet, args.verbose if DEVELOP: logger.tracing = args.trace logger.log("Using " + PYPARSING + ".") if original_args is not None: logger.log("Directly passed args:", original_args) logger.log("Parsed args:", args) if args.recursion_limit is not None: set_recursion_limit(args.recursion_limit) if args.jobs is not None: self.set_jobs(args.jobs) if args.display: self.show = True if args.style is not None: self.prompt.set_style(args.style) if args.history_file is not None: self.prompt.set_history_file(args.history_file) if args.documentation: launch_documentation() if args.tutorial: launch_tutorial() self.setup( target=args.target, strict=args.strict, minify=args.minify, line_numbers=args.line_numbers, keep_lines=args.keep_lines, no_tco=args.no_tco, ) if args.mypy is not None: self.set_mypy_args(args.mypy) if args.argv is not None: sys.argv = [args.source if args.source is not None else ""] sys.argv.extend(args.argv) if args.source is not None: if args.interact and args.run: logger.warn("extraneous --run argument passed; --interact implies --run") if args.package and self.mypy: logger.warn("extraneous --package argument passed; --mypy implies --package") if args.standalone and args.package: raise CoconutException("cannot compile as both --package and --standalone") if args.standalone and self.mypy: raise CoconutException("cannot compile as both --package (implied by --mypy) and --standalone") if args.no_write and self.mypy: raise CoconutException("cannot compile with --no-write when using --mypy") if (args.run or args.interact) and os.path.isdir(args.source): if args.run: raise CoconutException("source path must point to file not directory when --run is enabled") if args.interact: raise CoconutException("source path must point to file not directory when --run (implied by --interact) is enabled") if args.watch and os.path.isfile(args.source): raise CoconutException("source path must point to directory not file when --watch is enabled") if args.dest is None: if args.no_write: dest = False # no dest else: dest = True # auto-generate dest elif args.no_write: raise CoconutException("destination path cannot be given when --no-write is enabled") else: dest = args.dest if args.package or self.mypy: package = True elif args.standalone: package = False else: package = None # auto-decide package with self.running_jobs(exit_on_error=not args.watch): filepaths = self.compile_path(args.source, dest, package, args.run or args.interact, args.force) self.run_mypy(filepaths) elif ( args.run or args.no_write or args.force or args.package or args.standalone or args.watch ): raise CoconutException("a source file/folder must be specified when options that depend on the source are enabled") if args.code is not None: self.execute(self.comp.parse_block(args.code)) got_stdin = False if args.jupyter is not None: self.start_jupyter(args.jupyter) elif stdin_readable(): logger.log("Reading piped input from stdin...") self.execute(self.comp.parse_block(sys.stdin.read())) got_stdin = True if args.interact or (interact and not ( got_stdin or args.source or args.code or args.tutorial or args.documentation or args.watch or args.jupyter is not None )): self.start_prompt() if args.watch: self.watch(args.source, dest, package, args.run, args.force)
def use_args(self, args, interact=True, original_args=None): """Handle command-line arguments.""" # fix args if not DEVELOP: args.trace = args.profile = False # set up logger logger.quiet, logger.verbose, logger.tracing = args.quiet, args.verbose, args.trace if args.trace or args.profile: unset_fast_pyparsing_reprs() if args.profile: collect_timing_info() logger.log(cli_version) if original_args is not None: logger.log("Directly passed args:", original_args) logger.log("Parsed args:", args) # validate general command args if args.mypy is not None and args.line_numbers: logger.warn("extraneous --line-numbers argument passed; --mypy implies --line-numbers") if args.site_install and args.site_uninstall: raise CoconutException("cannot --site-install and --site-uninstall simultaneously") # process general command args if args.recursion_limit is not None: set_recursion_limit(args.recursion_limit) if args.jobs is not None: self.set_jobs(args.jobs) if args.display: self.show = True if args.style is not None: self.prompt.set_style(args.style) if args.history_file is not None: self.prompt.set_history_file(args.history_file) if args.vi_mode: self.prompt.vi_mode = True if args.docs: launch_documentation() if args.tutorial: launch_tutorial() if args.site_uninstall: self.site_uninstall() if args.site_install: self.site_install() if args.argv is not None: self.argv_args = list(args.argv) # additional validation after processing if args.profile and self.jobs != 0: raise CoconutException("--profile incompatible with --jobs {jobs}".format(jobs=args.jobs)) # process general compiler args self.setup( target=args.target, strict=args.strict, minify=args.minify, line_numbers=args.line_numbers or args.mypy is not None, keep_lines=args.keep_lines, no_tco=args.no_tco, no_wrap=args.no_wrap, ) # process mypy args (must come after compiler setup) if args.mypy is not None: self.set_mypy_args(args.mypy) if args.source is not None: # warnings if source is given if args.interact and args.run: logger.warn("extraneous --run argument passed; --interact implies --run") if args.package and self.mypy: logger.warn("extraneous --package argument passed; --mypy implies --package") # errors if source is given if args.standalone and args.package: raise CoconutException("cannot compile as both --package and --standalone") if args.standalone and self.mypy: raise CoconutException("cannot compile as both --package (implied by --mypy) and --standalone") if args.no_write and self.mypy: raise CoconutException("cannot compile with --no-write when using --mypy") # process all source, dest pairs src_dest_package_triples = [ self.process_source_dest(src, dst, args) for src, dst in ( [(args.source, args.dest)] + (getattr(args, "and") or []) ) ] # do compilation with self.running_jobs(exit_on_error=not args.watch): filepaths = [] for source, dest, package in src_dest_package_triples: filepaths += self.compile_path(source, dest, package, run=args.run or args.interact, force=args.force) self.run_mypy(filepaths) # validate args if no source is given elif ( args.run or args.no_write or args.force or args.package or args.standalone or args.watch ): raise CoconutException("a source file/folder must be specified when options that depend on the source are enabled") elif getattr(args, "and"): raise CoconutException("--and should only be used for extra source/dest pairs, not the first source/dest pair") # handle extra cli tasks if args.code is not None: self.execute(self.comp.parse_block(args.code)) got_stdin = False if args.jupyter is not None: self.start_jupyter(args.jupyter) elif stdin_readable(): logger.log("Reading piped input from stdin...") self.execute(self.comp.parse_block(sys.stdin.read())) got_stdin = True if args.interact or ( interact and not ( got_stdin or args.source or args.code or args.tutorial or args.docs or args.watch or args.site_uninstall or args.site_install or args.jupyter is not None or args.mypy == [mypy_install_arg] ) ): self.start_prompt() if args.watch: # src_dest_package_triples is always available here self.watch(src_dest_package_triples, args.run, args.force) if args.profile: print_timing_info()