Practicalities: linting, testing, documentation.

Python Style Best Practises

Python Style Best Practises

PEP8: Style Guide for Python Code

PEP8 is the de facto coding style guide for Python.
PEP = Python Enhancement Proposal
It provides guidelines for writing clean, readable, and consistent Python code. Key points include:
Indentation: Use 4 spaces per indentation level.
Maximum Line Length: 79 characters for code, 72 for comments.
Blank Lines: Separate functions and classes with two blank lines.
Imports: Place imports at the top, grouped as standard library, third-party, and local.
Whitespace: Avoid unnecessary spaces inside parentheses, brackets, and braces.
Naming Conventions:
  • Variables & functions: lower_case_with_underscores
  • Classes: CapWords
  • Constants: UPPER_CASE_WITH_UNDERSCORES

Comments: Keep them meaningful and concise.
Docstrings: Use triple quotes for module, class, and function documentation.
Boolean Comparisons: Use if x is None instead of if x == None.
Exception Handling: Use try-except with specific exceptions.

Indentation


            # Wrong:

            # Arguments on first line forbidden when not using vertical alignment.
            foo = long_function_name(var_one, var_two,
                var_three, var_four)
        

            # Correct:

            # Aligned with opening delimiter.
            foo = long_function_name(var_one, var_two,
                                     var_three, var_four)

            # Add 4 spaces (an extra level of indentation) to distinguish arguments from the rest.
            def long_function_name(
                    var_one, var_two, var_three,
                    var_four):
                print(var_one)
        

Line break before or after a binary operator?


            # Wrong:
            # operators sit far away from their operands
            income = (gross_wages +
                      taxable_interest +
                      (dividends - qualified_dividends) -
                      ira_deduction -
                      student_loan_interest)
        

            # Correct:
            # easy to match operators with operands
            income = (gross_wages
                      + taxable_interest
                      + (dividends - qualified_dividends)
                      - ira_deduction
                      - student_loan_interest)
        

Indentation: Tabs or Spaces?

Spaces are the preferred indentation method.
Python 3 disallows mixing the use of tabs and spaces for indentation.

Code Productivity: Linting and Formatting

Code Productivity: Linting and Formatting

The Problem: Code Quality at Scale

As Python projects grow in size and complexity, maintaining consistent code quality becomes increasingly challenging. Developers face several issues:
Inconsistent code style across team members
Hard-to-catch bugs and anti-patterns
Time wasted on manual code reviews for style issues
Difficulty onboarding new team members to coding standards
That's why Python Developers use linters and formatters. These tools not only help maintain code quality but also significantly improve developer productivity and collaboration

Linting: Your First Line of Defense

Linting is the process of analyzing code to detect potential errors, bugs, stylistic issues, and suspicious constructs without actually executing the code.
Benefits of Linting:
Early detection of bugs and potential issues
Enforcement of coding standards
Reduction in technical debt
Improvement in code readability and maintainability
Educational tool for developers to learn best practices
Traditional Python linters are Pylint and Flake8

Formatting: Consistency Without Debate

Code formatting is the automatic restructuring of code layout to meet a consistent style, without changing its functionality.
Benefits of Formatting:
Eliminates style debates in code reviews
Creates consistent codebase appearance
Reduces cognitive load when reading code
Saves time previously spent on manual formatting
Traditional Python formatters are Black and YAPF

The Modern Approach: Ruff

What is Ruff?

Ruff is an extremely fast Python linter and formatter, written in Rust, that has been gaining significant adoption since its first stable release in 2024.
Key features of ruff:
Combines linting and formatting in one tool
10-100x faster than traditional Python linters
Compatible with Pylint, Flake8, and Black rules
Provides automatic fixes for many issues
Highly configurable through simple configuration files

Setup Ruff

VSCode Extension Method (Recommended for VSCode-only use):
Install the Ruff Extension.
This extension will handle the installation of Ruff itself and provide integration with VSCode
Pip Installation Method (CLI)
Install Ruff with pip install ruff
Then install the Ruff VSCode extension to connect the two
Installing via pip as well gives you more flexibility if you ever need to use Ruff from the command line or in scripts:

                # Install Ruff
                pip install ruff

                # Run linting
                ruff check .

                # Run linting with automatic fixes
                ruff check --fix .

                # Format code
                ruff format .
            

