Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -49,4 +49,8 @@ scratch/
sample_data/
external_ckpts/
external/MANO/

# setuptools build output
build/
dist/
docs/
20 changes: 18 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,16 +40,32 @@ git clone [email protected]:GaTech-RL2/EgoVerse.git
cd EgoVerse
uv venv emimic --python 3.11
source emimic/bin/activate
uv pip install -r requirements.txt
uv pip install -e .
uv run pre-commit install
```

`pyproject.toml` (locked in `uv.lock`) is the dependency spec for the
package. Three things live outside it: `requirements.txt` (used only by the
Eva robot `Dockerfile`), `requirements-ray.txt` (the Ray data-processing
image) and `scale_sensor_fusion_io`, needed only by the Scale converter under
`external/scale/scripts` (`uv pip install scale-sensor-fusion-io`).

For the Pi0.5 policy also install the `openpi` fork from the submodule. It is
installed without its own dependencies (its `lerobot` pin needs `av>=14.2`,
which conflicts with our `av==12.0.0`), then its `transformers` patch is copied in:
```
git submodule update --init external/openpi
uv pip install --no-deps -e external/openpi
cp -r external/openpi/src/openpi/models_pytorch/transformers_replace/* emimic/lib/python3.11/site-packages/transformers/
```
Re-run the `cp` after any `uv sync` or `transformers` reinstall, which silently
undoes the patch. See `pi05.md` for details.

### Conda
```
git clone --recursive [email protected]:GaTech-RL2/EgoVerse.git
cd EgoVerse
conda env create -f environment.yaml
conda create -n emimic python=3.11
conda activate emimic
pip install -e .
pre-commit install
Expand Down
9 changes: 0 additions & 9 deletions environment.yaml

This file was deleted.

17 changes: 17 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -64,10 +64,27 @@ dependencies = [
"scaleapi",
"openai",
"scikit-learn>=1.8.0",
"scipy",
]

# Not declared: `openpi` (egomimic/algo/pi.py). The fork at external/openpi pins
# lerobot -> av>=14.2, which conflicts with av==12.0.0 above, so it cannot be a
# resolvable extra. Install it without its dependencies, as the lab venv does:
# uv pip install --no-deps -e external/openpi
# then apply openpi's `transformers_replace` patch (README, "Installation").
# `uv sync` reinstalls transformers and silently undoes that patch.
#
# Also not declared: `scale_sensor_fusion_io` (PyPI: scale-sensor-fusion-io),
# imported only by the Scale converter under external/scale/scripts, which is
# not part of this package; install it by hand when running that converter.
# The Ray data-processing image keeps its own requirements-ray.txt.

[tool.setuptools.packages.find]
where = ["."]
include = ["egomimic*"]

[tool.setuptools.package-data]
egomimic = ["hydra_configs/**/*.yaml", "resources/*"]

[tool.pytest.ini_options]
testpaths = ["tests"]
Expand Down
13 changes: 0 additions & 13 deletions setup.py

This file was deleted.

79 changes: 79 additions & 0 deletions tests/unit/test_packaging.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
"""A non-editable install must ship the training stack and nothing else.

Builds the wheel with the configured build backend (no pip / uv needed) and
inspects its contents: Hydra configs and robot resources must be inside,
``external/`` and ``tests/`` must not be.
"""

import shutil
import subprocess
import sys
import zipfile
from pathlib import Path

import pytest

REPO = Path(__file__).resolve().parents[2]


@pytest.fixture(scope="module")
def wheel_files(tmp_path_factory) -> list[str]:
out = tmp_path_factory.mktemp("wheel")
# setuptools reuses a stale build/lib (deleted modules would linger in the
# wheel); build from a clean slate and leave the checkout as we found it.
shutil.rmtree(REPO / "build", ignore_errors=True)
code = (
"import sys; from setuptools import build_meta; "
f"print(build_meta.build_wheel({str(out)!r}))"
)
proc = subprocess.run(
[sys.executable, "-c", code],
cwd=REPO,
capture_output=True,
text=True,
timeout=600,
)
shutil.rmtree(REPO / "build", ignore_errors=True)
assert proc.returncode == 0, proc.stderr[-3000:]
wheel = next(out.glob("*.whl"))
with zipfile.ZipFile(wheel) as zf:
return zf.namelist()


def test_wheel_does_not_ship_external_or_tests(wheel_files):
stray = sorted(
{n.split("/")[0] for n in wheel_files}
- {"egomimic"}
- {
n.split("/")[0]
for n in wheel_files
if n.split("/")[0].endswith(".dist-info")
}
)
assert stray == [], f"top-level entries other than egomimic in the wheel: {stray}"


def test_wheel_ships_hydra_configs(wheel_files):
packaged = {
n[len("egomimic/hydra_configs/") :]
for n in wheel_files
if n.startswith("egomimic/hydra_configs/") and n.endswith(".yaml")
}
on_disk = {
str(p.relative_to(REPO / "egomimic/hydra_configs"))
for p in (REPO / "egomimic/hydra_configs").rglob("*.yaml")
}
assert "train_zarr_cartesian.yaml" in packaged
assert "paths/default.yaml" in packaged
assert (
on_disk - packaged == set()
), f"hydra yamls missing from wheel: {sorted(on_disk - packaged)}"


def test_wheel_ships_robot_resources(wheel_files):
# model_x5.xml's meshdir points at egomimic/robot/eva/stanford_repo, which
# is not packaged, so the MJCF only loads from a checkout. Shipped anyway:
# the URDFs beside it are self-contained and the robot code resolves the
# XML relative to egomimic.__file__.
assert "egomimic/resources/model_x5.xml" in wheel_files
assert "egomimic/resources/model_arx.urdf" in wheel_files
2 changes: 2 additions & 0 deletions uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading