Thank you for your interest in contributing to shconfparser! This document provides guidelines and instructions for contributing to the project.
- Code of Conduct
- Getting Started
- Development Setup
- Development Workflow
- Coding Standards
- Testing
- Documentation
- Pull Request Process
- Project Architecture
- Release Process
This project adheres to the Contributor Covenant Code of Conduct. By participating, you are expected to uphold this code.
- Python 3.9+ (3.9, 3.10, 3.11, 3.12, 3.13 supported)
- uv package manager (recommended) or pip
- Git for version control
- Fork the repository on GitHub
- Clone your fork locally:
git clone https://github.com/YOUR_USERNAME/shconfparser.git
cd shconfparser- Add upstream remote:
git remote add upstream https://github.com/network-tools/shconfparser.git# Install uv if you haven't already
curl -LsSf https://astral.sh/uv/install.sh | sh
# Create virtual environment and install dependencies
uv venv
source .venv/bin/activate # On Windows: .venv\Scripts\activate
# Install package in editable mode with dev dependencies
uv pip install -e ".[dev]"
# Install pre-commit hooks (optional but recommended)
uv run pre-commit install# Create virtual environment
python -m venv .venv
source .venv/bin/activate # On Windows: .venv\Scripts\activate
# Install package in editable mode with dev dependencies
pip install -e ".[dev]"
# Install pre-commit hooks
pre-commit install# Install everything (package + dev tools + pre-commit)
make dev-installgit checkout -b feature/your-feature-name
# or
git checkout -b fix/issue-descriptionFollow the Coding Standards below.
# Run all tests
make test
# or
uv run pytest
# Run with coverage
uv run pytest --cov=shconfparser
# Run specific test file
uv run pytest tests/test_parser.py -v# Run all checks at once
make check-all
# Or run individually:
make format # Auto-format with black
make lint # Check with ruff
make type-check # Check types with mypygit add .
git commit -m "feat: add new feature" # Use conventional commitsCommit Message Format:
feat:- New featurefix:- Bug fixdocs:- Documentation changestest:- Test additions/changesrefactor:- Code refactoringperf:- Performance improvementschore:- Build/tooling changes
git push origin feature/your-feature-nameThen create a Pull Request on GitHub.
We follow PEP 8 with the following tools:
- Black (line length: 100) - Code formatting
- Ruff - Fast linting
- MyPy - Static type checking
All public functions and methods must have type hints:
def parse_tree(self, lines: List[str]) -> TreeData:
"""Parse hierarchical configuration."""
...Use Google-style docstrings with full descriptions:
def parse_table(
self,
lines: List[str],
headers: List[str]
) -> Optional[TableData]:
"""Parse tabular data into list of dictionaries.
Args:
lines: Lines containing table data
headers: List of column header names
Returns:
List of dictionaries (one per row), or None if header not found
Example:
>>> parser = Parser()
>>> table = parser.parse_table(lines, ['Port', 'Status'])
"""- Use custom exceptions from
exceptions.py - Provide clear error messages with context
- Log errors appropriately
from .exceptions import InvalidHeaderError
try:
header_index = self._fetch_header(lines, pattern)
except Exception as e:
raise InvalidHeaderError("Header not found", pattern=pattern)Organize imports in this order:
# Standard library
import json
import logging
from typing import List, Optional
# Third-party (if any)
# Local imports
from .exceptions import ParserError
from .models import TreeDataAdd __repr__() methods to classes:
def __repr__(self) -> str:
"""Return string representation for debugging."""
return f"Parser(data_keys={len(self.data)}, table_rows={len(self.table)})"- Parser: Orchestrates sub-parsers, maintains backward compatibility
- TreeParser: Pure tree parsing logic (stateless)
- TableParser: Pure table parsing logic (stateless)
- Reader: File I/O operations
- Search: Pattern matching utilities
- ShowSplit: Command splitting
Write pure functions where possible:
# Good: Pure function
def parse_tree(self, lines: List[str]) -> TreeData:
# Takes input, returns output, no side effects
return self._convert_to_dict(data)
# Avoid: Stateful methods when not needed
def parse_tree(self, lines: List[str]) -> None:
self.data = self._convert_to_dict(data) # Side effectUse protocols for interfaces:
from typing import Protocol
class Parsable(Protocol):
def parse(self, lines: List[str]) -> Any:
...- Place tests in
tests/directory - Name test files
test_*.py - Use descriptive test names:
test_parse_table_with_missing_header - Aim for 80%+ code coverage
import pytest
from shconfparser import Parser
class TestParser:
@pytest.fixture
def parser(self):
return Parser()
def test_parse_tree_valid_input(self, parser):
"""Test tree parsing with valid hierarchical input."""
lines = ['interface Ethernet0', ' ip address 1.1.1.1']
result = parser.parse_tree(lines)
assert 'interface Ethernet0' in result
assert result['interface Ethernet0'] is not None# All tests
make test
# Specific test
uv run pytest tests/test_parser.py::TestParser::test_tree_parser -v
# With coverage report
uv run pytest --cov=shconfparser --cov-report=html
# Fast fail (stop on first failure)
uv run pytest -xCheck coverage:
make test
# Coverage report generated in htmlcov/
open htmlcov/index.htmlAll public APIs must have docstrings with:
- Brief description
- Args section
- Returns section
- Raises section (if applicable)
- Example section (recommended)
If you add/change features, update:
- Docstrings in code
- README.md (if user-facing)
- CHANGELOG.md (add to Unreleased section)
- docs/ files (if major change)
✅ Checklist:
- Tests pass (
make test) - Code formatted (
make format) - Linting passes (
make lint) - Type checking passes (
make type-check) - All checks pass (
make check-all) - Documentation updated
- CHANGELOG.md updated (in Unreleased section)
- Commit messages follow conventional commits format
Use conventional commit format:
feat: Add TreeParser class for better separation of concernsfix: Handle mixed indentation in tree parsingdocs: Update contributing guidelines
## Description
Brief description of changes
## Type of Change
- [ ] Bug fix
- [ ] New feature
- [ ] Breaking change
- [ ] Documentation update
## Testing
- Describe tests added/modified
- Mention if manual testing was done
## Checklist
- [ ] Tests pass
- [ ] Code follows style guidelines
- [ ] Documentation updated
- [ ] CHANGELOG updated- Automated Checks: CI will run tests on multiple Python versions (3.9-3.13) and OSes
- Code Review: Maintainer will review your code
- Feedback: Address review comments
- Approval: Once approved, maintainer will merge
shconfparser/
├── __init__.py # Public API exports
├── exceptions.py # Custom exception classes
├── models.py # Dataclasses for structured results
├── protocols.py # Interface definitions
├── parser.py # Main Parser orchestrator
├── tree_parser.py # Tree structure parsing
├── table_parser.py # Table structure parsing
├── reader.py # File I/O operations
├── search.py # Pattern search utilities
└── shsplit.py # Command splitter
- Separation of Concerns: Each module has single responsibility
- Pure Functions: Stateless parsing where possible
- Backward Compatibility: Old APIs still work
- Type Safety: Full type hints with mypy validation
- Error Context: Rich exceptions with metadata
- Extensibility: Protocol-based interfaces
When adding features:
- Consider which module is responsible
- Add to appropriate parser (Tree/Table/etc.)
- Update main Parser if needed for orchestration
- Add custom exception if needed
- Create dataclass model for structured results (optional)
- Write comprehensive tests
- Document thoroughly
Releases are managed by maintainers:
- Update version in
pyproject.toml - Update CHANGELOG.md
- Create release tag:
git tag v3.0.1 - Push tag:
git push --tags - GitHub Actions will automatically publish to PyPI
- Issues: Open an issue on GitHub
- Discussions: Use GitHub Discussions for questions
- Email: kirankotari@live.com
Your contributions make shconfparser better for everyone. We appreciate your time and effort!
Quick Links: