|
| 1 | +# Python Code Formatting Guidelines |
| 2 | + |
| 3 | + |
| 4 | +# Code Formatting Philosophy, Principles and Specification |
| 5 | + |
| 6 | +## Core Principles |
| 7 | + |
| 8 | +### 1. Visual Pattern Recognition |
| 9 | +The human brain excels at pattern recognition. This formatting prioritizes creating clear visual patterns that make code structure immediately apparent: |
| 10 | +- Aligned equals signs create vertical lanes that guide the eye |
| 11 | +- Consistent comma placement creates predictable rhythm |
| 12 | +- Grouped imports with aligned elements form distinct visual blocks |
| 13 | + |
| 14 | +### 2. Information Density vs Readability |
| 15 | +While PEP-8 often spreads code across many lines for "readability", this approach recognizes that excessive vertical spread can actually harm comprehension by: |
| 16 | + |
| 17 | +- Forcing more scrolling |
| 18 | +- Breaking mental context |
| 19 | +- Making patterns harder to spot |
| 20 | +- Reducing the amount of code visible at once |
| 21 | + |
| 22 | +### 3. Contextual Proximity |
| 23 | +Related information should be visually close to enhance understanding: |
| 24 | +- Method documentation appears on the same line as the method definition |
| 25 | +- Constructor parameters align vertically to show relationships |
| 26 | +- Dictionary key-value pairs maintain close horizontal proximity |
| 27 | + |
| 28 | +## Departures from PEP-8 |
| 29 | + |
| 30 | +### Why We Differ |
| 31 | + |
| 32 | +PEP-8's formatting guidelines, while well-intentioned, can create several practical issues: |
| 33 | + |
| 34 | +1. Vertical Space Inefficiency |
| 35 | +```python |
| 36 | +# PEP-8 style |
| 37 | +self.method_call( |
| 38 | +parameter_one="value", |
| 39 | + parameter_two="value", |
| 40 | + parameter_three="value" |
| 41 | +) |
| 42 | + |
| 43 | +# This style |
| 44 | +self.method_call(parameter_one = "value", |
| 45 | + parameter_two = "value", |
| 46 | + parameter_three = "value") |
| 47 | +``` |
| 48 | + |
| 49 | +2. Loss of Visual Patterns |
| 50 | +```python |
| 51 | +# PEP-8 style |
| 52 | +assert something.value == expected_value |
| 53 | +assert something_else.other_value == other_expected_value |
| 54 | +assert third_thing.final_value == final_expected_value |
| 55 | + |
| 56 | +# This style |
| 57 | +assert something.value == expected_value |
| 58 | +assert something_else.value == other_expected_value |
| 59 | +assert third_thing.final_value == final_expected_value |
| 60 | +``` |
| 61 | + |
| 62 | +3. Broken Visual Context |
| 63 | +```python |
| 64 | +# PEP-8 style - related elements separated |
| 65 | +class SomeClass: |
| 66 | + |
| 67 | + def __init__( |
| 68 | + self, |
| 69 | + param_one, |
| 70 | + param_two |
| 71 | + ): |
| 72 | + self.param_one = param_one |
| 73 | + self.param_two = param_two |
| 74 | + |
| 75 | +# This style - related elements together |
| 76 | +class SomeClass: |
| 77 | + def __init__(self, param_one , |
| 78 | + param_two |
| 79 | + )-> None: |
| 80 | + self.param_one = param_one |
| 81 | + self.param_two = param_two |
| 82 | +``` |
| 83 | + |
| 84 | +## Benefits of Our Approach |
| 85 | + |
| 86 | +1. Enhanced Scanning |
| 87 | +- Column alignment makes it easy to scan for specific elements |
| 88 | +- Consistent patterns reduce cognitive load |
| 89 | +- Related information stays visually grouped |
| 90 | + |
| 91 | +2. Better Maintainability |
| 92 | +- Alignment makes inconsistencies immediately visible |
| 93 | +- Format violations stand out visually |
| 94 | +- Pattern adherence encourages consistent updates |
| 95 | + |
| 96 | +3. Improved Debugging |
| 97 | +- Clear visual structure helps spot logical errors |
| 98 | +- Aligned comparisons make value mismatches obvious |
| 99 | +- Grouped information reduces context switching |
| 100 | + |
| 101 | +4. Code Review Efficiency |
| 102 | +- Structured patterns make changes more apparent |
| 103 | +- Consistent formatting reduces noise in diffs |
| 104 | +- Visual grouping helps reviewers understand intent |
| 105 | + |
| 106 | +## Real-World Impact |
| 107 | + |
| 108 | +This formatting approach has proven particularly valuable in: |
| 109 | +- Large codebases where pattern recognition becomes crucial |
| 110 | +- Test files where structure and relationships matter more than PEP-8 conformity |
| 111 | +- Code review processes where visual clarity speeds up reviews |
| 112 | +- Debugging sessions where quick scanning and pattern recognition are essential |
| 113 | + |
| 114 | +Our philosophy prioritizes human factors and practical utility over strict adherence to style guidelines, recognizing that code is read far more often than it is written. |
| 115 | + |
| 116 | + |
| 117 | +# Python Code Formatting Specification |
| 118 | + |
| 119 | +## Import Statements |
| 120 | +Imports should be aligned with the longest import path, using spaces between major groups: |
| 121 | + |
| 122 | +```python |
| 123 | +from unittest import TestCase |
| 124 | +from mgraph_ai.schemas.Schema__MGraph__Node import Schema__MGraph__Node |
| 125 | +from mgraph_ai.schemas.Schema__MGraph__Node__Config import Schema__MGraph__Node__Config |
| 126 | +from osbot_utils.type_safe.primitives.safe_str.identifiers.Random_Guid import Random_Guid |
| 127 | +from osbot_utils.type_safe.primitives.safe_str.identifiers.Safe_Id import Safe_Id |
| 128 | +``` |
| 129 | + |
| 130 | +## Method Signature Formatting |
| 131 | + |
| 132 | +### Core Principles |
| 133 | + |
| 134 | +1. **Visual Lanes** |
| 135 | + - Parameters stack vertically |
| 136 | + - Type hints align in their own column |
| 137 | + - Comments align at a consistent position |
| 138 | + - Return types appear on a new line after continuation |
| 139 | + |
| 140 | +2. **Information Density** |
| 141 | + - Each line contains one parameter |
| 142 | + - Type information is immediately visible |
| 143 | + - Purpose is clear from aligned comment |
| 144 | + - Related elements stay visually grouped |
| 145 | + |
| 146 | +### Method Signature Layout |
| 147 | + |
| 148 | +```python |
| 149 | +def method_name(self, first_param : Type1 , # Method purpose comment |
| 150 | + second_param : Type2 , # Aligned at column 80 |
| 151 | + third_param : Type3 = None # Default values align with type |
| 152 | + ) -> ReturnType: # Return on new line |
| 153 | +``` |
| 154 | + |
| 155 | +Key aspects: |
| 156 | +- Method name starts at indent level |
| 157 | +- Parameters indent to align with opening parenthesis |
| 158 | +- Type hints align in their own column |
| 159 | +- Commas align in their own column |
| 160 | +- Backslash continuation before return type |
| 161 | +- Return type aligns with the first variable name |
| 162 | +- Comments align at column 80 |
| 163 | +- vertical alignment on : , # |
| 164 | +- DON'T use this when there is only one param or when (where are no types or default values being set) |
| 165 | +- the format for the return type is ") -> {return type}" |
| 166 | + |
| 167 | +### Parameter Documentation |
| 168 | + |
| 169 | +```python |
| 170 | +def complex_operation(self, data_input : Dict [str, Any] , # Primary data structure |
| 171 | + config_options : Optional[Config ] , # Processing configuration |
| 172 | + max_retries : int = 3 , # Maximum retry attempts |
| 173 | + timeout_ms : float = 1000.0 # Operation timeout |
| 174 | + ) -> Tuple[Results, Metrics]: # Returns results and metrics |
| 175 | +``` |
| 176 | + |
| 177 | +Guidelines: |
| 178 | +- Parameter names should be descriptive |
| 179 | +- Type hints should be as specific as possible |
| 180 | +- Default values align with type hints |
| 181 | +- Comments describe parameter purpose |
| 182 | +- Return type comment describes what is returned |
| 183 | + |
| 184 | +### Method Groups and Spacing |
| 185 | + |
| 186 | +Methods should be grouped by functionality with clear separation: |
| 187 | + |
| 188 | +```python |
| 189 | + # Core initialization methods |
| 190 | + def __init__(self, config : Config # Initialize with configuration |
| 191 | + ) -> None: |
| 192 | + |
| 193 | + def setup(self, options: Dict[str, Any] # Configure processing options |
| 194 | + ) -> bool: |
| 195 | + |
| 196 | + |
| 197 | + # Data validation methods |
| 198 | + def validate_input(self, data : InputData , # Validate input format |
| 199 | + strict_mode : bool = False # Enable strict validation |
| 200 | + ) -> ValidationResult: |
| 201 | + |
| 202 | + def validate_output(self, result : OutputData , # Validate output format |
| 203 | + thresholds : Thresholds # Validation thresholds |
| 204 | + ) -> bool: |
| 205 | + |
| 206 | + |
| 207 | + # Processing methods |
| 208 | + def process_item(self, item : DataItem , # Process single data item |
| 209 | + settings : Settings # Processing settings |
| 210 | + ) -> ProcessedItem: |
| 211 | +``` |
| 212 | +Note how the return type name assigns with the variable self, and there is always at least one space before the : and the , |
| 213 | + |
| 214 | +### Complex Type Signatures |
| 215 | + |
| 216 | +For methods with complex type signatures: |
| 217 | + |
| 218 | +```python |
| 219 | +def process_batch(self, items : List[DataItem] , # Batch of items to process |
| 220 | + batch_config : BatchConfig , # Batch processing config |
| 221 | + error_handler : ErrorHandler , # Handles processing errors |
| 222 | + retry_strategy : Optional[Strategy] , # Retry strategy to use |
| 223 | + metrics_callback : Callable[[Metrics], None] = None # Metrics reporting callback |
| 224 | + ) -> BatchResults: # Processed batch results |
| 225 | +``` |
| 226 | + |
| 227 | +Guidelines: |
| 228 | +- Break complex generic types at logical points |
| 229 | +- Align nested type parameters |
| 230 | +- Keep related type information together |
| 231 | +- Document complex types in comments |
| 232 | + |
| 233 | + |
| 234 | + |
| 235 | +## Variable Assignment Alignment |
| 236 | +Variable assignments should be aligned on the `=` operator: |
| 237 | + |
| 238 | +```python |
| 239 | +self.node_id = Random_Guid() |
| 240 | +self.value_type = str |
| 241 | +``` |
| 242 | + |
| 243 | +## Constructor Calls |
| 244 | +Constructor calls should be formatted with aligned parameters, aligned equals signs, and aligned commas: |
| 245 | + |
| 246 | +```python |
| 247 | +node_config = Schema__MGraph__Node__Config(node_id = Random_Guid(), |
| 248 | + value_type = str ) |
| 249 | + |
| 250 | +``` |
| 251 | + |
| 252 | +Note that: |
| 253 | +- The opening parenthesis is on the same line as the constructor call |
| 254 | +- Parameters are indented to align with the start of the constructor name |
| 255 | +- Equals signs are aligned |
| 256 | +- Commas are aligned at the end |
| 257 | +- Closing parenthesis is aligned with the commas |
| 258 | + |
| 259 | +## Assert Statements |
| 260 | +Assert statements should be aligned on the comparison operator: |
| 261 | + |
| 262 | +```python |
| 263 | +assert type(self.node) is Schema__MGraph__Node |
| 264 | +assert self.node.node_data == self.node_data |
| 265 | +assert self.node.value == "test_node_value" |
| 266 | +assert len(self.node.attributes) == 1 |
| 267 | +assert self.node.attributes[self.attribute.attribute_id] == self.attribute |
| 268 | +``` |
| 269 | + |
| 270 | +## Dictionary Literals |
| 271 | +Dictionary literals in constructor calls should maintain alignment while using minimal line breaks: |
| 272 | + |
| 273 | +```python |
| 274 | +node = Schema__MGraph__Node(attributes = {attr_1.attribute_id: attr_1 , |
| 275 | + attr_2.attribute_id: attr_2} , |
| 276 | + node_config = self.node_data , |
| 277 | + node_type = Schema__MGraph__Node , |
| 278 | + value = "test_node_value" ) |
| 279 | +``` |
| 280 | + |
| 281 | +## Test Class Structure |
| 282 | +Test classes should follow this structure: |
| 283 | +1. Helper classes (if needed) |
| 284 | +2. setUp method |
| 285 | +3. Test methods in logical grouping: |
| 286 | + - Basic initialization tests |
| 287 | + - Type safety validation tests |
| 288 | + - Functionality tests |
| 289 | + - Edge cases/special scenarios |
| 290 | + |
| 291 | +Example: |
| 292 | +```python |
| 293 | +class Simple_Node(Schema__MGraph__Node): pass # Helper class for testing |
| 294 | + |
| 295 | +class test_Schema__MGraph__Node(TestCase): |
| 296 | + |
| 297 | + def setUp(self): # Initialize test data |
| 298 | + ... |
| 299 | + |
| 300 | + def test_init(self): # Tests basic initialization |
| 301 | + ... |
| 302 | + |
| 303 | + def test_type_safety_validation(self): # Tests type safety |
| 304 | + ... |
| 305 | + |
| 306 | + def test_different_value_types(self): # Tests various scenarios |
| 307 | + ... |
| 308 | +``` |
| 309 | + |
| 310 | +## Comments and Documentation |
| 311 | +- Inline documentation should be minimal and descriptive |
| 312 | +- Comments explaining test cases should be aligned with the code |
| 313 | +- Complex test setups should include explanatory comments |
| 314 | +- DON'T add docstrings to methods or classes |
| 315 | +- methods or classes can have a comment in the same line as the method return value (column aligned with the other comments on the page) |
| 316 | + |
| 317 | +## Additional Guidelines |
| 318 | +- Maximum line length should be reasonable (around 120 characters) |
| 319 | +- Group related tests together |
| 320 | +- Use consistent spacing between methods (one line) |
| 321 | +- Maintain alphabetical ordering of imports when possible |
| 322 | +- Use clear and descriptive test method names |
| 323 | + |
| 324 | +This specification aims to enhance code readability while maintaining consistent formatting across the codebase. |
0 commit comments