def compile_file(self, filepath, write=True, package=False, *args, **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") self.compile(filepath, destpath, package, *args, **kwargs) return destpath
def watch(self, source, write=True, package=None, run=False, force=False): """Watches a source and recompiles on change.""" from coconut.command.watch import Observer, RecompilationWatcher source = fixpath(source) print() logger.show_tabulated("Watching", showpath(source), "(press Ctrl-C to end)...") def recompile(path): if os.path.isfile(path) and os.path.splitext(path)[1] in code_exts: with self.handling_exceptions(): self.run_mypy(self.compile_path(path, write, package, run, force)) observer = Observer() observer.schedule(RecompilationWatcher(recompile), source, recursive=True) with self.running_jobs(): observer.start() try: while True: time.sleep(watch_interval) except KeyboardInterrupt: logger.show("Got KeyboardInterrupt; stopping watcher.") finally: observer.stop() observer.join()
def run_file(self, path, all_errors_exit=True): """Execute a Python file.""" path = fixpath(path) with self.handling_errors(all_errors_exit): module_vars = run_file(path) self.vars.update(module_vars) self.store("from " + splitname(path)[1] + " import *")
def install_custom_kernel(executable=None, logger=None): """Force install the custom kernel.""" kernel_source = os.path.join(icoconut_custom_kernel_dir, "kernel.json") kernel_dest = fixpath( os.path.join(sys.exec_prefix, icoconut_custom_kernel_install_loc)) try: make_custom_kernel(executable) if not os.path.exists(kernel_dest): os.makedirs(kernel_dest) shutil.copy(kernel_source, kernel_dest) except OSError: existing_kernel = os.path.join(kernel_dest, "kernel.json") if os.path.exists(existing_kernel): if logger is not None: logger.log_exc() errmsg = "Failed to update Coconut Jupyter kernel installation; the 'coconut' kernel might not work properly as a result" else: if logger is None: traceback.print_exc() else: logger.print_exc() errmsg = "Coconut Jupyter kernel installation failed due to above error" if WINDOWS: errmsg += " (try again from a shell that is run as administrator)" else: errmsg += " (try again with 'sudo')" errmsg += "." if logger is None: warn(errmsg) else: logger.warn(errmsg) return None else: return kernel_dest
def compile_file(self, filepath, write=True, package=False, *args, **kwargs): """Compile a file and returns the compiled file's path.""" if write is None: destpath = None elif write is True: destpath = filepath else: # add the name of file to the destination path destpath = os.path.join(write, os.path.basename(filepath)) if destpath is not None: 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") self.compile(filepath, destpath, package, *args, **kwargs) return destpath
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 compile_path(self, path, write=True, package=None, *args, **kwargs): """Compile a path and returns paths to compiled files.""" path = fixpath(path) if write is not None and write is not True: write = fixpath(write) if os.path.isfile(path): if package is None: package = False destpath = self.compile_file(path, write, package, *args, **kwargs) return [destpath] if destpath is not None else [] elif os.path.isdir(path): if package is None: package = True return self.compile_folder(path, write, package, *args, **kwargs) else: raise CoconutException("could not find source path", path)
def compile_path(self, path, write=True, package=None, *args, **kwargs): """Compile a path and returns paths to compiled files.""" path = fixpath(path) if not isinstance(write, bool): write = fixpath(write) if os.path.isfile(path): if package is None: package = False destpath = self.compile_file(path, write, package, *args, **kwargs) return [destpath] if destpath is not None else [] elif os.path.isdir(path): if package is None: package = True return self.compile_folder(path, write, package, *args, **kwargs) else: raise CoconutException("could not find source path", path)
def watch(self, source, write=True, package=None, run=False, force=False): """Watches a source and recompiles on change.""" from coconut.command.watch import Observer, RecompilationWatcher source = fixpath(source) print() logger.show_tabulated("Watching", showpath(source), "(press Ctrl-C to end)...") def recompile(path): if os.path.isfile(path) and os.path.splitext(path)[1] in code_exts: with self.handling_exceptions(): self.run_mypy( self.compile_path(path, write, package, run, force)) observer = Observer() observer.schedule(RecompilationWatcher(recompile), source, recursive=True) with self.running_jobs(): observer.start() try: while True: time.sleep(watch_interval) except KeyboardInterrupt: logger.show("Got KeyboardInterrupt; stopping watcher.") finally: observer.stop() observer.join()
def compile_path(self, path, write=True, package=None, run=False, force=False): """Compiles a path and returns paths to compiled files.""" path = fixpath(path) if write is not None and write is not True: write = fixpath(write) if os.path.isfile(path): if package is None: package = False destpath = self.compile_file(path, write, package, run, force) if destpath is None: return [] else: return [destpath] elif os.path.isdir(path): if package is None: package = True return self.compile_folder(path, write, package, run, force) else: raise CoconutException("could not find source path", path)
def compile_path(self, path, write=True, package=True, *args, **kwargs): """Compile a path and returns paths to compiled files.""" if not isinstance(write, bool): write = fixpath(write) if os.path.isfile(path): destpath = self.compile_file(path, write, package, *args, **kwargs) return [destpath] if destpath is not None else [] elif os.path.isdir(path): return self.compile_folder(path, write, package, *args, **kwargs) else: raise CoconutException("could not find source path", path)
def build_vars(self, path=None): """Builds initial vars.""" init_vars = { "__name__": "__main__", "__package__": None, } for var in reserved_vars: init_vars[var] = None if path is not None: init_vars["__file__"] = fixpath(path) return init_vars
def recompile(path): path = fixpath(path) if os.path.isfile(path) and os.path.splitext(path)[1] in code_exts: with self.handling_exceptions(): if write is True or write is None: writedir = write else: # correct the compilation path based on the relative position of path to source dirpath = os.path.dirname(path) writedir = os.path.join(write, os.path.relpath(dirpath, source)) filepaths = self.compile_path(path, writedir, package, run, force, show_unchanged=False) self.run_mypy(filepaths)
def build_vars(path=None): """Build initial vars.""" init_vars = { "__name__": "__main__", "__package__": None, "reload": reload, } if path is not None: init_vars["__file__"] = fixpath(path) # put reserved_vars in for auto-completion purposes for var in reserved_vars: init_vars[var] = None return init_vars
def compile(self, codepath, destpath=None, package=False, run=False, force=False, show_unchanged=True): """Compile a source Coconut file to a destination Python file.""" with openfile(codepath, "r") as opened: code = readfile(opened) package_level = -1 if destpath is not None: destpath = fixpath(destpath) destdir = os.path.dirname(destpath) if not os.path.exists(destdir): os.makedirs(destdir) if package is True: package_level = self.get_package_level(codepath) if package_level == 0: self.create_package(destdir) foundhash = None if force else self.has_hash_of(destpath, code, package_level) if foundhash: if show_unchanged: logger.show_tabulated("Left unchanged", showpath(destpath), "(pass --force to override).") if self.show: print(foundhash) if run: self.execute_file(destpath) else: logger.show_tabulated("Compiling", showpath(codepath), "...") def callback(compiled): if destpath is None: logger.show_tabulated("Compiled", showpath(codepath), "without writing to file.") else: with openfile(destpath, "w") as opened: writefile(opened, compiled) logger.show_tabulated("Compiled to", showpath(destpath), ".") if self.show: print(compiled) if run: if destpath is None: self.execute(compiled, path=codepath, allow_show=False) else: self.execute_file(destpath) if package is True: self.submit_comp_job(codepath, callback, "parse_package", code, package_level=package_level) elif package is False: self.submit_comp_job(codepath, callback, "parse_file", code) else: raise CoconutInternalException("invalid value for package", package)
def build_vars(path=None, init=False): """Build initial vars.""" init_vars = { "__name__": "__main__", "__package__": None, "reload": reload, } if path is not None: init_vars["__file__"] = fixpath(path) if init: # put reserved_vars in for auto-completion purposes only at the very beginning for var in reserved_vars: # but don't override any default Python built-ins if var not in dir(builtins): init_vars[var] = None return init_vars
def compile_file(self, filepath, write=True, package=False, run=False, force=False): """Compiles a file and returns the compiled file's path.""" if write is None: destpath = None elif write is True: destpath = filepath else: destpath = os.path.join(write, os.path.basename(filepath)) if destpath is not None: 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") self.compile(filepath, destpath, package, run, force) return destpath
def watch(self, source, write=True, package=None, run=False, force=False): """Watch a source and recompiles on change.""" from coconut.command.watch import Observer, RecompilationWatcher source = fixpath(source) logger.show() logger.show_tabulated("Watching", showpath(source), "(press Ctrl-C to end)...") def recompile(path): path = fixpath(path) if os.path.isfile(path) and os.path.splitext(path)[1] in code_exts: with self.handling_exceptions(): if write is True or write is None: writedir = write else: # correct the compilation path based on the relative position of path to source dirpath = os.path.dirname(path) writedir = os.path.join( write, os.path.relpath(dirpath, source)) filepaths = self.compile_path(path, writedir, package, run, force, show_unchanged=False) self.run_mypy(filepaths) watcher = RecompilationWatcher(recompile) observer = Observer() observer.schedule(watcher, source, recursive=True) with self.running_jobs(): observer.start() try: while True: time.sleep(watch_interval) watcher.keep_watching() except KeyboardInterrupt: logger.show_sig("Got KeyboardInterrupt; stopping watcher.") finally: observer.stop() observer.join()
def process_source_dest(self, source, dest, args): """Determine the correct source, dest, package mode to use for the given source, dest, and args.""" # determine source processed_source = fixpath(source) # validate args if (args.run or args.interact) and os.path.isdir(processed_source): if args.run: raise CoconutException("source path %r must point to file not directory when --run is enabled" % (source,)) if args.interact: raise CoconutException("source path %r must point to file not directory when --run (implied by --interact) is enabled" % (source,)) if args.watch and os.path.isfile(processed_source): raise CoconutException("source path %r must point to directory not file when --watch is enabled" % (source,)) # determine dest if dest is None: if args.no_write: processed_dest = False # no dest else: processed_dest = True # auto-generate dest elif args.no_write: raise CoconutException("destination path cannot be given when --no-write is enabled") else: processed_dest = dest # determine package mode if args.package or self.mypy: package = True elif args.standalone: package = False else: # auto-decide package if os.path.isfile(source): package = False elif os.path.isdir(source): package = True else: raise CoconutException("could not find source path", source) return processed_source, processed_dest, package
def watch(self, source, write=True, package=None, run=False, force=False): """Watch a source and recompiles on change.""" from coconut.command.watch import Observer, RecompilationWatcher source = fixpath(source) logger.show() logger.show_tabulated("Watching", showpath(source), "(press Ctrl-C to end)...") def recompile(path): path = fixpath(path) if os.path.isfile(path) and os.path.splitext(path)[1] in code_exts: with self.handling_exceptions(): if write is True or write is None: writedir = write else: # correct the compilation path based on the relative position of path to source dirpath = os.path.dirname(path) writedir = os.path.join(write, os.path.relpath(dirpath, source)) filepaths = self.compile_path(path, writedir, package, run, force, show_unchanged=False) self.run_mypy(filepaths) watcher = RecompilationWatcher(recompile) observer = Observer() observer.schedule(watcher, source, recursive=True) with self.running_jobs(): observer.start() try: while True: time.sleep(watch_interval) watcher.keep_watching() except KeyboardInterrupt: logger.show_sig("Got KeyboardInterrupt; stopping watcher.") finally: observer.stop() observer.join()
def get_python_lib(self): """Get current Python lib location.""" from distutils import sysconfig # expensive, so should only be imported here return fixpath(sysconfig.get_python_lib())
def create_package(self, dirpath): """Sets up a package directory.""" dirpath = fixpath(dirpath) filepath = os.path.join(dirpath, "__coconut__.py") with openfile(filepath, "w") as opened: writefile(opened, self.comp.getheader("__coconut__"))
def subpath(path, base_path): """Check if path is a subpath of base_path.""" path = fixpath(path) base_path = fixpath(base_path) return path == base_path or path.startswith(base_path + os.sep)
def set_history_file(self, path): """Set path to history file. Pass empty string for in-memory history.""" if path: self.history = prompt_toolkit.history.FileHistory(fixpath(path)) else: self.history = prompt_toolkit.history.InMemoryHistory()
def set_history_file(self, path): """Set path to history file. "" produces no file.""" if path: self.history = prompt_toolkit.history.FileHistory(fixpath(path)) else: self.history = prompt_toolkit.history.InMemoryHistory()
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_INFO + ".") 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 source = fixpath(args.source) if args.package or self.mypy: package = True elif args.standalone: package = False else: # auto-decide package if os.path.isfile(source): package = False elif os.path.isdir(source): package = True else: raise CoconutException("could not find source path", source) with self.running_jobs(exit_on_error=not args.watch): filepaths = self.compile_path(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(source, dest, package, args.run, args.force)
def create_package(self, dirpath): """Set up a package directory.""" dirpath = fixpath(dirpath) filepath = os.path.join(dirpath, "__coconut__.py") with openfile(filepath, "w") as opened: writefile(opened, self.comp.getheader("__coconut__"))