Files
nadlan-mcp/CONTRIBUTING.md
T
Nitzan Pomerantz 02e69b6d3b Ran ruff format etc.
2025-10-31 19:02:33 +02:00

475 lines
9.4 KiB
Markdown

# Contributing to Nadlan-MCP
Thank you for your interest in contributing! This guide will help you get started.
## Code of Conduct
- Be respectful and inclusive
- Focus on constructive feedback
- Help others learn and grow
## Development Setup
### 1. Fork and Clone
```bash
git clone https://github.com/your-username/nadlan-mcp.git
cd nadlan-mcp
```
### 2. Create Virtual Environment
```bash
python -m venv venv
source venv/bin/activate # Windows: venv\Scripts\activate
```
### 3. Install Dependencies
```bash
# Install main dependencies
pip install -r requirements.txt
# Install development dependencies
pip install -r requirements-dev.txt
```
### 4. Set Up IDE Integration (Recommended)
**For VSCode/Cursor users:**
The project includes `.vscode/settings.json` which automatically:
- Formats code on save with Ruff
- Shows lint errors inline
- Organizes imports automatically
- Runs tests with pytest
**Install recommended extensions:**
1. Open VSCode/Cursor in the project directory
2. You'll be prompted to install recommended extensions
3. Install "Ruff" extension by charliermarsh
**Benefits:**
- ✅ Automatic formatting on save
- ✅ Real-time lint errors
- ✅ Auto-fix on save
- ✅ No manual commands needed
### 5. Verify Setup
```bash
# Run tests
pytest tests/ -m "not api_health" -q
# Check code quality
ruff check .
ruff format --check .
# Or use the quick check script
./check-quality.sh
```
## Development Workflow
### 1. Create a Branch
```bash
git checkout -b feature/your-feature-name
# or
git checkout -b fix/issue-description
```
### 2. Make Changes
Follow the code style guidelines below.
**If using VSCode/Cursor with Ruff extension:**
- Code is automatically formatted on save
- Lint errors are shown inline
- Auto-fixes apply on save
- No manual commands needed!
**If not using IDE integration:**
- Run `./check-quality.sh` before committing
- Or run individual commands below
### 3. Check Before Committing
**Quick check (recommended):**
```bash
./check-quality.sh
```
This script runs all checks that will run in the PR:
1. Ruff format check
2. Ruff linting
3. All tests
**Manual checks:**
```bash
# Format code
ruff format .
# Lint code
ruff check . --fix
# Run tests
pytest tests/ -m "not api_health" -q
# Check remaining issues
ruff check .
```
### 4. Commit Changes
```bash
git add .
git commit -m "feat: add new feature"
# or
git commit -m "fix: resolve issue with..."
```
**Commit Message Format:**
- `feat:` - New feature
- `fix:` - Bug fix
- `docs:` - Documentation changes
- `test:` - Test additions/changes
- `refactor:` - Code refactoring
- `style:` - Code style changes
- `chore:` - Build/tooling changes
### 6. Push and Create PR
```bash
git push origin feature/your-feature-name
```
Then create a Pull Request on GitHub.
## Code Style
### Python Style Guide
We use **Ruff** for formatting and linting (replaces black, isort, flake8):
- Line length: 100 characters
- Use double quotes for strings
- Follow PEP 8 conventions
### Formatting
```bash
# Auto-format all code
ruff format .
```
### Linting
```bash
# Check for issues
ruff check .
# Auto-fix issues
ruff check . --fix
```
### Type Hints
Use type hints for function signatures:
```python
from typing import List, Optional
from nadlan_mcp.govmap.models import Deal
def process_deals(
deals: List[Deal],
min_price: Optional[float] = None
) -> List[Deal]:
"""Process and filter deals."""
...
```
## Testing Guidelines
### Test Structure
```
tests/
├── govmap/ # Unit tests for govmap package
├── e2e/ # End-to-end integration tests
└── api_health/ # API health monitoring (weekly)
```
### Writing Tests
```python
import pytest
from nadlan_mcp.govmap.models import Deal
class TestYourFeature:
"""Test cases for your feature."""
@pytest.fixture
def sample_deals(self):
"""Create sample test data."""
return [
Deal(objectid=1, deal_amount=1000000, deal_date="2024-01-01"),
Deal(objectid=2, deal_amount=1500000, deal_date="2024-02-01"),
]
def test_basic_functionality(self, sample_deals):
"""Test basic functionality."""
result = your_function(sample_deals)
assert len(result) == 2
```
### Test Coverage
Aim for **>80% coverage** for new code:
```bash
pytest --cov=nadlan_mcp --cov-report=html
open htmlcov/index.html
```
### Running Different Test Suites
```bash
# Fast tests only (default, ~12s)
pytest tests/ -m "not api_health" -q
# Integration tests (makes real API calls)
pytest -m integration -v
# API health checks (weekly)
pytest -m api_health -v
# Specific test file
pytest tests/govmap/test_filters.py
```
## Architecture Guidelines
### Package Structure
```
nadlan_mcp/
├── govmap/ # Core business logic
│ ├── models.py # Pydantic data models
│ ├── client.py # API client
│ ├── filters.py # Deal filtering
│ ├── statistics.py # Statistical calculations
│ ├── market_analysis.py # Market analysis
│ ├── validators.py # Input validation
│ └── utils.py # Helper functions
├── fastmcp_server.py # MCP tool definitions
└── config.py # Configuration management
```
### Design Principles
1. **MCP provides data, LLM provides intelligence**
- Keep analysis simple in MCP layer
- Let LLM interpret and reason about data
2. **Return Pydantic models, not dicts**
- All API methods return typed models
- Use `.model_dump()` to serialize for JSON
3. **Separation of concerns**
- `client.py` - API calls only
- `filters.py` - Filtering logic
- `statistics.py` - Calculations
- `market_analysis.py` - Analysis functions
4. **Backward compatibility**
- Use `govmap/__init__.py` for public exports
- Maintain existing function signatures
### Adding New Features
#### 1. Add Pydantic Model (if needed)
```python
# nadlan_mcp/govmap/models.py
class YourModel(BaseModel):
"""Your model description."""
field_name: str = Field(..., description="Field description")
optional_field: Optional[int] = Field(None, description="Optional field")
```
#### 2. Add Business Logic
```python
# nadlan_mcp/govmap/your_module.py
from typing import List
from .models import Deal, YourModel
def your_function(deals: List[Deal]) -> YourModel:
"""
Your function description.
Args:
deals: List of Deal instances
Returns:
YourModel instance
Raises:
ValueError: If deals list is empty
"""
if not deals:
raise ValueError("Cannot process empty deals list")
# Your logic here
return YourModel(field_name="value")
```
#### 3. Add Client Method
```python
# nadlan_mcp/govmap/client.py
def your_method(self, param: str) -> YourModel:
"""
Client method description.
Args:
param: Parameter description
Returns:
YourModel instance
"""
# Implementation
return your_function(data)
```
#### 4. Add MCP Tool
```python
# nadlan_mcp/fastmcp_server.py
@mcp.tool()
def your_mcp_tool(param: str) -> str:
"""
MCP tool description visible to LLM.
Args:
param: Parameter description
Returns:
JSON string with results
"""
try:
result = client.your_method(param)
return json.dumps({
"result": result.model_dump(exclude_none=True)
}, ensure_ascii=False, indent=2)
except Exception as e:
logger.error(f"Error in your_mcp_tool: {e}")
return f"Error: {str(e)}"
```
#### 5. Add Tests
```python
# tests/govmap/test_your_module.py
def test_your_function():
"""Test your function."""
deals = [Deal(...)]
result = your_function(deals)
assert isinstance(result, YourModel)
assert result.field_name == "expected_value"
```
#### 6. Update Documentation
- Add to `API_REFERENCE.md`
- Add example to `examples/` if useful
- Update `README.md` if it's a major feature
## Pull Request Process
### Before Submitting
1. ✅ All tests pass
2. ✅ Code formatted with Ruff
3. ✅ No Ruff warnings
4. ✅ Added tests for new features
5. ✅ Updated documentation
### PR Checklist
```markdown
## Description
Brief description of changes
## Type of Change
- [ ] Bug fix
- [ ] New feature
- [ ] Breaking change
- [ ] Documentation update
## Testing
- [ ] Added new tests
- [ ] All existing tests pass
- [ ] Tested manually
## Documentation
- [ ] Updated README.md (if needed)
- [ ] Updated API_REFERENCE.md (if needed)
- [ ] Added examples (if needed)
```
### Code Review
- PRs reviewed by maintainers
- Address feedback constructively
- CI checks must pass (Ruff + tests)
## Common Tasks
### Adding a New MCP Tool
See "Adding New Features" section above.
### Fixing a Bug
1. Write a failing test that reproduces the bug
2. Fix the bug
3. Verify test now passes
4. Add regression test if needed
### Updating Dependencies
```bash
# Update requirements files
pip list --outdated
pip install <package> --upgrade
pip freeze > requirements.txt
# Test everything still works
pytest tests/ -m "not api_health"
```
### Running API Health Checks
```bash
# Weekly check that Govmap API still works
pytest -m api_health -v
```
## Questions?
- Create an issue for questions
- Check existing issues and PRs
- Read ARCHITECTURE.md for design decisions
- Review examples/ for usage patterns
## License
By contributing, you agree that your contributions will be licensed under the MIT License.
---
**Thank you for contributing to Nadlan-MCP!** 🎉