Developer Guide
Contribution
If you would like to contribute, whether by adding new features, improving the codebase, bug fixing, or providing feedback, your input is greatly appreciated. Please feel free to open issues, submit pull requests, or suggest improvements. If you would like to become a collaborator, please drop me an email at ahmedhassan@aims.ac.za.
AI Agents
You are welcome to use AI code agent to contribute to the project. However, note the following:
Warning
If you use AI agents (Claude, Codex, Opencode, Cursor, etc), please do not commit and push your agent config and artifacts to Github repo (e.g .agent, .opencode, CLAUDE.md, AGENTS.md, skills, MCP, etc). This repo does not assume any specific AI agent and publishing these will pollute it!
Tip
The current .gitignore ignore default agent-specific config and artifacts. If your agent files or directories are tracked by git, please add them to .gitignore.
Running Tests
-
Clone Github repo
-
Activate the virtual environment
source .env/bin/activate
- Install the development optional dependencies in the editable mode
pip install -e ".[test,docs,postgres]"
Repalce postgres with your database dialect (see Supported Database)
- Run the tests
pytest tests/
- Run the test with the coverage
pytest --cov=sql2excel
Databases
SQL2Excel is database-agnostic by design. It connects to any database supported by SQLAlchemy via a standard connection URL. It is currently tested against PostgreSQL and MySQL. If you use another database and encounter issues, please open an issue on GitHub.
Using Docker for Trial and Testing
Docker lets you spin up temporary database instances without installing them on your host machine. SQL2Excel is developed in machine hosting PostgreSQL (Docker is not used). However for MySQL, Docker was used and the instructions to set it up is below. We will use the DvD rental (also known as Sakila) database to test SQL2Excel for MySQL.
PostgreSQL
Docker postgres guide is coming up ...
MySQL
1. Download and Extract the Sakila Database
First, download the database schema and data files directly from MySQL and extract them to your local machine. Run the following command (assuming Linux):
wget https://downloads.mysql.com/docs/sakila-db.tar.gz
tar -xvf sakila-db.tar.gz
This creates a folder named sakila-db.
2. Start the MySQL Docker Container
Pull and start the official MySQL image. We will use version 8.0.
docker run --name mysql-sakila \
-e MYSQL_ROOT_PASSWORD=secretpassword \
-p 3306:3306 \
-d \
mysql:8.0
-
--name mysql-sakila: Gives the container an easy-to-remember name. -
-e MYSQL_ROOT_PASSWORD=...: Sets the administrative password. -
-p 3306:3306: Maps the default MySQL port from inside the container to your local machine, allowingSQL2Excelto connect to MySQL atlocalhost:3306. -
-d: Runs the container in the background (detached mode).
3. Copy the Database Files into the Container
To import the SQL files to MySQL, they need to be accessible from inside the running Docker container. You can copy the extracted folder directly into the container's root directory (or any other directory you prefer).
docker cp sakila-db mysql-sakila:/sakila-db
4. Open the MySQL CLI
Now, open an interactive terminal session inside the container and launch the MySQL command-line client to query the database.
docker exec -it mysql-sakila mysql -u root -p
When prompted for the password, enter your password you chose in Step 2 above. You should see mysql> in the terminal.
5. Import the Schema and Data to MySQL
From within the mysql> CLI, you can execute the SQL files you copied over. You must run the schema file first to create the tables, followed by the data file to populate them:
SOURCE /sakila-db/sakila-schema.sql;
SOURCE /sakila-db/sakila-data.sql;
6. Your MySQL DB URL
Your db_url that you will use to connect SQL2Excel to MySQL would be
"mysql+pymysql://root:<your-password>@localhost:3306/sakila"
Replace <password> with your password from Step 2.
That's it!
Project Architecture
Understanding the project structure is essential before contributing.
Core Modules
| Module | Description |
|---|---|
sql2excel/report.py |
Top-level orchestrator that executes queries and writes Excel |
sql2excel/sqlexec.py |
SQL execution engine and query configuration |
sql2excel/parser.py |
SQL file parser for annotated queries |
sql2excel/chart.py |
All chart implementations (Line, Bar, Pie, etc.) |
sql2excel/config.py |
Default configuration constants |
sql2excel/excel_helper.py |
openpyxl utility layer |
Chart Class Hierarchy
All chart types inherit from the Chart base class:
Chart
├── LineBasedChart (abstract)
│ ├── LineChart
│ └── RadarChart
├── TwoAxesChart (abstract)
│ ├── BarLineChart
├── BarChart
├── PieChart
├── AreaChart
├── ScatterChart
├── BubbleChart
├── StackedBarChart
├── SingleAxisBarLineChart
└── ImageChart
Code Style
Python Conventions
- Follow PEP 8 for code formatting
- Use type hints for all function signatures
- Write docstrings for public classes and methods
- Keep functions focused
Naming Conventions
- Classes: PascalCase (
BarChart,QueryConfig) - Functions: snake_case (
parse_sql_file,generate_report) - Constants: UPPER_SNAKE_CASE (
DEFAULT_FONT_SIZE) - Private methods: Leading underscore (
_apply_style)
Adding a New Chart Type
To add a new chart type to SQL2Excel:
Step 1: Create the Chart Class
In sql2excel/chart.py, add a new class inheriting from Chart:
class YourNewChart(Chart):
"""Description of your chart type."""
def __init__(self, config=None, excel_helper=None):
super().__init__(config, excel_helper)
def plot(self, df, worksheet, param1='x', param2='y'):
"""Specific description here
Parameters
----------
df : pd.DataFrame
Data to plot.
worksheet : openpyxl.worksheet.worksheet.Worksheet
Target worksheet.
param1 : int
First keyword argument.
param2 : int
Second keyword argument
"""
# Implementation here
# Call the super method to finalize the plot
# Note this is the private `_plot` (not the public `plot`)
super()._plot(df, ws, **kwargs)
Step 2: Register the Chart
Add the new class to sql2excel/__init__.py:
from sql2excel.chart import YourNewChart
__all__ = [
# ... existing exports
"YourNewChart",
]
Step 3: Add to Report
In sql2excel/report.py, update the chart type mapping:
CHART_TYPES = {
# ... existing types
"your_new": YourNewChart,
}
Step 4: Write Tests
Create tests in tests/test_chart.py:
def test_your_new_chart(worksheet, sample_df):
"""Test YourNewChart plotting."""
# Your assertions here
Testing Guidelines
- Use pytest
- Place tests in
tests/directory - Name test files
test_<module>.py - Use pytest fixtures defined in
tests/setup.py
Documentation
Docstring Format
Use NumPy-style docstrings:
def your_function(param1, param2):
"""Short summary.
Longer description if needed.
Parameters
----------
param1 : str
Description of param1.
param2 : int
Description of param2.
Returns
-------
bool
Description of return value.
Raises
------
ValueError
If param2 is negative.
"""
Building Documentation
# Install docs dependencies
pip install -e ".[docs]"
# Build static site
mkdocs build
# Serve documentation locally
mkdocs serve
Pull Request Process
Before Submitting
- Write tests for your code. Please do not push code that is not test
- Run the full test suite:
pytest tests/ - Ensure all tests pass
- Update documentation if adding new features
Issue Labels
bug: Something isn't working as expectedenhancement: New feature or requestdocumentation: Improvements to docs
Getting Help
- Open an issue on GitHub for bugs or feature requests
- Email: ahmedhassan@aims.ac.za
- Review existing documentation before asking questions