Source code for tooluniverse.space.loader

"""
ToolUniverse Space Configuration Loader

Simplified loader supporting HuggingFace, local files, and HTTP/HTTPS.
"""

import json
from pathlib import Path
from typing import Any, Dict, Optional, Union
import yaml
import requests
from huggingface_hub import hf_hub_download

from ..utils import get_user_cache_dir
from .validator import validate_space_config


[docs] class SpaceLoader: """Simplified loader for ToolUniverse Space configurations."""
[docs] def __init__(self, cache_dir: Optional[Union[str, Path]] = None): """ Initialize the Space loader. Args: cache_dir: Directory for caching downloaded configurations """ if cache_dir: self.cache_dir = Path(cache_dir) else: self.cache_dir = Path(get_user_cache_dir()) / "spaces" self.cache_dir.mkdir(parents=True, exist_ok=True)
[docs] def load(self, uri: str) -> Dict[str, Any]: """ Load Space configuration from URI. Args: uri: Space URI (e.g., "hf:user/repo", "./config.yaml", "https://example.com/config.yaml") Returns Loaded configuration dictionary Raises: ValueError: If URI is unsupported or configuration is invalid """ # Use URI directly (no alias resolution) resolved_uri = uri # Detect URI type if resolved_uri.startswith("hf:"): config = self._load_from_hf(resolved_uri) elif resolved_uri.startswith(("http://", "https://")): config = self._load_from_url(resolved_uri) else: config = self._load_from_file(resolved_uri) # Validate configuration is_valid, errors = validate_space_config(config) if not is_valid: error_msg = "Configuration validation failed:\n" + "\n".join( f" - {e}" for e in errors ) raise ValueError(error_msg) return config
def _load_from_hf(self, uri: str) -> Dict[str, Any]: """Load configuration from HuggingFace Hub.""" repo_id = uri[3:] # Remove 'hf:' prefix try: # Try to download the config file config_path = hf_hub_download( repo_id=repo_id, filename="space.yaml", cache_dir=self.cache_dir, local_files_only=False, ) return self._load_from_file(config_path) except Exception as e: # Fallback: try space.json try: config_path = hf_hub_download( repo_id=repo_id, filename="space.json", cache_dir=self.cache_dir, local_files_only=False, ) return self._load_from_file(config_path) except Exception: raise ValueError( f"Failed to load Space from HuggingFace {repo_id}: {e}" ) def _load_from_url(self, uri: str) -> Dict[str, Any]: """Load configuration from HTTP/HTTPS URL.""" try: response = requests.get(uri, timeout=30) response.raise_for_status() # Try YAML first, then JSON try: return yaml.safe_load(response.text) except yaml.YAMLError: return response.json() except Exception as e: raise ValueError(f"Failed to load Space from URL {uri}: {e}") def _load_from_file(self, file_path: str) -> Dict[str, Any]: """Load configuration from local file.""" path = Path(file_path) if not path.exists(): raise ValueError(f"Space file not found: {file_path}") try: with open(path, "r", encoding="utf-8") as f: if path.suffix.lower() in [".yaml", ".yml"]: return yaml.safe_load(f) elif path.suffix.lower() == ".json": return json.load(f) else: # Try YAML first, then JSON try: f.seek(0) return yaml.safe_load(f) except yaml.YAMLError: f.seek(0) return json.load(f) except Exception as e: raise ValueError(f"Failed to load Space from file {file_path}: {e}")