Development Guide

Essential information for developing DeepRetro.

Setup

git clone <repository-url>
cd DeepRetro
conda env create -f environment.yml
conda activate deepretro
pip install -r tests/requirements_tests.txt

Project Structure

DeepRetro/
├── src/                    # Main source code
│   ├── api.py             # Flask API server (main entry point)
│   ├── main.py            # Core retrosynthesis function
│   ├── cache.py           # Caching functionality
│   ├── prithvi.py         # Core retrosynthesis logic
│   ├── rec_prithvi.py     # Recursive retrosynthesis
│   ├── metadata.py        # Metadata extraction
│   └── utils/             # Utility modules
├── viewer/                # Web interface
├── tests/                 # Test suite
└── docs/                  # Documentation

Development Workflow

  1. Create feature branch:

    git checkout -b feature/your-feature-name
    
  2. Make changes following code standards

  3. Run tests:

    python -m pytest tests/
    
  4. Submit pull request

Code Standards

  • Follow PEP 8

  • Use type hints

  • Add docstrings (Google style)

  • Keep functions focused

Example:

def process_molecule(smiles: str, model: str) -> Dict[str, Any]:
    """Process molecule with specified model.

    Args:
        smiles: SMILES string
        model: Model identifier

    Returns:
        Processing results
    """
    return result

Testing

Unit Tests:

def test_parse_response():
    response = "test response"
    result = parse_response(response)
    assert result is not None

Integration Tests:

def test_retrosynthesis_api():
    response = client.post(
        '/api/retrosynthesis',
        headers={'X-API-KEY': 'test-key'},
        json={'smiles': 'CC'}
    )
    assert response.status_code == 200

Mock External Services:

@patch('src.utils.llm.call_LLM')
def test_llm_integration(mock_llm):
    mock_llm.return_value = '{"result": "test"}'
    result = process_with_llm("test")
    assert result is not None

Adding Features

New LLM Model:

  1. Add to variables.py:

    NEW_MODELS = ["new-model-name"]
    
  2. Update api.py model selection

  3. Add provider logic in llm.py

New Validation:

  1. Create validation function

  2. Add to main function with flag

  3. Update API endpoint parameters

New AiZynthFinder Model:

  1. Add to AZ_MODEL_LIST in variables.py

  2. Update model validation in api.py

Error Handling

Use structured error handling:

try:
    result = process_data(input_data)
except ValueError as e:
    return jsonify({"error": str(e)}), 400
except Exception as e:
    logger.error(f"Unexpected error: {e}")
    return jsonify({"error": "Internal server error"}), 500

Logging

Use structured logging:

import structlog

log = structlog.get_logger()
log.info("Processing molecule", smiles=smiles, model=model)

Documentation

  • Update docstrings for new functions

  • Update user guide for new features

  • Update API documentation if needed

  • Keep README current

For contribution guidelines, see Contributing Guide.