From 432f985dff420fe55a2023a8598291345afd4800 Mon Sep 17 00:00:00 2001 From: cmpatino Date: Tue, 3 Feb 2026 10:35:57 +0100 Subject: [PATCH 1/9] Fix issue with push-hf command The push-hf command was not working and returning an error related to "checkpoint_complete". --- src/tinker/cli/commands/checkpoint.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/tinker/cli/commands/checkpoint.py b/src/tinker/cli/commands/checkpoint.py index 3fdf87b..b7726ef 100644 --- a/src/tinker/cli/commands/checkpoint.py +++ b/src/tinker/cli/commands/checkpoint.py @@ -519,10 +519,13 @@ def _readme_tinker_path() -> str | None: f"Found {existing_tinker_path}, expected {tinker_path}.", ) + # Remove checkpoint_complete file before upload if no allow_patterns specified + # Workaround: huggingface_hub (which uses typer internally) conflicts with + # our Click-based CLI when "checkpoint_complete" is in ignore_patterns if allow_patterns is None: - ignore_patterns = list(ignore_patterns) if ignore_patterns else [] - if "checkpoint_complete" not in ignore_patterns: - ignore_patterns.append("checkpoint_complete") + checkpoint_complete_file = extract_dir / "checkpoint_complete" + if checkpoint_complete_file.exists(): + checkpoint_complete_file.unlink() api.upload_folder( folder_path=os.fspath(extract_dir), From c8fb4f5ee1f88524af0612d78d6ac7d03c8d9022 Mon Sep 17 00:00:00 2001 From: cmpatino Date: Tue, 3 Feb 2026 10:54:10 +0100 Subject: [PATCH 2/9] Enable creating revision in HF --- src/tinker/cli/commands/checkpoint.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/tinker/cli/commands/checkpoint.py b/src/tinker/cli/commands/checkpoint.py index b7726ef..0874f60 100644 --- a/src/tinker/cli/commands/checkpoint.py +++ b/src/tinker/cli/commands/checkpoint.py @@ -495,6 +495,19 @@ def _sanitize_repo_name(value: str) -> str: api.create_repo(repo_id=repo_id, private=private, exist_ok=exist_ok) + # Create the revision/branch if specified and it doesn't exist + if revision: + try: + # Check if the branch exists + refs = api.list_repo_refs(repo_id=repo_id) + branch_exists = any(ref.name == revision for ref in refs.branches) + if not branch_exists: + # Create the branch from main + api.create_branch(repo_id=repo_id, branch=revision, exist_ok=True) + except Exception: + # If we can't check or create the branch, try to proceed anyway + pass + def _readme_tinker_path() -> str | None: try: readme_file = hf_hub_download( From f49ac445ca6b39c86658f19dca18a9afc00fa0a9 Mon Sep 17 00:00:00 2001 From: cmpatino Date: Tue, 3 Feb 2026 11:11:17 +0100 Subject: [PATCH 3/9] Improve error logging when creating a HF revision --- src/tinker/cli/commands/checkpoint.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/tinker/cli/commands/checkpoint.py b/src/tinker/cli/commands/checkpoint.py index 0874f60..fd52d19 100644 --- a/src/tinker/cli/commands/checkpoint.py +++ b/src/tinker/cli/commands/checkpoint.py @@ -498,15 +498,15 @@ def _sanitize_repo_name(value: str) -> str: # Create the revision/branch if specified and it doesn't exist if revision: try: - # Check if the branch exists refs = api.list_repo_refs(repo_id=repo_id) branch_exists = any(ref.name == revision for ref in refs.branches) if not branch_exists: - # Create the branch from main api.create_branch(repo_id=repo_id, branch=revision, exist_ok=True) - except Exception: - # If we can't check or create the branch, try to proceed anyway - pass + except Exception as e: + raise TinkerCliError( + f"Failed to create branch {revision} in repo {repo_id}", + f"Error: {e}", + ) from e def _readme_tinker_path() -> str | None: try: From 34b44b27b8db55d06999a26b2cc168103a316045 Mon Sep 17 00:00:00 2001 From: cmpatino Date: Tue, 3 Feb 2026 11:31:18 +0100 Subject: [PATCH 4/9] Remove option to ignore_patterns from CLI --- src/tinker/cli/commands/checkpoint.py | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/src/tinker/cli/commands/checkpoint.py b/src/tinker/cli/commands/checkpoint.py index fd52d19..8085945 100644 --- a/src/tinker/cli/commands/checkpoint.py +++ b/src/tinker/cli/commands/checkpoint.py @@ -335,7 +335,6 @@ def _export_checkpoint_to_hub( create_pr: bool, exist_ok: bool, allow_patterns: list[str] | None, - ignore_patterns: list[str] | None, add_model_card: bool, ) -> str: # Lazy imports to keep CLI startup fast @@ -533,12 +532,9 @@ def _readme_tinker_path() -> str | None: ) # Remove checkpoint_complete file before upload if no allow_patterns specified - # Workaround: huggingface_hub (which uses typer internally) conflicts with - # our Click-based CLI when "checkpoint_complete" is in ignore_patterns if allow_patterns is None: checkpoint_complete_file = extract_dir / "checkpoint_complete" - if checkpoint_complete_file.exists(): - checkpoint_complete_file.unlink() + checkpoint_complete_file.unlink(missing_ok=True) api.upload_folder( folder_path=os.fspath(extract_dir), @@ -548,7 +544,6 @@ def _readme_tinker_path() -> str | None: commit_message=commit_message, create_pr=create_pr, allow_patterns=list(allow_patterns) if allow_patterns else None, - ignore_patterns=list(ignore_patterns) if ignore_patterns else None, ) return repo_id @@ -1019,12 +1014,6 @@ def download( multiple=True, help="Only upload files matching this pattern (can be repeated).", ) -@click.option( - "--ignore-pattern", - "ignore_patterns", - multiple=True, - help="Skip files matching this pattern (can be repeated).", -) @click.option( "--no-model-card", is_flag=True, @@ -1041,7 +1030,6 @@ def push_hf( commit_message: str | None, create_pr: bool, allow_patterns: tuple[str, ...], - ignore_patterns: tuple[str, ...], no_model_card: bool, ) -> None: """Upload a checkpoint to the Hugging Face Hub as a PEFT adapter. @@ -1066,7 +1054,6 @@ def push_hf( create_pr=create_pr, exist_ok=True, allow_patterns=list(allow_patterns) if allow_patterns else None, - ignore_patterns=list(ignore_patterns) if ignore_patterns else None, add_model_card=not no_model_card, ) From 2f38e0e41251dd4fe02c0ac58290df27c7f7260c Mon Sep 17 00:00:00 2001 From: cmpatino Date: Tue, 17 Feb 2026 15:26:11 +0100 Subject: [PATCH 5/9] Improve logic for revision upload to HF The command checks whether the target repository for the upload has a main branch. The previous logic left the main branch empty, which causes problems when using the model with transformers. The CLI now also exposes the `overwrite` arg to avoid overwriting a revision in HF without explicit approval from the user. --- src/tinker/cli/commands/checkpoint.py | 107 ++++++++++++++++---------- 1 file changed, 66 insertions(+), 41 deletions(-) diff --git a/src/tinker/cli/commands/checkpoint.py b/src/tinker/cli/commands/checkpoint.py index 8085945..0c07c46 100644 --- a/src/tinker/cli/commands/checkpoint.py +++ b/src/tinker/cli/commands/checkpoint.py @@ -336,10 +336,11 @@ def _export_checkpoint_to_hub( exist_ok: bool, allow_patterns: list[str] | None, add_model_card: bool, + overwrite: bool, ) -> str: # Lazy imports to keep CLI startup fast try: - from huggingface_hub import HfApi, hf_hub_download + from huggingface_hub import HfApi except ImportError as exc: raise TinkerCliError( "huggingface_hub is required for this command.", @@ -348,7 +349,6 @@ def _export_checkpoint_to_hub( import json import os - import re import tempfile from pathlib import Path @@ -494,57 +494,75 @@ def _sanitize_repo_name(value: str) -> str: api.create_repo(repo_id=repo_id, private=private, exist_ok=exist_ok) - # Create the revision/branch if specified and it doesn't exist - if revision: + # Helper function to get branch names + def _get_branch_names() -> set[str]: try: refs = api.list_repo_refs(repo_id=repo_id) - branch_exists = any(ref.name == revision for ref in refs.branches) - if not branch_exists: - api.create_branch(repo_id=repo_id, branch=revision, exist_ok=True) - except Exception as e: - raise TinkerCliError( - f"Failed to create branch {revision} in repo {repo_id}", - f"Error: {e}", - ) from e + return {ref.name for ref in refs.branches} + except Exception: + return set() - def _readme_tinker_path() -> str | None: - try: - readme_file = hf_hub_download( + # Create the revision/branch if specified and it doesn't exist + try: + branch_names = _get_branch_names() + target_revision = revision or "main" + uploaded_to_target = False + + # Ensure main branch has content if it doesn't exist + # Upload the actual checkpoint instead of a minimal README + if "main" not in branch_names: + api.upload_folder( + folder_path=os.fspath(extract_dir), repo_id=repo_id, - filename="README.md", - revision=revision, - token=None, + path_in_repo="", + revision="main", + commit_message=commit_message or "Upload checkpoint from Tinker", + create_pr=False, + allow_patterns=list(allow_patterns) if allow_patterns else None, ) - except Exception: - return None - try: - text = Path(readme_file).read_text(encoding="utf-8", errors="ignore") - except Exception: - return None - match = re.search(r"tinker://[^\s`]+", text) - return match.group(0) if match else None - - existing_tinker_path = _readme_tinker_path() - if existing_tinker_path and existing_tinker_path != tinker_path: + branch_names = _get_branch_names() + + if target_revision == "main": + # We've uploaded to the target already + uploaded_to_target = True + else: + # Create the target revision branch from main (which now has content) + # This avoids uploading the same content twice + if target_revision not in branch_names: + api.create_branch(repo_id=repo_id, branch=target_revision, exist_ok=True) + uploaded_to_target = True + else: + # Main exists, so we need to create the target branch if needed + if target_revision != "main" and target_revision not in branch_names: + api.create_branch(repo_id=repo_id, branch=target_revision, exist_ok=True) + except Exception as e: raise TinkerCliError( - "Repo ID appears to contain a different Tinker checkpoint.", - f"Found {existing_tinker_path}, expected {tinker_path}.", - ) + f"Failed to prepare revision {revision or 'main'} in repo {repo_id}", + f"Error: {e}", + ) from e # Remove checkpoint_complete file before upload if no allow_patterns specified if allow_patterns is None: checkpoint_complete_file = extract_dir / "checkpoint_complete" checkpoint_complete_file.unlink(missing_ok=True) - api.upload_folder( - folder_path=os.fspath(extract_dir), - repo_id=repo_id, - path_in_repo="", - revision=revision, - commit_message=commit_message, - create_pr=create_pr, - allow_patterns=list(allow_patterns) if allow_patterns else None, - ) + # Upload to target revision if we haven't already + if not uploaded_to_target: + # Check if we would be overwriting an existing branch + if not overwrite and target_revision in branch_names: + raise TinkerCliError( + f"Branch '{target_revision}' already exists in repo {repo_id}", + "Use --overwrite to replace the existing branch, or specify a different --revision", + ) + api.upload_folder( + folder_path=os.fspath(extract_dir), + repo_id=repo_id, + path_in_repo="", + revision=target_revision, + commit_message=commit_message, + create_pr=create_pr, + allow_patterns=list(allow_patterns) if allow_patterns else None, + ) return repo_id @@ -1019,6 +1037,11 @@ def download( is_flag=True, help="Do not create a README.md model card if one is missing.", ) +@click.option( + "--overwrite", + is_flag=True, + help="Allow overwriting an existing branch (default: False).", +) @click.pass_obj @handle_api_errors def push_hf( @@ -1031,6 +1054,7 @@ def push_hf( create_pr: bool, allow_patterns: tuple[str, ...], no_model_card: bool, + overwrite: bool, ) -> None: """Upload a checkpoint to the Hugging Face Hub as a PEFT adapter. @@ -1055,6 +1079,7 @@ def push_hf( exist_ok=True, allow_patterns=list(allow_patterns) if allow_patterns else None, add_model_card=not no_model_card, + overwrite=overwrite, ) output_obj = CheckpointHubUploadOutput( From 780c5ba9e317e959178644b26419f43bb4479db3 Mon Sep 17 00:00:00 2001 From: cmpatino Date: Tue, 17 Feb 2026 15:31:54 +0100 Subject: [PATCH 6/9] Avoid redefining variable when deleting file --- src/tinker/cli/commands/checkpoint.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/tinker/cli/commands/checkpoint.py b/src/tinker/cli/commands/checkpoint.py index 0c07c46..2968993 100644 --- a/src/tinker/cli/commands/checkpoint.py +++ b/src/tinker/cli/commands/checkpoint.py @@ -543,8 +543,7 @@ def _get_branch_names() -> set[str]: # Remove checkpoint_complete file before upload if no allow_patterns specified if allow_patterns is None: - checkpoint_complete_file = extract_dir / "checkpoint_complete" - checkpoint_complete_file.unlink(missing_ok=True) + checkpoint_complete.unlink(missing_ok=True) # Upload to target revision if we haven't already if not uploaded_to_target: From 8d125017cb3e841e15ffbac2c46ea6583d47f977 Mon Sep 17 00:00:00 2001 From: cmpatino Date: Tue, 17 Feb 2026 15:41:22 +0100 Subject: [PATCH 7/9] Clean comments and simplify logic --- src/tinker/cli/commands/checkpoint.py | 22 +++++----------------- 1 file changed, 5 insertions(+), 17 deletions(-) diff --git a/src/tinker/cli/commands/checkpoint.py b/src/tinker/cli/commands/checkpoint.py index 2968993..7659b95 100644 --- a/src/tinker/cli/commands/checkpoint.py +++ b/src/tinker/cli/commands/checkpoint.py @@ -494,7 +494,6 @@ def _sanitize_repo_name(value: str) -> str: api.create_repo(repo_id=repo_id, private=private, exist_ok=exist_ok) - # Helper function to get branch names def _get_branch_names() -> set[str]: try: refs = api.list_repo_refs(repo_id=repo_id) @@ -502,14 +501,11 @@ def _get_branch_names() -> set[str]: except Exception: return set() - # Create the revision/branch if specified and it doesn't exist try: branch_names = _get_branch_names() target_revision = revision or "main" uploaded_to_target = False - # Ensure main branch has content if it doesn't exist - # Upload the actual checkpoint instead of a minimal README if "main" not in branch_names: api.upload_folder( folder_path=os.fspath(extract_dir), @@ -523,31 +519,23 @@ def _get_branch_names() -> set[str]: branch_names = _get_branch_names() if target_revision == "main": - # We've uploaded to the target already uploaded_to_target = True else: - # Create the target revision branch from main (which now has content) - # This avoids uploading the same content twice if target_revision not in branch_names: api.create_branch(repo_id=repo_id, branch=target_revision, exist_ok=True) uploaded_to_target = True - else: - # Main exists, so we need to create the target branch if needed - if target_revision != "main" and target_revision not in branch_names: - api.create_branch(repo_id=repo_id, branch=target_revision, exist_ok=True) - except Exception as e: + elif target_revision != "main" and target_revision not in branch_names: + api.create_branch(repo_id=repo_id, branch=target_revision, exist_ok=True) + except Exception as exc: raise TinkerCliError( f"Failed to prepare revision {revision or 'main'} in repo {repo_id}", - f"Error: {e}", - ) from e + f"Error: {exc}", + ) from exc - # Remove checkpoint_complete file before upload if no allow_patterns specified if allow_patterns is None: checkpoint_complete.unlink(missing_ok=True) - # Upload to target revision if we haven't already if not uploaded_to_target: - # Check if we would be overwriting an existing branch if not overwrite and target_revision in branch_names: raise TinkerCliError( f"Branch '{target_revision}' already exists in repo {repo_id}", From 168137bb65f0555f07c59b628e42f89984ea56b7 Mon Sep 17 00:00:00 2001 From: cmpatino Date: Tue, 17 Feb 2026 15:50:35 +0100 Subject: [PATCH 8/9] Improve docs and warnings --- src/tinker/cli/commands/checkpoint.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/tinker/cli/commands/checkpoint.py b/src/tinker/cli/commands/checkpoint.py index 7659b95..c46c34e 100644 --- a/src/tinker/cli/commands/checkpoint.py +++ b/src/tinker/cli/commands/checkpoint.py @@ -507,6 +507,12 @@ def _get_branch_names() -> set[str]: uploaded_to_target = False if "main" not in branch_names: + if create_pr: + click.echo( + "Warning: --create-pr was requested, but this upload is creating a new repository. " + "Uploading content to 'main' without a PR.", + err=True, + ) api.upload_folder( folder_path=os.fspath(extract_dir), repo_id=repo_id, @@ -539,7 +545,8 @@ def _get_branch_names() -> set[str]: if not overwrite and target_revision in branch_names: raise TinkerCliError( f"Branch '{target_revision}' already exists in repo {repo_id}", - "Use --overwrite to replace the existing branch, or specify a different --revision", + "Use --overwrite to add a new commit to the existing branch, " + "or specify a different --revision", ) api.upload_folder( folder_path=os.fspath(extract_dir), @@ -1027,7 +1034,7 @@ def download( @click.option( "--overwrite", is_flag=True, - help="Allow overwriting an existing branch (default: False).", + help="Allow uploading a new commit to an existing branch (default: False).", ) @click.pass_obj @handle_api_errors @@ -1046,6 +1053,8 @@ def push_hf( """Upload a checkpoint to the Hugging Face Hub as a PEFT adapter. CHECKPOINT_PATH must be a tinker path (e.g., tinker://run-id/sampler_weights/0001). + If --overwrite is set and the target branch exists, this command uploads a new commit + to that branch (it does not replace branch history). """ # Validate it's a tinker path if not checkpoint_path.startswith("tinker://"): From c5f593bfe37205382c0cb970f262583bffce901a Mon Sep 17 00:00:00 2001 From: cmpatino Date: Tue, 17 Feb 2026 20:24:20 +0100 Subject: [PATCH 9/9] Fix overwrite logic when repo didn't exist --- src/tinker/cli/commands/checkpoint.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/tinker/cli/commands/checkpoint.py b/src/tinker/cli/commands/checkpoint.py index c46c34e..4102de9 100644 --- a/src/tinker/cli/commands/checkpoint.py +++ b/src/tinker/cli/commands/checkpoint.py @@ -492,7 +492,13 @@ def _sanitize_repo_name(value: str) -> str: model_card.append("") readme_path.write_text("\n".join(model_card), encoding="utf-8") - api.create_repo(repo_id=repo_id, private=private, exist_ok=exist_ok) + if api.repo_exists(repo_id=repo_id): + repo_was_created = False + if not exist_ok: + raise TinkerCliError(f"Repository {repo_id} already exists") + else: + api.create_repo(repo_id=repo_id, private=private, exist_ok=False) + repo_was_created = True def _get_branch_names() -> set[str]: try: @@ -542,7 +548,7 @@ def _get_branch_names() -> set[str]: checkpoint_complete.unlink(missing_ok=True) if not uploaded_to_target: - if not overwrite and target_revision in branch_names: + if not repo_was_created and not overwrite and target_revision in branch_names: raise TinkerCliError( f"Branch '{target_revision}' already exists in repo {repo_id}", "Use --overwrite to add a new commit to the existing branch, "