Python Business-Ready Cheatsheet
venv + pyproject + ruff + pytest + Typer CLI + Streamlit UI (layout src/)
Technical Writer & Python Architect
March 5, 2026
1. Panoramica “progetto moderno” (in 10 righe)
• Obiettivo: un progetto pulito, testabile e riusabile (backend condiviso da CLI e UI)
• Layout consigliato: src/ + tests/ + [Link] (una sola fonte di verità).
• Ambiente isolato: venv (.venv/) + dipendenze minime (ruff, pytest, typer, streamlit).
• Qualità: ruff per lint+format (veloce, zero fronzoli).
• Test: pytest con fixture, parametrize, raises (unit test rapidi).
• CLI: typer per comandi business (create/list/total/export).
• UI: streamlit per una dashboard base (input + tabella + totali).
• Backend: dataclass + classi service semplici (storage in memoria, estendibile a DB).
2. Setup ambiente (venv) + comandi
• Crea venv in locale progetto: .venv/ (non committare).
• Attiva venv: cambia per OS (vedi comandi sotto).
• Installa tool di base: ruff e pytest prima di tutto.
• Esegui sempre da root progetto (dove sta [Link]).
• Preferisci esecuzione modulo: python -m ... (coerente con src/).
# 1) crea venv
python -m venv .venv
# 2) attiva venv
# Linux/macOS:
source .venv/bin/activate
# Windows PowerShell:
.\.venv\Scripts\Activate.ps1
# 3) installa dipendenze (minime richieste)
python -m pip install -U pip
python -m pip install ruff pytest typer streamlit
3. Struttura cartelle consigliata (layout src/)
• Nome caso business (coerente ovunque): Order Management
• Package: order mgmt dentro src/ (import puliti e testabili).
• Entrypoint CLI e UI in src/order mgmt/ (eseguibili come moduli).
• Test separati in tests/ (importano dal package, non copiano logica).
• [Link] configura tool e dipendenze in un posto solo.
Template riusabile: albero progetto
your-project/
[Link]
[Link]
src/
order_mgmt/
__init__.py
[Link] # dataclass (Customer, LineItem, Order)
[Link] # OrderService (create, total, list, export)
[Link] # Typer CLI
1
[Link] # Streamlit UI
tests/
test_service.py
.gitignore
Template: .gitignore minimo
.venv/
__pycache__/
*.pyc
.pytest_cache/
.ruff_cache/
.dist/
build/
*.egg-info/
4. [Link] minimale ma completo (dipendenze, ruff, pytest)
• Semplificazione: anche senza packaging avanzato, [Link] centralizza configurazioni.
• Dipendenze runtime: typer, streamlit. Tool dev: ruff, pytest.
• Ruff : abilita format + check e fix automatici.
• Pytest: punta al folder tests/ e usa output conciso.
• Nota: questo template assume installazione via pip install ...; per build/packaging puoi estendere in seguito.
# [Link]
[project]
name = "order-mgmt"
version = "0.1.0"
requires-python = ">=3.11"
dependencies = [
"typer>=0.12",
"streamlit>=1.30",
]
[[Link]]
line-length = 100
target-version = "py311"
[[Link]]
select = ["E", "F", "I", "B", "UP"] # base: pycodestyle/pyflakes/isort/bugbear/pyupgrade
ignore = []
[[Link]]
quote-style = "double"
indent-style = "space"
[[Link].ini_options]
testpaths = ["tests"]
addopts = "-q"
5. Backend “business” (dataclass + classi + metodi) — Order Management
• Modelli: Customer, LineItem, Order con @dataclass (dati + type hints).
• Service: OrderService con storage in memoria (dict) e metodi: create, list, total, export csv.
• Logica riusabile: nessuna dipendenza da Typer/Streamlit nel backend.
• Estensione facile: sostituisci lo storage in memoria con DB/repo senza cambiare CLI/UI (stessa API).
• Consiglio pratico: metodi piccoli + dati immutabili dove possibile.
# src/order_mgmt/[Link]
from __future__ import annotations
from dataclasses import dataclass
from datetime import date
2
@dataclass(frozen=True, slots=True)
class Customer:
id: str
name: str
email: str
@dataclass(frozen=True, slots=True)
class LineItem:
sku: str
qty: int
unit_price: float
def subtotal(self) -> float:
return [Link] * self.unit_price
@dataclass(frozen=True, slots=True)
class Order:
id: str
customer_id: str
items: list[LineItem]
created_at: date
def total(self) -> float:
return sum([Link]() for i in [Link])
# src/order_mgmt/[Link]
from __future__ import annotations
from dataclasses import asdict
from datetime import date
from typing import Iterable
from order_mgmt.models import Customer, LineItem, Order
class OrderService:
def __init__(self) -> None:
[Link]: dict[str, Customer] = {}
[Link]: dict[str, Order] = {}
def add_customer(self, customer: Customer) -> None:
[Link][[Link]] = customer
def create_order(self, order_id: str, customer_id: str, items: list[LineItem]) -> Order:
if customer_id not in [Link]:
raise ValueError(f"Unknown customer_id: {customer_id}")
order = Order(id=order_id, customer_id=customer_id, items=items, created_at=[Link]())
[Link][[Link]] = order
return order
def list_orders(self) -> list[Order]:
return sorted([Link](), key=lambda o: o.created_at, reverse=True)
def total_for_order(self, order_id: str) -> float:
return [Link][order_id].total()
def export_orders_csv(self, rows: Iterable[Order]) -> str:
# output CSV "semplice": stringa pronta da salvare
header = "order_id,customer_id,created_at,total\n"
lines = [
f"{[Link]},{o.customer_id},{o.created_at.isoformat()},{[Link]():.2f}"
for o in rows
]
return header + "\n".join(lines) + "\n"
3
6. CLI con Typer (metodi principali + esempio comandi)
• CLI = interfaccia business-friendly: crea ordine, lista, totale, export.
• Riuso backend: import diretto di OrderService e modelli.
• Preferisci python -m order [Link] ... per avvio coerente con src/.
• Pattern: un app = [Link]() + funzioni decorate @[Link]().
• Output semplice con [Link]; errori con [Link](code=...).
Tabella metodi chiave Typer
Elemento Uso rapido
[Link]() Crea l’app CLI (raggruppa comandi).
@[Link]() Registra una funzione come comando.
[Link](...) Parametro posizionale (obbligatorio o con default).
[Link](...) Flag/Opzione (es. --customer-id).
[Link](...) Stampa (più sicuro/portabile di print).
raise [Link](code) Termina con exit code (utile in CI).
# src/order_mgmt/[Link]
from __future__ import annotations
import typer
from order_mgmt.models import Customer, LineItem
from order_mgmt.service import OrderService
app = [Link](help="Order Management CLI")
_svc = OrderService()
_svc.add_customer(Customer(id="c1", name="Acme Srl", email="info@[Link]"))
@[Link]()
def create(
order_id: str = [Link](..., help="Order ID"),
customer_id: str = [Link]("c1", "--customer-id", help="Customer ID"),
) -> None:
items = [LineItem(sku="SKU-001", qty=2, unit_price=19.90)]
try:
o = _svc.create_order(order_id=order_id, customer_id=customer_id, items=items)
except ValueError as e:
[Link](f"ERROR: {e}")
raise [Link](code=2)
[Link](f"Created {[Link]} total={[Link]():.2f}")
@[Link]()
def list() -> None:
for o in _svc.list_orders():
[Link](f"{[Link]} customer={o.customer_id} date={o.created_at} total={[Link]():.2f}")
@[Link]()
def export(path: str = [Link]("[Link]", "--path")) -> None:
csv_text = _svc.export_orders_csv(_svc.list_orders())
with open(path, "w", encoding="utf-8") as f:
[Link](csv_text)
[Link](f"Wrote {path}")
if __name__ == "__main__":
app()
Comandi esempio (da copiare)
• python -m order [Link] create o1 --customer-id c1
• python -m order [Link] list
• python -m order [Link] export --path [Link]
4
7. UI base con Streamlit (metodi principali + esempio)
• Streamlit = UI rapida: input + bottone + tabella (dashboard base)
• Riuso backend: stessa OrderService della CLI (nessuna logica duplicata).
• Stato: usa [Link] state per tenere il service vivo tra rerun.
• Pattern: sidebar per input, main per risultati.
• Avvio: streamlit run src/order mgmt/[Link].
Tabella metodi chiave Streamlit
Elemento Uso rapido
[Link](...) Titolo pagina.
[Link] Area laterale per controlli.
[Link] input(...) Input testuale (es. order id).
[Link](...) Selezione da lista (es. customer).
[Link](...) Azione (crea ordine, export).
[Link](...) Tabella interattiva (ordini).
[Link] state Stato persistente tra rerun.
# src/order_mgmt/[Link]
from __future__ import annotations
import streamlit as st
from order_mgmt.models import Customer, LineItem
from order_mgmt.service import OrderService
st.set_page_config(page_title="Order Dashboard", layout="wide")
[Link]("Order Management Dashboard")
if "svc" not in st.session_state:
svc = OrderService()
svc.add_customer(Customer(id="c1", name="Acme Srl", email="info@[Link]"))
svc.add_customer(Customer(id="c2", name="Globex Spa", email="sales@[Link]"))
st.session_state.svc = svc
svc: OrderService = st.session_state.svc
with [Link]:
[Link]("Crea ordine")
order_id = st.text_input("Order ID", value="o1")
customer_id = [Link]("Customer", options=list([Link]()))
qty = st.number_input("Qty", min_value=1, value=2, step=1)
price = st.number_input("Unit price", min_value=0.0, value=19.90, step=0.10)
if [Link]("Create"):
items = [LineItem(sku="SKU-001", qty=int(qty), unit_price=float(price))]
try:
svc.create_order(order_id=order_id, customer_id=customer_id, items=items)
[Link]("Ordine creato!")
except ValueError as e:
[Link](str(e))
orders = svc.list_orders()
rows = [{"id": [Link], "customer": o.customer_id, "date": str(o.created_at), "total": round([Link](), 2)}
for o in orders]
[Link](rows, use_container_width=True)
if orders:
[Link]("Totale ultimo ordine", f"{orders[0].total():.2f}")
8. Test con Pytest (pattern, fixture, parametrize, mock base)
• Testa service e modelli: sono la “verità” del business.
• Pattern: Arrange–Act–Assert (setup, azione, assert).
• fixture per creare un service pronto (customer già inserito).
5
• parametrize per testare più casi in poche righe.
• [Link] per errori attesi (es. customer sconosciuto).
• Mock base: preferisci funzioni pure e dependency injection; mock solo dove serve (I/O, tempo, rete).
Tabella metodi chiave Pytest
Elemento Uso rapido
assert ... Verifica risultato (semplice e leggibile).
@[Link] Prepara oggetti riusabili per più test.
@[Link] Parametrizza input/output (molti casi, un test).
with [Link](...) Verifica eccezioni.
# tests/test_service.py
import pytest
from order_mgmt.models import Customer, LineItem
from order_mgmt.service import OrderService
@[Link]()
def svc() -> OrderService:
s = OrderService()
s.add_customer(Customer(id="c1", name="Acme Srl", email="info@[Link]"))
return s
def test_create_order_and_total(svc: OrderService) -> None:
o = svc.create_order("o1", "c1", [LineItem(sku="A", qty=2, unit_price=10.0)])
assert [Link]() == 20.0
assert svc.total_for_order("o1") == 20.0
@[Link](
"qty,price,expected",
[(1, 9.99, 9.99), (2, 10.00, 20.00), (3, 0.50, 1.50)],
)
def test_lineitem_subtotal(qty: int, price: float, expected: float) -> None:
li = LineItem(sku="X", qty=qty, unit_price=price)
assert [Link]() == expected
def test_unknown_customer_raises(svc: OrderService) -> None:
with [Link](ValueError):
svc.create_order("o2", "missing", [LineItem(sku="A", qty=1, unit_price=1.0)])
9. Ruff (lint/format, regole comuni, fix) + comandi
• ruff = lint + formatter (veloce, semplice)
• Usa due comandi: ruff check . e ruff format .
• Fix automatico: ruff check . --fix
• In CI: ruff check . + ruff format . --check + pytest
• Regole utili già incluse: E/F/I/B/UP (errori, import, bugbear, pyupgrade).
Tabella comandi chiave Ruff
Comando Cosa fa
ruff check . Lint su tutto il progetto.
ruff check . --fix Lint + fix automatici (quando possibile).
ruff format . Format code (stile consistente).
ruff format . --check Verifica formattazione (utile in CI).
# Routine veloce (prima di push)
ruff format .
ruff check . --fix
pytest -q
6
10. Note Python: future annotations, decoratori, classi/dataclass
• from f uture mportannotations :rendeitypehintlazy(comestringhe)
i
• Quando serve: se vuoi annotare tipi che non sono ancora definiti, o per evitare import circolari.
• In Python 3.11 è spesso ‘‘nice-to-have’’: migliora compatibilità e riduce problemi con forward referenc
• Decoratori: funzioni che modificano funzioni/classi (es. @dataclass, @[Link]).
• Classi: incapsulano stato+metodi; usa service per logica, dataclass per dati.
• @dataclass(frozen=True, slots=True): oggetti più leggeri, (quasi) immutabili, e chiari.
from __future__ import annotations
from dataclasses import dataclass
# Forward reference: "Node" usato dentro la classe stessa.
@dataclass(slots=True)
class Node:
value: int
next: Node | None = None
def audit(fn): # decoratore minimale
def wrapper(*args, **kwargs):
return fn(*args, **kwargs)
return wrapper
@audit
def add(a: int, b: int) -> int:
return a + b
11. Checklist finale (prima di committare / rilasciare)
• ruff format . e poi ruff check . --fix
• pytest -q verde (niente test skipped senza motivo)
• CLI funziona: python -m order [Link] list
• UI parte: streamlit run src/order mgmt/[Link]
• Import puliti: backend non dipende da Typer/Streamlit
• .venv/ e cache in .gitignore
• Nomi coerenti: package order mgmt, file models/service/cli/ui
• Prima di release: valuta persistenza (DB/repo) al posto dello storage in memoria