nepher 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. nepher/__init__.py +36 -0
  2. nepher/api/__init__.py +6 -0
  3. nepher/api/client.py +384 -0
  4. nepher/api/endpoints.py +97 -0
  5. nepher/auth.py +150 -0
  6. nepher/cli/__init__.py +2 -0
  7. nepher/cli/commands/__init__.py +6 -0
  8. nepher/cli/commands/auth.py +37 -0
  9. nepher/cli/commands/cache.py +85 -0
  10. nepher/cli/commands/config.py +77 -0
  11. nepher/cli/commands/download.py +72 -0
  12. nepher/cli/commands/list.py +75 -0
  13. nepher/cli/commands/upload.py +69 -0
  14. nepher/cli/commands/view.py +310 -0
  15. nepher/cli/main.py +30 -0
  16. nepher/cli/utils.py +28 -0
  17. nepher/config.py +202 -0
  18. nepher/core.py +67 -0
  19. nepher/env_cfgs/__init__.py +7 -0
  20. nepher/env_cfgs/base.py +32 -0
  21. nepher/env_cfgs/manipulation/__init__.py +4 -0
  22. nepher/env_cfgs/navigation/__init__.py +45 -0
  23. nepher/env_cfgs/navigation/abstract_nav_cfg.py +159 -0
  24. nepher/env_cfgs/navigation/preset_nav_cfg.py +590 -0
  25. nepher/env_cfgs/navigation/usd_nav_cfg.py +644 -0
  26. nepher/env_cfgs/registry.py +31 -0
  27. nepher/loader/__init__.py +9 -0
  28. nepher/loader/base.py +27 -0
  29. nepher/loader/category_loaders/__init__.py +2 -0
  30. nepher/loader/preset_loader.py +80 -0
  31. nepher/loader/registry.py +63 -0
  32. nepher/loader/usd_loader.py +49 -0
  33. nepher/storage/__init__.py +8 -0
  34. nepher/storage/bundle.py +78 -0
  35. nepher/storage/cache.py +145 -0
  36. nepher/storage/manifest.py +80 -0
  37. nepher/utils/__init__.py +12 -0
  38. nepher/utils/fast_spawn_sampler.py +334 -0
  39. nepher/utils/free_zone_finder.py +239 -0
  40. nepher-0.1.0.dist-info/METADATA +235 -0
  41. nepher-0.1.0.dist-info/RECORD +45 -0
  42. nepher-0.1.0.dist-info/WHEEL +5 -0
  43. nepher-0.1.0.dist-info/entry_points.txt +2 -0
  44. nepher-0.1.0.dist-info/licenses/LICENSE +97 -0
  45. nepher-0.1.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,37 @@
