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
Create feature branch:
git checkout -b feature/your-feature-name
Make changes following code standards
Run tests:
python -m pytest tests/
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:
Add to variables.py:
NEW_MODELS = ["new-model-name"]
Update api.py model selection
Add provider logic in llm.py
New Validation:
Create validation function
Add to main function with flag
Update API endpoint parameters
New AiZynthFinder Model:
Add to AZ_MODEL_LIST in variables.py
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.