Skip to content
Open
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
Binary file added .coverage.187cd0c7f35e.624.XupRuNYx
Binary file not shown.
71 changes: 68 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,69 @@
__pycache__
build
# Python
__pycache__/
*.py[cod]
*$py.class
*.so
runs
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
*.egg-info/
.installed.cfg
*.egg

# Testing
.pytest_cache/
.coverage
htmlcov/
coverage.xml
*.cover
.hypothesis/
.tox/
.nox/

# Virtual environments
env/
venv/
ENV/
env.bak/
venv.bak/

# IDE
.vscode/
.idea/
*.swp
*.swo
*~
.DS_Store

# Project specific
runs/
outputs/
checkpoints/
*.pth
*.ckpt

# Claude
.claude/*

# Poetry
poetry.lock

# Build artifacts
*.o
*.obj
*.exp
*.lib
*.dll
*.exe
*.out
*.app
113 changes: 113 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
[tool.poetry]
name = "dva-mvp"
version = "0.1.0"
description = "DVA-MVP: Diffusion Model for 3D Generation"
authors = ["Your Name <you@example.com>"]
readme = "README.md"
packages = [{include = "dva"}, {include = "models"}, {include = "datasets"}, {include = "utils"}]

[tool.poetry.dependencies]
python = ">=3.9,<3.12"
einops = "*"
omegaconf = "*"
opencv-python = "*"
libigl = "*"
trimesh = "4.2.0"
pygltflib = "*"
pymeshlab = "0.2"
PyMCubes = "*"
xatlas = "*"
nvdiffrast = {git = "https://github.com/NVlabs/nvdiffrast/"}
scikit-learn = "*"
open-clip-torch = "*"
triton = "2.1.0"
rembg = "*"
gradio = "*"
tqdm = "*"
transformers = "4.40.1"
diffusers = "0.19.3"
ninja = "*"
imageio = "*"
imageio-ffmpeg = "*"
gradio-litmodel3d = "0.0.1"
jaxtyping = "0.2.31"

[tool.poetry.group.dev.dependencies]
pytest = "^8.0.0"
pytest-cov = "^5.0.0"
pytest-mock = "^3.14.0"
pillow = "^10.0.0"

[tool.poetry.scripts]
test = "pytest:main"
tests = "pytest:main"

[tool.pytest.ini_options]
minversion = "8.0"
testpaths = ["tests"]
python_files = ["test_*.py", "*_test.py"]
python_classes = ["Test*", "*Tests"]
python_functions = ["test_*"]
addopts = """
-v
--strict-markers
--strict-config
--cov=dva
--cov=models
--cov=datasets
--cov=utils
--cov-branch
--cov-report=term-missing:skip-covered
--cov-report=html:htmlcov
--cov-report=xml:coverage.xml
"""
markers = [
"unit: marks tests as unit tests (fast, isolated)",
"integration: marks tests as integration tests (may require external resources)",
"slow: marks tests as slow (deselect with '-m \"not slow\"')",
]
console_output_style = "progress"
filterwarnings = [
"error",
"ignore::UserWarning",
"ignore::DeprecationWarning",
]

[tool.coverage.run]
source = ["dva", "models", "datasets", "utils"]
omit = [
"*/tests/*",
"*/test_*",
"*/__init__.py",
"*/setup.py",
"*/simple-knn/*",
"*/extensions/*",
]

[tool.coverage.report]
exclude_lines = [
"pragma: no cover",
"def __repr__",
"if self.debug:",
"if settings.DEBUG",
"raise AssertionError",
"raise NotImplementedError",
"if 0:",
"if __name__ == .__main__.:",
"if TYPE_CHECKING:",
"class .*\\bProtocol\\):",
"@(abc\\.)?abstractmethod",
]
precision = 2
show_missing = true
skip_covered = false

[tool.coverage.html]
directory = "htmlcov"

[tool.coverage.xml]
output = "coverage.xml"

