Skip to content

Latest commit

 

History

History
219 lines (217 loc) · 7.11 KB

File metadata and controls

219 lines (217 loc) · 7.11 KB

Python Startup Guide for GitHub Copilot Sessions

==============================================================================

This guide ensures proper code layout and industry standards for novice Python programmers

==============================================================================

==============================================================================

IMPORT RULES

==============================================================================

1. Import order (as enforced by isort):

- Future imports

- Standard library imports (grouped by module)

- Third-party imports (alphabetically)

- Local/first-party imports (alphabetically)

- Project/local folder imports

2. Example:

from future import annotations

import os

import sys

from pathlib import Path

import requests

import numpy as np

from myproject.utils import helper

from myapp.models import User

3. Never import without a clear requirement:

- Each import should serve a specific purpose

- Import only what you need, not everything from a package

- Document the dependency in requirements.txt

==============================================================================

FUNCTION DEFINITION RULES

==============================================================================

1. Every function must have:

- A clear docstring explaining its purpose

- Type hints for parameters and return values

- Type hints should be added as you learn, don't skip them entirely

- Clear docstring signature with parameters and return value

2. Docstring format (PEP 257/258):

"""

Brief description of what the function does.

Args:

param_name (type): Description of parameter.

param_name (type): Description of parameter.

Returns:

type: Description of return value.

Raises:

ExceptionType: When exception is raised.

"""

3. Function naming:

- Use descriptive names that explain WHAT, not HOW

- Use snake_case for functions

- Prefix with underscore for private functions

4. Example:

def calculate_average_score(scores: list[float]) -> float:

"""Calculate the average of a list of scores.

Args:

scores (list[float]): List of numerical scores.

Returns:

float: The average score.

Raises:

ValueError: If the scores list is empty.

"""

if not scores:

raise ValueError("Scores list cannot be empty")

return sum(scores) / len(scores)

5. NO GUARDIAN CLAUSE FUNCTIONS:

Avoid patterns like:

def process_data(data: dict) -> Optional[dict]:

if data is None:

return None

# process...

Instead:

def process_data(data: dict | None) -> dict | None:

return data if data else None

==============================================================================

CLASS DEFINITION RULES

==============================================================================

1. Every class must have:

- A clear docstring explaining its purpose

- Type hints for init parameters and instance attributes

- Property-based accessors for instance attributes (prefer @property)

2. Example:

class User:

"""A user entity with profile information.

Attributes:

user_id (int): The unique identifier.

name (str): The user's full name.

email (str): The user's email address.

"""

def init(self, user_id: int, name: str, email: str) -> None:

"""Initialize a new User instance.

Args:

user_id (int): The unique identifier.

name (str): The user's full name.

email (str): The user's email address.

"""

self._user_id = user_id

self._name = name

self._email = email

@property

def user_id(self) -> int:

"""Get the user's unique identifier."""

return self._user_id

@property

def name(self) -> str:

"""Get the user's full name."""

return self._name

==============================================================================

LAYOUT RULES

==============================================================================

1. File structure:

- One file per module (one concern per file)

- Related but distinct functionality should be in separate files

- Example: models.py, services.py, validators.py for a feature

2. Module organization:

app/

init.py

models/ # Data models

user.py

post.py

services/ # Business logic

auth.py

notification.py

controllers/ # Request handlers

user.py

post.py

utils/ # Shared utilities

validators.py

formatters.py

3. No circular imports - import from top-level modules only

==============================================================================

ERROR HANDLING RULES

==============================================================================

1. Never use bare except:

- Always catch specific exceptions

- Example: except ValueError as e:

2. Use logging, not print statements:

import logging

logger = logging.getLogger(name)

logger.info("Processing...")

logger.error("Something went wrong", exc_info=True)

3. Validate inputs with clear error messages:

def process(data: dict) -> dict:

if "id" not in data:

raise ValueError("Missing required field: id")

return data

==============================================================================

TYPE HINTING RULES

==============================================================================

1. Use typing module for complex types:

from typing import Optional, List, Dict, Union

2. Use Python 3.10+ syntax for simple cases:

def func(x: int | str) -> None: # Union[int, str]

3. Type hint collections:

- list[int] instead of List[int] (Python 3.9+)

- dict[str, int] instead of Dict[str, int]

- Optional[int] for nullable values

==============================================================================

DO NOT DO:

==============================================================================

1. NEVER create functions without:

- Type hints on parameters

- Type hints on return values (except for None, bool, etc.)

- A docstring

2. NEVER use magic numbers:

BAD: result = value * 0.95

GOOD: result = value * DISCOUNT_RATE

3. NEVER assume data shapes:

BAD: data[0][1] # assuming list of lists

GOOD: data["items"][0]["price"] # using explicit keys

4. NEVER import modules just in case you need them:

import numpy as np # don't use

Instead:

from numpy import array # import only what you need

==============================================================================