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
64 changes: 61 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,64 @@
# IDE and editor files
.idea
venv
*pyc
.vscode/
*.swp
*.swo
*~

# Python
__pycache__/
*.py[cod]
*$py.class
*.so
.Python
venv/
env/
ENV/
.venv/
*.egg-info/
dist/
build/
*.egg

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

# Claude
.claude/*

# Project specific
online_prepared_data
offline_prepared_data
threedod/sample_data
threedod/sample_data

# OS files
.DS_Store
Thumbs.db

# Jupyter
.ipynb_checkpoints/
*.ipynb_checkpoints

# Logs
*.log
logs/

# Model weights and checkpoints
*.pth
*.pt
*.ckpt
checkpoints/
weights/

# Data files
*.h5
*.hdf5
*.npz
*.npy
5,028 changes: 5,028 additions & 0 deletions poetry.lock

Large diffs are not rendered by default.

138 changes: 138 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
[tool.poetry]
name = "depth-upsampling-3dod"
version = "0.1.0"
description = "Depth upsampling and 3D object detection project"
authors = ["Your Name <[email protected]>"]
readme = "README.md"
packages = [
{ include = "depth_upsampling" },
{ include = "threedod" }
]

[tool.poetry.dependencies]
python = "^3.8"
numpy = "^1.20.3"
opencv-python = "^4.5.1"
pandas = "^1.3.3"
matplotlib = "^3.4.3"
torch = ">=1.9.1"
torchvision = ">=0.10.1"
tensorboard = "^2.0.0"
addict = "^2.4.0"
aiohttp = "^3.7.4"
async-timeout = "^3.0.1"
attrs = "^21.2.0"
autobahn = "^21.3.1"
Automat = "^20.2.0"
cffi = "^1.14.6"
chardet = "^4.0.0"
constantly = "^15.1.0"
cryptography = "^3.4.8"
cycler = "^0.10.0"
hyperlink = "^21.0.0"
idna = "^3.2"
incremental = "^21.3.0"
joblib = "^1.0.1"
kiwisolver = "^1.3.2"
multidict = "^5.1.0"
open3d = ">=0.13.0"
Pillow = "^8.3.2"
plyfile = "^0.7.4"
pycparser = "^2.20"
pyparsing = "^2.4.7"
python-dateutil = "^2.8.2"
pytz = "^2021.1"
PyYAML = "^6.0"
scikit-learn = "^1.0"
scipy = "^1.7.1"
six = "^1.16.0"
threadpoolctl = "^2.2.0"
tqdm = "^4.62.3"
Twisted = "^21.7.0"
txaio = "^21.2.1"
typing-extensions = ">=4.0.0"
vtk = "^9.0.3"
wslink = "^1.0.7"
yarl = "^1.6.3"
zope-interface = "^5.4.0"

[tool.poetry.group.dev.dependencies]
pytest = "^7.4.0"
pytest-cov = "^4.1.0"
pytest-mock = "^3.11.0"


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

[tool.pytest.ini_options]
minversion = "6.0"
addopts = [
"-ra",
"--strict-markers",
"--strict-config",
"--cov=depth_upsampling",
"--cov=threedod",
"--cov-branch",
"--cov-report=term-missing:skip-covered",
"--cov-report=html",
"--cov-report=xml",
"--cov-fail-under=80",
]
testpaths = ["tests"]
python_files = ["test_*.py", "*_test.py"]
python_classes = ["Test*"]
python_functions = ["test_*"]
markers = [
"unit: Unit tests",
"integration: Integration tests",
"slow: Slow running tests",
]
filterwarnings = [
"error",
"ignore::UserWarning",
"ignore::DeprecationWarning",
]

[tool.coverage.run]
source = ["depth_upsampling", "threedod"]
branch = true
parallel = true
omit = [
"*/tests/*",
"*/test_*",
"*/__init__.py",
"*/setup.py",
"*/conf.py",
"*/.venv/*",
"*/venv/*",
]

[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",
]
show_missing = true
skip_covered = true
fail_under = 80

