Building the Project¶
This guide covers how to build, test, and package the Siglent Oscilloscope Control library for development and distribution.
Overview¶
The project uses a modern Python build system based on:
- Build Backend:
setuptoolswith PEP 517/518 support - Build Tool:
python -m build - Configuration:
pyproject.toml(PEP 621 metadata) - Task Runner:
Makefilefor common development tasks - Package Manager:
pipfor dependency management - Distribution: PyPI (Python Package Index)
Prerequisites¶
System Requirements¶
Python Version:
- Python 3.8 or later
- Supports: 3.8, 3.9, 3.10, 3.11, 3.12
Operating Systems:
- Linux (tested on Ubuntu 20.04+)
- macOS (tested on 10.15+)
- Windows (tested on Windows 10/11)
Development Tools:
- Git (for version control)
- Make (GNU Make or compatible)
- pip (comes with Python)
Installing Prerequisites¶
Linux (Debian/Ubuntu):
macOS:
# Install Homebrew if not already installed
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
# Install prerequisites
brew install python git make
Windows:
- Install Python from python.org
- Install Git for Windows
- Make is included with Git Bash or install via Chocolatey:
choco install make
Quick Start¶
Clone Repository¶
git clone https://github.com/little-did-I-know/SCPI-Instrument-Control.git
cd SCPI-Instrument-Control
Development Setup¶
Complete environment setup (recommended):
This command:
- Installs package in editable mode
- Installs all dependencies (core + optional + dev)
- Sets up pre-commit hooks
- Configures development environment
Manual setup:
# Create virtual environment (recommended)
python -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activate
# Install in editable mode with all dependencies
pip install -e ".[all,dev]"
Verify Installation¶
Installation Options¶
The package has several installation profiles for different use cases:
Core Package (Basic)¶
Minimal installation:
Dependencies:
numpy>=1.24.0matplotlib>=3.7.0scipy>=1.10.0
Use Case: Basic oscilloscope control, waveform capture, measurements
Development Installation¶
With development tools:
Additional Dependencies:
pytest>=7.0- Testing frameworkblack>=23.0- Code formatterflake8>=6.0- Linterbuild>=0.10.0- Build tooltwine>=4.0.0- Package upload tool
Use Case: Contributing to the project, running tests
GUI Installation¶
With PyQt6 GUI:
Additional Dependencies:
PyQt6>=6.6.0- Qt6 GUI frameworkPyQt6-WebEngine>=6.6.0- Web rendering (for VNC)pyqtgraph>=0.13.0- High-performance plotting
Use Case: Using the graphical interface
HDF5 Support¶
With HDF5 file format support:
Additional Dependencies:
h5py>=3.8.0- HDF5 file format
Use Case: Saving large datasets in HDF5 format
Vector Graphics (Fun!)¶
With vector graphics features:
Additional Dependencies:
shapely>=2.0.0- Geometric operationsPillow>=10.0.0- Image processingsvgpathtools>=1.6.0- SVG path manipulation
Use Case: Creating XY mode shapes, waveform art
Documentation Tools¶
With documentation generation:
Additional Dependencies:
mkdocs>=1.5.0- Documentation generatormkdocs-material>=9.5.0- Material thememkdocstrings[python]>=0.24.0- API documentation from docstringsmkdocs-gen-files>=0.5.0- Dynamic file generationmkdocs-literate-nav>=0.6.0- Navigation from filesmkdocs-section-index>=0.3.0- Section indexes
Use Case: Building and serving documentation
Complete Installation¶
All optional dependencies:
Use Case: Full development environment with all features
Building the Package¶
Build Distribution Packages¶
Using Make:
Manual build:
# Install build tool
pip install build twine
# Build source and wheel distributions
python -m build
# Verify packages
twine check dist/*
Output:
dist/
Siglent_Oscilloscope-0.3.0.tar.gz # Source distribution
Siglent_Oscilloscope-0.3.0-py3-none-any.whl # Wheel distribution
Clean Build Artifacts¶
Remove all build artifacts:
This removes:
build/- Build directorydist/- Distribution packages*.egg-info- Package metadata.pytest_cache- Test cache.coverage,htmlcov/- Coverage reports__pycache__directories*.pycfiles
Build Process Details¶
What happens during build:
- Parse Configuration
- Read
pyproject.toml - Extract package metadata
-
Identify dependencies
-
Find Packages
- Scan for
siglent*packages -
Include package data (
py.typed) -
Build Source Distribution (sdist)
- Create
.tar.gzarchive - Include source files
-
Add metadata
-
Build Wheel (bdist_wheel)
- Create
.whlfile - Compiled bytecode
-
Platform-independent (
py3-none-any) -
Validation
- Check metadata completeness
- Verify README rendering
- Validate package structure
Testing¶
Run Tests¶
All tests:
With coverage report:
Opens htmlcov/index.html with detailed coverage report.
Fast parallel testing:
Uses pytest-xdist for parallel test execution.
Specific tests:
# Test specific file
pytest tests/test_oscilloscope.py -v
# Test specific function
pytest tests/test_oscilloscope.py::test_connection -v
# Test with markers
pytest tests/ -m "not hardware" -v # Skip hardware tests
pytest tests/ -m gui -v # Only GUI tests
Test Markers¶
Available markers:
hardware- Requires actual oscilloscope hardwaregui- Requires GUI dependencies (PyQt6)
Usage:
import pytest
@pytest.mark.hardware
def test_real_scope():
"""Test that requires connected oscilloscope."""
pass
@pytest.mark.gui
def test_gui_window():
"""Test that requires PyQt6."""
pass
Skip hardware tests:
Coverage Requirements¶
Current coverage targets:
- Overall: >80%
- Core modules: >90%
- GUI modules: >70% (harder to test)
View coverage:
Watch Mode¶
Auto-run tests on file changes:
Requires pytest-watch:
Code Quality¶
Linting¶
Run all linting checks:
Checks performed:
- Black: Code formatting (line length: 200)
- Flake8: Style guide enforcement
Expected output:
Formatting¶
Auto-format code:
Black configuration:
- Line length: 200 characters
- Target: Python 3.8, 3.9, 3.10, 3.11, 3.12
- See
pyproject.tomlfor details
Formatted files:
siglent/- Main packagetests/- Test filesexamples/- Example scripts
Pre-commit Hooks¶
Install hooks:
Run manually:
Configured hooks:
- Trailing whitespace removal
- End-of-file fixer
- YAML syntax check
- Black formatting
- Flake8 linting
Comprehensive Checks¶
Run all checks before committing:
Performs:
- Linting (Black + Flake8)
- All tests
- Build package
- Validate distributions
Pre-PR validation:
Runs comprehensive validation including:
- Code formatting
- Linting
- Type checking
- Tests with coverage
- Documentation build
- Package build
Fast pre-PR (skip slow checks):
Auto-fix issues:
Documentation¶
Generate Documentation¶
From code docstrings:
Runs scripts:
scripts/docs/generate_examples_docs.py- Creates example documentationscripts/docs/generate_api_stubs.py- Generates API reference from docstrings
What gets generated:
- API reference pages from Python docstrings
- Example documentation from
examples/directory - Navigation structure
Build Documentation¶
Build static site:
Output: site/ directory with static HTML
Open documentation:
Serve Documentation Locally¶
With live reload:
Access: http://127.0.0.1:8000
Features:
- Live reload on file changes
- Auto-rebuild on save
- Real-time preview
Deploy Documentation¶
To GitHub Pages:
Requirements:
- Git repository
- GitHub Pages enabled
- Write access to repository
What happens:
- Generates documentation from code
- Builds MkDocs site
- Pushes to
gh-pagesbranch - Documentation live at:
https://little-did-I-know.github.io/SCPI-Instrument-Control/
Documentation Structure¶
docs/
├── index.md # Homepage
├── getting-started/ # Getting started guides
│ ├── installation.md
│ ├── quickstart.md
│ └── connection.md
├── user-guide/ # User documentation
│ ├── basic-usage.md
│ ├── waveform-capture.md
│ ├── measurements.md
│ ├── trigger-control.md
│ └── advanced-features.md
├── gui/ # GUI documentation
│ ├── overview.md
│ ├── interface.md
│ ├── live-view.md
│ ├── visual-measurements.md
│ ├── fft-analysis.md
│ ├── protocol-decoding.md
│ └── vector-graphics.md
├── api/ # API reference (auto-generated)
│ ├── oscilloscope.md
│ ├── channel.md
│ ├── trigger.md
│ └── gui.md
├── examples/ # Example code (auto-generated)
│ └── *.md
└── development/ # Development guides
├── building.md
├── structure.md
└── testing.md
Documentation Autodoc¶
How it works:
- mkdocstrings - Extracts docstrings from Python code
- mkdocs-gen-files - Dynamically generates markdown files
- Scripts - Custom scripts generate example and API docs
Example API documentation:
Python code with docstrings:
def get_waveform(self, channel: int) -> Waveform:
"""Get waveform data from specified channel.
Args:
channel: Channel number (1-4)
Returns:
Waveform object with data and metadata
Raises:
ValueError: If channel number is invalid
"""
pass
Generated markdown:
MkDocs renders this as formatted API documentation.
Publishing¶
Publish to TestPyPI¶
Test upload:
Requirements:
- TestPyPI account
- API token configured in
~/.pypirc
Verify:
Publish to PyPI¶
Production release:
⚠️ Warning: This publishes to production PyPI!
Requirements:
- PyPI account
- API token configured
- Write access to package
Steps:
- Update version in
pyproject.toml - Update
CHANGELOG.md - Commit changes
- Create git tag:
git tag v0.3.0 - Push with tags:
git push --tags - Clean:
make clean - Build:
make build - Publish:
make publish
PyPI Configuration¶
Setup ~/.pypirc:
[distutils]
index-servers =
pypi
testpypi
[pypi]
username = __token__
password = pypi-... # Your PyPI API token
[testpypi]
username = __token__
password = pypi-... # Your TestPyPI API token
Security:
- Use API tokens, not passwords
- Generate tokens at: https://pypi.org/manage/account/token/
- Limit token scope to specific projects
Version Management¶
Version Location¶
Single source of truth: pyproject.toml
Also defined in: siglent/__init__.py
Check version:
Version Scheme¶
Semantic Versioning (SemVer):
- Major.Minor.Patch (e.g.,
0.3.0) - Major: Breaking changes
- Minor: New features, backwards compatible
- Patch: Bug fixes, backwards compatible
Development versions:
0.3.0.dev1- Development pre-release0.3.0a1- Alpha0.3.0b1- Beta0.3.0rc1- Release candidate
Release Process¶
1. Update version:
2. Update changelog:
3. Commit and tag:
git add pyproject.toml siglent/__init__.py CHANGELOG.md
git commit -m "Release v0.4.0"
git tag v0.4.0
git push origin main --tags
4. Build and publish:
5. Create GitHub release:
- Go to: https://github.com/little-did-I-know/SCPI-Instrument-Control/releases
- Click "Create a new release"
- Select tag:
v0.4.0 - Title:
Release 0.4.0 - Description: Copy from CHANGELOG.md
- Attach:
dist/*.tar.gzanddist/*.whl
Continuous Integration¶
GitHub Actions¶
Automated workflows:
- Run tests on push/PR
- Multiple Python versions
- Multiple operating systems
- Code coverage reporting
- Build validation
Workflow files:
.github/workflows/
├── test.yml # Run tests
├── lint.yml # Code quality
├── build.yml # Build package
└── publish.yml # Auto-publish on tag
Local CI Simulation¶
Run complete CI checks locally:
Simulates:
- All test suites
- Code formatting
- Linting
- Type checking
- Documentation build
- Package build
Troubleshooting¶
Build Failures¶
Problem: ModuleNotFoundError during build
Solution:
Problem: twine check fails
Solution:
# Check README syntax
pip install readme-renderer
python -c "import readme_renderer.rst; readme_renderer.rst.render(open('README.md').read())"
Test Failures¶
Problem: Import errors in tests
Solution:
Problem: GUI tests fail
Solution:
# Install GUI dependencies
pip install -e ".[gui]"
# Skip GUI tests if not needed
pytest tests/ -m "not gui"
Documentation Build Failures¶
Problem: mkdocs build fails
Solution:
# Install documentation dependencies
pip install -e ".[docs]"
# Regenerate API docs
make docs-generate
Problem: Autodoc not finding modules
Solution:
# Ensure package is installed
pip install -e .
# Check mkdocs.yml configuration
# Verify plugins are installed
Publishing Issues¶
Problem: twine upload authentication fails
Solution:
Problem: Package already exists
Solution:
Development Workflows¶
Daily Development¶
# 1. Pull latest changes
git pull
# 2. Create feature branch
git checkout -b feature/my-feature
# 3. Make changes to code
# 4. Format code
make format
# 5. Run tests
make test
# 6. Commit changes
git add .
git commit -m "Add feature X"
# 7. Push branch
git push origin feature/my-feature
# 8. Create pull request
Before Committing¶
# Format code
make format
# Run linting
make lint
# Run tests
make test
# Or run all at once
make check
Before Creating PR¶
Updating Dependencies¶
Update all dependencies:
Update specific dependency:
Freeze dependencies:
Quick Reference¶
Common Make Commands¶
| Command | Description |
|---|---|
make help |
Show all available commands |
make dev-setup |
Complete development setup |
make install |
Install package (editable) |
make install-all |
Install with all dependencies |
make test |
Run tests |
make test-cov |
Run tests with coverage |
make lint |
Run linting checks |
make format |
Auto-format code |
make clean |
Remove build artifacts |
make build |
Build distribution packages |
make check |
Run all checks |
make pre-pr |
Pre-PR validation |
make docs |
Build documentation |
make docs-serve |
Serve docs locally |
make publish-test |
Publish to TestPyPI |
make publish |
Publish to PyPI |
Build Artifacts¶
| Path | Description |
|---|---|
build/ |
Build directory (temporary) |
dist/ |
Distribution packages |
*.egg-info/ |
Package metadata |
site/ |
Built documentation |
htmlcov/ |
Coverage report |
.pytest_cache/ |
Pytest cache |
Configuration Files¶
| File | Purpose |
|---|---|
pyproject.toml |
Package metadata and build config |
Makefile |
Development task automation |
mkdocs.yml |
Documentation configuration |
.pre-commit-config.yaml |
Pre-commit hooks |
pytest.ini |
Pytest configuration |
Next Steps¶
- Project Structure - Understand the codebase organization
- Testing Guide - Learn about the test suite
- Contributing Guidelines - How to contribute
- Code of Conduct - Community guidelines