Saturday, April 18, 2026

Python Challenge Setup 2026: uv + Ruff + Ty + Polars



Picture by Editor

 

Introduction

 
Python undertaking setup used to imply making a dozen small selections earlier than you wrote your first helpful line of code. Which surroundings supervisor? Which dependency software? Which formatter? Which linter? Which kind checker? And in case your undertaking touched information, have been you supposed to begin with pandas, DuckDB, or one thing newer?

In 2026, that setup may be a lot easier.

For many new initiatives, the cleanest default stack is:

  • uv for Python set up, environments, dependency administration, locking, and command operating.
  • Ruff for linting and formatting.
  • Ty for kind checking.
  • Polars for dataframe work.

This stack is quick, trendy, and notably coherent. Three of the 4 instruments (uv, Ruff, and Ty) really come from the identical firm, Astral, which implies they combine seamlessly with one another and together with your pyproject.toml.

 

Understanding Why This Stack Works

 
Older setups typically seemed like this:

pyenv + pip + venv + pip-tools or Poetry + Black + isort + Flake8 + mypy + pandas

 

This labored, but it surely created vital overlap, inconsistency, and upkeep overhead. You had separate instruments for surroundings setup, dependency locking, formatting, import sorting, linting, and typing. Each new undertaking began with a selection explosion. The 2026 default stack collapses all of that. The top result’s fewer instruments, fewer configuration information, and fewer friction when onboarding contributors or wiring up steady integration (CI). Earlier than leaping into setup, let’s take a fast take a look at what every software within the 2026 stack is doing:

  1. uv: That is the bottom of your undertaking setup. It creates the undertaking, manages variations, handles dependencies, and runs your code. As a substitute of manually establishing digital environments and putting in packages, uv handles the heavy lifting. It retains your surroundings constant utilizing a lockfile and ensures the whole lot is appropriate earlier than operating any command.
  2. Ruff: That is your all-in-one software for code high quality. This can be very quick, checks for points, fixes a lot of them robotically, and in addition codecs your code. You should utilize it as a substitute of instruments like Black, isort, Flake8, and others.
  3. Ty: It is a newer software for kind checking. It helps catch errors by checking varieties in your code and works with numerous editors. Whereas newer than instruments like mypy or Pyright, it’s optimized for contemporary workflows.
  4. Polars: It is a trendy library for working with dataframes. It focuses on environment friendly information processing utilizing lazy execution, which implies it optimizes queries earlier than operating them. This makes it sooner and extra reminiscence environment friendly than pandas, particularly for giant information duties.

 

Reviewing Conditions

 
The setup is sort of easy. Listed here are the few issues you have to get began:

  • Terminal: macOS Terminal, Home windows PowerShell, or any Linux shell.
  • Web connection: Required for the one-time uv installer and package deal downloads.
  • Code editor: VS Code is really useful as a result of it really works nicely with Ruff and Ty, however any editor is ok.
  • Git: Required for model management; notice that uv initializes a Git repository robotically.

That’s it. You do not want Python pre-installed. You do not want pip, venv, pyenv, or conda. uv handles set up and surroundings administration for you.

 

Step 1: Putting in uv

 
uv gives a standalone installer that works on macOS, Linux, and Home windows with out requiring Python or Rust to be current in your machine.

macOS and Linux:

curl -LsSf https://astral.sh/uv/set up.sh | sh

 

Home windows PowerShell:

powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/set up.ps1 | iex"

 

After set up, restart your terminal and confirm:

 

Output:

uv 0.8.0 (Homebrew 2025-07-17)

 

This single binary now replaces pyenv, pip, venv, pip-tools, and the undertaking administration layer of Poetry.

 

Step 2: Making a New Challenge

 
Navigate to your undertaking listing and scaffold a brand new one:

uv init my-project
cd my-project

 

uv creates a clear beginning construction:

my-project/
├── .python-version
├── pyproject.toml
├── README.md
└── predominant.py

 

Reshape it right into a src/ format, which improves imports, packaging, take a look at isolation, and type-checker configuration:

mkdir -p src/my_project checks information/uncooked information/processed
mv predominant.py src/my_project/predominant.py
contact src/my_project/__init__.py checks/test_main.py

 

Your construction ought to now appear like this:

my-project/
├── .python-version
├── README.md
├── pyproject.toml
├── uv.lock
├── src/
│   └── my_project/
│       ├── __init__.py
│       └── predominant.py
├── checks/
│   └── test_main.py
└── information/
    ├── uncooked/
    └── processed/

 

In case you want a selected model (e.g. 3.12), uv can set up and pin it:

uv python set up 3.12
uv python pin 3.12

 

