Vinay Varma

Python VsCode Ecosystem

The Core: Python Extension & Pylance

Pylance is an (official) VS Code extension from Microsoft that comes along with the official Python VS Code extension (it also downloads the Python debugger).

The Python VS Code extension provides many features:

Linting & Type Checking

What is a Linter?

A linter highlights potential issues at code editing time (before actually running the code). Static type checking is a subset of the responsibilities of a linter.

Most linters (Pyright, Mypy, Ruff) have VS Code extensions for inline errors and also come as a CLI for terminal use.

Categories of Linting

Configuring Type Checking in VS Code

IMPORTANT: To enable static code checking at coding time, set Python > Analysis: Type Checking Mode to "Basic" or "Strict". Note: This setting comes from the Python extension rather than Pylance itself.

Strict Mode Considerations

Strict mode can take away some flexibility that Python allows at runtime. Example with Pydantic:

class OnboardBankRequest(BaseModel):
    bankIdrssd: int
    onboardedBy: str

request = OnboardBankRequest(bankIdrssd="123", onboardedBy="John Doe")

Pydantic will convert the string "123" into int 123 at runtime. However, Strict Mode will complain about this. I believe it's better to adhere to strict mode and not rely on such runtime flexibilities.

Pylance automatically works with Pydantic models as well.

Modern Tooling: Ruff

Ruff provides both linting and formatting options. It is widely used to replace isort, flake8, and others.

Formatting & Refactoring

Code Formatter

Restructures the code (not refactoring) to fall in line with best practices defined in PEPs. Examples: autopep8, black, ruff.

Code Restructurer (Refactoring)

Allows automatic modifications like:

Intellisense & Autocomplete

Intellisense provides autocompleting variables, parameters, and attribute names, as well as "Go to Definition".

Observations: Autocomplete Behavior

Static type checking integrates well with native types, but autocomplete doesn't always behave as expected.

Example 1: Pydantic BaseModel (Works)

For autocomplete to work in constructors, I had to subclass BaseModel from Pydantic.

class PydanticUser(BaseModel):
    id: int
    name: str
    email: Optional[str] = None

# Autocomplete works here
pydantic_user = PydanticUser(na 

Example 2: Pydantic without Type Hints (Fails)

Even with Pydantic, if type hints are missing, it fails:

class PydanticUserIn(BaseModel):
    name = "lol"
    secret = 1

# Autocomplete for 'name' attribute doesn't work here
pydantic_user = PydanticUserIn(nam

Conclusion: Autocomplete seems to only work reliably when using BaseModel AND explicit type hints.

This is beacause un-annotated fields are treated as class attributes, not constructor arguments by pydantic.

References