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
30 changes: 30 additions & 0 deletions .coveragerc
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
[run]
source = sbin
omit =
*/tests/*
*/__pycache__/*
*/venv/*
*/.venv/*

[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
precision = 2
# fail_under = 80 # Enable this when you have actual tests

[html]
directory = htmlcov

[xml]
output = coverage.xml
69 changes: 69 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
# Python
__pycache__/
*.py[cod]
*$py.class
*.so
.Python
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST

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

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

# IDEs
.idea/
.vscode/
*.swp
*.swo
*~
.project
.pydevproject
.settings/

# OS
.DS_Store
Thumbs.db

# Claude
.claude/*

# Build artifacts
build/
*.log

# Jupyter Notebook
.ipynb_checkpoints

# mypy
.mypy_cache/
.dmypy.json
dmypy.json

# Pyre type checker
.pyre/
282 changes: 282 additions & 0 deletions poetry.lock

Large diffs are not rendered by default.

72 changes: 72 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
[tool.poetry]
name = "ml-interpretability-papers"
version = "0.1.0"
description = "Machine Learning Interpretability Papers Collection"
authors = ["Your Name <[email protected]>"]
readme = "README.org"
packages = [{include = "sbin"}]

[tool.poetry.dependencies]
python = "^3.8"

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

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

[tool.pytest.ini_options]
minversion = "8.0"
addopts = [
"-ra",
"--strict-markers",
"--strict-config",
]
testpaths = ["tests"]
python_files = ["test_*.py", "*_test.py"]
python_classes = ["Test*"]
python_functions = ["test_*"]
markers = [
"unit: marks tests as unit tests (fast, isolated)",
"integration: marks tests as integration tests (may require external resources)",
"slow: marks tests as slow running",
]

[tool.coverage.run]
source = ["sbin"]
omit = [
"*/tests/*",
"*/__pycache__/*",
"*/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
precision = 2

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

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

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

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

import pytest


@pytest.fixture
def temp_dir() -> Generator[Path, None, None]:
"""Create a temporary directory for testing."""
with tempfile.TemporaryDirectory() as tmpdir:
yield Path(tmpdir)


@pytest.fixture
def sample_cache_data() -> Dict[str, Any]:
"""Provide sample cache data for testing."""
return {
"a:1234.5678": {
"0KEY_": "a:1234.5678",
"GetRecord": {
"record": {
"header": {
"identifier": "oai:arXiv.org:1234.5678"
},
"metadata": {
"arXiv": {
"title": "Sample Paper Title",
"authors": {
"author": [
{"keyname": "Doe", "forenames": "John"},
{"keyname": "Smith", "forenames": "Jane"}
]
},
"created": "2023-01-01"
}
}
}
}
}
}


@pytest.fixture
def sample_cache_file(temp_dir: Path, sample_cache_data: Dict[str, Any]) -> Path:
"""Create a sample cache file for testing."""
cache_file = temp_dir / "test_cache.jsonl"
with open(cache_file, 'w') as f:
for key, value in sample_cache_data.items():
f.write(json.dumps(value) + '\n')
return cache_file


@pytest.fixture
def sample_readme_template(temp_dir: Path) -> Path:
"""Create a sample README template for testing."""
template_file = temp_dir / "test_template.org"
content = """* Machine Learning Interpretability Papers

** Papers
+ {"arxiv_id": "1234.5678"}
+ {"doi": "10.1234/sample"}
+ {"sems_id": "sample-semantic-id"}

** Other Content
This is some other content.
"""
template_file.write_text(content)
return template_file


@pytest.fixture
def mock_http_response(mocker):
"""Mock HTTP responses for external API calls."""
def _mock_response(url: str, data: Any, status_code: int = 200):
mock_response = mocker.Mock()
mock_response.read.return_value = json.dumps(data).encode('utf-8') if isinstance(data, dict) else data
mock_response.status = status_code
return mock_response
return _mock_response


@pytest.fixture
def mock_env_vars(monkeypatch):
"""Fixture to easily set environment variables for testing."""
def _set_env(**kwargs):
for key, value in kwargs.items():
monkeypatch.setenv(key, str(value))
return _set_env


@pytest.fixture
def isolated_filesystem(temp_dir: Path, monkeypatch) -> Path:
"""Create an isolated filesystem for testing with proper working directory."""
monkeypatch.chdir(temp_dir)
return temp_dir
Empty file added tests/integration/__init__.py
Empty file.
67 changes: 67 additions & 0 deletions tests/test_setup_validation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
"""Validation tests to ensure the testing infrastructure is set up correctly."""

import sys
from pathlib import Path

import pytest


class TestSetupValidation:
"""Test suite to validate the testing infrastructure setup."""

def test_pytest_installed(self):
"""Verify pytest is installed and importable."""
import pytest
assert pytest.__version__

def test_pytest_cov_installed(self):
"""Verify pytest-cov is installed and importable."""
import pytest_cov
assert pytest_cov

def test_pytest_mock_installed(self):
"""Verify pytest-mock is installed and importable."""
import pytest_mock
assert pytest_mock

def test_project_structure(self):
"""Verify the project structure is set up correctly."""
workspace = Path(__file__).parent.parent

# Check main directories exist
assert workspace.exists()
assert (workspace / "tests").exists()
assert (workspace / "tests" / "unit").exists()
assert (workspace / "tests" / "integration").exists()
assert (workspace / "sbin").exists()

# Check important files exist
assert (workspace / "pyproject.toml").exists()
assert (workspace / "tests" / "__init__.py").exists()
assert (workspace / "tests" / "conftest.py").exists()

def test_conftest_fixtures(self, temp_dir, sample_cache_data):
"""Verify conftest fixtures are working."""
assert temp_dir.exists()
assert isinstance(sample_cache_data, dict)
assert "a:1234.5678" in sample_cache_data

@pytest.mark.unit
def test_unit_marker(self):
"""Test that the unit marker is registered."""
pass

@pytest.mark.integration
def test_integration_marker(self):
"""Test that the integration marker is registered."""
pass

@pytest.mark.slow
def test_slow_marker(self):
"""Test that the slow marker is registered."""
pass

def test_python_path(self):
"""Verify the Python path includes the project root."""
workspace = Path(__file__).parent.parent
assert str(workspace) in sys.path or str(workspace.absolute()) in sys.path
Empty file added tests/unit/__init__.py
Empty file.