humalab 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.
- humalab/__init__.py +34 -0
- humalab/assets/__init__.py +10 -0
- humalab/assets/archive.py +101 -0
- humalab/assets/files/__init__.py +4 -0
- humalab/assets/files/resource_file.py +131 -0
- humalab/assets/files/urdf_file.py +103 -0
- humalab/assets/resource_operator.py +139 -0
- humalab/constants.py +50 -0
- humalab/dists/__init__.py +24 -0
- humalab/dists/bernoulli.py +84 -0
- humalab/dists/categorical.py +81 -0
- humalab/dists/discrete.py +103 -0
- humalab/dists/distribution.py +49 -0
- humalab/dists/gaussian.py +96 -0
- humalab/dists/log_uniform.py +97 -0
- humalab/dists/truncated_gaussian.py +129 -0
- humalab/dists/uniform.py +95 -0
- humalab/episode.py +306 -0
- humalab/humalab.py +219 -0
- humalab/humalab_api_client.py +966 -0
- humalab/humalab_config.py +122 -0
- humalab/humalab_test.py +527 -0
- humalab/metrics/__init__.py +17 -0
- humalab/metrics/code.py +59 -0
- humalab/metrics/metric.py +96 -0
- humalab/metrics/scenario_stats.py +163 -0
- humalab/metrics/summary.py +75 -0
- humalab/run.py +325 -0
- humalab/scenarios/__init__.py +11 -0
- humalab/scenarios/scenario.py +375 -0
- humalab/scenarios/scenario_operator.py +114 -0
- humalab/scenarios/scenario_test.py +792 -0
- humalab/utils.py +37 -0
- humalab-0.1.0.dist-info/METADATA +43 -0
- humalab-0.1.0.dist-info/RECORD +39 -0
- humalab-0.1.0.dist-info/WHEEL +5 -0
- humalab-0.1.0.dist-info/entry_points.txt +2 -0
- humalab-0.1.0.dist-info/licenses/LICENSE +21 -0
- humalab-0.1.0.dist-info/top_level.txt +1 -0
humalab/__init__.py
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"""HumaLab SDK - Python library for robotics and embodied AI experimentation.
|
|
2
|
+
|
|
3
|
+
The HumaLab SDK provides tools for managing scenarios, runs, episodes, and metrics
|
|
4
|
+
for robotics experiments and simulations. It supports probabilistic scenario generation,
|
|
5
|
+
metric tracking, and integration with the HumaLab platform.
|
|
6
|
+
|
|
7
|
+
Main components:
|
|
8
|
+
- init: Context manager for creating and managing runs
|
|
9
|
+
- Run: Represents a complete experimental run
|
|
10
|
+
- Episode: Represents a single episode within a run
|
|
11
|
+
- Scenario: Manages scenario configurations with distributions
|
|
12
|
+
- Metrics: Base class for tracking various metric types
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
from humalab.humalab import init, finish, login
|
|
16
|
+
from humalab import assets
|
|
17
|
+
from humalab import metrics
|
|
18
|
+
from humalab import scenarios
|
|
19
|
+
from humalab.run import Run
|
|
20
|
+
from humalab.constants import MetricDimType, GraphType
|
|
21
|
+
# from humalab import evaluators
|
|
22
|
+
|
|
23
|
+
__all__ = [
|
|
24
|
+
"init",
|
|
25
|
+
"finish",
|
|
26
|
+
"login",
|
|
27
|
+
"assets",
|
|
28
|
+
"metrics",
|
|
29
|
+
"scenarios",
|
|
30
|
+
"Run",
|
|
31
|
+
"MetricDimType",
|
|
32
|
+
"GraphType",
|
|
33
|
+
# "evaluators",
|
|
34
|
+
]
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"""Asset management for resources like URDF files, meshes, and media.
|
|
2
|
+
|
|
3
|
+
This module provides functionality for downloading and listing versioned resources
|
|
4
|
+
from HumaLab, including URDF robot descriptions, meshes, videos, and other data files.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from .resource_operator import download, list_resources
|
|
8
|
+
from .files import ResourceFile, URDFFile
|
|
9
|
+
|
|
10
|
+
__all__ = ["download", "list_resources", "ResourceFile", "URDFFile"]
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import shutil
|
|
2
|
+
import zipfile
|
|
3
|
+
import tarfile
|
|
4
|
+
import gzip
|
|
5
|
+
import bz2
|
|
6
|
+
import lzma
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
try:
|
|
11
|
+
import py7zr # for .7z
|
|
12
|
+
except ImportError:
|
|
13
|
+
py7zr = None
|
|
14
|
+
|
|
15
|
+
try:
|
|
16
|
+
import rarfile # for .rar
|
|
17
|
+
except ImportError:
|
|
18
|
+
rarfile = None
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
# ---------- Detection ---------------------------------------------------------
|
|
22
|
+
def detect_archive_type(path: str | Path) -> str:
|
|
23
|
+
"""Return a simple string label for the archive type, else 'unknown'."""
|
|
24
|
+
p = Path(path).with_suffix("").name.lower() # strip double-suffix like .tar.gz
|
|
25
|
+
ext = Path(path).suffix.lower()
|
|
26
|
+
|
|
27
|
+
if ext == ".zip":
|
|
28
|
+
return "zip"
|
|
29
|
+
if ext in {".tar"}:
|
|
30
|
+
return "tar"
|
|
31
|
+
if ext in {".gz"} and p.endswith(".tar"):
|
|
32
|
+
return "tar.gz"
|
|
33
|
+
if ext in {".bz2"} and p.endswith(".tar"):
|
|
34
|
+
return "tar.bz2"
|
|
35
|
+
if ext in {".xz"} and p.endswith(".tar"):
|
|
36
|
+
return "tar.xz"
|
|
37
|
+
if ext == ".gz":
|
|
38
|
+
return "gzip"
|
|
39
|
+
if ext == ".bz2":
|
|
40
|
+
return "bzip2"
|
|
41
|
+
if ext == ".xz":
|
|
42
|
+
return "xz"
|
|
43
|
+
if ext == ".7z":
|
|
44
|
+
return "7z"
|
|
45
|
+
if ext == ".rar":
|
|
46
|
+
return "rar"
|
|
47
|
+
return "unknown"
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def _extract_stream(open_func, path: Path, out_dir: Path):
|
|
51
|
+
"""Helper for single-file compressed streams (.gz, .bz2, .xz)."""
|
|
52
|
+
out_dir.mkdir(parents=True, exist_ok=True)
|
|
53
|
+
out_file = out_dir / path.with_suffix("").name
|
|
54
|
+
with open_func(path, "rb") as f_in, open(out_file, "wb") as f_out:
|
|
55
|
+
shutil.copyfileobj(f_in, f_out)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
# ---------- Extraction --------------------------------------------------------
|
|
59
|
+
def extract_archive(path: str | Path, out_dir: str | Path) -> None:
|
|
60
|
+
"""Detect the archive type and extract it into out_dir."""
|
|
61
|
+
path, out_dir = Path(path), Path(out_dir)
|
|
62
|
+
archive_type = detect_archive_type(path)
|
|
63
|
+
|
|
64
|
+
match archive_type:
|
|
65
|
+
# --- ZIP
|
|
66
|
+
case "zip":
|
|
67
|
+
with zipfile.ZipFile(path) as zf:
|
|
68
|
+
zf.extractall(out_dir)
|
|
69
|
+
|
|
70
|
+
# --- tar.* (auto-deduces compression)
|
|
71
|
+
case "tar" | "tar.gz" | "tar.bz2" | "tar.xz":
|
|
72
|
+
with tarfile.open(path, mode="r:*") as tf:
|
|
73
|
+
tf.extractall(out_dir)
|
|
74
|
+
|
|
75
|
+
# --- single-file streams
|
|
76
|
+
case "gzip":
|
|
77
|
+
_extract_stream(gzip.open, path, out_dir)
|
|
78
|
+
case "bzip2":
|
|
79
|
+
_extract_stream(bz2.open, path, out_dir)
|
|
80
|
+
case "xz":
|
|
81
|
+
_extract_stream(lzma.open, path, out_dir)
|
|
82
|
+
|
|
83
|
+
# --- 7-Zip
|
|
84
|
+
case "7z":
|
|
85
|
+
if py7zr is None:
|
|
86
|
+
raise ImportError("py7zr not installed - run `pip install py7zr`")
|
|
87
|
+
with py7zr.SevenZipFile(path, mode="r") as z:
|
|
88
|
+
z.extractall(path=out_dir)
|
|
89
|
+
|
|
90
|
+
# --- RAR
|
|
91
|
+
case "rar":
|
|
92
|
+
if rarfile is None:
|
|
93
|
+
raise ImportError("rarfile not installed - run `pip install rarfile`")
|
|
94
|
+
if not rarfile.is_rarfile(path):
|
|
95
|
+
raise rarfile.BadRarFile(f"{path} is not a valid RAR archive")
|
|
96
|
+
with rarfile.RarFile(path) as rf:
|
|
97
|
+
rf.extractall(out_dir)
|
|
98
|
+
|
|
99
|
+
# --- fallback
|
|
100
|
+
case _:
|
|
101
|
+
raise ValueError(f"Unsupported or unknown archive type: {archive_type}")
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
from datetime import datetime
|
|
2
|
+
from enum import Enum
|
|
3
|
+
|
|
4
|
+
from humalab.constants import DEFAULT_PROJECT
|
|
5
|
+
|
|
6
|
+
class ResourceType(Enum):
|
|
7
|
+
"""Enumeration of supported resource file types.
|
|
8
|
+
|
|
9
|
+
Supported types include URDF, MJCF, USD formats for robot descriptions,
|
|
10
|
+
MESH for 3D models, VIDEO and IMAGE for media files, and DATA for generic data.
|
|
11
|
+
"""
|
|
12
|
+
URDF = "urdf"
|
|
13
|
+
MJCF = "mjcf"
|
|
14
|
+
USD = "usd"
|
|
15
|
+
MESH = "mesh"
|
|
16
|
+
VIDEO = "video"
|
|
17
|
+
IMAGE = "image"
|
|
18
|
+
DATA = "data"
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class ResourceFile:
|
|
23
|
+
"""Represents a resource file stored in HumaLab.
|
|
24
|
+
|
|
25
|
+
Resource files are versioned assets that can be downloaded and used in runs.
|
|
26
|
+
They include robot descriptions, meshes, media files, and other data.
|
|
27
|
+
|
|
28
|
+
Attributes:
|
|
29
|
+
project (str): The project name this resource belongs to.
|
|
30
|
+
name (str): The resource name.
|
|
31
|
+
version (int): The version number of this resource.
|
|
32
|
+
filename (str): The local filesystem path to the resource file.
|
|
33
|
+
resource_type (ResourceType): The type of resource.
|
|
34
|
+
created_at (datetime | None): When the resource was created.
|
|
35
|
+
description (str | None): Optional description of the resource.
|
|
36
|
+
"""
|
|
37
|
+
def __init__(self,
|
|
38
|
+
name: str,
|
|
39
|
+
version: int,
|
|
40
|
+
filename: str,
|
|
41
|
+
resource_type: str | ResourceType,
|
|
42
|
+
project: str = DEFAULT_PROJECT,
|
|
43
|
+
description: str | None = None,
|
|
44
|
+
created_at: datetime | None = None):
|
|
45
|
+
self._project = project
|
|
46
|
+
self._name = name
|
|
47
|
+
self._version = version
|
|
48
|
+
self._filename = filename
|
|
49
|
+
self._resource_type = ResourceType(resource_type)
|
|
50
|
+
self._description = description
|
|
51
|
+
self._created_at = created_at
|
|
52
|
+
|
|
53
|
+
@property
|
|
54
|
+
def project(self) -> str:
|
|
55
|
+
"""The project name this resource belongs to.
|
|
56
|
+
|
|
57
|
+
Returns:
|
|
58
|
+
str: The project name.
|
|
59
|
+
"""
|
|
60
|
+
return self._project
|
|
61
|
+
|
|
62
|
+
@property
|
|
63
|
+
def name(self) -> str:
|
|
64
|
+
"""The resource name.
|
|
65
|
+
|
|
66
|
+
Returns:
|
|
67
|
+
str: The resource name.
|
|
68
|
+
"""
|
|
69
|
+
return self._name
|
|
70
|
+
|
|
71
|
+
@property
|
|
72
|
+
def version(self) -> int:
|
|
73
|
+
"""The version number of this resource.
|
|
74
|
+
|
|
75
|
+
Returns:
|
|
76
|
+
int: The version number.
|
|
77
|
+
"""
|
|
78
|
+
return self._version
|
|
79
|
+
|
|
80
|
+
@property
|
|
81
|
+
def filename(self) -> str:
|
|
82
|
+
"""The local filesystem path to the resource file.
|
|
83
|
+
|
|
84
|
+
Returns:
|
|
85
|
+
str: The file path.
|
|
86
|
+
"""
|
|
87
|
+
return self._filename
|
|
88
|
+
|
|
89
|
+
@property
|
|
90
|
+
def resource_type(self) -> ResourceType:
|
|
91
|
+
"""The type of resource.
|
|
92
|
+
|
|
93
|
+
Returns:
|
|
94
|
+
ResourceType: The resource type.
|
|
95
|
+
"""
|
|
96
|
+
return self._resource_type
|
|
97
|
+
|
|
98
|
+
@property
|
|
99
|
+
def created_at(self) -> datetime | None:
|
|
100
|
+
"""When the resource was created.
|
|
101
|
+
|
|
102
|
+
Returns:
|
|
103
|
+
datetime | None: The creation timestamp, or None if not available.
|
|
104
|
+
"""
|
|
105
|
+
return self._created_at
|
|
106
|
+
|
|
107
|
+
@property
|
|
108
|
+
def description(self) -> str | None:
|
|
109
|
+
"""Optional description of the resource.
|
|
110
|
+
|
|
111
|
+
Returns:
|
|
112
|
+
str | None: The description, or None if not provided.
|
|
113
|
+
"""
|
|
114
|
+
return self._description
|
|
115
|
+
|
|
116
|
+
def __repr__(self) -> str:
|
|
117
|
+
"""String representation of the resource file.
|
|
118
|
+
|
|
119
|
+
Returns:
|
|
120
|
+
str: String representation with all attributes.
|
|
121
|
+
"""
|
|
122
|
+
return f"ResourceFile(project={self._project}, name={self._name}, version={self._version}, filename={self._filename}, resource_type={self._resource_type}, description={self._description}, created_at={self._created_at})"
|
|
123
|
+
|
|
124
|
+
def __str__(self) -> str:
|
|
125
|
+
"""String representation of the resource file.
|
|
126
|
+
|
|
127
|
+
Returns:
|
|
128
|
+
str: Same as __repr__.
|
|
129
|
+
"""
|
|
130
|
+
return self.__repr__()
|
|
131
|
+
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import glob
|
|
3
|
+
from datetime import datetime
|
|
4
|
+
|
|
5
|
+
from humalab.assets.files.resource_file import ResourceFile, ResourceType
|
|
6
|
+
from humalab.assets.archive import extract_archive
|
|
7
|
+
from humalab.constants import DEFAULT_PROJECT
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class URDFFile(ResourceFile):
|
|
11
|
+
"""Represents a URDF (Unified Robot Description Format) file resource.
|
|
12
|
+
|
|
13
|
+
URDF files describe robot kinematics and geometry. This class handles
|
|
14
|
+
automatic extraction of compressed URDF archives and locates the main
|
|
15
|
+
URDF file within the extracted contents.
|
|
16
|
+
|
|
17
|
+
Attributes:
|
|
18
|
+
urdf_filename (str | None): Path to the main URDF file.
|
|
19
|
+
root_path (str): Root directory containing the extracted URDF and assets.
|
|
20
|
+
"""
|
|
21
|
+
def __init__(self,
|
|
22
|
+
name: str,
|
|
23
|
+
version: int,
|
|
24
|
+
filename: str,
|
|
25
|
+
project: str = DEFAULT_PROJECT,
|
|
26
|
+
urdf_filename: str | None = None,
|
|
27
|
+
description: str | None = None,
|
|
28
|
+
created_at: datetime | None = None,):
|
|
29
|
+
super().__init__(project=project,
|
|
30
|
+
name=name,
|
|
31
|
+
version=version,
|
|
32
|
+
description=description,
|
|
33
|
+
filename=filename,
|
|
34
|
+
resource_type=ResourceType.URDF,
|
|
35
|
+
created_at=created_at)
|
|
36
|
+
self._urdf_base_filename = urdf_filename
|
|
37
|
+
self._urdf_filename, self._root_path = self._extract()
|
|
38
|
+
self._urdf_filename = os.path.join(self._urdf_filename, self._urdf_filename)
|
|
39
|
+
|
|
40
|
+
def _extract(self):
|
|
41
|
+
"""Extract the URDF archive and locate the main URDF file.
|
|
42
|
+
|
|
43
|
+
Returns:
|
|
44
|
+
tuple[str, str]: (urdf_filename, root_path)
|
|
45
|
+
"""
|
|
46
|
+
working_path = os.path.dirname(self.filename)
|
|
47
|
+
if os.path.exists(self.filename):
|
|
48
|
+
_, ext = os.path.splitext(self.filename)
|
|
49
|
+
ext = ext.lstrip('.') # Remove leading dot
|
|
50
|
+
if ext.lower() != "urdf":
|
|
51
|
+
extract_archive(self.filename, working_path)
|
|
52
|
+
try:
|
|
53
|
+
os.remove(self.filename)
|
|
54
|
+
except Exception as e:
|
|
55
|
+
print(f"Error removing saved file {self.filename}: {e}")
|
|
56
|
+
local_filename = self.search_resource_file(self._urdf_base_filename, working_path)
|
|
57
|
+
if local_filename is None:
|
|
58
|
+
raise ValueError(f"Resource filename {self._urdf_base_filename} not found in {working_path}")
|
|
59
|
+
return local_filename, working_path
|
|
60
|
+
|
|
61
|
+
def search_resource_file(self, resource_filename: str | None, working_path: str) -> str | None:
|
|
62
|
+
"""Search for a URDF file in the working directory.
|
|
63
|
+
|
|
64
|
+
Args:
|
|
65
|
+
resource_filename (str | None): Optional specific filename to search for.
|
|
66
|
+
working_path (str): Directory to search within.
|
|
67
|
+
|
|
68
|
+
Returns:
|
|
69
|
+
str | None: Path to the found URDF file, or None if not found.
|
|
70
|
+
"""
|
|
71
|
+
found_filename = None
|
|
72
|
+
if resource_filename:
|
|
73
|
+
search_path = os.path.join(working_path, "**")
|
|
74
|
+
search_pattern = os.path.join(search_path, resource_filename)
|
|
75
|
+
files = glob.glob(search_pattern, recursive=True)
|
|
76
|
+
if len(files) > 0:
|
|
77
|
+
found_filename = files[0]
|
|
78
|
+
|
|
79
|
+
if found_filename is None:
|
|
80
|
+
ext = "urdf"
|
|
81
|
+
search_pattern = os.path.join(working_path, "**", f"*.{ext}")
|
|
82
|
+
files = glob.glob(search_pattern, recursive=True)
|
|
83
|
+
if len(files) > 0:
|
|
84
|
+
found_filename = files[0]
|
|
85
|
+
return found_filename
|
|
86
|
+
|
|
87
|
+
@property
|
|
88
|
+
def urdf_filename(self) -> str | None:
|
|
89
|
+
"""Path to the main URDF file.
|
|
90
|
+
|
|
91
|
+
Returns:
|
|
92
|
+
str | None: The URDF file path.
|
|
93
|
+
"""
|
|
94
|
+
return self._urdf_filename
|
|
95
|
+
|
|
96
|
+
@property
|
|
97
|
+
def root_path(self) -> str:
|
|
98
|
+
"""Root directory containing the extracted URDF and assets.
|
|
99
|
+
|
|
100
|
+
Returns:
|
|
101
|
+
str: The root path.
|
|
102
|
+
"""
|
|
103
|
+
return self._root_path
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
from humalab.constants import DEFAULT_PROJECT
|
|
2
|
+
from humalab.assets.files.resource_file import ResourceFile, ResourceType
|
|
3
|
+
from humalab.humalab_config import HumalabConfig
|
|
4
|
+
from humalab.humalab_api_client import HumaLabApiClient
|
|
5
|
+
from humalab.assets.files.urdf_file import URDFFile
|
|
6
|
+
import os
|
|
7
|
+
from typing import Any, Optional
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def _asset_dir(humalab_config: HumalabConfig, name: str, version: int) -> str:
|
|
11
|
+
"""Get the local directory path for a specific asset version.
|
|
12
|
+
|
|
13
|
+
Args:
|
|
14
|
+
humalab_config (HumalabConfig): Configuration containing workspace path.
|
|
15
|
+
name (str): Asset name.
|
|
16
|
+
version (int): Asset version.
|
|
17
|
+
|
|
18
|
+
Returns:
|
|
19
|
+
str: Path to the asset directory.
|
|
20
|
+
"""
|
|
21
|
+
return os.path.join(humalab_config.workspace_path, "assets", name, f"{version}")
|
|
22
|
+
|
|
23
|
+
def _create_asset_dir(humalab_config: HumalabConfig, name: str, version: int) -> bool:
|
|
24
|
+
"""Create the local directory for an asset if it doesn't exist.
|
|
25
|
+
|
|
26
|
+
Args:
|
|
27
|
+
humalab_config (HumalabConfig): Configuration containing workspace path.
|
|
28
|
+
name (str): Asset name.
|
|
29
|
+
version (int): Asset version.
|
|
30
|
+
|
|
31
|
+
Returns:
|
|
32
|
+
bool: True if directory was created, False if it already existed.
|
|
33
|
+
"""
|
|
34
|
+
asset_dir = _asset_dir(humalab_config, name, version)
|
|
35
|
+
if not os.path.exists(asset_dir):
|
|
36
|
+
os.makedirs(asset_dir, exist_ok=True)
|
|
37
|
+
return True
|
|
38
|
+
return False
|
|
39
|
+
|
|
40
|
+
def download(name: str,
|
|
41
|
+
version: int | None=None,
|
|
42
|
+
project: str = DEFAULT_PROJECT,
|
|
43
|
+
|
|
44
|
+
host: str | None = None,
|
|
45
|
+
api_key: str | None = None,
|
|
46
|
+
timeout: float | None = None,
|
|
47
|
+
) -> Any:
|
|
48
|
+
"""Download a resource from HumaLab.
|
|
49
|
+
|
|
50
|
+
Args:
|
|
51
|
+
name (str): The resource name to download.
|
|
52
|
+
version (int | None): Optional specific version. If None, downloads latest.
|
|
53
|
+
project (str): The project name. Defaults to DEFAULT_PROJECT.
|
|
54
|
+
host (str | None): Optional API host override.
|
|
55
|
+
api_key (str | None): Optional API key override.
|
|
56
|
+
timeout (float | None): Optional timeout override.
|
|
57
|
+
|
|
58
|
+
Returns:
|
|
59
|
+
ResourceFile | URDFFile: The downloaded resource file object.
|
|
60
|
+
"""
|
|
61
|
+
humalab_config = HumalabConfig()
|
|
62
|
+
|
|
63
|
+
api_client = HumaLabApiClient(base_url=host,
|
|
64
|
+
api_key=api_key,
|
|
65
|
+
timeout=timeout)
|
|
66
|
+
|
|
67
|
+
resource = api_client.get_resource(project_name=project, name=name, version=version)
|
|
68
|
+
filename = os.path.basename(resource['resource_url'])
|
|
69
|
+
filename = os.path.join(_asset_dir(humalab_config, name, resource["version"]), filename)
|
|
70
|
+
if _create_asset_dir(humalab_config, name, resource["version"]):
|
|
71
|
+
file_content = api_client.download_resource(project_name=project, name="lerobot")
|
|
72
|
+
with open(filename, "wb") as f:
|
|
73
|
+
f.write(file_content)
|
|
74
|
+
|
|
75
|
+
if resource["resource_type"].lower() == "urdf":
|
|
76
|
+
return URDFFile(project=project,
|
|
77
|
+
name=name,
|
|
78
|
+
version=resource["version"],
|
|
79
|
+
description=resource.get("description"),
|
|
80
|
+
filename=filename,
|
|
81
|
+
urdf_filename=resource.get("filename"),
|
|
82
|
+
created_at=resource.get("created_at"))
|
|
83
|
+
|
|
84
|
+
return ResourceFile(project=project,
|
|
85
|
+
name=name,
|
|
86
|
+
version=resource["version"],
|
|
87
|
+
filename=filename,
|
|
88
|
+
resource_type=resource["resource_type"],
|
|
89
|
+
description=resource.get("description"),
|
|
90
|
+
created_at=resource.get("created_at"))
|
|
91
|
+
|
|
92
|
+
def list_resources(project: str = DEFAULT_PROJECT,
|
|
93
|
+
resource_types: Optional[list[str | ResourceType]] = None,
|
|
94
|
+
limit: int = 20,
|
|
95
|
+
offset: int = 0,
|
|
96
|
+
latest_only: bool = True,
|
|
97
|
+
|
|
98
|
+
host: str | None = None,
|
|
99
|
+
api_key: str | None = None,
|
|
100
|
+
timeout: float | None = None,) -> list[ResourceFile]:
|
|
101
|
+
"""List available resources from HumaLab.
|
|
102
|
+
|
|
103
|
+
Args:
|
|
104
|
+
project (str): The project name. Defaults to DEFAULT_PROJECT.
|
|
105
|
+
resource_types (Optional[list[str | ResourceType]]): Filter by resource types.
|
|
106
|
+
limit (int): Maximum number of resources to return. Defaults to 20.
|
|
107
|
+
offset (int): Pagination offset. Defaults to 0.
|
|
108
|
+
latest_only (bool): Only return latest versions. Defaults to True.
|
|
109
|
+
host (str | None): Optional API host override.
|
|
110
|
+
api_key (str | None): Optional API key override.
|
|
111
|
+
timeout (float | None): Optional timeout override.
|
|
112
|
+
|
|
113
|
+
Returns:
|
|
114
|
+
list[ResourceFile]: List of resource file objects.
|
|
115
|
+
"""
|
|
116
|
+
api_client = HumaLabApiClient(base_url=host,
|
|
117
|
+
api_key=api_key,
|
|
118
|
+
timeout=timeout)
|
|
119
|
+
|
|
120
|
+
resource_type_string = None
|
|
121
|
+
if resource_types:
|
|
122
|
+
resource_type_strings = {rt.value if isinstance(rt, ResourceType) else rt for rt in resource_types}
|
|
123
|
+
resource_type_string = ",".join(resource_type_strings)
|
|
124
|
+
resp = api_client.get_resources(project_name=project,
|
|
125
|
+
resource_types=resource_type_string,
|
|
126
|
+
limit=limit,
|
|
127
|
+
offset=offset,
|
|
128
|
+
latest_only=latest_only)
|
|
129
|
+
resources = resp.get("resources", [])
|
|
130
|
+
ret_list = []
|
|
131
|
+
for resource in resources:
|
|
132
|
+
ret_list.append(ResourceFile(name=resource["name"],
|
|
133
|
+
version=resource.get("version"),
|
|
134
|
+
project=project,
|
|
135
|
+
filename=resource.get("filename"),
|
|
136
|
+
resource_type=resource.get("resource_type"),
|
|
137
|
+
description=resource.get("description"),
|
|
138
|
+
created_at=resource.get("created_at")))
|
|
139
|
+
return ret_list
|
humalab/constants.py
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"""Constants and enumerations used throughout the HumaLab SDK."""
|
|
2
|
+
|
|
3
|
+
from enum import Enum
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
RESERVED_NAMES = {
|
|
7
|
+
"sceanario",
|
|
8
|
+
"seed",
|
|
9
|
+
}
|
|
10
|
+
"""Set of reserved names that cannot be used for metric or artifact keys."""
|
|
11
|
+
|
|
12
|
+
DEFAULT_PROJECT = "default"
|
|
13
|
+
"""Default project name used when no project is specified."""
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class ArtifactType(Enum):
|
|
17
|
+
"""Types of artifacts that can be stored"""
|
|
18
|
+
METRICS = "metrics" # Run & Episode
|
|
19
|
+
SCENARIO_STATS = "scenario_stats" # Run only
|
|
20
|
+
PYTHON = "python" # Run & Episode
|
|
21
|
+
CODE = "code" # Run & Episode (YAML)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class MetricType(Enum):
|
|
25
|
+
"""Enumeration of metric types.
|
|
26
|
+
|
|
27
|
+
Maps to corresponding artifact types for metrics and scenario statistics.
|
|
28
|
+
"""
|
|
29
|
+
METRICS = ArtifactType.METRICS.value
|
|
30
|
+
SCENARIO_STATS = ArtifactType.SCENARIO_STATS.value
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class GraphType(Enum):
|
|
34
|
+
"""Types of graphs supported by Humalab."""
|
|
35
|
+
NUMERIC = "numeric"
|
|
36
|
+
LINE = "line"
|
|
37
|
+
BAR = "bar"
|
|
38
|
+
SCATTER = "scatter"
|
|
39
|
+
HISTOGRAM = "histogram"
|
|
40
|
+
GAUSSIAN = "gaussian"
|
|
41
|
+
HEATMAP = "heatmap"
|
|
42
|
+
THREE_D_MAP = "3d_map"
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class MetricDimType(Enum):
|
|
46
|
+
"""Types of metric dimensions"""
|
|
47
|
+
ZERO_D = "0d"
|
|
48
|
+
ONE_D = "1d"
|
|
49
|
+
TWO_D = "2d"
|
|
50
|
+
THREE_D = "3d"
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"""Probability distributions for scenario randomization.
|
|
2
|
+
|
|
3
|
+
This module provides various probability distribution classes used in scenario generation,
|
|
4
|
+
including uniform, gaussian, bernoulli, categorical, discrete, log-uniform, and truncated
|
|
5
|
+
gaussian distributions. Each supports 0D (scalar) and multi-dimensional (1D-3D) variants.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from .bernoulli import Bernoulli
|
|
9
|
+
from .categorical import Categorical
|
|
10
|
+
from .discrete import Discrete
|
|
11
|
+
from .gaussian import Gaussian
|
|
12
|
+
from .log_uniform import LogUniform
|
|
13
|
+
from .truncated_gaussian import TruncatedGaussian
|
|
14
|
+
from .uniform import Uniform
|
|
15
|
+
|
|
16
|
+
__all__ = [
|
|
17
|
+
"Bernoulli",
|
|
18
|
+
"Categorical",
|
|
19
|
+
"Discrete",
|
|
20
|
+
"LogUniform",
|
|
21
|
+
"Gaussian",
|
|
22
|
+
"TruncatedGaussian",
|
|
23
|
+
"Uniform",
|
|
24
|
+
]
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
from humalab.dists.distribution import Distribution
|
|
2
|
+
|
|
3
|
+
from typing import Any
|
|
4
|
+
import numpy as np
|
|
5
|
+
|
|
6
|
+
class Bernoulli(Distribution):
|
|
7
|
+
"""Bernoulli distribution for binary outcomes.
|
|
8
|
+
|
|
9
|
+
Samples binary values (0 or 1) with a specified probability of success.
|
|
10
|
+
Supports scalar outputs as well as multi-dimensional arrays with 1D variants.
|
|
11
|
+
"""
|
|
12
|
+
def __init__(self,
|
|
13
|
+
generator: np.random.Generator,
|
|
14
|
+
p: float | Any,
|
|
15
|
+
size: int | tuple[int, ...] | None = None) -> None:
|
|
16
|
+
"""
|
|
17
|
+
Initialize the Bernoulli distribution.
|
|
18
|
+
|
|
19
|
+
Args:
|
|
20
|
+
generator (np.random.Generator): The random number generator.
|
|
21
|
+
p (float | Any): The probability of success.
|
|
22
|
+
size (int | tuple[int, ...] | None): The size of the output.
|
|
23
|
+
"""
|
|
24
|
+
super().__init__(generator=generator)
|
|
25
|
+
self._p = p
|
|
26
|
+
self._size = size
|
|
27
|
+
|
|
28
|
+
@staticmethod
|
|
29
|
+
def validate(dimensions: int, *args) -> bool:
|
|
30
|
+
"""Validate distribution parameters for the given dimensions.
|
|
31
|
+
|
|
32
|
+
Args:
|
|
33
|
+
dimensions (int): The number of dimensions (0 for scalar, -1 for any).
|
|
34
|
+
*args: The distribution parameters (p).
|
|
35
|
+
|
|
36
|
+
Returns:
|
|
37
|
+
bool: True if parameters are valid, False otherwise.
|
|
38
|
+
"""
|
|
39
|
+
arg1 = args[0]
|
|
40
|
+
if dimensions == 0:
|
|
41
|
+
if not isinstance(arg1, (int, float)):
|
|
42
|
+
return False
|
|
43
|
+
return True
|
|
44
|
+
if dimensions == -1:
|
|
45
|
+
return True
|
|
46
|
+
if not isinstance(arg1, (int, float)):
|
|
47
|
+
if isinstance(arg1, (list, np.ndarray)):
|
|
48
|
+
if len(arg1) != dimensions:
|
|
49
|
+
return False
|
|
50
|
+
|
|
51
|
+
return True
|
|
52
|
+
|
|
53
|
+
def _sample(self) -> int | float | np.ndarray:
|
|
54
|
+
"""Generate a sample from the Bernoulli distribution.
|
|
55
|
+
|
|
56
|
+
Returns:
|
|
57
|
+
int | float | np.ndarray: Sampled binary value(s) (0 or 1).
|
|
58
|
+
"""
|
|
59
|
+
return self._generator.binomial(n=1, p=self._p, size=self._size)
|
|
60
|
+
|
|
61
|
+
def __repr__(self) -> str:
|
|
62
|
+
"""String representation of the Bernoulli distribution.
|
|
63
|
+
|
|
64
|
+
Returns:
|
|
65
|
+
str: String representation showing p and size.
|
|
66
|
+
"""
|
|
67
|
+
return f"Bernoulli(p={self._p}, size={self._size})"
|
|
68
|
+
|
|
69
|
+
@staticmethod
|
|
70
|
+
def create(generator: np.random.Generator,
|
|
71
|
+
p: float | Any,
|
|
72
|
+
size: int | tuple[int, ...] | None = None) -> 'Bernoulli':
|
|
73
|
+
"""
|
|
74
|
+
Create a Bernoulli distribution.
|
|
75
|
+
|
|
76
|
+
Args:
|
|
77
|
+
generator (np.random.Generator): The random number generator.
|
|
78
|
+
p (float | Any): The probability of success.
|
|
79
|
+
size (int | tuple[int, ...] | None): The size of the output.
|
|
80
|
+
|
|
81
|
+
Returns:
|
|
82
|
+
Bernoulli: The created Bernoulli distribution.
|
|
83
|
+
"""
|
|
84
|
+
return Bernoulli(generator=generator, p=p, size=size)
|