Skip to content

Commit 69203d2

Browse files
Add STYLE_GUIDE.md to docs and enhance content
This commit introduces STYLE_GUIDE.md in the docs/ directory to outline coding conventions, patterns, and best practices for the project. Key changes from any previous (uncommitted) versions: - Moved the style guide to `docs/STYLE_GUIDE.md`. - Added a dedicated 'Testing' section with expanded guidelines on: - Test location and naming. - Use of Pytest fixtures (e.g., `LoggingEnvironment` pattern). - Test parametrization. - Writing clear, focused, and robust test cases. - Clarified Markdown heading usage versus internal code comment sectioning. The guide covers: - Use of automated formatters/linters (Black, Pylint, MyPy). - Import organization. - Naming conventions. - Type hinting requirements. - Docstring standards (Google style via mkdocstrings) with version markers. - Rule for explicit return statements. - Class structure and internal code commenting conventions. - Common code patterns (versioning, TypeAlias, custom exceptions, utils).
1 parent 1f0cbd0 commit 69203d2

1 file changed

Lines changed: 146 additions & 0 deletions

File tree

docs/STYLE_GUIDE.md

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
# Python Style Guide
2+
3+
This document outlines the coding style, conventions, and common patterns for the `python-json-logger` project. Adhering to this guide will help maintain code consistency, readability, and quality.
4+
5+
## General Principles
6+
7+
* **Readability Counts:** Write code that is easy for others (and your future self) to understand.
8+
* **Consistency:** Strive for consistency in naming, formatting, and structure throughout the codebase.
9+
* **Simplicity:** Prefer simple, straightforward solutions over overly complex ones.
10+
11+
## Formatting and Linting
12+
13+
We use automated tools to enforce a consistent code style and catch potential errors. These include:
14+
15+
* **Black:** For opinionated code formatting.
16+
* **Pylint:** For static code analysis and error detection.
17+
* **MyPy:** For static type checking.
18+
19+
Ensure these tools are run before committing code. Configuration for these tools can be found in `pyproject.toml`, `pylintrc`, and `mypy.ini` respectively. This guide does not repeat rules enforced by these tools but focuses on conventions not automatically verifiable.
20+
21+
## Imports
22+
23+
Imports should be structured into the following groups, separated by a blank line:
24+
25+
1. **Future Imports:** e.g., `from __future__ import annotations`
26+
2. **Standard Library Imports:** e.g., `import sys`, `from datetime import datetime`
27+
3. **Installed (Third-Party) Library Imports:** e.g., `import pytest`
28+
4. **Application (Local) Imports:** e.g., `from .core import BaseJsonFormatter`
29+
30+
Within each group, imports should generally be alphabetized.
31+
32+
## Naming Conventions
33+
34+
* **Modules:** `lowercase_with_underscores.py`
35+
* **Packages:** `lowercase`
36+
* **Classes:** `CapWords` (e.g., `BaseJsonFormatter`)
37+
* **Type Aliases:** `CapWords` (e.g., `OptionalCallableOrStr`)
38+
* **Functions and Methods:** `lowercase_with_underscores()` (e.g., `merge_record_extra()`)
39+
* **Variables:** `lowercase_with_underscores`
40+
* **Constants:** `UPPERCASE_WITH_UNDERSCORES` (e.g., `RESERVED_ATTRS`)
41+
42+
## Type Hinting
43+
44+
* All new code **must** include type hints for function arguments, return types, and variables where appropriate.
45+
* Use standard types from the `typing` module (e.g., `Optional`, `Union`, `List`, `Dict`, `Callable`, `Any`).
46+
* For Python versions older than 3.10, use `typing_extensions.TypeAlias` for creating type aliases. For Python 3.10+, use `typing.TypeAlias`.
47+
48+
## Docstrings
49+
50+
* All public modules, classes, functions, and methods **must** have docstrings.
51+
* We use `mkdocstrings` for generating API documentation, which defaults to the **Google Python Style Guide** for docstrings. Please adhere to this style. You can find the guide [here](https://google.github.io/styleguide/pyguide.html#38-comments-and-docstrings).
52+
* Docstrings should clearly explain the purpose, arguments, return values, and any exceptions raised.
53+
* Use the following markers to indicate changes over time:
54+
* `*New in version_number*`: For features added in a specific version.
55+
* `*Changed in version_number*`: For changes made in a specific version.
56+
* `*Deprecated in version_number*`: For features deprecated in a specific version.
57+
58+
Example:
59+
```python
60+
def my_function(param1: str, param2: int) -> bool:
61+
"""Does something interesting.
62+
63+
Args:
64+
param1: The first parameter, a string.
65+
param2: The second parameter, an integer.
66+
67+
Returns:
68+
True if successful, False otherwise.
69+
70+
Raises:
71+
ValueError: If param2 is negative.
72+
73+
*New in 3.1*
74+
"""
75+
if param2 < 0:
76+
raise ValueError("param2 cannot be negative")
77+
# ... function logic ...
78+
return True
79+
```
80+
81+
## Return Statements
82+
83+
* **All functions and methods must have an explicit `return` statement.**
84+
* If a function does not logically return a value, it should end with `return None` or simply `return`. This makes the intent clear.
85+
86+
Example:
87+
```python
88+
def process_data(data: dict) -> None:
89+
"""Processes the given data."""
90+
# ... processing logic ...
91+
print(data)
92+
return # or return None
93+
```
94+
95+
## Class Structure
96+
97+
* Group methods logically within a class. For example:
98+
* Initialization methods (`__init__`, `__new__`)
99+
* Public methods
100+
* Protected/Private methods (by convention, prefixed with `_` or `__`)
101+
* Special methods (`__str__`, `__repr__`)
102+
* Within source code comments, use `## Section Name ##` or `### Subsection Name ###` to delineate logical sections if it improves readability, especially in larger classes (e.g., `## Parent Methods ##` as seen in `src/pythonjsonlogger/core.py`).
103+
104+
## Testing
105+
106+
This project uses `pytest` for testing.
107+
108+
* **Test Location:** Tests are located in the `tests/` directory.
109+
* **Test Naming:** Test files should be named `test_*.py` and test functions/methods should be prefixed with `test_`.
110+
* **Fixtures:** Utilize `pytest` fixtures (e.g., `@pytest.fixture`) for setting up test preconditions and managing test state.
111+
* The `LoggingEnvironment` dataclass and `env` fixture in `tests/test_formatters.py` are good examples of reusable test setups for logger testing. Strive to create similar helpers for common testing scenarios.
112+
* **Parametrization:** Use `@pytest.mark.parametrize` to run the same test function with different inputs and expected outputs. This is highly encouraged to reduce code duplication and cover multiple scenarios efficiently.
113+
* **Clarity and Focus:** Each test case should ideally test one specific aspect of functionality. Test names should be descriptive of what they are testing.
114+
* **Assertions:** Use clear and specific `pytest` assertions (e.g., `assert foo == bar`, `assert isinstance(obj, MyClass)`).
115+
* **Robustness:** Write tests that are not overly brittle. For example, avoid making assertions on exact string matches of complex, auto-generated outputs if only a part of it is relevant.
116+
117+
## Common Code Patterns and Idioms
118+
119+
* **Version-Specific Logic:** When code needs to behave differently based on the Python version, use `sys.version_info`:
120+
```python
121+
if sys.version_info >= (3, 10):
122+
# Python 3.10+ specific code
123+
pass
124+
else:
125+
# Code for older versions
126+
pass
127+
```
128+
* **Type Aliases for Clarity:** Use `TypeAlias` for complex or frequently used type combinations to improve readability.
129+
```python
130+
from typing import List, Tuple, Union
131+
from typing_extensions import TypeAlias # For Python < 3.10
132+
133+
Coordinate: TypeAlias = Tuple[int, int]
134+
PointOrListOfPoints: TypeAlias = Union[Coordinate, List[Coordinate]]
135+
```
136+
* **Custom Exceptions:** Define custom exception classes for application-specific error conditions to provide more meaningful error information (e.g., `MissingPackageError`).
137+
* **Helper/Utility Functions:** Encapsulate reusable logic into well-named helper functions, often placed in `utils.py` or similar utility modules.
138+
139+
## Comments
140+
141+
* Use comments to explain non-obvious code, complex logic, or important decisions.
142+
* Avoid comments that merely restate what the code does.
143+
* Module-level, class-level, and function/method-level explanations should primarily be in docstrings.
144+
* For internal code organization within files, especially in longer modules or classes, use comments like `## Section Title ##` or `### Subsection Title ###` to delineate logical blocks of code. This is distinct from Markdown headings used in this document.
145+
146+
By following these guidelines, we can ensure that `python-json-logger` remains a high-quality, maintainable, and developer-friendly library.

0 commit comments

Comments
 (0)