Skip to content

Commit 9e4c164

Browse files
committed
📚 Formatting & Linting: add linting sections
1 parent de35798 commit 9e4c164

File tree

4 files changed

+137
-28
lines changed

4 files changed

+137
-28
lines changed

‎docs/formatting.md‎

Lines changed: 119 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,26 @@
1-
# Formatting
1+
# Formatting & Linting
22

33
## What
44

5-
Code formatting refers to the consistent styling of your code - how it looks visually.
5+
**Code formatting** refers to the consistent styling of your code - how it looks visually.
66
This includes indentation, spacing, line length, quote styles, and other stylistic choices that don't affect how the code runs but impact how it reads.
77

8-
A code formatter automatically reformats your code to follow a consistent style.
9-
Popular Python formatters include:
10-
11-
- **black**: An opinionated formatter that enforces a strict style with minimal configuration.
12-
- **ruff**: A fast formatter that can also perform linting (checking for code quality issues).
8+
**Linting** checks your code for potential bugs, code smells, and programming errors.
9+
It catches issues like unused variables, undefined names, or overly complex code before they cause problems.
1310

1411
## Why
1512

16-
Consistent formatting serves several important purposes:
13+
**Formatting** helps you focus on logic rather than style:
1714

18-
**Focus on logic, not style**: With automatic formatting, you don't waste time or mental energy deciding where to put spaces, how to break lines, or arguing about style preferences during code reviews.
15+
- **Save time and energy**: No more deciding where to put spaces or how to break lines
16+
- **Improved readability**: Consistent code is easier to read and understand
17+
- **Better collaboration**: Everyone's code looks the same, so git diffs show real changes instead of whitespace adjustments
1918

20-
**Improved readability**: Consistent code is easier to read and understand.
21-
When all code follows the same patterns, you can focus on what the code does rather than getting distracted by inconsistent styling.
19+
**Linting** catches bugs before they happen:
2220

23-
**Better collaboration**: When everyone's code looks the same, it's easier to work together.
24-
Code reviews focus on functionality rather than style preferences, and git diffs show real changes instead of whitespace adjustments.
21+
- **Early bug detection**: Find issues like unused variables or undefined names before running your code
22+
- **Code quality**: Identify overly complex code, missing error handling, or potential performance issues
23+
- **Learn best practices**: Linters teach you Python conventions and common pitfalls to avoid
2524

2625
!!!example "Real-world scenario"
2726

@@ -37,7 +36,7 @@ Code reviews focus on functionality rather than style preferences, and git diffs
3736

3837
## How
3938

40-
We'll use `ruff` as our formatter.
39+
We'll use `ruff` as our tool of choice.
4140
It's fast, modern, and can handle both formatting (using `black` under the hood) and linting.
4241
Let's install `ruff` in our environment:
4342