The pin command writes the model to .python-version, guaranteeing each crew member makes use of the identical interpreter.

 

Step 3: Including Dependencies

 
Including dependencies is a single command that resolves, installs, and locks concurrently:

 

uv robotically creates a digital surroundings (.venv/) if one doesn’t exist, resolves the dependency tree, installs packages, and updates uv.lock with actual, pinned variations.

For instruments wanted solely throughout improvement, use the --dev flag:

uv add --dev ruff ty pytest

 

This locations them in a separate [dependency-groups] part in pyproject.toml, holding manufacturing dependencies lean. You by no means have to run supply .venv/bin/activate; if you use uv run, it robotically prompts the right surroundings.

 

Step 4: Configuring Ruff (Linting and Formatting)

 
Ruff is configured instantly inside your pyproject.toml. Add the next sections:

[tool.ruff]
line-length = 100
target-version = "py312"

[tool.ruff.lint]
choose = ["E4", "E7", "E9", "F", "B", "I", "UP"]

[tool.ruff.format]
docstring-code-format = true
quote-style = "double"

 

A 100-character line size is an effective compromise for contemporary screens. Rule teams flake8-bugbear (B), isort (I), and pyupgrade (UP) add actual worth with out overwhelming a brand new repository.

Working Ruff:

# Lint your code
uv run ruff examine .

# Auto-fix points the place doable
uv run ruff examine --fix .

# Format your code
uv run ruff format .

 

Discover the sample: uv run . You by no means set up instruments globally or activate environments manually.

 

Step 5: Configuring Ty for Sort Checking

 
Ty can also be configured in pyproject.toml. Add these sections:

[tool.ty.environment]
root = ["./src"]

[tool.ty.rules]
all = "warn"

[[tool.ty.overrides]]
embrace = ["src/**"]

[tool.ty.overrides.rules]
possibly-unresolved-reference = "error"

[tool.ty.terminal]
error-on-warning = false
output-format = "full"

 

