Example Hub and Local Operation Collections#
This notebook demonstrates the complete workflow for uploading and downloading operations collections using the
HubAnalysisOpManager and loading local operations via IT_ANALYSIS_OP_PATHS. The workflow includes:
Setting up local op collection path via IT_ANALYSIS_OP_PATHS
Copying the current hub_op_collection folder to /tmp/
Uploading operations to HuggingFace Hub as a private repository
Downloading the uploaded collection to the default cache
Re-importing interpretune to verify both hub and local operations are available
Testing the loaded operations
Cleaning up downloaded operations and re-importing
Verifying only local operations remain available
Final cleanup of the local operations collection
**Note**: This example requires HuggingFace Hub authentication and will create a private repository.
Setup and Imports#
import os
from pathlib import Path
# Import interpretune components
import interpretune
from interpretune.analysis.ops.hub_manager import HubAnalysisOpManager
from interpretune.analysis import IT_ANALYSIS_CACHE, IT_ANALYSIS_HUB_CACHE, IT_ANALYSIS_OP_PATHS, IT_MODULES_CACHE
from interpretune.base.components.cli import IT_BASE
# Import utility functions for op collection demo setup/cleanup
import it_examples.notebooks.publish.example_op_collections.op_collection_demo_utils as op_demo_utils
example_op_collections_dir = Path(IT_BASE / "notebooks" / "publish" / "example_op_collections")
example_hub_op_collection_dir = Path(example_op_collections_dir / "hub_op_collection")
example_local_op_collection_dir = Path(example_op_collections_dir / "local_op_collection")
# Print environment summary
op_demo_utils.print_env_summary(
interpretune.version,
IT_ANALYSIS_CACHE,
IT_MODULES_CACHE,
IT_ANALYSIS_HUB_CACHE,
IT_ANALYSIS_OP_PATHS,
example_hub_op_collection_dir,
example_local_op_collection_dir,
)
Interpretune version: <function version at 0x7f93c6a1ab60>
Current analysis cache location: /mnt/cache_extended/speediedan/.cache/huggingface/interpretune
Current modules cache location: /mnt/cache_extended/speediedan/.cache/huggingface/interpretune/modules
Current hub cache location: /mnt/cache_extended/speediedan/.cache/huggingface/hub/interpretune_ops
Current IT analysis op paths: []
This notebook's example hub op collection directory: /home/speediedan/repos/interpretune/src/it_examples/notebooks/publish/example_op_collections/hub_op_collection
This notebook's example local op collection directory: /home/speediedan/repos/interpretune/src/it_examples/notebooks/publish/example_op_collections/local_op_collection
Step 1: Stage example local op collections to a temporary directory#
Copy the local_op_collection to /tmp/ and add it to IT_ANALYSIS_OP_PATHS so local operations are loaded.
# Define source and destination paths for local ops
source_local_op_collection = example_local_op_collection_dir
tmp_local_op_collection = Path("/tmp/local_op_collection")
# copy our local op collection to `tmp_local_op_collection` and that path to our IT_ANALYSIS_OP_PATHS env var
original_op_paths_env, new_op_paths = op_demo_utils.setup_local_op_collection(
source_local_op_collection=source_local_op_collection, tmp_local_op_collection=tmp_local_op_collection
)
Source local op_collection: /home/speediedan/repos/interpretune/src/it_examples/notebooks/publish/example_op_collections/local_op_collection
Destination: /tmp/local_op_collection
✓ Successfully copied local op_collection to /tmp/local_op_collection
Original IT_ANALYSIS_OP_PATHS environment variable: ''
✓ Set IT_ANALYSIS_OP_PATHS environment variable to: '/tmp/local_op_collection'
✓ Also added /tmp/local_op_collection to imported IT_ANALYSIS_OP_PATHS list
Updated IT_ANALYSIS_OP_PATHS list: ['/tmp/local_op_collection']
Current IT_ANALYSIS_OP_PATHS env var: '/tmp/local_op_collection'
Contents of copied local op_collection:
- local_op_definitions.py
- local_op_collection.yaml
Step 2: Copy hub op_collection to /tmp/#
Copy the hub op_collection folder to /tmp/ for upload to the hub.
# Define source and destination paths for hub ops
source_op_collection = example_hub_op_collection_dir
tmp_op_collection = Path("/tmp/hub_op_collection")
# Stage a hub op collection using utility function
op_demo_utils.setup_hub_op_collection(source_op_collection=source_op_collection, tmp_op_collection=tmp_op_collection)
Source hub op_collection: /home/speediedan/repos/interpretune/src/it_examples/notebooks/publish/example_op_collections/hub_op_collection
Destination: /tmp/hub_op_collection
✓ Successfully copied hub op_collection to /tmp/hub_op_collection
Contents of copied hub op_collection:
- hub_op_collection.yaml
- hub_op_definitions.py
Step 3: Upload operations to HuggingFace Hub#
Upload the hub op_collection to HuggingFace Hub as a private repository named “trivial_op_repo”.
from huggingface_hub import whoami
# Resolve HF token: try dedicated key first, then standard HF_TOKEN, then interactive login.
hub_token = os.environ.get("HF_TRIVIAL_OP_REPO_EXAMPLE_AUTH_KEY") or os.environ.get("HF_TOKEN")
if not hub_token:
from huggingface_hub import notebook_login
notebook_login()
hub_token = os.environ.get("HF_TOKEN") # notebook_login sets HF_TOKEN
current_user = whoami(token=hub_token)["name"]
# Initialize the hub manager with the resolved token
hub_manager = HubAnalysisOpManager(token=hub_token)
# Repository configuration
repo_name = "trivial_op_repo"
private = True
print("Uploading op_collection to HuggingFace Hub...")
print(f"Current HF user: {current_user}")
print(f"Repository: {repo_name}")
print(f"Private: {private}")
print(f"Source folder: {tmp_op_collection}")
# Ensure the user is authenticated
repo_id = f"{current_user}/{repo_name}"
try:
# Upload operations to hub
# 1. This will create the specified repository if it doesn't exist
# 2. If the repo exists, it will clean existing operations and upload the new ones in a single commit
# - If no files have changed, it will skip the commit and leave the repository unchanged
upload_result = hub_manager.upload_ops(
local_dir=tmp_op_collection, repo_id=repo_id, private=private, clean_existing=True
)
print(f"\u2713 Successfully uploaded operations (if necessary) to {repo_name}")
print(f"Upload result (new or latest op repo commit sha): {upload_result}")
except Exception as e:
print(f"\u274c Error uploading operations: {e}")
raise
Uploading op_collection to HuggingFace Hub...
Current HF user: speediedan
Repository: trivial_op_repo
Private: True
Source folder: /tmp/hub_op_collection
✓ Successfully uploaded operations (if necessary) to trivial_op_repo
Upload result (new or latest op repo commit sha): 66f9e0cc2c6d9b792bbc5020c5ae20cffb6b8934
No files have been modified since last commit. Skipping to prevent empty commit.
Step 4: Download operations to default hub cache#
Download the uploaded operations collection to the default IT_ANALYSIS_HUB_CACHE location.
print(f"Downloading operations from {repo_id} to default cache...")
print(f"Cache location: {IT_ANALYSIS_HUB_CACHE}")
# Initialize download_result to None so we can safely check it in cleanup step
download_result = None
try:
# Download operations from hub to default cache
download_result = hub_manager.download_ops(repo_id=repo_id) # no cache_dir default IT_ANALYSIS_HUB_CACHE is used
print("✓ Successfully downloaded operations to cache")
print(f"Download result: {download_result}")
# Check what was downloaded
cache_path = Path(IT_ANALYSIS_HUB_CACHE)
if cache_path.exists():
print("\nContents of hub cache:")
for item in cache_path.rglob("*"):
if item.is_file():
rel_path = item.relative_to(cache_path)
print(f" - {rel_path}")
except Exception as e:
print(f"❌ Error downloading operations: {e}")
raise
Downloading operations from speediedan/trivial_op_repo to default cache...
Cache location: /mnt/cache_extended/speediedan/.cache/huggingface/hub/interpretune_ops
✓ Successfully downloaded operations to cache
Download result: HubOpCollection(repo_id='speediedan/trivial_op_repo', username='speediedan', repo_name='trivial_op_repo', local_path=PosixPath('/mnt/cache_extended/speediedan/.cache/huggingface/hub/interpretune_ops/models--speediedan--trivial_op_repo/snapshots/66f9e0cc2c6d9b792bbc5020c5ae20cffb6b8934'), revision='main')
Contents of hub cache:
- models--speediedan--trivial_op_repo/refs/main
- models--speediedan--trivial_op_repo/blobs/d3a1af9f8d6af798898c9c3fb510335840b8892f
- models--speediedan--trivial_op_repo/blobs/a6344aac8c09253b3b630fb776ae94478aa0275b
- models--speediedan--trivial_op_repo/blobs/7b95401dc46245ac339fc25059d4a56d90b4cde5
- models--speediedan--trivial_op_repo/blobs/0c9a339e3604787df9cdb0e59cff48e3481b1370
- models--speediedan--trivial_op_repo/blobs/a88c06240bbf197b5030361d8601ac94d41273cc
- models--speediedan--trivial_op_repo/snapshots/66f9e0cc2c6d9b792bbc5020c5ae20cffb6b8934/hub_op_definitions.py
- models--speediedan--trivial_op_repo/snapshots/66f9e0cc2c6d9b792bbc5020c5ae20cffb6b8934/.gitattributes
- models--speediedan--trivial_op_repo/snapshots/66f9e0cc2c6d9b792bbc5020c5ae20cffb6b8934/README.md
- models--speediedan--trivial_op_repo/snapshots/66f9e0cc2c6d9b792bbc5020c5ae20cffb6b8934/hub_op_collection.yaml
- models--speediedan--trivial_op_repo/snapshots/66f9e0cc2c6d9b792bbc5020c5ae20cffb6b8934/__pycache__/hub_op_definitions.cpython-310.pyc
- .locks/models--speediedan--trivial_op_repo/c68fb334d3f79897fb401c712fe5842b426a090e.lock
- .locks/models--speediedan--trivial_op_repo/730c649faee83eba503022680e3ba25d1dac1869.lock
- .locks/models--speediedan--trivial_op_repo/3600a180683366a0958f528646f1807432a29bd7.lock
- .locks/models--speediedan--trivial_op_repo/68e45efe2690af6547f00c85fdf2b0c3246475a6.lock
- .locks/models--speediedan--trivial_op_repo/c0df4fea470bb73756130fe1647b61a4cfa103d7.lock
- .locks/models--speediedan--trivial_op_repo/ac03bc96098cfcb07a9b4ad699c8e61d7abc20b6.lock
- .locks/models--speediedan--trivial_op_repo/2f07dedfaf6b0931ffce732008d50ef8d618e1f5.lock
- .locks/models--speediedan--trivial_op_repo/8404f2975e97cf974ba01d02ddc40583e9b1277b.lock
- .locks/models--speediedan--trivial_op_repo/9f57e62abbbd4cf3cb0659d478526cc1aa1cddc9.lock
- .locks/models--speediedan--trivial_op_repo/43194e6247d09dba781653b7094e7f059130f540.lock
- .locks/models--speediedan--trivial_op_repo/814e7a81ede3c895fef998c58d08dac3e1b49b46.lock
- .locks/models--speediedan--trivial_op_repo/82e04d7a174cd438780c43b7cdd2c2a9de36968f.lock
- .locks/models--speediedan--trivial_op_repo/81bc1c8d053116a09cbe67552a7774d0e023080b.lock
Step 5: Re-import interpretune and verify hub and local operations#
Re-import interpretune to pick up both hub and local operations and verify they are available.
print("Re-importing interpretune to pick up hub and local operations...")
# Remove interpretune modules from sys.modules to force reimport
op_demo_utils.purge_it_modules_from_sys()
# ruff: noqa: E402
# Re-import interpretune
import interpretune as it
from interpretune import DISPATCHER
print("✓ Interpretune re-imported")
# Get operation definitions and generate summary
operation_definitions = DISPATCHER.registered_ops
op_demo_utils.generate_op_summary(operation_definitions)
# Show operations by type
canonical_ops, alias_map, hub_ops, local_ops, composed_ops, builtin_ops = op_demo_utils.categorize_operations(
operation_definitions
)
# Demo lazy operation instantiation
op_demo_utils.demo_lazy_op_instantiation(it, hub_ops, local_ops)
Re-importing interpretune to pick up hub and local operations...
✓ Interpretune re-imported
📊 Operation Summary:
Total registered names: 45
Unique operations: 32
Hub operations: 1
Local operations: 10
Composed operations: 8
Built-in operations: 13
🌐 Hub operations found:
- speediedan.trivial_op_repo.trivial_test_op (accessible as: speediedan.trivial_op_repo.trivial_test_op, trivial_test_op)
🏠 Local operations found:
- extract_concept_latent_state (accessible as: extract_concept_latent_state, concept_latent_state_from_cache) - Extract per-example latent rows from the configured cache key
- extract_concept_latent_examples (accessible as: extract_concept_latent_examples, concept_latent_examples) - Filter and annotate latent rows for concept-direction aggregation
- concept_direction (accessible as: concept_direction, semantic_direction) - Aggregate latent concept examples into a normalized concept direction vector
- compute_attribution_graph (accessible as: compute_attribution_graph, ct_graph) - Generate an attribution graph with circuit-tracer
- extract_top_features (accessible as: extract_top_features, ct_top_features) - Extract top-N influential features from an attribution graph
- graph_prune (accessible as: graph_prune, ct_graph_prune) - Prune a circuit-tracer attribution graph
- graph_node_influence (accessible as: graph_node_influence, ct_node_influence) - Compute node influence scores for an attribution graph
- feature_intervention_forward (accessible as: feature_intervention_forward, ct_feature_intervention) - Run feature interventions and return pre/post intervention outputs
- model_fwd_intervention (accessible as: model_fwd_intervention, direction_intervention, direct_concept_direction_intervention) - Apply generalized hook-point interventions and return pre/post intervention logits
- trivial_local_test_op (accessible as: trivial_local_test_op) - Local test op that transforms a simple orig_labels tensor to a preds tensor
🔧 Testing operation instantiation:
labels_to_ids op reference type: <class 'interpretune.analysis.ops.base.OpWrapper'>
get_answer_indices op reference type: <class 'interpretune.analysis.ops.base.OpWrapper'>
trivial_test_op op reference type: <class 'interpretune.analysis.ops.base.OpWrapper'>
Get non-direct access attribute of labels_to_ids (description of the underlying AnalysisOp): Convert label strings to tensor IDs
Type of labels_to_ids now: <class 'interpretune.analysis.ops.base.AnalysisOp'>
Type of get_answer_indices is still: <class 'interpretune.analysis.ops.base.OpWrapper'> and its instantiated status is False
Non-direct access attribute of get_answer_indices (name of the underlying AnalysisOp): get_answer_indices
Type of get_answer_indices is now: <class 'interpretune.analysis.ops.base.AnalysisOp'>
Type of trivial_test_op is: <class 'interpretune.analysis.ops.base.OpWrapper'> and its instantiated status is False
Non-direct access attribute of trivial_test_op (name of the underlying AnalysisOp): trivial_test_op
Type of trivial_test_op is now: <class 'interpretune.analysis.ops.base.AnalysisOp'> as it has been successfully instantiated
Non-direct access attribute of trivial_local_test_op (name of the underlying AnalysisOp): trivial_local_test_op
Type of trivial_local_test_op is now: <class 'interpretune.analysis.ops.base.AnalysisOp'> as it has been successfully instantiated
speediedan.trivial_op_repo.trivial_test_op op reference type: <class 'interpretune.analysis.ops.base.OpWrapper'>
extract_concept_latent_state op reference type: <class 'interpretune.analysis.ops.base.OpWrapper'>
Overwriting format type 'interpretune' (ITAnalysisFormatter -> ITAnalysisFormatter)
Overwriting format type alias 'itanalysis' (interpretune -> interpretune)
Overwriting format type alias 'it' (interpretune -> interpretune)
Overwriting format type alias 'interpretune' (interpretune -> interpretune)
Step 6: Test executing the loaded operations#
Test executing simple hub and local operations both individually executed and as part of a composite operation to ensure loading and execution works correctly.
print("\n🧪 Testing loaded operations with demo data...")
# Import required components
from interpretune import trivial_test_op, trivial_local_test_op, composite_trivial_test_op
NUM_BATCHES = 2 # Number of test batches to generate
VERBOSE_OP_OUTPUTS = False # Set to True to log operation outputs
# Test the operations
print(f"\n📋 Testing operation pipeline parity of composite vs individual component ops (over {NUM_BATCHES} batches):")
individual_op_output_batches = []
composite_op_output_batches = []
for batch_name, individual_test_batch, composite_test_batch in op_demo_utils.generate_test_batches(NUM_BATCHES):
print("\nComposite op execution...")
if VERBOSE_OP_OUTPUTS:
print(f"\n--- {batch_name} ---")
print(f"Input batch: {individual_test_batch}")
composite_output_batch = composite_trivial_test_op(analysis_batch=composite_test_batch)
op_demo_utils.maybe_print_output(f"Composite op output batch: {composite_output_batch}", VERBOSE_OP_OUTPUTS)
composite_op_output_batches.append(composite_output_batch)
print("\nRe-running with individual component ops...")
local_batch_output = trivial_local_test_op(analysis_batch=individual_test_batch)
op_demo_utils.maybe_print_output(f"Local op batch output: {local_batch_output}", VERBOSE_OP_OUTPUTS)
individual_output_batch = trivial_test_op(analysis_batch=local_batch_output)
op_demo_utils.maybe_print_output(f"Hub output batch: {individual_output_batch}", VERBOSE_OP_OUTPUTS)
individual_op_output_batches.append(individual_output_batch)
# Compare outputs using utility function
all_match = op_demo_utils.compare_operation_outputs(individual_op_output_batches, composite_op_output_batches)
🧪 Testing loaded operations with demo data...
📋 Testing operation pipeline parity of composite vs individual component ops (over 2 batches):
Composite op execution...
Local op: Converted orig_labels tensor([4, 3, 1, 2]) to preds tensor([5, 4, 2, 3])
Hub op: Calculated pred_sum: 14
Re-running with individual component ops...
Local op: Converted orig_labels tensor([4, 3, 1, 2]) to preds tensor([5, 4, 2, 3])
Hub op: Calculated pred_sum: 14
Composite op execution...
Local op: Converted orig_labels tensor([3, 0, 1, 4]) to preds tensor([4, 1, 2, 5])
Hub op: Calculated pred_sum: 12
Re-running with individual component ops...
Local op: Converted orig_labels tensor([3, 0, 1, 4]) to preds tensor([4, 1, 2, 5])
Hub op: Calculated pred_sum: 12
🔍 Validating that composite and individual component op outputs are identical...
✓ Batch 1: Outputs match.
✓ Batch 2: Outputs match.
🎉 All batches match: individual and composite operation outputs are identical!
Step 7: Clean up hub operations and re-import#
Delete the downloaded hub operations folder and re-import interpretune to verify only local operations remain.
print("Cleaning up downloaded hub operations...")
# Remove only the specific repository we downloaded, not the entire hub cache
op_demo_utils.cleanup_hub_repository(download_result)
# Re-import interpretune again
print("\nRe-importing interpretune after cleanup...")
# Capture stdout and stderr during import to check for the expected warning
stdout_output, stderr_output, DISPATCHER = op_demo_utils.reimport_interpretune_with_capture()
op_demo_utils.inspect_err_for_composite_op_warning(stderr_output)
print("\n ✓ Interpretune re-imported after cleanup")
Cleaning up downloaded hub operations...
✓ Removed specific hub repository cache: /mnt/cache_extended/speediedan/.cache/huggingface/hub/interpretune_ops/models--speediedan--trivial_op_repo
Re-importing interpretune after cleanup...
/home/speediedan/repos/interpretune/src/interpretune/analysis/ops/compiler/schema_compiler.py:306: Failed to compile operation 'composite_trivial_test_op' with composition ['trivial_local_test_op', 'trivial_test_op']: Operation trivial_test_op not found
Note the above "Failed to compile operation 'composite_trivial_test_op'" error on re-import of interpretune after our cleanup.
This is expected: we have removed our hub op definitions (trivial_test_op), but not our local op definitions (trivial_local_test_op, composite_trivial_test_op).
As a result, the locally defined composite operation 'composite_trivial_test_op' could not be constructed since it depended on the now-missing hub op.
All other available operations (local and built-in) should still be present as we will see.
✓ Interpretune re-imported after cleanup
Overwriting format type 'interpretune' (ITAnalysisFormatter -> ITAnalysisFormatter)
Overwriting format type alias 'itanalysis' (interpretune -> interpretune)
Overwriting format type alias 'it' (interpretune -> interpretune)
Overwriting format type alias 'interpretune' (interpretune -> interpretune)
Step 8: Verify only local operations remain#
Verify that only the local and built-in operations are available after hub cleanup.
print("Verifying operations after cleanup...")
# Get operation definitions after cleanup and verify cleanup status
operation_definitions_after = DISPATCHER.registered_ops
op_demo_utils.verify_cleanup_status(operation_definitions_after)
Verifying operations after cleanup...
📊 Operation Summary After Cleanup:
Total registered names: 42
Unique operations: 30
Hub operations: 0
Local operations: 10
Composed operations: 7
Built-in operations: 13
✅ Success: No hub operations found - cleanup successful!
🏠 Local operations still available:
- extract_concept_latent_state (accessible as: extract_concept_latent_state, concept_latent_state_from_cache) - Extract per-example latent rows from the configured cache key
- extract_concept_latent_examples (accessible as: extract_concept_latent_examples, concept_latent_examples) - Filter and annotate latent rows for concept-direction aggregation
- concept_direction (accessible as: concept_direction, semantic_direction) - Aggregate latent concept examples into a normalized concept direction vector
- compute_attribution_graph (accessible as: compute_attribution_graph, ct_graph) - Generate an attribution graph with circuit-tracer
- extract_top_features (accessible as: extract_top_features, ct_top_features) - Extract top-N influential features from an attribution graph
- graph_prune (accessible as: graph_prune, ct_graph_prune) - Prune a circuit-tracer attribution graph
- graph_node_influence (accessible as: graph_node_influence, ct_node_influence) - Compute node influence scores for an attribution graph
- feature_intervention_forward (accessible as: feature_intervention_forward, ct_feature_intervention) - Run feature interventions and return pre/post intervention outputs
- model_fwd_intervention (accessible as: model_fwd_intervention, direction_intervention, direct_concept_direction_intervention) - Apply generalized hook-point interventions and return pre/post intervention logits
- trivial_local_test_op (accessible as: trivial_local_test_op) - Local test op that transforms a simple orig_labels tensor to a preds tensor
📋 Detailed breakdown:
Built-in operations (13):
- ablation_attribution (accessible as: ablation_attribution)
- get_alive_latents (accessible as: get_alive_latents)
- get_answer_indices (accessible as: get_answer_indices)
- gradient_attribution (accessible as: gradient_attribution)
- labels_to_ids (accessible as: labels_to_ids)
- logit_diffs (accessible as: logit_diffs)
- logit_diffs_cache (accessible as: logit_diffs_cache)
- model_ablation (accessible as: model_ablation)
- model_fwd (accessible as: model_fwd, model_forward)
- model_fwd_w_cache (accessible as: model_fwd_w_cache)
- model_fwd_w_cache_latent_models (accessible as: model_fwd_w_cache_latent_models)
- model_gradient (accessible as: model_gradient)
- sae_correct_acts (accessible as: sae_correct_acts)
Composed operations (7):
- attribution_from_concept (accessible as: attribution_from_concept)
- intervention_from_concept (accessible as: intervention_from_concept)
- intervention_from_features (accessible as: intervention_from_features)
- logit_diffs_attr_ablation (accessible as: logit_diffs_attr_ablation, logit_diffs_ablation)
- logit_diffs_attr_grad (accessible as: logit_diffs_attr_grad)
- logit_diffs_base (accessible as: logit_diffs_base)
- logit_diffs_sae (accessible as: logit_diffs_sae)
Cleanup temporary files#
Clean up the temporary files created during this example.
# Clean up using utility function
op_demo_utils.cleanup_op_collections(
tmp_op_collection=tmp_op_collection,
tmp_local_op_collection=tmp_local_op_collection,
original_op_paths_env=original_op_paths_env,
)
print("\n🎉 Hub and Local operations workflow example completed successfully!")
print("\nSummary of what was demonstrated:")
print("1. ✓ Setup local op collection path via IT_ANALYSIS_OP_PATHS environment variable")
print("2. ✓ Copied hub op_collection to /tmp/ with overwrite warning")
print("3. ✓ Uploaded operations to HuggingFace Hub as private repo")
print("4. ✓ Downloaded operations to default hub cache")
print("5. ✓ Re-imported interpretune and verified both hub and local operations")
print("6. ✓ Tested operation instantiation and execution with demo data")
print("7. ✓ Cleaned up hub operations and re-imported")
print("8. ✓ Verified only local and built-in operations remain available")
print("9. ✓ Restored original IT_ANALYSIS_OP_PATHS environment variable")
Cleaning up temporary files...
✓ Removed temporary hub op_collection: /tmp/hub_op_collection
✓ Removed temporary local op_collection: /tmp/local_op_collection
✓ Unset IT_ANALYSIS_OP_PATHS environment variable
✓ Removed /tmp/local_op_collection from imported IT_ANALYSIS_OP_PATHS list
Final IT_ANALYSIS_OP_PATHS list: []
Final IT_ANALYSIS_OP_PATHS env var: ''
🎉 Hub and Local operations workflow example completed successfully!
Summary of what was demonstrated:
1. ✓ Setup local op collection path via IT_ANALYSIS_OP_PATHS environment variable
2. ✓ Copied hub op_collection to /tmp/ with overwrite warning
3. ✓ Uploaded operations to HuggingFace Hub as private repo
4. ✓ Downloaded operations to default hub cache
5. ✓ Re-imported interpretune and verified both hub and local operations
6. ✓ Tested operation instantiation and execution with demo data
7. ✓ Cleaned up hub operations and re-imported
8. ✓ Verified only local and built-in operations remain available
9. ✓ Restored original IT_ANALYSIS_OP_PATHS environment variable
Step 9: Final verification after environment cleanup#
Re-import interpretune one final time to verify that local operations are no longer available after unsetting IT_ANALYSIS_OP_PATHS.
print("Final verification: Re-importing interpretune after environment cleanup...")
# Remove interpretune modules from sys.modules to force reimport
op_demo_utils.purge_it_modules_from_sys()
# Re-import interpretune one final time
import interpretune
from interpretune import DISPATCHER
print("✓ Interpretune re-imported after environment cleanup")
# Get operation definitions after complete cleanup and generate final summary
operation_definitions_final = DISPATCHER.registered_ops
canonical_ops_final, alias_map_final, hub_ops_final, local_ops_final, composed_ops_final, builtin_ops = (
op_demo_utils.categorize_operations(operation_definitions_final)
)
print("\n📊 Final Operation Summary (after complete cleanup):")
print(f" Total registered names: {len(operation_definitions_final)}")
print(f" Unique operations: {len(canonical_ops_final)}")
print(f" Hub operations: {len(hub_ops_final)}")
print(f" Local operations: {len(local_ops_final)}")
print(f" Composed operations: {len(composed_ops_final)}")
print(f" Built-in operations: {len(builtin_ops)}")
# Verify complete cleanup
if len(hub_ops_final) == 0 and len(local_ops_final) == 0:
print("\n🎯 Perfect! Complete cleanup successful - only built-in and composed operations remain!")
elif len(hub_ops_final) == 0:
print(f"\n⚠️ Hub operations cleaned up, but {len(local_ops_final)} local operations still present:")
for op_name, op_def in local_ops_final.items():
aliases = alias_map_final.get(op_name, [])
all_names = [op_name] + aliases
print(f" - {op_name} (accessible as: {', '.join(all_names)})")
elif len(local_ops_final) == 0:
print(f"\n⚠️ Local operations cleaned up, but {len(hub_ops_final)} hub operations still present:")
for op_name, op_def in hub_ops_final.items():
aliases = alias_map_final.get(op_name, [])
all_names = [op_name] + aliases
print(f" - {op_name} (accessible as: {', '.join(all_names)})")
else:
print(f"\n❌ Cleanup incomplete: {len(hub_ops_final)} hub ops and {len(local_ops_final)} local ops still present")
print("\nEnvironment verification:")
print(f" Current IT_ANALYSIS_OP_PATHS env var: '{os.environ.get('IT_ANALYSIS_OP_PATHS', 'Not set')}'")
Final verification: Re-importing interpretune after environment cleanup...
✓ Interpretune re-imported after environment cleanup
📊 Final Operation Summary (after complete cleanup):
Total registered names: 41
Unique operations: 29
Hub operations: 0
Local operations: 9
Composed operations: 7
Built-in operations: 13
⚠️ Hub operations cleaned up, but 9 local operations still present:
- extract_concept_latent_state (accessible as: extract_concept_latent_state, concept_latent_state_from_cache)
- extract_concept_latent_examples (accessible as: extract_concept_latent_examples, concept_latent_examples)
- concept_direction (accessible as: concept_direction, semantic_direction)
- compute_attribution_graph (accessible as: compute_attribution_graph, ct_graph)
- extract_top_features (accessible as: extract_top_features, ct_top_features)
- graph_prune (accessible as: graph_prune, ct_graph_prune)
- graph_node_influence (accessible as: graph_node_influence, ct_node_influence)
- feature_intervention_forward (accessible as: feature_intervention_forward, ct_feature_intervention)
- model_fwd_intervention (accessible as: model_fwd_intervention, direction_intervention, direct_concept_direction_intervention)
Environment verification:
Current IT_ANALYSIS_OP_PATHS env var: 'Not set'
Overwriting format type 'interpretune' (ITAnalysisFormatter -> ITAnalysisFormatter)
Overwriting format type alias 'itanalysis' (interpretune -> interpretune)
Overwriting format type alias 'it' (interpretune -> interpretune)
Overwriting format type alias 'interpretune' (interpretune -> interpretune)
Appendix: All Registered Analysis Ops#
The dispatcher also includes built-in native analysis ops (e.g., circuit-tracer attribution and intervention ops). Here is the full set of registered operations:
from interpretune.analysis.ops.dispatcher import DISPATCHER
print(f"Total registered ops: {len(DISPATCHER.registered_ops)}")
for name, op in sorted(DISPATCHER.registered_ops.items()):
desc = getattr(op, "description", "")
print(f" {name}: {desc}")
Total registered ops: 41
ablation_attribution: Compute attribution values from ablation
attribution_from_concept: Compiled composition: concept_direction.compute_attribution_graph.graph_node_influence.extract_top_features
compute_attribution_graph: Generate an attribution graph with circuit-tracer
concept_direction: Aggregate latent concept examples into a normalized concept direction vector
concept_latent_examples: Filter and annotate latent rows for concept-direction aggregation
concept_latent_state_from_cache: Extract per-example latent rows from the configured cache key
ct_feature_intervention: Run feature interventions and return pre/post intervention outputs
ct_graph: Generate an attribution graph with circuit-tracer
ct_graph_prune: Prune a circuit-tracer attribution graph
ct_node_influence: Compute node influence scores for an attribution graph
ct_top_features: Extract top-N influential features from an attribution graph
direct_concept_direction_intervention: Apply generalized hook-point interventions and return pre/post intervention logits
direction_intervention: Apply generalized hook-point interventions and return pre/post intervention logits
extract_concept_latent_examples: Filter and annotate latent rows for concept-direction aggregation
extract_concept_latent_state: Extract per-example latent rows from the configured cache key
extract_top_features: Extract top-N influential features from an attribution graph
feature_intervention_forward: Run feature interventions and return pre/post intervention outputs
get_alive_latents: Extract alive latents from cache
get_answer_indices: Extract answer indices from batch
gradient_attribution: Compute attribution values from gradients
graph_node_influence: Compute node influence scores for an attribution graph
graph_prune: Prune a circuit-tracer attribution graph
intervention_from_concept: Compiled composition: concept_direction.compute_attribution_graph.graph_node_influence.extract_top_features.feature_intervention_forward
intervention_from_features: Compiled composition: feature_intervention_forward
labels_to_ids: Convert label strings to tensor IDs
logit_diffs: Clean forward pass for computing logit differences
logit_diffs_ablation: Compiled composition: labels_to_ids.model_fwd_w_cache_latent_models.logit_diffs_cache.model_ablation.ablation_attribution
logit_diffs_attr_ablation: Compiled composition: labels_to_ids.model_fwd_w_cache_latent_models.logit_diffs_cache.model_ablation.ablation_attribution
logit_diffs_attr_grad: Compiled composition: labels_to_ids.model_gradient.gradient_attribution
logit_diffs_base: Compiled composition: labels_to_ids.model_fwd.logit_diffs
logit_diffs_cache: Clean forward pass for computing logit differences including cache activations (composition only)
logit_diffs_sae: Compiled composition: labels_to_ids.model_fwd_w_cache_latent_models.logit_diffs_cache.sae_correct_acts
model_ablation: Model ablation analysis
model_forward: Basic model forward pass
model_fwd: Basic model forward pass
model_fwd_intervention: Apply generalized hook-point interventions and return pre/post intervention logits
model_fwd_w_cache: Model forward pass with activation caching (no latent model hooks)
model_fwd_w_cache_latent_models: Model forward pass with activation caching and latent model (SAE) hooks
model_gradient: Model gradient-based attribution
sae_correct_acts: Compute correct activations from SAE cache
semantic_direction: Aggregate latent concept examples into a normalized concept direction vector