1
+ """Authentication commands."""
2
+
3
+ import click
4
+ from nepher.auth import login as auth_login, logout as auth_logout, whoami as auth_whoami
5
+ from nepher.cli.utils import print_success, print_error, print_info
6
+
7
+
8
+ @click.command()
9
+ @click.argument("api_key")
10
+ def login(api_key: str):
11
+ """Login with API key."""
12
+ if auth_login(api_key):
13
+ print_success("Login successful!")
14
+ else:
15
+ print_error("Login failed. Please check your API key.")
16
+
17
+
18
+ @click.command()
19
+ def logout():
20
+ """Logout and clear credentials."""
21
+ auth_logout()
22
+ print_success("Logged out successfully.")
23
+
24
+
25
+ @click.command()
26
+ def whoami():
27
+ """Show current user information."""
28
+ user_info = auth_whoami()
29
+ if user_info:
30
+ print_info("Current user:")
31
+ click.echo(f" Fullname: {user_info.get('fullname', 'N/A')}")
32
+ click.echo(f" Email: {user_info.get('email', 'N/A')}")
33
+ click.echo(f" Role: {user_info.get('role', 'N/A')}")
34
+ click.echo(f" Status: {user_info.get('status', 'N/A')}")
35
+ else:
36
+ print_error("Not authenticated. Use 'nepher login <api_key>' to authenticate.")
37
+
@@ -0,0 +1,85 @@
1
+ """Cache management commands."""
2
+
3
+ import click
4
+ from pathlib import Path
5
+ from typing import Optional
6
+ from nepher.storage.cache import get_cache_manager
7
+ from nepher.cli.utils import print_error, print_success, print_info
8
+
9
+
10
+ @click.group()
11
+ def cache():
12
+ """Manage local cache."""
13
+ pass
14
+
15
+
16
+ @cache.command()
17
+ def list():
18
+ """List cached environments."""
19
+ try:
20
+ cache_manager = get_cache_manager()
21
+ cached = cache_manager.list_cached()
22
+
23
+ if not cached:
24
+ print_info("No cached environments.")
25
+ return
26
+
27
+ print_info(f"Cached environments ({len(cached)}):")
28
+ for env_id in cached:
29
+ click.echo(f" {env_id}")
30
+
31
+ except Exception as e:
32
+ print_error(f"Failed to list cache: {str(e)}")
33
+
34
+
35
+ @cache.command()
36
+ @click.argument("env_id", required=False)
37
+ def clear(env_id: Optional[str]):
38
+ """Clear cache (all or specific environment)."""
39
+ try:
40
+ cache_manager = get_cache_manager()
41
+ if env_id:
42
+ cache_manager.clear_cache(env_id)
43
+ print_success(f"Cleared cache for {env_id}")
44
+ else:
45
+ cache_manager.clear_cache()
46
+ print_success("Cleared all cache")
47
+
48
+ except Exception as e:
49
+ print_error(f"Failed to clear cache: {str(e)}")
50
+
51
+
52
+ @cache.command()
53
+ def info():
54
+ """Show cache statistics."""
55
+ try:
56
+ cache_manager = get_cache_manager()
57
+ info = cache_manager.get_cache_info()
58
+
59
+ print_info("Cache Information:")
60
+ click.echo(f" Cache Directory: {info['cache_dir']}")
61
+ click.echo(f" Total Size: {info['total_size'] / (1024**2):.2f} MB")
62
+ click.echo(f" Environment Count: {info['env_count']}")
63
+
64
+ if info["environments"]:
65
+ click.echo("\n Environments:")
66
+ for env in info["environments"]:
67
+ click.echo(f" {env['id']}: {env['size'] / (1024**2):.2f} MB")
68
+
69
+ except Exception as e:
70
+ print_error(f"Failed to get cache info: {str(e)}")
71
+
72
+
73
+ @cache.command()
74
+ @click.argument("new_path", type=click.Path())
75
+ def migrate(new_path: str):
76
+ """Migrate cache to new location."""
77
+ try:
78
+ cache_manager = get_cache_manager()
79
+ new_cache_dir = Path(new_path)
80
+ cache_manager.migrate_cache(new_cache_dir)
81
+ print_success(f"Cache migrated to {new_path}")
82
+
83
+ except Exception as e:
84
+ print_error(f"Failed to migrate cache: {str(e)}")
85
+
@@ -0,0 +1,77 @@
1
+ """Configuration management commands."""
2
+
3
+ import click
4
+ from nepher.config import get_config, set_config
5
+ from nepher.cli.utils import print_error, print_success, print_info
6
+
7
+
8
+ @click.group()
9
+ def config():
10
+ """Manage configuration."""
11
+ pass
12
+
13
+
14
+ @config.command()
15
+ @click.argument("key")
16
+ def get(key: str):
17
+ """Get configuration value."""
18
+ try:
19
+ value = get_config().get(key)
20
+ if value is None:
21
+ print_error(f"Configuration key '{key}' not found.")
22
+ else:
23
+ click.echo(value)
24
+
25
+ except Exception as e:
26
+ print_error(f"Failed to get config: {str(e)}")
27
+
28
+
29
+ @config.command()
30
+ @click.argument("key")
31
+ @click.argument("value")
32
+ def set(key: str, value: str):
33
+ """Set configuration value."""
34
+ try:
35
+ if value.lower() in ("true", "false"):
36
+ value = value.lower() == "true"
37
+ elif value.isdigit():
38
+ value = int(value)
39
+ elif value.replace(".", "", 1).isdigit():
40
+ value = float(value)
41
+
42
+ set_config(key, value, save=True)
43
+ print_success(f"Set {key} = {value}")
44
+
45
+ except Exception as e:
46
+ print_error(f"Failed to set config: {str(e)}")
47
+
48
+
49
+ @config.command()
50
+ def list():
51
+ """List all configuration values."""
52
+ try:
53
+ cfg = get_config()
54
+ print_info("Configuration:")
55
+ click.echo(f" api_url: {cfg.get('api_url')}")
56
+ click.echo(f" cache_dir: {cfg.get('cache_dir')}")
57
+ click.echo(f" default_category: {cfg.get('default_category')}")
58
+
59
+ except Exception as e:
60
+ print_error(f"Failed to list config: {str(e)}")
61
+
62
+
63
+ @config.command()
64
+ def reset():
65
+ """Reset configuration to defaults."""
66
+ try:
67
+ config = get_config()
68
+ config_file = getattr(config, "_config_file", None)
69
+ if config_file and config_file.exists():
70
+ config_file.unlink()
71
+ print_success("Configuration reset to defaults.")
72
+ else:
73
+ print_info("No configuration file to reset.")
74
+
75
+ except Exception as e:
76
+ print_error(f"Failed to reset config: {str(e)}")
77
+
@@ -0,0 +1,72 @@
1
+ """Download environment command."""
2
+
3
+ from pathlib import Path
4
+ from typing import Optional
5
+ import click
6
+ from nepher.api.client import get_client
7
+ from nepher.storage.cache import get_cache_manager
8
+ from nepher.storage.bundle import BundleManager
9
+ from nepher.cli.utils import print_error, print_success, print_info
10
+
11
+
12
+ @click.command()
13
+ @click.argument("env_id")
14
+ @click.option("--category", required=True, help="Environment category")
15
+ @click.option("--cache-dir", type=click.Path(), help="Override cache directory")
16
+ @click.option("--force", is_flag=True, help="Force re-download")
17
+ def download(env_id: str, category: str, cache_dir: Optional[str], force: bool):
18
+ """Download an environment."""
19
+ try:
20
+ client = get_client()
21
+ cache_manager = get_cache_manager(
22
+ cache_dir=Path(cache_dir) if cache_dir else None, category=category
23
+ )
24
+
25
+ actual_env_id = env_id
26
+ try:
27
+ env_info = client.get_environment(env_id)
28
+ actual_env_id = env_info.get("id", env_id)
29
+ except Exception:
30
+ print_info(f"Searching for environment matching '{env_id}'...")
31
+ envs = client.list_environments(category=category, search=env_id, limit=10)
32
+
33
+ matches = [e for e in envs if e.get("original_name") == env_id]
34
+
35
+ if not matches:
36
+ matches = [e for e in envs if env_id.lower() in e.get("original_name", "").lower()]
37
+
38
+ if not matches:
39
+ print_error(f"Environment '{env_id}' not found in category '{category}'")
40
+ print_info("Use 'nepher list --category navigation' to see available environments")
41
+ return
42
+
43
+ if len(matches) > 1:
44
+ matches.sort(key=lambda x: x.get("uploaded_at", ""), reverse=True)
45
+ print_info(f"Found {len(matches)} matches, using most recent: {matches[0].get('id')}")
46
+
47
+ actual_env_id = matches[0].get("id")
48
+ if not actual_env_id:
49
+ print_error(f"Could not determine environment ID for '{env_id}'")
50
+ return
51
+
52
+ if cache_manager.is_cached(actual_env_id) and not force:
53
+ print_info(f"Environment {actual_env_id} is already cached.")
54
+ return
55
+
56
+ print_info(f"Downloading {actual_env_id}...")
57
+
58
+ cache_path = cache_manager.get_env_cache_path(actual_env_id)
59
+ zip_path = cache_path.parent / f"{actual_env_id}.zip"
60
+
61
+ client.download_environment(actual_env_id, zip_path)
62
+
63
+ print_info("Extracting bundle...")
64
+ BundleManager.extract_bundle(zip_path, cache_path)
65
+
66
+ zip_path.unlink()
67
+
68
+ print_success(f"Environment {actual_env_id} downloaded and cached successfully!")
69
+
70
+ except Exception as e:
71
+ print_error(f"Failed to download environment: {str(e)}")
72
+
@@ -0,0 +1,75 @@
1
+ """List environments command."""
2
+
3
+ import json
4
+ from typing import Optional
5
+ import click
6
+ from nepher.api.client import get_client
7
+ from nepher.cli.utils import print_error, print_info
8
+
9
+
10
+ @click.command(name="list")
11
+ @click.option("--category", help="Filter by category")
12
+ @click.option("--type", type=click.Choice(["usd", "preset"]), help="Filter by type")
13
+ @click.option("--benchmark", is_flag=True, help="List only benchmark environments")
14
+ @click.option("--eval-benchmarks", "eval_benchmarks", is_flag=True, help="List only evaluation benchmarks")
15
+ @click.option("--search", help="Search query")
16
+ @click.option("--json", "output_json", is_flag=True, help="Output as JSON")
17
+ @click.option("--limit", type=int, help="Maximum number of results")
18
+ def list_cmd(
19
+ category: Optional[str],
20
+ type: Optional[str],
21
+ benchmark: bool,
22
+ eval_benchmarks: bool,
23
+ search: Optional[str],
24
+ output_json: bool,
25
+ limit: Optional[int],
26
+ ):
27
+ """List available environments."""
28
+ try:
29
+ client = get_client()
30
+
31
+ if eval_benchmarks:
32
+ envs = client.list_eval_benchmarks()
33
+ else:
34
+ envs = client.list_environments(
35
+ category=category,
36
+ type=type,
37
+ benchmark=benchmark if benchmark else None,
38
+ search=search,
39
+ limit=limit,
40
+ )
41
+
42
+ if output_json:
43
+ click.echo(json.dumps(envs, indent=2))
44
+ else:
45
+ if not envs:
46
+ print_info("No environments found.")
47
+ return
48
+
49
+ print_info(f"Found {len(envs)} environment(s):\n")
50
+ for env in envs:
51
+ click.echo(f" {env.get('id', 'N/A')}")
52
+ click.echo(f" Name: {env.get('original_name', 'N/A')}")
53
+ click.echo(f" Version: {env.get('version', 'N/A')}")
54
+ click.echo(f" Category: {env.get('category', 'N/A')}")
55
+ click.echo(f" Type: {env.get('type', 'N/A')}")
56
+ click.echo(f" Status: {env.get('status', 'N/A')}")
57
+
58
+ if env.get("is_benchmark"):
59
+ click.echo(" Benchmark: Yes")
60
+
61
+ if eval_benchmarks:
62
+ if env.get("evaluation_period_start"):
63
+ click.echo(f" Evaluation Start: {env.get('evaluation_period_start')}")
64
+ if env.get("evaluation_period_end"):
65
+ click.echo(f" Evaluation End: {env.get('evaluation_period_end')}")
66
+ if env.get("is_active_for_evaluation") is not None:
67
+ click.echo(f" Active for Evaluation: {'Yes' if env.get('is_active_for_evaluation') else 'No'}")
68
+
69
+ if env.get("description"):
70
+ click.echo(f" Description: {env.get('description')}")
71
+ click.echo()
72
+
73
+ except Exception as e:
74
+ print_error(f"Failed to list environments: {str(e)}")
75
+
@@ -0,0 +1,69 @@
1
+ """Upload environment command."""
2
+
3
+ import shutil
4
+ import tempfile
5
+ import zipfile
6
+ from pathlib import Path
7
+ from typing import Optional
8
+ import click
9
+ from nepher.api.client import get_client
10
+ from nepher.storage.bundle import BundleManager
11
+ from nepher.cli.utils import print_error, print_success, print_info
12
+
13
+
14
+ @click.command()
15
+ @click.argument("path", type=click.Path(exists=True))
16
+ @click.option("--category", required=True, help="Environment category")
17
+ @click.option("--benchmark", is_flag=True, help="Mark as benchmark environment")
18
+ @click.option("--force", is_flag=True, help="Force upload even if duplicate exists")
19
+ @click.option("--thumbnail", type=click.Path(exists=True), help="Thumbnail image path")
20
+ def upload(path: str, category: str, benchmark: bool, force: bool, thumbnail: Optional[str]):
21
+ """Upload an environment bundle."""
22
+ temp_zip = None
23
+ try:
24
+ bundle_path = Path(path)
25
+ if not bundle_path.exists():
26
+ print_error(f"Bundle not found: {bundle_path}")
27
+ return
28
+
29
+ print_info("Validating bundle...")
30
+ if not BundleManager.validate_bundle(bundle_path):
31
+ print_error("Invalid bundle: manifest.yaml not found")
32
+ return
33
+
34
+ upload_path = bundle_path
35
+ if bundle_path.is_dir():
36
+ print_info("Creating bundle ZIP...")
37
+ temp_dir = tempfile.gettempdir()
38
+ zip_name = f"{bundle_path.name}.zip"
39
+ temp_zip = Path(temp_dir) / zip_name
40
+
41
+ with zipfile.ZipFile(temp_zip, "w", zipfile.ZIP_DEFLATED) as zipf:
42
+ for file_path in bundle_path.rglob("*"):
43
+ if file_path.is_file():
44
+ arcname = file_path.relative_to(bundle_path)
45
+ zipf.write(file_path, arcname)
46
+
47
+ upload_path = temp_zip
48
+
49
+ print_info(f"Uploading {bundle_path.name}...")
50
+
51
+ client = get_client()
52
+ result = client.upload_environment(
53
+ bundle_path=upload_path,
54
+ category=category,
55
+ benchmark=benchmark,
56
+ force=force,
57
+ duplicate_policy="reject",
58
+ thumbnail=Path(thumbnail) if thumbnail else None,
59
+ )
60
+
61
+ print_success(f"Environment uploaded successfully!")
62
+ click.echo(f" Environment ID: {result.get('id', 'N/A')}")
63
+
64
+ except Exception as e:
65
+ print_error(f"Failed to upload environment: {str(e)}")
66
+ finally:
67
+ if temp_zip and temp_zip.exists():
68
+ temp_zip.unlink()
69
+