From 52661e5b5cf7a5393452af886d11b98de1501834 Mon Sep 17 00:00:00 2001 From: Tsvika Shapira Date: Thu, 25 Dec 2025 19:07:57 +0200 Subject: [PATCH] refactor: use Path convenience methods for file operations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Simplified file reading patterns by using Path.read_text() instead of with path.open() as f: f.read(). This makes the code more concise and Pythonic while maintaining the same functionality. Changes: - Replace path.open().read() with path.read_text() - Replace yaml.safe_load(f) with yaml.safe_load(path.read_text()) - Eliminate redundant file reads in configurator.py (read file once) - Reduce code by 10 lines overall All changes preserve existing behavior and encoding specifications. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 --- dev/gen_synthetic_data.py | 4 ++-- nanochat/configurator.py | 7 +++---- nanochat/report.py | 16 +++++++--------- scripts/base_loss.py | 3 +-- scripts/base_train.py | 3 +-- scripts/chat_rl.py | 3 +-- scripts/chat_sft.py | 3 +-- scripts/chat_web.py | 3 +-- scripts/mid_train.py | 3 +-- 9 files changed, 18 insertions(+), 27 deletions(-) diff --git a/dev/gen_synthetic_data.py b/dev/gen_synthetic_data.py index d17df705..2e9117c6 100644 --- a/dev/gen_synthetic_data.py +++ b/dev/gen_synthetic_data.py @@ -37,7 +37,7 @@ from pathlib import Path from nanochat.common import get_base_dir -api_key = Path("openroutertoken.txt").open("r", encoding="utf-8").read().strip() +api_key = Path("openroutertoken.txt").read_text(encoding="utf-8").strip() url = "https://openrouter.ai/api/v1/chat/completions" headers = { @@ -45,7 +45,7 @@ headers = { "Content-Type": "application/json" } -readme = Path("README.md").open("r", encoding="utf-8").read().strip() +readme = Path("README.md").read_text(encoding="utf-8").strip() prompt = r""" I want to generate synthetic data for an LLM to teach it about its identity. Here is the identity I want: diff --git a/nanochat/configurator.py b/nanochat/configurator.py index 231a3b8f..4e59604f 100644 --- a/nanochat/configurator.py +++ b/nanochat/configurator.py @@ -30,10 +30,9 @@ for arg in sys.argv[1:]: assert not arg.startswith('--') config_file = Path(arg) print0(f"Overriding config with {config_file}:") - with config_file.open() as f: - print0(f.read()) - with config_file.open() as f: - exec(f.read()) + config_content = config_file.read_text() + print0(config_content) + exec(config_content) else: # assume it's a --key=value argument assert arg.startswith('--') diff --git a/nanochat/report.py b/nanochat/report.py index dcde337c..32dc028a 100644 --- a/nanochat/report.py +++ b/nanochat/report.py @@ -278,13 +278,12 @@ class Report: # write the header first header_file = report_dir / "header.md" if header_file.exists(): - with header_file.open("r", encoding="utf-8") as f: - header_content = f.read() - out_file.write(header_content) - start_time = extract_timestamp(header_content, "Run started:") - # capture bloat data for summary later (the stuff after Bloat header and until \n\n) - bloat_data = re.search(r"### Bloat\n(.*?)\n\n", header_content, re.DOTALL) - bloat_data = bloat_data.group(1) if bloat_data else "" + header_content = header_file.read_text(encoding="utf-8") + out_file.write(header_content) + start_time = extract_timestamp(header_content, "Run started:") + # capture bloat data for summary later (the stuff after Bloat header and until \n\n) + bloat_data = re.search(r"### Bloat\n(.*?)\n\n", header_content, re.DOTALL) + bloat_data = bloat_data.group(1) if bloat_data else "" else: start_time = None # will cause us to not write the total wall clock time bloat_data = "[bloat data missing]" @@ -295,8 +294,7 @@ class Report: if not section_file.exists(): print(f"Warning: {section_file} does not exist, skipping") continue - with section_file.open("r", encoding="utf-8") as in_file: - section = in_file.read() + section = section_file.read_text(encoding="utf-8") # Extract timestamp from this section (the last section's timestamp will "stick" as end_time) if "rl" not in file_name: # Skip RL sections for end_time calculation because RL is experimental diff --git a/scripts/base_loss.py b/scripts/base_loss.py index f46b2155..ea4ef9c2 100644 --- a/scripts/base_loss.py +++ b/scripts/base_loss.py @@ -22,8 +22,7 @@ split_tokens = 20*524288 # number of tokens to evaluate per split model_tag = None # optional model tag for the output directory name model_step = None # optional model step for the output directory name device_type = "" # cuda|cpu|mps (empty => autodetect) -with (Path('nanochat') / 'configurator.py').open() as f: - exec(f.read()) # overrides from command line or config file +exec((Path('nanochat') / 'configurator.py').read_text()) # overrides from command line or config file # Load the base model and the tokenizer device_type = autodetect_device_type() if device_type == "" else device_type diff --git a/scripts/base_train.py b/scripts/base_train.py index 4520c97e..5e1137a9 100644 --- a/scripts/base_train.py +++ b/scripts/base_train.py @@ -66,8 +66,7 @@ model_tag = "" # optionally override the model tag for the output checkpoint dir # now allow CLI to override the settings via the configurator lol config_keys = [k for k,v in globals().items() if not k.startswith('_') and isinstance(v, (int, float, bool, str))] configurator_path = Path('nanochat') / 'configurator.py' -with configurator_path.open() as f: - exec(f.read()) # overrides from command line or config file +exec(configurator_path.read_text()) # overrides from command line or config file user_config = {k: globals()[k] for k in config_keys} # will be useful for logging # ----------------------------------------------------------------------------- diff --git a/scripts/chat_rl.py b/scripts/chat_rl.py index e2526dc7..53e1a82f 100644 --- a/scripts/chat_rl.py +++ b/scripts/chat_rl.py @@ -49,8 +49,7 @@ eval_examples = 400 # number of examples used for evaluating pass@k # now allow CLI to override the settings via the configurator lol config_keys = [k for k,v in globals().items() if not k.startswith('_') and isinstance(v, (int, float, bool, str))] configurator_path = Path('nanochat') / 'configurator.py' -with configurator_path.open() as f: - exec(f.read()) # overrides from command line or config file +exec(configurator_path.read_text()) # overrides from command line or config file user_config = {k: globals()[k] for k in config_keys} # will be useful for logging # ----------------------------------------------------------------------------- diff --git a/scripts/chat_sft.py b/scripts/chat_sft.py index a7cbe64f..d5fc507a 100644 --- a/scripts/chat_sft.py +++ b/scripts/chat_sft.py @@ -59,8 +59,7 @@ eval_metrics_max_problems = 1024 # now allow CLI to override the settings via the configurator lol config_keys = [k for k,v in globals().items() if not k.startswith('_') and isinstance(v, (int, float, bool, str))] configurator_path = Path('nanochat') / 'configurator.py' -with configurator_path.open() as f: - exec(f.read()) # overrides from command line or config file +exec(configurator_path.read_text()) # overrides from command line or config file user_config = {k: globals()[k] for k in config_keys} # possibly useful for logging # ----------------------------------------------------------------------------- diff --git a/scripts/chat_web.py b/scripts/chat_web.py index 2e10f0d2..6261b458 100644 --- a/scripts/chat_web.py +++ b/scripts/chat_web.py @@ -243,8 +243,7 @@ app.add_middleware( async def root(): """Serve the chat UI.""" ui_html_path = Path("nanochat") / "ui.html" - with ui_html_path.open("r", encoding="utf-8") as f: - html_content = f.read() + html_content = ui_html_path.read_text(encoding="utf-8") # Replace the API_URL to use the same origin html_content = html_content.replace( "const API_URL = `http://${window.location.hostname}:8000`;", diff --git a/scripts/mid_train.py b/scripts/mid_train.py index bd76c7f8..c6b51054 100644 --- a/scripts/mid_train.py +++ b/scripts/mid_train.py @@ -51,8 +51,7 @@ total_batch_size = 524288 dry_run = 0 # dry_run=1 is for experiments: we will log to wandb but we won't write checkpoints or report config_keys = [k for k,v in globals().items() if not k.startswith('_') and isinstance(v, (int, float, bool, str))] configurator_path = Path('nanochat') / 'configurator.py' -with configurator_path.open() as f: - exec(f.read()) # overrides from command line or config file +exec(configurator_path.read_text()) # overrides from command line or config file user_config = {k: globals()[k] for k in config_keys} # possibly useful for logging # -----------------------------------------------------------------------------