Blame
| 77ba1d | Melisha Dsouza | 2026-01-16 07:46:25 | 1 | # **Python** |
| 2 | ||||
| 3 | **Scope**: This document defines the mandatory standards for all Python code to ensure readability, maintainability, security, and performance. |
|||
| 4 | ||||
| 5 | ### **1. Code Layout & Formatting** |
|||
| 6 | #### **1.1 Indentation** |
|||
| 7 | - **Rule**: Use 4 spaces per indentation level. |
|||
| 8 | - **Prohibited**: Never use tabs. |
|||
| 9 | ||||
| 10 | #### **1.2 Line Length** |
|||
| 11 | - **Standard**: Limit all lines to a maximum of 79 characters (PEP 8 standard). |
|||
| 12 | - **Modern Exception**: For complex configurations or type hints, 88 characters (Black formatter default) is acceptable if agreed upon by the team. |
|||
| 13 | - **Handling**: Break long lines using parentheses `()`, not backslashes `\`. |
|||
| 14 | ||||
| 15 | ```Python |
|||
| 16 | # Good |
|||
| 17 | user_permissions = ( |
|||
| 18 | "read_access", |
|||
| 19 | "write_access", |
|||
| 20 | "delete_access", |
|||
| 21 | "admin_access" |
|||
| 22 | ) |
|||
| 23 | ``` |
|||
| 24 | ||||
| 25 | #### **1.3 Imports** |
|||
| 26 | - **Order**: |
|||
| 27 | - Standard Library (e.g., `os`, `sys`) |
|||
| 28 | - Third-Party (e.g., `requests`, `pandas`) |
|||
| 29 | - Local Application (e.g., `from myapp.utils import helper`) |
|||
| 30 | - **Style**: Use absolute imports. Avoid wildcard imports (`from module import *`). |
|||
| 31 | ||||
| 32 | #### **1.4 Whitespace** |
|||
| 33 | - **Operators**: Surround binary operators with a single space (`x = 12`). |
|||
| 34 | - **Definitions**: One space after the colon in type hints (`age: int`). |
|||
| 35 | - **Functions**: Two blank lines before top-level functions; one blank line before methods inside a class. |
|||
| 36 | ||||
| 37 | ### **2. Naming Conventions** |
|||
| 38 | Follow strict PEP 8 naming to communicate intent instantly. |
|||
| 39 | ||||
| 40 | | Entity | Convention | Example | |
|||
| 41 | | --------- | --------------------- | ---------------------- | |
|||
| 42 | | Modules | `snake_case` | `data_processor.py` | |
|||
| 43 | | Classes | `PascalCase` | `UserProfile` | |
|||
| 44 | | Functions | `snake_case` | `calculate_total()` | |
|||
| 45 | | Variables | `snake_case` | `is_active`, `user_id` | |
|||
| 46 | | Constants | `SCREAMING_SNAKE` | `MAX_RETRIES = 3` | |
|||
| 47 | | Private | `_leading_underscore` | `_internal_cache` | |
|||
| 48 | ||||
| 49 | ### **3. Modern Type Hinting (Python 3.10+)** |
|||
| 50 | Type hinting is no longer optional; it is mandatory for maintainability. |
|||
| 51 | ||||
| 52 | #### **3.1 Syntax** |
|||
| 53 | - **Rule**: Use the modern pipe | operator for Unions instead of importing `Union` or `Optional`. |
|||
| 54 | - **Return Types**: Always specify the return type, even if it is `None`. |
|||
| 55 | ```Python |
|||
| 56 | ||||
| 57 | # Bad (Old Style) |
|||
| 58 | from typing import List, Optional |
|||
| 59 | def find_user(ids: List[int]) -> Optional[str]: ... |
|||
| 60 | ||||
| 61 | # Good (Modern Style) |
|||
| 62 | def find_user(ids: list[int]) -> str | None: |
|||
| 63 | ... |
|||
| 64 | ``` |
|||
| 65 | ||||
| 66 | #### **3.2 Collections** |
|||
| 67 | - **Rule**: Use standard collections `(list, dict, tuple)` instead of `typing.List` or `typing.Dict`. |
|||
| 68 | ||||
| 69 | ### **4. Documentation & Docstrings** |
|||
| 70 | #### **4.1 Format** |
|||
| 71 | - **Standard**: Use the Google Style docstring format. It is cleaner and more readable than reStructuredText. |
|||
| 72 | - **Requirement**: All public modules, classes, and functions must have a docstring. |
|||
| 73 | ||||
| 74 | ```Python |
|||
| 75 | def connect_to_db(timeout: int = 10) -> bool: |
|||
| 76 | """Establishes a connection to the primary database. |
|||
| 77 | ||||
| 78 | Args: |
|||
| 79 | timeout (int): Max time in seconds to wait for connection. |
|||
| 80 | ||||
| 81 | Returns: |
|||
| 82 | bool: True if connection successful, False otherwise. |
|||
| 83 | ||||
| 84 | Raises: |
|||
| 85 | ConnectionError: If the network is down. |
|||
| 86 | """ |
|||
| 87 | pass |
|||
| 88 | ``` |
|||
| 89 | #### **4.2 Comments** |
|||
| 90 | - **Rule**: Comments must explain "Why", not "What". |
|||
| 91 | - **Maintenance**: Delete commented-out code immediately. Do not commit dead code. |
|||
| 92 | ||||
| 93 | ### **5. Programming Best Practices** |
|||
| 94 | **5.1 Error Handling** |
|||
| 95 | - **Prohibited**: Never use bare except:. |
|||
| 96 | - **Best Practice**: Catch specific exceptions. |
|||
| 97 | - **Chaining**: When re-raising an exception, use `raise ... from e` to preserve the stack trace. |
|||
| 98 | ```Python |
|||
| 99 | # Good |
|||
| 100 | try: |
|||
| 101 | process_data() |
|||
| 102 | except ValueError as e: |
|||
| 103 | raise DataProcessingError("Invalid data format") from e |
|||
| 104 | ``` |
|||
| 105 | ||||
| 106 | #### **5.2 Conditionals & Truthiness** |
|||
| 107 | - Explicit is better: Use `if x is None:` instead `of if x == None:`. |
|||
| 108 | - Implicit False: Use implicit boolean checks for lists/strings. |
|||
| 109 | - Yes: `if my_list:` (Checks if list is not empty) |
|||
| 110 | - No: `if len(my_list) > 0:` |
|||
| 111 | ||||
| 112 | #### **5.3 Magic Numbers** |
|||
| 113 | - **Rule**: Replace raw numbers/strings with named constants or Enums. |
|||
| 114 | ||||
| 115 | ```Python |
|||
| 116 | from enum import Enum |
|||
| 117 | ||||
| 118 | class Status(Enum): |
|||
| 119 | PENDING = "pending" |
|||
| 120 | ACTIVE = "active" |
|||
| 121 | ||||
| 122 | # Usage |
|||
| 123 | if user.status == Status.ACTIVE: |
|||
| 124 | ... |
|||
| 125 | ``` |
|||
| 126 | ||||
| 127 | ### **6. Async & Performance (Modern Standards)** |
|||
| 128 | #### **6.1 Async/Await** |
|||
| 129 | - **Rule**: Do not use blocking code (e.g., `time.sleep, requests.get`) inside `async` functions. Use `await asyncio.sleep` or asynchronous libraries (e.g., `httpx`). |
|||
| 130 | - **Safe Handling**: Use `TaskGroup` (Python 3.11+) for managing concurrent tasks safely. |
|||
| 131 | #### **6.2 Loops** |
|||
| 132 | - **Rule**: Use `enumerate()` for indexing. |
|||
| 133 | - **Rule**: Prefer List Comprehensions for simple transformations, but use `for` loops if the logic is complex. |
|||
| 134 | ||||
| 135 | ### **7. Security & Privacy** |
|||
| 136 | - **Secrets**: Never commit API keys, passwords, or tokens to Git. Use `.env` files and `pydantic-settings`. |
|||
| 137 | - **Inputs**: Always validate user input. Never pass user input directly to `eval(), exec(),` or raw SQL queries (use ORM or parameterized queries). |
|||
| 138 | ||||
| 139 | ### **8. Automation & Tooling** |
|||
| 140 | Manual enforcement is unreliable. The project can use the following automated tools: |
|||
| 141 | - **Ruff**: The modern, high-speed replacement for Flake8 and isort. |
|||
| 142 | - **Black**: For uncompromising code formatting. |
|||
| 143 | - **Mypy**: For static type checking. |
|||
| 144 | - **Pre-commit**: To run these checks before every commit. |
|||
| 145 | Configuration (`pyproject.toml`) |
|||
| 146 | ||||
| 147 | Copy this configuration to standardise your team's tooling: |
|||
| 148 | ```Python |
|||
| 149 | [tool.ruff] |
|||
| 150 | line-length = 79 |
|||
| 151 | select = ["E", "F", "I", "UP", "B"] # Enforce PEP8, Imports, pyupgrade, Bugbear |
|||
| 152 | ||||
| 153 | [tool.mypy] |
|||
| 154 | strict = true |
|||
| 155 | ignore_missing_imports = true |
|||
| 156 | ``` |
|||
| 157 | ||||
| 158 | **Recommended folder structure for modern Python projects)** |
|||
| 159 | ``` |
|||
| 160 | project_root/ |
|||
| 161 | │ |
|||
| 162 | ├── src/ |
|||
| 163 | │ └── my_package/ |
|||
| 164 | │ ├── __init__.py |
|||
| 165 | │ ├── main.py |
|||
| 166 | │ └── utils.py |
|||
| 167 | ├── tests/ |
|||
| 168 | │ ├── __init__.py |
|||
| 169 | │ └── test_main.py |
|||
| 170 | ├── .env # Secrets (GitIgnored) |
|||
| 171 | ├── .gitignore |
|||
| 172 | ├── pyproject.toml # Tooling Config |
|||
| 173 | └── README.md |
|||
| 174 | ``` |