This configuration begins Ty in warning mode, which is good for adoption. You repair apparent points first, then regularly promote guidelines to errors. Conserving information/** excluded prevents type-checker noise from non-code directories.

 

Step 6: Configuring pytest

 
Add a bit for pytest:

[tool.pytest.ini_options]
testpaths = ["tests"]

 

Run your take a look at suite with:

 

Step 7: Inspecting the Full pyproject.toml

 
Here’s what your closing configuration appears to be like like with the whole lot wired up — one file, each software configured, with no scattered config information:

[project]
identify = "my-project"
model = "0.1.0"
description = "Fashionable Python undertaking with uv, Ruff, Ty, and Polars"
readme = "README.md"
requires-python = ">=3.13"
dependencies = [
    "polars>=1.39.3",
]

[dependency-groups]
dev = [
    "pytest>=9.0.2",
    "ruff>=0.15.8",
    "ty>=0.0.26",
]

[tool.ruff]
line-length = 100
target-version = "py312"

[tool.ruff.lint]
choose = ["E4", "E7", "E9", "F", "B", "I", "UP"]

[tool.ruff.format]
docstring-code-format = true
quote-style = "double"

[tool.ty.environment]
root = ["./src"]

[tool.ty.rules]
all = "warn"

[[tool.ty.overrides]]
embrace = ["src/**"]

[tool.ty.overrides.rules]
possibly-unresolved-reference = "error"

[tool.ty.terminal]
error-on-warning = false
output-format = "full"

[tool.pytest.ini_options]
testpaths = ["tests"]

 

Step 8: Writing Code with Polars

 
Exchange the contents of src/my_project/predominant.py with code that workouts the Polars facet of the stack:

"""Pattern information evaluation with Polars."""

import polars as pl

def build_report(path: str) -> pl.DataFrame:
    """Construct a income abstract from uncooked information utilizing the lazy API."""
    q = (
        pl.scan_csv(path)
        .filter(pl.col("standing") == "lively")
        .with_columns(
            revenue_per_user=(pl.col("income") / pl.col("customers")).alias("rpu")
        )
        .group_by("section")
        .agg(
            pl.len().alias("rows"),
            pl.col("income").sum().alias("income"),
            pl.col("rpu").imply().alias("avg_rpu"),
        )
        .type("income", descending=True)
    )
    return q.gather()

def predominant() -> None:
    """Entry level with pattern in-memory information."""
    df = pl.DataFrame(
        {
            "section": ["Enterprise", "SMB", "Enterprise", "SMB", "Enterprise"],
            "standing": ["active", "active", "churned", "active", "active"],
            "income": [12000, 3500, 8000, 4200, 15000],
            "customers": [120, 70, 80, 84, 150],
        }
    )

    abstract = (
        df.lazy()
        .filter(pl.col("standing") == "lively")
        .with_columns(
            (pl.col("income") / pl.col("customers")).spherical(2).alias("rpu")
        )
        .group_by("section")
        .agg(
            pl.len().alias("rows"),
            pl.col("income").sum().alias("total_revenue"),
            pl.col("rpu").imply().spherical(2).alias("avg_rpu"),
        )
        .type("total_revenue", descending=True)
        .gather()
    )

    print("Income Abstract:")
    print(abstract)

if __name__ == "__main__":
    predominant()

 

Earlier than operating, you want a construct system in pyproject.toml so uv installs your undertaking as a package deal. We are going to use Hatchling:

cat >> pyproject.toml << 'EOF'

[build-system]
requires = ["hatchling"]
build-backend = "hatchling.construct"

[tool.hatch.build.targets.wheel]
packages = ["src/my_project"]
EOF

 

Then sync and run:

uv sync
uv run python -m my_project.predominant

 

It is best to see a formatted Polars desk:

Income Abstract:
form: (2, 4)
┌────────────┬──────┬───────────────┬─────────┐
│ section    ┆ rows ┆ total_revenue ┆ avg_rpu │
│ ---        ┆ ---  ┆ ---           ┆ ---     │
│ str        ┆ u32  ┆ i64           ┆ f64     │
╞════════════╪══════╪═══════════════╪═════════╡
│ Enterprise ┆ 2    ┆ 27000         ┆ 100.0   │
│ SMB        ┆ 2    ┆ 7700          ┆ 50.0    │
└────────────┴──────┴───────────────┴─────────┘

 

Managing the Day by day Workflow

 
As soon as the undertaking is ready up, the day-to-day loop is easy:

# Pull newest, sync dependencies
git pull
uv sync

# Write code...

# Earlier than committing: lint, format, type-check, take a look at
uv run ruff examine --fix .
uv run ruff format .
uv run ty examine
uv run pytest

# Commit
git add .
git commit -m "feat: add income report module"

 

Altering the Method You Write Python with Polars

 
The largest mindset shift on this stack is on the information facet. With Polars, your defaults must be:

  • Expressions over row-wise operations. Polars expressions let the engine vectorize and parallelize operations. Keep away from consumer outlined capabilities (UDFs) except there isn’t any native various, as UDFs are considerably slower.
  • Lazy execution over keen loading. Use scan_csv() as a substitute of read_csv(). This creates a LazyFrame that builds a question plan, permitting the optimizer to push filters down and remove unused columns.
  • Parquet-first workflows over CSV-heavy pipelines. A very good sample for inner information preparation appears to be like like this.

 

Evaluating When This Setup Is Not the Greatest Match

 
It’s your decision a special selection if:

  • Your crew has a mature Poetry or mypy workflow that’s working nicely.
  • Your codebase relies upon closely on pandas-specific APIs or ecosystem libraries.
  • Your group is standardized on Pyright.
  • You might be working in a legacy repository the place altering instruments would create extra disruption than worth.

 

Implementing Professional Ideas

 

  1. By no means activate digital environments manually. Use uv run for the whole lot to make sure you are utilizing the right surroundings.
  2. At all times commit uv.lock to model management. This ensures the undertaking runs identically on each machine.
  3. Use --frozen in CI. This installs dependencies from the lockfile for sooner, extra dependable builds.
  4. Use uvx for one-off instruments. Run instruments with out putting in them in your undertaking.
  5. Use Ruff’s --fix flag liberally. It might auto-fix unused imports, outdated syntax, and extra.
  6. Choose the lazy API by default. Use scan_csv() and solely name .gather() on the finish.
  7. Centralize configuration. Use pyproject.toml as the only supply of reality for all instruments.

 

Concluding Ideas

 
The 2026 Python default stack reduces setup effort and encourages higher practices: locked environments, a single configuration file, quick suggestions, and optimized information pipelines. Give it a attempt; when you expertise environment-agnostic execution, you’ll perceive why builders are switching.
 
 

Kanwal Mehreen is a machine studying engineer and a technical author with a profound ardour for information science and the intersection of AI with drugs. She co-authored the book “Maximizing Productiveness with ChatGPT”. As a Google Technology Scholar 2022 for APAC, she champions variety and educational excellence. She’s additionally acknowledged as a Teradata Range in Tech Scholar, Mitacs Globalink Analysis Scholar, and Harvard WeCode Scholar. Kanwal is an ardent advocate for change, having based FEMCodes to empower girls in STEM fields.

Related Articles

Latest Articles