Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 13 additions & 10 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,32 +2,35 @@
# Install: pip install pre-commit && pre-commit install
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.5.0
rev: v5.0.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-yaml
- id: check-added-large-files
- id: check-merge-conflict
- id: check-toml
- id: check-yaml
- id: detect-private-key
- id: end-of-file-fixer
- id: no-commit-to-branch
args: ['--branch', 'main']
- id: trailing-whitespace

- repo: https://github.com/psf/black
rev: 24.0.0
rev: 25.1.0
hooks:
- id: black
language_version: python3

- repo: https://github.com/pycqa/isort
rev: 5.13.0
rev: 6.0.1
hooks:
- id: isort

- repo: https://github.com/pycqa/flake8
rev: 7.0.0
rev: 7.3.0
hooks:
- id: flake8

- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.16.0
rev: v1.16.1
hooks:
- id: mypy
additional_dependencies: [types-all]
additional_dependencies: [pytest]
45 changes: 23 additions & 22 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,18 @@ A minimal Python project template following modern best practices and industry s
pip install -e .
```

4. **Set up pre-commit hooks**
```bash
# Install pre-commit
pip install pre-commit

# Install the git hook scripts
pre-commit install

# (Optional) Run on all files to test setup
pre-commit run --all-files
```

## 🧪 Running Tests

```bash
Expand All @@ -59,33 +71,22 @@ pytest tests/test_main.py -v

## 🛠️ Development Tools

### Code Formatting & Linting
```bash
# Format code with Black
black src/ tests/
### Pre-commit Hooks Setup

# Sort imports with isort
isort src/ tests/

# Lint with flake8
flake8 src/ tests/

# Type checking with mypy
mypy src/
```

### Pre-commit Hooks
Pre-commit hooks automatically run code formatting, linting, and type checking before each commit to ensure code quality.
```bash
# Install pre-commit
pip install pre-commit

# Install hooks
# Install the git hook scripts
pre-commit install

# Run hooks manually
# Test the setup
pre-commit run --all-files
```

> **Note**: Once installed, pre-commit will automatically run on every `git commit`. If any checks fail, the commit will be blocked until issues are fixed. Code formatting tools like Black and isort will auto-fix many issues.

## Features

- ✅ Modern Python packaging with `pyproject.toml`
Expand All @@ -112,7 +113,7 @@ python-template/
├── .gitignore # Git ignore rules
├── README.md # Project documentation
├── pyproject.toml # Modern Python packaging
└── requirements.txt # Dependencies
└── requirements-dev.txt # Development dependencies
```

## Installation
Expand All @@ -131,23 +132,23 @@ python-template/

3. Install dependencies:
```bash
pip install -r requirements.txt
pip install -r requirements-dev.txt
```

## Usage

Run the hello world application:

```bash
python -m src.hello_world.main
python -m hello_world.main
```

Or import and use in your code:

```python
from src.hello_world import hello_world
from hello_world import greet

print(hello_world("Python")) # Output: Hello, Python!
print(greet("Python")) # Output: Hello, Python!
```

## Development
Expand Down
13 changes: 7 additions & 6 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,17 @@ classifiers = [

[project.optional-dependencies]
dev = [
"pytest>=8.3.0",
"black>=25.1.0",
"flake8>=7.3.0",
"isort>=6.0.1",
"mypy>=1.16.1",
"pre-commit>=4.2.0",
"pytest-cov>=6.2.0",
"black>=24.0.0",
"isort>=5.13.0",
"flake8>=7.0.0",
"mypy>=1.16.0"
"pytest>=8.4.1",
]

[tool.pytest.ini_options]
minversion = "6.0"
minversion = "8.4"
addopts = "-ra -q --strict-markers --strict-config"
testpaths = ["tests"]
python_files = ["test_*.py", "*_test.py"]
Expand Down
11 changes: 6 additions & 5 deletions requirements.txt → requirements-dev.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@
# Add your production dependencies here

# Development dependencies (optional - can also use pip install -e ".[dev]")
pytest>=8.3.0
black>=25.1.0
flake8>=7.3.0
isort>=6.0.1
mypy>=1.16.1
pre-commit>=4.2.0
pytest-cov>=6.2.0
black>=24.0.0
isort>=5.13.0
flake8>=7.0.0
mypy>=1.16.0
pytest>=8.4.1
2 changes: 1 addition & 1 deletion src/hello_world/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ def greet(name: Optional[str] = None) -> str:
def main() -> None:
"""
Main entry point for the application.

Prints a default greeting message to stdout.
"""
print(greet())
Expand Down
24 changes: 14 additions & 10 deletions tests/test_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,34 +6,38 @@
"""

import pytest

from hello_world.main import greet


class TestGreetFunction:
"""Test cases for the greet function."""

def test_greet_default(self):
def test_greet_default(self) -> None:
"""Test greet function with default parameter (None)."""
assert greet() == "Hello, World!"

def test_greet_custom(self):
def test_greet_custom(self) -> None:
"""Test greet function with custom name."""
assert greet("Python") == "Hello, Python!"

def test_greet_empty_string(self):
def test_greet_empty_string(self) -> None:
"""Test greet function with empty string should default to World."""
assert greet("") == "Hello, World!"

def test_greet_none_explicit(self):
def test_greet_none_explicit(self) -> None:
"""Test greet function with explicit None parameter."""
assert greet(None) == "Hello, World!"

@pytest.mark.parametrize("name,expected", [
("Alice", "Hello, Alice!"),
("Bob", "Hello, Bob!"),
("123", "Hello, 123!"),
("Test User", "Hello, Test User!"),
])
@pytest.mark.parametrize(
"name,expected",
[
("Alice", "Hello, Alice!"),
("Bob", "Hello, Bob!"),
("123", "Hello, 123!"),
("Test User", "Hello, Test User!"),
],
)
def test_greet_parametrized(self, name: str, expected: str) -> None:
"""Test greet function with various inputs using parametrization."""
assert greet(name) == expected