def test_atomic_writeable_file(self): fd, path = tempfile.mkstemp(text=True) with os.fdopen(fd, "w") as f: f.write("contents0") # (1) normal writing works with AtomicWriteableFile(path) as f: f.write("contents1") assert read_file(path) == "contents1" # (2) if an error happens, no writing happens class CustomExc(Exception): pass try: with AtomicWriteableFile(path) as f: f.write("con") raise CustomExc() f.write("tents2") except CustomExc: pass assert read_file(path) == "contents1"
def run(): """Entry point for Cozy executable. This procedure reads sys.argv and executes the requested tasks. """ parser = argparse.ArgumentParser(description='Data structure synthesizer.') parser.add_argument("-S", "--save", metavar="FILE", type=str, default=None, help="Save synthesis output") parser.add_argument("-R", "--resume", action="store_true", help="Resume from saved synthesis output") parser.add_argument( "-t", "--timeout", metavar="N", type=float, default=60, help="Per-query synthesis timeout (in seconds); default=60") parser.add_argument( "-s", "--simple", action="store_true", help= "Do not synthesize improved solution; use the most trivial implementation of the spec" ) parser.add_argument("-p", "--port", metavar="P", type=int, default=None, help="Port to run progress-showing HTTP server") java_opts = parser.add_argument_group("Java codegen") java_opts.add_argument( "--java", metavar="FILE.java", default=None, help="Output file for java classes, use '-' for stdout") java_opts.add_argument( "--unboxed", action="store_true", help= "Use unboxed primitives. NOTE: synthesized data structures may require GNU Trove (http://trove.starlight-systems.com/)" ) cxx_opts = parser.add_argument_group("C++ codegen") cxx_opts.add_argument( "--c++", metavar="FILE.h", default=None, help="Output file for C++ (header-only class), use '-' for stdout") cxx_opts.add_argument( "--use-qhash", action="store_true", help= "QHash---the Qt implementation of hash maps---often outperforms the default C++ map implementations" ) internal_opts = parser.add_argument_group("Internal parameters") opts.setup(internal_opts) parser.add_argument("file", nargs="?", default=None, help="Input file (omit to use stdin)") args = parser.parse_args() opts.read(args) if args.resume: if args.file is None: ast = pickle.load(sys.stdin.buffer) else: with open(args.file, "rb") as f: ast = pickle.load(f) print("Loaded implementation from {}".format( "stdin" if args.file is None else "file {}".format(args.file))) else: input_text = sys.stdin.read( ) if args.file is None else common.read_file(args.file) ast = parse.parse_spec(input_text) errors = typecheck.typecheck(ast) if errors: for e in errors: print("Error: {}".format(e)) sys.exit(1) ast = desugar.desugar(ast) ast = invariant_preservation.add_implicit_handle_assumptions(ast) print("Checking assumptions...") errors = (invariant_preservation.check_ops_preserve_invariants(ast) + invariant_preservation.check_the_wf(ast)) if errors: for e in errors: print("Error: {}".format(e)) sys.exit(1) print("Done!") ast = synthesis.construct_initial_implementation(ast) start = datetime.datetime.now() if not args.simple: callback = None server = None if checkpoint_prefix.value: def callback(res): impl, ast, state_map = res assert isinstance(impl, synthesis.Implementation) now = datetime.datetime.now() elapsed = now - start fname = "{}{:010d}.synthesized".format( checkpoint_prefix.value, int(elapsed.total_seconds())) with open(fname, "wb") as f: pickle.dump(impl, f) print("Saved checkpoint {}".format(fname)) if args.port: from cozy import progress_server state = ["Initializing..."] orig_callback = callback def callback(res): if orig_callback is not None: orig_callback(res) impl, ast, state_map = res s = "<!DOCTYPE html>\n" s += "<html>" s += "<head><style>" s += ".kw { color: #909; font-weight: bold; }" s += ".builtin { color: #009; font-weight: bold; }" s += ".comment { color: #999; }" s += "</style></head>" s += "<body><pre>" for v, e in state_map.items(): s += "{} : {} = {}\n".format( v, syntax_tools.pprint(e.type, format="html"), syntax_tools.pprint(e, format="html")) s += "\n" s += syntax_tools.pprint(ast, format="html") s += "</pre></body></html>" state[0] = s server = progress_server.ProgressServer(port=args.port, callback=lambda: state[0]) server.start_async() # Do full synthesis ast = synthesis.improve_implementation( ast, timeout=datetime.timedelta(seconds=args.timeout), progress_callback=callback) if server is not None: server.join() print("Generating IR...") code = ast.code print("Loading concretization functions...") state_map = ast.concretization_functions print() for v, e in state_map.items(): print("{} : {} = {}".format(v, syntax_tools.pprint(e.type), syntax_tools.pprint(e))) print() print(syntax_tools.pprint(code)) if args.save: with open(args.save, "wb") as f: pickle.dump(ast, f) print("Saved implementation to file {}".format(args.save)) impl = code share_info = defaultdict(list) if do_cse.value: impl = syntax_tools.inline_calls(impl) impl = syntax_tools.eliminate_common_subexpressions(impl) try: java = args.java if java is not None: with common.open_maybe_stdout(java) as out: codegen.JavaPrinter(out=out).render_complete( spec=impl, state_map=state_map, share_info=share_info, abstract_state=ast.spec.statevars) cxx = getattr(args, "c++") if cxx is not None: with common.open_maybe_stdout(cxx) as out: codegen.CxxPrinter(out=out, use_qhash=args.use_qhash).visit( impl, state_map, share_info, abstract_state=ast.spec.statevars) except: print("Code generation failed!") if save_failed_codegen_inputs.value: with open(save_failed_codegen_inputs.value, "w") as f: f.write("impl = {}\n".format(repr(impl))) f.write("state_map = {}\n".format(repr(state_map))) f.write("share_info = {}\n".format(repr(share_info))) print("Implementation was dumped to {}".format( save_failed_codegen_inputs.value)) raise