[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"
Empty file added tests/__init__.py
Empty file.
166 changes: 166 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
"""Shared pytest fixtures and configuration for all tests."""

import os
import tempfile
import shutil
from pathlib import Path
from typing import Generator, Dict, Any

import pytest
import numpy as np
import torch
from omegaconf import DictConfig, OmegaConf


@pytest.fixture
def temp_dir() -> Generator[Path, None, None]:
"""Create a temporary directory for test files."""
temp_path = tempfile.mkdtemp()
yield Path(temp_path)
shutil.rmtree(temp_path)


@pytest.fixture
def sample_config() -> DictConfig:
"""Create a sample configuration for testing."""
config = {
"model": {
"type": "test_model",
"hidden_dim": 128,
"num_layers": 4,
},
"training": {
"batch_size": 32,
"learning_rate": 1e-4,
"num_epochs": 10,
},
"data": {
"dataset": "test_dataset",
"num_workers": 4,
},
}
return OmegaConf.create(config)


@pytest.fixture
def mock_tensor_data() -> Dict[str, torch.Tensor]:
"""Create mock tensor data for testing."""
return {
"input": torch.randn(4, 3, 256, 256),
"target": torch.randn(4, 128, 128, 128),
"mask": torch.ones(4, 1, 256, 256),
}


@pytest.fixture
def mock_numpy_data() -> Dict[str, np.ndarray]:
"""Create mock numpy data for testing."""
return {
"points": np.random.randn(1000, 3).astype(np.float32),
"colors": np.random.randint(0, 255, (1000, 3), dtype=np.uint8),
"normals": np.random.randn(1000, 3).astype(np.float32),
}


@pytest.fixture
def sample_image_path(temp_dir: Path) -> Path:
"""Create a sample image file for testing."""
image_path = temp_dir / "test_image.png"
# Create a simple 10x10 white image
import numpy as np
from PIL import Image

img_array = np.ones((10, 10, 3), dtype=np.uint8) * 255
img = Image.fromarray(img_array)
img.save(image_path)
return image_path


@pytest.fixture
def sample_mesh_data() -> Dict[str, Any]:
"""Create sample mesh data for testing."""
vertices = np.array([
[0, 0, 0],
[1, 0, 0],
[0, 1, 0],
[0, 0, 1],
], dtype=np.float32)

faces = np.array([
[0, 1, 2],
[0, 1, 3],
[0, 2, 3],
[1, 2, 3],
], dtype=np.int32)

return {
"vertices": vertices,
"faces": faces,
"vertex_colors": np.random.rand(4, 3).astype(np.float32),
}


@pytest.fixture
def device() -> torch.device:
"""Get the appropriate device for testing."""
return torch.device("cuda" if torch.cuda.is_available() else "cpu")


@pytest.fixture(autouse=True)
def reset_random_seeds():
"""Reset random seeds before each test for reproducibility."""
np.random.seed(42)
torch.manual_seed(42)
if torch.cuda.is_available():
torch.cuda.manual_seed_all(42)
torch.backends.cudnn.deterministic = True
torch.backends.cudnn.benchmark = False


@pytest.fixture
def mock_model_weights(temp_dir: Path) -> Path:
"""Create mock model weights file."""
weights_path = temp_dir / "model_weights.pth"
torch.save({
"model_state_dict": {"layer1.weight": torch.randn(10, 10)},
"optimizer_state_dict": {"param_groups": []},
"epoch": 5,
"loss": 0.123,
}, weights_path)
return weights_path


@pytest.fixture
def environment_variables() -> Generator[Dict[str, str], None, None]:
"""Temporarily set environment variables for testing."""
original_env = os.environ.copy()
test_env = {
"TEST_MODE": "true",
"LOG_LEVEL": "DEBUG",
}
os.environ.update(test_env)
yield test_env
# Restore original environment
os.environ.clear()
os.environ.update(original_env)


# Custom markers configuration
def pytest_configure(config):
"""Configure custom markers."""
config.addinivalue_line(
"markers", "gpu: marks tests that require GPU (deselect with '-m \"not gpu\"')"
)
config.addinivalue_line(
"markers", "network: marks tests that require network access"
)


# Hook to skip GPU tests if CUDA is not available
def pytest_collection_modifyitems(config, items):
"""Modify test collection to skip GPU tests when appropriate."""
if not torch.cuda.is_available():
skip_gpu = pytest.mark.skip(reason="GPU not available")
for item in items:
if "gpu" in item.keywords:
item.add_marker(skip_gpu)
Empty file added tests/integration/__init__.py
Empty file.
Loading