-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy path200-python.mdc
More file actions
3339 lines (2543 loc) · 91.3 KB
/
Copy path200-python.mdc
File metadata and controls
3339 lines (2543 loc) · 91.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
---
title: Python Code Review & Enhancement Guidelines
description: Opinionated, performance- and security-minded Python rules for generation and review.
priority: 200
alwaysApply: false
files:
include:
- "**/*.py"
- "pyproject.toml"
- "uv.lock"
- "requirements*.txt"
- ".pre-commit-config.yaml"
---
## Guiding Principle
Apply features only when they add clarity, correctness, performance, or security. Prefer simple, intentional solutions (DRY, KISS, YAGNI, Fail Fast).
## The Zen of Python (`import this`)
The canonical aphorisms by Tim Peters (PEP 20). When in doubt about which Python idiom to choose, re-read these. Quote verbatim; do not paraphrase in code reviews.
```text
The Zen of Python, by Tim Peters
Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!
```
Operative readings (how to apply each in review):
- **Beautiful is better than ugly.** Refactor for clarity even when the ugly version "works".
- **Explicit is better than implicit.** Type hints, named arguments for booleans, no magic numbers, no implicit string-to-int conversion.
- **Simple is better than complex.** Reach for stdlib before a framework. Reach for a function before a class.
- **Complex is better than complicated.** When complexity is intrinsic, structure it (clear names, small functions); don't tangle it.
- **Flat is better than nested.** Early returns, guard clauses, comprehensions over nested loops where readable.
- **Sparse is better than dense.** Whitespace and blank lines are tools. One-liners that need a comment to explain are not Pythonic.
- **Readability counts.** Code is read more often than written. Optimize for the reader.
- **Special cases aren't special enough to break the rules.** No "just this once" pattern violations. Refactor the rule or live with it.
- **Although practicality beats purity.** Ship the working answer; idealize in the next PR.
- **Errors should never pass silently.** No bare `except:`; no `try: ... except: pass`. Raise specific exceptions.
- **Unless explicitly silenced.** When you do want to swallow, document why and catch the *specific* exception.
- **In the face of ambiguity, refuse the temptation to guess.** Ask. Test. Read the spec. Don't ship a heuristic dressed as logic.
- **There should be one-- and preferably only one --obvious way to do it.** Prefer `dict.get(k)` over `dict[k] if k in dict else None`. Use the canonical idiom, not the cleverest one.
- **Although that way may not be obvious at first unless you're Dutch.** A wink at Guido. Translation: when the obvious way isn't obvious to you yet, it's because you haven't read enough Python.
- **Now is better than never.** Ship the boring correct version; don't wait for perfection.
- **Although never is often better than *right* now.** Don't merge under pressure. Bad code now costs more than no code now.
- **If the implementation is hard to explain, it's a bad idea.** If reviewers can't follow it, neither will the on-call.
- **If the implementation is easy to explain, it may be a good idea.** Easy to explain is necessary, not sufficient. Confirm it's also correct.
- **Namespaces are one honking great idea -- let's do more of those!** Modules over flat top-level namespaces. Classes when state warrants. Avoid `from foo import *`.
### Examples
```python
# BAD: Unpythonic - dense, nested, unclear
def process(data):
return [x*2 for x in [y for y in data if y>0] if x*2<100]
# GOOD: Pythonic - flat, explicit, readable
def process(data: list[int]) -> list[int]:
"""Process positive numbers, doubling values under 100."""
positive = [x for x in data if x > 0]
doubled = [x * 2 for x in positive]
return [x for x in doubled if x < 100]
# BAD: Unpythonic - implicit, two ways to do one thing
def get_value(d, k):
if k in d:
return d[k]
return None
# GOOD: Pythonic - one obvious way
def get_value(d: dict[str, int], k: str) -> int | None:
"""Get value from dictionary, returning None if missing."""
return d.get(k)
# BAD: Unpythonic - errors pass silently
def divide(a, b):
try:
return a / b
except Exception:
pass
# GOOD: Pythonic - errors handled explicitly; specific exception
def divide(a: float, b: float) -> float:
"""Divide a by b. Raises ValueError if b is zero."""
if b == 0:
raise ValueError("Division by zero")
return a / b
```
> Run `python -c "import this"` in any Python REPL to see the canonical text.
## Non-negotiables
> [!IMPORTANT]
> These are the hard floors. Every other section in this rule is guidance; the items below are **reject-in-review**.
### NN-1: Python ≥ 3.14 for new applications, services, and Lambda functions
Any new Python application, service, scheduled job, CLI tool, or AWS Lambda function ships with `requires-python = ">=3.14"`. This is non-negotiable for the same reason Module Workers syntax is non-negotiable for new Cloudflare Workers (`401-cloudflare-workers.mdc` NN-1): consistent runtime semantics, access to current type-system features (built-in generics, `|` union syntax, template strings, deferred annotations, free-threading), and the cost of supporting older runtimes that the rest of the codebase doesn't.
**Exception - libraries with broad audiences:**
Libraries published to PyPI or shipped to external customers MAY target a lower floor when there is a stated compatibility commitment. The acceptable lower floor is **Python 3.11** (the oldest CPython version with active security support per [PEP 387 deprecation policy](https://peps.python.org/pep-0387/) as of this rule's last review). The PR description MUST include:
- The audience justification (e.g., "library targets all CPython versions with active security support per PEP 387")
- The features being foregone by the lower floor (no template strings, no deferred annotations, no free-threading, no built-in `type` statement)
- A planned floor-bump date (e.g., "raise to 3.14 when 3.11 reaches EOL")
**Reject in review:**
- New application / service / Lambda with `requires-python = ">=3.11"` (or lower) and no library-audience justification
- New code targeting Python 3.10 or below for any reason (3.10 reaches EOL in October 2026; 3.11 is the absolute floor)
- `pyproject.toml` without `requires-python` at all (must be explicit)
- New code using `from typing import List, Dict, Optional, Tuple, Union` instead of `list[X]`, `dict[K, V]`, `X | None`, `tuple[X, Y]`, `X | Y` (the 3.14+ built-in generics + `|` union syntax are the only acceptable forms; see § Type Hints below)
- `Dockerfile` based on `python:3.13`, `python:3.12`, `python:3.11`, or older for a new app / service / Lambda
- CI workflow using `python-version: '3.13'`, `'3.12'`, `'3.11'`, or older for a new app / service / Lambda
- `runtime = "python3.13"` (or older) in Lambda / serverless configuration for a new function
### NN-2: Leading underscores mean non-public API
Do not prefix functions, methods, classes, variables, modules, or packages with `_` unless they are intentionally non-public implementation details. A leading underscore is a contract with readers and tools: "this is internal; don't import or call it from outside this module/package."
Use public names for public behavior:
```python
# GOOD: public API, public name
def validate_order(order: Order) -> None:
...
# GOOD: internal helper, module-private name
def _normalize_order_id(raw_order_id: str) -> str:
...
```
**Reject in review:**
- `_process_data()`, `_validate_input()`, or `_build_payload()` called directly from other modules
- Public classes or modules named `_Client`, `_Service`, `_helpers`, or similar without being intentionally internal
- Double-underscore methods (`__method`) unless name-mangling is intentionally required to avoid subclass collisions
- Invented dunder names such as `__process__` or `__validate__` in application code
- Leading underscore added "because it looks cleaner" or because the function is merely small
If a helper starts internal but becomes reused across modules, promote it to a public name or move it behind a clearer public API. Do not leak private-looking names into callers.
## 0) AI Assistant Guidelines
When providing code assistance, follow these guardrails:
- **Avoid Over-Engineering**: Do not recommend `boto3` client caching, `async/await`, `threading`, `multiprocessing`, or other advanced concurrency patterns unless the user explicitly requests them or performance bottlenecks are evident.
- **Keep It Simple**: Prefer straightforward solutions using standard library features over complex architectures.
- **Testing Guidance**: Suggest appropriate tests or improvements to existing test coverage when reviewing code.
- **Explain Trade-offs**: When proposing optimizations or refactoring, clearly explain the benefits and costs (complexity, maintenance, performance).
- **Respect Context**: Analyze the provided code and suggest improvements that align with its scope and purpose - don't transform a 20-line script into a 200-line framework.
## 1) Standards
- **Shebang:** `#!/usr/bin/env -S uv run` (required for new scripts). Use `uv` for modern Python tooling.
- **Python Version:** ≥ 3.14.
- **Formatting:** 4-space indents; soft wrap at 120 chars (adhere to PEP 8, PEP 257, PEP 484).
- **Linting:** Run `black`, `ruff`, `isort`, `mypy`, and `pylint`. Aim for a score of ≥9.5 on `pylint`.
- **Security Scanning:** Run `bandit` to detect common security issues in Python code.
- **String Formatting:** Use double quotes `"` unless the string contains double quotes (use `'` then). `black` handles this.
- **Imports:** Grouped: stdlib / third-party / local. Sorted alphabetically within groups. Separate groups with blank lines. Use `isort` to automatically sort imports.
- **Documentation:**
- Google-style docstrings for all functions, classes, methods.
- Keep docstrings accurate: when changing behavior or signatures, update docstrings (and examples, if present) in the same change.
- Module docstring immediately below shebang (leave space between shebang and docstring).
- Include workflow with numbered steps if applicable.
- Add usage syntax guide with command-line examples (not needed for Lambda).
- Inline comments for complex logic.
- **Type Hints:** Strict typing required. Use Python 3.14 built-in types:
- `Dict` -> `dict`
- `List` -> `list`
- `Tuple` -> `tuple`
- `Set` -> `set`
- `Union[X, Y]` -> `X | Y`
- `Optional[X]` -> `X | None`
- **Type Checking:** Use `ty` (recommended), `mypy --strict`, or `pyright`.
- **ty** (recommended): Astral's Rust-based type checker, 10-60x faster than mypy with excellent diagnostics. Install: `uv tool install ty@latest`, run: `ty check .`
- **mypy**: Stable, widely adopted. Run with `--strict` for full coverage.
- **pyright**: Microsoft's type checker, good VS Code integration.
- Use `NewType`, `TypedDict`, or `TypeAlias` for specificity.
- **Dependencies:** Use `uv` for package management. Define dependencies in `pyproject.toml` (not `requirements.txt`). Introduce third-party libraries only when needed - stick to stdlib otherwise.
- **Circular Imports:** Avoid by restructuring (move shared logic to separate module).
- **Local Libraries:** Use `aws_utils.py`, `cloudflare_utils.py`, `utils.py` for common tasks to avoid duplication.
## 1a) Code Quality Tools & Commands
**Required Tools:** All Python projects must run these tools before committing.
### Formatting & Linting Commands
**Format code (auto-fix):**
```bash
# Format with black
black .
# Sort imports with isort
isort .
# Run both together
black . && isort .
```
**Check formatting (CI/pre-commit):**
```bash
# Check without modifying files
black --check .
isort --check-only .
# Run both checks
black --check . && isort --check-only .
```
**Lint with ruff:**
```bash
# Check for issues
ruff check .
# Auto-fix issues
ruff check --fix .
# Check specific file
ruff check path/to/file.py
```
**Type checking with mypy:**
```bash
# Strict type checking (recommended)
mypy --strict .
# Type check specific file
mypy --strict path/to/file.py
# Alternative: Use ty (faster, recommended)
ty check .
```
**Lint with pylint:**
```bash
# Run pylint on file/directory
pylint path/to/file.py
# Run with specific score threshold (fail if below 9.5)
pylint --fail-under=9.5 path/to/file.py
# Run on entire project
pylint --fail-under=9.5 .
# Generate report
pylint --output-format=text path/to/file.py > pylint_report.txt
```
### Complete Quality Check Workflow
**Before committing, run:**
```bash
# 1. Format code
black .
isort .
# 2. Lint and auto-fix
ruff check --fix .
# 3. Type check
mypy --strict .
# OR (faster)
ty check .
# 4. Pylint (aim for ≥9.5)
pylint --fail-under=9.5 .
# 5. Security scan
bandit -r . -ll
```
**Quick check (CI/pre-commit):**
```bash
# Check-only mode (no modifications)
black --check . && \
isort --check-only . && \
ruff check . && \
mypy --strict . && \
pylint --fail-under=9.5 . && \
bandit -r . -ll
```
### Configuration Files
**pyproject.toml (Recommended):**
```toml
[tool.black]
line-length = 120
target-version = ['py314']
[tool.isort]
profile = "black"
line_length = 120
[tool.ruff]
line-length = 120
target-version = "py314"
[tool.ruff.lint]
select = ["E", "F", "I", "N", "W", "UP"]
ignore = []
[tool.mypy]
python_version = "3.14"
strict = true
warn_return_any = true
warn_unused_configs = true
disallow_untyped_defs = true
[tool.pylint.messages_control]
disable = ["C0103", "C0111"] # Disable specific checks if needed
[tool.pylint.format]
max-line-length = 120
```
**pylintrc (Optional, for project-specific config):**
```ini
[FORMAT]
max-line-length=120
[MESSAGES CONTROL]
disable=
C0103, # invalid-name (if using non-standard naming)
C0111, # missing-docstring (if docstrings not required)
[REPORTS]
output-format=text
score=yes
```
### Pylint Score Targets
**Score interpretation:**
- **10.0** - Perfect (rare, may require disabling some checks)
- **9.5-9.9** - Excellent (target for production code)
- **9.0-9.4** - Good (acceptable, but aim higher)
- **<9.0** - Needs improvement
**Common issues that lower score:**
- Missing docstrings
- Long lines (>120 chars)
- Too many arguments (>5)
- Too many local variables (>15)
- Cyclomatic complexity (>10)
**Improving pylint score:**
```bash
# Run pylint to see issues
pylint path/to/file.py
# Fix issues incrementally:
# 1. Add missing docstrings
# 2. Break up complex functions
# 3. Reduce function arguments
# 4. Fix naming conventions
# 5. Add type hints
```
### Pre-commit Integration
**Add to `.pre-commit-config.yaml`:**
```yaml
repos:
- repo: https://github.com/psf/black
rev: 24.1.1
hooks:
- id: black
args: [--line-length=120]
- repo: https://github.com/pycqa/isort
rev: 5.13.2
hooks:
- id: isort
args: [--profile=black, --line-length=120]
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.1.8
hooks:
- id: ruff
args: [--fix, --exit-non-zero-on-fix]
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.8.0
hooks:
- id: mypy
args: [--strict]
additional_dependencies: [types-all]
- repo: local
hooks:
- id: pylint
name: pylint
entry: pylint
language: system
args: [--fail-under=9.5]
types: [python]
```
### CI/CD Integration
**GitHub Actions example:**
```yaml
name: Code Quality
on: [push, pull_request]
jobs:
quality:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.14'
- name: Install dependencies
run: |
uv sync
- name: Format check
run: |
black --check .
isort --check-only .
- name: Lint
run: |
ruff check .
- name: Type check
run: |
mypy --strict .
- name: Pylint
run: |
pylint --fail-under=9.5 .
```
## 1a) Package Management (uv)
**Prefer `uv` for new projects** - Fast, modern Python package installer and resolver.
**Installation:**
```bash
curl -LsSf https://astral.sh/uv/install.sh | sh
```
**Project Setup:**
```bash
uv init my-project
uv sync
```
**Benefits:** 10-100x faster, deterministic resolution, drop-in pip replacement.
## 1b) Import Sorting (isort)
**Use `isort` to automatically sort imports** - Ensures consistent import ordering across projects.
**Installation:**
```bash
uv add --dev isort
# or
pip install isort
```
**Configuration (pyproject.toml):**
```toml
[tool.isort]
profile = "black" # Compatible with black formatting
line_length = 120
multi_line_output = 3 # Vertical hanging indent
include_trailing_comma = true
force_grid_wrap = 0
use_parentheses = true
ensure_newline_before_comments = true
skip_glob = ["*/migrations/*", "*/venv/*", "*/.venv/*"]
# Import sections: stdlib, third-party, local
sections = ["FUTURE", "STDLIB", "THIRDPARTY", "FIRSTPARTY", "LOCALFOLDER"]
known_first_party = ["my_package"]
```
**Usage:**
```bash
# Check import order
isort --check-only .
# Auto-fix import order
isort .
# Check specific file
isort --check-only src/main.py
# Auto-fix specific file
isort src/main.py
```
**Integration with pre-commit:**
```yaml
# .pre-commit-config.yaml
repos:
- repo: https://github.com/PyCQA/isort
rev: 5.13.2
hooks:
- id: isort
args: ["--profile", "black"]
```
**Import order example:**
```python
# Standard library
import logging
import os
from datetime import datetime, timezone
from typing import Any
# Third-party
import boto3
import requests
from pydantic import BaseModel
# Local
from utils import setup_logger
from models import User
```
## 2) Code Structure & Readability
- **Function Order:** Order functions by call hierarchy. Helper functions first, `main()` last.
- **Entry Point:** Always use `if __name__ == "__main__":` to call the main function.
- **Small Functions:** Break code into small, reusable functions with meaningful verb-based names.
- **Defensive Programming:** Validate inputs early (fail-fast). Use specific checks (`if x is None`) over broad `try/except`.
- **Meaningful Naming:** Use `fetch_user_details` (not `get`) or `order_total` (not `ot`).
- **No Mutable Defaults:** Avoid `def foo(bar=[])`. Use `def foo(bar: list[str] | None = None): bar = bar or []`.
## 3) Modern Python & Advanced Features
### Core Language Features
- **f-strings:** Use `f"User: {user_name}"` for formatting. Python 3.14: `f"{text!r}"` for debugging.
- **Exception Handling:** Use `try-except-else-finally` for complex flows.
- **Assertions:** Use `assert stock >= 0, "Stock cannot be negative"` for development - not production.
- **Comprehensions:** Use `[price * 2 for price in prices]` where clear - avoid if it reduces readability.
- **Walrus Operator (`:=`):** Use `if (count := len(items)) > 5:` for inline assignments - don't force it.
- **match-case:** Simplify complex conditionals:
```python
def handle_response(code: int) -> str:
match code:
case 200: return "Success"
case 400 | 404: return "Client Error"
case _: return "Unknown"
```
- **Literal Types:** Use `status: Literal["active", "inactive"]` for fixed values.
- **Type Safety:** Use `isinstance` and `issubclass` for safe type checks.
### Python 3.14 Features (Released Oct 2025)
**Template String Literals (PEP 750):**
Safe custom string processing with t-strings for parameterized queries, HTML escaping, and custom formatting:
```python
# SQL query with safe parameterization
query = t"SELECT * FROM users WHERE id = {user_id}"
# HTML generation with auto-escaping
html = t"<div>{user_input}</div>"
# Custom formatting
config = t"server={host}:{port}"
```
**Deferred Annotation Evaluation (PEP 649):**
Annotations are no longer evaluated eagerly, improving startup performance for heavily-annotated code:
```python
# Annotations stored in __annotate__ function
# Evaluated only when inspect.get_annotations() is called
def process(data: ComplexType) -> Result:
"""Annotations evaluated lazily, not at import time."""
...
```
**Free-Threading Support (PEP 779):**
True parallelism without the GIL (experimental, use with `python3.14t`):
```python
# Enable with: python3.14t (free-threaded build)
# Performance penalty reduced to 5-10% for single-threaded code
import concurrent.futures
with concurrent.futures.ThreadPoolExecutor() as executor:
results = executor.map(cpu_intensive_task, items)
```
**datetime Improvements:**
Direct parsing of date and time strings:
```python
from datetime import date, time
# Python 3.14+
d = date.fromisoformat("2025-10-07")
t = time.fromisoformat("14:30:00")
```
**UUID7 and UUID8 Support:**
Modern UUID versions with better properties:
```python
import uuid
# UUID7: Time-ordered, sortable (recommended for databases)
id = uuid.uuid7()
# UUID8: Custom format
id = uuid.uuid8(bytes16)
```
**Enhanced REPL:**
- Colorized syntax highlighting as you type
- Improved error messages with keyword suggestions
- Better interactive debugging experience
### Functional Programming
- **`functools.wraps`:** Preserve metadata in decorators.
- **`functools.cache`:** Use `@functools.cache` for costly, repeated calls.
- **`functools.partial`:** Pre-specify function arguments: `partial(multiply, 2)`.
- **`functools.singledispatch`:** Polymorphic functions based on type.
- **`functools.total_ordering`:** Reduce comparison method boilerplate.
- **map/filter/reduce:** Use where readable - prefer comprehensions otherwise.
### Data Structures
- **dataclasses:** Use for data-centric classes:
```python
from dataclasses import dataclass, field
@dataclass
class Product:
product_id: int
tags: list[str] = field(default_factory=list)
```
- **`collections`:** Use `Counter`, `deque`, `defaultdict`, `namedtuple` where appropriate.
- **Tuple Unpacking:** Use `x, y = get_coordinates()` for cleaner code.
- **`enumerate`:** Use `for idx, value in enumerate(values):` for indexed loops.
### Standard Library Modules to Prefer
**Principle:** Prefer standard library modules over third-party alternatives when they meet your needs. This reduces dependencies, improves portability, and leverages well-tested, maintained code.
**Common Standard Library Modules:**
#### File & Path Operations
**`pathlib` (Preferred over `os.path`):**
```python
# BAD: os.path (old-style, string-based)
import os
file_path = os.path.join("data", "users", "file.txt")
if os.path.exists(file_path):
with open(file_path) as f:
content = f.read()
# GOOD: pathlib (object-oriented, cross-platform)
from pathlib import Path
file_path = Path("data") / "users" / "file.txt"
if file_path.exists():
content = file_path.read_text()
# Advanced pathlib features
config_dir = Path.home() / ".config" / "app"
config_dir.mkdir(parents=True, exist_ok=True)
config_file = config_dir / "config.toml"
# Iterate over directory
for py_file in Path("src").rglob("*.py"):
print(py_file.stem) # filename without extension
```
**`shutil` (File operations):**
```python
import shutil
from pathlib import Path
# Copy files/directories
shutil.copy("source.txt", "dest.txt")
shutil.copytree("src_dir", "dest_dir", dirs_exist_ok=True)
# Move/rename
shutil.move("old.txt", "new.txt")
# Archive operations
shutil.make_archive("backup", "zip", "data_dir")
shutil.unpack_archive("backup.zip", "extract_dir")
# Disk usage
total, used, free = shutil.disk_usage("/")
```
#### Functional Programming
**`functools` (Function utilities):**
```python
from functools import partial, cache, wraps, singledispatch
# partial: Pre-specify function arguments
def multiply(x: int, y: int) -> int:
return x * y
double = partial(multiply, 2) # Equivalent to: lambda y: multiply(2, y)
result = double(5) # 10
# cache: Memoization for expensive functions
@cache
def expensive_computation(n: int) -> int:
# Expensive operation
return sum(i**2 for i in range(n))
# wraps: Preserve function metadata in decorators
def timing_decorator(func):
@wraps(func) # Preserves __name__, __doc__, etc.
def wrapper(*args, **kwargs):
start = time.time()
result = func(*args, **kwargs)
print(f"{func.__name__} took {time.time() - start:.2f}s")
return result
return wrapper
# singledispatch: Polymorphic functions based on type
@singledispatch
def process(data):
raise NotImplementedError(f"Cannot process {type(data)}")
@process.register
def _(data: dict):
return {k: str(v) for k, v in data.items()}
@process.register
def _(data: list):
return [str(item) for item in data]
```
#### Data Structures & Algorithms
**`heapq` (Priority queues):**
```python
import heapq
# Min-heap (default)
heap = []
heapq.heappush(heap, 5)
heapq.heappush(heap, 2)
heapq.heappush(heap, 8)
smallest = heapq.heappop(heap) # 2
# Max-heap (negate values)
max_heap = []
heapq.heappush(max_heap, -10)
heapq.heappush(max_heap, -5)
largest = -heapq.heappop(max_heap) # 10
# Priority queue pattern
tasks = []
heapq.heappush(tasks, (1, "low priority task"))
heapq.heappush(tasks, (0, "high priority task"))
priority, task = heapq.heappop(tasks) # Gets high priority first
```
**`graphlib` (Topological sorting, Python 3.9+):**
```python
from graphlib import TopologicalSorter
# Build dependency graph
graph = {
"task_a": {"task_b", "task_c"},
"task_b": {"task_d"},
"task_c": {"task_d"},
"task_d": set(),
}
# Get execution order
ts = TopologicalSorter(graph)
execution_order = list(ts.static_order()) # ['task_d', 'task_b', 'task_c', 'task_a']
```
**`secrets` (Cryptographically secure random, preferred over `random` for security):**
```python
import secrets
import string
# Generate secure random token
token = secrets.token_urlsafe(32) # URL-safe token
# Generate secure random string
alphabet = string.ascii_letters + string.digits
password = ''.join(secrets.choice(alphabet) for _ in range(16))
# Compare securely (constant-time)
if secrets.compare_digest(user_input, expected_token):
# Secure comparison (prevents timing attacks)
pass
# BAD: Using random for security
import random
token = ''.join(random.choice(alphabet) for _ in range(16)) # Not cryptographically secure!
```
#### Configuration & Data Formats
**`tomllib` (TOML parsing, Python 3.11+):**
```python
import tomllib
from pathlib import Path
# Read TOML file
with open("config.toml", "rb") as f: # Note: binary mode required
config = tomllib.load(f)
# Access nested values
database_url = config["database"]["url"]
api_key = config["api"]["key"]
# BAD: Using third-party library
# import tomli # Don't need this if Python 3.11+
```
**`json` (JSON parsing):**
```python
import json
from pathlib import Path
# Read JSON
with Path("data.json").open() as f:
data = json.load(f)
# Write JSON (with formatting)
with Path("output.json").open("w") as f:
json.dump(data, f, indent=2, sort_keys=True)
# Parse JSON string
config = json.loads('{"key": "value"}')
```
**`configparser` (INI-style config files):**
```python
import configparser
config = configparser.ConfigParser()
config.read("config.ini")
database_host = config.get("database", "host")
debug = config.getboolean("app", "debug", fallback=False)
```
#### Utilities
**`itertools` (Iterator tools):**
```python
from itertools import chain, cycle, islice, pairwise, batched, groupby, combinations, permutations, product, zip_longest
# Chain iterables
combined = list(chain([1, 2], [3, 4])) # [1, 2, 3, 4]
# Pairwise iteration (Python 3.10+)
for prev, curr in pairwise([1, 2, 3, 4]):
print(f"{prev} -> {curr}") # 1 -> 2, 2 -> 3, 3 -> 4
# Batched (Python 3.12+)
for batch in batched(range(10), 3):
print(list(batch)) # [0, 1, 2], [3, 4, 5], [6, 7, 8], [9]
# Cycle through values
colors = cycle(["red", "green", "blue"])
next(colors) # "red"
next(colors) # "green"
# Group consecutive elements
data = [1, 1, 2, 2, 2, 3, 3]
for key, group in groupby(data):
print(f"{key}: {list(group)}") # 1: [1, 1], 2: [2, 2, 2], 3: [3, 3]
# Combinations and permutations
items = ['a', 'b', 'c']
list(combinations(items, 2)) # [('a', 'b'), ('a', 'c'), ('b', 'c')]
list(permutations(items, 2)) # [('a', 'b'), ('a', 'c'), ('b', 'a'), ...]
# Cartesian product
list(product([1, 2], ['a', 'b'])) # [(1, 'a'), (1, 'b'), (2, 'a'), (2, 'b')]
# Zip longest (fill missing with default)
list(zip_longest([1, 2], ['a'], fillvalue='-')) # [(1, 'a'), (2, '-')]
# Slice iterator
for item in islice(range(100), 10, 20): # Items 10-19
print(item)
```
**`textwrap` (Text formatting):**
```python
import textwrap
# Wrap text to specified width
text = "This is a long line that needs to be wrapped to fit within 50 characters."
wrapped = textwrap.wrap(text, width=50)
# ['This is a long line that needs to be', 'wrapped to fit within 50 characters.']
# Fill text (wrap and join)
filled = textwrap.fill(text, width=50)
# Multi-line string with line breaks
# Dedent (remove leading whitespace) - great for SQL, templates
sql = textwrap.dedent("""
SELECT *
FROM users
WHERE active = true
""").strip()
# Removes common leading whitespace
# Indent text
indented = textwrap.indent("Line 1\nLine 2", prefix=" ")
# " Line 1\n Line 2"
# Shorten text with ellipsis
short = textwrap.shorten("This is a very long string", width=20, placeholder="...")
# "This is a very..."
```
**`contextlib` (Context managers):**
```python
from contextlib import contextmanager, suppress, redirect_stdout