@@ -46,13 +45,13 @@ pip install ruff
4645
```
4746

4847
Let's see `ruff` in action!
49-
First, create a poorly formatted Python file to demonstrate the formatter.
50-
51-
Copy this messy code into a new file `src/dev_tutorial/messy.py`:
48+
Have a look at the file `src/dev_tutorial/messy.py`:
5249

53-
```python
50+
```python {.no-copy}
51+
# src/dev_tutorial/messy.py
5452
def calculate_statistics(data,include_median=True):
5553
"""Calculate statistics for a list of numbers."""
54+
debug_mode=True
5655
if len(data)==0:
5756
return None
5857

@@ -77,14 +76,112 @@ This code has several formatting issues:
7776
Now run the formatter:
7877

7978
```
80-
ruff format
79+
ruff format src/dev_tutorial/messy_code.py
8180
```
8281

83-
You should see output like:
84-
8582
```console {.no-copy}
8683
1 file reformatted
8784
```
8885

8986
Open `src/dev_tutorial/messy.py` again and check how the code has changed.
90-
`ruff` has automatically fixed all the formatting issues.
87+
`ruff` has automatically fixed all the formatting issues:
88+
89+
```python
90+
def calculate_statistics(data, include_median=True):
91+
"""Calculate statistics for a list of numbers."""
92+
debug_mode = True
93+
if len(data) == 0:
94+
return None
95+
96+
mean = sum(data) / len(data)
97+
result = {"mean": mean, "min": min(data), "max": max(data)}
98+
99+
if include_median:
100+
sorted_data = sorted(data)
101+
n = len(sorted_data)
102+
median = (
103+
sorted_data[n // 2]
104+
if n % 2 != 0
105+
else (sorted_data[n // 2 - 1] + sorted_data[n // 2]) / 2
106+
)
107+
result["median"] = median
108+
109+
return result
110+
```
111+
112+
Much better!
113+
But we still haven't checked the code for quality issues.
114+
Let's run the linter:
115+
116+
```
117+
ruff check src/dev_tutorial/messy_code.py
118+
```
119+
120+
```console {.no-copy}
121+
F841 Local variable `debug_mode` is assigned to but never used
122+
--> src/dev_tutorial/messy_code.py:3:5
123+
|
124+
1 | def calculate_statistics(data, include_median=True):
125+
2 | """Calculate statistics for a list of numbers."""
126+
3 | debug_mode = True
127+
| ^^^^^^^^^^
128+
4 | if len(data) == 0:
129+
5 | return None
130+
|
131+
help: Remove assignment to unused variable `debug_mode`
132+
133+
Found 1 error.
134+
No fixes available (1 hidden fix can be enabled with the `--unsafe-fixes` option).
135+
```
136+
137+
The linter found an issue with our code!
138+
To understand the problem, run:
139+
140+
```
141+
ruff rule F841
142+
```
143+
144+
Now fix the issue by removing the unused `debug_mode` variable
145+
After making these changes manually, run both commands again to verify everything is clean:
146+
147+
```
148+
ruff format && ruff check
149+
```
150+
151+
### Automating with pre-commit
152+
153+
Instead of remembering to run `ruff format` and `ruff check` before every commit, you can use `pre-commit` to automatically run these checks.
154+
155+
`pre-commit` is a framework that manages git hooks - scripts that run automatically before you commit code.
156+
157+
First, install pre-commit:
158+
159+
```
160+
pip install pre-commit
161+
```
162+
163+
The project already has a `.pre-commit-config.yaml` file that configures which checks to run (have a look!).
164+
To install the git hooks, run:
165+
166+
```
167+
pre-commit install
168+
```
169+
170+
Now, every time you try to commit code, `pre-commit` will automatically:
171+
172+
1. Run `ruff format` to format your code
173+
2. Run `ruff check` to lint your code
174+
3. If any issues are found, the commit will be blocked until you fix them
175+
176+
You can also run the checks manually without committing:
177+
178+
```
179+
pre-commit run -a
180+
```
181+
182+
This ensures your code is always formatted and linted before it enters version control!
183+
184+
!!! tip "Give it a try!"
185+
186+
Try to make some changes to one of the modules, and run `git commit`.
187+
Both the linter and formatter should run automatically.

‎docs/index.md‎

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ Topics that will be covered:
1414
- [Packages](packages.md)
1515
- [Writing documentation](documentation.md)
1616
- [Testing with `pytest`](tests.md)
17-
- Formatting/linting your code with Ruff
17+
- [Formatting/linting your code with Ruff](formatting.md)
1818
- Continuous Integration (CI)
1919
- Publishing your code on the PyPI (CD)
2020

@@ -27,7 +27,3 @@ You won't need any advanced Python concepts, but understanding basic syntax will
2727
**Don't worry in case you don't understand everything right away!**
2828
All of this is very intimidating at first, I know, I've been there.
2929
It took me a long time to learn how to use these tools, and I'm still learning more every day.
30-
31-
!!! note
32-
33-
The material presented here is mostly based on my experience, but has also been inspired by [this excellent guide](https://learn.scientific-python.org/development/) from the [Scientific Python project](https://github.com/scientific-python).

‎template/src/{{ package_name.lower().replace('-', '_') }}/functions.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
"""Example functions."""
22

3+
34
def add(a, b):
45
return a + b
56

@@ -10,4 +11,3 @@ def sum_and_multiply(integer_list, factor):
1011

1112
def multiply(integer_list, factor):
1213
return [value * factor for value in integer_list]
13-
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
def calculate_statistics(data,include_median=True):
2+
"""Calculate statistics for a list of numbers."""
3+
debug_mode=True
4+
if len(data)==0:
5+
return None
6+
7+
mean=sum(data)/len(data)
8+
result={'mean':mean,'min':min(data),'max':max(data)}
9+
10+
if include_median:
11+
sorted_data=sorted(data)
12+
n=len(sorted_data)
13+
median=sorted_data[n//2] if n%2!=0 else (sorted_data[n//2-1]+sorted_data[n//2])/2
14+
result['median']=median
15+
16+
return result

0 commit comments

Comments
 (0)