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.
- nepher/__init__.py +36 -0
- nepher/api/__init__.py +6 -0
- nepher/api/client.py +384 -0
- nepher/api/endpoints.py +97 -0
- nepher/auth.py +150 -0
- nepher/cli/__init__.py +2 -0
- nepher/cli/commands/__init__.py +6 -0
- nepher/cli/commands/auth.py +37 -0
- nepher/cli/commands/cache.py +85 -0
- nepher/cli/commands/config.py +77 -0
- nepher/cli/commands/download.py +72 -0
- nepher/cli/commands/list.py +75 -0
- nepher/cli/commands/upload.py +69 -0
- nepher/cli/commands/view.py +310 -0
- nepher/cli/main.py +30 -0
- nepher/cli/utils.py +28 -0
- nepher/config.py +202 -0
- nepher/core.py +67 -0
- nepher/env_cfgs/__init__.py +7 -0
- nepher/env_cfgs/base.py +32 -0
- nepher/env_cfgs/manipulation/__init__.py +4 -0
- nepher/env_cfgs/navigation/__init__.py +45 -0
- nepher/env_cfgs/navigation/abstract_nav_cfg.py +159 -0
- nepher/env_cfgs/navigation/preset_nav_cfg.py +590 -0
- nepher/env_cfgs/navigation/usd_nav_cfg.py +644 -0
- nepher/env_cfgs/registry.py +31 -0
- nepher/loader/__init__.py +9 -0
- nepher/loader/base.py +27 -0
- nepher/loader/category_loaders/__init__.py +2 -0
- nepher/loader/preset_loader.py +80 -0
- nepher/loader/registry.py +63 -0
- nepher/loader/usd_loader.py +49 -0
- nepher/storage/__init__.py +8 -0
- nepher/storage/bundle.py +78 -0
- nepher/storage/cache.py +145 -0
- nepher/storage/manifest.py +80 -0
- nepher/utils/__init__.py +12 -0
- nepher/utils/fast_spawn_sampler.py +334 -0
- nepher/utils/free_zone_finder.py +239 -0
- nepher-0.1.0.dist-info/METADATA +235 -0
- nepher-0.1.0.dist-info/RECORD +45 -0
- nepher-0.1.0.dist-info/WHEEL +5 -0
- nepher-0.1.0.dist-info/entry_points.txt +2 -0
- nepher-0.1.0.dist-info/licenses/LICENSE +97 -0
- 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
|
+
|