Picture by Editor
# Introduction
Python undertaking setup used to imply making a dozen small choices earlier than you wrote your first helpful line of code. Which setting supervisor? Which dependency device? Which formatter? Which linter? Which kind checker? And in case your undertaking touched information, had been you supposed to start out with pandas, DuckDB, or one thing newer?
In 2026, that setup will be a lot less complicated.
For many new initiatives, the cleanest default stack is:
- uv for Python set up, environments, dependency administration, locking, and command working.
- Ruff for linting and formatting.
- Ty for sort checking.
- Polars for dataframe work.
This stack is quick, trendy, and notably coherent. Three of the 4 instruments (uv, Ruff, and Ty) truly come from the identical firm, Astral, which suggests they combine seamlessly with one another and along 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, nevertheless it created important overlap, inconsistency, and upkeep overhead. You had separate instruments for setting setup, dependency locking, formatting, import sorting, linting, and typing. Each new undertaking began with a alternative explosion. The 2026 default stack collapses all of that. The top result’s fewer instruments, fewer configuration recordsdata, 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 device within the 2026 stack is doing:
- 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 organising digital environments and putting in packages, uv handles the heavy lifting. It retains your setting constant utilizing a lockfile and ensures every part is appropriate earlier than working any command.
- Ruff: That is your all-in-one device for code high quality. This can be very quick, checks for points, fixes a lot of them routinely, and likewise codecs your code. You should use it as an alternative of instruments like Black, isort, Flake8, and others.
- Ty: It is a newer device for sort checking. It helps catch errors by checking sorts in your code and works with varied editors. Whereas newer than instruments like mypy or Pyright, it’s optimized for contemporary workflows.
- Polars: It is a trendy library for working with dataframes. It focuses on environment friendly information processing utilizing lazy execution, which suggests it optimizes queries earlier than working 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 it’s essential to get began:
- Terminal: macOS Terminal, Home windows PowerShell, or any Linux shell.
- Web connection: Required for the one-time uv installer and bundle downloads.
- Code editor: VS Code is advisable as a result of it really works properly with Ruff and Ty, however any editor is ok.
- Git: Required for model management; word that uv initializes a Git repository routinely.
That’s it. You do not want Python pre-installed. You do not want pip, venv, pyenv, or conda. uv handles set up and setting administration for you.
# Step 1: Putting in uv
uv supplies 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 Venture
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
└── foremost.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 foremost.py src/my_project/foremost.py
contact src/my_project/__init__.py checks/test_main.py
Your construction ought to now appear to be this:
my-project/
├── .python-version
├── README.md
├── pyproject.toml
├── uv.lock
├── src/
│ └── my_project/
│ ├── __init__.py
│ └── foremost.py
├── checks/
│ └── test_main.py
└── information/
├── uncooked/
└── processed/
If you happen to want a particular 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 workforce member makes use of the identical interpreter.
# Step 3: Including Dependencies
Including dependencies is a single command that resolves, installs, and locks concurrently:
uv routinely creates a digital setting (.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 must run supply .venv/bin/activate; whenever you use uv run, it routinely prompts the proper setting.
# Step 4: Configuring Ruff (Linting and Formatting)
Ruff is configured straight 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.
Operating Ruff:
# Lint your code
uv run ruff test .
# Auto-fix points the place potential
uv run ruff test –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 Kind Checking
Ty can 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 right for adoption. You repair apparent points first, then step by step 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 ultimate configuration appears like with every part wired up — one file, each device configured, with no scattered config recordsdata:
[project]
title = “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
Substitute the contents of src/my_project/foremost.py with code that workout routines the Polars aspect 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”) == “energetic”)
.with_columns(
revenue_per_user=(pl.col(“income”) / pl.col(“customers”)).alias(“rpu”)
)
.group_by(“phase”)
.agg(
pl.len().alias(“rows”),
pl.col(“income”).sum().alias(“income”),
pl.col(“rpu”).imply().alias(“avg_rpu”),
)
.kind(“income”, descending=True)
)
return q.accumulate()
def foremost() -> None:
“””Entry level with pattern in-memory information.”””
df = pl.DataFrame(
{
“phase”: [“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”) == “energetic”)
.with_columns(
(pl.col(“income”) / pl.col(“customers”)).spherical(2).alias(“rpu”)
)
.group_by(“phase”)
.agg(
pl.len().alias(“rows”),
pl.col(“income”).sum().alias(“total_revenue”),
pl.col(“rpu”).imply().spherical(2).alias(“avg_rpu”),
)
.kind(“total_revenue”, descending=True)
.accumulate()
)
print(“Income Abstract:”)
print(abstract)
if __name__ == “__main__”:
foremost()
Earlier than working, you want a construct system in pyproject.toml so uv installs your undertaking as a bundle. 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.foremost
It’s best to see a formatted Polars desk:
Income Abstract:
form: (2, 4)
┌────────────┬──────┬───────────────┬─────────┐
│ phase ┆ 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 test –fix .
uv run ruff format .
uv run ty test
uv run pytest
# Commit
git add .
git commit -m “feat: add income report module”
# Altering the Method You Write Python with Polars
The most important mindset shift on this stack is on the info aspect. With Polars, your defaults must be:
- Expressions over row-wise operations. Polars expressions let the engine vectorize and parallelize operations. Keep away from person outlined features (UDFs) except there is no such thing as a native various, as UDFs are considerably slower.
- Lazy execution over keen loading. Use scan_csv() as an alternative of read_csv(). This creates a LazyFrame that builds a question plan, permitting the optimizer to push filters down and eradicate unused columns.
- Parquet-first workflows over CSV-heavy pipelines. A very good sample for inner information preparation appears like this.
# Evaluating When This Setup Is Not the Finest Match
You might have considered trying a distinct alternative if:
- Your workforce has a mature Poetry or mypy workflow that’s working properly.
- 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 Suggestions
- By no means activate digital environments manually. Use uv run for every part to make sure you are utilizing the proper setting.
- At all times commit uv.lock to model management. This ensures the undertaking runs identically on each machine.
- Use –frozen in CI. This installs dependencies from the lockfile for sooner, extra dependable builds.
- Use uvx for one-off instruments. Run instruments with out putting in them in your undertaking.
- Use Ruff’s –fix flag liberally. It might probably auto-fix unused imports, outdated syntax, and extra.
- Desire the lazy API by default. Use scan_csv() and solely name .accumulate() on the finish.
- Centralize configuration. Use pyproject.toml as the one supply of fact 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 medication. She co-authored the book “Maximizing Productiveness with ChatGPT”. As a Google Era Scholar 2022 for APAC, she champions range and tutorial excellence. She’s additionally acknowledged as a Teradata Variety in Tech Scholar, Mitacs Globalink Analysis Scholar, and Harvard WeCode Scholar. Kanwal is an ardent advocate for change, having based FEMCodes to empower ladies in STEM fields.