Configure Ruff

Ruff works well out-of-the-box with sensible defaults, but you can configure it to suit your project's specific needs.
Ruff's configuration lives in a pyproject.toml file, which must be in your project root folder.
Example of Ruff's configuration:

                [tool.ruff]
                # Set the maximum allowed line length to 80 characters
                line-length = 80

                # Select which rules to enable
                # "ALL" enables every single rule that Ruff supports
                select = [
                    "ALL",
                ]

                # Specify which rules to ignore
                ignore = [
                    "D100",   # Ignore missing module docstrings (top-level docstrings in files)
                    "T201",   # Ignore warnings about print statements (useful for debugging/learning)
                ]

                # Exclude files and directories from being checked
                # These are typically system directories or generated code
                exclude = [
                    ".git",
                    ".mypy_cache",
                    ".ruff_cache",
                    "venv",
                    ".venv",
                    "__pycache__",
                ]

                # Configuration for the linting component of Ruff
                [tool.ruff.lint]
                # Allow Ruff to automatically fix all fixable violations
                # This makes it easy to clean up code with a single command
                fixable = ["ALL"]

                # Configuration for the formatting component of Ruff
                [tool.ruff.format]
                # Use double quotes for strings (similar to Black's default style)
                quote-style = "double"
            
Reference: Configuring Ruff

TOML syntax

TOML (Tom's Obvious, Minimal Language) is a configuration file format designed to be easy to read and write. Created as an alternative to formats like JSON, YAML, and INI.
TOML syntax isn't natively recognized by VSCode as a language, meaning that you might not get syntax highlighting and other language-specific features out of the box.
To enable TOML support, install the Even Better TOML extension from the VSCode marketplace.
This extension provides syntax highlighting, formatting, and other TOML-specific features.

Configure VSCode Settings

You can configure Ruff to format Python code on-save by enabling the editor.formatOnSave action in settings.json, and setting Ruff as your default formatter:

                {
                  "[python]": {
                    "editor.formatOnSave": true,
                    "editor.defaultFormatter": "charliermarsh.ruff"
                  }
                }
            
You can configure Ruff to fix lint violations on-save by enabling the source.fixAll action in settings.json:

                {
                    "[python]": {
                    "editor.codeActionsOnSave": {
                        "source.fixAll": "explicit"
                    }
                    }
                }
            

Resources

Video: ruff - ultra-fast Python Linting & Formatting | Django example

Video: Python Linting in VS Code

Document your code

Document your code

Docstring Versus Block Comments

Docstrings and block comments are not interchangeable..
The docstring describes the operation of the function or class and will be shown on calling the help function.

                def foo(x,y):
                    # Just a Block comment - do not use it for function description
                    """foo() Summary

                    Args:
                        x (TYPE): int
                        y (TYPE): int

                    Returns:
                        TYPE: int
                    """
                    return x+Y


                help(foo)

                # Help on function foo in module __main__:

                # foo(x, y)
                #     foo() Summary

                #     Args:
                #         x (TYPE): int
                #         y (TYPE): int

                #     Returns:
                #         TYPE: int
            

Project Documentation for Contributors

A README file at the root directory should give general information to both users and maintainers of a project
A LICENSE file should always be present and specify the license under which the software is made available to the public.
A TODO file (or section in README) should list the planned development for the code.
A CHANGELOG file (or section in README) should present a short overview of the changes in the code base for the latest versions.

Python documentation tools

Sphinx - is a tool that makes it easy to create intelligent and beautiful documentation
Sphinx is well integrated with Read The Docs - free documentation hosting for the open source community
Features:
Supports various output formats (HTML, PDF, LaTeX, etc.)
Generates comprehensive documentation including API references, tutorials, and narratives.
Integrates with other tools like Read the Docs for hosting documentation.

These slides are based on

customised version of

Hakimel's reveal.js

framework