Development
This page provides information for developers who want to contribute to AtPack Parser.
Development Setup
Prerequisites
- Python 3.9 or higher
- Git
- A text editor or IDE
Clone and Setup
# Clone the repository
git clone https://github.com/s-celles/atpack-python-parser.git
cd atpack-python-parser
# Create virtual environment
python -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activate
# Install in development mode
pip install -e ".[dev]"
Development Dependencies
The development setup includes:
- pytest - Testing framework
- pytest-cov - Coverage reporting
- black - Code formatting
- ruff - Fast linting
- mypy - Type checking
Project Structure
atpack-python-parser/
├── src/
│ └── atpack_parser/
│ ├── __init__.py # Package initialization
│ ├── parser.py # Main parser class
│ ├── atdf_parser.py # ATMEL format parser
│ ├── pic_parser.py # Microchip PIC parser
│ ├── pdsc_parser.py # Pack description parser
│ ├── models.py # Data models
│ ├── exceptions.py # Custom exceptions
│ ├── xml_utils.py # XML utilities
│ └── cli.py # Command line interface
├── tests/
│ ├── __init__.py
│ ├── conftest.py # Test configuration
│ ├── test_parser.py # Parser tests
│ ├── test_enhanced_atmel.py # ATMEL parser tests
│ └── test_enhanced_pic.py # PIC parser tests
├── docs/ # Documentation
├── examples/ # Usage examples
├── atpacks/ # Test AtPack files
├── pyproject.toml # Project configuration
└── README.md # Project README
Running Tests
Run All Tests
Run with Coverage
Run Specific Tests
# Test specific file
pytest tests/test_parser.py
# Test specific function
pytest tests/test_parser.py::test_parse_device_info
# Test with verbose output
pytest -v
Code Quality
Formatting
Format code with Black:
Linting
Lint code with Ruff:
Type Checking
Check types with MyPy:
Pre-commit Hooks
Install pre-commit hooks to run checks automatically:
Documentation
Building Documentation
The documentation is built with MkDocs:
# Install MkDocs and dependencies
pip install mkdocs mkdocs-material mkdocstrings[python]
# Serve documentation locally
mkdocs serve
# Build documentation
mkdocs build
Writing Documentation
- Documentation files are in
docs/
- Use Markdown format
- Include code examples
- Document all public APIs
- Keep examples up to date
Contributing Guidelines
Code Style
- Follow PEP 8 style guidelines
- Use Black for formatting
- Write clear, descriptive docstrings
- Add type hints to all functions
- Keep functions focused and small
Adding New Features
- Create an issue describing the feature
- Fork the repository and create a feature branch
- Write tests for your feature first (TDD)
- Implement the feature
- Update documentation
- Submit a pull request
Example: Adding a New Parser
# src/atpack_parser/new_format_parser.py
from typing import List, Dict, Any
from .models import Device
from .exceptions import AtPackParseError
class NewFormatParser:
"""Parser for new AtPack format."""
def __init__(self, file_content: bytes):
self.content = file_content
def parse_devices(self) -> List[Device]:
"""Parse devices from the new format."""
try:
# Implementation here
pass
except Exception as e:
raise AtPackParseError(f"Failed to parse new format: {e}")
Testing New Features
# tests/test_new_format_parser.py
import pytest
from atpack_parser.new_format_parser import NewFormatParser
from atpack_parser.exceptions import AtPackParseError
def test_parse_devices():
"""Test parsing devices from new format."""
# Test data
test_content = b"..."
# Test
parser = NewFormatParser(test_content)
devices = parser.parse_devices()
# Assertions
assert len(devices) > 0
assert devices[0].name == "ExpectedDevice"
def test_parse_invalid_content():
"""Test error handling for invalid content."""
with pytest.raises(AtPackParseError):
parser = NewFormatParser(b"invalid")
parser.parse_devices()
Debugging
Debug Mode
Enable debug mode for verbose output:
import logging
logging.basicConfig(level=logging.DEBUG)
from atpack_parser import AtPackParser
parser = AtPackParser("test.atpack")
Common Issues
XML Parsing Errors
# Check XML structure
from lxml import etree
try:
tree = etree.parse("test.atpack")
except etree.XMLSyntaxError as e:
print(f"XML parsing error: {e}")
Memory Issues with Large Files
# Use streaming for large files
def parse_large_atpack(file_path):
with open(file_path, 'rb') as f:
# Process in chunks
chunk_size = 1024 * 1024 # 1MB chunks
while True:
chunk = f.read(chunk_size)
if not chunk:
break
# Process chunk
Release Process
Version Bumping
- Update version in
pyproject.toml
- Update
CHANGELOG.md
- Create git tag:
git tag v0.2.0
- Push tag:
git push origin v0.2.0
Publishing to PyPI
Performance Optimization
Profiling
import cProfile
import pstats
def profile_parser():
pr = cProfile.Profile()
pr.enable()
# Your code here
from atpack_parser import AtPackParser
parser = AtPackParser("large.atpack")
devices = parser.get_devices()
pr.disable()
stats = pstats.Stats(pr)
stats.sort_stats('cumulative')
stats.print_stats(10)
profile_parser()
Memory Profiling
# Install memory profiler
pip install memory-profiler
# Run with memory profiling
python -m memory_profiler example_script.py
Architecture Notes
Parser Design
The parser uses a modular design:
- AtPackParser - Main interface, delegates to format-specific parsers
- ATDFParser - Handles ATMEL Device Files
- PICParser - Handles Microchip PIC format
- Models - Pydantic models for data validation
- XML Utils - Common XML processing functions
Data Flow
Extension Points
To add support for new formats:
- Create a new parser class
- Implement required methods
- Register in main parser
- Add tests and documentation
Troubleshooting Development
Import Errors
# Ensure package is installed in development mode
pip install -e .
# Check Python path
python -c "import sys; print(sys.path)"
Test Failures
# Run tests with verbose output
pytest -vv
# Debug specific test
pytest --pdb tests/test_parser.py::test_specific_function
Documentation Issues
Getting Help
- Create an issue on GitHub
- Join discussions in the repository
- Check existing issues and pull requests
- Review the documentation
Error Handling Architecture
The AtPack Parser implements a DRY (Don't Repeat Yourself) error handling system with intelligent device name suggestions.
Core Components
Central Error Handlers (src/atpack_parser/cli/common.py
)
def handle_device_not_found_error(e: DeviceNotFoundError, parser=None, no_color: bool = False):
"""Centralized handling of device not found errors with fuzzy suggestions."""
def handle_atpack_error(e: AtPackError, no_color: bool = False):
"""Centralized handling of general AtPack errors."""
Fuzzy Matching Engine
The suggestion system uses rapidfuzz (MIT licensed) with multiple algorithms:
- Exact matching: Case-insensitive perfect matches get priority 0
- Ratio scoring: Character-by-character similarity
- Partial ratio: Handles substring matches
- Token sort: Handles reordered tokens
- Token set: Handles partial token matches
- Weighted combination: Optimized scoring for device names
Implementation Details
Multi-Algorithm Scoring
def _get_device_suggestions(target_device: str, parser, max_suggestions: int = 5):
# 1. Exact case-insensitive match gets highest priority
if target_upper == device_upper:
final_score = 0 # Perfect match
else:
# 2. Multiple fuzzy algorithms
ratio_score = fuzz.ratio(target_upper, device_upper)
partial_ratio_score = fuzz.partial_ratio(target_upper, device_upper)
token_sort_ratio_score = fuzz.token_sort_ratio(target_upper, device_upper)
token_set_ratio_score = fuzz.token_set_ratio(target_upper, device_upper)
# 3. Weighted combination (optimized for device names)
combined_score = (
ratio_score * 0.4 + # Character similarity
partial_ratio_score * 0.3 + # Substring matches
token_sort_ratio_score * 0.2 + # Reordered tokens
token_set_ratio_score * 0.1 # Partial tokens
)
DRY Pattern Usage
All CLI commands use the centralized error handlers:
# Before (repetitive code in each command)
try:
device = parser.get_device(device_name)
except DeviceNotFoundError as e:
console.print(f"[red]Device not found: {e}[/red]")
raise typer.Exit(1)
# After (DRY pattern)
try:
device = parser.get_device(device_name)
except DeviceNotFoundError as e:
handle_device_not_found_error(e, parser, no_color)
Performance Characteristics
- Scalability: Optimized for 1000+ device lists
- Memory efficiency: Processes device lists on-demand
- Speed: Sub-second suggestion generation for typical AtPack files
- Fallback safety: Graceful handling when suggestions can't be generated
Testing the Error Handling
Unit Testing
def test_fuzzy_device_suggestions():
"""Test that device suggestions are properly ranked."""
suggestions = _get_device_suggestions("PIC16f877", parser)
assert suggestions[0] == "PIC16F877" # Exact match first
assert "PIC16F877A" in suggestions # Similar devices included
Integration Testing
# Test actual CLI behavior
atpack memory show PIC16f877 test.atpack # Should suggest PIC16F877
atpack devices info atmega16 test.atpack # Should suggest ATmega16
Extending the Error Handling
Adding New Error Types
-
Define the error handler in
common.py
: -
Use it consistently across CLI commands:
Customizing Suggestion Algorithms
The fuzzy matching weights can be tuned for specific use cases:
# Device name focused (current)
combined_score = (
ratio_score * 0.4 + # High weight on character similarity
partial_ratio_score * 0.3 +
token_sort_ratio_score * 0.2 +
token_set_ratio_score * 0.1
)
# Register name focused (hypothetical)
combined_score = (
ratio_score * 0.3 +
partial_ratio_score * 0.4 + # Higher weight on substrings
token_sort_ratio_score * 0.2 +
token_set_ratio_score * 0.1
)
Dependencies
- rapidfuzz>=3.0.0: MIT licensed fuzzy string matching
- rich: Terminal formatting and colors
- typer: CLI framework integration
The system has no GPL dependencies and uses only MIT-compatible libraries.
Contributing Checklist
Before submitting a pull request:
- [ ] Tests pass:
pytest
- [ ] Code is formatted:
black src/ tests/
- [ ] Linting passes:
ruff check src/ tests/
- [ ] Type checking passes:
mypy src/
- [ ] Documentation is updated
- [ ] CHANGELOG.md is updated
- [ ] Tests are added for new features
- [ ] All public functions have docstrings