[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.
173 changes: 173 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
import os
import shutil
import tempfile
from pathlib import Path
from typing import Generator
from unittest.mock import MagicMock

import pytest
import numpy as np
import torch


@pytest.fixture
def temp_dir() -> Generator[Path, None, None]:
"""Create a temporary directory that is cleaned up after the test."""
temp_path = Path(tempfile.mkdtemp())
yield temp_path
shutil.rmtree(temp_path)


@pytest.fixture
def mock_config() -> dict:
"""Provide a mock configuration dictionary for testing."""
return {
"model": {
"name": "test_model",
"num_classes": 10,
"input_channels": 3,
"learning_rate": 0.001,
},
"data": {
"batch_size": 32,
"num_workers": 4,
"train_path": "/path/to/train",
"val_path": "/path/to/val",
},
"training": {
"epochs": 100,
"checkpoint_dir": "/path/to/checkpoints",
"log_interval": 10,
},
}


@pytest.fixture
def sample_image() -> np.ndarray:
"""Create a sample image array for testing."""
return np.random.randint(0, 255, size=(480, 640, 3), dtype=np.uint8)


@pytest.fixture
def sample_depth_map() -> np.ndarray:
"""Create a sample depth map for testing."""
return np.random.rand(480, 640).astype(np.float32) * 10.0


@pytest.fixture
def sample_point_cloud() -> np.ndarray:
"""Create a sample 3D point cloud for testing."""
num_points = 1000
points = np.random.randn(num_points, 3).astype(np.float32)
return points


@pytest.fixture
def sample_torch_tensor() -> torch.Tensor:
"""Create a sample PyTorch tensor for testing."""
return torch.randn(1, 3, 224, 224)


@pytest.fixture
def mock_model() -> MagicMock:
"""Create a mock PyTorch model for testing."""
model = MagicMock()
model.eval = MagicMock(return_value=model)
model.train = MagicMock(return_value=model)
model.forward = MagicMock(return_value=torch.randn(1, 10))
model.parameters = MagicMock(return_value=[torch.randn(10, 10)])
return model


@pytest.fixture
def mock_dataset() -> MagicMock:
"""Create a mock dataset for testing."""
dataset = MagicMock()
dataset.__len__ = MagicMock(return_value=100)
dataset.__getitem__ = MagicMock(
return_value=(torch.randn(3, 224, 224), torch.tensor(1))
)
return dataset


@pytest.fixture
def mock_dataloader(mock_dataset) -> MagicMock:
"""Create a mock dataloader for testing."""
dataloader = MagicMock()
dataloader.__iter__ = MagicMock(
return_value=iter([(torch.randn(32, 3, 224, 224), torch.randint(0, 10, (32,)))])
)
dataloader.dataset = mock_dataset
return dataloader


@pytest.fixture
def sample_bounding_boxes() -> np.ndarray:
"""Create sample bounding boxes for 3D object detection testing."""
# Format: [x_center, y_center, z_center, width, height, depth, rotation]
boxes = np.array([
[0.0, 0.0, 5.0, 2.0, 1.5, 4.0, 0.0],
[3.0, 0.0, 10.0, 2.5, 1.8, 4.5, np.pi/4],
[-2.0, 0.0, 8.0, 1.8, 1.6, 3.8, -np.pi/6],
], dtype=np.float32)
return boxes


@pytest.fixture
def sample_lidar_data() -> np.ndarray:
"""Create sample LiDAR data for testing."""
num_points = 5000
# Generate points in a cone pattern to simulate LiDAR
angles = np.random.uniform(0, 2*np.pi, num_points)
distances = np.random.uniform(0.5, 50.0, num_points)
heights = np.random.uniform(-2.0, 2.0, num_points)

x = distances * np.cos(angles)
y = distances * np.sin(angles)
z = heights
intensity = np.random.uniform(0, 1, num_points)

return np.column_stack([x, y, z, intensity]).astype(np.float32)


@pytest.fixture(autouse=True)
def reset_environment():
"""Reset environment variables before each test."""
original_env = os.environ.copy()
yield
os.environ.clear()
os.environ.update(original_env)


@pytest.fixture
def capture_logs(caplog):
"""Fixture to capture log messages during tests."""
with caplog.at_level("DEBUG"):
yield caplog


def pytest_configure(config):
"""Configure pytest with custom settings."""
# Set random seeds for reproducibility
np.random.seed(42)
torch.manual_seed(42)
if torch.cuda.is_available():
torch.cuda.manual_seed(42)

# Disable GPU for tests by default
os.environ["CUDA_VISIBLE_DEVICES"] = ""


def pytest_collection_modifyitems(config, items):
"""Modify test collection to add markers automatically."""
for item in items:
# Add unit marker to tests in unit directory
if "unit" in str(item.fspath):
item.add_marker(pytest.mark.unit)
# Add integration marker to tests in integration directory
elif "integration" in str(item.fspath):
item.add_marker(pytest.mark.integration)

# Add slow marker to tests with "slow" in their name
if "slow" in item.nodeid:
item.add_marker(pytest.mark.slow)
Empty file added tests/integration/__init__.py
Empty file.
Loading